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/elements.h" | 7 #include "src/elements.h" |
8 #include "src/factory.h" | 8 #include "src/factory.h" |
9 #include "src/isolate-inl.h" | 9 #include "src/isolate-inl.h" |
10 #include "src/objects-inl.h" | 10 #include "src/objects-inl.h" |
(...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
356 USE(first_non_empty_prototype); | 356 USE(first_non_empty_prototype); |
357 return; | 357 return; |
358 } | 358 } |
359 DCHECK(has_empty_prototype_); | 359 DCHECK(has_empty_prototype_); |
360 is_receiver_simple_enum_ = | 360 is_receiver_simple_enum_ = |
361 receiver_->map()->EnumLength() != kInvalidEnumCacheSentinel && | 361 receiver_->map()->EnumLength() != kInvalidEnumCacheSentinel && |
362 !JSObject::cast(*receiver_)->HasEnumerableElements(); | 362 !JSObject::cast(*receiver_)->HasEnumerableElements(); |
363 } | 363 } |
364 | 364 |
365 namespace { | 365 namespace { |
| 366 |
| 367 template <bool fast_properties> |
366 Handle<FixedArray> GetOwnKeysWithElements(Isolate* isolate, | 368 Handle<FixedArray> GetOwnKeysWithElements(Isolate* isolate, |
367 Handle<JSObject> object, | 369 Handle<JSObject> object, |
368 GetKeysConversion convert) { | 370 GetKeysConversion convert) { |
369 Handle<FixedArray> keys = JSObject::GetFastEnumPropertyKeys(isolate, object); | 371 Handle<FixedArray> keys; |
370 ElementsAccessor* accessor = object->GetElementsAccessor(); | 372 ElementsAccessor* accessor = object->GetElementsAccessor(); |
| 373 if (fast_properties) { |
| 374 keys = JSObject::GetFastEnumPropertyKeys(isolate, object); |
| 375 } else { |
| 376 // TODO(cbruni): preallocate big enough array to also hold elements. |
| 377 keys = JSObject::GetEnumPropertyKeys(object); |
| 378 } |
371 Handle<FixedArray> result = | 379 Handle<FixedArray> result = |
372 accessor->PrependElementIndices(object, keys, convert, ONLY_ENUMERABLE); | 380 accessor->PrependElementIndices(object, keys, convert, ONLY_ENUMERABLE); |
373 | 381 |
374 if (FLAG_trace_for_in_enumerate) { | 382 if (FLAG_trace_for_in_enumerate) { |
375 PrintF("| strings=%d symbols=0 elements=%u || prototypes>=1 ||\n", | 383 PrintF("| strings=%d symbols=0 elements=%u || prototypes>=1 ||\n", |
376 keys->length(), result->length() - keys->length()); | 384 keys->length(), result->length() - keys->length()); |
377 } | 385 } |
378 return result; | 386 return result; |
379 } | 387 } |
380 | 388 |
381 MaybeHandle<FixedArray> GetOwnKeysWithUninitializedEnumCache( | 389 MaybeHandle<FixedArray> GetOwnKeysWithUninitializedEnumCache( |
382 Isolate* isolate, Handle<JSObject> object) { | 390 Isolate* isolate, Handle<JSObject> object) { |
383 // Uninitalized enum cache | 391 // Uninitalized enum cache |
384 Map* map = object->map(); | 392 Map* map = object->map(); |
385 if (object->elements() != isolate->heap()->empty_fixed_array() || | 393 if (object->elements() != isolate->heap()->empty_fixed_array() || |
386 object->elements() != isolate->heap()->empty_slow_element_dictionary()) { | 394 object->elements() != isolate->heap()->empty_slow_element_dictionary()) { |
387 // Assume that there are elements. | 395 // Assume that there are elements. |
388 return MaybeHandle<FixedArray>(); | 396 return MaybeHandle<FixedArray>(); |
389 } | 397 } |
390 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); | 398 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); |
391 if (number_of_own_descriptors == 0) { | 399 if (number_of_own_descriptors == 0) { |
392 map->SetEnumLength(0); | 400 map->SetEnumLength(0); |
393 return isolate->factory()->empty_fixed_array(); | 401 return isolate->factory()->empty_fixed_array(); |
394 } | 402 } |
395 // We have no elements but possibly enumerable property keys, hence we can | 403 // We have no elements but possibly enumerable property keys, hence we can |
396 // directly initialize the enum cache. | 404 // directly initialize the enum cache. |
397 return JSObject::GetFastEnumPropertyKeys(isolate, object); | 405 return JSObject::GetFastEnumPropertyKeys(isolate, object); |
398 } | 406 } |
399 | 407 |
| 408 bool OnlyHasSimpleProperties(Map* map) { |
| 409 return map->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER; |
| 410 } |
| 411 |
400 } // namespace | 412 } // namespace |
401 | 413 |
402 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeys(GetKeysConversion convert) { | 414 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeys(GetKeysConversion convert) { |
403 Handle<FixedArray> keys; | 415 Handle<FixedArray> keys; |
404 if (GetKeysFast(convert).ToHandle(&keys)) { | 416 if (GetKeysFast(convert).ToHandle(&keys)) { |
405 return keys; | 417 return keys; |
406 } | 418 } |
407 return GetKeysSlow(convert); | 419 return GetKeysSlow(convert); |
408 } | 420 } |
409 | 421 |
410 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysFast( | 422 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysFast( |
411 GetKeysConversion convert) { | 423 GetKeysConversion convert) { |
412 bool own_only = has_empty_prototype_ || type_ == OWN_ONLY; | 424 bool own_only = has_empty_prototype_ || type_ == OWN_ONLY; |
413 if (!own_only || !receiver_->map()->OnlyHasSimpleProperties()) { | 425 Map* map = receiver_->map(); |
| 426 if (!own_only || !OnlyHasSimpleProperties(map)) { |
414 return MaybeHandle<FixedArray>(); | 427 return MaybeHandle<FixedArray>(); |
415 } | 428 } |
416 | 429 |
417 Handle<FixedArray> keys; | 430 // From this point on we are certiain to only collect own keys. |
418 DCHECK(receiver_->IsJSObject()); | 431 DCHECK(receiver_->IsJSObject()); |
419 Handle<JSObject> object = Handle<JSObject>::cast(receiver_); | 432 Handle<JSObject> object = Handle<JSObject>::cast(receiver_); |
420 | 433 |
| 434 // Do not try to use the enum-cache for dict-mode objects. |
| 435 if (map->is_dictionary_map()) { |
| 436 return GetOwnKeysWithElements<false>(isolate_, object, convert); |
| 437 } |
421 int enum_length = receiver_->map()->EnumLength(); | 438 int enum_length = receiver_->map()->EnumLength(); |
422 if (enum_length == kInvalidEnumCacheSentinel) { | 439 if (enum_length == kInvalidEnumCacheSentinel) { |
| 440 Handle<FixedArray> keys; |
423 // Try initializing the enum cache and return own properties. | 441 // Try initializing the enum cache and return own properties. |
424 if (GetOwnKeysWithUninitializedEnumCache(isolate_, object) | 442 if (GetOwnKeysWithUninitializedEnumCache(isolate_, object) |
425 .ToHandle(&keys)) { | 443 .ToHandle(&keys)) { |
426 if (FLAG_trace_for_in_enumerate) { | 444 if (FLAG_trace_for_in_enumerate) { |
427 PrintF("| strings=%d symbols=0 elements=0 || prototypes>=1 ||\n", | 445 PrintF("| strings=%d symbols=0 elements=0 || prototypes>=1 ||\n", |
428 keys->length()); | 446 keys->length()); |
429 } | 447 } |
430 | |
431 is_receiver_simple_enum_ = | 448 is_receiver_simple_enum_ = |
432 object->map()->EnumLength() != kInvalidEnumCacheSentinel; | 449 object->map()->EnumLength() != kInvalidEnumCacheSentinel; |
433 return keys; | 450 return keys; |
434 } | 451 } |
435 } | 452 } |
436 // The properties-only case failed because there were probably elements on the | 453 // The properties-only case failed because there were probably elements on the |
437 // receiver. | 454 // receiver. |
438 return GetOwnKeysWithElements(isolate_, object, convert); | 455 return GetOwnKeysWithElements<true>(isolate_, object, convert); |
439 } | 456 } |
440 | 457 |
441 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysSlow( | 458 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysSlow( |
442 GetKeysConversion convert) { | 459 GetKeysConversion convert) { |
443 return JSReceiver::GetKeys(receiver_, type_, ENUMERABLE_STRINGS, KEEP_NUMBERS, | 460 return JSReceiver::GetKeys(receiver_, type_, ENUMERABLE_STRINGS, KEEP_NUMBERS, |
444 filter_proxy_keys_); | 461 filter_proxy_keys_); |
445 } | 462 } |
446 | 463 |
447 } // namespace internal | 464 } // namespace internal |
448 } // namespace v8 | 465 } // namespace v8 |
OLD | NEW |