| Index: runtime/vm/code_generator.cc
|
| ===================================================================
|
| --- runtime/vm/code_generator.cc (revision 34771)
|
| +++ runtime/vm/code_generator.cc (working copy)
|
| @@ -621,34 +621,6 @@
|
| }
|
|
|
|
|
| -// Resolves and compiles the target function of an instance call, updates
|
| -// function cache of the receiver's class and returns the compiled code or null.
|
| -// Only the number of named arguments is checked, but not the actual names.
|
| -RawCode* ResolveCompileInstanceCallTarget(const Instance& receiver,
|
| - const ICData& ic_data) {
|
| - ArgumentsDescriptor
|
| - arguments_descriptor(Array::Handle(ic_data.arguments_descriptor()));
|
| - String& function_name = String::Handle(ic_data.target_name());
|
| - ASSERT(function_name.IsSymbol());
|
| -
|
| - Function& function = Function::Handle();
|
| - function = Resolver::ResolveDynamic(receiver,
|
| - function_name,
|
| - arguments_descriptor);
|
| - if (function.IsNull()) {
|
| - return Code::null();
|
| - } else {
|
| - if (!function.HasCode()) {
|
| - const Error& error = Error::Handle(Compiler::CompileFunction(function));
|
| - if (!error.IsNull()) {
|
| - Exceptions::PropagateError(error);
|
| - }
|
| - }
|
| - return function.CurrentCode();
|
| - }
|
| -}
|
| -
|
| -
|
| // Result of an invoke may be an unhandled exception, in which case we
|
| // rethrow it.
|
| static void CheckResultError(const Object& result) {
|
| @@ -679,24 +651,98 @@
|
| }
|
|
|
|
|
| +// An instance call of the form o.f(...) could not be resolved. Check if
|
| +// there is a getter with the same name. If so, invoke it. If the value is
|
| +// a closure, invoke it with the given arguments. If the value is a
|
| +// non-closure, attempt to invoke "call" on it.
|
| +static bool ResolveCallThroughGetter(const Instance& receiver,
|
| + const Class& receiver_class,
|
| + const String& target_name,
|
| + const Array& arguments_descriptor,
|
| + const ICData& ic_data,
|
| + Function* result) {
|
| + // 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;
|
| + ArgumentsDescriptor args_desc(
|
| + Array::Handle(ArgumentsDescriptor::New(kNumArguments)));
|
| + const Function& getter = Function::Handle(
|
| + Resolver::ResolveDynamicForReceiverClass(receiver_class,
|
| + getter_name,
|
| + args_desc));
|
| + if (getter.IsNull() || getter.IsMethodExtractor()) {
|
| + return false;
|
| + }
|
| +
|
| + const Function& target_function =
|
| + Function::Handle(receiver_class.GetInvocationDispatcher(
|
| + target_name,
|
| + arguments_descriptor,
|
| + RawFunction::kInvokeFieldDispatcher));
|
| + ASSERT(!target_function.IsNull());
|
| + if (FLAG_trace_ic) {
|
| + OS::PrintErr("InvokeField IC miss: adding <%s> id:%" Pd " -> <%s>\n",
|
| + Class::Handle(receiver.clazz()).ToCString(),
|
| + receiver.GetClassId(),
|
| + target_function.ToCString());
|
| + }
|
| + *result = target_function.raw();
|
| + return true;
|
| +}
|
| +
|
| +
|
| +// Handle other invocations (implicit closures, noSuchMethod).
|
| +RawFunction* InlineCacheMissHelper(
|
| + const Instance& receiver,
|
| + const ICData& ic_data) {
|
| + const Array& args_descriptor = Array::Handle(ic_data.arguments_descriptor());
|
| +
|
| + const Class& receiver_class = Class::Handle(receiver.clazz());
|
| + const String& target_name = String::Handle(ic_data.target_name());
|
| +
|
| + Function& result = Function::Handle();
|
| + if (!ResolveCallThroughGetter(receiver,
|
| + receiver_class,
|
| + target_name,
|
| + args_descriptor,
|
| + ic_data,
|
| + &result)) {
|
| + ArgumentsDescriptor desc(args_descriptor);
|
| + const Function& target_function =
|
| + Function::Handle(receiver_class.GetInvocationDispatcher(
|
| + target_name,
|
| + args_descriptor,
|
| + RawFunction::kNoSuchMethodDispatcher));
|
| + if (FLAG_trace_ic) {
|
| + OS::PrintErr("NoSuchMethod IC miss: adding <%s> id:%" Pd " -> <%s>\n",
|
| + Class::Handle(receiver.clazz()).ToCString(),
|
| + receiver.GetClassId(),
|
| + target_function.ToCString());
|
| + }
|
| + result = target_function.raw();
|
| + }
|
| + return result.raw();
|
| +}
|
| +
|
| static RawFunction* InlineCacheMissHandler(
|
| const GrowableArray<const Instance*>& args,
|
| const ICData& ic_data) {
|
| const Instance& receiver = *args[0];
|
| - const Code& target_code =
|
| - Code::Handle(ResolveCompileInstanceCallTarget(receiver, ic_data));
|
| - if (target_code.IsNull()) {
|
| - // Let the megamorphic stub handle special cases: NoSuchMethod,
|
| - // closure calls.
|
| + ArgumentsDescriptor
|
| + arguments_descriptor(Array::Handle(ic_data.arguments_descriptor()));
|
| + String& function_name = String::Handle(ic_data.target_name());
|
| + ASSERT(function_name.IsSymbol());
|
| + Function& target_function = Function::Handle(
|
| + Resolver::ResolveDynamic(receiver, function_name, arguments_descriptor));
|
| + if (target_function.IsNull()) {
|
| if (FLAG_trace_ic) {
|
| - OS::PrintErr("InlineCacheMissHandler NULL code for %s receiver: %s\n",
|
| + OS::PrintErr("InlineCacheMissHandler NULL function for %s receiver: %s\n",
|
| String::Handle(ic_data.target_name()).ToCString(),
|
| receiver.ToCString());
|
| }
|
| - return Function::null();
|
| + ic_data.set_is_closure_call(true);
|
| + target_function = InlineCacheMissHelper(receiver, ic_data);
|
| }
|
| - const Function& target_function =
|
| - Function::Handle(target_code.function());
|
| ASSERT(!target_function.IsNull());
|
| if (args.length() == 1) {
|
| ic_data.AddReceiverCheck(args[0]->GetClassId(), target_function);
|
| @@ -834,9 +880,7 @@
|
| // Arg1: ICData object.
|
| // Arg2: Arguments descriptor array.
|
|
|
| -// Returns: target instructions to call or null if the
|
| -// InstanceFunctionLookup stub should be used (e.g., to invoke no such
|
| -// method and implicit closures)..
|
| +// Returns: target function to call.
|
| DEFINE_RUNTIME_ENTRY(MegamorphicCacheMissHandler, 3) {
|
| const Instance& receiver = Instance::CheckedHandle(arguments.ArgAt(0));
|
| const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(1));
|
| @@ -852,62 +896,24 @@
|
| }
|
|
|
| ArgumentsDescriptor args_desc(descriptor);
|
| - const Function& target = Function::Handle(
|
| + Function& target_function = Function::Handle(
|
| Resolver::ResolveDynamicForReceiverClass(cls,
|
| name,
|
| args_desc));
|
| -
|
| - Instructions& instructions = Instructions::Handle();
|
| - if (!target.IsNull()) {
|
| - if (!target.HasCode()) {
|
| - const Error& error = Error::Handle(Compiler::CompileFunction(target));
|
| - if (!error.IsNull()) {
|
| - Exceptions::PropagateError(error);
|
| - }
|
| - }
|
| - ASSERT(target.HasCode());
|
| - instructions = Code::Handle(target.CurrentCode()).instructions();
|
| + if (target_function.IsNull()) {
|
| + ic_data.set_is_closure_call(true);
|
| + target_function = InlineCacheMissHelper(receiver, ic_data);
|
| }
|
| - arguments.SetReturn(instructions);
|
| - if (instructions.IsNull()) return;
|
|
|
| + ASSERT(!target_function.IsNull());
|
| + // Insert function found into cache and return it.
|
| cache.EnsureCapacity();
|
| const Smi& class_id = Smi::Handle(Smi::New(cls.id()));
|
| - cache.Insert(class_id, target);
|
| - return;
|
| + cache.Insert(class_id, target_function);
|
| + arguments.SetReturn(target_function);
|
| }
|
|
|
|
|
| -// Updates IC data for two arguments. Used by the equality operation when
|
| -// the control flow bypasses regular inline cache (null arguments).
|
| -// Arg0: Receiver object.
|
| -// Arg1: Argument after receiver.
|
| -// Arg2: Target's name.
|
| -// Arg3: ICData.
|
| -DEFINE_RUNTIME_ENTRY(UpdateICDataTwoArgs, 4) {
|
| - const Instance& receiver = Instance::CheckedHandle(arguments.ArgAt(0));
|
| - const Instance& arg1 = Instance::CheckedHandle(arguments.ArgAt(1));
|
| - const String& target_name = String::CheckedHandle(arguments.ArgAt(2));
|
| - const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(3));
|
| - GrowableArray<const Instance*> args(2);
|
| - args.Add(&receiver);
|
| - args.Add(&arg1);
|
| - const intptr_t kNumArguments = 2;
|
| - ArgumentsDescriptor args_desc(
|
| - Array::Handle(ArgumentsDescriptor::New(kNumArguments)));
|
| - const Function& target_function = Function::Handle(
|
| - Resolver::ResolveDynamic(receiver,
|
| - target_name,
|
| - args_desc));
|
| - ASSERT(!target_function.IsNull());
|
| - GrowableArray<intptr_t> class_ids(kNumArguments);
|
| - ASSERT(ic_data.num_args_tested() == kNumArguments);
|
| - class_ids.Add(receiver.GetClassId());
|
| - class_ids.Add(arg1.GetClassId());
|
| - ic_data.AddCheck(class_ids, target_function);
|
| -}
|
| -
|
| -
|
| // Invoke appropriate noSuchMethod function.
|
| // Arg0: receiver.
|
| // Arg1: ic-data.
|
| @@ -952,126 +958,6 @@
|
| }
|
|
|
|
|
| -// An instance call of the form o.f(...) could not be resolved. Check if
|
| -// there is a getter with the same name. If so, invoke it. If the value is
|
| -// a closure, invoke it with the given arguments. If the value is a
|
| -// non-closure, attempt to invoke "call" on it.
|
| -static bool ResolveCallThroughGetter(const Instance& receiver,
|
| - const Class& receiver_class,
|
| - const String& target_name,
|
| - const Array& arguments_descriptor,
|
| - const Array& arguments,
|
| - const ICData& ic_data,
|
| - Object* result) {
|
| - // 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;
|
| - ArgumentsDescriptor args_desc(
|
| - Array::Handle(ArgumentsDescriptor::New(kNumArguments)));
|
| - const Function& getter = Function::Handle(
|
| - Resolver::ResolveDynamicForReceiverClass(receiver_class,
|
| - getter_name,
|
| - args_desc));
|
| - if (getter.IsNull() || getter.IsMethodExtractor()) {
|
| - return false;
|
| - }
|
| -
|
| - const Function& target_function =
|
| - Function::Handle(receiver_class.GetInvocationDispatcher(
|
| - target_name,
|
| - arguments_descriptor,
|
| - RawFunction::kInvokeFieldDispatcher));
|
| - // Update IC data.
|
| - ASSERT(!target_function.IsNull());
|
| - ic_data.AddReceiverCheck(receiver.GetClassId(), target_function);
|
| - if (FLAG_trace_ic) {
|
| - OS::PrintErr("InvokeField IC miss: adding <%s> id:%" Pd " -> <%s>\n",
|
| - Class::Handle(receiver.clazz()).ToCString(),
|
| - receiver.GetClassId(),
|
| - target_function.ToCString());
|
| - }
|
| - *result = DartEntry::InvokeFunction(target_function,
|
| - arguments,
|
| - arguments_descriptor);
|
| - CheckResultError(*result);
|
| - return true;
|
| -}
|
| -
|
| -
|
| -// The IC miss handler has failed to find a (cacheable) instance function to
|
| -// invoke. Handle three possibilities:
|
| -//
|
| -// 1. If the call was a getter o.f, there may be an instance function with
|
| -// the same name. If so, create an implicit closure and return it.
|
| -//
|
| -// 2. If the call was an instance call o.f(...), there may be a getter with
|
| -// the same name. If so, invoke it. If the value is a closure, invoke
|
| -// it with the given arguments. If the value is a non-closure, attempt
|
| -// to invoke "call" on it.
|
| -//
|
| -// 3. There is no such method.
|
| -DEFINE_RUNTIME_ENTRY(InstanceFunctionLookup, 4) {
|
| - const Instance& receiver = Instance::CheckedHandle(arguments.ArgAt(0));
|
| - const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(1));
|
| - const Array& args_descriptor = Array::CheckedHandle(arguments.ArgAt(2));
|
| - const Array& args = Array::CheckedHandle(arguments.ArgAt(3));
|
| -
|
| - const Class& receiver_class = Class::Handle(receiver.clazz());
|
| - const String& target_name = String::Handle(ic_data.target_name());
|
| -
|
| - Object& result = Object::Handle();
|
| - if (!ResolveCallThroughGetter(receiver,
|
| - receiver_class,
|
| - target_name,
|
| - args_descriptor,
|
| - args,
|
| - ic_data,
|
| - &result)) {
|
| - ArgumentsDescriptor desc(args_descriptor);
|
| - const Function& target_function =
|
| - Function::Handle(receiver_class.GetInvocationDispatcher(
|
| - target_name,
|
| - args_descriptor,
|
| - RawFunction::kNoSuchMethodDispatcher));
|
| - // Update IC data.
|
| - ASSERT(!target_function.IsNull());
|
| - intptr_t receiver_cid = receiver.GetClassId();
|
| - if (ic_data.num_args_tested() == 1) {
|
| - // In optimized code we may enter into here via the
|
| - // MegamorphicCacheMissHandler since noSuchMethod dispatchers are not
|
| - // inserted into the megamorphic cache. Therefore, we need to guard
|
| - // against entering the same check twice into the ICData.
|
| - // Note that num_args_tested == 1 in optimized code.
|
| - // TODO(fschneider): Handle extraordinary cases like noSuchMethod and
|
| - // implicit closure invocation properly in the megamorphic cache.
|
| - const Function& target =
|
| - Function::Handle(ic_data.GetTargetForReceiverClassId(receiver_cid));
|
| - if (target.IsNull()) {
|
| - ic_data.AddReceiverCheck(receiver_cid, target_function);
|
| - }
|
| - } else {
|
| - // Operators calls have two or three arguments tested ([], []=, etc.)
|
| - ASSERT(ic_data.num_args_tested() > 1);
|
| - GrowableArray<intptr_t> class_ids(ic_data.num_args_tested());
|
| - class_ids.Add(receiver_cid);
|
| - for (intptr_t i = 1; i < ic_data.num_args_tested(); ++i) {
|
| - class_ids.Add(Object::Handle(args.At(i)).GetClassId());
|
| - }
|
| - ic_data.AddCheck(class_ids, target_function);
|
| - }
|
| - if (FLAG_trace_ic) {
|
| - OS::PrintErr("NoSuchMethod IC miss: adding <%s> id:%" Pd " -> <%s>\n",
|
| - Class::Handle(receiver.clazz()).ToCString(),
|
| - receiver_cid,
|
| - target_function.ToCString());
|
| - }
|
| - result = DartEntry::InvokeFunction(target_function, args, args_descriptor);
|
| - }
|
| - CheckResultError(result);
|
| - arguments.SetReturn(result);
|
| -}
|
| -
|
| -
|
| static bool CanOptimizeFunction(const Function& function, Isolate* isolate) {
|
| const intptr_t kLowInvocationCount = -100000000;
|
| if (isolate->debugger()->IsStepping() ||
|
|
|