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

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

Issue 2809583002: Use off-heap data for type feedback in PolymorphicInstanceCallInstr (Closed)
Patch Set: More 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
« no previous file with comments | « runtime/vm/flow_graph_compiler.h ('k') | runtime/vm/flow_graph_compiler_arm.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 bool FlowGraphCompiler::LookupMethodFor(int class_id,
1821 const GrowableArray<CidRangeTarget>& sorted, 1814 const String& name,
1822 intptr_t max_immediate) { 1815 const ArgumentsDescriptor& args_desc,
1823 // Sometimes a bias can be useful so we can emit more compact compare 1816 Function* fn_return) {
1824 // instructions. 1817 Thread* thread = Thread::Current();
1825 intptr_t min_cid = 1000000; 1818 Isolate* isolate = thread->isolate();
1826 intptr_t max_cid = -1; 1819 Zone* zone = thread->zone();
1820 if (class_id < 0) return false;
1821 if (class_id >= isolate->class_table()->NumCids()) return false;
1827 1822
1828 const intptr_t sorted_len = sorted.length(); 1823 RawClass* raw_class = isolate->class_table()->At(class_id);
1824 if (raw_class == NULL) return false;
1825 Class& cls = Class::Handle(zone, raw_class);
1826 if (cls.IsNull()) return false;
1827 if (!cls.is_finalized()) return false;
1828 if (Array::Handle(cls.functions()).IsNull()) return false;
1829 1829
1830 for (intptr_t i = 0; i < sorted_len + 1; i++) { 1830 const bool allow_add = false;
1831 bool done = (i == sorted_len); 1831 Function& target_function =
1832 intptr_t start = done ? 0 : sorted[i].cid_start; 1832 Function::Handle(zone, Resolver::ResolveDynamicForReceiverClass(
1833 intptr_t end = done ? 0 : sorted[i].cid_end; 1833 cls, name, args_desc, allow_add));
1834 bool is_range = start != end; 1834 if (target_function.IsNull()) return false;
1835 bool spread_too_big = start - min_cid > max_immediate; 1835 *fn_return ^= target_function.raw();
1836 if (done || is_range || spread_too_big) { 1836 return true;
1837 if (i >= 2 && max_cid - min_cid <= max_immediate &&
1838 max_cid > max_immediate) {
1839 return min_cid;
1840 } else {
1841 return 0;
1842 }
1843 }
1844 min_cid = Utils::Minimum(min_cid, start);
1845 max_cid = Utils::Maximum(max_cid, end);
1846 }
1847 UNREACHABLE();
1848 return 0;
1849 } 1837 }
1850 1838
1851 1839
1852 #if !defined(TARGET_ARCH_DBC) 1840 #if !defined(TARGET_ARCH_DBC)
1853 // DBC emits calls very differently from other architectures due to its 1841 // DBC emits calls very differently from other architectures due to its
1854 // interpreted nature. 1842 // interpreted nature.
1855 void FlowGraphCompiler::EmitPolymorphicInstanceCall(const ICData& ic_data, 1843 void FlowGraphCompiler::EmitPolymorphicInstanceCall(
1856 intptr_t argument_count, 1844 const CallTargets& targets,
1857 const Array& argument_names, 1845 const InstanceCallInstr& original_call,
1858 intptr_t deopt_id, 1846 intptr_t argument_count,
1859 TokenPosition token_pos, 1847 const Array& argument_names,
1860 LocationSummary* locs, 1848 intptr_t deopt_id,
1861 bool complete, 1849 TokenPosition token_pos,
1862 intptr_t total_ic_calls) { 1850 LocationSummary* locs,
1851 bool complete,
1852 intptr_t total_ic_calls) {
1863 if (FLAG_polymorphic_with_deopt) { 1853 if (FLAG_polymorphic_with_deopt) {
1864 Label* deopt = 1854 Label* deopt =
1865 AddDeoptStub(deopt_id, ICData::kDeoptPolymorphicInstanceCallTestFail); 1855 AddDeoptStub(deopt_id, ICData::kDeoptPolymorphicInstanceCallTestFail);
1866 Label ok; 1856 Label ok;
1867 EmitTestAndCall(ic_data, argument_count, argument_names, 1857 EmitTestAndCall(targets, original_call.function_name(), argument_count,
1858 argument_names,
1868 deopt, // No cid match. 1859 deopt, // No cid match.
1869 &ok, // Found cid. 1860 &ok, // Found cid.
1870 deopt_id, token_pos, locs, complete, total_ic_calls); 1861 deopt_id, token_pos, locs, complete, total_ic_calls);
1871 assembler()->Bind(&ok); 1862 assembler()->Bind(&ok);
1872 } else { 1863 } else {
1873 if (complete) { 1864 if (complete) {
1874 Label ok; 1865 Label ok;
1875 EmitTestAndCall(ic_data, argument_count, argument_names, 1866 EmitTestAndCall(targets, original_call.function_name(), argument_count,
1867 argument_names,
1876 NULL, // No cid match. 1868 NULL, // No cid match.
1877 &ok, // Found cid. 1869 &ok, // Found cid.
1878 deopt_id, token_pos, locs, true, total_ic_calls); 1870 deopt_id, token_pos, locs, true, total_ic_calls);
1879 assembler()->Bind(&ok); 1871 assembler()->Bind(&ok);
1880 } else { 1872 } else {
1881 EmitSwitchableInstanceCall(ic_data, argument_count, deopt_id, token_pos, 1873 const ICData& unary_checks = ICData::ZoneHandle(
1882 locs); 1874 zone(), original_call.ic_data()->AsUnaryClassChecks());
1875 EmitSwitchableInstanceCall(unary_checks, argument_count, deopt_id,
1876 token_pos, locs);
1883 } 1877 }
1884 } 1878 }
1885 } 1879 }
1880
1881
1882 #define __ assembler()->
1883 void FlowGraphCompiler::EmitTestAndCall(const CallTargets& targets,
1884 const String& function_name,
1885 intptr_t argument_count,
1886 const Array& argument_names,
1887 Label* failed,
1888 Label* match_found,
1889 intptr_t deopt_id,
1890 TokenPosition token_index,
1891 LocationSummary* locs,
1892 bool complete,
1893 intptr_t total_ic_calls) {
1894 ASSERT(is_optimizing());
1895
1896 const Array& arguments_descriptor = Array::ZoneHandle(
1897 zone(), ArgumentsDescriptor::New(argument_count, argument_names));
1898
1899 EmitTestAndCallLoadReceiver(argument_count, arguments_descriptor);
1900
1901 static const int kNoCase = -1;
1902 int smi_case = kNoCase;
1903 int which_case_to_skip = kNoCase;
1904
1905 const int length = targets.length();
1906 ASSERT(length > 0);
1907 int non_smi_length = length;
1908
1909 // Find out if one of the classes in one of the cases is the Smi class. We
1910 // will be handling that specially.
1911 for (int i = 0; i < length; i++) {
1912 const intptr_t start = targets[i].cid_start;
1913 if (start > kSmiCid) continue;
1914 const intptr_t end = targets[i].cid_end;
1915 if (end >= kSmiCid) {
1916 smi_case = i;
1917 if (start == kSmiCid && end == kSmiCid) {
1918 // If this case has only the Smi class then we won't need to emit it at
1919 // all later.
1920 which_case_to_skip = i;
1921 non_smi_length--;
1922 }
1923 break;
1924 }
1925 }
1926
1927 if (smi_case != kNoCase) {
1928 Label after_smi_test;
1929 EmitTestAndCallSmiBranch(non_smi_length == 0 ? failed : &after_smi_test,
1930 false); // Jump if receiver is not Smi.
1931
1932 // Do not use the code from the function, but let the code be patched so
1933 // that we can record the outgoing edges to other code.
1934 const Function& function = *targets[smi_case].target;
1935 GenerateStaticDartCall(deopt_id, token_index,
1936 *StubCode::CallStaticFunction_entry(),
1937 RawPcDescriptors::kOther, locs, function);
1938 __ Drop(argument_count);
1939 if (match_found != NULL) {
1940 __ Jump(match_found);
1941 }
1942 __ Bind(&after_smi_test);
1943 } else {
1944 if (!complete) {
1945 // Smi is not a valid class.
1946 EmitTestAndCallSmiBranch(failed,
1947 true); // Jump to failed if it's a Smi.
1948 }
1949 }
1950
1951 if (non_smi_length == 0) {
1952 // If non_smi_length is 0 then only a Smi check was needed; the Smi check
1953 // above will fail if there was only one check and receiver is not Smi.
1954 return;
1955 }
1956
1957 bool add_megamorphic_call = false;
1958 int bias = 0;
1959
1960 // Value is not Smi.
1961 EmitTestAndCallLoadCid();
1962
1963 int last_check = which_case_to_skip == length - 1 ? length - 2 : length - 1;
1964
1965 for (intptr_t i = 0; i < length; i++) {
1966 if (i == which_case_to_skip) continue;
1967 const bool is_last_check = (i == last_check);
1968 const int count = targets[i].count;
1969 if (!is_last_check && !complete && count < (total_ic_calls >> 5)) {
1970 // This case is hit too rarely to be worth writing class-id checks inline
1971 // for. Note that we can't do this for calls with only one target because
1972 // the type propagator may have made use of that and expects a deopt if
1973 // a new class is seen at this calls site. See IsMonomorphic.
1974 add_megamorphic_call = true;
1975 break;
1976 }
1977 Label next_test;
1978 if (!complete || !is_last_check) {
1979 bias = EmitTestAndCallCheckCid(is_last_check ? failed : &next_test,
1980 targets[i], bias);
1981 }
1982 // Do not use the code from the function, but let the code be patched so
1983 // that we can record the outgoing edges to other code.
1984 const Function& function = *targets[i].target;
1985 GenerateStaticDartCall(deopt_id, token_index,
1986 *StubCode::CallStaticFunction_entry(),
1987 RawPcDescriptors::kOther, locs, function);
1988 __ Drop(argument_count);
1989 if (!is_last_check || add_megamorphic_call) {
1990 __ Jump(match_found);
1991 }
1992 __ Bind(&next_test);
1993 }
1994 if (add_megamorphic_call) {
1995 int try_index = CatchClauseNode::kInvalidTryIndex;
1996 EmitMegamorphicInstanceCall(function_name, arguments_descriptor,
1997 argument_count, deopt_id, token_index, locs,
1998 try_index);
1999 }
2000 }
2001 #undef __
1886 #endif 2002 #endif
1887 2003
1888 #if defined(DEBUG) && !defined(TARGET_ARCH_DBC) 2004 #if defined(DEBUG) && !defined(TARGET_ARCH_DBC)
1889 // TODO(vegorov) re-enable frame state tracking on DBC. It is 2005 // TODO(vegorov) re-enable frame state tracking on DBC. It is
1890 // currently disabled because it relies on LocationSummaries and 2006 // currently disabled because it relies on LocationSummaries and
1891 // we don't use them during unoptimized compilation on DBC. 2007 // we don't use them during unoptimized compilation on DBC.
1892 void FlowGraphCompiler::FrameStateUpdateWith(Instruction* instr) { 2008 void FlowGraphCompiler::FrameStateUpdateWith(Instruction* instr) {
1893 ASSERT(!is_optimizing()); 2009 ASSERT(!is_optimizing());
1894 2010
1895 switch (instr->tag()) { 2011 switch (instr->tag()) {
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
1954 2070
1955 2071
1956 void FlowGraphCompiler::FrameStateClear() { 2072 void FlowGraphCompiler::FrameStateClear() {
1957 ASSERT(!is_optimizing()); 2073 ASSERT(!is_optimizing());
1958 frame_state_.TruncateTo(0); 2074 frame_state_.TruncateTo(0);
1959 } 2075 }
1960 #endif // defined(DEBUG) && !defined(TARGET_ARCH_DBC) 2076 #endif // defined(DEBUG) && !defined(TARGET_ARCH_DBC)
1961 2077
1962 2078
1963 } // namespace dart 2079 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_compiler.h ('k') | runtime/vm/flow_graph_compiler_arm.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698