]> git.saurik.com Git - apple/javascriptcore.git/blame - API/JSContextRef.cpp
JavaScriptCore-7601.1.46.3.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"
ed1e77d3 38#include "RuntimeFlags.h"
93a37866 39#include "SourceProvider.h"
81345200 40#include "StackVisitor.h"
93a37866 41#include <wtf/text/StringBuilder.h>
4e4e5a6f 42#include <wtf/text/StringHash.h>
b37bf2e1 43
81345200
A
44#if ENABLE(REMOTE_INSPECTOR)
45#include "JSGlobalObjectDebuggable.h"
46#include "JSGlobalObjectInspectorController.h"
ed1e77d3
A
47#include "JSRemoteInspector.h"
48#endif
49
50#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
51#include "JSContextRefInspectorSupport.h"
81345200
A
52#endif
53
f9bf01c6 54#if OS(DARWIN)
9dae56ea
A
55#include <mach-o/dyld.h>
56
57static const int32_t webkitFirstVersionWithConcurrentGlobalContexts = 0x2100500; // 528.5.0
58#endif
59
60using namespace JSC;
61
ed1e77d3
A
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
6fe7ccc8
A
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
9dae56ea
A
76JSContextGroupRef JSContextGroupCreate()
77{
78 initializeThreading();
ed1e77d3 79 return toRef(&VM::createContextGroup().leakRef());
9dae56ea
A
80}
81
82JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group)
83{
84 toJS(group)->ref();
85 return group;
86}
87
88void JSContextGroupRelease(JSContextGroupRef group)
89{
93a37866
A
90 VM& vm = *toJS(group);
91
81345200
A
92 JSLockHolder locker(&vm);
93 vm.deref();
93a37866
A
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
ed1e77d3
A
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
93a37866
A
116void JSContextGroupSetExecutionTimeLimit(JSContextGroupRef group, double limit, JSShouldTerminateCallback callback, void* callbackData)
117{
118 VM& vm = *toJS(group);
81345200 119 JSLockHolder locker(&vm);
ed1e77d3 120 createWatchdogIfNeeded(vm);
81345200 121 Watchdog& watchdog = *vm.watchdog;
93a37866
A
122 if (callback) {
123 void* callbackPtr = reinterpret_cast<void*>(callback);
ed1e77d3 124 watchdog.setTimeLimit(vm, std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::duration<double>(limit)), internalScriptTimeoutCallback, callbackPtr, callbackData);
93a37866 125 } else
ed1e77d3 126 watchdog.setTimeLimit(vm, std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::duration<double>(limit)));
93a37866
A
127}
128
129void JSContextGroupClearExecutionTimeLimit(JSContextGroupRef group)
130{
131 VM& vm = *toJS(group);
81345200 132 JSLockHolder locker(&vm);
ed1e77d3 133 createWatchdogIfNeeded(vm);
81345200 134 Watchdog& watchdog = *vm.watchdog;
ed1e77d3 135 watchdog.setTimeLimit(vm, std::chrono::microseconds::max());
9dae56ea 136}
b37bf2e1 137
6fe7ccc8
A
138// From the API's perspective, a global context remains alive iff it has been JSGlobalContextRetained.
139
b37bf2e1
A
140JSGlobalContextRef JSGlobalContextCreate(JSClassRef globalObjectClass)
141{
9dae56ea 142 initializeThreading();
6fe7ccc8 143
f9bf01c6 144#if OS(DARWIN)
93a37866 145 // If the application was linked before JSGlobalContextCreate was changed to use a unique VM,
6fe7ccc8 146 // we use a shared one for backwards compatibility.
9dae56ea 147 if (NSVersionOfLinkTimeLibrary("JavaScriptCore") <= webkitFirstVersionWithConcurrentGlobalContexts) {
93a37866 148 return JSGlobalContextCreateInGroup(toRef(&VM::sharedInstance()), globalObjectClass);
9dae56ea 149 }
f9bf01c6 150#endif // OS(DARWIN)
9dae56ea
A
151
152 return JSGlobalContextCreateInGroup(0, globalObjectClass);
153}
154
155JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClassRef globalObjectClass)
156{
157 initializeThreading();
158
93a37866 159 RefPtr<VM> vm = group ? PassRefPtr<VM>(toJS(group)) : VM::createContextGroup();
9dae56ea 160
81345200 161 JSLockHolder locker(vm.get());
b37bf2e1
A
162
163 if (!globalObjectClass) {
ed1e77d3
A
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
b37bf2e1
A
169 return JSGlobalContextRetain(toGlobalRef(globalObject->globalExec()));
170 }
171
93a37866 172 JSGlobalObject* globalObject = JSCallbackObject<JSGlobalObject>::create(*vm, globalObjectClass, JSCallbackObject<JSGlobalObject>::createStructure(*vm, 0, jsNull()));
9dae56ea 173 ExecState* exec = globalObject->globalExec();
ba379fdc 174 JSValue prototype = globalObjectClass->prototype(exec);
b37bf2e1
A
175 if (!prototype)
176 prototype = jsNull();
93a37866 177 globalObject->resetPrototype(*vm, prototype);
ed1e77d3
A
178#if ENABLE(REMOTE_INSPECTOR)
179 if (JSRemoteInspectorGetInspectionEnabledByDefault())
180 globalObject->setRemoteDebuggingEnabled(true);
181#endif
9dae56ea 182 return JSGlobalContextRetain(toGlobalRef(exec));
b37bf2e1
A
183}
184
185JSGlobalContextRef JSGlobalContextRetain(JSGlobalContextRef ctx)
186{
b37bf2e1 187 ExecState* exec = toJS(ctx);
81345200 188 JSLockHolder locker(exec);
9dae56ea 189
93a37866 190 VM& vm = exec->vm();
81345200 191 gcProtect(exec->vmEntryGlobalObject());
93a37866 192 vm.ref();
b37bf2e1
A
193 return ctx;
194}
195
196void JSGlobalContextRelease(JSGlobalContextRef ctx)
197{
b37bf2e1 198 ExecState* exec = toJS(ctx);
81345200 199 JSLockHolder locker(exec);
9dae56ea 200
81345200
A
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();
b37bf2e1
A
206}
207
208JSObjectRef JSContextGetGlobalObject(JSContextRef ctx)
209{
93a37866
A
210 if (!ctx) {
211 ASSERT_NOT_REACHED();
212 return 0;
213 }
b37bf2e1 214 ExecState* exec = toJS(ctx);
81345200 215 JSLockHolder locker(exec);
9dae56ea 216
81345200 217 return toRef(jsCast<JSObject*>(exec->lexicalGlobalObject()->methodTable()->toThis(exec->lexicalGlobalObject(), exec, NotStrictMode)));
9dae56ea
A
218}
219
220JSContextGroupRef JSContextGetGroup(JSContextRef ctx)
221{
93a37866
A
222 if (!ctx) {
223 ASSERT_NOT_REACHED();
224 return 0;
225 }
9dae56ea 226 ExecState* exec = toJS(ctx);
93a37866 227 return toRef(&exec->vm());
b37bf2e1 228}
f9bf01c6
A
229
230JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx)
231{
93a37866
A
232 if (!ctx) {
233 ASSERT_NOT_REACHED();
234 return 0;
235 }
f9bf01c6 236 ExecState* exec = toJS(ctx);
81345200 237 JSLockHolder locker(exec);
f9bf01c6
A
238
239 return toGlobalRef(exec->lexicalGlobalObject()->globalExec());
240}
81345200
A
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
14957cd0
A
321JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize)
322{
93a37866
A
323 if (!ctx) {
324 ASSERT_NOT_REACHED();
325 return 0;
326 }
14957cd0 327 ExecState* exec = toJS(ctx);
6fe7ccc8 328 JSLockHolder lock(exec);
93a37866 329 StringBuilder builder;
81345200
A
330 CallFrame* frame = exec->vm().topCallFrame;
331
332 ASSERT(maxStackSize);
333 BacktraceFunctor functor(builder, maxStackSize);
334 frame->iterate(functor);
335
93a37866 336 return OpaqueJSString::create(builder.toString()).leakRef();
14957cd0
A
337}
338
81345200
A
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}
14957cd0 351
81345200
A
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}
ed1e77d3
A
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}
81345200 454#endif