bug 453157 - watchdog thread as an alternative to operation count
☠☠ backed out by f506b00d99f4 ☠ ☠
authorAndrei Saprykin <andrei@runitsoft.com>
Sun, 21 Dec 2008 17:16:09 +0100
changeset 23112 7184e014cd05187008c3c579b66e79799e423710
parent 23111 7dd3e4a4ceffa6459573229efc3a474ab7e3adbd
child 23113 f506b00d99f4bfcd16df58ff86c0e435ae3bbcc0
push idunknown
push userunknown
push dateunknown
bugs453157
milestone1.9.2a1pre
bug 453157 - watchdog thread as an alternative to operation count
build/Makefile.in
build/pgo/Makefile.in
build/pgo/automation.py.in
dom/src/base/nsJSEnvironment.cpp
dom/src/threads/nsDOMThreadService.cpp
js/src/js.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jsinterp.cpp
js/src/jspubtd.h
js/src/jsversion.h
js/src/xpconnect/idl/nsIXPConnect.idl
js/src/xpconnect/src/nsXPConnect.cpp
js/src/xpconnect/src/xpccomponents.cpp
js/src/xpconnect/src/xpccontext.cpp
js/src/xpconnect/src/xpcjsruntime.cpp
js/src/xpconnect/src/xpcprivate.h
testing/mochitest/Makefile.in
--- a/build/Makefile.in
+++ b/build/Makefile.in
@@ -104,16 +104,22 @@ AUTOMATION_PPARGS += -DIS_CYGWIN=1
 endif
 
 ifeq ($(ENABLE_TESTS), 1)
 AUTOMATION_PPARGS += -DIS_TEST_BUILD=1
 else
 AUTOMATION_PPARGS += -DIS_TEST_BUILD=0
 endif
 
+ifeq ($(MOZ_DEBUG), 1)
+AUTOMATION_PPARGS += -DIS_DEBUG_BUILD=1
+else
+AUTOMATION_PPARGS += -DIS_DEBUG_BUILD=0
+endif
+
 _LEAKTEST_DIR = $(DEPTH)/_leaktest
 
 _LEAKTEST_FILES =    \
 		automation.py \
 		leaktest.py \
 		bloatcycle.html \
 		$(topsrcdir)/build/pgo/server-locations.txt \
 		$(NULL)
--- a/build/pgo/Makefile.in
+++ b/build/pgo/Makefile.in
@@ -109,16 +109,22 @@ AUTOMATION_PPARGS += -DIS_CYGWIN=1
 endif
 
 ifeq ($(ENABLE_TESTS), 1)
 AUTOMATION_PPARGS += -DIS_TEST_BUILD=1
 else
 AUTOMATION_PPARGS += -DIS_TEST_BUILD=0
 endif
 
