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:
parent
73fe82426f
commit
1bd9f602be
@ -2757,9 +2757,9 @@ void v8::Object::SetIndexedPropertiesToPixelData(uint8_t* data, int length) {
|
||||
return;
|
||||
}
|
||||
i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(length, data);
|
||||
i::Handle<i::Map> slow_map =
|
||||
i::Factory::GetSlowElementsMap(i::Handle<i::Map>(self->map()));
|
||||
self->set_map(*slow_map);
|
||||
i::Handle<i::Map> pixel_array_map =
|
||||
i::Factory::GetPixelArrayElementsMap(i::Handle<i::Map>(self->map()));
|
||||
self->set_map(*pixel_array_map);
|
||||
self->set_elements(*pixels);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
||||
|
@ -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) {
|
||||
CALL_HEAP_FUNCTION(array->Copy(), FixedArray);
|
||||
}
|
||||
|
@ -196,6 +196,8 @@ class Factory : public AllStatic {
|
||||
|
||||
static Handle<Map> GetSlowElementsMap(Handle<Map> map);
|
||||
|
||||
static Handle<Map> GetPixelArrayElementsMap(Handle<Map> map);
|
||||
|
||||
static Handle<FixedArray> CopyFixedArray(Handle<FixedArray> array);
|
||||
|
||||
// Numbers (eg, literals) are pretenured by the parser.
|
||||
|
@ -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(".");
|
||||
|
@ -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> 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)
|
||||
|
@ -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,
|
||||
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<Map> 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());
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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) \
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user