2 * Copyright (C) 2006, 2007, 2013 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 "JSContextRef.h"
28 #include "JSContextRefInternal.h"
31 #include "CallFrame.h"
32 #include "InitializeThreading.h"
33 #include "JSCallbackObject.h"
34 #include "JSClassRef.h"
35 #include "JSGlobalObject.h"
37 #include "JSCInlines.h"
38 #include "RuntimeFlags.h"
39 #include "SourceProvider.h"
40 #include "StackVisitor.h"
41 #include <wtf/text/StringBuilder.h>
42 #include <wtf/text/StringHash.h>
44 #if ENABLE(REMOTE_INSPECTOR)
45 #include "JSGlobalObjectDebuggable.h"
46 #include "JSGlobalObjectInspectorController.h"
47 #include "JSRemoteInspector.h"
50 #if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
51 #include "JSContextRefInspectorSupport.h"
55 #include <mach-o/dyld.h>
57 static const int32_t webkitFirstVersionWithConcurrentGlobalContexts
= 0x2100500; // 528.5.0
62 static RuntimeFlags
javaScriptRuntimeFlags(const JSGlobalObject
* globalObject
)
64 RuntimeFlags runtimeFlags
= JSGlobalObject::javaScriptRuntimeFlags(globalObject
);
65 runtimeFlags
.setPromiseDisabled(true);
69 const GlobalObjectMethodTable
JSC::javaScriptCoreAPIGlobalObjectMethodTable
= { &JSGlobalObject::allowsAccessFrom
, &JSGlobalObject::supportsProfiling
, &JSGlobalObject::supportsRichSourceInfo
, &JSGlobalObject::shouldInterruptScript
, &javaScriptRuntimeFlags
, nullptr, &JSGlobalObject::shouldInterruptScriptBeforeTimeout
};
71 // From the API's perspective, a context group remains alive iff
72 // (a) it has been JSContextGroupRetained
74 // (b) one of its contexts has been JSContextRetained
76 JSContextGroupRef
JSContextGroupCreate()
78 initializeThreading();
79 return toRef(&VM::createContextGroup().leakRef());
82 JSContextGroupRef
JSContextGroupRetain(JSContextGroupRef group
)
88 void JSContextGroupRelease(JSContextGroupRef group
)
90 VM
& vm
= *toJS(group
);
92 JSLockHolder
locker(&vm
);
96 static bool internalScriptTimeoutCallback(ExecState
* exec
, void* callbackPtr
, void* callbackData
)
98 JSShouldTerminateCallback callback
= reinterpret_cast<JSShouldTerminateCallback
>(callbackPtr
);
99 JSContextRef contextRef
= toRef(exec
);
101 return callback(contextRef
, callbackData
);
104 static void createWatchdogIfNeeded(VM
& vm
)
107 vm
.watchdog
= std::make_unique
<Watchdog
>();
109 // The LLINT peeks into the Watchdog object directly. In order to do that,
110 // the LLINT assumes that the internal shape of a std::unique_ptr is the
111 // same as a plain C++ pointer, and loads the address of Watchdog from it.
112 RELEASE_ASSERT(*reinterpret_cast<Watchdog
**>(&vm
.watchdog
) == vm
.watchdog
.get());
116 void JSContextGroupSetExecutionTimeLimit(JSContextGroupRef group
, double limit
, JSShouldTerminateCallback callback
, void* callbackData
)
118 VM
& vm
= *toJS(group
);
119 JSLockHolder
locker(&vm
);
120 createWatchdogIfNeeded(vm
);
121 Watchdog
& watchdog
= *vm
.watchdog
;
123 void* callbackPtr
= reinterpret_cast<void*>(callback
);
124 watchdog
.setTimeLimit(vm
, std::chrono::duration_cast
<std::chrono::microseconds
>(std::chrono::duration
<double>(limit
)), internalScriptTimeoutCallback
, callbackPtr
, callbackData
);
126 watchdog
.setTimeLimit(vm
, std::chrono::duration_cast
<std::chrono::microseconds
>(std::chrono::duration
<double>(limit
)));
129 void JSContextGroupClearExecutionTimeLimit(JSContextGroupRef group
)
131 VM
& vm
= *toJS(group
);
132 JSLockHolder
locker(&vm
);
133 createWatchdogIfNeeded(vm
);
134 Watchdog
& watchdog
= *vm
.watchdog
;
135 watchdog
.setTimeLimit(vm
, std::chrono::microseconds::max());
138 // From the API's perspective, a global context remains alive iff it has been JSGlobalContextRetained.
140 JSGlobalContextRef
JSGlobalContextCreate(JSClassRef globalObjectClass
)
142 initializeThreading();
145 // If the application was linked before JSGlobalContextCreate was changed to use a unique VM,
146 // we use a shared one for backwards compatibility.
147 if (NSVersionOfLinkTimeLibrary("JavaScriptCore") <= webkitFirstVersionWithConcurrentGlobalContexts
) {
148 return JSGlobalContextCreateInGroup(toRef(&VM::sharedInstance()), globalObjectClass
);
152 return JSGlobalContextCreateInGroup(0, globalObjectClass
);
155 JSGlobalContextRef
JSGlobalContextCreateInGroup(JSContextGroupRef group
, JSClassRef globalObjectClass
)
157 initializeThreading();
159 RefPtr
<VM
> vm
= group
? PassRefPtr
<VM
>(toJS(group
)) : VM::createContextGroup();
161 JSLockHolder
locker(vm
.get());
163 if (!globalObjectClass
) {
164 JSGlobalObject
* globalObject
= JSGlobalObject::create(*vm
, JSGlobalObject::createStructure(*vm
, jsNull()), &javaScriptCoreAPIGlobalObjectMethodTable
);
165 #if ENABLE(REMOTE_INSPECTOR)
166 if (JSRemoteInspectorGetInspectionEnabledByDefault())
167 globalObject
->setRemoteDebuggingEnabled(true);
169 return JSGlobalContextRetain(toGlobalRef(globalObject
->globalExec()));
172 JSGlobalObject
* globalObject
= JSCallbackObject
<JSGlobalObject
>::create(*vm
, globalObjectClass
, JSCallbackObject
<JSGlobalObject
>::createStructure(*vm
, 0, jsNull()));
173 ExecState
* exec
= globalObject
->globalExec();
174 JSValue prototype
= globalObjectClass
->prototype(exec
);
176 prototype
= jsNull();
177 globalObject
->resetPrototype(*vm
, prototype
);
178 #if ENABLE(REMOTE_INSPECTOR)
179 if (JSRemoteInspectorGetInspectionEnabledByDefault())
180 globalObject
->setRemoteDebuggingEnabled(true);
182 return JSGlobalContextRetain(toGlobalRef(exec
));
185 JSGlobalContextRef
JSGlobalContextRetain(JSGlobalContextRef ctx
)
187 ExecState
* exec
= toJS(ctx
);
188 JSLockHolder
locker(exec
);
191 gcProtect(exec
->vmEntryGlobalObject());
196 void JSGlobalContextRelease(JSGlobalContextRef ctx
)
198 ExecState
* exec
= toJS(ctx
);
199 JSLockHolder
locker(exec
);
202 bool protectCountIsZero
= Heap::heap(exec
->vmEntryGlobalObject())->unprotect(exec
->vmEntryGlobalObject());
203 if (protectCountIsZero
)
204 vm
.heap
.reportAbandonedObjectGraph();
208 JSObjectRef
JSContextGetGlobalObject(JSContextRef ctx
)
211 ASSERT_NOT_REACHED();
214 ExecState
* exec
= toJS(ctx
);
215 JSLockHolder
locker(exec
);
217 return toRef(jsCast
<JSObject
*>(exec
->lexicalGlobalObject()->methodTable()->toThis(exec
->lexicalGlobalObject(), exec
, NotStrictMode
)));
220 JSContextGroupRef
JSContextGetGroup(JSContextRef ctx
)
223 ASSERT_NOT_REACHED();
226 ExecState
* exec
= toJS(ctx
);
227 return toRef(&exec
->vm());
230 JSGlobalContextRef
JSContextGetGlobalContext(JSContextRef ctx
)
233 ASSERT_NOT_REACHED();
236 ExecState
* exec
= toJS(ctx
);
237 JSLockHolder
locker(exec
);
239 return toGlobalRef(exec
->lexicalGlobalObject()->globalExec());
242 JSStringRef
JSGlobalContextCopyName(JSGlobalContextRef ctx
)
245 ASSERT_NOT_REACHED();
249 ExecState
* exec
= toJS(ctx
);
250 JSLockHolder
locker(exec
);
252 String name
= exec
->vmEntryGlobalObject()->name();
256 return OpaqueJSString::create(name
).leakRef();
259 void JSGlobalContextSetName(JSGlobalContextRef ctx
, JSStringRef name
)
262 ASSERT_NOT_REACHED();
266 ExecState
* exec
= toJS(ctx
);
267 JSLockHolder
locker(exec
);
269 exec
->vmEntryGlobalObject()->setName(name
? name
->string() : String());
273 class BacktraceFunctor
{
275 BacktraceFunctor(StringBuilder
& builder
, unsigned remainingCapacityForFrameCapture
)
277 , m_remainingCapacityForFrameCapture(remainingCapacityForFrameCapture
)
281 StackVisitor::Status
operator()(StackVisitor
& visitor
)
283 if (m_remainingCapacityForFrameCapture
) {
284 // If callee is unknown, but we've not added any frame yet, we should
285 // still add the frame, because something called us, and gave us arguments.
286 JSObject
* callee
= visitor
->callee();
287 if (!callee
&& visitor
->index())
288 return StackVisitor::Done
;
290 StringBuilder
& builder
= m_builder
;
291 if (!builder
.isEmpty())
292 builder
.append('\n');
294 builder
.appendNumber(visitor
->index());
296 builder
.append(visitor
->functionName());
297 builder
.appendLiteral("() at ");
298 builder
.append(visitor
->sourceURL());
299 if (visitor
->isJSFrame()) {
302 unsigned unusedColumn
;
303 visitor
->computeLineAndColumn(lineNumber
, unusedColumn
);
304 builder
.appendNumber(lineNumber
);
308 return StackVisitor::Done
;
310 m_remainingCapacityForFrameCapture
--;
311 return StackVisitor::Continue
;
313 return StackVisitor::Done
;
317 StringBuilder
& m_builder
;
318 unsigned m_remainingCapacityForFrameCapture
;
321 JSStringRef
JSContextCreateBacktrace(JSContextRef ctx
, unsigned maxStackSize
)
324 ASSERT_NOT_REACHED();
327 ExecState
* exec
= toJS(ctx
);
328 JSLockHolder
lock(exec
);
329 StringBuilder builder
;
330 CallFrame
* frame
= exec
->vm().topCallFrame
;
332 ASSERT(maxStackSize
);
333 BacktraceFunctor
functor(builder
, maxStackSize
);
334 frame
->iterate(functor
);
336 return OpaqueJSString::create(builder
.toString()).leakRef();
339 bool JSGlobalContextGetRemoteInspectionEnabled(JSGlobalContextRef ctx
)
342 ASSERT_NOT_REACHED();
346 ExecState
* exec
= toJS(ctx
);
347 JSLockHolder
lock(exec
);
349 return exec
->vmEntryGlobalObject()->remoteDebuggingEnabled();
352 void JSGlobalContextSetRemoteInspectionEnabled(JSGlobalContextRef ctx
, bool enabled
)
355 ASSERT_NOT_REACHED();
359 ExecState
* exec
= toJS(ctx
);
360 JSLockHolder
lock(exec
);
362 exec
->vmEntryGlobalObject()->setRemoteDebuggingEnabled(enabled
);
365 bool JSGlobalContextGetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx
)
367 #if ENABLE(REMOTE_INSPECTOR)
369 ASSERT_NOT_REACHED();
373 ExecState
* exec
= toJS(ctx
);
374 JSLockHolder
lock(exec
);
376 JSGlobalObject
* globalObject
= exec
->vmEntryGlobalObject();
377 return globalObject
->inspectorController().includesNativeCallStackWhenReportingExceptions();
384 void JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx
, bool includesNativeCallStack
)
386 #if ENABLE(REMOTE_INSPECTOR)
388 ASSERT_NOT_REACHED();
392 ExecState
* exec
= toJS(ctx
);
393 JSLockHolder
lock(exec
);
395 JSGlobalObject
* globalObject
= exec
->vmEntryGlobalObject();
396 globalObject
->inspectorController().setIncludesNativeCallStackWhenReportingExceptions(includesNativeCallStack
);
399 UNUSED_PARAM(includesNativeCallStack
);
404 CFRunLoopRef
JSGlobalContextGetDebuggerRunLoop(JSGlobalContextRef ctx
)
406 #if ENABLE(REMOTE_INSPECTOR)
408 ASSERT_NOT_REACHED();
412 ExecState
* exec
= toJS(ctx
);
413 JSLockHolder
lock(exec
);
415 return exec
->vmEntryGlobalObject()->inspectorDebuggable().debuggerRunLoop();
422 void JSGlobalContextSetDebuggerRunLoop(JSGlobalContextRef ctx
, CFRunLoopRef runLoop
)
424 #if ENABLE(REMOTE_INSPECTOR)
426 ASSERT_NOT_REACHED();
430 ExecState
* exec
= toJS(ctx
);
431 JSLockHolder
lock(exec
);
433 exec
->vmEntryGlobalObject()->inspectorDebuggable().setDebuggerRunLoop(runLoop
);
436 UNUSED_PARAM(runLoop
);
441 #if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
442 Inspector::AugmentableInspectorController
* JSGlobalContextGetAugmentableInspectorController(JSGlobalContextRef ctx
)
445 ASSERT_NOT_REACHED();
449 ExecState
* exec
= toJS(ctx
);
450 JSLockHolder
lock(exec
);
452 return &exec
->vmEntryGlobalObject()->inspectorController();