Title: [185772] trunk/Source/_javascript_Core
Revision
185772
Author
[email protected]
Date
2015-06-19 15:28:18 -0700 (Fri, 19 Jun 2015)

Log Message

Crash in com.apple.WebKit.WebContent at com.apple._javascript_Core: 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().

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (185771 => 185772)


--- trunk/Source/_javascript_Core/ChangeLog	2015-06-19 22:24:55 UTC (rev 185771)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-06-19 22:28:18 UTC (rev 185772)
@@ -1,3 +1,32 @@
+2015-06-19  Michael Saboff  <[email protected]>
+
+        Crash in com.apple.WebKit.WebContent at com.apple._javascript_Core: 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().
+
 2015-06-19  Geoffrey Garen  <[email protected]>
 
         WebKit crash while loading nytimes at _javascript_Core: JSC::ExecutableAllocator::allocate + 276

Modified: trunk/Source/_javascript_Core/ftl/FTLCompile.cpp (185771 => 185772)


--- trunk/Source/_javascript_Core/ftl/FTLCompile.cpp	2015-06-19 22:24:55 UTC (rev 185771)
+++ trunk/Source/_javascript_Core/ftl/FTLCompile.cpp	2015-06-19 22:28:18 UTC (rev 185772)
@@ -155,6 +155,49 @@
     return capturedLocation.addend() / sizeof(Register);
 }
 
+static 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)
+{
+    std::unique_ptr<LinkBuffer> codeLinkBuffer;
+    size_t actualCodeSize = code.m_assembler.buffer().codeSize();
+
+    if (actualCodeSize <= sizeOfInlineCode) {
+        LinkBuffer codeLinkBuffer(vm, code, startOfInlineCode, sizeOfInlineCode);
+
+        // Fill the remainder of the inline space with nops to avoid confusing the disassembler.
+        MacroAssembler::AssemblerType_T::fillNops(bitwise_cast<char*>(startOfInlineCode) + actualCodeSize, sizeOfInlineCode - actualCodeSize);
+
+        callback(codeLinkBuffer, code, true);
+
+        return;
+    }
+
+    // If there isn't enough space in the provided inline code area, allocate out of line
+    // executable memory to link the provided code. Place a jump at the beginning of the
+    // inline area and jump to the out of line code. Similarly return by appending a jump
+    // to the provided code that goes to the instruction after the inline code.
+    // Fill the middle with nop's.
+    MacroAssembler::Jump returnToMainline = code.jump();
+
+    // Allocate out of line executable memory and link the provided code there.
+    codeLinkBuffer = std::make_unique<LinkBuffer>(vm, code, codeBlock, JITCompilationMustSucceed);
+
+    // Plant a jmp in the inline buffer to the out of line code.
+    MacroAssembler callToOutOfLineCode;
+    MacroAssembler::Jump jumpToOutOfLine = callToOutOfLineCode.jump();
+    LinkBuffer inlineBuffer(vm, callToOutOfLineCode, startOfInlineCode, sizeOfInlineCode);
+    inlineBuffer.link(jumpToOutOfLine, codeLinkBuffer->entrypoint());
+
+    // Fill the remainder of the inline space with nops to avoid confusing the disassembler.
+    MacroAssembler::AssemblerType_T::fillNops(bitwise_cast<char*>(startOfInlineCode) + inlineBuffer.size(), sizeOfInlineCode - inlineBuffer.size());
+
+    // Link the end of the out of line code to right after the inline area.
+    codeLinkBuffer->link(returnToMainline, CodeLocationLabel(MacroAssemblerCodePtr::createFromExecutableAddress(startOfInlineCode)).labelAtOffset(sizeOfInlineCode));
+
+    callback(*codeLinkBuffer.get(), code, false);
+
+    state.finalizer->outOfLineCodeInfos.append(OutOfLineCodeInfo(WTF::move(codeLinkBuffer), codeDescription));
+}
+
 template<typename DescriptorType>
 void generateICFastPath(
     State& state, CodeBlock* codeBlock, GeneratedFunction generatedFunction,
@@ -181,23 +224,16 @@
         
         char* startOfIC =
             bitwise_cast<char*>(generatedFunction) + record.instructionOffset;
-        
-        LinkBuffer linkBuffer(vm, fastPathJIT, startOfIC, sizeOfIC);
-        // Note: we could handle the !isValid() case. We just don't appear to have a
-        // reason to do so, yet.
-        RELEASE_ASSERT(linkBuffer.isValid());
-        
-        MacroAssembler::AssemblerType_T::fillNops(
-            startOfIC + linkBuffer.size(), sizeOfIC - linkBuffer.size());
-        
-        state.finalizer->sideCodeLinkBuffer->link(
-            ic.m_slowPathDone[i], CodeLocationLabel(startOfIC + sizeOfIC));
-        
-        linkBuffer.link(
-            generator.slowPathJump(),
-            state.finalizer->sideCodeLinkBuffer->locationOf(generator.slowPathBegin()));
-        
-        generator.finalize(linkBuffer, *state.finalizer->sideCodeLinkBuffer);
+
+        generateInlineIfPossibleOutOfLineIfNot(state, vm, codeBlock, fastPathJIT, startOfIC, sizeOfIC, "inline cache fast path", [&] (LinkBuffer& linkBuffer, CCallHelpers&, bool) {
+            state.finalizer->sideCodeLinkBuffer->link(ic.m_slowPathDone[i],
+                CodeLocationLabel(startOfIC + sizeOfIC));
+
+            linkBuffer.link(generator.slowPathJump(),
+                state.finalizer->sideCodeLinkBuffer->locationOf(generator.slowPathBegin()));
+
+            generator.finalize(linkBuffer, *state.finalizer->sideCodeLinkBuffer);
+        });
     }
 }
 
