OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/elements.h" | 5 #include "src/elements.h" |
6 | 6 |
7 #include "src/arguments.h" | 7 #include "src/arguments.h" |
8 #include "src/conversions.h" | 8 #include "src/conversions.h" |
9 #include "src/factory.h" | 9 #include "src/factory.h" |
10 #include "src/messages.h" | 10 #include "src/messages.h" |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
108 return false; | 108 return false; |
109 } | 109 } |
110 | 110 |
111 | 111 |
112 MUST_USE_RESULT | 112 MUST_USE_RESULT |
113 static MaybeHandle<Object> ThrowArrayLengthRangeError(Isolate* isolate) { | 113 static MaybeHandle<Object> ThrowArrayLengthRangeError(Isolate* isolate) { |
114 THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidArrayLength), | 114 THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidArrayLength), |
115 Object); | 115 Object); |
116 } | 116 } |
117 | 117 |
118 | |
119 static void CopyObjectToObjectElements(FixedArrayBase* from_base, | 118 static void CopyObjectToObjectElements(FixedArrayBase* from_base, |
120 ElementsKind from_kind, | 119 ElementsKind from_kind, |
121 uint32_t from_start, | 120 uint32_t from_start, |
122 FixedArrayBase* to_base, | 121 FixedArrayBase* to_base, |
123 ElementsKind to_kind, uint32_t to_start, | 122 ElementsKind to_kind, uint32_t to_start, |
124 int raw_copy_size) { | 123 int raw_copy_size) { |
125 DCHECK(to_base->map() != | 124 DCHECK(to_base->map() != |
126 from_base->GetIsolate()->heap()->fixed_cow_array_map()); | 125 from_base->GetIsolate()->heap()->fixed_cow_array_map()); |
127 DisallowHeapAllocation no_allocation; | 126 DisallowHeapAllocation no_allocation; |
128 int copy_size = raw_copy_size; | 127 int copy_size = raw_copy_size; |
(...skipping 450 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
579 push_size, direction); | 578 push_size, direction); |
580 } | 579 } |
581 | 580 |
582 static uint32_t PushImpl(Handle<JSArray> receiver, | 581 static uint32_t PushImpl(Handle<JSArray> receiver, |
583 Handle<FixedArrayBase> elms_obj, Object** objects, | 582 Handle<FixedArrayBase> elms_obj, Object** objects, |
584 uint32_t push_size, int direction) { | 583 uint32_t push_size, int direction) { |
585 UNREACHABLE(); | 584 UNREACHABLE(); |
586 return 0; | 585 return 0; |
587 } | 586 } |
588 | 587 |
| 588 virtual Handle<JSArray> Splice(Handle<JSArray> receiver, |
| 589 Handle<FixedArrayBase> backing_store, |
| 590 uint32_t start, uint32_t delete_count, |
| 591 Arguments args, uint32_t add_count) { |
| 592 return ElementsAccessorSubclass::SpliceImpl(receiver, backing_store, start, |
| 593 delete_count, args, add_count); |
| 594 } |
| 595 |
| 596 static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver, |
| 597 Handle<FixedArrayBase> backing_store, |
| 598 uint32_t start, uint32_t delete_count, |
| 599 Arguments args, uint32_t add_count) { |
| 600 UNREACHABLE(); |
| 601 return Handle<JSArray>(); |
| 602 } |
| 603 |
| 604 |
589 virtual void SetLength(Handle<JSArray> array, uint32_t length) final { | 605 virtual void SetLength(Handle<JSArray> array, uint32_t length) final { |
590 ElementsAccessorSubclass::SetLengthImpl(array, length, | 606 ElementsAccessorSubclass::SetLengthImpl(array, length, |
591 handle(array->elements())); | 607 handle(array->elements())); |
592 } | 608 } |
593 | 609 |
594 static void SetLengthImpl(Handle<JSArray> array, uint32_t length, | 610 static void SetLengthImpl(Handle<JSArray> array, uint32_t length, |
595 Handle<FixedArrayBase> backing_store); | 611 Handle<FixedArrayBase> backing_store); |
596 | 612 |
597 static Handle<FixedArrayBase> ConvertElementsWithCapacity( | 613 static Handle<FixedArrayBase> ConvertElementsWithCapacity( |
598 Handle<JSObject> object, Handle<FixedArrayBase> old_elements, | 614 Handle<JSObject> object, Handle<FixedArrayBase> old_elements, |
599 ElementsKind from_kind, uint32_t capacity) { | 615 ElementsKind from_kind, uint32_t capacity) { |
| 616 return ConvertElementsWithCapacity( |
| 617 object, old_elements, from_kind, capacity, |
| 618 ElementsAccessor::kCopyToEndAndInitializeToHole); |
| 619 } |
| 620 |
| 621 static Handle<FixedArrayBase> ConvertElementsWithCapacity( |
| 622 Handle<JSObject> object, Handle<FixedArrayBase> old_elements, |
| 623 ElementsKind from_kind, uint32_t capacity, int copy_size) { |
600 Isolate* isolate = object->GetIsolate(); | 624 Isolate* isolate = object->GetIsolate(); |
601 Handle<FixedArrayBase> elements; | 625 Handle<FixedArrayBase> new_elements; |
602 if (IsFastDoubleElementsKind(kind())) { | 626 if (IsFastDoubleElementsKind(kind())) { |
603 elements = isolate->factory()->NewFixedDoubleArray(capacity); | 627 new_elements = isolate->factory()->NewFixedDoubleArray(capacity); |
604 } else { | 628 } else { |
605 elements = isolate->factory()->NewUninitializedFixedArray(capacity); | 629 new_elements = isolate->factory()->NewUninitializedFixedArray(capacity); |
606 } | 630 } |
607 | 631 |
608 int packed = kPackedSizeNotKnown; | 632 int packed_size = kPackedSizeNotKnown; |
609 if (IsFastPackedElementsKind(from_kind) && object->IsJSArray()) { | 633 if (IsFastPackedElementsKind(from_kind) && object->IsJSArray()) { |
610 packed = Smi::cast(JSArray::cast(*object)->length())->value(); | 634 packed_size = Smi::cast(JSArray::cast(*object)->length())->value(); |
611 } | 635 } |
612 | 636 |
613 ElementsAccessorSubclass::CopyElementsImpl( | 637 ElementsAccessorSubclass::CopyElementsImpl( |
614 *old_elements, 0, *elements, from_kind, 0, packed, | 638 *old_elements, 0, *new_elements, from_kind, 0, packed_size, copy_size); |
615 ElementsAccessor::kCopyToEndAndInitializeToHole); | 639 |
616 return elements; | 640 return new_elements; |
617 } | 641 } |
618 | 642 |
619 static void GrowCapacityAndConvertImpl(Handle<JSObject> object, | 643 static void GrowCapacityAndConvertImpl(Handle<JSObject> object, |
620 uint32_t capacity) { | 644 uint32_t capacity) { |
621 ElementsKind from_kind = object->GetElementsKind(); | 645 ElementsKind from_kind = object->GetElementsKind(); |
622 if (IsFastSmiOrObjectElementsKind(from_kind)) { | 646 if (IsFastSmiOrObjectElementsKind(from_kind)) { |
623 // Array optimizations rely on the prototype lookups of Array objects | 647 // Array optimizations rely on the prototype lookups of Array objects |
624 // always returning undefined. If there is a store to the initial | 648 // always returning undefined. If there is a store to the initial |
625 // prototype object, make sure all of these optimizations are invalidated. | 649 // prototype object, make sure all of these optimizations are invalidated. |
626 object->GetIsolate()->UpdateArrayProtectorOnSetLength(object); | 650 object->GetIsolate()->UpdateArrayProtectorOnSetLength(object); |
(...skipping 545 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1172 uint32_t new_length = len + push_size; | 1196 uint32_t new_length = len + push_size; |
1173 Handle<FixedArrayBase> new_elms; | 1197 Handle<FixedArrayBase> new_elms; |
1174 | 1198 |
1175 if (new_length > elms_len) { | 1199 if (new_length > elms_len) { |
1176 // New backing storage is needed. | 1200 // New backing storage is needed. |
1177 uint32_t capacity = new_length + (new_length >> 1) + 16; | 1201 uint32_t capacity = new_length + (new_length >> 1) + 16; |
1178 new_elms = FastElementsAccessorSubclass::ConvertElementsWithCapacity( | 1202 new_elms = FastElementsAccessorSubclass::ConvertElementsWithCapacity( |
1179 receiver, backing_store, KindTraits::Kind, capacity); | 1203 receiver, backing_store, KindTraits::Kind, capacity); |
1180 } else { | 1204 } else { |
1181 // push_size is > 0 and new_length <= elms_len, so backing_store cannot be | 1205 // push_size is > 0 and new_length <= elms_len, so backing_store cannot be |
1182 // the | 1206 // the empty_fixed_array. |
1183 // empty_fixed_array. | |
1184 new_elms = backing_store; | 1207 new_elms = backing_store; |
1185 } | 1208 } |
1186 | 1209 |
1187 // Add the provided values. | 1210 // Add the provided values. |
1188 DisallowHeapAllocation no_gc; | 1211 DisallowHeapAllocation no_gc; |
1189 DCHECK(direction == ElementsAccessor::kDirectionForward || | 1212 DCHECK(direction == ElementsAccessor::kDirectionForward || |
1190 direction == ElementsAccessor::kDirectionReverse); | 1213 direction == ElementsAccessor::kDirectionReverse); |
1191 STATIC_ASSERT(ElementsAccessor::kDirectionForward == 1); | 1214 STATIC_ASSERT(ElementsAccessor::kDirectionForward == 1); |
1192 STATIC_ASSERT(ElementsAccessor::kDirectionReverse == -1); | 1215 STATIC_ASSERT(ElementsAccessor::kDirectionReverse == -1); |
1193 for (uint32_t index = 0; index < push_size; index++) { | 1216 for (uint32_t index = 0; index < push_size; index++) { |
1194 int offset = direction * index; | 1217 int offset = direction * index; |
1195 Object* object = objects[offset]; | 1218 Object* object = objects[offset]; |
1196 FastElementsAccessorSubclass::SetImpl(*new_elms, index + len, object); | 1219 FastElementsAccessorSubclass::SetImpl(*new_elms, index + len, object); |
1197 } | 1220 } |
1198 if (!new_elms.is_identical_to(backing_store)) { | 1221 if (!new_elms.is_identical_to(backing_store)) { |
1199 receiver->set_elements(*new_elms); | 1222 receiver->set_elements(*new_elms); |
1200 } | 1223 } |
1201 DCHECK(*new_elms == receiver->elements()); | 1224 DCHECK(*new_elms == receiver->elements()); |
1202 // Set the length. | 1225 // Set the length. |
1203 receiver->set_length(Smi::FromInt(new_length)); | 1226 receiver->set_length(Smi::FromInt(new_length)); |
1204 return new_length; | 1227 return new_length; |
1205 } | 1228 } |
| 1229 |
| 1230 static void MoveElements(Heap* heap, Handle<FixedArrayBase> backing_store, |
| 1231 int dst_index, int src_index, int len, |
| 1232 int hole_start, int hole_end) { |
| 1233 UNREACHABLE(); |
| 1234 } |
| 1235 |
| 1236 static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver, |
| 1237 Handle<FixedArrayBase> backing_store, |
| 1238 uint32_t start, uint32_t delete_count, |
| 1239 Arguments args, uint32_t add_count) { |
| 1240 Isolate* isolate = receiver->GetIsolate(); |
| 1241 Heap* heap = isolate->heap(); |
| 1242 const uint32_t len = Smi::cast(receiver->length())->value(); |
| 1243 const uint32_t new_length = len - delete_count + add_count; |
| 1244 |
| 1245 if (new_length == 0) { |
| 1246 receiver->set_elements(heap->empty_fixed_array()); |
| 1247 receiver->set_length(Smi::FromInt(0)); |
| 1248 return isolate->factory()->NewJSArrayWithElements( |
| 1249 backing_store, KindTraits::Kind, delete_count); |
| 1250 } |
| 1251 |
| 1252 // construct the result array which holds the deleted elements |
| 1253 Handle<JSArray> deleted_elements = isolate->factory()->NewJSArray( |
| 1254 KindTraits::Kind, delete_count, delete_count); |
| 1255 if (delete_count > 0) { |
| 1256 DisallowHeapAllocation no_gc; |
| 1257 FastElementsAccessorSubclass::CopyElementsImpl( |
| 1258 *backing_store, start, deleted_elements->elements(), KindTraits::Kind, |
| 1259 0, kPackedSizeNotKnown, delete_count); |
| 1260 } |
| 1261 |
| 1262 // delete and move elements to make space for add_count new elements |
| 1263 bool elms_changed = false; |
| 1264 if (add_count < delete_count) { |
| 1265 elms_changed = SpliceShrinkStep(backing_store, heap, start, delete_count, |
| 1266 add_count, len, new_length); |
| 1267 } else if (add_count > delete_count) { |
| 1268 elms_changed = |
| 1269 SpliceGrowStep(receiver, backing_store, isolate, heap, start, |
| 1270 delete_count, add_count, len, new_length); |
| 1271 } |
| 1272 |
| 1273 // Copy new Elements from args |
| 1274 DisallowHeapAllocation no_gc; |
| 1275 for (uint32_t index = start; index < start + add_count; index++) { |
| 1276 Object* arg = args[3 + index - start]; |
| 1277 FastElementsAccessorSubclass::SetImpl(*backing_store, index, arg); |
| 1278 } |
| 1279 |
| 1280 if (elms_changed) { |
| 1281 receiver->set_elements(*backing_store); |
| 1282 } |
| 1283 receiver->set_length(Smi::FromInt(new_length)); |
| 1284 return deleted_elements; |
| 1285 } |
| 1286 |
| 1287 private: |
| 1288 static bool SpliceShrinkStep(Handle<FixedArrayBase>& backing_store, |
| 1289 Heap* heap, uint32_t start, |
| 1290 uint32_t delete_count, uint32_t add_count, |
| 1291 uint32_t len, uint32_t new_length) { |
| 1292 const int move_left_count = len - delete_count - start; |
| 1293 const int move_left_dst_index = start + add_count; |
| 1294 const bool left_trim_array = heap->CanMoveObjectStart(*backing_store) && |
| 1295 (move_left_dst_index < move_left_count); |
| 1296 if (left_trim_array) { |
| 1297 const int delta = delete_count - add_count; |
| 1298 // shift from before the insertion point to the right |
| 1299 FastElementsAccessorSubclass::MoveElements(heap, backing_store, delta, 0, |
| 1300 start, 0, 0); |
| 1301 backing_store = handle(heap->LeftTrimFixedArray(*backing_store, delta)); |
| 1302 return true; |
| 1303 } else { |
| 1304 // No left-trim needed or possible (in this case we left-move and store |
| 1305 // the hole) |
| 1306 FastElementsAccessorSubclass::MoveElements( |
| 1307 heap, backing_store, move_left_dst_index, start + delete_count, |
| 1308 move_left_count, new_length, len); |
| 1309 } |
| 1310 return false; |
| 1311 } |
| 1312 |
| 1313 |
| 1314 static bool SpliceGrowStep(Handle<JSArray> receiver, |
| 1315 Handle<FixedArrayBase>& backing_store, |
| 1316 Isolate* isolate, Heap* heap, uint32_t start, |
| 1317 uint32_t delete_count, uint32_t add_count, |
| 1318 uint32_t len, uint32_t new_length) { |
| 1319 // Currently fixed arrays cannot grow too big, so |
| 1320 // we should never hit this case. |
| 1321 DCHECK((add_count - delete_count) <= (Smi::kMaxValue - len)); |
| 1322 // Check if backing_store needs to grow. |
| 1323 if (new_length > static_cast<uint32_t>(backing_store->length())) { |
| 1324 // New backing storage is needed. |
| 1325 int capacity = new_length + (new_length >> 1) + 16; |
| 1326 // partially copy all elements up to start |
| 1327 Handle<FixedArrayBase> new_elms = |
| 1328 FastElementsAccessorSubclass::ConvertElementsWithCapacity( |
| 1329 receiver, backing_store, KindTraits::Kind, capacity, start); |
| 1330 // Copy the trailing elements after start + delete_count |
| 1331 FastElementsAccessorSubclass::CopyElementsImpl( |
| 1332 *backing_store, start + delete_count, *new_elms, KindTraits::Kind, |
| 1333 start + add_count, kPackedSizeNotKnown, |
| 1334 ElementsAccessor::kCopyToEndAndInitializeToHole); |
| 1335 |
| 1336 backing_store = new_elms; |
| 1337 return true; |
| 1338 } else { |
| 1339 DisallowHeapAllocation no_gc; |
| 1340 FastElementsAccessorSubclass::MoveElements( |
| 1341 heap, backing_store, start + add_count, start + delete_count, |
| 1342 (len - delete_count - start), 0, 0); |
| 1343 } |
| 1344 return false; |
| 1345 } |
1206 }; | 1346 }; |
1207 | 1347 |
1208 | 1348 |
1209 template<typename FastElementsAccessorSubclass, | 1349 template<typename FastElementsAccessorSubclass, |
1210 typename KindTraits> | 1350 typename KindTraits> |
1211 class FastSmiOrObjectElementsAccessor | 1351 class FastSmiOrObjectElementsAccessor |
1212 : public FastElementsAccessor<FastElementsAccessorSubclass, KindTraits> { | 1352 : public FastElementsAccessor<FastElementsAccessorSubclass, KindTraits> { |
1213 public: | 1353 public: |
1214 explicit FastSmiOrObjectElementsAccessor(const char* name) | 1354 explicit FastSmiOrObjectElementsAccessor(const char* name) |
1215 : FastElementsAccessor<FastElementsAccessorSubclass, | 1355 : FastElementsAccessor<FastElementsAccessorSubclass, |
1216 KindTraits>(name) {} | 1356 KindTraits>(name) {} |
1217 | 1357 |
1218 static Object* GetRaw(FixedArray* backing_store, uint32_t entry) { | 1358 static Object* GetRaw(FixedArray* backing_store, uint32_t entry) { |
1219 uint32_t index = FastElementsAccessorSubclass::GetIndexForEntryImpl( | 1359 uint32_t index = FastElementsAccessorSubclass::GetIndexForEntryImpl( |
1220 backing_store, entry); | 1360 backing_store, entry); |
1221 return backing_store->get(index); | 1361 return backing_store->get(index); |
1222 } | 1362 } |
1223 | 1363 |
| 1364 static void MoveElements(Heap* heap, Handle<FixedArrayBase> backing_store, |
| 1365 int dst_index, int src_index, int len, |
| 1366 int hole_start, int hole_end) { |
| 1367 Handle<FixedArray> dst_elms = Handle<FixedArray>::cast(backing_store); |
| 1368 if (len != 0) { |
| 1369 DisallowHeapAllocation no_gc; |
| 1370 heap->MoveElements(*dst_elms, dst_index, src_index, len); |
| 1371 } |
| 1372 if (hole_start != hole_end) { |
| 1373 dst_elms->FillWithHoles(hole_start, hole_end); |
| 1374 } |
| 1375 } |
| 1376 |
1224 // NOTE: this method violates the handlified function signature convention: | 1377 // NOTE: this method violates the handlified function signature convention: |
1225 // raw pointer parameters in the function that allocates. | 1378 // raw pointer parameters in the function that allocates. |
1226 // See ElementsAccessor::CopyElements() for details. | 1379 // See ElementsAccessor::CopyElements() for details. |
1227 // This method could actually allocate if copying from double elements to | 1380 // This method could actually allocate if copying from double elements to |
1228 // object elements. | 1381 // object elements. |
1229 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start, | 1382 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start, |
1230 FixedArrayBase* to, ElementsKind from_kind, | 1383 FixedArrayBase* to, ElementsKind from_kind, |
1231 uint32_t to_start, int packed_size, | 1384 uint32_t to_start, int packed_size, |
1232 int copy_size) { | 1385 int copy_size) { |
1233 DisallowHeapAllocation no_gc; | 1386 DisallowHeapAllocation no_gc; |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1314 | 1467 |
1315 template<typename FastElementsAccessorSubclass, | 1468 template<typename FastElementsAccessorSubclass, |
1316 typename KindTraits> | 1469 typename KindTraits> |
1317 class FastDoubleElementsAccessor | 1470 class FastDoubleElementsAccessor |
1318 : public FastElementsAccessor<FastElementsAccessorSubclass, KindTraits> { | 1471 : public FastElementsAccessor<FastElementsAccessorSubclass, KindTraits> { |
1319 public: | 1472 public: |
1320 explicit FastDoubleElementsAccessor(const char* name) | 1473 explicit FastDoubleElementsAccessor(const char* name) |
1321 : FastElementsAccessor<FastElementsAccessorSubclass, | 1474 : FastElementsAccessor<FastElementsAccessorSubclass, |
1322 KindTraits>(name) {} | 1475 KindTraits>(name) {} |
1323 | 1476 |
| 1477 static void MoveElements(Heap* heap, Handle<FixedArrayBase> backing_store, |
| 1478 int dst_index, int src_index, int len, |
| 1479 int hole_start, int hole_end) { |
| 1480 Handle<FixedDoubleArray> dst_elms = |
| 1481 Handle<FixedDoubleArray>::cast(backing_store); |
| 1482 if (len != 0) { |
| 1483 MemMove(dst_elms->data_start() + dst_index, |
| 1484 dst_elms->data_start() + src_index, len * kDoubleSize); |
| 1485 } |
| 1486 if (hole_start != hole_end) { |
| 1487 dst_elms->FillWithHoles(hole_start, hole_end); |
| 1488 } |
| 1489 } |
| 1490 |
1324 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start, | 1491 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start, |
1325 FixedArrayBase* to, ElementsKind from_kind, | 1492 FixedArrayBase* to, ElementsKind from_kind, |
1326 uint32_t to_start, int packed_size, | 1493 uint32_t to_start, int packed_size, |
1327 int copy_size) { | 1494 int copy_size) { |
1328 DisallowHeapAllocation no_allocation; | 1495 DisallowHeapAllocation no_allocation; |
1329 switch (from_kind) { | 1496 switch (from_kind) { |
1330 case FAST_SMI_ELEMENTS: | 1497 case FAST_SMI_ELEMENTS: |
1331 CopyPackedSmiToDoubleElements(from, from_start, to, to_start, | 1498 CopyPackedSmiToDoubleElements(from, from_start, to, to_start, |
1332 packed_size, copy_size); | 1499 packed_size, copy_size); |
1333 break; | 1500 break; |
(...skipping 640 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1974 #define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind]; | 2141 #define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind]; |
1975 ELEMENTS_LIST(ACCESSOR_DELETE) | 2142 ELEMENTS_LIST(ACCESSOR_DELETE) |
1976 #undef ACCESSOR_DELETE | 2143 #undef ACCESSOR_DELETE |
1977 elements_accessors_ = NULL; | 2144 elements_accessors_ = NULL; |
1978 } | 2145 } |
1979 | 2146 |
1980 | 2147 |
1981 ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL; | 2148 ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL; |
1982 } // namespace internal | 2149 } // namespace internal |
1983 } // namespace v8 | 2150 } // namespace v8 |
OLD | NEW |