]> git.saurik.com Git - apple/javascriptcore.git/blob - API/JSContextRef.cpp
JavaScriptCore-7600.1.4.15.12.tar.gz
[apple/javascriptcore.git] / API / JSContextRef.cpp
1 /*
2 * Copyright (C) 2006, 2007, 2013 Apple Inc. All rights reserved.
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 *
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.
24 */
25
26 #include "config.h"
27 #include "JSContextRef.h"
28 #include "JSContextRefInternal.h"
29
30 #include "APICast.h"
31 #include "CallFrame.h"
32 #include "InitializeThreading.h"
33 #include "JSCallbackObject.h"
34 #include "JSClassRef.h"
35 #include "JSGlobalObject.h"
36 #include "JSObject.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>
42
43 #if ENABLE(REMOTE_INSPECTOR)
44 #include "JSGlobalObjectDebuggable.h"
45 #include "JSGlobalObjectInspectorController.h"
46 #endif
47
48 #if OS(DARWIN)
49 #include <mach-o/dyld.h>
50
51 static const int32_t webkitFirstVersionWithConcurrentGlobalContexts = 0x2100500; // 528.5.0
52 #endif
53
54 using namespace JSC;
55
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
61 JSContextGroupRef JSContextGroupCreate()
62 {
63 initializeThreading();
64 return toRef(VM::createContextGroup().leakRef());
65 }
66
67 JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group)
68 {
69 toJS(group)->ref();
70 return group;
71 }
72
73 void JSContextGroupRelease(JSContextGroupRef group)
74 {
75 VM& vm = *toJS(group);
76
77 JSLockHolder locker(&vm);
78 vm.deref();
79 }
80
81 static 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
89 void JSContextGroupSetExecutionTimeLimit(JSContextGroupRef group, double limit, JSShouldTerminateCallback callback, void* callbackData)
90 {
91 VM& vm = *toJS(group);
92 JSLockHolder locker(&vm);
93 if (!vm.watchdog)
94 vm.watchdog = std::make_unique<Watchdog>();
95 Watchdog& watchdog = *vm.watchdog;
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
103 void JSContextGroupClearExecutionTimeLimit(JSContextGroupRef group)
104 {
105 VM& vm = *toJS(group);
106 JSLockHolder locker(&vm);
107 if (!vm.watchdog)
108 vm.watchdog = std::make_unique<Watchdog>();
109 Watchdog& watchdog = *vm.watchdog;
110 watchdog.setTimeLimit(vm, std::numeric_limits<double>::infinity());
111 }
112
113 // From the API's perspective, a global context remains alive iff it has been JSGlobalContextRetained.
114
115 JSGlobalContextRef JSGlobalContextCreate(JSClassRef globalObjectClass)
116 {
117 initializeThreading();
118
119 #if OS(DARWIN)
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);
124 }
125 #endif // OS(DARWIN)
126
127 return JSGlobalContextCreateInGroup(0, globalObjectClass);
128 }
129
130 JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClassRef globalObjectClass)
131 {
132 initializeThreading();
133
134 RefPtr<VM> vm = group ? PassRefPtr<VM>(toJS(group)) : VM::createContextGroup();
135
136 JSLockHolder locker(vm.get());
137 vm->makeUsableFromMultipleThreads();
138
139 if (!globalObjectClass) {
140 JSGlobalObject* globalObject = JSGlobalObject::create(*vm, JSGlobalObject::createStructure(*vm, jsNull()));
141 return JSGlobalContextRetain(toGlobalRef(globalObject->globalExec()));
142 }
143
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);
147 if (!prototype)
148 prototype = jsNull();
149 globalObject->resetPrototype(*vm, prototype);
150 return JSGlobalContextRetain(toGlobalRef(exec));
151 }
152
153 JSGlobalContextRef JSGlobalContextRetain(JSGlobalContextRef ctx)
154 {
155 ExecState* exec = toJS(ctx);
156 JSLockHolder locker(exec);
157
158 VM& vm = exec->vm();
159 gcProtect(exec->vmEntryGlobalObject());
160 vm.ref();
161 return ctx;
162 }
163
164 void JSGlobalContextRelease(JSGlobalContextRef ctx)
165 {
166 ExecState* exec = toJS(ctx);
167 JSLockHolder locker(exec);
168
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();
174 }
175
176 JSObjectRef JSContextGetGlobalObject(JSContextRef ctx)
177 {
178 if (!ctx) {
179 ASSERT_NOT_REACHED();
180 return 0;
181 }
182 ExecState* exec = toJS(ctx);
183 JSLockHolder locker(exec);
184
185 return toRef(jsCast<JSObject*>(exec->lexicalGlobalObject()->methodTable()->toThis(exec->lexicalGlobalObject(), exec, NotStrictMode)));
186 }
187
188 JSContextGroupRef JSContextGetGroup(JSContextRef ctx)
189 {
190 if (!ctx) {
191 ASSERT_NOT_REACHED();
192 return 0;
193 }
194 ExecState* exec = toJS(ctx);
195 return toRef(&exec->vm());
196 }
197
198 JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx)
199 {
200 if (!ctx) {
201 ASSERT_NOT_REACHED();
202 return 0;
203 }
204 ExecState* exec = toJS(ctx);
205 JSLockHolder locker(exec);
206
207 return toGlobalRef(exec->lexicalGlobalObject()->globalExec());
208 }
209
210 JSStringRef 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
227 void 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
241 class BacktraceFunctor {
242 public:
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
284 private:
285 StringBuilder& m_builder;
286 unsigned m_remainingCapacityForFrameCapture;
287 };
288
289 JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize)
290 {
291 if (!ctx) {
292 ASSERT_NOT_REACHED();
293 return 0;
294 }
295 ExecState* exec = toJS(ctx);
296 JSLockHolder lock(exec);
297 StringBuilder builder;
298 CallFrame* frame = exec->vm().topCallFrame;
299
300 ASSERT(maxStackSize);
301 BacktraceFunctor functor(builder, maxStackSize);
302 frame->iterate(functor);
303
304 return OpaqueJSString::create(builder.toString()).leakRef();
305 }
306
307 bool 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 }
319
320 void 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
333 bool 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
352 void 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)
372 CFRunLoopRef 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
390 void 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