Revision: 8886
Author: [email protected]
Date: Thu Aug 11 00:22:16 2011
Log: Simplify and optimize ToBoolean handling.
Changing our builtin JavaScript code slightly, we can make sure that we
never
see internal objects as arguments for ToBoolean at runtime. Removing that
case
from the stub generator and crankshaft makes things a lot easier.
Heap numbers can never be undetectable (only strings and spec objects can),
so
we can leave out a useless test.
Try to re-use a non-null register value when returning 'true' in some cases.
Removed special handling of the 'handle all' case, it will very probably
never
happen in real code and only makes things more complicated.
Improved naming of the ToBoolean stubs a bit, reflecting the order in which
cases are handled in the code itself.
Review URL: http://codereview.chromium.org/7497063
http://code.google.com/p/v8/source/detail?r=8886
Modified:
/branches/bleeding_edge/src/apinatives.js
/branches/bleeding_edge/src/arm/code-stubs-arm.cc
/branches/bleeding_edge/src/arm/lithium-arm.cc
/branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
/branches/bleeding_edge/src/code-stubs.cc
/branches/bleeding_edge/src/code-stubs.h
/branches/bleeding_edge/src/ia32/code-stubs-ia32.cc
/branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
/branches/bleeding_edge/src/ia32/lithium-ia32.cc
/branches/bleeding_edge/src/x64/code-stubs-x64.cc
/branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
/branches/bleeding_edge/src/x64/lithium-x64.cc
=======================================
--- /branches/bleeding_edge/src/apinatives.js Mon Jul 25 08:01:45 2011
+++ /branches/bleeding_edge/src/apinatives.js Thu Aug 11 00:22:16 2011
@@ -49,7 +49,10 @@
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;
@@ -74,13 +77,18 @@
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;
}
=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.cc Tue Aug 9 00:59:00
2011
+++ /branches/bleeding_edge/src/arm/code-stubs-arm.cc Thu Aug 11 00:22:16
2011
@@ -1613,14 +1613,14 @@
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
@@ -1635,12 +1635,13 @@
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)) {
@@ -1648,10 +1649,6 @@
__ 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)) {
@@ -1659,10 +1656,6 @@
__ 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)) {
@@ -1679,30 +1672,17 @@
__ 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);
@@ -1713,12 +1693,6 @@
__ 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);
}
}
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.cc Tue Aug 9 00:59:00 2011
+++ /branches/bleeding_edge/src/arm/lithium-arm.cc Thu Aug 11 00:22:16 2011
@@ -1039,13 +1039,7 @@
: 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)));
}
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Wed Aug 10
05:32:43 2011
+++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Thu Aug 11
00:22:16 2011
@@ -1583,46 +1583,18 @@
// 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)) {
@@ -1639,20 +1611,19 @@
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)) {
@@ -1665,10 +1636,6 @@
__ 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)) {
@@ -1683,19 +1650,10 @@
__ 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());
}
}
}
=======================================
--- /branches/bleeding_edge/src/code-stubs.cc Thu Jul 28 06:33:51 2011
+++ /branches/bleeding_edge/src/code-stubs.cc Thu Aug 11 00:22:16 2011
@@ -340,12 +340,11 @@
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");
}
@@ -385,12 +384,14 @@
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;
}
}
@@ -398,8 +399,13 @@
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);
}
=======================================
--- /branches/bleeding_edge/src/code-stubs.h Mon Aug 1 05:53:24 2011
+++ /branches/bleeding_edge/src/code-stubs.h Thu Aug 11 00:22:16 2011
@@ -908,7 +908,6 @@
SPEC_OBJECT,
STRING,
HEAP_NUMBER,
- INTERNAL_OBJECT,
NUMBER_OF_TYPES
};
@@ -922,7 +921,6 @@
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(); }
@@ -930,6 +928,7 @@
void TraceTransition(Types to) const;
bool Record(Handle<Object> object);
bool NeedsMap() const;
+ bool CanBeUndetectable() const;
private:
EnumSet<Type, byte> set_;
@@ -956,8 +955,7 @@
void CheckOddball(MacroAssembler* masm,
Type type,
Heap::RootListIndex value,
- bool result,
- Label* patch);
+ bool result);
void GenerateTypeTransition(MacroAssembler* masm);
Register tos_;
=======================================
--- /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Mon Aug 1 06:35:11
2011
+++ /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Thu Aug 11 00:22:16
2011
@@ -249,20 +249,20 @@
}
// 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);
}
@@ -276,15 +276,16 @@
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)) {
@@ -292,13 +293,12 @@
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)) {
@@ -309,10 +309,6 @@
__ 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)) {
@@ -324,50 +320,42 @@
__ 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);
}
}
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Wed Aug 10
05:32:43 2011
+++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Thu Aug 11
00:22:16 2011
@@ -1412,40 +1412,19 @@
// 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)) {
@@ -1459,26 +1438,24 @@
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)) {
@@ -1490,10 +1467,6 @@
__ 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)) {
@@ -1508,20 +1481,10 @@
__ 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());
}
}
}
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.cc Thu Jul 28 07:56:08
2011
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.cc Thu Aug 11 00:22:16
2011
@@ -1047,10 +1047,7 @@
// 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));
}
=======================================
--- /branches/bleeding_edge/src/x64/code-stubs-x64.cc Mon Aug 1 05:53:24
2011
+++ /branches/bleeding_edge/src/x64/code-stubs-x64.cc Thu Aug 11 00:22:16
2011
@@ -242,14 +242,14 @@
}
// 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
@@ -269,15 +269,16 @@
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)) {
@@ -285,13 +286,12 @@
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)) {
@@ -302,10 +302,6 @@
__ 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)) {
@@ -316,50 +312,42 @@
__ 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);
}
}
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Wed Aug 10
06:11:14 2011
+++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Thu Aug 11
00:22:16 2011
@@ -1410,40 +1410,19 @@
// 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)) {
@@ -1460,21 +1439,19 @@
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)) {
@@ -1486,10 +1463,6 @@
__ 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)) {
@@ -1502,19 +1475,10 @@
__ 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());
}
}
}
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.cc Mon Aug 1 05:53:24 2011
+++ /branches/bleeding_edge/src/x64/lithium-x64.cc Thu Aug 11 00:22:16 2011
@@ -1036,11 +1036,7 @@
: 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)));
}
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev