Don't rely on weak pointers for eager CodeBlock finalization
authorggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 8 Jun 2012 18:17:16 +0000 (18:17 +0000)
committerggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 8 Jun 2012 18:17:16 +0000 (18:17 +0000)
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.

* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: Maybe this
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.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@119844 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
Source/JavaScriptCore/debugger/Debugger.cpp
Source/JavaScriptCore/heap/Heap.cpp
Source/JavaScriptCore/heap/Heap.h
Source/JavaScriptCore/runtime/Executable.cpp
Source/JavaScriptCore/runtime/Executable.h
Source/JavaScriptCore/runtime/JSGlobalData.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.cpp

index 296805d..d8effc9 100644 (file)
@@ -1,3 +1,85 @@
+        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.
+
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: Maybe this
+        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.
+
 2012-06-07  Filip Pizlo  <fpizlo@apple.com>
 
         DFG should inline prototype chain accesses, and do the right things if the
index ada0930..a2900b5 100755 (executable)
@@ -151,7 +151,7 @@ EXPORTS
     ?detach@Debugger@JSC@@UAEXPAVJSGlobalObject@2@@Z
     ?detachThread@WTF@@YAXI@Z
     ?didTimeOut@TimeoutChecker@JSC@@QAE_NPAVExecState@2@@Z
-    ?discardAllCompiledCode@Heap@JSC@@QAEXXZ
+    ?deleteAllCompiledCode@Heap@JSC@@QAEXXZ
     ?displayName@JSFunction@JSC@@QAE?BVUString@2@PAVExecState@2@@Z
     ?dtoa@WTF@@YAXQADNAA_NAAHAAI@Z
     ?dumpSampleData@JSGlobalData@JSC@@QAEXPAVExecState@2@@Z
index ede8a9b..0a66d6f 100644 (file)
@@ -79,7 +79,7 @@ inline void Recompiler::operator()(JSCell* cell)
         return;
 
     ExecState* exec = function->scope()->globalObject->JSGlobalObject::globalExec();
-    executable->discardCode();
+    executable->clearCodeIfNotCompiling();
     if (m_debugger == function->scope()->globalObject->debugger())
         m_sourceProviders.add(executable->source().provider(), exec);
 }
index 790e3aa..f1f1875 100644 (file)
@@ -643,15 +643,38 @@ PassOwnPtr<TypeCountSet> Heap::objectTypeCounts()
     return m_objectSpace.forEachCell<RecordType>();
 }
 
-void Heap::discardAllCompiledCode()
+void Heap::deleteAllCompiledCode()
 {
-    // If JavaScript is running, it's not safe to recompile, since we'll end
-    // up throwing away code that is live on the stack.
+    // If JavaScript is running, it's not safe to delete code, since we'll end
+    // up deleting code that is live on the stack.
     if (m_globalData->dynamicGlobalObject)
         return;
 
-    for (FunctionExecutable* current = m_functions.head(); current; current = current->next())
-        current->discardCode();
+    for (ExecutableBase* current = m_compiledCode.head(); current; current = current->next()) {
+        if (!current->isFunctionExecutable())
+            continue;
+        static_cast<FunctionExecutable*>(current)->clearCodeIfNotCompiling();
+    }
+
+    m_dfgCodeBlocks.clearMarks();
+    m_dfgCodeBlocks.deleteUnmarkedJettisonedCodeBlocks();
+}
+
+void Heap::deleteUnmarkedCompiledCode()
+{
+    ExecutableBase* next;
+    for (ExecutableBase* current = m_compiledCode.head(); current; current = next) {
+        next = current->next();
+        if (isMarked(current))
+            continue;
+
+        // We do this because executable memory is limited on some platforms and because
+        // CodeBlock requires eager finalization.
+        ExecutableBase::clearCodeVirtual(current);
+        m_compiledCode.remove(current);
+    }
+
+    m_dfgCodeBlocks.deleteUnmarkedJettisonedCodeBlocks();
 }
 
 void Heap::collectAllGarbage()
@@ -680,7 +703,7 @@ void Heap::collect(SweepToggle sweepToggle)
 
     double lastGCStartTime = WTF::currentTime();
     if (lastGCStartTime - m_lastCodeDiscardTime > minute) {
-        discardAllCompiledCode();
+        deleteAllCompiledCode();
         m_lastCodeDiscardTime = WTF::currentTime();
     }
 
