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 | 4 |
5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_XXX. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_XXX. |
6 | 6 |
7 #include "vm/flow_graph_compiler.h" | 7 #include "vm/flow_graph_compiler.h" |
8 | 8 |
9 #include "vm/bit_vector.h" | 9 #include "vm/bit_vector.h" |
10 #include "vm/cha.h" | 10 #include "vm/cha.h" |
(...skipping 16 matching lines...) Expand all Loading... |
27 #include "vm/stub_code.h" | 27 #include "vm/stub_code.h" |
28 #include "vm/symbols.h" | 28 #include "vm/symbols.h" |
29 #include "vm/timeline.h" | 29 #include "vm/timeline.h" |
30 | 30 |
31 namespace dart { | 31 namespace dart { |
32 | 32 |
33 DEFINE_FLAG(bool, | 33 DEFINE_FLAG(bool, |
34 enable_simd_inline, | 34 enable_simd_inline, |
35 true, | 35 true, |
36 "Enable inlining of SIMD related method calls."); | 36 "Enable inlining of SIMD related method calls."); |
37 DEFINE_FLAG( | |
38 bool, | |
39 inline_smi_string_hashcode, | |
40 true, | |
41 "Inline hashcode for Smi and one-byte strings in case of megamorphic call"); | |
42 DEFINE_FLAG( | |
43 int, | |
44 inline_smi_string_hashcode_ratio, | |
45 50, | |
46 "Minimal hotness (0..100) of one-byte-string before inlining its hashcode"); | |
47 DEFINE_FLAG(int, | 37 DEFINE_FLAG(int, |
48 min_optimization_counter_threshold, | 38 min_optimization_counter_threshold, |
49 5000, | 39 5000, |
50 "The minimum invocation count for a function."); | 40 "The minimum invocation count for a function."); |
51 DEFINE_FLAG(int, | 41 DEFINE_FLAG(int, |
52 optimization_counter_scale, | 42 optimization_counter_scale, |
53 2000, | 43 2000, |
54 "The scale of invocation count, by size of the function."); | 44 "The scale of invocation count, by size of the function."); |
55 DEFINE_FLAG(bool, source_lines, false, "Emit source line as assembly comment."); | 45 DEFINE_FLAG(bool, source_lines, false, "Emit source line as assembly comment."); |
56 DEFINE_FLAG(bool, | 46 DEFINE_FLAG(bool, |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
145 if (it.CurrentLocation().IsInvalid()) { | 135 if (it.CurrentLocation().IsInvalid()) { |
146 MaterializeObjectInstr* mat = | 136 MaterializeObjectInstr* mat = |
147 it.CurrentValue()->definition()->AsMaterializeObject(); | 137 it.CurrentValue()->definition()->AsMaterializeObject(); |
148 ASSERT(mat != NULL); | 138 ASSERT(mat != NULL); |
149 builder->AddMaterialization(mat); | 139 builder->AddMaterialization(mat); |
150 } | 140 } |
151 } | 141 } |
152 } | 142 } |
153 | 143 |
154 | 144 |
155 // Returns true if OnebyteString is a frequent receiver class. We inline | |
156 // Smi check as well, since a Smi check must be done anyway. | |
157 // TODO(srdjan): Add check and code if Smi class is hot. | |
158 bool FlowGraphCompiler::ShouldInlineSmiStringHashCode(const ICData& ic_data) { | |
159 if (!FLAG_inline_smi_string_hashcode || | |
160 (ic_data.target_name() != Symbols::hashCode().raw())) { | |
161 return false; | |
162 } | |
163 // Precompiled code has no ICData, optimistically inline it. | |
164 if (ic_data.IsNull() || ic_data.NumberOfChecksIs(0)) { | |
165 return true; | |
166 } | |
167 // Check if OneByteString is hot enough. | |
168 const ICData& ic_data_sorted = | |
169 ICData::Handle(ic_data.AsUnaryClassChecksSortedByCount()); | |
170 ASSERT(!ic_data_sorted.NumberOfChecksIs(0)); | |
171 if (ic_data_sorted.GetReceiverClassIdAt(0) == kOneByteStringCid) { | |
172 const intptr_t total_count = ic_data_sorted.AggregateCount(); | |
173 const intptr_t ratio = (ic_data_sorted.GetCountAt(0) * 100) / total_count; | |
174 return ratio > FLAG_inline_smi_string_hashcode_ratio; | |
175 } | |
176 return false; | |
177 } | |
178 | |
179 | |
180 FlowGraphCompiler::FlowGraphCompiler( | 145 FlowGraphCompiler::FlowGraphCompiler( |
181 Assembler* assembler, | 146 Assembler* assembler, |
182 FlowGraph* flow_graph, | 147 FlowGraph* flow_graph, |
183 const ParsedFunction& parsed_function, | 148 const ParsedFunction& parsed_function, |
184 bool is_optimizing, | 149 bool is_optimizing, |
185 const GrowableArray<const Function*>& inline_id_to_function, | 150 const GrowableArray<const Function*>& inline_id_to_function, |
186 const GrowableArray<TokenPosition>& inline_id_to_token_pos, | 151 const GrowableArray<TokenPosition>& inline_id_to_token_pos, |
187 const GrowableArray<intptr_t>& caller_inline_id) | 152 const GrowableArray<intptr_t>& caller_inline_id) |
188 : thread_(Thread::Current()), | 153 : thread_(Thread::Current()), |
189 zone_(Thread::Current()->zone()), | 154 zone_(Thread::Current()->zone()), |
(...skipping 1421 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1611 } | 1576 } |
1612 | 1577 |
1613 | 1578 |
1614 ParallelMoveResolver::ScratchRegisterScope::~ScratchRegisterScope() { | 1579 ParallelMoveResolver::ScratchRegisterScope::~ScratchRegisterScope() { |
1615 if (spilled_) { | 1580 if (spilled_) { |
1616 resolver_->RestoreScratch(reg_); | 1581 resolver_->RestoreScratch(reg_); |
1617 } | 1582 } |
1618 } | 1583 } |
1619 | 1584 |
1620 | 1585 |
1621 static int HighestCountFirst(const CidTarget* a, const CidTarget* b) { | 1586 template <typename T> |
| 1587 static int HighestCountFirst(const T* a, const T* b) { |
1622 // Negative if 'a' should sort before 'b'. | 1588 // Negative if 'a' should sort before 'b'. |
1623 return b->count - a->count; | 1589 return b->count - a->count; |
1624 } | 1590 } |
1625 | 1591 |
1626 | 1592 |
| 1593 static int LowestCidFirst(const CidRangeTarget* a, const CidRangeTarget* b) { |
| 1594 // Negative if 'a' should sort before 'b'. |
| 1595 return a->cid_start - b->cid_start; |
| 1596 } |
| 1597 |
| 1598 |
1627 // Returns 'sorted' array in decreasing count order. | 1599 // Returns 'sorted' array in decreasing count order. |
1628 // The expected number of elements to sort is less than 10. | 1600 // The expected number of elements to sort is less than 10. |
1629 void FlowGraphCompiler::SortICDataByCount(const ICData& ic_data, | 1601 void FlowGraphCompiler::SortICDataByCount( |
1630 GrowableArray<CidTarget>* sorted, | 1602 const ICData& ic_data, |
1631 bool drop_smi) { | 1603 GrowableArray<CidRangeTarget>* sorted_arg, |
| 1604 bool drop_smi) { |
| 1605 GrowableArray<CidRangeTarget>& sorted = *sorted_arg; |
1632 ASSERT(ic_data.NumArgsTested() == 1); | 1606 ASSERT(ic_data.NumArgsTested() == 1); |
1633 const intptr_t len = ic_data.NumberOfChecks(); | 1607 const intptr_t len = ic_data.NumberOfChecks(); |
1634 sorted->Clear(); | 1608 sorted.Clear(); |
1635 | 1609 |
1636 for (int i = 0; i < len; i++) { | 1610 for (int i = 0; i < len; i++) { |
1637 intptr_t receiver_cid = ic_data.GetReceiverClassIdAt(i); | 1611 intptr_t receiver_cid = ic_data.GetReceiverClassIdAt(i); |
1638 if (drop_smi && (receiver_cid == kSmiCid)) continue; | 1612 if (drop_smi && (receiver_cid == kSmiCid)) continue; |
1639 sorted->Add(CidTarget(receiver_cid, | 1613 Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i)); |
1640 &Function::ZoneHandle(ic_data.GetTargetAt(i)), | 1614 sorted.Add(CidRangeTarget(receiver_cid, receiver_cid, &target, |
1641 ic_data.GetCountAt(i))); | 1615 ic_data.GetCountAt(i))); |
1642 } | 1616 } |
1643 sorted->Sort(HighestCountFirst); | 1617 sorted.Sort(LowestCidFirst); |
| 1618 int dest = 0; |
| 1619 |
| 1620 // Merge adjacent ranges. |
| 1621 for (int src = 0; src < sorted.length(); src++) { |
| 1622 if (src > 0 && sorted[src - 1].cid_end + 1 == sorted[src].cid_start && |
| 1623 sorted[src - 1].target->raw() == sorted[src].target->raw()) { |
| 1624 sorted[dest - 1].cid_end++; |
| 1625 sorted[dest - 1].count += sorted[dest].count; |
| 1626 } else { |
| 1627 sorted[dest++] = sorted[src]; |
| 1628 } |
| 1629 } |
| 1630 |
| 1631 sorted.SetLength(dest); |
| 1632 sorted.Sort(HighestCountFirst); |
1644 } | 1633 } |
1645 | 1634 |
1646 | 1635 |
1647 const ICData* FlowGraphCompiler::GetOrAddInstanceCallICData( | 1636 const ICData* FlowGraphCompiler::GetOrAddInstanceCallICData( |
1648 intptr_t deopt_id, | 1637 intptr_t deopt_id, |
1649 const String& target_name, | 1638 const String& target_name, |
1650 const Array& arguments_descriptor, | 1639 const Array& arguments_descriptor, |
1651 intptr_t num_args_tested) { | 1640 intptr_t num_args_tested) { |
1652 if ((deopt_id_to_ic_data_ != NULL) && | 1641 if ((deopt_id_to_ic_data_ != NULL) && |
1653 ((*deopt_id_to_ic_data_)[deopt_id] != NULL)) { | 1642 ((*deopt_id_to_ic_data_)[deopt_id] != NULL)) { |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1775 ic_data.deopt_id(), ic_data.NumArgsTested(), false)); | 1764 ic_data.deopt_id(), ic_data.NumArgsTested(), false)); |
1776 new_ic_data.SetDeoptReasons(ic_data.DeoptReasons()); | 1765 new_ic_data.SetDeoptReasons(ic_data.DeoptReasons()); |
1777 new_ic_data.AddReceiverCheck(cid, function, count); | 1766 new_ic_data.AddReceiverCheck(cid, function, count); |
1778 return new_ic_data; | 1767 return new_ic_data; |
1779 } | 1768 } |
1780 | 1769 |
1781 return ic_data; | 1770 return ic_data; |
1782 } | 1771 } |
1783 | 1772 |
1784 | 1773 |
| 1774 intptr_t FlowGraphCompiler::ComputeGoodBiasForCidComparison( |
| 1775 const GrowableArray<CidRangeTarget>& sorted, |
| 1776 intptr_t max_immediate) { |
| 1777 // Sometimes a bias can be useful so we can emit more compact compare |
| 1778 // instructions. |
| 1779 intptr_t min_cid = 1000000; |
| 1780 intptr_t max_cid = -1; |
| 1781 |
| 1782 const intptr_t sorted_len = sorted.length(); |
| 1783 |
| 1784 for (intptr_t i = 0; i < sorted_len + 1; i++) { |
| 1785 bool done = (i == sorted_len); |
| 1786 intptr_t start = done ? 0 : sorted[i].cid_start; |
| 1787 intptr_t end = done ? 0 : sorted[i].cid_end; |
| 1788 bool is_range = start != end; |
| 1789 bool spread_too_big = start - min_cid > max_immediate; |
| 1790 if (done || is_range || spread_too_big) { |
| 1791 if (i >= 2 && max_cid - min_cid <= max_immediate && |
| 1792 max_cid > max_immediate) { |
| 1793 return min_cid; |
| 1794 } else { |
| 1795 return 0; |
| 1796 } |
| 1797 } |
| 1798 min_cid = Utils::Minimum(min_cid, start); |
| 1799 max_cid = Utils::Maximum(max_cid, end); |
| 1800 } |
| 1801 UNREACHABLE(); |
| 1802 return 0; |
| 1803 } |
| 1804 |
| 1805 |
1785 #if !defined(TARGET_ARCH_DBC) | 1806 #if !defined(TARGET_ARCH_DBC) |
1786 // DBC emits calls very differently from other architectures due to its | 1807 // DBC emits calls very differently from other architectures due to its |
1787 // interpreted nature. | 1808 // interpreted nature. |
1788 void FlowGraphCompiler::EmitPolymorphicInstanceCall(const ICData& ic_data, | 1809 void FlowGraphCompiler::EmitPolymorphicInstanceCall(const ICData& ic_data, |
1789 intptr_t argument_count, | 1810 intptr_t argument_count, |
1790 const Array& argument_names, | 1811 const Array& argument_names, |
1791 intptr_t deopt_id, | 1812 intptr_t deopt_id, |
1792 TokenPosition token_pos, | 1813 TokenPosition token_pos, |
1793 LocationSummary* locs, | 1814 LocationSummary* locs, |
1794 bool complete) { | 1815 bool complete, |
| 1816 intptr_t total_ic_calls) { |
1795 if (FLAG_polymorphic_with_deopt) { | 1817 if (FLAG_polymorphic_with_deopt) { |
1796 Label* deopt = | 1818 Label* deopt = |
1797 AddDeoptStub(deopt_id, ICData::kDeoptPolymorphicInstanceCallTestFail); | 1819 AddDeoptStub(deopt_id, ICData::kDeoptPolymorphicInstanceCallTestFail); |
1798 Label ok; | 1820 Label ok; |
1799 EmitTestAndCall(ic_data, argument_count, argument_names, | 1821 EmitTestAndCall(ic_data, argument_count, argument_names, |
1800 deopt, // No cid match. | 1822 deopt, // No cid match. |
1801 &ok, // Found cid. | 1823 &ok, // Found cid. |
1802 deopt_id, token_pos, locs, complete); | 1824 deopt_id, token_pos, locs, complete, total_ic_calls); |
1803 assembler()->Bind(&ok); | 1825 assembler()->Bind(&ok); |
1804 } else { | 1826 } else { |
1805 if (complete) { | 1827 if (complete) { |
1806 Label ok; | 1828 Label ok; |
1807 EmitTestAndCall(ic_data, argument_count, argument_names, | 1829 EmitTestAndCall(ic_data, argument_count, argument_names, |
1808 NULL, // No cid match. | 1830 NULL, // No cid match. |
1809 &ok, // Found cid. | 1831 &ok, // Found cid. |
1810 deopt_id, token_pos, locs, true); | 1832 deopt_id, token_pos, locs, true, total_ic_calls); |
1811 assembler()->Bind(&ok); | 1833 assembler()->Bind(&ok); |
1812 } else { | 1834 } else { |
1813 EmitSwitchableInstanceCall(ic_data, argument_count, deopt_id, token_pos, | 1835 EmitSwitchableInstanceCall(ic_data, argument_count, deopt_id, token_pos, |
1814 locs); | 1836 locs); |
1815 } | 1837 } |
1816 } | 1838 } |
1817 } | 1839 } |
1818 #endif | 1840 #endif |
1819 | 1841 |
1820 #if defined(DEBUG) && !defined(TARGET_ARCH_DBC) | 1842 #if defined(DEBUG) && !defined(TARGET_ARCH_DBC) |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1886 | 1908 |
1887 | 1909 |
1888 void FlowGraphCompiler::FrameStateClear() { | 1910 void FlowGraphCompiler::FrameStateClear() { |
1889 ASSERT(!is_optimizing()); | 1911 ASSERT(!is_optimizing()); |
1890 frame_state_.TruncateTo(0); | 1912 frame_state_.TruncateTo(0); |
1891 } | 1913 } |
1892 #endif // defined(DEBUG) && !defined(TARGET_ARCH_DBC) | 1914 #endif // defined(DEBUG) && !defined(TARGET_ARCH_DBC) |
1893 | 1915 |
1894 | 1916 |
1895 } // namespace dart | 1917 } // namespace dart |
OLD | NEW |