diff --git a/src/arm/fast-codegen-arm.cc b/src/arm/fast-codegen-arm.cc index d410a50e45..d21d624f0b 100644 --- a/src/arm/fast-codegen-arm.cc +++ b/src/arm/fast-codegen-arm.cc @@ -1110,4 +1110,169 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { } +void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { + ASSERT_EQ(Expression::kValue, expr->left()->context()); + ASSERT_EQ(Expression::kValue, expr->right()->context()); + Visit(expr->left()); + Visit(expr->right()); + + // Convert current context to test context: Pre-test code. + Label push_true; + Label push_false; + Label done; + Label* saved_true = true_label_; + Label* saved_false = false_label_; + switch (expr->context()) { + case Expression::kUninitialized: + UNREACHABLE(); + break; + + case Expression::kValue: + true_label_ = &push_true; + false_label_ = &push_false; + break; + + case Expression::kEffect: + true_label_ = &done; + false_label_ = &done; + break; + + case Expression::kTest: + break; + + case Expression::kValueTest: + true_label_ = &push_true; + break; + + case Expression::kTestValue: + false_label_ = &push_false; + break; + } + // Convert current context to test context: End pre-test code. + + switch (expr->op()) { + case Token::IN: { + __ InvokeBuiltin(Builtins::IN, CALL_JS); + __ LoadRoot(ip, Heap::kTrueValueRootIndex); + __ cmp(r0, ip); + __ b(eq, true_label_); + __ jmp(false_label_); + break; + } + + case Token::INSTANCEOF: { + InstanceofStub stub; + __ CallStub(&stub); + __ tst(r0, r0); + __ b(eq, true_label_); // The stub returns 0 for true. + __ jmp(false_label_); + break; + } + + default: { + Condition cc = eq; + bool strict = false; + switch (expr->op()) { + case Token::EQ_STRICT: + strict = true; + // Fall through + case Token::EQ: + cc = eq; + __ pop(r0); + __ pop(r1); + break; + case Token::LT: + cc = lt; + __ pop(r0); + __ pop(r1); + break; + case Token::GT: + // Reverse left and right sizes to obtain ECMA-262 conversion order. + cc = lt; + __ pop(r1); + __ pop(r0); + break; + case Token::LTE: + // Reverse left and right sizes to obtain ECMA-262 conversion order. + cc = ge; + __ pop(r1); + __ pop(r0); + break; + case Token::GTE: + cc = ge; + __ pop(r0); + __ pop(r1); + break; + case Token::IN: + case Token::INSTANCEOF: + default: + UNREACHABLE(); + } + + // The comparison stub expects the smi vs. smi case to be handled + // before it is called. + Label slow_case; + __ orr(r2, r0, Operand(r1)); + __ tst(r2, Operand(kSmiTagMask)); + __ b(ne, &slow_case); + __ cmp(r1, r0); + __ b(cc, true_label_); + __ jmp(false_label_); + + __ bind(&slow_case); + CompareStub stub(cc, strict); + __ CallStub(&stub); + __ tst(r0, r0); + __ b(cc, true_label_); + __ jmp(false_label_); + } + } + + // Convert current context to test context: Post-test code. + switch (expr->context()) { + case Expression::kUninitialized: + UNREACHABLE(); + break; + + case Expression::kValue: + __ bind(&push_true); + __ LoadRoot(ip, Heap::kTrueValueRootIndex); + __ push(ip); + __ jmp(&done); + __ bind(&push_false); + __ LoadRoot(ip, Heap::kFalseValueRootIndex); + __ push(ip); + __ bind(&done); + break; + + case Expression::kEffect: + __ bind(&done); + break; + + case Expression::kTest: + break; + + case Expression::kValueTest: + __ bind(&push_true); + __ LoadRoot(ip, Heap::kTrueValueRootIndex); + __ push(ip); + __ jmp(saved_true); + break; + + case Expression::kTestValue: + __ bind(&push_false); + __ LoadRoot(ip, Heap::kFalseValueRootIndex); + __ push(ip); + __ jmp(saved_false); + break; + } + true_label_ = saved_true; + false_label_ = saved_false; + // Convert current context to test context: End post-test code. +} + + +#undef __ + + } } // namespace v8::internal diff --git a/src/compiler.cc b/src/compiler.cc index 837a02b049..2fa41c48bc 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -969,7 +969,9 @@ void CodeGenSelector::VisitBinaryOperation(BinaryOperation* expr) { void CodeGenSelector::VisitCompareOperation(CompareOperation* expr) { - BAILOUT("CompareOperation"); + ProcessExpression(expr->left(), Expression::kValue); + CHECK_BAILOUT; + ProcessExpression(expr->right(), Expression::kValue); } diff --git a/src/fast-codegen.cc b/src/fast-codegen.cc index 6d4606b102..3ea2782528 100644 --- a/src/fast-codegen.cc +++ b/src/fast-codegen.cc @@ -501,11 +501,6 @@ void FastCodeGenerator::VisitThrow(Throw* expr) { } -void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { - UNREACHABLE(); -} - - void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) { UNREACHABLE(); } diff --git a/src/ia32/fast-codegen-ia32.cc b/src/ia32/fast-codegen-ia32.cc index e049dba23c..d512fa211e 100644 --- a/src/ia32/fast-codegen-ia32.cc +++ b/src/ia32/fast-codegen-ia32.cc @@ -1124,6 +1124,164 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { } +void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { + ASSERT_EQ(Expression::kValue, expr->left()->context()); + ASSERT_EQ(Expression::kValue, expr->right()->context()); + Visit(expr->left()); + Visit(expr->right()); + + // Convert current context to test context: Pre-test code. + Label push_true; + Label push_false; + Label done; + Label* saved_true = true_label_; + Label* saved_false = false_label_; + switch (expr->context()) { + case Expression::kUninitialized: + UNREACHABLE(); + break; + + case Expression::kValue: + true_label_ = &push_true; + false_label_ = &push_false; + break; + + case Expression::kEffect: + true_label_ = &done; + false_label_ = &done; + break; + + case Expression::kTest: + break; + + case Expression::kValueTest: + true_label_ = &push_true; + break; + + case Expression::kTestValue: + false_label_ = &push_false; + break; + } + // Convert current context to test context: End pre-test code. + + switch (expr->op()) { + case Token::IN: { + __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); + __ cmp(eax, Factory::true_value()); + __ j(equal, true_label_); + __ jmp(false_label_); + break; + } + + case Token::INSTANCEOF: { + InstanceofStub stub; + __ CallStub(&stub); + __ test(eax, Operand(eax)); + __ j(zero, true_label_); // The stub returns 0 for true. + __ jmp(false_label_); + break; + } + + default: { + Condition cc = no_condition; + bool strict = false; + switch (expr->op()) { + case Token::EQ_STRICT: + strict = true; + // Fall through + case Token::EQ: + cc = equal; + __ pop(eax); + __ pop(edx); + break; + case Token::LT: + cc = less; + __ pop(eax); + __ pop(edx); + break; + case Token::GT: + // Reverse left and right sizes to obtain ECMA-262 conversion order. + cc = less; + __ pop(edx); + __ pop(eax); + break; + case Token::LTE: + // Reverse left and right sizes to obtain ECMA-262 conversion order. + cc = greater_equal; + __ pop(edx); + __ pop(eax); + break; + case Token::GTE: + cc = greater_equal; + __ pop(eax); + __ pop(edx); + break; + case Token::IN: + case Token::INSTANCEOF: + default: + UNREACHABLE(); + } + + // The comparison stub expects the smi vs. smi case to be handled + // before it is called. + Label slow_case; + __ mov(ecx, Operand(edx)); + __ or_(ecx, Operand(eax)); + __ test(ecx, Immediate(kSmiTagMask)); + __ j(not_zero, &slow_case, not_taken); + __ cmp(edx, Operand(eax)); + __ j(cc, true_label_); + __ jmp(false_label_); + + __ bind(&slow_case); + CompareStub stub(cc, strict); + __ CallStub(&stub); + __ test(eax, Operand(eax)); + __ j(cc, true_label_); + __ jmp(false_label_); + } + } + + // Convert current context to test context: Post-test code. + switch (expr->context()) { + case Expression::kUninitialized: + UNREACHABLE(); + break; + + case Expression::kValue: + __ bind(&push_true); + __ push(Immediate(Factory::true_value())); + __ jmp(&done); + __ bind(&push_false); + __ push(Immediate(Factory::false_value())); + __ bind(&done); + break; + + case Expression::kEffect: + __ bind(&done); + break; + + case Expression::kTest: + break; + + case Expression::kValueTest: + __ bind(&push_true); + __ push(Immediate(Factory::true_value())); + __ jmp(saved_true); + break; + + case Expression::kTestValue: + __ bind(&push_false); + __ push(Immediate(Factory::false_value())); + __ jmp(saved_false); + break; + } + true_label_ = saved_true; + false_label_ = saved_false; + // Convert current context to test context: End post-test code. +} + + #undef __ diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc index 397e964261..0721ede00a 100644 --- a/src/x64/codegen-x64.cc +++ b/src/x64/codegen-x64.cc @@ -6580,11 +6580,11 @@ void InstanceofStub::Generate(MacroAssembler* masm) { __ jmp(&loop); __ bind(&is_instance); - __ xor_(rax, rax); + __ xorl(rax, rax); __ ret(2 * kPointerSize); __ bind(&is_not_instance); - __ Move(rax, Smi::FromInt(1)); + __ movl(rax, Immediate(1)); __ ret(2 * kPointerSize); // Slow-case: Go through the JavaScript implementation. diff --git a/src/x64/fast-codegen-x64.cc b/src/x64/fast-codegen-x64.cc index 5df9146231..d5381a210c 100644 --- a/src/x64/fast-codegen-x64.cc +++ b/src/x64/fast-codegen-x64.cc @@ -1138,4 +1138,162 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { } +void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { + ASSERT_EQ(Expression::kValue, expr->left()->context()); + ASSERT_EQ(Expression::kValue, expr->right()->context()); + Visit(expr->left()); + Visit(expr->right()); + + // Convert current context to test context: Pre-test code. + Label push_true; + Label push_false; + Label done; + Label* saved_true = true_label_; + Label* saved_false = false_label_; + switch (expr->context()) { + case Expression::kUninitialized: + UNREACHABLE(); + break; + + case Expression::kValue: + true_label_ = &push_true; + false_label_ = &push_false; + break; + + case Expression::kEffect: + true_label_ = &done; + false_label_ = &done; + break; + + case Expression::kTest: + break; + + case Expression::kValueTest: + true_label_ = &push_true; + break; + + case Expression::kTestValue: + false_label_ = &push_false; + break; + } + // Convert current context to test context: End pre-test code. + + switch (expr->op()) { + case Token::IN: { + __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); + __ CompareRoot(rax, Heap::kTrueValueRootIndex); + __ j(equal, true_label_); + __ jmp(false_label_); + break; + } + + case Token::INSTANCEOF: { + InstanceofStub stub; + __ CallStub(&stub); + __ testq(rax, rax); + __ j(zero, true_label_); // The stub returns 0 for true. + __ jmp(false_label_); + break; + } + + default: { + Condition cc = no_condition; + bool strict = false; + switch (expr->op()) { + case Token::EQ_STRICT: + strict = true; + // Fall through + case Token::EQ: + cc = equal; + __ pop(rax); + __ pop(rdx); + break; + case Token::LT: + cc = less; + __ pop(rax); + __ pop(rdx); + break; + case Token::GT: + // Reverse left and right sizes to obtain ECMA-262 conversion order. + cc = less; + __ pop(rdx); + __ pop(rax); + break; + case Token::LTE: + // Reverse left and right sizes to obtain ECMA-262 conversion order. + cc = greater_equal; + __ pop(rdx); + __ pop(rax); + break; + case Token::GTE: + cc = greater_equal; + __ pop(rax); + __ pop(rdx); + break; + case Token::IN: + case Token::INSTANCEOF: + default: + UNREACHABLE(); + } + + // The comparison stub expects the smi vs. smi case to be handled + // before it is called. + Label slow_case; + __ JumpIfNotBothSmi(rax, rdx, &slow_case); + __ SmiCompare(rdx, rax); + __ j(cc, true_label_); + __ jmp(false_label_); + + __ bind(&slow_case); + CompareStub stub(cc, strict); + __ CallStub(&stub); + __ testq(rax, rax); + __ j(cc, true_label_); + __ jmp(false_label_); + } + } + + // Convert current context to test context: Post-test code. + switch (expr->context()) { + case Expression::kUninitialized: + UNREACHABLE(); + break; + + case Expression::kValue: + __ bind(&push_true); + __ PushRoot(Heap::kTrueValueRootIndex); + __ jmp(&done); + __ bind(&push_false); + __ PushRoot(Heap::kFalseValueRootIndex); + __ bind(&done); + break; + + case Expression::kEffect: + __ bind(&done); + break; + + case Expression::kTest: + break; + + case Expression::kValueTest: + __ bind(&push_true); + __ PushRoot(Heap::kTrueValueRootIndex); + __ jmp(saved_true); + break; + + case Expression::kTestValue: + __ bind(&push_false); + __ PushRoot(Heap::kFalseValueRootIndex); + __ jmp(saved_false); + break; + } + true_label_ = saved_true; + false_label_ = saved_false; + // Convert current context to test context: End post-test code. +} + + +#undef __ + + } } // namespace v8::internal