| Index: src/objects.cc
|
| ===================================================================
|
| --- src/objects.cc (revision 2544)
|
| +++ src/objects.cc (working copy)
|
| @@ -1006,6 +1006,9 @@
|
| case BYTE_ARRAY_TYPE:
|
| accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
|
| break;
|
| + case PIXEL_ARRAY_TYPE:
|
| + accumulator->Add("<PixelArray[%u]>", PixelArray::cast(this)->length());
|
| + break;
|
| case SHARED_FUNCTION_INFO_TYPE:
|
| accumulator->Add("<SharedFunctionInfo>");
|
| break;
|
| @@ -1147,6 +1150,7 @@
|
| case HEAP_NUMBER_TYPE:
|
| case FILLER_TYPE:
|
| case BYTE_ARRAY_TYPE:
|
| + case PIXEL_ARRAY_TYPE:
|
| break;
|
| case SHARED_FUNCTION_INFO_TYPE: {
|
| SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(this);
|
| @@ -1669,7 +1673,9 @@
|
| for (Object* pt = GetPrototype();
|
| pt != Heap::null_value();
|
| pt = pt->GetPrototype()) {
|
| - if (JSObject::cast(pt)->HasFastElements()) continue;
|
| + if (!JSObject::cast(pt)->HasDictionaryElements()) {
|
| + continue;
|
| + }
|
| NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary();
|
| int entry = dictionary->FindEntry(index);
|
| if (entry != NumberDictionary::kNotFound) {
|
| @@ -2231,7 +2237,8 @@
|
|
|
|
|
| Object* JSObject::NormalizeElements() {
|
| - if (!HasFastElements()) return this;
|
| + ASSERT(!HasPixelElements());
|
| + if (HasDictionaryElements()) return this;
|
|
|
| // Get number of entries.
|
| FixedArray* array = FixedArray::cast(elements());
|
| @@ -2317,21 +2324,29 @@
|
|
|
| Object* JSObject::DeleteElementPostInterceptor(uint32_t index,
|
| DeleteMode mode) {
|
| - if (HasFastElements()) {
|
| - uint32_t length = IsJSArray() ?
|
| + ASSERT(!HasPixelElements());
|
| + switch (GetElementsKind()) {
|
| + case FAST_ELEMENTS: {
|
| + uint32_t length = IsJSArray() ?
|
| static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) :
|
| static_cast<uint32_t>(FixedArray::cast(elements())->length());
|
| - if (index < length) {
|
| - FixedArray::cast(elements())->set_the_hole(index);
|
| + if (index < length) {
|
| + FixedArray::cast(elements())->set_the_hole(index);
|
| + }
|
| + break;
|
| }
|
| - return Heap::true_value();
|
| + case DICTIONARY_ELEMENTS: {
|
| + NumberDictionary* dictionary = element_dictionary();
|
| + int entry = dictionary->FindEntry(index);
|
| + if (entry != NumberDictionary::kNotFound) {
|
| + return dictionary->DeleteProperty(entry, mode);
|
| + }
|
| + break;
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| }
|
| - ASSERT(!HasFastElements());
|
| - NumberDictionary* dictionary = element_dictionary();
|
| - int entry = dictionary->FindEntry(index);
|
| - if (entry != NumberDictionary::kNotFound) {
|
| - return dictionary->DeleteProperty(entry, mode);
|
| - }
|
| return Heap::true_value();
|
| }
|
|
|
| @@ -2392,20 +2407,31 @@
|
| return DeleteElementWithInterceptor(index);
|
| }
|
|
|
| - if (HasFastElements()) {
|
| - uint32_t length = IsJSArray() ?
|
| + switch (GetElementsKind()) {
|
| + case FAST_ELEMENTS: {
|
| + uint32_t length = IsJSArray() ?
|
| static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) :
|
| static_cast<uint32_t>(FixedArray::cast(elements())->length());
|
| - if (index < length) {
|
| - FixedArray::cast(elements())->set_the_hole(index);
|
| + if (index < length) {
|
| + FixedArray::cast(elements())->set_the_hole(index);
|
| + }
|
| + break;
|
| }
|
| - return Heap::true_value();
|
| - } else {
|
| - NumberDictionary* dictionary = element_dictionary();
|
| - int entry = dictionary->FindEntry(index);
|
| - if (entry != NumberDictionary::kNotFound) {
|
| - return dictionary->DeleteProperty(entry, mode);
|
| + case PIXEL_ELEMENTS: {
|
| + // Pixel elements cannot be deleted. Just silently ignore here.
|
| + break;
|
| }
|
| + case DICTIONARY_ELEMENTS: {
|
| + NumberDictionary* dictionary = element_dictionary();
|
| + int entry = dictionary->FindEntry(index);
|
| + if (entry != NumberDictionary::kNotFound) {
|
| + return dictionary->DeleteProperty(entry, mode);
|
| + }
|
| + break;
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| }
|
| return Heap::true_value();
|
| }
|
| @@ -2483,21 +2509,32 @@
|
| }
|
|
|
| // Check if the object is among the indexed properties.
|
| - if (HasFastElements()) {
|
| - int length = IsJSArray()
|
| - ? Smi::cast(JSArray::cast(this)->length())->value()
|
| - : FixedArray::cast(elements())->length();
|
| - for (int i = 0; i < length; i++) {
|
| - Object* element = FixedArray::cast(elements())->get(i);
|
| - if (!element->IsTheHole() && element == obj) {
|
| + switch (GetElementsKind()) {
|
| + case PIXEL_ELEMENTS:
|
| + // Raw pixels do not reference other objects.
|
| + break;
|
| + case FAST_ELEMENTS: {
|
| + int length = IsJSArray() ?
|
| + Smi::cast(JSArray::cast(this)->length())->value() :
|
| + FixedArray::cast(elements())->length();
|
| + for (int i = 0; i < length; i++) {
|
| + Object* element = FixedArray::cast(elements())->get(i);
|
| + if (!element->IsTheHole() && element == obj) {
|
| + return true;
|
| + }
|
| + }
|
| + break;
|
| + }
|
| + case DICTIONARY_ELEMENTS: {
|
| + key = element_dictionary()->SlowReverseLookup(obj);
|
| + if (key != Heap::undefined_value()) {
|
| return true;
|
| }
|
| + break;
|
| }
|
| - } else {
|
| - key = element_dictionary()->SlowReverseLookup(obj);
|
| - if (key != Heap::undefined_value()) {
|
| - return true;
|
| - }
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| }
|
|
|
| // For functions check the context. Boilerplate functions do
|
| @@ -2715,20 +2752,31 @@
|
| if (is_element && IsJSArray()) return Heap::undefined_value();
|
|
|
| if (is_element) {
|
| - // Lookup the index.
|
| - if (!HasFastElements()) {
|
| - NumberDictionary* dictionary = element_dictionary();
|
| - int entry = dictionary->FindEntry(index);
|
| - if (entry != NumberDictionary::kNotFound) {
|
| - Object* result = dictionary->ValueAt(entry);
|
| - PropertyDetails details = dictionary->DetailsAt(entry);
|
| - if (details.IsReadOnly()) return Heap::undefined_value();
|
| - if (details.type() == CALLBACKS) {
|
| - // Only accessors allowed as elements.
|
| - ASSERT(result->IsFixedArray());
|
| - return result;
|
| + switch (GetElementsKind()) {
|
| + case FAST_ELEMENTS:
|
| + break;
|
| + case PIXEL_ELEMENTS:
|
| + // Ignore getters and setters on pixel elements.
|
| + return Heap::undefined_value();
|
| + case DICTIONARY_ELEMENTS: {
|
| + // Lookup the index.
|
| + NumberDictionary* dictionary = element_dictionary();
|
| + int entry = dictionary->FindEntry(index);
|
| + if (entry != NumberDictionary::kNotFound) {
|
| + Object* result = dictionary->ValueAt(entry);
|
| + PropertyDetails details = dictionary->DetailsAt(entry);
|
| + if (details.IsReadOnly()) return Heap::undefined_value();
|
| + if (details.type() == CALLBACKS) {
|
| + // Only accessors allowed as elements.
|
| + ASSERT(result->IsFixedArray());
|
| + return result;
|
| + }
|
| }
|
| + break;
|
| }
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| }
|
| } else {
|
| // Lookup the name.
|
| @@ -2827,9 +2875,9 @@
|
| for (Object* obj = this;
|
| obj != Heap::null_value();
|
| obj = JSObject::cast(obj)->GetPrototype()) {
|
| - JSObject* jsObject = JSObject::cast(obj);
|
| - if (!jsObject->HasFastElements()) {
|
| - NumberDictionary* dictionary = jsObject->element_dictionary();
|
| + JSObject* js_object = JSObject::cast(obj);
|
| + if (js_object->HasDictionaryElements()) {
|
| + NumberDictionary* dictionary = js_object->element_dictionary();
|
| int entry = dictionary->FindEntry(index);
|
| if (entry != NumberDictionary::kNotFound) {
|
| Object* element = dictionary->ValueAt(entry);
|
| @@ -3029,28 +3077,35 @@
|
|
|
|
|
| Object* FixedArray::AddKeysFromJSArray(JSArray* array) {
|
| - if (array->HasFastElements()) {
|
| - return UnionOfKeys(array->elements());
|
| - }
|
| - ASSERT(!array->HasFastElements());
|
| - NumberDictionary* dict = array->element_dictionary();
|
| - int size = dict->NumberOfElements();
|
| -
|
| - // Allocate a temporary fixed array.
|
| - 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 < capacity; i++) {
|
| - if (dict->IsKey(dict->KeyAt(i))) {
|
| - key_array->set(pos++, dict->ValueAt(i));
|
| + ASSERT(!array->HasPixelElements());
|
| + switch (array->GetElementsKind()) {
|
| + case JSObject::FAST_ELEMENTS:
|
| + return UnionOfKeys(FixedArray::cast(array->elements()));
|
| + case JSObject::DICTIONARY_ELEMENTS: {
|
| + NumberDictionary* dict = array->element_dictionary();
|
| + int size = dict->NumberOfElements();
|
| +
|
| + // Allocate a temporary fixed array.
|
| + 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 < 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);
|
| }
|
| + default:
|
| + UNREACHABLE();
|
| }
|
| - // Compute the union of this and the temporary fixed array.
|
| - return UnionOfKeys(key_array);
|
| + UNREACHABLE();
|
| + return Heap::null_value(); // Failure case needs to "return" a value.
|
| }
|
|
|
|
|
| @@ -5089,54 +5144,74 @@
|
|
|
|
|
| void JSObject::SetFastElements(FixedArray* elems) {
|
| + // We should never end in here with a pixel array.
|
| + ASSERT(!HasPixelElements());
|
| #ifdef DEBUG
|
| // Check the provided array is filled with the_hole.
|
| uint32_t len = static_cast<uint32_t>(elems->length());
|
| for (uint32_t i = 0; i < len; i++) ASSERT(elems->get(i)->IsTheHole());
|
| #endif
|
| WriteBarrierMode mode = elems->GetWriteBarrierMode();
|
| - if (HasFastElements()) {
|
| - FixedArray* old_elements = FixedArray::cast(elements());
|
| - uint32_t old_length = static_cast<uint32_t>(old_elements->length());
|
| - // Fill out the new array with this content and array holes.
|
| - for (uint32_t i = 0; i < old_length; i++) {
|
| - elems->set(i, old_elements->get(i), mode);
|
| + switch (GetElementsKind()) {
|
| + case FAST_ELEMENTS: {
|
| + FixedArray* old_elements = FixedArray::cast(elements());
|
| + uint32_t old_length = static_cast<uint32_t>(old_elements->length());
|
| + // Fill out the new array with this content and array holes.
|
| + for (uint32_t i = 0; i < old_length; i++) {
|
| + elems->set(i, old_elements->get(i), mode);
|
| + }
|
| + break;
|
| }
|
| - } else {
|
| - NumberDictionary* dictionary = NumberDictionary::cast(elements());
|
| - for (int i = 0; i < dictionary->Capacity(); i++) {
|
| - Object* key = dictionary->KeyAt(i);
|
| - if (key->IsNumber()) {
|
| - uint32_t entry = static_cast<uint32_t>(key->Number());
|
| - elems->set(entry, dictionary->ValueAt(i), mode);
|
| + case DICTIONARY_ELEMENTS: {
|
| + NumberDictionary* dictionary = NumberDictionary::cast(elements());
|
| + for (int i = 0; i < dictionary->Capacity(); i++) {
|
| + Object* key = dictionary->KeyAt(i);
|
| + if (key->IsNumber()) {
|
| + uint32_t entry = static_cast<uint32_t>(key->Number());
|
| + elems->set(entry, dictionary->ValueAt(i), mode);
|
| + }
|
| }
|
| + break;
|
| }
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| }
|
| set_elements(elems);
|
| }
|
|
|
|
|
| Object* JSObject::SetSlowElements(Object* len) {
|
| + // We should never end in here with a pixel array.
|
| + ASSERT(!HasPixelElements());
|
| +
|
| uint32_t new_length = static_cast<uint32_t>(len->Number());
|
|
|
| - if (!HasFastElements()) {
|
| - if (IsJSArray()) {
|
| - uint32_t old_length =
|
| - static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
|
| - element_dictionary()->RemoveNumberEntries(new_length, old_length),
|
| - JSArray::cast(this)->set_length(len);
|
| + switch (GetElementsKind()) {
|
| + case FAST_ELEMENTS: {
|
| + // Make sure we never try to shrink dense arrays into sparse arrays.
|
| + ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <=
|
| + new_length);
|
| + Object* obj = NormalizeElements();
|
| + if (obj->IsFailure()) return obj;
|
| +
|
| + // Update length for JSArrays.
|
| + if (IsJSArray()) JSArray::cast(this)->set_length(len);
|
| + break;
|
| }
|
| - return this;
|
| + case DICTIONARY_ELEMENTS: {
|
| + if (IsJSArray()) {
|
| + uint32_t old_length =
|
| + static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
|
| + element_dictionary()->RemoveNumberEntries(new_length, old_length),
|
| + JSArray::cast(this)->set_length(len);
|
| + }
|
| + break;
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| }
|
| -
|
| - // Make sure we never try to shrink dense arrays into sparse arrays.
|
| - ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <=
|
| - new_length);
|
| - Object* obj = NormalizeElements();
|
| - if (obj->IsFailure()) return obj;
|
| -
|
| - // Update length for JSArrays.
|
| - if (IsJSArray()) JSArray::cast(this)->set_length(len);
|
| return this;
|
| }
|
|
|
| @@ -5159,7 +5234,7 @@
|
|
|
| void JSArray::Expand(int required_size) {
|
| Handle<JSArray> self(this);
|
| - Handle<FixedArray> old_backing(elements());
|
| + Handle<FixedArray> old_backing(FixedArray::cast(elements()));
|
| int old_size = old_backing->length();
|
| // Doubling in size would be overkill, but leave some slack to avoid
|
| // constantly growing.
|
| @@ -5186,52 +5261,62 @@
|
|
|
|
|
| Object* JSObject::SetElementsLength(Object* len) {
|
| + // We should never end in here with a pixel array.
|
| + ASSERT(!HasPixelElements());
|
| +
|
| Object* smi_length = len->ToSmi();
|
| if (smi_length->IsSmi()) {
|
| int value = Smi::cast(smi_length)->value();
|
| if (value < 0) return ArrayLengthRangeError();
|
| - if (HasFastElements()) {
|
| - int old_capacity = FixedArray::cast(elements())->length();
|
| - if (value <= old_capacity) {
|
| + switch (GetElementsKind()) {
|
| + case FAST_ELEMENTS: {
|
| + int old_capacity = FixedArray::cast(elements())->length();
|
| + if (value <= old_capacity) {
|
| + if (IsJSArray()) {
|
| + int old_length = FastD2I(JSArray::cast(this)->length()->Number());
|
| + // NOTE: We may be able to optimize this by removing the
|
| + // last part of the elements backing storage array and
|
| + // setting the capacity to the new size.
|
| + for (int i = value; i < old_length; i++) {
|
| + FixedArray::cast(elements())->set_the_hole(i);
|
| + }
|
| + JSArray::cast(this)->set_length(smi_length, SKIP_WRITE_BARRIER);
|
| + }
|
| + return this;
|
| + }
|
| + int min = NewElementsCapacity(old_capacity);
|
| + int new_capacity = value > min ? value : min;
|
| + if (new_capacity <= kMaxFastElementsLength ||
|
| + !ShouldConvertToSlowElements(new_capacity)) {
|
| + Object* obj = Heap::AllocateFixedArrayWithHoles(new_capacity);
|
| + if (obj->IsFailure()) return obj;
|
| + if (IsJSArray()) JSArray::cast(this)->set_length(smi_length,
|
| + SKIP_WRITE_BARRIER);
|
| + SetFastElements(FixedArray::cast(obj));
|
| + return this;
|
| + }
|
| + break;
|
| + }
|
| + case DICTIONARY_ELEMENTS: {
|
| if (IsJSArray()) {
|
| - int old_length = FastD2I(JSArray::cast(this)->length()->Number());
|
| - // NOTE: We may be able to optimize this by removing the
|
| - // last part of the elements backing storage array and
|
| - // setting the capacity to the new size.
|
| - for (int i = value; i < old_length; i++) {
|
| - FixedArray::cast(elements())->set_the_hole(i);
|
| + if (value == 0) {
|
| + // If the length of a slow array is reset to zero, we clear
|
| + // the array and flush backing storage. This has the added
|
| + // benefit that the array returns to fast mode.
|
| + initialize_elements();
|
| + } else {
|
| + // Remove deleted elements.
|
| + uint32_t old_length =
|
| + static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
|
| + element_dictionary()->RemoveNumberEntries(value, old_length);
|
| }
|
| JSArray::cast(this)->set_length(smi_length, SKIP_WRITE_BARRIER);
|
| }
|
| return this;
|
| }
|
| - int min = NewElementsCapacity(old_capacity);
|
| - int new_capacity = value > min ? value : min;
|
| - if (new_capacity <= kMaxFastElementsLength ||
|
| - !ShouldConvertToSlowElements(new_capacity)) {
|
| - Object* obj = Heap::AllocateFixedArrayWithHoles(new_capacity);
|
| - if (obj->IsFailure()) return obj;
|
| - if (IsJSArray()) JSArray::cast(this)->set_length(smi_length,
|
| - SKIP_WRITE_BARRIER);
|
| - SetFastElements(FixedArray::cast(obj));
|
| - return this;
|
| - }
|
| - } else {
|
| - if (IsJSArray()) {
|
| - if (value == 0) {
|
| - // If the length of a slow array is reset to zero, we clear
|
| - // the array and flush backing storage. This has the added
|
| - // benefit that the array returns to fast mode.
|
| - initialize_elements();
|
| - } else {
|
| - // Remove deleted elements.
|
| - uint32_t old_length =
|
| - static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
|
| - element_dictionary()->RemoveNumberEntries(value, old_length);
|
| - }
|
| - JSArray::cast(this)->set_length(smi_length, SKIP_WRITE_BARRIER);
|
| - }
|
| - return this;
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| }
|
| }
|
|
|
| @@ -5258,20 +5343,36 @@
|
|
|
|
|
| bool JSObject::HasElementPostInterceptor(JSObject* receiver, uint32_t index) {
|
| - if (HasFastElements()) {
|
| - uint32_t length = IsJSArray() ?
|
| - static_cast<uint32_t>(
|
| - Smi::cast(JSArray::cast(this)->length())->value()) :
|
| - static_cast<uint32_t>(FixedArray::cast(elements())->length());
|
| - if ((index < length) &&
|
| - !FixedArray::cast(elements())->get(index)->IsTheHole()) {
|
| - return true;
|
| + switch (GetElementsKind()) {
|
| + case FAST_ELEMENTS: {
|
| + uint32_t length = IsJSArray() ?
|
| + static_cast<uint32_t>
|
| + (Smi::cast(JSArray::cast(this)->length())->value()) :
|
| + static_cast<uint32_t>(FixedArray::cast(elements())->length());
|
| + if ((index < length) &&
|
| + !FixedArray::cast(elements())->get(index)->IsTheHole()) {
|
| + return true;
|
| + }
|
| + break;
|
| }
|
| - } else {
|
| - if (element_dictionary()->FindEntry(index)
|
| - != NumberDictionary::kNotFound) {
|
| - return true;
|
| + case PIXEL_ELEMENTS: {
|
| + // TODO(iposva): Add testcase.
|
| + PixelArray* pixels = PixelArray::cast(elements());
|
| + if (index < static_cast<uint32_t>(pixels->length())) {
|
| + return true;
|
| + }
|
| + break;
|
| }
|
| + case DICTIONARY_ELEMENTS: {
|
| + if (element_dictionary()->FindEntry(index)
|
| + != NumberDictionary::kNotFound) {
|
| + return true;
|
| + }
|
| + break;
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| }
|
|
|
| // Handle [] on String objects.
|
| @@ -5338,17 +5439,29 @@
|
| // Handle [] on String objects.
|
| if (this->IsStringObjectWithCharacterAt(index)) return true;
|
|
|
| - if (HasFastElements()) {
|
| - uint32_t length = IsJSArray() ?
|
| - static_cast<uint32_t>(
|
| - Smi::cast(JSArray::cast(this)->length())->value()) :
|
| - static_cast<uint32_t>(FixedArray::cast(elements())->length());
|
| - return (index < length) &&
|
| - !FixedArray::cast(elements())->get(index)->IsTheHole();
|
| - } else {
|
| - return element_dictionary()->FindEntry(index)
|
| - != NumberDictionary::kNotFound;
|
| + switch (GetElementsKind()) {
|
| + case FAST_ELEMENTS: {
|
| + uint32_t length = IsJSArray() ?
|
| + static_cast<uint32_t>
|
| + (Smi::cast(JSArray::cast(this)->length())->value()) :
|
| + static_cast<uint32_t>(FixedArray::cast(elements())->length());
|
| + return (index < length) &&
|
| + !FixedArray::cast(elements())->get(index)->IsTheHole();
|
| + }
|
| + case PIXEL_ELEMENTS: {
|
| + PixelArray* pixels = PixelArray::cast(elements());
|
| + return (index < static_cast<uint32_t>(pixels->length()));
|
| + }
|
| + case DICTIONARY_ELEMENTS: {
|
| + return element_dictionary()->FindEntry(index)
|
| + != NumberDictionary::kNotFound;
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| }
|
| + UNREACHABLE();
|
| + return Heap::null_value();
|
| }
|
|
|
|
|
| @@ -5365,18 +5478,33 @@
|
| return HasElementWithInterceptor(receiver, index);
|
| }
|
|
|
| - if (HasFastElements()) {
|
| - uint32_t length = IsJSArray() ?
|
| - static_cast<uint32_t>(
|
| - Smi::cast(JSArray::cast(this)->length())->value()) :
|
| - static_cast<uint32_t>(FixedArray::cast(elements())->length());
|
| - if ((index < length) &&
|
| - !FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
|
| - } else {
|
| - if (element_dictionary()->FindEntry(index)
|
| - != NumberDictionary::kNotFound) {
|
| - return true;
|
| + switch (GetElementsKind()) {
|
| + case FAST_ELEMENTS: {
|
| + uint32_t length = IsJSArray() ?
|
| + static_cast<uint32_t>
|
| + (Smi::cast(JSArray::cast(this)->length())->value()) :
|
| + static_cast<uint32_t>(FixedArray::cast(elements())->length());
|
| + if ((index < length) &&
|
| + !FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
|
| + break;
|
| }
|
| + case PIXEL_ELEMENTS: {
|
| + PixelArray* pixels = PixelArray::cast(elements());
|
| + if (index < static_cast<uint32_t>(pixels->length())) {
|
| + return true;
|
| + }
|
| + break;
|
| + }
|
| + case DICTIONARY_ELEMENTS: {
|
| + if (element_dictionary()->FindEntry(index)
|
| + != NumberDictionary::kNotFound) {
|
| + return true;
|
| + }
|
| + break;
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| }
|
|
|
| // Handle [] on String objects.
|
| @@ -5472,7 +5600,7 @@
|
| // Otherwise default to slow case.
|
| Object* obj = NormalizeElements();
|
| if (obj->IsFailure()) return obj;
|
| - ASSERT(!HasFastElements());
|
| + ASSERT(HasDictionaryElements());
|
| return SetElement(index, value);
|
| }
|
|
|
| @@ -5501,80 +5629,95 @@
|
|
|
|
|
| Object* JSObject::SetElementWithoutInterceptor(uint32_t index, Object* value) {
|
| - // Fast case.
|
| - if (HasFastElements()) return SetFastElement(index, value);
|
| -
|
| - // Dictionary case.
|
| - ASSERT(!HasFastElements());
|
| -
|
| - // Insert element in the dictionary.
|
| - FixedArray* elms = FixedArray::cast(elements());
|
| - NumberDictionary* dictionary = NumberDictionary::cast(elms);
|
| -
|
| - int entry = dictionary->FindEntry(index);
|
| - if (entry != NumberDictionary::kNotFound) {
|
| - Object* element = dictionary->ValueAt(entry);
|
| - PropertyDetails details = dictionary->DetailsAt(entry);
|
| - if (details.type() == CALLBACKS) {
|
| - // Only accessors allowed as elements.
|
| - FixedArray* structure = FixedArray::cast(element);
|
| - if (structure->get(kSetterIndex)->IsJSFunction()) {
|
| - JSFunction* setter = JSFunction::cast(structure->get(kSetterIndex));
|
| - return SetPropertyWithDefinedSetter(setter, value);
|
| + switch (GetElementsKind()) {
|
| + case FAST_ELEMENTS:
|
| + // Fast case.
|
| + return SetFastElement(index, value);
|
| + case PIXEL_ELEMENTS: {
|
| + PixelArray* pixels = PixelArray::cast(elements());
|
| + return pixels->SetValue(index, value);
|
| + }
|
| + case DICTIONARY_ELEMENTS: {
|
| + // Insert element in the dictionary.
|
| + FixedArray* elms = FixedArray::cast(elements());
|
| + NumberDictionary* dictionary = NumberDictionary::cast(elms);
|
| +
|
| + int entry = dictionary->FindEntry(index);
|
| + if (entry != NumberDictionary::kNotFound) {
|
| + Object* element = dictionary->ValueAt(entry);
|
| + PropertyDetails details = dictionary->DetailsAt(entry);
|
| + if (details.type() == CALLBACKS) {
|
| + // Only accessors allowed as elements.
|
| + FixedArray* structure = FixedArray::cast(element);
|
| + if (structure->get(kSetterIndex)->IsJSFunction()) {
|
| + JSFunction* setter = JSFunction::cast(structure->get(kSetterIndex));
|
| + return SetPropertyWithDefinedSetter(setter, value);
|
| + } else {
|
| + Handle<Object> self(this);
|
| + Handle<Object> key(Factory::NewNumberFromUint(index));
|
| + Handle<Object> args[2] = { key, self };
|
| + return Top::Throw(*Factory::NewTypeError("no_setter_in_callback",
|
| + HandleVector(args, 2)));
|
| + }
|
| + } else {
|
| + dictionary->UpdateMaxNumberKey(index);
|
| + dictionary->ValueAtPut(entry, value);
|
| + }
|
| } else {
|
| - Handle<Object> self(this);
|
| - Handle<Object> key(Factory::NewNumberFromUint(index));
|
| - Handle<Object> args[2] = { key, self };
|
| - return Top::Throw(*Factory::NewTypeError("no_setter_in_callback",
|
| - HandleVector(args, 2)));
|
| + // Index not already used. Look for an accessor in the prototype chain.
|
| + if (!IsJSArray()) {
|
| + Object* setter = LookupCallbackSetterInPrototypes(index);
|
| + if (setter->IsJSFunction()) {
|
| + return SetPropertyWithDefinedSetter(JSFunction::cast(setter),
|
| + value);
|
| + }
|
| + }
|
| + Object* result = dictionary->AtNumberPut(index, value);
|
| + if (result->IsFailure()) return result;
|
| + if (elms != FixedArray::cast(result)) {
|
| + set_elements(FixedArray::cast(result));
|
| + }
|
| }
|
| - } else {
|
| - dictionary->UpdateMaxNumberKey(index);
|
| - dictionary->ValueAtPut(entry, value);
|
| - }
|
| - } else {
|
| - // Index not already used. Look for an accessor in the prototype chain.
|
| - if (!IsJSArray()) {
|
| - Object* setter = LookupCallbackSetterInPrototypes(index);
|
| - if (setter->IsJSFunction()) {
|
| - return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
|
| +
|
| + // Update the array length if this JSObject is an array.
|
| + if (IsJSArray()) {
|
| + JSArray* array = JSArray::cast(this);
|
| + Object* return_value = array->JSArrayUpdateLengthFromIndex(index,
|
| + value);
|
| + if (return_value->IsFailure()) return return_value;
|
| }
|
| - }
|
| - Object* result = dictionary->AtNumberPut(index, value);
|
| - if (result->IsFailure()) return result;
|
| - if (elms != FixedArray::cast(result)) {
|
| - set_elements(FixedArray::cast(result));
|
| - }
|
| - }
|
| -
|
| - // Update the array length if this JSObject is an array.
|
| - if (IsJSArray()) {
|
| - JSArray* array = JSArray::cast(this);
|
| - Object* return_value = array->JSArrayUpdateLengthFromIndex(index, value);
|
| - if (return_value->IsFailure()) return return_value;
|
| - }
|
| -
|
| - // Attempt to put this object back in fast case.
|
| - if (ShouldConvertToFastElements()) {
|
| - uint32_t new_length = 0;
|
| - if (IsJSArray()) {
|
| - CHECK(Array::IndexFromObject(JSArray::cast(this)->length(), &new_length));
|
| - JSArray::cast(this)->set_length(Smi::FromInt(new_length));
|
| - } else {
|
| - new_length = NumberDictionary::cast(elements())->max_number_key() + 1;
|
| - }
|
| - Object* obj = Heap::AllocateFixedArrayWithHoles(new_length);
|
| - if (obj->IsFailure()) return obj;
|
| - SetFastElements(FixedArray::cast(obj));
|
| +
|
| + // Attempt to put this object back in fast case.
|
| + if (ShouldConvertToFastElements()) {
|
| + uint32_t new_length = 0;
|
| + if (IsJSArray()) {
|
| + CHECK(Array::IndexFromObject(JSArray::cast(this)->length(),
|
| + &new_length));
|
| + JSArray::cast(this)->set_length(Smi::FromInt(new_length));
|
| + } else {
|
| + new_length = NumberDictionary::cast(elements())->max_number_key() + 1;
|
| + }
|
| + Object* obj = Heap::AllocateFixedArrayWithHoles(new_length);
|
| + if (obj->IsFailure()) return obj;
|
| + SetFastElements(FixedArray::cast(obj));
|
| #ifdef DEBUG
|
| - if (FLAG_trace_normalization) {
|
| - PrintF("Object elements are fast case again:\n");
|
| - Print();
|
| + if (FLAG_trace_normalization) {
|
| + PrintF("Object elements are fast case again:\n");
|
| + Print();
|
| + }
|
| +#endif
|
| + }
|
| +
|
| + return value;
|
| }
|
| -#endif
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| }
|
| -
|
| - return value;
|
| + // All possible cases have been handled above. Add a return to avoid the
|
| + // complaints from the compiler.
|
| + UNREACHABLE();
|
| + return Heap::null_value();
|
| }
|
|
|
|
|
| @@ -5597,32 +5740,45 @@
|
| uint32_t index) {
|
| // Get element works for both JSObject and JSArray since
|
| // JSArray::length cannot change.
|
| - if (HasFastElements()) {
|
| - FixedArray* elms = FixedArray::cast(elements());
|
| - if (index < static_cast<uint32_t>(elms->length())) {
|
| - Object* value = elms->get(index);
|
| - if (!value->IsTheHole()) return value;
|
| + switch (GetElementsKind()) {
|
| + case FAST_ELEMENTS: {
|
| + FixedArray* elms = FixedArray::cast(elements());
|
| + if (index < static_cast<uint32_t>(elms->length())) {
|
| + Object* value = elms->get(index);
|
| + if (!value->IsTheHole()) return value;
|
| + }
|
| + break;
|
| }
|
| - } else {
|
| - NumberDictionary* dictionary = element_dictionary();
|
| - int entry = dictionary->FindEntry(index);
|
| - if (entry != NumberDictionary::kNotFound) {
|
| - Object* element = dictionary->ValueAt(entry);
|
| - PropertyDetails details = dictionary->DetailsAt(entry);
|
| - if (details.type() == CALLBACKS) {
|
| - // Only accessors allowed as elements.
|
| - FixedArray* structure = FixedArray::cast(element);
|
| - Object* getter = structure->get(kGetterIndex);
|
| - if (getter->IsJSFunction()) {
|
| - return GetPropertyWithDefinedGetter(receiver,
|
| - JSFunction::cast(getter));
|
| - } else {
|
| - // Getter is not a function.
|
| - return Heap::undefined_value();
|
| + case PIXEL_ELEMENTS: {
|
| + // TODO(iposva): Add testcase and implement.
|
| + UNIMPLEMENTED();
|
| + break;
|
| + }
|
| + case DICTIONARY_ELEMENTS: {
|
| + NumberDictionary* dictionary = element_dictionary();
|
| + int entry = dictionary->FindEntry(index);
|
| + if (entry != NumberDictionary::kNotFound) {
|
| + Object* element = dictionary->ValueAt(entry);
|
| + PropertyDetails details = dictionary->DetailsAt(entry);
|
| + if (details.type() == CALLBACKS) {
|
| + // Only accessors allowed as elements.
|
| + FixedArray* structure = FixedArray::cast(element);
|
| + Object* getter = structure->get(kGetterIndex);
|
| + if (getter->IsJSFunction()) {
|
| + return GetPropertyWithDefinedGetter(receiver,
|
| + JSFunction::cast(getter));
|
| + } else {
|
| + // Getter is not a function.
|
| + return Heap::undefined_value();
|
| + }
|
| }
|
| + return element;
|
| }
|
| - return element;
|
| + break;
|
| }
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| }
|
|
|
| // Continue searching via the prototype chain.
|
| @@ -5681,31 +5837,44 @@
|
|
|
| // Get element works for both JSObject and JSArray since
|
| // JSArray::length cannot change.
|
| - if (HasFastElements()) {
|
| - FixedArray* elms = FixedArray::cast(elements());
|
| - if (index < static_cast<uint32_t>(elms->length())) {
|
| - Object* value = elms->get(index);
|
| - if (!value->IsTheHole()) return value;
|
| + switch (GetElementsKind()) {
|
| + case FAST_ELEMENTS: {
|
| + FixedArray* elms = FixedArray::cast(elements());
|
| + if (index < static_cast<uint32_t>(elms->length())) {
|
| + Object* value = elms->get(index);
|
| + if (!value->IsTheHole()) return value;
|
| + }
|
| + break;
|
| }
|
| - } else {
|
| - NumberDictionary* dictionary = element_dictionary();
|
| - int entry = dictionary->FindEntry(index);
|
| - if (entry != NumberDictionary::kNotFound) {
|
| - Object* element = dictionary->ValueAt(entry);
|
| - PropertyDetails details = dictionary->DetailsAt(entry);
|
| - if (details.type() == CALLBACKS) {
|
| - // Only accessors allowed as elements.
|
| - FixedArray* structure = FixedArray::cast(element);
|
| - Object* getter = structure->get(kGetterIndex);
|
| - if (getter->IsJSFunction()) {
|
| - return GetPropertyWithDefinedGetter(receiver,
|
| - JSFunction::cast(getter));
|
| - } else {
|
| - // Getter is not a function.
|
| - return Heap::undefined_value();
|
| + case PIXEL_ELEMENTS: {
|
| + PixelArray* pixels = PixelArray::cast(elements());
|
| + if (index < static_cast<uint32_t>(pixels->length())) {
|
| + uint8_t value = pixels->get(index);
|
| + return Smi::FromInt(value);
|
| + }
|
| + break;
|
| + }
|
| + case DICTIONARY_ELEMENTS: {
|
| + NumberDictionary* dictionary = element_dictionary();
|
| + int entry = dictionary->FindEntry(index);
|
| + if (entry != NumberDictionary::kNotFound) {
|
| + Object* element = dictionary->ValueAt(entry);
|
| + PropertyDetails details = dictionary->DetailsAt(entry);
|
| + if (details.type() == CALLBACKS) {
|
| + // Only accessors allowed as elements.
|
| + FixedArray* structure = FixedArray::cast(element);
|
| + Object* getter = structure->get(kGetterIndex);
|
| + if (getter->IsJSFunction()) {
|
| + return GetPropertyWithDefinedGetter(receiver,
|
| + JSFunction::cast(getter));
|
| + } else {
|
| + // Getter is not a function.
|
| + return Heap::undefined_value();
|
| + }
|
| }
|
| + return element;
|
| }
|
| - return element;
|
| + break;
|
| }
|
| }
|
|
|
| @@ -5719,16 +5888,27 @@
|
| int capacity = 0;
|
| int number_of_elements = 0;
|
|
|
| - if (HasFastElements()) {
|
| - FixedArray* elms = FixedArray::cast(elements());
|
| - capacity = elms->length();
|
| - for (int i = 0; i < capacity; i++) {
|
| - if (!elms->get(i)->IsTheHole()) number_of_elements++;
|
| + switch (GetElementsKind()) {
|
| + case FAST_ELEMENTS: {
|
| + FixedArray* elms = FixedArray::cast(elements());
|
| + capacity = elms->length();
|
| + for (int i = 0; i < capacity; i++) {
|
| + if (!elms->get(i)->IsTheHole()) number_of_elements++;
|
| + }
|
| + break;
|
| }
|
| - } else {
|
| - NumberDictionary* dictionary = NumberDictionary::cast(elements());
|
| - capacity = dictionary->Capacity();
|
| - number_of_elements = dictionary->NumberOfElements();
|
| + case PIXEL_ELEMENTS: {
|
| + return true;
|
| + }
|
| + case DICTIONARY_ELEMENTS: {
|
| + NumberDictionary* dictionary = NumberDictionary::cast(elements());
|
| + capacity = dictionary->Capacity();
|
| + number_of_elements = dictionary->NumberOfElements();
|
| + break;
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| }
|
|
|
| if (capacity == 0) return true;
|
| @@ -5747,7 +5927,7 @@
|
|
|
|
|
| bool JSObject::ShouldConvertToFastElements() {
|
| - ASSERT(!HasFastElements());
|
| + ASSERT(HasDictionaryElements());
|
| NumberDictionary* dictionary = NumberDictionary::cast(elements());
|
| // If the elements are sparse, we should not go back to fast case.
|
| if (!HasDenseElements()) return false;
|
| @@ -6001,16 +6181,30 @@
|
| // Handle [] on String objects.
|
| if (this->IsStringObjectWithCharacterAt(index)) return true;
|
|
|
| - if (HasFastElements()) {
|
| - uint32_t length = IsJSArray() ?
|
| - static_cast<uint32_t>(
|
| - Smi::cast(JSArray::cast(this)->length())->value()) :
|
| - static_cast<uint32_t>(FixedArray::cast(elements())->length());
|
| - return (index < length) &&
|
| - !FixedArray::cast(elements())->get(index)->IsTheHole();
|
| + switch (GetElementsKind()) {
|
| + case FAST_ELEMENTS: {
|
| + uint32_t length = IsJSArray() ?
|
| + static_cast<uint32_t>(
|
| + Smi::cast(JSArray::cast(this)->length())->value()) :
|
| + static_cast<uint32_t>(FixedArray::cast(elements())->length());
|
| + return (index < length) &&
|
| + !FixedArray::cast(elements())->get(index)->IsTheHole();
|
| + }
|
| + case PIXEL_ELEMENTS: {
|
| + PixelArray* pixels = PixelArray::cast(elements());
|
| + return index < static_cast<uint32_t>(pixels->length());
|
| + }
|
| + case DICTIONARY_ELEMENTS: {
|
| + return element_dictionary()->FindEntry(index)
|
| + != NumberDictionary::kNotFound;
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| }
|
| - return element_dictionary()->FindEntry(index)
|
| - != NumberDictionary::kNotFound;
|
| + // All possibilities have been handled above already.
|
| + UNREACHABLE();
|
| + return Heap::null_value();
|
| }
|
|
|
|
|
| @@ -6193,24 +6387,43 @@
|
| int JSObject::GetLocalElementKeys(FixedArray* storage,
|
| PropertyAttributes filter) {
|
| int counter = 0;
|
| - if (HasFastElements()) {
|
| - int length = IsJSArray()
|
| - ? Smi::cast(JSArray::cast(this)->length())->value()
|
| - : FixedArray::cast(elements())->length();
|
| - for (int i = 0; i < length; i++) {
|
| - if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
|
| - if (storage) {
|
| - storage->set(counter, Smi::FromInt(i), SKIP_WRITE_BARRIER);
|
| + switch (GetElementsKind()) {
|
| + case FAST_ELEMENTS: {
|
| + int length = IsJSArray() ?
|
| + Smi::cast(JSArray::cast(this)->length())->value() :
|
| + FixedArray::cast(elements())->length();
|
| + for (int i = 0; i < length; i++) {
|
| + if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
|
| + if (storage != NULL) {
|
| + storage->set(counter, Smi::FromInt(i), SKIP_WRITE_BARRIER);
|
| + }
|
| + counter++;
|
| }
|
| + }
|
| + ASSERT(!storage || storage->length() >= counter);
|
| + break;
|
| + }
|
| + case PIXEL_ELEMENTS: {
|
| + int length = PixelArray::cast(elements())->length();
|
| + while (counter < length) {
|
| + if (storage != NULL) {
|
| + storage->set(counter, Smi::FromInt(counter), SKIP_WRITE_BARRIER);
|
| + }
|
| counter++;
|
| }
|
| + ASSERT(!storage || storage->length() >= counter);
|
| + break;
|
| }
|
| - ASSERT(!storage || storage->length() >= counter);
|
| - } else {
|
| - if (storage) {
|
| - element_dictionary()->CopyKeysTo(storage, filter);
|
| + case DICTIONARY_ELEMENTS: {
|
| + if (storage != NULL) {
|
| + element_dictionary()->CopyKeysTo(storage, filter);
|
| + }
|
| + counter = element_dictionary()->NumberOfElementsFilterAttributes(filter);
|
| + break;
|
| }
|
| - counter = element_dictionary()->NumberOfElementsFilterAttributes(filter);
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| }
|
|
|
| if (this->IsJSValue()) {
|
| @@ -6669,7 +6882,7 @@
|
| // 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) {
|
| - ASSERT(!HasFastElements());
|
| + ASSERT(HasDictionaryElements());
|
| // 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.
|
| @@ -6743,7 +6956,9 @@
|
| // If the object is in dictionary mode, it is converted to fast elements
|
| // mode.
|
| Object* JSObject::PrepareElementsForSort(uint32_t limit) {
|
| - if (!HasFastElements()) {
|
| + ASSERT(!HasPixelElements());
|
| +
|
| + if (HasDictionaryElements()) {
|
| // Convert to fast elements containing only the existing properties.
|
| // Ordering is irrelevant, since we are going to sort anyway.
|
| NumberDictionary* dict = element_dictionary();
|
| @@ -6768,7 +6983,7 @@
|
| // 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();
|
| + FixedArray* elements = FixedArray::cast(this->elements());
|
| uint32_t elements_length = static_cast<uint32_t>(elements->length());
|
| if (limit > elements_length) {
|
| limit = elements_length ;
|
| @@ -6838,6 +7053,41 @@
|
| }
|
|
|
|
|
| +Object* PixelArray::SetValue(uint32_t index, Object* value) {
|
| + uint8_t clamped_value = 0;
|
| + if (index < static_cast<uint32_t>(length())) {
|
| + int int_value = 0;
|
| + if (value->IsSmi()) {
|
| + int_value = Smi::cast(value)->value();
|
| + } else if (value->IsHeapNumber()) {
|
| + static const DoubleRepresentation nan(OS::nan_value());
|
| + DoubleRepresentation double_value = HeapNumber::cast(value)->value();
|
| + if (nan.bits != double_value.bits) {
|
| + int_value = static_cast<int>(double_value.value + 0.5);
|
| + } else {
|
| + // NaN clamps to zero.
|
| + int_value = 0;
|
| + }
|
| + } else if (value->IsUndefined()) {
|
| + int_value = 0;
|
| + } else {
|
| + // All other types have been converted to a number type further up in the
|
| + // call chain.
|
| + UNREACHABLE();
|
| + }
|
| + if (int_value < 0) {
|
| + clamped_value = 0;
|
| + } else if (int_value > 255) {
|
| + clamped_value = 255;
|
| + } else {
|
| + clamped_value = static_cast<uint8_t>(int_value);
|
| + }
|
| + set(index, clamped_value);
|
| + }
|
| + return Smi::FromInt(clamped_value);
|
| +}
|
| +
|
| +
|
| Object* GlobalObject::GetPropertyCell(LookupResult* result) {
|
| ASSERT(!HasFastProperties());
|
| Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
|
|
|