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

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

Issue 2226893002: Optimize AOT's switchable calls for the monomorphic case. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: sync Created 4 years, 4 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/clustered_snapshot.cc ('k') | runtime/vm/code_patcher.h » ('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/code_generator.h" 5 #include "vm/code_generator.h"
6 6
7 #include "vm/assembler.h" 7 #include "vm/assembler.h"
8 #include "vm/ast.h" 8 #include "vm/ast.h"
9 #include "vm/code_patcher.h" 9 #include "vm/code_patcher.h"
10 #include "vm/compiler.h" 10 #include "vm/compiler.h"
(...skipping 653 matching lines...) Expand 10 before | Expand all | Expand 10 after
664 CodePatcher::GetStaticCallTargetAt(caller_frame->pc(), caller_code)); 664 CodePatcher::GetStaticCallTargetAt(caller_frame->pc(), caller_code));
665 CodePatcher::PatchStaticCallAt(caller_frame->pc(), 665 CodePatcher::PatchStaticCallAt(caller_frame->pc(),
666 caller_code, 666 caller_code,
667 target_code); 667 target_code);
668 caller_code.SetStaticCallTargetCodeAt(caller_frame->pc(), target_code); 668 caller_code.SetStaticCallTargetCodeAt(caller_frame->pc(), target_code);
669 if (FLAG_trace_patching) { 669 if (FLAG_trace_patching) {
670 THR_Print("PatchStaticCall: patching caller pc %#" Px "" 670 THR_Print("PatchStaticCall: patching caller pc %#" Px ""
671 " to '%s' new entry point %#" Px " (%s)\n", 671 " to '%s' new entry point %#" Px " (%s)\n",
672 caller_frame->pc(), 672 caller_frame->pc(),
673 target_function.ToFullyQualifiedCString(), 673 target_function.ToFullyQualifiedCString(),
674 target_code.EntryPoint(), 674 target_code.UncheckedEntryPoint(),
675 target_code.is_optimized() ? "optimized" : "unoptimized"); 675 target_code.is_optimized() ? "optimized" : "unoptimized");
676 } 676 }
677 arguments.SetReturn(target_code); 677 arguments.SetReturn(target_code);
678 } 678 }
679 679
680 680
681 // Result of an invoke may be an unhandled exception, in which case we 681 // Result of an invoke may be an unhandled exception, in which case we
682 // rethrow it. 682 // rethrow it.
683 static void CheckResultError(const Object& result) { 683 static void CheckResultError(const Object& result) {
684 if (result.IsError()) { 684 if (result.IsError()) {
(...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after
1021 OS::PrintErr("StaticCallMissHandler at %#" Px 1021 OS::PrintErr("StaticCallMissHandler at %#" Px
1022 " target %s (%" Pd ", %" Pd ")\n", 1022 " target %s (%" Pd ", %" Pd ")\n",
1023 caller_frame->pc(), target.ToCString(), cids[0], cids[1]); 1023 caller_frame->pc(), target.ToCString(), cids[0], cids[1]);
1024 } 1024 }
1025 arguments.SetReturn(target); 1025 arguments.SetReturn(target);
1026 } 1026 }
1027 1027
1028 1028
1029 // Handle a miss of a megamorphic cache. 1029 // Handle a miss of a megamorphic cache.
1030 // Arg0: Receiver. 1030 // Arg0: Receiver.
1031 // Returns: the ICData used to continue with a polymorphic call.
1032 DEFINE_RUNTIME_ENTRY(MonomorphicMiss, 1) {
1033 #if defined(TARGET_ARCH_DBC)
1034 // DBC does not use switchable calls.
1035 UNREACHABLE();
1036 #else
1037 const Instance& receiver = Instance::CheckedHandle(zone, arguments.ArgAt(0));
1038
1039 DartFrameIterator iterator;
1040 StackFrame* caller_frame = iterator.NextFrame();
1041 ASSERT(caller_frame->IsDartFrame());
1042 const Code& caller_code = Code::Handle(zone, caller_frame->LookupDartCode());
1043 const Function& caller_function =
1044 Function::Handle(zone, caller_frame->LookupDartFunction());
1045
1046 Smi& old_expected_cid = Smi::Handle(zone);
1047 old_expected_cid ^= CodePatcher::GetSwitchableCallDataAt(caller_frame->pc(),
1048 caller_code);
1049 const Code& old_target_code =
1050 Code::Handle(CodePatcher::GetSwitchableCallTargetAt(caller_frame->pc(),
1051 caller_code));
1052 Function& old_target = Function::Handle(zone);
1053 old_target ^= old_target_code.owner();
1054
1055 // We lost the original ICData when we patched to the monomorphic case.
1056 const String& name = String::Handle(zone, old_target.name());
1057 ASSERT(!old_target.HasOptionalParameters());
1058 const Array& descriptor = Array::Handle(zone,
1059 ArgumentsDescriptor::New(old_target.num_fixed_parameters()));
1060 const ICData& ic_data =
1061 ICData::Handle(zone, ICData::New(caller_function,
1062 name,
1063 descriptor,
1064 Thread::kNoDeoptId,
1065 1, /* args_tested */
1066 false /* static_call */));
1067
1068 // Add the first target.
1069 ic_data.AddReceiverCheck(old_expected_cid.Value(), old_target);
1070
1071 // Maybe add the new target.
1072 Class& cls = Class::Handle(zone, receiver.clazz());
1073 ArgumentsDescriptor args_desc(descriptor);
1074 Function& target_function = Function::Handle(zone,
1075 Resolver::ResolveDynamicForReceiverClass(cls,
1076 name,
1077 args_desc));
1078 if (target_function.IsNull()) {
1079 target_function = InlineCacheMissHelper(receiver, descriptor, name);
1080 }
1081 if (target_function.IsNull()) {
1082 ASSERT(!FLAG_lazy_dispatchers);
1083 } else {
1084 ic_data.AddReceiverCheck(receiver.GetClassId(), target_function);
1085 }
1086
1087 // Patch to call through stub.
1088 const Code& stub =
1089 Code::Handle(zone, StubCode::ICLookupThroughCode_entry()->code());
1090 ASSERT(!Isolate::Current()->compilation_allowed());
1091 CodePatcher::PatchSwitchableCallAt(caller_frame->pc(),
1092 caller_code,
1093 ic_data,
1094 stub);
1095
1096 // Return the ICData. The miss stub will jump to continue in the IC lookup
1097 // stub.
1098 arguments.SetReturn(ic_data);
1099 #endif // !defined(TARGET_ARCH_DBC)
1100 }
1101
1102
1103 // Handle a miss of a megamorphic cache.
1104 // Arg0: Receiver.
1031 // Arg1: ICData or MegamorphicCache. 1105 // Arg1: ICData or MegamorphicCache.
1032 // Arg2: Arguments descriptor array. 1106 // Arg2: Arguments descriptor array.
1033 // Returns: target function to call. 1107 // Returns: target function to call.
1034 DEFINE_RUNTIME_ENTRY(MegamorphicCacheMissHandler, 3) { 1108 DEFINE_RUNTIME_ENTRY(MegamorphicCacheMissHandler, 3) {
1035 // DBC does not use megamorphic calls right now. 1109 #if defined(TARGET_ARCH_DBC)
1036 #if !defined(TARGET_ARCH_DBC) 1110 // DBC does not use megamorphic calls right now.
1111 UNREACHABLE();
1112 #else
1037 const Instance& receiver = Instance::CheckedHandle(zone, arguments.ArgAt(0)); 1113 const Instance& receiver = Instance::CheckedHandle(zone, arguments.ArgAt(0));
1038 const Object& ic_data_or_cache = Object::Handle(zone, arguments.ArgAt(1)); 1114 const Object& ic_data_or_cache = Object::Handle(zone, arguments.ArgAt(1));
1039 const Array& descriptor = Array::CheckedHandle(zone, arguments.ArgAt(2)); 1115 const Array& descriptor = Array::CheckedHandle(zone, arguments.ArgAt(2));
1040 String& name = String::Handle(zone); 1116 String& name = String::Handle(zone);
1041 if (ic_data_or_cache.IsICData()) { 1117 if (ic_data_or_cache.IsICData()) {
1042 name = ICData::Cast(ic_data_or_cache).target_name(); 1118 name = ICData::Cast(ic_data_or_cache).target_name();
1043 } else { 1119 } else {
1044 ASSERT(ic_data_or_cache.IsMegamorphicCache()); 1120 ASSERT(ic_data_or_cache.IsMegamorphicCache());
1045 name = MegamorphicCache::Cast(ic_data_or_cache).target_name(); 1121 name = MegamorphicCache::Cast(ic_data_or_cache).target_name();
1046 } 1122 }
(...skipping 13 matching lines...) Expand all
1060 target_function = InlineCacheMissHelper(receiver, descriptor, name); 1136 target_function = InlineCacheMissHelper(receiver, descriptor, name);
1061 } 1137 }
1062 if (target_function.IsNull()) { 1138 if (target_function.IsNull()) {
1063 ASSERT(!FLAG_lazy_dispatchers); 1139 ASSERT(!FLAG_lazy_dispatchers);
1064 arguments.SetReturn(target_function); 1140 arguments.SetReturn(target_function);
1065 return; 1141 return;
1066 } 1142 }
1067 1143
1068 if (ic_data_or_cache.IsICData()) { 1144 if (ic_data_or_cache.IsICData()) {
1069 const ICData& ic_data = ICData::Cast(ic_data_or_cache); 1145 const ICData& ic_data = ICData::Cast(ic_data_or_cache);
1070 ic_data.AddReceiverCheck(receiver.GetClassId(), target_function); 1146
1071 if (ic_data.NumberOfChecks() > FLAG_max_polymorphic_checks) { 1147 if ((ic_data.NumberOfChecks() == 0) &&
1072 // Switch to megamorphic call. 1148 !target_function.HasOptionalParameters() &&
1073 const MegamorphicCache& cache = MegamorphicCache::Handle(zone, 1149 !Isolate::Current()->compilation_allowed()) {
1074 MegamorphicCacheTable::Lookup(isolate, name, descriptor)); 1150 // This call site is unlinked: transition to a monomorphic direct call.
1151 // Note we cannot do this if the target has optional parameters because
1152 // the monomorphic direct call does not load the arguments descriptor.
1153 // We cannot do this if we are still in the middle of precompiling because
1154 // the monomorphic case hides an live instance selector from the
1155 // treeshaker.
1156
1157 if (!target_function.HasCode()) {
1158 const Error& error =
1159 Error::Handle(Compiler::CompileFunction(thread, target_function));
1160 if (!error.IsNull()) {
1161 Exceptions::PropagateError(error);
1162 }
1163 }
1164
1075 DartFrameIterator iterator; 1165 DartFrameIterator iterator;
1076 StackFrame* miss_function_frame = iterator.NextFrame(); 1166 StackFrame* miss_function_frame = iterator.NextFrame();
1077 ASSERT(miss_function_frame->IsDartFrame()); 1167 ASSERT(miss_function_frame->IsDartFrame());
1078 StackFrame* caller_frame = iterator.NextFrame(); 1168 StackFrame* caller_frame = iterator.NextFrame();
1079 ASSERT(caller_frame->IsDartFrame()); 1169 ASSERT(caller_frame->IsDartFrame());
1080 const Code& code = Code::Handle(zone, caller_frame->LookupDartCode()); 1170 const Code& caller_code =
1081 const Code& stub = 1171 Code::Handle(zone, caller_frame->LookupDartCode());
1082 Code::Handle(zone, StubCode::MegamorphicLookup_entry()->code()); 1172 const Code& target_code =
1083 CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), 1173 Code::Handle(zone, target_function.CurrentCode());
1084 code, ic_data, cache, stub); 1174 const Smi& expected_cid =
1175 Smi::Handle(zone, Smi::New(receiver.GetClassId()));
1176
1177 CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), caller_code,
1178 expected_cid, target_code);
1179 } else {
1180 ic_data.AddReceiverCheck(receiver.GetClassId(), target_function);
1181 if (ic_data.NumberOfChecks() > FLAG_max_polymorphic_checks) {
1182 // Switch to megamorphic call.
1183 const MegamorphicCache& cache = MegamorphicCache::Handle(zone,
1184 MegamorphicCacheTable::Lookup(isolate, name, descriptor));
1185 DartFrameIterator iterator;
1186 StackFrame* miss_function_frame = iterator.NextFrame();
1187 ASSERT(miss_function_frame->IsDartFrame());
1188 StackFrame* caller_frame = iterator.NextFrame();
1189 ASSERT(caller_frame->IsDartFrame());
1190 const Code& caller_code =
1191 Code::Handle(zone, caller_frame->LookupDartCode());
1192 const Code& stub =
1193 Code::Handle(zone, StubCode::MegamorphicLookup_entry()->code());
1194
1195 CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), caller_code,
1196 cache, stub);
1197 }
1085 } 1198 }
1086 } else { 1199 } else {
1087 const MegamorphicCache& cache = MegamorphicCache::Cast(ic_data_or_cache); 1200 const MegamorphicCache& cache = MegamorphicCache::Cast(ic_data_or_cache);
1088 // Insert function found into cache and return it. 1201 // Insert function found into cache and return it.
1089 cache.EnsureCapacity(); 1202 cache.EnsureCapacity();
1090 const Smi& class_id = Smi::Handle(zone, Smi::New(cls.id())); 1203 const Smi& class_id = Smi::Handle(zone, Smi::New(cls.id()));
1091 cache.Insert(class_id, target_function); 1204 cache.Insert(class_id, target_function);
1092 } 1205 }
1093 arguments.SetReturn(target_function); 1206 arguments.SetReturn(target_function);
1094 #else
1095 UNREACHABLE();
1096 #endif // !defined(TARGET_ARCH_DBC) 1207 #endif // !defined(TARGET_ARCH_DBC)
1097 } 1208 }
1098 1209
1099 1210
1100 // Invoke appropriate noSuchMethod or closure from getter. 1211 // Invoke appropriate noSuchMethod or closure from getter.
1101 // Arg0: receiver 1212 // Arg0: receiver
1102 // Arg1: ICData or MegamorphicCache 1213 // Arg1: ICData or MegamorphicCache
1103 // Arg2: arguments descriptor array 1214 // Arg2: arguments descriptor array
1104 // Arg3: arguments array 1215 // Arg3: arguments array
1105 DEFINE_RUNTIME_ENTRY(InvokeNoSuchMethodDispatcher, 4) { 1216 DEFINE_RUNTIME_ENTRY(InvokeNoSuchMethodDispatcher, 4) {
(...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after
1454 } 1565 }
1455 1566
1456 const Code& optimized_code = Code::Handle(function.CurrentCode()); 1567 const Code& optimized_code = Code::Handle(function.CurrentCode());
1457 // The current code will not be changed in the case that the compiler 1568 // The current code will not be changed in the case that the compiler
1458 // bailed out during OSR compilation. 1569 // bailed out during OSR compilation.
1459 if (optimized_code.raw() != original_code.raw()) { 1570 if (optimized_code.raw() != original_code.raw()) {
1460 // The OSR code does not work for calling the function, so restore the 1571 // The OSR code does not work for calling the function, so restore the
1461 // unoptimized code. Patch the stack frame to return into the OSR 1572 // unoptimized code. Patch the stack frame to return into the OSR
1462 // code. 1573 // code.
1463 uword optimized_entry = 1574 uword optimized_entry =
1464 Instructions::Handle(optimized_code.instructions()).EntryPoint(); 1575 Instructions::UncheckedEntryPoint(optimized_code.instructions());
1465 function.AttachCode(original_code); 1576 function.AttachCode(original_code);
1466 frame->set_pc(optimized_entry); 1577 frame->set_pc(optimized_entry);
1467 frame->set_pc_marker(optimized_code.raw()); 1578 frame->set_pc_marker(optimized_code.raw());
1468 } 1579 }
1469 } 1580 }
1470 } 1581 }
1471 1582
1472 1583
1473 DEFINE_RUNTIME_ENTRY(TraceICCall, 2) { 1584 DEFINE_RUNTIME_ENTRY(TraceICCall, 2) {
1474 const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(0)); 1585 const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(0));
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
1589 zone, target_function.CurrentCode()); 1700 zone, target_function.CurrentCode());
1590 CodePatcher::PatchStaticCallAt(frame->pc(), 1701 CodePatcher::PatchStaticCallAt(frame->pc(),
1591 caller_code, 1702 caller_code,
1592 current_target_code); 1703 current_target_code);
1593 caller_code.SetStaticCallTargetCodeAt(frame->pc(), current_target_code); 1704 caller_code.SetStaticCallTargetCodeAt(frame->pc(), current_target_code);
1594 if (FLAG_trace_patching) { 1705 if (FLAG_trace_patching) {
1595 OS::PrintErr("FixCallersTarget: caller %#" Px " " 1706 OS::PrintErr("FixCallersTarget: caller %#" Px " "
1596 "target '%s' -> %#" Px "\n", 1707 "target '%s' -> %#" Px "\n",
1597 frame->pc(), 1708 frame->pc(),
1598 target_function.ToFullyQualifiedCString(), 1709 target_function.ToFullyQualifiedCString(),
1599 current_target_code.EntryPoint()); 1710 current_target_code.UncheckedEntryPoint());
1600 } 1711 }
1601 arguments.SetReturn(current_target_code); 1712 arguments.SetReturn(current_target_code);
1602 } 1713 }
1603 1714
1604 1715
1605 // The caller tried to allocate an instance via an invalidated allocation 1716 // The caller tried to allocate an instance via an invalidated allocation
1606 // stub. 1717 // stub.
1607 DEFINE_RUNTIME_ENTRY(FixAllocationStubTarget, 0) { 1718 DEFINE_RUNTIME_ENTRY(FixAllocationStubTarget, 0) {
1608 #if !defined(DART_PRECOMPILED_RUNTIME) 1719 #if !defined(DART_PRECOMPILED_RUNTIME)
1609 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames); 1720 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
(...skipping 21 matching lines...) Expand all
1631 } 1742 }
1632 CodePatcher::PatchStaticCallAt(frame->pc(), 1743 CodePatcher::PatchStaticCallAt(frame->pc(),
1633 caller_code, 1744 caller_code,
1634 alloc_stub); 1745 alloc_stub);
1635 caller_code.SetStubCallTargetCodeAt(frame->pc(), alloc_stub); 1746 caller_code.SetStubCallTargetCodeAt(frame->pc(), alloc_stub);
1636 if (FLAG_trace_patching) { 1747 if (FLAG_trace_patching) {
1637 OS::PrintErr("FixAllocationStubTarget: caller %#" Px " alloc-class %s " 1748 OS::PrintErr("FixAllocationStubTarget: caller %#" Px " alloc-class %s "
1638 " -> %#" Px "\n", 1749 " -> %#" Px "\n",
1639 frame->pc(), 1750 frame->pc(),
1640 alloc_class.ToCString(), 1751 alloc_class.ToCString(),
1641 alloc_stub.EntryPoint()); 1752 alloc_stub.UncheckedEntryPoint());
1642 } 1753 }
1643 arguments.SetReturn(alloc_stub); 1754 arguments.SetReturn(alloc_stub);
1644 #else 1755 #else
1645 UNREACHABLE(); 1756 UNREACHABLE();
1646 #endif 1757 #endif
1647 } 1758 }
1648 1759
1649 1760
1650 const char* DeoptReasonToCString(ICData::DeoptReasonId deopt_reason) { 1761 const char* DeoptReasonToCString(ICData::DeoptReasonId deopt_reason) {
1651 switch (deopt_reason) { 1762 switch (deopt_reason) {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
1683 } 1794 }
1684 // Patch call site (lazy deoptimization is quite rare, patching it twice 1795 // Patch call site (lazy deoptimization is quite rare, patching it twice
1685 // is not a performance issue). 1796 // is not a performance issue).
1686 uword lazy_deopt_jump = optimized_code.GetLazyDeoptPc(); 1797 uword lazy_deopt_jump = optimized_code.GetLazyDeoptPc();
1687 #if !defined(TARGET_ARCH_DBC) 1798 #if !defined(TARGET_ARCH_DBC)
1688 ASSERT(lazy_deopt_jump != 0); 1799 ASSERT(lazy_deopt_jump != 0);
1689 #endif 1800 #endif
1690 const Instructions& instrs = 1801 const Instructions& instrs =
1691 Instructions::Handle(zone, optimized_code.instructions()); 1802 Instructions::Handle(zone, optimized_code.instructions());
1692 { 1803 {
1693 WritableInstructionsScope writable(instrs.EntryPoint(), instrs.size()); 1804 WritableInstructionsScope writable(instrs.PayloadStart(), instrs.size());
1694 CodePatcher::InsertDeoptimizationCallAt(pc, lazy_deopt_jump); 1805 CodePatcher::InsertDeoptimizationCallAt(pc, lazy_deopt_jump);
1695 } 1806 }
1696 if (FLAG_trace_patching) { 1807 if (FLAG_trace_patching) {
1697 const String& name = String::Handle(function.name()); 1808 const String& name = String::Handle(function.name());
1698 OS::PrintErr("InsertDeoptimizationCallAt: %" Px " to %" Px " for %s\n", pc, 1809 OS::PrintErr("InsertDeoptimizationCallAt: %" Px " to %" Px " for %s\n", pc,
1699 lazy_deopt_jump, name.ToCString()); 1810 lazy_deopt_jump, name.ToCString());
1700 } 1811 }
1701 // Mark code as dead (do not GC its embedded objects). 1812 // Mark code as dead (do not GC its embedded objects).
1702 optimized_code.set_is_alive(false); 1813 optimized_code.set_is_alive(false);
1703 } 1814 }
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after
1959 const intptr_t elm_size = old_data.ElementSizeInBytes(); 2070 const intptr_t elm_size = old_data.ElementSizeInBytes();
1960 const TypedData& new_data = 2071 const TypedData& new_data =
1961 TypedData::Handle(TypedData::New(cid, new_size, Heap::kOld)); 2072 TypedData::Handle(TypedData::New(cid, new_size, Heap::kOld));
1962 TypedData::Copy(new_data, 0, old_data, 0, old_size * elm_size); 2073 TypedData::Copy(new_data, 0, old_data, 0, old_size * elm_size);
1963 typed_data_cell.SetAt(0, new_data); 2074 typed_data_cell.SetAt(0, new_data);
1964 arguments.SetReturn(new_data); 2075 arguments.SetReturn(new_data);
1965 } 2076 }
1966 2077
1967 2078
1968 } // namespace dart 2079 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/clustered_snapshot.cc ('k') | runtime/vm/code_patcher.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698