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 {
kWasmTrapNullDereference,
kWasmTrapIllegalCast,
kWasmTrapArrayOutOfBounds,
kWasmTrapWasmJSFunction,
kWeakRefsRegisterTargetAndHoldingsMustNotBeSame,
kWeakRefsRegisterTargetMustBeObject,
kWeakRefsUnregisterTokenMustBeObject,
......
......@@ -815,6 +815,7 @@ namespace internal {
TFS(WasmAllocateArrayWithRtt, kMap, kLength, kElementSize) \
TFC(WasmI32AtomicWait32, WasmI32AtomicWait32) \
TFC(WasmI64AtomicWait32, WasmI64AtomicWait32) \
TFS(WasmAllocatePair, kValue1, kValue2) \
\
/* WeakMap */ \
TFJ(WeakMapConstructor, kDontAdaptArgumentsSentinel) \
......
......@@ -127,5 +127,27 @@ TF_BUILTIN(WasmAllocateArrayWithRtt, WasmBuiltinsAssembler) {
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 v8
......@@ -427,8 +427,4 @@ builtin ThrowWasmTrapIllegalCast(): JSAny {
builtin ThrowWasmTrapArrayOutOfBounds(): JSAny {
tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapArrayOutOfBounds));
}
builtin ThrowWasmTrapWasmJSFunction(): JSAny {
tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapWasmJSFunction));
}
}
......@@ -1606,7 +1606,6 @@ enum class LoadSensitivity {
V(TrapRethrowNull) \
V(TrapNullDereference) \
V(TrapIllegalCast) \
V(TrapWasmJSFunction) \
V(TrapArrayOutOfBounds)
enum KeyedAccessLoadMode {
......
......@@ -569,7 +569,6 @@ namespace internal {
T(WasmTrapNullDereference, "dereferencing a null pointer") \
T(WasmTrapIllegalCast, "illegal cast") \
T(WasmTrapArrayOutOfBounds, "array element access out of bounds") \
T(WasmTrapWasmJSFunction, "cannot call WebAssembly.Function with call_ref") \
T(WasmExceptionError, "wasm exception") \
/* Asm.js validation related */ \
T(AsmJsInvalid, "Invalid asm.js: %") \
......
......@@ -3077,13 +3077,30 @@ Node* WasmGraphBuilder::BuildCallRef(uint32_t sig_index, Vector<Node*> args,
}
{
// Call to a WasmJSFunction.
// The call target is the wasm-to-js wrapper code.
// Call to a WasmJSFunction. The call target is
// function_data->wasm_to_js_wrapper_code()->instruction_start().
// The instance_node is the pair
// (current WasmInstanceObject, function_data->callable()).
gasm_->Bind(&js_label);
// TODO(9495): Implement when the interaction with the type reflection
// proposal is clear.
TrapIfTrue(wasm::kTrapWasmJSFunction, gasm_->Int32Constant(1), position);
gasm_->Goto(&end_label, args[0], RefNull() /* Dummy value */);
Node* wrapper_code =
gasm_->Load(MachineType::TaggedPointer(), function_data,
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);
......@@ -6766,9 +6783,8 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
Node* function_context =
gasm_->Load(MachineType::TaggedPointer(), callable_node,
wasm::ObjectAccess::ContextOffsetInTaggedJSFunction());
args[pos++] = mcgraph()->RelocatableIntPtrConstant(
wasm::WasmCode::kArgumentsAdaptorTrampoline,
RelocInfo::WASM_STUB_CALL);
args[pos++] =
GetBuiltinPointerTarget(Builtins::kArgumentsAdaptorTrampoline);
args[pos++] = callable_node; // target callable
args[pos++] = undefined_node; // new target
args[pos++] = mcgraph()->Int32Constant(wasm_count); // argument count
......@@ -6793,7 +6809,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
auto call_descriptor = Linkage::GetStubCallDescriptor(
mcgraph()->zone(), ArgumentsAdaptorDescriptor{}, 1 + wasm_count,
CallDescriptor::kNoFlags, Operator::kNoProperties,
StubCallMode::kCallWasmRuntimeStub);
StubCallMode::kCallBuiltinPointer);
// Convert wasm numbers to JS values.
pos = AddArgumentNodes(VectorOf(args), pos, wasm_count, sig_);
......
......@@ -606,9 +606,10 @@ StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator,
return STUB;
case CodeKind::C_WASM_ENTRY:
return C_WASM_ENTRY;
case CodeKind::WASM_TO_JS_FUNCTION:
return WASM_TO_JS;
case CodeKind::WASM_FUNCTION:
case CodeKind::WASM_TO_CAPI_FUNCTION:
case CodeKind::WASM_TO_JS_FUNCTION:
// Never appear as on-heap {Code} objects.
UNREACHABLE();
default:
......
......@@ -57,6 +57,7 @@ struct WasmModule;
V(WasmFloat64ToNumber) \
V(WasmTaggedToFloat64) \
V(WasmAllocateJSArray) \
V(WasmAllocatePair) \
V(WasmAtomicNotify) \
V(WasmI32AtomicWait32) \
V(WasmI32AtomicWait64) \
......
......@@ -22,8 +22,8 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
var sig_index = builder.addType(kSig_i_ii);
var imported_type_reflection_function_index =
builder.addImport("imports", "mul", sig_index);
var imported_js_api_function_index =
builder.addImport("imports", "js_api_mul", sig_index);
var imported_js_function_index =
builder.addImport("imports", "js_add", sig_index);
......@@ -31,10 +31,6 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
var imported_wasm_function_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 =
builder.addFunction("sub", sig_index)
......@@ -57,34 +53,35 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
kExprRefFunc, imported_js_function_index, kExprCallRef])
.exportFunc();
builder.addFunction("test_wasm_import", kSig_i_v)
.addBody([kExprI32Const, 15, kExprI32Const, 42,
kExprRefFunc, imported_wasm_function_index, kExprCallRef])
.exportFunc();
builder.addFunction("test_wasm_import", kSig_i_v)
.addBody([kExprI32Const, 15, kExprI32Const, 42,
kExprRefFunc, imported_wasm_function_index, kExprCallRef])
.exportFunc();
/* Future use
builder.addFunction("test_webassembly_import", kSig_i_v)
builder.addFunction("test_js_api_import", kSig_i_v)
.addBody([kExprI32Const, 3, kExprI32Const, 7,
kExprRefFunc, imported_type_reflection_function_index,
kExprRefFunc, imported_js_api_function_index,
kExprCallRef])
.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: {
js_add: function(a, b) { return a + b; },
wasm_add: exporting_instance.exports.addition,
mul: new WebAssembly.Function({parameters:['i32', 'i32'],
results: ['i32']},
function(a, b) { return a * b; })
js_api_mul: new WebAssembly.Function(
{parameters:['i32', 'i32'], results: ['i32']},
function(a, b) { return a * b; })
}});
})();
// Check the modules exist.
assertFalse(instance === undefined);
assertFalse(instance === null);
assertFalse(instance === 0);
assertEquals("object", typeof instance.exports);
assertEquals("function", typeof instance.exports.main);
// Check that the modules exist.
assertTrue(!!exporting_instance);
assertTrue(!!instance);
print("--locally defined func--");
assertEquals(13, instance.exports.test_local());
......@@ -103,9 +100,18 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
assertEquals(19, instance.exports.main(
exporting_instance.exports.addition, 12, 7));
// TODO(7748): Make these work once we know how we interact
// with the 'type reflection' proposal.
//print("--imported WebAssembly.Function--")
//assertEquals(21, instance.exports.test_webassembly_import());
//print(" --not imported WebAssembly.Function--")
print("--imported WebAssembly.Function--")
assertEquals(21, instance.exports.test_js_api_import());
print("--not imported WebAssembly.Function--")
assertEquals(-5, instance.exports.main(
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