OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/objects.h" | 5 #include "src/objects.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 #include <iomanip> | 8 #include <iomanip> |
9 #include <memory> | 9 #include <memory> |
10 #include <sstream> | 10 #include <sstream> |
(...skipping 6135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6146 object->set_elements(*new_elements); | 6146 object->set_elements(*new_elements); |
6147 } else { | 6147 } else { |
6148 object->set_elements(object->map()->GetInitialElements()); | 6148 object->set_elements(object->map()->GetInitialElements()); |
6149 } | 6149 } |
6150 } | 6150 } |
6151 | 6151 |
6152 | 6152 |
6153 void JSObject::RequireSlowElements(SeededNumberDictionary* dictionary) { | 6153 void JSObject::RequireSlowElements(SeededNumberDictionary* dictionary) { |
6154 if (dictionary->requires_slow_elements()) return; | 6154 if (dictionary->requires_slow_elements()) return; |
6155 dictionary->set_requires_slow_elements(); | 6155 dictionary->set_requires_slow_elements(); |
| 6156 // TODO(verwaest): Remove this hack. |
6156 if (map()->is_prototype_map()) { | 6157 if (map()->is_prototype_map()) { |
6157 // If this object is a prototype (the callee will check), invalidate any | 6158 TypeFeedbackVector::ClearAllKeyedStoreICs(GetIsolate()); |
6158 // prototype chains involving it. | |
6159 InvalidatePrototypeChains(map()); | |
6160 } | 6159 } |
6161 } | 6160 } |
6162 | 6161 |
6163 | 6162 |
6164 Handle<SeededNumberDictionary> JSObject::NormalizeElements( | 6163 Handle<SeededNumberDictionary> JSObject::NormalizeElements( |
6165 Handle<JSObject> object) { | 6164 Handle<JSObject> object) { |
6166 DCHECK(!object->HasFixedTypedArrayElements()); | 6165 DCHECK(!object->HasFixedTypedArrayElements()); |
6167 Isolate* isolate = object->GetIsolate(); | 6166 Isolate* isolate = object->GetIsolate(); |
6168 bool is_arguments = object->HasSloppyArgumentsElements(); | 6167 bool is_arguments = object->HasSloppyArgumentsElements(); |
6169 { | 6168 { |
(...skipping 9435 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
15605 } | 15604 } |
15606 } else { | 15605 } else { |
15607 DCHECK(!object->IsAccessCheckNeeded()); | 15606 DCHECK(!object->IsAccessCheckNeeded()); |
15608 } | 15607 } |
15609 | 15608 |
15610 Heap* heap = isolate->heap(); | 15609 Heap* heap = isolate->heap(); |
15611 // Silently ignore the change if value is not a JSObject or null. | 15610 // Silently ignore the change if value is not a JSObject or null. |
15612 // SpiderMonkey behaves this way. | 15611 // SpiderMonkey behaves this way. |
15613 if (!value->IsJSReceiver() && !value->IsNull(isolate)) return Just(true); | 15612 if (!value->IsJSReceiver() && !value->IsNull(isolate)) return Just(true); |
15614 | 15613 |
| 15614 bool dictionary_elements_in_chain = |
| 15615 object->map()->DictionaryElementsInPrototypeChainOnly(); |
| 15616 |
15615 bool all_extensible = object->map()->is_extensible(); | 15617 bool all_extensible = object->map()->is_extensible(); |
15616 Handle<JSObject> real_receiver = object; | 15618 Handle<JSObject> real_receiver = object; |
15617 if (from_javascript) { | 15619 if (from_javascript) { |
15618 // Find the first object in the chain whose prototype object is not | 15620 // Find the first object in the chain whose prototype object is not |
15619 // hidden. | 15621 // hidden. |
15620 PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype, | 15622 PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype, |
15621 PrototypeIterator::END_AT_NON_HIDDEN); | 15623 PrototypeIterator::END_AT_NON_HIDDEN); |
15622 while (!iter.IsAtEnd()) { | 15624 while (!iter.IsAtEnd()) { |
15623 // Casting to JSObject is fine because hidden prototypes are never | 15625 // Casting to JSObject is fine because hidden prototypes are never |
15624 // JSProxies. | 15626 // JSProxies. |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
15670 // Set the new prototype of the object. | 15672 // Set the new prototype of the object. |
15671 | 15673 |
15672 isolate->UpdateArrayProtectorOnSetPrototype(real_receiver); | 15674 isolate->UpdateArrayProtectorOnSetPrototype(real_receiver); |
15673 | 15675 |
15674 PrototypeOptimizationMode mode = | 15676 PrototypeOptimizationMode mode = |
15675 from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE; | 15677 from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE; |
15676 Handle<Map> new_map = Map::TransitionToPrototype(map, value, mode); | 15678 Handle<Map> new_map = Map::TransitionToPrototype(map, value, mode); |
15677 DCHECK(new_map->prototype() == *value); | 15679 DCHECK(new_map->prototype() == *value); |
15678 JSObject::MigrateToMap(real_receiver, new_map); | 15680 JSObject::MigrateToMap(real_receiver, new_map); |
15679 | 15681 |
| 15682 if (from_javascript && !dictionary_elements_in_chain && |
| 15683 new_map->DictionaryElementsInPrototypeChainOnly()) { |
| 15684 // If the prototype chain didn't previously have element callbacks, then |
| 15685 // KeyedStoreICs need to be cleared to ensure any that involve this |
| 15686 // map go generic. |
| 15687 TypeFeedbackVector::ClearAllKeyedStoreICs(isolate); |
| 15688 } |
| 15689 |
15680 heap->ClearInstanceofCache(); | 15690 heap->ClearInstanceofCache(); |
15681 DCHECK(size == object->Size()); | 15691 DCHECK(size == object->Size()); |
15682 return Just(true); | 15692 return Just(true); |
15683 } | 15693 } |
15684 | 15694 |
15685 // static | 15695 // static |
15686 void JSObject::SetImmutableProto(Handle<JSObject> object) { | 15696 void JSObject::SetImmutableProto(Handle<JSObject> object) { |
15687 DCHECK(!object->IsAccessCheckNeeded()); // Never called from JS | 15697 DCHECK(!object->IsAccessCheckNeeded()); // Never called from JS |
15688 Handle<Map> map(object->map()); | 15698 Handle<Map> map(object->map()); |
15689 | 15699 |
(...skipping 1676 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
17366 uint32_t key = NumberToUint32(k); | 17376 uint32_t key = NumberToUint32(k); |
17367 if (key < limit) { | 17377 if (key < limit) { |
17368 if (value->IsUndefined(isolate)) { | 17378 if (value->IsUndefined(isolate)) { |
17369 undefs++; | 17379 undefs++; |
17370 } else if (pos > static_cast<uint32_t>(Smi::kMaxValue)) { | 17380 } else if (pos > static_cast<uint32_t>(Smi::kMaxValue)) { |
17371 // Adding an entry with the key beyond smi-range requires | 17381 // Adding an entry with the key beyond smi-range requires |
17372 // allocation. Bailout. | 17382 // allocation. Bailout. |
17373 return bailout; | 17383 return bailout; |
17374 } else { | 17384 } else { |
17375 Handle<Object> result = SeededNumberDictionary::AddNumberEntry( | 17385 Handle<Object> result = SeededNumberDictionary::AddNumberEntry( |
17376 new_dict, pos, value, details, object); | 17386 new_dict, pos, value, details, object->map()->is_prototype_map()); |
17377 DCHECK(result.is_identical_to(new_dict)); | 17387 DCHECK(result.is_identical_to(new_dict)); |
17378 USE(result); | 17388 USE(result); |
17379 pos++; | 17389 pos++; |
17380 } | 17390 } |
17381 } else if (key > static_cast<uint32_t>(Smi::kMaxValue)) { | 17391 } else if (key > static_cast<uint32_t>(Smi::kMaxValue)) { |
17382 // Adding an entry with the key beyond smi-range requires | 17392 // Adding an entry with the key beyond smi-range requires |
17383 // allocation. Bailout. | 17393 // allocation. Bailout. |
17384 return bailout; | 17394 return bailout; |
17385 } else { | 17395 } else { |
17386 Handle<Object> result = SeededNumberDictionary::AddNumberEntry( | 17396 Handle<Object> result = SeededNumberDictionary::AddNumberEntry( |
17387 new_dict, key, value, details, object); | 17397 new_dict, key, value, details, object->map()->is_prototype_map()); |
17388 DCHECK(result.is_identical_to(new_dict)); | 17398 DCHECK(result.is_identical_to(new_dict)); |
17389 USE(result); | 17399 USE(result); |
17390 } | 17400 } |
17391 } | 17401 } |
17392 | 17402 |
17393 uint32_t result = pos; | 17403 uint32_t result = pos; |
17394 PropertyDetails no_details = PropertyDetails::Empty(); | 17404 PropertyDetails no_details = PropertyDetails::Empty(); |
17395 while (undefs > 0) { | 17405 while (undefs > 0) { |
17396 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) { | 17406 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) { |
17397 // Adding an entry with the key beyond smi-range requires | 17407 // Adding an entry with the key beyond smi-range requires |
17398 // allocation. Bailout. | 17408 // allocation. Bailout. |
17399 return bailout; | 17409 return bailout; |
17400 } | 17410 } |
17401 HandleScope scope(isolate); | 17411 HandleScope scope(isolate); |
17402 Handle<Object> result = SeededNumberDictionary::AddNumberEntry( | 17412 Handle<Object> result = SeededNumberDictionary::AddNumberEntry( |
17403 new_dict, pos, isolate->factory()->undefined_value(), no_details, | 17413 new_dict, pos, isolate->factory()->undefined_value(), no_details, |
17404 object); | 17414 object->map()->is_prototype_map()); |
17405 DCHECK(result.is_identical_to(new_dict)); | 17415 DCHECK(result.is_identical_to(new_dict)); |
17406 USE(result); | 17416 USE(result); |
17407 pos++; | 17417 pos++; |
17408 undefs--; | 17418 undefs--; |
17409 } | 17419 } |
17410 | 17420 |
17411 object->set_elements(*new_dict); | 17421 object->set_elements(*new_dict); |
17412 | 17422 |
17413 AllowHeapAllocation allocate_return_value; | 17423 AllowHeapAllocation allocate_return_value; |
17414 return isolate->factory()->NewNumberFromUint(result); | 17424 return isolate->factory()->NewNumberFromUint(result); |
(...skipping 751 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
18166 if (!this->IsKey(isolate, k)) continue; | 18176 if (!this->IsKey(isolate, k)) continue; |
18167 DCHECK(!IsDeleted(i)); | 18177 DCHECK(!IsDeleted(i)); |
18168 PropertyDetails details = this->DetailsAt(i); | 18178 PropertyDetails details = this->DetailsAt(i); |
18169 if (details.type() == ACCESSOR_CONSTANT) return true; | 18179 if (details.type() == ACCESSOR_CONSTANT) return true; |
18170 PropertyAttributes attr = details.attributes(); | 18180 PropertyAttributes attr = details.attributes(); |
18171 if (attr & ALL_ATTRIBUTES_MASK) return true; | 18181 if (attr & ALL_ATTRIBUTES_MASK) return true; |
18172 } | 18182 } |
18173 return false; | 18183 return false; |
18174 } | 18184 } |
18175 | 18185 |
18176 void SeededNumberDictionary::UpdateMaxNumberKey( | 18186 void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key, |
18177 uint32_t key, Handle<JSObject> dictionary_holder) { | 18187 bool used_as_prototype) { |
18178 DisallowHeapAllocation no_allocation; | 18188 DisallowHeapAllocation no_allocation; |
18179 // If the dictionary requires slow elements an element has already | 18189 // If the dictionary requires slow elements an element has already |
18180 // been added at a high index. | 18190 // been added at a high index. |
18181 if (requires_slow_elements()) return; | 18191 if (requires_slow_elements()) return; |
18182 // Check if this index is high enough that we should require slow | 18192 // Check if this index is high enough that we should require slow |
18183 // elements. | 18193 // elements. |
18184 if (key > kRequiresSlowElementsLimit) { | 18194 if (key > kRequiresSlowElementsLimit) { |
18185 if (!dictionary_holder.is_null()) { | 18195 if (used_as_prototype) { |
18186 dictionary_holder->RequireSlowElements(this); | 18196 // TODO(verwaest): Remove this hack. |
| 18197 TypeFeedbackVector::ClearAllKeyedStoreICs(GetIsolate()); |
18187 } | 18198 } |
18188 set_requires_slow_elements(); | 18199 set_requires_slow_elements(); |
18189 return; | 18200 return; |
18190 } | 18201 } |
18191 // Update max key value. | 18202 // Update max key value. |
18192 Object* max_index_object = get(kMaxNumberKeyIndex); | 18203 Object* max_index_object = get(kMaxNumberKeyIndex); |
18193 if (!max_index_object->IsSmi() || max_number_key() < key) { | 18204 if (!max_index_object->IsSmi() || max_number_key() < key) { |
18194 FixedArray::set(kMaxNumberKeyIndex, | 18205 FixedArray::set(kMaxNumberKeyIndex, |
18195 Smi::FromInt(key << kRequiresSlowElementsTagSize)); | 18206 Smi::FromInt(key << kRequiresSlowElementsTagSize)); |
18196 } | 18207 } |
18197 } | 18208 } |
18198 | 18209 |
| 18210 |
18199 Handle<SeededNumberDictionary> SeededNumberDictionary::AddNumberEntry( | 18211 Handle<SeededNumberDictionary> SeededNumberDictionary::AddNumberEntry( |
18200 Handle<SeededNumberDictionary> dictionary, uint32_t key, | 18212 Handle<SeededNumberDictionary> dictionary, uint32_t key, |
18201 Handle<Object> value, PropertyDetails details, | 18213 Handle<Object> value, PropertyDetails details, bool used_as_prototype) { |
18202 Handle<JSObject> dictionary_holder) { | 18214 dictionary->UpdateMaxNumberKey(key, used_as_prototype); |
18203 dictionary->UpdateMaxNumberKey(key, dictionary_holder); | |
18204 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound); | 18215 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound); |
18205 return Add(dictionary, key, value, details); | 18216 return Add(dictionary, key, value, details); |
18206 } | 18217 } |
18207 | 18218 |
18208 | 18219 |
18209 Handle<UnseededNumberDictionary> UnseededNumberDictionary::AddNumberEntry( | 18220 Handle<UnseededNumberDictionary> UnseededNumberDictionary::AddNumberEntry( |
18210 Handle<UnseededNumberDictionary> dictionary, | 18221 Handle<UnseededNumberDictionary> dictionary, |
18211 uint32_t key, | 18222 uint32_t key, |
18212 Handle<Object> value) { | 18223 Handle<Object> value) { |
18213 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound); | 18224 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound); |
18214 return Add(dictionary, key, value, PropertyDetails::Empty()); | 18225 return Add(dictionary, key, value, PropertyDetails::Empty()); |
18215 } | 18226 } |
18216 | 18227 |
18217 Handle<UnseededNumberDictionary> UnseededNumberDictionary::DeleteKey( | 18228 Handle<UnseededNumberDictionary> UnseededNumberDictionary::DeleteKey( |
18218 Handle<UnseededNumberDictionary> dictionary, uint32_t key) { | 18229 Handle<UnseededNumberDictionary> dictionary, uint32_t key) { |
18219 int entry = dictionary->FindEntry(key); | 18230 int entry = dictionary->FindEntry(key); |
18220 if (entry == kNotFound) return dictionary; | 18231 if (entry == kNotFound) return dictionary; |
18221 | 18232 |
18222 Factory* factory = dictionary->GetIsolate()->factory(); | 18233 Factory* factory = dictionary->GetIsolate()->factory(); |
18223 dictionary->SetEntry(entry, factory->the_hole_value(), | 18234 dictionary->SetEntry(entry, factory->the_hole_value(), |
18224 factory->the_hole_value()); | 18235 factory->the_hole_value()); |
18225 dictionary->ElementRemoved(); | 18236 dictionary->ElementRemoved(); |
18226 return dictionary->Shrink(dictionary, key); | 18237 return dictionary->Shrink(dictionary, key); |
18227 } | 18238 } |
18228 | 18239 |
18229 Handle<SeededNumberDictionary> SeededNumberDictionary::AtNumberPut( | 18240 Handle<SeededNumberDictionary> SeededNumberDictionary::AtNumberPut( |
18230 Handle<SeededNumberDictionary> dictionary, uint32_t key, | 18241 Handle<SeededNumberDictionary> dictionary, uint32_t key, |
18231 Handle<Object> value, Handle<JSObject> dictionary_holder) { | 18242 Handle<Object> value, bool used_as_prototype) { |
18232 dictionary->UpdateMaxNumberKey(key, dictionary_holder); | 18243 dictionary->UpdateMaxNumberKey(key, used_as_prototype); |
18233 return AtPut(dictionary, key, value); | 18244 return AtPut(dictionary, key, value); |
18234 } | 18245 } |
18235 | 18246 |
18236 | 18247 |
18237 Handle<UnseededNumberDictionary> UnseededNumberDictionary::AtNumberPut( | 18248 Handle<UnseededNumberDictionary> UnseededNumberDictionary::AtNumberPut( |
18238 Handle<UnseededNumberDictionary> dictionary, | 18249 Handle<UnseededNumberDictionary> dictionary, |
18239 uint32_t key, | 18250 uint32_t key, |
18240 Handle<Object> value) { | 18251 Handle<Object> value) { |
18241 return AtPut(dictionary, key, value); | 18252 return AtPut(dictionary, key, value); |
18242 } | 18253 } |
18243 | 18254 |
| 18255 |
18244 Handle<SeededNumberDictionary> SeededNumberDictionary::Set( | 18256 Handle<SeededNumberDictionary> SeededNumberDictionary::Set( |
18245 Handle<SeededNumberDictionary> dictionary, uint32_t key, | 18257 Handle<SeededNumberDictionary> dictionary, uint32_t key, |
18246 Handle<Object> value, PropertyDetails details, | 18258 Handle<Object> value, PropertyDetails details, bool used_as_prototype) { |
18247 Handle<JSObject> dictionary_holder) { | |
18248 int entry = dictionary->FindEntry(key); | 18259 int entry = dictionary->FindEntry(key); |
18249 if (entry == kNotFound) { | 18260 if (entry == kNotFound) { |
18250 return AddNumberEntry(dictionary, key, value, details, dictionary_holder); | 18261 return AddNumberEntry(dictionary, key, value, details, used_as_prototype); |
18251 } | 18262 } |
18252 // Preserve enumeration index. | 18263 // Preserve enumeration index. |
18253 details = details.set_index(dictionary->DetailsAt(entry).dictionary_index()); | 18264 details = details.set_index(dictionary->DetailsAt(entry).dictionary_index()); |
18254 Handle<Object> object_key = | 18265 Handle<Object> object_key = |
18255 SeededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key); | 18266 SeededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key); |
18256 dictionary->SetEntry(entry, object_key, value, details); | 18267 dictionary->SetEntry(entry, object_key, value, details); |
18257 return dictionary; | 18268 return dictionary; |
18258 } | 18269 } |
18259 | 18270 |
18260 | 18271 |
(...skipping 2167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
20428 // depend on this. | 20439 // depend on this. |
20429 return DICTIONARY_ELEMENTS; | 20440 return DICTIONARY_ELEMENTS; |
20430 } | 20441 } |
20431 DCHECK_LE(kind, LAST_ELEMENTS_KIND); | 20442 DCHECK_LE(kind, LAST_ELEMENTS_KIND); |
20432 return kind; | 20443 return kind; |
20433 } | 20444 } |
20434 } | 20445 } |
20435 | 20446 |
20436 } // namespace internal | 20447 } // namespace internal |
20437 } // namespace v8 | 20448 } // namespace v8 |
OLD | NEW |