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

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

Issue 221173011: Simplify handling of IC and megamorphic cache misses. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 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 | Annotate | Revision Log
« no previous file with comments | « runtime/vm/code_generator.h ('k') | runtime/vm/instructions_arm_test.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/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/bigint_operations.h" 9 #include "vm/bigint_operations.h"
10 #include "vm/code_patcher.h" 10 #include "vm/code_patcher.h"
(...skipping 602 matching lines...) Expand 10 before | Expand all | Expand 10 after
613 OS::PrintErr("PatchStaticCall: patching from %#" Px " to '%s' %#" Px "\n", 613 OS::PrintErr("PatchStaticCall: patching from %#" Px " to '%s' %#" Px "\n",
614 caller_frame->pc(), 614 caller_frame->pc(),
615 target_function.ToFullyQualifiedCString(), 615 target_function.ToFullyQualifiedCString(),
616 target_code.EntryPoint()); 616 target_code.EntryPoint());
617 } 617 }
618 arguments.SetReturn(target_code); 618 arguments.SetReturn(target_code);
619 } 619 }
620 620
621 621
622 // Resolves and compiles the target function of an instance call, updates 622 // Resolves and compiles the target function of an instance call, updates
623 // function cache of the receiver's class and returns the compiled code or null. 623 // function cache of the receiver's class and returns the function or null.
624 // Only the number of named arguments is checked, but not the actual names. 624 // Only the number of named arguments is checked, but not the actual names.
625 RawCode* ResolveCompileInstanceCallTarget(const Instance& receiver, 625 static RawFunction* ResolveCompileInstanceCallTarget(const Instance& receiver,
626 const ICData& ic_data) { 626 const ICData& ic_data) {
srdjan 2014/04/03 18:30:23 This method does not compile a function as the nam
Florian Schneider 2014/04/04 09:31:27 Done. Removed this helper since it is only 3 lines
627 ArgumentsDescriptor 627 ArgumentsDescriptor
628 arguments_descriptor(Array::Handle(ic_data.arguments_descriptor())); 628 arguments_descriptor(Array::Handle(ic_data.arguments_descriptor()));
629 String& function_name = String::Handle(ic_data.target_name()); 629 String& function_name = String::Handle(ic_data.target_name());
630 ASSERT(function_name.IsSymbol()); 630 ASSERT(function_name.IsSymbol());
631 631
632 Function& function = Function::Handle(); 632 return Resolver::ResolveDynamic(receiver,
633 function = Resolver::ResolveDynamic(receiver, 633 function_name,
634 function_name, 634 arguments_descriptor);
635 arguments_descriptor);
636 if (function.IsNull()) {
637 return Code::null();
638 } else {
639 if (!function.HasCode()) {
640 const Error& error = Error::Handle(Compiler::CompileFunction(function));
641 if (!error.IsNull()) {
642 Exceptions::PropagateError(error);
643 }
644 }
645 return function.CurrentCode();
646 }
647 } 635 }
648 636
649 637
650 // Result of an invoke may be an unhandled exception, in which case we 638 // Result of an invoke may be an unhandled exception, in which case we
651 // rethrow it. 639 // rethrow it.
652 static void CheckResultError(const Object& result) { 640 static void CheckResultError(const Object& result) {
653 if (result.IsError()) { 641 if (result.IsError()) {
654 Exceptions::PropagateError(Error::Cast(result)); 642 Exceptions::PropagateError(Error::Cast(result));
655 } 643 }
656 } 644 }
(...skipping 13 matching lines...) Expand all
670 arguments.SetReturn(Smi::Handle(reinterpret_cast<RawSmi*>(orig_stub))); 658 arguments.SetReturn(Smi::Handle(reinterpret_cast<RawSmi*>(orig_stub)));
671 } 659 }
672 660
673 661
674 DEFINE_RUNTIME_ENTRY(SingleStepHandler, 0) { 662 DEFINE_RUNTIME_ENTRY(SingleStepHandler, 0) {
675 ASSERT(isolate->debugger() != NULL); 663 ASSERT(isolate->debugger() != NULL);
676 isolate->debugger()->DebuggerStepCallback(); 664 isolate->debugger()->DebuggerStepCallback();
677 } 665 }
678 666
679 667
668 // An instance call of the form o.f(...) could not be resolved. Check if
669 // there is a getter with the same name. If so, invoke it. If the value is
670 // a closure, invoke it with the given arguments. If the value is a
671 // non-closure, attempt to invoke "call" on it.
672 static bool ResolveCallThroughGetter(const Instance& receiver,
673 const Class& receiver_class,
674 const String& target_name,
675 const Array& arguments_descriptor,
676 const ICData& ic_data,
677 Function* result) {
678 // 1. Check if there is a getter with the same name.
679 const String& getter_name = String::Handle(Field::GetterName(target_name));
680 const int kNumArguments = 1;
681 ArgumentsDescriptor args_desc(
682 Array::Handle(ArgumentsDescriptor::New(kNumArguments)));
683 const Function& getter = Function::Handle(
684 Resolver::ResolveDynamicForReceiverClass(receiver_class,
685 getter_name,
686 args_desc));
687 if (getter.IsNull() || getter.IsMethodExtractor()) {
688 return false;
689 }
690
691 const Function& target_function =
692 Function::Handle(receiver_class.GetInvocationDispatcher(
693 target_name,
694 arguments_descriptor,
695 RawFunction::kInvokeFieldDispatcher));
696 ASSERT(!target_function.IsNull());
697 if (FLAG_trace_ic) {
698 OS::PrintErr("InvokeField IC miss: adding <%s> id:%" Pd " -> <%s>\n",
699 Class::Handle(receiver.clazz()).ToCString(),
700 receiver.GetClassId(),
701 target_function.ToCString());
702 }
703 *result = target_function.raw();
704 return true;
705 }
706
707
708 // Handle other invocations (implicit closures, noSuchMethod).
709 RawFunction* InlineCacheMissHelper(
710 const Instance& receiver,
711 const ICData& ic_data) {
712 const Array& args_descriptor = Array::Handle(ic_data.arguments_descriptor());
713
714 const Class& receiver_class = Class::Handle(receiver.clazz());
715 const String& target_name = String::Handle(ic_data.target_name());
716
717 Function& result = Function::Handle();
718 if (!ResolveCallThroughGetter(receiver,
719 receiver_class,
720 target_name,
721 args_descriptor,
722 ic_data,
723 &result)) {
724 ArgumentsDescriptor desc(args_descriptor);
725 const Function& target_function =
726 Function::Handle(receiver_class.GetInvocationDispatcher(
727 target_name,
728 args_descriptor,
729 RawFunction::kNoSuchMethodDispatcher));
730 if (FLAG_trace_ic) {
731 OS::PrintErr("NoSuchMethod IC miss: adding <%s> id:%" Pd " -> <%s>\n",
732 Class::Handle(receiver.clazz()).ToCString(),
733 receiver.GetClassId(),
734 target_function.ToCString());
735 }
736 result = target_function.raw();
737 }
738 return result.raw();
739 }
740
680 static RawFunction* InlineCacheMissHandler( 741 static RawFunction* InlineCacheMissHandler(
681 const GrowableArray<const Instance*>& args, 742 const GrowableArray<const Instance*>& args,
682 const ICData& ic_data) { 743 const ICData& ic_data) {
683 const Instance& receiver = *args[0]; 744 const Instance& receiver = *args[0];
684 const Code& target_code = 745 Function& target_function =
685 Code::Handle(ResolveCompileInstanceCallTarget(receiver, ic_data)); 746 Function::Handle(ResolveCompileInstanceCallTarget(receiver, ic_data));
686 if (target_code.IsNull()) { 747 if (target_function.IsNull()) {
687 // Let the megamorphic stub handle special cases: NoSuchMethod,
688 // closure calls.
689 if (FLAG_trace_ic) { 748 if (FLAG_trace_ic) {
690 OS::PrintErr("InlineCacheMissHandler NULL code for %s receiver: %s\n", 749 OS::PrintErr("InlineCacheMissHandler NULL function for %s receiver: %s\n",
691 String::Handle(ic_data.target_name()).ToCString(), 750 String::Handle(ic_data.target_name()).ToCString(),
692 receiver.ToCString()); 751 receiver.ToCString());
693 } 752 }
694 return Function::null(); 753 ic_data.set_is_closure_call(true);
754 target_function = InlineCacheMissHelper(receiver, ic_data);
695 } 755 }
696 const Function& target_function =
697 Function::Handle(target_code.function());
698 ASSERT(!target_function.IsNull()); 756 ASSERT(!target_function.IsNull());
699 if (args.length() == 1) { 757 if (args.length() == 1) {
700 ic_data.AddReceiverCheck(args[0]->GetClassId(), target_function); 758 ic_data.AddReceiverCheck(args[0]->GetClassId(), target_function);
701 } else { 759 } else {
702 GrowableArray<intptr_t> class_ids(args.length()); 760 GrowableArray<intptr_t> class_ids(args.length());
703 ASSERT(ic_data.num_args_tested() == args.length()); 761 ASSERT(ic_data.num_args_tested() == args.length());
704 for (intptr_t i = 0; i < args.length(); i++) { 762 for (intptr_t i = 0; i < args.length(); i++) {
705 class_ids.Add(args[i]->GetClassId()); 763 class_ids.Add(args[i]->GetClassId());
706 } 764 }
707 ic_data.AddCheck(class_ids, target_function); 765 ic_data.AddCheck(class_ids, target_function);
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
825 } 883 }
826 arguments.SetReturn(target); 884 arguments.SetReturn(target);
827 } 885 }
828 886
829 887
830 // Handle a miss of a megamorphic cache. 888 // Handle a miss of a megamorphic cache.
831 // Arg0: Receiver. 889 // Arg0: Receiver.
832 // Arg1: ICData object. 890 // Arg1: ICData object.
833 // Arg2: Arguments descriptor array. 891 // Arg2: Arguments descriptor array.
834 892
835 // Returns: target instructions to call or null if the 893 // Returns: target function to call or null if the
srdjan 2014/04/03 18:30:23 truncated comment
Florian Schneider 2014/04/04 09:31:27 Done.
836 // InstanceFunctionLookup stub should be used (e.g., to invoke no such
837 // method and implicit closures)..
838 DEFINE_RUNTIME_ENTRY(MegamorphicCacheMissHandler, 3) { 894 DEFINE_RUNTIME_ENTRY(MegamorphicCacheMissHandler, 3) {
839 const Instance& receiver = Instance::CheckedHandle(arguments.ArgAt(0)); 895 const Instance& receiver = Instance::CheckedHandle(arguments.ArgAt(0));
840 const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(1)); 896 const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(1));
841 const Array& descriptor = Array::CheckedHandle(arguments.ArgAt(2)); 897 const Array& descriptor = Array::CheckedHandle(arguments.ArgAt(2));
842 const String& name = String::Handle(ic_data.target_name()); 898 const String& name = String::Handle(ic_data.target_name());
843 const MegamorphicCache& cache = MegamorphicCache::Handle( 899 const MegamorphicCache& cache = MegamorphicCache::Handle(
844 isolate->megamorphic_cache_table()->Lookup(name, descriptor)); 900 isolate->megamorphic_cache_table()->Lookup(name, descriptor));
845 Class& cls = Class::Handle(receiver.clazz()); 901 Class& cls = Class::Handle(receiver.clazz());
846 ASSERT(!cls.IsNull()); 902 ASSERT(!cls.IsNull());
847 if (FLAG_trace_ic || FLAG_trace_ic_miss_in_optimized) { 903 if (FLAG_trace_ic || FLAG_trace_ic_miss_in_optimized) {
848 OS::PrintErr("Megamorphic IC miss, class=%s, function=%s\n", 904 OS::PrintErr("Megamorphic IC miss, class=%s, function=%s\n",
849 cls.ToCString(), name.ToCString()); 905 cls.ToCString(), name.ToCString());
850 } 906 }
851 907
852 ArgumentsDescriptor args_desc(descriptor); 908 ArgumentsDescriptor args_desc(descriptor);
853 const Function& target = Function::Handle( 909 Function& target_function = Function::Handle(
854 Resolver::ResolveDynamicForReceiverClass(cls, 910 Resolver::ResolveDynamicForReceiverClass(cls,
855 name, 911 name,
856 args_desc)); 912 args_desc));
913 if (target_function.IsNull()) {
914 ic_data.set_is_closure_call(true);
915 target_function = InlineCacheMissHelper(receiver, ic_data);
916 }
857 917
858 Instructions& instructions = Instructions::Handle(); 918 ASSERT(!target_function.IsNull());
859 if (!target.IsNull()) { 919 // Insert function found into cache and return it.
860 if (!target.HasCode()) {
861 const Error& error = Error::Handle(Compiler::CompileFunction(target));
862 if (!error.IsNull()) {
863 Exceptions::PropagateError(error);
864 }
865 }
866 ASSERT(target.HasCode());
867 instructions = Code::Handle(target.CurrentCode()).instructions();
868 }
869 arguments.SetReturn(instructions);
870 if (instructions.IsNull()) return;
871
872 cache.EnsureCapacity(); 920 cache.EnsureCapacity();
873 const Smi& class_id = Smi::Handle(Smi::New(cls.id())); 921 const Smi& class_id = Smi::Handle(Smi::New(cls.id()));
874 cache.Insert(class_id, target); 922 cache.Insert(class_id, target_function);
875 return; 923 arguments.SetReturn(target_function);
srdjan 2014/04/03 18:30:23 Who compiles the target_function? The caller of th
Florian Schneider 2014/04/04 09:31:27 The lazy-compile stub compile the target function
srdjan 2014/04/04 15:36:24 It seems that only ARM64 is not installing the laz
876 } 924 }
877 925
878 926
879 // Updates IC data for two arguments. Used by the equality operation when 927 // Updates IC data for two arguments. Used by the equality operation when
880 // the control flow bypasses regular inline cache (null arguments). 928 // the control flow bypasses regular inline cache (null arguments).
881 // Arg0: Receiver object. 929 // Arg0: Receiver object.
882 // Arg1: Argument after receiver. 930 // Arg1: Argument after receiver.
883 // Arg2: Target's name. 931 // Arg2: Target's name.
884 // Arg3: ICData. 932 // Arg3: ICData.
885 DEFINE_RUNTIME_ENTRY(UpdateICDataTwoArgs, 4) { 933 DEFINE_RUNTIME_ENTRY(UpdateICDataTwoArgs, 4) {
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
943 const Array& args_descriptor = Array::CheckedHandle(arguments.ArgAt(0)); 991 const Array& args_descriptor = Array::CheckedHandle(arguments.ArgAt(0));
944 const Array& function_args = Array::CheckedHandle(arguments.ArgAt(1)); 992 const Array& function_args = Array::CheckedHandle(arguments.ArgAt(1));
945 993
946 const Object& result = Object::Handle( 994 const Object& result = Object::Handle(
947 DartEntry::InvokeClosure(function_args, args_descriptor)); 995 DartEntry::InvokeClosure(function_args, args_descriptor));
948 CheckResultError(result); 996 CheckResultError(result);
949 arguments.SetReturn(result); 997 arguments.SetReturn(result);
950 } 998 }
951 999
952 1000
953 // An instance call of the form o.f(...) could not be resolved. Check if
954 // there is a getter with the same name. If so, invoke it. If the value is
955 // a closure, invoke it with the given arguments. If the value is a
956 // non-closure, attempt to invoke "call" on it.
957 static bool ResolveCallThroughGetter(const Instance& receiver,
958 const Class& receiver_class,
959 const String& target_name,
960 const Array& arguments_descriptor,
961 const Array& arguments,
962 const ICData& ic_data,
963 Object* result) {
964 // 1. Check if there is a getter with the same name.
965 const String& getter_name = String::Handle(Field::GetterName(target_name));
966 const int kNumArguments = 1;
967 ArgumentsDescriptor args_desc(
968 Array::Handle(ArgumentsDescriptor::New(kNumArguments)));
969 const Function& getter = Function::Handle(
970 Resolver::ResolveDynamicForReceiverClass(receiver_class,
971 getter_name,
972 args_desc));
973 if (getter.IsNull() || getter.IsMethodExtractor()) {
974 return false;
975 }
976
977 const Function& target_function =
978 Function::Handle(receiver_class.GetInvocationDispatcher(
979 target_name,
980 arguments_descriptor,
981 RawFunction::kInvokeFieldDispatcher));
982 // Update IC data.
983 ASSERT(!target_function.IsNull());
984 ic_data.AddReceiverCheck(receiver.GetClassId(), target_function);
985 if (FLAG_trace_ic) {
986 OS::PrintErr("InvokeField IC miss: adding <%s> id:%" Pd " -> <%s>\n",
987 Class::Handle(receiver.clazz()).ToCString(),
988 receiver.GetClassId(),
989 target_function.ToCString());
990 }
991 *result = DartEntry::InvokeFunction(target_function,
992 arguments,
993 arguments_descriptor);
994 CheckResultError(*result);
995 return true;
996 }
997
998
999 // The IC miss handler has failed to find a (cacheable) instance function to
1000 // invoke. Handle three possibilities:
1001 //
1002 // 1. If the call was a getter o.f, there may be an instance function with
1003 // the same name. If so, create an implicit closure and return it.
1004 //
1005 // 2. If the call was an instance call o.f(...), there may be a getter with
1006 // the same name. If so, invoke it. If the value is a closure, invoke
1007 // it with the given arguments. If the value is a non-closure, attempt
1008 // to invoke "call" on it.
1009 //
1010 // 3. There is no such method.
1011 DEFINE_RUNTIME_ENTRY(InstanceFunctionLookup, 4) {
1012 const Instance& receiver = Instance::CheckedHandle(arguments.ArgAt(0));
1013 const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(1));
1014 const Array& args_descriptor = Array::CheckedHandle(arguments.ArgAt(2));
1015 const Array& args = Array::CheckedHandle(arguments.ArgAt(3));
1016
1017 const Class& receiver_class = Class::Handle(receiver.clazz());
1018 const String& target_name = String::Handle(ic_data.target_name());
1019
1020 Object& result = Object::Handle();
1021 if (!ResolveCallThroughGetter(receiver,
1022 receiver_class,
1023 target_name,
1024 args_descriptor,
1025 args,
1026 ic_data,
1027 &result)) {
1028 ArgumentsDescriptor desc(args_descriptor);
1029 const Function& target_function =
1030 Function::Handle(receiver_class.GetInvocationDispatcher(
1031 target_name,
1032 args_descriptor,
1033 RawFunction::kNoSuchMethodDispatcher));
1034 // Update IC data.
1035 ASSERT(!target_function.IsNull());
1036 intptr_t receiver_cid = receiver.GetClassId();
1037 if (ic_data.num_args_tested() == 1) {
1038 // In optimized code we may enter into here via the
1039 // MegamorphicCacheMissHandler since noSuchMethod dispatchers are not
1040 // inserted into the megamorphic cache. Therefore, we need to guard
1041 // against entering the same check twice into the ICData.
1042 // Note that num_args_tested == 1 in optimized code.
1043 // TODO(fschneider): Handle extraordinary cases like noSuchMethod and
1044 // implicit closure invocation properly in the megamorphic cache.
1045 const Function& target =
1046 Function::Handle(ic_data.GetTargetForReceiverClassId(receiver_cid));
1047 if (target.IsNull()) {
1048 ic_data.AddReceiverCheck(receiver_cid, target_function);
1049 }
1050 } else {
1051 // Operators calls have two or three arguments tested ([], []=, etc.)
1052 ASSERT(ic_data.num_args_tested() > 1);
1053 GrowableArray<intptr_t> class_ids(ic_data.num_args_tested());
1054 class_ids.Add(receiver_cid);
1055 for (intptr_t i = 1; i < ic_data.num_args_tested(); ++i) {
1056 class_ids.Add(Object::Handle(args.At(i)).GetClassId());
1057 }
1058 ic_data.AddCheck(class_ids, target_function);
1059 }
1060 if (FLAG_trace_ic) {
1061 OS::PrintErr("NoSuchMethod IC miss: adding <%s> id:%" Pd " -> <%s>\n",
1062 Class::Handle(receiver.clazz()).ToCString(),
1063 receiver_cid,
1064 target_function.ToCString());
1065 }
1066 result = DartEntry::InvokeFunction(target_function, args, args_descriptor);
1067 }
1068 CheckResultError(result);
1069 arguments.SetReturn(result);
1070 }
1071
1072
1073 static bool CanOptimizeFunction(const Function& function, Isolate* isolate) { 1001 static bool CanOptimizeFunction(const Function& function, Isolate* isolate) {
1074 const intptr_t kLowInvocationCount = -100000000; 1002 const intptr_t kLowInvocationCount = -100000000;
1075 if (isolate->debugger()->IsStepping() || 1003 if (isolate->debugger()->IsStepping() ||
1076 isolate->debugger()->HasBreakpoint(function)) { 1004 isolate->debugger()->HasBreakpoint(function)) {
1077 // We cannot set breakpoints and single step in optimized code, 1005 // We cannot set breakpoints and single step in optimized code,
1078 // so do not optimize the function. 1006 // so do not optimize the function.
1079 function.set_usage_counter(0); 1007 function.set_usage_counter(0);
1080 return false; 1008 return false;
1081 } 1009 }
1082 if (function.deoptimization_counter() >= 1010 if (function.deoptimization_counter() >=
(...skipping 465 matching lines...) Expand 10 before | Expand all | Expand 10 after
1548 // of the given value. 1476 // of the given value.
1549 // Arg0: Field object; 1477 // Arg0: Field object;
1550 // Arg1: Value that is being stored. 1478 // Arg1: Value that is being stored.
1551 DEFINE_RUNTIME_ENTRY(UpdateFieldCid, 2) { 1479 DEFINE_RUNTIME_ENTRY(UpdateFieldCid, 2) {
1552 const Field& field = Field::CheckedHandle(arguments.ArgAt(0)); 1480 const Field& field = Field::CheckedHandle(arguments.ArgAt(0));
1553 const Object& value = Object::Handle(arguments.ArgAt(1)); 1481 const Object& value = Object::Handle(arguments.ArgAt(1));
1554 field.UpdateGuardedCidAndLength(value); 1482 field.UpdateGuardedCidAndLength(value);
1555 } 1483 }
1556 1484
1557 } // namespace dart 1485 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/code_generator.h ('k') | runtime/vm/instructions_arm_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698