Chromium Code Reviews| 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 596 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 CallTargets* FlowGraphCompiler::ResolveCallTargetsForReceiverCid( |
| 1791 const ICData& ic_data, | 1796 intptr_t cid, |
| 1792 intptr_t cid) { | 1797 const String& selector, |
| 1798 const Array& args_desc_array) { | |
| 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::ZoneHandle(zone); |
| 1801 const Function& function = | 1804 if (!LookupMethodFor(cid, selector, args_desc, &fn)) return NULL; |
| 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 CallTargets* targets = new (zone) CallTargets(); |
| 1807 targets->Add(CidRangeTarget(cid, cid, &fn, /* count = */ 1)); | |
| 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 CallTargets& 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 String& name, | |
| 1847 const ArgumentsDescriptor& args_desc, | |
| 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 const bool allow_add = false; | |
| 1863 Function& target_function = | |
| 1864 Function::Handle(zone, Resolver::ResolveDynamicForReceiverClass( | |
| 1865 cls, name, args_desc, allow_add)); | |
| 1866 if (target_function.IsNull()) return false; | |
| 1867 *fn_return ^= target_function.raw(); | |
| 1868 return true; | |
| 1869 } | |
| 1870 | |
| 1871 | |
| 1852 #if !defined(TARGET_ARCH_DBC) | 1872 #if !defined(TARGET_ARCH_DBC) |
| 1853 // DBC emits calls very differently from other architectures due to its | 1873 // DBC emits calls very differently from other architectures due to its |
| 1854 // interpreted nature. | 1874 // interpreted nature. |
| 1855 void FlowGraphCompiler::EmitPolymorphicInstanceCall(const ICData& ic_data, | 1875 void FlowGraphCompiler::EmitPolymorphicInstanceCall( |
| 1856 intptr_t argument_count, | 1876 const CallTargets& targets, |
| 1857 const Array& argument_names, | 1877 const InstanceCallInstr& original_call, |
| 1858 intptr_t deopt_id, | 1878 intptr_t argument_count, |
| 1859 TokenPosition token_pos, | 1879 const Array& argument_names, |
| 1860 LocationSummary* locs, | 1880 intptr_t deopt_id, |
| 1861 bool complete, | 1881 TokenPosition token_pos, |
| 1862 intptr_t total_ic_calls) { | 1882 LocationSummary* locs, |
| 1883 bool complete, | |
| 1884 intptr_t total_ic_calls) { | |
| 1863 if (FLAG_polymorphic_with_deopt) { | 1885 if (FLAG_polymorphic_with_deopt) { |
| 1864 Label* deopt = | 1886 Label* deopt = |
| 1865 AddDeoptStub(deopt_id, ICData::kDeoptPolymorphicInstanceCallTestFail); | 1887 AddDeoptStub(deopt_id, ICData::kDeoptPolymorphicInstanceCallTestFail); |
| 1866 Label ok; | 1888 Label ok; |
| 1867 EmitTestAndCall(ic_data, argument_count, argument_names, | 1889 EmitTestAndCall(targets, original_call.function_name(), argument_count, |
| 1890 argument_names, | |
| 1868 deopt, // No cid match. | 1891 deopt, // No cid match. |
| 1869 &ok, // Found cid. | 1892 &ok, // Found cid. |
| 1870 deopt_id, token_pos, locs, complete, total_ic_calls); | 1893 deopt_id, token_pos, locs, complete, total_ic_calls); |
| 1871 assembler()->Bind(&ok); | 1894 assembler()->Bind(&ok); |
| 1872 } else { | 1895 } else { |
| 1873 if (complete) { | 1896 if (complete) { |
| 1874 Label ok; | 1897 Label ok; |
| 1875 EmitTestAndCall(ic_data, argument_count, argument_names, | 1898 EmitTestAndCall(targets, original_call.function_name(), argument_count, |
| 1899 argument_names, | |
| 1876 NULL, // No cid match. | 1900 NULL, // No cid match. |
| 1877 &ok, // Found cid. | 1901 &ok, // Found cid. |
| 1878 deopt_id, token_pos, locs, true, total_ic_calls); | 1902 deopt_id, token_pos, locs, true, total_ic_calls); |
| 1879 assembler()->Bind(&ok); | 1903 assembler()->Bind(&ok); |
| 1880 } else { | 1904 } else { |
| 1881 EmitSwitchableInstanceCall(ic_data, argument_count, deopt_id, token_pos, | 1905 const ICData& unary_checks = ICData::ZoneHandle( |
| 1882 locs); | 1906 zone(), original_call.ic_data()->AsUnaryClassChecks()); |
| 1907 EmitSwitchableInstanceCall(unary_checks, argument_count, deopt_id, | |
| 1908 token_pos, locs); | |
| 1883 } | 1909 } |
| 1884 } | 1910 } |
| 1885 } | 1911 } |
| 1912 | |
| 1913 | |
| 1914 #define __ assembler()-> | |
| 1915 void FlowGraphCompiler::EmitTestAndCall(const CallTargets& targets, | |
| 1916 const String& function_name, | |
| 1917 intptr_t argument_count, | |
| 1918 const Array& argument_names, | |
| 1919 Label* failed, | |
| 1920 Label* match_found, | |
| 1921 intptr_t deopt_id, | |
| 1922 TokenPosition token_index, | |
| 1923 LocationSummary* locs, | |
| 1924 bool complete, | |
| 1925 intptr_t total_ic_calls) { | |
| 1926 ASSERT(is_optimizing()); | |
| 1927 | |
| 1928 const Array& arguments_descriptor = Array::ZoneHandle( | |
| 1929 zone(), ArgumentsDescriptor::New(argument_count, argument_names)); | |
| 1930 | |
| 1931 EmitTestAndCallLoadReceiver(argument_count, arguments_descriptor); | |
| 1932 | |
| 1933 static const int kNoCase = -1; | |
| 1934 int smi_case = kNoCase; | |
| 1935 int which_case_to_skip = kNoCase; | |
| 1936 | |
| 1937 const int length = targets.length(); | |
| 1938 ASSERT(length > 0); | |
| 1939 int non_smi_length = length; | |
| 1940 | |
| 1941 // Find out if one of the classes in one of the cases is the Smi class. We | |
| 1942 // will be handling that specially. | |
| 1943 for (int i = 0; i < length; i++) { | |
| 1944 const intptr_t start = targets[i].cid_start; | |
| 1945 if (start > kSmiCid) continue; | |
| 1946 const intptr_t end = targets[i].cid_end; | |
| 1947 if (end >= kSmiCid) { | |
| 1948 smi_case = i; | |
| 1949 if (start == kSmiCid && end == kSmiCid) { | |
| 1950 // If this case has only the Smi class then we won't need to emit it at | |
| 1951 // all later. | |
| 1952 which_case_to_skip = i; | |
| 1953 non_smi_length--; | |
| 1954 } | |
| 1955 break; | |
| 1956 } | |
| 1957 } | |
| 1958 | |
| 1959 if (smi_case != kNoCase) { | |
| 1960 Label after_smi_test; | |
| 1961 // Jump if receiver is not Smi. | |
| 1962 EmitTestAndCallSmiBranch(non_smi_length == 0 ? failed : &after_smi_test, | |
| 1963 false); | |
| 1964 | |
| 1965 // Do not use the code from the function, but let the code be patched so | |
| 1966 // that we can record the outgoing edges to other code. | |
| 1967 const Function& function = *targets[smi_case].target; | |
| 1968 GenerateStaticDartCall(deopt_id, token_index, | |
| 1969 *StubCode::CallStaticFunction_entry(), | |
| 1970 RawPcDescriptors::kOther, locs, function); | |
| 1971 __ Drop(argument_count); | |
| 1972 if (match_found != NULL) { | |
| 1973 EmitTestAndCallGotoMatchFound(match_found); | |
| 1974 } | |
| 1975 __ Bind(&after_smi_test); | |
| 1976 } else { | |
| 1977 if (!complete) { | |
| 1978 // Smi is not a valid class so jump to fail if it's a Smi. | |
| 1979 EmitTestAndCallSmiBranch(failed, true); | |
|
Vyacheslav Egorov (Google)
2017/04/20 16:45:33
please add a comment what true/false means in this
erikcorry
2017/04/21 13:04:43
Done.
| |
| 1980 } | |
| 1981 } | |
| 1982 | |
| 1983 if (non_smi_length == 0) { | |
| 1984 // If non_smi_length is 0 then only a Smi check was needed; the Smi check | |
| 1985 // above will fail if there was only one check and receiver is not Smi. | |
| 1986 return; | |
| 1987 } | |
| 1988 | |
| 1989 bool add_megamorphic_call = false; | |
| 1990 const int kMaxImmediateInInstruction = 256; | |
|
Vyacheslav Egorov (Google)
2017/04/20 16:45:33
Maybe add a note that this works on all architectu
erikcorry
2017/04/21 13:04:43
This wasn't a very noticable win (microscopic code
| |
| 1991 int bias = | |
| 1992 ComputeGoodBiasForCidComparison(targets, kMaxImmediateInInstruction); | |
| 1993 | |
| 1994 // Value is not Smi. | |
| 1995 EmitTestAndCallLoadCid(bias); | |
| 1996 | |
| 1997 int last_check = which_case_to_skip == length - 1 ? length - 2 : length - 1; | |
| 1998 | |
| 1999 for (intptr_t i = 0; i < length; i++) { | |
| 2000 if (i == which_case_to_skip) continue; | |
| 2001 const bool is_last_check = (i == last_check); | |
| 2002 const int count = targets[i].count; | |
| 2003 if (!is_last_check && !complete && count < (total_ic_calls >> 5)) { | |
| 2004 // This case is hit too rarely to be worth writing class-id checks inline | |
| 2005 // for. Note that we can't do this for calls with only one target because | |
| 2006 // the type propagator may have made use of that and expects a deopt if | |
| 2007 // a new class is seen at this calls site. See IsMonomorphic. | |
| 2008 add_megamorphic_call = true; | |
| 2009 break; | |
| 2010 } | |
| 2011 Label next_test; | |
| 2012 if (!complete || !is_last_check) { | |
| 2013 bias = EmitTestAndCallCheckCid(is_last_check ? failed : &next_test, | |
| 2014 targets[i], bias); | |
| 2015 } | |
| 2016 // Do not use the code from the function, but let the code be patched so | |
| 2017 // that we can record the outgoing edges to other code. | |
| 2018 const Function& function = *targets[i].target; | |
| 2019 GenerateStaticDartCall(deopt_id, token_index, | |
| 2020 *StubCode::CallStaticFunction_entry(), | |
| 2021 RawPcDescriptors::kOther, locs, function); | |
| 2022 __ Drop(argument_count); | |
| 2023 if (!is_last_check || add_megamorphic_call) { | |
| 2024 EmitTestAndCallGotoMatchFound(match_found); | |
| 2025 } | |
| 2026 __ Bind(&next_test); | |
| 2027 } | |
| 2028 if (add_megamorphic_call) { | |
| 2029 int try_index = CatchClauseNode::kInvalidTryIndex; | |
| 2030 EmitMegamorphicInstanceCall(function_name, arguments_descriptor, | |
| 2031 argument_count, deopt_id, token_index, locs, | |
| 2032 try_index); | |
| 2033 } | |
| 2034 } | |
| 2035 #undef __ | |
| 1886 #endif | 2036 #endif |
| 1887 | 2037 |
| 1888 #if defined(DEBUG) && !defined(TARGET_ARCH_DBC) | 2038 #if defined(DEBUG) && !defined(TARGET_ARCH_DBC) |
| 1889 // TODO(vegorov) re-enable frame state tracking on DBC. It is | 2039 // TODO(vegorov) re-enable frame state tracking on DBC. It is |
| 1890 // currently disabled because it relies on LocationSummaries and | 2040 // currently disabled because it relies on LocationSummaries and |
| 1891 // we don't use them during unoptimized compilation on DBC. | 2041 // we don't use them during unoptimized compilation on DBC. |
| 1892 void FlowGraphCompiler::FrameStateUpdateWith(Instruction* instr) { | 2042 void FlowGraphCompiler::FrameStateUpdateWith(Instruction* instr) { |
| 1893 ASSERT(!is_optimizing()); | 2043 ASSERT(!is_optimizing()); |
| 1894 | 2044 |
| 1895 switch (instr->tag()) { | 2045 switch (instr->tag()) { |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1954 | 2104 |
| 1955 | 2105 |
| 1956 void FlowGraphCompiler::FrameStateClear() { | 2106 void FlowGraphCompiler::FrameStateClear() { |
| 1957 ASSERT(!is_optimizing()); | 2107 ASSERT(!is_optimizing()); |
| 1958 frame_state_.TruncateTo(0); | 2108 frame_state_.TruncateTo(0); |
| 1959 } | 2109 } |
| 1960 #endif // defined(DEBUG) && !defined(TARGET_ARCH_DBC) | 2110 #endif // defined(DEBUG) && !defined(TARGET_ARCH_DBC) |
| 1961 | 2111 |
| 1962 | 2112 |
| 1963 } // namespace dart | 2113 } // namespace dart |
| OLD | NEW |