2ed8241e3b447005726f9d66f5242d94c2469dbe
[WebKit-https.git] / Source / JavaScriptCore / API / JSContextRef.cpp
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"
28 #include "JSContextRefPrivate.h"
29
30 #include "APICast.h"
31 #include "CallFrame.h"
32 #include "CallFrameInlines.h"
33 #include "InitializeThreading.h"
34 #include "JSCallbackObject.h"
35 #include "JSClassRef.h"
36 #include "JSGlobalObject.h"
37 #include "JSObject.h"
38 #include "Operations.h"
39 #include "SourceProvider.h"
40 #include "StackVisitor.h"
41 #include <wtf/text/StringBuilder.h>
42 #include <wtf/text/StringHash.h>
43
44 #if OS(DARWIN)
45 #include <mach-o/dyld.h>
46
47 static const int32_t webkitFirstVersionWithConcurrentGlobalContexts = 0x2100500; // 528.5.0
48 #endif
49
50 using namespace JSC;
51
52 // From the API's perspective, a context group remains alive iff
53 //     (a) it has been JSContextGroupRetained
54 //     OR
55 //     (b) one of its contexts has been JSContextRetained
56
57 JSContextGroupRef JSContextGroupCreate()
58 {
59     initializeThreading();
60     return toRef(VM::createContextGroup().leakRef());
61 }
62
63 JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group)
64 {
65     toJS(group)->ref();
66     return group;
67 }
68
69 void JSContextGroupRelease(JSContextGroupRef group)
70 {
71     IdentifierTable* savedIdentifierTable;
72     VM& vm = *toJS(group);
73
74     {
75         JSLockHolder lock(vm);
76         savedIdentifierTable = wtfThreadData().setCurrentIdentifierTable(vm.identifierTable);
77         vm.deref();
78     }
79
80     wtfThreadData().setCurrentIdentifierTable(savedIdentifierTable);
81 }
82
83 static bool internalScriptTimeoutCallback(ExecState* exec, void* callbackPtr, void* callbackData)
84 {
85     JSShouldTerminateCallback callback = reinterpret_cast<JSShouldTerminateCallback>(callbackPtr);
86     JSContextRef contextRef = toRef(exec);
87     ASSERT(callback);
88     return callback(contextRef, callbackData);
89 }
90
91 void JSContextGroupSetExecutionTimeLimit(JSContextGroupRef group, double limit, JSShouldTerminateCallback callback, void* callbackData)
92 {
93     VM& vm = *toJS(group);
94     APIEntryShim entryShim(&vm);
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     APIEntryShim entryShim(&vm);
107     Watchdog& watchdog = vm.watchdog;
108     watchdog.setTimeLimit(vm, std::numeric_limits<double>::infinity());
109 }
110
111 // From the API's perspective, a global context remains alive iff it has been JSGlobalContextRetained.
112
113 JSGlobalContextRef JSGlobalContextCreate(JSClassRef globalObjectClass)
114 {
115     initializeThreading();
116
117 #if OS(DARWIN)
118     // If the application was linked before JSGlobalContextCreate was changed to use a unique VM,
119     // we use a shared one for backwards compatibility.
120     if (NSVersionOfLinkTimeLibrary("JavaScriptCore") <= webkitFirstVersionWithConcurrentGlobalContexts) {
121         return JSGlobalContextCreateInGroup(toRef(&VM::sharedInstance()), globalObjectClass);
122     }
123 #endif // OS(DARWIN)
124
125     return JSGlobalContextCreateInGroup(0, globalObjectClass);
126 }
127
128 JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClassRef globalObjectClass)
129 {
130     initializeThreading();
131
132     RefPtr<VM> vm = group ? PassRefPtr<VM>(toJS(group)) : VM::createContextGroup();
133
134     APIEntryShim entryShim(vm.get(), false);
135     vm->makeUsableFromMultipleThreads();
136
137     if (!globalObjectClass) {
138         JSGlobalObject* globalObject = JSGlobalObject::create(*vm, JSGlobalObject::createStructure(*vm, jsNull()));
139         globalObject->setGlobalThis(*vm, JSProxy::create(*vm, JSProxy::createStructure(*vm, globalObject, globalObject->prototype()), globalObject));
140         return JSGlobalContextRetain(toGlobalRef(globalObject->globalExec()));
141     }
142
143     JSGlobalObject* globalObject = JSCallbackObject<JSGlobalObject>::create(*vm, globalObjectClass, JSCallbackObject<JSGlobalObject>::createStructure(*vm, 0, jsNull()));
144     ExecState* exec = globalObject->globalExec();
145     JSValue prototype = globalObjectClass->prototype(exec);
146     if (!prototype)
147         prototype = jsNull();
148     globalObject->resetPrototype(*vm, prototype);
149     return JSGlobalContextRetain(toGlobalRef(exec));
150 }
151
152 JSGlobalContextRef JSGlobalContextRetain(JSGlobalContextRef ctx)
153 {
154     ExecState* exec = toJS(ctx);
155     APIEntryShim entryShim(exec);
156
157     VM& vm = exec->vm();
158     gcProtect(exec->dynamicGlobalObject());
159     vm.ref();
160     return ctx;
161 }
162
163 void JSGlobalContextRelease(JSGlobalContextRef ctx)
164 {
165     IdentifierTable* savedIdentifierTable;
166     ExecState* exec = toJS(ctx);
167     {
168         JSLockHolder lock(exec);
169
170         VM& vm = exec->vm();
171         savedIdentifierTable = wtfThreadData().setCurrentIdentifierTable(vm.identifierTable);
172
173         bool protectCountIsZero = Heap::heap(exec->dynamicGlobalObject())->unprotect(exec->dynamicGlobalObject());
174         if (protectCountIsZero)
175             vm.heap.reportAbandonedObjectGraph();
176         vm.deref();
177     }
178
179     wtfThreadData().setCurrentIdentifierTable(savedIdentifierTable);
180 }
181
182 JSObjectRef JSContextGetGlobalObject(JSContextRef ctx)
183 {
184     if (!ctx) {
185         ASSERT_NOT_REACHED();
186         return 0;
187     }
188     ExecState* exec = toJS(ctx);
189     APIEntryShim entryShim(exec);
190
191     return toRef(jsCast<JSObject*>(exec->lexicalGlobalObject()->methodTable()->toThis(exec->lexicalGlobalObject(), exec, NotStrictMode)));
192 }
193
194 JSContextGroupRef JSContextGetGroup(JSContextRef ctx)
195 {
196     if (!ctx) {
197         ASSERT_NOT_REACHED();
198         return 0;
199     }
200     ExecState* exec = toJS(ctx);
201     return toRef(&exec->vm());
202 }
203
204 JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx)
205 {
206     if (!ctx) {
207         ASSERT_NOT_REACHED();
208         return 0;
209     }
210     ExecState* exec = toJS(ctx);
211     APIEntryShim entryShim(exec);
212
213     return toGlobalRef(exec->lexicalGlobalObject()->globalExec());
214 }
215
216 class BacktraceFunctor {
217 public:
218     BacktraceFunctor(StringBuilder& builder, unsigned remainingCapacityForFrameCapture)
219         : m_builder(builder)
220         , m_remainingCapacityForFrameCapture(remainingCapacityForFrameCapture)
221     {
222     }
223
224     StackVisitor::Status operator()(StackVisitor& visitor)
225     {
226         if (m_remainingCapacityForFrameCapture) {
227             // If callee is unknown, but we've not added any frame yet, we should
228             // still add the frame, because something called us, and gave us arguments.
229             JSObject* callee = visitor->callee();
230             if (!callee && visitor->index())
231                 return StackVisitor::Done;
232
233             StringBuilder& builder = m_builder;
234             if (!builder.isEmpty())
235                 builder.append('\n');
236             builder.append('#');
237             builder.appendNumber(visitor->index());
238             builder.append(' ');
239             builder.append(visitor->functionName());
240             builder.appendLiteral("() at ");
241             builder.append(visitor->sourceURL());
242             if (visitor->isJSFrame()) {
243                 builder.append(':');
244                 unsigned lineNumber;
245                 unsigned unusedColumn;
246                 visitor->computeLineAndColumn(lineNumber, unusedColumn);
247                 builder.appendNumber(lineNumber);
248             }
249
250             if (!callee)
251                 return StackVisitor::Done;
252
253             m_remainingCapacityForFrameCapture--;
254             return StackVisitor::Continue;
255         }
256         return StackVisitor::Done;
257     }
258
259 private:
260     StringBuilder& m_builder;
261     unsigned m_remainingCapacityForFrameCapture;
262 };
263
264 JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize)
265 {
266     if (!ctx) {
267         ASSERT_NOT_REACHED();
268         return 0;
269     }
270     ExecState* exec = toJS(ctx);
271     JSLockHolder lock(exec);
272     StringBuilder builder;
273     CallFrame* frame = exec->vm().topCallFrame;
274
275     ASSERT(maxStackSize);
276     BacktraceFunctor functor(builder, maxStackSize);
277     frame->iterate(functor);
278
279     return OpaqueJSString::create(builder.toString()).leakRef();
280 }
281
282