| 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 |