Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(380)

Side by Side Diff: src/objects.cc

Issue 35413006: Correct handling of arrays with callbacks in the prototype chain. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Bugfix: check on dictionary elements was incorrect. Added test. Re-enabled test. Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/objects.h ('k') | src/x64/ic-x64.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 the V8 project authors. All rights reserved. 1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 6201 matching lines...) Expand 10 before | Expand all | Expand 10 after
6212 return !AccessorInfo::cast(obj)->prohibits_overwriting(); 6212 return !AccessorInfo::cast(obj)->prohibits_overwriting();
6213 } 6213 }
6214 if (obj->IsAccessorPair()) { 6214 if (obj->IsAccessorPair()) {
6215 return !AccessorPair::cast(obj)->prohibits_overwriting(); 6215 return !AccessorPair::cast(obj)->prohibits_overwriting();
6216 } 6216 }
6217 } 6217 }
6218 return true; 6218 return true;
6219 } 6219 }
6220 6220
6221 6221
6222 bool Map::DictionaryElementsInPrototypeChainOnly() {
6223 Heap* heap = GetHeap();
6224
6225 if (IsDictionaryElementsKind(elements_kind())) {
6226 return false;
6227 }
6228
6229 for (Object* prototype = this->prototype();
6230 prototype != heap->null_value();
6231 prototype = prototype->GetPrototype(GetIsolate())) {
6232 if (prototype->IsJSProxy()) {
6233 // Be conservative, don't walk into proxies.
6234 return true;
6235 }
6236
6237 if (IsDictionaryElementsKind(
6238 JSObject::cast(prototype)->map()->elements_kind())) {
6239 return true;
6240 }
6241 }
6242
6243 return false;
6244 }
6245
6246
6222 void JSObject::SetElementCallback(Handle<JSObject> object, 6247 void JSObject::SetElementCallback(Handle<JSObject> object,
6223 uint32_t index, 6248 uint32_t index,
6224 Handle<Object> structure, 6249 Handle<Object> structure,
6225 PropertyAttributes attributes) { 6250 PropertyAttributes attributes) {
6226 Heap* heap = object->GetHeap(); 6251 Heap* heap = object->GetHeap();
6227 PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0); 6252 PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0);
6228 6253
6229 // Normalize elements to make this operation simple. 6254 // Normalize elements to make this operation simple.
6255 bool had_dictionary_elements = object->HasDictionaryElements();
6230 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object); 6256 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
6231 ASSERT(object->HasDictionaryElements() || 6257 ASSERT(object->HasDictionaryElements() ||
6232 object->HasDictionaryArgumentsElements()); 6258 object->HasDictionaryArgumentsElements());
6233 6259
6234 // Update the dictionary with the new CALLBACKS property. 6260 // Update the dictionary with the new CALLBACKS property.
6235 dictionary = SeededNumberDictionary::Set(dictionary, index, structure, 6261 dictionary = SeededNumberDictionary::Set(dictionary, index, structure,
6236 details); 6262 details);
6237 dictionary->set_requires_slow_elements(); 6263 dictionary->set_requires_slow_elements();
6238 6264
6239 // Update the dictionary backing store on the object. 6265 // Update the dictionary backing store on the object.
6240 if (object->elements()->map() == heap->non_strict_arguments_elements_map()) { 6266 if (object->elements()->map() == heap->non_strict_arguments_elements_map()) {
6241 // Also delete any parameter alias. 6267 // Also delete any parameter alias.
6242 // 6268 //
6243 // TODO(kmillikin): when deleting the last parameter alias we could 6269 // TODO(kmillikin): when deleting the last parameter alias we could
6244 // switch to a direct backing store without the parameter map. This 6270 // switch to a direct backing store without the parameter map. This
6245 // would allow GC of the context. 6271 // would allow GC of the context.
6246 FixedArray* parameter_map = FixedArray::cast(object->elements()); 6272 FixedArray* parameter_map = FixedArray::cast(object->elements());
6247 if (index < static_cast<uint32_t>(parameter_map->length()) - 2) { 6273 if (index < static_cast<uint32_t>(parameter_map->length()) - 2) {
6248 parameter_map->set(index + 2, heap->the_hole_value()); 6274 parameter_map->set(index + 2, heap->the_hole_value());
6249 } 6275 }
6250 parameter_map->set(1, *dictionary); 6276 parameter_map->set(1, *dictionary);
6251 } else { 6277 } else {
6252 object->set_elements(*dictionary); 6278 object->set_elements(*dictionary);
6279
6280 if (!had_dictionary_elements) {
6281 // KeyedStoreICs (at least the non-generic ones) need a reset.
6282 heap->ClearAllICsByKind(Code::KEYED_STORE_IC);
6283 }
6253 } 6284 }
6254 } 6285 }
6255 6286
6256 6287
6257 void JSObject::SetPropertyCallback(Handle<JSObject> object, 6288 void JSObject::SetPropertyCallback(Handle<JSObject> object,
6258 Handle<Name> name, 6289 Handle<Name> name,
6259 Handle<Object> structure, 6290 Handle<Object> structure,
6260 PropertyAttributes attributes) { 6291 PropertyAttributes attributes) {
6261 // Normalize object to make this operation simple. 6292 // Normalize object to make this operation simple.
6262 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0); 6293 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
(...skipping 4339 matching lines...) Expand 10 before | Expand all | Expand 10 after
10602 if (--n == 0) { 10633 if (--n == 0) {
10603 info->set_target_cell(replace_with); 10634 info->set_target_cell(replace_with);
10604 return; 10635 return;
10605 } 10636 }
10606 } 10637 }
10607 UNREACHABLE(); 10638 UNREACHABLE();
10608 } 10639 }
10609 10640
10610 10641
10611 void Code::ClearInlineCaches() { 10642 void Code::ClearInlineCaches() {
10643 ClearInlineCaches(NULL);
10644 }
10645
10646
10647 void Code::ClearInlineCaches(Code::Kind kind) {
10648 ClearInlineCaches(&kind);
10649 }
10650
10651
10652 void Code::ClearInlineCaches(Code::Kind* kind) {
10612 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) | 10653 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
10613 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) | 10654 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
10614 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) | 10655 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
10615 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT); 10656 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT);
10616 for (RelocIterator it(this, mask); !it.done(); it.next()) { 10657 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10617 RelocInfo* info = it.rinfo(); 10658 RelocInfo* info = it.rinfo();
10618 Code* target(Code::GetCodeFromTargetAddress(info->target_address())); 10659 Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
10619 if (target->is_inline_cache_stub()) { 10660 if (target->is_inline_cache_stub()) {
10620 IC::Clear(this->GetIsolate(), info->pc()); 10661 if (kind == NULL || *kind == target->kind()) {
10662 IC::Clear(this->GetIsolate(), info->pc());
10663 }
10621 } 10664 }
10622 } 10665 }
10623 } 10666 }
10624 10667
10625 10668
10626 void Code::ClearTypeFeedbackCells(Heap* heap) { 10669 void Code::ClearTypeFeedbackCells(Heap* heap) {
10627 if (kind() != FUNCTION) return; 10670 if (kind() != FUNCTION) return;
10628 Object* raw_info = type_feedback_info(); 10671 Object* raw_info = type_feedback_info();
10629 if (raw_info->IsTypeFeedbackInfo()) { 10672 if (raw_info->IsTypeFeedbackInfo()) {
10630 TypeFeedbackCells* type_feedback_cells = 10673 TypeFeedbackCells* type_feedback_cells =
(...skipping 1152 matching lines...) Expand 10 before | Expand all | Expand 10 after
11783 pt = pt->GetPrototype(isolate)) { 11826 pt = pt->GetPrototype(isolate)) {
11784 if (JSReceiver::cast(pt) == *object) { 11827 if (JSReceiver::cast(pt) == *object) {
11785 // Cycle detected. 11828 // Cycle detected.
11786 Handle<Object> error = isolate->factory()->NewError( 11829 Handle<Object> error = isolate->factory()->NewError(
11787 "cyclic_proto", HandleVector<Object>(NULL, 0)); 11830 "cyclic_proto", HandleVector<Object>(NULL, 0));
11788 isolate->Throw(*error); 11831 isolate->Throw(*error);
11789 return Handle<Object>(); 11832 return Handle<Object>();
11790 } 11833 }
11791 } 11834 }
11792 11835
11836 bool dictionary_elements_in_chain =
11837 object->map()->DictionaryElementsInPrototypeChainOnly();
11793 Handle<JSObject> real_receiver = object; 11838 Handle<JSObject> real_receiver = object;
11794 11839
11795 if (skip_hidden_prototypes) { 11840 if (skip_hidden_prototypes) {
11796 // Find the first object in the chain whose prototype object is not 11841 // Find the first object in the chain whose prototype object is not
11797 // hidden and set the new prototype on that object. 11842 // hidden and set the new prototype on that object.
11798 Object* current_proto = real_receiver->GetPrototype(); 11843 Object* current_proto = real_receiver->GetPrototype();
11799 while (current_proto->IsJSObject() && 11844 while (current_proto->IsJSObject() &&
11800 JSObject::cast(current_proto)->map()->is_hidden_prototype()) { 11845 JSObject::cast(current_proto)->map()->is_hidden_prototype()) {
11801 real_receiver = handle(JSObject::cast(current_proto), isolate); 11846 real_receiver = handle(JSObject::cast(current_proto), isolate);
11802 current_proto = current_proto->GetPrototype(isolate); 11847 current_proto = current_proto->GetPrototype(isolate);
(...skipping 12 matching lines...) Expand all
11815 11860
11816 Handle<Map> new_map = Map::GetPrototypeTransition(map, value); 11861 Handle<Map> new_map = Map::GetPrototypeTransition(map, value);
11817 if (new_map.is_null()) { 11862 if (new_map.is_null()) {
11818 new_map = Map::Copy(map); 11863 new_map = Map::Copy(map);
11819 Map::PutPrototypeTransition(map, value, new_map); 11864 Map::PutPrototypeTransition(map, value, new_map);
11820 new_map->set_prototype(*value); 11865 new_map->set_prototype(*value);
11821 } 11866 }
11822 ASSERT(new_map->prototype() == *value); 11867 ASSERT(new_map->prototype() == *value);
11823 real_receiver->set_map(*new_map); 11868 real_receiver->set_map(*new_map);
11824 11869
11870 if (!dictionary_elements_in_chain &&
11871 new_map->DictionaryElementsInPrototypeChainOnly()) {
11872 // If the prototype chain didn't previously have element callbacks, then
11873 // KeyedStoreICs need to be cleared to ensure any that involve this
11874 // map go generic.
11875 object->GetHeap()->ClearAllICsByKind(Code::KEYED_STORE_IC);
11876 }
11877
11825 heap->ClearInstanceofCache(); 11878 heap->ClearInstanceofCache();
11826 ASSERT(size == object->Size()); 11879 ASSERT(size == object->Size());
11827 return value; 11880 return value;
11828 } 11881 }
11829 11882
11830 11883
11831 MaybeObject* JSObject::EnsureCanContainElements(Arguments* args, 11884 MaybeObject* JSObject::EnsureCanContainElements(Arguments* args,
11832 uint32_t first_arg, 11885 uint32_t first_arg,
11833 uint32_t arg_count, 11886 uint32_t arg_count,
11834 EnsureElementsMode mode) { 11887 EnsureElementsMode mode) {
(...skipping 968 matching lines...) Expand 10 before | Expand all | Expand 10 after
12803 12856
12804 MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) { 12857 MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) {
12805 ASSERT(!map()->is_observed()); 12858 ASSERT(!map()->is_observed());
12806 ElementsKind from_kind = map()->elements_kind(); 12859 ElementsKind from_kind = map()->elements_kind();
12807 12860
12808 if (IsFastHoleyElementsKind(from_kind)) { 12861 if (IsFastHoleyElementsKind(from_kind)) {
12809 to_kind = GetHoleyElementsKind(to_kind); 12862 to_kind = GetHoleyElementsKind(to_kind);
12810 } 12863 }
12811 12864
12812 if (from_kind == to_kind) return this; 12865 if (from_kind == to_kind) return this;
12813 12866 // Don't update the site if to_kind isn't fast
12814 MaybeObject* maybe_failure = UpdateAllocationSite(to_kind); 12867 if (IsFastElementsKind(to_kind)) {
12815 if (maybe_failure->IsFailure()) return maybe_failure; 12868 MaybeObject* maybe_failure = UpdateAllocationSite(to_kind);
12869 if (maybe_failure->IsFailure()) return maybe_failure;
12870 }
12816 12871
12817 Isolate* isolate = GetIsolate(); 12872 Isolate* isolate = GetIsolate();
12818 if (elements() == isolate->heap()->empty_fixed_array() || 12873 if (elements() == isolate->heap()->empty_fixed_array() ||
12819 (IsFastSmiOrObjectElementsKind(from_kind) && 12874 (IsFastSmiOrObjectElementsKind(from_kind) &&
12820 IsFastSmiOrObjectElementsKind(to_kind)) || 12875 IsFastSmiOrObjectElementsKind(to_kind)) ||
12821 (from_kind == FAST_DOUBLE_ELEMENTS && 12876 (from_kind == FAST_DOUBLE_ELEMENTS &&
12822 to_kind == FAST_HOLEY_DOUBLE_ELEMENTS)) { 12877 to_kind == FAST_HOLEY_DOUBLE_ELEMENTS)) {
12823 ASSERT(from_kind != TERMINAL_FAST_ELEMENTS_KIND); 12878 ASSERT(from_kind != TERMINAL_FAST_ELEMENTS_KIND);
12824 // No change is needed to the elements() buffer, the transition 12879 // No change is needed to the elements() buffer, the transition
12825 // only requires a map change. 12880 // only requires a map change.
(...skipping 3637 matching lines...) Expand 10 before | Expand all | Expand 10 after
16463 #define ERROR_MESSAGES_TEXTS(C, T) T, 16518 #define ERROR_MESSAGES_TEXTS(C, T) T,
16464 static const char* error_messages_[] = { 16519 static const char* error_messages_[] = {
16465 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) 16520 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS)
16466 }; 16521 };
16467 #undef ERROR_MESSAGES_TEXTS 16522 #undef ERROR_MESSAGES_TEXTS
16468 return error_messages_[reason]; 16523 return error_messages_[reason];
16469 } 16524 }
16470 16525
16471 16526
16472 } } // namespace v8::internal 16527 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/objects.h ('k') | src/x64/ic-x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698