Commit e2c3e4f2 authored by Clemens Backes's avatar Clemens Backes Committed by V8 LUCI CQ

[wasm] Allocate the lazy compile table anywhere

The jump table and far jump table are allocated once per code space, but
the lazy compile table only needs to exist exactly once, and it does not
really matter in which code space we allocate it.
Before dynamic tiering, we could always allocate it in the initial code
space (which was empty at the point when we allocated it), but with
deserialization of a partially tiered module we can end up in a
situation where we first deserialize some TurboFan functions into the
initial code space, and when we later try to allocate the lazy compile
table (when we encounter the first non-serialized function) we do not
have enough space any more in the initial code space.

This CL allows to allocate the lazy compile jump table in any code space
to avoid that failure.

R=thibaudm@chromium.org

Bug: chromium:1348472, chromium:1348214
Change-Id: I58c9a8a6541f2ab7df26ddfd1b65d31cc99337fc
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3792607Reviewed-by: 's avatarThibaud Michaud <thibaudm@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82086}
parent ba8ad5dd
......@@ -609,13 +609,6 @@ size_t OverheadPerCodeSpace(uint32_t num_declared_functions) {
size_t ReservationSize(size_t code_size_estimate, int num_declared_functions,
size_t total_reserved) {
size_t overhead = OverheadPerCodeSpace(num_declared_functions);
// If this is the first code space, we also need space for the lazy
// compilation jump table (except if both dynamic tiering and lazy compilation
// are disabled via flags, which we chose to ignore here).
if (total_reserved == 0) {
overhead += JumpTableAssembler::SizeForNumberOfLazyFunctions(
num_declared_functions);
}
// Reserve the maximum of
// a) needed size + overhead (this is the minimum needed)
......@@ -706,6 +699,11 @@ class CheckWritableMemoryRegions {
};
#endif // !DEBUG
// Sentinel value to be used for {AllocateForCodeInRegion} for specifying no
// restriction on the region to allocate in.
constexpr base::AddressRegion kUnrestrictedRegion{
kNullAddress, std::numeric_limits<size_t>::max()};
} // namespace
base::Vector<byte> WasmCodeAllocator::AllocateForCode(
......@@ -961,9 +959,6 @@ void WasmCodeAllocator::InsertIntoWritableRegions(base::AddressRegion region,
}
}
// static
constexpr base::AddressRegion WasmCodeAllocator::kUnrestrictedRegion;
namespace {
BoundsCheckStrategy GetBoundsChecks(const WasmModule* module) {
if (!FLAG_wasm_bounds_checks) return kNoBoundsChecks;
......@@ -1168,18 +1163,15 @@ void NativeModule::UseLazyStub(uint32_t func_index) {
if (!lazy_compile_table_) {
uint32_t num_slots = module_->num_declared_functions;
WasmCodeRefScope code_ref_scope;
DCHECK_EQ(1, code_space_data_.size());
base::AddressRegion single_code_space_region = code_space_data_[0].region;
lazy_compile_table_ = CreateEmptyJumpTableInRegionLocked(
JumpTableAssembler::SizeForNumberOfLazyFunctions(num_slots),
single_code_space_region);
JumpTableAssembler::GenerateLazyCompileTable(
lazy_compile_table_->instruction_start(), num_slots,
module_->num_imported_functions,
GetNearRuntimeStubEntry(
lazy_compile_table_ = CreateEmptyJumpTableLocked(
JumpTableAssembler::SizeForNumberOfLazyFunctions(num_slots));
Address compile_lazy_address = GetNearRuntimeStubEntry(
WasmCode::kWasmCompileLazy,
FindJumpTablesForRegionLocked(
base::AddressRegionOf(lazy_compile_table_->instructions()))));
base::AddressRegionOf(lazy_compile_table_->instructions())));
JumpTableAssembler::GenerateLazyCompileTable(
lazy_compile_table_->instruction_start(), num_slots,
module_->num_imported_functions, compile_lazy_address);
}
// Add jump table entry for jump to the lazy compile stub.
......@@ -1487,6 +1479,11 @@ WasmModuleSourceMap* NativeModule::GetWasmSourceMap() const {
return source_map_.get();
}
WasmCode* NativeModule::CreateEmptyJumpTableLocked(int jump_table_size) {
return CreateEmptyJumpTableInRegionLocked(jump_table_size,
kUnrestrictedRegion);
}
WasmCode* NativeModule::CreateEmptyJumpTableInRegionLocked(
int jump_table_size, base::AddressRegion region) {
allocation_mutex_.AssertHeld();
......@@ -2087,8 +2084,13 @@ size_t WasmCodeManager::EstimateNativeModuleCodeSize(
size_t WasmCodeManager::EstimateNativeModuleCodeSize(
int num_functions, int num_imported_functions, int code_section_length,
bool include_liftoff, DynamicTiering dynamic_tiering) {
// Note that the size for jump tables is added later, in {ReservationSize} /
// {OverheadPerCodeSpace}.
// The size for the jump table and far jump table is added later, per code
// space (see {OverheadPerCodeSpace}). We still need to add the overhead for
// the lazy compile table once, though. There are configurations where we do
// not need it (non-asm.js, no dynamic tiering and no lazy compilation), but
// we ignore this here as most of the time we will need it.
const size_t lazy_compile_table_size =
JumpTableAssembler::SizeForNumberOfLazyFunctions(num_functions);
const size_t size_of_imports = kImportSize * num_imported_functions;
......@@ -2099,20 +2101,18 @@ size_t WasmCodeManager::EstimateNativeModuleCodeSize(
const size_t overhead_per_function_liftoff =
kLiftoffFunctionOverhead + kCodeAlignment / 2;
size_t size_of_liftoff = overhead_per_function_liftoff * num_functions +
kLiftoffCodeSizeMultiplier * code_section_length;
const size_t size_of_liftoff =
include_liftoff ? overhead_per_function_liftoff * num_functions +
kLiftoffCodeSizeMultiplier * code_section_length
: 0;
if (!include_liftoff) {
size_of_liftoff = 0;
}
// With dynamic tiering we don't expect to compile more than 25% with
// TurboFan. If there is no liftoff though then all code will get generated
// by TurboFan.
if (include_liftoff && dynamic_tiering) {
size_of_turbofan /= 4;
}
if (include_liftoff && dynamic_tiering) size_of_turbofan /= 4;
return size_of_imports + size_of_liftoff + size_of_turbofan;
return lazy_compile_table_size + size_of_imports + size_of_liftoff +
size_of_turbofan;
}
// static
......
......@@ -585,11 +585,6 @@ class WasmCodeAllocator {
Counters* counters() const { return async_counters_.get(); }
private:
// Sentinel value to be used for {AllocateForCodeInRegion} for specifying no
// restriction on the region to allocate in.
static constexpr base::AddressRegion kUnrestrictedRegion{
kNullAddress, std::numeric_limits<size_t>::max()};
void InsertIntoWritableRegions(base::AddressRegion region,
bool switch_to_writable);
......@@ -887,6 +882,8 @@ class V8_EXPORT_PRIVATE NativeModule final {
ExecutionTier tier, ForDebugging for_debugging,
base::Vector<uint8_t> code_space, const JumpTablesRef& jump_tables_ref);
WasmCode* CreateEmptyJumpTableLocked(int jump_table_size);
WasmCode* CreateEmptyJumpTableInRegionLocked(int jump_table_size,
base::AddressRegion);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment