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

[wasm] Materialize suspender in JS-to-wasm wrapper

Instead of creating the Suspender object in JS and passing it to the
stack-switching js-to-wasm wrapper, the wrapper now automatically
creates the Suspender object and forwards it as an extra parameter to
the wasm function. See:
https://github.com/WebAssembly/js-promise-integration/pull/1/files

R=ahaas@chromium.org

Bug: v8:12191
Change-Id: I2badee823f4223a293632f93e7e59f24c49d0820
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3779688
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81890}
parent 9d3c0b6c
......@@ -2999,20 +2999,19 @@ void SaveState(MacroAssembler* masm, Register active_continuation, Register tmp,
FillJumpBuffer(masm, jmpbuf, suspend);
}
// Returns the new continuation in rax.
void AllocateContinuation(MacroAssembler* masm, Register function_data,
Register wasm_instance, Register suspender) {
// Returns the new suspender in rax.
void AllocateSuspender(MacroAssembler* masm, Register function_data,
Register wasm_instance) {
MemOperand GCScanSlotPlace =
MemOperand(rbp, BuiltinWasmWrapperConstants::kGCScanSlotCountOffset);
__ Move(GCScanSlotPlace, 3);
__ Move(GCScanSlotPlace, 2);
__ Push(wasm_instance);
__ Push(function_data);
__ Push(suspender); // Argument.
__ LoadAnyTaggedField(
kContextRegister,
MemOperand(wasm_instance, wasm::ObjectAccess::ToTagged(
WasmInstanceObject::kNativeContextOffset)));
__ CallRuntime(Runtime::kWasmAllocateContinuation);
__ CallRuntime(Runtime::kWasmAllocateSuspender);
__ Pop(function_data);
__ Pop(wasm_instance);
static_assert(kReturnRegister0 == rax);
......@@ -3174,7 +3173,9 @@ void GenericJSToWasmWrapperHelper(MacroAssembler* masm, bool stack_switch) {
// The number of parameters according to the signature.
constexpr int kParamCountOffset =
BuiltinWasmWrapperConstants::kParamCountOffset;
constexpr int kReturnCountOffset = kParamCountOffset - kSystemPointerSize;
constexpr int kSuspenderOffset =
BuiltinWasmWrapperConstants::kSuspenderOffset;
constexpr int kReturnCountOffset = kSuspenderOffset - kSystemPointerSize;
constexpr int kValueTypesArrayStartOffset =
kReturnCountOffset - kSystemPointerSize;
// A boolean flag to check if one of the parameters is a reference. If so, we
......@@ -3186,7 +3187,9 @@ void GenericJSToWasmWrapperHelper(MacroAssembler* masm, bool stack_switch) {
// registers (so no GC scan is needed).
constexpr int kFunctionDataOffset = kHasRefTypesOffset - kSystemPointerSize;
constexpr int kLastSpillOffset = kFunctionDataOffset;
constexpr int kNumSpillSlots = 7;
constexpr int kNumSpillSlots =
(-TypedFrameConstants::kFixedFrameSizeFromFp - kLastSpillOffset) >>
kSystemPointerSizeLog2;
__ subq(rsp, Immediate(kNumSpillSlots * kSystemPointerSize));
// Put the in_parameter count on the stack, we only need it at the very end
// when we pop the parameters off the stack.
......@@ -3221,17 +3224,21 @@ void GenericJSToWasmWrapperHelper(MacroAssembler* masm, bool stack_switch) {
Label suspend;
if (stack_switch) {
// Set the suspender spill slot to a sentinel value, in case a GC happens
// before we set the actual value.
__ LoadRoot(kScratchRegister, RootIndex::kUndefinedValue);
__ movq(MemOperand(rbp, kSuspenderOffset), kScratchRegister);
Register active_continuation = rbx;
__ LoadRoot(active_continuation, RootIndex::kActiveContinuation);
SaveState(masm, active_continuation, rcx, &suspend);
Register suspender = rax;
constexpr int kReceiverOnStackSize = kSystemPointerSize;
constexpr int kFirstParamOffset =
kFPOnStackSize + kPCOnStackSize + kReceiverOnStackSize;
__ movq(suspender, MemOperand(rbp, kFirstParamOffset));
AllocateContinuation(masm, function_data, wasm_instance, suspender);
AllocateSuspender(masm, function_data, wasm_instance);
Register suspender = rax; // Fixed.
__ movq(MemOperand(rbp, kSuspenderOffset), suspender);
Register target_continuation = rax;
__ LoadAnyTaggedField(
target_continuation,
FieldOperand(suspender, WasmSuspenderObject::kContinuationOffset));
suspender = no_reg;
Register target_continuation = rax; // fixed
// Save the old stack's rbp in r9, and use it to access the parameters in
// the parent frame.
// We also distribute the spill slots across the two stacks as needed by
......@@ -3249,9 +3256,11 @@ void GenericJSToWasmWrapperHelper(MacroAssembler* masm, bool stack_switch) {
// +-----------------+ +-----------------+
// |kGCScanSlotCount | |kGCScanSlotCount |
// +-----------------+ +-----------------+
// | kInParamCount | | / |
// +-----------------+ +-----------------+
// | kParamCount | | / |
// +-----------------+ +-----------------+
// | kInParamCount | | / |
// | kSuspender | | / |
// +-----------------+ +-----------------+
// | / | | kReturnCount |
// +-----------------+ +-----------------+
......@@ -3283,6 +3292,9 @@ void GenericJSToWasmWrapperHelper(MacroAssembler* masm, bool stack_switch) {
// this marks the base of the stack segment for the stack frame iterator.
__ EnterFrame(StackFrame::STACK_SWITCH);
__ subq(rsp, Immediate(kNumSpillSlots * kSystemPointerSize));
// Set a sentinel value for the suspender spill slot in the new frame.
__ LoadRoot(kScratchRegister, RootIndex::kUndefinedValue);
__ movq(MemOperand(rbp, kSuspenderOffset), kScratchRegister);
}
Register original_fp = stack_switch ? r9 : rbp;
......@@ -3424,6 +3436,22 @@ void GenericJSToWasmWrapperHelper(MacroAssembler* masm, bool stack_switch) {
returns_size = no_reg;
Register valuetype = r12;
Label numeric_params_done;
if (stack_switch) {
// Prepare for materializing the suspender parameter. We don't materialize
// it here but in the next loop that processes references. Here we only
// adjust the pointers to keep the state consistent:
// - Skip the first valuetype in the signature,
// - Adjust the param limit which is off by one because of the extra
// param in the signature,
// - Set HasRefTypes to 1 to ensure that the reference loop is entered.
__ addq(valuetypes_array_ptr, Immediate(kValueTypeSize));
__ subq(param_limit, Immediate(kSystemPointerSize));
__ movq(MemOperand(rbp, kHasRefTypesOffset), Immediate(1));
__ cmpq(current_param, param_limit);
__ j(equal, &numeric_params_done);
}
// -------------------------------------------
// Param evaluation loop.
// -------------------------------------------
......@@ -3443,7 +3471,7 @@ void GenericJSToWasmWrapperHelper(MacroAssembler* masm, bool stack_switch) {
__ cmpq(valuetype, Immediate(wasm::kWasmI32.raw_bit_field()));
__ j(not_equal, &convert_param);
__ JumpIfNotSmi(param, &convert_param);
// Change the paramfrom Smi to int32.
// Change the param from Smi to int32.
__ SmiUntag(param);
// Zero extend.
__ movl(param, param);
......@@ -3462,6 +3490,7 @@ void GenericJSToWasmWrapperHelper(MacroAssembler* masm, bool stack_switch) {
__ cmpq(current_param, param_limit);
__ j(not_equal, &loop_through_params);
__ bind(&numeric_params_done);
// -------------------------------------------
// Second loop to handle references.
......@@ -3490,6 +3519,17 @@ void GenericJSToWasmWrapperHelper(MacroAssembler* masm, bool stack_switch) {
__ Move(current_param,
kFPOnStackSize + kPCOnStackSize + kReceiverOnStackSize);
if (stack_switch) {
// Materialize the suspender param
__ movq(param, MemOperand(original_fp, kSuspenderOffset));
__ movq(MemOperand(current_int_param_slot, 0), param);
__ subq(current_int_param_slot, Immediate(kSystemPointerSize));
__ addq(valuetypes_array_ptr, Immediate(kValueTypeSize));
__ addq(ref_param_count, Immediate(1));
__ cmpq(current_param, param_limit);
__ j(equal, &ref_params_done);
}
Label ref_loop_through_params;
Label ref_loop_end;
// Start of the loop.
......@@ -4142,6 +4182,10 @@ void Generate_WasmResumeHelper(MacroAssembler* masm, wasm::OnResume on_resume) {
__ subq(rsp, Immediate(3 * kSystemPointerSize));
__ movq(MemOperand(rbp, kParamCountOffset), param_count);
__ movq(MemOperand(rbp, kInParamCountOffset), param_count);
// Set a sentinel value for the spill slot visited by the GC.
__ LoadRoot(kScratchRegister, RootIndex::kUndefinedValue);
__ movq(MemOperand(rbp, BuiltinWasmWrapperConstants::kSuspenderOffset),
kScratchRegister);
param_count = no_reg;
......
......@@ -652,7 +652,6 @@ namespace internal {
T(WasmTrapStringOffsetOutOfBounds, "string offset out of bounds") \
T(WasmTrapStringIsolatedSurrogate, \
"Failed to encode string as UTF-8: contains unpaired surrogate") \
T(WasmTrapReentrantSuspender, "re-entering an active/suspended suspender") \
T(WasmExceptionError, "wasm exception") \
/* Asm.js validation related */ \
T(AsmJsInvalid, "Invalid asm.js: %") \
......
......@@ -216,6 +216,7 @@ class BuiltinWasmWrapperConstants : public TypedFrameConstants {
static constexpr int kInParamCountOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(1);
// The number of parameters according to the signature.
static constexpr int kParamCountOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(2);
static constexpr int kSuspenderOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(3);
};
class ConstructFrameConstants : public TypedFrameConstants {
......
......@@ -2332,6 +2332,10 @@ void StackSwitchFrame::Iterate(RootVisitor* v) const {
&Memory<Address>(sp() + scan_count * kSystemPointerSize));
v->VisitRootPointers(Root::kStackRoots, nullptr, spill_slot_base,
spill_slot_limit);
// Also visit fixed spill slots that contain references.
FullObjectSlot suspender_slot(
&Memory<Address>(fp() + BuiltinWasmWrapperConstants::kSuspenderOffset));
v->VisitRootPointer(Root::kStackRoots, nullptr, suspender_slot);
}
// static
......
......@@ -797,21 +797,12 @@ void SyncStackLimit(Isolate* isolate) {
}
} // namespace
// Allocate a new continuation, and prepare for stack switching by updating the
// Allocate a new suspender, and prepare for stack switching by updating the
// active continuation, active suspender and stack limit.
RUNTIME_FUNCTION(Runtime_WasmAllocateContinuation) {
RUNTIME_FUNCTION(Runtime_WasmAllocateSuspender) {
CHECK(FLAG_experimental_wasm_stack_switching);
HandleScope scope(isolate);
if (!args[0].IsWasmSuspenderObject()) {
return ThrowWasmError(isolate, MessageTemplate::kWasmTrapJSTypeError);
}
Handle<WasmSuspenderObject> suspender =
handle(WasmSuspenderObject::cast(args[0]), isolate);
if (suspender->state() != WasmSuspenderObject::kInactive) {
return ThrowWasmError(isolate,
MessageTemplate::kWasmTrapReentrantSuspender);
}
Handle<WasmSuspenderObject> suspender = WasmSuspenderObject::New(isolate);
// Update the continuation state.
auto parent = handle(WasmContinuationObject::cast(
......@@ -833,7 +824,7 @@ RUNTIME_FUNCTION(Runtime_WasmAllocateContinuation) {
active_suspender_slot.store(*suspender);
SyncStackLimit(isolate);
return *target;
return *suspender;
}
// Update the stack limit after a stack switch, and preserve pending interrupts.
......
......@@ -609,7 +609,7 @@ namespace internal {
F(WasmDebugBreak, 0, 1) \
F(WasmArrayCopy, 5, 1) \
F(WasmArrayNewSegment, 5, 1) \
F(WasmAllocateContinuation, 1, 1) \
F(WasmAllocateSuspender, 0, 1) \
F(WasmSyncStackLimit, 0, 1) \
F(WasmCreateResumePromise, 2, 1) \
F(WasmStringNewWtf8, 5, 1) \
......
......@@ -2022,13 +2022,15 @@ void WebAssemblyFunctionType(const v8::FunctionCallbackInfo<v8::Value>& args) {
handle(sfi->wasm_exported_function_data(), i_isolate);
sig = wasm_exported_function->sig();
if (data->suspend()) {
// If this export is suspendable, the function returns a
// If this export is suspendable, the first parameter of the original
// function is an externref (suspender) which does not appear in the
// wrapper function's signature. The wrapper function also returns a
// promise as an externref instead of the original return type.
size_t param_count = sig->parameter_count();
DCHECK_GE(param_count, 1);
DCHECK_EQ(sig->GetParam(0), i::wasm::kWasmAnyRef);
i::wasm::FunctionSig::Builder builder(&zone, 1, param_count);
for (size_t i = 0; i < param_count; ++i) {
i::wasm::FunctionSig::Builder builder(&zone, 1, param_count - 1);
for (size_t i = 1; i < param_count; ++i) {
builder.AddParam(sig->GetParam(i));
}
builder.AddReturn(i::wasm::kWasmAnyRef);
......
......@@ -1795,10 +1795,8 @@ Handle<WasmContinuationObject> WasmContinuationObject::New(
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));
isolate->factory()->NewJSObject(suspender_cons));
suspender->set_state(kInactive);
// Instantiate the callable object which resumes this Suspender. This will be
// used implicitly as the onFulfilled callback of the returned JS promise.
......
......@@ -1713,6 +1713,7 @@
['arch != x64', {
# Stack switching is only supported on x64.
'wasm/stack-switching': [SKIP],
'wasm/stack-switching-export': [SKIP],
}], # arch != x64
##############################################################################
......
// Copyright 2022 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: --wasm-generic-wrapper --expose-gc --allow-natives-syntax
// Flags: --experimental-wasm-stack-switching
// Flags: --experimental-wasm-type-reflection
// This is a port of the generic-wrapper.js tests for the JS Promise Integration
// variant of the wrapper. We don't suspend the stacks in this test, we only
// test the wrapper's argument conversion logic.
d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
(function testGenericWrapper0Param() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig_index = builder.addType(kSig_r_r);
let func_index = builder.addImport("mod", "func", kSig_r_v);
builder.addFunction("main", sig_index)
.addBody([
kExprCallFunction, func_index
])
.exportFunc();
let x = 12;
function import_func() {
gc();
x = 20;
}
let instance = builder.instantiate({ mod: { func: import_func } });
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertEquals(undefined, main());
assertEquals(20, x);
})();
(function testGenericWrapper0ParamTraps() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig_index = builder.addType(kSig_r_r);
builder.addFunction("main", sig_index)
.addBody([
kExprUnreachable
])
.exportFunc();
let instance = builder.instantiate();
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertTraps(kTrapUnreachable, main);
})();
(function testGenericWrapper1ParamTrap() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig = makeSig([kWasmAnyRef, kWasmI32], [kWasmAnyRef]);
let sig_index = builder.addType(sig);
builder.addFunction("main", sig_index)
.addBody([
kExprLocalGet, 1, kExprUnreachable
])
.exportFunc();
let instance = builder.instantiate();
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertTraps(kTrapUnreachable, main);
})();
(function testGenericWrapper1ParamGeneral() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig = makeSig([kWasmAnyRef, kWasmI32], [kWasmAnyRef]);
let sig_index = builder.addType(sig);
let func_index = builder.addImport("mod", "func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
kExprLocalGet, 0,
kExprLocalGet, 1,
kExprCallFunction, func_index
])
.exportFunc();
let x = 12;
function import_func(suspender, param) {
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += param;
}
let instance = builder.instantiate({ mod: { func: import_func } });
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertEquals(undefined, main(5));
assertEquals(17, x);
})();
(function testGenericWrapper1ParamNotSmi() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig = makeSig([kWasmAnyRef, kWasmI32], [kWasmAnyRef]);
let sig_index = builder.addType(sig);
let func_index = builder.addImport("mod", "func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
kExprLocalGet, 0,
kExprLocalGet, 1,
kExprCallFunction, func_index
])
.exportFunc();
let x = 12;
function import_func(suspender, param) {
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += param;
}
let y = { valueOf: () => { print("Hello!"); gc(); return 24; } };
let instance = builder.instantiate({ mod: { func: import_func } });
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertEquals(undefined, main(y));
assertEquals(36, x);
})();
(function testGenericWrapper4Param() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig = makeSig([kWasmAnyRef, kWasmI32, kWasmI32, kWasmI32, kWasmI32],
[kWasmAnyRef]);
let sig_index = builder.addType(sig);
let func_index = builder.addImport("mod", "func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
kExprLocalGet, 0,
kExprLocalGet, 1,
kExprLocalGet, 2,
kExprLocalGet, 3,
kExprLocalGet, 4,
kExprCallFunction, func_index
])
.exportFunc();
let x = 12;
function import_func(suspender, param1, param2, param3, param4) {
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += 2 * param1 + 3 * param2 + 4 * param3 + 5 * param4;
}
let param2 = { valueOf: () => { gc(); return 6; } };
let param3 = { valueOf: () => { gc(); return 3; } };
let instance = builder.instantiate({ mod: { func: import_func } });
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertEquals(undefined, main(9, param2, param3, 0));
assertEquals(60, x);
// Now we test if the evaluation order of the parameters is correct.
x = 12;
param3 = {
valueOf: () => {
Object.defineProperty(param2, 'valueOf', {
value: () => 30
})
return 3;
}
};
assertEquals(undefined, main(9, param2, param3, 0));
assertEquals(60, x);
})();
let kSig_r_riiiiiiii = makeSig([kWasmAnyRef, kWasmI32, kWasmI32, kWasmI32,
kWasmI32, kWasmI32, kWasmI32, kWasmI32, kWasmI32], [kWasmAnyRef]);
(function testGenericWrapper8Param() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig_index = builder.addType(kSig_r_riiiiiiii);
let func_index = builder.addImport("mod", "func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
kExprLocalGet, 0,
kExprLocalGet, 1,
kExprLocalGet, 2,
kExprLocalGet, 3,
kExprLocalGet, 4,
kExprLocalGet, 5,
kExprLocalGet, 6,
kExprLocalGet, 7,
kExprLocalGet, 8,
kExprCallFunction, func_index
])
.exportFunc();
let x = 12;
function import_func(suspender, param1, param2, param3, param4, param5,
param6, param7, param8) {
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += param1 + 2 * param2 + 3 * param3 + 4 * param4 + 5 * param5
+ 6 * param6 + 7 * param7 + 8 * param8;
}
let param1 = { valueOf: () => { gc(); return 5; } };
let param4 = { valueOf: () => { gc(); return 8; } };
let param6 = { valueOf: () => { gc(); return 10; } };
let param8 = { valueOf: () => { gc(); return 12; } };
let instance = builder.instantiate({ mod: { func: import_func } });
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertEquals(undefined, main(param1, 6, 7, param4, 9, param6, 11, param8));
assertEquals(360, x);
})();
// Passing less parameters than expected.
(function testGenericWrapper4ParamWithLessParams() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig = makeSig([kWasmAnyRef, kWasmI32, kWasmI32, kWasmI32, kWasmI32],
[kWasmAnyRef]);
let sig_index = builder.addType(sig);
let func_index = builder.addImport("mod", "func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
kExprLocalGet, 0,
kExprLocalGet, 1,
kExprLocalGet, 2,
kExprLocalGet, 3,
kExprLocalGet, 4,
kExprCallFunction, func_index
])
.exportFunc();
let x = 12;
function import_func(suspender, param1, param2, param3, param4) {
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += param1 + param2 + param3 + param4;
}
let param2 = { valueOf: () => { gc(); return 3; } };
let instance = builder.instantiate({ mod: { func: import_func } });
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertEquals(undefined, main(5, param2));
assertEquals(20, x);
})();
// Passing more parameters than expected.
(function testGenericWrapper4ParamWithMoreParams() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig = makeSig([kWasmAnyRef, kWasmI32, kWasmI32, kWasmI32, kWasmI32],
[kWasmAnyRef]);
let sig_index = builder.addType(sig);
let func_index = builder.addImport("mod", "func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
kExprLocalGet, 0,
kExprLocalGet, 1,
kExprLocalGet, 2,
kExprLocalGet, 3,
kExprLocalGet, 4,
kExprCallFunction, func_index
])
.exportFunc();
let x = 12;
function import_func(suspender, param1, param2, param3, param4) {
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += param1 + param2 + param3 + param4;
}
let param2 = { valueOf: () => { gc(); return 3; } };
let param3 = { valueOf: () => { gc(); return 6; } };
let instance = builder.instantiate({ mod: { func: import_func } });
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertEquals(undefined, main(5, param2, param3, 7, 200, 300, 400));
assertEquals(33, x);
})();
(function testGenericWrapper1I32ReturnSmi() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig = makeSig([kWasmAnyRef, kWasmI32], [kWasmI32]);
let sig_index = builder.addType(sig);
let func_index = builder.addImport("mod", "func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
kExprLocalGet, 0,
kExprLocalGet, 1,
kExprCallFunction, func_index
])
.exportFunc();
let x = 12;
function import_func(suspender, param) {
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
return x + param;
}
let instance = builder.instantiate({ mod: { func: import_func } });
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertEquals(17, main(5));
})();
(function testGenericWrapper1I32ReturnHeapNumber() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig = makeSig([kWasmAnyRef, kWasmI32], [kWasmI32]);
let sig_index = builder.addType(sig);
let func_index = builder.addImport("mod", "func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
kExprLocalGet, 0,
kExprLocalGet, 1,
kExprCallFunction, func_index
])
.exportFunc();
let x = 2147483640;
function import_func(suspender, param) {
assertInstanceof(suspender, WebAssembly.Suspender);
let result = x + param;
%SimulateNewspaceFull();
return result;
}
let instance = builder.instantiate({ mod: { func: import_func } });
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertEquals(2147483645, main(5));
})();
let kSig_i_rlili = makeSig([kWasmAnyRef, kWasmI64, kWasmI32, kWasmI64, kWasmI32],
[kWasmI32]);
(function testGenericWrapper4IParam1I32Ret() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig_index = builder.addType(kSig_i_rlili);
let func_index = builder.addImport("mod", "func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
kExprLocalGet, 0,
kExprLocalGet, 1,
kExprLocalGet, 2,
kExprLocalGet, 3,
kExprLocalGet, 4,
kExprCallFunction, func_index
])
.exportFunc();
let x = 12n;
function import_func(suspender, param1, param2, param3, param4) {
assertInstanceof(suspender, WebAssembly.Suspender);
x += 2n * param1 + BigInt(3 * param2) + 4n * param3 + BigInt(5 * param4);
return Number(x);
}
let param2 = { valueOf: () => { gc(); return 6; } };
let param3 = { valueOf: () => { gc(); return 3n; } };
let instance = builder.instantiate({ mod: { func: import_func } });
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertEquals(60, main(9n, param2, param3, 0));
})();
let kSig_r_riiili = makeSig([kWasmAnyRef, kWasmI32, kWasmI32, kWasmI32, kWasmI64,
kWasmI32], [kWasmAnyRef]);
(function testGenericWrapper5IParam() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig_index = builder.addType(kSig_r_riiili);
let func_index = builder.addImport("mod", "func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
kExprLocalGet, 0,
kExprLocalGet, 1,
kExprLocalGet, 2,
kExprLocalGet, 3,
kExprLocalGet, 4,
kExprLocalGet, 5,
kExprCallFunction, func_index
])
.exportFunc();
let x = 12;
function import_func(suspender, param1, param2, param3, param4, param5) {
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += 2 * param1 + 3 * param2 + 4 * param3 + 5 * Number(param4) + 6 * param5;
}
let param2 = { valueOf: () => { gc(); return 6; } };
let param3 = { valueOf: () => { gc(); return 3; } };
let instance = builder.instantiate({ mod: { func: import_func } });
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertEquals(undefined, main(9, param2, param3, 0n, 2));
assertEquals(72, x);
})();
let kSig_r_riiilii = makeSig([kWasmAnyRef, kWasmI32, kWasmI32, kWasmI32,
kWasmI64, kWasmI32, kWasmI32], [kWasmAnyRef]);
(function testGenericWrapper6IParam() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig_index = builder.addType(kSig_r_riiilii);
let func_index = builder.addImport("mod", "func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
kExprLocalGet, 0,
kExprLocalGet, 1,
kExprLocalGet, 2,
kExprLocalGet, 3,
kExprLocalGet, 4,
kExprLocalGet, 5,
kExprLocalGet, 6,
kExprCallFunction, func_index
])
.exportFunc();
let x = 12;
function import_func(suspender, param1, param2, param3, param4, param5,
param6) {
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += 2 * param1 + 3 * param2 + 4 * param3 + 5 * Number(param4) + 6 * param5 + 7 * param6;
}
let param2 = { valueOf: () => { gc(); return 6; } };
let param3 = { valueOf: () => { gc(); return 3; } };
let instance = builder.instantiate({ mod: { func: import_func } });
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertEquals(undefined, main(9, param2, param3, 0n, 2, 3));
assertEquals(93, x);
})();
let kSig_r_rliilliiil = makeSig([kWasmAnyRef, kWasmI64, kWasmI32, kWasmI32,
kWasmI64, kWasmI64, kWasmI32, kWasmI32, kWasmI32, kWasmI64], [kWasmI32]);
(function testGenericWrapper9IParam132Ret() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig_index = builder.addType(kSig_r_rliilliiil);
let func_index = builder.addImport("mod", "func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
kExprLocalGet, 0,
kExprLocalGet, 1,
kExprLocalGet, 2,
kExprLocalGet, 3,
kExprLocalGet, 4,
kExprLocalGet, 5,
kExprLocalGet, 6,
kExprLocalGet, 7,
kExprLocalGet, 8,
kExprLocalGet, 9,
kExprCallFunction, func_index
])
.exportFunc();
let x = 12;
function import_func(suspender, param1, param2, param3, param4, param5,
param6, param7, param8, param9) {
assertInstanceof(suspender, WebAssembly.Suspender);
x += Number(param1) + 2 * param2 + 3 * param3 + Number(4n * param4) + Number(5n * param5)
+ 6 * param6 + 7 * param7 + 8 * param8 + Number(9n * param9);
return x;
}
let param1 = { valueOf: () => { gc(); return 5n; } };
let param4 = { valueOf: () => { gc(); return 8n; } };
let param6 = { valueOf: () => { gc(); return 10; } };
let param8 = { valueOf: () => { gc(); return 12; } };
let instance = builder.instantiate({ mod: { func: import_func } });
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertEquals(360, main(param1, 6, 7, param4, 9n, param6, 11, param8, 0n));
})();
// The function expects BigInt, but gets Number.
(function testGenericWrapperTypeError() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig = makeSig([kWasmAnyRef, kWasmI64], [kWasmAnyRef]);
let sig_index = builder.addType(sig);
let func_index = builder.addImport("mod", "func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
kExprLocalGet, 0,
kExprLocalGet, 1,
kExprCallFunction, func_index
])
.exportFunc();
let x = 12n;
function import_func(suspender, param1) {
assertInstanceof(suspender, WebAssembly.Suspender);
x += param1;
}
let instance = builder.instantiate({ mod: { func: import_func } });
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertThrows(() => { main(17) }, TypeError);
})();
(function testGenericWrapper1I64Return() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig = makeSig([kWasmAnyRef], [kWasmI64]);
let sig_index = builder.addType(sig);
let func_index = builder.addImport("mod", "func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
kExprLocalGet, 0,
kExprCallFunction, func_index
])
.exportFunc();
function import_func(suspender) {
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
return 10000000000n;
}
let instance = builder.instantiate({ mod: { func: import_func } });
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertEquals(10000000000n, main());
})();
(function testGenericWrapper1F32Return() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig = makeSig([kWasmAnyRef], [kWasmF32]);
let sig_index = builder.addType(sig);
let func_index = builder.addImport("mod", "func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
kExprLocalGet, 0,
kExprCallFunction, func_index
])
.exportFunc();
function import_func(suspender) {
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
return 0.5;
}
let instance = builder.instantiate({ mod: { func: import_func } });
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertEquals(0.5, main());
})();
(function testGenericWrapper1F64Return() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig = makeSig([kWasmAnyRef], [kWasmF64]);
let sig_index = builder.addType(sig);
let func_index = builder.addImport("mod", "func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
kExprLocalGet, 0,
kExprCallFunction, func_index
])
.exportFunc();
function import_func(suspender) {
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
return 0.25;
}
let instance = builder.instantiate({ mod: { func: import_func } });
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertEquals(0.25, main());
})();
(function testGenericWrapper1Float32() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig = makeSig([kWasmAnyRef, kWasmF32], [kWasmAnyRef]);
let sig_index = builder.addType(sig);
let func_index = builder.addImport("mod", "func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
kExprLocalGet, 0,
kExprLocalGet, 1,
kExprCallFunction, func_index
])
.exportFunc();
let x = 12.5;
function import_func(suspender, param) {
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += param;
}
let instance = builder.instantiate({ mod: { func: import_func } });
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertEquals(undefined, main(12.5));
assertEquals(25, x);
})();
(function testGenericWrapper1Float64() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig = makeSig([kWasmAnyRef, kWasmF64], [kWasmAnyRef]);
let sig_index = builder.addType(sig);
let func_index = builder.addImport("mod", "func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
kExprLocalGet, 0,
kExprLocalGet, 1,
kExprCallFunction, func_index
])
.exportFunc();
let x = 12.5;
function import_func(suspender, param) {
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += param;
}
let instance = builder.instantiate({ mod: { func: import_func } });
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertEquals(undefined, main(12.5));
assertEquals(25, x);
})();
let kSig_r_rffddddff = makeSig([kWasmAnyRef, kWasmF32, kWasmF32, kWasmF64,
kWasmF64, kWasmF64, kWasmF64, kWasmF32, kWasmF32], [kWasmAnyRef]);
(function testGenericWrapper8Floats() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig_index = builder.addType(kSig_r_rffddddff);
let func_index = builder.addImport("mod", "func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
kExprLocalGet, 0,
kExprLocalGet, 1,
kExprLocalGet, 2,
kExprLocalGet, 3,
kExprLocalGet, 4,
kExprLocalGet, 5,
kExprLocalGet, 6,
kExprLocalGet, 7,
kExprLocalGet, 8,
kExprCallFunction, func_index
])
.exportFunc();
let x = 12;
function import_func(suspender, param1, param2, param3, param4, param5,
param6, param7, param8) {
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += param1 + 2 * param2 + 3 * param3 + 4 * param4 + 5 * param5
+ 6 * param6 + 7 * param7 + 8 * param8;
}
let param1 = { valueOf: () => { gc(); return 1.5; } };
let param4 = { valueOf: () => { gc(); return 4.5; } };
let param6 = { valueOf: () => { gc(); return 6.5; } };
let param8 = { valueOf: () => { gc(); return 8.5; } };
let instance = builder.instantiate({ mod: { func: import_func } });
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertEquals(undefined, main(param1, 2.5, 3.5, param4, 5.5, param6, 7.5,
param8));
assertEquals(234, x);
})();
let kSig_r_riiliffddlfdff = makeSig([kWasmAnyRef, kWasmI32, kWasmI32, kWasmI64,
kWasmI32, kWasmF32, kWasmF32, kWasmF64, kWasmF64, kWasmI64, kWasmF32,
kWasmF64, kWasmF32, kWasmF32], [kWasmAnyRef]);
// Floats don't fit into param registers.
(function testGenericWrapper13ParamMix() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig_index = builder.addType(kSig_r_riiliffddlfdff);
let func_index = builder.addImport("mod", "func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
kExprLocalGet, 0,
kExprLocalGet, 1,
kExprLocalGet, 2,
kExprLocalGet, 3,
kExprLocalGet, 4,
kExprLocalGet, 5,
kExprLocalGet, 6,
kExprLocalGet, 7,
kExprLocalGet, 8,
kExprLocalGet, 9,
kExprLocalGet, 10,
kExprLocalGet, 11,
kExprLocalGet, 12,
kExprLocalGet, 13,
kExprCallFunction, func_index
])
.exportFunc();
let x = 12;
let y = 1.0;
function import_func(suspender, parami1, parami2, paraml1, parami3, paramf1,
paramf2, paramd1, paramd2, paraml2, paramf3, paramd3, paramf4, paramf5) {
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += parami1 + 2 * parami2 + 3 * Number(paraml1) + 4 * parami3
+ 5 * Number(paraml2);
y += paramf1 + 2 * paramf2 + 3 * paramd1 + 4 * paramd2 + 5 * paramf3
+ 6 * paramd3 + 7 * paramf4 + 8 * paramf5;
}
let instance = builder.instantiate({ mod: { func: import_func } });
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertEquals(undefined, main(5, 6, 7n, 8, 1.5, 2.5, 3.5, 4.5, 11n, 5.5, 6.5,
7.5, 8.5));
assertEquals(137, x);
assertEquals(223, y);
})();
let kSig_r_riiliiiffddli = makeSig([kWasmAnyRef, kWasmI32, kWasmI32, kWasmI64,
kWasmI32, kWasmI32, kWasmI32, kWasmF32, kWasmF32, kWasmF64, kWasmF64,
kWasmI64, kWasmI32], [kWasmAnyRef]);
// Integers don't fit into param registers.
(function testGenericWrapper12ParamMix() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig_index = builder.addType(kSig_r_riiliiiffddli);
let func_index = builder.addImport("mod", "func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
kExprLocalGet, 0,
kExprLocalGet, 1,
kExprLocalGet, 2,
kExprLocalGet, 3,
kExprLocalGet, 4,
kExprLocalGet, 5,
kExprLocalGet, 6,
kExprLocalGet, 7,
kExprLocalGet, 8,
kExprLocalGet, 9,
kExprLocalGet, 10,
kExprLocalGet, 11,
kExprLocalGet, 12,
kExprCallFunction, func_index
])
.exportFunc();
let x = 12;
let y = 1.0;
function import_func(suspender, param1, param2, param3, param4, param5,
param6, paramf1, paramf2, paramd1, paramd2, param7, param8) {
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += param1 + 2 * param2 + 3 * Number(param3) + 4 * param4 + 5 * param5
+ 6 * param6 + 7 * Number(param7) + 8 * param8;
y += paramf1 + paramf2 + paramd1 + paramd2;
}
let param1 = { valueOf: () => { gc(); return 5; } };
let param4 = { valueOf: () => { gc(); return 8; } };
let param6 = { valueOf: () => { gc(); return 10; } };
let param8 = { valueOf: () => { gc(); return 12; } };
let instance = builder.instantiate({ mod: { func: import_func } });
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertEquals(undefined, main(param1, 6, 7n, param4, 9, param6,
1.5, 2.5, 3.6, 4.4, 11n, param8));
assertEquals(360, x);
assertEquals(13, y);
})();
let kSig_f_riiliiiffddlifffdi = makeSig([kWasmAnyRef, kWasmI32, kWasmI32,
kWasmI64, kWasmI32, kWasmI32, kWasmI32, kWasmF32, kWasmF32, kWasmF64,
kWasmF64, kWasmI64, kWasmI32, kWasmF32, kWasmF32, kWasmF32, kWasmF64,
kWasmI32], [kWasmF32]);
// Integers and floats don't fit into param registers.
(function testGenericWrapper17ParamMix() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig_index = builder.addType(kSig_f_riiliiiffddlifffdi);
let func_index = builder.addImport("mod", "func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
kExprLocalGet, 0,
kExprLocalGet, 1,
kExprLocalGet, 2,
kExprLocalGet, 3,
kExprLocalGet, 4,
kExprLocalGet, 5,
kExprLocalGet, 6,
kExprLocalGet, 7,
kExprLocalGet, 8,
kExprLocalGet, 9,
kExprLocalGet, 10,
kExprLocalGet, 11,
kExprLocalGet, 12,
kExprLocalGet, 13,
kExprLocalGet, 14,
kExprLocalGet, 15,
kExprLocalGet, 16,
kExprLocalGet, 17,
kExprCallFunction, func_index
])
.exportFunc();
let x = 12;
function import_func(suspender, param1, param2, param3, param4, param5,
param6, paramf1, paramf2, paramd1, paramd2, param7, param8, paramf3,
paramf4, paramf5, paramd3, param9) {
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += param1 + 2 * param2 + 3 * Number(param3) + 4 * param4 + 5 * param5
+ 6 * param6 + 7 * Number(param7) + 8 * param8 + 9 * param9;
let y = 1.0;
y += paramf1 + 2 * paramf2 + 3 * paramd1 + 4 * paramd2 + 5 * paramf3
+ 6 * paramf4 + 7 * paramf5 + 8 * paramd3;
return y;
}
let param1 = { valueOf: () => { gc(); return 5; } };
let param4 = { valueOf: () => { gc(); return 8; } };
let param6 = { valueOf: () => { gc(); return 10; } };
let param8 = { valueOf: () => { gc(); return 12; } };
let paramd1 = { valueOf: () => { gc(); return 3.5; } };
let paramf3 = { valueOf: () => { gc(); return 5.5; } };
let param9 = { valueOf: () => { gc(); return 0; } };
let instance = builder.instantiate({ mod: { func: import_func } });
let main = WebAssembly.returnPromiseOnSuspend(instance.exports.main);
assertEquals(223, main(param1, 6, 7n, param4, 9, param6, 1.5, 2.5, paramd1,
4.5, 11n, param8, paramf3, 6.5, 7.5, 8.5, param9));
assertEquals(360, x);
})();
(function testCallFromOptimizedFunction() {
print(arguments.callee.name);
const builder = new WasmModuleBuilder();
builder.addFunction('wasm_fn', kSig_r_r).addBody([
kExprLocalGet, 0
]).exportFunc();
instance = builder.instantiate();
function js_caller() {
return WebAssembly.returnPromiseOnSuspend(instance.exports.wasm_fn)();
}
%PrepareFunctionForOptimization(js_caller);
js_caller();
%OptimizeFunctionOnNextCall(js_caller);
js_caller();
})();
(function Regression1130385() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig_index = builder.addType(kSig_i_r);
builder.addFunction("f0", sig_index)
.addBody([kExprI32Const, 12])
.exportFunc();
builder.addFunction("f1", sig_index)
.addBody([kExprI32Const, 15])
.exportFunc();
let instance = builder.instantiate();
let f1 = WebAssembly.returnPromiseOnSuspend(instance.exports.f1);
assertEquals(15, f1());
})();
(function testDeoptWithIncorrectNumberOfParams() {
print(arguments.callee.name);
const builder = new WasmModuleBuilder();
let sig = makeSig([kWasmAnyRef, kWasmI32, kWasmI32], [kWasmAnyRef]);
let sig_index = builder.addType(sig);
let imp = builder.addImport('q', 'func', sig_index);
builder.addFunction('main', sig_index)
.addBody([
kExprLocalGet, 0,
kExprLocalGet, 1,
kExprLocalGet, 2,
kExprCallFunction, imp])
.exportAs('main');
function deopt() {
%DeoptimizeFunction(caller);
}
let main = WebAssembly.returnPromiseOnSuspend(
builder.instantiate({q: {func: deopt}}).exports.main);
function caller() {
main(1, 2, 3, 4, 5);
main(1, 2, 3, 4);
main(1, 2, 3);
main(1, 2);
main(1);
main();
}
caller();
})();
(function testGenericWrapper6Ref7F64Param() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig_r_rddrrrrrrddddd = builder.addType(makeSig(
[kWasmAnyRef, kWasmF64, kWasmF64, kWasmExternRef, kWasmExternRef,
kWasmExternRef, kWasmExternRef, kWasmExternRef, kWasmExternRef, kWasmF64,
kWasmF64, kWasmF64, kWasmF64, kWasmF64],
[kWasmExternRef]));
builder.addFunction("func0", sig_r_rddrrrrrrddddd)
.addBody([
kExprLocalGet, 8,
])
.exportAs("func0");
let module = new WebAssembly.Module(builder.toBuffer());
let instance = new WebAssembly.Instance(module);
let func0 = WebAssembly.returnPromiseOnSuspend(instance.exports.func0);
let res = func0(1, 2, "3", "4", "5", "6", "7", "8", 9, 10, 11, 12, 13);
assertEquals("8", res);
})();
......@@ -67,7 +67,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
// Check the wrapped export's signature.
let export_sig = WebAssembly.Function.type(export_wrapper);
assertEquals(['externref', 'i32'], export_sig.parameters);
assertEquals(['i32'], export_sig.parameters);
assertEquals(['externref'], export_sig.results);
// Check the wrapped import's signature.
......@@ -84,9 +84,6 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
let instance = builder.instantiate();
let suspender = new WebAssembly.Suspender();
let wrapper = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
assertThrows(() => wrapper(undefined),
WebAssembly.RuntimeError,
/type incompatibility when transforming from\/to JS/);
})();
(function TestStackSwitchNoSuspend() {
......@@ -99,9 +96,8 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
kExprGlobalSet, 0,
kExprI32Const, 0]).exportFunc();
let instance = builder.instantiate();
let suspender = new WebAssembly.Suspender();
let wrapper = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
wrapper(suspender);
wrapper();
assertEquals(42, instance.exports.g.value);
})();
......@@ -120,8 +116,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
() => Promise.resolve(42)));
let instance = builder.instantiate({m: {import: js_import}});
let wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
let suspender = new WebAssembly.Suspender();
let combined_promise = wrapped_export(suspender);
let combined_promise = wrapped_export();
combined_promise.then(v => assertEquals(42, v));
// Also try with a JS function with a mismatching arity.
......@@ -131,8 +126,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
(unused) => Promise.resolve(42)));
instance = builder.instantiate({m: {import: js_import}});
wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
suspender = new WebAssembly.Suspender();
combined_promise = wrapped_export(suspender);
combined_promise = wrapped_export();
combined_promise.then(v => assertEquals(42, v));
// Also try with a proxy.
......@@ -142,8 +136,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
new Proxy(() => Promise.resolve(42), {})));
instance = builder.instantiate({m: {import: js_import}});
wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
suspender = new WebAssembly.Suspender();
combined_promise = wrapped_export(suspender);
combined_promise = wrapped_export();
combined_promise.then(v => assertEquals(42, v));
})();
......@@ -176,10 +169,9 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
kExprEnd,
kExprI32Const, 0,
]).exportFunc();
let suspender = new WebAssembly.Suspender();
let i = 0;
// The n-th call to the import returns a promise that resolves to n.
function js_import(suspender) {
function js_import() {
return Promise.resolve(++i);
};
let wasm_js_import = new WebAssembly.Function(
......@@ -188,11 +180,12 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
WebAssembly.suspendOnReturnedPromise(wasm_js_import);
let instance = builder.instantiate({m: {import: suspending_wasm_js_import}});
let wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
let chained_promise = wrapped_export(suspender);
let chained_promise = wrapped_export();
assertEquals(0, instance.exports.g.value);
chained_promise.then(_ => assertEquals(15, instance.exports.g.value));
})();
// Call the GC in the import call.
(function TestStackSwitchGC() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
......@@ -203,14 +196,13 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
kExprCallFunction, gc_index,
kExprI32Const, 0
]).exportFunc();
let suspender = new WebAssembly.Suspender();
let js_import = WebAssembly.suspendOnReturnedPromise(
new WebAssembly.Function(
{parameters: [], results: ['externref']},
gc));
let instance = builder.instantiate({'m': {'gc': js_import}});
let wrapper = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
wrapper(suspender);
wrapper();
})();
// Call the GC during param conversion.
......@@ -232,8 +224,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
let instance = builder.instantiate({'m': {'import': js_import}});
let wrapper = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
let arg = { valueOf: () => { gc(); return 24; } };
let suspender = new WebAssembly.Suspender();
wrapper(suspender, arg).then((v) => assertEquals(arg.valueOf(), v));
wrapper(arg).then((v) => assertEquals(arg.valueOf(), v));
})();
// Check that the suspender does not suspend if the import's
......@@ -250,15 +241,14 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
kExprGlobalSet, 0, // resume
kExprGlobalGet, 0,
]).exportFunc();
let suspender = new WebAssembly.Suspender();
function js_import(suspender) {
function js_import() {
return 42
};
let wasm_js_import = new WebAssembly.Function({parameters: [], results: ['externref']}, js_import);
let suspending_wasm_js_import = WebAssembly.suspendOnReturnedPromise(wasm_js_import);
let instance = builder.instantiate({m: {import: suspending_wasm_js_import}});
let wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
let result = wrapped_export(suspender);
let result = wrapped_export();
assertEquals(42, instance.exports.g.value);
})();
......@@ -293,10 +283,10 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
let instance = builder.instantiate({m: {import: suspending_wasm_js_import}});
let wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
let args = [suspender, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
let args = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
let combined_promise =
wrapped_export.apply(null, args);
combined_promise.then(v => assertEquals(reduce(args.slice(1)), v));
combined_promise.then(v => assertEquals(reduce(args), v));
})();
(function TestStackSwitchReturnFloat() {
......@@ -309,8 +299,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
kExprLocalGet, 0,
kExprCallFunction, import_index, // suspend
]).exportFunc();
let suspender = new WebAssembly.Suspender();
function js_import(suspender) {
function js_import() {
return Promise.resolve(0.5);
};
let wasm_js_import = new WebAssembly.Function(
......@@ -320,7 +309,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
let instance = builder.instantiate({m: {import: suspending_wasm_js_import}});
let wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
let combined_promise = wrapped_export(suspender);
let combined_promise = wrapped_export();
combined_promise.then(v => assertEquals(0.5, v));
})();
......@@ -332,10 +321,9 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
builder.addFunction("throw", kSig_i_r)
.addBody([kExprThrow, tag]).exportFunc();
let instance = builder.instantiate();
let suspender = new WebAssembly.Suspender();
let wrapper = WebAssembly.returnPromiseOnSuspend(instance.exports.throw);
try {
wrapper(suspender);
wrapper();
assertUnreachable();
} catch (e) {
assertTrue(e instanceof WebAssembly.Exception);
......@@ -356,8 +344,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
kExprCallFunction, import_index,
kExprThrow, tag_index
]).exportFunc();
let suspender = new WebAssembly.Suspender();
function js_import(suspender) {
function js_import() {
return Promise.resolve(42);
};
let wasm_js_import = new WebAssembly.Function(
......@@ -367,7 +354,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
let instance = builder.instantiate({m: {import: suspending_wasm_js_import, tag: tag}});
let wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
let combined_promise = wrapped_export(suspender);
let combined_promise = wrapped_export();
assertThrowsAsync(combined_promise, WebAssembly.Exception);
})();
......@@ -385,8 +372,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
kExprCatch, tag_index,
kExprEnd,
]).exportFunc();
let suspender = new WebAssembly.Suspender();
function js_import(suspender) {
function js_import() {
return Promise.reject(new WebAssembly.Exception(tag, [42]));
};
let wasm_js_import = new WebAssembly.Function(
......@@ -396,55 +382,10 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
let instance = builder.instantiate({m: {import: suspending_wasm_js_import, tag: tag}});
let wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
let combined_promise = wrapped_export(suspender);
let combined_promise = wrapped_export();
assertPromiseResult(combined_promise, v => assertEquals(v, 42));
})();
(function TestReenterActiveSuspenderFails() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let import_index = builder.addImport("m", "i", kSig_v_r);
builder.addFunction("test", kSig_i_r)
.addBody([
kExprLocalGet, 0,
kExprCallFunction, import_index,
kExprI32Const, 0
]).exportFunc();
let wrapped_export;
let suspender;
function js_import() {
wrapped_export(suspender); // Re-enter the same wrapped export.
}
let instance = builder.instantiate({m: {i: js_import}});
suspender = new WebAssembly.Suspender();
wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
assertThrows(() => wrapped_export(suspender), WebAssembly.RuntimeError,
/re-entering an active\/suspended suspender/);
})();
(function TestReenterSuspendedSuspenderFails() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let import_index = builder.addImport("m", "i", kSig_v_r);
builder.addFunction("test", kSig_i_r)
.addBody([
kExprLocalGet, 0,
kExprCallFunction, import_index,
kExprI32Const, 0
]).exportFunc();
let suspender = new WebAssembly.Suspender();
let i = WebAssembly.suspendOnReturnedPromise(
new WebAssembly.Function(
{parameters: [], results: ['externref']},
() => Promise.resolve(0)));
let instance = builder.instantiate({m: {i}});
let wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
let promise1 = wrapped_export(suspender);
// Re-enter the suspender before resolving the promise.
assertThrows(() => wrapped_export(suspender), WebAssembly.RuntimeError,
/re-entering an active\/suspended suspender/);
})();
function TestNestedSuspenders(suspend) {
// Nest two suspenders. The call chain looks like:
// outer (wasm) -> outer (js) -> inner (wasm) -> inner (js)
......@@ -468,8 +409,6 @@ function TestNestedSuspenders(suspend) {
kExprLocalGet, 0,
kExprCallFunction, inner_index
]).exportFunc();
let outer_suspender = new WebAssembly.Suspender();
let inner_suspender = new WebAssembly.Suspender();
let inner = WebAssembly.suspendOnReturnedPromise(
new WebAssembly.Function(
......@@ -480,15 +419,15 @@ function TestNestedSuspenders(suspend) {
let outer = WebAssembly.suspendOnReturnedPromise(
new WebAssembly.Function(
{parameters: [], results: ['externref']},
() => export_inner(inner_suspender)));
() => export_inner()));
let instance = builder.instantiate({m: {inner, outer}});
export_inner = WebAssembly.returnPromiseOnSuspend(instance.exports.inner);
let export_outer = WebAssembly.returnPromiseOnSuspend(instance.exports.outer);
if (suspend) {
assertPromiseResult(export_outer(outer_suspender), v => assertEquals(42, v));
assertPromiseResult(export_outer(), v => assertEquals(42, v));
} else {
assertEquals(export_outer(outer_suspender), 42);
assertEquals(export_outer(), 42);
}
}
......@@ -501,26 +440,3 @@ function TestNestedSuspenders(suspend) {
print(arguments.callee.name);
TestNestedSuspenders(false);
})();
(function TestReenterInactiveSuspender() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let import_index = builder.addImport("m", "i", kSig_i_r);
builder.addFunction("test", kSig_i_r)
.addBody([
kExprLocalGet, 0,
kExprCallFunction, import_index,
]).exportFunc();
let suspender = new WebAssembly.Suspender();
let i = WebAssembly.suspendOnReturnedPromise(
new WebAssembly.Function(
{parameters: [], results: ['externref']},
() => Promise.resolve(0)));
let instance = builder.instantiate({m: {i}});
let wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
assertPromiseResult(
wrapped_export(suspender),
() => assertPromiseResult(
wrapped_export(suspender),
v => assertEquals(v, 0)));
})();
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