Changeset 119844 in webkit


Ignore:
Timestamp:
Jun 8, 2012 11:17:16 AM (12 years ago)
Author:
ggaren@apple.com
Message:

Don't rely on weak pointers for eager CodeBlock finalization
https://bugs.webkit.org/show_bug.cgi?id=88465

Reviewed by Gavin Barraclough.

This is incompatible with lazy weak pointer finalization.

I considered just making CodeBlock finalization lazy-friendly, but it
turns out that the heap is already way up in CodeBlock's business when
it comes to finalization, so I decided to finish the job and move full
responsibility for CodeBlock finalization into the heap.

will build.

  • debugger/Debugger.cpp: Updated for rename.
  • heap/Heap.cpp:

(JSC::Heap::deleteAllCompiledCode): Renamed for consistency. Fixed a bug
where we would not delete code for a code block that had been previously
jettisoned. I don't know if this happens in practice -- I mostly did
this to improve consistency with deleteUnmarkedCompiledCode.

(JSC::Heap::deleteUnmarkedCompiledCode): New function, responsible for
eager finalization of unmarked code blocks.

(JSC::Heap::collect): Updated for rename. Updated to call
deleteUnmarkedCompiledCode(), which takes care of jettisoned DFG code
blocks too.

(JSC::Heap::addCompiledCode): Renamed, since this points to all code
now, not just functions.

  • heap/Heap.h:

(Heap): Keep track of all user code, not just functions. This is a
negligible additional overhead, since most code is function code.

  • runtime/Executable.cpp:

(JSC::*::finalize): Removed these functions, since we don't rely on
weak pointer finalization anymore.

(JSC::FunctionExecutable::FunctionExecutable): Moved linked-list stuff
into base class so all executables can be in the list.

(JSC::EvalExecutable::clearCode):
(JSC::ProgramExecutable::clearCode):
(JSC::FunctionExecutable::clearCode): All we need to do is delete our
CodeBlock -- that will delete all of its internal data structures.

(JSC::FunctionExecutable::clearCodeIfNotCompiling): Factored out a helper
function to improve clarity.

  • runtime/Executable.h:

(JSC::ExecutableBase): Moved linked-list stuff
into base class so all executables can be in the list.

(JSC::NativeExecutable::create):
(NativeExecutable):
(ScriptExecutable):
(JSC::ScriptExecutable::finishCreation):
(JSC::EvalExecutable::create):
(EvalExecutable):
(JSC::ProgramExecutable::create):
(ProgramExecutable):
(FunctionExecutable):
(JSC::FunctionExecutable::create): Don't use a finalizer -- the heap
will call us back to destroy our code block.

(JSC::FunctionExecutable::discardCode): Renamed to clearCodeIfNotCompiling()
for clarity.

(JSC::FunctionExecutable::isCompiling): New helper function, for clarity.

(JSC::ScriptExecutable::clearCodeVirtual): New helper function, since
the heap needs to make polymorphic calls to clear code.

  • runtime/JSGlobalData.cpp:

(JSC::StackPreservingRecompiler::operator()):

  • runtime/JSGlobalObject.cpp:

(JSC::DynamicGlobalObjectScope::DynamicGlobalObjectScope): Updated for
renames.

