tor-browser

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

WasmInitExpr.cpp (20395B)


      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 2021 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 #include "wasm/WasmInitExpr.h"
     20 
     21 #include "mozilla/Maybe.h"
     22 
     23 #include "js/Value.h"
     24 
     25 #include "wasm/WasmGcObject.h"
     26 #include "wasm/WasmInstance.h"
     27 #include "wasm/WasmOpIter.h"
     28 #include "wasm/WasmSerialize.h"
     29 #include "wasm/WasmUtility.h"
     30 #include "wasm/WasmValidate.h"
     31 
     32 #include "wasm/WasmInstance-inl.h"
     33 
     34 using namespace js;
     35 using namespace js::wasm;
     36 
     37 using mozilla::Maybe;
     38 using mozilla::Nothing;
     39 using mozilla::Some;
     40 
     41 class MOZ_STACK_CLASS InitExprInterpreter {
     42 public:
     43  explicit InitExprInterpreter(JSContext* cx,
     44                               Handle<WasmInstanceObject*> instanceObj)
     45      : features(FeatureArgs::build(cx, FeatureOptions())),
     46        stack(cx),
     47        instanceObj(cx, instanceObj),
     48        types(instanceObj->instance().codeMeta().types) {}
     49 
     50  bool evaluate(JSContext* cx, Decoder& d);
     51 
     52  Val result() {
     53    MOZ_ASSERT(stack.length() == 1);
     54    return stack.popCopy();
     55  }
     56 
     57 private:
     58  FeatureArgs features;
     59  RootedValVectorN<48> stack;
     60  Rooted<WasmInstanceObject*> instanceObj;
     61  SharedTypeContext types;
     62 
     63  Instance& instance() { return instanceObj->instance(); }
     64 
     65  [[nodiscard]] bool pushI32(int32_t c) {
     66    return stack.append(Val(uint32_t(c)));
     67  }
     68  [[nodiscard]] bool pushI64(int64_t c) {
     69    return stack.append(Val(uint64_t(c)));
     70  }
     71  [[nodiscard]] bool pushF32(float c) { return stack.append(Val(c)); }
     72  [[nodiscard]] bool pushF64(double c) { return stack.append(Val(c)); }
     73  [[nodiscard]] bool pushV128(V128 c) { return stack.append(Val(c)); }
     74  [[nodiscard]] bool pushRef(ValType type, AnyRef ref) {
     75    return stack.append(Val(type, ref));
     76  }
     77  [[nodiscard]] bool pushFuncRef(RefType type, FuncRef ref) {
     78    return stack.append(Val(type, ref));
     79  }
     80 
     81  int32_t popI32() {
     82    uint32_t result = stack.back().i32();
     83    stack.popBack();
     84    return int32_t(result);
     85  }
     86  int64_t popI64() {
     87    uint64_t result = stack.back().i64();
     88    stack.popBack();
     89    return int64_t(result);
     90  }
     91 
     92  bool evalGlobalGet(JSContext* cx, uint32_t index) {
     93    RootedVal val(cx);
     94    instance().constantGlobalGet(index, &val);
     95    return stack.append(val);
     96  }
     97  bool evalI32Const(int32_t c) { return pushI32(c); }
     98  bool evalI64Const(int64_t c) { return pushI64(c); }
     99  bool evalF32Const(float c) { return pushF32(c); }
    100  bool evalF64Const(double c) { return pushF64(c); }
    101  bool evalV128Const(V128 c) { return pushV128(c); }
    102  bool evalRefFunc(JSContext* cx, uint32_t funcIndex) {
    103    RootedFunction func(cx);
    104    if (!instance().getExportedFunction(cx, funcIndex, &func)) {
    105      return false;
    106    }
    107    const TypeDef& t = instance().codeMeta().getFuncTypeDef(funcIndex);
    108    return pushFuncRef(RefType::fromTypeDef(&t, false),
    109                       FuncRef::fromJSFunction(func.get()));
    110  }
    111  bool evalRefNull(RefType type) { return pushRef(type, AnyRef::null()); }
    112  bool evalI32Add() {
    113    uint32_t b = popI32();
    114    uint32_t a = popI32();
    115    return pushI32(a + b);
    116  }
    117  bool evalI32Sub() {
    118    uint32_t b = popI32();
    119    uint32_t a = popI32();
    120    return pushI32(a - b);
    121  }
    122  bool evalI32Mul() {
    123    uint32_t b = popI32();
    124    uint32_t a = popI32();
    125    return pushI32(a * b);
    126  }
    127  bool evalI64Add() {
    128    uint64_t b = popI64();
    129    uint64_t a = popI64();
    130    return pushI64(a + b);
    131  }
    132  bool evalI64Sub() {
    133    uint64_t b = popI64();
    134    uint64_t a = popI64();
    135    return pushI64(a - b);
    136  }
    137  bool evalI64Mul() {
    138    uint64_t b = popI64();
    139    uint64_t a = popI64();
    140    return pushI64(a * b);
    141  }
    142  bool evalStructNew(JSContext* cx, uint32_t typeIndex) {
    143    const TypeDef& typeDef = instance().codeMeta().types->type(typeIndex);
    144    const StructType& structType = typeDef.structType();
    145 
    146    Rooted<WasmStructObject*> structObj(
    147        cx, instance().constantStructNewDefault(cx, typeIndex));
    148    if (!structObj) {
    149      return false;
    150    }
    151 
    152    uint32_t numFields = structType.fields_.length();
    153    for (uint32_t forwardIndex = 0; forwardIndex < numFields; forwardIndex++) {
    154      uint32_t reverseIndex = numFields - forwardIndex - 1;
    155      const Val& val = stack.back();
    156      structObj->storeVal(val, reverseIndex);
    157      stack.popBack();
    158    }
    159 
    160    return pushRef(RefType::fromTypeDef(&typeDef, false),
    161                   AnyRef::fromJSObject(*structObj));
    162  }
    163 
    164  bool evalStructNewDefault(JSContext* cx, uint32_t typeIndex) {
    165    Rooted<WasmStructObject*> structObj(
    166        cx, instance().constantStructNewDefault(cx, typeIndex));
    167    if (!structObj) {
    168      return false;
    169    }
    170 
    171    const TypeDef& typeDef = instance().codeMeta().types->type(typeIndex);
    172    return pushRef(RefType::fromTypeDef(&typeDef, false),
    173                   AnyRef::fromJSObject(*structObj));
    174  }
    175 
    176  bool evalArrayNew(JSContext* cx, uint32_t typeIndex) {
    177    uint32_t numElements = popI32();
    178    Rooted<WasmArrayObject*> arrayObj(
    179        cx, instance().constantArrayNewDefault(cx, typeIndex, numElements));
    180    if (!arrayObj) {
    181      return false;
    182    }
    183 
    184    const Val& val = stack.back();
    185    arrayObj->fillVal(val, 0, numElements);
    186    stack.popBack();
    187 
    188    const TypeDef& typeDef = instance().codeMeta().types->type(typeIndex);
    189    return pushRef(RefType::fromTypeDef(&typeDef, false),
    190                   AnyRef::fromJSObject(*arrayObj));
    191  }
    192 
    193  bool evalArrayNewDefault(JSContext* cx, uint32_t typeIndex) {
    194    uint32_t numElements = popI32();
    195    Rooted<WasmArrayObject*> arrayObj(
    196        cx, instance().constantArrayNewDefault(cx, typeIndex, numElements));
    197    if (!arrayObj) {
    198      return false;
    199    }
    200 
    201    const TypeDef& typeDef = instance().codeMeta().types->type(typeIndex);
    202    return pushRef(RefType::fromTypeDef(&typeDef, false),
    203                   AnyRef::fromJSObject(*arrayObj));
    204  }
    205 
    206  bool evalArrayNewFixed(JSContext* cx, uint32_t typeIndex,
    207                         uint32_t numElements) {
    208    Rooted<WasmArrayObject*> arrayObj(
    209        cx, instance().constantArrayNewDefault(cx, typeIndex, numElements));
    210    if (!arrayObj) {
    211      return false;
    212    }
    213 
    214    for (uint32_t forwardIndex = 0; forwardIndex < numElements;
    215         forwardIndex++) {
    216      uint32_t reverseIndex = numElements - forwardIndex - 1;
    217      const Val& val = stack.back();
    218      arrayObj->storeVal(val, reverseIndex);
    219      stack.popBack();
    220    }
    221 
    222    const TypeDef& typeDef = instance().codeMeta().types->type(typeIndex);
    223    return pushRef(RefType::fromTypeDef(&typeDef, false),
    224                   AnyRef::fromJSObject(*arrayObj));
    225  }
    226 
    227  bool evalI31New(JSContext* cx) {
    228    uint32_t value = stack.back().i32();
    229    stack.popBack();
    230    return pushRef(RefType::i31().asNonNullable(),
    231                   AnyRef::fromUint32Truncate(value));
    232  }
    233 
    234  bool evalAnyConvertExtern(JSContext* cx) {
    235    AnyRef ref = stack.back().ref();
    236    stack.popBack();
    237    return pushRef(RefType::extern_(), ref);
    238  }
    239 
    240  bool evalExternConvertAny(JSContext* cx) {
    241    AnyRef ref = stack.back().ref();
    242    stack.popBack();
    243    return pushRef(RefType::any(), ref);
    244  }
    245 };
    246 
    247 bool InitExprInterpreter::evaluate(JSContext* cx, Decoder& d) {
    248 #define CHECK(c)          \
    249  if (!(c)) return false; \
    250  break
    251 
    252  while (true) {
    253    OpBytes op;
    254    if (!d.readOp(&op)) {
    255      return false;
    256    }
    257 
    258    switch (op.b0) {
    259      case uint16_t(Op::End): {
    260        return true;
    261      }
    262      case uint16_t(Op::GlobalGet): {
    263        uint32_t index;
    264        if (!d.readGlobalIndex(&index)) {
    265          return false;
    266        }
    267        CHECK(evalGlobalGet(cx, index));
    268      }
    269      case uint16_t(Op::I32Const): {
    270        int32_t c;
    271        if (!d.readI32Const(&c)) {
    272          return false;
    273        }
    274        CHECK(evalI32Const(c));
    275      }
    276      case uint16_t(Op::I64Const): {
    277        int64_t c;
    278        if (!d.readI64Const(&c)) {
    279          return false;
    280        }
    281        CHECK(evalI64Const(c));
    282      }
    283      case uint16_t(Op::F32Const): {
    284        float c;
    285        if (!d.readF32Const(&c)) {
    286          return false;
    287        }
    288        CHECK(evalF32Const(c));
    289      }
    290      case uint16_t(Op::F64Const): {
    291        double c;
    292        if (!d.readF64Const(&c)) {
    293          return false;
    294        }
    295        CHECK(evalF64Const(c));
    296      }
    297 #ifdef ENABLE_WASM_SIMD
    298      case uint16_t(Op::SimdPrefix): {
    299        MOZ_RELEASE_ASSERT(op.b1 == uint32_t(SimdOp::V128Const));
    300        V128 c;
    301        if (!d.readV128Const(&c)) {
    302          return false;
    303        }
    304        CHECK(evalV128Const(c));
    305      }
    306 #endif
    307      case uint16_t(Op::RefFunc): {
    308        uint32_t funcIndex;
    309        if (!d.readFuncIndex(&funcIndex)) {
    310          return false;
    311        }
    312        CHECK(evalRefFunc(cx, funcIndex));
    313      }
    314      case uint16_t(Op::RefNull): {
    315        RefType type;
    316        if (!d.readRefNull(*types, features, &type)) {
    317          return false;
    318        }
    319        CHECK(evalRefNull(type));
    320      }
    321      case uint16_t(Op::I32Add): {
    322        if (!d.readBinary()) {
    323          return false;
    324        }
    325        CHECK(evalI32Add());
    326      }
    327      case uint16_t(Op::I32Sub): {
    328        if (!d.readBinary()) {
    329          return false;
    330        }
    331        CHECK(evalI32Sub());
    332      }
    333      case uint16_t(Op::I32Mul): {
    334        if (!d.readBinary()) {
    335          return false;
    336        }
    337        CHECK(evalI32Mul());
    338      }
    339      case uint16_t(Op::I64Add): {
    340        if (!d.readBinary()) {
    341          return false;
    342        }
    343        CHECK(evalI64Add());
    344      }
    345      case uint16_t(Op::I64Sub): {
    346        if (!d.readBinary()) {
    347          return false;
    348        }
    349        CHECK(evalI64Sub());
    350      }
    351      case uint16_t(Op::I64Mul): {
    352        if (!d.readBinary()) {
    353          return false;
    354        }
    355        CHECK(evalI64Mul());
    356      }
    357      case uint16_t(Op::GcPrefix): {
    358        switch (op.b1) {
    359          case uint32_t(GcOp::StructNew): {
    360            uint32_t typeIndex;
    361            if (!d.readTypeIndex(&typeIndex)) {
    362              return false;
    363            }
    364            CHECK(evalStructNew(cx, typeIndex));
    365          }
    366          case uint32_t(GcOp::StructNewDefault): {
    367            uint32_t typeIndex;
    368            if (!d.readTypeIndex(&typeIndex)) {
    369              return false;
    370            }
    371            CHECK(evalStructNewDefault(cx, typeIndex));
    372          }
    373          case uint32_t(GcOp::ArrayNew): {
    374            uint32_t typeIndex;
    375            if (!d.readTypeIndex(&typeIndex)) {
    376              return false;
    377            }
    378            CHECK(evalArrayNew(cx, typeIndex));
    379          }
    380          case uint32_t(GcOp::ArrayNewFixed): {
    381            uint32_t typeIndex, len;
    382            if (!d.readTypeIndex(&typeIndex)) {
    383              return false;
    384            }
    385            if (!d.readVarU32(&len)) {
    386              return false;
    387            }
    388            CHECK(evalArrayNewFixed(cx, typeIndex, len));
    389          }
    390          case uint32_t(GcOp::ArrayNewDefault): {
    391            uint32_t typeIndex;
    392            if (!d.readTypeIndex(&typeIndex)) {
    393              return false;
    394            }
    395            CHECK(evalArrayNewDefault(cx, typeIndex));
    396          }
    397          case uint32_t(GcOp::RefI31): {
    398            CHECK(evalI31New(cx));
    399          }
    400          case uint32_t(GcOp::AnyConvertExtern): {
    401            CHECK(evalAnyConvertExtern(cx));
    402          }
    403          case uint32_t(GcOp::ExternConvertAny): {
    404            CHECK(evalExternConvertAny(cx));
    405          }
    406          default: {
    407            MOZ_CRASH();
    408          }
    409        }
    410        break;
    411      }
    412      default: {
    413        MOZ_CRASH();
    414      }
    415    }
    416  }
    417 
    418 #undef CHECK
    419 }
    420 
    421 bool wasm::DecodeConstantExpression(Decoder& d, CodeMetadata* codeMeta,
    422                                    ValType expected, Maybe<LitVal>* literal) {
    423  ValTypeVector locals;
    424  ValidatingOpIter iter(*codeMeta, d, locals, ValidatingOpIter::InitExpr);
    425 
    426  if (!iter.startInitExpr(expected)) {
    427    return false;
    428  }
    429 
    430  // Perform trivial constant recovery, this is done so that codegen may
    431  // generate optimal code for global.get on immutable globals with simple
    432  // initializers.
    433  //
    434  // We simply update the last seen literal value while validating an
    435  // instruction with a literal value, and clear the literal value when
    436  // validating an instruction with a dynamic value. The last value is the
    437  // literal for this init expressions, if any. This is correct because there
    438  // are no drops or control flow allowed in init expressions.
    439  *literal = Nothing();
    440 
    441  while (true) {
    442    OpBytes op;
    443    if (!iter.readOp(&op)) {
    444      return false;
    445    }
    446 
    447    Nothing nothing;
    448    NothingVector nothings{};
    449    ResultType unusedType;
    450 
    451    switch (op.b0) {
    452      case uint16_t(Op::End): {
    453        LabelKind kind;
    454        if (!iter.readEnd(&kind, &unusedType, &nothings, &nothings)) {
    455          return false;
    456        }
    457        MOZ_ASSERT(kind == LabelKind::Body);
    458        iter.popEnd();
    459        if (iter.controlStackEmpty()) {
    460          return iter.endInitExpr();
    461        }
    462        break;
    463      }
    464      case uint16_t(Op::GlobalGet): {
    465        uint32_t index;
    466        if (!iter.readGetGlobal(&index)) {
    467          return false;
    468        }
    469        *literal = Nothing();
    470        break;
    471      }
    472      case uint16_t(Op::I32Const): {
    473        int32_t c;
    474        if (!iter.readI32Const(&c)) {
    475          return false;
    476        }
    477        *literal = Some(LitVal(uint32_t(c)));
    478        break;
    479      }
    480      case uint16_t(Op::I64Const): {
    481        int64_t c;
    482        if (!iter.readI64Const(&c)) {
    483          return false;
    484        }
    485        *literal = Some(LitVal(uint64_t(c)));
    486        break;
    487      }
    488      case uint16_t(Op::F32Const): {
    489        float c;
    490        if (!iter.readF32Const(&c)) {
    491          return false;
    492        }
    493        *literal = Some(LitVal(c));
    494        break;
    495      }
    496      case uint16_t(Op::F64Const): {
    497        double c;
    498        if (!iter.readF64Const(&c)) {
    499          return false;
    500        }
    501        *literal = Some(LitVal(c));
    502        break;
    503      }
    504 #ifdef ENABLE_WASM_SIMD
    505      case uint16_t(Op::SimdPrefix): {
    506        if (!codeMeta->simdAvailable()) {
    507          return d.fail("v128 not enabled");
    508        }
    509        if (op.b1 != uint32_t(SimdOp::V128Const)) {
    510          return iter.unrecognizedOpcode(&op);
    511        }
    512        V128 c;
    513        if (!iter.readV128Const(&c)) {
    514          return false;
    515        }
    516        *literal = Some(LitVal(c));
    517        break;
    518      }
    519 #endif
    520      case uint16_t(Op::RefFunc): {
    521        uint32_t funcIndex;
    522        if (!iter.readRefFunc(&funcIndex)) {
    523          return false;
    524        }
    525        codeMeta->funcs[funcIndex].declareFuncExported(/* eager */ false,
    526                                                       /* canRefFunc */ true);
    527        *literal = Nothing();
    528        break;
    529      }
    530      case uint16_t(Op::RefNull): {
    531        RefType type;
    532        if (!iter.readRefNull(&type)) {
    533          return false;
    534        }
    535        *literal = Some(LitVal(ValType(type)));
    536        break;
    537      }
    538      case uint16_t(Op::I32Add):
    539      case uint16_t(Op::I32Sub):
    540      case uint16_t(Op::I32Mul): {
    541        if (!iter.readBinary(ValType::I32, &nothing, &nothing)) {
    542          return false;
    543        }
    544        *literal = Nothing();
    545        break;
    546      }
    547      case uint16_t(Op::I64Add):
    548      case uint16_t(Op::I64Sub):
    549      case uint16_t(Op::I64Mul): {
    550        if (!iter.readBinary(ValType::I64, &nothing, &nothing)) {
    551          return false;
    552        }
    553        *literal = Nothing();
    554        break;
    555      }
    556      case uint16_t(Op::GcPrefix): {
    557        switch (op.b1) {
    558          case uint32_t(GcOp::StructNew): {
    559            uint32_t typeIndex;
    560            if (!iter.readStructNew(&typeIndex, &nothings)) {
    561              return false;
    562            }
    563            break;
    564          }
    565          case uint32_t(GcOp::StructNewDefault): {
    566            uint32_t typeIndex;
    567            if (!iter.readStructNewDefault(&typeIndex)) {
    568              return false;
    569            }
    570            break;
    571          }
    572          case uint32_t(GcOp::ArrayNew): {
    573            uint32_t typeIndex;
    574            if (!iter.readArrayNew(&typeIndex, &nothing, &nothing)) {
    575              return false;
    576            }
    577            break;
    578          }
    579          case uint32_t(GcOp::ArrayNewFixed): {
    580            uint32_t typeIndex, len;
    581            if (!iter.readArrayNewFixed(&typeIndex, &len, &nothings)) {
    582              return false;
    583            }
    584            break;
    585          }
    586          case uint32_t(GcOp::ArrayNewDefault): {
    587            uint32_t typeIndex;
    588            if (!iter.readArrayNewDefault(&typeIndex, &nothing)) {
    589              return false;
    590            }
    591            break;
    592          }
    593          case uint32_t(GcOp::RefI31): {
    594            Nothing value;
    595            if (!iter.readConversion(ValType::I32,
    596                                     ValType(RefType::i31().asNonNullable()),
    597                                     &value)) {
    598              return false;
    599            }
    600            break;
    601          }
    602          case uint32_t(GcOp::AnyConvertExtern): {
    603            Nothing value;
    604            if (!iter.readRefConversion(RefType::extern_(), RefType::any(),
    605                                        &value)) {
    606              return false;
    607            }
    608            break;
    609          }
    610          case uint32_t(GcOp::ExternConvertAny): {
    611            Nothing value;
    612            if (!iter.readRefConversion(RefType::any(), RefType::extern_(),
    613                                        &value)) {
    614              return false;
    615            }
    616            break;
    617          }
    618          default: {
    619            return iter.unrecognizedOpcode(&op);
    620          }
    621        }
    622        *literal = Nothing();
    623        break;
    624      }
    625      default: {
    626        return iter.unrecognizedOpcode(&op);
    627      }
    628    }
    629  }
    630 }
    631 
    632 bool InitExpr::decodeAndValidate(Decoder& d, CodeMetadata* codeMeta,
    633                                 ValType expected, InitExpr* expr) {
    634  Maybe<LitVal> literal = Nothing();
    635  const uint8_t* exprStart = d.currentPosition();
    636  if (!DecodeConstantExpression(d, codeMeta, expected, &literal)) {
    637    return false;
    638  }
    639  const uint8_t* exprEnd = d.currentPosition();
    640 
    641  if (!expr->bytecode_.append(exprStart, exprEnd)) {
    642    return false;
    643  }
    644 
    645  MOZ_ASSERT(expr->kind_ == InitExprKind::None);
    646  expr->type_ = expected;
    647 
    648  if (literal) {
    649    literal->unsafeSetType(expected);
    650    expr->kind_ = InitExprKind::Literal;
    651    expr->literal_ = *literal;
    652    return true;
    653  }
    654 
    655  expr->kind_ = InitExprKind::Variable;
    656  return true;
    657 }
    658 
    659 /* static */ bool InitExpr::decodeAndEvaluate(
    660    JSContext* cx, Handle<WasmInstanceObject*> instanceObj, Decoder& d,
    661    ValType expectedType, MutableHandleVal result) {
    662  InitExprInterpreter interp(cx, instanceObj);
    663  if (!interp.evaluate(cx, d)) {
    664    return false;
    665  }
    666 
    667  Val interpResult = interp.result();
    668  // The interpreter evaluation stack does not track the precise type of values.
    669  // Users of the result expect the precise type though, so we need to overwrite
    670  // it with the one we validated with.
    671  interpResult.unsafeSetType(expectedType);
    672  result.set(interpResult);
    673  return true;
    674 }
    675 
    676 bool InitExpr::evaluate(JSContext* cx, Handle<WasmInstanceObject*> instanceObj,
    677                        MutableHandleVal result) const {
    678  MOZ_ASSERT(kind_ != InitExprKind::None);
    679 
    680  if (isLiteral()) {
    681    result.set(Val(literal()));
    682    return true;
    683  }
    684 
    685  UniqueChars error;
    686  Decoder d(bytecode_.begin(), bytecode_.end(), 0, &error);
    687  if (!decodeAndEvaluate(cx, instanceObj, d, type_, result)) {
    688    // This expression should have been validated already. So we should only be
    689    // able to OOM, which is reported by having no error message.
    690    MOZ_RELEASE_ASSERT(!error);
    691    return false;
    692  }
    693 
    694  return true;
    695 }
    696 
    697 bool InitExpr::clone(const InitExpr& src) {
    698  kind_ = src.kind_;
    699  MOZ_ASSERT(bytecode_.empty());
    700  if (!bytecode_.appendAll(src.bytecode_)) {
    701    return false;
    702  }
    703  literal_ = src.literal_;
    704  type_ = src.type_;
    705  return true;
    706 }
    707 
    708 size_t InitExpr::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
    709  return bytecode_.sizeOfExcludingThis(mallocSizeOf);
    710 }