[wasm] Fix regression caused by multiple code spaces
The {GetNearRuntimeStubEntry} and {GetNearCallTargetForFunction} functions need to find the code space that contains the current function. This lookup requires a lock and is non-trivial. The repeated lookup caused severe regressions. This CL introduces a {JumpTablesRef} struct which holds information about the jump tables to use. It can be looked up once and then used for a whole function or even several functions within the same code space (in {NativeModule::AddCompiledCode} which adds a whole vector of compilation results). This fixes the regressions. R=ahaas@chromium.org Bug: chromium:1004262, v8:9477 Change-Id: I50bd8327a131e3bee79d86b6d7e867a506959312 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1840153 Commit-Queue: Clemens Backes <clemensb@chromium.org> Reviewed-by: Andreas Haas <ahaas@chromium.org> Cr-Commit-Position: refs/heads/master@{#64129}
This commit is contained in:
parent
8ca191b6cb
commit
44c3b7b518
@ -833,6 +833,8 @@ WasmCode* NativeModule::AddCodeForTesting(Handle<Code> code) {
|
|||||||
code->InstructionStart();
|
code->InstructionStart();
|
||||||
int mode_mask = RelocInfo::kApplyMask |
|
int mode_mask = RelocInfo::kApplyMask |
|
||||||
RelocInfo::ModeMask(RelocInfo::WASM_STUB_CALL);
|
RelocInfo::ModeMask(RelocInfo::WASM_STUB_CALL);
|
||||||
|
auto jump_tables_ref =
|
||||||
|
FindJumpTablesForCode(reinterpret_cast<Address>(dst_code_bytes.begin()));
|
||||||
Address dst_code_addr = reinterpret_cast<Address>(dst_code_bytes.begin());
|
Address dst_code_addr = reinterpret_cast<Address>(dst_code_bytes.begin());
|
||||||
Address constant_pool_start = dst_code_addr + constant_pool_offset;
|
Address constant_pool_start = dst_code_addr + constant_pool_offset;
|
||||||
RelocIterator orig_it(*code, mode_mask);
|
RelocIterator orig_it(*code, mode_mask);
|
||||||
@ -844,7 +846,7 @@ WasmCode* NativeModule::AddCodeForTesting(Handle<Code> code) {
|
|||||||
uint32_t stub_call_tag = orig_it.rinfo()->wasm_call_tag();
|
uint32_t stub_call_tag = orig_it.rinfo()->wasm_call_tag();
|
||||||
DCHECK_LT(stub_call_tag, WasmCode::kRuntimeStubCount);
|
DCHECK_LT(stub_call_tag, WasmCode::kRuntimeStubCount);
|
||||||
Address entry = GetNearRuntimeStubEntry(
|
Address entry = GetNearRuntimeStubEntry(
|
||||||
static_cast<WasmCode::RuntimeStubId>(stub_call_tag), dst_code_addr);
|
static_cast<WasmCode::RuntimeStubId>(stub_call_tag), jump_tables_ref);
|
||||||
it.rinfo()->set_wasm_stub_call_address(entry, SKIP_ICACHE_FLUSH);
|
it.rinfo()->set_wasm_stub_call_address(entry, SKIP_ICACHE_FLUSH);
|
||||||
} else {
|
} else {
|
||||||
it.rinfo()->apply(delta);
|
it.rinfo()->apply(delta);
|
||||||
@ -896,8 +898,9 @@ void NativeModule::UseLazyStub(uint32_t func_index) {
|
|||||||
JumpTableAssembler::GenerateLazyCompileTable(
|
JumpTableAssembler::GenerateLazyCompileTable(
|
||||||
lazy_compile_table_->instruction_start(), num_slots,
|
lazy_compile_table_->instruction_start(), num_slots,
|
||||||
module_->num_imported_functions,
|
module_->num_imported_functions,
|
||||||
GetNearRuntimeStubEntry(WasmCode::kWasmCompileLazy,
|
GetNearRuntimeStubEntry(
|
||||||
lazy_compile_table_->instruction_start()));
|
WasmCode::kWasmCompileLazy,
|
||||||
|
FindJumpTablesForCode(lazy_compile_table_->instruction_start())));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add jump table entry for jump to the lazy compile stub.
|
// Add jump table entry for jump to the lazy compile stub.
|
||||||
@ -916,10 +919,14 @@ std::unique_ptr<WasmCode> NativeModule::AddCode(
|
|||||||
OwnedVector<trap_handler::ProtectedInstructionData> protected_instructions,
|
OwnedVector<trap_handler::ProtectedInstructionData> protected_instructions,
|
||||||
OwnedVector<const byte> source_position_table, WasmCode::Kind kind,
|
OwnedVector<const byte> source_position_table, WasmCode::Kind kind,
|
||||||
ExecutionTier tier) {
|
ExecutionTier tier) {
|
||||||
return AddCodeWithCodeSpace(
|
Vector<byte> code_space =
|
||||||
index, desc, stack_slots, tagged_parameter_slots,
|
code_allocator_.AllocateForCode(this, desc.instr_size);
|
||||||
std::move(protected_instructions), std::move(source_position_table), kind,
|
auto jump_table_ref =
|
||||||
tier, code_allocator_.AllocateForCode(this, desc.instr_size));
|
FindJumpTablesForCode(reinterpret_cast<Address>(code_space.begin()));
|
||||||
|
return AddCodeWithCodeSpace(index, desc, stack_slots, tagged_parameter_slots,
|
||||||
|
std::move(protected_instructions),
|
||||||
|
std::move(source_position_table), kind, tier,
|
||||||
|
code_space, jump_table_ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<WasmCode> NativeModule::AddCodeWithCodeSpace(
|
std::unique_ptr<WasmCode> NativeModule::AddCodeWithCodeSpace(
|
||||||
@ -927,7 +934,8 @@ std::unique_ptr<WasmCode> NativeModule::AddCodeWithCodeSpace(
|
|||||||
uint32_t tagged_parameter_slots,
|
uint32_t tagged_parameter_slots,
|
||||||
OwnedVector<ProtectedInstructionData> protected_instructions,
|
OwnedVector<ProtectedInstructionData> protected_instructions,
|
||||||
OwnedVector<const byte> source_position_table, WasmCode::Kind kind,
|
OwnedVector<const byte> source_position_table, WasmCode::Kind kind,
|
||||||
ExecutionTier tier, Vector<uint8_t> dst_code_bytes) {
|
ExecutionTier tier, Vector<uint8_t> dst_code_bytes,
|
||||||
|
const JumpTablesRef& jump_tables_ref) {
|
||||||
OwnedVector<byte> reloc_info;
|
OwnedVector<byte> reloc_info;
|
||||||
if (desc.reloc_size > 0) {
|
if (desc.reloc_size > 0) {
|
||||||
reloc_info = OwnedVector<byte>::New(desc.reloc_size);
|
reloc_info = OwnedVector<byte>::New(desc.reloc_size);
|
||||||
@ -964,13 +972,13 @@ std::unique_ptr<WasmCode> NativeModule::AddCodeWithCodeSpace(
|
|||||||
RelocInfo::Mode mode = it.rinfo()->rmode();
|
RelocInfo::Mode mode = it.rinfo()->rmode();
|
||||||
if (RelocInfo::IsWasmCall(mode)) {
|
if (RelocInfo::IsWasmCall(mode)) {
|
||||||
uint32_t call_tag = it.rinfo()->wasm_call_tag();
|
uint32_t call_tag = it.rinfo()->wasm_call_tag();
|
||||||
Address target = GetNearCallTargetForFunction(call_tag, code_start);
|
Address target = GetNearCallTargetForFunction(call_tag, jump_tables_ref);
|
||||||
it.rinfo()->set_wasm_call_address(target, SKIP_ICACHE_FLUSH);
|
it.rinfo()->set_wasm_call_address(target, SKIP_ICACHE_FLUSH);
|
||||||
} else if (RelocInfo::IsWasmStubCall(mode)) {
|
} else if (RelocInfo::IsWasmStubCall(mode)) {
|
||||||
uint32_t stub_call_tag = it.rinfo()->wasm_call_tag();
|
uint32_t stub_call_tag = it.rinfo()->wasm_call_tag();
|
||||||
DCHECK_LT(stub_call_tag, WasmCode::kRuntimeStubCount);
|
DCHECK_LT(stub_call_tag, WasmCode::kRuntimeStubCount);
|
||||||
Address entry = GetNearRuntimeStubEntry(
|
Address entry = GetNearRuntimeStubEntry(
|
||||||
static_cast<WasmCode::RuntimeStubId>(stub_call_tag), code_start);
|
static_cast<WasmCode::RuntimeStubId>(stub_call_tag), jump_tables_ref);
|
||||||
it.rinfo()->set_wasm_stub_call_address(entry, SKIP_ICACHE_FLUSH);
|
it.rinfo()->set_wasm_stub_call_address(entry, SKIP_ICACHE_FLUSH);
|
||||||
} else {
|
} else {
|
||||||
it.rinfo()->apply(delta);
|
it.rinfo()->apply(delta);
|
||||||
@ -1333,32 +1341,34 @@ Address NativeModule::GetCallTargetForFunction(uint32_t func_index) const {
|
|||||||
return main_jump_table_->instruction_start() + slot_offset;
|
return main_jump_table_->instruction_start() + slot_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
Address NativeModule::GetNearCallTargetForFunction(uint32_t func_index,
|
NativeModule::JumpTablesRef NativeModule::FindJumpTablesForCode(
|
||||||
Address near_to) const {
|
Address code_addr) const {
|
||||||
uint32_t slot_offset = GetJumpTableOffset(func_index);
|
|
||||||
base::MutexGuard guard(&allocation_mutex_);
|
base::MutexGuard guard(&allocation_mutex_);
|
||||||
for (auto& code_space_data : code_space_data_) {
|
for (auto& code_space_data : code_space_data_) {
|
||||||
const bool jump_table_reachable = !kNeedsFarJumpsBetweenCodeSpaces ||
|
const bool jump_table_reachable =
|
||||||
code_space_data.region.contains(near_to);
|
!kNeedsFarJumpsBetweenCodeSpaces ||
|
||||||
if (jump_table_reachable && code_space_data.jump_table) {
|
code_space_data.region.contains(code_addr);
|
||||||
DCHECK_LT(slot_offset, code_space_data.jump_table->instructions().size());
|
if (jump_table_reachable && code_space_data.far_jump_table) {
|
||||||
return code_space_data.jump_table->instruction_start() + slot_offset;
|
// We might not have a jump table if we have no functions.
|
||||||
|
return {code_space_data.jump_table
|
||||||
|
? code_space_data.jump_table->instruction_start()
|
||||||
|
: kNullAddress,
|
||||||
|
code_space_data.far_jump_table->instruction_start()};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FATAL("near_to is not part of a code space");
|
FATAL("code_addr is not part of a code space");
|
||||||
}
|
}
|
||||||
|
|
||||||
Address NativeModule::GetNearRuntimeStubEntry(WasmCode::RuntimeStubId index,
|
Address NativeModule::GetNearCallTargetForFunction(
|
||||||
Address near_to) const {
|
uint32_t func_index, const JumpTablesRef& jump_tables) const {
|
||||||
base::MutexGuard guard(&allocation_mutex_);
|
uint32_t slot_offset = GetJumpTableOffset(func_index);
|
||||||
for (auto& code_space_data : code_space_data_) {
|
return jump_tables.jump_table_start + slot_offset;
|
||||||
if (code_space_data.region.contains(near_to)) {
|
}
|
||||||
|
|
||||||
|
Address NativeModule::GetNearRuntimeStubEntry(
|
||||||
|
WasmCode::RuntimeStubId index, const JumpTablesRef& jump_tables) const {
|
||||||
auto offset = JumpTableAssembler::FarJumpSlotIndexToOffset(index);
|
auto offset = JumpTableAssembler::FarJumpSlotIndexToOffset(index);
|
||||||
DCHECK_GT(code_space_data.far_jump_table->instructions().size(), offset);
|
return jump_tables.far_jump_table_start + offset;
|
||||||
return code_space_data.far_jump_table->instruction_start() + offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FATAL("near_to is not part of a code space");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t NativeModule::GetFunctionIndexFromJumpTableSlot(
|
uint32_t NativeModule::GetFunctionIndexFromJumpTableSlot(
|
||||||
@ -1661,6 +1671,9 @@ std::vector<WasmCode*> NativeModule::AddCompiledCode(
|
|||||||
}
|
}
|
||||||
Vector<byte> code_space =
|
Vector<byte> code_space =
|
||||||
code_allocator_.AllocateForCode(this, total_code_space);
|
code_allocator_.AllocateForCode(this, total_code_space);
|
||||||
|
// Lookup the jump tables to use once, then use for all code objects.
|
||||||
|
auto jump_tables_ref =
|
||||||
|
FindJumpTablesForCode(reinterpret_cast<Address>(code_space.begin()));
|
||||||
|
|
||||||
std::vector<std::unique_ptr<WasmCode>> generated_code;
|
std::vector<std::unique_ptr<WasmCode>> generated_code;
|
||||||
generated_code.reserve(results.size());
|
generated_code.reserve(results.size());
|
||||||
@ -1675,7 +1688,7 @@ std::vector<WasmCode*> NativeModule::AddCompiledCode(
|
|||||||
result.func_index, result.code_desc, result.frame_slot_count,
|
result.func_index, result.code_desc, result.frame_slot_count,
|
||||||
result.tagged_parameter_slots, std::move(result.protected_instructions),
|
result.tagged_parameter_slots, std::move(result.protected_instructions),
|
||||||
std::move(result.source_positions), GetCodeKind(result),
|
std::move(result.source_positions), GetCodeKind(result),
|
||||||
result.result_tier, this_code_space));
|
result.result_tier, this_code_space, jump_tables_ref));
|
||||||
}
|
}
|
||||||
DCHECK_EQ(0, code_space.size());
|
DCHECK_EQ(0, code_space.size());
|
||||||
|
|
||||||
|
@ -421,16 +421,26 @@ class V8_EXPORT_PRIVATE NativeModule final {
|
|||||||
// the first jump table).
|
// the first jump table).
|
||||||
Address GetCallTargetForFunction(uint32_t func_index) const;
|
Address GetCallTargetForFunction(uint32_t func_index) const;
|
||||||
|
|
||||||
// Similarly to {GetCallTargetForFunction}, but ensures that the returned
|
struct JumpTablesRef {
|
||||||
// address is near to the {near_to} address by finding the closest jump table.
|
const Address jump_table_start;
|
||||||
Address GetNearCallTargetForFunction(uint32_t func_index,
|
const Address far_jump_table_start;
|
||||||
Address near_to) const;
|
};
|
||||||
|
|
||||||
// Get a runtime stub entry (which is a far jump table slot) within near-call
|
// Finds the jump tables that should be used for the code at {code_addr}. This
|
||||||
// distance to {near_to}. Fails if {near_to} is not part of any code space of
|
// information is then passed to {GetNearCallTargetForFunction} and
|
||||||
// this module.
|
// {GetNearRuntimeStubEntry} to avoid the overhead of looking this information
|
||||||
|
// up there.
|
||||||
|
JumpTablesRef FindJumpTablesForCode(Address code_addr) const;
|
||||||
|
|
||||||
|
// Similarly to {GetCallTargetForFunction}, but uses the jump table previously
|
||||||
|
// looked up via {FindJumpTablesForCode}.
|
||||||
|
Address GetNearCallTargetForFunction(uint32_t func_index,
|
||||||
|
const JumpTablesRef&) const;
|
||||||
|
|
||||||
|
// Get a runtime stub entry (which is a far jump table slot) in the jump table
|
||||||
|
// previously looked up via {FindJumpTablesForCode}.
|
||||||
Address GetNearRuntimeStubEntry(WasmCode::RuntimeStubId index,
|
Address GetNearRuntimeStubEntry(WasmCode::RuntimeStubId index,
|
||||||
Address near_to) const;
|
const JumpTablesRef&) const;
|
||||||
|
|
||||||
// Reverse lookup from a given call target (which must be a jump table slot)
|
// Reverse lookup from a given call target (which must be a jump table slot)
|
||||||
// to a function index.
|
// to a function index.
|
||||||
@ -534,7 +544,8 @@ class V8_EXPORT_PRIVATE NativeModule final {
|
|||||||
OwnedVector<trap_handler::ProtectedInstructionData>
|
OwnedVector<trap_handler::ProtectedInstructionData>
|
||||||
protected_instructions,
|
protected_instructions,
|
||||||
OwnedVector<const byte> source_position_table, WasmCode::Kind kind,
|
OwnedVector<const byte> source_position_table, WasmCode::Kind kind,
|
||||||
ExecutionTier tier, Vector<uint8_t> code_space);
|
ExecutionTier tier, Vector<uint8_t> code_space,
|
||||||
|
const JumpTablesRef& jump_tables_ref);
|
||||||
|
|
||||||
WasmCode* CreateEmptyJumpTableInRegion(uint32_t jump_table_size,
|
WasmCode* CreateEmptyJumpTableInRegion(uint32_t jump_table_size,
|
||||||
base::AddressRegion);
|
base::AddressRegion);
|
||||||
|
@ -541,6 +541,8 @@ bool NativeModuleDeserializer::ReadCode(uint32_t fn_index, Reader* reader) {
|
|||||||
RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
|
RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
|
||||||
RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
|
RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
|
||||||
RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED);
|
RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED);
|
||||||
|
auto jump_tables_ref =
|
||||||
|
native_module_->FindJumpTablesForCode(code->instruction_start());
|
||||||
for (RelocIterator iter(code->instructions(), code->reloc_info(),
|
for (RelocIterator iter(code->instructions(), code->reloc_info(),
|
||||||
code->constant_pool(), mask);
|
code->constant_pool(), mask);
|
||||||
!iter.done(); iter.next()) {
|
!iter.done(); iter.next()) {
|
||||||
@ -548,8 +550,8 @@ bool NativeModuleDeserializer::ReadCode(uint32_t fn_index, Reader* reader) {
|
|||||||
switch (mode) {
|
switch (mode) {
|
||||||
case RelocInfo::WASM_CALL: {
|
case RelocInfo::WASM_CALL: {
|
||||||
uint32_t tag = GetWasmCalleeTag(iter.rinfo());
|
uint32_t tag = GetWasmCalleeTag(iter.rinfo());
|
||||||
Address target = native_module_->GetNearCallTargetForFunction(
|
Address target =
|
||||||
tag, code->instruction_start());
|
native_module_->GetNearCallTargetForFunction(tag, jump_tables_ref);
|
||||||
iter.rinfo()->set_wasm_call_address(target, SKIP_ICACHE_FLUSH);
|
iter.rinfo()->set_wasm_call_address(target, SKIP_ICACHE_FLUSH);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -557,8 +559,7 @@ bool NativeModuleDeserializer::ReadCode(uint32_t fn_index, Reader* reader) {
|
|||||||
uint32_t tag = GetWasmCalleeTag(iter.rinfo());
|
uint32_t tag = GetWasmCalleeTag(iter.rinfo());
|
||||||
DCHECK_LT(tag, WasmCode::kRuntimeStubCount);
|
DCHECK_LT(tag, WasmCode::kRuntimeStubCount);
|
||||||
Address target = native_module_->GetNearRuntimeStubEntry(
|
Address target = native_module_->GetNearRuntimeStubEntry(
|
||||||
static_cast<WasmCode::RuntimeStubId>(tag),
|
static_cast<WasmCode::RuntimeStubId>(tag), jump_tables_ref);
|
||||||
code->instruction_start());
|
|
||||||
iter.rinfo()->set_wasm_stub_call_address(target, SKIP_ICACHE_FLUSH);
|
iter.rinfo()->set_wasm_stub_call_address(target, SKIP_ICACHE_FLUSH);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user