]> git.saurik.com Git - apple/javascriptcore.git/blame_incremental - API/JSContextRef.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / API / JSContextRef.cpp
... / ...
CommitLineData
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
57static const int32_t webkitFirstVersionWithConcurrentGlobalContexts = 0x2100500; // 528.5.0
58#endif
59
60using namespace JSC;
61
62static RuntimeFlags javaScriptRuntimeFlags(const JSGlobalObject* globalObject)
63{
64 RuntimeFlags runtimeFlags = JSGlobalObject::javaScriptRuntimeFlags(globalObject);
65 runtimeFlags.setPromiseDisabled(true);
66 return runtimeFlags;
67}
68
69const 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
76JSContextGroupRef JSContextGroupCreate()
77{
78 initializeThreading();
79 return toRef(&VM::createContextGroup().leakRef());
80}
81
82JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group)
83{
84 toJS(group)->ref();
85 return group;
86}
87
88void JSContextGroupRelease(JSContextGroupRef group)
89{
90 VM& vm = *toJS(group);
91
92 JSLockHolder locker(&vm);
93 vm.deref();
94}
95
96static 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
104static 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
116void 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
129void 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
140JSGlobalContextRef 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
155JSGlobalContextRef 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
185JSGlobalContextRef 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
196void 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
208JSObjectRef 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
220JSContextGroupRef 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
230JSGlobalContextRef 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
242JSStringRef 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
259void 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
273class BacktraceFunctor {
274public:
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
316private:
317 StringBuilder& m_builder;
318 unsigned m_remainingCapacityForFrameCapture;
319};
320
321JSStringRef 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
339bool 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
352void 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
365bool 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
384void 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)
404CFRunLoopRef 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
422void 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)
442Inspector::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