From 1816e05dc21803f2b2c642abf57e61b04da7761c Mon Sep 17 00:00:00 2001 From: "kasperl@chromium.org" Date: Wed, 25 Aug 2010 14:22:03 +0000 Subject: [PATCH] Prepare for optionally inlining smi cases in the code generated by the full codegens. Review URL: http://codereview.chromium.org/3116042 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5343 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/full-codegen-arm.cc | 74 ++++++++++++++++---------------- src/full-codegen.cc | 12 ++++-- src/ia32/full-codegen-ia32.cc | 80 +++++++++++++++++------------------ src/x64/full-codegen-x64.cc | 67 +++++++++++++++-------------- 4 files changed, 119 insertions(+), 114 deletions(-) diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index a0505a7a67..61fbd76415 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -665,19 +665,20 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { // Compile the label expression. VisitForValue(clause->label(), kAccumulator); - // Perform the comparison as if via '==='. The comparison stub expects - // the smi vs. smi case to be handled before it is called. - Label slow_case; + // Perform the comparison as if via '==='. __ ldr(r1, MemOperand(sp, 0)); // Switch value. - __ orr(r2, r1, r0); - __ tst(r2, Operand(kSmiTagMask)); - __ b(ne, &slow_case); - __ cmp(r1, r0); - __ b(ne, &next_test); - __ Drop(1); // Switch value is no longer needed. - __ b(clause->body_target()->entry_label()); - + if (ShouldInlineSmiCase(Token::EQ_STRICT)) { + Label slow_case; + __ orr(r2, r1, r0); + __ tst(r2, Operand(kSmiTagMask)); + __ b(ne, &slow_case); + __ cmp(r1, r0); + __ b(ne, &next_test); + __ Drop(1); // Switch value is no longer needed. + __ b(clause->body_target()->entry_label()); __ bind(&slow_case); + } + CompareStub stub(eq, true, kBothCouldBeNaN, true, r1, r0); __ CallStub(&stub); __ cmp(r0, Operand(0)); @@ -2672,26 +2673,26 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { case Token::BIT_NOT: { Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)"); - bool can_overwrite = expr->expression()->ResultOverwriteAllowed(); - UnaryOverwriteMode overwrite = - can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; - GenericUnaryOpStub stub(Token::BIT_NOT, overwrite); - // GenericUnaryOpStub expects the argument to be in the - // accumulator register r0. + // The generic unary operation stub expects the argument to be + // in the accumulator register r0. VisitForValue(expr->expression(), kAccumulator); - // Avoid calling the stub for Smis. - Label smi, done; - __ BranchOnSmi(result_register(), &smi); - // Non-smi: call stub leaving result in accumulator register. + Label done; + if (ShouldInlineSmiCase(expr->op())) { + Label call_stub; + __ BranchOnNotSmi(r0, &call_stub); + __ mvn(r0, Operand(r0)); + // Bit-clear inverted smi-tag. + __ bic(r0, r0, Operand(kSmiTagMask)); + __ b(&done); + __ bind(&call_stub); + } + bool overwrite = expr->expression()->ResultOverwriteAllowed(); + UnaryOverwriteMode mode = + overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; + GenericUnaryOpStub stub(Token::BIT_NOT, mode); __ CallStub(&stub); - __ b(&done); - // Perform operation directly on Smis. - __ bind(&smi); - __ mvn(result_register(), Operand(result_register())); - // Bit-clear inverted smi-tag. - __ bic(result_register(), result_register(), Operand(kSmiTagMask)); __ bind(&done); - Apply(context_, result_register()); + Apply(context_, r0); break; } @@ -3055,16 +3056,15 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { 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)); - __ BranchOnNotSmi(r2, &slow_case); - __ cmp(r1, r0); - __ b(cc, if_true); - __ jmp(if_false); + if (ShouldInlineSmiCase(op)) { + Label slow_case; + __ orr(r2, r0, Operand(r1)); + __ BranchOnNotSmi(r2, &slow_case); + __ cmp(r1, r0); + Split(cc, if_true, if_false, NULL); + __ bind(&slow_case); + } - __ bind(&slow_case); CompareStub stub(cc, strict, kBothCouldBeNaN, true, r1, r0); __ CallStub(&stub); __ cmp(r0, Operand(0)); diff --git a/src/full-codegen.cc b/src/full-codegen.cc index c33f1f90d5..65c1e2adea 100644 --- a/src/full-codegen.cc +++ b/src/full-codegen.cc @@ -318,9 +318,15 @@ int FullCodeGenerator::SlotOffset(Slot* slot) { bool FullCodeGenerator::ShouldInlineSmiCase(Token::Value op) { - if (Debugger::IsDebuggerActive()) return false; - if (op == Token::DIV ||op == Token::MOD) return false; - return loop_depth_ > 0; + // TODO(kasperl): Once the compare stub allows leaving out the + // inlined smi case, we should get rid of this check. + if (Token::IsCompareOp(op)) return true; + // TODO(kasperl): Once the unary bit not stub allows leaving out + // the inlined smi case, we should get rid of this check. + if (op == Token::BIT_NOT) return true; + // Inline smi case inside loops, but not division and modulo which + // are too complicated and take up too much space. + return (op != Token::DIV) && (op != Token::MOD) && (loop_depth_ > 0); } diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index d804ce97d5..de772f88d3 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -668,20 +668,21 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { // Compile the label expression. VisitForValue(clause->label(), kAccumulator); - // Perform the comparison as if via '==='. The comparison stub expects - // the smi vs. smi case to be handled before it is called. - Label slow_case; + // Perform the comparison as if via '==='. __ mov(edx, Operand(esp, 0)); // Switch value. - __ mov(ecx, edx); - __ or_(ecx, Operand(eax)); - __ test(ecx, Immediate(kSmiTagMask)); - __ j(not_zero, &slow_case, not_taken); - __ cmp(edx, Operand(eax)); - __ j(not_equal, &next_test); - __ Drop(1); // Switch value is no longer needed. - __ jmp(clause->body_target()->entry_label()); + if (ShouldInlineSmiCase(Token::EQ_STRICT)) { + Label slow_case; + __ mov(ecx, edx); + __ or_(ecx, Operand(eax)); + __ test(ecx, Immediate(kSmiTagMask)); + __ j(not_zero, &slow_case, not_taken); + __ cmp(edx, Operand(eax)); + __ j(not_equal, &next_test); + __ Drop(1); // Switch value is no longer needed. + __ jmp(clause->body_target()->entry_label()); + __ bind(&slow_case); + } - __ bind(&slow_case); CompareStub stub(equal, true); __ CallStub(&stub); __ test(eax, Operand(eax)); @@ -2672,26 +2673,26 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { case Token::BIT_NOT: { Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)"); - bool can_overwrite = expr->expression()->ResultOverwriteAllowed(); - UnaryOverwriteMode overwrite = - can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; - GenericUnaryOpStub stub(Token::BIT_NOT, overwrite); - // GenericUnaryOpStub expects the argument to be in the - // accumulator register eax. + // The generic unary operation stub expects the argument to be + // in the accumulator register eax. VisitForValue(expr->expression(), kAccumulator); - // Avoid calling the stub for Smis. - Label smi, done; - __ test(result_register(), Immediate(kSmiTagMask)); - __ j(zero, &smi); - // Non-smi: call stub leaving result in accumulator register. + Label done; + if (ShouldInlineSmiCase(expr->op())) { + Label call_stub; + __ test(eax, Immediate(kSmiTagMask)); + __ j(not_zero, &call_stub); + __ lea(eax, Operand(eax, kSmiTagMask)); + __ not_(eax); + __ jmp(&done); + __ bind(&call_stub); + } + bool overwrite = expr->expression()->ResultOverwriteAllowed(); + UnaryOverwriteMode mode = + overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; + GenericUnaryOpStub stub(Token::BIT_NOT, mode); __ CallStub(&stub); - __ jmp(&done); - // Perform operation directly on Smis. - __ bind(&smi); - __ not_(result_register()); - __ and_(result_register(), ~kSmiTagMask); // Remove inverted smi-tag. __ bind(&done); - Apply(context_, result_register()); + Apply(context_, eax); break; } @@ -3066,18 +3067,17 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { 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, if_true); - __ jmp(if_false); + if (ShouldInlineSmiCase(op)) { + 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)); + Split(cc, if_true, if_false, NULL); + __ bind(&slow_case); + } - __ bind(&slow_case); CompareStub stub(cc, strict); __ CallStub(&stub); __ test(eax, Operand(eax)); diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index 45e721af19..4eadac7eac 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -672,17 +672,18 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { // Compile the label expression. VisitForValue(clause->label(), kAccumulator); - // Perform the comparison as if via '==='. The comparison stub expects - // the smi vs. smi case to be handled before it is called. - Label slow_case; - __ movq(rdx, Operand(rsp, 0)); // Switch value. - __ JumpIfNotBothSmi(rdx, rax, &slow_case); - __ SmiCompare(rdx, rax); - __ j(not_equal, &next_test); - __ Drop(1); // Switch value is no longer needed. - __ jmp(clause->body_target()->entry_label()); + // Perform the comparison as if via '==='. + if (ShouldInlineSmiCase(Token::EQ_STRICT)) { + Label slow_case; + __ movq(rdx, Operand(rsp, 0)); // Switch value. + __ JumpIfNotBothSmi(rdx, rax, &slow_case); + __ SmiCompare(rdx, rax); + __ j(not_equal, &next_test); + __ Drop(1); // Switch value is no longer needed. + __ jmp(clause->body_target()->entry_label()); + __ bind(&slow_case); + } - __ bind(&slow_case); CompareStub stub(equal, true); __ CallStub(&stub); __ testq(rax, rax); @@ -2667,25 +2668,24 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { case Token::BIT_NOT: { Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)"); - bool can_overwrite = expr->expression()->ResultOverwriteAllowed(); - UnaryOverwriteMode overwrite = - can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; - GenericUnaryOpStub stub(Token::BIT_NOT, overwrite); - // GenericUnaryOpStub expects the argument to be in the - // accumulator register rax. + // The generic unary operation stub expects the argument to be + // in the accumulator register rax. VisitForValue(expr->expression(), kAccumulator); - // Avoid calling the stub for Smis. - Label smi, done; - Condition is_smi = masm_->CheckSmi(result_register()); - __ j(is_smi, &smi); - // Non-smi: call stub leaving result in accumulator register. + Label done; + if (ShouldInlineSmiCase(expr->op())) { + Label call_stub; + __ JumpIfNotSmi(rax, &call_stub); + __ SmiNot(rax, rax); + __ jmp(&done); + __ bind(&call_stub); + } + bool overwrite = expr->expression()->ResultOverwriteAllowed(); + UnaryOverwriteMode mode = + overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; + GenericUnaryOpStub stub(Token::BIT_NOT, mode); __ CallStub(&stub); - __ jmp(&done); - // Perform operation directly on Smis. - __ bind(&smi); - __ SmiNot(result_register(), result_register()); __ bind(&done); - Apply(context_, result_register()); + Apply(context_, rax); break; } @@ -3054,15 +3054,14 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { 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, if_true); - __ jmp(if_false); + if (ShouldInlineSmiCase(op)) { + Label slow_case; + __ JumpIfNotBothSmi(rax, rdx, &slow_case); + __ SmiCompare(rdx, rax); + Split(cc, if_true, if_false, NULL); + __ bind(&slow_case); + } - __ bind(&slow_case); CompareStub stub(cc, strict); __ CallStub(&stub); __ testq(rax, rax);