Chromium Code Reviews| 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 { |