Changeset 91225 in webkit


Ignore:
Timestamp:
Jul 18, 2011 5:26:14 PM (13 years ago)
Author:
barraclough@apple.com
Message:

https://bugs.webkit.org/show_bug.cgi?id=64760
DFG JIT - Should be able to compile program code.

Reviewed by Geoff Garen.

Add support for op_end, hooks to compile program code in Executable.cpp.

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::parseBlock):

  • Add support for op_end
  • dfg/DFGJITCompiler.cpp:

(JSC::DFG::JITCompiler::compileEntry):
(JSC::DFG::JITCompiler::compileBody):
(JSC::DFG::JITCompiler::link):

  • Added, separate out steps of compileFunction.

(JSC::DFG::JITCompiler::compile):

  • Added, compile program code.

(JSC::DFG::JITCompiler::compileFunction):

  • Sections separated out to helper functions.
  • dfg/DFGJITCompiler.h:

(JSC::DFG::JITCompiler::JITCompiler):

  • Added m_exceptionCheckCount.
  • runtime/Executable.cpp:

(JSC::tryDFGCompile):
(JSC::tryDFGCompileFunction):
(JSC::ProgramExecutable::compileInternal):
(JSC::FunctionExecutable::compileForCallInternal):

  • Renamed tryDFGCompile to tryDFGCompileFunction, added tryDFGCompile to compile program code.
