Cache IC handlers on the prototype's map if possible
authorjkummerow@chromium.org <jkummerow@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 18 Jul 2014 13:50:21 +0000 (13:50 +0000)
committerjkummerow@chromium.org <jkummerow@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 18 Jul 2014 13:50:21 +0000 (13:50 +0000)
instead of on the receiver's map. Lazily overwrite cached handler if it is
identical to the handler that just missed.

R=verwaest@chromium.org

Review URL: https://codereview.chromium.org/400523007

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22483 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

20 files changed:
src/arm/ic-arm.cc
src/arm/stub-cache-arm.cc
src/arm64/ic-arm64.cc
src/arm64/stub-cache-arm64.cc
src/globals.h
src/hydrogen.cc
src/hydrogen.h
src/ia32/ic-ia32.cc
src/ia32/stub-cache-ia32.cc
src/ic-inl.h
src/ic.cc
src/ic.h
src/objects-inl.h
src/objects.cc
src/objects.h
src/property.h
src/stub-cache.cc
src/stub-cache.h
src/x64/ic-x64.cc
src/x64/stub-cache-x64.cc

index 5db538d..17c815e 100644 (file)
@@ -276,7 +276,8 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
   ASSERT(name.is(r2));
 
   // Probe the stub cache.
-  Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC);
+  Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::LOAD_IC));
   masm->isolate()->stub_cache()->GenerateProbe(
       masm, flags, receiver, name, r3, r4, r5, r6);
 
@@ -1086,7 +1087,8 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
   ASSERT(ValueRegister().is(r0));
 
   // Get the receiver from the stack and probe the stub cache.
-  Code::Flags flags = Code::ComputeHandlerFlags(Code::STORE_IC);
+  Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::STORE_IC));
 
   masm->isolate()->stub_cache()->GenerateProbe(
       masm, flags, receiver, name, r3, r4, r5, r6);
index 50c3ff1..d9abe0a 100644 (file)
@@ -893,12 +893,15 @@ Register StubCompiler::CheckPrototypes(Handle<HeapType> type,
 
       reg = holder_reg;  // From now on the object will be in holder_reg.
 
-      if (heap()->InNewSpace(*prototype)) {
-        // The prototype is in new space; we cannot store a reference to it
-        // in the code.  Load it from the map.
+      // Two possible reasons for loading the prototype from the map:
+      // (1) Can't store references to new space in code.
+      // (2) Handler is shared for all receivers with the same prototype
+      //     map (but not necessarily the same prototype instance).
+      bool load_prototype_from_map =
+          heap()->InNewSpace(*prototype) || depth == 1;
+      if (load_prototype_from_map) {
         __ ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
       } else {
-        // The prototype is in old space; load it directly.
         __ mov(reg, Operand(prototype));
       }
     }
index bde701c..5be6438 100644 (file)
@@ -369,7 +369,8 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
   ASSERT(name.is(x2));
 
   // Probe the stub cache.
-  Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC);
+  Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::LOAD_IC));
   masm->isolate()->stub_cache()->GenerateProbe(
       masm, flags, receiver, name, x3, x4, x5, x6);
 
@@ -1122,7 +1123,8 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
   ASSERT(!AreAliased(receiver, name, ValueRegister(), x3, x4, x5, x6));
 
   // Probe the stub cache.
-  Code::Flags flags = Code::ComputeHandlerFlags(Code::STORE_IC);
+  Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::STORE_IC));
   masm->isolate()->stub_cache()->GenerateProbe(
       masm, flags, receiver, name, x3, x4, x5, x6);
 
