Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(160)

Side by Side Diff: src/elements.cc

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

Powered by Google App Engine
This is Rietveld 408576698