Bug 1450261: Implement Val, a rooted LitVal; r=luke, r=jonco

--HG--
extra : rebase_source : 010cd8dafd03402487cc80f30ff67a607895fe75
This commit is contained in:
Benjamin Bouvier 2018-06-29 16:43:20 +02:00
parent 29f287f4d4
commit f82eacce97
12 changed files with 293 additions and 144 deletions

View File

@ -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
}

View 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");

View File

@ -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());

View File

@ -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");

View File

@ -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;
}

View File

@ -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);

View File

@ -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*

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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