Changeset 58902 in webkit for trunk/JavaScriptCore


Ignore:
Timestamp:
May 6, 2010, 12:39:54 PM (15 years ago)
Author:
[email protected]
Message:

2010-05-06 Oliver Hunt <[email protected]>

Reviewed by Geoffrey Garen.

Improve performance of single character string compares
https://bugs.webkit.org/show_bug.cgi?id=38659

Add logic to the jit to identify comparisons to single character string literals
and then just perform the comparison inline, rather than ignoring the evidence
and attempting to perform an integer comparison.

Multiple changes required -- add jnlesseq opcode, add helper function to identify
single character string constants, add a helper to load single character strings.
Then add the 32_64 and normal codepaths to the JIT.

  • assembler/MacroAssemblerX86Common.h: (JSC::MacroAssemblerX86Common::load16):
  • bytecode/CodeBlock.cpp: (JSC::CodeBlock::dump):
  • bytecode/Opcode.h:
  • bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::emitJumpIfTrue):
  • interpreter/Interpreter.cpp: (JSC::Interpreter::privateExecute):
  • jit/JIT.cpp: (JSC::JIT::privateCompileMainPass): (JSC::JIT::privateCompileSlowCases):
  • jit/JIT.h:
  • jit/JITArithmetic.cpp: (JSC::JIT::emit_op_jnless): (JSC::JIT::emitSlow_op_jnless): (JSC::JIT::emit_op_jless): (JSC::JIT::emitSlow_op_jless): (JSC::JIT::emit_op_jlesseq): (JSC::JIT::emit_op_jnlesseq): (JSC::JIT::emitSlow_op_jlesseq): (JSC::JIT::emitSlow_op_jnlesseq):
  • jit/JITArithmetic32_64.cpp: (JSC::JIT::emit_op_jnless): (JSC::JIT::emitSlow_op_jnless): (JSC::JIT::emit_op_jless): (JSC::JIT::emitSlow_op_jless): (JSC::JIT::emit_op_jlesseq): (JSC::JIT::emit_op_jnlesseq): (JSC::JIT::emitSlow_op_jlesseq): (JSC::JIT::emitSlow_op_jnlesseq): (JSC::JIT::emitBinaryDoubleOp):
  • jit/JITInlineMethods.h: (JSC::JIT::emitLoadCharacterString): (JSC::JIT::isOperandConstantImmediateChar):
  • jit/JSInterfaceJIT.h: (JSC::ThunkHelpers::stringImplDataOffset): (JSC::ThunkHelpers::jsStringLengthOffset): (JSC::ThunkHelpers::jsStringValueOffset): Moved from ThunkGenerators to make it possible to share.
  • jit/ThunkGenerators.cpp:

2010-05-06 Oliver Hunt <[email protected]>

Reviewed by Geoffrey Garen.

Improve performance of single character string compares
https://bugs.webkit.org/show_bug.cgi?id=38659

Add many tests of <, >, <=, >=, ==, ===, !=, !== as the existing
tests were woefully inadequate.

  • fast/js/comparison-operators-expected.txt: Added.
  • fast/js/comparison-operators-greater-expected.txt: Added.
  • fast/js/comparison-operators-greater.html: Added.
  • fast/js/comparison-operators-less-expected.txt: Added.
  • fast/js/comparison-operators-less.html: Added.
  • fast/js/comparison-operators.html: Added.
  • fast/js/script-tests/comparison-operators-greater.js: Added. (description.makeTest.func.f.toString): (description.makeTest): (doTest):
  • fast/js/script-tests/comparison-operators-less.js: Added. (description.makeTest.func.f.toString): (description.makeTest): (doTest):
  • fast/js/script-tests/comparison-operators.js: Added. (description.makeTest.func.f.toString): (description.makeTest): (doTest):
