*/
Local<Object> Clone();
+ /**
+ * Set the backing store of the indexed properties to be managed by the
+ * embedding layer. Access to the indexed properties will follow the rules
+ * spelled out in CanvasPixelArray.
+ * Note: The embedding program still owns the data and needs to ensure that
+ * the backing store is preserved while V8 has a reference.
+ */
+ void SetIndexedPropertiesToPixelData(uint8_t* data, int length);
+
static Local<Object> New();
static Object* Cast(Value* obj);
private:
}
+void v8::Object::SetIndexedPropertiesToPixelData(uint8_t* data, int length) {
+ ON_BAILOUT("v8::SetElementsToPixelData()", return);
+ ENTER_V8;
+ if (!ApiCheck(i::Smi::IsValid(length),
+ "v8::Object::SetIndexedPropertiesToPixelData()",
+ "length exceeds max acceptable value")) {
+ return;
+ }
+ i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+ if (!ApiCheck(!self->IsJSArray(),
+ "v8::Object::SetIndexedPropertiesToPixelData()",
+ "JSArray is not supported")) {
+ return;
+ }
+ i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(length, data);
+ self->set_elements(*pixels);
+}
+
+
Local<v8::Object> Function::NewInstance() const {
return NewInstance(0, NULL);
}
if (!self->HasFastElements()) {
return Local<Object>();
}
- i::FixedArray* elms = self->elements();
+ i::FixedArray* elms = i::FixedArray::cast(self->elements());
i::Object* paragon = elms->get(index);
if (!paragon->IsJSObject()) {
return Local<Object>();
__ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
// Check that the object is in fast mode (not dictionary).
__ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
- __ cmp(r3, Operand(Factory::hash_table_map()));
- __ b(eq, &slow);
+ __ cmp(r3, Operand(Factory::fixed_array_map()));
+ __ b(ne, &slow);
// Check that the key (index) is within bounds.
__ ldr(r3, FieldMemOperand(r1, Array::kLengthOffset));
__ cmp(r0, Operand(r3));
__ ldr(r3, FieldMemOperand(r3, JSObject::kElementsOffset));
// Check that the object is in fast mode (not dictionary).
__ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
- __ cmp(r2, Operand(Factory::hash_table_map()));
- __ b(eq, &slow);
+ __ cmp(r2, Operand(Factory::fixed_array_map()));
+ __ b(ne, &slow);
// Untag the key (for checking against untagged length in the fixed array).
__ mov(r1, Operand(r1, ASR, kSmiTagSize));
// Compute address to store into and check array bounds.
__ bind(&array);
__ ldr(r2, FieldMemOperand(r3, JSObject::kElementsOffset));
__ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
- __ cmp(r1, Operand(Factory::hash_table_map()));
- __ b(eq, &slow);
+ __ cmp(r1, Operand(Factory::fixed_array_map()));
+ __ b(ne, &slow);
// Check the key against the length in the array, compute the
// address to store into and fall through to fast case.
}
+Handle<PixelArray> Factory::NewPixelArray(int length,
+ uint8_t* external_pointer,
+ PretenureFlag pretenure) {
+ ASSERT(0 <= length);
+ CALL_HEAP_FUNCTION(Heap::AllocatePixelArray(length,
+ external_pointer,
+ pretenure), PixelArray);
+}
+
+
Handle<Map> Factory::NewMap(InstanceType type, int instance_size) {
CALL_HEAP_FUNCTION(Heap::AllocateMap(type, instance_size), Map);
}
static Handle<ByteArray> NewByteArray(int length,
PretenureFlag pretenure = NOT_TENURED);
+ static Handle<PixelArray> NewPixelArray(int length,
+ uint8_t* external_pointer,
+ PretenureFlag pretenure = NOT_TENURED);
+
static Handle<Map> NewMap(InstanceType type, int instance_size);
static Handle<JSObject> NewFunctionPrototype(Handle<JSFunction> function);
class IC;
class InterceptorInfo;
class IterationStatement;
+class Array;
class JSArray;
class JSFunction;
class JSObject;
Handle<Object> SetElement(Handle<JSObject> object,
uint32_t index,
Handle<Object> value) {
+ if (object->HasPixelElements()) {
+ if (!value->IsSmi() && !value->IsHeapNumber() && !value->IsUndefined()) {
+ bool has_exception;
+ Handle<Object> number = Execution::ToNumber(value, &has_exception);
+ if (has_exception) return Handle<Object>();
+ value = number;
+ }
+ }
CALL_HEAP_FUNCTION(object->SetElement(index, *value), Object);
}
if (obj->IsFailure()) return false;
set_byte_array_map(Map::cast(obj));
+ obj = AllocateMap(PIXEL_ARRAY_TYPE, PixelArray::kAlignedSize);
+ if (obj->IsFailure()) return false;
+ set_pixel_array_map(Map::cast(obj));
+
obj = AllocateMap(CODE_TYPE, Code::kHeaderSize);
if (obj->IsFailure()) return false;
set_code_map(Map::cast(obj));
Object* Heap::AllocateProxy(Address proxy, PretenureFlag pretenure) {
// Statically ensure that it is safe to allocate proxies in paged spaces.
STATIC_ASSERT(Proxy::kSize <= Page::kMaxHeapObjectSize);
- AllocationSpace space =
- (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
+ AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
Object* result = Allocate(proxy_map(), space);
if (result->IsFailure()) return result;
}
+Object* Heap::AllocatePixelArray(int length,
+ uint8_t* external_pointer,
+ PretenureFlag pretenure) {
+ AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
+
+ Object* result = AllocateRaw(PixelArray::kAlignedSize, space, OLD_DATA_SPACE);
+
+ if (result->IsFailure()) return result;
+
+ reinterpret_cast<PixelArray*>(result)->set_map(pixel_array_map());
+ reinterpret_cast<PixelArray*>(result)->set_length(length);
+ reinterpret_cast<PixelArray*>(result)->set_external_pointer(external_pointer);
+
+ return result;
+}
+
+
Object* Heap::CreateCode(const CodeDesc& desc,
ZoneScopeInfo* sinfo,
Code::Flags flags,
UndetectableMediumAsciiStringMap) \
V(Map, undetectable_long_ascii_string_map, UndetectableLongAsciiStringMap) \
V(Map, byte_array_map, ByteArrayMap) \
+ V(Map, pixel_array_map, PixelArrayMap) \
V(Map, fixed_array_map, FixedArrayMap) \
V(Map, hash_table_map, HashTableMap) \
V(Map, context_map, ContextMap) \
// Please note this does not perform a garbage collection.
static Object* AllocateByteArray(int length);
+ // Allocate a pixel array of the specified length
+ // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+ // failed.
+ // Please note this does not perform a garbage collection.
+ static Object* AllocatePixelArray(int length,
+ uint8_t* external_pointer,
+ PretenureFlag pretenure);
+
// Allocate a tenured JS global property cell.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
__ mov(elements.reg(),
FieldOperand(receiver.reg(), JSObject::kElementsOffset));
__ cmp(FieldOperand(elements.reg(), HeapObject::kMapOffset),
- Immediate(Factory::hash_table_map()));
- deferred->Branch(equal);
+ Immediate(Factory::fixed_array_map()));
+ deferred->Branch(not_equal);
// Shift the key to get the actual index value and check that
// it is within bounds.
// -- esp[4] : name
// -- esp[8] : receiver
// -----------------------------------
- Label slow, fast, check_string, index_int, index_string;
+ Label slow, check_string, index_int, index_string, check_pixel_array;
// Load name and receiver.
__ mov(eax, Operand(esp, kPointerSize));
__ mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset));
// Check that the object is in fast mode (not dictionary).
__ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
- Immediate(Factory::hash_table_map()));
- __ j(equal, &slow, not_taken);
+ Immediate(Factory::fixed_array_map()));
+ __ j(not_equal, &check_pixel_array);
// Check that the key (index) is within bounds.
__ cmp(eax, FieldOperand(ecx, FixedArray::kLengthOffset));
- __ j(below, &fast, taken);
+ __ j(above_equal, &slow);
+ // Fast case: Do the load.
+ __ mov(eax,
+ Operand(ecx, eax, times_4, FixedArray::kHeaderSize - kHeapObjectTag));
+ __ cmp(Operand(eax), Immediate(Factory::the_hole_value()));
+ // In case the loaded value is the_hole we have to consult GetProperty
+ // to ensure the prototype chain is searched.
+ __ j(equal, &slow);
+ __ IncrementCounter(&Counters::keyed_load_generic_smi, 1);
+ __ ret(0);
+
+ // Check whether the elements is a pixel array.
+ // eax: untagged index
+ // ecx: elements array
+ __ bind(&check_pixel_array);
+ __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
+ Immediate(Factory::pixel_array_map()));
+ __ j(not_equal, &slow);
+ __ cmp(eax, FieldOperand(ecx, PixelArray::kLengthOffset));
+ __ j(above_equal, &slow);
+ __ mov(ecx, FieldOperand(ecx, PixelArray::kExternalPointerOffset));
+ __ movzx_b(eax, Operand(ecx, eax, times_1, 0));
+ __ shl(eax, kSmiTagSize);
+ __ ret(0);
+
+
// Slow case: Load name and receiver from stack and jump to runtime.
__ bind(&slow);
__ IncrementCounter(&Counters::keyed_load_generic_slow, 1);
__ and_(eax, (1 << String::kShortLengthShift) - 1);
__ shr(eax, String::kLongLengthShift);
__ jmp(&index_int);
- // Fast case: Do the load.
- __ bind(&fast);
- __ mov(eax,
- Operand(ecx, eax, times_4, FixedArray::kHeaderSize - kHeapObjectTag));
- __ cmp(Operand(eax), Immediate(Factory::the_hole_value()));
- // In case the loaded value is the_hole we have to consult GetProperty
- // to ensure the prototype chain is searched.
- __ j(equal, &slow, not_taken);
- __ IncrementCounter(&Counters::keyed_load_generic_smi, 1);
- __ ret(0);
}
// -- esp[4] : key
// -- esp[8] : receiver
// -----------------------------------
- Label slow, fast, array, extra;
+ Label slow, fast, array, extra, check_pixel_array;
// Get the receiver from the stack.
__ mov(edx, Operand(esp, 2 * kPointerSize)); // 2 ~ return address, key
__ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
// Check that the object is in fast mode (not dictionary).
__ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
- Immediate(Factory::hash_table_map()));
- __ j(equal, &slow, not_taken);
+ Immediate(Factory::fixed_array_map()));
+ __ j(not_equal, &check_pixel_array, not_taken);
// Untag the key (for checking against untagged length in the fixed array).
__ mov(edx, Operand(ebx));
__ sar(edx, kSmiTagSize); // untag the index and use it for the comparison
// ebx: index (as a smi)
__ j(below, &fast, taken);
-
// Slow case: Push extra copies of the arguments (3).
__ bind(&slow);
__ pop(ecx);
// Do tail-call to runtime routine.
__ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3);
+ // Check whether the elements is a pixel array.
+ // eax: value
+ // ecx: elements array
+ // ebx: index (as a smi)
+ __ bind(&check_pixel_array);
+ __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
+ Immediate(Factory::pixel_array_map()));
+ __ j(not_equal, &slow);
+ // Check that the value is a smi. If a conversion is needed call into the
+ // runtime to convert and clamp.
+ __ test(eax, Immediate(kSmiTagMask));
+ __ j(not_zero, &slow);
+ __ sar(ebx, kSmiTagSize); // Untag the index.
+ __ cmp(ebx, FieldOperand(ecx, PixelArray::kLengthOffset));
+ __ j(above_equal, &slow);
+ __ sar(eax, kSmiTagSize); // Untag the value.
+ { // Clamp the value to [0..255].
+ Label done, check_255;
+ __ cmp(eax, 0);
+ __ j(greater_equal, &check_255);
+ __ mov(eax, Immediate(0));
+ __ jmp(&done);
+ __ bind(&check_255);
+ __ cmp(eax, 255);
+ __ j(less_equal, &done);
+ __ mov(eax, Immediate(255));
+ __ bind(&done);
+ }
+ __ mov(ecx, FieldOperand(ecx, PixelArray::kExternalPointerOffset));
+ __ mov_b(Operand(ecx, ebx, times_1, 0), eax);
+ __ ret(0);
// Extra capacity case: Check if there is extra capacity to
// perform the store and update the length. Used for adding one
// ebx: index (as a smi)
__ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
__ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
- Immediate(Factory::hash_table_map()));
- __ j(equal, &slow, not_taken);
+ Immediate(Factory::fixed_array_map()));
+ __ j(not_equal, &check_pixel_array);
// Check the key against the length in the array, compute the
// address to store into and fall through to fast case.
__ cmp(ebx, FieldOperand(edx, JSArray::kLengthOffset));
__ j(above_equal, &extra, not_taken);
-
// Fast case: Do the store.
__ bind(&fast);
// eax: value
{
NoHandleAllocation no_handles;
- FixedArray* array = last_match_info->elements();
+ FixedArray* array = FixedArray::cast(last_match_info->elements());
SetAtomLastCapture(array, *subject, value, value + needle->length());
}
return last_match_info;
if (res != RegExpMacroAssemblerIA32::SUCCESS) return Factory::null_value();
- array = Handle<FixedArray>(last_match_info->elements());
+ array = Handle<FixedArray>(FixedArray::cast(last_match_info->elements()));
ASSERT(array->length() >= number_of_capture_registers + kLastMatchOverhead);
// The captures come in (start, end+1) pairs.
for (int i = 0; i < number_of_capture_registers; i += 2) {
return Factory::null_value();
}
- array = Handle<FixedArray>(last_match_info->elements());
+ array = Handle<FixedArray>(FixedArray::cast(last_match_info->elements()));
ASSERT(array->length() >= number_of_capture_registers + kLastMatchOverhead);
// The captures come in (start, end+1) pairs.
for (int i = 0; i < number_of_capture_registers; i += 2) {
case BYTE_ARRAY_TYPE:
ByteArray::cast(this)->ByteArrayPrint();
break;
+ case PIXEL_ARRAY_TYPE:
+ PixelArray::cast(this)->PixelArrayPrint();
+ break;
case FILLER_TYPE:
PrintF("filler");
break;
case BYTE_ARRAY_TYPE:
ByteArray::cast(this)->ByteArrayVerify();
break;
+ case PIXEL_ARRAY_TYPE:
+ PixelArray::cast(this)->PixelArrayVerify();
+ break;
case CODE_TYPE:
Code::cast(this)->CodeVerify();
break;
}
+void PixelArray::PixelArrayPrint() {
+ PrintF("pixel array");
+}
+
+
void ByteArray::ByteArrayVerify() {
ASSERT(IsByteArray());
}
+void PixelArray::PixelArrayVerify() {
+ ASSERT(IsPixelArray());
+}
+
+
void JSObject::PrintProperties() {
if (HasFastProperties()) {
DescriptorArray* descs = map()->instance_descriptors();
void JSObject::PrintElements() {
- if (HasFastElements()) {
- FixedArray* p = FixedArray::cast(elements());
- for (int i = 0; i < p->length(); i++) {
- PrintF(" %d: ", i);
- p->get(i)->ShortPrint();
- PrintF("\n");
+ switch (GetElementsKind()) {
+ case FAST_ELEMENTS: {
+ // Print in array notation for non-sparse arrays.
+ FixedArray* p = FixedArray::cast(elements());
+ for (int i = 0; i < p->length(); i++) {
+ PrintF(" %d: ", i);
+ p->get(i)->ShortPrint();
+ PrintF("\n");
+ }
+ break;
}
- } else {
- elements()->Print();
+ case PIXEL_ELEMENTS: {
+ PixelArray* p = PixelArray::cast(elements());
+ for (int i = 0; i < p->length(); i++) {
+ PrintF(" %d: %d\n", i, p->get(i));
+ }
+ break;
+ }
+ case DICTIONARY_ELEMENTS:
+ elements()->Print();
+ break;
+ default:
+ UNREACHABLE();
+ break;
}
}
case LONG_EXTERNAL_STRING_TYPE: return "EXTERNAL_STRING";
case FIXED_ARRAY_TYPE: return "FIXED_ARRAY";
case BYTE_ARRAY_TYPE: return "BYTE_ARRAY";
+ case PIXEL_ARRAY_TYPE: return "PIXEL_ARRAY";
case FILLER_TYPE: return "FILLER";
case JS_OBJECT_TYPE: return "JS_OBJECT";
case JS_CONTEXT_EXTENSION_OBJECT_TYPE: return "JS_CONTEXT_EXTENSION_OBJECT";
dict->Capacity() - dict->NumberOfElements();
}
// Indexed properties
- if (HasFastElements()) {
- info->number_of_objects_with_fast_elements_++;
- int holes = 0;
- FixedArray* e = FixedArray::cast(elements());
- int len = e->length();
- for (int i = 0; i < len; i++) {
- if (e->get(i) == Heap::the_hole_value()) holes++;
+ switch (GetElementsKind()) {
+ case FAST_ELEMENTS: {
+ info->number_of_objects_with_fast_elements_++;
+ int holes = 0;
+ FixedArray* e = FixedArray::cast(elements());
+ int len = e->length();
+ for (int i = 0; i < len; i++) {
+ if (e->get(i) == Heap::the_hole_value()) holes++;
+ }
+ info->number_of_fast_used_elements_ += len - holes;
+ info->number_of_fast_unused_elements_ += holes;
+ break;
}
- info->number_of_fast_used_elements_ += len - holes;
- info->number_of_fast_unused_elements_ += holes;
- } else {
- NumberDictionary* dict = element_dictionary();
- info->number_of_slow_used_elements_ += dict->NumberOfElements();
- info->number_of_slow_unused_elements_ +=
- dict->Capacity() - dict->NumberOfElements();
+ case PIXEL_ELEMENTS: {
+ info->number_of_objects_with_fast_elements_++;
+ PixelArray* e = PixelArray::cast(elements());
+ info->number_of_fast_used_elements_ += e->length();
+ break;
+ }
+ case DICTIONARY_ELEMENTS: {
+ NumberDictionary* dict = element_dictionary();
+ info->number_of_slow_used_elements_ += dict->NumberOfElements();
+ info->number_of_slow_unused_elements_ +=
+ dict->Capacity() - dict->NumberOfElements();
+ break;
+ }
+ default:
+ UNREACHABLE();
+ break;
}
}
}
+bool Object::IsPixelArray() {
+ return Object::IsHeapObject() &&
+ HeapObject::cast(this)->map()->instance_type() == PIXEL_ARRAY_TYPE;
+}
+
+
bool Object::IsFailure() {
return HAS_FAILURE_TAG(this);
}
ACCESSORS(JSObject, properties, FixedArray, kPropertiesOffset)
-ACCESSORS(JSObject, elements, FixedArray, kElementsOffset)
+
+
+Array* JSObject::elements() {
+ Object* array = READ_FIELD(this, kElementsOffset);
+ // In the assert below Dictionary is covered under FixedArray.
+ ASSERT(array->IsFixedArray() || array->IsPixelArray());
+ return reinterpret_cast<Array*>(array);
+}
+
+
+void JSObject::set_elements(Array* value, WriteBarrierMode mode) {
+ // In the assert below Dictionary is covered under FixedArray.
+ ASSERT(value->IsFixedArray() || value->IsPixelArray());
+ WRITE_FIELD(this, kElementsOffset, value);
+ CONDITIONAL_WRITE_BARRIER(this, kElementsOffset, mode);
+}
void JSObject::initialize_properties() {
CAST_ACCESSOR(JSRegExp)
CAST_ACCESSOR(Proxy)
CAST_ACCESSOR(ByteArray)
+CAST_ACCESSOR(PixelArray)
CAST_ACCESSOR(Struct)
}
+uint8_t* PixelArray::external_pointer() {
+ intptr_t ptr = READ_INTPTR_FIELD(this, kExternalPointerOffset);
+ return reinterpret_cast<uint8_t*>(ptr);
+}
+
+
+void PixelArray::set_external_pointer(uint8_t* value, WriteBarrierMode mode) {
+ intptr_t ptr = reinterpret_cast<intptr_t>(value);
+ WRITE_INTPTR_FIELD(this, kExternalPointerOffset, ptr);
+}
+
+
+uint8_t PixelArray::get(int index) {
+ ASSERT((index >= 0) && (index < this->length()));
+ uint8_t* ptr = external_pointer();
+ return ptr[index];
+}
+
+
+void PixelArray::set(int index, uint8_t value) {
+ ASSERT((index >= 0) && (index < this->length()));
+ uint8_t* ptr = external_pointer();
+ ptr[index] = value;
+}
+
+
int Map::instance_size() {
return READ_BYTE_FIELD(this, kInstanceSizeOffset) << kPointerSizeLog2;
}
}
+JSObject::ElementsKind JSObject::GetElementsKind() {
+ Array* array = elements();
+ if (array->IsFixedArray()) {
+ // FAST_ELEMENTS or DICTIONARY_ELEMENTS are both stored in a FixedArray.
+ if (array->map() == Heap::fixed_array_map()) {
+ return FAST_ELEMENTS;
+ }
+ ASSERT(array->IsDictionary());
+ return DICTIONARY_ELEMENTS;
+ }
+ ASSERT(array->IsPixelArray());
+ return PIXEL_ELEMENTS;
+}
+
+
bool JSObject::HasFastElements() {
- return !elements()->IsDictionary();
+ return GetElementsKind() == FAST_ELEMENTS;
+}
+
+
+bool JSObject::HasDictionaryElements() {
+ return GetElementsKind() == DICTIONARY_ELEMENTS;
+}
+
+
+bool JSObject::HasPixelElements() {
+ return GetElementsKind() == PIXEL_ELEMENTS;
}
NumberDictionary* JSObject::element_dictionary() {
- ASSERT(!HasFastElements());
+ ASSERT(HasDictionaryElements());
return NumberDictionary::cast(elements());
}
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;
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);
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) {
Object* JSObject::NormalizeElements() {
- if (!HasFastElements()) return this;
+ ASSERT(!HasPixelElements());
+ if (HasDictionaryElements()) return this;
// Get number of entries.
FixedArray* array = FixedArray::cast(elements());
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();
- }
- ASSERT(!HasFastElements());
- NumberDictionary* dictionary = element_dictionary();
- int entry = dictionary->FindEntry(index);
- if (entry != NumberDictionary::kNotFound) {
- return dictionary->DeleteProperty(entry, mode);
+ 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();
}
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();
}
}
// 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) {
- return true;
+ 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;
}
- } else {
- key = element_dictionary()->SlowReverseLookup(obj);
- if (key != Heap::undefined_value()) {
- return true;
+ case DICTIONARY_ELEMENTS: {
+ key = element_dictionary()->SlowReverseLookup(obj);
+ if (key != Heap::undefined_value()) {
+ return true;
+ }
+ break;
}
+ default:
+ UNREACHABLE();
+ break;
}
// For functions check the context. Boilerplate functions do
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.
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);
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.
}
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;
}
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.
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;
}
}
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.
// 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();
}
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.
// Otherwise default to slow case.
Object* obj = NormalizeElements();
if (obj->IsFailure()) return obj;
- ASSERT(!HasFastElements());
+ ASSERT(HasDictionaryElements());
return SetElement(index, value);
}
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;
+ }
+ 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();
}
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.
// 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;
}
}
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;
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;
// 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();
}
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()) {
// 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.
// 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();
// 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 ;
}
+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());
// - JSValue
// - Array
// - ByteArray
+// - PixelArray
// - FixedArray
// - DescriptorArray
// - HashTable
// HeapObject: [32 bit direct pointer] (4 byte aligned) | 01
// Failure: [30 bit signed int] 11
-
// Ecma-262 3rd 8.6.1
enum PropertyAttributes {
NONE = v8::None,
V(ODDBALL_TYPE) \
V(PROXY_TYPE) \
V(BYTE_ARRAY_TYPE) \
+ V(PIXEL_ARRAY_TYPE) \
V(FILLER_TYPE) \
\
V(ACCESSOR_INFO_TYPE) \
JS_GLOBAL_PROPERTY_CELL_TYPE,
PROXY_TYPE,
BYTE_ARRAY_TYPE,
+ PIXEL_ARRAY_TYPE,
FILLER_TYPE,
SMI_TYPE,
inline bool IsNumber();
inline bool IsByteArray();
+ inline bool IsPixelArray();
inline bool IsFailure();
inline bool IsRetryAfterGC();
inline bool IsOutOfMemoryFailure();
class JSObject: public HeapObject {
public:
enum DeleteMode { NORMAL_DELETION, FORCE_DELETION };
+ enum ElementsKind {
+ FAST_ELEMENTS,
+ DICTIONARY_ELEMENTS,
+ PIXEL_ELEMENTS
+ };
// [properties]: Backing storage for properties.
// properties is a FixedArray in the fast case, and a Dictionary in the
// [elements]: The elements (properties with names that are integers).
// elements is a FixedArray in the fast case, and a Dictionary in the slow
- // case.
- DECL_ACCESSORS(elements, FixedArray) // Get and set fast elements.
+ // case or a PixelArray in a special case.
+ DECL_ACCESSORS(elements, Array) // Get and set fast elements.
inline void initialize_elements();
+ inline ElementsKind GetElementsKind();
inline bool HasFastElements();
+ inline bool HasDictionaryElements();
+ inline bool HasPixelElements();
inline NumberDictionary* element_dictionary(); // Gets slow elements.
// Collects elements starting at index 0.
};
+// PixelArray represents a fixed size byte array with special sematics used for
+// implementing the CanvasPixelArray object. Please see the specification at:
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#canvaspixelarray
+// In particular write access clamps the values to 0 or 255 if the value
+// used is outside this range.
+class PixelArray: public Array {
+ public:
+ // [external_pointer]: The pointer to the external memory area backing this
+ // pixel array.
+ DECL_ACCESSORS(external_pointer, uint8_t) // Pointer to the data store.
+
+ // Setter and getter.
+ inline uint8_t get(int index);
+ inline void set(int index, uint8_t value);
+
+ // This accessor applies the correct conversion from Smi, HeapNumber and
+ // undefined and clamps the converted value between 0 and 255.
+ Object* SetValue(uint32_t index, Object* value);
+
+ // Casting.
+ static inline PixelArray* cast(Object* obj);
+
+#ifdef DEBUG
+ void PixelArrayPrint();
+ void PixelArrayVerify();
+#endif // DEBUG
+
+ // PixelArray headers are not quadword aligned.
+ static const int kExternalPointerOffset = Array::kAlignedSize;
+ static const int kHeaderSize = kExternalPointerOffset + kPointerSize;
+ static const int kAlignedSize = OBJECT_SIZE_ALIGN(kHeaderSize);
+
+private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(PixelArray);
+};
+
+
// Code describes objects with on-the-fly generated machine code.
class Code: public HeapObject {
public:
}
// Deep copy local elements.
- if (copy->HasFastElements()) {
- FixedArray* elements = copy->elements();
- WriteBarrierMode mode = elements->GetWriteBarrierMode();
- for (int i = 0; i < elements->length(); i++) {
- Object* value = elements->get(i);
- if (value->IsJSObject()) {
- JSObject* jsObject = JSObject::cast(value);
- result = DeepCopyBoilerplate(jsObject);
- if (result->IsFailure()) return result;
- elements->set(i, result, mode);
- }
- }
- } else {
- NumberDictionary* element_dictionary = copy->element_dictionary();
- int capacity = element_dictionary->Capacity();
- for (int i = 0; i < capacity; i++) {
- Object* k = element_dictionary->KeyAt(i);
- if (element_dictionary->IsKey(k)) {
- Object* value = element_dictionary->ValueAt(i);
+ // Pixel elements cannot be created using an object literal.
+ ASSERT(!copy->HasPixelElements());
+ switch (copy->GetElementsKind()) {
+ case JSObject::FAST_ELEMENTS: {
+ FixedArray* elements = FixedArray::cast(copy->elements());
+ WriteBarrierMode mode = elements->GetWriteBarrierMode();
+ for (int i = 0; i < elements->length(); i++) {
+ Object* value = elements->get(i);
if (value->IsJSObject()) {
JSObject* jsObject = JSObject::cast(value);
result = DeepCopyBoilerplate(jsObject);
if (result->IsFailure()) return result;
- element_dictionary->ValueAtPut(i, result);
+ elements->set(i, result, mode);
+ }
+ }
+ break;
+ }
+ case JSObject::DICTIONARY_ELEMENTS: {
+ NumberDictionary* element_dictionary = copy->element_dictionary();
+ int capacity = element_dictionary->Capacity();
+ for (int i = 0; i < capacity; i++) {
+ Object* k = element_dictionary->KeyAt(i);
+ if (element_dictionary->IsKey(k)) {
+ Object* value = element_dictionary->ValueAt(i);
+ if (value->IsJSObject()) {
+ JSObject* jsObject = JSObject::cast(value);
+ result = DeepCopyBoilerplate(jsObject);
+ if (result->IsFailure()) return result;
+ element_dictionary->ValueAtPut(i, result);
+ }
}
}
+ break;
}
+ default:
+ UNREACHABLE();
+ break;
}
return copy;
}
}
case SUBJECT_CAPTURE: {
int capture = part.data;
- FixedArray* match_info = last_match_info->elements();
+ FixedArray* match_info = FixedArray::cast(last_match_info->elements());
int from = RegExpImpl::GetCapture(match_info, capture * 2);
int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
if (from >= 0 && to > from) {
int start, end;
{
AssertNoAllocation match_info_array_is_not_in_a_handle;
- FixedArray* match_info_array = last_match_info_handle->elements();
+ FixedArray* match_info_array =
+ FixedArray::cast(last_match_info_handle->elements());
ASSERT_EQ(capture_count * 2 + 2,
RegExpImpl::GetLastCaptureCount(match_info_array));
int end;
{
AssertNoAllocation no_alloc;
- FixedArray* elements = regexp_info->elements();
+ FixedArray* elements = FixedArray::cast(regexp_info->elements());
start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
}
AssertNoAllocation no_allocation;
- FixedArray* output_array = output->elements();
+ FixedArray* output_array = FixedArray::cast(output->elements());
RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
bool result;
if (str->IsAsciiRepresentation()) {
ArrayConcatVisitor* visitor) {
uint32_t num_of_elements = 0;
- if (receiver->HasFastElements()) {
- Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
- uint32_t len = elements->length();
- if (range < len) len = range;
+ switch (receiver->GetElementsKind()) {
+ case JSObject::FAST_ELEMENTS: {
+ Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
+ uint32_t len = elements->length();
+ if (range < len) {
+ len = range;
+ }
+
+ for (uint32_t j = 0; j < len; j++) {
+ Handle<Object> e(elements->get(j));
+ if (!e->IsTheHole()) {
+ num_of_elements++;
+ if (visitor) {
+ visitor->visit(j, e);
+ }
+ }
+ }
+ break;
+ }
+ case JSObject::PIXEL_ELEMENTS: {
+ Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
+ uint32_t len = pixels->length();
+ if (range < len) {
+ len = range;
+ }
- for (uint32_t j = 0; j < len; j++) {
- Handle<Object> e(elements->get(j));
- if (!e->IsTheHole()) {
+ for (uint32_t j = 0; j < len; j++) {
num_of_elements++;
- if (visitor)
+ if (visitor != NULL) {
+ Handle<Smi> e(Smi::FromInt(pixels->get(j)));
visitor->visit(j, e);
+ }
}
+ break;
}
-
- } else {
- Handle<NumberDictionary> dict(receiver->element_dictionary());
- uint32_t capacity = dict->Capacity();
- for (uint32_t j = 0; j < capacity; j++) {
- Handle<Object> k(dict->KeyAt(j));
- if (dict->IsKey(*k)) {
- ASSERT(k->IsNumber());
- uint32_t index = static_cast<uint32_t>(k->Number());
- if (index < range) {
- num_of_elements++;
- if (visitor) {
- visitor->visit(index,
- Handle<Object>(dict->ValueAt(j)));
+ case JSObject::DICTIONARY_ELEMENTS: {
+ Handle<NumberDictionary> dict(receiver->element_dictionary());
+ uint32_t capacity = dict->Capacity();
+ for (uint32_t j = 0; j < capacity; j++) {
+ Handle<Object> k(dict->KeyAt(j));
+ if (dict->IsKey(*k)) {
+ ASSERT(k->IsNumber());
+ uint32_t index = static_cast<uint32_t>(k->Number());
+ if (index < range) {
+ num_of_elements++;
+ if (visitor) {
+ visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
+ }
}
}
}
+ break;
}
+ default:
+ UNREACHABLE();
+ break;
}
return num_of_elements;
Address pc = frame->pc();
Address start = frame->code()->address();
Smi* offset = Smi::FromInt(pc - start);
- FixedArray* elements = result->elements();
+ FixedArray* elements = FixedArray::cast(result->elements());
if (cursor + 2 < elements->length()) {
elements->set(cursor++, recv);
elements->set(cursor++, fun);
context->DetachGlobal();
CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
}
+
+
+THREADED_TEST(PixelArray) {
+ v8::HandleScope scope;
+ LocalContext context;
+ const int kElementCount = 40;
+ uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
+ i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount,
+ pixel_data);
+ i::Heap::CollectAllGarbage(); // Force GC to trigger verification.
+ for (int i = 0; i < kElementCount; i++) {
+ pixels->set(i, i);
+ }
+ i::Heap::CollectAllGarbage(); // Force GC to trigger verification.
+ for (int i = 0; i < kElementCount; i++) {
+ CHECK_EQ(i, pixels->get(i));
+ CHECK_EQ(i, pixel_data[i]);
+ }
+
+ v8::Handle<v8::Object> obj = v8::Object::New();
+ i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
+ // Set the elements to be the pixels.
+ // jsobj->set_elements(*pixels);
+ obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
+ CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
+ obj->Set(v8_str("field"), v8::Int32::New(1503));
+ context->Global()->Set(v8_str("pixels"), obj);
+ v8::Handle<v8::Value> result = CompileRun("pixels.field");
+ CHECK_EQ(1503, result->Int32Value());
+ result = CompileRun("pixels[1]");
+ CHECK_EQ(1, result->Int32Value());
+ result = CompileRun("var sum = 0;"
+ "for (var i = 0; i < 8; i++) {"
+ " sum += pixels[i];"
+ "}"
+ "sum;");
+ CHECK_EQ(28, result->Int32Value());
+
+ i::Handle<i::Smi> value(i::Smi::FromInt(2));
+ i::SetElement(jsobj, 1, value);
+ CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1))->value());
+ *value.location() = i::Smi::FromInt(256);
+ i::SetElement(jsobj, 1, value);
+ CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(1))->value());
+ *value.location() = i::Smi::FromInt(-1);
+ i::SetElement(jsobj, 1, value);
+ CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
+
+ result = CompileRun("for (var i = 0; i < 8; i++) {"
+ " pixels[i] = (i * 65) - 109;"
+ "}"
+ "pixels[1] + pixels[6];");
+ CHECK_EQ(255, result->Int32Value());
+ CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
+ CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
+ CHECK_EQ(21, i::Smi::cast(jsobj->GetElement(2))->value());
+ CHECK_EQ(86, i::Smi::cast(jsobj->GetElement(3))->value());
+ CHECK_EQ(151, i::Smi::cast(jsobj->GetElement(4))->value());
+ CHECK_EQ(216, i::Smi::cast(jsobj->GetElement(5))->value());
+ CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(6))->value());
+ CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(7))->value());
+ result = CompileRun("var sum = 0;"
+ "for (var i = 0; i < 8; i++) {"
+ " sum += pixels[i];"
+ "}"
+ "sum;");
+ CHECK_EQ(984, result->Int32Value());
+
+ result = CompileRun("for (var i = 0; i < 8; i++) {"
+ " pixels[i] = (i * 1.1);"
+ "}"
+ "pixels[1] + pixels[6];");
+ CHECK_EQ(8, result->Int32Value());
+ CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
+ CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
+ CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2))->value());
+ CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3))->value());
+ CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4))->value());
+ CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5))->value());
+ CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6))->value());
+ CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7))->value());
+
+ result = CompileRun("for (var i = 0; i < 8; i++) {"
+ " pixels[7] = undefined;"
+ "}"
+ "pixels[7];");
+ CHECK_EQ(0, result->Int32Value());
+ CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7))->value());
+
+ result = CompileRun("for (var i = 0; i < 8; i++) {"
+ " pixels[6] = '2.3';"
+ "}"
+ "pixels[6];");
+ CHECK_EQ(2, result->Int32Value());
+ CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6))->value());
+
+ result = CompileRun("var nan = 0/0;"
+ "for (var i = 0; i < 8; i++) {"
+ " pixels[5] = nan;"
+ "}"
+ "pixels[5];");
+ CHECK_EQ(0, result->Int32Value());
+ CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
+
+ result = CompileRun("pixels[3] = 33;"
+ "delete pixels[3];"
+ "pixels[3];");
+ CHECK_EQ(33, result->Int32Value());
+
+ result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
+ "pixels[2] = 12; pixels[3] = 13;"
+ "pixels.__defineGetter__('2',"
+ "function() { return 120; });"
+ "pixels[2];");
+ CHECK_EQ(12, result->Int32Value());
+
+ result = CompileRun("var js_array = new Array(40);"
+ "js_array[0] = 77;"
+ "js_array;"
+ );
+ CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
+
+ result = CompileRun("pixels[1] = 23;"
+ "pixels.__proto__ = [];"
+ "js_array.__proto__ = pixels;"
+ "js_array.concat(pixels);");
+ CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
+ CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
+
+ free(pixel_data);
+}
uint32_t int_length = 0;
CHECK(Array::IndexFromObject(length, &int_length));
CHECK_EQ(length, array->length());
- CHECK(!array->HasFastElements()); // Must be in slow mode.
+ CHECK(array->HasDictionaryElements()); // Must be in slow mode.
// array[length] = name.
array->SetElement(int_length, name);