tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

WasmBCRegMgmt-inl.h (11907B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 *
      4 * Copyright 2016 Mozilla Foundation
      5 *
      6 * Licensed under the Apache License, Version 2.0 (the "License");
      7 * you may not use this file except in compliance with the License.
      8 * You may obtain a copy of the License at
      9 *
     10 *     http://www.apache.org/licenses/LICENSE-2.0
     11 *
     12 * Unless required by applicable law or agreed to in writing, software
     13 * distributed under the License is distributed on an "AS IS" BASIS,
     14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15 * See the License for the specific language governing permissions and
     16 * limitations under the License.
     17 */
     18 
     19 // This is an INTERNAL header for Wasm baseline compiler: inline methods in the
     20 // compiler for register management.
     21 
     22 #ifndef wasm_wasm_baseline_reg_mgmt_inl_h
     23 #define wasm_wasm_baseline_reg_mgmt_inl_h
     24 
     25 namespace js {
     26 namespace wasm {
     27 
     28 bool BaseCompiler::isAvailableI32(RegI32 r) { return ra.isAvailableI32(r); }
     29 bool BaseCompiler::isAvailableI64(RegI64 r) { return ra.isAvailableI64(r); }
     30 bool BaseCompiler::isAvailableRef(RegRef r) { return ra.isAvailableRef(r); }
     31 bool BaseCompiler::isAvailablePtr(RegPtr r) { return ra.isAvailablePtr(r); }
     32 bool BaseCompiler::isAvailableF32(RegF32 r) { return ra.isAvailableF32(r); }
     33 bool BaseCompiler::isAvailableF64(RegF64 r) { return ra.isAvailableF64(r); }
     34 #ifdef ENABLE_WASM_SIMD
     35 bool BaseCompiler::isAvailableV128(RegV128 r) { return ra.isAvailableV128(r); }
     36 #endif
     37 
     38 [[nodiscard]] RegI32 BaseCompiler::needI32() { return ra.needI32(); }
     39 [[nodiscard]] RegI64 BaseCompiler::needI64() { return ra.needI64(); }
     40 [[nodiscard]] RegRef BaseCompiler::needRef() { return ra.needRef(); }
     41 [[nodiscard]] RegPtr BaseCompiler::needPtr() { return ra.needPtr(); }
     42 [[nodiscard]] RegF32 BaseCompiler::needF32() { return ra.needF32(); }
     43 [[nodiscard]] RegF64 BaseCompiler::needF64() { return ra.needF64(); }
     44 #ifdef ENABLE_WASM_SIMD
     45 [[nodiscard]] RegV128 BaseCompiler::needV128() { return ra.needV128(); }
     46 #endif
     47 
     48 void BaseCompiler::needI32(RegI32 specific) { ra.needI32(specific); }
     49 void BaseCompiler::needI64(RegI64 specific) { ra.needI64(specific); }
     50 void BaseCompiler::needRef(RegRef specific) { ra.needRef(specific); }
     51 void BaseCompiler::needPtr(RegPtr specific) { ra.needPtr(specific); }
     52 void BaseCompiler::needF32(RegF32 specific) { ra.needF32(specific); }
     53 void BaseCompiler::needF64(RegF64 specific) { ra.needF64(specific); }
     54 #ifdef ENABLE_WASM_SIMD
     55 void BaseCompiler::needV128(RegV128 specific) { ra.needV128(specific); }
     56 #endif
     57 
     58 #if defined(JS_CODEGEN_ARM)
     59 [[nodiscard]] RegI64 BaseCompiler::needI64Pair() { return ra.needI64Pair(); }
     60 #endif
     61 
     62 void BaseCompiler::freeI32(RegI32 r) { ra.freeI32(r); }
     63 void BaseCompiler::freeI64(RegI64 r) { ra.freeI64(r); }
     64 void BaseCompiler::freeRef(RegRef r) { ra.freeRef(r); }
     65 void BaseCompiler::freePtr(RegPtr r) { ra.freePtr(r); }
     66 void BaseCompiler::freeF32(RegF32 r) { ra.freeF32(r); }
     67 void BaseCompiler::freeF64(RegF64 r) { ra.freeF64(r); }
     68 #ifdef ENABLE_WASM_SIMD
     69 void BaseCompiler::freeV128(RegV128 r) { ra.freeV128(r); }
     70 #endif
     71 
     72 void BaseCompiler::freeAny(AnyReg r) {
     73  switch (r.tag) {
     74    case AnyReg::I32:
     75      freeI32(r.i32());
     76      break;
     77    case AnyReg::I64:
     78      freeI64(r.i64());
     79      break;
     80    case AnyReg::REF:
     81      freeRef(r.ref());
     82      break;
     83    case AnyReg::F32:
     84      freeF32(r.f32());
     85      break;
     86    case AnyReg::F64:
     87      freeF64(r.f64());
     88      break;
     89 #ifdef ENABLE_WASM_SIMD
     90    case AnyReg::V128:
     91      freeV128(r.v128());
     92      break;
     93 #endif
     94    default:
     95      MOZ_CRASH();
     96  }
     97 }
     98 
     99 template <>
    100 inline void BaseCompiler::free<RegI32>(RegI32 r) {
    101  freeI32(r);
    102 }
    103 
    104 template <>
    105 inline void BaseCompiler::free<RegI64>(RegI64 r) {
    106  freeI64(r);
    107 }
    108 
    109 template <>
    110 inline void BaseCompiler::free<RegRef>(RegRef r) {
    111  freeRef(r);
    112 }
    113 
    114 template <>
    115 inline void BaseCompiler::free<RegPtr>(RegPtr r) {
    116  freePtr(r);
    117 }
    118 
    119 template <>
    120 inline void BaseCompiler::free<RegF32>(RegF32 r) {
    121  freeF32(r);
    122 }
    123 
    124 template <>
    125 inline void BaseCompiler::free<RegF64>(RegF64 r) {
    126  freeF64(r);
    127 }
    128 
    129 #ifdef ENABLE_WASM_SIMD
    130 template <>
    131 inline void BaseCompiler::free<RegV128>(RegV128 r) {
    132  freeV128(r);
    133 }
    134 #endif
    135 
    136 template <>
    137 inline void BaseCompiler::free<AnyReg>(AnyReg r) {
    138  freeAny(r);
    139 }
    140 
    141 void BaseCompiler::freeI64Except(RegI64 r, RegI32 except) {
    142 #ifdef JS_PUNBOX64
    143  MOZ_ASSERT(r.reg == except);
    144 #else
    145  MOZ_ASSERT(r.high == except || r.low == except);
    146  freeI64(r);
    147  needI32(except);
    148 #endif
    149 }
    150 
    151 void BaseCompiler::maybeFree(RegI32 r) {
    152  if (r.isValid()) {
    153    freeI32(r);
    154  }
    155 }
    156 
    157 void BaseCompiler::maybeFree(RegI64 r) {
    158  if (r.isValid()) {
    159    freeI64(r);
    160  }
    161 }
    162 
    163 void BaseCompiler::maybeFree(RegF32 r) {
    164  if (r.isValid()) {
    165    freeF32(r);
    166  }
    167 }
    168 
    169 void BaseCompiler::maybeFree(RegF64 r) {
    170  if (r.isValid()) {
    171    freeF64(r);
    172  }
    173 }
    174 
    175 void BaseCompiler::maybeFree(RegRef r) {
    176  if (r.isValid()) {
    177    freeRef(r);
    178  }
    179 }
    180 
    181 void BaseCompiler::maybeFree(RegPtr r) {
    182  if (r.isValid()) {
    183    freePtr(r);
    184  }
    185 }
    186 
    187 #ifdef ENABLE_WASM_SIMD128
    188 void BaseCompiler::maybeFree(RegV128 r) {
    189  if (r.isValid()) {
    190    freeV128(r);
    191  }
    192 }
    193 #endif
    194 
    195 void BaseCompiler::needI32NoSync(RegI32 r) {
    196  MOZ_ASSERT(isAvailableI32(r));
    197  needI32(r);
    198 }
    199 
    200 // TODO / OPTIMIZE: need2xI32() can be optimized along with needI32()
    201 // to avoid sync(). (Bug 1316802)
    202 
    203 void BaseCompiler::need2xI32(RegI32 r0, RegI32 r1) {
    204  needI32(r0);
    205  needI32(r1);
    206 }
    207 
    208 void BaseCompiler::need2xI64(RegI64 r0, RegI64 r1) {
    209  needI64(r0);
    210  needI64(r1);
    211 }
    212 
    213 RegI32 BaseCompiler::fromI64(RegI64 r) { return RegI32(lowPart(r)); }
    214 
    215 RegI32 BaseCompiler::maybeFromI64(RegI64 r) {
    216  if (!r.isValid()) {
    217    return RegI32::Invalid();
    218  }
    219  return fromI64(r);
    220 }
    221 
    222 #ifdef JS_PUNBOX64
    223 RegI64 BaseCompiler::fromI32(RegI32 r) { return RegI64(Register64(r)); }
    224 #endif
    225 
    226 RegI64 BaseCompiler::widenI32(RegI32 r) {
    227  MOZ_ASSERT(!isAvailableI32(r));
    228 #ifdef JS_PUNBOX64
    229  return fromI32(r);
    230 #else
    231  RegI32 high = needI32();
    232  return RegI64(Register64(high, r));
    233 #endif
    234 }
    235 
    236 RegI32 BaseCompiler::narrowI64(RegI64 r) {
    237 #ifdef JS_PUNBOX64
    238  return RegI32(r.reg);
    239 #else
    240  freeI32(RegI32(r.high));
    241  return RegI32(r.low);
    242 #endif
    243 }
    244 
    245 RegI32 BaseCompiler::narrowRef(RegRef r) { return RegI32(r); }
    246 
    247 RegI32 BaseCompiler::lowPart(RegI64 r) {
    248 #ifdef JS_PUNBOX64
    249  return RegI32(r.reg);
    250 #else
    251  return RegI32(r.low);
    252 #endif
    253 }
    254 
    255 RegI32 BaseCompiler::maybeHighPart(RegI64 r) {
    256 #ifdef JS_PUNBOX64
    257  return RegI32::Invalid();
    258 #else
    259  return RegI32(r.high);
    260 #endif
    261 }
    262 
    263 // TODO: We want these to be inlined for sure; do we need an `inline` somewhere?
    264 
    265 template <>
    266 inline RegI32 BaseCompiler::need<RegI32>() {
    267  return needI32();
    268 }
    269 template <>
    270 inline RegI64 BaseCompiler::need<RegI64>() {
    271  return needI64();
    272 }
    273 template <>
    274 inline RegF32 BaseCompiler::need<RegF32>() {
    275  return needF32();
    276 }
    277 template <>
    278 inline RegF64 BaseCompiler::need<RegF64>() {
    279  return needF64();
    280 }
    281 
    282 template <>
    283 inline RegI32 BaseCompiler::pop<RegI32>() {
    284  return popI32();
    285 }
    286 template <>
    287 inline RegI64 BaseCompiler::pop<RegI64>() {
    288  return popI64();
    289 }
    290 template <>
    291 inline RegF32 BaseCompiler::pop<RegF32>() {
    292  return popF32();
    293 }
    294 template <>
    295 inline RegF64 BaseCompiler::pop<RegF64>() {
    296  return popF64();
    297 }
    298 
    299 #ifdef ENABLE_WASM_SIMD
    300 template <>
    301 inline RegV128 BaseCompiler::need<RegV128>() {
    302  return needV128();
    303 }
    304 template <>
    305 inline RegV128 BaseCompiler::pop<RegV128>() {
    306  return popV128();
    307 }
    308 #endif
    309 
    310 // RegPtr values can't be pushed, hence can't be popped.
    311 template <>
    312 inline RegPtr BaseCompiler::need<RegPtr>() {
    313  return needPtr();
    314 }
    315 
    316 void BaseCompiler::needResultRegisters(ResultType type, ResultRegKind which) {
    317  if (type.empty()) {
    318    return;
    319  }
    320 
    321  for (ABIResultIter iter(type); !iter.done(); iter.next()) {
    322    ABIResult result = iter.cur();
    323    // Register results are visited first; when we see a stack result we're
    324    // done.
    325    if (!result.inRegister()) {
    326      return;
    327    }
    328    switch (result.type().kind()) {
    329      case ValType::I32:
    330        needI32(RegI32(result.gpr()));
    331        break;
    332      case ValType::I64:
    333        needI64(RegI64(result.gpr64()));
    334        break;
    335      case ValType::V128:
    336 #ifdef ENABLE_WASM_SIMD
    337        if (which == ResultRegKind::All) {
    338          needV128(RegV128(result.fpr()));
    339        }
    340        break;
    341 #else
    342        MOZ_CRASH("No SIMD support");
    343 #endif
    344      case ValType::F32:
    345        if (which == ResultRegKind::All) {
    346          needF32(RegF32(result.fpr()));
    347        }
    348        break;
    349      case ValType::F64:
    350        if (which == ResultRegKind::All) {
    351          needF64(RegF64(result.fpr()));
    352        }
    353        break;
    354      case ValType::Ref:
    355        needRef(RegRef(result.gpr()));
    356        break;
    357    }
    358  }
    359 }
    360 
    361 #ifdef JS_64BIT
    362 void BaseCompiler::widenInt32ResultRegisters(ResultType type) {
    363  if (type.empty()) {
    364    return;
    365  }
    366 
    367  for (ABIResultIter iter(type); !iter.done(); iter.next()) {
    368    ABIResult result = iter.cur();
    369    if (result.inRegister() && result.type().kind() == ValType::I32) {
    370      masm.widenInt32(result.gpr());
    371    }
    372  }
    373 }
    374 #endif
    375 
    376 void BaseCompiler::freeResultRegisters(ResultType type, ResultRegKind which) {
    377  if (type.empty()) {
    378    return;
    379  }
    380 
    381  for (ABIResultIter iter(type); !iter.done(); iter.next()) {
    382    ABIResult result = iter.cur();
    383    // Register results are visited first; when we see a stack result we're
    384    // done.
    385    if (!result.inRegister()) {
    386      return;
    387    }
    388    switch (result.type().kind()) {
    389      case ValType::I32:
    390        freeI32(RegI32(result.gpr()));
    391        break;
    392      case ValType::I64:
    393        freeI64(RegI64(result.gpr64()));
    394        break;
    395      case ValType::V128:
    396 #ifdef ENABLE_WASM_SIMD
    397        if (which == ResultRegKind::All) {
    398          freeV128(RegV128(result.fpr()));
    399        }
    400        break;
    401 #else
    402        MOZ_CRASH("No SIMD support");
    403 #endif
    404      case ValType::F32:
    405        if (which == ResultRegKind::All) {
    406          freeF32(RegF32(result.fpr()));
    407        }
    408        break;
    409      case ValType::F64:
    410        if (which == ResultRegKind::All) {
    411          freeF64(RegF64(result.fpr()));
    412        }
    413        break;
    414      case ValType::Ref:
    415        freeRef(RegRef(result.gpr()));
    416        break;
    417    }
    418  }
    419 }
    420 
    421 void BaseCompiler::needIntegerResultRegisters(ResultType type) {
    422  needResultRegisters(type, ResultRegKind::OnlyGPRs);
    423 }
    424 
    425 void BaseCompiler::freeIntegerResultRegisters(ResultType type) {
    426  freeResultRegisters(type, ResultRegKind::OnlyGPRs);
    427 }
    428 
    429 void BaseCompiler::needResultRegisters(ResultType type) {
    430  needResultRegisters(type, ResultRegKind::All);
    431 }
    432 
    433 void BaseCompiler::freeResultRegisters(ResultType type) {
    434  freeResultRegisters(type, ResultRegKind::All);
    435 }
    436 
    437 void BaseCompiler::captureResultRegisters(ResultType type) {
    438  assertResultRegistersAvailable(type);
    439  needResultRegisters(type);
    440 }
    441 
    442 void BaseCompiler::captureCallResultRegisters(ResultType type) {
    443  captureResultRegisters(type);
    444 #ifdef JS_64BIT
    445  widenInt32ResultRegisters(type);
    446 #endif
    447 }
    448 
    449 //////////////////////////////////////////////////////////////////////////////
    450 //
    451 // Control stack.  Some of these are very hot.
    452 
    453 void BaseCompiler::initControl(Control& item, ResultType params) {
    454  // Make sure the constructor was run properly
    455  MOZ_ASSERT(!item.stackHeight.isValid() && item.stackSize == UINT32_MAX);
    456 
    457  uint32_t paramCount = deadCode_ ? 0 : params.length();
    458  uint32_t stackParamSize = stackConsumed(paramCount);
    459  item.stackHeight = fr.stackResultsBase(stackParamSize);
    460  item.stackSize = stk_.length() - paramCount;
    461  item.deadOnArrival = deadCode_;
    462  item.bceSafeOnEntry = bceSafe_;
    463 }
    464 
    465 Control& BaseCompiler::controlItem() { return iter_.controlItem(); }
    466 
    467 Control& BaseCompiler::controlItem(uint32_t relativeDepth) {
    468  return iter_.controlItem(relativeDepth);
    469 }
    470 
    471 Control& BaseCompiler::controlOutermost() { return iter_.controlOutermost(); }
    472 
    473 LabelKind BaseCompiler::controlKind(uint32_t relativeDepth) {
    474  return iter_.controlKind(relativeDepth);
    475 }
    476 
    477 }  // namespace wasm
    478 }  // namespace js
    479 
    480 #endif  // wasm_wasm_baseline_reg_mgmt_inl_h