GC should safepoint the DFG worklist in a smarter way rather than just waiting for...
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 8 Feb 2014 05:06:33 +0000 (05:06 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 8 Feb 2014 05:06:33 +0000 (05:06 +0000)
https://bugs.webkit.org/show_bug.cgi?id=128297

Reviewed by Oliver Hunt.

This makes DFG worklist threads have a rightToRun lock that gives them the ability to
be safepointed by the GC in much the same way as you'd expect from a fully
multithreaded VM.

The idea is that the worklist threads's roots are the DFG::Plan. They only touch those
roots when holding the rightToRun lock. They currently grab that lock to run the
compiler, but relinquish it when accessing - and waiting on - the worklist.

* bytecode/CodeBlock.h:
(JSC::CodeBlockSet::mark):
* dfg/DFGCompilationKey.cpp:
(JSC::DFG::CompilationKey::visitChildren):
* dfg/DFGCompilationKey.h:
* dfg/DFGDesiredStructureChains.cpp:
(JSC::DFG::DesiredStructureChains::visitChildren):
* dfg/DFGDesiredStructureChains.h:
* dfg/DFGDesiredTransitions.cpp:
(JSC::DFG::DesiredTransition::visitChildren):
(JSC::DFG::DesiredTransitions::visitChildren):
* dfg/DFGDesiredTransitions.h:
* dfg/DFGDesiredWeakReferences.cpp:
(JSC::DFG::DesiredWeakReferences::visitChildren):
* dfg/DFGDesiredWeakReferences.h:
* dfg/DFGDesiredWriteBarriers.cpp:
(JSC::DFG::DesiredWriteBarrier::visitChildren):
(JSC::DFG::DesiredWriteBarriers::visitChildren):
* dfg/DFGDesiredWriteBarriers.h:
* dfg/DFGPlan.cpp:
(JSC::DFG::Plan::visitChildren):
* dfg/DFGPlan.h:
* dfg/DFGWorklist.cpp:
(JSC::DFG::Worklist::~Worklist):
(JSC::DFG::Worklist::finishCreation):
(JSC::DFG::Worklist::suspendAllThreads):
(JSC::DFG::Worklist::resumeAllThreads):
(JSC::DFG::Worklist::visitChildren):
(JSC::DFG::Worklist::runThread):
(JSC::DFG::Worklist::threadFunction):
* dfg/DFGWorklist.h:
(JSC::DFG::numberOfWorklists):
(JSC::DFG::worklistForIndexOrNull):
* heap/CodeBlockSet.h:
* heap/Heap.cpp:
(JSC::Heap::markRoots):
(JSC::Heap::collect):
* runtime/IntendedStructureChain.cpp:
(JSC::IntendedStructureChain::visitChildren):
* runtime/IntendedStructureChain.h:
* runtime/VM.cpp:
(JSC::VM::~VM):
(JSC::VM::prepareToDiscardCode):

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

21 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/dfg/DFGCompilationKey.cpp
Source/JavaScriptCore/dfg/DFGCompilationKey.h
Source/JavaScriptCore/dfg/DFGDesiredStructureChains.cpp
Source/JavaScriptCore/dfg/DFGDesiredStructureChains.h
Source/JavaScriptCore/dfg/DFGDesiredTransitions.cpp
Source/JavaScriptCore/dfg/DFGDesiredTransitions.h
Source/JavaScriptCore/dfg/DFGDesiredWeakReferences.cpp
Source/JavaScriptCore/dfg/DFGDesiredWeakReferences.h
Source/JavaScriptCore/dfg/DFGDesiredWriteBarriers.cpp
Source/JavaScriptCore/dfg/DFGDesiredWriteBarriers.h
Source/JavaScriptCore/dfg/DFGPlan.cpp
Source/JavaScriptCore/dfg/DFGPlan.h
Source/JavaScriptCore/dfg/DFGWorklist.cpp
Source/JavaScriptCore/dfg/DFGWorklist.h
Source/JavaScriptCore/heap/CodeBlockSet.h
Source/JavaScriptCore/heap/Heap.cpp
Source/JavaScriptCore/runtime/IntendedStructureChain.cpp
Source/JavaScriptCore/runtime/IntendedStructureChain.h
Source/JavaScriptCore/runtime/VM.cpp

index 77635da54424da03ba48a8547dd7c518438834c8..66dbbed3cf0c8b2006c7723ed0633bb78d930f10 100644 (file)
@@ -1,3 +1,62 @@
+2014-02-07  Filip Pizlo  <fpizlo@apple.com>
+
+        GC should safepoint the DFG worklist in a smarter way rather than just waiting for everything to complete
+        https://bugs.webkit.org/show_bug.cgi?id=128297
+
+        Reviewed by Oliver Hunt.
+        
+        This makes DFG worklist threads have a rightToRun lock that gives them the ability to
+        be safepointed by the GC in much the same way as you'd expect from a fully
+        multithreaded VM.
+        
+        The idea is that the worklist threads's roots are the DFG::Plan. They only touch those
+        roots when holding the rightToRun lock. They currently grab that lock to run the
+        compiler, but relinquish it when accessing - and waiting on - the worklist.
+
+        * bytecode/CodeBlock.h:
+        (JSC::CodeBlockSet::mark):
+        * dfg/DFGCompilationKey.cpp:
+        (JSC::DFG::CompilationKey::visitChildren):
+        * dfg/DFGCompilationKey.h:
+        * dfg/DFGDesiredStructureChains.cpp:
+        (JSC::DFG::DesiredStructureChains::visitChildren):
+        * dfg/DFGDesiredStructureChains.h:
+        * dfg/DFGDesiredTransitions.cpp:
+        (JSC::DFG::DesiredTransition::visitChildren):
+        (JSC::DFG::DesiredTransitions::visitChildren):
+        * dfg/DFGDesiredTransitions.h:
+        * dfg/DFGDesiredWeakReferences.cpp:
+        (JSC::DFG::DesiredWeakReferences::visitChildren):
+        * dfg/DFGDesiredWeakReferences.h:
+        * dfg/DFGDesiredWriteBarriers.cpp:
+        (JSC::DFG::DesiredWriteBarrier::visitChildren):
+        (JSC::DFG::DesiredWriteBarriers::visitChildren):
+        * dfg/DFGDesiredWriteBarriers.h:
+        * dfg/DFGPlan.cpp:
+        (JSC::DFG::Plan::visitChildren):
+        * dfg/DFGPlan.h:
+        * dfg/DFGWorklist.cpp:
+        (JSC::DFG::Worklist::~Worklist):
+        (JSC::DFG::Worklist::finishCreation):
+        (JSC::DFG::Worklist::suspendAllThreads):
+        (JSC::DFG::Worklist::resumeAllThreads):
+        (JSC::DFG::Worklist::visitChildren):
+        (JSC::DFG::Worklist::runThread):
+        (JSC::DFG::Worklist::threadFunction):
+        * dfg/DFGWorklist.h:
+        (JSC::DFG::numberOfWorklists):
+        (JSC::DFG::worklistForIndexOrNull):
+        * heap/CodeBlockSet.h:
+        * heap/Heap.cpp:
+        (JSC::Heap::markRoots):
+        (JSC::Heap::collect):
+        * runtime/IntendedStructureChain.cpp:
+        (JSC::IntendedStructureChain::visitChildren):
+        * runtime/IntendedStructureChain.h:
+        * runtime/VM.cpp:
+        (JSC::VM::~VM):
+        (JSC::VM::prepareToDiscardCode):
+
 2014-02-07  Mark Lam  <mark.lam@apple.com>
 
         Unify JSLock implementation for iOS and non-iOS ports.
index 54f3de0720558e78a79d373c156add3748c731e2..66fdcd01f6a75343f1a76470450d7982459892a9 100644 (file)
@@ -894,7 +894,7 @@ public:
     void setSteppingMode(SteppingMode);
 
     void clearDebuggerRequests() { m_debuggerRequests = 0; }
-
+    
     // FIXME: Make these remaining members private.
 
     int m_numCalleeRegisters;
@@ -1273,9 +1273,20 @@ inline void CodeBlockSet::mark(void* candidateCodeBlock)
     if (iter == m_set.end())
         return;
     
-    (*iter)->m_mayBeExecuting = true;
+    mark(*iter);
+}
+
+inline void CodeBlockSet::mark(CodeBlock* codeBlock)
+{
+    if (!codeBlock)
+        return;
+    
+    if (codeBlock->m_mayBeExecuting)
+        return;
+    
+    codeBlock->m_mayBeExecuting = true;
 #if ENABLE(GGC)
-    m_currentlyExecuting.append(static_cast<CodeBlock*>(candidateCodeBlock));
+    m_currentlyExecuting.append(codeBlock);
 #endif
 }
 
