Changeset 51735 in webkit


Ignore:
Timestamp:
Dec 6, 2009 1:42:03 AM (14 years ago)
Author:
mjs@apple.com
Message:

2009-12-05 Maciej Stachowiak <mjs@apple.com>

Reviewed by Oliver Hunt.

conway benchmark spends half it's time in op_less (jump fusion fails)
https://bugs.webkit.org/show_bug.cgi?id=32190

<1% speedup on SunSpider and V8
2x speedup on "conway" benchmark


Two optimizations:

1) Improve codegen for logical operators &&,
and ! in a condition context


When generating code for combinations of &&,
and !, in a

condition context (i.e. in an if statement or loop condition), we
used to produce a value, and then separately jump based on its
truthiness. Now we pass the false and true targets in, and let the
logical operators generate jumps directly. This helps in four
ways:

a) Individual clauses of a short-circuit logical operator can now
jump directly to the then or else clause of an if statement (or to
the top or exit of a loop) instead of jumping to a jump.


b) It used to be that jump fusion with the condition of the first
clause of a logical operator was inhibited, because the register
was ref'd to be used later, in the actual condition jump; this no
longer happens since a jump straight to the final target is
generated directly.

c) It used to be that jump fusion with the condition of the second
clause of a logical operator was inhibited, because there was a
jump target right after the second clause and before the actual
condition jump. But now it's no longer necessary for the first
clause to jump there so jump fusion is not blocked.

d) We avoid generating excess mov statements in some cases.


As a concrete example this source:


if (!((x < q && y < q)
(t < q && z < q))) {

...

}


Used to generate this bytecode:


[ 34] less r1, r-15, r-19
[ 38] jfalse r1, 7(->45)
[ 41] less r1, r-16, r-19
[ 45] jtrue r1, 14(->59)
[ 48] less r1, r-17, r-19
[ 52] jfalse r1, 7(->59)
[ 55] less r1, r-18, r-19
[ 59] jtrue r1, 17(->76)


And now generates this bytecode (also taking advantage of the second optimization below):


[ 34] jnless r-15, r-19, 8(->42)
[ 38] jless r-16, r-19, 26(->64)
[ 42] jnless r-17, r-19, 8(->50)
[ 46] jless r-18, r-19, 18(->64)


Note the jump fusion and the fact that there's less jump
indirection - three of the four jumps go straight to the target
clause instead of indirecting through another jump.


2) Implement jless opcode to take advantage of the above, since we'll now often generate
a less followed by a jtrue where fusion is not forbidden.


  • parser/Nodes.h: (JSC::ExpressionNode::hasConditionContextCodegen): Helper function to determine whether a node supports special conditional codegen. Return false as this is the default. (JSC::ExpressionNode::emitBytecodeInConditionContext): Assert not reached - only really defined for nodes that do have conditional codegen. (JSC::UnaryOpNode::expr): Add const version. (JSC::LogicalNotNode::hasConditionContextCodegen): Returne true only if subexpression supports it. (JSC::LogicalOpNode::hasConditionContextCodegen): Return true.
  • parser/Nodes.cpp: (JSC::LogicalNotNode::emitBytecodeInConditionContext): Implemented - just swap the true and false targets for the child node. (JSC::LogicalOpNode::emitBytecodeInConditionContext): Implemented - handle jumps directly, improving codegen quality. Also handles further nested conditional codegen. (JSC::ConditionalNode::emitBytecode): Use condition context codegen when available. (JSC::IfNode::emitBytecode): ditto (JSC::IfElseNode::emitBytecode): ditto (JSC::DoWhileNode::emitBytecode): ditto (JSC::WhileNode::emitBytecode): ditto (JSC::ForNode::emitBytecode): ditto
  • bytecode/Opcode.h:
  • Added loop_if_false opcode - needed now that falsey jumps can be backwards.
  • Added jless opcode to take advantage of new fusion opportunities.
  • bytecode/CodeBlock.cpp: (JSC::CodeBlock::dump): Handle above.
  • bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::emitJumpIfTrue): Add peephole for less + jtrue ==> jless. (JSC::BytecodeGenerator::emitJumpIfFalse): Add handling of backwrds falsey jumps.
  • bytecompiler/BytecodeGenerator.h: (JSC::BytecodeGenerator::emitNodeInConditionContext): Wrapper to handle tracking of overly deep expressions etc.
  • interpreter/Interpreter.cpp: (JSC::Interpreter::privateExecute): Implement the two new opcodes (loop_if_false, jless).
  • jit/JIT.cpp: (JSC::JIT::privateCompileMainPass): Implement JIT support for the two new opcodes. (JSC::JIT::privateCompileSlowCases): ditto
  • jit/JIT.h:
  • jit/JITArithmetic.cpp: (JSC::JIT::emit_op_jless): (JSC::JIT::emitSlow_op_jless): ditto (JSC::JIT::emitBinaryDoubleOp): ditto
  • jit/JITOpcodes.cpp: (JSC::JIT::emitSlow_op_loop_if_less): ditto (JSC::JIT::emit_op_loop_if_false): ditto (JSC::JIT::emitSlow_op_loop_if_false): ditto
  • jit/JITStubs.cpp:
  • jit/JITStubs.h: (JSC::):

2009-12-05 Maciej Stachowiak <mjs@apple.com>

Reviewed by Oliver Hunt.

conway benchmark spends half it's time in op_less (jump fusion fails)
https://bugs.webkit.org/show_bug.cgi?id=32190

  • fast/js/codegen-loops-logical-nodes-expected.txt:
  • fast/js/script-tests/codegen-loops-logical-nodes.js: Update to test some newly sensitive cases of codegen that were not already covered.
