| 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 652 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 663 Handle<FixedArrayBase> backing_store) final { | 663 Handle<FixedArrayBase> backing_store) final { |
| 664 return ElementsAccessorSubclass::PopImpl(receiver, backing_store); | 664 return ElementsAccessorSubclass::PopImpl(receiver, backing_store); |
| 665 } | 665 } |
| 666 | 666 |
| 667 static Handle<Object> PopImpl(Handle<JSArray> receiver, | 667 static Handle<Object> PopImpl(Handle<JSArray> receiver, |
| 668 Handle<FixedArrayBase> backing_store) { | 668 Handle<FixedArrayBase> backing_store) { |
| 669 UNREACHABLE(); | 669 UNREACHABLE(); |
| 670 return Handle<Object>(); | 670 return Handle<Object>(); |
| 671 } | 671 } |
| 672 | 672 |
| 673 virtual Handle<Object> Shift(Handle<JSArray> receiver, |
| 674 Handle<FixedArrayBase> backing_store) final { |
| 675 return ElementsAccessorSubclass::ShiftImpl(receiver, backing_store); |
| 676 } |
| 677 |
| 678 static Handle<Object> ShiftImpl(Handle<JSArray> receiver, |
| 679 Handle<FixedArrayBase> backing_store) { |
| 680 UNREACHABLE(); |
| 681 return Handle<Object>(); |
| 682 } |
| 683 |
| 673 virtual void SetLength(Handle<JSArray> array, uint32_t length) final { | 684 virtual void SetLength(Handle<JSArray> array, uint32_t length) final { |
| 674 ElementsAccessorSubclass::SetLengthImpl(array, length, | 685 ElementsAccessorSubclass::SetLengthImpl(array, length, |
| 675 handle(array->elements())); | 686 handle(array->elements())); |
| 676 } | 687 } |
| 677 | 688 |
| 678 static void SetLengthImpl(Handle<JSArray> array, uint32_t length, | 689 static void SetLengthImpl(Handle<JSArray> array, uint32_t length, |
| 679 Handle<FixedArrayBase> backing_store); | 690 Handle<FixedArrayBase> backing_store) { |
| 691 DCHECK(!array->SetLengthWouldNormalize(length)); |
| 692 DCHECK(IsFastElementsKind(array->GetElementsKind())); |
| 693 uint32_t old_length = 0; |
| 694 CHECK(array->length()->ToArrayIndex(&old_length)); |
| 695 |
| 696 if (old_length < length) { |
| 697 ElementsKind kind = array->GetElementsKind(); |
| 698 if (!IsFastHoleyElementsKind(kind)) { |
| 699 kind = GetHoleyElementsKind(kind); |
| 700 JSObject::TransitionElementsKind(array, kind); |
| 701 } |
| 702 } |
| 703 |
| 704 // Check whether the backing store should be shrunk. |
| 705 uint32_t capacity = backing_store->length(); |
| 706 if (length == 0) { |
| 707 array->initialize_elements(); |
| 708 } else if (length <= capacity) { |
| 709 if (array->HasFastSmiOrObjectElements()) { |
| 710 backing_store = JSObject::EnsureWritableFastElements(array); |
| 711 } |
| 712 if (2 * length <= capacity) { |
| 713 // If more than half the elements won't be used, trim the array. |
| 714 array->GetHeap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>( |
| 715 *backing_store, capacity - length); |
| 716 } else { |
| 717 // Otherwise, fill the unused tail with holes. |
| 718 for (uint32_t i = length; i < old_length; i++) { |
| 719 BackingStore::cast(*backing_store)->set_the_hole(i); |
| 720 } |
| 721 } |
| 722 } else { |
| 723 // Check whether the backing store should be expanded. |
| 724 capacity = Max(length, JSObject::NewElementsCapacity(capacity)); |
| 725 ElementsAccessorSubclass::GrowCapacityAndConvertImpl(array, capacity); |
| 726 } |
| 727 |
| 728 array->set_length(Smi::FromInt(length)); |
| 729 JSObject::ValidateElements(array); |
| 730 } |
| 680 | 731 |
| 681 static Handle<FixedArrayBase> ConvertElementsWithCapacity( | 732 static Handle<FixedArrayBase> ConvertElementsWithCapacity( |
| 682 Handle<JSObject> object, Handle<FixedArrayBase> old_elements, | 733 Handle<JSObject> object, Handle<FixedArrayBase> old_elements, |
| 683 ElementsKind from_kind, uint32_t capacity) { | 734 ElementsKind from_kind, uint32_t capacity) { |
| 684 return ConvertElementsWithCapacity( | 735 return ConvertElementsWithCapacity( |
| 685 object, old_elements, from_kind, capacity, 0, 0, | 736 object, old_elements, from_kind, capacity, 0, 0, |
| 686 ElementsAccessor::kCopyToEndAndInitializeToHole); | 737 ElementsAccessor::kCopyToEndAndInitializeToHole); |
| 687 } | 738 } |
| 688 | 739 |
| 689 static Handle<FixedArrayBase> ConvertElementsWithCapacity( | 740 static Handle<FixedArrayBase> ConvertElementsWithCapacity( |
| (...skipping 564 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1254 DCHECK(BackingStore::get(backing_store, i)->IsSmi() || | 1305 DCHECK(BackingStore::get(backing_store, i)->IsSmi() || |
| 1255 (IsFastHoleyElementsKind(KindTraits::Kind) && | 1306 (IsFastHoleyElementsKind(KindTraits::Kind) && |
| 1256 backing_store->is_the_hole(i))); | 1307 backing_store->is_the_hole(i))); |
| 1257 } | 1308 } |
| 1258 } | 1309 } |
| 1259 #endif | 1310 #endif |
| 1260 } | 1311 } |
| 1261 | 1312 |
| 1262 static Handle<Object> PopImpl(Handle<JSArray> receiver, | 1313 static Handle<Object> PopImpl(Handle<JSArray> receiver, |
| 1263 Handle<FixedArrayBase> backing_store) { | 1314 Handle<FixedArrayBase> backing_store) { |
| 1264 uint32_t new_length = | 1315 uint32_t len = |
| 1265 static_cast<uint32_t>(Smi::cast(receiver->length())->value()) - 1; | 1316 static_cast<uint32_t>(Smi::cast(receiver->length())->value()); |
| 1317 DCHECK(len > 0); |
| 1318 uint32_t new_length = len - 1; |
| 1266 Handle<Object> result = | 1319 Handle<Object> result = |
| 1267 FastElementsAccessorSubclass::GetImpl(backing_store, new_length); | 1320 FastElementsAccessorSubclass::GetImpl(backing_store, new_length); |
| 1268 FastElementsAccessorSubclass::SetLengthImpl(receiver, new_length, | 1321 FastElementsAccessorSubclass::SetLengthImpl(receiver, new_length, |
| 1269 backing_store); | 1322 backing_store); |
| 1270 | 1323 |
| 1271 if (IsHoleyElementsKind(KindTraits::Kind) && result->IsTheHole()) { | 1324 if (IsHoleyElementsKind(KindTraits::Kind) && result->IsTheHole()) { |
| 1325 return receiver->GetIsolate()->factory()->undefined_value(); |
| 1326 } |
| 1327 return result; |
| 1328 } |
| 1329 |
| 1330 static Handle<Object> ShiftImpl(Handle<JSArray> receiver, |
| 1331 Handle<FixedArrayBase> backing_store) { |
| 1332 uint32_t len = |
| 1333 static_cast<uint32_t>(Smi::cast(receiver->length())->value()); |
| 1334 Isolate* isolate = receiver->GetIsolate(); |
| 1335 DCHECK(len > 0); |
| 1336 int new_length = len - 1; |
| 1337 Handle<Object> result = |
| 1338 FastElementsAccessorSubclass::GetImpl(backing_store, 0); |
| 1339 Heap* heap = isolate->heap(); |
| 1340 if (heap->CanMoveObjectStart(*backing_store)) { |
| 1341 receiver->set_elements(heap->LeftTrimFixedArray(*backing_store, 1)); |
| 1342 } else { |
| 1343 FastElementsAccessorSubclass::MoveElements(heap, backing_store, 0, 1, |
| 1344 new_length, 0, 0); |
| 1345 } |
| 1346 FastElementsAccessorSubclass::SetLengthImpl(receiver, new_length, |
| 1347 backing_store); |
| 1348 |
| 1349 if (IsHoleyElementsKind(KindTraits::Kind) && result->IsTheHole()) { |
| 1272 result = receiver->GetIsolate()->factory()->undefined_value(); | 1350 result = receiver->GetIsolate()->factory()->undefined_value(); |
| 1273 } | 1351 } |
| 1274 return result; | 1352 return result; |
| 1275 } | 1353 } |
| 1276 | 1354 |
| 1277 static uint32_t PushImpl(Handle<JSArray> receiver, | 1355 static uint32_t PushImpl(Handle<JSArray> receiver, |
| 1278 Handle<FixedArrayBase> backing_store, | 1356 Handle<FixedArrayBase> backing_store, |
| 1279 Arguments* args, uint32_t push_size) { | 1357 Arguments* args, uint32_t push_size) { |
| 1280 uint32_t len = Smi::cast(receiver->length())->value(); | 1358 uint32_t len = Smi::cast(receiver->length())->value(); |
| 1281 if (push_size == 0) { | 1359 DCHECK(push_size > 0); |
| 1282 return len; | |
| 1283 } | |
| 1284 uint32_t elms_len = backing_store->length(); | 1360 uint32_t elms_len = backing_store->length(); |
| 1285 // Currently fixed arrays cannot grow too big, so | 1361 // Currently fixed arrays cannot grow too big, so |
| 1286 // we should never hit this case. | 1362 // we should never hit this case. |
| 1287 DCHECK(push_size <= static_cast<uint32_t>(Smi::kMaxValue - len)); | 1363 DCHECK(push_size <= static_cast<uint32_t>(Smi::kMaxValue - len)); |
| 1288 uint32_t new_length = len + push_size; | 1364 uint32_t new_length = len + push_size; |
| 1289 | 1365 |
| 1290 if (new_length > elms_len) { | 1366 if (new_length > elms_len) { |
| 1291 // New backing storage is needed. | 1367 // New backing storage is needed. |
| 1292 uint32_t capacity = new_length + (new_length >> 1) + 16; | 1368 uint32_t capacity = new_length + (new_length >> 1) + 16; |
| 1293 backing_store = FastElementsAccessorSubclass::ConvertElementsWithCapacity( | 1369 backing_store = FastElementsAccessorSubclass::ConvertElementsWithCapacity( |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1307 DCHECK(*backing_store == receiver->elements()); | 1383 DCHECK(*backing_store == receiver->elements()); |
| 1308 // Set the length. | 1384 // Set the length. |
| 1309 receiver->set_length(Smi::FromInt(new_length)); | 1385 receiver->set_length(Smi::FromInt(new_length)); |
| 1310 return new_length; | 1386 return new_length; |
| 1311 } | 1387 } |
| 1312 | 1388 |
| 1313 static uint32_t UnshiftImpl(Handle<JSArray> receiver, | 1389 static uint32_t UnshiftImpl(Handle<JSArray> receiver, |
| 1314 Handle<FixedArrayBase> backing_store, | 1390 Handle<FixedArrayBase> backing_store, |
| 1315 Arguments* args, uint32_t unshift_size) { | 1391 Arguments* args, uint32_t unshift_size) { |
| 1316 uint32_t len = Smi::cast(receiver->length())->value(); | 1392 uint32_t len = Smi::cast(receiver->length())->value(); |
| 1317 if (unshift_size == 0) { | 1393 DCHECK(unshift_size > 0); |
| 1318 return len; | |
| 1319 } | |
| 1320 uint32_t elms_len = backing_store->length(); | 1394 uint32_t elms_len = backing_store->length(); |
| 1321 // Currently fixed arrays cannot grow too big, so | 1395 // Currently fixed arrays cannot grow too big, so |
| 1322 // we should never hit this case. | 1396 // we should never hit this case. |
| 1323 DCHECK(unshift_size <= static_cast<uint32_t>(Smi::kMaxValue - len)); | 1397 DCHECK(unshift_size <= static_cast<uint32_t>(Smi::kMaxValue - len)); |
| 1324 uint32_t new_length = len + unshift_size; | 1398 uint32_t new_length = len + unshift_size; |
| 1325 | 1399 |
| 1326 if (new_length > elms_len) { | 1400 if (new_length > elms_len) { |
| 1327 // New backing storage is needed. | 1401 // New backing storage is needed. |
| 1328 uint32_t capacity = new_length + (new_length >> 1) + 16; | 1402 uint32_t capacity = new_length + (new_length >> 1) + 16; |
| 1329 backing_store = FastElementsAccessorSubclass::ConvertElementsWithCapacity( | 1403 backing_store = FastElementsAccessorSubclass::ConvertElementsWithCapacity( |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1355 | 1429 |
| 1356 static void MoveElements(Heap* heap, Handle<FixedArrayBase> backing_store, | 1430 static void MoveElements(Heap* heap, Handle<FixedArrayBase> backing_store, |
| 1357 int dst_index, int src_index, int len, | 1431 int dst_index, int src_index, int len, |
| 1358 int hole_start, int hole_end) { | 1432 int hole_start, int hole_end) { |
| 1359 UNREACHABLE(); | 1433 UNREACHABLE(); |
| 1360 } | 1434 } |
| 1361 | 1435 |
| 1362 static Handle<JSArray> SliceImpl(Handle<JSObject> receiver, | 1436 static Handle<JSArray> SliceImpl(Handle<JSObject> receiver, |
| 1363 Handle<FixedArrayBase> backing_store, | 1437 Handle<FixedArrayBase> backing_store, |
| 1364 uint32_t start, uint32_t end) { | 1438 uint32_t start, uint32_t end) { |
| 1439 DCHECK(start < end); |
| 1365 Isolate* isolate = receiver->GetIsolate(); | 1440 Isolate* isolate = receiver->GetIsolate(); |
| 1366 if (end <= start) { | |
| 1367 return isolate->factory()->NewJSArray(KindTraits::Kind, 0, 0); | |
| 1368 } | |
| 1369 int result_len = end - start; | 1441 int result_len = end - start; |
| 1370 Handle<JSArray> result_array = isolate->factory()->NewJSArray( | 1442 Handle<JSArray> result_array = isolate->factory()->NewJSArray( |
| 1371 KindTraits::Kind, result_len, result_len); | 1443 KindTraits::Kind, result_len, result_len); |
| 1372 DisallowHeapAllocation no_gc; | 1444 DisallowHeapAllocation no_gc; |
| 1373 FastElementsAccessorSubclass::CopyElementsImpl( | 1445 FastElementsAccessorSubclass::CopyElementsImpl( |
| 1374 *backing_store, start, result_array->elements(), KindTraits::Kind, 0, | 1446 *backing_store, start, result_array->elements(), KindTraits::Kind, 0, |
| 1375 kPackedSizeNotKnown, result_len); | 1447 kPackedSizeNotKnown, result_len); |
| 1376 return result_array; | 1448 return result_array; |
| 1377 } | 1449 } |
| 1378 | 1450 |
| (...skipping 736 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2115 ConvertElementsWithCapacity(object, old_elements, from_kind, capacity); | 2187 ConvertElementsWithCapacity(object, old_elements, from_kind, capacity); |
| 2116 Handle<Map> new_map = JSObject::GetElementsTransitionMap( | 2188 Handle<Map> new_map = JSObject::GetElementsTransitionMap( |
| 2117 object, FAST_SLOPPY_ARGUMENTS_ELEMENTS); | 2189 object, FAST_SLOPPY_ARGUMENTS_ELEMENTS); |
| 2118 JSObject::MigrateToMap(object, new_map); | 2190 JSObject::MigrateToMap(object, new_map); |
| 2119 parameter_map->set(1, *elements); | 2191 parameter_map->set(1, *elements); |
| 2120 JSObject::ValidateElements(object); | 2192 JSObject::ValidateElements(object); |
| 2121 } | 2193 } |
| 2122 }; | 2194 }; |
| 2123 | 2195 |
| 2124 | 2196 |
| 2125 template <typename ElementsAccessorSubclass, typename ElementsKindTraits> | |
| 2126 void ElementsAccessorBase<ElementsAccessorSubclass, ElementsKindTraits>:: | |
| 2127 SetLengthImpl(Handle<JSArray> array, uint32_t length, | |
| 2128 Handle<FixedArrayBase> backing_store) { | |
| 2129 DCHECK(!array->SetLengthWouldNormalize(length)); | |
| 2130 DCHECK(IsFastElementsKind(array->GetElementsKind())); | |
| 2131 uint32_t old_length = 0; | |
| 2132 CHECK(array->length()->ToArrayIndex(&old_length)); | |
| 2133 | |
| 2134 if (old_length < length) { | |
| 2135 ElementsKind kind = array->GetElementsKind(); | |
| 2136 if (!IsFastHoleyElementsKind(kind)) { | |
| 2137 kind = GetHoleyElementsKind(kind); | |
| 2138 JSObject::TransitionElementsKind(array, kind); | |
| 2139 } | |
| 2140 } | |
| 2141 | |
| 2142 // Check whether the backing store should be shrunk. | |
| 2143 uint32_t capacity = backing_store->length(); | |
| 2144 if (length == 0) { | |
| 2145 array->initialize_elements(); | |
| 2146 } else if (length <= capacity) { | |
| 2147 if (array->HasFastSmiOrObjectElements()) { | |
| 2148 backing_store = JSObject::EnsureWritableFastElements(array); | |
| 2149 } | |
| 2150 if (2 * length <= capacity) { | |
| 2151 // If more than half the elements won't be used, trim the array. | |
| 2152 array->GetHeap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>( | |
| 2153 *backing_store, capacity - length); | |
| 2154 } else { | |
| 2155 // Otherwise, fill the unused tail with holes. | |
| 2156 for (uint32_t i = length; i < old_length; i++) { | |
| 2157 BackingStore::cast(*backing_store)->set_the_hole(i); | |
| 2158 } | |
| 2159 } | |
| 2160 } else { | |
| 2161 // Check whether the backing store should be expanded. | |
| 2162 capacity = Max(length, JSObject::NewElementsCapacity(capacity)); | |
| 2163 ElementsAccessorSubclass::GrowCapacityAndConvertImpl(array, capacity); | |
| 2164 } | |
| 2165 | |
| 2166 array->set_length(Smi::FromInt(length)); | |
| 2167 JSObject::ValidateElements(array); | |
| 2168 } | |
| 2169 } // namespace | 2197 } // namespace |
| 2170 | 2198 |
| 2171 | 2199 |
| 2172 void CheckArrayAbuse(Handle<JSObject> obj, const char* op, uint32_t index, | 2200 void CheckArrayAbuse(Handle<JSObject> obj, const char* op, uint32_t index, |
| 2173 bool allow_appending) { | 2201 bool allow_appending) { |
| 2174 DisallowHeapAllocation no_allocation; | 2202 DisallowHeapAllocation no_allocation; |
| 2175 Object* raw_length = NULL; | 2203 Object* raw_length = NULL; |
| 2176 const char* elements_type = "array"; | 2204 const char* elements_type = "array"; |
| 2177 if (obj->IsJSArray()) { | 2205 if (obj->IsJSArray()) { |
| 2178 JSArray* array = JSArray::cast(*obj); | 2206 JSArray* array = JSArray::cast(*obj); |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2318 #define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind]; | 2346 #define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind]; |
| 2319 ELEMENTS_LIST(ACCESSOR_DELETE) | 2347 ELEMENTS_LIST(ACCESSOR_DELETE) |
| 2320 #undef ACCESSOR_DELETE | 2348 #undef ACCESSOR_DELETE |
| 2321 elements_accessors_ = NULL; | 2349 elements_accessors_ = NULL; |
| 2322 } | 2350 } |
| 2323 | 2351 |
| 2324 | 2352 |
| 2325 ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL; | 2353 ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL; |
| 2326 } // namespace internal | 2354 } // namespace internal |
| 2327 } // namespace v8 | 2355 } // namespace v8 |
| OLD | NEW |