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

[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: 's avatarAndreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarDominik Inführ <dinfuehr@chromium.org>
Cr-Commit-Position: refs/heads/main@{#77734}
parent f0e5e3b2
...@@ -1852,6 +1852,12 @@ void WasmContinuationObject::WasmContinuationObjectPrint(std::ostream& os) { ...@@ -1852,6 +1852,12 @@ void WasmContinuationObject::WasmContinuationObjectPrint(std::ostream& os) {
os << "\n"; os << "\n";
} }
void WasmSuspenderObject::WasmSuspenderObjectPrint(std::ostream& os) {
PrintHeader(os, "WasmSuspenderObject");
os << "\n - continuation: " << continuation();
os << "\n";
}
void WasmInstanceObject::WasmInstanceObjectPrint(std::ostream& os) { void WasmInstanceObject::WasmInstanceObjectPrint(std::ostream& os) {
JSObjectPrintHeader(os, *this, "WasmInstanceObject"); JSObjectPrintHeader(os, *this, "WasmInstanceObject");
os << "\n - module_object: " << Brief(module_object()); os << "\n - module_object: " << Brief(module_object());
......
...@@ -59,6 +59,7 @@ namespace internal { ...@@ -59,6 +59,7 @@ namespace internal {
IF_WASM(V, WasmJSFunctionData) \ IF_WASM(V, WasmJSFunctionData) \
IF_WASM(V, WasmApiFunctionRef) \ IF_WASM(V, WasmApiFunctionRef) \
IF_WASM(V, WasmStruct) \ IF_WASM(V, WasmStruct) \
IF_WASM(V, WasmSuspenderObject) \
IF_WASM(V, WasmTypeInfo) IF_WASM(V, WasmTypeInfo)
#define FORWARD_DECLARE(TypeName) class TypeName; #define FORWARD_DECLARE(TypeName) class TypeName;
......
...@@ -312,6 +312,7 @@ enum ContextLookupFlags { ...@@ -312,6 +312,7 @@ enum ContextLookupFlags {
V(WASM_MEMORY_CONSTRUCTOR_INDEX, JSFunction, wasm_memory_constructor) \ V(WASM_MEMORY_CONSTRUCTOR_INDEX, JSFunction, wasm_memory_constructor) \
V(WASM_MODULE_CONSTRUCTOR_INDEX, JSFunction, wasm_module_constructor) \ V(WASM_MODULE_CONSTRUCTOR_INDEX, JSFunction, wasm_module_constructor) \
V(WASM_TABLE_CONSTRUCTOR_INDEX, JSFunction, wasm_table_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(TEMPLATE_WEAKMAP_INDEX, HeapObject, template_weakmap) \
V(TYPED_ARRAY_FUN_INDEX, JSFunction, typed_array_function) \ V(TYPED_ARRAY_FUN_INDEX, JSFunction, typed_array_function) \
V(TYPED_ARRAY_PROTOTYPE_INDEX, JSObject, typed_array_prototype) \ V(TYPED_ARRAY_PROTOTYPE_INDEX, JSObject, typed_array_prototype) \
......
...@@ -2372,6 +2372,8 @@ int JSObject::GetHeaderSize(InstanceType type, ...@@ -2372,6 +2372,8 @@ int JSObject::GetHeaderSize(InstanceType type,
return WasmMemoryObject::kHeaderSize; return WasmMemoryObject::kHeaderSize;
case WASM_MODULE_OBJECT_TYPE: case WASM_MODULE_OBJECT_TYPE:
return WasmModuleObject::kHeaderSize; return WasmModuleObject::kHeaderSize;
case WASM_SUSPENDER_OBJECT_TYPE:
return WasmSuspenderObject::kHeaderSize;
case WASM_TABLE_OBJECT_TYPE: case WASM_TABLE_OBJECT_TYPE:
return WasmTableObject::kHeaderSize; return WasmTableObject::kHeaderSize;
case WASM_VALUE_OBJECT_TYPE: case WASM_VALUE_OBJECT_TYPE:
......
...@@ -374,6 +374,8 @@ VisitorId Map::GetVisitorId(Map map) { ...@@ -374,6 +374,8 @@ VisitorId Map::GetVisitorId(Map map) {
return kVisitWasmExportedFunctionData; return kVisitWasmExportedFunctionData;
case WASM_CAPI_FUNCTION_DATA_TYPE: case WASM_CAPI_FUNCTION_DATA_TYPE:
return kVisitWasmCapiFunctionData; return kVisitWasmCapiFunctionData;
case WASM_SUSPENDER_OBJECT_TYPE:
return kVisitWasmSuspenderObject;
#endif // V8_ENABLE_WEBASSEMBLY #endif // V8_ENABLE_WEBASSEMBLY
#define MAKE_TQ_CASE(TYPE, Name) \ #define MAKE_TQ_CASE(TYPE, Name) \
......
...@@ -77,6 +77,7 @@ enum InstanceType : uint16_t; ...@@ -77,6 +77,7 @@ enum InstanceType : uint16_t;
IF_WASM(V, WasmJSFunctionData) \ IF_WASM(V, WasmJSFunctionData) \
IF_WASM(V, WasmApiFunctionRef) \ IF_WASM(V, WasmApiFunctionRef) \
IF_WASM(V, WasmStruct) \ IF_WASM(V, WasmStruct) \
IF_WASM(V, WasmSuspenderObject) \
IF_WASM(V, WasmTypeInfo) \ IF_WASM(V, WasmTypeInfo) \
V(WeakCell) V(WeakCell)
......
...@@ -242,6 +242,7 @@ class ZoneForwardList; ...@@ -242,6 +242,7 @@ class ZoneForwardList;
IF_WASM(V, WasmTypeInfo) \ IF_WASM(V, WasmTypeInfo) \
IF_WASM(V, WasmTableObject) \ IF_WASM(V, WasmTableObject) \
IF_WASM(V, WasmValueObject) \ IF_WASM(V, WasmValueObject) \
IF_WASM(V, WasmSuspenderObject) \
V(WeakFixedArray) \ V(WeakFixedArray) \
V(WeakArrayList) \ V(WeakArrayList) \
V(WeakCell) \ V(WeakCell) \
......
...@@ -1162,11 +1162,12 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) { ...@@ -1162,11 +1162,12 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) {
case JS_SEGMENTS_TYPE: case JS_SEGMENTS_TYPE:
#endif // V8_INTL_SUPPORT #endif // V8_INTL_SUPPORT
#if V8_ENABLE_WEBASSEMBLY #if V8_ENABLE_WEBASSEMBLY
case WASM_TAG_OBJECT_TYPE:
case WASM_GLOBAL_OBJECT_TYPE: case WASM_GLOBAL_OBJECT_TYPE:
case WASM_MEMORY_OBJECT_TYPE: case WASM_MEMORY_OBJECT_TYPE:
case WASM_MODULE_OBJECT_TYPE: case WASM_MODULE_OBJECT_TYPE:
case WASM_SUSPENDER_OBJECT_TYPE:
case WASM_TABLE_OBJECT_TYPE: case WASM_TABLE_OBJECT_TYPE:
case WASM_TAG_OBJECT_TYPE:
case WASM_VALUE_OBJECT_TYPE: case WASM_VALUE_OBJECT_TYPE:
#endif // V8_ENABLE_WEBASSEMBLY #endif // V8_ENABLE_WEBASSEMBLY
return Op::template apply<JSObject::BodyDescriptor>(p1, p2, p3, p4); return Op::template apply<JSObject::BodyDescriptor>(p1, p2, p3, p4);
......
...@@ -96,6 +96,7 @@ ...@@ -96,6 +96,7 @@
// - WasmMemoryObject // - WasmMemoryObject
// - WasmModuleObject // - WasmModuleObject
// - WasmTableObject // - WasmTableObject
// - WasmSuspenderObject
// - JSProxy // - JSProxy
// - FixedArrayBase // - FixedArrayBase
// - ByteArray // - ByteArray
......
...@@ -1603,6 +1603,34 @@ void WebAssemblyTag(const v8::FunctionCallbackInfo<v8::Value>& args) { ...@@ -1603,6 +1603,34 @@ void WebAssemblyTag(const v8::FunctionCallbackInfo<v8::Value>& args) {
args.GetReturnValue().Set(Utils::ToLocal(tag_object)); 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 { namespace {
uint32_t GetEncodedSize(i::Handle<i::WasmTagObject> tag_object) { uint32_t GetEncodedSize(i::Handle<i::WasmTagObject> tag_object) {
...@@ -2751,6 +2779,16 @@ void WasmJs::Install(Isolate* isolate, bool exposed_on_global_object) { ...@@ -2751,6 +2779,16 @@ void WasmJs::Install(Isolate* isolate, bool exposed_on_global_object) {
exception_proto); 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 // Setup Function
if (enabled_features.has_type_reflection()) { if (enabled_features.has_type_reflection()) {
Handle<JSFunction> function_constructor = InstallConstructorFunc( Handle<JSFunction> function_constructor = InstallConstructorFunc(
......
...@@ -52,6 +52,7 @@ TQ_OBJECT_CONSTRUCTORS_IMPL(WasmTypeInfo) ...@@ -52,6 +52,7 @@ TQ_OBJECT_CONSTRUCTORS_IMPL(WasmTypeInfo)
TQ_OBJECT_CONSTRUCTORS_IMPL(WasmStruct) TQ_OBJECT_CONSTRUCTORS_IMPL(WasmStruct)
TQ_OBJECT_CONSTRUCTORS_IMPL(WasmArray) TQ_OBJECT_CONSTRUCTORS_IMPL(WasmArray)
TQ_OBJECT_CONSTRUCTORS_IMPL(WasmContinuationObject) TQ_OBJECT_CONSTRUCTORS_IMPL(WasmContinuationObject)
TQ_OBJECT_CONSTRUCTORS_IMPL(WasmSuspenderObject)
CAST_ACCESSOR(WasmInstanceObject) CAST_ACCESSOR(WasmInstanceObject)
......
...@@ -1864,6 +1864,18 @@ Handle<WasmContinuationObject> WasmContinuationObject::New( ...@@ -1864,6 +1864,18 @@ Handle<WasmContinuationObject> WasmContinuationObject::New(
return New(isolate, std::move(stack), parent); 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 #ifdef DEBUG
namespace { namespace {
......
...@@ -973,6 +973,7 @@ class WasmArray : public TorqueGeneratedWasmArray<WasmArray, WasmObject> { ...@@ -973,6 +973,7 @@ class WasmArray : public TorqueGeneratedWasmArray<WasmArray, WasmObject> {
TQ_OBJECT_CONSTRUCTORS(WasmArray) TQ_OBJECT_CONSTRUCTORS(WasmArray)
}; };
// A wasm delimited continuation.
class WasmContinuationObject class WasmContinuationObject
: public TorqueGeneratedWasmContinuationObject<WasmContinuationObject, : public TorqueGeneratedWasmContinuationObject<WasmContinuationObject,
Struct> { Struct> {
...@@ -991,6 +992,17 @@ class WasmContinuationObject ...@@ -991,6 +992,17 @@ class WasmContinuationObject
HeapObject parent); 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 #undef DECL_OPTIONAL_ACCESSORS
namespace wasm { namespace wasm {
......
...@@ -79,6 +79,10 @@ extern class WasmContinuationObject extends Struct { ...@@ -79,6 +79,10 @@ extern class WasmContinuationObject extends Struct {
parent: WasmContinuationObject|Undefined; parent: WasmContinuationObject|Undefined;
} }
extern class WasmSuspenderObject extends JSObject {
continuation: WasmContinuationObject|Undefined;
}
extern class WasmExceptionTag extends Struct { extern class WasmExceptionTag extends Struct {
// Note that this index is only useful for debugging purposes and it is not // 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 // unique across modules. The GC however does not allow objects without at
......
...@@ -6,6 +6,14 @@ ...@@ -6,6 +6,14 @@
load("test/mjsunit/wasm/wasm-module-builder.js"); 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() { (function TestStackSwitchNoSuspend() {
print(arguments.callee.name); print(arguments.callee.name);
let builder = new WasmModuleBuilder(); let builder = new WasmModuleBuilder();
......
...@@ -248,9 +248,10 @@ INSTANCE_TYPES = { ...@@ -248,9 +248,10 @@ INSTANCE_TYPES = {
2138: "WASM_INSTANCE_OBJECT_TYPE", 2138: "WASM_INSTANCE_OBJECT_TYPE",
2139: "WASM_MEMORY_OBJECT_TYPE", 2139: "WASM_MEMORY_OBJECT_TYPE",
2140: "WASM_MODULE_OBJECT_TYPE", 2140: "WASM_MODULE_OBJECT_TYPE",
2141: "WASM_TABLE_OBJECT_TYPE", 2141: "WASM_SUSPENDER_OBJECT_TYPE",
2142: "WASM_TAG_OBJECT_TYPE", 2142: "WASM_TABLE_OBJECT_TYPE",
2143: "WASM_VALUE_OBJECT_TYPE", 2143: "WASM_TAG_OBJECT_TYPE",
2144: "WASM_VALUE_OBJECT_TYPE",
} }
# List of known V8 maps. # List of known V8 maps.
......
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