Copying collection shouldn't require O(live bytes) memory overhead
[WebKit-https.git] / Source / JavaScriptCore / heap / GCThreadSharedData.cpp
1 /*
2  * Copyright (C) 2009, 2011 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "GCThreadSharedData.h"
28
29 #include "CopyVisitor.h"
30 #include "CopyVisitorInlineMethods.h"
31 #include "GCThread.h"
32 #include "JSGlobalData.h"
33 #include "MarkStack.h"
34 #include "SlotVisitor.h"
35 #include "SlotVisitorInlineMethods.h"
36
37 namespace JSC {
38
39 #if ENABLE(PARALLEL_GC)
40 void GCThreadSharedData::resetChildren()
41 {
42     for (size_t i = 0; i < m_gcThreads.size(); ++i)
43         m_gcThreads[i]->slotVisitor()->reset();
44 }
45
46 size_t GCThreadSharedData::childVisitCount()
47 {       
48     unsigned long result = 0;
49     for (unsigned i = 0; i < m_gcThreads.size(); ++i)
50         result += m_gcThreads[i]->slotVisitor()->visitCount();
51     return result;
52 }
53 #endif
54
55 GCThreadSharedData::GCThreadSharedData(JSGlobalData* globalData)
56     : m_globalData(globalData)
57     , m_copiedSpace(&globalData->heap.m_storageSpace)
58     , m_shouldHashConst(false)
59     , m_sharedMarkStack(m_segmentAllocator)
60     , m_numberOfActiveParallelMarkers(0)
61     , m_parallelMarkersShouldExit(false)
62     , m_blocksToCopy(globalData->heap.m_blockSnapshot)
63     , m_copyIndex(0)
64     , m_currentPhase(NoPhase)
65 {
66     m_copyLock.Init();
67 #if ENABLE(PARALLEL_GC)
68     // Grab the lock so the new GC threads can be properly initialized before they start running.
69     MutexLocker locker(m_markingLock);
70     for (unsigned i = 1; i < Options::numberOfGCMarkers(); ++i) {
71         SlotVisitor* slotVisitor = new SlotVisitor(*this);
72         CopyVisitor* copyVisitor = new CopyVisitor(*this);
73         size_t index = m_gcThreads.size();
74         GCThread* newThread = new GCThread(*this, slotVisitor, copyVisitor, index);
75         ThreadIdentifier threadID = createThread(GCThread::gcThreadStartFunc, newThread, "JavaScriptCore::Marking");
76         newThread->initializeThreadID(threadID);
77         m_gcThreads.append(newThread);
78     }
79 #endif
80 }
81
82 GCThreadSharedData::~GCThreadSharedData()
83 {
84 #if ENABLE(PARALLEL_GC)    
85     // Destroy our marking threads.
86     {
87         MutexLocker markingLocker(m_markingLock);
88         MutexLocker phaseLocker(m_phaseLock);
89         ASSERT(m_currentPhase == NoPhase);
90         m_parallelMarkersShouldExit = true;
91         m_currentPhase = Exit;
92         m_phaseCondition.broadcast();
93     }
94     for (unsigned i = 0; i < m_gcThreads.size(); ++i) {
95         waitForThreadCompletion(m_gcThreads[i]->threadID());
96         delete m_gcThreads[i];
97     }
98 #endif
99 }
100     
101 void GCThreadSharedData::reset()
102 {
103     ASSERT(m_sharedMarkStack.isEmpty());
104     
105 #if ENABLE(PARALLEL_GC)
106     m_segmentAllocator.shrinkReserve();
107     m_opaqueRoots.clear();
108 #else
109     ASSERT(m_opaqueRoots.isEmpty());
110 #endif
111     m_weakReferenceHarvesters.removeAll();
112
113     if (m_shouldHashConst) {
114         m_globalData->resetNewStringsSinceLastHashConst();
115         m_shouldHashConst = false;
116     }
117 }
118
119 void GCThreadSharedData::didStartMarking()
120 {
121     MutexLocker markingLocker(m_markingLock);
122     MutexLocker phaseLocker(m_phaseLock);
123     ASSERT(m_currentPhase == NoPhase);
124     m_currentPhase = Mark;
125     m_parallelMarkersShouldExit = false;
126     m_phaseCondition.broadcast();
127 }
128
129 void GCThreadSharedData::didFinishMarking()
130 {
131     MutexLocker markingLocker(m_markingLock);
132     MutexLocker phaseLocker(m_phaseLock);
133     ASSERT(m_currentPhase == Mark);
134     m_currentPhase = NoPhase;
135     m_parallelMarkersShouldExit = true;
136     m_markingCondition.broadcast();
137 }
138
139 void GCThreadSharedData::didStartCopying()
140 {
141     {
142         SpinLockHolder locker(&m_copyLock);
143         m_blocksToCopy = m_globalData->heap.m_blockSnapshot;
144         m_copyIndex = 0;
145     }
146
147     // We do this here so that we avoid a race condition where the main thread can 
148     // blow through all of the copying work before the GCThreads fully wake up. 
149     // The GCThreads then request a block from the CopiedSpace when the copying phase 
150     // has completed, which isn't allowed.
151     for (size_t i = 0; i < m_gcThreads.size(); i++)
152         m_gcThreads[i]->copyVisitor()->startCopying();
153
154     MutexLocker locker(m_phaseLock);
155     ASSERT(m_currentPhase == NoPhase);
156     m_currentPhase = Copy;
157     m_phaseCondition.broadcast(); 
158 }
159
160 void GCThreadSharedData::didFinishCopying()
161 {
162     MutexLocker locker(m_phaseLock);
163     ASSERT(m_currentPhase == Copy);
164     m_currentPhase = NoPhase;
165     m_phaseCondition.broadcast();
166 }
167
168 } // namespace JSC