[wasm] Add WebAssembly.Suspender object
R=ahaas@chromium.org Bug: v8:12191 Change-Id: I15a5507a7dd0f02a3bbe9d3ce200206adf4d4539 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3231075 Commit-Queue: Thibaud Michaud <thibaudm@chromium.org> Reviewed-by: Andreas Haas <ahaas@chromium.org> Reviewed-by: Dominik Inführ <dinfuehr@chromium.org> Cr-Commit-Position: refs/heads/main@{#77734}
This commit is contained in:
parent
f0e5e3b282
commit
cce7154d57
@ -1852,6 +1852,12 @@ void WasmContinuationObject::WasmContinuationObjectPrint(std::ostream& os) {
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
void WasmSuspenderObject::WasmSuspenderObjectPrint(std::ostream& os) {
|
||||
PrintHeader(os, "WasmSuspenderObject");
|
||||
os << "\n - continuation: " << continuation();
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
void WasmInstanceObject::WasmInstanceObjectPrint(std::ostream& os) {
|
||||
JSObjectPrintHeader(os, *this, "WasmInstanceObject");
|
||||
os << "\n - module_object: " << Brief(module_object());
|
||||
|
@ -59,6 +59,7 @@ namespace internal {
|
||||
IF_WASM(V, WasmJSFunctionData) \
|
||||
IF_WASM(V, WasmApiFunctionRef) \
|
||||
IF_WASM(V, WasmStruct) \
|
||||
IF_WASM(V, WasmSuspenderObject) \
|
||||
IF_WASM(V, WasmTypeInfo)
|
||||
|
||||
#define FORWARD_DECLARE(TypeName) class TypeName;
|
||||
|
@ -312,6 +312,7 @@ enum ContextLookupFlags {
|
||||
V(WASM_MEMORY_CONSTRUCTOR_INDEX, JSFunction, wasm_memory_constructor) \
|
||||
V(WASM_MODULE_CONSTRUCTOR_INDEX, JSFunction, wasm_module_constructor) \
|
||||
V(WASM_TABLE_CONSTRUCTOR_INDEX, JSFunction, wasm_table_constructor) \
|
||||
V(WASM_SUSPENDER_CONSTRUCTOR_INDEX, JSFunction, wasm_suspender_constructor) \
|
||||
V(TEMPLATE_WEAKMAP_INDEX, HeapObject, template_weakmap) \
|
||||
V(TYPED_ARRAY_FUN_INDEX, JSFunction, typed_array_function) \
|
||||
V(TYPED_ARRAY_PROTOTYPE_INDEX, JSObject, typed_array_prototype) \
|
||||
|
@ -2372,6 +2372,8 @@ int JSObject::GetHeaderSize(InstanceType type,
|
||||
return WasmMemoryObject::kHeaderSize;
|
||||
case WASM_MODULE_OBJECT_TYPE:
|
||||
return WasmModuleObject::kHeaderSize;
|
||||
case WASM_SUSPENDER_OBJECT_TYPE:
|
||||
return WasmSuspenderObject::kHeaderSize;
|
||||
case WASM_TABLE_OBJECT_TYPE:
|
||||
return WasmTableObject::kHeaderSize;
|
||||
case WASM_VALUE_OBJECT_TYPE:
|
||||
|
@ -374,6 +374,8 @@ VisitorId Map::GetVisitorId(Map map) {
|
||||
return kVisitWasmExportedFunctionData;
|
||||
case WASM_CAPI_FUNCTION_DATA_TYPE:
|
||||
return kVisitWasmCapiFunctionData;
|
||||
case WASM_SUSPENDER_OBJECT_TYPE:
|
||||
return kVisitWasmSuspenderObject;
|
||||
#endif // V8_ENABLE_WEBASSEMBLY
|
||||
|
||||
#define MAKE_TQ_CASE(TYPE, Name) \
|
||||
|
@ -77,6 +77,7 @@ enum InstanceType : uint16_t;
|
||||
IF_WASM(V, WasmJSFunctionData) \
|
||||
IF_WASM(V, WasmApiFunctionRef) \
|
||||
IF_WASM(V, WasmStruct) \
|
||||
IF_WASM(V, WasmSuspenderObject) \
|
||||
IF_WASM(V, WasmTypeInfo) \
|
||||
V(WeakCell)
|
||||
|
||||
|
@ -242,6 +242,7 @@ class ZoneForwardList;
|
||||
IF_WASM(V, WasmTypeInfo) \
|
||||
IF_WASM(V, WasmTableObject) \
|
||||
IF_WASM(V, WasmValueObject) \
|
||||
IF_WASM(V, WasmSuspenderObject) \
|
||||
V(WeakFixedArray) \
|
||||
V(WeakArrayList) \
|
||||
V(WeakCell) \
|
||||
|
@ -1162,11 +1162,12 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) {
|
||||
case JS_SEGMENTS_TYPE:
|
||||
#endif // V8_INTL_SUPPORT
|
||||
#if V8_ENABLE_WEBASSEMBLY
|
||||
case WASM_TAG_OBJECT_TYPE:
|
||||
case WASM_GLOBAL_OBJECT_TYPE:
|
||||
case WASM_MEMORY_OBJECT_TYPE:
|
||||
case WASM_MODULE_OBJECT_TYPE:
|
||||
case WASM_SUSPENDER_OBJECT_TYPE:
|
||||
case WASM_TABLE_OBJECT_TYPE:
|
||||
case WASM_TAG_OBJECT_TYPE:
|
||||
case WASM_VALUE_OBJECT_TYPE:
|
||||
#endif // V8_ENABLE_WEBASSEMBLY
|
||||
return Op::template apply<JSObject::BodyDescriptor>(p1, p2, p3, p4);
|
||||
|
@ -96,6 +96,7 @@
|
||||
// - WasmMemoryObject
|
||||
// - WasmModuleObject
|
||||
// - WasmTableObject
|
||||
// - WasmSuspenderObject
|
||||
// - JSProxy
|
||||
// - FixedArrayBase
|
||||
// - ByteArray
|
||||
|
@ -1603,6 +1603,34 @@ void WebAssemblyTag(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
args.GetReturnValue().Set(Utils::ToLocal(tag_object));
|
||||
}
|
||||
|
||||
// WebAssembly.Suspender
|
||||
void WebAssemblySuspender(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()");
|
||||
if (!args.IsConstructCall()) {
|
||||
thrower.TypeError("WebAssembly.Suspender must be invoked with 'new'");
|
||||
return;
|
||||
}
|
||||
|
||||
i::Handle<i::JSObject> suspender = i::WasmSuspenderObject::New(i_isolate);
|
||||
|
||||
// The infrastructure for `new Foo` calls allocates an object, which is
|
||||
// available here as {args.This()}. We're going to discard this object
|
||||
// and use {suspender} instead, but it does have the correct prototype,
|
||||
// which we must harvest from it. This makes a difference when the JS
|
||||
// constructor function wasn't {WebAssembly.Suspender} directly, but some
|
||||
// subclass: {suspender} has {WebAssembly.Suspender}'s prototype at this
|
||||
// point, so we must overwrite that with the correct prototype for {Foo}.
|
||||
if (!TransferPrototype(i_isolate, suspender,
|
||||
Utils::OpenHandle(*args.This()))) {
|
||||
return;
|
||||
}
|
||||
args.GetReturnValue().Set(Utils::ToLocal(suspender));
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
uint32_t GetEncodedSize(i::Handle<i::WasmTagObject> tag_object) {
|
||||
@ -2751,6 +2779,16 @@ void WasmJs::Install(Isolate* isolate, bool exposed_on_global_object) {
|
||||
exception_proto);
|
||||
}
|
||||
|
||||
// Setup Suspender.
|
||||
if (enabled_features.has_stack_switching()) {
|
||||
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");
|
||||
}
|
||||
|
||||
// Setup Function
|
||||
if (enabled_features.has_type_reflection()) {
|
||||
Handle<JSFunction> function_constructor = InstallConstructorFunc(
|
||||
|
@ -52,6 +52,7 @@ TQ_OBJECT_CONSTRUCTORS_IMPL(WasmTypeInfo)
|
||||
TQ_OBJECT_CONSTRUCTORS_IMPL(WasmStruct)
|
||||
TQ_OBJECT_CONSTRUCTORS_IMPL(WasmArray)
|
||||
TQ_OBJECT_CONSTRUCTORS_IMPL(WasmContinuationObject)
|
||||
TQ_OBJECT_CONSTRUCTORS_IMPL(WasmSuspenderObject)
|
||||
|
||||
CAST_ACCESSOR(WasmInstanceObject)
|
||||
|
||||
|
@ -1864,6 +1864,18 @@ Handle<WasmContinuationObject> WasmContinuationObject::New(
|
||||
return New(isolate, std::move(stack), parent);
|
||||
}
|
||||
|
||||
// static
|
||||
Handle<WasmSuspenderObject> WasmSuspenderObject::New(Isolate* isolate) {
|
||||
Handle<JSFunction> suspender_cons(
|
||||
isolate->native_context()->wasm_suspender_constructor(), isolate);
|
||||
// Suspender objects should be at least as long-lived as the instances of
|
||||
// which it will wrap the imports/exports, allocate in old space too.
|
||||
auto suspender = Handle<WasmSuspenderObject>::cast(
|
||||
isolate->factory()->NewJSObject(suspender_cons, AllocationType::kOld));
|
||||
suspender->set_continuation(ReadOnlyRoots(isolate).undefined_value());
|
||||
return suspender;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
namespace {
|
||||
|
@ -973,6 +973,7 @@ class WasmArray : public TorqueGeneratedWasmArray<WasmArray, WasmObject> {
|
||||
TQ_OBJECT_CONSTRUCTORS(WasmArray)
|
||||
};
|
||||
|
||||
// A wasm delimited continuation.
|
||||
class WasmContinuationObject
|
||||
: public TorqueGeneratedWasmContinuationObject<WasmContinuationObject,
|
||||
Struct> {
|
||||
@ -991,6 +992,17 @@ class WasmContinuationObject
|
||||
HeapObject parent);
|
||||
};
|
||||
|
||||
// The suspender object provides an API to suspend and resume wasm code using
|
||||
// promises. See: https://github.com/WebAssembly/js-promise-integration.
|
||||
class WasmSuspenderObject
|
||||
: public TorqueGeneratedWasmSuspenderObject<WasmSuspenderObject, JSObject> {
|
||||
public:
|
||||
static Handle<WasmSuspenderObject> New(Isolate* isolate);
|
||||
// TODO(thibaudm): returnPromiseOnSuspend & suspendOnReturnedPromise.
|
||||
DECL_PRINTER(WasmSuspenderObject)
|
||||
TQ_OBJECT_CONSTRUCTORS(WasmSuspenderObject)
|
||||
};
|
||||
|
||||
#undef DECL_OPTIONAL_ACCESSORS
|
||||
|
||||
namespace wasm {
|
||||
|
@ -79,6 +79,10 @@ extern class WasmContinuationObject extends Struct {
|
||||
parent: WasmContinuationObject|Undefined;
|
||||
}
|
||||
|
||||
extern class WasmSuspenderObject extends JSObject {
|
||||
continuation: WasmContinuationObject|Undefined;
|
||||
}
|
||||
|
||||
extern class WasmExceptionTag extends Struct {
|
||||
// Note that this index is only useful for debugging purposes and it is not
|
||||
// unique across modules. The GC however does not allow objects without at
|
||||
|
@ -6,6 +6,14 @@
|
||||
|
||||
load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
|
||||
(function TestSuspender() {
|
||||
print(arguments.callee.name);
|
||||
let suspender = new WebAssembly.Suspender();
|
||||
assertTrue(suspender.toString() == "[object WebAssembly.Suspender]");
|
||||
assertThrows(() => WebAssembly.Suspender(), TypeError,
|
||||
/WebAssembly.Suspender must be invoked with 'new'/);
|
||||
})();
|
||||
|
||||
(function TestStackSwitchNoSuspend() {
|
||||
print(arguments.callee.name);
|
||||
let builder = new WasmModuleBuilder();
|
||||
|
@ -248,9 +248,10 @@ INSTANCE_TYPES = {
|
||||
2138: "WASM_INSTANCE_OBJECT_TYPE",
|
||||
2139: "WASM_MEMORY_OBJECT_TYPE",
|
||||
2140: "WASM_MODULE_OBJECT_TYPE",
|
||||
2141: "WASM_TABLE_OBJECT_TYPE",
|
||||
2142: "WASM_TAG_OBJECT_TYPE",
|
||||
2143: "WASM_VALUE_OBJECT_TYPE",
|
||||
2141: "WASM_SUSPENDER_OBJECT_TYPE",
|
||||
2142: "WASM_TABLE_OBJECT_TYPE",
|
||||
2143: "WASM_TAG_OBJECT_TYPE",
|
||||
2144: "WASM_VALUE_OBJECT_TYPE",
|
||||
}
|
||||
|
||||
# List of known V8 maps.
|
||||
|
Loading…
Reference in New Issue
Block a user