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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/objects.h ('k') | src/runtime.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/objects.cc
diff --git a/src/objects.cc b/src/objects.cc
index 31c5babec9047a9fa84460e46294b6359a52b50c..689c40923220334190f2c4fe26fc0fec87535202 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -2845,22 +2845,26 @@ static bool HasKey(FixedArray* array, Object* key) {
Object* FixedArray::AddKeysFromJSArray(JSArray* array) {
- // Remove array holes from array if any.
- Object* object = array->RemoveHoles();
- if (object->IsFailure()) return object;
- JSArray* compacted_array = JSArray::cast(object);
+ if (array->HasFastElements()) {
+ return UnionOfKeys(array->elements());
+ }
+ ASSERT(!array->HasFastElements());
+ Dictionary* dict = array->element_dictionary();
+ int size = dict->NumberOfElements();
// Allocate a temporary fixed array.
- int compacted_array_length = Smi::cast(compacted_array->length())->value();
- object = Heap::AllocateFixedArray(compacted_array_length);
+ Object* object = Heap::AllocateFixedArray(size);
if (object->IsFailure()) return object;
FixedArray* key_array = FixedArray::cast(object);
+ int capacity = dict->Capacity();
+ int pos = 0;
// Copy the elements from the JSArray to the temporary fixed array.
- for (int i = 0; i < compacted_array_length; i++) {
- key_array->set(i, compacted_array->GetElement(i));
+ for (int i = 0; i < capacity; i++) {
+ if (dict->IsKey(dict->KeyAt(i))) {
+ key_array->set(pos++, dict->ValueAt(i));
+ }
}
-
// Compute the union of this and the temporary fixed array.
return UnionOfKeys(key_array);
}
@@ -2876,9 +2880,12 @@ Object* FixedArray::UnionOfKeys(FixedArray* other) {
// Compute how many elements are not in this.
int extra = 0;
for (int y = 0; y < len1; y++) {
- if (!HasKey(this, other->get(y))) extra++;
+ Object* value = other->get(y);
+ if (!value->IsTheHole() && !HasKey(this, value)) extra++;
}
+ if (extra == 0) return this;
+
// Allocate the result
Object* obj = Heap::AllocateFixedArray(len0 + extra);
if (obj->IsFailure()) return obj;
@@ -2891,7 +2898,8 @@ Object* FixedArray::UnionOfKeys(FixedArray* other) {
// Fill in the extra keys.
int index = 0;
for (int y = 0; y < len1; y++) {
- if (!HasKey(this, other->get(y))) {
+ Object* value = other->get(y);
+ if (!value->IsTheHole() && !HasKey(this, value)) {
result->set(len0 + index, other->get(y), mode);
index++;
}
@@ -5623,75 +5631,18 @@ bool JSObject::ShouldConvertToFastElements() {
}
-Object* Dictionary::RemoveHoles() {
- int capacity = Capacity();
- Object* obj = Allocate(NumberOfElements());
- if (obj->IsFailure()) return obj;
- Dictionary* dict = Dictionary::cast(obj);
- uint32_t pos = 0;
- for (int i = 0; i < capacity; i++) {
- Object* k = KeyAt(i);
- if (IsKey(k)) {
- dict->AddNumberEntry(pos++, ValueAt(i), DetailsAt(i));
- }
- }
- return dict;
-}
-
-
void Dictionary::CopyValuesTo(FixedArray* elements) {
int pos = 0;
int capacity = Capacity();
+ WriteBarrierMode mode = elements->GetWriteBarrierMode();
for (int i = 0; i < capacity; i++) {
Object* k = KeyAt(i);
- if (IsKey(k)) elements->set(pos++, ValueAt(i));
+ if (IsKey(k)) elements->set(pos++, ValueAt(i), mode);
}
ASSERT(pos == elements->length());
}
-Object* JSArray::RemoveHoles() {
- if (HasFastElements()) {
- int len = Smi::cast(length())->value();
- int pos = 0;
- FixedArray* elms = FixedArray::cast(elements());
- for (int index = 0; index < len; index++) {
- Object* e = elms->get(index);
- if (!e->IsTheHole()) {
- if (index != pos) elms->set(pos, e);
- pos++;
- }
- }
- set_length(Smi::FromInt(pos), SKIP_WRITE_BARRIER);
- for (int index = pos; index < len; index++) {
- elms->set_the_hole(index);
- }
- return this;
- }
-
- // Compact the sparse array if possible.
- Dictionary* dict = element_dictionary();
- int length = dict->NumberOfElements();
-
- // Try to make this a fast array again.
- if (length <= kMaxFastElementsLength) {
- Object* obj = Heap::AllocateFixedArray(length);
- if (obj->IsFailure()) return obj;
- dict->CopyValuesTo(FixedArray::cast(obj));
- set_length(Smi::FromInt(length), SKIP_WRITE_BARRIER);
- set_elements(FixedArray::cast(obj));
- return this;
- }
-
- // Make another dictionary with smaller indices.
- Object* obj = dict->RemoveHoles();
- if (obj->IsFailure()) return obj;
- set_length(Smi::FromInt(length), SKIP_WRITE_BARRIER);
- set_elements(Dictionary::cast(obj));
- return this;
-}
-
-
InterceptorInfo* JSObject::GetNamedInterceptor() {
ASSERT(map()->has_named_interceptor());
JSFunction* constructor = JSFunction::cast(map()->constructor());
@@ -6443,6 +6394,173 @@ template class HashTable<2, 3>;
template class HashTable<0, 2>;
+// Collates undefined and unexisting elements below limit from position
+// zero of the elements. The object stays in Dictionary mode.
+Object* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
+ static const uint32_t kMaxUInt32 = 4294967295u;
Erik Corry 2009/04/27 09:42:13 This should probably go next to kMaxInt in globals
+ ASSERT(!HasFastElements());
+ // Must stay in dictionary mode, either because of requires_slow_elements,
+ // or because we are not going to sort (and therefore compact) all of the
+ // elements.
+ Dictionary* dict = element_dictionary();
+ HeapNumber* result_double;
Erik Corry 2009/04/27 09:42:13 Please initialize to NULL and ASSERT it is not nul
+ if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
+ // Allocate space for result before we start mutating the object.
+ Object* new_double = Heap::AllocateHeapNumber(0.0);
+ if (new_double->IsFailure()) return new_double;
+ result_double = HeapNumber::cast(new_double);
+ }
+
+ int capacity = dict->Capacity();
+ Object* obj = Dictionary::Allocate(dict->Capacity());
+ if (obj->IsFailure()) return obj;
+ Dictionary* new_dict = Dictionary::cast(obj);
+
+ AssertNoAllocation no_alloc;
+
+ // Loose all details on properties when moving them around.
+ // Elements do not have special details like properties.
+ PropertyDetails no_details = PropertyDetails(NONE, NORMAL);
+
+ uint32_t pos = 0;
+ uint32_t undefs = 0;
+ for (int i = 0; i < capacity; i++) {
+ Object* k = dict->KeyAt(i);
+ if (dict->IsKey(k)) {
+ ASSERT(k->IsNumber());
+ ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
+ ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
+ ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
+ Object* value = dict->ValueAt(i);
+ uint32_t key = NumberToUint32(k);
+ if (key < limit) {
+ if (value->IsUndefined()) {
+ undefs++;
+ } else {
+ new_dict->AddNumberEntry(pos, value, no_details);
+ pos++;
+ }
+ } else {
+ new_dict->AddNumberEntry(key, value, no_details);
+ }
+ }
+ }
+
+ uint32_t result = pos;
+ while (undefs > 0) {
+ new_dict->AddNumberEntry(pos, Heap::undefined_value(), no_details);
+ pos++;
+ undefs--;
+ }
+
+ set_elements(new_dict);
+
+ if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
+ return Smi::FromInt(static_cast<int>(result));
+ }
+ result_double->set_value(static_cast<double>(result));
+ return result_double;
+}
+
+
+// Collects all defined (non-hole) and non-undefined (array) elements at
+// the start of the elements array.
+// If the object is in dictionary mode, it is converted to fast elements
+// mode.
+Object* JSObject::PrepareElementsForSort(uint32_t limit) {
+ if (!HasFastElements()) {
+ // Convert to fast elements containing only the existing properties.
+ // Ordering is irrelevant, since we are going to sort anyway.
+ Dictionary* dict = element_dictionary();
+ if (dict->requires_slow_elements() || dict->max_number_key() >= limit) {
+ return PrepareSlowElementsForSort(limit);
+ }
+ // Convert to fast elements.
+
+ PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED: TENURED;
+ Object* new_array =
+ Heap::AllocateFixedArray(dict->NumberOfElements(), tenure);
+ if (new_array->IsFailure()) {
+ return new_array;
+ }
+ FixedArray* fast_elements = FixedArray::cast(new_array);
+ dict->CopyValuesTo(fast_elements);
+ set_elements(fast_elements);
+ }
+ ASSERT(HasFastElements());
+
+ // Collect holes at the end, undefined before that and the rest at the
+ // start, and return the number of non-hole, non-undefined values.
+
+ FixedArray* elements = this->elements();
+ uint32_t elements_length = static_cast<uint32_t>(elements->length());
+ if (limit > elements_length ) {
+ limit = elements_length ;
Erik Corry 2009/04/27 09:42:13 Do we have a test that excercises this?
+ }
+ if (limit == 0) {
+ return Smi::FromInt(0);
+ }
+
+ HeapNumber* result_double;
Erik Corry 2009/04/27 09:42:13 And here.
+ if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
+ // Pessimistically allocate space for return value before
+ // we start mutating the array.
+ Object* new_double = Heap::AllocateHeapNumber(0.0);
+ if (new_double->IsFailure()) return new_double;
+ result_double = HeapNumber::cast(new_double);
+ }
+
+ AssertNoAllocation no_alloc;
+
+ // Split elements into defined, undefined and the_hole, in that order.
+ // Only count locations for undefined and the hole, and fill them afterwards.
+ WriteBarrierMode write_barrier = elements->GetWriteBarrierMode();
+ unsigned int undefs = limit;
+ unsigned int holes = limit;
+ // Assume most arrays contain no holes and undefined values, so minimize the
+ // number of stores of non-undefined, non-the-hole values.
+ for(unsigned int i = 0; i < undefs; i++) {
+ Object* current = elements->get(i);
+ if (current->IsTheHole()) {
+ holes--;
+ undefs--;
+ } else if (current->IsUndefined()) {
+ undefs--;
+ } else {
+ continue;
+ }
+ // Position i needs to be filled.
+ while (undefs > i) {
+ current = elements->get(undefs);
+ if (current->IsTheHole()) {
+ holes--;
+ undefs--;
+ } else if (current->IsUndefined()) {
+ undefs--;
+ } else {
+ elements->set(i, current, write_barrier);
+ break;
+ }
+ }
+ }
+ uint32_t result = undefs;
+ while(undefs < holes) {
+ elements->set_undefined(undefs);
+ undefs++;
+ }
+ while (holes < limit) {
+ elements->set_the_hole(holes);
+ holes++;
+ }
+
+ if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
+ return Smi::FromInt(static_cast<int>(result));
+ }
+ result_double->set_value(static_cast<double>(result));
+ return result_double;
+}
+
+
Object* SymbolTable::LookupString(String* string, Object** s) {
SymbolKey key(string);
return LookupKey(&key, s);
« 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