Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |