| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index e0f160ba2b312981affdd1a3d220baf3ae3e4069..458f7dd2cf404791de51f0aecc1af763b02048fb 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -2948,6 +2948,25 @@ Handle<Object> JSReceiver::SetPropertyWithDefinedSetter(
|
| }
|
|
|
|
|
| +bool JSReceiver::MayHaveIndexedCallbacksInPrototypeChain() {
|
| + Heap* heap = GetHeap();
|
| + for (Object* pt = GetPrototype();
|
| + pt != heap->null_value();
|
| + pt = pt->GetPrototype(GetIsolate())) {
|
| + if (pt->IsJSProxy()) {
|
| + // Be conservative, don't walk into proxies.
|
| + return true;
|
| + }
|
| +
|
| + if (JSObject::cast(pt)->map()->has_element_callbacks()) {
|
| + return true;
|
| + }
|
| + }
|
| +
|
| + return false;
|
| +}
|
| +
|
| +
|
| MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
|
| uint32_t index,
|
| Object* value,
|
| @@ -6229,12 +6248,14 @@ void JSObject::SetElementCallback(Handle<JSObject> object,
|
| Handle<Object> structure,
|
| PropertyAttributes attributes) {
|
| Heap* heap = object->GetHeap();
|
| + Handle<Map> old_map(object->map());
|
| PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0);
|
|
|
| // Normalize elements to make this operation simple.
|
| Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
|
| ASSERT(object->HasDictionaryElements() ||
|
| object->HasDictionaryArgumentsElements());
|
| + bool map_changed = object->map() != *old_map;
|
|
|
| // Update the dictionary with the new CALLBACKS property.
|
| dictionary = SeededNumberDictionary::Set(dictionary, index, structure,
|
| @@ -6256,6 +6277,34 @@ void JSObject::SetElementCallback(Handle<JSObject> object,
|
| } else {
|
| object->set_elements(*dictionary);
|
| }
|
| +
|
| + if (!object->map()->has_element_callbacks()) {
|
| + if (!map_changed) {
|
| + Handle<Map> new_map = Map::Copy(handle(object->map()));
|
| + object->set_map(*new_map);
|
| + }
|
| + object->map()->set_has_element_callbacks(true);
|
| + }
|
| +
|
| + // If we are the array prototype object, rebuild the cache.
|
| + Isolate* isolate = object->GetIsolate();
|
| + if (isolate->initial_array_prototype().is_identical_to(object)) {
|
| + // Install the initial map, new_ek_map in the function prototype for
|
| + // array.
|
| + Handle<JSFunction> array_function(
|
| + isolate->global_context()->array_function(), isolate);
|
| + JSFunction::SetPrototype(array_function, object);
|
| + } else if (isolate->initial_object_prototype().is_identical_to(object)) {
|
| + Handle<JSFunction> object_function(
|
| + isolate->global_context()->object_function(), isolate);
|
| + JSFunction::SetPrototype(object_function, object);
|
| + }
|
| +
|
| + // TODO(mvstanton): With a dependency group we can avoid the need to
|
| + // deoptimize code that doesn't depend on the changed maps. Address this
|
| + // in a follow-up checkin.
|
| + Deoptimizer::DeoptimizeAll(object->GetIsolate());
|
| + object->GetHeap()->ClearAllKeyedStoreICs();
|
| }
|
|
|
|
|
| @@ -10577,6 +10626,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) |
|
| @@ -10585,7 +10644,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());
|
| + }
|
| }
|
| }
|
| }
|
| @@ -12755,8 +12816,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() ||
|
|
|