Add Heap verification infrastructure.
<https://webkit.org/b/138851>

Reviewed by Geoffrey Garen.

The verification infrastructure code is always built in but disabled by
default.  When disabled, the cost is minimal:
1. Heap has a m_verifier field.
2. GC does a few "if (m_verifier)" checks that should fail.
3. HeapVerifier takes up code space though not used.

When enabled:
1. The HeapVerifier will keep N number of GC cycle data.
   Each GC cycle will contain a "before marking" and "after marking" live
   object list.
   The GC cycles is a circular buffer.  Only data for the last N GC cycles
   will be retained.
2. During GC, the current GC cycle's live objects lists will be populated
   before and after marking.
3. The current GC cycle's live object lists will be validated before GC,
   after marking, and after GC.

Currently, the only validation being done is to verify that object
butterflies are allocated from valid blocks in the Storage (aka Copied)
space.

* CMakeLists.txt:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* heap/Heap.cpp:
(JSC::Heap::Heap):
(JSC::Heap::collect):
* heap/Heap.h:
* heap/HeapVerifier.cpp: Added.
(JSC::LiveObjectList::findObject):
(JSC::HeapVerifier::HeapVerifier):
(JSC::HeapVerifier::collectionTypeName):
(JSC::HeapVerifier::phaseName):
(JSC::getButterflyDetails):
(JSC::HeapVerifier::initializeGCCycle):
(JSC::GatherLiveObjFunctor::GatherLiveObjFunctor):
(JSC::GatherLiveObjFunctor::operator()):
(JSC::HeapVerifier::gatherLiveObjects):
(JSC::HeapVerifier::liveObjectListForGathering):
(JSC::trimDeadObjectsFromList):
(JSC::HeapVerifier::trimDeadObjects):
(JSC::HeapVerifier::verifyButterflyIsInStorageSpace):
(JSC::HeapVerifier::verify):
(JSC::HeapVerifier::reportObject):
(JSC::HeapVerifier::checkIfRecorded):
* heap/HeapVerifier.h: Added.
(JSC::LiveObjectData::LiveObjectData):
(JSC::LiveObjectList::LiveObjectList):
(JSC::LiveObjectList::reset):
(JSC::HeapVerifier::GCCycle::GCCycle):
(JSC::HeapVerifier::GCCycle::collectionTypeName):
(JSC::HeapVerifier::incrementCycle):
(JSC::HeapVerifier::currentCycle):
(JSC::HeapVerifier::cycleForIndex):
* runtime/Options.h:



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@176424 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/heap/Heap.cpp b/Source/JavaScriptCore/heap/Heap.cpp
index aed6b70..6e95291 100644
--- a/Source/JavaScriptCore/heap/Heap.cpp
+++ b/Source/JavaScriptCore/heap/Heap.cpp
@@ -35,6 +35,7 @@
 #include "HeapIterationScope.h"
 #include "HeapRootVisitor.h"
 #include "HeapStatistics.h"
+#include "HeapVerifier.h"
 #include "IncrementalSweeper.h"
 #include "Interpreter.h"
 #include "JSGlobalObject.h"
@@ -339,6 +340,8 @@
     , m_deferralDepth(0)
 {
     m_storageSpace.init();
+    if (Options::verifyHeap())
+        m_verifier = std::make_unique<HeapVerifier>(this, Options::numberOfGCCyclesToRecordForVerification());
 }
 
 Heap::~Heap()
@@ -1004,6 +1007,14 @@
     GCPHASE(Collect);
 
     double gcStartTime = WTF::monotonicallyIncreasingTime();
+    if (m_verifier) {
+        // Verify that live objects from the last GC cycle haven't been corrupted by
+        // mutators before we begin this new GC cycle.
+        m_verifier->verify(HeapVerifier::Phase::BeforeGC);
+
+        m_verifier->initializeGCCycle();
+        m_verifier->gatherLiveObjects(HeapVerifier::Phase::BeforeMarking);
+    }
 
     deleteOldCode(gcStartTime);
     flushOldStructureIDTables();
@@ -1012,6 +1023,10 @@
 
     markRoots(gcStartTime);
 
+    if (m_verifier) {
+        m_verifier->gatherLiveObjects(HeapVerifier::Phase::AfterMarking);
+        m_verifier->verify(HeapVerifier::Phase::AfterMarking);
+    }
     JAVASCRIPTCORE_GC_MARKED();
 
     if (vm()->typeProfiler())
@@ -1035,6 +1050,11 @@
     didFinishCollection(gcStartTime);
     resumeCompilerThreads();
 
+    if (m_verifier) {
+        m_verifier->trimDeadObjects();
+        m_verifier->verify(HeapVerifier::Phase::AfterGC);
+    }
+
     if (Options::logGC()) {
         double after = currentTimeMS();
         dataLog(after - before, " ms]\n");