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):
File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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:
Note: See TracChangeset for help on using the changeset viewer.