Commit 1250fd59 authored by evih's avatar evih Committed by Commit Bot

[wasm] Add a generic js-to-wasm wrapper

This generic wrapper builtin is currently used only when the wasm
function has no parameters and no return value.

Added a new V8 flag to use this generic wrapper.

Also added a JS test function for this generic wrapper.

Bug: v8:10701
Change-Id: Id8cd1771f26922927363b715d8a6ffd384a143ce
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2307240Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarThibaud Michaud <thibaudm@chromium.org>
Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Commit-Queue: Eva Herencsárová <evih@google.com>
Cr-Commit-Position: refs/heads/master@{#69097}
parent f97620b9
...@@ -3060,6 +3060,11 @@ void Builtins::Generate_DoubleToI(MacroAssembler* masm) { ...@@ -3060,6 +3060,11 @@ void Builtins::Generate_DoubleToI(MacroAssembler* masm) {
__ Ret(); __ Ret();
} }
void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
// TODO(v8:10701): Implement for this platform.
__ Trap();
}
namespace { namespace {
int AddressOffset(ExternalReference ref0, ExternalReference ref1) { int AddressOffset(ExternalReference ref0, ExternalReference ref1) {
......
...@@ -3728,6 +3728,11 @@ void Builtins::Generate_DoubleToI(MacroAssembler* masm) { ...@@ -3728,6 +3728,11 @@ void Builtins::Generate_DoubleToI(MacroAssembler* masm) {
__ Ret(); __ Ret();
} }
void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
// TODO(v8:10701): Implement for this platform.
__ Trap();
}
namespace { namespace {
// The number of register that CallApiFunctionAndReturn will need to save on // The number of register that CallApiFunctionAndReturn will need to save on
......
...@@ -815,6 +815,7 @@ namespace internal { ...@@ -815,6 +815,7 @@ namespace internal {
TFJ(TypedArrayPrototypeMap, kDontAdaptArgumentsSentinel) \ TFJ(TypedArrayPrototypeMap, kDontAdaptArgumentsSentinel) \
\ \
/* Wasm */ \ /* Wasm */ \
ASM(GenericJSToWasmWrapper, Dummy) \
ASM(WasmCompileLazy, Dummy) \ ASM(WasmCompileLazy, Dummy) \
ASM(WasmDebugBreak, Dummy) \ ASM(WasmDebugBreak, Dummy) \
TFC(WasmFloat32ToNumber, WasmFloat32ToNumber) \ TFC(WasmFloat32ToNumber, WasmFloat32ToNumber) \
......
...@@ -3291,6 +3291,11 @@ void Builtins::Generate_DoubleToI(MacroAssembler* masm) { ...@@ -3291,6 +3291,11 @@ void Builtins::Generate_DoubleToI(MacroAssembler* masm) {
__ ret(0); __ ret(0);
} }
void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
// TODO(v8:10701): Implement for this platform.
__ Trap();
}
namespace { namespace {
// Generates an Operand for saving parameters after PrepareCallApiFunction. // Generates an Operand for saving parameters after PrepareCallApiFunction.
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "src/objects/objects-inl.h" #include "src/objects/objects-inl.h"
#include "src/objects/smi.h" #include "src/objects/smi.h"
#include "src/wasm/baseline/liftoff-assembler-defs.h" #include "src/wasm/baseline/liftoff-assembler-defs.h"
#include "src/wasm/object-access.h"
#include "src/wasm/wasm-linkage.h" #include "src/wasm/wasm-linkage.h"
#include "src/wasm/wasm-objects.h" #include "src/wasm/wasm-objects.h"
...@@ -3198,6 +3199,97 @@ void Builtins::Generate_DoubleToI(MacroAssembler* masm) { ...@@ -3198,6 +3199,97 @@ void Builtins::Generate_DoubleToI(MacroAssembler* masm) {
__ ret(0); __ ret(0);
} }
void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
// Set up the stackframe.
__ EnterFrame(StackFrame::JS_TO_WASM);
Register closure = rdi;
Register shared_function_info = rbx;
__ LoadAnyTaggedField(
shared_function_info,
MemOperand(
closure,
wasm::ObjectAccess::SharedFunctionInfoOffsetInTaggedJSFunction()));
Register function_data = shared_function_info;
__ LoadAnyTaggedField(
function_data,
MemOperand(shared_function_info,
SharedFunctionInfo::kFunctionDataOffset - kHeapObjectTag));
shared_function_info = no_reg;
Register wasm_instance = rsi;
__ LoadAnyTaggedField(
wasm_instance,
MemOperand(function_data,
WasmExportedFunctionData::kInstanceOffset - kHeapObjectTag));
int isolate_root_offset =
wasm::ObjectAccess::ToTagged(WasmInstanceObject::kIsolateRootOffset);
// Set thread_in_wasm_flag.
Register isolate_root = rdx;
__ movq(isolate_root, MemOperand(wasm_instance, isolate_root_offset));
Register thread_in_wasm_flag_addr = isolate_root;
__ movq(
thread_in_wasm_flag_addr,
MemOperand(isolate_root, Isolate::thread_in_wasm_flag_address_offset()));
__ movl(MemOperand(thread_in_wasm_flag_addr, 0), Immediate(1));
isolate_root = no_reg;
Register jump_table_start = thread_in_wasm_flag_addr;
__ movq(jump_table_start,
MemOperand(wasm_instance,
wasm::ObjectAccess::ToTagged(
WasmInstanceObject::kJumpTableStartOffset)));
thread_in_wasm_flag_addr = no_reg;
Register jump_table_offset = function_data;
__ DecompressTaggedSigned(
jump_table_offset,
MemOperand(
function_data,
WasmExportedFunctionData::kJumpTableOffsetOffset - kHeapObjectTag));
function_data = no_reg;
// Change from smi to int64.
__ sarl(jump_table_offset, Immediate(1));
__ movsxlq(jump_table_offset, jump_table_offset);
Register function_entry = jump_table_offset;
__ addq(function_entry, jump_table_start);
jump_table_offset = no_reg;
jump_table_start = no_reg;
// Save wasm_instance on the stack.
__ pushq(wasm_instance);
__ call(function_entry);
function_entry = no_reg;
// Restore wasm_instance.
__ popq(wasm_instance);
// Unset thread_in_wasm_flag.
isolate_root = rdx;
__ movq(isolate_root, MemOperand(wasm_instance, isolate_root_offset));
thread_in_wasm_flag_addr = r8;
__ movq(
thread_in_wasm_flag_addr,
MemOperand(isolate_root, Isolate::thread_in_wasm_flag_address_offset()));
__ movl(MemOperand(thread_in_wasm_flag_addr, 0), Immediate(0));
Register return_reg = rax;
__ movq(return_reg,
MemOperand(isolate_root, IsolateData::root_slot_offset(
RootIndex::kUndefinedValue)));
// Deconstrunct the stack frame.
__ LeaveFrame(StackFrame::JS_TO_WASM);
__ ret(8);
}
namespace { namespace {
int Offset(ExternalReference ref0, ExternalReference ref1) { int Offset(ExternalReference ref0, ExternalReference ref1) {
......
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "src/objects/objects.h"
#include "src/codegen/assembler-inl.h" #include "src/codegen/assembler-inl.h"
#include "src/date/date.h" #include "src/date/date.h"
#include "src/diagnostics/disasm.h" #include "src/diagnostics/disasm.h"
...@@ -32,6 +30,7 @@ ...@@ -32,6 +30,7 @@
#include "src/objects/js-array-inl.h" #include "src/objects/js-array-inl.h"
#include "src/objects/layout-descriptor.h" #include "src/objects/layout-descriptor.h"
#include "src/objects/objects-inl.h" #include "src/objects/objects-inl.h"
#include "src/objects/objects.h"
#include "src/roots/roots.h" #include "src/roots/roots.h"
#ifdef V8_INTL_SUPPORT #ifdef V8_INTL_SUPPORT
#include "src/objects/js-break-iterator-inl.h" #include "src/objects/js-break-iterator-inl.h"
...@@ -1446,7 +1445,9 @@ void WasmExportedFunctionData::WasmExportedFunctionDataVerify( ...@@ -1446,7 +1445,9 @@ void WasmExportedFunctionData::WasmExportedFunctionDataVerify(
Isolate* isolate) { Isolate* isolate) {
TorqueGeneratedClassVerifiers::WasmExportedFunctionDataVerify(*this, isolate); TorqueGeneratedClassVerifiers::WasmExportedFunctionDataVerify(*this, isolate);
CHECK(wrapper_code().kind() == Code::JS_TO_WASM_FUNCTION || CHECK(wrapper_code().kind() == Code::JS_TO_WASM_FUNCTION ||
wrapper_code().kind() == Code::C_WASM_ENTRY); wrapper_code().kind() == Code::C_WASM_ENTRY ||
(wrapper_code().is_builtin() &&
wrapper_code().builtin_index() == Builtins::kGenericJSToWasmWrapper));
} }
USE_TORQUE_VERIFIER(WasmModuleObject) USE_TORQUE_VERIFIER(WasmModuleObject)
......
...@@ -701,6 +701,8 @@ DEFINE_BOOL(untrusted_code_mitigations, V8_DEFAULT_UNTRUSTED_CODE_MITIGATIONS, ...@@ -701,6 +701,8 @@ DEFINE_BOOL(untrusted_code_mitigations, V8_DEFAULT_UNTRUSTED_CODE_MITIGATIONS,
#undef V8_DEFAULT_UNTRUSTED_CODE_MITIGATIONS #undef V8_DEFAULT_UNTRUSTED_CODE_MITIGATIONS
// Flags for native WebAssembly. // Flags for native WebAssembly.
DEFINE_BOOL(wasm_generic_wrapper, false,
"use generic js-to-wasm wrapper instead of per-signature wrappers")
DEFINE_BOOL(expose_wasm, true, "expose wasm interface to JavaScript") DEFINE_BOOL(expose_wasm, true, "expose wasm interface to JavaScript")
DEFINE_BOOL(assume_asmjs_origin, false, DEFINE_BOOL(assume_asmjs_origin, false,
"force wasm decoder to assume input is internal asm-wasm format") "force wasm decoder to assume input is internal asm-wasm format")
......
...@@ -66,12 +66,13 @@ Context GetNativeContextFromWasmInstanceOnStackTop(Isolate* isolate) { ...@@ -66,12 +66,13 @@ Context GetNativeContextFromWasmInstanceOnStackTop(Isolate* isolate) {
class ClearThreadInWasmScope { class ClearThreadInWasmScope {
public: public:
ClearThreadInWasmScope() { ClearThreadInWasmScope() {
DCHECK_EQ(trap_handler::IsTrapHandlerEnabled(), DCHECK_IMPLIES(trap_handler::IsTrapHandlerEnabled(),
trap_handler::IsThreadInWasm()); trap_handler::IsThreadInWasm());
trap_handler::ClearThreadInWasm(); trap_handler::ClearThreadInWasm();
} }
~ClearThreadInWasmScope() { ~ClearThreadInWasmScope() {
DCHECK(!trap_handler::IsThreadInWasm()); DCHECK_IMPLIES(trap_handler::IsTrapHandlerEnabled(),
!trap_handler::IsThreadInWasm());
trap_handler::SetThreadInWasm(); trap_handler::SetThreadInWasm();
} }
}; };
......
...@@ -272,23 +272,40 @@ JSToWasmWrapperCompilationUnit::JSToWasmWrapperCompilationUnit( ...@@ -272,23 +272,40 @@ JSToWasmWrapperCompilationUnit::JSToWasmWrapperCompilationUnit(
bool is_import, const WasmFeatures& enabled_features) bool is_import, const WasmFeatures& enabled_features)
: is_import_(is_import), : is_import_(is_import),
sig_(sig), sig_(sig),
job_(compiler::NewJSToWasmCompilationJob(isolate, wasm_engine, sig, #if V8_TARGET_ARCH_X64
is_import, enabled_features)) {} use_generic_wrapper_(FLAG_wasm_generic_wrapper &&
sig->parameters().empty() && sig->returns().empty()),
#else
use_generic_wrapper_(false),
#endif
job_(use_generic_wrapper_
? nullptr
: compiler::NewJSToWasmCompilationJob(
isolate, wasm_engine, sig, is_import, enabled_features)) {
}
JSToWasmWrapperCompilationUnit::~JSToWasmWrapperCompilationUnit() = default; JSToWasmWrapperCompilationUnit::~JSToWasmWrapperCompilationUnit() = default;
void JSToWasmWrapperCompilationUnit::Execute() { void JSToWasmWrapperCompilationUnit::Execute() {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"), TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"),
"wasm.CompileJSToWasmWrapper"); "wasm.CompileJSToWasmWrapper");
CompilationJob::Status status = job_->ExecuteJob(nullptr); if (!use_generic_wrapper_) {
CHECK_EQ(status, CompilationJob::SUCCEEDED); CompilationJob::Status status = job_->ExecuteJob(nullptr);
CHECK_EQ(status, CompilationJob::SUCCEEDED);
}
} }
Handle<Code> JSToWasmWrapperCompilationUnit::Finalize(Isolate* isolate) { Handle<Code> JSToWasmWrapperCompilationUnit::Finalize(Isolate* isolate) {
CompilationJob::Status status = job_->FinalizeJob(isolate); Handle<Code> code;
CHECK_EQ(status, CompilationJob::SUCCEEDED); if (use_generic_wrapper_) {
Handle<Code> code = job_->compilation_info()->code(); code =
if (must_record_function_compilation(isolate)) { isolate->builtins()->builtin_handle(Builtins::kGenericJSToWasmWrapper);
} else {
CompilationJob::Status status = job_->FinalizeJob(isolate);
CHECK_EQ(status, CompilationJob::SUCCEEDED);
code = job_->compilation_info()->code();
}
if (!use_generic_wrapper_ && must_record_function_compilation(isolate)) {
RecordWasmHeapStubCompilation( RecordWasmHeapStubCompilation(
isolate, code, "%s", job_->compilation_info()->GetDebugName().get()); isolate, code, "%s", job_->compilation_info()->GetDebugName().get());
} }
......
...@@ -132,6 +132,7 @@ class V8_EXPORT_PRIVATE JSToWasmWrapperCompilationUnit final { ...@@ -132,6 +132,7 @@ class V8_EXPORT_PRIVATE JSToWasmWrapperCompilationUnit final {
private: private:
bool is_import_; bool is_import_;
const FunctionSig* sig_; const FunctionSig* sig_;
bool use_generic_wrapper_;
std::unique_ptr<OptimizedCompilationJob> job_; std::unique_ptr<OptimizedCompilationJob> job_;
}; };
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "src/wasm/wasm-objects.h" #include "src/wasm/wasm-objects.h"
#include "src/utils/utils.h"
#include "src/base/iterator.h" #include "src/base/iterator.h"
#include "src/codegen/assembler-inl.h" #include "src/codegen/assembler-inl.h"
...@@ -16,6 +15,7 @@ ...@@ -16,6 +15,7 @@
#include "src/objects/shared-function-info.h" #include "src/objects/shared-function-info.h"
#include "src/objects/struct-inl.h" #include "src/objects/struct-inl.h"
#include "src/trap-handler/trap-handler.h" #include "src/trap-handler/trap-handler.h"
#include "src/utils/utils.h"
#include "src/utils/vector.h" #include "src/utils/vector.h"
#include "src/wasm/jump-table-assembler.h" #include "src/wasm/jump-table-assembler.h"
#include "src/wasm/module-compiler.h" #include "src/wasm/module-compiler.h"
...@@ -1746,7 +1746,10 @@ uint32_t WasmExceptionPackage::GetEncodedSize( ...@@ -1746,7 +1746,10 @@ uint32_t WasmExceptionPackage::GetEncodedSize(
bool WasmExportedFunction::IsWasmExportedFunction(Object object) { bool WasmExportedFunction::IsWasmExportedFunction(Object object) {
if (!object.IsJSFunction()) return false; if (!object.IsJSFunction()) return false;
JSFunction js_function = JSFunction::cast(object); JSFunction js_function = JSFunction::cast(object);
if (Code::JS_TO_WASM_FUNCTION != js_function.code().kind()) return false; if (Code::JS_TO_WASM_FUNCTION != js_function.code().kind() &&
js_function.code().builtin_index() != Builtins::kGenericJSToWasmWrapper) {
return false;
}
DCHECK(js_function.shared().HasWasmExportedFunctionData()); DCHECK(js_function.shared().HasWasmExportedFunctionData());
return true; return true;
} }
...@@ -1795,7 +1798,10 @@ int WasmExportedFunction::function_index() { ...@@ -1795,7 +1798,10 @@ int WasmExportedFunction::function_index() {
Handle<WasmExportedFunction> WasmExportedFunction::New( Handle<WasmExportedFunction> WasmExportedFunction::New(
Isolate* isolate, Handle<WasmInstanceObject> instance, int func_index, Isolate* isolate, Handle<WasmInstanceObject> instance, int func_index,
int arity, Handle<Code> export_wrapper) { int arity, Handle<Code> export_wrapper) {
DCHECK_EQ(Code::JS_TO_WASM_FUNCTION, export_wrapper->kind()); DCHECK(
Code::JS_TO_WASM_FUNCTION == export_wrapper->kind() ||
(export_wrapper->is_builtin() &&
export_wrapper->builtin_index() == Builtins::kGenericJSToWasmWrapper));
int num_imported_functions = instance->module()->num_imported_functions; int num_imported_functions = instance->module()->num_imported_functions;
int jump_table_offset = -1; int jump_table_offset = -1;
if (func_index >= num_imported_functions) { if (func_index >= num_imported_functions) {
......
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --wasm-generic-wrapper
load("test/mjsunit/wasm/wasm-module-builder.js");
(function testGenericWrapper() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig_index = builder.addType(kSig_v_v);
let func_index = builder.addImport("mod", "func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
kExprCallFunction, func_index
])
.exportFunc();
let x = 12;
function import_func() {
x = 20;
}
builder.instantiate({ mod: { func: import_func } }).exports.main();
assertEquals(x, 20);
})();
(function testGenericWrapperFunctionTraps() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig_index = builder.addType(kSig_v_v);
builder.addFunction("main", sig_index)
.addBody([
kExprUnreachable
])
.exportFunc();
let instance = builder.instantiate();
assertTraps(kTrapUnreachable, instance.exports.main);
})();
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