Commit 0e546f54 authored by Thibaud Michaud's avatar Thibaud Michaud Committed by V8 LUCI CQ

[wasm] Add Suspender.returnPromiseOnSuspend

R=ahaas@chromium.org
CC=fgm@chromium.org

Bug: v8:12191
Change-Id: I415c4488262a97cf04b71fd8e96071c7bff972cf
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3231337Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
Cr-Commit-Position: refs/heads/main@{#77740}
parent 6745405f
......@@ -1422,29 +1422,5 @@ RUNTIME_FUNCTION(Runtime_Is64Bit) {
return isolate->heap()->ToBoolean(kSystemPointerSize == 8);
}
#if V8_ENABLE_WEBASSEMBLY
// TODO(thibaudm): Handle this in Suspender.returnPromiseOnSuspend() when
// the Suspender object is added.
RUNTIME_FUNCTION(Runtime_WasmReturnPromiseOnSuspend) {
CHECK(FLAG_experimental_wasm_stack_switching);
DCHECK_EQ(1, args.length());
HandleScope scope(isolate);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
SharedFunctionInfo sfi = function->shared();
// TODO(thibaudm): Throw an error if this is not a wasm function.
CHECK(sfi.HasWasmExportedFunctionData());
WasmExportedFunctionData data = sfi.wasm_exported_function_data();
int index = data.function_index();
Handle<WasmInstanceObject> instance(WasmInstanceObject::cast(data.ref()),
isolate);
auto wrapper =
isolate->builtins()->code_handle(Builtin::kWasmReturnPromiseOnSuspend);
auto result = Handle<WasmExternalFunction>::cast(WasmExportedFunction::New(
isolate, instance, index, static_cast<int>(data.sig()->parameter_count()),
wrapper));
return *result;
}
#endif
} // namespace internal
} // namespace v8
......@@ -594,7 +594,6 @@ namespace internal {
F(WasmAllocateRtt, 3, 1) \
F(WasmArrayCopy, 5, 1) \
F(WasmAllocateContinuation, 1, 1) \
F(WasmReturnPromiseOnSuspend, 1, 1) \
F(WasmSyncStackLimit, 1, 1)
#define FOR_EACH_INTRINSIC_WASM_TEST(F, I) \
......
......@@ -180,9 +180,7 @@ Local<String> v8_str(Isolate* isolate, const char* str) {
thrower->TypeError("Argument 0 must be a WebAssembly." #Type); \
return {}; \
} \
Local<Object> obj = Local<Object>::Cast(args[0]); \
return i::Handle<i::Wasm##Type##Object>::cast( \
v8::Utils::OpenHandle(*obj)); \
return i::Handle<i::Wasm##Type##Object>::cast(arg0); \
}
GET_FIRST_ARGUMENT_AS(Module)
......@@ -231,6 +229,16 @@ i::wasm::ModuleWireBytes GetFirstArgumentAsBytes(
return i::wasm::ModuleWireBytes(start, start + length);
}
i::MaybeHandle<i::JSFunction> GetFirstArgumentAsJSFunction(
const v8::FunctionCallbackInfo<v8::Value>& args, ErrorThrower* thrower) {
i::Handle<i::Object> arg0 = Utils::OpenHandle(*args[0]);
if (!arg0->IsJSFunction()) {
thrower->TypeError("Argument 0 must be a function");
return {};
}
return i::Handle<i::JSFunction>::cast(arg0);
}
i::MaybeHandle<i::JSReceiver> GetValueAsImports(Local<Value> arg,
ErrorThrower* thrower) {
if (arg->IsUndefined()) return {};
......@@ -2493,6 +2501,39 @@ void WebAssemblyGlobalType(const v8::FunctionCallbackInfo<v8::Value>& args) {
args.GetReturnValue().Set(Utils::ToLocal(type));
}
// WebAssembly.Suspender.returnPromiseOnSuspend(WebAssembly.Function) ->
// WebAssembly.Function
void WebAssemblySuspenderReturnPromiseOnSuspend(
const v8::FunctionCallbackInfo<v8::Value>& args) {
Isolate* isolate = args.GetIsolate();
HandleScope scope(isolate);
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
ScheduledErrorThrower thrower(
i_isolate, "WebAssembly.Suspender.returnPromiseOnSuspend()");
if (args.Length() == 0) {
thrower.TypeError("Argument 0 is required");
return;
}
auto maybe_function = GetFirstArgumentAsJSFunction(args, &thrower);
if (thrower.error()) return;
i::Handle<i::JSFunction> function = maybe_function.ToHandleChecked();
i::SharedFunctionInfo sfi = function->shared();
if (!sfi.HasWasmExportedFunctionData()) {
thrower.TypeError("Argument 0 must be a wasm function");
}
i::WasmExportedFunctionData data = sfi.wasm_exported_function_data();
int index = data.function_index();
i::Handle<i::WasmInstanceObject> instance(
i::WasmInstanceObject::cast(data.ref()), i_isolate);
i::Handle<i::Code> wrapper = i_isolate->builtins()->code_handle(
i::Builtin::kWasmReturnPromiseOnSuspend);
i::Handle<i::JSObject> result =
i::Handle<i::WasmExternalFunction>::cast(i::WasmExportedFunction::New(
i_isolate, instance, index,
static_cast<int>(data.sig()->parameter_count()), wrapper));
args.GetReturnValue().Set(Utils::ToLocal(result));
}
} // namespace
// TODO(titzer): we use the API to create the function template because the
......@@ -2784,9 +2825,11 @@ void WasmJs::Install(Isolate* isolate, bool exposed_on_global_object) {
Handle<JSFunction> suspender_constructor = InstallConstructorFunc(
isolate, webassembly, "Suspender", WebAssemblySuspender);
context->set_wasm_suspender_constructor(*suspender_constructor);
SetupConstructor(isolate, suspender_constructor,
i::WASM_SUSPENDER_OBJECT_TYPE,
WasmSuspenderObject::kHeaderSize, "WebAssembly.Suspender");
Handle<JSObject> suspender_proto = SetupConstructor(
isolate, suspender_constructor, i::WASM_SUSPENDER_OBJECT_TYPE,
WasmSuspenderObject::kHeaderSize, "WebAssembly.Suspender");
InstallFunc(isolate, suspender_proto, "returnPromiseOnSuspend",
WebAssemblySuspenderReturnPromiseOnSuspend, 1);
}
// Setup Function
......
......@@ -21,7 +21,8 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
builder.addFunction("test", kSig_v_v)
.addBody([kExprI32Const, 42, kExprGlobalSet, 0]).exportFunc();
let instance = builder.instantiate();
let wrapper = %WasmReturnPromiseOnSuspend(instance.exports.test);
let suspender = new WebAssembly.Suspender();
let wrapper = suspender.returnPromiseOnSuspend(instance.exports.test);
wrapper();
assertEquals(42, instance.exports.g.value);
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment