# Global Metrics

path: .metrics.nexits.average
old: null
new: 1.2
path: .metrics.nexits.sum
old: 0.0
new: 18.0
path: .metrics.cognitive.sum
old: 0.0
new: 15.0
path: .metrics.cognitive.average
old: null
new: 1.0
path: .metrics.cyclomatic.sum
old: 9.0
new: 34.0
path: .metrics.cyclomatic.average
old: 1.0
new: 2.0
path: .metrics.nargs.sum
old: 0.0
new: 10.0
path: .metrics.nargs.average
old: null
new: 0.6666666666666666
path: .metrics.loc.ploc
old: 78.0
new: 164.0
path: .metrics.loc.blank
old: 43.0
new: 33.0
path: .metrics.loc.cloc
old: 17.0
new: 36.0
path: .metrics.loc.lloc
old: 0.0
new: 73.0
path: .metrics.loc.sloc
old: 138.0
new: 233.0
path: .metrics.mi.mi_original
old: 49.130595729626165
new: 30.49085063446458
path: .metrics.mi.mi_visual_studio
old: 28.731342531945128
new: 17.830906803780454
path: .metrics.mi.mi_sei
old: 21.96296461632253
new: 0.35019128220051954
path: .metrics.nom.total
old: 0.0
new: 15.0
path: .metrics.nom.functions
old: 0.0
new: 15.0
path: .metrics.halstead.volume
old: 2182.12979324149
new: 5090.150987437282
path: .metrics.halstead.level
old: 0.16385135135135137
new: 0.028299319727891157
path: .metrics.halstead.bugs
old: 0.18728332572784973
new: 1.0621402282669643
path: .metrics.halstead.effort
old: 13317.740593803732
new: 179868.31614261548
path: .metrics.halstead.n1
old: 8.0
new: 25.0
path: .metrics.halstead.N1
old: 177.0
new: 432.0
path: .metrics.halstead.time
old: 739.8744774335406
new: 9992.684230145303
path: .metrics.halstead.length
old: 325.0
new: 726.0
path: .metrics.halstead.N2
old: 148.0
new: 294.0
path: .metrics.halstead.estimated_program_length
old: 664.1915456921514
new: 812.9421354310416
path: .metrics.halstead.purity_ratio
old: 2.043666294437389
new: 1.1197550074807736
path: .metrics.halstead.n2
old: 97.0
new: 104.0
path: .metrics.halstead.vocabulary
old: 105.0
new: 129.0
path: .metrics.halstead.difficulty
old: 6.103092783505154
new: 35.33653846153846

# Spaces Data

## Minimal test - lines (11, 233)

path: .spaces[0].metrics.nom.functions
old: 0.0
new: 15.0
path: .spaces[0].metrics.nom.total
old: 0.0
new: 15.0
path: .spaces[0].metrics.mi.mi_visual_studio
old: 68.70259094468457
new: 18.399170613568092
path: .spaces[0].metrics.mi.mi_sei
old: 93.89084506851594
new: -0.04340424844734514
path: .spaces[0].metrics.mi.mi_original
old: 117.4814305154106
new: 31.462581749201433
path: .spaces[0].metrics.cognitive.sum
old: 0.0
new: 15.0
path: .spaces[0].metrics.cognitive.average
old: null
new: 1.0
path: .spaces[0].metrics.halstead.effort
old: 131.4584015082173
new: 181061.74660062863
path: .spaces[0].metrics.halstead.level
old: 0.5
new: 0.02794520547945206
path: .spaces[0].metrics.halstead.difficulty
old: 2.0
new: 35.78431372549019
path: .spaces[0].metrics.halstead.n2
old: 7.0
new: 102.0
path: .spaces[0].metrics.halstead.length
old: 19.0
new: 724.0
path: .spaces[0].metrics.halstead.n1
old: 4.0
new: 25.0
path: .spaces[0].metrics.halstead.volume
old: 65.72920075410865
new: 5059.807713223047
path: .spaces[0].metrics.halstead.purity_ratio
old: 1.455341287073854
new: 1.100391974620802
path: .spaces[0].metrics.halstead.estimated_program_length
old: 27.651484454403228
new: 796.6837896254606
path: .spaces[0].metrics.halstead.N2
old: 7.0
new: 292.0
path: .spaces[0].metrics.halstead.vocabulary
old: 11.0
new: 127.0
path: .spaces[0].metrics.halstead.N1
old: 12.0
new: 432.0
path: .spaces[0].metrics.halstead.time
old: 7.303244528234294
new: 10058.985922257149
path: .spaces[0].metrics.halstead.bugs
old: 0.008617956746016684
new: 1.0668332647994656
path: .spaces[0].metrics.nargs.sum
old: 0.0
new: 10.0
path: .spaces[0].metrics.nargs.average
old: null
new: 0.6666666666666666
path: .spaces[0].metrics.cyclomatic.average
old: 1.0
new: 2.0625
path: .spaces[0].metrics.cyclomatic.sum
old: 1.0
new: 33.0
path: .spaces[0].metrics.nexits.average
old: null
new: 1.2
path: .spaces[0].metrics.nexits.sum
old: 0.0
new: 18.0
path: .spaces[0].metrics.loc.lloc
old: 0.0
new: 73.0
path: .spaces[0].metrics.loc.cloc
old: 0.0
new: 30.0
path: .spaces[0].metrics.loc.sloc
old: 7.0
new: 223.0
path: .spaces[0].metrics.loc.blank
old: 0.0
new: 31.0
path: .spaces[0].metrics.loc.ploc
old: 7.0
new: 162.0

