# Global Metrics

path: .metrics.nexits.sum
old: 0.0
new: 22.0
path: .metrics.nexits.average
old: 0.0
new: 0.8461538461538461
path: .metrics.cognitive.sum
old: 0.0
new: 22.0
path: .metrics.cognitive.average
old: 0.0
new: 0.8461538461538461
path: .metrics.loc.blank
old: 19.0
new: 55.0
path: .metrics.loc.lloc
old: 0.0
new: 92.0
path: .metrics.loc.cloc
old: 6.0
new: 34.0
path: .metrics.loc.ploc
old: 83.0
new: 253.0
path: .metrics.loc.sloc
old: 108.0
new: 342.0
path: .metrics.mi.mi_original
old: 54.1579465950381
new: 17.276604743750113
path: .metrics.mi.mi_sei
old: 20.89786254430325
new: -21.61059094316863
path: .metrics.mi.mi_visual_studio
old: 31.671313798267896
new: 10.103277627924042
path: .metrics.nargs.average
old: 8.0
new: 0.5384615384615384
path: .metrics.nargs.sum
old: 8.0
new: 14.0
path: .metrics.cyclomatic.average
old: 1.0
new: 1.5555555555555556
path: .metrics.cyclomatic.sum
old: 6.0
new: 56.0
path: .metrics.halstead.n1
old: 13.0
new: 26.0
path: .metrics.halstead.n2
old: 80.0
new: 134.0
path: .metrics.halstead.vocabulary
old: 93.0
new: 160.0
path: .metrics.halstead.level
old: 0.08606777837547068
new: 0.025388404698749527
path: .metrics.halstead.bugs
old: 0.2744773629700805
new: 1.4637476836917094
path: .metrics.halstead.time
old: 1312.711155376145
new: 16166.22832221345
path: .metrics.halstead.difficulty
old: 11.61875
new: 39.38805970149254
path: .metrics.halstead.estimated_program_length
old: 553.8599639268232
new: 1069.06738419301
path: .metrics.halstead.purity_ratio
old: 1.780900205552486
new: 1.0595315997948562
path: .metrics.halstead.N2
old: 143.0
new: 406.0
path: .metrics.halstead.effort
old: 23628.800796770607
new: 290992.1097998421
path: .metrics.halstead.volume
old: 2033.6783902545976
new: 7387.825447741349
path: .metrics.halstead.N1
old: 168.0
new: 603.0
path: .metrics.halstead.length
old: 311.0
new: 1009.0
path: .metrics.nom.functions
old: 1.0
new: 26.0
path: .metrics.nom.total
old: 1.0
new: 26.0

# Spaces Data

## Minimal test - lines (25, 259)

