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

[wasm] Add initial returnPromiseOnSuspend builtin

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

Bug: v8:12191
Change-Id: Ied9ab5fa5009e5ab268d1c9893729d8210ae62ce
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3220344
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/main@{#77542}
parent c8976f64
......@@ -2747,6 +2747,11 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
__ Trap();
}
void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
// TODO(v8:12191): Implement for this platform.
__ Trap();
}
void Builtins::Generate_WasmOnStackReplace(MacroAssembler* masm) {
// Only needed on x64.
__ Trap();
......
......@@ -3175,6 +3175,11 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
__ Trap();
}
void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
// TODO(v8:12191): Implement for this platform.
__ Trap();
}
void Builtins::Generate_WasmOnStackReplace(MacroAssembler* masm) {
// Only needed on x64.
__ Trap();
......
......@@ -935,6 +935,7 @@ namespace internal {
\
/* Wasm */ \
IF_WASM(ASM, GenericJSToWasmWrapper, Dummy) \
IF_WASM(ASM, WasmReturnPromiseOnSuspend, Dummy) \
IF_WASM(ASM, WasmCompileLazy, Dummy) \
IF_WASM(ASM, WasmDebugBreak, Dummy) \
IF_WASM(ASM, WasmOnStackReplace, Dummy) \
......
......@@ -3007,6 +3007,11 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
__ Trap();
}
void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
// TODO(v8:12191): Implement for this platform.
__ Trap();
}
void Builtins::Generate_WasmOnStackReplace(MacroAssembler* masm) {
// Only needed on x64.
__ Trap();
......
......@@ -2745,6 +2745,11 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
__ Trap();
}
void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
// TODO(v8:12191): Implement for this platform.
__ Trap();
}
void Builtins::Generate_WasmOnStackReplace(MacroAssembler* masm) {
// Only needed on x64.
__ Trap();
......
......@@ -2682,6 +2682,11 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
__ Trap();
}
void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
// TODO(v8:12191): Implement for this platform.
__ Trap();
}
void Builtins::Generate_WasmOnStackReplace(MacroAssembler* masm) {
// Only needed on x64.
__ Trap();
......
......@@ -2767,6 +2767,11 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
__ Trap();
}
void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
// TODO(v8:12191): Implement for this platform.
__ Trap();
}
void Builtins::Generate_WasmOnStackReplace(MacroAssembler* masm) {
// Only needed on x64.
__ Trap();
......
......@@ -2507,6 +2507,11 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
__ Trap();
}
void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
// TODO(v8:12191): Implement for this platform.
__ Trap();
}
void Builtins::Generate_WasmOnStackReplace(MacroAssembler* masm) {
// Only needed on x64.
__ Trap();
......
......@@ -3129,6 +3129,11 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
__ Trap();
}
void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
// TODO(v8:12191): Implement for this platform.
__ Trap();
}
void Builtins::Generate_WasmOnStackReplace(MacroAssembler* masm) {
// Only needed on x64.
__ Trap();
......
......@@ -2541,6 +2541,11 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
__ Trap();
}
void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
// TODO(v8:12191): Implement for this platform.
__ Trap();
}
void Builtins::Generate_WasmOnStackReplace(MacroAssembler* masm) {
// Only needed on x64.
__ Trap();
......
......@@ -3640,6 +3640,208 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
__ jmp(&compile_wrapper_done);
}
namespace {
// Helper function for WasmReturnPromiseOnSuspend.
void LoadJumpBuffer(MacroAssembler* masm, Register jmpbuf,
Register stack_limit_address, Register stack_limit_tmp) {
__ movq(rsp, MemOperand(jmpbuf, wasm::kJmpBufSpOffset));
__ movq(stack_limit_tmp, MemOperand(jmpbuf, wasm::kJmpBufStackLimitOffset));
__ movq(MemOperand(stack_limit_address, 0), stack_limit_tmp);
// TODO(thibaudm): Reload live registers.
}
} // namespace
void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
// Set up the stackframe.
__ EnterFrame(StackFrame::JS_TO_WASM);
// Parameters.
Register closure = kJSFunctionRegister; // rdi
Register param_count = kJavaScriptCallArgCountRegister; // rax
if (kJSArgcIncludesReceiver) {
__ decq(param_count);
}
constexpr int kFrameMarkerOffset = -kSystemPointerSize;
constexpr int kParamCountOffset = kFrameMarkerOffset - kSystemPointerSize;
// The frame marker is not included in the slot count.
constexpr int kNumSpillSlots =
-(kParamCountOffset - kFrameMarkerOffset) / kSystemPointerSize;
__ subq(rsp, Immediate(kNumSpillSlots * kSystemPointerSize));
__ movq(MemOperand(rbp, kParamCountOffset), param_count);
// -------------------------------------------
// Get the instance and wasm call target.
// -------------------------------------------
Register sfi = closure;
__ LoadAnyTaggedField(
sfi,
MemOperand(
closure,
wasm::ObjectAccess::SharedFunctionInfoOffsetInTaggedJSFunction()));
Register function_data = sfi;
__ LoadAnyTaggedField(
function_data,
FieldOperand(sfi, SharedFunctionInfo::kFunctionDataOffset));
Register wasm_instance = kWasmInstanceRegister; // rsi
__ LoadAnyTaggedField(
wasm_instance,
FieldOperand(function_data, WasmExportedFunctionData::kInstanceOffset));
sfi = no_reg;
closure = no_reg;
// live: [rsi, rdi]
// -------------------------------------------
// Save current state in active jmpbuf.
// -------------------------------------------
Register active_continuation = rax;
Register foreign_jmpbuf = rbx;
__ LoadAnyTaggedField(
active_continuation,
FieldOperand(wasm_instance,
WasmInstanceObject::kActiveContinuationOffset));
__ LoadAnyTaggedField(
foreign_jmpbuf,
FieldOperand(active_continuation, WasmContinuationObject::kJmpbufOffset));
Register jmpbuf = rbx;
__ LoadExternalPointerField(
jmpbuf, FieldOperand(foreign_jmpbuf, Foreign::kForeignAddressOffset),
kForeignForeignAddressTag, r8);
__ movq(MemOperand(jmpbuf, wasm::kJmpBufSpOffset), rsp);
Register stack_limit_address = rcx;
__ movq(stack_limit_address,
FieldOperand(wasm_instance,
WasmInstanceObject::kStackLimitAddressOffset));
Register stack_limit = rdx;
__ movq(stack_limit, MemOperand(stack_limit_address, 0));
__ movq(MemOperand(jmpbuf, wasm::kJmpBufStackLimitOffset), stack_limit);
// TODO(thibaudm): Save live registers.
foreign_jmpbuf = no_reg;
stack_limit = no_reg;
stack_limit_address = no_reg;
// live: [rsi, rdi, rax, rcx]
// -------------------------------------------
// Allocate a new continuation.
// -------------------------------------------
__ Push(wasm_instance);
__ Push(function_data);
__ Push(wasm_instance);
__ Move(kContextRegister, Smi::zero());
// TODO(thibaudm): Handle GC.
__ CallRuntime(Runtime::kWasmAllocateContinuation);
__ Pop(function_data);
__ Pop(wasm_instance);
STATIC_ASSERT(kReturnRegister0 == rax);
Register target_continuation = rax;
// live: [rsi, rdi, rax]
// -------------------------------------------
// Load target continuation jmpbuf.
// -------------------------------------------
foreign_jmpbuf = rbx;
__ LoadAnyTaggedField(
foreign_jmpbuf,
FieldOperand(target_continuation, WasmContinuationObject::kJmpbufOffset));
Register target_jmpbuf = rbx;
__ LoadExternalPointerField(
target_jmpbuf,
FieldOperand(foreign_jmpbuf, Foreign::kForeignAddressOffset),
kForeignForeignAddressTag, r8);
stack_limit_address = rcx;
__ movq(stack_limit_address,
FieldOperand(wasm_instance,
WasmInstanceObject::kStackLimitAddressOffset));
// Switch stack!
LoadJumpBuffer(masm, target_jmpbuf, stack_limit_address, rdx);
__ movq(rbp, rsp); // New stack, there is no frame yet.
foreign_jmpbuf = no_reg;
target_jmpbuf = no_reg;
stack_limit_address = no_reg;
// live: [rsi, rdi]
// -------------------------------------------
// Load and call target wasm function.
// -------------------------------------------
// TODO(thibaudm): Handle arguments.
// TODO(thibaudm): Handle GC.
Register function_entry = function_data;
__ LoadExternalPointerField(
function_entry,
FieldOperand(function_data,
WasmExportedFunctionData::kForeignAddressOffset),
kForeignForeignAddressTag, r8);
__ Push(wasm_instance);
__ call(function_entry);
__ Pop(wasm_instance);
function_entry = no_reg;
function_data = no_reg;
// live: [rsi]
// -------------------------------------------
// Reload parent continuation.
// -------------------------------------------
active_continuation = rbx;
__ LoadAnyTaggedField(
active_continuation,
FieldOperand(wasm_instance,
WasmInstanceObject::kActiveContinuationOffset));
Register parent = rdx;
__ LoadAnyTaggedField(
parent,
FieldOperand(active_continuation, WasmContinuationObject::kParentOffset));
active_continuation = no_reg;
// live: [rsi]
// -------------------------------------------
// Update instance active continuation.
// -------------------------------------------
Register object = WriteBarrierDescriptor::ObjectRegister();
Register slot_address = WriteBarrierDescriptor::SlotAddressRegister();
DCHECK_EQ(object, rdi);
DCHECK((slot_address == rbx || slot_address == r8));
// Save reg clobbered by the write barrier.
__ movq(rax, parent);
__ movq(object, wasm_instance);
__ StoreTaggedField(
FieldOperand(object, WasmInstanceObject::kActiveContinuationOffset),
parent);
__ RecordWriteField(object, WasmInstanceObject::kActiveContinuationOffset,
parent, slot_address, SaveFPRegsMode::kIgnore);
// Restore reg clobbered by the write barrier.
__ movq(parent, rax);
foreign_jmpbuf = rax;
__ LoadAnyTaggedField(
foreign_jmpbuf,
FieldOperand(parent, WasmContinuationObject::kJmpbufOffset));
jmpbuf = foreign_jmpbuf;
__ LoadExternalPointerField(
jmpbuf, FieldOperand(foreign_jmpbuf, Foreign::kForeignAddressOffset),
kForeignForeignAddressTag, r8);
stack_limit_address = rcx;
__ movq(stack_limit_address,
FieldOperand(wasm_instance,
WasmInstanceObject::kStackLimitAddressOffset));
// Switch stack!
LoadJumpBuffer(masm, jmpbuf, stack_limit_address, rdx);
__ leaq(rbp, Operand(rsp, (kNumSpillSlots + 1) * kSystemPointerSize));
parent = no_reg;
active_continuation = no_reg;
stack_limit_address = no_reg;
foreign_jmpbuf = no_reg;
wasm_instance = no_reg;
// -------------------------------------------
// Epilogue.
// -------------------------------------------
__ movq(param_count, MemOperand(rbp, kParamCountOffset));
__ LeaveFrame(StackFrame::JS_TO_WASM);
__ DropArguments(param_count, r8, TurboAssembler::kCountIsInteger,
TurboAssembler::kCountExcludesReceiver);
__ ret(0);
}
void Builtins::Generate_WasmOnStackReplace(MacroAssembler* masm) {
MemOperand OSRTargetSlot(rbp, -wasm::kOSRTargetOffset);
__ movq(kScratchRegister, OSRTargetSlot);
......
......@@ -1666,10 +1666,12 @@ void WasmValueObject::WasmValueObjectVerify(Isolate* isolate) {
void WasmExportedFunctionData::WasmExportedFunctionDataVerify(
Isolate* isolate) {
TorqueGeneratedClassVerifiers::WasmExportedFunctionDataVerify(*this, isolate);
CHECK(wrapper_code().kind() == CodeKind::JS_TO_WASM_FUNCTION ||
wrapper_code().kind() == CodeKind::C_WASM_ENTRY ||
(wrapper_code().is_builtin() &&
wrapper_code().builtin_id() == Builtin::kGenericJSToWasmWrapper));
CHECK(
wrapper_code().kind() == CodeKind::JS_TO_WASM_FUNCTION ||
wrapper_code().kind() == CodeKind::C_WASM_ENTRY ||
(wrapper_code().is_builtin() &&
(wrapper_code().builtin_id() == Builtin::kGenericJSToWasmWrapper ||
wrapper_code().builtin_id() == Builtin::kWasmReturnPromiseOnSuspend)));
}
#endif // V8_ENABLE_WEBASSEMBLY
......
......@@ -1845,7 +1845,8 @@ void WasmContinuationObject::WasmContinuationObjectPrint(std::ostream& os) {
PrintHeader(os, "WasmContinuationObject");
os << "\n - parent: " << parent();
os << "\n - jmpbuf: " << jmpbuf();
os << "\n - stack: " << stack();
os << "\n - managed_stack: " << managed_stack();
os << "\n - managed_jmpbuf: " << managed_jmpbuf();
os << "\n";
}
......
......@@ -1422,5 +1422,29 @@ 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
......@@ -16,6 +16,7 @@
#include "src/runtime/runtime-utils.h"
#include "src/trap-handler/trap-handler.h"
#include "src/wasm/module-compiler.h"
#include "src/wasm/stacks.h"
#include "src/wasm/value-type.h"
#include "src/wasm/wasm-code-manager.h"
#include "src/wasm/wasm-constants.h"
......@@ -680,5 +681,16 @@ RUNTIME_FUNCTION(Runtime_WasmArrayCopy) {
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_WasmAllocateContinuation) {
CHECK(FLAG_experimental_wasm_stack_switching);
DCHECK_EQ(1, args.length());
HandleScope scope(isolate);
CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
auto parent = instance->active_continuation();
auto target = WasmContinuationObject::New(isolate, parent);
instance->set_active_continuation(*target);
return *target;
}
} // namespace internal
} // namespace v8
......@@ -594,7 +594,9 @@ namespace internal {
F(WasmTriggerTierUp, 1, 1) \
F(WasmDebugBreak, 0, 1) \
F(WasmAllocateRtt, 3, 1) \
F(WasmArrayCopy, 5, 1)
F(WasmArrayCopy, 5, 1) \
F(WasmAllocateContinuation, 1, 1) \
F(WasmReturnPromiseOnSuspend, 1, 1)
#define FOR_EACH_INTRINSIC_WASM_TEST(F, I) \
F(DeserializeWasmModule, 2, 1) \
......
......@@ -20,13 +20,11 @@ namespace wasm {
struct JumpBuffer {
void* sp;
void* fp;
void* stack_limit;
// TODO(thibaudm/fgm): Add general-purpose registers.
};
constexpr int kJmpBufSpOffset = offsetof(JumpBuffer, sp);
constexpr int kJmpBufFpOffset = offsetof(JumpBuffer, fp);
constexpr int kJmpBufStackLimitOffset = offsetof(JumpBuffer, stack_limit);
class StackMemory {
......
......@@ -225,6 +225,8 @@ PRIMITIVE_ACCESSORS(WasmInstanceObject, hook_on_function_call_address, Address,
kHookOnFunctionCallAddressOffset)
PRIMITIVE_ACCESSORS(WasmInstanceObject, num_liftoff_function_calls_array,
uint32_t*, kNumLiftoffFunctionCallsArrayOffset)
ACCESSORS(WasmInstanceObject, active_continuation, WasmContinuationObject,
kActiveContinuationOffset)
PRIMITIVE_ACCESSORS(WasmInstanceObject, break_on_entry, uint8_t,
kBreakOnEntryOffset)
......
......@@ -1316,6 +1316,15 @@ Handle<WasmInstanceObject> WasmInstanceObject::New(
module_object->native_module()->num_liftoff_function_calls_array());
instance->set_break_on_entry(module_object->script().break_on_entry());
if (FLAG_experimental_wasm_stack_switching) {
// TODO(thibaudm): If there is already a continuation object for the current
// execution context, re-use that instead of creating a new one.
std::unique_ptr<wasm::StackMemory> stack(
wasm::StackMemory::GetCurrentStackView(isolate));
auto continuation = WasmContinuationObject::New(isolate, std::move(stack));
instance->set_active_continuation(*continuation);
}
// Insert the new instance into the scripts weak list of instances. This list
// is used for breakpoints affecting all instances belonging to the script.
if (module_object->script().type() == Script::TYPE_WASM) {
......@@ -1840,14 +1849,16 @@ Handle<WasmContinuationObject> WasmContinuationObject::New(
isolate->factory()->NewStruct(WASM_CONTINUATION_OBJECT_TYPE));
auto jmpbuf = std::make_unique<wasm::JumpBuffer>();
jmpbuf->stack_limit = stack->limit();
jmpbuf->fp = stack->base();
jmpbuf->sp = stack->base();
result->set_jmpbuf(
*isolate->factory()->NewForeign(reinterpret_cast<Address>(jmpbuf.get())));
size_t external_size = stack->owned_size();
Handle<Foreign> managed_stack = Managed<wasm::StackMemory>::FromUniquePtr(
isolate, stack->owned_size(), std::move(stack));
isolate, external_size, std::move(stack));
Handle<Foreign> managed_jmpbuf = Managed<wasm::JumpBuffer>::FromUniquePtr(
isolate, sizeof(wasm::JumpBuffer), std::move(jmpbuf));
result->set_stack(*managed_stack);
result->set_jmpbuf(*managed_jmpbuf);
result->set_managed_stack(*managed_stack);
result->set_managed_jmpbuf(*managed_jmpbuf);
result->set_parent(parent);
return result;
}
......@@ -1924,7 +1935,8 @@ bool WasmExportedFunction::IsWasmExportedFunction(Object object) {
JSFunction js_function = JSFunction::cast(object);
Code code = js_function.code();
if (CodeKind::JS_TO_WASM_FUNCTION != code.kind() &&
code.builtin_id() != Builtin::kGenericJSToWasmWrapper) {
code.builtin_id() != Builtin::kGenericJSToWasmWrapper &&
code.builtin_id() != Builtin::kWasmReturnPromiseOnSuspend) {
return false;
}
DCHECK(js_function.shared().HasWasmExportedFunctionData());
......@@ -1978,9 +1990,11 @@ int WasmExportedFunction::function_index() {
Handle<WasmExportedFunction> WasmExportedFunction::New(
Isolate* isolate, Handle<WasmInstanceObject> instance, int func_index,
int arity, Handle<Code> export_wrapper) {
DCHECK(CodeKind::JS_TO_WASM_FUNCTION == export_wrapper->kind() ||
(export_wrapper->is_builtin() &&
export_wrapper->builtin_id() == Builtin::kGenericJSToWasmWrapper));
DCHECK(
CodeKind::JS_TO_WASM_FUNCTION == export_wrapper->kind() ||
(export_wrapper->is_builtin() &&
export_wrapper->builtin_id() == Builtin::kGenericJSToWasmWrapper ||
export_wrapper->builtin_id() == Builtin::kWasmReturnPromiseOnSuspend));
int num_imported_functions = instance->module()->num_imported_functions;
Handle<Object> ref =
func_index >= num_imported_functions
......
......@@ -372,6 +372,7 @@ class V8_EXPORT_PRIVATE WasmInstanceObject : public JSObject {
DECL_PRIMITIVE_ACCESSORS(dropped_elem_segments, byte*)
DECL_PRIMITIVE_ACCESSORS(hook_on_function_call_address, Address)
DECL_PRIMITIVE_ACCESSORS(num_liftoff_function_calls_array, uint32_t*)
DECL_ACCESSORS(active_continuation, WasmContinuationObject)
DECL_PRIMITIVE_ACCESSORS(break_on_entry, uint8_t)
// Clear uninitialized padding space. This ensures that the snapshot content
......@@ -428,6 +429,7 @@ class V8_EXPORT_PRIVATE WasmInstanceObject : public JSObject {
V(kWasmExternalFunctionsOffset, kTaggedSize) \
V(kManagedObjectMapsOffset, kTaggedSize) \
V(kFeedbackVectorsOffset, kTaggedSize) \
V(kActiveContinuationOffset, kTaggedSize) \
V(kBreakOnEntryOffset, kUInt8Size) \
/* More padding to make the header pointer-size aligned */ \
V(kHeaderPaddingOffset, POINTER_SIZE_PADDING(kHeaderPaddingOffset)) \
......
......@@ -64,8 +64,9 @@ extern class WasmIndirectFunctionTable extends Struct {
}
extern class WasmContinuationObject extends Struct {
stack: Foreign;
jmpbuf: Foreign;
managed_stack: Foreign;
managed_jmpbuf: Foreign;
jmpbuf: Foreign; // Direct access to managed_jmpbuf's underlying pointer.
parent: WasmContinuationObject|Undefined;
}
......
......@@ -1645,6 +1645,8 @@
['arch != x64', {
# Tests that include types only supported on x64.
'compiler/fast-api-sequences-x64': [SKIP],
# Stack switching is only supported on x64.
'wasm/stack-switching': [SKIP],
}], # arch != x64
]
// Copyright 2021 the V8 project authors. All rights reserved.
// 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
load("test/mjsunit/wasm/wasm-module-builder.js");
(function TestStackSwitchNoSuspend() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
builder.addGlobal(kWasmI32, true).exportAs('g');
builder.addFunction("test", kSig_v_v)
.addBody([kExprI32Const, 42, kExprGlobalSet, 0]).exportFunc();
let instance = builder.instantiate();
let wrapper = %WasmReturnPromiseOnSuspend(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