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 "InitializeThreading.h" 32#include <interpreter/CallFrame.h> 33#include <interpreter/Interpreter.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 <wtf/text/StringBuilder.h> 41#include <wtf/text/StringHash.h> 42 43#if OS(DARWIN) 44#include <mach-o/dyld.h> 45 46static const int32_t webkitFirstVersionWithConcurrentGlobalContexts = 0x2100500; // 528.5.0 47#endif 48 49using namespace JSC; 50 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 56JSContextGroupRef JSContextGroupCreate() 57{ 58 initializeThreading(); 59 return toRef(VM::createContextGroup().leakRef()); 60} 61 62JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group) 63{ 64 toJS(group)->ref(); 65 return group; 66} 67 68void JSContextGroupRelease(JSContextGroupRef group) 69{ 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()); 108} 109 110// From the API's perspective, a global context remains alive iff it has been JSGlobalContextRetained. 111 112JSGlobalContextRef JSGlobalContextCreate(JSClassRef globalObjectClass) 113{ 114 initializeThreading(); 115 116#if OS(DARWIN) 117 // If the application was linked before JSGlobalContextCreate was changed to use a unique VM, 118 // we use a shared one for backwards compatibility. 119 if (NSVersionOfLinkTimeLibrary("JavaScriptCore") <= webkitFirstVersionWithConcurrentGlobalContexts) { 120 return JSGlobalContextCreateInGroup(toRef(&VM::sharedInstance()), globalObjectClass); 121 } 122#endif // OS(DARWIN) 123 124 return JSGlobalContextCreateInGroup(0, globalObjectClass); 125} 126 127JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClassRef globalObjectClass) 128{ 129 initializeThreading(); 130 131 RefPtr<VM> vm = group ? PassRefPtr<VM>(toJS(group)) : VM::createContextGroup(); 132 133 APIEntryShim entryShim(vm.get(), false); 134 vm->makeUsableFromMultipleThreads(); 135 136 if (!globalObjectClass) { 137 JSGlobalObject* globalObject = JSGlobalObject::create(*vm, JSGlobalObject::createStructure(*vm, jsNull())); 138 return JSGlobalContextRetain(toGlobalRef(globalObject->globalExec())); 139 } 140 141 JSGlobalObject* globalObject = JSCallbackObject<JSGlobalObject>::create(*vm, globalObjectClass, JSCallbackObject<JSGlobalObject>::createStructure(*vm, 0, jsNull())); 142 ExecState* exec = globalObject->globalExec(); 143 JSValue prototype = globalObjectClass->prototype(exec); 144 if (!prototype) 145 prototype = jsNull(); 146 globalObject->resetPrototype(*vm, prototype); 147 return JSGlobalContextRetain(toGlobalRef(exec)); 148} 149 150JSGlobalContextRef JSGlobalContextRetain(JSGlobalContextRef ctx) 151{ 152 ExecState* exec = toJS(ctx); 153 APIEntryShim entryShim(exec); 154 155 VM& vm = exec->vm(); 156 gcProtect(exec->dynamicGlobalObject()); 157 vm.ref(); 158 return ctx; 159} 160 161void JSGlobalContextRelease(JSGlobalContextRef ctx) 162{ 163 IdentifierTable* savedIdentifierTable; 164 ExecState* exec = toJS(ctx); 165 { 166 JSLockHolder lock(exec); 167 168 VM& vm = exec->vm(); 169 savedIdentifierTable = wtfThreadData().setCurrentIdentifierTable(vm.identifierTable); 170 171 bool protectCountIsZero = Heap::heap(exec->dynamicGlobalObject())->unprotect(exec->dynamicGlobalObject()); 172 if (protectCountIsZero) 173 vm.heap.reportAbandonedObjectGraph(); 174 vm.deref(); 175 } 176 177 wtfThreadData().setCurrentIdentifierTable(savedIdentifierTable); 178} 179 180JSObjectRef JSContextGetGlobalObject(JSContextRef ctx) 181{ 182 if (!ctx) { 183 ASSERT_NOT_REACHED(); 184 return 0; 185 } 186 ExecState* exec = toJS(ctx); 187 APIEntryShim entryShim(exec); 188 189 // It is necessary to call toThisObject to get the wrapper object when used with WebCore. 190 return toRef(exec->lexicalGlobalObject()->methodTable()->toThisObject(exec->lexicalGlobalObject(), exec)); 191} 192 193JSContextGroupRef JSContextGetGroup(JSContextRef ctx) 194{ 195 if (!ctx) { 196 ASSERT_NOT_REACHED(); 197 return 0; 198 } 199 ExecState* exec = toJS(ctx); 200 return toRef(&exec->vm()); 201} 202 203JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx) 204{ 205 if (!ctx) { 206 ASSERT_NOT_REACHED(); 207 return 0; 208 } 209 ExecState* exec = toJS(ctx); 210 APIEntryShim entryShim(exec); 211 212 return toGlobalRef(exec->lexicalGlobalObject()->globalExec()); 213} 214 215JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize) 216{ 217 if (!ctx) { 218 ASSERT_NOT_REACHED(); 219 return 0; 220 } 221 ExecState* exec = toJS(ctx); 222 JSLockHolder lock(exec); 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); 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. 237 if (i) 238 break; 239 } 240 unsigned lineNumber; 241 unsigned column; 242 frame.computeLineAndColumn(lineNumber, column); 243 if (!builder.isEmpty()) 244 builder.append('\n'); 245 builder.append('#'); 246 builder.appendNumber(i); 247 builder.append(' '); 248 builder.append(functionName); 249 builder.appendLiteral("() at "); 250 builder.append(urlString); 251 if (frame.codeType != StackFrameNativeCode) { 252 builder.append(':'); 253 builder.appendNumber(lineNumber); 254 } 255 if (!function) 256 break; 257 } 258 return OpaqueJSString::create(builder.toString()).leakRef(); 259} 260 261 262