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;