index d31ac9e2d58ad5fd26c9c27d56d5d28484d5dcf8..f22fdf37fec976b7b8bebb80e179b34ae0f7ed46 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,6 +27,7 @@
 #include "DFGCompilationKey.h"
 
 #include "CodeBlock.h"
+#include "CodeBlockSet.h"
 
 #if ENABLE(DFG_JIT)
 
@@ -41,6 +42,11 @@ void CompilationKey::dump(PrintStream& out) const
     out.print("(Compile of ", *m_profiledBlock, " with ", m_mode, ")");
 }
 
+void CompilationKey::visitChildren(CodeBlockSet& codeBlocks)
+{
+    codeBlocks.mark(m_profiledBlock);
+}
+
 } } // namespace JSC::DFG
 
 
index a866acdf17097f44419a6dca47395e9c71cee71e..fb7461d9c21ce62e95b2490f9b2a727e506c8d8e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -32,6 +32,7 @@
 namespace JSC {
 
 class CodeBlock;
+class CodeBlockSet;
 
 namespace DFG {
 
@@ -79,6 +80,8 @@ public:
         return WTF::pairIntHash(WTF::PtrHash<CodeBlock*>::hash(m_profiledBlock), m_mode);
     }
     
+    void visitChildren(CodeBlockSet&);
+    
     void dump(PrintStream&) const;
 
 private:
index 04bd5f01f07ce32b69028bbe78302515ad3da2c2..cd8a3222eed4f00664af7778421d8f3b82def99e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -42,6 +42,12 @@ bool DesiredStructureChains::areStillValid() const
     return true;
 }
 
