[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:
Thibaud Michaud 2021-11-05 15:02:33 +01:00 committed by V8 LUCI CQ
parent f0e5e3b282
commit cce7154d57
16 changed files with 96 additions and 4 deletions

View File

@ -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());

View File

@ -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;

View File

@ -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) \

View File

@ -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:

View File

@ -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) \

View File

@ -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)

View File

@ -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) \

View File

@ -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);

View File

@ -96,6 +96,7 @@
// - WasmMemoryObject
// - WasmModuleObject
// - WasmTableObject
// - WasmSuspenderObject
// - JSProxy
// - FixedArrayBase
// - ByteArray

View File

@ -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(

View File

@ -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)

View File

@ -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 {

View File

@ -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 {

View File

@ -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

View File

@ -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();

View File

@ -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.