Implement crankshaft support for pixel array loads.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6725 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
danno@chromium.org 2011-02-10 12:02:36 +00:00
parent 73fe82426f
commit 1bd9f602be
20 changed files with 496 additions and 27 deletions

View File

@ -2757,9 +2757,9 @@ void v8::Object::SetIndexedPropertiesToPixelData(uint8_t* data, int length) {
return; return;
} }
i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(length, data); i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(length, data);
i::Handle<i::Map> slow_map = i::Handle<i::Map> pixel_array_map =
i::Factory::GetSlowElementsMap(i::Handle<i::Map>(self->map())); i::Factory::GetPixelArrayElementsMap(i::Handle<i::Map>(self->map()));
self->set_map(*slow_map); self->set_map(*pixel_array_map);
self->set_elements(*pixels); self->set_elements(*pixels);
} }

View File

@ -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) { LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value()); LOperand* array = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LFixedArrayLength(array)); return DefineAsRegister(new LFixedArrayLength(array));
@ -1714,7 +1720,14 @@ LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) { LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
LOperand* input = UseRegisterAtStart(instr->value()); 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) { LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
LOperand* object = UseFixed(instr->object(), r1); LOperand* object = UseFixed(instr->object(), r1);
LOperand* key = UseFixed(instr->key(), r0); LOperand* key = UseFixed(instr->key(), r0);

View File

@ -122,6 +122,8 @@ class LCodeGen;
V(LoadKeyedGeneric) \ V(LoadKeyedGeneric) \
V(LoadNamedField) \ V(LoadNamedField) \
V(LoadNamedGeneric) \ V(LoadNamedGeneric) \
V(LoadPixelArrayElement) \
V(LoadPixelArrayExternalPointer) \
V(ModI) \ V(ModI) \
V(MulI) \ V(MulI) \
V(NumberTagD) \ V(NumberTagD) \
@ -131,6 +133,7 @@ class LCodeGen;
V(OsrEntry) \ V(OsrEntry) \
V(OuterContext) \ V(OuterContext) \
V(Parameter) \ V(Parameter) \
V(PixelArrayLength) \
V(PushArgument) \ V(PushArgument) \
V(RegExpLiteral) \ V(RegExpLiteral) \
V(Return) \ 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> { class LFixedArrayLength: public LTemplateInstruction<1, 1, 0> {
public: public:
explicit LFixedArrayLength(LOperand* value) { 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> { class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> {
public: public:
LLoadKeyedFastElement(LOperand* elements, LOperand* key) { 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> { class LLoadKeyedGeneric: public LTemplateInstruction<1, 2, 0> {
public: public:
LLoadKeyedGeneric(LOperand* obj, LOperand* key) { LLoadKeyedGeneric(LOperand* obj, LOperand* key) {

View File

@ -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) { void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
Register result = ToRegister(instr->result()); Register result = ToRegister(instr->result());
Register array = ToRegister(instr->InputAt(0)); Register array = ToRegister(instr->InputAt(0));
@ -2354,17 +2361,20 @@ void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
void LCodeGen::DoLoadElements(LLoadElements* instr) { void LCodeGen::DoLoadElements(LLoadElements* instr) {
ASSERT(instr->result()->Equals(instr->InputAt(0))); Register result = ToRegister(instr->result());
Register reg = ToRegister(instr->InputAt(0)); Register input = ToRegister(instr->InputAt(0));
Register scratch = scratch0(); Register scratch = scratch0();
__ ldr(reg, FieldMemOperand(reg, JSObject::kElementsOffset)); __ ldr(result, FieldMemOperand(input, JSObject::kElementsOffset));
if (FLAG_debug_code) { if (FLAG_debug_code) {
Label done; Label done;
__ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset)); __ ldr(scratch, FieldMemOperand(result, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
__ cmp(scratch, ip); __ cmp(scratch, ip);
__ b(eq, &done); __ b(eq, &done);
__ LoadRoot(ip, Heap::kPixelArrayMapRootIndex);
__ cmp(scratch, ip);
__ b(eq, &done);
__ LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex); __ LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex);
__ cmp(scratch, ip); __ cmp(scratch, ip);
__ Check(eq, "Check for fast elements failed."); __ 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) { void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
Register arguments = ToRegister(instr->arguments()); Register arguments = ToRegister(instr->arguments());
Register length = ToRegister(instr->length()); 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) { void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
ASSERT(ToRegister(instr->object()).is(r1)); ASSERT(ToRegister(instr->object()).is(r1));
ASSERT(ToRegister(instr->key()).is(r0)); ASSERT(ToRegister(instr->key()).is(r0));

View File

@ -334,6 +334,11 @@ Handle<Map> Factory::GetSlowElementsMap(Handle<Map> src) {
} }
Handle<Map> Factory::GetPixelArrayElementsMap(Handle<Map> src) {
CALL_HEAP_FUNCTION(src->GetPixelArrayElementsMap(), Map);
}
Handle<FixedArray> Factory::CopyFixedArray(Handle<FixedArray> array) { Handle<FixedArray> Factory::CopyFixedArray(Handle<FixedArray> array) {
CALL_HEAP_FUNCTION(array->Copy(), FixedArray); CALL_HEAP_FUNCTION(array->Copy(), FixedArray);
} }

View File

@ -196,6 +196,8 @@ class Factory : public AllStatic {
static Handle<Map> GetSlowElementsMap(Handle<Map> map); static Handle<Map> GetSlowElementsMap(Handle<Map> map);
static Handle<Map> GetPixelArrayElementsMap(Handle<Map> map);
static Handle<FixedArray> CopyFixedArray(Handle<FixedArray> array); static Handle<FixedArray> CopyFixedArray(Handle<FixedArray> array);
// Numbers (eg, literals) are pretenured by the parser. // Numbers (eg, literals) are pretenured by the parser.

View File

@ -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 { void HStoreNamed::PrintDataTo(StringStream* stream) const {
object()->PrintNameTo(stream); object()->PrintNameTo(stream);
stream->Add("."); stream->Add(".");

View File

@ -127,12 +127,15 @@ class LChunkBuilder;
V(LoadKeyedGeneric) \ V(LoadKeyedGeneric) \
V(LoadNamedField) \ V(LoadNamedField) \
V(LoadNamedGeneric) \ V(LoadNamedGeneric) \
V(LoadPixelArrayElement) \
V(LoadPixelArrayExternalPointer) \
V(Mod) \ V(Mod) \
V(Mul) \ V(Mul) \
V(ObjectLiteral) \ V(ObjectLiteral) \
V(OsrEntry) \ V(OsrEntry) \
V(OuterContext) \ V(OuterContext) \
V(Parameter) \ V(Parameter) \
V(PixelArrayLength) \
V(Power) \ V(Power) \
V(PushArgument) \ V(PushArgument) \
V(RegExpLiteral) \ V(RegExpLiteral) \
@ -164,6 +167,7 @@ class LChunkBuilder;
V(InobjectFields) \ V(InobjectFields) \
V(BackingStoreFields) \ V(BackingStoreFields) \
V(ArrayElements) \ V(ArrayElements) \
V(PixelArrayElements) \
V(GlobalVars) \ V(GlobalVars) \
V(Maps) \ V(Maps) \
V(ArrayLengths) \ V(ArrayLengths) \
@ -289,6 +293,7 @@ class Representation {
kTagged, kTagged,
kDouble, kDouble,
kInteger32, kInteger32,
kExternal,
kNumRepresentations kNumRepresentations
}; };
@ -298,6 +303,7 @@ class Representation {
static Representation Tagged() { return Representation(kTagged); } static Representation Tagged() { return Representation(kTagged); }
static Representation Integer32() { return Representation(kInteger32); } static Representation Integer32() { return Representation(kInteger32); }
static Representation Double() { return Representation(kDouble); } static Representation Double() { return Representation(kDouble); }
static Representation External() { return Representation(kExternal); }
bool Equals(const Representation& other) const { bool Equals(const Representation& other) const {
return kind_ == other.kind_; return kind_ == other.kind_;
@ -308,6 +314,7 @@ class Representation {
bool IsTagged() const { return kind_ == kTagged; } bool IsTagged() const { return kind_ == kTagged; }
bool IsInteger32() const { return kind_ == kInteger32; } bool IsInteger32() const { return kind_ == kInteger32; }
bool IsDouble() const { return kind_ == kDouble; } bool IsDouble() const { return kind_ == kDouble; }
bool IsExternal() const { return kind_ == kExternal; }
bool IsSpecialization() const { bool IsSpecialization() const {
return kind_ == kInteger32 || kind_ == kDouble; 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 { class HBitNot: public HUnaryOperation {
public: public:
explicit HBitNot(HValue* value) : HUnaryOperation(value) { 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 { class HCheckMap: public HUnaryOperation {
public: public:
HCheckMap(HValue* value, Handle<Map> map) HCheckMap(HValue* value, Handle<Map> 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 { class HLoadKeyedGeneric: public HLoadKeyed {
public: public:
HLoadKeyedGeneric(HContext* context, HValue* obj, HValue* key) HLoadKeyedGeneric(HContext* context, HValue* obj, HValue* key)

View File

@ -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> 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, HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object,
HValue* key, HValue* key,
HValue* value) { HValue* value) {
@ -3852,12 +3874,20 @@ void HGraphBuilder::VisitProperty(Property* expr) {
HValue* key = Pop(); HValue* key = Pop();
HValue* obj = Pop(); HValue* obj = Pop();
bool is_fast_elements = expr->IsMonomorphic() && if (expr->IsMonomorphic()) {
expr->GetMonomorphicReceiverType()->has_fast_elements(); Handle<Map> receiver_type(expr->GetMonomorphicReceiverType());
// An object has either fast elements or pixel array elements, but never
instr = is_fast_elements // both. Pixel array maps that are assigned to pixel array elements are
? BuildLoadKeyedFastElement(obj, key, expr) // always created with the fast elements flag cleared.
: BuildLoadKeyedGeneric(obj, key); 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()); instr->set_position(expr->position());
ast_context()->ReturnInstruction(instr, expr->id()); ast_context()->ReturnInstruction(instr, expr->id());

View File

@ -791,6 +791,9 @@ class HGraphBuilder: public AstVisitor {
HInstruction* BuildLoadKeyedFastElement(HValue* object, HInstruction* BuildLoadKeyedFastElement(HValue* object,
HValue* key, HValue* key,
Property* expr); Property* expr);
HInstruction* BuildLoadKeyedPixelArrayElement(HValue* object,
HValue* key,
Property* expr);
HInstruction* BuildLoadKeyedGeneric(HValue* object, HInstruction* BuildLoadKeyedGeneric(HValue* object,
HValue* key); HValue* key);

View File

@ -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) { void LCodeGen::DoValueOf(LValueOf* instr) {
Register input = ToRegister(instr->InputAt(0)); Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result()); Register result = ToRegister(instr->result());
@ -2024,22 +2031,33 @@ void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
void LCodeGen::DoLoadElements(LLoadElements* instr) { void LCodeGen::DoLoadElements(LLoadElements* instr) {
ASSERT(instr->result()->Equals(instr->InputAt(0))); Register result = ToRegister(instr->result());
Register reg = ToRegister(instr->InputAt(0)); Register input = ToRegister(instr->InputAt(0));
__ mov(reg, FieldOperand(reg, JSObject::kElementsOffset)); __ mov(result, FieldOperand(input, JSObject::kElementsOffset));
if (FLAG_debug_code) { if (FLAG_debug_code) {
NearLabel done; NearLabel done;
__ cmp(FieldOperand(reg, HeapObject::kMapOffset), __ cmp(FieldOperand(result, HeapObject::kMapOffset),
Immediate(Factory::fixed_array_map())); Immediate(Factory::fixed_array_map()));
__ j(equal, &done); __ 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())); 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); __ 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) { void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
Register arguments = ToRegister(instr->arguments()); Register arguments = ToRegister(instr->arguments());
Register length = ToRegister(instr->length()); 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) { void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
ASSERT(ToRegister(instr->context()).is(esi)); ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->object()).is(edx)); ASSERT(ToRegister(instr->object()).is(edx));

View File

@ -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) { LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
LOperand* object = UseRegister(instr->value()); LOperand* object = UseRegister(instr->value());
LValueOf* result = new LValueOf(object, TempRegister()); LValueOf* result = new LValueOf(object, TempRegister());
@ -1763,7 +1769,14 @@ LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) { LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
LOperand* input = UseRegisterAtStart(instr->value()); 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) { LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
LOperand* context = UseFixed(instr->context(), esi); LOperand* context = UseFixed(instr->context(), esi);
LOperand* object = UseFixed(instr->object(), edx); LOperand* object = UseFixed(instr->object(), edx);

View File

@ -124,6 +124,8 @@ class LCodeGen;
V(LoadKeyedGeneric) \ V(LoadKeyedGeneric) \
V(LoadNamedField) \ V(LoadNamedField) \
V(LoadNamedGeneric) \ V(LoadNamedGeneric) \
V(LoadPixelArrayElement) \
V(LoadPixelArrayExternalPointer) \
V(ModI) \ V(ModI) \
V(MulI) \ V(MulI) \
V(NumberTagD) \ V(NumberTagD) \
@ -133,6 +135,7 @@ class LCodeGen;
V(OsrEntry) \ V(OsrEntry) \
V(OuterContext) \ V(OuterContext) \
V(Parameter) \ V(Parameter) \
V(PixelArrayLength) \
V(Power) \ V(Power) \
V(PushArgument) \ V(PushArgument) \
V(RegExpLiteral) \ 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> { class LFixedArrayLength: public LTemplateInstruction<1, 1, 0> {
public: public:
explicit LFixedArrayLength(LOperand* value) { 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> { class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> {
public: public:
LLoadKeyedFastElement(LOperand* elements, LOperand* key) { 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> { class LLoadKeyedGeneric: public LTemplateInstruction<1, 3, 0> {
public: public:
LLoadKeyedGeneric(LOperand* context, LOperand* obj, LOperand* key) { LLoadKeyedGeneric(LOperand* context, LOperand* obj, LOperand* key) {

View File

@ -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, ACCESSORS(Map, instance_descriptors, DescriptorArray,
kInstanceDescriptorsOffset) kInstanceDescriptorsOffset)
ACCESSORS(Map, code_cache, Object, kCodeCacheOffset) ACCESSORS(Map, code_cache, Object, kCodeCacheOffset)

View File

@ -3593,6 +3593,19 @@ class Map: public HeapObject {
return ((1 << kHasFastElements) & bit_field2()) != 0; 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 // Tells whether the map is attached to SharedFunctionInfo
// (for inobject slack tracking). // (for inobject slack tracking).
inline void set_attached_to_shared_function_info(bool value); 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. // from the descriptors and the fast elements bit cleared.
MUST_USE_RESULT inline MaybeObject* GetSlowElementsMap(); 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). // Returns the property index for name (only valid for FAST MODE).
int PropertyIndexFor(String* name); int PropertyIndexFor(String* name);
@ -3769,6 +3787,7 @@ class Map: public HeapObject {
static const int kStringWrapperSafeForDefaultValueOf = 3; static const int kStringWrapperSafeForDefaultValueOf = 3;
static const int kAttachedToSharedFunctionInfo = 4; static const int kAttachedToSharedFunctionInfo = 4;
static const int kIsShared = 5; static const int kIsShared = 5;
static const int kHasPixelArrayElements = 6;
// Layout of the default cache. It holds alternating name and code objects. // Layout of the default cache. It holds alternating name and code objects.
static const int kCodeCacheEntrySize = 2; static const int kCodeCacheEntrySize = 2;

View File

@ -128,6 +128,7 @@ namespace internal {
SC(gc_last_resort_from_handles, V8.GCLastResortFromHandles) \ SC(gc_last_resort_from_handles, V8.GCLastResortFromHandles) \
SC(map_slow_to_fast_elements, V8.MapSlowToFastElements) \ SC(map_slow_to_fast_elements, V8.MapSlowToFastElements) \
SC(map_fast_to_slow_elements, V8.MapFastToSlowElements) \ SC(map_fast_to_slow_elements, V8.MapFastToSlowElements) \
SC(map_to_pixel_array_elements, V8.MapToPixelArrayElements) \
/* How is the generic keyed-load stub used? */ \ /* How is the generic keyed-load stub used? */ \
SC(keyed_load_generic_smi, V8.KeyedLoadGenericSmi) \ SC(keyed_load_generic_smi, V8.KeyedLoadGenericSmi) \
SC(keyed_load_generic_symbol, V8.KeyedLoadGenericSymbol) \ SC(keyed_load_generic_symbol, V8.KeyedLoadGenericSymbol) \

View File

@ -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) { void LCodeGen::DoValueOf(LValueOf* instr) {
Abort("Unimplemented: %s", "DoValueOf"); Abort("Unimplemented: %s", "DoValueOf");
} }
@ -1726,15 +1733,18 @@ void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
void LCodeGen::DoLoadElements(LLoadElements* instr) { void LCodeGen::DoLoadElements(LLoadElements* instr) {
ASSERT(instr->result()->Equals(instr->InputAt(0))); Register result = ToRegister(instr->result());
Register reg = ToRegister(instr->InputAt(0)); Register input = ToRegister(instr->InputAt(0));
__ movq(reg, FieldOperand(reg, JSObject::kElementsOffset)); __ movq(result, FieldOperand(input, JSObject::kElementsOffset));
if (FLAG_debug_code) { if (FLAG_debug_code) {
NearLabel done; NearLabel done;
__ Cmp(FieldOperand(reg, HeapObject::kMapOffset), __ Cmp(FieldOperand(result, HeapObject::kMapOffset),
Factory::fixed_array_map()); Factory::fixed_array_map());
__ j(equal, &done); __ 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()); Factory::fixed_cow_array_map());
__ Check(equal, "Check for fast elements failed."); __ Check(equal, "Check for fast elements failed.");
__ bind(&done); __ 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) { void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
Abort("Unimplemented: %s", "DoAccessArgumentsAt"); 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) { void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
Abort("Unimplemented: %s", "DoLoadKeyedGeneric"); Abort("Unimplemented: %s", "DoLoadKeyedGeneric");
} }

View File

@ -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) { LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
Abort("Unimplemented: %s", "DoValueOf"); Abort("Unimplemented: %s", "DoValueOf");
return NULL; return NULL;
@ -1638,7 +1644,14 @@ LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) { LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
LOperand* input = UseRegisterAtStart(instr->value()); 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) { LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
Abort("Unimplemented: %s", "DoLoadKeyedGeneric"); Abort("Unimplemented: %s", "DoLoadKeyedGeneric");
return NULL; return NULL;

View File

@ -121,6 +121,8 @@ class LCodeGen;
V(LoadNamedField) \ V(LoadNamedField) \
V(LoadNamedGeneric) \ V(LoadNamedGeneric) \
V(LoadFunctionPrototype) \ V(LoadFunctionPrototype) \
V(LoadPixelArrayElement) \
V(LoadPixelArrayExternalPointer) \
V(ModI) \ V(ModI) \
V(MulI) \ V(MulI) \
V(NumberTagD) \ V(NumberTagD) \
@ -129,6 +131,7 @@ class LCodeGen;
V(ObjectLiteral) \ V(ObjectLiteral) \
V(OsrEntry) \ V(OsrEntry) \
V(Parameter) \ V(Parameter) \
V(PixelArrayLength) \
V(Power) \ V(Power) \
V(PushArgument) \ V(PushArgument) \
V(RegExpLiteral) \ 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> { class LFixedArrayLength: public LTemplateInstruction<1, 1, 0> {
public: public:
explicit LFixedArrayLength(LOperand* value) { 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> { class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> {
public: public:
LLoadKeyedFastElement(LOperand* elements, LOperand* key) { 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> { class LLoadKeyedGeneric: public LTemplateInstruction<1, 2, 0> {
public: public:
LLoadKeyedGeneric(LOperand* obj, LOperand* key) { LLoadKeyedGeneric(LOperand* obj, LOperand* key) {

View File

@ -10674,6 +10674,21 @@ THREADED_TEST(PixelArray) {
"result"); "result");
CHECK_EQ(32640, result->Int32Value()); 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); free(pixel_data);
} }