[wasm] Add Suspender.suspendOnReturnedPromise
- Add Suspender.suspendOnReturnedPromise method - Extend the WasmApiFunctionRef data with the suspender - Detect wrapped WasmJSFunctions when we resolve the import For now the generated wrapper is still a regular wasm-to-js wrapper, but this sets the ground for generating specific wrappers for functions wrapped by suspendOnReturnedPromise, and to access the suspender from the wrapper code. R=ahaas@chromium.org CC=fgm@chromium.org Bug: v8:12191 Change-Id: I81cbec6b023507e47e6e1463b5f9b912f807da6a Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3345000 Reviewed-by: Andreas Haas <ahaas@chromium.org> Reviewed-by: Dominik Inführ <dinfuehr@chromium.org> Commit-Queue: Thibaud Michaud <thibaudm@chromium.org> Cr-Commit-Position: refs/heads/main@{#78560}
This commit is contained in:
parent
d82b4b6699
commit
5c829be17c
@ -7579,46 +7579,48 @@ std::unique_ptr<OptimizedCompilationJob> NewJSToWasmCompilationJob(
|
||||
std::move(debug_name), WasmAssemblerOptions());
|
||||
}
|
||||
|
||||
std::pair<WasmImportCallKind, Handle<JSReceiver>> ResolveWasmImportCall(
|
||||
WasmImportData ResolveWasmImportCall(
|
||||
Handle<JSReceiver> callable, const wasm::FunctionSig* expected_sig,
|
||||
const wasm::WasmModule* module,
|
||||
const wasm::WasmFeatures& enabled_features) {
|
||||
Isolate* isolate = callable->GetIsolate();
|
||||
Handle<HeapObject> no_suspender;
|
||||
if (WasmExportedFunction::IsWasmExportedFunction(*callable)) {
|
||||
auto imported_function = Handle<WasmExportedFunction>::cast(callable);
|
||||
if (!imported_function->MatchesSignature(module, expected_sig)) {
|
||||
return std::make_pair(WasmImportCallKind::kLinkError, callable);
|
||||
return {WasmImportCallKind::kLinkError, callable, no_suspender};
|
||||
}
|
||||
uint32_t func_index =
|
||||
static_cast<uint32_t>(imported_function->function_index());
|
||||
if (func_index >=
|
||||
imported_function->instance().module()->num_imported_functions) {
|
||||
return std::make_pair(WasmImportCallKind::kWasmToWasm, callable);
|
||||
return {WasmImportCallKind::kWasmToWasm, callable, no_suspender};
|
||||
}
|
||||
Isolate* isolate = callable->GetIsolate();
|
||||
// Resolve the shortcut to the underlying callable and continue.
|
||||
Handle<WasmInstanceObject> instance(imported_function->instance(), isolate);
|
||||
ImportedFunctionEntry entry(instance, func_index);
|
||||
callable = handle(entry.callable(), isolate);
|
||||
}
|
||||
Handle<HeapObject> suspender = isolate->factory()->undefined_value();
|
||||
if (WasmJSFunction::IsWasmJSFunction(*callable)) {
|
||||
auto js_function = Handle<WasmJSFunction>::cast(callable);
|
||||
if (!js_function->MatchesSignature(expected_sig)) {
|
||||
return std::make_pair(WasmImportCallKind::kLinkError, callable);
|
||||
return {WasmImportCallKind::kLinkError, callable, no_suspender};
|
||||
}
|
||||
Isolate* isolate = callable->GetIsolate();
|
||||
suspender = handle(js_function->GetSuspender(), isolate);
|
||||
// Resolve the short-cut to the underlying callable and continue.
|
||||
callable = handle(js_function->GetCallable(), isolate);
|
||||
}
|
||||
if (WasmCapiFunction::IsWasmCapiFunction(*callable)) {
|
||||
auto capi_function = Handle<WasmCapiFunction>::cast(callable);
|
||||
if (!capi_function->MatchesSignature(expected_sig)) {
|
||||
return std::make_pair(WasmImportCallKind::kLinkError, callable);
|
||||
return {WasmImportCallKind::kLinkError, callable, no_suspender};
|
||||
}
|
||||
return std::make_pair(WasmImportCallKind::kWasmToCapi, callable);
|
||||
return {WasmImportCallKind::kWasmToCapi, callable, no_suspender};
|
||||
}
|
||||
// Assuming we are calling to JS, check whether this would be a runtime error.
|
||||
if (!wasm::IsJSCompatibleSignature(expected_sig, module, enabled_features)) {
|
||||
return std::make_pair(WasmImportCallKind::kRuntimeTypeError, callable);
|
||||
return {WasmImportCallKind::kRuntimeTypeError, callable, no_suspender};
|
||||
}
|
||||
// For JavaScript calls, determine whether the target has an arity match.
|
||||
if (callable->IsJSFunction()) {
|
||||
@ -7634,7 +7636,7 @@ std::pair<WasmImportCallKind, Handle<JSReceiver>> ResolveWasmImportCall(
|
||||
if (!sig) sig = wasm::WasmOpcodes::AsmjsSignature(wasm::kExpr##name); \
|
||||
DCHECK_NOT_NULL(sig); \
|
||||
if (*expected_sig == *sig) { \
|
||||
return std::make_pair(WasmImportCallKind::k##name, callable); \
|
||||
return {WasmImportCallKind::k##name, callable, no_suspender}; \
|
||||
} \
|
||||
}
|
||||
#define COMPARE_SIG_FOR_BUILTIN_F64(name) \
|
||||
@ -7679,13 +7681,12 @@ std::pair<WasmImportCallKind, Handle<JSReceiver>> ResolveWasmImportCall(
|
||||
|
||||
if (IsClassConstructor(shared->kind())) {
|
||||
// Class constructor will throw anyway.
|
||||
return std::make_pair(WasmImportCallKind::kUseCallBuiltin, callable);
|
||||
return {WasmImportCallKind::kUseCallBuiltin, callable, suspender};
|
||||
}
|
||||
|
||||
if (shared->internal_formal_parameter_count_without_receiver() ==
|
||||
expected_sig->parameter_count()) {
|
||||
return std::make_pair(WasmImportCallKind::kJSFunctionArityMatch,
|
||||
callable);
|
||||
return {WasmImportCallKind::kJSFunctionArityMatch, callable, suspender};
|
||||
}
|
||||
|
||||
// If function isn't compiled, compile it now.
|
||||
@ -7696,11 +7697,10 @@ std::pair<WasmImportCallKind, Handle<JSReceiver>> ResolveWasmImportCall(
|
||||
&is_compiled_scope);
|
||||
}
|
||||
|
||||
return std::make_pair(WasmImportCallKind::kJSFunctionArityMismatch,
|
||||
callable);
|
||||
return {WasmImportCallKind::kJSFunctionArityMismatch, callable, suspender};
|
||||
}
|
||||
// Unknown case. Use the call builtin.
|
||||
return std::make_pair(WasmImportCallKind::kUseCallBuiltin, callable);
|
||||
return {WasmImportCallKind::kUseCallBuiltin, callable, suspender};
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -107,14 +107,19 @@ enum class WasmImportCallKind : uint8_t {
|
||||
constexpr WasmImportCallKind kDefaultImportCallKind =
|
||||
WasmImportCallKind::kJSFunctionArityMatch;
|
||||
|
||||
struct WasmImportData {
|
||||
WasmImportCallKind kind;
|
||||
Handle<JSReceiver> callable;
|
||||
Handle<HeapObject> suspender;
|
||||
};
|
||||
// Resolves which import call wrapper is required for the given JS callable.
|
||||
// Returns the kind of wrapper need and the ultimate target callable. Note that
|
||||
// some callables (e.g. a {WasmExportedFunction} or {WasmJSFunction}) just wrap
|
||||
// another target, which is why the ultimate target is returned as well.
|
||||
V8_EXPORT_PRIVATE std::pair<WasmImportCallKind, Handle<JSReceiver>>
|
||||
ResolveWasmImportCall(Handle<JSReceiver> callable, const wasm::FunctionSig* sig,
|
||||
const wasm::WasmModule* module,
|
||||
const wasm::WasmFeatures& enabled_features);
|
||||
// Returns the kind of wrapper needed, the ultimate target callable, and the
|
||||
// suspender object if applicable. Note that some callables (e.g. a
|
||||
// {WasmExportedFunction} or {WasmJSFunction}) just wrap another target, which
|
||||
// is why the ultimate target is returned as well.
|
||||
V8_EXPORT_PRIVATE WasmImportData ResolveWasmImportCall(
|
||||
Handle<JSReceiver> callable, const wasm::FunctionSig* sig,
|
||||
const wasm::WasmModule* module, const wasm::WasmFeatures& enabled_features);
|
||||
|
||||
// Compiles an import call wrapper, which allows Wasm to call imports.
|
||||
V8_EXPORT_PRIVATE wasm::WasmCompilationResult CompileWasmImportCallWrapper(
|
||||
|
@ -1946,6 +1946,7 @@ void WasmApiFunctionRef::WasmApiFunctionRefPrint(std::ostream& os) {
|
||||
os << "\n - isolate_root: " << reinterpret_cast<void*>(isolate_root());
|
||||
os << "\n - native_context: " << Brief(native_context());
|
||||
os << "\n - callable: " << Brief(callable());
|
||||
os << "\n - suspender: " << Brief(suspender());
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
|
@ -1523,7 +1523,7 @@ Handle<WasmTypeInfo> Factory::NewWasmTypeInfo(
|
||||
}
|
||||
|
||||
Handle<WasmApiFunctionRef> Factory::NewWasmApiFunctionRef(
|
||||
Handle<JSReceiver> callable) {
|
||||
Handle<JSReceiver> callable, Handle<HeapObject> suspender) {
|
||||
Map map = *wasm_api_function_ref_map();
|
||||
auto result = WasmApiFunctionRef::cast(AllocateRawWithImmortalMap(
|
||||
map.instance_size(), AllocationType::kOld, map));
|
||||
@ -1535,6 +1535,11 @@ Handle<WasmApiFunctionRef> Factory::NewWasmApiFunctionRef(
|
||||
} else {
|
||||
result.set_callable(*undefined_value());
|
||||
}
|
||||
if (!suspender.is_null()) {
|
||||
result.set_suspender(*suspender);
|
||||
} else {
|
||||
result.set_suspender(*undefined_value());
|
||||
}
|
||||
return handle(result, isolate());
|
||||
}
|
||||
|
||||
@ -1556,8 +1561,8 @@ Handle<WasmInternalFunction> Factory::NewWasmInternalFunction(
|
||||
Handle<WasmJSFunctionData> Factory::NewWasmJSFunctionData(
|
||||
Address opt_call_target, Handle<JSReceiver> callable, int return_count,
|
||||
int parameter_count, Handle<PodArray<wasm::ValueType>> serialized_sig,
|
||||
Handle<CodeT> wrapper_code, Handle<Map> rtt) {
|
||||
Handle<WasmApiFunctionRef> ref = NewWasmApiFunctionRef(callable);
|
||||
Handle<CodeT> wrapper_code, Handle<Map> rtt, Handle<HeapObject> suspender) {
|
||||
Handle<WasmApiFunctionRef> ref = NewWasmApiFunctionRef(callable, suspender);
|
||||
Handle<WasmInternalFunction> internal =
|
||||
NewWasmInternalFunction(opt_call_target, ref, rtt);
|
||||
Map map = *wasm_js_function_data_map();
|
||||
@ -1602,7 +1607,8 @@ Handle<WasmCapiFunctionData> Factory::NewWasmCapiFunctionData(
|
||||
Address call_target, Handle<Foreign> embedder_data,
|
||||
Handle<CodeT> wrapper_code, Handle<Map> rtt,
|
||||
Handle<PodArray<wasm::ValueType>> serialized_sig) {
|
||||
Handle<WasmApiFunctionRef> ref = NewWasmApiFunctionRef(Handle<JSReceiver>());
|
||||
Handle<WasmApiFunctionRef> ref =
|
||||
NewWasmApiFunctionRef(Handle<JSReceiver>(), Handle<HeapObject>());
|
||||
Handle<WasmInternalFunction> internal =
|
||||
NewWasmInternalFunction(call_target, ref, rtt);
|
||||
Map map = *wasm_capi_function_data_map();
|
||||
|
@ -604,13 +604,15 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
|
||||
Handle<CodeT> export_wrapper, Handle<WasmInstanceObject> instance,
|
||||
Address call_target, Handle<Object> ref, int func_index,
|
||||
Address sig_address, int wrapper_budget, Handle<Map> rtt);
|
||||
Handle<WasmApiFunctionRef> NewWasmApiFunctionRef(Handle<JSReceiver> callable);
|
||||
Handle<WasmApiFunctionRef> NewWasmApiFunctionRef(
|
||||
Handle<JSReceiver> callable, Handle<HeapObject> suspender);
|
||||
// {opt_call_target} is kNullAddress for JavaScript functions, and
|
||||
// non-null for exported Wasm functions.
|
||||
Handle<WasmJSFunctionData> NewWasmJSFunctionData(
|
||||
Address opt_call_target, Handle<JSReceiver> callable, int return_count,
|
||||
int parameter_count, Handle<PodArray<wasm::ValueType>> serialized_sig,
|
||||
Handle<CodeT> wrapper_code, Handle<Map> rtt);
|
||||
Handle<CodeT> wrapper_code, Handle<Map> rtt,
|
||||
Handle<HeapObject> suspender);
|
||||
Handle<WasmStruct> NewWasmStruct(const wasm::StructType* type,
|
||||
wasm::WasmValue* args, Handle<Map> map);
|
||||
Handle<WasmArray> NewWasmArray(const wasm::ArrayType* type,
|
||||
|
@ -1181,8 +1181,8 @@ bool InstanceBuilder::ProcessImportedFunction(
|
||||
const FunctionSig* expected_sig = module_->functions[func_index].sig;
|
||||
auto resolved = compiler::ResolveWasmImportCall(js_receiver, expected_sig,
|
||||
module_, enabled_);
|
||||
compiler::WasmImportCallKind kind = resolved.first;
|
||||
js_receiver = resolved.second;
|
||||
compiler::WasmImportCallKind kind = resolved.kind;
|
||||
js_receiver = resolved.callable;
|
||||
switch (kind) {
|
||||
case compiler::WasmImportCallKind::kLinkError:
|
||||
ReportLinkError("imported function does not match the expected type",
|
||||
@ -1224,7 +1224,8 @@ bool InstanceBuilder::ProcessImportedFunction(
|
||||
ImportedFunctionEntry entry(instance, func_index);
|
||||
// We re-use the SetWasmToJs infrastructure because it passes the
|
||||
// callable to the wrapper, which we need to get the function data.
|
||||
entry.SetWasmToJs(isolate_, js_receiver, wasm_code);
|
||||
entry.SetWasmToJs(isolate_, js_receiver, wasm_code,
|
||||
isolate_->factory()->undefined_value());
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@ -1245,7 +1246,7 @@ bool InstanceBuilder::ProcessImportedFunction(
|
||||
ImportedFunctionEntry entry(instance, func_index);
|
||||
if (wasm_code->kind() == WasmCode::kWasmToJsWrapper) {
|
||||
// Wasm to JS wrappers are treated specially in the import table.
|
||||
entry.SetWasmToJs(isolate_, js_receiver, wasm_code);
|
||||
entry.SetWasmToJs(isolate_, js_receiver, wasm_code, resolved.suspender);
|
||||
} else {
|
||||
// Wasm math intrinsics are compiled as regular Wasm functions.
|
||||
DCHECK(kind >= compiler::WasmImportCallKind::kFirstMathIntrinsic &&
|
||||
@ -1634,7 +1635,7 @@ void InstanceBuilder::CompileImportWrappers(
|
||||
const FunctionSig* sig = module_->functions[func_index].sig;
|
||||
auto resolved =
|
||||
compiler::ResolveWasmImportCall(js_receiver, sig, module_, enabled_);
|
||||
compiler::WasmImportCallKind kind = resolved.first;
|
||||
compiler::WasmImportCallKind kind = resolved.kind;
|
||||
if (kind == compiler::WasmImportCallKind::kWasmToWasm ||
|
||||
kind == compiler::WasmImportCallKind::kLinkError ||
|
||||
kind == compiler::WasmImportCallKind::kWasmToCapi) {
|
||||
@ -1642,9 +1643,9 @@ void InstanceBuilder::CompileImportWrappers(
|
||||
}
|
||||
|
||||
int expected_arity = static_cast<int>(sig->parameter_count());
|
||||
if (resolved.first ==
|
||||
if (resolved.kind ==
|
||||
compiler::WasmImportCallKind::kJSFunctionArityMismatch) {
|
||||
Handle<JSFunction> function = Handle<JSFunction>::cast(resolved.second);
|
||||
Handle<JSFunction> function = Handle<JSFunction>::cast(resolved.callable);
|
||||
SharedFunctionInfo shared = function->shared();
|
||||
expected_arity =
|
||||
shared.internal_formal_parameter_count_without_receiver();
|
||||
|
@ -25,9 +25,11 @@
|
||||
#include "src/init/v8.h"
|
||||
#include "src/objects/fixed-array.h"
|
||||
#include "src/objects/instance-type.h"
|
||||
#include "src/objects/js-function.h"
|
||||
#include "src/objects/js-promise-inl.h"
|
||||
#include "src/objects/managed-inl.h"
|
||||
#include "src/objects/objects-inl.h"
|
||||
#include "src/objects/shared-function-info.h"
|
||||
#include "src/objects/templates.h"
|
||||
#include "src/parsing/parse-info.h"
|
||||
#include "src/tasks/task-utils.h"
|
||||
@ -1894,8 +1896,10 @@ void WebAssemblyFunction(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
return;
|
||||
}
|
||||
|
||||
i::Handle<i::HeapObject> suspender =
|
||||
handle(i::ReadOnlyRoots(i_isolate).undefined_value(), i_isolate);
|
||||
i::Handle<i::JSFunction> result =
|
||||
i::WasmJSFunction::New(i_isolate, sig, callable);
|
||||
i::WasmJSFunction::New(i_isolate, sig, callable, suspender);
|
||||
args.GetReturnValue().Set(Utils::ToLocal(result));
|
||||
}
|
||||
|
||||
@ -1925,6 +1929,7 @@ void WebAssemblyFunctionType(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
constexpr const char* kName_WasmGlobalObject = "WebAssembly.Global";
|
||||
constexpr const char* kName_WasmMemoryObject = "WebAssembly.Memory";
|
||||
constexpr const char* kName_WasmInstanceObject = "WebAssembly.Instance";
|
||||
constexpr const char* kName_WasmSuspenderObject = "WebAssembly.Suspender";
|
||||
constexpr const char* kName_WasmTableObject = "WebAssembly.Table";
|
||||
constexpr const char* kName_WasmTagObject = "WebAssembly.Tag";
|
||||
constexpr const char* kName_WasmExceptionPackage = "WebAssembly.Exception";
|
||||
@ -2580,6 +2585,38 @@ void WebAssemblySuspenderReturnPromiseOnSuspend(
|
||||
args.GetReturnValue().Set(Utils::ToLocal(result));
|
||||
}
|
||||
|
||||
// WebAssembly.Suspender.suspendOnReturnedPromise(Function) -> Function
|
||||
void WebAssemblySuspenderSuspendOnReturnedPromise(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
v8::Isolate* isolate = args.GetIsolate();
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
HandleScope scope(isolate);
|
||||
ScheduledErrorThrower thrower(
|
||||
i_isolate, "WebAssembly.Suspender.suspendOnReturnedPromise()");
|
||||
if (!args[0]->IsObject()) {
|
||||
thrower.TypeError("Argument 0 must be a WebAssembly.Function");
|
||||
return;
|
||||
}
|
||||
i::Zone zone(i_isolate->allocator(), ZONE_NAME);
|
||||
const i::wasm::FunctionSig* sig;
|
||||
i::Handle<i::Object> arg0 = Utils::OpenHandle(*args[0]);
|
||||
|
||||
if (i::WasmExportedFunction::IsWasmExportedFunction(*arg0)) {
|
||||
// TODO(thibaudm): Suspend on wrapped wasm-to-wasm calls too.
|
||||
UNIMPLEMENTED();
|
||||
} else if (!i::WasmJSFunction::IsWasmJSFunction(*arg0)) {
|
||||
thrower.TypeError("Argument 0 must be a WebAssembly.Function");
|
||||
return;
|
||||
}
|
||||
sig = i::Handle<i::WasmJSFunction>::cast(arg0)->GetSignature(&zone);
|
||||
|
||||
auto callable = handle(
|
||||
i::Handle<i::WasmJSFunction>::cast(arg0)->GetCallable(), i_isolate);
|
||||
EXTRACT_THIS(suspender, WasmSuspenderObject);
|
||||
i::Handle<i::JSFunction> result =
|
||||
i::WasmJSFunction::New(i_isolate, sig, callable, suspender);
|
||||
args.GetReturnValue().Set(Utils::ToLocal(result));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// TODO(titzer): we use the API to create the function template because the
|
||||
@ -2876,6 +2913,8 @@ void WasmJs::Install(Isolate* isolate, bool exposed_on_global_object) {
|
||||
WasmSuspenderObject::kHeaderSize, "WebAssembly.Suspender");
|
||||
InstallFunc(isolate, suspender_proto, "returnPromiseOnSuspend",
|
||||
WebAssemblySuspenderReturnPromiseOnSuspend, 1);
|
||||
InstallFunc(isolate, suspender_proto, "suspendOnReturnedPromise",
|
||||
WebAssemblySuspenderSuspendOnReturnedPromise, 1);
|
||||
}
|
||||
|
||||
// Setup Function
|
||||
|
@ -1076,7 +1076,7 @@ FunctionTargetAndRef::FunctionTargetAndRef(
|
||||
|
||||
void ImportedFunctionEntry::SetWasmToJs(
|
||||
Isolate* isolate, Handle<JSReceiver> callable,
|
||||
const wasm::WasmCode* wasm_to_js_wrapper) {
|
||||
const wasm::WasmCode* wasm_to_js_wrapper, Handle<HeapObject> suspender) {
|
||||
TRACE_IFT("Import callable 0x%" PRIxPTR "[%d] = {callable=0x%" PRIxPTR
|
||||
", target=%p}\n",
|
||||
instance_->ptr(), index_, callable->ptr(),
|
||||
@ -1084,7 +1084,7 @@ void ImportedFunctionEntry::SetWasmToJs(
|
||||
DCHECK(wasm_to_js_wrapper->kind() == wasm::WasmCode::kWasmToJsWrapper ||
|
||||
wasm_to_js_wrapper->kind() == wasm::WasmCode::kWasmToCapiWrapper);
|
||||
Handle<WasmApiFunctionRef> ref =
|
||||
isolate->factory()->NewWasmApiFunctionRef(callable);
|
||||
isolate->factory()->NewWasmApiFunctionRef(callable, suspender);
|
||||
instance_->imported_function_refs().set(index_, *ref);
|
||||
instance_->imported_function_targets()[index_] =
|
||||
wasm_to_js_wrapper->instruction_start();
|
||||
@ -1448,8 +1448,8 @@ void WasmInstanceObject::ImportWasmJSFunctionIntoTable(
|
||||
const wasm::WasmFeatures enabled = native_module->enabled_features();
|
||||
auto resolved = compiler::ResolveWasmImportCall(
|
||||
callable, sig, instance->module(), enabled);
|
||||
compiler::WasmImportCallKind kind = resolved.first;
|
||||
callable = resolved.second; // Update to ultimate target.
|
||||
compiler::WasmImportCallKind kind = resolved.kind;
|
||||
callable = resolved.callable; // Update to ultimate target.
|
||||
DCHECK_NE(compiler::WasmImportCallKind::kLinkError, kind);
|
||||
wasm::CompilationEnv env = native_module->CreateCompilationEnv();
|
||||
// {expected_arity} should only be used if kind != kJSFunctionArityMismatch.
|
||||
@ -1479,8 +1479,9 @@ void WasmInstanceObject::ImportWasmJSFunctionIntoTable(
|
||||
}
|
||||
|
||||
// Update the dispatch table.
|
||||
Handle<HeapObject> suspender = handle(js_function->GetSuspender(), isolate);
|
||||
Handle<WasmApiFunctionRef> ref =
|
||||
isolate->factory()->NewWasmApiFunctionRef(callable);
|
||||
isolate->factory()->NewWasmApiFunctionRef(callable, suspender);
|
||||
WasmIndirectFunctionTable::cast(
|
||||
instance->indirect_function_tables().get(table_index))
|
||||
.Set(entry_index, sig_id, call_target, *ref);
|
||||
@ -2031,7 +2032,8 @@ bool WasmJSFunction::IsWasmJSFunction(Object object) {
|
||||
|
||||
Handle<WasmJSFunction> WasmJSFunction::New(Isolate* isolate,
|
||||
const wasm::FunctionSig* sig,
|
||||
Handle<JSReceiver> callable) {
|
||||
Handle<JSReceiver> callable,
|
||||
Handle<HeapObject> suspender) {
|
||||
DCHECK_LE(sig->all().size(), kMaxInt);
|
||||
int sig_size = static_cast<int>(sig->all().size());
|
||||
int return_count = static_cast<int>(sig->return_count());
|
||||
@ -2061,7 +2063,7 @@ Handle<WasmJSFunction> WasmJSFunction::New(Isolate* isolate,
|
||||
Handle<Map> rtt = factory->wasm_internal_function_map();
|
||||
Handle<WasmJSFunctionData> function_data = factory->NewWasmJSFunctionData(
|
||||
call_target, callable, return_count, parameter_count, serialized_sig,
|
||||
wrapper_code, rtt);
|
||||
wrapper_code, rtt, suspender);
|
||||
|
||||
if (wasm::WasmFeatures::FromIsolate(isolate).has_typed_funcref()) {
|
||||
using CK = compiler::WasmImportCallKind;
|
||||
@ -2108,6 +2110,12 @@ JSReceiver WasmJSFunction::GetCallable() const {
|
||||
.callable());
|
||||
}
|
||||
|
||||
HeapObject WasmJSFunction::GetSuspender() const {
|
||||
return WasmApiFunctionRef::cast(
|
||||
shared().wasm_js_function_data().internal().ref())
|
||||
.suspender();
|
||||
}
|
||||
|
||||
const wasm::FunctionSig* WasmJSFunction::GetSignature(Zone* zone) {
|
||||
WasmJSFunctionData function_data = shared().wasm_js_function_data();
|
||||
int sig_size = function_data.serialized_signature().length();
|
||||
|
@ -91,7 +91,8 @@ class ImportedFunctionEntry {
|
||||
// Initialize this entry as a Wasm to JS call. This accepts the isolate as a
|
||||
// parameter, since it must allocate a tuple.
|
||||
V8_EXPORT_PRIVATE void SetWasmToJs(Isolate*, Handle<JSReceiver> callable,
|
||||
const wasm::WasmCode* wasm_to_js_wrapper);
|
||||
const wasm::WasmCode* wasm_to_js_wrapper,
|
||||
Handle<HeapObject> suspender);
|
||||
// Initialize this entry as a Wasm to Wasm call.
|
||||
void SetWasmToWasm(WasmInstanceObject target_instance, Address call_target);
|
||||
|
||||
@ -622,9 +623,11 @@ class WasmJSFunction : public JSFunction {
|
||||
|
||||
static Handle<WasmJSFunction> New(Isolate* isolate,
|
||||
const wasm::FunctionSig* sig,
|
||||
Handle<JSReceiver> callable);
|
||||
Handle<JSReceiver> callable,
|
||||
Handle<HeapObject> suspender);
|
||||
|
||||
JSReceiver GetCallable() const;
|
||||
HeapObject GetSuspender() const;
|
||||
// Deserializes the signature of this function using the provided zone. Note
|
||||
// that lifetime of the signature is hence directly coupled to the zone.
|
||||
const wasm::FunctionSig* GetSignature(Zone* zone);
|
||||
|
@ -21,6 +21,7 @@ extern class WasmApiFunctionRef extends HeapObject {
|
||||
isolate_root: RawPtr;
|
||||
native_context: NativeContext;
|
||||
callable: JSReceiver|Undefined;
|
||||
suspender: WasmSuspenderObject|Undefined;
|
||||
}
|
||||
|
||||
// This is the representation that is used internally by wasm to represent
|
||||
|
@ -73,8 +73,8 @@ TestingModuleBuilder::TestingModuleBuilder(
|
||||
auto resolved = compiler::ResolveWasmImportCall(
|
||||
maybe_import->js_function, maybe_import->sig,
|
||||
instance_object_->module(), enabled_features_);
|
||||
compiler::WasmImportCallKind kind = resolved.first;
|
||||
Handle<JSReceiver> callable = resolved.second;
|
||||
compiler::WasmImportCallKind kind = resolved.kind;
|
||||
Handle<JSReceiver> callable = resolved.callable;
|
||||
WasmImportWrapperCache::ModificationScope cache_scope(
|
||||
native_module_->import_wrapper_cache());
|
||||
WasmImportWrapperCache::CacheKey key(
|
||||
@ -89,7 +89,7 @@ TestingModuleBuilder::TestingModuleBuilder(
|
||||
}
|
||||
|
||||
ImportedFunctionEntry(instance_object_, maybe_import_index)
|
||||
.SetWasmToJs(isolate_, callable, import_wrapper);
|
||||
.SetWasmToJs(isolate_, callable, import_wrapper, resolved.suspender);
|
||||
}
|
||||
|
||||
if (tier == TestExecutionTier::kInterpreter) {
|
||||
|
@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax --experimental-wasm-stack-switching --expose-gc
|
||||
// Flags: --allow-natives-syntax --experimental-wasm-stack-switching
|
||||
// Flags: --experimental-wasm-type-reflection --expose-gc
|
||||
|
||||
load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
|
||||
@ -27,6 +28,31 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
assertEquals(42, instance.exports.g.value);
|
||||
})();
|
||||
|
||||
(function TestStackSwitchSuspend() {
|
||||
print(arguments.callee.name);
|
||||
let builder = new WasmModuleBuilder();
|
||||
builder.addGlobal(kWasmI32, true).exportAs('g');
|
||||
import_index = builder.addImport('m', 'import', kSig_i_v);
|
||||
builder.addFunction("test", kSig_v_v)
|
||||
.addBody([
|
||||
kExprCallFunction, import_index, // suspend
|
||||
kExprGlobalSet, 0 // resume
|
||||
]).exportFunc();
|
||||
let suspender = new WebAssembly.Suspender();
|
||||
function js_import() {
|
||||
// TODO(thibaudm): Return the value as a promise.
|
||||
return 42;
|
||||
};
|
||||
let wasm_js_import = new WebAssembly.Function({parameters: [], results: ['i32']}, js_import);
|
||||
let suspending_wasm_js_import = suspender.suspendOnReturnedPromise(wasm_js_import);
|
||||
let instance = builder.instantiate({m: {import: suspending_wasm_js_import}});
|
||||
let wrapped_export = suspender.returnPromiseOnSuspend(instance.exports.test);
|
||||
let combined_promise = wrapped_export();
|
||||
// TODO(thibaudm): Once we generate the actual wrapper, we expect 0 here
|
||||
// The global will only be set after the promise resolves.
|
||||
assertEquals(42, instance.exports.g.value);
|
||||
})();
|
||||
|
||||
(function TestStackSwitchGC() {
|
||||
print(arguments.callee.name);
|
||||
let builder = new WasmModuleBuilder();
|
||||
|
Loading…
Reference in New Issue
Block a user