+void DesiredStructureChains::visitChildren(SlotVisitor& visitor)
+{
+    for (unsigned i = m_vector.size(); i--;)
+        m_vector[i]->visitChildren(visitor);
+}
+
 } } // namespace JSC::DFG
 
 #endif // ENABLE(DFG_JIT)
index 3c20194d7f18fd530f3bd54b0562a06b4f640d4a..f74add604b41cf7ba898eaf89171e4ce55dcfcd6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -46,6 +46,9 @@ public:
     }
     
     bool areStillValid() const;
+    
+    void visitChildren(SlotVisitor&);
+    
 private:
     Vector<RefPtr<IntendedStructureChain>> m_vector;
 };
index 0cfa00f6f9ddd8558b0196fe702521712cea831d..0f77659a0de233d0c9f30c2aea7228cfa9a5add2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -51,6 +51,13 @@ void DesiredTransition::reallyAdd(VM& vm, CommonData* common)
             m_oldStructure, m_newStructure));
 }
 
+void DesiredTransition::visitChildren(SlotVisitor& visitor)
+{
+    visitor.appendUnbarrieredPointer(&m_codeOriginOwner);
+    visitor.appendUnbarrieredPointer(&m_oldStructure);
+    visitor.appendUnbarrieredPointer(&m_newStructure);
+}
+
 DesiredTransitions::DesiredTransitions()
 {
 }
