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