]> git.saurik.com Git - apple/javascriptcore.git/blame - API/JSContextRef.cpp
JavaScriptCore-1218.35.tar.gz
[apple/javascriptcore.git] / API / JSContextRef.cpp
CommitLineData
b37bf2e1
A
1/*
2 * Copyright (C) 2006, 2007 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 COMPUTER, 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 COMPUTER, 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"
f9bf01c6 28#include "JSContextRefPrivate.h"
b37bf2e1
A
29
30#include "APICast.h"
9dae56ea 31#include "InitializeThreading.h"
14957cd0
A
32#include <interpreter/CallFrame.h>
33#include <interpreter/Interpreter.h>
b37bf2e1
A
34#include "JSCallbackObject.h"
35#include "JSClassRef.h"
36#include "JSGlobalObject.h"
9dae56ea 37#include "JSObject.h"
93a37866
A
38#include "Operations.h"
39#include "SourceProvider.h"
40#include <wtf/text/StringBuilder.h>
4e4e5a6f 41#include <wtf/text/StringHash.h>
b37bf2e1 42
f9bf01c6 43#if OS(DARWIN)
9dae56ea
A
44#include <mach-o/dyld.h>
45
46static const int32_t webkitFirstVersionWithConcurrentGlobalContexts = 0x2100500; // 528.5.0
47#endif
48
49using namespace JSC;
50
6fe7ccc8
A
51// From the API's perspective, a context group remains alive iff
52// (a) it has been JSContextGroupRetained
53// OR
54// (b) one of its contexts has been JSContextRetained
55
9dae56ea
A
56JSContextGroupRef JSContextGroupCreate()
57{
58 initializeThreading();
93a37866 59 return toRef(VM::createContextGroup().leakRef());
9dae56ea
A
60}
61
62JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group)
63{
64 toJS(group)->ref();
65 return group;
66}
67
68void JSContextGroupRelease(JSContextGroupRef group)
69{
93a37866
A
70 IdentifierTable* savedIdentifierTable;
71 VM& vm = *toJS(group);
72
73 {
74 JSLockHolder lock(vm);
75 savedIdentifierTable = wtfThreadData().setCurrentIdentifierTable(vm.identifierTable);
76 vm.deref();
77 }
78
79 wtfThreadData().setCurrentIdentifierTable(savedIdentifierTable);
80}
81
82static bool internalScriptTimeoutCallback(ExecState* exec, void* callbackPtr, void* callbackData)
83{
84 JSShouldTerminateCallback callback = reinterpret_cast<JSShouldTerminateCallback>(callbackPtr);
85 JSContextRef contextRef = toRef(exec);
86 ASSERT(callback);
87 return callback(contextRef, callbackData);
88}
89
90void JSContextGroupSetExecutionTimeLimit(JSContextGroupRef group, double limit, JSShouldTerminateCallback callback, void* callbackData)
91{
92 VM& vm = *toJS(group);
93 APIEntryShim entryShim(&vm);
94 Watchdog& watchdog = vm.watchdog;
95 if (callback) {
96 void* callbackPtr = reinterpret_cast<void*>(callback);
97 watchdog.setTimeLimit(vm, limit, internalScriptTimeoutCallback, callbackPtr, callbackData);
98 } else
99 watchdog.setTimeLimit(vm, limit);
100}
101
102void JSContextGroupClearExecutionTimeLimit(JSContextGroupRef group)
103{
104 VM& vm = *toJS(group);
105 APIEntryShim entryShim(&vm);
106 Watchdog& watchdog = vm.watchdog;
107 watchdog.setTimeLimit(vm, std::numeric_limits<double>::infinity());
9dae56ea 108}
b37bf2e1 109
6fe7ccc8
A
110// From the API's perspective, a global context remains alive iff it has been JSGlobalContextRetained.
111
b37bf2e1
A
112JSGlobalContextRef JSGlobalContextCreate(JSClassRef globalObjectClass)
113{
9dae56ea 114 initializeThreading();
6fe7ccc8 115
f9bf01c6 116#if OS(DARWIN)
93a37866 117 // If the application was linked before JSGlobalContextCreate was changed to use a unique VM,
6fe7ccc8 118 // we use a shared one for backwards compatibility.
9dae56ea 119 if (NSVersionOfLinkTimeLibrary("JavaScriptCore") <= webkitFirstVersionWithConcurrentGlobalContexts) {
93a37866 120 return JSGlobalContextCreateInGroup(toRef(&VM::sharedInstance()), globalObjectClass);
9dae56ea 121 }
f9bf01c6 122#endif // OS(DARWIN)
9dae56ea
A
123
124 return JSGlobalContextCreateInGroup(0, globalObjectClass);
125}
126
127JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClassRef globalObjectClass)
128{
129 initializeThreading();
130
93a37866 131 RefPtr<VM> vm = group ? PassRefPtr<VM>(toJS(group)) : VM::createContextGroup();
9dae56ea 132
93a37866
A
133 APIEntryShim entryShim(vm.get(), false);
134 vm->makeUsableFromMultipleThreads();
b37bf2e1
A
135
136 if (!globalObjectClass) {
93a37866 137 JSGlobalObject* globalObject = JSGlobalObject::create(*vm, JSGlobalObject::createStructure(*vm, jsNull()));
b37bf2e1
A
138 return JSGlobalContextRetain(toGlobalRef(globalObject->globalExec()));
139 }
140
93a37866 141 JSGlobalObject* globalObject = JSCallbackObject<JSGlobalObject>::create(*vm, globalObjectClass, JSCallbackObject<JSGlobalObject>::createStructure(*vm, 0, jsNull()));
9dae56ea 142 ExecState* exec = globalObject->globalExec();
ba379fdc 143 JSValue prototype = globalObjectClass->prototype(exec);
b37bf2e1
A
144 if (!prototype)
145 prototype = jsNull();
93a37866 146 globalObject->resetPrototype(*vm, prototype);
9dae56ea 147 return JSGlobalContextRetain(toGlobalRef(exec));
b37bf2e1
A
148}
149
150JSGlobalContextRef JSGlobalContextRetain(JSGlobalContextRef ctx)
151{
b37bf2e1 152 ExecState* exec = toJS(ctx);
f9bf01c6 153 APIEntryShim entryShim(exec);
9dae56ea 154
93a37866 155 VM& vm = exec->vm();
b37bf2e1 156 gcProtect(exec->dynamicGlobalObject());
93a37866 157 vm.ref();
b37bf2e1
A
158 return ctx;
159}
160
161void JSGlobalContextRelease(JSGlobalContextRef ctx)
162{
6fe7ccc8 163 IdentifierTable* savedIdentifierTable;
b37bf2e1 164 ExecState* exec = toJS(ctx);
6fe7ccc8
A
165 {
166 JSLockHolder lock(exec);
9dae56ea 167
93a37866
A
168 VM& vm = exec->vm();
169 savedIdentifierTable = wtfThreadData().setCurrentIdentifierTable(vm.identifierTable);
9dae56ea 170
6fe7ccc8
A
171 bool protectCountIsZero = Heap::heap(exec->dynamicGlobalObject())->unprotect(exec->dynamicGlobalObject());
172 if (protectCountIsZero)
93a37866
A
173 vm.heap.reportAbandonedObjectGraph();
174 vm.deref();
6fe7ccc8 175 }
f9bf01c6 176
4e4e5a6f 177 wtfThreadData().setCurrentIdentifierTable(savedIdentifierTable);
b37bf2e1
A
178}
179
180JSObjectRef JSContextGetGlobalObject(JSContextRef ctx)
181{
93a37866
A
182 if (!ctx) {
183 ASSERT_NOT_REACHED();
184 return 0;
185 }
b37bf2e1 186 ExecState* exec = toJS(ctx);
f9bf01c6 187 APIEntryShim entryShim(exec);
9dae56ea
A
188
189 // It is necessary to call toThisObject to get the wrapper object when used with WebCore.
6fe7ccc8 190 return toRef(exec->lexicalGlobalObject()->methodTable()->toThisObject(exec->lexicalGlobalObject(), exec));
9dae56ea
A
191}
192
193JSContextGroupRef JSContextGetGroup(JSContextRef ctx)
194{
93a37866
A
195 if (!ctx) {
196 ASSERT_NOT_REACHED();
197 return 0;
198 }
9dae56ea 199 ExecState* exec = toJS(ctx);
93a37866 200 return toRef(&exec->vm());
b37bf2e1 201}
f9bf01c6
A
202
203JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx)
204{
93a37866
A
205 if (!ctx) {
206 ASSERT_NOT_REACHED();
207 return 0;
208 }
f9bf01c6
A
209 ExecState* exec = toJS(ctx);
210 APIEntryShim entryShim(exec);
211
212 return toGlobalRef(exec->lexicalGlobalObject()->globalExec());
213}
14957cd0
A
214
215JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize)
216{
93a37866
A
217 if (!ctx) {
218 ASSERT_NOT_REACHED();
219 return 0;
220 }
14957cd0 221 ExecState* exec = toJS(ctx);
6fe7ccc8 222 JSLockHolder lock(exec);
93a37866
A
223 StringBuilder builder;
224 Vector<StackFrame> stackTrace;
225 Interpreter::getStackTrace(&exec->vm(), stackTrace, maxStackSize);
226
227 for (size_t i = 0; i < stackTrace.size(); i++) {
228 String urlString;
229 String functionName;
230 StackFrame& frame = stackTrace[i];
231 JSValue function = frame.callee.get();
232 if (frame.callee)
233 functionName = frame.friendlyFunctionName(exec);
14957cd0
A
234 else {
235 // Caller is unknown, but if frame is empty we should still add the frame, because
236 // something called us, and gave us arguments.
93a37866 237 if (i)
14957cd0
A
238 break;
239 }
93a37866
A
240 unsigned lineNumber;
241 unsigned column;
242 frame.computeLineAndColumn(lineNumber, column);
14957cd0 243 if (!builder.isEmpty())
93a37866
A
244 builder.append('\n');
245 builder.append('#');
246 builder.appendNumber(i);
247 builder.append(' ');
14957cd0 248 builder.append(functionName);
93a37866 249 builder.appendLiteral("() at ");
14957cd0 250 builder.append(urlString);
93a37866
A
251 if (frame.codeType != StackFrameNativeCode) {
252 builder.append(':');
253 builder.appendNumber(lineNumber);
254 }
255 if (!function)
14957cd0 256 break;
14957cd0 257 }
93a37866 258 return OpaqueJSString::create(builder.toString()).leakRef();
14957cd0
A
259}
260
261