@@ -70,6 +77,12 @@ void DesiredTransitions::reallyAdd(VM& vm, CommonData* common)
         m_transitions[i].reallyAdd(vm, common);
 }
 
+void DesiredTransitions::visitChildren(SlotVisitor& visitor)
+{
+    for (unsigned i = 0; i < m_transitions.size(); i++)
+        m_transitions[i].visitChildren(visitor);
+}
+
 } } // namespace JSC::DFG
 
 #endif // ENABLE(DFG_JIT)
index 246a81062b0c91ad6e83875f75a6a30062560921..addaf3ecdc008752f1466f57ad8df1fba8a2f93e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -34,6 +34,7 @@ namespace JSC {
 
 class CodeBlock;
 class ScriptExecutable;
+class SlotVisitor;
 class Structure;
 class VM;
 
@@ -46,6 +47,8 @@ public:
     DesiredTransition(CodeBlock*, ScriptExecutable*, Structure*, Structure*);
 
     void reallyAdd(VM&, CommonData*);
+    
+    void visitChildren(SlotVisitor&);
 
 private:
     CodeBlock* m_codeBlock;
@@ -61,6 +64,7 @@ public:
 
     void addLazily(CodeBlock*, ScriptExecutable*, Structure*, Structure*);
     void reallyAdd(VM&, CommonData*);
+    void visitChildren(SlotVisitor&);
 
 private:
     Vector<DesiredTransition> m_transitions;
index a8376ea8a749e45e668497531f59a4ff0baacd2a..5b1485f649fc2c4a32efc5d0cd57edea626f40e0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -31,6 +31,7 @@
 
 #include "CodeBlock.h"
 #include "DFGCommonData.h"
+#include "Operations.h"
 
 namespace JSC { namespace DFG {
 
@@ -56,6 +57,12 @@ void DesiredWeakReferences::reallyAdd(VM& vm, CommonData* common)
     }
 }
 
+void DesiredWeakReferences::visitChildren(SlotVisitor& visitor)
+{
+    for (unsigned i = m_references.size(); i--;)
+        visitor.appendUnbarrieredPointer(&m_references[i]);
+}
+
 } } // namespace JSC::DFG
 
 #endif // ENABLE(DFG_JIT)
