зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1784499 - Extend reftype parsing in JS API. r=rhunt
Adds object (ref)type description for tables and globals. Differential Revision: https://phabricator.services.mozilla.com/D162888
This commit is contained in:
Родитель
8ab1f55f02
Коммит
57664750c6
|
@ -0,0 +1,35 @@
|
|||
// |jit-test| skip-if: !wasmFunctionReferencesEnabled()
|
||||
|
||||
// RefType/ValueType as a simple string
|
||||
const t01 = new WebAssembly.Table({element: 'funcref', initial: 3});
|
||||
const t02 = new WebAssembly.Table({element: 'externref', initial: 8});
|
||||
const g01 = new WebAssembly.Global({value: 'funcref', mutable: true}, null);
|
||||
const g02 = new WebAssembly.Global({value: 'externref', mutable: true}, null);
|
||||
|
||||
// Specify ToString() equivalents
|
||||
const t05 = new WebAssembly.Table({element: {toString() { return 'funcref' },}, initial: 11});
|
||||
const t06 = new WebAssembly.Table({element: ['externref'], initial: 7});
|
||||
|
||||
assertErrorMessage(
|
||||
() => new WebAssembly.Table({element: 'foo', initial: 1}),
|
||||
TypeError, /bad value type/);
|
||||
assertErrorMessage(
|
||||
() => new WebAssembly.Table({element: true, initial: 1}),
|
||||
TypeError, /bad value type/);
|
||||
|
||||
// RefType/ValueType can be specified as an {ref: 'func', ...} object
|
||||
const t11 = new WebAssembly.Table({element: {ref: 'func', nullable: true}, initial: 3});
|
||||
const t12 = new WebAssembly.Table({element: {ref: 'extern', nullable: true}, initial: 3});
|
||||
// TODO new WebAssembly.Table({element: {ref: 'func', nullable: false}, initial: 3}),
|
||||
|
||||
assertErrorMessage(
|
||||
() => new WebAssembly.Table({element: {ref: 'bar', nullable: true}, initial: 1}),
|
||||
TypeError, /bad value type/);
|
||||
|
||||
const g11 = new WebAssembly.Global({value: {ref: 'func', nullable: true}, mutable: true});
|
||||
const g12 = new WebAssembly.Global({value: {ref: 'extern', nullable: true}, mutable: true});
|
||||
// TODO new WebAssembly.Global({value: {ref: 'extern', nullable: false}, mutable: true});
|
||||
|
||||
assertErrorMessage(
|
||||
() => new WebAssembly.Global({value: {ref: 'bar', nullable: true}, mutable: true}),
|
||||
TypeError, /bad value type/);
|
|
@ -3109,18 +3109,8 @@ bool WasmTableObject::construct(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return false;
|
||||
}
|
||||
|
||||
RootedString elementStr(cx, ToString(cx, elementVal));
|
||||
if (!elementStr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Rooted<JSLinearString*> elementLinearStr(cx, elementStr->ensureLinear(cx));
|
||||
if (!elementLinearStr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefType tableType;
|
||||
if (!ToRefType(cx, elementLinearStr, &tableType)) {
|
||||
if (!ToRefType(cx, elementVal, &tableType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,13 +23,136 @@
|
|||
#include "js/friend/ErrorMessages.h" // JSMSG_*
|
||||
#include "js/Printf.h"
|
||||
#include "js/Value.h"
|
||||
|
||||
#include "vm/JSAtom.h"
|
||||
#include "vm/JSObject.h"
|
||||
#include "vm/StringType.h"
|
||||
#include "wasm/WasmJS.h"
|
||||
|
||||
#include "vm/JSAtom-inl.h"
|
||||
#include "vm/JSObject-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::wasm;
|
||||
|
||||
static bool ToRefType(JSContext* cx, JSLinearString* typeLinearStr,
|
||||
RefType* out) {
|
||||
if (StringEqualsLiteral(typeLinearStr, "anyfunc") ||
|
||||
StringEqualsLiteral(typeLinearStr, "funcref")) {
|
||||
// The JS API uses "anyfunc" uniformly as the external name of funcref. We
|
||||
// also allow "funcref" for compatibility with code we've already shipped.
|
||||
*out = RefType::func();
|
||||
} else if (StringEqualsLiteral(typeLinearStr, "externref")) {
|
||||
*out = RefType::extern_();
|
||||
#ifdef ENABLE_WASM_GC
|
||||
} else if (GcAvailable(cx) && StringEqualsLiteral(typeLinearStr, "anyref")) {
|
||||
*out = RefType::any();
|
||||
} else if (GcAvailable(cx) && StringEqualsLiteral(typeLinearStr, "eqref")) {
|
||||
*out = RefType::eq();
|
||||
} else if (GcAvailable(cx) &&
|
||||
StringEqualsLiteral(typeLinearStr, "structref")) {
|
||||
*out = RefType::struct_();
|
||||
} else if (GcAvailable(cx) &&
|
||||
StringEqualsLiteral(typeLinearStr, "arrayref")) {
|
||||
*out = RefType::array();
|
||||
#endif
|
||||
} else {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_WASM_BAD_STRING_VAL_TYPE);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
enum class RefTypeResult {
|
||||
Failure,
|
||||
Parsed,
|
||||
Unparsed,
|
||||
};
|
||||
|
||||
static RefTypeResult MaybeToRefType(JSContext* cx, HandleObject obj,
|
||||
RefType* out) {
|
||||
#ifdef ENABLE_WASM_FUNCTION_REFERENCES
|
||||
if (!wasm::FunctionReferencesAvailable(cx)) {
|
||||
return RefTypeResult::Unparsed;
|
||||
}
|
||||
|
||||
JSAtom* refAtom = Atomize(cx, "ref", strlen("ref"));
|
||||
if (!refAtom) {
|
||||
return RefTypeResult::Failure;
|
||||
}
|
||||
RootedId refId(cx, AtomToId(refAtom));
|
||||
|
||||
RootedValue refVal(cx);
|
||||
if (!GetProperty(cx, obj, obj, refId, &refVal)) {
|
||||
return RefTypeResult::Failure;
|
||||
}
|
||||
|
||||
RootedString typeStr(cx, ToString(cx, refVal));
|
||||
if (!typeStr) {
|
||||
return RefTypeResult::Failure;
|
||||
}
|
||||
|
||||
Rooted<JSLinearString*> typeLinearStr(cx, typeStr->ensureLinear(cx));
|
||||
if (!typeLinearStr) {
|
||||
return RefTypeResult::Failure;
|
||||
}
|
||||
|
||||
if (StringEqualsLiteral(typeLinearStr, "func")) {
|
||||
*out = RefType::func();
|
||||
} else if (StringEqualsLiteral(typeLinearStr, "extern")) {
|
||||
*out = RefType::extern_();
|
||||
# ifdef ENABLE_WASM_GC
|
||||
} else if (GcAvailable(cx) && StringEqualsLiteral(typeLinearStr, "any")) {
|
||||
*out = RefType::any();
|
||||
} else if (GcAvailable(cx) && StringEqualsLiteral(typeLinearStr, "eq")) {
|
||||
*out = RefType::eq();
|
||||
} else if (GcAvailable(cx) && StringEqualsLiteral(typeLinearStr, "struct")) {
|
||||
*out = RefType::struct_();
|
||||
} else if (GcAvailable(cx) && StringEqualsLiteral(typeLinearStr, "array")) {
|
||||
*out = RefType::array();
|
||||
# endif
|
||||
} else {
|
||||
return RefTypeResult::Unparsed;
|
||||
}
|
||||
|
||||
JSAtom* nullableAtom = Atomize(cx, "nullable", strlen("nullable"));
|
||||
if (!nullableAtom) {
|
||||
return RefTypeResult::Failure;
|
||||
}
|
||||
RootedId nullableId(cx, AtomToId(nullableAtom));
|
||||
RootedValue nullableVal(cx);
|
||||
if (!GetProperty(cx, obj, obj, nullableId, &nullableVal)) {
|
||||
return RefTypeResult::Failure;
|
||||
}
|
||||
|
||||
bool nullable = ToBoolean(nullableVal);
|
||||
if (!nullable) {
|
||||
*out = out->asNonNullable();
|
||||
}
|
||||
MOZ_ASSERT(out->isNullable() == nullable);
|
||||
return RefTypeResult::Parsed;
|
||||
#else
|
||||
return RefTypeResult::Unparsed;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool wasm::ToValType(JSContext* cx, HandleValue v, ValType* out) {
|
||||
if (v.isObject()) {
|
||||
RootedObject obj(cx, &v.toObject());
|
||||
RefType refType;
|
||||
switch (MaybeToRefType(cx, obj, &refType)) {
|
||||
case RefTypeResult::Failure:
|
||||
return false;
|
||||
case RefTypeResult::Parsed:
|
||||
*out = ValType(refType);
|
||||
return true;
|
||||
case RefTypeResult::Unparsed:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RootedString typeStr(cx, ToString(cx, v));
|
||||
if (!typeStr) {
|
||||
return false;
|
||||
|
@ -65,34 +188,30 @@ bool wasm::ToValType(JSContext* cx, HandleValue v, ValType* out) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool wasm::ToRefType(JSContext* cx, JSLinearString* typeLinearStr,
|
||||
RefType* out) {
|
||||
if (StringEqualsLiteral(typeLinearStr, "anyfunc") ||
|
||||
StringEqualsLiteral(typeLinearStr, "funcref")) {
|
||||
// The JS API uses "anyfunc" uniformly as the external name of funcref. We
|
||||
// also allow "funcref" for compatibility with code we've already shipped.
|
||||
*out = RefType::func();
|
||||
} else if (StringEqualsLiteral(typeLinearStr, "externref")) {
|
||||
*out = RefType::extern_();
|
||||
#ifdef ENABLE_WASM_GC
|
||||
} else if (GcAvailable(cx) && StringEqualsLiteral(typeLinearStr, "anyref")) {
|
||||
*out = RefType::any();
|
||||
} else if (GcAvailable(cx) && StringEqualsLiteral(typeLinearStr, "eqref")) {
|
||||
*out = RefType::eq();
|
||||
} else if (GcAvailable(cx) &&
|
||||
StringEqualsLiteral(typeLinearStr, "structref")) {
|
||||
*out = RefType::struct_();
|
||||
} else if (GcAvailable(cx) &&
|
||||
StringEqualsLiteral(typeLinearStr, "arrayref")) {
|
||||
*out = RefType::array();
|
||||
#endif
|
||||
} else {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_WASM_BAD_STRING_VAL_TYPE);
|
||||
bool wasm::ToRefType(JSContext* cx, HandleValue v, RefType* out) {
|
||||
if (v.isObject()) {
|
||||
RootedObject obj(cx, &v.toObject());
|
||||
switch (MaybeToRefType(cx, obj, out)) {
|
||||
case RefTypeResult::Failure:
|
||||
return false;
|
||||
case RefTypeResult::Parsed:
|
||||
return true;
|
||||
case RefTypeResult::Unparsed:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RootedString typeStr(cx, ToString(cx, v));
|
||||
if (!typeStr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
Rooted<JSLinearString*> typeLinearStr(cx, typeStr->ensureLinear(cx));
|
||||
if (!typeLinearStr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ToRefType(cx, typeLinearStr, out);
|
||||
}
|
||||
|
||||
UniqueChars wasm::ToString(RefType type, const TypeContext* types) {
|
||||
|
|
|
@ -844,8 +844,7 @@ using ValTypeVector = Vector<ValType, 16, SystemAllocPolicy>;
|
|||
// ValType utilities
|
||||
|
||||
extern bool ToValType(JSContext* cx, HandleValue v, ValType* out);
|
||||
extern bool ToRefType(JSContext* cx, JSLinearString* typeLinearStr,
|
||||
RefType* out);
|
||||
extern bool ToRefType(JSContext* cx, HandleValue v, RefType* out);
|
||||
|
||||
extern UniqueChars ToString(RefType type, const TypeContext* types);
|
||||
extern UniqueChars ToString(ValType type, const TypeContext* types);
|
||||
|
|
Загрузка…
Ссылка в новой задаче