@@ -232,33 +268,29 @@
 
         char* startOfIC =
             bitwise_cast<char*>(generatedFunction) + record.instructionOffset;
-        
-        LinkBuffer fastPath(vm, fastPathJIT, startOfIC, sizeOfIC);
-        LinkBuffer& slowPath = *state.finalizer->sideCodeLinkBuffer;
-        // Note: we could handle the !isValid() case. We just don't appear to have a
-        // reason to do so, yet.
-        RELEASE_ASSERT(fastPath.isValid());
 
-        MacroAssembler::AssemblerType_T::fillNops(
-            startOfIC + fastPath.size(), sizeOfIC - fastPath.size());
-        
-        state.finalizer->sideCodeLinkBuffer->link(
-            ic.m_slowPathDone[i], CodeLocationLabel(startOfIC + sizeOfIC));
-        
-        CodeLocationLabel slowPathBeginLoc = slowPath.locationOf(slowPathBegin);
-        fastPath.link(jump, slowPathBeginLoc);
+        auto postLink = [&] (LinkBuffer& fastPath, CCallHelpers&, bool) {
+            LinkBuffer& slowPath = *state.finalizer->sideCodeLinkBuffer;
 
-        CodeLocationCall callReturnLocation = slowPath.locationOf(call);
+            state.finalizer->sideCodeLinkBuffer->link(
+                ic.m_slowPathDone[i], CodeLocationLabel(startOfIC + sizeOfIC));
 
-        stubInfo.patch.deltaCallToDone = MacroAssembler::differenceBetweenCodePtr(
-            callReturnLocation, fastPath.locationOf(done));
+            CodeLocationLabel slowPathBeginLoc = slowPath.locationOf(slowPathBegin);
+            fastPath.link(jump, slowPathBeginLoc);
 
-        stubInfo.patch.deltaCallToJump = MacroAssembler::differenceBetweenCodePtr(
-            callReturnLocation, fastPath.locationOf(jump));
-        stubInfo.callReturnLocation = callReturnLocation;
-        stubInfo.patch.deltaCallToSlowCase = MacroAssembler::differenceBetweenCodePtr(
-            callReturnLocation, slowPathBeginLoc);
-        
+            CodeLocationCall callReturnLocation = slowPath.locationOf(call);
+
+            stubInfo.patch.deltaCallToDone = MacroAssembler::differenceBetweenCodePtr(
+                callReturnLocation, fastPath.locationOf(done));
+
+            stubInfo.patch.deltaCallToJump = MacroAssembler::differenceBetweenCodePtr(
+                callReturnLocation, fastPath.locationOf(jump));
+            stubInfo.callReturnLocation = callReturnLocation;
+            stubInfo.patch.deltaCallToSlowCase = MacroAssembler::differenceBetweenCodePtr(
+                callReturnLocation, slowPathBeginLoc);
+        };
+
+        generateInlineIfPossibleOutOfLineIfNot(state, vm, codeBlock, fastPathJIT, startOfIC, sizeOfIC, "CheckIn inline cache", postLink);
     }
 }
 
@@ -559,19 +591,12 @@
 
         CCallHelpers fastPathJIT(&vm, codeBlock);
         call.emit(fastPathJIT);
-        
+
         char* startOfIC = bitwise_cast<char*>(generatedFunction) + call.m_instructionOffset;