@@ -703,6 +726,8 @@ void Heap::collect(SweepToggle sweepToggle)
         m_objectSpace.reapWeakSets();
     }
 
+    JAVASCRIPTCORE_GC_MARKED();
+
     {
         GCPHASE(FinalizeUnconditionalFinalizers);
         finalizeUnconditionalFinalizers();
@@ -713,12 +738,10 @@ void Heap::collect(SweepToggle sweepToggle)
         m_objectSpace.sweepWeakSets();
         m_globalData->smallStrings.finalizeSmallStrings();
     }
-    
-    JAVASCRIPTCORE_GC_MARKED();
 
     {
         GCPHASE(DeleteCodeBlocks);
-        m_dfgCodeBlocks.deleteUnmarkedJettisonedCodeBlocks();
+        deleteUnmarkedCompiledCode();
     }
 
     if (sweepToggle == DoSweep) {
@@ -808,14 +831,9 @@ void Heap::FinalizerOwner::finalize(Handle<Unknown> handle, void* context)
     WeakSet::deallocate(WeakImpl::asWeakImpl(slot));
 }
 
-void Heap::addFunctionExecutable(FunctionExecutable* executable)
-{
-    m_functions.append(executable);
-}
-
-void Heap::removeFunctionExecutable(FunctionExecutable* executable)
+void Heap::addCompiledCode(ExecutableBase* executable)
 {
-    m_functions.remove(executable);
+    m_compiledCode.append(executable);
 }
 
 } // namespace JSC
index fdd3fee..22e4890 100644 (file)
@@ -42,7 +42,7 @@ namespace JSC {
 
     class CopiedSpace;
     class CodeBlock;
-    class FunctionExecutable;
+    class ExecutableBase;
     class GCActivityCallback;
     class GlobalCodeBlock;
     class Heap;
@@ -116,8 +116,7 @@ namespace JSC {
 
         typedef void (*Finalizer)(JSCell*);
         JS_EXPORT_PRIVATE void addFinalizer(JSCell*, Finalizer);
-        void addFunctionExecutable(FunctionExecutable*);
-        void removeFunctionExecutable(FunctionExecutable*);
+        void addCompiledCode(ExecutableBase*);
 
         void notifyIsSafeToCollect() { m_isSafeToCollect = true; }
 
@@ -159,7 +158,7 @@ namespace JSC {
         double lastGCLength() { return m_lastGCLength; }
         void increaseLastGCLength(double amount) { m_lastGCLength += amount; }
 
-        JS_EXPORT_PRIVATE void discardAllCompiledCode();
+        JS_EXPORT_PRIVATE void deleteAllCompiledCode();
 
         void didAllocate(size_t);
         void didAbandon(size_t);
@@ -194,6 +193,7 @@ namespace JSC {
         void markTempSortVectors(HeapRootVisitor&);
         void harvestWeakReferences();
         void finalizeUnconditionalFinalizers();
+        void deleteUnmarkedCompiledCode();
         
         RegisterFile& registerFile();
         BlockAllocator& blockAllocator();
@@ -239,7 +239,7 @@ namespace JSC {
         double m_lastGCLength;
         double m_lastCodeDiscardTime;
 
-        DoublyLinkedList<FunctionExecutable> m_functions;
+        DoublyLinkedList<ExecutableBase> m_compiledCode;
     };
 
     inline bool Heap::shouldCollect()
index 0ada2cb..73b4b6c 100644 (file)
@@ -47,7 +47,7 @@ void ExecutableBase::destroy(JSCell* cell)
 }
 #endif
 
-inline void ExecutableBase::clearCode()
+void ExecutableBase::clearCode()
 {
 #if ENABLE(JIT)
     m_jitCodeForCall.clear();
@@ -98,11 +98,6 @@ static void jettisonCodeBlock(JSGlobalData& globalData, OwnPtr<T>& codeBlock)
 }
 #endif
 
-void NativeExecutable::finalize(JSCell* cell)
-{
-    jsCast<NativeExecutable*>(cell)->clearCode();
-}
-
 const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(ScriptExecutable) };
 
 #if ENABLE(JIT)
@@ -146,8 +141,6 @@ FunctionExecutable::FunctionExecutable(JSGlobalData& globalData, const Identifie
     , m_name(name)
     , m_inferredName(inferredName.isNull() ? globalData.propertyNames->emptyIdentifier : inferredName)
     , m_symbolTable(0)
-    , m_next(0)
-    , m_prev(0)
 {
 }
 
@@ -159,8 +152,6 @@ FunctionExecutable::FunctionExecutable(ExecState* exec, const Identifier& name,
     , m_name(name)
     , m_inferredName(inferredName.isNull() ? exec->globalData().propertyNames->emptyIdentifier : inferredName)
     , m_symbolTable(0)
-    , m_next(0)
-    , m_prev(0)
 {
 }
 
@@ -292,17 +283,9 @@ void EvalExecutable::unlinkCalls()
 #endif
 }
 
-void EvalExecutable::finalize(JSCell* cell)
-{
-    jsCast<EvalExecutable*>(cell)->clearCode();
-}
-
-inline void EvalExecutable::clearCode()
+void EvalExecutable::clearCode()
 {
-    if (m_evalCodeBlock) {
-        m_evalCodeBlock->clearEvalCache();
-        m_evalCodeBlock.clear();
-    }
+    m_evalCodeBlock.clear();
     Base::clearCode();
 }
 
@@ -424,17 +407,9 @@ void ProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor)
         thisObject->m_programCodeBlock->visitAggregate(visitor);
 }
 
-void ProgramExecutable::finalize(JSCell* cell)
-{
-    jsCast<ProgramExecutable*>(cell)->clearCode();
-}
-
-inline void ProgramExecutable::clearCode()
+void ProgramExecutable::clearCode()
 {
-    if (m_programCodeBlock) {
-        m_programCodeBlock->clearEvalCache();
-        m_programCodeBlock.clear();
-    }
+    m_programCodeBlock.clear();
     Base::clearCode();
 }
 
@@ -642,37 +617,17 @@ void FunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor)
         thisObject->m_codeBlockForConstruct->visitAggregate(visitor);
 }
 
