1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "nsCodeCoverage.h"
7 #include "mozilla/CodeCoverageHandler.h"
8 #include "mozilla/Unused.h"
9 #include "mozilla/dom/ContentParent.h"
10 #include "mozilla/dom/Promise.h"
11
12 using mozilla::dom::ContentParent;
13 using mozilla::dom::Promise;
14
NS_IMPL_ISUPPORTS(nsCodeCoverage,nsICodeCoverage)15 NS_IMPL_ISUPPORTS(nsCodeCoverage, nsICodeCoverage)
16
17 nsCodeCoverage::nsCodeCoverage() {}
18
~nsCodeCoverage()19 nsCodeCoverage::~nsCodeCoverage() {}
20
21 enum RequestType { Flush };
22
23 class ProcessCount final {
24 NS_INLINE_DECL_REFCOUNTING(ProcessCount);
25
26 public:
ProcessCount(uint32_t c)27 explicit ProcessCount(uint32_t c) : mCount(c) {}
operator uint32_t() const28 operator uint32_t() const { return mCount; }
operator --()29 ProcessCount& operator--() {
30 mCount--;
31 return *this;
32 }
33
34 private:
~ProcessCount()35 ~ProcessCount() {}
36 uint32_t mCount;
37 };
38
39 namespace {
40
Request(JSContext * cx,Promise ** aPromise,RequestType requestType)41 nsresult Request(JSContext* cx, Promise** aPromise, RequestType requestType) {
42 MOZ_ASSERT(XRE_IsParentProcess());
43 MOZ_ASSERT(NS_IsMainThread());
44
45 nsIGlobalObject* global = xpc::CurrentNativeGlobal(cx);
46 if (NS_WARN_IF(!global)) {
47 return NS_ERROR_FAILURE;
48 }
49
50 mozilla::ErrorResult result;
51 RefPtr<Promise> promise = Promise::Create(global, result);
52 if (NS_WARN_IF(result.Failed())) {
53 return result.StealNSResult();
54 }
55
56 uint32_t processCount = 0;
57 for (auto* cp : ContentParent::AllProcesses(ContentParent::eLive)) {
58 mozilla::Unused << cp;
59 ++processCount;
60 }
61
62 if (requestType == RequestType::Flush) {
63 mozilla::CodeCoverageHandler::FlushCounters();
64 }
65
66 if (processCount == 0) {
67 promise->MaybeResolveWithUndefined();
68 } else {
69 RefPtr<ProcessCount> processCountHolder(new ProcessCount(processCount));
70
71 auto resolve = [processCountHolder, promise](bool unused) {
72 if (--(*processCountHolder) == 0) {
73 promise->MaybeResolveWithUndefined();
74 }
75 };
76
77 auto reject = [promise](mozilla::ipc::ResponseRejectReason&& aReason) {
78 promise->MaybeReject(NS_ERROR_FAILURE);
79 };
80
81 for (auto* cp : ContentParent::AllProcesses(ContentParent::eLive)) {
82 if (requestType == RequestType::Flush) {
83 cp->SendFlushCodeCoverageCounters(resolve, reject);
84 }
85 }
86 }
87
88 promise.forget(aPromise);
89 return NS_OK;
90 }
91
92 } // anonymous namespace
93
FlushCounters(JSContext * cx,Promise ** aPromise)94 NS_IMETHODIMP nsCodeCoverage::FlushCounters(JSContext* cx, Promise** aPromise) {
95 return Request(cx, aPromise, RequestType::Flush);
96 }
97