Revert "Revert "[wasm] JIT using WasmCodeManager""

This reverts commit b301203e5a.

Reason for revert: Fixed issues on arm.

Original change's description:
> Revert "[wasm] JIT using WasmCodeManager"
> 
> This reverts commit d4c8393c1c.
> 
> Reason for revert: Breaks ARM hardware:
> https://build.chromium.org/p/client.v8.ports/builders/V8%20Arm%20-%20debug/builds/5268
> 
> Original change's description:
> > [wasm] JIT using WasmCodeManager
> > 
> > This is the first step towards wasm code sharing. This CL moves wasm
> > code generation outside the JavaScript GC heap using the previously -
> > introduced WasmCodeManager (all this, behind the --wasm-jit-to-native
> > flag).
> > 
> > See design document: go/wasm-on-native-heap-stage-1
> > 
> > This CL doesn't change other wasm architectural invariants. We still
> > have per-Isolate wasm code generation, and per-wasm module instance
> > code specialization.
> > 
> > Bug:v8:6876
> > 
> > Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng
> > Change-Id: I1e08cecad75f93fb081545c31228a4568be276d3
> > Reviewed-on: https://chromium-review.googlesource.com/674086
> > Reviewed-by: Ben Titzer <titzer@chromium.org>
> > Reviewed-by: Eric Holk <eholk@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#49689}
> 
> TBR=bradnelson@chromium.org,titzer@chromium.org,mtrofin@chromium.org,eholk@chromium.org
> 
> Change-Id: I89af1ea5decd841bc12cd2ceaf74d32bc4433885
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: v8:6876
> Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng
> Reviewed-on: https://chromium-review.googlesource.com/794690
> Reviewed-by: Michael Achenbach <machenbach@chromium.org>
> Commit-Queue: Michael Achenbach <machenbach@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#49691}

TBR=bradnelson@chromium.org,machenbach@chromium.org,titzer@chromium.org,mtrofin@chromium.org,eholk@chromium.org

Change-Id: I1b07638d1bb2ba0664305b4b2dcfc1342dc8444f
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:6876
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng
Reviewed-on: https://chromium-review.googlesource.com/794434
Commit-Queue: Mircea Trofin <mtrofin@chromium.org>
Reviewed-by: Mircea Trofin <mtrofin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49692}
This commit is contained in:
Mircea Trofin 2017-11-28 14:25:36 -08:00 committed by Commit Bot
parent b301203e5a
commit b03b1bd9a8
48 changed files with 3606 additions and 986 deletions

View File

