LCOV - code coverage report
Current view: top level - js/src/wasm - WasmJS.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 62 1133 5.5 %
Date: 2017-07-14 16:53:18 Functions: 9 114 7.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       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             : #include "wasm/WasmJS.h"
      20             : 
      21             : #include "mozilla/CheckedInt.h"
      22             : #include "mozilla/Maybe.h"
      23             : #include "mozilla/RangedPtr.h"
      24             : 
      25             : #include "jsprf.h"
      26             : 
      27             : #include "builtin/Promise.h"
      28             : #include "jit/JitOptions.h"
      29             : #include "vm/Interpreter.h"
      30             : #include "vm/String.h"
      31             : #include "vm/StringBuffer.h"
      32             : #include "wasm/WasmCompile.h"
      33             : #include "wasm/WasmInstance.h"
      34             : #include "wasm/WasmModule.h"
      35             : #include "wasm/WasmSignalHandlers.h"
      36             : #include "wasm/WasmValidate.h"
      37             : 
      38             : #include "jsobjinlines.h"
      39             : 
      40             : #include "vm/NativeObject-inl.h"
      41             : 
      42             : using namespace js;
      43             : using namespace js::jit;
      44             : using namespace js::wasm;
      45             : 
      46             : using mozilla::BitwiseCast;
      47             : using mozilla::CheckedInt;
      48             : using mozilla::IsNaN;
      49             : using mozilla::IsSame;
      50             : using mozilla::Nothing;
      51             : using mozilla::RangedPtr;
      52             : 
      53             : bool
      54          12 : wasm::HasCompilerSupport(JSContext* cx)
      55             : {
      56          12 :     if (gc::SystemPageSize() > wasm::PageSize)
      57           0 :         return false;
      58             : 
      59          12 :     if (!cx->jitSupportsFloatingPoint())
      60           0 :         return false;
      61             : 
      62          12 :     if (!cx->jitSupportsUnalignedAccesses())
      63           0 :         return false;
      64             : 
      65          12 :     if (!wasm::HaveSignalHandlers())
      66           0 :         return false;
      67             : 
      68             : #if defined(JS_CODEGEN_NONE) || defined(JS_CODEGEN_ARM64)
      69             :     return false;
      70             : #else
      71          12 :     return true;
      72             : #endif
      73             : }
      74             : 
      75             : bool
      76          12 : wasm::HasSupport(JSContext* cx)
      77             : {
      78          12 :     return cx->options().wasm() && HasCompilerSupport(cx);
      79             : }
      80             : 
      81             : // ============================================================================
      82             : // Imports
      83             : 
      84             : template<typename T>
      85             : JSObject*
      86           0 : wasm::CreateCustomNaNObject(JSContext* cx, T* addr)
      87             : {
      88           0 :     MOZ_ASSERT(IsNaN(*addr));
      89             : 
      90           0 :     RootedObject obj(cx, JS_NewPlainObject(cx));
      91           0 :     if (!obj)
      92           0 :         return nullptr;
      93             : 
      94           0 :     int32_t* i32 = (int32_t*)addr;
      95           0 :     RootedValue intVal(cx, Int32Value(i32[0]));
      96           0 :     if (!JS_DefineProperty(cx, obj, "nan_low", intVal, JSPROP_ENUMERATE))
      97           0 :         return nullptr;
      98             : 
      99             :     if (IsSame<double, T>::value) {
     100           0 :         intVal = Int32Value(i32[1]);
     101           0 :         if (!JS_DefineProperty(cx, obj, "nan_high", intVal, JSPROP_ENUMERATE))
     102           0 :             return nullptr;
     103             :     }
     104             : 
     105           0 :     return obj;
     106             : }
     107             : 
     108             : template JSObject* wasm::CreateCustomNaNObject(JSContext* cx, float* addr);
     109             : template JSObject* wasm::CreateCustomNaNObject(JSContext* cx, double* addr);
     110             : 
     111             : bool
     112           0 : wasm::ReadCustomFloat32NaNObject(JSContext* cx, HandleValue v, uint32_t* ret)
     113             : {
     114           0 :     RootedObject obj(cx, &v.toObject());
     115           0 :     RootedValue val(cx);
     116             : 
     117             :     int32_t i32;
     118           0 :     if (!JS_GetProperty(cx, obj, "nan_low", &val))
     119           0 :         return false;
     120           0 :     if (!ToInt32(cx, val, &i32))
     121           0 :         return false;
     122             : 
     123           0 :     *ret = i32;
     124           0 :     return true;
     125             : }
     126             : 
     127             : bool
     128           0 : wasm::ReadCustomDoubleNaNObject(JSContext* cx, HandleValue v, uint64_t* ret)
     129             : {
     130           0 :     RootedObject obj(cx, &v.toObject());
     131           0 :     RootedValue val(cx);
     132             : 
     133             :     int32_t i32;
     134           0 :     if (!JS_GetProperty(cx, obj, "nan_high", &val))
     135           0 :         return false;
     136           0 :     if (!ToInt32(cx, val, &i32))
     137           0 :         return false;
     138           0 :     *ret = uint32_t(i32);
     139           0 :     *ret <<= 32;
     140             : 
     141           0 :     if (!JS_GetProperty(cx, obj, "nan_low", &val))
     142           0 :         return false;
     143           0 :     if (!ToInt32(cx, val, &i32))
     144           0 :         return false;
     145           0 :     *ret |= uint32_t(i32);
     146             : 
     147           0 :     return true;
     148             : }
     149             : 
     150             : JSObject*
     151           0 : wasm::CreateI64Object(JSContext* cx, int64_t i64)
     152             : {
     153           0 :     RootedObject result(cx, JS_NewPlainObject(cx));
     154           0 :     if (!result)
     155           0 :         return nullptr;
     156             : 
     157           0 :     RootedValue val(cx, Int32Value(uint32_t(i64)));
     158           0 :     if (!JS_DefineProperty(cx, result, "low", val, JSPROP_ENUMERATE))
     159           0 :         return nullptr;
     160             : 
     161           0 :     val = Int32Value(uint32_t(i64 >> 32));
     162           0 :     if (!JS_DefineProperty(cx, result, "high", val, JSPROP_ENUMERATE))
     163           0 :         return nullptr;
     164             : 
     165           0 :     return result;
     166             : }
     167             : 
     168             : bool
     169           0 : wasm::ReadI64Object(JSContext* cx, HandleValue v, int64_t* i64)
     170             : {
     171           0 :     if (!v.isObject()) {
     172           0 :         JS_ReportErrorASCII(cx, "i64 JS value must be an object");
     173           0 :         return false;
     174             :     }
     175             : 
     176           0 :     RootedObject obj(cx, &v.toObject());
     177             : 
     178           0 :     int32_t* i32 = (int32_t*)i64;
     179             : 
     180           0 :     RootedValue val(cx);
     181           0 :     if (!JS_GetProperty(cx, obj, "low", &val))
     182           0 :         return false;
     183           0 :     if (!ToInt32(cx, val, &i32[0]))
     184           0 :         return false;
     185             : 
     186           0 :     if (!JS_GetProperty(cx, obj, "high", &val))
     187           0 :         return false;
     188           0 :     if (!ToInt32(cx, val, &i32[1]))
     189           0 :         return false;
     190             : 
     191           0 :     return true;
     192             : }
     193             : 
     194             : static bool
     195           0 : ThrowBadImportArg(JSContext* cx)
     196             : {
     197           0 :     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_IMPORT_ARG);
     198           0 :     return false;
     199             : }
     200             : 
     201             : static bool
     202           0 : ThrowBadImportType(JSContext* cx, const char* field, const char* str)
     203             : {
     204           0 :     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_IMPORT_TYPE, field, str);
     205           0 :     return false;
     206             : }
     207             : 
     208             : static bool
     209           0 : GetProperty(JSContext* cx, HandleObject obj, const char* chars, MutableHandleValue v)
     210             : {
     211           0 :     JSAtom* atom = AtomizeUTF8Chars(cx, chars, strlen(chars));
     212           0 :     if (!atom)
     213           0 :         return false;
     214             : 
     215           0 :     RootedId id(cx, AtomToId(atom));
     216           0 :     return GetProperty(cx, obj, obj, id, v);
     217             : }
     218             : 
     219             : static bool
     220           0 : GetImports(JSContext* cx,
     221             :            const Module& module,
     222             :            HandleObject importObj,
     223             :            MutableHandle<FunctionVector> funcImports,
     224             :            MutableHandleWasmTableObject tableImport,
     225             :            MutableHandleWasmMemoryObject memoryImport,
     226             :            ValVector* globalImports)
     227             : {
     228           0 :     const ImportVector& imports = module.imports();
     229           0 :     if (!imports.empty() && !importObj)
     230           0 :         return ThrowBadImportArg(cx);
     231             : 
     232           0 :     const Metadata& metadata = module.metadata();
     233             : 
     234           0 :     uint32_t globalIndex = 0;
     235           0 :     const GlobalDescVector& globals = metadata.globals;
     236           0 :     for (const Import& import : imports) {
     237           0 :         RootedValue v(cx);
     238           0 :         if (!GetProperty(cx, importObj, import.module.get(), &v))
     239           0 :             return false;
     240             : 
     241           0 :         if (!v.isObject()) {
     242           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_IMPORT_FIELD,
     243           0 :                                       import.module.get());
     244           0 :             return false;
     245             :         }
     246             : 
     247           0 :         RootedObject obj(cx, &v.toObject());
     248           0 :         if (!GetProperty(cx, obj, import.field.get(), &v))
     249           0 :             return false;
     250             : 
     251           0 :         switch (import.kind) {
     252             :           case DefinitionKind::Function:
     253           0 :             if (!IsFunctionObject(v))
     254           0 :                 return ThrowBadImportType(cx, import.field.get(), "Function");
     255             : 
     256           0 :             if (!funcImports.append(&v.toObject().as<JSFunction>()))
     257           0 :                 return false;
     258             : 
     259           0 :             break;
     260             :           case DefinitionKind::Table:
     261           0 :             if (!v.isObject() || !v.toObject().is<WasmTableObject>())
     262           0 :                 return ThrowBadImportType(cx, import.field.get(), "Table");
     263             : 
     264           0 :             MOZ_ASSERT(!tableImport);
     265           0 :             tableImport.set(&v.toObject().as<WasmTableObject>());
     266           0 :             break;
     267             :           case DefinitionKind::Memory:
     268           0 :             if (!v.isObject() || !v.toObject().is<WasmMemoryObject>())
     269           0 :                 return ThrowBadImportType(cx, import.field.get(), "Memory");
     270             : 
     271           0 :             MOZ_ASSERT(!memoryImport);
     272           0 :             memoryImport.set(&v.toObject().as<WasmMemoryObject>());
     273           0 :             break;
     274             : 
     275             :           case DefinitionKind::Global:
     276           0 :             Val val;
     277           0 :             const GlobalDesc& global = globals[globalIndex++];
     278           0 :             MOZ_ASSERT(global.importIndex() == globalIndex - 1);
     279           0 :             MOZ_ASSERT(!global.isMutable());
     280           0 :             switch (global.type()) {
     281             :               case ValType::I32: {
     282           0 :                 if (!v.isNumber())
     283           0 :                     return ThrowBadImportType(cx, import.field.get(), "Number");
     284             :                 int32_t i32;
     285           0 :                 if (!ToInt32(cx, v, &i32))
     286           0 :                     return false;
     287           0 :                 val = Val(uint32_t(i32));
     288           0 :                 break;
     289             :               }
     290             :               case ValType::I64: {
     291           0 :                 MOZ_ASSERT(JitOptions.wasmTestMode, "no int64 in JS");
     292             :                 int64_t i64;
     293           0 :                 if (!ReadI64Object(cx, v, &i64))
     294           0 :                     return false;
     295           0 :                 val = Val(uint64_t(i64));
     296           0 :                 break;
     297             :               }
     298             :               case ValType::F32: {
     299           0 :                 if (JitOptions.wasmTestMode && v.isObject()) {
     300             :                     uint32_t bits;
     301           0 :                     if (!ReadCustomFloat32NaNObject(cx, v, &bits))
     302           0 :                         return false;
     303             :                     float f;
     304           0 :                     BitwiseCast(bits, &f);
     305           0 :                     val = Val(f);
     306           0 :                     break;
     307             :                 }
     308           0 :                 if (!v.isNumber())
     309           0 :                     return ThrowBadImportType(cx, import.field.get(), "Number");
     310             :                 double d;
     311           0 :                 if (!ToNumber(cx, v, &d))
     312           0 :                     return false;
     313           0 :                 val = Val(float(d));
     314           0 :                 break;
     315             :               }
     316             :               case ValType::F64: {
     317           0 :                 if (JitOptions.wasmTestMode && v.isObject()) {
     318             :                     uint64_t bits;
     319           0 :                     if (!ReadCustomDoubleNaNObject(cx, v, &bits))
     320           0 :                         return false;
     321             :                     double d;
     322           0 :                     BitwiseCast(bits, &d);
     323           0 :                     val = Val(d);
     324           0 :                     break;
     325             :                 }
     326           0 :                 if (!v.isNumber())
     327           0 :                     return ThrowBadImportType(cx, import.field.get(), "Number");
     328             :                 double d;
     329           0 :                 if (!ToNumber(cx, v, &d))
     330           0 :                     return false;
     331           0 :                 val = Val(d);
     332           0 :                 break;
     333             :               }
     334             :               default: {
     335           0 :                 MOZ_CRASH("unexpected import value type");
     336             :               }
     337             :             }
     338           0 :             if (!globalImports->append(val))
     339           0 :                 return false;
     340             :         }
     341             :     }
     342             : 
     343           0 :     MOZ_ASSERT(globalIndex == globals.length() || !globals[globalIndex].isImport());
     344             : 
     345           0 :     return true;
     346             : }
     347             : 
     348             : // ============================================================================
     349             : // Fuzzing support
     350             : 
     351             : static bool
     352           0 : DescribeScriptedCaller(JSContext* cx, ScriptedCaller* scriptedCaller)
     353             : {
     354             :     // Note: JS::DescribeScriptedCaller returns whether a scripted caller was
     355             :     // found, not whether an error was thrown. This wrapper function converts
     356             :     // back to the more ordinary false-if-error form.
     357             : 
     358           0 :     JS::AutoFilename af;
     359           0 :     if (JS::DescribeScriptedCaller(cx, &af, &scriptedCaller->line, &scriptedCaller->column)) {
     360           0 :         scriptedCaller->filename = DuplicateString(cx, af.get());
     361           0 :         if (!scriptedCaller->filename)
     362           0 :             return false;
     363             :     }
     364             : 
     365           0 :     return true;
     366             : }
     367             : 
     368             : bool
     369           0 : wasm::Eval(JSContext* cx, Handle<TypedArrayObject*> code, HandleObject importObj,
     370             :            MutableHandleWasmInstanceObject instanceObj)
     371             : {
     372           0 :     if (!GlobalObject::ensureConstructor(cx, cx->global(), JSProto_WebAssembly))
     373           0 :         return false;
     374             : 
     375           0 :     MutableBytes bytecode = cx->new_<ShareableBytes>();
     376           0 :     if (!bytecode)
     377           0 :         return false;
     378             : 
     379           0 :     if (!bytecode->append((uint8_t*)code->viewDataEither().unwrap(), code->byteLength())) {
     380           0 :         ReportOutOfMemory(cx);
     381           0 :         return false;
     382             :     }
     383             : 
     384           0 :     ScriptedCaller scriptedCaller;
     385           0 :     if (!DescribeScriptedCaller(cx, &scriptedCaller))
     386           0 :         return false;
     387             : 
     388           0 :     CompileArgs compileArgs;
     389           0 :     if (!compileArgs.initFromContext(cx, Move(scriptedCaller)))
     390           0 :         return false;
     391             : 
     392           0 :     UniqueChars error;
     393           0 :     SharedModule module = Compile(*bytecode, compileArgs, &error);
     394           0 :     if (!module) {
     395           0 :         if (error) {
     396           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_COMPILE_ERROR,
     397           0 :                                       error.get());
     398           0 :             return false;
     399             :         }
     400           0 :         ReportOutOfMemory(cx);
     401           0 :         return false;
     402             :     }
     403             : 
     404           0 :     Rooted<FunctionVector> funcs(cx, FunctionVector(cx));
     405           0 :     RootedWasmTableObject table(cx);
     406           0 :     RootedWasmMemoryObject memory(cx);
     407           0 :     ValVector globals;
     408           0 :     if (!GetImports(cx, *module, importObj, &funcs, &table, &memory, &globals))
     409           0 :         return false;
     410             : 
     411           0 :     return module->instantiate(cx, funcs, table, memory, globals, nullptr, instanceObj);
     412             : }
     413             : 
     414             : // ============================================================================
     415             : // Common functions
     416             : 
     417             : static bool
     418           0 : ToNonWrappingUint32(JSContext* cx, HandleValue v, uint32_t max, const char* kind, const char* noun,
     419             :                     uint32_t* u32)
     420             : {
     421             :     double dbl;
     422           0 :     if (!ToInteger(cx, v, &dbl))
     423           0 :         return false;
     424             : 
     425           0 :     if (dbl < 0 || dbl > max) {
     426           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_UINT32, kind, noun);
     427           0 :         return false;
     428             :     }
     429             : 
     430           0 :     *u32 = uint32_t(dbl);
     431           0 :     MOZ_ASSERT(double(*u32) == dbl);
     432           0 :     return true;
     433             : }
     434             : 
     435             : static bool
     436           0 : GetLimits(JSContext* cx, HandleObject obj, uint32_t maxInitial, uint32_t maxMaximum,
     437             :           const char* kind, Limits* limits)
     438             : {
     439           0 :     JSAtom* initialAtom = Atomize(cx, "initial", strlen("initial"));
     440           0 :     if (!initialAtom)
     441           0 :         return false;
     442           0 :     RootedId initialId(cx, AtomToId(initialAtom));
     443             : 
     444           0 :     RootedValue initialVal(cx);
     445           0 :     if (!GetProperty(cx, obj, obj, initialId, &initialVal))
     446           0 :         return false;
     447             : 
     448           0 :     if (!ToNonWrappingUint32(cx, initialVal, maxInitial, kind, "initial size", &limits->initial))
     449           0 :         return false;
     450             : 
     451           0 :     JSAtom* maximumAtom = Atomize(cx, "maximum", strlen("maximum"));
     452           0 :     if (!maximumAtom)
     453           0 :         return false;
     454           0 :     RootedId maximumId(cx, AtomToId(maximumAtom));
     455             : 
     456             :     bool found;
     457           0 :     if (HasProperty(cx, obj, maximumId, &found) && found) {
     458           0 :         RootedValue maxVal(cx);
     459           0 :         if (!GetProperty(cx, obj, obj, maximumId, &maxVal))
     460           0 :             return false;
     461             : 
     462           0 :         limits->maximum.emplace();
     463           0 :         if (!ToNonWrappingUint32(cx, maxVal, maxMaximum, kind, "maximum size", limits->maximum.ptr()))
     464           0 :             return false;
     465             : 
     466           0 :         if (limits->initial > *limits->maximum) {
     467             :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_UINT32,
     468           0 :                                       kind, "maximum size");
     469           0 :             return false;
     470             :         }
     471             :     }
     472             : 
     473           0 :     return true;
     474             : }
     475             : 
     476             : // ============================================================================
     477             : // WebAssembly.Module class and methods
     478             : 
     479             : const ClassOps WasmModuleObject::classOps_ =
     480             : {
     481             :     nullptr, /* addProperty */
     482             :     nullptr, /* delProperty */
     483             :     nullptr, /* getProperty */
     484             :     nullptr, /* setProperty */
     485             :     nullptr, /* enumerate */
     486             :     nullptr, /* newEnumerate */
     487             :     nullptr, /* resolve */
     488             :     nullptr, /* mayResolve */
     489             :     WasmModuleObject::finalize
     490             : };
     491             : 
     492             : const Class WasmModuleObject::class_ =
     493             : {
     494             :     "WebAssembly.Module",
     495             :     JSCLASS_DELAY_METADATA_BUILDER |
     496             :     JSCLASS_HAS_RESERVED_SLOTS(WasmModuleObject::RESERVED_SLOTS) |
     497             :     JSCLASS_FOREGROUND_FINALIZE,
     498             :     &WasmModuleObject::classOps_,
     499             : };
     500             : 
     501             : const JSPropertySpec WasmModuleObject::properties[] =
     502             : { JS_PS_END };
     503             : 
     504             : const JSFunctionSpec WasmModuleObject::methods[] =
     505             : { JS_FS_END };
     506             : 
     507             : const JSFunctionSpec WasmModuleObject::static_methods[] =
     508             : {
     509             :     JS_FN("imports", WasmModuleObject::imports, 1, 0),
     510             :     JS_FN("exports", WasmModuleObject::exports, 1, 0),
     511             :     JS_FN("customSections", WasmModuleObject::customSections, 2, 0),
     512             :     JS_FS_END
     513             : };
     514             : 
     515             : /* static */ void
     516           0 : WasmModuleObject::finalize(FreeOp* fop, JSObject* obj)
     517             : {
     518           0 :     obj->as<WasmModuleObject>().module().Release();
     519           0 : }
     520             : 
     521             : static bool
     522           0 : IsModuleObject(JSObject* obj, Module** module)
     523             : {
     524           0 :     JSObject* unwrapped = CheckedUnwrap(obj);
     525           0 :     if (!unwrapped || !unwrapped->is<WasmModuleObject>())
     526           0 :         return false;
     527             : 
     528           0 :     *module = &unwrapped->as<WasmModuleObject>().module();
     529           0 :     return true;
     530             : }
     531             : 
     532             : static bool
     533           0 : GetModuleArg(JSContext* cx, CallArgs args, const char* name, Module** module)
     534             : {
     535           0 :     if (!args.requireAtLeast(cx, name, 1))
     536           0 :         return false;
     537             : 
     538           0 :     if (!args[0].isObject() || !IsModuleObject(&args[0].toObject(), module)) {
     539           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_MOD_ARG);
     540           0 :         return false;
     541             :     }
     542             : 
     543           0 :     return true;
     544             : }
     545             : 
     546           0 : struct KindNames
     547             : {
     548             :     RootedPropertyName kind;
     549             :     RootedPropertyName table;
     550             :     RootedPropertyName memory;
     551             :     RootedPropertyName signature;
     552             : 
     553           0 :     explicit KindNames(JSContext* cx) : kind(cx), table(cx), memory(cx), signature(cx) {}
     554             : };
     555             : 
     556             : static bool
     557           0 : InitKindNames(JSContext* cx, KindNames* names)
     558             : {
     559           0 :     JSAtom* kind = Atomize(cx, "kind", strlen("kind"));
     560           0 :     if (!kind)
     561           0 :         return false;
     562           0 :     names->kind = kind->asPropertyName();
     563             : 
     564           0 :     JSAtom* table = Atomize(cx, "table", strlen("table"));
     565           0 :     if (!table)
     566           0 :         return false;
     567           0 :     names->table = table->asPropertyName();
     568             : 
     569           0 :     JSAtom* memory = Atomize(cx, "memory", strlen("memory"));
     570           0 :     if (!memory)
     571           0 :         return false;
     572           0 :     names->memory = memory->asPropertyName();
     573             : 
     574           0 :     JSAtom* signature = Atomize(cx, "signature", strlen("signature"));
     575           0 :     if (!signature)
     576           0 :         return false;
     577           0 :     names->signature = signature->asPropertyName();
     578             : 
     579           0 :     return true;
     580             : }
     581             : 
     582             : static JSString*
     583           0 : KindToString(JSContext* cx, const KindNames& names, DefinitionKind kind)
     584             : {
     585           0 :     switch (kind) {
     586             :       case DefinitionKind::Function:
     587           0 :         return cx->names().function;
     588             :       case DefinitionKind::Table:
     589           0 :         return names.table;
     590             :       case DefinitionKind::Memory:
     591           0 :         return names.memory;
     592             :       case DefinitionKind::Global:
     593           0 :         return cx->names().global;
     594             :     }
     595             : 
     596           0 :     MOZ_CRASH("invalid kind");
     597             : }
     598             : 
     599             : static JSString*
     600           0 : SigToString(JSContext* cx, const Sig& sig)
     601             : {
     602           0 :     StringBuffer buf(cx);
     603           0 :     if (!buf.append('('))
     604           0 :         return nullptr;
     605             : 
     606           0 :     bool first = true;
     607           0 :     for (ValType arg : sig.args()) {
     608           0 :         if (!first && !buf.append(", ", strlen(", ")))
     609           0 :             return nullptr;
     610             : 
     611           0 :         const char* argStr = ToCString(arg);
     612           0 :         if (!buf.append(argStr, strlen(argStr)))
     613           0 :             return nullptr;
     614             : 
     615           0 :         first = false;
     616             :     }
     617             : 
     618           0 :     if (!buf.append(") -> (", strlen(") -> (")))
     619           0 :         return nullptr;
     620             : 
     621           0 :     if (sig.ret() != ExprType::Void) {
     622           0 :         const char* retStr = ToCString(sig.ret());
     623           0 :         if (!buf.append(retStr, strlen(retStr)))
     624           0 :             return nullptr;
     625             :     }
     626             : 
     627           0 :     if (!buf.append(')'))
     628           0 :         return nullptr;
     629             : 
     630           0 :     return buf.finishString();
     631             : }
     632             : 
     633             : static JSString*
     634           0 : UTF8CharsToString(JSContext* cx, const char* chars)
     635             : {
     636           0 :     return NewStringCopyUTF8Z<CanGC>(cx, JS::ConstUTF8CharsZ(chars, strlen(chars)));
     637             : }
     638             : 
     639             : /* static */ bool
     640           0 : WasmModuleObject::imports(JSContext* cx, unsigned argc, Value* vp)
     641             : {
     642           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     643             : 
     644             :     Module* module;
     645           0 :     if (!GetModuleArg(cx, args, "WebAssembly.Module.imports", &module))
     646           0 :         return false;
     647             : 
     648           0 :     KindNames names(cx);
     649           0 :     if (!InitKindNames(cx, &names))
     650           0 :         return false;
     651             : 
     652           0 :     AutoValueVector elems(cx);
     653           0 :     if (!elems.reserve(module->imports().length()))
     654           0 :         return false;
     655             : 
     656           0 :     const FuncImportVector& funcImports = module->metadata(module->code().anyTier()).funcImports;
     657             : 
     658           0 :     size_t numFuncImport = 0;
     659           0 :     for (const Import& import : module->imports()) {
     660           0 :         Rooted<IdValueVector> props(cx, IdValueVector(cx));
     661           0 :         if (!props.reserve(3))
     662           0 :             return false;
     663             : 
     664           0 :         JSString* moduleStr = UTF8CharsToString(cx, import.module.get());
     665           0 :         if (!moduleStr)
     666           0 :             return false;
     667           0 :         props.infallibleAppend(IdValuePair(NameToId(cx->names().module), StringValue(moduleStr)));
     668             : 
     669           0 :         JSString* nameStr = UTF8CharsToString(cx, import.field.get());
     670           0 :         if (!nameStr)
     671           0 :             return false;
     672           0 :         props.infallibleAppend(IdValuePair(NameToId(cx->names().name), StringValue(nameStr)));
     673             : 
     674           0 :         JSString* kindStr = KindToString(cx, names, import.kind);
     675           0 :         if (!kindStr)
     676           0 :             return false;
     677           0 :         props.infallibleAppend(IdValuePair(NameToId(names.kind), StringValue(kindStr)));
     678             : 
     679           0 :         if (JitOptions.wasmTestMode && import.kind == DefinitionKind::Function) {
     680           0 :             JSString* sigStr = SigToString(cx, funcImports[numFuncImport++].sig());
     681           0 :             if (!sigStr)
     682           0 :                 return false;
     683           0 :             if (!props.append(IdValuePair(NameToId(names.signature), StringValue(sigStr))))
     684           0 :                 return false;
     685             :         }
     686             : 
     687           0 :         JSObject* obj = ObjectGroup::newPlainObject(cx, props.begin(), props.length(), GenericObject);
     688           0 :         if (!obj)
     689           0 :             return false;
     690             : 
     691           0 :         elems.infallibleAppend(ObjectValue(*obj));
     692             :     }
     693             : 
     694           0 :     JSObject* arr = NewDenseCopiedArray(cx, elems.length(), elems.begin());
     695           0 :     if (!arr)
     696           0 :         return false;
     697             : 
     698           0 :     args.rval().setObject(*arr);
     699           0 :     return true;
     700             : }
     701             : 
     702             : /* static */ bool
     703           0 : WasmModuleObject::exports(JSContext* cx, unsigned argc, Value* vp)
     704             : {
     705           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     706             : 
     707             :     Module* module;
     708           0 :     if (!GetModuleArg(cx, args, "WebAssembly.Module.exports", &module))
     709           0 :         return false;
     710             : 
     711           0 :     KindNames names(cx);
     712           0 :     if (!InitKindNames(cx, &names))
     713           0 :         return false;
     714             : 
     715           0 :     AutoValueVector elems(cx);
     716           0 :     if (!elems.reserve(module->exports().length()))
     717           0 :         return false;
     718             : 
     719           0 :     const FuncExportVector& funcExports = module->metadata(module->code().anyTier()).funcExports;
     720             : 
     721           0 :     size_t numFuncExport = 0;
     722           0 :     for (const Export& exp : module->exports()) {
     723           0 :         Rooted<IdValueVector> props(cx, IdValueVector(cx));
     724           0 :         if (!props.reserve(2))
     725           0 :             return false;
     726             : 
     727           0 :         JSString* nameStr = UTF8CharsToString(cx, exp.fieldName());
     728           0 :         if (!nameStr)
     729           0 :             return false;
     730           0 :         props.infallibleAppend(IdValuePair(NameToId(cx->names().name), StringValue(nameStr)));
     731             : 
     732           0 :         JSString* kindStr = KindToString(cx, names, exp.kind());
     733           0 :         if (!kindStr)
     734           0 :             return false;
     735           0 :         props.infallibleAppend(IdValuePair(NameToId(names.kind), StringValue(kindStr)));
     736             : 
     737           0 :         if (JitOptions.wasmTestMode && exp.kind() == DefinitionKind::Function) {
     738           0 :             JSString* sigStr = SigToString(cx, funcExports[numFuncExport++].sig());
     739           0 :             if (!sigStr)
     740           0 :                 return false;
     741           0 :             if (!props.append(IdValuePair(NameToId(names.signature), StringValue(sigStr))))
     742           0 :                 return false;
     743             :         }
     744             : 
     745           0 :         JSObject* obj = ObjectGroup::newPlainObject(cx, props.begin(), props.length(), GenericObject);
     746           0 :         if (!obj)
     747           0 :             return false;
     748             : 
     749           0 :         elems.infallibleAppend(ObjectValue(*obj));
     750             :     }
     751             : 
     752           0 :     JSObject* arr = NewDenseCopiedArray(cx, elems.length(), elems.begin());
     753           0 :     if (!arr)
     754           0 :         return false;
     755             : 
     756           0 :     args.rval().setObject(*arr);
     757           0 :     return true;
     758             : }
     759             : 
     760             : /* static */ bool
     761           0 : WasmModuleObject::customSections(JSContext* cx, unsigned argc, Value* vp)
     762             : {
     763           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     764             : 
     765             :     Module* module;
     766           0 :     if (!GetModuleArg(cx, args, "WebAssembly.Module.customSections", &module))
     767           0 :         return false;
     768             : 
     769           0 :     Vector<char, 8> name(cx);
     770             :     {
     771           0 :         RootedString str(cx, ToString(cx, args.get(1)));
     772           0 :         if (!str)
     773           0 :             return false;
     774             : 
     775           0 :         Rooted<JSFlatString*> flat(cx, str->ensureFlat(cx));
     776           0 :         if (!flat)
     777           0 :             return false;
     778             : 
     779           0 :         if (!name.initLengthUninitialized(JS::GetDeflatedUTF8StringLength(flat)))
     780           0 :             return false;
     781             : 
     782           0 :         JS::DeflateStringToUTF8Buffer(flat, RangedPtr<char>(name.begin(), name.length()));
     783             :     }
     784             : 
     785           0 :     const uint8_t* bytecode = module->bytecode().begin();
     786             : 
     787           0 :     AutoValueVector elems(cx);
     788           0 :     RootedArrayBufferObject buf(cx);
     789           0 :     for (const CustomSection& sec : module->metadata().customSections) {
     790           0 :         if (name.length() != sec.name.length)
     791           0 :             continue;
     792           0 :         if (memcmp(name.begin(), bytecode + sec.name.offset, name.length()))
     793           0 :             continue;
     794             : 
     795           0 :         buf = ArrayBufferObject::create(cx, sec.length);
     796           0 :         if (!buf)
     797           0 :             return false;
     798             : 
     799           0 :         memcpy(buf->dataPointer(), bytecode + sec.offset, sec.length);
     800           0 :         if (!elems.append(ObjectValue(*buf)))
     801           0 :             return false;
     802             :     }
     803             : 
     804           0 :     JSObject* arr = NewDenseCopiedArray(cx, elems.length(), elems.begin());
     805           0 :     if (!arr)
     806           0 :         return false;
     807             : 
     808           0 :     args.rval().setObject(*arr);
     809           0 :     return true;
     810             : }
     811             : 
     812             : /* static */ WasmModuleObject*
     813           0 : WasmModuleObject::create(JSContext* cx, Module& module, HandleObject proto)
     814             : {
     815           0 :     AutoSetNewObjectMetadata metadata(cx);
     816           0 :     auto* obj = NewObjectWithGivenProto<WasmModuleObject>(cx, proto);
     817           0 :     if (!obj)
     818           0 :         return nullptr;
     819             : 
     820           0 :     obj->initReservedSlot(MODULE_SLOT, PrivateValue(&module));
     821           0 :     module.AddRef();
     822             :     // We account for the first tier here; the second tier, if different, will be
     823             :     // accounted for separately when it's been compiled.
     824           0 :     cx->zone()->updateJitCodeMallocBytes(module.codeLength(module.code().anyTier()));
     825           0 :     return obj;
     826             : }
     827             : 
     828             : static bool
     829           0 : GetBufferSource(JSContext* cx, JSObject* obj, unsigned errorNumber, MutableBytes* bytecode)
     830             : {
     831           0 :     *bytecode = cx->new_<ShareableBytes>();
     832           0 :     if (!*bytecode)
     833           0 :         return false;
     834             : 
     835           0 :     JSObject* unwrapped = CheckedUnwrap(obj);
     836             : 
     837           0 :     size_t byteLength = 0;
     838           0 :     uint8_t* ptr = nullptr;
     839           0 :     if (unwrapped && unwrapped->is<TypedArrayObject>()) {
     840           0 :         TypedArrayObject& view = unwrapped->as<TypedArrayObject>();
     841           0 :         byteLength = view.byteLength();
     842           0 :         ptr = (uint8_t*)view.viewDataEither().unwrap();
     843           0 :     } else if (unwrapped && unwrapped->is<ArrayBufferObject>()) {
     844           0 :         ArrayBufferObject& buffer = unwrapped->as<ArrayBufferObject>();
     845           0 :         byteLength = buffer.byteLength();
     846           0 :         ptr = buffer.dataPointer();
     847             :     } else {
     848           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, errorNumber);
     849           0 :         return false;
     850             :     }
     851             : 
     852           0 :     if (!(*bytecode)->append(ptr, byteLength)) {
     853           0 :         ReportOutOfMemory(cx);
     854           0 :         return false;
     855             :     }
     856             : 
     857           0 :     return true;
     858             : }
     859             : 
     860             : static bool
     861           0 : InitCompileArgs(JSContext* cx, CompileArgs* compileArgs)
     862             : {
     863           0 :     ScriptedCaller scriptedCaller;
     864           0 :     if (!DescribeScriptedCaller(cx, &scriptedCaller))
     865           0 :         return false;
     866             : 
     867           0 :     return compileArgs->initFromContext(cx, Move(scriptedCaller));
     868             : }
     869             : 
     870             : /* static */ bool
     871           0 : WasmModuleObject::construct(JSContext* cx, unsigned argc, Value* vp)
     872             : {
     873           0 :     CallArgs callArgs = CallArgsFromVp(argc, vp);
     874             : 
     875           0 :     if (!ThrowIfNotConstructing(cx, callArgs, "Module"))
     876           0 :         return false;
     877             : 
     878           0 :     if (!callArgs.requireAtLeast(cx, "WebAssembly.Module", 1))
     879           0 :         return false;
     880             : 
     881           0 :     if (!callArgs[0].isObject()) {
     882           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_BUF_ARG);
     883           0 :         return false;
     884             :     }
     885             : 
     886           0 :     MutableBytes bytecode;
     887           0 :     if (!GetBufferSource(cx, &callArgs[0].toObject(), JSMSG_WASM_BAD_BUF_ARG, &bytecode))
     888           0 :         return false;
     889             : 
     890           0 :     CompileArgs compileArgs;
     891           0 :     if (!InitCompileArgs(cx, &compileArgs))
     892           0 :         return false;
     893             : 
     894           0 :     UniqueChars error;
     895           0 :     SharedModule module = Compile(*bytecode, compileArgs, &error);
     896           0 :     if (!module) {
     897           0 :         if (error) {
     898           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_COMPILE_ERROR,
     899           0 :                                       error.get());
     900           0 :             return false;
     901             :         }
     902           0 :         ReportOutOfMemory(cx);
     903           0 :         return false;
     904             :     }
     905             : 
     906           0 :     RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmModule).toObject());
     907           0 :     RootedObject moduleObj(cx, WasmModuleObject::create(cx, *module, proto));
     908           0 :     if (!moduleObj)
     909           0 :         return false;
     910             : 
     911           0 :     callArgs.rval().setObject(*moduleObj);
     912           0 :     return true;
     913             : }
     914             : 
     915             : Module&
     916           0 : WasmModuleObject::module() const
     917             : {
     918           0 :     MOZ_ASSERT(is<WasmModuleObject>());
     919           0 :     return *(Module*)getReservedSlot(MODULE_SLOT).toPrivate();
     920             : }
     921             : 
     922             : // ============================================================================
     923             : // WebAssembly.Instance class and methods
     924             : 
     925             : const ClassOps WasmInstanceObject::classOps_ =
     926             : {
     927             :     nullptr, /* addProperty */
     928             :     nullptr, /* delProperty */
     929             :     nullptr, /* getProperty */
     930             :     nullptr, /* setProperty */
     931             :     nullptr, /* enumerate */
     932             :     nullptr, /* newEnumerate */
     933             :     nullptr, /* resolve */
     934             :     nullptr, /* mayResolve */
     935             :     WasmInstanceObject::finalize,
     936             :     nullptr, /* call */
     937             :     nullptr, /* hasInstance */
     938             :     nullptr, /* construct */
     939             :     WasmInstanceObject::trace
     940             : };
     941             : 
     942             : const Class WasmInstanceObject::class_ =
     943             : {
     944             :     "WebAssembly.Instance",
     945             :     JSCLASS_DELAY_METADATA_BUILDER |
     946             :     JSCLASS_HAS_RESERVED_SLOTS(WasmInstanceObject::RESERVED_SLOTS) |
     947             :     JSCLASS_FOREGROUND_FINALIZE,
     948             :     &WasmInstanceObject::classOps_,
     949             : };
     950             : 
     951             : static bool
     952           0 : IsInstance(HandleValue v)
     953             : {
     954           0 :     return v.isObject() && v.toObject().is<WasmInstanceObject>();
     955             : }
     956             : 
     957             : /* static */ bool
     958           0 : WasmInstanceObject::exportsGetterImpl(JSContext* cx, const CallArgs& args)
     959             : {
     960           0 :     args.rval().setObject(args.thisv().toObject().as<WasmInstanceObject>().exportsObj());
     961           0 :     return true;
     962             : }
     963             : 
     964             : /* static */ bool
     965           0 : WasmInstanceObject::exportsGetter(JSContext* cx, unsigned argc, Value* vp)
     966             : {
     967           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     968           0 :     return CallNonGenericMethod<IsInstance, exportsGetterImpl>(cx, args);
     969             : }
     970             : 
     971             : const JSPropertySpec WasmInstanceObject::properties[] =
     972             : {
     973             :     JS_PSG("exports", WasmInstanceObject::exportsGetter, 0),
     974             :     JS_PS_END
     975             : };
     976             : 
     977             : const JSFunctionSpec WasmInstanceObject::methods[] =
     978             : { JS_FS_END };
     979             : 
     980             : const JSFunctionSpec WasmInstanceObject::static_methods[] =
     981             : { JS_FS_END };
     982             : 
     983             : bool
     984           0 : WasmInstanceObject::isNewborn() const
     985             : {
     986           0 :     MOZ_ASSERT(is<WasmInstanceObject>());
     987           0 :     return getReservedSlot(INSTANCE_SLOT).isUndefined();
     988             : }
     989             : 
     990             : /* static */ void
     991           0 : WasmInstanceObject::finalize(FreeOp* fop, JSObject* obj)
     992             : {
     993           0 :     fop->delete_(&obj->as<WasmInstanceObject>().exports());
     994           0 :     fop->delete_(&obj->as<WasmInstanceObject>().scopes());
     995           0 :     if (!obj->as<WasmInstanceObject>().isNewborn())
     996           0 :         fop->delete_(&obj->as<WasmInstanceObject>().instance());
     997           0 : }
     998             : 
     999             : /* static */ void
    1000           0 : WasmInstanceObject::trace(JSTracer* trc, JSObject* obj)
    1001             : {
    1002           0 :     WasmInstanceObject& instanceObj = obj->as<WasmInstanceObject>();
    1003           0 :     instanceObj.exports().trace(trc);
    1004           0 :     if (!instanceObj.isNewborn())
    1005           0 :         instanceObj.instance().tracePrivate(trc);
    1006           0 : }
    1007             : 
    1008             : /* static */ WasmInstanceObject*
    1009           0 : WasmInstanceObject::create(JSContext* cx,
    1010             :                            SharedCode code,
    1011             :                            UniqueDebugState debug,
    1012             :                            UniqueGlobalSegment globals,
    1013             :                            HandleWasmMemoryObject memory,
    1014             :                            SharedTableVector&& tables,
    1015             :                            Handle<FunctionVector> funcImports,
    1016             :                            const ValVector& globalImports,
    1017             :                            HandleObject proto)
    1018             : {
    1019           0 :     UniquePtr<ExportMap> exports = js::MakeUnique<ExportMap>();
    1020           0 :     if (!exports || !exports->init()) {
    1021           0 :         ReportOutOfMemory(cx);
    1022           0 :         return nullptr;
    1023             :     }
    1024             : 
    1025           0 :     UniquePtr<ScopeMap> scopes = js::MakeUnique<ScopeMap>(cx->zone());
    1026           0 :     if (!scopes || !scopes->init()) {
    1027           0 :         ReportOutOfMemory(cx);
    1028           0 :         return nullptr;
    1029             :     }
    1030             : 
    1031           0 :     AutoSetNewObjectMetadata metadata(cx);
    1032           0 :     RootedWasmInstanceObject obj(cx, NewObjectWithGivenProto<WasmInstanceObject>(cx, proto));
    1033           0 :     if (!obj)
    1034           0 :         return nullptr;
    1035             : 
    1036           0 :     obj->setReservedSlot(EXPORTS_SLOT, PrivateValue(exports.release()));
    1037           0 :     obj->setReservedSlot(SCOPES_SLOT, PrivateValue(scopes.release()));
    1038           0 :     MOZ_ASSERT(obj->isNewborn());
    1039             : 
    1040           0 :     MOZ_ASSERT(obj->isTenured(), "assumed by WasmTableObject write barriers");
    1041             : 
    1042             :     // Root the Instance via WasmInstanceObject before any possible GC.
    1043           0 :     auto* instance = cx->new_<Instance>(cx,
    1044             :                                         obj,
    1045             :                                         code,
    1046           0 :                                         Move(debug),
    1047           0 :                                         Move(globals),
    1048             :                                         memory,
    1049           0 :                                         Move(tables),
    1050             :                                         funcImports,
    1051           0 :                                         globalImports);
    1052           0 :     if (!instance)
    1053           0 :         return nullptr;
    1054             : 
    1055           0 :     obj->initReservedSlot(INSTANCE_SLOT, PrivateValue(instance));
    1056           0 :     MOZ_ASSERT(!obj->isNewborn());
    1057             : 
    1058           0 :     if (!instance->init(cx))
    1059           0 :         return nullptr;
    1060             : 
    1061           0 :     return obj;
    1062             : }
    1063             : 
    1064             : void
    1065           0 : WasmInstanceObject::initExportsObj(JSObject& exportsObj)
    1066             : {
    1067           0 :     MOZ_ASSERT(getReservedSlot(EXPORTS_OBJ_SLOT).isUndefined());
    1068           0 :     setReservedSlot(EXPORTS_OBJ_SLOT, ObjectValue(exportsObj));
    1069           0 : }
    1070             : 
    1071             : static bool
    1072           0 : GetImportArg(JSContext* cx, CallArgs callArgs, MutableHandleObject importObj)
    1073             : {
    1074           0 :     if (!callArgs.get(1).isUndefined()) {
    1075           0 :         if (!callArgs[1].isObject())
    1076           0 :             return ThrowBadImportArg(cx);
    1077           0 :         importObj.set(&callArgs[1].toObject());
    1078             :     }
    1079           0 :     return true;
    1080             : }
    1081             : 
    1082             : static bool
    1083           0 : Instantiate(JSContext* cx, const Module& module, HandleObject importObj,
    1084             :             MutableHandleWasmInstanceObject instanceObj)
    1085             : {
    1086           0 :     RootedObject instanceProto(cx, &cx->global()->getPrototype(JSProto_WasmInstance).toObject());
    1087             : 
    1088           0 :     Rooted<FunctionVector> funcs(cx, FunctionVector(cx));
    1089           0 :     RootedWasmTableObject table(cx);
    1090           0 :     RootedWasmMemoryObject memory(cx);
    1091           0 :     ValVector globals;
    1092           0 :     if (!GetImports(cx, module, importObj, &funcs, &table, &memory, &globals))
    1093           0 :         return false;
    1094             : 
    1095           0 :     return module.instantiate(cx, funcs, table, memory, globals, instanceProto, instanceObj);
    1096             : }
    1097             : 
    1098             : /* static */ bool
    1099           0 : WasmInstanceObject::construct(JSContext* cx, unsigned argc, Value* vp)
    1100             : {
    1101           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1102             : 
    1103           0 :     if (!ThrowIfNotConstructing(cx, args, "Instance"))
    1104           0 :         return false;
    1105             : 
    1106           0 :     if (!args.requireAtLeast(cx, "WebAssembly.Instance", 1))
    1107           0 :         return false;
    1108             : 
    1109             :     Module* module;
    1110           0 :     if (!args[0].isObject() || !IsModuleObject(&args[0].toObject(), &module)) {
    1111           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_MOD_ARG);
    1112           0 :         return false;
    1113             :     }
    1114             : 
    1115           0 :     RootedObject importObj(cx);
    1116           0 :     if (!GetImportArg(cx, args, &importObj))
    1117           0 :         return false;
    1118             : 
    1119           0 :     RootedWasmInstanceObject instanceObj(cx);
    1120           0 :     if (!Instantiate(cx, *module, importObj, &instanceObj))
    1121           0 :         return false;
    1122             : 
    1123           0 :     args.rval().setObject(*instanceObj);
    1124           0 :     return true;
    1125             : }
    1126             : 
    1127             : Instance&
    1128           0 : WasmInstanceObject::instance() const
    1129             : {
    1130           0 :     MOZ_ASSERT(!isNewborn());
    1131           0 :     return *(Instance*)getReservedSlot(INSTANCE_SLOT).toPrivate();
    1132             : }
    1133             : 
    1134             : JSObject&
    1135           0 : WasmInstanceObject::exportsObj() const
    1136             : {
    1137           0 :     return getReservedSlot(EXPORTS_OBJ_SLOT).toObject();
    1138             : }
    1139             : 
    1140             : WasmInstanceObject::ExportMap&
    1141           0 : WasmInstanceObject::exports() const
    1142             : {
    1143           0 :     return *(ExportMap*)getReservedSlot(EXPORTS_SLOT).toPrivate();
    1144             : }
    1145             : 
    1146             : WasmInstanceObject::ScopeMap&
    1147           0 : WasmInstanceObject::scopes() const
    1148             : {
    1149           0 :     return *(ScopeMap*)getReservedSlot(SCOPES_SLOT).toPrivate();
    1150             : }
    1151             : 
    1152             : static bool
    1153           0 : WasmCall(JSContext* cx, unsigned argc, Value* vp)
    1154             : {
    1155           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1156           0 :     RootedFunction callee(cx, &args.callee().as<JSFunction>());
    1157             : 
    1158           0 :     Instance& instance = ExportedFunctionToInstance(callee);
    1159           0 :     uint32_t funcIndex = ExportedFunctionToFuncIndex(callee);
    1160           0 :     return instance.callExport(cx, funcIndex, args);
    1161             : }
    1162             : 
    1163             : /* static */ bool
    1164           0 : WasmInstanceObject::getExportedFunction(JSContext* cx, HandleWasmInstanceObject instanceObj,
    1165             :                                         uint32_t funcIndex, MutableHandleFunction fun)
    1166             : {
    1167           0 :     if (ExportMap::Ptr p = instanceObj->exports().lookup(funcIndex)) {
    1168           0 :         fun.set(p->value());
    1169           0 :         return true;
    1170             :     }
    1171             : 
    1172           0 :     const Instance& instance = instanceObj->instance();
    1173           0 :     unsigned numArgs = instance.metadata(instance.code().anyTier()).lookupFuncExport(funcIndex).sig().args().length();
    1174             : 
    1175             :     // asm.js needs to act like a normal JS function which means having the name
    1176             :     // from the original source and being callable as a constructor.
    1177           0 :     if (instance.isAsmJS()) {
    1178           0 :         RootedAtom name(cx, instance.getFuncAtom(cx, funcIndex));
    1179           0 :         if (!name)
    1180           0 :             return false;
    1181             : 
    1182           0 :         fun.set(NewNativeConstructor(cx, WasmCall, numArgs, name, gc::AllocKind::FUNCTION_EXTENDED,
    1183           0 :                                      SingletonObject, JSFunction::ASMJS_CTOR));
    1184           0 :         if (!fun)
    1185           0 :             return false;
    1186             :     } else {
    1187           0 :         RootedAtom name(cx, NumberToAtom(cx, funcIndex));
    1188           0 :         if (!name)
    1189           0 :             return false;
    1190             : 
    1191           0 :         fun.set(NewNativeFunction(cx, WasmCall, numArgs, name, gc::AllocKind::FUNCTION_EXTENDED));
    1192           0 :         if (!fun)
    1193           0 :             return false;
    1194             :     }
    1195             : 
    1196           0 :     fun->setExtendedSlot(FunctionExtended::WASM_INSTANCE_SLOT, ObjectValue(*instanceObj));
    1197           0 :     fun->setExtendedSlot(FunctionExtended::WASM_FUNC_INDEX_SLOT, Int32Value(funcIndex));
    1198             : 
    1199           0 :     if (!instanceObj->exports().putNew(funcIndex, fun)) {
    1200           0 :         ReportOutOfMemory(cx);
    1201           0 :         return false;
    1202             :     }
    1203             : 
    1204           0 :     return true;
    1205             : }
    1206             : 
    1207             : const CodeRange&
    1208           0 : WasmInstanceObject::getExportedFunctionCodeRange(HandleFunction fun, Tier tier)
    1209             : {
    1210           0 :     uint32_t funcIndex = ExportedFunctionToFuncIndex(fun);
    1211           0 :     MOZ_ASSERT(exports().lookup(funcIndex)->value() == fun);
    1212           0 :     const FuncExport& funcExport = instance().metadata(tier).lookupFuncExport(funcIndex);
    1213           0 :     return instance().metadata(tier).codeRanges[funcExport.codeRangeIndex()];
    1214             : }
    1215             : 
    1216             : /* static */ WasmFunctionScope*
    1217           0 : WasmInstanceObject::getFunctionScope(JSContext* cx, HandleWasmInstanceObject instanceObj,
    1218             :                                      uint32_t funcIndex)
    1219             : {
    1220           0 :     if (ScopeMap::Ptr p = instanceObj->scopes().lookup(funcIndex))
    1221           0 :         return p->value();
    1222             : 
    1223           0 :     Rooted<WasmFunctionScope*> funcScope(cx, WasmFunctionScope::create(cx, instanceObj, funcIndex));
    1224           0 :     if (!funcScope)
    1225           0 :         return nullptr;
    1226             : 
    1227           0 :     if (!instanceObj->scopes().putNew(funcIndex, funcScope)) {
    1228           0 :         ReportOutOfMemory(cx);
    1229           0 :         return nullptr;
    1230             :     }
    1231             : 
    1232           0 :     return funcScope;
    1233             : }
    1234             : 
    1235             : bool
    1236           4 : wasm::IsExportedFunction(JSFunction* fun)
    1237             : {
    1238           4 :     return fun->maybeNative() == WasmCall;
    1239             : }
    1240             : 
    1241             : bool
    1242           0 : wasm::IsExportedWasmFunction(JSFunction* fun)
    1243             : {
    1244           0 :     return IsExportedFunction(fun) && !ExportedFunctionToInstance(fun).isAsmJS();
    1245             : }
    1246             : 
    1247             : bool
    1248           0 : wasm::IsExportedFunction(const Value& v, MutableHandleFunction f)
    1249             : {
    1250           0 :     if (!v.isObject())
    1251           0 :         return false;
    1252             : 
    1253           0 :     JSObject& obj = v.toObject();
    1254           0 :     if (!obj.is<JSFunction>() || !IsExportedFunction(&obj.as<JSFunction>()))
    1255           0 :         return false;
    1256             : 
    1257           0 :     f.set(&obj.as<JSFunction>());
    1258           0 :     return true;
    1259             : }
    1260             : 
    1261             : Instance&
    1262           0 : wasm::ExportedFunctionToInstance(JSFunction* fun)
    1263             : {
    1264           0 :     return ExportedFunctionToInstanceObject(fun)->instance();
    1265             : }
    1266             : 
    1267             : WasmInstanceObject*
    1268           0 : wasm::ExportedFunctionToInstanceObject(JSFunction* fun)
    1269             : {
    1270           0 :     MOZ_ASSERT(IsExportedFunction(fun));
    1271           0 :     const Value& v = fun->getExtendedSlot(FunctionExtended::WASM_INSTANCE_SLOT);
    1272           0 :     return &v.toObject().as<WasmInstanceObject>();
    1273             : }
    1274             : 
    1275             : uint32_t
    1276           0 : wasm::ExportedFunctionToFuncIndex(JSFunction* fun)
    1277             : {
    1278           0 :     MOZ_ASSERT(IsExportedFunction(fun));
    1279           0 :     const Value& v = fun->getExtendedSlot(FunctionExtended::WASM_FUNC_INDEX_SLOT);
    1280           0 :     return v.toInt32();
    1281             : }
    1282             : 
    1283             : // ============================================================================
    1284             : // WebAssembly.Memory class and methods
    1285             : 
    1286             : const ClassOps WasmMemoryObject::classOps_ =
    1287             : {
    1288             :     nullptr, /* addProperty */
    1289             :     nullptr, /* delProperty */
    1290             :     nullptr, /* getProperty */
    1291             :     nullptr, /* setProperty */
    1292             :     nullptr, /* enumerate */
    1293             :     nullptr, /* newEnumerate */
    1294             :     nullptr, /* resolve */
    1295             :     nullptr, /* mayResolve */
    1296             :     WasmMemoryObject::finalize
    1297             : };
    1298             : 
    1299             : const Class WasmMemoryObject::class_ =
    1300             : {
    1301             :     "WebAssembly.Memory",
    1302             :     JSCLASS_DELAY_METADATA_BUILDER |
    1303             :     JSCLASS_HAS_RESERVED_SLOTS(WasmMemoryObject::RESERVED_SLOTS) |
    1304             :     JSCLASS_FOREGROUND_FINALIZE,
    1305             :     &WasmMemoryObject::classOps_
    1306             : };
    1307             : 
    1308             : /* static */ void
    1309           0 : WasmMemoryObject::finalize(FreeOp* fop, JSObject* obj)
    1310             : {
    1311           0 :     WasmMemoryObject& memory = obj->as<WasmMemoryObject>();
    1312           0 :     if (memory.hasObservers())
    1313           0 :         fop->delete_(&memory.observers());
    1314           0 : }
    1315             : 
    1316             : /* static */ WasmMemoryObject*
    1317           0 : WasmMemoryObject::create(JSContext* cx, HandleArrayBufferObjectMaybeShared buffer,
    1318             :                          HandleObject proto)
    1319             : {
    1320           0 :     AutoSetNewObjectMetadata metadata(cx);
    1321           0 :     auto* obj = NewObjectWithGivenProto<WasmMemoryObject>(cx, proto);
    1322           0 :     if (!obj)
    1323           0 :         return nullptr;
    1324             : 
    1325           0 :     obj->initReservedSlot(BUFFER_SLOT, ObjectValue(*buffer));
    1326           0 :     MOZ_ASSERT(!obj->hasObservers());
    1327           0 :     return obj;
    1328             : }
    1329             : 
    1330             : /* static */ bool
    1331           0 : WasmMemoryObject::construct(JSContext* cx, unsigned argc, Value* vp)
    1332             : {
    1333           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1334             : 
    1335           0 :     if (!ThrowIfNotConstructing(cx, args, "Memory"))
    1336           0 :         return false;
    1337             : 
    1338           0 :     if (!args.requireAtLeast(cx, "WebAssembly.Memory", 1))
    1339           0 :         return false;
    1340             : 
    1341           0 :     if (!args.get(0).isObject()) {
    1342           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_DESC_ARG, "memory");
    1343           0 :         return false;
    1344             :     }
    1345             : 
    1346           0 :     RootedObject obj(cx, &args[0].toObject());
    1347           0 :     Limits limits;
    1348           0 :     if (!GetLimits(cx, obj, MaxMemoryInitialPages, MaxMemoryMaximumPages, "Memory", &limits))
    1349           0 :         return false;
    1350             : 
    1351           0 :     limits.initial *= PageSize;
    1352           0 :     if (limits.maximum)
    1353           0 :         limits.maximum = Some(*limits.maximum * PageSize);
    1354             : 
    1355             :     RootedArrayBufferObject buffer(cx,
    1356           0 :         ArrayBufferObject::createForWasm(cx, limits.initial, limits.maximum));
    1357           0 :     if (!buffer)
    1358           0 :         return false;
    1359             : 
    1360           0 :     RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmMemory).toObject());
    1361           0 :     RootedWasmMemoryObject memoryObj(cx, WasmMemoryObject::create(cx, buffer, proto));
    1362           0 :     if (!memoryObj)
    1363           0 :         return false;
    1364             : 
    1365           0 :     args.rval().setObject(*memoryObj);
    1366           0 :     return true;
    1367             : }
    1368             : 
    1369             : static bool
    1370           0 : IsMemory(HandleValue v)
    1371             : {
    1372           0 :     return v.isObject() && v.toObject().is<WasmMemoryObject>();
    1373             : }
    1374             : 
    1375             : /* static */ bool
    1376           0 : WasmMemoryObject::bufferGetterImpl(JSContext* cx, const CallArgs& args)
    1377             : {
    1378           0 :     args.rval().setObject(args.thisv().toObject().as<WasmMemoryObject>().buffer());
    1379           0 :     return true;
    1380             : }
    1381             : 
    1382             : /* static */ bool
    1383           0 : WasmMemoryObject::bufferGetter(JSContext* cx, unsigned argc, Value* vp)
    1384             : {
    1385           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1386           0 :     return CallNonGenericMethod<IsMemory, bufferGetterImpl>(cx, args);
    1387             : }
    1388             : 
    1389             : const JSPropertySpec WasmMemoryObject::properties[] =
    1390             : {
    1391             :     JS_PSG("buffer", WasmMemoryObject::bufferGetter, 0),
    1392             :     JS_PS_END
    1393             : };
    1394             : 
    1395             : /* static */ bool
    1396           0 : WasmMemoryObject::growImpl(JSContext* cx, const CallArgs& args)
    1397             : {
    1398           0 :     RootedWasmMemoryObject memory(cx, &args.thisv().toObject().as<WasmMemoryObject>());
    1399             : 
    1400             :     uint32_t delta;
    1401           0 :     if (!ToNonWrappingUint32(cx, args.get(0), UINT32_MAX, "Memory", "grow delta", &delta))
    1402           0 :         return false;
    1403             : 
    1404           0 :     uint32_t ret = grow(memory, delta, cx);
    1405             : 
    1406           0 :     if (ret == uint32_t(-1)) {
    1407           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_GROW, "memory");
    1408           0 :         return false;
    1409             :     }
    1410             : 
    1411           0 :     args.rval().setInt32(ret);
    1412           0 :     return true;
    1413             : }
    1414             : 
    1415             : /* static */ bool
    1416           0 : WasmMemoryObject::grow(JSContext* cx, unsigned argc, Value* vp)
    1417             : {
    1418           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1419           0 :     return CallNonGenericMethod<IsMemory, growImpl>(cx, args);
    1420             : }
    1421             : 
    1422             : const JSFunctionSpec WasmMemoryObject::methods[] =
    1423             : {
    1424             :     JS_FN("grow", WasmMemoryObject::grow, 1, 0),
    1425             :     JS_FS_END
    1426             : };
    1427             : 
    1428             : const JSFunctionSpec WasmMemoryObject::static_methods[] =
    1429             : { JS_FS_END };
    1430             : 
    1431             : ArrayBufferObjectMaybeShared&
    1432           0 : WasmMemoryObject::buffer() const
    1433             : {
    1434           0 :     return getReservedSlot(BUFFER_SLOT).toObject().as<ArrayBufferObjectMaybeShared>();
    1435             : }
    1436             : 
    1437             : bool
    1438           0 : WasmMemoryObject::hasObservers() const
    1439             : {
    1440           0 :     return !getReservedSlot(OBSERVERS_SLOT).isUndefined();
    1441             : }
    1442             : 
    1443             : WasmMemoryObject::InstanceSet&
    1444           0 : WasmMemoryObject::observers() const
    1445             : {
    1446           0 :     MOZ_ASSERT(hasObservers());
    1447           0 :     return *reinterpret_cast<InstanceSet*>(getReservedSlot(OBSERVERS_SLOT).toPrivate());
    1448             : }
    1449             : 
    1450             : WasmMemoryObject::InstanceSet*
    1451           0 : WasmMemoryObject::getOrCreateObservers(JSContext* cx)
    1452             : {
    1453           0 :     if (!hasObservers()) {
    1454           0 :         auto observers = MakeUnique<InstanceSet>(cx->zone());
    1455           0 :         if (!observers || !observers->init()) {
    1456           0 :             ReportOutOfMemory(cx);
    1457           0 :             return nullptr;
    1458             :         }
    1459             : 
    1460           0 :         setReservedSlot(OBSERVERS_SLOT, PrivateValue(observers.release()));
    1461             :     }
    1462             : 
    1463           0 :     return &observers();
    1464             : }
    1465             : 
    1466             : bool
    1467           0 : WasmMemoryObject::movingGrowable() const
    1468             : {
    1469             : #ifdef WASM_HUGE_MEMORY
    1470           0 :     return false;
    1471             : #else
    1472             :     return !buffer().wasmMaxSize();
    1473             : #endif
    1474             : }
    1475             : 
    1476             : bool
    1477           0 : WasmMemoryObject::addMovingGrowObserver(JSContext* cx, WasmInstanceObject* instance)
    1478             : {
    1479           0 :     MOZ_ASSERT(movingGrowable());
    1480             : 
    1481           0 :     InstanceSet* observers = getOrCreateObservers(cx);
    1482           0 :     if (!observers)
    1483           0 :         return false;
    1484             : 
    1485           0 :     if (!observers->putNew(instance)) {
    1486           0 :         ReportOutOfMemory(cx);
    1487           0 :         return false;
    1488             :     }
    1489             : 
    1490           0 :     return true;
    1491             : }
    1492             : 
    1493             : /* static */ uint32_t
    1494           0 : WasmMemoryObject::grow(HandleWasmMemoryObject memory, uint32_t delta, JSContext* cx)
    1495             : {
    1496           0 :     RootedArrayBufferObject oldBuf(cx, &memory->buffer().as<ArrayBufferObject>());
    1497             : 
    1498           0 :     MOZ_ASSERT(oldBuf->byteLength() % PageSize == 0);
    1499           0 :     uint32_t oldNumPages = oldBuf->byteLength() / PageSize;
    1500             : 
    1501           0 :     CheckedInt<uint32_t> newSize = oldNumPages;
    1502           0 :     newSize += delta;
    1503           0 :     newSize *= PageSize;
    1504           0 :     if (!newSize.isValid())
    1505           0 :         return -1;
    1506             : 
    1507           0 :     RootedArrayBufferObject newBuf(cx);
    1508           0 :     uint8_t* prevMemoryBase = nullptr;
    1509             : 
    1510           0 :     if (Maybe<uint32_t> maxSize = oldBuf->wasmMaxSize()) {
    1511           0 :         if (newSize.value() > maxSize.value())
    1512           0 :             return -1;
    1513             : 
    1514           0 :         if (!ArrayBufferObject::wasmGrowToSizeInPlace(newSize.value(), oldBuf, &newBuf, cx))
    1515           0 :             return -1;
    1516             :     } else {
    1517             : #ifdef WASM_HUGE_MEMORY
    1518           0 :         if (!ArrayBufferObject::wasmGrowToSizeInPlace(newSize.value(), oldBuf, &newBuf, cx))
    1519           0 :             return -1;
    1520             : #else
    1521             :         MOZ_ASSERT(memory->movingGrowable());
    1522             :         prevMemoryBase = oldBuf->dataPointer();
    1523             :         if (!ArrayBufferObject::wasmMovingGrowToSize(newSize.value(), oldBuf, &newBuf, cx))
    1524             :             return -1;
    1525             : #endif
    1526             :     }
    1527             : 
    1528           0 :     memory->setReservedSlot(BUFFER_SLOT, ObjectValue(*newBuf));
    1529             : 
    1530             :     // Only notify moving-grow-observers after the BUFFER_SLOT has been updated
    1531             :     // since observers will call buffer().
    1532           0 :     if (memory->hasObservers()) {
    1533           0 :         MOZ_ASSERT(prevMemoryBase);
    1534           0 :         for (InstanceSet::Range r = memory->observers().all(); !r.empty(); r.popFront())
    1535           0 :             r.front()->instance().onMovingGrowMemory(prevMemoryBase);
    1536             :     }
    1537             : 
    1538           0 :     return oldNumPages;
    1539             : }
    1540             : 
    1541             : // ============================================================================
    1542             : // WebAssembly.Table class and methods
    1543             : 
    1544             : const ClassOps WasmTableObject::classOps_ =
    1545             : {
    1546             :     nullptr, /* addProperty */
    1547             :     nullptr, /* delProperty */
    1548             :     nullptr, /* getProperty */
    1549             :     nullptr, /* setProperty */
    1550             :     nullptr, /* enumerate */
    1551             :     nullptr, /* newEnumerate */
    1552             :     nullptr, /* resolve */
    1553             :     nullptr, /* mayResolve */
    1554             :     WasmTableObject::finalize,
    1555             :     nullptr, /* call */
    1556             :     nullptr, /* hasInstance */
    1557             :     nullptr, /* construct */
    1558             :     WasmTableObject::trace
    1559             : };
    1560             : 
    1561             : const Class WasmTableObject::class_ =
    1562             : {
    1563             :     "WebAssembly.Table",
    1564             :     JSCLASS_DELAY_METADATA_BUILDER |
    1565             :     JSCLASS_HAS_RESERVED_SLOTS(WasmTableObject::RESERVED_SLOTS) |
    1566             :     JSCLASS_FOREGROUND_FINALIZE,
    1567             :     &WasmTableObject::classOps_
    1568             : };
    1569             : 
    1570             : bool
    1571           0 : WasmTableObject::isNewborn() const
    1572             : {
    1573           0 :     MOZ_ASSERT(is<WasmTableObject>());
    1574           0 :     return getReservedSlot(TABLE_SLOT).isUndefined();
    1575             : }
    1576             : 
    1577             : /* static */ void
    1578           0 : WasmTableObject::finalize(FreeOp* fop, JSObject* obj)
    1579             : {
    1580           0 :     WasmTableObject& tableObj = obj->as<WasmTableObject>();
    1581           0 :     if (!tableObj.isNewborn())
    1582           0 :         tableObj.table().Release();
    1583           0 : }
    1584             : 
    1585             : /* static */ void
    1586           0 : WasmTableObject::trace(JSTracer* trc, JSObject* obj)
    1587             : {
    1588           0 :     WasmTableObject& tableObj = obj->as<WasmTableObject>();
    1589           0 :     if (!tableObj.isNewborn())
    1590           0 :         tableObj.table().tracePrivate(trc);
    1591           0 : }
    1592             : 
    1593             : /* static */ WasmTableObject*
    1594           0 : WasmTableObject::create(JSContext* cx, const Limits& limits)
    1595             : {
    1596           0 :     RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmTable).toObject());
    1597             : 
    1598           0 :     AutoSetNewObjectMetadata metadata(cx);
    1599           0 :     RootedWasmTableObject obj(cx, NewObjectWithGivenProto<WasmTableObject>(cx, proto));
    1600           0 :     if (!obj)
    1601           0 :         return nullptr;
    1602             : 
    1603           0 :     MOZ_ASSERT(obj->isNewborn());
    1604             : 
    1605           0 :     TableDesc td(TableKind::AnyFunction, limits);
    1606           0 :     td.external = true;
    1607             : 
    1608           0 :     SharedTable table = Table::create(cx, td, obj);
    1609           0 :     if (!table)
    1610           0 :         return nullptr;
    1611             : 
    1612           0 :     obj->initReservedSlot(TABLE_SLOT, PrivateValue(table.forget().take()));
    1613             : 
    1614           0 :     MOZ_ASSERT(!obj->isNewborn());
    1615           0 :     return obj;
    1616             : }
    1617             : 
    1618             : /* static */ bool
    1619           0 : WasmTableObject::construct(JSContext* cx, unsigned argc, Value* vp)
    1620             : {
    1621           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1622             : 
    1623           0 :     if (!ThrowIfNotConstructing(cx, args, "Table"))
    1624           0 :         return false;
    1625             : 
    1626           0 :     if (!args.requireAtLeast(cx, "WebAssembly.Table", 1))
    1627           0 :         return false;
    1628             : 
    1629           0 :     if (!args.get(0).isObject()) {
    1630           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_DESC_ARG, "table");
    1631           0 :         return false;
    1632             :     }
    1633             : 
    1634           0 :     RootedObject obj(cx, &args[0].toObject());
    1635             : 
    1636           0 :     JSAtom* elementAtom = Atomize(cx, "element", strlen("element"));
    1637           0 :     if (!elementAtom)
    1638           0 :         return false;
    1639           0 :     RootedId elementId(cx, AtomToId(elementAtom));
    1640             : 
    1641           0 :     RootedValue elementVal(cx);
    1642           0 :     if (!GetProperty(cx, obj, obj, elementId, &elementVal))
    1643           0 :         return false;
    1644             : 
    1645           0 :     if (!elementVal.isString()) {
    1646           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_ELEMENT);
    1647           0 :         return false;
    1648             :     }
    1649             : 
    1650           0 :     JSLinearString* elementStr = elementVal.toString()->ensureLinear(cx);
    1651           0 :     if (!elementStr)
    1652           0 :         return false;
    1653             : 
    1654           0 :     if (!StringEqualsAscii(elementStr, "anyfunc")) {
    1655           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_ELEMENT);
    1656           0 :         return false;
    1657             :     }
    1658             : 
    1659           0 :     Limits limits;
    1660           0 :     if (!GetLimits(cx, obj, MaxTableInitialLength, UINT32_MAX, "Table", &limits))
    1661           0 :         return false;
    1662             : 
    1663           0 :     RootedWasmTableObject table(cx, WasmTableObject::create(cx, limits));
    1664           0 :     if (!table)
    1665           0 :         return false;
    1666             : 
    1667           0 :     args.rval().setObject(*table);
    1668           0 :     return true;
    1669             : }
    1670             : 
    1671             : static bool
    1672           0 : IsTable(HandleValue v)
    1673             : {
    1674           0 :     return v.isObject() && v.toObject().is<WasmTableObject>();
    1675             : }
    1676             : 
    1677             : /* static */ bool
    1678           0 : WasmTableObject::lengthGetterImpl(JSContext* cx, const CallArgs& args)
    1679             : {
    1680           0 :     args.rval().setNumber(args.thisv().toObject().as<WasmTableObject>().table().length());
    1681           0 :     return true;
    1682             : }
    1683             : 
    1684             : /* static */ bool
    1685           0 : WasmTableObject::lengthGetter(JSContext* cx, unsigned argc, Value* vp)
    1686             : {
    1687           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1688           0 :     return CallNonGenericMethod<IsTable, lengthGetterImpl>(cx, args);
    1689             : }
    1690             : 
    1691             : const JSPropertySpec WasmTableObject::properties[] =
    1692             : {
    1693             :     JS_PSG("length", WasmTableObject::lengthGetter, 0),
    1694             :     JS_PS_END
    1695             : };
    1696             : 
    1697             : /* static */ bool
    1698           0 : WasmTableObject::getImpl(JSContext* cx, const CallArgs& args)
    1699             : {
    1700           0 :     RootedWasmTableObject tableObj(cx, &args.thisv().toObject().as<WasmTableObject>());
    1701           0 :     const Table& table = tableObj->table();
    1702             : 
    1703             :     uint32_t index;
    1704           0 :     if (!ToNonWrappingUint32(cx, args.get(0), table.length() - 1, "Table", "get index", &index))
    1705           0 :         return false;
    1706             : 
    1707           0 :     ExternalTableElem& elem = table.externalArray()[index];
    1708           0 :     if (!elem.code) {
    1709           0 :         args.rval().setNull();
    1710           0 :         return true;
    1711             :     }
    1712             : 
    1713           0 :     Instance& instance = *elem.tls->instance;
    1714           0 :     const CodeRange& codeRange = *instance.code().lookupRange(elem.code);
    1715           0 :     MOZ_ASSERT(codeRange.isFunction());
    1716             : 
    1717           0 :     RootedWasmInstanceObject instanceObj(cx, instance.object());
    1718           0 :     RootedFunction fun(cx);
    1719           0 :     if (!instanceObj->getExportedFunction(cx, instanceObj, codeRange.funcIndex(), &fun))
    1720           0 :         return false;
    1721             : 
    1722           0 :     args.rval().setObject(*fun);
    1723           0 :     return true;
    1724             : }
    1725             : 
    1726             : /* static */ bool
    1727           0 : WasmTableObject::get(JSContext* cx, unsigned argc, Value* vp)
    1728             : {
    1729           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1730           0 :     return CallNonGenericMethod<IsTable, getImpl>(cx, args);
    1731             : }
    1732             : 
    1733             : /* static */ bool
    1734           0 : WasmTableObject::setImpl(JSContext* cx, const CallArgs& args)
    1735             : {
    1736           0 :     RootedWasmTableObject tableObj(cx, &args.thisv().toObject().as<WasmTableObject>());
    1737           0 :     Table& table = tableObj->table();
    1738             : 
    1739           0 :     if (!args.requireAtLeast(cx, "set", 2))
    1740           0 :         return false;
    1741             : 
    1742             :     uint32_t index;
    1743           0 :     if (!ToNonWrappingUint32(cx, args.get(0), table.length() - 1, "Table", "set index", &index))
    1744           0 :         return false;
    1745             : 
    1746           0 :     RootedFunction value(cx);
    1747           0 :     if (!IsExportedFunction(args[1], &value) && !args[1].isNull()) {
    1748           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_TABLE_VALUE);
    1749           0 :         return false;
    1750             :     }
    1751             : 
    1752           0 :     if (value) {
    1753           0 :         RootedWasmInstanceObject instanceObj(cx, ExportedFunctionToInstanceObject(value));
    1754           0 :         uint32_t funcIndex = ExportedFunctionToFuncIndex(value);
    1755           0 :         Tier tier = Tier::TBD;  // Perhaps the tier that the function is at?
    1756             : 
    1757             : #ifdef DEBUG
    1758           0 :         RootedFunction f(cx);
    1759           0 :         MOZ_ASSERT(instanceObj->getExportedFunction(cx, instanceObj, funcIndex, &f));
    1760           0 :         MOZ_ASSERT(value == f);
    1761             : #endif
    1762             : 
    1763           0 :         Instance& instance = instanceObj->instance();
    1764           0 :         const FuncExport& funcExport = instance.metadata(tier).lookupFuncExport(funcIndex);
    1765           0 :         const CodeRange& codeRange = instance.metadata(tier).codeRanges[funcExport.codeRangeIndex()];
    1766           0 :         void* code = instance.codeBase(tier) + codeRange.funcTableEntry();
    1767           0 :         table.set(index, code, instance);
    1768             :     } else {
    1769           0 :         table.setNull(index);
    1770             :     }
    1771             : 
    1772           0 :     args.rval().setUndefined();
    1773           0 :     return true;
    1774             : }
    1775             : 
    1776             : /* static */ bool
    1777           0 : WasmTableObject::set(JSContext* cx, unsigned argc, Value* vp)
    1778             : {
    1779           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1780           0 :     return CallNonGenericMethod<IsTable, setImpl>(cx, args);
    1781             : }
    1782             : 
    1783             : /* static */ bool
    1784           0 : WasmTableObject::growImpl(JSContext* cx, const CallArgs& args)
    1785             : {
    1786           0 :     RootedWasmTableObject table(cx, &args.thisv().toObject().as<WasmTableObject>());
    1787             : 
    1788             :     uint32_t delta;
    1789           0 :     if (!ToNonWrappingUint32(cx, args.get(0), UINT32_MAX, "Table", "grow delta", &delta))
    1790           0 :         return false;
    1791             : 
    1792           0 :     uint32_t ret = table->table().grow(delta, cx);
    1793             : 
    1794           0 :     if (ret == uint32_t(-1)) {
    1795           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_GROW, "table");
    1796           0 :         return false;
    1797             :     }
    1798             : 
    1799           0 :     args.rval().setInt32(ret);
    1800           0 :     return true;
    1801             : }
    1802             : 
    1803             : /* static */ bool
    1804           0 : WasmTableObject::grow(JSContext* cx, unsigned argc, Value* vp)
    1805             : {
    1806           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1807           0 :     return CallNonGenericMethod<IsTable, growImpl>(cx, args);
    1808             : }
    1809             : 
    1810             : const JSFunctionSpec WasmTableObject::methods[] =
    1811             : {
    1812             :     JS_FN("get", WasmTableObject::get, 1, 0),
    1813             :     JS_FN("set", WasmTableObject::set, 2, 0),
    1814             :     JS_FN("grow", WasmTableObject::grow, 1, 0),
    1815             :     JS_FS_END
    1816             : };
    1817             : 
    1818             : const JSFunctionSpec WasmTableObject::static_methods[] =
    1819             : { JS_FS_END };
    1820             : 
    1821             : Table&
    1822           0 : WasmTableObject::table() const
    1823             : {
    1824           0 :     return *(Table*)getReservedSlot(TABLE_SLOT).toPrivate();
    1825             : }
    1826             : 
    1827             : // ============================================================================
    1828             : // WebAssembly class and static methods
    1829             : 
    1830             : #if JS_HAS_TOSOURCE
    1831             : static bool
    1832           0 : WebAssembly_toSource(JSContext* cx, unsigned argc, Value* vp)
    1833             : {
    1834           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1835           0 :     args.rval().setString(cx->names().WebAssembly);
    1836           0 :     return true;
    1837             : }
    1838             : #endif
    1839             : 
    1840             : static bool
    1841           0 : Reject(JSContext* cx, const CompileArgs& args, UniqueChars error, Handle<PromiseObject*> promise)
    1842             : {
    1843           0 :     if (!error) {
    1844           0 :         ReportOutOfMemory(cx);
    1845             : 
    1846           0 :         RootedValue rejectionValue(cx);
    1847           0 :         if (!cx->getPendingException(&rejectionValue))
    1848           0 :             return false;
    1849             : 
    1850           0 :         return PromiseObject::reject(cx, promise, rejectionValue);
    1851             :     }
    1852             : 
    1853           0 :     RootedObject stack(cx, promise->allocationSite());
    1854           0 :     RootedString filename(cx, JS_NewStringCopyZ(cx, args.scriptedCaller.filename.get()));
    1855           0 :     if (!filename)
    1856           0 :         return false;
    1857             : 
    1858           0 :     unsigned line = args.scriptedCaller.line;
    1859           0 :     unsigned column = args.scriptedCaller.column;
    1860             : 
    1861             :     // Ideally we'd report a JSMSG_WASM_COMPILE_ERROR here, but there's no easy
    1862             :     // way to create an ErrorObject for an arbitrary error code with multiple
    1863             :     // replacements.
    1864           0 :     UniqueChars str(JS_smprintf("wasm validation error: %s", error.get()));
    1865           0 :     if (!str)
    1866           0 :         return false;
    1867             : 
    1868           0 :     RootedString message(cx, NewLatin1StringZ(cx, Move(str)));
    1869           0 :     if (!message)
    1870           0 :         return false;
    1871             : 
    1872             :     RootedObject errorObj(cx,
    1873           0 :         ErrorObject::create(cx, JSEXN_WASMCOMPILEERROR, stack, filename, line, column, nullptr, message));
    1874           0 :     if (!errorObj)
    1875           0 :         return false;
    1876             : 
    1877           0 :     RootedValue rejectionValue(cx, ObjectValue(*errorObj));
    1878           0 :     return PromiseObject::reject(cx, promise, rejectionValue);
    1879             : }
    1880             : 
    1881             : static bool
    1882           0 : ResolveCompilation(JSContext* cx, Module& module, Handle<PromiseObject*> promise)
    1883             : {
    1884           0 :     RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmModule).toObject());
    1885           0 :     RootedObject moduleObj(cx, WasmModuleObject::create(cx, module, proto));
    1886           0 :     if (!moduleObj)
    1887           0 :         return false;
    1888             : 
    1889           0 :     RootedValue resolutionValue(cx, ObjectValue(*moduleObj));
    1890           0 :     return PromiseObject::resolve(cx, promise, resolutionValue);
    1891             : }
    1892             : 
    1893           0 : struct CompilePromiseTask : PromiseTask
    1894             : {
    1895             :     MutableBytes bytecode;
    1896             :     CompileArgs  compileArgs;
    1897             :     UniqueChars  error;
    1898             :     SharedModule module;
    1899             : 
    1900           0 :     CompilePromiseTask(JSContext* cx, Handle<PromiseObject*> promise)
    1901           0 :       : PromiseTask(cx, promise)
    1902           0 :     {}
    1903             : 
    1904           0 :     void execute() override {
    1905           0 :         module = Compile(*bytecode, compileArgs, &error);
    1906           0 :     }
    1907             : 
    1908           0 :     bool finishPromise(JSContext* cx, Handle<PromiseObject*> promise) override {
    1909             :         return module
    1910           0 :                ? ResolveCompilation(cx, *module, promise)
    1911           0 :                : Reject(cx, compileArgs, Move(error), promise);
    1912             :     }
    1913             : };
    1914             : 
    1915             : static bool
    1916           0 : RejectWithPendingException(JSContext* cx, Handle<PromiseObject*> promise)
    1917             : {
    1918           0 :     if (!cx->isExceptionPending())
    1919           0 :         return false;
    1920             : 
    1921           0 :     RootedValue rejectionValue(cx);
    1922           0 :     if (!GetAndClearException(cx, &rejectionValue))
    1923           0 :         return false;
    1924             : 
    1925           0 :     return PromiseObject::reject(cx, promise, rejectionValue);
    1926             : }
    1927             : 
    1928             : static bool
    1929           0 : RejectWithPendingException(JSContext* cx, Handle<PromiseObject*> promise, CallArgs& callArgs)
    1930             : {
    1931           0 :     if (!RejectWithPendingException(cx, promise))
    1932           0 :         return false;
    1933             : 
    1934           0 :     callArgs.rval().setObject(*promise);
    1935           0 :     return true;
    1936             : }
    1937             : 
    1938             : static bool
    1939           0 : GetBufferSource(JSContext* cx, CallArgs callArgs, const char* name, MutableBytes* bytecode)
    1940             : {
    1941           0 :     if (!callArgs.requireAtLeast(cx, name, 1))
    1942           0 :         return false;
    1943             : 
    1944           0 :     if (!callArgs[0].isObject()) {
    1945           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_BUF_ARG);
    1946           0 :         return false;
    1947             :     }
    1948             : 
    1949           0 :     return GetBufferSource(cx, &callArgs[0].toObject(), JSMSG_WASM_BAD_BUF_ARG, bytecode);
    1950             : }
    1951             : 
    1952             : static bool
    1953           0 : WebAssembly_compile(JSContext* cx, unsigned argc, Value* vp)
    1954             : {
    1955           0 :     if (!cx->runtime()->startAsyncTaskCallback || !cx->runtime()->finishAsyncTaskCallback) {
    1956           0 :         JS_ReportErrorASCII(cx, "WebAssembly.compile not supported in this runtime.");
    1957           0 :         return false;
    1958             :     }
    1959             : 
    1960           0 :     Rooted<PromiseObject*> promise(cx, PromiseObject::createSkippingExecutor(cx));
    1961           0 :     if (!promise)
    1962           0 :         return false;
    1963             : 
    1964           0 :     auto task = cx->make_unique<CompilePromiseTask>(cx, promise);
    1965           0 :     if (!task)
    1966           0 :         return false;
    1967             : 
    1968           0 :     CallArgs callArgs = CallArgsFromVp(argc, vp);
    1969             : 
    1970           0 :     if (!GetBufferSource(cx, callArgs, "WebAssembly.compile", &task->bytecode))
    1971           0 :         return RejectWithPendingException(cx, promise, callArgs);
    1972             : 
    1973           0 :     if (!InitCompileArgs(cx, &task->compileArgs))
    1974           0 :         return false;
    1975             : 
    1976           0 :     if (!StartPromiseTask(cx, Move(task)))
    1977           0 :         return false;
    1978             : 
    1979           0 :     callArgs.rval().setObject(*promise);
    1980           0 :     return true;
    1981             : }
    1982             : 
    1983             : static bool
    1984           0 : ResolveInstantiation(JSContext* cx, Module& module, HandleObject importObj,
    1985             :                      Handle<PromiseObject*> promise)
    1986             : {
    1987           0 :     RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmModule).toObject());
    1988           0 :     RootedObject moduleObj(cx, WasmModuleObject::create(cx, module, proto));
    1989           0 :     if (!moduleObj)
    1990           0 :         return false;
    1991             : 
    1992           0 :     RootedWasmInstanceObject instanceObj(cx);
    1993           0 :     if (!Instantiate(cx, module, importObj, &instanceObj))
    1994           0 :         return RejectWithPendingException(cx, promise);
    1995             : 
    1996           0 :     RootedObject resultObj(cx, JS_NewPlainObject(cx));
    1997           0 :     if (!resultObj)
    1998           0 :         return false;
    1999             : 
    2000           0 :     RootedValue val(cx, ObjectValue(*moduleObj));
    2001           0 :     if (!JS_DefineProperty(cx, resultObj, "module", val, JSPROP_ENUMERATE))
    2002           0 :         return false;
    2003             : 
    2004           0 :     val = ObjectValue(*instanceObj);
    2005           0 :     if (!JS_DefineProperty(cx, resultObj, "instance", val, JSPROP_ENUMERATE))
    2006           0 :         return false;
    2007             : 
    2008           0 :     val = ObjectValue(*resultObj);
    2009           0 :     return PromiseObject::resolve(cx, promise, val);
    2010             : }
    2011             : 
    2012           0 : struct InstantiatePromiseTask : CompilePromiseTask
    2013             : {
    2014             :     PersistentRootedObject importObj;
    2015             : 
    2016           0 :     InstantiatePromiseTask(JSContext* cx, Handle<PromiseObject*> promise, HandleObject importObj)
    2017           0 :       : CompilePromiseTask(cx, promise),
    2018           0 :         importObj(cx, importObj)
    2019           0 :     {}
    2020             : 
    2021           0 :     bool finishPromise(JSContext* cx, Handle<PromiseObject*> promise) override {
    2022             :         return module
    2023           0 :                ? ResolveInstantiation(cx, *module, importObj, promise)
    2024           0 :                : Reject(cx, compileArgs, Move(error), promise);
    2025             :     }
    2026             : };
    2027             : 
    2028             : static bool
    2029           0 : GetInstantiateArgs(JSContext* cx, CallArgs callArgs, MutableHandleObject firstArg,
    2030             :                    MutableHandleObject importObj)
    2031             : {
    2032           0 :     if (!callArgs.requireAtLeast(cx, "WebAssembly.instantiate", 1))
    2033           0 :         return false;
    2034             : 
    2035           0 :     if (!callArgs[0].isObject()) {
    2036           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_BUF_MOD_ARG);
    2037           0 :         return false;
    2038             :     }
    2039             : 
    2040           0 :     firstArg.set(&callArgs[0].toObject());
    2041             : 
    2042           0 :     return GetImportArg(cx, callArgs, importObj);
    2043             : }
    2044             : 
    2045             : static bool
    2046           0 : WebAssembly_instantiate(JSContext* cx, unsigned argc, Value* vp)
    2047             : {
    2048           0 :     if (!cx->runtime()->startAsyncTaskCallback || !cx->runtime()->finishAsyncTaskCallback) {
    2049           0 :         JS_ReportErrorASCII(cx, "WebAssembly.instantiate not supported in this runtime.");
    2050           0 :         return false;
    2051             :     }
    2052             : 
    2053           0 :     Rooted<PromiseObject*> promise(cx, PromiseObject::createSkippingExecutor(cx));
    2054           0 :     if (!promise)
    2055           0 :         return false;
    2056             : 
    2057           0 :     CallArgs callArgs = CallArgsFromVp(argc, vp);
    2058             : 
    2059           0 :     RootedObject firstArg(cx);
    2060           0 :     RootedObject importObj(cx);
    2061           0 :     if (!GetInstantiateArgs(cx, callArgs, &firstArg, &importObj))
    2062           0 :         return RejectWithPendingException(cx, promise, callArgs);
    2063             : 
    2064             :     Module* module;
    2065           0 :     if (IsModuleObject(firstArg, &module)) {
    2066           0 :         RootedWasmInstanceObject instanceObj(cx);
    2067           0 :         if (!Instantiate(cx, *module, importObj, &instanceObj))
    2068           0 :             return RejectWithPendingException(cx, promise, callArgs);
    2069             : 
    2070           0 :         RootedValue resolutionValue(cx, ObjectValue(*instanceObj));
    2071           0 :         if (!PromiseObject::resolve(cx, promise, resolutionValue))
    2072           0 :             return false;
    2073             :     } else {
    2074           0 :         auto task = cx->make_unique<InstantiatePromiseTask>(cx, promise, importObj);
    2075           0 :         if (!task)
    2076           0 :             return false;
    2077             : 
    2078           0 :         if (!GetBufferSource(cx, firstArg, JSMSG_WASM_BAD_BUF_MOD_ARG, &task->bytecode))
    2079           0 :             return RejectWithPendingException(cx, promise, callArgs);
    2080             : 
    2081           0 :         if (!InitCompileArgs(cx, &task->compileArgs))
    2082           0 :             return false;
    2083             : 
    2084           0 :         if (!StartPromiseTask(cx, Move(task)))
    2085           0 :             return false;
    2086             :     }
    2087             : 
    2088           0 :     callArgs.rval().setObject(*promise);
    2089           0 :     return true;
    2090             : }
    2091             : 
    2092             : static bool
    2093           0 : WebAssembly_validate(JSContext* cx, unsigned argc, Value* vp)
    2094             : {
    2095           0 :     CallArgs callArgs = CallArgsFromVp(argc, vp);
    2096             : 
    2097           0 :     MutableBytes bytecode;
    2098           0 :     if (!GetBufferSource(cx, callArgs, "WebAssembly.validate", &bytecode))
    2099           0 :         return false;
    2100             : 
    2101           0 :     UniqueChars error;
    2102           0 :     bool validated = Validate(*bytecode, &error);
    2103             : 
    2104             :     // If the reason for validation failure was OOM (signalled by null error
    2105             :     // message), report out-of-memory so that validate's return is always
    2106             :     // correct.
    2107           0 :     if (!validated && !error) {
    2108           0 :         ReportOutOfMemory(cx);
    2109           0 :         return false;
    2110             :     }
    2111             : 
    2112           0 :     callArgs.rval().setBoolean(validated);
    2113           0 :     return true;
    2114             : }
    2115             : 
    2116             : static const JSFunctionSpec WebAssembly_static_methods[] =
    2117             : {
    2118             : #if JS_HAS_TOSOURCE
    2119             :     JS_FN(js_toSource_str, WebAssembly_toSource, 0, 0),
    2120             : #endif
    2121             :     JS_FN("compile", WebAssembly_compile, 1, 0),
    2122             :     JS_FN("instantiate", WebAssembly_instantiate, 1, 0),
    2123             :     JS_FN("validate", WebAssembly_validate, 1, 0),
    2124             :     JS_FS_END
    2125             : };
    2126             : 
    2127             : const Class js::WebAssemblyClass =
    2128             : {
    2129             :     js_WebAssembly_str,
    2130             :     JSCLASS_HAS_CACHED_PROTO(JSProto_WebAssembly)
    2131             : };
    2132             : 
    2133             : template <class Class>
    2134             : static bool
    2135          24 : InitConstructor(JSContext* cx, HandleObject wasm, const char* name, MutableHandleObject proto)
    2136             : {
    2137          24 :     proto.set(NewBuiltinClassInstance<PlainObject>(cx, SingletonObject));
    2138          24 :     if (!proto)
    2139           0 :         return false;
    2140             : 
    2141          24 :     if (!DefinePropertiesAndFunctions(cx, proto, Class::properties, Class::methods))
    2142           0 :         return false;
    2143             : 
    2144          48 :     RootedAtom className(cx, Atomize(cx, name, strlen(name)));
    2145          24 :     if (!className)
    2146           0 :         return false;
    2147             : 
    2148          48 :     RootedFunction ctor(cx, NewNativeConstructor(cx, Class::construct, 1, className));
    2149          24 :     if (!ctor)
    2150           0 :         return false;
    2151             : 
    2152          24 :     if (!DefinePropertiesAndFunctions(cx, ctor, nullptr, Class::static_methods))
    2153           0 :         return false;
    2154             : 
    2155          24 :     if (!LinkConstructorAndPrototype(cx, ctor, proto))
    2156           0 :         return false;
    2157             : 
    2158          48 :     UniqueChars tagStr(JS_smprintf("WebAssembly.%s", name));
    2159          24 :     if (!tagStr) {
    2160           0 :         ReportOutOfMemory(cx);
    2161           0 :         return false;
    2162             :     }
    2163             : 
    2164          48 :     RootedAtom tag(cx, Atomize(cx, tagStr.get(), strlen(tagStr.get())));
    2165          24 :     if (!tag)
    2166           0 :         return false;
    2167          24 :     if (!DefineToStringTag(cx, proto, tag))
    2168           0 :         return false;
    2169             : 
    2170          48 :     RootedId id(cx, AtomToId(className));
    2171          48 :     RootedValue ctorValue(cx, ObjectValue(*ctor));
    2172          24 :     return DefineProperty(cx, wasm, id, ctorValue, nullptr, nullptr, 0);
    2173             : }
    2174             : 
    2175             : static bool
    2176          18 : InitErrorClass(JSContext* cx, HandleObject wasm, const char* name, JSExnType exn)
    2177             : {
    2178          18 :     Handle<GlobalObject*> global = cx->global();
    2179          36 :     RootedObject proto(cx, GlobalObject::getOrCreateCustomErrorPrototype(cx, global, exn));
    2180          18 :     if (!proto)
    2181           0 :         return false;
    2182             : 
    2183          36 :     RootedAtom className(cx, Atomize(cx, name, strlen(name)));
    2184          18 :     if (!className)
    2185           0 :         return false;
    2186             : 
    2187          36 :     RootedId id(cx, AtomToId(className));
    2188          36 :     RootedValue ctorValue(cx, global->getConstructor(GetExceptionProtoKey(exn)));
    2189          18 :     return DefineProperty(cx, wasm, id, ctorValue, nullptr, nullptr, 0);
    2190             : }
    2191             : 
    2192             : JSObject*
    2193           6 : js::InitWebAssemblyClass(JSContext* cx, HandleObject obj)
    2194             : {
    2195           6 :     MOZ_RELEASE_ASSERT(HasSupport(cx));
    2196             : 
    2197           6 :     Handle<GlobalObject*> global = obj.as<GlobalObject>();
    2198           6 :     MOZ_ASSERT(!global->isStandardClassResolved(JSProto_WebAssembly));
    2199             : 
    2200          12 :     RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global));
    2201           6 :     if (!proto)
    2202           0 :         return nullptr;
    2203             : 
    2204          12 :     RootedObject wasm(cx, NewObjectWithGivenProto(cx, &WebAssemblyClass, proto, SingletonObject));
    2205           6 :     if (!wasm)
    2206           0 :         return nullptr;
    2207             : 
    2208           6 :     if (!JS_DefineFunctions(cx, wasm, WebAssembly_static_methods))
    2209           0 :         return nullptr;
    2210             : 
    2211          12 :     RootedObject moduleProto(cx), instanceProto(cx), memoryProto(cx), tableProto(cx);
    2212           6 :     if (!InitConstructor<WasmModuleObject>(cx, wasm, "Module", &moduleProto))
    2213           0 :         return nullptr;
    2214           6 :     if (!InitConstructor<WasmInstanceObject>(cx, wasm, "Instance", &instanceProto))
    2215           0 :         return nullptr;
    2216           6 :     if (!InitConstructor<WasmMemoryObject>(cx, wasm, "Memory", &memoryProto))
    2217           0 :         return nullptr;
    2218           6 :     if (!InitConstructor<WasmTableObject>(cx, wasm, "Table", &tableProto))
    2219           0 :         return nullptr;
    2220           6 :     if (!InitErrorClass(cx, wasm, "CompileError", JSEXN_WASMCOMPILEERROR))
    2221           0 :         return nullptr;
    2222           6 :     if (!InitErrorClass(cx, wasm, "LinkError", JSEXN_WASMLINKERROR))
    2223           0 :         return nullptr;
    2224           6 :     if (!InitErrorClass(cx, wasm, "RuntimeError", JSEXN_WASMRUNTIMEERROR))
    2225           0 :         return nullptr;
    2226             : 
    2227             :     // Perform the final fallible write of the WebAssembly object to a global
    2228             :     // object property at the end. Only after that succeeds write all the
    2229             :     // constructor and prototypes to the JSProto slots. This ensures that
    2230             :     // initialization is atomic since a failed initialization can be retried.
    2231             : 
    2232           6 :     if (!JS_DefineProperty(cx, global, js_WebAssembly_str, wasm, JSPROP_RESOLVING))
    2233           0 :         return nullptr;
    2234             : 
    2235           6 :     global->setPrototype(JSProto_WasmModule, ObjectValue(*moduleProto));
    2236           6 :     global->setPrototype(JSProto_WasmInstance, ObjectValue(*instanceProto));
    2237           6 :     global->setPrototype(JSProto_WasmMemory, ObjectValue(*memoryProto));
    2238           6 :     global->setPrototype(JSProto_WasmTable, ObjectValue(*tableProto));
    2239           6 :     global->setConstructor(JSProto_WebAssembly, ObjectValue(*wasm));
    2240             : 
    2241           6 :     MOZ_ASSERT(global->isStandardClassResolved(JSProto_WebAssembly));
    2242           6 :     return wasm;
    2243             : }

Generated by: LCOV version 1.13