-void FunctionExecutable::discardCode()
+void FunctionExecutable::clearCodeIfNotCompiling()
 {
-#if ENABLE(JIT)
-    // These first two checks are to handle the rare case where
-    // we are trying to evict code for a function during its
-    // codegen.
-    if (!m_jitCodeForCall && m_codeBlockForCall)
-        return;
-    if (!m_jitCodeForConstruct && m_codeBlockForConstruct)
+    if (isCompiling())
         return;
-#endif
     clearCode();
 }
 
-void FunctionExecutable::finalize(JSCell* cell)
+void FunctionExecutable::clearCode()
 {
-    FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell);
-    Heap::heap(executable)->removeFunctionExecutable(executable);
-    executable->clearCode();
-}
-
-inline void FunctionExecutable::clearCode()
-{
-    if (m_codeBlockForCall) {
-        m_codeBlockForCall->clearEvalCache();
-        m_codeBlockForCall.clear();
-    }
-    if (m_codeBlockForConstruct) {
-        m_codeBlockForConstruct->clearEvalCache();
-        m_codeBlockForConstruct.clear();
-    }
+    m_codeBlockForCall.clear();
+    m_codeBlockForConstruct.clear();
     Base::clearCode();
 }
 
index e999d3a..ef545de 100644 (file)
@@ -54,7 +54,8 @@ namespace JSC {
         return false;
     }
 
