2 * Copyright (C) 2009, 2011 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "GCThreadSharedData.h"
29 #include "CopyVisitor.h"
30 #include "CopyVisitorInlines.h"
33 #include "MarkStack.h"
34 #include "SlotVisitor.h"
35 #include "SlotVisitorInlines.h"
39 #if ENABLE(PARALLEL_GC)
40 void GCThreadSharedData::resetChildren()
42 for (size_t i
= 0; i
< m_gcThreads
.size(); ++i
)
43 m_gcThreads
[i
]->slotVisitor()->reset();
46 size_t GCThreadSharedData::childVisitCount()
48 unsigned long result
= 0;
49 for (unsigned i
= 0; i
< m_gcThreads
.size(); ++i
)
50 result
+= m_gcThreads
[i
]->slotVisitor()->visitCount();
55 GCThreadSharedData::GCThreadSharedData(VM
* vm
)
57 , m_copiedSpace(&vm
->heap
.m_storageSpace
)
58 , m_shouldHashCons(false)
59 , m_sharedMarkStack(vm
->heap
.blockAllocator())
60 , m_numberOfActiveParallelMarkers(0)
61 , m_parallelMarkersShouldExit(false)
63 , m_numberOfActiveGCThreads(0)
64 , m_gcThreadsShouldWait(false)
65 , m_currentPhase(NoPhase
)
68 #if ENABLE(PARALLEL_GC)
69 // Grab the lock so the new GC threads can be properly initialized before they start running.
70 MutexLocker
locker(m_phaseLock
);
71 for (unsigned i
= 1; i
< Options::numberOfGCMarkers(); ++i
) {
72 m_numberOfActiveGCThreads
++;
73 SlotVisitor
* slotVisitor
= new SlotVisitor(*this);
74 CopyVisitor
* copyVisitor
= new CopyVisitor(*this);
75 GCThread
* newThread
= new GCThread(*this, slotVisitor
, copyVisitor
);
76 ThreadIdentifier threadID
= createThread(GCThread::gcThreadStartFunc
, newThread
, "JavaScriptCore::Marking");
77 newThread
->initializeThreadID(threadID
);
78 m_gcThreads
.append(newThread
);
81 // Wait for all the GCThreads to get to the right place.
82 while (m_numberOfActiveGCThreads
)
83 m_activityCondition
.wait(m_phaseLock
);
87 GCThreadSharedData::~GCThreadSharedData()
89 #if ENABLE(PARALLEL_GC)
90 // Destroy our marking threads.
92 MutexLocker
markingLocker(m_markingLock
);
93 MutexLocker
phaseLocker(m_phaseLock
);
94 ASSERT(m_currentPhase
== NoPhase
);
95 m_parallelMarkersShouldExit
= true;
96 m_gcThreadsShouldWait
= false;
97 m_currentPhase
= Exit
;
98 m_phaseCondition
.broadcast();
100 for (unsigned i
= 0; i
< m_gcThreads
.size(); ++i
) {
101 waitForThreadCompletion(m_gcThreads
[i
]->threadID());
102 delete m_gcThreads
[i
];
107 void GCThreadSharedData::reset()
109 ASSERT(m_sharedMarkStack
.isEmpty());
111 #if ENABLE(PARALLEL_GC)
112 m_opaqueRoots
.clear();
114 ASSERT(m_opaqueRoots
.isEmpty());
116 m_weakReferenceHarvesters
.removeAll();
118 if (m_shouldHashCons
) {
119 m_vm
->resetNewStringsSinceLastHashCons();
120 m_shouldHashCons
= false;
124 void GCThreadSharedData::startNextPhase(GCPhase phase
)
126 MutexLocker
phaseLocker(m_phaseLock
);
127 ASSERT(!m_gcThreadsShouldWait
);
128 ASSERT(m_currentPhase
== NoPhase
);
129 m_gcThreadsShouldWait
= true;
130 m_currentPhase
= phase
;
131 m_phaseCondition
.broadcast();
134 void GCThreadSharedData::endCurrentPhase()
136 ASSERT(m_gcThreadsShouldWait
);
137 MutexLocker
locker(m_phaseLock
);
138 m_currentPhase
= NoPhase
;
139 m_gcThreadsShouldWait
= false;
140 m_phaseCondition
.broadcast();
141 while (m_numberOfActiveGCThreads
)
142 m_activityCondition
.wait(m_phaseLock
);
145 void GCThreadSharedData::didStartMarking()
147 MutexLocker
markingLocker(m_markingLock
);
148 m_parallelMarkersShouldExit
= false;
149 startNextPhase(Mark
);
152 void GCThreadSharedData::didFinishMarking()
155 MutexLocker
markingLocker(m_markingLock
);
156 m_parallelMarkersShouldExit
= true;
157 m_markingCondition
.broadcast();
160 ASSERT(m_currentPhase
== Mark
);
164 void GCThreadSharedData::didStartCopying()
167 SpinLockHolder
locker(&m_copyLock
);
168 WTF::copyToVector(m_copiedSpace
->m_blockSet
, m_blocksToCopy
);
172 // We do this here so that we avoid a race condition where the main thread can
173 // blow through all of the copying work before the GCThreads fully wake up.
174 // The GCThreads then request a block from the CopiedSpace when the copying phase
175 // has completed, which isn't allowed.
176 for (size_t i
= 0; i
< m_gcThreads
.size(); i
++)
177 m_gcThreads
[i
]->copyVisitor()->startCopying();
179 startNextPhase(Copy
);
182 void GCThreadSharedData::didFinishCopying()
184 ASSERT(m_currentPhase
== Copy
);