OLD | NEW |
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 2204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2215 if (HasFastProperties()) return this; | 2215 if (HasFastProperties()) return this; |
2216 ASSERT(!IsGlobalObject()); | 2216 ASSERT(!IsGlobalObject()); |
2217 return property_dictionary()-> | 2217 return property_dictionary()-> |
2218 TransformPropertiesToFastFor(this, unused_property_fields); | 2218 TransformPropertiesToFastFor(this, unused_property_fields); |
2219 } | 2219 } |
2220 | 2220 |
2221 | 2221 |
2222 Object* JSObject::NormalizeElements() { | 2222 Object* JSObject::NormalizeElements() { |
2223 ASSERT(!HasPixelElements() && !HasExternalArrayElements()); | 2223 ASSERT(!HasPixelElements() && !HasExternalArrayElements()); |
2224 if (HasDictionaryElements()) return this; | 2224 if (HasDictionaryElements()) return this; |
| 2225 ASSERT(map()->has_fast_elements()); |
| 2226 |
| 2227 Object* obj = map()->GetSlowElementsMap(); |
| 2228 if (obj->IsFailure()) return obj; |
| 2229 Map* new_map = Map::cast(obj); |
2225 | 2230 |
2226 // Get number of entries. | 2231 // Get number of entries. |
2227 FixedArray* array = FixedArray::cast(elements()); | 2232 FixedArray* array = FixedArray::cast(elements()); |
2228 | 2233 |
2229 // Compute the effective length. | 2234 // Compute the effective length. |
2230 int length = IsJSArray() ? | 2235 int length = IsJSArray() ? |
2231 Smi::cast(JSArray::cast(this)->length())->value() : | 2236 Smi::cast(JSArray::cast(this)->length())->value() : |
2232 array->length(); | 2237 array->length(); |
2233 Object* obj = NumberDictionary::Allocate(length); | 2238 obj = NumberDictionary::Allocate(length); |
2234 if (obj->IsFailure()) return obj; | 2239 if (obj->IsFailure()) return obj; |
2235 NumberDictionary* dictionary = NumberDictionary::cast(obj); | 2240 NumberDictionary* dictionary = NumberDictionary::cast(obj); |
2236 // Copy entries. | 2241 // Copy entries. |
2237 for (int i = 0; i < length; i++) { | 2242 for (int i = 0; i < length; i++) { |
2238 Object* value = array->get(i); | 2243 Object* value = array->get(i); |
2239 if (!value->IsTheHole()) { | 2244 if (!value->IsTheHole()) { |
2240 PropertyDetails details = PropertyDetails(NONE, NORMAL); | 2245 PropertyDetails details = PropertyDetails(NONE, NORMAL); |
2241 Object* result = dictionary->AddNumberEntry(i, array->get(i), details); | 2246 Object* result = dictionary->AddNumberEntry(i, array->get(i), details); |
2242 if (result->IsFailure()) return result; | 2247 if (result->IsFailure()) return result; |
2243 dictionary = NumberDictionary::cast(result); | 2248 dictionary = NumberDictionary::cast(result); |
2244 } | 2249 } |
2245 } | 2250 } |
2246 // Switch to using the dictionary as the backing storage for elements. | 2251 // Switch to using the dictionary as the backing storage for |
| 2252 // elements. Set the new map first to satify the elements type |
| 2253 // assert in set_elements(). |
| 2254 set_map(new_map); |
2247 set_elements(dictionary); | 2255 set_elements(dictionary); |
2248 | 2256 |
2249 Counters::elements_to_dictionary.Increment(); | 2257 Counters::elements_to_dictionary.Increment(); |
2250 | 2258 |
2251 #ifdef DEBUG | 2259 #ifdef DEBUG |
2252 if (FLAG_trace_normalization) { | 2260 if (FLAG_trace_normalization) { |
2253 PrintF("Object elements have been normalized:\n"); | 2261 PrintF("Object elements have been normalized:\n"); |
2254 Print(); | 2262 Print(); |
2255 } | 2263 } |
2256 #endif | 2264 #endif |
(...skipping 3209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5466 PrintF("\n"); | 5474 PrintF("\n"); |
5467 | 5475 |
5468 PrintF("RelocInfo (size = %d)\n", relocation_size()); | 5476 PrintF("RelocInfo (size = %d)\n", relocation_size()); |
5469 for (RelocIterator it(this); !it.done(); it.next()) | 5477 for (RelocIterator it(this); !it.done(); it.next()) |
5470 it.rinfo()->Print(); | 5478 it.rinfo()->Print(); |
5471 PrintF("\n"); | 5479 PrintF("\n"); |
5472 } | 5480 } |
5473 #endif // ENABLE_DISASSEMBLER | 5481 #endif // ENABLE_DISASSEMBLER |
5474 | 5482 |
5475 | 5483 |
5476 void JSObject::SetFastElements(FixedArray* elems) { | 5484 Object* JSObject::SetFastElementsCapacityAndLength(int capacity, int length) { |
5477 // We should never end in here with a pixel or external array. | 5485 // We should never end in here with a pixel or external array. |
5478 ASSERT(!HasPixelElements() && !HasExternalArrayElements()); | 5486 ASSERT(!HasPixelElements() && !HasExternalArrayElements()); |
5479 #ifdef DEBUG | 5487 |
5480 // Check the provided array is filled with the_hole. | 5488 Object* obj = Heap::AllocateFixedArrayWithHoles(capacity); |
5481 uint32_t len = static_cast<uint32_t>(elems->length()); | 5489 if (obj->IsFailure()) return obj; |
5482 for (uint32_t i = 0; i < len; i++) ASSERT(elems->get(i)->IsTheHole()); | 5490 FixedArray* elems = FixedArray::cast(obj); |
5483 #endif | 5491 |
| 5492 obj = map()->GetFastElementsMap(); |
| 5493 if (obj->IsFailure()) return obj; |
| 5494 Map* new_map = Map::cast(obj); |
| 5495 |
5484 AssertNoAllocation no_gc; | 5496 AssertNoAllocation no_gc; |
5485 WriteBarrierMode mode = elems->GetWriteBarrierMode(no_gc); | 5497 WriteBarrierMode mode = elems->GetWriteBarrierMode(no_gc); |
5486 switch (GetElementsKind()) { | 5498 switch (GetElementsKind()) { |
5487 case FAST_ELEMENTS: { | 5499 case FAST_ELEMENTS: { |
5488 FixedArray* old_elements = FixedArray::cast(elements()); | 5500 FixedArray* old_elements = FixedArray::cast(elements()); |
5489 uint32_t old_length = static_cast<uint32_t>(old_elements->length()); | 5501 uint32_t old_length = static_cast<uint32_t>(old_elements->length()); |
5490 // Fill out the new array with this content and array holes. | 5502 // Fill out the new array with this content and array holes. |
5491 for (uint32_t i = 0; i < old_length; i++) { | 5503 for (uint32_t i = 0; i < old_length; i++) { |
5492 elems->set(i, old_elements->get(i), mode); | 5504 elems->set(i, old_elements->get(i), mode); |
5493 } | 5505 } |
5494 break; | 5506 break; |
5495 } | 5507 } |
5496 case DICTIONARY_ELEMENTS: { | 5508 case DICTIONARY_ELEMENTS: { |
5497 NumberDictionary* dictionary = NumberDictionary::cast(elements()); | 5509 NumberDictionary* dictionary = NumberDictionary::cast(elements()); |
5498 for (int i = 0; i < dictionary->Capacity(); i++) { | 5510 for (int i = 0; i < dictionary->Capacity(); i++) { |
5499 Object* key = dictionary->KeyAt(i); | 5511 Object* key = dictionary->KeyAt(i); |
5500 if (key->IsNumber()) { | 5512 if (key->IsNumber()) { |
5501 uint32_t entry = static_cast<uint32_t>(key->Number()); | 5513 uint32_t entry = static_cast<uint32_t>(key->Number()); |
5502 elems->set(entry, dictionary->ValueAt(i), mode); | 5514 elems->set(entry, dictionary->ValueAt(i), mode); |
5503 } | 5515 } |
5504 } | 5516 } |
5505 break; | 5517 break; |
5506 } | 5518 } |
5507 default: | 5519 default: |
5508 UNREACHABLE(); | 5520 UNREACHABLE(); |
5509 break; | 5521 break; |
5510 } | 5522 } |
| 5523 |
| 5524 set_map(new_map); |
5511 set_elements(elems); | 5525 set_elements(elems); |
| 5526 |
| 5527 if (IsJSArray()) { |
| 5528 JSArray::cast(this)->set_length(Smi::FromInt(length)); |
| 5529 } |
| 5530 |
| 5531 return this; |
5512 } | 5532 } |
5513 | 5533 |
5514 | 5534 |
5515 Object* JSObject::SetSlowElements(Object* len) { | 5535 Object* JSObject::SetSlowElements(Object* len) { |
5516 // We should never end in here with a pixel or external array. | 5536 // We should never end in here with a pixel or external array. |
5517 ASSERT(!HasPixelElements() && !HasExternalArrayElements()); | 5537 ASSERT(!HasPixelElements() && !HasExternalArrayElements()); |
5518 | 5538 |
5519 uint32_t new_length = static_cast<uint32_t>(len->Number()); | 5539 uint32_t new_length = static_cast<uint32_t>(len->Number()); |
5520 | 5540 |
5521 switch (GetElementsKind()) { | 5541 switch (GetElementsKind()) { |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5588 HandleVector<Object>(NULL, 0))); | 5608 HandleVector<Object>(NULL, 0))); |
5589 } | 5609 } |
5590 | 5610 |
5591 | 5611 |
5592 Object* JSObject::SetElementsLength(Object* len) { | 5612 Object* JSObject::SetElementsLength(Object* len) { |
5593 // We should never end in here with a pixel or external array. | 5613 // We should never end in here with a pixel or external array. |
5594 ASSERT(AllowsSetElementsLength()); | 5614 ASSERT(AllowsSetElementsLength()); |
5595 | 5615 |
5596 Object* smi_length = len->ToSmi(); | 5616 Object* smi_length = len->ToSmi(); |
5597 if (smi_length->IsSmi()) { | 5617 if (smi_length->IsSmi()) { |
5598 int value = Smi::cast(smi_length)->value(); | 5618 const int value = Smi::cast(smi_length)->value(); |
5599 if (value < 0) return ArrayLengthRangeError(); | 5619 if (value < 0) return ArrayLengthRangeError(); |
5600 switch (GetElementsKind()) { | 5620 switch (GetElementsKind()) { |
5601 case FAST_ELEMENTS: { | 5621 case FAST_ELEMENTS: { |
5602 int old_capacity = FixedArray::cast(elements())->length(); | 5622 int old_capacity = FixedArray::cast(elements())->length(); |
5603 if (value <= old_capacity) { | 5623 if (value <= old_capacity) { |
5604 if (IsJSArray()) { | 5624 if (IsJSArray()) { |
5605 int old_length = FastD2I(JSArray::cast(this)->length()->Number()); | 5625 int old_length = FastD2I(JSArray::cast(this)->length()->Number()); |
5606 // NOTE: We may be able to optimize this by removing the | 5626 // NOTE: We may be able to optimize this by removing the |
5607 // last part of the elements backing storage array and | 5627 // last part of the elements backing storage array and |
5608 // setting the capacity to the new size. | 5628 // setting the capacity to the new size. |
5609 for (int i = value; i < old_length; i++) { | 5629 for (int i = value; i < old_length; i++) { |
5610 FixedArray::cast(elements())->set_the_hole(i); | 5630 FixedArray::cast(elements())->set_the_hole(i); |
5611 } | 5631 } |
5612 JSArray::cast(this)->set_length(Smi::cast(smi_length)); | 5632 JSArray::cast(this)->set_length(Smi::cast(smi_length)); |
5613 } | 5633 } |
5614 return this; | 5634 return this; |
5615 } | 5635 } |
5616 int min = NewElementsCapacity(old_capacity); | 5636 int min = NewElementsCapacity(old_capacity); |
5617 int new_capacity = value > min ? value : min; | 5637 int new_capacity = value > min ? value : min; |
5618 if (new_capacity <= kMaxFastElementsLength || | 5638 if (new_capacity <= kMaxFastElementsLength || |
5619 !ShouldConvertToSlowElements(new_capacity)) { | 5639 !ShouldConvertToSlowElements(new_capacity)) { |
5620 Object* obj = Heap::AllocateFixedArrayWithHoles(new_capacity); | 5640 Object* obj = SetFastElementsCapacityAndLength(new_capacity, value); |
5621 if (obj->IsFailure()) return obj; | 5641 if (obj->IsFailure()) return obj; |
5622 if (IsJSArray()) { | |
5623 JSArray::cast(this)->set_length(Smi::cast(smi_length)); | |
5624 } | |
5625 SetFastElements(FixedArray::cast(obj)); | |
5626 return this; | 5642 return this; |
5627 } | 5643 } |
5628 break; | 5644 break; |
5629 } | 5645 } |
5630 case DICTIONARY_ELEMENTS: { | 5646 case DICTIONARY_ELEMENTS: { |
5631 if (IsJSArray()) { | 5647 if (IsJSArray()) { |
5632 if (value == 0) { | 5648 if (value == 0) { |
5633 // If the length of a slow array is reset to zero, we clear | 5649 // If the length of a slow array is reset to zero, we clear |
5634 // the array and flush backing storage. This has the added | 5650 // the array and flush backing storage. This has the added |
5635 // benefit that the array returns to fast mode. | 5651 // benefit that the array returns to fast mode. |
5636 initialize_elements(); | 5652 Object* obj = ResetElements(); |
| 5653 if (obj->IsFailure()) return obj; |
5637 } else { | 5654 } else { |
5638 // Remove deleted elements. | 5655 // Remove deleted elements. |
5639 uint32_t old_length = | 5656 uint32_t old_length = |
5640 static_cast<uint32_t>(JSArray::cast(this)->length()->Number()); | 5657 static_cast<uint32_t>(JSArray::cast(this)->length()->Number()); |
5641 element_dictionary()->RemoveNumberEntries(value, old_length); | 5658 element_dictionary()->RemoveNumberEntries(value, old_length); |
5642 } | 5659 } |
5643 JSArray::cast(this)->set_length(Smi::cast(smi_length)); | 5660 JSArray::cast(this)->set_length(Smi::cast(smi_length)); |
5644 } | 5661 } |
5645 return this; | 5662 return this; |
5646 } | 5663 } |
(...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6085 return value; | 6102 return value; |
6086 } | 6103 } |
6087 | 6104 |
6088 // Allow gap in fast case. | 6105 // Allow gap in fast case. |
6089 if ((index - elms_length) < kMaxGap) { | 6106 if ((index - elms_length) < kMaxGap) { |
6090 // Try allocating extra space. | 6107 // Try allocating extra space. |
6091 int new_capacity = NewElementsCapacity(index+1); | 6108 int new_capacity = NewElementsCapacity(index+1); |
6092 if (new_capacity <= kMaxFastElementsLength || | 6109 if (new_capacity <= kMaxFastElementsLength || |
6093 !ShouldConvertToSlowElements(new_capacity)) { | 6110 !ShouldConvertToSlowElements(new_capacity)) { |
6094 ASSERT(static_cast<uint32_t>(new_capacity) > index); | 6111 ASSERT(static_cast<uint32_t>(new_capacity) > index); |
6095 Object* obj = Heap::AllocateFixedArrayWithHoles(new_capacity); | 6112 Object* obj = SetFastElementsCapacityAndLength(new_capacity, index + 1); |
6096 if (obj->IsFailure()) return obj; | 6113 if (obj->IsFailure()) return obj; |
6097 SetFastElements(FixedArray::cast(obj)); | |
6098 if (IsJSArray()) { | |
6099 JSArray::cast(this)->set_length(Smi::FromInt(index + 1)); | |
6100 } | |
6101 FixedArray::cast(elements())->set(index, value); | 6114 FixedArray::cast(elements())->set(index, value); |
6102 return value; | 6115 return value; |
6103 } | 6116 } |
6104 } | 6117 } |
6105 | 6118 |
6106 // Otherwise default to slow case. | 6119 // Otherwise default to slow case. |
6107 Object* obj = NormalizeElements(); | 6120 Object* obj = NormalizeElements(); |
6108 if (obj->IsFailure()) return obj; | 6121 if (obj->IsFailure()) return obj; |
6109 ASSERT(HasDictionaryElements()); | 6122 ASSERT(HasDictionaryElements()); |
6110 return SetElement(index, value); | 6123 return SetElement(index, value); |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6209 Object* return_value = array->JSArrayUpdateLengthFromIndex(index, | 6222 Object* return_value = array->JSArrayUpdateLengthFromIndex(index, |
6210 value); | 6223 value); |
6211 if (return_value->IsFailure()) return return_value; | 6224 if (return_value->IsFailure()) return return_value; |
6212 } | 6225 } |
6213 | 6226 |
6214 // Attempt to put this object back in fast case. | 6227 // Attempt to put this object back in fast case. |
6215 if (ShouldConvertToFastElements()) { | 6228 if (ShouldConvertToFastElements()) { |
6216 uint32_t new_length = 0; | 6229 uint32_t new_length = 0; |
6217 if (IsJSArray()) { | 6230 if (IsJSArray()) { |
6218 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length)); | 6231 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length)); |
6219 JSArray::cast(this)->set_length(Smi::FromInt(new_length)); | |
6220 } else { | 6232 } else { |
6221 new_length = NumberDictionary::cast(elements())->max_number_key() + 1; | 6233 new_length = NumberDictionary::cast(elements())->max_number_key() + 1; |
6222 } | 6234 } |
6223 Object* obj = Heap::AllocateFixedArrayWithHoles(new_length); | 6235 Object* obj = SetFastElementsCapacityAndLength(new_length, new_length); |
6224 if (obj->IsFailure()) return obj; | 6236 if (obj->IsFailure()) return obj; |
6225 SetFastElements(FixedArray::cast(obj)); | |
6226 #ifdef DEBUG | 6237 #ifdef DEBUG |
6227 if (FLAG_trace_normalization) { | 6238 if (FLAG_trace_normalization) { |
6228 PrintF("Object elements are fast case again:\n"); | 6239 PrintF("Object elements are fast case again:\n"); |
6229 Print(); | 6240 Print(); |
6230 } | 6241 } |
6231 #endif | 6242 #endif |
6232 } | 6243 } |
6233 | 6244 |
6234 return value; | 6245 return value; |
6235 } | 6246 } |
(...skipping 1283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7519 if (HasDictionaryElements()) { | 7530 if (HasDictionaryElements()) { |
7520 // Convert to fast elements containing only the existing properties. | 7531 // Convert to fast elements containing only the existing properties. |
7521 // Ordering is irrelevant, since we are going to sort anyway. | 7532 // Ordering is irrelevant, since we are going to sort anyway. |
7522 NumberDictionary* dict = element_dictionary(); | 7533 NumberDictionary* dict = element_dictionary(); |
7523 if (IsJSArray() || dict->requires_slow_elements() || | 7534 if (IsJSArray() || dict->requires_slow_elements() || |
7524 dict->max_number_key() >= limit) { | 7535 dict->max_number_key() >= limit) { |
7525 return PrepareSlowElementsForSort(limit); | 7536 return PrepareSlowElementsForSort(limit); |
7526 } | 7537 } |
7527 // Convert to fast elements. | 7538 // Convert to fast elements. |
7528 | 7539 |
| 7540 Object* obj = map()->GetFastElementsMap(); |
| 7541 if (obj->IsFailure()) return obj; |
| 7542 Map* new_map = Map::cast(obj); |
| 7543 |
7529 PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED: TENURED; | 7544 PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED: TENURED; |
7530 Object* new_array = | 7545 Object* new_array = |
7531 Heap::AllocateFixedArray(dict->NumberOfElements(), tenure); | 7546 Heap::AllocateFixedArray(dict->NumberOfElements(), tenure); |
7532 if (new_array->IsFailure()) { | 7547 if (new_array->IsFailure()) return new_array; |
7533 return new_array; | |
7534 } | |
7535 FixedArray* fast_elements = FixedArray::cast(new_array); | 7548 FixedArray* fast_elements = FixedArray::cast(new_array); |
7536 dict->CopyValuesTo(fast_elements); | 7549 dict->CopyValuesTo(fast_elements); |
| 7550 |
| 7551 set_map(new_map); |
7537 set_elements(fast_elements); | 7552 set_elements(fast_elements); |
7538 } | 7553 } |
7539 ASSERT(HasFastElements()); | 7554 ASSERT(HasFastElements()); |
7540 | 7555 |
7541 // Collect holes at the end, undefined before that and the rest at the | 7556 // Collect holes at the end, undefined before that and the rest at the |
7542 // start, and return the number of non-hole, non-undefined values. | 7557 // start, and return the number of non-hole, non-undefined values. |
7543 | 7558 |
7544 FixedArray* elements = FixedArray::cast(this->elements()); | 7559 FixedArray* elements = FixedArray::cast(this->elements()); |
7545 uint32_t elements_length = static_cast<uint32_t>(elements->length()); | 7560 uint32_t elements_length = static_cast<uint32_t>(elements->length()); |
7546 if (limit > elements_length) { | 7561 if (limit > elements_length) { |
(...skipping 1176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8723 if (break_point_objects()->IsUndefined()) return 0; | 8738 if (break_point_objects()->IsUndefined()) return 0; |
8724 // Single beak point. | 8739 // Single beak point. |
8725 if (!break_point_objects()->IsFixedArray()) return 1; | 8740 if (!break_point_objects()->IsFixedArray()) return 1; |
8726 // Multiple break points. | 8741 // Multiple break points. |
8727 return FixedArray::cast(break_point_objects())->length(); | 8742 return FixedArray::cast(break_point_objects())->length(); |
8728 } | 8743 } |
8729 #endif | 8744 #endif |
8730 | 8745 |
8731 | 8746 |
8732 } } // namespace v8::internal | 8747 } } // namespace v8::internal |
OLD | NEW |