Location:
trunk
Files:
17 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r51724 r51735  
     12009-12-05  Maciej Stachowiak  <mjs@apple.com>
     2
     3        Reviewed by Oliver Hunt.
     4
     5        conway benchmark spends half it's time in op_less (jump fusion fails)
     6        https://bugs.webkit.org/show_bug.cgi?id=32190
     7
     8        <1% speedup on SunSpider and V8
     9        2x speedup on "conway" benchmark
     10       
     11        Two optimizations:
     12        1) Improve codegen for logical operators &&, || and ! in a condition context
     13       
     14        When generating code for combinations of &&, || and !, in a
     15        condition context (i.e. in an if statement or loop condition), we
     16        used to produce a value, and then separately jump based on its
     17        truthiness. Now we pass the false and true targets in, and let the
     18        logical operators generate jumps directly. This helps in four
     19        ways:
     20
     21        a) Individual clauses of a short-circuit logical operator can now
     22        jump directly to the then or else clause of an if statement (or to
     23        the top or exit of a loop) instead of jumping to a jump.
     24       
     25        b) It used to be that jump fusion with the condition of the first
     26        clause of a logical operator was inhibited, because the register
     27        was ref'd to be used later, in the actual condition jump; this no
     28        longer happens since a jump straight to the final target is
     29        generated directly.
     30
     31        c) It used to be that jump fusion with the condition of the second
     32        clause of a logical operator was inhibited, because there was a
     33        jump target right after the second clause and before the actual
     34        condition jump. But now it's no longer necessary for the first
     35        clause to jump there so jump fusion is not blocked.
     36
     37        d) We avoid generating excess mov statements in some cases.
     38       
     39        As a concrete example this source:
     40       
     41        if (!((x < q && y < q) || (t < q && z < q))) {
     42            // ...
     43        }
     44       
     45        Used to generate this bytecode:
     46       
     47        [  34] less              r1, r-15, r-19
     48        [  38] jfalse            r1, 7(->45)
     49        [  41] less              r1, r-16, r-19
     50        [  45] jtrue             r1, 14(->59)
     51        [  48] less              r1, r-17, r-19
     52        [  52] jfalse            r1, 7(->59)
     53        [  55] less              r1, r-18, r-19
     54        [  59] jtrue             r1, 17(->76)
     55       
     56        And now generates this bytecode (also taking advantage of the second optimization below):
     57       
     58        [  34] jnless            r-15, r-19, 8(->42)
     59        [  38] jless             r-16, r-19, 26(->64)
     60        [  42] jnless            r-17, r-19, 8(->50)
     61        [  46] jless             r-18, r-19, 18(->64)
     62       
     63        Note the jump fusion and the fact that there's less jump
     64        indirection - three of the four jumps go straight to the target
     65        clause instead of indirecting through another jump.
     66       
     67        2) Implement jless opcode to take advantage of the above, since we'll now often generate
     68        a less followed by a jtrue where fusion is not forbidden.
     69       
     70        * parser/Nodes.h:
     71        (JSC::ExpressionNode::hasConditionContextCodegen): Helper function to determine
     72        whether a node supports special conditional codegen. Return false as this is the default.
     73        (JSC::ExpressionNode::emitBytecodeInConditionContext): Assert not reached - only really
     74        defined for nodes that do have conditional codegen.
     75        (JSC::UnaryOpNode::expr): Add const version.
     76        (JSC::LogicalNotNode::hasConditionContextCodegen): Returne true only if subexpression
     77        supports it.
     78        (JSC::LogicalOpNode::hasConditionContextCodegen): Return true.
     79        * parser/Nodes.cpp:
     80        (JSC::LogicalNotNode::emitBytecodeInConditionContext): Implemented - just swap
     81        the true and false targets for the child node.
     82        (JSC::LogicalOpNode::emitBytecodeInConditionContext): Implemented - handle jumps
     83        directly, improving codegen quality. Also handles further nested conditional codegen.
     84        (JSC::ConditionalNode::emitBytecode): Use condition context codegen when available.
     85        (JSC::IfNode::emitBytecode): ditto
     86        (JSC::IfElseNode::emitBytecode): ditto
     87        (JSC::DoWhileNode::emitBytecode): ditto
     88        (JSC::WhileNode::emitBytecode): ditto
     89        (JSC::ForNode::emitBytecode): ditto
     90
     91        * bytecode/Opcode.h:
     92        - Added loop_if_false opcode - needed now that falsey jumps can be backwards.
     93        - Added jless opcode to take advantage of new fusion opportunities.
     94        * bytecode/CodeBlock.cpp:
     95        (JSC::CodeBlock::dump): Handle above.
     96        * bytecompiler/BytecodeGenerator.cpp:
     97        (JSC::BytecodeGenerator::emitJumpIfTrue): Add peephole for less + jtrue ==> jless.
     98        (JSC::BytecodeGenerator::emitJumpIfFalse): Add handling of backwrds falsey jumps.
     99        * bytecompiler/BytecodeGenerator.h:
     100        (JSC::BytecodeGenerator::emitNodeInConditionContext): Wrapper to handle tracking of
     101        overly deep expressions etc.
     102        * interpreter/Interpreter.cpp:
     103        (JSC::Interpreter::privateExecute): Implement the two new opcodes (loop_if_false, jless).
     104        * jit/JIT.cpp:
     105        (JSC::JIT::privateCompileMainPass): Implement JIT support for the two new opcodes.
     106        (JSC::JIT::privateCompileSlowCases): ditto
     107        * jit/JIT.h:
     108        * jit/JITArithmetic.cpp:
     109        (JSC::JIT::emit_op_jless):
     110        (JSC::JIT::emitSlow_op_jless): ditto
     111        (JSC::JIT::emitBinaryDoubleOp): ditto
     112        * jit/JITOpcodes.cpp:
     113        (JSC::JIT::emitSlow_op_loop_if_less): ditto
     114        (JSC::JIT::emit_op_loop_if_false): ditto
     115        (JSC::JIT::emitSlow_op_loop_if_false): ditto
     116        * jit/JITStubs.cpp:
     117        * jit/JITStubs.h:
     118        (JSC::):
     119
    11202009-12-04  Kent Hansen  <kent.hansen@nokia.com>
    2121
  • trunk/JavaScriptCore/bytecode/CodeBlock.cpp

    r50538 r51735  
    877877            break;
    878878        }
     879        case op_loop_if_false: {
     880            printConditionalJump(exec, begin, it, location, "loop_if_false");
     881            break;
     882        }
    879883        case op_jfalse: {
    880884            printConditionalJump(exec, begin, it, location, "jfalse");
     
    915919            int offset = (++it)->u.operand;
    916920            printf("[%4d] loop_if_less\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str(), offset, location + offset);
     921            break;
     922        }
     923        case op_jless: {
     924            int r0 = (++it)->u.operand;
     925            int r1 = (++it)->u.operand;
     926            int offset = (++it)->u.operand;
     927            printf("[%4d] jless\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str(), offset, location + offset);
    917928            break;
    918929        }
  • trunk/JavaScriptCore/bytecode/Opcode.h

    r50254 r51735  
    129129        macro(op_jnless, 4) \
    130130        macro(op_jnlesseq, 4) \
     131        macro(op_jless, 4) \
    131132        macro(op_jmp_scopes, 3) \
    132133        macro(op_loop, 2) \
    133134        macro(op_loop_if_true, 3) \
     135        macro(op_loop_if_false, 3) \
    134136        macro(op_loop_if_less, 4) \
    135137        macro(op_loop_if_lesseq, 4) \
  • trunk/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r50916 r51735  
    617617PassRefPtr<Label> BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label* target)
    618618{
    619     if (m_lastOpcodeID == op_less && !target->isForward()) {
     619    if (m_lastOpcodeID == op_less) {
    620620        int dstIndex;
    621621        int src1Index;
     
    628628
    629629            size_t begin = instructions().size();
    630             emitOpcode(op_loop_if_less);
     630            emitOpcode(target->isForward() ? op_jless : op_loop_if_less);
    631631            instructions().append(src1Index);
    632632            instructions().append(src2Index);
     
    693693PassRefPtr<Label> BytecodeGenerator::emitJumpIfFalse(RegisterID* cond, Label* target)
    694694{
    695     ASSERT(target->isForward());
    696 
    697     if (m_lastOpcodeID == op_less) {
     695    if (m_lastOpcodeID == op_less && target->isForward()) {
    698696        int dstIndex;
    699697        int src1Index;
     
    712710            return target;
    713711        }
    714     } else if (m_lastOpcodeID == op_lesseq) {
     712    } else if (m_lastOpcodeID == op_lesseq && target->isForward()) {
    715713        int dstIndex;
    716714        int src1Index;
     
    739737
    740738            size_t begin = instructions().size();
    741             emitOpcode(op_jtrue);
     739            emitOpcode(target->isForward() ? op_jtrue : op_loop_if_true);
    742740            instructions().append(srcIndex);
    743741            instructions().append(target->bind(begin, instructions().size()));
    744742            return target;
    745743        }
    746     } else if (m_lastOpcodeID == op_eq_null) {
     744    } else if (m_lastOpcodeID == op_eq_null && target->isForward()) {
    747745        int dstIndex;
    748746        int srcIndex;
     
    759757            return target;
    760758        }
    761     } else if (m_lastOpcodeID == op_neq_null) {
     759    } else if (m_lastOpcodeID == op_neq_null && target->isForward()) {
    762760        int dstIndex;
    763761        int srcIndex;
     
    777775
    778776    size_t begin = instructions().size();
    779     emitOpcode(op_jfalse);
     777    emitOpcode(target->isForward() ? op_jfalse : op_loop_if_false);
    780778    instructions().append(cond->index());
    781779    instructions().append(target->bind(begin, instructions().size()));
  • trunk/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r50254 r51735  
    193193        }
    194194
     195        void emitNodeInConditionContext(ExpressionNode* n, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue)
     196        {
     197            if (!m_codeBlock->numberOfLineInfos() || m_codeBlock->lastLineInfo().lineNumber != n->lineNo()) {
     198                LineInfo info = { instructions().size(), n->lineNo() };
     199                m_codeBlock->addLineInfo(info);
     200            }
     201            if (m_emitNodeDepth >= s_maxEmitNodeDepth)
     202                emitThrowExpressionTooDeepException();
     203            ++m_emitNodeDepth;
     204            n->emitBytecodeInConditionContext(*this, trueTarget, falseTarget, fallThroughMeansTrue);
     205            --m_emitNodeDepth;
     206        }
     207
    195208        void emitExpressionInfo(unsigned divot, unsigned startOffset, unsigned endOffset)
    196209        {
  • trunk/JavaScriptCore/interpreter/Interpreter.cpp

    r51671 r51735  
    26482648        NEXT_INSTRUCTION();
    26492649    }
     2650    DEFINE_OPCODE(op_loop_if_false) {
     2651        /* loop_if_true cond(r) target(offset)
     2652         
     2653           Jumps to offset target from the current instruction, if and
     2654           only if register cond converts to boolean as false.
     2655
     2656           Additionally this loop instruction may terminate JS execution is
     2657           the JS timeout is reached.
     2658         */
     2659        int cond = vPC[1].u.operand;
     2660        int target = vPC[2].u.operand;
     2661        if (!callFrame->r(cond).jsValue().toBoolean(callFrame)) {
     2662            vPC += target;
     2663            CHECK_FOR_TIMEOUT();
     2664            NEXT_INSTRUCTION();
     2665        }
     2666       
     2667        vPC += OPCODE_LENGTH(op_loop_if_true);
     2668        NEXT_INSTRUCTION();
     2669    }
    26502670    DEFINE_OPCODE(op_jtrue) {
    26512671        /* jtrue cond(r) target(offset)
     
    28092829
    28102830        vPC += OPCODE_LENGTH(op_jnless);
     2831        NEXT_INSTRUCTION();
     2832    }
     2833    DEFINE_OPCODE(op_jless) {
     2834        /* jless src1(r) src2(r) target(offset)
     2835
     2836           Checks whether register src1 is less than register src2, as
     2837           with the ECMAScript '<' operator, and then jumps to offset
     2838           target from the current instruction, if and only if the
     2839           result of the comparison is true.
     2840        */
     2841        JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
     2842        JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
     2843        int target = vPC[3].u.operand;
     2844
     2845        bool result = jsLess(callFrame, src1, src2);
     2846        CHECK_FOR_EXCEPTION();
     2847       
     2848        if (result) {
     2849            vPC += target;
     2850            NEXT_INSTRUCTION();
     2851        }
     2852
     2853        vPC += OPCODE_LENGTH(op_jless);
    28112854        NEXT_INSTRUCTION();
    28122855    }
  • trunk/JavaScriptCore/jit/JIT.cpp

    r50981 r51735  
    251251        DEFINE_OP(op_jneq_ptr)
    252252        DEFINE_OP(op_jnless)
     253        DEFINE_OP(op_jless)
    253254        DEFINE_OP(op_jnlesseq)
    254255        DEFINE_OP(op_jsr)
     
    259260        DEFINE_OP(op_loop_if_lesseq)
    260261        DEFINE_OP(op_loop_if_true)
     262        DEFINE_OP(op_loop_if_false)
    261263        DEFINE_OP(op_lshift)
    262264        DEFINE_OP(op_method_check)
     
    390392        DEFINE_SLOWCASE_OP(op_jfalse)
    391393        DEFINE_SLOWCASE_OP(op_jnless)
     394        DEFINE_SLOWCASE_OP(op_jless)
    392395        DEFINE_SLOWCASE_OP(op_jnlesseq)
    393396        DEFINE_SLOWCASE_OP(op_jtrue)
     
    395398        DEFINE_SLOWCASE_OP(op_loop_if_lesseq)
    396399        DEFINE_SLOWCASE_OP(op_loop_if_true)
     400        DEFINE_SLOWCASE_OP(op_loop_if_false)
    397401        DEFINE_SLOWCASE_OP(op_lshift)
    398402        DEFINE_SLOWCASE_OP(op_method_check)
  • trunk/JavaScriptCore/jit/JIT.h

    r50982 r51735  
    737737        void emit_op_jneq_ptr(Instruction*);
    738738        void emit_op_jnless(Instruction*);
     739        void emit_op_jless(Instruction*);
    739740        void emit_op_jnlesseq(Instruction*);
    740741        void emit_op_jsr(Instruction*);
     
    745746        void emit_op_loop_if_lesseq(Instruction*);
    746747        void emit_op_loop_if_true(Instruction*);
     748        void emit_op_loop_if_false(Instruction*);
    747749        void emit_op_lshift(Instruction*);
    748750        void emit_op_method_check(Instruction*);
     
    819821        void emitSlow_op_jfalse(Instruction*, Vector<SlowCaseEntry>::iterator&);
    820822        void emitSlow_op_jnless(Instruction*, Vector<SlowCaseEntry>::iterator&);
     823        void emitSlow_op_jless(Instruction*, Vector<SlowCaseEntry>::iterator&);
    821824        void emitSlow_op_jnlesseq(Instruction*, Vector<SlowCaseEntry>::iterator&);
    822825        void emitSlow_op_jtrue(Instruction*, Vector<SlowCaseEntry>::iterator&);
     
    824827        void emitSlow_op_loop_if_lesseq(Instruction*, Vector<SlowCaseEntry>::iterator&);
    825828        void emitSlow_op_loop_if_true(Instruction*, Vector<SlowCaseEntry>::iterator&);
     829        void emitSlow_op_loop_if_false(Instruction*, Vector<SlowCaseEntry>::iterator&);
    826830        void emitSlow_op_lshift(Instruction*, Vector<SlowCaseEntry>::iterator&);
    827831        void emitSlow_op_method_check(Instruction*, Vector<SlowCaseEntry>::iterator&);
  • trunk/JavaScriptCore/jit/JITArithmetic.cpp

    r50599 r51735  
    147147    stubCall.call();
    148148    emitJumpSlowToHot(branchTest32(Zero, regT0), target);
     149}
     150
     151void JIT::emit_op_jless(Instruction* currentInstruction)
     152{
     153    unsigned op1 = currentInstruction[1].u.operand;
     154    unsigned op2 = currentInstruction[2].u.operand;
     155    unsigned target = currentInstruction[3].u.operand;
     156
     157    JumpList notInt32Op1;
     158    JumpList notInt32Op2;
     159
     160    // Int32 less.
     161    if (isOperandConstantImmediateInt(op1)) {
     162        emitLoad(op2, regT3, regT2);
     163        notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
     164        addJump(branch32(GreaterThan, regT2, Imm32(getConstantOperand(op1).asInt32())), target);
     165    } else if (isOperandConstantImmediateInt(op2)) {
     166        emitLoad(op1, regT1, regT0);
     167        notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
     168        addJump(branch32(LessThan, regT0, Imm32(getConstantOperand(op2).asInt32())), target);
     169    } else {
     170        emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
     171        notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
     172        notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
     173        addJump(branch32(LessThan, regT0, regT2), target);
     174    }
     175
     176    if (!supportsFloatingPoint()) {
     177        addSlowCase(notInt32Op1);
     178        addSlowCase(notInt32Op2);
     179        return;
     180    }
     181    Jump end = jump();
     182
     183    // Double less.
     184    emitBinaryDoubleOp(op_jless, target, op1, op2, OperandTypes(), notInt32Op1, notInt32Op2, !isOperandConstantImmediateInt(op1), isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2));
     185    end.link(this);
     186}
     187
     188void JIT::emitSlow_op_jless(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     189{
     190    unsigned op1 = currentInstruction[1].u.operand;
     191    unsigned op2 = currentInstruction[2].u.operand;
     192    unsigned target = currentInstruction[3].u.operand;
     193
     194    if (!supportsFloatingPoint()) {
     195        if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2))
     196            linkSlowCase(iter); // int32 check
     197        linkSlowCase(iter); // int32 check
     198    } else {
     199        if (!isOperandConstantImmediateInt(op1)) {
     200            linkSlowCase(iter); // double check
     201            linkSlowCase(iter); // int32 check
     202        }
     203        if (isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2))
     204            linkSlowCase(iter); // double check
     205    }
     206
     207    JITStubCall stubCall(this, cti_op_jless);
     208    stubCall.addArgument(op1);
     209    stubCall.addArgument(op2);
     210    stubCall.call();
     211    emitJumpSlowToHot(branchTest32(NonZero, regT0), target);
    149212}
    150213
     
    832895                addJump(branchDouble(DoubleLessThanOrEqualOrUnordered, fpRegT0, fpRegT2), dst);
    833896                break;
     897            case op_jless:
     898                emitLoadDouble(op1, fpRegT2);
     899                addJump(branchDouble(DoubleLessThan, fpRegT2, fpRegT0), dst);
     900                break;
    834901            case op_jnlesseq:
    835902                emitLoadDouble(op1, fpRegT2);
     
    885952                addJump(branchDouble(DoubleLessThanOrEqualOrUnordered, fpRegT1, fpRegT0), dst);
    886953                break;
     954            case op_jless:
     955                emitLoadDouble(op2, fpRegT1);
     956                addJump(branchDouble(DoubleLessThan, fpRegT0, fpRegT1), dst);
     957                break;
    887958            case op_jnlesseq:
    888959                emitLoadDouble(op2, fpRegT1);
     
    14531524        stubCall.call();
    14541525        emitJumpSlowToHot(branchTest32(Zero, regT0), target);
     1526    }
     1527}
     1528
     1529void JIT::emit_op_jless(Instruction* currentInstruction)
     1530{
     1531    unsigned op1 = currentInstruction[1].u.operand;
     1532    unsigned op2 = currentInstruction[2].u.operand;
     1533    unsigned target = currentInstruction[3].u.operand;
     1534
     1535    // We generate inline code for the following cases in the fast path:
     1536    // - int immediate to constant int immediate
     1537    // - constant int immediate to int immediate
     1538    // - int immediate to int immediate
     1539
     1540    if (isOperandConstantImmediateInt(op2)) {
     1541        emitGetVirtualRegister(op1, regT0);
     1542        emitJumpSlowCaseIfNotImmediateInteger(regT0);
     1543#if USE(JSVALUE64)
     1544        int32_t op2imm = getConstantOperandImmediateInt(op2);
     1545#else
     1546        int32_t op2imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op2)));
     1547#endif
     1548        addJump(branch32(LessThan, regT0, Imm32(op2imm)), target);
     1549    } else if (isOperandConstantImmediateInt(op1)) {
     1550        emitGetVirtualRegister(op2, regT1);
     1551        emitJumpSlowCaseIfNotImmediateInteger(regT1);
     1552#if USE(JSVALUE64)
     1553        int32_t op1imm = getConstantOperandImmediateInt(op1);
     1554#else
     1555        int32_t op1imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op1)));
     1556#endif
     1557        addJump(branch32(GreaterThan, regT1, Imm32(op1imm)), target);
     1558    } else {
     1559        emitGetVirtualRegisters(op1, regT0, op2, regT1);
     1560        emitJumpSlowCaseIfNotImmediateInteger(regT0);
     1561        emitJumpSlowCaseIfNotImmediateInteger(regT1);
     1562
     1563        addJump(branch32(LessThan, regT0, regT1), target);
     1564    }
     1565}
     1566
     1567void JIT::emitSlow_op_jless(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     1568{
     1569    unsigned op1 = currentInstruction[1].u.operand;
     1570    unsigned op2 = currentInstruction[2].u.operand;
     1571    unsigned target = currentInstruction[3].u.operand;
     1572
     1573    // We generate inline code for the following cases in the slow path:
     1574    // - floating-point number to constant int immediate
     1575    // - constant int immediate to floating-point number
     1576    // - floating-point number to floating-point number.
     1577
     1578    if (isOperandConstantImmediateInt(op2)) {
     1579        linkSlowCase(iter);
     1580
     1581        if (supportsFloatingPoint()) {
     1582#if USE(JSVALUE64)
     1583            Jump fail1 = emitJumpIfNotImmediateNumber(regT0);
     1584            addPtr(tagTypeNumberRegister, regT0);
     1585            movePtrToDouble(regT0, fpRegT0);
     1586#else
     1587            Jump fail1;
     1588            if (!m_codeBlock->isKnownNotImmediate(op1))
     1589                fail1 = emitJumpIfNotJSCell(regT0);
     1590
     1591            Jump fail2 = checkStructure(regT0, m_globalData->numberStructure.get());
     1592            loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
     1593#endif
     1594           
     1595            int32_t op2imm = getConstantOperand(op2).asInt32();
     1596                   
     1597            move(Imm32(op2imm), regT1);
     1598            convertInt32ToDouble(regT1, fpRegT1);
     1599
     1600            emitJumpSlowToHot(branchDouble(DoubleLessThan, fpRegT0, fpRegT1), target);
     1601
     1602            emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless));
     1603
     1604#if USE(JSVALUE64)
     1605            fail1.link(this);
     1606#else
     1607            if (!m_codeBlock->isKnownNotImmediate(op1))
     1608                fail1.link(this);
     1609            fail2.link(this);
     1610#endif
     1611        }
     1612
     1613        JITStubCall stubCall(this, cti_op_jless);
     1614        stubCall.addArgument(regT0);
     1615        stubCall.addArgument(op2, regT2);
     1616        stubCall.call();
     1617        emitJumpSlowToHot(branchTest32(Zero, regT0), target);
     1618
     1619    } else if (isOperandConstantImmediateInt(op1)) {
     1620        linkSlowCase(iter);
     1621
     1622        if (supportsFloatingPoint()) {
     1623#if USE(JSVALUE64)
     1624            Jump fail1 = emitJumpIfNotImmediateNumber(regT1);
     1625            addPtr(tagTypeNumberRegister, regT1);
     1626            movePtrToDouble(regT1, fpRegT1);
     1627#else
     1628            Jump fail1;
     1629            if (!m_codeBlock->isKnownNotImmediate(op2))
     1630                fail1 = emitJumpIfNotJSCell(regT1);
     1631           
     1632            Jump fail2 = checkStructure(regT1, m_globalData->numberStructure.get());
     1633            loadDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT1);
     1634#endif
     1635           
     1636            int32_t op1imm = getConstantOperand(op1).asInt32();
     1637                   
     1638            move(Imm32(op1imm), regT0);
     1639            convertInt32ToDouble(regT0, fpRegT0);
     1640
     1641            emitJumpSlowToHot(branchDouble(DoubleLessThan, fpRegT0, fpRegT1), target);
     1642
     1643            emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless));
     1644
     1645#if USE(JSVALUE64)
     1646            fail1.link(this);
     1647#else
     1648            if (!m_codeBlock->isKnownNotImmediate(op2))
     1649                fail1.link(this);
     1650            fail2.link(this);
     1651#endif
     1652        }
     1653
     1654        JITStubCall stubCall(this, cti_op_jless);
     1655        stubCall.addArgument(op1, regT2);
     1656        stubCall.addArgument(regT1);
     1657        stubCall.call();
     1658        emitJumpSlowToHot(branchTest32(Zero, regT0), target);
     1659
     1660    } else {
     1661        linkSlowCase(iter);
     1662
     1663        if (supportsFloatingPoint()) {
     1664#if USE(JSVALUE64)
     1665            Jump fail1 = emitJumpIfNotImmediateNumber(regT0);
     1666            Jump fail2 = emitJumpIfNotImmediateNumber(regT1);
     1667            Jump fail3 = emitJumpIfImmediateInteger(regT1);
     1668            addPtr(tagTypeNumberRegister, regT0);
     1669            addPtr(tagTypeNumberRegister, regT1);
     1670            movePtrToDouble(regT0, fpRegT0);
     1671            movePtrToDouble(regT1, fpRegT1);
     1672#else
     1673            Jump fail1;
     1674            if (!m_codeBlock->isKnownNotImmediate(op1))
     1675                fail1 = emitJumpIfNotJSCell(regT0);
     1676
     1677            Jump fail2;
     1678            if (!m_codeBlock->isKnownNotImmediate(op2))
     1679                fail2 = emitJumpIfNotJSCell(regT1);
     1680
     1681            Jump fail3 = checkStructure(regT0, m_globalData->numberStructure.get());
     1682            Jump fail4 = checkStructure(regT1, m_globalData->numberStructure.get());
     1683            loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
     1684            loadDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT1);
     1685#endif
     1686
     1687            emitJumpSlowToHot(branchDouble(DoubleLessThan, fpRegT0, fpRegT1), target);
     1688
     1689            emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless));
     1690
     1691#if USE(JSVALUE64)
     1692            fail1.link(this);
     1693            fail2.link(this);
     1694            fail3.link(this);
     1695#else
     1696            if (!m_codeBlock->isKnownNotImmediate(op1))
     1697                fail1.link(this);
     1698            if (!m_codeBlock->isKnownNotImmediate(op2))
     1699                fail2.link(this);
     1700            fail3.link(this);
     1701            fail4.link(this);
     1702#endif
     1703        }
     1704
     1705        linkSlowCase(iter);
     1706        JITStubCall stubCall(this, cti_op_jless);
     1707        stubCall.addArgument(regT0);
     1708        stubCall.addArgument(regT1);
     1709        stubCall.call();
     1710        emitJumpSlowToHot(branchTest32(NotZero, regT0), target);
    14551711    }
    14561712}
  • trunk/JavaScriptCore/jit/JITOpcodes.cpp

    r51671 r51735  
    455455    linkSlowCase(iter); // int32 check
    456456
    457     JITStubCall stubCall(this, cti_op_loop_if_less);
     457    JITStubCall stubCall(this, cti_op_jless);
    458458    stubCall.addArgument(op1);
    459459    stubCall.addArgument(op2);
     
    742742    stubCall.call();
    743743    emitJumpSlowToHot(branchTest32(NonZero, regT0), target);
     744}
     745
     746void JIT::emit_op_loop_if_false(Instruction* currentInstruction)
     747{
     748    unsigned cond = currentInstruction[1].u.operand;
     749    unsigned target = currentInstruction[2].u.operand;
     750
     751    emitTimeoutCheck();
     752
     753    emitLoad(cond, regT1, regT0);
     754
     755    Jump isTrue = branch32(Equal, regT1, Imm32(JSValue::TrueTag));
     756    addJump(branch32(Equal, regT1, Imm32(JSValue::FalseTag)), target);
     757
     758    Jump isNotInteger = branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag));
     759    Jump isTrue2 = branch32(NotEqual, regT0, Imm32(0));
     760    addJump(jump(), target);
     761
     762    if (supportsFloatingPoint()) {
     763        isNotInteger.link(this);
     764
     765        addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag)));
     766
     767        zeroDouble(fpRegT0);
     768        emitLoadDouble(cond, fpRegT1);
     769        addJump(branchDouble(DoubleEqualOrUnordered, fpRegT0, fpRegT1), target);
     770    } else
     771        addSlowCase(isNotInteger);
     772
     773    isTrue.link(this);
     774    isTrue2.link(this);
     775}
     776
     777void JIT::emitSlow_op_loop_if_false(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     778{
     779    unsigned cond = currentInstruction[1].u.operand;
     780    unsigned target = currentInstruction[2].u.operand;
     781
     782    linkSlowCase(iter);
     783
     784    JITStubCall stubCall(this, cti_op_jtrue);
     785    stubCall.addArgument(cond);
     786    stubCall.call();
     787    emitJumpSlowToHot(branchTest32(Zero, regT0), target);
    744788}
    745789
  • trunk/JavaScriptCore/jit/JITStubs.cpp

    r51671 r51735  
    11201120}
    11211121
    1122 DEFINE_STUB_FUNCTION(int, op_loop_if_less)
    1123 {
    1124     STUB_INIT_STACK_FRAME(stackFrame);
    1125 
    1126     JSValue src1 = stackFrame.args[0].jsValue();
    1127     JSValue src2 = stackFrame.args[1].jsValue();
    1128     CallFrame* callFrame = stackFrame.callFrame;
    1129 
    1130     bool result = jsLess(callFrame, src1, src2);
    1131     CHECK_FOR_EXCEPTION_AT_END();
    1132     return result;
    1133 }
    1134 
    11351122DEFINE_STUB_FUNCTION(int, op_loop_if_lesseq)
    11361123{
     
    20982085}
    20992086
    2100 DEFINE_STUB_FUNCTION(int, op_loop_if_true)
    2101 {
    2102     STUB_INIT_STACK_FRAME(stackFrame);
    2103 
    2104     JSValue src1 = stackFrame.args[0].jsValue();
    2105 
    2106     CallFrame* callFrame = stackFrame.callFrame;
    2107 
    2108     bool result = src1.toBoolean(callFrame);
    2109     CHECK_FOR_EXCEPTION_AT_END();
    2110     return result;
    2111 }
    2112    
    21132087DEFINE_STUB_FUNCTION(int, op_load_varargs)
    21142088{
  • trunk/JavaScriptCore/jit/JITStubs.h

    r50594 r51735  
    336336    int JIT_STUB cti_op_jtrue(STUB_ARGS_DECLARATION);
    337337    int JIT_STUB cti_op_load_varargs(STUB_ARGS_DECLARATION);
    338     int JIT_STUB cti_op_loop_if_less(STUB_ARGS_DECLARATION);
    339338    int JIT_STUB cti_op_loop_if_lesseq(STUB_ARGS_DECLARATION);
    340     int JIT_STUB cti_op_loop_if_true(STUB_ARGS_DECLARATION);
    341339    int JIT_STUB cti_timeout_check(STUB_ARGS_DECLARATION);
    342340    int JIT_STUB cti_has_property(STUB_ARGS_DECLARATION);
  • trunk/JavaScriptCore/parser/Nodes.cpp

    r50916 r51735  
    812812}
    813813
     814
     815// ------------------------------ LogicalNotNode -----------------------------------
     816
     817void LogicalNotNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue)
     818{
     819    ASSERT(expr()->hasConditionContextCodegen());
     820
     821    // reverse the true and false targets
     822    generator.emitNodeInConditionContext(expr(), falseTarget, trueTarget, !fallThroughMeansTrue);
     823}
     824
     825
    814826// ------------------------------ Binary Operation Nodes -----------------------------------
    815827
     
    10181030}
    10191031
     1032void LogicalOpNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue)
     1033{
     1034    if (m_expr1->hasConditionContextCodegen()) {
     1035        RefPtr<Label> afterExpr1 = generator.newLabel();
     1036        if (m_operator == OpLogicalAnd)
     1037            generator.emitNodeInConditionContext(m_expr1, afterExpr1.get(), falseTarget, true);
     1038        else
     1039            generator.emitNodeInConditionContext(m_expr1, trueTarget, afterExpr1.get(), false);
     1040        generator.emitLabel(afterExpr1.get());
     1041    } else {
     1042        RegisterID* temp = generator.emitNode(m_expr1);
     1043        if (m_operator == OpLogicalAnd)
     1044            generator.emitJumpIfFalse(temp, falseTarget);
     1045        else
     1046            generator.emitJumpIfTrue(temp, trueTarget);
     1047    }
     1048
     1049    if (m_expr2->hasConditionContextCodegen())
     1050        generator.emitNodeInConditionContext(m_expr2, trueTarget, falseTarget, fallThroughMeansTrue);
     1051    else {
     1052        RegisterID* temp = generator.emitNode(m_expr2);
     1053        if (fallThroughMeansTrue)
     1054            generator.emitJumpIfFalse(temp, falseTarget);
     1055        else
     1056            generator.emitJumpIfTrue(temp, trueTarget);
     1057    }
     1058}
     1059
    10201060// ------------------------------ ConditionalNode ------------------------------
    10211061
     
    10261066    RefPtr<Label> afterElse = generator.newLabel();
    10271067
    1028     RegisterID* cond = generator.emitNode(m_logical);
    1029     generator.emitJumpIfFalse(cond, beforeElse.get());
     1068    if (m_logical->hasConditionContextCodegen()) {
     1069        RefPtr<Label> beforeThen = generator.newLabel();
     1070        generator.emitNodeInConditionContext(m_logical, beforeThen.get(), beforeElse.get(), true);
     1071        generator.emitLabel(beforeThen.get());
     1072    } else {
     1073        RegisterID* cond = generator.emitNode(m_logical);
     1074        generator.emitJumpIfFalse(cond, beforeElse.get());
     1075    }
    10301076
    10311077    generator.emitNode(newDst.get(), m_expr1);
     
    13441390    RefPtr<Label> afterThen = generator.newLabel();
    13451391
    1346     RegisterID* cond = generator.emitNode(m_condition);
    1347     generator.emitJumpIfFalse(cond, afterThen.get());
     1392    if (m_condition->hasConditionContextCodegen()) {
     1393        RefPtr<Label> beforeThen = generator.newLabel();
     1394        generator.emitNodeInConditionContext(m_condition, beforeThen.get(), afterThen.get(), true);
     1395        generator.emitLabel(beforeThen.get());
     1396    } else {
     1397        RegisterID* cond = generator.emitNode(m_condition);
     1398        generator.emitJumpIfFalse(cond, afterThen.get());
     1399    }
    13481400
    13491401    generator.emitNode(dst, m_ifBlock);
     
    13631415    RefPtr<Label> afterElse = generator.newLabel();
    13641416
    1365     RegisterID* cond = generator.emitNode(m_condition);
    1366     generator.emitJumpIfFalse(cond, beforeElse.get());
     1417    if (m_condition->hasConditionContextCodegen()) {
     1418        RefPtr<Label> beforeThen = generator.newLabel();
     1419        generator.emitNodeInConditionContext(m_condition, beforeThen.get(), beforeElse.get(), true);
     1420        generator.emitLabel(beforeThen.get());
     1421    } else {
     1422        RegisterID* cond = generator.emitNode(m_condition);
     1423        generator.emitJumpIfFalse(cond, beforeElse.get());
     1424    }
    13671425
    13681426    generator.emitNode(dst, m_ifBlock);
     
    13941452    generator.emitLabel(scope->continueTarget());
    13951453    generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->lineNo());
    1396     RegisterID* cond = generator.emitNode(m_expr);
    1397     generator.emitJumpIfTrue(cond, topOfLoop.get());
     1454    if (m_expr->hasConditionContextCodegen())
     1455        generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), false);
     1456    else {
     1457        RegisterID* cond = generator.emitNode(m_expr);
     1458        generator.emitJumpIfTrue(cond, topOfLoop.get());
     1459    }
    13981460
    13991461    generator.emitLabel(scope->breakTarget());
     
    14161478    generator.emitLabel(scope->continueTarget());
    14171479    generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->lineNo());
    1418     RegisterID* cond = generator.emitNode(m_expr);
    1419     generator.emitJumpIfTrue(cond, topOfLoop.get());
     1480
     1481    if (m_expr->hasConditionContextCodegen())
     1482        generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), false);
     1483    else {
     1484        RegisterID* cond = generator.emitNode(m_expr);
     1485        generator.emitJumpIfTrue(cond, topOfLoop.get());
     1486    }
    14201487
    14211488    generator.emitLabel(scope->breakTarget());
     
    14511518    generator.emitLabel(condition.get());
    14521519    if (m_expr2) {
    1453         RegisterID* cond = generator.emitNode(m_expr2);
    1454         generator.emitJumpIfTrue(cond, topOfLoop.get());
     1520        if (m_expr2->hasConditionContextCodegen())
     1521            generator.emitNodeInConditionContext(m_expr2, topOfLoop.get(), scope->breakTarget(), false);
     1522        else {
     1523            RegisterID* cond = generator.emitNode(m_expr2);
     1524            generator.emitJumpIfTrue(cond, topOfLoop.get());
     1525        }
    14551526    } else
    14561527        generator.emitJump(topOfLoop.get());
  • trunk/JavaScriptCore/parser/Nodes.h

    r47775 r51735  
    4141    class BytecodeGenerator;
    4242    class FunctionBodyNode;
     43    class Label;
    4344    class PropertyListNode;
    4445    class ReadModifyResolveNode;
     
    152153        virtual bool isSimpleArray() const { return false; }
    153154        virtual bool isAdd() const { return false; }
     155        virtual bool hasConditionContextCodegen() const { return false; }
     156
     157        virtual void emitBytecodeInConditionContext(BytecodeGenerator&, Label*, Label*, bool) { ASSERT_NOT_REACHED(); }
    154158
    155159        virtual ExpressionNode* stripUnaryPlus() { return this; }
     
    758762    protected:
    759763        ExpressionNode* expr() { return m_expr; }
     764        const ExpressionNode* expr() const { return m_expr; }
    760765
    761766    private:
     
    789794    public:
    790795        LogicalNotNode(JSGlobalData*, ExpressionNode*);
     796    private:
     797        void emitBytecodeInConditionContext(BytecodeGenerator&, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue);
     798        virtual bool hasConditionContextCodegen() const { return expr()->hasConditionContextCodegen(); }
    791799    };
    792800
     
    953961    private:
    954962        virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
     963        void emitBytecodeInConditionContext(BytecodeGenerator&, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue);
     964        virtual bool hasConditionContextCodegen() const { return true; }
    955965
    956966        ExpressionNode* m_expr1;
  • trunk/LayoutTests/ChangeLog

    r51734 r51735  
     12009-12-05  Maciej Stachowiak  <mjs@apple.com>
     2
     3        Reviewed by Oliver Hunt.
     4
     5        conway benchmark spends half it's time in op_less (jump fusion fails)
     6        https://bugs.webkit.org/show_bug.cgi?id=32190
     7
     8        * fast/js/codegen-loops-logical-nodes-expected.txt:
     9        * fast/js/script-tests/codegen-loops-logical-nodes.js: Update to test some newly
     10        sensitive cases of codegen that were not already covered.
     11
    1122009-12-05  Philippe Normand  <pnormand@igalia.com>
    213
  • trunk/LayoutTests/fast/js/codegen-loops-logical-nodes-expected.txt

    r34758 r51735  
    2828PASS dowhile_and_less() is true
    2929PASS dowhile_and_lesseq() is true
     30PASS while_not_or_eq() is false
     31PASS while_not_or_neq() is false
     32PASS while_not_or_less() is false
     33PASS while_not_or_lesseq() is false
     34PASS while_not_and_eq() is false
     35PASS while_not_and_neq() is false
     36PASS while_not_and_less() is false
     37PASS while_not_and_lesseq() is false
     38PASS for_not_or_eq() is false
     39PASS for_not_or_neq() is false
     40PASS for_not_or_less() is false
     41PASS for_not_or_lesseq() is false
     42PASS for_not_and_eq() is false
     43PASS for_not_and_neq() is false
     44PASS for_not_and_less() is false
     45PASS for_not_and_lesseq() is false
     46PASS dowhile_not_or_eq() is false
     47PASS dowhile_not_or_neq() is false
     48PASS dowhile_not_or_less() is false
     49PASS dowhile_not_or_lesseq() is false
     50PASS dowhile_not_and_eq() is false
     51PASS dowhile_not_and_neq() is false
     52PASS dowhile_not_and_less() is false
     53PASS dowhile_not_and_lesseq() is false
     54PASS float_while_or_eq() is true
     55PASS float_while_or_neq() is true
     56PASS float_while_or_less() is true
     57PASS float_while_or_lesseq() is true
     58PASS float_while_and_eq() is true
     59PASS float_while_and_neq() is true
     60PASS float_while_and_less() is true
     61PASS float_while_and_lesseq() is true
     62PASS float_for_or_eq() is true
     63PASS float_for_or_neq() is true
     64PASS float_for_or_less() is true
     65PASS float_for_or_lesseq() is true
     66PASS float_for_and_eq() is true
     67PASS float_for_and_neq() is true
     68PASS float_for_and_less() is true
     69PASS float_for_and_lesseq() is true
     70PASS float_dowhile_or_eq() is true
     71PASS float_dowhile_or_neq() is true
     72PASS float_dowhile_or_less() is true
     73PASS float_dowhile_or_lesseq() is true
     74PASS float_dowhile_and_eq() is true
     75PASS float_dowhile_and_neq() is true
     76PASS float_dowhile_and_less() is true
     77PASS float_dowhile_and_lesseq() is true
     78PASS float_while_not_or_eq() is false
     79PASS float_while_not_or_neq() is false
     80PASS float_while_not_or_less() is false
     81PASS float_while_not_or_lesseq() is false
     82PASS float_while_not_and_eq() is false
     83PASS float_while_not_and_neq() is false
     84PASS float_while_not_and_less() is false
     85PASS float_while_not_and_lesseq() is false
     86PASS float_for_not_or_eq() is false
     87PASS float_for_not_or_neq() is false
     88PASS float_for_not_or_less() is false
     89PASS float_for_not_or_lesseq() is false
     90PASS float_for_not_and_eq() is false
     91PASS float_for_not_and_neq() is false
     92PASS float_for_not_and_less() is false
     93PASS float_for_not_and_lesseq() is false
     94PASS float_dowhile_not_or_eq() is false
     95PASS float_dowhile_not_or_neq() is false
     96PASS float_dowhile_not_or_less() is false
     97PASS float_dowhile_not_or_lesseq() is false
     98PASS float_dowhile_not_and_eq() is false
     99PASS float_dowhile_not_and_neq() is false
     100PASS float_dowhile_not_and_less() is false
    30101PASS successfullyParsed is true
    31102
  • trunk/LayoutTests/fast/js/script-tests/codegen-loops-logical-nodes.js

    r48651 r51735  
    267267shouldBeTrue("dowhile_and_lesseq()");
    268268
     269function while_not_or_eq()
     270{
     271    var a = 0;
     272    while (!(a == 0 || a == 0))
     273        return true;
     274    return false;
     275}
     276
     277shouldBeFalse("while_not_or_eq()");
     278
     279function while_not_or_neq()
     280{
     281    var a = 0;
     282    while (!(a != 1 || a != 1))
     283        return true;
     284    return false;
     285}
     286
     287shouldBeFalse("while_not_or_neq()");
     288
     289function while_not_or_less()
     290{
     291    var a = 0;
     292    while (!(a < 1 || a < 1))
     293        return true;
     294    return false;
     295}
     296
     297shouldBeFalse("while_not_or_less()");
     298
     299function while_not_or_lesseq()
     300{
     301    var a = 0;
     302    while (!(a <= 1 || a <= 1))
     303        return true;
     304    return false;
     305}
     306
     307shouldBeFalse("while_not_or_lesseq()");
     308
     309function while_not_and_eq()
     310{
     311    var a = 0;
     312    while (!(a == 0 && a == 0))
     313        return true;
     314    return false;
     315}
     316
     317shouldBeFalse("while_not_and_eq()");
     318
     319function while_not_and_neq()
     320{
     321    var a = 0;
     322    while (!(a != 1 && a != 1))
     323        return true;
     324    return false;
     325}
     326
     327shouldBeFalse("while_not_and_neq()");
     328
     329function while_not_and_less()
     330{
     331    var a = 0;
     332    while (!(a < 1 && a < 1))
     333        return true;
     334    return false;
     335}
     336
     337shouldBeFalse("while_not_and_less()");
     338
     339function while_not_and_lesseq()
     340{
     341    var a = 0;
     342    while (!(a <= 1 && a <= 1))
     343        return true;
     344    return false;
     345}
     346
     347shouldBeFalse("while_not_and_lesseq()");
     348
     349function for_not_or_eq()
     350{
     351    for (var a = 0; !(a == 0 || a == 0); )
     352        return true;
     353    return false;
     354}
     355
     356shouldBeFalse("for_not_or_eq()");
     357
     358function for_not_or_neq()
     359{
     360    for (var a = 0; !(a != 1 || a != 1); )
     361        return true;
     362    return false;
     363}
     364
     365shouldBeFalse("for_not_or_neq()");
     366
     367function for_not_or_less()
     368{
     369    for (var a = 0; !(a < 1 || a < 1); )
     370        return true;
     371    return false;
     372}
     373
     374shouldBeFalse("for_not_or_less()");
     375
     376function for_not_or_lesseq()
     377{
     378    for (var a = 0; !(a <= 1 || a <= 1); )
     379        return true;
     380    return false;
     381}
     382
     383shouldBeFalse("for_not_or_lesseq()");
     384
     385function for_not_and_eq()
     386{
     387    for (var a = 0; !(a == 0 && a == 0); )
     388        return true;
     389    return false;
     390}
     391
     392shouldBeFalse("for_not_and_eq()");
     393
     394function for_not_and_neq()
     395{
     396    for (var a = 0; !(a != 1 && a != 1); )
     397        return true;
     398    return false;
     399}
     400
     401shouldBeFalse("for_not_and_neq()");
     402
     403function for_not_and_less()
     404{
     405    for (var a = 0; !(a < 1 && a < 1); )
     406        return true;
     407    return false;
     408}
     409
     410shouldBeFalse("for_not_and_less()");
     411
     412function for_not_and_lesseq()
     413{
     414    for (var a = 0; !(a <= 1 && a <= 1); )
     415        return true;
     416    return false;
     417}
     418
     419shouldBeFalse("for_not_and_lesseq()");
     420
     421function dowhile_not_or_eq()
     422{
     423    var a = 0;
     424    var i = 0;
     425    do {
     426        if (i > 0)
     427            return true;
     428        i++;
     429    } while (!(a == 0 || a == 0))
     430    return false;
     431}
     432
     433shouldBeFalse("dowhile_not_or_eq()");
     434
     435function dowhile_not_or_neq()
     436{
     437    var a = 0;
     438    var i = 0;
     439    do {
     440        if (i > 0)
     441            return true;
     442        i++;
     443    } while (!(a != 1 || a != 1))
     444    return false;
     445}
     446
     447shouldBeFalse("dowhile_not_or_neq()");
     448
     449function dowhile_not_or_less()
     450{
     451    var a = 0;
     452    var i = 0;
     453    do {
     454        if (i > 0)
     455            return true;
     456        i++;
     457    } while (!(a < 1 || a < 1))
     458    return false;
     459}
     460
     461shouldBeFalse("dowhile_not_or_less()");
     462
     463function dowhile_not_or_lesseq()
     464{
     465    var a = 0;
     466    var i = 0;
     467    do {
     468        if (i > 0)
     469            return true;
     470        i++;
     471    } while (!(a <= 1 || a <= 1))
     472    return false;
     473}
     474
     475shouldBeFalse("dowhile_not_or_lesseq()");
     476
     477function dowhile_not_and_eq()
     478{
     479    var a = 0;
     480    var i = 0;
     481    do {
     482        if (i > 0)
     483            return true;
     484        i++;
     485    } while (!(a == 0 && a == 0))
     486    return false;
     487}
     488
     489shouldBeFalse("dowhile_not_and_eq()");
     490
     491function dowhile_not_and_neq()
     492{
     493    var a = 0;
     494    var i = 0;
     495    do {
     496        if (i > 0)
     497            return true;
     498        i++;
     499    } while (!(a != 1 && a != 1))
     500    return false;
     501}
     502
     503shouldBeFalse("dowhile_not_and_neq()");
     504
     505function dowhile_not_and_less()
     506{
     507    var a = 0;
     508    var i = 0;
     509    do {
     510        if (i > 0)
     511            return true;
     512        i++;
     513    } while (!(a < 1 && a < 1))
     514    return false;
     515}
     516
     517shouldBeFalse("dowhile_not_and_less()");
     518
     519function dowhile_not_and_lesseq()
     520{
     521    var a = 0;
     522    var i = 0;
     523    do {
     524        if (i > 0)
     525            return true;
     526        i++;
     527    } while (!(a <= 1 && a <= 1))
     528    return false;
     529}
     530
     531shouldBeFalse("dowhile_not_and_lesseq()");
     532
     533function float_while_or_eq()
     534{
     535    var a = 0.1;
     536    while (a == 0.1 || a == 0.1)
     537        return true;
     538    return false;
     539}
     540
     541shouldBeTrue("float_while_or_eq()");
     542
     543function float_while_or_neq()
     544{
     545    var a = 0.1;
     546    while (a != 1.1 || a != 1.1)
     547        return true;
     548    return false;
     549}
     550
     551shouldBeTrue("float_while_or_neq()");
     552
     553function float_while_or_less()
     554{
     555    var a = 0.1;
     556    while (a < 1.1 || a < 1.1)
     557        return true;
     558    return false;
     559}
     560
     561shouldBeTrue("float_while_or_less()");
     562
     563function float_while_or_lesseq()
     564{
     565    var a = 0.1;
     566    while (a <= 1.1 || a <= 1.1)
     567        return true;
     568    return false;
     569}
     570
     571shouldBeTrue("float_while_or_lesseq()");
     572
     573function float_while_and_eq()
     574{
     575    var a = 0.1;
     576    while (a == 0.1 && a == 0.1)
     577        return true;
     578    return false;
     579}
     580
     581shouldBeTrue("float_while_and_eq()");
     582
     583function float_while_and_neq()
     584{
     585    var a = 0.1;
     586    while (a != 1.1 && a != 1.1)
     587        return true;
     588    return false;
     589}
     590
     591shouldBeTrue("float_while_and_neq()");
     592
     593function float_while_and_less()
     594{
     595    var a = 0.1;
     596    while (a < 1.1 && a < 1.1)
     597        return true;
     598    return false;
     599}
     600
     601shouldBeTrue("float_while_and_less()");
     602
     603function float_while_and_lesseq()
     604{
     605    var a = 0.1;
     606    while (a <= 1.1 && a <= 1.1)
     607        return true;
     608    return false;
     609}
     610
     611shouldBeTrue("float_while_and_lesseq()");
     612
     613function float_for_or_eq()
     614{
     615    for (var a = 0.1; a == 0.1 || a == 0.1; )
     616        return true;
     617    return false;
     618}
     619
     620shouldBeTrue("float_for_or_eq()");
     621
     622function float_for_or_neq()
     623{
     624    for (var a = 0.1; a != 1.1 || a != 1.1; )
     625        return true;
     626    return false;
     627}
     628
     629shouldBeTrue("float_for_or_neq()");
     630
     631function float_for_or_less()
     632{
     633    for (var a = 0.1; a < 1.1 || a < 1.1; )
     634        return true;
     635    return false;
     636}
     637
     638shouldBeTrue("float_for_or_less()");
     639
     640function float_for_or_lesseq()
     641{
     642    for (var a = 0.1; a <= 1.1 || a <= 1.1; )
     643        return true;
     644    return false;
     645}
     646
     647shouldBeTrue("float_for_or_lesseq()");
     648
     649function float_for_and_eq()
     650{
     651    for (var a = 0.1; a == 0.1 && a == 0.1; )
     652        return true;
     653    return false;
     654}
     655
     656shouldBeTrue("float_for_and_eq()");
     657
     658function float_for_and_neq()
     659{
     660    for (var a = 0.1; a != 1.1 && a != 1.1; )
     661        return true;
     662    return false;
     663}
     664
     665shouldBeTrue("float_for_and_neq()");
     666
     667function float_for_and_less()
     668{
     669    for (var a = 0.1; a < 1.1 && a < 1.1; )
     670        return true;
     671    return false;
     672}
     673
     674shouldBeTrue("float_for_and_less()");
     675
     676function float_for_and_lesseq()
     677{
     678    for (var a = 0.1; a <= 1.1 && a <= 1.1; )
     679        return true;
     680    return false;
     681}
     682
     683shouldBeTrue("float_for_and_lesseq()");
     684
     685function float_dowhile_or_eq()
     686{
     687    var a = 0.1;
     688    var i = 0.1;
     689    do {
     690        if (i > 0.1)
     691            return true;
     692        i++;
     693    } while (a == 0.1 || a == 0.1)
     694    return false;
     695}
     696
     697shouldBeTrue("float_dowhile_or_eq()");
     698
     699function float_dowhile_or_neq()
     700{
     701    var a = 0.1;
     702    var i = 0.1;
     703    do {
     704        if (i > 0.1)
     705            return true;
     706        i++;
     707    } while (a != 1.1 || a != 1.1)
     708    return false;
     709}
     710
     711shouldBeTrue("float_dowhile_or_neq()");
     712
     713function float_dowhile_or_less()
     714{
     715    var a = 0.1;
     716    var i = 0.1;
     717    do {
     718        if (i > 0.1)
     719            return true;
     720        i++;
     721    } while (a < 1.1 || a < 1.1)
     722    return false;
     723}
     724
     725shouldBeTrue("float_dowhile_or_less()");
     726
     727function float_dowhile_or_lesseq()
     728{
     729    var a = 0.1;
     730    var i = 0.1;
     731    do {
     732        if (i > 0.1)
     733            return true;
     734        i++;
     735    } while (a <= 1.1 || a <= 1.1)
     736    return false;
     737}
     738
     739shouldBeTrue("float_dowhile_or_lesseq()");
     740
     741function float_dowhile_and_eq()
     742{
     743    var a = 0.1;
     744    var i = 0.1;
     745    do {
     746        if (i > 0.1)
     747            return true;
     748        i++;
     749    } while (a == 0.1 && a == 0.1)
     750    return false;
     751}
     752
     753shouldBeTrue("float_dowhile_and_eq()");
     754
     755function float_dowhile_and_neq()
     756{
     757    var a = 0.1;
     758    var i = 0.1;
     759    do {
     760        if (i > 0.1)
     761            return true;
     762        i++;
     763    } while (a != 1.1 && a != 1.1)
     764    return false;
     765}
     766
     767shouldBeTrue("float_dowhile_and_neq()");
     768
     769function float_dowhile_and_less()
     770{
     771    var a = 0.1;
     772    var i = 0.1;
     773    do {
     774        if (i > 0.1)
     775            return true;
     776        i++;
     777    } while (a < 1.1 && a < 1.1)
     778    return false;
     779}
     780
     781shouldBeTrue("float_dowhile_and_less()");
     782
     783function float_dowhile_and_lesseq()
     784{
     785    var a = 0.1;
     786    var i = 0.1;
     787    do {
     788        if (i > 0.1)
     789            return true;
     790        i++;
     791    } while (a <= 1.1 && a <= 1.1)
     792    return false;
     793}
     794
     795shouldBeTrue("float_dowhile_and_lesseq()");
     796
     797function float_while_not_or_eq()
     798{
     799    var a = 0.1;
     800    while (!(a == 0.1 || a == 0.1))
     801        return true;
     802    return false;
     803}
     804
     805shouldBeFalse("float_while_not_or_eq()");
     806
     807function float_while_not_or_neq()
     808{
     809    var a = 0.1;
     810    while (!(a != 1.1 || a != 1.1))
     811        return true;
     812    return false;
     813}
     814
     815shouldBeFalse("float_while_not_or_neq()");
     816
     817function float_while_not_or_less()
     818{
     819    var a = 0.1;
     820    while (!(a < 1.1 || a < 1.1))
     821        return true;
     822    return false;
     823}
     824
     825shouldBeFalse("float_while_not_or_less()");
     826
     827function float_while_not_or_lesseq()
     828{
     829    var a = 0.1;
     830    while (!(a <= 1.1 || a <= 1.1))
     831        return true;
     832    return false;
     833}
     834
     835shouldBeFalse("float_while_not_or_lesseq()");
     836
     837function float_while_not_and_eq()
     838{
     839    var a = 0.1;
     840    while (!(a == 0.1 && a == 0.1))
     841        return true;
     842    return false;
     843}
     844
     845shouldBeFalse("float_while_not_and_eq()");
     846
     847function float_while_not_and_neq()
     848{
     849    var a = 0.1;
     850    while (!(a != 1.1 && a != 1.1))
     851        return true;
     852    return false;
     853}
     854
     855shouldBeFalse("float_while_not_and_neq()");
     856
     857function float_while_not_and_less()
     858{
     859    var a = 0.1;
     860    while (!(a < 1.1 && a < 1.1))
     861        return true;
     862    return false;
     863}
     864
     865shouldBeFalse("float_while_not_and_less()");
     866
     867function float_while_not_and_lesseq()
     868{
     869    var a = 0.1;
     870    while (!(a <= 1.1 && a <= 1.1))
     871        return true;
     872    return false;
     873}
     874
     875shouldBeFalse("float_while_not_and_lesseq()");
     876
     877function float_for_not_or_eq()
     878{
     879    for (var a = 0.1; !(a == 0.1 || a == 0.1); )
     880        return true;
     881    return false;
     882}
     883
     884shouldBeFalse("float_for_not_or_eq()");
     885
     886function float_for_not_or_neq()
     887{
     888    for (var a = 0.1; !(a != 1.1 || a != 1.1); )
     889        return true;
     890    return false;
     891}
     892
     893shouldBeFalse("float_for_not_or_neq()");
     894
     895function float_for_not_or_less()
     896{
     897    for (var a = 0.1; !(a < 1.1 || a < 1.1); )
     898        return true;
     899    return false;
     900}
     901
     902shouldBeFalse("float_for_not_or_less()");
     903
     904function float_for_not_or_lesseq()
     905{
     906    for (var a = 0.1; !(a <= 1.1 || a <= 1.1); )
     907        return true;
     908    return false;
     909}
     910
     911shouldBeFalse("float_for_not_or_lesseq()");
     912
     913function float_for_not_and_eq()
     914{
     915    for (var a = 0.1; !(a == 0.1 && a == 0.1); )
     916        return true;
     917    return false;
     918}
     919
     920shouldBeFalse("float_for_not_and_eq()");
     921
     922function float_for_not_and_neq()
     923{
     924    for (var a = 0.1; !(a != 1.1 && a != 1.1); )
     925        return true;
     926    return false;
     927}
     928
     929shouldBeFalse("float_for_not_and_neq()");
     930
     931function float_for_not_and_less()
     932{
     933    for (var a = 0.1; !(a < 1.1 && a < 1.1); )
     934        return true;
     935    return false;
     936}
     937
     938shouldBeFalse("float_for_not_and_less()");
     939
     940function float_for_not_and_lesseq()
     941{
     942    for (var a = 0.1; !(a <= 1.1 && a <= 1.1); )
     943        return true;
     944    return false;
     945}
     946
     947shouldBeFalse("float_for_not_and_lesseq()");
     948
     949function float_dowhile_not_or_eq()
     950{
     951    var a = 0.1;
     952    var i = 0.1;
     953    do {
     954        if (i > 0.1)
     955            return true;
     956        i++;
     957    } while (!(a == 0.1 || a == 0.1))
     958    return false;
     959}
     960
     961shouldBeFalse("float_dowhile_not_or_eq()");
     962
     963function float_dowhile_not_or_neq()
     964{
     965    var a = 0.1;
     966    var i = 0.1;
     967    do {
     968        if (i > 0.1)
     969            return true;
     970        i++;
     971    } while (!(a != 1.1 || a != 1.1))
     972    return false;
     973}
     974
     975shouldBeFalse("float_dowhile_not_or_neq()");
     976
     977function float_dowhile_not_or_less()
     978{
     979    var a = 0.1;
     980    var i = 0.1;
     981    do {
     982        if (i > 0.1)
     983            return true;
     984        i++;
     985    } while (!(a < 1.1 || a < 1.1))
     986    return false;
     987}
     988
     989shouldBeFalse("float_dowhile_not_or_less()");
     990
     991function float_dowhile_not_or_lesseq()
     992{
     993    var a = 0.1;
     994    var i = 0.1;
     995    do {
     996        if (i > 0.1)
     997            return true;
     998        i++;
     999    } while (!(a <= 1.1 || a <= 1.1))
     1000    return false;
     1001}
     1002
     1003shouldBeFalse("float_dowhile_not_or_lesseq()");
     1004
     1005function float_dowhile_not_and_eq()
     1006{
     1007    var a = 0.1;
     1008    var i = 0.1;
     1009    do {
     1010        if (i > 0.1)
     1011            return true;
     1012        i++;
     1013    } while (!(a == 0.1 && a == 0.1))
     1014    return false;
     1015}
     1016
     1017shouldBeFalse("float_dowhile_not_and_eq()");
     1018
     1019function float_dowhile_not_and_neq()
     1020{
     1021    var a = 0.1;
     1022    var i = 0.1;
     1023    do {
     1024        if (i > 0.1)
     1025            return true;
     1026        i++;
     1027    } while (!(a != 1.1 && a != 1.1))
     1028    return false;
     1029}
     1030
     1031shouldBeFalse("float_dowhile_not_and_neq()");
     1032
     1033function float_dowhile_not_and_less()
     1034{
     1035    var a = 0.1;
     1036    var i = 0.1;
     1037    do {
     1038        if (i > 0.1)
     1039            return true;
     1040        i++;
     1041    } while (!(a < 1.1 && a < 1.1))
     1042    return false;
     1043}
     1044
     1045shouldBeFalse("float_dowhile_not_and_less()");
     1046
     1047function float_dowhile_not_and_lesseq()
     1048{
     1049    var a = 0.1;
     1050    var i = 0.1;
     1051    do {
     1052        if (i > 0.1)
     1053            return true;
     1054        i++;
     1055    } while (!(a <= 1.1 && a <= 1.1))
     1056    return false;
     1057}
     1058
    2691059var successfullyParsed = true;
Note: See TracChangeset for help on using the changeset viewer.