]> git.saurik.com Git - apple/javascriptcore.git/blob - API/JSContextRef.cpp
4976c29aeeef91393bb0a8729e500647264c1f79
[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 "RuntimeFlags.h"
39 #include "SourceProvider.h"
40 #include "StackVisitor.h"
41 #include <wtf/text/StringBuilder.h>
42 #include <wtf/text/StringHash.h>
43
44 #if ENABLE(REMOTE_INSPECTOR)
45 #include "JSGlobalObjectDebuggable.h"
46 #include "JSGlobalObjectInspectorController.h"
47 #include "JSRemoteInspector.h"
48 #endif
49
50 #if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
51 #include "JSContextRefInspectorSupport.h"
52 #endif
53
54 #if OS(DARWIN)
55 #include <mach-o/dyld.h>
56
57 static const int32_t webkitFirstVersionWithConcurrentGlobalContexts = 0x2100500; // 528.5.0
58 #endif
59
60 using namespace JSC;
61
62 static RuntimeFlags javaScriptRuntimeFlags(const JSGlobalObject* globalObject)
63 {
64 RuntimeFlags runtimeFlags = JSGlobalObject::javaScriptRuntimeFlags(globalObject);
65 runtimeFlags.setPromiseDisabled(true);
66 return runtimeFlags;
67 }
68
69 const GlobalObjectMethodTable JSC::javaScriptCoreAPIGlobalObjectMethodTable = { &JSGlobalObject::allowsAccessFrom, &JSGlobalObject::supportsProfiling, &JSGlobalObject::supportsRichSourceInfo, &JSGlobalObject::shouldInterruptScript, &javaScriptRuntimeFlags, nullptr, &JSGlobalObject::shouldInterruptScriptBeforeTimeout };
70
71 // From the API's perspective, a context group remains alive iff
72 // (a) it has been JSContextGroupRetained
73 // OR
74 // (b) one of its contexts has been JSContextRetained
75
76 JSContextGroupRef JSContextGroupCreate()
77 {
78 initializeThreading();
79 return toRef(&VM::createContextGroup().leakRef());
80 }
81
82 JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group)
83 {
84 toJS(group)->ref();
85 return group;
86 }
87
88 void JSContextGroupRelease(JSContextGroupRef group)
89 {
90 VM& vm = *toJS(group);
91
92 JSLockHolder locker(&vm);
93 vm.deref();
94 }
95
96 static bool internalScriptTimeoutCallback(ExecState* exec, void* callbackPtr, void* callbackData)
97 {
98 JSShouldTerminateCallback callback = reinterpret_cast<JSShouldTerminateCallback>(callbackPtr);
99 JSContextRef contextRef = toRef(exec);
100 ASSERT(callback);
101 return callback(contextRef, callbackData);
102 }
103
104 static void createWatchdogIfNeeded(VM& vm)
105 {
106 if (!vm.watchdog) {
107 vm.watchdog = std::make_unique<Watchdog>();
108
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());
113 }
114 }
115
116 void JSContextGroupSetExecutionTimeLimit(JSContextGroupRef group, double limit, JSShouldTerminateCallback callback, void* callbackData)
117 {
118 VM& vm = *toJS(group);
119 JSLockHolder locker(&vm);
120 createWatchdogIfNeeded(vm);
121 Watchdog& watchdog = *vm.watchdog;
122 if (callback) {
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);
125 } else
126 watchdog.setTimeLimit(vm, std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::duration<double>(limit)));
127 }
128
129 void JSContextGroupClearExecutionTimeLimit(JSContextGroupRef group)
130 {
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());
136 }
137
138 // From the API's perspective, a global context remains alive iff it has been JSGlobalContextRetained.
139
140 JSGlobalContextRef JSGlobalContextCreate(JSClassRef globalObjectClass)
141 {
142 initializeThreading();
143
144 #if OS(DARWIN)
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);
149 }
150 #endif // OS(DARWIN)
151
152 return JSGlobalContextCreateInGroup(0, globalObjectClass);
153 }
154
155 JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClassRef globalObjectClass)
156 {
157 initializeThreading();
158
159 RefPtr<VM> vm = group ? PassRefPtr<VM>(toJS(group)) : VM::createContextGroup();
160
161 JSLockHolder locker(vm.get());
162
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);
168 #endif
169 return JSGlobalContextRetain(toGlobalRef(globalObject->globalExec()));
170 }
171
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);
175 if (!prototype)
176 prototype = jsNull();
177 globalObject->resetPrototype(*vm, prototype);
178 #if ENABLE(REMOTE_INSPECTOR)
179 if (JSRemoteInspectorGetInspectionEnabledByDefault())
180 globalObject->setRemoteDebuggingEnabled(true);
181 #endif
182 return JSGlobalContextRetain(toGlobalRef(exec));
183 }
184
185 JSGlobalContextRef JSGlobalContextRetain(JSGlobalContextRef ctx)
186 {
187 ExecState* exec = toJS(ctx);
188 JSLockHolder locker(exec);
189
190 VM& vm = exec->vm();
191 gcProtect(exec->vmEntryGlobalObject());
192 vm.ref();
193 return ctx;
194 }
195
196 void JSGlobalContextRelease(JSGlobalContextRef ctx)
197 {
198 ExecState* exec = toJS(ctx);
199 JSLockHolder locker(exec);
200
201 VM& vm = exec->vm();
202 bool protectCountIsZero = Heap::heap(exec->vmEntryGlobalObject())->unprotect(exec->vmEntryGlobalObject());
203 if (protectCountIsZero)
204 vm.heap.reportAbandonedObjectGraph();
205 vm.deref();
206 }
207
208 JSObjectRef JSContextGetGlobalObject(JSContextRef ctx)
209 {
210 if (!ctx) {
211 ASSERT_NOT_REACHED();
212 return 0;
213 }
214 ExecState* exec = toJS(ctx);
215 JSLockHolder locker(exec);
216
217 return toRef(jsCast<JSObject*>(exec->lexicalGlobalObject()->methodTable()->toThis(exec->lexicalGlobalObject(), exec, NotStrictMode)));
218 }
219
220 JSContextGroupRef JSContextGetGroup(JSContextRef ctx)
221 {
222 if (!ctx) {
223 ASSERT_NOT_REACHED();
224 return 0;
225 }
226 ExecState* exec = toJS(ctx);
227 return toRef(&exec->vm());
228 }
229
230 JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx)
231 {
232 if (!ctx) {
233 ASSERT_NOT_REACHED();
234 return 0;
235 }
236 ExecState* exec = toJS(ctx);
237 JSLockHolder locker(exec);
238
239 return toGlobalRef(exec->lexicalGlobalObject()->globalExec());
240 }
241
242 JSStringRef JSGlobalContextCopyName(JSGlobalContextRef ctx)
243 {
244 if (!ctx) {
245 ASSERT_NOT_REACHED();
246 return 0;
247 }
248
249 ExecState* exec = toJS(ctx);
250 JSLockHolder locker(exec);
251
252 String name = exec->vmEntryGlobalObject()->name();
253 if (name.isNull())
254 return 0;
255
256 return OpaqueJSString::create(name).leakRef();
257 }
258
259 void JSGlobalContextSetName(JSGlobalContextRef ctx, JSStringRef name)
260 {
261 if (!ctx) {
262 ASSERT_NOT_REACHED();
263 return;
264 }
265
266 ExecState* exec = toJS(ctx);
267 JSLockHolder locker(exec);
268
269 exec->vmEntryGlobalObject()->setName(name ? name->string() : String());
270 }
271
272
273 class BacktraceFunctor {
274 public:
275 BacktraceFunctor(StringBuilder& builder, unsigned remainingCapacityForFrameCapture)
276 : m_builder(builder)
277 , m_remainingCapacityForFrameCapture(remainingCapacityForFrameCapture)
278 {
279 }
280
281 StackVisitor::Status operator()(StackVisitor& visitor)
282 {
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;
289
290 StringBuilder& builder = m_builder;
291 if (!builder.isEmpty())
292 builder.append('\n');
293 builder.append('#');
294 builder.appendNumber(visitor->index());
295 builder.append(' ');
296 builder.append(visitor->functionName());
297 builder.appendLiteral("() at ");
298 builder.append(visitor->sourceURL());
299 if (visitor->isJSFrame()) {
300 builder.append(':');
301 unsigned lineNumber;
302 unsigned unusedColumn;
303 visitor->computeLineAndColumn(lineNumber, unusedColumn);
304 builder.appendNumber(lineNumber);
305 }
306
307 if (!callee)
308 return StackVisitor::Done;
309
310 m_remainingCapacityForFrameCapture--;
311 return StackVisitor::Continue;
312 }
313 return StackVisitor::Done;
314 }
315
316 private:
317 StringBuilder& m_builder;
318 unsigned m_remainingCapacityForFrameCapture;
319 };
320
321 JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize)
322 {
323 if (!ctx) {
324 ASSERT_NOT_REACHED();
325 return 0;
326 }
327 ExecState* exec = toJS(ctx);
328 JSLockHolder lock(exec);
329 StringBuilder builder;
330 CallFrame* frame = exec->vm().topCallFrame;
331
332 ASSERT(maxStackSize);
333 BacktraceFunctor functor(builder, maxStackSize);
334 frame->iterate(functor);
335
336 return OpaqueJSString::create(builder.toString()).leakRef();
337 }
338
339 bool JSGlobalContextGetRemoteInspectionEnabled(JSGlobalContextRef ctx)
340 {
341 if (!ctx) {
342 ASSERT_NOT_REACHED();
343 return false;
344 }
345
346 ExecState* exec = toJS(ctx);
347 JSLockHolder lock(exec);
348
349 return exec->vmEntryGlobalObject()->remoteDebuggingEnabled();
350 }
351
352 void JSGlobalContextSetRemoteInspectionEnabled(JSGlobalContextRef ctx, bool enabled)
353 {
354 if (!ctx) {
355 ASSERT_NOT_REACHED();
356 return;
357 }
358
359 ExecState* exec = toJS(ctx);
360 JSLockHolder lock(exec);
361
362 exec->vmEntryGlobalObject()->setRemoteDebuggingEnabled(enabled);
363 }
364
365 bool JSGlobalContextGetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx)
366 {
367 #if ENABLE(REMOTE_INSPECTOR)
368 if (!ctx) {
369 ASSERT_NOT_REACHED();
370 return false;
371 }
372
373 ExecState* exec = toJS(ctx);
374 JSLockHolder lock(exec);
375
376 JSGlobalObject* globalObject = exec->vmEntryGlobalObject();
377 return globalObject->inspectorController().includesNativeCallStackWhenReportingExceptions();
378 #else
379 UNUSED_PARAM(ctx);
380 return false;
381 #endif
382 }
383
384 void JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx, bool includesNativeCallStack)
385 {
386 #if ENABLE(REMOTE_INSPECTOR)
387 if (!ctx) {
388 ASSERT_NOT_REACHED();
389 return;
390 }
391
392 ExecState* exec = toJS(ctx);
393 JSLockHolder lock(exec);
394
395 JSGlobalObject* globalObject = exec->vmEntryGlobalObject();
396 globalObject->inspectorController().setIncludesNativeCallStackWhenReportingExceptions(includesNativeCallStack);
397 #else
398 UNUSED_PARAM(ctx);
399 UNUSED_PARAM(includesNativeCallStack);
400 #endif
401 }
402
403 #if USE(CF)
404 CFRunLoopRef JSGlobalContextGetDebuggerRunLoop(JSGlobalContextRef ctx)
405 {
406 #if ENABLE(REMOTE_INSPECTOR)
407 if (!ctx) {
408 ASSERT_NOT_REACHED();
409 return nullptr;
410 }
411
412 ExecState* exec = toJS(ctx);
413 JSLockHolder lock(exec);
414
415 return exec->vmEntryGlobalObject()->inspectorDebuggable().debuggerRunLoop();
416 #else
417 UNUSED_PARAM(ctx);
418 return nullptr;
419 #endif
420 }
421
422 void JSGlobalContextSetDebuggerRunLoop(JSGlobalContextRef ctx, CFRunLoopRef runLoop)
423 {
424 #if ENABLE(REMOTE_INSPECTOR)
425 if (!ctx) {
426 ASSERT_NOT_REACHED();
427 return;
428 }
429
430 ExecState* exec = toJS(ctx);
431 JSLockHolder lock(exec);
432
433 exec->vmEntryGlobalObject()->inspectorDebuggable().setDebuggerRunLoop(runLoop);
434 #else
435 UNUSED_PARAM(ctx);
436 UNUSED_PARAM(runLoop);
437 #endif
438 }
439 #endif // USE(CF)
440
441 #if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
442 Inspector::AugmentableInspectorController* JSGlobalContextGetAugmentableInspectorController(JSGlobalContextRef ctx)
443 {
444 if (!ctx) {
445 ASSERT_NOT_REACHED();
446 return nullptr;
447 }
448
449 ExecState* exec = toJS(ctx);
450 JSLockHolder lock(exec);
451
452 return &exec->vmEntryGlobalObject()->inspectorController();
453 }
454 #endif