@@ -28,6 +28,14 @@ struct Lock {
28
28
void unlock (const jsc::JSCRuntime&) const {}
29
29
};
30
30
31
+ #if __has_builtin(__builtin_expect)
32
+ #define JSC_LIKELY (EXPR ) __builtin_expect((bool )(EXPR), true )
33
+ #define JSC_UNLIKELY (EXPR ) __builtin_expect((bool )(EXPR), false )
34
+ #else
35
+ #define JSC_LIKELY (EXPR ) (EXPR)
36
+ #define JSC_UNLIKELY (EXPR ) (EXPR)
37
+ #endif
38
+
31
39
class JSCRuntime : public jsi ::Runtime {
32
40
public:
33
41
// Creates new context in new context group
@@ -191,23 +199,32 @@ class JSCRuntime : public jsi::Runtime {
191
199
void checkException (JSValueRef exc, const char * msg);
192
200
void checkException (JSValueRef res, JSValueRef exc, const char * msg);
193
201
202
+ void checkThreadId () {
203
+ #ifndef NDEBUG
204
+ if (JSC_UNLIKELY (tid_ != std::this_thread::get_id ())) {
205
+ // In the version of JSC on iOS 11, creating a JSContext on one
206
+ // thread and using it on another can trigger subtle and nearly
207
+ // impossible to debug reentrancy-related crashes in the VM (see
208
+ // https://bugs.webkit.org/show_bug.cgi?id=186827). In !NDEBUG
209
+ // builds, check for this case and throw an exception, so it can
210
+ // be detected early. This could be called anywhere, but for
211
+ // now, it's called only in a few less frequently used places to
212
+ // avoid unnecessary checks.
213
+ throw std::logic_error (" Detected JSC thread hazard" );
214
+ }
215
+ #endif
216
+ }
217
+
194
218
JSGlobalContextRef ctx_;
195
219
std::atomic<bool > ctxInvalid_;
196
220
std::string desc_;
197
221
#ifndef NDEBUG
198
222
mutable std::atomic<intptr_t > objectCounter_;
199
223
mutable std::atomic<intptr_t > stringCounter_;
224
+ std::thread::id tid_;
200
225
#endif
201
226
};
202
227
203
- #if __has_builtin(__builtin_expect)
204
- #define JSC_LIKELY (EXPR ) __builtin_expect((bool )(EXPR), true )
205
- #define JSC_UNLIKELY (EXPR ) __builtin_expect((bool )(EXPR), false )
206
- #else
207
- #define JSC_LIKELY (EXPR ) (EXPR)
208
- #define JSC_UNLIKELY (EXPR ) (EXPR)
209
- #endif
210
-
211
228
#define JSC_ASSERT (x ) \
212
229
do { \
213
230
if (JSC_UNLIKELY (!!(x))) { \
@@ -292,7 +309,8 @@ JSCRuntime::JSCRuntime(JSGlobalContextRef ctx)
292
309
#ifndef NDEBUG
293
310
,
294
311
objectCounter_ (0 ),
295
- stringCounter_(0 )
312
+ stringCounter_(0 ),
313
+ tid_(std::this_thread::get_id())
296
314
#endif
297
315
{
298
316
}
@@ -317,6 +335,8 @@ JSCRuntime::~JSCRuntime() {
317
335
void JSCRuntime::evaluateJavaScript (
318
336
std::unique_ptr<const jsi::Buffer> buffer,
319
337
const std::string& sourceURL) {
338
+ checkThreadId ();
339
+
320
340
std::string tmp (
321
341
reinterpret_cast <const char *>(buffer->data ()), buffer->size ());
322
342
JSStringRef sourceRef = JSStringCreateWithUTF8CString (tmp.c_str ());
@@ -335,6 +355,8 @@ void JSCRuntime::evaluateJavaScript(
335
355
}
336
356
337
357
jsi::Object JSCRuntime::global () {
358
+ checkThreadId ();
359
+
338
360
return createObject (JSContextGetGlobalObject (ctx_));
339
361
}
340
362
0 commit comments