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 6145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6156 object->set_elements(*new_elements); | 6156 object->set_elements(*new_elements); |
6157 } else { | 6157 } else { |
6158 object->set_elements(object->map()->GetInitialElements()); | 6158 object->set_elements(object->map()->GetInitialElements()); |
6159 } | 6159 } |
6160 } | 6160 } |
6161 | 6161 |
6162 | 6162 |
6163 void JSObject::RequireSlowElements(SeededNumberDictionary* dictionary) { | 6163 void JSObject::RequireSlowElements(SeededNumberDictionary* dictionary) { |
6164 if (dictionary->requires_slow_elements()) return; | 6164 if (dictionary->requires_slow_elements()) return; |
6165 dictionary->set_requires_slow_elements(); | 6165 dictionary->set_requires_slow_elements(); |
6166 // TODO(verwaest): Remove this hack. | |
6167 if (map()->is_prototype_map()) { | 6166 if (map()->is_prototype_map()) { |
6168 TypeFeedbackVector::ClearAllKeyedStoreICs(GetIsolate()); | 6167 // If this object is a prototype (the callee will check), invalidate any |
| 6168 // prototype chains involving it. |
| 6169 InvalidatePrototypeChains(map()); |
6169 } | 6170 } |
6170 } | 6171 } |
6171 | 6172 |
6172 | 6173 |
6173 Handle<SeededNumberDictionary> JSObject::NormalizeElements( | 6174 Handle<SeededNumberDictionary> JSObject::NormalizeElements( |
6174 Handle<JSObject> object) { | 6175 Handle<JSObject> object) { |
6175 DCHECK(!object->HasFixedTypedArrayElements()); | 6176 DCHECK(!object->HasFixedTypedArrayElements()); |
6176 Isolate* isolate = object->GetIsolate(); | 6177 Isolate* isolate = object->GetIsolate(); |
6177 bool is_arguments = object->HasSloppyArgumentsElements(); | 6178 bool is_arguments = object->HasSloppyArgumentsElements(); |
6178 { | 6179 { |
(...skipping 9406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
15585 } | 15586 } |
15586 } else { | 15587 } else { |
15587 DCHECK(!object->IsAccessCheckNeeded()); | 15588 DCHECK(!object->IsAccessCheckNeeded()); |
15588 } | 15589 } |
15589 | 15590 |
15590 Heap* heap = isolate->heap(); | 15591 Heap* heap = isolate->heap(); |
15591 // Silently ignore the change if value is not a JSObject or null. | 15592 // Silently ignore the change if value is not a JSObject or null. |
15592 // SpiderMonkey behaves this way. | 15593 // SpiderMonkey behaves this way. |
15593 if (!value->IsJSReceiver() && !value->IsNull(isolate)) return Just(true); | 15594 if (!value->IsJSReceiver() && !value->IsNull(isolate)) return Just(true); |
15594 | 15595 |
15595 bool dictionary_elements_in_chain = | |
15596 object->map()->DictionaryElementsInPrototypeChainOnly(); | |
15597 | |
15598 bool all_extensible = object->map()->is_extensible(); | 15596 bool all_extensible = object->map()->is_extensible(); |
15599 Handle<JSObject> real_receiver = object; | 15597 Handle<JSObject> real_receiver = object; |
15600 if (from_javascript) { | 15598 if (from_javascript) { |
15601 // Find the first object in the chain whose prototype object is not | 15599 // Find the first object in the chain whose prototype object is not |
15602 // hidden. | 15600 // hidden. |
15603 PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype, | 15601 PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype, |
15604 PrototypeIterator::END_AT_NON_HIDDEN); | 15602 PrototypeIterator::END_AT_NON_HIDDEN); |
15605 while (!iter.IsAtEnd()) { | 15603 while (!iter.IsAtEnd()) { |
15606 // Casting to JSObject is fine because hidden prototypes are never | 15604 // Casting to JSObject is fine because hidden prototypes are never |
15607 // JSProxies. | 15605 // JSProxies. |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
15653 // Set the new prototype of the object. | 15651 // Set the new prototype of the object. |
15654 | 15652 |
15655 isolate->UpdateArrayProtectorOnSetPrototype(real_receiver); | 15653 isolate->UpdateArrayProtectorOnSetPrototype(real_receiver); |
15656 | 15654 |
15657 PrototypeOptimizationMode mode = | 15655 PrototypeOptimizationMode mode = |
15658 from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE; | 15656 from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE; |
15659 Handle<Map> new_map = Map::TransitionToPrototype(map, value, mode); | 15657 Handle<Map> new_map = Map::TransitionToPrototype(map, value, mode); |
15660 DCHECK(new_map->prototype() == *value); | 15658 DCHECK(new_map->prototype() == *value); |
15661 JSObject::MigrateToMap(real_receiver, new_map); | 15659 JSObject::MigrateToMap(real_receiver, new_map); |
15662 | 15660 |
15663 if (from_javascript && !dictionary_elements_in_chain && | |
15664 new_map->DictionaryElementsInPrototypeChainOnly()) { | |
15665 // If the prototype chain didn't previously have element callbacks, then | |
15666 // KeyedStoreICs need to be cleared to ensure any that involve this | |
15667 // map go generic. | |
15668 TypeFeedbackVector::ClearAllKeyedStoreICs(isolate); | |
15669 } | |
15670 | |
15671 heap->ClearInstanceofCache(); | 15661 heap->ClearInstanceofCache(); |
15672 DCHECK(size == object->Size()); | 15662 DCHECK(size == object->Size()); |
15673 return Just(true); | 15663 return Just(true); |
15674 } | 15664 } |
15675 | 15665 |
15676 // static | 15666 // static |
15677 void JSObject::SetImmutableProto(Handle<JSObject> object) { | 15667 void JSObject::SetImmutableProto(Handle<JSObject> object) { |
15678 DCHECK(!object->IsAccessCheckNeeded()); // Never called from JS | 15668 DCHECK(!object->IsAccessCheckNeeded()); // Never called from JS |
15679 Handle<Map> map(object->map()); | 15669 Handle<Map> map(object->map()); |
15680 | 15670 |
(...skipping 1676 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
17357 uint32_t key = NumberToUint32(k); | 17347 uint32_t key = NumberToUint32(k); |
17358 if (key < limit) { | 17348 if (key < limit) { |
17359 if (value->IsUndefined(isolate)) { | 17349 if (value->IsUndefined(isolate)) { |
17360 undefs++; | 17350 undefs++; |
17361 } else if (pos > static_cast<uint32_t>(Smi::kMaxValue)) { | 17351 } else if (pos > static_cast<uint32_t>(Smi::kMaxValue)) { |
17362 // Adding an entry with the key beyond smi-range requires | 17352 // Adding an entry with the key beyond smi-range requires |
17363 // allocation. Bailout. | 17353 // allocation. Bailout. |
17364 return bailout; | 17354 return bailout; |
17365 } else { | 17355 } else { |
17366 Handle<Object> result = SeededNumberDictionary::AddNumberEntry( | 17356 Handle<Object> result = SeededNumberDictionary::AddNumberEntry( |
17367 new_dict, pos, value, details, object->map()->is_prototype_map()); | 17357 new_dict, pos, value, details, object); |
17368 DCHECK(result.is_identical_to(new_dict)); | 17358 DCHECK(result.is_identical_to(new_dict)); |
17369 USE(result); | 17359 USE(result); |
17370 pos++; | 17360 pos++; |
17371 } | 17361 } |
17372 } else if (key > static_cast<uint32_t>(Smi::kMaxValue)) { | 17362 } else if (key > static_cast<uint32_t>(Smi::kMaxValue)) { |
17373 // Adding an entry with the key beyond smi-range requires | 17363 // Adding an entry with the key beyond smi-range requires |
17374 // allocation. Bailout. | 17364 // allocation. Bailout. |
17375 return bailout; | 17365 return bailout; |
17376 } else { | 17366 } else { |
17377 Handle<Object> result = SeededNumberDictionary::AddNumberEntry( | 17367 Handle<Object> result = SeededNumberDictionary::AddNumberEntry( |
17378 new_dict, key, value, details, object->map()->is_prototype_map()); | 17368 new_dict, key, value, details, object); |
17379 DCHECK(result.is_identical_to(new_dict)); | 17369 DCHECK(result.is_identical_to(new_dict)); |
17380 USE(result); | 17370 USE(result); |
17381 } | 17371 } |
17382 } | 17372 } |
17383 | 17373 |
17384 uint32_t result = pos; | 17374 uint32_t result = pos; |
17385 PropertyDetails no_details = PropertyDetails::Empty(); | 17375 PropertyDetails no_details = PropertyDetails::Empty(); |
17386 while (undefs > 0) { | 17376 while (undefs > 0) { |
17387 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) { | 17377 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) { |
17388 // Adding an entry with the key beyond smi-range requires | 17378 // Adding an entry with the key beyond smi-range requires |
17389 // allocation. Bailout. | 17379 // allocation. Bailout. |
17390 return bailout; | 17380 return bailout; |
17391 } | 17381 } |
17392 HandleScope scope(isolate); | 17382 HandleScope scope(isolate); |
17393 Handle<Object> result = SeededNumberDictionary::AddNumberEntry( | 17383 Handle<Object> result = SeededNumberDictionary::AddNumberEntry( |
17394 new_dict, pos, isolate->factory()->undefined_value(), no_details, | 17384 new_dict, pos, isolate->factory()->undefined_value(), no_details, |
17395 object->map()->is_prototype_map()); | 17385 object); |
17396 DCHECK(result.is_identical_to(new_dict)); | 17386 DCHECK(result.is_identical_to(new_dict)); |
17397 USE(result); | 17387 USE(result); |
17398 pos++; | 17388 pos++; |
17399 undefs--; | 17389 undefs--; |
17400 } | 17390 } |
17401 | 17391 |
17402 object->set_elements(*new_dict); | 17392 object->set_elements(*new_dict); |
17403 | 17393 |
17404 AllowHeapAllocation allocate_return_value; | 17394 AllowHeapAllocation allocate_return_value; |
17405 return isolate->factory()->NewNumberFromUint(result); | 17395 return isolate->factory()->NewNumberFromUint(result); |
(...skipping 847 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
18253 if (!this->IsKey(isolate, k)) continue; | 18243 if (!this->IsKey(isolate, k)) continue; |
18254 DCHECK(!IsDeleted(i)); | 18244 DCHECK(!IsDeleted(i)); |
18255 PropertyDetails details = this->DetailsAt(i); | 18245 PropertyDetails details = this->DetailsAt(i); |
18256 if (details.type() == ACCESSOR_CONSTANT) return true; | 18246 if (details.type() == ACCESSOR_CONSTANT) return true; |
18257 PropertyAttributes attr = details.attributes(); | 18247 PropertyAttributes attr = details.attributes(); |
18258 if (attr & ALL_ATTRIBUTES_MASK) return true; | 18248 if (attr & ALL_ATTRIBUTES_MASK) return true; |
18259 } | 18249 } |
18260 return false; | 18250 return false; |
18261 } | 18251 } |
18262 | 18252 |
18263 void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key, | 18253 void SeededNumberDictionary::UpdateMaxNumberKey( |
18264 bool used_as_prototype) { | 18254 uint32_t key, Handle<JSObject> dictionary_holder) { |
18265 DisallowHeapAllocation no_allocation; | 18255 DisallowHeapAllocation no_allocation; |
18266 // If the dictionary requires slow elements an element has already | 18256 // If the dictionary requires slow elements an element has already |
18267 // been added at a high index. | 18257 // been added at a high index. |
18268 if (requires_slow_elements()) return; | 18258 if (requires_slow_elements()) return; |
18269 // Check if this index is high enough that we should require slow | 18259 // Check if this index is high enough that we should require slow |
18270 // elements. | 18260 // elements. |
18271 if (key > kRequiresSlowElementsLimit) { | 18261 if (key > kRequiresSlowElementsLimit) { |
18272 if (used_as_prototype) { | 18262 if (!dictionary_holder.is_null()) { |
18273 // TODO(verwaest): Remove this hack. | 18263 dictionary_holder->RequireSlowElements(this); |
18274 TypeFeedbackVector::ClearAllKeyedStoreICs(GetIsolate()); | |
18275 } | 18264 } |
18276 set_requires_slow_elements(); | 18265 set_requires_slow_elements(); |
18277 return; | 18266 return; |
18278 } | 18267 } |
18279 // Update max key value. | 18268 // Update max key value. |
18280 Object* max_index_object = get(kMaxNumberKeyIndex); | 18269 Object* max_index_object = get(kMaxNumberKeyIndex); |
18281 if (!max_index_object->IsSmi() || max_number_key() < key) { | 18270 if (!max_index_object->IsSmi() || max_number_key() < key) { |
18282 FixedArray::set(kMaxNumberKeyIndex, | 18271 FixedArray::set(kMaxNumberKeyIndex, |
18283 Smi::FromInt(key << kRequiresSlowElementsTagSize)); | 18272 Smi::FromInt(key << kRequiresSlowElementsTagSize)); |
18284 } | 18273 } |
18285 } | 18274 } |
18286 | 18275 |
18287 | |
18288 Handle<SeededNumberDictionary> SeededNumberDictionary::AddNumberEntry( | 18276 Handle<SeededNumberDictionary> SeededNumberDictionary::AddNumberEntry( |
18289 Handle<SeededNumberDictionary> dictionary, uint32_t key, | 18277 Handle<SeededNumberDictionary> dictionary, uint32_t key, |
18290 Handle<Object> value, PropertyDetails details, bool used_as_prototype) { | 18278 Handle<Object> value, PropertyDetails details, |
18291 dictionary->UpdateMaxNumberKey(key, used_as_prototype); | 18279 Handle<JSObject> dictionary_holder) { |
| 18280 dictionary->UpdateMaxNumberKey(key, dictionary_holder); |
18292 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound); | 18281 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound); |
18293 return Add(dictionary, key, value, details); | 18282 return Add(dictionary, key, value, details); |
18294 } | 18283 } |
18295 | 18284 |
18296 | 18285 |
18297 Handle<UnseededNumberDictionary> UnseededNumberDictionary::AddNumberEntry( | 18286 Handle<UnseededNumberDictionary> UnseededNumberDictionary::AddNumberEntry( |
18298 Handle<UnseededNumberDictionary> dictionary, | 18287 Handle<UnseededNumberDictionary> dictionary, |
18299 uint32_t key, | 18288 uint32_t key, |
18300 Handle<Object> value) { | 18289 Handle<Object> value) { |
18301 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound); | 18290 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound); |
18302 return Add(dictionary, key, value, PropertyDetails::Empty()); | 18291 return Add(dictionary, key, value, PropertyDetails::Empty()); |
18303 } | 18292 } |
18304 | 18293 |
18305 Handle<UnseededNumberDictionary> UnseededNumberDictionary::DeleteKey( | 18294 Handle<UnseededNumberDictionary> UnseededNumberDictionary::DeleteKey( |
18306 Handle<UnseededNumberDictionary> dictionary, uint32_t key) { | 18295 Handle<UnseededNumberDictionary> dictionary, uint32_t key) { |
18307 int entry = dictionary->FindEntry(key); | 18296 int entry = dictionary->FindEntry(key); |
18308 if (entry == kNotFound) return dictionary; | 18297 if (entry == kNotFound) return dictionary; |
18309 | 18298 |
18310 Factory* factory = dictionary->GetIsolate()->factory(); | 18299 Factory* factory = dictionary->GetIsolate()->factory(); |
18311 dictionary->SetEntry(entry, factory->the_hole_value(), | 18300 dictionary->SetEntry(entry, factory->the_hole_value(), |
18312 factory->the_hole_value()); | 18301 factory->the_hole_value()); |
18313 dictionary->ElementRemoved(); | 18302 dictionary->ElementRemoved(); |
18314 return dictionary->Shrink(dictionary, key); | 18303 return dictionary->Shrink(dictionary, key); |
18315 } | 18304 } |
18316 | 18305 |
18317 Handle<SeededNumberDictionary> SeededNumberDictionary::AtNumberPut( | 18306 Handle<SeededNumberDictionary> SeededNumberDictionary::AtNumberPut( |
18318 Handle<SeededNumberDictionary> dictionary, uint32_t key, | 18307 Handle<SeededNumberDictionary> dictionary, uint32_t key, |
18319 Handle<Object> value, bool used_as_prototype) { | 18308 Handle<Object> value, Handle<JSObject> dictionary_holder) { |
18320 dictionary->UpdateMaxNumberKey(key, used_as_prototype); | 18309 dictionary->UpdateMaxNumberKey(key, dictionary_holder); |
18321 return AtPut(dictionary, key, value); | 18310 return AtPut(dictionary, key, value); |
18322 } | 18311 } |
18323 | 18312 |
18324 | 18313 |
18325 Handle<UnseededNumberDictionary> UnseededNumberDictionary::AtNumberPut( | 18314 Handle<UnseededNumberDictionary> UnseededNumberDictionary::AtNumberPut( |
18326 Handle<UnseededNumberDictionary> dictionary, | 18315 Handle<UnseededNumberDictionary> dictionary, |
18327 uint32_t key, | 18316 uint32_t key, |
18328 Handle<Object> value) { | 18317 Handle<Object> value) { |
18329 return AtPut(dictionary, key, value); | 18318 return AtPut(dictionary, key, value); |
18330 } | 18319 } |
18331 | 18320 |
18332 | |
18333 Handle<SeededNumberDictionary> SeededNumberDictionary::Set( | 18321 Handle<SeededNumberDictionary> SeededNumberDictionary::Set( |
18334 Handle<SeededNumberDictionary> dictionary, uint32_t key, | 18322 Handle<SeededNumberDictionary> dictionary, uint32_t key, |
18335 Handle<Object> value, PropertyDetails details, bool used_as_prototype) { | 18323 Handle<Object> value, PropertyDetails details, |
| 18324 Handle<JSObject> dictionary_holder) { |
18336 int entry = dictionary->FindEntry(key); | 18325 int entry = dictionary->FindEntry(key); |
18337 if (entry == kNotFound) { | 18326 if (entry == kNotFound) { |
18338 return AddNumberEntry(dictionary, key, value, details, used_as_prototype); | 18327 return AddNumberEntry(dictionary, key, value, details, dictionary_holder); |
18339 } | 18328 } |
18340 // Preserve enumeration index. | 18329 // Preserve enumeration index. |
18341 details = details.set_index(dictionary->DetailsAt(entry).dictionary_index()); | 18330 details = details.set_index(dictionary->DetailsAt(entry).dictionary_index()); |
18342 Handle<Object> object_key = | 18331 Handle<Object> object_key = |
18343 SeededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key); | 18332 SeededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key); |
18344 dictionary->SetEntry(entry, object_key, value, details); | 18333 dictionary->SetEntry(entry, object_key, value, details); |
18345 return dictionary; | 18334 return dictionary; |
18346 } | 18335 } |
18347 | 18336 |
18348 | 18337 |
(...skipping 2167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
20516 // depend on this. | 20505 // depend on this. |
20517 return DICTIONARY_ELEMENTS; | 20506 return DICTIONARY_ELEMENTS; |
20518 } | 20507 } |
20519 DCHECK_LE(kind, LAST_ELEMENTS_KIND); | 20508 DCHECK_LE(kind, LAST_ELEMENTS_KIND); |
20520 return kind; | 20509 return kind; |
20521 } | 20510 } |
20522 } | 20511 } |
20523 | 20512 |
20524 } // namespace internal | 20513 } // namespace internal |
20525 } // namespace v8 | 20514 } // namespace v8 |
OLD | NEW |