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 713 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
724 JSObject::PrintElementsTransition(stdout, object, from_kind, old_elements, | 724 JSObject::PrintElementsTransition(stdout, object, from_kind, old_elements, |
725 to_kind, elements); | 725 to_kind, elements); |
726 } | 726 } |
727 } | 727 } |
728 | 728 |
729 virtual void GrowCapacityAndConvert(Handle<JSObject> object, | 729 virtual void GrowCapacityAndConvert(Handle<JSObject> object, |
730 uint32_t capacity) final { | 730 uint32_t capacity) final { |
731 ElementsAccessorSubclass::GrowCapacityAndConvertImpl(object, capacity); | 731 ElementsAccessorSubclass::GrowCapacityAndConvertImpl(object, capacity); |
732 } | 732 } |
733 | 733 |
734 virtual void Delete(Handle<JSObject> obj, uint32_t key, | 734 virtual void Delete(Handle<JSObject> obj, uint32_t index) override = 0; |
735 LanguageMode language_mode) override = 0; | |
736 | 735 |
737 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start, | 736 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start, |
738 FixedArrayBase* to, ElementsKind from_kind, | 737 FixedArrayBase* to, ElementsKind from_kind, |
739 uint32_t to_start, int packed_size, | 738 uint32_t to_start, int packed_size, |
740 int copy_size) { | 739 int copy_size) { |
741 UNREACHABLE(); | 740 UNREACHABLE(); |
742 } | 741 } |
743 | 742 |
744 virtual void CopyElements(Handle<FixedArrayBase> from, uint32_t from_start, | 743 virtual void CopyElements(Handle<FixedArrayBase> from, uint32_t from_start, |
745 ElementsKind from_kind, Handle<FixedArrayBase> to, | 744 ElementsKind from_kind, Handle<FixedArrayBase> to, |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
982 } | 981 } |
983 | 982 |
984 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start, | 983 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start, |
985 FixedArrayBase* to, ElementsKind from_kind, | 984 FixedArrayBase* to, ElementsKind from_kind, |
986 uint32_t to_start, int packed_size, | 985 uint32_t to_start, int packed_size, |
987 int copy_size) { | 986 int copy_size) { |
988 UNREACHABLE(); | 987 UNREACHABLE(); |
989 } | 988 } |
990 | 989 |
991 | 990 |
992 static void DeleteCommon(Handle<JSObject> obj, uint32_t key, | 991 static void DeleteImpl(Handle<JSObject> obj, uint32_t index, |
993 LanguageMode language_mode) { | 992 Handle<FixedArrayBase> store) { |
994 Isolate* isolate = obj->GetIsolate(); | 993 Handle<SeededNumberDictionary> dict = |
995 Handle<FixedArray> backing_store(FixedArray::cast(obj->elements()), | 994 Handle<SeededNumberDictionary>::cast(store); |
996 isolate); | 995 // TODO(verwaest): Remove reliance on key in Shrink. |
997 bool is_arguments = obj->HasSloppyArgumentsElements(); | 996 uint32_t key = GetKeyForIndexImpl(*dict, index); |
998 if (is_arguments) { | 997 Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, index); |
999 backing_store = handle(FixedArray::cast(backing_store->get(1)), isolate); | 998 USE(result); |
1000 } | 999 DCHECK(result->IsTrue()); |
1001 Handle<SeededNumberDictionary> dictionary = | 1000 Handle<FixedArray> new_elements = SeededNumberDictionary::Shrink(dict, key); |
1002 Handle<SeededNumberDictionary>::cast(backing_store); | |
1003 int entry = dictionary->FindEntry(key); | |
1004 if (entry != SeededNumberDictionary::kNotFound) { | |
1005 Handle<Object> result = | |
1006 SeededNumberDictionary::DeleteProperty(dictionary, entry); | |
1007 USE(result); | |
1008 DCHECK(result->IsTrue()); | |
1009 Handle<FixedArray> new_elements = | |
1010 SeededNumberDictionary::Shrink(dictionary, key); | |
1011 | 1001 |
1012 if (is_arguments) { | 1002 if (obj->elements() != *store) { |
Igor Sheludko
2015/07/03 15:09:01
It looks like you can do the same trick to unify A
| |
1013 FixedArray::cast(obj->elements())->set(1, *new_elements); | 1003 DCHECK(obj->HasSlowArgumentsElements()); |
1014 } else { | 1004 FixedArray::cast(obj->elements())->set(1, *new_elements); |
1015 obj->set_elements(*new_elements); | 1005 } else { |
1016 } | 1006 obj->set_elements(*new_elements); |
1017 } | 1007 } |
1018 } | 1008 } |
1019 | 1009 |
1020 virtual void Delete(Handle<JSObject> obj, uint32_t key, | 1010 virtual void Delete(Handle<JSObject> obj, uint32_t index) final { |
Igor Sheludko
2015/07/03 15:09:01
Could you please move this virtual Delete() implem
| |
1021 LanguageMode language_mode) final { | 1011 DeleteImpl(obj, index, handle(obj->elements())); |
1022 DeleteCommon(obj, key, language_mode); | |
1023 } | 1012 } |
1024 | 1013 |
1025 static Handle<Object> GetImpl(Handle<JSObject> obj, uint32_t key, | 1014 static Handle<Object> GetImpl(Handle<JSObject> obj, uint32_t key, |
1026 Handle<FixedArrayBase> store) { | 1015 Handle<FixedArrayBase> store) { |
1027 Handle<SeededNumberDictionary> backing_store = | 1016 Handle<SeededNumberDictionary> backing_store = |
1028 Handle<SeededNumberDictionary>::cast(store); | 1017 Handle<SeededNumberDictionary>::cast(store); |
1029 Isolate* isolate = backing_store->GetIsolate(); | 1018 Isolate* isolate = backing_store->GetIsolate(); |
1030 int entry = backing_store->FindEntry(key); | 1019 int entry = backing_store->FindEntry(key); |
1031 if (entry != SeededNumberDictionary::kNotFound) { | 1020 if (entry != SeededNumberDictionary::kNotFound) { |
1032 return handle(backing_store->ValueAt(entry), isolate); | 1021 return handle(backing_store->ValueAt(entry), isolate); |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1120 typename KindTraits> | 1109 typename KindTraits> |
1121 class FastElementsAccessor | 1110 class FastElementsAccessor |
1122 : public ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits> { | 1111 : public ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits> { |
1123 public: | 1112 public: |
1124 explicit FastElementsAccessor(const char* name) | 1113 explicit FastElementsAccessor(const char* name) |
1125 : ElementsAccessorBase<FastElementsAccessorSubclass, | 1114 : ElementsAccessorBase<FastElementsAccessorSubclass, |
1126 KindTraits>(name) {} | 1115 KindTraits>(name) {} |
1127 | 1116 |
1128 typedef typename KindTraits::BackingStore BackingStore; | 1117 typedef typename KindTraits::BackingStore BackingStore; |
1129 | 1118 |
1130 static void DeleteCommon(Handle<JSObject> obj, uint32_t key, | 1119 static void DeleteImpl(Handle<JSObject> obj, uint32_t index, |
1131 LanguageMode language_mode) { | 1120 Handle<FixedArrayBase> store) { |
1132 DCHECK(obj->HasFastSmiOrObjectElements() || | 1121 DCHECK(obj->HasFastSmiOrObjectElements() || |
1133 obj->HasFastDoubleElements() || | 1122 obj->HasFastDoubleElements() || |
1134 obj->HasFastArgumentsElements()); | 1123 obj->HasFastArgumentsElements()); |
1135 Isolate* isolate = obj->GetIsolate(); | 1124 Handle<BackingStore> backing_store = Handle<BackingStore>::cast(store); |
1136 Heap* heap = obj->GetHeap(); | 1125 backing_store->set_the_hole(index); |
1137 Handle<FixedArrayBase> elements(obj->elements()); | |
1138 if (*elements == heap->empty_fixed_array()) return; | |
1139 | 1126 |
1140 Handle<BackingStore> backing_store = Handle<BackingStore>::cast(elements); | 1127 // TODO(verwaest): Move this out of elements.cc. |
1141 bool is_sloppy_arguments_elements_map = | 1128 // If an old space backing store is larger than a certain size and |
1142 backing_store->map() == heap->sloppy_arguments_elements_map(); | 1129 // has too few used values, normalize it. |
1143 if (is_sloppy_arguments_elements_map) { | 1130 // To avoid doing the check on every delete we require at least |
1144 backing_store = handle( | 1131 // one adjacent hole to the value being deleted. |
1145 BackingStore::cast(Handle<FixedArray>::cast(backing_store)->get(1)), | 1132 const int kMinLengthForSparsenessCheck = 64; |
1146 isolate); | 1133 if (backing_store->length() < kMinLengthForSparsenessCheck) return; |
1134 if (backing_store->GetHeap()->InNewSpace(*backing_store)) return; | |
1135 uint32_t length = 0; | |
1136 if (obj->IsJSArray()) { | |
1137 JSArray::cast(*obj)->length()->ToArrayLength(&length); | |
1138 } else { | |
1139 length = static_cast<uint32_t>(store->length()); | |
1147 } | 1140 } |
1148 uint32_t length = static_cast<uint32_t>( | 1141 if ((index > 0 && backing_store->is_the_hole(index - 1)) || |
1149 obj->IsJSArray() | 1142 (index + 1 < length && backing_store->is_the_hole(index + 1))) { |
1150 ? Smi::cast(Handle<JSArray>::cast(obj)->length())->value() | 1143 int num_used = 0; |
1151 : backing_store->length()); | 1144 for (int i = 0; i < backing_store->length(); ++i) { |
1152 if (key < length) { | 1145 if (!backing_store->is_the_hole(i)) ++num_used; |
1153 if (!is_sloppy_arguments_elements_map) { | 1146 // Bail out early if more than 1/4 is used. |
1154 ElementsKind kind = KindTraits::Kind; | 1147 if (4 * num_used > backing_store->length()) break; |
1155 if (IsFastPackedElementsKind(kind)) { | |
1156 JSObject::TransitionElementsKind(obj, GetHoleyElementsKind(kind)); | |
1157 } | |
1158 if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) { | |
1159 Handle<Object> writable = JSObject::EnsureWritableFastElements(obj); | |
1160 backing_store = Handle<BackingStore>::cast(writable); | |
1161 } | |
1162 } | 1148 } |
1163 backing_store->set_the_hole(key); | 1149 if (4 * num_used <= backing_store->length()) { |
1164 // If an old space backing store is larger than a certain size and | 1150 JSObject::NormalizeElements(obj); |
1165 // has too few used values, normalize it. | |
1166 // To avoid doing the check on every delete we require at least | |
1167 // one adjacent hole to the value being deleted. | |
1168 const int kMinLengthForSparsenessCheck = 64; | |
1169 if (backing_store->length() >= kMinLengthForSparsenessCheck && | |
1170 !heap->InNewSpace(*backing_store) && | |
1171 ((key > 0 && backing_store->is_the_hole(key - 1)) || | |
1172 (key + 1 < length && backing_store->is_the_hole(key + 1)))) { | |
1173 int num_used = 0; | |
1174 for (int i = 0; i < backing_store->length(); ++i) { | |
1175 if (!backing_store->is_the_hole(i)) ++num_used; | |
1176 // Bail out early if more than 1/4 is used. | |
1177 if (4 * num_used > backing_store->length()) break; | |
1178 } | |
1179 if (4 * num_used <= backing_store->length()) { | |
1180 JSObject::NormalizeElements(obj); | |
1181 } | |
1182 } | 1151 } |
1183 } | 1152 } |
1184 } | 1153 } |
1185 | 1154 |
1186 static void ReconfigureImpl(Handle<JSObject> object, | 1155 static void ReconfigureImpl(Handle<JSObject> object, |
1187 Handle<FixedArrayBase> store, uint32_t index, | 1156 Handle<FixedArrayBase> store, uint32_t index, |
1188 Handle<Object> value, | 1157 Handle<Object> value, |
1189 PropertyAttributes attributes) { | 1158 PropertyAttributes attributes) { |
1190 Handle<SeededNumberDictionary> dictionary = | 1159 Handle<SeededNumberDictionary> dictionary = |
1191 JSObject::NormalizeElements(object); | 1160 JSObject::NormalizeElements(object); |
(...skipping 20 matching lines...) Expand all Loading... | |
1212 JSObject::TransitionElementsKind(object, to_kind); | 1181 JSObject::TransitionElementsKind(object, to_kind); |
1213 } | 1182 } |
1214 if (IsFastSmiOrObjectElementsKind(from_kind)) { | 1183 if (IsFastSmiOrObjectElementsKind(from_kind)) { |
1215 DCHECK(IsFastSmiOrObjectElementsKind(to_kind)); | 1184 DCHECK(IsFastSmiOrObjectElementsKind(to_kind)); |
1216 JSObject::EnsureWritableFastElements(object); | 1185 JSObject::EnsureWritableFastElements(object); |
1217 } | 1186 } |
1218 } | 1187 } |
1219 FastElementsAccessorSubclass::SetImpl(object->elements(), index, *value); | 1188 FastElementsAccessorSubclass::SetImpl(object->elements(), index, *value); |
1220 } | 1189 } |
1221 | 1190 |
1222 virtual void Delete(Handle<JSObject> obj, uint32_t key, | 1191 virtual void Delete(Handle<JSObject> obj, uint32_t index) final { |
1223 LanguageMode language_mode) final { | 1192 ElementsKind kind = KindTraits::Kind; |
1224 DeleteCommon(obj, key, language_mode); | 1193 if (IsFastPackedElementsKind(kind)) { |
1194 JSObject::TransitionElementsKind(obj, GetHoleyElementsKind(kind)); | |
1195 } | |
1196 if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) { | |
1197 JSObject::EnsureWritableFastElements(obj); | |
1198 } | |
1199 DeleteImpl(obj, index, handle(obj->elements())); | |
1225 } | 1200 } |
1226 | 1201 |
1227 static bool HasIndexImpl(FixedArrayBase* backing_store, uint32_t index) { | 1202 static bool HasIndexImpl(FixedArrayBase* backing_store, uint32_t index) { |
1228 return !BackingStore::cast(backing_store)->is_the_hole(index); | 1203 return !BackingStore::cast(backing_store)->is_the_hole(index); |
1229 } | 1204 } |
1230 | 1205 |
1231 static void ValidateContents(Handle<JSObject> holder, int length) { | 1206 static void ValidateContents(Handle<JSObject> holder, int length) { |
1232 #if DEBUG | 1207 #if DEBUG |
1233 Isolate* isolate = holder->GetIsolate(); | 1208 Isolate* isolate = holder->GetIsolate(); |
1234 HandleScope scope(isolate); | 1209 HandleScope scope(isolate); |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1455 uint32_t index) { | 1430 uint32_t index) { |
1456 return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell); | 1431 return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell); |
1457 } | 1432 } |
1458 | 1433 |
1459 static void SetLengthImpl(Handle<JSArray> array, uint32_t length, | 1434 static void SetLengthImpl(Handle<JSArray> array, uint32_t length, |
1460 Handle<FixedArrayBase> backing_store) { | 1435 Handle<FixedArrayBase> backing_store) { |
1461 // External arrays do not support changing their length. | 1436 // External arrays do not support changing their length. |
1462 UNREACHABLE(); | 1437 UNREACHABLE(); |
1463 } | 1438 } |
1464 | 1439 |
1465 virtual void Delete(Handle<JSObject> obj, uint32_t key, | 1440 virtual void Delete(Handle<JSObject> obj, uint32_t index) final { |
1466 LanguageMode language_mode) final { | 1441 UNREACHABLE(); |
1467 // External arrays always ignore deletes. | |
1468 } | 1442 } |
1469 | 1443 |
1470 static uint32_t GetIndexForKeyImpl(JSObject* holder, | 1444 static uint32_t GetIndexForKeyImpl(JSObject* holder, |
1471 FixedArrayBase* backing_store, | 1445 FixedArrayBase* backing_store, |
1472 uint32_t key) { | 1446 uint32_t key) { |
1473 return key < AccessorClass::GetCapacityImpl(holder, backing_store) | 1447 return key < AccessorClass::GetCapacityImpl(holder, backing_store) |
1474 ? key | 1448 ? key |
1475 : kMaxUInt32; | 1449 : kMaxUInt32; |
1476 } | 1450 } |
1477 | 1451 |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1533 Context* context = Context::cast(parameter_map->get(0)); | 1507 Context* context = Context::cast(parameter_map->get(0)); |
1534 int context_index = entry->aliased_context_slot(); | 1508 int context_index = entry->aliased_context_slot(); |
1535 DCHECK(!context->get(context_index)->IsTheHole()); | 1509 DCHECK(!context->get(context_index)->IsTheHole()); |
1536 return handle(context->get(context_index), isolate); | 1510 return handle(context->get(context_index), isolate); |
1537 } else { | 1511 } else { |
1538 return result; | 1512 return result; |
1539 } | 1513 } |
1540 } | 1514 } |
1541 } | 1515 } |
1542 | 1516 |
1543 virtual void Delete(Handle<JSObject> obj, uint32_t key, | 1517 virtual void Delete(Handle<JSObject> obj, uint32_t index) final { |
1544 LanguageMode language_mode) final { | |
1545 FixedArray* parameter_map = FixedArray::cast(obj->elements()); | 1518 FixedArray* parameter_map = FixedArray::cast(obj->elements()); |
1546 if (!GetParameterMapArg(parameter_map, key)->IsTheHole()) { | 1519 uint32_t length = static_cast<uint32_t>(parameter_map->length()) - 2; |
1520 if (index < length) { | |
1547 // TODO(kmillikin): We could check if this was the last aliased | 1521 // TODO(kmillikin): We could check if this was the last aliased |
1548 // parameter, and revert to normal elements in that case. That | 1522 // parameter, and revert to normal elements in that case. That |
1549 // would enable GC of the context. | 1523 // would enable GC of the context. |
1550 parameter_map->set_the_hole(key + 2); | 1524 parameter_map->set_the_hole(index + 2); |
1551 } else { | 1525 } else { |
1552 ArgumentsAccessor::DeleteCommon(obj, key, language_mode); | 1526 Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1))); |
1527 ArgumentsAccessor::DeleteImpl(obj, index - length, arguments); | |
1553 } | 1528 } |
1554 } | 1529 } |
1555 | 1530 |
1556 static void GrowCapacityAndConvertImpl(Handle<JSObject> object, | 1531 static void GrowCapacityAndConvertImpl(Handle<JSObject> object, |
1557 uint32_t capacity) { | 1532 uint32_t capacity) { |
1558 UNREACHABLE(); | 1533 UNREACHABLE(); |
1559 } | 1534 } |
1560 | 1535 |
1561 static void SetImpl(FixedArrayBase* store, uint32_t key, Object* value) { | 1536 static void SetImpl(FixedArrayBase* store, uint32_t key, Object* value) { |
1562 FixedArray* parameter_map = FixedArray::cast(store); | 1537 FixedArray* parameter_map = FixedArray::cast(store); |
(...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1951 break; | 1926 break; |
1952 } | 1927 } |
1953 | 1928 |
1954 array->set_elements(*elms); | 1929 array->set_elements(*elms); |
1955 array->set_length(Smi::FromInt(number_of_elements)); | 1930 array->set_length(Smi::FromInt(number_of_elements)); |
1956 return array; | 1931 return array; |
1957 } | 1932 } |
1958 | 1933 |
1959 } // namespace internal | 1934 } // namespace internal |
1960 } // namespace v8 | 1935 } // namespace v8 |
OLD | NEW |