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 |