[wasm] Use generic js-to-wasm wrapper for 0 or 1 int32 return case
The generic wrapper can be used for Wasm functions with int32 parameters and 0 or 1 int32 return values. Added tests for cases when the return value can & cannot be converted to a Smi. Bug: v8:10701 Change-Id: I470954ed0aced0e4ec6e65a9f38caac19c576549 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2390141 Commit-Queue: Eva Herencsárová <evih@google.com> Reviewed-by: Andreas Haas <ahaas@chromium.org> Reviewed-by: Thibaud Michaud <thibaudm@chromium.org> Cr-Commit-Position: refs/heads/master@{#69700}
This commit is contained in:
parent
c878e00db8
commit
17cda1e6f1
@ -3295,6 +3295,10 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
|
||||
Foreign::kForeignAddressOffset)));
|
||||
foreign_signature = no_reg;
|
||||
|
||||
Register return_count = r8;
|
||||
__ movq(return_count,
|
||||
MemOperand(signature, wasm::FunctionSig::kReturnCountOffset));
|
||||
|
||||
Register param_count = signature;
|
||||
__ movq(param_count,
|
||||
MemOperand(signature, wasm::FunctionSig::kParameterCountOffset));
|
||||
@ -3311,9 +3315,11 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
|
||||
constexpr int kGCScanSlotCountOffset =
|
||||
kFrameMarkerOffset - kSystemPointerSize;
|
||||
constexpr int kParamCountOffset = kGCScanSlotCountOffset - kSystemPointerSize;
|
||||
constexpr int kNumSpillSlots = 2;
|
||||
constexpr int kReturnCountOffset = kParamCountOffset - kSystemPointerSize;
|
||||
constexpr int kNumSpillSlots = 3;
|
||||
__ subq(rsp, Immediate(kNumSpillSlots * kSystemPointerSize));
|
||||
__ movq(MemOperand(rbp, kParamCountOffset), param_count);
|
||||
__ movq(MemOperand(rbp, kReturnCountOffset), return_count);
|
||||
|
||||
__ cmpl(param_count, Immediate(0));
|
||||
|
||||
@ -3375,14 +3381,14 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
|
||||
__ movq(param, MemOperand(rbp, current_param, times_1, 0));
|
||||
__ addq(current_param, Immediate(increment));
|
||||
|
||||
Label not_smi;
|
||||
__ JumpIfNotSmi(param, ¬_smi);
|
||||
Label param_not_smi;
|
||||
__ JumpIfNotSmi(param, ¶m_not_smi);
|
||||
|
||||
// Change from smi to int32.
|
||||
__ SmiUntag(param);
|
||||
|
||||
Label conversion_done;
|
||||
__ bind(&conversion_done);
|
||||
Label param_conversion_done;
|
||||
__ bind(¶m_conversion_done);
|
||||
|
||||
__ pushq(param);
|
||||
|
||||
@ -3436,7 +3442,8 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
|
||||
function_entry = no_reg;
|
||||
|
||||
// Restore rsp to free the reserved stack slots for 5 param Registers.
|
||||
constexpr int kLastSpillOffset = kParamCountOffset;
|
||||
constexpr int kLastSpillOffset =
|
||||
kFrameMarkerOffset - kNumSpillSlots * kSystemPointerSize;
|
||||
__ leaq(rsp, MemOperand(rbp, kLastSpillOffset));
|
||||
__ movq(param_count, MemOperand(rbp, kParamCountOffset));
|
||||
|
||||
@ -3446,9 +3453,23 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
|
||||
thread_in_wasm_flag_addr,
|
||||
MemOperand(kRootRegister, Isolate::thread_in_wasm_flag_address_offset()));
|
||||
__ movl(MemOperand(thread_in_wasm_flag_addr, 0), Immediate(0));
|
||||
thread_in_wasm_flag_addr = no_reg;
|
||||
|
||||
// Handle returns.
|
||||
__ movq(return_count, MemOperand(rbp, kReturnCountOffset));
|
||||
Register return_reg = rax;
|
||||
|
||||
// If we have 1 return value, then jump to conversion.
|
||||
__ cmpl(return_count, Immediate(1));
|
||||
Label convert_return;
|
||||
__ j(equal, &convert_return);
|
||||
|
||||
// Otherwise load undefined.
|
||||
__ LoadRoot(return_reg, RootIndex::kUndefinedValue);
|
||||
|
||||
Label return_done;
|
||||
__ bind(&return_done);
|
||||
|
||||
// Deconstrunct the stack frame.
|
||||
__ LeaveFrame(StackFrame::JS_TO_WASM);
|
||||
|
||||
@ -3469,7 +3490,7 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
|
||||
__ ret(0);
|
||||
|
||||
// Handle the conversion to int32 when the param is not a smi.
|
||||
__ bind(¬_smi);
|
||||
__ bind(¶m_not_smi);
|
||||
|
||||
// The order of pushes is important. We want the heap objects, that should be
|
||||
// scanned by GC, to be on the top of the stack.
|
||||
@ -3497,8 +3518,38 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
|
||||
__ popq(param_limit);
|
||||
__ popq(current_param);
|
||||
__ movq(param_count, MemOperand(rbp, kParamCountOffset));
|
||||
__ jmp(¶m_conversion_done);
|
||||
|
||||
__ jmp(&conversion_done);
|
||||
__ bind(&convert_return);
|
||||
|
||||
Label to_heapnumber;
|
||||
// If pointer compression is disabled, we can convert the return to a smi.
|
||||
if (SmiValuesAre32Bits()) {
|
||||
__ SmiTag(return_reg);
|
||||
} else {
|
||||
Register temp = rbx;
|
||||
__ movq(temp, return_reg);
|
||||
// Double the return value to test if it can be a Smi.
|
||||
__ addl(temp, return_reg);
|
||||
// If there was overflow, convert the return value to a HeapNumber.
|
||||
__ j(overflow, &to_heapnumber);
|
||||
// If there was no overflow, we can convert to Smi.
|
||||
__ SmiTag(return_reg);
|
||||
}
|
||||
__ jmp(&return_done);
|
||||
|
||||
// Handle the conversion of the return value to HeapNumber when it cannot be a
|
||||
// smi.
|
||||
__ bind(&to_heapnumber);
|
||||
// We have to make sure that the kGCScanSlotCount is set correctly. For this
|
||||
// builtin it's the same as for the Wasm call = 0, so we don't have to reset
|
||||
// it.
|
||||
// We don't need the JS context for this builtin call.
|
||||
__ Call(BUILTIN_CODE(masm->isolate(), WasmInt32ToHeapNumber),
|
||||
RelocInfo::CODE_TARGET);
|
||||
// We will need the parameter_count later.
|
||||
__ movq(param_count, MemOperand(rbp, kParamCountOffset));
|
||||
__ jmp(&return_done);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -267,14 +267,21 @@ void WasmCompilationUnit::CompileWasmFunction(Isolate* isolate,
|
||||
|
||||
namespace {
|
||||
bool UseGenericWrapper(const FunctionSig* sig) {
|
||||
// Work only for int32 parameters and no return values for now.
|
||||
// Work only for int32 parameters and 1 or 0 return value for now.
|
||||
#if V8_TARGET_ARCH_X64
|
||||
if (sig->returns().size() > 1) {
|
||||
return false;
|
||||
}
|
||||
if (sig->returns().size() == 1 &&
|
||||
sig->GetReturn(0).kind() != ValueType::kI32) {
|
||||
return false;
|
||||
}
|
||||
for (ValueType type : sig->parameters()) {
|
||||
if (type.kind() != ValueType::kI32) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return FLAG_wasm_generic_wrapper && sig->returns().empty();
|
||||
return FLAG_wasm_generic_wrapper;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
@ -2,7 +2,7 @@
|
||||
// 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
|
||||
// Flags: --wasm-generic-wrapper --expose-gc --allow-natives-syntax
|
||||
|
||||
load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
|
||||
@ -74,7 +74,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
}
|
||||
|
||||
let instance = builder.instantiate({ mod: { func: import_func } });
|
||||
instance.exports.main(5);
|
||||
assertEquals(undefined, instance.exports.main(5));
|
||||
assertEquals(17, x);
|
||||
})();
|
||||
|
||||
@ -97,7 +97,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
|
||||
let y = { valueOf: () => { print("Hello!"); gc(); return 24; } };
|
||||
let instance = builder.instantiate({ mod: { func: import_func } });
|
||||
instance.exports.main(y);
|
||||
assertEquals(undefined, instance.exports.main(y));
|
||||
assertEquals(36, x);
|
||||
})();
|
||||
|
||||
@ -125,7 +125,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
let param2 = { valueOf: () => { gc(); return 6; } };
|
||||
let param3 = { valueOf: () => { gc(); return 3; } };
|
||||
let instance = builder.instantiate({ mod: { func: import_func } });
|
||||
instance.exports.main(9, param2, param3, 0);
|
||||
assertEquals(undefined, instance.exports.main(9, param2, param3, 0));
|
||||
assertEquals(60, x);
|
||||
})();
|
||||
|
||||
@ -164,7 +164,7 @@ let kSig_v_iiiiiiii = makeSig([kWasmI32, kWasmI32, kWasmI32, kWasmI32,
|
||||
let param6 = { valueOf: () => { gc(); return 10; } };
|
||||
let param8 = { valueOf: () => { gc(); return 12; } };
|
||||
let instance = builder.instantiate({ mod: { func: import_func } });
|
||||
instance.exports.main(param1, 6, 7, param4, 9, param6, 11, param8);
|
||||
assertEquals(undefined, instance.exports.main(param1, 6, 7, param4, 9, param6, 11, param8));
|
||||
assertEquals(360, x);
|
||||
})();
|
||||
|
||||
@ -192,7 +192,7 @@ let kSig_v_iiiiiiii = makeSig([kWasmI32, kWasmI32, kWasmI32, kWasmI32,
|
||||
|
||||
let param2 = { valueOf: () => { gc(); return 3; } };
|
||||
let instance = builder.instantiate({ mod: { func: import_func } });
|
||||
instance.exports.main(5, param2);
|
||||
assertEquals(undefined, instance.exports.main(5, param2));
|
||||
assertEquals(20, x);
|
||||
})();
|
||||
|
||||
@ -221,6 +221,49 @@ let kSig_v_iiiiiiii = makeSig([kWasmI32, kWasmI32, kWasmI32, kWasmI32,
|
||||
let param2 = { valueOf: () => { gc(); return 3; } };
|
||||
let param3 = { valueOf: () => { gc(); return 6; } };
|
||||
let instance = builder.instantiate({ mod: { func: import_func } });
|
||||
instance.exports.main(5, param2, param3, 7, 200, 300, 400);
|
||||
assertEquals(undefined, instance.exports.main(5, param2, param3, 7, 200, 300, 400));
|
||||
assertEquals(33, x);
|
||||
})();
|
||||
|
||||
(function testGenericWrapper1ReturnSmi() {
|
||||
print(arguments.callee.name);
|
||||
let builder = new WasmModuleBuilder();
|
||||
let sig_index = builder.addType(kSig_i_i);
|
||||
let func_index = builder.addImport("mod", "func", sig_index);
|
||||
builder.addFunction("main", sig_index)
|
||||
.addBody([
|
||||
kExprLocalGet, 0, kExprCallFunction, func_index
|
||||
])
|
||||
.exportFunc();
|
||||
|
||||
let x = 12;
|
||||
function import_func(param) {
|
||||
gc();
|
||||
return x + param;
|
||||
}
|
||||
|
||||
let instance = builder.instantiate({ mod: { func: import_func } });
|
||||
assertEquals(17, instance.exports.main(5));
|
||||
})();
|
||||
|
||||
(function testGenericWrapper1ReturnHeapNumber() {
|
||||
print(arguments.callee.name);
|
||||
let builder = new WasmModuleBuilder();
|
||||
let sig_index = builder.addType(kSig_i_i);
|
||||
let func_index = builder.addImport("mod", "func", sig_index);
|
||||
builder.addFunction("main", sig_index)
|
||||
.addBody([
|
||||
kExprLocalGet, 0, kExprCallFunction, func_index
|
||||
])
|
||||
.exportFunc();
|
||||
|
||||
let x = 2147483640;
|
||||
function import_func(param) {
|
||||
let result = x + param;
|
||||
%SimulateNewspaceFull();
|
||||
return result;
|
||||
}
|
||||
|
||||
let instance = builder.instantiate({ mod: { func: import_func } });
|
||||
assertEquals(2147483645, instance.exports.main(5));
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user