index 981e752eaab1c5bc9e150491dfd971f428a1964a..7b3198c4f01fb364dca8c8ea724f0d634b2f560f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -34,6 +34,7 @@ namespace JSC {
 
 class CodeBlock;
 class JSCell;
+class SlotVisitor;
 class VM;
 
 namespace DFG {
@@ -47,6 +48,8 @@ public:
 
     void addLazily(JSCell*);
     void reallyAdd(VM&, CommonData*);
+    
+    void visitChildren(SlotVisitor&);
 
 private:
     CodeBlock* m_codeBlock;
index bf1a24375e02d2c676ef78ae5fb09d475405b15f..ddb81f783358ea4708e51ca699fa32a1f2f1599b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -30,7 +30,7 @@
 #include "DFGDesiredWriteBarriers.h"
 
 #include "CodeBlock.h"
-#include "JSCJSValueInlines.h"
+#include "Operations.h"
 
 namespace JSC { namespace DFG {
 
@@ -68,6 +68,24 @@ void DesiredWriteBarrier::trigger(VM& vm)
     RELEASE_ASSERT_NOT_REACHED();
 }
 
+void DesiredWriteBarrier::visitChildren(SlotVisitor& visitor)
+{
+    switch (m_type) {
+    case ConstantType: {
+        WriteBarrier<Unknown>& barrier = m_codeBlock->constants()[m_which.index];
+        visitor.append(&barrier);
+        return;
+    }
+        
+    case InlineCallFrameExecutableType: {
+        InlineCallFrame* inlineCallFrame = m_which.inlineCallFrame;
+        WriteBarrier<ScriptExecutable>& executable = inlineCallFrame->executable;
+        visitor.append(&executable);
+        return;
+    } }
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
 DesiredWriteBarriers::DesiredWriteBarriers()
 {
 }
@@ -82,6 +100,12 @@ void DesiredWriteBarriers::trigger(VM& vm)
         m_barriers[i].trigger(vm);
 }
 
+void DesiredWriteBarriers::visitChildren(SlotVisitor& visitor)
+{
+    for (unsigned i = 0; i < m_barriers.size(); i++)
+        m_barriers[i].visitChildren(visitor);
+}
+
 } } // namespace JSC::DFG
 
 #endif // ENABLE(DFG_JIT)
index cbbb2cb5edc2a1112c449d449aa9bc00f37ceeca..a74d0b8a77904e20d6f8b73aeb1d4a7dbe751a78 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -35,6 +35,7 @@ namespace JSC {
 
 class JSFunction;
 class ScriptExecutable;
+class SlotVisitor;
 class VM;
 struct InlineCallFrame;
 
@@ -50,6 +51,8 @@ public:
     DesiredWriteBarrier(Type, CodeBlock*, InlineCallFrame*, JSCell* owner);
 
     void trigger(VM&);
+    
+    void visitChildren(SlotVisitor&);
 
 private:
     JSCell* m_owner;
@@ -78,6 +81,8 @@ public:
     }
 
     void trigger(VM&);
+    
+    void visitChildren(SlotVisitor&);
 
 private:
     Vector<DesiredWriteBarrier> m_barriers;
index 5c8bb1e03468974b93529aed4ab12cdb715eb378..99d30a9ba2938e03bb3353a982a9de0a8bd11b63 100644 (file)
@@ -404,6 +404,20 @@ CompilationKey Plan::key()
     return CompilationKey(codeBlock->alternative(), mode);
 }
 
+void Plan::visitChildren(SlotVisitor& visitor, CodeBlockSet& codeBlocks)
+{
+    for (unsigned i = mustHandleValues.size(); i--;)
+        visitor.appendUnbarrieredValue(&mustHandleValues[i]);
+    
+    codeBlocks.mark(codeBlock.get());
+    codeBlocks.mark(profiledDFGCodeBlock.get());
+    
+    chains.visitChildren(visitor);
+    weakReferences.visitChildren(visitor);
+    writeBarriers.visitChildren(visitor);
+    transitions.visitChildren(visitor);
+}
+
 } } // namespace JSC::DFG
 
 #endif // ENABLE(DFG_JIT)
index 1f6bce0c417b153287984935fdbf958c879b4a82..8515f9639e1ab206144b9b8116edab41a91e62e8 100644 (file)
@@ -46,6 +46,8 @@
 namespace JSC {
 
 class CodeBlock;
+class CodeBlockSet;
+class SlotVisitor;
 
 namespace DFG {
 
@@ -69,6 +71,8 @@ struct Plan : public ThreadSafeRefCounted<Plan> {
     
     CompilationKey key();
     
+    void visitChildren(SlotVisitor&, CodeBlockSet&);
+    
     VM& vm;
     RefPtr<CodeBlock> codeBlock;
     RefPtr<CodeBlock> profiledDFGCodeBlock;
index a36eb3836c948a42f163a88768228fd224fe2566..67c65b9660215b40ad563645fd143bf408135685 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -49,15 +49,19 @@ Worklist::~Worklist()
         m_planEnqueued.broadcast();
     }
     for (unsigned i = m_threads.size(); i--;)
-        waitForThreadCompletion(m_threads[i]);
+        waitForThreadCompletion(m_threads[i]->m_identifier);
     ASSERT(!m_numberOfActiveThreads);
 }
 
 void Worklist::finishCreation(unsigned numberOfThreads)
 {
     RELEASE_ASSERT(numberOfThreads);
-    for (unsigned i = numberOfThreads; i--;)
-        m_threads.append(createThread(threadFunction, this, "JSC Compilation Thread"));
+    for (unsigned i = numberOfThreads; i--;) {
+        std::unique_ptr<ThreadData> data = std::make_unique<ThreadData>();
+        data->m_worklist = this;
+        data->m_identifier = createThread(threadFunction, data.get(), "JSC Compilation Thread");
+        m_threads.append(std::move(data));
+    }
 }
 
 PassRefPtr<Worklist> Worklist::create(unsigned numberOfThreads)
@@ -188,6 +192,26 @@ void Worklist::completeAllPlansForVM(VM& vm)
     completeAllReadyPlansForVM(vm);
 }
 
