Commit 1ce28eda authored by iposva@chromium.org's avatar iposva@chromium.org

- Expose CanvasPixelArray functionality directly in JavaScript

  indexed property accesses.
- The IC stubs have not been updated to handle these directly, but
  at least we do not have to leave the VM to access bytes.

Review URL: http://codereview.chromium.org/159263

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2549 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 60bdcf9e
...@@ -1169,6 +1169,15 @@ class V8EXPORT Object : public Value { ...@@ -1169,6 +1169,15 @@ class V8EXPORT Object : public Value {
*/ */
Local<Object> Clone(); 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 Local<Object> New();
static Object* Cast(Value* obj); static Object* Cast(Value* obj);
private: private:
......
...@@ -2194,6 +2194,25 @@ bool v8::Object::DeleteHiddenValue(v8::Handle<v8::String> key) { ...@@ -2194,6 +2194,25 @@ bool v8::Object::DeleteHiddenValue(v8::Handle<v8::String> key) {
} }
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 { Local<v8::Object> Function::NewInstance() const {
return NewInstance(0, NULL); return NewInstance(0, NULL);
} }
...@@ -3057,7 +3076,7 @@ Local<Object> Array::CloneElementAt(uint32_t index) { ...@@ -3057,7 +3076,7 @@ Local<Object> Array::CloneElementAt(uint32_t index) {
if (!self->HasFastElements()) { if (!self->HasFastElements()) {
return Local<Object>(); return Local<Object>();
} }
i::FixedArray* elms = self->elements(); i::FixedArray* elms = i::FixedArray::cast(self->elements());
i::Object* paragon = elms->get(index); i::Object* paragon = elms->get(index);
if (!paragon->IsJSObject()) { if (!paragon->IsJSObject()) {
return Local<Object>(); return Local<Object>();
......
...@@ -582,8 +582,8 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { ...@@ -582,8 +582,8 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
__ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset)); __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
// Check that the object is in fast mode (not dictionary). // Check that the object is in fast mode (not dictionary).
__ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset)); __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
__ cmp(r3, Operand(Factory::hash_table_map())); __ cmp(r3, Operand(Factory::fixed_array_map()));
__ b(eq, &slow); __ b(ne, &slow);
// Check that the key (index) is within bounds. // Check that the key (index) is within bounds.
__ ldr(r3, FieldMemOperand(r1, Array::kLengthOffset)); __ ldr(r3, FieldMemOperand(r1, Array::kLengthOffset));
__ cmp(r0, Operand(r3)); __ cmp(r0, Operand(r3));
...@@ -661,8 +661,8 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { ...@@ -661,8 +661,8 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
__ ldr(r3, FieldMemOperand(r3, JSObject::kElementsOffset)); __ ldr(r3, FieldMemOperand(r3, JSObject::kElementsOffset));
// Check that the object is in fast mode (not dictionary). // Check that the object is in fast mode (not dictionary).
__ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset)); __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
__ cmp(r2, Operand(Factory::hash_table_map())); __ cmp(r2, Operand(Factory::fixed_array_map()));
__ b(eq, &slow); __ b(ne, &slow);
// Untag the key (for checking against untagged length in the fixed array). // Untag the key (for checking against untagged length in the fixed array).
__ mov(r1, Operand(r1, ASR, kSmiTagSize)); __ mov(r1, Operand(r1, ASR, kSmiTagSize));
// Compute address to store into and check array bounds. // Compute address to store into and check array bounds.
...@@ -710,8 +710,8 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { ...@@ -710,8 +710,8 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
__ bind(&array); __ bind(&array);
__ ldr(r2, FieldMemOperand(r3, JSObject::kElementsOffset)); __ ldr(r2, FieldMemOperand(r3, JSObject::kElementsOffset));
__ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset)); __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
__ cmp(r1, Operand(Factory::hash_table_map())); __ cmp(r1, Operand(Factory::fixed_array_map()));
__ b(eq, &slow); __ b(ne, &slow);
// Check the key against the length in the array, compute the // Check the key against the length in the array, compute the
// address to store into and fall through to fast case. // address to store into and fall through to fast case.
......
...@@ -210,6 +210,16 @@ Handle<ByteArray> Factory::NewByteArray(int length, PretenureFlag pretenure) { ...@@ -210,6 +210,16 @@ Handle<ByteArray> Factory::NewByteArray(int length, PretenureFlag pretenure) {
} }
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) { Handle<Map> Factory::NewMap(InstanceType type, int instance_size) {
CALL_HEAP_FUNCTION(Heap::AllocateMap(type, instance_size), Map); CALL_HEAP_FUNCTION(Heap::AllocateMap(type, instance_size), Map);
} }
......
...@@ -154,6 +154,10 @@ class Factory : public AllStatic { ...@@ -154,6 +154,10 @@ class Factory : public AllStatic {
static Handle<ByteArray> NewByteArray(int length, static Handle<ByteArray> NewByteArray(int length,
PretenureFlag pretenure = NOT_TENURED); 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<Map> NewMap(InstanceType type, int instance_size);
static Handle<JSObject> NewFunctionPrototype(Handle<JSFunction> function); static Handle<JSObject> NewFunctionPrototype(Handle<JSFunction> function);
......
...@@ -207,6 +207,7 @@ class HeapObject; ...@@ -207,6 +207,7 @@ class HeapObject;
class IC; class IC;
class InterceptorInfo; class InterceptorInfo;
class IterationStatement; class IterationStatement;
class Array;
class JSArray; class JSArray;
class JSFunction; class JSFunction;
class JSObject; class JSObject;
......
...@@ -341,6 +341,14 @@ Handle<String> SubString(Handle<String> str, int start, int end) { ...@@ -341,6 +341,14 @@ Handle<String> SubString(Handle<String> str, int start, int end) {
Handle<Object> SetElement(Handle<JSObject> object, Handle<Object> SetElement(Handle<JSObject> object,
uint32_t index, uint32_t index,
Handle<Object> value) { 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); CALL_HEAP_FUNCTION(object->SetElement(index, *value), Object);
} }
......
...@@ -1191,6 +1191,10 @@ bool Heap::CreateInitialMaps() { ...@@ -1191,6 +1191,10 @@ bool Heap::CreateInitialMaps() {
if (obj->IsFailure()) return false; if (obj->IsFailure()) return false;
set_byte_array_map(Map::cast(obj)); 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); obj = AllocateMap(CODE_TYPE, Code::kHeaderSize);
if (obj->IsFailure()) return false; if (obj->IsFailure()) return false;
set_code_map(Map::cast(obj)); set_code_map(Map::cast(obj));
...@@ -1576,8 +1580,7 @@ Object* Heap::NumberFromDouble(double value, PretenureFlag pretenure) { ...@@ -1576,8 +1580,7 @@ Object* Heap::NumberFromDouble(double value, PretenureFlag pretenure) {
Object* Heap::AllocateProxy(Address proxy, PretenureFlag pretenure) { Object* Heap::AllocateProxy(Address proxy, PretenureFlag pretenure) {
// Statically ensure that it is safe to allocate proxies in paged spaces. // Statically ensure that it is safe to allocate proxies in paged spaces.
STATIC_ASSERT(Proxy::kSize <= Page::kMaxHeapObjectSize); STATIC_ASSERT(Proxy::kSize <= Page::kMaxHeapObjectSize);
AllocationSpace space = AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
(pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
Object* result = Allocate(proxy_map(), space); Object* result = Allocate(proxy_map(), space);
if (result->IsFailure()) return result; if (result->IsFailure()) return result;
...@@ -1859,6 +1862,23 @@ void Heap::CreateFillerObjectAt(Address addr, int size) { ...@@ -1859,6 +1862,23 @@ void Heap::CreateFillerObjectAt(Address addr, int size) {
} }
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, Object* Heap::CreateCode(const CodeDesc& desc,
ZoneScopeInfo* sinfo, ZoneScopeInfo* sinfo,
Code::Flags flags, Code::Flags flags,
......
...@@ -94,6 +94,7 @@ namespace internal { ...@@ -94,6 +94,7 @@ namespace internal {
UndetectableMediumAsciiStringMap) \ UndetectableMediumAsciiStringMap) \
V(Map, undetectable_long_ascii_string_map, UndetectableLongAsciiStringMap) \ V(Map, undetectable_long_ascii_string_map, UndetectableLongAsciiStringMap) \
V(Map, byte_array_map, ByteArrayMap) \ V(Map, byte_array_map, ByteArrayMap) \
V(Map, pixel_array_map, PixelArrayMap) \
V(Map, fixed_array_map, FixedArrayMap) \ V(Map, fixed_array_map, FixedArrayMap) \
V(Map, hash_table_map, HashTableMap) \ V(Map, hash_table_map, HashTableMap) \
V(Map, context_map, ContextMap) \ V(Map, context_map, ContextMap) \
...@@ -418,6 +419,14 @@ class Heap : public AllStatic { ...@@ -418,6 +419,14 @@ class Heap : public AllStatic {
// Please note this does not perform a garbage collection. // Please note this does not perform a garbage collection.
static Object* AllocateByteArray(int length); 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. // Allocate a tenured JS global property cell.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed. // failed.
......
...@@ -6297,8 +6297,8 @@ void Reference::GetValue(TypeofState typeof_state) { ...@@ -6297,8 +6297,8 @@ void Reference::GetValue(TypeofState typeof_state) {
__ mov(elements.reg(), __ mov(elements.reg(),
FieldOperand(receiver.reg(), JSObject::kElementsOffset)); FieldOperand(receiver.reg(), JSObject::kElementsOffset));
__ cmp(FieldOperand(elements.reg(), HeapObject::kMapOffset), __ cmp(FieldOperand(elements.reg(), HeapObject::kMapOffset),
Immediate(Factory::hash_table_map())); Immediate(Factory::fixed_array_map()));
deferred->Branch(equal); deferred->Branch(not_equal);
// Shift the key to get the actual index value and check that // Shift the key to get the actual index value and check that
// it is within bounds. // it is within bounds.
......
...@@ -234,7 +234,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { ...@@ -234,7 +234,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// -- esp[4] : name // -- esp[4] : name
// -- esp[8] : receiver // -- 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. // Load name and receiver.
__ mov(eax, Operand(esp, kPointerSize)); __ mov(eax, Operand(esp, kPointerSize));
...@@ -269,11 +269,36 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { ...@@ -269,11 +269,36 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
__ mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset)); __ mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset));
// Check that the object is in fast mode (not dictionary). // Check that the object is in fast mode (not dictionary).
__ cmp(FieldOperand(ecx, HeapObject::kMapOffset), __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
Immediate(Factory::hash_table_map())); Immediate(Factory::fixed_array_map()));
__ j(equal, &slow, not_taken); __ j(not_equal, &check_pixel_array);
// Check that the key (index) is within bounds. // Check that the key (index) is within bounds.
__ cmp(eax, FieldOperand(ecx, FixedArray::kLengthOffset)); __ 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. // Slow case: Load name and receiver from stack and jump to runtime.
__ bind(&slow); __ bind(&slow);
__ IncrementCounter(&Counters::keyed_load_generic_slow, 1); __ IncrementCounter(&Counters::keyed_load_generic_slow, 1);
...@@ -315,16 +340,6 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { ...@@ -315,16 +340,6 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
__ and_(eax, (1 << String::kShortLengthShift) - 1); __ and_(eax, (1 << String::kShortLengthShift) - 1);
__ shr(eax, String::kLongLengthShift); __ shr(eax, String::kLongLengthShift);
__ jmp(&index_int); __ 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);
} }
...@@ -335,7 +350,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { ...@@ -335,7 +350,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
// -- esp[4] : key // -- esp[4] : key
// -- esp[8] : receiver // -- esp[8] : receiver
// ----------------------------------- // -----------------------------------
Label slow, fast, array, extra; Label slow, fast, array, extra, check_pixel_array;
// Get the receiver from the stack. // Get the receiver from the stack.
__ mov(edx, Operand(esp, 2 * kPointerSize)); // 2 ~ return address, key __ mov(edx, Operand(esp, 2 * kPointerSize)); // 2 ~ return address, key
...@@ -370,8 +385,8 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { ...@@ -370,8 +385,8 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
__ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset)); __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
// Check that the object is in fast mode (not dictionary). // Check that the object is in fast mode (not dictionary).
__ cmp(FieldOperand(ecx, HeapObject::kMapOffset), __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
Immediate(Factory::hash_table_map())); Immediate(Factory::fixed_array_map()));
__ j(equal, &slow, not_taken); __ j(not_equal, &check_pixel_array, not_taken);
// Untag the key (for checking against untagged length in the fixed array). // Untag the key (for checking against untagged length in the fixed array).
__ mov(edx, Operand(ebx)); __ mov(edx, Operand(ebx));
__ sar(edx, kSmiTagSize); // untag the index and use it for the comparison __ sar(edx, kSmiTagSize); // untag the index and use it for the comparison
...@@ -381,7 +396,6 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { ...@@ -381,7 +396,6 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
// ebx: index (as a smi) // ebx: index (as a smi)
__ j(below, &fast, taken); __ j(below, &fast, taken);
// Slow case: Push extra copies of the arguments (3). // Slow case: Push extra copies of the arguments (3).
__ bind(&slow); __ bind(&slow);
__ pop(ecx); __ pop(ecx);
...@@ -392,6 +406,37 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { ...@@ -392,6 +406,37 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
// Do tail-call to runtime routine. // Do tail-call to runtime routine.
__ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3); __ 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 // Extra capacity case: Check if there is extra capacity to
// perform the store and update the length. Used for adding one // perform the store and update the length. Used for adding one
...@@ -422,15 +467,14 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { ...@@ -422,15 +467,14 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
// ebx: index (as a smi) // ebx: index (as a smi)
__ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset)); __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
__ cmp(FieldOperand(ecx, HeapObject::kMapOffset), __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
Immediate(Factory::hash_table_map())); Immediate(Factory::fixed_array_map()));
__ j(equal, &slow, not_taken); __ j(not_equal, &check_pixel_array);
// Check the key against the length in the array, compute the // Check the key against the length in the array, compute the
// address to store into and fall through to fast case. // address to store into and fall through to fast case.
__ cmp(ebx, FieldOperand(edx, JSArray::kLengthOffset)); __ cmp(ebx, FieldOperand(edx, JSArray::kLengthOffset));
__ j(above_equal, &extra, not_taken); __ j(above_equal, &extra, not_taken);
// Fast case: Do the store. // Fast case: Do the store.
__ bind(&fast); __ bind(&fast);
// eax: value // eax: value
......
...@@ -254,7 +254,7 @@ Handle<Object> RegExpImpl::AtomExec(Handle<JSRegExp> re, ...@@ -254,7 +254,7 @@ Handle<Object> RegExpImpl::AtomExec(Handle<JSRegExp> re,
{ {
NoHandleAllocation no_handles; NoHandleAllocation no_handles;
FixedArray* array = last_match_info->elements(); FixedArray* array = FixedArray::cast(last_match_info->elements());
SetAtomLastCapture(array, *subject, value, value + needle->length()); SetAtomLastCapture(array, *subject, value, value + needle->length());
} }
return last_match_info; return last_match_info;
...@@ -442,7 +442,7 @@ Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> jsregexp, ...@@ -442,7 +442,7 @@ Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> jsregexp,
if (res != RegExpMacroAssemblerIA32::SUCCESS) return Factory::null_value(); 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); ASSERT(array->length() >= number_of_capture_registers + kLastMatchOverhead);
// The captures come in (start, end+1) pairs. // The captures come in (start, end+1) pairs.
for (int i = 0; i < number_of_capture_registers; i += 2) { for (int i = 0; i < number_of_capture_registers; i += 2) {
...@@ -475,7 +475,7 @@ Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> jsregexp, ...@@ -475,7 +475,7 @@ Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> jsregexp,
return Factory::null_value(); 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); ASSERT(array->length() >= number_of_capture_registers + kLastMatchOverhead);
// The captures come in (start, end+1) pairs. // The captures come in (start, end+1) pairs.
for (int i = 0; i < number_of_capture_registers; i += 2) { for (int i = 0; i < number_of_capture_registers; i += 2) {
......
...@@ -115,6 +115,9 @@ void HeapObject::HeapObjectPrint() { ...@@ -115,6 +115,9 @@ void HeapObject::HeapObjectPrint() {
case BYTE_ARRAY_TYPE: case BYTE_ARRAY_TYPE:
ByteArray::cast(this)->ByteArrayPrint(); ByteArray::cast(this)->ByteArrayPrint();
break; break;
case PIXEL_ARRAY_TYPE:
PixelArray::cast(this)->PixelArrayPrint();
break;
case FILLER_TYPE: case FILLER_TYPE:
PrintF("filler"); PrintF("filler");
break; break;
...@@ -191,6 +194,9 @@ void HeapObject::HeapObjectVerify() { ...@@ -191,6 +194,9 @@ void HeapObject::HeapObjectVerify() {
case BYTE_ARRAY_TYPE: case BYTE_ARRAY_TYPE:
ByteArray::cast(this)->ByteArrayVerify(); ByteArray::cast(this)->ByteArrayVerify();
break; break;
case PIXEL_ARRAY_TYPE:
PixelArray::cast(this)->PixelArrayVerify();
break;
case CODE_TYPE: case CODE_TYPE:
Code::cast(this)->CodeVerify(); Code::cast(this)->CodeVerify();
break; break;
...@@ -264,11 +270,21 @@ void ByteArray::ByteArrayPrint() { ...@@ -264,11 +270,21 @@ void ByteArray::ByteArrayPrint() {
} }
void PixelArray::PixelArrayPrint() {
PrintF("pixel array");
}
void ByteArray::ByteArrayVerify() { void ByteArray::ByteArrayVerify() {
ASSERT(IsByteArray()); ASSERT(IsByteArray());
} }
void PixelArray::PixelArrayVerify() {
ASSERT(IsPixelArray());
}
void JSObject::PrintProperties() { void JSObject::PrintProperties() {
if (HasFastProperties()) { if (HasFastProperties()) {
DescriptorArray* descs = map()->instance_descriptors(); DescriptorArray* descs = map()->instance_descriptors();
...@@ -312,15 +328,30 @@ void JSObject::PrintProperties() { ...@@ -312,15 +328,30 @@ void JSObject::PrintProperties() {
void JSObject::PrintElements() { void JSObject::PrintElements() {
if (HasFastElements()) { switch (GetElementsKind()) {
FixedArray* p = FixedArray::cast(elements()); case FAST_ELEMENTS: {
for (int i = 0; i < p->length(); i++) { // Print in array notation for non-sparse arrays.
PrintF(" %d: ", i); FixedArray* p = FixedArray::cast(elements());
p->get(i)->ShortPrint(); for (int i = 0; i < p->length(); i++) {
PrintF("\n"); PrintF(" %d: ", i);
p->get(i)->ShortPrint();
PrintF("\n");
}
break;
} }
} else { case PIXEL_ELEMENTS: {
elements()->Print(); 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;
} }
} }
...@@ -402,6 +433,7 @@ static const char* TypeToString(InstanceType type) { ...@@ -402,6 +433,7 @@ static const char* TypeToString(InstanceType type) {
case LONG_EXTERNAL_STRING_TYPE: return "EXTERNAL_STRING"; case LONG_EXTERNAL_STRING_TYPE: return "EXTERNAL_STRING";
case FIXED_ARRAY_TYPE: return "FIXED_ARRAY"; case FIXED_ARRAY_TYPE: return "FIXED_ARRAY";
case BYTE_ARRAY_TYPE: return "BYTE_ARRAY"; case BYTE_ARRAY_TYPE: return "BYTE_ARRAY";
case PIXEL_ARRAY_TYPE: return "PIXEL_ARRAY";
case FILLER_TYPE: return "FILLER"; case FILLER_TYPE: return "FILLER";
case JS_OBJECT_TYPE: return "JS_OBJECT"; case JS_OBJECT_TYPE: return "JS_OBJECT";
case JS_CONTEXT_EXTENSION_OBJECT_TYPE: return "JS_CONTEXT_EXTENSION_OBJECT"; case JS_CONTEXT_EXTENSION_OBJECT_TYPE: return "JS_CONTEXT_EXTENSION_OBJECT";
...@@ -1015,21 +1047,35 @@ void JSObject::IncrementSpillStatistics(SpillInformation* info) { ...@@ -1015,21 +1047,35 @@ void JSObject::IncrementSpillStatistics(SpillInformation* info) {
dict->Capacity() - dict->NumberOfElements(); dict->Capacity() - dict->NumberOfElements();
} }
// Indexed properties // Indexed properties
if (HasFastElements()) { switch (GetElementsKind()) {
info->number_of_objects_with_fast_elements_++; case FAST_ELEMENTS: {
int holes = 0; info->number_of_objects_with_fast_elements_++;
FixedArray* e = FixedArray::cast(elements()); int holes = 0;
int len = e->length(); FixedArray* e = FixedArray::cast(elements());
for (int i = 0; i < len; i++) { int len = e->length();
if (e->get(i) == Heap::the_hole_value()) holes++; 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; case PIXEL_ELEMENTS: {
info->number_of_fast_unused_elements_ += holes; info->number_of_objects_with_fast_elements_++;
} else { PixelArray* e = PixelArray::cast(elements());
NumberDictionary* dict = element_dictionary(); info->number_of_fast_used_elements_ += e->length();
info->number_of_slow_used_elements_ += dict->NumberOfElements(); break;
info->number_of_slow_unused_elements_ += }
dict->Capacity() - dict->NumberOfElements(); 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;
} }
} }
......
...@@ -321,6 +321,12 @@ bool Object::IsByteArray() { ...@@ -321,6 +321,12 @@ bool Object::IsByteArray() {
} }
bool Object::IsPixelArray() {
return Object::IsHeapObject() &&
HeapObject::cast(this)->map()->instance_type() == PIXEL_ARRAY_TYPE;
}
bool Object::IsFailure() { bool Object::IsFailure() {
return HAS_FAILURE_TAG(this); return HAS_FAILURE_TAG(this);
} }
...@@ -1043,7 +1049,22 @@ void HeapNumber::set_value(double value) { ...@@ -1043,7 +1049,22 @@ void HeapNumber::set_value(double value) {
ACCESSORS(JSObject, properties, FixedArray, kPropertiesOffset) 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() { void JSObject::initialize_properties() {
...@@ -1502,6 +1523,7 @@ CAST_ACCESSOR(JSArray) ...@@ -1502,6 +1523,7 @@ CAST_ACCESSOR(JSArray)
CAST_ACCESSOR(JSRegExp) CAST_ACCESSOR(JSRegExp)
CAST_ACCESSOR(Proxy) CAST_ACCESSOR(Proxy)
CAST_ACCESSOR(ByteArray) CAST_ACCESSOR(ByteArray)
CAST_ACCESSOR(PixelArray)
CAST_ACCESSOR(Struct) CAST_ACCESSOR(Struct)
...@@ -1860,6 +1882,32 @@ Address ByteArray::GetDataStartAddress() { ...@@ -1860,6 +1882,32 @@ Address ByteArray::GetDataStartAddress() {
} }
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() { int Map::instance_size() {
return READ_BYTE_FIELD(this, kInstanceSizeOffset) << kPointerSizeLog2; return READ_BYTE_FIELD(this, kInstanceSizeOffset) << kPointerSizeLog2;
} }
...@@ -2523,8 +2571,33 @@ void JSRegExp::SetDataAt(int index, Object* value) { ...@@ -2523,8 +2571,33 @@ void JSRegExp::SetDataAt(int index, Object* value) {
} }
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() { bool JSObject::HasFastElements() {
return !elements()->IsDictionary(); return GetElementsKind() == FAST_ELEMENTS;
}
bool JSObject::HasDictionaryElements() {
return GetElementsKind() == DICTIONARY_ELEMENTS;
}
bool JSObject::HasPixelElements() {
return GetElementsKind() == PIXEL_ELEMENTS;
} }
...@@ -2545,7 +2618,7 @@ StringDictionary* JSObject::property_dictionary() { ...@@ -2545,7 +2618,7 @@ StringDictionary* JSObject::property_dictionary() {
NumberDictionary* JSObject::element_dictionary() { NumberDictionary* JSObject::element_dictionary() {
ASSERT(!HasFastElements()); ASSERT(HasDictionaryElements());
return NumberDictionary::cast(elements()); return NumberDictionary::cast(elements());
} }
......
This diff is collapsed.
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
// - JSValue // - JSValue
// - Array // - Array
// - ByteArray // - ByteArray
// - PixelArray
// - FixedArray // - FixedArray
// - DescriptorArray // - DescriptorArray
// - HashTable // - HashTable
...@@ -95,7 +96,6 @@ ...@@ -95,7 +96,6 @@
// HeapObject: [32 bit direct pointer] (4 byte aligned) | 01 // HeapObject: [32 bit direct pointer] (4 byte aligned) | 01
// Failure: [30 bit signed int] 11 // Failure: [30 bit signed int] 11
// Ecma-262 3rd 8.6.1 // Ecma-262 3rd 8.6.1
enum PropertyAttributes { enum PropertyAttributes {
NONE = v8::None, NONE = v8::None,
...@@ -270,6 +270,7 @@ enum PropertyNormalizationMode { ...@@ -270,6 +270,7 @@ enum PropertyNormalizationMode {
V(ODDBALL_TYPE) \ V(ODDBALL_TYPE) \
V(PROXY_TYPE) \ V(PROXY_TYPE) \
V(BYTE_ARRAY_TYPE) \ V(BYTE_ARRAY_TYPE) \
V(PIXEL_ARRAY_TYPE) \
V(FILLER_TYPE) \ V(FILLER_TYPE) \
\ \
V(ACCESSOR_INFO_TYPE) \ V(ACCESSOR_INFO_TYPE) \
...@@ -659,6 +660,7 @@ enum InstanceType { ...@@ -659,6 +660,7 @@ enum InstanceType {
JS_GLOBAL_PROPERTY_CELL_TYPE, JS_GLOBAL_PROPERTY_CELL_TYPE,
PROXY_TYPE, PROXY_TYPE,
BYTE_ARRAY_TYPE, BYTE_ARRAY_TYPE,
PIXEL_ARRAY_TYPE,
FILLER_TYPE, FILLER_TYPE,
SMI_TYPE, SMI_TYPE,
...@@ -760,6 +762,7 @@ class Object BASE_EMBEDDED { ...@@ -760,6 +762,7 @@ class Object BASE_EMBEDDED {
inline bool IsNumber(); inline bool IsNumber();
inline bool IsByteArray(); inline bool IsByteArray();
inline bool IsPixelArray();
inline bool IsFailure(); inline bool IsFailure();
inline bool IsRetryAfterGC(); inline bool IsRetryAfterGC();
inline bool IsOutOfMemoryFailure(); inline bool IsOutOfMemoryFailure();
...@@ -1302,6 +1305,11 @@ class HeapNumber: public HeapObject { ...@@ -1302,6 +1305,11 @@ class HeapNumber: public HeapObject {
class JSObject: public HeapObject { class JSObject: public HeapObject {
public: public:
enum DeleteMode { NORMAL_DELETION, FORCE_DELETION }; enum DeleteMode { NORMAL_DELETION, FORCE_DELETION };
enum ElementsKind {
FAST_ELEMENTS,
DICTIONARY_ELEMENTS,
PIXEL_ELEMENTS
};
// [properties]: Backing storage for properties. // [properties]: Backing storage for properties.
// properties is a FixedArray in the fast case, and a Dictionary in the // properties is a FixedArray in the fast case, and a Dictionary in the
...@@ -1313,10 +1321,13 @@ class JSObject: public HeapObject { ...@@ -1313,10 +1321,13 @@ class JSObject: public HeapObject {
// [elements]: The elements (properties with names that are integers). // [elements]: The elements (properties with names that are integers).
// elements is a FixedArray in the fast case, and a Dictionary in the slow // elements is a FixedArray in the fast case, and a Dictionary in the slow
// case. // case or a PixelArray in a special case.
DECL_ACCESSORS(elements, FixedArray) // Get and set fast elements. DECL_ACCESSORS(elements, Array) // Get and set fast elements.
inline void initialize_elements(); inline void initialize_elements();
inline ElementsKind GetElementsKind();
inline bool HasFastElements(); inline bool HasFastElements();
inline bool HasDictionaryElements();
inline bool HasPixelElements();
inline NumberDictionary* element_dictionary(); // Gets slow elements. inline NumberDictionary* element_dictionary(); // Gets slow elements.
// Collects elements starting at index 0. // Collects elements starting at index 0.
...@@ -2440,6 +2451,43 @@ class ByteArray: public Array { ...@@ -2440,6 +2451,43 @@ class ByteArray: public Array {
}; };
// 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. // Code describes objects with on-the-fly generated machine code.
class Code: public HeapObject { class Code: public HeapObject {
public: public:
......
...@@ -155,33 +155,43 @@ static Object* DeepCopyBoilerplate(JSObject* boilerplate) { ...@@ -155,33 +155,43 @@ static Object* DeepCopyBoilerplate(JSObject* boilerplate) {
} }
// Deep copy local elements. // Deep copy local elements.
if (copy->HasFastElements()) { // Pixel elements cannot be created using an object literal.
FixedArray* elements = copy->elements(); ASSERT(!copy->HasPixelElements());
WriteBarrierMode mode = elements->GetWriteBarrierMode(); switch (copy->GetElementsKind()) {
for (int i = 0; i < elements->length(); i++) { case JSObject::FAST_ELEMENTS: {
Object* value = elements->get(i); FixedArray* elements = FixedArray::cast(copy->elements());
if (value->IsJSObject()) { WriteBarrierMode mode = elements->GetWriteBarrierMode();
JSObject* jsObject = JSObject::cast(value); for (int i = 0; i < elements->length(); i++) {
result = DeepCopyBoilerplate(jsObject); Object* value = elements->get(i);
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);
if (value->IsJSObject()) { if (value->IsJSObject()) {
JSObject* jsObject = JSObject::cast(value); JSObject* jsObject = JSObject::cast(value);
result = DeepCopyBoilerplate(jsObject); result = DeepCopyBoilerplate(jsObject);
if (result->IsFailure()) return result; 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; return copy;
} }
...@@ -1637,7 +1647,7 @@ void CompiledReplacement::Apply(ReplacementStringBuilder* builder, ...@@ -1637,7 +1647,7 @@ void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
} }
case SUBJECT_CAPTURE: { case SUBJECT_CAPTURE: {
int capture = part.data; 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 from = RegExpImpl::GetCapture(match_info, capture * 2);
int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1); int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
if (from >= 0 && to > from) { if (from >= 0 && to > from) {
...@@ -1717,7 +1727,8 @@ static Object* StringReplaceRegExpWithString(String* subject, ...@@ -1717,7 +1727,8 @@ static Object* StringReplaceRegExpWithString(String* subject,
int start, end; int start, end;
{ {
AssertNoAllocation match_info_array_is_not_in_a_handle; 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, ASSERT_EQ(capture_count * 2 + 2,
RegExpImpl::GetLastCaptureCount(match_info_array)); RegExpImpl::GetLastCaptureCount(match_info_array));
...@@ -2345,7 +2356,7 @@ static Object* Runtime_StringMatch(Arguments args) { ...@@ -2345,7 +2356,7 @@ static Object* Runtime_StringMatch(Arguments args) {
int end; int end;
{ {
AssertNoAllocation no_alloc; AssertNoAllocation no_alloc;
FixedArray* elements = regexp_info->elements(); FixedArray* elements = FixedArray::cast(regexp_info->elements());
start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value(); start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value(); end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
} }
...@@ -4885,7 +4896,7 @@ static Object* Runtime_DateParseString(Arguments args) { ...@@ -4885,7 +4896,7 @@ static Object* Runtime_DateParseString(Arguments args) {
AssertNoAllocation no_allocation; AssertNoAllocation no_allocation;
FixedArray* output_array = output->elements(); FixedArray* output_array = FixedArray::cast(output->elements());
RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE); RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
bool result; bool result;
if (str->IsAsciiRepresentation()) { if (str->IsAsciiRepresentation()) {
...@@ -5173,37 +5184,62 @@ static uint32_t IterateElements(Handle<JSObject> receiver, ...@@ -5173,37 +5184,62 @@ static uint32_t IterateElements(Handle<JSObject> receiver,
ArrayConcatVisitor* visitor) { ArrayConcatVisitor* visitor) {
uint32_t num_of_elements = 0; uint32_t num_of_elements = 0;
if (receiver->HasFastElements()) { switch (receiver->GetElementsKind()) {
Handle<FixedArray> elements(FixedArray::cast(receiver->elements())); case JSObject::FAST_ELEMENTS: {
uint32_t len = elements->length(); Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
if (range < len) len = range; 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++) { for (uint32_t j = 0; j < len; j++) {
Handle<Object> e(elements->get(j));
if (!e->IsTheHole()) {
num_of_elements++; num_of_elements++;
if (visitor) if (visitor != NULL) {
Handle<Smi> e(Smi::FromInt(pixels->get(j)));
visitor->visit(j, e); visitor->visit(j, e);
}
} }
break;
} }
case JSObject::DICTIONARY_ELEMENTS: {
} else { Handle<NumberDictionary> dict(receiver->element_dictionary());
Handle<NumberDictionary> dict(receiver->element_dictionary()); uint32_t capacity = dict->Capacity();
uint32_t capacity = dict->Capacity(); for (uint32_t j = 0; j < capacity; j++) {
for (uint32_t j = 0; j < capacity; j++) { Handle<Object> k(dict->KeyAt(j));
Handle<Object> k(dict->KeyAt(j)); if (dict->IsKey(*k)) {
if (dict->IsKey(*k)) { ASSERT(k->IsNumber());
ASSERT(k->IsNumber()); uint32_t index = static_cast<uint32_t>(k->Number());
uint32_t index = static_cast<uint32_t>(k->Number()); if (index < range) {
if (index < range) { num_of_elements++;
num_of_elements++; if (visitor) {
if (visitor) { visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
visitor->visit(index, }
Handle<Object>(dict->ValueAt(j)));
} }
} }
} }
break;
} }
default:
UNREACHABLE();
break;
} }
return num_of_elements; return num_of_elements;
...@@ -7449,7 +7485,7 @@ static Object* Runtime_CollectStackTrace(Arguments args) { ...@@ -7449,7 +7485,7 @@ static Object* Runtime_CollectStackTrace(Arguments args) {
Address pc = frame->pc(); Address pc = frame->pc();
Address start = frame->code()->address(); Address start = frame->code()->address();
Smi* offset = Smi::FromInt(pc - start); Smi* offset = Smi::FromInt(pc - start);
FixedArray* elements = result->elements(); FixedArray* elements = FixedArray::cast(result->elements());
if (cursor + 2 < elements->length()) { if (cursor + 2 < elements->length()) {
elements->set(cursor++, recv); elements->set(cursor++, recv);
elements->set(cursor++, fun); elements->set(cursor++, fun);
......
...@@ -7548,3 +7548,134 @@ THREADED_TEST(Regress16276) { ...@@ -7548,3 +7548,134 @@ THREADED_TEST(Regress16276) {
context->DetachGlobal(); context->DetachGlobal();
CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value()); 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);
}
...@@ -653,7 +653,7 @@ TEST(JSArray) { ...@@ -653,7 +653,7 @@ TEST(JSArray) {
uint32_t int_length = 0; uint32_t int_length = 0;
CHECK(Array::IndexFromObject(length, &int_length)); CHECK(Array::IndexFromObject(length, &int_length));
CHECK_EQ(length, array->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[length] = name.
array->SetElement(int_length, name); array->SetElement(int_length, name);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment