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 2878 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2889 } | 2889 } |
2890 if (array->IsDictionary()) return array; | 2890 if (array->IsDictionary()) return array; |
2891 | 2891 |
2892 ASSERT(HasFastElements() || | 2892 ASSERT(HasFastElements() || |
2893 HasFastDoubleElements() || | 2893 HasFastDoubleElements() || |
2894 HasFastArgumentsElements()); | 2894 HasFastArgumentsElements()); |
2895 // Compute the effective length and allocate a new backing store. | 2895 // Compute the effective length and allocate a new backing store. |
2896 int length = IsJSArray() | 2896 int length = IsJSArray() |
2897 ? Smi::cast(JSArray::cast(this)->length())->value() | 2897 ? Smi::cast(JSArray::cast(this)->length())->value() |
2898 : array->length(); | 2898 : array->length(); |
| 2899 int old_capacity = 0; |
| 2900 int used_elements = 0; |
| 2901 GetElementsCapacityAndUsage(&old_capacity, &used_elements); |
2899 NumberDictionary* dictionary = NULL; | 2902 NumberDictionary* dictionary = NULL; |
2900 { Object* object; | 2903 { Object* object; |
2901 MaybeObject* maybe = NumberDictionary::Allocate(length); | 2904 MaybeObject* maybe = NumberDictionary::Allocate(used_elements); |
2902 if (!maybe->ToObject(&object)) return maybe; | 2905 if (!maybe->ToObject(&object)) return maybe; |
2903 dictionary = NumberDictionary::cast(object); | 2906 dictionary = NumberDictionary::cast(object); |
2904 } | 2907 } |
2905 | 2908 |
2906 // Copy the elements to the new backing store. | 2909 // Copy the elements to the new backing store. |
2907 bool has_double_elements = array->IsFixedDoubleArray(); | 2910 bool has_double_elements = array->IsFixedDoubleArray(); |
2908 for (int i = 0; i < length; i++) { | 2911 for (int i = 0; i < length; i++) { |
2909 Object* value = NULL; | 2912 Object* value = NULL; |
2910 if (has_double_elements) { | 2913 if (has_double_elements) { |
2911 FixedDoubleArray* double_array = FixedDoubleArray::cast(array); | 2914 FixedDoubleArray* double_array = FixedDoubleArray::cast(array); |
(...skipping 5696 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8608 } | 8611 } |
8609 | 8612 |
8610 // Attempt to put this object back in fast case. | 8613 // Attempt to put this object back in fast case. |
8611 if (ShouldConvertToFastElements()) { | 8614 if (ShouldConvertToFastElements()) { |
8612 uint32_t new_length = 0; | 8615 uint32_t new_length = 0; |
8613 if (IsJSArray()) { | 8616 if (IsJSArray()) { |
8614 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length)); | 8617 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length)); |
8615 } else { | 8618 } else { |
8616 new_length = dictionary->max_number_key() + 1; | 8619 new_length = dictionary->max_number_key() + 1; |
8617 } | 8620 } |
8618 MaybeObject* result = ShouldConvertToFastDoubleElements() | 8621 MaybeObject* result = CanConvertToFastDoubleElements() |
8619 ? SetFastDoubleElementsCapacityAndLength(new_length, new_length) | 8622 ? SetFastDoubleElementsCapacityAndLength(new_length, new_length) |
8620 : SetFastElementsCapacityAndLength(new_length, new_length); | 8623 : SetFastElementsCapacityAndLength(new_length, new_length); |
8621 if (result->IsFailure()) return result; | 8624 if (result->IsFailure()) return result; |
8622 #ifdef DEBUG | 8625 #ifdef DEBUG |
8623 if (FLAG_trace_normalization) { | 8626 if (FLAG_trace_normalization) { |
8624 PrintF("Object elements are fast case again:\n"); | 8627 PrintF("Object elements are fast case again:\n"); |
8625 Print(); | 8628 Print(); |
8626 } | 8629 } |
8627 #endif | 8630 #endif |
8628 } | 8631 } |
(...skipping 521 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9150 case NON_STRICT_ARGUMENTS_ELEMENTS: | 9153 case NON_STRICT_ARGUMENTS_ELEMENTS: |
9151 UNIMPLEMENTED(); | 9154 UNIMPLEMENTED(); |
9152 break; | 9155 break; |
9153 } | 9156 } |
9154 return GetHeap()->undefined_value(); | 9157 return GetHeap()->undefined_value(); |
9155 } | 9158 } |
9156 | 9159 |
9157 | 9160 |
9158 bool JSObject::HasDenseElements() { | 9161 bool JSObject::HasDenseElements() { |
9159 int capacity = 0; | 9162 int capacity = 0; |
9160 int number_of_elements = 0; | 9163 int used = 0; |
| 9164 GetElementsCapacityAndUsage(&capacity, &used); |
| 9165 return (capacity == 0) || (used > (capacity / 2)); |
| 9166 } |
| 9167 |
| 9168 |
| 9169 void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) { |
| 9170 *capacity = 0; |
| 9171 *used = 0; |
9161 | 9172 |
9162 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements()); | 9173 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements()); |
9163 FixedArray* backing_store = NULL; | 9174 FixedArray* backing_store = NULL; |
9164 switch (GetElementsKind()) { | 9175 switch (GetElementsKind()) { |
9165 case NON_STRICT_ARGUMENTS_ELEMENTS: | 9176 case NON_STRICT_ARGUMENTS_ELEMENTS: |
9166 backing_store_base = | 9177 backing_store_base = |
9167 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1)); | 9178 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1)); |
9168 backing_store = FixedArray::cast(backing_store_base); | 9179 backing_store = FixedArray::cast(backing_store_base); |
9169 if (backing_store->IsDictionary()) { | 9180 if (backing_store->IsDictionary()) { |
9170 NumberDictionary* dictionary = NumberDictionary::cast(backing_store); | 9181 NumberDictionary* dictionary = NumberDictionary::cast(backing_store); |
9171 capacity = dictionary->Capacity(); | 9182 *capacity = dictionary->Capacity(); |
9172 number_of_elements = dictionary->NumberOfElements(); | 9183 *used = dictionary->NumberOfElements(); |
9173 break; | 9184 break; |
9174 } | 9185 } |
9175 // Fall through. | 9186 // Fall through. |
9176 case FAST_ELEMENTS: | 9187 case FAST_ELEMENTS: |
9177 backing_store = FixedArray::cast(backing_store_base); | 9188 backing_store = FixedArray::cast(backing_store_base); |
9178 capacity = backing_store->length(); | 9189 *capacity = backing_store->length(); |
9179 for (int i = 0; i < capacity; ++i) { | 9190 for (int i = 0; i < *capacity; ++i) { |
9180 if (!backing_store->get(i)->IsTheHole()) ++number_of_elements; | 9191 if (!backing_store->get(i)->IsTheHole()) ++(*used); |
9181 } | 9192 } |
9182 break; | 9193 break; |
9183 case DICTIONARY_ELEMENTS: { | 9194 case DICTIONARY_ELEMENTS: { |
9184 NumberDictionary* dictionary = | 9195 NumberDictionary* dictionary = |
9185 NumberDictionary::cast(FixedArray::cast(elements())); | 9196 NumberDictionary::cast(FixedArray::cast(elements())); |
9186 capacity = dictionary->Capacity(); | 9197 *capacity = dictionary->Capacity(); |
9187 number_of_elements = dictionary->NumberOfElements(); | 9198 *used = dictionary->NumberOfElements(); |
9188 break; | 9199 break; |
9189 } | 9200 } |
9190 case FAST_DOUBLE_ELEMENTS: { | 9201 case FAST_DOUBLE_ELEMENTS: { |
9191 FixedDoubleArray* elms = FixedDoubleArray::cast(elements()); | 9202 FixedDoubleArray* elms = FixedDoubleArray::cast(elements()); |
9192 capacity = elms->length(); | 9203 *capacity = elms->length(); |
9193 for (int i = 0; i < capacity; i++) { | 9204 for (int i = 0; i < *capacity; i++) { |
9194 if (!elms->is_the_hole(i)) number_of_elements++; | 9205 if (!elms->is_the_hole(i)) ++(*used); |
9195 } | 9206 } |
9196 break; | 9207 break; |
9197 } | 9208 } |
9198 case EXTERNAL_PIXEL_ELEMENTS: | |
9199 case EXTERNAL_BYTE_ELEMENTS: | 9209 case EXTERNAL_BYTE_ELEMENTS: |
9200 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 9210 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
9201 case EXTERNAL_SHORT_ELEMENTS: | 9211 case EXTERNAL_SHORT_ELEMENTS: |
9202 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 9212 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
9203 case EXTERNAL_INT_ELEMENTS: | 9213 case EXTERNAL_INT_ELEMENTS: |
9204 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 9214 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
9205 case EXTERNAL_FLOAT_ELEMENTS: | 9215 case EXTERNAL_FLOAT_ELEMENTS: |
9206 case EXTERNAL_DOUBLE_ELEMENTS: { | 9216 case EXTERNAL_DOUBLE_ELEMENTS: |
9207 return true; | 9217 case EXTERNAL_PIXEL_ELEMENTS: |
9208 } | 9218 // External arrays are considered 100% used. |
| 9219 ExternalArray* external_array = ExternalArray::cast(elements()); |
| 9220 *capacity = external_array->length(); |
| 9221 *used = external_array->length(); |
| 9222 break; |
9209 } | 9223 } |
9210 return (capacity == 0) || (number_of_elements > (capacity / 2)); | |
9211 } | 9224 } |
9212 | 9225 |
9213 | 9226 |
9214 bool JSObject::ShouldConvertToSlowElements(int new_capacity) { | 9227 bool JSObject::ShouldConvertToSlowElements(int new_capacity) { |
9215 if (new_capacity <= kMaxFastElementsLength) return false; | 9228 STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <= |
9216 // Keep the array in fast case if the current backing storage is | 9229 kMaxUncheckedFastElementsLength); |
9217 // almost filled and if the new capacity is no more than twice the | 9230 if (new_capacity <= kMaxUncheckedOldFastElementsLength || |
9218 // old capacity. | 9231 (new_capacity <= kMaxUncheckedFastElementsLength && |
| 9232 GetHeap()->InNewSpace(this))) { |
| 9233 return false; |
| 9234 } |
| 9235 // If the fast-case backing storage takes up roughly three times as |
| 9236 // much space (in machine words) as a dictionary backing storage |
| 9237 // would, the object should have slow elements. |
9219 int old_capacity = 0; | 9238 int old_capacity = 0; |
9220 if (elements()->map() == GetHeap()->non_strict_arguments_elements_map()) { | 9239 int used_elements = 0; |
9221 FixedArray* backing_store = FixedArray::cast(elements()); | 9240 GetElementsCapacityAndUsage(&old_capacity, &used_elements); |
9222 old_capacity = FixedArray::cast(backing_store->get(1))->length(); | 9241 int dictionary_size = NumberDictionary::ComputeCapacity(used_elements) * |
9223 } else if (HasFastElements()) { | 9242 NumberDictionary::kEntrySize; |
9224 old_capacity = FixedArray::cast(elements())->length(); | 9243 return 3 * dictionary_size <= new_capacity; |
9225 } else if (HasFastDoubleElements()) { | |
9226 old_capacity = FixedDoubleArray::cast(elements())->length(); | |
9227 } else { | |
9228 UNREACHABLE(); | |
9229 } | |
9230 return !HasDenseElements() || ((new_capacity / 2) > old_capacity); | |
9231 } | 9244 } |
9232 | 9245 |
9233 | 9246 |
9234 bool JSObject::ShouldConvertToFastElements() { | 9247 bool JSObject::ShouldConvertToFastElements() { |
9235 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); | 9248 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); |
9236 // If the elements are sparse, we should not go back to fast case. | 9249 // If the elements are sparse, we should not go back to fast case. |
9237 if (!HasDenseElements()) return false; | 9250 if (!HasDenseElements()) return false; |
9238 // An object requiring access checks is never allowed to have fast | 9251 // An object requiring access checks is never allowed to have fast |
9239 // elements. If it had fast elements we would skip security checks. | 9252 // elements. If it had fast elements we would skip security checks. |
9240 if (IsAccessCheckNeeded()) return false; | 9253 if (IsAccessCheckNeeded()) return false; |
9241 | 9254 |
9242 FixedArray* elements = FixedArray::cast(this->elements()); | 9255 FixedArray* elements = FixedArray::cast(this->elements()); |
9243 NumberDictionary* dictionary = NULL; | 9256 NumberDictionary* dictionary = NULL; |
9244 if (elements->map() == GetHeap()->non_strict_arguments_elements_map()) { | 9257 if (elements->map() == GetHeap()->non_strict_arguments_elements_map()) { |
9245 dictionary = NumberDictionary::cast(elements->get(1)); | 9258 dictionary = NumberDictionary::cast(elements->get(1)); |
9246 } else { | 9259 } else { |
9247 dictionary = NumberDictionary::cast(elements); | 9260 dictionary = NumberDictionary::cast(elements); |
9248 } | 9261 } |
9249 // If an element has been added at a very high index in the elements | 9262 // If an element has been added at a very high index in the elements |
9250 // dictionary, we cannot go back to fast case. | 9263 // dictionary, we cannot go back to fast case. |
9251 if (dictionary->requires_slow_elements()) return false; | 9264 if (dictionary->requires_slow_elements()) return false; |
9252 // If the dictionary backing storage takes up roughly half as much | 9265 // If the dictionary backing storage takes up roughly half as much |
9253 // space as a fast-case backing storage would the array should have | 9266 // space (in machine words) as a fast-case backing storage would, |
9254 // fast elements. | 9267 // the object should have fast elements. |
9255 uint32_t length = 0; | 9268 uint32_t array_size = 0; |
9256 if (IsJSArray()) { | 9269 if (IsJSArray()) { |
9257 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length)); | 9270 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size)); |
9258 } else { | 9271 } else { |
9259 length = dictionary->max_number_key(); | 9272 array_size = dictionary->max_number_key(); |
9260 } | 9273 } |
9261 return static_cast<uint32_t>(dictionary->Capacity()) >= | 9274 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) * |
9262 (length / (2 * NumberDictionary::kEntrySize)); | 9275 NumberDictionary::kEntrySize; |
| 9276 return 2 * dictionary_size >= array_size; |
9263 } | 9277 } |
9264 | 9278 |
9265 | 9279 |
9266 bool JSObject::ShouldConvertToFastDoubleElements() { | 9280 bool JSObject::CanConvertToFastDoubleElements() { |
9267 if (FLAG_unbox_double_arrays) { | 9281 if (FLAG_unbox_double_arrays) { |
9268 ASSERT(HasDictionaryElements()); | 9282 ASSERT(HasDictionaryElements()); |
9269 NumberDictionary* dictionary = NumberDictionary::cast(elements()); | 9283 NumberDictionary* dictionary = NumberDictionary::cast(elements()); |
9270 for (int i = 0; i < dictionary->Capacity(); i++) { | 9284 for (int i = 0; i < dictionary->Capacity(); i++) { |
9271 Object* key = dictionary->KeyAt(i); | 9285 Object* key = dictionary->KeyAt(i); |
9272 if (key->IsNumber()) { | 9286 if (key->IsNumber()) { |
9273 if (!dictionary->ValueAt(i)->IsNumber()) return false; | 9287 if (!dictionary->ValueAt(i)->IsNumber()) return false; |
9274 } | 9288 } |
9275 } | 9289 } |
9276 return true; | 9290 return true; |
(...skipping 910 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10187 void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) { | 10201 void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) { |
10188 IteratePointers(v, | 10202 IteratePointers(v, |
10189 kElementsStartOffset, | 10203 kElementsStartOffset, |
10190 kHeaderSize + length() * kPointerSize); | 10204 kHeaderSize + length() * kPointerSize); |
10191 } | 10205 } |
10192 | 10206 |
10193 | 10207 |
10194 template<typename Shape, typename Key> | 10208 template<typename Shape, typename Key> |
10195 MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for, | 10209 MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for, |
10196 PretenureFlag pretenure) { | 10210 PretenureFlag pretenure) { |
10197 const int kMinCapacity = 32; | 10211 int capacity = ComputeCapacity(at_least_space_for); |
10198 int capacity = RoundUpToPowerOf2(at_least_space_for * 2); | 10212 if (capacity > HashTable::kMaxCapacity) { |
10199 if (capacity < kMinCapacity) { | |
10200 capacity = kMinCapacity; // Guarantee min capacity. | |
10201 } else if (capacity > HashTable::kMaxCapacity) { | |
10202 return Failure::OutOfMemoryException(); | 10213 return Failure::OutOfMemoryException(); |
10203 } | 10214 } |
10204 | 10215 |
10205 Object* obj; | 10216 Object* obj; |
10206 { MaybeObject* maybe_obj = Isolate::Current()->heap()-> | 10217 { MaybeObject* maybe_obj = Isolate::Current()->heap()-> |
10207 AllocateHashTable(EntryToIndex(capacity), pretenure); | 10218 AllocateHashTable(EntryToIndex(capacity), pretenure); |
10208 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 10219 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
10209 } | 10220 } |
10210 HashTable::cast(obj)->SetNumberOfElements(0); | 10221 HashTable::cast(obj)->SetNumberOfElements(0); |
10211 HashTable::cast(obj)->SetNumberOfDeletedElements(0); | 10222 HashTable::cast(obj)->SetNumberOfDeletedElements(0); |
(...skipping 1712 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11924 if (break_point_objects()->IsUndefined()) return 0; | 11935 if (break_point_objects()->IsUndefined()) return 0; |
11925 // Single beak point. | 11936 // Single beak point. |
11926 if (!break_point_objects()->IsFixedArray()) return 1; | 11937 if (!break_point_objects()->IsFixedArray()) return 1; |
11927 // Multiple break points. | 11938 // Multiple break points. |
11928 return FixedArray::cast(break_point_objects())->length(); | 11939 return FixedArray::cast(break_point_objects())->length(); |
11929 } | 11940 } |
11930 #endif | 11941 #endif |
11931 | 11942 |
11932 | 11943 |
11933 } } // namespace v8::internal | 11944 } } // namespace v8::internal |
OLD | NEW |