Index: runtime/vm/code_generator.cc |
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc |
index a4359a75817fa6f3845247c33ff2e11460ab7bcf..dd977b239684252db484eb32a0e25e3a92e5da2d 100644 |
--- a/runtime/vm/code_generator.cc |
+++ b/runtime/vm/code_generator.cc |
@@ -724,6 +724,7 @@ static bool ResolveCallThroughGetter(const Instance& receiver, |
const String& target_name, |
const Array& arguments_descriptor, |
Function* result) { |
+ ASSERT(FLAG_lazy_dispatchers); |
// 1. Check if there is a getter with the same name. |
const String& getter_name = String::Handle(Field::GetterName(target_name)); |
const int kNumArguments = 1; |
@@ -764,6 +765,10 @@ static bool ResolveCallThroughGetter(const Instance& receiver, |
RawFunction* InlineCacheMissHelper( |
const Instance& receiver, |
const ICData& ic_data) { |
+ if (!FLAG_lazy_dispatchers) { |
+ return Function::null(); // We'll handle it in the runtime. |
+ } |
+ |
const Array& args_descriptor = Array::Handle(ic_data.arguments_descriptor()); |
const Class& receiver_class = Class::Handle(receiver.clazz()); |
@@ -775,9 +780,6 @@ RawFunction* InlineCacheMissHelper( |
target_name, |
args_descriptor, |
&result)) { |
- if (!FLAG_lazy_dispatchers) { |
- return result.raw(); // Return null. |
- } |
ArgumentsDescriptor desc(args_descriptor); |
const Function& target_function = |
Function::Handle(receiver_class.GetInvocationDispatcher( |
@@ -1042,6 +1044,78 @@ DEFINE_RUNTIME_ENTRY(InvokeNoSuchMethodDispatcher, 4) { |
const Array& orig_arguments_desc = Array::CheckedHandle(arguments.ArgAt(2)); |
const Array& orig_arguments = Array::CheckedHandle(arguments.ArgAt(3)); |
const String& target_name = String::Handle(ic_data.target_name()); |
+ |
+ Class& cls = Class::Handle(receiver.clazz()); |
+ Function& function = Function::Handle(); |
+ |
+ // Dart distinguishes getters and regular methods and allows their calls |
+ // to mix with conversions, and its selectors are independent of arity. So do |
+ // a zigzagged lookup to see if this call failed because of an arity mismatch, |
+ // need for conversion, or there really is no such method. |
+ |
+ const bool is_getter = Field::IsGetterName(target_name); |
+ if (is_getter) { |
+ // o.foo failed, closurize o.foo() if it exists |
+ const String& field_name = |
+ String::Handle(Field::NameFromGetter(target_name)); |
+ while (!cls.IsNull()) { |
+ function ^= cls.LookupDynamicFunction(field_name); |
+ if (!function.IsNull()) { |
+ const Function& closure_function = |
+ Function::Handle(function.ImplicitClosureFunction()); |
+ const Object& result = |
+ Object::Handle(closure_function.ImplicitInstanceClosure(receiver)); |
+ arguments.SetReturn(result); |
+ return; |
+ } |
+ cls = cls.SuperClass(); |
+ } |
+ } else { |
+ // o.foo(...) failed, invoke noSuchMethod is foo exists but has the wrong |
+ // number of arguments, or try (o.foo).call(...) |
+ |
+ if ((target_name.raw() == Symbols::Call().raw()) && receiver.IsClosure()) { |
+ // Special case: closures are implemented with a call getter instead of a |
+ // call method and with lazy dispatchers the field-invocation-dispatcher |
+ // would perform the closure call. |
+ const Object& result = |
+ Object::Handle(DartEntry::InvokeClosure(orig_arguments, |
+ orig_arguments_desc)); |
+ CheckResultError(result); |
+ arguments.SetReturn(result); |
+ return; |
+ } |
+ |
+ const String& getter_name = String::Handle(Field::GetterName(target_name)); |
+ while (!cls.IsNull()) { |
+ function ^= cls.LookupDynamicFunction(target_name); |
+ if (!function.IsNull()) { |
+ ArgumentsDescriptor args_desc(orig_arguments_desc); |
+ ASSERT(!function.AreValidArguments(args_desc, NULL)); |
+ break; // mismatch, invoke noSuchMethod |
+ } |
+ function ^= cls.LookupDynamicFunction(getter_name); |
+ if (!function.IsNull()) { |
+ const Array& getter_arguments = Array::Handle(Array::New(1)); |
+ getter_arguments.SetAt(0, receiver); |
+ const Object& getter_result = |
+ Object::Handle(DartEntry::InvokeFunction(function, |
+ getter_arguments)); |
+ CheckResultError(getter_result); |
+ ASSERT(getter_result.IsNull() || getter_result.IsInstance()); |
+ |
+ orig_arguments.SetAt(0, getter_result); |
+ const Object& call_result = |
+ Object::Handle(DartEntry::InvokeClosure(orig_arguments, |
+ orig_arguments_desc)); |
+ CheckResultError(call_result); |
+ arguments.SetReturn(call_result); |
+ return; |
+ } |
+ cls = cls.SuperClass(); |
+ } |
+ } |
+ |
// Handle noSuchMethod invocation. |
const Object& result = Object::Handle( |
DartEntry::InvokeNoSuchMethod(receiver, |