-    class ExecutableBase : public JSCell {
+    class ExecutableBase : public JSCell, public DoublyLinkedListNode<ExecutableBase> {
+        friend class WTF::DoublyLinkedListNode<ExecutableBase>;
         friend class JIT;
 
     protected:
@@ -80,6 +81,11 @@ namespace JSC {
         static void destroy(JSCell*);
 #endif
 
+        bool isFunctionExecutable()
+        {
+            return structure()->typeInfo().type() == FunctionExecutableType;
+        }
+
         bool isHostFunction() const
         {
             ASSERT((m_numParametersForCall == NUM_PARAMETERS_IS_HOST) == (m_numParametersForConstruct == NUM_PARAMETERS_IS_HOST));
@@ -88,6 +94,8 @@ namespace JSC {
 
         static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(globalData, globalObject, proto, TypeInfo(CompoundType, StructureFlags), &s_info); }
         
+        void clearCode();
+
         static JS_EXPORTDATA const ClassInfo s_info;
 
     protected:
@@ -97,6 +105,8 @@ namespace JSC {
 
 #if ENABLE(JIT)
     public:
+        static void clearCodeVirtual(ExecutableBase*);
+
         JITCode& generatedJITCodeForCall()
         {
             ASSERT(m_jitCodeForCall);
@@ -168,12 +178,14 @@ namespace JSC {
         }
 
     protected:
+        ExecutableBase* m_prev;
+        ExecutableBase* m_next;
+
         JITCode m_jitCodeForCall;
         JITCode m_jitCodeForConstruct;
         MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck;
         MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck;
 #endif
-        void clearCode();
     };
 
     class NativeExecutable : public ExecutableBase {
@@ -194,7 +206,6 @@ namespace JSC {
                 executable = new (NotNull, allocateCell<NativeExecutable>(globalData.heap)) NativeExecutable(globalData, function, constructor);
                 executable->finishCreation(globalData, JITCode::HostFunction(callThunk), JITCode::HostFunction(constructThunk), intrinsic);
             }
-            globalData.heap.addFinalizer(executable, &finalize);
             return executable;
         }
 #endif
@@ -205,7 +216,6 @@ namespace JSC {
             ASSERT(!globalData.canUseJIT());
             NativeExecutable* executable = new (NotNull, allocateCell<NativeExecutable>(globalData.heap)) NativeExecutable(globalData, function, constructor);
             executable->finishCreation(globalData);
-            globalData.heap.addFinalizer(executable, &finalize);
             return executable;
         }
 #endif
@@ -246,8 +256,6 @@ namespace JSC {
         }
 #endif
 
-        static void finalize(JSCell*);
     private:
         NativeExecutable(JSGlobalData& globalData, NativeFunction function, NativeFunction constructor)
             : ExecutableBase(globalData, globalData.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST)
@@ -303,6 +311,8 @@ namespace JSC {
         void finishCreation(JSGlobalData& globalData)
         {
             Base::finishCreation(globalData);
+            globalData.heap.addCompiledCode(this); // Balanced by Heap::deleteUnmarkedCompiledCode().
+
 #if ENABLE(CODEBLOCK_SAMPLING)
             if (SamplingTool* sampler = globalData.interpreter->sampler())
                 sampler->notifyOfScope(globalData, this);
@@ -358,7 +368,6 @@ namespace JSC {
         {
             EvalExecutable* executable = new (NotNull, allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, source, isInStrictContext);
             executable->finishCreation(exec->globalData());
-            exec->globalData().heap.addFinalizer(executable, &finalize);
             return executable;
         }
 
@@ -377,9 +386,7 @@ namespace JSC {
 
         void unlinkCalls();
 
-    protected:
         void clearCode();
-        static void finalize(JSCell*);
 
     private:
         static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
@@ -400,7 +407,6 @@ namespace JSC {
         {
             ProgramExecutable* executable = new (NotNull, allocateCell<ProgramExecutable>(*exec->heap())) ProgramExecutable(exec, source);
             executable->finishCreation(exec->globalData());
-            exec->globalData().heap.addFinalizer(executable, &finalize);
             return executable;
         }
 
@@ -447,9 +453,7 @@ namespace JSC {
         
         void unlinkCalls();
 
-    protected:
         void clearCode();
-        static void finalize(JSCell*);
 
     private:
         static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
@@ -461,10 +465,9 @@ namespace JSC {
         OwnPtr<ProgramCodeBlock> m_programCodeBlock;
     };
 
-    class FunctionExecutable : public ScriptExecutable, public DoublyLinkedListNode<FunctionExecutable> {
+    class FunctionExecutable : public ScriptExecutable {
         friend class JIT;
         friend class LLIntOffsetsExtractor;
-        friend class WTF::DoublyLinkedListNode<FunctionExecutable>;
     public:
         typedef ScriptExecutable Base;
 
@@ -472,8 +475,6 @@ namespace JSC {
         {
             FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(*exec->heap())) FunctionExecutable(exec, name, inferredName, source, forceUsesArguments, parameters, isInStrictContext);
             executable->finishCreation(exec->globalData(), name, firstLine, lastLine);
-            exec->globalData().heap.addFunctionExecutable(executable);
-            exec->globalData().heap.addFinalizer(executable, &finalize);
             return executable;
         }
 
@@ -481,8 +482,6 @@ namespace JSC {
         {
             FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(globalData.heap)) FunctionExecutable(globalData, name, inferredName, source, forceUsesArguments, parameters, isInStrictContext);
             executable->finishCreation(globalData, name, firstLine, lastLine);
-            globalData.heap.addFunctionExecutable(executable);
-            globalData.heap.addFinalizer(executable, &finalize);
             return executable;
         }
 
@@ -639,7 +638,7 @@ namespace JSC {
         UString paramString() const;
         SharedSymbolTable* symbolTable() const { return m_symbolTable; }
 
-        void discardCode();
+        void clearCodeIfNotCompiling();
         static void visitChildren(JSCell*, SlotVisitor&);
         static FunctionExecutable* fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, JSObject** exception);
         static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
@@ -651,10 +650,9 @@ namespace JSC {
         
         void unlinkCalls();
 
-    protected:
         void clearCode();
-        static void finalize(JSCell*);
 
+    protected:
         void finishCreation(JSGlobalData& globalData, const Identifier& name, int firstLine, int lastLine)
         {
             Base::finishCreation(globalData);
@@ -677,7 +675,18 @@ namespace JSC {
             ASSERT(kind == CodeForConstruct);
             return m_codeBlockForConstruct;
         }
-        
+        bool isCompiling()
+        {
+#if ENABLE(JIT)
+            if (!m_jitCodeForCall && m_codeBlockForCall)
+                return true;
+            if (!m_jitCodeForConstruct && m_codeBlockForConstruct)
+                return true;
+#endif
+            return false;
+        }
+
         static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
         unsigned m_numCapturedVariables : 31;
         bool m_forceUsesArguments : 1;
@@ -689,8 +698,6 @@ namespace JSC {
         Identifier m_inferredName;
         WriteBarrier<JSString> m_nameValue;
         SharedSymbolTable* m_symbolTable;
-        FunctionExecutable* m_next;
-        FunctionExecutable* m_prev;
     };
 
     inline FunctionExecutable* JSFunction::jsExecutable() const
@@ -725,6 +732,20 @@ namespace JSC {
         return function->nativeFunction() == nativeFunction;
     }
 
+    inline void ExecutableBase::clearCodeVirtual(ExecutableBase* executable)
+    {
+        switch (executable->structure()->typeInfo().type()) {
+        case EvalExecutableType:
+            return jsCast<EvalExecutable*>(executable)->clearCode();
+        case ProgramExecutableType:
+            return jsCast<ProgramExecutable*>(executable)->clearCode();
+        case FunctionExecutableType:
+            return jsCast<FunctionExecutable*>(executable)->clearCode();
+        default:
+            return jsCast<NativeExecutable*>(executable)->clearCode();
+        }
+    }
+
     inline void ScriptExecutable::unlinkCalls()
     {
         switch (structure()->typeInfo().type()) {
index 3aa1257..f9da3d3 100644 (file)
@@ -419,7 +419,7 @@ struct StackPreservingRecompiler : public MarkedBlock::VoidFunctor {
         FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell);
         if (currentlyExecutingFunctions.contains(executable))
             return;
-        executable->discardCode();
+        executable->clearCodeIfNotCompiling();
     }
 };
 
index b0e460f..7b61095 100644 (file)
@@ -443,7 +443,7 @@ DynamicGlobalObjectScope::DynamicGlobalObjectScope(JSGlobalData& globalData, JSG
     if (!m_dynamicGlobalObjectSlot) {
 #if ENABLE(ASSEMBLER)
         if (ExecutableAllocator::underMemoryPressure())
-            globalData.heap.discardAllCompiledCode();
+            globalData.heap.deleteAllCompiledCode();
 #endif
 
         m_dynamicGlobalObjectSlot = dynamicGlobalObject;