-        
-        LinkBuffer linkBuffer(vm, fastPathJIT, startOfIC, sizeOfCall());
-        if (!linkBuffer.isValid()) {
-            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");
-            RELEASE_ASSERT_NOT_REACHED();
-        }
-        
-        MacroAssembler::AssemblerType_T::fillNops(
-            startOfIC + linkBuffer.size(), sizeOfCall() - linkBuffer.size());
-        
-        call.link(vm, linkBuffer);
+
+        generateInlineIfPossibleOutOfLineIfNot(state, vm, codeBlock, fastPathJIT, startOfIC, sizeOfCall(), "JSCall inline cache", [&] (LinkBuffer& linkBuffer, CCallHelpers&, bool) {
+            call.link(vm, linkBuffer);
+        });
     }
     
     adjustCallICsForStackmaps(state.jsCallVarargses, recordMap);
@@ -581,20 +606,13 @@
         
         CCallHelpers fastPathJIT(&vm, codeBlock);
         call.emit(fastPathJIT, varargsSpillSlotsOffset);
-        
+
         char* startOfIC = bitwise_cast<char*>(generatedFunction) + call.m_instructionOffset;
         size_t sizeOfIC = sizeOfICFor(call.node());
 
-        LinkBuffer linkBuffer(vm, fastPathJIT, startOfIC, sizeOfIC);
-        if (!linkBuffer.isValid()) {
-            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");
-            RELEASE_ASSERT_NOT_REACHED();
-        }
-        
-        MacroAssembler::AssemblerType_T::fillNops(
-            startOfIC + linkBuffer.size(), sizeOfIC - linkBuffer.size());
-        
-        call.link(vm, linkBuffer, state.finalizer->handleExceptionsLinkBuffer->entrypoint());
+        generateInlineIfPossibleOutOfLineIfNot(state, vm, codeBlock, fastPathJIT, startOfIC, sizeOfIC, "varargs call inline cache", [&] (LinkBuffer& linkBuffer, CCallHelpers&, bool) {
+            call.link(vm, linkBuffer, state.finalizer->handleExceptionsLinkBuffer->entrypoint());
+        });
     }
     
     RepatchBuffer repatchBuffer(codeBlock);

Modified: trunk/Source/_javascript_Core/ftl/FTLJITFinalizer.cpp (185771 => 185772)


--- trunk/Source/_javascript_Core/ftl/FTLJITFinalizer.cpp	2015-06-19 22:24:55 UTC (rev 185771)
+++ trunk/Source/_javascript_Core/ftl/FTLJITFinalizer.cpp	2015-06-19 22:28:18 UTC (rev 185772)
@@ -127,7 +127,13 @@
                 toCString(CodeBlockWithJITType(m_plan.codeBlock.get(), JITCode::FTLJIT)).data()))
             .executableMemory());
     }
-    
+
+    for (unsigned i = 0; i < outOfLineCodeInfos.size(); ++i) {
+        jitCode->addHandle(FINALIZE_DFG_CODE(
+            *outOfLineCodeInfos[i].m_linkBuffer,
+            ("FTL out of line code for %s", outOfLineCodeInfos[i].m_codeDescription)).executableMemory());
+    }
+
     jitCode->initializeArityCheckEntrypoint(
         FINALIZE_DFG_CODE(
             *entrypointLinkBuffer,

Modified: trunk/Source/_javascript_Core/ftl/FTLJITFinalizer.h (185771 => 185772)


--- trunk/Source/_javascript_Core/ftl/FTLJITFinalizer.h	2015-06-19 22:24:55 UTC (rev 185771)
+++ trunk/Source/_javascript_Core/ftl/FTLJITFinalizer.h	2015-06-19 22:28:18 UTC (rev 185772)
@@ -39,11 +39,23 @@
 
 namespace JSC { namespace FTL {
 
+class OutOfLineCodeInfo {
+public:
+    OutOfLineCodeInfo(std::unique_ptr<LinkBuffer> linkBuffer, const char* codeDescription)
+        : m_linkBuffer(WTF::move(linkBuffer))
+        , m_codeDescription(codeDescription)
+    {
+    }
+
+    std::unique_ptr<LinkBuffer> m_linkBuffer;
+    const char* m_codeDescription;
+};
+
 class JITFinalizer : public DFG::Finalizer {
 public:
     JITFinalizer(DFG::Plan&);
     virtual ~JITFinalizer();
-    
+
     size_t codeSize() override;
     bool finalize() override;
     bool finalizeFunction() override;
@@ -52,6 +64,7 @@
     std::unique_ptr<LinkBuffer> entrypointLinkBuffer;
     std::unique_ptr<LinkBuffer> sideCodeLinkBuffer;
     std::unique_ptr<LinkBuffer> handleExceptionsLinkBuffer;
+    Vector<OutOfLineCodeInfo> outOfLineCodeInfos;
     Vector<SlowPathCall> slowPathCalls; // Calls inside the side code.
     Vector<OSRExitCompilationInfo> osrExit;
     GeneratedFunction function;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to