summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/heap/GCThread.cpp
blob: ce3bbedc9f6af7244426120069c8b8922c63770d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
 * Copyright (C) 2012 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. AND ITS CONTRIBUTORS ``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 ITS 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.
 */

#include "config.h"
#include "GCThread.h"

#include "CopyVisitor.h"
#include "CopyVisitorInlineMethods.h"
#include "GCThreadSharedData.h"
#include "SlotVisitor.h"
#include <wtf/MainThread.h>
#include <wtf/PassOwnPtr.h>

namespace JSC {

GCThread::GCThread(GCThreadSharedData& shared, SlotVisitor* slotVisitor, CopyVisitor* copyVisitor)
    : m_threadID(0)
    , m_shared(shared)
    , m_slotVisitor(WTF::adoptPtr(slotVisitor))
    , m_copyVisitor(WTF::adoptPtr(copyVisitor))
{
}

ThreadIdentifier GCThread::threadID()
{
    ASSERT(m_threadID);
    return m_threadID;
}

void GCThread::initializeThreadID(ThreadIdentifier threadID)
{
    ASSERT(!m_threadID);
    m_threadID = threadID;
}

SlotVisitor* GCThread::slotVisitor()
{
    ASSERT(m_slotVisitor);
    return m_slotVisitor.get();
}

CopyVisitor* GCThread::copyVisitor()
{
    ASSERT(m_copyVisitor);
    return m_copyVisitor.get();
}

GCPhase GCThread::waitForNextPhase()
{
    MutexLocker locker(m_shared.m_phaseLock);
    while (m_shared.m_gcThreadsShouldWait)
        m_shared.m_phaseCondition.wait(m_shared.m_phaseLock);

    m_shared.m_numberOfActiveGCThreads--;
    if (!m_shared.m_numberOfActiveGCThreads)
        m_shared.m_activityCondition.signal();

    while (m_shared.m_currentPhase == NoPhase)
        m_shared.m_phaseCondition.wait(m_shared.m_phaseLock);
    m_shared.m_numberOfActiveGCThreads++;
    return m_shared.m_currentPhase;
}

void GCThread::gcThreadMain()
{
    GCPhase currentPhase;
#if ENABLE(PARALLEL_GC)
    WTF::registerGCThread();
#endif
    // Wait for the main thread to finish creating and initializing us. The main thread grabs this lock before 
    // creating this thread. We aren't guaranteed to have a valid threadID until the main thread releases this lock.
    {
        MutexLocker locker(m_shared.m_phaseLock);
    }
    {
        ParallelModeEnabler enabler(*m_slotVisitor);
        while ((currentPhase = waitForNextPhase()) != Exit) {
            // Note: Each phase is responsible for its own termination conditions. The comments below describe 
            // how each phase reaches termination.
            switch (currentPhase) {
            case Mark:
                m_slotVisitor->drainFromShared(SlotVisitor::SlaveDrain);
                // GCThreads only return from drainFromShared() if the main thread sets the m_parallelMarkersShouldExit 
                // flag in the GCThreadSharedData. The only way the main thread sets that flag is if it realizes 
                // that all of the various subphases in Heap::markRoots() have been fully finished and there is 
                // no more marking work to do and all of the GCThreads are idle, meaning no more work can be generated.
                break;
            case Copy:
                // We don't have to call startCopying() because it's called for us on the main thread to avoid a 
                // race condition.
                m_copyVisitor->copyFromShared();
                // We know we're done copying when we return from copyFromShared() because we would 
                // only do so if there were no more chunks of copying work left to do. When there is no 
                // more copying work to do, the main thread will wait in CopiedSpace::doneCopying() until 
                // all of the blocks that the GCThreads borrowed have been returned. doneCopying() 
                // returns our borrowed CopiedBlock, allowing the copying phase to finish.
                m_copyVisitor->doneCopying();
                break;
            case NoPhase:
                ASSERT_NOT_REACHED();
                break;
            case Exit:
                ASSERT_NOT_REACHED();
                break;
            }
        }
    }
}

void GCThread::gcThreadStartFunc(void* data)
{
    GCThread* thread = static_cast<GCThread*>(data);
    thread->gcThreadMain();
}

} // namespace JSC