LBranch* result = new(zone()) LBranch(UseRegister(value));
// Tagged values that are not known smis or booleans require a
- // deoptimization environment.
+ // deoptimization environment. If the instruction is generic no
+ // environment is needed since all cases are handled.
Representation rep = value->representation();
HType type = value->type();
- if (rep.IsTagged() && !type.IsSmi() && !type.IsBoolean()) {
+ ToBooleanStub::Types expected = instr->expected_input_types();
+ if (rep.IsTagged() && !type.IsSmi() && !type.IsBoolean() &&
+ !expected.IsGeneric()) {
return AssignEnvironment(result);
}
return result;
DwVfpRegister reg = ToDoubleRegister(instr->value());
// Test the double value. Zero and NaN are false.
__ VFPCompareAndSetFlags(reg, 0.0);
- __ cmp(r0, r0, vs); // If NaN, set the Z flag.
+ __ cmp(r0, r0, vs); // If NaN, set the Z flag. (NaN -> false)
EmitBranch(instr, ne);
} else {
ASSERT(r.IsTagged());
ASSERT(!info()->IsStub());
__ cmp(reg, Operand::Zero());
EmitBranch(instr, ne);
+ } else if (type.IsJSArray()) {
+ ASSERT(!info()->IsStub());
+ EmitBranch(instr, al);
+ } else if (type.IsHeapNumber()) {
+ ASSERT(!info()->IsStub());
+ DwVfpRegister dbl_scratch = double_scratch0();
+ __ vldr(dbl_scratch, FieldMemOperand(reg, HeapNumber::kValueOffset));
+ // Test the double value. Zero and NaN are false.
+ __ VFPCompareAndSetFlags(dbl_scratch, 0.0);
+ __ cmp(r0, r0, vs); // If NaN, set the Z flag. (NaN)
+ EmitBranch(instr, ne);
+ } else if (type.IsString()) {
+ ASSERT(!info()->IsStub());
+ __ ldr(ip, FieldMemOperand(reg, String::kLengthOffset));
+ __ cmp(ip, Operand::Zero());
+ EmitBranch(instr, ne);
} else {
ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
// Avoid deopts in the case where we've never executed this path before.
- if (expected.IsEmpty()) expected = ToBooleanStub::all_types();
+ if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
if (expected.Contains(ToBooleanStub::UNDEFINED)) {
// undefined -> false.
__ bind(¬_heap_number);
}
- // We've seen something for the first time -> deopt.
- DeoptimizeIf(al, instr->environment());
+ if (!expected.IsGeneric()) {
+ // We've seen something for the first time -> deopt.
+ // This can only happen if we are not generic already.
+ DeoptimizeIf(al, instr->environment());
+ }
}
}
}
class Types : public EnumSet<Type, byte> {
public:
- Types() {}
+ Types() : EnumSet<Type, byte>(0) {}
explicit Types(byte bits) : EnumSet<Type, byte>(bits) {}
byte ToByte() const { return ToIntegral(); }
bool Record(Handle<Object> object);
bool NeedsMap() const;
bool CanBeUndetectable() const;
- };
+ bool IsGeneric() const { return ToIntegral() == Generic().ToIntegral(); }
- static Types no_types() { return Types(); }
- static Types all_types() { return Types((1 << NUMBER_OF_TYPES) - 1); }
+ static Types Generic() { return Types((1 << NUMBER_OF_TYPES) - 1); }
+ };
explicit ToBooleanStub(Types types = Types())
: types_(types) { }
Representation HBranch::observed_input_representation(int index) {
static const ToBooleanStub::Types tagged_types(
- ToBooleanStub::UNDEFINED |
ToBooleanStub::NULL_TYPE |
ToBooleanStub::SPEC_OBJECT |
ToBooleanStub::STRING |
ToBooleanStub::SYMBOL);
if (expected_input_types_.ContainsAnyOf(tagged_types)) {
return Representation::Tagged();
- } else if (expected_input_types_.Contains(ToBooleanStub::HEAP_NUMBER)) {
+ }
+ if (expected_input_types_.Contains(ToBooleanStub::UNDEFINED)) {
+ if (expected_input_types_.Contains(ToBooleanStub::HEAP_NUMBER)) {
+ return Representation::Double();
+ }
+ return Representation::Tagged();
+ }
+ if (expected_input_types_.Contains(ToBooleanStub::HEAP_NUMBER)) {
return Representation::Double();
- } else if (expected_input_types_.Contains(ToBooleanStub::SMI)) {
+ }
+ if (expected_input_types_.Contains(ToBooleanStub::SMI)) {
return Representation::Smi();
- } else {
- return Representation::None();
}
+ return Representation::None();
}
HBranch(HValue* value,
HBasicBlock* true_target,
HBasicBlock* false_target,
- ToBooleanStub::Types expected_input_types = ToBooleanStub::no_types())
+ ToBooleanStub::Types expected_input_types = ToBooleanStub::Types())
: HUnaryControlInstruction(value, true_target, false_target),
expected_input_types_(expected_input_types) {
ASSERT(true_target != NULL && false_target != NULL);
+ SetFlag(kAllowUndefinedAsNaN);
}
explicit HBranch(HValue* value)
- : HUnaryControlInstruction(value, NULL, NULL) { }
+ : HUnaryControlInstruction(value, NULL, NULL) {
+ SetFlag(kAllowUndefinedAsNaN);
+ }
HBranch(HValue* value, ToBooleanStub::Types expected_input_types)
: HUnaryControlInstruction(value, NULL, NULL),
- expected_input_types_(expected_input_types) { }
-
+ expected_input_types_(expected_input_types) {
+ SetFlag(kAllowUndefinedAsNaN);
+ }
virtual Representation RequiredInputRepresentation(int index) {
return Representation::None();
// so that the graph builder visits it and sees any live range extending
// constructs within it.
HConstant* constant_false = builder_->graph()->GetConstantFalse();
- ToBooleanStub::Types boolean_type = ToBooleanStub::no_types();
+ ToBooleanStub::Types boolean_type = ToBooleanStub::Types();
boolean_type.Add(ToBooleanStub::BOOLEAN);
HBranch* branch =
new(zone()) HBranch(constant_false, first_true_block_,
ASSERT(!info()->IsStub());
__ test(reg, Operand(reg));
EmitBranch(instr, not_equal);
+ } else if (type.IsJSArray()) {
+ ASSERT(!info()->IsStub());
+ EmitBranch(instr, no_condition);
+ } else if (type.IsHeapNumber()) {
+ ASSERT(!info()->IsStub());
+ CpuFeatureScope scope(masm(), SSE2);
+ __ xorps(xmm0, xmm0);
+ __ ucomisd(xmm0, FieldOperand(reg, HeapNumber::kValueOffset));
+ EmitBranch(instr, not_equal);
+ } else if (type.IsString()) {
+ ASSERT(!info()->IsStub());
+ __ cmp(FieldOperand(reg, String::kLengthOffset), Immediate(0));
+ EmitBranch(instr, not_equal);
} else {
ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
- // Avoid deopts in the case where we've never executed this path before.
- if (expected.IsEmpty()) expected = ToBooleanStub::all_types();
+ if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
if (expected.Contains(ToBooleanStub::UNDEFINED)) {
// undefined -> false.
__ bind(¬_heap_number);
}
- // We've seen something for the first time -> deopt.
- DeoptimizeIf(no_condition, instr->environment());
+ if (!expected.IsGeneric()) {
+ // We've seen something for the first time -> deopt.
+ // This can only happen if we are not generic already.
+ DeoptimizeIf(no_condition, instr->environment());
+ }
}
}
}
return new(zone()) LGoto(successor->block_id());
}
- // Untagged integers or doubles, smis and booleans don't require a
- // deoptimization environment nor a temp register.
+ ToBooleanStub::Types expected = instr->expected_input_types();
+
+ // Tagged values that are not known smis or booleans require a
+ // deoptimization environment. If the instruction is generic no
+ // environment is needed since all cases are handled.
Representation rep = value->representation();
HType type = value->type();
if (!rep.IsTagged() || type.IsSmi() || type.IsBoolean()) {
return new(zone()) LBranch(UseRegister(value), NULL);
}
- ToBooleanStub::Types expected = instr->expected_input_types();
+ bool needs_temp = expected.NeedsMap() || expected.IsEmpty();
+ LOperand* temp = needs_temp ? TempRegister() : NULL;
+
+ // The Generic stub does not have a deopt, so we need no environment.
+ if (expected.IsGeneric()) {
+ return new(zone()) LBranch(UseRegister(value), temp);
+ }
+
// We need a temporary register when we have to access the map *or* we have
// no type info yet, in which case we handle all cases (including the ones
// involving maps).
- bool needs_temp = expected.NeedsMap() || expected.IsEmpty();
- LOperand* temp = needs_temp ? TempRegister() : NULL;
return AssignEnvironment(new(zone()) LBranch(UseRegister(value), temp));
}
ASSERT(!info()->IsStub());
__ SmiCompare(reg, Smi::FromInt(0));
EmitBranch(instr, not_equal);
+ } else if (type.IsJSArray()) {
+ ASSERT(!info()->IsStub());
+ EmitBranch(instr, no_condition);
+ } else if (type.IsHeapNumber()) {
+ ASSERT(!info()->IsStub());
+ __ xorps(xmm0, xmm0);
+ __ ucomisd(xmm0, FieldOperand(reg, HeapNumber::kValueOffset));
+ EmitBranch(instr, not_equal);
+ } else if (type.IsString()) {
+ ASSERT(!info()->IsStub());
+ __ cmpq(FieldOperand(reg, String::kLengthOffset), Immediate(0));
+ EmitBranch(instr, not_equal);
} else {
ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
// Avoid deopts in the case where we've never executed this path before.
- if (expected.IsEmpty()) expected = ToBooleanStub::all_types();
+ if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
if (expected.Contains(ToBooleanStub::UNDEFINED)) {
// undefined -> false.
__ bind(¬_heap_number);
}
- // We've seen something for the first time -> deopt.
- DeoptimizeIf(no_condition, instr->environment());
+ if (!expected.IsGeneric()) {
+ // We've seen something for the first time -> deopt.
+ // This can only happen if we are not generic already.
+ DeoptimizeIf(no_condition, instr->environment());
+ }
}
}
}
LBranch* result = new(zone()) LBranch(UseRegister(value));
// Tagged values that are not known smis or booleans require a
- // deoptimization environment.
+ // deoptimization environment. If the instruction is generic no
+ // environment is needed since all cases are handled.
+ ToBooleanStub::Types expected = instr->expected_input_types();
Representation rep = value->representation();
HType type = value->type();
- if (rep.IsTagged() && !type.IsSmi() && !type.IsBoolean()) {
+ if (rep.IsTagged() && !type.IsSmi() && !type.IsBoolean() &&
+ !expected.IsGeneric()) {
return AssignEnvironment(result);
}
return result;