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" |
11 #include "vm/compiler.h" | 11 #include "vm/compiler.h" |
12 #include "vm/dart_entry.h" | 12 #include "vm/dart_entry.h" |
13 #include "vm/debugger.h" | 13 #include "vm/debugger.h" |
14 #include "vm/deopt_instructions.h" | 14 #include "vm/deopt_instructions.h" |
15 #include "vm/exceptions.h" | 15 #include "vm/exceptions.h" |
16 #include "vm/flags.h" | 16 #include "vm/flags.h" |
17 #include "vm/flow_graph_allocator.h" | 17 #include "vm/flow_graph_allocator.h" |
18 #include "vm/il_printer.h" | 18 #include "vm/il_printer.h" |
19 #include "vm/intrinsifier.h" | 19 #include "vm/intrinsifier.h" |
20 #include "vm/locations.h" | 20 #include "vm/locations.h" |
21 #include "vm/log.h" | 21 #include "vm/log.h" |
22 #include "vm/longjump.h" | 22 #include "vm/longjump.h" |
23 #include "vm/object_store.h" | 23 #include "vm/object_store.h" |
24 #include "vm/parser.h" | 24 #include "vm/parser.h" |
25 #include "vm/raw_object.h" | 25 #include "vm/raw_object.h" |
26 #include "vm/resolver.h" | |
26 #include "vm/stack_frame.h" | 27 #include "vm/stack_frame.h" |
27 #include "vm/stub_code.h" | 28 #include "vm/stub_code.h" |
28 #include "vm/symbols.h" | 29 #include "vm/symbols.h" |
29 #include "vm/timeline.h" | 30 #include "vm/timeline.h" |
30 | 31 |
31 namespace dart { | 32 namespace dart { |
32 | 33 |
33 DEFINE_FLAG(bool, | 34 DEFINE_FLAG(bool, |
34 enable_simd_inline, | 35 enable_simd_inline, |
35 true, | 36 true, |
(...skipping 1126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1162 *StubCode::TwoArgsOptimizedCheckInlineCache_entry(), ic_data, | 1163 *StubCode::TwoArgsOptimizedCheckInlineCache_entry(), ic_data, |
1163 argument_count, deopt_id, token_pos, locs); | 1164 argument_count, deopt_id, token_pos, locs); |
1164 return; | 1165 return; |
1165 default: | 1166 default: |
1166 UNIMPLEMENTED(); | 1167 UNIMPLEMENTED(); |
1167 } | 1168 } |
1168 return; | 1169 return; |
1169 } | 1170 } |
1170 | 1171 |
1171 if (is_optimizing()) { | 1172 if (is_optimizing()) { |
1172 EmitMegamorphicInstanceCall(ic_data_in, argument_count, deopt_id, token_pos, | 1173 String& name = String::Handle(ic_data_in.target_name()); |
1173 locs, CatchClauseNode::kInvalidTryIndex); | 1174 Array& arguments_descriptor = |
1175 Array::Handle(ic_data_in.arguments_descriptor()); | |
1176 EmitMegamorphicInstanceCall(name, arguments_descriptor, argument_count, | |
1177 deopt_id, token_pos, locs, | |
1178 CatchClauseNode::kInvalidTryIndex); | |
1174 return; | 1179 return; |
1175 } | 1180 } |
1176 | 1181 |
1177 switch (ic_data.NumArgsTested()) { | 1182 switch (ic_data.NumArgsTested()) { |
1178 case 1: | 1183 case 1: |
1179 EmitInstanceCall(*StubCode::OneArgCheckInlineCache_entry(), ic_data, | 1184 EmitInstanceCall(*StubCode::OneArgCheckInlineCache_entry(), ic_data, |
1180 argument_count, deopt_id, token_pos, locs); | 1185 argument_count, deopt_id, token_pos, locs); |
1181 break; | 1186 break; |
1182 case 2: | 1187 case 2: |
1183 EmitInstanceCall(*StubCode::TwoArgsCheckInlineCache_entry(), ic_data, | 1188 EmitInstanceCall(*StubCode::TwoArgsCheckInlineCache_entry(), ic_data, |
(...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1639 static int LowestCidFirst(const CidRangeTarget* a, const CidRangeTarget* b) { | 1644 static int LowestCidFirst(const CidRangeTarget* a, const CidRangeTarget* b) { |
1640 // Negative if 'a' should sort before 'b'. | 1645 // Negative if 'a' should sort before 'b'. |
1641 return a->cid_start - b->cid_start; | 1646 return a->cid_start - b->cid_start; |
1642 } | 1647 } |
1643 | 1648 |
1644 | 1649 |
1645 // Returns 'sorted' array in decreasing count order. | 1650 // Returns 'sorted' array in decreasing count order. |
1646 // The expected number of elements to sort is less than 10. | 1651 // The expected number of elements to sort is less than 10. |
1647 void FlowGraphCompiler::SortICDataByCount( | 1652 void FlowGraphCompiler::SortICDataByCount( |
1648 const ICData& ic_data, | 1653 const ICData& ic_data, |
1649 GrowableArray<CidRangeTarget>* sorted_arg, | 1654 ZoneGrowableArray<CidRangeTarget>* sorted_arg, |
Vyacheslav Egorov (Google)
2017/04/10 10:59:27
why did this suddenly become ZoneGrowableArray?
erikcorry
2017/04/19 15:06:39
Undone.
| |
1650 bool drop_smi) { | 1655 bool drop_smi) { |
1651 GrowableArray<CidRangeTarget>& sorted = *sorted_arg; | 1656 ZoneGrowableArray<CidRangeTarget>& sorted = *sorted_arg; |
1652 ASSERT(ic_data.NumArgsTested() == 1); | 1657 ASSERT(ic_data.NumArgsTested() == 1); |
1653 const intptr_t len = ic_data.NumberOfChecks(); | 1658 const intptr_t len = ic_data.NumberOfChecks(); |
1654 sorted.Clear(); | 1659 sorted.Clear(); |
1655 | 1660 |
1656 for (int i = 0; i < len; i++) { | 1661 for (int i = 0; i < len; i++) { |
1657 intptr_t receiver_cid = ic_data.GetReceiverClassIdAt(i); | 1662 intptr_t receiver_cid = ic_data.GetReceiverClassIdAt(i); |
1658 if (drop_smi && (receiver_cid == kSmiCid)) continue; | 1663 if (drop_smi && (receiver_cid == kSmiCid)) continue; |
1659 Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i)); | 1664 Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i)); |
1660 sorted.Add(CidRangeTarget(receiver_cid, receiver_cid, &target, | 1665 sorted.Add(CidRangeTarget(receiver_cid, receiver_cid, &target, |
1661 ic_data.GetCountAt(i))); | 1666 ic_data.GetCountAt(i))); |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1780 code_source_map_builder_->BeginCodeSourceRange(assembler()->CodeSize()); | 1785 code_source_map_builder_->BeginCodeSourceRange(assembler()->CodeSize()); |
1781 } | 1786 } |
1782 | 1787 |
1783 | 1788 |
1784 void FlowGraphCompiler::EndCodeSourceRange(TokenPosition token_pos) { | 1789 void FlowGraphCompiler::EndCodeSourceRange(TokenPosition token_pos) { |
1785 code_source_map_builder_->EndCodeSourceRange(assembler()->CodeSize(), | 1790 code_source_map_builder_->EndCodeSourceRange(assembler()->CodeSize(), |
1786 token_pos); | 1791 token_pos); |
1787 } | 1792 } |
1788 | 1793 |
1789 | 1794 |
1790 const ICData& FlowGraphCompiler::TrySpecializeICDataByReceiverCid( | 1795 const PolymorphicTargets* FlowGraphCompiler::TrySpecializeByReceiverCid( |
Vyacheslav Egorov (Google)
2017/04/10 10:59:27
I think this name now is confusing given that we d
erikcorry
2017/04/19 15:06:39
Done.
| |
1791 const ICData& ic_data, | 1796 const Array& args_desc_array, |
1797 const String& selector, | |
1792 intptr_t cid) { | 1798 intptr_t cid) { |
1793 Zone* zone = Thread::Current()->zone(); | 1799 Zone* zone = Thread::Current()->zone(); |
1794 if (ic_data.NumArgsTested() != 1) return ic_data; | |
1795 | 1800 |
1796 if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) { | 1801 ArgumentsDescriptor args_desc(args_desc_array); |
1797 return ic_data; // Nothing to do | |
1798 } | |
1799 | 1802 |
1800 intptr_t count = 1; | 1803 Function& fn = Function::Handle(zone); |
1801 const Function& function = | 1804 if (!LookupMethodFor(cid, args_desc, selector, &fn)) return NULL; |
Vyacheslav Egorov (Google)
2017/04/10 10:59:27
Similar here: natural arguments order should proba
erikcorry
2017/04/19 15:06:39
Done.
| |
1802 Function::Handle(zone, ic_data.GetTargetForReceiverClassId(cid, &count)); | |
1803 // TODO(fschneider): Try looking up the function on the class if it is | |
1804 // not found in the ICData. | |
1805 if (!function.IsNull()) { | |
1806 const ICData& new_ic_data = ICData::ZoneHandle( | |
1807 zone, ICData::New(Function::Handle(zone, ic_data.Owner()), | |
1808 String::Handle(zone, ic_data.target_name()), | |
1809 Object::empty_array(), // Dummy argument descriptor. | |
1810 ic_data.deopt_id(), ic_data.NumArgsTested(), false)); | |
1811 new_ic_data.SetDeoptReasons(ic_data.DeoptReasons()); | |
1812 new_ic_data.AddReceiverCheck(cid, function, count); | |
1813 return new_ic_data; | |
1814 } | |
1815 | 1805 |
1816 return ic_data; | 1806 PolymorphicTargets* targets = new (zone) PolymorphicTargets(zone); |
1807 targets->Add(CidRangeTarget(cid, cid, &fn, 1)); | |
Vyacheslav Egorov (Google)
2017/04/10 10:59:27
this 1 needs a comment, e.g. /*count=*/1
erikcorry
2017/04/19 15:06:39
Done.
| |
1808 | |
1809 return targets; | |
1817 } | 1810 } |
1818 | 1811 |
1819 | 1812 |
1820 intptr_t FlowGraphCompiler::ComputeGoodBiasForCidComparison( | 1813 intptr_t FlowGraphCompiler::ComputeGoodBiasForCidComparison( |
1821 const GrowableArray<CidRangeTarget>& sorted, | 1814 const PolymorphicTargets& sorted, |
1822 intptr_t max_immediate) { | 1815 intptr_t max_immediate) { |
1823 // Sometimes a bias can be useful so we can emit more compact compare | 1816 // Sometimes a bias can be useful so we can emit more compact compare |
1824 // instructions. | 1817 // instructions. |
1825 intptr_t min_cid = 1000000; | 1818 intptr_t min_cid = 1000000; |
1826 intptr_t max_cid = -1; | 1819 intptr_t max_cid = -1; |
1827 | 1820 |
1828 const intptr_t sorted_len = sorted.length(); | 1821 const intptr_t sorted_len = sorted.length(); |
1829 | 1822 |
1830 for (intptr_t i = 0; i < sorted_len + 1; i++) { | 1823 for (intptr_t i = 0; i < sorted_len + 1; i++) { |
1831 bool done = (i == sorted_len); | 1824 bool done = (i == sorted_len); |
(...skipping 10 matching lines...) Expand all Loading... | |
1842 } | 1835 } |
1843 } | 1836 } |
1844 min_cid = Utils::Minimum(min_cid, start); | 1837 min_cid = Utils::Minimum(min_cid, start); |
1845 max_cid = Utils::Maximum(max_cid, end); | 1838 max_cid = Utils::Maximum(max_cid, end); |
1846 } | 1839 } |
1847 UNREACHABLE(); | 1840 UNREACHABLE(); |
1848 return 0; | 1841 return 0; |
1849 } | 1842 } |
1850 | 1843 |
1851 | 1844 |
1845 bool FlowGraphCompiler::LookupMethodFor(int class_id, | |
1846 const ArgumentsDescriptor& args_desc, | |
1847 const String& name, | |
1848 Function* fn_return) { | |
1849 Thread* thread = Thread::Current(); | |
1850 Isolate* isolate = thread->isolate(); | |
1851 Zone* zone = thread->zone(); | |
1852 if (class_id < 0) return false; | |
1853 if (class_id >= isolate->class_table()->NumCids()) return false; | |
1854 | |
1855 RawClass* raw_class = isolate->class_table()->At(class_id); | |
1856 if (raw_class == NULL) return false; | |
1857 Class& cls = Class::Handle(zone, raw_class); | |
1858 if (cls.IsNull()) return false; | |
1859 if (!cls.is_finalized()) return false; | |
1860 if (Array::Handle(cls.functions()).IsNull()) return false; | |
1861 | |
1862 Function& target_function = | |
Vyacheslav Egorov (Google)
2017/04/10 10:59:27
for named arguments I suggest:
const bool allow_a
erikcorry
2017/04/19 15:06:39
Done.
| |
1863 Function::Handle(zone, Resolver::ResolveDynamicForReceiverClass( | |
1864 cls, name, args_desc, false /* allow add */)); | |
1865 if (target_function.IsNull()) return false; | |
1866 *fn_return ^= target_function.raw(); | |
1867 return true; | |
1868 } | |
1869 | |
1870 | |
1852 #if !defined(TARGET_ARCH_DBC) | 1871 #if !defined(TARGET_ARCH_DBC) |
1853 // DBC emits calls very differently from other architectures due to its | 1872 // DBC emits calls very differently from other architectures due to its |
1854 // interpreted nature. | 1873 // interpreted nature. |
1855 void FlowGraphCompiler::EmitPolymorphicInstanceCall(const ICData& ic_data, | 1874 void FlowGraphCompiler::EmitPolymorphicInstanceCall( |
1856 intptr_t argument_count, | 1875 const PolymorphicTargets& targets, |
1857 const Array& argument_names, | 1876 const InstanceCallInstr& original_call_insn, |
Vyacheslav Egorov (Google)
2017/04/10 10:59:27
maybe just original_call instead of original_call_
erikcorry
2017/04/19 15:06:39
Done.
| |
1858 intptr_t deopt_id, | 1877 intptr_t argument_count, |
1859 TokenPosition token_pos, | 1878 const Array& argument_names, |
1860 LocationSummary* locs, | 1879 intptr_t deopt_id, |
1861 bool complete, | 1880 TokenPosition token_pos, |
1862 intptr_t total_ic_calls) { | 1881 LocationSummary* locs, |
1882 bool complete, | |
1883 intptr_t total_ic_calls) { | |
1863 if (FLAG_polymorphic_with_deopt) { | 1884 if (FLAG_polymorphic_with_deopt) { |
1864 Label* deopt = | 1885 Label* deopt = |
1865 AddDeoptStub(deopt_id, ICData::kDeoptPolymorphicInstanceCallTestFail); | 1886 AddDeoptStub(deopt_id, ICData::kDeoptPolymorphicInstanceCallTestFail); |
1866 Label ok; | 1887 Label ok; |
1867 EmitTestAndCall(ic_data, argument_count, argument_names, | 1888 EmitTestAndCall(targets, original_call_insn.function_name(), argument_count, |
1889 argument_names, | |
1868 deopt, // No cid match. | 1890 deopt, // No cid match. |
1869 &ok, // Found cid. | 1891 &ok, // Found cid. |
1870 deopt_id, token_pos, locs, complete, total_ic_calls); | 1892 deopt_id, token_pos, locs, complete, total_ic_calls); |
1871 assembler()->Bind(&ok); | 1893 assembler()->Bind(&ok); |
1872 } else { | 1894 } else { |
1873 if (complete) { | 1895 if (complete) { |
1874 Label ok; | 1896 Label ok; |
1875 EmitTestAndCall(ic_data, argument_count, argument_names, | 1897 EmitTestAndCall(targets, original_call_insn.function_name(), |
1898 argument_count, argument_names, | |
1876 NULL, // No cid match. | 1899 NULL, // No cid match. |
1877 &ok, // Found cid. | 1900 &ok, // Found cid. |
1878 deopt_id, token_pos, locs, true, total_ic_calls); | 1901 deopt_id, token_pos, locs, true, total_ic_calls); |
1879 assembler()->Bind(&ok); | 1902 assembler()->Bind(&ok); |
1880 } else { | 1903 } else { |
1881 EmitSwitchableInstanceCall(ic_data, argument_count, deopt_id, token_pos, | 1904 const ICData& unary_checks = ICData::ZoneHandle( |
1882 locs); | 1905 zone(), original_call_insn.ic_data()->AsUnaryClassChecks()); |
1906 EmitSwitchableInstanceCall(unary_checks, argument_count, deopt_id, | |
1907 token_pos, locs); | |
1883 } | 1908 } |
1884 } | 1909 } |
1885 } | 1910 } |
1886 #endif | 1911 #endif |
1887 | 1912 |
1888 #if defined(DEBUG) && !defined(TARGET_ARCH_DBC) | 1913 #if defined(DEBUG) && !defined(TARGET_ARCH_DBC) |
1889 // TODO(vegorov) re-enable frame state tracking on DBC. It is | 1914 // TODO(vegorov) re-enable frame state tracking on DBC. It is |
1890 // currently disabled because it relies on LocationSummaries and | 1915 // currently disabled because it relies on LocationSummaries and |
1891 // we don't use them during unoptimized compilation on DBC. | 1916 // we don't use them during unoptimized compilation on DBC. |
1892 void FlowGraphCompiler::FrameStateUpdateWith(Instruction* instr) { | 1917 void FlowGraphCompiler::FrameStateUpdateWith(Instruction* instr) { |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1954 | 1979 |
1955 | 1980 |
1956 void FlowGraphCompiler::FrameStateClear() { | 1981 void FlowGraphCompiler::FrameStateClear() { |
1957 ASSERT(!is_optimizing()); | 1982 ASSERT(!is_optimizing()); |
1958 frame_state_.TruncateTo(0); | 1983 frame_state_.TruncateTo(0); |
1959 } | 1984 } |
1960 #endif // defined(DEBUG) && !defined(TARGET_ARCH_DBC) | 1985 #endif // defined(DEBUG) && !defined(TARGET_ARCH_DBC) |
1961 | 1986 |
1962 | 1987 |
1963 } // namespace dart | 1988 } // namespace dart |
OLD | NEW |