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:
Yury Delendik 2023-03-23 13:46:15 +00:00
Родитель 8ab1f55f02
Коммит 57664750c6
4 изменённых файлов: 181 добавлений и 38 удалений

Просмотреть файл

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