| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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/keys.h" | 5 #include "src/keys.h" |
| 6 | 6 |
| 7 #include "src/api-arguments.h" | 7 #include "src/api-arguments.h" |
| 8 #include "src/elements.h" | 8 #include "src/elements.h" |
| 9 #include "src/factory.h" | 9 #include "src/factory.h" |
| 10 #include "src/identity-map.h" | 10 #include "src/identity-map.h" |
| (...skipping 29 matching lines...) Expand all Loading... |
| 40 FastKeyAccumulator accumulator(isolate, object, mode, filter); | 40 FastKeyAccumulator accumulator(isolate, object, mode, filter); |
| 41 accumulator.set_is_for_in(is_for_in); | 41 accumulator.set_is_for_in(is_for_in); |
| 42 return accumulator.GetKeys(keys_conversion); | 42 return accumulator.GetKeys(keys_conversion); |
| 43 } | 43 } |
| 44 | 44 |
| 45 Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) { | 45 Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) { |
| 46 if (keys_.is_null()) { | 46 if (keys_.is_null()) { |
| 47 return isolate_->factory()->empty_fixed_array(); | 47 return isolate_->factory()->empty_fixed_array(); |
| 48 } | 48 } |
| 49 if (mode_ == KeyCollectionMode::kOwnOnly && | 49 if (mode_ == KeyCollectionMode::kOwnOnly && |
| 50 keys_->map() == isolate_->heap()->fixed_array_map()) { | 50 (keys_->map() == isolate_->heap()->fixed_array_map() || |
| 51 keys_->map() == isolate_->heap()->fixed_cow_array_map())) { |
| 51 return Handle<FixedArray>::cast(keys_); | 52 return Handle<FixedArray>::cast(keys_); |
| 52 } | 53 } |
| 53 USE(ContainsOnlyValidKeys); | 54 USE(ContainsOnlyValidKeys); |
| 54 Handle<FixedArray> result = | 55 Handle<FixedArray> result = |
| 55 OrderedHashSet::ConvertToKeysArray(keys(), convert); | 56 OrderedHashSet::ConvertToKeysArray(keys(), convert); |
| 56 DCHECK(ContainsOnlyValidKeys(result)); | 57 DCHECK(ContainsOnlyValidKeys(result)); |
| 57 return result; | 58 return result; |
| 58 } | 59 } |
| 59 | 60 |
| 60 void KeyAccumulator::AddKey(Object* key, AddKeyConversion convert) { | 61 void KeyAccumulator::AddKey(Object* key, AddKeyConversion convert) { |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 256 if (has_empty_prototype_) { | 257 if (has_empty_prototype_) { |
| 257 is_receiver_simple_enum_ = | 258 is_receiver_simple_enum_ = |
| 258 receiver_->map()->EnumLength() != kInvalidEnumCacheSentinel && | 259 receiver_->map()->EnumLength() != kInvalidEnumCacheSentinel && |
| 259 !JSObject::cast(*receiver_)->HasEnumerableElements(); | 260 !JSObject::cast(*receiver_)->HasEnumerableElements(); |
| 260 } else if (last_prototype != nullptr) { | 261 } else if (last_prototype != nullptr) { |
| 261 last_non_empty_prototype_ = handle(last_prototype, isolate_); | 262 last_non_empty_prototype_ = handle(last_prototype, isolate_); |
| 262 } | 263 } |
| 263 } | 264 } |
| 264 | 265 |
| 265 namespace { | 266 namespace { |
| 266 static Handle<FixedArray> ReduceFixedArrayTo(Isolate* isolate, | 267 |
| 267 Handle<FixedArray> array, | 268 Handle<FixedArray> ReduceFixedArrayTo(Isolate* isolate, |
| 268 int length) { | 269 Handle<FixedArray> array, int length) { |
| 269 DCHECK_LE(length, array->length()); | 270 DCHECK_LE(length, array->length()); |
| 270 if (array->length() == length) return array; | 271 if (array->length() == length) return array; |
| 271 return isolate->factory()->CopyFixedArrayUpTo(array, length); | 272 return isolate->factory()->CopyFixedArrayUpTo(array, length); |
| 272 } | 273 } |
| 273 | 274 |
| 274 // Initializes and directly returns the enume cache. Users of this function | 275 // Initializes and directly returns the enume cache. Users of this function |
| 275 // have to make sure to never directly leak the enum cache. | 276 // have to make sure to never directly leak the enum cache. |
| 276 Handle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate, | 277 Handle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate, |
| 277 Handle<JSObject> object) { | 278 Handle<JSObject> object) { |
| 278 Handle<Map> map(object->map()); | 279 Handle<Map> map(object->map()); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 308 } | 309 } |
| 309 | 310 |
| 310 if (descs->IsEmpty()) { | 311 if (descs->IsEmpty()) { |
| 311 isolate->counters()->enum_cache_hits()->Increment(); | 312 isolate->counters()->enum_cache_hits()->Increment(); |
| 312 if (cache_enum_length) map->SetEnumLength(0); | 313 if (cache_enum_length) map->SetEnumLength(0); |
| 313 return isolate->factory()->empty_fixed_array(); | 314 return isolate->factory()->empty_fixed_array(); |
| 314 } | 315 } |
| 315 | 316 |
| 316 isolate->counters()->enum_cache_misses()->Increment(); | 317 isolate->counters()->enum_cache_misses()->Increment(); |
| 317 | 318 |
| 318 Handle<FixedArray> storage = | 319 Handle<FixedArray> storage = isolate->factory()->empty_fixed_array(); |
| 319 isolate->factory()->NewFixedArray(own_property_count); | 320 Handle<FixedArray> indices = isolate->factory()->empty_fixed_array(); |
| 320 Handle<FixedArray> indices = | 321 if (own_property_count != 0) { |
| 321 isolate->factory()->NewFixedArray(own_property_count); | 322 storage = isolate->factory()->NewFixedArray(own_property_count); |
| 323 indices = isolate->factory()->NewFixedArray(own_property_count); |
| 322 | 324 |
| 323 int size = map->NumberOfOwnDescriptors(); | 325 int size = map->NumberOfOwnDescriptors(); |
| 324 int index = 0; | 326 int index = 0; |
| 325 | 327 |
| 326 for (int i = 0; i < size; i++) { | 328 for (int i = 0; i < size; i++) { |
| 327 PropertyDetails details = descs->GetDetails(i); | 329 PropertyDetails details = descs->GetDetails(i); |
| 328 if (details.IsDontEnum()) continue; | 330 if (details.IsDontEnum()) continue; |
| 329 Object* key = descs->GetKey(i); | 331 Object* key = descs->GetKey(i); |
| 330 if (key->IsSymbol()) continue; | 332 if (key->IsSymbol()) continue; |
| 331 storage->set(index, key); | 333 storage->set(index, key); |
| 332 if (!indices.is_null()) { | 334 if (!indices.is_null()) { |
| 333 if (details.location() == kField) { | 335 if (details.location() == kField) { |
| 334 DCHECK_EQ(kData, details.kind()); | 336 DCHECK_EQ(kData, details.kind()); |
| 335 FieldIndex field_index = FieldIndex::ForDescriptor(*map, i); | 337 FieldIndex field_index = FieldIndex::ForDescriptor(*map, i); |
| 336 int load_by_field_index = field_index.GetLoadByFieldIndex(); | 338 int load_by_field_index = field_index.GetLoadByFieldIndex(); |
| 337 indices->set(index, Smi::FromInt(load_by_field_index)); | 339 indices->set(index, Smi::FromInt(load_by_field_index)); |
| 338 } else { | 340 } else { |
| 339 indices = Handle<FixedArray>(); | 341 indices = Handle<FixedArray>(); |
| 342 } |
| 340 } | 343 } |
| 344 index++; |
| 341 } | 345 } |
| 342 index++; | 346 DCHECK_EQ(index, storage->length()); |
| 347 |
| 348 // Mark the {storage} as copy-on-write, so we can use this |
| 349 // as JSArray elements backing store directly w/o copying. |
| 350 storage->set_map(isolate->heap()->fixed_cow_array_map()); |
| 343 } | 351 } |
| 344 DCHECK(index == storage->length()); | |
| 345 | 352 |
| 346 DescriptorArray::SetEnumCache(descs, isolate, storage, indices); | 353 DescriptorArray::SetEnumCache(descs, isolate, storage, indices); |
| 347 if (cache_enum_length) { | 354 if (cache_enum_length) { |
| 348 map->SetEnumLength(own_property_count); | 355 map->SetEnumLength(own_property_count); |
| 349 } | 356 } |
| 350 return storage; | 357 return storage; |
| 351 } | 358 } |
| 352 | 359 |
| 353 template <bool fast_properties> | 360 template <bool fast_properties> |
| 354 MaybeHandle<FixedArray> GetOwnKeysWithElements(Isolate* isolate, | 361 MaybeHandle<FixedArray> GetOwnKeysWithElements(Isolate* isolate, |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 435 // Assume that there are elements. | 442 // Assume that there are elements. |
| 436 return MaybeHandle<FixedArray>(); | 443 return MaybeHandle<FixedArray>(); |
| 437 } | 444 } |
| 438 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); | 445 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); |
| 439 if (number_of_own_descriptors == 0) { | 446 if (number_of_own_descriptors == 0) { |
| 440 map->SetEnumLength(0); | 447 map->SetEnumLength(0); |
| 441 return isolate_->factory()->empty_fixed_array(); | 448 return isolate_->factory()->empty_fixed_array(); |
| 442 } | 449 } |
| 443 // We have no elements but possibly enumerable property keys, hence we can | 450 // We have no elements but possibly enumerable property keys, hence we can |
| 444 // directly initialize the enum cache. | 451 // directly initialize the enum cache. |
| 445 Handle<FixedArray> keys = GetFastEnumPropertyKeys(isolate_, object); | 452 return GetFastEnumPropertyKeys(isolate_, object); |
| 446 if (is_for_in_) return keys; | |
| 447 // Do not leak the enum cache as it might end up as an elements backing store. | |
| 448 return isolate_->factory()->CopyFixedArray(keys); | |
| 449 } | 453 } |
| 450 | 454 |
| 451 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysSlow( | 455 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysSlow( |
| 452 GetKeysConversion keys_conversion) { | 456 GetKeysConversion keys_conversion) { |
| 453 KeyAccumulator accumulator(isolate_, mode_, filter_); | 457 KeyAccumulator accumulator(isolate_, mode_, filter_); |
| 454 accumulator.set_is_for_in(is_for_in_); | 458 accumulator.set_is_for_in(is_for_in_); |
| 455 accumulator.set_last_non_empty_prototype(last_non_empty_prototype_); | 459 accumulator.set_last_non_empty_prototype(last_non_empty_prototype_); |
| 456 | 460 |
| 457 MAYBE_RETURN(accumulator.CollectKeys(receiver_, receiver_), | 461 MAYBE_RETURN(accumulator.CollectKeys(receiver_, receiver_), |
| 458 MaybeHandle<FixedArray>()); | 462 MaybeHandle<FixedArray>()); |
| (...skipping 424 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 883 isolate_, keys, | 887 isolate_, keys, |
| 884 KeyAccumulator::GetKeys(target, KeyCollectionMode::kOwnOnly, filter_, | 888 KeyAccumulator::GetKeys(target, KeyCollectionMode::kOwnOnly, filter_, |
| 885 GetKeysConversion::kConvertToString, is_for_in_), | 889 GetKeysConversion::kConvertToString, is_for_in_), |
| 886 Nothing<bool>()); | 890 Nothing<bool>()); |
| 887 Maybe<bool> result = AddKeysFromJSProxy(proxy, keys); | 891 Maybe<bool> result = AddKeysFromJSProxy(proxy, keys); |
| 888 return result; | 892 return result; |
| 889 } | 893 } |
| 890 | 894 |
| 891 } // namespace internal | 895 } // namespace internal |
| 892 } // namespace v8 | 896 } // namespace v8 |
| OLD | NEW |