Location:
trunk/JavaScriptCore
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r58885 r58902  
     12010-05-06  Oliver Hunt  <[email protected]>
     2
     3        Reviewed by Geoffrey Garen.
     4
     5        Improve performance of single character string compares
     6        https://bugs.webkit.org/show_bug.cgi?id=38659
     7
     8        Add logic to the jit to identify comparisons to single character string literals
     9        and then just perform the comparison inline, rather than ignoring the evidence
     10        and attempting to perform an integer comparison.
     11
     12        Multiple changes required -- add jnlesseq opcode, add helper function to identify
     13        single character string constants, add a helper to load single character strings.
     14        Then add the 32_64 and normal codepaths to the JIT.
     15
     16        * assembler/MacroAssemblerX86Common.h:
     17        (JSC::MacroAssemblerX86Common::load16):
     18        * bytecode/CodeBlock.cpp:
     19        (JSC::CodeBlock::dump):
     20        * bytecode/Opcode.h:
     21        * bytecompiler/BytecodeGenerator.cpp:
     22        (JSC::BytecodeGenerator::emitJumpIfTrue):
     23        * interpreter/Interpreter.cpp:
     24        (JSC::Interpreter::privateExecute):
     25        * jit/JIT.cpp:
     26        (JSC::JIT::privateCompileMainPass):
     27        (JSC::JIT::privateCompileSlowCases):
     28        * jit/JIT.h:
     29        * jit/JITArithmetic.cpp:
     30        (JSC::JIT::emit_op_jnless):
     31        (JSC::JIT::emitSlow_op_jnless):
     32        (JSC::JIT::emit_op_jless):
     33        (JSC::JIT::emitSlow_op_jless):
     34        (JSC::JIT::emit_op_jlesseq):
     35        (JSC::JIT::emit_op_jnlesseq):
     36        (JSC::JIT::emitSlow_op_jlesseq):
     37        (JSC::JIT::emitSlow_op_jnlesseq):
     38        * jit/JITArithmetic32_64.cpp:
     39        (JSC::JIT::emit_op_jnless):
     40        (JSC::JIT::emitSlow_op_jnless):
     41        (JSC::JIT::emit_op_jless):
     42        (JSC::JIT::emitSlow_op_jless):
     43        (JSC::JIT::emit_op_jlesseq):
     44        (JSC::JIT::emit_op_jnlesseq):
     45        (JSC::JIT::emitSlow_op_jlesseq):
     46        (JSC::JIT::emitSlow_op_jnlesseq):
     47        (JSC::JIT::emitBinaryDoubleOp):
     48        * jit/JITInlineMethods.h:
     49        (JSC::JIT::emitLoadCharacterString):
     50        (JSC::JIT::isOperandConstantImmediateChar):
     51        * jit/JSInterfaceJIT.h:
     52        (JSC::ThunkHelpers::stringImplDataOffset):
     53        (JSC::ThunkHelpers::jsStringLengthOffset):
     54        (JSC::ThunkHelpers::jsStringValueOffset):
     55         Moved from ThunkGenerators to make it possible to share.
     56        * jit/ThunkGenerators.cpp:
     57
    1582010-05-06  Martin Robinson  <[email protected]>
    259
  • trunk/JavaScriptCore/assembler/MacroAssemblerX86Common.h

    r58562 r58902  
    365365    {
    366366        m_assembler.movzwl_mr(address.offset, address.base, address.index, address.scale, dest);
     367    }
     368   
     369    void load16(Address address, RegisterID dest)
     370    {
     371        m_assembler.movzwl_mr(address.offset, address.base, dest);
    367372    }
    368373
  • trunk/JavaScriptCore/bytecode/CodeBlock.cpp

    r58705 r58902  
    932932            break;
    933933        }
     934        case op_jlesseq: {
     935            int r0 = (++it)->u.operand;
     936            int r1 = (++it)->u.operand;
     937            int offset = (++it)->u.operand;
     938            printf("[%4d] jlesseq\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
     939            break;
     940        }
    934941        case op_loop_if_lesseq: {
    935942            int r0 = (++it)->u.operand;
  • trunk/JavaScriptCore/bytecode/Opcode.h

    r57955 r58902  
    139139        macro(op_jnlesseq, 4) \
    140140        macro(op_jless, 4) \
     141        macro(op_jlesseq, 4) \
    141142        macro(op_jmp_scopes, 3) \
    142143        macro(op_loop, 2) \
  • trunk/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r57955 r58902  
    636636            return target;
    637637        }
    638     } else if (m_lastOpcodeID == op_lesseq && !target->isForward()) {
     638    } else if (m_lastOpcodeID == op_lesseq) {
    639639        int dstIndex;
    640640        int src1Index;
     
    647647
    648648            size_t begin = instructions().size();
    649             emitOpcode(op_loop_if_lesseq);
     649            emitOpcode(target->isForward() ? op_jlesseq : op_loop_if_lesseq);
    650650            instructions().append(src1Index);
    651651            instructions().append(src2Index);
  • trunk/JavaScriptCore/interpreter/Interpreter.cpp

    r58012 r58902  
    32103210
    32113211        vPC += OPCODE_LENGTH(op_jnlesseq);
     3212        NEXT_INSTRUCTION();
     3213    }
     3214    DEFINE_OPCODE(op_jlesseq) {
     3215        /* jlesseq src1(r) src2(r) target(offset)
     3216         
     3217         Checks whether register src1 is less than or equal to
     3218         register src2, as with the ECMAScript '<=' operator,
     3219         and then jumps to offset target from the current instruction,
     3220         if and only if the result of the comparison is true.
     3221         */
     3222        JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
     3223        JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
     3224        int target = vPC[3].u.operand;
     3225       
     3226        bool result = jsLessEq(callFrame, src1, src2);
     3227        CHECK_FOR_EXCEPTION();
     3228       
     3229        if (result) {
     3230            vPC += target;
     3231            NEXT_INSTRUCTION();
     3232        }
     3233       
     3234        vPC += OPCODE_LENGTH(op_jlesseq);
    32123235        NEXT_INSTRUCTION();
    32133236    }
  • trunk/JavaScriptCore/jit/JIT.cpp

    r58562 r58902  
    251251        DEFINE_OP(op_jnless)
    252252        DEFINE_OP(op_jless)
     253        DEFINE_OP(op_jlesseq)
    253254        DEFINE_OP(op_jnlesseq)
    254255        DEFINE_OP(op_jsr)
     
    402403        DEFINE_SLOWCASE_OP(op_jnless)
    403404        DEFINE_SLOWCASE_OP(op_jless)
     405        DEFINE_SLOWCASE_OP(op_jlesseq)
    404406        DEFINE_SLOWCASE_OP(op_jnlesseq)
    405407        DEFINE_SLOWCASE_OP(op_jtrue)
  • trunk/JavaScriptCore/jit/JIT.h

    r58562 r58902  
    673673        void emit_op_jnless(Instruction*);
    674674        void emit_op_jless(Instruction*);
     675        void emit_op_jlesseq(Instruction*, bool invert = false);
    675676        void emit_op_jnlesseq(Instruction*);
    676677        void emit_op_jsr(Instruction*);
     
    760761        void emitSlow_op_jnless(Instruction*, Vector<SlowCaseEntry>::iterator&);
    761762        void emitSlow_op_jless(Instruction*, Vector<SlowCaseEntry>::iterator&);
     763        void emitSlow_op_jlesseq(Instruction*, Vector<SlowCaseEntry>::iterator&, bool invert = false);
    762764        void emitSlow_op_jnlesseq(Instruction*, Vector<SlowCaseEntry>::iterator&);
    763765        void emitSlow_op_jtrue(Instruction*, Vector<SlowCaseEntry>::iterator&);
     
    813815        JSValue getConstantOperand(unsigned src);
    814816        bool isOperandConstantImmediateInt(unsigned src);
     817        bool isOperandConstantImmediateChar(unsigned src);
    815818
    816819        Jump getSlowCase(Vector<SlowCaseEntry>::iterator& iter)
     
    836839        void restoreReturnAddressBeforeReturn(Address);
    837840
     841        // Loads the character value of a single character string into dst.
     842        void emitLoadCharacterString(RegisterID src, RegisterID dst, JumpList& failures);
     843       
    838844        void emitTimeoutCheck();
    839845#ifndef NDEBUG
  • trunk/JavaScriptCore/jit/JITArithmetic.cpp

    r58562 r58902  
    311311    // - int immediate to int immediate
    312312
     313    if (isOperandConstantImmediateChar(op1)) {
     314        emitGetVirtualRegister(op2, regT0);
     315        addSlowCase(emitJumpIfNotJSCell(regT0));
     316        JumpList failures;
     317        emitLoadCharacterString(regT0, regT0, failures);
     318        addSlowCase(failures);
     319        addJump(branch32(LessThanOrEqual, regT0, Imm32(asString(getConstantOperand(op1))->tryGetValue()[0])), target);
     320        return;
     321    }
     322    if (isOperandConstantImmediateChar(op2)) {
     323        emitGetVirtualRegister(op1, regT0);
     324        addSlowCase(emitJumpIfNotJSCell(regT0));
     325        JumpList failures;
     326        emitLoadCharacterString(regT0, regT0, failures);
     327        addSlowCase(failures);
     328        addJump(branch32(GreaterThanOrEqual, regT0, Imm32(asString(getConstantOperand(op2))->tryGetValue()[0])), target);
     329        return;
     330    }
    313331    if (isOperandConstantImmediateInt(op2)) {
    314332        emitGetVirtualRegister(op1, regT0);
     
    348366    // - constant int immediate to floating-point number
    349367    // - floating-point number to floating-point number.
     368    if (isOperandConstantImmediateChar(op1) || isOperandConstantImmediateChar(op2)) {
     369        linkSlowCase(iter);
     370        linkSlowCase(iter);
     371        linkSlowCase(iter);
     372        linkSlowCase(iter);
     373        JITStubCall stubCall(this, cti_op_jlesseq);
     374        stubCall.addArgument(op1, regT0);
     375        stubCall.addArgument(op2, regT1);
     376        stubCall.call();
     377        emitJumpSlowToHot(branchTest32(Zero, regT0), target);
     378        return;
     379    }
    350380
    351381    if (isOperandConstantImmediateInt(op2)) {
     
    496526    // - int immediate to int immediate
    497527
     528    if (isOperandConstantImmediateChar(op1)) {
     529        emitGetVirtualRegister(op2, regT0);
     530        addSlowCase(emitJumpIfNotJSCell(regT0));
     531        JumpList failures;
     532        emitLoadCharacterString(regT0, regT0, failures);
     533        addSlowCase(failures);
     534        addJump(branch32(GreaterThan, regT0, Imm32(asString(getConstantOperand(op1))->tryGetValue()[0])), target);
     535        return;
     536    }
     537    if (isOperandConstantImmediateChar(op2)) {
     538        emitGetVirtualRegister(op1, regT0);
     539        addSlowCase(emitJumpIfNotJSCell(regT0));
     540        JumpList failures;
     541        emitLoadCharacterString(regT0, regT0, failures);
     542        addSlowCase(failures);
     543        addJump(branch32(LessThan, regT0, Imm32(asString(getConstantOperand(op2))->tryGetValue()[0])), target);
     544        return;
     545    }
    498546    if (isOperandConstantImmediateInt(op2)) {
    499547        emitGetVirtualRegister(op1, regT0);
     
    533581    // - constant int immediate to floating-point number
    534582    // - floating-point number to floating-point number.
     583    if (isOperandConstantImmediateChar(op1) || isOperandConstantImmediateChar(op2)) {
     584        linkSlowCase(iter);
     585        linkSlowCase(iter);
     586        linkSlowCase(iter);
     587        linkSlowCase(iter);
     588        JITStubCall stubCall(this, cti_op_jlesseq);
     589        stubCall.addArgument(op1, regT0);
     590        stubCall.addArgument(op2, regT1);
     591        stubCall.call();
     592        emitJumpSlowToHot(branchTest32(NonZero, regT0), target);
     593        return;
     594    }
    535595
    536596    if (isOperandConstantImmediateInt(op2)) {
     
    670730}
    671731
    672 void JIT::emit_op_jnlesseq(Instruction* currentInstruction)
     732void JIT::emit_op_jlesseq(Instruction* currentInstruction, bool invert)
    673733{
    674734    unsigned op1 = currentInstruction[1].u.operand;
     
    681741    // - int immediate to int immediate
    682742
     743    if (isOperandConstantImmediateChar(op1)) {
     744        emitGetVirtualRegister(op2, regT0);
     745        addSlowCase(emitJumpIfNotJSCell(regT0));
     746        JumpList failures;
     747        emitLoadCharacterString(regT0, regT0, failures);
     748        addSlowCase(failures);
     749        addJump(branch32(invert ? LessThan : GreaterThanOrEqual, regT0, Imm32(asString(getConstantOperand(op1))->tryGetValue()[0])), target);
     750        return;
     751    }
     752    if (isOperandConstantImmediateChar(op2)) {
     753        emitGetVirtualRegister(op1, regT0);
     754        addSlowCase(emitJumpIfNotJSCell(regT0));
     755        JumpList failures;
     756        emitLoadCharacterString(regT0, regT0, failures);
     757        addSlowCase(failures);
     758        addJump(branch32(invert ? GreaterThan : LessThanOrEqual, regT0, Imm32(asString(getConstantOperand(op2))->tryGetValue()[0])), target);
     759        return;
     760    }
    683761    if (isOperandConstantImmediateInt(op2)) {
    684762        emitGetVirtualRegister(op1, regT0);
     
    689767        int32_t op2imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op2)));
    690768#endif
    691         addJump(branch32(GreaterThan, regT0, Imm32(op2imm)), target);
     769        addJump(branch32(invert ? GreaterThan : LessThanOrEqual, regT0, Imm32(op2imm)), target);
    692770    } else if (isOperandConstantImmediateInt(op1)) {
    693771        emitGetVirtualRegister(op2, regT1);
     
    698776        int32_t op1imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op1)));
    699777#endif
    700         addJump(branch32(LessThan, regT1, Imm32(op1imm)), target);
     778        addJump(branch32(invert ? LessThan : GreaterThanOrEqual, regT1, Imm32(op1imm)), target);
    701779    } else {
    702780        emitGetVirtualRegisters(op1, regT0, op2, regT1);
     
    704782        emitJumpSlowCaseIfNotImmediateInteger(regT1);
    705783
    706         addJump(branch32(GreaterThan, regT0, regT1), target);
    707     }
    708 }
    709 
    710 void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     784        addJump(branch32(invert ? GreaterThan : LessThanOrEqual, regT0, regT1), target);
     785    }
     786}
     787
     788void JIT::emitSlow_op_jlesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter, bool invert)
    711789{
    712790    unsigned op1 = currentInstruction[1].u.operand;
     
    719797    // - floating-point number to floating-point number.
    720798
     799    if (isOperandConstantImmediateChar(op1) || isOperandConstantImmediateChar(op2)) {
     800        linkSlowCase(iter);
     801        linkSlowCase(iter);
     802        linkSlowCase(iter);
     803        linkSlowCase(iter);
     804        JITStubCall stubCall(this, cti_op_jlesseq);
     805        stubCall.addArgument(op1, regT0);
     806        stubCall.addArgument(op2, regT1);
     807        stubCall.call();
     808        emitJumpSlowToHot(branchTest32(invert ? Zero : NonZero, regT0), target);
     809        return;
     810    }
     811
    721812    if (isOperandConstantImmediateInt(op2)) {
    722813        linkSlowCase(iter);
     
    741832            convertInt32ToDouble(regT1, fpRegT1);
    742833
    743             emitJumpSlowToHot(branchDouble(DoubleLessThanOrUnordered, fpRegT1, fpRegT0), target);
     834            emitJumpSlowToHot(branchDouble(invert ? DoubleLessThanOrUnordered : DoubleGreaterThanOrEqual, fpRegT1, fpRegT0), target);
    744835
    745836            emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnlesseq));
     
    758849        stubCall.addArgument(op2, regT2);
    759850        stubCall.call();
    760         emitJumpSlowToHot(branchTest32(Zero, regT0), target);
     851        emitJumpSlowToHot(branchTest32(invert ? Zero : NonZero, regT0), target);
    761852
    762853    } else if (isOperandConstantImmediateInt(op1)) {
     
    782873            convertInt32ToDouble(regT0, fpRegT0);
    783874
    784             emitJumpSlowToHot(branchDouble(DoubleLessThanOrUnordered, fpRegT1, fpRegT0), target);
     875            emitJumpSlowToHot(branchDouble(invert ? DoubleLessThanOrUnordered : DoubleGreaterThanOrEqual, fpRegT1, fpRegT0), target);
    785876
    786877            emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnlesseq));
     
    799890        stubCall.addArgument(regT1);
    800891        stubCall.call();
    801         emitJumpSlowToHot(branchTest32(Zero, regT0), target);
     892        emitJumpSlowToHot(branchTest32(invert ? Zero : NonZero, regT0), target);
    802893
    803894    } else {
     
    828919#endif
    829920
    830             emitJumpSlowToHot(branchDouble(DoubleLessThanOrUnordered, fpRegT1, fpRegT0), target);
     921            emitJumpSlowToHot(branchDouble(invert ? DoubleLessThanOrUnordered : DoubleGreaterThanOrEqual, fpRegT1, fpRegT0), target);
    831922
    832923            emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnlesseq));
     
    851942        stubCall.addArgument(regT1);
    852943        stubCall.call();
    853         emitJumpSlowToHot(branchTest32(Zero, regT0), target);
    854     }
     944        emitJumpSlowToHot(branchTest32(invert ? Zero : NonZero, regT0), target);
     945    }
     946}
     947
     948void JIT::emit_op_jnlesseq(Instruction* currentInstruction)
     949{
     950    emit_op_jlesseq(currentInstruction, true);
     951}
     952
     953void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     954{
     955    emitSlow_op_jlesseq(currentInstruction, iter, true);
    855956}
    856957
  • trunk/JavaScriptCore/jit/JITArithmetic32_64.cpp

    r58562 r58902  
    9595    JumpList notInt32Op2;
    9696
    97     // Int32 less.
     97    // Character less.
     98    if (isOperandConstantImmediateChar(op1)) {
     99        emitLoad(op2, regT1, regT0);
     100        addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
     101        JumpList failures;
     102        emitLoadCharacterString(regT0, regT0, failures);
     103        addSlowCase(failures);
     104        addJump(branch32(LessThanOrEqual, regT0, Imm32(asString(getConstantOperand(op1))->tryGetValue()[0])), target);
     105        return;
     106    }
     107    if (isOperandConstantImmediateChar(op2)) {
     108        emitLoad(op1, regT1, regT0);
     109        addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
     110        JumpList failures;
     111        emitLoadCharacterString(regT0, regT0, failures);
     112        addSlowCase(failures);
     113        addJump(branch32(GreaterThanOrEqual, regT0, Imm32(asString(getConstantOperand(op2))->tryGetValue()[0])), target);
     114        return;
     115    }
    98116    if (isOperandConstantImmediateInt(op1)) {
     117        // Int32 less.
    99118        emitLoad(op2, regT3, regT2);
    100119        notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
     
    129148    unsigned target = currentInstruction[3].u.operand;
    130149
    131     if (!supportsFloatingPoint()) {
    132         if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2))
     150    if (isOperandConstantImmediateChar(op1) || isOperandConstantImmediateChar(op2)) {
     151        linkSlowCase(iter);
     152        linkSlowCase(iter);
     153        linkSlowCase(iter);
     154        linkSlowCase(iter);
     155    } else {
     156        if (!supportsFloatingPoint()) {
     157            if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2))
     158                linkSlowCase(iter); // int32 check
    133159            linkSlowCase(iter); // int32 check
    134         linkSlowCase(iter); // int32 check
    135     } else {
    136         if (!isOperandConstantImmediateInt(op1)) {
    137             linkSlowCase(iter); // double check
    138             linkSlowCase(iter); // int32 check
     160        } else {
     161            if (!isOperandConstantImmediateInt(op1)) {
     162                linkSlowCase(iter); // double check
     163                linkSlowCase(iter); // int32 check
     164            }
     165            if (isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2))
     166                linkSlowCase(iter); // double check
    139167        }
    140         if (isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2))
    141             linkSlowCase(iter); // double check
    142168    }
    143169
     
    158184    JumpList notInt32Op2;
    159185
    160     // Int32 less.
     186    // Character less.
     187    if (isOperandConstantImmediateChar(op1)) {
     188        emitLoad(op2, regT1, regT0);
     189        addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
     190        JumpList failures;
     191        emitLoadCharacterString(regT0, regT0, failures);
     192        addSlowCase(failures);
     193        addJump(branch32(GreaterThan, regT0, Imm32(asString(getConstantOperand(op1))->tryGetValue()[0])), target);
     194        return;
     195    }
     196    if (isOperandConstantImmediateChar(op2)) {
     197        emitLoad(op1, regT1, regT0);
     198        addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
     199        JumpList failures;
     200        emitLoadCharacterString(regT0, regT0, failures);
     201        addSlowCase(failures);
     202        addJump(branch32(LessThan, regT0, Imm32(asString(getConstantOperand(op2))->tryGetValue()[0])), target);
     203        return;
     204    }
    161205    if (isOperandConstantImmediateInt(op1)) {
    162206        emitLoad(op2, regT3, regT2);
     
    191235    unsigned op2 = currentInstruction[2].u.operand;
    192236    unsigned target = currentInstruction[3].u.operand;
    193 
    194     if (!supportsFloatingPoint()) {
    195         if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2))
     237   
     238    if (isOperandConstantImmediateChar(op1) || isOperandConstantImmediateChar(op2)) {
     239        linkSlowCase(iter);
     240        linkSlowCase(iter);
     241        linkSlowCase(iter);
     242        linkSlowCase(iter);
     243    } else {
     244        if (!supportsFloatingPoint()) {
     245            if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2))
     246                linkSlowCase(iter); // int32 check
    196247            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
     248        } else {
     249            if (!isOperandConstantImmediateInt(op1)) {
     250                linkSlowCase(iter); // double check
     251                linkSlowCase(iter); // int32 check
     252            }
     253            if (isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2))
     254                linkSlowCase(iter); // double check
    202255        }
    203         if (isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2))
    204             linkSlowCase(iter); // double check
    205     }
    206 
     256    }
    207257    JITStubCall stubCall(this, cti_op_jless);
    208258    stubCall.addArgument(op1);
     
    212262}
    213263
    214 void JIT::emit_op_jnlesseq(Instruction* currentInstruction)
     264void JIT::emit_op_jlesseq(Instruction* currentInstruction, bool invert)
    215265{
    216266    unsigned op1 = currentInstruction[1].u.operand;
     
    221271    JumpList notInt32Op2;
    222272
    223     // Int32 less.
     273    // Character less.
     274    if (isOperandConstantImmediateChar(op1)) {
     275        emitLoad(op2, regT1, regT0);
     276        addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
     277        JumpList failures;
     278        emitLoadCharacterString(regT0, regT0, failures);
     279        addSlowCase(failures);
     280        addJump(branch32(invert ? LessThan : GreaterThanOrEqual, regT0, Imm32(asString(getConstantOperand(op1))->tryGetValue()[0])), target);
     281        return;
     282    }
     283    if (isOperandConstantImmediateChar(op2)) {
     284        emitLoad(op1, regT1, regT0);
     285        addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
     286        JumpList failures;
     287        emitLoadCharacterString(regT0, regT0, failures);
     288        addSlowCase(failures);
     289        addJump(branch32(invert ? GreaterThan : LessThanOrEqual, regT0, Imm32(asString(getConstantOperand(op2))->tryGetValue()[0])), target);
     290        return;
     291    }
    224292    if (isOperandConstantImmediateInt(op1)) {
    225293        emitLoad(op2, regT3, regT2);
    226294        notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
    227         addJump(branch32(LessThan, regT2, Imm32(getConstantOperand(op1).asInt32())), target);
     295        addJump(branch32(invert ? LessThan : GreaterThan, regT2, Imm32(getConstantOperand(op1).asInt32())), target);
    228296    } else if (isOperandConstantImmediateInt(op2)) {
    229297        emitLoad(op1, regT1, regT0);
    230298        notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
    231         addJump(branch32(GreaterThan, regT0, Imm32(getConstantOperand(op2).asInt32())), target);
     299        addJump(branch32(invert ? GreaterThan : LessThanOrEqual, regT0, Imm32(getConstantOperand(op2).asInt32())), target);
    232300    } else {
    233301        emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
    234302        notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
    235303        notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
    236         addJump(branch32(GreaterThan, regT0, regT2), target);
     304        addJump(branch32(invert ? GreaterThan : LessThanOrEqual, regT0, regT2), target);
    237305    }
    238306
     
    245313
    246314    // Double less.
    247     emitBinaryDoubleOp(op_jnlesseq, target, op1, op2, OperandTypes(), notInt32Op1, notInt32Op2, !isOperandConstantImmediateInt(op1), isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2));
     315    emitBinaryDoubleOp(invert ? op_jnlesseq : op_jlesseq, target, op1, op2, OperandTypes(), notInt32Op1, notInt32Op2, !isOperandConstantImmediateInt(op1), isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2));
    248316    end.link(this);
    249317}
    250318
    251 void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     319void JIT::emitSlow_op_jlesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter, bool invert)
    252320{
    253321    unsigned op1 = currentInstruction[1].u.operand;
     
    255323    unsigned target = currentInstruction[3].u.operand;
    256324
    257     if (!supportsFloatingPoint()) {
    258         if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2))
     325    if (isOperandConstantImmediateChar(op1) || isOperandConstantImmediateChar(op2)) {
     326        linkSlowCase(iter);
     327        linkSlowCase(iter);
     328        linkSlowCase(iter);
     329        linkSlowCase(iter);
     330    } else {
     331        if (!supportsFloatingPoint()) {
     332            if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2))
     333                linkSlowCase(iter); // int32 check
    259334            linkSlowCase(iter); // int32 check
    260         linkSlowCase(iter); // int32 check
    261     } else {
    262         if (!isOperandConstantImmediateInt(op1)) {
    263             linkSlowCase(iter); // double check
    264             linkSlowCase(iter); // int32 check
     335        } else {
     336            if (!isOperandConstantImmediateInt(op1)) {
     337                linkSlowCase(iter); // double check
     338                linkSlowCase(iter); // int32 check
     339            }
     340            if (isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2))
     341                linkSlowCase(iter); // double check
    265342        }
    266         if (isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2))
    267             linkSlowCase(iter); // double check
    268343    }
    269344
     
    272347    stubCall.addArgument(op2);
    273348    stubCall.call();
    274     emitJumpSlowToHot(branchTest32(Zero, regT0), target);
     349    emitJumpSlowToHot(branchTest32(invert ? Zero : NonZero, regT0), target);
     350}
     351
     352void JIT::emit_op_jnlesseq(Instruction* currentInstruction)
     353{
     354    emit_op_jlesseq(currentInstruction, true);
     355}
     356
     357void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     358{
     359    emitSlow_op_jlesseq(currentInstruction, iter, true);
    275360}
    276361
     
    9841069                addJump(branchDouble(DoubleLessThan, fpRegT2, fpRegT0), dst);
    9851070                break;
     1071            case op_jlesseq:
     1072                emitLoadDouble(op1, fpRegT2);
     1073                addJump(branchDouble(DoubleLessThanOrEqual, fpRegT2, fpRegT0), dst);
     1074                break;
    9861075            case op_jnlesseq:
    9871076                emitLoadDouble(op1, fpRegT2);
     
    10441133                emitLoadDouble(op2, fpRegT1);
    10451134                addJump(branchDouble(DoubleLessThanOrUnordered, fpRegT1, fpRegT0), dst);
     1135                break;
     1136            case op_jlesseq:
     1137                emitLoadDouble(op2, fpRegT1);
     1138                addJump(branchDouble(DoubleLessThanOrEqual, fpRegT1, fpRegT0), dst);
    10461139                break;
    10471140            default:
  • trunk/JavaScriptCore/jit/JITInlineMethods.h

    r58469 r58902  
    9494}
    9595
     96ALWAYS_INLINE void JIT::emitLoadCharacterString(RegisterID src, RegisterID dst, JumpList& failures)
     97{
     98    failures.append(branchPtr(NotEqual, Address(src), ImmPtr(m_globalData->jsStringVPtr)));
     99    failures.append(branchTest32(NonZero, Address(src, OBJECT_OFFSETOF(JSString, m_fiberCount))));
     100    failures.append(branch32(NotEqual, MacroAssembler::Address(src, ThunkHelpers::jsStringLengthOffset()), Imm32(1)));
     101    loadPtr(MacroAssembler::Address(src, ThunkHelpers::jsStringValueOffset()), dst);
     102    loadPtr(MacroAssembler::Address(dst, ThunkHelpers::stringImplDataOffset()), dst);
     103    load16(MacroAssembler::Address(dst, 0), dst);
     104}
     105
    96106ALWAYS_INLINE void JIT::emitGetFromCallFrameHeader32(RegisterFile::CallFrameHeaderEntry entry, RegisterID to, RegisterID from)
    97107{
     
    323333#endif
    324334#endif
     335
     336ALWAYS_INLINE bool JIT::isOperandConstantImmediateChar(unsigned src)
     337{
     338    return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isString() && asString(getConstantOperand(src).asCell())->length() == 1;
     339}
    325340
    326341#if USE(JSVALUE32_64)
  • trunk/JavaScriptCore/jit/JSInterfaceJIT.h

    r58469 r58902  
    176176    };
    177177
     178    struct ThunkHelpers {
     179        static unsigned stringImplDataOffset() { return WebCore::StringImpl::dataOffset(); }
     180        static unsigned jsStringLengthOffset() { return OBJECT_OFFSETOF(JSString, m_length); }
     181        static unsigned jsStringValueOffset() { return OBJECT_OFFSETOF(JSString, m_value); }
     182    };
     183
    178184#if USE(JSVALUE32_64)
    179185    inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID payload)
  • trunk/JavaScriptCore/jit/ThunkGenerators.cpp

    r58712 r58902  
    3333
    3434namespace JSC {
    35 
    36 struct ThunkHelpers {
    37     static unsigned stringImplDataOffset() { return WebCore::StringImpl::dataOffset(); }
    38     static unsigned jsStringLengthOffset() { return OBJECT_OFFSETOF(JSString, m_length); }
    39     static unsigned jsStringValueOffset() { return OBJECT_OFFSETOF(JSString, m_value); }
    40 };
    4135
    4236static void stringCharLoad(SpecializedThunkJIT& jit)
Note: See TracChangeset for help on using the changeset viewer.