]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - API/JSContextRef.cpp
JavaScriptCore-1218.tar.gz
[apple/javascriptcore.git] / API / JSContextRef.cpp
index 7a57287ded4e02d4b0dcc4997dda90431b6da1ab..3869e87bfff7db7190e40ed2807874d1612c90e9 100644 (file)
@@ -35,7 +35,9 @@
 #include "JSClassRef.h"
 #include "JSGlobalObject.h"
 #include "JSObject.h"
 #include "JSClassRef.h"
 #include "JSGlobalObject.h"
 #include "JSObject.h"
-#include "UStringBuilder.h"
+#include "Operations.h"
+#include "SourceProvider.h"
+#include <wtf/text/StringBuilder.h>
 #include <wtf/text/StringHash.h>
 
 #if OS(DARWIN)
 #include <wtf/text/StringHash.h>
 
 #if OS(DARWIN)
@@ -54,7 +56,7 @@ using namespace JSC;
 JSContextGroupRef JSContextGroupCreate()
 {
     initializeThreading();
 JSContextGroupRef JSContextGroupCreate()
 {
     initializeThreading();
-    return toRef(JSGlobalData::createContextGroup(ThreadStackTypeSmall).leakRef());
+    return toRef(VM::createContextGroup().leakRef());
 }
 
 JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group)
 }
 
 JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group)
@@ -65,7 +67,44 @@ JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group)
 
 void JSContextGroupRelease(JSContextGroupRef group)
 {
 
 void JSContextGroupRelease(JSContextGroupRef group)
 {
-    toJS(group)->deref();
+    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.
 }
 
 // From the API's perspective, a global context remains alive iff it has been JSGlobalContextRetained.
@@ -75,10 +114,10 @@ JSGlobalContextRef JSGlobalContextCreate(JSClassRef globalObjectClass)
     initializeThreading();
 
 #if OS(DARWIN)
     initializeThreading();
 
 #if OS(DARWIN)
-    // If the application was linked before JSGlobalContextCreate was changed to use a unique JSGlobalData,
+    // 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) {
     // we use a shared one for backwards compatibility.
     if (NSVersionOfLinkTimeLibrary("JavaScriptCore") <= webkitFirstVersionWithConcurrentGlobalContexts) {
-        return JSGlobalContextCreateInGroup(toRef(&JSGlobalData::sharedInstance()), globalObjectClass);
+        return JSGlobalContextCreateInGroup(toRef(&VM::sharedInstance()), globalObjectClass);
     }
 #endif // OS(DARWIN)
 
     }
 #endif // OS(DARWIN)
 
@@ -89,22 +128,22 @@ JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClass
 {
     initializeThreading();
 
 {
     initializeThreading();
 
-    RefPtr<JSGlobalData> globalData = group ? PassRefPtr<JSGlobalData>(toJS(group)) : JSGlobalData::createContextGroup(ThreadStackTypeSmall);
+    RefPtr<VM> vm = group ? PassRefPtr<VM>(toJS(group)) : VM::createContextGroup();
 
 
-    APIEntryShim entryShim(globalData.get(), false);
-    globalData->makeUsableFromMultipleThreads();
+    APIEntryShim entryShim(vm.get(), false);
+    vm->makeUsableFromMultipleThreads();
 
     if (!globalObjectClass) {
 
     if (!globalObjectClass) {
-        JSGlobalObject* globalObject = JSGlobalObject::create(*globalData, JSGlobalObject::createStructure(*globalData, jsNull()));
+        JSGlobalObject* globalObject = JSGlobalObject::create(*vm, JSGlobalObject::createStructure(*vm, jsNull()));
         return JSGlobalContextRetain(toGlobalRef(globalObject->globalExec()));
     }
 
         return JSGlobalContextRetain(toGlobalRef(globalObject->globalExec()));
     }
 
-    JSGlobalObject* globalObject = JSCallbackObject<JSGlobalObject>::create(*globalData, globalObjectClass, JSCallbackObject<JSGlobalObject>::createStructure(*globalData, 0, jsNull()));
+    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();
     ExecState* exec = globalObject->globalExec();
     JSValue prototype = globalObjectClass->prototype(exec);
     if (!prototype)
         prototype = jsNull();
-    globalObject->resetPrototype(*globalData, prototype);
+    globalObject->resetPrototype(*vm, prototype);
     return JSGlobalContextRetain(toGlobalRef(exec));
 }
 
     return JSGlobalContextRetain(toGlobalRef(exec));
 }
 
@@ -113,9 +152,9 @@ JSGlobalContextRef JSGlobalContextRetain(JSGlobalContextRef ctx)
     ExecState* exec = toJS(ctx);
     APIEntryShim entryShim(exec);
 
     ExecState* exec = toJS(ctx);
     APIEntryShim entryShim(exec);
 
-    JSGlobalData& globalData = exec->globalData();
+    VM& vm = exec->vm();
     gcProtect(exec->dynamicGlobalObject());
     gcProtect(exec->dynamicGlobalObject());
-    globalData.ref();
+    vm.ref();
     return ctx;
 }
 
     return ctx;
 }
 
