| 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 |