return InstantiateFunction(data, name);
case kNewObjectTag:
var Constructor = %GetTemplateField(data, kApiConstructorOffset);
- var result = Constructor ? new (Instantiate(Constructor))() : {};
+ // Note: Do not directly use a function template as a condition, our
+ // internal ToBoolean doesn't handle that!
+ var result = typeof Constructor === 'undefined' ?
+ {} : new (Instantiate(Constructor))();
ConfigureTemplateInstance(result, data);
result = %ToFastProperties(result);
return result;
cache[serialNumber] = fun;
var prototype = %GetTemplateField(data, kApiPrototypeTemplateOffset);
var flags = %GetTemplateField(data, kApiFlagOffset);
- fun.prototype = prototype ? Instantiate(prototype) : {};
+ // Note: Do not directly use an object template as a condition, our
+ // internal ToBoolean doesn't handle that!
+ fun.prototype = typeof prototype === 'undefined' ?
+ {} : Instantiate(prototype);
if (flags & (1 << kReadOnlyPrototypeBit)) {
%FunctionSetReadOnlyPrototype(fun);
}
%SetProperty(fun.prototype, "constructor", fun, DONT_ENUM);
var parent = %GetTemplateField(data, kApiParentTemplateOffset);
- if (parent) {
+ // Note: Do not directly use a function template as a condition, our
+ // internal ToBoolean doesn't handle that!
+ if (!(typeof parent === 'undefined')) {
var parent_fun = Instantiate(parent);
fun.prototype.__proto__ = parent_fun.prototype;
}
const Register map = r9.is(tos_) ? r7 : r9;
// undefined -> false.
- CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false, &patch);
+ CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
// Boolean -> its value.
- CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false, &patch);
- CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true, &patch);
+ CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
+ CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
// 'null' -> false.
- CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false, &patch);
+ CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
if (types_.Contains(SMI)) {
// Smis: 0 -> false, all other -> true
if (types_.NeedsMap()) {
__ ldr(map, FieldMemOperand(tos_, HeapObject::kMapOffset));
- // Everything with a map could be undetectable, so check this now.
- __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset));
- __ tst(ip, Operand(1 << Map::kIsUndetectable));
- // Undetectable -> false.
- __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, ne);
- __ Ret(ne);
+ if (types_.CanBeUndetectable()) {
+ __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset));
+ __ tst(ip, Operand(1 << Map::kIsUndetectable));
+ // Undetectable -> false.
+ __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, ne);
+ __ Ret(ne);
+ }
}
if (types_.Contains(SPEC_OBJECT)) {
__ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
// tos_ contains the correct non-zero return value already.
__ Ret(ge);
- } else if (types_.Contains(INTERNAL_OBJECT)) {
- // We've seen a spec object for the first time -> patch.
- __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
- __ b(ge, &patch);
}
if (types_.Contains(STRING)) {
__ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
__ ldr(tos_, FieldMemOperand(tos_, String::kLengthOffset), lt);
__ Ret(lt); // the string length is OK as the return value
- } else if (types_.Contains(INTERNAL_OBJECT)) {
- // We've seen a string for the first time -> patch
- __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
- __ b(lt, &patch);
}
if (types_.Contains(HEAP_NUMBER)) {
__ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, vs); // for FP_NAN
__ Ret();
__ bind(¬_heap_number);
- } else if (types_.Contains(INTERNAL_OBJECT)) {
- // We've seen a heap number for the first time -> patch
- __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
- __ b(eq, &patch);
}
- if (types_.Contains(INTERNAL_OBJECT)) {
- // Internal objects -> true.
- __ mov(tos_, Operand(1, RelocInfo::NONE));
- __ Ret();
- }
-
- if (!types_.IsAll()) {
- __ bind(&patch);
- GenerateTypeTransition(masm);
- }
+ __ bind(&patch);
+ GenerateTypeTransition(masm);
}
void ToBooleanStub::CheckOddball(MacroAssembler* masm,
Type type,
Heap::RootListIndex value,
- bool result,
- Label* patch) {
+ bool result) {
if (types_.Contains(type)) {
// If we see an expected oddball, return its ToBoolean value tos_.
__ LoadRoot(ip, value);
__ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, eq);
}
__ Ret(eq);
- } else if (types_.Contains(INTERNAL_OBJECT)) {
- // If we see an unexpected oddball and handle internal objects, we must
- // patch because the code for internal objects doesn't handle it explictly.
- __ LoadRoot(ip, value);
- __ cmp(tos_, ip);
- __ b(eq, patch);
}
}
: instr->SecondSuccessor();
return new LGoto(successor->block_id());
}
- LInstruction* branch = new LBranch(UseRegister(v));
- // When we handle all cases, we never deopt, so we don't need to assign the
- // environment then. Note that we map the "empty" case to the "all" case in
- // the code generator.
- ToBooleanStub::Types types = instr->expected_input_types();
- bool all_cases_handled = types.IsAll() || types.IsEmpty();
- return all_cases_handled ? branch : AssignEnvironment(branch);
+ return AssignEnvironment(new LBranch(UseRegister(v)));
}
// undefined -> false.
__ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
__ b(eq, false_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen undefined for the first time -> deopt.
- __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
- DeoptimizeIf(eq, instr->environment());
}
-
if (expected.Contains(ToBooleanStub::BOOLEAN)) {
// Boolean -> its value.
__ CompareRoot(reg, Heap::kTrueValueRootIndex);
__ b(eq, true_label);
__ CompareRoot(reg, Heap::kFalseValueRootIndex);
__ b(eq, false_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a boolean for the first time -> deopt.
- __ CompareRoot(reg, Heap::kTrueValueRootIndex);
- DeoptimizeIf(eq, instr->environment());
- __ CompareRoot(reg, Heap::kFalseValueRootIndex);
- DeoptimizeIf(eq, instr->environment());
- }
-
-#if 0
- if (expected.Contains(ToBooleanStub::BOOLEAN)) {
- // false -> false.
- __ CompareRoot(reg, Heap::kFalseValueRootIndex);
- __ b(eq, false_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a boolean for the first time -> deopt.
- __ CompareRoot(reg, Heap::kFalseValueRootIndex);
- DeoptimizeIf(eq, instr->environment());
}
-#endif
-
if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
// 'null' -> false.
__ CompareRoot(reg, Heap::kNullValueRootIndex);
__ b(eq, false_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen null for the first time -> deopt.
- __ CompareRoot(reg, Heap::kNullValueRootIndex);
- DeoptimizeIf(eq, instr->environment());
}
if (expected.Contains(ToBooleanStub::SMI)) {
const Register map = scratch0();
if (expected.NeedsMap()) {
__ ldr(map, FieldMemOperand(reg, HeapObject::kMapOffset));
- // Everything with a map could be undetectable, so check this now.
- __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset));
- __ tst(ip, Operand(1 << Map::kIsUndetectable));
- __ b(ne, false_label);
+
+ if (expected.CanBeUndetectable()) {
+ // Undetectable -> false.
+ __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset));
+ __ tst(ip, Operand(1 << Map::kIsUndetectable));
+ __ b(ne, false_label);
+ }
}
if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
// spec object -> true.
__ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
__ b(ge, true_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a spec object for the first time -> deopt.
- __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
- DeoptimizeIf(ge, instr->environment());
}
if (expected.Contains(ToBooleanStub::STRING)) {
__ b(ne, true_label);
__ b(false_label);
__ bind(¬_string);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a string for the first time -> deopt
- __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
- DeoptimizeIf(lt, instr->environment());
}
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
__ b(eq, false_label); // +0, -0 -> false.
__ b(true_label);
__ bind(¬_heap_number);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a heap number for the first time -> deopt.
- __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
- DeoptimizeIf(eq, instr->environment());
}
- if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // internal objects -> true
- __ b(true_label);
- } else {
- // We've seen something for the first time -> deopt.
- DeoptimizeIf(al, instr->environment());
- }
+ // We've seen something for the first time -> deopt.
+ DeoptimizeIf(al, instr->environment());
}
}
}
if (IsEmpty()) stream->Add("None");
if (Contains(UNDEFINED)) stream->Add("Undefined");
if (Contains(BOOLEAN)) stream->Add("Bool");
- if (Contains(SMI)) stream->Add("Smi");
if (Contains(NULL_TYPE)) stream->Add("Null");
+ if (Contains(SMI)) stream->Add("Smi");
if (Contains(SPEC_OBJECT)) stream->Add("SpecObject");
if (Contains(STRING)) stream->Add("String");
if (Contains(HEAP_NUMBER)) stream->Add("HeapNumber");
- if (Contains(INTERNAL_OBJECT)) stream->Add("InternalObject");
}
return !object->IsUndetectableObject() &&
String::cast(*object)->length() != 0;
} else if (object->IsHeapNumber()) {
+ ASSERT(!object->IsUndetectableObject());
Add(HEAP_NUMBER);
double value = HeapNumber::cast(*object)->value();
- return !object->IsUndetectableObject() && value != 0 && !isnan(value);
+ return value != 0 && !isnan(value);
} else {
- Add(INTERNAL_OBJECT);
- return !object->IsUndetectableObject();
+ // We should never see an internal object at runtime here!
+ UNREACHABLE();
+ return true;
}
}
bool ToBooleanStub::Types::NeedsMap() const {
return Contains(ToBooleanStub::SPEC_OBJECT)
|| Contains(ToBooleanStub::STRING)
- || Contains(ToBooleanStub::HEAP_NUMBER)
- || Contains(ToBooleanStub::INTERNAL_OBJECT);
+ || Contains(ToBooleanStub::HEAP_NUMBER);
+}
+
+
+bool ToBooleanStub::Types::CanBeUndetectable() const {
+ return Contains(ToBooleanStub::SPEC_OBJECT)
+ || Contains(ToBooleanStub::STRING);
}
SPEC_OBJECT,
STRING,
HEAP_NUMBER,
- INTERNAL_OBJECT,
NUMBER_OF_TYPES
};
explicit Types(byte bits) : set_(bits) {}
bool IsEmpty() const { return set_.IsEmpty(); }
- bool IsAll() const { return ToByte() == ((1 << NUMBER_OF_TYPES) - 1); }
bool Contains(Type type) const { return set_.Contains(type); }
void Add(Type type) { set_.Add(type); }
byte ToByte() const { return set_.ToIntegral(); }
void TraceTransition(Types to) const;
bool Record(Handle<Object> object);
bool NeedsMap() const;
+ bool CanBeUndetectable() const;
private:
EnumSet<Type, byte> set_;
void CheckOddball(MacroAssembler* masm,
Type type,
Heap::RootListIndex value,
- bool result,
- Label* patch);
+ bool result);
void GenerateTypeTransition(MacroAssembler* masm);
Register tos_;
}
// undefined -> false
- CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false, &patch);
+ CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
// Boolean -> its value
- CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false, &patch);
- CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true, &patch);
+ CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
+ CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
// 'null' -> false.
- CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false, &patch);
+ CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
if (types_.Contains(SMI)) {
// Smis: 0 -> false, all other -> true
Label not_smi;
__ JumpIfNotSmi(argument, ¬_smi, Label::kNear);
- // argument contains the correct return value already
+ // argument contains the correct return value already.
if (!tos_.is(argument)) {
__ mov(tos_, argument);
}
if (types_.NeedsMap()) {
__ mov(map, FieldOperand(argument, HeapObject::kMapOffset));
- // Everything with a map could be undetectable, so check this now.
- __ test_b(FieldOperand(map, Map::kBitFieldOffset),
- 1 << Map::kIsUndetectable);
- // Undetectable -> false.
- Label not_undetectable;
- __ j(zero, ¬_undetectable, Label::kNear);
- __ Set(tos_, Immediate(0));
- __ ret(1 * kPointerSize);
- __ bind(¬_undetectable);
+ if (types_.CanBeUndetectable()) {
+ __ test_b(FieldOperand(map, Map::kBitFieldOffset),
+ 1 << Map::kIsUndetectable);
+ // Undetectable -> false.
+ Label not_undetectable;
+ __ j(zero, ¬_undetectable, Label::kNear);
+ __ Set(tos_, Immediate(0));
+ __ ret(1 * kPointerSize);
+ __ bind(¬_undetectable);
+ }
}
if (types_.Contains(SPEC_OBJECT)) {
Label not_js_object;
__ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
__ j(below, ¬_js_object, Label::kNear);
- __ Set(tos_, Immediate(1));
+ // argument contains the correct return value already.
+ if (!tos_.is(argument)) {
+ __ Set(tos_, Immediate(1));
+ }
__ ret(1 * kPointerSize);
__ bind(¬_js_object);
- } else if (types_.Contains(INTERNAL_OBJECT)) {
- // We've seen a spec object for the first time -> patch.
- __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
- __ j(above_equal, &patch, Label::kNear);
}
if (types_.Contains(STRING)) {
__ mov(tos_, FieldOperand(argument, String::kLengthOffset));
__ ret(1 * kPointerSize); // the string length is OK as the return value
__ bind(¬_string);
- } else if (types_.Contains(INTERNAL_OBJECT)) {
- // We've seen a string for the first time -> patch
- __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
- __ j(below, &patch, Label::kNear);
}
if (types_.Contains(HEAP_NUMBER)) {
__ fld_d(FieldOperand(argument, HeapNumber::kValueOffset));
__ FCmp();
__ j(zero, &false_result, Label::kNear);
- __ Set(tos_, Immediate(1));
+ // argument contains the correct return value already.
+ if (!tos_.is(argument)) {
+ __ Set(tos_, Immediate(1));
+ }
__ ret(1 * kPointerSize);
__ bind(&false_result);
__ Set(tos_, Immediate(0));
__ ret(1 * kPointerSize);
__ bind(¬_heap_number);
- } else if (types_.Contains(INTERNAL_OBJECT)) {
- // We've seen a heap number for the first time -> patch
- __ cmp(map, factory->heap_number_map());
- __ j(equal, &patch, Label::kNear);
- }
-
- if (types_.Contains(INTERNAL_OBJECT)) {
- // internal objects -> true
- __ Set(tos_, Immediate(1));
- __ ret(1 * kPointerSize);
}
- if (!types_.IsAll()) {
- __ bind(&patch);
- GenerateTypeTransition(masm);
- }
+ __ bind(&patch);
+ GenerateTypeTransition(masm);
}
void ToBooleanStub::CheckOddball(MacroAssembler* masm,
Type type,
Heap::RootListIndex value,
- bool result,
- Label* patch) {
+ bool result) {
const Register argument = eax;
if (types_.Contains(type)) {
// If we see an expected oddball, return its ToBoolean value tos_.
Label different_value;
__ CompareRoot(argument, value);
__ j(not_equal, &different_value, Label::kNear);
- __ Set(tos_, Immediate(result ? 1 : 0));
+ if (!result) {
+ // If we have to return zero, there is no way around clearing tos_.
+ __ Set(tos_, Immediate(0));
+ } else if (!tos_.is(argument)) {
+ // If we have to return non-zero, we can re-use the argument if it is the
+ // same register as the result, because we never see Smi-zero here.
+ __ Set(tos_, Immediate(1));
+ }
__ ret(1 * kPointerSize);
__ bind(&different_value);
- } else if (types_.Contains(INTERNAL_OBJECT)) {
- // If we see an unexpected oddball and handle internal objects, we must
- // patch because the code for internal objects doesn't handle it explictly.
- __ CompareRoot(argument, value);
- __ j(equal, patch);
}
}
// undefined -> false.
__ cmp(reg, factory()->undefined_value());
__ j(equal, false_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen undefined for the first time -> deopt.
- __ cmp(reg, factory()->undefined_value());
- DeoptimizeIf(equal, instr->environment());
}
-
if (expected.Contains(ToBooleanStub::BOOLEAN)) {
// true -> true.
__ cmp(reg, factory()->true_value());
__ j(equal, true_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a boolean for the first time -> deopt.
- __ cmp(reg, factory()->true_value());
- DeoptimizeIf(equal, instr->environment());
- }
-
- if (expected.Contains(ToBooleanStub::BOOLEAN)) {
// false -> false.
__ cmp(reg, factory()->false_value());
__ j(equal, false_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a boolean for the first time -> deopt.
- __ cmp(reg, factory()->false_value());
- DeoptimizeIf(equal, instr->environment());
}
-
if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
// 'null' -> false.
__ cmp(reg, factory()->null_value());
__ j(equal, false_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen null for the first time -> deopt.
- __ cmp(reg, factory()->null_value());
- DeoptimizeIf(equal, instr->environment());
}
if (expected.Contains(ToBooleanStub::SMI)) {
DeoptimizeIf(zero, instr->environment());
}
- Register map = no_reg;
+ Register map = no_reg; // Keep the compiler happy.
if (expected.NeedsMap()) {
map = ToRegister(instr->TempAt(0));
ASSERT(!map.is(reg));
__ mov(map, FieldOperand(reg, HeapObject::kMapOffset));
- // Everything with a map could be undetectable, so check this now.
- __ test_b(FieldOperand(map, Map::kBitFieldOffset),
- 1 << Map::kIsUndetectable);
- // Undetectable -> false.
- __ j(not_zero, false_label);
+
+ if (expected.CanBeUndetectable()) {
+ // Undetectable -> false.
+ __ test_b(FieldOperand(map, Map::kBitFieldOffset),
+ 1 << Map::kIsUndetectable);
+ __ j(not_zero, false_label);
+ }
}
if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
// spec object -> true.
__ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
__ j(above_equal, true_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a spec object for the first time -> deopt.
- __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
- DeoptimizeIf(above_equal, instr->environment());
}
if (expected.Contains(ToBooleanStub::STRING)) {
__ j(not_zero, true_label);
__ jmp(false_label);
__ bind(¬_string);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a string for the first time -> deopt
- __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
- DeoptimizeIf(below, instr->environment());
}
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
__ j(zero, false_label);
__ jmp(true_label);
__ bind(¬_heap_number);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a heap number for the first time -> deopt.
- __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
- factory()->heap_number_map());
- DeoptimizeIf(equal, instr->environment());
}
- if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // internal objects -> true
- __ jmp(true_label);
- } else {
- // We've seen something for the first time -> deopt.
- DeoptimizeIf(no_condition, instr->environment());
- }
+ // We've seen something for the first time -> deopt.
+ DeoptimizeIf(no_condition, instr->environment());
}
}
}
// involving maps).
bool needs_temp = expected.NeedsMap() || expected.IsEmpty();
LOperand* temp = needs_temp ? TempRegister() : NULL;
- LInstruction* branch = new LBranch(UseRegister(v), temp);
- // When we handle all cases, we never deopt, so we don't need to assign the
- // environment then.
- return expected.IsAll() ? branch : AssignEnvironment(branch);
+ return AssignEnvironment(new LBranch(UseRegister(v), temp));
}
}
// undefined -> false
- CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false, &patch);
+ CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
// Boolean -> its value
- CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false, &patch);
- CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true, &patch);
+ CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
+ CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
// 'null' -> false.
- CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false, &patch);
+ CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
if (types_.Contains(SMI)) {
// Smis: 0 -> false, all other -> true
if (types_.NeedsMap()) {
__ movq(map, FieldOperand(argument, HeapObject::kMapOffset));
- // Everything with a map could be undetectable, so check this now.
- __ testb(FieldOperand(map, Map::kBitFieldOffset),
- Immediate(1 << Map::kIsUndetectable));
- // Undetectable -> false.
- Label not_undetectable;
- __ j(zero, ¬_undetectable, Label::kNear);
- __ Set(tos_, 0);
- __ ret(1 * kPointerSize);
- __ bind(¬_undetectable);
+ if (types_.CanBeUndetectable()) {
+ __ testb(FieldOperand(map, Map::kBitFieldOffset),
+ Immediate(1 << Map::kIsUndetectable));
+ // Undetectable -> false.
+ Label not_undetectable;
+ __ j(zero, ¬_undetectable, Label::kNear);
+ __ Set(tos_, 0);
+ __ ret(1 * kPointerSize);
+ __ bind(¬_undetectable);
+ }
}
if (types_.Contains(SPEC_OBJECT)) {
Label not_js_object;
__ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
__ j(below, ¬_js_object, Label::kNear);
- __ Set(tos_, 1);
+ // argument contains the correct return value already.
+ if (!tos_.is(argument)) {
+ __ Set(tos_, 1);
+ }
__ ret(1 * kPointerSize);
__ bind(¬_js_object);
- } else if (types_.Contains(INTERNAL_OBJECT)) {
- // We've seen a spec object for the first time -> patch.
- __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
- __ j(above_equal, &patch, Label::kNear);
}
if (types_.Contains(STRING)) {
__ movq(tos_, FieldOperand(argument, String::kLengthOffset));
__ ret(1 * kPointerSize); // the string length is OK as the return value
__ bind(¬_string);
- } else if (types_.Contains(INTERNAL_OBJECT)) {
- // We've seen a string for the first time -> patch
- __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
- __ j(below, &patch, Label::kNear);
}
if (types_.Contains(HEAP_NUMBER)) {
__ xorps(xmm0, xmm0);
__ ucomisd(xmm0, FieldOperand(argument, HeapNumber::kValueOffset));
__ j(zero, &false_result, Label::kNear);
- __ Set(tos_, 1);
+ // argument contains the correct return value already.
+ if (!tos_.is(argument)) {
+ __ Set(tos_, 1);
+ }
__ ret(1 * kPointerSize);
__ bind(&false_result);
__ Set(tos_, 0);
__ ret(1 * kPointerSize);
__ bind(¬_heap_number);
- } else if (types_.Contains(INTERNAL_OBJECT)) {
- // We've seen a heap number for the first time -> patch
- __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
- __ j(equal, &patch, Label::kNear);
- }
-
- if (types_.Contains(INTERNAL_OBJECT)) {
- // internal objects -> true
- __ Set(tos_, 1);
- __ ret(1 * kPointerSize);
}
- if (!types_.IsAll()) {
- __ bind(&patch);
- GenerateTypeTransition(masm);
- }
+ __ bind(&patch);
+ GenerateTypeTransition(masm);
}
void ToBooleanStub::CheckOddball(MacroAssembler* masm,
Type type,
Heap::RootListIndex value,
- bool result,
- Label* patch) {
+ bool result) {
const Register argument = rax;
if (types_.Contains(type)) {
// If we see an expected oddball, return its ToBoolean value tos_.
Label different_value;
__ CompareRoot(argument, value);
__ j(not_equal, &different_value, Label::kNear);
- __ Set(tos_, result ? 1 : 0);
+ if (!result) {
+ // If we have to return zero, there is no way around clearing tos_.
+ __ Set(tos_, 0);
+ } else if (!tos_.is(argument)) {
+ // If we have to return non-zero, we can re-use the argument if it is the
+ // same register as the result, because we never see Smi-zero here.
+ __ Set(tos_, 1);
+ }
__ ret(1 * kPointerSize);
__ bind(&different_value);
- } else if (types_.Contains(INTERNAL_OBJECT)) {
- // If we see an unexpected oddball and handle internal objects, we must
- // patch because the code for internal objects doesn't handle it explictly.
- __ CompareRoot(argument, value);
- __ j(equal, patch);
}
}
// undefined -> false.
__ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
__ j(equal, false_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen undefined for the first time -> deopt.
- __ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
- DeoptimizeIf(equal, instr->environment());
}
-
if (expected.Contains(ToBooleanStub::BOOLEAN)) {
// true -> true.
__ CompareRoot(reg, Heap::kTrueValueRootIndex);
__ j(equal, true_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a boolean for the first time -> deopt.
- __ CompareRoot(reg, Heap::kTrueValueRootIndex);
- DeoptimizeIf(equal, instr->environment());
- }
-
- if (expected.Contains(ToBooleanStub::BOOLEAN)) {
// false -> false.
__ CompareRoot(reg, Heap::kFalseValueRootIndex);
__ j(equal, false_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a boolean for the first time -> deopt.
- __ CompareRoot(reg, Heap::kFalseValueRootIndex);
- DeoptimizeIf(equal, instr->environment());
}
-
if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
// 'null' -> false.
__ CompareRoot(reg, Heap::kNullValueRootIndex);
__ j(equal, false_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen null for the first time -> deopt.
- __ CompareRoot(reg, Heap::kNullValueRootIndex);
- DeoptimizeIf(equal, instr->environment());
}
if (expected.Contains(ToBooleanStub::SMI)) {
const Register map = kScratchRegister;
if (expected.NeedsMap()) {
__ movq(map, FieldOperand(reg, HeapObject::kMapOffset));
- // Everything with a map could be undetectable, so check this now.
- __ testb(FieldOperand(map, Map::kBitFieldOffset),
- Immediate(1 << Map::kIsUndetectable));
- // Undetectable -> false.
- __ j(not_zero, false_label);
+
+ if (expected.CanBeUndetectable()) {
+ // Undetectable -> false.
+ __ testb(FieldOperand(map, Map::kBitFieldOffset),
+ Immediate(1 << Map::kIsUndetectable));
+ __ j(not_zero, false_label);
+ }
}
if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
// spec object -> true.
__ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
__ j(above_equal, true_label);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a spec object for the first time -> deopt.
- __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
- DeoptimizeIf(above_equal, instr->environment());
}
if (expected.Contains(ToBooleanStub::STRING)) {
__ j(not_zero, true_label);
__ jmp(false_label);
__ bind(¬_string);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a string for the first time -> deopt
- __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
- DeoptimizeIf(below, instr->environment());
}
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
__ j(zero, false_label);
__ jmp(true_label);
__ bind(¬_heap_number);
- } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // We've seen a heap number for the first time -> deopt.
- __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
- DeoptimizeIf(equal, instr->environment());
}
- if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
- // internal objects -> true
- __ jmp(true_label);
- } else {
- // We've seen something for the first time -> deopt.
- DeoptimizeIf(no_condition, instr->environment());
- }
+ // We've seen something for the first time -> deopt.
+ DeoptimizeIf(no_condition, instr->environment());
}
}
}
: instr->SecondSuccessor();
return new LGoto(successor->block_id());
}
- LInstruction* branch = new LBranch(UseRegister(v));
- // When we handle all cases, we never deopt, so we don't need to assign the
- // environment then.
- bool all_cases_handled = instr->expected_input_types().IsAll();
- return all_cases_handled ? branch : AssignEnvironment(branch);
+ return AssignEnvironment(new LBranch(UseRegister(v)));
}