@@ -126,13 +165,13 @@ void JSGlobalContextRelease(JSGlobalContextRef ctx)
     {
         JSLockHolder lock(exec);
 
     {
         JSLockHolder lock(exec);
 
-        JSGlobalData& globalData = exec->globalData();
-        savedIdentifierTable = wtfThreadData().setCurrentIdentifierTable(globalData.identifierTable);
+        VM& vm = exec->vm();
+        savedIdentifierTable = wtfThreadData().setCurrentIdentifierTable(vm.identifierTable);
 
         bool protectCountIsZero = Heap::heap(exec->dynamicGlobalObject())->unprotect(exec->dynamicGlobalObject());
         if (protectCountIsZero)
 
         bool protectCountIsZero = Heap::heap(exec->dynamicGlobalObject())->unprotect(exec->dynamicGlobalObject());
         if (protectCountIsZero)
-            globalData.heap.reportAbandonedObjectGraph();
-        globalData.deref();
+            vm.heap.reportAbandonedObjectGraph();
+        vm.deref();
     }
 
     wtfThreadData().setCurrentIdentifierTable(savedIdentifierTable);
     }
 
     wtfThreadData().setCurrentIdentifierTable(savedIdentifierTable);
@@ -140,6 +179,10 @@ void JSGlobalContextRelease(JSGlobalContextRef ctx)
 
 JSObjectRef JSContextGetGlobalObject(JSContextRef ctx)
 {
 
 JSObjectRef JSContextGetGlobalObject(JSContextRef ctx)
 {
+    if (!ctx) {
+        ASSERT_NOT_REACHED();
+        return 0;
+    }
     ExecState* exec = toJS(ctx);
     APIEntryShim entryShim(exec);
 
     ExecState* exec = toJS(ctx);
     APIEntryShim entryShim(exec);
 
@@ -149,12 +192,20 @@ JSObjectRef JSContextGetGlobalObject(JSContextRef ctx)
 
 JSContextGroupRef JSContextGetGroup(JSContextRef ctx)
 {
 
 JSContextGroupRef JSContextGetGroup(JSContextRef ctx)
 {
+    if (!ctx) {
+        ASSERT_NOT_REACHED();
+        return 0;
+    }
     ExecState* exec = toJS(ctx);
     ExecState* exec = toJS(ctx);
-    return toRef(&exec->globalData());
+    return toRef(&exec->vm());
 }
 
 JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx)
 {
 }
 
 JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx)
 {
+    if (!ctx) {
+        ASSERT_NOT_REACHED();
+        return 0;
+    }
     ExecState* exec = toJS(ctx);
     APIEntryShim entryShim(exec);
 
     ExecState* exec = toJS(ctx);
     APIEntryShim entryShim(exec);
 
@@ -163,57 +214,48 @@ JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx)
     
 JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize)
 {
     
 JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize)
 {
+    if (!ctx) {
+        ASSERT_NOT_REACHED();
+        return 0;
+    }
     ExecState* exec = toJS(ctx);
     JSLockHolder lock(exec);
     ExecState* exec = toJS(ctx);
     JSLockHolder lock(exec);
-
-    unsigned count = 0;
-    UStringBuilder builder;
-    CallFrame* callFrame = exec;
-    UString functionName;
-    if (exec->callee()) {
-        if (asObject(exec->callee())->inherits(&InternalFunction::s_info)) {
-            functionName = asInternalFunction(exec->callee())->name(exec);
-            builder.append("#0 ");
-            builder.append(functionName);
-            builder.append("() ");
-            count++;
-        }
-    }
-    while (true) {
-        ASSERT(callFrame);
-        int signedLineNumber;
-        intptr_t sourceID;
-        UString urlString;
-        JSValue function;
-        
-        UString levelStr = UString::number(count);
-        
-        exec->interpreter()->retrieveLastCaller(callFrame, signedLineNumber, sourceID, urlString, function);
-
-        if (function)
-            functionName = jsCast<JSFunction*>(function)->name(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.
         else {
             // Caller is unknown, but if frame is empty we should still add the frame, because
             // something called us, and gave us arguments.
-            if (count)
+            if (i)
                 break;
         }
                 break;
         }
-        unsigned lineNumber = signedLineNumber >= 0 ? signedLineNumber : 0;
+        unsigned lineNumber;
+        unsigned column;
+        frame.computeLineAndColumn(lineNumber, column);
         if (!builder.isEmpty())
         if (!builder.isEmpty())
-            builder.append("\n");
-        builder.append("#");
-        builder.append(levelStr);
-        builder.append(" ");
+            builder.append('\n');
+        builder.append('#');
+        builder.appendNumber(i);
+        builder.append(' ');
         builder.append(functionName);
         builder.append(functionName);
-        builder.append("() at ");
+        builder.appendLiteral("() at ");
         builder.append(urlString);
         builder.append(urlString);
-        builder.append(":");
-        builder.append(UString::number(lineNumber));
-        if (!function || ++count == maxStackSize)
+        if (frame.codeType != StackFrameNativeCode) {
+            builder.append(':');
+            builder.appendNumber(lineNumber);
+        }
+        if (!function)
             break;
             break;
-        callFrame = callFrame->callerFrame();
     }
     }
-    return OpaqueJSString::create(builder.toUString()).leakRef();
+    return OpaqueJSString::create(builder.toString()).leakRef();
 }
 
 
 }