path: .spaces[0].metrics.loc.cloc
old: 1.0
new: 22.0
path: .spaces[0].metrics.loc.ploc
old: 72.0
new: 174.0
path: .spaces[0].metrics.loc.blank
old: 16.0
new: 39.0
path: .spaces[0].metrics.loc.sloc
old: 89.0
new: 235.0
path: .spaces[0].metrics.loc.lloc
old: 0.0
new: 60.0
path: .spaces[0].metrics.cognitive.sum
old: 0.0
new: 12.0
path: .spaces[0].metrics.cognitive.average
old: 0.0
new: 0.5714285714285714
path: .spaces[0].metrics.mi.mi_sei
old: 16.251607584085797
new: -7.3885781428147475
path: .spaces[0].metrics.mi.mi_original
old: 57.71802216163934
new: 28.637365831306624
path: .spaces[0].metrics.mi.mi_visual_studio
old: 33.75322933429201
new: 16.746997562167618
path: .spaces[0].metrics.nexits.average
old: 0.0
new: 0.6666666666666666
path: .spaces[0].metrics.nexits.sum
old: 0.0
new: 14.0
path: .spaces[0].metrics.halstead.N2
old: 136.0
new: 293.0
path: .spaces[0].metrics.halstead.length
old: 304.0
new: 742.0
path: .spaces[0].metrics.halstead.N1
old: 168.0
new: 449.0
path: .spaces[0].metrics.halstead.level
old: 0.08371040723981901
new: 0.02677868206878446
path: .spaces[0].metrics.halstead.time
old: 1299.8880355108136
new: 10775.5697167756
path: .spaces[0].metrics.halstead.volume
old: 1958.6548227380133
new: 5194.0
path: .spaces[0].metrics.halstead.difficulty
old: 11.945945945945946
new: 37.34313725490196
path: .spaces[0].metrics.halstead.n1
old: 13.0
new: 26.0
path: .spaces[0].metrics.halstead.estimated_program_length
old: 507.6052653923765
new: 802.7988175527609
path: .spaces[0].metrics.halstead.effort
old: 23397.984639194645
new: 193960.2549019608
path: .spaces[0].metrics.halstead.purity_ratio
old: 1.6697541624749228
new: 1.0819391072139637
path: .spaces[0].metrics.halstead.bugs
old: 0.2726869658563649
new: 1.1169161639642688
path: .spaces[0].metrics.halstead.vocabulary
old: 87.0
new: 128.0
path: .spaces[0].metrics.halstead.n2
old: 74.0
new: 102.0
path: .spaces[0].metrics.nom.total
old: 1.0
new: 21.0
path: .spaces[0].metrics.nom.functions
old: 1.0
new: 21.0
path: .spaces[0].metrics.cyclomatic.sum
old: 5.0
new: 41.0
path: .spaces[0].metrics.cyclomatic.average
old: 1.0
new: 1.4137931034482758
path: .spaces[0].metrics.nargs.average
old: 8.0
new: 0.6666666666666666
path: .spaces[0].metrics.nargs.sum
old: 8.0
new: 14.0