+void Worklist::suspendAllThreads()
+{
+    for (unsigned i = m_threads.size(); i--;)
+        m_threads[i]->m_rightToRun.lock();
+}
+
+void Worklist::resumeAllThreads()
+{
+    for (unsigned i = m_threads.size(); i--;)
+        m_threads[i]->m_rightToRun.unlock();
+}
+
+void Worklist::visitChildren(SlotVisitor& visitor, CodeBlockSet& codeBlocks)
+{
+    for (PlanMap::iterator iter = m_plans.begin(); iter != m_plans.end(); ++iter) {
+        iter->key.visitChildren(codeBlocks);
+        iter->value->visitChildren(visitor, codeBlocks);
+    }
+}
+
 size_t Worklist::queueLength()
 {
     MutexLocker locker(m_lock);
@@ -208,7 +232,7 @@ void Worklist::dump(const MutexLocker&, PrintStream& out) const
         ", Num Active Threads = ", m_numberOfActiveThreads, "/", m_threads.size(), "]");
 }
 
-void Worklist::runThread()
+void Worklist::runThread(ThreadData* data)
 {
     CompilationScope compilationScope;
     
@@ -223,6 +247,7 @@ void Worklist::runThread()
             MutexLocker locker(m_lock);
             while (m_queue.isEmpty())
                 m_planEnqueued.wait(m_lock);
+            
             plan = m_queue.takeFirst();
             if (plan)
                 m_numberOfActiveThreads++;
@@ -234,10 +259,14 @@ void Worklist::runThread()
             return;
         }
         
