зеркало из 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;
|
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;
|
RefType tableType;
|
||||||
if (!ToRefType(cx, elementLinearStr, &tableType)) {
|
if (!ToRefType(cx, elementVal, &tableType)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,13 +23,136 @@
|
||||||
#include "js/friend/ErrorMessages.h" // JSMSG_*
|
#include "js/friend/ErrorMessages.h" // JSMSG_*
|
||||||
#include "js/Printf.h"
|
#include "js/Printf.h"
|
||||||
#include "js/Value.h"
|
#include "js/Value.h"
|
||||||
|
|
||||||
|
#include "vm/JSAtom.h"
|
||||||
|
#include "vm/JSObject.h"
|
||||||
#include "vm/StringType.h"
|
#include "vm/StringType.h"
|
||||||
#include "wasm/WasmJS.h"
|
#include "wasm/WasmJS.h"
|
||||||
|
|
||||||
|
#include "vm/JSAtom-inl.h"
|
||||||
|
#include "vm/JSObject-inl.h"
|
||||||
|
|
||||||
using namespace js;
|
using namespace js;
|
||||||
using namespace js::wasm;
|
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) {
|
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));
|
RootedString typeStr(cx, ToString(cx, v));
|
||||||
if (!typeStr) {
|
if (!typeStr) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -65,34 +188,30 @@ bool wasm::ToValType(JSContext* cx, HandleValue v, ValType* out) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wasm::ToRefType(JSContext* cx, JSLinearString* typeLinearStr,
|
bool wasm::ToRefType(JSContext* cx, HandleValue v, RefType* out) {
|
||||||
RefType* out) {
|
if (v.isObject()) {
|
||||||
if (StringEqualsLiteral(typeLinearStr, "anyfunc") ||
|
RootedObject obj(cx, &v.toObject());
|
||||||
StringEqualsLiteral(typeLinearStr, "funcref")) {
|
switch (MaybeToRefType(cx, obj, out)) {
|
||||||
// The JS API uses "anyfunc" uniformly as the external name of funcref. We
|
case RefTypeResult::Failure:
|
||||||
// also allow "funcref" for compatibility with code we've already shipped.
|
return false;
|
||||||
*out = RefType::func();
|
case RefTypeResult::Parsed:
|
||||||
} else if (StringEqualsLiteral(typeLinearStr, "externref")) {
|
return true;
|
||||||
*out = RefType::extern_();
|
case RefTypeResult::Unparsed:
|
||||||
#ifdef ENABLE_WASM_GC
|
break;
|
||||||
} else if (GcAvailable(cx) && StringEqualsLiteral(typeLinearStr, "anyref")) {
|
}
|
||||||
*out = RefType::any();
|
}
|
||||||
} else if (GcAvailable(cx) && StringEqualsLiteral(typeLinearStr, "eqref")) {
|
|
||||||
*out = RefType::eq();
|
RootedString typeStr(cx, ToString(cx, v));
|
||||||
} else if (GcAvailable(cx) &&
|
if (!typeStr) {
|
||||||
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 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) {
|
UniqueChars wasm::ToString(RefType type, const TypeContext* types) {
|
||||||
|
|
|
@ -844,8 +844,7 @@ using ValTypeVector = Vector<ValType, 16, SystemAllocPolicy>;
|
||||||
// ValType utilities
|
// ValType utilities
|
||||||
|
|
||||||
extern bool ToValType(JSContext* cx, HandleValue v, ValType* out);
|
extern bool ToValType(JSContext* cx, HandleValue v, ValType* out);
|
||||||
extern bool ToRefType(JSContext* cx, JSLinearString* typeLinearStr,
|
extern bool ToRefType(JSContext* cx, HandleValue v, RefType* out);
|
||||||
RefType* out);
|
|
||||||
|
|
||||||
extern UniqueChars ToString(RefType type, const TypeContext* types);
|
extern UniqueChars ToString(RefType type, const TypeContext* types);
|
||||||
extern UniqueChars ToString(ValType type, const TypeContext* types);
|
extern UniqueChars ToString(ValType type, const TypeContext* types);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче