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 "SourceProvider.h"
39 #include "StackVisitor.h"
40 #include <wtf/text/StringBuilder.h>
41 #include <wtf/text/StringHash.h>
43 #if ENABLE(REMOTE_INSPECTOR)
44 #include "JSGlobalObjectDebuggable.h"
45 #include "JSGlobalObjectInspectorController.h"
49 #include <mach-o/dyld.h>
51 static const int32_t webkitFirstVersionWithConcurrentGlobalContexts
= 0x2100500; // 528.5.0
56 // From the API's perspective, a context group remains alive iff
57 // (a) it has been JSContextGroupRetained
59 // (b) one of its contexts has been JSContextRetained
61 JSContextGroupRef
JSContextGroupCreate()
63 initializeThreading();
64 return toRef(VM::createContextGroup().leakRef());
67 JSContextGroupRef
JSContextGroupRetain(JSContextGroupRef group
)
73 void JSContextGroupRelease(JSContextGroupRef group
)
75 VM
& vm
= *toJS(group
);
77 JSLockHolder
locker(&vm
);
81 static bool internalScriptTimeoutCallback(ExecState
* exec
, void* callbackPtr
, void* callbackData
)
83 JSShouldTerminateCallback callback
= reinterpret_cast<JSShouldTerminateCallback
>(callbackPtr
);
84 JSContextRef contextRef
= toRef(exec
);
86 return callback(contextRef
, callbackData
);
89 void JSContextGroupSetExecutionTimeLimit(JSContextGroupRef group
, double limit
, JSShouldTerminateCallback callback
, void* callbackData
)
91 VM
& vm
= *toJS(group
);
92 JSLockHolder
locker(&vm
);
94 vm
.watchdog
= std::make_unique
<Watchdog
>();
95 Watchdog
& watchdog
= *vm
.watchdog
;
97 void* callbackPtr
= reinterpret_cast<void*>(callback
);
98 watchdog
.setTimeLimit(vm
, limit
, internalScriptTimeoutCallback
, callbackPtr
, callbackData
);
100 watchdog
.setTimeLimit(vm
, limit
);
103 void JSContextGroupClearExecutionTimeLimit(JSContextGroupRef group
)
105 VM
& vm
= *toJS(group
);
106 JSLockHolder
locker(&vm
);
108 vm
.watchdog
= std::make_unique
<Watchdog
>();
109 Watchdog
& watchdog
= *vm
.watchdog
;
110 watchdog
.setTimeLimit(vm
, std::numeric_limits
<double>::infinity());
113 // From the API's perspective, a global context remains alive iff it has been JSGlobalContextRetained.
115 JSGlobalContextRef
JSGlobalContextCreate(JSClassRef globalObjectClass
)
117 initializeThreading();
120 // If the application was linked before JSGlobalContextCreate was changed to use a unique VM,
121 // we use a shared one for backwards compatibility.
122 if (NSVersionOfLinkTimeLibrary("JavaScriptCore") <= webkitFirstVersionWithConcurrentGlobalContexts
) {
123 return JSGlobalContextCreateInGroup(toRef(&VM::sharedInstance()), globalObjectClass
);
127 return JSGlobalContextCreateInGroup(0, globalObjectClass
);
130 JSGlobalContextRef
JSGlobalContextCreateInGroup(JSContextGroupRef group
, JSClassRef globalObjectClass
)
132 initializeThreading();
134 RefPtr
<VM
> vm
= group
? PassRefPtr
<VM
>(toJS(group
)) : VM::createContextGroup();
136 JSLockHolder
locker(vm
.get());
137 vm
->makeUsableFromMultipleThreads();
139 if (!globalObjectClass
) {
140 JSGlobalObject
* globalObject
= JSGlobalObject::create(*vm
, JSGlobalObject::createStructure(*vm
, jsNull()));
141 return JSGlobalContextRetain(toGlobalRef(globalObject
->globalExec()));
144 JSGlobalObject
* globalObject
= JSCallbackObject
<JSGlobalObject
>::create(*vm
, globalObjectClass
, JSCallbackObject
<JSGlobalObject
>::createStructure(*vm
, 0, jsNull()));
145 ExecState
* exec
= globalObject
->globalExec();
146 JSValue prototype
= globalObjectClass
->prototype(exec
);
148 prototype
= jsNull();
149 globalObject
->resetPrototype(*vm
, prototype
);
150 return JSGlobalContextRetain(toGlobalRef(exec
));
153 JSGlobalContextRef
JSGlobalContextRetain(JSGlobalContextRef ctx
)
155 ExecState
* exec
= toJS(ctx
);
156 JSLockHolder
locker(exec
);
159 gcProtect(exec
->vmEntryGlobalObject());
164 void JSGlobalContextRelease(JSGlobalContextRef ctx
)
166 ExecState
* exec
= toJS(ctx
);
167 JSLockHolder
locker(exec
);
170 bool protectCountIsZero
= Heap::heap(exec
->vmEntryGlobalObject())->unprotect(exec
->vmEntryGlobalObject());
171 if (protectCountIsZero
)
172 vm
.heap
.reportAbandonedObjectGraph();
176 JSObjectRef
JSContextGetGlobalObject(JSContextRef ctx
)
179 ASSERT_NOT_REACHED();
182 ExecState
* exec
= toJS(ctx
);
183 JSLockHolder
locker(exec
);
185 return toRef(jsCast
<JSObject
*>(exec
->lexicalGlobalObject()->methodTable()->toThis(exec
->lexicalGlobalObject(), exec
, NotStrictMode
)));
188 JSContextGroupRef
JSContextGetGroup(JSContextRef ctx
)
191 ASSERT_NOT_REACHED();
194 ExecState
* exec
= toJS(ctx
);
195 return toRef(&exec
->vm());
198 JSGlobalContextRef
JSContextGetGlobalContext(JSContextRef ctx
)
201 ASSERT_NOT_REACHED();
204 ExecState
* exec
= toJS(ctx
);
205 JSLockHolder
locker(exec
);
207 return toGlobalRef(exec
->lexicalGlobalObject()->globalExec());
210 JSStringRef
JSGlobalContextCopyName(JSGlobalContextRef ctx
)
213 ASSERT_NOT_REACHED();
217 ExecState
* exec
= toJS(ctx
);
218 JSLockHolder
locker(exec
);
220 String name
= exec
->vmEntryGlobalObject()->name();
224 return OpaqueJSString::create(name
).leakRef();
227 void JSGlobalContextSetName(JSGlobalContextRef ctx
, JSStringRef name
)
230 ASSERT_NOT_REACHED();
234 ExecState
* exec
= toJS(ctx
);
235 JSLockHolder
locker(exec
);
237 exec
->vmEntryGlobalObject()->setName(name
? name
->string() : String());
241 class BacktraceFunctor
{
243 BacktraceFunctor(StringBuilder
& builder
, unsigned remainingCapacityForFrameCapture
)
245 , m_remainingCapacityForFrameCapture(remainingCapacityForFrameCapture
)
249 StackVisitor::Status
operator()(StackVisitor
& visitor
)
251 if (m_remainingCapacityForFrameCapture
) {
252 // If callee is unknown, but we've not added any frame yet, we should
253 // still add the frame, because something called us, and gave us arguments.
254 JSObject
* callee
= visitor
->callee();
255 if (!callee
&& visitor
->index())
256 return StackVisitor::Done
;
258 StringBuilder
& builder
= m_builder
;
259 if (!builder
.isEmpty())
260 builder
.append('\n');
262 builder
.appendNumber(visitor
->index());
264 builder
.append(visitor
->functionName());
265 builder
.appendLiteral("() at ");
266 builder
.append(visitor
->sourceURL());
267 if (visitor
->isJSFrame()) {
270 unsigned unusedColumn
;
271 visitor
->computeLineAndColumn(lineNumber
, unusedColumn
);
272 builder
.appendNumber(lineNumber
);
276 return StackVisitor::Done
;
278 m_remainingCapacityForFrameCapture
--;
279 return StackVisitor::Continue
;
281 return StackVisitor::Done
;
285 StringBuilder
& m_builder
;
286 unsigned m_remainingCapacityForFrameCapture
;
289 JSStringRef
JSContextCreateBacktrace(JSContextRef ctx
, unsigned maxStackSize
)
292 ASSERT_NOT_REACHED();
295 ExecState
* exec
= toJS(ctx
);
296 JSLockHolder
lock(exec
);
297 StringBuilder builder
;
298 CallFrame
* frame
= exec
->vm().topCallFrame
;
300 ASSERT(maxStackSize
);
301 BacktraceFunctor
functor(builder
, maxStackSize
);
302 frame
->iterate(functor
);
304 return OpaqueJSString::create(builder
.toString()).leakRef();
307 bool JSGlobalContextGetRemoteInspectionEnabled(JSGlobalContextRef ctx
)
310 ASSERT_NOT_REACHED();
314 ExecState
* exec
= toJS(ctx
);
315 JSLockHolder
lock(exec
);
317 return exec
->vmEntryGlobalObject()->remoteDebuggingEnabled();
320 void JSGlobalContextSetRemoteInspectionEnabled(JSGlobalContextRef ctx
, bool enabled
)
323 ASSERT_NOT_REACHED();
327 ExecState
* exec
= toJS(ctx
);
328 JSLockHolder
lock(exec
);
330 exec
->vmEntryGlobalObject()->setRemoteDebuggingEnabled(enabled
);
333 bool JSGlobalContextGetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx
)
335 #if ENABLE(REMOTE_INSPECTOR)
337 ASSERT_NOT_REACHED();
341 ExecState
* exec
= toJS(ctx
);
342 JSLockHolder
lock(exec
);
344 JSGlobalObject
* globalObject
= exec
->vmEntryGlobalObject();
345 return globalObject
->inspectorController().includesNativeCallStackWhenReportingExceptions();
352 void JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx
, bool includesNativeCallStack
)
354 #if ENABLE(REMOTE_INSPECTOR)
356 ASSERT_NOT_REACHED();
360 ExecState
* exec
= toJS(ctx
);
361 JSLockHolder
lock(exec
);
363 JSGlobalObject
* globalObject
= exec
->vmEntryGlobalObject();
364 globalObject
->inspectorController().setIncludesNativeCallStackWhenReportingExceptions(includesNativeCallStack
);
367 UNUSED_PARAM(includesNativeCallStack
);
372 CFRunLoopRef
JSGlobalContextGetDebuggerRunLoop(JSGlobalContextRef ctx
)
374 #if ENABLE(REMOTE_INSPECTOR)
376 ASSERT_NOT_REACHED();
380 ExecState
* exec
= toJS(ctx
);
381 JSLockHolder
lock(exec
);
383 return exec
->vmEntryGlobalObject()->inspectorDebuggable().debuggerRunLoop();
390 void JSGlobalContextSetDebuggerRunLoop(JSGlobalContextRef ctx
, CFRunLoopRef runLoop
)
392 #if ENABLE(REMOTE_INSPECTOR)
394 ASSERT_NOT_REACHED();
398 ExecState
* exec
= toJS(ctx
);
399 JSLockHolder
lock(exec
);
401 exec
->vmEntryGlobalObject()->inspectorDebuggable().setDebuggerRunLoop(runLoop
);
404 UNUSED_PARAM(runLoop
);