Changeset 165005 in webkit for trunk/Source/JavaScriptCore/dfg


Ignore:
Timestamp:
Mar 3, 2014, 1:39:21 PM (11 years ago)
Author:
[email protected]
Message:

ASSERTION FAILED: m_numBreakpoints >= numBreakpoints when deleting breakpoints.
<https://webkit.org/b/129393>

Reviewed by Geoffrey Garen.

The issue manifests because the debugger will iterate all CodeBlocks in
the heap when setting / clearing breakpoints, but it is possible for a
CodeBlock to have been instantiate but is not yet registered with the
debugger. This can happen because of the following:

  1. DFG worklist compilation is still in progress, and the target codeBlock is not ready for installation in its executable yet.
  1. DFG compilation failed and we have a codeBlock that will never be installed in its executable, and the codeBlock has not been cleaned up by the GC yet.

The code for installing the codeBlock in its executable is the same code
that registers it with the debugger. Hence, these codeBlocks are not
registered with the debugger, and any pending breakpoints that would map
to that CodeBlock is as yet unset or will never be set. As such, an
attempt to remove a breakpoint in that CodeBlock will fail that assertion.

To fix this, we do the following:

  1. We'll eagerly clean up any zombie CodeBlocks due to failed DFG / FTL compilation. This is achieved by providing a DeferredCompilationCallback::compilationDidComplete() that does this clean up, and have all sub classes call it at the end of their compilationDidComplete() methods.
  1. Before the debugger or profiler iterates CodeBlocks in the heap, they will wait for all compilations to complete before proceeding. This ensures that:
    1. any zombie CodeBlocks would have been cleaned up, and won't be seen by the debugger or profiler.
    2. all CodeBlocks that the debugger and profiler needs to operate on will be "ready" for whatever needs to be done to them e.g. jettison'ing of DFG codeBlocks.
  • bytecode/DeferredCompilationCallback.cpp:

(JSC::DeferredCompilationCallback::compilationDidComplete):

  • bytecode/DeferredCompilationCallback.h:
  • Provide default implementation method to clean up zombie CodeBlocks.
  • debugger/Debugger.cpp:

(JSC::Debugger::forEachCodeBlock):

  • Utility function to iterate CodeBlocks. It ensures that all compilations are complete before proceeding.

(JSC::Debugger::setSteppingMode):
(JSC::Debugger::toggleBreakpoint):
(JSC::Debugger::recompileAllJSFunctions):
(JSC::Debugger::clearBreakpoints):
(JSC::Debugger::clearDebuggerRequests):

  • Use the utility iterator function.
  • debugger/Debugger.h:
  • dfg/DFGOperations.cpp:
  • Added an assert to ensure that zombie CodeBlocks will be imminently cleaned up.
  • dfg/DFGPlan.cpp:

(JSC::DFG::Plan::finalizeWithoutNotifyingCallback):

  • Remove unneeded code (that was not the best solution anyway) for ensuring that we don't generate new DFG codeBlocks after enabling the debugger or profiler. Now that we wait for compilations to complete before proceeding with debugger and profiler work, this scenario will never happen.
  • dfg/DFGToFTLDeferredCompilationCallback.cpp:

(JSC::DFG::ToFTLDeferredCompilationCallback::compilationDidComplete):

  • Call the super class method to clean up zombie codeBlocks.
  • dfg/DFGToFTLForOSREntryDeferredCompilationCallback.cpp:

(JSC::DFG::ToFTLForOSREntryDeferredCompilationCallback::compilationDidComplete):

  • Call the super class method to clean up zombie codeBlocks.
  • heap/CodeBlockSet.cpp:

(JSC::CodeBlockSet::remove):

  • heap/CodeBlockSet.h:
  • heap/Heap.h:

(JSC::Heap::removeCodeBlock):

  • New method to remove a codeBlock from the codeBlock set.
  • jit/JITOperations.cpp:
  • Added an assert to ensure that zombie CodeBlocks will be imminently cleaned up.
  • jit/JITToDFGDeferredCompilationCallback.cpp:

(JSC::JITToDFGDeferredCompilationCallback::compilationDidComplete):

  • Call the super class method to clean up zombie codeBlocks.
  • runtime/VM.cpp:

(JSC::VM::waitForCompilationsToComplete):

  • Renamed from prepareToDiscardCode() to be clearer about what it does.

(JSC::VM::discardAllCode):
(JSC::VM::releaseExecutableMemory):
(JSC::VM::setEnabledProfiler):

  • Wait for compilation to complete before enabling the profiler.
  • runtime/VM.h:
Location:
trunk/Source/JavaScriptCore/dfg
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r164764 r165005  
    12541254    jitCode->reconstruct(
    12551255        exec, codeBlock, CodeOrigin(bytecodeIndex), streamIndex, mustHandleValues);
     1256    RefPtr<CodeBlock> replacementCodeBlock = codeBlock->newReplacement();
    12561257    CompilationResult forEntryResult = compile(
    1257         *vm, codeBlock->newReplacement().get(), codeBlock, FTLForOSREntryMode, bytecodeIndex,
     1258        *vm, replacementCodeBlock.get(), codeBlock, FTLForOSREntryMode, bytecodeIndex,
    12581259        mustHandleValues, ToFTLForOSREntryDeferredCompilationCallback::create(codeBlock));
    12591260   
    1260     if (forEntryResult != CompilationSuccessful)
     1261    if (forEntryResult != CompilationSuccessful) {
     1262        ASSERT(forEntryResult == CompilationDeferred || replacementCodeBlock->hasOneRef());
    12611263        return 0;
    1262    
     1264    }
     1265
    12631266    // It's possible that the for-entry compile already succeeded. In that case OSR
    12641267    // entry will succeed unless we ran out of stack. It's not clear what we should do.
  • trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp

    r164459 r165005  
    392392        return CompilationInvalidated;
    393393
    394     if (vm.enabledProfiler())
    395         return CompilationInvalidated;
    396 
    397     Debugger* debugger = codeBlock->globalObject()->debugger();
    398     if (debugger && (debugger->isStepping() || codeBlock->baselineAlternative()->hasDebuggerRequests()))
    399         return CompilationInvalidated;
    400 
    401394    bool result;
    402395    if (codeBlock->codeType() == FunctionCode)
  • trunk/Source/JavaScriptCore/dfg/DFGToFTLDeferredCompilationCallback.cpp

    r164229 r165005  
    8686    m_dfgCodeBlock->jitCode()->dfg()->setOptimizationThresholdBasedOnCompilationResult(
    8787        m_dfgCodeBlock.get(), result);
     88
     89    DeferredCompilationCallback::compilationDidComplete(codeBlock, result);
    8890}
    8991
  • trunk/Source/JavaScriptCore/dfg/DFGToFTLForOSREntryDeferredCompilationCallback.cpp

    r164229 r165005  
    8080    case CompilationSuccessful:
    8181        jitCode->osrEntryBlock = codeBlock;
    82         return;
     82        break;
    8383    case CompilationFailed:
    8484        jitCode->osrEntryRetry = 0;
    8585        jitCode->abandonOSREntry = true;
    86         return;
     86        break;
    8787    case CompilationDeferred:
    88         return;
     88        RELEASE_ASSERT_NOT_REACHED();
    8989    case CompilationInvalidated:
    9090        jitCode->osrEntryRetry = 0;
    91         return;
     91        break;
    9292    }
    9393   
    94     RELEASE_ASSERT_NOT_REACHED();
     94    DeferredCompilationCallback::compilationDidComplete(codeBlock, result);
    9595}
    9696
Note: See TracChangeset for help on using the changeset viewer.