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 <sstream> | 9 #include <sstream> |
10 | 10 |
(...skipping 8080 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8091 } | 8091 } |
8092 } | 8092 } |
8093 } | 8093 } |
8094 } else { | 8094 } else { |
8095 // Only deep copy fields from the object literal expression. | 8095 // Only deep copy fields from the object literal expression. |
8096 // In particular, don't try to copy the length attribute of | 8096 // In particular, don't try to copy the length attribute of |
8097 // an array. | 8097 // an array. |
8098 PropertyFilter filter = static_cast<PropertyFilter>( | 8098 PropertyFilter filter = static_cast<PropertyFilter>( |
8099 ONLY_WRITABLE | ONLY_ENUMERABLE | ONLY_CONFIGURABLE); | 8099 ONLY_WRITABLE | ONLY_ENUMERABLE | ONLY_CONFIGURABLE); |
8100 KeyAccumulator accumulator(isolate, filter); | 8100 KeyAccumulator accumulator(isolate, filter); |
8101 accumulator.Prepare(); | 8101 accumulator.NextPrototype(); |
8102 copy->CollectOwnPropertyKeys(&accumulator, filter); | 8102 copy->CollectOwnPropertyNames(&accumulator, filter); |
8103 Handle<FixedArray> names = accumulator.GetKeys(); | 8103 Handle<FixedArray> names = accumulator.GetKeys(); |
8104 for (int i = 0; i < names->length(); i++) { | 8104 for (int i = 0; i < names->length(); i++) { |
8105 DCHECK(names->get(i)->IsName()); | 8105 DCHECK(names->get(i)->IsName()); |
8106 Handle<Name> name(Name::cast(names->get(i))); | 8106 Handle<Name> name(Name::cast(names->get(i))); |
8107 Handle<Object> value = | 8107 Handle<Object> value = |
8108 Object::GetProperty(copy, name).ToHandleChecked(); | 8108 Object::GetProperty(copy, name).ToHandleChecked(); |
8109 if (value->IsJSObject()) { | 8109 if (value->IsJSObject()) { |
8110 Handle<JSObject> result; | 8110 Handle<JSObject> result; |
8111 ASSIGN_RETURN_ON_EXCEPTION( | 8111 ASSIGN_RETURN_ON_EXCEPTION( |
8112 isolate, result, | 8112 isolate, result, |
(...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8431 | 8431 |
8432 Handle<FixedArray> new_array = | 8432 Handle<FixedArray> new_array = |
8433 array->GetIsolate()->factory()->NewFixedArray(length); | 8433 array->GetIsolate()->factory()->NewFixedArray(length); |
8434 for (int i = 0; i < length; ++i) new_array->set(i, array->get(i)); | 8434 for (int i = 0; i < length; ++i) new_array->set(i, array->get(i)); |
8435 return new_array; | 8435 return new_array; |
8436 } | 8436 } |
8437 | 8437 |
8438 | 8438 |
8439 namespace { | 8439 namespace { |
8440 | 8440 |
8441 Handle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate, JSObject* object, | 8441 Handle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate, |
| 8442 Handle<JSObject> object, |
8442 bool cache_enum_length) { | 8443 bool cache_enum_length) { |
8443 Handle<Map> map(object->map(), isolate); | 8444 Handle<Map> map(object->map()); |
8444 Handle<DescriptorArray> descs = | 8445 Handle<DescriptorArray> descs = |
8445 Handle<DescriptorArray>(map->instance_descriptors(), isolate); | 8446 Handle<DescriptorArray>(map->instance_descriptors(), isolate); |
8446 int own_property_count = map->EnumLength(); | 8447 int own_property_count = map->EnumLength(); |
8447 // If the enum length of the given map is set to kInvalidEnumCache, this | 8448 // If the enum length of the given map is set to kInvalidEnumCache, this |
8448 // means that the map itself has never used the present enum cache. The | 8449 // means that the map itself has never used the present enum cache. The |
8449 // first step to using the cache is to set the enum length of the map by | 8450 // first step to using the cache is to set the enum length of the map by |
8450 // counting the number of own descriptors that are ENUMERABLE_STRINGS. | 8451 // counting the number of own descriptors that are ENUMERABLE_STRINGS. |
8451 if (own_property_count == kInvalidEnumCacheSentinel) { | 8452 if (own_property_count == kInvalidEnumCacheSentinel) { |
8452 own_property_count = | 8453 own_property_count = |
8453 map->NumberOfDescribedProperties(OWN_DESCRIPTORS, ENUMERABLE_STRINGS); | 8454 map->NumberOfDescribedProperties(OWN_DESCRIPTORS, ENUMERABLE_STRINGS); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8507 DescriptorArray::SetEnumCache(descs, isolate, storage, indices); | 8508 DescriptorArray::SetEnumCache(descs, isolate, storage, indices); |
8508 if (cache_enum_length) { | 8509 if (cache_enum_length) { |
8509 map->SetEnumLength(own_property_count); | 8510 map->SetEnumLength(own_property_count); |
8510 } | 8511 } |
8511 return storage; | 8512 return storage; |
8512 } | 8513 } |
8513 | 8514 |
8514 } // namespace | 8515 } // namespace |
8515 | 8516 |
8516 | 8517 |
8517 Handle<FixedArray> JSObject::GetOwnEnumPropertyKeys(Handle<JSObject> object, | 8518 Handle<FixedArray> JSObject::GetEnumPropertyKeys(Handle<JSObject> object, |
8518 bool cache_enum_length) { | 8519 bool cache_enum_length) { |
8519 PropertyFilter filter = PropertyFilter::ENUMERABLE_STRINGS; | 8520 Isolate* isolate = object->GetIsolate(); |
8520 KeyAccumulator keys(object->GetIsolate(), filter); | 8521 if (object->HasFastProperties()) { |
8521 keys.Prepare(); | 8522 return GetFastEnumPropertyKeys(isolate, object, cache_enum_length); |
8522 object->CollectOwnPropertyKeys(&keys, filter); | 8523 } else if (object->IsJSGlobalObject()) { |
8523 return keys.GetKeys(); | 8524 Handle<GlobalDictionary> dictionary(object->global_dictionary()); |
| 8525 int length = dictionary->NumberOfEnumElements(); |
| 8526 if (length == 0) { |
| 8527 return Handle<FixedArray>(isolate->heap()->empty_fixed_array()); |
| 8528 } |
| 8529 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length); |
| 8530 dictionary->CopyEnumKeysTo(*storage); |
| 8531 return storage; |
| 8532 } else { |
| 8533 Handle<NameDictionary> dictionary(object->property_dictionary()); |
| 8534 int length = dictionary->NumberOfEnumElements(); |
| 8535 if (length == 0) { |
| 8536 return Handle<FixedArray>(isolate->heap()->empty_fixed_array()); |
| 8537 } |
| 8538 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length); |
| 8539 dictionary->CopyEnumKeysTo(*storage); |
| 8540 return storage; |
| 8541 } |
8524 } | 8542 } |
8525 | 8543 |
8526 | 8544 |
8527 enum IndexedOrNamed { kIndexed, kNamed }; | 8545 enum IndexedOrNamed { kIndexed, kNamed }; |
8528 | 8546 |
8529 | 8547 |
8530 // Returns |true| on success, |nothing| on exception. | 8548 // Returns |true| on success, |nothing| on exception. |
8531 template <class Callback, IndexedOrNamed type> | 8549 template <class Callback, IndexedOrNamed type> |
8532 static Maybe<bool> GetKeysFromInterceptor(Isolate* isolate, | 8550 static Maybe<bool> GetKeysFromInterceptor(Isolate* isolate, |
8533 Handle<JSReceiver> receiver, | 8551 Handle<JSReceiver> receiver, |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8597 } | 8615 } |
8598 | 8616 |
8599 JSObject::CollectOwnElementKeys(object, accumulator, *filter); | 8617 JSObject::CollectOwnElementKeys(object, accumulator, *filter); |
8600 | 8618 |
8601 // Add the element keys from the interceptor. | 8619 // Add the element keys from the interceptor. |
8602 Maybe<bool> success = | 8620 Maybe<bool> success = |
8603 GetKeysFromInterceptor<v8::IndexedPropertyEnumeratorCallback, kIndexed>( | 8621 GetKeysFromInterceptor<v8::IndexedPropertyEnumeratorCallback, kIndexed>( |
8604 isolate, receiver, object, *filter, accumulator); | 8622 isolate, receiver, object, *filter, accumulator); |
8605 MAYBE_RETURN(success, Nothing<bool>()); | 8623 MAYBE_RETURN(success, Nothing<bool>()); |
8606 | 8624 |
8607 object->CollectOwnPropertyKeys(accumulator, *filter, type); | 8625 if (*filter == ENUMERABLE_STRINGS) { |
| 8626 // We can cache the computed property keys if access checks are |
| 8627 // not needed and no interceptors are involved. |
| 8628 // |
| 8629 // We do not use the cache if the object has elements and |
| 8630 // therefore it does not make sense to cache the property names |
| 8631 // for arguments objects. Arguments objects will always have |
| 8632 // elements. |
| 8633 // Wrapped strings have elements, but don't have an elements |
| 8634 // array or dictionary. So the fast inline test for whether to |
| 8635 // use the cache says yes, so we should not create a cache. |
| 8636 Handle<JSFunction> arguments_function( |
| 8637 JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor())); |
| 8638 bool cache_enum_length = |
| 8639 ((object->map()->GetConstructor() != *arguments_function) && |
| 8640 !object->IsJSValue() && !object->IsAccessCheckNeeded() && |
| 8641 !object->HasNamedInterceptor() && !object->HasIndexedInterceptor()); |
| 8642 // Compute the property keys and cache them if possible. |
| 8643 Handle<FixedArray> enum_keys = |
| 8644 JSObject::GetEnumPropertyKeys(object, cache_enum_length); |
| 8645 accumulator->AddKeys(enum_keys); |
| 8646 } else { |
| 8647 object->CollectOwnPropertyNames(accumulator, *filter); |
| 8648 } |
8608 | 8649 |
8609 // Add the property keys from the interceptor. | 8650 // Add the property keys from the interceptor. |
8610 success = GetKeysFromInterceptor<v8::GenericNamedPropertyEnumeratorCallback, | 8651 success = GetKeysFromInterceptor<v8::GenericNamedPropertyEnumeratorCallback, |
8611 kNamed>(isolate, receiver, object, *filter, | 8652 kNamed>(isolate, receiver, object, *filter, |
8612 accumulator); | 8653 accumulator); |
8613 MAYBE_RETURN(success, Nothing<bool>()); | 8654 MAYBE_RETURN(success, Nothing<bool>()); |
8614 return Just(true); | 8655 return Just(true); |
8615 } | 8656 } |
8616 | 8657 |
8617 | 8658 |
(...skipping 7715 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16333 SwapPairs(numbers, i, p); | 16374 SwapPairs(numbers, i, p); |
16334 } | 16375 } |
16335 } | 16376 } |
16336 } else { | 16377 } else { |
16337 HeapSortPairs(this, numbers, len); | 16378 HeapSortPairs(this, numbers, len); |
16338 return; | 16379 return; |
16339 } | 16380 } |
16340 } | 16381 } |
16341 | 16382 |
16342 | 16383 |
16343 namespace { | 16384 void JSObject::CollectOwnPropertyNames(KeyAccumulator* keys, |
16344 | 16385 PropertyFilter filter) { |
16345 void CollectEnumCacheTo(KeyAccumulator* keys, JSObject* object) { | 16386 if (HasFastProperties()) { |
16346 // We can cache the computed property keys if access checks are | 16387 int real_size = map()->NumberOfOwnDescriptors(); |
16347 // not needed and no interceptors are involved. | 16388 Handle<DescriptorArray> descs(map()->instance_descriptors()); |
16348 // | 16389 for (int i = 0; i < real_size; i++) { |
16349 // We do not use the cache if the object has elements and | 16390 PropertyDetails details = descs->GetDetails(i); |
16350 // therefore it does not make sense to cache the property names | 16391 if ((details.attributes() & filter) != 0) continue; |
16351 // for arguments objects. Arguments objects will always have | 16392 if (filter & ONLY_ALL_CAN_READ) { |
16352 // elements. | 16393 if (details.kind() != kAccessor) continue; |
16353 // Wrapped strings have elements, but don't have an elements | 16394 Object* accessors = descs->GetValue(i); |
16354 // array or dictionary. So the fast inline test for whether to | 16395 if (!accessors->IsAccessorInfo()) continue; |
16355 // use the cache says yes, so we should not create a cache. | 16396 if (!AccessorInfo::cast(accessors)->all_can_read()) continue; |
16356 Isolate* isolate = keys->isolate(); | |
16357 Handle<JSFunction> arguments_function( | |
16358 JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor())); | |
16359 bool cache_enum_length = | |
16360 ((object->map()->GetConstructor() != *arguments_function) && | |
16361 !object->IsJSValue() && !object->IsAccessCheckNeeded() && | |
16362 !object->HasNamedInterceptor() && !object->HasIndexedInterceptor()); | |
16363 // Compute the property keys and cache them if possible. | |
16364 Handle<FixedArray> enum_keys = | |
16365 GetFastEnumPropertyKeys(isolate, object, cache_enum_length); | |
16366 keys->AddKeys(enum_keys); | |
16367 } | |
16368 | |
16369 } // namespace | |
16370 | |
16371 | |
16372 void JSObject::CollectFastPropertyKeysTo(KeyAccumulator* keys, | |
16373 PropertyFilter filter, | |
16374 JSReceiver::KeyCollectionType type) { | |
16375 // Avoid using the enum cache if we have to walk the prototype chain due | |
16376 // to shadowing properties. | |
16377 if (filter == ENUMERABLE_STRINGS && type == JSReceiver::OWN_ONLY) { | |
16378 CollectEnumCacheTo(keys, this); | |
16379 return; | |
16380 } | |
16381 | |
16382 int real_size = map()->NumberOfOwnDescriptors(); | |
16383 Handle<DescriptorArray> descs(map()->instance_descriptors()); | |
16384 for (int i = 0; i < real_size; i++) { | |
16385 PropertyDetails details = descs->GetDetails(i); | |
16386 if ((details.attributes() & filter) != 0) { | |
16387 if (type == JSReceiver::OWN_ONLY) continue; | |
16388 if (details.attributes() & DONT_ENUM) { | |
16389 keys->HideKey(descs->GetKey(i)); | |
16390 } | 16397 } |
16391 continue; | 16398 Name* key = descs->GetKey(i); |
| 16399 if (key->FilterKey(filter)) continue; |
| 16400 keys->AddKey(key); |
16392 } | 16401 } |
16393 if (filter & ONLY_ALL_CAN_READ) { | |
16394 if (details.kind() != kAccessor) continue; | |
16395 Object* accessors = descs->GetValue(i); | |
16396 if (!accessors->IsAccessorInfo()) continue; | |
16397 if (!AccessorInfo::cast(accessors)->all_can_read()) continue; | |
16398 } | |
16399 Name* key = descs->GetKey(i); | |
16400 if (key->FilterKey(filter)) continue; | |
16401 keys->AddKey(key); | |
16402 } | |
16403 } | |
16404 | |
16405 | |
16406 void JSObject::CollectOwnPropertyKeys(KeyAccumulator* keys, | |
16407 PropertyFilter filter, | |
16408 JSReceiver::KeyCollectionType type) { | |
16409 if (HasFastProperties()) { | |
16410 CollectFastPropertyKeysTo(keys, filter, type); | |
16411 } else if (IsJSGlobalObject()) { | 16402 } else if (IsJSGlobalObject()) { |
16412 GlobalDictionary::CollectKeysTo(handle(global_dictionary()), keys, filter); | 16403 GlobalDictionary::CollectKeysTo(handle(global_dictionary()), keys, filter); |
16413 } else { | 16404 } else { |
16414 NameDictionary::CollectKeysTo(handle(property_dictionary()), keys, filter); | 16405 NameDictionary::CollectKeysTo(handle(property_dictionary()), keys, filter); |
16415 } | 16406 } |
16416 } | 16407 } |
16417 | 16408 |
16418 | 16409 |
16419 int JSObject::NumberOfOwnElements(PropertyFilter filter) { | 16410 int JSObject::NumberOfOwnElements(PropertyFilter filter) { |
16420 // Fast case for objects with no elements. | 16411 // Fast case for objects with no elements. |
(...skipping 2013 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
18434 } | 18425 } |
18435 DCHECK(storage->length() >= index); | 18426 DCHECK(storage->length() >= index); |
18436 return index - start_index; | 18427 return index - start_index; |
18437 } | 18428 } |
18438 | 18429 |
18439 | 18430 |
18440 template <typename Derived, typename Shape, typename Key> | 18431 template <typename Derived, typename Shape, typename Key> |
18441 void Dictionary<Derived, Shape, Key>::CollectKeysTo( | 18432 void Dictionary<Derived, Shape, Key>::CollectKeysTo( |
18442 Handle<Dictionary<Derived, Shape, Key> > dictionary, KeyAccumulator* keys, | 18433 Handle<Dictionary<Derived, Shape, Key> > dictionary, KeyAccumulator* keys, |
18443 PropertyFilter filter) { | 18434 PropertyFilter filter) { |
18444 if (dictionary->NumberOfElements() == 0) return; | |
18445 int capacity = dictionary->Capacity(); | 18435 int capacity = dictionary->Capacity(); |
18446 Handle<FixedArray> array = | 18436 Handle<FixedArray> array = |
18447 keys->isolate()->factory()->NewFixedArray(dictionary->NumberOfElements()); | 18437 keys->isolate()->factory()->NewFixedArray(dictionary->NumberOfElements()); |
18448 int array_size = 0; | 18438 int array_size = 0; |
18449 std::vector<int> hidden_key_indices; | |
18450 | 18439 |
18451 { | 18440 { |
18452 DisallowHeapAllocation no_gc; | 18441 DisallowHeapAllocation no_gc; |
18453 Dictionary<Derived, Shape, Key>* raw_dict = *dictionary; | 18442 Dictionary<Derived, Shape, Key>* raw_dict = *dictionary; |
18454 for (int i = 0; i < capacity; i++) { | 18443 for (int i = 0; i < capacity; i++) { |
18455 Object* key = raw_dict->KeyAt(i); | 18444 Object* k = raw_dict->KeyAt(i); |
18456 if (!raw_dict->IsKey(key) || key->FilterKey(filter)) continue; | 18445 if (!raw_dict->IsKey(k) || k->FilterKey(filter)) continue; |
18457 if (raw_dict->IsDeleted(i)) continue; | 18446 if (raw_dict->IsDeleted(i)) continue; |
18458 PropertyDetails details = raw_dict->DetailsAt(i); | 18447 PropertyDetails details = raw_dict->DetailsAt(i); |
18459 if ((details.attributes() & filter) != 0) { | 18448 if ((details.attributes() & filter) != 0) continue; |
18460 if (details.attributes() & DONT_ENUM) { | |
18461 hidden_key_indices.push_back(i); | |
18462 } | |
18463 continue; | |
18464 } | |
18465 if (filter & ONLY_ALL_CAN_READ) { | 18449 if (filter & ONLY_ALL_CAN_READ) { |
18466 if (details.kind() != kAccessor) continue; | 18450 if (details.kind() != kAccessor) continue; |
18467 Object* accessors = raw_dict->ValueAt(i); | 18451 Object* accessors = raw_dict->ValueAt(i); |
18468 if (accessors->IsPropertyCell()) { | 18452 if (accessors->IsPropertyCell()) { |
18469 accessors = PropertyCell::cast(accessors)->value(); | 18453 accessors = PropertyCell::cast(accessors)->value(); |
18470 } | 18454 } |
18471 if (!accessors->IsAccessorInfo()) continue; | 18455 if (!accessors->IsAccessorInfo()) continue; |
18472 if (!AccessorInfo::cast(accessors)->all_can_read()) continue; | 18456 if (!AccessorInfo::cast(accessors)->all_can_read()) continue; |
18473 } | 18457 } |
18474 array->set(array_size++, Smi::FromInt(i)); | 18458 array->set(array_size++, Smi::FromInt(i)); |
18475 } | 18459 } |
18476 | 18460 |
18477 EnumIndexComparator<Derived> cmp(static_cast<Derived*>(raw_dict)); | 18461 EnumIndexComparator<Derived> cmp(static_cast<Derived*>(raw_dict)); |
18478 Smi** start = reinterpret_cast<Smi**>(array->GetFirstElementAddress()); | 18462 Smi** start = reinterpret_cast<Smi**>(array->GetFirstElementAddress()); |
18479 std::sort(start, start + array_size, cmp); | 18463 std::sort(start, start + array_size, cmp); |
18480 } | 18464 } |
18481 for (uint32_t i = 0; i < hidden_key_indices.size(); i++) { | 18465 |
18482 keys->HideKey(dictionary->KeyAt(hidden_key_indices[i])); | |
18483 } | |
18484 for (int i = 0; i < array_size; i++) { | 18466 for (int i = 0; i < array_size; i++) { |
18485 int index = Smi::cast(array->get(i))->value(); | 18467 int index = Smi::cast(array->get(i))->value(); |
18486 keys->AddKey(dictionary->KeyAt(index)); | 18468 keys->AddKey(dictionary->KeyAt(index)); |
18487 } | 18469 } |
18488 } | 18470 } |
18489 | 18471 |
18490 | 18472 |
18491 // Backwards lookup (slow). | 18473 // Backwards lookup (slow). |
18492 template<typename Derived, typename Shape, typename Key> | 18474 template<typename Derived, typename Shape, typename Key> |
18493 Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) { | 18475 Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) { |
(...skipping 1239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
19733 if (cell->value() != *new_value) { | 19715 if (cell->value() != *new_value) { |
19734 cell->set_value(*new_value); | 19716 cell->set_value(*new_value); |
19735 Isolate* isolate = cell->GetIsolate(); | 19717 Isolate* isolate = cell->GetIsolate(); |
19736 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 19718 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
19737 isolate, DependentCode::kPropertyCellChangedGroup); | 19719 isolate, DependentCode::kPropertyCellChangedGroup); |
19738 } | 19720 } |
19739 } | 19721 } |
19740 | 19722 |
19741 } // namespace internal | 19723 } // namespace internal |
19742 } // namespace v8 | 19724 } // namespace v8 |
OLD | NEW |