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

Side by Side Diff: src/objects.cc

Issue 7464032: Improve fast to slow elements conversion: (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Review fixes and tweaks Created 9 years, 4 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 | Annotate | Revision Log
« no previous file with comments | « src/objects.h ('k') | src/objects-inl.h » ('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 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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/objects.h ('k') | src/objects-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698