5#ifndef V8_WASM_INLINING_TREE_H_
6#define V8_WASM_INLINING_TREE_H_
8#if !V8_ENABLE_WEBASSEMBLY
9#error This header should only be included if WebAssembly is enabled.
60 size_t wirebytes =
module->functions[func_index].code.length();
64 constexpr int kTurboshaftAdjustment = 2;
66 static_cast<int>(
v8_flags.wasm_inlining_factor) + kTurboshaftAdjustment;
67 constexpr int kLowestUsefulValue = 2;
68 int low_growth = std::max(kLowestUsefulValue, high_growth - 3);
69 double max_growth_factor = low_growth * (1 - scaled) + high_growth * scaled;
70 return std::max(
static_cast<int>(
v8_flags.wasm_inlining_min_budget),
71 static_cast<int>(max_growth_factor * wirebytes));
77 constexpr int count_factor = 2;
78 constexpr int size_factor = 3;
116 double small_function_percentage =
117 module->num_small_functions * 100.0 / module->num_declared_functions;
118 if (small_function_percentage <= 25) {
120 }
else if (small_function_percentage >= 50) {
123 return (small_function_percentage - 25) / 25;
139 constexpr int kTurboshaftAdjustment = 2;
140 int high_growth =
static_cast<int>(
v8_flags.wasm_inlining_factor) +
141 kTurboshaftAdjustment;
143 constexpr int kLowestUsefulValue = 2;
144 int low_growth = std::max(kLowestUsefulValue, high_growth - 3);
153 constexpr double kTurboshaftCorrectionFactor = 1.4;
155 v8_flags.wasm_inlining_budget * kTurboshaftCorrectionFactor;
156 double low_cap = high_cap / 10;
157 budget_cap = low_cap * (1 - scaled) + high_cap * scaled;
168 int wire_byte_size, uint32_t caller_index,
int feedback_slot,
169 int the_case, uint32_t depth)
189 size_t inlined_wire_byte_count);
211 auto& feedback_map =
data_->
module->type_feedback.feedback_for_function;
213 if (feedback_it == feedback_map.end())
return;
216 feedback.feedback_vector.as_vector();
217 if (type_feedback.
empty())
return;
218 DCHECK_EQ(type_feedback.
size(), feedback.call_targets.size());
224 for (
size_t i = 0;
i < type_feedback.
size();
i++) {
226 type_feedback[
i].num_cases());
228 type_feedback[
i].has_non_inlineable_targets();
229 for (
int the_case = 0; the_case < type_feedback[
i].num_cases();
231 uint32_t callee_index = type_feedback[
i].function_index(the_case);
235 data_, callee_index, type_feedback[
i].call_count(the_case),
237 static_cast<int>(
i), the_case,
depth_ + 1);
253 size_t initial_wire_byte_size =
255 size_t inlined_wire_byte_count = 0;
256 std::priority_queue<InliningTree*, std::vector<InliningTree*>,
260 int inlined_count = 0;
267 "[function %d: in function %d, considering call #%d, case #%d, to "
268 "function %d (count=%d, size=%d, score=%" PRId64
")... ",
270 top->feedback_slot_,
static_cast<int>(top->case_),
271 static_cast<int>(top->function_index_), top->call_count_,
272 top->wire_byte_size_,
static_cast<int64_t
>(top->score()));
274 PrintF(
"[function %d: expanding topmost caller... ",
279 if (top->function_index_ <
data_->
module->num_imported_functions) {
280 if (
v8_flags.trace_wasm_inlining && top !=
this) {
281 PrintF(
"imported function]\n");
287 PrintF(
"cannot inline asm.js function]\n");
295 if (top !=
this && top->wire_byte_size_ >= 12 &&
296 !
v8_flags.wasm_inlining_ignore_call_counts) {
297 if (top->call_count_ < top->wire_byte_size_ / 2) {
299 PrintF(
"not called often enough]\n");
305 if (!top->SmallEnoughToInline(initial_wire_byte_size,
306 inlined_wire_byte_count)) {
307 if (
v8_flags.trace_wasm_inlining && top !=
this) {
308 PrintF(
"not enough inlining budget]\n");
312 if (
v8_flags.trace_wasm_inlining && top !=
this) {
313 PrintF(
"decided to inline! ");
321 constexpr int kOneLessCall = 6;
322 inlined_wire_byte_count += std::max(top->wire_byte_size_ - kOneLessCall, 0);
324 if (!top->feedback_found()) {
326 PrintF(
"no feedback yet or no callees]\n");
330 PrintF(
"queueing %zu callee(s)]\n", top->function_calls_.size());
334 if (call !=
nullptr) {
339 }
else if (
v8_flags.trace_wasm_inlining) {
340 PrintF(
"max inlining depth reached]\n");
343 if (
v8_flags.trace_wasm_inlining && !queue.empty()) {
344 PrintF(
"[function %d: too many inlining candidates, stopping...]\n",
352 size_t inlined_wire_byte_count) {
361 if (inlined_wire_byte_count > 100) {
362 inlined_wire_byte_count -= 100;
364 inlined_wire_byte_count = 0;
374 size_t budget_small_function =
375 std::max<size_t>(
v8_flags.wasm_inlining_min_budget,
388 size_t budget_large_function =
390 size_t total_size = initial_wire_byte_size + inlined_wire_byte_count +
393 PrintF(
"budget=min(%zu, %zu), size %zu->%zu ", budget_small_function,
394 budget_large_function,
395 (initial_wire_byte_size + inlined_wire_byte_count), total_size);
398 std::min<size_t>(budget_small_function, budget_large_function);
constexpr bool empty() const
constexpr size_t size() const
base::Vector< T > AllocateVector(size_t length)
static double BudgetScaleFactor(const WasmModule *module)
base::Vector< CasesPerCallSite > function_calls_
base::Vector< CasesPerCallSite > function_calls()
static int NoLiftoffBudget(const WasmModule *module, uint32_t func_index)
base::Vector< bool > has_non_inlineable_targets()
base::Vector< bool > has_non_inlineable_targets_
InliningTree(Data *shared, uint32_t function_index, int call_count, int wire_byte_size, uint32_t caller_index, int feedback_slot, int the_case, uint32_t depth)
static constexpr uint32_t kMaxInliningNestingDepth
uint32_t function_index()
static constexpr int kMaxInlinedCount
static InliningTree * CreateRoot(Zone *zone, const WasmModule *module, uint32_t function_index)
bool SmallEnoughToInline(size_t initial_wire_byte_size, size_t inlined_wire_byte_count)
bool is_asmjs_module(const WasmModule *module)
void PrintF(const char *format,...)
V8_EXPORT_PRIVATE FlagValues v8_flags
#define DCHECK_EQ(v1, v2)
const WasmModule * module
uint32_t topmost_caller_index
Data(Zone *zone, const WasmModule *module, uint32_t topmost_caller_index)
bool operator()(InliningTree *t1, InliningTree *t2)