]> git.saurik.com Git - apple/javascriptcore.git/blame - API/JSContextRef.cpp
JavaScriptCore-7600.1.4.15.12.tar.gz
[apple/javascriptcore.git] / API / JSContextRef.cpp
CommitLineData
b37bf2e1 1/*
81345200 2 * Copyright (C) 2006, 2007, 2013 Apple Inc. All rights reserved.
b37bf2e1
A
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
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.
12 *
81345200 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
b37bf2e1
A
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
81345200 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
b37bf2e1
A
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
81345200 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
b37bf2e1
A
24 */
25
26#include "config.h"
27#include "JSContextRef.h"
81345200 28#include "JSContextRefInternal.h"
b37bf2e1
A
29
30#include "APICast.h"
81345200 31#include "CallFrame.h"
9dae56ea 32#include "InitializeThreading.h"
b37bf2e1
A
33#include "JSCallbackObject.h"
34#include "JSClassRef.h"
35#include "JSGlobalObject.h"
9dae56ea 36#include "JSObject.h"
81345200 37#include "JSCInlines.h"
93a37866 38#include "SourceProvider.h"
81345200 39#include "StackVisitor.h"
93a37866 40#include <wtf/text/StringBuilder.h>
4e4e5a6f 41#include <wtf/text/StringHash.h>
b37bf2e1 42
81345200
A
43#if ENABLE(REMOTE_INSPECTOR)
44#include "JSGlobalObjectDebuggable.h"
45#include "JSGlobalObjectInspectorController.h"
46#endif
47
f9bf01c6 48#if OS(DARWIN)
9dae56ea
A
49#include <mach-o/dyld.h>
50
51static const int32_t webkitFirstVersionWithConcurrentGlobalContexts = 0x2100500; // 528.5.0
52#endif
53
54using namespace JSC;
55
6fe7ccc8
A
56// From the API's perspective, a context group remains alive iff
57// (a) it has been JSContextGroupRetained
58// OR
59// (b) one of its contexts has been JSContextRetained
60
9dae56ea
A
61JSContextGroupRef JSContextGroupCreate()
62{
63 initializeThreading();
93a37866 64 return toRef(VM::createContextGroup().leakRef());
9dae56ea
A
65}
66
67JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group)
68{
69 toJS(group)->ref();
70 return group;
71}
72
73void JSContextGroupRelease(JSContextGroupRef group)
74{
93a37866
A
75 VM& vm = *toJS(group);
76
81345200
A
77 JSLockHolder locker(&vm);
78 vm.deref();
93a37866
A
79}
80
81static bool internalScriptTimeoutCallback(ExecState* exec, void* callbackPtr, void* callbackData)
82{
83 JSShouldTerminateCallback callback = reinterpret_cast<JSShouldTerminateCallback>(callbackPtr);
84 JSContextRef contextRef = toRef(exec);
85 ASSERT(callback);
86 return callback(contextRef, callbackData);
87}
88
89void JSContextGroupSetExecutionTimeLimit(JSContextGroupRef group, double limit, JSShouldTerminateCallback callback, void* callbackData)
90{
91 VM& vm = *toJS(group);
81345200
A
92 JSLockHolder locker(&vm);
93 if (!vm.watchdog)
94 vm.watchdog = std::make_unique<Watchdog>();
95 Watchdog& watchdog = *vm.watchdog;
93a37866
A
96 if (callback) {
97 void* callbackPtr = reinterpret_cast<void*>(callback);
98 watchdog.setTimeLimit(vm, limit, internalScriptTimeoutCallback, callbackPtr, callbackData);
99 } else
100 watchdog.setTimeLimit(vm, limit);
101}
102
103void JSContextGroupClearExecutionTimeLimit(JSContextGroupRef group)
104{
105 VM& vm = *toJS(group);
81345200
A
106 JSLockHolder locker(&vm);
107 if (!vm.watchdog)
108 vm.watchdog = std::make_unique<Watchdog>();
109 Watchdog& watchdog = *vm.watchdog;
93a37866 110 watchdog.setTimeLimit(vm, std::numeric_limits<double>::infinity());
9dae56ea 111}
b37bf2e1 112
6fe7ccc8
A
113// From the API's perspective, a global context remains alive iff it has been JSGlobalContextRetained.
114
b37bf2e1
A
115JSGlobalContextRef JSGlobalContextCreate(JSClassRef globalObjectClass)
116{
9dae56ea 117 initializeThreading();
6fe7ccc8 118
f9bf01c6 119#if OS(DARWIN)
93a37866 120 // If the application was linked before JSGlobalContextCreate was changed to use a unique VM,
6fe7ccc8 121 // we use a shared one for backwards compatibility.
9dae56ea 122 if (NSVersionOfLinkTimeLibrary("JavaScriptCore") <= webkitFirstVersionWithConcurrentGlobalContexts) {
93a37866 123 return JSGlobalContextCreateInGroup(toRef(&VM::sharedInstance()), globalObjectClass);
9dae56ea 124 }
f9bf01c6 125#endif // OS(DARWIN)
9dae56ea
A
126
127 return JSGlobalContextCreateInGroup(0, globalObjectClass);
128}
129
130JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClassRef globalObjectClass)
131{
132 initializeThreading();
133
93a37866 134 RefPtr<VM> vm = group ? PassRefPtr<VM>(toJS(group)) : VM::createContextGroup();
9dae56ea 135
81345200 136 JSLockHolder locker(vm.get());
93a37866 137 vm->makeUsableFromMultipleThreads();
b37bf2e1
A
138
139 if (!globalObjectClass) {
93a37866 140 JSGlobalObject* globalObject = JSGlobalObject::create(*vm, JSGlobalObject::createStructure(*vm, jsNull()));
b37bf2e1
A
141 return JSGlobalContextRetain(toGlobalRef(globalObject->globalExec()));
142 }
143
93a37866 144 JSGlobalObject* globalObject = JSCallbackObject<JSGlobalObject>::create(*vm, globalObjectClass, JSCallbackObject<JSGlobalObject>::createStructure(*vm, 0, jsNull()));
9dae56ea 145 ExecState* exec = globalObject->globalExec();
ba379fdc 146 JSValue prototype = globalObjectClass->prototype(exec);
b37bf2e1
A
147 if (!prototype)
148 prototype = jsNull();
93a37866 149 globalObject->resetPrototype(*vm, prototype);
9dae56ea 150 return JSGlobalContextRetain(toGlobalRef(exec));
b37bf2e1
A
151}
152
153JSGlobalContextRef JSGlobalContextRetain(JSGlobalContextRef ctx)
154{
b37bf2e1 155 ExecState* exec = toJS(ctx);
81345200 156 JSLockHolder locker(exec);
9dae56ea 157
93a37866 158 VM& vm = exec->vm();
81345200 159 gcProtect(exec->vmEntryGlobalObject());
93a37866 160 vm.ref();
b37bf2e1
A
161 return ctx;
162}
163
164void JSGlobalContextRelease(JSGlobalContextRef ctx)
165{
b37bf2e1 166 ExecState* exec = toJS(ctx);
81345200 167 JSLockHolder locker(exec);
9dae56ea 168
81345200
A
169 VM& vm = exec->vm();
170 bool protectCountIsZero = Heap::heap(exec->vmEntryGlobalObject())->unprotect(exec->vmEntryGlobalObject());
171 if (protectCountIsZero)
172 vm.heap.reportAbandonedObjectGraph();
173 vm.deref();
b37bf2e1
A
174}
175
176JSObjectRef JSContextGetGlobalObject(JSContextRef ctx)
177{
93a37866
A
178 if (!ctx) {
179 ASSERT_NOT_REACHED();
180 return 0;
181 }
b37bf2e1 182 ExecState* exec = toJS(ctx);
81345200 183 JSLockHolder locker(exec);
9dae56ea 184
81345200 185 return toRef(jsCast<JSObject*>(exec->lexicalGlobalObject()->methodTable()->toThis(exec->lexicalGlobalObject(), exec, NotStrictMode)));
9dae56ea
A
186}
187
188JSContextGroupRef JSContextGetGroup(JSContextRef ctx)
189{
93a37866
A
190 if (!ctx) {
191 ASSERT_NOT_REACHED();
192 return 0;
193 }
9dae56ea 194 ExecState* exec = toJS(ctx);
93a37866 195 return toRef(&exec->vm());
b37bf2e1 196}
f9bf01c6
A
197
198JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx)
199{
93a37866
A
200 if (!ctx) {
201 ASSERT_NOT_REACHED();
202 return 0;
203 }
f9bf01c6 204 ExecState* exec = toJS(ctx);
81345200 205 JSLockHolder locker(exec);
f9bf01c6
A
206
207 return toGlobalRef(exec->lexicalGlobalObject()->globalExec());
208}
81345200
A
209
210JSStringRef JSGlobalContextCopyName(JSGlobalContextRef ctx)
211{
212 if (!ctx) {
213 ASSERT_NOT_REACHED();
214 return 0;
215 }
216
217 ExecState* exec = toJS(ctx);
218 JSLockHolder locker(exec);
219
220 String name = exec->vmEntryGlobalObject()->name();
221 if (name.isNull())
222 return 0;
223
224 return OpaqueJSString::create(name).leakRef();
225}
226
227void JSGlobalContextSetName(JSGlobalContextRef ctx, JSStringRef name)
228{
229 if (!ctx) {
230 ASSERT_NOT_REACHED();
231 return;
232 }
233
234 ExecState* exec = toJS(ctx);
235 JSLockHolder locker(exec);
236
237 exec->vmEntryGlobalObject()->setName(name ? name->string() : String());
238}
239
240
241class BacktraceFunctor {
242public:
243 BacktraceFunctor(StringBuilder& builder, unsigned remainingCapacityForFrameCapture)
244 : m_builder(builder)
245 , m_remainingCapacityForFrameCapture(remainingCapacityForFrameCapture)
246 {
247 }
248
249 StackVisitor::Status operator()(StackVisitor& visitor)
250 {
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;
257
258 StringBuilder& builder = m_builder;
259 if (!builder.isEmpty())
260 builder.append('\n');
261 builder.append('#');
262 builder.appendNumber(visitor->index());
263 builder.append(' ');
264 builder.append(visitor->functionName());
265 builder.appendLiteral("() at ");
266 builder.append(visitor->sourceURL());
267 if (visitor->isJSFrame()) {
268 builder.append(':');
269 unsigned lineNumber;
270 unsigned unusedColumn;
271 visitor->computeLineAndColumn(lineNumber, unusedColumn);
272 builder.appendNumber(lineNumber);
273 }
274
275 if (!callee)
276 return StackVisitor::Done;
277
278 m_remainingCapacityForFrameCapture--;
279 return StackVisitor::Continue;
280 }
281 return StackVisitor::Done;
282 }
283
284private:
285 StringBuilder& m_builder;
286 unsigned m_remainingCapacityForFrameCapture;
287};
288
14957cd0
A
289JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize)
290{
93a37866
A
291 if (!ctx) {
292 ASSERT_NOT_REACHED();
293 return 0;
294 }
14957cd0 295 ExecState* exec = toJS(ctx);
6fe7ccc8 296 JSLockHolder lock(exec);
93a37866 297 StringBuilder builder;
81345200
A
298 CallFrame* frame = exec->vm().topCallFrame;
299
300 ASSERT(maxStackSize);
301 BacktraceFunctor functor(builder, maxStackSize);
302 frame->iterate(functor);
303
93a37866 304 return OpaqueJSString::create(builder.toString()).leakRef();
14957cd0
A
305}
306
81345200
A
307bool JSGlobalContextGetRemoteInspectionEnabled(JSGlobalContextRef ctx)
308{
309 if (!ctx) {
310 ASSERT_NOT_REACHED();
311 return false;
312 }
313
314 ExecState* exec = toJS(ctx);
315 JSLockHolder lock(exec);
316
317 return exec->vmEntryGlobalObject()->remoteDebuggingEnabled();
318}
14957cd0 319
81345200
A
320void JSGlobalContextSetRemoteInspectionEnabled(JSGlobalContextRef ctx, bool enabled)
321{
322 if (!ctx) {
323 ASSERT_NOT_REACHED();
324 return;
325 }
326
327 ExecState* exec = toJS(ctx);
328 JSLockHolder lock(exec);
329
330 exec->vmEntryGlobalObject()->setRemoteDebuggingEnabled(enabled);
331}
332
333bool JSGlobalContextGetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx)
334{
335#if ENABLE(REMOTE_INSPECTOR)
336 if (!ctx) {
337 ASSERT_NOT_REACHED();
338 return false;
339 }
340
341 ExecState* exec = toJS(ctx);
342 JSLockHolder lock(exec);
343
344 JSGlobalObject* globalObject = exec->vmEntryGlobalObject();
345 return globalObject->inspectorController().includesNativeCallStackWhenReportingExceptions();
346#else
347 UNUSED_PARAM(ctx);
348 return false;
349#endif
350}
351
352void JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx, bool includesNativeCallStack)
353{
354#if ENABLE(REMOTE_INSPECTOR)
355 if (!ctx) {
356 ASSERT_NOT_REACHED();
357 return;
358 }
359
360 ExecState* exec = toJS(ctx);
361 JSLockHolder lock(exec);
362
363 JSGlobalObject* globalObject = exec->vmEntryGlobalObject();
364 globalObject->inspectorController().setIncludesNativeCallStackWhenReportingExceptions(includesNativeCallStack);
365#else
366 UNUSED_PARAM(ctx);
367 UNUSED_PARAM(includesNativeCallStack);
368#endif
369}
370
371#if USE(CF)
372CFRunLoopRef JSGlobalContextGetDebuggerRunLoop(JSGlobalContextRef ctx)
373{
374#if ENABLE(REMOTE_INSPECTOR)
375 if (!ctx) {
376 ASSERT_NOT_REACHED();
377 return nullptr;
378 }
379
380 ExecState* exec = toJS(ctx);
381 JSLockHolder lock(exec);
382
383 return exec->vmEntryGlobalObject()->inspectorDebuggable().debuggerRunLoop();
384#else
385 UNUSED_PARAM(ctx);
386 return nullptr;
387#endif
388}
389
390void JSGlobalContextSetDebuggerRunLoop(JSGlobalContextRef ctx, CFRunLoopRef runLoop)
391{
392#if ENABLE(REMOTE_INSPECTOR)
393 if (!ctx) {
394 ASSERT_NOT_REACHED();
395 return;
396 }
397
398 ExecState* exec = toJS(ctx);
399 JSLockHolder lock(exec);
400
401 exec->vmEntryGlobalObject()->inspectorDebuggable().setDebuggerRunLoop(runLoop);
402#else
403 UNUSED_PARAM(ctx);
404 UNUSED_PARAM(runLoop);
405#endif
406}
407#endif