[wasm-gc] Allow Js -> Wasm wrapper inlining for (non-null) ref extern
This is a follow-up to https://crrev.com/c/4204032 which allowed wrapper inlining for the nullable externref type. Bug: v8:7748 Change-Id: I5a82c37b7cf0cfcbcacbe399f8b3119176c3bba4 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4212394 Commit-Queue: Matthias Liedtke <mliedtke@chromium.org> Reviewed-by: Manos Koukoutos <manoskouk@chromium.org> Reviewed-by: Darius Mercadier <dmercadier@chromium.org> Auto-Submit: Matthias Liedtke <mliedtke@chromium.org> Cr-Commit-Position: refs/heads/main@{#85598}
This commit is contained in:
parent
8082a8f51a
commit
811d50b9c1
@ -3554,13 +3554,14 @@ bool CanInlineJSToWasmCall(const wasm::FunctionSig* wasm_signature) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wasm::ValueType externRefNonNull = wasm::kWasmExternRef.AsNonNull();
|
||||
for (auto type : wasm_signature->all()) {
|
||||
#if defined(V8_TARGET_ARCH_32_BIT)
|
||||
if (type == wasm::kWasmI64) return false;
|
||||
#endif
|
||||
if (type != wasm::kWasmI32 && type != wasm::kWasmI64 &&
|
||||
type != wasm::kWasmF32 && type != wasm::kWasmF64 &&
|
||||
type != wasm::kWasmExternRef) {
|
||||
type != wasm::kWasmExternRef && type != externRefNonNull) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -730,6 +730,7 @@ Type JSWasmCallNode::TypeForWasmReturnType(const wasm::ValueType& type) {
|
||||
case wasm::kF32:
|
||||
case wasm::kF64:
|
||||
return Type::Number();
|
||||
case wasm::kRef:
|
||||
case wasm::kRefNull:
|
||||
CHECK_EQ(type.heap_type(), wasm::HeapType::kExtern);
|
||||
return Type::Any();
|
||||
|
@ -2033,6 +2033,7 @@ class RepresentationSelector {
|
||||
return MachineType::Float32();
|
||||
case wasm::kF64:
|
||||
return MachineType::Float64();
|
||||
case wasm::kRef:
|
||||
case wasm::kRefNull:
|
||||
return MachineType::AnyTagged();
|
||||
default:
|
||||
@ -2057,6 +2058,7 @@ class RepresentationSelector {
|
||||
// WasmWrapperGraphBuilder::BuildJSToWasmWrapper.
|
||||
return UseInfo::CheckedNumberOrOddballAsFloat64(kDistinguishZeros,
|
||||
feedback);
|
||||
case wasm::kRef:
|
||||
case wasm::kRefNull:
|
||||
return UseInfo::AnyTagged();
|
||||
default:
|
||||
|
@ -72,6 +72,14 @@ struct ConvertJSValue<uint32_t> {
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ConvertJSValue<std::nullptr_t> {
|
||||
static v8::Maybe<std::nullptr_t> Get(v8::Local<v8::Value> value,
|
||||
v8::Local<v8::Context> context) {
|
||||
return value->IsNull() ? v8::Just(nullptr) : v8::Nothing<std::nullptr_t>();
|
||||
}
|
||||
};
|
||||
|
||||
// NaNs and +/-Infinity should be 0, otherwise (modulo 2^64) - 2^63.
|
||||
// Step 8 - 12 of https://heycam.github.io/webidl/#abstract-opdef-converttoint
|
||||
// The int64_t and uint64_t implementations below are copied from Blink:
|
||||
|
@ -47,11 +47,16 @@ bool CheckType<v8::Local<v8::String>>(v8::Local<v8::Value> result) {
|
||||
return result->IsString();
|
||||
}
|
||||
|
||||
template <>
|
||||
bool CheckType<std::nullptr_t>(v8::Local<v8::Value> result) {
|
||||
return result->IsNull();
|
||||
}
|
||||
|
||||
static TestSignatures sigs;
|
||||
|
||||
struct ExportedFunction {
|
||||
std::string name;
|
||||
FunctionSig* signature;
|
||||
const FunctionSig* signature;
|
||||
std::vector<ValueType> locals;
|
||||
std::vector<uint8_t> code;
|
||||
|
||||
@ -84,7 +89,14 @@ DECLARE_EXPORTED_FUNCTION(i64_square, sigs.l_l(),
|
||||
WASM_CODE({WASM_LOCAL_GET(0), WASM_LOCAL_GET(0),
|
||||
kExprI64Mul}))
|
||||
|
||||
DECLARE_EXPORTED_FUNCTION(externref_id, sigs.a_a(),
|
||||
DECLARE_EXPORTED_FUNCTION(externref_null_id, sigs.a_a(),
|
||||
WASM_CODE({WASM_LOCAL_GET(0)}))
|
||||
|
||||
static constexpr ValueType extern_extern_types[] = {kWasmExternRef.AsNonNull(),
|
||||
kWasmExternRef.AsNonNull()};
|
||||
static constexpr FunctionSig sig_extern_extern(1, 1, extern_extern_types);
|
||||
|
||||
DECLARE_EXPORTED_FUNCTION(externref_id, &sig_extern_extern,
|
||||
WASM_CODE({WASM_LOCAL_GET(0)}))
|
||||
|
||||
DECLARE_EXPORTED_FUNCTION(f32_square, sigs.f_f(),
|
||||
@ -273,6 +285,7 @@ class FastJSWasmCallTester {
|
||||
: allocator_(),
|
||||
zone_(&allocator_, ZONE_NAME),
|
||||
builder_(zone_.New<WasmModuleBuilder>(&zone_)) {
|
||||
i::v8_flags.experimental_wasm_typed_funcref = true;
|
||||
i::v8_flags.allow_natives_syntax = true;
|
||||
i::v8_flags.turbo_inline_js_wasm_calls = true;
|
||||
i::v8_flags.stress_background_compile = false;
|
||||
@ -817,6 +830,19 @@ TEST(TestFastJSWasmCall_I64NegativeResult) {
|
||||
"i64_add", {v8_bigint(1ll), v8_bigint(-2ll)}, v8_bigint(-1ll));
|
||||
}
|
||||
|
||||
TEST(TestFastJSWasmCall_ExternrefNullArg) {
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
FastJSWasmCallTester tester;
|
||||
tester.AddExportedFunction(k_externref_null_id);
|
||||
Local<Primitive> v8_null = v8::Null(CcTest::isolate());
|
||||
tester.CallAndCheckWasmFunction("externref_null_id", {v8_null}, nullptr);
|
||||
tester.CallAndCheckWasmFunction("externref_null_id", {v8_num(42)}, 42);
|
||||
tester.CallAndCheckWasmFunctionBigInt("externref_null_id", {v8_bigint(42)},
|
||||
v8_bigint(42));
|
||||
auto str = v8_str("test");
|
||||
tester.CallAndCheckWasmFunction("externref_null_id", {str}, str);
|
||||
}
|
||||
|
||||
TEST(TestFastJSWasmCall_ExternrefArg) {
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
FastJSWasmCallTester tester;
|
||||
|
@ -6,12 +6,23 @@
|
||||
|
||||
d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
|
||||
function testOptimized(run, fctToOptimize) {
|
||||
%PrepareFunctionForOptimization(fctToOptimize);
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
run();
|
||||
}
|
||||
%OptimizeFunctionOnNextCall(fctToOptimize);
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
run();
|
||||
}
|
||||
}
|
||||
|
||||
(function TestInliningStructGet() {
|
||||
print(arguments.callee.name);
|
||||
let builder = new WasmModuleBuilder();
|
||||
let struct = builder.addStruct([makeField(kWasmI32, true)]);
|
||||
|
||||
builder.addFunction('createStruct', makeSig([kWasmI32], [kWasmExternRef]))
|
||||
builder.addFunction('createStructNull', makeSig([kWasmI32], [kWasmExternRef]))
|
||||
.addBody([
|
||||
kExprLocalGet, 0,
|
||||
kGCPrefix, kExprStructNew, struct,
|
||||
@ -19,7 +30,25 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
])
|
||||
.exportFunc();
|
||||
|
||||
builder.addFunction('getElement', makeSig([kWasmExternRef], [kWasmI32]))
|
||||
builder.addFunction('getElementNull', makeSig([kWasmExternRef], [kWasmI32]))
|
||||
.addBody([
|
||||
kExprLocalGet, 0,
|
||||
kGCPrefix, kExprExternInternalize,
|
||||
kGCPrefix, kExprRefCast, struct,
|
||||
kGCPrefix, kExprStructGet, struct, 0])
|
||||
.exportFunc();
|
||||
|
||||
builder.addFunction('createStruct',
|
||||
makeSig([kWasmI32], [wasmRefType(kWasmExternRef)]))
|
||||
.addBody([
|
||||
kExprLocalGet, 0,
|
||||
kGCPrefix, kExprStructNew, struct,
|
||||
kGCPrefix, kExprExternExternalize,
|
||||
])
|
||||
.exportFunc();
|
||||
|
||||
builder.addFunction('getElement',
|
||||
makeSig([wasmRefType(kWasmExternRef)], [kWasmI32]))
|
||||
.addBody([
|
||||
kExprLocalGet, 0,
|
||||
kGCPrefix, kExprExternInternalize,
|
||||
@ -31,24 +60,27 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
let wasm = instance.exports;
|
||||
let n = 100;
|
||||
|
||||
const createStruct = wasm.createStruct;
|
||||
const getElement = wasm.getElement;
|
||||
for (let [create, get] of [
|
||||
[wasm.createStruct, wasm.getElement],
|
||||
[wasm.createStructNull, wasm.getElementNull]]) {
|
||||
let fct = () => {
|
||||
let res = 0;
|
||||
for (let i = 1; i <= n; ++i) {
|
||||
const struct = create(i);
|
||||
res += get(struct);
|
||||
}
|
||||
return res;
|
||||
};
|
||||
testOptimized(() => assertEquals((n * n + n) / 2, fct()), fct);
|
||||
|
||||
let fct = () => {
|
||||
let res = 0;
|
||||
for (let i = 1; i <= n; ++i) {
|
||||
const struct = createStruct(i);
|
||||
res += getElement(struct);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
%PrepareFunctionForOptimization(fct);
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
assertEquals((n * n + n) / 2, fct());
|
||||
}
|
||||
%OptimizeFunctionOnNextCall(fct);
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
assertEquals((n * n + n) / 2, fct());
|
||||
let getNull = () => get(null);
|
||||
let fctNullValue = () => {
|
||||
for (let i = 1; i <= n; ++i) {
|
||||
// Depending on the param type (ref / ref.null), either the wrapper or
|
||||
// the cast inside the function will throw.
|
||||
assertThrows(getNull);
|
||||
}
|
||||
};
|
||||
testOptimized(fctNullValue, getNull);
|
||||
}
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user