+ifeq ($(MOZ_DEBUG), 1)
+AUTOMATION_PPARGS += -DIS_DEBUG_BUILD=1
+else
+AUTOMATION_PPARGS += -DIS_DEBUG_BUILD=0
+endif
+
 automation.py: automation.py.in
 	$(PYTHON) $(topsrcdir)/config/Preprocessor.py \
 	$(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $^ > $@
 
 genpgocert.py: genpgocert.py.in
 	$(PYTHON) $(topsrcdir)/config/Preprocessor.py \
 	$(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $^ > $@
 
--- a/build/pgo/automation.py.in
+++ b/build/pgo/automation.py.in
@@ -79,16 +79,17 @@ IS_CYGWIN = False
 #expand IS_CAMINO = __IS_CAMINO__ != 0
 #expand BIN_SUFFIX = __BIN_SUFFIX__
 
 UNIXISH = not IS_WIN32 and not IS_MAC
 
 #expand DEFAULT_APP = "./" + __BROWSER_PATH__
 #expand CERTS_DIR = __CERTS_DIR__
 #expand IS_TEST_BUILD = __IS_TEST_BUILD__
+#expand IS_DEBUG_BUILD = __IS_DEBUG_BUILD__
 
 ###########
 # LOGGING #
 ###########
 
 # We use the logging system here primarily because it'll handle multiple
 # threads, which is needed to process the output of the server and application
 # processes simultaneously.
@@ -309,16 +310,23 @@ user_pref("layout.debug.enable_data_xbl"
 user_pref("browser.EULA.override", true);
 user_pref("javascript.options.jit.content", true);
 user_pref("gfx.color_management.force_srgb", true);
 
 user_pref("camino.warn_when_closing", false); // Camino-only, harmless to others
 """
   prefs.append(part)
 
+  # Increase the max script run time 10-fold for debug builds
+  if (IS_DEBUG_BUILD):
+    prefs.append("""\
+user_pref("dom.max_script_run_time", 100);
+user_pref("dom.max_chrome_script_run_time", 200);
+""")
+
   locations = readLocations()
 
   # Grant God-power to all the privileged servers on which tests run.
   privileged = filter(lambda loc: "privileged" in loc.options, locations)
   for (i, l) in itertools.izip(itertools.count(1), privileged):
     part = """
 user_pref("capability.principal.codebase.p%(i)d.granted",
           "UniversalXPConnect UniversalBrowserRead UniversalBrowserWrite \
--- a/dom/src/base/nsJSEnvironment.cpp
+++ b/dom/src/base/nsJSEnvironment.cpp
@@ -847,19 +847,16 @@ PrintWinCodebase(nsGlobalWindow *win)
   }
 
   nsCAutoString spec;
   uri->GetSpec(spec);
   printf("%s\n", spec.get());
 }
 #endif
 
-// The accumulated operation weight before we call MaybeGC
-const PRUint32 MAYBE_GC_OPERATION_WEIGHT = 5000 * JS_OPERATION_WEIGHT_BASE;
-
 static void
 MaybeGC(JSContext *cx)
 {
   size_t bytes = cx->runtime->gcBytes;
   size_t lastBytes = cx->runtime->gcLastBytes;
 
   if ((bytes > 8192 && bytes / 16 > lastBytes)
 #ifdef DEBUG
@@ -929,34 +926,34 @@ nsJSContext::DOMOperationCallback(JSCont
     if (! ::JS_IsSystemObject(cx, ::JS_GetGlobalObject(cx))) {
 
       // lets see if CC() did anything, if not, cancel the script.
       mem->IsLowMemory(&lowMemory);
       if (lowMemory) {
 
         if (nsContentUtils::GetBoolPref("dom.prevent_oom_dialog", PR_FALSE))
           return JS_FALSE;
-        
+
         nsCOMPtr<nsIPrompt> prompt = GetPromptFromContext(ctx);
-        
+
         nsXPIDLString title, msg;
         rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
                                                 "LowMemoryTitle",
                                                 title);
-        
+
         rv |= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
                                                  "LowMemoryMessage",
                                                  msg);
-        
+
         //GetStringFromName can return NS_OK and still give NULL string
         if (NS_FAILED(rv) || !title || !msg) {
           NS_ERROR("Failed to get localized strings.");
           return JS_FALSE;
         }
-        
+
         prompt->Alert(title, msg);
         return JS_FALSE;
       }
     }
   }
 
   PRTime now = PR_Now();
 
@@ -1233,19 +1230,18 @@ nsJSContext::nsJSContext(JSRuntime *aRun
 
     // Make sure the new context gets the default context options
     ::JS_SetOptions(mContext, mDefaultJSOptions);
 
     // Watch for the JS boolean options
     nsContentUtils::RegisterPrefCallback(js_options_dot_str,
                                          JSOptionChangedCallback,
                                          this);
-
-    ::JS_SetOperationCallback(mContext, DOMOperationCallback,
-                              MAYBE_GC_OPERATION_WEIGHT);
+    ::JS_SetOperationCallback(mContext, DOMOperationCallback);
+    nsContentUtils::XPConnect()->SetWatchdogLimit(mContext, PR_TicksPerSecond()/10);
 
     static JSLocaleCallbacks localeCallbacks =
       {
         LocaleToUpperCase,
         LocaleToLowerCase,
         LocaleCompare,
         LocaleToUnicode
       };
--- a/dom/src/threads/nsDOMThreadService.cpp
+++ b/dom/src/threads/nsDOMThreadService.cpp
@@ -789,18 +789,18 @@ nsDOMThreadService::CreateJSContext()
   gJSRuntimeService->GetRuntime(&rt);
   NS_ENSURE_TRUE(rt, nsnull);
 
   JSAutoContextDestroyer cx(JS_NewContext(rt, 8192));
   NS_ENSURE_TRUE(cx, nsnull);
 
   JS_SetErrorReporter(cx, DOMWorkerErrorReporter);
 
-  JS_SetOperationCallback(cx, DOMWorkerOperationCallback,
-                          100 * JS_OPERATION_WEIGHT_BASE);
+  JS_SetOperationCallback(cx, DOMWorkerOperationCallback);
+  nsContentUtils::XPConnect()->SetWatchdogLimit(cx, PR_TicksPerSecond()/100);
 
   static JSSecurityCallbacks securityCallbacks = {
     nsDOMWorkerSecurityManager::JSCheckAccess,
     nsDOMWorkerSecurityManager::JSTranscodePrincipals,
     nsDOMWorkerSecurityManager::JSFindPrincipal
   };
 
   JS_SetContextSecurityCallbacks(cx, &securityCallbacks);
--- a/js/src/js.cpp
+++ b/js/src/js.cpp
@@ -99,29 +99,42 @@ typedef enum JSShellExitCode {
 
 size_t gStackChunkSize = 8192;
 
 /* Assume that we can not use more than 5e5 bytes of C stack by default. */
 static size_t gMaxStackSize = 500000;
 static jsuword gStackBase;
 
 static size_t gScriptStackQuota = JS_DEFAULT_SCRIPT_STACK_QUOTA;
-
+#if JS_HAS_OPERATION_COUNT
 static JSBool gEnableBranchCallback = JS_FALSE;
 static uint32 gBranchCount;
 static uint32 gBranchLimit;
+#endif
 
 int gExitCode = 0;
 JSBool gQuitting = JS_FALSE;
 FILE *gErrFile = NULL;
 FILE *gOutFile = NULL;
 
 static JSBool reportWarnings = JS_TRUE;
 static JSBool compileOnly = JS_FALSE;
 
+#if !JS_HAS_OPERATION_COUNT
+/*
+ * Variables to support watchdog thread.
+ */
+static PRLock *gWatchdogLock;
+static PRCondVar *gWatchdogWakeup;
+static PRBool gWatchdogRunning;
+static PRThread *gWatchdogThread;
+static PRIntervalTime gCurrentInterval;
+static PRIntervalTime gWatchdogLimit;
+#endif
+
 typedef enum JSShellErrNum {
 #define MSG_DEF(name, number, count, exception, format) \
     name = number,
 #include "jsshell.msg"
 #undef MSG_DEF
     JSShellErr_Limit
 #undef MSGDEF
 } JSShellErrNum;
@@ -164,16 +177,17 @@ GetLine(JSContext *cx, char *bufp, FILE 
         fflush(gOutFile);
         if (!fgets(line, sizeof line, file))
             return JS_FALSE;
         strcpy(bufp, line);
     }
     return JS_TRUE;
 }
 
+#if JS_HAS_OPERATION_COUNT
 static JSBool
 my_BranchCallback(JSContext *cx, JSScript *script)
 {
     if (++gBranchCount == gBranchLimit) {
         if (script) {
             if (script->filename)
                 fprintf(gErrFile, "%s:", script->filename);
             fprintf(gErrFile, "%u: script branch callback (%u callbacks)\n",
@@ -192,16 +206,142 @@ my_BranchCallback(JSContext *cx, JSScrip
             JS_MaybeGC(cx);
 #ifdef JS_THREADSAFE
         else
             JS_YieldRequest(cx);
     }
 #endif
     return JS_TRUE;
 }
+#endif
+
+#if !JS_HAS_OPERATION_COUNT
+static void
+ShutdownWatchdog()
+{
+    PRThread *t;
+
+    PR_Lock(gWatchdogLock);
+    gWatchdogRunning = PR_FALSE;
+    t = gWatchdogThread;
+    gWatchdogThread = NULL;
+    PR_NotifyCondVar(gWatchdogWakeup);
+    PR_Unlock(gWatchdogLock);
+    if (t)
+        PR_JoinThread(t);
+}
+
+static void
+WakeupWatchdog()
+{
+    PR_Lock(gWatchdogLock);
+    if (gWatchdogThread && gWatchdogLimit &&
+        (gCurrentInterval == PR_INTERVAL_NO_TIMEOUT ||
+         gCurrentInterval > gWatchdogLimit)) {
+        PR_NotifyCondVar(gWatchdogWakeup);
+    }
+    PR_Unlock(gWatchdogLock);
+
+}
+
+static JSBool
+ShellOperationCallback(JSContext *cx)
+{
+    if (gWatchdogLimit) {
+        fprintf(stderr, "Error: Script is running too long\n");
+        return JS_FALSE;
+    }
+    return JS_TRUE;
+}
+
+static void
+WatchdogMain(void *arg)
+{
+    JSRuntime *rt = (JSRuntime *) arg;
+    PRStatus status;
+    PRBool isRunning;
+
+    do {
+        JSContext *iter = NULL;
+        JSContext *acx;
+        JSBool isContextRunning = JS_FALSE;
+        PRIntervalTime ct = PR_IntervalNow();
+
+        PR_Lock(gWatchdogLock);
+        if (gWatchdogLimit) {
+            JS_LOCK_GC(rt);
+            while ((acx = js_ContextIterator(rt, JS_FALSE, &iter))) {
+                if (acx->requestDepth) {
+                    if (ct - acx->startTime > gWatchdogLimit)
+                        JS_TriggerOperationCallback(acx);
+                    if (!isContextRunning)
+                        isContextRunning = JS_TRUE;
+                }
+            }
+            JS_UNLOCK_GC(rt);
+        }
+        gCurrentInterval = (isContextRunning && gWatchdogLimit)
+                           ? gWatchdogLimit
+                           : PR_INTERVAL_NO_TIMEOUT;
+        if (gWatchdogRunning)
+            status = PR_WaitCondVar(gWatchdogWakeup, gCurrentInterval);
+        isRunning = gWatchdogRunning;
+        PR_Unlock(gWatchdogLock);
+    } while (isRunning && status == PR_SUCCESS);
+}
+
+/*
+ * Get the watchdog limit associated with the watchdog callback.
+ */
+static PRIntervalTime
+GetWatchdogLimit(JSContext *cx)
+{
+    return gWatchdogLimit;
+}
+
+/*
+ * Change the watchdog limit associated with the watchdog callback. This API
+ * function may be called only when the result of JS_GetOperationCallback(cx)
+ * is not null.
+ */
+static JSBool
+SetWatchdogLimit(JSContext *cx, PRIntervalTime newWatchdogLimit)
+{
+    if (newWatchdogLimit == gWatchdogLimit)
+        return JS_TRUE;
+
+    gWatchdogLimit = newWatchdogLimit;
+
+    /*
+     * Start a new watchdog thread if it has not been started. If it has been
+     * started wake up the thread and cause the watchdog rescheduling.
+     */
+    PR_Lock(gWatchdogLock);
+    if (!gWatchdogThread) {
+        gWatchdogRunning = PR_TRUE;
+        gWatchdogThread =
+            PR_CreateThread(PRThreadType(PR_USER_THREAD),
+                            WatchdogMain,
+                            cx->runtime,
+                            PRThreadPriority(PR_PRIORITY_NORMAL),
+                            PRThreadScope(PR_LOCAL_THREAD),
+                            PRThreadState(PR_JOINABLE_THREAD),
+                            0);
+    }
+    PR_Unlock(gWatchdogLock);
+    if (!gWatchdogThread) {
+        JS_ReportError(cx, "Failed to create watchdog thread");
+        return JS_FALSE;
+    }
+
+    WakeupWatchdog();
+    return JS_TRUE;
+}
+
+#endif
 
 static void
 SetContextOptions(JSContext *cx)
 {
     jsuword stackLimit;
 
     if (gMaxStackSize == 0) {
         /*
@@ -212,20 +352,22 @@ SetContextOptions(JSContext *cx)
 #if JS_STACK_GROWTH_DIRECTION > 0
         stackLimit = gStackBase + gMaxStackSize;
 #else
         stackLimit = gStackBase - gMaxStackSize;
 #endif
     }
     JS_SetThreadStackLimit(cx, stackLimit);
     JS_SetScriptStackQuota(cx, gScriptStackQuota);
+#if JS_HAS_OPERATION_COUNT
     if (gEnableBranchCallback) {
         JS_SetBranchCallback(cx, my_BranchCallback);
         JS_ToggleOptions(cx, JSOPTION_NATIVE_BRANCH_CALLBACK);
     }
+#endif
 }
 
 static void
 Process(JSContext *cx, JSObject *obj, char *filename, JSBool forceTTY)
 {
     JSBool ok, hitEOF;
     JSScript *script;
     jsval result;
@@ -419,17 +561,19 @@ ProcessArgs(JSContext *cx, JSObject *obj
      * have to keep the option logic here and in the second for loop in sync.
      */
     for (i = 0; i < argc; i++) {
         if (argv[i][0] != '-' || argv[i][1] == '\0') {
             ++i;
             break;
         }
         switch (argv[i][1]) {
+#if JS_HAS_OPERATION_COUNT
           case 'b':
+#endif
           case 'c':
           case 'f':
           case 'e':
           case 'v':
           case 'S':
 #ifdef JS_GC_ZEAL
           case 'Z':
 #endif
@@ -539,23 +683,25 @@ extern void js_InitJITStatsClass(JSConte
                 if (!JS_SetPrototype(cx, gobj, obj))
                     return JS_FALSE;
                 JS_SetParent(cx, gobj, NULL);
                 JS_SetGlobalObject(cx, gobj);
                 obj = gobj;
             }
             break;
 
+#if JS_HAS_OPERATION_COUNT
         case 'b':
             if (++i == argc)
                 return usage();
 
             gBranchLimit = atoi(argv[i]);
             gEnableBranchCallback = (gBranchLimit != 0);
             break;
+#endif
 
         case 'c':
             /* set stack chunk size */
             gStackChunkSize = atoi(argv[++i]);
             break;
 
         case 'f':
             if (++i == argc)
@@ -2161,16 +2307,48 @@ TestUTF8(JSContext *cx, JSObject *obj, u
 
 static JSBool
 ThrowError(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
     JS_ReportError(cx, "This is an error");
     return JS_FALSE;
 }
 
+#if !JS_HAS_OPERATION_COUNT
+
+static JSBool
+WatchdogInterval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+    if (argc > 1) {
+        JS_ReportError(cx, "Wrong number of arguments");
+        return JS_FALSE;
+    }
+
+    if (argc == 0)
+        return JS_NewDoubleValue(cx, GetWatchdogLimit(cx), rval);
+
+    jsdouble interval;
+    if (!JS_ValueToNumber(cx, argv[0], &interval))
+        return JS_FALSE;
+
+    /* NB: The next condition take negative values and NaNs into account. */
+    if (!(interval >= 0.0)) {
+        JS_ReportError(cx, "Negative or NaN argument value");
+        return JS_FALSE;
+    }
+    if (interval > 1800.0) {
+        JS_ReportError(cx, "Excessive argument value");
+        return JS_FALSE;
+    }
+
+    return SetWatchdogLimit(cx, (PRIntervalTime) (interval * PR_TicksPerSecond()));
+}
+
+#endif
+
 #define LAZY_STANDARD_CLASSES
 
 /* A class for easily testing the inner/outer object callbacks. */
 typedef struct ComplexObject {
     JSBool isInner;
     JSBool frozen;
     JSObject *inner;
     JSObject *outer;
@@ -2746,22 +2924,24 @@ Scatter(JSContext *cx, uintN argc, jsval
     jsuint i;
     jsuint n;  /* number of threads */
     JSObject *inArr;
     JSObject *arr;
     ScatterData sd;
     JSBool ok;
     jsrefcount rc;
 
+#if JS_HAS_OPERATION_COUNT
     if (!gEnableBranchCallback) {
         /* Enable the branch callback, for periodic scope-sharing. */
         gEnableBranchCallback = JS_TRUE;
         JS_SetBranchCallback(cx, my_BranchCallback);
         JS_ToggleOptions(cx, JSOPTION_NATIVE_BRANCH_CALLBACK);
     }
+#endif
 
     sd.lock = NULL;
     sd.cvar = NULL;
     sd.results = NULL;
     sd.threads = NULL;
     sd.status = SCATTER_WAIT;
 
     if (argc == 0 || JSVAL_IS_PRIMITIVE(JS_ARGV(cx, vp)[0])) {
@@ -3051,16 +3231,19 @@ static JSFunctionSpec shell_functions[] 
     JS_FS("trap",           Trap,           3,0,0),
     JS_FS("untrap",         Untrap,         2,0,0),
     JS_FS("line2pc",        LineToPC,       0,0,0),
     JS_FS("pc2line",        PCToLine,       0,0,0),
     JS_FN("stackQuota",     StackQuota,     0,0),
     JS_FS("stringsAreUTF8", StringsAreUTF8, 0,0,0),
     JS_FS("testUTF8",       TestUTF8,       1,0,0),
     JS_FS("throwError",     ThrowError,     0,0,0),
+#if !JS_HAS_OPERATION_COUNT
+    JS_FS("watchint",       WatchdogInterval,     1,0,0),
+#endif
 #ifdef DEBUG
     JS_FS("dis",            Disassemble,    1,0,0),
     JS_FS("disfile",        DisassFile,     1,0,0),
     JS_FS("dissrc",         DisassWithSrc,  1,0,0),
     JS_FN("dumpHeap",       DumpHeap,       0,0),
     JS_FS("notes",          Notes,          1,0,0),
     JS_FS("tracing",        Tracing,        0,0,0),
     JS_FS("stats",          DumpStats,      1,0,0),
@@ -3133,16 +3316,21 @@ static const char *const shell_help_mess
 "trap([fun, [pc,]] exp)   Trap bytecode execution",
 "untrap(fun[, pc])        Remove a trap",
 "line2pc([fun,] line)     Map line number to PC",
 "pc2line(fun[, pc])       Map PC to line number",
 "stackQuota([number])     Query/set script stack quota",
 "stringsAreUTF8()         Check if strings are UTF-8 encoded",
 "testUTF8(mode)           Perform UTF-8 tests (modes are 1 to 4)",
 "throwError()             Throw an error from JS_ReportError",
+#if !JS_HAS_OPERATION_COUNT
+"watchint(interval)       Set watchdog interval to the specified number"
+" of seconds. If parameters are not specified it returns watchdog interval"
+" in seconds",
+#endif
 #ifdef DEBUG
 "dis([fun])               Disassemble functions into bytecodes",
 "disfile('foo.js')        Disassemble script file into bytecodes",
 "dissrc([fun])            Disassemble functions with source lines",
 "dumpHeap([fileName[, start[, toFind[, maxDepth[, toIgnore]]]]])\n"
 "  Interface to JS_DumpHeap with output sent to file",
 "notes([fun])             Show source notes for functions",
 "tracing([toggle])        Turn tracing on or off",
@@ -3958,17 +4146,24 @@ Evaluate(JSContext *cx, JSObject *obj, u
 
 static JSBool
 ContextCallback(JSContext *cx, uintN contextOp)
 {
     if (contextOp == JSCONTEXT_NEW) {
         JS_SetErrorReporter(cx, my_ErrorReporter);
         JS_SetVersion(cx, JSVERSION_LATEST);
         SetContextOptions(cx);
+#if !JS_HAS_OPERATION_COUNT
+        JS_SetOperationCallback(cx, ShellOperationCallback);
+    } else if (contextOp == JSCONTEXT_REQUEST_START &&
+               cx->runtime->state != JSRTS_LANDING) {
+        WakeupWatchdog();
+#endif
     }
+
     return JS_TRUE;
 }
 
 int
 main(int argc, char **argv, char **envp)
 {
     int stackDummy;
     JSRuntime *rt;
@@ -4006,16 +4201,28 @@ main(int argc, char **argv, char **envp)
     gOutFile = stdout;
 
     argc--;
     argv++;
 
     rt = JS_NewRuntime(64L * 1024L * 1024L);
     if (!rt)
         return 1;
+
+#if !JS_HAS_OPERATION_COUNT
+    gWatchdogLock = JS_NEW_LOCK();
+    if (!gWatchdogLock)
+        return 1;
+    gWatchdogWakeup = JS_NEW_CONDVAR(gWatchdogLock);
+    if (!gWatchdogWakeup)
+        return 1;
+    gWatchdogLimit = 0;
+    gWatchdogThread = NULL;
+#endif
+
     JS_SetContextCallback(rt, ContextCallback);
 
     cx = JS_NewContext(rt, gStackChunkSize);
     if (!cx)
         return 1;
 
 #ifdef JS_THREADSAFE
     JS_BeginRequest(cx);
@@ -4113,13 +4320,25 @@ main(int argc, char **argv, char **envp)
         JSD_DebuggerOff(jsdc);
     }
 #endif  /* JSDEBUGGER */
 
 #ifdef JS_THREADSAFE
     JS_EndRequest(cx);
 #endif
 
+#if !JS_HAS_OPERATION_COUNT
+    ShutdownWatchdog();
+#endif
+
+#if !JS_HAS_OPERATION_COUNT
+    if (gWatchdogWakeup)
+        JS_DESTROY_CONDVAR(gWatchdogWakeup);
+    if (gWatchdogLock)
+        JS_DESTROY_LOCK(gWatchdogLock);
+#endif
+
     JS_DestroyContext(cx);
     JS_DestroyRuntime(rt);
     JS_ShutDown();
+
     return result;
 }
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -900,36 +900,50 @@ JS_SetRuntimePrivate(JSRuntime *rt, void
     rt->data = data;
 }
 
 JS_PUBLIC_API(void)
 JS_BeginRequest(JSContext *cx)
 {
 #ifdef JS_THREADSAFE
     JSRuntime *rt;
+    JSContextCallback cxCallback;
 
     JS_ASSERT(cx->thread->id == js_CurrentThreadId());
     if (!cx->requestDepth) {
         JS_ASSERT(cx->gcLocalFreeLists == &js_GCEmptyFreeListSet);
 
         /* Wait until the GC is finished. */
         rt = cx->runtime;
+#if !JS_HAS_OPERATION_COUNT
+        cx->startTime = PR_IntervalNow();
+#endif
         JS_LOCK_GC(rt);
 
         /* NB: we use cx->thread here, not js_GetCurrentThread(). */
         if (rt->gcThread != cx->thread) {
             while (rt->gcLevel > 0)
                 JS_AWAIT_GC_DONE(rt);
         }
 
         /* Indicate that a request is running. */
         rt->requestCount++;
         cx->requestDepth = 1;
         cx->outstandingRequests++;
         JS_UNLOCK_GC(rt);
+
+        cxCallback = cx->runtime->cxCallback;
+        if (cxCallback) {
+#ifdef DEBUG
+            JSBool callbackStatus =
+#endif
+                cxCallback(cx, JSCONTEXT_REQUEST_START);
+            JS_ASSERT(callbackStatus);
+        }
+
         return;
     }
     cx->requestDepth++;
     cx->outstandingRequests++;
 #endif
 }
 
 JS_PUBLIC_API(void)
@@ -980,17 +994,19 @@ JS_EndRequest(JSContext *cx)
 
         js_RevokeGCLocalFreeLists(cx);
 
         /* Give the GC a chance to run if this was the last request running. */
         JS_ASSERT(rt->requestCount > 0);
         rt->requestCount--;
         if (rt->requestCount == 0)
             JS_NOTIFY_REQUEST_DONE(rt);
-
+#if !JS_HAS_OPERATION_COUNT
+        cx->startTime = 0;
+#endif
         JS_UNLOCK_GC(rt);
         return;
     }
 
     cx->requestDepth--;
     cx->outstandingRequests--;
 #endif
 }
@@ -3130,17 +3146,17 @@ DefinePropertyById(JSContext *cx, JSObje
                    uintN flags, intN tinyid)
 {
     if (flags != 0 && OBJ_IS_NATIVE(obj)) {
         JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING);
         return js_DefineNativeProperty(cx, obj, id, value, getter, setter,
                                        attrs, flags, tinyid, NULL);
     }
     return OBJ_DEFINE_PROPERTY(cx, obj, id, value, getter, setter, attrs,
-                               NULL);   
+                               NULL);
 }
 
 static JSBool
 DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
                JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
                uintN flags, intN tinyid)
 {
     jsid id;
@@ -3807,17 +3823,17 @@ JS_HasUCProperty(JSContext *cx, JSObject
                  const jschar *name, size_t namelen,
                  JSBool *vp)
 {
     JSBool ok;
     JSObject *obj2;
     JSProperty *prop;
 
     CHECK_REQUEST(cx);
-    ok = LookupUCProperty(cx, obj, name, namelen, 
+    ok = LookupUCProperty(cx, obj, name, namelen,
                           JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
                           &obj2, &prop);
     if (ok) {
         *vp = (prop != NULL);
         if (prop)
             OBJ_DROP_PROPERTY(cx, obj2, prop);
     }
     return ok;
@@ -5244,16 +5260,17 @@ JS_CallFunctionValue(JSContext *cx, JSOb
     JSBool ok;
 
     CHECK_REQUEST(cx);
     ok = js_InternalCall(cx, obj, fval, argc, argv, rval);
     LAST_FRAME_CHECKS(cx, ok);
     return ok;
 }
 
+#if JS_HAS_OPERATION_COUNT
 JS_PUBLIC_API(void)
 JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback,
                         uint32 operationLimit)
 {
     JS_ASSERT(callback);
     JS_ASSERT(operationLimit <= JS_MAX_OPERATION_LIMIT);
     JS_ASSERT(operationLimit > 0);
 
@@ -5319,17 +5336,44 @@ JS_SetBranchCallback(JSContext *cx, JSBr
         cx->operationCount = JSOW_SCRIPT_JUMP;
         cx->operationLimit = JSOW_SCRIPT_JUMP;
         cx->operationCallback = (JSOperationCallback) cb;
     } else {
         JS_ClearOperationCallback(cx);
     }
     return oldcb;
 }
-
+#else
+
+JS_PUBLIC_API(void)
+JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback)
+{
+    cx->operationCallback = callback;
+}
+
+JS_PUBLIC_API(void)
+JS_ClearOperationCallback(JSContext *cx)
+{
+    cx->operationCallback = NULL;
+}
+
+JS_PUBLIC_API(JSOperationCallback)
+JS_GetOperationCallback(JSContext *cx)
+{
+    return cx->operationCallback;
+}
+
+#endif
+
+JS_PUBLIC_API(void)
+JS_TriggerOperationCallback(JSContext *cx)
+{
+    cx->operationCount = 0;
+}
+  
 JS_PUBLIC_API(JSBool)
 JS_IsRunning(JSContext *cx)
 {
     /* The use of cx->fp below is safe: if we're on trace, it is skipped. */
     VOUCH_DOES_NOT_REQUIRE_STACK();
 
     return JS_ON_TRACE(cx) || cx->fp != NULL;
 }
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -40,16 +40,17 @@
 
 #ifndef jsapi_h___
 #define jsapi_h___
 /*
  * JavaScript API.
  */
 #include <stddef.h>
 #include <stdio.h>
+#include "jsversion.h"
 #include "js-config.h"
 #include "jspubtd.h"
 #include "jsutil.h"
 
 JS_BEGIN_EXTERN_C
 
 /*
  * Type tags stored in the low bits of a jsval.
@@ -2164,16 +2165,23 @@ JS_CallFunction(JSContext *cx, JSObject 
 extern JS_PUBLIC_API(JSBool)
 JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc,
                     jsval *argv, jsval *rval);
 
 extern JS_PUBLIC_API(JSBool)
 JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc,
                      jsval *argv, jsval *rval);
 
+extern JS_PUBLIC_API(void)
+JS_ClearOperationCallback(JSContext *cx);
+
+extern JS_PUBLIC_API(JSOperationCallback)
+JS_GetOperationCallback(JSContext *cx);
+
+#if JS_HAS_OPERATION_COUNT
 /*
  * The maximum value of the operation limit to pass to JS_SetOperationCallback
  * and JS_SetOperationLimit.
  */
 #define JS_MAX_OPERATION_LIMIT ((uint32) 0x7FFFFFFF)
 
 #define JS_OPERATION_WEIGHT_BASE 4096
 
@@ -2188,22 +2196,16 @@ JS_CallFunctionValue(JSContext *cx, JSOb
  *   100 * JS_OPERATION_WEIGHT_BASE
  *
  * as a value for operationLimit.
  */
 extern JS_PUBLIC_API(void)
 JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback,
                         uint32 operationLimit);
 
-extern JS_PUBLIC_API(void)
-JS_ClearOperationCallback(JSContext *cx);
-
-extern JS_PUBLIC_API(JSOperationCallback)
-JS_GetOperationCallback(JSContext *cx);
-
 /*
  * Get the operation limit associated with the operation callback. This API
  * function may be called only when the result of JS_GetOperationCallback(cx)
  * is not null.
  */
 extern JS_PUBLIC_API(uint32)
 JS_GetOperationLimit(JSContext *cx);
 
@@ -2221,16 +2223,28 @@ JS_SetOperationLimit(JSContext *cx, uint
  *   JS_SetOperationCallback(cx, callback, 4096, NULL);
  *
  * except that the callback will not be called from a long-running native
  * function when JSOPTION_NATIVE_BRANCH_CALLBACK is not set and the top-most
  * frame is native.
  */
 extern JS_PUBLIC_API(JSBranchCallback)
 JS_SetBranchCallback(JSContext *cx, JSBranchCallback cb);
+#else
+/*
+ * Set the operation callback that the engine calls while resetting
+ * context.
+ */
+extern JS_PUBLIC_API(void)
+JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback);
+
+#endif
+
+extern JS_PUBLIC_API(void)
+JS_TriggerOperationCallback(JSContext *cx);
 
 extern JS_PUBLIC_API(JSBool)
 JS_IsRunning(JSContext *cx);
 
 extern JS_PUBLIC_API(JSBool)
 JS_IsConstructing(JSContext *cx);
 
 /*
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -246,17 +246,21 @@ js_NewContext(JSRuntime *rt, size_t stac
     JSContextCallback cxCallback;
 
     cx = (JSContext *) malloc(sizeof *cx);
     if (!cx)
         return NULL;
     memset(cx, 0, sizeof *cx);
 
     cx->runtime = rt;
+#if JS_OPERATION_COUNT
     JS_ClearOperationCallback(cx);
+#else
+    cx->operationCount = 1;
+#endif
     cx->debugHooks = &rt->globalDebugHooks;
 #if JS_STACK_GROWTH_DIRECTION > 0
     cx->stackLimit = (jsuword)-1;
 #endif
     cx->scriptStackQuota = JS_DEFAULT_SCRIPT_STACK_QUOTA;
 #ifdef JS_THREADSAFE
     cx->gcLocalFreeLists = (JSGCFreeListSet *) &js_GCEmptyFreeListSet;
     JS_INIT_CLIST(&cx->threadLinks);
@@ -502,17 +506,17 @@ js_ValidContextPointer(JSRuntime *rt, JS
     for (cl = rt->contextList.next; cl != &rt->contextList; cl = cl->next) {
         if (cl == &cx->link)
             return JS_TRUE;
     }
     JS_RUNTIME_METER(rt, deadContexts);
     return JS_FALSE;
 }
 
-JSContext *
+JS_FRIEND_API(JSContext *)
 js_ContextIterator(JSRuntime *rt, JSBool unlocked, JSContext **iterp)
 {
     JSContext *cx = *iterp;
 
     if (unlocked)
         JS_LOCK_GC(rt);
     cx = js_ContextFromLinkField(cx ? cx->link.next : rt->contextList.next);
     if (&cx->link == &rt->contextList)
@@ -1343,37 +1347,45 @@ js_GetErrorMessage(void *userRef, const 
     if ((errorNumber > 0) && (errorNumber < JSErr_Limit))
         return &js_ErrorFormatString[errorNumber];
     return NULL;
 }
 
 JSBool
 js_ResetOperationCount(JSContext *cx)
 {
+    JS_ASSERT(cx->operationCount <= 0);
+
+#if JS_HAS_OPERATION_COUNT
     JSScript *script;
     JSStackFrame *fp;
 
-    JS_ASSERT(cx->operationCount <= 0);
-    JS_ASSERT(cx->operationLimit > 0);
-
     cx->operationCount = (int32) cx->operationLimit;
     if (cx->operationCallbackIsSet)
         return cx->operationCallback(cx);
 
     if (cx->operationCallback) {
         /*
          * Invoke the deprecated branch callback. It may be called only when
          * the top-most frame is scripted or JSOPTION_NATIVE_BRANCH_CALLBACK
          * is set.
          */
         fp = js_GetTopStackFrame(cx);
         script = fp ? fp->script : NULL;
         if (script || JS_HAS_OPTION(cx, JSOPTION_NATIVE_BRANCH_CALLBACK))
             return ((JSBranchCallback) cx->operationCallback)(cx, script);
     }
+#else
+    JSOperationCallback operationCallback;
+
+    cx->operationCount = 1;
+    operationCallback = cx->operationCallback;
+    if (operationCallback)
+        return operationCallback(cx);
+#endif
     return JS_TRUE;
 }
 
 #ifndef JS_TRACER
 /* This is defined in jstracer.cpp in JS_TRACER builds. */
 extern JS_FORCES_STACK JSStackFrame *
 js_GetTopStackFrame(JSContext *cx)
 {
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -733,18 +733,22 @@ JS_STATIC_ASSERT(sizeof(JSTempValueUnion
 
 #define JSRESOLVE_INFER         0xffff  /* infer bits from current bytecode */
 
 struct JSContext {
     /*
      * Operation count. It is declared as the first field in the struct to
      * ensure the fastest possible access.
      */
+#if !JS_HAS_OPERATION_COUNT
+    volatile int32      operationCount;
+#else
     int32               operationCount;
-
+#endif
+  
     /* JSRuntime contextList linkage. */
     JSCList             link;
 
 #if JS_HAS_XML_SUPPORT
     /*
      * Bit-set formed from binary exponentials of the XML_* tiny-ids defined
      * for boolean settings in jsxml.c, plus an XSF_CACHE_VALID bit.  Together
      * these act as a cache of the boolean XML.ignore* and XML.prettyPrinting
@@ -847,18 +851,20 @@ struct JSContext {
     /* Per-context optional error reporter. */
     JSErrorReporter     errorReporter;
 
     /*
      * Flag indicating that the operation callback is set. When the flag is 0
      * but operationCallback is not null, operationCallback stores the branch
      * callback.
      */
+#if JS_HAS_OPERATION_COUNT
     uint32              operationCallbackIsSet :    1;
     uint32              operationLimit         :    31;
+#endif
     JSOperationCallback operationCallback;
 
     /* Interpreter activation count. */
     uintN               interpLevel;
 
     /* Client opaque pointers. */
     void                *data;
     void                *data2;
@@ -874,16 +880,20 @@ struct JSContext {
     JSTitle             *lockedSealedTitle; /* weak ref, for low-cost sealed
                                                title locking */
     JSCList             threadLinks;        /* JSThread contextList linkage */
 
 #define CX_FROM_THREAD_LINKS(tl) \
     ((JSContext *)((char *)(tl) - offsetof(JSContext, threadLinks)))
 #endif
 
+#if !JS_HAS_OPERATION_COUNT
+    PRIntervalTime      startTime;          /* time when the context thread was started */
+#endif
+
     /* PDL of stack headers describing stack slots not rooted by argv, etc. */
     JSStackHeader       *stackHeaders;
 
     /* Optional stack of heap-allocated scoped local GC roots. */
     JSLocalRootStack    *localRootStack;
 
     /* Stack of thread-stack-allocated temporary GC roots. */
     JSTempValueRooter   *tempValueRooters;
@@ -1053,17 +1063,17 @@ js_ContextFromLinkField(JSCList *link)
     JS_ASSERT(link);
     return (JSContext *) ((uint8 *) link - offsetof(JSContext, link));
 }
 
 /*
  * If unlocked, acquire and release rt->gcLock around *iterp update; otherwise
  * the caller must be holding rt->gcLock.
  */
-extern JSContext *
+extern JS_FRIEND_API(JSContext *)
 js_ContextIterator(JSRuntime *rt, JSBool unlocked, JSContext **iterp);
 
 /*
  * JSClass.resolve and watchpoint recursion damping machinery.
  */
 extern JSBool
 js_StartResolving(JSContext *cx, JSResolvingKey *key, uint32 flag,
                   JSResolvingEntry **entryp);
@@ -1215,51 +1225,57 @@ extern JSErrorFormatString js_ErrorForma
  * Update the operation counter according to the given weight and call the
  * operation callback when we reach the operation limit. To make this
  * frequently executed macro faster we decrease the counter from
  * JSContext.operationLimit and compare against zero to check the limit.
  *
  * This macro can run the full GC. Return true if it is OK to continue and
  * false otherwise.
  */
-#define JS_CHECK_OPERATION_LIMIT(cx, weight)                                  \
+#if JS_HAS_OPERATION_COUNT
+
+# define JS_CHECK_OPERATION_LIMIT(cx, weight)                                 \
     (JS_CHECK_OPERATION_WEIGHT(weight),                                       \
-     (((cx)->operationCount -= (weight)) > 0 || js_ResetOperationCount(cx)))
+    (((cx)->operationCount -= (weight)) > 0 || js_ResetOperationCount(cx)))
 
 /*
  * A version of JS_CHECK_OPERATION_LIMIT that just updates the operation count
  * without calling the operation callback or any other API. This macro resets
  * the count to 0 when it becomes negative to prevent a wrap-around when the
  * macro is called repeatably.
  */
-#define JS_COUNT_OPERATION(cx, weight)                                        \
+# define JS_COUNT_OPERATION(cx, weight)                                       \
     ((void)(JS_CHECK_OPERATION_WEIGHT(weight),                                \
-            (cx)->operationCount = ((cx)->operationCount > 0)                 \
-                                   ? (cx)->operationCount - (weight)          \
-                                   : 0))
+     (cx)->operationCount = ((cx)->operationCount > 0)                        \
+                            ? (cx)->operationCount - (weight)                 \
+                            : 0))
 
 /*
  * The implementation of the above macros assumes that subtracting weights
  * twice from a positive number does not wrap-around INT32_MIN.
  */
-#define JS_CHECK_OPERATION_WEIGHT(weight)                                     \
+# define JS_CHECK_OPERATION_WEIGHT(weight)                                    \
     (JS_ASSERT((uint32) (weight) > 0),                                        \
      JS_ASSERT((uint32) (weight) < JS_BIT(30)))
 
 /* Relative operations weights. */
-#define JSOW_JUMP                   1
-#define JSOW_ALLOCATION             100
-#define JSOW_LOOKUP_PROPERTY        5
-#define JSOW_GET_PROPERTY           10
-#define JSOW_SET_PROPERTY           20
-#define JSOW_NEW_PROPERTY           200
-#define JSOW_DELETE_PROPERTY        30
-#define JSOW_ENTER_SHARP            JS_OPERATION_WEIGHT_BASE
-#define JSOW_SCRIPT_JUMP            JS_OPERATION_WEIGHT_BASE
-
+# define JSOW_JUMP                 1
+# define JSOW_ALLOCATION           100
+# define JSOW_LOOKUP_PROPERTY      5
+# define JSOW_GET_PROPERTY         10
+# define JSOW_SET_PROPERTY         20
+# define JSOW_NEW_PROPERTY         200
+# define JSOW_DELETE_PROPERTY      30
+# define JSOW_ENTER_SHARP          JS_OPERATION_WEIGHT_BASE
+# define JSOW_SCRIPT_JUMP          JS_OPERATION_WEIGHT_BASE
+#else
+# define JS_CHECK_OPERATION_LIMIT(cx, weight)                                 \
+     (((cx)->operationCount) > 0 || js_ResetOperationCount(cx))
+# define JS_COUNT_OPERATION(cx, weight) ((void) 0)
+#endif
 /*
  * Reset the operation count and call the operation callback assuming that the
  * operation limit is reached.
  */
 extern JSBool
 js_ResetOperationCount(JSContext *cx);
 
 /*
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -2662,24 +2662,33 @@ js_Interpret(JSContext *cx)
 #define MONITOR_BRANCH() ((void) 0)
 
 #endif /* !JS_TRACER */
 
     /*
      * Prepare to call a user-supplied branch handler, and abort the script
      * if it returns false.
      */
-#define CHECK_BRANCH()                                                        \
+#if JS_HAS_OPERATION_COUNT
+# define CHECK_BRANCH()                                                       \
     JS_BEGIN_MACRO                                                            \
         if ((cx->operationCount -= JSOW_SCRIPT_JUMP) <= 0) {                  \
             if (!js_ResetOperationCount(cx))                                  \
                 goto error;                                                   \
         }                                                                     \
     JS_END_MACRO
-
+#else
+# define CHECK_BRANCH()                                                       \
+    JS_BEGIN_MACRO                                                            \
+        if (cx->operationCount < 1) {                                         \
+            if (!js_ResetOperationCount(cx))                                  \
+                goto error;                                                   \
+        }                                                                     \
+    JS_END_MACRO
+#endif
 #define BRANCH(n)                                                             \
     JS_BEGIN_MACRO                                                            \
         regs.pc += n;                                                         \
         if (n <= 0) {                                                         \
             CHECK_BRANCH();                                                   \
             MONITOR_BRANCH();                                                 \
         }                                                                     \
         op = (JSOp) *regs.pc;                                                 \
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -101,18 +101,18 @@ typedef enum JSProtoKey {
     JSProto_LIMIT
 } JSProtoKey;
 
 /* JSObjectOps.checkAccess mode enumeration. */
 typedef enum JSAccessMode {
     JSACC_PROTO  = 0,           /* XXXbe redundant w.r.t. id */
     JSACC_PARENT = 1,           /* XXXbe redundant w.r.t. id */
 
-                                /* 
-                                 * enum value #2 formerly called JSACC_IMPORT, 
+                                /*
+                                 * enum value #2 formerly called JSACC_IMPORT,
                                  * gap preserved for liveconnect ABI compatibility.
                                  */
 
     JSACC_WATCH  = 3,           /* a watchpoint on object foo for id 'bar' */
     JSACC_READ   = 4,           /* a "get" of foo.bar */
     JSACC_WRITE  = 8,           /* a "set" of foo.bar = baz */
     JSACC_LIMIT
 } JSAccessMode;
@@ -589,31 +589,35 @@ typedef JSBool
 /* See jsapi.h, the JS_CALLEE, JS_THIS, etc. macros. */
 typedef JSBool
 (* JSFastNative)(JSContext *cx, uintN argc, jsval *vp);
 
 /* Callbacks and their arguments. */
 
 typedef enum JSContextOp {
     JSCONTEXT_NEW,
-    JSCONTEXT_DESTROY
+    JSCONTEXT_DESTROY,
+    JSCONTEXT_REQUEST_START
 } JSContextOp;
 
 /*
  * The possible values for contextOp when the runtime calls the callback are:
- *   JSCONTEXT_NEW      JS_NewContext successfully created a new JSContext
- *                      instance. The callback can initialize the instance as
- *                      required. If the callback returns false, the instance
- *                      will be destroyed and JS_NewContext returns null. In
- *                      this case the callback is not called again.
- *   JSCONTEXT_DESTROY  One of JS_DestroyContext* methods is called. The
- *                      callback may perform its own cleanup and must always
- *                      return true.
- *   Any other value    For future compatibility the callback must do nothing
- *                      and return true in this case.
+ *  JSCONTEXT_NEW           JS_NewContext successfully created a new JSContext
+ *                          instance. The callback can initialize the instance as
+ *                          required. If the callback returns false, the instance
+ *                          will be destroyed and JS_NewContext returns null. In
+ *                          this case the callback is not called again.
+ *  JSCONTEXT_DESTROY       One of JS_DestroyContext* methods is called. The
+ *                          callback may perform its own cleanup and must always
+ *                          return true.
+ *  JSCONTEXT_REQUEST_START JS_BeginRequest was called with requestDepth == 0.
+ *                          This callback can be used to notify other components
+ *                          that execution has begun on this context.
+ *  Any other value         For future compatibility the callback must do nothing
+ *                          and return true in this case.
  */
 typedef JSBool
 (* JSContextCallback)(JSContext *cx, uintN contextOp);
 
 typedef enum JSGCStatus {
     JSGC_BEGIN,
     JSGC_END,
     JSGC_MARK_END,
--- a/js/src/jsversion.h
+++ b/js/src/jsversion.h
@@ -236,8 +236,16 @@
 #endif
 
 /* Features that are present in all versions. */
 #define JS_HAS_RESERVED_JAVA_KEYWORDS   1
 #define JS_HAS_RESERVED_ECMA_KEYWORDS   1
 
 /* Feature-test macro for evolving destructuring support. */
 #define JS_HAS_DESTRUCTURING_SHORTHAND  (JS_HAS_DESTRUCTURING == 2)
+
+#ifndef JS_HAS_OPERATION_COUNT
+# if defined(MOZILLA_VERSION) || defined(JS_THREADSAFE)
+#  define JS_HAS_OPERATION_COUNT 0
+# else
+#  define JS_HAS_OPERATION_COUNT 1
+# endif
+#endif
--- a/js/src/xpconnect/idl/nsIXPConnect.idl
+++ b/js/src/xpconnect/idl/nsIXPConnect.idl
@@ -65,16 +65,17 @@
       native JSVal(jsval);
 [ptr] native JSClassConstPtr(const JSClass);
       native JSGetObjectOps(JSGetObjectOps);
       native JSID(jsid);
 [ptr] native voidPtrPtr(void*);
 [ptr] native nsScriptObjectTracerPtr(nsScriptObjectTracer);
 [ref] native nsCCTraversalCallbackRef(nsCycleCollectionTraversalCallback);
 [ptr] native nsAXPCNativeCallContextPtr(nsAXPCNativeCallContext);
+      native PRIntervalTime(PRIntervalTime);
 
 /***************************************************************************/
 
 %{ C++
 /***************************************************************************/
 #define GENERATE_XPC_FAILURE(x) \
             (NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XPCONNECT,x))
 
@@ -400,17 +401,17 @@ interface nsIXPCFunctionThisTranslator :
 %{ C++
 // For use with the service manager
 // {CB6593E0-F9B2-11d2-BDD6-000064657374}
 #define NS_XPCONNECT_CID \
 { 0xcb6593e0, 0xf9b2, 0x11d2, \
     { 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } }
 %}
 
-[uuid(f8bf005e-3700-411c-ba0c-e018075f22a4)]
+[uuid(eb95710a-e112-44ae-abe1-6f8dfb58d7f8)]
 interface nsIXPConnect : nsISupports
 {
 %{ C++
   NS_DEFINE_STATIC_CID_ACCESSOR(NS_XPCONNECT_CID)
 %}
 
     void
     initClasses(in JSContextPtr aJSContext,
@@ -780,9 +781,25 @@ interface nsIXPConnect : nsISupports
      *     interfaceCount are like what nsIClassInfo.getInterfaces returns.
      */
     [noscript,notxpcom] PRBool defineDOMQuickStubs(
         in JSContextPtr cx,
         in JSObjectPtr proto,
         in PRUint32 flags,
         in PRUint32 interfaceCount,
         [array, size_is(interfaceCount)] in nsIIDPtr interfaceArray);
+
+    /**
+     * Returns the value of the watchdog limit for the specified context.
+     * @param cx
+     *     A context
+     */
+    [noscript,notxpcom] PRIntervalTime getWatchdogLimit(in JSContextPtr cx);
+
+    /**
+     * Sets a new value of the watchdog limit.
+     * @param cx
+     *     A context
+     * @param limit
+     *     New value of the watchdog limit.
+     */
+    [noscript,notxpcom] PRBool setWatchdogLimit(in JSContextPtr cx, in PRIntervalTime limit);
 };
--- a/js/src/xpconnect/src/nsXPConnect.cpp
+++ b/js/src/xpconnect/src/nsXPConnect.cpp
@@ -314,23 +314,23 @@ static PRBool IIDTester(nsIInterfaceInfo
 
 static PRBool NameTester(nsIInterfaceInfoManager* manager, const void* data,
                       nsIInterfaceInfo** info)
 {
     return NS_SUCCEEDED(manager->GetInfoForName((const char *) data, info)) &&
            *info;
 }
 
-static nsresult FindInfo(InfoTester tester, const void* data, 
+static nsresult FindInfo(InfoTester tester, const void* data,
                          nsIInterfaceInfoSuperManager* iism,
                          nsIInterfaceInfo** info)
 {
     if(tester(iism, data, info))
         return NS_OK;
-    
+
     // If not found, then let's ask additional managers.
 
     PRBool yes;
     nsCOMPtr<nsISimpleEnumerator> list;
 
     if(NS_SUCCEEDED(iism->HasAdditionalManagers(&yes)) && yes &&
        NS_SUCCEEDED(iism->EnumerateAdditionalManagers(getter_AddRefs(list))) &&
        list)
@@ -340,19 +340,19 @@ static nsresult FindInfo(InfoTester test
 
         while(NS_SUCCEEDED(list->HasMoreElements(&more)) && more &&
               NS_SUCCEEDED(list->GetNext(getter_AddRefs(current))) && current)
         {
             if(tester(current, data, info))
                 return NS_OK;
         }
     }
-    
+
     return NS_ERROR_NO_INTERFACE;
-}    
+}
 
 nsresult
 nsXPConnect::GetInfoForIID(const nsIID * aIID, nsIInterfaceInfo** info)
 {
     return FindInfo(IIDTester, aIID, mInterfaceInfoManager, info);
 }
 
 nsresult
@@ -432,17 +432,17 @@ nsXPConnect::Collect()
     //
     //
     // We split up garbage collection into 3 phases (1, 3 and 4) and do cycle
     // collection between the first 2 phases of garbage collection:
     //
     // 1. marking of the roots in category 1 by having the JS GC do its marking
     // 2. cycle collection
     // 3. marking of the roots in category 2 by
-    //    XPCJSRuntime::TraceXPConnectRoots 
+    //    XPCJSRuntime::TraceXPConnectRoots
     // 4. sweeping of unmarked JS objects
     //
     // During cycle collection, marked JS objects (and the objects they hold)
     // will be colored black. White objects holding roots from category 2 will
     // be forgotten by XPConnect (in the unlink callback of the white objects).
     // During phase 3 we'll only mark black objects holding JS objects (white
     // objects were forgotten) and white JS objects will be swept during
     // phase 4.
@@ -518,17 +518,17 @@ NoteJSRoot(JSTracer *trc, void *thing, u
     }
     else if(kind != JSTRACE_DOUBLE && kind != JSTRACE_STRING)
     {
         JS_TraceChildren(trc, thing, kind);
     }
 }
 #endif
 
-nsresult 
+nsresult
 nsXPConnect::BeginCycleCollection(nsCycleCollectionTraversalCallback &cb)
 {
 #ifdef DEBUG_CC
     NS_ASSERTION(!mJSRoots.ops, "Didn't call FinishCollection?");
 
     if(!mCycleCollectionContext)
     {
         // Being called from nsCycleCollector::ExplainLiveExpectedGarbage.
@@ -586,17 +586,17 @@ nsXPConnect::BeginCycleCollection(nsCycl
 #ifndef XPCONNECT_STANDALONE
 void
 nsXPConnect::RecordTraversal(void *p, nsISupports *s)
 {
     mScopes.Put(p, s);
 }
 #endif
 
-nsresult 
+nsresult
 nsXPConnect::FinishCycleCollection()
 {
 #ifdef DEBUG_CC
     if(mExplainCycleCollectionContext)
     {
         mCycleCollectionContext = nsnull;
         mExplainCycleCollectionContext = nsnull;
 
@@ -873,17 +873,17 @@ nsXPConnect::Traverse(void *p, nsCycleCo
 
     TraversalTracer trc(cb);
 
     JS_TRACER_INIT(&trc, cx, NoteJSChild);
     JS_TraceChildren(&trc, p, traceKind);
 
     if(traceKind != JSTRACE_OBJECT)
         return NS_OK;
-    
+
     JSObject *obj = static_cast<JSObject*>(p);
     JSClass* clazz = OBJ_GET_CLASS(cx, obj);
 
     if(clazz == &XPC_WN_Tearoff_JSClass)
     {
         // A tearoff holds a strong reference to its native object
         // (see XPCWrappedNative::FlatJSObjectFinalized). Its XPCWrappedNative
         // will be held alive through the parent of the JSObject of the tearoff.
@@ -1703,17 +1703,17 @@ nsXPConnect::GetFunctionThisTranslator(c
         old = map->Find(aIID);
         NS_IF_ADDREF(old);
         *_retval = old;
     }
     return NS_OK;
 }
 
 /* void setSafeJSContextForCurrentThread (in JSContextPtr cx); */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPConnect::SetSafeJSContextForCurrentThread(JSContext * cx)
 {
     XPCCallContext ccx(NATIVE_CALLER);
     if(!ccx.IsValid())
         return UnexpectedFailure(NS_ERROR_FAILURE);
     return ccx.GetThreadData()->GetJSContextStack()->SetSafeJSContext(cx);
 }
 
@@ -1724,20 +1724,20 @@ nsXPConnect::ClearAllWrappedNativeSecuri
     XPCCallContext ccx(NATIVE_CALLER);
     if(!ccx.IsValid())
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     return XPCWrappedNativeScope::ClearAllWrappedNativeSecurityPolicies(ccx);
 }
 
 /* void restoreWrappedNativePrototype (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsIClassInfo aClassInfo, in nsIXPConnectJSObjectHolder aPrototype); */
-NS_IMETHODIMP 
-nsXPConnect::RestoreWrappedNativePrototype(JSContext * aJSContext, 
-                                           JSObject * aScope, 
-                                           nsIClassInfo * aClassInfo, 
+NS_IMETHODIMP
+nsXPConnect::RestoreWrappedNativePrototype(JSContext * aJSContext,
+                                           JSObject * aScope,
+                                           nsIClassInfo * aClassInfo,
                                            nsIXPConnectJSObjectHolder * aPrototype)
 {
     XPCCallContext ccx(NATIVE_CALLER, aJSContext);
     if(!ccx.IsValid())
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     if(!aClassInfo || !aPrototype)
         return UnexpectedFailure(NS_ERROR_INVALID_ARG);
@@ -1885,43 +1885,43 @@ nsXPConnect::GetXPCWrappedNativeJSClassI
     *clazz = &XPC_WN_NoHelper_JSClass.base;
     *ops1 = XPC_WN_GetObjectOpsNoCall;
     *ops2 = XPC_WN_GetObjectOpsWithCall;
 
     return NS_OK;
 }
 
 /* nsIXPConnectJSObjectHolder getWrappedNativePrototype (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsIClassInfo aClassInfo); */
-NS_IMETHODIMP 
-nsXPConnect::GetWrappedNativePrototype(JSContext * aJSContext, 
-                                       JSObject * aScope, 
-                                       nsIClassInfo *aClassInfo, 
+NS_IMETHODIMP
+nsXPConnect::GetWrappedNativePrototype(JSContext * aJSContext,
+                                       JSObject * aScope,
+                                       nsIClassInfo *aClassInfo,
                                        nsIXPConnectJSObjectHolder **_retval)
 {
     XPCCallContext ccx(NATIVE_CALLER, aJSContext);
     if(!ccx.IsValid())
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     XPCWrappedNativeScope* scope =
         XPCWrappedNativeScope::FindInJSObjectScope(ccx, aScope);
     if(!scope)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     XPCNativeScriptableCreateInfo sciProto;
     XPCWrappedNative::GatherProtoScriptableCreateInfo(aClassInfo, &sciProto);
 
     AutoMarkingWrappedNativeProtoPtr proto(ccx);
-    proto = XPCWrappedNativeProto::GetNewOrUsed(ccx, scope, aClassInfo, 
+    proto = XPCWrappedNativeProto::GetNewOrUsed(ccx, scope, aClassInfo,
                                                 &sciProto, JS_FALSE,
                                                 OBJ_IS_NOT_GLOBAL);
     if(!proto)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     nsIXPConnectJSObjectHolder* holder;
-    *_retval = holder = XPCJSObjectHolder::newHolder(ccx, 
+    *_retval = holder = XPCJSObjectHolder::newHolder(ccx,
                                                      proto->GetJSProtoObject());
     if(!holder)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     NS_ADDREF(holder);
     return NS_OK;
 }
 
@@ -1982,53 +1982,53 @@ nsXPConnect::UpdateXOWs(JSContext* aJSCo
         if(!PerformOp(aJSContext, aWay, cur->obj))
             return NS_ERROR_FAILURE;
     }
 
     return NS_OK;
 }
 
 /* void releaseJSContext (in JSContextPtr aJSContext, in PRBool noGC); */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPConnect::ReleaseJSContext(JSContext * aJSContext, PRBool noGC)
 {
     NS_ASSERTION(aJSContext, "bad param");
     XPCPerThreadData* tls = XPCPerThreadData::GetData(aJSContext);
     if(tls)
     {
         XPCCallContext* ccx = nsnull;
-        for(XPCCallContext* cur = tls->GetCallContext(); 
-            cur; 
+        for(XPCCallContext* cur = tls->GetCallContext();
+            cur;
             cur = cur->GetPrevCallContext())
         {
             if(cur->GetJSContext() == aJSContext)
             {
                 ccx = cur;
                 // Keep looping to find the deepest matching call context.
             }
         }
-    
+
         if(ccx)
         {
 #ifdef DEBUG_xpc_hacker
-            printf("!xpc - deferring destruction of JSContext @ %p\n", 
+            printf("!xpc - deferring destruction of JSContext @ %p\n",
                    (void *)aJSContext);
 #endif
             ccx->SetDestroyJSContextInDestructor(JS_TRUE);
             JS_ClearNewbornRoots(aJSContext);
             return NS_OK;
         }
         // else continue on and synchronously destroy the JSContext ...
 
-        NS_ASSERTION(!tls->GetJSContextStack() || 
+        NS_ASSERTION(!tls->GetJSContextStack() ||
                      !tls->GetJSContextStack()->
                         DEBUG_StackHasJSContext(aJSContext),
                      "JSContext still in threadjscontextstack!");
     }
-    
+
     if(noGC)
         JS_DestroyContextNoGC(aJSContext);
     else
         JS_DestroyContext(aJSContext);
     return NS_OK;
 }
 
 /* void debugDump (in short depth); */
@@ -2139,62 +2139,62 @@ nsXPConnect::DebugDumpEvalInJSStackFrame
         printf("there is no JSContext on the nsIThreadJSContextStack!\n");
     else
         xpc_DumpEvalInJSStackFrame(cx, aFrameNumber, aSourceText);
 
     return NS_OK;
 }
 
 /* JSVal variantToJS (in JSContextPtr ctx, in JSObjectPtr scope, in nsIVariant value); */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPConnect::VariantToJS(JSContext* ctx, JSObject* scope, nsIVariant* value, jsval* _retval)
 {
     NS_PRECONDITION(ctx, "bad param");
     NS_PRECONDITION(scope, "bad param");
     NS_PRECONDITION(value, "bad param");
     NS_PRECONDITION(_retval, "bad param");
 
     XPCCallContext ccx(NATIVE_CALLER, ctx);
     if(!ccx.IsValid())
         return NS_ERROR_FAILURE;
 
     nsresult rv = NS_OK;
     if(!XPCVariant::VariantDataToJS(ccx, value, scope, &rv, _retval))
     {
-        if(NS_FAILED(rv)) 
+        if(NS_FAILED(rv))
             return rv;
 
         return NS_ERROR_FAILURE;
     }
 
     return NS_OK;
 }
 
 /* nsIVariant JSToVariant (in JSContextPtr ctx, in JSVal value); */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPConnect::JSToVariant(JSContext* ctx, jsval value, nsIVariant** _retval)
 {
     NS_PRECONDITION(ctx, "bad param");
     NS_PRECONDITION(value, "bad param");
     NS_PRECONDITION(_retval, "bad param");
 
     XPCCallContext ccx(NATIVE_CALLER, ctx);
     if(!ccx.IsValid())
         return NS_ERROR_FAILURE;
 
     *_retval = XPCVariant::newVariant(ccx, value);
-    if(!(*_retval)) 
+    if(!(*_retval))
         return NS_ERROR_FAILURE;
 
     return NS_OK;
 }
 
 /* void flagSystemFilenamePrefix (in string filenamePrefix,
  *                                in PRBool aWantNativeWrappers); */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPConnect::FlagSystemFilenamePrefix(const char *aFilenamePrefix,
                                       PRBool aWantNativeWrappers)
 {
     NS_PRECONDITION(aFilenamePrefix, "bad param");
 
     JSRuntime* rt = GetRuntime()->GetJSRuntime();;
     uint32 flags = JSFILENAME_SYSTEM;
     if(aWantNativeWrappers)
@@ -2387,16 +2387,28 @@ nsXPConnect::SetSafeJSContext(JSContext 
     XPCPerThreadData* data = XPCPerThreadData::GetData(aSafeJSContext);
 
     if(!data)
         return NS_ERROR_FAILURE;
 
     return data->GetJSContextStack()->SetSafeJSContext(aSafeJSContext);
 }
 
+NS_IMETHODIMP_(PRBool)
+nsXPConnect::SetWatchdogLimit(JSContext *cx, PRIntervalTime limit)
+{
+    return GetRuntime()->SetWatchdogLimit(cx, limit);
+}
+
+NS_IMETHODIMP_(PRIntervalTime)
+nsXPConnect::GetWatchdogLimit(JSContext *cx)
+{
+    return GetRuntime()->GetWatchdogLimit(cx);
+}
+
 /* These are here to be callable from a debugger */
 JS_BEGIN_EXTERN_C
 JS_EXPORT_API(void) DumpJSStack()
 {
     nsresult rv;
     nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
     if(NS_SUCCEEDED(rv) && xpc)
         xpc->DebugDumpJSStack(PR_TRUE, PR_TRUE, PR_FALSE);
--- a/js/src/xpconnect/src/xpccomponents.cpp
+++ b/js/src/xpconnect/src/xpccomponents.cpp
@@ -760,17 +760,17 @@ nsXPCComponents_InterfacesByID::CanSetPr
 #endif
 
 /***************************************************************************/
 /***************************************************************************/
 /***************************************************************************/
 
 
 
-class nsXPCComponents_Classes : 
+class nsXPCComponents_Classes :
   public nsIXPCComponents_Classes,
   public nsIXPCScriptable,
   public nsIClassInfo
 {
 public:
     // all the interface method declarations...
     NS_DECL_ISUPPORTS
     NS_DECL_NSIXPCCOMPONENTS_CLASSES
@@ -778,19 +778,19 @@ public:
     NS_DECL_NSICLASSINFO
 
 public:
     nsXPCComponents_Classes();
     virtual ~nsXPCComponents_Classes();
 };
 
 /***************************************************************************/
-/* void getInterfaces (out PRUint32 count, [array, size_is (count), retval] 
+/* void getInterfaces (out PRUint32 count, [array, size_is (count), retval]
                        out nsIIDPtr array); */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Classes::GetInterfaces(PRUint32 *aCount, nsIID * **aArray)
 {
     PRUint32 count = 2;
     *aCount = count;
     nsIID **array;
     *aArray = array = static_cast<nsIID**>(nsMemory::Alloc(count * sizeof(nsIID*)));
     if(!array)
         return NS_ERROR_OUT_OF_MEMORY;
@@ -813,68 +813,68 @@ oom:
     while (index)
         nsMemory::Free(array[--index]);
     nsMemory::Free(array);
     *aArray = nsnull;
     return NS_ERROR_OUT_OF_MEMORY;
 }
 
 /* nsISupports getHelperForLanguage (in PRUint32 language); */
-NS_IMETHODIMP 
-nsXPCComponents_Classes::GetHelperForLanguage(PRUint32 language, 
+NS_IMETHODIMP
+nsXPCComponents_Classes::GetHelperForLanguage(PRUint32 language,
                                       nsISupports **retval)
 {
     *retval = nsnull;
     return NS_OK;
 }
 
 /* readonly attribute string contractID; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Classes::GetContractID(char * *aContractID)
 {
     *aContractID = nsnull;
     return NS_ERROR_NOT_AVAILABLE;
 }
 
 /* readonly attribute string classDescription; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Classes::GetClassDescription(char * *aClassDescription)
 {
     static const char classDescription[] = "XPCComponents_Classes";
     *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription));
     return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
 
 /* readonly attribute nsCIDPtr classID; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Classes::GetClassID(nsCID * *aClassID)
 {
     *aClassID = nsnull;
     return NS_OK;
 }
 
 /* readonly attribute PRUint32 implementationLanguage; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Classes::GetImplementationLanguage(
     PRUint32 *aImplementationLanguage)
 {
     *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
     return NS_OK;
 }
 
 /* readonly attribute PRUint32 flags; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Classes::GetFlags(PRUint32 *aFlags)
 {
     *aFlags = nsIClassInfo::THREADSAFE;
     return NS_OK;
 }
 
 /* [notxpcom] readonly attribute nsCID classIDNoAlloc; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Classes::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
 {
     return NS_ERROR_NOT_AVAILABLE;
 }
 
 nsXPCComponents_Classes::nsXPCComponents_Classes()
 {
 }
@@ -1033,19 +1033,19 @@ public:
     NS_DECL_NSICLASSINFO
 
 public:
     nsXPCComponents_ClassesByID();
     virtual ~nsXPCComponents_ClassesByID();
 };
 
 /***************************************************************************/
-/* void getInterfaces (out PRUint32 count, [array, size_is (count), retval] 
+/* void getInterfaces (out PRUint32 count, [array, size_is (count), retval]
                        out nsIIDPtr array); */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_ClassesByID::GetInterfaces(PRUint32 *aCount, nsIID * **aArray)
 {
     PRUint32 count = 2;
     *aCount = count;
     nsIID **array;
     *aArray = array = static_cast<nsIID**>(nsMemory::Alloc(count * sizeof(nsIID*)));
     if(!array)
         return NS_ERROR_OUT_OF_MEMORY;
@@ -1068,68 +1068,68 @@ oom:
     while (index)
         nsMemory::Free(array[--index]);
     nsMemory::Free(array);
     *aArray = nsnull;
     return NS_ERROR_OUT_OF_MEMORY;
 }
 
 /* nsISupports getHelperForLanguage (in PRUint32 language); */
-NS_IMETHODIMP 
-nsXPCComponents_ClassesByID::GetHelperForLanguage(PRUint32 language, 
+NS_IMETHODIMP
+nsXPCComponents_ClassesByID::GetHelperForLanguage(PRUint32 language,
                                       nsISupports **retval)
 {
     *retval = nsnull;
     return NS_OK;
 }
 
 /* readonly attribute string contractID; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_ClassesByID::GetContractID(char * *aContractID)
 {
     *aContractID = nsnull;
     return NS_ERROR_NOT_AVAILABLE;
 }
 
 /* readonly attribute string classDescription; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_ClassesByID::GetClassDescription(char * *aClassDescription)
 {
     static const char classDescription[] = "XPCComponents_Interfaces";
     *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription));
     return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
 
 /* readonly attribute nsCIDPtr classID; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_ClassesByID::GetClassID(nsCID * *aClassID)
 {
     *aClassID = nsnull;
     return NS_OK;
 }
 
 /* readonly attribute PRUint32 implementationLanguage; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_ClassesByID::GetImplementationLanguage(
     PRUint32 *aImplementationLanguage)
 {
     *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
     return NS_OK;
 }
 
 /* readonly attribute PRUint32 flags; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_ClassesByID::GetFlags(PRUint32 *aFlags)
 {
     *aFlags = nsIClassInfo::THREADSAFE;
     return NS_OK;
 }
 
 /* [notxpcom] readonly attribute nsCID classIDNoAlloc; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_ClassesByID::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
 {
     return NS_ERROR_NOT_AVAILABLE;
 }
 
 nsXPCComponents_ClassesByID::nsXPCComponents_ClassesByID()
 {
 }
@@ -1307,19 +1307,19 @@ public:
     NS_DECL_NSICLASSINFO
 
 public:
     nsXPCComponents_Results();
     virtual ~nsXPCComponents_Results();
 };
 
 /***************************************************************************/
-/* void getInterfaces (out PRUint32 count, [array, size_is (count), retval] 
+/* void getInterfaces (out PRUint32 count, [array, size_is (count), retval]
                        out nsIIDPtr array); */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Results::GetInterfaces(PRUint32 *aCount, nsIID * **aArray)
 {
     PRUint32 count = 2;
     *aCount = count;
     nsIID **array;
     *aArray = array = static_cast<nsIID**>(nsMemory::Alloc(count * sizeof(nsIID*)));
     if(!array)
         return NS_ERROR_OUT_OF_MEMORY;
@@ -1342,68 +1342,68 @@ oom:
     while (index)
         nsMemory::Free(array[--index]);
     nsMemory::Free(array);
     *aArray = nsnull;
     return NS_ERROR_OUT_OF_MEMORY;
 }
 
 /* nsISupports getHelperForLanguage (in PRUint32 language); */
-NS_IMETHODIMP 
-nsXPCComponents_Results::GetHelperForLanguage(PRUint32 language, 
+NS_IMETHODIMP
+nsXPCComponents_Results::GetHelperForLanguage(PRUint32 language,
                                       nsISupports **retval)
 {
     *retval = nsnull;
     return NS_OK;
 }
 
 /* readonly attribute string contractID; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Results::GetContractID(char * *aContractID)
 {
     *aContractID = nsnull;
     return NS_ERROR_NOT_AVAILABLE;
 }
 
 /* readonly attribute string classDescription; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Results::GetClassDescription(char * *aClassDescription)
 {
     static const char classDescription[] = "XPCComponents_Interfaces";
     *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription));
     return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
 
 /* readonly attribute nsCIDPtr classID; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Results::GetClassID(nsCID * *aClassID)
 {
     *aClassID = nsnull;
     return NS_OK;
 }
 
 /* readonly attribute PRUint32 implementationLanguage; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Results::GetImplementationLanguage(
     PRUint32 *aImplementationLanguage)
 {
     *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
     return NS_OK;
 }
 
 /* readonly attribute PRUint32 flags; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Results::GetFlags(PRUint32 *aFlags)
 {
     *aFlags = nsIClassInfo::THREADSAFE;
     return NS_OK;
 }
 
 /* [notxpcom] readonly attribute nsCID classIDNoAlloc; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Results::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
 {
     return NS_ERROR_NOT_AVAILABLE;
 }
 
 nsXPCComponents_Results::nsXPCComponents_Results()
 {
 }
@@ -1539,19 +1539,19 @@ public:
 private:
     NS_METHOD CallOrConstruct(nsIXPConnectWrappedNative *wrapper,
                               JSContext * cx, JSObject * obj,
                               PRUint32 argc, jsval * argv,
                               jsval * vp, PRBool *_retval);
 };
 
 /***************************************************************************/
-/* void getInterfaces (out PRUint32 count, [array, size_is (count), retval] 
+/* void getInterfaces (out PRUint32 count, [array, size_is (count), retval]
                        out nsIIDPtr array); */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_ID::GetInterfaces(PRUint32 *aCount, nsIID * **aArray)
 {
     PRUint32 count = 2;
     *aCount = count;
     nsIID **array;
     *aArray = array = static_cast<nsIID**>(nsMemory::Alloc(count * sizeof(nsIID*)));
     if(!array)
         return NS_ERROR_OUT_OF_MEMORY;
@@ -1574,68 +1574,68 @@ oom:
     while (index)
         nsMemory::Free(array[--index]);
     nsMemory::Free(array);
     *aArray = nsnull;
     return NS_ERROR_OUT_OF_MEMORY;
 }
 
 /* nsISupports getHelperForLanguage (in PRUint32 language); */
-NS_IMETHODIMP 
-nsXPCComponents_ID::GetHelperForLanguage(PRUint32 language, 
+NS_IMETHODIMP
+nsXPCComponents_ID::GetHelperForLanguage(PRUint32 language,
                                       nsISupports **retval)
 {
     *retval = nsnull;
     return NS_OK;
 }
 
 /* readonly attribute string contractID; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_ID::GetContractID(char * *aContractID)
 {
     *aContractID = nsnull;
     return NS_ERROR_NOT_AVAILABLE;
 }
 
 /* readonly attribute string classDescription; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_ID::GetClassDescription(char * *aClassDescription)
 {
     static const char classDescription[] = "XPCComponents_Interfaces";
     *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription));
     return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
 
 /* readonly attribute nsCIDPtr classID; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_ID::GetClassID(nsCID * *aClassID)
 {
     *aClassID = nsnull;
     return NS_OK;
 }
 
 /* readonly attribute PRUint32 implementationLanguage; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_ID::GetImplementationLanguage(
     PRUint32 *aImplementationLanguage)
 {
     *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
     return NS_OK;
 }
 
 /* readonly attribute PRUint32 flags; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_ID::GetFlags(PRUint32 *aFlags)
 {
     *aFlags = nsIClassInfo::THREADSAFE;
     return NS_OK;
 }
 
 /* [notxpcom] readonly attribute nsCID classIDNoAlloc; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_ID::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
 {
     return NS_ERROR_NOT_AVAILABLE;
 }
 
 nsXPCComponents_ID::nsXPCComponents_ID()
 {
 }
@@ -1766,19 +1766,19 @@ public:
 private:
     NS_METHOD CallOrConstruct(nsIXPConnectWrappedNative *wrapper,
                               JSContext * cx, JSObject * obj,
                               PRUint32 argc, jsval * argv,
                               jsval * vp, PRBool *_retval);
 };
 
 /***************************************************************************/
-/* void getInterfaces (out PRUint32 count, [array, size_is (count), retval] 
+/* void getInterfaces (out PRUint32 count, [array, size_is (count), retval]
                        out nsIIDPtr array); */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Exception::GetInterfaces(PRUint32 *aCount, nsIID * **aArray)
 {
     PRUint32 count = 2;
     *aCount = count;
     nsIID **array;
     *aArray = array = static_cast<nsIID**>(nsMemory::Alloc(count * sizeof(nsIID*)));
     if(!array)
         return NS_ERROR_OUT_OF_MEMORY;
@@ -1801,68 +1801,68 @@ oom:
     while (index)
         nsMemory::Free(array[--index]);
     nsMemory::Free(array);
     *aArray = nsnull;
     return NS_ERROR_OUT_OF_MEMORY;
 }
 
 /* nsISupports getHelperForLanguage (in PRUint32 language); */
-NS_IMETHODIMP 
-nsXPCComponents_Exception::GetHelperForLanguage(PRUint32 language, 
+NS_IMETHODIMP
+nsXPCComponents_Exception::GetHelperForLanguage(PRUint32 language,
                                       nsISupports **retval)
 {
     *retval = nsnull;
     return NS_OK;
 }
 
 /* readonly attribute string contractID; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Exception::GetContractID(char * *aContractID)
 {
     *aContractID = nsnull;
     return NS_ERROR_NOT_AVAILABLE;
 }
 
 /* readonly attribute string classDescription; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Exception::GetClassDescription(char * *aClassDescription)
 {
     static const char classDescription[] = "XPCComponents_Interfaces";
     *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription));
     return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
 
 /* readonly attribute nsCIDPtr classID; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Exception::GetClassID(nsCID * *aClassID)
 {
     *aClassID = nsnull;
     return NS_OK;
 }
 
 /* readonly attribute PRUint32 implementationLanguage; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Exception::GetImplementationLanguage(
     PRUint32 *aImplementationLanguage)
 {
     *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
     return NS_OK;
 }
 
 /* readonly attribute PRUint32 flags; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Exception::GetFlags(PRUint32 *aFlags)
 {
     *aFlags = nsIClassInfo::THREADSAFE;
     return NS_OK;
 }
 
 /* [notxpcom] readonly attribute nsCID classIDNoAlloc; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Exception::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
 {
     return NS_ERROR_NOT_AVAILABLE;
 }
 
 nsXPCComponents_Exception::nsXPCComponents_Exception()
 {
 }
@@ -2059,19 +2059,19 @@ private:
                               jsval * vp, PRBool *_retval);
 private:
     nsIJSCID* mClassID;
     nsIJSIID* mInterfaceID;
     char*     mInitializer;
 };
 
 /***************************************************************************/
-/* void getInterfaces (out PRUint32 count, [array, size_is (count), retval] 
+/* void getInterfaces (out PRUint32 count, [array, size_is (count), retval]
                        out nsIIDPtr array); */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCConstructor::GetInterfaces(PRUint32 *aCount, nsIID * **aArray)
 {
     PRUint32 count = 2;
     *aCount = count;
     nsIID **array;
     *aArray = array = static_cast<nsIID**>(nsMemory::Alloc(count * sizeof(nsIID*)));
     if(!array)
         return NS_ERROR_OUT_OF_MEMORY;
@@ -2094,68 +2094,68 @@ oom:
     while (index)
         nsMemory::Free(array[--index]);
     nsMemory::Free(array);
     *aArray = nsnull;
     return NS_ERROR_OUT_OF_MEMORY;
 }
 
 /* nsISupports getHelperForLanguage (in PRUint32 language); */
-NS_IMETHODIMP 
-nsXPCConstructor::GetHelperForLanguage(PRUint32 language, 
+NS_IMETHODIMP
+nsXPCConstructor::GetHelperForLanguage(PRUint32 language,
                                       nsISupports **retval)
 {
     *retval = nsnull;
     return NS_OK;
 }
 
 /* readonly attribute string contractID; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCConstructor::GetContractID(char * *aContractID)
 {
     *aContractID = nsnull;
     return NS_ERROR_NOT_AVAILABLE;
 }
 
 /* readonly attribute string classDescription; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCConstructor::GetClassDescription(char * *aClassDescription)
 {
     static const char classDescription[] = "XPCComponents_Interfaces";
     *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription));
     return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
 
 /* readonly attribute nsCIDPtr classID; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCConstructor::GetClassID(nsCID * *aClassID)
 {
     *aClassID = nsnull;
     return NS_OK;
 }
 
 /* readonly attribute PRUint32 implementationLanguage; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCConstructor::GetImplementationLanguage(
     PRUint32 *aImplementationLanguage)
 {
     *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
     return NS_OK;
 }
 
 /* readonly attribute PRUint32 flags; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCConstructor::GetFlags(PRUint32 *aFlags)
 {
     *aFlags = nsIClassInfo::THREADSAFE;
     return NS_OK;
 }
 
 /* [notxpcom] readonly attribute nsCID classIDNoAlloc; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCConstructor::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
 {
     return NS_ERROR_NOT_AVAILABLE;
 }
 
 nsXPCConstructor::nsXPCConstructor(nsIJSCID* aClassID,
                                    nsIJSIID* aInterfaceID,
                                    const char* aInitializer)
@@ -2324,19 +2324,19 @@ public:
 private:
     NS_METHOD CallOrConstruct(nsIXPConnectWrappedNative *wrapper,
                               JSContext * cx, JSObject * obj,
                               PRUint32 argc, jsval * argv,
                               jsval * vp, PRBool *_retval);
 };
 
 /***************************************************************************/
-/* void getInterfaces (out PRUint32 count, [array, size_is (count), retval] 
+/* void getInterfaces (out PRUint32 count, [array, size_is (count), retval]
                        out nsIIDPtr array); */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Constructor::GetInterfaces(PRUint32 *aCount, nsIID * **aArray)
 {
     PRUint32 count = 2;
     *aCount = count;
     nsIID **array;
     *aArray = array = static_cast<nsIID**>(nsMemory::Alloc(count * sizeof(nsIID*)));
     if(!array)
         return NS_ERROR_OUT_OF_MEMORY;
@@ -2359,68 +2359,68 @@ oom:
     while (index)
         nsMemory::Free(array[--index]);
     nsMemory::Free(array);
     *aArray = nsnull;
     return NS_ERROR_OUT_OF_MEMORY;
 }
 
 /* nsISupports getHelperForLanguage (in PRUint32 language); */
-NS_IMETHODIMP 
-nsXPCComponents_Constructor::GetHelperForLanguage(PRUint32 language, 
+NS_IMETHODIMP
+nsXPCComponents_Constructor::GetHelperForLanguage(PRUint32 language,
                                       nsISupports **retval)
 {
     *retval = nsnull;
     return NS_OK;
 }
 
 /* readonly attribute string contractID; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Constructor::GetContractID(char * *aContractID)
 {
     *aContractID = nsnull;
     return NS_ERROR_NOT_AVAILABLE;
 }
 
 /* readonly attribute string classDescription; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Constructor::GetClassDescription(char * *aClassDescription)
 {
     static const char classDescription[] = "XPCComponents_Interfaces";
     *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription));
     return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
 
 /* readonly attribute nsCIDPtr classID; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Constructor::GetClassID(nsCID * *aClassID)
 {
     *aClassID = nsnull;
     return NS_OK;
 }
 
 /* readonly attribute PRUint32 implementationLanguage; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Constructor::GetImplementationLanguage(
     PRUint32 *aImplementationLanguage)
 {
     *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
     return NS_OK;
 }
 
 /* readonly attribute PRUint32 flags; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Constructor::GetFlags(PRUint32 *aFlags)
 {
     *aFlags = nsIClassInfo::THREADSAFE;
     return NS_OK;
 }
 
 /* [notxpcom] readonly attribute nsCID classIDNoAlloc; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents_Constructor::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
 {
     return NS_ERROR_NOT_AVAILABLE;
 }
 
 nsXPCComponents_Constructor::nsXPCComponents_Constructor()
 {
 }
@@ -3215,17 +3215,17 @@ xpc_CreateSandboxObject(JSContext * cx, 
         if (!principal) {
             principal = do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
             NS_ASSERTION(NS_FAILED(rv) || principal,
                          "Bad return from do_CreateInstance");
 
             if (!principal || NS_FAILED(rv)) {
                 if (NS_SUCCEEDED(rv))
                     rv = NS_ERROR_FAILURE;
-                
+
                 return rv;
             }
         }
 
         sop = new PrincipalHolder(principal);
         if (!sop)
             return NS_ERROR_OUT_OF_MEMORY;
     }
@@ -3381,17 +3381,17 @@ public:
     {
         return mJSContext;
     }
 
     NS_DECL_ISUPPORTS
 
 private:
     static JSBool ContextHolderOperationCallback(JSContext *cx);
-    
+
     XPCAutoJSContext mJSContext;
     JSContext* mOrigCx;
 };
 
 NS_IMPL_ISUPPORTS0(ContextHolder)
 
 ContextHolder::ContextHolder(JSContext *aOuterCx, JSObject *aSandbox)
     : mJSContext(JS_NewContext(JS_GetRuntime(aOuterCx), 1024), JS_FALSE),
@@ -3400,21 +3400,27 @@ ContextHolder::ContextHolder(JSContext *
     if(mJSContext)
     {
         JS_SetOptions(mJSContext,
                       JSOPTION_DONT_REPORT_UNCAUGHT |
                       JSOPTION_PRIVATE_IS_NSISUPPORTS);
         JS_SetGlobalObject(mJSContext, aSandbox);
         JS_SetContextPrivate(mJSContext, this);
 
-        if(JS_GetOperationCallback(aOuterCx))
+        PRIntervalTime watchdogLimit =
+            nsXPConnect::GetXPConnect()->GetWatchdogLimit(aOuterCx);
+
+        if(watchdogLimit)
         {
-            JS_SetOperationCallback(mJSContext, ContextHolderOperationCallback,
-                                    JS_GetOperationLimit(aOuterCx));
+            JS_SetOperationCallback(mJSContext,
+                                    ContextHolderOperationCallback);
+            nsXPConnect::GetXPConnect()->SetWatchdogLimit(mJSContext,
+                                                          watchdogLimit);
         }
+
     }
 }
 
 JSBool
 ContextHolder::ContextHolderOperationCallback(JSContext *cx)
 {
     ContextHolder* thisObject =
         static_cast<ContextHolder*>(JS_GetContextPrivate(cx));
@@ -3426,17 +3432,19 @@ ContextHolder::ContextHolderOperationCal
     if(callback)
     {
         ok = callback(origCx);
         callback = JS_GetOperationCallback(origCx);
         if(callback)
         {
             // If the callback is still set in the original context, reflect
             // a possibly updated operation limit into cx.
-            JS_SetOperationLimit(cx, JS_GetOperationLimit(origCx));
+            PRIntervalTime limit =
+                nsXPConnect::GetXPConnect()->GetWatchdogLimit(origCx);
+            ok = nsXPConnect::GetXPConnect()->SetWatchdogLimit(cx, limit);
             return ok;
         }
     }
 
     JS_ClearOperationCallback(cx);
     return ok;
 }
 
@@ -3731,19 +3739,19 @@ NS_INTERFACE_MAP_BEGIN(nsXPCComponents)
   NS_INTERFACE_MAP_ENTRY(nsISecurityCheckedComponent)
 #endif
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCComponents)
 NS_INTERFACE_MAP_END_THREADSAFE
 
 NS_IMPL_THREADSAFE_ADDREF(nsXPCComponents)
 NS_IMPL_THREADSAFE_RELEASE(nsXPCComponents)
 
-/* void getInterfaces (out PRUint32 count, [array, size_is (count), retval] 
+/* void getInterfaces (out PRUint32 count, [array, size_is (count), retval]
                        out nsIIDPtr array); */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents::GetInterfaces(PRUint32 *aCount, nsIID * **aArray)
 {
     PRUint32 count = 2;
 #ifdef XPC_USE_SECURITY_CHECKED_COMPONENT
     ++count;
 #endif
     *aCount = count;
     nsIID **array;
@@ -3772,68 +3780,68 @@ oom:
     while (index)
         nsMemory::Free(array[--index]);
     nsMemory::Free(array);
     *aArray = nsnull;
     return NS_ERROR_OUT_OF_MEMORY;
 }
 
 /* nsISupports getHelperForLanguage (in PRUint32 language); */
-NS_IMETHODIMP 
-nsXPCComponents::GetHelperForLanguage(PRUint32 language, 
+NS_IMETHODIMP
+nsXPCComponents::GetHelperForLanguage(PRUint32 language,
                                       nsISupports **retval)
 {
     *retval = nsnull;
     return NS_OK;
 }
 
 /* readonly attribute string contractID; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents::GetContractID(char * *aContractID)
 {
     *aContractID = nsnull;
     return NS_ERROR_NOT_AVAILABLE;
 }
 
 /* readonly attribute string classDescription; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents::GetClassDescription(char * *aClassDescription)
 {
     static const char classDescription[] = "XPCComponents";
     *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription));
     return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
 
 /* readonly attribute nsCIDPtr classID; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents::GetClassID(nsCID * *aClassID)
 {
     *aClassID = nsnull;
     return NS_OK;
 }
 
 /* readonly attribute PRUint32 implementationLanguage; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents::GetImplementationLanguage(
     PRUint32 *aImplementationLanguage)
 {
     *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
     return NS_OK;
 }
 
 /* readonly attribute PRUint32 flags; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents::GetFlags(PRUint32 *aFlags)
 {
     *aFlags = nsIClassInfo::THREADSAFE;
     return NS_OK;
 }
 
 /* [notxpcom] readonly attribute nsCID classIDNoAlloc; */
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXPCComponents::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
 {
     return NS_ERROR_NOT_AVAILABLE;
 }
 
 nsXPCComponents::nsXPCComponents()
     :   mInterfaces(nsnull),
         mInterfacesByID(nsnull),
--- a/js/src/xpconnect/src/xpccontext.cpp
+++ b/js/src/xpconnect/src/xpccontext.cpp
@@ -47,16 +47,17 @@
 XPCContext::XPCContext(XPCJSRuntime* aRuntime,
                        JSContext* aJSContext)
     :   mRuntime(aRuntime),
         mJSContext(aJSContext),
         mLastResult(NS_OK),
         mPendingResult(NS_OK),
         mSecurityManager(nsnull),
         mException(nsnull),
+        mWatchdogLimit(0),
         mCallingLangType(LANG_UNKNOWN),
         mSecurityManagerFlags(0)
 {
     MOZ_COUNT_CTOR(XPCContext);
 
     PR_INIT_CLIST(&mScopes);
     for(const char** p =  XPC_ARG_FORMATTER_FORMAT_STRINGS; *p; p++)
         JS_AddArgumentFormatter(mJSContext, *p, XPC_JSArgumentFormatter);
--- a/js/src/xpconnect/src/xpcjsruntime.cpp
+++ b/js/src/xpconnect/src/xpcjsruntime.cpp
@@ -212,17 +212,17 @@ DyingProtoKiller(JSDHashTable *table, JS
     delete proto;
     return JS_DHASH_REMOVE;
 }
 
 static JSDHashOperator
 DetachedWrappedNativeProtoMarker(JSDHashTable *table, JSDHashEntryHdr *hdr,
                                  uint32 number, void *arg)
 {
-    XPCWrappedNativeProto* proto = 
+    XPCWrappedNativeProto* proto =
         (XPCWrappedNativeProto*)((JSDHashEntryStub*)hdr)->key;
 
     proto->Mark();
     return JS_DHASH_NEXT;
 }
 
 // GCCallback calls are chained
 static JSBool
@@ -235,16 +235,24 @@ ContextCallback(JSContext *cx, uintN ope
         {
             if(!self->OnJSContextNew(cx))
                 return JS_FALSE;
         }
         else if(operation == JSCONTEXT_DESTROY)
         {
             delete XPCContext::GetXPCContext(cx);
         }
+        else if(operation == JSCONTEXT_REQUEST_START)
+        {
+            // If we're called during context creation, we will assert if we
+            // try to call XPCContext::GetXPCContext.
+            if(!cx->data2)
+                return JS_TRUE;
+            self->WakeupWatchdog(cx);
+        }
     }
     return JS_TRUE;
 }
 
 struct ObjectHolder : public JSDHashEntryHdr
 {
     void *holder;
     nsScriptObjectTracer* tracer;
@@ -305,17 +313,17 @@ void XPCJSRuntime::TraceJS(JSTracer* trc
             }
         }
     }
 
     // XPCJSObjectHolders don't participate in cycle collection, so always trace
     // them here.
     for(XPCRootSetElem *e = self->mObjectHolderRoots; e ; e = e->GetNextRoot())
         static_cast<XPCJSObjectHolder*>(e)->TraceJS(trc);
-        
+
     if(self->GetXPConnect()->ShouldTraceRoots())
     {
         // Only trace these if we're not cycle-collecting, the cycle collector
         // will do that if we are.
         self->TraceXPConnectRoots(trc);
     }
 }
 
@@ -477,17 +485,17 @@ JSBool XPCJSRuntime::GCCallback(JSContex
                 {
                     return JS_FALSE;
                 }
                 break;
             }
             case JSGC_MARK_END:
             {
                 NS_ASSERTION(!self->mDoingFinalization, "bad state");
-    
+
                 // mThreadRunningGC indicates that GC is running
                 { // scoped lock
                     XPCAutoLock lock(self->GetMapLock());
                     NS_ASSERTION(!self->mThreadRunningGC, "bad state");
                     self->mThreadRunningGC = PR_GetCurrentThread();
                 }
 
                 dyingWrappedJSArray = &self->mWrappedJSToReleaseArray;
@@ -500,18 +508,18 @@ JSBool XPCJSRuntime::GCCallback(JSContex
                     // we do not want to be changing the refcount of these wrappers.
                     // We add them to the array now and Release the array members
                     // later to avoid the posibility of doing any JS GCThing
                     // allocations during the gc cycle.
                     self->mWrappedJSMap->
                         Enumerate(WrappedJSDyingJSObjectFinder, &data);
                 }
 
-                // Do cleanup in NativeInterfaces. This part just finds 
-                // member cloned function objects that are about to be 
+                // Do cleanup in NativeInterfaces. This part just finds
+                // member cloned function objects that are about to be
                 // collected. It does not deal with collection of interfaces or
                 // sets at this point.
                 CX_AND_XPCRT_Data data = {cx, self};
 
                 self->mIID2NativeInterfaceMap->
                     Enumerate(NativeInterfaceGC, &data);
 
                 // Find dying scopes...
@@ -668,17 +676,17 @@ JSBool XPCJSRuntime::GCCallback(JSContex
                 // Skip this part if XPConnect is shutting down. We get into
                 // bad locking problems with the thread iteration otherwise.
                 if(!self->GetXPConnect()->IsShuttingDown())
                 {
                     PRLock* threadLock = XPCPerThreadData::GetLock();
                     if(threadLock)
                     {
                         // Do the marking...
-                        
+
                         { // scoped lock
                             nsAutoLock lock(threadLock);
 
                             XPCPerThreadData* iterp = nsnull;
                             XPCPerThreadData* thread;
 
                             while(nsnull != (thread =
                                      XPCPerThreadData::IterateThreads(&iterp)))
@@ -687,26 +695,26 @@ JSBool XPCJSRuntime::GCCallback(JSContex
                                 while(ccxp)
                                 {
                                     // Deal with the strictness of callcontext that
                                     // complains if you ask for a tearoff when
                                     // it is in a state where the tearoff could not
                                     // possibly be valid.
                                     if(ccxp->CanGetTearOff())
                                     {
-                                        XPCWrappedNativeTearOff* to = 
+                                        XPCWrappedNativeTearOff* to =
                                             ccxp->GetTearOff();
                                         if(to)
                                             to->Mark();
                                     }
                                     ccxp = ccxp->GetPrevCallContext();
                                 }
                             }
                         }
-    
+
                         // Do the sweeping...
                         XPCWrappedNativeScope::SweepAllWrappedNativeTearOffs();
                     }
                 }
 
                 // Now we need to kill the 'Dying' XPCWrappedNativeProtos.
                 // We transfered these native objects to this table when their
                 // JSObject's were finalized. We did not destroy them immediately
@@ -772,16 +780,136 @@ JSBool XPCJSRuntime::GCCallback(JSContex
             default:
                 break;
         }
     }
 
     return JS_TRUE;
 }
 
+/* static */
+void
+XPCJSRuntime::WatchdogMain(void *arg)
+{
+    XPCJSRuntime *xpcrt = (XPCJSRuntime *) arg;
+    JSRuntime *rt = xpcrt->GetJSRuntime();
+    PRStatus status;
+    PRBool isRunning;
+
+    do
+    {
+        JSContext *iter = NULL;
+        JSContext *acx;
+        PRIntervalTime newInterval = (PRIntervalTime) 0;
+        XPCContext *ccx;
+
+        PRIntervalTime ct = PR_IntervalNow();
+        PR_Lock(xpcrt->mWatchdogLock);
+        JS_LOCK_GC(rt);
+
+        while((acx = js_ContextIterator(rt, JS_FALSE, &iter)))
+        {
+            if(acx->requestDepth)
+            {
+                ccx = XPCContext::GetXPCContext(acx);
+                if(ccx->mWatchdogLimit &&
+                   ct - acx->startTime > ccx->mWatchdogLimit)
+                {
+                    JS_TriggerOperationCallback(acx);
+                }
+                if(newInterval > ccx->mWatchdogLimit || !newInterval)
+                    newInterval = ccx->mWatchdogLimit;
+            }
+        }
+        JS_UNLOCK_GC(rt);
+
+        xpcrt->mCurrentInterval = newInterval ? newInterval
+                                              : PR_INTERVAL_NO_TIMEOUT;
+        if (xpcrt->mWatchdogRunning)
+            status = PR_WaitCondVar(xpcrt->mWatchdogWakeup,
+                                    xpcrt->mCurrentInterval);
+        isRunning = xpcrt->mWatchdogRunning;
+        PR_Unlock(xpcrt->mWatchdogLock);
+    } while (isRunning && status == PR_SUCCESS);
+}
+
+PRBool
+XPCJSRuntime::SetWatchdogLimit(JSContext *cx, PRIntervalTime newWatchdogLimit)
+{
+    PRBool isRunning;
+    PRIntervalTime oldWatchdogLimit;
+    XPCContext *ccx = XPCContext::GetXPCContext(cx);
+
+    if(newWatchdogLimit == ccx->mWatchdogLimit)
+        return PR_TRUE;
+
+    oldWatchdogLimit = ccx->mWatchdogLimit;
+    ccx->mWatchdogLimit = newWatchdogLimit;
+
+    /*
+     * Start a new watchdog thread if it has not been started. If it has been
+     * started wake up the thread and cause the watchdog rescheduling.
+     */
+    PR_Lock(mWatchdogLock);
+    isRunning = !!mWatchdogThread;
+
+    if(!isRunning)
+    {
+        mWatchdogRunning = PR_TRUE;
+        mWatchdogThread =
+            PR_CreateThread(PRThreadType(PR_USER_THREAD),
+                            WatchdogMain,
+                            this,
+                            PRThreadPriority(PR_PRIORITY_NORMAL),
+                            PRThreadScope(PR_LOCAL_THREAD),
+                            PRThreadState(PR_JOINABLE_THREAD),
+                            0);
+    }
+    PR_Unlock(mWatchdogLock);
+    if(!mWatchdogThread)
+        return PR_FALSE;
+    if(isRunning &&
+       (oldWatchdogLimit > ccx->mWatchdogLimit ||
+        mCurrentInterval == PR_INTERVAL_NO_TIMEOUT))
+        WakeupWatchdog(cx);
+    return PR_TRUE;
+
+}
+
+void
+XPCJSRuntime::WakeupWatchdog(JSContext *cx)
+{
+    XPCContext *ccx = XPCContext::GetXPCContext(cx);
+    PR_Lock(mWatchdogLock);
+    if(mCurrentInterval == PR_INTERVAL_NO_TIMEOUT ||
+       (ccx && mCurrentInterval > ccx->mWatchdogLimit))
+        PR_NotifyCondVar(mWatchdogWakeup);
+    PR_Unlock(mWatchdogLock);
+}
+
+PRBool
+XPCJSRuntime::ShutdownWatchdog()
+{
+    PR_Lock(mWatchdogLock);
+    mWatchdogRunning = PR_FALSE;
+    PRThread *t = mWatchdogThread;
+    mWatchdogThread = NULL;
+    PR_NotifyCondVar(mWatchdogWakeup);
+    PR_Unlock(mWatchdogLock);
+    if(t)
+        PR_JoinThread(t);
+    return PR_TRUE;
+}
+
+PRIntervalTime
+XPCJSRuntime::GetWatchdogLimit(JSContext *cx)
+{
+    return XPCContext::GetXPCContext(cx)->mWatchdogLimit;
+}
+
 /***************************************************************************/
 
 #ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN
 static JSDHashOperator
 DEBUG_WrapperChecker(JSDHashTable *table, JSDHashEntryHdr *hdr,
                      uint32 number, void *arg)
 {
     XPCWrappedNative* wrapper = (XPCWrappedNative*)((JSDHashEntryStub*)hdr)->key;
@@ -802,17 +930,17 @@ WrappedJSShutdownMarker(JSDHashTable *ta
     wrapper->SystemIsBeingShutDown(rt);
     return JS_DHASH_NEXT;
 }
 
 static JSDHashOperator
 DetachedWrappedNativeProtoShutdownMarker(JSDHashTable *table, JSDHashEntryHdr *hdr,
                                          uint32 number, void *arg)
 {
-    XPCWrappedNativeProto* proto = 
+    XPCWrappedNativeProto* proto =
         (XPCWrappedNativeProto*)((JSDHashEntryStub*)hdr)->key;
 
     proto->SystemIsBeingShutDown((JSContext*)arg);
     return JS_DHASH_NEXT;
 }
 
 void XPCJSRuntime::SystemIsBeingShutDown(JSContext* cx)
 {
@@ -960,16 +1088,22 @@ XPCJSRuntime::~XPCJSRuntime()
     XPCConvert::RemoveXPCOMUCStringFinalizer();
 
     if(mJSHolders.ops)
     {
         JS_DHashTableFinish(&mJSHolders);
         mJSHolders.ops = nsnull;
     }
 
+    ShutdownWatchdog();
+    if(mWatchdogWakeup)
+        JS_DESTROY_CONDVAR(mWatchdogWakeup);
+    if(mWatchdogLock)
+        JS_DESTROY_LOCK(mWatchdogLock);
+
     if(mJSRuntime)
     {
         JS_DestroyRuntime(mJSRuntime);
         JS_ShutDown();
 #ifdef DEBUG_shaver_off
         fprintf(stderr, "nJRSI: destroyed runtime %p\n", (void *)mJSRuntime);
 #endif
     }
@@ -993,16 +1127,20 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* 
    mMapLock(XPCAutoLock::NewLock("XPCJSRuntime::mMapLock")),
    mThreadRunningGC(nsnull),
    mWrappedJSToReleaseArray(),
    mNativesToReleaseArray(),
    mDoingFinalization(JS_FALSE),
    mVariantRoots(nsnull),
    mWrappedJSRoots(nsnull),
    mObjectHolderRoots(nsnull),
+   mWatchdogLock(nsnull),
+   mWatchdogWakeup(nsnull),
+   mWatchdogThread(nsnull),
+   mCurrentInterval(PR_INTERVAL_NO_TIMEOUT),
    mUnrootedGlobalCount(0)
 {
 #ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN
     DEBUG_WrappedNativeHashtable =
         JS_NewDHashTable(JS_DHashGetStubOps(), nsnull,
                          sizeof(JSDHashEntryStub), 128);
 #endif
 
@@ -1047,16 +1185,20 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* 
                           sizeof(ObjectHolder), 512))
         mJSHolders.ops = nsnull;
 
     // Install a JavaScript 'debugger' keyword handler in debug builds only
 #ifdef DEBUG
     if(mJSRuntime && !JS_GetGlobalDebugHooks(mJSRuntime)->debuggerHandler)
         xpc_InstallJSDebuggerKeywordHandler(mJSRuntime);
 #endif
+
+    mWatchdogLock = JS_NEW_LOCK();
+    if (mWatchdogLock)
+        mWatchdogWakeup = JS_NEW_CONDVAR(mWatchdogLock);
 }
 
 // static
 XPCJSRuntime*
 XPCJSRuntime::newXPCJSRuntime(nsXPConnect* aXPConnect)
 {
     NS_PRECONDITION(aXPConnect,"bad param");
 
@@ -1068,17 +1210,18 @@ XPCJSRuntime::newXPCJSRuntime(nsXPConnec
        self->GetWrappedJSClassMap()          &&
        self->GetIID2NativeInterfaceMap()     &&
        self->GetClassInfo2NativeSetMap()     &&
        self->GetNativeSetMap()               &&
        self->GetThisTranslatorMap()          &&
        self->GetNativeScriptableSharedMap()  &&
        self->GetDyingWrappedNativeProtoMap() &&
        self->GetExplicitNativeWrapperMap()   &&
-       self->GetMapLock())
+       self->GetMapLock()                    &&
+       self->mWatchdogWakeup)
     {
         return self;
     }
     delete self;
     return nsnull;
 }
 
 JSBool
@@ -1096,25 +1239,25 @@ XPCJSRuntime::OnJSContextNew(JSContext *
             {
                 mStrIDs[0] = 0;
                 ok = JS_FALSE;
                 break;
             }
             mStrJSVals[i] = STRING_TO_JSVAL(str);
         }
     }
-    if (!ok)
+    if(!ok)
         return JS_FALSE;
 
     XPCPerThreadData* tls = XPCPerThreadData::GetData(cx);
     if(!tls)
         return JS_FALSE;
 
     XPCContext* xpc = new XPCContext(this, cx);
-    if (!xpc)
+    if(!xpc)
         return JS_FALSE;
 
     JS_SetThreadStackLimit(cx, tls->GetStackLimit());
     JS_SetScriptStackQuota(cx, 100*1024*1024);
     return JS_TRUE;
 }
 
 JSBool
--- a/js/src/xpconnect/src/xpcprivate.h
+++ b/js/src/xpconnect/src/xpcprivate.h
@@ -270,32 +270,32 @@ extern const char XPC_XPCONNECT_CONTRACT
 
 // We PROMISE to never screw this up.
 #ifdef _MSC_VER
 #pragma warning(disable : 4355) // OK to pass "this" in member initializer
 #endif
 
 typedef PRMonitor XPCLock;
 
-static inline void xpc_Wait(XPCLock* lock) 
+static inline void xpc_Wait(XPCLock* lock)
     {
         NS_ASSERTION(lock, "xpc_Wait called with null lock!");
 #ifdef DEBUG
-        PRStatus result = 
+        PRStatus result =
 #endif
         PR_Wait(lock, PR_INTERVAL_NO_TIMEOUT);
         NS_ASSERTION(PR_SUCCESS == result, "bad result from PR_Wait!");
     }
 
-static inline void xpc_NotifyAll(XPCLock* lock) 
+static inline void xpc_NotifyAll(XPCLock* lock)
     {
         NS_ASSERTION(lock, "xpc_NotifyAll called with null lock!");
 #ifdef DEBUG
-        PRStatus result = 
-#endif    
+        PRStatus result =
+#endif
         PR_NotifyAll(lock);
         NS_ASSERTION(PR_SUCCESS == result, "bad result from PR_NotifyAll!");
     }
 
 // This is a cloned subset of nsAutoMonitor. We want the use of a monitor -
 // mostly because we need reenterability - but we also want to support passing
 // a null monitor in without things blowing up. This is used for wrappers that
 // are guaranteed to be used only on one thread. We avoid lock overhead by
@@ -505,17 +505,17 @@ public:
     nsresult GetInfoForName(const char * name, nsIInterfaceInfo** info);
 
     // nsCycleCollectionParticipant
     NS_IMETHOD RootAndUnlinkJSObjects(void *p);
     NS_IMETHOD Unlink(void *p);
     NS_IMETHOD Unroot(void *p);
     NS_IMETHOD Traverse(void *p,
                         nsCycleCollectionTraversalCallback &cb);
-    
+
     // nsCycleCollectionLanguageRuntime
     virtual nsresult BeginCycleCollection(nsCycleCollectionTraversalCallback &cb);
     virtual nsresult FinishCycleCollection();
     virtual nsCycleCollectionParticipant *ToParticipant(void *p);
     virtual PRBool Collect();
 #ifdef DEBUG_CC
     virtual void PrintAllReferencesTo(void *p);
 #endif
@@ -731,16 +731,20 @@ public:
     void DebugDump(PRInt16 depth);
 
     void SystemIsBeingShutDown(JSContext* cx);
 
     PRThread* GetThreadRunningGC() const {return mThreadRunningGC;}
 
     ~XPCJSRuntime();
 
+    PRIntervalTime GetWatchdogLimit(JSContext *cx);
+    PRBool SetWatchdogLimit(JSContext *cx, PRIntervalTime limit);
+    void WakeupWatchdog(JSContext *cx);
+
 #ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN
    void DEBUG_AddWrappedNative(nsIXPConnectWrappedNative* wrapper)
         {XPCAutoLock lock(GetMapLock());
          JSDHashEntryHdr *entry =
             JS_DHashTableOperate(DEBUG_WrappedNativeHashtable,
                                  wrapper, JS_DHASH_ADD);
          if(entry) ((JSDHashEntryStub *)entry)->key = wrapper;}
 
@@ -752,16 +756,19 @@ private:
    JSDHashTable* DEBUG_WrappedNativeHashtable;
 public:
 #endif
 
 private:
     XPCJSRuntime(); // no implementation
     XPCJSRuntime(nsXPConnect* aXPConnect);
 
+    PRBool ShutdownWatchdog();
+    static void WatchdogMain(void *args);
+
 private:
     static const char* mStrings[IDX_TOTAL_COUNT];
     jsid mStrIDs[IDX_TOTAL_COUNT];
     jsval mStrJSVals[IDX_TOTAL_COUNT];
 
     nsXPConnect* mXPConnect;
     JSRuntime*  mJSRuntime;
     JSObject2WrappedJSMap*   mWrappedJSMap;
@@ -778,16 +785,25 @@ private:
     PRThread* mThreadRunningGC;
     nsVoidArray mWrappedJSToReleaseArray;
     nsVoidArray mNativesToReleaseArray;
     JSBool mDoingFinalization;
     XPCRootSetElem *mVariantRoots;
     XPCRootSetElem *mWrappedJSRoots;
     XPCRootSetElem *mObjectHolderRoots;
     JSDHashTable mJSHolders;
+
+    /*
+     * Variables to support watchdog thread.
+     */
+    PRLock *mWatchdogLock;
+    PRCondVar *mWatchdogWakeup;
+    PRBool mWatchdogRunning;
+    PRThread *mWatchdogThread;
+    PRIntervalTime mCurrentInterval;
     uintN mUnrootedGlobalCount;
 };
 
 /***************************************************************************/
 /***************************************************************************/
 // XPCContext is mostly a dumb class to hold JSContext specific data and
 // maps that let us find wrappers created for the given JSContext.
 
@@ -801,36 +817,36 @@ public:
             NS_ASSERTION(aJSContext->data2, "should already have XPCContext");
             return static_cast<XPCContext *>(aJSContext->data2);
         }
 
     XPCJSRuntime* GetRuntime() const {return mRuntime;}
     JSContext* GetJSContext() const {return mJSContext;}
 
     enum LangType {LANG_UNKNOWN, LANG_JS, LANG_NATIVE};
-    
+
     LangType GetCallingLangType() const
         {
             return mCallingLangType;
         }
     LangType SetCallingLangType(LangType lt)
         {
-            LangType tmp = mCallingLangType; 
-            mCallingLangType = lt; 
+            LangType tmp = mCallingLangType;
+            mCallingLangType = lt;
             return tmp;
         }
-    JSBool CallerTypeIsJavaScript() const 
+    JSBool CallerTypeIsJavaScript() const
         {
             return LANG_JS == mCallingLangType;
         }
-    JSBool CallerTypeIsNative() const 
+    JSBool CallerTypeIsNative() const
         {
             return LANG_NATIVE == mCallingLangType;
         }
-    JSBool CallerTypeIsKnown() const 
+    JSBool CallerTypeIsKnown() const
         {
             return LANG_UNKNOWN != mCallingLangType;
         }
 
     nsresult GetException(nsIException** e)
         {
             NS_IF_ADDREF(mException);
             *e = mException;
@@ -894,16 +910,17 @@ private:
                                      JSContext* aJSContext);
 private:
     XPCJSRuntime* mRuntime;
     JSContext*  mJSContext;
     nsresult mLastResult;
     nsresult mPendingResult;
     nsIXPCSecurityManager* mSecurityManager;
     nsIException* mException;
+    PRIntervalTime mWatchdogLimit;
     LangType mCallingLangType;
     PRUint16 mSecurityManagerFlags;
 
     // A linked list of scopes to notify when we are destroyed.
     PRCList mScopes;
 };
 
 /***************************************************************************/
@@ -1237,17 +1254,17 @@ public:
     GetPrototypeNoHelper(XPCCallContext& ccx);
 
 #ifndef XPCONNECT_STANDALONE
     nsIPrincipal*
     GetPrincipal() const
     {return mScriptObjectPrincipal ?
          mScriptObjectPrincipal->GetPrincipal() : nsnull;}
 #endif
-    
+
     JSObject*
     GetPrototypeJSFunction() const {return mPrototypeJSFunction;}
 
     void RemoveWrappedNativeProtos();
 
     static XPCWrappedNativeScope*
     FindInJSObjectScope(XPCCallContext& ccx, JSObject* obj,
                         JSBool OKIfNotInitialized = JS_FALSE);
@@ -1970,17 +1987,17 @@ public:
             mScriptableInfo->Mark();
     }
 
     // NOP. This is just here to make the AutoMarkingPtr code compile.
     inline void AutoTrace(JSTracer* trc) {}
 
     // Yes, we *do* need to mark the mScriptableInfo in both cases.
     void Mark() const
-        {mSet->Mark(); 
+        {mSet->Mark();
          if(mScriptableInfo) mScriptableInfo->Mark();}
 
 #ifdef DEBUG
     void ASSERT_SetNotMarked() const {mSet->ASSERT_NotMarked();}
 #endif
 
     ~XPCWrappedNativeProto();
 
@@ -2492,19 +2509,19 @@ public:
 
     JSObject*  CallQueryInterfaceOnJSObject(XPCCallContext& ccx,
                                             JSObject* jsobj, REFNSIID aIID);
 
     static nsresult BuildPropertyEnumerator(XPCCallContext& ccx,
                                             JSObject* aJSObj,
                                             nsISimpleEnumerator** aEnumerate);
 
-    static nsresult GetNamedPropertyAsVariant(XPCCallContext& ccx, 
+    static nsresult GetNamedPropertyAsVariant(XPCCallContext& ccx,
                                               JSObject* aJSObj,
-                                              jsval aName, 
+                                              jsval aName,
                                               nsIVariant** aResult);
 
     virtual ~nsXPCWrappedJSClass();
 
     static nsresult CheckForException(XPCCallContext & ccx,
                                       const char * aPropertyName,
                                       const char * anInterfaceName,
                                       PRBool aForceReport);
@@ -2730,17 +2747,17 @@ public:
      * @param ccx the context for the whole procedure
      * @param d [out] the resulting jsval
      * @param s the native object we're working with
      * @param type the type of object that s is
      * @param iid the interface of s that we want
      * @param scope the default scope to put on the new JSObject's __parent__
      *        chain
      * @param pErr [out] relevant error code, if any.
-     */    
+     */
     static JSBool NativeData2JS(XPCCallContext& ccx, jsval* d, const void* s,
                                 const nsXPTType& type, const nsID* iid,
                                 JSObject* scope, nsresult* pErr);
 
     static JSBool JSData2Native(XPCCallContext& ccx, void* d, jsval s,
                                 const nsXPTType& type,
                                 JSBool useAllocator, const nsID* iid,
                                 nsresult* pErr);
@@ -2766,17 +2783,17 @@ public:
                                            XPCNativeInterface* Interface,
                                            JSObject* scope,
                                            PRBool allowNativeWrapper,
                                            PRBool isGlobal,
                                            nsresult* pErr);
 
     static JSBool GetNativeInterfaceFromJSObject(XPCCallContext& ccx,
                                                  void** dest, JSObject* src,
-                                                 const nsID* iid, 
+                                                 const nsID* iid,
                                                  nsresult* pErr);
     static JSBool JSObject2NativeInterface(XPCCallContext& ccx,
                                            void** dest, JSObject* src,
                                            const nsID* iid,
                                            nsISupports* aOuter,
                                            nsresult* pErr);
     static JSBool GetISupportsFromJSObject(JSObject* obj, nsISupports** iface);
 
@@ -2787,17 +2804,17 @@ public:
      * @param d [out] the resulting jsval
      * @param s the native array we're working with
      * @param type the type of objects in the array
      * @param iid the interface of each object in the array that we want
      * @param count the number of items in the array
      * @param scope the default scope to put on the new JSObjects' __parent__
      *        chain
      * @param pErr [out] relevant error code, if any.
-     */    
+     */
     static JSBool NativeArray2JS(XPCCallContext& ccx,
                                  jsval* d, const void** s,
                                  const nsXPTType& type, const nsID* iid,
                                  JSUint32 count, JSObject* scope,
                                  nsresult* pErr);
 
     static JSBool JSArray2Native(XPCCallContext& ccx, void** d, jsval s,
                                  JSUint32 count, JSUint32 capacity,
@@ -2837,17 +2854,16 @@ public:
                                        nsIException** exception,
                                        JSContext* cx,
                                        jsval *jsExceptionPtr);
 
     static void RemoveXPCOMUCStringFinalizer();
 
 private:
     XPCConvert(); // not implemented
-
 };
 
 /***************************************************************************/
 
 // readable string conversions, static methods only
 class XPCStringConvert
 {
 public:
@@ -2875,17 +2891,17 @@ XPC_JSArgumentFormatter(JSContext *cx, c
 class XPCThrower
 {
 public:
     static void Throw(nsresult rv, JSContext* cx);
     static void Throw(nsresult rv, XPCCallContext& ccx);
     static void ThrowBadResult(nsresult rv, nsresult result, XPCCallContext& ccx);
     static void ThrowBadParam(nsresult rv, uintN paramNum, XPCCallContext& ccx);
 #ifdef XPC_IDISPATCH_SUPPORT
-    static void ThrowCOMError(JSContext* cx, unsigned long COMErrorCode, 
+    static void ThrowCOMError(JSContext* cx, unsigned long COMErrorCode,
                               nsresult rv = NS_ERROR_XPC_COM_ERROR,
                               const EXCEPINFO * exception = nsnull);
 #endif
     static JSBool SetVerbosity(JSBool state)
         {JSBool old = sVerbose; sVerbose = state; return old;}
 
     static void BuildAndThrowException(JSContext* cx, nsresult rv, const char* sz);
     static JSBool CheckForPendingException(nsresult result, JSContext *cx);
@@ -3282,17 +3298,17 @@ private:
     JSUint32             mWrappedNativeThreadsafetyReportDepth;
 #endif
     PRThread*            mThread;
 
     static PRLock*           gLock;
     static XPCPerThreadData* gThreads;
     static PRUintn           gTLSIndex;
 
-    // Cached value of cx->thread on the main thread. 
+    // Cached value of cx->thread on the main thread.
     static void *sMainJSThread;
 
     // Cached per thread data for the main thread. Only safe to access
     // if cx->thread == sMainJSThread.
     static XPCPerThreadData *sMainThreadData;
 };
 
 /***************************************************************************/
@@ -3590,17 +3606,17 @@ private:
             mDepth = JS_SuspendRequest(mCX);
         else
             mCX = nsnull;
     }
 
     JSContext *mCX;
     jsrefcount mDepth;
 };
-        
+
 
 /*****************************************/
 
 class AutoJSRequestWithNoCallContext
 {
 public:
     AutoJSRequestWithNoCallContext(JSContext* aCX) : mCX(aCX) {BeginRequest();}
     ~AutoJSRequestWithNoCallContext() {EndRequest();}
@@ -3686,17 +3702,17 @@ class AutoResolveName
 public:
     AutoResolveName(XPCCallContext& ccx, jsval name)
         : mTLS(ccx.GetThreadData()),
           mOld(mTLS->SetResolveName(name)),
           mCheck(name) {}
     ~AutoResolveName()
         {
 #ifdef DEBUG
-            jsval old = 
+            jsval old =
 #endif
             mTLS->SetResolveName(mOld);
             NS_ASSERTION(old == mCheck, "Bad Nesting!");
         }
 
 private:
     XPCPerThreadData* mTLS;
     jsval mOld;
@@ -3712,54 +3728,54 @@ public:
     ~XPCMarkableJSVal() {}
     void Mark() {}
     void TraceJS(JSTracer* trc)
     {
         JS_CALL_VALUE_TRACER(trc, *mValPtr, "XPCMarkableJSVal");
     }
     void AutoTrace(JSTracer* trc) {}
 private:
-    XPCMarkableJSVal(); // not implemented    
+    XPCMarkableJSVal(); // not implemented
     jsval  mVal;
     jsval* mValPtr;
-}; 
+};
 
 /***************************************************************************/
-// AutoMarkingPtr is the base class for the various AutoMarking pointer types 
-// below. This system allows us to temporarily protect instances of our garbage 
-// collected types after they are constructed but before they are safely 
+// AutoMarkingPtr is the base class for the various AutoMarking pointer types
+// below. This system allows us to temporarily protect instances of our garbage
+// collected types after they are constructed but before they are safely
 // attached to other rooted objects.
-// This base class has pure virtual support for marking. 
+// This base class has pure virtual support for marking.
 
 class AutoMarkingPtr
 {
 public:
     AutoMarkingPtr(XPCCallContext& ccx)
         : mNext(nsnull), mTLS(ccx.GetThreadData()) {Link();}
 
     virtual ~AutoMarkingPtr() {Unlink();}
-    
-    void Link() 
+
+    void Link()
         {if(!mTLS) return;
-         AutoMarkingPtr** list = mTLS->GetAutoRootsAdr(); 
+         AutoMarkingPtr** list = mTLS->GetAutoRootsAdr();
          mNext = *list; *list = this;}
 
-    void Unlink() 
+    void Unlink()
         {if(!mTLS) return;
-         AutoMarkingPtr** cur = mTLS->GetAutoRootsAdr(); 
+         AutoMarkingPtr** cur = mTLS->GetAutoRootsAdr();
          while(*cur != this) {
             NS_ASSERTION(*cur, "This object not in list!");
             cur = &(*cur)->mNext;
          }
          *cur = mNext;
          mTLS = nsnull;
         }
 
     AutoMarkingPtr* GetNext() {return mNext;}
-    
+
     virtual void TraceJS(JSTracer* trc) = 0;
     virtual void MarkAfterJSFinalize() = 0;
 
 protected:
     AutoMarkingPtr* mNext;
     XPCPerThreadData* mTLS;
 };
 
@@ -3798,17 +3814,17 @@ protected:                              
 // Use the macro above to define our AutoMarking types...
 
 DEFINE_AUTO_MARKING_PTR_TYPE(AutoMarkingNativeInterfacePtr, XPCNativeInterface)
 DEFINE_AUTO_MARKING_PTR_TYPE(AutoMarkingNativeSetPtr, XPCNativeSet)
 DEFINE_AUTO_MARKING_PTR_TYPE(AutoMarkingWrappedNativePtr, XPCWrappedNative)
 DEFINE_AUTO_MARKING_PTR_TYPE(AutoMarkingWrappedNativeTearOffPtr, XPCWrappedNativeTearOff)
 DEFINE_AUTO_MARKING_PTR_TYPE(AutoMarkingWrappedNativeProtoPtr, XPCWrappedNativeProto)
 DEFINE_AUTO_MARKING_PTR_TYPE(AutoMarkingJSVal, XPCMarkableJSVal)
-                                    
+
 #define DEFINE_AUTO_MARKING_ARRAY_PTR_TYPE(class_, type_)                    \
 class class_ : public AutoMarkingPtr                                         \
 {                                                                            \
 public:                                                                      \
     class_ (XPCCallContext& ccx)                                             \
         : AutoMarkingPtr(ccx), mPtr(nsnull), mCount(0) {}                    \
     class_ (XPCCallContext& ccx, type_** aPtr, PRUint32 aCount,              \
             PRBool aClear = PR_FALSE)                                        \
@@ -3853,19 +3869,19 @@ public:                                 
                                                                              \
 protected:                                                                   \
     type_ ** mPtr;                                                           \
     PRUint32 mCount;                                                         \
 };
 
 DEFINE_AUTO_MARKING_ARRAY_PTR_TYPE(AutoMarkingNativeInterfacePtrArrayPtr,
                                    XPCNativeInterface)
-    
+
 // Note: It looked like I would need one of these AutoMarkingPtr types for
-// XPCNativeScriptableInfo in order to manage marking its 
+// XPCNativeScriptableInfo in order to manage marking its
 // XPCNativeScriptableShared member during construction. But AFAICT we build
 // these and bind them to rooted things so immediately that this just is not
 // needed.
 
 #define AUTO_MARK_JSVAL_HELPER2(tok, line) tok##line
 #define AUTO_MARK_JSVAL_HELPER(tok, line) AUTO_MARK_JSVAL_HELPER2(tok, line)
 
 #define AUTO_MARK_JSVAL(ccx, val)                                            \
@@ -3898,18 +3914,18 @@ public:
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_NSIVARIANT
     NS_DECL_CYCLE_COLLECTION_CLASS(XPCVariant)
 
     // If this class ever implements nsIWritableVariant, take special care with
     // the case when mJSVal is JSVAL_STRING, since we don't own the data in
     // that case.
 
-    // We #define and iid so that out module local code can use QI to detect 
-    // if a given nsIVariant is in fact an XPCVariant. 
+    // We #define and iid so that out module local code can use QI to detect
+    // if a given nsIVariant is in fact an XPCVariant.
     NS_DECLARE_STATIC_IID_ACCESSOR(XPCVARIANT_IID)
 
     static XPCVariant* newVariant(XPCCallContext& ccx, jsval aJSVal);
 
     jsval GetJSVal() const {return mJSVal;}
 
     XPCVariant(jsval aJSVal);
 
@@ -3917,18 +3933,18 @@ public:
      * Convert a variant into a jsval.
      *
      * @param ccx the context for the whole procedure
      * @param variant the variant to convert
      * @param scope the default scope to put on the new JSObject's __parent__
      *        chain
      * @param pErr [out] relevant error code, if any.
      * @param pJSVal [out] the resulting jsval.
-     */    
-    static JSBool VariantDataToJS(XPCCallContext& ccx, 
+     */
+    static JSBool VariantDataToJS(XPCCallContext& ccx,
                                   nsIVariant* variant,
                                   JSObject* scope, nsresult* pErr,
                                   jsval* pJSVal);
 
 protected:
     virtual ~XPCVariant() { }
 
     JSBool InitializeData(XPCCallContext& ccx);
--- a/testing/mochitest/Makefile.in
+++ b/testing/mochitest/Makefile.in
@@ -121,16 +121,22 @@ TEST_DRIVER_PPARGS += -DIS_CYGWIN=1
 endif
 
 ifeq ($(ENABLE_TESTS), 1)
 TEST_DRIVER_PPARGS += -DIS_TEST_BUILD=1
 else
 TEST_DRIVER_PPARGS += -DIS_TEST_BUILD=0
 endif
 
+ifeq ($(MOZ_DEBUG), 1)
+TEST_DRIVER_PPARGS += -DIS_DEBUG_BUILD=1
+else
+TEST_DRIVER_PPARGS += -DIS_DEBUG_BUILD=0
+endif
+
 runtests.py: runtests.py.in
 	$(PYTHON) $(topsrcdir)/config/Preprocessor.py \
 	$(TEST_DRIVER_PPARGS) $(DEFINES) $(ACDEFINES) $^ > $@
 
 automation.py: $(topsrcdir)/build/pgo/automation.py.in
 	$(PYTHON) $(topsrcdir)/config/Preprocessor.py \
 	$(TEST_DRIVER_PPARGS) $(DEFINES) $(ACDEFINES) $^ > $@