Commit da3c7318 authored by Manos Koukoutos's avatar Manos Koukoutos Committed by Commit Bot

[wasm-gc] Cleanup/preparation to enable call_ref with WasmJSFunction

Changes:
- Add wasm-to-js wrapper field to WasmJSFunction. A WasmJSFunction might
  be called with call_ref without being imported to a module, and this
  provides a call target for this scenario. The wrapper is only compiled
  if --experimental-wasm-typed-funcref is set.
- Add CompileWasmToJSWrapper in wasm-compiler.
- Rename  BuildLoadFunctionDataFromExportedFunction ->
  BuildLoadFunctionDataFromJSFunction to reflect its wider usage.
- Rename BuildWasmImportCallWrapper -> BuildWasmToJsWrapper to reflect
  this function is now also used by CompileWasmToJSWrapper (unrelated to
  imports).
- (Drive-by) Remove dead arguments from wasm-module-builder.js.

Bug: v8:9495
Change-Id: I23468b69d42310cb8e96da5286ce68c701188876
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2459371Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70421}
parent 3935dc49
......@@ -2952,10 +2952,9 @@ Node* WasmGraphBuilder::BuildIndirectCall(uint32_t table_index,
}
}
Node* WasmGraphBuilder::BuildLoadFunctionDataFromExportedFunction(
Node* closure) {
Node* WasmGraphBuilder::BuildLoadFunctionDataFromJSFunction(Node* js_function) {
Node* shared = gasm_->Load(
MachineType::AnyTagged(), closure,
MachineType::AnyTagged(), js_function,
wasm::ObjectAccess::SharedFunctionInfoOffsetInTaggedJSFunction());
return gasm_->Load(MachineType::AnyTagged(), shared,
SharedFunctionInfo::kFunctionDataOffset - kHeapObjectTag);
......@@ -3000,7 +2999,7 @@ Node* WasmGraphBuilder::BuildCallRef(uint32_t sig_index, Vector<Node*> args,
const wasm::FunctionSig* sig = env_->module->signature(sig_index);
Node* function_data = BuildLoadFunctionDataFromExportedFunction(args[0]);
Node* function_data = BuildLoadFunctionDataFromJSFunction(args[0]);
Node* is_js_function =
HasInstanceType(gasm_.get(), function_data, WASM_JS_FUNCTION_DATA_TYPE);
......@@ -6502,7 +6501,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
// an actual reference to an instance or a placeholder reference,
// called {WasmExportedFunction} via the {WasmExportedFunctionData}
// structure.
Node* function_data = BuildLoadFunctionDataFromExportedFunction(js_closure);
Node* function_data = BuildLoadFunctionDataFromJSFunction(js_closure);
instance_node_.set(
BuildLoadInstanceFromExportedFunctionData(function_data));
......@@ -6598,7 +6597,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
global_proxy);
}
bool BuildWasmImportCallWrapper(WasmImportCallKind kind, int expected_arity) {
bool BuildWasmToJSWrapper(WasmImportCallKind kind, int expected_arity) {
int wasm_count = static_cast<int>(sig_->parameter_count());
// Build the start and the parameter nodes.
......@@ -7459,7 +7458,7 @@ wasm::WasmCompilationResult CompileWasmImportCallWrapper(
WasmWrapperGraphBuilder builder(
&zone, mcgraph, sig, env->module, source_position_table,
StubCallMode::kCallWasmRuntimeStub, env->enabled_features);
builder.BuildWasmImportCallWrapper(kind, expected_arity);
builder.BuildWasmToJSWrapper(kind, expected_arity);
// Build a name in the form "wasm-to-js-<kind>-<signature>".
constexpr size_t kMaxNameLen = 128;
......@@ -7536,6 +7535,57 @@ wasm::WasmCode* CompileWasmCapiCallWrapper(wasm::WasmEngine* wasm_engine,
return native_module->PublishCode(std::move(wasm_code));
}
MaybeHandle<Code> CompileWasmToJSWrapper(Isolate* isolate,
const wasm::FunctionSig* sig,
WasmImportCallKind kind,
int expected_arity) {
std::unique_ptr<Zone> zone = std::make_unique<Zone>(
isolate->allocator(), ZONE_NAME, kCompressGraphZone);
// Create the Graph
Graph* graph = zone->New<Graph>(zone.get());
CommonOperatorBuilder* common = zone->New<CommonOperatorBuilder>(zone.get());
MachineOperatorBuilder* machine = zone->New<MachineOperatorBuilder>(
zone.get(), MachineType::PointerRepresentation(),
InstructionSelector::SupportedMachineOperatorFlags(),
InstructionSelector::AlignmentRequirements());
MachineGraph* mcgraph = zone->New<MachineGraph>(graph, common, machine);
WasmWrapperGraphBuilder builder(zone.get(), mcgraph, sig, nullptr, nullptr,
StubCallMode::kCallWasmRuntimeStub,
wasm::WasmFeatures::FromIsolate(isolate));
builder.BuildWasmToJSWrapper(kind, expected_arity);
// Build a name in the form "wasm-to-js-<kind>-<signature>".
constexpr size_t kMaxNameLen = 128;
constexpr size_t kNamePrefixLen = 11;
auto name_buffer = std::unique_ptr<char[]>(new char[kMaxNameLen]);
memcpy(name_buffer.get(), "wasm-to-js:", kNamePrefixLen);
PrintSignature(VectorOf(name_buffer.get(), kMaxNameLen) + kNamePrefixLen,
sig);
// Generate the call descriptor.
CallDescriptor* incoming =
GetWasmCallDescriptor(zone.get(), sig, WasmGraphBuilder::kNoRetpoline,
WasmCallKind::kWasmImportWrapper);
// Run the compilation job synchronously.
std::unique_ptr<OptimizedCompilationJob> job(
Pipeline::NewWasmHeapStubCompilationJob(
isolate, isolate->wasm_engine(), incoming, std::move(zone), graph,
CodeKind::WASM_TO_JS_FUNCTION, std::move(name_buffer),
AssemblerOptions::Default(isolate)));
// Compile the wrapper
if (job->ExecuteJob(isolate->counters()->runtime_call_stats()) ==
CompilationJob::FAILED ||
job->FinalizeJob(isolate) == CompilationJob::FAILED) {
return Handle<Code>();
}
Handle<Code> code = job->compilation_info()->code();
return code;
}
MaybeHandle<Code> CompileJSToJSWrapper(Isolate* isolate,
const wasm::FunctionSig* sig,
const wasm::WasmModule* module) {
......
......@@ -126,6 +126,11 @@ std::unique_ptr<OptimizedCompilationJob> NewJSToWasmCompilationJob(
const wasm::FunctionSig* sig, const wasm::WasmModule* module,
bool is_import, const wasm::WasmFeatures& enabled_features);
MaybeHandle<Code> CompileWasmToJSWrapper(Isolate* isolate,
const wasm::FunctionSig* sig,
WasmImportCallKind kind,
int expected_arity);
// Compiles a stub with JS linkage that serves as an adapter for function
// objects constructed via {WebAssembly.Function}. It performs a round-trip
// simulating a JS-to-Wasm-to-JS coercion of parameter and return values.
......@@ -613,7 +618,7 @@ class WasmGraphBuilder {
Node* BuildMultiReturnFixedArrayFromIterable(const wasm::FunctionSig* sig,
Node* iterable, Node* context);
Node* BuildLoadFunctionDataFromExportedFunction(Node* closure);
Node* BuildLoadFunctionDataFromJSFunction(Node* closure);
Node* BuildLoadJumpTableOffsetFromExportedFunctionData(Node* function_data);
Node* BuildLoadFunctionIndexFromExportedFunctionData(Node* function_data);
......
......@@ -1480,6 +1480,8 @@ void InstanceBuilder::CompileImportWrappers(
// Also compile in the current thread, in case there are no worker threads.
while (base::Optional<WasmImportWrapperCache::CacheKey> key =
import_wrapper_queue.pop()) {
// TODO(9495): When typed_funcref is enabled, reuse the already compiled
// wrappers inside WasmJSFunctions.
CompileImportWrapper(isolate_->wasm_engine(), native_module,
isolate_->counters(), key->kind, key->signature,
key->expected_arity, &cache_scope);
......
......@@ -353,6 +353,8 @@ ACCESSORS(WasmJSFunctionData, serialized_signature, PodArray<wasm::ValueType>,
kSerializedSignatureOffset)
ACCESSORS(WasmJSFunctionData, callable, JSReceiver, kCallableOffset)
ACCESSORS(WasmJSFunctionData, wrapper_code, Code, kWrapperCodeOffset)
ACCESSORS(WasmJSFunctionData, wasm_to_js_wrapper_code, Code,
kWasmToJsWrapperCodeOffset)
// WasmCapiFunction
WasmCapiFunction::WasmCapiFunction(Address ptr) : JSFunction(ptr) {
......
......@@ -1975,8 +1975,6 @@ bool WasmJSFunction::IsWasmJSFunction(Object object) {
return js_function.shared().HasWasmJSFunctionData();
}
// TODO(7748): WasmJSFunctions should compile/find and store an import wrapper
// in case they are called from within wasm.
Handle<WasmJSFunction> WasmJSFunction::New(Isolate* isolate,
const wasm::FunctionSig* sig,
Handle<JSReceiver> callable) {
......@@ -1993,6 +1991,7 @@ Handle<WasmJSFunction> WasmJSFunction::New(Isolate* isolate,
// signature instead of compiling a new one for every instantiation.
Handle<Code> wrapper_code =
compiler::CompileJSToJSWrapper(isolate, sig, nullptr).ToHandleChecked();
Handle<WasmJSFunctionData> function_data =
Handle<WasmJSFunctionData>::cast(isolate->factory()->NewStruct(
WASM_JS_FUNCTION_DATA_TYPE, AllocationType::kOld));
......@@ -2001,6 +2000,36 @@ Handle<WasmJSFunction> WasmJSFunction::New(Isolate* isolate,
function_data->set_serialized_signature(*serialized_sig);
function_data->set_callable(*callable);
function_data->set_wrapper_code(*wrapper_code);
if (wasm::WasmFeatures::FromIsolate(isolate).has_typed_funcref()) {
using CK = compiler::WasmImportCallKind;
int expected_arity = parameter_count;
CK kind = compiler::kDefaultImportCallKind;
if (callable->IsJSFunction()) {
SharedFunctionInfo shared = Handle<JSFunction>::cast(callable)->shared();
expected_arity = shared.internal_formal_parameter_count();
if (expected_arity != parameter_count) {
#ifdef V8_REVERSE_JSARGS
kind = CK::kJSFunctionArityMismatch;
#else
kind = shared.is_safe_to_skip_arguments_adaptor()
? CK::kJSFunctionArityMismatchSkipAdaptor
: CK::kJSFunctionArityMismatch;
#endif
}
}
// TODO(wasm): Think about caching and sharing the wasm-to-JS wrappers per
// signature instead of compiling a new one for every instantiation.
Handle<Code> wasm_to_js_wrapper_code =
compiler::CompileWasmToJSWrapper(isolate, sig, kind, expected_arity)
.ToHandleChecked();
function_data->set_wasm_to_js_wrapper_code(*wasm_to_js_wrapper_code);
} else {
// Use Abort() as a default value (it will never be called).
function_data->set_wasm_to_js_wrapper_code(
isolate->heap()->builtin(Builtins::kAbort));
}
Handle<String> name = isolate->factory()->Function_string();
if (callable->IsJSFunction()) {
name = JSFunction::GetName(Handle<JSFunction>::cast(callable));
......
......@@ -813,6 +813,7 @@ class WasmJSFunctionData : public Struct {
DECL_ACCESSORS(serialized_signature, PodArray<wasm::ValueType>)
DECL_ACCESSORS(callable, JSReceiver)
DECL_ACCESSORS(wrapper_code, Code)
DECL_ACCESSORS(wasm_to_js_wrapper_code, Code)
DECL_CAST(WasmJSFunctionData)
......
......@@ -27,6 +27,7 @@ extern class WasmExportedFunctionData extends Struct {
extern class WasmJSFunctionData extends Struct {
callable: JSReceiver;
wrapper_code: Code;
wasm_to_js_wrapper_code: Code;
serialized_return_count: Smi;
serialized_parameter_count: Smi;
serialized_signature: PodArrayOfWasmValueType;
......
......@@ -1130,13 +1130,13 @@ class WasmModuleBuilder {
return this;
}
addPassiveElementSegment(array, is_import = false) {
addPassiveElementSegment(array) {
this.element_segments.push(
{array: array, is_active: false, is_declarative: false});
return this;
}
addDeclarativeElementSegment(array, is_import = false) {
addDeclarativeElementSegment(array) {
this.element_segments.push(
{array: array, is_active: false, is_declarative: true});
return this;
......
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