Index: src/ic.cc |
=================================================================== |
--- src/ic.cc (revision 5007) |
+++ src/ic.cc (working copy) |
@@ -134,14 +134,46 @@ |
} |
#endif |
+ |
+static bool HasNormalObjectsInPrototypeChain(LookupResult* lookup, |
+ Object* receiver) { |
+ Object* end = lookup->IsProperty() ? lookup->holder() : Heap::null_value(); |
+ for (Object* current = receiver; |
+ current != end; |
+ current = current->GetPrototype()) { |
+ if (current->IsJSObject() && |
+ !JSObject::cast(current)->HasFastProperties() && |
+ !current->IsJSGlobalProxy() && |
+ !current->IsJSGlobalObject()) { |
+ return true; |
+ } |
+ } |
+ |
+ return false; |
+} |
+ |
+ |
IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { |
IC::State state = target->ic_state(); |
if (state != MONOMORPHIC) return state; |
if (receiver->IsUndefined() || receiver->IsNull()) return state; |
- Map* map = GetCodeCacheMapForObject(receiver); |
+ InlineCacheHolderFlag cache_holder = |
+ Code::ExtractCacheHolderFromFlags(target->flags()); |
+ |
+ if (cache_holder == OWN_MAP && !receiver->IsJSObject()) { |
+ // The stub was generated for JSObject but called for non-JSObject. |
+ // IC::GetCodeCacheMap is not applicable. |
+ return MONOMORPHIC; |
+ } else if (cache_holder == PROTOTYPE_MAP && |
+ receiver->GetPrototype()->IsNull()) { |
+ // IC::GetCodeCacheMap is not applicable. |
+ return MONOMORPHIC; |
+ } |
+ Map* map = IC::GetCodeCacheMap(receiver, cache_holder); |
+ |
// Decide whether the inline cache failed because of changes to the |
// receiver itself or changes to one of its prototypes. |
// |
@@ -487,12 +519,24 @@ |
void CallICBase::UpdateCaches(LookupResult* lookup, |
- State state, |
- Handle<Object> object, |
- Handle<String> name) { |
+ State state, |
+ Handle<Object> object, |
+ Handle<String> name) { |
// Bail out if we didn't find a result. |
if (!lookup->IsProperty() || !lookup->IsCacheable()) return; |
+#ifndef V8_TARGET_ARCH_IA32 |
+ // Normal objects only implemented for IA32 by now. |
+ if (HasNormalObjectsInPrototypeChain(lookup, *object)) return; |
+#else |
+ if (lookup->holder() != *object && |
+ HasNormalObjectsInPrototypeChain(lookup, object->GetPrototype())) { |
+ // Suppress optimization for prototype chains with slow properties objects |
+ // in the middle. |
+ return; |
+ } |
+#endif |
+ |
// Compute the number of arguments. |
int argc = target()->arguments_count(); |
InLoopFlag in_loop = target()->ic_in_loop(); |
@@ -590,8 +634,13 @@ |
state == MONOMORPHIC_PROTOTYPE_FAILURE) { |
set_target(Code::cast(code)); |
} else if (state == MEGAMORPHIC) { |
+ // Cache code holding map should be consistent with |
+ // GenerateMonomorphicCacheProbe. It is not the map which holds the stub. |
+ Map* map = JSObject::cast(object->IsJSObject() ? *object : |
+ object->GetPrototype())->map(); |
+ |
// Update the stub cache. |
- StubCache::Set(*name, GetCodeCacheMapForObject(*object), Code::cast(code)); |
+ StubCache::Set(*name, map, Code::cast(code)); |
} |
#ifdef DEBUG |
@@ -795,6 +844,8 @@ |
if (!object->IsJSObject()) return; |
Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
+ if (HasNormalObjectsInPrototypeChain(lookup, *object)) return; |
+ |
// Compute the code stub for this load. |
Object* code = NULL; |
if (state == UNINITIALIZED) { |
@@ -871,8 +922,12 @@ |
} else if (state == MONOMORPHIC) { |
set_target(megamorphic_stub()); |
} else if (state == MEGAMORPHIC) { |
- // Update the stub cache. |
- StubCache::Set(*name, GetCodeCacheMapForObject(*object), Code::cast(code)); |
+ // Cache code holding map should be consistent with |
+ // GenerateMonomorphicCacheProbe. |
+ Map* map = JSObject::cast(object->IsJSObject() ? *object : |
+ object->GetPrototype())->map(); |
+ |
+ StubCache::Set(*name, map, Code::cast(code)); |
} |
#ifdef DEBUG |
@@ -1018,6 +1073,8 @@ |
if (!object->IsJSObject()) return; |
Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
+ if (HasNormalObjectsInPrototypeChain(lookup, *object)) return; |
+ |
// Compute the code stub for this load. |
Object* code = NULL; |