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/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 706 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
717 | 717 |
718 // An instance call of the form o.f(...) could not be resolved. Check if | 718 // An instance call of the form o.f(...) could not be resolved. Check if |
719 // there is a getter with the same name. If so, invoke it. If the value is | 719 // there is a getter with the same name. If so, invoke it. If the value is |
720 // a closure, invoke it with the given arguments. If the value is a | 720 // a closure, invoke it with the given arguments. If the value is a |
721 // non-closure, attempt to invoke "call" on it. | 721 // non-closure, attempt to invoke "call" on it. |
722 static bool ResolveCallThroughGetter(const Instance& receiver, | 722 static bool ResolveCallThroughGetter(const Instance& receiver, |
723 const Class& receiver_class, | 723 const Class& receiver_class, |
724 const String& target_name, | 724 const String& target_name, |
725 const Array& arguments_descriptor, | 725 const Array& arguments_descriptor, |
726 Function* result) { | 726 Function* result) { |
727 ASSERT(FLAG_lazy_dispatchers); | |
727 // 1. Check if there is a getter with the same name. | 728 // 1. Check if there is a getter with the same name. |
728 const String& getter_name = String::Handle(Field::GetterName(target_name)); | 729 const String& getter_name = String::Handle(Field::GetterName(target_name)); |
729 const int kNumArguments = 1; | 730 const int kNumArguments = 1; |
730 ArgumentsDescriptor args_desc( | 731 ArgumentsDescriptor args_desc( |
731 Array::Handle(ArgumentsDescriptor::New(kNumArguments))); | 732 Array::Handle(ArgumentsDescriptor::New(kNumArguments))); |
732 const Function& getter = Function::Handle( | 733 const Function& getter = Function::Handle( |
733 Resolver::ResolveDynamicForReceiverClass(receiver_class, | 734 Resolver::ResolveDynamicForReceiverClass(receiver_class, |
734 getter_name, | 735 getter_name, |
735 args_desc)); | 736 args_desc)); |
736 if (getter.IsNull() || getter.IsMethodExtractor()) { | 737 if (getter.IsNull() || getter.IsMethodExtractor()) { |
(...skipping 20 matching lines...) Expand all Loading... | |
757 } | 758 } |
758 *result = target_function.raw(); | 759 *result = target_function.raw(); |
759 return true; | 760 return true; |
760 } | 761 } |
761 | 762 |
762 | 763 |
763 // Handle other invocations (implicit closures, noSuchMethod). | 764 // Handle other invocations (implicit closures, noSuchMethod). |
764 RawFunction* InlineCacheMissHelper( | 765 RawFunction* InlineCacheMissHelper( |
765 const Instance& receiver, | 766 const Instance& receiver, |
766 const ICData& ic_data) { | 767 const ICData& ic_data) { |
768 if (!FLAG_lazy_dispatchers) { | |
769 return Function::null(); // We'll handle it in the runtime. | |
770 } | |
771 | |
767 const Array& args_descriptor = Array::Handle(ic_data.arguments_descriptor()); | 772 const Array& args_descriptor = Array::Handle(ic_data.arguments_descriptor()); |
768 | 773 |
769 const Class& receiver_class = Class::Handle(receiver.clazz()); | 774 const Class& receiver_class = Class::Handle(receiver.clazz()); |
770 const String& target_name = String::Handle(ic_data.target_name()); | 775 const String& target_name = String::Handle(ic_data.target_name()); |
771 | 776 |
772 Function& result = Function::Handle(); | 777 Function& result = Function::Handle(); |
773 if (!ResolveCallThroughGetter(receiver, | 778 if (!ResolveCallThroughGetter(receiver, |
774 receiver_class, | 779 receiver_class, |
775 target_name, | 780 target_name, |
776 args_descriptor, | 781 args_descriptor, |
777 &result)) { | 782 &result)) { |
778 if (!FLAG_lazy_dispatchers) { | |
779 return result.raw(); // Return null. | |
780 } | |
781 ArgumentsDescriptor desc(args_descriptor); | 783 ArgumentsDescriptor desc(args_descriptor); |
782 const Function& target_function = | 784 const Function& target_function = |
783 Function::Handle(receiver_class.GetInvocationDispatcher( | 785 Function::Handle(receiver_class.GetInvocationDispatcher( |
784 target_name, | 786 target_name, |
785 args_descriptor, | 787 args_descriptor, |
786 RawFunction::kNoSuchMethodDispatcher)); | 788 RawFunction::kNoSuchMethodDispatcher)); |
787 if (FLAG_trace_ic) { | 789 if (FLAG_trace_ic) { |
788 OS::PrintErr("NoSuchMethod IC miss: adding <%s> id:%" Pd " -> <%s>\n", | 790 OS::PrintErr("NoSuchMethod IC miss: adding <%s> id:%" Pd " -> <%s>\n", |
789 Class::Handle(receiver.clazz()).ToCString(), | 791 Class::Handle(receiver.clazz()).ToCString(), |
790 receiver.GetClassId(), | 792 receiver.GetClassId(), |
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1035 // Arg1: IC data | 1037 // Arg1: IC data |
1036 // Arg2: arguments descriptor array | 1038 // Arg2: arguments descriptor array |
1037 // Arg3: arguments array | 1039 // Arg3: arguments array |
1038 DEFINE_RUNTIME_ENTRY(InvokeNoSuchMethodDispatcher, 4) { | 1040 DEFINE_RUNTIME_ENTRY(InvokeNoSuchMethodDispatcher, 4) { |
1039 ASSERT(!FLAG_lazy_dispatchers); | 1041 ASSERT(!FLAG_lazy_dispatchers); |
1040 const Instance& receiver = Instance::CheckedHandle(arguments.ArgAt(0)); | 1042 const Instance& receiver = Instance::CheckedHandle(arguments.ArgAt(0)); |
1041 const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(1)); | 1043 const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(1)); |
1042 const Array& orig_arguments_desc = Array::CheckedHandle(arguments.ArgAt(2)); | 1044 const Array& orig_arguments_desc = Array::CheckedHandle(arguments.ArgAt(2)); |
1043 const Array& orig_arguments = Array::CheckedHandle(arguments.ArgAt(3)); | 1045 const Array& orig_arguments = Array::CheckedHandle(arguments.ArgAt(3)); |
1044 const String& target_name = String::Handle(ic_data.target_name()); | 1046 const String& target_name = String::Handle(ic_data.target_name()); |
1047 | |
1048 Class& cls = Class::Handle(receiver.clazz()); | |
1049 Function& function = Function::Handle(); | |
1050 | |
1051 // Ugh. Dart distinguishes getters and regular methods and allows their calls | |
1052 // to mix with conversions, and its selectors are independent of arity. So do | |
1053 // a zigzagged lookup to see if this call failed because of an arity mismatch, | |
1054 // need for conversion, or there really is no such method. | |
1055 | |
1056 const bool is_getter = Field::IsGetterName(target_name); | |
1057 if (is_getter) { | |
1058 // o.foo failed, closurize o.foo() if it exists | |
1059 const String& field_name = | |
1060 String::Handle(Field::NameFromGetter(target_name)); | |
1061 while (!cls.IsNull()) { | |
1062 function ^= cls.LookupDynamicFunction(field_name); | |
1063 if (!function.IsNull()) { | |
1064 const Function& closure_function = | |
1065 Function::Handle(function.ImplicitClosureFunction()); | |
1066 const Object& result = | |
1067 Object::Handle(closure_function.ImplicitInstanceClosure(receiver)); | |
1068 arguments.SetReturn(result); | |
1069 return; | |
1070 } | |
1071 cls = cls.SuperClass(); | |
1072 } | |
1073 } else { | |
1074 // o.foo(...) failed, invoke noSuchMethod is foo exists but has the wrong | |
1075 // number of arguments, or try (o.foo).call(...) | |
1076 | |
1077 if ((target_name.raw() == Symbols::Call().raw()) && receiver.IsClosure()) { | |
1078 // Special case: closures are implemented with a call getter instead of a | |
1079 // call method and with lazy dispatchers the field-invocation-dispatcher | |
1080 // would perform the closure call. | |
rmacnak
2015/06/19 17:02:49
In fact, every closure call goes through the runti
Florian Schneider
2015/06/29 10:37:53
Yes, that's a bit unfortunate. Let's discuss how t
rmacnak
2015/06/29 21:54:19
It may be enough to just emit the field-invocation
| |
1081 const Object& result = | |
1082 Object::Handle(DartEntry::InvokeClosure(orig_arguments, | |
1083 orig_arguments_desc)); | |
1084 CheckResultError(result); | |
1085 arguments.SetReturn(result); | |
1086 return; | |
1087 } | |
1088 | |
1089 const String& getter_name = String::Handle(Field::GetterName(target_name)); | |
1090 while (!cls.IsNull()) { | |
1091 function ^= cls.LookupDynamicFunction(target_name); | |
1092 if (!function.IsNull()) { | |
1093 ArgumentsDescriptor args_desc(orig_arguments_desc); | |
1094 ASSERT(!function.AreValidArguments(args_desc, NULL)); | |
1095 break; // mismatch, invoke noSuchMethod | |
1096 } | |
1097 function ^= cls.LookupDynamicFunction(getter_name); | |
1098 if (!function.IsNull()) { | |
1099 const Array& getter_arguments = Array::Handle(Array::New(1)); | |
1100 getter_arguments.SetAt(0, receiver); | |
1101 const Object& getter_result = | |
1102 Object::Handle(DartEntry::InvokeFunction(function, | |
1103 getter_arguments)); | |
1104 CheckResultError(getter_result); | |
1105 ASSERT(getter_result.IsNull() || getter_result.IsInstance()); | |
1106 | |
1107 orig_arguments.SetAt(0, getter_result); | |
1108 const Object& call_result = | |
1109 Object::Handle(DartEntry::InvokeClosure(orig_arguments, | |
1110 orig_arguments_desc)); | |
1111 CheckResultError(call_result); | |
1112 arguments.SetReturn(call_result); | |
1113 return; | |
1114 } | |
1115 cls = cls.SuperClass(); | |
1116 } | |
1117 } | |
1118 | |
1045 // Handle noSuchMethod invocation. | 1119 // Handle noSuchMethod invocation. |
1046 const Object& result = Object::Handle( | 1120 const Object& result = Object::Handle( |
1047 DartEntry::InvokeNoSuchMethod(receiver, | 1121 DartEntry::InvokeNoSuchMethod(receiver, |
1048 target_name, | 1122 target_name, |
1049 orig_arguments, | 1123 orig_arguments, |
1050 orig_arguments_desc)); | 1124 orig_arguments_desc)); |
1051 CheckResultError(result); | 1125 CheckResultError(result); |
1052 arguments.SetReturn(result); | 1126 arguments.SetReturn(result); |
1053 } | 1127 } |
1054 | 1128 |
(...skipping 661 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1716 const intptr_t elm_size = old_data.ElementSizeInBytes(); | 1790 const intptr_t elm_size = old_data.ElementSizeInBytes(); |
1717 const TypedData& new_data = | 1791 const TypedData& new_data = |
1718 TypedData::Handle(TypedData::New(cid, new_size, Heap::kOld)); | 1792 TypedData::Handle(TypedData::New(cid, new_size, Heap::kOld)); |
1719 TypedData::Copy(new_data, 0, old_data, 0, old_size * elm_size); | 1793 TypedData::Copy(new_data, 0, old_data, 0, old_size * elm_size); |
1720 typed_data_cell.SetAt(0, new_data); | 1794 typed_data_cell.SetAt(0, new_data); |
1721 arguments.SetReturn(new_data); | 1795 arguments.SetReturn(new_data); |
1722 } | 1796 } |
1723 | 1797 |
1724 | 1798 |
1725 } // namespace dart | 1799 } // namespace dart |
OLD | NEW |