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 |