Changeset 68338 in webkit


Ignore:
Timestamp:
Sep 25, 2010 2:42:00 PM (14 years ago)
Author:
oliver@apple.com
Message:

2010-09-25 Oliver Hunt <oliver@apple.com>

Reviewed by Cameron Zwarich.

Avoid constructing arguments object when accessing length and index properties
https://bugs.webkit.org/show_bug.cgi?id=46572

Add opcodes to read argument length and properties, and then implement them.
Much like other lazy opcodes these opcodes take a fast path when the arguments
object has not been instantiated, and fall back on generic access mechanisms
if they are acting on an instantiated object.

3% win on v8-earleyboyer, no change elsewhere.

  • bytecode/CodeBlock.cpp: (JSC::CodeBlock::dump):
  • bytecode/Opcode.h:
  • bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::emitGetArgumentsLength): (JSC::BytecodeGenerator::emitGetArgumentByVal):
  • bytecompiler/BytecodeGenerator.h:
  • bytecompiler/NodesCodegen.cpp: (JSC::BracketAccessorNode::emitBytecode): (JSC::DotAccessorNode::emitBytecode):
  • interpreter/Interpreter.cpp: (JSC::Interpreter::privateExecute):
  • jit/JIT.cpp: (JSC::JIT::privateCompileMainPass): (JSC::JIT::privateCompileSlowCases):
  • jit/JIT.h:
  • jit/JITOpcodes.cpp: (JSC::JIT::emit_op_get_arguments_length): (JSC::JIT::emitSlow_op_get_arguments_length): (JSC::JIT::emit_op_get_argument_by_val): (JSC::JIT::emitSlow_op_get_argument_by_val):
  • jit/JITOpcodes32_64.cpp: (JSC::JIT::emit_op_get_arguments_length): (JSC::JIT::emitSlow_op_get_arguments_length): (JSC::JIT::emit_op_get_argument_by_val): (JSC::JIT::emitSlow_op_get_argument_by_val):
