Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(487)

Side by Side Diff: runtime/vm/flow_graph_compiler.cc

Issue 2809583002: Use off-heap data for type feedback in PolymorphicInstanceCallInstr (Closed)
Patch Set: Feedback from Slava Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698