DFG should not reparse code that was just parsed
https://bugs.webkit.org/show_bug.cgi?id=71977

Reviewed by Geoff Garen.
        
The instruction stream of a code block is now kept around until
the next GC. When doing either an optimizing compilation of an
executable, or inlining of an executable, we now try to find the
already preexisting bytecode. If we find it, we don't have to parse.
If we don't find it, we parse as before. Inlining takes the extra
step of caching code blocks, so if the same executable gets inlined
multiple times into the same caller, then we parse it at most once
even if prior to inlining that executable did not have any code
blocks with an instruction stream.
        
Also fixed a silly bug where the strict mode for various operations
was being determined by looking at the machine code block rather
than the inlinee.

To enable the delete-on-next-GC policy, I introduced the notion
of an ultra weak finalizer, which anyone can register during
tracing. This is thread-safe (for parallel GC) and
stop-the-world-safe (so calls to free() are postponed until the
world is resumed). This required reusing some facilities previously
created for WeakReferenceHarvester, so I created a common utility
class. I also retweaked the handling of WeakReferenceHarvesters,
since they should be executed during stop-the-world since in the
future we may want to allow them to call drain().
        
2% win on SunSpider. 2% win on V8, when run in my harness. Neutral
elsewhere.

* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::visitAggregate):
(JSC::CodeBlock::copyPostParseDataFrom):
(JSC::CodeBlock::copyPostParseDataFromAlternative):
(JSC::CodeBlock::finalizeUnconditionally):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::canProduceCopyWithBytecode):
(JSC::CodeBlock::discardBytecodeLater):
(JSC::CodeBlock::handleBytecodeDiscardingOpportunity):
(JSC::GlobalCodeBlock::GlobalCodeBlock):
(JSC::ProgramCodeBlock::ProgramCodeBlock):
(JSC::EvalCodeBlock::EvalCodeBlock):
(JSC::FunctionCodeBlock::FunctionCodeBlock):
(JSC::BytecodeDestructionBlocker::BytecodeDestructionBlocker):
(JSC::BytecodeDestructionBlocker::~BytecodeDestructionBlocker):
* dfg/DFGAssemblyHelpers.h:
(JSC::DFG::AssemblyHelpers::strictModeFor):
* dfg/DFGByteCodeCache.h: Added.
(JSC::DFG::CodeBlockKey::CodeBlockKey):
(JSC::DFG::CodeBlockKey::operator==):
(JSC::DFG::CodeBlockKey::hash):
(JSC::DFG::CodeBlockKey::executable):
(JSC::DFG::CodeBlockKey::kind):
(JSC::DFG::CodeBlockKey::isHashTableDeletedValue):
(JSC::DFG::CodeBlockKeyHash::hash):
(JSC::DFG::CodeBlockKeyHash::equal):
(JSC::DFG::ByteCodeCache::ByteCodeCache):
(JSC::DFG::ByteCodeCache::~ByteCodeCache):
(JSC::DFG::ByteCodeCache::get):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleInlining):
* dfg/DFGJITCodeGenerator32_64.cpp:
(JSC::DFG::JITCodeGenerator::cachedPutById):
* dfg/DFGJITCodeGenerator64.cpp:
(JSC::DFG::JITCodeGenerator::cachedPutById):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* heap/Heap.cpp:
(JSC::Heap::finalizeUnconditionally):
(JSC::Heap::markRoots):
(JSC::Heap::collect):
* heap/Heap.h:
* heap/ListableHandler.h: Added.
(JSC::ListableHandler::ListableHandler):
(JSC::ListableHandler::~ListableHandler):
(JSC::ListableHandler::List::List):
(JSC::ListableHandler::List::addNotThreadSafe):
(JSC::ListableHandler::List::addThreadSafe):
(JSC::ListableHandler::List::hasNext):
(JSC::ListableHandler::List::removeNext):
* heap/MarkStack.cpp:
(JSC::MarkStackThreadSharedData::MarkStackThreadSharedData):
(JSC::SlotVisitor::harvestWeakReferences):
(JSC::SlotVisitor::finalizeUnconditionally):
* heap/MarkStack.h:
(JSC::MarkStack::addWeakReferenceHarvester):
(JSC::MarkStack::addUnconditionalFinalizer):
* heap/SlotVisitor.h:
* heap/UnconditionalFinalizer.h: Added.
(JSC::UnconditionalFinalizer::~UnconditionalFinalizer):
* heap/WeakReferenceHarvester.h:
(JSC::WeakReferenceHarvester::WeakReferenceHarvester):
(JSC::WeakReferenceHarvester::~WeakReferenceHarvester):
* runtime/Executable.cpp:
(JSC::EvalExecutable::compileInternal):
(JSC::ProgramExecutable::compileInternal):
(JSC::FunctionExecutable::baselineCodeBlockFor):
(JSC::FunctionExecutable::codeBlockWithBytecodeFor):
(JSC::FunctionExecutable::produceCodeBlockFor):
(JSC::FunctionExecutable::compileForCallInternal):
(JSC::FunctionExecutable::compileForConstructInternal):
* runtime/Executable.h:
(JSC::FunctionExecutable::profiledCodeBlockFor):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@99898 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/heap/Heap.cpp b/Source/JavaScriptCore/heap/Heap.cpp
index e838495..294fa95 100644
--- a/Source/JavaScriptCore/heap/Heap.cpp
+++ b/Source/JavaScriptCore/heap/Heap.cpp
@@ -530,6 +530,11 @@
     m_slotVisitor.harvestWeakReferences();
 }
 
