Bug 912719 - Notify debugger about scripts compiled off thread, report parse errors/warnings for scripts in XUL documents, r=billm.
authorBrian Hackett <bhackett1024@gmail.com>
Tue, 10 Sep 2013 16:18:30 -0700
changeset 146467 55b09bed41221497e739830045a6ddf63a9532e0
parent 146466 d0a0127e099e03a7ff9ad32b8616260b19a09429
child 146468 4cb81ac52275ed9c819b001ceacd15d78b7b9db9
push id25261
push usercbook@mozilla.com
push dateWed, 11 Sep 2013 07:31:01 +0000
treeherdermozilla-central@f9e8e8ce552c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs912719
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 912719 - Notify debugger about scripts compiled off thread, report parse errors/warnings for scripts in XUL documents, r=billm.
content/xul/content/src/nsXULElement.cpp
js/src/jsworkers.cpp
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -2574,20 +2574,21 @@ NotifyOffThreadScriptCompletedRunnable::
     MOZ_ASSERT(NS_IsMainThread());
 
     // Note: this unroots mScript so that it is available to be collected by the
     // JS GC. The receiver needs to root the script before performing a call that
     // could GC.
     nsCOMPtr<nsIJSRuntimeService> svc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
     NS_ENSURE_TRUE(svc, NS_ERROR_FAILURE);
 
-    JSRuntime *rt;
-    svc->GetRuntime(&rt);
-    NS_ENSURE_TRUE(svc, NS_ERROR_FAILURE);
-    JSScript *script = JS::FinishOffThreadScript(NULL, rt, mToken);
+    JSScript *script;
+    {
+        AutoSafeJSContext cx;
+        script = JS::FinishOffThreadScript(cx, JS_GetRuntime(cx), mToken);
+    }
 
     return mReceiver->OnScriptCompileComplete(script, script ? NS_OK : NS_ERROR_FAILURE);
 }
 
 static void
 OffThreadScriptReceiverCallback(void *aToken, void *aCallbackData)
 {
     // Be careful not to adjust the refcount on the receiver, as this callback
--- a/js/src/jsworkers.cpp
+++ b/js/src/jsworkers.cpp
@@ -9,16 +9,17 @@
 #ifdef JS_WORKER_THREADS
 #include "mozilla/DebugOnly.h"
 
 #include "prmjtime.h"
 
 #include "frontend/BytecodeCompiler.h"
 #include "jit/ExecutionModeInlines.h"
 #include "jit/IonBuilder.h"
+#include "vm/Debugger.h"
 
 #include "jscntxtinlines.h"
 #include "jscompartmentinlines.h"
 #include "jsobjinlines.h"
 
 using namespace js;
 
 using mozilla::DebugOnly;
@@ -494,22 +495,50 @@ WorkerThreadState::canStartParseTask()
 }
 
 bool
 WorkerThreadState::canStartCompressionTask()
 {
     return !compressionWorklist.empty();
 }
 
+static void
+CallNewScriptHookForAllScripts(JSContext *cx, HandleScript script)
+{
+    // We should never hit this, since nested scripts are also constructed via
+    // BytecodeEmitter instances on the stack.
+    JS_CHECK_RECURSION(cx, return);
+
+    // Recurse to any nested scripts.
+    if (script->hasObjects()) {
+        ObjectArray *objects = script->objects();
+        for (size_t i = 0; i < objects->length; i++) {
+            JSObject *obj = objects->vector[i];
+            if (obj->is<JSFunction>()) {
+                JSFunction *fun = &obj->as<JSFunction>();
+                if (fun->hasScript()) {
+                    RootedScript nested(cx, fun->nonLazyScript());
+                    CallNewScriptHookForAllScripts(cx, nested);
+                }
+            }
+        }
+    }
+
+    // The global new script hook is called on every script that was compiled.
+    RootedFunction function(cx, script->function());
+    CallNewScriptHook(cx, script, function);
+}
+
 JSScript *
 WorkerThreadState::finishParseTask(JSContext *maybecx, JSRuntime *rt, void *token)
 {
     ParseTask *parseTask = NULL;
 
     // The token is a ParseTask* which should be in the finished list.
+    // Find and remove its entry.
     {
         AutoLockWorkerThreadState lock(*rt->workerThreadState);
         for (size_t i = 0; i < parseFinishedList.length(); i++) {
             if (parseFinishedList[i] == token) {
                 parseTask = parseFinishedList[i];
                 parseFinishedList[i] = parseFinishedList.back();
                 parseFinishedList.popBack();
                 break;
@@ -543,25 +572,37 @@ WorkerThreadState::finishParseTask(JSCon
         JS_ASSERT(newProto);
 
         object->proto = newProto;
     }
 
     // Move the parsed script and all its contents into the desired compartment.
     gc::MergeCompartments(parseTask->cx->compartment(), parseTask->scopeChain->compartment());
 
+    RootedScript script(rt, parseTask->script);
+
     // If we have a context, report any error or warnings generated during the
-    // parse.
+    // parse, and inform the debugger about the compiled scripts.
     if (maybecx) {
         AutoCompartment ac(maybecx, parseTask->scopeChain);
         for (size_t i = 0; i < parseTask->errors.length(); i++)
             parseTask->errors[i]->throwError(maybecx);
+
+        if (script) {
+            // The Debugger only needs to be told about the topmost script that was compiled.
+            GlobalObject *compileAndGoGlobal = NULL;
+            if (script->compileAndGo)
+                compileAndGoGlobal = &script->global();
+            Debugger::onNewScript(maybecx, script, compileAndGoGlobal);
+
+            // The NewScript hook needs to be called for all compiled scripts.
+            CallNewScriptHookForAllScripts(maybecx, script);
+        }
     }
 
-    JSScript *script = parseTask->script;
     js_delete(parseTask);
     return script;
 }
 
 void
 WorkerThread::destroy()
 {
     WorkerThreadState &state = *runtime->workerThreadState;