Commit 40ad9116 authored by Manos Koukoutos's avatar Manos Koukoutos Committed by Commit Bot

Reland "[wasm-gc] Implement call_ref on WasmJSFunction"

This is a reland of 6227c95e

Fixes compared to original landing:
- Decode a WASM_TO_JS_FUNCTION Code object as a WASM_TO_JS frame.
- Enable call_ref on WasmJSFunctions with arity mismatch.
- Use builtin pointer in BuildWasmToJSWrapper, to avoid having to
  resolve the relocatable constant.

Original change's description:
> [wasm-gc] Implement call_ref on WasmJSFunction
>
> Changes:
> - Introduce turbofan builtin WasmAllocatePair.
> - Implement call_ref for WasmJSFunction in wasm-compiler.cc.
> - Remove WasmJSFunction trap.
> - Improve and extend call-ref.js test.
>
> Bug: v8:9495
> Change-Id: I8b4d1ab70cbbe9ae37887a6241d409eec638fd28
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2463226
> Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
> Reviewed-by: Clemens Backes <clemensb@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#70535}

Bug: v8:9495
Cq-Include-Trybots: luci.v8.try:v8_mac64_gc_stress_dbg_ng
Cq-Include-Trybots: luci.v8.try:v8_linux_gc_stress_dbg_ng
Change-Id: I294947059e612d417d92614a43cb7383cd5f3b92
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2476314
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70719}
parent e02a625a
...@@ -335,7 +335,6 @@ extern enum MessageTemplate { ...@@ -335,7 +335,6 @@ extern enum MessageTemplate {
kWasmTrapNullDereference, kWasmTrapNullDereference,
kWasmTrapIllegalCast, kWasmTrapIllegalCast,
kWasmTrapArrayOutOfBounds, kWasmTrapArrayOutOfBounds,
kWasmTrapWasmJSFunction,
kWeakRefsRegisterTargetAndHoldingsMustNotBeSame, kWeakRefsRegisterTargetAndHoldingsMustNotBeSame,
kWeakRefsRegisterTargetMustBeObject, kWeakRefsRegisterTargetMustBeObject,
kWeakRefsUnregisterTokenMustBeObject, kWeakRefsUnregisterTokenMustBeObject,
......
...@@ -815,6 +815,7 @@ namespace internal { ...@@ -815,6 +815,7 @@ namespace internal {
TFS(WasmAllocateArrayWithRtt, kMap, kLength, kElementSize) \ TFS(WasmAllocateArrayWithRtt, kMap, kLength, kElementSize) \
TFC(WasmI32AtomicWait32, WasmI32AtomicWait32) \ TFC(WasmI32AtomicWait32, WasmI32AtomicWait32) \
TFC(WasmI64AtomicWait32, WasmI64AtomicWait32) \ TFC(WasmI64AtomicWait32, WasmI64AtomicWait32) \
TFS(WasmAllocatePair, kValue1, kValue2) \
\ \
/* WeakMap */ \ /* WeakMap */ \
TFJ(WeakMapConstructor, kDontAdaptArgumentsSentinel) \ TFJ(WeakMapConstructor, kDontAdaptArgumentsSentinel) \
......
...@@ -127,5 +127,27 @@ TF_BUILTIN(WasmAllocateArrayWithRtt, WasmBuiltinsAssembler) { ...@@ -127,5 +127,27 @@ TF_BUILTIN(WasmAllocateArrayWithRtt, WasmBuiltinsAssembler) {
Return(result); Return(result);
} }
TF_BUILTIN(WasmAllocatePair, WasmBuiltinsAssembler) {
TNode<WasmInstanceObject> instance = LoadInstanceFromFrame();
TNode<HeapObject> value1 = Parameter<HeapObject>(Descriptor::kValue1);
TNode<HeapObject> value2 = Parameter<HeapObject>(Descriptor::kValue2);
TNode<IntPtrT> roots = LoadObjectField<IntPtrT>(
instance, WasmInstanceObject::kIsolateRootOffset);
TNode<Map> map = CAST(Load(
MachineType::AnyTagged(), roots,
IntPtrConstant(IsolateData::root_slot_offset(RootIndex::kTuple2Map))));
TNode<IntPtrT> instance_size =
TimesTaggedSize(LoadMapInstanceSizeInWords(map));
TNode<Tuple2> result = UncheckedCast<Tuple2>(Allocate(instance_size));
StoreMap(result, map);
StoreObjectField(result, Tuple2::kValue1Offset, value1);
StoreObjectField(result, Tuple2::kValue2Offset, value2);
Return(result);
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -427,8 +427,4 @@ builtin ThrowWasmTrapIllegalCast(): JSAny { ...@@ -427,8 +427,4 @@ builtin ThrowWasmTrapIllegalCast(): JSAny {
builtin ThrowWasmTrapArrayOutOfBounds(): JSAny { builtin ThrowWasmTrapArrayOutOfBounds(): JSAny {
tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapArrayOutOfBounds)); tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapArrayOutOfBounds));
} }
builtin ThrowWasmTrapWasmJSFunction(): JSAny {
tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapWasmJSFunction));
}
} }
...@@ -1606,7 +1606,6 @@ enum class LoadSensitivity { ...@@ -1606,7 +1606,6 @@ enum class LoadSensitivity {
V(TrapRethrowNull) \ V(TrapRethrowNull) \
V(TrapNullDereference) \ V(TrapNullDereference) \
V(TrapIllegalCast) \ V(TrapIllegalCast) \
V(TrapWasmJSFunction) \
V(TrapArrayOutOfBounds) V(TrapArrayOutOfBounds)
enum KeyedAccessLoadMode { enum KeyedAccessLoadMode {
......
...@@ -569,7 +569,6 @@ namespace internal { ...@@ -569,7 +569,6 @@ namespace internal {
T(WasmTrapNullDereference, "dereferencing a null pointer") \ T(WasmTrapNullDereference, "dereferencing a null pointer") \
T(WasmTrapIllegalCast, "illegal cast") \ T(WasmTrapIllegalCast, "illegal cast") \
T(WasmTrapArrayOutOfBounds, "array element access out of bounds") \ T(WasmTrapArrayOutOfBounds, "array element access out of bounds") \
T(WasmTrapWasmJSFunction, "cannot call WebAssembly.Function with call_ref") \
T(WasmExceptionError, "wasm exception") \ T(WasmExceptionError, "wasm exception") \
/* Asm.js validation related */ \ /* Asm.js validation related */ \
T(AsmJsInvalid, "Invalid asm.js: %") \ T(AsmJsInvalid, "Invalid asm.js: %") \
......
...@@ -3077,13 +3077,30 @@ Node* WasmGraphBuilder::BuildCallRef(uint32_t sig_index, Vector<Node*> args, ...@@ -3077,13 +3077,30 @@ Node* WasmGraphBuilder::BuildCallRef(uint32_t sig_index, Vector<Node*> args,
} }
{ {
// Call to a WasmJSFunction. // Call to a WasmJSFunction. The call target is
// The call target is the wasm-to-js wrapper code. // function_data->wasm_to_js_wrapper_code()->instruction_start().
// The instance_node is the pair
// (current WasmInstanceObject, function_data->callable()).
gasm_->Bind(&js_label); gasm_->Bind(&js_label);
// TODO(9495): Implement when the interaction with the type reflection
// proposal is clear. Node* wrapper_code =
TrapIfTrue(wasm::kTrapWasmJSFunction, gasm_->Int32Constant(1), position); gasm_->Load(MachineType::TaggedPointer(), function_data,
gasm_->Goto(&end_label, args[0], RefNull() /* Dummy value */); wasm::ObjectAccess::ToTagged(
WasmJSFunctionData::kWasmToJsWrapperCodeOffset));
Node* call_target = gasm_->IntAdd(
wrapper_code,
gasm_->IntPtrConstant(wasm::ObjectAccess::ToTagged(Code::kHeaderSize)));
Node* callable = gasm_->Load(
MachineType::TaggedPointer(), function_data,
wasm::ObjectAccess::ToTagged(WasmJSFunctionData::kCallableOffset));
// TODO(manoskouk): Find an elegant way to avoid allocating this pair for
// every call.
Node* function_instance_node = CALL_BUILTIN(
WasmAllocatePair, instance_node_.get(), callable,
LOAD_INSTANCE_FIELD(NativeContext, MachineType::TaggedPointer()));
gasm_->Goto(&end_label, call_target, function_instance_node);
} }
gasm_->Bind(&end_label); gasm_->Bind(&end_label);
...@@ -6766,9 +6783,8 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder { ...@@ -6766,9 +6783,8 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
Node* function_context = Node* function_context =
gasm_->Load(MachineType::TaggedPointer(), callable_node, gasm_->Load(MachineType::TaggedPointer(), callable_node,
wasm::ObjectAccess::ContextOffsetInTaggedJSFunction()); wasm::ObjectAccess::ContextOffsetInTaggedJSFunction());
args[pos++] = mcgraph()->RelocatableIntPtrConstant( args[pos++] =
wasm::WasmCode::kArgumentsAdaptorTrampoline, GetBuiltinPointerTarget(Builtins::kArgumentsAdaptorTrampoline);
RelocInfo::WASM_STUB_CALL);
args[pos++] = callable_node; // target callable args[pos++] = callable_node; // target callable
args[pos++] = undefined_node; // new target args[pos++] = undefined_node; // new target
args[pos++] = mcgraph()->Int32Constant(wasm_count); // argument count args[pos++] = mcgraph()->Int32Constant(wasm_count); // argument count
...@@ -6793,7 +6809,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder { ...@@ -6793,7 +6809,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
auto call_descriptor = Linkage::GetStubCallDescriptor( auto call_descriptor = Linkage::GetStubCallDescriptor(
mcgraph()->zone(), ArgumentsAdaptorDescriptor{}, 1 + wasm_count, mcgraph()->zone(), ArgumentsAdaptorDescriptor{}, 1 + wasm_count,
CallDescriptor::kNoFlags, Operator::kNoProperties, CallDescriptor::kNoFlags, Operator::kNoProperties,
StubCallMode::kCallWasmRuntimeStub); StubCallMode::kCallBuiltinPointer);
// Convert wasm numbers to JS values. // Convert wasm numbers to JS values.
pos = AddArgumentNodes(VectorOf(args), pos, wasm_count, sig_); pos = AddArgumentNodes(VectorOf(args), pos, wasm_count, sig_);
......
...@@ -606,9 +606,10 @@ StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator, ...@@ -606,9 +606,10 @@ StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator,
return STUB; return STUB;
case CodeKind::C_WASM_ENTRY: case CodeKind::C_WASM_ENTRY:
return C_WASM_ENTRY; return C_WASM_ENTRY;
case CodeKind::WASM_TO_JS_FUNCTION:
return WASM_TO_JS;
case CodeKind::WASM_FUNCTION: case CodeKind::WASM_FUNCTION:
case CodeKind::WASM_TO_CAPI_FUNCTION: case CodeKind::WASM_TO_CAPI_FUNCTION:
case CodeKind::WASM_TO_JS_FUNCTION:
// Never appear as on-heap {Code} objects. // Never appear as on-heap {Code} objects.
UNREACHABLE(); UNREACHABLE();
default: default:
......
...@@ -57,6 +57,7 @@ struct WasmModule; ...@@ -57,6 +57,7 @@ struct WasmModule;
V(WasmFloat64ToNumber) \ V(WasmFloat64ToNumber) \
V(WasmTaggedToFloat64) \ V(WasmTaggedToFloat64) \
V(WasmAllocateJSArray) \ V(WasmAllocateJSArray) \
V(WasmAllocatePair) \
V(WasmAtomicNotify) \ V(WasmAtomicNotify) \
V(WasmI32AtomicWait32) \ V(WasmI32AtomicWait32) \
V(WasmI32AtomicWait64) \ V(WasmI32AtomicWait64) \
......
...@@ -22,8 +22,8 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -22,8 +22,8 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
var sig_index = builder.addType(kSig_i_ii); var sig_index = builder.addType(kSig_i_ii);
var imported_type_reflection_function_index = var imported_js_api_function_index =
builder.addImport("imports", "mul", sig_index); builder.addImport("imports", "js_api_mul", sig_index);
var imported_js_function_index = var imported_js_function_index =
builder.addImport("imports", "js_add", sig_index); builder.addImport("imports", "js_add", sig_index);
...@@ -31,10 +31,6 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -31,10 +31,6 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
var imported_wasm_function_index = var imported_wasm_function_index =
builder.addImport("imports", "wasm_add", sig_index); builder.addImport("imports", "wasm_add", sig_index);
builder.addExport("unused", imported_wasm_function_index);
builder.addExport("reexported_js_function", imported_js_function_index);
builder.addExport("reexported_webassembly_function",
imported_type_reflection_function_index);
var locally_defined_function = var locally_defined_function =
builder.addFunction("sub", sig_index) builder.addFunction("sub", sig_index)
...@@ -62,29 +58,30 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -62,29 +58,30 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
kExprRefFunc, imported_wasm_function_index, kExprCallRef]) kExprRefFunc, imported_wasm_function_index, kExprCallRef])
.exportFunc(); .exportFunc();
/* Future use builder.addFunction("test_js_api_import", kSig_i_v)
builder.addFunction("test_webassembly_import", kSig_i_v)
.addBody([kExprI32Const, 3, kExprI32Const, 7, .addBody([kExprI32Const, 3, kExprI32Const, 7,
kExprRefFunc, imported_type_reflection_function_index, kExprRefFunc, imported_js_api_function_index,
kExprCallRef]) kExprCallRef])
.exportFunc(); .exportFunc();
*/
builder.addExport("reexported_js_function", imported_js_function_index);
// Just to make these functions eligible for call_ref.
builder.addDeclarativeElementSegment([imported_wasm_function_index,
imported_js_api_function_index]);
return builder.instantiate({imports: { return builder.instantiate({imports: {
js_add: function(a, b) { return a + b; }, js_add: function(a, b) { return a + b; },
wasm_add: exporting_instance.exports.addition, wasm_add: exporting_instance.exports.addition,
mul: new WebAssembly.Function({parameters:['i32', 'i32'], js_api_mul: new WebAssembly.Function(
results: ['i32']}, {parameters:['i32', 'i32'], results: ['i32']},
function(a, b) { return a * b; }) function(a, b) { return a * b; })
}}); }});
})(); })();
// Check the modules exist. // Check that the modules exist.
assertFalse(instance === undefined); assertTrue(!!exporting_instance);
assertFalse(instance === null); assertTrue(!!instance);
assertFalse(instance === 0);
assertEquals("object", typeof instance.exports);
assertEquals("function", typeof instance.exports.main);
print("--locally defined func--"); print("--locally defined func--");
assertEquals(13, instance.exports.test_local()); assertEquals(13, instance.exports.test_local());
...@@ -103,9 +100,18 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -103,9 +100,18 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
assertEquals(19, instance.exports.main( assertEquals(19, instance.exports.main(
exporting_instance.exports.addition, 12, 7)); exporting_instance.exports.addition, 12, 7));
// TODO(7748): Make these work once we know how we interact print("--imported WebAssembly.Function--")
// with the 'type reflection' proposal. assertEquals(21, instance.exports.test_js_api_import());
//print("--imported WebAssembly.Function--") print("--not imported WebAssembly.Function--")
//assertEquals(21, instance.exports.test_webassembly_import()); assertEquals(-5, instance.exports.main(
//print(" --not imported WebAssembly.Function--") new WebAssembly.Function(
{parameters:['i32', 'i32'], results: ['i32']},
function(a, b) { return a - b; }),
10, 15));
print("--not imported WebAssembly.Function, arity mismatch--")
assertEquals(100, instance.exports.main(
new WebAssembly.Function(
{parameters:['i32', 'i32'], results: ['i32']},
function(a) { return a * a; }),
10, 15));
})(); })();
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