summaryrefslogtreecommitdiffstats
path: root/js/src/wasm/WasmJS.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/wasm/WasmJS.cpp')
-rw-r--r--js/src/wasm/WasmJS.cpp178
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)) {