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
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());
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();
+ }
+ }
};
}
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();
+ }
};
uint32_t index,
JSReceiver::DeleteMode mode) = 0;
+ virtual MaybeObject* AddJSArrayKeysToFixedArray(JSArray* other,
+ FixedArray* keys) = 0;
+
// Returns a shared ElementsAccessor for the specified ElementsKind.
static ElementsAccessor* ForKind(JSObject::ElementsKind elements_kind) {
ASSERT(elements_kind < JSObject::kElementsKindCount);
MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
- ASSERT(!array->HasExternalArrayElements());
- switch (array->GetElementsKind()) {
- case JSObject::FAST_ELEMENTS:
- return UnionOfKeys(FixedArray::cast(array->elements()));
- case JSObject::FAST_DOUBLE_ELEMENTS:
- return UnionOfDoubleKeys(FixedDoubleArray::cast(array->elements()));
- break;
- case JSObject::DICTIONARY_ELEMENTS: {
- NumberDictionary* dict = array->element_dictionary();
- int size = dict->NumberOfElements();
-
- // Allocate a temporary fixed array.
- Object* object;
- { MaybeObject* maybe_object = GetHeap()->AllocateFixedArray(size);
- if (!maybe_object->ToObject(&object)) return maybe_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 < 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);
- }
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
- UNIMPLEMENTED();
- break;
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- break;
- }
- UNREACHABLE();
- return GetHeap()->null_value(); // Failure case needs to "return" a value.
+ return array->GetElementsAccessor()->AddJSArrayKeysToFixedArray(array, this);
}
}
-MaybeObject* FixedArray::UnionOfDoubleKeys(FixedDoubleArray* other) {
- int len0 = length();
-#ifdef DEBUG
- if (FLAG_enable_slow_asserts) {
- for (int i = 0; i < len0; i++) {
- ASSERT(get(i)->IsString() || get(i)->IsNumber());
- }
- }
-#endif
- int len1 = other->length();
- // Optimize if 'other' is empty.
- // We cannot optimize if 'this' is empty, as other may have holes
- // or non keys.
- if (len1 == 0) return this;
-
- // Compute how many elements are not in this.
- int extra = 0;
- Heap* heap = GetHeap();
- Object* obj;
- for (int y = 0; y < len1; y++) {
- if (!other->is_the_hole(y)) {
- MaybeObject* maybe_obj = heap->NumberFromDouble(other->get_scalar(y));
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- if (!HasKey(this, obj)) extra++;
- }
- }
-
- if (extra == 0) return this;
-
- // Allocate the result
- { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(len0 + extra);
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
- // Fill in the content
- FixedArray* result = FixedArray::cast(obj);
- {
- // Limit the scope of the AssertNoAllocation
- AssertNoAllocation no_gc;
- WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
- for (int i = 0; i < len0; i++) {
- Object* e = 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++) {
- if (!other->is_the_hole(y)) {
- MaybeObject* maybe_obj = heap->NumberFromDouble(other->get_scalar(y));
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- if (!HasKey(this, obj)) {
- result->set(len0 + index, obj);
- index++;
- }
- }
- }
- ASSERT(extra == index);
- return result;
-}
-
-
MaybeObject* FixedArray::CopySize(int new_length) {
Heap* heap = GetHeap();
if (new_length == 0) return heap->empty_fixed_array();
// Compute the union of this and other.
MUST_USE_RESULT MaybeObject* UnionOfKeys(FixedArray* other);
- // Compute the union of this and other.
- MUST_USE_RESULT MaybeObject* UnionOfDoubleKeys(
- FixedDoubleArray* other);
-
// Copy a sub array from the receiver to dest.
void CopyTo(int pos, FixedArray* dest, int dest_pos, int len);