tor-browser

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

WasmValue.cpp (27702B)


      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/WasmValue.h"
     20 
     21 #include "jsmath.h"
     22 #include "js/friend/ErrorMessages.h"  // JSMSG_*
     23 #include "js/Printf.h"
     24 #include "js/Value.h"
     25 #include "vm/BigIntType.h"
     26 #include "vm/GlobalObject.h"
     27 #include "vm/JSContext.h"
     28 #include "vm/JSFunction.h"
     29 #include "vm/JSObject.h"
     30 #include "vm/StringType.h"
     31 #include "wasm/WasmGcObject.h"
     32 #include "wasm/WasmJS.h"
     33 #include "wasm/WasmLog.h"
     34 #include "wasm/WasmTypeDef.h"
     35 
     36 #include "vm/JSObject-inl.h"
     37 
     38 using namespace js;
     39 using namespace js::wasm;
     40 
     41 Val::Val(const LitVal& val) {
     42  type_ = val.type();
     43  switch (type_.kind()) {
     44    case ValType::I32:
     45      cell_.i32_ = val.i32();
     46      return;
     47    case ValType::F32:
     48      cell_.f32_ = val.f32();
     49      return;
     50    case ValType::I64:
     51      cell_.i64_ = val.i64();
     52      return;
     53    case ValType::F64:
     54      cell_.f64_ = val.f64();
     55      return;
     56    case ValType::V128:
     57      cell_.v128_ = val.v128();
     58      return;
     59    case ValType::Ref:
     60      cell_.ref_ = val.ref();
     61      return;
     62  }
     63  MOZ_CRASH();
     64 }
     65 
     66 void Val::initFromRootedLocation(ValType type, const void* loc) {
     67  MOZ_ASSERT(!type_.isValid());
     68  type_ = type;
     69  memset(&cell_, 0, sizeof(Cell));
     70  memcpy(&cell_, loc, type_.size());
     71 }
     72 
     73 void Val::initFromHeapLocation(ValType type, const void* loc) {
     74  MOZ_ASSERT(!type_.isValid());
     75  type_ = type;
     76  memset(&cell_, 0, sizeof(Cell));
     77  readFromHeapLocation(loc);
     78 }
     79 
     80 void Val::writeToRootedLocation(void* loc, bool mustWrite64) const {
     81  memcpy(loc, &cell_, type_.size());
     82  if (mustWrite64 && type_.size() == 4) {
     83    memset((uint8_t*)(loc) + 4, 0, 4);
     84  }
     85 }
     86 
     87 void Val::readFromHeapLocation(const void* loc) {
     88  memcpy(&cell_, loc, type_.size());
     89 }
     90 
     91 void Val::writeToHeapLocation(void* loc) const {
     92  if (isAnyRef()) {
     93    *((GCPtr<AnyRef>*)loc) = toAnyRef();
     94    return;
     95  }
     96  memcpy(loc, &cell_, type_.size());
     97 }
     98 
     99 bool Val::fromJSValue(JSContext* cx, ValType targetType, HandleValue val,
    100                      MutableHandleVal rval) {
    101  rval.get().type_ = targetType;
    102  // No pre/post barrier needed as rval is rooted
    103  return ToWebAssemblyValue(cx, val, targetType, &rval.get().cell_,
    104                            targetType.size() == 8);
    105 }
    106 
    107 bool Val::toJSValue(JSContext* cx, MutableHandleValue rval) const {
    108  return ToJSValue(cx, &cell_, type_, rval);
    109 }
    110 
    111 void Val::trace(JSTracer* trc) const {
    112  if (isAnyRef()) {
    113    TraceManuallyBarrieredEdge(trc, &toAnyRef(), "anyref");
    114  }
    115 }
    116 
    117 bool CheckFuncRefValue(JSContext* cx, HandleValue v, MutableHandleAnyRef vp) {
    118  if (v.isNull()) {
    119    vp.set(AnyRef::null());
    120    return true;
    121  }
    122 
    123  if (v.isObject()) {
    124    JSObject& obj = v.toObject();
    125    if (obj.is<JSFunction>()) {
    126      JSFunction* f = &obj.as<JSFunction>();
    127      if (f->isWasm()) {
    128        vp.set(AnyRef::fromJSObject(*f));
    129        return true;
    130      }
    131    }
    132  }
    133 
    134  JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
    135                           JSMSG_WASM_BAD_FUNCREF_VALUE);
    136  return false;
    137 }
    138 
    139 bool CheckAnyRefValue(JSContext* cx, HandleValue v, MutableHandleAnyRef vp) {
    140  if (!AnyRef::fromJSValue(cx, v, vp)) {
    141    MOZ_ASSERT(cx->isThrowingOutOfMemory());
    142    return false;
    143  }
    144  return true;
    145 }
    146 
    147 bool CheckNullFuncRefValue(JSContext* cx, HandleValue v,
    148                           MutableHandleAnyRef vp) {
    149  if (!v.isNull()) {
    150    JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
    151                             JSMSG_WASM_BAD_NULL_FUNCREF_VALUE);
    152    return false;
    153  }
    154  vp.set(AnyRef::null());
    155  return true;
    156 }
    157 
    158 bool CheckNullExnRefValue(JSContext* cx, HandleValue v,
    159                          MutableHandleAnyRef vp) {
    160  if (!v.isNull()) {
    161    JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
    162                             JSMSG_WASM_BAD_NULL_EXNREF_VALUE);
    163    return false;
    164  }
    165 
    166  vp.set(AnyRef::null());
    167  return true;
    168 }
    169 
    170 bool CheckNullExternRefValue(JSContext* cx, HandleValue v,
    171                             MutableHandleAnyRef vp) {
    172  if (!v.isNull()) {
    173    JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
    174                             JSMSG_WASM_BAD_NULL_EXTERNREF_VALUE);
    175    return false;
    176  }
    177 
    178  vp.set(AnyRef::null());
    179  return true;
    180 }
    181 
    182 bool CheckNullRefValue(JSContext* cx, HandleValue v, MutableHandleAnyRef vp) {
    183  if (!v.isNull()) {
    184    JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
    185                             JSMSG_WASM_BAD_NULL_ANYREF_VALUE);
    186    return false;
    187  }
    188 
    189  vp.set(AnyRef::null());
    190  return true;
    191 }
    192 
    193 bool CheckEqRefValue(JSContext* cx, HandleValue v, MutableHandleAnyRef vp) {
    194  if (!AnyRef::fromJSValue(cx, v, vp)) {
    195    MOZ_ASSERT(cx->isThrowingOutOfMemory());
    196    return false;
    197  }
    198 
    199  if (vp.isNull() || vp.isI31() ||
    200      (vp.isJSObject() && vp.toJSObject().is<WasmGcObject>())) {
    201    return true;
    202  }
    203 
    204  JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
    205                           JSMSG_WASM_BAD_EQREF_VALUE);
    206  return false;
    207 }
    208 
    209 bool CheckI31RefValue(JSContext* cx, HandleValue v, MutableHandleAnyRef vp) {
    210  if (!AnyRef::fromJSValue(cx, v, vp)) {
    211    MOZ_ASSERT(cx->isThrowingOutOfMemory());
    212    return false;
    213  }
    214 
    215  if (vp.isNull() || vp.isI31()) {
    216    return true;
    217  }
    218 
    219  JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
    220                           JSMSG_WASM_BAD_I31REF_VALUE);
    221  return false;
    222 }
    223 
    224 bool CheckStructRefValue(JSContext* cx, HandleValue v, MutableHandleAnyRef vp) {
    225  if (v.isNull()) {
    226    vp.set(AnyRef::null());
    227    return true;
    228  }
    229 
    230  if (v.isObject()) {
    231    JSObject& obj = v.toObject();
    232    if (obj.is<WasmStructObject>()) {
    233      vp.set(AnyRef::fromJSObject(obj.as<WasmStructObject>()));
    234      return true;
    235    }
    236  }
    237 
    238  JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
    239                           JSMSG_WASM_BAD_STRUCTREF_VALUE);
    240  return false;
    241 }
    242 
    243 bool CheckArrayRefValue(JSContext* cx, HandleValue v, MutableHandleAnyRef vp) {
    244  if (v.isNull()) {
    245    vp.set(AnyRef::null());
    246    return true;
    247  }
    248 
    249  if (v.isObject()) {
    250    JSObject& obj = v.toObject();
    251    if (obj.is<WasmArrayObject>()) {
    252      vp.set(AnyRef::fromJSObject(obj.as<WasmArrayObject>()));
    253      return true;
    254    }
    255  }
    256 
    257  JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
    258                           JSMSG_WASM_BAD_ARRAYREF_VALUE);
    259  return false;
    260 }
    261 
    262 bool CheckTypeRefValue(JSContext* cx, const TypeDef* typeDef, HandleValue v,
    263                       MutableHandleAnyRef vp) {
    264  if (v.isNull()) {
    265    vp.set(AnyRef::null());
    266    return true;
    267  }
    268 
    269  if (v.isObject()) {
    270    JSObject& obj = v.toObject();
    271    if (obj.is<WasmGcObject>() &&
    272        obj.as<WasmGcObject>().isRuntimeSubtypeOf(typeDef)) {
    273      vp.set(AnyRef::fromJSObject(obj.as<WasmGcObject>()));
    274      return true;
    275    }
    276    if (obj.is<JSFunction>() && obj.as<JSFunction>().isWasm()) {
    277      JSFunction& funcObj = obj.as<JSFunction>();
    278      if (TypeDef::isSubTypeOf(funcObj.wasmTypeDef(), typeDef)) {
    279        vp.set(AnyRef::fromJSObject(funcObj));
    280        return true;
    281      }
    282    }
    283  }
    284 
    285  JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
    286                           JSMSG_WASM_BAD_TYPEREF_VALUE);
    287  return false;
    288 }
    289 
    290 bool wasm::CheckRefType(JSContext* cx, RefType targetType, HandleValue v,
    291                        MutableHandleAnyRef vp) {
    292  if (!targetType.isNullable() && v.isNull()) {
    293    JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
    294                             JSMSG_WASM_BAD_REF_NONNULLABLE_VALUE);
    295    return false;
    296  }
    297 
    298  switch (targetType.kind()) {
    299    case RefType::Func:
    300      return CheckFuncRefValue(cx, v, vp);
    301    case RefType::Extern:
    302      return AnyRef::fromJSValue(cx, v, vp);
    303    case RefType::Exn:
    304      // Break to the non-exposable case
    305      break;
    306    case RefType::Any:
    307      return CheckAnyRefValue(cx, v, vp);
    308    case RefType::NoFunc:
    309      return CheckNullFuncRefValue(cx, v, vp);
    310    case RefType::NoExn:
    311      return CheckNullExnRefValue(cx, v, vp);
    312    case RefType::NoExtern:
    313      return CheckNullExternRefValue(cx, v, vp);
    314    case RefType::None:
    315      return CheckNullRefValue(cx, v, vp);
    316    case RefType::Eq:
    317      return CheckEqRefValue(cx, v, vp);
    318    case RefType::I31:
    319      return CheckI31RefValue(cx, v, vp);
    320    case RefType::Struct:
    321      return CheckStructRefValue(cx, v, vp);
    322    case RefType::Array:
    323      return CheckArrayRefValue(cx, v, vp);
    324    case RefType::TypeRef:
    325      return CheckTypeRefValue(cx, targetType.typeDef(), v, vp);
    326  }
    327 
    328  MOZ_ASSERT(!ValType(targetType).isExposable());
    329  JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
    330                           JSMSG_WASM_BAD_VAL_TYPE);
    331  return false;
    332 }
    333 
    334 bool wasm::CheckRefType(JSContext* cx, RefType targetType, HandleValue v) {
    335  RootedAnyRef any(cx, AnyRef::null());
    336  return CheckRefType(cx, targetType, v, &any);
    337 }
    338 
    339 class wasm::NoDebug {
    340 public:
    341  template <typename T>
    342  static void print(T v) {}
    343 };
    344 
    345 class wasm::DebugCodegenVal {
    346  template <typename T>
    347  static void print(const char* fmt, T v) {
    348    DebugCodegen(DebugChannel::Function, fmt, v);
    349  }
    350 
    351 public:
    352  static void print(int32_t v) { print(" i32(%d)", v); }
    353  static void print(int64_t v) { print(" i64(%" PRId64 ")", v); }
    354  static void print(float v) { print(" f32(%f)", v); }
    355  static void print(double v) { print(" f64(%lf)", v); }
    356  static void print(void* v) { print(" ptr(%p)", v); }
    357 };
    358 
    359 template bool wasm::ToJSValue<NoDebug>(JSContext* cx, const void* src,
    360                                       StorageType type, MutableHandleValue dst,
    361                                       CoercionLevel level);
    362 template bool wasm::ToJSValue<DebugCodegenVal>(JSContext* cx, const void* src,
    363                                               StorageType type,
    364                                               MutableHandleValue dst,
    365                                               CoercionLevel level);
    366 template bool wasm::ToJSValueMayGC<NoDebug>(StorageType type);
    367 template bool wasm::ToJSValueMayGC<DebugCodegenVal>(StorageType type);
    368 
    369 template bool wasm::ToWebAssemblyValue<NoDebug>(JSContext* cx, HandleValue val,
    370                                                ValType type, void* loc,
    371                                                bool mustWrite64,
    372                                                CoercionLevel level);
    373 template bool wasm::ToWebAssemblyValue<DebugCodegenVal>(JSContext* cx,
    374                                                        HandleValue val,
    375                                                        ValType type, void* loc,
    376                                                        bool mustWrite64,
    377                                                        CoercionLevel level);
    378 template bool wasm::ToJSValue<NoDebug>(JSContext* cx, const void* src,
    379                                       ValType type, MutableHandleValue dst,
    380                                       CoercionLevel level);
    381 template bool wasm::ToJSValue<DebugCodegenVal>(JSContext* cx, const void* src,
    382                                               ValType type,
    383                                               MutableHandleValue dst,
    384                                               CoercionLevel level);
    385 template bool wasm::ToJSValueMayGC<NoDebug>(ValType type);
    386 template bool wasm::ToJSValueMayGC<DebugCodegenVal>(ValType type);
    387 
    388 template <typename Debug = NoDebug>
    389 bool ToWebAssemblyValue_i32(JSContext* cx, HandleValue val, int32_t* loc,
    390                            bool mustWrite64) {
    391  bool ok = ToInt32(cx, val, loc);
    392  if (ok && mustWrite64) {
    393 #if defined(JS_CODEGEN_MIPS64)
    394    loc[1] = loc[0] >> 31;
    395 #else
    396    loc[1] = 0;
    397 #endif
    398  }
    399  Debug::print(*loc);
    400  return ok;
    401 }
    402 
    403 template <typename Debug = NoDebug>
    404 bool ToWebAssemblyValue_i64(JSContext* cx, HandleValue val, int64_t* loc,
    405                            bool mustWrite64) {
    406  MOZ_ASSERT(mustWrite64);
    407  JS_TRY_VAR_OR_RETURN_FALSE(cx, *loc, ToBigInt64(cx, val));
    408  Debug::print(*loc);
    409  return true;
    410 }
    411 
    412 template <typename Debug = NoDebug>
    413 bool ToWebAssemblyValue_f32(JSContext* cx, HandleValue val, float* loc,
    414                            bool mustWrite64) {
    415  bool ok = RoundFloat32(cx, val, loc);
    416  if (ok && mustWrite64) {
    417    loc[1] = 0.0;
    418  }
    419  Debug::print(*loc);
    420  return ok;
    421 }
    422 
    423 template <typename Debug = NoDebug>
    424 bool ToWebAssemblyValue_f64(JSContext* cx, HandleValue val, double* loc,
    425                            bool mustWrite64) {
    426  MOZ_ASSERT(mustWrite64);
    427  bool ok = ToNumber(cx, val, loc);
    428  Debug::print(*loc);
    429  return ok;
    430 }
    431 
    432 template <typename Debug = NoDebug>
    433 bool ToWebAssemblyValue_externref(JSContext* cx, HandleValue val, void** loc,
    434                                  bool mustWrite64) {
    435  RootedAnyRef result(cx, AnyRef::null());
    436  if (!AnyRef::fromJSValue(cx, val, &result)) {
    437    return false;
    438  }
    439  loc[0] = result.get().forCompiledCode();
    440 #ifndef JS_64BIT
    441  if (mustWrite64) {
    442    loc[1] = nullptr;
    443  }
    444 #endif
    445  Debug::print(*loc);
    446  return true;
    447 }
    448 
    449 template <typename Debug = NoDebug>
    450 bool ToWebAssemblyValue_nullexnref(JSContext* cx, HandleValue val, void** loc,
    451                                   bool mustWrite64) {
    452  RootedAnyRef result(cx, AnyRef::null());
    453  if (!CheckNullExnRefValue(cx, val, &result)) {
    454    return false;
    455  }
    456  loc[0] = result.get().forCompiledCode();
    457 #ifndef JS_64BIT
    458  if (mustWrite64) {
    459    loc[1] = nullptr;
    460  }
    461 #endif
    462  Debug::print(*loc);
    463  return true;
    464 }
    465 
    466 template <typename Debug = NoDebug>
    467 bool ToWebAssemblyValue_nullexternref(JSContext* cx, HandleValue val,
    468                                      void** loc, bool mustWrite64) {
    469  RootedAnyRef result(cx, AnyRef::null());
    470  if (!CheckNullExternRefValue(cx, val, &result)) {
    471    return false;
    472  }
    473  loc[0] = result.get().forCompiledCode();
    474 #ifndef JS_64BIT
    475  if (mustWrite64) {
    476    loc[1] = nullptr;
    477  }
    478 #endif
    479  Debug::print(*loc);
    480  return true;
    481 }
    482 
    483 template <typename Debug = NoDebug>
    484 bool ToWebAssemblyValue_funcref(JSContext* cx, HandleValue val, void** loc,
    485                                bool mustWrite64) {
    486  RootedAnyRef result(cx, AnyRef::null());
    487  if (!CheckFuncRefValue(cx, val, &result)) {
    488    return false;
    489  }
    490  loc[0] = result.get().forCompiledCode();
    491 #ifndef JS_64BIT
    492  if (mustWrite64) {
    493    loc[1] = nullptr;
    494  }
    495 #endif
    496  Debug::print(*loc);
    497  return true;
    498 }
    499 
    500 template <typename Debug = NoDebug>
    501 bool ToWebAssemblyValue_nullfuncref(JSContext* cx, HandleValue val, void** loc,
    502                                    bool mustWrite64) {
    503  RootedAnyRef result(cx, AnyRef::null());
    504  if (!CheckNullFuncRefValue(cx, val, &result)) {
    505    return false;
    506  }
    507  loc[0] = result.get().forCompiledCode();
    508 #ifndef JS_64BIT
    509  if (mustWrite64) {
    510    loc[1] = nullptr;
    511  }
    512 #endif
    513  Debug::print(*loc);
    514  return true;
    515 }
    516 
    517 template <typename Debug = NoDebug>
    518 bool ToWebAssemblyValue_anyref(JSContext* cx, HandleValue val, void** loc,
    519                               bool mustWrite64) {
    520  RootedAnyRef result(cx, AnyRef::null());
    521  if (!CheckAnyRefValue(cx, val, &result)) {
    522    return false;
    523  }
    524  loc[0] = result.get().forCompiledCode();
    525 #ifndef JS_64BIT
    526  if (mustWrite64) {
    527    loc[1] = nullptr;
    528  }
    529 #endif
    530  Debug::print(*loc);
    531  return true;
    532 }
    533 
    534 template <typename Debug = NoDebug>
    535 bool ToWebAssemblyValue_nullref(JSContext* cx, HandleValue val, void** loc,
    536                                bool mustWrite64) {
    537  RootedAnyRef result(cx, AnyRef::null());
    538  if (!CheckNullRefValue(cx, val, &result)) {
    539    return false;
    540  }
    541  loc[0] = result.get().forCompiledCode();
    542 #ifndef JS_64BIT
    543  if (mustWrite64) {
    544    loc[1] = nullptr;
    545  }
    546 #endif
    547  Debug::print(*loc);
    548  return true;
    549 }
    550 
    551 template <typename Debug = NoDebug>
    552 bool ToWebAssemblyValue_eqref(JSContext* cx, HandleValue val, void** loc,
    553                              bool mustWrite64) {
    554  RootedAnyRef result(cx, AnyRef::null());
    555  if (!CheckEqRefValue(cx, val, &result)) {
    556    return false;
    557  }
    558  loc[0] = result.get().forCompiledCode();
    559 #ifndef JS_64BIT
    560  if (mustWrite64) {
    561    loc[1] = nullptr;
    562  }
    563 #endif
    564  Debug::print(*loc);
    565  return true;
    566 }
    567 
    568 template <typename Debug = NoDebug>
    569 bool ToWebAssemblyValue_i31ref(JSContext* cx, HandleValue val, void** loc,
    570                               bool mustWrite64) {
    571  RootedAnyRef result(cx, AnyRef::null());
    572  if (!CheckI31RefValue(cx, val, &result)) {
    573    return false;
    574  }
    575  loc[0] = result.get().forCompiledCode();
    576 #ifndef JS_64BIT
    577  if (mustWrite64) {
    578    loc[1] = nullptr;
    579  }
    580 #endif
    581  Debug::print(*loc);
    582  return true;
    583 }
    584 
    585 template <typename Debug = NoDebug>
    586 bool ToWebAssemblyValue_structref(JSContext* cx, HandleValue val, void** loc,
    587                                  bool mustWrite64) {
    588  RootedAnyRef result(cx, AnyRef::null());
    589  if (!CheckStructRefValue(cx, val, &result)) {
    590    return false;
    591  }
    592  loc[0] = result.get().forCompiledCode();
    593 #ifndef JS_64BIT
    594  if (mustWrite64) {
    595    loc[1] = nullptr;
    596  }
    597 #endif
    598  Debug::print(*loc);
    599  return true;
    600 }
    601 
    602 template <typename Debug = NoDebug>
    603 bool ToWebAssemblyValue_arrayref(JSContext* cx, HandleValue val, void** loc,
    604                                 bool mustWrite64) {
    605  RootedAnyRef result(cx, AnyRef::null());
    606  if (!CheckArrayRefValue(cx, val, &result)) {
    607    return false;
    608  }
    609  loc[0] = result.get().forCompiledCode();
    610 #ifndef JS_64BIT
    611  if (mustWrite64) {
    612    loc[1] = nullptr;
    613  }
    614 #endif
    615  Debug::print(*loc);
    616  return true;
    617 }
    618 
    619 template <typename Debug = NoDebug>
    620 bool ToWebAssemblyValue_typeref(JSContext* cx, const TypeDef* typeDef,
    621                                HandleValue val, void** loc, bool mustWrite64) {
    622  RootedAnyRef result(cx, AnyRef::null());
    623  if (!CheckTypeRefValue(cx, typeDef, val, &result)) {
    624    return false;
    625  }
    626  loc[0] = result.get().forCompiledCode();
    627 #ifndef JS_64BIT
    628  if (mustWrite64) {
    629    loc[1] = nullptr;
    630  }
    631 #endif
    632  Debug::print(*loc);
    633  return true;
    634 }
    635 
    636 bool ToWebAssemblyValue_lossless(JSContext* cx, HandleValue val, ValType type,
    637                                 void* loc, bool mustWrite64) {
    638  if (!val.isObject() || !val.toObject().is<WasmGlobalObject>()) {
    639    return false;
    640  }
    641  Rooted<WasmGlobalObject*> srcVal(cx, &val.toObject().as<WasmGlobalObject>());
    642 
    643  if (srcVal->type() != type) {
    644    return false;
    645  }
    646 
    647  srcVal->val().get().writeToRootedLocation(loc, mustWrite64);
    648  return true;
    649 }
    650 
    651 template <typename Debug>
    652 bool wasm::ToWebAssemblyValue(JSContext* cx, HandleValue val, ValType type,
    653                              void* loc, bool mustWrite64,
    654                              CoercionLevel level) {
    655  if (level == CoercionLevel::Lossless &&
    656      ToWebAssemblyValue_lossless(cx, val, type.valType(), (void*)loc,
    657                                  mustWrite64)) {
    658    return true;
    659  }
    660 
    661  switch (type.kind()) {
    662    case ValType::I32:
    663      return ToWebAssemblyValue_i32<Debug>(cx, val, (int32_t*)loc, mustWrite64);
    664    case ValType::I64:
    665      return ToWebAssemblyValue_i64<Debug>(cx, val, (int64_t*)loc, mustWrite64);
    666    case ValType::F32:
    667      return ToWebAssemblyValue_f32<Debug>(cx, val, (float*)loc, mustWrite64);
    668    case ValType::F64:
    669      return ToWebAssemblyValue_f64<Debug>(cx, val, (double*)loc, mustWrite64);
    670    case ValType::V128:
    671      break;
    672    case ValType::Ref:
    673      if (!type.isNullable() && val.isNull()) {
    674        JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
    675                                 JSMSG_WASM_BAD_REF_NONNULLABLE_VALUE);
    676        return false;
    677      }
    678      switch (type.refTypeKind()) {
    679        case RefType::Func:
    680          return ToWebAssemblyValue_funcref<Debug>(cx, val, (void**)loc,
    681                                                   mustWrite64);
    682        case RefType::Extern:
    683          return ToWebAssemblyValue_externref<Debug>(cx, val, (void**)loc,
    684                                                     mustWrite64);
    685        case RefType::Exn:
    686          // Break to the non-exposable case
    687          break;
    688        case RefType::Any:
    689          return ToWebAssemblyValue_anyref<Debug>(cx, val, (void**)loc,
    690                                                  mustWrite64);
    691        case RefType::NoFunc:
    692          return ToWebAssemblyValue_nullfuncref<Debug>(cx, val, (void**)loc,
    693                                                       mustWrite64);
    694        case RefType::NoExn:
    695          return ToWebAssemblyValue_nullexnref<Debug>(cx, val, (void**)loc,
    696                                                      mustWrite64);
    697        case RefType::NoExtern:
    698          return ToWebAssemblyValue_nullexternref<Debug>(cx, val, (void**)loc,
    699                                                         mustWrite64);
    700        case RefType::None:
    701          return ToWebAssemblyValue_nullref<Debug>(cx, val, (void**)loc,
    702                                                   mustWrite64);
    703        case RefType::Eq:
    704          return ToWebAssemblyValue_eqref<Debug>(cx, val, (void**)loc,
    705                                                 mustWrite64);
    706        case RefType::I31:
    707          return ToWebAssemblyValue_i31ref<Debug>(cx, val, (void**)loc,
    708                                                  mustWrite64);
    709        case RefType::Struct:
    710          return ToWebAssemblyValue_structref<Debug>(cx, val, (void**)loc,
    711                                                     mustWrite64);
    712        case RefType::Array:
    713          return ToWebAssemblyValue_arrayref<Debug>(cx, val, (void**)loc,
    714                                                    mustWrite64);
    715        case RefType::TypeRef:
    716          return ToWebAssemblyValue_typeref<Debug>(cx, type.typeDef(), val,
    717                                                   (void**)loc, mustWrite64);
    718      }
    719  }
    720 
    721  MOZ_ASSERT(!type.isExposable());
    722  JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
    723                           JSMSG_WASM_BAD_VAL_TYPE);
    724  return false;
    725 }
    726 
    727 template <typename Debug = NoDebug>
    728 bool ToJSValue_i8(JSContext* cx, int8_t src, MutableHandleValue dst) {
    729  dst.set(Int32Value(src));
    730  Debug::print(src);
    731  return true;
    732 }
    733 
    734 template <typename Debug = NoDebug>
    735 bool ToJSValue_i16(JSContext* cx, int16_t src, MutableHandleValue dst) {
    736  dst.set(Int32Value(src));
    737  Debug::print(src);
    738  return true;
    739 }
    740 
    741 template <typename Debug = NoDebug>
    742 bool ToJSValue_i32(JSContext* cx, int32_t src, MutableHandleValue dst) {
    743  dst.set(Int32Value(src));
    744  Debug::print(src);
    745  return true;
    746 }
    747 
    748 template <typename Debug = NoDebug>
    749 bool ToJSValue_i64(JSContext* cx, int64_t src, MutableHandleValue dst) {
    750  // If bi is manipulated other than test & storing, it would need
    751  // to be rooted here.
    752  BigInt* bi = BigInt::createFromInt64(cx, src);
    753  if (!bi) {
    754    return false;
    755  }
    756  dst.set(BigIntValue(bi));
    757  Debug::print(src);
    758  return true;
    759 }
    760 
    761 template <typename Debug = NoDebug>
    762 bool ToJSValue_f32(JSContext* cx, float src, MutableHandleValue dst) {
    763  dst.set(JS::CanonicalizedDoubleValue(src));
    764  Debug::print(src);
    765  return true;
    766 }
    767 
    768 template <typename Debug = NoDebug>
    769 bool ToJSValue_f64(JSContext* cx, double src, MutableHandleValue dst) {
    770  dst.set(JS::CanonicalizedDoubleValue(src));
    771  Debug::print(src);
    772  return true;
    773 }
    774 
    775 template <typename Debug = NoDebug>
    776 bool ToJSValue_funcref(JSContext* cx, void* src, MutableHandleValue dst) {
    777  dst.set(UnboxFuncRef(FuncRef::fromCompiledCode(src)));
    778  Debug::print(src);
    779  return true;
    780 }
    781 
    782 template <typename Debug = NoDebug>
    783 bool ToJSValue_externref(JSContext* cx, void* src, MutableHandleValue dst) {
    784  dst.set(AnyRef::fromCompiledCode(src).toJSValue());
    785  Debug::print(src);
    786  return true;
    787 }
    788 
    789 template <typename Debug = NoDebug>
    790 bool ToJSValue_anyref(JSContext* cx, void* src, MutableHandleValue dst) {
    791  dst.set(AnyRef::fromCompiledCode(src).toJSValue());
    792  Debug::print(src);
    793  return true;
    794 }
    795 
    796 template <typename Debug = NoDebug>
    797 bool ToJSValue_lossless(JSContext* cx, const void* src, MutableHandleValue dst,
    798                        ValType type) {
    799  RootedVal srcVal(cx);
    800  srcVal.get().initFromRootedLocation(type, src);
    801  RootedObject prototype(
    802      cx, GlobalObject::getOrCreatePrototype(cx, JSProto_WasmGlobal));
    803  Rooted<WasmGlobalObject*> srcGlobal(
    804      cx, WasmGlobalObject::create(cx, srcVal, false, prototype));
    805  if (!srcGlobal) {
    806    return false;
    807  }
    808  dst.set(ObjectValue(*srcGlobal.get()));
    809  return true;
    810 }
    811 
    812 template <typename Debug>
    813 bool wasm::ToJSValue(JSContext* cx, const void* src, StorageType type,
    814                     MutableHandleValue dst, CoercionLevel level) {
    815  if (level == CoercionLevel::Lossless) {
    816    MOZ_ASSERT(type.isValType());
    817    return ToJSValue_lossless(cx, src, dst, type.valType());
    818  }
    819 
    820  switch (type.kind()) {
    821    case StorageType::I8:
    822      return ToJSValue_i8<Debug>(cx, *reinterpret_cast<const int8_t*>(src),
    823                                 dst);
    824    case StorageType::I16:
    825      return ToJSValue_i16<Debug>(cx, *reinterpret_cast<const int16_t*>(src),
    826                                  dst);
    827    case StorageType::I32:
    828      return ToJSValue_i32<Debug>(cx, *reinterpret_cast<const int32_t*>(src),
    829                                  dst);
    830    case StorageType::I64:
    831      return ToJSValue_i64<Debug>(cx, *reinterpret_cast<const int64_t*>(src),
    832                                  dst);
    833    case StorageType::F32:
    834      return ToJSValue_f32<Debug>(cx, *reinterpret_cast<const float*>(src),
    835                                  dst);
    836    case StorageType::F64:
    837      return ToJSValue_f64<Debug>(cx, *reinterpret_cast<const double*>(src),
    838                                  dst);
    839    case StorageType::V128:
    840      break;
    841    case StorageType::Ref:
    842      switch (type.refType().hierarchy()) {
    843        case RefTypeHierarchy::Func:
    844          return ToJSValue_funcref<Debug>(
    845              cx, *reinterpret_cast<void* const*>(src), dst);
    846        case RefTypeHierarchy::Exn:
    847          // Break to the non-exposable case
    848          break;
    849        case RefTypeHierarchy::Extern:
    850          return ToJSValue_externref<Debug>(
    851              cx, *reinterpret_cast<void* const*>(src), dst);
    852        case RefTypeHierarchy::Any:
    853          return ToJSValue_anyref<Debug>(
    854              cx, *reinterpret_cast<void* const*>(src), dst);
    855          break;
    856      }
    857  }
    858  MOZ_ASSERT(!type.isExposable());
    859  Debug::print(nullptr);
    860  dst.setUndefined();
    861  return true;
    862 }
    863 
    864 template <typename Debug>
    865 bool wasm::ToJSValueMayGC(StorageType type) {
    866  return type.kind() == StorageType::I64;
    867 }
    868 
    869 template <typename Debug>
    870 bool wasm::ToJSValue(JSContext* cx, const void* src, ValType type,
    871                     MutableHandleValue dst, CoercionLevel level) {
    872  return wasm::ToJSValue(cx, src, StorageType(type.packed()), dst, level);
    873 }
    874 
    875 template <typename Debug>
    876 bool wasm::ToJSValueMayGC(ValType type) {
    877  return wasm::ToJSValueMayGC(StorageType(type.packed()));
    878 }
    879 
    880 /* static */
    881 wasm::FuncRef wasm::FuncRef::fromAnyRefUnchecked(AnyRef p) {
    882  if (p.isNull()) {
    883    return FuncRef::null();
    884  }
    885 
    886  MOZ_ASSERT(p.isJSObject() && p.toJSObject().is<JSFunction>());
    887  return FuncRef(&p.toJSObject().as<JSFunction>());
    888 }
    889 
    890 void wasm::FuncRef::trace(JSTracer* trc) const {
    891  if (value_) {
    892    TraceManuallyBarrieredEdge(trc, &value_, "wasm funcref referent");
    893  }
    894 }
    895 
    896 Value wasm::UnboxFuncRef(FuncRef val) {
    897  JSFunction* fn = val.asJSFunction();
    898  Value result;
    899  MOZ_ASSERT_IF(fn, fn->is<JSFunction>());
    900  result.setObjectOrNull(fn);
    901  return result;
    902 }
    903 
    904 #ifdef DEBUG
    905 void wasm::AssertEdgeSourceNotInsideNursery(void* vp) {
    906  Nursery& nursery = TlsContext.get()->runtime()->gc.nursery();
    907  MOZ_ASSERT(!nursery.isInside(vp));
    908 }
    909 #endif