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 |