Location:
trunk/Source/JavaScriptCore
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r91224 r91225  
     12011-07-18  Gavin Barraclough  <barraclough@apple.com>
     2
     3        https://bugs.webkit.org/show_bug.cgi?id=64760
     4        DFG JIT - Should be able to compile program code.
     5
     6        Reviewed by Geoff Garen.
     7
     8        Add support for op_end, hooks to compile program code in Executable.cpp.
     9
     10        * dfg/DFGByteCodeParser.cpp:
     11        (JSC::DFG::ByteCodeParser::parseBlock):
     12            - Add support for op_end
     13        * dfg/DFGJITCompiler.cpp:
     14        (JSC::DFG::JITCompiler::compileEntry):
     15        (JSC::DFG::JITCompiler::compileBody):
     16        (JSC::DFG::JITCompiler::link):
     17            - Added, separate out steps of compileFunction.
     18        (JSC::DFG::JITCompiler::compile):
     19            - Added, compile program code.
     20        (JSC::DFG::JITCompiler::compileFunction):
     21            - Sections separated out to helper functions.
     22        * dfg/DFGJITCompiler.h:
     23        (JSC::DFG::JITCompiler::JITCompiler):
     24            - Added m_exceptionCheckCount.
     25        * runtime/Executable.cpp:
     26        (JSC::tryDFGCompile):
     27        (JSC::tryDFGCompileFunction):
     28        (JSC::ProgramExecutable::compileInternal):
     29        (JSC::FunctionExecutable::compileForCallInternal):
     30            - Renamed tryDFGCompile to tryDFGCompileFunction, added tryDFGCompile to compile program code.
     31
    1322011-07-18  Gavin Barraclough  <barraclough@apple.com>
    233
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r90877 r91225  
    11131113        }
    11141114
    1115         case op_ret: {
     1115        case op_ret:
    11161116            addToGraph(Return, get(currentInstruction[1].u.operand));
    11171117            LAST_OPCODE(op_ret);
    1118         }
     1118           
     1119        case op_end:
     1120            addToGraph(Return, get(currentInstruction[1].u.operand));
     1121            LAST_OPCODE(op_end);
    11191122           
    11201123        case op_call: {
  • trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp

    r90950 r91225  
    224224}
    225225
    226 void JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck)
    227 {
    228     // === Stage 1 - Function header code generation ===
    229     //
     226void JITCompiler::compileEntry()
     227{
    230228    // This code currently matches the old JIT. In the function header we need to
    231229    // pop the return address (since we do not allow any recursion on the machine
    232230    // stack), and perform a fast register file check.
    233 
    234     // This is the main entry point, without performing an arity check.
    235231    // FIXME: https://bugs.webkit.org/show_bug.cgi?id=56292
    236232    // We'll need to convert the remaining cti_ style calls (specifically the register file
     
    239235    preserveReturnAddressAfterCall(GPRInfo::regT2);
    240236    emitPutToCallFrameHeader(GPRInfo::regT2, RegisterFile::ReturnPC);
    241     // If we needed to perform an arity check we will already have moved the return address,
    242     // so enter after this.
    243     Label fromArityCheck(this);
    244 
    245     // Setup a pointer to the codeblock in the CallFrameHeader.
    246     emitPutImmediateToCallFrameHeader(m_codeBlock, RegisterFile::CodeBlock);
    247 
    248     // Plant a check that sufficient space is available in the RegisterFile.
    249     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=56291
    250     addPtr(Imm32(m_codeBlock->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::regT1);
    251     Jump registerFileCheck = branchPtr(Below, AbsoluteAddress(m_globalData->interpreter->registerFile().addressOfEnd()), GPRInfo::regT1);
    252     // Return here after register file check.
    253     Label fromRegisterFileCheck = label();
    254 
    255 
    256     // === Stage 2 - Function body code generation ===
    257     //
     237}
     238
     239void JITCompiler::compileBody()
     240{
    258241    // We generate the speculative code path, followed by the non-speculative
    259242    // code for the function. Next we need to link the two together, making
     
    305288    }
    306289
    307     // === Stage 3 - Function footer code generation ===
    308     //
    309     // Generate code to lookup and jump to exception handlers, to perform the slow
    310     // register file check (if the fast one in the function header fails), and
    311     // generate the entry point with arity check.
    312 
    313290    // Iterate over the m_calls vector, checking for exception checks,
    314291    // and linking them to here.
    315     unsigned exceptionCheckCount = 0;
    316292    for (unsigned i = 0; i < m_calls.size(); ++i) {
    317293        Jump& exceptionCheck = m_calls[i].m_exceptionCheck;
    318294        if (exceptionCheck.isSet()) {
    319295            exceptionCheck.link(this);
    320             ++exceptionCheckCount;
     296            ++m_exceptionCheckCount;
    321297        }
    322298    }
    323299    // If any exception checks were linked, generate code to lookup a handler.
    324     if (exceptionCheckCount) {
     300    if (m_exceptionCheckCount) {
    325301        // lookupExceptionHandler is passed two arguments, exec (the CallFrame*), and
    326302        // an identifier for the operation that threw the exception, which we can use
     
    335311        jump(GPRInfo::returnValueGPR2);
    336312    }
    337 
     313}
     314
     315void JITCompiler::link(LinkBuffer& linkBuffer)
     316{
     317    // Link the code, populate data in CodeBlock data structures.
     318#if DFG_DEBUG_VERBOSE
     319    fprintf(stderr, "JIT code start at %p\n", linkBuffer.debugAddress());
     320#endif
     321
     322    // Link all calls out from the JIT code to their respective functions.
     323    for (unsigned i = 0; i < m_calls.size(); ++i) {
     324        if (m_calls[i].m_function.value())
     325            linkBuffer.link(m_calls[i].m_call, m_calls[i].m_function);
     326    }
     327
     328    if (m_codeBlock->needsCallReturnIndices()) {
     329        m_codeBlock->callReturnIndexVector().reserveCapacity(m_exceptionCheckCount);
     330        for (unsigned i = 0; i < m_calls.size(); ++i) {
     331            if (m_calls[i].m_handlesExceptions) {
     332                unsigned returnAddressOffset = linkBuffer.returnAddressOffset(m_calls[i].m_call);
     333                unsigned exceptionInfo = m_calls[i].m_exceptionInfo;
     334                m_codeBlock->callReturnIndexVector().append(CallReturnOffsetToBytecodeOffset(returnAddressOffset, exceptionInfo));
     335            }
     336        }
     337    }
     338
     339    m_codeBlock->setNumberOfStructureStubInfos(m_propertyAccesses.size());
     340    for (unsigned i = 0; i < m_propertyAccesses.size(); ++i) {
     341        StructureStubInfo& info = m_codeBlock->structureStubInfo(i);
     342        info.callReturnLocation = linkBuffer.locationOf(m_propertyAccesses[i].m_functionCall);
     343        info.u.unset.deltaCheckImmToCall = m_propertyAccesses[i].m_deltaCheckImmToCall;
     344        info.deltaCallToStructCheck = m_propertyAccesses[i].m_deltaCallToStructCheck;
     345        info.u.unset.deltaCallToLoadOrStore = m_propertyAccesses[i].m_deltaCallToLoadOrStore;
     346        info.deltaCallToSlowCase = m_propertyAccesses[i].m_deltaCallToSlowCase;
     347        info.deltaCallToDone = m_propertyAccesses[i].m_deltaCallToDone;
     348        info.baseGPR = m_propertyAccesses[i].m_baseGPR;
     349        info.valueGPR = m_propertyAccesses[i].m_valueGPR;
     350        info.scratchGPR = m_propertyAccesses[i].m_scratchGPR;
     351    }
     352   
     353    m_codeBlock->setNumberOfCallLinkInfos(m_jsCalls.size());
     354    for (unsigned i = 0; i < m_jsCalls.size(); ++i) {
     355        CallLinkInfo& info = m_codeBlock->callLinkInfo(i);
     356        info.isCall = m_jsCalls[i].m_isCall;
     357        info.callReturnLocation = CodeLocationLabel(linkBuffer.locationOf(m_jsCalls[i].m_slowCall));
     358        info.hotPathBegin = linkBuffer.locationOf(m_jsCalls[i].m_targetToCheck);
     359        info.hotPathOther = linkBuffer.locationOfNearCall(m_jsCalls[i].m_fastCall);
     360    }
     361   
     362    m_codeBlock->addMethodCallLinkInfos(m_methodGets.size());
     363    for (unsigned i = 0; i < m_methodGets.size(); ++i) {
     364        MethodCallLinkInfo& info = m_codeBlock->methodCallLinkInfo(i);
     365        info.cachedStructure.setLocation(linkBuffer.locationOf(m_methodGets[i].m_structToCompare));
     366        info.cachedPrototypeStructure.setLocation(linkBuffer.locationOf(m_methodGets[i].m_protoStructToCompare));
     367        info.cachedFunction.setLocation(linkBuffer.locationOf(m_methodGets[i].m_putFunction));
     368        info.cachedPrototype.setLocation(linkBuffer.locationOf(m_methodGets[i].m_protoObj));
     369        info.callReturnLocation = linkBuffer.locationOf(m_methodGets[i].m_slowCall);
     370    }
     371}
     372
     373void JITCompiler::compile(JITCode& entry)
     374{
     375    // Preserve the return address to the callframe.
     376    compileEntry();
     377    // Generate the body of the program.
     378    compileBody();
     379    // Link
     380    LinkBuffer linkBuffer(*m_globalData, this, m_globalData->executableAllocator);
     381    link(linkBuffer);
     382    entry = JITCode(linkBuffer.finalizeCode(), JITCode::DFGJIT);
     383}
     384
     385void JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck)
     386{
     387    compileEntry();
     388
     389    // === Function header code generation ===
     390    // This is the main entry point, without performing an arity check.
     391    // If we needed to perform an arity check we will already have moved the return address,
     392    // so enter after this.
     393    Label fromArityCheck(this);
     394    // Setup a pointer to the codeblock in the CallFrameHeader.
     395    emitPutImmediateToCallFrameHeader(m_codeBlock, RegisterFile::CodeBlock);
     396    // Plant a check that sufficient space is available in the RegisterFile.
     397    // FIXME: https://bugs.webkit.org/show_bug.cgi?id=56291
     398    addPtr(Imm32(m_codeBlock->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::regT1);
     399    Jump registerFileCheck = branchPtr(Below, AbsoluteAddress(m_globalData->interpreter->registerFile().addressOfEnd()), GPRInfo::regT1);
     400    // Return here after register file check.
     401    Label fromRegisterFileCheck = label();
     402
     403
     404    // === Function body code generation ===
     405    compileBody();
     406
     407    // === Function footer code generation ===
     408    //
     409    // Generate code to perform the slow register file check (if the fast one in
     410    // the function header fails), and generate the entry point with arity check.
     411    //
    338412    // Generate the register file check; if the fast check in the function head fails,
    339413    // we need to call out to a helper function to check whether more space is available.
     
    344418    Call callRegisterFileCheck = call();
    345419    jump(fromRegisterFileCheck);
    346 
     420   
    347421    // The fast entry point into a function does not check the correct number of arguments
    348422    // have been passed to the call (we only use the fast entry point where we can statically
     
    361435
    362436
    363     // === Stage 4 - Link ===
    364     //
    365     // Link the code, populate data in CodeBlock data structures.
    366 
     437    // === Link ===
    367438    LinkBuffer linkBuffer(*m_globalData, this, m_globalData->executableAllocator);
    368 
    369 #if DFG_DEBUG_VERBOSE
    370     fprintf(stderr, "JIT code start at %p\n", linkBuffer.debugAddress());
    371 #endif
    372 
    373     // Link all calls out from the JIT code to their respective functions.
    374     for (unsigned i = 0; i < m_calls.size(); ++i) {
    375         if (m_calls[i].m_function.value())
    376             linkBuffer.link(m_calls[i].m_call, m_calls[i].m_function);
    377     }
    378 
    379     if (m_codeBlock->needsCallReturnIndices()) {
    380         m_codeBlock->callReturnIndexVector().reserveCapacity(exceptionCheckCount);
    381         for (unsigned i = 0; i < m_calls.size(); ++i) {
    382             if (m_calls[i].m_handlesExceptions) {
    383                 unsigned returnAddressOffset = linkBuffer.returnAddressOffset(m_calls[i].m_call);
    384                 unsigned exceptionInfo = m_calls[i].m_exceptionInfo;
    385                 m_codeBlock->callReturnIndexVector().append(CallReturnOffsetToBytecodeOffset(returnAddressOffset, exceptionInfo));
    386             }
    387         }
    388     }
    389 
    390     m_codeBlock->setNumberOfStructureStubInfos(m_propertyAccesses.size());
    391     for (unsigned i = 0; i < m_propertyAccesses.size(); ++i) {
    392         StructureStubInfo& info = m_codeBlock->structureStubInfo(i);
    393         info.callReturnLocation = linkBuffer.locationOf(m_propertyAccesses[i].m_functionCall);
    394         info.u.unset.deltaCheckImmToCall = m_propertyAccesses[i].m_deltaCheckImmToCall;
    395         info.deltaCallToStructCheck = m_propertyAccesses[i].m_deltaCallToStructCheck;
    396         info.u.unset.deltaCallToLoadOrStore = m_propertyAccesses[i].m_deltaCallToLoadOrStore;
    397         info.deltaCallToSlowCase = m_propertyAccesses[i].m_deltaCallToSlowCase;
    398         info.deltaCallToDone = m_propertyAccesses[i].m_deltaCallToDone;
    399         info.baseGPR = m_propertyAccesses[i].m_baseGPR;
    400         info.valueGPR = m_propertyAccesses[i].m_valueGPR;
    401         info.scratchGPR = m_propertyAccesses[i].m_scratchGPR;
    402     }
    403    
    404     m_codeBlock->setNumberOfCallLinkInfos(m_jsCalls.size());
    405     for (unsigned i = 0; i < m_jsCalls.size(); ++i) {
    406         CallLinkInfo& info = m_codeBlock->callLinkInfo(i);
    407         info.isCall = m_jsCalls[i].m_isCall;
    408         info.callReturnLocation = CodeLocationLabel(linkBuffer.locationOf(m_jsCalls[i].m_slowCall));
    409         info.hotPathBegin = linkBuffer.locationOf(m_jsCalls[i].m_targetToCheck);
    410         info.hotPathOther = linkBuffer.locationOfNearCall(m_jsCalls[i].m_fastCall);
    411     }
    412    
    413     m_codeBlock->addMethodCallLinkInfos(m_methodGets.size());
    414     for (unsigned i = 0; i < m_methodGets.size(); ++i) {
    415         MethodCallLinkInfo& info = m_codeBlock->methodCallLinkInfo(i);
    416         info.cachedStructure.setLocation(linkBuffer.locationOf(m_methodGets[i].m_structToCompare));
    417         info.cachedPrototypeStructure.setLocation(linkBuffer.locationOf(m_methodGets[i].m_protoStructToCompare));
    418         info.cachedFunction.setLocation(linkBuffer.locationOf(m_methodGets[i].m_putFunction));
    419         info.cachedPrototype.setLocation(linkBuffer.locationOf(m_methodGets[i].m_protoObj));
    420         info.callReturnLocation = linkBuffer.locationOf(m_methodGets[i].m_slowCall);
    421     }
     439    link(linkBuffer);
    422440   
    423441    // FIXME: switch the register file check & arity check over to DFGOpertaion style calls, not JIT stubs.
  • trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.h

    r90529 r91225  
    111111        , m_graph(dfg)
    112112        , m_codeBlock(codeBlock)
    113     {
    114     }
    115 
     113        , m_exceptionCheckCount(0)
     114    {
     115    }
     116
     117    void compile(JITCode& entry);
    116118    void compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck);
    117119
     
    280282
    281283private:
     284    // Internal implementation to compile.
     285    void compileEntry();
     286    void compileBody();
     287    void link(LinkBuffer&);
     288
    282289    // These methods used in linking the speculative & non-speculative paths together.
    283290    void fillNumericToDouble(NodeIndex, FPRReg, GPRReg temporary);
     
    297304
    298305    // Vector of calls out from JIT code, including exception handler information.
     306    // Count of the number of CallRecords with exception handlers.
    299307    Vector<CallRecord> m_calls;
     308    unsigned m_exceptionCheckCount;
    300309
    301310    struct PropertyAccessRecord {
  • trunk/Source/JavaScriptCore/runtime/Executable.cpp

    r91194 r91225  
    4444
    4545#if ENABLE(JIT)
     46#if ENABLE(DFG_JIT)
     47static bool tryDFGCompile(ExecState* exec, CodeBlock* codeBlock, JITCode& jitCode)
     48{
     49#if ENABLE(DFG_JIT_RESTRICTIONS)
     50    // FIXME: No flow control yet supported, don't bother scanning the bytecode if there are any jump targets.
     51    if (codeBlock->numberOfJumpTargets())
     52        return false;
     53#endif
     54
     55    JSGlobalData* globalData = &exec->globalData();
     56    DFG::Graph dfg(codeBlock->m_numParameters, codeBlock->m_numVars);
     57    if (!parse(dfg, globalData, codeBlock))
     58        return false;
     59
     60    dfg.predictArgumentTypes(exec);
     61
     62    DFG::JITCompiler dataFlowJIT(globalData, dfg, codeBlock);
     63    dataFlowJIT.compile(jitCode);
     64    return true;
     65}
     66
     67static bool tryDFGCompileFunction(ExecState* exec, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck)
     68{
     69#if ENABLE(DFG_JIT_RESTRICTIONS)
     70    // FIXME: No flow control yet supported, don't bother scanning the bytecode if there are any jump targets.
     71    if (codeBlock->numberOfJumpTargets())
     72        return false;
     73#endif
     74
     75    JSGlobalData* globalData = &exec->globalData();
     76    DFG::Graph dfg(codeBlock->m_numParameters, codeBlock->m_numVars);
     77    if (!parse(dfg, globalData, codeBlock))
     78        return false;
     79
     80    dfg.predictArgumentTypes(exec);
     81
     82    DFG::JITCompiler dataFlowJIT(globalData, dfg, codeBlock);
     83    dataFlowJIT.compileFunction(jitCode, jitCodeWithArityCheck);
     84    return true;
     85}
     86#else
     87static bool tryDFGCompile(ExecState*, CodeBlock*, JITCode&) { return false; }
     88static bool tryDFGCompileFunction(ExecState*, CodeBlock*, JITCode&, MacroAssemblerCodePtr&) { return false; }
     89#endif
     90
    4691class ExecutableFinalizer : public WeakHandleOwner {
    4792    virtual void finalize(Handle<Unknown> handle, void*)
     
    227272#if ENABLE(JIT)
    228273    if (exec->globalData().canUseJIT()) {
    229         m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_programCodeBlock.get());
     274        bool dfgCompiled = tryDFGCompile(exec, m_programCodeBlock.get(), m_jitCodeForCall);
     275        if (!dfgCompiled)
     276            m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_programCodeBlock.get());
    230277#if !ENABLE(OPCODE_SAMPLING)
    231278        if (!BytecodeGenerator::dumpsGeneratedCode())
     
    258305#endif
    259306}
    260 
    261 #if ENABLE(JIT)
    262 static bool tryDFGCompile(ExecState* exec, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck)
    263 {
    264     JSGlobalData* globalData = &exec->globalData();
    265 #if ENABLE(DFG_JIT)
    266 #if ENABLE(DFG_JIT_RESTRICTIONS)
    267     // FIXME: No flow control yet supported, don't bother scanning the bytecode if there are any jump targets.
    268     if (codeBlock->numberOfJumpTargets())
    269         return false;
    270 #endif
    271 
    272     DFG::Graph dfg(codeBlock->m_numParameters, codeBlock->m_numVars);
    273     if (!parse(dfg, globalData, codeBlock))
    274         return false;
    275 
    276     dfg.predictArgumentTypes(exec);
    277 
    278     DFG::JITCompiler dataFlowJIT(globalData, dfg, codeBlock);
    279     dataFlowJIT.compileFunction(jitCode, jitCodeWithArityCheck);
    280     return true;
    281 #else
    282     UNUSED_PARAM(globalData);
    283     UNUSED_PARAM(codeBlock);
    284     UNUSED_PARAM(jitCode);
    285     UNUSED_PARAM(jitCodeWithArityCheck);
    286     return false;
    287 #endif
    288 }
    289 #endif
    290307
    291308void ProgramExecutable::visitChildren(SlotVisitor& visitor)
     
    333350#if ENABLE(JIT)
    334351    if (exec->globalData().canUseJIT()) {
    335         bool dfgCompiled = tryDFGCompile(exec, m_codeBlockForCall.get(), m_jitCodeForCall, m_jitCodeForCallWithArityCheck);
     352        bool dfgCompiled = tryDFGCompileFunction(exec, m_codeBlockForCall.get(), m_jitCodeForCall, m_jitCodeForCallWithArityCheck);
    336353        if (!dfgCompiled)
    337354            m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_codeBlockForCall.get(), &m_jitCodeForCallWithArityCheck);
Note: See TracChangeset for help on using the changeset viewer.