| Index: vm/code_generator.cc
 | 
| ===================================================================
 | 
| --- vm/code_generator.cc	(revision 700)
 | 
| +++ vm/code_generator.cc	(working copy)
 | 
| @@ -7,10 +7,10 @@
 | 
|  #include "vm/code_index_table.h"
 | 
|  #include "vm/code_patcher.h"
 | 
|  #include "vm/compiler.h"
 | 
| +#include "vm/dart_api_impl.h"
 | 
|  #include "vm/dart_entry.h"
 | 
|  #include "vm/exceptions.h"
 | 
|  #include "vm/ic_data.h"
 | 
| -#include "vm/ic_stubs.h"
 | 
|  #include "vm/object_store.h"
 | 
|  #include "vm/resolver.h"
 | 
|  #include "vm/runtime_entry.h"
 | 
| @@ -421,6 +421,7 @@
 | 
|  //   Returns: RawCode object or NULL (method not found or not compileable).
 | 
|  // This is called by the megamorphic stub when instance call does not need to be
 | 
|  // patched.
 | 
| +// Used by megamorphic lookup/no-such-method-handling.
 | 
|  DEFINE_RUNTIME_ENTRY(ResolveCompileInstanceFunction, 1) {
 | 
|    ASSERT(arguments.Count() ==
 | 
|           kResolveCompileInstanceFunctionRuntimeEntry.argument_count());
 | 
| @@ -430,100 +431,56 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| -// Resolve instance call and patch it to jump to IC stub or megamorphic stub.
 | 
| -// After patching the caller's instance call instruction, that call will
 | 
| -// be reexecuted and ran through the created IC stub. The null receivers
 | 
| -// have special handling, i.e., they lead to megamorphic lookup that implements
 | 
| -// the appropriate null behavior.
 | 
| -//   Arg0: receiver object.
 | 
| -DEFINE_RUNTIME_ENTRY(ResolvePatchInstanceCall, 1) {
 | 
| +// Handles inline cache misses by updating the IC data array of the call
 | 
| +// site.
 | 
| +//   Arg0: Receiver object.
 | 
| +//   Returns: target function with compiled code or 0.
 | 
| +// Modifies the instance call to hold the updated IC data array.
 | 
| +DEFINE_RUNTIME_ENTRY(InlineCacheMissHandler, 1) {
 | 
|    ASSERT(arguments.Count() ==
 | 
| -         kResolvePatchInstanceCallRuntimeEntry.argument_count());
 | 
| +      kInlineCacheMissHandlerRuntimeEntry.argument_count());
 | 
|    const Instance& receiver = Instance::CheckedHandle(arguments.At(0));
 | 
| -  const Code& code = Code::Handle(ResolveCompileInstanceCallTarget(receiver));
 | 
| -  DartFrameIterator iterator;
 | 
| -  DartFrame* caller_frame = iterator.NextFrame();
 | 
| -  String& function_name = String::Handle();
 | 
| -  if ((!receiver.IsNull() && code.IsNull()) || !FLAG_inline_cache) {
 | 
| -    // We did not find a method; it means either that we need to invoke
 | 
| -    // noSuchMethod or that we have encountered a situation with implicit
 | 
| -    // closures. All these cases are handled by the megamorphic lookup stub.
 | 
| -    CodePatcher::PatchInstanceCallAt(
 | 
| -        caller_frame->pc(), StubCode::MegamorphicLookupEntryPoint());
 | 
| +  const Code& target_code =
 | 
| +      Code::Handle(ResolveCompileInstanceCallTarget(receiver));
 | 
| +  if (target_code.IsNull()) {
 | 
| +    // Let the megamorphic stub handle special cases: NoSuchMethod,
 | 
| +    // closure calls.
 | 
|      if (FLAG_trace_ic) {
 | 
| -      OS::Print("IC: cannot find function at 0x%x -> megamorphic lookup.\n",
 | 
| -          caller_frame->pc());
 | 
| +      OS::Print("InlineCacheMissHandler NULL code for receiver: %s\n",
 | 
| +          receiver.ToCString());
 | 
|      }
 | 
| -    if (FLAG_trace_patching) {
 | 
| -      OS::Print("ResolvePatchInstanceCall: patching 0x%x to megamorphic\n",
 | 
| -          caller_frame->pc());
 | 
| -    }
 | 
| -  } else {
 | 
| -    int num_arguments = -1;
 | 
| -    int num_named_arguments = -1;
 | 
| -    uword caller_target = 0;
 | 
| -    CodePatcher::GetInstanceCallAt(caller_frame->pc(),
 | 
| -                                   &function_name,
 | 
| -                                   &num_arguments,
 | 
| -                                   &num_named_arguments,
 | 
| -                                   &caller_target);
 | 
| -    // If caller_target is not in CallInstanceFunction stub (resolve call)
 | 
| -    // then it must be pointing to an IC stub.
 | 
| -    const Class& receiver_class = Class::ZoneHandle(receiver.clazz());
 | 
| -    const bool ic_miss =
 | 
| -        !StubCode::InCallInstanceFunctionStubCode(caller_target);
 | 
| -    GrowableArray<const Class*> classes;
 | 
| -    GrowableArray<const Function*> targets;
 | 
| -    if (ic_miss) {
 | 
| -      bool is_ic =
 | 
| -          ICStubs::RecognizeICStub(caller_target, &classes, &targets);
 | 
| -      ASSERT(is_ic);
 | 
| -      ASSERT(classes.length() == targets.length());
 | 
| -      // The returned classes array can be empty if the first patch occured
 | 
| -      // with a null class. 'receiver_class' should not exists.
 | 
| -      ASSERT(ICStubs::IndexOfClass(classes, receiver_class) < 0);
 | 
| -      ASSERT(!code.IsNull());
 | 
| -      ASSERT(!receiver_class.IsNullClass());
 | 
| -      const Function& function = Function::ZoneHandle(code.function());
 | 
| -      targets.Add(&function);
 | 
| -      classes.Add(&receiver_class);
 | 
| -    } else {
 | 
| -      // First patch of instance call.
 | 
| -      // Do not add classes for null receiver. For first IC patch it means that
 | 
| -      // the IC will always miss and jump to megamorphic lookup (null handling).
 | 
| -      if (!receiver_class.IsNullClass()) {
 | 
| -        ASSERT(!code.IsNull());
 | 
| -        const Function& function = Function::ZoneHandle(code.function());
 | 
| -        targets.Add(&function);
 | 
| -        classes.Add(&receiver_class);
 | 
| -      }
 | 
| -    }
 | 
| -    const Code& ic_code = Code::Handle(ICStubs::GetICStub(classes, targets));
 | 
| +    arguments.SetReturn(target_code);
 | 
| +    return;
 | 
| +  }
 | 
| +  const Function& target_function =
 | 
| +      Function::Handle(target_code.function());
 | 
| +  ASSERT(!target_function.IsNull());
 | 
| +  if (receiver.IsNull()) {
 | 
| +    // Null dispatch is slow (e.g., (null).toCString()). The only
 | 
| +    // fast execution with null receiver is the "==" operator.
 | 
| +    // Special handling so that we do not pollute the inline cache with null
 | 
| +    // classes.
 | 
| +    arguments.SetReturn(target_function);
 | 
|      if (FLAG_trace_ic) {
 | 
| -      CodeIndexTable* ci_table = Isolate::Current()->code_index_table();
 | 
| -      ASSERT(ci_table != NULL);
 | 
| -      const Function& caller =
 | 
| -          Function::Handle(ci_table->LookupFunction(caller_frame->pc()));
 | 
| -      const char* patch_kind = ic_miss ? "miss" : "patch";
 | 
| -      OS::Print("IC %s at 0x%x '%s' (receiver:'%s' function:'%s')",
 | 
| -          patch_kind,
 | 
| -          caller_frame->pc(),
 | 
| -          String::Handle(caller.name()).ToCString(),
 | 
| -          receiver.ToCString(),
 | 
| -          function_name.ToCString());
 | 
| -      OS::Print(" patched to 0x%x\n", ic_code.EntryPoint());
 | 
| -      if (ic_miss) {
 | 
| -        for (int i = 0; i < classes.length(); i++) {
 | 
| -          OS::Print("  IC Miss on %s\n", classes[i]->ToCString());
 | 
| -        }
 | 
| -      }
 | 
| +      OS::Print("InlineCacheMissHandler Null receiver target %s\n",
 | 
| +          target_function.ToCString());
 | 
|      }
 | 
| -    CodePatcher::PatchInstanceCallAt(caller_frame->pc(), ic_code.EntryPoint());
 | 
| -    if (FLAG_trace_patching) {
 | 
| -      OS::Print("ResolvePatchInstanceCall: patching 0x%x to ic 0x%x\n",
 | 
| -          caller_frame->pc(), ic_code.EntryPoint());
 | 
| -    }
 | 
| +    return;
 | 
|    }
 | 
| +  DartFrameIterator iterator;
 | 
| +  DartFrame* caller_frame = iterator.NextFrame();
 | 
| +  ICData ic_data(Array::Handle(
 | 
| +      CodePatcher::GetInstanceCallIcDataAt(caller_frame->pc())));
 | 
| +  GrowableArray<const Class*> classes;
 | 
| +  classes.Add(&Class::ZoneHandle(receiver.clazz()));
 | 
| +  ic_data.AddCheck(classes, target_function);
 | 
| +  CodePatcher::SetInstanceCallIcDataAt(caller_frame->pc(),
 | 
| +                                       Array::ZoneHandle(ic_data.data()));
 | 
| +  arguments.SetReturn(target_function);
 | 
| +  if (FLAG_trace_ic) {
 | 
| +    OS::Print("InlineCacheMissHandler 0x%x adding receiver '%s' -> '%s'\n",
 | 
| +        caller_frame->pc(), receiver.ToCString(), target_function.ToCString());
 | 
| +  }
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -797,32 +754,6 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| -static void DisableOldCode(const Function& function,
 | 
| -                           const Code& old_code,
 | 
| -                           const Code& new_code) {
 | 
| -  const Array& class_ic_stubs = Array::Handle(old_code.class_ic_stubs());
 | 
| -  if (function.IsClosureFunction()) {
 | 
| -    // Nothing to do, code may not have inline caches.
 | 
| -    ASSERT(class_ic_stubs.Length() == 0);
 | 
| -    return;
 | 
| -  }
 | 
| -  if (function.is_static() || function.IsConstructor()) {
 | 
| -    ASSERT(class_ic_stubs.Length() == 0);
 | 
| -    return;
 | 
| -  }
 | 
| -  Code& ic_stub = Code::Handle();
 | 
| -  for (int i = 0; i < class_ic_stubs.Length(); i += 2) {
 | 
| -    // i: array of classes, i + 1: ic stub code.
 | 
| -    ic_stub ^= class_ic_stubs.At(i + 1);
 | 
| -    ICStubs::PatchTargets(ic_stub.EntryPoint(),
 | 
| -                          old_code.EntryPoint(),
 | 
| -                          new_code.EntryPoint());
 | 
| -  }
 | 
| -  new_code.set_class_ic_stubs(class_ic_stubs);
 | 
| -  old_code.set_class_ic_stubs(Array::Handle(Array::Empty()));
 | 
| -}
 | 
| -
 | 
| -
 | 
|  // Only unoptimized code has invocation counter threshold checking.
 | 
|  // Once the invocation counter threshold is reached any entry into the
 | 
|  // unoptimized code is redirected to this function.
 | 
| @@ -838,7 +769,6 @@
 | 
|      const Code& optimized_code = Code::Handle(function.code());
 | 
|      ASSERT(!optimized_code.IsNull());
 | 
|      ASSERT(!unoptimized_code.IsNull());
 | 
| -    DisableOldCode(function, unoptimized_code, optimized_code);
 | 
|    } else {
 | 
|      // TODO(5442338): Abort as this should not happen.
 | 
|      function.set_invocation_counter(0);
 | 
| @@ -930,8 +860,6 @@
 | 
|      // Get unoptimized code. Compilation restores (reenables) the entry of
 | 
|      // unoptimized code.
 | 
|      Compiler::CompileFunction(function);
 | 
| -
 | 
| -    DisableOldCode(function, optimized_code, unoptimized_code);
 | 
|    }
 | 
|    // TODO(srdjan): Handle better complex cases, e.g. when an older optimized
 | 
|    // code is alive on frame and gets deoptimized after the function was
 | 
| 
 |