author | Brian Hackett <bhackett1024@gmail.com> |
Tue, 07 Feb 2017 13:20:32 -0700 | |
changeset 341292 | e2b893be9f4ca14fe0b96080092d9b19b46b5d70 |
parent 341291 | 2922efcfc78d861138c50c4d8731230d24343224 |
child 341293 | 3bd986e5c3c856b81a5b09fdd69925555ec5a93f |
push id | 31329 |
push user | cbook@mozilla.com |
push date | Wed, 08 Feb 2017 10:30:09 +0000 |
treeherder | mozilla-central@3a95aa424665 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jandem |
bugs | 1334845 |
milestone | 54.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
|
--- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -1026,17 +1026,17 @@ JSContext::JSContext(JSRuntime* runtime, if (!TlsContext.get()) TlsContext.set(this); } JSContext::~JSContext() { #ifdef XP_WIN if (threadNative_) - CloseHandle((HANDLE)threadNative_); + CloseHandle((HANDLE)threadNative_.ref()); #endif /* Free the stuff hanging off of cx. */ MOZ_ASSERT(!resolvingList); if (dtoaState) DestroyDtoaState(dtoaState); @@ -1046,16 +1046,28 @@ JSContext::~JSContext() #ifdef JS_SIMULATOR js::jit::Simulator::Destroy(simulator_); #endif if (TlsContext.get() == this) TlsContext.set(nullptr); } +void +JSContext::setRuntime(JSRuntime* rt) +{ + MOZ_ASSERT(!resolvingList); + MOZ_ASSERT(!compartment()); + MOZ_ASSERT(!activation()); + MOZ_ASSERT(!unwrappedException_.ref().initialized()); + MOZ_ASSERT(!asyncStackForNewActivations_.ref().initialized()); + + runtime_ = rt; +} + bool JSContext::getPendingException(MutableHandleValue rval) { MOZ_ASSERT(throwing); rval.set(unwrappedException()); if (IsAtomsCompartment(compartment())) return true; bool wasOverRecursed = overRecursed_;
--- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -88,29 +88,33 @@ struct JSContext : public JS::RootingCon public js::MallocProvider<JSContext> { explicit JSContext(JSRuntime* runtime, const JS::ContextOptions& options); ~JSContext(); bool init(); private: - JSRuntime* const runtime_; + js::UnprotectedData<JSRuntime*> runtime_; // System handle for the thread this context is associated with. - size_t threadNative_; + js::WriteOnceData<size_t> threadNative_; // The thread on which this context is running, if this is performing a parse task. js::ThreadLocalData<js::HelperThread*> helperThread_; js::ThreadLocalData<JS::ContextOptions> options_; js::ThreadLocalData<js::gc::ArenaLists*> arenas_; public: + // This is used by helper threads to change the runtime their context is + // currently operating on. + void setRuntime(JSRuntime* rt); + size_t threadNative() const { return threadNative_; } inline js::gc::ArenaLists* arenas() const { return arenas_; } template <typename T> bool isInsideCurrentZone(T thing) const { return thing->zoneFromAnyThread() == zone_; }
--- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -868,16 +868,26 @@ GlobalHelperThreadState::checkTaskThread count++; if (count >= maxThreads) return false; } return true; } +struct MOZ_RAII AutoSetContextRuntime +{ + explicit AutoSetContextRuntime(JSRuntime* rt) { + TlsContext.get()->setRuntime(rt); + } + ~AutoSetContextRuntime() { + TlsContext.get()->setRuntime(nullptr); + } +}; + static inline bool IsHelperThreadSimulatingOOM(js::oom::ThreadType threadType) { #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) return js::oom::targetThread == threadType; #else return false; #endif @@ -1177,25 +1187,25 @@ js::GCParallelTask::runFromMainThread(JS mozilla::TimeStamp timeStart = mozilla::TimeStamp::Now(); run(); duration_ = mozilla::TimeStamp::Now() - timeStart; } void js::GCParallelTask::runFromHelperThread(AutoLockHelperThreadState& locked) { - JSContext cx(runtime(), JS::ContextOptions()); + AutoSetContextRuntime ascr(runtime()); gc::AutoSetThreadIsPerformingGC performingGC; { AutoUnlockHelperThreadState parallelSection(locked); mozilla::TimeStamp timeStart = mozilla::TimeStamp::Now(); - cx.heapState = JS::HeapState::MajorCollecting; + TlsContext.get()->heapState = JS::HeapState::MajorCollecting; run(); - cx.heapState = JS::HeapState::Idle; + TlsContext.get()->heapState = JS::HeapState::Idle; duration_ = mozilla::TimeStamp::Now() - timeStart; } state = Finished; HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked); } bool @@ -1489,17 +1499,16 @@ HelperThread::handlePromiseTaskWorkload( MOZ_ASSERT(HelperThreadState().canStartPromiseTask(locked)); MOZ_ASSERT(idle()); PromiseTask* task = HelperThreadState().promiseTasks(locked).popCopy(); currentTask.emplace(task); { AutoUnlockHelperThreadState unlock(locked); - JSContext cx(nullptr, JS::ContextOptions()); task->execute(); if (!task->runtime()->finishAsyncTaskCallback(task)) { // We cannot simply delete the task now because the PromiseTask must // be destroyed on its runtime's thread. Add it to a list of tasks // to delete before the next GC. AutoEnterOOMUnsafeRegion oomUnsafe; @@ -1543,17 +1552,17 @@ HelperThread::handleIonWorkload(AutoLock { AutoUnlockHelperThreadState unlock(locked); TraceLoggerThread* logger = TraceLoggerForCurrentThread(); TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, builder->script()); AutoTraceLog logScript(logger, event); AutoTraceLog logCompile(logger, TraceLogger_IonCompilation); - JSContext cx(rt, JS::ContextOptions()); + AutoSetContextRuntime ascr(rt); jit::JitContext jctx(jit::CompileRuntime::get(rt), jit::CompileCompartment::get(builder->script()->compartment()), &builder->alloc()); builder->setBackgroundCodegen(jit::CompileBackEnd(builder)); } FinishOffThreadIonCompile(builder, locked); currentTask.reset(); @@ -1660,23 +1669,23 @@ HelperThread::handleParseWorkload(AutoLo currentTask.emplace(HelperThreadState().parseWorklist(locked).popCopy()); ParseTask* task = parseTask(); task->cx->setHelperThread(this); for (size_t i = 0; i < ArrayLength(task->cx->nativeStackLimit); i++) task->cx->nativeStackLimit[i] = stackLimit; - MOZ_ASSERT(!TlsContext.get()); + JSContext* oldcx = TlsContext.get(); TlsContext.set(task->cx); { AutoUnlockHelperThreadState unlock(locked); task->parse(); } - TlsContext.set(nullptr); + TlsContext.set(oldcx); // The callback is invoked while we are still off the main thread. task->callback(task, task->callbackData); // FinishOffThreadScript will need to be called on the script to // migrate it into the correct compartment. { AutoEnterOOMUnsafeRegion oomUnsafe; @@ -1858,17 +1867,17 @@ void HelperThread::handleGCHelperWorkload(AutoLockHelperThreadState& locked) { MOZ_ASSERT(HelperThreadState().canStartGCHelperTask(locked)); MOZ_ASSERT(idle()); currentTask.emplace(HelperThreadState().gcHelperWorklist(locked).popCopy()); GCHelperState* task = gcHelperTask(); - JSContext cx(task->runtime(), JS::ContextOptions()); + AutoSetContextRuntime ascr(task->runtime()); { AutoUnlockHelperThreadState unlock(locked); task->work(); } currentTask.reset(); HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked); @@ -1877,16 +1886,18 @@ HelperThread::handleGCHelperWorkload(Aut void HelperThread::threadLoop() { MOZ_ASSERT(CanUseExtraThreads()); JS::AutoSuppressGCAnalysis nogc; AutoLockHelperThreadState lock; + JSContext cx(nullptr, JS::ContextOptions()); + // Compute the thread's stack limit, for over-recursed checks. uintptr_t stackLimit = GetNativeStackBase(); #if JS_STACK_GROWTH_DIRECTION > 0 stackLimit += HELPER_STACK_QUOTA; #else stackLimit -= HELPER_STACK_QUOTA; #endif