-        if (Options::verboseCompilationQueue())
-            dataLog(*this, ": Compiling ", plan->key(), " asynchronously\n");
+        {
+            MutexLocker locker(data->m_rightToRun);
+        
+            if (Options::verboseCompilationQueue())
+                dataLog(*this, ": Compiling ", plan->key(), " asynchronously\n");
         
-        plan->compileInThread(longLivedState);
+            plan->compileInThread(longLivedState);
+        }
         
         {
             MutexLocker locker(m_lock);
@@ -258,7 +287,8 @@ void Worklist::runThread()
 
 void Worklist::threadFunction(void* argument)
 {
-    static_cast<Worklist*>(argument)->runThread();
+    ThreadData* data = static_cast<ThreadData*>(argument);
+    data->m_worklist->runThread(data);
 }
 
 static Worklist* theGlobalDFGWorklist;
index 25a3168e09ce2fd889d1f609dd6682946209cbb4..eecfe1682973116fb521753237f73dc97abff713 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include <wtf/PassOwnPtr.h>
 #include <wtf/ThreadingPrimitives.h>
 
-namespace JSC { namespace DFG {
+namespace JSC {
+
+class CodeBlockSet;
+class SlotVisitor;
+
+namespace DFG {
 
 class Worklist : public RefCounted<Worklist> {
 public:
@@ -61,13 +66,25 @@ public:
     State compilationState(CompilationKey);
     
     size_t queueLength();
+    
+    void suspendAllThreads();
+    void resumeAllThreads();
+    
+    void visitChildren(SlotVisitor&, CodeBlockSet&); // Only called on the main thread after suspending all threads.
+    
     void dump(PrintStream&) const;
     
 private:
+    struct ThreadData {
+        Worklist* m_worklist;
+        ThreadIdentifier m_identifier;
+        Mutex m_rightToRun;
+    };
+    
     Worklist();
     void finishCreation(unsigned numberOfThreads);
     
-    void runThread();
+    void runThread(ThreadData*);
     static void threadFunction(void* argument);
     
     void removeAllReadyPlansForVM(VM&, Vector<RefPtr<Plan>, 8>&);
@@ -91,7 +108,8 @@ private:
     mutable Mutex m_lock;
     ThreadCondition m_planEnqueued;
     ThreadCondition m_planCompiled;
-    Vector<ThreadIdentifier> m_threads;
+    
+    Vector<std::unique_ptr<ThreadData>> m_threads;
     unsigned m_numberOfActiveThreads;
 };
 
@@ -105,6 +123,21 @@ Worklist* existingGlobalFTLWorklistOrNull();
 
 Worklist* ensureGlobalWorklistFor(CompilationMode);
 
+// Simplify doing things for all worklists.
+inline unsigned numberOfWorklists() { return 2; }
+inline Worklist* worklistForIndexOrNull(unsigned index)
+{
+    switch (index) {
+    case 0:
+        return existingGlobalDFGWorklistOrNull();
+    case 1:
+        return existingGlobalFTLWorklistOrNull();
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+        return 0;
+    }
+}
+
 } } // namespace JSC::DFG
 
 #endif // ENABLE(DFG_JIT)
index 6b173f98b198689cf407567e67f7ff746461af76..b529d4bdd3e9fec69405c397c1c5e18df939a756 100644 (file)
@@ -58,6 +58,7 @@ public:
     
     // Mark a pointer that may be a CodeBlock that belongs to the set of DFG
     // blocks. This is defined in CodeBlock.h.
+    void mark(CodeBlock* candidateCodeBlock);
     void mark(void* candidateCodeBlock);
     
     // Delete all code blocks that are only referenced by this set (i.e. owned
index c20b0617993018f9d312ffae73fc75e9ccf1c579..16b504a50bfc2d81965de3d6da69069d48d35e7d 100644 (file)
@@ -524,6 +524,14 @@ void Heap::markRoots()
             visitor.append(scratchBufferRoots);
             visitor.donateAndDrain();
         }
+        {
+            GCPHASE(VisitDFGWorklists);
+            MARK_LOG_ROOT(visitor, "DFG Worklists");
+            for (unsigned i = DFG::numberOfWorklists(); i--;) {
+                if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i))
+                    worklist->visitChildren(visitor, m_codeBlocks);
+            }
+        }
 #endif
         {
             GCPHASE(VisitProtectedObjects);
@@ -801,10 +809,12 @@ void Heap::collect()
     JAVASCRIPTCORE_GC_BEGIN();
     RELEASE_ASSERT(m_operationInProgress == NoOperation);
     
-    {
-        RecursiveAllocationScope scope(*this);
-        m_vm->prepareToDiscardCode();
+#if ENABLE(DFG_JIT)
+    for (unsigned i = DFG::numberOfWorklists(); i--;) {
+        if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i))
+            worklist->suspendAllThreads();
     }
