Index: runtime/vm/code_generator.cc |
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc |
index 6c1dc9b0027c0859f59f404edca8abae8c8eab78..5df3636a446cf0ec3eef3693d1676ec78a5bcd7f 100644 |
--- a/runtime/vm/code_generator.cc |
+++ b/runtime/vm/code_generator.cc |
@@ -1054,23 +1054,72 @@ DEFINE_RUNTIME_ENTRY(InvokeNoSuchMethodDispatcher, 4) { |
// a zigzagged lookup to see if this call failed because of an arity mismatch, |
// need for conversion, or there really is no such method. |
+#define NO_SUCH_METHOD() \ |
+ const Object& result = Object::Handle( \ |
+ DartEntry::InvokeNoSuchMethod(receiver, \ |
+ target_name, \ |
+ orig_arguments, \ |
+ orig_arguments_desc)); \ |
+ CheckResultError(result); \ |
+ arguments.SetReturn(result); \ |
+ |
+#define CLOSURIZE(some_function) \ |
+ const Function& closure_function = \ |
+ Function::Handle(some_function.ImplicitClosureFunction()); \ |
+ const Object& result = \ |
+ Object::Handle(closure_function.ImplicitInstanceClosure(receiver)); \ |
+ arguments.SetReturn(result); \ |
+ |
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)); |
+ // o.foo (o.get:foo) failed, closurize o.foo() if it exists. Or, |
+ // o#foo (o.get:#foo) failed, closurizee o.foo or o.foo(), whichever is |
+ // encountered first on the inheritance chain. Or, |
+ // o#foo= (o.get:#set:foo) failed, closurize o.foo= if it exists. |
+ String& field_name = |
+ String::Handle(Field::NameFromGetter(target_name)); |
+ |
+ const bool is_extractor = field_name.CharAt(0) == '#'; |
+ if (is_extractor) { |
+ field_name = String::SubString(field_name, 1); |
+ ASSERT(!Field::IsGetterName(field_name)); |
+ field_name = Symbols::New(field_name); |
+ |
+ if (!Field::IsSetterName(field_name)) { |
+ const String& getter_name = |
+ String::Handle(Field::GetterName(field_name)); |
+ |
+ // Zigzagged lookup: closure either a regular method or a getter. |
+ while (!cls.IsNull()) { |
+ function ^= cls.LookupDynamicFunction(field_name); |
+ if (!function.IsNull()) { |
+ CLOSURIZE(function); |
+ return; |
+ } |
+ function ^= cls.LookupDynamicFunction(getter_name); |
+ if (!function.IsNull()) { |
+ CLOSURIZE(function); |
+ return; |
+ } |
+ cls = cls.SuperClass(); |
+ } |
+ NO_SUCH_METHOD(); |
+ return; |
+ } else { |
+ // Fall through for non-ziggaged lookup for o#foo=. |
+ } |
+ } |
+ |
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); |
+ CLOSURIZE(function); |
return; |
} |
cls = cls.SuperClass(); |
} |
+ |
+ // Fall through for noSuchMethod |
} else { |
// o.foo(...) failed, invoke noSuchMethod is foo exists but has the wrong |
// number of arguments, or try (o.foo).call(...) |
@@ -1117,14 +1166,10 @@ DEFINE_RUNTIME_ENTRY(InvokeNoSuchMethodDispatcher, 4) { |
} |
} |
- // Handle noSuchMethod invocation. |
- const Object& result = Object::Handle( |
- DartEntry::InvokeNoSuchMethod(receiver, |
- target_name, |
- orig_arguments, |
- orig_arguments_desc)); |
- CheckResultError(result); |
- arguments.SetReturn(result); |
+ NO_SUCH_METHOD(); |
+ |
+#undef NO_SUCH_METHOD |
+#undef CLOSURIZE |
} |