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

Side by Side Diff: src/elements.cc

Issue 2146293003: [builtins] implement Array.prototype.includes in TurboFan (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Add a basic impl in ElementsAccessor, cleanup %ArrayIncludes_Slow, lots of new tests Created 4 years, 5 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
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 450 matching lines...) Expand 10 before | Expand all | Expand 10 after
461 } cmp; 461 } cmp;
462 Object** start = 462 Object** start =
463 reinterpret_cast<Object**>(indices->GetFirstElementAddress()); 463 reinterpret_cast<Object**>(indices->GetFirstElementAddress());
464 std::sort(start, start + sort_size, cmp); 464 std::sort(start, start + sort_size, cmp);
465 if (write_barrier_mode != SKIP_WRITE_BARRIER) { 465 if (write_barrier_mode != SKIP_WRITE_BARRIER) {
466 FIXED_ARRAY_ELEMENTS_WRITE_BARRIER(indices->GetIsolate()->heap(), *indices, 466 FIXED_ARRAY_ELEMENTS_WRITE_BARRIER(indices->GetIsolate()->heap(), *indices,
467 0, sort_size); 467 0, sort_size);
468 } 468 }
469 } 469 }
470 470
471 static Maybe<bool> IncludesValueSlowPath(Isolate* isolate,
472 Handle<JSObject> receiver,
473 Handle<Object> value,
474 uint32_t start_from, uint32_t length) {
475 bool search_for_hole = value->IsUndefined(isolate);
476 for (uint32_t k = start_from; k < length; ++k) {
477 LookupIterator it(isolate, receiver, k);
478 if (!it.IsFound()) {
479 if (search_for_hole) return Just(true);
480 continue;
481 }
482 Handle<Object> element_k;
483 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,
484 Object::GetProperty(&it), Nothing<bool>());
485
486 if (value->SameValueZero(*element_k)) return Just(true);
487 }
488
489 return Just(false);
490 }
491
471 // Base class for element handler implementations. Contains the 492 // Base class for element handler implementations. Contains the
472 // the common logic for objects with different ElementsKinds. 493 // the common logic for objects with different ElementsKinds.
473 // Subclasses must specialize method for which the element 494 // Subclasses must specialize method for which the element
474 // implementation differs from the base class implementation. 495 // implementation differs from the base class implementation.
475 // 496 //
476 // This class is intended to be used in the following way: 497 // This class is intended to be used in the following way:
477 // 498 //
478 // class SomeElementsAccessor : 499 // class SomeElementsAccessor :
479 // public ElementsAccessorBase<SomeElementsAccessor, 500 // public ElementsAccessorBase<SomeElementsAccessor,
480 // BackingStoreClass> { 501 // BackingStoreClass> {
(...skipping 558 matching lines...) Expand 10 before | Expand all | Expand 10 after
1039 1060
1040 static uint32_t GetCapacityImpl(JSObject* holder, 1061 static uint32_t GetCapacityImpl(JSObject* holder,
1041 FixedArrayBase* backing_store) { 1062 FixedArrayBase* backing_store) {
1042 return backing_store->length(); 1063 return backing_store->length();
1043 } 1064 }
1044 1065
1045 uint32_t GetCapacity(JSObject* holder, FixedArrayBase* backing_store) final { 1066 uint32_t GetCapacity(JSObject* holder, FixedArrayBase* backing_store) final {
1046 return Subclass::GetCapacityImpl(holder, backing_store); 1067 return Subclass::GetCapacityImpl(holder, backing_store);
1047 } 1068 }
1048 1069
1070 static Maybe<bool> IncludesValueImpl(Isolate* isolate,
1071 Handle<JSReceiver> receiver,
1072 Handle<Object> value,
1073 uint32_t start_from, uint32_t length) {
1074 UNREACHABLE();
caitp 2016/07/21 03:28:55 mostly for debugging, could make this fall back to
1075 }
1076
1077 Maybe<bool> IncludesValue(Isolate* isolate, Handle<JSObject> receiver,
1078 Handle<Object> value, uint32_t start_from,
1079 uint32_t length) final {
1080 return Subclass::IncludesValueImpl(isolate, receiver, value, start_from,
1081 length);
1082 }
1083
1049 static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store, 1084 static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
1050 uint32_t entry) { 1085 uint32_t entry) {
1051 return entry; 1086 return entry;
1052 } 1087 }
1053 1088
1054 static uint32_t GetEntryForIndexImpl(JSObject* holder, 1089 static uint32_t GetEntryForIndexImpl(JSObject* holder,
1055 FixedArrayBase* backing_store, 1090 FixedArrayBase* backing_store,
1056 uint32_t index, PropertyFilter filter) { 1091 uint32_t index, PropertyFilter filter) {
1057 if (IsHoleyElementsKind(kind())) { 1092 if (IsHoleyElementsKind(kind())) {
1058 return index < Subclass::GetCapacityImpl(holder, backing_store) && 1093 return index < Subclass::GetCapacityImpl(holder, backing_store) &&
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after
1375 if (k == *undefined) continue; 1410 if (k == *undefined) continue;
1376 if (k == *the_hole) continue; 1411 if (k == *the_hole) continue;
1377 if (dictionary->IsDeleted(i)) continue; 1412 if (dictionary->IsDeleted(i)) continue;
1378 Object* value = dictionary->ValueAt(i); 1413 Object* value = dictionary->ValueAt(i);
1379 DCHECK(!value->IsTheHole(isolate)); 1414 DCHECK(!value->IsTheHole(isolate));
1380 DCHECK(!value->IsAccessorPair()); 1415 DCHECK(!value->IsAccessorPair());
1381 DCHECK(!value->IsAccessorInfo()); 1416 DCHECK(!value->IsAccessorInfo());
1382 accumulator->AddKey(value, convert); 1417 accumulator->AddKey(value, convert);
1383 } 1418 }
1384 } 1419 }
1420
1421 static Maybe<bool> IncludesValueImpl(Isolate* isolate,
1422 Handle<JSObject> receiver,
1423 Handle<Object> value,
1424 uint32_t start_from, uint32_t length) {
1425 Handle<SeededNumberDictionary> dictionary(
1426 SeededNumberDictionary::cast(receiver->elements()), isolate);
1427
1428 Handle<Map> original_map = handle(receiver->map(), isolate);
1429
1430 bool search_for_hole = value->IsUndefined(isolate);
1431
1432 // Iterate through entire range, as accessing elements out of order is
1433 // observable
1434 for (uint32_t k = start_from; k < length; ++k) {
caitp 2016/07/21 03:28:55 This comment _may_ be wrong --- if there's some so
Camillo Bruni 2016/07/21 08:01:55 Right, this is probably tricky to get fast always.
1435 int entry = dictionary->FindEntry(k);
1436 if (entry == SeededNumberDictionary::kNotFound) {
1437 if (search_for_hole) return Just(true);
1438 continue;
1439 }
1440
1441 PropertyDetails details = GetDetailsImpl(receiver->elements(), entry);
1442 switch (details.kind()) {
1443 case kData: {
1444 Object* element_k = dictionary->ValueAt(entry);
1445 if (value->SameValueZero(element_k)) return Just(true);
1446 break;
1447 }
1448 case kAccessor: {
1449 LookupIterator it(isolate, receiver, k, LookupIterator::OWN);
1450 DCHECK(it.IsFound());
1451 DCHECK_EQ(it.state(), LookupIterator::ACCESSOR);
1452 Handle<Object> element_k;
1453
1454 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1455 isolate, element_k, JSObject::GetPropertyWithAccessor(&it),
1456 Nothing<bool>());
1457
1458 if (value->SameValueZero(*element_k)) return Just(true);
1459
1460 if (receiver->map() != *original_map) {
1461 // Some mutation occurred in accessor. Abort "fast" path
1462 return IncludesValueSlowPath(isolate, receiver, value, k + 1,
1463 length);
1464 }
1465 break;
1466 }
1467 }
1468 }
1469 return Just(false);
1470 }
1385 }; 1471 };
1386 1472
1387 1473
1388 // Super class for all fast element arrays. 1474 // Super class for all fast element arrays.
1389 template <typename Subclass, typename KindTraits> 1475 template <typename Subclass, typename KindTraits>
1390 class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> { 1476 class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
1391 public: 1477 public:
1392 explicit FastElementsAccessor(const char* name) 1478 explicit FastElementsAccessor(const char* name)
1393 : ElementsAccessorBase<Subclass, KindTraits>(name) {} 1479 : ElementsAccessorBase<Subclass, KindTraits>(name) {}
1394 1480
(...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after
1735 DisallowHeapAllocation no_gc; 1821 DisallowHeapAllocation no_gc;
1736 heap->MoveElements(FixedArray::cast(*dst_elms), dst_index, src_index, 1822 heap->MoveElements(FixedArray::cast(*dst_elms), dst_index, src_index,
1737 len); 1823 len);
1738 } 1824 }
1739 } 1825 }
1740 if (hole_start != hole_end) { 1826 if (hole_start != hole_end) {
1741 dst_elms->FillWithHoles(hole_start, hole_end); 1827 dst_elms->FillWithHoles(hole_start, hole_end);
1742 } 1828 }
1743 } 1829 }
1744 1830
1831 static Maybe<bool> IncludesValueImpl(Isolate* isolate,
1832 Handle<JSObject> receiver,
1833 Handle<Object> search_value,
1834 uint32_t start_from, uint32_t length) {
1835 DisallowHeapAllocation no_gc;
1836 FixedArrayBase* elements_base = receiver->elements();
1837 Object* the_hole = isolate->heap()->the_hole_value();
1838 Object* undefined = isolate->heap()->undefined_value();
1839 Object* value = *search_value;
1840
1841 // Elements beyond the capacity of the backing store treated as undefined.
1842 if (value == undefined && elements_base->length() < length) {
caitp 2016/07/21 03:28:55 I think this assumption holds if there are no elem
1843 return Just(true);
1844 }
1845
1846 if (start_from >= length) return Just(false);
1847
1848 if (!value->IsNumber()) {
caitp 2016/07/21 03:28:55 I prefer not to add these sorts of fast paths in a
Camillo Bruni 2016/07/21 08:01:55 I'd vouch for exactly the opposite. TF and Cranksh
caitp 2016/07/21 20:32:29 Maybe the way to do this is to have just a C++ bui
1849 if (value == undefined) {
1850 // Only FAST_ELEMENTS, FAST_HOLEY_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS, and
1851 // FAST_HOLEY_DOUBLE_ELEMENTS can have `undefined` as a value.
1852 if (!IsFastObjectElementsKind(KindTraits::Kind) &&
1853 !IsFastHoleyElementsKind(KindTraits::Kind)) {
1854 return Just(false);
1855 }
1856 if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) {
1857 auto elements = FixedArray::cast(receiver->elements());
1858
1859 for (uint32_t k = start_from; k < length; ++k) {
1860 Object* element_k = elements->get(k);
1861
1862 if (IsFastHoleyElementsKind(KindTraits::Kind) &&
1863 element_k == the_hole) {
1864 return Just(true);
1865 }
1866 if (IsFastObjectElementsKind(KindTraits::Kind) &&
1867 element_k == undefined) {
1868 return Just(true);
1869 }
1870 }
1871 return Just(false);
1872 } else {
1873 // Loop searching for non-Number, non-Undefined elements
1874 auto elements = FixedDoubleArray::cast(receiver->elements());
1875
1876 for (uint32_t k = start_from; k < length; ++k) {
1877 if (IsFastHoleyElementsKind(KindTraits::Kind) &&
1878 elements->is_the_hole(k)) {
1879 return Just(true);
1880 }
1881 }
1882 return Just(false);
1883 }
1884 } else if (!IsFastObjectElementsKind(KindTraits::Kind)) {
1885 // Only Numbers can be represented as packed Smi or Double elements
1886 return Just(false);
1887 } else {
1888 auto elements = FixedArray::cast(receiver->elements());
1889
1890 for (uint32_t k = start_from; k < length; ++k) {
1891 Object* element_k = elements->get(k);
1892 if (IsFastHoleyElementsKind(KindTraits::Kind) &&
1893 element_k == the_hole) {
1894 continue;
1895 }
1896
1897 if (value->SameValueZero(element_k)) return Just(true);
1898 }
1899 return Just(false);
1900 }
1901 } else {
1902 if (!value->IsNaN()) {
1903 double search_value = value->Number();
1904 if (IsFastDoubleElementsKind(KindTraits::Kind)) {
1905 auto elements = FixedDoubleArray::cast(receiver->elements());
1906
1907 for (uint32_t k = start_from; k < length; ++k) {
1908 if (IsFastHoleyElementsKind(KindTraits::Kind) &&
1909 elements->is_the_hole(k)) {
1910 continue;
1911 }
1912 if (elements->get_scalar(k) == search_value) return Just(true);
1913 }
1914 return Just(false);
1915 } else {
1916 auto elements = FixedArray::cast(receiver->elements());
1917
1918 for (uint32_t k = start_from; k < length; ++k) {
1919 Object* element_k = elements->get(k);
1920 if (element_k->IsNumber() && element_k->Number() == search_value) {
1921 return Just(true);
1922 }
1923 }
1924 return Just(false);
1925 }
1926 } else {
1927 // NaN cannot be represented with Smi elements
1928 if (IsFastSmiElementsKind(KindTraits::Kind)) return Just(false);
1929
1930 if (IsFastDoubleElementsKind(KindTraits::Kind)) {
1931 auto elements = FixedDoubleArray::cast(receiver->elements());
1932
1933 for (uint32_t k = start_from; k < length; ++k) {
1934 if (IsFastHoleyElementsKind(KindTraits::Kind) &&
1935 elements->is_the_hole(k)) {
1936 continue;
1937 }
1938 if (std::isnan(elements->get_scalar(k))) return Just(true);
1939 }
1940 return Just(false);
1941 } else {
1942 auto elements = FixedArray::cast(receiver->elements());
1943
1944 for (uint32_t k = start_from; k < length; ++k) {
1945 if (elements->get(k)->IsNaN()) return Just(true);
1946 }
1947 return Just(false);
1948 }
1949 }
1950 }
1951 }
1952
1745 private: 1953 private:
1746 // SpliceShrinkStep might modify the backing_store. 1954 // SpliceShrinkStep might modify the backing_store.
1747 static void SpliceShrinkStep(Isolate* isolate, Handle<JSArray> receiver, 1955 static void SpliceShrinkStep(Isolate* isolate, Handle<JSArray> receiver,
1748 Handle<FixedArrayBase> backing_store, 1956 Handle<FixedArrayBase> backing_store,
1749 uint32_t start, uint32_t delete_count, 1957 uint32_t start, uint32_t delete_count,
1750 uint32_t add_count, uint32_t len, 1958 uint32_t add_count, uint32_t len,
1751 uint32_t new_length) { 1959 uint32_t new_length) {
1752 const int move_left_count = len - delete_count - start; 1960 const int move_left_count = len - delete_count - start;
1753 const int move_left_dst_index = start + add_count; 1961 const int move_left_dst_index = start + add_count;
1754 Subclass::MoveElements(isolate, receiver, backing_store, 1962 Subclass::MoveElements(isolate, receiver, backing_store,
(...skipping 668 matching lines...) Expand 10 before | Expand all | Expand 10 after
2423 list->set(insertion_index, Smi::FromInt(i), SKIP_WRITE_BARRIER); 2631 list->set(insertion_index, Smi::FromInt(i), SKIP_WRITE_BARRIER);
2424 } 2632 }
2425 insertion_index++; 2633 insertion_index++;
2426 } 2634 }
2427 2635
2428 Handle<FixedArrayBase> store(FixedArrayBase::cast(parameter_map->get(1))); 2636 Handle<FixedArrayBase> store(FixedArrayBase::cast(parameter_map->get(1)));
2429 return ArgumentsAccessor::DirectCollectElementIndicesImpl( 2637 return ArgumentsAccessor::DirectCollectElementIndicesImpl(
2430 isolate, object, store, convert, filter, list, nof_indices, 2638 isolate, object, store, convert, filter, list, nof_indices,
2431 insertion_index); 2639 insertion_index);
2432 } 2640 }
2641
2642 static Maybe<bool> IncludesValueImpl(Isolate* isolate,
2643 Handle<JSObject> object,
2644 Handle<Object> value,
2645 uint32_t start_from, uint32_t length) {
2646 Handle<Map> original_map = handle(object->map(), isolate);
2647 FixedArray* parameter_map = FixedArray::cast(object->elements());
2648 bool search_for_hole = value->IsUndefined(isolate);
2649
2650 for (uint32_t k = start_from; k < length; ++k) {
2651 uint32_t entry =
2652 GetEntryForIndexImpl(*object, parameter_map, k, ALL_PROPERTIES);
2653 if (entry == kMaxUInt32) {
2654 if (search_for_hole) return Just(true);
2655 continue;
2656 }
2657
2658 Handle<Object> element_k = GetImpl(parameter_map, entry);
2659
2660 if (element_k->IsAccessorPair()) {
2661 LookupIterator it(isolate, object, k, LookupIterator::OWN);
2662 DCHECK(it.IsFound());
2663 DCHECK_EQ(it.state(), LookupIterator::ACCESSOR);
2664 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,
2665 Object::GetPropertyWithAccessor(&it),
2666 Nothing<bool>());
2667
2668 if (value->SameValueZero(*element_k)) return Just(true);
2669
2670 if (object->map() != *original_map) {
2671 // Some mutation occurred in accessor. Abort "fast" path
2672 return IncludesValueSlowPath(isolate, object, value, k + 1, length);
caitp 2016/07/21 03:28:55 I don't think a map check is really adequate for t
Camillo Bruni 2016/07/21 08:01:55 You can only have a dictionary (with potential acc
caitp 2016/07/21 20:32:29 I agree that it only applies to the SlowArgumentsC
caitp 2016/07/26 21:09:45 the map-check was not enough --- I changed it to a
2673 }
2674 } else if (value->SameValueZero(*element_k)) {
2675 return Just(true);
2676 }
2677 }
2678 return Just(false);
2679 }
2433 }; 2680 };
2434 2681
2435 2682
2436 class SlowSloppyArgumentsElementsAccessor 2683 class SlowSloppyArgumentsElementsAccessor
2437 : public SloppyArgumentsElementsAccessor< 2684 : public SloppyArgumentsElementsAccessor<
2438 SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor, 2685 SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
2439 ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> > { 2686 ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> > {
2440 public: 2687 public:
2441 explicit SlowSloppyArgumentsElementsAccessor(const char* name) 2688 explicit SlowSloppyArgumentsElementsAccessor(const char* name)
2442 : SloppyArgumentsElementsAccessor< 2689 : SloppyArgumentsElementsAccessor<
(...skipping 587 matching lines...) Expand 10 before | Expand all | Expand 10 after
3030 insertion_index += len; 3277 insertion_index += len;
3031 } 3278 }
3032 3279
3033 DCHECK_EQ(insertion_index, result_len); 3280 DCHECK_EQ(insertion_index, result_len);
3034 return result_array; 3281 return result_array;
3035 } 3282 }
3036 3283
3037 ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL; 3284 ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL;
3038 } // namespace internal 3285 } // namespace internal
3039 } // namespace v8 3286 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698