Location:
trunk/JavaScriptCore
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r68330 r68338  
     12010-09-25  Oliver Hunt  <oliver@apple.com>
     2
     3        Reviewed by Cameron Zwarich.
     4
     5        Avoid constructing arguments object when accessing length and index properties
     6        https://bugs.webkit.org/show_bug.cgi?id=46572
     7
     8        Add opcodes to read argument length and properties, and then implement them.
     9        Much like other lazy opcodes these opcodes take a fast path when the arguments
     10        object has not been instantiated, and fall back on generic access mechanisms
     11        if they are acting on an instantiated object.
     12
     13        3% win on v8-earleyboyer, no change elsewhere.
     14
     15        * bytecode/CodeBlock.cpp:
     16        (JSC::CodeBlock::dump):
     17        * bytecode/Opcode.h:
     18        * bytecompiler/BytecodeGenerator.cpp:
     19        (JSC::BytecodeGenerator::emitGetArgumentsLength):
     20        (JSC::BytecodeGenerator::emitGetArgumentByVal):
     21        * bytecompiler/BytecodeGenerator.h:
     22        * bytecompiler/NodesCodegen.cpp:
     23        (JSC::BracketAccessorNode::emitBytecode):
     24        (JSC::DotAccessorNode::emitBytecode):
     25        * interpreter/Interpreter.cpp:
     26        (JSC::Interpreter::privateExecute):
     27        * jit/JIT.cpp:
     28        (JSC::JIT::privateCompileMainPass):
     29        (JSC::JIT::privateCompileSlowCases):
     30        * jit/JIT.h:
     31        * jit/JITOpcodes.cpp:
     32        (JSC::JIT::emit_op_get_arguments_length):
     33        (JSC::JIT::emitSlow_op_get_arguments_length):
     34        (JSC::JIT::emit_op_get_argument_by_val):
     35        (JSC::JIT::emitSlow_op_get_argument_by_val):
     36        * jit/JITOpcodes32_64.cpp:
     37        (JSC::JIT::emit_op_get_arguments_length):
     38        (JSC::JIT::emitSlow_op_get_arguments_length):
     39        (JSC::JIT::emit_op_get_argument_by_val):
     40        (JSC::JIT::emitSlow_op_get_argument_by_val):
     41
    1422010-09-25  Patrick Gansterer  <paroga@webkit.org>
    243
  • trunk/JavaScriptCore/bytecode/CodeBlock.cpp

    r68281 r68338  
    843843            break;
    844844        }
     845        case op_get_arguments_length: {
     846            printUnaryOp(exec, location, it, "get_arguments_length");
     847            break;
     848        }
    845849        case op_put_by_id: {
    846850            printPutByIdOp(exec, location, it, "put_by_id");
     
    889893            int r2 = (++it)->u.operand;
    890894            printf("[%4d] get_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
     895            break;
     896        }
     897        case op_get_argument_by_val: {
     898            int r0 = (++it)->u.operand;
     899            int r1 = (++it)->u.operand;
     900            int r2 = (++it)->u.operand;
     901            printf("[%4d] get_argument_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
    891902            break;
    892903        }
  • trunk/JavaScriptCore/bytecode/Opcode.h

    r68281 r68338  
    121121        macro(op_get_array_length, 8) \
    122122        macro(op_get_string_length, 8) \
     123        macro(op_get_arguments_length, 4) \
    123124        macro(op_put_by_id, 9) \
    124125        macro(op_put_by_id_transition, 9) \
     
    127128        macro(op_del_by_id, 4) \
    128129        macro(op_get_by_val, 4) \
     130        macro(op_get_argument_by_val, 4) \
    129131        macro(op_get_by_pname, 7) \
    130132        macro(op_put_by_val, 4) \
  • trunk/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r68281 r68338  
    13291329}
    13301330
     1331RegisterID* BytecodeGenerator::emitGetArgumentsLength(RegisterID* dst, RegisterID* base)
     1332{
     1333    emitOpcode(op_get_arguments_length);
     1334    instructions().append(dst->index());
     1335    ASSERT(base->index() == m_codeBlock->argumentsRegister());
     1336    instructions().append(base->index());
     1337    instructions().append(addConstant(propertyNames().arguments));
     1338    return dst;
     1339}
     1340
    13311341RegisterID* BytecodeGenerator::emitPutById(RegisterID* base, const Identifier& property, RegisterID* value)
    13321342{
     
    13961406}
    13971407
     1408RegisterID* BytecodeGenerator::emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
     1409{
     1410    emitOpcode(op_get_argument_by_val);
     1411    instructions().append(dst->index());
     1412    ASSERT(base->index() == m_codeBlock->argumentsRegister());
     1413    instructions().append(base->index());
     1414    instructions().append(property->index());
     1415    return dst;
     1416}
     1417
    13981418RegisterID* BytecodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
    13991419{
  • trunk/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r68281 r68338  
    335335
    336336        RegisterID* emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property);
     337        RegisterID* emitGetArgumentsLength(RegisterID* dst, RegisterID* base);
    337338        RegisterID* emitPutById(RegisterID* base, const Identifier& property, RegisterID* value);
    338339        RegisterID* emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value);
    339340        RegisterID* emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier&);
    340341        RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
     342        RegisterID* emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
    341343        RegisterID* emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value);
    342344        RegisterID* emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
  • trunk/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r65593 r68338  
    291291RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    292292{
     293    if (m_base->isResolveNode() && generator.willResolveToArguments(static_cast<ResolveNode*>(m_base)->identifier())) {
     294        RegisterID* property = generator.emitNode(m_subscript);
     295        generator.emitExpressionInfo(divot(), startOffset(), endOffset());   
     296        return generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedRegisterForArguments(), property);
     297    }
     298
    293299    RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator));
    294300    RegisterID* property = generator.emitNode(m_subscript);
     
    301307RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    302308{
     309    if (m_ident == generator.propertyNames().length) {
     310        if (!m_base->isResolveNode())
     311            goto nonArgumentsPath;
     312        ResolveNode* resolveNode = static_cast<ResolveNode*>(m_base);
     313        if (!generator.willResolveToArguments(resolveNode->identifier()))
     314            goto nonArgumentsPath;
     315        generator.emitExpressionInfo(divot(), startOffset(), endOffset());   
     316        return generator.emitGetArgumentsLength(generator.finalDestination(dst), generator.uncheckedRegisterForArguments());
     317    }
     318
     319nonArgumentsPath:
    303320    RegisterID* base = generator.emitNode(m_base);
    304321    generator.emitExpressionInfo(divot(), startOffset(), endOffset());
  • trunk/JavaScriptCore/interpreter/Interpreter.cpp

    r68281 r68338  
    30913091        vPC += OPCODE_LENGTH(op_get_by_pname);
    30923092        NEXT_INSTRUCTION();
     3093    }
     3094    DEFINE_OPCODE(op_get_arguments_length) {
     3095        int dst = vPC[1].u.operand;
     3096        int argumentsRegister = vPC[2].u.operand;
     3097        int property = vPC[3].u.operand;
     3098        JSValue arguments = callFrame->r(argumentsRegister).jsValue();
     3099        if (arguments) {
     3100            Identifier& ident = codeBlock->identifier(property);
     3101            PropertySlot slot(arguments);
     3102            JSValue result = arguments.get(callFrame, ident, slot);
     3103            CHECK_FOR_EXCEPTION();
     3104            callFrame->r(dst) = result;
     3105        } else
     3106            callFrame->r(dst) = jsNumber(callFrame, callFrame->argumentCount());
     3107
     3108        vPC += OPCODE_LENGTH(op_get_arguments_length);
     3109        NEXT_INSTRUCTION();
     3110    }
     3111    DEFINE_OPCODE(op_get_argument_by_val) {
     3112        int dst = vPC[1].u.operand;
     3113        int argumentsRegister = vPC[2].u.operand;
     3114        int property = vPC[3].u.operand;
     3115        JSValue arguments = callFrame->r(argumentsRegister).jsValue();
     3116        JSValue subscript = callFrame->r(property).jsValue();
     3117        if (!arguments && subscript.isUInt32() && subscript.asUInt32() < callFrame->argumentCount()) {
     3118            unsigned arg = subscript.asUInt32() + 1;
     3119            unsigned numParameters = callFrame->codeBlock()->m_numParameters;
     3120            if (arg < numParameters)
     3121                callFrame->r(dst) = callFrame->r(arg - RegisterFile::CallFrameHeaderSize - numParameters);
     3122            else
     3123                callFrame->r(dst) = callFrame->r(arg - RegisterFile::CallFrameHeaderSize - numParameters - callFrame->argumentCount() - 1);
     3124            vPC += OPCODE_LENGTH(op_get_argument_by_val);
     3125            NEXT_INSTRUCTION();
     3126        }
     3127        if (!arguments) {
     3128            Arguments* arguments = new (globalData) Arguments(callFrame);
     3129            callFrame->r(dst) = JSValue(arguments);
     3130            callFrame->r(unmodifiedArgumentsRegister(dst)) = JSValue(arguments);
     3131        }
     3132        // fallthrough
    30933133    }
    30943134    DEFINE_OPCODE(op_get_by_val) {
  • trunk/JavaScriptCore/jit/JIT.cpp

    r68281 r68338  
    239239        DEFINE_OP(op_eq_null)
    240240        DEFINE_OP(op_get_by_id)
     241        DEFINE_OP(op_get_arguments_length)
    241242        DEFINE_OP(op_get_by_val)
     243        DEFINE_OP(op_get_argument_by_val)
    242244        DEFINE_OP(op_get_by_pname)
    243245        DEFINE_OP(op_get_global_var)
     
    400402        DEFINE_SLOWCASE_OP(op_eq)
    401403        DEFINE_SLOWCASE_OP(op_get_by_id)
     404        DEFINE_SLOWCASE_OP(op_get_arguments_length)
    402405        DEFINE_SLOWCASE_OP(op_get_by_val)
     406        DEFINE_SLOWCASE_OP(op_get_argument_by_val)
    403407        DEFINE_SLOWCASE_OP(op_get_by_pname)
    404408        DEFINE_SLOWCASE_OP(op_instanceof)
  • trunk/JavaScriptCore/jit/JIT.h

    r68281 r68338  
    749749        void emit_op_eq_null(Instruction*);
    750750        void emit_op_get_by_id(Instruction*);
     751        void emit_op_get_arguments_length(Instruction*);
    751752        void emit_op_get_by_val(Instruction*);
     753        void emit_op_get_argument_by_val(Instruction*);
    752754        void emit_op_get_by_pname(Instruction*);
    753755        void emit_op_get_global_var(Instruction*);
     
    847849        void emitSlow_op_eq(Instruction*, Vector<SlowCaseEntry>::iterator&);
    848850        void emitSlow_op_get_by_id(Instruction*, Vector<SlowCaseEntry>::iterator&);
     851        void emitSlow_op_get_arguments_length(Instruction*, Vector<SlowCaseEntry>::iterator&);
    849852        void emitSlow_op_get_by_val(Instruction*, Vector<SlowCaseEntry>::iterator&);
     853        void emitSlow_op_get_argument_by_val(Instruction*, Vector<SlowCaseEntry>::iterator&);
    850854        void emitSlow_op_get_by_pname(Instruction*, Vector<SlowCaseEntry>::iterator&);
    851855        void emitSlow_op_instanceof(Instruction*, Vector<SlowCaseEntry>::iterator&);
  • trunk/JavaScriptCore/jit/JITOpcodes.cpp

    r68281 r68338  
    14711471}
    14721472
     1473void JIT::emit_op_get_arguments_length(Instruction* currentInstruction)
     1474{
     1475    int dst = currentInstruction[1].u.operand;
     1476    int argumentsRegister = currentInstruction[2].u.operand;
     1477    addSlowCase(branchTestPtr(NonZero, addressFor(argumentsRegister)));
     1478    emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0);
     1479    sub32(Imm32(1), regT0);
     1480    emitFastArithReTagImmediate(regT0, regT0);
     1481    emitPutVirtualRegister(dst, regT0);
     1482}
     1483
     1484void JIT::emitSlow_op_get_arguments_length(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     1485{
     1486    linkSlowCase(iter);
     1487    unsigned dst = currentInstruction[1].u.operand;
     1488    unsigned base = currentInstruction[2].u.operand;
     1489    Identifier* ident = &(m_codeBlock->identifier(currentInstruction[3].u.operand));
     1490   
     1491    emitGetVirtualRegister(base, regT0);
     1492    JITStubCall stubCall(this, cti_op_get_by_id_generic);
     1493    stubCall.addArgument(regT0);
     1494    stubCall.addArgument(ImmPtr(ident));
     1495    stubCall.call(dst);
     1496}
     1497
     1498void JIT::emit_op_get_argument_by_val(Instruction* currentInstruction)
     1499{
     1500    int dst = currentInstruction[1].u.operand;
     1501    int argumentsRegister = currentInstruction[2].u.operand;
     1502    int property = currentInstruction[3].u.operand;
     1503    addSlowCase(branchTestPtr(NonZero, addressFor(argumentsRegister)));
     1504    emitGetVirtualRegister(property, regT1);
     1505    addSlowCase(emitJumpIfNotImmediateInteger(regT1));
     1506    add32(Imm32(1), regT1);
     1507    // regT1 now contains the integer index of the argument we want, including this
     1508    emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT2);
     1509    addSlowCase(branch32(AboveOrEqual, regT1, regT2));
     1510   
     1511    Jump skipOutofLineParams;
     1512    int numArgs = m_codeBlock->m_numParameters;
     1513    if (numArgs) {
     1514        Jump notInInPlaceArgs = branch32(AboveOrEqual, regT1, Imm32(numArgs));
     1515        addPtr(Imm32(static_cast<unsigned>(-(RegisterFile::CallFrameHeaderSize + numArgs) * sizeof(Register))), callFrameRegister, regT0);
     1516        loadPtr(BaseIndex(regT0, regT1, TimesEight, 0), regT0);
     1517        skipOutofLineParams = jump();
     1518        notInInPlaceArgs.link(this);
     1519    }
     1520   
     1521    addPtr(Imm32(static_cast<unsigned>(-(RegisterFile::CallFrameHeaderSize + numArgs) * sizeof(Register))), callFrameRegister, regT0);
     1522    mul32(Imm32(sizeof(Register)), regT2, regT2);
     1523    subPtr(regT2, regT0);
     1524    loadPtr(BaseIndex(regT0, regT1, TimesEight, 0), regT0);
     1525    if (numArgs)
     1526        skipOutofLineParams.link(this);
     1527    emitPutVirtualRegister(dst, regT0);
     1528}
     1529
     1530void JIT::emitSlow_op_get_argument_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     1531{
     1532    unsigned dst = currentInstruction[1].u.operand;
     1533    unsigned arguments = currentInstruction[2].u.operand;
     1534    unsigned property = currentInstruction[3].u.operand;
     1535   
     1536    linkSlowCase(iter);
     1537    Jump skipArgumentsCreation = jump();
     1538   
     1539    linkSlowCase(iter);
     1540    linkSlowCase(iter);
     1541    if (m_codeBlock->m_numParameters == 1)
     1542        JITStubCall(this, cti_op_create_arguments_no_params).call();
     1543    else
     1544        JITStubCall(this, cti_op_create_arguments).call();
     1545    emitPutVirtualRegister(dst);
     1546    emitPutVirtualRegister(unmodifiedArgumentsRegister(dst));
     1547   
     1548    skipArgumentsCreation.link(this);
     1549    JITStubCall stubCall(this, cti_op_get_by_val);
     1550    stubCall.addArgument(arguments, regT2);
     1551    stubCall.addArgument(property, regT2);
     1552    stubCall.call(dst);
     1553}
     1554
    14731555#endif // !USE(JSVALUE32_64)
    14741556
  • trunk/JavaScriptCore/jit/JITOpcodes32_64.cpp

    r68281 r68338  
    15631563}
    15641564
     1565void JIT::emit_op_get_arguments_length(Instruction* currentInstruction)
     1566{
     1567    int dst = currentInstruction[1].u.operand;
     1568    int argumentsRegister = currentInstruction[2].u.operand;
     1569    addSlowCase(branch32(NotEqual, tagFor(argumentsRegister), Imm32(JSValue::EmptyValueTag)));
     1570    emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0);
     1571    sub32(Imm32(1), regT0);
     1572    emitStoreInt32(dst, regT0);
     1573}
     1574
     1575void JIT::emitSlow_op_get_arguments_length(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     1576{
     1577    linkSlowCase(iter);
     1578    int dst = currentInstruction[1].u.operand;
     1579    int base = currentInstruction[2].u.operand;
     1580    int ident = currentInstruction[3].u.operand;
     1581   
     1582    JITStubCall stubCall(this, cti_op_get_by_id_generic);
     1583    stubCall.addArgument(base);
     1584    stubCall.addArgument(ImmPtr(&(m_codeBlock->identifier(ident))));
     1585    stubCall.call(dst);
     1586}
     1587
     1588void JIT::emit_op_get_argument_by_val(Instruction* currentInstruction)
     1589{
     1590    int dst = currentInstruction[1].u.operand;
     1591    int argumentsRegister = currentInstruction[2].u.operand;
     1592    int property = currentInstruction[3].u.operand;
     1593    addSlowCase(branch32(NotEqual, tagFor(argumentsRegister), Imm32(JSValue::EmptyValueTag)));
     1594    emitLoad(property, regT1, regT2);
     1595    addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
     1596    add32(Imm32(1), regT2);
     1597    // regT2 now contains the integer index of the argument we want, including this
     1598    emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT3);
     1599    addSlowCase(branch32(AboveOrEqual, regT2, regT3));
     1600   
     1601    Jump skipOutofLineParams;
     1602    int numArgs = m_codeBlock->m_numParameters;
     1603    if (numArgs) {
     1604        Jump notInInPlaceArgs = branch32(AboveOrEqual, regT2, Imm32(numArgs));
     1605        addPtr(Imm32(static_cast<unsigned>(-(RegisterFile::CallFrameHeaderSize + numArgs) * sizeof(Register))), callFrameRegister, regT1);
     1606        loadPtr(BaseIndex(regT1, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0);
     1607        loadPtr(BaseIndex(regT1, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1);
     1608        skipOutofLineParams = jump();
     1609        notInInPlaceArgs.link(this);
     1610    }
     1611
     1612    addPtr(Imm32(static_cast<unsigned>(-(RegisterFile::CallFrameHeaderSize + numArgs) * sizeof(Register))), callFrameRegister, regT1);
     1613    mul32(Imm32(sizeof(Register)), regT3, regT3);
     1614    subPtr(regT3, regT1);
     1615    loadPtr(BaseIndex(regT1, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0);
     1616    loadPtr(BaseIndex(regT1, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1);
     1617    if (numArgs)
     1618        skipOutofLineParams.link(this);
     1619    emitStore(dst, regT1, regT0);
     1620}
     1621
     1622void JIT::emitSlow_op_get_argument_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     1623{
     1624    unsigned dst = currentInstruction[1].u.operand;
     1625    unsigned arguments = currentInstruction[2].u.operand;
     1626    unsigned property = currentInstruction[3].u.operand;
     1627
     1628    linkSlowCase(iter);
     1629    Jump skipArgumentsCreation = jump();
     1630
     1631    linkSlowCase(iter);
     1632    linkSlowCase(iter);
     1633    if (m_codeBlock->m_numParameters == 1)
     1634        JITStubCall(this, cti_op_create_arguments_no_params).call();
     1635    else
     1636        JITStubCall(this, cti_op_create_arguments).call();
     1637   
     1638    emitStore(arguments, regT1, regT0);
     1639    emitStore(unmodifiedArgumentsRegister(arguments), regT1, regT0);
     1640   
     1641    skipArgumentsCreation.link(this);
     1642    JITStubCall stubCall(this, cti_op_get_by_val);
     1643    stubCall.addArgument(arguments);
     1644    stubCall.addArgument(property);
     1645    stubCall.call(dst);
     1646}
     1647
    15651648} // namespace JSC
    15661649
Note: See TracChangeset for help on using the changeset viewer.