| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1 | // Copyright 2012 the V8 project authors. All rights reserved. | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be | 
|  | 3 | // found in the LICENSE file. | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 4 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 5 | #include "src/elements.h" | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 6 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 7 | #include "src/arguments.h" | 
|  | 8 | #include "src/conversions.h" | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 9 | #include "src/factory.h" | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 10 | #include "src/isolate-inl.h" | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 11 | #include "src/messages.h" | 
|  | 12 | #include "src/objects-inl.h" | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 13 | #include "src/utils.h" | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 14 |  | 
|  | 15 | // Each concrete ElementsAccessor can handle exactly one ElementsKind, | 
|  | 16 | // several abstract ElementsAccessor classes are used to allow sharing | 
|  | 17 | // common code. | 
|  | 18 | // | 
|  | 19 | // Inheritance hierarchy: | 
|  | 20 | // - ElementsAccessorBase                        (abstract) | 
|  | 21 | //   - FastElementsAccessor                      (abstract) | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 22 | //     - FastSmiOrObjectElementsAccessor | 
|  | 23 | //       - FastPackedSmiElementsAccessor | 
|  | 24 | //       - FastHoleySmiElementsAccessor | 
|  | 25 | //       - FastPackedObjectElementsAccessor | 
|  | 26 | //       - FastHoleyObjectElementsAccessor | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 27 | //     - FastDoubleElementsAccessor | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 28 | //       - FastPackedDoubleElementsAccessor | 
|  | 29 | //       - FastHoleyDoubleElementsAccessor | 
|  | 30 | //   - TypedElementsAccessor: template, with instantiations: | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 31 | //     - FixedUint8ElementsAccessor | 
|  | 32 | //     - FixedInt8ElementsAccessor | 
|  | 33 | //     - FixedUint16ElementsAccessor | 
|  | 34 | //     - FixedInt16ElementsAccessor | 
|  | 35 | //     - FixedUint32ElementsAccessor | 
|  | 36 | //     - FixedInt32ElementsAccessor | 
|  | 37 | //     - FixedFloat32ElementsAccessor | 
|  | 38 | //     - FixedFloat64ElementsAccessor | 
|  | 39 | //     - FixedUint8ClampedElementsAccessor | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 40 | //   - DictionaryElementsAccessor | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 41 | //   - SloppyArgumentsElementsAccessor | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 42 | //     - FastSloppyArgumentsElementsAccessor | 
|  | 43 | //     - SlowSloppyArgumentsElementsAccessor | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 44 | //   - StringWrapperElementsAccessor | 
|  | 45 | //     - FastStringWrapperElementsAccessor | 
|  | 46 | //     - SlowStringWrapperElementsAccessor | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 47 |  | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 48 | namespace v8 { | 
|  | 49 | namespace internal { | 
|  | 50 |  | 
|  | 51 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 52 | namespace { | 
|  | 53 |  | 
|  | 54 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 55 | static const int kPackedSizeNotKnown = -1; | 
|  | 56 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 57 | enum Where { AT_START, AT_END }; | 
|  | 58 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 59 |  | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 60 | // First argument in list is the accessor class, the second argument is the | 
|  | 61 | // accessor ElementsKind, and the third is the backing store class.  Use the | 
|  | 62 | // fast element handler for smi-only arrays.  The implementation is currently | 
|  | 63 | // identical.  Note that the order must match that of the ElementsKind enum for | 
|  | 64 | // the |accessor_array[]| below to work. | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 65 | #define ELEMENTS_LIST(V)                                                      \ | 
|  | 66 | V(FastPackedSmiElementsAccessor, FAST_SMI_ELEMENTS, FixedArray)             \ | 
|  | 67 | V(FastHoleySmiElementsAccessor, FAST_HOLEY_SMI_ELEMENTS, FixedArray)        \ | 
|  | 68 | V(FastPackedObjectElementsAccessor, FAST_ELEMENTS, FixedArray)              \ | 
|  | 69 | V(FastHoleyObjectElementsAccessor, FAST_HOLEY_ELEMENTS, FixedArray)         \ | 
|  | 70 | V(FastPackedDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS, FixedDoubleArray) \ | 
|  | 71 | V(FastHoleyDoubleElementsAccessor, FAST_HOLEY_DOUBLE_ELEMENTS,              \ | 
|  | 72 | FixedDoubleArray)                                                         \ | 
|  | 73 | V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS, SeededNumberDictionary)  \ | 
|  | 74 | V(FastSloppyArgumentsElementsAccessor, FAST_SLOPPY_ARGUMENTS_ELEMENTS,      \ | 
|  | 75 | FixedArray)                                                               \ | 
|  | 76 | V(SlowSloppyArgumentsElementsAccessor, SLOW_SLOPPY_ARGUMENTS_ELEMENTS,      \ | 
|  | 77 | FixedArray)                                                               \ | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 78 | V(FastStringWrapperElementsAccessor, FAST_STRING_WRAPPER_ELEMENTS,          \ | 
|  | 79 | FixedArray)                                                               \ | 
|  | 80 | V(SlowStringWrapperElementsAccessor, SLOW_STRING_WRAPPER_ELEMENTS,          \ | 
|  | 81 | FixedArray)                                                               \ | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 82 | V(FixedUint8ElementsAccessor, UINT8_ELEMENTS, FixedUint8Array)              \ | 
|  | 83 | V(FixedInt8ElementsAccessor, INT8_ELEMENTS, FixedInt8Array)                 \ | 
|  | 84 | V(FixedUint16ElementsAccessor, UINT16_ELEMENTS, FixedUint16Array)           \ | 
|  | 85 | V(FixedInt16ElementsAccessor, INT16_ELEMENTS, FixedInt16Array)              \ | 
|  | 86 | V(FixedUint32ElementsAccessor, UINT32_ELEMENTS, FixedUint32Array)           \ | 
|  | 87 | V(FixedInt32ElementsAccessor, INT32_ELEMENTS, FixedInt32Array)              \ | 
|  | 88 | V(FixedFloat32ElementsAccessor, FLOAT32_ELEMENTS, FixedFloat32Array)        \ | 
|  | 89 | V(FixedFloat64ElementsAccessor, FLOAT64_ELEMENTS, FixedFloat64Array)        \ | 
|  | 90 | V(FixedUint8ClampedElementsAccessor, UINT8_CLAMPED_ELEMENTS,                \ | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 91 | FixedUint8ClampedArray) | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 92 |  | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 93 | template<ElementsKind Kind> class ElementsKindTraits { | 
|  | 94 | public: | 
|  | 95 | typedef FixedArrayBase BackingStore; | 
|  | 96 | }; | 
|  | 97 |  | 
|  | 98 | #define ELEMENTS_TRAITS(Class, KindParam, Store)               \ | 
|  | 99 | template<> class ElementsKindTraits<KindParam> {               \ | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 100 | public:   /* NOLINT */                                        \ | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 101 | static const ElementsKind Kind = KindParam;                  \ | 
|  | 102 | typedef Store BackingStore;                                  \ | 
|  | 103 | }; | 
|  | 104 | ELEMENTS_LIST(ELEMENTS_TRAITS) | 
|  | 105 | #undef ELEMENTS_TRAITS | 
|  | 106 |  | 
|  | 107 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 108 | MUST_USE_RESULT | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 109 | MaybeHandle<Object> ThrowArrayLengthRangeError(Isolate* isolate) { | 
|  | 110 | THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidArrayLength), | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 111 | Object); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 112 | } | 
|  | 113 |  | 
|  | 114 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 115 | void CopyObjectToObjectElements(FixedArrayBase* from_base, | 
|  | 116 | ElementsKind from_kind, uint32_t from_start, | 
|  | 117 | FixedArrayBase* to_base, ElementsKind to_kind, | 
|  | 118 | uint32_t to_start, int raw_copy_size) { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 119 | DCHECK(to_base->map() != | 
|  | 120 | from_base->GetIsolate()->heap()->fixed_cow_array_map()); | 
|  | 121 | DisallowHeapAllocation no_allocation; | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 122 | int copy_size = raw_copy_size; | 
|  | 123 | if (raw_copy_size < 0) { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 124 | DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd || | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 125 | raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 126 | copy_size = Min(from_base->length() - from_start, | 
|  | 127 | to_base->length() - to_start); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 128 | if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 129 | int start = to_start + copy_size; | 
|  | 130 | int length = to_base->length() - start; | 
|  | 131 | if (length > 0) { | 
|  | 132 | Heap* heap = from_base->GetHeap(); | 
|  | 133 | MemsetPointer(FixedArray::cast(to_base)->data_start() + start, | 
|  | 134 | heap->the_hole_value(), length); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 135 | } | 
|  | 136 | } | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 137 | } | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 138 | DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() && | 
|  | 139 | (copy_size + static_cast<int>(from_start)) <= from_base->length()); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 140 | if (copy_size == 0) return; | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 141 | FixedArray* from = FixedArray::cast(from_base); | 
|  | 142 | FixedArray* to = FixedArray::cast(to_base); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 143 | DCHECK(IsFastSmiOrObjectElementsKind(from_kind) || | 
|  | 144 | from_kind == FAST_STRING_WRAPPER_ELEMENTS); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 145 | DCHECK(IsFastSmiOrObjectElementsKind(to_kind)); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 146 |  | 
|  | 147 | WriteBarrierMode write_barrier_mode = | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 148 | ((IsFastObjectElementsKind(from_kind) && | 
|  | 149 | IsFastObjectElementsKind(to_kind)) || | 
|  | 150 | from_kind == FAST_STRING_WRAPPER_ELEMENTS) | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 151 | ? UPDATE_WRITE_BARRIER | 
|  | 152 | : SKIP_WRITE_BARRIER; | 
|  | 153 | for (int i = 0; i < copy_size; i++) { | 
|  | 154 | Object* value = from->get(from_start + i); | 
|  | 155 | to->set(to_start + i, value, write_barrier_mode); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 156 | } | 
|  | 157 | } | 
|  | 158 |  | 
|  | 159 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 160 | static void CopyDictionaryToObjectElements( | 
|  | 161 | FixedArrayBase* from_base, uint32_t from_start, FixedArrayBase* to_base, | 
|  | 162 | ElementsKind to_kind, uint32_t to_start, int raw_copy_size) { | 
|  | 163 | DisallowHeapAllocation no_allocation; | 
|  | 164 | SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 165 | int copy_size = raw_copy_size; | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 166 | if (raw_copy_size < 0) { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 167 | DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd || | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 168 | raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); | 
|  | 169 | copy_size = from->max_number_key() + 1 - from_start; | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 170 | if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 171 | int start = to_start + copy_size; | 
|  | 172 | int length = to_base->length() - start; | 
|  | 173 | if (length > 0) { | 
|  | 174 | Heap* heap = from->GetHeap(); | 
|  | 175 | MemsetPointer(FixedArray::cast(to_base)->data_start() + start, | 
|  | 176 | heap->the_hole_value(), length); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 177 | } | 
|  | 178 | } | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 179 | } | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 180 | DCHECK(to_base != from_base); | 
|  | 181 | DCHECK(IsFastSmiOrObjectElementsKind(to_kind)); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 182 | if (copy_size == 0) return; | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 183 | FixedArray* to = FixedArray::cast(to_base); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 184 | uint32_t to_length = to->length(); | 
|  | 185 | if (to_start + copy_size > to_length) { | 
|  | 186 | copy_size = to_length - to_start; | 
|  | 187 | } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 188 | WriteBarrierMode write_barrier_mode = IsFastObjectElementsKind(to_kind) | 
|  | 189 | ? UPDATE_WRITE_BARRIER | 
|  | 190 | : SKIP_WRITE_BARRIER; | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 191 | for (int i = 0; i < copy_size; i++) { | 
|  | 192 | int entry = from->FindEntry(i + from_start); | 
|  | 193 | if (entry != SeededNumberDictionary::kNotFound) { | 
|  | 194 | Object* value = from->ValueAt(entry); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 195 | DCHECK(!value->IsTheHole()); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 196 | to->set(i + to_start, value, write_barrier_mode); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 197 | } else { | 
|  | 198 | to->set_the_hole(i + to_start); | 
|  | 199 | } | 
|  | 200 | } | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 201 | } | 
|  | 202 |  | 
|  | 203 |  | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 204 | // NOTE: this method violates the handlified function signature convention: | 
|  | 205 | // raw pointer parameters in the function that allocates. | 
|  | 206 | // See ElementsAccessorBase::CopyElements() for details. | 
|  | 207 | static void CopyDoubleToObjectElements(FixedArrayBase* from_base, | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 208 | uint32_t from_start, | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 209 | FixedArrayBase* to_base, | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 210 | uint32_t to_start, int raw_copy_size) { | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 211 | int copy_size = raw_copy_size; | 
|  | 212 | if (raw_copy_size < 0) { | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 213 | DisallowHeapAllocation no_allocation; | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 214 | DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd || | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 215 | raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 216 | copy_size = Min(from_base->length() - from_start, | 
|  | 217 | to_base->length() - to_start); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 218 | if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 219 | // Also initialize the area that will be copied over since HeapNumber | 
|  | 220 | // allocation below can cause an incremental marking step, requiring all | 
|  | 221 | // existing heap objects to be propertly initialized. | 
|  | 222 | int start = to_start; | 
|  | 223 | int length = to_base->length() - start; | 
|  | 224 | if (length > 0) { | 
|  | 225 | Heap* heap = from_base->GetHeap(); | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 226 | MemsetPointer(FixedArray::cast(to_base)->data_start() + start, | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 227 | heap->the_hole_value(), length); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 228 | } | 
|  | 229 | } | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 230 | } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 231 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 232 | DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() && | 
|  | 233 | (copy_size + static_cast<int>(from_start)) <= from_base->length()); | 
|  | 234 | if (copy_size == 0) return; | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 235 |  | 
|  | 236 | // From here on, the code below could actually allocate. Therefore the raw | 
|  | 237 | // values are wrapped into handles. | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 238 | Isolate* isolate = from_base->GetIsolate(); | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 239 | Handle<FixedDoubleArray> from(FixedDoubleArray::cast(from_base), isolate); | 
|  | 240 | Handle<FixedArray> to(FixedArray::cast(to_base), isolate); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 241 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 242 | // Use an outer loop to not waste too much time on creating HandleScopes. | 
|  | 243 | // On the other hand we might overflow a single handle scope depending on | 
|  | 244 | // the copy_size. | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 245 | int offset = 0; | 
|  | 246 | while (offset < copy_size) { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 247 | HandleScope scope(isolate); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 248 | offset += 100; | 
|  | 249 | for (int i = offset - 100; i < offset && i < copy_size; ++i) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 250 | Handle<Object> value = | 
|  | 251 | FixedDoubleArray::get(*from, i + from_start, isolate); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 252 | to->set(i + to_start, *value, UPDATE_WRITE_BARRIER); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 253 | } | 
|  | 254 | } | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 255 | } | 
|  | 256 |  | 
|  | 257 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 258 | static void CopyDoubleToDoubleElements(FixedArrayBase* from_base, | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 259 | uint32_t from_start, | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 260 | FixedArrayBase* to_base, | 
|  | 261 | uint32_t to_start, int raw_copy_size) { | 
|  | 262 | DisallowHeapAllocation no_allocation; | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 263 | int copy_size = raw_copy_size; | 
|  | 264 | if (raw_copy_size < 0) { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 265 | DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd || | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 266 | raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 267 | copy_size = Min(from_base->length() - from_start, | 
|  | 268 | to_base->length() - to_start); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 269 | if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 270 | for (int i = to_start + copy_size; i < to_base->length(); ++i) { | 
|  | 271 | FixedDoubleArray::cast(to_base)->set_the_hole(i); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 272 | } | 
|  | 273 | } | 
|  | 274 | } | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 275 | DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() && | 
|  | 276 | (copy_size + static_cast<int>(from_start)) <= from_base->length()); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 277 | if (copy_size == 0) return; | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 278 | FixedDoubleArray* from = FixedDoubleArray::cast(from_base); | 
|  | 279 | FixedDoubleArray* to = FixedDoubleArray::cast(to_base); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 280 | Address to_address = to->address() + FixedDoubleArray::kHeaderSize; | 
|  | 281 | Address from_address = from->address() + FixedDoubleArray::kHeaderSize; | 
|  | 282 | to_address += kDoubleSize * to_start; | 
|  | 283 | from_address += kDoubleSize * from_start; | 
|  | 284 | int words_per_double = (kDoubleSize / kPointerSize); | 
|  | 285 | CopyWords(reinterpret_cast<Object**>(to_address), | 
|  | 286 | reinterpret_cast<Object**>(from_address), | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 287 | static_cast<size_t>(words_per_double * copy_size)); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 288 | } | 
|  | 289 |  | 
|  | 290 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 291 | static void CopySmiToDoubleElements(FixedArrayBase* from_base, | 
|  | 292 | uint32_t from_start, | 
|  | 293 | FixedArrayBase* to_base, uint32_t to_start, | 
|  | 294 | int raw_copy_size) { | 
|  | 295 | DisallowHeapAllocation no_allocation; | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 296 | int copy_size = raw_copy_size; | 
|  | 297 | if (raw_copy_size < 0) { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 298 | DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd || | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 299 | raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 300 | copy_size = from_base->length() - from_start; | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 301 | if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 302 | for (int i = to_start + copy_size; i < to_base->length(); ++i) { | 
|  | 303 | FixedDoubleArray::cast(to_base)->set_the_hole(i); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 304 | } | 
|  | 305 | } | 
|  | 306 | } | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 307 | DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() && | 
|  | 308 | (copy_size + static_cast<int>(from_start)) <= from_base->length()); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 309 | if (copy_size == 0) return; | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 310 | FixedArray* from = FixedArray::cast(from_base); | 
|  | 311 | FixedDoubleArray* to = FixedDoubleArray::cast(to_base); | 
|  | 312 | Object* the_hole = from->GetHeap()->the_hole_value(); | 
|  | 313 | for (uint32_t from_end = from_start + static_cast<uint32_t>(copy_size); | 
|  | 314 | from_start < from_end; from_start++, to_start++) { | 
|  | 315 | Object* hole_or_smi = from->get(from_start); | 
|  | 316 | if (hole_or_smi == the_hole) { | 
|  | 317 | to->set_the_hole(to_start); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 318 | } else { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 319 | to->set(to_start, Smi::cast(hole_or_smi)->value()); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 320 | } | 
|  | 321 | } | 
|  | 322 | } | 
|  | 323 |  | 
|  | 324 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 325 | static void CopyPackedSmiToDoubleElements(FixedArrayBase* from_base, | 
|  | 326 | uint32_t from_start, | 
|  | 327 | FixedArrayBase* to_base, | 
|  | 328 | uint32_t to_start, int packed_size, | 
|  | 329 | int raw_copy_size) { | 
|  | 330 | DisallowHeapAllocation no_allocation; | 
|  | 331 | int copy_size = raw_copy_size; | 
|  | 332 | uint32_t to_end; | 
|  | 333 | if (raw_copy_size < 0) { | 
|  | 334 | DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd || | 
|  | 335 | raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); | 
|  | 336 | copy_size = packed_size - from_start; | 
|  | 337 | if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { | 
|  | 338 | to_end = to_base->length(); | 
|  | 339 | for (uint32_t i = to_start + copy_size; i < to_end; ++i) { | 
|  | 340 | FixedDoubleArray::cast(to_base)->set_the_hole(i); | 
|  | 341 | } | 
|  | 342 | } else { | 
|  | 343 | to_end = to_start + static_cast<uint32_t>(copy_size); | 
|  | 344 | } | 
|  | 345 | } else { | 
|  | 346 | to_end = to_start + static_cast<uint32_t>(copy_size); | 
|  | 347 | } | 
|  | 348 | DCHECK(static_cast<int>(to_end) <= to_base->length()); | 
|  | 349 | DCHECK(packed_size >= 0 && packed_size <= copy_size); | 
|  | 350 | DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() && | 
|  | 351 | (copy_size + static_cast<int>(from_start)) <= from_base->length()); | 
|  | 352 | if (copy_size == 0) return; | 
|  | 353 | FixedArray* from = FixedArray::cast(from_base); | 
|  | 354 | FixedDoubleArray* to = FixedDoubleArray::cast(to_base); | 
|  | 355 | for (uint32_t from_end = from_start + static_cast<uint32_t>(packed_size); | 
|  | 356 | from_start < from_end; from_start++, to_start++) { | 
|  | 357 | Object* smi = from->get(from_start); | 
|  | 358 | DCHECK(!smi->IsTheHole()); | 
|  | 359 | to->set(to_start, Smi::cast(smi)->value()); | 
|  | 360 | } | 
|  | 361 | } | 
|  | 362 |  | 
|  | 363 |  | 
|  | 364 | static void CopyObjectToDoubleElements(FixedArrayBase* from_base, | 
|  | 365 | uint32_t from_start, | 
|  | 366 | FixedArrayBase* to_base, | 
|  | 367 | uint32_t to_start, int raw_copy_size) { | 
|  | 368 | DisallowHeapAllocation no_allocation; | 
|  | 369 | int copy_size = raw_copy_size; | 
|  | 370 | if (raw_copy_size < 0) { | 
|  | 371 | DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd || | 
|  | 372 | raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); | 
|  | 373 | copy_size = from_base->length() - from_start; | 
|  | 374 | if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { | 
|  | 375 | for (int i = to_start + copy_size; i < to_base->length(); ++i) { | 
|  | 376 | FixedDoubleArray::cast(to_base)->set_the_hole(i); | 
|  | 377 | } | 
|  | 378 | } | 
|  | 379 | } | 
|  | 380 | DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() && | 
|  | 381 | (copy_size + static_cast<int>(from_start)) <= from_base->length()); | 
|  | 382 | if (copy_size == 0) return; | 
|  | 383 | FixedArray* from = FixedArray::cast(from_base); | 
|  | 384 | FixedDoubleArray* to = FixedDoubleArray::cast(to_base); | 
|  | 385 | Object* the_hole = from->GetHeap()->the_hole_value(); | 
|  | 386 | for (uint32_t from_end = from_start + copy_size; | 
|  | 387 | from_start < from_end; from_start++, to_start++) { | 
|  | 388 | Object* hole_or_object = from->get(from_start); | 
|  | 389 | if (hole_or_object == the_hole) { | 
|  | 390 | to->set_the_hole(to_start); | 
|  | 391 | } else { | 
|  | 392 | to->set(to_start, hole_or_object->Number()); | 
|  | 393 | } | 
|  | 394 | } | 
|  | 395 | } | 
|  | 396 |  | 
|  | 397 |  | 
|  | 398 | static void CopyDictionaryToDoubleElements(FixedArrayBase* from_base, | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 399 | uint32_t from_start, | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 400 | FixedArrayBase* to_base, | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 401 | uint32_t to_start, | 
|  | 402 | int raw_copy_size) { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 403 | DisallowHeapAllocation no_allocation; | 
|  | 404 | SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 405 | int copy_size = raw_copy_size; | 
|  | 406 | if (copy_size < 0) { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 407 | DCHECK(copy_size == ElementsAccessor::kCopyToEnd || | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 408 | copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); | 
|  | 409 | copy_size = from->max_number_key() + 1 - from_start; | 
|  | 410 | if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 411 | for (int i = to_start + copy_size; i < to_base->length(); ++i) { | 
|  | 412 | FixedDoubleArray::cast(to_base)->set_the_hole(i); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 413 | } | 
|  | 414 | } | 
|  | 415 | } | 
|  | 416 | if (copy_size == 0) return; | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 417 | FixedDoubleArray* to = FixedDoubleArray::cast(to_base); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 418 | uint32_t to_length = to->length(); | 
|  | 419 | if (to_start + copy_size > to_length) { | 
|  | 420 | copy_size = to_length - to_start; | 
|  | 421 | } | 
|  | 422 | for (int i = 0; i < copy_size; i++) { | 
|  | 423 | int entry = from->FindEntry(i + from_start); | 
|  | 424 | if (entry != SeededNumberDictionary::kNotFound) { | 
|  | 425 | to->set(i + to_start, from->ValueAt(entry)->Number()); | 
|  | 426 | } else { | 
|  | 427 | to->set_the_hole(i + to_start); | 
|  | 428 | } | 
|  | 429 | } | 
|  | 430 | } | 
|  | 431 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 432 | static void TraceTopFrame(Isolate* isolate) { | 
|  | 433 | StackFrameIterator it(isolate); | 
|  | 434 | if (it.done()) { | 
|  | 435 | PrintF("unknown location (no JavaScript frames present)"); | 
|  | 436 | return; | 
|  | 437 | } | 
|  | 438 | StackFrame* raw_frame = it.frame(); | 
|  | 439 | if (raw_frame->is_internal()) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 440 | Code* apply_builtin = | 
|  | 441 | isolate->builtins()->builtin(Builtins::kFunctionPrototypeApply); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 442 | if (raw_frame->unchecked_code() == apply_builtin) { | 
|  | 443 | PrintF("apply from "); | 
|  | 444 | it.Advance(); | 
|  | 445 | raw_frame = it.frame(); | 
|  | 446 | } | 
|  | 447 | } | 
|  | 448 | JavaScriptFrame::PrintTop(isolate, stdout, false, true); | 
|  | 449 | } | 
|  | 450 |  | 
|  | 451 |  | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 452 | // Base class for element handler implementations. Contains the | 
|  | 453 | // the common logic for objects with different ElementsKinds. | 
|  | 454 | // Subclasses must specialize method for which the element | 
|  | 455 | // implementation differs from the base class implementation. | 
|  | 456 | // | 
|  | 457 | // This class is intended to be used in the following way: | 
|  | 458 | // | 
|  | 459 | //   class SomeElementsAccessor : | 
|  | 460 | //       public ElementsAccessorBase<SomeElementsAccessor, | 
|  | 461 | //                                   BackingStoreClass> { | 
|  | 462 | //     ... | 
|  | 463 | //   } | 
|  | 464 | // | 
|  | 465 | // This is an example of the Curiously Recurring Template Pattern (see | 
|  | 466 | // http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern).  We use | 
|  | 467 | // CRTP to guarantee aggressive compile time optimizations (i.e.  inlining and | 
|  | 468 | // specialization of SomeElementsAccessor methods). | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 469 | template <typename ElementsAccessorSubclass, | 
|  | 470 | typename ElementsTraitsParam> | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 471 | class ElementsAccessorBase : public ElementsAccessor { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 472 | public: | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 473 | explicit ElementsAccessorBase(const char* name) | 
|  | 474 | : ElementsAccessor(name) { } | 
|  | 475 |  | 
|  | 476 | typedef ElementsTraitsParam ElementsTraits; | 
|  | 477 | typedef typename ElementsTraitsParam::BackingStore BackingStore; | 
|  | 478 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 479 | static ElementsKind kind() { return ElementsTraits::Kind; } | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 480 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 481 | static void ValidateContents(Handle<JSObject> holder, int length) { | 
|  | 482 | } | 
|  | 483 |  | 
|  | 484 | static void ValidateImpl(Handle<JSObject> holder) { | 
|  | 485 | Handle<FixedArrayBase> fixed_array_base(holder->elements()); | 
|  | 486 | if (!fixed_array_base->IsHeapObject()) return; | 
|  | 487 | // Arrays that have been shifted in place can't be verified. | 
|  | 488 | if (fixed_array_base->IsFiller()) return; | 
|  | 489 | int length = 0; | 
|  | 490 | if (holder->IsJSArray()) { | 
|  | 491 | Object* length_obj = Handle<JSArray>::cast(holder)->length(); | 
|  | 492 | if (length_obj->IsSmi()) { | 
|  | 493 | length = Smi::cast(length_obj)->value(); | 
|  | 494 | } | 
|  | 495 | } else { | 
|  | 496 | length = fixed_array_base->length(); | 
|  | 497 | } | 
|  | 498 | ElementsAccessorSubclass::ValidateContents(holder, length); | 
|  | 499 | } | 
|  | 500 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 501 | void Validate(Handle<JSObject> holder) final { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 502 | DisallowHeapAllocation no_gc; | 
|  | 503 | ElementsAccessorSubclass::ValidateImpl(holder); | 
|  | 504 | } | 
|  | 505 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 506 | static bool IsPackedImpl(Handle<JSObject> holder, | 
|  | 507 | Handle<FixedArrayBase> backing_store, uint32_t start, | 
|  | 508 | uint32_t end) { | 
|  | 509 | if (IsFastPackedElementsKind(kind())) return true; | 
|  | 510 | for (uint32_t i = start; i < end; i++) { | 
|  | 511 | if (!ElementsAccessorSubclass::HasElementImpl(holder, i, backing_store, | 
|  | 512 | ALL_PROPERTIES)) { | 
|  | 513 | return false; | 
|  | 514 | } | 
|  | 515 | } | 
|  | 516 | return true; | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 517 | } | 
|  | 518 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 519 | static void TryTransitionResultArrayToPacked(Handle<JSArray> array) { | 
|  | 520 | if (!IsHoleyElementsKind(kind())) return; | 
|  | 521 | int length = Smi::cast(array->length())->value(); | 
|  | 522 | Handle<FixedArrayBase> backing_store(array->elements()); | 
|  | 523 | if (!ElementsAccessorSubclass::IsPackedImpl(array, backing_store, 0, | 
|  | 524 | length)) { | 
|  | 525 | return; | 
|  | 526 | } | 
|  | 527 | ElementsKind packed_kind = GetPackedElementsKind(kind()); | 
|  | 528 | Handle<Map> new_map = | 
|  | 529 | JSObject::GetElementsTransitionMap(array, packed_kind); | 
|  | 530 | JSObject::MigrateToMap(array, new_map); | 
|  | 531 | if (FLAG_trace_elements_transitions) { | 
|  | 532 | JSObject::PrintElementsTransition(stdout, array, kind(), backing_store, | 
|  | 533 | packed_kind, backing_store); | 
|  | 534 | } | 
|  | 535 | } | 
|  | 536 |  | 
|  | 537 | bool HasElement(Handle<JSObject> holder, uint32_t index, | 
|  | 538 | Handle<FixedArrayBase> backing_store, | 
|  | 539 | PropertyFilter filter) final { | 
|  | 540 | return ElementsAccessorSubclass::HasElementImpl(holder, index, | 
|  | 541 | backing_store, filter); | 
|  | 542 | } | 
|  | 543 |  | 
|  | 544 | static bool HasElementImpl(Handle<JSObject> holder, uint32_t index, | 
|  | 545 | Handle<FixedArrayBase> backing_store, | 
|  | 546 | PropertyFilter filter) { | 
|  | 547 | return ElementsAccessorSubclass::GetEntryForIndexImpl( | 
|  | 548 | *holder, *backing_store, index, filter) != kMaxUInt32; | 
|  | 549 | } | 
|  | 550 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 551 | bool HasAccessors(JSObject* holder) final { | 
|  | 552 | return ElementsAccessorSubclass::HasAccessorsImpl(holder, | 
|  | 553 | holder->elements()); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 554 | } | 
|  | 555 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 556 | static bool HasAccessorsImpl(JSObject* holder, | 
|  | 557 | FixedArrayBase* backing_store) { | 
|  | 558 | return false; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 559 | } | 
|  | 560 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 561 | Handle<Object> Get(Handle<JSObject> holder, uint32_t entry) final { | 
|  | 562 | return ElementsAccessorSubclass::GetImpl(holder, entry); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 563 | } | 
|  | 564 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 565 | static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) { | 
|  | 566 | return ElementsAccessorSubclass::GetImpl(holder->elements(), entry); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 567 | } | 
|  | 568 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 569 | static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) { | 
|  | 570 | Isolate* isolate = backing_store->GetIsolate(); | 
|  | 571 | uint32_t index = GetIndexForEntryImpl(backing_store, entry); | 
|  | 572 | return handle(BackingStore::cast(backing_store)->get(index), isolate); | 
|  | 573 | } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 574 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 575 | void Set(Handle<JSObject> holder, uint32_t entry, Object* value) final { | 
|  | 576 | ElementsAccessorSubclass::SetImpl(holder, entry, value); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 577 | } | 
|  | 578 |  | 
|  | 579 | void Reconfigure(Handle<JSObject> object, Handle<FixedArrayBase> store, | 
|  | 580 | uint32_t entry, Handle<Object> value, | 
|  | 581 | PropertyAttributes attributes) final { | 
|  | 582 | ElementsAccessorSubclass::ReconfigureImpl(object, store, entry, value, | 
|  | 583 | attributes); | 
|  | 584 | } | 
|  | 585 |  | 
|  | 586 | static void ReconfigureImpl(Handle<JSObject> object, | 
|  | 587 | Handle<FixedArrayBase> store, uint32_t entry, | 
|  | 588 | Handle<Object> value, | 
|  | 589 | PropertyAttributes attributes) { | 
|  | 590 | UNREACHABLE(); | 
|  | 591 | } | 
|  | 592 |  | 
|  | 593 | void Add(Handle<JSObject> object, uint32_t index, Handle<Object> value, | 
|  | 594 | PropertyAttributes attributes, uint32_t new_capacity) final { | 
|  | 595 | ElementsAccessorSubclass::AddImpl(object, index, value, attributes, | 
|  | 596 | new_capacity); | 
|  | 597 | } | 
|  | 598 |  | 
|  | 599 | static void AddImpl(Handle<JSObject> object, uint32_t index, | 
|  | 600 | Handle<Object> value, PropertyAttributes attributes, | 
|  | 601 | uint32_t new_capacity) { | 
|  | 602 | UNREACHABLE(); | 
|  | 603 | } | 
|  | 604 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 605 | uint32_t Push(Handle<JSArray> receiver, Arguments* args, | 
|  | 606 | uint32_t push_size) final { | 
|  | 607 | return ElementsAccessorSubclass::PushImpl(receiver, args, push_size); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 608 | } | 
|  | 609 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 610 | static uint32_t PushImpl(Handle<JSArray> receiver, Arguments* args, | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 611 | uint32_t push_sized) { | 
|  | 612 | UNREACHABLE(); | 
|  | 613 | return 0; | 
|  | 614 | } | 
|  | 615 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 616 | uint32_t Unshift(Handle<JSArray> receiver, Arguments* args, | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 617 | uint32_t unshift_size) final { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 618 | return ElementsAccessorSubclass::UnshiftImpl(receiver, args, unshift_size); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 619 | } | 
|  | 620 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 621 | static uint32_t UnshiftImpl(Handle<JSArray> receiver, Arguments* args, | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 622 | uint32_t unshift_size) { | 
|  | 623 | UNREACHABLE(); | 
|  | 624 | return 0; | 
|  | 625 | } | 
|  | 626 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 627 | Handle<JSArray> Slice(Handle<JSObject> receiver, uint32_t start, | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 628 | uint32_t end) final { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 629 | return ElementsAccessorSubclass::SliceImpl(receiver, start, end); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 630 | } | 
|  | 631 |  | 
|  | 632 | static Handle<JSArray> SliceImpl(Handle<JSObject> receiver, | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 633 | uint32_t start, uint32_t end) { | 
|  | 634 | UNREACHABLE(); | 
|  | 635 | return Handle<JSArray>(); | 
|  | 636 | } | 
|  | 637 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 638 | Handle<JSArray> Splice(Handle<JSArray> receiver, uint32_t start, | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 639 | uint32_t delete_count, Arguments* args, | 
|  | 640 | uint32_t add_count) final { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 641 | return ElementsAccessorSubclass::SpliceImpl(receiver, start, delete_count, | 
|  | 642 | args, add_count); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 643 | } | 
|  | 644 |  | 
|  | 645 | static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver, | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 646 | uint32_t start, uint32_t delete_count, | 
|  | 647 | Arguments* args, uint32_t add_count) { | 
|  | 648 | UNREACHABLE(); | 
|  | 649 | return Handle<JSArray>(); | 
|  | 650 | } | 
|  | 651 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 652 | Handle<Object> Pop(Handle<JSArray> receiver) final { | 
|  | 653 | return ElementsAccessorSubclass::PopImpl(receiver); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 654 | } | 
|  | 655 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 656 | static Handle<Object> PopImpl(Handle<JSArray> receiver) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 657 | UNREACHABLE(); | 
|  | 658 | return Handle<Object>(); | 
|  | 659 | } | 
|  | 660 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 661 | Handle<Object> Shift(Handle<JSArray> receiver) final { | 
|  | 662 | return ElementsAccessorSubclass::ShiftImpl(receiver); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 663 | } | 
|  | 664 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 665 | static Handle<Object> ShiftImpl(Handle<JSArray> receiver) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 666 | UNREACHABLE(); | 
|  | 667 | return Handle<Object>(); | 
|  | 668 | } | 
|  | 669 |  | 
|  | 670 | void SetLength(Handle<JSArray> array, uint32_t length) final { | 
|  | 671 | ElementsAccessorSubclass::SetLengthImpl(array->GetIsolate(), array, length, | 
|  | 672 | handle(array->elements())); | 
|  | 673 | } | 
|  | 674 |  | 
|  | 675 | static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array, | 
|  | 676 | uint32_t length, | 
|  | 677 | Handle<FixedArrayBase> backing_store) { | 
|  | 678 | DCHECK(!array->SetLengthWouldNormalize(length)); | 
|  | 679 | DCHECK(IsFastElementsKind(array->GetElementsKind())); | 
|  | 680 | uint32_t old_length = 0; | 
|  | 681 | CHECK(array->length()->ToArrayIndex(&old_length)); | 
|  | 682 |  | 
|  | 683 | if (old_length < length) { | 
|  | 684 | ElementsKind kind = array->GetElementsKind(); | 
|  | 685 | if (!IsFastHoleyElementsKind(kind)) { | 
|  | 686 | kind = GetHoleyElementsKind(kind); | 
|  | 687 | JSObject::TransitionElementsKind(array, kind); | 
|  | 688 | } | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 689 | } | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 690 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 691 | // Check whether the backing store should be shrunk. | 
|  | 692 | uint32_t capacity = backing_store->length(); | 
|  | 693 | old_length = Min(old_length, capacity); | 
|  | 694 | if (length == 0) { | 
|  | 695 | array->initialize_elements(); | 
|  | 696 | } else if (length <= capacity) { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 697 | if (IsFastSmiOrObjectElementsKind(kind())) { | 
|  | 698 | JSObject::EnsureWritableFastElements(array); | 
|  | 699 | if (array->elements() != *backing_store) { | 
|  | 700 | backing_store = handle(array->elements(), isolate); | 
|  | 701 | } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 702 | } | 
|  | 703 | if (2 * length <= capacity) { | 
|  | 704 | // If more than half the elements won't be used, trim the array. | 
|  | 705 | isolate->heap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>( | 
|  | 706 | *backing_store, capacity - length); | 
|  | 707 | } else { | 
|  | 708 | // Otherwise, fill the unused tail with holes. | 
|  | 709 | for (uint32_t i = length; i < old_length; i++) { | 
|  | 710 | BackingStore::cast(*backing_store)->set_the_hole(i); | 
|  | 711 | } | 
|  | 712 | } | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 713 | } else { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 714 | // Check whether the backing store should be expanded. | 
|  | 715 | capacity = Max(length, JSObject::NewElementsCapacity(capacity)); | 
|  | 716 | ElementsAccessorSubclass::GrowCapacityAndConvertImpl(array, capacity); | 
|  | 717 | } | 
|  | 718 |  | 
|  | 719 | array->set_length(Smi::FromInt(length)); | 
|  | 720 | JSObject::ValidateElements(array); | 
|  | 721 | } | 
|  | 722 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 723 | static uint32_t GetIterationLength(JSObject* receiver, | 
|  | 724 | FixedArrayBase* elements) { | 
|  | 725 | if (receiver->IsJSArray()) { | 
|  | 726 | DCHECK(JSArray::cast(receiver)->length()->IsSmi()); | 
|  | 727 | return static_cast<uint32_t>( | 
|  | 728 | Smi::cast(JSArray::cast(receiver)->length())->value()); | 
|  | 729 | } | 
|  | 730 | return ElementsAccessorSubclass::GetCapacityImpl(receiver, elements); | 
|  | 731 | } | 
|  | 732 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 733 | static Handle<FixedArrayBase> ConvertElementsWithCapacity( | 
|  | 734 | Handle<JSObject> object, Handle<FixedArrayBase> old_elements, | 
|  | 735 | ElementsKind from_kind, uint32_t capacity) { | 
|  | 736 | return ConvertElementsWithCapacity( | 
|  | 737 | object, old_elements, from_kind, capacity, 0, 0, | 
|  | 738 | ElementsAccessor::kCopyToEndAndInitializeToHole); | 
|  | 739 | } | 
|  | 740 |  | 
|  | 741 | static Handle<FixedArrayBase> ConvertElementsWithCapacity( | 
|  | 742 | Handle<JSObject> object, Handle<FixedArrayBase> old_elements, | 
|  | 743 | ElementsKind from_kind, uint32_t capacity, int copy_size) { | 
|  | 744 | return ConvertElementsWithCapacity(object, old_elements, from_kind, | 
|  | 745 | capacity, 0, 0, copy_size); | 
|  | 746 | } | 
|  | 747 |  | 
|  | 748 | static Handle<FixedArrayBase> ConvertElementsWithCapacity( | 
|  | 749 | Handle<JSObject> object, Handle<FixedArrayBase> old_elements, | 
|  | 750 | ElementsKind from_kind, uint32_t capacity, uint32_t src_index, | 
|  | 751 | uint32_t dst_index, int copy_size) { | 
|  | 752 | Isolate* isolate = object->GetIsolate(); | 
|  | 753 | Handle<FixedArrayBase> new_elements; | 
|  | 754 | if (IsFastDoubleElementsKind(kind())) { | 
|  | 755 | new_elements = isolate->factory()->NewFixedDoubleArray(capacity); | 
|  | 756 | } else { | 
|  | 757 | new_elements = isolate->factory()->NewUninitializedFixedArray(capacity); | 
|  | 758 | } | 
|  | 759 |  | 
|  | 760 | int packed_size = kPackedSizeNotKnown; | 
|  | 761 | if (IsFastPackedElementsKind(from_kind) && object->IsJSArray()) { | 
|  | 762 | packed_size = Smi::cast(JSArray::cast(*object)->length())->value(); | 
|  | 763 | } | 
|  | 764 |  | 
|  | 765 | ElementsAccessorSubclass::CopyElementsImpl( | 
|  | 766 | *old_elements, src_index, *new_elements, from_kind, dst_index, | 
|  | 767 | packed_size, copy_size); | 
|  | 768 |  | 
|  | 769 | return new_elements; | 
|  | 770 | } | 
|  | 771 |  | 
|  | 772 | static void GrowCapacityAndConvertImpl(Handle<JSObject> object, | 
|  | 773 | uint32_t capacity) { | 
|  | 774 | ElementsKind from_kind = object->GetElementsKind(); | 
|  | 775 | if (IsFastSmiOrObjectElementsKind(from_kind)) { | 
|  | 776 | // Array optimizations rely on the prototype lookups of Array objects | 
|  | 777 | // always returning undefined. If there is a store to the initial | 
|  | 778 | // prototype object, make sure all of these optimizations are invalidated. | 
|  | 779 | object->GetIsolate()->UpdateArrayProtectorOnSetLength(object); | 
|  | 780 | } | 
|  | 781 | Handle<FixedArrayBase> old_elements(object->elements()); | 
|  | 782 | // This method should only be called if there's a reason to update the | 
|  | 783 | // elements. | 
|  | 784 | DCHECK(IsFastDoubleElementsKind(from_kind) != | 
|  | 785 | IsFastDoubleElementsKind(kind()) || | 
|  | 786 | IsDictionaryElementsKind(from_kind) || | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 787 | from_kind == SLOW_STRING_WRAPPER_ELEMENTS || | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 788 | static_cast<uint32_t>(old_elements->length()) < capacity); | 
|  | 789 | Handle<FixedArrayBase> elements = | 
|  | 790 | ConvertElementsWithCapacity(object, old_elements, from_kind, capacity); | 
|  | 791 |  | 
|  | 792 | ElementsKind to_kind = kind(); | 
|  | 793 | if (IsHoleyElementsKind(from_kind)) to_kind = GetHoleyElementsKind(to_kind); | 
|  | 794 | Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, to_kind); | 
|  | 795 | JSObject::SetMapAndElements(object, new_map, elements); | 
|  | 796 |  | 
|  | 797 | // Transition through the allocation site as well if present. | 
|  | 798 | JSObject::UpdateAllocationSite(object, to_kind); | 
|  | 799 |  | 
|  | 800 | if (FLAG_trace_elements_transitions) { | 
|  | 801 | JSObject::PrintElementsTransition(stdout, object, from_kind, old_elements, | 
|  | 802 | to_kind, elements); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 803 | } | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 804 | } | 
|  | 805 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 806 | void GrowCapacityAndConvert(Handle<JSObject> object, | 
|  | 807 | uint32_t capacity) final { | 
|  | 808 | ElementsAccessorSubclass::GrowCapacityAndConvertImpl(object, capacity); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 809 | } | 
|  | 810 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 811 | void Delete(Handle<JSObject> obj, uint32_t entry) final { | 
|  | 812 | ElementsAccessorSubclass::DeleteImpl(obj, entry); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 813 | } | 
|  | 814 |  | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 815 | static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start, | 
|  | 816 | FixedArrayBase* to, ElementsKind from_kind, | 
|  | 817 | uint32_t to_start, int packed_size, | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 818 | int copy_size) { | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 819 | UNREACHABLE(); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 820 | } | 
|  | 821 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 822 | void CopyElements(JSObject* from_holder, uint32_t from_start, | 
|  | 823 | ElementsKind from_kind, Handle<FixedArrayBase> to, | 
|  | 824 | uint32_t to_start, int copy_size) final { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 825 | int packed_size = kPackedSizeNotKnown; | 
|  | 826 | bool is_packed = IsFastPackedElementsKind(from_kind) && | 
|  | 827 | from_holder->IsJSArray(); | 
|  | 828 | if (is_packed) { | 
|  | 829 | packed_size = | 
|  | 830 | Smi::cast(JSArray::cast(from_holder)->length())->value(); | 
|  | 831 | if (copy_size >= 0 && packed_size > copy_size) { | 
|  | 832 | packed_size = copy_size; | 
|  | 833 | } | 
|  | 834 | } | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 835 | FixedArrayBase* from = from_holder->elements(); | 
|  | 836 | // NOTE: the ElementsAccessorSubclass::CopyElementsImpl() methods | 
|  | 837 | // violate the handlified function signature convention: | 
|  | 838 | // raw pointer parameters in the function that allocates. This is done | 
|  | 839 | // intentionally to avoid ArrayConcat() builtin performance degradation. | 
|  | 840 | // | 
|  | 841 | // Details: The idea is that allocations actually happen only in case of | 
|  | 842 | // copying from object with fast double elements to object with object | 
|  | 843 | // elements. In all the other cases there are no allocations performed and | 
|  | 844 | // handle creation causes noticeable performance degradation of the builtin. | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 845 | ElementsAccessorSubclass::CopyElementsImpl( | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 846 | from, from_start, *to, from_kind, to_start, packed_size, copy_size); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 847 | } | 
|  | 848 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 849 | Handle<SeededNumberDictionary> Normalize(Handle<JSObject> object) final { | 
|  | 850 | return ElementsAccessorSubclass::NormalizeImpl(object, | 
|  | 851 | handle(object->elements())); | 
|  | 852 | } | 
|  | 853 |  | 
|  | 854 | static Handle<SeededNumberDictionary> NormalizeImpl( | 
|  | 855 | Handle<JSObject> object, Handle<FixedArrayBase> elements) { | 
|  | 856 | UNREACHABLE(); | 
|  | 857 | return Handle<SeededNumberDictionary>(); | 
|  | 858 | } | 
|  | 859 |  | 
|  | 860 | Maybe<bool> CollectValuesOrEntries(Isolate* isolate, Handle<JSObject> object, | 
|  | 861 | Handle<FixedArray> values_or_entries, | 
|  | 862 | bool get_entries, int* nof_items, | 
|  | 863 | PropertyFilter filter) { | 
|  | 864 | return ElementsAccessorSubclass::CollectValuesOrEntriesImpl( | 
|  | 865 | isolate, object, values_or_entries, get_entries, nof_items, filter); | 
|  | 866 | } | 
|  | 867 |  | 
|  | 868 | static Maybe<bool> CollectValuesOrEntriesImpl( | 
|  | 869 | Isolate* isolate, Handle<JSObject> object, | 
|  | 870 | Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items, | 
|  | 871 | PropertyFilter filter) { | 
|  | 872 | int count = 0; | 
|  | 873 | KeyAccumulator accumulator(isolate, OWN_ONLY, ALL_PROPERTIES); | 
|  | 874 | accumulator.NextPrototype(); | 
|  | 875 | ElementsAccessorSubclass::CollectElementIndicesImpl( | 
|  | 876 | object, handle(object->elements(), isolate), &accumulator, kMaxUInt32, | 
|  | 877 | ALL_PROPERTIES, 0); | 
|  | 878 | Handle<FixedArray> keys = accumulator.GetKeys(); | 
|  | 879 |  | 
|  | 880 | for (int i = 0; i < keys->length(); ++i) { | 
|  | 881 | Handle<Object> key(keys->get(i), isolate); | 
|  | 882 | Handle<Object> value; | 
|  | 883 | uint32_t index; | 
|  | 884 | if (!key->ToUint32(&index)) continue; | 
|  | 885 |  | 
|  | 886 | uint32_t entry = ElementsAccessorSubclass::GetEntryForIndexImpl( | 
|  | 887 | *object, object->elements(), index, filter); | 
|  | 888 | if (entry == kMaxUInt32) continue; | 
|  | 889 |  | 
|  | 890 | PropertyDetails details = | 
|  | 891 | ElementsAccessorSubclass::GetDetailsImpl(*object, entry); | 
|  | 892 |  | 
|  | 893 | if (details.kind() == kData) { | 
|  | 894 | value = ElementsAccessorSubclass::GetImpl(object, entry); | 
|  | 895 | } else { | 
|  | 896 | LookupIterator it(isolate, object, index, LookupIterator::OWN); | 
|  | 897 | ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 
|  | 898 | isolate, value, Object::GetProperty(&it), Nothing<bool>()); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 899 | } | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 900 | if (get_entries) { | 
|  | 901 | value = MakeEntryPair(isolate, index, value); | 
|  | 902 | } | 
|  | 903 | values_or_entries->set(count++, *value); | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 904 | } | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 905 |  | 
|  | 906 | *nof_items = count; | 
|  | 907 | return Just(true); | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 908 | } | 
|  | 909 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 910 | void CollectElementIndices(Handle<JSObject> object, | 
|  | 911 | Handle<FixedArrayBase> backing_store, | 
|  | 912 | KeyAccumulator* keys, uint32_t range, | 
|  | 913 | PropertyFilter filter, uint32_t offset) final { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 914 | if (filter & ONLY_ALL_CAN_READ) return; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 915 | ElementsAccessorSubclass::CollectElementIndicesImpl( | 
|  | 916 | object, backing_store, keys, range, filter, offset); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 917 | } | 
|  | 918 |  | 
|  | 919 | static void CollectElementIndicesImpl(Handle<JSObject> object, | 
|  | 920 | Handle<FixedArrayBase> backing_store, | 
|  | 921 | KeyAccumulator* keys, uint32_t range, | 
|  | 922 | PropertyFilter filter, | 
|  | 923 | uint32_t offset) { | 
|  | 924 | DCHECK_NE(DICTIONARY_ELEMENTS, kind()); | 
|  | 925 | // Non-dictionary elements can't have all-can-read accessors. | 
|  | 926 | uint32_t length = GetIterationLength(*object, *backing_store); | 
|  | 927 | if (range < length) length = range; | 
|  | 928 | for (uint32_t i = offset; i < length; i++) { | 
|  | 929 | if (ElementsAccessorSubclass::HasElementImpl(object, i, backing_store, | 
|  | 930 | filter)) { | 
|  | 931 | keys->AddKey(i); | 
|  | 932 | } | 
|  | 933 | } | 
|  | 934 | } | 
|  | 935 |  | 
|  | 936 | static Handle<FixedArray> DirectCollectElementIndicesImpl( | 
|  | 937 | Isolate* isolate, Handle<JSObject> object, | 
|  | 938 | Handle<FixedArrayBase> backing_store, GetKeysConversion convert, | 
|  | 939 | PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices, | 
|  | 940 | uint32_t insertion_index = 0) { | 
|  | 941 | uint32_t length = | 
|  | 942 | ElementsAccessorSubclass::GetIterationLength(*object, *backing_store); | 
|  | 943 | for (uint32_t i = 0; i < length; i++) { | 
|  | 944 | if (ElementsAccessorSubclass::HasElementImpl(object, i, backing_store, | 
|  | 945 | filter)) { | 
|  | 946 | if (convert == CONVERT_TO_STRING) { | 
|  | 947 | Handle<String> index_string = isolate->factory()->Uint32ToString(i); | 
|  | 948 | list->set(insertion_index, *index_string); | 
|  | 949 | } else { | 
|  | 950 | list->set(insertion_index, Smi::FromInt(i), SKIP_WRITE_BARRIER); | 
|  | 951 | } | 
|  | 952 | insertion_index++; | 
|  | 953 | } | 
|  | 954 | } | 
|  | 955 | *nof_indices = insertion_index; | 
|  | 956 | return list; | 
|  | 957 | } | 
|  | 958 |  | 
|  | 959 | Handle<FixedArray> PrependElementIndices(Handle<JSObject> object, | 
|  | 960 | Handle<FixedArrayBase> backing_store, | 
|  | 961 | Handle<FixedArray> keys, | 
|  | 962 | GetKeysConversion convert, | 
|  | 963 | PropertyFilter filter) final { | 
|  | 964 | return ElementsAccessorSubclass::PrependElementIndicesImpl( | 
|  | 965 | object, backing_store, keys, convert, filter); | 
|  | 966 | } | 
|  | 967 |  | 
|  | 968 | static Handle<FixedArray> PrependElementIndicesImpl( | 
|  | 969 | Handle<JSObject> object, Handle<FixedArrayBase> backing_store, | 
|  | 970 | Handle<FixedArray> keys, GetKeysConversion convert, | 
|  | 971 | PropertyFilter filter) { | 
|  | 972 | Isolate* isolate = object->GetIsolate(); | 
|  | 973 | uint32_t nof_property_keys = keys->length(); | 
|  | 974 | uint32_t initial_list_length = | 
|  | 975 | ElementsAccessorSubclass::GetCapacityImpl(*object, *backing_store); | 
|  | 976 | initial_list_length += nof_property_keys; | 
|  | 977 |  | 
|  | 978 | // Collect the element indices into a new list. | 
|  | 979 | uint32_t nof_indices = 0; | 
|  | 980 | Handle<FixedArray> combined_keys = | 
|  | 981 | isolate->factory()->NewFixedArray(initial_list_length); | 
|  | 982 | combined_keys = ElementsAccessorSubclass::DirectCollectElementIndicesImpl( | 
|  | 983 | isolate, object, backing_store, convert, filter, combined_keys, | 
|  | 984 | &nof_indices); | 
|  | 985 |  | 
|  | 986 | // Sort the indices list if necessary. | 
|  | 987 | if (IsDictionaryElementsKind(kind()) || IsSloppyArgumentsElements(kind())) { | 
|  | 988 | struct { | 
|  | 989 | bool operator()(Object* a, Object* b) { | 
|  | 990 | if (!a->IsUndefined()) { | 
|  | 991 | if (b->IsUndefined()) return true; | 
|  | 992 | return a->Number() < b->Number(); | 
|  | 993 | } | 
|  | 994 | return !b->IsUndefined(); | 
|  | 995 | } | 
|  | 996 | } cmp; | 
|  | 997 | Object** start = | 
|  | 998 | reinterpret_cast<Object**>(combined_keys->GetFirstElementAddress()); | 
|  | 999 | std::sort(start, start + nof_indices, cmp); | 
|  | 1000 | uint32_t array_length = 0; | 
|  | 1001 | // Indices from dictionary elements should only be converted after | 
|  | 1002 | // sorting. | 
|  | 1003 | if (convert == CONVERT_TO_STRING) { | 
|  | 1004 | for (uint32_t i = 0; i < nof_indices; i++) { | 
|  | 1005 | Handle<Object> index_string = isolate->factory()->Uint32ToString( | 
|  | 1006 | combined_keys->get(i)->Number()); | 
|  | 1007 | combined_keys->set(i, *index_string); | 
|  | 1008 | } | 
|  | 1009 | } else if (!(object->IsJSArray() && | 
|  | 1010 | JSArray::cast(*object)->length()->ToArrayLength( | 
|  | 1011 | &array_length) && | 
|  | 1012 | array_length <= Smi::kMaxValue)) { | 
|  | 1013 | // Since we use std::sort above, the GC will no longer know where the | 
|  | 1014 | // HeapNumbers are, hence we have to write them again. | 
|  | 1015 | // For Arrays with valid Smi length, we are sure to have no HeapNumber | 
|  | 1016 | // indices and thus we can skip this step. | 
|  | 1017 | for (uint32_t i = 0; i < nof_indices; i++) { | 
|  | 1018 | Object* index = combined_keys->get(i); | 
|  | 1019 | combined_keys->set(i, index); | 
|  | 1020 | } | 
|  | 1021 | } | 
|  | 1022 | } | 
|  | 1023 |  | 
|  | 1024 | // Copy over the passed-in property keys. | 
|  | 1025 | CopyObjectToObjectElements(*keys, FAST_ELEMENTS, 0, *combined_keys, | 
|  | 1026 | FAST_ELEMENTS, nof_indices, nof_property_keys); | 
|  | 1027 |  | 
|  | 1028 | if (IsHoleyElementsKind(kind())) { | 
|  | 1029 | // Shrink combined_keys to the final size. | 
|  | 1030 | int final_size = nof_indices + nof_property_keys; | 
|  | 1031 | DCHECK_LE(final_size, combined_keys->length()); | 
|  | 1032 | combined_keys->Shrink(final_size); | 
|  | 1033 | } | 
|  | 1034 |  | 
|  | 1035 | return combined_keys; | 
|  | 1036 | } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1037 |  | 
|  | 1038 | void AddElementsToKeyAccumulator(Handle<JSObject> receiver, | 
|  | 1039 | KeyAccumulator* accumulator, | 
|  | 1040 | AddKeyConversion convert) final { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1041 | ElementsAccessorSubclass::AddElementsToKeyAccumulatorImpl( | 
|  | 1042 | receiver, accumulator, convert); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1043 | } | 
|  | 1044 |  | 
|  | 1045 | static uint32_t GetCapacityImpl(JSObject* holder, | 
|  | 1046 | FixedArrayBase* backing_store) { | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 1047 | return backing_store->length(); | 
|  | 1048 | } | 
|  | 1049 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1050 | uint32_t GetCapacity(JSObject* holder, FixedArrayBase* backing_store) final { | 
|  | 1051 | return ElementsAccessorSubclass::GetCapacityImpl(holder, backing_store); | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 1052 | } | 
|  | 1053 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1054 | static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store, | 
|  | 1055 | uint32_t entry) { | 
|  | 1056 | return entry; | 
|  | 1057 | } | 
|  | 1058 |  | 
|  | 1059 | static uint32_t GetEntryForIndexImpl(JSObject* holder, | 
|  | 1060 | FixedArrayBase* backing_store, | 
|  | 1061 | uint32_t index, PropertyFilter filter) { | 
|  | 1062 | if (IsHoleyElementsKind(kind())) { | 
|  | 1063 | return index < ElementsAccessorSubclass::GetCapacityImpl(holder, | 
|  | 1064 | backing_store) && | 
|  | 1065 | !BackingStore::cast(backing_store)->is_the_hole(index) | 
|  | 1066 | ? index | 
|  | 1067 | : kMaxUInt32; | 
|  | 1068 | } else { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1069 | uint32_t length = GetIterationLength(holder, backing_store); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1070 | return index < length ? index : kMaxUInt32; | 
|  | 1071 | } | 
|  | 1072 | } | 
|  | 1073 |  | 
|  | 1074 | uint32_t GetEntryForIndex(JSObject* holder, FixedArrayBase* backing_store, | 
|  | 1075 | uint32_t index) final { | 
|  | 1076 | return ElementsAccessorSubclass::GetEntryForIndexImpl( | 
|  | 1077 | holder, backing_store, index, ALL_PROPERTIES); | 
|  | 1078 | } | 
|  | 1079 |  | 
|  | 1080 | static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store, | 
|  | 1081 | uint32_t entry) { | 
|  | 1082 | return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell); | 
|  | 1083 | } | 
|  | 1084 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1085 | static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) { | 
|  | 1086 | return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell); | 
|  | 1087 | } | 
|  | 1088 |  | 
|  | 1089 | PropertyDetails GetDetails(JSObject* holder, uint32_t entry) final { | 
|  | 1090 | return ElementsAccessorSubclass::GetDetailsImpl(holder, entry); | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 1091 | } | 
|  | 1092 |  | 
|  | 1093 | private: | 
|  | 1094 | DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase); | 
|  | 1095 | }; | 
|  | 1096 |  | 
|  | 1097 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1098 | class DictionaryElementsAccessor | 
|  | 1099 | : public ElementsAccessorBase<DictionaryElementsAccessor, | 
|  | 1100 | ElementsKindTraits<DICTIONARY_ELEMENTS> > { | 
|  | 1101 | public: | 
|  | 1102 | explicit DictionaryElementsAccessor(const char* name) | 
|  | 1103 | : ElementsAccessorBase<DictionaryElementsAccessor, | 
|  | 1104 | ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {} | 
|  | 1105 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1106 | static uint32_t GetIterationLength(JSObject* receiver, | 
|  | 1107 | FixedArrayBase* elements) { | 
|  | 1108 | uint32_t length; | 
|  | 1109 | if (receiver->IsJSArray()) { | 
|  | 1110 | // Special-case GetIterationLength for dictionary elements since the | 
|  | 1111 | // length of the array might be a HeapNumber. | 
|  | 1112 | JSArray::cast(receiver)->length()->ToArrayLength(&length); | 
|  | 1113 | } else { | 
|  | 1114 | length = GetCapacityImpl(receiver, elements); | 
|  | 1115 | } | 
|  | 1116 | return length; | 
|  | 1117 | } | 
|  | 1118 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1119 | static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array, | 
|  | 1120 | uint32_t length, | 
|  | 1121 | Handle<FixedArrayBase> backing_store) { | 
|  | 1122 | Handle<SeededNumberDictionary> dict = | 
|  | 1123 | Handle<SeededNumberDictionary>::cast(backing_store); | 
|  | 1124 | int capacity = dict->Capacity(); | 
|  | 1125 | uint32_t old_length = 0; | 
|  | 1126 | CHECK(array->length()->ToArrayLength(&old_length)); | 
|  | 1127 | if (length < old_length) { | 
|  | 1128 | if (dict->requires_slow_elements()) { | 
|  | 1129 | // Find last non-deletable element in range of elements to be | 
|  | 1130 | // deleted and adjust range accordingly. | 
|  | 1131 | for (int entry = 0; entry < capacity; entry++) { | 
|  | 1132 | DisallowHeapAllocation no_gc; | 
|  | 1133 | Object* index = dict->KeyAt(entry); | 
|  | 1134 | if (index->IsNumber()) { | 
|  | 1135 | uint32_t number = static_cast<uint32_t>(index->Number()); | 
|  | 1136 | if (length <= number && number < old_length) { | 
|  | 1137 | PropertyDetails details = dict->DetailsAt(entry); | 
|  | 1138 | if (!details.IsConfigurable()) length = number + 1; | 
|  | 1139 | } | 
|  | 1140 | } | 
|  | 1141 | } | 
|  | 1142 | } | 
|  | 1143 |  | 
|  | 1144 | if (length == 0) { | 
|  | 1145 | // Flush the backing store. | 
|  | 1146 | JSObject::ResetElements(array); | 
|  | 1147 | } else { | 
|  | 1148 | DisallowHeapAllocation no_gc; | 
|  | 1149 | // Remove elements that should be deleted. | 
|  | 1150 | int removed_entries = 0; | 
|  | 1151 | Handle<Object> the_hole_value = isolate->factory()->the_hole_value(); | 
|  | 1152 | for (int entry = 0; entry < capacity; entry++) { | 
|  | 1153 | Object* index = dict->KeyAt(entry); | 
|  | 1154 | if (index->IsNumber()) { | 
|  | 1155 | uint32_t number = static_cast<uint32_t>(index->Number()); | 
|  | 1156 | if (length <= number && number < old_length) { | 
|  | 1157 | dict->SetEntry(entry, the_hole_value, the_hole_value); | 
|  | 1158 | removed_entries++; | 
|  | 1159 | } | 
|  | 1160 | } | 
|  | 1161 | } | 
|  | 1162 |  | 
|  | 1163 | // Update the number of elements. | 
|  | 1164 | dict->ElementsRemoved(removed_entries); | 
|  | 1165 | } | 
|  | 1166 | } | 
|  | 1167 |  | 
|  | 1168 | Handle<Object> length_obj = isolate->factory()->NewNumberFromUint(length); | 
|  | 1169 | array->set_length(*length_obj); | 
|  | 1170 | } | 
|  | 1171 |  | 
|  | 1172 | static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start, | 
|  | 1173 | FixedArrayBase* to, ElementsKind from_kind, | 
|  | 1174 | uint32_t to_start, int packed_size, | 
|  | 1175 | int copy_size) { | 
|  | 1176 | UNREACHABLE(); | 
|  | 1177 | } | 
|  | 1178 |  | 
|  | 1179 |  | 
|  | 1180 | static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) { | 
|  | 1181 | // TODO(verwaest): Remove reliance on index in Shrink. | 
|  | 1182 | Handle<SeededNumberDictionary> dict( | 
|  | 1183 | SeededNumberDictionary::cast(obj->elements())); | 
|  | 1184 | uint32_t index = GetIndexForEntryImpl(*dict, entry); | 
|  | 1185 | Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry); | 
|  | 1186 | USE(result); | 
|  | 1187 | DCHECK(result->IsTrue()); | 
|  | 1188 | Handle<FixedArray> new_elements = | 
|  | 1189 | SeededNumberDictionary::Shrink(dict, index); | 
|  | 1190 | obj->set_elements(*new_elements); | 
|  | 1191 | } | 
|  | 1192 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1193 | static bool HasAccessorsImpl(JSObject* holder, | 
|  | 1194 | FixedArrayBase* backing_store) { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1195 | DisallowHeapAllocation no_gc; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1196 | SeededNumberDictionary* dict = SeededNumberDictionary::cast(backing_store); | 
|  | 1197 | if (!dict->requires_slow_elements()) return false; | 
|  | 1198 | int capacity = dict->Capacity(); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1199 | Heap* heap = holder->GetHeap(); | 
|  | 1200 | Object* undefined = heap->undefined_value(); | 
|  | 1201 | Object* the_hole = heap->the_hole_value(); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1202 | for (int i = 0; i < capacity; i++) { | 
|  | 1203 | Object* key = dict->KeyAt(i); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1204 | if (key == the_hole || key == undefined) continue; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1205 | DCHECK(!dict->IsDeleted(i)); | 
|  | 1206 | PropertyDetails details = dict->DetailsAt(i); | 
|  | 1207 | if (details.type() == ACCESSOR_CONSTANT) return true; | 
|  | 1208 | } | 
|  | 1209 | return false; | 
|  | 1210 | } | 
|  | 1211 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1212 | static Object* GetRaw(FixedArrayBase* store, uint32_t entry) { | 
|  | 1213 | SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store); | 
|  | 1214 | return backing_store->ValueAt(entry); | 
|  | 1215 | } | 
|  | 1216 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1217 | static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) { | 
|  | 1218 | return GetImpl(holder->elements(), entry); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1219 | } | 
|  | 1220 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1221 | static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) { | 
|  | 1222 | return handle(GetRaw(backing_store, entry), backing_store->GetIsolate()); | 
|  | 1223 | } | 
|  | 1224 |  | 
|  | 1225 | static inline void SetImpl(Handle<JSObject> holder, uint32_t entry, | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1226 | Object* value) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1227 | SetImpl(holder->elements(), entry, value); | 
|  | 1228 | } | 
|  | 1229 |  | 
|  | 1230 | static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry, | 
|  | 1231 | Object* value) { | 
|  | 1232 | SeededNumberDictionary::cast(backing_store)->ValueAtPut(entry, value); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1233 | } | 
|  | 1234 |  | 
|  | 1235 | static void ReconfigureImpl(Handle<JSObject> object, | 
|  | 1236 | Handle<FixedArrayBase> store, uint32_t entry, | 
|  | 1237 | Handle<Object> value, | 
|  | 1238 | PropertyAttributes attributes) { | 
|  | 1239 | SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(*store); | 
|  | 1240 | if (attributes != NONE) object->RequireSlowElements(dictionary); | 
|  | 1241 | dictionary->ValueAtPut(entry, *value); | 
|  | 1242 | PropertyDetails details = dictionary->DetailsAt(entry); | 
|  | 1243 | details = PropertyDetails(attributes, DATA, details.dictionary_index(), | 
|  | 1244 | PropertyCellType::kNoCell); | 
|  | 1245 | dictionary->DetailsAtPut(entry, details); | 
|  | 1246 | } | 
|  | 1247 |  | 
|  | 1248 | static void AddImpl(Handle<JSObject> object, uint32_t index, | 
|  | 1249 | Handle<Object> value, PropertyAttributes attributes, | 
|  | 1250 | uint32_t new_capacity) { | 
|  | 1251 | PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell); | 
|  | 1252 | Handle<SeededNumberDictionary> dictionary = | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1253 | object->HasFastElements() || object->HasFastStringWrapperElements() | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1254 | ? JSObject::NormalizeElements(object) | 
|  | 1255 | : handle(SeededNumberDictionary::cast(object->elements())); | 
|  | 1256 | Handle<SeededNumberDictionary> new_dictionary = | 
|  | 1257 | SeededNumberDictionary::AddNumberEntry( | 
|  | 1258 | dictionary, index, value, details, | 
|  | 1259 | object->map()->is_prototype_map()); | 
|  | 1260 | if (attributes != NONE) object->RequireSlowElements(*new_dictionary); | 
|  | 1261 | if (dictionary.is_identical_to(new_dictionary)) return; | 
|  | 1262 | object->set_elements(*new_dictionary); | 
|  | 1263 | } | 
|  | 1264 |  | 
|  | 1265 | static bool HasEntryImpl(FixedArrayBase* store, uint32_t entry) { | 
|  | 1266 | DisallowHeapAllocation no_gc; | 
|  | 1267 | SeededNumberDictionary* dict = SeededNumberDictionary::cast(store); | 
|  | 1268 | Object* index = dict->KeyAt(entry); | 
|  | 1269 | return !index->IsTheHole(); | 
|  | 1270 | } | 
|  | 1271 |  | 
|  | 1272 | static uint32_t GetIndexForEntryImpl(FixedArrayBase* store, uint32_t entry) { | 
|  | 1273 | DisallowHeapAllocation no_gc; | 
|  | 1274 | SeededNumberDictionary* dict = SeededNumberDictionary::cast(store); | 
|  | 1275 | uint32_t result = 0; | 
|  | 1276 | CHECK(dict->KeyAt(entry)->ToArrayIndex(&result)); | 
|  | 1277 | return result; | 
|  | 1278 | } | 
|  | 1279 |  | 
|  | 1280 | static uint32_t GetEntryForIndexImpl(JSObject* holder, FixedArrayBase* store, | 
|  | 1281 | uint32_t index, PropertyFilter filter) { | 
|  | 1282 | DisallowHeapAllocation no_gc; | 
|  | 1283 | SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(store); | 
|  | 1284 | int entry = dictionary->FindEntry(index); | 
|  | 1285 | if (entry == SeededNumberDictionary::kNotFound) return kMaxUInt32; | 
|  | 1286 | if (filter != ALL_PROPERTIES) { | 
|  | 1287 | PropertyDetails details = dictionary->DetailsAt(entry); | 
|  | 1288 | PropertyAttributes attr = details.attributes(); | 
|  | 1289 | if ((attr & filter) != 0) return kMaxUInt32; | 
|  | 1290 | } | 
|  | 1291 | return static_cast<uint32_t>(entry); | 
|  | 1292 | } | 
|  | 1293 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1294 | static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) { | 
|  | 1295 | return GetDetailsImpl(holder->elements(), entry); | 
|  | 1296 | } | 
|  | 1297 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1298 | static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store, | 
|  | 1299 | uint32_t entry) { | 
|  | 1300 | return SeededNumberDictionary::cast(backing_store)->DetailsAt(entry); | 
|  | 1301 | } | 
|  | 1302 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1303 | static uint32_t FilterKey(Handle<SeededNumberDictionary> dictionary, | 
|  | 1304 | int entry, Object* raw_key, PropertyFilter filter) { | 
|  | 1305 | DCHECK(!dictionary->IsDeleted(entry)); | 
|  | 1306 | DCHECK(raw_key->IsNumber()); | 
|  | 1307 | DCHECK_LE(raw_key->Number(), kMaxUInt32); | 
|  | 1308 | PropertyDetails details = dictionary->DetailsAt(entry); | 
|  | 1309 | PropertyAttributes attr = details.attributes(); | 
|  | 1310 | if ((attr & filter) != 0) return kMaxUInt32; | 
|  | 1311 | return static_cast<uint32_t>(raw_key->Number()); | 
|  | 1312 | } | 
|  | 1313 |  | 
|  | 1314 | static uint32_t GetKeyForEntryImpl(Handle<SeededNumberDictionary> dictionary, | 
|  | 1315 | int entry, PropertyFilter filter) { | 
|  | 1316 | DisallowHeapAllocation no_gc; | 
|  | 1317 | Object* raw_key = dictionary->KeyAt(entry); | 
|  | 1318 | if (!dictionary->IsKey(raw_key)) return kMaxUInt32; | 
|  | 1319 | return FilterKey(dictionary, entry, raw_key, filter); | 
|  | 1320 | } | 
|  | 1321 |  | 
|  | 1322 | static uint32_t GetKeyForEntryImpl(Handle<SeededNumberDictionary> dictionary, | 
|  | 1323 | int entry, PropertyFilter filter, | 
|  | 1324 | Object* undefined, Object* the_hole) { | 
|  | 1325 | DisallowHeapAllocation no_gc; | 
|  | 1326 | Object* raw_key = dictionary->KeyAt(entry); | 
|  | 1327 | // Replace the IsKey check with a direct comparison which is much faster. | 
|  | 1328 | if (raw_key == undefined || raw_key == the_hole) { | 
|  | 1329 | return kMaxUInt32; | 
|  | 1330 | } | 
|  | 1331 | return FilterKey(dictionary, entry, raw_key, filter); | 
|  | 1332 | } | 
|  | 1333 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1334 | static void CollectElementIndicesImpl(Handle<JSObject> object, | 
|  | 1335 | Handle<FixedArrayBase> backing_store, | 
|  | 1336 | KeyAccumulator* keys, uint32_t range, | 
|  | 1337 | PropertyFilter filter, | 
|  | 1338 | uint32_t offset) { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1339 | if (filter & SKIP_STRINGS) return; | 
|  | 1340 | Isolate* isolate = keys->isolate(); | 
|  | 1341 | Handle<Object> undefined = isolate->factory()->undefined_value(); | 
|  | 1342 | Handle<Object> the_hole = isolate->factory()->the_hole_value(); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1343 | Handle<SeededNumberDictionary> dictionary = | 
|  | 1344 | Handle<SeededNumberDictionary>::cast(backing_store); | 
|  | 1345 | int capacity = dictionary->Capacity(); | 
|  | 1346 | for (int i = 0; i < capacity; i++) { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1347 | uint32_t key = | 
|  | 1348 | GetKeyForEntryImpl(dictionary, i, filter, *undefined, *the_hole); | 
|  | 1349 | if (key == kMaxUInt32) continue; | 
|  | 1350 | keys->AddKey(key); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1351 | } | 
|  | 1352 |  | 
|  | 1353 | keys->SortCurrentElementsList(); | 
|  | 1354 | } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1355 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1356 | static Handle<FixedArray> DirectCollectElementIndicesImpl( | 
|  | 1357 | Isolate* isolate, Handle<JSObject> object, | 
|  | 1358 | Handle<FixedArrayBase> backing_store, GetKeysConversion convert, | 
|  | 1359 | PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices, | 
|  | 1360 | uint32_t insertion_index = 0) { | 
|  | 1361 | if (filter & SKIP_STRINGS) return list; | 
|  | 1362 | if (filter & ONLY_ALL_CAN_READ) return list; | 
|  | 1363 |  | 
|  | 1364 | Handle<Object> undefined = isolate->factory()->undefined_value(); | 
|  | 1365 | Handle<Object> the_hole = isolate->factory()->the_hole_value(); | 
|  | 1366 | Handle<SeededNumberDictionary> dictionary = | 
|  | 1367 | Handle<SeededNumberDictionary>::cast(backing_store); | 
|  | 1368 | uint32_t capacity = dictionary->Capacity(); | 
|  | 1369 | for (uint32_t i = 0; i < capacity; i++) { | 
|  | 1370 | uint32_t key = | 
|  | 1371 | GetKeyForEntryImpl(dictionary, i, filter, *undefined, *the_hole); | 
|  | 1372 | if (key == kMaxUInt32) continue; | 
|  | 1373 | Handle<Object> index = isolate->factory()->NewNumberFromUint(key); | 
|  | 1374 | list->set(insertion_index, *index); | 
|  | 1375 | insertion_index++; | 
|  | 1376 | } | 
|  | 1377 | *nof_indices = insertion_index; | 
|  | 1378 | return list; | 
|  | 1379 | } | 
|  | 1380 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1381 | static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver, | 
|  | 1382 | KeyAccumulator* accumulator, | 
|  | 1383 | AddKeyConversion convert) { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1384 | Isolate* isolate = accumulator->isolate(); | 
|  | 1385 | Handle<Object> undefined = isolate->factory()->undefined_value(); | 
|  | 1386 | Handle<Object> the_hole = isolate->factory()->the_hole_value(); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1387 | SeededNumberDictionary* dictionary = | 
|  | 1388 | SeededNumberDictionary::cast(receiver->elements()); | 
|  | 1389 | int capacity = dictionary->Capacity(); | 
|  | 1390 | for (int i = 0; i < capacity; i++) { | 
|  | 1391 | Object* k = dictionary->KeyAt(i); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1392 | if (k == *undefined) continue; | 
|  | 1393 | if (k == *the_hole) continue; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1394 | if (dictionary->IsDeleted(i)) continue; | 
|  | 1395 | Object* value = dictionary->ValueAt(i); | 
|  | 1396 | DCHECK(!value->IsTheHole()); | 
|  | 1397 | DCHECK(!value->IsAccessorPair()); | 
|  | 1398 | DCHECK(!value->IsAccessorInfo()); | 
|  | 1399 | accumulator->AddKey(value, convert); | 
|  | 1400 | } | 
|  | 1401 | } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1402 | }; | 
|  | 1403 |  | 
|  | 1404 |  | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1405 | // Super class for all fast element arrays. | 
|  | 1406 | template<typename FastElementsAccessorSubclass, | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1407 | typename KindTraits> | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 1408 | class FastElementsAccessor | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1409 | : public ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits> { | 
| Ben Murdoch | 5d4cdbf | 2012-04-11 10:23:59 +0100 | [diff] [blame] | 1410 | public: | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1411 | explicit FastElementsAccessor(const char* name) | 
|  | 1412 | : ElementsAccessorBase<FastElementsAccessorSubclass, | 
|  | 1413 | KindTraits>(name) {} | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1414 |  | 
|  | 1415 | typedef typename KindTraits::BackingStore BackingStore; | 
|  | 1416 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1417 | static Handle<SeededNumberDictionary> NormalizeImpl( | 
|  | 1418 | Handle<JSObject> object, Handle<FixedArrayBase> store) { | 
|  | 1419 | Isolate* isolate = store->GetIsolate(); | 
|  | 1420 | ElementsKind kind = FastElementsAccessorSubclass::kind(); | 
|  | 1421 |  | 
|  | 1422 | // Ensure that notifications fire if the array or object prototypes are | 
|  | 1423 | // normalizing. | 
|  | 1424 | if (IsFastSmiOrObjectElementsKind(kind)) { | 
|  | 1425 | isolate->UpdateArrayProtectorOnNormalizeElements(object); | 
|  | 1426 | } | 
|  | 1427 |  | 
|  | 1428 | int capacity = object->GetFastElementsUsage(); | 
|  | 1429 | Handle<SeededNumberDictionary> dictionary = | 
|  | 1430 | SeededNumberDictionary::New(isolate, capacity); | 
|  | 1431 |  | 
|  | 1432 | PropertyDetails details = PropertyDetails::Empty(); | 
|  | 1433 | bool used_as_prototype = object->map()->is_prototype_map(); | 
|  | 1434 | int j = 0; | 
|  | 1435 | for (int i = 0; j < capacity; i++) { | 
|  | 1436 | if (IsHoleyElementsKind(kind)) { | 
|  | 1437 | if (BackingStore::cast(*store)->is_the_hole(i)) continue; | 
|  | 1438 | } | 
|  | 1439 | Handle<Object> value = FastElementsAccessorSubclass::GetImpl(*store, i); | 
|  | 1440 | dictionary = SeededNumberDictionary::AddNumberEntry( | 
|  | 1441 | dictionary, i, value, details, used_as_prototype); | 
|  | 1442 | j++; | 
|  | 1443 | } | 
|  | 1444 | return dictionary; | 
|  | 1445 | } | 
|  | 1446 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1447 | static void DeleteAtEnd(Handle<JSObject> obj, | 
|  | 1448 | Handle<BackingStore> backing_store, uint32_t entry) { | 
|  | 1449 | uint32_t length = static_cast<uint32_t>(backing_store->length()); | 
|  | 1450 | Heap* heap = obj->GetHeap(); | 
|  | 1451 | for (; entry > 0; entry--) { | 
|  | 1452 | if (!backing_store->is_the_hole(entry - 1)) break; | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1453 | } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1454 | if (entry == 0) { | 
|  | 1455 | FixedArray* empty = heap->empty_fixed_array(); | 
|  | 1456 | if (obj->HasFastArgumentsElements()) { | 
|  | 1457 | FixedArray::cast(obj->elements())->set(1, empty); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1458 | } else { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1459 | obj->set_elements(empty); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1460 | } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1461 | return; | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1462 | } | 
|  | 1463 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1464 | heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(*backing_store, | 
|  | 1465 | length - entry); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1466 | } | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1467 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1468 | static void DeleteCommon(Handle<JSObject> obj, uint32_t entry, | 
|  | 1469 | Handle<FixedArrayBase> store) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1470 | DCHECK(obj->HasFastSmiOrObjectElements() || obj->HasFastDoubleElements() || | 
|  | 1471 | obj->HasFastArgumentsElements() || | 
|  | 1472 | obj->HasFastStringWrapperElements()); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1473 | Handle<BackingStore> backing_store = Handle<BackingStore>::cast(store); | 
|  | 1474 | if (!obj->IsJSArray() && | 
|  | 1475 | entry == static_cast<uint32_t>(store->length()) - 1) { | 
|  | 1476 | DeleteAtEnd(obj, backing_store, entry); | 
|  | 1477 | return; | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1478 | } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1479 |  | 
|  | 1480 | backing_store->set_the_hole(entry); | 
|  | 1481 |  | 
|  | 1482 | // TODO(verwaest): Move this out of elements.cc. | 
|  | 1483 | // If an old space backing store is larger than a certain size and | 
|  | 1484 | // has too few used values, normalize it. | 
|  | 1485 | // To avoid doing the check on every delete we require at least | 
|  | 1486 | // one adjacent hole to the value being deleted. | 
|  | 1487 | const int kMinLengthForSparsenessCheck = 64; | 
|  | 1488 | if (backing_store->length() < kMinLengthForSparsenessCheck) return; | 
|  | 1489 | if (backing_store->GetHeap()->InNewSpace(*backing_store)) return; | 
|  | 1490 | uint32_t length = 0; | 
|  | 1491 | if (obj->IsJSArray()) { | 
|  | 1492 | JSArray::cast(*obj)->length()->ToArrayLength(&length); | 
|  | 1493 | } else { | 
|  | 1494 | length = static_cast<uint32_t>(store->length()); | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 1495 | } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1496 | if ((entry > 0 && backing_store->is_the_hole(entry - 1)) || | 
|  | 1497 | (entry + 1 < length && backing_store->is_the_hole(entry + 1))) { | 
|  | 1498 | if (!obj->IsJSArray()) { | 
|  | 1499 | uint32_t i; | 
|  | 1500 | for (i = entry + 1; i < length; i++) { | 
|  | 1501 | if (!backing_store->is_the_hole(i)) break; | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1502 | } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1503 | if (i == length) { | 
|  | 1504 | DeleteAtEnd(obj, backing_store, entry); | 
|  | 1505 | return; | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1506 | } | 
|  | 1507 | } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1508 | int num_used = 0; | 
|  | 1509 | for (int i = 0; i < backing_store->length(); ++i) { | 
|  | 1510 | if (!backing_store->is_the_hole(i)) { | 
|  | 1511 | ++num_used; | 
|  | 1512 | // Bail out if a number dictionary wouldn't be able to save at least | 
|  | 1513 | // 75% space. | 
|  | 1514 | if (4 * SeededNumberDictionary::ComputeCapacity(num_used) * | 
|  | 1515 | SeededNumberDictionary::kEntrySize > | 
|  | 1516 | backing_store->length()) { | 
|  | 1517 | return; | 
|  | 1518 | } | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 1519 | } | 
|  | 1520 | } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1521 | JSObject::NormalizeElements(obj); | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 1522 | } | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 1523 | } | 
|  | 1524 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1525 | static void ReconfigureImpl(Handle<JSObject> object, | 
|  | 1526 | Handle<FixedArrayBase> store, uint32_t entry, | 
|  | 1527 | Handle<Object> value, | 
|  | 1528 | PropertyAttributes attributes) { | 
|  | 1529 | Handle<SeededNumberDictionary> dictionary = | 
|  | 1530 | JSObject::NormalizeElements(object); | 
|  | 1531 | entry = dictionary->FindEntry(entry); | 
|  | 1532 | DictionaryElementsAccessor::ReconfigureImpl(object, dictionary, entry, | 
|  | 1533 | value, attributes); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1534 | } | 
|  | 1535 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1536 | static void AddImpl(Handle<JSObject> object, uint32_t index, | 
|  | 1537 | Handle<Object> value, PropertyAttributes attributes, | 
|  | 1538 | uint32_t new_capacity) { | 
|  | 1539 | DCHECK_EQ(NONE, attributes); | 
|  | 1540 | ElementsKind from_kind = object->GetElementsKind(); | 
|  | 1541 | ElementsKind to_kind = FastElementsAccessorSubclass::kind(); | 
|  | 1542 | if (IsDictionaryElementsKind(from_kind) || | 
|  | 1543 | IsFastDoubleElementsKind(from_kind) != | 
|  | 1544 | IsFastDoubleElementsKind(to_kind) || | 
|  | 1545 | FastElementsAccessorSubclass::GetCapacityImpl( | 
|  | 1546 | *object, object->elements()) != new_capacity) { | 
|  | 1547 | FastElementsAccessorSubclass::GrowCapacityAndConvertImpl(object, | 
|  | 1548 | new_capacity); | 
|  | 1549 | } else { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1550 | if (IsFastElementsKind(from_kind) && from_kind != to_kind) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1551 | JSObject::TransitionElementsKind(object, to_kind); | 
|  | 1552 | } | 
|  | 1553 | if (IsFastSmiOrObjectElementsKind(from_kind)) { | 
|  | 1554 | DCHECK(IsFastSmiOrObjectElementsKind(to_kind)); | 
|  | 1555 | JSObject::EnsureWritableFastElements(object); | 
|  | 1556 | } | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1557 | } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1558 | FastElementsAccessorSubclass::SetImpl(object, index, *value); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1559 | } | 
|  | 1560 |  | 
|  | 1561 | static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) { | 
|  | 1562 | ElementsKind kind = KindTraits::Kind; | 
|  | 1563 | if (IsFastPackedElementsKind(kind)) { | 
|  | 1564 | JSObject::TransitionElementsKind(obj, GetHoleyElementsKind(kind)); | 
|  | 1565 | } | 
|  | 1566 | if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) { | 
|  | 1567 | JSObject::EnsureWritableFastElements(obj); | 
|  | 1568 | } | 
|  | 1569 | DeleteCommon(obj, entry, handle(obj->elements())); | 
|  | 1570 | } | 
|  | 1571 |  | 
|  | 1572 | static bool HasEntryImpl(FixedArrayBase* backing_store, uint32_t entry) { | 
|  | 1573 | return !BackingStore::cast(backing_store)->is_the_hole(entry); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1574 | } | 
|  | 1575 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1576 | static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver, | 
|  | 1577 | KeyAccumulator* accumulator, | 
|  | 1578 | AddKeyConversion convert) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1579 | Handle<FixedArrayBase> elements(receiver->elements(), | 
|  | 1580 | receiver->GetIsolate()); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1581 | uint32_t length = | 
|  | 1582 | FastElementsAccessorSubclass::GetIterationLength(*receiver, *elements); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1583 | for (uint32_t i = 0; i < length; i++) { | 
|  | 1584 | if (IsFastPackedElementsKind(KindTraits::Kind) || | 
|  | 1585 | HasEntryImpl(*elements, i)) { | 
|  | 1586 | accumulator->AddKey(FastElementsAccessorSubclass::GetImpl(*elements, i), | 
|  | 1587 | convert); | 
|  | 1588 | } | 
|  | 1589 | } | 
|  | 1590 | } | 
|  | 1591 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1592 | static void ValidateContents(Handle<JSObject> holder, int length) { | 
|  | 1593 | #if DEBUG | 
|  | 1594 | Isolate* isolate = holder->GetIsolate(); | 
|  | 1595 | HandleScope scope(isolate); | 
|  | 1596 | Handle<FixedArrayBase> elements(holder->elements(), isolate); | 
|  | 1597 | Map* map = elements->map(); | 
|  | 1598 | DCHECK((IsFastSmiOrObjectElementsKind(KindTraits::Kind) && | 
|  | 1599 | (map == isolate->heap()->fixed_array_map() || | 
|  | 1600 | map == isolate->heap()->fixed_cow_array_map())) || | 
|  | 1601 | (IsFastDoubleElementsKind(KindTraits::Kind) == | 
|  | 1602 | ((map == isolate->heap()->fixed_array_map() && length == 0) || | 
|  | 1603 | map == isolate->heap()->fixed_double_array_map()))); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1604 | if (length == 0) return;  // nothing to do! | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1605 | DisallowHeapAllocation no_gc; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1606 | Handle<BackingStore> backing_store = Handle<BackingStore>::cast(elements); | 
|  | 1607 | if (IsFastSmiElementsKind(KindTraits::Kind)) { | 
|  | 1608 | for (int i = 0; i < length; i++) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1609 | DCHECK(BackingStore::get(*backing_store, i, isolate)->IsSmi() || | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1610 | (IsFastHoleyElementsKind(KindTraits::Kind) && | 
|  | 1611 | backing_store->is_the_hole(i))); | 
|  | 1612 | } | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1613 | } | 
|  | 1614 | #endif | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 1615 | } | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 1616 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1617 | static Handle<Object> PopImpl(Handle<JSArray> receiver) { | 
|  | 1618 | return FastElementsAccessorSubclass::RemoveElement(receiver, AT_END); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1619 | } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1620 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1621 | static Handle<Object> ShiftImpl(Handle<JSArray> receiver) { | 
|  | 1622 | return FastElementsAccessorSubclass::RemoveElement(receiver, AT_START); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1623 | } | 
|  | 1624 |  | 
|  | 1625 | static uint32_t PushImpl(Handle<JSArray> receiver, | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1626 | Arguments* args, uint32_t push_size) { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1627 | Handle<FixedArrayBase> backing_store(receiver->elements()); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1628 | return FastElementsAccessorSubclass::AddArguments(receiver, backing_store, | 
|  | 1629 | args, push_size, AT_END); | 
|  | 1630 | } | 
|  | 1631 |  | 
|  | 1632 | static uint32_t UnshiftImpl(Handle<JSArray> receiver, | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1633 | Arguments* args, uint32_t unshift_size) { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1634 | Handle<FixedArrayBase> backing_store(receiver->elements()); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1635 | return FastElementsAccessorSubclass::AddArguments( | 
|  | 1636 | receiver, backing_store, args, unshift_size, AT_START); | 
|  | 1637 | } | 
|  | 1638 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1639 | static Handle<JSArray> SliceImpl(Handle<JSObject> receiver, | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1640 | uint32_t start, uint32_t end) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1641 | Isolate* isolate = receiver->GetIsolate(); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1642 | Handle<FixedArrayBase> backing_store(receiver->elements(), isolate); | 
|  | 1643 | int result_len = end < start ? 0u : end - start; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1644 | Handle<JSArray> result_array = isolate->factory()->NewJSArray( | 
|  | 1645 | KindTraits::Kind, result_len, result_len); | 
|  | 1646 | DisallowHeapAllocation no_gc; | 
|  | 1647 | FastElementsAccessorSubclass::CopyElementsImpl( | 
|  | 1648 | *backing_store, start, result_array->elements(), KindTraits::Kind, 0, | 
|  | 1649 | kPackedSizeNotKnown, result_len); | 
|  | 1650 | FastElementsAccessorSubclass::TryTransitionResultArrayToPacked( | 
|  | 1651 | result_array); | 
|  | 1652 | return result_array; | 
|  | 1653 | } | 
|  | 1654 |  | 
|  | 1655 | static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver, | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1656 | uint32_t start, uint32_t delete_count, | 
|  | 1657 | Arguments* args, uint32_t add_count) { | 
|  | 1658 | Isolate* isolate = receiver->GetIsolate(); | 
|  | 1659 | Heap* heap = isolate->heap(); | 
|  | 1660 | uint32_t length = Smi::cast(receiver->length())->value(); | 
|  | 1661 | uint32_t new_length = length - delete_count + add_count; | 
|  | 1662 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1663 | ElementsKind kind = KindTraits::Kind; | 
|  | 1664 | if (new_length <= static_cast<uint32_t>(receiver->elements()->length()) && | 
|  | 1665 | IsFastSmiOrObjectElementsKind(kind)) { | 
|  | 1666 | HandleScope scope(isolate); | 
|  | 1667 | JSObject::EnsureWritableFastElements(receiver); | 
|  | 1668 | } | 
|  | 1669 |  | 
|  | 1670 | Handle<FixedArrayBase> backing_store(receiver->elements(), isolate); | 
|  | 1671 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1672 | if (new_length == 0) { | 
|  | 1673 | receiver->set_elements(heap->empty_fixed_array()); | 
|  | 1674 | receiver->set_length(Smi::FromInt(0)); | 
|  | 1675 | return isolate->factory()->NewJSArrayWithElements( | 
|  | 1676 | backing_store, KindTraits::Kind, delete_count); | 
|  | 1677 | } | 
|  | 1678 |  | 
|  | 1679 | // Construct the result array which holds the deleted elements. | 
|  | 1680 | Handle<JSArray> deleted_elements = isolate->factory()->NewJSArray( | 
|  | 1681 | KindTraits::Kind, delete_count, delete_count); | 
|  | 1682 | if (delete_count > 0) { | 
|  | 1683 | DisallowHeapAllocation no_gc; | 
|  | 1684 | FastElementsAccessorSubclass::CopyElementsImpl( | 
|  | 1685 | *backing_store, start, deleted_elements->elements(), KindTraits::Kind, | 
|  | 1686 | 0, kPackedSizeNotKnown, delete_count); | 
|  | 1687 | } | 
|  | 1688 |  | 
|  | 1689 | // Delete and move elements to make space for add_count new elements. | 
|  | 1690 | if (add_count < delete_count) { | 
|  | 1691 | FastElementsAccessorSubclass::SpliceShrinkStep( | 
|  | 1692 | isolate, receiver, backing_store, start, delete_count, add_count, | 
|  | 1693 | length, new_length); | 
|  | 1694 | } else if (add_count > delete_count) { | 
|  | 1695 | backing_store = FastElementsAccessorSubclass::SpliceGrowStep( | 
|  | 1696 | isolate, receiver, backing_store, start, delete_count, add_count, | 
|  | 1697 | length, new_length); | 
|  | 1698 | } | 
|  | 1699 |  | 
|  | 1700 | // Copy over the arguments. | 
|  | 1701 | FastElementsAccessorSubclass::CopyArguments(args, backing_store, add_count, | 
|  | 1702 | 3, start); | 
|  | 1703 |  | 
|  | 1704 | receiver->set_length(Smi::FromInt(new_length)); | 
|  | 1705 | FastElementsAccessorSubclass::TryTransitionResultArrayToPacked( | 
|  | 1706 | deleted_elements); | 
|  | 1707 | return deleted_elements; | 
|  | 1708 | } | 
|  | 1709 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1710 | static Maybe<bool> CollectValuesOrEntriesImpl( | 
|  | 1711 | Isolate* isolate, Handle<JSObject> object, | 
|  | 1712 | Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items, | 
|  | 1713 | PropertyFilter filter) { | 
|  | 1714 | int count = 0; | 
|  | 1715 | uint32_t length = object->elements()->length(); | 
|  | 1716 | for (uint32_t index = 0; index < length; ++index) { | 
|  | 1717 | if (!HasEntryImpl(object->elements(), index)) continue; | 
|  | 1718 | Handle<Object> value = | 
|  | 1719 | FastElementsAccessorSubclass::GetImpl(object->elements(), index); | 
|  | 1720 | if (get_entries) { | 
|  | 1721 | value = MakeEntryPair(isolate, index, value); | 
|  | 1722 | } | 
|  | 1723 | values_or_entries->set(count++, *value); | 
|  | 1724 | } | 
|  | 1725 | *nof_items = count; | 
|  | 1726 | return Just(true); | 
|  | 1727 | } | 
|  | 1728 |  | 
|  | 1729 | static void MoveElements(Isolate* isolate, Handle<JSArray> receiver, | 
|  | 1730 | Handle<FixedArrayBase> backing_store, int dst_index, | 
|  | 1731 | int src_index, int len, int hole_start, | 
|  | 1732 | int hole_end) { | 
|  | 1733 | Heap* heap = isolate->heap(); | 
|  | 1734 | Handle<BackingStore> dst_elms = Handle<BackingStore>::cast(backing_store); | 
|  | 1735 | if (heap->CanMoveObjectStart(*dst_elms) && dst_index == 0) { | 
|  | 1736 | // Update all the copies of this backing_store handle. | 
|  | 1737 | *dst_elms.location() = | 
|  | 1738 | BackingStore::cast(heap->LeftTrimFixedArray(*dst_elms, src_index)); | 
|  | 1739 | receiver->set_elements(*dst_elms); | 
|  | 1740 | // Adjust the hole offset as the array has been shrunk. | 
|  | 1741 | hole_end -= src_index; | 
|  | 1742 | DCHECK_LE(hole_start, backing_store->length()); | 
|  | 1743 | DCHECK_LE(hole_end, backing_store->length()); | 
|  | 1744 | } else if (len != 0) { | 
|  | 1745 | if (IsFastDoubleElementsKind(KindTraits::Kind)) { | 
|  | 1746 | MemMove(dst_elms->data_start() + dst_index, | 
|  | 1747 | dst_elms->data_start() + src_index, len * kDoubleSize); | 
|  | 1748 | } else { | 
|  | 1749 | DisallowHeapAllocation no_gc; | 
|  | 1750 | heap->MoveElements(FixedArray::cast(*dst_elms), dst_index, src_index, | 
|  | 1751 | len); | 
|  | 1752 | } | 
|  | 1753 | } | 
|  | 1754 | if (hole_start != hole_end) { | 
|  | 1755 | dst_elms->FillWithHoles(hole_start, hole_end); | 
|  | 1756 | } | 
|  | 1757 | } | 
|  | 1758 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1759 | private: | 
|  | 1760 | // SpliceShrinkStep might modify the backing_store. | 
|  | 1761 | static void SpliceShrinkStep(Isolate* isolate, Handle<JSArray> receiver, | 
|  | 1762 | Handle<FixedArrayBase> backing_store, | 
|  | 1763 | uint32_t start, uint32_t delete_count, | 
|  | 1764 | uint32_t add_count, uint32_t len, | 
|  | 1765 | uint32_t new_length) { | 
|  | 1766 | const int move_left_count = len - delete_count - start; | 
|  | 1767 | const int move_left_dst_index = start + add_count; | 
|  | 1768 | FastElementsAccessorSubclass::MoveElements( | 
|  | 1769 | isolate, receiver, backing_store, move_left_dst_index, | 
|  | 1770 | start + delete_count, move_left_count, new_length, len); | 
|  | 1771 | } | 
|  | 1772 |  | 
|  | 1773 | // SpliceGrowStep might modify the backing_store. | 
|  | 1774 | static Handle<FixedArrayBase> SpliceGrowStep( | 
|  | 1775 | Isolate* isolate, Handle<JSArray> receiver, | 
|  | 1776 | Handle<FixedArrayBase> backing_store, uint32_t start, | 
|  | 1777 | uint32_t delete_count, uint32_t add_count, uint32_t length, | 
|  | 1778 | uint32_t new_length) { | 
|  | 1779 | // Check we do not overflow the new_length. | 
|  | 1780 | DCHECK((add_count - delete_count) <= (Smi::kMaxValue - length)); | 
|  | 1781 | // Check if backing_store is big enough. | 
|  | 1782 | if (new_length <= static_cast<uint32_t>(backing_store->length())) { | 
|  | 1783 | FastElementsAccessorSubclass::MoveElements( | 
|  | 1784 | isolate, receiver, backing_store, start + add_count, | 
|  | 1785 | start + delete_count, (length - delete_count - start), 0, 0); | 
|  | 1786 | // MoveElements updates the backing_store in-place. | 
|  | 1787 | return backing_store; | 
|  | 1788 | } | 
|  | 1789 | // New backing storage is needed. | 
|  | 1790 | int capacity = JSObject::NewElementsCapacity(new_length); | 
|  | 1791 | // Partially copy all elements up to start. | 
|  | 1792 | Handle<FixedArrayBase> new_elms = | 
|  | 1793 | FastElementsAccessorSubclass::ConvertElementsWithCapacity( | 
|  | 1794 | receiver, backing_store, KindTraits::Kind, capacity, start); | 
|  | 1795 | // Copy the trailing elements after start + delete_count | 
|  | 1796 | FastElementsAccessorSubclass::CopyElementsImpl( | 
|  | 1797 | *backing_store, start + delete_count, *new_elms, KindTraits::Kind, | 
|  | 1798 | start + add_count, kPackedSizeNotKnown, | 
|  | 1799 | ElementsAccessor::kCopyToEndAndInitializeToHole); | 
|  | 1800 | receiver->set_elements(*new_elms); | 
|  | 1801 | return new_elms; | 
|  | 1802 | } | 
|  | 1803 |  | 
|  | 1804 | static Handle<Object> RemoveElement(Handle<JSArray> receiver, | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1805 | Where remove_position) { | 
|  | 1806 | Isolate* isolate = receiver->GetIsolate(); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1807 | ElementsKind kind = KindTraits::Kind; | 
|  | 1808 | if (IsFastSmiOrObjectElementsKind(kind)) { | 
|  | 1809 | HandleScope scope(isolate); | 
|  | 1810 | JSObject::EnsureWritableFastElements(receiver); | 
|  | 1811 | } | 
|  | 1812 | Handle<FixedArrayBase> backing_store(receiver->elements(), isolate); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1813 | uint32_t length = | 
|  | 1814 | static_cast<uint32_t>(Smi::cast(receiver->length())->value()); | 
|  | 1815 | DCHECK(length > 0); | 
|  | 1816 | int new_length = length - 1; | 
|  | 1817 | int remove_index = remove_position == AT_START ? 0 : new_length; | 
|  | 1818 | Handle<Object> result = | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1819 | FastElementsAccessorSubclass::GetImpl(*backing_store, remove_index); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1820 | if (remove_position == AT_START) { | 
|  | 1821 | FastElementsAccessorSubclass::MoveElements( | 
|  | 1822 | isolate, receiver, backing_store, 0, 1, new_length, 0, 0); | 
|  | 1823 | } | 
|  | 1824 | FastElementsAccessorSubclass::SetLengthImpl(isolate, receiver, new_length, | 
|  | 1825 | backing_store); | 
|  | 1826 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1827 | if (IsHoleyElementsKind(kind) && result->IsTheHole()) { | 
|  | 1828 | return isolate->factory()->undefined_value(); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1829 | } | 
|  | 1830 | return result; | 
|  | 1831 | } | 
|  | 1832 |  | 
|  | 1833 | static uint32_t AddArguments(Handle<JSArray> receiver, | 
|  | 1834 | Handle<FixedArrayBase> backing_store, | 
|  | 1835 | Arguments* args, uint32_t add_size, | 
|  | 1836 | Where remove_position) { | 
|  | 1837 | uint32_t length = Smi::cast(receiver->length())->value(); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1838 | DCHECK(0 < add_size); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1839 | uint32_t elms_len = backing_store->length(); | 
|  | 1840 | // Check we do not overflow the new_length. | 
|  | 1841 | DCHECK(add_size <= static_cast<uint32_t>(Smi::kMaxValue - length)); | 
|  | 1842 | uint32_t new_length = length + add_size; | 
|  | 1843 |  | 
|  | 1844 | if (new_length > elms_len) { | 
|  | 1845 | // New backing storage is needed. | 
|  | 1846 | uint32_t capacity = JSObject::NewElementsCapacity(new_length); | 
|  | 1847 | // If we add arguments to the start we have to shift the existing objects. | 
|  | 1848 | int copy_dst_index = remove_position == AT_START ? add_size : 0; | 
|  | 1849 | // Copy over all objects to a new backing_store. | 
|  | 1850 | backing_store = FastElementsAccessorSubclass::ConvertElementsWithCapacity( | 
|  | 1851 | receiver, backing_store, KindTraits::Kind, capacity, 0, | 
|  | 1852 | copy_dst_index, ElementsAccessor::kCopyToEndAndInitializeToHole); | 
|  | 1853 | receiver->set_elements(*backing_store); | 
|  | 1854 | } else if (remove_position == AT_START) { | 
|  | 1855 | // If the backing store has enough capacity and we add elements to the | 
|  | 1856 | // start we have to shift the existing objects. | 
|  | 1857 | Isolate* isolate = receiver->GetIsolate(); | 
|  | 1858 | FastElementsAccessorSubclass::MoveElements( | 
|  | 1859 | isolate, receiver, backing_store, add_size, 0, length, 0, 0); | 
|  | 1860 | } | 
|  | 1861 |  | 
|  | 1862 | int insertion_index = remove_position == AT_START ? 0 : length; | 
|  | 1863 | // Copy the arguments to the start. | 
|  | 1864 | FastElementsAccessorSubclass::CopyArguments(args, backing_store, add_size, | 
|  | 1865 | 1, insertion_index); | 
|  | 1866 | // Set the length. | 
|  | 1867 | receiver->set_length(Smi::FromInt(new_length)); | 
|  | 1868 | return new_length; | 
|  | 1869 | } | 
|  | 1870 |  | 
|  | 1871 | static void CopyArguments(Arguments* args, Handle<FixedArrayBase> dst_store, | 
|  | 1872 | uint32_t copy_size, uint32_t src_index, | 
|  | 1873 | uint32_t dst_index) { | 
|  | 1874 | // Add the provided values. | 
|  | 1875 | DisallowHeapAllocation no_gc; | 
|  | 1876 | FixedArrayBase* raw_backing_store = *dst_store; | 
|  | 1877 | WriteBarrierMode mode = raw_backing_store->GetWriteBarrierMode(no_gc); | 
|  | 1878 | for (uint32_t i = 0; i < copy_size; i++) { | 
|  | 1879 | Object* argument = (*args)[i + src_index]; | 
|  | 1880 | FastElementsAccessorSubclass::SetImpl(raw_backing_store, i + dst_index, | 
|  | 1881 | argument, mode); | 
|  | 1882 | } | 
|  | 1883 | } | 
|  | 1884 | }; | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1885 |  | 
|  | 1886 |  | 
|  | 1887 | template<typename FastElementsAccessorSubclass, | 
|  | 1888 | typename KindTraits> | 
|  | 1889 | class FastSmiOrObjectElementsAccessor | 
|  | 1890 | : public FastElementsAccessor<FastElementsAccessorSubclass, KindTraits> { | 
|  | 1891 | public: | 
|  | 1892 | explicit FastSmiOrObjectElementsAccessor(const char* name) | 
|  | 1893 | : FastElementsAccessor<FastElementsAccessorSubclass, | 
|  | 1894 | KindTraits>(name) {} | 
|  | 1895 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1896 | static inline void SetImpl(Handle<JSObject> holder, uint32_t entry, | 
|  | 1897 | Object* value) { | 
|  | 1898 | SetImpl(holder->elements(), entry, value); | 
|  | 1899 | } | 
|  | 1900 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1901 | static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry, | 
|  | 1902 | Object* value) { | 
|  | 1903 | FixedArray::cast(backing_store)->set(entry, value); | 
|  | 1904 | } | 
|  | 1905 |  | 
|  | 1906 | static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry, | 
|  | 1907 | Object* value, WriteBarrierMode mode) { | 
|  | 1908 | FixedArray::cast(backing_store)->set(entry, value, mode); | 
|  | 1909 | } | 
|  | 1910 |  | 
|  | 1911 | static Object* GetRaw(FixedArray* backing_store, uint32_t entry) { | 
|  | 1912 | uint32_t index = FastElementsAccessorSubclass::GetIndexForEntryImpl( | 
|  | 1913 | backing_store, entry); | 
|  | 1914 | return backing_store->get(index); | 
|  | 1915 | } | 
|  | 1916 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1917 |  | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 1918 | // NOTE: this method violates the handlified function signature convention: | 
|  | 1919 | // raw pointer parameters in the function that allocates. | 
|  | 1920 | // See ElementsAccessor::CopyElements() for details. | 
|  | 1921 | // This method could actually allocate if copying from double elements to | 
|  | 1922 | // object elements. | 
|  | 1923 | static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start, | 
|  | 1924 | FixedArrayBase* to, ElementsKind from_kind, | 
|  | 1925 | uint32_t to_start, int packed_size, | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1926 | int copy_size) { | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 1927 | DisallowHeapAllocation no_gc; | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1928 | ElementsKind to_kind = KindTraits::Kind; | 
|  | 1929 | switch (from_kind) { | 
|  | 1930 | case FAST_SMI_ELEMENTS: | 
|  | 1931 | case FAST_HOLEY_SMI_ELEMENTS: | 
|  | 1932 | case FAST_ELEMENTS: | 
|  | 1933 | case FAST_HOLEY_ELEMENTS: | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1934 | case FAST_STRING_WRAPPER_ELEMENTS: | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 1935 | CopyObjectToObjectElements(from, from_kind, from_start, to, to_kind, | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1936 | to_start, copy_size); | 
|  | 1937 | break; | 
|  | 1938 | case FAST_DOUBLE_ELEMENTS: | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 1939 | case FAST_HOLEY_DOUBLE_ELEMENTS: { | 
|  | 1940 | AllowHeapAllocation allow_allocation; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1941 | DCHECK(IsFastObjectElementsKind(to_kind)); | 
|  | 1942 | CopyDoubleToObjectElements(from, from_start, to, to_start, copy_size); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1943 | break; | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 1944 | } | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1945 | case DICTIONARY_ELEMENTS: | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1946 | case SLOW_STRING_WRAPPER_ELEMENTS: | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 1947 | CopyDictionaryToObjectElements(from, from_start, to, to_kind, to_start, | 
|  | 1948 | copy_size); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1949 | break; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1950 | case FAST_SLOPPY_ARGUMENTS_ELEMENTS: | 
|  | 1951 | case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1952 | #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS: | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1953 | TYPED_ARRAYS(TYPED_ARRAY_CASE) | 
|  | 1954 | #undef TYPED_ARRAY_CASE | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1955 | // This function is currently only used for JSArrays with non-zero | 
|  | 1956 | // length. | 
|  | 1957 | UNREACHABLE(); | 
|  | 1958 | break; | 
|  | 1959 | case NO_ELEMENTS: | 
|  | 1960 | break;  // Nothing to do. | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1961 | } | 
|  | 1962 | } | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1963 | }; | 
|  | 1964 |  | 
|  | 1965 |  | 
|  | 1966 | class FastPackedSmiElementsAccessor | 
|  | 1967 | : public FastSmiOrObjectElementsAccessor< | 
|  | 1968 | FastPackedSmiElementsAccessor, | 
|  | 1969 | ElementsKindTraits<FAST_SMI_ELEMENTS> > { | 
|  | 1970 | public: | 
|  | 1971 | explicit FastPackedSmiElementsAccessor(const char* name) | 
|  | 1972 | : FastSmiOrObjectElementsAccessor< | 
|  | 1973 | FastPackedSmiElementsAccessor, | 
|  | 1974 | ElementsKindTraits<FAST_SMI_ELEMENTS> >(name) {} | 
|  | 1975 | }; | 
|  | 1976 |  | 
|  | 1977 |  | 
|  | 1978 | class FastHoleySmiElementsAccessor | 
|  | 1979 | : public FastSmiOrObjectElementsAccessor< | 
|  | 1980 | FastHoleySmiElementsAccessor, | 
|  | 1981 | ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> > { | 
|  | 1982 | public: | 
|  | 1983 | explicit FastHoleySmiElementsAccessor(const char* name) | 
|  | 1984 | : FastSmiOrObjectElementsAccessor< | 
|  | 1985 | FastHoleySmiElementsAccessor, | 
|  | 1986 | ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> >(name) {} | 
|  | 1987 | }; | 
|  | 1988 |  | 
|  | 1989 |  | 
|  | 1990 | class FastPackedObjectElementsAccessor | 
|  | 1991 | : public FastSmiOrObjectElementsAccessor< | 
|  | 1992 | FastPackedObjectElementsAccessor, | 
|  | 1993 | ElementsKindTraits<FAST_ELEMENTS> > { | 
|  | 1994 | public: | 
|  | 1995 | explicit FastPackedObjectElementsAccessor(const char* name) | 
|  | 1996 | : FastSmiOrObjectElementsAccessor< | 
|  | 1997 | FastPackedObjectElementsAccessor, | 
|  | 1998 | ElementsKindTraits<FAST_ELEMENTS> >(name) {} | 
|  | 1999 | }; | 
|  | 2000 |  | 
|  | 2001 |  | 
|  | 2002 | class FastHoleyObjectElementsAccessor | 
|  | 2003 | : public FastSmiOrObjectElementsAccessor< | 
|  | 2004 | FastHoleyObjectElementsAccessor, | 
|  | 2005 | ElementsKindTraits<FAST_HOLEY_ELEMENTS> > { | 
|  | 2006 | public: | 
|  | 2007 | explicit FastHoleyObjectElementsAccessor(const char* name) | 
|  | 2008 | : FastSmiOrObjectElementsAccessor< | 
|  | 2009 | FastHoleyObjectElementsAccessor, | 
|  | 2010 | ElementsKindTraits<FAST_HOLEY_ELEMENTS> >(name) {} | 
|  | 2011 | }; | 
|  | 2012 |  | 
|  | 2013 |  | 
|  | 2014 | template<typename FastElementsAccessorSubclass, | 
|  | 2015 | typename KindTraits> | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 2016 | class FastDoubleElementsAccessor | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2017 | : public FastElementsAccessor<FastElementsAccessorSubclass, KindTraits> { | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 2018 | public: | 
|  | 2019 | explicit FastDoubleElementsAccessor(const char* name) | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2020 | : FastElementsAccessor<FastElementsAccessorSubclass, | 
|  | 2021 | KindTraits>(name) {} | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 2022 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 2023 | static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) { | 
|  | 2024 | return GetImpl(holder->elements(), entry); | 
|  | 2025 | } | 
|  | 2026 |  | 
|  | 2027 | static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) { | 
|  | 2028 | Isolate* isolate = backing_store->GetIsolate(); | 
|  | 2029 | return FixedDoubleArray::get(FixedDoubleArray::cast(backing_store), entry, | 
|  | 2030 | isolate); | 
|  | 2031 | } | 
|  | 2032 |  | 
|  | 2033 | static inline void SetImpl(Handle<JSObject> holder, uint32_t entry, | 
|  | 2034 | Object* value) { | 
|  | 2035 | SetImpl(holder->elements(), entry, value); | 
|  | 2036 | } | 
|  | 2037 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2038 | static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry, | 
|  | 2039 | Object* value) { | 
|  | 2040 | FixedDoubleArray::cast(backing_store)->set(entry, value->Number()); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 2041 | } | 
|  | 2042 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2043 | static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry, | 
|  | 2044 | Object* value, WriteBarrierMode mode) { | 
|  | 2045 | FixedDoubleArray::cast(backing_store)->set(entry, value->Number()); | 
|  | 2046 | } | 
|  | 2047 |  | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 2048 | static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start, | 
|  | 2049 | FixedArrayBase* to, ElementsKind from_kind, | 
|  | 2050 | uint32_t to_start, int packed_size, | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2051 | int copy_size) { | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 2052 | DisallowHeapAllocation no_allocation; | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2053 | switch (from_kind) { | 
|  | 2054 | case FAST_SMI_ELEMENTS: | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 2055 | CopyPackedSmiToDoubleElements(from, from_start, to, to_start, | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2056 | packed_size, copy_size); | 
|  | 2057 | break; | 
|  | 2058 | case FAST_HOLEY_SMI_ELEMENTS: | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 2059 | CopySmiToDoubleElements(from, from_start, to, to_start, copy_size); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2060 | break; | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 2061 | case FAST_DOUBLE_ELEMENTS: | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2062 | case FAST_HOLEY_DOUBLE_ELEMENTS: | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 2063 | CopyDoubleToDoubleElements(from, from_start, to, to_start, copy_size); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2064 | break; | 
|  | 2065 | case FAST_ELEMENTS: | 
|  | 2066 | case FAST_HOLEY_ELEMENTS: | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 2067 | CopyObjectToDoubleElements(from, from_start, to, to_start, copy_size); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2068 | break; | 
|  | 2069 | case DICTIONARY_ELEMENTS: | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 2070 | CopyDictionaryToDoubleElements(from, from_start, to, to_start, | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2071 | copy_size); | 
|  | 2072 | break; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2073 | case FAST_SLOPPY_ARGUMENTS_ELEMENTS: | 
|  | 2074 | case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 2075 | case FAST_STRING_WRAPPER_ELEMENTS: | 
|  | 2076 | case SLOW_STRING_WRAPPER_ELEMENTS: | 
|  | 2077 | case NO_ELEMENTS: | 
|  | 2078 | #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS: | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2079 | TYPED_ARRAYS(TYPED_ARRAY_CASE) | 
|  | 2080 | #undef TYPED_ARRAY_CASE | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 2081 | // This function is currently only used for JSArrays with non-zero | 
|  | 2082 | // length. | 
|  | 2083 | UNREACHABLE(); | 
|  | 2084 | break; | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 2085 | } | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 2086 | } | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2087 | }; | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 2088 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2089 |  | 
|  | 2090 | class FastPackedDoubleElementsAccessor | 
|  | 2091 | : public FastDoubleElementsAccessor< | 
|  | 2092 | FastPackedDoubleElementsAccessor, | 
|  | 2093 | ElementsKindTraits<FAST_DOUBLE_ELEMENTS> > { | 
|  | 2094 | public: | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2095 | explicit FastPackedDoubleElementsAccessor(const char* name) | 
|  | 2096 | : FastDoubleElementsAccessor< | 
|  | 2097 | FastPackedDoubleElementsAccessor, | 
|  | 2098 | ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >(name) {} | 
|  | 2099 | }; | 
|  | 2100 |  | 
|  | 2101 |  | 
|  | 2102 | class FastHoleyDoubleElementsAccessor | 
|  | 2103 | : public FastDoubleElementsAccessor< | 
|  | 2104 | FastHoleyDoubleElementsAccessor, | 
|  | 2105 | ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> > { | 
|  | 2106 | public: | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2107 | explicit FastHoleyDoubleElementsAccessor(const char* name) | 
|  | 2108 | : FastDoubleElementsAccessor< | 
|  | 2109 | FastHoleyDoubleElementsAccessor, | 
|  | 2110 | ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >(name) {} | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 2111 | }; | 
|  | 2112 |  | 
|  | 2113 |  | 
|  | 2114 | // Super class for all external element arrays. | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2115 | template<ElementsKind Kind> | 
|  | 2116 | class TypedElementsAccessor | 
|  | 2117 | : public ElementsAccessorBase<TypedElementsAccessor<Kind>, | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 2118 | ElementsKindTraits<Kind> > { | 
|  | 2119 | public: | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2120 | explicit TypedElementsAccessor(const char* name) | 
|  | 2121 | : ElementsAccessorBase<AccessorClass, | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 2122 | ElementsKindTraits<Kind> >(name) {} | 
| Ben Murdoch | 5d4cdbf | 2012-04-11 10:23:59 +0100 | [diff] [blame] | 2123 |  | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 2124 | typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore; | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2125 | typedef TypedElementsAccessor<Kind> AccessorClass; | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 2126 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 2127 | static inline void SetImpl(Handle<JSObject> holder, uint32_t entry, | 
|  | 2128 | Object* value) { | 
|  | 2129 | SetImpl(holder->elements(), entry, value); | 
|  | 2130 | } | 
|  | 2131 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2132 | static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry, | 
|  | 2133 | Object* value) { | 
|  | 2134 | BackingStore::cast(backing_store)->SetValue(entry, value); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 2135 | } | 
|  | 2136 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2137 | static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry, | 
|  | 2138 | Object* value, WriteBarrierMode mode) { | 
|  | 2139 | BackingStore::cast(backing_store)->SetValue(entry, value); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2140 | } | 
|  | 2141 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 2142 | static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) { | 
|  | 2143 | return GetImpl(holder->elements(), entry); | 
|  | 2144 | } | 
|  | 2145 |  | 
|  | 2146 | static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) { | 
|  | 2147 | return BackingStore::get(BackingStore::cast(backing_store), entry); | 
|  | 2148 | } | 
|  | 2149 |  | 
|  | 2150 | static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) { | 
|  | 2151 | return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2152 | } | 
|  | 2153 |  | 
|  | 2154 | static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store, | 
|  | 2155 | uint32_t entry) { | 
|  | 2156 | return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell); | 
|  | 2157 | } | 
|  | 2158 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 2159 | static bool HasElementImpl(Handle<JSObject> holder, uint32_t index, | 
|  | 2160 | Handle<FixedArrayBase> backing_store, | 
|  | 2161 | PropertyFilter filter) { | 
|  | 2162 | return index < AccessorClass::GetCapacityImpl(*holder, *backing_store); | 
|  | 2163 | } | 
|  | 2164 |  | 
|  | 2165 | static bool HasAccessorsImpl(JSObject* holder, | 
|  | 2166 | FixedArrayBase* backing_store) { | 
|  | 2167 | return false; | 
|  | 2168 | } | 
|  | 2169 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2170 | static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array, | 
|  | 2171 | uint32_t length, | 
|  | 2172 | Handle<FixedArrayBase> backing_store) { | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 2173 | // External arrays do not support changing their length. | 
|  | 2174 | UNREACHABLE(); | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 2175 | } | 
|  | 2176 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2177 | static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) { | 
|  | 2178 | UNREACHABLE(); | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 2179 | } | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 2180 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2181 | static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store, | 
|  | 2182 | uint32_t entry) { | 
|  | 2183 | return entry; | 
|  | 2184 | } | 
|  | 2185 |  | 
|  | 2186 | static uint32_t GetEntryForIndexImpl(JSObject* holder, | 
|  | 2187 | FixedArrayBase* backing_store, | 
|  | 2188 | uint32_t index, PropertyFilter filter) { | 
|  | 2189 | return index < AccessorClass::GetCapacityImpl(holder, backing_store) | 
|  | 2190 | ? index | 
|  | 2191 | : kMaxUInt32; | 
|  | 2192 | } | 
|  | 2193 |  | 
|  | 2194 | static uint32_t GetCapacityImpl(JSObject* holder, | 
|  | 2195 | FixedArrayBase* backing_store) { | 
|  | 2196 | JSArrayBufferView* view = JSArrayBufferView::cast(holder); | 
|  | 2197 | if (view->WasNeutered()) return 0; | 
|  | 2198 | return backing_store->length(); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 2199 | } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 2200 |  | 
|  | 2201 | static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver, | 
|  | 2202 | KeyAccumulator* accumulator, | 
|  | 2203 | AddKeyConversion convert) { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 2204 | Handle<FixedArrayBase> elements(receiver->elements()); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 2205 | uint32_t length = AccessorClass::GetCapacityImpl(*receiver, *elements); | 
|  | 2206 | for (uint32_t i = 0; i < length; i++) { | 
|  | 2207 | Handle<Object> value = AccessorClass::GetImpl(*elements, i); | 
|  | 2208 | accumulator->AddKey(value, convert); | 
|  | 2209 | } | 
|  | 2210 | } | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 2211 |  | 
|  | 2212 | static Maybe<bool> CollectValuesOrEntriesImpl( | 
|  | 2213 | Isolate* isolate, Handle<JSObject> object, | 
|  | 2214 | Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items, | 
|  | 2215 | PropertyFilter filter) { | 
|  | 2216 | int count = 0; | 
|  | 2217 | if ((filter & ONLY_CONFIGURABLE) == 0) { | 
|  | 2218 | Handle<FixedArrayBase> elements(object->elements()); | 
|  | 2219 | uint32_t length = AccessorClass::GetCapacityImpl(*object, *elements); | 
|  | 2220 | for (uint32_t index = 0; index < length; ++index) { | 
|  | 2221 | Handle<Object> value = AccessorClass::GetImpl(*elements, index); | 
|  | 2222 | if (get_entries) { | 
|  | 2223 | value = MakeEntryPair(isolate, index, value); | 
|  | 2224 | } | 
|  | 2225 | values_or_entries->set(count++, *value); | 
|  | 2226 | } | 
|  | 2227 | } | 
|  | 2228 | *nof_items = count; | 
|  | 2229 | return Just(true); | 
|  | 2230 | } | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 2231 | }; | 
|  | 2232 |  | 
|  | 2233 |  | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 2234 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2235 | #define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size)       \ | 
|  | 2236 | typedef TypedElementsAccessor<TYPE##_ELEMENTS >                    \ | 
|  | 2237 | Fixed##Type##ElementsAccessor; | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 2238 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2239 | TYPED_ARRAYS(FIXED_ELEMENTS_ACCESSOR) | 
|  | 2240 | #undef FIXED_ELEMENTS_ACCESSOR | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 2241 |  | 
|  | 2242 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2243 | template <typename SloppyArgumentsElementsAccessorSubclass, | 
|  | 2244 | typename ArgumentsAccessor, typename KindTraits> | 
|  | 2245 | class SloppyArgumentsElementsAccessor | 
|  | 2246 | : public ElementsAccessorBase<SloppyArgumentsElementsAccessorSubclass, | 
|  | 2247 | KindTraits> { | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 2248 | public: | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2249 | explicit SloppyArgumentsElementsAccessor(const char* name) | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2250 | : ElementsAccessorBase<SloppyArgumentsElementsAccessorSubclass, | 
|  | 2251 | KindTraits>(name) { | 
|  | 2252 | USE(KindTraits::Kind); | 
|  | 2253 | } | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 2254 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 2255 | static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) { | 
|  | 2256 | return GetImpl(holder->elements(), entry); | 
|  | 2257 | } | 
|  | 2258 |  | 
|  | 2259 | static Handle<Object> GetImpl(FixedArrayBase* parameters, uint32_t entry) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2260 | Isolate* isolate = parameters->GetIsolate(); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 2261 | Handle<FixedArray> parameter_map(FixedArray::cast(parameters), isolate); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2262 | uint32_t length = parameter_map->length() - 2; | 
|  | 2263 | if (entry < length) { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2264 | DisallowHeapAllocation no_gc; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2265 | Object* probe = parameter_map->get(entry + 2); | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 2266 | Context* context = Context::cast(parameter_map->get(0)); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2267 | int context_entry = Smi::cast(probe)->value(); | 
|  | 2268 | DCHECK(!context->get(context_entry)->IsTheHole()); | 
|  | 2269 | return handle(context->get(context_entry), isolate); | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 2270 | } else { | 
|  | 2271 | // Object is not mapped, defer to the arguments. | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 2272 | Handle<Object> result = ArgumentsAccessor::GetImpl( | 
|  | 2273 | FixedArray::cast(parameter_map->get(1)), entry - length); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 2274 | // Elements of the arguments object in slow mode might be slow aliases. | 
|  | 2275 | if (result->IsAliasedArgumentsEntry()) { | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2276 | DisallowHeapAllocation no_gc; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2277 | AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(*result); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 2278 | Context* context = Context::cast(parameter_map->get(0)); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2279 | int context_entry = alias->aliased_context_slot(); | 
|  | 2280 | DCHECK(!context->get(context_entry)->IsTheHole()); | 
|  | 2281 | return handle(context->get(context_entry), isolate); | 
|  | 2282 | } | 
|  | 2283 | return result; | 
|  | 2284 | } | 
|  | 2285 | } | 
|  | 2286 |  | 
|  | 2287 | static void GrowCapacityAndConvertImpl(Handle<JSObject> object, | 
|  | 2288 | uint32_t capacity) { | 
|  | 2289 | UNREACHABLE(); | 
|  | 2290 | } | 
|  | 2291 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 2292 | static inline void SetImpl(Handle<JSObject> holder, uint32_t entry, | 
|  | 2293 | Object* value) { | 
|  | 2294 | SetImpl(holder->elements(), entry, value); | 
|  | 2295 | } | 
|  | 2296 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2297 | static inline void SetImpl(FixedArrayBase* store, uint32_t entry, | 
|  | 2298 | Object* value) { | 
|  | 2299 | FixedArray* parameter_map = FixedArray::cast(store); | 
|  | 2300 | uint32_t length = parameter_map->length() - 2; | 
|  | 2301 | if (entry < length) { | 
|  | 2302 | Object* probe = parameter_map->get(entry + 2); | 
|  | 2303 | Context* context = Context::cast(parameter_map->get(0)); | 
|  | 2304 | int context_entry = Smi::cast(probe)->value(); | 
|  | 2305 | DCHECK(!context->get(context_entry)->IsTheHole()); | 
|  | 2306 | context->set(context_entry, value); | 
|  | 2307 | } else { | 
|  | 2308 | FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | 
|  | 2309 | Object* current = ArgumentsAccessor::GetRaw(arguments, entry - length); | 
|  | 2310 | if (current->IsAliasedArgumentsEntry()) { | 
|  | 2311 | AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(current); | 
|  | 2312 | Context* context = Context::cast(parameter_map->get(0)); | 
|  | 2313 | int context_entry = alias->aliased_context_slot(); | 
|  | 2314 | DCHECK(!context->get(context_entry)->IsTheHole()); | 
|  | 2315 | context->set(context_entry, value); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 2316 | } else { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2317 | ArgumentsAccessor::SetImpl(arguments, entry - length, value); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 2318 | } | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 2319 | } | 
|  | 2320 | } | 
|  | 2321 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2322 | static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array, | 
|  | 2323 | uint32_t length, | 
|  | 2324 | Handle<FixedArrayBase> parameter_map) { | 
|  | 2325 | // Sloppy arguments objects are not arrays. | 
|  | 2326 | UNREACHABLE(); | 
|  | 2327 | } | 
|  | 2328 |  | 
|  | 2329 | static uint32_t GetCapacityImpl(JSObject* holder, | 
|  | 2330 | FixedArrayBase* backing_store) { | 
|  | 2331 | FixedArray* parameter_map = FixedArray::cast(backing_store); | 
|  | 2332 | FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1)); | 
|  | 2333 | return parameter_map->length() - 2 + | 
|  | 2334 | ArgumentsAccessor::GetCapacityImpl(holder, arguments); | 
|  | 2335 | } | 
|  | 2336 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 2337 | static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver, | 
|  | 2338 | KeyAccumulator* accumulator, | 
|  | 2339 | AddKeyConversion convert) { | 
|  | 2340 | FixedArrayBase* elements = receiver->elements(); | 
|  | 2341 | uint32_t length = GetCapacityImpl(*receiver, elements); | 
|  | 2342 | for (uint32_t entry = 0; entry < length; entry++) { | 
|  | 2343 | if (!HasEntryImpl(elements, entry)) continue; | 
|  | 2344 | Handle<Object> value = GetImpl(elements, entry); | 
|  | 2345 | accumulator->AddKey(value, convert); | 
|  | 2346 | } | 
|  | 2347 | } | 
|  | 2348 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2349 | static bool HasEntryImpl(FixedArrayBase* parameters, uint32_t entry) { | 
|  | 2350 | FixedArray* parameter_map = FixedArray::cast(parameters); | 
|  | 2351 | uint32_t length = parameter_map->length() - 2; | 
|  | 2352 | if (entry < length) { | 
|  | 2353 | return !GetParameterMapArg(parameter_map, entry)->IsTheHole(); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2354 | } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2355 |  | 
|  | 2356 | FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1)); | 
|  | 2357 | return ArgumentsAccessor::HasEntryImpl(arguments, entry - length); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2358 | } | 
|  | 2359 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 2360 | static bool HasAccessorsImpl(JSObject* holder, | 
|  | 2361 | FixedArrayBase* backing_store) { | 
|  | 2362 | FixedArray* parameter_map = FixedArray::cast(backing_store); | 
|  | 2363 | FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1)); | 
|  | 2364 | return ArgumentsAccessor::HasAccessorsImpl(holder, arguments); | 
|  | 2365 | } | 
|  | 2366 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2367 | static uint32_t GetIndexForEntryImpl(FixedArrayBase* parameters, | 
|  | 2368 | uint32_t entry) { | 
|  | 2369 | FixedArray* parameter_map = FixedArray::cast(parameters); | 
|  | 2370 | uint32_t length = parameter_map->length() - 2; | 
|  | 2371 | if (entry < length) return entry; | 
|  | 2372 |  | 
|  | 2373 | FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | 
|  | 2374 | return ArgumentsAccessor::GetIndexForEntryImpl(arguments, entry - length); | 
|  | 2375 | } | 
|  | 2376 |  | 
|  | 2377 | static uint32_t GetEntryForIndexImpl(JSObject* holder, | 
|  | 2378 | FixedArrayBase* parameters, | 
|  | 2379 | uint32_t index, PropertyFilter filter) { | 
|  | 2380 | FixedArray* parameter_map = FixedArray::cast(parameters); | 
|  | 2381 | Object* probe = GetParameterMapArg(parameter_map, index); | 
|  | 2382 | if (!probe->IsTheHole()) return index; | 
|  | 2383 |  | 
|  | 2384 | FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | 
|  | 2385 | uint32_t entry = ArgumentsAccessor::GetEntryForIndexImpl(holder, arguments, | 
|  | 2386 | index, filter); | 
|  | 2387 | if (entry == kMaxUInt32) return entry; | 
|  | 2388 | return (parameter_map->length() - 2) + entry; | 
|  | 2389 | } | 
|  | 2390 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 2391 | static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) { | 
|  | 2392 | FixedArray* parameter_map = FixedArray::cast(holder->elements()); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2393 | uint32_t length = parameter_map->length() - 2; | 
|  | 2394 | if (entry < length) { | 
|  | 2395 | return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2396 | } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2397 | FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | 
|  | 2398 | return ArgumentsAccessor::GetDetailsImpl(arguments, entry - length); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2399 | } | 
|  | 2400 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2401 | static Object* GetParameterMapArg(FixedArray* parameter_map, uint32_t index) { | 
|  | 2402 | uint32_t length = parameter_map->length() - 2; | 
|  | 2403 | return index < length | 
|  | 2404 | ? parameter_map->get(index + 2) | 
|  | 2405 | : Object::cast(parameter_map->GetHeap()->the_hole_value()); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 2406 | } | 
|  | 2407 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2408 | static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) { | 
|  | 2409 | FixedArray* parameter_map = FixedArray::cast(obj->elements()); | 
|  | 2410 | uint32_t length = static_cast<uint32_t>(parameter_map->length()) - 2; | 
|  | 2411 | if (entry < length) { | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 2412 | // TODO(kmillikin): We could check if this was the last aliased | 
|  | 2413 | // parameter, and revert to normal elements in that case.  That | 
|  | 2414 | // would enable GC of the context. | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2415 | parameter_map->set_the_hole(entry + 2); | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 2416 | } else { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2417 | SloppyArgumentsElementsAccessorSubclass::DeleteFromArguments( | 
|  | 2418 | obj, entry - length); | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 2419 | } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2420 | } | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 2421 |  | 
|  | 2422 | static void CollectElementIndicesImpl(Handle<JSObject> object, | 
|  | 2423 | Handle<FixedArrayBase> backing_store, | 
|  | 2424 | KeyAccumulator* keys, uint32_t range, | 
|  | 2425 | PropertyFilter filter, | 
|  | 2426 | uint32_t offset) { | 
|  | 2427 | FixedArray* parameter_map = FixedArray::cast(*backing_store); | 
|  | 2428 | uint32_t length = parameter_map->length() - 2; | 
|  | 2429 | if (range < length) length = range; | 
|  | 2430 |  | 
|  | 2431 | for (uint32_t i = offset; i < length; ++i) { | 
|  | 2432 | if (!parameter_map->get(i + 2)->IsTheHole()) { | 
|  | 2433 | keys->AddKey(i); | 
|  | 2434 | } | 
|  | 2435 | } | 
|  | 2436 |  | 
|  | 2437 | Handle<FixedArrayBase> store(FixedArrayBase::cast(parameter_map->get(1))); | 
|  | 2438 | ArgumentsAccessor::CollectElementIndicesImpl(object, store, keys, range, | 
|  | 2439 | filter, offset); | 
|  | 2440 | if (SloppyArgumentsElementsAccessorSubclass::kind() == | 
|  | 2441 | FAST_SLOPPY_ARGUMENTS_ELEMENTS) { | 
|  | 2442 | keys->SortCurrentElementsList(); | 
|  | 2443 | } | 
|  | 2444 | } | 
|  | 2445 |  | 
|  | 2446 | static Handle<FixedArray> DirectCollectElementIndicesImpl( | 
|  | 2447 | Isolate* isolate, Handle<JSObject> object, | 
|  | 2448 | Handle<FixedArrayBase> backing_store, GetKeysConversion convert, | 
|  | 2449 | PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices, | 
|  | 2450 | uint32_t insertion_index = 0) { | 
|  | 2451 | FixedArray* parameter_map = FixedArray::cast(*backing_store); | 
|  | 2452 | uint32_t length = parameter_map->length() - 2; | 
|  | 2453 |  | 
|  | 2454 | for (uint32_t i = 0; i < length; ++i) { | 
|  | 2455 | if (parameter_map->get(i + 2)->IsTheHole()) continue; | 
|  | 2456 | if (convert == CONVERT_TO_STRING) { | 
|  | 2457 | Handle<String> index_string = isolate->factory()->Uint32ToString(i); | 
|  | 2458 | list->set(insertion_index, *index_string); | 
|  | 2459 | } else { | 
|  | 2460 | list->set(insertion_index, Smi::FromInt(i), SKIP_WRITE_BARRIER); | 
|  | 2461 | } | 
|  | 2462 | insertion_index++; | 
|  | 2463 | } | 
|  | 2464 |  | 
|  | 2465 | Handle<FixedArrayBase> store(FixedArrayBase::cast(parameter_map->get(1))); | 
|  | 2466 | return ArgumentsAccessor::DirectCollectElementIndicesImpl( | 
|  | 2467 | isolate, object, store, convert, filter, list, nof_indices, | 
|  | 2468 | insertion_index); | 
|  | 2469 | } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2470 | }; | 
|  | 2471 |  | 
|  | 2472 |  | 
|  | 2473 | class SlowSloppyArgumentsElementsAccessor | 
|  | 2474 | : public SloppyArgumentsElementsAccessor< | 
|  | 2475 | SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor, | 
|  | 2476 | ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> > { | 
|  | 2477 | public: | 
|  | 2478 | explicit SlowSloppyArgumentsElementsAccessor(const char* name) | 
|  | 2479 | : SloppyArgumentsElementsAccessor< | 
|  | 2480 | SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor, | 
|  | 2481 | ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {} | 
|  | 2482 |  | 
|  | 2483 | static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) { | 
|  | 2484 | Handle<FixedArray> parameter_map(FixedArray::cast(obj->elements())); | 
|  | 2485 | Handle<SeededNumberDictionary> dict( | 
|  | 2486 | SeededNumberDictionary::cast(parameter_map->get(1))); | 
|  | 2487 | // TODO(verwaest): Remove reliance on index in Shrink. | 
|  | 2488 | uint32_t index = GetIndexForEntryImpl(*dict, entry); | 
|  | 2489 | Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry); | 
|  | 2490 | USE(result); | 
|  | 2491 | DCHECK(result->IsTrue()); | 
|  | 2492 | Handle<FixedArray> new_elements = | 
|  | 2493 | SeededNumberDictionary::Shrink(dict, index); | 
|  | 2494 | parameter_map->set(1, *new_elements); | 
|  | 2495 | } | 
|  | 2496 |  | 
|  | 2497 | static void AddImpl(Handle<JSObject> object, uint32_t index, | 
|  | 2498 | Handle<Object> value, PropertyAttributes attributes, | 
|  | 2499 | uint32_t new_capacity) { | 
|  | 2500 | Handle<FixedArray> parameter_map(FixedArray::cast(object->elements())); | 
|  | 2501 | Handle<FixedArrayBase> old_elements( | 
|  | 2502 | FixedArrayBase::cast(parameter_map->get(1))); | 
|  | 2503 | Handle<SeededNumberDictionary> dictionary = | 
|  | 2504 | old_elements->IsSeededNumberDictionary() | 
|  | 2505 | ? Handle<SeededNumberDictionary>::cast(old_elements) | 
|  | 2506 | : JSObject::NormalizeElements(object); | 
|  | 2507 | PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell); | 
|  | 2508 | Handle<SeededNumberDictionary> new_dictionary = | 
|  | 2509 | SeededNumberDictionary::AddNumberEntry( | 
|  | 2510 | dictionary, index, value, details, | 
|  | 2511 | object->map()->is_prototype_map()); | 
|  | 2512 | if (attributes != NONE) object->RequireSlowElements(*new_dictionary); | 
|  | 2513 | if (*dictionary != *new_dictionary) { | 
|  | 2514 | FixedArray::cast(object->elements())->set(1, *new_dictionary); | 
|  | 2515 | } | 
|  | 2516 | } | 
|  | 2517 |  | 
|  | 2518 | static void ReconfigureImpl(Handle<JSObject> object, | 
|  | 2519 | Handle<FixedArrayBase> store, uint32_t entry, | 
|  | 2520 | Handle<Object> value, | 
|  | 2521 | PropertyAttributes attributes) { | 
|  | 2522 | Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(store); | 
|  | 2523 | uint32_t length = parameter_map->length() - 2; | 
|  | 2524 | if (entry < length) { | 
|  | 2525 | Object* probe = parameter_map->get(entry + 2); | 
|  | 2526 | DCHECK(!probe->IsTheHole()); | 
|  | 2527 | Context* context = Context::cast(parameter_map->get(0)); | 
|  | 2528 | int context_entry = Smi::cast(probe)->value(); | 
|  | 2529 | DCHECK(!context->get(context_entry)->IsTheHole()); | 
|  | 2530 | context->set(context_entry, *value); | 
|  | 2531 |  | 
|  | 2532 | // Redefining attributes of an aliased element destroys fast aliasing. | 
|  | 2533 | parameter_map->set_the_hole(entry + 2); | 
|  | 2534 | // For elements that are still writable we re-establish slow aliasing. | 
|  | 2535 | if ((attributes & READ_ONLY) == 0) { | 
|  | 2536 | Isolate* isolate = store->GetIsolate(); | 
|  | 2537 | value = isolate->factory()->NewAliasedArgumentsEntry(context_entry); | 
|  | 2538 | } | 
|  | 2539 |  | 
|  | 2540 | PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell); | 
|  | 2541 | Handle<SeededNumberDictionary> arguments( | 
|  | 2542 | SeededNumberDictionary::cast(parameter_map->get(1))); | 
|  | 2543 | arguments = SeededNumberDictionary::AddNumberEntry( | 
|  | 2544 | arguments, entry, value, details, object->map()->is_prototype_map()); | 
|  | 2545 | // If the attributes were NONE, we would have called set rather than | 
|  | 2546 | // reconfigure. | 
|  | 2547 | DCHECK_NE(NONE, attributes); | 
|  | 2548 | object->RequireSlowElements(*arguments); | 
|  | 2549 | parameter_map->set(1, *arguments); | 
|  | 2550 | } else { | 
|  | 2551 | Handle<FixedArrayBase> arguments( | 
|  | 2552 | FixedArrayBase::cast(parameter_map->get(1))); | 
|  | 2553 | DictionaryElementsAccessor::ReconfigureImpl( | 
|  | 2554 | object, arguments, entry - length, value, attributes); | 
|  | 2555 | } | 
|  | 2556 | } | 
|  | 2557 | }; | 
|  | 2558 |  | 
|  | 2559 |  | 
|  | 2560 | class FastSloppyArgumentsElementsAccessor | 
|  | 2561 | : public SloppyArgumentsElementsAccessor< | 
|  | 2562 | FastSloppyArgumentsElementsAccessor, FastHoleyObjectElementsAccessor, | 
|  | 2563 | ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> > { | 
|  | 2564 | public: | 
|  | 2565 | explicit FastSloppyArgumentsElementsAccessor(const char* name) | 
|  | 2566 | : SloppyArgumentsElementsAccessor< | 
|  | 2567 | FastSloppyArgumentsElementsAccessor, | 
|  | 2568 | FastHoleyObjectElementsAccessor, | 
|  | 2569 | ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {} | 
|  | 2570 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 2571 | static Handle<SeededNumberDictionary> NormalizeImpl( | 
|  | 2572 | Handle<JSObject> object, Handle<FixedArrayBase> elements) { | 
|  | 2573 | FixedArray* parameter_map = FixedArray::cast(*elements); | 
|  | 2574 | Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1))); | 
|  | 2575 | return FastHoleyObjectElementsAccessor::NormalizeImpl(object, arguments); | 
|  | 2576 | } | 
|  | 2577 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2578 | static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) { | 
|  | 2579 | FixedArray* parameter_map = FixedArray::cast(obj->elements()); | 
|  | 2580 | Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1))); | 
|  | 2581 | FastHoleyObjectElementsAccessor::DeleteCommon(obj, entry, arguments); | 
|  | 2582 | } | 
|  | 2583 |  | 
|  | 2584 | static void AddImpl(Handle<JSObject> object, uint32_t index, | 
|  | 2585 | Handle<Object> value, PropertyAttributes attributes, | 
|  | 2586 | uint32_t new_capacity) { | 
|  | 2587 | DCHECK_EQ(NONE, attributes); | 
|  | 2588 | Handle<FixedArray> parameter_map(FixedArray::cast(object->elements())); | 
|  | 2589 | Handle<FixedArrayBase> old_elements( | 
|  | 2590 | FixedArrayBase::cast(parameter_map->get(1))); | 
|  | 2591 | if (old_elements->IsSeededNumberDictionary() || | 
|  | 2592 | static_cast<uint32_t>(old_elements->length()) < new_capacity) { | 
|  | 2593 | GrowCapacityAndConvertImpl(object, new_capacity); | 
|  | 2594 | } | 
|  | 2595 | FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | 
|  | 2596 | // For fast holey objects, the entry equals the index. The code above made | 
|  | 2597 | // sure that there's enough space to store the value. We cannot convert | 
|  | 2598 | // index to entry explicitly since the slot still contains the hole, so the | 
|  | 2599 | // current EntryForIndex would indicate that it is "absent" by returning | 
|  | 2600 | // kMaxUInt32. | 
|  | 2601 | FastHoleyObjectElementsAccessor::SetImpl(arguments, index, *value); | 
|  | 2602 | } | 
|  | 2603 |  | 
|  | 2604 | static void ReconfigureImpl(Handle<JSObject> object, | 
|  | 2605 | Handle<FixedArrayBase> store, uint32_t entry, | 
|  | 2606 | Handle<Object> value, | 
|  | 2607 | PropertyAttributes attributes) { | 
|  | 2608 | Handle<SeededNumberDictionary> dictionary = | 
|  | 2609 | JSObject::NormalizeElements(object); | 
|  | 2610 | FixedArray::cast(*store)->set(1, *dictionary); | 
|  | 2611 | uint32_t length = static_cast<uint32_t>(store->length()) - 2; | 
|  | 2612 | if (entry >= length) { | 
|  | 2613 | entry = dictionary->FindEntry(entry - length) + length; | 
|  | 2614 | } | 
|  | 2615 | SlowSloppyArgumentsElementsAccessor::ReconfigureImpl(object, store, entry, | 
|  | 2616 | value, attributes); | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 2617 | } | 
|  | 2618 |  | 
| Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 2619 | static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start, | 
|  | 2620 | FixedArrayBase* to, ElementsKind from_kind, | 
|  | 2621 | uint32_t to_start, int packed_size, | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2622 | int copy_size) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2623 | DCHECK(!to->IsDictionary()); | 
|  | 2624 | if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) { | 
|  | 2625 | CopyDictionaryToObjectElements(from, from_start, to, FAST_HOLEY_ELEMENTS, | 
|  | 2626 | to_start, copy_size); | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 2627 | } else { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2628 | DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, from_kind); | 
|  | 2629 | CopyObjectToObjectElements(from, FAST_HOLEY_ELEMENTS, from_start, to, | 
|  | 2630 | FAST_HOLEY_ELEMENTS, to_start, copy_size); | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 2631 | } | 
|  | 2632 | } | 
|  | 2633 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2634 | static void GrowCapacityAndConvertImpl(Handle<JSObject> object, | 
|  | 2635 | uint32_t capacity) { | 
|  | 2636 | Handle<FixedArray> parameter_map(FixedArray::cast(object->elements())); | 
|  | 2637 | Handle<FixedArray> old_elements(FixedArray::cast(parameter_map->get(1))); | 
|  | 2638 | ElementsKind from_kind = object->GetElementsKind(); | 
|  | 2639 | // This method should only be called if there's a reason to update the | 
|  | 2640 | // elements. | 
|  | 2641 | DCHECK(from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS || | 
|  | 2642 | static_cast<uint32_t>(old_elements->length()) < capacity); | 
|  | 2643 | Handle<FixedArrayBase> elements = | 
|  | 2644 | ConvertElementsWithCapacity(object, old_elements, from_kind, capacity); | 
|  | 2645 | Handle<Map> new_map = JSObject::GetElementsTransitionMap( | 
|  | 2646 | object, FAST_SLOPPY_ARGUMENTS_ELEMENTS); | 
|  | 2647 | JSObject::MigrateToMap(object, new_map); | 
|  | 2648 | parameter_map->set(1, *elements); | 
|  | 2649 | JSObject::ValidateElements(object); | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 2650 | } | 
|  | 2651 | }; | 
|  | 2652 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 2653 | template <typename StringWrapperElementsAccessorSubclass, | 
|  | 2654 | typename BackingStoreAccessor, typename KindTraits> | 
|  | 2655 | class StringWrapperElementsAccessor | 
|  | 2656 | : public ElementsAccessorBase<StringWrapperElementsAccessorSubclass, | 
|  | 2657 | KindTraits> { | 
|  | 2658 | public: | 
|  | 2659 | explicit StringWrapperElementsAccessor(const char* name) | 
|  | 2660 | : ElementsAccessorBase<StringWrapperElementsAccessorSubclass, KindTraits>( | 
|  | 2661 | name) { | 
|  | 2662 | USE(KindTraits::Kind); | 
|  | 2663 | } | 
|  | 2664 |  | 
|  | 2665 | static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) { | 
|  | 2666 | Isolate* isolate = holder->GetIsolate(); | 
|  | 2667 | Handle<String> string(GetString(*holder), isolate); | 
|  | 2668 | uint32_t length = static_cast<uint32_t>(string->length()); | 
|  | 2669 | if (entry < length) { | 
|  | 2670 | return isolate->factory()->LookupSingleCharacterStringFromCode( | 
|  | 2671 | String::Flatten(string)->Get(entry)); | 
|  | 2672 | } | 
|  | 2673 | return BackingStoreAccessor::GetImpl(holder, entry - length); | 
|  | 2674 | } | 
|  | 2675 |  | 
|  | 2676 | static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) { | 
|  | 2677 | uint32_t length = static_cast<uint32_t>(GetString(holder)->length()); | 
|  | 2678 | if (entry < length) { | 
|  | 2679 | PropertyAttributes attributes = | 
|  | 2680 | static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE); | 
|  | 2681 | return PropertyDetails(attributes, v8::internal::DATA, 0, | 
|  | 2682 | PropertyCellType::kNoCell); | 
|  | 2683 | } | 
|  | 2684 | return BackingStoreAccessor::GetDetailsImpl(holder, entry - length); | 
|  | 2685 | } | 
|  | 2686 |  | 
|  | 2687 | static uint32_t GetEntryForIndexImpl(JSObject* holder, | 
|  | 2688 | FixedArrayBase* backing_store, | 
|  | 2689 | uint32_t index, PropertyFilter filter) { | 
|  | 2690 | uint32_t length = static_cast<uint32_t>(GetString(holder)->length()); | 
|  | 2691 | if (index < length) return index; | 
|  | 2692 | uint32_t backing_store_entry = BackingStoreAccessor::GetEntryForIndexImpl( | 
|  | 2693 | holder, backing_store, index, filter); | 
|  | 2694 | if (backing_store_entry == kMaxUInt32) return kMaxUInt32; | 
|  | 2695 | DCHECK(backing_store_entry < kMaxUInt32 - length); | 
|  | 2696 | return backing_store_entry + length; | 
|  | 2697 | } | 
|  | 2698 |  | 
|  | 2699 | static void DeleteImpl(Handle<JSObject> holder, uint32_t entry) { | 
|  | 2700 | uint32_t length = static_cast<uint32_t>(GetString(*holder)->length()); | 
|  | 2701 | if (entry < length) { | 
|  | 2702 | return;  // String contents can't be deleted. | 
|  | 2703 | } | 
|  | 2704 | BackingStoreAccessor::DeleteImpl(holder, entry - length); | 
|  | 2705 | } | 
|  | 2706 |  | 
|  | 2707 | static void SetImpl(Handle<JSObject> holder, uint32_t entry, Object* value) { | 
|  | 2708 | uint32_t length = static_cast<uint32_t>(GetString(*holder)->length()); | 
|  | 2709 | if (entry < length) { | 
|  | 2710 | return;  // String contents are read-only. | 
|  | 2711 | } | 
|  | 2712 | BackingStoreAccessor::SetImpl(holder->elements(), entry - length, value); | 
|  | 2713 | } | 
|  | 2714 |  | 
|  | 2715 | static void AddImpl(Handle<JSObject> object, uint32_t index, | 
|  | 2716 | Handle<Object> value, PropertyAttributes attributes, | 
|  | 2717 | uint32_t new_capacity) { | 
|  | 2718 | DCHECK(index >= static_cast<uint32_t>(GetString(*object)->length())); | 
|  | 2719 | // Explicitly grow fast backing stores if needed. Dictionaries know how to | 
|  | 2720 | // extend their capacity themselves. | 
|  | 2721 | if (KindTraits::Kind == FAST_STRING_WRAPPER_ELEMENTS && | 
|  | 2722 | (object->GetElementsKind() == SLOW_STRING_WRAPPER_ELEMENTS || | 
|  | 2723 | BackingStoreAccessor::GetCapacityImpl(*object, object->elements()) != | 
|  | 2724 | new_capacity)) { | 
|  | 2725 | StringWrapperElementsAccessorSubclass::GrowCapacityAndConvertImpl( | 
|  | 2726 | object, new_capacity); | 
|  | 2727 | } | 
|  | 2728 | BackingStoreAccessor::AddImpl(object, index, value, attributes, | 
|  | 2729 | new_capacity); | 
|  | 2730 | } | 
|  | 2731 |  | 
|  | 2732 | static void ReconfigureImpl(Handle<JSObject> object, | 
|  | 2733 | Handle<FixedArrayBase> store, uint32_t entry, | 
|  | 2734 | Handle<Object> value, | 
|  | 2735 | PropertyAttributes attributes) { | 
|  | 2736 | uint32_t length = static_cast<uint32_t>(GetString(*object)->length()); | 
|  | 2737 | if (entry < length) { | 
|  | 2738 | return;  // String contents can't be reconfigured. | 
|  | 2739 | } | 
|  | 2740 | BackingStoreAccessor::ReconfigureImpl(object, store, entry - length, value, | 
|  | 2741 | attributes); | 
|  | 2742 | } | 
|  | 2743 |  | 
|  | 2744 | static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver, | 
|  | 2745 | KeyAccumulator* accumulator, | 
|  | 2746 | AddKeyConversion convert) { | 
|  | 2747 | Isolate* isolate = receiver->GetIsolate(); | 
|  | 2748 | Handle<String> string(GetString(*receiver), isolate); | 
|  | 2749 | string = String::Flatten(string); | 
|  | 2750 | uint32_t length = static_cast<uint32_t>(string->length()); | 
|  | 2751 | for (uint32_t i = 0; i < length; i++) { | 
|  | 2752 | accumulator->AddKey( | 
|  | 2753 | isolate->factory()->LookupSingleCharacterStringFromCode( | 
|  | 2754 | string->Get(i)), | 
|  | 2755 | convert); | 
|  | 2756 | } | 
|  | 2757 | BackingStoreAccessor::AddElementsToKeyAccumulatorImpl(receiver, accumulator, | 
|  | 2758 | convert); | 
|  | 2759 | } | 
|  | 2760 |  | 
|  | 2761 | static void CollectElementIndicesImpl(Handle<JSObject> object, | 
|  | 2762 | Handle<FixedArrayBase> backing_store, | 
|  | 2763 | KeyAccumulator* keys, uint32_t range, | 
|  | 2764 | PropertyFilter filter, | 
|  | 2765 | uint32_t offset) { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 2766 | uint32_t length = GetString(*object)->length(); | 
|  | 2767 | for (uint32_t i = 0; i < length; i++) { | 
|  | 2768 | keys->AddKey(i); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 2769 | } | 
|  | 2770 | BackingStoreAccessor::CollectElementIndicesImpl(object, backing_store, keys, | 
|  | 2771 | range, filter, offset); | 
|  | 2772 | } | 
|  | 2773 |  | 
|  | 2774 | static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start, | 
|  | 2775 | FixedArrayBase* to, ElementsKind from_kind, | 
|  | 2776 | uint32_t to_start, int packed_size, | 
|  | 2777 | int copy_size) { | 
|  | 2778 | BackingStoreAccessor::CopyElementsImpl(from, from_start, to, from_kind, | 
|  | 2779 | to_start, packed_size, copy_size); | 
|  | 2780 | } | 
|  | 2781 |  | 
|  | 2782 | private: | 
|  | 2783 | static String* GetString(JSObject* holder) { | 
|  | 2784 | DCHECK(holder->IsJSValue()); | 
|  | 2785 | JSValue* js_value = JSValue::cast(holder); | 
|  | 2786 | DCHECK(js_value->value()->IsString()); | 
|  | 2787 | return String::cast(js_value->value()); | 
|  | 2788 | } | 
|  | 2789 | }; | 
|  | 2790 |  | 
|  | 2791 | class FastStringWrapperElementsAccessor | 
|  | 2792 | : public StringWrapperElementsAccessor< | 
|  | 2793 | FastStringWrapperElementsAccessor, FastHoleyObjectElementsAccessor, | 
|  | 2794 | ElementsKindTraits<FAST_STRING_WRAPPER_ELEMENTS>> { | 
|  | 2795 | public: | 
|  | 2796 | explicit FastStringWrapperElementsAccessor(const char* name) | 
|  | 2797 | : StringWrapperElementsAccessor< | 
|  | 2798 | FastStringWrapperElementsAccessor, FastHoleyObjectElementsAccessor, | 
|  | 2799 | ElementsKindTraits<FAST_STRING_WRAPPER_ELEMENTS>>(name) {} | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 2800 |  | 
|  | 2801 | static Handle<SeededNumberDictionary> NormalizeImpl( | 
|  | 2802 | Handle<JSObject> object, Handle<FixedArrayBase> elements) { | 
|  | 2803 | return FastHoleyObjectElementsAccessor::NormalizeImpl(object, elements); | 
|  | 2804 | } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 2805 | }; | 
|  | 2806 |  | 
|  | 2807 | class SlowStringWrapperElementsAccessor | 
|  | 2808 | : public StringWrapperElementsAccessor< | 
|  | 2809 | SlowStringWrapperElementsAccessor, DictionaryElementsAccessor, | 
|  | 2810 | ElementsKindTraits<SLOW_STRING_WRAPPER_ELEMENTS>> { | 
|  | 2811 | public: | 
|  | 2812 | explicit SlowStringWrapperElementsAccessor(const char* name) | 
|  | 2813 | : StringWrapperElementsAccessor< | 
|  | 2814 | SlowStringWrapperElementsAccessor, DictionaryElementsAccessor, | 
|  | 2815 | ElementsKindTraits<SLOW_STRING_WRAPPER_ELEMENTS>>(name) {} | 
|  | 2816 |  | 
|  | 2817 | static bool HasAccessorsImpl(JSObject* holder, | 
|  | 2818 | FixedArrayBase* backing_store) { | 
|  | 2819 | return DictionaryElementsAccessor::HasAccessorsImpl(holder, backing_store); | 
|  | 2820 | } | 
|  | 2821 | }; | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 2822 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2823 | }  // namespace | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 2824 |  | 
|  | 2825 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2826 | void CheckArrayAbuse(Handle<JSObject> obj, const char* op, uint32_t index, | 
|  | 2827 | bool allow_appending) { | 
|  | 2828 | DisallowHeapAllocation no_allocation; | 
|  | 2829 | Object* raw_length = NULL; | 
|  | 2830 | const char* elements_type = "array"; | 
|  | 2831 | if (obj->IsJSArray()) { | 
|  | 2832 | JSArray* array = JSArray::cast(*obj); | 
|  | 2833 | raw_length = array->length(); | 
|  | 2834 | } else { | 
|  | 2835 | raw_length = Smi::FromInt(obj->elements()->length()); | 
|  | 2836 | elements_type = "object"; | 
|  | 2837 | } | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 2838 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2839 | if (raw_length->IsNumber()) { | 
|  | 2840 | double n = raw_length->Number(); | 
|  | 2841 | if (FastI2D(FastD2UI(n)) == n) { | 
|  | 2842 | int32_t int32_length = DoubleToInt32(n); | 
|  | 2843 | uint32_t compare_length = static_cast<uint32_t>(int32_length); | 
|  | 2844 | if (allow_appending) compare_length++; | 
|  | 2845 | if (index >= compare_length) { | 
|  | 2846 | PrintF("[OOB %s %s (%s length = %d, element accessed = %d) in ", | 
|  | 2847 | elements_type, op, elements_type, static_cast<int>(int32_length), | 
|  | 2848 | static_cast<int>(index)); | 
|  | 2849 | TraceTopFrame(obj->GetIsolate()); | 
|  | 2850 | PrintF("]\n"); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 2851 | } | 
|  | 2852 | } else { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2853 | PrintF("[%s elements length not integer value in ", elements_type); | 
|  | 2854 | TraceTopFrame(obj->GetIsolate()); | 
|  | 2855 | PrintF("]\n"); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 2856 | } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2857 | } else { | 
|  | 2858 | PrintF("[%s elements length not a number in ", elements_type); | 
|  | 2859 | TraceTopFrame(obj->GetIsolate()); | 
|  | 2860 | PrintF("]\n"); | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 2861 | } | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 2862 | } | 
|  | 2863 |  | 
|  | 2864 |  | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2865 | MaybeHandle<Object> ArrayConstructInitializeElements(Handle<JSArray> array, | 
|  | 2866 | Arguments* args) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2867 | if (args->length() == 0) { | 
|  | 2868 | // Optimize the case where there are no parameters passed. | 
|  | 2869 | JSArray::Initialize(array, JSArray::kPreallocatedArrayElements); | 
|  | 2870 | return array; | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2871 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2872 | } else if (args->length() == 1 && args->at<Object>(0)->IsNumber()) { | 
|  | 2873 | uint32_t length; | 
|  | 2874 | if (!args->at<Object>(0)->ToArrayLength(&length)) { | 
|  | 2875 | return ThrowArrayLengthRangeError(array->GetIsolate()); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2876 | } | 
|  | 2877 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2878 | // Optimize the case where there is one argument and the argument is a small | 
|  | 2879 | // smi. | 
|  | 2880 | if (length > 0 && length < JSArray::kInitialMaxFastElementArray) { | 
|  | 2881 | ElementsKind elements_kind = array->GetElementsKind(); | 
|  | 2882 | JSArray::Initialize(array, length, length); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2883 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2884 | if (!IsFastHoleyElementsKind(elements_kind)) { | 
|  | 2885 | elements_kind = GetHoleyElementsKind(elements_kind); | 
|  | 2886 | JSObject::TransitionElementsKind(array, elements_kind); | 
|  | 2887 | } | 
|  | 2888 | } else if (length == 0) { | 
|  | 2889 | JSArray::Initialize(array, JSArray::kPreallocatedArrayElements); | 
|  | 2890 | } else { | 
|  | 2891 | // Take the argument as the length. | 
|  | 2892 | JSArray::Initialize(array, 0); | 
|  | 2893 | JSArray::SetLength(array, length); | 
|  | 2894 | } | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2895 | return array; | 
|  | 2896 | } | 
|  | 2897 |  | 
|  | 2898 | Factory* factory = array->GetIsolate()->factory(); | 
|  | 2899 |  | 
|  | 2900 | // Set length and elements on the array. | 
|  | 2901 | int number_of_elements = args->length(); | 
|  | 2902 | JSObject::EnsureCanContainElements( | 
|  | 2903 | array, args, 0, number_of_elements, ALLOW_CONVERTED_DOUBLE_ELEMENTS); | 
|  | 2904 |  | 
|  | 2905 | // Allocate an appropriately typed elements array. | 
|  | 2906 | ElementsKind elements_kind = array->GetElementsKind(); | 
|  | 2907 | Handle<FixedArrayBase> elms; | 
|  | 2908 | if (IsFastDoubleElementsKind(elements_kind)) { | 
|  | 2909 | elms = Handle<FixedArrayBase>::cast( | 
|  | 2910 | factory->NewFixedDoubleArray(number_of_elements)); | 
|  | 2911 | } else { | 
|  | 2912 | elms = Handle<FixedArrayBase>::cast( | 
|  | 2913 | factory->NewFixedArrayWithHoles(number_of_elements)); | 
|  | 2914 | } | 
|  | 2915 |  | 
|  | 2916 | // Fill in the content | 
|  | 2917 | switch (array->GetElementsKind()) { | 
|  | 2918 | case FAST_HOLEY_SMI_ELEMENTS: | 
|  | 2919 | case FAST_SMI_ELEMENTS: { | 
|  | 2920 | Handle<FixedArray> smi_elms = Handle<FixedArray>::cast(elms); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2921 | for (int entry = 0; entry < number_of_elements; entry++) { | 
|  | 2922 | smi_elms->set(entry, (*args)[entry], SKIP_WRITE_BARRIER); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2923 | } | 
|  | 2924 | break; | 
|  | 2925 | } | 
|  | 2926 | case FAST_HOLEY_ELEMENTS: | 
|  | 2927 | case FAST_ELEMENTS: { | 
|  | 2928 | DisallowHeapAllocation no_gc; | 
|  | 2929 | WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); | 
|  | 2930 | Handle<FixedArray> object_elms = Handle<FixedArray>::cast(elms); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2931 | for (int entry = 0; entry < number_of_elements; entry++) { | 
|  | 2932 | object_elms->set(entry, (*args)[entry], mode); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2933 | } | 
|  | 2934 | break; | 
|  | 2935 | } | 
|  | 2936 | case FAST_HOLEY_DOUBLE_ELEMENTS: | 
|  | 2937 | case FAST_DOUBLE_ELEMENTS: { | 
|  | 2938 | Handle<FixedDoubleArray> double_elms = | 
|  | 2939 | Handle<FixedDoubleArray>::cast(elms); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2940 | for (int entry = 0; entry < number_of_elements; entry++) { | 
|  | 2941 | double_elms->set(entry, (*args)[entry]->Number()); | 
| Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2942 | } | 
|  | 2943 | break; | 
|  | 2944 | } | 
|  | 2945 | default: | 
|  | 2946 | UNREACHABLE(); | 
|  | 2947 | break; | 
|  | 2948 | } | 
|  | 2949 |  | 
|  | 2950 | array->set_elements(*elms); | 
|  | 2951 | array->set_length(Smi::FromInt(number_of_elements)); | 
|  | 2952 | return array; | 
|  | 2953 | } | 
|  | 2954 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2955 |  | 
|  | 2956 | void ElementsAccessor::InitializeOncePerProcess() { | 
|  | 2957 | static ElementsAccessor* accessor_array[] = { | 
|  | 2958 | #define ACCESSOR_ARRAY(Class, Kind, Store) new Class(#Kind), | 
|  | 2959 | ELEMENTS_LIST(ACCESSOR_ARRAY) | 
|  | 2960 | #undef ACCESSOR_ARRAY | 
|  | 2961 | }; | 
|  | 2962 |  | 
|  | 2963 | STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) == | 
|  | 2964 | kElementsKindCount); | 
|  | 2965 |  | 
|  | 2966 | elements_accessors_ = accessor_array; | 
|  | 2967 | } | 
|  | 2968 |  | 
|  | 2969 |  | 
|  | 2970 | void ElementsAccessor::TearDown() { | 
|  | 2971 | if (elements_accessors_ == NULL) return; | 
|  | 2972 | #define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind]; | 
|  | 2973 | ELEMENTS_LIST(ACCESSOR_DELETE) | 
|  | 2974 | #undef ACCESSOR_DELETE | 
|  | 2975 | elements_accessors_ = NULL; | 
|  | 2976 | } | 
|  | 2977 |  | 
|  | 2978 |  | 
|  | 2979 | Handle<JSArray> ElementsAccessor::Concat(Isolate* isolate, Arguments* args, | 
|  | 2980 | uint32_t concat_size) { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 2981 | const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); | 
|  | 2982 | STATIC_ASSERT(FixedDoubleArray::kMaxLength < kHalfOfMaxInt); | 
|  | 2983 | USE(kHalfOfMaxInt); | 
|  | 2984 | uint32_t result_len = 0; | 
|  | 2985 | bool has_raw_doubles = false; | 
|  | 2986 | ElementsKind result_elements_kind = GetInitialFastElementsKind(); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2987 | { | 
|  | 2988 | DisallowHeapAllocation no_gc; | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 2989 | bool is_holey = false; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2990 | // Iterate through all the arguments performing checks | 
|  | 2991 | // and calculating total length. | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2992 | for (uint32_t i = 0; i < concat_size; i++) { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 2993 | JSArray* array = JSArray::cast((*args)[i]); | 
|  | 2994 | uint32_t len = 0; | 
|  | 2995 | array->length()->ToArrayLength(&len); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2996 |  | 
|  | 2997 | // We shouldn't overflow when adding another len. | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 2998 | result_len += len; | 
|  | 2999 | DCHECK(0 <= result_len); | 
|  | 3000 | DCHECK(result_len <= FixedDoubleArray::kMaxLength); | 
|  | 3001 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 3002 | ElementsKind arg_kind = array->GetElementsKind(); | 
|  | 3003 | has_raw_doubles = has_raw_doubles || IsFastDoubleElementsKind(arg_kind); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 3004 | is_holey = is_holey || IsFastHoleyElementsKind(arg_kind); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 3005 | result_elements_kind = | 
|  | 3006 | GetMoreGeneralElementsKind(result_elements_kind, arg_kind); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 3007 | } | 
|  | 3008 | if (is_holey) { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 3009 | result_elements_kind = GetHoleyElementsKind(result_elements_kind); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 3010 | } | 
|  | 3011 | } | 
|  | 3012 |  | 
|  | 3013 | // If a double array is concatted into a fast elements array, the fast | 
|  | 3014 | // elements array needs to be initialized to contain proper holes, since | 
|  | 3015 | // boxing doubles may cause incremental marking. | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 3016 | bool requires_double_boxing = | 
|  | 3017 | has_raw_doubles && !IsFastDoubleElementsKind(result_elements_kind); | 
|  | 3018 | ArrayStorageAllocationMode mode = requires_double_boxing | 
|  | 3019 | ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE | 
|  | 3020 | : DONT_INITIALIZE_ARRAY_ELEMENTS; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 3021 | Handle<JSArray> result_array = isolate->factory()->NewJSArray( | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 3022 | result_elements_kind, result_len, result_len, mode); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 3023 | if (result_len == 0) return result_array; | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 3024 |  | 
|  | 3025 | uint32_t insertion_index = 0; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 3026 | Handle<FixedArrayBase> storage(result_array->elements(), isolate); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 3027 | ElementsAccessor* accessor = ElementsAccessor::ForKind(result_elements_kind); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 3028 | for (uint32_t i = 0; i < concat_size; i++) { | 
|  | 3029 | // It is crucial to keep |array| in a raw pointer form to avoid | 
|  | 3030 | // performance degradation. | 
|  | 3031 | JSArray* array = JSArray::cast((*args)[i]); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 3032 | uint32_t len = 0; | 
|  | 3033 | array->length()->ToArrayLength(&len); | 
|  | 3034 | if (len == 0) continue; | 
|  | 3035 | ElementsKind from_kind = array->GetElementsKind(); | 
|  | 3036 | accessor->CopyElements(array, 0, from_kind, storage, insertion_index, len); | 
|  | 3037 | insertion_index += len; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 3038 | } | 
|  | 3039 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 3040 | DCHECK_EQ(insertion_index, result_len); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 3041 | return result_array; | 
|  | 3042 | } | 
|  | 3043 |  | 
|  | 3044 | ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL; | 
|  | 3045 | }  // namespace internal | 
|  | 3046 | }  // namespace v8 |