--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -753,16 +753,17 @@ BytecodeEmitter::EmitterScope::searchInE
case ScopeKind::Global:
return NameLocation::Global(BindingKind::Var);
case ScopeKind::With:
case ScopeKind::NonSyntactic:
return NameLocation::Dynamic();
+ case ScopeKind::WasmInstance:
case ScopeKind::WasmFunction:
MOZ_CRASH("No direct eval inside wasm functions");
}
if (hasEnv) {
MOZ_ASSERT(hops < ENVCOORD_HOPS_LIMIT - 1);
hops++;
}
@@ -1453,16 +1454,17 @@ BytecodeEmitter::EmitterScope::leave(Byt
case ScopeKind::StrictNamedLambda:
case ScopeKind::Eval:
case ScopeKind::StrictEval:
case ScopeKind::Global:
case ScopeKind::NonSyntactic:
case ScopeKind::Module:
break;
+ case ScopeKind::WasmInstance:
case ScopeKind::WasmFunction:
MOZ_CRASH("No wasm function scopes in JS");
}
// Finish up the scope if we are leaving it in LIFO fashion.
if (!nonLocal) {
// Popping scopes due to non-local jumps generate additional scope
// notes. See NonLocalExitControl::prepareForNonLocalJump.
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -1280,19 +1280,24 @@ EvalScope::Data::trace(JSTracer* trc)
}
void
ModuleScope::Data::trace(JSTracer* trc)
{
TraceNullableEdge(trc, &module, "scope module");
TraceBindingNames(trc, names, length);
}
void
+WasmInstanceScope::Data::trace(JSTracer* trc)
+{
+ TraceNullableEdge(trc, &instance, "wasm instance");
+ TraceBindingNames(trc, names, length);
+}
+void
WasmFunctionScope::Data::trace(JSTracer* trc)
{
- TraceNullableEdge(trc, &instance, "wasm function");
TraceBindingNames(trc, names, length);
}
void
Scope::traceChildren(JSTracer* trc)
{
TraceNullableEdge(trc, &enclosing_, "scope enclosing");
TraceNullableEdge(trc, &environmentShape_, "scope env shape");
switch (kind_) {
@@ -1318,16 +1323,19 @@ Scope::traceChildren(JSTracer* trc)
case ScopeKind::StrictEval:
reinterpret_cast<EvalScope::Data*>(data_)->trace(trc);
break;
case ScopeKind::Module:
reinterpret_cast<ModuleScope::Data*>(data_)->trace(trc);
break;
case ScopeKind::With:
break;
+ case ScopeKind::WasmInstance:
+ reinterpret_cast<WasmInstanceScope::Data*>(data_)->trace(trc);
+ break;
case ScopeKind::WasmFunction:
reinterpret_cast<WasmFunctionScope::Data*>(data_)->trace(trc);
break;
}
}
inline void
js::GCMarker::eagerlyMarkChildren(Scope* scope)
{
@@ -1387,19 +1395,26 @@ js::GCMarker::eagerlyMarkChildren(Scope*
names = data->names;
length = data->length;
break;
}
case ScopeKind::With:
break;
+ case ScopeKind::WasmInstance: {
+ WasmInstanceScope::Data* data = reinterpret_cast<WasmInstanceScope::Data*>(scope->data_);
+ traverseEdge(scope, static_cast<JSObject*>(data->instance));
+ names = data->names;
+ length = data->length;
+ break;
+ }
+
case ScopeKind::WasmFunction: {
WasmFunctionScope::Data* data = reinterpret_cast<WasmFunctionScope::Data*>(scope->data_);
- traverseEdge(scope, static_cast<JSObject*>(data->instance));
names = data->names;
length = data->length;
break;
}
}
if (scope->kind_ == ScopeKind::Function) {
for (uint32_t i = 0; i < length; i++) {
if (JSAtom* name = names[i].name())
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/wasm-13.js
@@ -0,0 +1,95 @@
+// |jit-test| test-also-wasm-baseline
+// Tests that wasm module scripts has inspectable globals and memory.
+
+load(libdir + "wasm.js");
+load(libdir + 'eqArrayHelper.js');
+
+function monitorGlobalValues(wast, lib, expected) {
+ function setupFrame(frame) {
+ var globals = {};
+ framesGlobals.push(globals);
+ // Environment with globals follow function scope enviroment
+ var globalEnv = frame.environment.parent;
+ globalEnv.names().forEach(n => {
+ globals[n] = [globalEnv.getVariable(n)];
+ });
+ frame.onStep = function () {
+ var globalEnv = frame.environment.parent;
+ globalEnv.names().forEach(n => {
+ var prevValues = globals[n];
+ if (!prevValues)
+ globals[n] = prevValues = [void 0];
+ var value = globalEnv.getVariable(n);
+ if (prevValues[prevValues.length - 1] !== value)
+ prevValues.push(value);
+ });
+ }
+ }
+ var framesGlobals = [];
+ wasmRunWithDebugger(wast, lib,
+ function ({dbg}) {
+ dbg.onEnterFrame = function(frame) {
+ if (frame.type == "wasmcall")
+ setupFrame(frame);
+ }
+ },
+ function ({error}) {
+ assertEq(error, undefined);
+ }
+ );
+ assertEq(framesGlobals.length, expected.length);
+ for (var i = 0; i < framesGlobals.length; i++) {
+ var frameGlobals = framesGlobals[i];
+ var expectedGlobals = expected[i];
+ var globalsNames = Object.keys(frameGlobals);
+ assertEq(globalsNames.length, Object.keys(expectedGlobals).length);
+ globalsNames.forEach(n => {
+ if (typeof expectedGlobals[n][0] === "function") {
+ // expectedGlobals are assert functions
+ expectedGlobals[n].forEach((assertFn, i) => {
+ assertFn(frameGlobals[n][i]);
+ });
+ return;
+ }
+ assertEqArray(frameGlobals[n], expectedGlobals[n]);
+ });
+ }
+}
+
+monitorGlobalValues(
+ '(module (func (export "test") (nop)))',
+ undefined,
+ [{}]
+);
+monitorGlobalValues(
+ '(module (memory (export "memory") 1 1) (func (export "test") (nop) (nop)))',
+ undefined,
+ [{
+ memory0: [
+ function (actual) {
+ var bufferProp = actual.proto.getOwnPropertyDescriptor("buffer");
+ assertEq(!!bufferProp, true, "wasm memory buffer property");
+ var buffer = bufferProp.get.call(actual).return;
+ var bufferLengthProp = buffer.proto.getOwnPropertyDescriptor("byteLength");
+ var bufferLength = bufferLengthProp.get.call(buffer).return;
+ assertEq(bufferLength, 65536, "wasm memory size");
+ }
+ ]
+ }]
+);
+monitorGlobalValues(
+ '(module\
+ (global i32 (i32.const 1))(global i64 (i64.const 2))(global f32 (f32.const 3.5))(global f64 (f64.const 42.25))\
+ (func (export "test") (nop)))',
+ undefined,
+ [{global0: [1], global1: [2], global2: [3.5], global3: [42.25]}]
+);
+monitorGlobalValues(
+ '(module (global (mut i32) (i32.const 1))(global (mut i64) (i64.const 2))\
+ (global (mut f32) (f32.const 3.5))(global (mut f64) (f64.const 42.25))\
+ (func (export "test")\
+ (i32.const 2)(set_global 0)(i64.const 1)(set_global 1)\
+ (f32.const 42.25)(set_global 2)(f64.const 3.5)(set_global 3)))',
+ undefined,
+ [{global0: [1, 2], global1: [2, 1], global2: [3.5, 42.25], global3: [42.25, 3.5]}]
+)
--- a/js/src/jit-test/tests/wasm/globals.js
+++ b/js/src/jit-test/tests/wasm/globals.js
@@ -239,8 +239,25 @@ testInitExpr('f64', 13.37, 0.1989, x =>
(export "defined" global 1)
)`, { globals: {x: createI64('0x1234567887654321')} }).exports;
assertEqI64(module.imported, createI64('0x1234567887654321'));
assertEqI64(module.defined, createI64('0xFAFADADABABA'));
setJitCompilerOption('wasm.test-mode', 0);
}
+
+// Custom NaN.
+{
+ let dv = new DataView(new ArrayBuffer(8));
+ module = wasmEvalText(`(module
+ (global $g f64 (f64.const -nan:0xe7ffff1591120))
+ (global $h f32 (f32.const -nan:0x651234))
+ (export "nan64" (global $g))(export "nan32" (global $h))
+ )`, {}).exports;
+
+ dv.setFloat64(0, module.nan64, true);
+ assertEq(dv.getUint32(4, true), 0x7ff80000);
+ assertEq(dv.getUint32(0, true), 0x00000000);
+
+ dv.setFloat32(0, module.nan32, true);
+ assertEq(dv.getUint32(0, true), 0x7fc00000);
+}
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -785,16 +785,17 @@ js::XDRScript(XDRState<mode>* xdr, Handl
return false;
break;
case ScopeKind::Global:
case ScopeKind::NonSyntactic:
if (!GlobalScope::XDR(xdr, scopeKind, &scope))
return false;
break;
case ScopeKind::Module:
+ case ScopeKind::WasmInstance:
MOZ_CRASH("NYI");
break;
case ScopeKind::WasmFunction:
MOZ_CRASH("wasm functions cannot be nested in JSScripts");
break;
}
if (mode == XDR_DECODE)
--- a/js/src/vm/EnvironmentObject.cpp
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -631,23 +631,56 @@ ModuleEnvironmentObject::newEnumerate(JS
properties.infallibleAppend(r.front().propid());
MOZ_ASSERT(properties.length() == count);
return true;
}
/*****************************************************************************/
+const Class WasmInstanceEnvironmentObject::class_ = {
+ "WasmInstance",
+ JSCLASS_IS_ANONYMOUS | JSCLASS_HAS_RESERVED_SLOTS(WasmInstanceEnvironmentObject::RESERVED_SLOTS)
+};
+
+/* static */ WasmInstanceEnvironmentObject*
+WasmInstanceEnvironmentObject::createHollowForDebug(JSContext* cx, Handle<WasmInstanceScope*> scope)
+{
+ RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr)));
+ if (!group)
+ return nullptr;
+
+ RootedShape shape(cx, scope->getEmptyEnvironmentShape(cx));
+ if (!shape)
+ return nullptr;
+
+ gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
+ MOZ_ASSERT(CanBeFinalizedInBackground(kind, &class_));
+ kind = gc::GetBackgroundAllocKind(kind);
+
+ JSObject* obj;
+ JS_TRY_VAR_OR_RETURN_NULL(cx, obj, NativeObject::create(cx, kind, gc::DefaultHeap, shape, group));
+
+ Rooted<WasmInstanceEnvironmentObject*> callobj(cx, &obj->as<WasmInstanceEnvironmentObject>());
+ callobj->initEnclosingEnvironment(&cx->global()->lexicalEnvironment());
+ callobj->initReservedSlot(SCOPE_SLOT, PrivateGCThingValue(scope));
+
+ return callobj;
+}
+
+/*****************************************************************************/
+
const Class WasmFunctionCallObject::class_ = {
"WasmCall",
JSCLASS_IS_ANONYMOUS | JSCLASS_HAS_RESERVED_SLOTS(WasmFunctionCallObject::RESERVED_SLOTS)
};
/* static */ WasmFunctionCallObject*
-WasmFunctionCallObject::createHollowForDebug(JSContext* cx, Handle<WasmFunctionScope*> scope)
+WasmFunctionCallObject::createHollowForDebug(JSContext* cx, HandleObject enclosing,
+ Handle<WasmFunctionScope*> scope)
{
RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr)));
if (!group)
return nullptr;
RootedShape shape(cx, scope->getEmptyEnvironmentShape(cx));
if (!shape)
return nullptr;
@@ -655,17 +688,17 @@ WasmFunctionCallObject::createHollowForD
gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
MOZ_ASSERT(CanBeFinalizedInBackground(kind, &class_));
kind = gc::GetBackgroundAllocKind(kind);
JSObject* obj;
JS_TRY_VAR_OR_RETURN_NULL(cx, obj, NativeObject::create(cx, kind, gc::DefaultHeap, shape, group));
Rooted<WasmFunctionCallObject*> callobj(cx, &obj->as<WasmFunctionCallObject>());
- callobj->initEnclosingEnvironment(&cx->global()->lexicalEnvironment());
+ callobj->initEnclosingEnvironment(enclosing);
callobj->initReservedSlot(SCOPE_SLOT, PrivateGCThingValue(scope));
return callobj;
}
/*****************************************************************************/
WithEnvironmentObject*
@@ -1668,16 +1701,48 @@ class DebugEnvironmentProxyHandler : pub
// TODO
}
} else {
*accessResult = ACCESS_LOST;
}
return true;
}
+ if (env->is<WasmInstanceEnvironmentObject>()) {
+ RootedScope scope(cx, getEnvironmentScope(*env));
+ MOZ_ASSERT(scope->is<WasmInstanceScope>());
+ uint32_t index = 0;
+ for (BindingIter bi(scope); bi; bi++) {
+ if (JSID_IS_ATOM(id, bi.name()))
+ break;
+ MOZ_ASSERT(!bi.isLast());
+ index++;
+ }
+ Rooted<WasmInstanceScope*> instanceScope(cx, &scope->as<WasmInstanceScope>());
+ wasm::Instance& instance = instanceScope->instance()->instance();
+
+ if (action == GET) {
+ if (instanceScope->memoriesStart() <= index && index < instanceScope->globalsStart()) {
+ MOZ_ASSERT(instanceScope->memoriesStart() + 1 == instanceScope->globalsStart());
+ vp.set(ObjectValue(*instance.memory()));
+ }
+ if (instanceScope->globalsStart() <= index) {
+ MOZ_ASSERT(index < instanceScope->namesCount());
+ if (!instance.debug().getGlobal(instance, index - instanceScope->globalsStart(), vp)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ }
+ *accessResult = ACCESS_UNALIASED;
+ } else { // if (action == SET)
+ // TODO
+ }
+ return true;
+ }
+
/* The rest of the internal scopes do not have unaliased vars. */
MOZ_ASSERT(!IsSyntacticEnvironment(env) ||
env->is<WithEnvironmentObject>());
return true;
}
static bool isArguments(JSContext* cx, jsid id)
{
@@ -1702,16 +1767,18 @@ class DebugEnvironmentProxyHandler : pub
static Scope* getEnvironmentScope(const JSObject& env)
{
if (isFunctionEnvironment(env))
return env.as<CallObject>().callee().nonLazyScript()->bodyScope();
if (isNonExtensibleLexicalEnvironment(env))
return &env.as<LexicalEnvironmentObject>().scope();
if (env.is<VarEnvironmentObject>())
return &env.as<VarEnvironmentObject>().scope();
+ if (env.is<WasmInstanceEnvironmentObject>())
+ return &env.as<WasmInstanceEnvironmentObject>().scope();
if (env.is<WasmFunctionCallObject>())
return &env.as<WasmFunctionCallObject>().scope();
return nullptr;
}
/*
* In theory, every non-arrow function scope contains an 'arguments'
* bindings. However, the engine only adds a binding if 'arguments' is
@@ -2306,16 +2373,17 @@ DebugEnvironmentProxy::initSnapshot(Arra
bool
DebugEnvironmentProxy::isForDeclarative() const
{
EnvironmentObject& e = environment();
return e.is<CallObject>() ||
e.is<VarEnvironmentObject>() ||
e.is<ModuleEnvironmentObject>() ||
+ e.is<WasmInstanceEnvironmentObject>() ||
e.is<WasmFunctionCallObject>() ||
e.is<LexicalEnvironmentObject>();
}
/* static */ bool
DebugEnvironmentProxy::getMaybeSentinelValue(JSContext* cx, Handle<DebugEnvironmentProxy*> env,
HandleId id, MutableHandleValue vp)
{
@@ -2952,16 +3020,17 @@ GetDebugEnvironmentForEnvironmentObject(
}
static DebugEnvironmentProxy*
GetDebugEnvironmentForMissing(JSContext* cx, const EnvironmentIter& ei)
{
MOZ_ASSERT(!ei.hasSyntacticEnvironment() &&
(ei.scope().is<FunctionScope>() ||
ei.scope().is<LexicalScope>() ||
+ ei.scope().is<WasmInstanceScope>() ||
ei.scope().is<WasmFunctionScope>() ||
ei.scope().is<VarScope>()));
if (DebugEnvironmentProxy* debugEnv = DebugEnvironments::hasDebugEnvironment(cx, ei))
return debugEnv;
EnvironmentIter copy(cx, ei);
RootedObject enclosingDebug(cx, GetDebugEnvironment(cx, ++copy));
@@ -2996,19 +3065,29 @@ GetDebugEnvironmentForMissing(JSContext*
} else if (ei.scope().is<LexicalScope>()) {
Rooted<LexicalScope*> lexicalScope(cx, &ei.scope().as<LexicalScope>());
Rooted<LexicalEnvironmentObject*> env(cx,
LexicalEnvironmentObject::createHollowForDebug(cx, lexicalScope));
if (!env)
return nullptr;
debugEnv = DebugEnvironmentProxy::create(cx, *env, enclosingDebug);
+ } else if (ei.scope().is<WasmInstanceScope>()) {
+ Rooted<WasmInstanceScope*> wasmInstanceScope(cx, &ei.scope().as<WasmInstanceScope>());
+ Rooted<WasmInstanceEnvironmentObject*> env(cx,
+ WasmInstanceEnvironmentObject::createHollowForDebug(cx, wasmInstanceScope));
+ if (!env)
+ return nullptr;
+
+ debugEnv = DebugEnvironmentProxy::create(cx, *env, enclosingDebug);
} else if (ei.scope().is<WasmFunctionScope>()) {
Rooted<WasmFunctionScope*> wasmFunctionScope(cx, &ei.scope().as<WasmFunctionScope>());
- Rooted<WasmFunctionCallObject*> callobj(cx, WasmFunctionCallObject::createHollowForDebug(cx, wasmFunctionScope));
+ RootedObject enclosing(cx, &enclosingDebug->as<DebugEnvironmentProxy>().environment());
+ Rooted<WasmFunctionCallObject*> callobj(cx,
+ WasmFunctionCallObject::createHollowForDebug(cx, enclosing, wasmFunctionScope));
if (!callobj)
return nullptr;
debugEnv = DebugEnvironmentProxy::create(cx, *callobj, enclosingDebug);
} else {
Rooted<VarScope*> varScope(cx, &ei.scope().as<VarScope>());
Rooted<VarEnvironmentObject*> env(cx,
VarEnvironmentObject::createHollowForDebug(cx, varScope));
@@ -3048,16 +3127,17 @@ GetDebugEnvironment(JSContext* cx, const
if (ei.done())
return GetDebugEnvironmentForNonEnvironmentObject(ei);
if (ei.hasAnyEnvironmentObject())
return GetDebugEnvironmentForEnvironmentObject(cx, ei);
if (ei.scope().is<FunctionScope>() ||
ei.scope().is<LexicalScope>() ||
+ ei.scope().is<WasmInstanceScope>() ||
ei.scope().is<WasmFunctionScope>() ||
ei.scope().is<VarScope>())
{
return GetDebugEnvironmentForMissing(cx, ei);
}
EnvironmentIter copy(cx, ei);
return GetDebugEnvironment(cx, ++copy);
--- a/js/src/vm/EnvironmentObject.h
+++ b/js/src/vm/EnvironmentObject.h
@@ -422,30 +422,52 @@ class ModuleEnvironmentObject : public E
static bool newEnumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
bool enumerableOnly);
};
typedef Rooted<ModuleEnvironmentObject*> RootedModuleEnvironmentObject;
typedef Handle<ModuleEnvironmentObject*> HandleModuleEnvironmentObject;
typedef MutableHandle<ModuleEnvironmentObject*> MutableHandleModuleEnvironmentObject;
+class WasmInstanceEnvironmentObject : public EnvironmentObject
+{
+ // Currently WasmInstanceScopes do not use their scopes in a
+ // meaningful way. However, it is an invariant of DebugEnvironments that
+ // environments kept in those maps have live scopes, thus this strong
+ // reference.
+ static const uint32_t SCOPE_SLOT = 1;
+
+ public:
+ static const Class class_;
+
+ static const uint32_t RESERVED_SLOTS = 2;
+
+ static WasmInstanceEnvironmentObject* createHollowForDebug(JSContext* cx,
+ Handle<WasmInstanceScope*> scope);
+ WasmInstanceScope& scope() const {
+ Value v = getReservedSlot(SCOPE_SLOT);
+ MOZ_ASSERT(v.isPrivateGCThing());
+ return *static_cast<WasmInstanceScope*>(v.toGCThing());
+ }
+};
+
class WasmFunctionCallObject : public EnvironmentObject
{
// Currently WasmFunctionCallObjects do not use their scopes in a
// meaningful way. However, it is an invariant of DebugEnvironments that
// environments kept in those maps have live scopes, thus this strong
// reference.
static const uint32_t SCOPE_SLOT = 1;
public:
static const Class class_;
static const uint32_t RESERVED_SLOTS = 2;
- static WasmFunctionCallObject* createHollowForDebug(JSContext* cx,
+ static WasmFunctionCallObject* createHollowForDebug(JSContext* cx, HandleObject enclosing,
Handle<WasmFunctionScope*> scope);
WasmFunctionScope& scope() const {
Value v = getReservedSlot(SCOPE_SLOT);
MOZ_ASSERT(v.isPrivateGCThing());
return *static_cast<WasmFunctionScope*>(v.toGCThing());
}
};
@@ -1010,16 +1032,17 @@ class DebugEnvironments
template <>
inline bool
JSObject::is<js::EnvironmentObject>() const
{
return is<js::CallObject>() ||
is<js::VarEnvironmentObject>() ||
is<js::ModuleEnvironmentObject>() ||
+ is<js::WasmInstanceEnvironmentObject>() ||
is<js::WasmFunctionCallObject>() ||
is<js::LexicalEnvironmentObject>() ||
is<js::WithEnvironmentObject>() ||
is<js::NonSyntacticVariablesObject>() ||
is<js::RuntimeLexicalErrorObject>();
}
template<>
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1066,16 +1066,17 @@ PopEnvironment(JSContext* cx, Environmen
if (ei.scope().hasEnvironment())
ei.initialFrame().popOffEnvironmentChain<VarEnvironmentObject>();
break;
case ScopeKind::Eval:
case ScopeKind::Global:
case ScopeKind::NonSyntactic:
case ScopeKind::Module:
break;
+ case ScopeKind::WasmInstance:
case ScopeKind::WasmFunction:
MOZ_CRASH("wasm is not interpreted");
break;
}
}
// Unwind environment chain and iterator to match the env corresponding to
// the given bytecode position.
--- a/js/src/vm/Scope.cpp
+++ b/js/src/vm/Scope.cpp
@@ -72,16 +72,18 @@ js::ScopeKindString(ScopeKind kind)
case ScopeKind::StrictEval:
return "strict eval";
case ScopeKind::Global:
return "global";
case ScopeKind::NonSyntactic:
return "non-syntactic";
case ScopeKind::Module:
return "module";
+ case ScopeKind::WasmInstance:
+ return "wasm instance";
case ScopeKind::WasmFunction:
return "wasm function";
}
MOZ_CRASH("Bad ScopeKind");
}
static Shape*
EmptyEnvironmentShape(JSContext* cx, const Class* cls, uint32_t numSlots,
@@ -422,16 +424,17 @@ Scope::clone(JSContext* cx, HandleScope
MOZ_CRASH("Use GlobalScope::clone.");
break;
case ScopeKind::WasmFunction:
MOZ_CRASH("wasm functions are not nested in JSScript");
break;
case ScopeKind::Module:
+ case ScopeKind::WasmInstance:
MOZ_CRASH("NYI");
break;
}
return nullptr;
}
@@ -509,16 +512,19 @@ LexicalScope::nextFrameSlot(Scope* scope
case ScopeKind::Eval:
case ScopeKind::StrictEval:
return si.scope()->as<EvalScope>().nextFrameSlot();
case ScopeKind::Global:
case ScopeKind::NonSyntactic:
return 0;
case ScopeKind::Module:
return si.scope()->as<ModuleScope>().nextFrameSlot();
+ case ScopeKind::WasmInstance:
+ // TODO return si.scope()->as<WasmInstanceScope>().nextFrameSlot();
+ return 0;
case ScopeKind::WasmFunction:
// TODO return si.scope()->as<WasmFunctionScope>().nextFrameSlot();
return 0;
}
}
MOZ_CRASH("Not an enclosing intra-frame Scope");
}
@@ -1230,72 +1236,136 @@ ModuleScope::getEmptyEnvironmentShape(JS
}
JSScript*
ModuleScope::script() const
{
return module()->script();
}
-// TODO Check what Debugger behavior should be when it evaluates a
-// var declaration.
-static const uint32_t WasmFunctionEnvShapeFlags =
+static const uint32_t WasmInstanceEnvShapeFlags =
BaseShape::NOT_EXTENSIBLE | BaseShape::DELEGATE;
+
+template <size_t ArrayLength>
static JSAtom*
-GenerateWasmVariableName(JSContext* cx, uint32_t index)
+GenerateWasmName(JSContext* cx, const char (&prefix)[ArrayLength], uint32_t index)
{
StringBuffer sb(cx);
- if (!sb.append("var"))
+ if (!sb.append(prefix))
return nullptr;
if (!NumberValueToStringBuffer(cx, Int32Value(index), sb))
return nullptr;
return sb.finishAtom();
}
-/* static */ WasmFunctionScope*
-WasmFunctionScope::create(JSContext* cx, WasmInstanceObject* instance, uint32_t funcIndex)
+/* static */ WasmInstanceScope*
+WasmInstanceScope::create(JSContext* cx, WasmInstanceObject* instance)
{
- // WasmFunctionScope::Data has GCManagedDeletePolicy because it contains a
+ // WasmInstanceScope::Data has GCManagedDeletePolicy because it contains a
// GCPtr. Destruction of |data| below may trigger calls into the GC.
- Rooted<WasmFunctionScope*> wasmFunctionScope(cx);
+ Rooted<WasmInstanceScope*> wasmInstanceScope(cx);
{
- // TODO pull the local variable names from the wasm function definition.
- wasm::ValTypeVector locals;
- size_t argsLength;
- if (!instance->instance().debug().debugGetLocalTypes(funcIndex, &locals, &argsLength))
- return nullptr;
- uint32_t namesCount = locals.length();
+ size_t namesCount = 0;
+ if (instance->instance().memory()) {
+ namesCount++;
+ }
+ size_t globalsStart = namesCount;
+ size_t globalsCount = instance->instance().metadata().globals.length();
+ namesCount += globalsCount;
- Rooted<UniquePtr<Data>> data(cx, NewEmptyScopeData<WasmFunctionScope>(cx, namesCount));
+ Rooted<UniquePtr<Data>> data(cx, NewEmptyScopeData<WasmInstanceScope>(cx, namesCount));
if (!data)
return nullptr;
- Rooted<Scope*> enclosingScope(cx, &cx->global()->emptyGlobalScope());
+ size_t nameIndex = 0;
+ if (instance->instance().memory()) {
+ RootedAtom name(cx, GenerateWasmName(cx, "memory", /* index = */ 0));
+ if (!name)
+ return nullptr;
+ data->names[nameIndex] = BindingName(name, false);
+ nameIndex++;
+ }
+ for (size_t i = 0; i < globalsCount; i++) {
+ RootedAtom name(cx, GenerateWasmName(cx, "global", i));
+ if (!name)
+ return nullptr;
+ data->names[nameIndex] = BindingName(name, false);
+ nameIndex++;
+ }
+ MOZ_ASSERT(nameIndex == namesCount);
data->instance.init(instance);
- data->funcIndex = funcIndex;
+ data->memoriesStart = 0;
+ data->globalsStart = globalsStart;
data->length = namesCount;
- for (size_t i = 0; i < namesCount; i++) {
- RootedAtom name(cx, GenerateWasmVariableName(cx, i));
- if (!name)
- return nullptr;
- data->names[i] = BindingName(name, false);
- }
- Scope* scope = Scope::create(cx, ScopeKind::WasmFunction, enclosingScope, /* envShape = */ nullptr);
+ Rooted<Scope*> enclosingScope(cx, &cx->global()->emptyGlobalScope());
+
+ Scope* scope = Scope::create(cx, ScopeKind::WasmInstance, enclosingScope, /* envShape = */ nullptr);
if (!scope)
return nullptr;
- wasmFunctionScope = &scope->as<WasmFunctionScope>();
- wasmFunctionScope->initData(Move(data.get()));
+ wasmInstanceScope = &scope->as<WasmInstanceScope>();
+ wasmInstanceScope->initData(Move(data.get()));
}
+ return wasmInstanceScope;
+}
+
+/* static */ Shape*
+WasmInstanceScope::getEmptyEnvironmentShape(JSContext* cx)
+{
+ const Class* cls = &WasmInstanceEnvironmentObject::class_;
+ return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), WasmInstanceEnvShapeFlags);
+}
+
+// TODO Check what Debugger behavior should be when it evaluates a
+// var declaration.
+static const uint32_t WasmFunctionEnvShapeFlags =
+ BaseShape::NOT_EXTENSIBLE | BaseShape::DELEGATE;
+
+/* static */ WasmFunctionScope*
+WasmFunctionScope::create(JSContext* cx, HandleScope enclosing, uint32_t funcIndex)
+{
+ MOZ_ASSERT(enclosing->is<WasmInstanceScope>());
+
+ Rooted<WasmFunctionScope*> wasmFunctionScope(cx);
+
+ Rooted<WasmInstanceObject*> instance(cx, enclosing->as<WasmInstanceScope>().instance());
+
+ // TODO pull the local variable names from the wasm function definition.
+ wasm::ValTypeVector locals;
+ size_t argsLength;
+ if (!instance->instance().debug().debugGetLocalTypes(funcIndex, &locals, &argsLength))
+ return nullptr;
+ uint32_t namesCount = locals.length();
+
+ Rooted<UniquePtr<Data>> data(cx, NewEmptyScopeData<WasmFunctionScope>(cx, namesCount));
+ if (!data)
+ return nullptr;
+
+ data->funcIndex = funcIndex;
+ data->length = namesCount;
+ for (size_t i = 0; i < namesCount; i++) {
+ RootedAtom name(cx, GenerateWasmName(cx, "var", i));
+ if (!name)
+ return nullptr;
+ data->names[i] = BindingName(name, false);
+ }
+
+ Scope* scope = Scope::create(cx, ScopeKind::WasmFunction, enclosing, /* envShape = */ nullptr);
+ if (!scope)
+ return nullptr;
+
+ wasmFunctionScope = &scope->as<WasmFunctionScope>();
+ wasmFunctionScope->initData(Move(data.get()));
+
return wasmFunctionScope;
}
/* static */ Shape*
WasmFunctionScope::getEmptyEnvironmentShape(JSContext* cx)
{
const Class* cls = &WasmFunctionCallObject::class_;
return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), WasmFunctionEnvShapeFlags);
@@ -1347,16 +1417,19 @@ BindingIter::BindingIter(Scope* scope)
break;
case ScopeKind::Global:
case ScopeKind::NonSyntactic:
init(scope->as<GlobalScope>().data());
break;
case ScopeKind::Module:
init(scope->as<ModuleScope>().data());
break;
+ case ScopeKind::WasmInstance:
+ init(scope->as<WasmInstanceScope>().data());
+ break;
case ScopeKind::WasmFunction:
init(scope->as<WasmFunctionScope>().data());
break;
}
}
BindingIter::BindingIter(JSScript* script)
: BindingIter(script->bodyScope())
@@ -1481,16 +1554,32 @@ BindingIter::init(ModuleScope::Data& dat
// consts - [data.constStart, data.length)
init(data.varStart, data.varStart, data.varStart, data.varStart, data.letStart, data.constStart,
CanHaveFrameSlots | CanHaveEnvironmentSlots,
0, JSSLOT_FREE(&ModuleEnvironmentObject::class_),
data.names, data.length);
}
void
+BindingIter::init(WasmInstanceScope::Data& data)
+{
+ // imports - [0, 0)
+ // positional formals - [0, 0)
+ // other formals - [0, 0)
+ // top-level funcs - [0, 0)
+ // vars - [0, data.length)
+ // lets - [data.length, data.length)
+ // consts - [data.length, data.length)
+ init(0, 0, 0, 0, data.length, data.length,
+ CanHaveFrameSlots | CanHaveEnvironmentSlots,
+ UINT32_MAX, UINT32_MAX,
+ data.names, data.length);
+}
+
+void
BindingIter::init(WasmFunctionScope::Data& data)
{
// imports - [0, 0)
// positional formals - [0, 0)
// other formals - [0, 0)
// top-level funcs - [0, 0)
// vars - [0, data.length)
// lets - [data.length, data.length)
--- a/js/src/vm/Scope.h
+++ b/js/src/vm/Scope.h
@@ -68,16 +68,19 @@ enum class ScopeKind : uint8_t
// GlobalScope
Global,
NonSyntactic,
// ModuleScope
Module,
+ // WasmInstanceScope
+ WasmInstance,
+
// WasmFunctionScope
WasmFunction
};
static inline bool
ScopeKindIsCatch(ScopeKind kind)
{
return kind == ScopeKind::SimpleCatch || kind == ScopeKind::Catch;
@@ -944,41 +947,39 @@ class ModuleScope : public Scope
return data().module;
}
JSScript* script() const;
static Shape* getEmptyEnvironmentShape(JSContext* cx);
};
-// Scope corresponding to the wasm function. A WasmFunctionScope is used by
-// Debugger only, and not for wasm execution.
-//
-class WasmFunctionScope : public Scope
+class WasmInstanceScope : public Scope
{
friend class BindingIter;
friend class Scope;
- static const ScopeKind classScopeKind_ = ScopeKind::WasmFunction;
+ static const ScopeKind classScopeKind_ = ScopeKind::WasmInstance;
public:
struct Data
{
+ uint32_t memoriesStart;
+ uint32_t globalsStart;
uint32_t length;
uint32_t nextFrameSlot;
- uint32_t funcIndex;
// The wasm instance of the scope.
GCPtr<WasmInstanceObject*> instance;
BindingName names[1];
void trace(JSTracer* trc);
};
- static WasmFunctionScope* create(JSContext* cx, WasmInstanceObject* instance, uint32_t funcIndex);
+ static WasmInstanceScope* create(JSContext* cx, WasmInstanceObject* instance);
static size_t sizeOfData(uint32_t length) {
return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
}
private:
Data& data() {
return *reinterpret_cast<Data*>(data_);
@@ -988,16 +989,68 @@ class WasmFunctionScope : public Scope
return *reinterpret_cast<Data*>(data_);
}
public:
WasmInstanceObject* instance() const {
return data().instance;
}
+ uint32_t memoriesStart() const {
+ return data().memoriesStart;
+ }
+
+ uint32_t globalsStart() const {
+ return data().globalsStart;
+ }
+
+ uint32_t namesCount() const {
+ return data().length;
+ }
+
+ static Shape* getEmptyEnvironmentShape(JSContext* cx);
+};
+
+// Scope corresponding to the wasm function. A WasmFunctionScope is used by
+// Debugger only, and not for wasm execution.
+//
+class WasmFunctionScope : public Scope
+{
+ friend class BindingIter;
+ friend class Scope;
+ static const ScopeKind classScopeKind_ = ScopeKind::WasmFunction;
+
+ public:
+ struct Data
+ {
+ uint32_t length;
+ uint32_t nextFrameSlot;
+ uint32_t funcIndex;
+
+ BindingName names[1];
+
+ void trace(JSTracer* trc);
+ };
+
+ static WasmFunctionScope* create(JSContext* cx, HandleScope enclosing, uint32_t funcIndex);
+
+ static size_t sizeOfData(uint32_t length) {
+ return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
+ }
+
+ private:
+ Data& data() {
+ return *reinterpret_cast<Data*>(data_);
+ }
+
+ const Data& data() const {
+ return *reinterpret_cast<Data*>(data_);
+ }
+
+ public:
uint32_t funcIndex() const {
return data().funcIndex;
}
static Shape* getEmptyEnvironmentShape(JSContext* cx);
};
//
@@ -1104,16 +1157,17 @@ class BindingIter
}
void init(LexicalScope::Data& data, uint32_t firstFrameSlot, uint8_t flags);
void init(FunctionScope::Data& data, uint8_t flags);
void init(VarScope::Data& data, uint32_t firstFrameSlot);
void init(GlobalScope::Data& data);
void init(EvalScope::Data& data, bool strict);
void init(ModuleScope::Data& data);
+ void init(WasmInstanceScope::Data& data);
void init(WasmFunctionScope::Data& data);
bool hasFormalParameterExprs() const {
return flags_ & HasFormalParameterExprs;
}
bool ignoreDestructuredFormalParameters() const {
return flags_ & IgnoreDestructuredFormalParameters;
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -154,16 +154,20 @@ AssertScopeMatchesEnvironment(Scope* sco
break;
case ScopeKind::Module:
MOZ_ASSERT(env->as<ModuleEnvironmentObject>().module().script() ==
si.scope()->as<ModuleScope>().script());
env = &env->as<ModuleEnvironmentObject>().enclosingEnvironment();
break;
+ case ScopeKind::WasmInstance:
+ env = &env->as<WasmInstanceEnvironmentObject>().enclosingEnvironment();
+ break;
+
case ScopeKind::WasmFunction:
env = &env->as<WasmFunctionCallObject>().enclosingEnvironment();
break;
}
}
}
// In the case of a non-syntactic env chain, the immediate parent of the
--- a/js/src/wasm/WasmDebug.cpp
+++ b/js/src/wasm/WasmDebug.cpp
@@ -21,16 +21,17 @@
#include "mozilla/BinarySearch.h"
#include "ds/Sort.h"
#include "jit/ExecutableAllocator.h"
#include "jit/MacroAssembler.h"
#include "vm/Debugger.h"
#include "vm/StringBuffer.h"
#include "wasm/WasmBinaryToText.h"
+#include "wasm/WasmInstance.h"
#include "wasm/WasmValidate.h"
using namespace js;
using namespace js::jit;
using namespace js::wasm;
using mozilla::BinarySearchIf;
@@ -544,16 +545,71 @@ DebugState::debugGetLocalTypes(uint32_t
ExprType
DebugState::debugGetResultType(uint32_t funcIndex)
{
MOZ_ASSERT(debugEnabled());
return metadata().debugFuncReturnTypes[funcIndex];
}
+bool
+DebugState::getGlobal(Instance& instance, uint32_t globalIndex, MutableHandleValue vp)
+{
+ const GlobalDesc& global = metadata().globals[globalIndex];
+
+ if (global.isConstant()) {
+ Val value = global.constantValue();
+ switch (value.type()) {
+ case ValType::I32:
+ vp.set(Int32Value(value.i32()));
+ break;
+ case ValType::I64:
+ // Just display as a Number; it's ok if we lose some precision
+ vp.set(NumberValue((double)value.i64()));
+ break;
+ case ValType::F32:
+ vp.set(NumberValue(JS::CanonicalizeNaN(value.f32())));
+ break;
+ case ValType::F64:
+ vp.set(NumberValue(JS::CanonicalizeNaN(value.f64())));
+ break;
+ default:
+ MOZ_CRASH("Global constant type");
+ }
+ return true;
+ }
+
+ uint8_t* globalData = instance.globalSegment().globalData();
+ void* dataPtr = globalData + global.offset();
+ switch (global.type()) {
+ case ValType::I32: {
+ vp.set(Int32Value(*static_cast<int32_t*>(dataPtr)));
+ break;
+ }
+ case ValType::I64: {
+ // Just display as a Number; it's ok if we lose some precision
+ vp.set(NumberValue((double)*static_cast<int64_t*>(dataPtr)));
+ break;
+ }
+ case ValType::F32: {
+ vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast<float*>(dataPtr))));
+ break;
+ }
+ case ValType::F64: {
+ vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast<double*>(dataPtr))));
+ break;
+ }
+ default:
+ MOZ_CRASH("Global variable type");
+ break;
+ }
+ return true;
+}
+
+
JSString*
DebugState::debugDisplayURL(JSContext* cx) const
{
// Build wasm module URL from following parts:
// - "wasm:" as protocol;
// - URI encoded filename from metadata (if can be encoded), plus ":";
// - 64-bit hash of the module bytes (as hex dump).
js::StringBuffer result(cx);
--- a/js/src/wasm/WasmDebug.h
+++ b/js/src/wasm/WasmDebug.h
@@ -138,16 +138,17 @@ class DebugState
bool stepModeEnabled(uint32_t funcIndex) const;
bool incrementStepModeCount(JSContext* cx, uint32_t funcIndex);
bool decrementStepModeCount(FreeOp* fop, uint32_t funcIndex);
// Stack inspection helpers.
bool debugGetLocalTypes(uint32_t funcIndex, ValTypeVector* locals, size_t* argsLength);
ExprType debugGetResultType(uint32_t funcIndex);
+ bool getGlobal(Instance& instance, uint32_t globalIndex, MutableHandleValue vp);
// Debug URL helpers.
JSString* debugDisplayURL(JSContext* cx) const;
bool getSourceMappingURL(JSContext* cx, MutableHandleString result) const;
// Accessors for commonly used elements of linked structures.
--- a/js/src/wasm/WasmInstance.cpp
+++ b/js/src/wasm/WasmInstance.cpp
@@ -518,16 +518,22 @@ Instance::trace(JSTracer* trc)
// Technically, instead of having this method, the caller could use
// Instance::object() to get the owning WasmInstanceObject to mark,
// but this method is simpler and more efficient. The trace hook of
// WasmInstanceObject will call Instance::tracePrivate at which point we
// can mark the rest of the children.
TraceEdge(trc, &object_, "wasm instance object");
}
+WasmMemoryObject*
+Instance::memory() const
+{
+ return memory_;
+}
+
SharedMem<uint8_t*>
Instance::memoryBase() const
{
MOZ_ASSERT(metadata().usesMemory());
MOZ_ASSERT(tlsData()->memoryBase == memory_->buffer().dataPointerEither());
return memory_->buffer().dataPointerEither();
}
--- a/js/src/wasm/WasmInstance.h
+++ b/js/src/wasm/WasmInstance.h
@@ -111,16 +111,17 @@ class Instance
const CodeSegment& codeSegment(Tier t) const { return code_->segment(t); }
const GlobalSegment& globalSegment() const { return *globals_; }
uint8_t* codeBase(Tier t) const { return code_->segment(t).base(); }
const MetadataTier& metadata(Tier t) const { return code_->metadata(t); }
const Metadata& metadata() const { return code_->metadata(); }
bool isAsmJS() const { return metadata().isAsmJS(); }
const SharedTableVector& tables() const { return tables_; }
SharedMem<uint8_t*> memoryBase() const;
+ WasmMemoryObject* memory() const;
size_t memoryLength() const;
size_t memoryMappedSize() const;
bool memoryAccessInGuardRegion(uint8_t* addr, unsigned numBytes) const;
TlsData* tlsData() const { return globals_->tlsData(); }
// This method returns a pointer to the GC object that owns this Instance.
// Instances may be reached via weak edges (e.g., Compartment::instances_)
// so this perform a read-barrier on the returned object unless the barrier
--- a/js/src/wasm/WasmJS.cpp
+++ b/js/src/wasm/WasmJS.cpp
@@ -1030,16 +1030,17 @@ WasmInstanceObject::create(JSContext* cx
AutoSetNewObjectMetadata metadata(cx);
RootedWasmInstanceObject obj(cx, NewObjectWithGivenProto<WasmInstanceObject>(cx, proto));
if (!obj)
return nullptr;
obj->setReservedSlot(EXPORTS_SLOT, PrivateValue(exports.release()));
obj->setReservedSlot(SCOPES_SLOT, PrivateValue(scopes.release()));
+ obj->setReservedSlot(INSTANCE_SCOPE_SLOT, UndefinedValue());
MOZ_ASSERT(obj->isNewborn());
MOZ_ASSERT(obj->isTenured(), "assumed by WasmTableObject write barriers");
// Root the Instance via WasmInstanceObject before any possible GC.
auto* instance = cx->new_<Instance>(cx,
obj,
code,
@@ -1208,24 +1209,43 @@ const CodeRange&
WasmInstanceObject::getExportedFunctionCodeRange(HandleFunction fun, Tier tier)
{
uint32_t funcIndex = ExportedFunctionToFuncIndex(fun);
MOZ_ASSERT(exports().lookup(funcIndex)->value() == fun);
const FuncExport& funcExport = instance().metadata(tier).lookupFuncExport(funcIndex);
return instance().metadata(tier).codeRanges[funcExport.codeRangeIndex()];
}
+/* static */ WasmInstanceScope*
+WasmInstanceObject::getScope(JSContext* cx, HandleWasmInstanceObject instanceObj)
+{
+ if (!instanceObj->getReservedSlot(INSTANCE_SCOPE_SLOT).isUndefined())
+ return (WasmInstanceScope*)instanceObj->getReservedSlot(INSTANCE_SCOPE_SLOT).toGCThing();
+
+ Rooted<WasmInstanceScope*> instanceScope(cx, WasmInstanceScope::create(cx, instanceObj));
+ if (!instanceScope)
+ return nullptr;
+
+ instanceObj->setReservedSlot(INSTANCE_SCOPE_SLOT, PrivateGCThingValue(instanceScope));
+
+ return instanceScope;
+}
+
/* static */ WasmFunctionScope*
WasmInstanceObject::getFunctionScope(JSContext* cx, HandleWasmInstanceObject instanceObj,
uint32_t funcIndex)
{
if (ScopeMap::Ptr p = instanceObj->scopes().lookup(funcIndex))
return p->value();
- Rooted<WasmFunctionScope*> funcScope(cx, WasmFunctionScope::create(cx, instanceObj, funcIndex));
+ Rooted<WasmInstanceScope*> instanceScope(cx, WasmInstanceObject::getScope(cx, instanceObj));
+ if (!instanceScope)
+ return nullptr;
+
+ Rooted<WasmFunctionScope*> funcScope(cx, WasmFunctionScope::create(cx, instanceScope, funcIndex));
if (!funcScope)
return nullptr;
if (!instanceObj->scopes().putNew(funcIndex, funcScope)) {
ReportOutOfMemory(cx);
return nullptr;
}
--- a/js/src/wasm/WasmJS.h
+++ b/js/src/wasm/WasmJS.h
@@ -22,16 +22,17 @@
#include "gc/Policy.h"
#include "vm/NativeObject.h"
#include "wasm/WasmTypes.h"
namespace js {
class TypedArrayObject;
class WasmFunctionScope;
+class WasmInstanceScope;
namespace wasm {
// Creates a testing-only NaN JS object with fields as described above, for
// T=float or T=double.
template<typename T>
JSObject*
@@ -142,16 +143,17 @@ class WasmModuleObject : public NativeOb
// as internal implementation details of asm.js.
class WasmInstanceObject : public NativeObject
{
static const unsigned INSTANCE_SLOT = 0;
static const unsigned EXPORTS_OBJ_SLOT = 1;
static const unsigned EXPORTS_SLOT = 2;
static const unsigned SCOPES_SLOT = 3;
+ static const unsigned INSTANCE_SCOPE_SLOT = 4;
static const ClassOps classOps_;
static bool exportsGetterImpl(JSContext* cx, const CallArgs& args);
static bool exportsGetter(JSContext* cx, unsigned argc, Value* vp);
bool isNewborn() const;
static void finalize(FreeOp* fop, JSObject* obj);
static void trace(JSTracer* trc, JSObject* obj);
// ExportMap maps from function index to exported function object.
@@ -169,17 +171,17 @@ class WasmInstanceObject : public Native
// during debugging.
using ScopeMap = JS::WeakCache<GCHashMap<uint32_t,
ReadBarriered<WasmFunctionScope*>,
DefaultHasher<uint32_t>,
SystemAllocPolicy>>;
ScopeMap& scopes() const;
public:
- static const unsigned RESERVED_SLOTS = 4;
+ static const unsigned RESERVED_SLOTS = 5;
static const Class class_;
static const JSPropertySpec properties[];
static const JSFunctionSpec methods[];
static const JSFunctionSpec static_methods[];
static bool construct(JSContext*, unsigned, Value*);
static WasmInstanceObject* create(JSContext* cx,
RefPtr<const wasm::Code> code,
@@ -197,16 +199,17 @@ class WasmInstanceObject : public Native
static bool getExportedFunction(JSContext* cx,
HandleWasmInstanceObject instanceObj,
uint32_t funcIndex,
MutableHandleFunction fun);
const wasm::CodeRange& getExportedFunctionCodeRange(HandleFunction fun, wasm::Tier tier);
+ static WasmInstanceScope* getScope(JSContext* cx, HandleWasmInstanceObject instanceObj);
static WasmFunctionScope* getFunctionScope(JSContext* cx,
HandleWasmInstanceObject instanceObj,
uint32_t funcIndex);
};
// The class of WebAssembly.Memory. A WasmMemoryObject references an ArrayBuffer
// or SharedArrayBuffer object which owns the actual memory.
--- a/js/src/wasm/WasmModule.cpp
+++ b/js/src/wasm/WasmModule.cpp
@@ -847,29 +847,29 @@ GetGlobalExport(JSContext* cx, const Glo
float f = val.f32();
if (JitOptions.wasmTestMode && IsNaN(f)) {
RootedObject obj(cx, CreateCustomNaNObject(cx, &f));
if (!obj)
return false;
jsval.set(ObjectValue(*obj));
return true;
}
- jsval.set(DoubleValue(double(f)));
+ jsval.set(DoubleValue(JS::CanonicalizeNaN(double(f))));
return true;
}
case ValType::F64: {
double d = val.f64();
if (JitOptions.wasmTestMode && IsNaN(d)) {
RootedObject obj(cx, CreateCustomNaNObject(cx, &d));
if (!obj)
return false;
jsval.set(ObjectValue(*obj));
return true;
}
- jsval.set(DoubleValue(d));
+ jsval.set(DoubleValue(JS::CanonicalizeNaN(d)));
return true;
}
default: {
break;
}
}
MOZ_CRASH("unexpected type when creating global exports");
}