Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1007)

Side by Side Diff: src/elements.cc

Issue 2232063002: [builtins] WIP: Array indexOf in TurboFan/Runtime (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Move fast path FastElements -> FastSmiOrObjectElements Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/elements.h ('k') | src/js/array.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 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/elements.h" 5 #include "src/elements.h"
6 6
7 #include "src/arguments.h" 7 #include "src/arguments.h"
8 #include "src/conversions.h" 8 #include "src/conversions.h"
9 #include "src/factory.h" 9 #include "src/factory.h"
10 #include "src/isolate-inl.h" 10 #include "src/isolate-inl.h"
(...skipping 471 matching lines...) Expand 10 before | Expand all | Expand 10 after
482 Handle<Object> element_k; 482 Handle<Object> element_k;
483 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k, 483 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,
484 Object::GetProperty(&it), Nothing<bool>()); 484 Object::GetProperty(&it), Nothing<bool>());
485 485
486 if (value->SameValueZero(*element_k)) return Just(true); 486 if (value->SameValueZero(*element_k)) return Just(true);
487 } 487 }
488 488
489 return Just(false); 489 return Just(false);
490 } 490 }
491 491
492 static Maybe<int64_t> IndexOfValueSlowPath(Isolate* isolate,
493 Handle<JSObject> receiver,
494 Handle<Object> value,
495 uint32_t start_from,
496 uint32_t length) {
497 for (uint32_t k = start_from; k < length; ++k) {
498 LookupIterator it(isolate, receiver, k);
499 if (!it.IsFound()) {
500 continue;
501 }
502 Handle<Object> element_k;
503 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
504 isolate, element_k, Object::GetProperty(&it), Nothing<int64_t>());
505
506 if (value->StrictEquals(*element_k)) return Just<int64_t>(k);
507 }
508
509 return Just<int64_t>(-1);
510 }
511
492 // Base class for element handler implementations. Contains the 512 // Base class for element handler implementations. Contains the
493 // the common logic for objects with different ElementsKinds. 513 // the common logic for objects with different ElementsKinds.
494 // Subclasses must specialize method for which the element 514 // Subclasses must specialize method for which the element
495 // implementation differs from the base class implementation. 515 // implementation differs from the base class implementation.
496 // 516 //
497 // This class is intended to be used in the following way: 517 // This class is intended to be used in the following way:
498 // 518 //
499 // class SomeElementsAccessor : 519 // class SomeElementsAccessor :
500 // public ElementsAccessorBase<SomeElementsAccessor, 520 // public ElementsAccessorBase<SomeElementsAccessor,
501 // BackingStoreClass> { 521 // BackingStoreClass> {
(...skipping 614 matching lines...) Expand 10 before | Expand all | Expand 10 after
1116 return IncludesValueSlowPath(isolate, receiver, value, start_from, length); 1136 return IncludesValueSlowPath(isolate, receiver, value, start_from, length);
1117 } 1137 }
1118 1138
1119 Maybe<bool> IncludesValue(Isolate* isolate, Handle<JSObject> receiver, 1139 Maybe<bool> IncludesValue(Isolate* isolate, Handle<JSObject> receiver,
1120 Handle<Object> value, uint32_t start_from, 1140 Handle<Object> value, uint32_t start_from,
1121 uint32_t length) final { 1141 uint32_t length) final {
1122 return Subclass::IncludesValueImpl(isolate, receiver, value, start_from, 1142 return Subclass::IncludesValueImpl(isolate, receiver, value, start_from,
1123 length); 1143 length);
1124 } 1144 }
1125 1145
1146 static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
1147 Handle<JSObject> receiver,
1148 Handle<Object> value,
1149 uint32_t start_from, uint32_t length) {
1150 return IndexOfValueSlowPath(isolate, receiver, value, start_from, length);
1151 }
1152
1153 Maybe<int64_t> IndexOfValue(Isolate* isolate, Handle<JSObject> receiver,
1154 Handle<Object> value, uint32_t start_from,
1155 uint32_t length) final {
1156 return Subclass::IndexOfValueImpl(isolate, receiver, value, start_from,
1157 length);
1158 }
1159
1126 static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store, 1160 static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
1127 uint32_t entry) { 1161 uint32_t entry) {
1128 return entry; 1162 return entry;
1129 } 1163 }
1130 1164
1131 static uint32_t GetEntryForIndexImpl(JSObject* holder, 1165 static uint32_t GetEntryForIndexImpl(JSObject* holder,
1132 FixedArrayBase* backing_store, 1166 FixedArrayBase* backing_store,
1133 uint32_t index, PropertyFilter filter) { 1167 uint32_t index, PropertyFilter filter) {
1134 if (IsHoleyElementsKind(kind())) { 1168 if (IsHoleyElementsKind(kind())) {
1135 return index < Subclass::GetCapacityImpl(holder, backing_store) && 1169 return index < Subclass::GetCapacityImpl(holder, backing_store) &&
(...skipping 428 matching lines...) Expand 10 before | Expand all | Expand 10 after
1564 length); 1598 length);
1565 } 1599 }
1566 dictionary = handle( 1600 dictionary = handle(
1567 SeededNumberDictionary::cast(receiver->elements()), isolate); 1601 SeededNumberDictionary::cast(receiver->elements()), isolate);
1568 break; 1602 break;
1569 } 1603 }
1570 } 1604 }
1571 } 1605 }
1572 return Just(false); 1606 return Just(false);
1573 } 1607 }
1608
1609 static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
1610 Handle<JSObject> receiver,
1611 Handle<Object> value,
1612 uint32_t start_from, uint32_t length) {
1613 DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
1614
1615 Handle<SeededNumberDictionary> dictionary(
1616 SeededNumberDictionary::cast(receiver->elements()), isolate);
1617 // Iterate through entire range, as accessing elements out of order is
1618 // observable.
1619 for (uint32_t k = start_from; k < length; ++k) {
1620 int entry = dictionary->FindEntry(k);
1621 if (entry == SeededNumberDictionary::kNotFound) {
1622 continue;
1623 }
1624
1625 PropertyDetails details = GetDetailsImpl(*dictionary, entry);
1626 switch (details.kind()) {
1627 case kData: {
1628 Object* element_k = dictionary->ValueAt(entry);
1629 if (value->StrictEquals(element_k)) {
1630 return Just<int64_t>(k);
1631 }
1632 break;
1633 }
1634 case kAccessor: {
1635 LookupIterator it(isolate, receiver, k,
1636 LookupIterator::OWN_SKIP_INTERCEPTOR);
1637 DCHECK(it.IsFound());
1638 DCHECK_EQ(it.state(), LookupIterator::ACCESSOR);
1639 Handle<Object> element_k;
1640
1641 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1642 isolate, element_k, JSObject::GetPropertyWithAccessor(&it),
1643 Nothing<int64_t>());
1644
1645 if (value->StrictEquals(*element_k)) return Just<int64_t>(k);
1646
1647 // Bailout to slow path if elements on prototype changed.
1648 if (!JSObject::PrototypeHasNoElements(isolate, *receiver)) {
1649 return IndexOfValueSlowPath(isolate, receiver, value, k + 1,
1650 length);
1651 }
1652
1653 // Continue if elements unchanged.
1654 if (*dictionary == receiver->elements()) continue;
1655
1656 // Otherwise, bailout or update elements.
1657 if (receiver->GetElementsKind() != DICTIONARY_ELEMENTS) {
1658 // Otherwise, switch to slow path.
1659 return IndexOfValueSlowPath(isolate, receiver, value, k + 1,
1660 length);
1661 }
1662 dictionary = handle(
1663 SeededNumberDictionary::cast(receiver->elements()), isolate);
1664 break;
1665 }
1666 }
1667 }
1668 return Just<int64_t>(-1);
1669 }
1574 }; 1670 };
1575 1671
1576 1672
1577 // Super class for all fast element arrays. 1673 // Super class for all fast element arrays.
1578 template <typename Subclass, typename KindTraits> 1674 template <typename Subclass, typename KindTraits>
1579 class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> { 1675 class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
1580 public: 1676 public:
1581 explicit FastElementsAccessor(const char* name) 1677 explicit FastElementsAccessor(const char* name)
1582 : ElementsAccessorBase<Subclass, KindTraits>(name) {} 1678 : ElementsAccessorBase<Subclass, KindTraits>(name) {}
1583 1679
(...skipping 686 matching lines...) Expand 10 before | Expand all | Expand 10 after
2270 TYPED_ARRAYS(TYPED_ARRAY_CASE) 2366 TYPED_ARRAYS(TYPED_ARRAY_CASE)
2271 #undef TYPED_ARRAY_CASE 2367 #undef TYPED_ARRAY_CASE
2272 // This function is currently only used for JSArrays with non-zero 2368 // This function is currently only used for JSArrays with non-zero
2273 // length. 2369 // length.
2274 UNREACHABLE(); 2370 UNREACHABLE();
2275 break; 2371 break;
2276 case NO_ELEMENTS: 2372 case NO_ELEMENTS:
2277 break; // Nothing to do. 2373 break; // Nothing to do.
2278 } 2374 }
2279 } 2375 }
2376
2377 static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
2378 Handle<JSObject> receiver,
2379 Handle<Object> search_value,
2380 uint32_t start_from, uint32_t length) {
2381 DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
2382 DisallowHeapAllocation no_gc;
2383 FixedArrayBase* elements_base = receiver->elements();
2384 Object* value = *search_value;
2385
2386 if (start_from >= length) return Just<int64_t>(-1);
2387
2388 length = std::min(static_cast<uint32_t>(elements_base->length()), length);
2389
2390 // Only FAST_{,HOLEY_}ELEMENTS can store non-numbers.
2391 if (!value->IsNumber() && !IsFastObjectElementsKind(Subclass::kind())) {
2392 return Just<int64_t>(-1);
2393 }
2394 // NaN can never be found by strict equality.
2395 if (value->IsNaN()) return Just<int64_t>(-1);
2396
2397 FixedArray* elements = FixedArray::cast(receiver->elements());
2398 for (uint32_t k = start_from; k < length; ++k) {
2399 if (value->StrictEquals(elements->get(k))) return Just<int64_t>(k);
2400 }
2401 return Just<int64_t>(-1);
2402 }
2280 }; 2403 };
2281 2404
2282 2405
2283 class FastPackedSmiElementsAccessor 2406 class FastPackedSmiElementsAccessor
2284 : public FastSmiOrObjectElementsAccessor< 2407 : public FastSmiOrObjectElementsAccessor<
2285 FastPackedSmiElementsAccessor, 2408 FastPackedSmiElementsAccessor,
2286 ElementsKindTraits<FAST_SMI_ELEMENTS> > { 2409 ElementsKindTraits<FAST_SMI_ELEMENTS> > {
2287 public: 2410 public:
2288 explicit FastPackedSmiElementsAccessor(const char* name) 2411 explicit FastPackedSmiElementsAccessor(const char* name)
2289 : FastSmiOrObjectElementsAccessor< 2412 : FastSmiOrObjectElementsAccessor<
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
2391 case NO_ELEMENTS: 2514 case NO_ELEMENTS:
2392 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS: 2515 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
2393 TYPED_ARRAYS(TYPED_ARRAY_CASE) 2516 TYPED_ARRAYS(TYPED_ARRAY_CASE)
2394 #undef TYPED_ARRAY_CASE 2517 #undef TYPED_ARRAY_CASE
2395 // This function is currently only used for JSArrays with non-zero 2518 // This function is currently only used for JSArrays with non-zero
2396 // length. 2519 // length.
2397 UNREACHABLE(); 2520 UNREACHABLE();
2398 break; 2521 break;
2399 } 2522 }
2400 } 2523 }
2524
2525 static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
2526 Handle<JSObject> receiver,
2527 Handle<Object> search_value,
2528 uint32_t start_from, uint32_t length) {
2529 DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
2530 DisallowHeapAllocation no_gc;
2531 FixedArrayBase* elements_base = receiver->elements();
2532 Object* value = *search_value;
2533
2534 if (start_from >= length) return Just<int64_t>(-1);
2535
2536 length = std::min(static_cast<uint32_t>(elements_base->length()), length);
2537
2538 if (!value->IsNumber()) {
2539 return Just<int64_t>(-1);
2540 }
2541 if (value->IsNaN()) {
2542 return Just<int64_t>(-1);
2543 }
2544 double numeric_search_value = value->Number();
2545 FixedDoubleArray* elements = FixedDoubleArray::cast(receiver->elements());
2546
2547 for (uint32_t k = start_from; k < length; ++k) {
2548 if (elements->is_the_hole(k)) {
2549 continue;
2550 }
2551 if (elements->get_scalar(k) == numeric_search_value) {
2552 return Just<int64_t>(k);
2553 }
2554 }
2555 return Just<int64_t>(-1);
2556 }
2401 }; 2557 };
2402 2558
2403 2559
2404 class FastPackedDoubleElementsAccessor 2560 class FastPackedDoubleElementsAccessor
2405 : public FastDoubleElementsAccessor< 2561 : public FastDoubleElementsAccessor<
2406 FastPackedDoubleElementsAccessor, 2562 FastPackedDoubleElementsAccessor,
2407 ElementsKindTraits<FAST_DOUBLE_ELEMENTS> > { 2563 ElementsKindTraits<FAST_DOUBLE_ELEMENTS> > {
2408 public: 2564 public:
2409 explicit FastPackedDoubleElementsAccessor(const char* name) 2565 explicit FastPackedDoubleElementsAccessor(const char* name)
2410 : FastDoubleElementsAccessor< 2566 : FastDoubleElementsAccessor<
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
2584 } 2740 }
2585 return Just(false); 2741 return Just(false);
2586 } else { 2742 } else {
2587 for (uint32_t k = start_from; k < length; ++k) { 2743 for (uint32_t k = start_from; k < length; ++k) {
2588 double element_k = elements->get_scalar(k); 2744 double element_k = elements->get_scalar(k);
2589 if (std::isnan(element_k)) return Just(true); 2745 if (std::isnan(element_k)) return Just(true);
2590 } 2746 }
2591 return Just(false); 2747 return Just(false);
2592 } 2748 }
2593 } 2749 }
2750
2751 static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
2752 Handle<JSObject> receiver,
2753 Handle<Object> value,
2754 uint32_t start_from, uint32_t length) {
2755 DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
2756 DisallowHeapAllocation no_gc;
2757
2758 BackingStore* elements = BackingStore::cast(receiver->elements());
2759 if (!value->IsNumber()) return Just<int64_t>(-1);
2760
2761 double search_value = value->Number();
2762
2763 if (!std::isfinite(search_value)) {
2764 // Integral types cannot represent +Inf or NaN.
2765 if (AccessorClass::kind() < FLOAT32_ELEMENTS ||
2766 AccessorClass::kind() > FLOAT64_ELEMENTS) {
2767 return Just<int64_t>(-1);
2768 }
2769 } else if (search_value < std::numeric_limits<ctype>::lowest() ||
2770 search_value > std::numeric_limits<ctype>::max()) {
2771 // Return false if value can't be represented in this ElementsKind.
2772 return Just<int64_t>(-1);
2773 }
2774
2775 // Prototype has no elements, and not searching for the hole --- limit
2776 // search to backing store length.
2777 if (static_cast<uint32_t>(elements->length()) < length) {
2778 length = elements->length();
2779 }
2780
2781 if (std::isnan(search_value)) {
2782 return Just<int64_t>(-1);
2783 }
2784
2785 ctype typed_search_value = static_cast<ctype>(search_value);
2786 if (static_cast<double>(typed_search_value) != search_value) {
2787 return Just<int64_t>(-1); // Loss of precision.
2788 }
2789
2790 for (uint32_t k = start_from; k < length; ++k) {
2791 ctype element_k = elements->get_scalar(k);
2792 if (element_k == typed_search_value) return Just<int64_t>(k);
2793 }
2794 return Just<int64_t>(-1);
2795 }
2594 }; 2796 };
2595 2797
2596 #define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size) \ 2798 #define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size) \
2597 typedef TypedElementsAccessor<TYPE##_ELEMENTS, ctype> \ 2799 typedef TypedElementsAccessor<TYPE##_ELEMENTS, ctype> \
2598 Fixed##Type##ElementsAccessor; 2800 Fixed##Type##ElementsAccessor;
2599 2801
2600 TYPED_ARRAYS(FIXED_ELEMENTS_ACCESSOR) 2802 TYPED_ARRAYS(FIXED_ELEMENTS_ACCESSOR)
2601 #undef FIXED_ELEMENTS_ACCESSOR 2803 #undef FIXED_ELEMENTS_ACCESSOR
2602 2804
2603 template <typename Subclass, typename ArgumentsAccessor, typename KindTraits> 2805 template <typename Subclass, typename ArgumentsAccessor, typename KindTraits>
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after
2862 if (object->map() != *original_map) { 3064 if (object->map() != *original_map) {
2863 // Some mutation occurred in accessor. Abort "fast" path 3065 // Some mutation occurred in accessor. Abort "fast" path
2864 return IncludesValueSlowPath(isolate, object, value, k + 1, length); 3066 return IncludesValueSlowPath(isolate, object, value, k + 1, length);
2865 } 3067 }
2866 } else if (value->SameValueZero(*element_k)) { 3068 } else if (value->SameValueZero(*element_k)) {
2867 return Just(true); 3069 return Just(true);
2868 } 3070 }
2869 } 3071 }
2870 return Just(false); 3072 return Just(false);
2871 } 3073 }
3074
3075 static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
3076 Handle<JSObject> object,
3077 Handle<Object> value,
3078 uint32_t start_from, uint32_t length) {
3079 DCHECK(JSObject::PrototypeHasNoElements(isolate, *object));
3080 Handle<Map> original_map = handle(object->map(), isolate);
3081 FixedArray* parameter_map = FixedArray::cast(object->elements());
3082
3083 for (uint32_t k = start_from; k < length; ++k) {
3084 uint32_t entry =
3085 GetEntryForIndexImpl(*object, parameter_map, k, ALL_PROPERTIES);
3086 if (entry == kMaxUInt32) {
3087 continue;
3088 }
3089
3090 Handle<Object> element_k = GetImpl(parameter_map, entry);
3091
3092 if (element_k->IsAccessorPair()) {
3093 LookupIterator it(isolate, object, k, LookupIterator::OWN);
3094 DCHECK(it.IsFound());
3095 DCHECK_EQ(it.state(), LookupIterator::ACCESSOR);
3096 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,
3097 Object::GetPropertyWithAccessor(&it),
3098 Nothing<int64_t>());
3099
3100 if (value->StrictEquals(*element_k)) {
3101 return Just<int64_t>(k);
3102 }
3103
3104 if (object->map() != *original_map) {
3105 // Some mutation occurred in accessor. Abort "fast" path.
3106 return IndexOfValueSlowPath(isolate, object, value, k + 1, length);
3107 }
3108 } else if (value->StrictEquals(*element_k)) {
3109 return Just<int64_t>(k);
3110 }
3111 }
3112 return Just<int64_t>(-1);
3113 }
2872 }; 3114 };
2873 3115
2874 3116
2875 class SlowSloppyArgumentsElementsAccessor 3117 class SlowSloppyArgumentsElementsAccessor
2876 : public SloppyArgumentsElementsAccessor< 3118 : public SloppyArgumentsElementsAccessor<
2877 SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor, 3119 SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
2878 ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> > { 3120 ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> > {
2879 public: 3121 public:
2880 explicit SlowSloppyArgumentsElementsAccessor(const char* name) 3122 explicit SlowSloppyArgumentsElementsAccessor(const char* name)
2881 : SloppyArgumentsElementsAccessor< 3123 : SloppyArgumentsElementsAccessor<
(...skipping 587 matching lines...) Expand 10 before | Expand all | Expand 10 after
3469 insertion_index += len; 3711 insertion_index += len;
3470 } 3712 }
3471 3713
3472 DCHECK_EQ(insertion_index, result_len); 3714 DCHECK_EQ(insertion_index, result_len);
3473 return result_array; 3715 return result_array;
3474 } 3716 }
3475 3717
3476 ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL; 3718 ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL;
3477 } // namespace internal 3719 } // namespace internal
3478 } // namespace v8 3720 } // namespace v8
OLDNEW
« no previous file with comments | « src/elements.h ('k') | src/js/array.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698