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

Side by Side Diff: src/objects.cc

Issue 92123: Fix Issue 326. Handle sorting of non-array objects correctly. (Closed)
Patch Set: Simplified fixed-array collation loop. Added more tests for dictionary. Created 11 years, 8 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
« no previous file with comments | « src/objects.h ('k') | src/runtime.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 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
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
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
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
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
OLDNEW
« no previous file with comments | « src/objects.h ('k') | src/runtime.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698