123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- /*
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include "config.h"
- #include "JSContextRef.h"
- #include "JSContextRefPrivate.h"
- #include "APICast.h"
- #include "InitializeThreading.h"
- #include <interpreter/CallFrame.h>
- #include <interpreter/Interpreter.h>
- #include "JSCallbackObject.h"
- #include "JSClassRef.h"
- #include "JSGlobalObject.h"
- #include "JSObject.h"
- #include "Operations.h"
- #include "SourceProvider.h"
- #include <wtf/text/StringBuilder.h>
- #include <wtf/text/StringHash.h>
- #if OS(DARWIN)
- #include <mach-o/dyld.h>
- static const int32_t webkitFirstVersionWithConcurrentGlobalContexts = 0x2100500; // 528.5.0
- #endif
- using namespace JSC;
- // From the API's perspective, a context group remains alive iff
- // (a) it has been JSContextGroupRetained
- // OR
- // (b) one of its contexts has been JSContextRetained
- JSContextGroupRef JSContextGroupCreate()
- {
- initializeThreading();
- return toRef(VM::createContextGroup().leakRef());
- }
- JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group)
- {
- toJS(group)->ref();
- return group;
- }
- void JSContextGroupRelease(JSContextGroupRef group)
- {
- IdentifierTable* savedIdentifierTable;
- VM& vm = *toJS(group);
- {
- JSLockHolder lock(vm);
- savedIdentifierTable = wtfThreadData().setCurrentIdentifierTable(vm.identifierTable);
- vm.deref();
- }
- wtfThreadData().setCurrentIdentifierTable(savedIdentifierTable);
- }
- static bool internalScriptTimeoutCallback(ExecState* exec, void* callbackPtr, void* callbackData)
- {
- JSShouldTerminateCallback callback = reinterpret_cast<JSShouldTerminateCallback>(callbackPtr);
- JSContextRef contextRef = toRef(exec);
- ASSERT(callback);
- return callback(contextRef, callbackData);
- }
- void JSContextGroupSetExecutionTimeLimit(JSContextGroupRef group, double limit, JSShouldTerminateCallback callback, void* callbackData)
- {
- VM& vm = *toJS(group);
- APIEntryShim entryShim(&vm);
- Watchdog& watchdog = vm.watchdog;
- if (callback) {
- void* callbackPtr = reinterpret_cast<void*>(callback);
- watchdog.setTimeLimit(vm, limit, internalScriptTimeoutCallback, callbackPtr, callbackData);
- } else
- watchdog.setTimeLimit(vm, limit);
- }
- void JSContextGroupClearExecutionTimeLimit(JSContextGroupRef group)
- {
- VM& vm = *toJS(group);
- APIEntryShim entryShim(&vm);
- Watchdog& watchdog = vm.watchdog;
- watchdog.setTimeLimit(vm, std::numeric_limits<double>::infinity());
- }
- // From the API's perspective, a global context remains alive iff it has been JSGlobalContextRetained.
- JSGlobalContextRef JSGlobalContextCreate(JSClassRef globalObjectClass)
- {
- initializeThreading();
- #if OS(DARWIN)
- // If the application was linked before JSGlobalContextCreate was changed to use a unique VM,
- // we use a shared one for backwards compatibility.
- if (NSVersionOfLinkTimeLibrary("JavaScriptCore") <= webkitFirstVersionWithConcurrentGlobalContexts) {
- return JSGlobalContextCreateInGroup(toRef(&VM::sharedInstance()), globalObjectClass);
- }
- #endif // OS(DARWIN)
- return JSGlobalContextCreateInGroup(0, globalObjectClass);
- }
- JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClassRef globalObjectClass)
- {
- initializeThreading();
- RefPtr<VM> vm = group ? PassRefPtr<VM>(toJS(group)) : VM::createContextGroup();
- APIEntryShim entryShim(vm.get(), false);
- vm->makeUsableFromMultipleThreads();
- if (!globalObjectClass) {
- JSGlobalObject* globalObject = JSGlobalObject::create(*vm, JSGlobalObject::createStructure(*vm, jsNull()));
- return JSGlobalContextRetain(toGlobalRef(globalObject->globalExec()));
- }
- JSGlobalObject* globalObject = JSCallbackObject<JSGlobalObject>::create(*vm, globalObjectClass, JSCallbackObject<JSGlobalObject>::createStructure(*vm, 0, jsNull()));
- ExecState* exec = globalObject->globalExec();
- JSValue prototype = globalObjectClass->prototype(exec);
- if (!prototype)
- prototype = jsNull();
- globalObject->resetPrototype(*vm, prototype);
- return JSGlobalContextRetain(toGlobalRef(exec));
- }
- JSGlobalContextRef JSGlobalContextRetain(JSGlobalContextRef ctx)
- {
- ExecState* exec = toJS(ctx);
- APIEntryShim entryShim(exec);
- VM& vm = exec->vm();
- gcProtect(exec->dynamicGlobalObject());
- vm.ref();
- return ctx;
- }
- void JSGlobalContextRelease(JSGlobalContextRef ctx)
- {
- IdentifierTable* savedIdentifierTable;
- ExecState* exec = toJS(ctx);
- {
- JSLockHolder lock(exec);
- VM& vm = exec->vm();
- savedIdentifierTable = wtfThreadData().setCurrentIdentifierTable(vm.identifierTable);
- bool protectCountIsZero = Heap::heap(exec->dynamicGlobalObject())->unprotect(exec->dynamicGlobalObject());
- if (protectCountIsZero)
- vm.heap.reportAbandonedObjectGraph();
- vm.deref();
- }
- wtfThreadData().setCurrentIdentifierTable(savedIdentifierTable);
- }
- JSObjectRef JSContextGetGlobalObject(JSContextRef ctx)
- {
- if (!ctx) {
- ASSERT_NOT_REACHED();
- return 0;
- }
- ExecState* exec = toJS(ctx);
- APIEntryShim entryShim(exec);
- // It is necessary to call toThisObject to get the wrapper object when used with WebCore.
- return toRef(exec->lexicalGlobalObject()->methodTable()->toThisObject(exec->lexicalGlobalObject(), exec));
- }
- JSContextGroupRef JSContextGetGroup(JSContextRef ctx)
- {
- if (!ctx) {
- ASSERT_NOT_REACHED();
- return 0;
- }
- ExecState* exec = toJS(ctx);
- return toRef(&exec->vm());
- }
- JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx)
- {
- if (!ctx) {
- ASSERT_NOT_REACHED();
- return 0;
- }
- ExecState* exec = toJS(ctx);
- APIEntryShim entryShim(exec);
- return toGlobalRef(exec->lexicalGlobalObject()->globalExec());
- }
-
- JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize)
- {
- if (!ctx) {
- ASSERT_NOT_REACHED();
- return 0;
- }
- ExecState* exec = toJS(ctx);
- JSLockHolder lock(exec);
- StringBuilder builder;
- Vector<StackFrame> stackTrace;
- Interpreter::getStackTrace(&exec->vm(), stackTrace, maxStackSize);
- for (size_t i = 0; i < stackTrace.size(); i++) {
- String urlString;
- String functionName;
- StackFrame& frame = stackTrace[i];
- JSValue function = frame.callee.get();
- if (frame.callee)
- functionName = frame.friendlyFunctionName(exec);
- else {
- // Caller is unknown, but if frame is empty we should still add the frame, because
- // something called us, and gave us arguments.
- if (i)
- break;
- }
- unsigned lineNumber;
- unsigned column;
- frame.computeLineAndColumn(lineNumber, column);
- if (!builder.isEmpty())
- builder.append('\n');
- builder.append('#');
- builder.appendNumber(i);
- builder.append(' ');
- builder.append(functionName);
- builder.appendLiteral("() at ");
- builder.append(urlString);
- if (frame.codeType != StackFrameNativeCode) {
- builder.append(':');
- builder.appendNumber(lineNumber);
- }
- if (!function)
- break;
- }
- return OpaqueJSString::create(builder.toString()).leakRef();
- }
|