### Code

    namespace {

    class AndroidUiThread;
    class AndroidUiTask;

    StaticAutoPtr > sTaskQueue;
    StaticAutoPtr sTaskQueueLock;
    StaticRefPtr sThread;
    static bool sThreadDestroyed;
    static MessageLoop* sMessageLoop;
    static Atomic sMessageLoopAccessMonitor;

    void EnqueueTask(already_AddRefed aTask, int aDelayMs);

    /*
     * The AndroidUiThread is derived from nsThread so that nsIRunnable objects that
     * get dispatched may be intercepted. Only nsIRunnable objects that need to be
     * synchronously executed are passed into the nsThread to be queued. All other
     * nsIRunnable object are immediately dispatched to the Android UI thread.
     * AndroidUiThread is derived from nsThread instead of being an nsIEventTarget
     * wrapper that contains an nsThread object because if nsIRunnable objects with
     * a delay were dispatch directly to an nsThread object, such as obtained from
     * nsThreadManager::GetCurrentThread(), the nsIRunnable could get stuck in the
     * nsThread nsIRunnable queue. This is due to the fact that Android controls the
     * event loop in the Android UI thread and has no knowledge of when the nsThread
     * needs to be drained.
     */

    class AndroidUiThread : public nsThread {
     public:
      NS_INLINE_DECL_REFCOUNTING_INHERITED(AndroidUiThread, nsThread)
      AndroidUiThread()
          : nsThread(
                MakeNotNull(MakeUnique()),
                nsThread::NOT_MAIN_THREAD, 0) {}

      nsresult Dispatch(already_AddRefed aEvent,
                        uint32_t aFlags) override;
      nsresult DelayedDispatch(already_AddRefed aEvent,
                               uint32_t aDelayMs) override;

     private:
      ~AndroidUiThread() {}
    };

    NS_IMETHODIMP
    AndroidUiThread::Dispatch(already_AddRefed aEvent,
                              uint32_t aFlags) {
      if (aFlags & NS_DISPATCH_SYNC) {
        return nsThread::Dispatch(std::move(aEvent), aFlags);
      } else {
        EnqueueTask(std::move(aEvent), 0);
        return NS_OK;
      }
    }

    NS_IMETHODIMP
    AndroidUiThread::DelayedDispatch(already_AddRefed aEvent,
                                     uint32_t aDelayMs) {
      EnqueueTask(std::move(aEvent), aDelayMs);
      return NS_OK;
    }

    static void PumpEvents() { NS_ProcessPendingEvents(sThread.get()); }

    class ThreadObserver : public nsIThreadObserver {
     public:
      NS_DECL_THREADSAFE_ISUPPORTS
      NS_DECL_NSITHREADOBSERVER

      ThreadObserver() {}

     private:
      virtual ~ThreadObserver() {}
    };

    NS_IMPL_ISUPPORTS(ThreadObserver, nsIThreadObserver)

    NS_IMETHODIMP
    ThreadObserver::OnDispatchedEvent() {
      EnqueueTask(NS_NewRunnableFunction("PumpEvents", &PumpEvents), 0);
      return NS_OK;
    }

    NS_IMETHODIMP
    ThreadObserver::OnProcessNextEvent(nsIThreadInternal* thread, bool mayWait) {
      return NS_OK;
    }

    NS_IMETHODIMP
    ThreadObserver::AfterProcessNextEvent(nsIThreadInternal* thread,
                                          bool eventWasProcessed) {
      return NS_OK;
    }

    class AndroidUiTask : public LinkedListElement {
      using TimeStamp = mozilla::TimeStamp;
      using TimeDuration = mozilla::TimeDuration;

     public:
      explicit AndroidUiTask(already_AddRefed aTask)
          : mTask(aTask),
            mRunTime()  // Null timestamp representing no delay.
      {}

      AndroidUiTask(already_AddRefed aTask, int aDelayMs)
          : mTask(aTask),
            mRunTime(TimeStamp::Now() + TimeDuration::FromMilliseconds(aDelayMs)) {}

      bool IsEarlierThan(const AndroidUiTask& aOther) const {
        if (mRunTime) {
          return aOther.mRunTime ? mRunTime < aOther.mRunTime : false;
        }
        // In the case of no delay, we're earlier if aOther has a delay.
        // Otherwise, we're not earlier, to maintain task order.
        return !!aOther.mRunTime;
      }

      int64_t MillisecondsToRunTime() const {
        if (mRunTime) {
          return int64_t((mRunTime - TimeStamp::Now()).ToMilliseconds());
        }
        return 0;
      }

      already_AddRefed TakeTask() { return mTask.forget(); }

     private:
      nsCOMPtr mTask;
      const TimeStamp mRunTime;
    };

    class CreateOnUiThread : public Runnable {
     public:
      CreateOnUiThread() : Runnable("CreateOnUiThread") {}

      NS_IMETHOD Run() override {
        MOZ_ASSERT(!sThreadDestroyed);
        MOZ_ASSERT(sMessageLoopAccessMonitor);
        MonitorAutoLock lock(*sMessageLoopAccessMonitor);
        sThread = new AndroidUiThread();
        sThread->InitCurrentThread();
        sThread->SetObserver(new ThreadObserver());
        PROFILER_REGISTER_THREAD("AndroidUI");
        sMessageLoop =
            new MessageLoop(MessageLoop::TYPE_MOZILLA_ANDROID_UI, sThread.get());
        lock.NotifyAll();
        return NS_OK;
      }
    };

    class DestroyOnUiThread : public Runnable {
     public:
      DestroyOnUiThread() : Runnable("DestroyOnUiThread"), mDestroyed(false) {}

      NS_IMETHOD Run() override {
        MOZ_ASSERT(!sThreadDestroyed);
        MOZ_ASSERT(sMessageLoopAccessMonitor);
        MOZ_ASSERT(sTaskQueue);
        MonitorAutoLock lock(*sMessageLoopAccessMonitor);
        sThreadDestroyed = true;

        {
          // Flush the queue
          MutexAutoLock lock(*sTaskQueueLock);
          while (AndroidUiTask* task = sTaskQueue->getFirst()) {
            delete task;
          }
        }

        delete sMessageLoop;
        sMessageLoop = nullptr;
        MOZ_ASSERT(sThread);
        PROFILER_UNREGISTER_THREAD();
        nsThreadManager::get().UnregisterCurrentThread(*sThread);
        sThread = nullptr;
        mDestroyed = true;
        lock.NotifyAll();
        return NS_OK;
      }

      void WaitForDestruction() {
        MOZ_ASSERT(sMessageLoopAccessMonitor);
        MonitorAutoLock lock(*sMessageLoopAccessMonitor);
        while (!mDestroyed) {
          lock.Wait();
        }
      }

     private:
      bool mDestroyed;
    };

    void EnqueueTask(already_AddRefed aTask, int aDelayMs) {
      if (sThreadDestroyed) {
        return;
      }

      // add the new task into the sTaskQueue, sorted with
      // the earliest task first in the queue
      AndroidUiTask* newTask =
          (aDelayMs ? new AndroidUiTask(std::move(aTask), aDelayMs)
                    : new AndroidUiTask(std::move(aTask)));

      bool headOfList = false;
      {
        MOZ_ASSERT(sTaskQueue);
        MOZ_ASSERT(sTaskQueueLock);
        MutexAutoLock lock(*sTaskQueueLock);

        AndroidUiTask* task = sTaskQueue->getFirst();

        while (task) {
          if (newTask->IsEarlierThan(*task)) {
            task->setPrevious(newTask);
            break;
          }
          task = task->getNext();
        }

        if (!newTask->isInList()) {
          sTaskQueue->insertBack(newTask);
        }
        headOfList = !newTask->getPrevious();
      }

      if (headOfList) {
        // if we're inserting it at the head of the queue, notify Java because
        // we need to get a callback at an earlier time than the last scheduled
        // callback
        java::GeckoThread::RequestUiThreadCallback(int64_t(aDelayMs));
      }
    }

    }  // namespace

