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/v8.h" | 5 #include "src/v8.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/elements.h" | 9 #include "src/elements.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 |
118 static void CopyObjectToObjectElements(FixedArrayBase* from_base, | 119 static void CopyObjectToObjectElements(FixedArrayBase* from_base, |
119 ElementsKind from_kind, | 120 ElementsKind from_kind, |
120 uint32_t from_start, | 121 uint32_t from_start, |
121 FixedArrayBase* to_base, | 122 FixedArrayBase* to_base, |
122 ElementsKind to_kind, uint32_t to_start, | 123 ElementsKind to_kind, uint32_t to_start, |
123 int raw_copy_size) { | 124 int raw_copy_size) { |
124 DCHECK(to_base->map() != | 125 DCHECK(to_base->map() != |
125 from_base->GetIsolate()->heap()->fixed_cow_array_map()); | 126 from_base->GetIsolate()->heap()->fixed_cow_array_map()); |
126 DisallowHeapAllocation no_allocation; | 127 DisallowHeapAllocation no_allocation; |
127 int copy_size = raw_copy_size; | 128 int copy_size = raw_copy_size; |
(...skipping 450 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
578 push_size, direction); | 579 push_size, direction); |
579 } | 580 } |
580 | 581 |
581 static uint32_t PushImpl(Handle<JSArray> receiver, | 582 static uint32_t PushImpl(Handle<JSArray> receiver, |
582 Handle<FixedArrayBase> elms_obj, Object** objects, | 583 Handle<FixedArrayBase> elms_obj, Object** objects, |
583 uint32_t push_size, int direction) { | 584 uint32_t push_size, int direction) { |
584 UNREACHABLE(); | 585 UNREACHABLE(); |
585 return 0; | 586 return 0; |
586 } | 587 } |
587 | 588 |
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 | |
605 virtual void SetLength(Handle<JSArray> array, uint32_t length) final { | 589 virtual void SetLength(Handle<JSArray> array, uint32_t length) final { |
606 ElementsAccessorSubclass::SetLengthImpl(array, length, | 590 ElementsAccessorSubclass::SetLengthImpl(array, length, |
607 handle(array->elements())); | 591 handle(array->elements())); |
608 } | 592 } |
609 | 593 |
610 static void SetLengthImpl(Handle<JSArray> array, uint32_t length, | 594 static void SetLengthImpl(Handle<JSArray> array, uint32_t length, |
611 Handle<FixedArrayBase> backing_store); | 595 Handle<FixedArrayBase> backing_store); |
612 | 596 |
613 static Handle<FixedArrayBase> ConvertElementsWithCapacity( | 597 static Handle<FixedArrayBase> ConvertElementsWithCapacity( |
614 Handle<JSObject> object, Handle<FixedArrayBase> old_elements, | 598 Handle<JSObject> object, Handle<FixedArrayBase> old_elements, |
615 ElementsKind from_kind, uint32_t capacity) { | 599 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) { | |
624 Isolate* isolate = object->GetIsolate(); | 600 Isolate* isolate = object->GetIsolate(); |
625 Handle<FixedArrayBase> new_elements; | 601 Handle<FixedArrayBase> elements; |
626 if (IsFastDoubleElementsKind(kind())) { | 602 if (IsFastDoubleElementsKind(kind())) { |
627 new_elements = isolate->factory()->NewFixedDoubleArray(capacity); | 603 elements = isolate->factory()->NewFixedDoubleArray(capacity); |
628 } else { | 604 } else { |
629 new_elements = isolate->factory()->NewUninitializedFixedArray(capacity); | 605 elements = isolate->factory()->NewUninitializedFixedArray(capacity); |
630 } | 606 } |
631 | 607 |
632 int packed_size = kPackedSizeNotKnown; | 608 int packed = kPackedSizeNotKnown; |
633 if (IsFastPackedElementsKind(from_kind) && object->IsJSArray()) { | 609 if (IsFastPackedElementsKind(from_kind) && object->IsJSArray()) { |
634 packed_size = Smi::cast(JSArray::cast(*object)->length())->value(); | 610 packed = Smi::cast(JSArray::cast(*object)->length())->value(); |
635 } | 611 } |
636 | 612 |
637 ElementsAccessorSubclass::CopyElementsImpl( | 613 ElementsAccessorSubclass::CopyElementsImpl( |
638 *old_elements, 0, *new_elements, from_kind, 0, packed_size, copy_size); | 614 *old_elements, 0, *elements, from_kind, 0, packed, |
639 | 615 ElementsAccessor::kCopyToEndAndInitializeToHole); |
640 return new_elements; | 616 return elements; |
641 } | 617 } |
642 | 618 |
643 static void GrowCapacityAndConvertImpl(Handle<JSObject> object, | 619 static void GrowCapacityAndConvertImpl(Handle<JSObject> object, |
644 uint32_t capacity) { | 620 uint32_t capacity) { |
645 ElementsKind from_kind = object->GetElementsKind(); | 621 ElementsKind from_kind = object->GetElementsKind(); |
646 if (IsFastSmiOrObjectElementsKind(from_kind)) { | 622 if (IsFastSmiOrObjectElementsKind(from_kind)) { |
647 // Array optimizations rely on the prototype lookups of Array objects | 623 // Array optimizations rely on the prototype lookups of Array objects |
648 // always returning undefined. If there is a store to the initial | 624 // always returning undefined. If there is a store to the initial |
649 // prototype object, make sure all of these optimizations are invalidated. | 625 // prototype object, make sure all of these optimizations are invalidated. |
650 object->GetIsolate()->UpdateArrayProtectorOnSetLength(object); | 626 object->GetIsolate()->UpdateArrayProtectorOnSetLength(object); |
(...skipping 545 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1196 uint32_t new_length = len + push_size; | 1172 uint32_t new_length = len + push_size; |
1197 Handle<FixedArrayBase> new_elms; | 1173 Handle<FixedArrayBase> new_elms; |
1198 | 1174 |
1199 if (new_length > elms_len) { | 1175 if (new_length > elms_len) { |
1200 // New backing storage is needed. | 1176 // New backing storage is needed. |
1201 uint32_t capacity = new_length + (new_length >> 1) + 16; | 1177 uint32_t capacity = new_length + (new_length >> 1) + 16; |
1202 new_elms = FastElementsAccessorSubclass::ConvertElementsWithCapacity( | 1178 new_elms = FastElementsAccessorSubclass::ConvertElementsWithCapacity( |
1203 receiver, backing_store, KindTraits::Kind, capacity); | 1179 receiver, backing_store, KindTraits::Kind, capacity); |
1204 } else { | 1180 } else { |
1205 // push_size is > 0 and new_length <= elms_len, so backing_store cannot be | 1181 // push_size is > 0 and new_length <= elms_len, so backing_store cannot be |
1206 // the empty_fixed_array. | 1182 // the |
| 1183 // empty_fixed_array. |
1207 new_elms = backing_store; | 1184 new_elms = backing_store; |
1208 } | 1185 } |
1209 | 1186 |
1210 // Add the provided values. | 1187 // Add the provided values. |
1211 DisallowHeapAllocation no_gc; | 1188 DisallowHeapAllocation no_gc; |
1212 DCHECK(direction == ElementsAccessor::kDirectionForward || | 1189 DCHECK(direction == ElementsAccessor::kDirectionForward || |
1213 direction == ElementsAccessor::kDirectionReverse); | 1190 direction == ElementsAccessor::kDirectionReverse); |
1214 STATIC_ASSERT(ElementsAccessor::kDirectionForward == 1); | 1191 STATIC_ASSERT(ElementsAccessor::kDirectionForward == 1); |
1215 STATIC_ASSERT(ElementsAccessor::kDirectionReverse == -1); | 1192 STATIC_ASSERT(ElementsAccessor::kDirectionReverse == -1); |
1216 for (uint32_t index = 0; index < push_size; index++) { | 1193 for (uint32_t index = 0; index < push_size; index++) { |
1217 int offset = direction * index; | 1194 int offset = direction * index; |
1218 Object* object = objects[offset]; | 1195 Object* object = objects[offset]; |
1219 FastElementsAccessorSubclass::SetImpl(*new_elms, index + len, object); | 1196 FastElementsAccessorSubclass::SetImpl(*new_elms, index + len, object); |
1220 } | 1197 } |
1221 if (!new_elms.is_identical_to(backing_store)) { | 1198 if (!new_elms.is_identical_to(backing_store)) { |
1222 receiver->set_elements(*new_elms); | 1199 receiver->set_elements(*new_elms); |
1223 } | 1200 } |
1224 DCHECK(*new_elms == receiver->elements()); | 1201 DCHECK(*new_elms == receiver->elements()); |
1225 // Set the length. | 1202 // Set the length. |
1226 receiver->set_length(Smi::FromInt(new_length)); | 1203 receiver->set_length(Smi::FromInt(new_length)); |
1227 return new_length; | 1204 return new_length; |
1228 } | 1205 } |
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 if (IsFastDoubleElementsKind(KindTraits::Kind)) { | |
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 } else { | |
1280 // FastSmiOrObjectElementsKind | |
1281 Handle<FixedArray> elms = Handle<FixedArray>::cast(backing_store); | |
1282 DisallowHeapAllocation no_gc; | |
1283 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); | |
1284 for (uint32_t index = start; index < start + add_count; index++) { | |
1285 elms->set(index, args[3 + index - start], mode); | |
1286 } | |
1287 } | |
1288 | |
1289 if (elms_changed) { | |
1290 receiver->set_elements(*backing_store); | |
1291 } | |
1292 receiver->set_length(Smi::FromInt(new_length)); | |
1293 return deleted_elements; | |
1294 } | |
1295 | |
1296 private: | |
1297 static bool SpliceShrinkStep(Handle<FixedArrayBase>& backing_store, | |
1298 Heap* heap, uint32_t start, | |
1299 uint32_t delete_count, uint32_t add_count, | |
1300 uint32_t len, uint32_t new_length) { | |
1301 const int move_left_count = len - delete_count - start; | |
1302 const int move_left_dst_index = start + add_count; | |
1303 const bool left_trim_array = heap->CanMoveObjectStart(*backing_store) && | |
1304 (move_left_dst_index < move_left_count); | |
1305 if (left_trim_array) { | |
1306 const int delta = delete_count - add_count; | |
1307 // shift from before the insertion point to the right | |
1308 FastElementsAccessorSubclass::MoveElements(heap, backing_store, delta, 0, | |
1309 start, 0, 0); | |
1310 backing_store = handle(heap->LeftTrimFixedArray(*backing_store, delta)); | |
1311 return true; | |
1312 } else { | |
1313 // No left-trim needed or possible (in this case we left-move and store | |
1314 // the hole) | |
1315 FastElementsAccessorSubclass::MoveElements( | |
1316 heap, backing_store, move_left_dst_index, start + delete_count, | |
1317 move_left_count, new_length, len); | |
1318 } | |
1319 return false; | |
1320 } | |
1321 | |
1322 | |
1323 static bool SpliceGrowStep(Handle<JSArray> receiver, | |
1324 Handle<FixedArrayBase>& backing_store, | |
1325 Isolate* isolate, Heap* heap, uint32_t start, | |
1326 uint32_t delete_count, uint32_t add_count, | |
1327 uint32_t len, uint32_t new_length) { | |
1328 // Currently fixed arrays cannot grow too big, so | |
1329 // we should never hit this case. | |
1330 DCHECK((add_count - delete_count) <= (Smi::kMaxValue - len)); | |
1331 // Check if backing_store needs to grow. | |
1332 if (new_length > static_cast<uint32_t>(backing_store->length())) { | |
1333 // New backing storage is needed. | |
1334 int capacity = new_length + (new_length >> 1) + 16; | |
1335 // partially copy all elements up to start | |
1336 Handle<FixedArrayBase> new_elms = | |
1337 FastElementsAccessorSubclass::ConvertElementsWithCapacity( | |
1338 receiver, backing_store, KindTraits::Kind, capacity, start); | |
1339 // Copy the trailing elements after start + delete_count | |
1340 FastElementsAccessorSubclass::CopyElementsImpl( | |
1341 *backing_store, start + delete_count, *new_elms, KindTraits::Kind, | |
1342 start + add_count, kPackedSizeNotKnown, | |
1343 ElementsAccessor::kCopyToEndAndInitializeToHole); | |
1344 | |
1345 backing_store = new_elms; | |
1346 return true; | |
1347 } else { | |
1348 DisallowHeapAllocation no_gc; | |
1349 FastElementsAccessorSubclass::MoveElements( | |
1350 heap, backing_store, start + add_count, start + delete_count, | |
1351 (len - delete_count - start), 0, 0); | |
1352 } | |
1353 return false; | |
1354 } | |
1355 }; | 1206 }; |
1356 | 1207 |
1357 | 1208 |
1358 template<typename FastElementsAccessorSubclass, | 1209 template<typename FastElementsAccessorSubclass, |
1359 typename KindTraits> | 1210 typename KindTraits> |
1360 class FastSmiOrObjectElementsAccessor | 1211 class FastSmiOrObjectElementsAccessor |
1361 : public FastElementsAccessor<FastElementsAccessorSubclass, KindTraits> { | 1212 : public FastElementsAccessor<FastElementsAccessorSubclass, KindTraits> { |
1362 public: | 1213 public: |
1363 explicit FastSmiOrObjectElementsAccessor(const char* name) | 1214 explicit FastSmiOrObjectElementsAccessor(const char* name) |
1364 : FastElementsAccessor<FastElementsAccessorSubclass, | 1215 : FastElementsAccessor<FastElementsAccessorSubclass, |
1365 KindTraits>(name) {} | 1216 KindTraits>(name) {} |
1366 | 1217 |
1367 static Object* GetRaw(FixedArray* backing_store, uint32_t entry) { | 1218 static Object* GetRaw(FixedArray* backing_store, uint32_t entry) { |
1368 uint32_t index = FastElementsAccessorSubclass::GetIndexForEntryImpl( | 1219 uint32_t index = FastElementsAccessorSubclass::GetIndexForEntryImpl( |
1369 backing_store, entry); | 1220 backing_store, entry); |
1370 return backing_store->get(index); | 1221 return backing_store->get(index); |
1371 } | 1222 } |
1372 | 1223 |
1373 static void MoveElements(Heap* heap, Handle<FixedArrayBase> backing_store, | |
1374 int dst_index, int src_index, int len, | |
1375 int hole_start, int hole_end) { | |
1376 if (len == 0) return; | |
1377 Handle<FixedArray> dst_elms = Handle<FixedArray>::cast(backing_store); | |
1378 DisallowHeapAllocation no_gc; | |
1379 heap->MoveElements(*dst_elms, dst_index, src_index, len); | |
1380 if (hole_start != hole_end) { | |
1381 dst_elms->FillWithHoles(hole_start, hole_end); | |
1382 } | |
1383 } | |
1384 | |
1385 // NOTE: this method violates the handlified function signature convention: | 1224 // NOTE: this method violates the handlified function signature convention: |
1386 // raw pointer parameters in the function that allocates. | 1225 // raw pointer parameters in the function that allocates. |
1387 // See ElementsAccessor::CopyElements() for details. | 1226 // See ElementsAccessor::CopyElements() for details. |
1388 // This method could actually allocate if copying from double elements to | 1227 // This method could actually allocate if copying from double elements to |
1389 // object elements. | 1228 // object elements. |
1390 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start, | 1229 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start, |
1391 FixedArrayBase* to, ElementsKind from_kind, | 1230 FixedArrayBase* to, ElementsKind from_kind, |
1392 uint32_t to_start, int packed_size, | 1231 uint32_t to_start, int packed_size, |
1393 int copy_size) { | 1232 int copy_size) { |
1394 DisallowHeapAllocation no_gc; | 1233 DisallowHeapAllocation no_gc; |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1475 | 1314 |
1476 template<typename FastElementsAccessorSubclass, | 1315 template<typename FastElementsAccessorSubclass, |
1477 typename KindTraits> | 1316 typename KindTraits> |
1478 class FastDoubleElementsAccessor | 1317 class FastDoubleElementsAccessor |
1479 : public FastElementsAccessor<FastElementsAccessorSubclass, KindTraits> { | 1318 : public FastElementsAccessor<FastElementsAccessorSubclass, KindTraits> { |
1480 public: | 1319 public: |
1481 explicit FastDoubleElementsAccessor(const char* name) | 1320 explicit FastDoubleElementsAccessor(const char* name) |
1482 : FastElementsAccessor<FastElementsAccessorSubclass, | 1321 : FastElementsAccessor<FastElementsAccessorSubclass, |
1483 KindTraits>(name) {} | 1322 KindTraits>(name) {} |
1484 | 1323 |
1485 static void MoveElements(Heap* heap, Handle<FixedArrayBase> backing_store, | |
1486 int dst_index, int src_index, int len, | |
1487 int hole_start, int hole_end) { | |
1488 if (len == 0) return; | |
1489 Handle<FixedDoubleArray> dst_elms = | |
1490 Handle<FixedDoubleArray>::cast(backing_store); | |
1491 MemMove(dst_elms->data_start() + dst_index, | |
1492 dst_elms->data_start() + src_index, len * kDoubleSize); | |
1493 if (hole_start != hole_end) { | |
1494 dst_elms->FillWithHoles(hole_start, hole_end); | |
1495 } | |
1496 } | |
1497 | |
1498 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start, | 1324 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start, |
1499 FixedArrayBase* to, ElementsKind from_kind, | 1325 FixedArrayBase* to, ElementsKind from_kind, |
1500 uint32_t to_start, int packed_size, | 1326 uint32_t to_start, int packed_size, |
1501 int copy_size) { | 1327 int copy_size) { |
1502 DisallowHeapAllocation no_allocation; | 1328 DisallowHeapAllocation no_allocation; |
1503 switch (from_kind) { | 1329 switch (from_kind) { |
1504 case FAST_SMI_ELEMENTS: | 1330 case FAST_SMI_ELEMENTS: |
1505 CopyPackedSmiToDoubleElements(from, from_start, to, to_start, | 1331 CopyPackedSmiToDoubleElements(from, from_start, to, to_start, |
1506 packed_size, copy_size); | 1332 packed_size, copy_size); |
1507 break; | 1333 break; |
(...skipping 640 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2148 #define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind]; | 1974 #define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind]; |
2149 ELEMENTS_LIST(ACCESSOR_DELETE) | 1975 ELEMENTS_LIST(ACCESSOR_DELETE) |
2150 #undef ACCESSOR_DELETE | 1976 #undef ACCESSOR_DELETE |
2151 elements_accessors_ = NULL; | 1977 elements_accessors_ = NULL; |
2152 } | 1978 } |
2153 | 1979 |
2154 | 1980 |
2155 ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL; | 1981 ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL; |
2156 } // namespace internal | 1982 } // namespace internal |
2157 } // namespace v8 | 1983 } // namespace v8 |
OLD | NEW |