### Code

    namespace mozilla {

    TaskQueue::TaskQueue(already_AddRefed aTarget,
                         const char* aName, bool aRequireTailDispatch)
        : AbstractThread(aRequireTailDispatch),
          mTarget(aTarget),
          mQueueMonitor("TaskQueue::Queue"),
          mTailDispatcher(nullptr),
          mIsRunning(false),
          mIsShutdown(false),
          mName(aName) {}

    TaskQueue::TaskQueue(already_AddRefed aTarget,
                         bool aSupportsTailDispatch)
        : TaskQueue(std::move(aTarget), "Unnamed", aSupportsTailDispatch) {}

    TaskQueue::~TaskQueue() {
      // No one is referencing this TaskQueue anymore, meaning no tasks can be
      // pending as all Runner hold a reference to this TaskQueue.
    }

    NS_IMPL_ISUPPORTS_INHERITED(TaskQueue, AbstractThread, nsIDirectTaskDispatcher);

    TaskDispatcher& TaskQueue::TailDispatcher() {
      MOZ_ASSERT(IsCurrentThreadIn());
      MOZ_ASSERT(mTailDispatcher);
      return *mTailDispatcher;
    }

    // Note aRunnable is passed by ref to support conditional ownership transfer.
    // See Dispatch() in TaskQueue.h for more details.
    nsresult TaskQueue::DispatchLocked(nsCOMPtr& aRunnable,
                                       uint32_t aFlags, DispatchReason aReason) {
      mQueueMonitor.AssertCurrentThreadOwns();
      if (mIsShutdown) {
        return NS_ERROR_FAILURE;
      }

      AbstractThread* currentThread;
      if (aReason != TailDispatch && (currentThread = GetCurrent()) &&
          RequiresTailDispatch(currentThread) &&
          currentThread->IsTailDispatcherAvailable()) {
        MOZ_ASSERT(aFlags == NS_DISPATCH_NORMAL,
                   "Tail dispatch doesn't support flags");
        return currentThread->TailDispatcher().AddTask(this, aRunnable.forget());
      }

      LogRunnable::LogDispatch(aRunnable);
      mTasks.push({std::move(aRunnable), aFlags});

      if (mIsRunning) {
        return NS_OK;
      }
      RefPtr runner(new Runner(this));
      nsresult rv = mTarget->Dispatch(runner.forget(), aFlags);
      if (NS_FAILED(rv)) {
        NS_WARNING("Failed to dispatch runnable to run TaskQueue");
        return rv;
      }
      mIsRunning = true;

      return NS_OK;
    }

    void TaskQueue::AwaitIdle() {
      MonitorAutoLock mon(mQueueMonitor);
      AwaitIdleLocked();
    }

    void TaskQueue::AwaitIdleLocked() {
      // Make sure there are no tasks for this queue waiting in the caller's tail
      // dispatcher.
      MOZ_ASSERT_IF(AbstractThread::GetCurrent(),
                    !AbstractThread::GetCurrent()->HasTailTasksFor(this));

      mQueueMonitor.AssertCurrentThreadOwns();
      MOZ_ASSERT(mIsRunning || mTasks.empty());
      while (mIsRunning) {
        mQueueMonitor.Wait();
      }
    }

    void TaskQueue::AwaitShutdownAndIdle() {
      MOZ_ASSERT(!IsCurrentThreadIn());
      // Make sure there are no tasks for this queue waiting in the caller's tail
      // dispatcher.
      MOZ_ASSERT_IF(AbstractThread::GetCurrent(),
                    !AbstractThread::GetCurrent()->HasTailTasksFor(this));

      MonitorAutoLock mon(mQueueMonitor);
      while (!mIsShutdown) {
        mQueueMonitor.Wait();
      }
      AwaitIdleLocked();
    }

    RefPtr TaskQueue::BeginShutdown() {
      // Dispatch any tasks for this queue waiting in the caller's tail dispatcher,
      // since this is the last opportunity to do so.
      if (AbstractThread* currentThread = AbstractThread::GetCurrent()) {
        currentThread->TailDispatchTasksFor(this);
      }
      MonitorAutoLock mon(mQueueMonitor);
      mIsShutdown = true;
      RefPtr p = mShutdownPromise.Ensure(__func__);
      MaybeResolveShutdown();
      mon.NotifyAll();
      return p;
    }

    bool TaskQueue::IsEmpty() {
      MonitorAutoLock mon(mQueueMonitor);
      return mTasks.empty();
    }

    bool TaskQueue::IsCurrentThreadIn() const {
      bool in = mRunningThread == PR_GetCurrentThread();
      return in;
    }

    nsresult TaskQueue::Runner::Run() {
      TaskStruct event;
      {
        MonitorAutoLock mon(mQueue->mQueueMonitor);
        MOZ_ASSERT(mQueue->mIsRunning);
        if (mQueue->mTasks.empty()) {
          mQueue->mIsRunning = false;
          mQueue->MaybeResolveShutdown();
          mon.NotifyAll();
          return NS_OK;
        }
        event = std::move(mQueue->mTasks.front());
        mQueue->mTasks.pop();
      }
      MOZ_ASSERT(event.event);

      // Note that dropping the queue monitor before running the task, and
      // taking the monitor again after the task has run ensures we have memory
      // fences enforced. This means that if the object we're calling wasn't
      // designed to be threadsafe, it will be, provided we're only calling it
      // in this task queue.
      {
        AutoTaskGuard g(mQueue);
        SerialEventTargetGuard tg(mQueue);
        {
          LogRunnable::Run log(event.event);

          event.event->Run();

          // Drop the reference to event. The event will hold a reference to the
          // object it's calling, and we don't want to keep it alive, it may be
          // making assumptions what holds references to it. This is especially
          // the case if the object is waiting for us to shutdown, so that it
          // can shutdown (like in the MediaDecoderStateMachine's SHUTDOWN case).
          event.event = nullptr;
        }
      }

      {
        MonitorAutoLock mon(mQueue->mQueueMonitor);
        if (mQueue->mTasks.empty()) {
          // No more events to run. Exit the task runner.
          mQueue->mIsRunning = false;
          mQueue->MaybeResolveShutdown();
          mon.NotifyAll();
          return NS_OK;
        }
      }

      // There's at least one more event that we can run. Dispatch this Runner
      // to the target again to ensure it runs again. Note that we don't just
      // run in a loop here so that we don't hog the target. This means we may
      // run on another thread next time, but we rely on the memory fences from
      // mQueueMonitor for thread safety of non-threadsafe tasks.
      nsresult rv;
      {
        MonitorAutoLock mon(mQueue->mQueueMonitor);
        rv = mQueue->mTarget->Dispatch(
            this, mQueue->mTasks.front().flags | NS_DISPATCH_AT_END);
      }
      if (NS_FAILED(rv)) {
        // Failed to dispatch, shutdown!
        MonitorAutoLock mon(mQueue->mQueueMonitor);
        mQueue->mIsRunning = false;
        mQueue->mIsShutdown = true;
        mQueue->MaybeResolveShutdown();
        mon.NotifyAll();
      }

      return NS_OK;
    }

    //-----------------------------------------------------------------------------
    // nsIDirectTaskDispatcher
    //-----------------------------------------------------------------------------

    NS_IMETHODIMP
    TaskQueue::DispatchDirectTask(already_AddRefed aEvent) {
      if (!IsCurrentThreadIn()) {
        return NS_ERROR_FAILURE;
      }
      mDirectTasks.AddTask(std::move(aEvent));
      return NS_OK;
    }

    NS_IMETHODIMP TaskQueue::DrainDirectTasks() {
      if (!IsCurrentThreadIn()) {
        return NS_ERROR_FAILURE;
      }
      mDirectTasks.DrainTasks();
      return NS_OK;
    }

    NS_IMETHODIMP TaskQueue::HaveDirectTasks(bool* aValue) {
      if (!IsCurrentThreadIn()) {
        return NS_ERROR_FAILURE;
      }

      *aValue = mDirectTasks.HaveTasks();
      return NS_OK;
    }

    }  // namespace mozilla