⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 185772 in webkit


Ignore:
Timestamp:
Jun 19, 2015, 3:28:18 PM (11 years ago)
Author:
msaboff@apple.com
Message:

Crash in com.apple.WebKit.WebContent at com.apple.JavaScriptCore: JSC::FTL::fixFunctionBasedOnStackMaps + 17225
https://bugs.webkit.org/show_bug.cgi?id=146133

Reviewed by Geoffrey Garen.

When generating code to put in inline caching areas, if there isn't enough space,
then create and link to an out of line area. We connect the inline code to this
out of line code area by planting a jump from the inline area to the out of line
code and appending a jump at the end of the out of line code bck to the instruction
following the inline area. We fill the unused inline area with nops, primarily to
ensure the disassembler doesn't get confused.

  • ftl/FTLCompile.cpp:

(generateInlineIfPossibleOutOfLineIfNot): New function that determines if there is enough space
in the inline code area for the code to link. If so, it links inline, otherwise it links the
code out of line and plants appropriate jumps to/from the out of line code.
(generateICFastPath):
(generateCheckInICFastPath):
(fixFunctionBasedOnStackMaps):
Use generateInlineIfPossibleOutOfLineIfNot() to link code intended for inline cache space.

  • ftl/FTLJITFinalizer.cpp:

(JSC::FTL::JITFinalizer::finalizeFunction):

  • ftl/FTLJITFinalizer.h:

(JSC::FTL::OutOfLineCodeInfo::OutOfLineCodeInfo):
Added code to finalize any out of line LinkBuffer created by generateInlineIfPossibleOutOfLineIfNot().

