Chromium Code Reviews| Index: src/x64/lithium-codegen-x64.cc |
| diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc |
| index e06b536295c4af0e5f50995f9f1ad9e065e4f49b..32be135b06ce0f862fbe25ed3aca31fe38e12f9c 100644 |
| --- a/src/x64/lithium-codegen-x64.cc |
| +++ b/src/x64/lithium-codegen-x64.cc |
| @@ -909,12 +909,86 @@ int LCodeGen::GetNextEmittedBlock(int block) { |
| void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) { |
| - Abort("Unimplemented: %s", "EmitBranch"); |
| + int next_block = GetNextEmittedBlock(current_block_); |
| + right_block = chunk_->LookupDestination(right_block); |
| + left_block = chunk_->LookupDestination(left_block); |
| + |
| + if (right_block == left_block) { |
| + EmitGoto(left_block); |
| + } else if (left_block == next_block) { |
| + __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block)); |
| + } else if (right_block == next_block) { |
| + __ j(cc, chunk_->GetAssemblyLabel(left_block)); |
| + } else { |
| + __ j(cc, chunk_->GetAssemblyLabel(left_block)); |
| + if (cc != always) { |
| + __ jmp(chunk_->GetAssemblyLabel(right_block)); |
| + } |
| + } |
| } |
| void LCodeGen::DoBranch(LBranch* instr) { |
| - Abort("Unimplemented: %s", "DoBranch"); |
| + int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| + int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| + |
| + Representation r = instr->hydrogen()->representation(); |
| + if (r.IsInteger32()) { |
| + Register reg = ToRegister(instr->InputAt(0)); |
| + __ testl(reg, reg); |
| + EmitBranch(true_block, false_block, not_zero); |
| + } else if (r.IsDouble()) { |
| + XMMRegister reg = ToDoubleRegister(instr->InputAt(0)); |
| + __ xorpd(xmm0, xmm0); |
| + __ ucomisd(reg, xmm0); |
| + EmitBranch(true_block, false_block, not_equal); |
| + } else { |
| + ASSERT(r.IsTagged()); |
| + Register reg = ToRegister(instr->InputAt(0)); |
| + HType type = instr->hydrogen()->type(); |
| + if (type.IsBoolean()) { |
| + __ Cmp(reg, Factory::true_value()); |
| + EmitBranch(true_block, false_block, equal); |
| + } else if (type.IsSmi()) { |
| + __ SmiCompare(reg, Smi::FromInt(0)); |
| + EmitBranch(true_block, false_block, not_equal); |
| + } else { |
| + Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| + Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| + |
| + __ Cmp(reg, Factory::undefined_value()); |
| + __ j(equal, false_label); |
| + __ Cmp(reg, Factory::true_value()); |
| + __ j(equal, true_label); |
| + __ Cmp(reg, Factory::false_value()); |
| + __ j(equal, false_label); |
| + __ SmiCompare(reg, Smi::FromInt(0)); |
| + __ j(equal, false_label); |
| + __ JumpIfSmi(reg, true_label); |
| + |
| + // Test for double values. Plus/minus zero are false. NaN is handled |
| + // in the stub. |
| + NearLabel call_stub; |
| + __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), |
| + Factory::heap_number_map()); |
| + __ j(not_equal, &call_stub); |
| + __ movq(kScratchRegister, FieldOperand(reg, HeapNumber::kValueOffset)); |
| + __ shl(kScratchRegister, Immediate(1)); // Shift out the sign bit. |
| + __ j(zero, false_label); // Zero or negative zero. |
| + __ jmp(true_label); |
| + |
| + // The conversion stub doesn't cause garbage collections so it's |
| + // safe to not record a safepoint after the call. |
| + __ bind(&call_stub); |
| + ToBooleanStub stub; |
| + __ Pushad(); |
| + __ push(reg); |
| + __ CallStub(&stub); |
| + __ testq(rax, rax); |
| + __ Popad(); |
| + EmitBranch(true_block, false_block, not_zero); |
| + } |
| + } |
| } |
| @@ -958,7 +1032,7 @@ void LCodeGen::DoGoto(LGoto* instr) { |
| } |
| -Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { |
| +inline Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { |
|
William Hesse
2011/01/18 14:01:50
If this is inline, it should be defined in the hea
Lasse Reichstein
2011/01/19 09:20:35
It's only used in this file, so it's declared here
|
| Condition cond = no_condition; |
| switch (op) { |
| case Token::EQ: |
| @@ -987,17 +1061,63 @@ Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { |
| void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) { |
| - Abort("Unimplemented: %s", "EmitCmpI"); |
| + if (right->IsConstantOperand()) { |
| + if (left->IsRegister()) { |
| + __ Cmp(ToRegister(left), ToHandle(LConstantOperand::cast(right))); |
|
William Hesse
2011/01/18 14:01:50
Shouldn't you use Immediate(Int32Value(LConstantOp
Lasse Reichstein
2011/01/19 09:20:35
I probably should. We know that the constant is a
|
| + } else { |
| + __ Cmp(ToOperand(left), ToHandle(LConstantOperand::cast(right))); |
| + } |
| + } else if (right->IsRegister()) { |
| + __ cmpq(ToRegister(left), ToRegister(right)); |
| + } else { |
| + __ cmpq(ToRegister(left), ToOperand(right)); |
| + } |
| } |
| void LCodeGen::DoCmpID(LCmpID* instr) { |
| - Abort("Unimplemented: %s", "DoCmpID"); |
| + LOperand* left = instr->InputAt(0); |
| + LOperand* right = instr->InputAt(1); |
| + LOperand* result = instr->result(); |
| + |
| + NearLabel unordered; |
| + if (instr->is_double()) { |
| + // Don't base result on EFLAGS when a NaN is involved. Instead |
| + // jump to the unordered case, which produces a false value. |
| + __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); |
| + __ j(parity_even, &unordered); |
| + } else { |
| + EmitCmpI(left, right); |
| + } |
| + |
| + NearLabel done; |
| + Condition cc = TokenToCondition(instr->op(), instr->is_double()); |
| + __ LoadRoot(ToRegister(result), Heap::kTrueValueRootIndex); |
| + __ j(cc, &done); |
| + |
| + __ bind(&unordered); |
| + __ LoadRoot(ToRegister(result), Heap::kFalseValueRootIndex); |
| + __ bind(&done); |
| } |
| void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { |
| - Abort("Unimplemented: %s", "DoCmpIDAndBranch"); |
| + LOperand* left = instr->InputAt(0); |
| + LOperand* right = instr->InputAt(1); |
| + int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| + int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| + |
| + if (instr->is_double()) { |
| + // Don't base result on EFLAGS when a NaN is involved. Instead |
| + // jump to the false block. |
| + __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); |
| + __ j(parity_even, chunk_->GetAssemblyLabel(false_block)); |
| + } else { |
| + EmitCmpI(left, right); |
| + } |
| + |
| + Condition cc = TokenToCondition(instr->op(), instr->is_double()); |
| + EmitBranch(true_block, false_block, cc); |
| } |
| @@ -1007,7 +1127,13 @@ void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) { |
| void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) { |
| - Abort("Unimplemented: %s", "DoCmpJSObjectAndBranch"); |
| + Register left = ToRegister(instr->InputAt(0)); |
| + Register right = ToRegister(instr->InputAt(1)); |
| + int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| + int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| + |
| + __ cmpq(left, right); |
| + EmitBranch(true_block, false_block, equal); |
| } |
| @@ -1017,7 +1143,39 @@ void LCodeGen::DoIsNull(LIsNull* instr) { |
| void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) { |
| - Abort("Unimplemented: %s", "DoIsNullAndBranch"); |
| + Register reg = ToRegister(instr->InputAt(0)); |
| + |
| + int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| + |
| + if (instr->hydrogen()->representation().IsSpecialization() || |
| + instr->hydrogen()->type().IsSmi()) { |
| + // If the expression is known to untagged or smi, then it's definitely |
| + // not null, and it can't be a an undetectable object. |
| + // Jump directly to the false block. |
| + EmitGoto(false_block); |
| + return; |
| + } |
| + |
| + int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| + |
| + __ Cmp(reg, Factory::null_value()); |
| + if (instr->is_strict()) { |
| + EmitBranch(true_block, false_block, equal); |
| + } else { |
| + Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| + Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| + __ j(equal, true_label); |
| + __ Cmp(reg, Factory::undefined_value()); |
| + __ j(equal, true_label); |
| + __ JumpIfSmi(reg, false_label); |
| + // Check for undetectable objects by looking in the bit field in |
| + // the map. The object has already been smi checked. |
| + Register scratch = ToRegister(instr->TempAt(0)); |
| + __ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset)); |
| + __ testb(FieldOperand(scratch, Map::kBitFieldOffset), |
| + Immediate(1 << Map::kIsUndetectable)); |
| + EmitBranch(true_block, false_block, not_zero); |
| + } |
| } |
| @@ -1026,7 +1184,25 @@ Condition LCodeGen::EmitIsObject(Register input, |
| Register temp2, |
| Label* is_not_object, |
| Label* is_object) { |
| - Abort("Unimplemented: %s", "EmitIsObject"); |
| + ASSERT(!input.is(temp1)); |
| + ASSERT(!input.is(temp2)); |
| + ASSERT(!temp1.is(temp2)); |
| + |
| + __ JumpIfSmi(input, is_not_object); |
| + |
| + __ Cmp(input, Factory::null_value()); |
| + __ j(equal, is_object); |
| + |
| + __ movq(temp1, FieldOperand(input, HeapObject::kMapOffset)); |
| + // Undetectable objects behave like undefined. |
| + __ testb(FieldOperand(temp1, Map::kBitFieldOffset), |
| + Immediate(1 << Map::kIsUndetectable)); |
| + __ j(not_zero, is_not_object); |
| + |
| + __ movzxbl(temp2, FieldOperand(temp1, Map::kInstanceTypeOffset)); |
| + __ cmpb(temp2, Immediate(FIRST_JS_OBJECT_TYPE)); |
| + __ j(below, is_not_object); |
| + __ cmpb(temp2, Immediate(LAST_JS_OBJECT_TYPE)); |
| return below_equal; |
| } |
| @@ -1037,7 +1213,18 @@ void LCodeGen::DoIsObject(LIsObject* instr) { |
| void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { |
| - Abort("Unimplemented: %s", "DoIsObjectAndBranch"); |
| + Register reg = ToRegister(instr->InputAt(0)); |
| + Register temp = ToRegister(instr->TempAt(0)); |
| + Register temp2 = ToRegister(instr->TempAt(1)); |
| + |
| + int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| + int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| + Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| + Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| + |
| + Condition true_cond = EmitIsObject(reg, temp, temp2, false_label, true_label); |
| + |
| + EmitBranch(true_block, false_block, true_cond); |
| } |
| @@ -1047,7 +1234,38 @@ void LCodeGen::DoIsSmi(LIsSmi* instr) { |
| void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { |
| - Abort("Unimplemented: %s", "DoIsSmiAndBranch"); |
| + int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| + int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| + |
| + Condition is_smi; |
| + if (instr->InputAt(0)->IsRegister()) { |
| + Register input = ToRegister(instr->InputAt(0)); |
| + is_smi = masm()->CheckSmi(input); |
| + } else { |
| + Operand input = ToOperand(instr->InputAt(0)); |
| + is_smi = masm()->CheckSmi(input); |
| + } |
| + EmitBranch(true_block, false_block, is_smi); |
| +} |
| + |
| + |
| +static InstanceType TestType(HHasInstanceType* instr) { |
| + InstanceType from = instr->from(); |
| + InstanceType to = instr->to(); |
| + if (from == FIRST_TYPE) return to; |
| + ASSERT(from == to || to == LAST_TYPE); |
| + return from; |
| +} |
| + |
| + |
| +static Condition BranchCondition(HHasInstanceType* instr) { |
| + InstanceType from = instr->from(); |
| + InstanceType to = instr->to(); |
| + if (from == to) return equal; |
| + if (to == LAST_TYPE) return above_equal; |
| + if (from == FIRST_TYPE) return below_equal; |
| + UNREACHABLE(); |
| + return equal; |
| } |
| @@ -1057,7 +1275,18 @@ void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) { |
| void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { |
| - Abort("Unimplemented: %s", "DoHasInstanceTypeAndBranch"); |
| + Register input = ToRegister(instr->InputAt(0)); |
| + Register temp = ToRegister(instr->TempAt(0)); |
|
William Hesse
2011/01/18 14:01:50
Unless we are using instr->temp after this instruc
Lasse Reichstein
2011/01/19 09:20:35
It should be safe. We only use it as scratch regis
|
| + |
| + int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| + int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| + |
| + Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| + |
| + __ JumpIfSmi(input, false_label); |
| + |
| + __ CmpObjectType(input, TestType(instr->hydrogen()), temp); |
| + EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen())); |
| } |
| @@ -1068,7 +1297,14 @@ void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) { |
| void LCodeGen::DoHasCachedArrayIndexAndBranch( |
| LHasCachedArrayIndexAndBranch* instr) { |
| - Abort("Unimplemented: %s", "DoHasCachedArrayIndexAndBranch"); |
| + Register input = ToRegister(instr->InputAt(0)); |
| + |
| + int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| + int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| + |
| + __ testl(FieldOperand(input, String::kHashFieldOffset), |
| + Immediate(String::kContainsCachedArrayIndexMask)); |
| + EmitBranch(true_block, false_block, not_equal); |
| } |
| @@ -1076,11 +1312,55 @@ void LCodeGen::DoHasCachedArrayIndexAndBranch( |
| // the temp registers, but not the input. Only input and temp2 may alias. |
| void LCodeGen::EmitClassOfTest(Label* is_true, |
| Label* is_false, |
| - Handle<String>class_name, |
| + Handle<String> class_name, |
| Register input, |
| Register temp, |
| Register temp2) { |
| - Abort("Unimplemented: %s", "EmitClassOfTest"); |
| + ASSERT(!input.is(temp)); |
| + ASSERT(!temp.is(temp2)); // But input and temp2 may be the same register. |
| + __ JumpIfSmi(input, is_false); |
| + __ CmpObjectType(input, FIRST_JS_OBJECT_TYPE, temp); |
| + __ j(below, is_false); |
| + |
| + // Map is now in temp. |
| + // Functions have class 'Function'. |
| + __ CmpInstanceType(temp, JS_FUNCTION_TYPE); |
| + if (class_name->IsEqualTo(CStrVector("Function"))) { |
| + __ j(equal, is_true); |
| + } else { |
| + __ j(equal, is_false); |
| + } |
| + |
| + // Check if the constructor in the map is a function. |
| + __ movq(temp, FieldOperand(temp, Map::kConstructorOffset)); |
| + |
| + // As long as JS_FUNCTION_TYPE is the last instance type and it is |
| + // right after LAST_JS_OBJECT_TYPE, we can avoid checking for |
| + // LAST_JS_OBJECT_TYPE. |
| + ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
| + ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1); |
| + |
| + // Objects with a non-function constructor have class 'Object'. |
| + __ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2); |
|
William Hesse
2011/01/18 14:01:50
We can use kScratchRegister here.
Lasse Reichstein
2011/01/19 09:20:35
We can, but the current implementation uses the fa
Lasse Reichstein
2011/01/19 10:14:53
I removed the second temp register, and just stopp
|
| + if (class_name->IsEqualTo(CStrVector("Object"))) { |
| + __ j(not_equal, is_true); |
| + } else { |
| + __ j(not_equal, is_false); |
| + } |
| + |
| + // temp now contains the constructor function. Grab the |
| + // instance class name from there. |
| + __ movq(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset)); |
| + __ movq(temp, FieldOperand(temp, |
| + SharedFunctionInfo::kInstanceClassNameOffset)); |
| + // The class name we are testing against is a symbol because it's a literal. |
|
William Hesse
2011/01/18 14:01:50
Could we assert that this is a symbol?
Lasse Reichstein
2011/01/19 09:20:35
Done.
|
| + // The name in the constructor is a symbol because of the way the context is |
| + // booted. This routine isn't expected to work for random API-created |
| + // classes and it doesn't have to because you can't access it with natives |
| + // syntax. Since both sides are symbols it is sufficient to use an identity |
| + // comparison. |
| + __ Cmp(temp, class_name); |
| + // End with the answer in the z flag. |
| } |
| @@ -1090,7 +1370,26 @@ void LCodeGen::DoClassOfTest(LClassOfTest* instr) { |
| void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { |
| - Abort("Unimplemented: %s", "DoClassOfTestAndBranch"); |
| + Register input = ToRegister(instr->InputAt(0)); |
| + Register temp = ToRegister(instr->TempAt(0)); |
| + Register temp2 = ToRegister(instr->TempAt(1)); |
| + if (input.is(temp)) { |
| + // Swap. |
| + Register swapper = temp; |
| + temp = temp2; |
|
William Hesse
2011/01/18 14:01:50
We probably don't need two temp registers here.
Lasse Reichstein
2011/01/19 09:20:35
This is the place where we seem that we do need th
|
| + temp2 = swapper; |
| + } |
| + Handle<String> class_name = instr->hydrogen()->class_name(); |
| + |
| + int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| + int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| + |
| + Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| + Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| + |
| + EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2); |
| + |
| + EmitBranch(true_block, false_block, equal); |
| } |
| @@ -1105,7 +1404,13 @@ void LCodeGen::DoInstanceOf(LInstanceOf* instr) { |
| void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) { |
| - Abort("Unimplemented: %s", "DoInstanceOfAndBranch"); |
| + int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| + int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| + |
| + InstanceofStub stub(InstanceofStub::kArgsInRegisters); |
| + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| + __ testq(rax, rax); |
| + EmitBranch(true_block, false_block, zero); |
| } |
| @@ -1121,12 +1426,42 @@ void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, |
| void LCodeGen::DoCmpT(LCmpT* instr) { |
| - Abort("Unimplemented: %s", "DoCmpT"); |
| + Token::Value op = instr->op(); |
| + |
| + Handle<Code> ic = CompareIC::GetUninitialized(op); |
| + CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| + |
| + Condition condition = TokenToCondition(op, false); |
| + if (op == Token::GT || op == Token::LTE) { |
| + condition = ReverseCondition(condition); |
| + } |
| + NearLabel true_value, done; |
| + __ testq(rax, rax); |
| + __ j(condition, &true_value); |
| + __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex); |
| + __ jmp(&done); |
| + __ bind(&true_value); |
| + __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex); |
| + __ bind(&done); |
| } |
| void LCodeGen::DoCmpTAndBranch(LCmpTAndBranch* instr) { |
| - Abort("Unimplemented: %s", "DoCmpTAndBranch"); |
| + Token::Value op = instr->op(); |
| + int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| + int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| + |
| + Handle<Code> ic = CompareIC::GetUninitialized(op); |
| + CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| + |
| + // The compare stub expects compare condition and the input operands |
| + // reversed for GT and LTE. |
| + Condition condition = TokenToCondition(op, false); |
| + if (op == Token::GT || op == Token::LTE) { |
| + condition = ReverseCondition(condition); |
| + } |
| + __ testq(rax, rax); |
| + EmitBranch(true_block, false_block, condition); |
| } |
| @@ -1473,7 +1808,18 @@ void LCodeGen::DoTypeofIs(LTypeofIs* instr) { |
| void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { |
| - Abort("Unimplemented: %s", "DoTypeofIsAndBranch"); |
| + Register input = ToRegister(instr->InputAt(0)); |
| + int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| + int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| + Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| + Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| + |
| + Condition final_branch_condition = EmitTypeofIs(true_label, |
| + false_label, |
| + input, |
| + instr->type_literal()); |
| + |
| + EmitBranch(true_block, false_block, final_branch_condition); |
| } |
| @@ -1481,8 +1827,63 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, |
| Label* false_label, |
| Register input, |
| Handle<String> type_name) { |
| - Abort("Unimplemented: %s", "EmitTypeofIs"); |
| - return no_condition; |
| + Condition final_branch_condition = no_condition; |
| + if (type_name->Equals(Heap::number_symbol())) { |
| + __ JumpIfSmi(input, true_label); |
| + __ Cmp(FieldOperand(input, HeapObject::kMapOffset), |
| + Factory::heap_number_map()); |
| + final_branch_condition = equal; |
| + |
| + } else if (type_name->Equals(Heap::string_symbol())) { |
| + __ JumpIfSmi(input, false_label); |
| + __ movq(input, FieldOperand(input, HeapObject::kMapOffset)); |
| + __ testb(FieldOperand(input, Map::kBitFieldOffset), |
| + Immediate(1 << Map::kIsUndetectable)); |
| + __ j(not_zero, false_label); |
| + __ CmpInstanceType(input, FIRST_NONSTRING_TYPE); |
| + final_branch_condition = below; |
| + |
| + } else if (type_name->Equals(Heap::boolean_symbol())) { |
| + __ Cmp(input, Handle<Object>(Heap::true_value())); |
|
William Hesse
2011/01/18 14:01:50
Can we use the root array here?
Lasse Reichstein
2011/01/19 09:20:35
Done, both.
|
| + __ j(equal, true_label); |
| + __ Cmp(input, Handle<Object>(Heap::false_value())); |
| + final_branch_condition = equal; |
| + |
| + } else if (type_name->Equals(Heap::undefined_symbol())) { |
|
William Hesse
2011/01/18 14:01:50
Root array.
Lasse Reichstein
2011/01/19 09:20:35
Done.
|
| + __ Cmp(input, Factory::undefined_value()); |
| + __ j(equal, true_label); |
| + __ JumpIfSmi(input, false_label); |
| + // Check for undetectable objects => true. |
| + __ movq(input, FieldOperand(input, HeapObject::kMapOffset)); |
| + __ testb(FieldOperand(input, Map::kBitFieldOffset), |
| + Immediate(1 << Map::kIsUndetectable)); |
| + final_branch_condition = not_zero; |
| + |
| + } else if (type_name->Equals(Heap::function_symbol())) { |
| + __ JumpIfSmi(input, false_label); |
| + __ CmpObjectType(input, FIRST_FUNCTION_CLASS_TYPE, input); |
| + final_branch_condition = above_equal; |
| + |
| + } else if (type_name->Equals(Heap::object_symbol())) { |
| + __ JumpIfSmi(input, false_label); |
| + __ Cmp(input, Factory::null_value()); |
| + __ j(equal, true_label); |
| + // Check for undetectable objects => false. |
| + __ testb(FieldOperand(input, Map::kBitFieldOffset), |
| + Immediate(1 << Map::kIsUndetectable)); |
| + __ j(not_zero, false_label); |
| + // Check for JS objects that are not RegExp or Function => true. |
| + __ CmpInstanceType(input, FIRST_JS_OBJECT_TYPE); |
| + __ j(below, false_label); |
| + __ CmpInstanceType(input, FIRST_FUNCTION_CLASS_TYPE); |
| + final_branch_condition = below_equal; |
| + |
| + } else { |
| + final_branch_condition = never; |
| + __ jmp(false_label); |
| + } |
| + |
| + return final_branch_condition; |
| } |