From c0e306ba339ce48f511e082fda8cc4cf73fbe0a3 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Thu, 1 Jun 2017 15:18:47 +0100 Subject: [PATCH] Bug 1352507 - Reset the profiling stack when the shell context owning it dies r=njn --- .../jit-test/tests/profiler/bug1352507-1.js | 3 + .../jit-test/tests/profiler/bug1352507-2.js | 3 + js/src/shell/js.cpp | 61 ++++++++++++++++--- js/src/shell/jsshell.h | 3 +- 4 files changed, 62 insertions(+), 8 deletions(-) create mode 100644 js/src/jit-test/tests/profiler/bug1352507-1.js create mode 100644 js/src/jit-test/tests/profiler/bug1352507-2.js diff --git a/js/src/jit-test/tests/profiler/bug1352507-1.js b/js/src/jit-test/tests/profiler/bug1352507-1.js new file mode 100644 index 000000000000..3289da864938 --- /dev/null +++ b/js/src/jit-test/tests/profiler/bug1352507-1.js @@ -0,0 +1,3 @@ +if (helperThreadCount() === 0) + quit(); +evalInWorker("enableGeckoProfiling()"); diff --git a/js/src/jit-test/tests/profiler/bug1352507-2.js b/js/src/jit-test/tests/profiler/bug1352507-2.js new file mode 100644 index 000000000000..cf09062adf87 --- /dev/null +++ b/js/src/jit-test/tests/profiler/bug1352507-2.js @@ -0,0 +1,3 @@ +if (helperThreadCount() === 0) + quit(); +evalInCooperativeThread("enableGeckoProfiling()"); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 4f752ffabe13..108d8e14727f 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -3430,6 +3430,11 @@ WorkerMain(void* arg) KillWatchdog(cx); JS_SetGrayGCRootsTracer(cx, nullptr, nullptr); + + if (sc->geckoProfilingStack) { + MOZ_ALWAYS_TRUE(cx->runtime()->geckoProfiler().enable(false)); + SetContextProfilingStack(cx, nullptr); + } } // Workers can spawn other workers, so we need a lock to access workerThreads. @@ -5205,6 +5210,29 @@ IsLatin1(JSContext* cx, unsigned argc, Value* vp) return true; } +static bool +EnsureGeckoProfilingStackInstalled(JSContext* cx, ShellContext* sc) +{ + if (cx->runtime()->geckoProfiler().installed()) { + if (!sc->geckoProfilingStack) { + JS_ReportErrorASCII(cx, "Profiler already installed by another context"); + return false; + } + + return true; + } + + MOZ_ASSERT(!sc->geckoProfilingStack); + sc->geckoProfilingStack = MakeUnique(); + if (!sc->geckoProfilingStack) { + JS_ReportOutOfMemory(cx); + return false; + } + + SetContextProfilingStack(cx, sc->geckoProfilingStack.get()); + return true; +} + static bool EnableGeckoProfiling(JSContext* cx, unsigned argc, Value* vp) { @@ -5212,14 +5240,19 @@ EnableGeckoProfiling(JSContext* cx, unsigned argc, Value* vp) ShellContext* sc = GetShellContext(cx); - // Disable before re-enabling; see the assertion in |GeckoProfiler::setProfilingStack|. + if (!EnsureGeckoProfilingStackInstalled(cx, sc)) + return false; + + // Disable before re-enabling; see the assertion in + // |GeckoProfiler::setProfilingStack|. if (cx->runtime()->geckoProfiler().installed()) MOZ_ALWAYS_TRUE(cx->runtime()->geckoProfiler().enable(false)); - SetContextProfilingStack(cx, &sc->geckoProfilingStack); cx->runtime()->geckoProfiler().enableSlowAssertions(false); - if (!cx->runtime()->geckoProfiler().enable(true)) + if (!cx->runtime()->geckoProfiler().enable(true)) { JS_ReportErrorASCII(cx, "Cannot ensure single threaded execution in profiler"); + return false; + } args.rval().setUndefined(); return true; @@ -5233,6 +5266,9 @@ EnableGeckoProfilingWithSlowAssertions(JSContext* cx, unsigned argc, Value* vp) ShellContext* sc = GetShellContext(cx); + if (!EnsureGeckoProfilingStackInstalled(cx, sc)) + return false; + if (cx->runtime()->geckoProfiler().enabled()) { // If profiling already enabled with slow assertions disabled, // this is a no-op. @@ -5248,10 +5284,11 @@ EnableGeckoProfilingWithSlowAssertions(JSContext* cx, unsigned argc, Value* vp) if (cx->runtime()->geckoProfiler().installed()) MOZ_ALWAYS_TRUE(cx->runtime()->geckoProfiler().enable(false)); - SetContextProfilingStack(cx, &sc->geckoProfilingStack); cx->runtime()->geckoProfiler().enableSlowAssertions(true); - if (!cx->runtime()->geckoProfiler().enable(true)) + if (!cx->runtime()->geckoProfiler().enable(true)) { JS_ReportErrorASCII(cx, "Cannot ensure single threaded execution in profiler"); + return false; + } return true; } @@ -5260,9 +5297,19 @@ static bool DisableGeckoProfiling(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); - if (cx->runtime()->geckoProfiler().installed()) - MOZ_ALWAYS_TRUE(cx->runtime()->geckoProfiler().enable(false)); args.rval().setUndefined(); + + ShellContext* sc = GetShellContext(cx); + + if (!cx->runtime()->geckoProfiler().installed()) + return true; + + if (!sc->geckoProfilingStack) { + JS_ReportErrorASCII(cx, "Profiler was not installed by this context"); + return false; + } + + MOZ_ALWAYS_TRUE(cx->runtime()->geckoProfiler().enable(false)); return true; } diff --git a/js/src/shell/jsshell.h b/js/src/shell/jsshell.h index b4ceedd021e9..f33e158af299 100644 --- a/js/src/shell/jsshell.h +++ b/js/src/shell/jsshell.h @@ -171,6 +171,7 @@ using StackChars = Vector; struct ShellContext { explicit ShellContext(JSContext* cx); + bool isWorker; double timeoutInterval; double startTime; @@ -203,7 +204,7 @@ struct ShellContext js::shell::RCFile** errFilePtr; js::shell::RCFile** outFilePtr; - PseudoStack geckoProfilingStack; + UniquePtr geckoProfilingStack; OffThreadState offThreadState;