diff options
Diffstat (limited to 'js/src/wasm/WasmJS.cpp')
-rw-r--r-- | js/src/wasm/WasmJS.cpp | 178 |
1 files changed, 177 insertions, 1 deletions
diff --git a/js/src/wasm/WasmJS.cpp b/js/src/wasm/WasmJS.cpp index d987ecec29..8a7e967a80 100644 --- a/js/src/wasm/WasmJS.cpp +++ b/js/src/wasm/WasmJS.cpp @@ -68,6 +68,7 @@ #include "wasm/WasmIonCompile.h" #include "wasm/WasmMemory.h" #include "wasm/WasmModule.h" +#include "wasm/WasmPI.h" #include "wasm/WasmProcess.h" #include "wasm/WasmSignalHandlers.h" #include "wasm/WasmStubs.h" @@ -139,6 +140,10 @@ static bool IsCallableNonCCW(const Value& v) { return IsCallable(v) && !IsCrossCompartmentWrapper(&v.toObject()); } +static bool IsWasmSuspendingWrapper(const Value& v) { + return v.isObject() && js::IsWasmSuspendingObject(&v.toObject()); +} + bool js::wasm::GetImports(JSContext* cx, const Module& module, HandleObject importObj, ImportValues* imports) { if (!module.imports().empty() && !importObj) { @@ -207,7 +212,8 @@ bool js::wasm::GetImports(JSContext* cx, const Module& module, switch (import.kind) { case DefinitionKind::Function: { - if (!IsCallableNonCCW(importFieldValue)) { + if (!IsCallableNonCCW(importFieldValue) && + !IsWasmSuspendingWrapper(importFieldValue)) { return ThrowBadImportType(cx, import.field, "Function"); } @@ -4225,6 +4231,66 @@ bool WasmFunctionConstruct(JSContext* cx, unsigned argc, Value* vp) { return false; } +# ifdef ENABLE_WASM_JSPI + // Check suspeding and promising + SuspenderArgPosition suspending = SuspenderArgPosition::None; + SuspenderArgPosition promising = SuspenderArgPosition::None; + if (wasm::JSPromiseIntegrationAvailable(cx) && args.length() > 2 && + args[2].isObject()) { + RootedObject usageObj(cx, &args[2].toObject()); + RootedValue val(cx); + if (!JS_GetProperty(cx, usageObj, "suspending", &val)) { + return false; + } + if (!ParseSuspendingPromisingString(cx, val, suspending)) { + return false; + } + if (!JS_GetProperty(cx, usageObj, "promising", &val)) { + return false; + } + if (!ParseSuspendingPromisingString(cx, val, promising)) { + return false; + } + } + + if (suspending > SuspenderArgPosition::None) { + if (!IsCallableNonCCW(args[1])) { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, + JSMSG_WASM_BAD_FUNCTION_VALUE); + return false; + } + + RootedObject func(cx, &args[1].toObject()); + RootedFunction suspend( + cx, WasmSuspendingFunctionCreate(cx, func, std::move(params), + std::move(results), suspending)); + if (!suspend) { + return false; + } + args.rval().setObject(*suspend); + + return true; + } + if (promising > SuspenderArgPosition::None) { + if (!IsWasmFunction(args[1])) { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, + JSMSG_WASM_BAD_FUNCTION_VALUE); + return false; + } + + RootedObject func(cx, &args[1].toObject()); + RootedFunction promise( + cx, WasmPromisingFunctionCreate(cx, func, std::move(params), + std::move(results), promising)); + if (!promise) { + return false; + } + args.rval().setObject(*promise); + + return true; + } +# endif // ENABLE_WASM_JSPI + // Get the target function if (!IsCallableNonCCW(args[1]) || IsWasmFunction(args[1])) { @@ -5291,6 +5357,91 @@ static bool WebAssembly_instantiateStreaming(JSContext* cx, unsigned argc, return true; } +#ifdef ENABLE_WASM_JSPI +const ClassSpec WasmSuspendingObject::classSpec_ = { + GenericCreateConstructor<construct, 1, gc::AllocKind::FUNCTION>, + GenericCreatePrototype<WasmSuspendingObject>, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + ClassSpec::DontDefineConstructor}; + +const JSClass WasmSuspendingObject::class_ = { + "Suspending", + JSCLASS_HAS_RESERVED_SLOTS(WasmSuspendingObject::RESERVED_SLOTS), + JS_NULL_CLASS_OPS, &classSpec_}; + +const JSClass& WasmSuspendingObject::protoClass_ = PlainObject::class_; + +/* static */ +bool WasmSuspendingObject::construct(JSContext* cx, unsigned argc, Value* vp) { + CallArgs args = CallArgsFromVp(argc, vp); + + if (!args.requireAtLeast(cx, "WebAssembly.Suspending", 1)) { + return false; + } + + if (!IsCallableNonCCW(args[0])) { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, + JSMSG_WASM_BAD_FUNCTION_VALUE); + return false; + } + + RootedObject callable(cx, &args[0].toObject()); + Rooted<WasmSuspendingObject*> suspending( + cx, NewBuiltinClassInstance<WasmSuspendingObject>(cx)); + if (!suspending) { + return false; + } + suspending->setWrappedFunction(callable); + args.rval().setObject(*suspending); + return true; +} + +static bool WebAssembly_promising(JSContext* cx, unsigned argc, Value* vp) { + CallArgs args = CallArgsFromVp(argc, vp); + + if (!args.requireAtLeast(cx, "WebAssembly.promising", 1)) { + return false; + } + + if (!IsWasmFunction(args[0])) { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, + JSMSG_WASM_BAD_FUNCTION_VALUE); + return false; + } + + RootedObject func(cx, &args[0].toObject()); + RootedFunction promise( + cx, WasmPromisingFunctionCreate(cx, func, wasm::ValTypeVector(), + wasm::ValTypeVector(), + SuspenderArgPosition::None)); + if (!promise) { + return false; + } + args.rval().setObject(*promise); + return true; +} + +static const JSFunctionSpec WebAssembly_jspi_methods[] = { + JS_FN("promising", WebAssembly_promising, 1, JSPROP_ENUMERATE), JS_FS_END}; + +bool js::IsWasmSuspendingObject(JSObject* obj) { + return obj->is<WasmSuspendingObject>(); +} + +JSObject* js::MaybeUnwrapSuspendingObject(JSObject* wrapper) { + if (!wrapper->is<WasmSuspendingObject>()) { + return nullptr; + } + return wrapper->as<WasmSuspendingObject>().wrappedFunction(); +} +#else +bool js::IsWasmSuspendingObject(JSObject* obj) { return false; } +#endif // ENABLE_WASM_JSPI + #ifdef ENABLE_WASM_MOZ_INTGEMM static bool WebAssembly_mozIntGemm(JSContext* cx, unsigned argc, Value* vp) { @@ -5410,6 +5561,31 @@ static bool WebAssemblyClassFinish(JSContext* cx, HandleObject object, wasm->setWrappedJSValueTag(wrappedJSValueTagObject); + if (ExnRefAvailable(cx)) { + RootedId jsTagName(cx, NameToId(cx->names().jsTag)); + RootedValue jsTagValue(cx, ObjectValue(*wrappedJSValueTagObject)); + if (!DefineDataProperty(cx, wasm, jsTagName, jsTagValue, + JSPROP_READONLY | JSPROP_ENUMERATE)) { + return false; + } + } + +#ifdef ENABLE_WASM_JSPI + constexpr NameAndProtoKey jspiEntries[] = { + {"Suspending", JSProto_WasmSuspending}, + }; + if (JSPromiseIntegrationAvailable(cx)) { + if (!JS_DefineFunctions(cx, wasm, WebAssembly_jspi_methods)) { + return false; + } + for (const auto& entry : jspiEntries) { + if (!WebAssemblyDefineConstructor(cx, wasm, entry, &ctorValue, &id)) { + return false; + } + } + } +#endif + #ifdef ENABLE_WASM_MOZ_INTGEMM if (MozIntGemmAvailable(cx) && !JS_DefineFunctions(cx, wasm, WebAssembly_mozIntGemm_methods)) { |