Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/base/DocGroup.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "mozilla/dom/DocGroup.h"
8
#include "mozilla/dom/DOMTypes.h"
9
#include "mozilla/dom/TabGroup.h"
10
#include "mozilla/StaticPrefs.h"
11
#include "mozilla/Telemetry.h"
12
#include "nsIDocShell.h"
13
#include "nsDOMMutationObserver.h"
14
#if defined(XP_WIN)
15
#include <processthreadsapi.h>  // for GetCurrentProcessId()
16
#else
17
#include <unistd.h> // for getpid()
18
#endif // defined(XP_WIN)
19
20
namespace mozilla {
21
namespace dom {
22
23
AutoTArray<RefPtr<DocGroup>, 2>* DocGroup::sPendingDocGroups = nullptr;
24
25
/* static */ nsresult
26
DocGroup::GetKey(nsIPrincipal* aPrincipal, nsACString& aKey)
27
0
{
28
0
  // Use GetBaseDomain() to handle things like file URIs, IP address URIs,
29
0
  // etc. correctly.
30
0
  nsresult rv = aPrincipal->GetBaseDomain(aKey);
31
0
  if (NS_FAILED(rv)) {
32
0
    // We don't really know what to do here.  But we should be conservative,
33
0
    // otherwise it would be possible to reorder two events incorrectly in the
34
0
    // future if we interrupt at the DocGroup level, so to be safe, use an
35
0
    // empty string to classify all such documents as belonging to the same
36
0
    // DocGroup.
37
0
    aKey.Truncate();
38
0
  }
39
0
40
0
  return rv;
41
0
}
42
43
void
44
DocGroup::RemoveDocument(nsIDocument* aDocument)
45
0
{
46
0
  MOZ_ASSERT(NS_IsMainThread());
47
0
  MOZ_ASSERT(mDocuments.Contains(aDocument));
48
0
  mDocuments.RemoveElement(aDocument);
49
0
}
50
51
DocGroup::DocGroup(TabGroup* aTabGroup, const nsACString& aKey)
52
  : mKey(aKey), mTabGroup(aTabGroup)
53
0
{
54
0
  // This method does not add itself to mTabGroup->mDocGroups as the caller does it for us.
55
0
  if (mozilla::StaticPrefs::dom_performance_enable_scheduler_timing()) {
56
0
    mPerformanceCounter = new mozilla::PerformanceCounter(NS_LITERAL_CSTRING("DocGroup:") + aKey);
57
0
  }
58
0
}
59
60
DocGroup::~DocGroup()
61
0
{
62
0
  MOZ_ASSERT(mDocuments.IsEmpty());
63
0
  if (!NS_IsMainThread()) {
64
0
    nsIEventTarget* target = EventTargetFor(TaskCategory::Other);
65
0
    NS_ProxyRelease("DocGroup::mReactionsStack", target, mReactionsStack.forget());
66
0
  }
67
0
68
0
  mTabGroup->mDocGroups.RemoveEntry(mKey);
69
0
}
70
71
PerformanceInfo
72
DocGroup::ReportPerformanceInfo()
73
0
{
74
0
  AssertIsOnMainThread();
75
0
  MOZ_ASSERT(mPerformanceCounter);
76
#if defined(XP_WIN)
77
  uint32_t pid = GetCurrentProcessId();
78
#else
79
  uint32_t pid = getpid();
80
0
#endif
81
0
  uint64_t windowID = 0;
82
0
  uint16_t count = 0;
83
0
  uint64_t duration = 0;
84
0
  bool isTopLevel = false;
85
0
  nsCString host;
86
0
87
0
  // iterating on documents until we find the top window
88
0
  for (const auto& document : *this) {
89
0
    nsCOMPtr<nsIDocument> doc = do_QueryInterface(document);
90
0
    MOZ_ASSERT(doc);
91
0
    nsCOMPtr<nsIURI> docURI = doc->GetDocumentURI();
92
0
    if (!docURI) {
93
0
      continue;
94
0
    }
95
0
    docURI->GetHost(host);
96
0
    // If the host is empty, using the url
97
0
    if (host.IsEmpty()) {
98
0
      host = docURI->GetSpecOrDefault();
99
0
    }
100
0
    // looking for the top level document URI
101
0
    nsPIDOMWindowOuter* win = doc->GetWindow();
102
0
    if (!win) {
103
0
      continue;
104
0
    }
105
0
    nsPIDOMWindowOuter* outer = win->GetOuterWindow();
106
0
    if (!outer) {
107
0
      continue;
108
0
    }
109
0
    nsCOMPtr<nsPIDOMWindowOuter> top = outer->GetTop();
110
0
    if (!top) {
111
0
      continue;
112
0
    }
113
0
    windowID = top->WindowID();
114
0
    isTopLevel = outer->IsTopLevelWindow();
115
0
    break;
116
0
  }
117
0
118
0
  MOZ_ASSERT(!host.IsEmpty());
119
0
  duration = mPerformanceCounter->GetExecutionDuration();
120
0
  FallibleTArray<CategoryDispatch> items;
121
0
122
0
  // now that we have the host and window ids, let's look at the perf counters
123
0
  for (uint32_t index = 0; index < (uint32_t)TaskCategory::Count; index++) {
124
0
    TaskCategory category = static_cast<TaskCategory>(index);
125
0
    count = mPerformanceCounter->GetDispatchCount(DispatchCategory(category));
126
0
    CategoryDispatch item = CategoryDispatch(index, count);
127
0
    if (!items.AppendElement(item, fallible)) {
128
0
      NS_ERROR("Could not complete the operation");
129
0
      break;
130
0
    }
131
0
  }
132
0
133
0
  return PerformanceInfo(host, pid, windowID, duration, mPerformanceCounter->GetID(),
134
0
                         false, isTopLevel, items);
135
0
}
136
137
nsresult
138
DocGroup::Dispatch(TaskCategory aCategory,
139
                   already_AddRefed<nsIRunnable>&& aRunnable)
140
0
{
141
0
  if (mPerformanceCounter) {
142
0
    mPerformanceCounter->IncrementDispatchCounter(DispatchCategory(aCategory));
143
0
  }
144
0
  return mTabGroup->DispatchWithDocGroup(aCategory, std::move(aRunnable), this);
145
0
}
146
147
nsISerialEventTarget*
148
DocGroup::EventTargetFor(TaskCategory aCategory) const
149
0
{
150
0
  return mTabGroup->EventTargetFor(aCategory);
151
0
}
152
153
AbstractThread*
154
DocGroup::AbstractMainThreadFor(TaskCategory aCategory)
155
0
{
156
0
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
157
0
  return mTabGroup->AbstractMainThreadFor(aCategory);
158
0
}
159
160
bool*
161
DocGroup::GetValidAccessPtr()
162
0
{
163
0
  return mTabGroup->GetValidAccessPtr();
164
0
}
165
166
void
167
DocGroup::SignalSlotChange(HTMLSlotElement& aSlot)
168
0
{
169
0
  MOZ_ASSERT(!mSignalSlotList.Contains(&aSlot));
170
0
  mSignalSlotList.AppendElement(&aSlot);
171
0
172
0
  if (!sPendingDocGroups) {
173
0
    // Queue a mutation observer compound microtask.
174
0
    nsDOMMutationObserver::QueueMutationObserverMicroTask();
175
0
    sPendingDocGroups = new AutoTArray<RefPtr<DocGroup>, 2>;
176
0
  }
177
0
178
0
  sPendingDocGroups->AppendElement(this);
179
0
}
180
181
void
182
DocGroup::MoveSignalSlotListTo(nsTArray<RefPtr<HTMLSlotElement>>& aDest)
183
0
{
184
0
  aDest.SetCapacity(aDest.Length() + mSignalSlotList.Length());
185
0
  for (RefPtr<HTMLSlotElement>& slot : mSignalSlotList) {
186
0
    slot->RemovedFromSignalSlotList();
187
0
    aDest.AppendElement(std::move(slot));
188
0
  }
189
0
  mSignalSlotList.Clear();
190
0
}
191
192
bool
193
DocGroup::IsActive() const
194
0
{
195
0
  for (nsIDocument* doc : mDocuments) {
196
0
    if (doc->IsCurrentActiveDocument()) {
197
0
      return true;
198
0
    }
199
0
  }
200
0
201
0
  return false;
202
0
}
203
204
}
205
}