Location:
trunk/Source/JavaScriptCore
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r119795 r119844  
     1        Don't rely on weak pointers for eager CodeBlock finalization
     2        https://bugs.webkit.org/show_bug.cgi?id=88465
     3
     4        Reviewed by Gavin Barraclough.
     5
     6        This is incompatible with lazy weak pointer finalization.
     7
     8        I considered just making CodeBlock finalization lazy-friendly, but it
     9        turns out that the heap is already way up in CodeBlock's business when
     10        it comes to finalization, so I decided to finish the job and move full
     11        responsibility for CodeBlock finalization into the heap.
     12
     13        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: Maybe this
     14        will build.
     15
     16        * debugger/Debugger.cpp: Updated for rename.
     17
     18        * heap/Heap.cpp:
     19        (JSC::Heap::deleteAllCompiledCode): Renamed for consistency. Fixed a bug
     20        where we would not delete code for a code block that had been previously
     21        jettisoned. I don't know if this happens in practice -- I mostly did
     22        this to improve consistency with deleteUnmarkedCompiledCode.
     23
     24        (JSC::Heap::deleteUnmarkedCompiledCode): New function, responsible for
     25        eager finalization of unmarked code blocks.
     26
     27        (JSC::Heap::collect): Updated for rename. Updated to call
     28        deleteUnmarkedCompiledCode(), which takes care of jettisoned DFG code
     29        blocks too.
     30
     31        (JSC::Heap::addCompiledCode): Renamed, since this points to all code
     32        now, not just functions.
     33
     34        * heap/Heap.h:
     35        (Heap): Keep track of all user code, not just functions. This is a
     36        negligible additional overhead, since most code is function code.
     37
     38        * runtime/Executable.cpp:
     39        (JSC::*::finalize): Removed these functions, since we don't rely on
     40        weak pointer finalization anymore.
     41
     42        (JSC::FunctionExecutable::FunctionExecutable): Moved linked-list stuff
     43        into base class so all executables can be in the list.
     44
     45        (JSC::EvalExecutable::clearCode):
     46        (JSC::ProgramExecutable::clearCode):
     47        (JSC::FunctionExecutable::clearCode): All we need to do is delete our
     48        CodeBlock -- that will delete all of its internal data structures.
     49
     50        (JSC::FunctionExecutable::clearCodeIfNotCompiling): Factored out a helper
     51        function to improve clarity.
     52
     53        * runtime/Executable.h:
     54        (JSC::ExecutableBase): Moved linked-list stuff
     55        into base class so all executables can be in the list.
     56
     57        (JSC::NativeExecutable::create):
     58        (NativeExecutable):
     59        (ScriptExecutable):
     60        (JSC::ScriptExecutable::finishCreation):
     61        (JSC::EvalExecutable::create):
     62        (EvalExecutable):
     63        (JSC::ProgramExecutable::create):
     64        (ProgramExecutable):
     65        (FunctionExecutable):
     66        (JSC::FunctionExecutable::create): Don't use a finalizer -- the heap
     67        will call us back to destroy our code block.
     68
     69        (JSC::FunctionExecutable::discardCode): Renamed to clearCodeIfNotCompiling()
     70        for clarity.
     71
     72        (JSC::FunctionExecutable::isCompiling): New helper function, for clarity.
     73
     74        (JSC::ScriptExecutable::clearCodeVirtual): New helper function, since
     75        the heap needs to make polymorphic calls to clear code.
     76
     77        * runtime/JSGlobalData.cpp:
     78        (JSC::StackPreservingRecompiler::operator()):
     79        * runtime/JSGlobalObject.cpp:
     80        (JSC::DynamicGlobalObjectScope::DynamicGlobalObjectScope): Updated for
     81        renames.
     82
    1832012-06-07  Filip Pizlo  <fpizlo@apple.com>
    284
  • trunk/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def

    r119655 r119844  
    152152    ?detachThread@WTF@@YAXI@Z
    153153    ?didTimeOut@TimeoutChecker@JSC@@QAE_NPAVExecState@2@@Z
    154     ?discardAllCompiledCode@Heap@JSC@@QAEXXZ
     154    ?deleteAllCompiledCode@Heap@JSC@@QAEXXZ
    155155    ?displayName@JSFunction@JSC@@QAE?BVUString@2@PAVExecState@2@@Z
    156156    ?dtoa@WTF@@YAXQADNAA_NAAHAAI@Z
  • trunk/Source/JavaScriptCore/debugger/Debugger.cpp

    r112555 r119844  
    8080
    8181    ExecState* exec = function->scope()->globalObject->JSGlobalObject::globalExec();
    82     executable->discardCode();
     82    executable->clearCodeIfNotCompiling();
    8383    if (m_debugger == function->scope()->globalObject->debugger())
    8484        m_sourceProviders.add(executable->source().provider(), exec);
  • trunk/Source/JavaScriptCore/heap/Heap.cpp

    r119633 r119844  
    644644}
    645645
    646 void Heap::discardAllCompiledCode()
    647 {
    648     // If JavaScript is running, it's not safe to recompile, since we'll end
    649     // up throwing away code that is live on the stack.
     646void Heap::deleteAllCompiledCode()
     647{
     648    // If JavaScript is running, it's not safe to delete code, since we'll end
     649    // up deleting code that is live on the stack.
    650650    if (m_globalData->dynamicGlobalObject)
    651651        return;
    652652
    653     for (FunctionExecutable* current = m_functions.head(); current; current = current->next())
    654         current->discardCode();
     653    for (ExecutableBase* current = m_compiledCode.head(); current; current = current->next()) {
     654        if (!current->isFunctionExecutable())
     655            continue;
     656        static_cast<FunctionExecutable*>(current)->clearCodeIfNotCompiling();
     657    }
     658
     659    m_dfgCodeBlocks.clearMarks();
     660    m_dfgCodeBlocks.deleteUnmarkedJettisonedCodeBlocks();
     661}
     662
     663void Heap::deleteUnmarkedCompiledCode()
     664{
     665    ExecutableBase* next;
     666    for (ExecutableBase* current = m_compiledCode.head(); current; current = next) {
     667        next = current->next();
     668        if (isMarked(current))
     669            continue;
     670
     671        // We do this because executable memory is limited on some platforms and because
     672        // CodeBlock requires eager finalization.
     673        ExecutableBase::clearCodeVirtual(current);
     674        m_compiledCode.remove(current);
     675    }
     676
     677    m_dfgCodeBlocks.deleteUnmarkedJettisonedCodeBlocks();
    655678}
    656679
     
    681704    double lastGCStartTime = WTF::currentTime();
    682705    if (lastGCStartTime - m_lastCodeDiscardTime > minute) {
    683         discardAllCompiledCode();
     706        deleteAllCompiledCode();
    684707        m_lastCodeDiscardTime = WTF::currentTime();
    685708    }
     
    704727    }
    705728
     729    JAVASCRIPTCORE_GC_MARKED();
     730
    706731    {
    707732        GCPHASE(FinalizeUnconditionalFinalizers);
     
    714739        m_globalData->smallStrings.finalizeSmallStrings();
    715740    }
    716    
    717     JAVASCRIPTCORE_GC_MARKED();
    718741
    719742    {
    720743        GCPHASE(DeleteCodeBlocks);
    721         m_dfgCodeBlocks.deleteUnmarkedJettisonedCodeBlocks();
     744        deleteUnmarkedCompiledCode();
    722745    }
    723746
     
    809832}
    810833
    811 void Heap::addFunctionExecutable(FunctionExecutable* executable)
    812 {
    813     m_functions.append(executable);
    814 }
    815 
    816 void Heap::removeFunctionExecutable(FunctionExecutable* executable)
    817 {
    818     m_functions.remove(executable);
     834void Heap::addCompiledCode(ExecutableBase* executable)
     835{
     836    m_compiledCode.append(executable);
    819837}
    820838
  • trunk/Source/JavaScriptCore/heap/Heap.h

    r119655 r119844  
    4343    class CopiedSpace;
    4444    class CodeBlock;
    45     class FunctionExecutable;
     45    class ExecutableBase;
    4646    class GCActivityCallback;
    4747    class GlobalCodeBlock;
     
    117117        typedef void (*Finalizer)(JSCell*);
    118118        JS_EXPORT_PRIVATE void addFinalizer(JSCell*, Finalizer);
    119         void addFunctionExecutable(FunctionExecutable*);
    120         void removeFunctionExecutable(FunctionExecutable*);
     119        void addCompiledCode(ExecutableBase*);
    121120
    122121        void notifyIsSafeToCollect() { m_isSafeToCollect = true; }
     
    160159        void increaseLastGCLength(double amount) { m_lastGCLength += amount; }
    161160
    162         JS_EXPORT_PRIVATE void discardAllCompiledCode();
     161        JS_EXPORT_PRIVATE void deleteAllCompiledCode();
    163162
    164163        void didAllocate(size_t);
     
    195194        void harvestWeakReferences();
    196195        void finalizeUnconditionalFinalizers();
     196        void deleteUnmarkedCompiledCode();
    197197       
    198198        RegisterFile& registerFile();
     
    240240        double m_lastCodeDiscardTime;
    241241
    242         DoublyLinkedList<FunctionExecutable> m_functions;
     242        DoublyLinkedList<ExecutableBase> m_compiledCode;
    243243    };
    244244
  • trunk/Source/JavaScriptCore/runtime/Executable.cpp

    r118616 r119844  
    4848#endif
    4949
    50 inline void ExecutableBase::clearCode()
     50void ExecutableBase::clearCode()
    5151{
    5252#if ENABLE(JIT)
     
    9898}
    9999#endif
    100 
    101 void NativeExecutable::finalize(JSCell* cell)
    102 {
    103     jsCast<NativeExecutable*>(cell)->clearCode();
    104 }
    105100
    106101const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(ScriptExecutable) };
     
    147142    , m_inferredName(inferredName.isNull() ? globalData.propertyNames->emptyIdentifier : inferredName)
    148143    , m_symbolTable(0)
    149     , m_next(0)
    150     , m_prev(0)
    151144{
    152145}
     
    160153    , m_inferredName(inferredName.isNull() ? exec->globalData().propertyNames->emptyIdentifier : inferredName)
    161154    , m_symbolTable(0)
    162     , m_next(0)
    163     , m_prev(0)
    164155{
    165156}
     
    293284}
    294285
    295 void EvalExecutable::finalize(JSCell* cell)
    296 {
    297     jsCast<EvalExecutable*>(cell)->clearCode();
    298 }
    299 
    300 inline void EvalExecutable::clearCode()
    301 {
    302     if (m_evalCodeBlock) {
    303         m_evalCodeBlock->clearEvalCache();
    304         m_evalCodeBlock.clear();
    305     }
     286void EvalExecutable::clearCode()
     287{
     288    m_evalCodeBlock.clear();
    306289    Base::clearCode();
    307290}
     
    425408}
    426409
    427 void ProgramExecutable::finalize(JSCell* cell)
    428 {
    429     jsCast<ProgramExecutable*>(cell)->clearCode();
    430 }
    431 
    432 inline void ProgramExecutable::clearCode()
    433 {
    434     if (m_programCodeBlock) {
    435         m_programCodeBlock->clearEvalCache();
    436         m_programCodeBlock.clear();
    437     }
     410void ProgramExecutable::clearCode()
     411{
     412    m_programCodeBlock.clear();
    438413    Base::clearCode();
    439414}
     
    643618}
    644619
    645 void FunctionExecutable::discardCode()
    646 {
    647 #if ENABLE(JIT)
    648     // These first two checks are to handle the rare case where
    649     // we are trying to evict code for a function during its
    650     // codegen.
    651     if (!m_jitCodeForCall && m_codeBlockForCall)
     620void FunctionExecutable::clearCodeIfNotCompiling()
     621{
     622    if (isCompiling())
    652623        return;
    653     if (!m_jitCodeForConstruct && m_codeBlockForConstruct)
    654         return;
    655 #endif
    656624    clearCode();
    657625}
    658626
    659 void FunctionExecutable::finalize(JSCell* cell)
    660 {
    661     FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell);
    662     Heap::heap(executable)->removeFunctionExecutable(executable);
    663     executable->clearCode();
    664 }
    665 
    666 inline void FunctionExecutable::clearCode()
    667 {
    668     if (m_codeBlockForCall) {
    669         m_codeBlockForCall->clearEvalCache();
    670         m_codeBlockForCall.clear();
    671     }
    672     if (m_codeBlockForConstruct) {
    673         m_codeBlockForConstruct->clearEvalCache();
    674         m_codeBlockForConstruct.clear();
    675     }
     627void FunctionExecutable::clearCode()
     628{
     629    m_codeBlockForCall.clear();
     630    m_codeBlockForConstruct.clear();
    676631    Base::clearCode();
    677632}
  • trunk/Source/JavaScriptCore/runtime/Executable.h

    r118966 r119844  
    5555    }
    5656
    57     class ExecutableBase : public JSCell {
     57    class ExecutableBase : public JSCell, public DoublyLinkedListNode<ExecutableBase> {
     58        friend class WTF::DoublyLinkedListNode<ExecutableBase>;
    5859        friend class JIT;
    5960
     
    8182#endif
    8283
     84        bool isFunctionExecutable()
     85        {
     86            return structure()->typeInfo().type() == FunctionExecutableType;
     87        }
     88
    8389        bool isHostFunction() const
    8490        {
     
    8995        static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(globalData, globalObject, proto, TypeInfo(CompoundType, StructureFlags), &s_info); }
    9096       
     97        void clearCode();
     98
    9199        static JS_EXPORTDATA const ClassInfo s_info;
    92100
     
    98106#if ENABLE(JIT)
    99107    public:
     108        static void clearCodeVirtual(ExecutableBase*);
     109
    100110        JITCode& generatedJITCodeForCall()
    101111        {
     
    169179
    170180    protected:
     181        ExecutableBase* m_prev;
     182        ExecutableBase* m_next;
     183
    171184        JITCode m_jitCodeForCall;
    172185        JITCode m_jitCodeForConstruct;
     
    174187        MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck;
    175188#endif
    176         void clearCode();
    177189    };
    178190
     
    195207                executable->finishCreation(globalData, JITCode::HostFunction(callThunk), JITCode::HostFunction(constructThunk), intrinsic);
    196208            }
    197             globalData.heap.addFinalizer(executable, &finalize);
    198209            return executable;
    199210        }
     
    206217            NativeExecutable* executable = new (NotNull, allocateCell<NativeExecutable>(globalData.heap)) NativeExecutable(globalData, function, constructor);
    207218            executable->finishCreation(globalData);
    208             globalData.heap.addFinalizer(executable, &finalize);
    209219            return executable;
    210220        }
     
    247257#endif
    248258
    249         static void finalize(JSCell*);
    250  
    251259    private:
    252260        NativeExecutable(JSGlobalData& globalData, NativeFunction function, NativeFunction constructor)
     
    304312        {
    305313            Base::finishCreation(globalData);
     314            globalData.heap.addCompiledCode(this); // Balanced by Heap::deleteUnmarkedCompiledCode().
     315
    306316#if ENABLE(CODEBLOCK_SAMPLING)
    307317            if (SamplingTool* sampler = globalData.interpreter->sampler())
     
    359369            EvalExecutable* executable = new (NotNull, allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, source, isInStrictContext);
    360370            executable->finishCreation(exec->globalData());
    361             exec->globalData().heap.addFinalizer(executable, &finalize);
    362371            return executable;
    363372        }
     
    378387        void unlinkCalls();
    379388
    380     protected:
    381389        void clearCode();
    382         static void finalize(JSCell*);
    383390
    384391    private:
     
    401408            ProgramExecutable* executable = new (NotNull, allocateCell<ProgramExecutable>(*exec->heap())) ProgramExecutable(exec, source);
    402409            executable->finishCreation(exec->globalData());
    403             exec->globalData().heap.addFinalizer(executable, &finalize);
    404410            return executable;
    405411        }
     
    448454        void unlinkCalls();
    449455
    450     protected:
    451456        void clearCode();
    452         static void finalize(JSCell*);
    453457
    454458    private:
     
    462466    };
    463467
    464     class FunctionExecutable : public ScriptExecutable, public DoublyLinkedListNode<FunctionExecutable> {
     468    class FunctionExecutable : public ScriptExecutable {
    465469        friend class JIT;
    466470        friend class LLIntOffsetsExtractor;
    467         friend class WTF::DoublyLinkedListNode<FunctionExecutable>;
    468471    public:
    469472        typedef ScriptExecutable Base;
     
    473476            FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(*exec->heap())) FunctionExecutable(exec, name, inferredName, source, forceUsesArguments, parameters, isInStrictContext);
    474477            executable->finishCreation(exec->globalData(), name, firstLine, lastLine);
    475             exec->globalData().heap.addFunctionExecutable(executable);
    476             exec->globalData().heap.addFinalizer(executable, &finalize);
    477478            return executable;
    478479        }
     
    482483            FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(globalData.heap)) FunctionExecutable(globalData, name, inferredName, source, forceUsesArguments, parameters, isInStrictContext);
    483484            executable->finishCreation(globalData, name, firstLine, lastLine);
    484             globalData.heap.addFunctionExecutable(executable);
    485             globalData.heap.addFinalizer(executable, &finalize);
    486485            return executable;
    487486        }
     
    640639        SharedSymbolTable* symbolTable() const { return m_symbolTable; }
    641640
    642         void discardCode();
     641        void clearCodeIfNotCompiling();
    643642        static void visitChildren(JSCell*, SlotVisitor&);
    644643        static FunctionExecutable* fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, JSObject** exception);
     
    652651        void unlinkCalls();
    653652
     653        void clearCode();
     654
    654655    protected:
    655         void clearCode();
    656         static void finalize(JSCell*);
    657 
    658656        void finishCreation(JSGlobalData& globalData, const Identifier& name, int firstLine, int lastLine)
    659657        {
     
    678676            return m_codeBlockForConstruct;
    679677        }
    680        
     678 
     679        bool isCompiling()
     680        {
     681#if ENABLE(JIT)
     682            if (!m_jitCodeForCall && m_codeBlockForCall)
     683                return true;
     684            if (!m_jitCodeForConstruct && m_codeBlockForConstruct)
     685                return true;
     686#endif
     687            return false;
     688        }
     689
    681690        static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
    682691        unsigned m_numCapturedVariables : 31;
     
    690699        WriteBarrier<JSString> m_nameValue;
    691700        SharedSymbolTable* m_symbolTable;
    692         FunctionExecutable* m_next;
    693         FunctionExecutable* m_prev;
    694701    };
    695702
     
    724731            return false;
    725732        return function->nativeFunction() == nativeFunction;
     733    }
     734
     735    inline void ExecutableBase::clearCodeVirtual(ExecutableBase* executable)
     736    {
     737        switch (executable->structure()->typeInfo().type()) {
     738        case EvalExecutableType:
     739            return jsCast<EvalExecutable*>(executable)->clearCode();
     740        case ProgramExecutableType:
     741            return jsCast<ProgramExecutable*>(executable)->clearCode();
     742        case FunctionExecutableType:
     743            return jsCast<FunctionExecutable*>(executable)->clearCode();
     744        default:
     745            return jsCast<NativeExecutable*>(executable)->clearCode();
     746        }
    726747    }
    727748
  • trunk/Source/JavaScriptCore/runtime/JSGlobalData.cpp

    r119441 r119844  
    420420        if (currentlyExecutingFunctions.contains(executable))
    421421            return;
    422         executable->discardCode();
     422        executable->clearCodeIfNotCompiling();
    423423    }
    424424};
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp

    r119655 r119844  
    444444#if ENABLE(ASSEMBLER)
    445445        if (ExecutableAllocator::underMemoryPressure())
    446             globalData.heap.discardAllCompiledCode();
     446            globalData.heap.deleteAllCompiledCode();
    447447#endif
    448448
Note: See TracChangeset for help on using the changeset viewer.