Support external arrays in Crankshaft

Add specialized hydrogen and lithium instructions to support loading and storing to external arrays.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7354 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
danno@chromium.org 2011-03-24 22:14:15 +00:00
parent 401b308778
commit ea45f6719e
18 changed files with 590 additions and 176 deletions

View File

@ -1822,15 +1822,21 @@ LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
}
LInstruction* LChunkBuilder::DoLoadPixelArrayElement(
HLoadPixelArrayElement* instr) {
LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
HLoadKeyedSpecializedArrayElement* instr) {
// TODO(danno): Add support for other external array types.
if (instr->array_type() != kExternalPixelArray) {
Abort("unsupported load for external array type.");
}
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);
LLoadKeyedSpecializedArrayElement* result =
new LLoadKeyedSpecializedArrayElement(external_pointer,
key);
return DefineAsRegister(result);
}
@ -1864,8 +1870,13 @@ LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
}
LInstruction* LChunkBuilder::DoStorePixelArrayElement(
HStorePixelArrayElement* instr) {
LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
HStoreKeyedSpecializedArrayElement* instr) {
// TODO(danno): Add support for other external array types.
if (instr->array_type() != kExternalPixelArray) {
Abort("unsupported store for external array type.");
}
ASSERT(instr->value()->representation().IsInteger32());
ASSERT(instr->external_pointer()->representation().IsExternal());
ASSERT(instr->key()->representation().IsInteger32());
@ -1874,7 +1885,9 @@ LInstruction* LChunkBuilder::DoStorePixelArrayElement(
LOperand* value = UseTempRegister(instr->value()); // changed by clamp.
LOperand* key = UseRegister(instr->key());
return new LStorePixelArrayElement(external_pointer, key, value);
return new LStoreKeyedSpecializedArrayElement(external_pointer,
key,
value);
}

View File

@ -122,10 +122,10 @@ class LCodeGen;
V(LoadGlobal) \
V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \
V(LoadKeyedSpecializedArrayElement) \
V(LoadNamedField) \
V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
V(LoadPixelArrayElement) \
V(ModI) \
V(MulI) \
V(NumberTagD) \
@ -147,9 +147,9 @@ class LCodeGen;
V(StoreGlobal) \
V(StoreKeyedFastElement) \
V(StoreKeyedGeneric) \
V(StoreKeyedSpecializedArrayElement) \
V(StoreNamedField) \
V(StoreNamedGeneric) \
V(StorePixelArrayElement) \
V(StringCharCodeAt) \
V(StringCharFromCode) \
V(StringLength) \
@ -1225,19 +1225,23 @@ class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> {
};
class LLoadPixelArrayElement: public LTemplateInstruction<1, 2, 0> {
class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
public:
LLoadPixelArrayElement(LOperand* external_pointer, LOperand* key) {
LLoadKeyedSpecializedArrayElement(LOperand* external_pointer,
LOperand* key) {
inputs_[0] = external_pointer;
inputs_[1] = key;
}
DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayElement,
"load-pixel-array-element")
DECLARE_HYDROGEN_ACCESSOR(LoadPixelArrayElement)
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedSpecializedArrayElement,
"load-keyed-specialized-array-element")
DECLARE_HYDROGEN_ACCESSOR(LoadKeyedSpecializedArrayElement)
LOperand* external_pointer() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
ExternalArrayType array_type() const {
return hydrogen()->array_type();
}
};
@ -1642,9 +1646,9 @@ class LStoreKeyedGeneric: public LTemplateInstruction<0, 3, 0> {
LOperand* value() { return inputs_[2]; }
};
class LStorePixelArrayElement: public LTemplateInstruction<0, 3, 0> {
class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> {
public:
LStorePixelArrayElement(LOperand* external_pointer,
LStoreKeyedSpecializedArrayElement(LOperand* external_pointer,
LOperand* key,
LOperand* val) {
inputs_[0] = external_pointer;
@ -1652,15 +1656,19 @@ class LStorePixelArrayElement: public LTemplateInstruction<0, 3, 0> {
inputs_[2] = val;
}
DECLARE_CONCRETE_INSTRUCTION(StorePixelArrayElement,
"store-pixel-array-element")
DECLARE_HYDROGEN_ACCESSOR(StorePixelArrayElement)
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement,
"store-keyed-specialized-array-element")
DECLARE_HYDROGEN_ACCESSOR(StoreKeyedSpecializedArrayElement)
LOperand* external_pointer() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
ExternalArrayType array_type() const {
return hydrogen()->array_type();
}
};
class LStringCharCodeAt: public LTemplateInstruction<1, 2, 0> {
public:
LStringCharCodeAt(LOperand* string, LOperand* index) {

View File

@ -2390,7 +2390,10 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
}
void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) {
void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) {
ASSERT(instr->array_type() == kExternalPixelArray);
Register external_pointer = ToRegister(instr->external_pointer());
Register key = ToRegister(instr->key());
Register result = ToRegister(instr->result());
@ -3058,7 +3061,10 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
}
void LCodeGen::DoStorePixelArrayElement(LStorePixelArrayElement* instr) {
void LCodeGen::DoStoreKeyedSpecializedArrayElement(
LStoreKeyedSpecializedArrayElement* instr) {
ASSERT(instr->array_type() == kExternalPixelArray);
Register external_pointer = ToRegister(instr->external_pointer());
Register key = ToRegister(instr->key());
Register value = ToRegister(instr->value());

View File

@ -1226,8 +1226,36 @@ void HLoadKeyedGeneric::PrintDataTo(StringStream* stream) {
}
void HLoadPixelArrayElement::PrintDataTo(StringStream* stream) {
void HLoadKeyedSpecializedArrayElement::PrintDataTo(
StringStream* stream) {
external_pointer()->PrintNameTo(stream);
stream->Add(".");
switch (array_type()) {
case kExternalByteArray:
stream->Add("byte");
break;
case kExternalUnsignedByteArray:
stream->Add("u_byte");
break;
case kExternalShortArray:
stream->Add("short");
break;
case kExternalUnsignedShortArray:
stream->Add("u_short");
break;
case kExternalIntArray:
stream->Add("int");
break;
case kExternalUnsignedIntArray:
stream->Add("u_int");
break;
case kExternalFloatArray:
stream->Add("float");
break;
case kExternalPixelArray:
stream->Add("pixel");
break;
}
stream->Add("[");
key()->PrintNameTo(stream);
stream->Add("]");
@ -1275,8 +1303,36 @@ void HStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
}
void HStorePixelArrayElement::PrintDataTo(StringStream* stream) {
void HStoreKeyedSpecializedArrayElement::PrintDataTo(
StringStream* stream) {
external_pointer()->PrintNameTo(stream);
stream->Add(".");
switch (array_type()) {
case kExternalByteArray:
stream->Add("byte");
break;
case kExternalUnsignedByteArray:
stream->Add("u_byte");
break;
case kExternalShortArray:
stream->Add("short");
break;
case kExternalUnsignedShortArray:
stream->Add("u_short");
break;
case kExternalIntArray:
stream->Add("int");
break;
case kExternalUnsignedIntArray:
stream->Add("u_int");
break;
case kExternalFloatArray:
stream->Add("float");
break;
case kExternalPixelArray:
stream->Add("pixel");
break;
}
stream->Add("[");
key()->PrintNameTo(stream);
stream->Add("] = ");

View File

@ -127,10 +127,10 @@ class LChunkBuilder;
V(LoadGlobal) \
V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \
V(LoadKeyedSpecializedArrayElement) \
V(LoadNamedField) \
V(LoadNamedGeneric) \
V(LoadNamedFieldPolymorphic) \
V(LoadPixelArrayElement) \
V(LoadNamedGeneric) \
V(Mod) \
V(Mul) \
V(ObjectLiteral) \
@ -149,7 +149,7 @@ class LChunkBuilder;
V(StoreContextSlot) \
V(StoreGlobal) \
V(StoreKeyedFastElement) \
V(StorePixelArrayElement) \
V(StoreKeyedSpecializedArrayElement) \
V(StoreKeyedGeneric) \
V(StoreNamedField) \
V(StoreNamedGeneric) \
@ -171,7 +171,7 @@ class LChunkBuilder;
V(InobjectFields) \
V(BackingStoreFields) \
V(ArrayElements) \
V(PixelArrayElements) \
V(SpecializedArrayElements) \
V(GlobalVars) \
V(Maps) \
V(ArrayLengths) \
@ -1587,7 +1587,7 @@ class HLoadExternalArrayPointer: public HUnaryOperation {
: 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. The external array of a specialized array elements object cannot
// change once set, so it's no necessary to introduce any additional
// dependencies on top of the inputs.
SetFlag(kUseGVN);
@ -3079,13 +3079,20 @@ class HLoadKeyedFastElement: public HBinaryOperation {
};
class HLoadPixelArrayElement: public HBinaryOperation {
class HLoadKeyedSpecializedArrayElement: public HBinaryOperation {
public:
HLoadPixelArrayElement(HValue* external_elements, HValue* key)
: HBinaryOperation(external_elements, key) {
HLoadKeyedSpecializedArrayElement(HValue* external_elements,
HValue* key,
ExternalArrayType array_type)
: HBinaryOperation(external_elements, key),
array_type_(array_type) {
if (array_type == kExternalFloatArray) {
set_representation(Representation::Double());
} else {
set_representation(Representation::Integer32());
SetFlag(kDependsOnPixelArrayElements);
// Native code could change the pixel array.
}
SetFlag(kDependsOnSpecializedArrayElements);
// Native code could change the specialized array.
SetFlag(kDependsOnCalls);
SetFlag(kUseGVN);
}
@ -3101,12 +3108,21 @@ class HLoadPixelArrayElement: public HBinaryOperation {
HValue* external_pointer() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
ExternalArrayType array_type() const { return array_type_; }
DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayElement,
"load_pixel_array_element")
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedSpecializedArrayElement,
"load_keyed_specialized_array_element")
protected:
virtual bool DataEquals(HValue* other) { return true; }
virtual bool DataEquals(HValue* other) {
if (!other->IsLoadKeyedSpecializedArrayElement()) return false;
HLoadKeyedSpecializedArrayElement* cast_other =
HLoadKeyedSpecializedArrayElement::cast(other);
return array_type_ == cast_other->array_type();
}
private:
ExternalArrayType array_type_;
};
@ -3241,10 +3257,14 @@ class HStoreKeyedFastElement: public HTemplateInstruction<3> {
};
class HStorePixelArrayElement: public HTemplateInstruction<3> {
class HStoreKeyedSpecializedArrayElement: public HTemplateInstruction<3> {
public:
HStorePixelArrayElement(HValue* external_elements, HValue* key, HValue* val) {
SetFlag(kChangesPixelArrayElements);
HStoreKeyedSpecializedArrayElement(HValue* external_elements,
HValue* key,
HValue* val,
ExternalArrayType array_type)
: array_type_(array_type) {
SetFlag(kChangesSpecializedArrayElements);
SetOperandAt(0, external_elements);
SetOperandAt(1, key);
SetOperandAt(2, val);
@ -3255,17 +3275,24 @@ class HStorePixelArrayElement: public HTemplateInstruction<3> {
virtual Representation RequiredInputRepresentation(int index) const {
if (index == 0) {
return Representation::External();
} else {
if (index == 2 && array_type() == kExternalFloatArray) {
return Representation::Double();
} else {
return Representation::Integer32();
}
}
}
HValue* external_pointer() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
HValue* value() { return OperandAt(2); }
ExternalArrayType array_type() const { return array_type_; }
DECLARE_CONCRETE_INSTRUCTION(StorePixelArrayElement,
"store_pixel_array_element")
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement,
"store_keyed_specialized_array_element")
private:
ExternalArrayType array_type_;
};

View File

@ -3219,9 +3219,10 @@ void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
// 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_external_array_elements()) {
if (expr->GetExternalArrayType() == kExternalPixelArray) {
instr = BuildStoreKeyedPixelArrayElement(object, key, value, expr);
}
instr = BuildStoreKeyedSpecializedArrayElement(object,
key,
value,
expr);
} else if (receiver_type->has_fast_elements()) {
instr = BuildStoreKeyedFastElement(object, key, value, expr);
}
@ -3534,7 +3535,8 @@ HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object,
}
HInstruction* HGraphBuilder::BuildLoadKeyedPixelArrayElement(HValue* object,
HInstruction* HGraphBuilder::BuildLoadKeyedSpecializedArrayElement(
HValue* object,
HValue* key,
Property* expr) {
ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic());
@ -3551,8 +3553,10 @@ HInstruction* HGraphBuilder::BuildLoadKeyedPixelArrayElement(HValue* object,
HLoadExternalArrayPointer* external_elements =
new HLoadExternalArrayPointer(elements);
AddInstruction(external_elements);
HLoadPixelArrayElement* pixel_array_value =
new HLoadPixelArrayElement(external_elements, key);
HLoadKeyedSpecializedArrayElement* pixel_array_value =
new HLoadKeyedSpecializedArrayElement(external_elements,
key,
expr->GetExternalArrayType());
return pixel_array_value;
}
@ -3590,11 +3594,11 @@ HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object,
}
HInstruction* HGraphBuilder::BuildStoreKeyedPixelArrayElement(
HInstruction* HGraphBuilder::BuildStoreKeyedSpecializedArrayElement(
HValue* object,
HValue* key,
HValue* val,
Expression* expr) {
Assignment* expr) {
ASSERT(expr->IsMonomorphic());
AddInstruction(new HCheckNonSmi(object));
Handle<Map> map = expr->GetMonomorphicReceiverType();
@ -3608,7 +3612,11 @@ HInstruction* HGraphBuilder::BuildStoreKeyedPixelArrayElement(
HLoadExternalArrayPointer* external_elements =
new HLoadExternalArrayPointer(elements);
AddInstruction(external_elements);
return new HStorePixelArrayElement(external_elements, key, val);
return new HStoreKeyedSpecializedArrayElement(
external_elements,
key,
val,
expr->GetExternalArrayType());
}
@ -3703,9 +3711,7 @@ void HGraphBuilder::VisitProperty(Property* expr) {
// both. Pixel array maps that are assigned to pixel array elements are
// always created with the fast elements flag cleared.
if (receiver_type->has_external_array_elements()) {
if (expr->GetExternalArrayType() == kExternalPixelArray) {
instr = BuildLoadKeyedPixelArrayElement(obj, key, expr);
}
instr = BuildLoadKeyedSpecializedArrayElement(obj, key, expr);
} else if (receiver_type->has_fast_elements()) {
instr = BuildLoadKeyedFastElement(obj, key, expr);
}

View File

@ -819,7 +819,7 @@ class HGraphBuilder: public AstVisitor {
HInstruction* BuildLoadKeyedFastElement(HValue* object,
HValue* key,
Property* expr);
HInstruction* BuildLoadKeyedPixelArrayElement(HValue* object,
HInstruction* BuildLoadKeyedSpecializedArrayElement(HValue* object,
HValue* key,
Property* expr);
HInstruction* BuildLoadKeyedGeneric(HValue* object,
@ -850,10 +850,11 @@ class HGraphBuilder: public AstVisitor {
HValue* val,
Expression* expr);
HInstruction* BuildStoreKeyedPixelArrayElement(HValue* object,
HInstruction* BuildStoreKeyedSpecializedArrayElement(
HValue* object,
HValue* key,
HValue* val,
Expression* expr);
Assignment* expr);
HValue* BuildContextChainWalk(Variable* var);

View File

@ -2176,6 +2176,17 @@ void Assembler::cvtss2sd(XMMRegister dst, XMMRegister src) {
}
void Assembler::cvtsd2ss(XMMRegister dst, XMMRegister src) {
ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xF2);
EMIT(0x0F);
EMIT(0x5A);
emit_sse_operand(dst, src);
}
void Assembler::addsd(XMMRegister dst, XMMRegister src) {
ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
@ -2420,6 +2431,39 @@ void Assembler::movsd(XMMRegister dst, XMMRegister src) {
}
void Assembler::movss(const Operand& dst, XMMRegister src ) {
ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xF3); // float
EMIT(0x0F);
EMIT(0x11); // store
emit_sse_operand(src, dst);
}
void Assembler::movss(XMMRegister dst, const Operand& src) {
ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xF3); // float
EMIT(0x0F);
EMIT(0x10); // load
emit_sse_operand(dst, src);
}
void Assembler::movss(XMMRegister dst, XMMRegister src) {
ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xF3);
EMIT(0x0F);
EMIT(0x10);
emit_sse_operand(dst, src);
}
void Assembler::movd(XMMRegister dst, const Operand& src) {
ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);

View File

@ -904,6 +904,7 @@ class Assembler : public AssemblerBase {
void cvtsi2sd(XMMRegister dst, const Operand& src);
void cvtss2sd(XMMRegister dst, XMMRegister src);
void cvtsd2ss(XMMRegister dst, XMMRegister src);
void addsd(XMMRegister dst, XMMRegister src);
void subsd(XMMRegister dst, XMMRegister src);
@ -934,6 +935,10 @@ class Assembler : public AssemblerBase {
void movd(const Operand& src, XMMRegister dst);
void movsd(XMMRegister dst, XMMRegister src);
void movss(XMMRegister dst, const Operand& src);
void movss(const Operand& src, XMMRegister dst);
void movss(XMMRegister dst, XMMRegister src);
void pand(XMMRegister dst, XMMRegister src);
void pxor(XMMRegister dst, XMMRegister src);
void por(XMMRegister dst, XMMRegister src);

View File

@ -1373,6 +1373,12 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
get_modrm(*data, &mod, &regop, &rm);
AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
data += PrintRightXMMOperand(data);
} else if (b2 == 0x5A) {
data += 3;
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
data += PrintRightXMMOperand(data);
} else {
const char* mnem = "?";
switch (b2) {
@ -1422,25 +1428,39 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
case 0xF3:
if (*(data+1) == 0x0F) {
if (*(data+2) == 0x2C) {
byte b2 = *(data+2);
if (b2 == 0x11) {
AppendToBuffer("movss ");
data += 3;
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
data += PrintRightXMMOperand(data);
AppendToBuffer(",%s", NameOfXMMRegister(regop));
} else if (b2 == 0x10) {
data += 3;
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
data += PrintRightXMMOperand(data);
} else if (b2 == 0x2C) {
data += 3;
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop));
data += PrintRightXMMOperand(data);
} else if (*(data+2) == 0x5A) {
} else if (b2 == 0x5A) {
data += 3;
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
data += PrintRightXMMOperand(data);
} else if (*(data+2) == 0x6F) {
} else if (b2 == 0x6F) {
data += 3;
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
data += PrintRightXMMOperand(data);
} else if (*(data+2) == 0x7F) {
} else if (b2 == 0x7F) {
AppendToBuffer("movdqu ");
data += 3;
int mod, regop, rm;

View File

@ -2245,12 +2245,17 @@ void LCodeGen::DoLoadElements(LLoadElements* instr) {
__ cmp(FieldOperand(result, HeapObject::kMapOffset),
Immediate(factory()->fixed_array_map()));
__ j(equal, &done);
__ cmp(FieldOperand(result, HeapObject::kMapOffset),
Immediate(factory()->external_pixel_array_map()));
__ j(equal, &done);
__ cmp(FieldOperand(result, HeapObject::kMapOffset),
Immediate(factory()->fixed_cow_array_map()));
__ Check(equal, "Check for fast elements or pixel array failed.");
__ j(equal, &done);
Register temp((result.is(eax)) ? ebx : eax);
__ push(temp);
__ mov(temp, FieldOperand(result, HeapObject::kMapOffset));
__ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
__ sub(Operand(temp), Immediate(FIRST_EXTERNAL_ARRAY_TYPE));
__ cmp(Operand(temp), Immediate(kExternalArrayTypeCount));
__ pop(temp);
__ Check(below, "Check for fast elements or pixel array failed.");
__ bind(&done);
}
}
@ -2298,14 +2303,47 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
}
void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) {
void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) {
Register external_pointer = ToRegister(instr->external_pointer());
Register key = ToRegister(instr->key());
Register result = ToRegister(instr->result());
ASSERT(result.is(external_pointer));
// Load the result.
ExternalArrayType array_type = instr->array_type();
if (array_type == kExternalFloatArray) {
XMMRegister result(ToDoubleRegister(instr->result()));
__ movss(result, Operand(external_pointer, key, times_4, 0));
__ cvtss2sd(result, result);
} else {
Register result(ToRegister(instr->result()));
switch (array_type) {
case kExternalByteArray:
__ movsx_b(result, Operand(external_pointer, key, times_1, 0));
break;
case kExternalUnsignedByteArray:
case kExternalPixelArray:
__ movzx_b(result, Operand(external_pointer, key, times_1, 0));
break;
case kExternalShortArray:
__ movsx_w(result, Operand(external_pointer, key, times_2, 0));
break;
case kExternalUnsignedShortArray:
__ movzx_w(result, Operand(external_pointer, key, times_2, 0));
break;
case kExternalIntArray:
__ mov(result, Operand(external_pointer, key, times_4, 0));
break;
case kExternalUnsignedIntArray:
__ mov(result, Operand(external_pointer, key, times_4, 0));
__ test(Operand(result), Immediate(0x80000000));
// TODO(danno): we could be more clever here, perhaps having a special
// version of the stub that detects if the overflow case actually
// happens, and generate code that returns a double rather than int.
DeoptimizeIf(not_zero, instr->environment());
break;
case kExternalFloatArray:
UNREACHABLE();
break;
}
}
}
@ -2930,22 +2968,52 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
}
void LCodeGen::DoStorePixelArrayElement(LStorePixelArrayElement* instr) {
void LCodeGen::DoStoreKeyedSpecializedArrayElement(
LStoreKeyedSpecializedArrayElement* instr) {
Register external_pointer = ToRegister(instr->external_pointer());
Register key = ToRegister(instr->key());
ExternalArrayType array_type = instr->array_type();
if (array_type == kExternalFloatArray) {
__ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
__ movss(Operand(external_pointer, key, times_4, 0), xmm0);
} else {
Register value = ToRegister(instr->value());
ASSERT(ToRegister(instr->TempAt(0)).is(eax));
__ mov(eax, value);
{ // Clamp the value to [0..255].
switch (array_type) {
case kExternalPixelArray: {
// Clamp the value to [0..255].
Register temp = ToRegister(instr->TempAt(0));
// The dec_b below requires that the clamped value is in a byte
// register. eax is an arbitrary choice to satisfy this requirement, we
// hinted the register allocator to give us eax when building the
// instruction.
ASSERT(temp.is(eax));
__ mov(temp, ToRegister(instr->value()));
NearLabel done;
__ test(eax, Immediate(0xFFFFFF00));
__ test(temp, Immediate(0xFFFFFF00));
__ j(zero, &done);
__ setcc(negative, eax); // 1 if negative, 0 if positive.
__ dec_b(eax); // 0 if negative, 255 if positive.
__ setcc(negative, temp); // 1 if negative, 0 if positive.
__ dec_b(temp); // 0 if negative, 255 if positive.
__ bind(&done);
__ mov_b(Operand(external_pointer, key, times_1, 0), temp);
break;
}
case kExternalByteArray:
case kExternalUnsignedByteArray:
__ mov_b(Operand(external_pointer, key, times_1, 0), value);
break;
case kExternalShortArray:
case kExternalUnsignedShortArray:
__ mov_w(Operand(external_pointer, key, times_2, 0), value);
break;
case kExternalIntArray:
case kExternalUnsignedIntArray:
__ mov(Operand(external_pointer, key, times_4, 0), value);
break;
case kExternalFloatArray:
UNREACHABLE();
break;
}
}
__ mov_b(Operand(external_pointer, key, times_1, 0), eax);
}

View File

@ -1845,16 +1845,24 @@ LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
}
LInstruction* LChunkBuilder::DoLoadPixelArrayElement(
HLoadPixelArrayElement* instr) {
ASSERT(instr->representation().IsInteger32());
LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
HLoadKeyedSpecializedArrayElement* instr) {
ExternalArrayType array_type = instr->array_type();
Representation representation(instr->representation());
ASSERT((representation.IsInteger32() && array_type != kExternalFloatArray) ||
(representation.IsDouble() && array_type == kExternalFloatArray));
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);
LOperand* external_pointer = UseRegister(instr->external_pointer());
LOperand* key = UseRegister(instr->key());
LLoadKeyedSpecializedArrayElement* result =
new LLoadKeyedSpecializedArrayElement(external_pointer,
key);
LInstruction* load_instr = DefineAsRegister(result);
// An unsigned int array load might overflow and cause a deopt, make sure it
// has an environment.
return (array_type == kExternalUnsignedIntArray)
? AssignEnvironment(load_instr)
: load_instr;
}
@ -1887,20 +1895,31 @@ LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
}
LInstruction* LChunkBuilder::DoStorePixelArrayElement(
HStorePixelArrayElement* instr) {
ASSERT(instr->value()->representation().IsInteger32());
LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
HStoreKeyedSpecializedArrayElement* instr) {
Representation representation(instr->value()->representation());
ExternalArrayType array_type = instr->array_type();
ASSERT((representation.IsInteger32() && array_type != kExternalFloatArray) ||
(representation.IsDouble() && array_type == kExternalFloatArray));
ASSERT(instr->external_pointer()->representation().IsExternal());
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer = UseRegister(instr->external_pointer());
LOperand* val = UseRegister(instr->value());
LOperand* key = UseRegister(instr->key());
// The generated code requires that the clamped value is in a byte
// register. eax is an arbitrary choice to satisfy this requirement.
LOperand* clamped = FixedTemp(eax);
LOperand* temp = NULL;
return new LStorePixelArrayElement(external_pointer, key, val, clamped);
if (array_type == kExternalPixelArray) {
// The generated code for pixel array stores requires that the clamped value
// is in a byte register. eax is an arbitrary choice to satisfy this
// requirement.
temp = FixedTemp(eax);
}
return new LStoreKeyedSpecializedArrayElement(external_pointer,
key,
val,
temp);
}

View File

@ -124,10 +124,10 @@ class LCodeGen;
V(LoadGlobal) \
V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \
V(LoadKeyedSpecializedArrayElement) \
V(LoadNamedField) \
V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
V(LoadPixelArrayElement) \
V(ModI) \
V(MulI) \
V(NumberTagD) \
@ -149,9 +149,9 @@ class LCodeGen;
V(StoreGlobal) \
V(StoreKeyedFastElement) \
V(StoreKeyedGeneric) \
V(StoreKeyedSpecializedArrayElement) \
V(StoreNamedField) \
V(StoreNamedGeneric) \
V(StorePixelArrayElement) \
V(StringCharCodeAt) \
V(StringCharFromCode) \
V(StringLength) \
@ -1256,19 +1256,23 @@ class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> {
};
class LLoadPixelArrayElement: public LTemplateInstruction<1, 2, 0> {
class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
public:
LLoadPixelArrayElement(LOperand* external_pointer, LOperand* key) {
LLoadKeyedSpecializedArrayElement(LOperand* external_pointer,
LOperand* key) {
inputs_[0] = external_pointer;
inputs_[1] = key;
}
DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayElement,
"load-pixel-array-element")
DECLARE_HYDROGEN_ACCESSOR(LoadPixelArrayElement)
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedSpecializedArrayElement,
"load-keyed-specialized-array-element")
DECLARE_HYDROGEN_ACCESSOR(LoadKeyedSpecializedArrayElement)
LOperand* external_pointer() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
ExternalArrayType array_type() const {
return hydrogen()->array_type();
}
};
@ -1674,25 +1678,28 @@ class LStoreKeyedFastElement: public LTemplateInstruction<0, 3, 0> {
};
class LStorePixelArrayElement: public LTemplateInstruction<0, 3, 1> {
class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 1> {
public:
LStorePixelArrayElement(LOperand* external_pointer,
LStoreKeyedSpecializedArrayElement(LOperand* external_pointer,
LOperand* key,
LOperand* val,
LOperand* clamped) {
LOperand* temp) {
inputs_[0] = external_pointer;
inputs_[1] = key;
inputs_[2] = val;
temps_[0] = clamped;
temps_[0] = temp;
}
DECLARE_CONCRETE_INSTRUCTION(StorePixelArrayElement,
"store-pixel-array-element")
DECLARE_HYDROGEN_ACCESSOR(StorePixelArrayElement)
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement,
"store-keyed-specialized-array-element")
DECLARE_HYDROGEN_ACCESSOR(StoreKeyedSpecializedArrayElement)
LOperand* external_pointer() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
ExternalArrayType array_type() const {
return hydrogen()->array_type();
}
};

View File

@ -583,6 +583,8 @@ enum InstanceType {
FIRST_FUNCTION_CLASS_TYPE = JS_REGEXP_TYPE
};
static const int kExternalArrayTypeCount = LAST_EXTERNAL_ARRAY_TYPE -
FIRST_EXTERNAL_ARRAY_TYPE + 1;
STATIC_CHECK(JS_OBJECT_TYPE == Internals::kJSObjectType);
STATIC_CHECK(FIRST_NONSTRING_TYPE == Internals::kFirstNonstringType);

View File

@ -2215,12 +2215,17 @@ void LCodeGen::DoLoadElements(LLoadElements* instr) {
__ CompareRoot(FieldOperand(result, HeapObject::kMapOffset),
Heap::kFixedArrayMapRootIndex);
__ j(equal, &done);
__ CompareRoot(FieldOperand(result, HeapObject::kMapOffset),
Heap::kExternalPixelArrayMapRootIndex);
__ j(equal, &done);
__ CompareRoot(FieldOperand(result, HeapObject::kMapOffset),
Heap::kFixedCOWArrayMapRootIndex);
__ Check(equal, "Check for fast elements failed.");
__ j(equal, &done);
Register temp((result.is(rax)) ? rbx : rax);
__ push(temp);
__ movq(temp, FieldOperand(result, HeapObject::kMapOffset));
__ movzxbq(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
__ subq(temp, Immediate(FIRST_EXTERNAL_ARRAY_TYPE));
__ cmpq(temp, Immediate(kExternalArrayTypeCount));
__ pop(temp);
__ Check(below, "Check for fast elements failed.");
__ bind(&done);
}
}
@ -2271,14 +2276,47 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
}
void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) {
Register external_elements = ToRegister(instr->external_pointer());
void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) {
Register external_pointer = 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));
ExternalArrayType array_type = instr->array_type();
if (array_type == kExternalFloatArray) {
XMMRegister result(ToDoubleRegister(instr->result()));
__ movss(result, Operand(external_pointer, key, times_4, 0));
__ cvtss2sd(result, result);
} else {
Register result(ToRegister(instr->result()));
switch (array_type) {
case kExternalByteArray:
__ movsxbq(result, Operand(external_pointer, key, times_1, 0));
break;
case kExternalUnsignedByteArray:
case kExternalPixelArray:
__ movzxbq(result, Operand(external_pointer, key, times_1, 0));
break;
case kExternalShortArray:
__ movsxwq(result, Operand(external_pointer, key, times_2, 0));
break;
case kExternalUnsignedShortArray:
__ movzxwq(result, Operand(external_pointer, key, times_2, 0));
break;
case kExternalIntArray:
__ movsxlq(result, Operand(external_pointer, key, times_4, 0));
break;
case kExternalUnsignedIntArray:
__ movl(result, Operand(external_pointer, key, times_4, 0));
__ testl(result, result);
// TODO(danno): we could be more clever here, perhaps having a special
// version of the stub that detects if the overflow case actually
// happens, and generate code that returns a double rather than int.
DeoptimizeIf(negative, instr->environment());
break;
case kExternalFloatArray:
UNREACHABLE();
break;
}
}
}
@ -2892,11 +2930,19 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
}
void LCodeGen::DoStorePixelArrayElement(LStorePixelArrayElement* instr) {
void LCodeGen::DoStoreKeyedSpecializedArrayElement(
LStoreKeyedSpecializedArrayElement* instr) {
Register external_pointer = ToRegister(instr->external_pointer());
Register key = ToRegister(instr->key());
Register value = ToRegister(instr->value());
ExternalArrayType array_type = instr->array_type();
if (array_type == kExternalFloatArray) {
XMMRegister value(ToDoubleRegister(instr->value()));
__ cvtsd2ss(value, value);
__ movss(Operand(external_pointer, key, times_4, 0), value);
} else {
Register value(ToRegister(instr->value()));
switch (array_type) {
case kExternalPixelArray:
{ // Clamp the value to [0..255].
NearLabel done;
__ testl(value, Immediate(0xFFFFFF00));
@ -2904,9 +2950,26 @@ void LCodeGen::DoStorePixelArrayElement(LStorePixelArrayElement* instr) {
__ setcc(negative, value); // 1 if negative, 0 if positive.
__ decb(value); // 0 if negative, 255 if positive.
__ bind(&done);
}
__ movb(Operand(external_pointer, key, times_1, 0), value);
}
break;
case kExternalByteArray:
case kExternalUnsignedByteArray:
__ movb(Operand(external_pointer, key, times_1, 0), value);
break;
case kExternalShortArray:
case kExternalUnsignedShortArray:
__ movw(Operand(external_pointer, key, times_2, 0), value);
break;
case kExternalIntArray:
case kExternalUnsignedIntArray:
__ movl(Operand(external_pointer, key, times_4, 0), value);
break;
case kExternalFloatArray:
UNREACHABLE();
break;
}
}
}

View File

@ -1816,16 +1816,22 @@ LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
}
LInstruction* LChunkBuilder::DoLoadPixelArrayElement(
HLoadPixelArrayElement* instr) {
ASSERT(instr->representation().IsInteger32());
LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
HLoadKeyedSpecializedArrayElement* instr) {
ExternalArrayType array_type = instr->array_type();
Representation representation(instr->representation());
ASSERT((representation.IsInteger32() && array_type != kExternalFloatArray) ||
(representation.IsDouble() && array_type == kExternalFloatArray));
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);
LOperand* external_pointer = UseRegister(instr->external_pointer());
LOperand* key = UseRegister(instr->key());
LLoadKeyedSpecializedArrayElement* result =
new LLoadKeyedSpecializedArrayElement(external_pointer, key);
LInstruction* load_instr = DefineAsRegister(result);
// An unsigned int array load might overflow and cause a deopt, make sure it
// has an environment.
return (array_type == kExternalUnsignedIntArray) ?
AssignEnvironment(load_instr) : load_instr;
}
@ -1857,17 +1863,26 @@ LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
}
LInstruction* LChunkBuilder::DoStorePixelArrayElement(
HStorePixelArrayElement* instr) {
ASSERT(instr->value()->representation().IsInteger32());
LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
HStoreKeyedSpecializedArrayElement* instr) {
Representation representation(instr->value()->representation());
ExternalArrayType array_type = instr->array_type();
ASSERT((representation.IsInteger32() && array_type != kExternalFloatArray) ||
(representation.IsDouble() && array_type == kExternalFloatArray));
ASSERT(instr->external_pointer()->representation().IsExternal());
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer = UseRegister(instr->external_pointer());
LOperand* val = UseTempRegister(instr->value());
bool val_is_temp_register = array_type == kExternalPixelArray ||
array_type == kExternalFloatArray;
LOperand* val = val_is_temp_register
? UseTempRegister(instr->value())
: UseRegister(instr->key());
LOperand* key = UseRegister(instr->key());
return new LStorePixelArrayElement(external_pointer, key, val);
return new LStoreKeyedSpecializedArrayElement(external_pointer,
key,
val);
}

View File

@ -121,11 +121,11 @@ class LCodeGen;
V(LoadGlobal) \
V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \
V(LoadKeyedSpecializedArrayElement) \
V(LoadNamedField) \
V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
V(LoadFunctionPrototype) \
V(LoadPixelArrayElement) \
V(ModI) \
V(MulI) \
V(NumberTagD) \
@ -147,9 +147,9 @@ class LCodeGen;
V(StoreGlobal) \
V(StoreKeyedFastElement) \
V(StoreKeyedGeneric) \
V(StoreKeyedSpecializedArrayElement) \
V(StoreNamedField) \
V(StoreNamedGeneric) \
V(StorePixelArrayElement) \
V(StringCharCodeAt) \
V(StringCharFromCode) \
V(StringLength) \
@ -1211,19 +1211,23 @@ class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> {
};
class LLoadPixelArrayElement: public LTemplateInstruction<1, 2, 0> {
class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
public:
LLoadPixelArrayElement(LOperand* external_pointer, LOperand* key) {
LLoadKeyedSpecializedArrayElement(LOperand* external_pointer,
LOperand* key) {
inputs_[0] = external_pointer;
inputs_[1] = key;
}
DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayElement,
"load-pixel-array-element")
DECLARE_HYDROGEN_ACCESSOR(LoadPixelArrayElement)
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedSpecializedArrayElement,
"load-keyed-specialized-array-element")
DECLARE_HYDROGEN_ACCESSOR(LoadKeyedSpecializedArrayElement)
LOperand* external_pointer() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
ExternalArrayType array_type() const {
return hydrogen()->array_type();
}
};
@ -1601,9 +1605,9 @@ class LStoreKeyedFastElement: public LTemplateInstruction<0, 3, 0> {
};
class LStorePixelArrayElement: public LTemplateInstruction<0, 3, 0> {
class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> {
public:
LStorePixelArrayElement(LOperand* external_pointer,
LStoreKeyedSpecializedArrayElement(LOperand* external_pointer,
LOperand* key,
LOperand* val) {
inputs_[0] = external_pointer;
@ -1611,13 +1615,16 @@ class LStorePixelArrayElement: public LTemplateInstruction<0, 3, 0> {
inputs_[2] = val;
}
DECLARE_CONCRETE_INSTRUCTION(StorePixelArrayElement,
"store-pixel-array-element")
DECLARE_HYDROGEN_ACCESSOR(StorePixelArrayElement)
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement,
"store-keyed-specialized-array-element")
DECLARE_HYDROGEN_ACCESSOR(StoreKeyedSpecializedArrayElement)
LOperand* external_pointer() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
ExternalArrayType array_type() const {
return hydrogen()->array_type();
}
};

View File

@ -11492,6 +11492,53 @@ static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
CHECK_EQ(true, result->BooleanValue());
}
// Test crankshaft external array loads
for (int i = 0; i < kElementCount; i++) {
array->set(i, static_cast<ElementType>(i));
}
result = CompileRun("function ee_load_test_func(sum) {"
" for (var i=0;i<40;++i)"
" sum += ext_array[i];"
" return sum;"
"}"
"sum=0;"
"for (var i=0;i<10000;++i) {"
" sum=ee_load_test_func(sum);"
"}"
"sum;");
CHECK_EQ(7800000, result->Int32Value());
// Test crankshaft external array stores
result = CompileRun("function ee_store_test_func(sum) {"
" for (var i=0;i<40;++i)"
" sum += ext_array[i] = i;"
" return sum;"
"}"
"sum=0;"
"for (var i=0;i<10000;++i) {"
" sum=ee_store_test_func(sum);"
"}"
"sum;");
CHECK_EQ(7800000, result->Int32Value());
// Test edge cases for crankshaft code.
array->set(0, static_cast<ElementType>(0xFFFFFFFF));
result = CompileRun("function ee_limit_test_func(i) {"
" return ext_array[i];"
" return sum;"
"}"
"sum=0;"
"for (var i=0;i<1000000;++i) {"
" sum=ee_limit_test_func(0);"
"}"
"sum;");
if (array_type == v8::kExternalFloatArray) {
CHECK_EQ(0, result->Int32Value());
} else {
CHECK_EQ(static_cast<int>(static_cast<ElementType>(0xFFFFFFFF)),
result->Int32Value());
}
result = CompileRun("ext_array[3] = 33;"
"delete ext_array[3];"
"ext_array[3];");