Changeset 37991 in webkit for trunk/JavaScriptCore


Ignore:
Timestamp:
Oct 29, 2008, 9:33:21 PM (17 years ago)
Author:
[email protected]
Message:

Initial work to reduce cost of JSNumberCell allocation

Reviewed by Geoffrey Garen

This does the initial work needed to bring more of number
allocation into CTI code directly, rather than just falling
back onto the slow paths if we can't guarantee that a number
cell can be reused.

Initial implementation only used by op_negate to make sure
it all works. In a negate heavy (though not dominated) test
it results in a 10% win in the non-reusable cell case.

Location:
trunk/JavaScriptCore
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r37990 r37991  
     12008-10-29  Oliver Hunt  <[email protected]>
     2
     3        Reviewed by Geoff Garen.
     4
     5        Initial work to reduce cost of JSNumberCell allocation
     6
     7        This does the initial work needed to bring more of number
     8        allocation into CTI code directly, rather than just falling
     9        back onto the slow paths if we can't guarantee that a number
     10        cell can be reused.
     11
     12        Initial implementation only used by op_negate to make sure
     13        it all works.  In a negate heavy (though not dominated) test
     14        it results in a 10% win in the non-reusable cell case.
     15
     16        * VM/CTI.cpp:
     17        (JSC::):
     18        (JSC::CTI::emitAllocateNumber):
     19        (JSC::CTI::emitNakedFastCall):
     20        (JSC::CTI::emitArithIntToImmWithJump):
     21        (JSC::CTI::privateCompileMainPass):
     22        (JSC::CTI::privateCompileSlowCases):
     23        * VM/CTI.h:
     24        * VM/CodeBlock.cpp:
     25        (JSC::CodeBlock::dump):
     26        * VM/CodeGenerator.cpp:
     27        (JSC::CodeGenerator::emitUnaryOp):
     28        * VM/CodeGenerator.h:
     29        (JSC::CodeGenerator::emitToJSNumber):
     30        (JSC::CodeGenerator::emitTypeOf):
     31        (JSC::CodeGenerator::emitGetPropertyNames):
     32        * VM/Machine.cpp:
     33        (JSC::Machine::privateExecute):
     34        * VM/Machine.h:
     35        * kjs/ResultType.h:
     36        (JSC::ResultType::isReusableNumber):
     37        (JSC::ResultType::toInt):
     38        * kjs/nodes.cpp:
     39        (JSC::UnaryOpNode::emitCode):
     40        (JSC::BinaryOpNode::emitCode):
     41        (JSC::EqualNode::emitCode):
     42        * masm/X86Assembler.h:
     43        (JSC::X86Assembler::):
     44        (JSC::X86Assembler::negl_r):
     45        (JSC::X86Assembler::xorpd_mr):
     46        * runtime/JSNumberCell.h:
     47        (JSC::JSNumberCell::JSNumberCell):
     48
    1492008-10-29  Steve Falkenburg  <[email protected]>
    250
  • trunk/JavaScriptCore/VM/CTI.cpp

    r37930 r37991  
    312312#endif
    313313
     314extern "C" {
     315    static JSValue* FASTCALL allocateNumber(JSGlobalData* globalData) {
     316        JSValue* result = new (globalData) JSNumberCell(globalData);
     317        ASSERT(result);
     318        return result;
     319    }
     320}
     321
     322ALWAYS_INLINE void CTI::emitAllocateNumber(JSGlobalData* globalData, unsigned opcodeIndex)
     323{
     324    m_jit.movl_i32r(reinterpret_cast<intptr_t>(globalData), X86::ecx);
     325    emitNakedFastCall(opcodeIndex, (void*)allocateNumber);
     326}
     327
    314328ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitNakedCall(unsigned opcodeIndex, X86::RegisterID r)
    315329{
     
    321335
    322336ALWAYS_INLINE  X86Assembler::JmpSrc CTI::emitNakedCall(unsigned opcodeIndex, void(*function)())
     337{
     338    X86Assembler::JmpSrc call = m_jit.emitCall();
     339    m_calls.append(CallRecord(call, reinterpret_cast<CTIHelper_v>(function), opcodeIndex));
     340    return call;
     341}
     342
     343ALWAYS_INLINE  X86Assembler::JmpSrc CTI::emitNakedFastCall(unsigned opcodeIndex, void* function)
    323344{
    324345    X86Assembler::JmpSrc call = m_jit.emitCall();
     
    515536    m_jit.addl_rr(reg, reg);
    516537    emitFastArithReTagImmediate(reg);
     538}
     539
     540ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitArithIntToImmWithJump(X86Assembler::RegisterID reg)
     541{
     542    m_jit.addl_rr(reg, reg);
     543    X86Assembler::JmpSrc jmp = m_jit.emitUnlinkedJo();
     544    emitFastArithReTagImmediate(reg);
     545    return jmp;
    517546}
    518547
     
    14811510        }
    14821511        case op_negate: {
    1483             emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
    1484             emitCTICall(instruction + i, i, Machine::cti_op_negate);
    1485             emitPutResult(instruction[i + 1].u.operand);
    1486             i += 3;
     1512            emitGetArg(instruction[i + 2].u.operand, X86::eax);
     1513            m_jit.testl_i32r(JSImmediate::TagBitTypeInteger, X86::eax);
     1514            X86Assembler::JmpSrc notImmediate = m_jit.emitUnlinkedJe();
     1515
     1516            m_jit.cmpl_i32r(JSImmediate::TagBitTypeInteger, X86::eax);
     1517            X86Assembler::JmpSrc zeroImmediate = m_jit.emitUnlinkedJe();
     1518            emitFastArithImmToInt(X86::eax);
     1519            m_jit.negl_r(X86::eax); // This can't overflow as we only have a 31bit int at this point
     1520            X86Assembler::JmpSrc overflow = emitArithIntToImmWithJump(X86::eax);
     1521            emitPutResult(instruction[i + 1].u.operand);
     1522            X86Assembler::JmpSrc immediateNegateSuccess = m_jit.emitUnlinkedJmp();
     1523
     1524            if (!isSSE2Present()) {
     1525                m_jit.link(zeroImmediate, m_jit.label());
     1526                m_jit.link(overflow, m_jit.label());
     1527                m_jit.link(notImmediate, m_jit.label());
     1528                emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
     1529                emitCTICall(instruction + i, i, Machine::cti_op_negate);
     1530                emitPutResult(instruction[i + 1].u.operand);
     1531            } else {
     1532                // Slow case immediates
     1533                m_slowCases.append(SlowCaseEntry(zeroImmediate, i));
     1534                m_slowCases.append(SlowCaseEntry(overflow, i));
     1535                m_jit.link(notImmediate, m_jit.label());
     1536                ResultType resultType(instruction[i + 3].u.resultType);
     1537                if (!resultType.definitelyIsNumber()) {
     1538                    emitJumpSlowCaseIfNotJSCell(X86::eax, i);
     1539                    StructureID* numberStructureID = m_callFrame->globalData().numberStructureID.get();
     1540                    m_jit.cmpl_i32m(reinterpret_cast<unsigned>(numberStructureID), OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
     1541                    m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
     1542                }
     1543                m_jit.movsd_mr(OBJECT_OFFSET(JSNumberCell, m_value), X86::eax, X86::xmm0);
     1544                // We need 3 copies of the sign bit mask so we can assure alignment and pad for the 128bit load
     1545                static double doubleSignBit[] = { -0.0, -0.0, -0.0 };
     1546                m_jit.xorpd_mr((void*)((((uintptr_t)doubleSignBit)+15)&~15), X86::xmm0);
     1547                X86Assembler::JmpSrc wasCell;
     1548                if (!resultType.isReusableNumber())
     1549                    emitAllocateNumber(&m_callFrame->globalData(), i);
     1550
     1551                putDoubleResultToJSNumberCellOrJSImmediate(X86::xmm0, X86::eax, instruction[i + 1].u.operand, &wasCell,
     1552                                                           X86::xmm1, X86::ecx, X86::edx);
     1553                m_jit.link(wasCell, m_jit.label());
     1554            }
     1555            m_jit.link(immediateNegateSuccess, m_jit.label());
     1556            i += 4;
    14871557            break;
    14881558        }
     
    23182388            break;
    23192389        }
     2390        case op_negate: {
     2391            m_jit.link(iter->from, m_jit.label());
     2392            emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
     2393            emitCTICall(instruction + i, i, Machine::cti_op_negate);
     2394            emitPutResult(instruction[i + 1].u.operand);
     2395            i += 4;
     2396            break;
     2397        }
    23202398        case op_rshift: {
    23212399            m_jit.link(iter->from, m_jit.label());
  • trunk/JavaScriptCore/VM/CTI.h

    r37891 r37991  
    8484#define CTI_RETURN_ADDRESS_SLOT (ARGS[-1])
    8585
     86#if COMPILER(MSVC)
     87#define FASTCALL __fastcall
     88#elif COMPILER(GCC)
     89#define FASTCALL  __attribute__ ((fastcall))
     90#else
     91#error Need to support fastcall calling convention in this compiler
     92#endif
     93
    8694namespace JSC {
    8795
     
    406414        void emitFastArithIntToImmOrSlowCase(X86Assembler::RegisterID, unsigned opcodeIndex);
    407415        void emitFastArithIntToImmNoCheck(X86Assembler::RegisterID);
     416        X86Assembler::JmpSrc emitArithIntToImmWithJump(X86Assembler::RegisterID reg);
    408417
    409418        void emitTagAsBoolImmediate(X86Assembler::RegisterID reg);
     419
     420        void emitAllocateNumber(JSGlobalData*, unsigned);
    410421
    411422        X86Assembler::JmpSrc emitNakedCall(unsigned opcodeIndex, X86::RegisterID);
    412423        X86Assembler::JmpSrc emitNakedCall(unsigned opcodeIndex, void(*function)());
     424        X86Assembler::JmpSrc emitNakedFastCall(unsigned opcodeIndex, void*);
    413425        X86Assembler::JmpSrc emitCTICall(Instruction*, unsigned opcodeIndex, CTIHelper_j);
    414426        X86Assembler::JmpSrc emitCTICall(Instruction*, unsigned opcodeIndex, CTIHelper_o);
  • trunk/JavaScriptCore/VM/CodeBlock.cpp

    r37951 r37991  
    469469        case op_negate: {
    470470            printUnaryOp(location, it, "negate");
     471            ++it;
    471472            break;
    472473        }
  • trunk/JavaScriptCore/VM/CodeGenerator.cpp

    r37845 r37991  
    710710}
    711711
    712 RegisterID* CodeGenerator::emitUnaryOp(OpcodeID opcode, RegisterID* dst, RegisterID* src)
     712RegisterID* CodeGenerator::emitUnaryOp(OpcodeID opcode, RegisterID* dst, RegisterID* src, ResultType type)
    713713{
    714714    emitOpcode(opcode);
    715715    instructions().append(dst->index());
    716716    instructions().append(src->index());
     717    if (opcode == op_negate)
     718        instructions().append(type.toInt());
    717719    return dst;
    718720}
  • trunk/JavaScriptCore/VM/CodeGenerator.h

    r37845 r37991  
    234234        RegisterID* emitUnexpectedLoad(RegisterID* dst, double);
    235235
    236         RegisterID* emitUnaryOp(OpcodeID, RegisterID* dst, RegisterID* src);
     236        RegisterID* emitUnaryOp(OpcodeID, RegisterID* dst, RegisterID* src, ResultType);
    237237        RegisterID* emitBinaryOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes);
    238238        RegisterID* emitEqualityOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2);
     
    248248        RegisterID* emitMove(RegisterID* dst, RegisterID* src);
    249249
    250         RegisterID* emitToJSNumber(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_to_jsnumber, dst, src); }
     250        RegisterID* emitToJSNumber(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_to_jsnumber, dst, src, ResultType::unknown()); }
    251251        RegisterID* emitPreInc(RegisterID* srcDst);
    252252        RegisterID* emitPreDec(RegisterID* srcDst);
     
    255255
    256256        RegisterID* emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* base, RegisterID* basePrototype);
    257         RegisterID* emitTypeOf(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_typeof, dst, src); }
     257        RegisterID* emitTypeOf(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_typeof, dst, src, ResultType::unknown()); }
    258258        RegisterID* emitIn(RegisterID* dst, RegisterID* property, RegisterID* base) { return emitBinaryOp(op_in, dst, property, base, OperandTypes()); }
    259259
     
    293293        void emitSubroutineReturn(RegisterID* retAddrSrc);
    294294
    295         RegisterID* emitGetPropertyNames(RegisterID* dst, RegisterID* base) { return emitUnaryOp(op_get_pnames, dst, base); }
     295        RegisterID* emitGetPropertyNames(RegisterID* dst, RegisterID* base) { return emitUnaryOp(op_get_pnames, dst, base, ResultType::unknown()); }
    296296        RegisterID* emitNextPropertyName(RegisterID* dst, RegisterID* iter, LabelID* target);
    297297
  • trunk/JavaScriptCore/VM/Instruction.h

    r36972 r37991  
    3131
    3232#include "Opcode.h"
     33#include "ResultType.h"
    3334#include <wtf/VectorTraits.h>
    3435
     
    5960            StructureIDChain* structureIDChain;
    6061            JSCell* jsCell;
     62            ResultType::Type resultType;
    6163        } u;
    6264    };
  • trunk/JavaScriptCore/VM/Machine.cpp

    r37894 r37991  
    18451845        int dst = (++vPC)->u.operand;
    18461846        JSValue* src = callFrame[(++vPC)->u.operand].jsValue(callFrame);
     1847        ++vPC;
    18471848        double v;
    18481849        if (fastIsNumber(src, v))
  • trunk/JavaScriptCore/VM/Machine.h

    r37891 r37991  
    260260        static void SFX_CALL cti_op_debug(CTI_ARGS);
    261261
     262        static JSValue* SFX_CALL cti_allocate_number(CTI_ARGS);
     263
    262264        static JSValue* SFX_CALL cti_vm_throw(CTI_ARGS);
    263265        static void* SFX_CALL cti_vm_compile(CTI_ARGS);
  • trunk/JavaScriptCore/kjs/ResultType.h

    r36976 r37991  
    5454        }
    5555       
     56        bool isReusableNumber()
     57        {
     58            return isReusable() && definitelyIsNumber();
     59        }
     60
    5661        bool definitelyIsNumber()
    5762        {
     
    6974        }
    7075       
     76        int toInt()
     77        {
     78            return static_cast<int>(m_type);
     79        }
     80
    7181        static ResultType nullType()
    7282        {
  • trunk/JavaScriptCore/kjs/nodes.cpp

    r37972 r37991  
    716716{
    717717    RegisterID* src = generator.emitNode(m_expr.get());
    718     return generator.emitUnaryOp(opcode(), generator.finalDestination(dst), src);
     718    return generator.emitUnaryOp(opcode(), generator.finalDestination(dst), src, m_expr->resultDescriptor());
    719719}
    720720
     
    727727        if (m_expr1->isNull() || m_expr2->isNull()) {
    728728            RefPtr<RegisterID> src = generator.emitNode(dst, m_expr1->isNull() ? m_expr2.get() : m_expr1.get());
    729             return generator.emitUnaryOp(op_neq_null, generator.finalDestination(dst, src.get()), src.get());
     729            return generator.emitUnaryOp(op_neq_null, generator.finalDestination(dst, src.get()), src.get(), ResultType::unknown());
    730730        }
    731731    }
     
    740740    if (m_expr1->isNull() || m_expr2->isNull()) {
    741741        RefPtr<RegisterID> src = generator.emitNode(dst, m_expr1->isNull() ? m_expr2.get() : m_expr1.get());
    742         return generator.emitUnaryOp(op_eq_null, generator.finalDestination(dst, src.get()), src.get());
     742        return generator.emitUnaryOp(op_eq_null, generator.finalDestination(dst, src.get()), src.get(), ResultType::unknown());
    743743    }
    744744
  • trunk/JavaScriptCore/masm/X86Assembler.h

    r37804 r37991  
    229229        OP2_CVTTSD2SI_GdWsd = 0x2C,
    230230        OP2_UCOMISD_VsdWsd  = 0x2E,
     231        OP2_XORPD_VsdWsd    = 0x57,
    231232        OP2_ADDSD_VsdWsd    = 0x58,
    232233        OP2_MULSD_VsdWsd    = 0x59,
     
    264265
    265266        GROUP3_OP_TEST = 0,
     267        GROUP3_OP_NEG  = 3,
    266268        GROUP3_OP_IDIV = 7,
    267269
     
    606608    }
    607609
     610    void negl_r(RegisterID dst)
     611    {
     612        m_buffer->putByte(OP_GROUP3_Ev);
     613        emitModRm_opr(GROUP3_OP_NEG, dst);
     614    }
     615
    608616    void cdq()
    609617    {
     
    740748        m_buffer->putByte(OP2_MOVSD_VsdWsd);
    741749        emitModRm_rm((RegisterID)dst, base, offset);
     750    }
     751
     752    void xorpd_mr(void* addr, XMMRegisterID dst)
     753    {
     754        m_buffer->putByte(PRE_SSE_66);
     755        m_buffer->putByte(OP_2BYTE_ESCAPE);
     756        m_buffer->putByte(OP2_XORPD_VsdWsd);
     757        emitModRm_rm((RegisterID)dst, addr);
    742758    }
    743759
  • trunk/JavaScriptCore/runtime/JSNumberCell.h

    r37938 r37991  
    8585        static PassRefPtr<StructureID> createStructureID(JSValue* proto) { return StructureID::create(proto, TypeInfo(NumberType, NeedsThisConversion)); }
    8686
     87        JSNumberCell(JSGlobalData* globalData)
     88        : JSCell(globalData->numberStructureID.get())
     89        {
     90        }
     91
    8792    private:
    8893        JSNumberCell(JSGlobalData* globalData, double value)
Note: See TracChangeset for help on using the changeset viewer.