| Index: src/x64/lithium-codegen-x64.cc
|
| diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
|
| index 151fad7362f525efa5212a294263509a60aa8461..9938ff0fe0c09a5be482ad8d5e12962569e95ab5 100644
|
| --- a/src/x64/lithium-codegen-x64.cc
|
| +++ b/src/x64/lithium-codegen-x64.cc
|
| @@ -930,12 +930,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);
|
| + }
|
| + }
|
| }
|
|
|
|
|
| @@ -979,7 +1053,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) {
|
| Condition cond = no_condition;
|
| switch (op) {
|
| case Token::EQ:
|
| @@ -1008,17 +1082,64 @@ Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
|
|
|
|
|
| void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) {
|
| - Abort("Unimplemented: %s", "EmitCmpI");
|
| + if (right->IsConstantOperand()) {
|
| + int32_t value = ToInteger32(LConstantOperand::cast(right));
|
| + if (left->IsRegister()) {
|
| + __ cmpl(ToRegister(left), Immediate(value));
|
| + } else {
|
| + __ cmpl(ToOperand(left), Immediate(value));
|
| + }
|
| + } 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);
|
| }
|
|
|
|
|
| @@ -1028,7 +1149,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);
|
| }
|
|
|
|
|
| @@ -1038,7 +1165,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);
|
| + }
|
| }
|
|
|
|
|
| @@ -1047,7 +1206,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;
|
| }
|
|
|
| @@ -1058,7 +1235,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);
|
| }
|
|
|
|
|
| @@ -1068,7 +1256,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;
|
| }
|
|
|
|
|
| @@ -1078,7 +1297,17 @@ void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) {
|
|
|
|
|
| void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
|
| - Abort("Unimplemented: %s", "DoHasInstanceTypeAndBranch");
|
| + 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* false_label = chunk_->GetAssemblyLabel(false_block);
|
| +
|
| + __ JumpIfSmi(input, false_label);
|
| +
|
| + __ CmpObjectType(input, TestType(instr->hydrogen()), kScratchRegister);
|
| + EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen()));
|
| }
|
|
|
|
|
| @@ -1089,19 +1318,68 @@ 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);
|
| }
|
|
|
|
|
| -// Branches to a label or falls through with the answer in the z flag. Trashes
|
| -// the temp registers, but not the input. Only input and temp2 may alias.
|
| +// Branches to a label or falls through with the answer in the z flag.
|
| +// Trashes the temp register and possibly input (if it and temp are aliased).
|
| 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");
|
| + Register temp) {
|
| + __ 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, kScratchRegister);
|
| + 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.
|
| + // 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.
|
| + ASSERT(class_name->IsSymbol());
|
| + __ Cmp(temp, class_name);
|
| + // End with the answer in the z flag.
|
| }
|
|
|
|
|
| @@ -1111,7 +1389,19 @@ 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));
|
| + 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);
|
| +
|
| + EmitBranch(true_block, false_block, equal);
|
| }
|
|
|
|
|
| @@ -1126,7 +1416,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);
|
| }
|
|
|
|
|
| @@ -1142,12 +1438,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);
|
| }
|
|
|
|
|
| @@ -1494,7 +1820,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);
|
| }
|
|
|
|
|
| @@ -1502,8 +1839,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())) {
|
| + __ CompareRoot(input, Heap::kTrueValueRootIndex);
|
| + __ j(equal, true_label);
|
| + __ CompareRoot(input, Heap::kFalseValueRootIndex);
|
| + final_branch_condition = equal;
|
| +
|
| + } else if (type_name->Equals(Heap::undefined_symbol())) {
|
| + __ CompareRoot(input, Heap::kUndefinedValueRootIndex);
|
| + __ 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;
|
| }
|
|
|
|
|
|
|