Bug 1335652 - wasm exceptions part 10: add WebAssembly.RuntimeException r=rhunt

This patch adds the WebAssembly.RuntimeException class in order to
represent exceptions thrown from Wasm. When the JS API is finalized,
this class may allow access to the thrown values from JS.

Differential Revision: https://phabricator.services.mozilla.com/D101134
This commit is contained in:
Asumu Takikawa 2021-02-03 04:21:07 +00:00
parent df9c9cd78c
commit d8058476ca
8 changed files with 156 additions and 3 deletions

View File

@ -122,6 +122,7 @@
REAL(WasmTable, OCLASP(WasmTable)) \
REAL(WasmGlobal, OCLASP(WasmGlobal)) \
REAL(WasmException, OCLASP(WasmException)) \
REAL(WasmRuntimeException, OCLASP(WasmRuntimeException)) \
REAL(FinalizationRegistry, OCLASP(FinalizationRegistry)) \
REAL(WeakRef, OCLASP(WeakRef)) \
REAL(Iterator, OCLASP(Iterator)) \

View File

@ -461,7 +461,7 @@ MSG_DEF(JSMSG_WASM_NONSHARED_WAIT , 0, JSEXN_WASMRUNTIMEERROR, "atomic wait o
MSG_DEF(JSMSG_WASM_NULL_REQUIRED, 0, JSEXN_TYPEERR, "nullref requires a null value")
MSG_DEF(JSMSG_WASM_SUPPLY_ONLY_ONE, 2, JSEXN_TYPEERR, "exactly one of {0} and {1} must be supplied")
MSG_DEF(JSMSG_WASM_MISSING_REQUIRED, 1, JSEXN_TYPEERR, "Missing required argument {0}")
MSG_DEF(JSMSG_WASM_EXN_CONSTRUCTOR, 0, JSEXN_WASMRUNTIMEERROR, "cannot call WebAssembly.Exception")
MSG_DEF(JSMSG_WASM_EXN_CONSTRUCTOR, 1, JSEXN_WASMRUNTIMEERROR, "cannot call {0}")
// Proxy
MSG_DEF(JSMSG_BAD_TRAP_RETURN_VALUE, 2, JSEXN_TYPEERR,"trap {1} for {0} returned a primitive value")

View File

@ -129,6 +129,7 @@ enum class GCAbortReason {
_(WasmTableTable) \
_(WasmExceptionTag) \
_(WasmExceptionType) \
_(WasmRuntimeExceptionTag) \
_(FileObjectFile) \
_(Debugger) \
_(DebuggerFrameGeneratorInfo) \

View File

@ -1,13 +1,19 @@
// Tests for Wasm exception import and export.
// The WebAssembly.Exception constructor cannot be called for now until the
// JS API specifies the behavior.
// JS API specifies the behavior. Same with WebAssembly.RuntimeException.
function testException() {
assertErrorMessage(
() => new WebAssembly.Exception(),
WebAssembly.RuntimeError,
/cannot call WebAssembly.Exception/
);
assertErrorMessage(
() => new WebAssembly.RuntimeException(),
WebAssembly.RuntimeError,
/cannot call WebAssembly.RuntimeException/
);
}
function testImports() {

View File

@ -157,6 +157,7 @@ bool GlobalObject::skipDeselectedConstructor(JSContext* cx, JSProtoKey key) {
case JSProto_WasmTable:
case JSProto_WasmGlobal:
case JSProto_WasmException:
case JSProto_WasmRuntimeException:
return false;
#ifdef JS_HAS_INTL_API

View File

@ -3391,7 +3391,7 @@ bool WasmExceptionObject::construct(JSContext* cx, unsigned argc, Value* vp) {
// here.
// For now, we implement the same behavior as V8 and error when called.
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_EXN_CONSTRUCTOR);
JSMSG_WASM_EXN_CONSTRUCTOR, "WebAssembly.Exception");
return false;
}
@ -3456,6 +3456,112 @@ ExceptionTag& WasmExceptionObject::tag() const {
return *(ExceptionTag*)getReservedSlot(TAG_SLOT).toPrivate();
}
// ============================================================================
// WebAssembly.RuntimeException class and methods
const JSClassOps WasmRuntimeExceptionObject::classOps_ = {
nullptr, // addProperty
nullptr, // delProperty
nullptr, // enumerate
nullptr, // newEnumerate
nullptr, // resolve
nullptr, // mayResolve
WasmRuntimeExceptionObject::finalize, // finalize
nullptr, // call
nullptr, // hasInstance
nullptr, // construct
nullptr, // trace
};
const JSClass WasmRuntimeExceptionObject::class_ = {
"WebAssembly.RuntimeException",
JSCLASS_HAS_RESERVED_SLOTS(WasmRuntimeExceptionObject::RESERVED_SLOTS) |
JSCLASS_HAS_PRIVATE | JSCLASS_FOREGROUND_FINALIZE,
&WasmRuntimeExceptionObject::classOps_,
&WasmRuntimeExceptionObject::classSpec_};
const JSClass& WasmRuntimeExceptionObject::protoClass_ = PlainObject::class_;
static constexpr char WasmRuntimeExceptionName[] = "RuntimeException";
const ClassSpec WasmRuntimeExceptionObject::classSpec_ = {
CreateWasmConstructor<WasmRuntimeExceptionObject, WasmRuntimeExceptionName>,
GenericCreatePrototype<WasmRuntimeExceptionObject>,
WasmRuntimeExceptionObject::static_methods,
nullptr,
WasmRuntimeExceptionObject::methods,
WasmRuntimeExceptionObject::properties,
nullptr,
ClassSpec::DontDefineConstructor};
/* static */
void WasmRuntimeExceptionObject::finalize(JSFreeOp* fop, JSObject* obj) {
WasmRuntimeExceptionObject& exnObj = obj->as<WasmRuntimeExceptionObject>();
if (!exnObj.isNewborn()) {
fop->release(obj, &exnObj.tag(), MemoryUse::WasmRuntimeExceptionTag);
}
}
bool WasmRuntimeExceptionObject::construct(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
if (!ThrowIfNotConstructing(cx, args, "RuntimeException")) {
return false;
}
// FIXME: When the JS API is finalized, it may be possible to construct
// WebAssembly.RuntimeException instances from JS, but not for now.
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_EXN_CONSTRUCTOR,
"WebAssembly.RuntimeException");
return false;
}
/* static */
WasmRuntimeExceptionObject* WasmRuntimeExceptionObject::create(
JSContext* cx, wasm::SharedExceptionTag tag,
HandleArrayBufferObject values) {
RootedObject proto(
cx, &cx->global()->getPrototype(JSProto_WasmRuntimeException).toObject());
AutoSetNewObjectMetadata metadata(cx);
RootedWasmRuntimeExceptionObject obj(
cx, NewObjectWithGivenProto<WasmRuntimeExceptionObject>(cx, proto));
if (!obj) {
return nullptr;
}
MOZ_ASSERT(obj->isNewborn());
InitReservedSlot(obj, TAG_SLOT, tag.forget().take(),
MemoryUse::WasmRuntimeExceptionTag);
obj->initFixedSlot(VALUES_SLOT, ObjectValue(*values));
MOZ_ASSERT(!obj->isNewborn());
return obj;
}
bool WasmRuntimeExceptionObject::isNewborn() const {
MOZ_ASSERT(is<WasmRuntimeExceptionObject>());
return getReservedSlot(VALUES_SLOT).isUndefined();
}
const JSPropertySpec WasmRuntimeExceptionObject::properties[] = {
JS_STRING_SYM_PS(toStringTag, "WebAssembly.RuntimeException",
JSPROP_READONLY),
JS_PS_END};
const JSFunctionSpec WasmRuntimeExceptionObject::methods[] = {JS_FS_END};
const JSFunctionSpec WasmRuntimeExceptionObject::static_methods[] = {JS_FS_END};
ExceptionTag& WasmRuntimeExceptionObject::tag() const {
return *(ExceptionTag*)getReservedSlot(TAG_SLOT).toPrivate();
}
// ============================================================================
// WebAssembly class and static methods
@ -4435,6 +4541,7 @@ static bool WebAssemblyClassFinish(JSContext* cx, HandleObject object,
{"Global", JSProto_WasmGlobal},
#ifdef ENABLE_WASM_EXCEPTIONS
{"Exception", JSProto_WasmException},
{"RuntimeException", JSProto_WasmRuntimeException},
#endif
{"CompileError", GetExceptionProtoKey(JSEXN_WASMCOMPILEERROR)},
{"LinkError", GetExceptionProtoKey(JSEXN_WASMLINKERROR)},

View File

@ -512,6 +512,40 @@ class WasmExceptionObject : public NativeObject {
wasm::ExceptionTag& tag() const;
};
// The class of WebAssembly.RuntimeException. This class is used for
// representing exceptions thrown from Wasm in JS. (it is also used as
// the internal representation for exceptions in Wasm)
class WasmRuntimeExceptionObject : public NativeObject {
static const unsigned TAG_SLOT = 0;
static const unsigned VALUES_SLOT = 1;
static const JSClassOps classOps_;
static const ClassSpec classSpec_;
static void finalize(JSFreeOp*, JSObject* obj);
static void trace(JSTracer* trc, JSObject* obj);
public:
static const unsigned RESERVED_SLOTS = 2;
static const JSClass class_;
static const JSClass& protoClass_;
static const JSPropertySpec properties[];
static const JSFunctionSpec methods[];
static const JSFunctionSpec static_methods[];
static bool construct(JSContext*, unsigned, Value*);
static WasmRuntimeExceptionObject* create(JSContext* cx,
wasm::SharedExceptionTag tag,
Handle<ArrayBufferObject*> values);
bool isNewborn() const;
wasm::ExceptionTag& tag() const;
static size_t offsetOfValues() {
return NativeObject::getFixedSlotOffset(VALUES_SLOT);
}
};
// The class of the WebAssembly global namespace object.
class WasmNamespaceObject : public NativeObject {

View File

@ -88,6 +88,9 @@ typedef GCVector<WasmExceptionObject*, 0, SystemAllocPolicy>
WasmExceptionObjectVector;
using RootedWasmExceptionObject = Rooted<WasmExceptionObject*>;
class WasmRuntimeExceptionObject;
using RootedWasmRuntimeExceptionObject = Rooted<WasmRuntimeExceptionObject*>;
namespace wasm {
using mozilla::Atomic;