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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
|
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
* Copyright (C) 2003-2017 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
*
*/
#pragma once
#include "RegisterState.h"
#include <wtf/Lock.h>
#include <wtf/Noncopyable.h>
#include <wtf/ScopedLambda.h>
#include <wtf/ThreadSpecific.h>
#if OS(DARWIN)
#include <mach/thread_act.h>
#endif
#if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN)
#include <semaphore.h>
#include <signal.h>
// Using signal.h didn't make mcontext_t and ucontext_t available on FreeBSD.
// This bug has been fixed in FreeBSD 11.0-CURRENT, so this workaround can be
// removed after FreeBSD 10.x goes EOL.
// https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=207079
#if OS(FREEBSD)
#include <ucontext.h>
#endif
#endif
#if OS(DARWIN)
typedef mach_port_t PlatformThread;
#elif OS(WINDOWS)
typedef DWORD PlatformThread;
#elif USE(PTHREADS)
typedef pthread_t PlatformThread;
#endif // OS(DARWIN)
namespace JSC {
class CodeBlockSet;
class ConservativeRoots;
class Heap;
class JITStubRoutineSet;
struct CurrentThreadState {
void* stackOrigin { nullptr };
void* stackTop { nullptr };
RegisterState* registerState { nullptr };
};
class MachineThreads {
WTF_MAKE_NONCOPYABLE(MachineThreads);
public:
MachineThreads(Heap*);
~MachineThreads();
void gatherConservativeRoots(ConservativeRoots&, JITStubRoutineSet&, CodeBlockSet&, CurrentThreadState*);
JS_EXPORT_PRIVATE void addCurrentThread(); // Only needs to be called by clients that can use the same heap from multiple threads.
class ThreadData {
WTF_MAKE_FAST_ALLOCATED;
public:
ThreadData();
~ThreadData();
static ThreadData* createForCurrentThread();
struct Registers {
void* stackPointer() const;
#if ENABLE(SAMPLING_PROFILER)
void* framePointer() const;
void* instructionPointer() const;
void* llintPC() const;
#endif // ENABLE(SAMPLING_PROFILER)
#if OS(DARWIN)
#if CPU(X86)
typedef i386_thread_state_t PlatformRegisters;
#elif CPU(X86_64)
typedef x86_thread_state64_t PlatformRegisters;
#elif CPU(PPC)
typedef ppc_thread_state_t PlatformRegisters;
#elif CPU(PPC64)
typedef ppc_thread_state64_t PlatformRegisters;
#elif CPU(ARM)
typedef arm_thread_state_t PlatformRegisters;
#elif CPU(ARM64)
typedef arm_thread_state64_t PlatformRegisters;
#else
#error Unknown Architecture
#endif
#elif OS(WINDOWS)
typedef CONTEXT PlatformRegisters;
#elif USE(PTHREADS)
struct PlatformRegisters {
pthread_attr_t attribute;
mcontext_t machineContext;
};
#else
#error Need a thread register struct for this platform
#endif
PlatformRegisters regs;
};
bool suspend();
void resume();
size_t getRegisters(Registers&);
void freeRegisters(Registers&);
std::pair<void*, size_t> captureStack(void* stackTop);
PlatformThread platformThread;
void* stackBase;
void* stackEnd;
#if OS(WINDOWS)
HANDLE platformThreadHandle;
#elif USE(PTHREADS) && !OS(DARWIN)
sem_t semaphoreForSuspendResume;
mcontext_t suspendedMachineContext;
int suspendCount { 0 };
std::atomic<bool> suspended { false };
#endif
};
class Thread {
WTF_MAKE_FAST_ALLOCATED;
Thread(ThreadData*);
public:
using Registers = ThreadData::Registers;
static Thread* createForCurrentThread();
bool operator==(const PlatformThread& other) const;
bool operator!=(const PlatformThread& other) const { return !(*this == other); }
bool suspend() { return data->suspend(); }
void resume() { data->resume(); }
size_t getRegisters(Registers& regs) { return data->getRegisters(regs); }
void freeRegisters(Registers& regs) { data->freeRegisters(regs); }
std::pair<void*, size_t> captureStack(void* stackTop) { return data->captureStack(stackTop); }
const PlatformThread& platformThread() { return data->platformThread; }
void* stackBase() const { return data->stackBase; }
void* stackEnd() const { return data->stackEnd; }
Thread* next;
ThreadData* data;
};
Lock& getLock() { return m_registeredThreadsMutex; }
Thread* threadsListHead(const LockHolder&) const { ASSERT(m_registeredThreadsMutex.isLocked()); return m_registeredThreads; }
Thread* machineThreadForCurrentThread();
private:
void gatherFromCurrentThread(ConservativeRoots&, JITStubRoutineSet&, CodeBlockSet&, CurrentThreadState&);
void tryCopyOtherThreadStack(Thread*, void*, size_t capacity, size_t*);
bool tryCopyOtherThreadStacks(LockHolder&, void*, size_t capacity, size_t*);
static void THREAD_SPECIFIC_CALL removeThread(void*);
template<typename PlatformThread>
void removeThreadIfFound(PlatformThread);
Lock m_registeredThreadsMutex;
Thread* m_registeredThreads;
WTF::ThreadSpecificKey m_threadSpecificForMachineThreads;
#if !ASSERT_DISABLED
Heap* m_heap;
#endif
};
#define DECLARE_AND_COMPUTE_CURRENT_THREAD_STATE(stateName) \
CurrentThreadState stateName; \
stateName.stackTop = &stateName; \
stateName.stackOrigin = wtfThreadData().stack().origin(); \
ALLOCATE_AND_GET_REGISTER_STATE(stateName ## _registerState); \
stateName.registerState = &stateName ## _registerState
// The return value is meaningless. We just use it to suppress tail call optimization.
int callWithCurrentThreadState(const ScopedLambda<void(CurrentThreadState&)>&);
} // namespace JSC
|