Implement HChange support for Smis and use it in Load/StoreNameField
BUG= R=verwaest@chromium.org Review URL: https://chromiumcodereview.appspot.com/15303004 Patch from Daniel Clifford <danno@chromium.org>. git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14765 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
366948840a
commit
308e69755b
@ -1887,12 +1887,24 @@ LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) {
|
|||||||
LInstruction* LChunkBuilder::DoChange(HChange* instr) {
|
LInstruction* LChunkBuilder::DoChange(HChange* instr) {
|
||||||
Representation from = instr->from();
|
Representation from = instr->from();
|
||||||
Representation to = instr->to();
|
Representation to = instr->to();
|
||||||
|
if (from.IsSmi()) {
|
||||||
|
if (to.IsTagged()) {
|
||||||
|
LOperand* value = UseRegister(instr->value());
|
||||||
|
return DefineSameAsFirst(new(zone()) LDummyUse(value));
|
||||||
|
}
|
||||||
|
from = Representation::Tagged();
|
||||||
|
}
|
||||||
if (from.IsTagged()) {
|
if (from.IsTagged()) {
|
||||||
if (to.IsDouble()) {
|
if (to.IsDouble()) {
|
||||||
info()->MarkAsDeferredCalling();
|
info()->MarkAsDeferredCalling();
|
||||||
LOperand* value = UseRegister(instr->value());
|
LOperand* value = UseRegister(instr->value());
|
||||||
LNumberUntagD* res = new(zone()) LNumberUntagD(value);
|
LNumberUntagD* res = new(zone()) LNumberUntagD(value);
|
||||||
return AssignEnvironment(DefineAsRegister(res));
|
return AssignEnvironment(DefineAsRegister(res));
|
||||||
|
} else if (to.IsSmi()) {
|
||||||
|
HValue* val = instr->value();
|
||||||
|
LOperand* value = UseRegisterAtStart(val);
|
||||||
|
return AssignEnvironment(
|
||||||
|
DefineSameAsFirst(new(zone()) LCheckSmi(value)));
|
||||||
} else {
|
} else {
|
||||||
ASSERT(to.IsInteger32());
|
ASSERT(to.IsInteger32());
|
||||||
LOperand* value = NULL;
|
LOperand* value = NULL;
|
||||||
@ -1934,6 +1946,10 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
|
|||||||
LNumberTagD* result = new(zone()) LNumberTagD(value, temp1, temp2);
|
LNumberTagD* result = new(zone()) LNumberTagD(value, temp1, temp2);
|
||||||
Define(result, result_temp);
|
Define(result, result_temp);
|
||||||
return AssignPointerMap(result);
|
return AssignPointerMap(result);
|
||||||
|
} else if (to.IsSmi()) {
|
||||||
|
LOperand* value = UseRegister(instr->value());
|
||||||
|
return AssignEnvironment(DefineAsRegister(new(zone()) LDoubleToSmi(value,
|
||||||
|
TempRegister(), TempRegister())));
|
||||||
} else {
|
} else {
|
||||||
ASSERT(to.IsInteger32());
|
ASSERT(to.IsInteger32());
|
||||||
LOperand* value = UseRegister(instr->value());
|
LOperand* value = UseRegister(instr->value());
|
||||||
@ -1956,6 +1972,15 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
|
|||||||
LNumberTagI* result = new(zone()) LNumberTagI(value);
|
LNumberTagI* result = new(zone()) LNumberTagI(value);
|
||||||
return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
|
return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
|
||||||
}
|
}
|
||||||
|
} else if (to.IsSmi()) {
|
||||||
|
HValue* val = instr->value();
|
||||||
|
LOperand* value = UseRegister(val);
|
||||||
|
LInstruction* result =
|
||||||
|
DefineSameAsFirst(new(zone()) LInteger32ToSmi(value));
|
||||||
|
if (val->HasRange() && val->range()->IsInSmiRange()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return AssignEnvironment(result);
|
||||||
} else {
|
} else {
|
||||||
ASSERT(to.IsDouble());
|
ASSERT(to.IsDouble());
|
||||||
if (instr->value()->CheckFlag(HInstruction::kUint32)) {
|
if (instr->value()->CheckFlag(HInstruction::kUint32)) {
|
||||||
@ -2049,7 +2074,7 @@ LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
|
|||||||
return DefineAsRegister(new(zone()) LConstantI);
|
return DefineAsRegister(new(zone()) LConstantI);
|
||||||
} else if (r.IsDouble()) {
|
} else if (r.IsDouble()) {
|
||||||
return DefineAsRegister(new(zone()) LConstantD);
|
return DefineAsRegister(new(zone()) LConstantD);
|
||||||
} else if (r.IsTagged()) {
|
} else if (r.IsTagged() || r.IsSmi()) {
|
||||||
return DefineAsRegister(new(zone()) LConstantT);
|
return DefineAsRegister(new(zone()) LConstantT);
|
||||||
} else {
|
} else {
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
|
@ -95,6 +95,7 @@ class LCodeGen;
|
|||||||
V(Deoptimize) \
|
V(Deoptimize) \
|
||||||
V(DivI) \
|
V(DivI) \
|
||||||
V(DoubleToI) \
|
V(DoubleToI) \
|
||||||
|
V(DoubleToSmi) \
|
||||||
V(DummyUse) \
|
V(DummyUse) \
|
||||||
V(ElementsKind) \
|
V(ElementsKind) \
|
||||||
V(FixedArrayBaseLength) \
|
V(FixedArrayBaseLength) \
|
||||||
@ -111,6 +112,7 @@ class LCodeGen;
|
|||||||
V(InstanceSize) \
|
V(InstanceSize) \
|
||||||
V(InstructionGap) \
|
V(InstructionGap) \
|
||||||
V(Integer32ToDouble) \
|
V(Integer32ToDouble) \
|
||||||
|
V(Integer32ToSmi) \
|
||||||
V(Uint32ToDouble) \
|
V(Uint32ToDouble) \
|
||||||
V(InvokeFunction) \
|
V(InvokeFunction) \
|
||||||
V(IsConstructCallAndBranch) \
|
V(IsConstructCallAndBranch) \
|
||||||
@ -1954,6 +1956,19 @@ class LInteger32ToDouble: public LTemplateInstruction<1, 1, 0> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class LInteger32ToSmi: public LTemplateInstruction<1, 1, 0> {
|
||||||
|
public:
|
||||||
|
explicit LInteger32ToSmi(LOperand* value) {
|
||||||
|
inputs_[0] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOperand* value() { return inputs_[0]; }
|
||||||
|
|
||||||
|
DECLARE_CONCRETE_INSTRUCTION(Integer32ToSmi, "int32-to-smi")
|
||||||
|
DECLARE_HYDROGEN_ACCESSOR(Change)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class LUint32ToDouble: public LTemplateInstruction<1, 1, 0> {
|
class LUint32ToDouble: public LTemplateInstruction<1, 1, 0> {
|
||||||
public:
|
public:
|
||||||
explicit LUint32ToDouble(LOperand* value) {
|
explicit LUint32ToDouble(LOperand* value) {
|
||||||
@ -2007,6 +2022,25 @@ class LNumberTagD: public LTemplateInstruction<1, 1, 2> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class LDoubleToSmi: public LTemplateInstruction<1, 1, 2> {
|
||||||
|
public:
|
||||||
|
LDoubleToSmi(LOperand* value, LOperand* temp, LOperand* temp2) {
|
||||||
|
inputs_[0] = value;
|
||||||
|
temps_[0] = temp;
|
||||||
|
temps_[1] = temp2;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOperand* value() { return inputs_[0]; }
|
||||||
|
LOperand* temp() { return temps_[0]; }
|
||||||
|
LOperand* temp2() { return temps_[1]; }
|
||||||
|
|
||||||
|
DECLARE_CONCRETE_INSTRUCTION(DoubleToSmi, "double-to-smi")
|
||||||
|
DECLARE_HYDROGEN_ACCESSOR(UnaryOperation)
|
||||||
|
|
||||||
|
bool truncating() { return hydrogen()->CanTruncateToInt32(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// Sometimes truncating conversion from a tagged value to an int32.
|
// Sometimes truncating conversion from a tagged value to an int32.
|
||||||
class LDoubleToI: public LTemplateInstruction<1, 1, 2> {
|
class LDoubleToI: public LTemplateInstruction<1, 1, 2> {
|
||||||
public:
|
public:
|
||||||
@ -2353,7 +2387,7 @@ class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 2> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class LCheckSmi: public LTemplateInstruction<0, 1, 0> {
|
class LCheckSmi: public LTemplateInstruction<1, 1, 0> {
|
||||||
public:
|
public:
|
||||||
explicit LCheckSmi(LOperand* value) {
|
explicit LCheckSmi(LOperand* value) {
|
||||||
inputs_[0] = value;
|
inputs_[0] = value;
|
||||||
|
@ -518,7 +518,7 @@ DwVfpRegister LCodeGen::EmitLoadDoubleRegister(LOperand* op,
|
|||||||
|
|
||||||
Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
|
Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
|
||||||
HConstant* constant = chunk_->LookupConstant(op);
|
HConstant* constant = chunk_->LookupConstant(op);
|
||||||
ASSERT(chunk_->LookupLiteralRepresentation(op).IsTagged());
|
ASSERT(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
|
||||||
return constant->handle();
|
return constant->handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -528,6 +528,11 @@ bool LCodeGen::IsInteger32(LConstantOperand* op) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LCodeGen::IsSmi(LConstantOperand* op) const {
|
||||||
|
return chunk_->LookupLiteralRepresentation(op).IsSmi();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int LCodeGen::ToInteger32(LConstantOperand* op) const {
|
int LCodeGen::ToInteger32(LConstantOperand* op) const {
|
||||||
HConstant* constant = chunk_->LookupConstant(op);
|
HConstant* constant = chunk_->LookupConstant(op);
|
||||||
return constant->Integer32Value();
|
return constant->Integer32Value();
|
||||||
@ -2207,7 +2212,7 @@ void LCodeGen::DoBranch(LBranch* instr) {
|
|||||||
int false_block = chunk_->LookupDestination(instr->false_block_id());
|
int false_block = chunk_->LookupDestination(instr->false_block_id());
|
||||||
|
|
||||||
Representation r = instr->hydrogen()->value()->representation();
|
Representation r = instr->hydrogen()->value()->representation();
|
||||||
if (r.IsInteger32()) {
|
if (r.IsInteger32() || r.IsSmi()) {
|
||||||
Register reg = ToRegister(instr->value());
|
Register reg = ToRegister(instr->value());
|
||||||
__ cmp(reg, Operand::Zero());
|
__ cmp(reg, Operand::Zero());
|
||||||
EmitBranch(true_block, false_block, ne);
|
EmitBranch(true_block, false_block, ne);
|
||||||
@ -4210,13 +4215,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
|
|||||||
|
|
||||||
Handle<Map> transition = instr->transition();
|
Handle<Map> transition = instr->transition();
|
||||||
|
|
||||||
if (FLAG_track_fields && representation.IsSmi()) {
|
if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
|
||||||
Register value = ToRegister(instr->value());
|
|
||||||
__ SmiTag(value, value, SetCC);
|
|
||||||
if (!instr->hydrogen()->value()->range()->IsInSmiRange()) {
|
|
||||||
DeoptimizeIf(vs, instr->environment());
|
|
||||||
}
|
|
||||||
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
|
|
||||||
Register value = ToRegister(instr->value());
|
Register value = ToRegister(instr->value());
|
||||||
if (!instr->hydrogen()->value()->type().IsHeapObject()) {
|
if (!instr->hydrogen()->value()->type().IsHeapObject()) {
|
||||||
__ SmiTst(value);
|
__ SmiTst(value);
|
||||||
@ -4702,6 +4701,19 @@ void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LCodeGen::DoInteger32ToSmi(LInteger32ToSmi* instr) {
|
||||||
|
LOperand* input = instr->value();
|
||||||
|
ASSERT(input->IsRegister());
|
||||||
|
LOperand* output = instr->result();
|
||||||
|
ASSERT(output->IsRegister());
|
||||||
|
__ SmiTag(ToRegister(output), ToRegister(input), SetCC);
|
||||||
|
if (!instr->hydrogen()->value()->HasRange() ||
|
||||||
|
!instr->hydrogen()->value()->range()->IsInSmiRange()) {
|
||||||
|
DeoptimizeIf(vs, instr->environment());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
|
void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
|
||||||
LOperand* input = instr->value();
|
LOperand* input = instr->value();
|
||||||
LOperand* output = instr->result();
|
LOperand* output = instr->result();
|
||||||
@ -5139,7 +5151,33 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
|
|||||||
DwVfpRegister double_input = ToDoubleRegister(instr->value());
|
DwVfpRegister double_input = ToDoubleRegister(instr->value());
|
||||||
DwVfpRegister double_scratch = double_scratch0();
|
DwVfpRegister double_scratch = double_scratch0();
|
||||||
|
|
||||||
|
if (instr->truncating()) {
|
||||||
|
Register scratch3 = ToRegister(instr->temp2());
|
||||||
|
__ ECMAToInt32(result_reg, double_input,
|
||||||
|
scratch1, scratch2, scratch3, double_scratch);
|
||||||
|
} else {
|
||||||
|
__ TryDoubleToInt32Exact(result_reg, double_input, double_scratch);
|
||||||
|
// Deoptimize if the input wasn't a int32 (inside a double).
|
||||||
|
DeoptimizeIf(ne, instr->environment());
|
||||||
|
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
||||||
Label done;
|
Label done;
|
||||||
|
__ cmp(result_reg, Operand::Zero());
|
||||||
|
__ b(ne, &done);
|
||||||
|
__ vmov(scratch1, double_input.high());
|
||||||
|
__ tst(scratch1, Operand(HeapNumber::kSignMask));
|
||||||
|
DeoptimizeIf(ne, instr->environment());
|
||||||
|
__ bind(&done);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) {
|
||||||
|
Register result_reg = ToRegister(instr->result());
|
||||||
|
Register scratch1 = scratch0();
|
||||||
|
Register scratch2 = ToRegister(instr->temp());
|
||||||
|
DwVfpRegister double_input = ToDoubleRegister(instr->value());
|
||||||
|
DwVfpRegister double_scratch = double_scratch0();
|
||||||
|
|
||||||
if (instr->truncating()) {
|
if (instr->truncating()) {
|
||||||
Register scratch3 = ToRegister(instr->temp2());
|
Register scratch3 = ToRegister(instr->temp2());
|
||||||
@ -5149,8 +5187,18 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
|
|||||||
__ TryDoubleToInt32Exact(result_reg, double_input, double_scratch);
|
__ TryDoubleToInt32Exact(result_reg, double_input, double_scratch);
|
||||||
// Deoptimize if the input wasn't a int32 (inside a double).
|
// Deoptimize if the input wasn't a int32 (inside a double).
|
||||||
DeoptimizeIf(ne, instr->environment());
|
DeoptimizeIf(ne, instr->environment());
|
||||||
}
|
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
||||||
|
Label done;
|
||||||
|
__ cmp(result_reg, Operand::Zero());
|
||||||
|
__ b(ne, &done);
|
||||||
|
__ vmov(scratch1, double_input.high());
|
||||||
|
__ tst(scratch1, Operand(HeapNumber::kSignMask));
|
||||||
|
DeoptimizeIf(ne, instr->environment());
|
||||||
__ bind(&done);
|
__ bind(&done);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__ SmiTag(result_reg, SetCC);
|
||||||
|
DeoptimizeIf(vs, instr->environment());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -126,6 +126,7 @@ class LCodeGen BASE_EMBEDDED {
|
|||||||
MemOperand ToHighMemOperand(LOperand* op) const;
|
MemOperand ToHighMemOperand(LOperand* op) const;
|
||||||
|
|
||||||
bool IsInteger32(LConstantOperand* op) const;
|
bool IsInteger32(LConstantOperand* op) const;
|
||||||
|
bool IsSmi(LConstantOperand* op) const;
|
||||||
Handle<Object> ToHandle(LConstantOperand* op) const;
|
Handle<Object> ToHandle(LConstantOperand* op) const;
|
||||||
|
|
||||||
// Try to generate code for the entire chunk, but it may fail if the
|
// Try to generate code for the entire chunk, but it may fail if the
|
||||||
|
@ -1687,7 +1687,7 @@ Range* HValue::InferRange(Zone* zone) {
|
|||||||
Range* HChange::InferRange(Zone* zone) {
|
Range* HChange::InferRange(Zone* zone) {
|
||||||
Range* input_range = value()->range();
|
Range* input_range = value()->range();
|
||||||
if (from().IsInteger32() &&
|
if (from().IsInteger32() &&
|
||||||
to().IsTagged() &&
|
to().IsSmiOrTagged() &&
|
||||||
!value()->CheckFlag(HInstruction::kUint32) &&
|
!value()->CheckFlag(HInstruction::kUint32) &&
|
||||||
input_range != NULL && input_range->IsInSmiRange()) {
|
input_range != NULL && input_range->IsInSmiRange()) {
|
||||||
set_type(HType::Smi());
|
set_type(HType::Smi());
|
||||||
@ -3563,7 +3563,7 @@ Representation HPhi::RepresentationFromInputs() {
|
|||||||
HPhi* hint_value = HUnknownOSRValue::cast(value)->incoming_value();
|
HPhi* hint_value = HUnknownOSRValue::cast(value)->incoming_value();
|
||||||
if (hint_value != NULL) {
|
if (hint_value != NULL) {
|
||||||
Representation hint = hint_value->representation();
|
Representation hint = hint_value->representation();
|
||||||
if (hint.IsTagged()) return hint;
|
if (hint.IsSmiOrTagged()) return hint;
|
||||||
if (hint.IsDouble()) double_occurred = true;
|
if (hint.IsDouble()) double_occurred = true;
|
||||||
if (hint.IsInteger32()) int32_occurred = true;
|
if (hint.IsInteger32()) int32_occurred = true;
|
||||||
}
|
}
|
||||||
@ -3571,7 +3571,7 @@ Representation HPhi::RepresentationFromInputs() {
|
|||||||
}
|
}
|
||||||
if (value->representation().IsDouble()) double_occurred = true;
|
if (value->representation().IsDouble()) double_occurred = true;
|
||||||
if (value->representation().IsInteger32()) int32_occurred = true;
|
if (value->representation().IsInteger32()) int32_occurred = true;
|
||||||
if (value->representation().IsTagged()) {
|
if (value->representation().IsSmiOrTagged()) {
|
||||||
if (value->IsConstant()) {
|
if (value->IsConstant()) {
|
||||||
HConstant* constant = HConstant::cast(value);
|
HConstant* constant = HConstant::cast(value);
|
||||||
if (constant->IsConvertibleToInteger()) {
|
if (constant->IsConvertibleToInteger()) {
|
||||||
|
@ -5209,7 +5209,7 @@ class HLoadNamedField: public HTemplateInstruction<2> {
|
|||||||
|
|
||||||
if (FLAG_track_fields && field_representation.IsSmi()) {
|
if (FLAG_track_fields && field_representation.IsSmi()) {
|
||||||
set_type(HType::Smi());
|
set_type(HType::Smi());
|
||||||
set_representation(Representation::Tagged());
|
set_representation(field_representation);
|
||||||
} else if (FLAG_track_double_fields && field_representation.IsDouble()) {
|
} else if (FLAG_track_double_fields && field_representation.IsDouble()) {
|
||||||
set_representation(field_representation);
|
set_representation(field_representation);
|
||||||
} else if (FLAG_track_heap_object_fields &&
|
} else if (FLAG_track_heap_object_fields &&
|
||||||
@ -5604,7 +5604,7 @@ class HStoreNamedField: public HTemplateInstruction<2> {
|
|||||||
return field_representation_;
|
return field_representation_;
|
||||||
} else if (FLAG_track_fields &&
|
} else if (FLAG_track_fields &&
|
||||||
index == 1 && field_representation_.IsSmi()) {
|
index == 1 && field_representation_.IsSmi()) {
|
||||||
return Representation::Integer32();
|
return field_representation_;
|
||||||
}
|
}
|
||||||
return Representation::Tagged();
|
return Representation::Tagged();
|
||||||
}
|
}
|
||||||
|
@ -4399,7 +4399,9 @@ void HGraph::ComputeMinusZeroChecks() {
|
|||||||
Representation from = change->value()->representation();
|
Representation from = change->value()->representation();
|
||||||
ASSERT(from.Equals(change->from()));
|
ASSERT(from.Equals(change->from()));
|
||||||
if (from.IsInteger32()) {
|
if (from.IsInteger32()) {
|
||||||
ASSERT(change->to().IsTagged() || change->to().IsDouble());
|
ASSERT(change->to().IsTagged() ||
|
||||||
|
change->to().IsDouble() ||
|
||||||
|
change->to().IsSmi());
|
||||||
ASSERT(visited.IsEmpty());
|
ASSERT(visited.IsEmpty());
|
||||||
PropagateMinusZeroChecks(change->value(), &visited);
|
PropagateMinusZeroChecks(change->value(), &visited);
|
||||||
visited.Clear();
|
visited.Clear();
|
||||||
|
@ -590,7 +590,7 @@ int LCodeGen::ToInteger32(LConstantOperand* op) const {
|
|||||||
|
|
||||||
Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
|
Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
|
||||||
HConstant* constant = chunk_->LookupConstant(op);
|
HConstant* constant = chunk_->LookupConstant(op);
|
||||||
ASSERT(chunk_->LookupLiteralRepresentation(op).IsTagged());
|
ASSERT(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
|
||||||
return constant->handle();
|
return constant->handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -607,6 +607,11 @@ bool LCodeGen::IsInteger32(LConstantOperand* op) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LCodeGen::IsSmi(LConstantOperand* op) const {
|
||||||
|
return chunk_->LookupLiteralRepresentation(op).IsSmi();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Operand LCodeGen::ToOperand(LOperand* op) const {
|
Operand LCodeGen::ToOperand(LOperand* op) const {
|
||||||
if (op->IsRegister()) return Operand(ToRegister(op));
|
if (op->IsRegister()) return Operand(ToRegister(op));
|
||||||
if (op->IsDoubleRegister()) return Operand(ToDoubleRegister(op));
|
if (op->IsDoubleRegister()) return Operand(ToDoubleRegister(op));
|
||||||
@ -2101,7 +2106,7 @@ void LCodeGen::DoBranch(LBranch* instr) {
|
|||||||
CpuFeatureScope scope(masm(), SSE2);
|
CpuFeatureScope scope(masm(), SSE2);
|
||||||
|
|
||||||
Representation r = instr->hydrogen()->value()->representation();
|
Representation r = instr->hydrogen()->value()->representation();
|
||||||
if (r.IsInteger32()) {
|
if (r.IsInteger32() || r.IsSmi()) {
|
||||||
Register reg = ToRegister(instr->value());
|
Register reg = ToRegister(instr->value());
|
||||||
__ test(reg, Operand(reg));
|
__ test(reg, Operand(reg));
|
||||||
EmitBranch(true_block, false_block, not_zero);
|
EmitBranch(true_block, false_block, not_zero);
|
||||||
@ -4220,15 +4225,9 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
|
|||||||
if (FLAG_track_fields && representation.IsSmi()) {
|
if (FLAG_track_fields && representation.IsSmi()) {
|
||||||
if (instr->value()->IsConstantOperand()) {
|
if (instr->value()->IsConstantOperand()) {
|
||||||
LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
|
LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
|
||||||
if (!IsInteger32(operand_value)) {
|
if (!IsSmi(operand_value)) {
|
||||||
DeoptimizeIf(no_condition, instr->environment());
|
DeoptimizeIf(no_condition, instr->environment());
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Register value = ToRegister(instr->value());
|
|
||||||
__ SmiTag(value);
|
|
||||||
if (!instr->hydrogen()->value()->range()->IsInSmiRange()) {
|
|
||||||
DeoptimizeIf(overflow, instr->environment());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
|
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
|
||||||
if (instr->value()->IsConstantOperand()) {
|
if (instr->value()->IsConstantOperand()) {
|
||||||
@ -4293,12 +4292,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
|
|||||||
|
|
||||||
if (instr->value()->IsConstantOperand()) {
|
if (instr->value()->IsConstantOperand()) {
|
||||||
LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
|
LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
|
||||||
if (IsInteger32(operand_value)) {
|
if (operand_value->IsRegister()) {
|
||||||
// In lithium register preparation, we made sure that the constant integer
|
|
||||||
// operand fits into smi range.
|
|
||||||
Smi* smi_value = Smi::FromInt(ToInteger32(operand_value));
|
|
||||||
__ mov(FieldOperand(write_register, offset), Immediate(smi_value));
|
|
||||||
} else if (operand_value->IsRegister()) {
|
|
||||||
__ mov(FieldOperand(write_register, offset), ToRegister(operand_value));
|
__ mov(FieldOperand(write_register, offset), ToRegister(operand_value));
|
||||||
} else {
|
} else {
|
||||||
Handle<Object> handle_value = ToHandle(operand_value);
|
Handle<Object> handle_value = ToHandle(operand_value);
|
||||||
@ -4769,6 +4763,16 @@ void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LCodeGen::DoInteger32ToSmi(LInteger32ToSmi* instr) {
|
||||||
|
Register input = ToRegister(instr->value());
|
||||||
|
__ SmiTag(input);
|
||||||
|
if (!instr->hydrogen()->value()->HasRange() ||
|
||||||
|
!instr->hydrogen()->value()->range()->IsInSmiRange()) {
|
||||||
|
DeoptimizeIf(overflow, instr->environment());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
|
void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
|
||||||
CpuFeatureScope scope(masm(), SSE2);
|
CpuFeatureScope scope(masm(), SSE2);
|
||||||
LOperand* input = instr->value();
|
LOperand* input = instr->value();
|
||||||
@ -5637,6 +5641,41 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) {
|
||||||
|
LOperand* input = instr->value();
|
||||||
|
ASSERT(input->IsDoubleRegister());
|
||||||
|
LOperand* result = instr->result();
|
||||||
|
ASSERT(result->IsRegister());
|
||||||
|
CpuFeatureScope scope(masm(), SSE2);
|
||||||
|
|
||||||
|
XMMRegister input_reg = ToDoubleRegister(input);
|
||||||
|
Register result_reg = ToRegister(result);
|
||||||
|
|
||||||
|
Label done;
|
||||||
|
__ cvttsd2si(result_reg, Operand(input_reg));
|
||||||
|
__ cvtsi2sd(xmm0, Operand(result_reg));
|
||||||
|
__ ucomisd(xmm0, input_reg);
|
||||||
|
DeoptimizeIf(not_equal, instr->environment());
|
||||||
|
DeoptimizeIf(parity_even, instr->environment()); // NaN.
|
||||||
|
|
||||||
|
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
||||||
|
// The integer converted back is equal to the original. We
|
||||||
|
// only have to test if we got -0 as an input.
|
||||||
|
__ test(result_reg, Operand(result_reg));
|
||||||
|
__ j(not_zero, &done, Label::kNear);
|
||||||
|
__ movmskpd(result_reg, input_reg);
|
||||||
|
// Bit 0 contains the sign of the double in input_reg.
|
||||||
|
// If input was positive, we are ok and return 0, otherwise
|
||||||
|
// deoptimize.
|
||||||
|
__ and_(result_reg, 1);
|
||||||
|
DeoptimizeIf(not_zero, instr->environment());
|
||||||
|
__ bind(&done);
|
||||||
|
}
|
||||||
|
__ SmiTag(result_reg);
|
||||||
|
DeoptimizeIf(overflow, instr->environment());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
|
void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
|
||||||
LOperand* input = instr->value();
|
LOperand* input = instr->value();
|
||||||
__ test(ToOperand(input), Immediate(kSmiTagMask));
|
__ test(ToOperand(input), Immediate(kSmiTagMask));
|
||||||
|
@ -111,6 +111,7 @@ class LCodeGen BASE_EMBEDDED {
|
|||||||
bool IsX87TopOfStack(LOperand* op) const;
|
bool IsX87TopOfStack(LOperand* op) const;
|
||||||
|
|
||||||
bool IsInteger32(LConstantOperand* op) const;
|
bool IsInteger32(LConstantOperand* op) const;
|
||||||
|
bool IsSmi(LConstantOperand* op) const;
|
||||||
Immediate ToInteger32Immediate(LOperand* op) const {
|
Immediate ToInteger32Immediate(LOperand* op) const {
|
||||||
return Immediate(ToInteger32(LConstantOperand::cast(op)));
|
return Immediate(ToInteger32(LConstantOperand::cast(op)));
|
||||||
}
|
}
|
||||||
|
@ -1908,6 +1908,13 @@ LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) {
|
|||||||
LInstruction* LChunkBuilder::DoChange(HChange* instr) {
|
LInstruction* LChunkBuilder::DoChange(HChange* instr) {
|
||||||
Representation from = instr->from();
|
Representation from = instr->from();
|
||||||
Representation to = instr->to();
|
Representation to = instr->to();
|
||||||
|
if (from.IsSmi()) {
|
||||||
|
if (to.IsTagged()) {
|
||||||
|
LOperand* value = UseRegister(instr->value());
|
||||||
|
return DefineSameAsFirst(new(zone()) LDummyUse(value));
|
||||||
|
}
|
||||||
|
from = Representation::Tagged();
|
||||||
|
}
|
||||||
// Only mark conversions that might need to allocate as calling rather than
|
// Only mark conversions that might need to allocate as calling rather than
|
||||||
// all changes. This makes simple, non-allocating conversion not have to force
|
// all changes. This makes simple, non-allocating conversion not have to force
|
||||||
// building a stack frame.
|
// building a stack frame.
|
||||||
@ -1925,6 +1932,11 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
|
|||||||
} else {
|
} else {
|
||||||
return AssignEnvironment(DefineX87TOS(res));
|
return AssignEnvironment(DefineX87TOS(res));
|
||||||
}
|
}
|
||||||
|
} else if (to.IsSmi()) {
|
||||||
|
HValue* val = instr->value();
|
||||||
|
LOperand* value = UseRegisterAtStart(val);
|
||||||
|
return AssignEnvironment(
|
||||||
|
DefineSameAsFirst(new(zone()) LCheckSmi(value)));
|
||||||
} else {
|
} else {
|
||||||
ASSERT(to.IsInteger32());
|
ASSERT(to.IsInteger32());
|
||||||
if (instr->value()->type().IsSmi()) {
|
if (instr->value()->type().IsSmi()) {
|
||||||
@ -1970,6 +1982,10 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
|
|||||||
LUnallocated* result_temp = TempRegister();
|
LUnallocated* result_temp = TempRegister();
|
||||||
LNumberTagD* result = new(zone()) LNumberTagD(value, temp);
|
LNumberTagD* result = new(zone()) LNumberTagD(value, temp);
|
||||||
return AssignPointerMap(Define(result, result_temp));
|
return AssignPointerMap(Define(result, result_temp));
|
||||||
|
} else if (to.IsSmi()) {
|
||||||
|
LOperand* value = UseRegister(instr->value());
|
||||||
|
return AssignEnvironment(
|
||||||
|
DefineAsRegister(new(zone()) LDoubleToSmi(value)));
|
||||||
} else {
|
} else {
|
||||||
ASSERT(to.IsInteger32());
|
ASSERT(to.IsInteger32());
|
||||||
bool truncating = instr->CanTruncateToInt32();
|
bool truncating = instr->CanTruncateToInt32();
|
||||||
@ -1994,6 +2010,15 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
|
|||||||
LNumberTagI* result = new(zone()) LNumberTagI(value);
|
LNumberTagI* result = new(zone()) LNumberTagI(value);
|
||||||
return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
|
return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
|
||||||
}
|
}
|
||||||
|
} else if (to.IsSmi()) {
|
||||||
|
HValue* val = instr->value();
|
||||||
|
LOperand* value = UseRegister(val);
|
||||||
|
LInstruction* result =
|
||||||
|
DefineSameAsFirst(new(zone()) LInteger32ToSmi(value));
|
||||||
|
if (val->HasRange() && val->range()->IsInSmiRange()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return AssignEnvironment(result);
|
||||||
} else {
|
} else {
|
||||||
ASSERT(to.IsDouble());
|
ASSERT(to.IsDouble());
|
||||||
if (instr->value()->CheckFlag(HInstruction::kUint32)) {
|
if (instr->value()->CheckFlag(HInstruction::kUint32)) {
|
||||||
@ -2034,13 +2059,13 @@ LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
|
|||||||
|
|
||||||
LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
|
LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
|
||||||
LOperand* value = UseAtStart(instr->value());
|
LOperand* value = UseAtStart(instr->value());
|
||||||
return AssignEnvironment(new(zone()) LCheckSmi(value));
|
return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LInstruction* LChunkBuilder::DoCheckSmiOrInt32(HCheckSmiOrInt32* instr) {
|
LInstruction* LChunkBuilder::DoCheckSmiOrInt32(HCheckSmiOrInt32* instr) {
|
||||||
LOperand* value = UseAtStart(instr->value());
|
LOperand* value = UseAtStart(instr->value());
|
||||||
return AssignEnvironment(new(zone()) LCheckSmi(value));
|
return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -90,6 +90,7 @@ class LCodeGen;
|
|||||||
V(Deoptimize) \
|
V(Deoptimize) \
|
||||||
V(DivI) \
|
V(DivI) \
|
||||||
V(DoubleToI) \
|
V(DoubleToI) \
|
||||||
|
V(DoubleToSmi) \
|
||||||
V(DummyUse) \
|
V(DummyUse) \
|
||||||
V(ElementsKind) \
|
V(ElementsKind) \
|
||||||
V(FixedArrayBaseLength) \
|
V(FixedArrayBaseLength) \
|
||||||
@ -106,6 +107,7 @@ class LCodeGen;
|
|||||||
V(InstanceSize) \
|
V(InstanceSize) \
|
||||||
V(InstructionGap) \
|
V(InstructionGap) \
|
||||||
V(Integer32ToDouble) \
|
V(Integer32ToDouble) \
|
||||||
|
V(Integer32ToSmi) \
|
||||||
V(Uint32ToDouble) \
|
V(Uint32ToDouble) \
|
||||||
V(InvokeFunction) \
|
V(InvokeFunction) \
|
||||||
V(IsConstructCallAndBranch) \
|
V(IsConstructCallAndBranch) \
|
||||||
@ -1998,6 +2000,19 @@ class LInteger32ToDouble: public LTemplateInstruction<1, 1, 0> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class LInteger32ToSmi: public LTemplateInstruction<1, 1, 0> {
|
||||||
|
public:
|
||||||
|
explicit LInteger32ToSmi(LOperand* value) {
|
||||||
|
inputs_[0] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOperand* value() { return inputs_[0]; }
|
||||||
|
|
||||||
|
DECLARE_CONCRETE_INSTRUCTION(Integer32ToSmi, "int32-to-smi")
|
||||||
|
DECLARE_HYDROGEN_ACCESSOR(Change)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class LUint32ToDouble: public LTemplateInstruction<1, 1, 1> {
|
class LUint32ToDouble: public LTemplateInstruction<1, 1, 1> {
|
||||||
public:
|
public:
|
||||||
explicit LUint32ToDouble(LOperand* value, LOperand* temp) {
|
explicit LUint32ToDouble(LOperand* value, LOperand* temp) {
|
||||||
@ -2069,6 +2084,19 @@ class LDoubleToI: public LTemplateInstruction<1, 1, 1> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class LDoubleToSmi: public LTemplateInstruction<1, 1, 0> {
|
||||||
|
public:
|
||||||
|
explicit LDoubleToSmi(LOperand* value) {
|
||||||
|
inputs_[0] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOperand* value() { return inputs_[0]; }
|
||||||
|
|
||||||
|
DECLARE_CONCRETE_INSTRUCTION(DoubleToSmi, "double-to-smi")
|
||||||
|
DECLARE_HYDROGEN_ACCESSOR(UnaryOperation)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// Truncating conversion from a tagged value to an int32.
|
// Truncating conversion from a tagged value to an int32.
|
||||||
class LTaggedToI: public LTemplateInstruction<1, 1, 1> {
|
class LTaggedToI: public LTemplateInstruction<1, 1, 1> {
|
||||||
public:
|
public:
|
||||||
@ -2433,7 +2461,7 @@ class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 1> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class LCheckSmi: public LTemplateInstruction<0, 1, 0> {
|
class LCheckSmi: public LTemplateInstruction<1, 1, 0> {
|
||||||
public:
|
public:
|
||||||
explicit LCheckSmi(LOperand* value) {
|
explicit LCheckSmi(LOperand* value) {
|
||||||
inputs_[0] = value;
|
inputs_[0] = value;
|
||||||
|
@ -1057,7 +1057,7 @@ void LAllocator::ResolvePhis(HBasicBlock* block) {
|
|||||||
LInstruction* branch =
|
LInstruction* branch =
|
||||||
InstructionAt(cur_block->last_instruction_index());
|
InstructionAt(cur_block->last_instruction_index());
|
||||||
if (branch->HasPointerMap()) {
|
if (branch->HasPointerMap()) {
|
||||||
if (phi->representation().IsTagged()) {
|
if (phi->representation().IsSmiOrTagged()) {
|
||||||
branch->pointer_map()->RecordPointer(phi_operand, zone());
|
branch->pointer_map()->RecordPointer(phi_operand, zone());
|
||||||
} else if (!phi->representation().IsDouble()) {
|
} else if (!phi->representation().IsDouble()) {
|
||||||
branch->pointer_map()->RecordUntagged(phi_operand, zone());
|
branch->pointer_map()->RecordUntagged(phi_operand, zone());
|
||||||
@ -1640,7 +1640,7 @@ void LAllocator::TraceAlloc(const char* msg, ...) {
|
|||||||
bool LAllocator::HasTaggedValue(int virtual_register) const {
|
bool LAllocator::HasTaggedValue(int virtual_register) const {
|
||||||
HValue* value = graph_->LookupValue(virtual_register);
|
HValue* value = graph_->LookupValue(virtual_register);
|
||||||
if (value == NULL) return false;
|
if (value == NULL) return false;
|
||||||
return value->representation().IsTagged();
|
return value->representation().IsSmiOrTagged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -558,7 +558,7 @@ class LEnvironment: public ZoneObject {
|
|||||||
Representation representation,
|
Representation representation,
|
||||||
bool is_uint32) {
|
bool is_uint32) {
|
||||||
values_.Add(operand, zone());
|
values_.Add(operand, zone());
|
||||||
if (representation.IsTagged()) {
|
if (representation.IsSmiOrTagged()) {
|
||||||
ASSERT(!is_uint32);
|
ASSERT(!is_uint32);
|
||||||
is_tagged_.Add(values_.length() - 1);
|
is_tagged_.Add(values_.length() - 1);
|
||||||
}
|
}
|
||||||
|
@ -131,6 +131,7 @@ class Representation {
|
|||||||
bool IsNone() const { return kind_ == kNone; }
|
bool IsNone() const { return kind_ == kNone; }
|
||||||
bool IsTagged() const { return kind_ == kTagged; }
|
bool IsTagged() const { return kind_ == kTagged; }
|
||||||
bool IsSmi() const { return kind_ == kSmi; }
|
bool IsSmi() const { return kind_ == kSmi; }
|
||||||
|
bool IsSmiOrTagged() const { return IsSmi() || IsTagged(); }
|
||||||
bool IsInteger32() const { return kind_ == kInteger32; }
|
bool IsInteger32() const { return kind_ == kInteger32; }
|
||||||
bool IsDouble() const { return kind_ == kDouble; }
|
bool IsDouble() const { return kind_ == kDouble; }
|
||||||
bool IsHeapObject() const { return kind_ == kHeapObject; }
|
bool IsHeapObject() const { return kind_ == kHeapObject; }
|
||||||
|
@ -435,6 +435,12 @@ bool LCodeGen::IsInteger32Constant(LConstantOperand* op) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LCodeGen::IsSmiConstant(LConstantOperand* op) const {
|
||||||
|
return op->IsConstantOperand() &&
|
||||||
|
chunk_->LookupLiteralRepresentation(op).IsSmi();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool LCodeGen::IsTaggedConstant(LConstantOperand* op) const {
|
bool LCodeGen::IsTaggedConstant(LConstantOperand* op) const {
|
||||||
return op->IsConstantOperand() &&
|
return op->IsConstantOperand() &&
|
||||||
chunk_->LookupLiteralRepresentation(op).IsTagged();
|
chunk_->LookupLiteralRepresentation(op).IsTagged();
|
||||||
@ -456,7 +462,7 @@ double LCodeGen::ToDouble(LConstantOperand* op) const {
|
|||||||
|
|
||||||
Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
|
Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
|
||||||
HConstant* constant = chunk_->LookupConstant(op);
|
HConstant* constant = chunk_->LookupConstant(op);
|
||||||
ASSERT(chunk_->LookupLiteralRepresentation(op).IsTagged());
|
ASSERT(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
|
||||||
return constant->handle();
|
return constant->handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1877,6 +1883,10 @@ void LCodeGen::DoBranch(LBranch* instr) {
|
|||||||
Register reg = ToRegister(instr->value());
|
Register reg = ToRegister(instr->value());
|
||||||
__ testl(reg, reg);
|
__ testl(reg, reg);
|
||||||
EmitBranch(true_block, false_block, not_zero);
|
EmitBranch(true_block, false_block, not_zero);
|
||||||
|
} else if (r.IsSmi()) {
|
||||||
|
Register reg = ToRegister(instr->value());
|
||||||
|
__ testq(reg, reg);
|
||||||
|
EmitBranch(true_block, false_block, not_zero);
|
||||||
} else if (r.IsDouble()) {
|
} else if (r.IsDouble()) {
|
||||||
XMMRegister reg = ToDoubleRegister(instr->value());
|
XMMRegister reg = ToDoubleRegister(instr->value());
|
||||||
__ xorps(xmm0, xmm0);
|
__ xorps(xmm0, xmm0);
|
||||||
@ -3905,12 +3915,9 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
|
|||||||
if (FLAG_track_fields && representation.IsSmi()) {
|
if (FLAG_track_fields && representation.IsSmi()) {
|
||||||
if (instr->value()->IsConstantOperand()) {
|
if (instr->value()->IsConstantOperand()) {
|
||||||
LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
|
LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
|
||||||
if (!IsInteger32Constant(operand_value)) {
|
if (!IsSmiConstant(operand_value)) {
|
||||||
DeoptimizeIf(no_condition, instr->environment());
|
DeoptimizeIf(no_condition, instr->environment());
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Register value = ToRegister(instr->value());
|
|
||||||
__ Integer32ToSmi(value, value);
|
|
||||||
}
|
}
|
||||||
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
|
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
|
||||||
if (instr->value()->IsConstantOperand()) {
|
if (instr->value()->IsConstantOperand()) {
|
||||||
@ -3968,12 +3975,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
|
|||||||
|
|
||||||
if (instr->value()->IsConstantOperand()) {
|
if (instr->value()->IsConstantOperand()) {
|
||||||
LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
|
LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
|
||||||
if (IsInteger32Constant(operand_value)) {
|
if (operand_value->IsRegister()) {
|
||||||
// In lithium register preparation, we made sure that the constant integer
|
|
||||||
// operand fits into smi range.
|
|
||||||
Smi* smi_value = Smi::FromInt(ToInteger32(operand_value));
|
|
||||||
__ Move(FieldOperand(write_register, offset), smi_value);
|
|
||||||
} else if (operand_value->IsRegister()) {
|
|
||||||
__ movq(FieldOperand(write_register, offset),
|
__ movq(FieldOperand(write_register, offset),
|
||||||
ToRegister(operand_value));
|
ToRegister(operand_value));
|
||||||
} else {
|
} else {
|
||||||
@ -4434,6 +4436,18 @@ void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LCodeGen::DoInteger32ToSmi(LInteger32ToSmi* instr) {
|
||||||
|
LOperand* input = instr->value();
|
||||||
|
ASSERT(input->IsRegister());
|
||||||
|
LOperand* output = instr->result();
|
||||||
|
__ Integer32ToSmi(ToRegister(output), ToRegister(input));
|
||||||
|
if (!instr->hydrogen()->value()->HasRange() ||
|
||||||
|
!instr->hydrogen()->value()->range()->IsInSmiRange()) {
|
||||||
|
DeoptimizeIf(overflow, instr->environment());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
|
void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
|
||||||
LOperand* input = instr->value();
|
LOperand* input = instr->value();
|
||||||
LOperand* output = instr->result();
|
LOperand* output = instr->result();
|
||||||
@ -4841,6 +4855,41 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) {
|
||||||
|
LOperand* input = instr->value();
|
||||||
|
ASSERT(input->IsDoubleRegister());
|
||||||
|
LOperand* result = instr->result();
|
||||||
|
ASSERT(result->IsRegister());
|
||||||
|
CpuFeatureScope scope(masm(), SSE2);
|
||||||
|
|
||||||
|
XMMRegister input_reg = ToDoubleRegister(input);
|
||||||
|
Register result_reg = ToRegister(result);
|
||||||
|
|
||||||
|
Label done;
|
||||||
|
__ cvttsd2si(result_reg, input_reg);
|
||||||
|
__ cvtlsi2sd(xmm0, result_reg);
|
||||||
|
__ ucomisd(xmm0, input_reg);
|
||||||
|
DeoptimizeIf(not_equal, instr->environment());
|
||||||
|
DeoptimizeIf(parity_even, instr->environment()); // NaN.
|
||||||
|
|
||||||
|
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
||||||
|
// The integer converted back is equal to the original. We
|
||||||
|
// only have to test if we got -0 as an input.
|
||||||
|
__ testl(result_reg, result_reg);
|
||||||
|
__ j(not_zero, &done, Label::kNear);
|
||||||
|
__ movmskpd(result_reg, input_reg);
|
||||||
|
// Bit 0 contains the sign of the double in input_reg.
|
||||||
|
// If input was positive, we are ok and return 0, otherwise
|
||||||
|
// deoptimize.
|
||||||
|
__ andl(result_reg, Immediate(1));
|
||||||
|
DeoptimizeIf(not_zero, instr->environment());
|
||||||
|
__ bind(&done);
|
||||||
|
}
|
||||||
|
__ Integer32ToSmi(result_reg, result_reg);
|
||||||
|
DeoptimizeIf(overflow, instr->environment());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
|
void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
|
||||||
LOperand* input = instr->value();
|
LOperand* input = instr->value();
|
||||||
Condition cc = masm()->CheckSmi(ToRegister(input));
|
Condition cc = masm()->CheckSmi(ToRegister(input));
|
||||||
|
@ -104,6 +104,7 @@ class LCodeGen BASE_EMBEDDED {
|
|||||||
Register ToRegister(LOperand* op) const;
|
Register ToRegister(LOperand* op) const;
|
||||||
XMMRegister ToDoubleRegister(LOperand* op) const;
|
XMMRegister ToDoubleRegister(LOperand* op) const;
|
||||||
bool IsInteger32Constant(LConstantOperand* op) const;
|
bool IsInteger32Constant(LConstantOperand* op) const;
|
||||||
|
bool IsSmiConstant(LConstantOperand* op) const;
|
||||||
int ToInteger32(LConstantOperand* op) const;
|
int ToInteger32(LConstantOperand* op) const;
|
||||||
double ToDouble(LConstantOperand* op) const;
|
double ToDouble(LConstantOperand* op) const;
|
||||||
bool IsTaggedConstant(LConstantOperand* op) const;
|
bool IsTaggedConstant(LConstantOperand* op) const;
|
||||||
|
@ -1812,6 +1812,13 @@ LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) {
|
|||||||
LInstruction* LChunkBuilder::DoChange(HChange* instr) {
|
LInstruction* LChunkBuilder::DoChange(HChange* instr) {
|
||||||
Representation from = instr->from();
|
Representation from = instr->from();
|
||||||
Representation to = instr->to();
|
Representation to = instr->to();
|
||||||
|
if (from.IsSmi()) {
|
||||||
|
if (to.IsTagged()) {
|
||||||
|
LOperand* value = UseRegister(instr->value());
|
||||||
|
return DefineSameAsFirst(new(zone()) LDummyUse(value));
|
||||||
|
}
|
||||||
|
from = Representation::Tagged();
|
||||||
|
}
|
||||||
// Only mark conversions that might need to allocate as calling rather than
|
// Only mark conversions that might need to allocate as calling rather than
|
||||||
// all changes. This makes simple, non-allocating conversion not have to force
|
// all changes. This makes simple, non-allocating conversion not have to force
|
||||||
// building a stack frame.
|
// building a stack frame.
|
||||||
@ -1821,6 +1828,11 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
|
|||||||
LOperand* value = UseRegister(instr->value());
|
LOperand* value = UseRegister(instr->value());
|
||||||
LNumberUntagD* res = new(zone()) LNumberUntagD(value);
|
LNumberUntagD* res = new(zone()) LNumberUntagD(value);
|
||||||
return AssignEnvironment(DefineAsRegister(res));
|
return AssignEnvironment(DefineAsRegister(res));
|
||||||
|
} else if (to.IsSmi()) {
|
||||||
|
HValue* val = instr->value();
|
||||||
|
LOperand* value = UseRegisterAtStart(val);
|
||||||
|
return AssignEnvironment(
|
||||||
|
DefineSameAsFirst(new(zone()) LCheckSmi(value)));
|
||||||
} else {
|
} else {
|
||||||
ASSERT(to.IsInteger32());
|
ASSERT(to.IsInteger32());
|
||||||
LOperand* value = UseRegister(instr->value());
|
LOperand* value = UseRegister(instr->value());
|
||||||
@ -1852,10 +1864,15 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
|
|||||||
LUnallocated* result_temp = TempRegister();
|
LUnallocated* result_temp = TempRegister();
|
||||||
LNumberTagD* result = new(zone()) LNumberTagD(value, temp);
|
LNumberTagD* result = new(zone()) LNumberTagD(value, temp);
|
||||||
return AssignPointerMap(Define(result, result_temp));
|
return AssignPointerMap(Define(result, result_temp));
|
||||||
|
} else if (to.IsSmi()) {
|
||||||
|
LOperand* value = UseRegister(instr->value());
|
||||||
|
return AssignEnvironment(
|
||||||
|
DefineAsRegister(new(zone()) LDoubleToSmi(value)));
|
||||||
} else {
|
} else {
|
||||||
ASSERT(to.IsInteger32());
|
ASSERT(to.IsInteger32());
|
||||||
LOperand* value = UseRegister(instr->value());
|
LOperand* value = UseRegister(instr->value());
|
||||||
return AssignEnvironment(DefineAsRegister(new(zone()) LDoubleToI(value)));
|
return AssignEnvironment(
|
||||||
|
DefineAsRegister(new(zone()) LDoubleToI(value)));
|
||||||
}
|
}
|
||||||
} else if (from.IsInteger32()) {
|
} else if (from.IsInteger32()) {
|
||||||
info()->MarkAsDeferredCalling();
|
info()->MarkAsDeferredCalling();
|
||||||
@ -1872,6 +1889,15 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
|
|||||||
LNumberTagI* result = new(zone()) LNumberTagI(value);
|
LNumberTagI* result = new(zone()) LNumberTagI(value);
|
||||||
return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
|
return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
|
||||||
}
|
}
|
||||||
|
} else if (to.IsSmi()) {
|
||||||
|
HValue* val = instr->value();
|
||||||
|
LOperand* value = UseRegister(val);
|
||||||
|
LInstruction* result =
|
||||||
|
DefineAsRegister(new(zone()) LInteger32ToSmi(value));
|
||||||
|
if (val->HasRange() && val->range()->IsInSmiRange()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return AssignEnvironment(result);
|
||||||
} else {
|
} else {
|
||||||
if (instr->value()->CheckFlag(HInstruction::kUint32)) {
|
if (instr->value()->CheckFlag(HInstruction::kUint32)) {
|
||||||
LOperand* temp = FixedTemp(xmm1);
|
LOperand* temp = FixedTemp(xmm1);
|
||||||
@ -1911,13 +1937,13 @@ LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
|
|||||||
|
|
||||||
LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
|
LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
|
||||||
LOperand* value = UseRegisterAtStart(instr->value());
|
LOperand* value = UseRegisterAtStart(instr->value());
|
||||||
return AssignEnvironment(new(zone()) LCheckSmi(value));
|
return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LInstruction* LChunkBuilder::DoCheckSmiOrInt32(HCheckSmiOrInt32* instr) {
|
LInstruction* LChunkBuilder::DoCheckSmiOrInt32(HCheckSmiOrInt32* instr) {
|
||||||
LOperand* value = UseRegisterAtStart(instr->value());
|
LOperand* value = UseRegisterAtStart(instr->value());
|
||||||
return AssignEnvironment(new(zone()) LCheckSmi(value));
|
return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -95,6 +95,7 @@ class LCodeGen;
|
|||||||
V(Deoptimize) \
|
V(Deoptimize) \
|
||||||
V(DivI) \
|
V(DivI) \
|
||||||
V(DoubleToI) \
|
V(DoubleToI) \
|
||||||
|
V(DoubleToSmi) \
|
||||||
V(DummyUse) \
|
V(DummyUse) \
|
||||||
V(ElementsKind) \
|
V(ElementsKind) \
|
||||||
V(FixedArrayBaseLength) \
|
V(FixedArrayBaseLength) \
|
||||||
@ -112,6 +113,7 @@ class LCodeGen;
|
|||||||
V(InstanceSize) \
|
V(InstanceSize) \
|
||||||
V(InstructionGap) \
|
V(InstructionGap) \
|
||||||
V(Integer32ToDouble) \
|
V(Integer32ToDouble) \
|
||||||
|
V(Integer32ToSmi) \
|
||||||
V(Uint32ToDouble) \
|
V(Uint32ToDouble) \
|
||||||
V(InvokeFunction) \
|
V(InvokeFunction) \
|
||||||
V(IsConstructCallAndBranch) \
|
V(IsConstructCallAndBranch) \
|
||||||
@ -1887,6 +1889,19 @@ class LInteger32ToDouble: public LTemplateInstruction<1, 1, 0> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class LInteger32ToSmi: public LTemplateInstruction<1, 1, 0> {
|
||||||
|
public:
|
||||||
|
explicit LInteger32ToSmi(LOperand* value) {
|
||||||
|
inputs_[0] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOperand* value() { return inputs_[0]; }
|
||||||
|
|
||||||
|
DECLARE_CONCRETE_INSTRUCTION(Integer32ToSmi, "int32-to-smi")
|
||||||
|
DECLARE_HYDROGEN_ACCESSOR(Change)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class LUint32ToDouble: public LTemplateInstruction<1, 1, 1> {
|
class LUint32ToDouble: public LTemplateInstruction<1, 1, 1> {
|
||||||
public:
|
public:
|
||||||
explicit LUint32ToDouble(LOperand* value, LOperand* temp) {
|
explicit LUint32ToDouble(LOperand* value, LOperand* temp) {
|
||||||
@ -1958,6 +1973,19 @@ class LDoubleToI: public LTemplateInstruction<1, 1, 0> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class LDoubleToSmi: public LTemplateInstruction<1, 1, 0> {
|
||||||
|
public:
|
||||||
|
explicit LDoubleToSmi(LOperand* value) {
|
||||||
|
inputs_[0] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOperand* value() { return inputs_[0]; }
|
||||||
|
|
||||||
|
DECLARE_CONCRETE_INSTRUCTION(DoubleToSmi, "double-to-smi")
|
||||||
|
DECLARE_HYDROGEN_ACCESSOR(UnaryOperation)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// Truncating conversion from a tagged value to an int32.
|
// Truncating conversion from a tagged value to an int32.
|
||||||
class LTaggedToI: public LTemplateInstruction<1, 1, 1> {
|
class LTaggedToI: public LTemplateInstruction<1, 1, 1> {
|
||||||
public:
|
public:
|
||||||
@ -2266,7 +2294,7 @@ class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 1> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class LCheckSmi: public LTemplateInstruction<0, 1, 0> {
|
class LCheckSmi: public LTemplateInstruction<1, 1, 0> {
|
||||||
public:
|
public:
|
||||||
explicit LCheckSmi(LOperand* value) {
|
explicit LCheckSmi(LOperand* value) {
|
||||||
inputs_[0] = value;
|
inputs_[0] = value;
|
||||||
|
68
test/mjsunit/smi-representation.js
Normal file
68
test/mjsunit/smi-representation.js
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// Copyright 2013 the V8 project authors. All rights reserved.
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following
|
||||||
|
// disclaimer in the documentation and/or other materials provided
|
||||||
|
// with the distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived
|
||||||
|
// from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
// Flags: --track-fields --track-double-fields --allow-natives-syntax
|
||||||
|
|
||||||
|
function smi_field() {
|
||||||
|
return {"smi":0};
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_smi_repr(o, d1, d2) {
|
||||||
|
var s = o.smi;
|
||||||
|
var d = d1 - d2;
|
||||||
|
s = s + d;
|
||||||
|
o.smi = s;
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
var test = smi_field();
|
||||||
|
check_smi_repr(smi_field(), 5, 3);
|
||||||
|
check_smi_repr(smi_field(), 6, 2);
|
||||||
|
%OptimizeFunctionOnNextCall(check_smi_repr);
|
||||||
|
var val = check_smi_repr(smi_field(), 8, 1);
|
||||||
|
assertTrue(%HaveSameMap(val, test));
|
||||||
|
|
||||||
|
function tagged_smi_field() {
|
||||||
|
var o = {"tag":false};
|
||||||
|
o.tag = 10;
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_smi_repr_from_tagged(o, o2) {
|
||||||
|
var t = o2.tag;
|
||||||
|
o.smi = t;
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
check_smi_repr_from_tagged(smi_field(), tagged_smi_field());
|
||||||
|
check_smi_repr_from_tagged(smi_field(), tagged_smi_field());
|
||||||
|
%OptimizeFunctionOnNextCall(check_smi_repr_from_tagged);
|
||||||
|
var val = check_smi_repr_from_tagged(smi_field(), tagged_smi_field());
|
||||||
|
assertTrue(%HaveSameMap(val, test));
|
||||||
|
var overflow = tagged_smi_field();
|
||||||
|
overflow.tag = 0x80000000;
|
||||||
|
var val = check_smi_repr_from_tagged(smi_field(), overflow);
|
Loading…
Reference in New Issue
Block a user