@ -2091,6 +2091,8 @@ v8_source_set("v8_base") {
"src/wasm/wasm-api.h",
"src/wasm/wasm-code-specialization.cc",
"src/wasm/wasm-code-specialization.h",
"src/wasm/wasm-code-wrapper.cc",
"src/wasm/wasm-code-wrapper.h",
"src/wasm/wasm-debug.cc",
"src/wasm/wasm-external-refs.cc",
"src/wasm/wasm-external-refs.h",
@ -2114,6 +2116,8 @@ v8_source_set("v8_base") {
"src/wasm/wasm-opcodes.h",
"src/wasm/wasm-result.cc",
"src/wasm/wasm-result.h",
"src/wasm/wasm-serialization.cc",
"src/wasm/wasm-serialization.h",
"src/wasm/wasm-text.cc",
"src/wasm/wasm-text.h",
"src/wasm/wasm-value.h",

View File

@ -86,6 +86,7 @@
#include "src/wasm/streaming-decoder.h"
#include "src/wasm/wasm-objects-inl.h"
#include "src/wasm/wasm-result.h"
#include "src/wasm/wasm-serialization.h"
namespace v8 {
@ -7781,26 +7782,40 @@ WasmCompiledModule::SerializedModule WasmCompiledModule::Serialize() {
i::Handle<i::WasmModuleObject>::cast(Utils::OpenHandle(this));
i::Handle<i::WasmCompiledModule> compiled_part =
i::handle(i::WasmCompiledModule::cast(obj->compiled_module()));
if (i::FLAG_wasm_jit_to_native) {
i::Isolate* isolate = obj->GetIsolate();
std::unique_ptr<i::ScriptData> script_data =
i::WasmCompiledModuleSerializer::SerializeWasmModule(obj->GetIsolate(),
compiled_part);
script_data->ReleaseDataOwnership();
return i::wasm::NativeModuleSerializer::SerializeWholeModule(isolate,
compiled_part);
} else {
std::unique_ptr<i::ScriptData> script_data =
i::WasmCompiledModuleSerializer::SerializeWasmModule(obj->GetIsolate(),
compiled_part);
script_data->ReleaseDataOwnership();
size_t size = static_cast<size_t>(script_data->length());
return {std::unique_ptr<const uint8_t[]>(script_data->data()), size};
size_t size = static_cast<size_t>(script_data->length());
return {std::unique_ptr<const uint8_t[]>(script_data->data()), size};
}
}
MaybeLocal<WasmCompiledModule> WasmCompiledModule::Deserialize(
Isolate* isolate,
const WasmCompiledModule::CallerOwnedBuffer& serialized_module,
const WasmCompiledModule::CallerOwnedBuffer& wire_bytes) {
int size = static_cast<int>(serialized_module.second);
i::ScriptData sc(serialized_module.first, size);
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
i::MaybeHandle<i::FixedArray> maybe_compiled_part =
i::WasmCompiledModuleSerializer::DeserializeWasmModule(
i_isolate, &sc, {wire_bytes.first, wire_bytes.second});
i::MaybeHandle<i::FixedArray> maybe_compiled_part;
if (i::FLAG_wasm_jit_to_native) {
maybe_compiled_part =
i::wasm::NativeModuleDeserializer::DeserializeFullBuffer(
i_isolate, {serialized_module.first, serialized_module.second},
{wire_bytes.first, wire_bytes.second});
} else {
int size = static_cast<int>(serialized_module.second);
i::ScriptData sc(serialized_module.first, size);
maybe_compiled_part =
i::WasmCompiledModuleSerializer::DeserializeWasmModule(
i_isolate, &sc, {wire_bytes.first, wire_bytes.second});
}
i::Handle<i::FixedArray> compiled_part;
if (!maybe_compiled_part.ToHandle(&compiled_part)) {
return MaybeLocal<WasmCompiledModule>();

View File

@ -54,6 +54,9 @@ namespace v8 {
class ApiFunction;
namespace internal {
namespace wasm {
class WasmCode;
}
// Forward declarations.
class Isolate;
@ -622,6 +625,9 @@ class RelocInfo {
byte* pc_;
Mode rmode_;
intptr_t data_;
// TODO(mtrofin): try remove host_, if all we need is the constant_pool_ or
// other few attributes, like start address, etc. This is so that we can reuse
// RelocInfo for WasmCode without having a modal design.
Code* host_;
Address constant_pool_ = nullptr;
friend class RelocIterator;

View File

@ -52,6 +52,18 @@ class V8_EXPORT_PRIVATE CompilationInfo final {
kLoopPeelingEnabled = 1 << 10,
};
// TODO(mtrofin): investigate if this might be generalized outside wasm, with
// the goal of better separating the compiler from where compilation lands. At
// that point, the Handle<Code> member of CompilationInfo would also be
// removed.
struct WasmCodeDesc {
CodeDesc code_desc;
size_t safepoint_table_offset = 0;
uint32_t frame_slot_count = 0;
Handle<ByteArray> source_positions_table;
MaybeHandle<HandlerTable> handler_table;
};
// Construct a compilation info for unoptimized compilation.
CompilationInfo(Zone* zone, ParseInfo* parse_info, FunctionLiteral* literal);
// Construct a compilation info for optimized compilation.
@ -255,6 +267,8 @@ class V8_EXPORT_PRIVATE CompilationInfo final {
coverage_info_ = coverage_info;
}
WasmCodeDesc* wasm_code_desc() { return &wasm_code_desc_; }
private:
// Compilation mode.
// BASE is generated by the full codegen, optionally prepared for bailouts.
@ -289,6 +303,7 @@ class V8_EXPORT_PRIVATE CompilationInfo final {
// The compiled code.
Handle<Code> code_;
WasmCodeDesc wasm_code_desc_;
// Compilation mode flag and whether deoptimization is allowed.
Mode mode_;

View File

@ -290,6 +290,25 @@ void CodeGenerator::AssembleCode() {
result_ = kSuccess;
}
Handle<ByteArray> CodeGenerator::GetSourcePositionTable() {
return source_position_table_builder_.ToSourcePositionTable(isolate());
}
MaybeHandle<HandlerTable> CodeGenerator::GetHandlerTable() const {
if (!handlers_.empty()) {
Handle<HandlerTable> table =
Handle<HandlerTable>::cast(isolate()->factory()->NewFixedArray(
HandlerTable::LengthForReturn(static_cast<int>(handlers_.size())),
TENURED));
for (size_t i = 0; i < handlers_.size(); ++i) {
table->SetReturnOffset(static_cast<int>(i), handlers_[i].pc_offset);
table->SetReturnHandler(static_cast<int>(i), handlers_[i].handler->pos());
}
return table;
}
return {};
}
Handle<Code> CodeGenerator::FinalizeCode() {
if (result_ != kSuccess) return Handle<Code>();

View File

@ -94,6 +94,9 @@ class CodeGenerator final : public GapResolver::Assembler {
void AssembleCode(); // Does not need to run on main thread.
Handle<Code> FinalizeCode();
Handle<ByteArray> GetSourcePositionTable();
MaybeHandle<HandlerTable> GetHandlerTable() const;
InstructionSequence* code() const { return code_; }
FrameAccessState* frame_access_state() const { return frame_access_state_; }
const Frame* frame() const { return frame_access_state_->frame(); }
@ -117,9 +120,10 @@ class CodeGenerator final : public GapResolver::Assembler {
int arguments, Safepoint::DeoptMode deopt_mode);
Zone* zone() const { return zone_; }
TurboAssembler* tasm() { return &tasm_; }
size_t GetSafepointTableOffset() const { return safepoints_.GetCodeOffset(); }
private:
TurboAssembler* tasm() { return &tasm_; }
GapResolver* resolver() { return &resolver_; }
SafepointTableBuilder* safepoints() { return &safepoints_; }
CompilationInfo* info() const { return info_; }

View File

@ -975,8 +975,22 @@ size_t PipelineWasmCompilationJob::AllocatedMemory() const {
PipelineWasmCompilationJob::Status PipelineWasmCompilationJob::FinalizeJobImpl(
Isolate* isolate) {
pipeline_.FinalizeCode();
ValidateImmovableEmbeddedObjects();
if (!FLAG_wasm_jit_to_native) {
pipeline_.FinalizeCode();
ValidateImmovableEmbeddedObjects();
} else {
CodeGenerator* code_generator = pipeline_.data_->code_generator();
CompilationInfo::WasmCodeDesc* wasm_code_desc =
compilation_info()->wasm_code_desc();
code_generator->tasm()->GetCode(isolate, &wasm_code_desc->code_desc);
wasm_code_desc->safepoint_table_offset =
code_generator->GetSafepointTableOffset();
wasm_code_desc->frame_slot_count =
code_generator->frame()->GetTotalFrameSlotCount();
wasm_code_desc->source_positions_table =
code_generator->GetSourcePositionTable();
wasm_code_desc->handler_table = code_generator->GetHandlerTable();
}
return SUCCEEDED;
}

View File

@ -13,6 +13,7 @@
#include "src/builtins/builtins.h"
#include "src/code-factory.h"
#include "src/compiler/access-builder.h"
#include "src/compiler/code-generator.h"
#include "src/compiler/common-operator.h"
#include "src/compiler/compiler-source-position-table.h"
#include "src/compiler/diamond.h"
@ -2364,15 +2365,21 @@ Node* WasmGraphBuilder::BuildWasmCall(wasm::FunctionSig* sig, Node** args,
Node* WasmGraphBuilder::CallDirect(uint32_t index, Node** args, Node*** rets,
wasm::WasmCodePosition position) {
DCHECK_NULL(args[0]);
// Add code object as constant.
Handle<Code> code = index < env_->function_code.size()
? env_->function_code[index]
: env_->default_function_code;
DCHECK(!code.is_null());
args[0] = HeapConstant(code);
wasm::FunctionSig* sig = env_->module->functions[index].sig;
if (FLAG_wasm_jit_to_native) {
// Simply encode the index of the target.
Address code = reinterpret_cast<Address>(index);
args[0] = jsgraph()->RelocatableIntPtrConstant(
reinterpret_cast<intptr_t>(code), RelocInfo::WASM_CALL);
} else {
// Add code object as constant.
Handle<Code> code = index < env_->function_code.size()
? env_->function_code[index]
: env_->default_function_code;
DCHECK(!code.is_null());
args[0] = HeapConstant(code);
}
return BuildWasmCall(sig, args, rets, position);
}
@ -2424,16 +2431,23 @@ Node* WasmGraphBuilder::CallIndirect(uint32_t sig_index, Node** args,
TrapIfFalse(wasm::kTrapFuncSigMismatch, sig_match, position);
}
// Load code object from the table.
Node* load_code = graph()->NewNode(
// Load code object from the table. It is held by a Foreign.
Node* entry = graph()->NewNode(
machine->Load(MachineType::AnyTagged()), table,
graph()->NewNode(machine->Int32Add(),
graph()->NewNode(machine->Word32Shl(), key,
Int32Constant(kPointerSizeLog2)),
Uint32Constant(fixed_offset)),
*effect_, *control_);
args[0] = load_code;
if (FLAG_wasm_jit_to_native) {
Node* address = graph()->NewNode(
machine->Load(MachineType::Pointer()), entry,
Int32Constant(Foreign::kForeignAddressOffset - kHeapObjectTag),
*effect_, *control_);
args[0] = address;
} else {
args[0] = entry;
}
return BuildWasmCall(sig, args, rets, position);
}
@ -2767,7 +2781,7 @@ Node* WasmGraphBuilder::BuildHeapNumberValueIndexConstant() {
return jsgraph()->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag);
}
void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<Code> wasm_code,
void WasmGraphBuilder::BuildJSToWasmWrapper(WasmCodeWrapper wasm_code,
Address wasm_context_address) {
const int wasm_count = static_cast<int>(sig_->parameter_count());
const int count =
@ -2793,6 +2807,16 @@ void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<Code> wasm_code,
reinterpret_cast<uintptr_t>(wasm_context_address),
RelocInfo::WASM_CONTEXT_REFERENCE);
Node* wasm_code_node = nullptr;
if (!wasm_code.IsCodeObject()) {
const wasm::WasmCode* code = wasm_code.GetWasmCode();
Address instr_start =
code == nullptr ? nullptr : code->instructions().start();
wasm_code_node = jsgraph()->RelocatableIntPtrConstant(
reinterpret_cast<intptr_t>(instr_start), RelocInfo::JS_TO_WASM_CALL);
} else {
wasm_code_node = HeapConstant(wasm_code.GetCode());
}
if (!wasm::IsJSCompatibleSignature(sig_)) {
// Throw a TypeError. Use the js_context of the calling javascript function
// (passed as a parameter), such that the generated code is js_context
@ -2804,7 +2828,7 @@ void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<Code> wasm_code,
// contains a reference to the wrapped wasm function. Without this reference
// the wasm function could not be re-imported into another wasm module.
int pos = 0;
args[pos++] = HeapConstant(wasm_code);
args[pos++] = wasm_code_node;
args[pos++] = wasm_context_;
args[pos++] = *effect_;
args[pos++] = *control_;
@ -2819,7 +2843,7 @@ void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<Code> wasm_code,
}
int pos = 0;
args[pos++] = HeapConstant(wasm_code);
args[pos++] = wasm_code_node;
args[pos++] = wasm_context_;
// Convert JS parameters to wasm numbers.
@ -3018,7 +3042,7 @@ bool HasInt64ParamOrReturn(wasm::FunctionSig* sig) {
}
} // namespace
void WasmGraphBuilder::BuildWasmToWasmWrapper(Handle<Code> target,
void WasmGraphBuilder::BuildWasmToWasmWrapper(WasmCodeWrapper wasm_code,
Address new_context_address) {
int wasm_count = static_cast<int>(sig_->parameter_count());
int count = wasm_count + 4; // wasm_code, wasm_context, effect, and control.
@ -3031,7 +3055,15 @@ void WasmGraphBuilder::BuildWasmToWasmWrapper(Handle<Code> target,
int pos = 0;
// Add the wasm code target.
args[pos++] = jsgraph()->HeapConstant(target);
if (!wasm_code.IsCodeObject()) {
const wasm::WasmCode* code = wasm_code.GetWasmCode();
Address instr_start =
code == nullptr ? nullptr : code->instructions().start();
args[pos++] = jsgraph()->RelocatableIntPtrConstant(
reinterpret_cast<intptr_t>(instr_start), RelocInfo::JS_TO_WASM_CALL);
} else {
args[pos++] = jsgraph()->HeapConstant(wasm_code.GetCode());
}
// Add the wasm_context of the other instance.
args[pos++] = jsgraph()->IntPtrConstant(
reinterpret_cast<uintptr_t>(new_context_address));
@ -3129,7 +3161,17 @@ void WasmGraphBuilder::BuildCWasmEntry(Address wasm_context_address) {
reinterpret_cast<uintptr_t>(wasm_context_address));
// Create parameter nodes (offset by 1 for the receiver parameter).
Node* code_obj = Param(CWasmEntryParameters::kCodeObject + 1);
Node* code_obj = nullptr;
if (FLAG_wasm_jit_to_native) {
Node* foreign_code_obj = Param(CWasmEntryParameters::kCodeObject + 1);
MachineOperatorBuilder* machine = jsgraph()->machine();
code_obj = graph()->NewNode(
machine->Load(MachineType::Pointer()), foreign_code_obj,
Int32Constant(Foreign::kForeignAddressOffset - kHeapObjectTag),
*effect_, *control_);
} else {
code_obj = Param(CWasmEntryParameters::kCodeObject + 1);
}
Node* arg_buffer = Param(CWasmEntryParameters::kArgumentsBuffer + 1);
int wasm_arg_count = static_cast<int>(sig_->parameter_count());
@ -4203,7 +4245,7 @@ void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag,
} // namespace
Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::WasmModule* module,
Handle<Code> wasm_code, uint32_t index,
WasmCodeWrapper wasm_code, uint32_t index,
Address wasm_context_address) {
const wasm::WasmFunction* func = &module->functions[index];
@ -4225,8 +4267,10 @@ Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::WasmModule* module,
// TODO(titzer): compile JS to WASM wrappers without a {ModuleEnv}.
ModuleEnv env = {
module,
std::vector<Address>(), // function_tables
std::vector<Address>(), // signature_tables
std::vector<Address>(), // function_tables
std::vector<Address>(), // signature_tables
// TODO(mtrofin): remove these 2 lines when we don't need
// FLAG_wasm_jit_to_native
std::vector<Handle<Code>>(), // function_code
BUILTIN_CODE(isolate, Illegal) // default_function_code
};
@ -4411,9 +4455,8 @@ Handle<Code> CompileWasmToJSWrapper(
return code;
}
Handle<Code> CompileWasmToWasmWrapper(Isolate* isolate, Handle<Code> target,
Handle<Code> CompileWasmToWasmWrapper(Isolate* isolate, WasmCodeWrapper target,
wasm::FunctionSig* sig,
uint32_t func_index,
Address new_wasm_context_address) {
//----------------------------------------------------------------------------
// Create the Graph
@ -4543,11 +4586,13 @@ Handle<Code> CompileWasmInterpreterEntry(Isolate* isolate, uint32_t func_index,
}
}
Handle<FixedArray> deopt_data = isolate->factory()->NewFixedArray(1, TENURED);
Handle<WeakCell> weak_instance = isolate->factory()->NewWeakCell(instance);
deopt_data->set(0, *weak_instance);
code->set_deoptimization_data(*deopt_data);
if (!FLAG_wasm_jit_to_native) {
Handle<FixedArray> deopt_data =
isolate->factory()->NewFixedArray(1, TENURED);
Handle<WeakCell> weak_instance = isolate->factory()->NewWeakCell(instance);
deopt_data->set(0, *weak_instance);
code->set_deoptimization_data(*deopt_data);
}
return code;
}
@ -4691,9 +4736,9 @@ WasmCompilationUnit::GetDefaultCompilationMode() {
}
WasmCompilationUnit::WasmCompilationUnit(
Isolate* isolate, ModuleEnv* env, wasm::FunctionBody body,
wasm::WasmName name, int index, Handle<Code> centry_stub,
CompilationMode mode, Counters* counters,
Isolate* isolate, ModuleEnv* env, wasm::NativeModule* native_module,
wasm::FunctionBody body, wasm::WasmName name, int index,
Handle<Code> centry_stub, CompilationMode mode, Counters* counters,
RuntimeExceptionSupport exception_support, bool lower_simd)
: isolate_(isolate),
env_(env),
@ -4703,7 +4748,10 @@ WasmCompilationUnit::WasmCompilationUnit(
centry_stub_(centry_stub),
func_index_(index),
runtime_exception_support_(exception_support),
native_module_(native_module),
lower_simd_(lower_simd),
protected_instructions_(
new std::vector<trap_handler::ProtectedInstructionData>()),
mode_(mode) {
switch (mode_) {
case WasmCompilationUnit::CompilationMode::kLiftoff:
@ -4803,7 +4851,7 @@ void WasmCompilationUnit::ExecuteTurbofanCompilation() {
tf_.job_.reset(Pipeline::NewWasmCompilationJob(
tf_.info_.get(), isolate_, tf_.jsgraph_, descriptor, source_positions,
&protected_instructions_, env_->module->origin()));
protected_instructions_.get(), env_->module->origin()));
ok_ = tf_.job_->ExecuteJob() == CompilationJob::SUCCEEDED;
// TODO(bradnelson): Improve histogram handling of size_t.
counters()->wasm_compile_function_peak_memory_bytes()->AddSample(
@ -4829,18 +4877,26 @@ void WasmCompilationUnit::ExecuteTurbofanCompilation() {
// WasmCompilationUnit::ExecuteLiftoffCompilation() is defined in
// liftoff-compiler.cc.
MaybeHandle<Code> WasmCompilationUnit::FinishCompilation(
WasmCodeWrapper WasmCompilationUnit::FinishCompilation(
wasm::ErrorThrower* thrower) {
WasmCodeWrapper ret;
switch (mode_) {
case WasmCompilationUnit::CompilationMode::kLiftoff:
return FinishLiftoffCompilation(thrower);
ret = FinishLiftoffCompilation(thrower);
break;
case WasmCompilationUnit::CompilationMode::kTurbofan:
return FinishTurbofanCompilation(thrower);
ret = FinishTurbofanCompilation(thrower);
break;
default:
UNREACHABLE();
}
UNREACHABLE();
if (!ret.IsCodeObject() && ret.is_null()) {
thrower->RuntimeError("Error finalizing code.");
}
return ret;
}
MaybeHandle<Code> WasmCompilationUnit::FinishTurbofanCompilation(
WasmCodeWrapper WasmCompilationUnit::FinishTurbofanCompilation(
wasm::ErrorThrower* thrower) {
if (!ok_) {
if (tf_.graph_construction_result_.failed()) {
@ -4862,39 +4918,78 @@ MaybeHandle<Code> WasmCompilationUnit::FinishTurbofanCompilation(
if (FLAG_trace_wasm_decode_time) {
codegen_timer.Start();
}
if (tf_.job_->FinalizeJob(isolate_) != CompilationJob::SUCCEEDED) {
return Handle<Code>::null();
return {};
}
Handle<Code> code = tf_.info_->code();
DCHECK(!code.is_null());
if (!FLAG_wasm_jit_to_native) {
Handle<Code> code = tf_.info_->code();
DCHECK(!code.is_null());
if (must_record_function_compilation(isolate_)) {
wasm::TruncatedUserString<> trunc_name(func_name_);
RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, isolate_, code,
"wasm_function#%d:%.*s", func_index_,
trunc_name.length(), trunc_name.start());
if (FLAG_trace_wasm_decode_time) {
double codegen_ms = codegen_timer.Elapsed().InMillisecondsF();
PrintF("wasm-code-generation ok: %u bytes, %0.3f ms code generation\n",
static_cast<unsigned>(func_body_.end - func_body_.start),
codegen_ms);
}
PackProtectedInstructions(code);
return WasmCodeWrapper(code);
} else {
// TODO(mtrofin): when we crystalize a design in lieu of WasmCodeDesc, that
// works for both wasm and non-wasm, we can simplify AddCode to just take
// that as a parameter.
const CodeDesc& desc =
tf_.job_->compilation_info()->wasm_code_desc()->code_desc;
wasm::WasmCode* code = native_module_->AddCode(
desc, tf_.job_->compilation_info()->wasm_code_desc()->frame_slot_count,
func_index_,
tf_.job_->compilation_info()->wasm_code_desc()->safepoint_table_offset,
protected_instructions_);
if (!code) {
return WasmCodeWrapper(code);
}
// TODO(mtrofin): add CodeEventListener call - see the non-native case.
if (FLAG_trace_wasm_decode_time) {
double codegen_ms = codegen_timer.Elapsed().InMillisecondsF();
PrintF("wasm-code-generation ok: %u bytes, %0.3f ms code generation\n",
static_cast<unsigned>(func_body_.end - func_body_.start),
codegen_ms);
}
Handle<ByteArray> source_positions =
tf_.job_->compilation_info()->wasm_code_desc()->source_positions_table;
MaybeHandle<HandlerTable> handler_table =
tf_.job_->compilation_info()->wasm_code_desc()->handler_table;
int function_index_as_int = static_cast<int>(func_index_);
native_module_->compiled_module()->source_positions()->set(
function_index_as_int, *source_positions);
if (!handler_table.is_null()) {
native_module_->compiled_module()->handler_table()->set(
function_index_as_int, *handler_table.ToHandleChecked());
}
// TODO(mtrofin): this should probably move up in the common caller,
// once liftoff has source positions. Until then, we'd need to handle
// undefined values, which is complicating the code.
LOG_CODE_EVENT(isolate_,
CodeLinePosInfoRecordEvent(code->instructions().start(),
*source_positions));
return WasmCodeWrapper(code);
}
if (FLAG_trace_wasm_decode_time) {
double codegen_ms = codegen_timer.Elapsed().InMillisecondsF();
PrintF("wasm-code-generation ok: %u bytes, %0.3f ms code generation\n",
static_cast<unsigned>(func_body_.end - func_body_.start),
codegen_ms);
}
PackProtectedInstructions(code);
return code;
}
// TODO(mtrofin): remove when FLAG_wasm_jit_to_native is not needed
void WasmCompilationUnit::PackProtectedInstructions(Handle<Code> code) const {
if (protected_instructions_.empty()) return;
DCHECK_LT(protected_instructions_.size(), std::numeric_limits<int>::max());
const int num_instructions = static_cast<int>(protected_instructions_.size());
if (protected_instructions_->empty()) return;
DCHECK_LT(protected_instructions_->size(), std::numeric_limits<int>::max());
const int num_instructions =
static_cast<int>(protected_instructions_->size());
Handle<FixedArray> fn_protected = isolate_->factory()->NewFixedArray(
num_instructions * Code::kTrapDataSize, TENURED);
for (int i = 0; i < num_instructions; ++i) {
const trap_handler::ProtectedInstructionData& instruction =
protected_instructions_[i];
protected_instructions_->at(i);
fn_protected->set(Code::kTrapDataSize * i + Code::kTrapCodeOffset,
Smi::FromInt(instruction.instr_offset));
fn_protected->set(Code::kTrapDataSize * i + Code::kTrapLandingOffset,
@ -4903,46 +4998,57 @@ void WasmCompilationUnit::PackProtectedInstructions(Handle<Code> code) const {
code->set_protected_instructions(*fn_protected);
}
MaybeHandle<Code> WasmCompilationUnit::FinishLiftoffCompilation(
WasmCodeWrapper WasmCompilationUnit::FinishLiftoffCompilation(
wasm::ErrorThrower* thrower) {
CodeDesc desc;
liftoff_.asm_.GetCode(isolate_, &desc);
Handle<Code> code;
code = isolate_->factory()->NewCode(desc, Code::WASM_FUNCTION, code);
WasmCodeWrapper ret;
if (!FLAG_wasm_jit_to_native) {
Handle<Code> code;
code = isolate_->factory()->NewCode(desc, Code::WASM_FUNCTION, code);
#ifdef ENABLE_DISASSEMBLER
if (FLAG_print_code || FLAG_print_wasm_code) {
// TODO(wasm): Use proper log files, here and elsewhere.
OFStream os(stdout);
os << "--- Wasm liftoff code ---\n";
EmbeddedVector<char, 32> func_name;
func_name.Truncate(SNPrintF(func_name, "wasm#%d-liftoff", func_index_));
code->Disassemble(func_name.start(), os);
os << "--- End code ---\n";
}
if (FLAG_print_code || FLAG_print_wasm_code) {
// TODO(wasm): Use proper log files, here and elsewhere.
OFStream os(stdout);
os << "--- Wasm liftoff code ---\n";
EmbeddedVector<char, 32> func_name;
func_name.Truncate(SNPrintF(func_name, "wasm#%d-liftoff", func_index_));
code->Disassemble(func_name.start(), os);
os << "--- End code ---\n";
}
#endif
if (isolate_->logger()->is_logging_code_events() ||
isolate_->is_profiling()) {
RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, isolate_, code,
"wasm#%d-liftoff", func_index_);
}
if (isolate_->logger()->is_logging_code_events() ||
isolate_->is_profiling()) {
RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, isolate_, code,
"wasm#%d-liftoff", func_index_);
PackProtectedInstructions(code);
return WasmCodeWrapper(code);
} else {
// TODO(mtrofin): figure a way to raise events; also, disassembly.
// Consider lifting them both to FinishCompilation.
return WasmCodeWrapper(native_module_->AddCode(
desc, liftoff_.asm_.GetTotalFrameSlotCount(), func_index_,
liftoff_.asm_.GetSafepointTableOffset(), protected_instructions_,
true));
}
PackProtectedInstructions(code);
return code;
}
// static
MaybeHandle<Code> WasmCompilationUnit::CompileWasmFunction(
wasm::ErrorThrower* thrower, Isolate* isolate,
const wasm::ModuleWireBytes& wire_bytes, ModuleEnv* env,
WasmCodeWrapper WasmCompilationUnit::CompileWasmFunction(
wasm::NativeModule* native_module, wasm::ErrorThrower* thrower,
Isolate* isolate, const wasm::ModuleWireBytes& wire_bytes, ModuleEnv* env,
const wasm::WasmFunction* function, CompilationMode mode) {
wasm::FunctionBody function_body{
function->sig, function->code.offset(),
wire_bytes.start() + function->code.offset(),
wire_bytes.start() + function->code.end_offset()};
WasmCompilationUnit unit(
isolate, env, function_body, wire_bytes.GetNameOrNull(function),
function->func_index, CEntryStub(isolate, 1).GetCode(), mode);
WasmCompilationUnit unit(isolate, env, native_module, function_body,
wire_bytes.GetNameOrNull(function),
function->func_index,
CEntryStub(isolate, 1).GetCode(), mode);
unit.ExecuteCompilation();
return unit.FinishCompilation(thrower);
}

View File

@ -37,6 +37,8 @@ class SignatureMap;
// Expose {Node} and {Graph} opaquely as {wasm::TFNode} and {wasm::TFGraph}.
typedef compiler::Node TFNode;
typedef compiler::JSGraph TFGraph;
class NativeModule;
class WasmCode;
} // namespace wasm
namespace compiler {
@ -60,6 +62,8 @@ struct ModuleEnv {
// (the same length as module.function_tables)
// We use the address to a global handle to the FixedArray.
const std::vector<Address> signature_tables;
// TODO(mtrofin): remove these 2 once we don't need FLAG_wasm_jit_to_native
// Contains the code objects to call for each direct call.
// (the same length as module.functions)
const std::vector<Handle<Code>> function_code;
@ -82,8 +86,9 @@ class WasmCompilationUnit final {
// typically means to hold a std::shared_ptr<Counters>).
// If no such pointer is passed, Isolate::counters() will be called. This is
// only allowed to happen on the foreground thread.
WasmCompilationUnit(Isolate*, ModuleEnv*, wasm::FunctionBody, wasm::WasmName,
int index, Handle<Code> centry_stub,
WasmCompilationUnit(Isolate*, ModuleEnv*, wasm::NativeModule*,
wasm::FunctionBody, wasm::WasmName, int index,
Handle<Code> centry_stub,
CompilationMode = GetDefaultCompilationMode(),
Counters* = nullptr,
RuntimeExceptionSupport = kRuntimeExceptionSupport,
@ -94,11 +99,13 @@ class WasmCompilationUnit final {
int func_index() const { return func_index_; }
void ExecuteCompilation();
MaybeHandle<Code> FinishCompilation(wasm::ErrorThrower*);
WasmCodeWrapper FinishCompilation(wasm::ErrorThrower* thrower);
static MaybeHandle<Code> CompileWasmFunction(
wasm::ErrorThrower*, Isolate*, const wasm::ModuleWireBytes&, ModuleEnv*,
const wasm::WasmFunction*, CompilationMode = GetDefaultCompilationMode());
static WasmCodeWrapper CompileWasmFunction(
wasm::NativeModule* native_module, wasm::ErrorThrower* thrower,
Isolate* isolate, const wasm::ModuleWireBytes& wire_bytes, ModuleEnv* env,
const wasm::WasmFunction* function,
CompilationMode = GetDefaultCompilationMode());
size_t memory_cost() const { return memory_cost_; }
@ -125,11 +132,11 @@ class WasmCompilationUnit final {
// Turbofan.
SourcePositionTable* BuildGraphForWasmFunction(double* decode_ms);
void ExecuteTurbofanCompilation();
MaybeHandle<Code> FinishTurbofanCompilation(wasm::ErrorThrower*);
WasmCodeWrapper FinishTurbofanCompilation(wasm::ErrorThrower*);
// Liftoff.
bool ExecuteLiftoffCompilation();
MaybeHandle<Code> FinishLiftoffCompilation(wasm::ErrorThrower*);
WasmCodeWrapper FinishLiftoffCompilation(wasm::ErrorThrower*);
Isolate* isolate_;
ModuleEnv* env_;
@ -142,8 +149,10 @@ class WasmCompilationUnit final {
RuntimeExceptionSupport runtime_exception_support_;
bool ok_ = true;
size_t memory_cost_ = 0;
wasm::NativeModule* native_module_;
bool lower_simd_;
std::vector<trap_handler::ProtectedInstructionData> protected_instructions_;
std::shared_ptr<std::vector<trap_handler::ProtectedInstructionData>>
protected_instructions_;
CompilationMode mode_;
// {liftoff_} is valid if mode_ == kLiftoff, tf_ if mode_ == kTurbofan.
union {
@ -166,15 +175,14 @@ Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, Handle<JSReceiver> target,
Handle<FixedArray> global_js_imports_table);
// Wraps a given wasm code object, producing a code object.
Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::WasmModule* module,
Handle<Code> wasm_code, uint32_t index,
Address wasm_context_address);
V8_EXPORT_PRIVATE Handle<Code> CompileJSToWasmWrapper(
Isolate* isolate, wasm::WasmModule* module, WasmCodeWrapper wasm_code,
uint32_t index, Address wasm_context_address);
// Wraps a wasm function, producing a code object that can be called from other
// wasm instances (the WasmContext address must be changed).
Handle<Code> CompileWasmToWasmWrapper(Isolate* isolate, Handle<Code> target,
Handle<Code> CompileWasmToWasmWrapper(Isolate* isolate, WasmCodeWrapper target,
wasm::FunctionSig* sig,
uint32_t func_index,
Address new_wasm_context_address);
// Compiles a stub that redirects a call to a wasm function to the wasm
@ -293,7 +301,7 @@ class WasmGraphBuilder {
Node* CallIndirect(uint32_t index, Node** args, Node*** rets,
wasm::WasmCodePosition position);
void BuildJSToWasmWrapper(Handle<Code> wasm_code,
void BuildJSToWasmWrapper(WasmCodeWrapper wasm_code_start,
Address wasm_context_address);
enum ImportDataType {
kFunction = 1,
@ -306,7 +314,7 @@ class WasmGraphBuilder {
bool BuildWasmToJSWrapper(Handle<JSReceiver> target,
Handle<FixedArray> global_js_imports_table,
int index);
void BuildWasmToWasmWrapper(Handle<Code> target,
void BuildWasmToWasmWrapper(WasmCodeWrapper wasm_code_start,
Address new_wasm_context_address);
void BuildWasmInterpreterEntry(uint32_t func_index);
void BuildCWasmEntry(Address wasm_context_address);

View File

@ -252,13 +252,18 @@ CallDescriptor* GetWasmCallDescriptor(Zone* zone, wasm::FunctionSig* fsig,
const RegList kCalleeSaveFPRegisters = 0;
// The target for wasm calls is always a code object.
MachineType target_type = MachineType::AnyTagged();
MachineType target_type = FLAG_wasm_jit_to_native ? MachineType::Pointer()
: MachineType::AnyTagged();
LinkageLocation target_loc = LinkageLocation::ForAnyRegister(target_type);
CallDescriptor::Flags flags = CallDescriptor::kUseNativeStack;
if (supports_tail_calls) flags |= CallDescriptor::kSupportsTailCalls;
CallDescriptor::Kind kind = FLAG_wasm_jit_to_native
? CallDescriptor::kCallWasmFunction
: CallDescriptor::kCallCodeObject;
return new (zone) CallDescriptor( // --
CallDescriptor::kCallCodeObject, // kind
kind, // kind
target_type, // target MachineType
target_loc, // target location
locations.Build(), // location_sig

View File

@ -16,6 +16,7 @@
#include "src/string-stream.h"
#include "src/visitors.h"
#include "src/vm-state-inl.h"
#include "src/wasm/wasm-heap.h"
#include "src/wasm/wasm-objects-inl.h"
#include "src/zone/zone-containers.h"
@ -432,45 +433,68 @@ StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator,
}
}
} else {
// Look up the code object to figure out the type of the stack frame.
Code* code_obj =
GetContainingCode(iterator->isolate(), *(state->pc_address));
if (code_obj != nullptr) {
switch (code_obj->kind()) {
case Code::BUILTIN:
if (StackFrame::IsTypeMarker(marker)) break;
if (code_obj->is_interpreter_trampoline_builtin()) {
return INTERPRETED;
}
if (code_obj->is_turbofanned()) {
// TODO(bmeurer): We treat frames for BUILTIN Code objects as
// OptimizedFrame for now (all the builtins with JavaScript
// linkage are actually generated with TurboFan currently, so
// this is sound).
return OPTIMIZED;
}
return BUILTIN;
case Code::OPTIMIZED_FUNCTION:
return OPTIMIZED;
case Code::WASM_FUNCTION:
return WASM_COMPILED;
case Code::WASM_TO_JS_FUNCTION:
return WASM_TO_JS;
case Code::JS_TO_WASM_FUNCTION:
return JS_TO_WASM;
case Code::WASM_INTERPRETER_ENTRY:
Address pc = *(state->pc_address);
// If FLAG_wasm_jit_to_native is disabled, we still have an empty
// wasm_code_manager, and this test will be false. This is easier to read
// than checking the flag, then getting the code, and then, if both are true
// (non-null, respectivelly), going down the wasm_code path.
wasm::WasmCode* wasm_code =
iterator->isolate()->wasm_code_manager()->LookupCode(pc);
if (wasm_code != nullptr) {
switch (wasm_code->kind()) {
case wasm::WasmCode::InterpreterStub:
return WASM_INTERPRETER_ENTRY;
case Code::C_WASM_ENTRY:
return C_WASM_ENTRY;
case wasm::WasmCode::Function:
case wasm::WasmCode::CopiedStub:
return WASM_COMPILED;
case wasm::WasmCode::LazyStub:
if (StackFrame::IsTypeMarker(marker)) break;
return BUILTIN;
case wasm::WasmCode::WasmToJsWrapper:
case wasm::WasmCode::WasmToWasmWrapper:
return WASM_TO_JS;
default:
// All other types should have an explicit marker
break;
UNREACHABLE();
}
} else {
return NONE;
// Look up the code object to figure out the type of the stack frame.
Code* code_obj = GetContainingCode(iterator->isolate(), pc);
if (code_obj != nullptr) {
switch (code_obj->kind()) {
case Code::BUILTIN:
if (StackFrame::IsTypeMarker(marker)) break;
if (code_obj->is_interpreter_trampoline_builtin()) {
return INTERPRETED;
}
if (code_obj->is_turbofanned()) {
// TODO(bmeurer): We treat frames for BUILTIN Code objects as
// OptimizedFrame for now (all the builtins with JavaScript
// linkage are actually generated with TurboFan currently, so
// this is sound).
return OPTIMIZED;
}
return BUILTIN;
case Code::OPTIMIZED_FUNCTION:
return OPTIMIZED;
case Code::WASM_FUNCTION:
return WASM_COMPILED;
case Code::WASM_TO_JS_FUNCTION:
return WASM_TO_JS;
case Code::JS_TO_WASM_FUNCTION:
return JS_TO_WASM;
case Code::WASM_INTERPRETER_ENTRY:
return WASM_INTERPRETER_ENTRY;
case Code::C_WASM_ENTRY:
return C_WASM_ENTRY;
default:
// All other types should have an explicit marker
break;
}
} else {
return NONE;
}
}
}
DCHECK(StackFrame::IsTypeMarker(marker));
StackFrame::Type candidate = StackFrame::MarkerToType(marker);
switch (candidate) {
@ -751,20 +775,38 @@ void StandardFrame::IterateCompiledFrame(RootVisitor* v) const {
// Find the code and compute the safepoint information.
Address inner_pointer = pc();
InnerPointerToCodeCache::InnerPointerToCodeCacheEntry* entry =
isolate()->inner_pointer_to_code_cache()->GetCacheEntry(inner_pointer);
if (!entry->safepoint_entry.is_valid()) {
entry->safepoint_entry = entry->code->GetSafepointEntry(inner_pointer);
DCHECK(entry->safepoint_entry.is_valid());
const wasm::WasmCode* wasm_code =
FLAG_wasm_jit_to_native
? isolate()->wasm_code_manager()->LookupCode(inner_pointer)
: nullptr;
SafepointEntry safepoint_entry;
uint32_t stack_slots;
Code* code = nullptr;
bool has_tagged_params = false;
if (wasm_code != nullptr) {
SafepointTable table(wasm_code->instructions().start(),
wasm_code->safepoint_table_offset(),
wasm_code->stack_slots());
safepoint_entry = table.FindEntry(inner_pointer);
stack_slots = wasm_code->stack_slots();
has_tagged_params = wasm_code->kind() != wasm::WasmCode::Function;
} else {
DCHECK(entry->safepoint_entry.Equals(
entry->code->GetSafepointEntry(inner_pointer)));
}
InnerPointerToCodeCache::InnerPointerToCodeCacheEntry* entry =
isolate()->inner_pointer_to_code_cache()->GetCacheEntry(inner_pointer);
if (!entry->safepoint_entry.is_valid()) {
entry->safepoint_entry = entry->code->GetSafepointEntry(inner_pointer);
DCHECK(entry->safepoint_entry.is_valid());
} else {
DCHECK(entry->safepoint_entry.Equals(
entry->code->GetSafepointEntry(inner_pointer)));
}
Code* code = entry->code;
SafepointEntry safepoint_entry = entry->safepoint_entry;
unsigned stack_slots = code->stack_slots();
unsigned slot_space = stack_slots * kPointerSize;
code = entry->code;
safepoint_entry = entry->safepoint_entry;
stack_slots = code->stack_slots();
has_tagged_params = code->has_tagged_params();
}
uint32_t slot_space = stack_slots * kPointerSize;
// Determine the fixed header and spill slot area size.
int frame_header_size = StandardFrameConstants::kFixedFrameSizeFromFp;
@ -847,7 +889,7 @@ void StandardFrame::IterateCompiledFrame(RootVisitor* v) const {
safepoint_bits += kNumSafepointRegisters >> kBitsPerByteLog2;
// Visit the rest of the parameters if they are tagged.
if (code->has_tagged_params()) {
if (has_tagged_params) {
v->VisitRootPointers(Root::kTop, parameters_base, parameters_limit);
}
@ -860,8 +902,11 @@ void StandardFrame::IterateCompiledFrame(RootVisitor* v) const {
}
}
// Visit the return address in the callee and incoming arguments.
IteratePc(v, pc_address(), constant_pool_address(), code);
// For wasm-to-js cases, we can skip this.
if (code != nullptr) {
// Visit the return address in the callee and incoming arguments.
IteratePc(v, pc_address(), constant_pool_address(), code);
}
if (!is_wasm() && !is_wasm_to_js()) {
// If this frame has JavaScript ABI, visit the context (in stub and JS
@ -1215,7 +1260,7 @@ Handle<Context> FrameSummary::WasmFrameSummary::native_context() const {
}
FrameSummary::WasmCompiledFrameSummary::WasmCompiledFrameSummary(
Isolate* isolate, Handle<WasmInstanceObject> instance, Handle<Code> code,
Isolate* isolate, Handle<WasmInstanceObject> instance, WasmCodeWrapper code,
int code_offset, bool at_to_number_conversion)
: WasmFrameSummary(isolate, WASM_COMPILED, instance,
at_to_number_conversion),
@ -1223,16 +1268,38 @@ FrameSummary::WasmCompiledFrameSummary::WasmCompiledFrameSummary(
code_offset_(code_offset) {}
uint32_t FrameSummary::WasmCompiledFrameSummary::function_index() const {
FixedArray* deopt_data = code()->deoptimization_data();
DCHECK_EQ(2, deopt_data->length());
DCHECK(deopt_data->get(1)->IsSmi());
int val = Smi::ToInt(deopt_data->get(1));
DCHECK_LE(0, val);
return static_cast<uint32_t>(val);
if (code().IsCodeObject()) {
FixedArray* deopt_data = code().GetCode()->deoptimization_data();
DCHECK_EQ(2, deopt_data->length());
DCHECK(deopt_data->get(1)->IsSmi());
int val = Smi::ToInt(deopt_data->get(1));
DCHECK_LE(0, val);
return static_cast<uint32_t>(val);
}
return code().GetWasmCode()->index();
}
int FrameSummary::WasmCompiledFrameSummary::GetWasmSourcePosition(
const wasm::WasmCode* code, int offset) {
int position = 0;
// Subtract one because the current PC is one instruction after the call site.
offset--;
Handle<ByteArray> source_position_table(
ByteArray::cast(code->owner()->compiled_module()->source_positions()->get(
code->index())));
for (SourcePositionTableIterator iterator(source_position_table);
!iterator.done() && iterator.code_offset() <= offset;
iterator.Advance()) {
position = iterator.source_position().ScriptOffset();
}
return position;
}
int FrameSummary::WasmCompiledFrameSummary::byte_offset() const {
return AbstractCode::cast(*code())->SourcePosition(code_offset());
if (code().IsCodeObject()) {
return AbstractCode::cast(*code().GetCode())->SourcePosition(code_offset());
}
return GetWasmSourcePosition(code_.GetWasmCode(), code_offset());
}
FrameSummary::WasmInterpretedFrameSummary::WasmInterpretedFrameSummary(
@ -1658,7 +1725,11 @@ Address WasmCompiledFrame::GetCallerStackPointer() const {
}
WasmInstanceObject* WasmCompiledFrame::wasm_instance() const {
WasmInstanceObject* obj = WasmInstanceObject::GetOwningInstance(LookupCode());
WasmInstanceObject* obj =
FLAG_wasm_jit_to_native
? WasmInstanceObject::GetOwningInstance(
isolate()->wasm_code_manager()->LookupCode(pc()))
: WasmInstanceObject::GetOwningInstanceGC(LookupCode());
// This is a live stack frame; it must have a live instance.
DCHECK_NOT_NULL(obj);
return obj;
@ -1678,9 +1749,25 @@ int WasmCompiledFrame::position() const {
void WasmCompiledFrame::Summarize(std::vector<FrameSummary>* functions) const {
DCHECK(functions->empty());
Handle<Code> code(LookupCode(), isolate());
int offset = static_cast<int>(pc() - code->instruction_start());
Handle<WasmInstanceObject> instance(wasm_instance(), isolate());
WasmCodeWrapper code;
Handle<WasmInstanceObject> instance;
int offset = -1;
if (FLAG_wasm_jit_to_native) {
code = WasmCodeWrapper(isolate()->wasm_code_manager()->LookupCode(pc()));
offset =
static_cast<int>(pc() - code.GetWasmCode()->instructions().start());
instance = Handle<WasmInstanceObject>(
WasmInstanceObject::cast(code.GetWasmCode()
->owner()
->compiled_module()
->weak_owning_instance()
->value()),
isolate());
} else {
code = WasmCodeWrapper(Handle<Code>(LookupCode(), isolate()));
offset = static_cast<int>(pc() - code.GetCode()->instruction_start());
instance = Handle<WasmInstanceObject>(wasm_instance(), isolate());
}
FrameSummary::WasmCompiledFrameSummary summary(
isolate(), instance, code, offset, at_to_number_conversion());
functions->push_back(summary);
@ -1690,10 +1777,21 @@ bool WasmCompiledFrame::at_to_number_conversion() const {
// Check whether our callee is a WASM_TO_JS frame, and this frame is at the
// ToNumber conversion call.
Address callee_pc = reinterpret_cast<Address>(this->callee_pc());
Code* code = callee_pc ? isolate()->FindCodeObject(callee_pc) : nullptr;
if (!code || code->kind() != Code::WASM_TO_JS_FUNCTION) return false;
int offset = static_cast<int>(callee_pc - code->instruction_start());
int pos = AbstractCode::cast(code)->SourcePosition(offset);
int pos = -1;
if (FLAG_wasm_jit_to_native) {
wasm::WasmCode* code =
callee_pc ? isolate()->wasm_code_manager()->LookupCode(callee_pc)
: nullptr;
if (!code || code->kind() != wasm::WasmCode::WasmToJsWrapper) return false;
int offset = static_cast<int>(callee_pc - code->instructions().start());
pos = FrameSummary::WasmCompiledFrameSummary::GetWasmSourcePosition(code,
offset);
} else {
Code* code = callee_pc ? isolate()->FindCodeObject(callee_pc) : nullptr;
if (!code || code->kind() != Code::WASM_TO_JS_FUNCTION) return false;
int offset = static_cast<int>(callee_pc - code->instruction_start());
pos = AbstractCode::cast(code)->SourcePosition(offset);
}
DCHECK(pos == 0 || pos == 1);
// The imported call has position 0, ToNumber has position 1.
return !!pos;
@ -1701,11 +1799,26 @@ bool WasmCompiledFrame::at_to_number_conversion() const {
int WasmCompiledFrame::LookupExceptionHandlerInTable(int* stack_slots) {
DCHECK_NOT_NULL(stack_slots);
Code* code = LookupCode();
HandlerTable* table = HandlerTable::cast(code->handler_table());
int pc_offset = static_cast<int>(pc() - code->entry());
*stack_slots = code->stack_slots();
return table->LookupReturn(pc_offset);
if (!FLAG_wasm_jit_to_native) {
Code* code = LookupCode();
HandlerTable* table = HandlerTable::cast(code->handler_table());
int pc_offset = static_cast<int>(pc() - code->entry());
*stack_slots = code->stack_slots();
return table->LookupReturn(pc_offset);
}
wasm::WasmCode* code = isolate()->wasm_code_manager()->LookupCode(pc());
if (!code->IsAnonymous()) {
Object* table_entry =
code->owner()->compiled_module()->ptr_to_handler_table()->get(
code->index());
if (table_entry->IsHandlerTable()) {
HandlerTable* table = HandlerTable::cast(table_entry);
int pc_offset = static_cast<int>(pc() - code->instructions().start());
*stack_slots = static_cast<int>(code->stack_slots());
return table->LookupReturn(pc_offset);
}
}
return -1;
}
void WasmInterpreterEntryFrame::Iterate(RootVisitor* v) const {
@ -1736,11 +1849,19 @@ void WasmInterpreterEntryFrame::Summarize(
}
Code* WasmInterpreterEntryFrame::unchecked_code() const {
return isolate()->FindCodeObject(pc());
if (FLAG_wasm_jit_to_native) {
UNIMPLEMENTED();
} else {
return isolate()->FindCodeObject(pc());
}
}
WasmInstanceObject* WasmInterpreterEntryFrame::wasm_instance() const {
WasmInstanceObject* ret = WasmInstanceObject::GetOwningInstance(LookupCode());
WasmInstanceObject* ret =
FLAG_wasm_jit_to_native
? WasmInstanceObject::GetOwningInstance(
isolate()->wasm_code_manager()->LookupCode(pc()))
: WasmInstanceObject::GetOwningInstanceGC(LookupCode());
// This is a live stack frame, there must be a live wasm instance available.
DCHECK_NOT_NULL(ret);
return ret;
@ -1965,15 +2086,22 @@ void JavaScriptFrame::Iterate(RootVisitor* v) const {
}
void InternalFrame::Iterate(RootVisitor* v) const {
Code* code = LookupCode();
IteratePc(v, pc_address(), constant_pool_address(), code);
// Internal frames typically do not receive any arguments, hence their stack
// only contains tagged pointers.
// We are misusing the has_tagged_params flag here to tell us whether
// the full stack frame contains only tagged pointers or only raw values.
// This is used for the WasmCompileLazy builtin, where we actually pass
// untagged arguments and also store untagged values on the stack.
if (code->has_tagged_params()) IterateExpressions(v);
wasm::WasmCode* wasm_code =
FLAG_wasm_jit_to_native ? isolate()->wasm_code_manager()->LookupCode(pc())
: nullptr;
if (wasm_code != nullptr) {
DCHECK(wasm_code->kind() == wasm::WasmCode::LazyStub);
} else {
Code* code = LookupCode();
IteratePc(v, pc_address(), constant_pool_address(), code);
// Internal frames typically do not receive any arguments, hence their stack
// only contains tagged pointers.
// We are misusing the has_tagged_params flag here to tell us whether
// the full stack frame contains only tagged pointers or only raw values.
// This is used for the WasmCompileLazy builtin, where we actually pass
// untagged arguments and also store untagged values on the stack.
if (code->has_tagged_params()) IterateExpressions(v);
}
}
// -------------------------------------------------------------------------

View File

@ -14,6 +14,9 @@
namespace v8 {
namespace internal {
namespace wasm {
class WasmCode;
}
class AbstractCode;
class Debug;
@ -526,15 +529,17 @@ class FrameSummary BASE_EMBEDDED {
class WasmCompiledFrameSummary : public WasmFrameSummary {
public:
WasmCompiledFrameSummary(Isolate*, Handle<WasmInstanceObject>, Handle<Code>,
int code_offset, bool at_to_number_conversion);
WasmCompiledFrameSummary(Isolate*, Handle<WasmInstanceObject>,
WasmCodeWrapper, int code_offset,
bool at_to_number_conversion);
uint32_t function_index() const;
Handle<Code> code() const { return code_; }
WasmCodeWrapper code() const { return code_; }
int code_offset() const { return code_offset_; }
int byte_offset() const;
static int GetWasmSourcePosition(const wasm::WasmCode* code, int offset);
private:
Handle<Code> code_;
WasmCodeWrapper const code_;
int code_offset_;
};

View File

@ -177,6 +177,7 @@ const int kElidedFrameSlots = 0;
#endif
const int kDoubleSizeLog2 = 3;
const size_t kMaxWasmCodeMemory = 256 * MB;
#if V8_HOST_ARCH_64_BIT
const int kPointerSizeLog2 = 3;

View File

@ -54,6 +54,7 @@
#include "src/visitors.h"
#include "src/vm-state-inl.h"
#include "src/wasm/compilation-manager.h"
#include "src/wasm/wasm-heap.h"
#include "src/wasm/wasm-objects.h"
#include "src/zone/accounting-allocator.h"
@ -427,6 +428,10 @@ class FrameArrayBuilder {
// Handle a WASM compiled frame.
//====================================================================
const auto& summary = summ.AsWasmCompiled();
if (!summary.code().IsCodeObject() &&
summary.code().GetWasmCode()->kind() != wasm::WasmCode::Function) {
continue;
}
Handle<WasmInstanceObject> instance = summary.wasm_instance();
int flags = 0;
if (instance->compiled_module()->is_asm_js()) {
@ -439,9 +444,8 @@ class FrameArrayBuilder {
}
elements_ = FrameArray::AppendWasmFrame(
elements_, instance, summary.function_index(),
Handle<AbstractCode>::cast(summary.code()), summary.code_offset(),
flags);
elements_, instance, summary.function_index(), summary.code(),
summary.code_offset(), flags);
} else if (summ.IsWasmInterpreted()) {
//====================================================================
// Handle a WASM interpreted frame.
@ -450,9 +454,9 @@ class FrameArrayBuilder {
Handle<WasmInstanceObject> instance = summary.wasm_instance();
int flags = FrameArray::kIsWasmInterpretedFrame;
DCHECK(!instance->compiled_module()->is_asm_js());
elements_ = FrameArray::AppendWasmFrame(
elements_, instance, summary.function_index(),
Handle<AbstractCode>::null(), summary.byte_offset(), flags);
elements_ = FrameArray::AppendWasmFrame(elements_, instance,
summary.function_index(), {},
summary.byte_offset(), flags);
}
}
}
@ -1295,9 +1299,17 @@ Object* Isolate::UnwindAndFindHandler() {
trap_handler::SetThreadInWasm();
set_wasm_caught_exception(exception);
Code* code = frame->LookupCode();
return FoundHandler(nullptr, code->instruction_start(), offset,
code->constant_pool(), return_sp, frame->fp());
if (FLAG_wasm_jit_to_native) {
wasm::WasmCode* wasm_code =
wasm_code_manager()->LookupCode(frame->pc());
return FoundHandler(nullptr, wasm_code->instructions().start(),
offset, wasm_code->constant_pool(), return_sp,
frame->fp());
} else {
Code* code = frame->LookupCode();
return FoundHandler(nullptr, code->instruction_start(), offset,
code->constant_pool(), return_sp, frame->fp());
}
}
case StackFrame::OPTIMIZED: {
@ -1673,9 +1685,19 @@ bool Isolate::ComputeLocationFromStackTrace(MessageLocation* target,
Handle<WasmCompiledModule> compiled_module(
WasmInstanceObject::cast(elements->WasmInstance(i))
->compiled_module());
int func_index = elements->WasmFunctionIndex(i)->value();
uint32_t func_index =
static_cast<uint32_t>(elements->WasmFunctionIndex(i)->value());
int code_offset = elements->Offset(i)->value();
int byte_offset = elements->Code(i)->SourcePosition(code_offset);
// TODO(titzer): store a reference to the code object in FrameArray;
// a second lookup here could lead to inconsistency.
int byte_offset =
FLAG_wasm_jit_to_native
? FrameSummary::WasmCompiledFrameSummary::GetWasmSourcePosition(
compiled_module->GetNativeModule()->GetCode(func_index),
code_offset)
: elements->Code(i)->SourcePosition(code_offset);
bool is_at_number_conversion =
elements->IsAsmJsWasmFrame(i) &&
elements->Flags(i)->value() & FrameArray::kAsmJsAtNumberConversion;
@ -2815,6 +2837,17 @@ bool Isolate::Init(StartupDeserializer* des) {
return false;
}
// Setup the wasm code manager. Currently, there's one per Isolate.
if (!wasm_code_manager_) {
size_t max_code_size = kMaxWasmCodeMemory;
if (kRequiresCodeRange) {
max_code_size = std::min(max_code_size,
heap_.memory_allocator()->code_range()->size());
}
wasm_code_manager_.reset(new wasm::WasmCodeManager(
reinterpret_cast<v8::Isolate*>(this), max_code_size));
}
// Initialize the interface descriptors ahead of time.
#define INTERFACE_DESCRIPTOR(Name, ...) \
{ Name##Descriptor(this); }
@ -3854,6 +3887,10 @@ void Isolate::PrintWithTimestamp(const char* format, ...) {
va_end(arguments);
}
wasm::WasmCodeManager* Isolate::wasm_code_manager() {
return wasm_code_manager_.get();
}
bool StackLimitCheck::JsHasOverflowed(uintptr_t gap) const {
StackGuard* stack_guard = isolate_->stack_guard();
#ifdef USE_SIMULATOR

View File

@ -110,6 +110,7 @@ class Interpreter;
namespace wasm {
class CompilationManager;
class WasmCodeManager;
}
#define RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate) \
@ -905,6 +906,7 @@ class Isolate {
}
StackGuard* stack_guard() { return &stack_guard_; }
Heap* heap() { return &heap_; }
V8_EXPORT_PRIVATE wasm::WasmCodeManager* wasm_code_manager();
StubCache* load_stub_cache() { return load_stub_cache_; }
StubCache* store_stub_cache() { return store_stub_cache_; }
DeoptimizerData* deoptimizer_data() { return deoptimizer_data_; }
@ -1652,6 +1654,8 @@ class Isolate {
size_t elements_deletion_counter_ = 0;
std::unique_ptr<wasm::WasmCodeManager> wasm_code_manager_;
// The top entry of the v8::Context::BackupIncumbentScope stack.
const v8::Context::BackupIncumbentScope* top_backup_incumbent_scope_ =
nullptr;

View File

@ -12,6 +12,7 @@
#include "src/keys.h"
#include "src/objects/frame-array-inl.h"
#include "src/string-builder.h"
#include "src/wasm/wasm-heap.h"
#include "src/wasm/wasm-objects.h"
namespace v8 {
@ -649,9 +650,18 @@ void WasmStackFrame::FromFrameArray(Isolate* isolate, Handle<FrameArray> array,
wasm_instance_ = handle(array->WasmInstance(frame_ix), isolate);
wasm_func_index_ = array->WasmFunctionIndex(frame_ix)->value();
if (array->IsWasmInterpretedFrame(frame_ix)) {
code_ = Handle<AbstractCode>::null();
code_ = {};
} else {
code_ = handle(array->Code(frame_ix), isolate);
code_ =
FLAG_wasm_jit_to_native
? WasmCodeWrapper(
wasm_instance_->compiled_module()->GetNativeModule()->GetCode(
wasm_func_index_))
: WasmCodeWrapper(handle(
Code::cast(
wasm_instance_->compiled_module()->code_table()->get(
wasm_func_index_)),
isolate));
}
offset_ = array->Offset(frame_ix)->value();
}
@ -712,7 +722,13 @@ MaybeHandle<String> WasmStackFrame::ToString() {
}
int WasmStackFrame::GetPosition() const {
return IsInterpreted() ? offset_ : code_->SourcePosition(offset_);
return IsInterpreted()
? offset_
: (code_.IsCodeObject()
? Handle<AbstractCode>::cast(code_.GetCode())
->SourcePosition(offset_)
: FrameSummary::WasmCompiledFrameSummary::
GetWasmSourcePosition(code_.GetWasmCode(), offset_));
}
Handle<Object> WasmStackFrame::Null() const {
@ -759,7 +775,11 @@ Handle<Object> AsmJsWasmStackFrame::GetScriptNameOrSourceUrl() {
int AsmJsWasmStackFrame::GetPosition() const {
DCHECK_LE(0, offset_);
int byte_offset = code_->SourcePosition(offset_);
int byte_offset =
code_.IsCodeObject()
? Handle<AbstractCode>::cast(code_.GetCode())->SourcePosition(offset_)
: FrameSummary::WasmCompiledFrameSummary::GetWasmSourcePosition(
code_.GetWasmCode(), offset_);
Handle<WasmCompiledModule> compiled_module(wasm_instance_->compiled_module(),
isolate_);
DCHECK_LE(0, byte_offset);

View File

@ -13,9 +13,13 @@
#include <memory>
#include "src/handles.h"
#include "src/wasm/wasm-code-wrapper.h"
namespace v8 {
namespace internal {
namespace wasm {
class WasmCode;
}
// Forward declarations.
class AbstractCode;
@ -161,7 +165,7 @@ class WasmStackFrame : public StackFrameBase {
Handle<WasmInstanceObject> wasm_instance_;
uint32_t wasm_func_index_;
Handle<AbstractCode> code_; // null handle for interpreted frames.
WasmCodeWrapper code_; // null for interpreted frames.
int offset_;
private:

View File

@ -10344,14 +10344,19 @@ Handle<FrameArray> FrameArray::AppendJSFrame(Handle<FrameArray> in,
// static
Handle<FrameArray> FrameArray::AppendWasmFrame(
Handle<FrameArray> in, Handle<WasmInstanceObject> wasm_instance,
int wasm_function_index, Handle<AbstractCode> code, int offset, int flags) {
int wasm_function_index, WasmCodeWrapper code, int offset, int flags) {
const int frame_count = in->FrameCount();
const int new_length = LengthFor(frame_count + 1);
Handle<FrameArray> array = EnsureSpace(in, new_length);
array->SetWasmInstance(frame_count, *wasm_instance);
array->SetWasmFunctionIndex(frame_count, Smi::FromInt(wasm_function_index));
// code will be a null handle for interpreted wasm frames.
if (!code.is_null()) array->SetCode(frame_count, *code);
if (!code.IsCodeObject()) {
array->SetIsWasmInterpreterFrame(frame_count, Smi::FromInt(code.is_null()));
} else {
if (!code.is_null())
array->SetCode(frame_count, AbstractCode::cast(*code.GetCode()));
}
array->SetOffset(frame_count, Smi::FromInt(offset));
array->SetFlags(frame_count, Smi::FromInt(flags));
array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));

View File

@ -160,6 +160,7 @@ class Code : public HeapObject {
DECL_ACCESSORS(source_position_table, Object)
inline ByteArray* SourcePositionTable() const;
// TODO(mtrofin): remove when we don't need FLAG_wasm_jit_to_native
// [protected instructions]: Array containing list of protected
// instructions and corresponding landing pad offset.
DECL_ACCESSORS(protected_instructions, FixedArray)

View File

@ -20,6 +20,7 @@ class Handle;
#define FRAME_ARRAY_FIELD_LIST(V) \
V(WasmInstance, WasmInstanceObject) \
V(WasmFunctionIndex, Smi) \
V(IsWasmInterpreterFrame, Smi) \
V(Receiver, Object) \
V(Function, JSFunction) \
V(Code, AbstractCode) \
@ -59,8 +60,7 @@ class FrameArray : public FixedArray {
int flags);
static Handle<FrameArray> AppendWasmFrame(
Handle<FrameArray> in, Handle<WasmInstanceObject> wasm_instance,
int wasm_function_index, Handle<AbstractCode> code, int offset,
int flags);
int wasm_function_index, WasmCodeWrapper code, int offset, int flags);
DECL_CAST(FrameArray)
@ -74,6 +74,7 @@ class FrameArray : public FixedArray {
static const int kWasmInstanceOffset = 0;
static const int kWasmFunctionIndexOffset = 1;
static const int kIsWasmInterpreterFrameOffset = 2;
static const int kReceiverOffset = 0;
static const int kFunctionOffset = 1;

View File

@ -21,6 +21,7 @@
#include "src/wasm/memory-tracing.h"
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-objects-inl.h"
#include "src/wasm/wasm-serialization.h"
namespace {
struct WasmCompileControls {
@ -481,48 +482,100 @@ RUNTIME_FUNCTION(Runtime_CheckWasmWrapperElision) {
CONVERT_ARG_HANDLE_CHECKED(Smi, type, 1);
Handle<Code> export_code = handle(function->code());
CHECK(export_code->kind() == Code::JS_TO_WASM_FUNCTION);
int const mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
int const mask =
RelocInfo::ModeMask(FLAG_wasm_jit_to_native ? RelocInfo::JS_TO_WASM_CALL
: RelocInfo::CODE_TARGET);
// check the type of the $export_fct
Handle<Code> export_fct;
wasm::WasmCode* export_fct = nullptr;
Handle<Code> export_fct_handle;
wasm::WasmCode* intermediate_fct = nullptr;
Handle<Code> intermediate_fct_handle;
int count = 0;
for (RelocIterator it(*export_code, mask); !it.done(); it.next()) {
RelocInfo* rinfo = it.rinfo();
Address target_address = rinfo->target_address();
Code* target = Code::GetCodeFromTargetAddress(target_address);
if (target->kind() == Code::WASM_FUNCTION) {
++count;
export_fct = handle(target);
Address target_address = FLAG_wasm_jit_to_native
? rinfo->js_to_wasm_address()
: rinfo->target_address();
if (FLAG_wasm_jit_to_native) {
wasm::WasmCode* target =
isolate->wasm_code_manager()->LookupCode(target_address);
if (target->kind() == wasm::WasmCode::Function) {
++count;
export_fct = target;
}
} else {
Code* target = Code::GetCodeFromTargetAddress(target_address);
if (target->kind() == Code::WASM_FUNCTION) {
++count;
export_fct_handle = handle(target);
}
}
}
CHECK_EQ(count, 1);
// check the type of the intermediate_fct
Handle<Code> intermediate_fct;
count = 0;
for (RelocIterator it(*export_fct, mask); !it.done(); it.next()) {
RelocInfo* rinfo = it.rinfo();
Address target_address = rinfo->target_address();
Code* target = Code::GetCodeFromTargetAddress(target_address);
if (target->kind() == Code::WASM_FUNCTION) {
++count;
intermediate_fct = handle(target);
if (FLAG_wasm_jit_to_native) {
for (RelocIterator it(export_fct->instructions(), export_fct->reloc_info(),
export_fct->constant_pool(),
RelocInfo::ModeMask(RelocInfo::WASM_CALL));
!it.done(); it.next()) {
RelocInfo* rinfo = it.rinfo();
Address target_address = rinfo->target_address();
wasm::WasmCode* target =
isolate->wasm_code_manager()->LookupCode(target_address);
if (target->kind() == wasm::WasmCode::Function) {
++count;
intermediate_fct = target;
}
}
} else {
count = 0;
for (RelocIterator it(*export_fct_handle, mask); !it.done(); it.next()) {
RelocInfo* rinfo = it.rinfo();
Address target_address = rinfo->target_address();
Code* target = Code::GetCodeFromTargetAddress(target_address);
if (target->kind() == Code::WASM_FUNCTION) {
++count;
intermediate_fct_handle = handle(target);
}
}
}
CHECK_EQ(count, 1);
// Check the type of the imported exported function, it should be also a wasm
// function in our case.
Handle<Code> imported_fct;
CHECK(type->value() == 0 || type->value() == 1);
Code::Kind target_kind = type->value() == 0 ? Code::WASM_TO_WASM_FUNCTION
: Code::WASM_TO_JS_FUNCTION;
count = 0;
for (RelocIterator it(*intermediate_fct, mask); !it.done(); it.next()) {
RelocInfo* rinfo = it.rinfo();
Address target_address = rinfo->target_address();
Code* target = Code::GetCodeFromTargetAddress(target_address);
if (target->kind() == target_kind) {
++count;
imported_fct = handle(target);
if (FLAG_wasm_jit_to_native) {
wasm::WasmCode::Kind target_kind = type->value() == 0
? wasm::WasmCode::WasmToWasmWrapper
: wasm::WasmCode::WasmToJsWrapper;
for (RelocIterator it(intermediate_fct->instructions(),
intermediate_fct->reloc_info(),
intermediate_fct->constant_pool(),
RelocInfo::ModeMask(RelocInfo::WASM_CALL));
!it.done(); it.next()) {
RelocInfo* rinfo = it.rinfo();
Address target_address = rinfo->target_address();
wasm::WasmCode* target =
isolate->wasm_code_manager()->LookupCode(target_address);
if (target->kind() == target_kind) {
++count;
}
}
} else {
Code::Kind target_kind = type->value() == 0 ? Code::WASM_TO_WASM_FUNCTION
: Code::WASM_TO_JS_FUNCTION;
count = 0;
for (RelocIterator it(*intermediate_fct_handle, mask); !it.done();
it.next()) {
RelocInfo* rinfo = it.rinfo();
Address target_address = rinfo->target_address();
Code* target = Code::GetCodeFromTargetAddress(target_address);
if (target->kind() == target_kind) {
++count;
}
}
}
CHECK_LE(count, 1);
@ -940,13 +993,24 @@ RUNTIME_FUNCTION(Runtime_SerializeWasmModule) {
CONVERT_ARG_HANDLE_CHECKED(WasmModuleObject, module_obj, 0);
Handle<WasmCompiledModule> orig(module_obj->compiled_module());
std::unique_ptr<ScriptData> data =
WasmCompiledModuleSerializer::SerializeWasmModule(isolate, orig);
void* buff = isolate->array_buffer_allocator()->Allocate(data->length());
Handle<JSArrayBuffer> ret = isolate->factory()->NewJSArrayBuffer();
JSArrayBuffer::Setup(ret, isolate, false, buff, data->length());
memcpy(buff, data->data(), data->length());
return *ret;
if (FLAG_wasm_jit_to_native) {
std::pair<std::unique_ptr<byte[]>, size_t> serialized_module =
wasm::NativeModuleSerializer::SerializeWholeModule(isolate, orig);
int data_size = static_cast<int>(serialized_module.second);
void* buff = isolate->array_buffer_allocator()->Allocate(data_size);
Handle<JSArrayBuffer> ret = isolate->factory()->NewJSArrayBuffer();
JSArrayBuffer::Setup(ret, isolate, false, buff, data_size);
memcpy(buff, serialized_module.first.get(), data_size);
return *ret;
} else {
std::unique_ptr<ScriptData> data =
WasmCompiledModuleSerializer::SerializeWasmModule(isolate, orig);
void* buff = isolate->array_buffer_allocator()->Allocate(data->length());
Handle<JSArrayBuffer> ret = isolate->factory()->NewJSArrayBuffer();
JSArrayBuffer::Setup(ret, isolate, false, buff, data->length());
memcpy(buff, data->data(), data->length());
return *ret;
}
}
// Take an array buffer and attempt to reconstruct a compiled wasm module.
@ -958,22 +1022,31 @@ RUNTIME_FUNCTION(Runtime_DeserializeWasmModule) {
CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, wire_bytes, 1);
Address mem_start = static_cast<Address>(buffer->backing_store());
int mem_size = static_cast<int>(buffer->byte_length()->Number());
size_t mem_size = static_cast<size_t>(buffer->byte_length()->Number());
// DeserializeWasmModule will allocate. We assume JSArrayBuffer doesn't
// get relocated.
ScriptData sc(mem_start, mem_size);
bool already_external = wire_bytes->is_external();
if (!already_external) {
wire_bytes->set_is_external(true);
isolate->heap()->UnregisterArrayBuffer(*wire_bytes);
}
MaybeHandle<FixedArray> maybe_compiled_module =
WasmCompiledModuleSerializer::DeserializeWasmModule(
isolate, &sc,
Vector<const uint8_t>(
reinterpret_cast<uint8_t*>(wire_bytes->backing_store()),
static_cast<int>(wire_bytes->byte_length()->Number())));
MaybeHandle<FixedArray> maybe_compiled_module;
if (FLAG_wasm_jit_to_native) {
maybe_compiled_module =
wasm::NativeModuleDeserializer::DeserializeFullBuffer(
isolate, {mem_start, mem_size},
Vector<const uint8_t>(
reinterpret_cast<uint8_t*>(wire_bytes->backing_store()),
static_cast<int>(wire_bytes->byte_length()->Number())));
} else {
ScriptData sc(mem_start, static_cast<int>(mem_size));
maybe_compiled_module = WasmCompiledModuleSerializer::DeserializeWasmModule(
isolate, &sc,
Vector<const uint8_t>(
reinterpret_cast<uint8_t*>(wire_bytes->backing_store()),
static_cast<int>(wire_bytes->byte_length()->Number())));
}
if (!already_external) {
wire_bytes->set_is_external(false);
isolate->heap()->RegisterNewArrayBuffer(*wire_bytes);
@ -1086,8 +1159,15 @@ RUNTIME_FUNCTION(Runtime_IsLiftoffFunction) {
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
CHECK(WasmExportedFunction::IsWasmExportedFunction(*function));
Handle<Code> wasm_code = WasmExportedFunction::cast(*function)->GetWasmCode();
return isolate->heap()->ToBoolean(!wasm_code->is_turbofanned());
WasmCodeWrapper wrapper =
WasmExportedFunction::cast(*function)->GetWasmCode();
if (!wrapper.IsCodeObject()) {
const wasm::WasmCode* wasm_code = wrapper.GetWasmCode();
return isolate->heap()->ToBoolean(wasm_code->is_liftoff());
} else {
Handle<Code> wasm_code = wrapper.GetCode();
return isolate->heap()->ToBoolean(!wasm_code->is_turbofanned());
}
}
RUNTIME_FUNCTION(Runtime_CompleteInobjectSlackTracking) {

View File

@ -16,6 +16,7 @@
#include "src/trap-handler/trap-handler.h"
#include "src/v8memory.h"
#include "src/wasm/module-compiler.h"
#include "src/wasm/wasm-heap.h"
#include "src/wasm/wasm-objects.h"
#include "src/wasm/wasm-opcodes.h"
@ -29,12 +30,18 @@ WasmInstanceObject* GetWasmInstanceOnStackTop(Isolate* isolate) {
const Address entry = Isolate::c_entry_fp(isolate->thread_local_top());
Address pc =
Memory::Address_at(entry + StandardFrameConstants::kCallerPCOffset);
Code* code = isolate->inner_pointer_to_code_cache()->GetCacheEntry(pc)->code;
WasmInstanceObject* owning_instance =
WasmInstanceObject::GetOwningInstance(code);
WasmInstanceObject* owning_instance = nullptr;
if (FLAG_wasm_jit_to_native) {
owning_instance = WasmInstanceObject::GetOwningInstance(
isolate->wasm_code_manager()->LookupCode(pc));
} else {
owning_instance = WasmInstanceObject::GetOwningInstanceGC(
isolate->inner_pointer_to_code_cache()->GetCacheEntry(pc)->code);
}
CHECK_NOT_NULL(owning_instance);
return owning_instance;
}
Context* GetWasmContextOnStackTop(Isolate* isolate) {
return GetWasmInstanceOnStackTop(isolate)
->compiled_module()
@ -287,7 +294,15 @@ RUNTIME_FUNCTION(Runtime_WasmCompileLazy) {
DCHECK_EQ(0, args.length());
HandleScope scope(isolate);
return *wasm::CompileLazy(isolate);
if (FLAG_wasm_jit_to_native) {
Address new_func = wasm::CompileLazy(isolate);
// The alternative to this is having 2 lazy compile builtins. The builtins
// are part of the snapshot, so the flag has no impact on the codegen there.
return reinterpret_cast<Object*>(new_func - Code::kHeaderSize +
kHeapObjectTag);
} else {
return *wasm::CompileLazyOnGCHeap(isolate);
}
}
} // namespace internal

View File

@ -115,7 +115,7 @@ void ValidateCodeObjects() {
CodeProtectionInfo* CreateHandlerData(
void* base, size_t size, size_t num_protected_instructions,
ProtectedInstructionData* protected_instructions) {
const ProtectedInstructionData* protected_instructions) {
const size_t alloc_size = HandlerDataSize(num_protected_instructions);
CodeProtectionInfo* data =
reinterpret_cast<CodeProtectionInfo*>(malloc(alloc_size));
@ -143,9 +143,9 @@ void UpdateHandlerDataCodePointer(int index, void* base) {
data->base = base;
}
int RegisterHandlerData(void* base, size_t size,
size_t num_protected_instructions,
ProtectedInstructionData* protected_instructions) {
int RegisterHandlerData(
void* base, size_t size, size_t num_protected_instructions,
const ProtectedInstructionData* protected_instructions) {
// TODO(eholk): in debug builds, make sure this data isn't already registered.
CodeProtectionInfo* data = CreateHandlerData(

View File

@ -50,9 +50,11 @@ void UpdateHandlerDataCodePointer(int index, void* base);
/// UpdateHandlerDataCodePointer and ReleaseHandlerData, or -1 on failure.
int RegisterHandlerData(void* base, size_t size,
size_t num_protected_instructions,
ProtectedInstructionData* protected_instructions);
const ProtectedInstructionData* protected_instructions);
/// Removes the data from the master list and frees any memory, if necessary.
/// TODO(mtrofin): once FLAG_wasm_jit_to_native is not needed, we can switch
/// to using size_t for index and not need kInvalidIndex.
void ReleaseHandlerData(int index);
#if V8_OS_WIN

View File

@ -1462,6 +1462,8 @@
'wasm/wasm-api.h',
'wasm/wasm-code-specialization.cc',
'wasm/wasm-code-specialization.h',
'wasm/wasm-code-wrapper.cc',
'wasm/wasm-code-wrapper.h',
'wasm/wasm-debug.cc',
'wasm/wasm-external-refs.cc',
'wasm/wasm-external-refs.h',
@ -1485,6 +1487,8 @@
'wasm/wasm-opcodes.h',
'wasm/wasm-result.cc',
'wasm/wasm-result.h',
'wasm/wasm-serialization.cc',
'wasm/wasm-serialization.h',
'wasm/wasm-text.cc',
'wasm/wasm-text.h',
'wasm/wasm-value.h',

View File

@ -21,6 +21,7 @@
#include "src/wasm/module-compiler.h"
#include "src/wasm/wasm-objects-inl.h"
#include "src/wasm/wasm-result.h"
#include "src/wasm/wasm-serialization.h"
namespace v8 {
namespace internal {
@ -855,13 +856,20 @@ Maybe<bool> ValueSerializer::WriteWasmModule(Handle<WasmModuleObject> object) {
String::WriteToFlat(*wire_bytes, destination, 0, wire_bytes_length);
}
std::unique_ptr<ScriptData> script_data =
WasmCompiledModuleSerializer::SerializeWasmModule(isolate_,
compiled_part);
int script_data_length = script_data->length();
WriteVarint<uint32_t>(script_data_length);
WriteRawBytes(script_data->data(), script_data_length);
if (FLAG_wasm_jit_to_native) {
std::pair<std::unique_ptr<byte[]>, size_t> serialized_module =
wasm::NativeModuleSerializer::SerializeWholeModule(isolate_,
compiled_part);
WriteVarint<uint32_t>(static_cast<uint32_t>(serialized_module.second));
WriteRawBytes(serialized_module.first.get(), serialized_module.second);
} else {
std::unique_ptr<ScriptData> script_data =
WasmCompiledModuleSerializer::SerializeWasmModule(isolate_,
compiled_part);
int script_data_length = script_data->length();
WriteVarint<uint32_t>(script_data_length);
WriteRawBytes(script_data->data(), script_data_length);
}
return ThrowIfOutOfMemory();
}
@ -1708,15 +1716,25 @@ MaybeHandle<JSObject> ValueDeserializer::ReadWasmModule() {
}
// Try to deserialize the compiled module first.
ScriptData script_data(compiled_bytes.start(), compiled_bytes.length());
Handle<FixedArray> compiled_part;
MaybeHandle<JSObject> result;
if (WasmCompiledModuleSerializer::DeserializeWasmModule(
isolate_, &script_data, wire_bytes)
.ToHandle(&compiled_part)) {
result = WasmModuleObject::New(
isolate_, Handle<WasmCompiledModule>::cast(compiled_part));
if (FLAG_wasm_jit_to_native) {
if (wasm::NativeModuleDeserializer::DeserializeFullBuffer(
isolate_, compiled_bytes, wire_bytes)
.ToHandle(&compiled_part)) {
result = WasmModuleObject::New(
isolate_, Handle<WasmCompiledModule>::cast(compiled_part));
}
} else {
ScriptData script_data(compiled_bytes.start(), compiled_bytes.length());
if (WasmCompiledModuleSerializer::DeserializeWasmModule(
isolate_, &script_data, wire_bytes)
.ToHandle(&compiled_part)) {
result = WasmModuleObject::New(
isolate_, Handle<WasmCompiledModule>::cast(compiled_part));
}
}
if (result.is_null()) {
wasm::ErrorThrower thrower(isolate_, "ValueDeserializer::ReadWasmModule");
result = wasm::SyncCompile(isolate_, &thrower,
wasm::ModuleWireBytes(wire_bytes));

View File

@ -123,7 +123,7 @@ class Vector {
}
inline Vector<T> operator+(size_t offset) {
DCHECK_LT(offset, length_);
DCHECK_LE(offset, length_);
return Vector<T>(start_ + offset, length_ - offset);
}

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,7 @@ namespace internal {
namespace wasm {
class ModuleCompiler;
class WasmCode;
V8_EXPORT_PRIVATE bool SyncValidate(Isolate* isolate,
const ModuleWireBytes& bytes);
@ -53,6 +54,9 @@ V8_EXPORT_PRIVATE void CompileJsToWasmWrappers(
Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
Counters* counters);
V8_EXPORT_PRIVATE Handle<Script> CreateWasmScript(
Isolate* isolate, const ModuleWireBytes& wire_bytes);
// Triggered by the WasmCompileLazy builtin.
// Walks the stack (top three frames) to determine the wasm instance involved
// and which function to compile.
@ -62,7 +66,8 @@ V8_EXPORT_PRIVATE void CompileJsToWasmWrappers(
// an error occurred. In the latter case, a pending exception has been set,
// which will be triggered when returning from the runtime function, i.e. the
// Illegal builtin will never be called.
Handle<Code> CompileLazy(Isolate* isolate);
Address CompileLazy(Isolate* isolate);
Handle<Code> CompileLazyOnGCHeap(Isolate* isolate);
// This class orchestrates the lazy compilation of wasm functions. It is
// triggered by the WasmCompileLazy builtin.
@ -72,12 +77,24 @@ Handle<Code> CompileLazy(Isolate* isolate);
// logic to actually orchestrate parallel execution of wasm compilation jobs.
// TODO(clemensh): Implement concurrent lazy compilation.
class LazyCompilationOrchestrator {
void CompileFunction(Isolate*, Handle<WasmInstanceObject>, int func_index);
const WasmCode* CompileFunction(Isolate*, Handle<WasmInstanceObject>,
int func_index);
public:
Handle<Code> CompileLazy(Isolate*, Handle<WasmInstanceObject>,
Handle<Code> caller, int call_offset,
int exported_func_index, bool patch_caller);
Handle<Code> CompileLazyOnGCHeap(Isolate*, Handle<WasmInstanceObject>,
Handle<Code> caller, int call_offset,
int exported_func_index, bool patch_caller);
const wasm::WasmCode* CompileFromJsToWasm(Isolate*,
Handle<WasmInstanceObject>,
Handle<Code> caller,
uint32_t exported_func_index);
const wasm::WasmCode* CompileDirectCall(Isolate*, Handle<WasmInstanceObject>,
Maybe<uint32_t>,
const WasmCode* caller,
int call_offset);
const wasm::WasmCode* CompileIndirectCall(Isolate*,
Handle<WasmInstanceObject>,
uint32_t func_index);
};
// Encapsulates all the state and steps of an asynchronous compilation.

View File

@ -17,13 +17,13 @@ namespace v8 {
namespace internal {
namespace wasm {
int ExtractDirectCallIndex(wasm::Decoder& decoder, const byte* pc) {
uint32_t ExtractDirectCallIndex(wasm::Decoder& decoder, const byte* pc) {
DCHECK_EQ(static_cast<int>(kExprCallFunction), static_cast<int>(*pc));
decoder.Reset(pc + 1, pc + 6);
uint32_t call_idx = decoder.consume_u32v("call index");
DCHECK(decoder.ok());
DCHECK_GE(kMaxInt, call_idx);
return static_cast<int>(call_idx);
return call_idx;
}
namespace {
@ -43,6 +43,17 @@ int AdvanceSourcePositionTableIterator(SourcePositionTableIterator& iterator,
class PatchDirectCallsHelper {
public:
PatchDirectCallsHelper(WasmInstanceObject* instance, const WasmCode* code)
: source_pos_it(ByteArray::cast(
instance->compiled_module()->source_positions()->get(
static_cast<int>(code->index())))),
decoder(nullptr, nullptr) {
uint32_t func_index = code->index();
WasmCompiledModule* comp_mod = instance->compiled_module();
func_bytes = comp_mod->module_bytes()->GetChars() +
comp_mod->module()->functions[func_index].code.offset();
}
PatchDirectCallsHelper(WasmInstanceObject* instance, Code* code)
: source_pos_it(code->SourcePositionTable()), decoder(nullptr, nullptr) {
FixedArray* deopt_data = code->deoptimization_data();
@ -71,7 +82,8 @@ bool IsAtWasmDirectCallTarget(RelocIterator& it) {
} // namespace
CodeSpecialization::CodeSpecialization(Isolate* isolate, Zone* zone) {}
CodeSpecialization::CodeSpecialization(Isolate* isolate, Zone* zone)
: isolate_(isolate) {}
CodeSpecialization::~CodeSpecialization() {}
@ -102,11 +114,11 @@ bool CodeSpecialization::ApplyToWholeInstance(
WasmInstanceObject* instance, ICacheFlushMode icache_flush_mode) {
DisallowHeapAllocation no_gc;
WasmCompiledModule* compiled_module = instance->compiled_module();
NativeModule* native_module = compiled_module->GetNativeModule();
FixedArray* code_table = compiled_module->ptr_to_code_table();
WasmModule* module = compiled_module->module();
std::vector<WasmFunction>* wasm_functions =
&compiled_module->module()->functions;
DCHECK_EQ(wasm_functions->size(), code_table->length());
DCHECK_EQ(compiled_module->export_wrappers()->length(),
compiled_module->module()->num_exported_functions);
@ -116,9 +128,19 @@ bool CodeSpecialization::ApplyToWholeInstance(
// Patch all wasm functions.
for (int num_wasm_functions = static_cast<int>(wasm_functions->size());
func_index < num_wasm_functions; ++func_index) {
Code* wasm_function = Code::cast(code_table->get(func_index));
if (wasm_function->kind() != Code::WASM_FUNCTION) continue;
changed |= ApplyToWasmCode(wasm_function, icache_flush_mode);
WasmCodeWrapper wrapper;
if (FLAG_wasm_jit_to_native) {
const WasmCode* wasm_function = native_module->GetCode(func_index);
if (wasm_function->kind() != WasmCode::Function) {
continue;
}
wrapper = WasmCodeWrapper(wasm_function);
} else {
Code* wasm_function = Code::cast(code_table->get(func_index));
if (wasm_function->kind() != Code::WASM_FUNCTION) continue;
wrapper = WasmCodeWrapper(handle(wasm_function));
}
changed |= ApplyToWasmCode(wrapper, icache_flush_mode);
}
// Patch all exported functions (JS_TO_WASM_FUNCTION).
@ -132,7 +154,9 @@ bool CodeSpecialization::ApplyToWholeInstance(
// should match the instance we currently patch (instance).
if (!relocate_direct_calls_instance.is_null()) {
DCHECK_EQ(instance, *relocate_direct_calls_instance);
reloc_mode |= RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
reloc_mode |=
RelocInfo::ModeMask(FLAG_wasm_jit_to_native ? RelocInfo::JS_TO_WASM_CALL
: RelocInfo::CODE_TARGET);
}
if (!reloc_mode) return changed;
int wrapper_index = 0;
@ -149,7 +173,14 @@ bool CodeSpecialization::ApplyToWholeInstance(
new_wasm_context_address,
icache_flush_mode);
break;
case RelocInfo::JS_TO_WASM_CALL: {
DCHECK(FLAG_wasm_jit_to_native);
const WasmCode* new_code = native_module->GetCode(exp.index);
it.rinfo()->set_js_to_wasm_address(
nullptr, new_code->instructions().start(), SKIP_ICACHE_FLUSH);
} break;
case RelocInfo::CODE_TARGET: {
DCHECK(!FLAG_wasm_jit_to_native);
// Ignore calls to other builtins like ToNumber.
if (!IsAtWasmDirectCallTarget(it)) continue;
Code* new_code = Code::cast(code_table->get(exp.index));
@ -164,15 +195,19 @@ bool CodeSpecialization::ApplyToWholeInstance(
changed = true;
++wrapper_index;
}
DCHECK_EQ(code_table->length(), func_index);
DCHECK_EQ(module->functions.size(), func_index);
DCHECK_EQ(compiled_module->export_wrappers()->length(), wrapper_index);
return changed;
}
bool CodeSpecialization::ApplyToWasmCode(Code* code,
bool CodeSpecialization::ApplyToWasmCode(WasmCodeWrapper code,
ICacheFlushMode icache_flush_mode) {
DisallowHeapAllocation no_gc;
DCHECK_EQ(Code::WASM_FUNCTION, code->kind());
if (code.IsCodeObject()) {
DCHECK_EQ(Code::WASM_FUNCTION, code.GetCode()->kind());
} else {
DCHECK_EQ(wasm::WasmCode::Function, code.GetWasmCode()->kind());
}
bool patch_table_size = old_function_table_size || new_function_table_size;
bool reloc_direct_calls = !relocate_direct_calls_instance.is_null();
@ -183,16 +218,30 @@ bool CodeSpecialization::ApplyToWasmCode(Code* code,
if (cond) reloc_mode |= RelocInfo::ModeMask(mode);
};
add_mode(patch_table_size, RelocInfo::WASM_FUNCTION_TABLE_SIZE_REFERENCE);
add_mode(reloc_direct_calls, RelocInfo::CODE_TARGET);
if (code.IsCodeObject()) {
add_mode(reloc_direct_calls, RelocInfo::CODE_TARGET);
} else {
add_mode(reloc_direct_calls, RelocInfo::WASM_CALL);
}
add_mode(reloc_pointers, RelocInfo::WASM_GLOBAL_HANDLE);
base::Optional<PatchDirectCallsHelper> patch_direct_calls_helper;
bool changed = false;
for (RelocIterator it(code, reloc_mode); !it.done(); it.next()) {
NativeModule* native_module =
code.IsCodeObject() ? nullptr : code.GetWasmCode()->owner();
RelocIterator it =
code.IsCodeObject()
? RelocIterator(*code.GetCode(), reloc_mode)
: RelocIterator(code.GetWasmCode()->instructions(),
code.GetWasmCode()->reloc_info(),
code.GetWasmCode()->constant_pool(), reloc_mode);
for (; !it.done(); it.next()) {
RelocInfo::Mode mode = it.rinfo()->rmode();
switch (mode) {
case RelocInfo::CODE_TARGET: {
DCHECK(!FLAG_wasm_jit_to_native);
DCHECK(reloc_direct_calls);
// Skip everything which is not a wasm call (stack checks, traps, ...).
if (!IsAtWasmDirectCallTarget(it)) continue;
@ -201,10 +250,10 @@ bool CodeSpecialization::ApplyToWasmCode(Code* code,
// position iterator forward to that position to find the byte offset of
// the respective call. Then extract the call index from the module wire
// bytes to find the new compiled function.
size_t offset = it.rinfo()->pc() - code->instruction_start();
size_t offset = it.rinfo()->pc() - code.GetCode()->instruction_start();
if (!patch_direct_calls_helper) {
patch_direct_calls_helper.emplace(*relocate_direct_calls_instance,
code);
*code.GetCode());
}
int byte_pos = AdvanceSourcePositionTableIterator(
patch_direct_calls_helper->source_pos_it, offset);
@ -220,21 +269,44 @@ bool CodeSpecialization::ApplyToWasmCode(Code* code,
UPDATE_WRITE_BARRIER, icache_flush_mode);
changed = true;
} break;
case RelocInfo::WASM_CALL: {
DCHECK(FLAG_wasm_jit_to_native);
DCHECK(reloc_direct_calls);
// Iterate simultaneously over the relocation information and the source
// position table. For each call in the reloc info, move the source
// position iterator forward to that position to find the byte offset of
// the respective call. Then extract the call index from the module wire
// bytes to find the new compiled function.
size_t offset =
it.rinfo()->pc() - code.GetWasmCode()->instructions().start();
if (!patch_direct_calls_helper) {
patch_direct_calls_helper.emplace(*relocate_direct_calls_instance,
code.GetWasmCode());
}
int byte_pos = AdvanceSourcePositionTableIterator(
patch_direct_calls_helper->source_pos_it, offset);
uint32_t called_func_index = ExtractDirectCallIndex(
patch_direct_calls_helper->decoder,
patch_direct_calls_helper->func_bytes + byte_pos);
const WasmCode* new_code = native_module->GetCode(called_func_index);
it.rinfo()->set_wasm_call_address(
isolate_, new_code->instructions().start(), icache_flush_mode);
changed = true;
} break;
case RelocInfo::WASM_GLOBAL_HANDLE: {
DCHECK(reloc_pointers);
Address old_ptr = it.rinfo()->global_handle();
if (pointers_to_relocate.count(old_ptr) == 1) {
Address new_ptr = pointers_to_relocate[old_ptr];
it.rinfo()->set_global_handle(code->GetIsolate(), new_ptr,
icache_flush_mode);
it.rinfo()->set_global_handle(isolate_, new_ptr, icache_flush_mode);
changed = true;
}
} break;
case RelocInfo::WASM_FUNCTION_TABLE_SIZE_REFERENCE:
DCHECK(patch_table_size);
it.rinfo()->update_wasm_function_table_size_reference(
code->GetIsolate(), old_function_table_size,
new_function_table_size, icache_flush_mode);
isolate_, old_function_table_size, new_function_table_size,
icache_flush_mode);
changed = true;
break;
default:

View File

@ -14,7 +14,7 @@ namespace v8 {
namespace internal {
namespace wasm {
int ExtractDirectCallIndex(wasm::Decoder& decoder, const byte* pc);
uint32_t ExtractDirectCallIndex(wasm::Decoder& decoder, const byte* pc);
// Helper class to specialize wasm code for a specific instance, or to update
// code when memory / globals / tables change.
@ -43,9 +43,11 @@ class CodeSpecialization {
bool ApplyToWholeInstance(WasmInstanceObject*,
ICacheFlushMode = FLUSH_ICACHE_IF_NEEDED);
// Apply all relocations and patching to one wasm code object.
bool ApplyToWasmCode(Code*, ICacheFlushMode = FLUSH_ICACHE_IF_NEEDED);
bool ApplyToWasmCode(WasmCodeWrapper,
ICacheFlushMode = FLUSH_ICACHE_IF_NEEDED);
private:
Isolate* isolate_;
Address new_wasm_context_address = 0;
uint32_t old_function_table_size = 0;

View File

@ -0,0 +1,38 @@
// Copyright 2017 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.
#include "src/wasm/wasm-code-wrapper.h"
#include "src/objects.h"
#include "src/objects/code.h"
namespace v8 {
namespace internal {
// When constructing, we check the flag. After that, we just
// check using the member.
WasmCodeWrapper::WasmCodeWrapper(Handle<Code> code) {
DCHECK(!FLAG_wasm_jit_to_native);
code_ptr_.code_handle_ = code.location();
}
WasmCodeWrapper::WasmCodeWrapper(const wasm::WasmCode* code) {
DCHECK(FLAG_wasm_jit_to_native);
code_ptr_.wasm_code_ = code;
}
Handle<Code> WasmCodeWrapper::GetCode() const {
DCHECK(IsCodeObject());
return Handle<Code>(code_ptr_.code_handle_);
}
const wasm::WasmCode* WasmCodeWrapper::GetWasmCode() const {
DCHECK(!IsCodeObject());
return code_ptr_.wasm_code_;
}
bool WasmCodeWrapper::IsCodeObject() const { return !FLAG_wasm_jit_to_native; }
} // namespace internal
} // namespace v8

View File

@ -0,0 +1,38 @@
// Copyright 2017 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.
#ifndef V8_WASM_CODE_WRAPPER_H_
#define V8_WASM_CODE_WRAPPER_H_
#include "src/handles.h"
namespace v8 {
namespace internal {
namespace wasm {
class WasmCode;
} // namespace wasm
class Code;
// TODO(mtrofin): remove once we remove FLAG_wasm_jit_to_native
class WasmCodeWrapper {
public:
WasmCodeWrapper() {}
explicit WasmCodeWrapper(Handle<Code> code);
explicit WasmCodeWrapper(const wasm::WasmCode* code);
Handle<Code> GetCode() const;
const wasm::WasmCode* GetWasmCode() const;
bool is_null() const { return code_ptr_.wasm_code_ == nullptr; }
bool IsCodeObject() const;
private:
union {
const wasm::WasmCode* wasm_code_;
Code** code_handle_;
} code_ptr_ = {};
};
} // namespace internal
} // namespace v8
#endif // V8_WASM_CODE_WRAPPER_H_

View File

@ -574,9 +574,11 @@ Handle<FixedArray> GetOrCreateInterpretedFunctions(
return new_arr;
}
using CodeRelocationMap = IdentityMap<Handle<Code>, FreeStoreAllocationPolicy>;
using CodeRelocationMap = std::map<Address, Address>;
using CodeRelocationMapGC =
IdentityMap<Handle<Code>, FreeStoreAllocationPolicy>;
void RedirectCallsitesInCode(Code* code, CodeRelocationMap& map) {
void RedirectCallsitesInCodeGC(Code* code, CodeRelocationMapGC& map) {
DisallowHeapAllocation no_gc;
for (RelocIterator it(code, RelocInfo::kCodeTargetMask); !it.done();
it.next()) {
@ -589,13 +591,40 @@ void RedirectCallsitesInCode(Code* code, CodeRelocationMap& map) {
}
}
void RedirectCallsitesInInstance(Isolate* isolate, WasmInstanceObject* instance,
CodeRelocationMap& map) {
void RedirectCallsitesInCode(Isolate* isolate, const wasm::WasmCode* code,
CodeRelocationMap* map) {
DisallowHeapAllocation no_gc;
for (RelocIterator it(code->instructions(), code->reloc_info(),
code->constant_pool(),
RelocInfo::ModeMask(RelocInfo::WASM_CALL));
!it.done(); it.next()) {
Address target = it.rinfo()->target_address();
auto new_target = map->find(target);
if (new_target == map->end()) continue;
it.rinfo()->set_wasm_call_address(isolate, new_target->second);
}
}
void RedirectCallsitesInJSWrapperCode(Isolate* isolate, Code* code,
CodeRelocationMap* map) {
DisallowHeapAllocation no_gc;
for (RelocIterator it(code, RelocInfo::ModeMask(RelocInfo::JS_TO_WASM_CALL));
!it.done(); it.next()) {
Address target = it.rinfo()->js_to_wasm_address();
auto new_target = map->find(target);
if (new_target == map->end()) continue;
it.rinfo()->set_js_to_wasm_address(isolate, new_target->second);
}
}
void RedirectCallsitesInInstanceGC(Isolate* isolate,
WasmInstanceObject* instance,
CodeRelocationMapGC& map) {
DisallowHeapAllocation no_gc;
// Redirect all calls in wasm functions.
FixedArray* code_table = instance->compiled_module()->ptr_to_code_table();
for (int i = 0, e = GetNumFunctions(instance); i < e; ++i) {
RedirectCallsitesInCode(Code::cast(code_table->get(i)), map);
RedirectCallsitesInCodeGC(Code::cast(code_table->get(i)), map);
}
// TODO(6668): Find instances that imported our code and also patch those.
@ -606,7 +635,29 @@ void RedirectCallsitesInInstance(Isolate* isolate, WasmInstanceObject* instance,
WeakCell* weak_function = WeakCell::cast(weak_exported_functions->get(i));
if (weak_function->cleared()) continue;
Code* code = JSFunction::cast(weak_function->value())->code();
RedirectCallsitesInCode(code, map);
RedirectCallsitesInCodeGC(code, map);
}
}
void RedirectCallsitesInInstance(Isolate* isolate, WasmInstanceObject* instance,
CodeRelocationMap* map) {
DisallowHeapAllocation no_gc;
// Redirect all calls in wasm functions.
for (uint32_t i = 0, e = GetNumFunctions(instance); i < e; ++i) {
wasm::WasmCode* code =
instance->compiled_module()->GetNativeModule()->GetCode(i);
RedirectCallsitesInCode(isolate, code, map);
}
// TODO(6668): Find instances that imported our code and also patch those.
// Redirect all calls in exported functions.
FixedArray* weak_exported_functions =
instance->compiled_module()->ptr_to_weak_exported_functions();
for (int i = 0, e = weak_exported_functions->length(); i != e; ++i) {
WeakCell* weak_function = WeakCell::cast(weak_exported_functions->get(i));
if (weak_function->cleared()) continue;
Code* code = JSFunction::cast(weak_function->value())->code();
RedirectCallsitesInJSWrapperCode(isolate, code, map);
}
}
@ -670,8 +721,12 @@ void WasmDebugInfo::RedirectToInterpreter(Handle<WasmDebugInfo> debug_info,
Handle<FixedArray> interpreted_functions =
GetOrCreateInterpretedFunctions(isolate, debug_info);
Handle<WasmInstanceObject> instance(debug_info->wasm_instance(), isolate);
wasm::NativeModule* native_module =
instance->compiled_module()->GetNativeModule();
CodeRelocationMap code_to_relocate;
Handle<FixedArray> code_table = instance->compiled_module()->code_table();
CodeRelocationMap code_to_relocate(isolate->heap());
CodeRelocationMapGC code_to_relocate_gc(isolate->heap());
// TODO(6792): No longer needed once WebAssembly code is off heap.
CodeSpaceMemoryModificationScope modification_scope(isolate->heap());
for (int func_index : func_indexes) {
@ -684,13 +739,30 @@ void WasmDebugInfo::RedirectToInterpreter(Handle<WasmDebugInfo> debug_info,
isolate, func_index,
instance->compiled_module()->module()->functions[func_index].sig,
instance);
Code* old_code = Code::cast(code_table->get(func_index));
interpreted_functions->set(func_index, *new_code);
DCHECK_NULL(code_to_relocate.Find(old_code));
code_to_relocate.Set(old_code, new_code);
if (FLAG_wasm_jit_to_native) {
const wasm::WasmCode* wasm_new_code =
native_module->AddInterpreterWrapper(new_code, func_index);
const wasm::WasmCode* old_code =
native_module->GetCode(static_cast<uint32_t>(func_index));
Handle<Foreign> foreign_holder = isolate->factory()->NewForeign(
wasm_new_code->instructions().start(), TENURED);
interpreted_functions->set(func_index, *foreign_holder);
DCHECK_EQ(0, code_to_relocate.count(old_code->instructions().start()));
code_to_relocate.insert(
std::make_pair(old_code->instructions().start(),
wasm_new_code->instructions().start()));
} else {
Code* old_code = Code::cast(code_table->get(func_index));
interpreted_functions->set(func_index, *new_code);
DCHECK_NULL(code_to_relocate_gc.Find(old_code));
code_to_relocate_gc.Set(old_code, new_code);
}
}
if (FLAG_wasm_jit_to_native) {
RedirectCallsitesInInstance(isolate, *instance, &code_to_relocate);
} else {
RedirectCallsitesInInstanceGC(isolate, *instance, code_to_relocate_gc);
}
RedirectCallsitesInInstance(isolate, *instance, code_to_relocate);
}
void WasmDebugInfo::PrepareStep(StepAction step_action) {

View File

@ -359,8 +359,6 @@ class V8_EXPORT_PRIVATE WasmCodeManager final {
intptr_t remaining_uncommitted() const;
private:
static const size_t kMaxWasmCodeMemory = 256 * MB;
friend class NativeModule;
WasmCodeManager(const WasmCodeManager&) = delete;

View File

@ -627,17 +627,29 @@ const char* OpcodeName(uint32_t val) {
// Unwrap a wasm to js wrapper, return the callable heap object.
// If the wrapper would throw a TypeError, return a null handle.
Handle<HeapObject> UnwrapWasmToJSWrapper(Isolate* isolate,
Handle<Code> js_wrapper) {
DCHECK_EQ(Code::WASM_TO_JS_FUNCTION, js_wrapper->kind());
Handle<FixedArray> deopt_data(js_wrapper->deoptimization_data(), isolate);
DCHECK_EQ(2, deopt_data->length());
intptr_t js_imports_table_loc = static_cast<intptr_t>(
HeapNumber::cast(deopt_data->get(0))->value_as_bits());
Handle<FixedArray> js_imports_table(
reinterpret_cast<FixedArray**>(js_imports_table_loc));
WasmCodeWrapper wrapper) {
Handle<FixedArray> js_imports_table;
int index = 0;
CHECK(deopt_data->get(1)->ToInt32(&index));
DCHECK_GT(js_imports_table->length(), index);
if (wrapper.IsCodeObject()) {
Handle<Code> js_wrapper = wrapper.GetCode();
DCHECK(Code::WASM_TO_JS_FUNCTION == js_wrapper->kind());
Handle<FixedArray> deopt_data(js_wrapper->deoptimization_data(), isolate);
DCHECK_EQ(2, deopt_data->length());
intptr_t js_imports_table_loc = static_cast<intptr_t>(
HeapNumber::cast(deopt_data->get(0))->value_as_bits());
js_imports_table = Handle<FixedArray>(
reinterpret_cast<FixedArray**>(js_imports_table_loc));
CHECK(deopt_data->get(1)->ToInt32(&index));
DCHECK_GT(js_imports_table->length(), index);
} else {
const wasm::WasmCode* wasm_code = wrapper.GetWasmCode();
DCHECK_EQ(wasm::WasmCode::WasmToJsWrapper, wasm_code->kind());
js_imports_table = Handle<FixedArray>(wasm_code->owner()
->compiled_module()
->owning_instance()
->js_imports_table());
index = 1 + 3 * static_cast<int>(wasm_code->index());
}
Handle<Object> obj(js_imports_table->get(index), isolate);
if (obj->IsCallable()) {
return Handle<HeapObject>::cast(obj);
@ -982,7 +994,15 @@ class CodeMap {
: MaybeHandle<WasmInstanceObject>();
}
Code* GetImportedFunction(uint32_t function_index) {
const wasm::WasmCode* GetImportedFunction(uint32_t function_index) {
DCHECK(has_instance());
DCHECK_GT(module_->num_imported_functions, function_index);
const wasm::NativeModule* native_module =
instance()->compiled_module()->GetNativeModule();
return native_module->GetCode(function_index);
}
Code* GetImportedFunctionGC(uint32_t function_index) {
DCHECK(has_instance());
DCHECK_GT(module_->num_imported_functions, function_index);
FixedArray* code_table = instance()->compiled_module()->ptr_to_code_table();
@ -2238,9 +2258,8 @@ class ThreadImpl {
return {ExternalCallResult::EXTERNAL_RETURNED};
}
// TODO(clemensh): Remove this, call JS via existing wasm-to-js wrapper, using
// CallExternalWasmFunction.
ExternalCallResult CallExternalJSFunction(Isolate* isolate, Handle<Code> code,
ExternalCallResult CallExternalJSFunction(Isolate* isolate,
WasmCodeWrapper code,
FunctionSig* signature) {
Handle<HeapObject> target = UnwrapWasmToJSWrapper(isolate, code);
@ -2295,7 +2314,7 @@ class ThreadImpl {
}
ExternalCallResult CallExternalWasmFunction(Isolate* isolate,
Handle<Code> code,
WasmCodeWrapper code,
FunctionSig* sig) {
Handle<WasmDebugInfo> debug_info(codemap()->instance()->debug_info(),
isolate);
@ -2356,7 +2375,11 @@ class ThreadImpl {
DCHECK(!arg_buffer_obj->IsHeapObject());
Handle<Object> args[compiler::CWasmEntryParameters::kNumParameters];
args[compiler::CWasmEntryParameters::kCodeObject] = code;
args[compiler::CWasmEntryParameters::kCodeObject] =
code.IsCodeObject()
? Handle<Object>::cast(code.GetCode())
: Handle<Object>::cast(isolate->factory()->NewForeign(
code.GetWasmCode()->instructions().start(), TENURED));
args[compiler::CWasmEntryParameters::kArgumentsBuffer] = arg_buffer_obj;
Handle<Object> receiver = isolate->factory()->undefined_value();
@ -2408,14 +2431,34 @@ class ThreadImpl {
code->kind() == Code::WASM_TO_WASM_FUNCTION) {
auto func_info = GetWasmFunctionInfo(isolate, code);
if (*func_info.instance.ToHandleChecked() != codemap()->instance()) {
return CallExternalWasmFunction(isolate, code, signature);
return CallExternalWasmFunction(isolate, WasmCodeWrapper(code),
signature);
}
DCHECK_LE(0, func_info.func_index);
return {ExternalCallResult::INTERNAL,
codemap()->GetCode(func_info.func_index)};
}
return CallExternalJSFunction(isolate, code, signature);
return CallExternalJSFunction(isolate, WasmCodeWrapper(code), signature);
}
ExternalCallResult CallWasmCode(Isolate* isolate, const wasm::WasmCode* code,
FunctionSig* signature) {
DCHECK(AllowHandleAllocation::IsAllowed());
DCHECK(AllowHeapAllocation::IsAllowed());
if (code->kind() == wasm::WasmCode::Function) {
DCHECK_EQ(*code->owner()->compiled_module()->owning_instance(),
codemap()->instance());
return {ExternalCallResult::INTERNAL, codemap()->GetCode(code->index())};
}
if (code->kind() == wasm::WasmCode::WasmToJsWrapper) {
return CallExternalJSFunction(isolate, WasmCodeWrapper(code), signature);
} else if (code->kind() == wasm::WasmCode::WasmToWasmWrapper) {
return CallExternalWasmFunction(isolate, WasmCodeWrapper(code),
signature);
}
return {ExternalCallResult::INVALID_FUNC};
}
ExternalCallResult CallImportedFunction(uint32_t function_index) {
@ -2424,17 +2467,36 @@ class ThreadImpl {
Isolate* isolate = codemap()->instance()->GetIsolate();
HandleScope handle_scope(isolate);
Handle<Code> target(codemap()->GetImportedFunction(function_index),
isolate);
return CallCodeObject(isolate, target,
if (FLAG_wasm_jit_to_native) {
const wasm::WasmCode* target =
codemap()->GetImportedFunction(function_index);
return CallWasmCode(isolate, target,
codemap()->module()->functions[function_index].sig);
} else {
Handle<Code> target(codemap()->GetImportedFunctionGC(function_index),
isolate);
return CallCodeObject(isolate, target,
codemap()->module()->functions[function_index].sig);
}
}
ExternalCallResult CallIndirectFunction(uint32_t table_index,
uint32_t entry_index,
uint32_t sig_index) {
if (!codemap()->has_instance() ||
!codemap()->instance()->compiled_module()->has_function_tables()) {
bool no_func_tables = !codemap()->has_instance();
if (FLAG_wasm_jit_to_native) {
no_func_tables = no_func_tables || codemap()
->instance()
->compiled_module()
->GetNativeModule()
->function_tables()
.empty();
} else {
no_func_tables =
no_func_tables ||
!codemap()->instance()->compiled_module()->has_function_tables();
}
if (no_func_tables) {
// No instance. Rely on the information stored in the WasmModule.
// TODO(wasm): This is only needed for testing. Refactor testing to use
// the same paths as production.
@ -2459,7 +2521,8 @@ class ThreadImpl {
codemap()->instance()->compiled_module();
Isolate* isolate = compiled_module->GetIsolate();
Code* target;
const wasm::WasmCode* target = nullptr;
Code* target_gc = nullptr;
{
DisallowHeapAllocation no_gc;
// Get function to be called directly from the live instance to see latest
@ -2470,39 +2533,80 @@ class ThreadImpl {
DCHECK_EQ(canonical_sig_index,
module()->signature_map.Find(module()->signatures[sig_index]));
// Check signature.
FixedArray* sig_tables = compiled_module->ptr_to_signature_tables();
if (table_index >= static_cast<uint32_t>(sig_tables->length())) {
return {ExternalCallResult::INVALID_FUNC};
}
// Reconstitute the global handle to sig_table, and, further below,
// to the function table, from the address stored in the
// respective table of tables.
int table_index_as_int = static_cast<int>(table_index);
Handle<FixedArray> sig_table(reinterpret_cast<FixedArray**>(
WasmCompiledModule::GetTableValue(sig_tables, table_index_as_int)));
if (entry_index >= static_cast<uint32_t>(sig_table->length())) {
return {ExternalCallResult::INVALID_FUNC};
}
int found_sig = Smi::ToInt(sig_table->get(static_cast<int>(entry_index)));
if (static_cast<uint32_t>(found_sig) != canonical_sig_index) {
return {ExternalCallResult::SIGNATURE_MISMATCH};
}
if (!FLAG_wasm_jit_to_native) {
// Check signature.
FixedArray* sig_tables = compiled_module->ptr_to_signature_tables();
if (table_index >= static_cast<uint32_t>(sig_tables->length())) {
return {ExternalCallResult::INVALID_FUNC};
}
// Reconstitute the global handle to sig_table, and, further below,
// to the function table, from the address stored in the
// respective table of tables.
int table_index_as_int = static_cast<int>(table_index);
Handle<FixedArray> sig_table(reinterpret_cast<FixedArray**>(
WasmCompiledModule::GetTableValue(sig_tables, table_index_as_int)));
if (entry_index >= static_cast<uint32_t>(sig_table->length())) {
return {ExternalCallResult::INVALID_FUNC};
}
int found_sig =
Smi::ToInt(sig_table->get(static_cast<int>(entry_index)));
if (static_cast<uint32_t>(found_sig) != canonical_sig_index) {
return {ExternalCallResult::SIGNATURE_MISMATCH};
}
// Get code object.
FixedArray* fun_tables = compiled_module->ptr_to_function_tables();
DCHECK_EQ(sig_tables->length(), fun_tables->length());
Handle<FixedArray> fun_table(reinterpret_cast<FixedArray**>(
WasmCompiledModule::GetTableValue(fun_tables, table_index_as_int)));
DCHECK_EQ(sig_table->length(), fun_table->length());
target = Code::cast(fun_table->get(static_cast<int>(entry_index)));
// Get code object.
FixedArray* fun_tables = compiled_module->ptr_to_function_tables();
DCHECK_EQ(sig_tables->length(), fun_tables->length());
Handle<FixedArray> fun_table(reinterpret_cast<FixedArray**>(
WasmCompiledModule::GetTableValue(fun_tables, table_index_as_int)));
DCHECK_EQ(sig_table->length(), fun_table->length());
target_gc = Code::cast(fun_table->get(static_cast<int>(entry_index)));
} else {
// Check signature.
std::vector<GlobalHandleAddress>& sig_tables =
compiled_module->GetNativeModule()->signature_tables();
if (table_index >= sig_tables.size()) {
return {ExternalCallResult::INVALID_FUNC};
}
// Reconstitute the global handle to sig_table, and, further below,
// to the function table, from the address stored in the
// respective table of tables.
int table_index_as_int = static_cast<int>(table_index);
Handle<FixedArray> sig_table(
reinterpret_cast<FixedArray**>(sig_tables[table_index_as_int]));
if (entry_index >= static_cast<uint32_t>(sig_table->length())) {
return {ExternalCallResult::INVALID_FUNC};
}
int found_sig =
Smi::ToInt(sig_table->get(static_cast<int>(entry_index)));
if (static_cast<uint32_t>(found_sig) != canonical_sig_index) {
return {ExternalCallResult::SIGNATURE_MISMATCH};
}
// Get code object.
std::vector<GlobalHandleAddress>& fun_tables =
compiled_module->GetNativeModule()->function_tables();
DCHECK_EQ(sig_tables.size(), fun_tables.size());
Handle<FixedArray> fun_table(
reinterpret_cast<FixedArray**>(fun_tables[table_index_as_int]));
DCHECK_EQ(sig_table->length(), fun_table->length());
Address first_instr =
Foreign::cast(fun_table->get(static_cast<int>(entry_index)))
->foreign_address();
target =
isolate->wasm_code_manager()->GetCodeFromStartAddress(first_instr);
}
}
// Call the code object. Use a new HandleScope to avoid leaking /
// accumulating handles in the outer scope.
HandleScope handle_scope(isolate);
FunctionSig* signature = module()->signatures[sig_index];
return CallCodeObject(isolate, handle(target, isolate), signature);
if (FLAG_wasm_jit_to_native) {
return CallWasmCode(isolate, target, signature);
} else {
return CallCodeObject(isolate, handle(target_gc, isolate), signature);
}
}
inline Activation current_activation() {

View File

@ -21,6 +21,7 @@
#include "src/wasm/module-compiler.h"
#include "src/wasm/module-decoder.h"
#include "src/wasm/wasm-code-specialization.h"
#include "src/wasm/wasm-heap.h"
#include "src/wasm/wasm-js.h"
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-objects-inl.h"
@ -54,8 +55,8 @@ constexpr const char* WasmException::kRuntimeIdStr;
// static
constexpr const char* WasmException::kRuntimeValuesStr;
void UnpackAndRegisterProtectedInstructions(Isolate* isolate,
Handle<FixedArray> code_table) {
void UnpackAndRegisterProtectedInstructionsGC(Isolate* isolate,
Handle<FixedArray> code_table) {
DisallowHeapAllocation no_gc;
std::vector<trap_handler::ProtectedInstructionData> unpacked;
@ -108,6 +109,37 @@ void UnpackAndRegisterProtectedInstructions(Isolate* isolate,
}
}
void UnpackAndRegisterProtectedInstructions(Isolate* isolate,
wasm::NativeModule* native_module) {
DisallowHeapAllocation no_gc;
for (uint32_t i = native_module->num_imported_functions(),
e = native_module->FunctionCount();
i < e; ++i) {
wasm::WasmCode* code = native_module->GetCode(i);
if (code == nullptr || code->kind() != wasm::WasmCode::Function) {
continue;
}
if (code->HasTrapHandlerIndex()) continue;
Address base = code->instructions().start();
size_t size = code->instructions().size();
const int index =
RegisterHandlerData(base, size, code->protected_instructions().size(),
code->protected_instructions().data());
// TODO(6792): No longer needed once WebAssembly code is off heap.
CodeSpaceMemoryModificationScope modification_scope(isolate->heap());
// TODO(eholk): if index is negative, fail.
CHECK_LE(0, index);
code->set_trap_handler_index(static_cast<size_t>(index));
}
}
std::ostream& operator<<(std::ostream& os, const WasmFunctionName& name) {
os << "#" << name.function_->func_index;
if (name.function_->name.is_set()) {
@ -140,7 +172,7 @@ WasmFunction* GetWasmFunctionForExport(Isolate* isolate,
void UpdateDispatchTables(Isolate* isolate, Handle<FixedArray> dispatch_tables,
int index, WasmFunction* function,
Handle<Code> code) {
Handle<Object> code_or_foreign) {
DCHECK_EQ(0, dispatch_tables->length() % 4);
for (int i = 0; i < dispatch_tables->length(); i += 4) {
Handle<FixedArray> function_table(
@ -154,7 +186,7 @@ void UpdateDispatchTables(Isolate* isolate, Handle<FixedArray> dispatch_tables,
// not found; it will simply never match any check.
auto sig_index = instance->module()->signature_map.Find(function->sig);
signature_table->set(index, Smi::FromInt(sig_index));
function_table->set(index, *code);
function_table->set(index, *code_or_foreign);
} else {
signature_table->set(index, Smi::FromInt(-1));
function_table->set(index, Smi::kZero);

View File

@ -15,6 +15,7 @@
#include "src/wasm/decoder.h"
#include "src/wasm/signature-map.h"
#include "src/wasm/wasm-heap.h"
#include "src/wasm/wasm-opcodes.h"
namespace v8 {
@ -284,10 +285,14 @@ Handle<FixedArray> DecodeLocalNames(Isolate*, Handle<WasmCompiledModule>);
WasmFunction* GetWasmFunctionForExport(Isolate* isolate, Handle<Object> target);
void UpdateDispatchTables(Isolate* isolate, Handle<FixedArray> dispatch_tables,
int index, WasmFunction* function, Handle<Code> code);
int index, WasmFunction* function,
Handle<Object> code_or_foreign);
void UnpackAndRegisterProtectedInstructionsGC(Isolate* isolate,
Handle<FixedArray> code_table);
void UnpackAndRegisterProtectedInstructions(Isolate* isolate,
Handle<FixedArray> code_table);
wasm::NativeModule* native_module);
const char* ExternalKindName(WasmExternalKind);

View File

@ -151,6 +151,14 @@ bool IsBreakablePosition(Handle<WasmCompiledModule> compiled_module,
}
#endif // DEBUG
void CompiledModuleFinalizer(const v8::WeakCallbackInfo<void>& data) {
DisallowHeapAllocation no_gc;
JSObject** p = reinterpret_cast<JSObject**>(data.GetParameter());
WasmCompiledModule* compiled_module = WasmCompiledModule::cast(*p);
compiled_module->reset_native_module();
GlobalHandles::Destroy(reinterpret_cast<Object**>(p));
}
} // namespace
Handle<WasmModuleObject> WasmModuleObject::New(
@ -253,7 +261,27 @@ void WasmTableObject::Grow(Isolate* isolate, uint32_t count) {
dispatch_tables->set(i + 3, *new_signature_table);
// Patch the code of the respective instance.
{
if (FLAG_wasm_jit_to_native) {
DisallowHeapAllocation no_gc;
wasm::CodeSpecialization code_specialization(isolate,
&specialization_zone);
WasmInstanceObject* instance =
WasmInstanceObject::cast(dispatch_tables->get(i));
WasmCompiledModule* compiled_module = instance->compiled_module();
wasm::NativeModule* native_module = compiled_module->GetNativeModule();
GlobalHandleAddress old_function_table_addr =
native_module->function_tables()[table_index];
GlobalHandleAddress old_signature_table_addr =
native_module->signature_tables()[table_index];
code_specialization.PatchTableSize(old_size, old_size + count);
code_specialization.RelocatePointer(old_function_table_addr,
new_function_table_addr);
code_specialization.RelocatePointer(old_signature_table_addr,
new_signature_table_addr);
code_specialization.ApplyToWholeInstance(instance);
native_module->function_tables()[table_index] = new_function_table_addr;
native_module->signature_tables()[table_index] = new_signature_table_addr;
} else {
DisallowHeapAllocation no_gc;
wasm::CodeSpecialization code_specialization(isolate,
&specialization_zone);
@ -289,7 +317,7 @@ void WasmTableObject::Set(Isolate* isolate, Handle<WasmTableObject> table,
Handle<FixedArray> dispatch_tables(table->dispatch_tables(), isolate);
WasmFunction* wasm_function = nullptr;
Handle<Code> code = Handle<Code>::null();
Handle<Object> code = Handle<Object>::null();
Handle<Object> value = isolate->factory()->null_value();
if (!function.is_null()) {
@ -301,18 +329,35 @@ void WasmTableObject::Set(Isolate* isolate, Handle<WasmTableObject> table,
value = function;
// TODO(titzer): Make JSToWasm wrappers just call the WASM to WASM wrapper,
// and then we can just reuse the WASM to WASM wrapper.
Handle<WasmInstanceObject> instance(exported_function->instance(), isolate);
int func_index = exported_function->function_index();
Address new_context_address =
reinterpret_cast<Address>(instance->wasm_context()->get());
code = compiler::CompileWasmToWasmWrapper(
isolate, exported_function->GetWasmCode(), wasm_function->sig,
func_index, new_context_address);
// TODO(6792): No longer needed once WebAssembly code is off heap.
CodeSpaceMemoryModificationScope modification_scope(isolate->heap());
AttachWasmFunctionInfo(isolate, code, instance, func_index);
Address new_context_address = reinterpret_cast<Address>(
exported_function->instance()->wasm_context()->get());
WasmCodeWrapper wasm_code = exported_function->GetWasmCode();
if (!wasm_code.IsCodeObject()) {
wasm::NativeModule* native_module = wasm_code.GetWasmCode()->owner();
// we create the wrapper on the module exporting the function. This
// wrapper will only be called as indirect call.
wasm::WasmCode* exported_wrapper =
native_module->GetExportedWrapper(wasm_code.GetWasmCode()->index());
if (exported_wrapper == nullptr) {
Handle<Code> new_wrapper = compiler::CompileWasmToWasmWrapper(
isolate, wasm_code, wasm_function->sig, new_context_address);
exported_wrapper = native_module->AddExportedWrapper(
new_wrapper, wasm_code.GetWasmCode()->index());
}
Address target = exported_wrapper->instructions().start();
code = isolate->factory()->NewForeign(target, TENURED);
} else {
Handle<WasmInstanceObject> instance(exported_function->instance(),
isolate);
int func_index = exported_function->function_index();
code = compiler::CompileWasmToWasmWrapper(
isolate, wasm_code, wasm_function->sig, new_context_address);
// TODO(6792): No longer needed once WebAssembly code is off heap.
CodeSpaceMemoryModificationScope modification_scope(isolate->heap());
AttachWasmFunctionInfo(isolate, Handle<Code>::cast(code), instance,
func_index);
}
}
UpdateDispatchTables(isolate, dispatch_tables, index, wasm_function, code);
array->set(index, *value);
}
@ -565,7 +610,20 @@ uint32_t WasmInstanceObject::GetMaxMemoryPages() {
return FLAG_wasm_max_mem_pages;
}
WasmInstanceObject* WasmInstanceObject::GetOwningInstance(Code* code) {
WasmInstanceObject* WasmInstanceObject::GetOwningInstance(
const wasm::WasmCode* code) {
DisallowHeapAllocation no_gc;
Object* weak_link = nullptr;
DCHECK(code->kind() == wasm::WasmCode::Function ||
code->kind() == wasm::WasmCode::InterpreterStub);
weak_link = code->owner()->compiled_module()->ptr_to_weak_owning_instance();
DCHECK(weak_link->IsWeakCell());
WeakCell* cell = WeakCell::cast(weak_link);
if (cell->cleared()) return nullptr;
return WasmInstanceObject::cast(cell->value());
}
WasmInstanceObject* WasmInstanceObject::GetOwningInstanceGC(Code* code) {
DisallowHeapAllocation no_gc;
DCHECK(code->kind() == Code::WASM_FUNCTION ||
code->kind() == Code::WASM_INTERPRETER_ENTRY);
@ -682,11 +740,13 @@ Handle<WasmExportedFunction> WasmExportedFunction::New(
return Handle<WasmExportedFunction>::cast(js_function);
}
Handle<Code> WasmExportedFunction::GetWasmCode() {
WasmCodeWrapper WasmExportedFunction::GetWasmCode() {
DisallowHeapAllocation no_gc;
Handle<Code> export_wrapper_code = handle(this->code());
DCHECK_EQ(export_wrapper_code->kind(), Code::JS_TO_WASM_FUNCTION);
int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
int mask =
RelocInfo::ModeMask(FLAG_wasm_jit_to_native ? RelocInfo::JS_TO_WASM_CALL
: RelocInfo::CODE_TARGET);
auto IsWasmFunctionCode = [](Code* code) {
return code->kind() == Code::WASM_FUNCTION ||
code->kind() == Code::WASM_TO_JS_FUNCTION ||
@ -694,18 +754,31 @@ Handle<Code> WasmExportedFunction::GetWasmCode() {
code->kind() == Code::WASM_INTERPRETER_ENTRY ||
code->builtin_index() == Builtins::kWasmCompileLazy;
};
for (RelocIterator it(*export_wrapper_code, mask);; it.next()) {
DCHECK(!it.done());
Code* target = Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
if (!IsWasmFunctionCode(target)) continue;
WasmCodeWrapper target;
if (FLAG_wasm_jit_to_native) {
target = WasmCodeWrapper(GetIsolate()->wasm_code_manager()->LookupCode(
it.rinfo()->js_to_wasm_address()));
} else {
Code* code = Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
if (!IsWasmFunctionCode(code)) continue;
target = WasmCodeWrapper(handle(code));
}
// There should only be this one call to wasm code.
#ifdef DEBUG
for (it.next(); !it.done(); it.next()) {
Code* code = Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
DCHECK(!IsWasmFunctionCode(code));
if (FLAG_wasm_jit_to_native) {
UNREACHABLE();
} else {
Code* code =
Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
DCHECK(!IsWasmFunctionCode(code));
}
}
#endif
return handle(target);
return target;
}
UNREACHABLE();
}
@ -943,8 +1016,8 @@ void WasmSharedModuleData::PrepareForLazyCompilation(
}
Handle<WasmCompiledModule> WasmCompiledModule::New(
Isolate* isolate, Handle<WasmSharedModuleData> shared,
Handle<FixedArray> code_table, Handle<FixedArray> export_wrappers,
Isolate* isolate, WasmModule* module, Handle<FixedArray> code_table,
Handle<FixedArray> export_wrappers,
const std::vector<GlobalHandleAddress>& function_tables,
const std::vector<GlobalHandleAddress>& signature_tables) {
DCHECK_EQ(function_tables.size(), signature_tables.size());
@ -953,40 +1026,75 @@ Handle<WasmCompiledModule> WasmCompiledModule::New(
// WasmCompiledModule::cast would fail since fields are not set yet.
Handle<WasmCompiledModule> compiled_module(
reinterpret_cast<WasmCompiledModule*>(*ret), isolate);
compiled_module->InitId();
compiled_module->set_shared(shared);
compiled_module->set_native_context(isolate->native_context());
compiled_module->set_code_table(code_table);
compiled_module->set_export_wrappers(export_wrappers);
// TODO(mtrofin): we copy these because the order of finalization isn't
// reliable, and we need these at Reset (which is called at
// finalization). If the order were reliable, and top-down, we could instead
// just get them from shared().
compiled_module->set_initial_pages(shared->module()->initial_pages);
compiled_module->set_num_imported_functions(
shared->module()->num_imported_functions);
if (!FLAG_wasm_jit_to_native) {
compiled_module->InitId();
compiled_module->set_native_context(isolate->native_context());
compiled_module->set_code_table(code_table);
compiled_module->set_export_wrappers(export_wrappers);
// TODO(mtrofin): we copy these because the order of finalization isn't
// reliable, and we need these at Reset (which is called at
// finalization). If the order were reliable, and top-down, we could instead
// just get them from shared().
compiled_module->set_initial_pages(module->initial_pages);
compiled_module->set_num_imported_functions(module->num_imported_functions);
int num_function_tables = static_cast<int>(function_tables.size());
if (num_function_tables > 0) {
Handle<FixedArray> st =
isolate->factory()->NewFixedArray(num_function_tables, TENURED);
Handle<FixedArray> ft =
isolate->factory()->NewFixedArray(num_function_tables, TENURED);
for (int i = 0; i < num_function_tables; ++i) {
size_t index = static_cast<size_t>(i);
SetTableValue(isolate, ft, i, function_tables[index]);
SetTableValue(isolate, st, i, signature_tables[index]);
int num_function_tables = static_cast<int>(function_tables.size());
if (num_function_tables > 0) {
Handle<FixedArray> st =
isolate->factory()->NewFixedArray(num_function_tables, TENURED);
Handle<FixedArray> ft =
isolate->factory()->NewFixedArray(num_function_tables, TENURED);
for (int i = 0; i < num_function_tables; ++i) {
size_t index = static_cast<size_t>(i);
SetTableValue(isolate, ft, i, function_tables[index]);
SetTableValue(isolate, st, i, signature_tables[index]);
}
// TODO(wasm): setting the empty tables here this way is OK under the
// assumption that we compile and then instantiate. It needs rework if we
// do direct instantiation. The empty tables are used as a default when
// resetting the compiled module.
compiled_module->set_signature_tables(st);
compiled_module->set_empty_signature_tables(st);
compiled_module->set_function_tables(ft);
compiled_module->set_empty_function_tables(ft);
}
// TODO(wasm): setting the empty tables here this way is OK under the
// assumption that we compile and then instantiate. It needs rework if we do
// direct instantiation. The empty tables are used as a default when
// resetting the compiled module.
compiled_module->set_signature_tables(st);
compiled_module->set_empty_signature_tables(st);
compiled_module->set_function_tables(ft);
compiled_module->set_empty_function_tables(ft);
}
} else {
if (!export_wrappers.is_null()) {
compiled_module->set_export_wrappers(export_wrappers);
}
wasm::NativeModule* native_module = nullptr;
{
std::unique_ptr<wasm::NativeModule> native_module_ptr =
isolate->wasm_code_manager()->NewNativeModule(*module);
native_module = native_module_ptr.release();
Handle<Foreign> native_module_wrapper =
Managed<wasm::NativeModule>::From(isolate, native_module);
compiled_module->set_native_module(native_module_wrapper);
Handle<WasmCompiledModule> weak_link =
isolate->global_handles()->Create(*compiled_module);
GlobalHandles::MakeWeak(Handle<Object>::cast(weak_link).location(),
Handle<Object>::cast(weak_link).location(),
&CompiledModuleFinalizer,
v8::WeakCallbackType::kFinalizer);
compiled_module->GetNativeModule()->SetCompiledModule(weak_link);
}
// This is here just because it's easier for APIs that need to work with
// either code_table or native_module. Otherwise we need to check if
// has_code_table and pass undefined.
compiled_module->set_code_table(code_table);
native_module->function_tables() = function_tables;
native_module->signature_tables() = signature_tables;
native_module->empty_function_tables() = function_tables;
native_module->empty_signature_tables() = signature_tables;
int function_count = static_cast<int>(module->functions.size());
compiled_module->set_handler_table(
isolate->factory()->NewFixedArray(function_count, TENURED));
compiled_module->set_source_positions(
isolate->factory()->NewFixedArray(function_count, TENURED));
}
// TODO(mtrofin): copy the rest of the specialization parameters over.
// We're currently OK because we're only using defaults.
return compiled_module;
@ -994,16 +1102,42 @@ Handle<WasmCompiledModule> WasmCompiledModule::New(
Handle<WasmCompiledModule> WasmCompiledModule::Clone(
Isolate* isolate, Handle<WasmCompiledModule> module) {
Handle<FixedArray> code_copy =
isolate->factory()->CopyFixedArray(module->code_table());
Handle<FixedArray> code_copy;
if (!FLAG_wasm_jit_to_native) {
code_copy = isolate->factory()->CopyFixedArray(module->code_table());
}
Handle<WasmCompiledModule> ret = Handle<WasmCompiledModule>::cast(
isolate->factory()->CopyFixedArray(module));
ret->InitId();
ret->set_code_table(code_copy);
ret->reset_weak_owning_instance();
ret->reset_next_instance();
ret->reset_prev_instance();
ret->reset_weak_exported_functions();
if (!FLAG_wasm_jit_to_native) {
ret->InitId();
ret->set_code_table(code_copy);
return ret;
}
std::unique_ptr<wasm::NativeModule> native_module =
module->GetNativeModule()->Clone();
// construct the wrapper in 2 steps, because its construction may trigger GC,
// which would shift the this pointer in set_native_module.
Handle<Foreign> native_module_wrapper =
Managed<wasm::NativeModule>::From(isolate, native_module.release());
ret->set_native_module(native_module_wrapper);
Handle<WasmCompiledModule> weak_link =
isolate->global_handles()->Create(*ret);
GlobalHandles::MakeWeak(Handle<Object>::cast(weak_link).location(),
Handle<Object>::cast(weak_link).location(),
&CompiledModuleFinalizer,
v8::WeakCallbackType::kFinalizer);
ret->GetNativeModule()->SetCompiledModule(weak_link);
if (module->has_lazy_compile_data()) {
Handle<FixedArray> lazy_comp_data = isolate->factory()->NewFixedArray(
module->lazy_compile_data()->length(), TENURED);
ret->set_lazy_compile_data(lazy_comp_data);
}
return ret;
}
@ -1028,8 +1162,13 @@ Address WasmCompiledModule::GetTableValue(FixedArray* table, int index) {
return reinterpret_cast<Address>(static_cast<size_t>(value));
}
void WasmCompiledModule::Reset(Isolate* isolate,
WasmCompiledModule* compiled_module) {
wasm::NativeModule* WasmCompiledModule::GetNativeModule() const {
if (!has_native_module()) return nullptr;
return Managed<wasm::NativeModule>::cast(ptr_to_native_module())->get();
}
void WasmCompiledModule::ResetGCModel(Isolate* isolate,
WasmCompiledModule* compiled_module) {
DisallowHeapAllocation no_gc;
TRACE("Resetting %d\n", compiled_module->instance_id());
Object* undefined = *isolate->factory()->undefined_value();
@ -1084,8 +1223,8 @@ void WasmCompiledModule::Reset(Isolate* isolate,
}
break;
}
bool changed =
code_specialization.ApplyToWasmCode(code, SKIP_ICACHE_FLUSH);
bool changed = code_specialization.ApplyToWasmCode(
WasmCodeWrapper(handle(code)), SKIP_ICACHE_FLUSH);
// TODO(wasm): Check if this is faster than passing FLUSH_ICACHE_IF_NEEDED
// above.
if (changed) {
@ -1104,6 +1243,82 @@ void WasmCompiledModule::InitId() {
#endif
}
void WasmCompiledModule::Reset(Isolate* isolate,
WasmCompiledModule* compiled_module) {
DisallowHeapAllocation no_gc;
compiled_module->reset_prev_instance();
compiled_module->reset_next_instance();
wasm::NativeModule* native_module = compiled_module->GetNativeModule();
if (native_module == nullptr) return;
TRACE("Resetting %zu\n", native_module->instance_id);
if (trap_handler::UseTrapHandler()) {
for (uint32_t i = native_module->num_imported_functions(),
e = native_module->FunctionCount();
i < e; ++i) {
wasm::WasmCode* wasm_code = native_module->GetCode(i);
if (wasm_code->HasTrapHandlerIndex()) {
CHECK_LT(wasm_code->trap_handler_index(),
static_cast<size_t>(std::numeric_limits<int>::max()));
trap_handler::ReleaseHandlerData(
static_cast<int>(wasm_code->trap_handler_index()));
wasm_code->ResetTrapHandlerIndex();
}
}
}
// Patch code to update memory references, global references, and function
// table references.
Zone specialization_zone(isolate->allocator(), ZONE_NAME);
wasm::CodeSpecialization code_specialization(isolate, &specialization_zone);
if (compiled_module->has_lazy_compile_data()) {
for (int i = 0, e = compiled_module->lazy_compile_data()->length(); i < e;
++i) {
compiled_module->lazy_compile_data()->set(
i, isolate->heap()->undefined_value());
}
}
// Reset function tables.
if (native_module->function_tables().size() > 0) {
std::vector<GlobalHandleAddress>& function_tables =
native_module->function_tables();
std::vector<GlobalHandleAddress>& signature_tables =
native_module->signature_tables();
std::vector<GlobalHandleAddress>& empty_function_tables =
native_module->empty_function_tables();
std::vector<GlobalHandleAddress>& empty_signature_tables =
native_module->empty_signature_tables();
if (function_tables != empty_function_tables) {
DCHECK_EQ(function_tables.size(), empty_function_tables.size());
for (size_t i = 0, e = function_tables.size(); i < e; ++i) {
code_specialization.RelocatePointer(function_tables[i],
empty_function_tables[i]);
code_specialization.RelocatePointer(signature_tables[i],
empty_signature_tables[i]);
}
native_module->function_tables() = empty_function_tables;
native_module->signature_tables() = empty_signature_tables;
}
}
for (uint32_t i = native_module->num_imported_functions(),
end = native_module->FunctionCount();
i < end; ++i) {
wasm::WasmCode* code = native_module->GetCode(i);
// Skip lazy compile stubs.
if (code == nullptr || code->kind() != wasm::WasmCode::Function) continue;
bool changed = code_specialization.ApplyToWasmCode(WasmCodeWrapper(code),
SKIP_ICACHE_FLUSH);
// TODO(wasm): Check if this is faster than passing FLUSH_ICACHE_IF_NEEDED
// above.
if (changed) {
Assembler::FlushICache(isolate, code->instructions().start(),
code->instructions().size());
}
}
}
MaybeHandle<String> WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
wasm::WireBytesRef ref) {
@ -1149,7 +1364,7 @@ bool WasmCompiledModule::IsWasmCompiledModule(Object* obj) {
#define WCM_CHECK_CONST_OBJECT(TYPE, NAME) \
WCM_CHECK_TYPE(NAME, obj->IsUndefined(isolate) || obj->Is##TYPE())
#define WCM_CHECK_WASM_OBJECT(TYPE, NAME) \
WCM_CHECK_TYPE(NAME, TYPE::Is##TYPE(obj))
WCM_CHECK_TYPE(NAME, obj->IsFixedArray() || obj->IsUndefined(isolate))
#define WCM_CHECK_WEAK_LINK(TYPE, NAME) WCM_CHECK_OBJECT(WeakCell, NAME)
#define WCM_CHECK_SMALL_NUMBER(TYPE, NAME) \
WCM_CHECK_TYPE(NAME, obj->IsUndefined(isolate) || obj->IsSmi())
@ -1173,7 +1388,11 @@ void WasmCompiledModule::PrintInstancesChain() {
#if DEBUG
if (!FLAG_trace_wasm_instances) return;
for (WasmCompiledModule* current = this; current != nullptr;) {
PrintF("->%d", current->instance_id());
if (FLAG_wasm_jit_to_native) {
PrintF("->%zu", current->GetNativeModule()->instance_id);
} else {
PrintF("->%d", current->instance_id());
}
if (!current->has_next_instance()) break;
current = current->ptr_to_next_instance();
}
@ -1204,6 +1423,11 @@ void WasmCompiledModule::RemoveFromChain() {
}
}
void WasmCompiledModule::OnWasmModuleDecodingComplete(
Handle<WasmSharedModuleData> shared) {
set_shared(shared);
}
void WasmCompiledModule::ReinitializeAfterDeserialization(
Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
// This method must only be called immediately after deserialization.
@ -1212,31 +1436,48 @@ void WasmCompiledModule::ReinitializeAfterDeserialization(
Handle<WasmSharedModuleData> shared(
static_cast<WasmSharedModuleData*>(compiled_module->get(kID_shared)),
isolate);
DCHECK(!WasmSharedModuleData::IsWasmSharedModuleData(*shared));
WasmSharedModuleData::ReinitializeAfterDeserialization(isolate, shared);
int function_table_count =
static_cast<int>(compiled_module->module()->function_tables.size());
if (!FLAG_wasm_jit_to_native) {
DCHECK(!WasmSharedModuleData::IsWasmSharedModuleData(*shared));
WasmSharedModuleData::ReinitializeAfterDeserialization(isolate, shared);
}
size_t function_table_count =
compiled_module->module()->function_tables.size();
wasm::NativeModule* native_module = compiled_module->GetNativeModule();
if (function_table_count > 0) {
// The tables are of the right size, but contain bogus global handle
// addresses. Produce new global handles for the empty tables, then reset,
// which will relocate the code. We end up with a WasmCompiledModule as-if
// it were just compiled.
DCHECK(compiled_module->has_function_tables());
DCHECK(compiled_module->has_signature_tables());
DCHECK(compiled_module->has_empty_signature_tables());
DCHECK(compiled_module->has_empty_function_tables());
for (int i = 0; i < function_table_count; ++i) {
if (!FLAG_wasm_jit_to_native) {
DCHECK(compiled_module->has_function_tables());
DCHECK(compiled_module->has_signature_tables());
DCHECK(compiled_module->has_empty_signature_tables());
DCHECK(compiled_module->has_empty_function_tables());
} else {
DCHECK_GT(native_module->function_tables().size(), 0);
DCHECK_GT(native_module->signature_tables().size(), 0);
DCHECK_EQ(native_module->empty_signature_tables().size(),
native_module->function_tables().size());
DCHECK_EQ(native_module->empty_function_tables().size(),
native_module->function_tables().size());
}
for (size_t i = 0; i < function_table_count; ++i) {
Handle<Object> global_func_table_handle =
isolate->global_handles()->Create(isolate->heap()->undefined_value());
Handle<Object> global_sig_table_handle =
isolate->global_handles()->Create(isolate->heap()->undefined_value());
GlobalHandleAddress new_func_table = global_func_table_handle.address();
GlobalHandleAddress new_sig_table = global_sig_table_handle.address();
SetTableValue(isolate, compiled_module->empty_function_tables(), i,
new_func_table);
SetTableValue(isolate, compiled_module->empty_signature_tables(), i,
new_sig_table);
if (!FLAG_wasm_jit_to_native) {
SetTableValue(isolate, compiled_module->empty_function_tables(),
static_cast<int>(i), new_func_table);
SetTableValue(isolate, compiled_module->empty_signature_tables(),
static_cast<int>(i), new_sig_table);
} else {
native_module->empty_function_tables()[i] = new_func_table;
native_module->empty_signature_tables()[i] = new_sig_table;
}
}
}
@ -1596,18 +1837,6 @@ MaybeHandle<FixedArray> WasmCompiledModule::CheckBreakPoints(int position) {
return isolate->debug()->GetHitBreakPointObjects(breakpoint_objects);
}
Handle<Code> WasmCompiledModule::CompileLazy(
Isolate* isolate, Handle<WasmInstanceObject> instance, Handle<Code> caller,
int offset, int func_index, bool patch_caller) {
isolate->set_context(*instance->compiled_module()->native_context());
Object* orch_obj =
instance->compiled_module()->shared()->lazy_compilation_orchestrator();
auto* orch =
Managed<wasm::LazyCompilationOrchestrator>::cast(orch_obj)->get();
return orch->CompileLazy(isolate, instance, caller, offset, func_index,
patch_caller);
}
void AttachWasmFunctionInfo(Isolate* isolate, Handle<Code> code,
MaybeHandle<WeakCell> weak_instance,
int func_index) {

View File

@ -22,6 +22,8 @@ namespace v8 {
namespace internal {
namespace wasm {
class InterpretedFrame;
class NativeModule;
class WasmCode;
class WasmInterpreter;
struct WasmModule;
class SignatureMap;
@ -228,7 +230,8 @@ class WasmInstanceObject : public JSObject {
// Assumed to be called with a code object associated to a wasm module
// instance. Intended to be called from runtime functions. Returns nullptr on
// failing to get owning instance.
static WasmInstanceObject* GetOwningInstance(Code* code);
static WasmInstanceObject* GetOwningInstance(const wasm::WasmCode* code);
static WasmInstanceObject* GetOwningInstanceGC(Code* code);
static void ValidateInstancesChainForTesting(
Isolate* isolate, Handle<WasmModuleObject> module_obj,
@ -253,7 +256,7 @@ class WasmExportedFunction : public JSFunction {
int func_index, int arity,
Handle<Code> export_wrapper);
Handle<Code> GetWasmCode();
WasmCodeWrapper GetWasmCode();
};
// Information shared by all WasmCompiledModule objects for the same module.
@ -305,9 +308,7 @@ class WasmSharedModuleData : public FixedArray {
Handle<SeqOneByteString> module_bytes, Handle<Script> script,
Handle<ByteArray> asm_js_offset_table);
private:
DECL_OPTIONAL_ACCESSORS(lazy_compilation_orchestrator, Foreign)
friend class WasmCompiledModule;
};
// This represents the set of wasm compiled functions, together
@ -403,6 +404,8 @@ class WasmCompiledModule : public FixedArray {
MACRO(CONST_OBJECT, FixedArray, empty_signature_tables) \
MACRO(SMALL_CONST_NUMBER, uint32_t, initial_pages)
// TODO(mtrofin): this is unnecessary when we stop needing
// FLAG_wasm_jit_to_native, because we have instance_id on NativeModule.
#if DEBUG
#define DEBUG_ONLY_TABLE(MACRO) MACRO(SMALL_CONST_NUMBER, uint32_t, instance_id)
#else
@ -426,8 +429,8 @@ class WasmCompiledModule : public FixedArray {
public:
static Handle<WasmCompiledModule> New(
Isolate* isolate, Handle<WasmSharedModuleData> shared,
Handle<FixedArray> code_table, Handle<FixedArray> export_wrappers,
Isolate* isolate, wasm::WasmModule* module, Handle<FixedArray> code_table,
Handle<FixedArray> export_wrappers,
const std::vector<wasm::GlobalHandleAddress>& function_tables,
const std::vector<wasm::GlobalHandleAddress>& signature_tables);
@ -435,9 +438,15 @@ class WasmCompiledModule : public FixedArray {
Handle<WasmCompiledModule> module);
static void Reset(Isolate* isolate, WasmCompiledModule* module);
// TODO(mtrofin): delete this when we don't need FLAG_wasm_jit_to_native
static void ResetGCModel(Isolate* isolate, WasmCompiledModule* module);
uint32_t default_mem_size() const;
wasm::NativeModule* GetNativeModule() const;
void InsertInChain(WasmModuleObject*);
void RemoveFromChain();
void OnWasmModuleDecodingComplete(Handle<WasmSharedModuleData>);
#define DECLARATION(KIND, TYPE, NAME) WCM_##KIND(TYPE, NAME)
WCM_PROPERTY_TABLE(DECLARATION)
@ -539,23 +548,16 @@ class WasmCompiledModule : public FixedArray {
// FixedArray with all hit breakpoint objects.
MaybeHandle<FixedArray> CheckBreakPoints(int position);
// Compile lazily the function called in the given caller code object at the
// given offset.
// If the called function cannot be determined from the caller (indirect
// call / exported function), func_index must be set. Otherwise it can be -1.
// If patch_caller is set, then all direct calls to functions which were
// already lazily compiled are patched (at least the given call site).
// Returns the Code to be called at the given call site.
static Handle<Code> CompileLazy(Isolate*, Handle<WasmInstanceObject>,
Handle<Code> caller, int offset,
int func_index, bool patch_caller);
inline void ReplaceCodeTableForTesting(Handle<FixedArray> testing_table);
inline void ReplaceCodeTableForTesting(
std::vector<wasm::WasmCode*>&& testing_table);
// TODO(mtrofin): following 4 unnecessary after we're done with
// FLAG_wasm_jit_to_native
static void SetTableValue(Isolate* isolate, Handle<FixedArray> table,
int index, Address value);
static void UpdateTableValue(FixedArray* table, int index, Address value);
static Address GetTableValue(FixedArray* table, int index);
inline void ReplaceCodeTableForTesting(Handle<FixedArray> testing_table);
private:
void InitId();

View File

@ -0,0 +1,687 @@
// Copyright 2017 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.
#include "src/wasm/wasm-serialization.h"
#include "src/assembler-inl.h"
#include "src/code-stubs.h"
#include "src/external-reference-table.h"
#include "src/objects-inl.h"
#include "src/objects.h"
#include "src/snapshot/serializer-common.h"
#include "src/version.h"
#include "src/wasm/module-compiler.h"
#include "src/wasm/module-decoder.h"
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-objects-inl.h"
#include "src/wasm/wasm-objects.h"
#include "src/wasm/wasm-result.h"
namespace v8 {
namespace internal {
namespace wasm {
namespace {
void SetRawTargetData(RelocInfo* rinfo, uint32_t value) {
if (rinfo->target_address_size() == sizeof(uint32_t)) {
*(reinterpret_cast<uint32_t*>(rinfo->target_address_address())) = value;
return;
} else {
DCHECK_EQ(rinfo->target_address_size(), sizeof(intptr_t));
DCHECK_EQ(rinfo->target_address_size(), 8);
*(reinterpret_cast<intptr_t*>(rinfo->target_address_address())) =
static_cast<intptr_t>(value);
return;
}
}
class Writer {
public:
explicit Writer(Vector<byte> buffer) : buffer_(buffer) {}
template <typename T>
void Write(const T& value) {
if (FLAG_wasm_trace_serialization) {
OFStream os(stdout);
os << "wrote: " << (size_t)value << " sized: " << sizeof(T) << std::endl;
}
DCHECK_GE(buffer_.size(), sizeof(T));
memcpy(buffer_.start(), reinterpret_cast<const byte*>(&value), sizeof(T));
buffer_ = buffer_ + sizeof(T);
}
void WriteVector(const Vector<const byte> data) {
DCHECK_GE(buffer_.size(), data.size());
if (data.size() > 0) {
memcpy(buffer_.start(), data.start(), data.size());
buffer_ = buffer_ + data.size();
}
if (FLAG_wasm_trace_serialization) {
OFStream os(stdout);
os << "wrote vector of " << data.size() << " elements" << std::endl;
}
}
Vector<byte> current_buffer() const { return buffer_; }
private:
Vector<byte> buffer_;
};
class Reader {
public:
explicit Reader(Vector<const byte> buffer) : buffer_(buffer) {}
template <typename T>
T Read() {
DCHECK_GE(buffer_.size(), sizeof(T));
T ret;
memcpy(reinterpret_cast<byte*>(&ret), buffer_.start(), sizeof(T));
buffer_ = buffer_ + sizeof(T);
if (FLAG_wasm_trace_serialization) {
OFStream os(stdout);
os << "read: " << (size_t)ret << " sized: " << sizeof(T) << std::endl;
}
return ret;
}
Vector<const byte> GetSubvector(size_t size) {
Vector<const byte> ret = {buffer_.start(), size};
buffer_ = buffer_ + size;
return ret;
}
void ReadIntoVector(const Vector<byte> data) {
if (data.size() > 0) {
DCHECK_GE(buffer_.size(), data.size());
memcpy(data.start(), buffer_.start(), data.size());
buffer_ = buffer_ + data.size();
}
if (FLAG_wasm_trace_serialization) {
OFStream os(stdout);
os << "read vector of " << data.size() << " elements" << std::endl;
}
}
Vector<const byte> current_buffer() const { return buffer_; }
private:
Vector<const byte> buffer_;
};
} // namespace
size_t WasmSerializedFormatVersion::GetVersionSize() { return kVersionSize; }
bool WasmSerializedFormatVersion::WriteVersion(Isolate* isolate,
Vector<byte> buffer) {
if (buffer.size() < GetVersionSize()) return false;
Writer writer(buffer);
writer.Write(SerializedData::ComputeMagicNumber(
ExternalReferenceTable::instance(isolate)));
writer.Write(Version::Hash());
writer.Write(static_cast<uint32_t>(CpuFeatures::SupportedFeatures()));
writer.Write(FlagList::Hash());
return true;
}
bool WasmSerializedFormatVersion::IsSupportedVersion(
Isolate* isolate, const Vector<const byte> buffer) {
if (buffer.size() < kVersionSize) return false;
byte version[kVersionSize];
CHECK(WriteVersion(isolate, {version, kVersionSize}));
if (memcmp(buffer.start(), version, kVersionSize) == 0) return true;
return false;
}
NativeModuleSerializer::NativeModuleSerializer(Isolate* isolate,
const NativeModule* module)
: isolate_(isolate), native_module_(module) {
DCHECK_NOT_NULL(isolate_);
DCHECK_NOT_NULL(native_module_);
DCHECK_NULL(native_module_->lazy_builtin_);
// TODO(mtrofin): persist the export wrappers. Ideally, we'd only persist
// the unique ones, i.e. the cache.
ExternalReferenceTable* table = ExternalReferenceTable::instance(isolate_);
for (uint32_t i = 0; i < table->size(); ++i) {
Address addr = table->address(i);
reference_table_lookup_.insert(std::make_pair(addr, i));
}
// defer populating the stub_lookup_ to when we buffer the stubs
for (auto pair : native_module_->trampolines_) {
v8::internal::Code* code = Code::GetCodeFromTargetAddress(pair.first);
int builtin_index = code->builtin_index();
if (builtin_index >= 0) {
uint32_t tag = static_cast<uint32_t>(builtin_index);
builtin_lookup_.insert(std::make_pair(pair.second, tag));
}
}
BufferHeader();
state_ = Metadata;
}
size_t NativeModuleSerializer::MeasureHeader() const {
return sizeof(uint32_t) + // total wasm fct count
sizeof(
uint32_t) + // imported fcts - i.e. index of first wasm function
sizeof(uint32_t) + // table count
native_module_->specialization_data_.function_tables.size() *
2 // 2 same-sized tables, containing pointers
* sizeof(GlobalHandleAddress);
}
void NativeModuleSerializer::BufferHeader() {
size_t metadata_size = MeasureHeader();
scratch_.resize(metadata_size);
remaining_ = {scratch_.data(), metadata_size};
Writer writer(remaining_);
writer.Write(native_module_->FunctionCount());
writer.Write(native_module_->num_imported_functions());
writer.Write(static_cast<uint32_t>(
native_module_->specialization_data_.function_tables.size()));
for (size_t i = 0,
e = native_module_->specialization_data_.function_tables.size();
i < e; ++i) {
writer.Write(native_module_->specialization_data_.function_tables[i]);
writer.Write(native_module_->specialization_data_.signature_tables[i]);
}
}
size_t NativeModuleSerializer::GetCodeHeaderSize() {
return sizeof(size_t) + // size of this section
sizeof(size_t) + // offset of constant pool
sizeof(size_t) + // offset of safepoint table
sizeof(uint32_t) + // stack slots
sizeof(size_t) + // code size
sizeof(size_t) + // reloc size
sizeof(uint32_t) + // handler size
sizeof(uint32_t) + // source positions size
sizeof(size_t) + // protected instructions size
sizeof(bool); // is_liftoff
}
size_t NativeModuleSerializer::MeasureCode(const WasmCode* code) const {
FixedArray* handler_table = GetHandlerTable(code);
ByteArray* source_positions = GetSourcePositions(code);
return GetCodeHeaderSize() + code->instructions().size() + // code
code->reloc_info().size() + // reloc info
(handler_table == nullptr
? 0
: static_cast<uint32_t>(
handler_table->length())) + // handler table
(source_positions == nullptr
? 0
: static_cast<uint32_t>(
source_positions->length())) + // source positions
code->protected_instructions().size() *
sizeof(trap_handler::ProtectedInstructionData);
}
size_t NativeModuleSerializer::Measure() const {
size_t ret = MeasureHeader() + MeasureCopiedStubs();
for (uint32_t i = native_module_->num_imported_functions(),
e = native_module_->FunctionCount();
i < e; ++i) {
ret += MeasureCode(native_module_->GetCode(i));
}
return ret;
}
size_t NativeModuleSerializer::DrainBuffer(Vector<byte> dest) {
size_t to_write = std::min(dest.size(), remaining_.size());
memcpy(dest.start(), remaining_.start(), to_write);
DCHECK_GE(remaining_.size(), to_write);
remaining_ = remaining_ + to_write;
return to_write;
}
size_t NativeModuleSerializer::MeasureCopiedStubs() const {
size_t ret = sizeof(uint32_t) + // number of stubs
native_module_->stubs_.size() * sizeof(uint32_t); // stub keys
for (auto pair : native_module_->trampolines_) {
v8::internal::Code* code = Code::GetCodeFromTargetAddress(pair.first);
int builtin_index = code->builtin_index();
if (builtin_index < 0) ret += sizeof(uint32_t);
}
return ret;
}
void NativeModuleSerializer::BufferCopiedStubs() {
// We buffer all the stubs together, because they are very likely
// few and small. Each stub is buffered like a WasmCode would,
// and in addition prefaced by its stub key. The whole section is prefaced
// by the number of stubs.
size_t buff_size = MeasureCopiedStubs();
scratch_.resize(buff_size);
remaining_ = {scratch_.data(), buff_size};
Writer writer(remaining_);
writer.Write(
static_cast<uint32_t>((buff_size - sizeof(uint32_t)) / sizeof(uint32_t)));
uint32_t stub_id = 0;
for (auto pair : native_module_->stubs_) {
uint32_t key = pair.first;
writer.Write(key);
stub_lookup_.insert(
std::make_pair(pair.second->instructions().start(), stub_id));
++stub_id;
}
for (auto pair : native_module_->trampolines_) {
v8::internal::Code* code = Code::GetCodeFromTargetAddress(pair.first);
int builtin_index = code->builtin_index();
if (builtin_index < 0) {
stub_lookup_.insert(std::make_pair(pair.second, stub_id));
writer.Write(code->stub_key());
++stub_id;
}
}
}
FixedArray* NativeModuleSerializer::GetHandlerTable(
const WasmCode* code) const {
if (code->kind() != WasmCode::Function) return nullptr;
uint32_t index = code->index();
// We write the address, the size, and then copy the code as-is, followed
// by reloc info, followed by handler table and source positions.
Object* handler_table_entry =
native_module_->compiled_module()->handler_table()->get(
static_cast<int>(index));
if (handler_table_entry->IsFixedArray()) {
return FixedArray::cast(handler_table_entry);
}
return nullptr;
}
ByteArray* NativeModuleSerializer::GetSourcePositions(
const WasmCode* code) const {
if (code->kind() != WasmCode::Function) return nullptr;
uint32_t index = code->index();
Object* source_positions_entry =
native_module_->compiled_module()->source_positions()->get(
static_cast<int>(index));
if (source_positions_entry->IsByteArray()) {
return ByteArray::cast(source_positions_entry);
}
return nullptr;
}
void NativeModuleSerializer::BufferCurrentWasmCode() {
const WasmCode* code = native_module_->GetCode(index_);
size_t size = MeasureCode(code);
scratch_.resize(size);
remaining_ = {scratch_.data(), size};
BufferCodeInAllocatedScratch(code);
}
void NativeModuleSerializer::BufferCodeInAllocatedScratch(
const WasmCode* code) {
// We write the address, the size, and then copy the code as-is, followed
// by reloc info, followed by handler table and source positions.
FixedArray* handler_table_entry = GetHandlerTable(code);
uint32_t handler_table_size = 0;
Address handler_table = nullptr;
if (handler_table_entry != nullptr) {
handler_table_size = static_cast<uint32_t>(handler_table_entry->length());
handler_table = reinterpret_cast<Address>(
handler_table_entry->GetFirstElementAddress());
}
ByteArray* source_positions_entry = GetSourcePositions(code);
Address source_positions = nullptr;
uint32_t source_positions_size = 0;
if (source_positions_entry != nullptr) {
source_positions = source_positions_entry->GetDataStartAddress();
source_positions_size =
static_cast<uint32_t>(source_positions_entry->length());
}
Writer writer(remaining_);
// write the header
writer.Write(MeasureCode(code));
writer.Write(code->constant_pool_offset());
writer.Write(code->safepoint_table_offset());
writer.Write(code->stack_slots());
writer.Write(code->instructions().size());
writer.Write(code->reloc_info().size());
writer.Write(handler_table_size);
writer.Write(source_positions_size);
writer.Write(code->protected_instructions().size());
writer.Write(code->is_liftoff());
// next is the code, which we have to reloc.
Address serialized_code_start = writer.current_buffer().start();
// write the code and everything else
writer.WriteVector(code->instructions());
writer.WriteVector(code->reloc_info());
writer.WriteVector({handler_table, handler_table_size});
writer.WriteVector({source_positions, source_positions_size});
writer.WriteVector(
{reinterpret_cast<const byte*>(code->protected_instructions().data()),
sizeof(trap_handler::ProtectedInstructionData) *
code->protected_instructions().size()});
// now relocate the code
int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
RelocInfo::ModeMask(RelocInfo::WASM_CALL) |
RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
RelocIterator orig_iter(code->instructions(), code->reloc_info(),
code->constant_pool(), mask);
for (RelocIterator
iter({serialized_code_start, code->instructions().size()},
code->reloc_info(),
serialized_code_start + code->constant_pool_offset(), mask);
!iter.done(); iter.next(), orig_iter.next()) {
RelocInfo::Mode mode = orig_iter.rinfo()->rmode();
switch (mode) {
case RelocInfo::CODE_TARGET: {
Address orig_target = orig_iter.rinfo()->target_address();
uint32_t tag = EncodeBuiltinOrStub(orig_target);
SetRawTargetData(iter.rinfo(), tag);
} break;
case RelocInfo::WASM_CALL: {
Address orig_target = orig_iter.rinfo()->wasm_call_address();
uint32_t tag = wasm_targets_lookup_[orig_target];
SetRawTargetData(iter.rinfo(), tag);
} break;
case RelocInfo::RUNTIME_ENTRY: {
Address orig_target = orig_iter.rinfo()->target_address();
uint32_t tag = reference_table_lookup_[orig_target];
SetRawTargetData(iter.rinfo(), tag);
} break;
default:
UNREACHABLE();
}
}
}
uint32_t NativeModuleSerializer::EncodeBuiltinOrStub(Address address) {
auto builtin_iter = builtin_lookup_.find(address);
uint32_t tag = 0;
if (builtin_iter != builtin_lookup_.end()) {
uint32_t id = builtin_iter->second;
DCHECK_LT(id, std::numeric_limits<uint16_t>::max());
tag = id << 16;
} else {
auto stub_iter = stub_lookup_.find(address);
DCHECK(stub_iter != stub_lookup_.end());
uint32_t id = stub_iter->second;
DCHECK_LT(id, std::numeric_limits<uint16_t>::max());
tag = id & 0x0000ffff;
}
return tag;
}
size_t NativeModuleSerializer::Write(Vector<byte> dest) {
Vector<byte> original = dest;
while (dest.size() > 0) {
switch (state_) {
case Metadata: {
dest = dest + DrainBuffer(dest);
if (remaining_.size() == 0) {
BufferCopiedStubs();
state_ = Stubs;
}
break;
}
case Stubs: {
dest = dest + DrainBuffer(dest);
if (remaining_.size() == 0) {
index_ = native_module_->num_imported_functions();
BufferCurrentWasmCode();
state_ = CodeSection;
}
break;
}
case CodeSection: {
dest = dest + DrainBuffer(dest);
if (remaining_.size() == 0) {
if (++index_ < native_module_->FunctionCount()) {
BufferCurrentWasmCode();
} else {
state_ = Done;
}
}
break;
}
default:
UNREACHABLE();
}
}
DCHECK_GE(original.size(), dest.size());
return original.size() - dest.size();
}
// static
std::pair<std::unique_ptr<byte[]>, size_t>
NativeModuleSerializer::SerializeWholeModule(
Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
NativeModule* native_module = compiled_module->GetNativeModule();
NativeModuleSerializer serializer(isolate, native_module);
size_t version_size = WasmSerializedFormatVersion::GetVersionSize();
size_t buff_size = serializer.Measure() + version_size;
std::unique_ptr<byte[]> ret(new byte[buff_size]);
if (!WasmSerializedFormatVersion::WriteVersion(isolate,
{ret.get(), buff_size})) {
return {};
}
size_t written =
serializer.Write({ret.get() + version_size, buff_size - version_size});
if (written != buff_size - version_size) return {};
return {std::move(ret), buff_size};
}
NativeModuleDeserializer::NativeModuleDeserializer(Isolate* isolate,
NativeModule* native_module)
: isolate_(isolate), native_module_(native_module) {}
void NativeModuleDeserializer::Expect(size_t size) {
scratch_.resize(size);
current_expectation_ = size;
unread_ = {scratch_.data(), size};
}
bool NativeModuleDeserializer::Read(Vector<const byte> data) {
unread_ = data;
if (!ReadHeader()) return false;
if (!ReadStubs()) return false;
index_ = native_module_->num_imported_functions();
for (; index_ < native_module_->FunctionCount(); ++index_) {
if (!ReadCode()) return false;
}
native_module_->LinkAll();
return data.size() - unread_.size();
}
bool NativeModuleDeserializer::ReadHeader() {
size_t start_size = unread_.size();
Reader reader(unread_);
size_t functions = reader.Read<uint32_t>();
size_t imports = reader.Read<uint32_t>();
bool ok = functions == native_module_->FunctionCount() &&
imports == native_module_->num_imported_functions();
if (!ok) return false;
size_t table_count = reader.Read<uint32_t>();
std::vector<GlobalHandleAddress> sigs(table_count);
std::vector<GlobalHandleAddress> funcs(table_count);
for (size_t i = 0; i < table_count; ++i) {
funcs[i] = reader.Read<GlobalHandleAddress>();
sigs[i] = reader.Read<GlobalHandleAddress>();
}
native_module_->signature_tables() = sigs;
native_module_->function_tables() = funcs;
// resize, so that from here on the native module can be
// asked about num_function_tables().
native_module_->empty_function_tables().resize(table_count);
native_module_->empty_signature_tables().resize(table_count);
unread_ = unread_ + (start_size - reader.current_buffer().size());
return true;
}
bool NativeModuleDeserializer::ReadStubs() {
size_t start_size = unread_.size();
Reader reader(unread_);
size_t nr_stubs = reader.Read<uint32_t>();
stubs_.reserve(nr_stubs);
for (size_t i = 0; i < nr_stubs; ++i) {
uint32_t key = reader.Read<uint32_t>();
v8::internal::Code* stub =
*(v8::internal::CodeStub::GetCode(isolate_, key).ToHandleChecked());
stubs_.push_back(native_module_->GetLocalAddressFor(handle(stub)));
}
unread_ = unread_ + (start_size - reader.current_buffer().size());
return true;
}
bool NativeModuleDeserializer::ReadCode() {
size_t start_size = unread_.size();
Reader reader(unread_);
size_t code_section_size = reader.Read<size_t>();
USE(code_section_size);
size_t constant_pool_offset = reader.Read<size_t>();
size_t safepoint_table_offset = reader.Read<size_t>();
uint32_t stack_slot_count = reader.Read<uint32_t>();
size_t code_size = reader.Read<size_t>();
size_t reloc_size = reader.Read<size_t>();
uint32_t handler_size = reader.Read<uint32_t>();
uint32_t source_position_size = reader.Read<uint32_t>();
size_t protected_instructions_size = reader.Read<size_t>();
bool is_liftoff = reader.Read<bool>();
std::shared_ptr<ProtectedInstructions> protected_instructions(
new ProtectedInstructions(protected_instructions_size));
DCHECK_EQ(protected_instructions_size, protected_instructions->size());
Vector<const byte> code_buffer = reader.GetSubvector(code_size);
std::unique_ptr<byte[]> reloc_info;
if (reloc_size > 0) {
reloc_info.reset(new byte[reloc_size]);
reader.ReadIntoVector({reloc_info.get(), reloc_size});
}
WasmCode* ret = native_module_->AddOwnedCode(
code_buffer, std::move(reloc_info), reloc_size, Just(index_),
WasmCode::Function, constant_pool_offset, stack_slot_count,
safepoint_table_offset, protected_instructions, is_liftoff);
if (ret == nullptr) return false;
native_module_->SetCodeTable(index_, ret);
// now relocate the code
int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
for (RelocIterator iter(ret->instructions(), ret->reloc_info(),
ret->constant_pool(), mask);
!iter.done(); iter.next()) {
RelocInfo::Mode mode = iter.rinfo()->rmode();
switch (mode) {
case RelocInfo::EMBEDDED_OBJECT: {
// We only expect {undefined}. We check for that when we add code.
iter.rinfo()->set_target_object(isolate_->heap()->undefined_value(),
SKIP_WRITE_BARRIER);
}
case RelocInfo::CODE_TARGET: {
uint32_t tag = *(reinterpret_cast<uint32_t*>(
iter.rinfo()->target_address_address()));
Address target = GetTrampolineOrStubFromTag(tag);
iter.rinfo()->set_target_address(nullptr, target, SKIP_WRITE_BARRIER,
SKIP_ICACHE_FLUSH);
} break;
case RelocInfo::RUNTIME_ENTRY: {
uint32_t orig_target = static_cast<uint32_t>(
reinterpret_cast<intptr_t>(iter.rinfo()->target_address()));
Address address =
ExternalReferenceTable::instance(isolate_)->address(orig_target);
iter.rinfo()->set_target_runtime_entry(
nullptr, address, SKIP_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
} break;
default:
break;
}
}
if (handler_size > 0) {
Handle<FixedArray> handler_table = isolate_->factory()->NewFixedArray(
static_cast<int>(handler_size), TENURED);
reader.ReadIntoVector(
{reinterpret_cast<Address>(handler_table->GetFirstElementAddress()),
handler_size});
native_module_->compiled_module()->handler_table()->set(
static_cast<int>(index_), *handler_table);
}
if (source_position_size > 0) {
Handle<ByteArray> source_positions = isolate_->factory()->NewByteArray(
static_cast<int>(source_position_size), TENURED);
reader.ReadIntoVector(
{source_positions->GetDataStartAddress(), source_position_size});
native_module_->compiled_module()->source_positions()->set(
static_cast<int>(index_), *source_positions);
}
if (protected_instructions_size > 0) {
reader.ReadIntoVector(
{reinterpret_cast<byte*>(protected_instructions->data()),
sizeof(trap_handler::ProtectedInstructionData) *
protected_instructions->size()});
}
unread_ = unread_ + (start_size - reader.current_buffer().size());
return true;
}
Address NativeModuleDeserializer::GetTrampolineOrStubFromTag(uint32_t tag) {
if ((tag & 0x0000ffff) == 0) {
int builtin_id = static_cast<int>(tag >> 16);
v8::internal::Code* builtin = isolate_->builtins()->builtin(builtin_id);
return native_module_->GetLocalAddressFor(handle(builtin));
} else {
DCHECK_EQ(tag & 0xffff0000, 0);
return stubs_[tag];
}
}
MaybeHandle<WasmCompiledModule> NativeModuleDeserializer::DeserializeFullBuffer(
Isolate* isolate, Vector<const byte> data, Vector<const byte> wire_bytes) {
if (!IsWasmCodegenAllowed(isolate, isolate->native_context())) {
return {};
}
if (!WasmSerializedFormatVersion::IsSupportedVersion(isolate, data)) {
return {};
}
data = data + WasmSerializedFormatVersion::GetVersionSize();
ModuleResult decode_result =
SyncDecodeWasmModule(isolate, wire_bytes.start(), wire_bytes.end(), false,
i::wasm::kWasmOrigin);
if (!decode_result.ok()) return {};
CHECK_NOT_NULL(decode_result.val);
Handle<String> module_bytes =
isolate->factory()
->NewStringFromOneByte(
{wire_bytes.start(), static_cast<size_t>(wire_bytes.length())},
TENURED)
.ToHandleChecked();
DCHECK(module_bytes->IsSeqOneByteString());
// The {module_wrapper} will take ownership of the {WasmModule} object,
// and it will be destroyed when the GC reclaims the wrapper object.
Handle<WasmModuleWrapper> module_wrapper =
WasmModuleWrapper::From(isolate, decode_result.val.release());
Handle<Script> script = CreateWasmScript(isolate, wire_bytes);
Handle<WasmSharedModuleData> shared = WasmSharedModuleData::New(
isolate, module_wrapper, Handle<SeqOneByteString>::cast(module_bytes),
script, Handle<ByteArray>::null());
int export_wrappers_size =
static_cast<int>(shared->module()->num_exported_functions);
Handle<FixedArray> export_wrappers = isolate->factory()->NewFixedArray(
static_cast<int>(export_wrappers_size), TENURED);
Handle<WasmCompiledModule> compiled_module = WasmCompiledModule::New(
isolate, shared->module(), isolate->factory()->NewFixedArray(0, TENURED),
export_wrappers, {}, {});
compiled_module->OnWasmModuleDecodingComplete(shared);
NativeModuleDeserializer deserializer(isolate,
compiled_module->GetNativeModule());
if (!deserializer.Read(data)) return {};
CompileJsToWasmWrappers(isolate, compiled_module, isolate->counters());
WasmCompiledModule::ReinitializeAfterDeserialization(isolate,
compiled_module);
return compiled_module;
}
} // namespace wasm
} // namespace internal
} // namespace v8

View File

@ -0,0 +1,96 @@
// Copyright 2017 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.
#ifndef V8_WASM_SERIALIZATION_H_
#define V8_WASM_SERIALIZATION_H_
#include "src/wasm/wasm-heap.h"
#include "src/wasm/wasm-objects.h"
namespace v8 {
namespace internal {
namespace wasm {
class WasmSerializedFormatVersion {
public:
static size_t GetVersionSize();
static bool WriteVersion(Isolate* isolate, Vector<byte>);
static bool IsSupportedVersion(Isolate* isolate, const Vector<const byte>);
private:
static constexpr size_t kVersionSize = 4 * sizeof(uint32_t);
};
enum SerializationSection { Init, Metadata, Stubs, CodeSection, Done };
class V8_EXPORT_PRIVATE NativeModuleSerializer {
public:
explicit NativeModuleSerializer(Isolate*, const NativeModule*);
size_t Measure() const;
size_t Write(Vector<byte>);
bool IsDone() const { return state_ == Done; }
static std::pair<std::unique_ptr<byte[]>, size_t> SerializeWholeModule(
Isolate*, Handle<WasmCompiledModule>);
private:
size_t MeasureHeader() const;
static size_t GetCodeHeaderSize();
size_t MeasureCode(const WasmCode*) const;
size_t MeasureCopiedStubs() const;
FixedArray* GetHandlerTable(const WasmCode*) const;
ByteArray* GetSourcePositions(const WasmCode*) const;
void BufferHeader();
// we buffer all the stubs because they are small
void BufferCopiedStubs();
void BufferCodeInAllocatedScratch(const WasmCode*);
void BufferCurrentWasmCode();
size_t DrainBuffer(Vector<byte> dest);
uint32_t EncodeBuiltinOrStub(Address);
Isolate* const isolate_ = nullptr;
const NativeModule* const native_module_ = nullptr;
SerializationSection state_ = Init;
uint32_t index_ = 0;
std::vector<byte> scratch_;
Vector<byte> remaining_;
// wasm and copied stubs reverse lookup
std::map<Address, uint32_t> wasm_targets_lookup_;
// immovable builtins and runtime entries lookup
std::map<Address, uint32_t> reference_table_lookup_;
std::map<Address, uint32_t> stub_lookup_;
std::map<Address, uint32_t> builtin_lookup_;
};
class V8_EXPORT_PRIVATE NativeModuleDeserializer {
public:
explicit NativeModuleDeserializer(Isolate*, NativeModule*);
// Currently, we don't support streamed reading, yet albeit the
// API suggests that.
bool Read(Vector<const byte>);
static MaybeHandle<WasmCompiledModule> DeserializeFullBuffer(
Isolate*, Vector<const byte> data, Vector<const byte> wire_bytes);
private:
void ExpectHeader();
void Expect(size_t size);
bool ReadHeader();
bool ReadCode();
bool ReadStubs();
Address GetTrampolineOrStubFromTag(uint32_t);
Isolate* const isolate_ = nullptr;
NativeModule* const native_module_ = nullptr;
std::vector<byte> scratch_;
std::vector<Address> stubs_;
Vector<const byte> unread_;
size_t current_expectation_ = 0;
uint32_t index_ = 0;
};
} // namespace wasm
} // namespace internal
} // namespace v8
#endif

View File

@ -62,7 +62,12 @@ class CWasmEntryArgTester {
Handle<Object> buffer_obj(reinterpret_cast<Object*>(arg_buffer.data()),
isolate_);
CHECK(!buffer_obj->IsHeapObject());
Handle<Object> call_args[]{wasm_code_, buffer_obj};
Handle<Object> call_args[]{
(FLAG_wasm_jit_to_native
? Handle<Object>::cast(isolate_->factory()->NewForeign(
wasm_code_.GetWasmCode()->instructions().start(), TENURED))
: Handle<Object>::cast(wasm_code_.GetCode())),
buffer_obj};
static_assert(
arraysize(call_args) == compiler::CWasmEntryParameters::kNumParameters,
"adapt this test");
@ -88,7 +93,7 @@ class CWasmEntryArgTester {
std::function<ReturnType(Args...)> expected_fn_;
FunctionSig* sig_;
Handle<JSFunction> c_wasm_entry_fn_;
Handle<Code> wasm_code_;
WasmCodeWrapper wasm_code_;
};
} // namespace

View File

@ -256,7 +256,7 @@ class WasmSerializationTest {
uint32_t* slot = reinterpret_cast<uint32_t*>(
const_cast<uint8_t*>(serialized_bytes_.first) +
SerializedCodeData::kPayloadLengthOffset);
*slot = 0xfefefefeu;
*slot = FLAG_wasm_jit_to_native ? 0u : 0xfefefefeu;
}
v8::MaybeLocal<v8::WasmCompiledModule> Deserialize() {

View File

@ -47,6 +47,7 @@ class ArgPassingHelper {
runner.Build(outer_code.data(), outer_code.data() + outer_code.size());
int funcs_to_redict[] = {static_cast<int>(inner_compiler.function_index())};
runner.builder().Link();
WasmDebugInfo::RedirectToInterpreter(debug_info_,
ArrayVector(funcs_to_redict));
main_fun_wrapper_ = runner.builder().WrapCode(runner.function_index());

View File

@ -66,14 +66,16 @@ byte* TestingModuleBuilder::AddMemory(uint32_t size) {
return mem_start_;
}
uint32_t TestingModuleBuilder::AddFunction(FunctionSig* sig, Handle<Code> code,
const char* name) {
uint32_t TestingModuleBuilder::AddFunction(FunctionSig* sig, const char* name) {
if (test_module_.functions.size() == 0) {
// TODO(titzer): Reserving space here to avoid the underlying WasmFunction
// structs from moving.
test_module_.functions.reserve(kMaxFunctions);
}
uint32_t index = static_cast<uint32_t>(test_module_.functions.size());
if (FLAG_wasm_jit_to_native) {
native_module_->ResizeCodeTableForTest(index);
}
test_module_.functions.push_back(
{sig, index, 0, {0, 0}, {0, 0}, false, false});
if (name) {
@ -81,7 +83,7 @@ uint32_t TestingModuleBuilder::AddFunction(FunctionSig* sig, Handle<Code> code,
test_module_.functions.back().name = {
AddBytes(name_vec), static_cast<uint32_t>(name_vec.length())};
}
function_code_.push_back(code);
function_code_.push_back(Handle<Code>::null());
if (interpreter_) {
interpreter_->AddFunctionForTesting(&test_module_.functions.back());
}
@ -93,19 +95,30 @@ uint32_t TestingModuleBuilder::AddJsFunction(
FunctionSig* sig, const char* source, Handle<FixedArray> js_imports_table) {
Handle<JSFunction> jsfunc = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
*v8::Local<v8::Function>::Cast(CompileRun(source))));
uint32_t index = AddFunction(sig, Handle<Code>::null(), nullptr);
uint32_t index = AddFunction(sig, nullptr);
js_imports_table->set(0, *isolate_->native_context());
// TODO(6792): No longer needed once WebAssembly code is off heap.
CodeSpaceMemoryModificationScope modification_scope(isolate_->heap());
Handle<Code> code = compiler::CompileWasmToJSWrapper(
isolate_, jsfunc, sig, index, test_module_.origin(), js_imports_table);
function_code_[index] = code;
if (FLAG_wasm_jit_to_native) {
native_module_->ResizeCodeTableForTest(index);
Handle<Code> wrapper = compiler::CompileWasmToJSWrapper(
isolate_, jsfunc, sig, index, test_module_.origin(), js_imports_table);
native_module_->AddCodeCopy(wrapper, wasm::WasmCode::WasmToJsWrapper,
index);
} else {
// TODO(6792): No longer needed once WebAssembly code is off heap.
CodeSpaceMemoryModificationScope modification_scope(isolate_->heap());
Handle<Code> code = compiler::CompileWasmToJSWrapper(
isolate_, jsfunc, sig, index, test_module_.origin(), js_imports_table);
function_code_[index] = code;
}
return index;
}
Handle<JSFunction> TestingModuleBuilder::WrapCode(uint32_t index) {
// Wrap the code so it can be called as a JS function.
Handle<Code> code = function_code_[index];
Link();
WasmCodeWrapper code = FLAG_wasm_jit_to_native
? WasmCodeWrapper(native_module_->GetCode(index))
: WasmCodeWrapper(function_code_[index]);
byte* context_address =
test_module_.has_memory
? reinterpret_cast<byte*>(instance_object_->wasm_context())
@ -167,7 +180,16 @@ void TestingModuleBuilder::PopulateIndirectFunctionTable() {
WasmFunction& function = test_module_.functions[table.values[j]];
signature_table->set(
j, Smi::FromInt(test_module_.signature_map.Find(function.sig)));
function_table->set(j, *function_code_[function.func_index]);
if (FLAG_wasm_jit_to_native) {
Handle<Foreign> foreign_holder = isolate_->factory()->NewForeign(
native_module_->GetCode(function.func_index)
->instructions()
.start(),
TENURED);
function_table->set(j, *foreign_holder);
} else {
function_table->set(j, *function_code_[function.func_index]);
}
}
}
}
@ -221,14 +243,22 @@ Handle<WasmInstanceObject> TestingModuleBuilder::InitInstanceObject() {
Handle<FixedArray> code_table = isolate_->factory()->NewFixedArray(0);
Handle<FixedArray> export_wrappers = isolate_->factory()->NewFixedArray(0);
Handle<WasmCompiledModule> compiled_module = WasmCompiledModule::New(
isolate_, shared_module_data, code_table, export_wrappers,
function_tables_, signature_tables_);
isolate_, test_module_ptr_, code_table, export_wrappers, function_tables_,
signature_tables_);
compiled_module->OnWasmModuleDecodingComplete(shared_module_data);
// This method is called when we initialize TestEnvironment. We don't
// have a memory yet, so we won't create it here. We'll update the
// interpreter when we get a memory. We do have globals, though.
native_module_ = compiled_module->GetNativeModule();
Handle<FixedArray> weak_exported = isolate_->factory()->NewFixedArray(0);
compiled_module->set_weak_exported_functions(weak_exported);
DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module));
script->set_wasm_compiled_module(*compiled_module);
auto instance = WasmInstanceObject::New(isolate_, compiled_module);
instance->wasm_context()->get()->globals_start = globals_data_;
Handle<WeakCell> weak_instance = isolate()->factory()->NewWeakCell(instance);
compiled_module->set_weak_owning_instance(weak_instance);
return instance;
}
@ -395,6 +425,10 @@ void WasmFunctionCompiler::Build(const byte* start, const byte* end) {
Handle<WasmCompiledModule> compiled_module(
builder_->instance_object()->compiled_module(), isolate());
NativeModule* native_module = compiled_module->GetNativeModule();
if (FLAG_wasm_jit_to_native) {
native_module->ResizeCodeTableForTest(function_->func_index);
}
Handle<SeqOneByteString> wire_bytes(compiled_module->module_bytes(),
isolate());
@ -415,46 +449,52 @@ void WasmFunctionCompiler::Build(const byte* start, const byte* end) {
? compiler::WasmCompilationUnit::CompilationMode::kLiftoff
: compiler::WasmCompilationUnit::CompilationMode::kTurbofan;
compiler::WasmCompilationUnit unit(
isolate(), &module_env, func_body, func_name, function_->func_index,
CEntryStub(isolate(), 1).GetCode(), comp_mode, isolate()->counters(),
builder_->runtime_exception_support(), builder_->lower_simd());
isolate(), &module_env, native_module, func_body, func_name,
function_->func_index, CEntryStub(isolate(), 1).GetCode(), comp_mode,
isolate()->counters(), builder_->runtime_exception_support(),
builder_->lower_simd());
unit.ExecuteCompilation();
MaybeHandle<Code> maybe_code = unit.FinishCompilation(&thrower);
WasmCodeWrapper code_wrapper = unit.FinishCompilation(&thrower);
CHECK(!thrower.error());
Handle<Code> code = maybe_code.ToHandleChecked();
if (!FLAG_wasm_jit_to_native) {
Handle<Code> code = code_wrapper.GetCode();
// TODO(6792): No longer needed once WebAssembly code is off heap.
CodeSpaceMemoryModificationScope modification_scope(isolate()->heap());
// TODO(6792): No longer needed once WebAssembly code is off heap.
CodeSpaceMemoryModificationScope modification_scope(isolate()->heap());
// Manually add the deoptimization info that would otherwise be added
// during instantiation. Deopt data holds <WeakCell<wasm_instance>,
// func_index>.
DCHECK_EQ(0, code->deoptimization_data()->length());
Handle<FixedArray> deopt_data =
isolate()->factory()->NewFixedArray(2, TENURED);
Handle<Object> weak_instance =
isolate()->factory()->NewWeakCell(builder_->instance_object());
deopt_data->set(0, *weak_instance);
deopt_data->set(1, Smi::FromInt(static_cast<int>(function_index())));
code->set_deoptimization_data(*deopt_data);
// Manually add the deoptimization info that would otherwise be added
// during instantiation. Deopt data holds <WeakCell<wasm_instance>,
// func_index>.
DCHECK_EQ(0, code->deoptimization_data()->length());
Handle<FixedArray> deopt_data =
isolate()->factory()->NewFixedArray(2, TENURED);
Handle<Object> weak_instance =
isolate()->factory()->NewWeakCell(builder_->instance_object());
deopt_data->set(0, *weak_instance);
deopt_data->set(1, Smi::FromInt(static_cast<int>(function_index())));
code->set_deoptimization_data(*deopt_data);
// Build the TurboFan graph.
builder_->SetFunctionCode(function_index(), code);
// Build the TurboFan graph.
builder_->SetFunctionCode(function_index(), code);
// Add to code table.
Handle<FixedArray> code_table = compiled_module->code_table();
if (static_cast<int>(function_index()) >= code_table->length()) {
Handle<FixedArray> new_arr = isolate()->factory()->NewFixedArray(
static_cast<int>(function_index()) + 1);
code_table->CopyTo(0, *new_arr, 0, code_table->length());
code_table = new_arr;
compiled_module->ReplaceCodeTableForTesting(code_table);
}
DCHECK(code_table->get(static_cast<int>(function_index()))
->IsUndefined(isolate()));
code_table->set(static_cast<int>(function_index()), *code);
if (trap_handler::UseTrapHandler()) {
UnpackAndRegisterProtectedInstructions(isolate(), code_table);
// Add to code table.
Handle<FixedArray> code_table = compiled_module->code_table();
if (static_cast<int>(function_index()) >= code_table->length()) {
Handle<FixedArray> new_arr = isolate()->factory()->NewFixedArray(
static_cast<int>(function_index()) + 1);
code_table->CopyTo(0, *new_arr, 0, code_table->length());
code_table = new_arr;
compiled_module->ReplaceCodeTableForTesting(code_table);
}
DCHECK(code_table->get(static_cast<int>(function_index()))
->IsUndefined(isolate()));
code_table->set(static_cast<int>(function_index()), *code);
if (trap_handler::UseTrapHandler()) {
UnpackAndRegisterProtectedInstructionsGC(isolate(), code_table);
}
} else {
if (trap_handler::UseTrapHandler()) {
UnpackAndRegisterProtectedInstructions(isolate(), native_module);
}
}
}
@ -471,17 +511,20 @@ WasmFunctionCompiler::WasmFunctionCompiler(Zone* zone, FunctionSig* sig,
source_position_table_(this->graph()),
interpreter_(builder->interpreter()) {
// Get a new function from the testing module.
int index = builder->AddFunction(sig, Handle<Code>::null(), name);
int index = builder->AddFunction(sig, name);
function_ = builder_->GetFunctionAt(index);
}
WasmFunctionCompiler::~WasmFunctionCompiler() {
if (trap_handler::UseTrapHandler() &&
!builder_->GetFunctionCode(function_index()).is_null()) {
const int handler_index = builder_->GetFunctionCode(function_index())
->trap_handler_index()
->value();
trap_handler::ReleaseHandlerData(handler_index);
if (!FLAG_wasm_jit_to_native) {
if (trap_handler::UseTrapHandler() &&
!builder_->GetFunctionCode(function_index()).is_null()) {
const int handler_index = builder_->GetFunctionCode(function_index())
.GetCode()
->trap_handler_index()
->value();
trap_handler::ReleaseHandlerData(handler_index);
}
}
}

View File

@ -77,7 +77,7 @@ using compiler::Node;
r.Build(code, code + arraysize(code)); \
} while (false)
// A buildable ModuleEnv. Globals are pre-set, however, memory and code may be
// A Wasm module builder. Globals are pre-set, however, memory and code may be
// progressively added by a test. In turn, we piecemeal update the runtime
// objects, i.e. {WasmInstanceObject}, {WasmCompiledModule} and, if necessary,
// the interpreter.
@ -90,7 +90,13 @@ class TestingModuleBuilder {
byte* AddMemory(uint32_t size);
size_t CodeTableLength() const { return function_code_.size(); }
size_t CodeTableLength() const {
if (FLAG_wasm_jit_to_native) {
return native_module_->FunctionCount();
} else {
return function_code_.size();
}
}
template <typename T>
T* AddMemoryElems(uint32_t count) {
@ -173,7 +179,7 @@ class TestingModuleBuilder {
void SetHasSharedMemory() { test_module_.has_shared_memory = true; }
uint32_t AddFunction(FunctionSig* sig, Handle<Code> code, const char* name);
uint32_t AddFunction(FunctionSig* sig, const char* name);
uint32_t AddJsFunction(FunctionSig* sig, const char* source,
Handle<FixedArray> js_imports_table);
@ -200,11 +206,24 @@ class TestingModuleBuilder {
bool lower_simd() { return lower_simd_; }
Isolate* isolate() { return isolate_; }
Handle<WasmInstanceObject> instance_object() { return instance_object_; }
Handle<Code> GetFunctionCode(int index) { return function_code_[index]; }
WasmCodeWrapper GetFunctionCode(uint32_t index) {
if (FLAG_wasm_jit_to_native) {
return WasmCodeWrapper(native_module_->GetCode(index));
} else {
return WasmCodeWrapper(function_code_[index]);
}
}
void SetFunctionCode(int index, Handle<Code> code) {
function_code_[index] = code;
}
Address globals_start() { return reinterpret_cast<Address>(globals_data_); }
void Link() {
if (!FLAG_wasm_jit_to_native) return;
if (!linked_) {
native_module_->LinkAll();
linked_ = true;
}
}
compiler::ModuleEnv CreateModuleEnv();
@ -228,6 +247,8 @@ class TestingModuleBuilder {
WasmInterpreter* interpreter_;
WasmExecutionMode execution_mode_;
Handle<WasmInstanceObject> instance_object_;
NativeModule* native_module_;
bool linked_ = false;
compiler::RuntimeExceptionSupport runtime_exception_support_;
bool lower_simd_;
@ -258,9 +279,21 @@ class WasmFunctionWrapper : private compiler::GraphAndBuilders {
Init(descriptor, MachineTypeForC<ReturnType>(), param_vec);
}
void SetInnerCode(Handle<Code> code_handle) {
compiler::NodeProperties::ChangeOp(inner_code_node_,
common()->HeapConstant(code_handle));
void SetInnerCode(WasmCodeWrapper code) {
if (FLAG_wasm_jit_to_native) {
intptr_t address = reinterpret_cast<intptr_t>(
code.GetWasmCode()->instructions().start());
compiler::NodeProperties::ChangeOp(
inner_code_node_,
kPointerSize == 8
? common()->RelocatableInt64Constant(address,
RelocInfo::WASM_CALL)
: common()->RelocatableInt32Constant(static_cast<int>(address),
RelocInfo::WASM_CALL));
} else {
compiler::NodeProperties::ChangeOp(
inner_code_node_, common()->HeapConstant(code.GetCode()));
}
}
const compiler::Operator* IntPtrConstant(intptr_t value) {
@ -444,6 +477,7 @@ class WasmRunner : public WasmRunnerBase {
WasmContext* wasm_context =
builder().instance_object()->wasm_context()->get();
wrapper_.SetContextAddress(reinterpret_cast<uintptr_t>(wasm_context));
builder().Link();
Handle<Code> wrapper_code = wrapper_.GetWrapperCode();
compiler::CodeRunner<int32_t> runner(CcTest::InitIsolateOnce(),
wrapper_code, wrapper_.signature());

View File

@ -16,7 +16,7 @@ ALL_VARIANT_FLAGS = {
# https://chromium-review.googlesource.com/c/452620/ for more discussion.
"nooptimization": [["--noopt"]],
"stress_background_compile": [["--background-compile", "--stress-background-compile"]],
"wasm_traps": [["--wasm_trap_handler", "--invoke-weak-callbacks"]],
"wasm_traps": [["--wasm_trap_handler", "--invoke-weak-callbacks", "--wasm-jit-to-native"]],
}
# FAST_VARIANTS implies no --always-opt.
@ -33,7 +33,7 @@ FAST_VARIANT_FLAGS = {
# https://chromium-review.googlesource.com/c/452620/ for more discussion.
"nooptimization": [["--noopt"]],
"stress_background_compile": [["--background-compile", "--stress-background-compile"]],
"wasm_traps": [["--wasm_trap_handler", "--invoke-weak-callbacks"]],
"wasm_traps": [["--wasm_trap_handler", "--invoke-weak-callbacks", "--wasm-jit-to-native"]],
}
ALL_VARIANTS = set(["default", "future", "liftoff", "stress",