mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-26 19:55:39 +00:00
Bug 1450261: Implement Val, a rooted LitVal; r=luke, r=jonco
--HG-- extra : rebase_source : 010cd8dafd03402487cc80f30ff67a607895fe75
This commit is contained in:
parent
29f287f4d4
commit
f82eacce97
@ -9,6 +9,6 @@
|
||||
"MSAN_OPTIONS": "external_symbolizer_path={TOOLTOOL_CHECKOUT}/clang/bin/llvm-symbolizer:log_path={OUTDIR}/sanitize_log"
|
||||
},
|
||||
"ignore-test-failures": "true",
|
||||
"max-errors": 6,
|
||||
"max-errors": 7,
|
||||
"use_minidump": false
|
||||
}
|
||||
|
14
js/src/jit-test/tests/wasm/gc/anyref-val-tracing.js
Normal file
14
js/src/jit-test/tests/wasm/gc/anyref-val-tracing.js
Normal file
@ -0,0 +1,14 @@
|
||||
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");
|
@ -7671,11 +7671,12 @@ HasPureCoercion(JSContext* cx, HandleValue v)
|
||||
}
|
||||
|
||||
static bool
|
||||
ValidateGlobalVariable(JSContext* cx, const AsmJSGlobal& global, HandleValue importVal, LitVal* val)
|
||||
ValidateGlobalVariable(JSContext* cx, const AsmJSGlobal& global, HandleValue importVal,
|
||||
Maybe<LitVal>* val)
|
||||
{
|
||||
switch (global.varInitKind()) {
|
||||
case AsmJSGlobal::InitConstant:
|
||||
*val = global.varInitVal();
|
||||
val->emplace(global.varInitVal());
|
||||
return true;
|
||||
|
||||
case AsmJSGlobal::InitImport: {
|
||||
@ -7691,7 +7692,7 @@ ValidateGlobalVariable(JSContext* cx, const AsmJSGlobal& global, HandleValue imp
|
||||
int32_t i32;
|
||||
if (!ToInt32(cx, v, &i32))
|
||||
return false;
|
||||
*val = LitVal(uint32_t(i32));
|
||||
val->emplace(uint32_t(i32));
|
||||
return true;
|
||||
}
|
||||
case ValType::I64:
|
||||
@ -7700,42 +7701,42 @@ ValidateGlobalVariable(JSContext* cx, const AsmJSGlobal& global, HandleValue imp
|
||||
float f;
|
||||
if (!RoundFloat32(cx, v, &f))
|
||||
return false;
|
||||
*val = LitVal(f);
|
||||
val->emplace(f);
|
||||
return true;
|
||||
}
|
||||
case ValType::F64: {
|
||||
double d;
|
||||
if (!ToNumber(cx, v, &d))
|
||||
return false;
|
||||
*val = LitVal(d);
|
||||
val->emplace(d);
|
||||
return true;
|
||||
}
|
||||
case ValType::I8x16: {
|
||||
SimdConstant simdConstant;
|
||||
if (!ToSimdConstant<Int8x16>(cx, v, &simdConstant))
|
||||
return false;
|
||||
*val = LitVal(simdConstant.asInt8x16());
|
||||
val->emplace(simdConstant.asInt8x16());
|
||||
return true;
|
||||
}
|
||||
case ValType::I16x8: {
|
||||
SimdConstant simdConstant;
|
||||
if (!ToSimdConstant<Int16x8>(cx, v, &simdConstant))
|
||||
return false;
|
||||
*val = LitVal(simdConstant.asInt16x8());
|
||||
val->emplace(simdConstant.asInt16x8());
|
||||
return true;
|
||||
}
|
||||
case ValType::I32x4: {
|
||||
SimdConstant simdConstant;
|
||||
if (!ToSimdConstant<Int32x4>(cx, v, &simdConstant))
|
||||
return false;
|
||||
*val = LitVal(simdConstant.asInt32x4());
|
||||
val->emplace(simdConstant.asInt32x4());
|
||||
return true;
|
||||
}
|
||||
case ValType::F32x4: {
|
||||
SimdConstant simdConstant;
|
||||
if (!ToSimdConstant<Float32x4>(cx, v, &simdConstant))
|
||||
return false;
|
||||
*val = LitVal(simdConstant.asFloat32x4());
|
||||
val->emplace(simdConstant.asFloat32x4());
|
||||
return true;
|
||||
}
|
||||
case ValType::B8x16: {
|
||||
@ -7743,7 +7744,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 = LitVal(simdConstant.asInt8x16());
|
||||
val->emplace(simdConstant.asInt8x16());
|
||||
return true;
|
||||
}
|
||||
case ValType::B16x8: {
|
||||
@ -7751,7 +7752,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 = LitVal(simdConstant.asInt16x8());
|
||||
val->emplace(simdConstant.asInt16x8());
|
||||
return true;
|
||||
}
|
||||
case ValType::B32x4: {
|
||||
@ -7759,7 +7760,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 = LitVal(simdConstant.asInt32x4());
|
||||
val->emplace(simdConstant.asInt32x4());
|
||||
return true;
|
||||
}
|
||||
case ValType::Ref:
|
||||
@ -8134,7 +8135,7 @@ CheckBuffer(JSContext* cx, const AsmJSMetadata& metadata, HandleValue bufferVal,
|
||||
static bool
|
||||
GetImports(JSContext* cx, const AsmJSMetadata& metadata, HandleValue globalVal,
|
||||
HandleValue importVal, MutableHandle<FunctionVector> funcImports,
|
||||
LitValVector* valImports)
|
||||
MutableHandleValVector valImports)
|
||||
{
|
||||
Rooted<FunctionVector> ffis(cx, FunctionVector(cx));
|
||||
if (!ffis.resize(metadata.numFFIs))
|
||||
@ -8143,10 +8144,10 @@ GetImports(JSContext* cx, const AsmJSMetadata& metadata, HandleValue globalVal,
|
||||
for (const AsmJSGlobal& global : metadata.asmJSGlobals) {
|
||||
switch (global.which()) {
|
||||
case AsmJSGlobal::Variable: {
|
||||
LitVal val;
|
||||
if (!ValidateGlobalVariable(cx, global, importVal, &val))
|
||||
Maybe<LitVal> litVal;
|
||||
if (!ValidateGlobalVariable(cx, global, importVal, &litVal))
|
||||
return false;
|
||||
if (!valImports->append(val))
|
||||
if (!valImports.append(Val(*litVal)))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
@ -8209,7 +8210,7 @@ TryInstantiate(JSContext* cx, CallArgs args, Module& module, const AsmJSMetadata
|
||||
return false;
|
||||
}
|
||||
|
||||
LitValVector valImports;
|
||||
RootedValVector valImports(cx);
|
||||
Rooted<FunctionVector> funcs(cx, FunctionVector(cx));
|
||||
if (!GetImports(cx, metadata, globalVal, importVal, &funcs, &valImports))
|
||||
return false;
|
||||
@ -8217,7 +8218,8 @@ 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());
|
||||
|
@ -8343,7 +8343,7 @@ BaseCompiler::emitGetGlobal()
|
||||
pushF64(value.f64());
|
||||
break;
|
||||
case ValType::AnyRef:
|
||||
pushRef(value.ptr());
|
||||
pushRef(intptr_t(value.ptr()));
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Global constant type");
|
||||
|
@ -413,15 +413,12 @@ 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();
|
||||
|
||||
@ -454,15 +451,12 @@ 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();
|
||||
|
||||
@ -477,7 +471,6 @@ Instance::memFill(Instance* instance, uint32_t byteOffset, uint32_t value, uint3
|
||||
return 0;
|
||||
}
|
||||
// else fall through to failure case
|
||||
|
||||
}
|
||||
|
||||
JSContext* cx = TlsContext.get();
|
||||
@ -515,7 +508,7 @@ Instance::Instance(JSContext* cx,
|
||||
HandleWasmMemoryObject memory,
|
||||
SharedTableVector&& tables,
|
||||
Handle<FunctionVector> funcImports,
|
||||
const LitValVector& globalImportValues,
|
||||
HandleValVector globalImportValues,
|
||||
const WasmGlobalObjectVector& globalObjs)
|
||||
: realm_(cx->realm()),
|
||||
object_(object),
|
||||
@ -598,7 +591,7 @@ Instance::Instance(JSContext* cx,
|
||||
if (global.isIndirect())
|
||||
*(void**)globalAddr = globalObjs[imported]->cell();
|
||||
else
|
||||
globalImportValues[imported].writePayload(globalAddr);
|
||||
globalImportValues[imported].get().writePayload(globalAddr);
|
||||
break;
|
||||
}
|
||||
case GlobalKind::Variable: {
|
||||
@ -608,7 +601,7 @@ Instance::Instance(JSContext* cx,
|
||||
if (global.isIndirect())
|
||||
*(void**)globalAddr = globalObjs[i]->cell();
|
||||
else
|
||||
init.val().writePayload(globalAddr);
|
||||
Val(init.val()).writePayload(globalAddr);
|
||||
break;
|
||||
}
|
||||
case InitExpr::Kind::GetGlobal: {
|
||||
@ -618,12 +611,13 @@ 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;
|
||||
globalImportValues[imported.importIndex()].writePayload((uint8_t*)address);
|
||||
dest.get().writePayload((uint8_t*)address);
|
||||
} else {
|
||||
globalImportValues[imported.importIndex()].writePayload(globalAddr);
|
||||
dest.get().writePayload(globalAddr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ class Instance
|
||||
HandleWasmMemoryObject memory,
|
||||
SharedTableVector&& tables,
|
||||
Handle<FunctionVector> funcImports,
|
||||
const LitValVector& globalImportValues,
|
||||
HandleValVector globalImportValues,
|
||||
const WasmGlobalObjectVector& globalObjs);
|
||||
~Instance();
|
||||
bool init(JSContext* cx);
|
||||
|
@ -45,6 +45,16 @@
|
||||
#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;
|
||||
@ -110,49 +120,53 @@ wasm::HasSupport(JSContext* cx)
|
||||
}
|
||||
|
||||
static bool
|
||||
ToWebAssemblyValue(JSContext* cx, ValType targetType, HandleValue v, LitVal* val)
|
||||
ToWebAssemblyValue(JSContext* cx, ValType targetType, HandleValue v, MutableHandleVal val)
|
||||
{
|
||||
switch (targetType.code()) {
|
||||
case ValType::I32: {
|
||||
int32_t i32;
|
||||
if (!ToInt32(cx, v, &i32))
|
||||
return false;
|
||||
*val = LitVal(uint32_t(i32));
|
||||
val.set(Val(uint32_t(i32)));
|
||||
return true;
|
||||
}
|
||||
case ValType::F32: {
|
||||
double d;
|
||||
if (!ToNumber(cx, v, &d))
|
||||
return false;
|
||||
*val = LitVal(float(d));
|
||||
val.set(Val(float(d)));
|
||||
return true;
|
||||
}
|
||||
case ValType::F64: {
|
||||
double d;
|
||||
if (!ToNumber(cx, v, &d))
|
||||
return false;
|
||||
*val = LitVal(d);
|
||||
val.set(Val(d));
|
||||
return true;
|
||||
}
|
||||
case ValType::AnyRef: {
|
||||
if (v.isNull()) {
|
||||
*val = LitVal(ValType::AnyRef, nullptr);
|
||||
val.set(Val(nullptr));
|
||||
} else {
|
||||
JSObject* obj = ToObject(cx, v);
|
||||
if (!obj)
|
||||
return false;
|
||||
*val = LitVal(ValType::AnyRef, obj);
|
||||
MOZ_ASSERT(obj->compartment() == cx->compartment());
|
||||
val.set(Val(obj));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
default: {
|
||||
MOZ_CRASH("unexpected import value type, caller must guard");
|
||||
WASM_CRASH_IF_SIMD_TYPES;
|
||||
case ValType::Ref:
|
||||
case ValType::I64: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
MOZ_CRASH("unexpected import value type, caller must guard");
|
||||
}
|
||||
|
||||
static Value
|
||||
ToJSValue(const LitVal& val)
|
||||
ToJSValue(const Val& val)
|
||||
{
|
||||
switch (val.type().code()) {
|
||||
case ValType::I32:
|
||||
@ -165,9 +179,12 @@ ToJSValue(const LitVal& val)
|
||||
if (!val.ptr())
|
||||
return NullValue();
|
||||
return ObjectValue(*(JSObject*)val.ptr());
|
||||
default:
|
||||
MOZ_CRASH("unexpected type when translating to a JS value");
|
||||
WASM_CRASH_IF_SIMD_TYPES;
|
||||
case ValType::Ref:
|
||||
case ValType::I64:
|
||||
break;
|
||||
}
|
||||
MOZ_CRASH("unexpected type when translating to a JS value");
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@ -206,7 +223,7 @@ GetImports(JSContext* cx,
|
||||
MutableHandleWasmTableObject tableImport,
|
||||
MutableHandleWasmMemoryObject memoryImport,
|
||||
WasmGlobalObjectVector& globalObjs,
|
||||
LitValVector* globalImportValues)
|
||||
MutableHandleValVector globalImportValues)
|
||||
{
|
||||
const ImportVector& imports = module.imports();
|
||||
if (!imports.empty() && !importObj)
|
||||
@ -258,11 +275,11 @@ GetImports(JSContext* cx,
|
||||
break;
|
||||
}
|
||||
case DefinitionKind::Global: {
|
||||
LitVal 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>());
|
||||
|
||||
@ -280,7 +297,7 @@ GetImports(JSContext* cx,
|
||||
return false;
|
||||
}
|
||||
globalObjs[index] = obj;
|
||||
val = obj->val();
|
||||
obj->val(&val);
|
||||
} else {
|
||||
if (IsNumberType(global.type())) {
|
||||
if (!v.isNumber())
|
||||
@ -305,7 +322,7 @@ GetImports(JSContext* cx,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!globalImportValues->append(val))
|
||||
if (!globalImportValues.append(val))
|
||||
return false;
|
||||
|
||||
break;
|
||||
@ -380,11 +397,12 @@ wasm::Eval(JSContext* cx, Handle<TypedArrayObject*> code, HandleObject importObj
|
||||
RootedWasmMemoryObject memory(cx);
|
||||
Rooted<WasmGlobalObjectVector> globalObjs(cx);
|
||||
|
||||
LitValVector globals;
|
||||
RootedValVector globals(cx);
|
||||
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);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@ -1070,7 +1088,7 @@ WasmInstanceObject::create(JSContext* cx,
|
||||
SharedTableVector&& tables,
|
||||
Handle<FunctionVector> funcImports,
|
||||
const GlobalDescVector& globals,
|
||||
const LitValVector& globalImportValues,
|
||||
HandleValVector globalImportValues,
|
||||
const WasmGlobalObjectVector& globalObjs,
|
||||
HandleObject proto)
|
||||
{
|
||||
@ -1177,11 +1195,12 @@ Instantiate(JSContext* cx, const Module& module, HandleObject importObj,
|
||||
RootedWasmMemoryObject memory(cx);
|
||||
Rooted<WasmGlobalObjectVector> globalObjs(cx);
|
||||
|
||||
LitValVector globals;
|
||||
RootedValVector globals(cx);
|
||||
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
|
||||
@ -2140,10 +2159,17 @@ WasmGlobalObject::trace(JSTracer* trc, JSObject* obj)
|
||||
WasmGlobalObject* global = reinterpret_cast<WasmGlobalObject*>(obj);
|
||||
switch (global->type().code()) {
|
||||
case ValType::AnyRef:
|
||||
TraceNullableEdge(trc, &global->cell()->ptr, "wasm anyref global");
|
||||
if (global->cell()->ptr)
|
||||
TraceManuallyBarrieredEdge(trc, &global->cell()->ptr, "wasm anyref global");
|
||||
break;
|
||||
default:
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
@ -2155,21 +2181,8 @@ WasmGlobalObject::finalize(FreeOp*, JSObject* obj)
|
||||
}
|
||||
|
||||
/* static */ WasmGlobalObject*
|
||||
WasmGlobalObject::create(JSContext* cx, const LitVal& val, bool isMutable)
|
||||
WasmGlobalObject::create(JSContext* cx, HandleVal hval, 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;
|
||||
case ValType::AnyRef: cell->ptr = (JSObject*)val.ptr(); break;
|
||||
default: MOZ_CRASH();
|
||||
}
|
||||
|
||||
RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmGlobal).toObject());
|
||||
|
||||
AutoSetNewObjectMetadata metadata(cx);
|
||||
@ -2179,9 +2192,41 @@ WasmGlobalObject::create(JSContext* cx, const LitVal& val, bool isMutable)
|
||||
|
||||
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.release()));
|
||||
obj->initReservedSlot(CELL_SLOT, PrivateValue(cell));
|
||||
|
||||
return obj;
|
||||
}
|
||||
@ -2243,20 +2288,20 @@ WasmGlobalObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
||||
bool isMutable = ToBoolean(mutableVal);
|
||||
|
||||
// Extract the initial value, or provide a suitable default.
|
||||
// Guard against control flow mistakes below failing to set |globalVal|.
|
||||
LitVal globalVal = LitVal(uint32_t(0));
|
||||
RootedVal globalVal(cx);
|
||||
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: /* set above */ break;
|
||||
case ValType::I64: globalVal = LitVal(uint64_t(0)); break;
|
||||
case ValType::F32: globalVal = LitVal(float(0.0)); break;
|
||||
case ValType::F64: globalVal = LitVal(double(0.0)); break;
|
||||
case ValType::AnyRef: globalVal = LitVal(ValType::AnyRef, nullptr); break;
|
||||
default: MOZ_CRASH();
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
@ -2282,14 +2327,16 @@ WasmGlobalObject::valueGetterImpl(JSContext* cx, const CallArgs& args)
|
||||
case ValType::F32:
|
||||
case ValType::F64:
|
||||
case ValType::AnyRef:
|
||||
args.rval().set(args.thisv().toObject().as<WasmGlobalObject>().value());
|
||||
args.rval().set(args.thisv().toObject().as<WasmGlobalObject>().value(cx));
|
||||
return true;
|
||||
case ValType::I64:
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_I64_TYPE);
|
||||
return false;
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
WASM_CRASH_IF_SIMD_TYPES;
|
||||
case ValType::Ref:
|
||||
MOZ_CRASH("Ref NYI");
|
||||
}
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
@ -2313,17 +2360,34 @@ WasmGlobalObject::valueSetterImpl(JSContext* cx, const CallArgs& args)
|
||||
return false;
|
||||
}
|
||||
|
||||
LitVal val;
|
||||
RootedVal val(cx);
|
||||
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.i32(); break;
|
||||
case ValType::F32: cell->f32 = val.f32(); break;
|
||||
case ValType::F64: cell->f64 = val.f64(); break;
|
||||
case ValType::AnyRef: cell->ptr = (JSObject*)val.ptr(); break;
|
||||
default: MOZ_CRASH();
|
||||
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");
|
||||
}
|
||||
|
||||
args.rval().setUndefined();
|
||||
@ -2365,27 +2429,29 @@ WasmGlobalObject::isMutable() const
|
||||
return getReservedSlot(MUTABLE_SLOT).toBoolean();
|
||||
}
|
||||
|
||||
LitVal
|
||||
WasmGlobalObject::val() const
|
||||
void
|
||||
WasmGlobalObject::val(MutableHandleVal outval) const
|
||||
{
|
||||
Cell* cell = this->cell();
|
||||
LitVal val;
|
||||
switch (type().code()) {
|
||||
case ValType::I32: val = LitVal(uint32_t(cell->i32)); break;
|
||||
case ValType::I64: val = LitVal(uint64_t(cell->i64)); break;
|
||||
case ValType::F32: val = LitVal(cell->f32); break;
|
||||
case ValType::F64: val = LitVal(cell->f64); break;
|
||||
case ValType::AnyRef: val = LitVal(ValType::AnyRef, (void*)cell->ptr); break;
|
||||
default: MOZ_CRASH();
|
||||
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");
|
||||
}
|
||||
return val;
|
||||
MOZ_CRASH("unexpected Global type");
|
||||
}
|
||||
|
||||
Value
|
||||
WasmGlobalObject::value() const
|
||||
WasmGlobalObject::value(JSContext* cx) const
|
||||
{
|
||||
// ToJSValue crashes on I64; this is desirable.
|
||||
return ToJSValue(val());
|
||||
RootedVal result(cx);
|
||||
val(&result);
|
||||
return ToJSValue(result.get());
|
||||
}
|
||||
|
||||
WasmGlobalObject::Cell*
|
||||
|
@ -137,12 +137,11 @@ 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;
|
||||
GCPtrObject ptr;
|
||||
|
||||
int32_t i32;
|
||||
int64_t i64;
|
||||
float f32;
|
||||
double f64;
|
||||
JSObject* ptr;
|
||||
Cell() : i64(0) {}
|
||||
~Cell() {}
|
||||
};
|
||||
@ -154,13 +153,13 @@ class WasmGlobalObject : public NativeObject
|
||||
static const JSFunctionSpec static_methods[];
|
||||
static bool construct(JSContext*, unsigned, Value*);
|
||||
|
||||
static WasmGlobalObject* create(JSContext* cx, const wasm::LitVal& value, bool isMutable);
|
||||
static WasmGlobalObject* create(JSContext* cx, wasm::HandleVal value, bool isMutable);
|
||||
|
||||
wasm::ValType type() const;
|
||||
wasm::LitVal val() const;
|
||||
void val(wasm::MutableHandleVal outval) const;
|
||||
bool isMutable() const;
|
||||
// value() will MOZ_CRASH if the type is int64
|
||||
Value value() const;
|
||||
Value value(JSContext* cx) const;
|
||||
Cell* cell() const;
|
||||
};
|
||||
|
||||
@ -219,7 +218,7 @@ class WasmInstanceObject : public NativeObject
|
||||
Vector<RefPtr<wasm::Table>, 0, SystemAllocPolicy>&& tables,
|
||||
Handle<FunctionVector> funcImports,
|
||||
const wasm::GlobalDescVector& globals,
|
||||
const wasm::LitValVector& globalImportValues,
|
||||
wasm::HandleValVector 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(const LitValVector& globalImportValues, InitExpr initExpr)
|
||||
EvaluateInitExpr(HandleValVector globalImportValues, InitExpr initExpr)
|
||||
{
|
||||
switch (initExpr.kind()) {
|
||||
case InitExpr::Kind::Constant:
|
||||
return initExpr.val().i32();
|
||||
case InitExpr::Kind::GetGlobal:
|
||||
return globalImportValues[initExpr.globalIndex()].i32();
|
||||
return globalImportValues[initExpr.globalIndex()].get().i32();
|
||||
}
|
||||
|
||||
MOZ_CRASH("bad initializer expression");
|
||||
@ -738,7 +738,7 @@ Module::initSegments(JSContext* cx,
|
||||
HandleWasmInstanceObject instanceObj,
|
||||
Handle<FunctionVector> funcImports,
|
||||
HandleWasmMemoryObject memoryObj,
|
||||
const LitValVector& globalImportValues) const
|
||||
HandleValVector globalImportValues) const
|
||||
{
|
||||
Instance& instance = instanceObj->instance();
|
||||
const SharedTableVector& tables = instance.tables();
|
||||
@ -1010,39 +1010,44 @@ Module::instantiateTable(JSContext* cx, MutableHandleWasmTableObject tableObj,
|
||||
return true;
|
||||
}
|
||||
|
||||
static LitVal
|
||||
ExtractGlobalValue(const LitValVector& globalImportValues, uint32_t globalIndex,
|
||||
const GlobalDesc& global)
|
||||
static void
|
||||
ExtractGlobalValue(HandleValVector globalImportValues, uint32_t globalIndex,
|
||||
const GlobalDesc& global, MutableHandleVal result)
|
||||
{
|
||||
switch (global.kind()) {
|
||||
case GlobalKind::Import: {
|
||||
return globalImportValues[globalIndex];
|
||||
result.set(Val(globalImportValues[globalIndex]));
|
||||
return;
|
||||
}
|
||||
case GlobalKind::Variable: {
|
||||
const InitExpr& init = global.initExpr();
|
||||
switch (init.kind()) {
|
||||
case InitExpr::Kind::Constant:
|
||||
return init.val();
|
||||
result.set(Val(init.val()));
|
||||
return;
|
||||
case InitExpr::Kind::GetGlobal:
|
||||
return globalImportValues[init.globalIndex()];
|
||||
result.set(Val(globalImportValues[init.globalIndex()]));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GlobalKind::Constant: {
|
||||
return global.constantValue();
|
||||
result.set(Val(global.constantValue()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
MOZ_CRASH("Not a global value");
|
||||
}
|
||||
|
||||
static bool
|
||||
EnsureGlobalObject(JSContext* cx, const LitValVector& globalImportValues, size_t globalIndex,
|
||||
EnsureGlobalObject(JSContext* cx, HandleValVector globalImportValues, size_t globalIndex,
|
||||
const GlobalDesc& global, WasmGlobalObjectVector& globalObjs)
|
||||
{
|
||||
if (globalIndex < globalObjs.length() && globalObjs[globalIndex])
|
||||
return true;
|
||||
|
||||
LitVal val = ExtractGlobalValue(globalImportValues, globalIndex, global);
|
||||
RootedVal val(cx);
|
||||
ExtractGlobalValue(globalImportValues, globalIndex, global, &val);
|
||||
RootedWasmGlobalObject go(cx, WasmGlobalObject::create(cx, val, global.isMutable()));
|
||||
if (!go)
|
||||
return false;
|
||||
@ -1057,7 +1062,7 @@ EnsureGlobalObject(JSContext* cx, const LitValVector& globalImportValues, size_t
|
||||
}
|
||||
|
||||
bool
|
||||
Module::instantiateGlobals(JSContext* cx, const LitValVector& globalImportValues,
|
||||
Module::instantiateGlobals(JSContext* cx, HandleValVector globalImportValues,
|
||||
WasmGlobalObjectVector& globalObjs) const
|
||||
{
|
||||
// If there are exported globals that aren't in globalObjs because they
|
||||
@ -1189,7 +1194,7 @@ Module::instantiate(JSContext* cx,
|
||||
Handle<FunctionVector> funcImports,
|
||||
HandleWasmTableObject tableImport,
|
||||
HandleWasmMemoryObject memoryImport,
|
||||
const LitValVector& globalImportValues,
|
||||
HandleValVector 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, const LitValVector& globalImportValues,
|
||||
bool instantiateGlobals(JSContext* cx, HandleValVector globalImportValues,
|
||||
WasmGlobalObjectVector& globalObjs) const;
|
||||
bool initSegments(JSContext* cx,
|
||||
HandleWasmInstanceObject instance,
|
||||
Handle<FunctionVector> funcImports,
|
||||
HandleWasmMemoryObject memory,
|
||||
const LitValVector& globalImportValues) const;
|
||||
HandleValVector globalImportValues) const;
|
||||
|
||||
class Tier2GeneratorTaskImpl;
|
||||
void notifyCompilationListeners();
|
||||
@ -207,7 +207,7 @@ class Module : public JS::WasmModule
|
||||
Handle<FunctionVector> funcImports,
|
||||
HandleWasmTableObject tableImport,
|
||||
HandleWasmMemoryObject memoryImport,
|
||||
const LitValVector& globalImportValues,
|
||||
HandleValVector globalImportValues,
|
||||
WasmGlobalObjectVector& globalObjs,
|
||||
HandleObject instanceProto,
|
||||
MutableHandleWasmInstanceObject instanceObj) const;
|
||||
|
@ -60,8 +60,29 @@ 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
|
||||
LitVal::writePayload(uint8_t* dst) const
|
||||
Val::writePayload(uint8_t* dst) const
|
||||
{
|
||||
switch (type_.code()) {
|
||||
case ValType::I32:
|
||||
@ -83,10 +104,27 @@ LitVal::writePayload(uint8_t* dst) const
|
||||
return;
|
||||
case ValType::Ref:
|
||||
case ValType::AnyRef:
|
||||
memcpy(dst, &u.ptr_, sizeof(intptr_t));
|
||||
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;
|
||||
}
|
||||
MOZ_CRASH("unexpected LitVal type");
|
||||
MOZ_CRASH("unexpected Val type");
|
||||
}
|
||||
|
||||
void
|
||||
Val::trace(JSTracer* trc)
|
||||
{
|
||||
if (type_.isValid() && type_ == ValType::AnyRef && u.ptr_)
|
||||
TraceManuallyBarrieredEdge(trc, &u.ptr_, "wasm anyref global");
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -775,21 +775,22 @@ enum class HasGcTypes
|
||||
|
||||
class LitVal
|
||||
{
|
||||
protected:
|
||||
ValType type_;
|
||||
union U {
|
||||
uint32_t i32_;
|
||||
uint64_t i64_;
|
||||
float f32_;
|
||||
double f64_;
|
||||
I8x16 i8x16_;
|
||||
I16x8 i16x8_;
|
||||
I32x4 i32x4_;
|
||||
F32x4 f32x4_;
|
||||
intptr_t ptr_;
|
||||
uint32_t i32_;
|
||||
uint64_t i64_;
|
||||
float f32_;
|
||||
double f64_;
|
||||
I8x16 i8x16_;
|
||||
I16x8 i16x8_;
|
||||
I32x4 i32x4_;
|
||||
F32x4 f32x4_;
|
||||
JSObject* ptr_;
|
||||
} u;
|
||||
|
||||
public:
|
||||
LitVal() = default;
|
||||
LitVal() : type_(), u{} {}
|
||||
|
||||
explicit LitVal(uint32_t i32) : type_(ValType::I32) { u.i32_ = i32; }
|
||||
explicit LitVal(uint64_t i64) : type_(ValType::I64) { u.i64_ = i64; }
|
||||
@ -797,9 +798,10 @@ class LitVal
|
||||
explicit LitVal(float f32) : type_(ValType::F32) { u.f32_ = f32; }
|
||||
explicit LitVal(double f64) : type_(ValType::F64) { u.f64_ = f64; }
|
||||
|
||||
explicit LitVal(ValType refType, void* ptr) : type_(refType) {
|
||||
explicit LitVal(ValType refType, JSObject* ptr) : type_(refType) {
|
||||
MOZ_ASSERT(refType.isRefOrAnyRef());
|
||||
u.ptr_ = intptr_t(ptr);
|
||||
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) {
|
||||
@ -826,7 +828,7 @@ 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_; }
|
||||
intptr_t ptr() const { MOZ_ASSERT(type_.isRefOrAnyRef()); return u.ptr_; }
|
||||
JSObject* ptr() const { MOZ_ASSERT(type_.isRefOrAnyRef()); return u.ptr_; }
|
||||
|
||||
const I8x16& i8x16() const {
|
||||
MOZ_ASSERT(type_ == ValType::I8x16 || type_ == ValType::B8x16);
|
||||
@ -844,12 +846,41 @@ class LitVal
|
||||
MOZ_ASSERT(type_ == ValType::F32x4);
|
||||
return u.f32x4_;
|
||||
}
|
||||
|
||||
void writePayload(uint8_t* dst) const;
|
||||
// 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;
|
||||
|
||||
// The FuncType class represents a WebAssembly function signature which takes a
|
||||
// list of value types and returns an expression type. The engine uses two
|
||||
// in-memory representations of the argument Vector's memory (when elements do
|
||||
|
Loading…
Reference in New Issue
Block a user