index 0a672bc..14ced59 100644 (file)
@@ -823,13 +823,14 @@ Register StubCompiler::CheckPrototypes(Handle<HeapType> type,
       reg = holder_reg;  // From now on the object will be in holder_reg.
       __ Ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
     } else {
-      bool need_map = (depth != 1 || check == CHECK_ALL_MAPS) ||
-                      heap()->InNewSpace(*prototype);
-      Register map_reg = NoReg;
-      if (need_map) {
-        map_reg = scratch1;
-        __ Ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
-      }
+      // Two possible reasons for loading the prototype from the map:
+      // (1) Can't store references to new space in code.
+      // (2) Handler is shared for all receivers with the same prototype
+      //     map (but not necessarily the same prototype instance).
+      bool load_prototype_from_map =
+          heap()->InNewSpace(*prototype) || depth == 1;
+      Register map_reg = scratch1;
+      __ Ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
 
       if (depth != 1 || check == CHECK_ALL_MAPS) {
         __ CheckMap(map_reg, current_map, miss, DONT_DO_SMI_CHECK);
@@ -849,12 +850,9 @@ Register StubCompiler::CheckPrototypes(Handle<HeapType> type,
 
       reg = holder_reg;  // From now on the object will be in holder_reg.
 
-      if (heap()->InNewSpace(*prototype)) {
-        // The prototype is in new space; we cannot store a reference to it
-        // in the code.  Load it from the map.
+      if (load_prototype_from_map) {
         __ Ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
       } else {
-        // The prototype is in old space; load it directly.
         __ Mov(reg, Operand(prototype));
       }
     }
index 871164e..bddd4ef 100644 (file)
@@ -420,8 +420,8 @@ enum InlineCacheState {
   PREMONOMORPHIC,
   // Has been executed and only one receiver type has been seen.
   MONOMORPHIC,
-  // Like MONOMORPHIC but check failed due to prototype.
-  MONOMORPHIC_PROTOTYPE_FAILURE,
+  // Check failed due to prototype (or map deprecation).
+  PROTOTYPE_FAILURE,
   // Multiple receiver types have been seen.
   POLYMORPHIC,
   // Many receiver types have been seen.
@@ -449,9 +449,11 @@ enum CallConstructorFlags {
 };
 
 
-enum InlineCacheHolderFlag {
-  OWN_MAP,  // For fast properties objects.
-  PROTOTYPE_MAP  // For slow properties objects (except GlobalObjects).
+enum CacheHolderFlag {
+  kCacheOnPrototype,
+  kCacheOnPrototypeReceiverIsDictionary,
+  kCacheOnPrototypeReceiverIsPrimitive,
+  kCacheOnReceiver
 };
 
 
index 0e9b95e..c48de4c 100644 (file)
@@ -6124,6 +6124,14 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessAsMonomorphic(
 }
 
 
+Handle<Map> HOptimizedGraphBuilder::PropertyAccessInfo::map() {
+  JSFunction* ctor = IC::GetRootConstructor(
+      type_, current_info()->closure()->context()->native_context());
+  if (ctor != NULL) return handle(ctor->initial_map());
+  return type_->AsClass()->Map();
+}
+
+
 static bool NeedsWrappingFor(Type* type, Handle<JSFunction> target) {
   return type->Is(Type::NumberOrString()) &&
       target->shared()->strict_mode() == SLOPPY &&
index a49fef7..bb93667 100644 (file)
@@ -2466,23 +2466,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
     // PropertyAccessInfo is built for types->first().
     bool CanAccessAsMonomorphic(SmallMapList* types);
 
-    Handle<Map> map() {
-      if (type_->Is(Type::Number())) {
-        Context* context = current_info()->closure()->context();
-        context = context->native_context();
-        return handle(context->number_function()->initial_map());
-      } else if (type_->Is(Type::Boolean())) {
-        Context* context = current_info()->closure()->context();
-        context = context->native_context();
-        return handle(context->boolean_function()->initial_map());
-      } else if (type_->Is(Type::String())) {
-        Context* context = current_info()->closure()->context();
-        context = context->native_context();
-        return handle(context->string_function()->initial_map());
-      } else {
-        return type_->AsClass()->Map();
-      }
-    }
+    Handle<Map> map();
     Type* type() const { return type_; }
     Handle<String> name() const { return name_; }
 
index bfec291..16b8ecf 100644 (file)
@@ -893,7 +893,8 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
   ASSERT(name.is(ecx));
 
   // Probe the stub cache.
-  Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC);
+  Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::LOAD_IC));
   masm->isolate()->stub_cache()->GenerateProbe(
       masm, flags, receiver, name, ebx, eax);
 
@@ -1009,7 +1010,8 @@ void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
 
 void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
   // Return address is on the stack.
-  Code::Flags flags = Code::ComputeHandlerFlags(Code::STORE_IC);
+  Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::STORE_IC));
   masm->isolate()->stub_cache()->GenerateProbe(
       masm, flags, ReceiverRegister(), NameRegister(),
       ebx, no_reg);
index e02de20..443ed4e 100644 (file)
@@ -823,6 +823,11 @@ Register StubCompiler::CheckPrototypes(Handle<HeapType> type,
       __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
     } else {
       bool in_new_space = heap()->InNewSpace(*prototype);
+      // Two possible reasons for loading the prototype from the map:
+      // (1) Can't store references to new space in code.
+      // (2) Handler is shared for all receivers with the same prototype
+      //     map (but not necessarily the same prototype instance).
+      bool load_prototype_from_map = in_new_space || depth == 1;
       if (depth != 1 || check == CHECK_ALL_MAPS) {
         __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
       }
@@ -838,19 +843,16 @@ Register StubCompiler::CheckPrototypes(Handle<HeapType> type,
             scratch2, miss);
       }
 
-      if (in_new_space) {
+      if (load_prototype_from_map) {
         // Save the map in scratch1 for later.
         __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
       }
 
       reg = holder_reg;  // From now on the object will be in holder_reg.
 
-      if (in_new_space) {
-        // The prototype is in new space; we cannot store a reference to it
-        // in the code.  Load it from the map.
+      if (load_prototype_from_map) {
         __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
       } else {
-        // The prototype is in old space; load it directly.
         __ mov(reg, prototype);
       }
     }
index 78d42ea..59dfedd 100644 (file)
@@ -119,61 +119,55 @@ void IC::SetTargetAtAddress(Address address,
 }
 
 
-InlineCacheHolderFlag IC::GetCodeCacheForObject(Object* object) {
-  if (object->IsJSObject()) return OWN_MAP;
-
-  // If the object is a value, we use the prototype map for the cache.
-  ASSERT(object->IsString() || object->IsSymbol() ||
-         object->IsNumber() || object->IsBoolean());
-  return PROTOTYPE_MAP;
-}
-
-
-HeapObject* IC::GetCodeCacheHolder(Isolate* isolate,
-                                   Object* object,
-                                   InlineCacheHolderFlag holder) {
-  if (object->IsSmi()) holder = PROTOTYPE_MAP;
-  PrototypeIterator iter(isolate, object,
-                         holder == OWN_MAP
-                             ? PrototypeIterator::START_AT_RECEIVER
-                             : PrototypeIterator::START_AT_PROTOTYPE);
-  return HeapObject::cast(iter.GetCurrent());
+template <class TypeClass>
+JSFunction* IC::GetRootConstructor(TypeClass* type, Context* native_context) {
+  if (type->Is(TypeClass::Boolean())) {
+    return native_context->boolean_function();
+  } else if (type->Is(TypeClass::Number())) {
+    return native_context->number_function();
+  } else if (type->Is(TypeClass::String())) {
+    return native_context->string_function();
+  } else if (type->Is(TypeClass::Symbol())) {
+    return native_context->symbol_function();
+  } else {
+    return NULL;
+  }
 }
 
 
-InlineCacheHolderFlag IC::GetCodeCacheFlag(HeapType* type) {
-  if (type->Is(HeapType::Boolean()) ||
-      type->Is(HeapType::Number()) ||
-      type->Is(HeapType::String()) ||
-      type->Is(HeapType::Symbol())) {
-    return PROTOTYPE_MAP;
+Handle<Map> IC::GetHandlerCacheHolder(HeapType* type, bool receiver_is_holder,
+                                      Isolate* isolate, CacheHolderFlag* flag) {
+  Handle<Map> receiver_map = TypeToMap(type, isolate);
+  if (receiver_is_holder) {
+    *flag = kCacheOnReceiver;
+    return receiver_map;
+  }
+  Context* native_context = *isolate->native_context();
+  JSFunction* builtin_ctor = GetRootConstructor(type, native_context);
+  if (builtin_ctor != NULL) {
+    *flag = kCacheOnPrototypeReceiverIsPrimitive;
+    return handle(HeapObject::cast(builtin_ctor->instance_prototype())->map());
   }
-  return OWN_MAP;
+  *flag = receiver_map->is_dictionary_map()
+              ? kCacheOnPrototypeReceiverIsDictionary
+              : kCacheOnPrototype;
+  // Callers must ensure that the prototype is non-null.
+  return handle(JSObject::cast(receiver_map->prototype())->map());
 }
 
 
-Handle<Map> IC::GetCodeCacheHolder(InlineCacheHolderFlag flag,
-                                   HeapType* type,
-                                   Isolate* isolate) {
-  if (flag == PROTOTYPE_MAP) {
-    Context* context = *isolate->native_context();
-    JSFunction* constructor;
-    if (type->Is(HeapType::Boolean())) {
-      constructor = context->boolean_function();
-    } else if (type->Is(HeapType::Number())) {
-      constructor = context->number_function();
-    } else if (type->Is(HeapType::String())) {
-      constructor = context->string_function();
-    } else {
-      ASSERT(type->Is(HeapType::Symbol()));
-      constructor = context->symbol_function();
-    }
-    return handle(JSObject::cast(constructor->instance_prototype())->map());
+Handle<Map> IC::GetICCacheHolder(HeapType* type, Isolate* isolate,
+                                 CacheHolderFlag* flag) {
+  Context* native_context = *isolate->native_context();
+  JSFunction* builtin_ctor = GetRootConstructor(type, native_context);
+  if (builtin_ctor != NULL) {
+    *flag = kCacheOnPrototype;
+    return handle(builtin_ctor->initial_map());
   }
+  *flag = kCacheOnReceiver;
   return TypeToMap(type, isolate);
 }
 
-
 } }  // namespace v8::internal
 
 #endif  // V8_IC_INL_H_
index ffabaf8..81afa53 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -23,7 +23,8 @@ char IC::TransitionMarkFromState(IC::State state) {
     case UNINITIALIZED: return '0';
     case PREMONOMORPHIC: return '.';
     case MONOMORPHIC: return '1';
-    case MONOMORPHIC_PROTOTYPE_FAILURE: return '^';
+    case PROTOTYPE_FAILURE:
+      return '^';
     case POLYMORPHIC: return 'P';
     case MEGAMORPHIC: return 'N';
     case GENERIC: return 'G';
@@ -236,60 +237,40 @@ static void LookupForRead(Handle<Object> object,
 
 bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
                                                 Handle<String> name) {
-  if (!IsNameCompatibleWithMonomorphicPrototypeFailure(name)) return false;
-
-  InlineCacheHolderFlag cache_holder =
-      Code::ExtractCacheHolderFromFlags(target()->flags());
-
-  switch (cache_holder) {
-    case OWN_MAP:
-      // The stub was generated for JSObject but called for non-JSObject.
-      // IC::GetCodeCacheHolder is not applicable.
-      if (!receiver->IsJSObject()) return false;
-      break;
-    case PROTOTYPE_MAP:
-      // IC::GetCodeCacheHolder is not applicable.
-      PrototypeIterator iter(isolate(), receiver);
-      if (iter.IsAtEnd()) return false;
-      break;
+  if (!IsNameCompatibleWithPrototypeFailure(name)) return false;
+  Handle<Map> receiver_map = TypeToMap(*receiver_type(), isolate());
+  maybe_handler_ = target()->FindHandlerForMap(*receiver_map);
+
+  // The current map wasn't handled yet. There's no reason to stay monomorphic,
+  // *unless* we're moving from a deprecated map to its replacement, or
+  // to a more general elements kind.
+  // TODO(verwaest): Check if the current map is actually what the old map
+  // would transition to.
+  if (maybe_handler_.is_null()) {
+    if (!receiver_map->IsJSObjectMap()) return false;
+    Map* first_map = FirstTargetMap();
+    if (first_map == NULL) return false;
+    Handle<Map> old_map(first_map);
+    if (old_map->is_deprecated()) return true;
+    if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
+                                            receiver_map->elements_kind())) {
+      return true;
+    }
+    return false;
   }
 
-  Handle<Map> map(
-      IC::GetCodeCacheHolder(isolate(), *receiver, cache_holder)->map());
-
-  // Decide whether the inline cache failed because of changes to the
-  // receiver itself or changes to one of its prototypes.
-  //
-  // If there are changes to the receiver itself, the map of the
-  // receiver will have changed and the current target will not be in
-  // the receiver map's code cache.  Therefore, if the current target
-  // is in the receiver map's code cache, the inline cache failed due
-  // to prototype check failure.
-  int index = map->IndexInCodeCache(*name, *target());
-  if (index >= 0) {
-    map->RemoveFromCodeCache(*name, *target(), index);
-    // Handlers are stored in addition to the ICs on the map. Remove those, too.
-    TryRemoveInvalidHandlers(map, name);
-    return true;
-  }
+  CacheHolderFlag flag;
+  Handle<Map> ic_holder_map(
+      GetICCacheHolder(*receiver_type(), isolate(), &flag));
 
-  // The stub is not in the cache. We've ruled out all other kinds of failure
-  // except for proptotype chain changes, a deprecated map, a map that's
-  // different from the one that the stub expects, elements kind changes, or a
-  // constant global property that will become mutable. Threat all those
-  // situations as prototype failures (stay monomorphic if possible).
-
-  // If the IC is shared between multiple receivers (slow dictionary mode), then
-  // the map cannot be deprecated and the stub invalidated.
-  if (cache_holder == OWN_MAP) {
-    Map* old_map = FirstTargetMap();
-    if (old_map == *map) return true;
-    if (old_map != NULL) {
-      if (old_map->is_deprecated()) return true;
-      if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
-                                              map->elements_kind())) {
-        return true;
-      }
+  ASSERT(flag != kCacheOnReceiver || receiver->IsJSObject());
+  ASSERT(flag != kCacheOnPrototype || !receiver->IsJSReceiver());
+  ASSERT(flag != kCacheOnPrototypeReceiverIsDictionary);
+
+  if (state() == MONOMORPHIC) {
+    int index = ic_holder_map->IndexInCodeCache(*name, *target());
+    if (index >= 0) {
+      ic_holder_map->RemoveFromCodeCache(*name, *target(), index);
     }
   }
 
@@ -302,25 +283,11 @@ bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
     return cell->type()->IsConstant();
   }
 
-  return false;
-}
-
-
-void IC::TryRemoveInvalidHandlers(Handle<Map> map, Handle<String> name) {
-  CodeHandleList handlers;
-  target()->FindHandlers(&handlers);
-  for (int i = 0; i < handlers.length(); i++) {
-    Handle<Code> handler = handlers.at(i);
-    int index = map->IndexInCodeCache(*name, *handler);
-    if (index >= 0) {
-      map->RemoveFromCodeCache(*name, *handler, index);
-      return;
-    }
-  }
+  return true;
 }
 
 
-bool IC::IsNameCompatibleWithMonomorphicPrototypeFailure(Handle<Object> name) {
+bool IC::IsNameCompatibleWithPrototypeFailure(Handle<Object> name) {
   if (target()->is_keyed_stub()) {
     // Determine whether the failure is due to a name failure.
     if (!name->IsName()) return false;
@@ -333,23 +300,17 @@ bool IC::IsNameCompatibleWithMonomorphicPrototypeFailure(Handle<Object> name) {
 
 
 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
+  receiver_type_ = CurrentTypeOf(receiver, isolate());
   if (!name->IsString()) return;
-  if (state() != MONOMORPHIC) {
-    if (state() == POLYMORPHIC && receiver->IsHeapObject()) {
-      TryRemoveInvalidHandlers(
-          handle(Handle<HeapObject>::cast(receiver)->map()),
-          Handle<String>::cast(name));
-    }
-    return;
-  }
+  if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
   if (receiver->IsUndefined() || receiver->IsNull()) return;
 
   // Remove the target from the code cache if it became invalid
   // because of changes in the prototype chain to avoid hitting it
   // again.
-  if (TryRemoveInvalidPrototypeDependentStub(
-          receiver, Handle<String>::cast(name)) &&
-      TryMarkMonomorphicPrototypeFailure(name)) {
+  if (TryRemoveInvalidPrototypeDependentStub(receiver,
+                                             Handle<String>::cast(name))) {
+    MarkPrototypeFailure(name);
     return;
   }
 
@@ -688,10 +649,10 @@ static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
 }
 
 
-bool IC::UpdatePolymorphicIC(Handle<HeapType> type,
-                             Handle<String> name,
-                             Handle<Code> code) {
+bool IC::UpdatePolymorphicIC(Handle<String> name, Handle<Code> code) {
   if (!code->is_handler()) return false;
+  if (target()->is_keyed_stub() && state() != PROTOTYPE_FAILURE) return false;
+  Handle<HeapType> type = receiver_type();
   TypeHandleList types;
   CodeHandleList handlers;
 
@@ -728,18 +689,25 @@ bool IC::UpdatePolymorphicIC(Handle<HeapType> type,
   if (!target()->FindHandlers(&handlers, types.length())) return false;
 
   number_of_valid_types++;
-  if (handler_to_overwrite >= 0) {
-    handlers.Set(handler_to_overwrite, code);
-    if (!type->NowIs(types.at(handler_to_overwrite))) {
-      types.Set(handler_to_overwrite, type);
-    }
+  if (number_of_valid_types > 1 && target()->is_keyed_stub()) return false;
+  Handle<Code> ic;
+  if (number_of_valid_types == 1) {
+    ic = isolate()->stub_cache()->ComputeMonomorphicIC(kind(), name, type, code,
+                                                       extra_ic_state());
   } else {
-    types.Add(type);
-    handlers.Add(code);
+    if (handler_to_overwrite >= 0) {
+      handlers.Set(handler_to_overwrite, code);
+      if (!type->NowIs(types.at(handler_to_overwrite))) {
+        types.Set(handler_to_overwrite, type);
+      }
+    } else {
+      types.Add(type);
+      handlers.Add(code);
+    }
+    ic = isolate()->stub_cache()->ComputePolymorphicIC(
+        kind(), &types, &handlers, number_of_valid_types, name,
+        extra_ic_state());
   }
-
-  Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC(
-      kind(), &types, &handlers, number_of_valid_types, name, extra_ic_state());
   set_target(*ic);
   return true;
 }
@@ -787,12 +755,10 @@ template
 Handle<HeapType> IC::MapToType<HeapType>(Handle<Map> map, Isolate* region);
 
 
-void IC::UpdateMonomorphicIC(Handle<HeapType> type,
-                             Handle<Code> handler,
-                             Handle<String> name) {
+void IC::UpdateMonomorphicIC(Handle<Code> handler, Handle<String> name) {
   if (!handler->is_handler()) return set_target(*handler);
   Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC(
-      kind(), name, type, handler, extra_ic_state());
+      kind(), name, receiver_type(), handler, extra_ic_state());
   set_target(*ic);
 }
 
@@ -823,19 +789,17 @@ bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) {
 }
 
 
-void IC::PatchCache(Handle<HeapType> type,
-                    Handle<String> name,
-                    Handle<Code> code) {
+void IC::PatchCache(Handle<String> name, Handle<Code> code) {
   switch (state()) {
     case UNINITIALIZED:
     case PREMONOMORPHIC:
-    case MONOMORPHIC_PROTOTYPE_FAILURE:
-      UpdateMonomorphicIC(type, code, name);
+      UpdateMonomorphicIC(code, name);
       break;
-    case MONOMORPHIC:  // Fall through.
+    case PROTOTYPE_FAILURE:
+    case MONOMORPHIC:
     case POLYMORPHIC:
-      if (!target()->is_keyed_stub()) {
-        if (UpdatePolymorphicIC(type, name, code)) break;
+      if (!target()->is_keyed_stub() || state() == PROTOTYPE_FAILURE) {
+        if (UpdatePolymorphicIC(name, code)) break;
         CopyICToMegamorphicCache(name);
       }
       if (FLAG_compiled_keyed_generic_loads && (kind() == Code::LOAD_IC)) {
@@ -845,7 +809,7 @@ void IC::PatchCache(Handle<HeapType> type,
       set_target(*megamorphic_stub());
       // Fall through.
     case MEGAMORPHIC:
-      UpdateMegamorphicCache(*type, *name, *code);
+      UpdateMegamorphicCache(*receiver_type(), *name, *code);
       break;
     case DEBUG_STUB:
       break;
@@ -901,14 +865,16 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
     return;
   }
 
-  Handle<HeapType> type = CurrentTypeOf(object, isolate());
   Handle<Code> code;
   if (!lookup->IsCacheable()) {
     // Bail out if the result is not cacheable.
     code = slow_stub();
   } else if (!lookup->IsProperty()) {
     if (kind() == Code::LOAD_IC) {
-      code = isolate()->stub_cache()->ComputeLoadNonexistent(name, type);
+      code = isolate()->stub_cache()->ComputeLoadNonexistent(name,
+                                                             receiver_type());
+      // TODO(jkummerow/verwaest): Introduce a builtin that handles this case.
+      if (code.is_null()) code = slow_stub();
     } else {
       code = slow_stub();
     }
@@ -916,7 +882,7 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
     code = ComputeHandler(lookup, object, name);
   }
 
-  PatchCache(type, name, code);
+  PatchCache(name, code);
   TRACE_IC("LoadIC", name);
 }
 
@@ -933,33 +899,50 @@ Handle<Code> IC::ComputeHandler(LookupResult* lookup,
                                 Handle<Object> object,
                                 Handle<String> name,
                                 Handle<Object> value) {
-  InlineCacheHolderFlag cache_holder = GetCodeCacheForObject(*object);
-  Handle<HeapObject> stub_holder(GetCodeCacheHolder(
-      isolate(), *object, cache_holder));
+  bool receiver_is_holder = lookup->ReceiverIsHolder(object);
+  CacheHolderFlag flag;
+  Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder(
+      *receiver_type(), receiver_is_holder, isolate(), &flag);
 
   Handle<Code> code = isolate()->stub_cache()->FindHandler(
-      name, handle(stub_holder->map()), kind(), cache_holder,
+      name, stub_holder_map, kind(), flag,
       lookup->holder()->HasFastProperties() ? Code::FAST : Code::NORMAL);
+  // Use the cached value if it exists, and if it is different from the
+  // handler that just missed.
   if (!code.is_null()) {
-    return code;
+    if (!maybe_handler_.is_null() &&
+        !maybe_handler_.ToHandleChecked().is_identical_to(code)) {
+      return code;
+    }
+    if (maybe_handler_.is_null()) {
+      // maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs.
+      // In MEGAMORPHIC case, check if the handler in the megamorphic stub
+      // cache (which just missed) is different from the cached handler.
+      if (state() == MEGAMORPHIC && object->IsHeapObject()) {
+        Map* map = Handle<HeapObject>::cast(object)->map();
+        Code* megamorphic_cached_code =
+            isolate()->stub_cache()->Get(*name, map, code->flags());
+        if (megamorphic_cached_code != *code) return code;
+      } else {
+        return code;
+      }
+    }
   }
 
-  code = CompileHandler(lookup, object, name, value, cache_holder);
+  code = CompileHandler(lookup, object, name, value, flag);
   ASSERT(code->is_handler());
 
   if (code->type() != Code::NORMAL) {
-    HeapObject::UpdateMapCodeCache(stub_holder, name, code);
+    Map::UpdateCodeCache(stub_holder_map, name, code);
   }
 
   return code;
 }
 
 
-Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
-                                    Handle<Object> object,
-                                    Handle<String> name,
-                                    Handle<Object> unused,
-                                    InlineCacheHolderFlag cache_holder) {
+Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, Handle<Object> object,
+                                    Handle<String> name, Handle<Object> unused,
+                                    CacheHolderFlag cache_holder) {
   if (object->IsString() &&
       String::Equals(isolate()->factory()->length_string(), name)) {
     FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset);
@@ -977,14 +960,15 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
     }
   }
 
-  Handle<HeapType> type = CurrentTypeOf(object, isolate());
+  Handle<HeapType> type = receiver_type();
   Handle<JSObject> holder(lookup->holder());
+  bool receiver_is_holder = object.is_identical_to(holder);
   LoadStubCompiler compiler(isolate(), kNoExtraICState, cache_holder, kind());
 
   switch (lookup->type()) {
     case FIELD: {
       FieldIndex field = lookup->GetFieldIndex();
-      if (object.is_identical_to(holder)) {
+      if (receiver_is_holder) {
         return SimpleFieldLoad(field);
       }
       return compiler.CompileLoadField(
@@ -1003,24 +987,23 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
         Handle<Code> code = compiler.CompileLoadGlobal(
             type, global, cell, name, lookup->IsDontDelete());
         // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
-        Handle<HeapObject> stub_holder(GetCodeCacheHolder(
-            isolate(), *object, cache_holder));
-        HeapObject::UpdateMapCodeCache(stub_holder, name, code);
+        CacheHolderFlag flag;
+        Handle<Map> stub_holder_map =
+            GetHandlerCacheHolder(*type, receiver_is_holder, isolate(), &flag);
+        Map::UpdateCodeCache(stub_holder_map, name, code);
         return code;
       }
       // There is only one shared stub for loading normalized
       // properties. It does not traverse the prototype chain, so the
       // property must be found in the object for the stub to be
       // applicable.
-      if (!object.is_identical_to(holder)) break;
+      if (!receiver_is_holder) break;
       return isolate()->builtins()->LoadIC_Normal();
     case CALLBACKS: {
       // Use simple field loads for some well-known callback properties.
-      if (object->IsJSObject()) {
+      if (receiver_is_holder) {
+        ASSERT(object->IsJSObject());
         Handle<JSObject> receiver = Handle<JSObject>::cast(object);
-        Handle<Map> map(receiver->map());
-        Handle<HeapType> type = IC::MapToType<HeapType>(
-            handle(receiver->map()), isolate());
         int object_offset;
         if (Accessors::IsJSObjectFieldAccessor<HeapType>(
                 type, name, &object_offset)) {
@@ -1270,7 +1253,9 @@ static bool LookupForWrite(Handle<JSObject> receiver,
     // entirely by the migration above.
     receiver->map()->LookupTransition(*holder, *name, lookup);
     if (!lookup->IsTransition()) return false;
-    return ic->TryMarkMonomorphicPrototypeFailure(name);
+    if (!ic->IsNameCompatibleWithPrototypeFailure(name)) return false;
+    ic->MarkPrototypeFailure(name);
+    return true;
   }
 
   return true;
@@ -1418,18 +1403,18 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
 
   Handle<Code> code = ComputeHandler(lookup, receiver, name, value);
 
-  PatchCache(CurrentTypeOf(receiver, isolate()), name, code);
+  PatchCache(name, code);
   TRACE_IC("StoreIC", name);
 }
 
 
 Handle<Code> StoreIC::CompileHandler(LookupResult* lookup,
-                                     Handle<Object> object,
-                                     Handle<String> name,
+                                     Handle<Object> object, Handle<String> name,
                                      Handle<Object> value,
-                                     InlineCacheHolderFlag cache_holder) {
+                                     CacheHolderFlag cache_holder) {
   if (object->IsAccessCheckNeeded()) return slow_stub();
-  ASSERT(cache_holder == OWN_MAP);
+  ASSERT(cache_holder == kCacheOnReceiver || lookup->type() == CALLBACKS ||
+         (object->IsJSGlobalProxy() && lookup->holder()->IsJSGlobalObject()));
   // This is currently guaranteed by checks in StoreIC::Store.
   Handle<JSObject> receiver = Handle<JSObject>::cast(object);
 
index 4647c9c..4e75423 100644 (file)
--- a/src/ic.h
+++ b/src/ic.h
@@ -75,13 +75,10 @@ class IC {
   // Compute the current IC state based on the target stub, receiver and name.
   void UpdateState(Handle<Object> receiver, Handle<Object> name);
 
-  bool IsNameCompatibleWithMonomorphicPrototypeFailure(Handle<Object> name);
-  bool TryMarkMonomorphicPrototypeFailure(Handle<Object> name) {
-    if (IsNameCompatibleWithMonomorphicPrototypeFailure(name)) {
-      state_ = MONOMORPHIC_PROTOTYPE_FAILURE;
-      return true;
-    }
-    return false;
+  bool IsNameCompatibleWithPrototypeFailure(Handle<Object> name);
+  void MarkPrototypeFailure(Handle<Object> name) {
+    ASSERT(IsNameCompatibleWithPrototypeFailure(name));
+    state_ = PROTOTYPE_FAILURE;
   }
 
   // If the stub contains weak maps then this function adds the stub to
@@ -111,20 +108,15 @@ class IC {
   }
 #endif
 
-  // Determines which map must be used for keeping the code stub.
-  // These methods should not be called with undefined or null.
-  static inline InlineCacheHolderFlag GetCodeCacheForObject(Object* object);
-  // TODO(verwaest): This currently returns a HeapObject rather than JSObject*
-  // since loading the IC for loading the length from strings are stored on
-  // the string map directly, rather than on the JSObject-typed prototype.
-  static inline HeapObject* GetCodeCacheHolder(Isolate* isolate,
-                                               Object* object,
-                                               InlineCacheHolderFlag holder);
-
-  static inline InlineCacheHolderFlag GetCodeCacheFlag(HeapType* type);
-  static inline Handle<Map> GetCodeCacheHolder(InlineCacheHolderFlag flag,
-                                               HeapType* type,
-                                               Isolate* isolate);
+  template <class TypeClass>
+  static JSFunction* GetRootConstructor(TypeClass* type,
+                                        Context* native_context);
+  static inline Handle<Map> GetHandlerCacheHolder(HeapType* type,
+                                                  bool receiver_is_holder,
+                                                  Isolate* isolate,
+                                                  CacheHolderFlag* flag);
+  static inline Handle<Map> GetICCacheHolder(HeapType* type, Isolate* isolate,
+                                             CacheHolderFlag* flag);
 
   static bool IsCleared(Code* code) {
     InlineCacheState state = code->ic_state();
@@ -193,28 +185,21 @@ class IC {
                               Handle<Object> value = Handle<Code>::null());
   virtual Handle<Code> CompileHandler(LookupResult* lookup,
                                       Handle<Object> object,
-                                      Handle<String> name,
-                                      Handle<Object> value,
-                                      InlineCacheHolderFlag cache_holder) {
+                                      Handle<String> name, Handle<Object> value,
+                                      CacheHolderFlag cache_holder) {
     UNREACHABLE();
     return Handle<Code>::null();
   }
 
-  void UpdateMonomorphicIC(Handle<HeapType> type,
-                           Handle<Code> handler,
-                           Handle<String> name);
+  void UpdateMonomorphicIC(Handle<Code> handler, Handle<String> name);
 
-  bool UpdatePolymorphicIC(Handle<HeapType> type,
-                           Handle<String> name,
-                           Handle<Code> code);
+  bool UpdatePolymorphicIC(Handle<String> name, Handle<Code> code);
 
   virtual void UpdateMegamorphicCache(HeapType* type, Name* name, Code* code);
 
   void CopyICToMegamorphicCache(Handle<String> name);
   bool IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map);
-  void PatchCache(Handle<HeapType> type,
-                  Handle<String> name,
-                  Handle<Code> code);
+  void PatchCache(Handle<String> name, Handle<Code> code);
   virtual Code::Kind kind() const {
     UNREACHABLE();
     return Code::STUB;
@@ -234,13 +219,14 @@ class IC {
 
   bool TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
                                               Handle<String> name);
-  void TryRemoveInvalidHandlers(Handle<Map> map, Handle<String> name);
 
   ExtraICState extra_ic_state() const { return extra_ic_state_; }
   void set_extra_ic_state(ExtraICState state) {
     extra_ic_state_ = state;
   }
 
+  Handle<HeapType> receiver_type() { return receiver_type_; }
+
   void TargetMaps(MapHandleList* list) {
     FindTargetMaps();
     for (int i = 0; i < target_maps_.length(); i++) {
@@ -300,8 +286,10 @@ class IC {
 
   // The original code target that missed.
   Handle<Code> target_;
-  State state_;
   bool target_set_;
+  State state_;
+  Handle<HeapType> receiver_type_;
+  MaybeHandle<Code> maybe_handler_;
 
   ExtraICState extra_ic_state_;
   MapHandleList target_maps_;
@@ -476,7 +464,7 @@ class LoadIC: public IC {
                                       Handle<Object> object,
                                       Handle<String> name,
                                       Handle<Object> unused,
-                                      InlineCacheHolderFlag cache_holder);
+                                      CacheHolderFlag cache_holder);
 
  private:
   // Stub accessors.
@@ -650,9 +638,8 @@ class StoreIC: public IC {
                     Handle<Object> value);
   virtual Handle<Code> CompileHandler(LookupResult* lookup,
                                       Handle<Object> object,
-                                      Handle<String> name,
-                                      Handle<Object> value,
-                                      InlineCacheHolderFlag cache_holder);
+                                      Handle<String> name, Handle<Object> value,
+                                      CacheHolderFlag cache_holder);
 
  private:
   void set_target(Code* code) {
index d348dc0..10fa803 100644 (file)
@@ -4955,11 +4955,9 @@ void Code::set_constant_pool(Object* value) {
 }
 
 
-Code::Flags Code::ComputeFlags(Kind kind,
-                               InlineCacheState ic_state,
-                               ExtraICState extra_ic_state,
-                               StubType type,
-                               InlineCacheHolderFlag holder) {
+Code::Flags Code::ComputeFlags(Kind kind, InlineCacheState ic_state,
+                               ExtraICState extra_ic_state, StubType type,
+                               CacheHolderFlag holder) {
   // Compute the bit mask.
   unsigned int bits = KindField::encode(kind)
       | ICStateField::encode(ic_state)
@@ -4972,15 +4970,14 @@ Code::Flags Code::ComputeFlags(Kind kind,
 
 Code::Flags Code::ComputeMonomorphicFlags(Kind kind,
                                           ExtraICState extra_ic_state,
-                                          InlineCacheHolderFlag holder,
+                                          CacheHolderFlag holder,
                                           StubType type) {
   return ComputeFlags(kind, MONOMORPHIC, extra_ic_state, type, holder);
 }
 
 
-Code::Flags Code::ComputeHandlerFlags(Kind handler_kind,
-                                      StubType type,
-                                      InlineCacheHolderFlag holder) {
+Code::Flags Code::ComputeHandlerFlags(Kind handler_kind, StubType type,
+                                      CacheHolderFlag holder) {
   return ComputeFlags(Code::HANDLER, MONOMORPHIC, handler_kind, type, holder);
 }
 
@@ -5005,7 +5002,7 @@ Code::StubType Code::ExtractTypeFromFlags(Flags flags) {
 }
 
 
-InlineCacheHolderFlag Code::ExtractCacheHolderFromFlags(Flags flags) {
+CacheHolderFlag Code::ExtractCacheHolderFromFlags(Flags flags) {
   return CacheHolderField::decode(flags);
 }
 
@@ -5016,6 +5013,12 @@ Code::Flags Code::RemoveTypeFromFlags(Flags flags) {
 }
 
 
+Code::Flags Code::RemoveTypeAndHolderFromFlags(Flags flags) {
+  int bits = flags & ~TypeField::kMask & ~CacheHolderField::kMask;
+  return static_cast<Flags>(bits);
+}
+
+
 Code* Code::GetCodeFromTargetAddress(Address address) {
   HeapObject* code = HeapObject::FromAddress(address - Code::kHeaderSize);
   // GetCodeFromTargetAddress might be called when marking objects during mark
index caae614..083f6e0 100644 (file)
@@ -10908,6 +10908,26 @@ bool Code::FindHandlers(CodeHandleList* code_list, int length) {
 }
 
 
+MaybeHandle<Code> Code::FindHandlerForMap(Map* map) {
+  ASSERT(is_inline_cache_stub());
+  int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
+             RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
+  bool return_next = false;
+  for (RelocIterator it(this, mask); !it.done(); it.next()) {
+    RelocInfo* info = it.rinfo();
+    if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
+      Object* object = info->target_object();
+      if (object == map) return_next = true;
+    } else if (return_next) {
+      Code* code = Code::GetCodeFromTargetAddress(info->target_address());
+      ASSERT(code->kind() == Code::HANDLER);
+      return handle(code);
+    }
+  }
+  return MaybeHandle<Code>();
+}
+
+
 Name* Code::FindFirstName() {
   ASSERT(is_inline_cache_stub());
   DisallowHeapAllocation no_allocation;
@@ -11371,7 +11391,8 @@ const char* Code::ICState2String(InlineCacheState state) {
     case UNINITIALIZED: return "UNINITIALIZED";
     case PREMONOMORPHIC: return "PREMONOMORPHIC";
     case MONOMORPHIC: return "MONOMORPHIC";
-    case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
+    case PROTOTYPE_FAILURE:
+      return "PROTOTYPE_FAILURE";
     case POLYMORPHIC: return "POLYMORPHIC";
     case MEGAMORPHIC: return "MEGAMORPHIC";
     case GENERIC: return "GENERIC";
index bbc164f..8084474 100644 (file)
@@ -5634,6 +5634,9 @@ class Code: public HeapObject {
   // enough handlers can be found.
   bool FindHandlers(CodeHandleList* code_list, int length = -1);
 
+  // Find the handler for |map|.
+  MaybeHandle<Code> FindHandlerForMap(Map* map);
+
   // Find the first name in an IC stub.
   Name* FindFirstName();
 
@@ -5655,30 +5658,26 @@ class Code: public HeapObject {
 
   // Flags operations.
   static inline Flags ComputeFlags(
-      Kind kind,
-      InlineCacheState ic_state = UNINITIALIZED,
-      ExtraICState extra_ic_state = kNoExtraICState,
-      StubType type = NORMAL,
-      InlineCacheHolderFlag holder = OWN_MAP);
+      Kind kind, InlineCacheState ic_state = UNINITIALIZED,
+      ExtraICState extra_ic_state = kNoExtraICState, StubType type = NORMAL,
+      CacheHolderFlag holder = kCacheOnReceiver);
 
   static inline Flags ComputeMonomorphicFlags(
-      Kind kind,
-      ExtraICState extra_ic_state = kNoExtraICState,
-      InlineCacheHolderFlag holder = OWN_MAP,
-      StubType type = NORMAL);
+      Kind kind, ExtraICState extra_ic_state = kNoExtraICState,
+      CacheHolderFlag holder = kCacheOnReceiver, StubType type = NORMAL);
 
   static inline Flags ComputeHandlerFlags(
-      Kind handler_kind,
-      StubType type = NORMAL,
-      InlineCacheHolderFlag holder = OWN_MAP);
+      Kind handler_kind, StubType type = NORMAL,
+      CacheHolderFlag holder = kCacheOnReceiver);
 
   static inline InlineCacheState ExtractICStateFromFlags(Flags flags);
   static inline StubType ExtractTypeFromFlags(Flags flags);
+  static inline CacheHolderFlag ExtractCacheHolderFromFlags(Flags flags);
   static inline Kind ExtractKindFromFlags(Flags flags);
-  static inline InlineCacheHolderFlag ExtractCacheHolderFromFlags(Flags flags);
   static inline ExtraICState ExtractExtraICStateFromFlags(Flags flags);
 
   static inline Flags RemoveTypeFromFlags(Flags flags);
+  static inline Flags RemoveTypeAndHolderFromFlags(Flags flags);
 
   // Convert a target address into a code object.
   static inline Code* GetCodeFromTargetAddress(Address address);
@@ -5844,7 +5843,7 @@ class Code: public HeapObject {
   // Flags layout.  BitField<type, shift, size>.
   class ICStateField: public BitField<InlineCacheState, 0, 3> {};
   class TypeField: public BitField<StubType, 3, 1> {};
-  class CacheHolderField: public BitField<InlineCacheHolderFlag, 5, 1> {};
+  class CacheHolderField : public BitField<CacheHolderFlag, 4, 2> {};
   class KindField: public BitField<Kind, 6, 4> {};
   // TODO(bmeurer): Bit 10 is available for free use. :-)
   class ExtraICStateField: public BitField<ExtraICState, 11,
index 2c05188..191b457 100644 (file)
@@ -460,6 +460,12 @@ class LookupResult V8_FINAL BASE_EMBEDDED {
     return map->FindFieldOwner(number_);
   }
 
+  bool ReceiverIsHolder(Handle<Object> receiver) {
+    if (*receiver == holder()) return true;
+    if (lookup_type_ == TRANSITION_TYPE) return true;
+    return false;
+  }
+
   void Iterate(ObjectVisitor* visitor);
 
  private:
index 5612bf2..91cb387 100644 (file)
@@ -33,13 +33,13 @@ void StubCache::Initialize() {
 }
 
 
-Code* StubCache::Set(Name* name, Map* map, Code* code) {
-  // Get the flags from the code.
-  Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
+static Code::Flags CommonStubCacheChecks(Name* name, Map* map,
+                                         Code::Flags flags, Heap* heap) {
+  flags = Code::RemoveTypeAndHolderFromFlags(flags);
 
   // Validate that the name does not move on scavenge, and that we
   // can use identity checks instead of structural equality checks.
-  ASSERT(!heap()->InNewSpace(name));
+  ASSERT(!heap->InNewSpace(name));
   ASSERT(name->IsUniqueName());
 
   // The state bits are not important to the hash function because
@@ -49,8 +49,16 @@ Code* StubCache::Set(Name* name, Map* map, Code* code) {
   ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
   STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1);
 
-  // Make sure that the code type is not included in the hash.
+  // Make sure that the code type and cache holder are not included in the hash.
   ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
+  ASSERT(Code::ExtractCacheHolderFromFlags(flags) == 0);
+
+  return flags;
+}
+
+
+Code* StubCache::Set(Name* name, Map* map, Code* code) {
+  Code::Flags flags = CommonStubCacheChecks(name, map, code->flags(), heap());
 
   // Compute the primary entry.
   int primary_offset = PrimaryOffset(name, flags, map);
@@ -61,7 +69,8 @@ Code* StubCache::Set(Name* name, Map* map, Code* code) {
   // secondary cache before overwriting it.
   if (old_code != isolate_->builtins()->builtin(Builtins::kIllegal)) {
     Map* old_map = primary->map;
-    Code::Flags old_flags = Code::RemoveTypeFromFlags(old_code->flags());
+    Code::Flags old_flags =
+        Code::RemoveTypeAndHolderFromFlags(old_code->flags());
     int seed = PrimaryOffset(primary->key, old_flags, old_map);
     int secondary_offset = SecondaryOffset(primary->key, old_flags, seed);
     Entry* secondary = entry(secondary_, secondary_offset);
@@ -77,11 +86,25 @@ Code* StubCache::Set(Name* name, Map* map, Code* code) {
 }
 
 
-Handle<Code> StubCache::FindIC(Handle<Name> name,
-                               Handle<Map> stub_holder,
-                               Code::Kind kind,
-                               ExtraICState extra_state,
-                               InlineCacheHolderFlag cache_holder) {
+Code* StubCache::Get(Name* name, Map* map, Code::Flags flags) {
+  flags = CommonStubCacheChecks(name, map, flags, heap());
+  int primary_offset = PrimaryOffset(name, flags, map);
+  Entry* primary = entry(primary_, primary_offset);
+  if (primary->key == name && primary->map == map) {
+    return primary->value;
+  }
+  int secondary_offset = SecondaryOffset(name, flags, primary_offset);
+  Entry* secondary = entry(secondary_, secondary_offset);
+  if (secondary->key == name && secondary->map == map) {
+    return secondary->value;
+  }
+  return NULL;
+}
+
+
+Handle<Code> StubCache::FindIC(Handle<Name> name, Handle<Map> stub_holder,
+                               Code::Kind kind, ExtraICState extra_state,
+                               CacheHolderFlag cache_holder) {
   Code::Flags flags = Code::ComputeMonomorphicFlags(
       kind, extra_state, cache_holder);
   Handle<Object> probe(stub_holder->FindInCodeCache(*name, flags), isolate_);
@@ -90,10 +113,9 @@ Handle<Code> StubCache::FindIC(Handle<Name> name,
 }
 
 
-Handle<Code> StubCache::FindHandler(Handle<Name> name,
-                                    Handle<Map> stub_holder,
+Handle<Code> StubCache::FindHandler(Handle<Name> name, Handle<Map> stub_holder,
                                     Code::Kind kind,
-                                    InlineCacheHolderFlag cache_holder,
+                                    CacheHolderFlag cache_holder,
                                     Code::StubType type) {
   Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder);
 
@@ -109,16 +131,15 @@ Handle<Code> StubCache::ComputeMonomorphicIC(
     Handle<HeapType> type,
     Handle<Code> handler,
     ExtraICState extra_ic_state) {
-  InlineCacheHolderFlag flag = IC::GetCodeCacheFlag(*type);
+  CacheHolderFlag flag;
+  Handle<Map> stub_holder = IC::GetICCacheHolder(*type, isolate(), &flag);
 
-  Handle<Map> stub_holder;
   Handle<Code> ic;
   // There are multiple string maps that all use the same prototype. That
   // prototype cannot hold multiple handlers, one for each of the string maps,
   // for a single name. Hence, turn off caching of the IC.
   bool can_be_cached = !type->Is(HeapType::String());
   if (can_be_cached) {
-    stub_holder = IC::GetCodeCacheHolder(flag, *type, isolate());
     ic = FindIC(name, stub_holder, kind, extra_ic_state, flag);
     if (!ic.is_null()) return ic;
   }
@@ -147,36 +168,45 @@ Handle<Code> StubCache::ComputeMonomorphicIC(
 
 Handle<Code> StubCache::ComputeLoadNonexistent(Handle<Name> name,
                                                Handle<HeapType> type) {
-  InlineCacheHolderFlag flag = IC::GetCodeCacheFlag(*type);
-  Handle<Map> stub_holder = IC::GetCodeCacheHolder(flag, *type, isolate());
+  Handle<Map> receiver_map = IC::TypeToMap(*type, isolate());
+  if (receiver_map->prototype()->IsNull()) {
+    // TODO(jkummerow/verwaest): If there is no prototype and the property
+    // is nonexistent, introduce a builtin to handle this (fast properties
+    // -> return undefined, dictionary properties -> do negative lookup).
+    return Handle<Code>();
+  }
+  CacheHolderFlag flag;
+  Handle<Map> stub_holder_map =
+      IC::GetHandlerCacheHolder(*type, false, isolate(), &flag);
+
   // If no dictionary mode objects are present in the prototype chain, the load
   // nonexistent IC stub can be shared for all names for a given map and we use
   // the empty string for the map cache in that case. If there are dictionary
   // mode objects involved, we need to do negative lookups in the stub and
   // therefore the stub will be specific to the name.
-  Handle<Map> current_map = stub_holder;
-  Handle<Name> cache_name = current_map->is_dictionary_map()
-      ? name : Handle<Name>::cast(isolate()->factory()->nonexistent_symbol());
-  Handle<Object> next(current_map->prototype(), isolate());
-  Handle<JSObject> last = Handle<JSObject>::null();
-  while (!next->IsNull()) {
-    last = Handle<JSObject>::cast(next);
-    next = handle(current_map->prototype(), isolate());
-    current_map = handle(Handle<HeapObject>::cast(next)->map());
+  Handle<Name> cache_name =
+      receiver_map->is_dictionary_map()
+          ? name
+          : Handle<Name>::cast(isolate()->factory()->nonexistent_symbol());
+  Handle<Map> current_map = stub_holder_map;
+  Handle<JSObject> last(JSObject::cast(receiver_map->prototype()));
+  while (true) {
     if (current_map->is_dictionary_map()) cache_name = name;
+    if (current_map->prototype()->IsNull()) break;
+    last = handle(JSObject::cast(current_map->prototype()));
+    current_map = handle(last->map());
   }
-
   // Compile the stub that is either shared for all names or
   // name specific if there are global objects involved.
-  Handle<Code> handler = FindHandler(
-      cache_name, stub_holder, Code::LOAD_IC, flag, Code::FAST);
+  Handle<Code> handler =
+      FindHandler(cache_name, stub_holder_map, Code::LOAD_IC, flag, Code::FAST);
   if (!handler.is_null()) {
     return handler;
   }
 
   LoadStubCompiler compiler(isolate_, kNoExtraICState, flag);
   handler = compiler.CompileLoadNonexistent(type, last, cache_name);
-  Map::UpdateCodeCache(stub_holder, cache_name, handler);
+  Map::UpdateCodeCache(stub_holder_map, cache_name, handler);
   return handler;
 }
 
@@ -203,8 +233,8 @@ Handle<Code> StubCache::ComputeKeyedStoreElement(
     KeyedAccessStoreMode store_mode) {
   ExtraICState extra_state =
       KeyedStoreIC::ComputeExtraICState(strict_mode, store_mode);
-  Code::Flags flags = Code::ComputeMonomorphicFlags(
-      Code::KEYED_STORE_IC, extra_state);
+  Code::Flags flags =
+      Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, extra_state);
 
   ASSERT(store_mode == STANDARD_STORE ||
          store_mode == STORE_AND_GROW_NO_TRANSITION ||
index 4687c1c..2a59ecc 100644 (file)
@@ -57,17 +57,13 @@ class StubCache {
   Handle<JSObject> StubHolder(Handle<JSObject> receiver,
                               Handle<JSObject> holder);
 
-  Handle<Code> FindIC(Handle<Name> name,
-                      Handle<Map> stub_holder_map,
+  Handle<Code> FindIC(Handle<Name> name, Handle<Map> stub_holder_map,
                       Code::Kind kind,
                       ExtraICState extra_state = kNoExtraICState,
-                      InlineCacheHolderFlag cache_holder = OWN_MAP);
+                      CacheHolderFlag cache_holder = kCacheOnReceiver);
 
-  Handle<Code> FindHandler(Handle<Name> name,
-                           Handle<Map> map,
-                           Code::Kind kind,
-                           InlineCacheHolderFlag cache_holder,
-                           Code::StubType type);
+  Handle<Code> FindHandler(Handle<Name> name, Handle<Map> map, Code::Kind kind,
+                           CacheHolderFlag cache_holder, Code::StubType type);
 
   Handle<Code> ComputeMonomorphicIC(Code::Kind kind,
                                     Handle<Name> name,
@@ -114,6 +110,8 @@ class StubCache {
   // Update cache for entry hash(name, map).
   Code* Set(Name* name, Map* map, Code* code);
 
+  Code* Get(Name* name, Map* map, Code::Flags flags);
+
   // Clear the lookup table (@ mark compact collection).
   void Clear();
 
@@ -415,10 +413,9 @@ enum FrontendCheckType { PERFORM_INITIAL_CHECKS, SKIP_INITIAL_CHECKS };
 
 class BaseLoadStoreStubCompiler: public StubCompiler {
  public:
-  BaseLoadStoreStubCompiler(Isolate* isolate,
-                            Code::Kind kind,
+  BaseLoadStoreStubCompiler(Isolate* isolate, Code::Kind kind,
                             ExtraICState extra_ic_state = kNoExtraICState,
-                            InlineCacheHolderFlag cache_holder = OWN_MAP)
+                            CacheHolderFlag cache_holder = kCacheOnReceiver)
       : StubCompiler(isolate, extra_ic_state),
         kind_(kind),
         cache_holder_(cache_holder) {
@@ -499,7 +496,7 @@ class BaseLoadStoreStubCompiler: public StubCompiler {
   bool IncludesNumberType(TypeHandleList* types);
 
   Code::Kind kind_;
-  InlineCacheHolderFlag cache_holder_;
+  CacheHolderFlag cache_holder_;
   Register* registers_;
 };
 
@@ -508,10 +505,10 @@ class LoadStubCompiler: public BaseLoadStoreStubCompiler {
  public:
   LoadStubCompiler(Isolate* isolate,
                    ExtraICState extra_ic_state = kNoExtraICState,
-                   InlineCacheHolderFlag cache_holder = OWN_MAP,
+                   CacheHolderFlag cache_holder = kCacheOnReceiver,
                    Code::Kind kind = Code::LOAD_IC)
-      : BaseLoadStoreStubCompiler(isolate, kind, extra_ic_state,
-                                  cache_holder) { }
+      : BaseLoadStoreStubCompiler(isolate, kind, extra_ic_state, cache_holder) {
+  }
   virtual ~LoadStubCompiler() { }
 
   Handle<Code> CompileLoadField(Handle<HeapType> type,
@@ -616,9 +613,9 @@ class KeyedLoadStubCompiler: public LoadStubCompiler {
  public:
   KeyedLoadStubCompiler(Isolate* isolate,
                         ExtraICState extra_ic_state = kNoExtraICState,
-                        InlineCacheHolderFlag cache_holder = OWN_MAP)
+                        CacheHolderFlag cache_holder = kCacheOnReceiver)
       : LoadStubCompiler(isolate, extra_ic_state, cache_holder,
-                         Code::KEYED_LOAD_IC) { }
+                         Code::KEYED_LOAD_IC) {}
 
   Handle<Code> CompileLoadElement(Handle<Map> receiver_map);
 
index 62585af..61696ce 100644 (file)
@@ -910,7 +910,8 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
   ASSERT(name.is(rcx));
 
   // Probe the stub cache.
-  Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC);
+  Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::LOAD_IC));
   masm->isolate()->stub_cache()->GenerateProbe(
       masm, flags, receiver, name, rbx, rax);
 
@@ -1041,7 +1042,8 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
   // The return address is on the stack.
 
   // Get the receiver from the stack and probe the stub cache.
-  Code::Flags flags = Code::ComputeHandlerFlags(Code::STORE_IC);
+  Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::STORE_IC));
   masm->isolate()->stub_cache()->GenerateProbe(
       masm, flags, ReceiverRegister(), NameRegister(), rbx, no_reg);
 
index 74f756a..c552dc6 100644 (file)
@@ -775,7 +775,12 @@ Register StubCompiler::CheckPrototypes(Handle<HeapType> type,
       __ movp(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
     } else {
       bool in_new_space = heap()->InNewSpace(*prototype);
-      if (in_new_space) {
+      // Two possible reasons for loading the prototype from the map:
+      // (1) Can't store references to new space in code.
+      // (2) Handler is shared for all receivers with the same prototype
+      //     map (but not necessarily the same prototype instance).
+      bool load_prototype_from_map = in_new_space || depth == 1;
+      if (load_prototype_from_map) {
         // Save the map in scratch1 for later.
         __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
       }
@@ -795,12 +800,9 @@ Register StubCompiler::CheckPrototypes(Handle<HeapType> type,
       }
       reg = holder_reg;  // From now on the object will be in holder_reg.
 
-      if (in_new_space) {
-        // The prototype is in new space; we cannot store a reference to it
-        // in the code.  Load it from the map.
+      if (load_prototype_from_map) {
         __ movp(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
       } else {
-        // The prototype is in old space; load it directly.
         __ Move(reg, prototype);
       }
     }