+#endif
 
     bool isFullCollection = m_shouldDoFullCollection;
     if (isFullCollection) {
@@ -950,6 +960,13 @@ void Heap::collect()
     if (Options::showObjectStatistics())
         HeapStatistics::showObjectStatistics(this);
     
+#if ENABLE(DFG_JIT)
+    for (unsigned i = DFG::numberOfWorklists(); i--;) {
+        if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i))
+            worklist->resumeAllThreads();
+    }
+#endif
+
     if (Options::logGC()) {
         double after = currentTimeMS();
         dataLog(after - before, " ms, ", currentHeapSize / 1024, " kb]\n");
index b38dae9f8485559685ff6cd9ca93cf2081f00179..2b10fc96ca396c7c961647d7aa74357d9d68633c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -137,5 +137,13 @@ JSObject* IntendedStructureChain::terminalPrototype() const
     return asObject(m_vector[m_vector.size() - 2]->storedPrototype());
 }
 
+void IntendedStructureChain::visitChildren(SlotVisitor& visitor)
+{
+    visitor.appendUnbarrieredPointer(&m_globalObject);
+    visitor.appendUnbarrieredPointer(&m_head);
+    for (unsigned i = m_vector.size(); i--;)
+        visitor.appendUnbarrieredPointer(&m_vector[i]);
+}
+
 } // namespace JSC
 
index 40af95c65a4ad71b8d2a546d253e34e44f82ec32..74c1e676d8220a82fcbf3b8fd5a06b2eb48f54c4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -59,6 +59,9 @@ public:
     JSObject* terminalPrototype() const;
     
     Structure* last() const { return m_vector.last(); }
+    
+    void visitChildren(SlotVisitor&);
+    
 private:
     JSGlobalObject* m_globalObject;
     Structure* m_head;
index 0b9c8be927dffbfee0d52dc5c06557f412687c5f..c6d63194a66306f54124f0fc3b9fb134cd51661a 100644 (file)
@@ -316,16 +316,6 @@ VM::VM(VMType vmType, HeapType heapType)
     m_typedArrayController = adoptRef(new SimpleTypedArrayController());
 }
 
-#if ENABLE(DFG_JIT)
-static void cleanWorklist(VM& vm, DFG::Worklist* worklist)
-{
-    if (!worklist)
-        return;
-    worklist->waitUntilAllPlansForVMAreReady(vm);
-    worklist->removeAllReadyPlansForVM(vm);
-}
-#endif // ENABLE(DFG_JIT)
-
 VM::~VM()
 {
     // Never GC, ever again.
@@ -334,8 +324,12 @@ VM::~VM()
 #if ENABLE(DFG_JIT)
     // Make sure concurrent compilations are done, but don't install them, since there is
     // no point to doing so.
-    cleanWorklist(*this, DFG::existingGlobalDFGWorklistOrNull());
-    cleanWorklist(*this, DFG::existingGlobalFTLWorklistOrNull());
+    for (unsigned i = DFG::numberOfWorklists(); i--;) {
+        if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i)) {
+            worklist->waitUntilAllPlansForVMAreReady(*this);
+            worklist->removeAllReadyPlansForVM(*this);
+        }
+    }
 #endif // ENABLE(DFG_JIT)
     
     // Clear this first to ensure that nobody tries to remove themselves from it.
@@ -508,20 +502,13 @@ void VM::stopSampling()
     interpreter->stopSampling();
 }
 
-#if ENABLE(DFG_JIT)
-static void prepareToDiscardCodeFor(VM& vm, DFG::Worklist* worklist)
-{
-    if (!worklist)
-        return;
-    worklist->completeAllPlansForVM(vm);
-}
-#endif // ENABLE(DFG_JIT)
-
 void VM::prepareToDiscardCode()
 {
 #if ENABLE(DFG_JIT)
-    prepareToDiscardCodeFor(*this, DFG::existingGlobalDFGWorklistOrNull());
-    prepareToDiscardCodeFor(*this, DFG::existingGlobalFTLWorklistOrNull());
+    for (unsigned i = DFG::numberOfWorklists(); i--;) {
+        if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i))
+            worklist->completeAllPlansForVM(*this);
+    }
 #endif // ENABLE(DFG_JIT)
 }