Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index 5ea9b5a4e490a3faae793e3da5a18e0d4d37463e..4e169cfa80cc58dff7de46bdd60982bc97fc3e80 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -6219,6 +6219,31 @@ bool JSObject::CanSetCallback(Name* name) { |
} |
+bool Map::DictionaryElementsInPrototypeChainOnly() { |
+ Heap* heap = GetHeap(); |
+ |
+ if (IsDictionaryElementsKind(elements_kind())) { |
+ return false; |
+ } |
+ |
+ for (Object* prototype = this->prototype(); |
+ prototype != heap->null_value(); |
+ prototype = prototype->GetPrototype(GetIsolate())) { |
+ if (prototype->IsJSProxy()) { |
+ // Be conservative, don't walk into proxies. |
+ return true; |
+ } |
+ |
+ if (IsDictionaryElementsKind( |
+ JSObject::cast(prototype)->map()->elements_kind())) { |
+ return true; |
+ } |
+ } |
+ |
+ return false; |
+} |
+ |
+ |
void JSObject::SetElementCallback(Handle<JSObject> object, |
uint32_t index, |
Handle<Object> structure, |
@@ -6227,6 +6252,7 @@ void JSObject::SetElementCallback(Handle<JSObject> object, |
PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0); |
// Normalize elements to make this operation simple. |
+ bool had_dictionary_elements = object->HasDictionaryElements(); |
Handle<SeededNumberDictionary> dictionary = NormalizeElements(object); |
ASSERT(object->HasDictionaryElements() || |
object->HasDictionaryArgumentsElements()); |
@@ -6250,6 +6276,11 @@ void JSObject::SetElementCallback(Handle<JSObject> object, |
parameter_map->set(1, *dictionary); |
} else { |
object->set_elements(*dictionary); |
+ |
+ if (!had_dictionary_elements) { |
+ // KeyedStoreICs (at least the non-generic ones) need a reset. |
+ heap->ClearAllICsByKind(Code::KEYED_STORE_IC); |
+ } |
} |
} |
@@ -10609,6 +10640,16 @@ void Code::ReplaceNthCell(int n, Cell* replace_with) { |
void Code::ClearInlineCaches() { |
+ ClearInlineCaches(NULL); |
+} |
+ |
+ |
+void Code::ClearInlineCaches(Code::Kind kind) { |
+ ClearInlineCaches(&kind); |
+} |
+ |
+ |
+void Code::ClearInlineCaches(Code::Kind* kind) { |
int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) | |
RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) | |
RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) | |
@@ -10617,7 +10658,9 @@ void Code::ClearInlineCaches() { |
RelocInfo* info = it.rinfo(); |
Code* target(Code::GetCodeFromTargetAddress(info->target_address())); |
if (target->is_inline_cache_stub()) { |
- IC::Clear(this->GetIsolate(), info->pc()); |
+ if (kind == NULL || *kind == target->kind()) { |
+ IC::Clear(this->GetIsolate(), info->pc()); |
+ } |
} |
} |
} |
@@ -11790,6 +11833,8 @@ Handle<Object> JSObject::SetPrototype(Handle<JSObject> object, |
} |
} |
+ bool dictionary_elements_in_chain = |
+ object->map()->DictionaryElementsInPrototypeChainOnly(); |
Handle<JSObject> real_receiver = object; |
if (skip_hidden_prototypes) { |
@@ -11822,6 +11867,14 @@ Handle<Object> JSObject::SetPrototype(Handle<JSObject> object, |
ASSERT(new_map->prototype() == *value); |
real_receiver->set_map(*new_map); |
+ if (!dictionary_elements_in_chain && |
+ new_map->DictionaryElementsInPrototypeChainOnly()) { |
+ // If the prototype chain didn't previously have element callbacks, then |
+ // KeyedStoreICs need to be cleared to ensure any that involve this |
+ // map go generic. |
+ object->GetHeap()->ClearAllICsByKind(Code::KEYED_STORE_IC); |
+ } |
+ |
heap->ClearInstanceofCache(); |
ASSERT(size == object->Size()); |
return value; |
@@ -12810,9 +12863,11 @@ MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) { |
} |
if (from_kind == to_kind) return this; |
- |
- MaybeObject* maybe_failure = UpdateAllocationSite(to_kind); |
- if (maybe_failure->IsFailure()) return maybe_failure; |
+ // Don't update the site if to_kind isn't fast |
+ if (IsFastElementsKind(to_kind)) { |
+ MaybeObject* maybe_failure = UpdateAllocationSite(to_kind); |
+ if (maybe_failure->IsFailure()) return maybe_failure; |
+ } |
Isolate* isolate = GetIsolate(); |
if (elements() == isolate->heap()->empty_fixed_array() || |