зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1703089 - Implement WebAssembly.Exception constructor r=rhunt
Differential Revision: https://phabricator.services.mozilla.com/D110851
This commit is contained in:
Родитель
8ed84b3bce
Коммит
87dd52d7c1
|
@ -465,6 +465,9 @@ MSG_DEF(JSMSG_WASM_BAD_EQREF_VALUE, 0, JSEXN_TYPEERR, "can only pass a Type
|
|||
MSG_DEF(JSMSG_WASM_BAD_VAL_TYPE, 0, JSEXN_TYPEERR, "cannot pass v128 to or from JS")
|
||||
MSG_DEF(JSMSG_WASM_BAD_STRING_VAL_TYPE, 0, JSEXN_TYPEERR, "bad value type")
|
||||
MSG_DEF(JSMSG_WASM_BAD_STRING_IDX_TYPE, 0, JSEXN_TYPEERR, "bad index type")
|
||||
MSG_DEF(JSMSG_WASM_BAD_EXN_ARG, 0, JSEXN_TYPEERR, "first argument must be a WebAssembly.Tag")
|
||||
MSG_DEF(JSMSG_WASM_BAD_EXN_PAYLOAD, 0, JSEXN_TYPEERR, "second argument must be an object")
|
||||
MSG_DEF(JSMSG_WASM_BAD_EXN_PAYLOAD_LEN, 2, JSEXN_TYPEERR, "expected {0} values but got {1}")
|
||||
MSG_DEF(JSMSG_WASM_NO_TRANSFER, 0, JSEXN_TYPEERR, "cannot transfer WebAssembly/asm.js ArrayBuffer")
|
||||
MSG_DEF(JSMSG_WASM_TEXT_FAIL, 1, JSEXN_SYNTAXERR, "wasm text error: {0}")
|
||||
MSG_DEF(JSMSG_WASM_MISSING_MAXIMUM, 0, JSEXN_TYPEERR, "'shared' is true but maximum is not specified")
|
||||
|
|
|
@ -8,12 +8,6 @@ function testException() {
|
|||
WebAssembly.RuntimeError,
|
||||
/cannot call WebAssembly.Tag/
|
||||
);
|
||||
|
||||
assertErrorMessage(
|
||||
() => new WebAssembly.Exception(),
|
||||
WebAssembly.RuntimeError,
|
||||
/cannot call WebAssembly.Exception/
|
||||
);
|
||||
}
|
||||
|
||||
function testImports() {
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
// Tests for wasm exception proposal JS API features.
|
||||
|
||||
load(libdir + "eqArrayHelper.js");
|
||||
|
||||
assertErrorMessage(
|
||||
() => WebAssembly.Exception(),
|
||||
TypeError,
|
||||
/calling a builtin Exception constructor without new is forbidden/
|
||||
);
|
||||
|
||||
assertErrorMessage(
|
||||
() => new WebAssembly.Exception(),
|
||||
TypeError,
|
||||
/At least 2 arguments required/
|
||||
);
|
||||
|
||||
assertErrorMessage(
|
||||
() => new WebAssembly.Exception(3, []),
|
||||
TypeError,
|
||||
/first argument must be a WebAssembly.Tag/
|
||||
);
|
||||
|
||||
const { tag1, tag2, tag3, tag4, tag5, tag6, tag7 } = wasmEvalText(
|
||||
`(module
|
||||
(event (export "tag1") (param))
|
||||
(event (export "tag2") (param i32))
|
||||
(event (export "tag3") (param i32 f32))
|
||||
(event (export "tag4") (param i32 externref i32))
|
||||
(event (export "tag5") (param i32 externref i32 externref))
|
||||
(event (export "tag6") (param funcref))
|
||||
(event (export "tag7") (param i64)))`
|
||||
).exports;
|
||||
|
||||
new WebAssembly.Exception(tag1, []);
|
||||
new WebAssembly.Exception(tag2, [3]);
|
||||
new WebAssembly.Exception(tag3, [3, 5.5]);
|
||||
new WebAssembly.Exception(tag4, [3, "foo", 4]);
|
||||
new WebAssembly.Exception(tag5, [3, "foo", 4, "bar"]);
|
||||
|
||||
assertErrorMessage(
|
||||
() => new WebAssembly.Exception(tag2, []),
|
||||
TypeError,
|
||||
/expected 1 values but got 0/
|
||||
);
|
||||
|
||||
assertErrorMessage(
|
||||
() => new WebAssembly.Exception(tag2, [3n]),
|
||||
TypeError,
|
||||
/can't convert BigInt to number/
|
||||
);
|
||||
|
||||
assertErrorMessage(
|
||||
() => new WebAssembly.Exception(tag6, [undefined]),
|
||||
TypeError,
|
||||
/can only pass WebAssembly exported functions to funcref/
|
||||
);
|
||||
|
||||
assertErrorMessage(
|
||||
() => new WebAssembly.Exception(tag7, [undefined]),
|
||||
TypeError,
|
||||
/can't convert undefined to BigInt/
|
||||
);
|
||||
|
||||
assertErrorMessage(
|
||||
() => new WebAssembly.Exception(tag7, {}),
|
||||
TypeError,
|
||||
/\({}\) is not iterable/
|
||||
);
|
||||
|
||||
assertErrorMessage(
|
||||
() => new WebAssembly.Exception(tag7, 1),
|
||||
TypeError,
|
||||
/second argument must be an object/
|
||||
);
|
||||
|
||||
// Test throwing a JS constructed exception to Wasm.
|
||||
assertEq(
|
||||
wasmEvalText(
|
||||
`(module
|
||||
(import "m" "exn" (event $exn (param i32)))
|
||||
(import "m" "f" (func $f))
|
||||
(func (export "f") (result i32)
|
||||
try (result i32)
|
||||
call $f
|
||||
(i32.const 0)
|
||||
catch $exn
|
||||
end))`,
|
||||
{
|
||||
m: {
|
||||
exn: tag2,
|
||||
f: () => {
|
||||
throw new WebAssembly.Exception(tag2, [42]);
|
||||
},
|
||||
},
|
||||
}
|
||||
).exports.f(),
|
||||
42
|
||||
);
|
||||
|
||||
assertEqArray(
|
||||
wasmEvalText(
|
||||
`(module
|
||||
(import "m" "exn" (event $exn (param i32 f32)))
|
||||
(import "m" "f" (func $f))
|
||||
(func (export "f") (result i32 f32)
|
||||
try (result i32 f32)
|
||||
call $f
|
||||
(i32.const 0)
|
||||
(f32.const 0)
|
||||
catch $exn
|
||||
end))`,
|
||||
{
|
||||
m: {
|
||||
exn: tag3,
|
||||
f: () => {
|
||||
throw new WebAssembly.Exception(tag3, [42, 5.5]);
|
||||
},
|
||||
},
|
||||
}
|
||||
).exports.f(),
|
||||
[42, 5.5]
|
||||
);
|
||||
|
||||
assertEqArray(
|
||||
wasmEvalText(
|
||||
`(module
|
||||
(import "m" "exn" (event $exn (param i32 externref i32)))
|
||||
(import "m" "f" (func $f))
|
||||
(func (export "f") (result i32 externref i32)
|
||||
try (result i32 externref i32)
|
||||
call $f
|
||||
(i32.const 0)
|
||||
(ref.null extern)
|
||||
(i32.const 0)
|
||||
catch $exn
|
||||
end))`,
|
||||
{
|
||||
m: {
|
||||
exn: tag4,
|
||||
f: () => {
|
||||
throw new WebAssembly.Exception(tag4, [42, "foo", 42]);
|
||||
},
|
||||
},
|
||||
}
|
||||
).exports.f(),
|
||||
[42, "foo", 42]
|
||||
);
|
||||
|
||||
assertEq(
|
||||
wasmEvalText(
|
||||
`(module
|
||||
(import "m" "exn" (event $exn))
|
||||
(import "m" "f" (func $f))
|
||||
(func (export "f") (result i32)
|
||||
try (result i32)
|
||||
call $f
|
||||
(i32.const 0)
|
||||
catch $exn
|
||||
(i32.const 0)
|
||||
catch_all
|
||||
(i32.const 1)
|
||||
end))`,
|
||||
{
|
||||
m: {
|
||||
exn: tag1,
|
||||
f: () => {
|
||||
throw new WebAssembly.Exception(tag2, [42]);
|
||||
},
|
||||
},
|
||||
}
|
||||
).exports.f(),
|
||||
1
|
||||
);
|
|
@ -3584,6 +3584,8 @@ void WasmTagObject::finalize(JSFreeOp* fop, JSObject* obj) {
|
|||
}
|
||||
}
|
||||
|
||||
static bool IsTagObject(JSObject* obj) { return obj->is<WasmTagObject>(); }
|
||||
|
||||
bool WasmTagObject::construct(JSContext* cx, unsigned argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
|
@ -3710,14 +3712,90 @@ bool WasmExceptionObject::construct(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// FIXME: When the JS API is finalized, it may be possible to construct
|
||||
// WebAssembly.Exception instances from JS, but not for now.
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_WASM_EXN_CONSTRUCTOR, "WebAssembly.Exception");
|
||||
|
||||
if (!args.requireAtLeast(cx, "WebAssembly.Exception", 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!args[0].isObject() || !IsTagObject(&args[0].toObject())) {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_WASM_BAD_EXN_ARG);
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedWasmTagObject exnTag(cx, &args[0].toObject().as<WasmTagObject>());
|
||||
|
||||
if (!args.get(1).isObject()) {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_WASM_BAD_EXN_PAYLOAD);
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::ForOfIterator iterator(cx);
|
||||
if (!iterator.init(args.get(1), JS::ForOfIterator::ThrowOnNonIterable)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wasm::ValTypeVector& params = exnTag->valueTypes();
|
||||
|
||||
// This is pre-sizing the data buffer for the exception object.
|
||||
size_t nbytes = 0;
|
||||
for (const ValType param : params) {
|
||||
if (!param.isReference()) {
|
||||
nbytes += SizeOf(param);
|
||||
}
|
||||
}
|
||||
|
||||
RootedArrayBufferObject buf(cx, ArrayBufferObject::createZeroed(cx, nbytes));
|
||||
if (!buf) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedArrayObject refs(cx, NewDenseEmptyArray(cx));
|
||||
if (!refs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t* bufPtr = buf->dataPointer();
|
||||
RootedValue nextArg(cx);
|
||||
for (size_t i = 0; i < params.length(); i++) {
|
||||
bool done;
|
||||
if (!iterator.next(&nextArg, &done)) {
|
||||
return false;
|
||||
}
|
||||
if (done) {
|
||||
UniqueChars expected(JS_smprintf("%zu", params.length()));
|
||||
UniqueChars got(JS_smprintf("%zu", i));
|
||||
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_WASM_BAD_EXN_PAYLOAD_LEN, expected.get(),
|
||||
got.get());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (params[i].isReference()) {
|
||||
RootedObject objPtr(cx);
|
||||
if (!ToWebAssemblyValue(cx, nextArg, params[i], objPtr.address(), true)) {
|
||||
return false;
|
||||
}
|
||||
if (!NewbornArrayPush(cx, refs, ObjectValue(*objPtr))) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!ToWebAssemblyValue(cx, nextArg, params[i], bufPtr, true)) {
|
||||
return false;
|
||||
}
|
||||
bufPtr += SizeOf(params[i]);
|
||||
}
|
||||
}
|
||||
|
||||
RootedWasmExceptionObject exnObj(
|
||||
cx, WasmExceptionObject::create(cx, SharedExceptionTag(&exnTag->tag()),
|
||||
buf, refs));
|
||||
|
||||
args.rval().setObject(*exnObj);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
WasmExceptionObject* WasmExceptionObject::create(JSContext* cx,
|
||||
wasm::SharedExceptionTag tag,
|
||||
|
|
Загрузка…
Ссылка в новой задаче