Location:
trunk/Source/JavaScriptCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r185770 r185772  
     12015-06-19  Michael Saboff  <msaboff@apple.com>
     2
     3        Crash in com.apple.WebKit.WebContent at com.apple.JavaScriptCore: JSC::FTL::fixFunctionBasedOnStackMaps + 17225
     4        https://bugs.webkit.org/show_bug.cgi?id=146133
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        When generating code to put in inline caching areas, if there isn't enough space,
     9        then create and link to an out of line area.  We connect the inline code to this
     10        out of line code area by planting a jump from the inline area to the out of line
     11        code and appending a jump at the end of the out of line code bck to the instruction
     12        following the inline area.  We fill the unused inline area with nops, primarily to
     13        ensure the disassembler doesn't get confused.
     14
     15        * ftl/FTLCompile.cpp:
     16        (generateInlineIfPossibleOutOfLineIfNot): New function that determines if there is enough space
     17        in the inline code area for the code to link.  If so, it links inline, otherwise it links the
     18        code out of line and plants appropriate jumps to/from the out of line code.
     19        (generateICFastPath):
     20        (generateCheckInICFastPath):
     21        (fixFunctionBasedOnStackMaps):
     22        Use generateInlineIfPossibleOutOfLineIfNot() to link code intended for inline cache space.
     23
     24        * ftl/FTLJITFinalizer.cpp:
     25        (JSC::FTL::JITFinalizer::finalizeFunction):
     26        * ftl/FTLJITFinalizer.h:
     27        (JSC::FTL::OutOfLineCodeInfo::OutOfLineCodeInfo):
     28        Added code to finalize any out of line LinkBuffer created by generateInlineIfPossibleOutOfLineIfNot().
     29
    1302015-06-19  Geoffrey Garen  <ggaren@apple.com>
    231
  • trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp

    r184828 r185772  
    156156}
    157157
     158static void generateInlineIfPossibleOutOfLineIfNot(State& state, VM& vm, CodeBlock* codeBlock, CCallHelpers& code, char* startOfInlineCode, size_t sizeOfInlineCode, const char* codeDescription, const std::function<void(LinkBuffer&, CCallHelpers&, bool wasCompiledInline)>& callback)
     159{
     160    std::unique_ptr<LinkBuffer> codeLinkBuffer;
     161    size_t actualCodeSize = code.m_assembler.buffer().codeSize();
     162
     163    if (actualCodeSize <= sizeOfInlineCode) {
     164        LinkBuffer codeLinkBuffer(vm, code, startOfInlineCode, sizeOfInlineCode);
     165
     166        // Fill the remainder of the inline space with nops to avoid confusing the disassembler.
     167        MacroAssembler::AssemblerType_T::fillNops(bitwise_cast<char*>(startOfInlineCode) + actualCodeSize, sizeOfInlineCode - actualCodeSize);
     168
     169        callback(codeLinkBuffer, code, true);
     170
     171        return;
     172    }
     173
     174    // If there isn't enough space in the provided inline code area, allocate out of line
     175    // executable memory to link the provided code. Place a jump at the beginning of the
     176    // inline area and jump to the out of line code. Similarly return by appending a jump
     177    // to the provided code that goes to the instruction after the inline code.
     178    // Fill the middle with nop's.
     179    MacroAssembler::Jump returnToMainline = code.jump();
     180
     181    // Allocate out of line executable memory and link the provided code there.
     182    codeLinkBuffer = std::make_unique<LinkBuffer>(vm, code, codeBlock, JITCompilationMustSucceed);
     183
     184    // Plant a jmp in the inline buffer to the out of line code.
     185    MacroAssembler callToOutOfLineCode;
     186    MacroAssembler::Jump jumpToOutOfLine = callToOutOfLineCode.jump();
     187    LinkBuffer inlineBuffer(vm, callToOutOfLineCode, startOfInlineCode, sizeOfInlineCode);
     188    inlineBuffer.link(jumpToOutOfLine, codeLinkBuffer->entrypoint());
     189
     190    // Fill the remainder of the inline space with nops to avoid confusing the disassembler.
     191    MacroAssembler::AssemblerType_T::fillNops(bitwise_cast<char*>(startOfInlineCode) + inlineBuffer.size(), sizeOfInlineCode - inlineBuffer.size());
     192
     193    // Link the end of the out of line code to right after the inline area.
     194    codeLinkBuffer->link(returnToMainline, CodeLocationLabel(MacroAssemblerCodePtr::createFromExecutableAddress(startOfInlineCode)).labelAtOffset(sizeOfInlineCode));
     195
     196    callback(*codeLinkBuffer.get(), code, false);
     197
     198    state.finalizer->outOfLineCodeInfos.append(OutOfLineCodeInfo(WTF::move(codeLinkBuffer), codeDescription));
     199}
     200
    158201template<typename DescriptorType>
    159202void generateICFastPath(
     
    182225        char* startOfIC =
    183226            bitwise_cast<char*>(generatedFunction) + record.instructionOffset;
    184        
    185         LinkBuffer linkBuffer(vm, fastPathJIT, startOfIC, sizeOfIC);
    186         // Note: we could handle the !isValid() case. We just don't appear to have a
    187         // reason to do so, yet.
    188         RELEASE_ASSERT(linkBuffer.isValid());
    189        
    190         MacroAssembler::AssemblerType_T::fillNops(
    191             startOfIC + linkBuffer.size(), sizeOfIC - linkBuffer.size());
    192        
    193         state.finalizer->sideCodeLinkBuffer->link(
    194             ic.m_slowPathDone[i], CodeLocationLabel(startOfIC + sizeOfIC));
    195        
    196         linkBuffer.link(
    197             generator.slowPathJump(),
    198             state.finalizer->sideCodeLinkBuffer->locationOf(generator.slowPathBegin()));
    199        
    200         generator.finalize(linkBuffer, *state.finalizer->sideCodeLinkBuffer);
     227
     228        generateInlineIfPossibleOutOfLineIfNot(state, vm, codeBlock, fastPathJIT, startOfIC, sizeOfIC, "inline cache fast path", [&] (LinkBuffer& linkBuffer, CCallHelpers&, bool) {
     229            state.finalizer->sideCodeLinkBuffer->link(ic.m_slowPathDone[i],
     230                CodeLocationLabel(startOfIC + sizeOfIC));
     231
     232            linkBuffer.link(generator.slowPathJump(),
     233                state.finalizer->sideCodeLinkBuffer->locationOf(generator.slowPathBegin()));
     234
     235            generator.finalize(linkBuffer, *state.finalizer->sideCodeLinkBuffer);
     236        });
    201237    }
    202238}
     
    233269        char* startOfIC =
    234270            bitwise_cast<char*>(generatedFunction) + record.instructionOffset;
    235        
    236         LinkBuffer fastPath(vm, fastPathJIT, startOfIC, sizeOfIC);
    237         LinkBuffer& slowPath = *state.finalizer->sideCodeLinkBuffer;
    238         // Note: we could handle the !isValid() case. We just don't appear to have a
    239         // reason to do so, yet.
    240         RELEASE_ASSERT(fastPath.isValid());
    241 
    242         MacroAssembler::AssemblerType_T::fillNops(
    243             startOfIC + fastPath.size(), sizeOfIC - fastPath.size());
    244        
    245         state.finalizer->sideCodeLinkBuffer->link(
    246             ic.m_slowPathDone[i], CodeLocationLabel(startOfIC + sizeOfIC));
    247        
    248         CodeLocationLabel slowPathBeginLoc = slowPath.locationOf(slowPathBegin);
    249         fastPath.link(jump, slowPathBeginLoc);
    250 
    251         CodeLocationCall callReturnLocation = slowPath.locationOf(call);
    252 
    253         stubInfo.patch.deltaCallToDone = MacroAssembler::differenceBetweenCodePtr(
    254             callReturnLocation, fastPath.locationOf(done));
    255 
    256         stubInfo.patch.deltaCallToJump = MacroAssembler::differenceBetweenCodePtr(
    257             callReturnLocation, fastPath.locationOf(jump));
    258         stubInfo.callReturnLocation = callReturnLocation;
    259         stubInfo.patch.deltaCallToSlowCase = MacroAssembler::differenceBetweenCodePtr(
    260             callReturnLocation, slowPathBeginLoc);
    261        
     271
     272        auto postLink = [&] (LinkBuffer& fastPath, CCallHelpers&, bool) {
     273            LinkBuffer& slowPath = *state.finalizer->sideCodeLinkBuffer;
     274
     275            state.finalizer->sideCodeLinkBuffer->link(
     276                ic.m_slowPathDone[i], CodeLocationLabel(startOfIC + sizeOfIC));
     277
     278            CodeLocationLabel slowPathBeginLoc = slowPath.locationOf(slowPathBegin);
     279            fastPath.link(jump, slowPathBeginLoc);
     280
     281            CodeLocationCall callReturnLocation = slowPath.locationOf(call);
     282
     283            stubInfo.patch.deltaCallToDone = MacroAssembler::differenceBetweenCodePtr(
     284                callReturnLocation, fastPath.locationOf(done));
     285
     286            stubInfo.patch.deltaCallToJump = MacroAssembler::differenceBetweenCodePtr(
     287                callReturnLocation, fastPath.locationOf(jump));
     288            stubInfo.callReturnLocation = callReturnLocation;
     289            stubInfo.patch.deltaCallToSlowCase = MacroAssembler::differenceBetweenCodePtr(
     290                callReturnLocation, slowPathBeginLoc);
     291        };
     292
     293        generateInlineIfPossibleOutOfLineIfNot(state, vm, codeBlock, fastPathJIT, startOfIC, sizeOfIC, "CheckIn inline cache", postLink);
    262294    }
    263295}
     
    560592        CCallHelpers fastPathJIT(&vm, codeBlock);
    561593        call.emit(fastPathJIT);
    562        
     594
    563595        char* startOfIC = bitwise_cast<char*>(generatedFunction) + call.m_instructionOffset;
    564        
    565         LinkBuffer linkBuffer(vm, fastPathJIT, startOfIC, sizeOfCall());
    566         if (!linkBuffer.isValid()) {
    567             dataLog("Failed to insert inline cache for call because we thought the size would be ", sizeOfCall(), " but it ended up being ", fastPathJIT.m_assembler.codeSize(), " prior to compaction.\n");
    568             RELEASE_ASSERT_NOT_REACHED();
    569         }
    570        
    571         MacroAssembler::AssemblerType_T::fillNops(
    572             startOfIC + linkBuffer.size(), sizeOfCall() - linkBuffer.size());
    573        
    574         call.link(vm, linkBuffer);
     596
     597        generateInlineIfPossibleOutOfLineIfNot(state, vm, codeBlock, fastPathJIT, startOfIC, sizeOfCall(), "JSCall inline cache", [&] (LinkBuffer& linkBuffer, CCallHelpers&, bool) {
     598            call.link(vm, linkBuffer);
     599        });
    575600    }
    576601   
     
    582607        CCallHelpers fastPathJIT(&vm, codeBlock);
    583608        call.emit(fastPathJIT, varargsSpillSlotsOffset);
    584        
     609
    585610        char* startOfIC = bitwise_cast<char*>(generatedFunction) + call.m_instructionOffset;
    586611        size_t sizeOfIC = sizeOfICFor(call.node());
    587612
    588         LinkBuffer linkBuffer(vm, fastPathJIT, startOfIC, sizeOfIC);
    589         if (!linkBuffer.isValid()) {
    590             dataLog("Failed to insert inline cache for varargs call (specifically, ", Graph::opName(call.node()->op()), ") because we thought the size would be ", sizeOfIC, " but it ended up being ", fastPathJIT.m_assembler.codeSize(), " prior to compaction.\n");
    591             RELEASE_ASSERT_NOT_REACHED();
    592         }
    593        
    594         MacroAssembler::AssemblerType_T::fillNops(
    595             startOfIC + linkBuffer.size(), sizeOfIC - linkBuffer.size());
    596        
    597         call.link(vm, linkBuffer, state.finalizer->handleExceptionsLinkBuffer->entrypoint());
     613        generateInlineIfPossibleOutOfLineIfNot(state, vm, codeBlock, fastPathJIT, startOfIC, sizeOfIC, "varargs call inline cache", [&] (LinkBuffer& linkBuffer, CCallHelpers&, bool) {
     614            call.link(vm, linkBuffer, state.finalizer->handleExceptionsLinkBuffer->entrypoint());
     615        });
    598616    }
    599617   
  • trunk/Source/JavaScriptCore/ftl/FTLJITFinalizer.cpp

    r171076 r185772  
    128128            .executableMemory());
    129129    }
    130    
     130
     131    for (unsigned i = 0; i < outOfLineCodeInfos.size(); ++i) {
     132        jitCode->addHandle(FINALIZE_DFG_CODE(
     133            *outOfLineCodeInfos[i].m_linkBuffer,
     134            ("FTL out of line code for %s", outOfLineCodeInfos[i].m_codeDescription)).executableMemory());
     135    }
     136
    131137    jitCode->initializeArityCheckEntrypoint(
    132138        FINALIZE_DFG_CODE(
  • trunk/Source/JavaScriptCore/ftl/FTLJITFinalizer.h

    r177222 r185772  
    4040namespace JSC { namespace FTL {
    4141
     42class OutOfLineCodeInfo {
     43public:
     44    OutOfLineCodeInfo(std::unique_ptr<LinkBuffer> linkBuffer, const char* codeDescription)
     45        : m_linkBuffer(WTF::move(linkBuffer))
     46        , m_codeDescription(codeDescription)
     47    {
     48    }
     49
     50    std::unique_ptr<LinkBuffer> m_linkBuffer;
     51    const char* m_codeDescription;
     52};
     53
    4254class JITFinalizer : public DFG::Finalizer {
    4355public:
    4456    JITFinalizer(DFG::Plan&);
    4557    virtual ~JITFinalizer();
    46    
     58
    4759    size_t codeSize() override;
    4860    bool finalize() override;
     
    5365    std::unique_ptr<LinkBuffer> sideCodeLinkBuffer;
    5466    std::unique_ptr<LinkBuffer> handleExceptionsLinkBuffer;
     67    Vector<OutOfLineCodeInfo> outOfLineCodeInfos;
    5568    Vector<SlowPathCall> slowPathCalls; // Calls inside the side code.
    5669    Vector<OSRExitCompilationInfo> osrExit;
Note: See TracChangeset for help on using the changeset viewer.