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 2827 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2838 if (element->IsString() && | 2838 if (element->IsString() && |
2839 key->IsString() && String::cast(element)->Equals(String::cast(key))) { | 2839 key->IsString() && String::cast(element)->Equals(String::cast(key))) { |
2840 return true; | 2840 return true; |
2841 } | 2841 } |
2842 } | 2842 } |
2843 return false; | 2843 return false; |
2844 } | 2844 } |
2845 | 2845 |
2846 | 2846 |
2847 Object* FixedArray::AddKeysFromJSArray(JSArray* array) { | 2847 Object* FixedArray::AddKeysFromJSArray(JSArray* array) { |
2848 // Remove array holes from array if any. | 2848 if (array->HasFastElements()) { |
2849 Object* object = array->RemoveHoles(); | 2849 return UnionOfKeys(array->elements()); |
2850 if (object->IsFailure()) return object; | 2850 } |
2851 JSArray* compacted_array = JSArray::cast(object); | 2851 ASSERT(!array->HasFastElements()); |
2852 Dictionary* dict = array->element_dictionary(); | |
2853 int size = dict->NumberOfElements(); | |
2852 | 2854 |
2853 // Allocate a temporary fixed array. | 2855 // Allocate a temporary fixed array. |
2854 int compacted_array_length = Smi::cast(compacted_array->length())->value(); | 2856 Object* object = Heap::AllocateFixedArray(size); |
2855 object = Heap::AllocateFixedArray(compacted_array_length); | |
2856 if (object->IsFailure()) return object; | 2857 if (object->IsFailure()) return object; |
2857 FixedArray* key_array = FixedArray::cast(object); | 2858 FixedArray* key_array = FixedArray::cast(object); |
2858 | 2859 |
2860 int capacity = dict->Capacity(); | |
2861 int pos = 0; | |
2859 // Copy the elements from the JSArray to the temporary fixed array. | 2862 // Copy the elements from the JSArray to the temporary fixed array. |
2860 for (int i = 0; i < compacted_array_length; i++) { | 2863 for (int i = 0; i < capacity; i++) { |
2861 key_array->set(i, compacted_array->GetElement(i)); | 2864 if (dict->IsKey(dict->KeyAt(i))) { |
2865 key_array->set(pos++, dict->ValueAt(i)); | |
2866 } | |
2862 } | 2867 } |
2863 | |
2864 // Compute the union of this and the temporary fixed array. | 2868 // Compute the union of this and the temporary fixed array. |
2865 return UnionOfKeys(key_array); | 2869 return UnionOfKeys(key_array); |
2866 } | 2870 } |
2867 | 2871 |
2868 | 2872 |
2869 Object* FixedArray::UnionOfKeys(FixedArray* other) { | 2873 Object* FixedArray::UnionOfKeys(FixedArray* other) { |
2870 int len0 = length(); | 2874 int len0 = length(); |
2871 int len1 = other->length(); | 2875 int len1 = other->length(); |
2872 // Optimize if either is empty. | 2876 // Optimize if either is empty. |
2873 if (len0 == 0) return other; | 2877 if (len0 == 0) return other; |
2874 if (len1 == 0) return this; | 2878 if (len1 == 0) return this; |
2875 | 2879 |
2876 // Compute how many elements are not in this. | 2880 // Compute how many elements are not in this. |
2877 int extra = 0; | 2881 int extra = 0; |
2878 for (int y = 0; y < len1; y++) { | 2882 for (int y = 0; y < len1; y++) { |
2879 if (!HasKey(this, other->get(y))) extra++; | 2883 Object* value = other->get(y); |
2884 if (!value->IsTheHole() && !HasKey(this, value)) extra++; | |
2880 } | 2885 } |
2881 | 2886 |
2887 if (extra == 0) return this; | |
2888 | |
2882 // Allocate the result | 2889 // Allocate the result |
2883 Object* obj = Heap::AllocateFixedArray(len0 + extra); | 2890 Object* obj = Heap::AllocateFixedArray(len0 + extra); |
2884 if (obj->IsFailure()) return obj; | 2891 if (obj->IsFailure()) return obj; |
2885 // Fill in the content | 2892 // Fill in the content |
2886 FixedArray* result = FixedArray::cast(obj); | 2893 FixedArray* result = FixedArray::cast(obj); |
2887 WriteBarrierMode mode = result->GetWriteBarrierMode(); | 2894 WriteBarrierMode mode = result->GetWriteBarrierMode(); |
2888 for (int i = 0; i < len0; i++) { | 2895 for (int i = 0; i < len0; i++) { |
2889 result->set(i, get(i), mode); | 2896 result->set(i, get(i), mode); |
2890 } | 2897 } |
2891 // Fill in the extra keys. | 2898 // Fill in the extra keys. |
2892 int index = 0; | 2899 int index = 0; |
2893 for (int y = 0; y < len1; y++) { | 2900 for (int y = 0; y < len1; y++) { |
2894 if (!HasKey(this, other->get(y))) { | 2901 Object* value = other->get(y); |
2902 if (!value->IsTheHole() && !HasKey(this, value)) { | |
2895 result->set(len0 + index, other->get(y), mode); | 2903 result->set(len0 + index, other->get(y), mode); |
2896 index++; | 2904 index++; |
2897 } | 2905 } |
2898 } | 2906 } |
2899 ASSERT(extra == index); | 2907 ASSERT(extra == index); |
2900 return result; | 2908 return result; |
2901 } | 2909 } |
2902 | 2910 |
2903 | 2911 |
2904 Object* FixedArray::CopySize(int new_length) { | 2912 Object* FixedArray::CopySize(int new_length) { |
(...skipping 2711 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5616 if (IsJSArray()) { | 5624 if (IsJSArray()) { |
5617 CHECK(Array::IndexFromObject(JSArray::cast(this)->length(), &length)); | 5625 CHECK(Array::IndexFromObject(JSArray::cast(this)->length(), &length)); |
5618 } else { | 5626 } else { |
5619 length = dictionary->max_number_key(); | 5627 length = dictionary->max_number_key(); |
5620 } | 5628 } |
5621 return static_cast<uint32_t>(dictionary->Capacity()) >= | 5629 return static_cast<uint32_t>(dictionary->Capacity()) >= |
5622 (length / (2 * Dictionary::kElementSize)); | 5630 (length / (2 * Dictionary::kElementSize)); |
5623 } | 5631 } |
5624 | 5632 |
5625 | 5633 |
5626 Object* Dictionary::RemoveHoles() { | |
5627 int capacity = Capacity(); | |
5628 Object* obj = Allocate(NumberOfElements()); | |
5629 if (obj->IsFailure()) return obj; | |
5630 Dictionary* dict = Dictionary::cast(obj); | |
5631 uint32_t pos = 0; | |
5632 for (int i = 0; i < capacity; i++) { | |
5633 Object* k = KeyAt(i); | |
5634 if (IsKey(k)) { | |
5635 dict->AddNumberEntry(pos++, ValueAt(i), DetailsAt(i)); | |
5636 } | |
5637 } | |
5638 return dict; | |
5639 } | |
5640 | |
5641 | |
5642 void Dictionary::CopyValuesTo(FixedArray* elements) { | 5634 void Dictionary::CopyValuesTo(FixedArray* elements) { |
5643 int pos = 0; | 5635 int pos = 0; |
5644 int capacity = Capacity(); | 5636 int capacity = Capacity(); |
5637 WriteBarrierMode mode = elements->GetWriteBarrierMode(); | |
5645 for (int i = 0; i < capacity; i++) { | 5638 for (int i = 0; i < capacity; i++) { |
5646 Object* k = KeyAt(i); | 5639 Object* k = KeyAt(i); |
5647 if (IsKey(k)) elements->set(pos++, ValueAt(i)); | 5640 if (IsKey(k)) elements->set(pos++, ValueAt(i), mode); |
5648 } | 5641 } |
5649 ASSERT(pos == elements->length()); | 5642 ASSERT(pos == elements->length()); |
5650 } | 5643 } |
5651 | 5644 |
5652 | 5645 |
5653 Object* JSArray::RemoveHoles() { | |
5654 if (HasFastElements()) { | |
5655 int len = Smi::cast(length())->value(); | |
5656 int pos = 0; | |
5657 FixedArray* elms = FixedArray::cast(elements()); | |
5658 for (int index = 0; index < len; index++) { | |
5659 Object* e = elms->get(index); | |
5660 if (!e->IsTheHole()) { | |
5661 if (index != pos) elms->set(pos, e); | |
5662 pos++; | |
5663 } | |
5664 } | |
5665 set_length(Smi::FromInt(pos), SKIP_WRITE_BARRIER); | |
5666 for (int index = pos; index < len; index++) { | |
5667 elms->set_the_hole(index); | |
5668 } | |
5669 return this; | |
5670 } | |
5671 | |
5672 // Compact the sparse array if possible. | |
5673 Dictionary* dict = element_dictionary(); | |
5674 int length = dict->NumberOfElements(); | |
5675 | |
5676 // Try to make this a fast array again. | |
5677 if (length <= kMaxFastElementsLength) { | |
5678 Object* obj = Heap::AllocateFixedArray(length); | |
5679 if (obj->IsFailure()) return obj; | |
5680 dict->CopyValuesTo(FixedArray::cast(obj)); | |
5681 set_length(Smi::FromInt(length), SKIP_WRITE_BARRIER); | |
5682 set_elements(FixedArray::cast(obj)); | |
5683 return this; | |
5684 } | |
5685 | |
5686 // Make another dictionary with smaller indices. | |
5687 Object* obj = dict->RemoveHoles(); | |
5688 if (obj->IsFailure()) return obj; | |
5689 set_length(Smi::FromInt(length), SKIP_WRITE_BARRIER); | |
5690 set_elements(Dictionary::cast(obj)); | |
5691 return this; | |
5692 } | |
5693 | |
5694 | |
5695 InterceptorInfo* JSObject::GetNamedInterceptor() { | 5646 InterceptorInfo* JSObject::GetNamedInterceptor() { |
5696 ASSERT(map()->has_named_interceptor()); | 5647 ASSERT(map()->has_named_interceptor()); |
5697 JSFunction* constructor = JSFunction::cast(map()->constructor()); | 5648 JSFunction* constructor = JSFunction::cast(map()->constructor()); |
5698 Object* template_info = constructor->shared()->function_data(); | 5649 Object* template_info = constructor->shared()->function_data(); |
5699 Object* result = | 5650 Object* result = |
5700 FunctionTemplateInfo::cast(template_info)->named_property_handler(); | 5651 FunctionTemplateInfo::cast(template_info)->named_property_handler(); |
5701 return InterceptorInfo::cast(result); | 5652 return InterceptorInfo::cast(result); |
5702 } | 5653 } |
5703 | 5654 |
5704 | 5655 |
(...skipping 731 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6436 | 6387 |
6437 | 6388 |
6438 // Force instantiation of Dictionary's base class | 6389 // Force instantiation of Dictionary's base class |
6439 template class HashTable<2, 3>; | 6390 template class HashTable<2, 3>; |
6440 | 6391 |
6441 | 6392 |
6442 // Force instantiation of EvalCache's base class | 6393 // Force instantiation of EvalCache's base class |
6443 template class HashTable<0, 2>; | 6394 template class HashTable<0, 2>; |
6444 | 6395 |
6445 | 6396 |
6397 // Collates undefined and unexisting elements below limit from position | |
6398 // zero of the elements. The object stays in Dictionary mode. | |
6399 Object* JSObject::PrepareSlowElementsForSort(uint32_t limit) { | |
6400 static const uint32_t kMaxUInt32 = 4294967295u; | |
Erik Corry
2009/04/27 09:42:13
This should probably go next to kMaxInt in globals
| |
6401 ASSERT(!HasFastElements()); | |
6402 // Must stay in dictionary mode, either because of requires_slow_elements, | |
6403 // or because we are not going to sort (and therefore compact) all of the | |
6404 // elements. | |
6405 Dictionary* dict = element_dictionary(); | |
6406 HeapNumber* result_double; | |
Erik Corry
2009/04/27 09:42:13
Please initialize to NULL and ASSERT it is not nul
| |
6407 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) { | |
6408 // Allocate space for result before we start mutating the object. | |
6409 Object* new_double = Heap::AllocateHeapNumber(0.0); | |
6410 if (new_double->IsFailure()) return new_double; | |
6411 result_double = HeapNumber::cast(new_double); | |
6412 } | |
6413 | |
6414 int capacity = dict->Capacity(); | |
6415 Object* obj = Dictionary::Allocate(dict->Capacity()); | |
6416 if (obj->IsFailure()) return obj; | |
6417 Dictionary* new_dict = Dictionary::cast(obj); | |
6418 | |
6419 AssertNoAllocation no_alloc; | |
6420 | |
6421 // Loose all details on properties when moving them around. | |
6422 // Elements do not have special details like properties. | |
6423 PropertyDetails no_details = PropertyDetails(NONE, NORMAL); | |
6424 | |
6425 uint32_t pos = 0; | |
6426 uint32_t undefs = 0; | |
6427 for (int i = 0; i < capacity; i++) { | |
6428 Object* k = dict->KeyAt(i); | |
6429 if (dict->IsKey(k)) { | |
6430 ASSERT(k->IsNumber()); | |
6431 ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0); | |
6432 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0); | |
6433 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32); | |
6434 Object* value = dict->ValueAt(i); | |
6435 uint32_t key = NumberToUint32(k); | |
6436 if (key < limit) { | |
6437 if (value->IsUndefined()) { | |
6438 undefs++; | |
6439 } else { | |
6440 new_dict->AddNumberEntry(pos, value, no_details); | |
6441 pos++; | |
6442 } | |
6443 } else { | |
6444 new_dict->AddNumberEntry(key, value, no_details); | |
6445 } | |
6446 } | |
6447 } | |
6448 | |
6449 uint32_t result = pos; | |
6450 while (undefs > 0) { | |
6451 new_dict->AddNumberEntry(pos, Heap::undefined_value(), no_details); | |
6452 pos++; | |
6453 undefs--; | |
6454 } | |
6455 | |
6456 set_elements(new_dict); | |
6457 | |
6458 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) { | |
6459 return Smi::FromInt(static_cast<int>(result)); | |
6460 } | |
6461 result_double->set_value(static_cast<double>(result)); | |
6462 return result_double; | |
6463 } | |
6464 | |
6465 | |
6466 // Collects all defined (non-hole) and non-undefined (array) elements at | |
6467 // the start of the elements array. | |
6468 // If the object is in dictionary mode, it is converted to fast elements | |
6469 // mode. | |
6470 Object* JSObject::PrepareElementsForSort(uint32_t limit) { | |
6471 if (!HasFastElements()) { | |
6472 // Convert to fast elements containing only the existing properties. | |
6473 // Ordering is irrelevant, since we are going to sort anyway. | |
6474 Dictionary* dict = element_dictionary(); | |
6475 if (dict->requires_slow_elements() || dict->max_number_key() >= limit) { | |
6476 return PrepareSlowElementsForSort(limit); | |
6477 } | |
6478 // Convert to fast elements. | |
6479 | |
6480 PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED: TENURED; | |
6481 Object* new_array = | |
6482 Heap::AllocateFixedArray(dict->NumberOfElements(), tenure); | |
6483 if (new_array->IsFailure()) { | |
6484 return new_array; | |
6485 } | |
6486 FixedArray* fast_elements = FixedArray::cast(new_array); | |
6487 dict->CopyValuesTo(fast_elements); | |
6488 set_elements(fast_elements); | |
6489 } | |
6490 ASSERT(HasFastElements()); | |
6491 | |
6492 // Collect holes at the end, undefined before that and the rest at the | |
6493 // start, and return the number of non-hole, non-undefined values. | |
6494 | |
6495 FixedArray* elements = this->elements(); | |
6496 uint32_t elements_length = static_cast<uint32_t>(elements->length()); | |
6497 if (limit > elements_length ) { | |
6498 limit = elements_length ; | |
Erik Corry
2009/04/27 09:42:13
Do we have a test that excercises this?
| |
6499 } | |
6500 if (limit == 0) { | |
6501 return Smi::FromInt(0); | |
6502 } | |
6503 | |
6504 HeapNumber* result_double; | |
Erik Corry
2009/04/27 09:42:13
And here.
| |
6505 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) { | |
6506 // Pessimistically allocate space for return value before | |
6507 // we start mutating the array. | |
6508 Object* new_double = Heap::AllocateHeapNumber(0.0); | |
6509 if (new_double->IsFailure()) return new_double; | |
6510 result_double = HeapNumber::cast(new_double); | |
6511 } | |
6512 | |
6513 AssertNoAllocation no_alloc; | |
6514 | |
6515 // Split elements into defined, undefined and the_hole, in that order. | |
6516 // Only count locations for undefined and the hole, and fill them afterwards. | |
6517 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(); | |
6518 unsigned int undefs = limit; | |
6519 unsigned int holes = limit; | |
6520 // Assume most arrays contain no holes and undefined values, so minimize the | |
6521 // number of stores of non-undefined, non-the-hole values. | |
6522 for(unsigned int i = 0; i < undefs; i++) { | |
6523 Object* current = elements->get(i); | |
6524 if (current->IsTheHole()) { | |
6525 holes--; | |
6526 undefs--; | |
6527 } else if (current->IsUndefined()) { | |
6528 undefs--; | |
6529 } else { | |
6530 continue; | |
6531 } | |
6532 // Position i needs to be filled. | |
6533 while (undefs > i) { | |
6534 current = elements->get(undefs); | |
6535 if (current->IsTheHole()) { | |
6536 holes--; | |
6537 undefs--; | |
6538 } else if (current->IsUndefined()) { | |
6539 undefs--; | |
6540 } else { | |
6541 elements->set(i, current, write_barrier); | |
6542 break; | |
6543 } | |
6544 } | |
6545 } | |
6546 uint32_t result = undefs; | |
6547 while(undefs < holes) { | |
6548 elements->set_undefined(undefs); | |
6549 undefs++; | |
6550 } | |
6551 while (holes < limit) { | |
6552 elements->set_the_hole(holes); | |
6553 holes++; | |
6554 } | |
6555 | |
6556 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) { | |
6557 return Smi::FromInt(static_cast<int>(result)); | |
6558 } | |
6559 result_double->set_value(static_cast<double>(result)); | |
6560 return result_double; | |
6561 } | |
6562 | |
6563 | |
6446 Object* SymbolTable::LookupString(String* string, Object** s) { | 6564 Object* SymbolTable::LookupString(String* string, Object** s) { |
6447 SymbolKey key(string); | 6565 SymbolKey key(string); |
6448 return LookupKey(&key, s); | 6566 return LookupKey(&key, s); |
6449 } | 6567 } |
6450 | 6568 |
6451 | 6569 |
6452 bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) { | 6570 bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) { |
6453 SymbolKey key(string); | 6571 SymbolKey key(string); |
6454 int entry = FindEntry(&key); | 6572 int entry = FindEntry(&key); |
6455 if (entry == -1) { | 6573 if (entry == -1) { |
(...skipping 956 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7412 // No break point. | 7530 // No break point. |
7413 if (break_point_objects()->IsUndefined()) return 0; | 7531 if (break_point_objects()->IsUndefined()) return 0; |
7414 // Single beak point. | 7532 // Single beak point. |
7415 if (!break_point_objects()->IsFixedArray()) return 1; | 7533 if (!break_point_objects()->IsFixedArray()) return 1; |
7416 // Multiple break points. | 7534 // Multiple break points. |
7417 return FixedArray::cast(break_point_objects())->length(); | 7535 return FixedArray::cast(break_point_objects())->length(); |
7418 } | 7536 } |
7419 #endif | 7537 #endif |
7420 | 7538 |
7421 } } // namespace v8::internal | 7539 } } // namespace v8::internal |
OLD | NEW |