diff --git a/src/api.cc b/src/api.cc index 188047bcc2..8d3018409a 100644 --- a/src/api.cc +++ b/src/api.cc @@ -2757,9 +2757,9 @@ void v8::Object::SetIndexedPropertiesToPixelData(uint8_t* data, int length) { return; } i::Handle pixels = i::Factory::NewPixelArray(length, data); - i::Handle slow_map = - i::Factory::GetSlowElementsMap(i::Handle(self->map())); - self->set_map(*slow_map); + i::Handle pixel_array_map = + i::Factory::GetPixelArrayElementsMap(i::Handle(self->map())); + self->set_map(*pixel_array_map); self->set_elements(*pixels); } diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index 11889d758b..10cca20621 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -1500,6 +1500,12 @@ LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) { } +LInstruction* LChunkBuilder::DoPixelArrayLength(HPixelArrayLength* instr) { + LOperand* array = UseRegisterAtStart(instr->value()); + return DefineAsRegister(new LPixelArrayLength(array)); +} + + LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) { LOperand* array = UseRegisterAtStart(instr->value()); return DefineAsRegister(new LFixedArrayLength(array)); @@ -1714,7 +1720,14 @@ LInstruction* LChunkBuilder::DoLoadFunctionPrototype( LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) { LOperand* input = UseRegisterAtStart(instr->value()); - return DefineSameAsFirst(new LLoadElements(input)); + return DefineAsRegister(new LLoadElements(input)); +} + + +LInstruction* LChunkBuilder::DoLoadPixelArrayExternalPointer( + HLoadPixelArrayExternalPointer* instr) { + LOperand* input = UseRegisterAtStart(instr->value()); + return DefineAsRegister(new LLoadPixelArrayExternalPointer(input)); } @@ -1729,6 +1742,19 @@ LInstruction* LChunkBuilder::DoLoadKeyedFastElement( } +LInstruction* LChunkBuilder::DoLoadPixelArrayElement( + HLoadPixelArrayElement* instr) { + ASSERT(instr->representation().IsInteger32()); + ASSERT(instr->key()->representation().IsInteger32()); + LOperand* external_pointer = + UseRegisterAtStart(instr->external_pointer()); + LOperand* key = UseRegisterAtStart(instr->key()); + LLoadPixelArrayElement* result = + new LLoadPixelArrayElement(external_pointer, key); + return DefineAsRegister(result); +} + + LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) { LOperand* object = UseFixed(instr->object(), r1); LOperand* key = UseFixed(instr->key(), r0); diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h index 7591f9403b..8d2573d96c 100644 --- a/src/arm/lithium-arm.h +++ b/src/arm/lithium-arm.h @@ -122,6 +122,8 @@ class LCodeGen; V(LoadKeyedGeneric) \ V(LoadNamedField) \ V(LoadNamedGeneric) \ + V(LoadPixelArrayElement) \ + V(LoadPixelArrayExternalPointer) \ V(ModI) \ V(MulI) \ V(NumberTagD) \ @@ -131,6 +133,7 @@ class LCodeGen; V(OsrEntry) \ V(OuterContext) \ V(Parameter) \ + V(PixelArrayLength) \ V(PushArgument) \ V(RegExpLiteral) \ V(Return) \ @@ -977,6 +980,17 @@ class LJSArrayLength: public LTemplateInstruction<1, 1, 0> { }; +class LPixelArrayLength: public LTemplateInstruction<1, 1, 0> { + public: + explicit LPixelArrayLength(LOperand* value) { + inputs_[0] = value; + } + + DECLARE_CONCRETE_INSTRUCTION(PixelArrayLength, "pixel-array-length") + DECLARE_HYDROGEN_ACCESSOR(PixelArrayLength) +}; + + class LFixedArrayLength: public LTemplateInstruction<1, 1, 0> { public: explicit LFixedArrayLength(LOperand* value) { @@ -1126,6 +1140,17 @@ class LLoadElements: public LTemplateInstruction<1, 1, 0> { }; +class LLoadPixelArrayExternalPointer: public LTemplateInstruction<1, 1, 0> { + public: + explicit LLoadPixelArrayExternalPointer(LOperand* object) { + inputs_[0] = object; + } + + DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayExternalPointer, + "load-pixel-array-external-pointer") +}; + + class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> { public: LLoadKeyedFastElement(LOperand* elements, LOperand* key) { @@ -1141,6 +1166,22 @@ class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> { }; +class LLoadPixelArrayElement: public LTemplateInstruction<1, 2, 0> { + public: + LLoadPixelArrayElement(LOperand* external_pointer, LOperand* key) { + inputs_[0] = external_pointer; + inputs_[1] = key; + } + + DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayElement, + "load-pixel-array-element") + DECLARE_HYDROGEN_ACCESSOR(LoadPixelArrayElement) + + LOperand* external_pointer() { return inputs_[0]; } + LOperand* key() { return inputs_[1]; } +}; + + class LLoadKeyedGeneric: public LTemplateInstruction<1, 2, 0> { public: LLoadKeyedGeneric(LOperand* obj, LOperand* key) { diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 67ed508e87..a027629e5e 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -1322,6 +1322,13 @@ void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) { } +void LCodeGen::DoPixelArrayLength(LPixelArrayLength* instr) { + Register result = ToRegister(instr->result()); + Register array = ToRegister(instr->InputAt(0)); + __ ldr(result, FieldMemOperand(array, PixelArray::kLengthOffset)); +} + + void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) { Register result = ToRegister(instr->result()); Register array = ToRegister(instr->InputAt(0)); @@ -2354,17 +2361,20 @@ void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { void LCodeGen::DoLoadElements(LLoadElements* instr) { - ASSERT(instr->result()->Equals(instr->InputAt(0))); - Register reg = ToRegister(instr->InputAt(0)); + Register result = ToRegister(instr->result()); + Register input = ToRegister(instr->InputAt(0)); Register scratch = scratch0(); - __ ldr(reg, FieldMemOperand(reg, JSObject::kElementsOffset)); + __ ldr(result, FieldMemOperand(input, JSObject::kElementsOffset)); if (FLAG_debug_code) { Label done; - __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset)); + __ ldr(scratch, FieldMemOperand(result, HeapObject::kMapOffset)); __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); __ cmp(scratch, ip); __ b(eq, &done); + __ LoadRoot(ip, Heap::kPixelArrayMapRootIndex); + __ cmp(scratch, ip); + __ b(eq, &done); __ LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex); __ cmp(scratch, ip); __ Check(eq, "Check for fast elements failed."); @@ -2373,6 +2383,14 @@ void LCodeGen::DoLoadElements(LLoadElements* instr) { } +void LCodeGen::DoLoadPixelArrayExternalPointer( + LLoadPixelArrayExternalPointer* instr) { + Register to_reg = ToRegister(instr->result()); + Register from_reg = ToRegister(instr->InputAt(0)); + __ ldr(to_reg, FieldMemOperand(from_reg, PixelArray::kExternalPointerOffset)); +} + + void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { Register arguments = ToRegister(instr->arguments()); Register length = ToRegister(instr->length()); @@ -2409,6 +2427,16 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) { } +void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) { + Register external_elements = ToRegister(instr->external_pointer()); + Register key = ToRegister(instr->key()); + Register result = ToRegister(instr->result()); + + // Load the result. + __ ldrb(result, MemOperand(external_elements, key)); +} + + void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { ASSERT(ToRegister(instr->object()).is(r1)); ASSERT(ToRegister(instr->key()).is(r0)); diff --git a/src/factory.cc b/src/factory.cc index a3d55921b6..f9738cf399 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -334,6 +334,11 @@ Handle Factory::GetSlowElementsMap(Handle src) { } +Handle Factory::GetPixelArrayElementsMap(Handle src) { + CALL_HEAP_FUNCTION(src->GetPixelArrayElementsMap(), Map); +} + + Handle Factory::CopyFixedArray(Handle array) { CALL_HEAP_FUNCTION(array->Copy(), FixedArray); } diff --git a/src/factory.h b/src/factory.h index ba2b181a34..7547f7c452 100644 --- a/src/factory.h +++ b/src/factory.h @@ -196,6 +196,8 @@ class Factory : public AllStatic { static Handle GetSlowElementsMap(Handle map); + static Handle GetPixelArrayElementsMap(Handle map); + static Handle CopyFixedArray(Handle array); // Numbers (eg, literals) are pretenured by the parser. diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc index e62162204b..eb1c5927d2 100644 --- a/src/hydrogen-instructions.cc +++ b/src/hydrogen-instructions.cc @@ -1235,6 +1235,14 @@ void HLoadKeyed::PrintDataTo(StringStream* stream) const { } +void HLoadPixelArrayElement::PrintDataTo(StringStream* stream) const { + external_pointer()->PrintNameTo(stream); + stream->Add("["); + key()->PrintNameTo(stream); + stream->Add("]"); +} + + void HStoreNamed::PrintDataTo(StringStream* stream) const { object()->PrintNameTo(stream); stream->Add("."); diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index 3ff7045fba..d6d5cfb891 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -127,12 +127,15 @@ class LChunkBuilder; V(LoadKeyedGeneric) \ V(LoadNamedField) \ V(LoadNamedGeneric) \ + V(LoadPixelArrayElement) \ + V(LoadPixelArrayExternalPointer) \ V(Mod) \ V(Mul) \ V(ObjectLiteral) \ V(OsrEntry) \ V(OuterContext) \ V(Parameter) \ + V(PixelArrayLength) \ V(Power) \ V(PushArgument) \ V(RegExpLiteral) \ @@ -164,6 +167,7 @@ class LChunkBuilder; V(InobjectFields) \ V(BackingStoreFields) \ V(ArrayElements) \ + V(PixelArrayElements) \ V(GlobalVars) \ V(Maps) \ V(ArrayLengths) \ @@ -289,6 +293,7 @@ class Representation { kTagged, kDouble, kInteger32, + kExternal, kNumRepresentations }; @@ -298,6 +303,7 @@ class Representation { static Representation Tagged() { return Representation(kTagged); } static Representation Integer32() { return Representation(kInteger32); } static Representation Double() { return Representation(kDouble); } + static Representation External() { return Representation(kExternal); } bool Equals(const Representation& other) const { return kind_ == other.kind_; @@ -308,6 +314,7 @@ class Representation { bool IsTagged() const { return kind_ == kTagged; } bool IsInteger32() const { return kind_ == kInteger32; } bool IsDouble() const { return kind_ == kDouble; } + bool IsExternal() const { return kind_ == kExternal; } bool IsSpecialization() const { return kind_ == kInteger32 || kind_ == kDouble; } @@ -1418,6 +1425,27 @@ class HFixedArrayLength: public HUnaryOperation { }; +class HPixelArrayLength: public HUnaryOperation { + public: + explicit HPixelArrayLength(HValue* value) : HUnaryOperation(value) { + set_representation(Representation::Integer32()); + // The result of this instruction is idempotent as long as its inputs don't + // change. The length of a pixel array cannot change once set, so it's not + // necessary to introduce a kDependsOnArrayLengths or any other dependency. + SetFlag(kUseGVN); + } + + virtual Representation RequiredInputRepresentation(int index) const { + return Representation::Tagged(); + } + + DECLARE_CONCRETE_INSTRUCTION(PixelArrayLength, "pixel_array_length") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } +}; + + class HBitNot: public HUnaryOperation { public: explicit HBitNot(HValue* value) : HUnaryOperation(value) { @@ -1536,6 +1564,30 @@ class HLoadElements: public HUnaryOperation { }; +class HLoadPixelArrayExternalPointer: public HUnaryOperation { + public: + explicit HLoadPixelArrayExternalPointer(HValue* value) + : HUnaryOperation(value) { + set_representation(Representation::External()); + // The result of this instruction is idempotent as long as its inputs don't + // change. The external array of a pixel array elements object cannot + // change once set, so it's no necessary to introduce any additional + // dependencies on top of the inputs. + SetFlag(kUseGVN); + } + + virtual Representation RequiredInputRepresentation(int index) const { + return Representation::Tagged(); + } + + DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayExternalPointer, + "load-pixel-array-external-pointer") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } +}; + + class HCheckMap: public HUnaryOperation { public: HCheckMap(HValue* value, Handle map) @@ -2952,6 +3004,37 @@ class HLoadKeyedFastElement: public HLoadKeyed { }; +class HLoadPixelArrayElement: public HBinaryOperation { + public: + HLoadPixelArrayElement(HValue* external_elements, HValue* key) + : HBinaryOperation(external_elements, key) { + set_representation(Representation::Integer32()); + SetFlag(kDependsOnPixelArrayElements); + // Native code could change the pixel array. + SetFlag(kDependsOnCalls); + SetFlag(kUseGVN); + } + + virtual void PrintDataTo(StringStream* stream) const; + + virtual Representation RequiredInputRepresentation(int index) const { + // The key is supposed to be Integer32, but the base pointer + // for the element load is a naked pointer. + return (index == 1) ? Representation::Integer32() + : Representation::External(); + } + + HValue* external_pointer() const { return OperandAt(0); } + HValue* key() const { return OperandAt(1); } + + DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayElement, + "load_pixel_array_element") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } +}; + + class HLoadKeyedGeneric: public HLoadKeyed { public: HLoadKeyedGeneric(HContext* context, HValue* obj, HValue* key) diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 2c65eeade2..c3dfd5ff26 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -3743,6 +3743,28 @@ HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object, } +HInstruction* HGraphBuilder::BuildLoadKeyedPixelArrayElement(HValue* object, + HValue* key, + Property* expr) { + ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic()); + AddInstruction(new HCheckNonSmi(object)); + Handle map = expr->GetMonomorphicReceiverType(); + ASSERT(!map->has_fast_elements()); + ASSERT(map->has_pixel_array_elements()); + AddInstruction(new HCheckMap(object, map)); + HLoadElements* elements = new HLoadElements(object); + AddInstruction(elements); + HInstruction* length = AddInstruction(new HPixelArrayLength(elements)); + AddInstruction(new HBoundsCheck(key, length)); + HLoadPixelArrayExternalPointer* external_elements = + new HLoadPixelArrayExternalPointer(elements); + AddInstruction(external_elements); + HLoadPixelArrayElement* pixel_array_value = + new HLoadPixelArrayElement(external_elements, key); + return pixel_array_value; +} + + HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object, HValue* key, HValue* value) { @@ -3852,12 +3874,20 @@ void HGraphBuilder::VisitProperty(Property* expr) { HValue* key = Pop(); HValue* obj = Pop(); - bool is_fast_elements = expr->IsMonomorphic() && - expr->GetMonomorphicReceiverType()->has_fast_elements(); - - instr = is_fast_elements - ? BuildLoadKeyedFastElement(obj, key, expr) - : BuildLoadKeyedGeneric(obj, key); + if (expr->IsMonomorphic()) { + Handle receiver_type(expr->GetMonomorphicReceiverType()); + // An object has either fast elements or pixel array elements, but never + // both. Pixel array maps that are assigned to pixel array elements are + // always created with the fast elements flag cleared. + if (receiver_type->has_pixel_array_elements()) { + instr = BuildLoadKeyedPixelArrayElement(obj, key, expr); + } else if (receiver_type->has_fast_elements()) { + instr = BuildLoadKeyedFastElement(obj, key, expr); + } + } + if (instr == NULL) { + instr = BuildLoadKeyedGeneric(obj, key); + } } instr->set_position(expr->position()); ast_context()->ReturnInstruction(instr, expr->id()); diff --git a/src/hydrogen.h b/src/hydrogen.h index 0178f3f85b..9d0cddf145 100644 --- a/src/hydrogen.h +++ b/src/hydrogen.h @@ -791,6 +791,9 @@ class HGraphBuilder: public AstVisitor { HInstruction* BuildLoadKeyedFastElement(HValue* object, HValue* key, Property* expr); + HInstruction* BuildLoadKeyedPixelArrayElement(HValue* object, + HValue* key, + Property* expr); HInstruction* BuildLoadKeyedGeneric(HValue* object, HValue* key); diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index 91efc296b6..b21eec83d2 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -1002,6 +1002,13 @@ void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) { } +void LCodeGen::DoPixelArrayLength(LPixelArrayLength* instr) { + Register result = ToRegister(instr->result()); + Register array = ToRegister(instr->InputAt(0)); + __ mov(result, FieldOperand(array, PixelArray::kLengthOffset)); +} + + void LCodeGen::DoValueOf(LValueOf* instr) { Register input = ToRegister(instr->InputAt(0)); Register result = ToRegister(instr->result()); @@ -2024,22 +2031,33 @@ void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { void LCodeGen::DoLoadElements(LLoadElements* instr) { - ASSERT(instr->result()->Equals(instr->InputAt(0))); - Register reg = ToRegister(instr->InputAt(0)); - __ mov(reg, FieldOperand(reg, JSObject::kElementsOffset)); + Register result = ToRegister(instr->result()); + Register input = ToRegister(instr->InputAt(0)); + __ mov(result, FieldOperand(input, JSObject::kElementsOffset)); if (FLAG_debug_code) { NearLabel done; - __ cmp(FieldOperand(reg, HeapObject::kMapOffset), + __ cmp(FieldOperand(result, HeapObject::kMapOffset), Immediate(Factory::fixed_array_map())); __ j(equal, &done); - __ cmp(FieldOperand(reg, HeapObject::kMapOffset), + __ cmp(FieldOperand(result, HeapObject::kMapOffset), + Immediate(Factory::pixel_array_map())); + __ j(equal, &done); + __ cmp(FieldOperand(result, HeapObject::kMapOffset), Immediate(Factory::fixed_cow_array_map())); - __ Check(equal, "Check for fast elements failed."); + __ Check(equal, "Check for fast elements or pixel array failed."); __ bind(&done); } } +void LCodeGen::DoLoadPixelArrayExternalPointer( + LLoadPixelArrayExternalPointer* instr) { + Register result = ToRegister(instr->result()); + Register input = ToRegister(instr->InputAt(0)); + __ mov(result, FieldOperand(input, PixelArray::kExternalPointerOffset)); +} + + void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { Register arguments = ToRegister(instr->arguments()); Register length = ToRegister(instr->length()); @@ -2073,6 +2091,17 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) { } +void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) { + Register external_elements = ToRegister(instr->external_pointer()); + Register key = ToRegister(instr->key()); + Register result = ToRegister(instr->result()); + ASSERT(result.is(external_elements)); + + // Load the result. + __ movzx_b(result, Operand(external_elements, key, times_1, 0)); +} + + void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { ASSERT(ToRegister(instr->context()).is(esi)); ASSERT(ToRegister(instr->object()).is(edx)); diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index e76a0bcd73..0ad3819292 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -1550,6 +1550,12 @@ LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) { } +LInstruction* LChunkBuilder::DoPixelArrayLength(HPixelArrayLength* instr) { + LOperand* array = UseRegisterAtStart(instr->value()); + return DefineAsRegister(new LPixelArrayLength(array)); +} + + LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) { LOperand* object = UseRegister(instr->value()); LValueOf* result = new LValueOf(object, TempRegister()); @@ -1763,7 +1769,14 @@ LInstruction* LChunkBuilder::DoLoadFunctionPrototype( LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) { LOperand* input = UseRegisterAtStart(instr->value()); - return DefineSameAsFirst(new LLoadElements(input)); + return DefineAsRegister(new LLoadElements(input)); +} + + +LInstruction* LChunkBuilder::DoLoadPixelArrayExternalPointer( + HLoadPixelArrayExternalPointer* instr) { + LOperand* input = UseRegisterAtStart(instr->value()); + return DefineAsRegister(new LLoadPixelArrayExternalPointer(input)); } @@ -1778,6 +1791,19 @@ LInstruction* LChunkBuilder::DoLoadKeyedFastElement( } +LInstruction* LChunkBuilder::DoLoadPixelArrayElement( + HLoadPixelArrayElement* instr) { + ASSERT(instr->representation().IsInteger32()); + ASSERT(instr->key()->representation().IsInteger32()); + LOperand* external_pointer = + UseRegisterAtStart(instr->external_pointer()); + LOperand* key = UseRegisterAtStart(instr->key()); + LLoadPixelArrayElement* result = + new LLoadPixelArrayElement(external_pointer, key); + return DefineSameAsFirst(result); +} + + LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) { LOperand* context = UseFixed(instr->context(), esi); LOperand* object = UseFixed(instr->object(), edx); diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h index db046feae8..f1b9ffc997 100644 --- a/src/ia32/lithium-ia32.h +++ b/src/ia32/lithium-ia32.h @@ -124,6 +124,8 @@ class LCodeGen; V(LoadKeyedGeneric) \ V(LoadNamedField) \ V(LoadNamedGeneric) \ + V(LoadPixelArrayElement) \ + V(LoadPixelArrayExternalPointer) \ V(ModI) \ V(MulI) \ V(NumberTagD) \ @@ -133,6 +135,7 @@ class LCodeGen; V(OsrEntry) \ V(OuterContext) \ V(Parameter) \ + V(PixelArrayLength) \ V(Power) \ V(PushArgument) \ V(RegExpLiteral) \ @@ -1022,6 +1025,17 @@ class LJSArrayLength: public LTemplateInstruction<1, 1, 0> { }; +class LPixelArrayLength: public LTemplateInstruction<1, 1, 0> { + public: + explicit LPixelArrayLength(LOperand* value) { + inputs_[0] = value; + } + + DECLARE_CONCRETE_INSTRUCTION(PixelArrayLength, "pixel-array-length") + DECLARE_HYDROGEN_ACCESSOR(PixelArrayLength) +}; + + class LFixedArrayLength: public LTemplateInstruction<1, 1, 0> { public: explicit LFixedArrayLength(LOperand* value) { @@ -1186,6 +1200,17 @@ class LLoadElements: public LTemplateInstruction<1, 1, 0> { }; +class LLoadPixelArrayExternalPointer: public LTemplateInstruction<1, 1, 0> { + public: + explicit LLoadPixelArrayExternalPointer(LOperand* object) { + inputs_[0] = object; + } + + DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayExternalPointer, + "load-pixel-array-external-pointer") +}; + + class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> { public: LLoadKeyedFastElement(LOperand* elements, LOperand* key) { @@ -1201,6 +1226,22 @@ class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> { }; +class LLoadPixelArrayElement: public LTemplateInstruction<1, 2, 0> { + public: + LLoadPixelArrayElement(LOperand* external_pointer, LOperand* key) { + inputs_[0] = external_pointer; + inputs_[1] = key; + } + + DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayElement, + "load-pixel-array-element") + DECLARE_HYDROGEN_ACCESSOR(LoadPixelArrayElement) + + LOperand* external_pointer() { return inputs_[0]; } + LOperand* key() { return inputs_[1]; } +}; + + class LLoadKeyedGeneric: public LTemplateInstruction<1, 3, 0> { public: LLoadKeyedGeneric(LOperand* context, LOperand* obj, LOperand* key) { diff --git a/src/objects-inl.h b/src/objects-inl.h index 3b83dd4869..302c0a4451 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -2747,6 +2747,22 @@ MaybeObject* Map::GetSlowElementsMap() { } +MaybeObject* Map::GetPixelArrayElementsMap() { + if (has_pixel_array_elements()) return this; + // TODO(danno): Special case empty object map (or most common case) + // to return a pre-canned pixel array map. + Object* obj; + { MaybeObject* maybe_obj = CopyDropTransitions(); + if (!maybe_obj->ToObject(&obj)) return maybe_obj; + } + Map* new_map = Map::cast(obj); + new_map->set_has_fast_elements(false); + new_map->set_has_pixel_array_elements(true); + Counters::map_to_pixel_array_elements.Increment(); + return new_map; +} + + ACCESSORS(Map, instance_descriptors, DescriptorArray, kInstanceDescriptorsOffset) ACCESSORS(Map, code_cache, Object, kCodeCacheOffset) diff --git a/src/objects.h b/src/objects.h index 71ef5069e6..9fa008fcee 100644 --- a/src/objects.h +++ b/src/objects.h @@ -3593,6 +3593,19 @@ class Map: public HeapObject { return ((1 << kHasFastElements) & bit_field2()) != 0; } + // Tells whether an instance has pixel array elements. + inline void set_has_pixel_array_elements(bool value) { + if (value) { + set_bit_field2(bit_field2() | (1 << kHasPixelArrayElements)); + } else { + set_bit_field2(bit_field2() & ~(1 << kHasPixelArrayElements)); + } + } + + inline bool has_pixel_array_elements() { + return ((1 << kHasPixelArrayElements) & bit_field2()) != 0; + } + // Tells whether the map is attached to SharedFunctionInfo // (for inobject slack tracking). inline void set_attached_to_shared_function_info(bool value); @@ -3651,6 +3664,11 @@ class Map: public HeapObject { // from the descriptors and the fast elements bit cleared. MUST_USE_RESULT inline MaybeObject* GetSlowElementsMap(); + // Returns this map if it has the pixel array elements bit is set, otherwise + // returns a copy of the map, with all transitions dropped from the + // descriptors and the pixel array elements bit set. + MUST_USE_RESULT inline MaybeObject* GetPixelArrayElementsMap(); + // Returns the property index for name (only valid for FAST MODE). int PropertyIndexFor(String* name); @@ -3769,6 +3787,7 @@ class Map: public HeapObject { static const int kStringWrapperSafeForDefaultValueOf = 3; static const int kAttachedToSharedFunctionInfo = 4; static const int kIsShared = 5; + static const int kHasPixelArrayElements = 6; // Layout of the default cache. It holds alternating name and code objects. static const int kCodeCacheEntrySize = 2; diff --git a/src/v8-counters.h b/src/v8-counters.h index aa30e4e150..9b91acebcd 100644 --- a/src/v8-counters.h +++ b/src/v8-counters.h @@ -128,6 +128,7 @@ namespace internal { SC(gc_last_resort_from_handles, V8.GCLastResortFromHandles) \ SC(map_slow_to_fast_elements, V8.MapSlowToFastElements) \ SC(map_fast_to_slow_elements, V8.MapFastToSlowElements) \ + SC(map_to_pixel_array_elements, V8.MapToPixelArrayElements) \ /* How is the generic keyed-load stub used? */ \ SC(keyed_load_generic_smi, V8.KeyedLoadGenericSmi) \ SC(keyed_load_generic_symbol, V8.KeyedLoadGenericSymbol) \ diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index a1f8cb430a..a17ef236a9 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -927,6 +927,13 @@ void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) { } +void LCodeGen::DoPixelArrayLength(LPixelArrayLength* instr) { + Register result = ToRegister(instr->result()); + Register array = ToRegister(instr->InputAt(0)); + __ movq(result, FieldOperand(array, PixelArray::kLengthOffset)); +} + + void LCodeGen::DoValueOf(LValueOf* instr) { Abort("Unimplemented: %s", "DoValueOf"); } @@ -1726,15 +1733,18 @@ void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { void LCodeGen::DoLoadElements(LLoadElements* instr) { - ASSERT(instr->result()->Equals(instr->InputAt(0))); - Register reg = ToRegister(instr->InputAt(0)); - __ movq(reg, FieldOperand(reg, JSObject::kElementsOffset)); + Register result = ToRegister(instr->result()); + Register input = ToRegister(instr->InputAt(0)); + __ movq(result, FieldOperand(input, JSObject::kElementsOffset)); if (FLAG_debug_code) { NearLabel done; - __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), + __ Cmp(FieldOperand(result, HeapObject::kMapOffset), Factory::fixed_array_map()); __ j(equal, &done); - __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), + __ Cmp(FieldOperand(result, HeapObject::kMapOffset), + Factory::pixel_array_map()); + __ j(equal, &done); + __ Cmp(FieldOperand(result, HeapObject::kMapOffset), Factory::fixed_cow_array_map()); __ Check(equal, "Check for fast elements failed."); __ bind(&done); @@ -1742,6 +1752,14 @@ void LCodeGen::DoLoadElements(LLoadElements* instr) { } +void LCodeGen::DoLoadPixelArrayExternalPointer( + LLoadPixelArrayExternalPointer* instr) { + Register result = ToRegister(instr->result()); + Register input = ToRegister(instr->InputAt(0)); + __ movq(result, FieldOperand(input, PixelArray::kExternalPointerOffset)); +} + + void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { Abort("Unimplemented: %s", "DoAccessArgumentsAt"); } @@ -1765,6 +1783,17 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) { } +void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) { + Register external_elements = ToRegister(instr->external_pointer()); + Register key = ToRegister(instr->key()); + Register result = ToRegister(instr->result()); + ASSERT(result.is(external_elements)); + + // Load the result. + __ movzxbq(result, Operand(external_elements, key, times_1, 0)); +} + + void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { Abort("Unimplemented: %s", "DoLoadKeyedGeneric"); } diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc index a0e23daeef..d0737dd5d5 100644 --- a/src/x64/lithium-x64.cc +++ b/src/x64/lithium-x64.cc @@ -1442,6 +1442,12 @@ LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) { } +LInstruction* LChunkBuilder::DoPixelArrayLength(HPixelArrayLength* instr) { + LOperand* array = UseRegisterAtStart(instr->value()); + return DefineAsRegister(new LPixelArrayLength(array)); +} + + LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) { Abort("Unimplemented: %s", "DoValueOf"); return NULL; @@ -1638,7 +1644,14 @@ LInstruction* LChunkBuilder::DoLoadFunctionPrototype( LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) { LOperand* input = UseRegisterAtStart(instr->value()); - return DefineSameAsFirst(new LLoadElements(input)); + return DefineAsRegister(new LLoadElements(input)); +} + + +LInstruction* LChunkBuilder::DoLoadPixelArrayExternalPointer( + HLoadPixelArrayExternalPointer* instr) { + LOperand* input = UseRegisterAtStart(instr->value()); + return DefineAsRegister(new LLoadPixelArrayExternalPointer(input)); } @@ -1653,6 +1666,19 @@ LInstruction* LChunkBuilder::DoLoadKeyedFastElement( } +LInstruction* LChunkBuilder::DoLoadPixelArrayElement( + HLoadPixelArrayElement* instr) { + ASSERT(instr->representation().IsInteger32()); + ASSERT(instr->key()->representation().IsInteger32()); + LOperand* external_pointer = + UseRegisterAtStart(instr->external_pointer()); + LOperand* key = UseRegisterAtStart(instr->key()); + LLoadPixelArrayElement* result = + new LLoadPixelArrayElement(external_pointer, key); + return DefineSameAsFirst(result); +} + + LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) { Abort("Unimplemented: %s", "DoLoadKeyedGeneric"); return NULL; diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h index 331824f4ac..6931d96269 100644 --- a/src/x64/lithium-x64.h +++ b/src/x64/lithium-x64.h @@ -121,6 +121,8 @@ class LCodeGen; V(LoadNamedField) \ V(LoadNamedGeneric) \ V(LoadFunctionPrototype) \ + V(LoadPixelArrayElement) \ + V(LoadPixelArrayExternalPointer) \ V(ModI) \ V(MulI) \ V(NumberTagD) \ @@ -129,6 +131,7 @@ class LCodeGen; V(ObjectLiteral) \ V(OsrEntry) \ V(Parameter) \ + V(PixelArrayLength) \ V(Power) \ V(PushArgument) \ V(RegExpLiteral) \ @@ -978,6 +981,17 @@ class LJSArrayLength: public LTemplateInstruction<1, 1, 0> { }; +class LPixelArrayLength: public LTemplateInstruction<1, 1, 0> { + public: + explicit LPixelArrayLength(LOperand* value) { + inputs_[0] = value; + } + + DECLARE_CONCRETE_INSTRUCTION(PixelArrayLength, "pixel-array-length") + DECLARE_HYDROGEN_ACCESSOR(PixelArrayLength) +}; + + class LFixedArrayLength: public LTemplateInstruction<1, 1, 0> { public: explicit LFixedArrayLength(LOperand* value) { @@ -1140,6 +1154,17 @@ class LLoadElements: public LTemplateInstruction<1, 1, 0> { }; +class LLoadPixelArrayExternalPointer: public LTemplateInstruction<1, 1, 0> { + public: + explicit LLoadPixelArrayExternalPointer(LOperand* object) { + inputs_[0] = object; + } + + DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayExternalPointer, + "load-pixel-array-external-pointer") +}; + + class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> { public: LLoadKeyedFastElement(LOperand* elements, LOperand* key) { @@ -1155,6 +1180,22 @@ class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> { }; +class LLoadPixelArrayElement: public LTemplateInstruction<1, 2, 0> { + public: + LLoadPixelArrayElement(LOperand* external_pointer, LOperand* key) { + inputs_[0] = external_pointer; + inputs_[1] = key; + } + + DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayElement, + "load-pixel-array-element") + DECLARE_HYDROGEN_ACCESSOR(LoadPixelArrayElement) + + LOperand* external_pointer() { return inputs_[0]; } + LOperand* key() { return inputs_[1]; } +}; + + class LLoadKeyedGeneric: public LTemplateInstruction<1, 2, 0> { public: LLoadKeyedGeneric(LOperand* obj, LOperand* key) { diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 1c0a52bd63..b68fdffe19 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -10674,6 +10674,21 @@ THREADED_TEST(PixelArray) { "result"); CHECK_EQ(32640, result->Int32Value()); + // Make sure that pixel array loads are optimized by crankshaft. + result = CompileRun("function pa_load(p) {" + " var sum = 0;" + " for (var i=0; i<256; ++i) {" + " sum += p[i];" + " }" + " return sum; " + "}" + "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" + "for (var i = 0; i < 10000; ++i) {" + " result = pa_load(pixels);" + "}" + "result"); + CHECK_EQ(32640, result->Int32Value()); + free(pixel_data); }