[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/+/2307240 Reviewed-by: Andreas Haas <ahaas@chromium.org> Reviewed-by: Thibaud Michaud <thibaudm@chromium.org> Reviewed-by: Clemens Backes <clemensb@chromium.org> Commit-Queue: Eva Herencsárová <evih@google.com> Cr-Commit-Position: refs/heads/master@{#69097}
This commit is contained in:
parent
f97620b924
commit
1250fd59aa
@ -3060,6 +3060,11 @@ void Builtins::Generate_DoubleToI(MacroAssembler* masm) {
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
|
||||
// TODO(v8:10701): Implement for this platform.
|
||||
__ Trap();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
int AddressOffset(ExternalReference ref0, ExternalReference ref1) {
|
||||
|
@ -3728,6 +3728,11 @@ void Builtins::Generate_DoubleToI(MacroAssembler* masm) {
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
|
||||
// TODO(v8:10701): Implement for this platform.
|
||||
__ Trap();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// The number of register that CallApiFunctionAndReturn will need to save on
|
||||
|
@ -815,6 +815,7 @@ namespace internal {
|
||||
TFJ(TypedArrayPrototypeMap, kDontAdaptArgumentsSentinel) \
|
||||
\
|
||||
/* Wasm */ \
|
||||
ASM(GenericJSToWasmWrapper, Dummy) \
|
||||
ASM(WasmCompileLazy, Dummy) \
|
||||
ASM(WasmDebugBreak, Dummy) \
|
||||
TFC(WasmFloat32ToNumber, WasmFloat32ToNumber) \
|
||||
|
@ -3291,6 +3291,11 @@ void Builtins::Generate_DoubleToI(MacroAssembler* masm) {
|
||||
__ ret(0);
|
||||
}
|
||||
|
||||
void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
|
||||
// TODO(v8:10701): Implement for this platform.
|
||||
__ Trap();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Generates an Operand for saving parameters after PrepareCallApiFunction.
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "src/objects/objects-inl.h"
|
||||
#include "src/objects/smi.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-objects.h"
|
||||
|
||||
@ -3198,6 +3199,97 @@ void Builtins::Generate_DoubleToI(MacroAssembler* masm) {
|
||||
__ 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 {
|
||||
|
||||
int Offset(ExternalReference ref0, ExternalReference ref1) {
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/objects/objects.h"
|
||||
|
||||
#include "src/codegen/assembler-inl.h"
|
||||
#include "src/date/date.h"
|
||||
#include "src/diagnostics/disasm.h"
|
||||
@ -32,6 +30,7 @@
|
||||
#include "src/objects/js-array-inl.h"
|
||||
#include "src/objects/layout-descriptor.h"
|
||||
#include "src/objects/objects-inl.h"
|
||||
#include "src/objects/objects.h"
|
||||
#include "src/roots/roots.h"
|
||||
#ifdef V8_INTL_SUPPORT
|
||||
#include "src/objects/js-break-iterator-inl.h"
|
||||
@ -1446,7 +1445,9 @@ void WasmExportedFunctionData::WasmExportedFunctionDataVerify(
|
||||
Isolate* isolate) {
|
||||
TorqueGeneratedClassVerifiers::WasmExportedFunctionDataVerify(*this, isolate);
|
||||
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)
|
||||
|
@ -701,6 +701,8 @@ DEFINE_BOOL(untrusted_code_mitigations, V8_DEFAULT_UNTRUSTED_CODE_MITIGATIONS,
|
||||
#undef V8_DEFAULT_UNTRUSTED_CODE_MITIGATIONS
|
||||
|
||||
// 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(assume_asmjs_origin, false,
|
||||
"force wasm decoder to assume input is internal asm-wasm format")
|
||||
|
@ -66,12 +66,13 @@ Context GetNativeContextFromWasmInstanceOnStackTop(Isolate* isolate) {
|
||||
class ClearThreadInWasmScope {
|
||||
public:
|
||||
ClearThreadInWasmScope() {
|
||||
DCHECK_EQ(trap_handler::IsTrapHandlerEnabled(),
|
||||
trap_handler::IsThreadInWasm());
|
||||
DCHECK_IMPLIES(trap_handler::IsTrapHandlerEnabled(),
|
||||
trap_handler::IsThreadInWasm());
|
||||
trap_handler::ClearThreadInWasm();
|
||||
}
|
||||
~ClearThreadInWasmScope() {
|
||||
DCHECK(!trap_handler::IsThreadInWasm());
|
||||
DCHECK_IMPLIES(trap_handler::IsTrapHandlerEnabled(),
|
||||
!trap_handler::IsThreadInWasm());
|
||||
trap_handler::SetThreadInWasm();
|
||||
}
|
||||
};
|
||||
|
@ -272,23 +272,40 @@ JSToWasmWrapperCompilationUnit::JSToWasmWrapperCompilationUnit(
|
||||
bool is_import, const WasmFeatures& enabled_features)
|
||||
: is_import_(is_import),
|
||||
sig_(sig),
|
||||
job_(compiler::NewJSToWasmCompilationJob(isolate, wasm_engine, sig,
|
||||
is_import, enabled_features)) {}
|
||||
#if V8_TARGET_ARCH_X64
|
||||
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;
|
||||
|
||||
void JSToWasmWrapperCompilationUnit::Execute() {
|
||||
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"),
|
||||
"wasm.CompileJSToWasmWrapper");
|
||||
CompilationJob::Status status = job_->ExecuteJob(nullptr);
|
||||
CHECK_EQ(status, CompilationJob::SUCCEEDED);
|
||||
if (!use_generic_wrapper_) {
|
||||
CompilationJob::Status status = job_->ExecuteJob(nullptr);
|
||||
CHECK_EQ(status, CompilationJob::SUCCEEDED);
|
||||
}
|
||||
}
|
||||
|
||||
Handle<Code> JSToWasmWrapperCompilationUnit::Finalize(Isolate* isolate) {
|
||||
CompilationJob::Status status = job_->FinalizeJob(isolate);
|
||||
CHECK_EQ(status, CompilationJob::SUCCEEDED);
|
||||
Handle<Code> code = job_->compilation_info()->code();
|
||||
if (must_record_function_compilation(isolate)) {
|
||||
Handle<Code> code;
|
||||
if (use_generic_wrapper_) {
|
||||
code =
|
||||
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(
|
||||
isolate, code, "%s", job_->compilation_info()->GetDebugName().get());
|
||||
}
|
||||
|
@ -132,6 +132,7 @@ class V8_EXPORT_PRIVATE JSToWasmWrapperCompilationUnit final {
|
||||
private:
|
||||
bool is_import_;
|
||||
const FunctionSig* sig_;
|
||||
bool use_generic_wrapper_;
|
||||
std::unique_ptr<OptimizedCompilationJob> job_;
|
||||
};
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/wasm/wasm-objects.h"
|
||||
#include "src/utils/utils.h"
|
||||
|
||||
#include "src/base/iterator.h"
|
||||
#include "src/codegen/assembler-inl.h"
|
||||
@ -16,6 +15,7 @@
|
||||
#include "src/objects/shared-function-info.h"
|
||||
#include "src/objects/struct-inl.h"
|
||||
#include "src/trap-handler/trap-handler.h"
|
||||
#include "src/utils/utils.h"
|
||||
#include "src/utils/vector.h"
|
||||
#include "src/wasm/jump-table-assembler.h"
|
||||
#include "src/wasm/module-compiler.h"
|
||||
@ -1746,7 +1746,10 @@ uint32_t WasmExceptionPackage::GetEncodedSize(
|
||||
bool WasmExportedFunction::IsWasmExportedFunction(Object object) {
|
||||
if (!object.IsJSFunction()) return false;
|
||||
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());
|
||||
return true;
|
||||
}
|
||||
@ -1795,7 +1798,10 @@ int WasmExportedFunction::function_index() {
|
||||
Handle<WasmExportedFunction> WasmExportedFunction::New(
|
||||
Isolate* isolate, Handle<WasmInstanceObject> instance, int func_index,
|
||||
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 jump_table_offset = -1;
|
||||
if (func_index >= num_imported_functions) {
|
||||
|
41
test/mjsunit/wasm/generic-wrapper.js
Normal file
41
test/mjsunit/wasm/generic-wrapper.js
Normal file
@ -0,0 +1,41 @@
|
||||
// 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);
|
||||
})();
|
Loading…
Reference in New Issue
Block a user