OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 475 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
486 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors(); | 486 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors(); |
487 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; | 487 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; |
488 } | 488 } |
489 set_map(Map::cast(new_map)); | 489 set_map(Map::cast(new_map)); |
490 } | 490 } |
491 JSGlobalPropertyCell* cell = | 491 JSGlobalPropertyCell* cell = |
492 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry)); | 492 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry)); |
493 cell->set_value(cell->heap()->the_hole_value()); | 493 cell->set_value(cell->heap()->the_hole_value()); |
494 dictionary->DetailsAtPut(entry, details.AsDeleted()); | 494 dictionary->DetailsAtPut(entry, details.AsDeleted()); |
495 } else { | 495 } else { |
496 return dictionary->DeleteProperty(entry, mode); | 496 Object* deleted = dictionary->DeleteProperty(entry, mode); |
| 497 if (deleted == GetHeap()->true_value()) { |
| 498 FixedArray* new_properties = NULL; |
| 499 MaybeObject* maybe_properties = dictionary->Shrink(name); |
| 500 if (!maybe_properties->To(&new_properties)) { |
| 501 return maybe_properties; |
| 502 } |
| 503 set_properties(new_properties); |
| 504 } |
| 505 return deleted; |
497 } | 506 } |
498 } | 507 } |
499 return GetHeap()->true_value(); | 508 return GetHeap()->true_value(); |
500 } | 509 } |
501 | 510 |
502 | 511 |
503 bool JSObject::IsDirty() { | 512 bool JSObject::IsDirty() { |
504 Object* cons_obj = map()->constructor(); | 513 Object* cons_obj = map()->constructor(); |
505 if (!cons_obj->IsJSFunction()) | 514 if (!cons_obj->IsJSFunction()) |
506 return true; | 515 return true; |
(...skipping 2441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2948 static_cast<uint32_t>(FixedArray::cast(elements())->length()); | 2957 static_cast<uint32_t>(FixedArray::cast(elements())->length()); |
2949 if (index < length) { | 2958 if (index < length) { |
2950 FixedArray::cast(elements())->set_the_hole(index); | 2959 FixedArray::cast(elements())->set_the_hole(index); |
2951 } | 2960 } |
2952 break; | 2961 break; |
2953 } | 2962 } |
2954 case DICTIONARY_ELEMENTS: { | 2963 case DICTIONARY_ELEMENTS: { |
2955 NumberDictionary* dictionary = element_dictionary(); | 2964 NumberDictionary* dictionary = element_dictionary(); |
2956 int entry = dictionary->FindEntry(index); | 2965 int entry = dictionary->FindEntry(index); |
2957 if (entry != NumberDictionary::kNotFound) { | 2966 if (entry != NumberDictionary::kNotFound) { |
2958 return dictionary->DeleteProperty(entry, mode); | 2967 Object* deleted = dictionary->DeleteProperty(entry, mode); |
| 2968 if (deleted == GetHeap()->true_value()) { |
| 2969 MaybeObject* maybe_elements = dictionary->Shrink(index); |
| 2970 FixedArray* new_elements = NULL; |
| 2971 if (!maybe_elements->To(&new_elements)) { |
| 2972 return maybe_elements; |
| 2973 } |
| 2974 set_elements(new_elements); |
| 2975 } |
| 2976 return deleted; |
2959 } | 2977 } |
2960 break; | 2978 break; |
2961 } | 2979 } |
2962 default: | 2980 default: |
2963 UNREACHABLE(); | 2981 UNREACHABLE(); |
2964 break; | 2982 break; |
2965 } | 2983 } |
2966 return GetHeap()->true_value(); | 2984 return GetHeap()->true_value(); |
2967 } | 2985 } |
2968 | 2986 |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3028 Isolate* isolate = GetIsolate(); | 3046 Isolate* isolate = GetIsolate(); |
3029 Heap* heap = isolate->heap(); | 3047 Heap* heap = isolate->heap(); |
3030 FixedArray* backing_store = FixedArray::cast(elements()); | 3048 FixedArray* backing_store = FixedArray::cast(elements()); |
3031 if (backing_store->map() == heap->non_strict_arguments_elements_map()) { | 3049 if (backing_store->map() == heap->non_strict_arguments_elements_map()) { |
3032 backing_store = FixedArray::cast(backing_store->get(1)); | 3050 backing_store = FixedArray::cast(backing_store->get(1)); |
3033 } | 3051 } |
3034 NumberDictionary* dictionary = NumberDictionary::cast(backing_store); | 3052 NumberDictionary* dictionary = NumberDictionary::cast(backing_store); |
3035 int entry = dictionary->FindEntry(index); | 3053 int entry = dictionary->FindEntry(index); |
3036 if (entry != NumberDictionary::kNotFound) { | 3054 if (entry != NumberDictionary::kNotFound) { |
3037 Object* result = dictionary->DeleteProperty(entry, mode); | 3055 Object* result = dictionary->DeleteProperty(entry, mode); |
| 3056 if (result == heap->true_value()) { |
| 3057 MaybeObject* maybe_elements = dictionary->Shrink(index); |
| 3058 FixedArray* new_elements = NULL; |
| 3059 if (!maybe_elements->To(&new_elements)) { |
| 3060 return maybe_elements; |
| 3061 } |
| 3062 set_elements(new_elements); |
| 3063 } |
3038 if (mode == STRICT_DELETION && result == heap->false_value()) { | 3064 if (mode == STRICT_DELETION && result == heap->false_value()) { |
3039 // In strict mode, attempting to delete a non-configurable property | 3065 // In strict mode, attempting to delete a non-configurable property |
3040 // throws an exception. | 3066 // throws an exception. |
3041 HandleScope scope(isolate); | 3067 HandleScope scope(isolate); |
3042 Handle<Object> name = isolate->factory()->NewNumberFromUint(index); | 3068 Handle<Object> name = isolate->factory()->NewNumberFromUint(index); |
3043 Handle<Object> args[2] = { name, Handle<Object>(this) }; | 3069 Handle<Object> args[2] = { name, Handle<Object>(this) }; |
3044 Handle<Object> error = | 3070 Handle<Object> error = |
3045 isolate->factory()->NewTypeError("strict_delete_property", | 3071 isolate->factory()->NewTypeError("strict_delete_property", |
3046 HandleVector(args, 2)); | 3072 HandleVector(args, 2)); |
3047 return isolate->Throw(*error); | 3073 return isolate->Throw(*error); |
(...skipping 5175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8223 if (check_prototype && | 8249 if (check_prototype && |
8224 (index >= length || backing_store->get(index)->IsTheHole())) { | 8250 (index >= length || backing_store->get(index)->IsTheHole())) { |
8225 bool found; | 8251 bool found; |
8226 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index, | 8252 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index, |
8227 value, | 8253 value, |
8228 &found, | 8254 &found, |
8229 strict_mode); | 8255 strict_mode); |
8230 if (found) return result; | 8256 if (found) return result; |
8231 } | 8257 } |
8232 | 8258 |
8233 // Check whether there is extra space in fixed array.. | 8259 // Check whether there is extra space in fixed array. |
8234 if (index < length) { | 8260 if (index < length) { |
8235 backing_store->set(index, value); | 8261 backing_store->set(index, value); |
8236 if (IsJSArray()) { | 8262 if (IsJSArray()) { |
8237 // Update the length of the array if needed. | 8263 // Update the length of the array if needed. |
8238 uint32_t array_length = 0; | 8264 uint32_t array_length = 0; |
8239 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length)); | 8265 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length)); |
8240 if (index >= array_length) { | 8266 if (index >= array_length) { |
8241 JSArray::cast(this)->set_length(Smi::FromInt(index + 1)); | 8267 JSArray::cast(this)->set_length(Smi::FromInt(index + 1)); |
8242 } | 8268 } |
8243 } | 8269 } |
(...skipping 1703 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9947 return entry; | 9973 return entry; |
9948 } | 9974 } |
9949 ASSERT(element->IsNull() || !String::cast(element)->Equals(key)); | 9975 ASSERT(element->IsNull() || !String::cast(element)->Equals(key)); |
9950 entry = NextProbe(entry, count++, capacity); | 9976 entry = NextProbe(entry, count++, capacity); |
9951 } | 9977 } |
9952 return kNotFound; | 9978 return kNotFound; |
9953 } | 9979 } |
9954 | 9980 |
9955 | 9981 |
9956 template<typename Shape, typename Key> | 9982 template<typename Shape, typename Key> |
| 9983 MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) { |
| 9984 ASSERT(NumberOfElements() < new_table->Capacity()); |
| 9985 |
| 9986 AssertNoAllocation no_gc; |
| 9987 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc); |
| 9988 |
| 9989 // Copy prefix to new array. |
| 9990 for (int i = kPrefixStartIndex; |
| 9991 i < kPrefixStartIndex + Shape::kPrefixSize; |
| 9992 i++) { |
| 9993 new_table->set(i, get(i), mode); |
| 9994 } |
| 9995 |
| 9996 // Rehash the elements. |
| 9997 int capacity = Capacity(); |
| 9998 for (int i = 0; i < capacity; i++) { |
| 9999 uint32_t from_index = EntryToIndex(i); |
| 10000 Object* k = get(from_index); |
| 10001 if (IsKey(k)) { |
| 10002 uint32_t hash = Shape::HashForObject(key, k); |
| 10003 uint32_t insertion_index = |
| 10004 EntryToIndex(new_table->FindInsertionEntry(hash)); |
| 10005 for (int j = 0; j < Shape::kEntrySize; j++) { |
| 10006 new_table->set(insertion_index + j, get(from_index + j), mode); |
| 10007 } |
| 10008 } |
| 10009 } |
| 10010 new_table->SetNumberOfElements(NumberOfElements()); |
| 10011 new_table->SetNumberOfDeletedElements(0); |
| 10012 return new_table; |
| 10013 } |
| 10014 |
| 10015 |
| 10016 template<typename Shape, typename Key> |
9957 MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) { | 10017 MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) { |
9958 int capacity = Capacity(); | 10018 int capacity = Capacity(); |
9959 int nof = NumberOfElements() + n; | 10019 int nof = NumberOfElements() + n; |
9960 int nod = NumberOfDeletedElements(); | 10020 int nod = NumberOfDeletedElements(); |
9961 // Return if: | 10021 // Return if: |
9962 // 50% is still free after adding n elements and | 10022 // 50% is still free after adding n elements and |
9963 // at most 50% of the free elements are deleted elements. | 10023 // at most 50% of the free elements are deleted elements. |
9964 if (nod <= (capacity - nof) >> 1) { | 10024 if (nod <= (capacity - nof) >> 1) { |
9965 int needed_free = nof >> 1; | 10025 int needed_free = nof >> 1; |
9966 if (nof + needed_free <= capacity) return this; | 10026 if (nof + needed_free <= capacity) return this; |
9967 } | 10027 } |
9968 | 10028 |
9969 const int kMinCapacityForPretenure = 256; | 10029 const int kMinCapacityForPretenure = 256; |
9970 bool pretenure = | 10030 bool pretenure = |
9971 (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this); | 10031 (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this); |
9972 Object* obj; | 10032 Object* obj; |
9973 { MaybeObject* maybe_obj = | 10033 { MaybeObject* maybe_obj = |
9974 Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED); | 10034 Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED); |
9975 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 10035 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
9976 } | 10036 } |
9977 | 10037 |
9978 AssertNoAllocation no_gc; | 10038 return Rehash(HashTable::cast(obj), key); |
9979 HashTable* table = HashTable::cast(obj); | |
9980 WriteBarrierMode mode = table->GetWriteBarrierMode(no_gc); | |
9981 | |
9982 // Copy prefix to new array. | |
9983 for (int i = kPrefixStartIndex; | |
9984 i < kPrefixStartIndex + Shape::kPrefixSize; | |
9985 i++) { | |
9986 table->set(i, get(i), mode); | |
9987 } | |
9988 // Rehash the elements. | |
9989 for (int i = 0; i < capacity; i++) { | |
9990 uint32_t from_index = EntryToIndex(i); | |
9991 Object* k = get(from_index); | |
9992 if (IsKey(k)) { | |
9993 uint32_t hash = Shape::HashForObject(key, k); | |
9994 uint32_t insertion_index = | |
9995 EntryToIndex(table->FindInsertionEntry(hash)); | |
9996 for (int j = 0; j < Shape::kEntrySize; j++) { | |
9997 table->set(insertion_index + j, get(from_index + j), mode); | |
9998 } | |
9999 } | |
10000 } | |
10001 table->SetNumberOfElements(NumberOfElements()); | |
10002 table->SetNumberOfDeletedElements(0); | |
10003 return table; | |
10004 } | 10039 } |
10005 | 10040 |
10006 | 10041 |
| 10042 template<typename Shape, typename Key> |
| 10043 MaybeObject* HashTable<Shape, Key>::Shrink(Key key) { |
| 10044 int capacity = Capacity(); |
| 10045 int nof = NumberOfElements(); |
| 10046 |
| 10047 // Shrink to fit the number of elements if only a quarter of the |
| 10048 // capacity is filled with elements. |
| 10049 if (nof > (capacity >> 2)) return this; |
| 10050 // Allocate a new dictionary with room for at least the current |
| 10051 // number of elements. The allocation method will make sure that |
| 10052 // there is extra room in the dictionary for additions. Don't go |
| 10053 // lower than room for 16 elements. |
| 10054 int at_least_room_for = nof; |
| 10055 if (at_least_room_for < 16) return this; |
| 10056 |
| 10057 const int kMinCapacityForPretenure = 256; |
| 10058 bool pretenure = |
| 10059 (at_least_room_for > kMinCapacityForPretenure) && |
| 10060 !GetHeap()->InNewSpace(this); |
| 10061 Object* obj; |
| 10062 { MaybeObject* maybe_obj = |
| 10063 Allocate(at_least_room_for, pretenure ? TENURED : NOT_TENURED); |
| 10064 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 10065 } |
| 10066 |
| 10067 return Rehash(HashTable::cast(obj), key); |
| 10068 } |
| 10069 |
| 10070 |
10007 template<typename Shape, typename Key> | 10071 template<typename Shape, typename Key> |
10008 uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) { | 10072 uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) { |
10009 uint32_t capacity = Capacity(); | 10073 uint32_t capacity = Capacity(); |
10010 uint32_t entry = FirstProbe(hash, capacity); | 10074 uint32_t entry = FirstProbe(hash, capacity); |
10011 uint32_t count = 1; | 10075 uint32_t count = 1; |
10012 // EnsureCapacity will guarantee the hash table is never full. | 10076 // EnsureCapacity will guarantee the hash table is never full. |
10013 while (true) { | 10077 while (true) { |
10014 Object* element = KeyAt(entry); | 10078 Object* element = KeyAt(entry); |
10015 if (element->IsUndefined() || element->IsNull()) break; | 10079 if (element->IsUndefined() || element->IsNull()) break; |
10016 entry = NextProbe(entry, count++, capacity); | 10080 entry = NextProbe(entry, count++, capacity); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10048 | 10112 |
10049 template void Dictionary<NumberDictionaryShape, uint32_t>::CopyKeysTo( | 10113 template void Dictionary<NumberDictionaryShape, uint32_t>::CopyKeysTo( |
10050 FixedArray*, PropertyAttributes); | 10114 FixedArray*, PropertyAttributes); |
10051 | 10115 |
10052 template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty( | 10116 template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty( |
10053 int, JSObject::DeleteMode); | 10117 int, JSObject::DeleteMode); |
10054 | 10118 |
10055 template Object* Dictionary<NumberDictionaryShape, uint32_t>::DeleteProperty( | 10119 template Object* Dictionary<NumberDictionaryShape, uint32_t>::DeleteProperty( |
10056 int, JSObject::DeleteMode); | 10120 int, JSObject::DeleteMode); |
10057 | 10121 |
| 10122 template MaybeObject* Dictionary<StringDictionaryShape, String*>::Shrink( |
| 10123 String*); |
| 10124 |
| 10125 template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Shrink( |
| 10126 uint32_t); |
| 10127 |
10058 template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo( | 10128 template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo( |
10059 FixedArray*); | 10129 FixedArray*); |
10060 | 10130 |
10061 template int | 10131 template int |
10062 Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes( | 10132 Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes( |
10063 PropertyAttributes); | 10133 PropertyAttributes); |
10064 | 10134 |
10065 template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add( | 10135 template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add( |
10066 String*, Object*, PropertyDetails); | 10136 String*, Object*, PropertyDetails); |
10067 | 10137 |
(...skipping 879 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10947 if (details.IsDontDelete() && mode != JSObject::FORCE_DELETION) { | 11017 if (details.IsDontDelete() && mode != JSObject::FORCE_DELETION) { |
10948 return heap->false_value(); | 11018 return heap->false_value(); |
10949 } | 11019 } |
10950 SetEntry(entry, heap->null_value(), heap->null_value()); | 11020 SetEntry(entry, heap->null_value(), heap->null_value()); |
10951 HashTable<Shape, Key>::ElementRemoved(); | 11021 HashTable<Shape, Key>::ElementRemoved(); |
10952 return heap->true_value(); | 11022 return heap->true_value(); |
10953 } | 11023 } |
10954 | 11024 |
10955 | 11025 |
10956 template<typename Shape, typename Key> | 11026 template<typename Shape, typename Key> |
| 11027 MaybeObject* Dictionary<Shape, Key>::Shrink(Key key) { |
| 11028 return HashTable<Shape, Key>::Shrink(key); |
| 11029 } |
| 11030 |
| 11031 |
| 11032 template<typename Shape, typename Key> |
10957 MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) { | 11033 MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) { |
10958 int entry = this->FindEntry(key); | 11034 int entry = this->FindEntry(key); |
10959 | 11035 |
10960 // If the entry is present set the value; | 11036 // If the entry is present set the value; |
10961 if (entry != Dictionary<Shape, Key>::kNotFound) { | 11037 if (entry != Dictionary<Shape, Key>::kNotFound) { |
10962 ValueAtPut(entry, value); | 11038 ValueAtPut(entry, value); |
10963 return this; | 11039 return this; |
10964 } | 11040 } |
10965 | 11041 |
10966 // Check whether the dictionary should be extended. | 11042 // Check whether the dictionary should be extended. |
(...skipping 594 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11561 if (break_point_objects()->IsUndefined()) return 0; | 11637 if (break_point_objects()->IsUndefined()) return 0; |
11562 // Single beak point. | 11638 // Single beak point. |
11563 if (!break_point_objects()->IsFixedArray()) return 1; | 11639 if (!break_point_objects()->IsFixedArray()) return 1; |
11564 // Multiple break points. | 11640 // Multiple break points. |
11565 return FixedArray::cast(break_point_objects())->length(); | 11641 return FixedArray::cast(break_point_objects())->length(); |
11566 } | 11642 } |
11567 #endif | 11643 #endif |
11568 | 11644 |
11569 | 11645 |
11570 } } // namespace v8::internal | 11646 } } // namespace v8::internal |
OLD | NEW |