1158 {
1162 function.deoptimization_counter());
1163 }
1164
1165
1168 " Bailout: not inlinable due to !function.CanBeInlined()\n"));
1170 call_data->call);
1171 return false;
1172 }
1173
1177 call_data->call);
1178 return false;
1179 }
1180
1181
1182
1187 call_data->call);
1188 return false;
1189 }
1190
1191
1192
1196 call_data->call);
1197 return false;
1198 }
1199
1200
1201
1206 call_data->call);
1207 return false;
1208 }
1209
1210
1211 if (
function.deoptimization_counter() >=
1212 FLAG_max_deoptimization_counter_threshold) {
1216 &call_data->caller, &
function, call_data->call);
1217 return false;
1218 }
1219
1220
1221
1222
1223
1224
1225 GrowableArray<Value*>* arguments = call_data->arguments;
1226 const intptr_t constant_arg_count = CountConstants(*arguments);
1227 const intptr_t instruction_count =
1228 constant_arg_count == 0 ?
function.optimized_instruction_count() : 0;
1229 const intptr_t call_site_count =
1230 constant_arg_count == 0 ?
function.optimized_call_site_count() : 0;
1231 InliningDecision decision =
1233 if (!decision.value) {
1235 THR_Print(
" Bailout: early heuristics (%s) with "
1236 "code size: %" Pd ", "
1237 "call sites: %" Pd ", "
1238 "inlining depth of callee: %d, "
1239 "const args: %" Pd "\n",
1240 decision.reason, instruction_count, call_site_count,
1241 function.inlining_depth(), constant_arg_count));
1243 call_data->call);
1244 return false;
1245 }
1246
1247 if ((
function.HasOptionalPositionalParameters() ||
1248 function.HasOptionalNamedParameters()) &&
1250 arguments->length(), argument_names,
1251 nullptr)) {
1255 return false;
1256 }
1257
1258
1259 Definition*
call = call_data->call;
1260
1262 if (is_recursive_call &&
1263 inlining_recursion_depth_ >= FLAG_inlining_recursion_depth_threshold) {
1266 call_data->call);
1267 return false;
1268 }
1269
1271 {
1272
1273 DeoptIdScope deopt_id_scope(
thread(), 0);
1274
1275
1276 LongJumpScope jump;
1277 if (setjmp(*jump.Set()) == 0) {
1278
1279 ZoneGrowableArray<const ICData*>* ic_data_array =
1280 new (
Z) ZoneGrowableArray<const ICData*>();
1284 function.RestoreICDataMap(ic_data_array, clone_ic_data);
1285
1286
1287 bool in_cache;
1288 ParsedFunction* parsed_function =
1289 GetParsedFunction(
function, &in_cache);
1290
1291
1292 InlineExitCollector* exit_collector =
1293 new (
Z) InlineExitCollector(caller_graph_,
call);
1294 FlowGraph* callee_graph;
1296 if (StaticCallInstr* instr = call_data->call->AsStaticCall()) {
1297 entry_kind = instr->entry_kind();
1298 } else if (InstanceCallInstr* instr =
1299 call_data->call->AsInstanceCall()) {
1300 entry_kind = instr->entry_kind();
1301 } else if (PolymorphicInstanceCallInstr* instr =
1302 call_data->call->AsPolymorphicInstanceCall()) {
1303 entry_kind = instr->entry_kind();
1304 } else if (call_data->call->IsClosureCall()) {
1305
1306 }
1307
1308 kernel::FlowGraphBuilder
builder(
1309 parsed_function, ic_data_array, nullptr,
1310 exit_collector,
1313 entry_kind == Code::EntryKind::kUnchecked);
1314 {
1316 callee_graph =
builder.BuildGraph();
1317
1318
1319 ASSERT(callee_graph->current_ssa_temp_index() == 0);
1320 callee_graph->set_current_ssa_temp_index(
1322#if defined(DEBUG)
1323
1324
1325 GrowableArray<const Function*> callee_inline_id_to_function;
1326 callee_inline_id_to_function.Add(&
function);
1327 FlowGraphChecker(callee_graph, callee_inline_id_to_function)
1328 .Check("Builder (callee)");
1329#endif
1331 }
1332
1333 {
1335
1336#if defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_IA32)
1338 callee_graph->PopulateWithICData(parsed_function->function());
1339 }
1340#endif
1341
1342
1343
1344
1346 callee_graph->PopulateWithICData(parsed_function->function());
1347 }
1348 }
1349
1350
1351
1352
1353
1354 const intptr_t first_actual_param_index = call_data->first_arg_index;
1355 const intptr_t inlined_type_args_param =
function.IsGeneric() ? 1 : 0;
1356 const intptr_t num_inlined_params =
1357 inlined_type_args_param +
function.NumParameters();
1358 ZoneGrowableArray<Definition*>* param_stubs =
1359 new (
Z) ZoneGrowableArray<Definition*>(num_inlined_params);
1360
1361
1362 if (first_actual_param_index > 0) {
1363
1364 param_stubs->Add(
1366 } else if (inlined_type_args_param > 0) {
1367
1368
1370 }
1371
1372 for (intptr_t
i = 0;
i <
function.num_fixed_parameters(); ++
i) {
1374 i, (*arguments)[first_actual_param_index +
i], callee_graph));
1375 }
1376
1377
1378
1379
1380 if (
function.HasOptionalParameters()) {
1382 if (!AdjustForOptionalParameters(
1383 *parsed_function, first_actual_param_index, argument_names,
1384 arguments, param_stubs, callee_graph)) {
1389 return false;
1390 }
1391 }
1392
1393
1394
1395 ASSERT(arguments->length() ==
1396 first_actual_param_index +
function.NumParameters());
1397
1398
1399 BlockEntryInstr* call_block = call_data->call->GetBlock();
1400 if (call_block->InsideTryBlock()) {
1401 intptr_t try_index = call_block->try_index();
1402 for (BlockIterator it = callee_graph->reverse_postorder_iterator();
1403 !it.Done(); it.Advance()) {
1404 BlockEntryInstr* block = it.Current();
1405 block->set_try_index(try_index);
1406 }
1407 }
1408
1410
1411 {
1412
1414 callee_graph->ComputeSSA(param_stubs);
1415#if defined(DEBUG)
1416
1417
1418 GrowableArray<const Function*> callee_inline_id_to_function;
1419 callee_inline_id_to_function.Add(&
function);
1420 FlowGraphChecker(callee_graph, callee_inline_id_to_function)
1421 .Check("SSA (callee)");
1422#endif
1423 }
1424
1426 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) {
1427 THR_Print(
"Callee graph for inlining %s (unoptimized)\n",
1428 function.ToFullyQualifiedCString());
1429 FlowGraphPrinter printer(*callee_graph);
1430 printer.PrintBlocks();
1431 }
1432
1433 {
1434
1435
1437#if defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_IA32)
1438 AotCallSpecializer call_specializer(inliner_->precompiler_,
1439 callee_graph,
1440 inliner_->speculative_policy_);
1441
1443 inliner_->speculative_policy_);
1444 state.call_specializer = &call_specializer;
1446#else
1448#endif
1449 } else {
1450 JitCallSpecializer call_specializer(callee_graph,
1451 inliner_->speculative_policy_);
1452
1454 inliner_->speculative_policy_);
1455 state.call_specializer = &call_specializer;
1457 }
1458 }
1459
1461 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) {
1462 THR_Print(
"Callee graph for inlining %s (optimized)\n",
1463 function.ToFullyQualifiedCString());
1464 FlowGraphPrinter printer(*callee_graph);
1465 printer.PrintBlocks();
1466 }
1467
1468
1469
1470
1471 intptr_t constants_count = 0;
1472 for (intptr_t
i = 0, n = param_stubs->length();
i < n; ++
i) {
1473 if ((*param_stubs)[
i]->
IsConstant()) ++constants_count;
1474 }
1475 intptr_t instruction_count = 0;
1476 intptr_t call_site_count = 0;
1478 false, &instruction_count,
1479 &call_site_count);
1480
1481
1482 {
1484 InliningDecision decision =
1486 if (!decision.value) {
1487
1488
1489
1490
1491
1492 if ((instruction_count > FLAG_inlining_size_threshold) &&
1493 (call_site_count > FLAG_inlining_callee_call_sites_threshold)) {
1494
1495
1500 }
1501 }
1503 THR_Print(
" Bailout: heuristics (%s) with "
1504 "code size: %" Pd ", "
1505 "call sites: %" Pd ", "
1506 "inlining depth of callee: %d, "
1507 "const args: %" Pd "\n",
1508 decision.reason, instruction_count, call_site_count,
1509 function.inlining_depth(), constants_count));
1511 call_data->call);
1512 return false;
1513 }
1514
1515
1516
1517
1518
1519
1520
1521 if (stricter_heuristic) {
1522 intptr_t call_site_instructions = 0;
1523 if (
auto static_call =
call->AsStaticCall()) {
1524
1525 call_site_instructions = static_call->ArgumentCount() + 1 + 1;
1526 }
1528 callee_graph)) {
1530 THR_Print(
" Bailout: heuristics (no small leaf)\n"));
1533 call_data->call);
1534 return false;
1535 }
1536 }
1537 }
1538
1539
1540 {
1541 const intptr_t depth =
1542 function.IsDispatcherOrImplicitAccessor() ? 0 : inlining_depth_;
1544 &inlined_info_);
1545 }
1546
1547
1548 if (!in_cache) {
1549 function_cache_.Add(parsed_function);
1550 }
1551
1552
1553 inlined_ = true;
1554 inlined_size_ += instruction_count;
1555 if (is_recursive_call) {
1556 inlined_recursive_call_ = true;
1557 }
1558
1559 call_data->callee_graph = callee_graph;
1560 call_data->parameter_stubs = param_stubs;
1561 call_data->exit_collector = exit_collector;
1562
1563
1564
1565 const FieldSet* callee_guarded_fields =
1566 callee_graph->parsed_function().guarded_fields();
1567 FieldSet::Iterator it = callee_guarded_fields->
GetIterator();
1568 while (const Field** field = it.Next()) {
1570 }
1571
1572 {
1575 callee_graph, inliner_->
NextInlineId(callee_graph->function(),
1576 call_data->call->source()));
1577 }
1580 " with reason %s, code size %" Pd ", call sites: %" Pd "\n",
1581 decision.reason, instruction_count, call_site_count));
1583 return true;
1584 } else {
1586
1587 if (
error.IsLanguageError() &&
1589 if (
error.ptr() == Object::background_compilation_error().ptr()) {
1590
1591 } else {
1595 return false;
1596 }
1597 } else {
1598
1599 }
1600 }
1601 }
1602
1603
1604
1605
1606
1607
1608
1609
1611 (
error.ptr() == Object::out_of_memory_error().ptr()) ||
1615 return false;
1616 }
Iterator GetIterator() const
static void AssignEdgeWeights(FlowGraph *flow_graph)
InliningDecision ShouldWeInline(const Function &callee, intptr_t instr_count, intptr_t call_site_count)
Definition * CreateParameterStub(intptr_t i, Value *argument, FlowGraph *graph)
bool trace_inlining() const
static void Validate(FlowGraph *callee_graph)
static void RunInliningPipeline(PipelineMode mode, CompilerPassState *state)
static CompilerState & Current()
static bool IsBackgroundCompilation()
static constexpr intptr_t kNoOSRDeoptId
intptr_t NextInlineId(const Function &function, const InstructionSource &source)
static bool FunctionHasAlwaysConsiderInliningPragma(const Function &function)
static void SetInliningId(FlowGraph *flow_graph, intptr_t inlining_id)
static bool FunctionHasNeverInlinePragma(const Function &function)
static void CollectGraphInfo(FlowGraph *flow_graph, intptr_t num_constant_args, bool force, intptr_t *instruction_count, intptr_t *call_site_count)
intptr_t current_ssa_temp_index() const
intptr_t max_block_id() const
const ParsedFunction & parsed_function() const
DART_NORETURN void Jump(int value, const Error &error)
static Object & ZoneHandle()
void AddToGuardedFields(const Field *field) const
LongJumpScope * long_jump_base() const
static Thread * Current()
DART_WARN_UNUSED_RESULT ErrorPtr StealStickyError()
#define COMPILER_TIMINGS_TIMER_SCOPE(thread, timer_id)
const uint8_t uint32_t uint32_t GError ** error
constexpr bool FLAG_support_il_printer
#define PRINT_INLINING_TREE(comment, caller, target, instance_call)
static bool IsSmallLeafOrReduction(int inlining_depth, intptr_t call_site_instructions, FlowGraph *graph)
static bool IsCallRecursive(const Function &function, Definition *call)
DirectChainedHashMap< FieldKeyValueTrait > FieldSet
static bool IsConstant(Definition *def, int64_t *val)