Chromium Code Reviews| 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 |