Index: src/ia32/code-stubs-ia32.cc |
=================================================================== |
--- src/ia32/code-stubs-ia32.cc (revision 8701) |
+++ src/ia32/code-stubs-ia32.cc (working copy) |
@@ -236,72 +236,163 @@ |
} |
-// The stub returns zero for false, and a non-zero value for true. |
+// The stub expects its argument on the stack and returns its result in tos_: |
+// zero for false, and a non-zero value for true. |
void ToBooleanStub::Generate(MacroAssembler* masm) { |
- Label false_result, true_result, not_string; |
+ Label patch; |
Factory* factory = masm->isolate()->factory(); |
const Register map = edx; |
- __ mov(eax, Operand(esp, 1 * kPointerSize)); |
+ if (!types_.IsEmpty()) { |
+ __ mov(eax, Operand(esp, 1 * kPointerSize)); |
+ } |
// undefined -> false |
- __ cmp(eax, factory->undefined_value()); |
- __ j(equal, &false_result); |
+ CheckOddball(masm, UNDEFINED, factory->undefined_value(), false, &patch); |
// Boolean -> its value |
- __ cmp(eax, factory->false_value()); |
- __ j(equal, &false_result); |
- __ cmp(eax, factory->true_value()); |
- __ j(equal, &true_result); |
+ CheckOddball(masm, BOOLEAN, factory->false_value(), false, &patch); |
+ CheckOddball(masm, BOOLEAN, factory->true_value(), true, &patch); |
- // Smis: 0 -> false, all other -> true |
- __ test(eax, Operand(eax)); |
- __ j(zero, &false_result); |
- __ JumpIfSmi(eax, &true_result); |
- |
// 'null' -> false. |
- __ cmp(eax, factory->null_value()); |
- __ j(equal, &false_result, Label::kNear); |
+ CheckOddball(masm, NULL_TYPE, factory->null_value(), false, &patch); |
- // Get the map of the heap object. |
- __ mov(map, FieldOperand(eax, HeapObject::kMapOffset)); |
+ bool need_map = |
+ types_.Contains(UNDETECTABLE) | |
+ types_.Contains(SPEC_OBJECT) | |
+ types_.Contains(STRING) | |
+ types_.Contains(HEAP_NUMBER) | |
+ types_.Contains(INTERNAL_OBJECT); |
- // Undetectable -> false. |
- __ test_b(FieldOperand(map, Map::kBitFieldOffset), |
- 1 << Map::kIsUndetectable); |
- __ j(not_zero, &false_result, Label::kNear); |
+ if (types_.Contains(SMI)) { |
+ // Smis: 0 -> false, all other -> true |
+ Label not_smi; |
+ __ JumpIfNotSmi(eax, ¬_smi, Label::kNear); |
+ __ ret(1 * kPointerSize); // eax contains the correct value already |
+ __ bind(¬_smi); |
+ } else if (need_map) { |
+ // If we need a map later and have a Smi -> patch. |
+ __ JumpIfSmi(eax, &patch, Label::kNear); |
+ } |
- // JavaScript object -> true. |
- __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); |
- __ j(above_equal, &true_result, Label::kNear); |
+ if (need_map) { |
+ __ mov(map, FieldOperand(eax, HeapObject::kMapOffset)); |
- // String value -> false iff empty. |
- __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); |
- __ j(above_equal, ¬_string, Label::kNear); |
- __ cmp(FieldOperand(eax, String::kLengthOffset), Immediate(0)); |
- __ j(zero, &false_result, Label::kNear); |
- __ jmp(&true_result, Label::kNear); |
+ // Everything with a map could be undetectable, so check this now. |
+ __ test_b(FieldOperand(map, Map::kBitFieldOffset), |
+ 1 << Map::kIsUndetectable); |
+ if (types_.Contains(UNDETECTABLE)) { |
+ // Undetectable -> false. |
+ Label not_undetectable; |
+ __ j(zero, ¬_undetectable, Label::kNear); |
+ __ xor_(tos_, Operand(tos_)); |
Vitaly Repeshko
2011/07/21 13:17:23
The macro assembler has Set macro that emits the o
Sven Panne
2011/07/21 13:49:28
I didn't know that one, thanks. :-)
|
+ __ ret(1 * kPointerSize); |
+ __ bind(¬_undetectable); |
+ } else { |
+ // We've seen an undetectable value for the first time -> patch. |
+ __ j(not_zero, &patch, Label::kNear); |
+ } |
+ } |
- __ bind(¬_string); |
- // HeapNumber -> false iff +0, -0, or NaN. |
- __ cmp(map, factory->heap_number_map()); |
- __ j(not_equal, &true_result, Label::kNear); |
- __ fldz(); |
- __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
- __ FCmp(); |
- __ j(zero, &false_result, Label::kNear); |
- // Fall through to |true_result|. |
+ if (types_.Contains(SPEC_OBJECT)) { |
+ // spec object -> true. |
+ Label not_js_object; |
+ __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); |
+ __ j(below, ¬_js_object, Label::kNear); |
+ __ mov(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); |
+ } |
- // Return 1/0 for true/false in tos_. |
- __ bind(&true_result); |
- __ mov(tos_, 1); |
- __ ret(1 * kPointerSize); |
- __ bind(&false_result); |
- __ mov(tos_, 0); |
- __ ret(1 * kPointerSize); |
+ if (types_.Contains(STRING)) { |
+ // String value -> false iff empty. |
+ Label not_string; |
+ __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); |
+ __ j(above_equal, ¬_string, Label::kNear); |
+ __ mov(eax, FieldOperand(eax, String::kLengthOffset)); |
danno
2011/07/21 12:39:07
eax -> tos_?
Sven Panne
2011/07/21 13:49:28
Ooops, fixed, same for Smi part above.
|
+ __ 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)) { |
+ // heap number -> false iff +0, -0, or NaN. |
+ Label not_heap_number, false_result; |
+ __ cmp(map, factory->heap_number_map()); |
+ __ j(not_equal, ¬_heap_number, Label::kNear); |
+ __ fldz(); |
+ __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
+ __ FCmp(); |
+ __ j(zero, &false_result, Label::kNear); |
+ __ mov(tos_, 1); |
+ __ ret(1 * kPointerSize); |
+ __ bind(&false_result); |
+ __ xor_(tos_, Operand(tos_)); |
+ __ 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)) { |
fschneider
2011/07/21 13:16:44
Can you explain why we need the INTERNAL_OBJECT ca
Sven Panne
2011/07/21 13:49:28
While we probably can't encounter internal objects
|
+ // internal objects -> true |
+ __ mov(tos_, 1); |
+ __ ret(1 * kPointerSize); |
+ } |
+ |
+ __ bind(&patch); |
+ GenerateTypeTransition(masm); |
} |
+void ToBooleanStub::CheckOddball(MacroAssembler* masm, |
+ Type type, |
+ Handle<Object> value, |
+ bool result, |
+ Label* patch) { |
+ __ cmp(eax, value); |
danno
2011/07/21 12:39:07
This should be duplicated in the two if branches s
Sven Panne
2011/07/21 13:49:28
Done.
|
+ if (types_.Contains(type)) { |
+ // If we see an expected oddball, return its ToBoolean value tos_. |
+ Label different_value; |
+ __ j(not_equal, &different_value, Label::kNear); |
+ if (result) { |
+ __ mov(tos_, 1); |
+ } else { |
+ __ xor_(tos_, Operand(tos_)); |
+ } |
+ __ 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. |
+ __ j(equal, patch); |
+ } |
+} |
+ |
+ |
+void ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) { |
+ __ pop(ecx); // Get return address, operand is now on top of stack. |
+ __ push(Immediate(Smi::FromInt(tos_.code()))); |
+ __ push(Immediate(Smi::FromInt(types_.ToInt()))); |
+ __ push(ecx); // Push return address. |
+ // Patch the caller to an appropriate specialized stub and return the |
+ // operation result to the caller of the stub. |
+ __ TailCallExternalReference( |
+ ExternalReference(IC_Utility(IC::kToBoolean_Patch), masm->isolate()), |
+ 3, |
+ 1); |
+} |
+ |
+ |
class FloatingPointHelper : public AllStatic { |
public: |
enum ArgLocation { |