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:
parent
401b308778
commit
ea45f6719e
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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());
|
||||
|
@ -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("] = ");
|
||||
|
@ -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_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -1373,6 +1373,12 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
|
||||
get_modrm(*data, &mod, ®op, &rm);
|
||||
AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
|
||||
data += PrintRightXMMOperand(data);
|
||||
} else if (b2 == 0x5A) {
|
||||
data += 3;
|
||||
int mod, regop, rm;
|
||||
get_modrm(*data, &mod, ®op, &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, ®op, &rm);
|
||||
data += PrintRightXMMOperand(data);
|
||||
AppendToBuffer(",%s", NameOfXMMRegister(regop));
|
||||
} else if (b2 == 0x10) {
|
||||
data += 3;
|
||||
int mod, regop, rm;
|
||||
get_modrm(*data, &mod, ®op, &rm);
|
||||
AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
|
||||
data += PrintRightXMMOperand(data);
|
||||
} else if (b2 == 0x2C) {
|
||||
data += 3;
|
||||
int mod, regop, rm;
|
||||
get_modrm(*data, &mod, ®op, &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, ®op, &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, ®op, &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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -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];");
|
||||
|
Loading…
Reference in New Issue
Block a user