Index: src/elements.cc |
diff --git a/src/elements.cc b/src/elements.cc |
index 45ab2d9aa8a30e9b1ef2f7dfed104e1c19633d2a..9cfcceec24cadeea63fd15c452cff71a3b08caf8 100644 |
--- a/src/elements.cc |
+++ b/src/elements.cc |
@@ -37,6 +37,20 @@ namespace internal { |
ElementsAccessor** ElementsAccessor::elements_accessors_; |
+bool HasKey(FixedArray* array, Object* key) { |
+ int len0 = array->length(); |
+ for (int i = 0; i < len0; i++) { |
+ Object* element = array->get(i); |
+ if (element->IsSmi() && element == key) return true; |
+ if (element->IsString() && |
+ key->IsString() && String::cast(element)->Equals(String::cast(key))) { |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
+ |
// Base class for element handler implementations. Contains the |
// the common logic for objects with different ElementsKinds. |
// Subclasses must specialize method for which the element |
@@ -73,6 +87,78 @@ class ElementsAccessorBase : public ElementsAccessor { |
uint32_t index, |
JSReceiver::DeleteMode mode) = 0; |
+ virtual MaybeObject* AddJSArrayKeysToFixedArray(JSArray* other, |
+ FixedArray* keys) { |
+ int len0 = keys->length(); |
+#ifdef DEBUG |
+ if (FLAG_enable_slow_asserts) { |
+ for (int i = 0; i < len0; i++) { |
+ ASSERT(keys->get(i)->IsString() || keys->get(i)->IsNumber()); |
+ } |
+ } |
+#endif |
+ int len1 = ElementsAccessorSubclass::GetCapacity(other); |
+ |
+ // Optimize if 'other' is empty. |
+ // We cannot optimize if 'this' is empty, as other may have holes |
+ // or non keys. |
+ if (len1 == 0) return keys; |
+ |
+ // Compute how many elements are not in other. |
+ int extra = 0; |
+ for (int y = 0; y < len1; y++) { |
+ Object* value; |
+ MaybeObject* maybe_value = |
+ ElementsAccessorSubclass::GetElementAtCapacityIndex(other, y); |
+ if (!maybe_value->ToObject(&value)) return maybe_value; |
+ if (!value->IsTheHole() && !HasKey(keys, value)) extra++; |
+ } |
+ |
+ if (extra == 0) return keys; |
+ |
+ // Allocate the result |
+ FixedArray* result; |
+ MaybeObject* maybe_obj = |
+ other->GetHeap()->AllocateFixedArray(len0 + extra); |
+ if (!maybe_obj->To<FixedArray>(&result)) return maybe_obj; |
+ |
+ // Fill in the content |
+ { |
+ AssertNoAllocation no_gc; |
+ WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); |
+ for (int i = 0; i < len0; i++) { |
+ Object* e = keys->get(i); |
+ ASSERT(e->IsString() || e->IsNumber()); |
+ result->set(i, e, mode); |
+ } |
+ } |
+ // Fill in the extra keys. |
+ int index = 0; |
+ for (int y = 0; y < len1; y++) { |
+ MaybeObject* maybe_value = |
+ ElementsAccessorSubclass::GetElementAtCapacityIndex(other, y); |
+ Object* value; |
+ if (!maybe_value->ToObject(&value)) return maybe_value; |
+ if (!value->IsTheHole() && !HasKey(keys, value)) { |
+ ASSERT(value->IsString() || value->IsNumber()); |
+ result->set(len0 + index, value); |
+ index++; |
+ } |
+ } |
+ ASSERT(extra == index); |
+ return result; |
+ } |
+ |
+ static uint32_t GetCapacity(JSObject* obj) { |
+ return ElementsAccessorSubclass::GetBackingStore(obj)->length(); |
+ } |
+ |
+ static MaybeObject* GetElementAtCapacityIndex(JSObject* obj, int index) { |
+ BackingStoreClass* backing_store = |
+ ElementsAccessorSubclass::GetBackingStore(obj); |
+ return backing_store->get(index); |
+ } |
+ |
protected: |
static BackingStoreClass* GetBackingStore(JSObject* obj) { |
return BackingStoreClass::cast(obj->elements()); |
@@ -325,6 +411,19 @@ class DictionaryElementsAccessor |
obj->element_dictionary(), |
index); |
} |
+ |
+ static uint32_t GetCapacity(JSObject* obj) { |
+ return obj->element_dictionary()->Capacity(); |
+ } |
+ |
+ static MaybeObject* GetElementAtCapacityIndex(JSObject* obj, int index) { |
+ NumberDictionary* dict = obj->element_dictionary(); |
+ if (dict->IsKey(dict->KeyAt(index))) { |
+ return dict->ValueAt(index); |
+ } else { |
+ return obj->GetHeap()->the_hole_value(); |
+ } |
+ } |
}; |
@@ -382,6 +481,18 @@ class NonStrictArgumentsElementsAccessor |
} |
return obj->GetHeap()->true_value(); |
} |
+ |
+ static uint32_t GetCapacity(JSObject* obj) { |
+ // TODO(danno): Return max of parameter map length or backing store |
+ // capacity. |
+ return 0; |
+ } |
+ |
+ static MaybeObject* GetElementAtCapacityIndex(JSObject* obj, int index) { |
+ // TODO(danno): Return either value from parameter map of backing |
+ // store value at index. |
+ return obj->GetHeap()->the_hole_value(); |
+ } |
}; |