+void Heap::finalizeUnconditionalFinalizers()
+{
+    m_slotVisitor.finalizeUnconditionalFinalizers();
+}
+
 inline RegisterFile& Heap::registerFile()
 {
     return m_globalData->interpreter->registerFile();
@@ -694,6 +699,12 @@
         } while (lastOpaqueRootCount != visitor.opaqueRootCount());
     }
     GCCOUNTER(VisitedValueCount, visitor.visitCount());
+
+    {
+        GCPHASE(HarvestWeakReferences);
+        harvestWeakReferences();
+    }
+
     visitor.reset();
     m_sharedData.reset();
 
@@ -781,14 +792,18 @@
     }
 
     markRoots(fullGC);
-
+    
     {
-        GCPHASE(HarvestWeakReferences);
-        harvestWeakReferences();
+        GCPHASE(FinalizeUnconditionalFinalizers);
+        finalizeUnconditionalFinalizers();
+    }
+        
+    {
+        GCPHASE(FinalizeWeakHandles);
         m_handleHeap.finalizeWeakHandles();
         m_globalData->smallStrings.finalizeSmallStrings();
     }
-
+    
     JAVASCRIPTCORE_GC_MARKED();
 
     {
diff --git a/Source/JavaScriptCore/heap/Heap.h b/Source/JavaScriptCore/heap/Heap.h
index 74b788d..8efc393 100644
--- a/Source/JavaScriptCore/heap/Heap.h
+++ b/Source/JavaScriptCore/heap/Heap.h
@@ -155,6 +155,7 @@
         void markProtectedObjects(HeapRootVisitor&);
         void markTempSortVectors(HeapRootVisitor&);
         void harvestWeakReferences();
+        void finalizeUnconditionalFinalizers();
         
         enum SweepToggle { DoNotSweep, DoSweep };
         void collect(SweepToggle);
diff --git a/Source/JavaScriptCore/heap/ListableHandler.h b/Source/JavaScriptCore/heap/ListableHandler.h
new file mode 100644
index 0000000..edd2a1a
--- /dev/null
+++ b/Source/JavaScriptCore/heap/ListableHandler.h
@@ -0,0 +1,102 @@
+/*
+ *  Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef ListableHandler_h
+#define ListableHandler_h
+
+#include <stdint.h>
+#include <wtf/Locker.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/ThreadingPrimitives.h>
+
+namespace JSC {
+
+class MarkStack;
+class MarkStackThreadSharedData;
+class SlotVisitor;
+
+template<typename T>
+class ListableHandler {
+    WTF_MAKE_NONCOPYABLE(ListableHandler);
+    
+protected:
+    ListableHandler()
+        : m_nextAndFlag(0)
+    {
+    }
+    
+    virtual ~ListableHandler() { }
+
+private:
+    // Allow these classes to use ListableHandler::List.
+    friend class MarkStack;
+    friend class MarkStackThreadSharedData;
+    friend class SlotVisitor;
+    
+    class List {
+        WTF_MAKE_NONCOPYABLE(List);
+    public:
+        List()
+            : m_first(0)
+        {
+        }
+        
+        void addThreadSafe(T* handler)
+        {
+            // NOTE: If we ever want this to be faster, we could turn it into
+            // a CAS loop, since this is a singly-linked-list that, in parallel
+            // tracing mode, can only grow. I.e. we don't have to worry about
+            // any ABA problems.
+            MutexLocker locker(m_lock);
+            addNotThreadSafe(handler);
+        }
+        
+        bool hasNext()
+        {
+            return !!m_first;
+        }
+        
+        T* removeNext()
+        {
+            T* current = m_first;
+            T* next = reinterpret_cast<T*>(current->m_nextAndFlag & ~1);
+            current->m_nextAndFlag = 0;
+            m_first = next;
+            return current;
+        }
+        
+    private:
+        void addNotThreadSafe(T* handler)
+        {
+            if (handler->m_nextAndFlag & 1)
+                return;
+            handler->m_nextAndFlag = reinterpret_cast<uintptr_t>(m_first) | 1;
+            m_first = handler;
+        }
+        
+        Mutex m_lock;
+        T* m_first;
+    };
+    
+    uintptr_t m_nextAndFlag;
+};
+
+} // namespace JSC
+
+#endif // ListableHandler_h
diff --git a/Source/JavaScriptCore/heap/MarkStack.cpp b/Source/JavaScriptCore/heap/MarkStack.cpp
index f545c64..f81c710 100644
--- a/Source/JavaScriptCore/heap/MarkStack.cpp
+++ b/Source/JavaScriptCore/heap/MarkStack.cpp
@@ -236,7 +236,6 @@
     , m_sharedMarkStack(m_segmentAllocator)
     , m_numberOfActiveParallelMarkers(0)
     , m_parallelMarkersShouldExit(false)
-    , m_firstWeakReferenceHarvester(0)
 {
 #if ENABLE(PARALLEL_GC)
     for (unsigned i = 1; i < Heuristics::numberOfGCMarkers; ++i) {
@@ -450,13 +449,14 @@
 
 void SlotVisitor::harvestWeakReferences()
 {
-    while (m_shared.m_firstWeakReferenceHarvester) {
-        WeakReferenceHarvester* current = m_shared.m_firstWeakReferenceHarvester;
-        WeakReferenceHarvester* next = reinterpret_cast<WeakReferenceHarvester*>(current->m_nextAndFlag & ~1);
-        current->m_nextAndFlag = 0;
-        m_shared.m_firstWeakReferenceHarvester = next;
-        current->visitWeakReferences(*this);
-    }
+    while (m_shared.m_weakReferenceHarvesters.hasNext())
+        m_shared.m_weakReferenceHarvesters.removeNext()->visitWeakReferences(*this);
+}
+
+void SlotVisitor::finalizeUnconditionalFinalizers()
+{
+    while (m_shared.m_unconditionalFinalizers.hasNext())
+        m_shared.m_unconditionalFinalizers.removeNext()->finalizeUnconditionally();
 }
 
 #if ENABLE(GC_VALIDATION)
diff --git a/Source/JavaScriptCore/heap/MarkStack.h b/Source/JavaScriptCore/heap/MarkStack.h
index 51b3486..cf96ff8 100644
--- a/Source/JavaScriptCore/heap/MarkStack.h
+++ b/Source/JavaScriptCore/heap/MarkStack.h
@@ -30,6 +30,7 @@
 #include "Heuristics.h"
 #include "JSValue.h"
 #include "Register.h"
+#include "UnconditionalFinalizer.h"
 #include "VTableSpectrum.h"
 #include "WeakReferenceHarvester.h"
 #include <wtf/HashMap.h>
@@ -194,8 +195,8 @@
         Mutex m_opaqueRootsLock;
         HashSet<void*> m_opaqueRoots;
 
-        Mutex m_weakReferenceHarvesterLock;
-        WeakReferenceHarvester* m_firstWeakReferenceHarvester;
+        ListableHandler<WeakReferenceHarvester>::List m_weakReferenceHarvesters;
+        ListableHandler<UnconditionalFinalizer>::List m_unconditionalFinalizers;
     };
 
     class MarkStack {
@@ -229,11 +230,12 @@
 
         void addWeakReferenceHarvester(WeakReferenceHarvester* weakReferenceHarvester)
         {
-            MutexLocker locker(m_shared.m_weakReferenceHarvesterLock);
-            if (weakReferenceHarvester->m_nextAndFlag & 1)
-                return;
-            weakReferenceHarvester->m_nextAndFlag = reinterpret_cast<uintptr_t>(m_shared.m_firstWeakReferenceHarvester) | 1;
-            m_shared.m_firstWeakReferenceHarvester = weakReferenceHarvester;
+            m_shared.m_weakReferenceHarvesters.addThreadSafe(weakReferenceHarvester);
+        }
+        
+        void addUnconditionalFinalizer(UnconditionalFinalizer* unconditionalFinalizer)
+        {
+            m_shared.m_unconditionalFinalizers.addThreadSafe(unconditionalFinalizer);
         }
 
     protected:
diff --git a/Source/JavaScriptCore/heap/SlotVisitor.h b/Source/JavaScriptCore/heap/SlotVisitor.h
index 09c38fb..a461781 100644
--- a/Source/JavaScriptCore/heap/SlotVisitor.h
+++ b/Source/JavaScriptCore/heap/SlotVisitor.h
@@ -58,6 +58,7 @@
     void drainFromShared(SharedDrainMode);
 
     void harvestWeakReferences();
+    void finalizeUnconditionalFinalizers();
         
 private:
     void donateSlow();
diff --git a/Source/JavaScriptCore/heap/UnconditionalFinalizer.h b/Source/JavaScriptCore/heap/UnconditionalFinalizer.h
new file mode 100644
index 0000000..26029d0
--- /dev/null
+++ b/Source/JavaScriptCore/heap/UnconditionalFinalizer.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef UnconditionalFinalizer_h
+#define UnconditionalFinalizer_h
+
+#include "ListableHandler.h"
+
+namespace JSC {
+
+// An unconditional finalizer is useful for caches that you would like to
+// destroy on each GC. This is currently used for the bytecode stream
+// associated with each CodeBlock.
+
+class UnconditionalFinalizer : public ListableHandler<UnconditionalFinalizer> {
+public:    
+    virtual void finalizeUnconditionally() = 0;
+
+protected:
+    virtual ~UnconditionalFinalizer() { }
+};
+
+}
+
+#endif // UltraWeakFinalizer_h
diff --git a/Source/JavaScriptCore/heap/WeakReferenceHarvester.h b/Source/JavaScriptCore/heap/WeakReferenceHarvester.h
index a9eb4d3..90b4dee 100644
--- a/Source/JavaScriptCore/heap/WeakReferenceHarvester.h
+++ b/Source/JavaScriptCore/heap/WeakReferenceHarvester.h
@@ -20,7 +20,7 @@
 #ifndef WeakReferenceHarvester_h
 #define WeakReferenceHarvester_h
 
-#include <stdint.h>
+#include "ListableHandler.h"
 
 namespace JSC {
 
@@ -28,24 +28,16 @@
 class MarkStackSharedData;
 class SlotVisitor;
 
-class WeakReferenceHarvester {
+class WeakReferenceHarvester : public ListableHandler<WeakReferenceHarvester> {
 public:
     virtual void visitWeakReferences(SlotVisitor&) = 0;
     
 protected:
     WeakReferenceHarvester()
-        : m_nextAndFlag(0)
     {
     }
     
     virtual ~WeakReferenceHarvester() { }
-
-private:
-    friend class MarkStack;
-    friend class MarkStackSharedData;
-    friend class SlotVisitor;
-    
-    uintptr_t m_nextAndFlag;
 };
 
 } // namespace JSC