## Minimal test - lines (27, 27)

path: .spaces[0].spaces[0].metrics.halstead.vocabulary
old: 86.0
new: 1.0
path: .spaces[0].spaces[0].metrics.halstead.difficulty
old: 12.02054794520548
new: 0.0
path: .spaces[0].spaces[0].metrics.halstead.n1
old: 13.0
new: 0.0
path: .spaces[0].spaces[0].metrics.halstead.N1
old: 167.0
new: 0.0
path: .spaces[0].spaces[0].metrics.halstead.estimated_program_length
old: 499.96290913407546
new: null
path: .spaces[0].spaces[0].metrics.halstead.length
old: 302.0
new: 1.0
path: .spaces[0].spaces[0].metrics.halstead.purity_ratio
old: 1.6555063216360115
new: null
path: .spaces[0].spaces[0].metrics.halstead.volume
old: 1940.7319559200337
new: 0.0
path: .spaces[0].spaces[0].metrics.halstead.n2
old: 73.0
new: 1.0
path: .spaces[0].spaces[0].metrics.halstead.effort
old: 23328.66152492917
new: 0.0
path: .spaces[0].spaces[0].metrics.halstead.level
old: 0.08319088319088319
new: null
path: .spaces[0].spaces[0].metrics.halstead.time
old: 1296.036751384954
new: 0.0
path: .spaces[0].spaces[0].metrics.halstead.bugs
old: 0.2721480916244786
new: 0.0
path: .spaces[0].spaces[0].metrics.halstead.N2
old: 135.0
new: 1.0
path: .spaces[0].spaces[0].metrics.nom.functions
old: 1.0
new: 0.0
path: .spaces[0].spaces[0].metrics.nom.total
old: 1.0
new: 0.0
path: .spaces[0].spaces[0].metrics.loc.blank
old: 17.0
new: 0.0
path: .spaces[0].spaces[0].metrics.loc.sloc
old: 87.0
new: 1.0
path: .spaces[0].spaces[0].metrics.loc.ploc
old: 70.0
new: 1.0
path: .spaces[0].spaces[0].metrics.nargs.average
old: 8.0
new: null
path: .spaces[0].spaces[0].metrics.nargs.sum
old: 8.0
new: 0.0
path: .spaces[0].spaces[0].metrics.mi.mi_visual_studio
old: 34.13100701369519
new: null
path: .spaces[0].spaces[0].metrics.mi.mi_sei
old: 8.907912541844738
new: null
path: .spaces[0].spaces[0].metrics.mi.mi_original
old: 58.364021993418774
new: null
path: .spaces[0].spaces[0].metrics.cyclomatic.sum
old: 4.0
new: 1.0
path: .spaces[0].spaces[0].metrics.cognitive.average
old: 0.0
new: null
path: .spaces[0].spaces[0].metrics.nexits.average
old: 0.0
new: null

### Code

    class AndroidUiThread;