зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 4 changesets (bug 1461616, bug 1450261) for wasm related spidermonkey build bustages CLOSED TREE
Backed out changeset aa826be7a24a (bug 1461616) Backed out changeset b05573ae795a (bug 1450261) Backed out changeset ddbbcea98cde (bug 1450261) Backed out changeset 1478fb0f82de (bug 1450261)
This commit is contained in:
Родитель
ab5640b5e6
Коммит
fa8c0e96eb
|
@ -54,6 +54,8 @@ class JSONPrinter;
|
|||
class MapObject;
|
||||
class SetObject;
|
||||
|
||||
void SetGCZeal(JSRuntime*, uint8_t, uint32_t);
|
||||
|
||||
namespace gc {
|
||||
class AutoMaybeStartBackgroundAllocation;
|
||||
class AutoTraceSession;
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
if (!wasmGcEnabled() || typeof WebAssembly.Global !== 'function') {
|
||||
quit(0);
|
||||
}
|
||||
|
||||
// Dummy object.
|
||||
function Baguette(calories) {
|
||||
this.calories = calories;
|
||||
}
|
||||
|
||||
assertEq(new WebAssembly.Global({value: "anyref"}) instanceof WebAssembly.Global, true);
|
||||
|
||||
(function() {
|
||||
// Test initialization without a value.
|
||||
let g = new WebAssembly.Global({value: "anyref"});
|
||||
assertEq(g.value, null);
|
||||
assertErrorMessage(() => g.value = 42, TypeError, /immutable global/);
|
||||
})();
|
||||
|
||||
(function() {
|
||||
// Test initialization with a value.
|
||||
let g = new WebAssembly.Global({value: "anyref"}, null);
|
||||
assertEq(g.value, null);
|
||||
assertErrorMessage(() => g.value = 42, TypeError, /immutable global/);
|
||||
|
||||
let obj = {};
|
||||
g = new WebAssembly.Global({value: "anyref"}, obj);
|
||||
assertEq(g.value, obj);
|
||||
assertErrorMessage(() => g.value = 42, TypeError, /immutable global/);
|
||||
|
||||
g = new WebAssembly.Global({value: "anyref"}, 1337);
|
||||
assertEq(g.value instanceof Number, true);
|
||||
assertEq(+g.value, 1337);
|
||||
|
||||
g = new WebAssembly.Global({value: "anyref"}, 13.37);
|
||||
assertEq(g.value instanceof Number, true);
|
||||
assertEq(+g.value, 13.37);
|
||||
|
||||
g = new WebAssembly.Global({value: "anyref"}, "string");
|
||||
assertEq(g.value instanceof String, true);
|
||||
assertEq(g.value.toString(), "string");
|
||||
|
||||
g = new WebAssembly.Global({value: "anyref"}, true);
|
||||
assertEq(g.value instanceof Boolean, true);
|
||||
assertEq(!!g.value, true);
|
||||
|
||||
g = new WebAssembly.Global({value: "anyref"}, Symbol("status"));
|
||||
assertEq(g.value instanceof Symbol, true);
|
||||
assertEq(g.value.toString(), "Symbol(status)");
|
||||
|
||||
assertErrorMessage(() => new WebAssembly.Global({value: "anyref"}, undefined),
|
||||
TypeError,
|
||||
"can't convert undefined to object");
|
||||
})();
|
||||
|
||||
(function() {
|
||||
// Test mutable property and assignment.
|
||||
let g = new WebAssembly.Global({value: "anyref", mutable: true}, null);
|
||||
assertEq(g.value, null);
|
||||
|
||||
let obj = { x: 42 };
|
||||
g.value = obj;
|
||||
assertEq(g.value, obj);
|
||||
assertEq(g.value.x, 42);
|
||||
|
||||
obj = null;
|
||||
assertEq(g.value.x, 42);
|
||||
|
||||
let otherObj = { y : 35 };
|
||||
g.value = otherObj;
|
||||
assertEq(g.value, otherObj);
|
||||
})();
|
||||
|
||||
(function() {
|
||||
// Test tracing.
|
||||
let nom = new Baguette(1);
|
||||
let g = new WebAssembly.Global({value: "anyref"}, nom);
|
||||
nom = null;
|
||||
gc();
|
||||
assertEq(g.value.calories, 1);
|
||||
})();
|
||||
|
||||
var global = new WebAssembly.Global({ value: "anyref", mutable: true }, null);
|
||||
|
||||
// GCZeal mode 2 implies that every allocation (second parameter = every single
|
||||
// allocation) will trigger a full GC.
|
||||
gczeal(2, 1);
|
||||
|
||||
{
|
||||
let nomnom = new Baguette(42);
|
||||
global.value = nomnom;
|
||||
nomnom = null;
|
||||
}
|
||||
new Baguette();
|
||||
assertEq(global.value.calories, 42);
|
|
@ -1,72 +0,0 @@
|
|||
if (!wasmGcEnabled()) {
|
||||
quit(0);
|
||||
}
|
||||
|
||||
const { startProfiling, endProfiling, assertEqPreciseStacks, isSingleStepProfilingEnabled } = WasmHelpers;
|
||||
|
||||
// Dummy constructor.
|
||||
function Baguette(calories) {
|
||||
this.calories = calories;
|
||||
}
|
||||
|
||||
let exportsPlain = wasmEvalText(`(module
|
||||
(global i32 (i32.const 42))
|
||||
(global $g (mut anyref) (ref.null anyref))
|
||||
(func (export "set") (param anyref) get_local 0 set_global $g)
|
||||
(func (export "get") (result anyref) get_global $g)
|
||||
)`).exports;
|
||||
|
||||
let exportsObj = wasmEvalText(`(module
|
||||
(global $g (export "g") (mut anyref) (ref.null anyref))
|
||||
(func (export "set") (param anyref) get_local 0 set_global $g)
|
||||
(func (export "get") (result anyref) get_global $g)
|
||||
)`).exports;
|
||||
|
||||
// 7 => Generational GC zeal.
|
||||
gczeal(7, 1);
|
||||
|
||||
for (var i = 0; i < 100; i++) {
|
||||
new Baguette(i);
|
||||
}
|
||||
|
||||
function test(exports) {
|
||||
// Test post-write barrier in wasm code.
|
||||
{
|
||||
let nomnom = new Baguette(15);
|
||||
exports.set(nomnom);
|
||||
nomnom = null;
|
||||
}
|
||||
new Baguette();
|
||||
assertEq(exports.get().calories, 15);
|
||||
}
|
||||
|
||||
test(exportsPlain);
|
||||
test(exportsObj);
|
||||
|
||||
// Test stacks reported in profiling mode in a separate way, to not perturb
|
||||
// the behavior of the tested functions.
|
||||
if (!isSingleStepProfilingEnabled)
|
||||
quit(0);
|
||||
|
||||
enableGeckoProfiling();
|
||||
|
||||
const EXPECTED_STACKS = [
|
||||
['', '!>', '0,!>', '<,0,!>', 'GC postbarrier,0,!>', '<,0,!>', '0,!>', '!>', ''],
|
||||
['', '!>', '0,!>', '!>', ''],
|
||||
];
|
||||
|
||||
function testStacks(exports) {
|
||||
// Test post-write barrier in wasm code.
|
||||
{
|
||||
let nomnom = new Baguette(15);
|
||||
startProfiling();
|
||||
exports.set(nomnom);
|
||||
assertEqPreciseStacks(endProfiling(), EXPECTED_STACKS);
|
||||
nomnom = null;
|
||||
}
|
||||
new Baguette();
|
||||
assertEq(exports.get().calories, 15);
|
||||
}
|
||||
|
||||
testStacks(exportsPlain);
|
||||
testStacks(exportsObj);
|
|
@ -1,39 +0,0 @@
|
|||
if (!wasmGcEnabled()) {
|
||||
quit(0);
|
||||
}
|
||||
|
||||
const { startProfiling, endProfiling, assertEqPreciseStacks, isSingleStepProfilingEnabled } = WasmHelpers;
|
||||
|
||||
let e = wasmEvalText(`(module
|
||||
(global $g (mut anyref) (ref.null anyref))
|
||||
(func (export "set") (param anyref) get_local 0 set_global $g)
|
||||
)`).exports;
|
||||
|
||||
let obj = { field: null };
|
||||
|
||||
// GCZeal mode 4 implies that prebarriers are being verified at many
|
||||
// locations in the interpreter, during interrupt checks, etc. It can be ultra
|
||||
// slow, so disable it with gczeal(0) when it's not strictly needed.
|
||||
gczeal(4, 1);
|
||||
e.set(obj);
|
||||
e.set(null);
|
||||
gczeal(0);
|
||||
|
||||
if (!isSingleStepProfilingEnabled) {
|
||||
quit(0);
|
||||
}
|
||||
|
||||
enableGeckoProfiling();
|
||||
startProfiling();
|
||||
gczeal(4, 1);
|
||||
e.set(obj);
|
||||
gczeal(0);
|
||||
assertEqPreciseStacks(endProfiling(), [['', '!>', '0,!>', '!>', '']]);
|
||||
|
||||
startProfiling();
|
||||
gczeal(4, 1);
|
||||
e.set(null);
|
||||
gczeal(0);
|
||||
|
||||
// We're losing stack info in the prebarrier code.
|
||||
assertEqPreciseStacks(endProfiling(), [['', '!>', '0,!>', '', '0,!>', '!>', '']]);
|
|
@ -1,14 +0,0 @@
|
|||
if (!wasmGcEnabled()) {
|
||||
quit(0);
|
||||
}
|
||||
|
||||
gczeal(14, 1);
|
||||
let { exports } = wasmEvalText(`(module
|
||||
(global $anyref (import "glob" "anyref") anyref)
|
||||
(func (export "get") (result anyref) get_global $anyref)
|
||||
)`, {
|
||||
glob: {
|
||||
anyref: { sentinel: "lol" },
|
||||
}
|
||||
});
|
||||
assertEq(exports.get().sentinel, "lol");
|
|
@ -49,8 +49,6 @@ let simpleTests = [
|
|||
"(module (func $test (local anyref) (result i32) (ref.is_null (get_local 0))))",
|
||||
`(module (import "a" "b" (param anyref)))`,
|
||||
`(module (import "a" "b" (result anyref)))`,
|
||||
`(module (global anyref (ref.null anyref)))`,
|
||||
`(module (global (mut anyref) (ref.null anyref)))`,
|
||||
];
|
||||
|
||||
for (let src of simpleTests) {
|
||||
|
@ -396,78 +394,3 @@ assertEq(x.i, 24);
|
|||
assertEq(x.newProp, "hello");
|
||||
assertEq(exports.count_f(), 1);
|
||||
assertEq(exports.count_g(), 1);
|
||||
|
||||
// Globals.
|
||||
|
||||
// Anyref globals in wasm modules.
|
||||
|
||||
assertErrorMessage(() => wasmEvalText(`(module (global (import "glob" "anyref") anyref))`, { glob: { anyref: 42 } }),
|
||||
WebAssembly.LinkError,
|
||||
/import object field 'anyref' is not a Object-or-null/);
|
||||
|
||||
assertErrorMessage(() => wasmEvalText(`(module (global (import "glob" "anyref") anyref))`, { glob: { anyref: new WebAssembly.Global({ value: 'i32' }, 42) } }),
|
||||
WebAssembly.LinkError,
|
||||
/imported global type mismatch/);
|
||||
|
||||
assertErrorMessage(() => wasmEvalText(`(module (global (import "glob" "i32") i32))`, { glob: { i32: {} } }),
|
||||
WebAssembly.LinkError,
|
||||
/import object field 'i32' is not a Number/);
|
||||
|
||||
imports = {
|
||||
constants: {
|
||||
imm_null: null,
|
||||
imm_bread: new Baguette(321),
|
||||
mut_null: new WebAssembly.Global({ value: "anyref", mutable: true }, null),
|
||||
mut_bread: new WebAssembly.Global({ value: "anyref", mutable: true }, new Baguette(123))
|
||||
}
|
||||
};
|
||||
|
||||
exports = wasmEvalText(`(module
|
||||
(global $g_imp_imm_null (import "constants" "imm_null") anyref)
|
||||
(global $g_imp_imm_bread (import "constants" "imm_bread") anyref)
|
||||
|
||||
(global $g_imp_mut_null (import "constants" "mut_null") (mut anyref))
|
||||
(global $g_imp_mut_bread (import "constants" "mut_bread") (mut anyref))
|
||||
|
||||
(global $g_imm_null anyref (ref.null anyref))
|
||||
(global $g_imm_getglob anyref (get_global $g_imp_imm_bread))
|
||||
(global $g_mut (mut anyref) (ref.null anyref))
|
||||
|
||||
(func (export "imm_null") (result anyref) get_global $g_imm_null)
|
||||
(func (export "imm_getglob") (result anyref) get_global $g_imm_getglob)
|
||||
|
||||
(func (export "imp_imm_null") (result anyref) get_global $g_imp_imm_null)
|
||||
(func (export "imp_imm_bread") (result anyref) get_global $g_imp_imm_bread)
|
||||
(func (export "imp_mut_null") (result anyref) get_global $g_imp_mut_null)
|
||||
(func (export "imp_mut_bread") (result anyref) get_global $g_imp_mut_bread)
|
||||
|
||||
(func (export "set_imp_null") (param anyref) get_local 0 set_global $g_imp_mut_null)
|
||||
(func (export "set_imp_bread") (param anyref) get_local 0 set_global $g_imp_mut_bread)
|
||||
|
||||
(func (export "set_mut") (param anyref) get_local 0 set_global $g_mut)
|
||||
(func (export "get_mut") (result anyref) get_global $g_mut)
|
||||
)`, imports).exports;
|
||||
|
||||
assertEq(exports.imp_imm_null(), imports.constants.imm_null);
|
||||
assertEq(exports.imp_imm_bread(), imports.constants.imm_bread);
|
||||
|
||||
assertEq(exports.imm_null(), null);
|
||||
assertEq(exports.imm_getglob(), imports.constants.imm_bread);
|
||||
|
||||
assertEq(exports.imp_mut_null(), imports.constants.mut_null.value);
|
||||
assertEq(exports.imp_mut_bread(), imports.constants.mut_bread.value);
|
||||
|
||||
let brandNewBaguette = new Baguette(1000);
|
||||
exports.set_imp_null(brandNewBaguette);
|
||||
assertEq(exports.imp_mut_null(), brandNewBaguette);
|
||||
assertEq(exports.imp_mut_bread(), imports.constants.mut_bread.value);
|
||||
|
||||
exports.set_imp_bread(null);
|
||||
assertEq(exports.imp_mut_null(), brandNewBaguette);
|
||||
assertEq(exports.imp_mut_bread(), null);
|
||||
|
||||
assertEq(exports.get_mut(), null);
|
||||
let glutenFreeBaguette = new Baguette("calories-free bread");
|
||||
exports.set_mut(glutenFreeBaguette);
|
||||
assertEq(exports.get_mut(), glutenFreeBaguette);
|
||||
assertEq(exports.get_mut().calories, "calories-free bread");
|
||||
|
|
|
@ -22,19 +22,14 @@ if (!wasmGcEnabled() || !wasmDebuggingIsSupported()) {
|
|||
|
||||
g.eval(`
|
||||
var obj = { somekey: 'somevalue' };
|
||||
|
||||
Debugger(parent).onEnterFrame = function(frame) {
|
||||
let v = frame.environment.getVariable('var0');
|
||||
assertEq(typeof v, 'object');
|
||||
|
||||
let prop = v.unwrap().getOwnPropertyDescriptor('somekey');
|
||||
assertEq(typeof prop, 'object');
|
||||
assertEq(typeof prop.value, 'string');
|
||||
assertEq(prop.value, 'somevalue');
|
||||
|
||||
// Disable onEnterFrame hook.
|
||||
Debugger(parent).onEnterFrame = undefined;
|
||||
assertEq(typeof v === 'object', true);
|
||||
assertEq(typeof v.somekey === 'string', true);
|
||||
assertEq(v.somekey === 'somevalue', true);
|
||||
};
|
||||
`);
|
||||
|
||||
new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(`${src}`))).exports.func(g.obj);
|
||||
new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(\`${src}\`))).exports.func(obj);
|
||||
`);
|
||||
})();
|
||||
|
|
|
@ -137,8 +137,8 @@ class AsmJSGlobal
|
|||
VarInitKind initKind_;
|
||||
union U {
|
||||
ValType importType_;
|
||||
LitVal val_;
|
||||
U() : val_(LitVal()) {}
|
||||
Val val_;
|
||||
U() : val_(Val()) {}
|
||||
} u;
|
||||
} var;
|
||||
uint32_t ffiIndex_;
|
||||
|
@ -178,7 +178,7 @@ class AsmJSGlobal
|
|||
MOZ_ASSERT(pod.which_ == Variable);
|
||||
return pod.u.var.initKind_;
|
||||
}
|
||||
LitVal varInitVal() const {
|
||||
Val varInitVal() const {
|
||||
MOZ_ASSERT(pod.which_ == Variable);
|
||||
MOZ_ASSERT(pod.u.var.initKind_ == InitConstant);
|
||||
return pod.u.var.u.val_;
|
||||
|
@ -823,7 +823,7 @@ ParseVarOrConstStatement(AsmJSParser& parser, ParseNode** var)
|
|||
//
|
||||
// This class distinguishes between signed and unsigned integer SIMD types like
|
||||
// Int32x4 and Uint32x4, and so does Type below. The wasm ValType and ExprType
|
||||
// enums, and the wasm::LitVal class do not.
|
||||
// enums, and the wasm::Val class do not.
|
||||
class NumLit
|
||||
{
|
||||
public:
|
||||
|
@ -948,33 +948,33 @@ class NumLit
|
|||
return false;
|
||||
}
|
||||
|
||||
LitVal value() const {
|
||||
Val value() const {
|
||||
switch (which_) {
|
||||
case NumLit::Fixnum:
|
||||
case NumLit::NegativeInt:
|
||||
case NumLit::BigUnsigned:
|
||||
return LitVal(toUint32());
|
||||
return Val(toUint32());
|
||||
case NumLit::Float:
|
||||
return LitVal(toFloat());
|
||||
return Val(toFloat());
|
||||
case NumLit::Double:
|
||||
return LitVal(toDouble());
|
||||
return Val(toDouble());
|
||||
case NumLit::Int8x16:
|
||||
case NumLit::Uint8x16:
|
||||
return LitVal(simdValue().asInt8x16());
|
||||
return Val(simdValue().asInt8x16());
|
||||
case NumLit::Int16x8:
|
||||
case NumLit::Uint16x8:
|
||||
return LitVal(simdValue().asInt16x8());
|
||||
return Val(simdValue().asInt16x8());
|
||||
case NumLit::Int32x4:
|
||||
case NumLit::Uint32x4:
|
||||
return LitVal(simdValue().asInt32x4());
|
||||
return Val(simdValue().asInt32x4());
|
||||
case NumLit::Float32x4:
|
||||
return LitVal(simdValue().asFloat32x4());
|
||||
return Val(simdValue().asFloat32x4());
|
||||
case NumLit::Bool8x16:
|
||||
return LitVal(simdValue().asInt8x16(), ValType::B8x16);
|
||||
return Val(simdValue().asInt8x16(), ValType::B8x16);
|
||||
case NumLit::Bool16x8:
|
||||
return LitVal(simdValue().asInt16x8(), ValType::B16x8);
|
||||
return Val(simdValue().asInt16x8(), ValType::B16x8);
|
||||
case NumLit::Bool32x4:
|
||||
return LitVal(simdValue().asInt32x4(), ValType::B32x4);
|
||||
return Val(simdValue().asInt32x4(), ValType::B32x4);
|
||||
case NumLit::OutOfRangeInt:;
|
||||
}
|
||||
MOZ_CRASH("bad literal");
|
||||
|
@ -2287,7 +2287,7 @@ class MOZ_STACK_CLASS JS_HAZ_ROOTED ModuleValidator
|
|||
for (uint32_t& index : elems)
|
||||
index += funcImportMap_.count();
|
||||
|
||||
return env_.elemSegments.emplaceBack(tableIndex, InitExpr(LitVal(uint32_t(0))), std::move(elems));
|
||||
return env_.elemSegments.emplaceBack(tableIndex, InitExpr(Val(uint32_t(0))), std::move(elems));
|
||||
}
|
||||
bool declareImport(PropertyName* name, FuncType&& sig, unsigned ffiIndex, uint32_t* importIndex) {
|
||||
FuncImportMap::AddPtr p = funcImportMap_.lookupForAdd(NamedSig::Lookup(name, sig));
|
||||
|
@ -7671,12 +7671,11 @@ HasPureCoercion(JSContext* cx, HandleValue v)
|
|||
}
|
||||
|
||||
static bool
|
||||
ValidateGlobalVariable(JSContext* cx, const AsmJSGlobal& global, HandleValue importVal,
|
||||
Maybe<LitVal>* val)
|
||||
ValidateGlobalVariable(JSContext* cx, const AsmJSGlobal& global, HandleValue importVal, Val* val)
|
||||
{
|
||||
switch (global.varInitKind()) {
|
||||
case AsmJSGlobal::InitConstant:
|
||||
val->emplace(global.varInitVal());
|
||||
*val = global.varInitVal();
|
||||
return true;
|
||||
|
||||
case AsmJSGlobal::InitImport: {
|
||||
|
@ -7692,7 +7691,7 @@ ValidateGlobalVariable(JSContext* cx, const AsmJSGlobal& global, HandleValue imp
|
|||
int32_t i32;
|
||||
if (!ToInt32(cx, v, &i32))
|
||||
return false;
|
||||
val->emplace(uint32_t(i32));
|
||||
*val = Val(uint32_t(i32));
|
||||
return true;
|
||||
}
|
||||
case ValType::I64:
|
||||
|
@ -7701,42 +7700,42 @@ ValidateGlobalVariable(JSContext* cx, const AsmJSGlobal& global, HandleValue imp
|
|||
float f;
|
||||
if (!RoundFloat32(cx, v, &f))
|
||||
return false;
|
||||
val->emplace(f);
|
||||
*val = Val(f);
|
||||
return true;
|
||||
}
|
||||
case ValType::F64: {
|
||||
double d;
|
||||
if (!ToNumber(cx, v, &d))
|
||||
return false;
|
||||
val->emplace(d);
|
||||
*val = Val(d);
|
||||
return true;
|
||||
}
|
||||
case ValType::I8x16: {
|
||||
SimdConstant simdConstant;
|
||||
if (!ToSimdConstant<Int8x16>(cx, v, &simdConstant))
|
||||
return false;
|
||||
val->emplace(simdConstant.asInt8x16());
|
||||
*val = Val(simdConstant.asInt8x16());
|
||||
return true;
|
||||
}
|
||||
case ValType::I16x8: {
|
||||
SimdConstant simdConstant;
|
||||
if (!ToSimdConstant<Int16x8>(cx, v, &simdConstant))
|
||||
return false;
|
||||
val->emplace(simdConstant.asInt16x8());
|
||||
*val = Val(simdConstant.asInt16x8());
|
||||
return true;
|
||||
}
|
||||
case ValType::I32x4: {
|
||||
SimdConstant simdConstant;
|
||||
if (!ToSimdConstant<Int32x4>(cx, v, &simdConstant))
|
||||
return false;
|
||||
val->emplace(simdConstant.asInt32x4());
|
||||
*val = Val(simdConstant.asInt32x4());
|
||||
return true;
|
||||
}
|
||||
case ValType::F32x4: {
|
||||
SimdConstant simdConstant;
|
||||
if (!ToSimdConstant<Float32x4>(cx, v, &simdConstant))
|
||||
return false;
|
||||
val->emplace(simdConstant.asFloat32x4());
|
||||
*val = Val(simdConstant.asFloat32x4());
|
||||
return true;
|
||||
}
|
||||
case ValType::B8x16: {
|
||||
|
@ -7744,7 +7743,7 @@ ValidateGlobalVariable(JSContext* cx, const AsmJSGlobal& global, HandleValue imp
|
|||
if (!ToSimdConstant<Bool8x16>(cx, v, &simdConstant))
|
||||
return false;
|
||||
// Bool8x16 uses the same data layout as Int8x16.
|
||||
val->emplace(simdConstant.asInt8x16());
|
||||
*val = Val(simdConstant.asInt8x16());
|
||||
return true;
|
||||
}
|
||||
case ValType::B16x8: {
|
||||
|
@ -7752,7 +7751,7 @@ ValidateGlobalVariable(JSContext* cx, const AsmJSGlobal& global, HandleValue imp
|
|||
if (!ToSimdConstant<Bool16x8>(cx, v, &simdConstant))
|
||||
return false;
|
||||
// Bool16x8 uses the same data layout as Int16x8.
|
||||
val->emplace(simdConstant.asInt16x8());
|
||||
*val = Val(simdConstant.asInt16x8());
|
||||
return true;
|
||||
}
|
||||
case ValType::B32x4: {
|
||||
|
@ -7760,7 +7759,7 @@ ValidateGlobalVariable(JSContext* cx, const AsmJSGlobal& global, HandleValue imp
|
|||
if (!ToSimdConstant<Bool32x4>(cx, v, &simdConstant))
|
||||
return false;
|
||||
// Bool32x4 uses the same data layout as Int32x4.
|
||||
val->emplace(simdConstant.asInt32x4());
|
||||
*val = Val(simdConstant.asInt32x4());
|
||||
return true;
|
||||
}
|
||||
case ValType::Ref:
|
||||
|
@ -8134,8 +8133,7 @@ CheckBuffer(JSContext* cx, const AsmJSMetadata& metadata, HandleValue bufferVal,
|
|||
|
||||
static bool
|
||||
GetImports(JSContext* cx, const AsmJSMetadata& metadata, HandleValue globalVal,
|
||||
HandleValue importVal, MutableHandle<FunctionVector> funcImports,
|
||||
MutableHandleValVector valImports)
|
||||
HandleValue importVal, MutableHandle<FunctionVector> funcImports, ValVector* valImports)
|
||||
{
|
||||
Rooted<FunctionVector> ffis(cx, FunctionVector(cx));
|
||||
if (!ffis.resize(metadata.numFFIs))
|
||||
|
@ -8144,10 +8142,10 @@ GetImports(JSContext* cx, const AsmJSMetadata& metadata, HandleValue globalVal,
|
|||
for (const AsmJSGlobal& global : metadata.asmJSGlobals) {
|
||||
switch (global.which()) {
|
||||
case AsmJSGlobal::Variable: {
|
||||
Maybe<LitVal> litVal;
|
||||
if (!ValidateGlobalVariable(cx, global, importVal, &litVal))
|
||||
Val val;
|
||||
if (!ValidateGlobalVariable(cx, global, importVal, &val))
|
||||
return false;
|
||||
if (!valImports.append(Val(*litVal)))
|
||||
if (!valImports->append(val))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
@ -8210,7 +8208,7 @@ TryInstantiate(JSContext* cx, CallArgs args, Module& module, const AsmJSMetadata
|
|||
return false;
|
||||
}
|
||||
|
||||
RootedValVector valImports(cx);
|
||||
ValVector valImports;
|
||||
Rooted<FunctionVector> funcs(cx, FunctionVector(cx));
|
||||
if (!GetImports(cx, metadata, globalVal, importVal, &funcs, &valImports))
|
||||
return false;
|
||||
|
@ -8218,8 +8216,7 @@ TryInstantiate(JSContext* cx, CallArgs args, Module& module, const AsmJSMetadata
|
|||
Rooted<WasmGlobalObjectVector> globalObjs(cx);
|
||||
|
||||
RootedWasmTableObject table(cx);
|
||||
if (!module.instantiate(cx, funcs, table, memory, valImports, globalObjs.get(), nullptr,
|
||||
instanceObj))
|
||||
if (!module.instantiate(cx, funcs, table, memory, valImports, globalObjs.get(), nullptr, instanceObj))
|
||||
return false;
|
||||
|
||||
exportObj.set(&instanceObj->exportsObj());
|
||||
|
|
|
@ -557,15 +557,15 @@ class AstDrop : public AstExpr
|
|||
|
||||
class AstConst : public AstExpr
|
||||
{
|
||||
const LitVal val_;
|
||||
const Val val_;
|
||||
|
||||
public:
|
||||
static const AstExprKind Kind = AstExprKind::Const;
|
||||
explicit AstConst(LitVal val)
|
||||
explicit AstConst(Val val)
|
||||
: AstExpr(Kind, ExprType::Limit),
|
||||
val_(val)
|
||||
{}
|
||||
LitVal val() const { return val_; }
|
||||
Val val() const { return val_; }
|
||||
};
|
||||
|
||||
class AstGetLocal : public AstExpr
|
||||
|
|
|
@ -139,7 +139,6 @@
|
|||
#endif
|
||||
|
||||
#include "wasm/WasmGenerator.h"
|
||||
#include "wasm/WasmInstance.h"
|
||||
#include "wasm/WasmOpIter.h"
|
||||
#include "wasm/WasmSignalHandlers.h"
|
||||
#include "wasm/WasmValidate.h"
|
||||
|
@ -4396,6 +4395,7 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
Address addressOfGlobalVar(const GlobalDesc& global, RegI32 tmp)
|
||||
{
|
||||
uint32_t globalToTlsOffset = offsetof(TlsData, globalArea) + global.offset();
|
||||
|
||||
masm.loadWasmTlsRegFromFrame(tmp);
|
||||
if (global.isIndirect()) {
|
||||
masm.loadPtr(Address(tmp, globalToTlsOffset), tmp);
|
||||
|
@ -5721,81 +5721,6 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
masm.branch64(c, lhs, rhs, l);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_WASM_GC
|
||||
// The following couple of functions emit a GC pre-write barrier. This is
|
||||
// needed when we replace a member field with a new value, and the previous
|
||||
// field value might have no other referents. The field might belong to an
|
||||
// object or be a stack slot or a register or a heap allocated value.
|
||||
//
|
||||
// let obj = { field: previousValue };
|
||||
// obj.field = newValue; // previousValue must be marked with a pre-barrier.
|
||||
//
|
||||
// Implementing a pre-barrier looks like this:
|
||||
// - call `testNeedPreBarrier` with a fresh label.
|
||||
// - user code must put the address of the field we're about to clobber in
|
||||
// PreBarrierReg (to avoid explicit pushing/popping).
|
||||
// - call `emitPreBarrier`, which binds the label.
|
||||
|
||||
void testNeedPreBarrier(Label* skipBarrier) {
|
||||
MOZ_ASSERT(!skipBarrier->used());
|
||||
MOZ_ASSERT(!skipBarrier->bound());
|
||||
|
||||
// If no incremental GC has started, we don't need the barrier.
|
||||
ScratchPtr scratch(*this);
|
||||
masm.loadWasmTlsRegFromFrame(scratch);
|
||||
masm.loadPtr(Address(scratch, offsetof(TlsData, addressOfNeedsIncrementalBarrier)), scratch);
|
||||
masm.branchTest32(Assembler::Zero, Address(scratch, 0), Imm32(0x1), skipBarrier);
|
||||
}
|
||||
|
||||
void emitPreBarrier(RegPtr valueAddr, Label* skipBarrier) {
|
||||
MOZ_ASSERT(valueAddr == PreBarrierReg);
|
||||
|
||||
// If the previous value is null, we don't need the barrier.
|
||||
ScratchPtr scratch(*this);
|
||||
masm.loadPtr(Address(valueAddr, 0), scratch);
|
||||
masm.branchTestPtr(Assembler::Zero, scratch, scratch, skipBarrier);
|
||||
|
||||
// Call the barrier. This assumes PreBarrierReg contains the address of
|
||||
// the stored value.
|
||||
masm.loadWasmTlsRegFromFrame(scratch);
|
||||
masm.loadPtr(Address(scratch, offsetof(TlsData, instance)), scratch);
|
||||
masm.loadPtr(Address(scratch, Instance::offsetOfPreBarrierCode()), scratch);
|
||||
masm.call(scratch);
|
||||
|
||||
masm.bind(skipBarrier);
|
||||
}
|
||||
|
||||
// This emits a GC post-write barrier. This is needed to ensure that the GC
|
||||
// is aware of slots of tenured things containing references to nursery
|
||||
// values. Pass None for object when the field's owner object is known to
|
||||
// be tenured or heap-allocated.
|
||||
|
||||
void emitPostBarrier(const Maybe<RegPtr>& object, RegPtr setValue, PostBarrierArg arg) {
|
||||
Label skipBarrier;
|
||||
|
||||
// If the set value is null, no barrier.
|
||||
masm.branchTestPtr(Assembler::Zero, setValue, setValue, &skipBarrier);
|
||||
|
||||
RegPtr scratch = needRef();
|
||||
if (object) {
|
||||
// If the object value isn't tenured, no barrier.
|
||||
masm.branchPtrInNurseryChunk(Assembler::Equal, *object, scratch, &skipBarrier);
|
||||
}
|
||||
|
||||
// If the set value is tenured, no barrier.
|
||||
masm.branchPtrInNurseryChunk(Assembler::NotEqual, setValue, scratch, &skipBarrier);
|
||||
|
||||
freeRef(scratch);
|
||||
|
||||
// Need a barrier.
|
||||
uint32_t bytecodeOffset = iter_.lastOpcodeOffset();
|
||||
pushI32(arg.rawPayload());
|
||||
emitInstanceCall(bytecodeOffset, SigPI_, ExprType::Void, SymbolicAddress::PostBarrier);
|
||||
|
||||
masm.bind(&skipBarrier);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Emit a conditional branch that optionally and optimally cleans up the CPU
|
||||
// stack before we branch.
|
||||
//
|
||||
|
@ -8328,7 +8253,7 @@ BaseCompiler::emitGetGlobal()
|
|||
const GlobalDesc& global = env_.globals[id];
|
||||
|
||||
if (global.isConstant()) {
|
||||
LitVal value = global.constantValue();
|
||||
Val value = global.constantValue();
|
||||
switch (value.type().code()) {
|
||||
case ValType::I32:
|
||||
pushI32(value.i32());
|
||||
|
@ -8342,9 +8267,6 @@ BaseCompiler::emitGetGlobal()
|
|||
case ValType::F64:
|
||||
pushF64(value.f64());
|
||||
break;
|
||||
case ValType::AnyRef:
|
||||
pushRef(intptr_t(value.ptr()));
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Global constant type");
|
||||
}
|
||||
|
@ -8380,13 +8302,6 @@ BaseCompiler::emitGetGlobal()
|
|||
pushF64(rv);
|
||||
break;
|
||||
}
|
||||
case ValType::AnyRef: {
|
||||
RegPtr rv = needRef();
|
||||
ScratchI32 tmp(*this);
|
||||
masm.loadPtr(addressOfGlobalVar(global, tmp), rv);
|
||||
pushRef(rv);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH("Global variable type");
|
||||
break;
|
||||
|
@ -8436,33 +8351,6 @@ BaseCompiler::emitSetGlobal()
|
|||
freeF64(rv);
|
||||
break;
|
||||
}
|
||||
#ifdef ENABLE_WASM_GC
|
||||
case ValType::AnyRef: {
|
||||
Label skipBarrier;
|
||||
testNeedPreBarrier(&skipBarrier);
|
||||
|
||||
RegPtr valueAddr(PreBarrierReg);
|
||||
needRef(valueAddr);
|
||||
{
|
||||
ScratchI32 tmp(*this);
|
||||
masm.computeEffectiveAddress(addressOfGlobalVar(global, tmp), valueAddr);
|
||||
}
|
||||
emitPreBarrier(valueAddr, &skipBarrier);
|
||||
freeRef(valueAddr);
|
||||
|
||||
RegPtr rv = popRef();
|
||||
{
|
||||
// Actual store.
|
||||
ScratchI32 tmp(*this);
|
||||
masm.storePtr(rv, addressOfGlobalVar(global, tmp));
|
||||
}
|
||||
|
||||
emitPostBarrier(Nothing(), rv, PostBarrierArg::Global(id));
|
||||
|
||||
freeRef(rv);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
MOZ_CRASH("Global variable type");
|
||||
break;
|
||||
|
|
|
@ -677,10 +677,6 @@ AddressOf(SymbolicAddress imm, ABIFunctionType* abiType)
|
|||
case SymbolicAddress::MemFill:
|
||||
*abiType = Args_General4;
|
||||
return FuncCast(Instance::memFill, *abiType);
|
||||
case SymbolicAddress::PostBarrier:
|
||||
*abiType = Args_General2;
|
||||
static_assert(sizeof(PostBarrierArg) == sizeof(uint32_t), "passed arg is a u32");
|
||||
return FuncCast(Instance::postBarrier, *abiType);
|
||||
#if defined(JS_CODEGEN_MIPS32)
|
||||
case SymbolicAddress::js_jit_gAtomic64Lock:
|
||||
return &js::jit::gAtomic64Lock;
|
||||
|
@ -759,7 +755,6 @@ wasm::NeedsBuiltinThunk(SymbolicAddress sym)
|
|||
case SymbolicAddress::ReportInt64JSCall:
|
||||
case SymbolicAddress::MemCopy:
|
||||
case SymbolicAddress::MemFill:
|
||||
case SymbolicAddress::PostBarrier:
|
||||
return true;
|
||||
case SymbolicAddress::Limit:
|
||||
break;
|
||||
|
|
|
@ -398,7 +398,7 @@ DebugState::getGlobal(Instance& instance, uint32_t globalIndex, MutableHandleVal
|
|||
const GlobalDesc& global = metadata().globals[globalIndex];
|
||||
|
||||
if (global.isConstant()) {
|
||||
LitVal value = global.constantValue();
|
||||
Val value = global.constantValue();
|
||||
switch (value.type().code()) {
|
||||
case ValType::I32:
|
||||
vp.set(Int32Value(value.i32()));
|
||||
|
|
|
@ -1267,8 +1267,6 @@ ThunkedNativeToDescription(SymbolicAddress func)
|
|||
return "call to native memory.copy function";
|
||||
case SymbolicAddress::MemFill:
|
||||
return "call to native memory.fill function";
|
||||
case SymbolicAddress::PostBarrier:
|
||||
return "call to native GC postbarrier (in wasm)";
|
||||
#if defined(JS_CODEGEN_MIPS32)
|
||||
case SymbolicAddress::js_jit_gAtomic64Lock:
|
||||
MOZ_CRASH();
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include "wasm/WasmBuiltins.h"
|
||||
#include "wasm/WasmModule.h"
|
||||
|
||||
#include "gc/StoreBuffer-inl.h"
|
||||
#include "vm/ArrayBufferObject-inl.h"
|
||||
#include "vm/JSObject-inl.h"
|
||||
|
||||
|
@ -413,12 +412,15 @@ Instance::memCopy(Instance* instance, uint32_t destByteOffset, uint32_t srcByteO
|
|||
|
||||
// Knowing that len > 0 below simplifies the wraparound checks.
|
||||
if (len == 0) {
|
||||
|
||||
// Even though the length is zero, we must check for a valid offset.
|
||||
if (destByteOffset < memLen && srcByteOffset < memLen)
|
||||
return 0;
|
||||
|
||||
// else fall through to failure case
|
||||
|
||||
} else {
|
||||
|
||||
ArrayBufferObjectMaybeShared& arrBuf = mem->buffer();
|
||||
uint8_t* rawBuf = arrBuf.dataPointerEither().unwrap();
|
||||
|
||||
|
@ -451,12 +453,15 @@ Instance::memFill(Instance* instance, uint32_t byteOffset, uint32_t value, uint3
|
|||
|
||||
// Knowing that len > 0 below simplifies the wraparound check.
|
||||
if (len == 0) {
|
||||
|
||||
// Even though the length is zero, we must check for a valid offset.
|
||||
if (byteOffset < memLen)
|
||||
return 0;
|
||||
|
||||
// else fall through to failure case
|
||||
|
||||
} else {
|
||||
|
||||
ArrayBufferObjectMaybeShared& arrBuf = mem->buffer();
|
||||
uint8_t* rawBuf = arrBuf.dataPointerEither().unwrap();
|
||||
|
||||
|
@ -471,6 +476,7 @@ Instance::memFill(Instance* instance, uint32_t byteOffset, uint32_t value, uint3
|
|||
return 0;
|
||||
}
|
||||
// else fall through to failure case
|
||||
|
||||
}
|
||||
|
||||
JSContext* cx = TlsContext.get();
|
||||
|
@ -478,28 +484,6 @@ Instance::memFill(Instance* instance, uint32_t byteOffset, uint32_t value, uint3
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
Instance::postBarrier(Instance* instance, PostBarrierArg arg)
|
||||
{
|
||||
gc::Cell** cell = nullptr;
|
||||
switch (arg.type()) {
|
||||
case PostBarrierArg::Type::Global: {
|
||||
const GlobalDesc& global = instance->metadata().globals[arg.globalIndex()];
|
||||
MOZ_ASSERT(!global.isConstant());
|
||||
MOZ_ASSERT(global.type().isRefOrAnyRef());
|
||||
uint8_t* globalAddr = instance->globalData() + global.offset();
|
||||
if (global.isIndirect())
|
||||
globalAddr = *(uint8_t**)globalAddr;
|
||||
MOZ_ASSERT(*(JSObject**)globalAddr, "shouldn't call postbarrier if null");
|
||||
cell = (gc::Cell**) globalAddr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(cell);
|
||||
TlsContext.get()->runtime()->gc.storeBuffer().putCell(cell);
|
||||
}
|
||||
|
||||
Instance::Instance(JSContext* cx,
|
||||
Handle<WasmInstanceObject*> object,
|
||||
SharedCode code,
|
||||
|
@ -508,7 +492,7 @@ Instance::Instance(JSContext* cx,
|
|||
HandleWasmMemoryObject memory,
|
||||
SharedTableVector&& tables,
|
||||
Handle<FunctionVector> funcImports,
|
||||
HandleValVector globalImportValues,
|
||||
const ValVector& globalImportValues,
|
||||
const WasmGlobalObjectVector& globalObjs)
|
||||
: realm_(cx->realm()),
|
||||
object_(object),
|
||||
|
@ -534,10 +518,6 @@ Instance::Instance(JSContext* cx,
|
|||
tlsData()->cx = cx;
|
||||
tlsData()->resetInterrupt(cx);
|
||||
tlsData()->jumpTable = code_->tieringJumpTable();
|
||||
#ifdef ENABLE_WASM_GC
|
||||
tlsData()->addressOfNeedsIncrementalBarrier =
|
||||
(uint8_t*)cx->compartment()->zone()->addressOfNeedsIncrementalBarrier();
|
||||
#endif
|
||||
|
||||
Tier callerTier = code_->bestTier();
|
||||
|
||||
|
@ -591,7 +571,7 @@ Instance::Instance(JSContext* cx,
|
|||
if (global.isIndirect())
|
||||
*(void**)globalAddr = globalObjs[imported]->cell();
|
||||
else
|
||||
globalImportValues[imported].get().writePayload(globalAddr);
|
||||
globalImportValues[imported].writePayload(globalAddr);
|
||||
break;
|
||||
}
|
||||
case GlobalKind::Variable: {
|
||||
|
@ -601,7 +581,7 @@ Instance::Instance(JSContext* cx,
|
|||
if (global.isIndirect())
|
||||
*(void**)globalAddr = globalObjs[i]->cell();
|
||||
else
|
||||
Val(init.val()).writePayload(globalAddr);
|
||||
init.val().writePayload(globalAddr);
|
||||
break;
|
||||
}
|
||||
case InitExpr::Kind::GetGlobal: {
|
||||
|
@ -611,13 +591,12 @@ Instance::Instance(JSContext* cx,
|
|||
// the source global should never be indirect.
|
||||
MOZ_ASSERT(!imported.isIndirect());
|
||||
|
||||
RootedVal dest(cx, globalImportValues[imported.importIndex()].get());
|
||||
if (global.isIndirect()) {
|
||||
void* address = globalObjs[i]->cell();
|
||||
*(void**)globalAddr = address;
|
||||
dest.get().writePayload((uint8_t*)address);
|
||||
globalImportValues[imported.importIndex()].writePayload((uint8_t*)address);
|
||||
} else {
|
||||
dest.get().writePayload(globalAddr);
|
||||
globalImportValues[imported.importIndex()].writePayload(globalAddr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -662,7 +641,6 @@ Instance::init(JSContext* cx)
|
|||
return false;
|
||||
jsJitArgsRectifier_ = jitRuntime->getArgumentsRectifier();
|
||||
jsJitExceptionHandler_ = jitRuntime->getExceptionTail();
|
||||
preBarrierCode_ = jitRuntime->preBarrier(MIRType::Object);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -730,16 +708,6 @@ Instance::tracePrivate(JSTracer* trc)
|
|||
for (const SharedTable& table : tables_)
|
||||
table->trace(trc);
|
||||
|
||||
#ifdef ENABLE_WASM_GC
|
||||
for (const GlobalDesc& global : code().metadata().globals) {
|
||||
// Indirect anyref global get traced by the owning WebAssembly.Global.
|
||||
if (global.type() != ValType::AnyRef || global.isConstant() || global.isIndirect())
|
||||
continue;
|
||||
GCPtrObject* obj = (GCPtrObject*)(globalData() + global.offset());
|
||||
TraceNullableEdge(trc, obj, "wasm anyref global");
|
||||
}
|
||||
#endif
|
||||
|
||||
TraceNullableEdge(trc, &memory_, "wasm buffer");
|
||||
}
|
||||
|
||||
|
|
|
@ -47,9 +47,6 @@ class Instance
|
|||
ReadBarrieredWasmInstanceObject object_;
|
||||
jit::TrampolinePtr jsJitArgsRectifier_;
|
||||
jit::TrampolinePtr jsJitExceptionHandler_;
|
||||
#ifdef ENABLE_WASM_GC
|
||||
jit::TrampolinePtr preBarrierCode_;
|
||||
#endif
|
||||
const SharedCode code_;
|
||||
const UniqueDebugState debug_;
|
||||
const UniqueTlsData tlsData_;
|
||||
|
@ -78,7 +75,7 @@ class Instance
|
|||
HandleWasmMemoryObject memory,
|
||||
SharedTableVector&& tables,
|
||||
Handle<FunctionVector> funcImports,
|
||||
HandleValVector globalImportValues,
|
||||
const ValVector& globalImportValues,
|
||||
const WasmGlobalObjectVector& globalObjs);
|
||||
~Instance();
|
||||
bool init(JSContext* cx);
|
||||
|
@ -111,11 +108,6 @@ class Instance
|
|||
static constexpr size_t offsetOfJSJitExceptionHandler() {
|
||||
return offsetof(Instance, jsJitExceptionHandler_);
|
||||
}
|
||||
#ifdef ENABLE_WASM_GC
|
||||
static constexpr size_t offsetOfPreBarrierCode() {
|
||||
return offsetof(Instance, preBarrierCode_);
|
||||
}
|
||||
#endif
|
||||
|
||||
// This method returns a pointer to the GC object that owns this Instance.
|
||||
// Instances may be reached via weak edges (e.g., Compartment::instances_)
|
||||
|
@ -179,7 +171,6 @@ class Instance
|
|||
static int32_t wake(Instance* instance, uint32_t byteOffset, int32_t count);
|
||||
static int32_t memCopy(Instance* instance, uint32_t destByteOffset, uint32_t srcByteOffset, uint32_t len);
|
||||
static int32_t memFill(Instance* instance, uint32_t byteOffset, uint32_t value, uint32_t len);
|
||||
static void postBarrier(Instance* instance, PostBarrierArg arg);
|
||||
};
|
||||
|
||||
typedef UniquePtr<Instance> UniqueInstance;
|
||||
|
|
|
@ -2303,7 +2303,7 @@ EmitGetGlobal(FunctionCompiler& f)
|
|||
return true;
|
||||
}
|
||||
|
||||
LitVal value = global.constantValue();
|
||||
Val value = global.constantValue();
|
||||
MIRType mirType = ToMIRType(value.type());
|
||||
|
||||
MDefinition* result;
|
||||
|
|
|
@ -45,16 +45,6 @@
|
|||
#include "vm/JSObject-inl.h"
|
||||
#include "vm/NativeObject-inl.h"
|
||||
|
||||
#define WASM_CRASH_IF_SIMD_TYPES \
|
||||
case ValType::I8x16: \
|
||||
case ValType::B8x16: \
|
||||
case ValType::I16x8: \
|
||||
case ValType::B16x8: \
|
||||
case ValType::I32x4: \
|
||||
case ValType::B32x4: \
|
||||
case ValType::F32x4: \
|
||||
MOZ_CRASH("unexpected SIMD type")
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
using namespace js::wasm;
|
||||
|
@ -120,49 +110,34 @@ wasm::HasSupport(JSContext* cx)
|
|||
}
|
||||
|
||||
static bool
|
||||
ToWebAssemblyValue(JSContext* cx, ValType targetType, HandleValue v, MutableHandleVal val)
|
||||
ToWebAssemblyValue(JSContext* cx, ValType targetType, HandleValue v, Val* val)
|
||||
{
|
||||
switch (targetType.code()) {
|
||||
case ValType::I32: {
|
||||
int32_t i32;
|
||||
if (!ToInt32(cx, v, &i32))
|
||||
return false;
|
||||
val.set(Val(uint32_t(i32)));
|
||||
*val = Val(uint32_t(i32));
|
||||
return true;
|
||||
}
|
||||
case ValType::F32: {
|
||||
double d;
|
||||
if (!ToNumber(cx, v, &d))
|
||||
return false;
|
||||
val.set(Val(float(d)));
|
||||
*val = Val(float(d));
|
||||
return true;
|
||||
}
|
||||
case ValType::F64: {
|
||||
double d;
|
||||
if (!ToNumber(cx, v, &d))
|
||||
return false;
|
||||
val.set(Val(d));
|
||||
*val = Val(d);
|
||||
return true;
|
||||
}
|
||||
case ValType::AnyRef: {
|
||||
if (v.isNull()) {
|
||||
val.set(Val(nullptr));
|
||||
} else {
|
||||
JSObject* obj = ToObject(cx, v);
|
||||
if (!obj)
|
||||
return false;
|
||||
MOZ_ASSERT(obj->compartment() == cx->compartment());
|
||||
val.set(Val(obj));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
WASM_CRASH_IF_SIMD_TYPES;
|
||||
case ValType::Ref:
|
||||
case ValType::I64: {
|
||||
break;
|
||||
default: {
|
||||
MOZ_CRASH("unexpected import value type, caller must guard");
|
||||
}
|
||||
}
|
||||
MOZ_CRASH("unexpected import value type, caller must guard");
|
||||
}
|
||||
|
||||
static Value
|
||||
|
@ -175,16 +150,9 @@ ToJSValue(const Val& val)
|
|||
return DoubleValue(JS::CanonicalizeNaN(double(val.f32())));
|
||||
case ValType::F64:
|
||||
return DoubleValue(JS::CanonicalizeNaN(val.f64()));
|
||||
case ValType::AnyRef:
|
||||
if (!val.ptr())
|
||||
return NullValue();
|
||||
return ObjectValue(*(JSObject*)val.ptr());
|
||||
WASM_CRASH_IF_SIMD_TYPES;
|
||||
case ValType::Ref:
|
||||
case ValType::I64:
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected type when translating to a JS value");
|
||||
}
|
||||
MOZ_CRASH("unexpected type when translating to a JS value");
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
@ -223,7 +191,7 @@ GetImports(JSContext* cx,
|
|||
MutableHandleWasmTableObject tableImport,
|
||||
MutableHandleWasmMemoryObject memoryImport,
|
||||
WasmGlobalObjectVector& globalObjs,
|
||||
MutableHandleValVector globalImportValues)
|
||||
ValVector* globalImportValues)
|
||||
{
|
||||
const ImportVector& imports = module.imports();
|
||||
if (!imports.empty() && !importObj)
|
||||
|
@ -275,11 +243,11 @@ GetImports(JSContext* cx,
|
|||
break;
|
||||
}
|
||||
case DefinitionKind::Global: {
|
||||
Val val;
|
||||
const uint32_t index = globalIndex++;
|
||||
const GlobalDesc& global = globals[index];
|
||||
MOZ_ASSERT(global.importIndex() == index);
|
||||
|
||||
RootedVal val(cx);
|
||||
if (v.isObject() && v.toObject().is<WasmGlobalObject>()) {
|
||||
RootedWasmGlobalObject obj(cx, &v.toObject().as<WasmGlobalObject>());
|
||||
|
||||
|
@ -297,17 +265,9 @@ GetImports(JSContext* cx,
|
|||
return false;
|
||||
}
|
||||
globalObjs[index] = obj;
|
||||
obj->val(&val);
|
||||
} else {
|
||||
if (IsNumberType(global.type())) {
|
||||
if (!v.isNumber())
|
||||
return ThrowBadImportType(cx, import.field.get(), "Number");
|
||||
} else {
|
||||
MOZ_ASSERT(global.type().isRefOrAnyRef());
|
||||
if (!v.isNull() && !v.isObject())
|
||||
return ThrowBadImportType(cx, import.field.get(), "Object-or-null");
|
||||
}
|
||||
|
||||
val = obj->val();
|
||||
} else
|
||||
if (v.isNumber()) {
|
||||
if (global.type() == ValType::I64) {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_I64_LINK);
|
||||
return false;
|
||||
|
@ -320,9 +280,11 @@ GetImports(JSContext* cx,
|
|||
|
||||
if (!ToWebAssemblyValue(cx, global.type(), v, &val))
|
||||
return false;
|
||||
} else {
|
||||
return ThrowBadImportType(cx, import.field.get(), "Number");
|
||||
}
|
||||
|
||||
if (!globalImportValues.append(val))
|
||||
if (!globalImportValues->append(val))
|
||||
return false;
|
||||
|
||||
break;
|
||||
|
@ -397,12 +359,11 @@ wasm::Eval(JSContext* cx, Handle<TypedArrayObject*> code, HandleObject importObj
|
|||
RootedWasmMemoryObject memory(cx);
|
||||
Rooted<WasmGlobalObjectVector> globalObjs(cx);
|
||||
|
||||
RootedValVector globals(cx);
|
||||
ValVector globals;
|
||||
if (!GetImports(cx, *module, importObj, &funcs, &table, &memory, globalObjs.get(), &globals))
|
||||
return false;
|
||||
|
||||
return module->instantiate(cx, funcs, table, memory, globals, globalObjs.get(), nullptr,
|
||||
instanceObj);
|
||||
return module->instantiate(cx, funcs, table, memory, globals, globalObjs.get(), nullptr, instanceObj);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
@ -1088,7 +1049,7 @@ WasmInstanceObject::create(JSContext* cx,
|
|||
SharedTableVector&& tables,
|
||||
Handle<FunctionVector> funcImports,
|
||||
const GlobalDescVector& globals,
|
||||
HandleValVector globalImportValues,
|
||||
const ValVector& globalImportValues,
|
||||
const WasmGlobalObjectVector& globalObjs,
|
||||
HandleObject proto)
|
||||
{
|
||||
|
@ -1195,12 +1156,11 @@ Instantiate(JSContext* cx, const Module& module, HandleObject importObj,
|
|||
RootedWasmMemoryObject memory(cx);
|
||||
Rooted<WasmGlobalObjectVector> globalObjs(cx);
|
||||
|
||||
RootedValVector globals(cx);
|
||||
ValVector globals;
|
||||
if (!GetImports(cx, module, importObj, &funcs, &table, &memory, globalObjs.get(), &globals))
|
||||
return false;
|
||||
|
||||
return module.instantiate(cx, funcs, table, memory, globals, globalObjs.get(), instanceProto,
|
||||
instanceObj);
|
||||
return module.instantiate(cx, funcs, table, memory, globals, globalObjs.get(), instanceProto, instanceObj);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
|
@ -2142,7 +2102,7 @@ const ClassOps WasmGlobalObject::classOps_ =
|
|||
nullptr, /* call */
|
||||
nullptr, /* hasInstance */
|
||||
nullptr, /* construct */
|
||||
WasmGlobalObject::trace
|
||||
nullptr /* trace */
|
||||
};
|
||||
|
||||
const Class WasmGlobalObject::class_ =
|
||||
|
@ -2153,26 +2113,6 @@ const Class WasmGlobalObject::class_ =
|
|||
&WasmGlobalObject::classOps_
|
||||
};
|
||||
|
||||
/* static */ void
|
||||
WasmGlobalObject::trace(JSTracer* trc, JSObject* obj)
|
||||
{
|
||||
WasmGlobalObject* global = reinterpret_cast<WasmGlobalObject*>(obj);
|
||||
switch (global->type().code()) {
|
||||
case ValType::AnyRef:
|
||||
if (global->cell()->ptr)
|
||||
TraceManuallyBarrieredEdge(trc, &global->cell()->ptr, "wasm anyref global");
|
||||
break;
|
||||
case ValType::I32:
|
||||
case ValType::F32:
|
||||
case ValType::I64:
|
||||
case ValType::F64:
|
||||
break;
|
||||
WASM_CRASH_IF_SIMD_TYPES;
|
||||
case ValType::Ref:
|
||||
MOZ_CRASH("Ref NYI");
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
WasmGlobalObject::finalize(FreeOp*, JSObject* obj)
|
||||
{
|
||||
|
@ -2181,8 +2121,20 @@ WasmGlobalObject::finalize(FreeOp*, JSObject* obj)
|
|||
}
|
||||
|
||||
/* static */ WasmGlobalObject*
|
||||
WasmGlobalObject::create(JSContext* cx, HandleVal hval, bool isMutable)
|
||||
WasmGlobalObject::create(JSContext* cx, const Val& val, bool isMutable)
|
||||
{
|
||||
UniquePtr<Cell> cell = js::MakeUnique<Cell>();
|
||||
if (!cell)
|
||||
return nullptr;
|
||||
|
||||
switch (val.type().code()) {
|
||||
case ValType::I32: cell->i32 = val.i32(); break;
|
||||
case ValType::I64: cell->i64 = val.i64(); break;
|
||||
case ValType::F32: cell->f32 = val.f32(); break;
|
||||
case ValType::F64: cell->f64 = val.f64(); break;
|
||||
default: MOZ_CRASH();
|
||||
}
|
||||
|
||||
RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmGlobal).toObject());
|
||||
|
||||
AutoSetNewObjectMetadata metadata(cx);
|
||||
|
@ -2190,43 +2142,9 @@ WasmGlobalObject::create(JSContext* cx, HandleVal hval, bool isMutable)
|
|||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
MOZ_ASSERT(obj->isTenured(), "assumed by set_global post barriers");
|
||||
|
||||
// It's simpler to initialize the cell after the object has been created,
|
||||
// to avoid needing to root the cell before the object creation.
|
||||
|
||||
Cell* cell = js_new<Cell>();
|
||||
if (!cell)
|
||||
return nullptr;
|
||||
|
||||
const Val& val = hval.get();
|
||||
switch (val.type().code()) {
|
||||
case ValType::I32:
|
||||
cell->i32 = val.i32();
|
||||
break;
|
||||
case ValType::I64:
|
||||
cell->i64 = val.i64();
|
||||
break;
|
||||
case ValType::F32:
|
||||
cell->f32 = val.f32();
|
||||
break;
|
||||
case ValType::F64:
|
||||
cell->f64 = val.f64();
|
||||
break;
|
||||
case ValType::AnyRef:
|
||||
MOZ_ASSERT(!cell->ptr, "no prebarriers needed");
|
||||
cell->ptr = val.ptr();
|
||||
if (cell->ptr)
|
||||
JSObject::writeBarrierPost(&cell->ptr, nullptr, cell->ptr);
|
||||
break;
|
||||
WASM_CRASH_IF_SIMD_TYPES;
|
||||
case ValType::Ref:
|
||||
MOZ_CRASH("Ref NYI");
|
||||
}
|
||||
|
||||
obj->initReservedSlot(TYPE_SLOT, Int32Value(int32_t(val.type().bitsUnsafe())));
|
||||
obj->initReservedSlot(MUTABLE_SLOT, JS::BooleanValue(isMutable));
|
||||
obj->initReservedSlot(CELL_SLOT, PrivateValue(cell));
|
||||
obj->initReservedSlot(CELL_SLOT, PrivateValue(cell.release()));
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
@ -2272,10 +2190,6 @@ WasmGlobalObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
|||
globalType = ValType::F32;
|
||||
} else if (StringEqualsAscii(typeLinearStr, "f64")) {
|
||||
globalType = ValType::F64;
|
||||
#ifdef ENABLE_WASM_GC
|
||||
} else if (cx->options().wasmGc() && StringEqualsAscii(typeLinearStr, "anyref")) {
|
||||
globalType = ValType::AnyRef;
|
||||
#endif
|
||||
} else {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_GLOBAL_TYPE);
|
||||
return false;
|
||||
|
@ -2288,20 +2202,20 @@ WasmGlobalObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
|||
bool isMutable = ToBoolean(mutableVal);
|
||||
|
||||
// Extract the initial value, or provide a suitable default.
|
||||
RootedVal globalVal(cx);
|
||||
// Guard against control flow mistakes below failing to set |globalVal|.
|
||||
Val globalVal = Val(uint32_t(0));
|
||||
if (args.length() >= 2) {
|
||||
RootedValue valueVal(cx, args.get(1));
|
||||
|
||||
if (!ToWebAssemblyValue(cx, globalType, valueVal, &globalVal))
|
||||
return false;
|
||||
} else {
|
||||
switch (globalType.code()) {
|
||||
case ValType::I32: globalVal = Val(uint32_t(0)); break;
|
||||
case ValType::I64: globalVal = Val(uint64_t(0)); break;
|
||||
case ValType::F32: globalVal = Val(float(0.0)); break;
|
||||
case ValType::F64: globalVal = Val(double(0.0)); break;
|
||||
case ValType::AnyRef: globalVal = Val(nullptr); break;
|
||||
WASM_CRASH_IF_SIMD_TYPES;
|
||||
case ValType::Ref: MOZ_CRASH("Ref NYI");
|
||||
case ValType::I32: /* set above */ break;
|
||||
case ValType::I64: globalVal = Val(uint64_t(0)); break;
|
||||
case ValType::F32: globalVal = Val(float(0.0)); break;
|
||||
case ValType::F64: globalVal = Val(double(0.0)); break;
|
||||
default: MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2326,17 +2240,14 @@ WasmGlobalObject::valueGetterImpl(JSContext* cx, const CallArgs& args)
|
|||
case ValType::I32:
|
||||
case ValType::F32:
|
||||
case ValType::F64:
|
||||
case ValType::AnyRef:
|
||||
args.rval().set(args.thisv().toObject().as<WasmGlobalObject>().value(cx));
|
||||
args.rval().set(args.thisv().toObject().as<WasmGlobalObject>().value());
|
||||
return true;
|
||||
case ValType::I64:
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_I64_TYPE);
|
||||
return false;
|
||||
WASM_CRASH_IF_SIMD_TYPES;
|
||||
case ValType::Ref:
|
||||
MOZ_CRASH("Ref NYI");
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
|
@ -2360,34 +2271,16 @@ WasmGlobalObject::valueSetterImpl(JSContext* cx, const CallArgs& args)
|
|||
return false;
|
||||
}
|
||||
|
||||
RootedVal val(cx);
|
||||
Val val;
|
||||
if (!ToWebAssemblyValue(cx, global->type(), args.get(0), &val))
|
||||
return false;
|
||||
|
||||
Cell* cell = global->cell();
|
||||
switch (global->type().code()) {
|
||||
case ValType::I32:
|
||||
cell->i32 = val.get().i32();
|
||||
break;
|
||||
case ValType::F32:
|
||||
cell->f32 = val.get().f32();
|
||||
break;
|
||||
case ValType::F64:
|
||||
cell->f64 = val.get().f64();
|
||||
break;
|
||||
case ValType::AnyRef: {
|
||||
JSObject* prevPtr = cell->ptr;
|
||||
JSObject::writeBarrierPre(prevPtr);
|
||||
cell->ptr = val.get().ptr();
|
||||
if (cell->ptr)
|
||||
JSObject::writeBarrierPost(&cell->ptr, prevPtr, cell->ptr);
|
||||
break;
|
||||
}
|
||||
WASM_CRASH_IF_SIMD_TYPES;
|
||||
case ValType::I64:
|
||||
MOZ_CRASH("unexpected i64 when setting global's value");
|
||||
case ValType::Ref:
|
||||
MOZ_CRASH("Ref NYI");
|
||||
case ValType::I32: cell->i32 = val.i32(); break;
|
||||
case ValType::F32: cell->f32 = val.f32(); break;
|
||||
case ValType::F64: cell->f64 = val.f64(); break;
|
||||
default: MOZ_CRASH();
|
||||
}
|
||||
|
||||
args.rval().setUndefined();
|
||||
|
@ -2429,29 +2322,26 @@ WasmGlobalObject::isMutable() const
|
|||
return getReservedSlot(MUTABLE_SLOT).toBoolean();
|
||||
}
|
||||
|
||||
void
|
||||
WasmGlobalObject::val(MutableHandleVal outval) const
|
||||
Val
|
||||
WasmGlobalObject::val() const
|
||||
{
|
||||
Cell* cell = this->cell();
|
||||
Val val;
|
||||
switch (type().code()) {
|
||||
case ValType::I32: outval.set(Val(uint32_t(cell->i32))); return;
|
||||
case ValType::I64: outval.set(Val(uint64_t(cell->i64))); return;
|
||||
case ValType::F32: outval.set(Val(cell->f32)); return;
|
||||
case ValType::F64: outval.set(Val(cell->f64)); return;
|
||||
case ValType::AnyRef: outval.set(Val(cell->ptr)); return;
|
||||
WASM_CRASH_IF_SIMD_TYPES;
|
||||
case ValType::Ref: MOZ_CRASH("Ref NYI");
|
||||
case ValType::I32: val = Val(uint32_t(cell->i32)); break;
|
||||
case ValType::I64: val = Val(uint64_t(cell->i64)); break;
|
||||
case ValType::F32: val = Val(cell->f32); break;
|
||||
case ValType::F64: val = Val(cell->f64); break;
|
||||
default: MOZ_CRASH();
|
||||
}
|
||||
MOZ_CRASH("unexpected Global type");
|
||||
return val;
|
||||
}
|
||||
|
||||
Value
|
||||
WasmGlobalObject::value(JSContext* cx) const
|
||||
WasmGlobalObject::value() const
|
||||
{
|
||||
// ToJSValue crashes on I64; this is desirable.
|
||||
RootedVal result(cx);
|
||||
val(&result);
|
||||
return ToJSValue(result.get());
|
||||
return ToJSValue(val());
|
||||
}
|
||||
|
||||
WasmGlobalObject::Cell*
|
||||
|
|
|
@ -126,7 +126,6 @@ class WasmGlobalObject : public NativeObject
|
|||
|
||||
static const ClassOps classOps_;
|
||||
static void finalize(FreeOp*, JSObject* obj);
|
||||
static void trace(JSTracer* trc, JSObject* obj);
|
||||
|
||||
static bool valueGetterImpl(JSContext* cx, const CallArgs& args);
|
||||
static bool valueGetter(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
@ -137,13 +136,10 @@ class WasmGlobalObject : public NativeObject
|
|||
// For exposed globals the Cell holds the value of the global; the
|
||||
// instance's global area holds a pointer to the Cell.
|
||||
union Cell {
|
||||
int32_t i32;
|
||||
int64_t i64;
|
||||
float f32;
|
||||
double f64;
|
||||
JSObject* ptr;
|
||||
Cell() : i64(0) {}
|
||||
~Cell() {}
|
||||
int32_t i32;
|
||||
int64_t i64;
|
||||
float f32;
|
||||
double f64;
|
||||
};
|
||||
|
||||
static const unsigned RESERVED_SLOTS = 3;
|
||||
|
@ -153,13 +149,13 @@ class WasmGlobalObject : public NativeObject
|
|||
static const JSFunctionSpec static_methods[];
|
||||
static bool construct(JSContext*, unsigned, Value*);
|
||||
|
||||
static WasmGlobalObject* create(JSContext* cx, wasm::HandleVal value, bool isMutable);
|
||||
static WasmGlobalObject* create(JSContext* cx, const wasm::Val& value, bool isMutable);
|
||||
|
||||
wasm::ValType type() const;
|
||||
void val(wasm::MutableHandleVal outval) const;
|
||||
wasm::Val val() const;
|
||||
bool isMutable() const;
|
||||
// value() will MOZ_CRASH if the type is int64
|
||||
Value value(JSContext* cx) const;
|
||||
Value value() const;
|
||||
Cell* cell() const;
|
||||
};
|
||||
|
||||
|
@ -218,7 +214,7 @@ class WasmInstanceObject : public NativeObject
|
|||
Vector<RefPtr<wasm::Table>, 0, SystemAllocPolicy>&& tables,
|
||||
Handle<FunctionVector> funcImports,
|
||||
const wasm::GlobalDescVector& globals,
|
||||
wasm::HandleValVector globalImportValues,
|
||||
const wasm::ValVector& globalImportValues,
|
||||
const WasmGlobalObjectVector& globalObjs,
|
||||
HandleObject proto);
|
||||
void initExportsObj(JSObject& exportsObj);
|
||||
|
|
|
@ -721,13 +721,13 @@ Module::extractCode(JSContext* cx, Tier tier, MutableHandleValue vp) const
|
|||
}
|
||||
|
||||
static uint32_t
|
||||
EvaluateInitExpr(HandleValVector globalImportValues, InitExpr initExpr)
|
||||
EvaluateInitExpr(const ValVector& globalImportValues, InitExpr initExpr)
|
||||
{
|
||||
switch (initExpr.kind()) {
|
||||
case InitExpr::Kind::Constant:
|
||||
return initExpr.val().i32();
|
||||
case InitExpr::Kind::GetGlobal:
|
||||
return globalImportValues[initExpr.globalIndex()].get().i32();
|
||||
return globalImportValues[initExpr.globalIndex()].i32();
|
||||
}
|
||||
|
||||
MOZ_CRASH("bad initializer expression");
|
||||
|
@ -738,7 +738,7 @@ Module::initSegments(JSContext* cx,
|
|||
HandleWasmInstanceObject instanceObj,
|
||||
Handle<FunctionVector> funcImports,
|
||||
HandleWasmMemoryObject memoryObj,
|
||||
HandleValVector globalImportValues) const
|
||||
const ValVector& globalImportValues) const
|
||||
{
|
||||
Instance& instance = instanceObj->instance();
|
||||
const SharedTableVector& tables = instance.tables();
|
||||
|
@ -1010,44 +1010,38 @@ Module::instantiateTable(JSContext* cx, MutableHandleWasmTableObject tableObj,
|
|||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
ExtractGlobalValue(HandleValVector globalImportValues, uint32_t globalIndex,
|
||||
const GlobalDesc& global, MutableHandleVal result)
|
||||
static Val
|
||||
ExtractGlobalValue(const ValVector& globalImportValues, uint32_t globalIndex, const GlobalDesc& global)
|
||||
{
|
||||
switch (global.kind()) {
|
||||
case GlobalKind::Import: {
|
||||
result.set(Val(globalImportValues[globalIndex]));
|
||||
return;
|
||||
return globalImportValues[globalIndex];
|
||||
}
|
||||
case GlobalKind::Variable: {
|
||||
const InitExpr& init = global.initExpr();
|
||||
switch (init.kind()) {
|
||||
case InitExpr::Kind::Constant:
|
||||
result.set(Val(init.val()));
|
||||
return;
|
||||
return init.val();
|
||||
case InitExpr::Kind::GetGlobal:
|
||||
result.set(Val(globalImportValues[init.globalIndex()]));
|
||||
return;
|
||||
return globalImportValues[init.globalIndex()];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GlobalKind::Constant: {
|
||||
result.set(Val(global.constantValue()));
|
||||
return;
|
||||
return global.constantValue();
|
||||
}
|
||||
}
|
||||
MOZ_CRASH("Not a global value");
|
||||
}
|
||||
|
||||
static bool
|
||||
EnsureGlobalObject(JSContext* cx, HandleValVector globalImportValues, size_t globalIndex,
|
||||
EnsureGlobalObject(JSContext* cx, const ValVector& globalImportValues, size_t globalIndex,
|
||||
const GlobalDesc& global, WasmGlobalObjectVector& globalObjs)
|
||||
{
|
||||
if (globalIndex < globalObjs.length() && globalObjs[globalIndex])
|
||||
return true;
|
||||
|
||||
RootedVal val(cx);
|
||||
ExtractGlobalValue(globalImportValues, globalIndex, global, &val);
|
||||
Val val = ExtractGlobalValue(globalImportValues, globalIndex, global);
|
||||
RootedWasmGlobalObject go(cx, WasmGlobalObject::create(cx, val, global.isMutable()));
|
||||
if (!go)
|
||||
return false;
|
||||
|
@ -1062,7 +1056,7 @@ EnsureGlobalObject(JSContext* cx, HandleValVector globalImportValues, size_t glo
|
|||
}
|
||||
|
||||
bool
|
||||
Module::instantiateGlobals(JSContext* cx, HandleValVector globalImportValues,
|
||||
Module::instantiateGlobals(JSContext* cx, const ValVector& globalImportValues,
|
||||
WasmGlobalObjectVector& globalObjs) const
|
||||
{
|
||||
// If there are exported globals that aren't in globalObjs because they
|
||||
|
@ -1194,7 +1188,7 @@ Module::instantiate(JSContext* cx,
|
|||
Handle<FunctionVector> funcImports,
|
||||
HandleWasmTableObject tableImport,
|
||||
HandleWasmMemoryObject memoryImport,
|
||||
HandleValVector globalImportValues,
|
||||
const ValVector& globalImportValues,
|
||||
WasmGlobalObjectVector& globalObjs,
|
||||
HandleObject instanceProto,
|
||||
MutableHandleWasmInstanceObject instance) const
|
||||
|
|
|
@ -151,13 +151,13 @@ class Module : public JS::WasmModule
|
|||
bool instantiateTable(JSContext* cx,
|
||||
MutableHandleWasmTableObject table,
|
||||
SharedTableVector* tables) const;
|
||||
bool instantiateGlobals(JSContext* cx, HandleValVector globalImportValues,
|
||||
bool instantiateGlobals(JSContext* cx, const ValVector& globalImportValues,
|
||||
WasmGlobalObjectVector& globalObjs) const;
|
||||
bool initSegments(JSContext* cx,
|
||||
HandleWasmInstanceObject instance,
|
||||
Handle<FunctionVector> funcImports,
|
||||
HandleWasmMemoryObject memory,
|
||||
HandleValVector globalImportValues) const;
|
||||
const ValVector& globalImportValues) const;
|
||||
|
||||
class Tier2GeneratorTaskImpl;
|
||||
void notifyCompilationListeners();
|
||||
|
@ -207,7 +207,7 @@ class Module : public JS::WasmModule
|
|||
Handle<FunctionVector> funcImports,
|
||||
HandleWasmTableObject tableImport,
|
||||
HandleWasmMemoryObject memoryImport,
|
||||
HandleValVector globalImportValues,
|
||||
const ValVector& globalImportValues,
|
||||
WasmGlobalObjectVector& globalObjs,
|
||||
HandleObject instanceProto,
|
||||
MutableHandleWasmInstanceObject instanceObj) const;
|
||||
|
|
|
@ -2115,7 +2115,7 @@ ParseNaNLiteral(WasmParseContext& c, WasmToken token, const char16_t* cur, bool
|
|||
|
||||
Float flt;
|
||||
BitwiseCast(value, &flt);
|
||||
return new (c.lifo) AstConst(LitVal(flt));
|
||||
return new (c.lifo) AstConst(Val(flt));
|
||||
|
||||
error:
|
||||
c.ts.generateError(token, c.error);
|
||||
|
@ -2267,7 +2267,7 @@ ParseFloatLiteral(WasmParseContext& c, WasmToken token)
|
|||
}
|
||||
|
||||
if (token.kind() != WasmToken::Float)
|
||||
return new (c.lifo) AstConst(LitVal(Float(result)));
|
||||
return new (c.lifo) AstConst(Val(Float(result)));
|
||||
|
||||
const char16_t* begin = token.begin();
|
||||
const char16_t* end = token.end();
|
||||
|
@ -2317,7 +2317,7 @@ ParseFloatLiteral(WasmParseContext& c, WasmToken token)
|
|||
if (isNegated)
|
||||
result = -result;
|
||||
|
||||
return new (c.lifo) AstConst(LitVal(Float(result)));
|
||||
return new (c.lifo) AstConst(Val(Float(result)));
|
||||
}
|
||||
|
||||
static AstConst*
|
||||
|
@ -2328,15 +2328,15 @@ ParseConst(WasmParseContext& c, WasmToken constToken)
|
|||
case ValType::I32: {
|
||||
switch (val.kind()) {
|
||||
case WasmToken::Index:
|
||||
return new(c.lifo) AstConst(LitVal(val.index()));
|
||||
return new(c.lifo) AstConst(Val(val.index()));
|
||||
case WasmToken::SignedInteger: {
|
||||
CheckedInt<int32_t> sint = val.sint();
|
||||
if (!sint.isValid())
|
||||
break;
|
||||
return new(c.lifo) AstConst(LitVal(uint32_t(sint.value())));
|
||||
return new(c.lifo) AstConst(Val(uint32_t(sint.value())));
|
||||
}
|
||||
case WasmToken::NegativeZero:
|
||||
return new(c.lifo) AstConst(LitVal(uint32_t(0)));
|
||||
return new(c.lifo) AstConst(Val(uint32_t(0)));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -2345,13 +2345,13 @@ ParseConst(WasmParseContext& c, WasmToken constToken)
|
|||
case ValType::I64: {
|
||||
switch (val.kind()) {
|
||||
case WasmToken::Index:
|
||||
return new(c.lifo) AstConst(LitVal(uint64_t(val.index())));
|
||||
return new(c.lifo) AstConst(Val(uint64_t(val.index())));
|
||||
case WasmToken::UnsignedInteger:
|
||||
return new(c.lifo) AstConst(LitVal(val.uint()));
|
||||
return new(c.lifo) AstConst(Val(val.uint()));
|
||||
case WasmToken::SignedInteger:
|
||||
return new(c.lifo) AstConst(LitVal(uint64_t(val.sint())));
|
||||
return new(c.lifo) AstConst(Val(uint64_t(val.sint())));
|
||||
case WasmToken::NegativeZero:
|
||||
return new(c.lifo) AstConst(LitVal(uint64_t(0)));
|
||||
return new(c.lifo) AstConst(Val(uint64_t(0)));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -3594,7 +3594,7 @@ ParseMemory(WasmParseContext& c, AstModule* module)
|
|||
}
|
||||
|
||||
if (fragments.length()) {
|
||||
AstExpr* offset = new(c.lifo) AstConst(LitVal(uint32_t(0)));
|
||||
AstExpr* offset = new(c.lifo) AstConst(Val(uint32_t(0)));
|
||||
if (!offset)
|
||||
return false;
|
||||
|
||||
|
@ -3914,7 +3914,7 @@ ParseTable(WasmParseContext& c, WasmToken token, AstModule* module)
|
|||
if (!module->addTable(name, Limits(numElements, Some(numElements), Shareable::False)))
|
||||
return false;
|
||||
|
||||
auto* zero = new(c.lifo) AstConst(LitVal(uint32_t(0)));
|
||||
auto* zero = new(c.lifo) AstConst(Val(uint32_t(0)));
|
||||
if (!zero)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -60,27 +60,6 @@ static_assert(MaxMemoryAccessSize <= 64, "MaxMemoryAccessSize too high");
|
|||
static_assert((MaxMemoryAccessSize & (MaxMemoryAccessSize-1)) == 0,
|
||||
"MaxMemoryAccessSize is not a power of two");
|
||||
|
||||
Val::Val(const LitVal& val)
|
||||
{
|
||||
type_ = val.type();
|
||||
switch (type_.code()) {
|
||||
case ValType::I32: u.i32_ = val.i32(); return;
|
||||
case ValType::F32: u.f32_ = val.f32(); return;
|
||||
case ValType::I64: u.i64_ = val.i64(); return;
|
||||
case ValType::F64: u.f64_ = val.f64(); return;
|
||||
case ValType::I8x16:
|
||||
case ValType::B8x16:
|
||||
case ValType::I16x8:
|
||||
case ValType::B16x8:
|
||||
case ValType::I32x4:
|
||||
case ValType::F32x4:
|
||||
case ValType::B32x4: memcpy(&u, val.rawSimd(), jit::Simd128DataSize); return;
|
||||
case ValType::AnyRef: u.ptr_ = val.ptr(); return;
|
||||
case ValType::Ref: break;
|
||||
}
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
void
|
||||
Val::writePayload(uint8_t* dst) const
|
||||
{
|
||||
|
@ -104,27 +83,9 @@ Val::writePayload(uint8_t* dst) const
|
|||
return;
|
||||
case ValType::Ref:
|
||||
case ValType::AnyRef:
|
||||
MOZ_ASSERT(*(JSObject**)dst == nullptr, "should be null so no need for a pre-barrier");
|
||||
memcpy(dst, &u.ptr_, sizeof(JSObject*));
|
||||
// Either the written location is in the global data section in the
|
||||
// WasmInstanceObject, or the Cell of a WasmGlobalObject:
|
||||
// - WasmInstanceObjects are always tenured and u.ptr_ may point to a
|
||||
// nursery object, so we need a post-barrier since the global data of
|
||||
// an instance is effectively a field of the WasmInstanceObject.
|
||||
// - WasmGlobalObjects are always tenured, and they have a Cell field,
|
||||
// so a post-barrier may be needed for the same reason as above.
|
||||
if (u.ptr_)
|
||||
JSObject::writeBarrierPost((JSObject**)dst, nullptr, u.ptr_);
|
||||
return;
|
||||
// TODO
|
||||
MOZ_CRASH("writing imported value of Ref/AnyRef in global NYI");
|
||||
}
|
||||
MOZ_CRASH("unexpected Val type");
|
||||
}
|
||||
|
||||
void
|
||||
Val::trace(JSTracer* trc)
|
||||
{
|
||||
if (type_ == ValType::AnyRef && u.ptr_)
|
||||
TraceManuallyBarrieredEdge(trc, &u.ptr_, "wasm anyref global");
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -507,7 +507,7 @@ SizeOf(ValType vt)
|
|||
return 16;
|
||||
case ValType::AnyRef:
|
||||
case ValType::Ref:
|
||||
return sizeof(intptr_t);
|
||||
MOZ_CRASH("unexpected ref/anyref");
|
||||
}
|
||||
MOZ_CRASH("Invalid ValType");
|
||||
}
|
||||
|
@ -766,57 +766,49 @@ enum class HasGcTypes
|
|||
True
|
||||
};
|
||||
|
||||
// The LitVal class represents a single WebAssembly value of a given value
|
||||
// type, mostly for the purpose of numeric literals and initializers. A LitVal
|
||||
// does not directly map to a JS value since there is not (currently) a precise
|
||||
// representation of i64 values. A LitVal may contain non-canonical NaNs since,
|
||||
// The Val class represents a single WebAssembly value of a given value type,
|
||||
// mostly for the purpose of numeric literals and initializers. A Val does not
|
||||
// directly map to a JS value since there is not (currently) a precise
|
||||
// representation of i64 values. A Val may contain non-canonical NaNs since,
|
||||
// within WebAssembly, floats are not canonicalized. Canonicalization must
|
||||
// happen at the JS boundary.
|
||||
|
||||
class LitVal
|
||||
class Val
|
||||
{
|
||||
protected:
|
||||
ValType type_;
|
||||
union U {
|
||||
uint32_t i32_;
|
||||
uint64_t i64_;
|
||||
float f32_;
|
||||
double f64_;
|
||||
I8x16 i8x16_;
|
||||
I16x8 i16x8_;
|
||||
I32x4 i32x4_;
|
||||
F32x4 f32x4_;
|
||||
JSObject* ptr_;
|
||||
uint32_t i32_;
|
||||
uint64_t i64_;
|
||||
float f32_;
|
||||
double f64_;
|
||||
I8x16 i8x16_;
|
||||
I16x8 i16x8_;
|
||||
I32x4 i32x4_;
|
||||
F32x4 f32x4_;
|
||||
} u;
|
||||
|
||||
public:
|
||||
LitVal() : type_(), u{} {}
|
||||
Val() = default;
|
||||
|
||||
explicit LitVal(uint32_t i32) : type_(ValType::I32) { u.i32_ = i32; }
|
||||
explicit LitVal(uint64_t i64) : type_(ValType::I64) { u.i64_ = i64; }
|
||||
explicit Val(uint32_t i32) : type_(ValType::I32) { u.i32_ = i32; }
|
||||
explicit Val(uint64_t i64) : type_(ValType::I64) { u.i64_ = i64; }
|
||||
|
||||
explicit LitVal(float f32) : type_(ValType::F32) { u.f32_ = f32; }
|
||||
explicit LitVal(double f64) : type_(ValType::F64) { u.f64_ = f64; }
|
||||
explicit Val(float f32) : type_(ValType::F32) { u.f32_ = f32; }
|
||||
explicit Val(double f64) : type_(ValType::F64) { u.f64_ = f64; }
|
||||
|
||||
explicit LitVal(ValType refType, JSObject* ptr) : type_(refType) {
|
||||
MOZ_ASSERT(refType.isRefOrAnyRef());
|
||||
MOZ_ASSERT(ptr == nullptr, "use Val for non-nullptr ref types to get tracing");
|
||||
u.ptr_ = ptr;
|
||||
}
|
||||
|
||||
explicit LitVal(const I8x16& i8x16, ValType type = ValType::I8x16) : type_(type) {
|
||||
explicit Val(const I8x16& i8x16, ValType type = ValType::I8x16) : type_(type) {
|
||||
MOZ_ASSERT(type_ == ValType::I8x16 || type_ == ValType::B8x16);
|
||||
memcpy(u.i8x16_, i8x16, sizeof(u.i8x16_));
|
||||
}
|
||||
explicit LitVal(const I16x8& i16x8, ValType type = ValType::I16x8) : type_(type) {
|
||||
explicit Val(const I16x8& i16x8, ValType type = ValType::I16x8) : type_(type) {
|
||||
MOZ_ASSERT(type_ == ValType::I16x8 || type_ == ValType::B16x8);
|
||||
memcpy(u.i16x8_, i16x8, sizeof(u.i16x8_));
|
||||
}
|
||||
explicit LitVal(const I32x4& i32x4, ValType type = ValType::I32x4) : type_(type) {
|
||||
explicit Val(const I32x4& i32x4, ValType type = ValType::I32x4) : type_(type) {
|
||||
MOZ_ASSERT(type_ == ValType::I32x4 || type_ == ValType::B32x4);
|
||||
memcpy(u.i32x4_, i32x4, sizeof(u.i32x4_));
|
||||
}
|
||||
explicit LitVal(const F32x4& f32x4) : type_(ValType::F32x4) {
|
||||
explicit Val(const F32x4& f32x4) : type_(ValType::F32x4) {
|
||||
memcpy(u.f32x4_, f32x4, sizeof(u.f32x4_));
|
||||
}
|
||||
|
||||
|
@ -828,7 +820,6 @@ class LitVal
|
|||
uint64_t i64() const { MOZ_ASSERT(type_ == ValType::I64); return u.i64_; }
|
||||
const float& f32() const { MOZ_ASSERT(type_ == ValType::F32); return u.f32_; }
|
||||
const double& f64() const { MOZ_ASSERT(type_ == ValType::F64); return u.f64_; }
|
||||
JSObject* ptr() const { MOZ_ASSERT(type_.isRefOrAnyRef()); return u.ptr_; }
|
||||
|
||||
const I8x16& i8x16() const {
|
||||
MOZ_ASSERT(type_ == ValType::I8x16 || type_ == ValType::B8x16);
|
||||
|
@ -846,40 +837,11 @@ class LitVal
|
|||
MOZ_ASSERT(type_ == ValType::F32x4);
|
||||
return u.f32x4_;
|
||||
}
|
||||
// To be used only by Val.
|
||||
const void* rawSimd() const { return &u.i32x4_; }
|
||||
};
|
||||
|
||||
typedef Vector<LitVal, 0, SystemAllocPolicy> LitValVector;
|
||||
|
||||
// A Val is a LitVal that can contain pointers to JSObjects, thanks to their
|
||||
// trace implementation. Since a Val is able to store a pointer to a JSObject,
|
||||
// it needs to be traced during compilation in case the pointee is moved.
|
||||
// The classic shorthands for Rooted things are defined after this class, for
|
||||
// easier usage.
|
||||
|
||||
class MOZ_NON_PARAM Val : public LitVal
|
||||
{
|
||||
public:
|
||||
Val() : LitVal() {}
|
||||
explicit Val(const LitVal& val);
|
||||
explicit Val(uint32_t i32) : LitVal(i32) {}
|
||||
explicit Val(uint64_t i64) : LitVal(i64) {}
|
||||
explicit Val(float f32) : LitVal(f32) {}
|
||||
explicit Val(double f64) : LitVal(f64) {}
|
||||
explicit Val(JSObject* obj) : LitVal(ValType::AnyRef, nullptr) { u.ptr_ = obj; }
|
||||
void writePayload(uint8_t* dst) const;
|
||||
void trace(JSTracer* trc);
|
||||
};
|
||||
|
||||
typedef Rooted<Val> RootedVal;
|
||||
typedef Handle<Val> HandleVal;
|
||||
typedef MutableHandle<Val> MutableHandleVal;
|
||||
|
||||
typedef GCVector<Val, 0, SystemAllocPolicy> GCVectorVal;
|
||||
typedef Rooted<GCVectorVal> RootedValVector;
|
||||
typedef Handle<GCVectorVal> HandleValVector;
|
||||
typedef MutableHandle<GCVectorVal> MutableHandleValVector;
|
||||
typedef Vector<Val, 0, SystemAllocPolicy> ValVector;
|
||||
|
||||
// The FuncType class represents a WebAssembly function signature which takes a
|
||||
// list of value types and returns an expression type. The engine uses two
|
||||
|
@ -1001,7 +963,7 @@ class InitExpr
|
|||
private:
|
||||
Kind kind_;
|
||||
union U {
|
||||
LitVal val_;
|
||||
Val val_;
|
||||
struct {
|
||||
uint32_t index_;
|
||||
ValType type_;
|
||||
|
@ -1012,7 +974,7 @@ class InitExpr
|
|||
public:
|
||||
InitExpr() = default;
|
||||
|
||||
explicit InitExpr(LitVal val) : kind_(Kind::Constant) {
|
||||
explicit InitExpr(Val val) : kind_(Kind::Constant) {
|
||||
u.val_ = val;
|
||||
}
|
||||
|
||||
|
@ -1024,13 +986,13 @@ class InitExpr
|
|||
Kind kind() const { return kind_; }
|
||||
|
||||
bool isVal() const { return kind() == Kind::Constant; }
|
||||
LitVal val() const { MOZ_ASSERT(isVal()); return u.val_; }
|
||||
Val val() const { MOZ_ASSERT(isVal()); return u.val_; }
|
||||
|
||||
uint32_t globalIndex() const { MOZ_ASSERT(kind() == Kind::GetGlobal); return u.global.index_; }
|
||||
|
||||
ValType type() const {
|
||||
switch (kind()) {
|
||||
case Kind::Constant: return u.val_.type();
|
||||
case Kind::Constant: return u.val_.type();
|
||||
case Kind::GetGlobal: return u.global.type_;
|
||||
}
|
||||
MOZ_CRASH("unexpected initExpr type");
|
||||
|
@ -1136,7 +1098,7 @@ class GlobalDesc
|
|||
bool isWasm_;
|
||||
bool isExport_;
|
||||
} var;
|
||||
LitVal cst_;
|
||||
Val cst_;
|
||||
V() {}
|
||||
} u;
|
||||
GlobalKind kind_;
|
||||
|
@ -1163,8 +1125,7 @@ class GlobalDesc
|
|||
}
|
||||
}
|
||||
|
||||
explicit GlobalDesc(ValType type, bool isMutable, uint32_t importIndex,
|
||||
ModuleKind kind = ModuleKind::Wasm)
|
||||
explicit GlobalDesc(ValType type, bool isMutable, uint32_t importIndex, ModuleKind kind = ModuleKind::Wasm)
|
||||
: kind_(GlobalKind::Import)
|
||||
{
|
||||
u.var.val.import.type_ = type;
|
||||
|
@ -1197,7 +1158,7 @@ class GlobalDesc
|
|||
bool isImport() const { return kind_ == GlobalKind::Import; }
|
||||
|
||||
bool isMutable() const { return !isConstant() && u.var.isMutable_; }
|
||||
LitVal constantValue() const { MOZ_ASSERT(isConstant()); return u.cst_; }
|
||||
Val constantValue() const { MOZ_ASSERT(isConstant()); return u.cst_; }
|
||||
const InitExpr& initExpr() const { MOZ_ASSERT(isVariable()); return u.var.val.initial_; }
|
||||
uint32_t importIndex() const { MOZ_ASSERT(isImport()); return u.var.val.import.index_; }
|
||||
|
||||
|
@ -1981,7 +1942,6 @@ enum class SymbolicAddress
|
|||
Wake,
|
||||
MemCopy,
|
||||
MemFill,
|
||||
PostBarrier,
|
||||
#if defined(JS_CODEGEN_MIPS32)
|
||||
js_jit_gAtomic64Lock,
|
||||
#endif
|
||||
|
@ -2103,10 +2063,6 @@ struct TlsData
|
|||
// Set to 1 when wasm should call CheckForInterrupt.
|
||||
Atomic<uint32_t, mozilla::Relaxed> interrupt;
|
||||
|
||||
#ifdef ENABLE_WASM_GC
|
||||
uint8_t* addressOfNeedsIncrementalBarrier;
|
||||
#endif
|
||||
|
||||
// Methods to set, test and clear the above two fields. Both interrupt
|
||||
// fields are Relaxed and so no consistency/ordering can be assumed.
|
||||
void setInterrupt();
|
||||
|
@ -2359,7 +2315,7 @@ static const unsigned PageSize = 64 * 1024;
|
|||
// catch the overflow. MaxMemoryAccessSize is a conservative approximation of
|
||||
// the maximum guard space needed to catch all unaligned overflows.
|
||||
|
||||
static const unsigned MaxMemoryAccessSize = LitVal::sizeofLargestValue();
|
||||
static const unsigned MaxMemoryAccessSize = Val::sizeofLargestValue();
|
||||
|
||||
#ifdef WASM_HUGE_MEMORY
|
||||
|
||||
|
@ -2563,48 +2519,6 @@ class DebugFrame
|
|||
static void alignmentStaticAsserts();
|
||||
};
|
||||
|
||||
# ifdef ENABLE_WASM_GC
|
||||
// A packed format for an argument to the Instance::postBarrier function.
|
||||
class PostBarrierArg
|
||||
{
|
||||
public:
|
||||
enum class Type {
|
||||
Global = 0x0,
|
||||
Last = Global
|
||||
};
|
||||
|
||||
private:
|
||||
uint32_t type_: 1;
|
||||
uint32_t payload_: 31;
|
||||
|
||||
PostBarrierArg(uint32_t payload, Type type)
|
||||
: type_(uint32_t(type)),
|
||||
payload_(payload)
|
||||
{
|
||||
MOZ_ASSERT(payload < (UINT32_MAX >> 1));
|
||||
MOZ_ASSERT(uint32_t(type) <= uint32_t(Type::Last));
|
||||
}
|
||||
|
||||
public:
|
||||
static PostBarrierArg Global(uint32_t globalIndex) {
|
||||
return PostBarrierArg(globalIndex, Type::Global);
|
||||
}
|
||||
|
||||
Type type() const {
|
||||
MOZ_ASSERT(type_ <= uint32_t(Type::Last));
|
||||
return Type(type_);
|
||||
}
|
||||
uint32_t globalIndex() const {
|
||||
MOZ_ASSERT(type() == Type::Global);
|
||||
return payload_;
|
||||
}
|
||||
|
||||
uint32_t rawPayload() const {
|
||||
return (payload_ << 1) | type_;
|
||||
}
|
||||
};
|
||||
# endif
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace js
|
||||
|
||||
|
|
|
@ -1398,7 +1398,6 @@ GlobalIsJSCompatible(Decoder& d, ValType type, bool isMutable)
|
|||
case ValType::F32:
|
||||
case ValType::F64:
|
||||
case ValType::I64:
|
||||
case ValType::AnyRef:
|
||||
break;
|
||||
default:
|
||||
return d.fail("unexpected variable type in global import/export");
|
||||
|
@ -1408,10 +1407,10 @@ GlobalIsJSCompatible(Decoder& d, ValType type, bool isMutable)
|
|||
}
|
||||
|
||||
static bool
|
||||
DecodeGlobalType(Decoder& d, const TypeDefVector& types, HasGcTypes gcTypesEnabled, ValType* type,
|
||||
bool* isMutable)
|
||||
DecodeGlobalType(Decoder& d, const TypeDefVector& types, ValType* type, bool* isMutable)
|
||||
{
|
||||
if (!DecodeValType(d, ModuleKind::Wasm, types.length(), gcTypesEnabled, type))
|
||||
// No gc types in globals at the moment.
|
||||
if (!DecodeValType(d, ModuleKind::Wasm, types.length(), HasGcTypes::False, type))
|
||||
return false;
|
||||
if (!ValidateRefType(d, types, *type))
|
||||
return false;
|
||||
|
@ -1510,7 +1509,7 @@ DecodeImport(Decoder& d, ModuleEnvironment* env)
|
|||
case DefinitionKind::Global: {
|
||||
ValType type;
|
||||
bool isMutable;
|
||||
if (!DecodeGlobalType(d, env->types, env->gcTypesEnabled, &type, &isMutable))
|
||||
if (!DecodeGlobalType(d, env->types, &type, &isMutable))
|
||||
return false;
|
||||
if (!GlobalIsJSCompatible(d, type, isMutable))
|
||||
return false;
|
||||
|
@ -1638,8 +1637,8 @@ DecodeMemorySection(Decoder& d, ModuleEnvironment* env)
|
|||
}
|
||||
|
||||
static bool
|
||||
DecodeInitializerExpression(Decoder& d, HasGcTypes gcTypesEnabled, const GlobalDescVector& globals,
|
||||
ValType expected, InitExpr* init)
|
||||
DecodeInitializerExpression(Decoder& d, const GlobalDescVector& globals, ValType expected,
|
||||
InitExpr* init)
|
||||
{
|
||||
OpBytes op;
|
||||
if (!d.readOp(&op))
|
||||
|
@ -1650,40 +1649,28 @@ DecodeInitializerExpression(Decoder& d, HasGcTypes gcTypesEnabled, const GlobalD
|
|||
int32_t i32;
|
||||
if (!d.readVarS32(&i32))
|
||||
return d.fail("failed to read initializer i32 expression");
|
||||
*init = InitExpr(LitVal(uint32_t(i32)));
|
||||
*init = InitExpr(Val(uint32_t(i32)));
|
||||
break;
|
||||
}
|
||||
case uint16_t(Op::I64Const): {
|
||||
int64_t i64;
|
||||
if (!d.readVarS64(&i64))
|
||||
return d.fail("failed to read initializer i64 expression");
|
||||
*init = InitExpr(LitVal(uint64_t(i64)));
|
||||
*init = InitExpr(Val(uint64_t(i64)));
|
||||
break;
|
||||
}
|
||||
case uint16_t(Op::F32Const): {
|
||||
float f32;
|
||||
if (!d.readFixedF32(&f32))
|
||||
return d.fail("failed to read initializer f32 expression");
|
||||
*init = InitExpr(LitVal(f32));
|
||||
*init = InitExpr(Val(f32));
|
||||
break;
|
||||
}
|
||||
case uint16_t(Op::F64Const): {
|
||||
double f64;
|
||||
if (!d.readFixedF64(&f64))
|
||||
return d.fail("failed to read initializer f64 expression");
|
||||
*init = InitExpr(LitVal(f64));
|
||||
break;
|
||||
}
|
||||
case uint16_t(Op::RefNull): {
|
||||
if (gcTypesEnabled == HasGcTypes::False)
|
||||
return d.fail("unexpected initializer expression");
|
||||
uint8_t valType;
|
||||
uint32_t unusedRefTypeIndex;
|
||||
if (!d.readValType(&valType, &unusedRefTypeIndex))
|
||||
return false;
|
||||
if (valType != uint8_t(ValType::AnyRef))
|
||||
return d.fail("expected anyref as type for ref.null");
|
||||
*init = InitExpr(LitVal(ValType::AnyRef, nullptr));
|
||||
*init = InitExpr(Val(f64));
|
||||
break;
|
||||
}
|
||||
case uint16_t(Op::GetGlobal): {
|
||||
|
@ -1736,11 +1723,11 @@ DecodeGlobalSection(Decoder& d, ModuleEnvironment* env)
|
|||
for (uint32_t i = 0; i < numDefs; i++) {
|
||||
ValType type;
|
||||
bool isMutable;
|
||||
if (!DecodeGlobalType(d, env->types, env->gcTypesEnabled, &type, &isMutable))
|
||||
if (!DecodeGlobalType(d, env->types, &type, &isMutable))
|
||||
return false;
|
||||
|
||||
InitExpr initializer;
|
||||
if (!DecodeInitializerExpression(d, env->gcTypesEnabled, env->globals, type, &initializer))
|
||||
if (!DecodeInitializerExpression(d, env->globals, type, &initializer))
|
||||
return false;
|
||||
|
||||
env->globals.infallibleAppend(GlobalDesc(initializer, isMutable));
|
||||
|
@ -1921,8 +1908,7 @@ DecodeElemSection(Decoder& d, ModuleEnvironment* env)
|
|||
return d.fail("table index out of range");
|
||||
|
||||
InitExpr offset;
|
||||
if (!DecodeInitializerExpression(d, env->gcTypesEnabled, env->globals, ValType::I32,
|
||||
&offset))
|
||||
if (!DecodeInitializerExpression(d, env->globals, ValType::I32, &offset))
|
||||
return false;
|
||||
|
||||
uint32_t numElems;
|
||||
|
@ -2092,8 +2078,7 @@ DecodeDataSection(Decoder& d, ModuleEnvironment* env)
|
|||
return d.fail("data segment requires a memory section");
|
||||
|
||||
DataSegment seg;
|
||||
if (!DecodeInitializerExpression(d, env->gcTypesEnabled, env->globals, ValType::I32,
|
||||
&seg.offset))
|
||||
if (!DecodeInitializerExpression(d, env->globals, ValType::I32, &seg.offset))
|
||||
return false;
|
||||
|
||||
if (!d.readVarU32(&seg.length))
|
||||
|
|
Загрузка…
Ссылка в новой задаче