OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 #if !defined(DART_PRECOMPILED_RUNTIME) | 4 #if !defined(DART_PRECOMPILED_RUNTIME) |
5 #include "vm/flow_graph_inliner.h" | 5 #include "vm/flow_graph_inliner.h" |
6 | 6 |
7 #include "vm/aot_optimizer.h" | 7 #include "vm/aot_optimizer.h" |
8 #include "vm/precompiler.h" | 8 #include "vm/precompiler.h" |
9 #include "vm/block_scheduler.h" | 9 #include "vm/block_scheduler.h" |
10 #include "vm/branch_optimizer.h" | 10 #include "vm/branch_optimizer.h" |
(...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
467 PolymorphicInstanceCallInstr* call, | 467 PolymorphicInstanceCallInstr* call, |
468 const Function& caller_function, | 468 const Function& caller_function, |
469 intptr_t caller_inlining_id); | 469 intptr_t caller_inlining_id); |
470 | 470 |
471 void Inline(); | 471 void Inline(); |
472 | 472 |
473 private: | 473 private: |
474 bool CheckInlinedDuplicate(const Function& target); | 474 bool CheckInlinedDuplicate(const Function& target); |
475 bool CheckNonInlinedDuplicate(const Function& target); | 475 bool CheckNonInlinedDuplicate(const Function& target); |
476 | 476 |
477 bool TryInliningPoly(const CidRangeTarget& target); | 477 bool TryInliningPoly(const TargetInfo& target); |
478 bool TryInlineRecognizedMethod(intptr_t receiver_cid, const Function& target); | 478 bool TryInlineRecognizedMethod(intptr_t receiver_cid, const Function& target); |
479 | 479 |
480 TargetEntryInstr* BuildDecisionGraph(); | 480 TargetEntryInstr* BuildDecisionGraph(); |
481 | 481 |
482 Isolate* isolate() const; | 482 Isolate* isolate() const; |
483 Zone* zone() const; | 483 Zone* zone() const; |
484 intptr_t AllocateBlockId() const; | 484 intptr_t AllocateBlockId() const; |
485 inline bool trace_inlining() const; | 485 inline bool trace_inlining() const; |
486 | 486 |
487 CallSiteInliner* const owner_; | 487 CallSiteInliner* const owner_; |
(...skipping 951 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1439 | 1439 |
1440 | 1440 |
1441 PolymorphicInliner::PolymorphicInliner(CallSiteInliner* owner, | 1441 PolymorphicInliner::PolymorphicInliner(CallSiteInliner* owner, |
1442 PolymorphicInstanceCallInstr* call, | 1442 PolymorphicInstanceCallInstr* call, |
1443 const Function& caller_function, | 1443 const Function& caller_function, |
1444 intptr_t caller_inlining_id) | 1444 intptr_t caller_inlining_id) |
1445 : owner_(owner), | 1445 : owner_(owner), |
1446 call_(call), | 1446 call_(call), |
1447 num_variants_(call->NumberOfChecks()), | 1447 num_variants_(call->NumberOfChecks()), |
1448 variants_(call->targets_), | 1448 variants_(call->targets_), |
1449 inlined_variants_(), | 1449 inlined_variants_(zone()), |
1450 non_inlined_variants_(new (zone()) CallTargets()), | 1450 non_inlined_variants_(new (zone()) CallTargets(zone())), |
1451 inlined_entries_(num_variants_), | 1451 inlined_entries_(num_variants_), |
1452 exit_collector_(new (Z) InlineExitCollector(owner->caller_graph(), call)), | 1452 exit_collector_(new (Z) InlineExitCollector(owner->caller_graph(), call)), |
1453 caller_function_(caller_function), | 1453 caller_function_(caller_function), |
1454 caller_inlining_id_(caller_inlining_id) {} | 1454 caller_inlining_id_(caller_inlining_id) {} |
1455 | 1455 |
1456 | 1456 |
1457 Isolate* PolymorphicInliner::isolate() const { | 1457 Isolate* PolymorphicInliner::isolate() const { |
1458 return owner_->caller_graph()->isolate(); | 1458 return owner_->caller_graph()->isolate(); |
1459 } | 1459 } |
1460 | 1460 |
(...skipping 12 matching lines...) Expand all Loading... |
1473 // inlined target. This sharing is represented by using three different | 1473 // inlined target. This sharing is represented by using three different |
1474 // types of entries in the inlined_entries_ array: | 1474 // types of entries in the inlined_entries_ array: |
1475 // | 1475 // |
1476 // * GraphEntry: the inlined body is not shared. | 1476 // * GraphEntry: the inlined body is not shared. |
1477 // | 1477 // |
1478 // * TargetEntry: the inlined body is shared and this is the first variant. | 1478 // * TargetEntry: the inlined body is shared and this is the first variant. |
1479 // | 1479 // |
1480 // * JoinEntry: the inlined body is shared and this is a subsequent variant. | 1480 // * JoinEntry: the inlined body is shared and this is a subsequent variant. |
1481 bool PolymorphicInliner::CheckInlinedDuplicate(const Function& target) { | 1481 bool PolymorphicInliner::CheckInlinedDuplicate(const Function& target) { |
1482 for (intptr_t i = 0; i < inlined_variants_.length(); ++i) { | 1482 for (intptr_t i = 0; i < inlined_variants_.length(); ++i) { |
1483 if ((target.raw() == inlined_variants_[i].target->raw()) && | 1483 if ((target.raw() == inlined_variants_.TargetAt(i)->target->raw()) && |
1484 !MethodRecognizer::PolymorphicTarget(target)) { | 1484 !MethodRecognizer::PolymorphicTarget(target)) { |
1485 // The call target is shared with a previous inlined variant. Share | 1485 // The call target is shared with a previous inlined variant. Share |
1486 // the graph. This requires a join block at the entry, and edge-split | 1486 // the graph. This requires a join block at the entry, and edge-split |
1487 // form requires a target for each branch. | 1487 // form requires a target for each branch. |
1488 // | 1488 // |
1489 // Represent the sharing by recording a fresh target for the first | 1489 // Represent the sharing by recording a fresh target for the first |
1490 // variant and the shared join for all later variants. | 1490 // variant and the shared join for all later variants. |
1491 if (inlined_entries_[i]->IsGraphEntry()) { | 1491 if (inlined_entries_[i]->IsGraphEntry()) { |
1492 // Convert the old target entry to a new join entry. | 1492 // Convert the old target entry to a new join entry. |
1493 TargetEntryInstr* old_target = | 1493 TargetEntryInstr* old_target = |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1525 return true; | 1525 return true; |
1526 } | 1526 } |
1527 } | 1527 } |
1528 | 1528 |
1529 return false; | 1529 return false; |
1530 } | 1530 } |
1531 | 1531 |
1532 | 1532 |
1533 bool PolymorphicInliner::CheckNonInlinedDuplicate(const Function& target) { | 1533 bool PolymorphicInliner::CheckNonInlinedDuplicate(const Function& target) { |
1534 for (intptr_t i = 0; i < non_inlined_variants_->length(); ++i) { | 1534 for (intptr_t i = 0; i < non_inlined_variants_->length(); ++i) { |
1535 if (target.raw() == non_inlined_variants_->At(i).target->raw()) { | 1535 if (target.raw() == non_inlined_variants_->TargetAt(i)->target->raw()) { |
1536 return true; | 1536 return true; |
1537 } | 1537 } |
1538 } | 1538 } |
1539 | 1539 |
1540 return false; | 1540 return false; |
1541 } | 1541 } |
1542 | 1542 |
1543 | 1543 |
1544 bool PolymorphicInliner::TryInliningPoly(const CidRangeTarget& range) { | 1544 bool PolymorphicInliner::TryInliningPoly(const TargetInfo& target_info) { |
1545 if ((!FLAG_precompiled_mode || | 1545 if ((!FLAG_precompiled_mode || |
1546 owner_->inliner_->use_speculative_inlining()) && | 1546 owner_->inliner_->use_speculative_inlining()) && |
1547 range.cid_start == range.cid_end && | 1547 target_info.cid_start == target_info.cid_end && |
1548 TryInlineRecognizedMethod(range.cid_start, *range.target)) { | 1548 TryInlineRecognizedMethod(target_info.cid_start, *target_info.target)) { |
1549 owner_->inlined_ = true; | 1549 owner_->inlined_ = true; |
1550 return true; | 1550 return true; |
1551 } | 1551 } |
1552 | 1552 |
1553 GrowableArray<Value*> arguments(call_->ArgumentCount()); | 1553 GrowableArray<Value*> arguments(call_->ArgumentCount()); |
1554 for (int i = 0; i < call_->ArgumentCount(); ++i) { | 1554 for (int i = 0; i < call_->ArgumentCount(); ++i) { |
1555 arguments.Add(call_->PushArgumentAt(i)->value()); | 1555 arguments.Add(call_->PushArgumentAt(i)->value()); |
1556 } | 1556 } |
1557 InlinedCallData call_data(call_, &arguments, caller_function_, | 1557 InlinedCallData call_data(call_, &arguments, caller_function_, |
1558 caller_inlining_id_); | 1558 caller_inlining_id_); |
1559 Function& target = Function::ZoneHandle(zone(), range.target->raw()); | 1559 Function& target = Function::ZoneHandle(zone(), target_info.target->raw()); |
1560 if (!owner_->TryInlining(target, call_->instance_call()->argument_names(), | 1560 if (!owner_->TryInlining(target, call_->instance_call()->argument_names(), |
1561 &call_data)) { | 1561 &call_data)) { |
1562 return false; | 1562 return false; |
1563 } | 1563 } |
1564 | 1564 |
1565 FlowGraph* callee_graph = call_data.callee_graph; | 1565 FlowGraph* callee_graph = call_data.callee_graph; |
1566 call_data.exit_collector->PrepareGraphs(callee_graph); | 1566 call_data.exit_collector->PrepareGraphs(callee_graph); |
1567 inlined_entries_.Add(callee_graph->graph_entry()); | 1567 inlined_entries_.Add(callee_graph->graph_entry()); |
1568 exit_collector_->Union(call_data.exit_collector); | 1568 exit_collector_->Union(call_data.exit_collector); |
1569 | 1569 |
1570 // Replace parameter stubs and constants. Replace the receiver argument | 1570 // Replace parameter stubs and constants. Replace the receiver argument |
1571 // with a redefinition to prevent code from the inlined body from being | 1571 // with a redefinition to prevent code from the inlined body from being |
1572 // hoisted above the inlined entry. | 1572 // hoisted above the inlined entry. |
1573 ASSERT(arguments.length() > 0); | 1573 ASSERT(arguments.length() > 0); |
1574 Value* actual = arguments[0]; | 1574 Value* actual = arguments[0]; |
1575 RedefinitionInstr* redefinition = new (Z) RedefinitionInstr(actual->Copy(Z)); | 1575 RedefinitionInstr* redefinition = new (Z) RedefinitionInstr(actual->Copy(Z)); |
1576 redefinition->set_ssa_temp_index( | 1576 redefinition->set_ssa_temp_index( |
1577 owner_->caller_graph()->alloc_ssa_temp_index()); | 1577 owner_->caller_graph()->alloc_ssa_temp_index()); |
1578 if (range.cid_start == range.cid_end) { | 1578 if (target_info.cid_start == target_info.cid_end) { |
1579 redefinition->UpdateType(CompileType::FromCid(range.cid_start)); | 1579 redefinition->UpdateType(CompileType::FromCid(target_info.cid_start)); |
1580 } | 1580 } |
1581 redefinition->InsertAfter(callee_graph->graph_entry()->normal_entry()); | 1581 redefinition->InsertAfter(callee_graph->graph_entry()->normal_entry()); |
1582 Definition* stub = (*call_data.parameter_stubs)[0]; | 1582 Definition* stub = (*call_data.parameter_stubs)[0]; |
1583 stub->ReplaceUsesWith(redefinition); | 1583 stub->ReplaceUsesWith(redefinition); |
1584 | 1584 |
1585 for (intptr_t i = 1; i < arguments.length(); ++i) { | 1585 for (intptr_t i = 1; i < arguments.length(); ++i) { |
1586 actual = arguments[i]; | 1586 actual = arguments[i]; |
1587 if (actual != NULL) { | 1587 if (actual != NULL) { |
1588 stub = (*call_data.parameter_stubs)[i]; | 1588 stub = (*call_data.parameter_stubs)[i]; |
1589 stub->ReplaceUsesWith(actual->definition()); | 1589 stub->ReplaceUsesWith(actual->definition()); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1689 | 1689 |
1690 Definition* receiver = call_->ArgumentAt(0); | 1690 Definition* receiver = call_->ArgumentAt(0); |
1691 // There are at least two variants including non-inlined ones, so we have | 1691 // There are at least two variants including non-inlined ones, so we have |
1692 // at least one branch on the class id. | 1692 // at least one branch on the class id. |
1693 LoadClassIdInstr* load_cid = | 1693 LoadClassIdInstr* load_cid = |
1694 new (Z) LoadClassIdInstr(new (Z) Value(receiver)); | 1694 new (Z) LoadClassIdInstr(new (Z) Value(receiver)); |
1695 load_cid->set_ssa_temp_index(owner_->caller_graph()->alloc_ssa_temp_index()); | 1695 load_cid->set_ssa_temp_index(owner_->caller_graph()->alloc_ssa_temp_index()); |
1696 cursor = AppendInstruction(cursor, load_cid); | 1696 cursor = AppendInstruction(cursor, load_cid); |
1697 bool follow_with_deopt = false; | 1697 bool follow_with_deopt = false; |
1698 for (intptr_t i = 0; i < inlined_variants_.length(); ++i) { | 1698 for (intptr_t i = 0; i < inlined_variants_.length(); ++i) { |
1699 const CidRangeTarget& variant = inlined_variants_[i]; | 1699 const CidRange& variant = inlined_variants_[i]; |
1700 bool test_is_range = (variant.cid_start != variant.cid_end); | 1700 bool test_is_range = (variant.cid_start != variant.cid_end); |
1701 bool is_last_test = (i == inlined_variants_.length() - 1); | 1701 bool is_last_test = (i == inlined_variants_.length() - 1); |
1702 // 1. Guard the body with a class id check. We don't need any check if | 1702 // 1. Guard the body with a class id check. We don't need any check if |
1703 // it's the last test and global analysis has told us that the call is | 1703 // it's the last test and global analysis has told us that the call is |
1704 // complete. TODO(erikcorry): Enhance CheckClassIdInstr so it can take an | 1704 // complete. TODO(erikcorry): Enhance CheckClassIdInstr so it can take an |
1705 // arbitrary CidRangeTarget. Currently we don't go into this branch if the | 1705 // arbitrary CidRangeTarget. Currently we don't go into this branch if the |
1706 // last test is a range test - instead we set the follow_with_deopt flag. | 1706 // last test is a range test - instead we set the follow_with_deopt flag. |
1707 if (is_last_test && (!test_is_range || call_->complete()) && | 1707 if (is_last_test && (!test_is_range || call_->complete()) && |
1708 non_inlined_variants_->is_empty()) { | 1708 non_inlined_variants_->is_empty()) { |
1709 // If it is the last variant use a check class id instruction which can | 1709 // If it is the last variant use a check class id instruction which can |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1919 for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) { | 1919 for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) { |
1920 PushArgumentInstr* push = call_->PushArgumentAt(i); | 1920 PushArgumentInstr* push = call_->PushArgumentAt(i); |
1921 push->ReplaceUsesWith(push->value()->definition()); | 1921 push->ReplaceUsesWith(push->value()->definition()); |
1922 push->RemoveFromGraph(); | 1922 push->RemoveFromGraph(); |
1923 } | 1923 } |
1924 } | 1924 } |
1925 return entry; | 1925 return entry; |
1926 } | 1926 } |
1927 | 1927 |
1928 | 1928 |
1929 static void TracePolyInlining(const CidRangeTarget& crt, | 1929 static void TracePolyInlining(const CallTargets& targets, |
| 1930 intptr_t idx, |
1930 intptr_t total, | 1931 intptr_t total, |
1931 const char* message) { | 1932 const char* message) { |
1932 String& name = String::Handle(crt.target->QualifiedUserVisibleName()); | 1933 String& name = |
1933 int percent = total == 0 ? 0 : (100 * crt.count) / total; | 1934 String::Handle(targets.TargetAt(idx)->target->QualifiedUserVisibleName()); |
| 1935 int percent = total == 0 ? 0 : (100 * targets.TargetAt(idx)->count) / total; |
1934 THR_Print("%s cid %" Pd "-%" Pd ": %" Pd "/%" Pd " %d%% %s\n", | 1936 THR_Print("%s cid %" Pd "-%" Pd ": %" Pd "/%" Pd " %d%% %s\n", |
1935 name.ToCString(), crt.cid_start, crt.cid_end, crt.count, total, | 1937 name.ToCString(), targets[idx].cid_start, targets[idx].cid_end, |
1936 percent, message); | 1938 targets.TargetAt(idx)->count, total, percent, message); |
1937 } | 1939 } |
1938 | 1940 |
1939 | 1941 |
1940 bool PolymorphicInliner::trace_inlining() const { | 1942 bool PolymorphicInliner::trace_inlining() const { |
1941 return owner_->trace_inlining(); | 1943 return owner_->trace_inlining(); |
1942 } | 1944 } |
1943 | 1945 |
1944 | 1946 |
1945 void PolymorphicInliner::Inline() { | 1947 void PolymorphicInliner::Inline() { |
1946 ASSERT(&variants_ == &call_->targets_); | 1948 ASSERT(&variants_ == &call_->targets_); |
1947 | 1949 |
1948 intptr_t total = call_->total_call_count(); | 1950 intptr_t total = call_->total_call_count(); |
1949 for (intptr_t var_idx = 0; var_idx < variants_.length(); ++var_idx) { | 1951 for (intptr_t var_idx = 0; var_idx < variants_.length(); ++var_idx) { |
| 1952 TargetInfo* info = variants_.TargetAt(var_idx); |
1950 if (variants_.length() > FLAG_max_polymorphic_checks) { | 1953 if (variants_.length() > FLAG_max_polymorphic_checks) { |
1951 non_inlined_variants_->Add(variants_[var_idx]); | 1954 non_inlined_variants_->Add(info); |
1952 continue; | 1955 continue; |
1953 } | 1956 } |
1954 | 1957 |
| 1958 const Function& target = *variants_.TargetAt(var_idx)->target; |
| 1959 const intptr_t count = variants_.TargetAt(var_idx)->count; |
| 1960 |
1955 // We we almost inlined all the cases then try a little harder to inline | 1961 // We we almost inlined all the cases then try a little harder to inline |
1956 // the last two, because it's a big win if we inline all of them (compiler | 1962 // the last two, because it's a big win if we inline all of them (compiler |
1957 // can see all side effects). | 1963 // can see all side effects). |
1958 const bool try_harder = (var_idx >= variants_.length() - 2) && | 1964 const bool try_harder = (var_idx >= variants_.length() - 2) && |
1959 non_inlined_variants_->length() == 0; | 1965 non_inlined_variants_->length() == 0; |
1960 const Function& target = *variants_[var_idx].target; | |
1961 const intptr_t count = variants_[var_idx].count; | |
1962 | 1966 |
1963 intptr_t size = target.optimized_instruction_count(); | 1967 intptr_t size = target.optimized_instruction_count(); |
1964 bool small = (size != 0 && size < FLAG_inlining_size_threshold); | 1968 bool small = (size != 0 && size < FLAG_inlining_size_threshold); |
1965 | 1969 |
1966 // If it's less than 3% of the dispatches, we won't even consider | 1970 // If it's less than 3% of the dispatches, we won't even consider |
1967 // checking for the class ID and branching to another already-inlined | 1971 // checking for the class ID and branching to another already-inlined |
1968 // version. | 1972 // version. |
1969 if (!try_harder && count < (total >> 5)) { | 1973 if (!try_harder && count < (total >> 5)) { |
1970 TRACE_INLINING( | 1974 TRACE_INLINING( |
1971 TracePolyInlining(variants_[var_idx], total, "way too infrequent")); | 1975 TracePolyInlining(variants_, var_idx, total, "way too infrequent")); |
1972 non_inlined_variants_->Add(variants_[var_idx]); | 1976 non_inlined_variants_->Add(info); |
1973 continue; | 1977 continue; |
1974 } | 1978 } |
1975 | 1979 |
1976 // First check if this is the same target as an earlier inlined variant. | 1980 // First check if this is the same target as an earlier inlined variant. |
1977 if (CheckInlinedDuplicate(target)) { | 1981 if (CheckInlinedDuplicate(target)) { |
1978 TRACE_INLINING(TracePolyInlining(variants_[var_idx], total, | 1982 TRACE_INLINING(TracePolyInlining(variants_, var_idx, total, |
1979 "duplicate already inlined")); | 1983 "duplicate already inlined")); |
1980 inlined_variants_.Add(variants_[var_idx]); | 1984 inlined_variants_.Add(info); |
1981 continue; | 1985 continue; |
1982 } | 1986 } |
1983 | 1987 |
1984 // If it's less than 12% of the dispatches and it's not already inlined, we | 1988 // If it's less than 12% of the dispatches and it's not already inlined, we |
1985 // don't consider inlining. For very small functions we are willing to | 1989 // don't consider inlining. For very small functions we are willing to |
1986 // consider inlining for 6% of the cases. | 1990 // consider inlining for 6% of the cases. |
1987 if (!try_harder && count < (total >> (small ? 4 : 3))) { | 1991 if (!try_harder && count < (total >> (small ? 4 : 3))) { |
1988 TRACE_INLINING( | 1992 TRACE_INLINING( |
1989 TracePolyInlining(variants_[var_idx], total, "too infrequent")); | 1993 TracePolyInlining(variants_, var_idx, total, "too infrequent")); |
1990 non_inlined_variants_->Add(variants_[var_idx]); | 1994 non_inlined_variants_->Add(&variants_[var_idx]); |
1991 continue; | 1995 continue; |
1992 } | 1996 } |
1993 | 1997 |
1994 // Also check if this is the same target as an earlier non-inlined | 1998 // Also check if this is the same target as an earlier non-inlined |
1995 // variant. If so and since inlining decisions are costly, do not try | 1999 // variant. If so and since inlining decisions are costly, do not try |
1996 // to inline this variant. | 2000 // to inline this variant. |
1997 if (CheckNonInlinedDuplicate(target)) { | 2001 if (CheckNonInlinedDuplicate(target)) { |
1998 TRACE_INLINING( | 2002 TRACE_INLINING( |
1999 TracePolyInlining(variants_[var_idx], total, "already not inlined")); | 2003 TracePolyInlining(variants_, var_idx, total, "already not inlined")); |
2000 non_inlined_variants_->Add(variants_[var_idx]); | 2004 non_inlined_variants_->Add(&variants_[var_idx]); |
2001 continue; | 2005 continue; |
2002 } | 2006 } |
2003 | 2007 |
2004 // Make an inlining decision. | 2008 // Make an inlining decision. |
2005 if (TryInliningPoly(variants_[var_idx])) { | 2009 if (TryInliningPoly(*info)) { |
2006 TRACE_INLINING(TracePolyInlining(variants_[var_idx], total, "inlined")); | 2010 TRACE_INLINING(TracePolyInlining(variants_, var_idx, total, "inlined")); |
2007 inlined_variants_.Add(variants_[var_idx]); | 2011 inlined_variants_.Add(&variants_[var_idx]); |
2008 } else { | 2012 } else { |
2009 TRACE_INLINING( | 2013 TRACE_INLINING( |
2010 TracePolyInlining(variants_[var_idx], total, "not inlined")); | 2014 TracePolyInlining(variants_, var_idx, total, "not inlined")); |
2011 non_inlined_variants_->Add(variants_[var_idx]); | 2015 non_inlined_variants_->Add(&variants_[var_idx]); |
2012 } | 2016 } |
2013 } | 2017 } |
2014 | 2018 |
2015 // If there are no inlined variants, leave the call in place. | 2019 // If there are no inlined variants, leave the call in place. |
2016 if (inlined_variants_.is_empty()) return; | 2020 if (inlined_variants_.is_empty()) return; |
2017 | 2021 |
2018 // Now build a decision tree (a DAG because of shared inline variants) and | 2022 // Now build a decision tree (a DAG because of shared inline variants) and |
2019 // inline it at the call site. | 2023 // inline it at the call site. |
2020 TargetEntryInstr* entry = BuildDecisionGraph(); | 2024 TargetEntryInstr* entry = BuildDecisionGraph(); |
2021 exit_collector_->ReplaceCall(entry); | 2025 exit_collector_->ReplaceCall(entry); |
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2262 } else if (RawObject::IsExternalTypedDataClassId(array_cid)) { | 2266 } else if (RawObject::IsExternalTypedDataClassId(array_cid)) { |
2263 LoadUntaggedInstr* elements = new (Z) LoadUntaggedInstr( | 2267 LoadUntaggedInstr* elements = new (Z) LoadUntaggedInstr( |
2264 new (Z) Value(*array), ExternalTypedData::data_offset()); | 2268 new (Z) Value(*array), ExternalTypedData::data_offset()); |
2265 *cursor = flow_graph->AppendTo(*cursor, elements, NULL, FlowGraph::kValue); | 2269 *cursor = flow_graph->AppendTo(*cursor, elements, NULL, FlowGraph::kValue); |
2266 *array = elements; | 2270 *array = elements; |
2267 } | 2271 } |
2268 return array_cid; | 2272 return array_cid; |
2269 } | 2273 } |
2270 | 2274 |
2271 | 2275 |
2272 static Instruction* GetCheckClass(FlowGraph* flow_graph, | |
2273 Definition* to_check, | |
2274 const ICData& unary_checks, | |
2275 intptr_t deopt_id, | |
2276 TokenPosition token_pos) { | |
2277 if ((unary_checks.NumberOfUsedChecks() == 1) && | |
2278 unary_checks.HasReceiverClassId(kSmiCid)) { | |
2279 return new (Z) CheckSmiInstr(new (Z) Value(to_check), deopt_id, token_pos); | |
2280 } | |
2281 return new (Z) CheckClassInstr(new (Z) Value(to_check), deopt_id, | |
2282 unary_checks, token_pos); | |
2283 } | |
2284 | |
2285 | |
2286 static bool InlineGetIndexed(FlowGraph* flow_graph, | 2276 static bool InlineGetIndexed(FlowGraph* flow_graph, |
2287 MethodRecognizer::Kind kind, | 2277 MethodRecognizer::Kind kind, |
2288 Instruction* call, | 2278 Instruction* call, |
2289 Definition* receiver, | 2279 Definition* receiver, |
2290 TargetEntryInstr** entry, | 2280 TargetEntryInstr** entry, |
2291 Definition** last) { | 2281 Definition** last) { |
2292 intptr_t array_cid = MethodRecognizer::MethodKindToReceiverCid(kind); | 2282 intptr_t array_cid = MethodRecognizer::MethodKindToReceiverCid(kind); |
2293 | 2283 |
2294 Definition* array = receiver; | 2284 Definition* array = receiver; |
2295 Definition* index = call->ArgumentAt(1); | 2285 Definition* index = call->ArgumentAt(1); |
(...skipping 30 matching lines...) Expand all Loading... |
2326 return true; | 2316 return true; |
2327 } | 2317 } |
2328 | 2318 |
2329 | 2319 |
2330 static bool InlineSetIndexed(FlowGraph* flow_graph, | 2320 static bool InlineSetIndexed(FlowGraph* flow_graph, |
2331 MethodRecognizer::Kind kind, | 2321 MethodRecognizer::Kind kind, |
2332 const Function& target, | 2322 const Function& target, |
2333 Instruction* call, | 2323 Instruction* call, |
2334 Definition* receiver, | 2324 Definition* receiver, |
2335 TokenPosition token_pos, | 2325 TokenPosition token_pos, |
2336 const ICData& value_check, | 2326 const Cids* value_check, |
2337 TargetEntryInstr** entry, | 2327 TargetEntryInstr** entry, |
2338 Definition** last) { | 2328 Definition** last) { |
2339 intptr_t array_cid = MethodRecognizer::MethodKindToReceiverCid(kind); | 2329 intptr_t array_cid = MethodRecognizer::MethodKindToReceiverCid(kind); |
2340 | 2330 |
2341 Definition* array = receiver; | 2331 Definition* array = receiver; |
2342 Definition* index = call->ArgumentAt(1); | 2332 Definition* index = call->ArgumentAt(1); |
2343 Definition* stored_value = call->ArgumentAt(2); | 2333 Definition* stored_value = call->ArgumentAt(2); |
2344 | 2334 |
2345 *entry = new (Z) TargetEntryInstr(flow_graph->allocate_block_id(), | 2335 *entry = new (Z) TargetEntryInstr(flow_graph->allocate_block_id(), |
2346 call->GetBlock()->try_index()); | 2336 call->GetBlock()->try_index()); |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2421 StoreBarrierType needs_store_barrier = | 2411 StoreBarrierType needs_store_barrier = |
2422 (RawObject::IsTypedDataClassId(array_cid) || | 2412 (RawObject::IsTypedDataClassId(array_cid) || |
2423 RawObject::IsTypedDataViewClassId(array_cid) || | 2413 RawObject::IsTypedDataViewClassId(array_cid) || |
2424 RawObject::IsExternalTypedDataClassId(array_cid)) | 2414 RawObject::IsExternalTypedDataClassId(array_cid)) |
2425 ? kNoStoreBarrier | 2415 ? kNoStoreBarrier |
2426 : kEmitStoreBarrier; | 2416 : kEmitStoreBarrier; |
2427 | 2417 |
2428 // No need to class check stores to Int32 and Uint32 arrays because | 2418 // No need to class check stores to Int32 and Uint32 arrays because |
2429 // we insert unboxing instructions below which include a class check. | 2419 // we insert unboxing instructions below which include a class check. |
2430 if ((array_cid != kTypedDataUint32ArrayCid) && | 2420 if ((array_cid != kTypedDataUint32ArrayCid) && |
2431 (array_cid != kTypedDataInt32ArrayCid) && !value_check.IsNull()) { | 2421 (array_cid != kTypedDataInt32ArrayCid) && value_check != NULL) { |
2432 // No store barrier needed because checked value is a smi, an unboxed mint, | 2422 // No store barrier needed because checked value is a smi, an unboxed mint, |
2433 // an unboxed double, an unboxed Float32x4, or unboxed Int32x4. | 2423 // an unboxed double, an unboxed Float32x4, or unboxed Int32x4. |
2434 needs_store_barrier = kNoStoreBarrier; | 2424 needs_store_barrier = kNoStoreBarrier; |
2435 Instruction* check = GetCheckClass(flow_graph, stored_value, value_check, | 2425 Instruction* check = flow_graph->CreateCheckClass( |
2436 call->deopt_id(), call->token_pos()); | 2426 stored_value, *value_check, call->deopt_id(), call->token_pos()); |
2437 cursor = | 2427 cursor = |
2438 flow_graph->AppendTo(cursor, check, call->env(), FlowGraph::kEffect); | 2428 flow_graph->AppendTo(cursor, check, call->env(), FlowGraph::kEffect); |
2439 } | 2429 } |
2440 | 2430 |
2441 if (array_cid == kTypedDataFloat32ArrayCid) { | 2431 if (array_cid == kTypedDataFloat32ArrayCid) { |
2442 stored_value = new (Z) | 2432 stored_value = new (Z) |
2443 DoubleToFloatInstr(new (Z) Value(stored_value), call->deopt_id()); | 2433 DoubleToFloatInstr(new (Z) Value(stored_value), call->deopt_id()); |
2444 cursor = | 2434 cursor = |
2445 flow_graph->AppendTo(cursor, stored_value, NULL, FlowGraph::kValue); | 2435 flow_graph->AppendTo(cursor, stored_value, NULL, FlowGraph::kValue); |
2446 } else if (array_cid == kTypedDataInt32ArrayCid) { | 2436 } else if (array_cid == kTypedDataInt32ArrayCid) { |
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2689 // Extract the instance call so we can use the function_name in the stored | 2679 // Extract the instance call so we can use the function_name in the stored |
2690 // value check ICData. | 2680 // value check ICData. |
2691 InstanceCallInstr* i_call = NULL; | 2681 InstanceCallInstr* i_call = NULL; |
2692 if (call->IsPolymorphicInstanceCall()) { | 2682 if (call->IsPolymorphicInstanceCall()) { |
2693 i_call = call->AsPolymorphicInstanceCall()->instance_call(); | 2683 i_call = call->AsPolymorphicInstanceCall()->instance_call(); |
2694 } else { | 2684 } else { |
2695 ASSERT(call->IsInstanceCall()); | 2685 ASSERT(call->IsInstanceCall()); |
2696 i_call = call->AsInstanceCall(); | 2686 i_call = call->AsInstanceCall(); |
2697 } | 2687 } |
2698 ASSERT(i_call != NULL); | 2688 ASSERT(i_call != NULL); |
2699 ICData& value_check = ICData::ZoneHandle(Z); | 2689 Cids* value_check = NULL; |
2700 switch (view_cid) { | 2690 switch (view_cid) { |
2701 case kTypedDataInt8ArrayCid: | 2691 case kTypedDataInt8ArrayCid: |
2702 case kTypedDataUint8ArrayCid: | 2692 case kTypedDataUint8ArrayCid: |
2703 case kTypedDataUint8ClampedArrayCid: | 2693 case kTypedDataUint8ClampedArrayCid: |
2704 case kExternalTypedDataUint8ArrayCid: | 2694 case kExternalTypedDataUint8ArrayCid: |
2705 case kExternalTypedDataUint8ClampedArrayCid: | 2695 case kExternalTypedDataUint8ClampedArrayCid: |
2706 case kTypedDataInt16ArrayCid: | 2696 case kTypedDataInt16ArrayCid: |
2707 case kTypedDataUint16ArrayCid: { | 2697 case kTypedDataUint16ArrayCid: { |
2708 // Check that value is always smi. | 2698 // Check that value is always smi. |
2709 value_check = ICData::New(flow_graph->function(), i_call->function_name(), | 2699 value_check = Cids::CreateMonomorphic(Z, kSmiCid); |
2710 Object::empty_array(), // Dummy args. descr. | |
2711 Thread::kNoDeoptId, 1, false); | |
2712 value_check.AddReceiverCheck(kSmiCid, target); | |
2713 break; | 2700 break; |
2714 } | 2701 } |
2715 case kTypedDataInt32ArrayCid: | 2702 case kTypedDataInt32ArrayCid: |
2716 case kTypedDataUint32ArrayCid: | 2703 case kTypedDataUint32ArrayCid: |
2717 // On 64-bit platforms assume that stored value is always a smi. | 2704 // On 64-bit platforms assume that stored value is always a smi. |
2718 if (kSmiBits >= 32) { | 2705 if (kSmiBits >= 32) { |
2719 value_check = | 2706 value_check = Cids::CreateMonomorphic(Z, kSmiCid); |
2720 ICData::New(flow_graph->function(), i_call->function_name(), | |
2721 Object::empty_array(), // Dummy args. descr. | |
2722 Thread::kNoDeoptId, 1, false); | |
2723 value_check.AddReceiverCheck(kSmiCid, target); | |
2724 } | 2707 } |
2725 break; | 2708 break; |
2726 case kTypedDataFloat32ArrayCid: | 2709 case kTypedDataFloat32ArrayCid: |
2727 case kTypedDataFloat64ArrayCid: { | 2710 case kTypedDataFloat64ArrayCid: { |
2728 // Check that value is always double. | 2711 // Check that value is always double. |
2729 value_check = ICData::New(flow_graph->function(), i_call->function_name(), | 2712 value_check = Cids::CreateMonomorphic(Z, kDoubleCid); |
2730 Object::empty_array(), // Dummy args. descr. | |
2731 Thread::kNoDeoptId, 1, false); | |
2732 value_check.AddReceiverCheck(kDoubleCid, target); | |
2733 break; | 2713 break; |
2734 } | 2714 } |
2735 case kTypedDataInt32x4ArrayCid: { | 2715 case kTypedDataInt32x4ArrayCid: { |
2736 // Check that value is always Int32x4. | 2716 // Check that value is always Int32x4. |
2737 value_check = ICData::New(flow_graph->function(), i_call->function_name(), | 2717 value_check = Cids::CreateMonomorphic(Z, kInt32x4Cid); |
2738 Object::empty_array(), // Dummy args. descr. | |
2739 Thread::kNoDeoptId, 1, false); | |
2740 value_check.AddReceiverCheck(kInt32x4Cid, target); | |
2741 break; | 2718 break; |
2742 } | 2719 } |
2743 case kTypedDataFloat32x4ArrayCid: { | 2720 case kTypedDataFloat32x4ArrayCid: { |
2744 // Check that value is always Float32x4. | 2721 // Check that value is always Float32x4. |
2745 value_check = ICData::New(flow_graph->function(), i_call->function_name(), | 2722 value_check = Cids::CreateMonomorphic(Z, kFloat32x4Cid); |
2746 Object::empty_array(), // Dummy args. descr. | |
2747 Thread::kNoDeoptId, 1, false); | |
2748 value_check.AddReceiverCheck(kFloat32x4Cid, target); | |
2749 break; | 2723 break; |
2750 } | 2724 } |
2751 default: | 2725 default: |
2752 // Array cids are already checked in the caller. | 2726 // Array cids are already checked in the caller. |
2753 UNREACHABLE(); | 2727 UNREACHABLE(); |
2754 } | 2728 } |
2755 | 2729 |
2756 Definition* stored_value = call->ArgumentAt(2); | 2730 Definition* stored_value = call->ArgumentAt(2); |
2757 if (!value_check.IsNull()) { | 2731 if (value_check != NULL) { |
2758 Instruction* check = GetCheckClass(flow_graph, stored_value, value_check, | 2732 Instruction* check = flow_graph->CreateCheckClass( |
2759 call->deopt_id(), call->token_pos()); | 2733 stored_value, *value_check, call->deopt_id(), call->token_pos()); |
2760 cursor = | 2734 cursor = |
2761 flow_graph->AppendTo(cursor, check, call->env(), FlowGraph::kEffect); | 2735 flow_graph->AppendTo(cursor, check, call->env(), FlowGraph::kEffect); |
2762 } | 2736 } |
2763 | 2737 |
2764 if (view_cid == kTypedDataFloat32ArrayCid) { | 2738 if (view_cid == kTypedDataFloat32ArrayCid) { |
2765 stored_value = new (Z) | 2739 stored_value = new (Z) |
2766 DoubleToFloatInstr(new (Z) Value(stored_value), call->deopt_id()); | 2740 DoubleToFloatInstr(new (Z) Value(stored_value), call->deopt_id()); |
2767 cursor = | 2741 cursor = |
2768 flow_graph->AppendTo(cursor, stored_value, NULL, FlowGraph::kValue); | 2742 flow_graph->AppendTo(cursor, stored_value, NULL, FlowGraph::kValue); |
2769 } else if (view_cid == kTypedDataInt32ArrayCid) { | 2743 } else if (view_cid == kTypedDataInt32ArrayCid) { |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2909 const intptr_t receiver_cid = class_ids[0]; | 2883 const intptr_t receiver_cid = class_ids[0]; |
2910 | 2884 |
2911 TargetEntryInstr* entry; | 2885 TargetEntryInstr* entry; |
2912 Definition* last; | 2886 Definition* last; |
2913 if (FlowGraphInliner::TryInlineRecognizedMethod( | 2887 if (FlowGraphInliner::TryInlineRecognizedMethod( |
2914 flow_graph, receiver_cid, target, call, call->ArgumentAt(0), | 2888 flow_graph, receiver_cid, target, call, call->ArgumentAt(0), |
2915 call->token_pos(), *call->ic_data(), &entry, &last)) { | 2889 call->token_pos(), *call->ic_data(), &entry, &last)) { |
2916 // Insert receiver class check if needed. | 2890 // Insert receiver class check if needed. |
2917 if (MethodRecognizer::PolymorphicTarget(target) || | 2891 if (MethodRecognizer::PolymorphicTarget(target) || |
2918 flow_graph->InstanceCallNeedsClassCheck(call, target.kind())) { | 2892 flow_graph->InstanceCallNeedsClassCheck(call, target.kind())) { |
2919 Instruction* check = GetCheckClass( | 2893 Instruction* check = flow_graph->CreateCheckClass( |
2920 flow_graph, call->ArgumentAt(0), | 2894 call->ArgumentAt(0), *Cids::Create(Z, *call->ic_data(), 0), |
2921 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()), | |
2922 call->deopt_id(), call->token_pos()); | 2895 call->deopt_id(), call->token_pos()); |
2923 flow_graph->InsertBefore(call, check, call->env(), FlowGraph::kEffect); | 2896 flow_graph->InsertBefore(call, check, call->env(), FlowGraph::kEffect); |
2924 } | 2897 } |
2925 | 2898 |
2926 // Remove the original push arguments. | 2899 // Remove the original push arguments. |
2927 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | 2900 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
2928 PushArgumentInstr* push = call->PushArgumentAt(i); | 2901 PushArgumentInstr* push = call->PushArgumentAt(i); |
2929 push->ReplaceUsesWith(push->value()->definition()); | 2902 push->ReplaceUsesWith(push->value()->definition()); |
2930 push->RemoveFromGraph(); | 2903 push->RemoveFromGraph(); |
2931 } | 2904 } |
(...skipping 466 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3398 | 3371 |
3399 bool FlowGraphInliner::TryInlineRecognizedMethod(FlowGraph* flow_graph, | 3372 bool FlowGraphInliner::TryInlineRecognizedMethod(FlowGraph* flow_graph, |
3400 intptr_t receiver_cid, | 3373 intptr_t receiver_cid, |
3401 const Function& target, | 3374 const Function& target, |
3402 Definition* call, | 3375 Definition* call, |
3403 Definition* receiver, | 3376 Definition* receiver, |
3404 TokenPosition token_pos, | 3377 TokenPosition token_pos, |
3405 const ICData& ic_data, | 3378 const ICData& ic_data, |
3406 TargetEntryInstr** entry, | 3379 TargetEntryInstr** entry, |
3407 Definition** last) { | 3380 Definition** last) { |
3408 ICData& value_check = ICData::ZoneHandle(Z); | |
3409 MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(target); | 3381 MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(target); |
3410 switch (kind) { | 3382 switch (kind) { |
3411 // Recognized [] operators. | 3383 // Recognized [] operators. |
3412 case MethodRecognizer::kImmutableArrayGetIndexed: | 3384 case MethodRecognizer::kImmutableArrayGetIndexed: |
3413 case MethodRecognizer::kObjectArrayGetIndexed: | 3385 case MethodRecognizer::kObjectArrayGetIndexed: |
3414 case MethodRecognizer::kGrowableArrayGetIndexed: | 3386 case MethodRecognizer::kGrowableArrayGetIndexed: |
3415 case MethodRecognizer::kInt8ArrayGetIndexed: | 3387 case MethodRecognizer::kInt8ArrayGetIndexed: |
3416 case MethodRecognizer::kUint8ArrayGetIndexed: | 3388 case MethodRecognizer::kUint8ArrayGetIndexed: |
3417 case MethodRecognizer::kUint8ClampedArrayGetIndexed: | 3389 case MethodRecognizer::kUint8ClampedArrayGetIndexed: |
3418 case MethodRecognizer::kExternalUint8ArrayGetIndexed: | 3390 case MethodRecognizer::kExternalUint8ArrayGetIndexed: |
(...skipping 20 matching lines...) Expand all Loading... |
3439 | 3411 |
3440 case MethodRecognizer::kInt64ArrayGetIndexed: | 3412 case MethodRecognizer::kInt64ArrayGetIndexed: |
3441 if (!ShouldInlineInt64ArrayOps()) { | 3413 if (!ShouldInlineInt64ArrayOps()) { |
3442 return false; | 3414 return false; |
3443 } | 3415 } |
3444 return InlineGetIndexed(flow_graph, kind, call, receiver, entry, last); | 3416 return InlineGetIndexed(flow_graph, kind, call, receiver, entry, last); |
3445 // Recognized []= operators. | 3417 // Recognized []= operators. |
3446 case MethodRecognizer::kObjectArraySetIndexed: | 3418 case MethodRecognizer::kObjectArraySetIndexed: |
3447 case MethodRecognizer::kGrowableArraySetIndexed: | 3419 case MethodRecognizer::kGrowableArraySetIndexed: |
3448 return InlineSetIndexed(flow_graph, kind, target, call, receiver, | 3420 return InlineSetIndexed(flow_graph, kind, target, call, receiver, |
3449 token_pos, value_check, entry, last); | 3421 token_pos, /* value_check = */ NULL, entry, last); |
3450 case MethodRecognizer::kInt8ArraySetIndexed: | 3422 case MethodRecognizer::kInt8ArraySetIndexed: |
3451 case MethodRecognizer::kUint8ArraySetIndexed: | 3423 case MethodRecognizer::kUint8ArraySetIndexed: |
3452 case MethodRecognizer::kUint8ClampedArraySetIndexed: | 3424 case MethodRecognizer::kUint8ClampedArraySetIndexed: |
3453 case MethodRecognizer::kExternalUint8ArraySetIndexed: | 3425 case MethodRecognizer::kExternalUint8ArraySetIndexed: |
3454 case MethodRecognizer::kExternalUint8ClampedArraySetIndexed: | 3426 case MethodRecognizer::kExternalUint8ClampedArraySetIndexed: |
3455 case MethodRecognizer::kInt16ArraySetIndexed: | 3427 case MethodRecognizer::kInt16ArraySetIndexed: |
3456 case MethodRecognizer::kUint16ArraySetIndexed: | 3428 case MethodRecognizer::kUint16ArraySetIndexed: { |
3457 // Optimistically assume Smi. | 3429 // Optimistically assume Smi. |
3458 if (ic_data.HasDeoptReason(ICData::kDeoptCheckSmi)) { | 3430 if (ic_data.HasDeoptReason(ICData::kDeoptCheckSmi)) { |
3459 // Optimistic assumption failed at least once. | 3431 // Optimistic assumption failed at least once. |
3460 return false; | 3432 return false; |
3461 } | 3433 } |
3462 value_check = ic_data.AsUnaryClassChecksForCid(kSmiCid, target); | 3434 Cids* value_check = Cids::CreateMonomorphic(Z, kSmiCid); |
3463 return InlineSetIndexed(flow_graph, kind, target, call, receiver, | 3435 return InlineSetIndexed(flow_graph, kind, target, call, receiver, |
3464 token_pos, value_check, entry, last); | 3436 token_pos, value_check, entry, last); |
| 3437 } |
3465 case MethodRecognizer::kInt32ArraySetIndexed: | 3438 case MethodRecognizer::kInt32ArraySetIndexed: |
3466 case MethodRecognizer::kUint32ArraySetIndexed: { | 3439 case MethodRecognizer::kUint32ArraySetIndexed: { |
3467 // Value check not needed for Int32 and Uint32 arrays because they | 3440 // Value check not needed for Int32 and Uint32 arrays because they |
3468 // implicitly contain unboxing instructions which check for right type. | 3441 // implicitly contain unboxing instructions which check for right type. |
3469 ICData& value_check = ICData::Handle(); | |
3470 return InlineSetIndexed(flow_graph, kind, target, call, receiver, | 3442 return InlineSetIndexed(flow_graph, kind, target, call, receiver, |
3471 token_pos, value_check, entry, last); | 3443 token_pos, /* value_check = */ NULL, entry, last); |
3472 } | 3444 } |
3473 case MethodRecognizer::kInt64ArraySetIndexed: | 3445 case MethodRecognizer::kInt64ArraySetIndexed: |
3474 if (!ShouldInlineInt64ArrayOps()) { | 3446 if (!ShouldInlineInt64ArrayOps()) { |
3475 return false; | 3447 return false; |
3476 } | 3448 } |
3477 return InlineSetIndexed(flow_graph, kind, target, call, receiver, | 3449 return InlineSetIndexed(flow_graph, kind, target, call, receiver, |
3478 token_pos, value_check, entry, last); | 3450 token_pos, /* value_check = */ NULL, entry, last); |
3479 case MethodRecognizer::kFloat32ArraySetIndexed: | 3451 case MethodRecognizer::kFloat32ArraySetIndexed: |
3480 case MethodRecognizer::kFloat64ArraySetIndexed: | 3452 case MethodRecognizer::kFloat64ArraySetIndexed: { |
3481 if (!CanUnboxDouble()) { | 3453 if (!CanUnboxDouble()) { |
3482 return false; | 3454 return false; |
3483 } | 3455 } |
3484 value_check = ic_data.AsUnaryClassChecksForCid(kDoubleCid, target); | 3456 Cids* value_check = Cids::CreateMonomorphic(Z, kDoubleCid); |
3485 return InlineSetIndexed(flow_graph, kind, target, call, receiver, | 3457 return InlineSetIndexed(flow_graph, kind, target, call, receiver, |
3486 token_pos, value_check, entry, last); | 3458 token_pos, value_check, entry, last); |
3487 case MethodRecognizer::kFloat32x4ArraySetIndexed: | 3459 } |
| 3460 case MethodRecognizer::kFloat32x4ArraySetIndexed: { |
3488 if (!ShouldInlineSimd()) { | 3461 if (!ShouldInlineSimd()) { |
3489 return false; | 3462 return false; |
3490 } | 3463 } |
3491 value_check = ic_data.AsUnaryClassChecksForCid(kFloat32x4Cid, target); | 3464 Cids* value_check = Cids::CreateMonomorphic(Z, kFloat32x4Cid); |
3492 | |
3493 return InlineSetIndexed(flow_graph, kind, target, call, receiver, | 3465 return InlineSetIndexed(flow_graph, kind, target, call, receiver, |
3494 token_pos, value_check, entry, last); | 3466 token_pos, value_check, entry, last); |
3495 case MethodRecognizer::kFloat64x2ArraySetIndexed: | 3467 } |
| 3468 case MethodRecognizer::kFloat64x2ArraySetIndexed: { |
3496 if (!ShouldInlineSimd()) { | 3469 if (!ShouldInlineSimd()) { |
3497 return false; | 3470 return false; |
3498 } | 3471 } |
3499 value_check = ic_data.AsUnaryClassChecksForCid(kFloat64x2Cid, target); | 3472 Cids* value_check = Cids::CreateMonomorphic(Z, kFloat64x2Cid); |
3500 return InlineSetIndexed(flow_graph, kind, target, call, receiver, | 3473 return InlineSetIndexed(flow_graph, kind, target, call, receiver, |
3501 token_pos, value_check, entry, last); | 3474 token_pos, value_check, entry, last); |
| 3475 } |
3502 case MethodRecognizer::kByteArrayBaseGetInt8: | 3476 case MethodRecognizer::kByteArrayBaseGetInt8: |
3503 return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid, | 3477 return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid, |
3504 kTypedDataInt8ArrayCid, entry, last); | 3478 kTypedDataInt8ArrayCid, entry, last); |
3505 case MethodRecognizer::kByteArrayBaseGetUint8: | 3479 case MethodRecognizer::kByteArrayBaseGetUint8: |
3506 return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid, | 3480 return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid, |
3507 kTypedDataUint8ArrayCid, entry, last); | 3481 kTypedDataUint8ArrayCid, entry, last); |
3508 case MethodRecognizer::kByteArrayBaseGetInt16: | 3482 case MethodRecognizer::kByteArrayBaseGetInt16: |
3509 return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid, | 3483 return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid, |
3510 kTypedDataInt16ArrayCid, entry, last); | 3484 kTypedDataInt16ArrayCid, entry, last); |
3511 case MethodRecognizer::kByteArrayBaseGetUint16: | 3485 case MethodRecognizer::kByteArrayBaseGetUint16: |
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3809 } | 3783 } |
3810 | 3784 |
3811 default: | 3785 default: |
3812 return false; | 3786 return false; |
3813 } | 3787 } |
3814 } | 3788 } |
3815 | 3789 |
3816 | 3790 |
3817 } // namespace dart | 3791 } // namespace dart |
3818 #endif // !defined(DART_PRECOMPILED_RUNTIME) | 3792 #endif // !defined(DART_PRECOMPILED_RUNTIME) |
OLD | NEW |