Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* vim: set ts=8 sts=4 et sw=4 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
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : /* Implementation of xptiInterfaceInfoManager. */
8 :
9 : #include "mozilla/XPTInterfaceInfoManager.h"
10 :
11 : #include "mozilla/FileUtils.h"
12 : #include "mozilla/MemoryReporting.h"
13 : #include "mozilla/StaticPtr.h"
14 :
15 : #include "xptiprivate.h"
16 : #include "nsDependentString.h"
17 : #include "nsString.h"
18 : #include "nsArrayEnumerator.h"
19 : #include "nsDirectoryService.h"
20 : #include "nsIMemoryReporter.h"
21 :
22 : using namespace mozilla;
23 :
24 102 : NS_IMPL_ISUPPORTS(
25 : XPTInterfaceInfoManager,
26 : nsIInterfaceInfoManager,
27 : nsIMemoryReporter)
28 :
29 3 : static StaticRefPtr<XPTInterfaceInfoManager> gInterfaceInfoManager;
30 :
31 : size_t
32 0 : XPTInterfaceInfoManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
33 : {
34 0 : size_t n = aMallocSizeOf(this);
35 0 : ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
36 : // The entries themselves are allocated out of an arena accounted
37 : // for elsewhere, so don't measure them
38 0 : n += mWorkingSet.mIIDTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
39 0 : n += mWorkingSet.mNameTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
40 0 : return n;
41 : }
42 :
43 0 : MOZ_DEFINE_MALLOC_SIZE_OF(XPTIMallocSizeOf)
44 :
45 : NS_IMETHODIMP
46 0 : XPTInterfaceInfoManager::CollectReports(nsIHandleReportCallback* aHandleReport,
47 : nsISupports* aData, bool aAnonymize)
48 : {
49 0 : size_t amount = SizeOfIncludingThis(XPTIMallocSizeOf);
50 :
51 : // Measure gXPTIStructArena here, too. This is a bit grotty because it
52 : // doesn't belong to the XPTIInterfaceInfoManager, but there's no
53 : // obviously better place to measure it.
54 0 : amount += XPT_SizeOfArenaIncludingThis(gXPTIStructArena, XPTIMallocSizeOf);
55 :
56 0 : MOZ_COLLECT_REPORT(
57 : "explicit/xpti-working-set", KIND_HEAP, UNITS_BYTES, amount,
58 0 : "Memory used by the XPCOM typelib system.");
59 :
60 0 : return NS_OK;
61 : }
62 :
63 : // static
64 : XPTInterfaceInfoManager*
65 6630 : XPTInterfaceInfoManager::GetSingleton()
66 : {
67 6630 : if (!gInterfaceInfoManager) {
68 3 : gInterfaceInfoManager = new XPTInterfaceInfoManager();
69 3 : gInterfaceInfoManager->InitMemoryReporter();
70 : }
71 6630 : return gInterfaceInfoManager;
72 : }
73 :
74 : void
75 0 : XPTInterfaceInfoManager::FreeInterfaceInfoManager()
76 : {
77 0 : gInterfaceInfoManager = nullptr;
78 0 : }
79 :
80 3 : XPTInterfaceInfoManager::XPTInterfaceInfoManager()
81 : : mWorkingSet(),
82 3 : mResolveLock("XPTInterfaceInfoManager.mResolveLock")
83 : {
84 3 : }
85 :
86 0 : XPTInterfaceInfoManager::~XPTInterfaceInfoManager()
87 : {
88 : // We only do this on shutdown of the service.
89 0 : mWorkingSet.InvalidateInterfaceInfos();
90 :
91 0 : UnregisterWeakMemoryReporter(this);
92 0 : }
93 :
94 : void
95 3 : XPTInterfaceInfoManager::InitMemoryReporter()
96 : {
97 3 : RegisterWeakMemoryReporter(this);
98 3 : }
99 :
100 : void
101 522 : XPTInterfaceInfoManager::RegisterBuffer(char *buf, uint32_t length)
102 : {
103 : XPTState state;
104 522 : XPT_InitXDRState(&state, buf, length);
105 :
106 : XPTCursor curs;
107 522 : NotNull<XPTCursor*> cursor = WrapNotNull(&curs);
108 522 : if (!XPT_MakeCursor(&state, XPT_HEADER, 0, cursor)) {
109 0 : return;
110 : }
111 :
112 522 : XPTHeader *header = nullptr;
113 522 : if (XPT_DoHeader(gXPTIStructArena, cursor, &header)) {
114 522 : RegisterXPTHeader(header);
115 : }
116 : }
117 :
118 : void
119 522 : XPTInterfaceInfoManager::RegisterXPTHeader(XPTHeader* aHeader)
120 : {
121 522 : if (aHeader->major_version >= XPT_MAJOR_INCOMPATIBLE_VERSION) {
122 0 : NS_ASSERTION(!aHeader->num_interfaces,"bad libxpt");
123 : LOG_AUTOREG((" file is version %d.%d Type file of version %d.0 or higher can not be read.\n", (int)header->major_version, (int)header->minor_version, (int)XPT_MAJOR_INCOMPATIBLE_VERSION));
124 : }
125 :
126 522 : xptiTypelibGuts* typelib = xptiTypelibGuts::Create(aHeader);
127 :
128 1044 : ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
129 6924 : for(uint16_t k = 0; k < aHeader->num_interfaces; k++)
130 6402 : VerifyAndAddEntryIfNew(aHeader->interface_directory + k, k, typelib);
131 522 : }
132 :
133 : void
134 6402 : XPTInterfaceInfoManager::VerifyAndAddEntryIfNew(XPTInterfaceDirectoryEntry* iface,
135 : uint16_t idx,
136 : xptiTypelibGuts* typelib)
137 : {
138 6402 : if (!iface->interface_descriptor)
139 5073 : return;
140 :
141 : // The number of maximum methods is not arbitrary. It is the same value as
142 : // in xpcom/reflect/xptcall/genstubs.pl; do not change this value
143 : // without changing that one or you WILL see problems.
144 3882 : if (iface->interface_descriptor->num_methods > 250 &&
145 0 : !(XPT_ID_IS_BUILTINCLASS(iface->interface_descriptor->flags))) {
146 0 : NS_ASSERTION(0, "Too many methods to handle for the stub, cannot load");
147 0 : fprintf(stderr, "ignoring too large interface: %s\n", iface->name);
148 0 : return;
149 : }
150 :
151 3882 : mWorkingSet.mTableReentrantMonitor.AssertCurrentThreadIn();
152 3882 : xptiInterfaceEntry* entry = mWorkingSet.mIIDTable.Get(iface->iid);
153 3882 : if (entry) {
154 : // XXX validate this info to find possible inconsistencies
155 : LOG_AUTOREG((" ignoring repeated interface: %s\n", iface->name));
156 33 : return;
157 : }
158 :
159 : // Build a new xptiInterfaceEntry object and hook it up.
160 :
161 3849 : entry = xptiInterfaceEntry::Create(iface->name,
162 : iface->iid,
163 : iface->interface_descriptor,
164 : typelib);
165 3849 : if (!entry)
166 0 : return;
167 :
168 : //XXX We should SetHeader too as part of the validation, no?
169 3849 : entry->SetScriptableFlag(XPT_ID_IS_SCRIPTABLE(iface->interface_descriptor->flags));
170 3849 : entry->SetBuiltinClassFlag(XPT_ID_IS_BUILTINCLASS(iface->interface_descriptor->flags));
171 3849 : entry->SetMainProcessScriptableOnlyFlag(
172 7698 : XPT_ID_IS_MAIN_PROCESS_SCRIPTABLE_ONLY(iface->interface_descriptor->flags));
173 :
174 3849 : mWorkingSet.mIIDTable.Put(entry->IID(), entry);
175 3849 : mWorkingSet.mNameTable.Put(entry->GetTheName(), entry);
176 :
177 3849 : typelib->SetEntryAt(idx, entry);
178 :
179 : LOG_AUTOREG((" added interface: %s\n", iface->name));
180 : }
181 :
182 : // this is a private helper
183 : static nsresult
184 2901 : EntryToInfo(xptiInterfaceEntry* entry, nsIInterfaceInfo **_retval)
185 : {
186 2901 : if (!entry) {
187 1383 : *_retval = nullptr;
188 1383 : return NS_ERROR_FAILURE;
189 : }
190 :
191 3036 : RefPtr<xptiInterfaceInfo> info = entry->InterfaceInfo();
192 1518 : info.forget(_retval);
193 1518 : return NS_OK;
194 : }
195 :
196 : xptiInterfaceEntry*
197 940 : XPTInterfaceInfoManager::GetInterfaceEntryForIID(const nsIID *iid)
198 : {
199 1880 : ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
200 1880 : return mWorkingSet.mIIDTable.Get(*iid);
201 : }
202 :
203 : NS_IMETHODIMP
204 2159 : XPTInterfaceInfoManager::GetInfoForIID(const nsIID * iid, nsIInterfaceInfo **_retval)
205 : {
206 2159 : NS_ASSERTION(iid, "bad param");
207 2159 : NS_ASSERTION(_retval, "bad param");
208 :
209 4318 : ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
210 2159 : xptiInterfaceEntry* entry = mWorkingSet.mIIDTable.Get(*iid);
211 4318 : return EntryToInfo(entry, _retval);
212 : }
213 :
214 : NS_IMETHODIMP
215 742 : XPTInterfaceInfoManager::GetInfoForName(const char *name, nsIInterfaceInfo **_retval)
216 : {
217 742 : NS_ASSERTION(name, "bad param");
218 742 : NS_ASSERTION(_retval, "bad param");
219 :
220 1484 : ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
221 742 : xptiInterfaceEntry* entry = mWorkingSet.mNameTable.Get(name);
222 1484 : return EntryToInfo(entry, _retval);
223 : }
224 :
225 : void
226 0 : XPTInterfaceInfoManager::GetScriptableInterfaces(nsCOMArray<nsIInterfaceInfo>& aInterfaces)
227 : {
228 : // I didn't want to incur the size overhead of using nsHashtable just to
229 : // make building an enumerator easier. So, this code makes a snapshot of
230 : // the table using an nsCOMArray and builds an enumerator for that.
231 : // We can afford this transient cost.
232 :
233 0 : ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
234 0 : aInterfaces.SetCapacity(mWorkingSet.mNameTable.Count());
235 0 : for (auto iter = mWorkingSet.mNameTable.Iter(); !iter.Done(); iter.Next()) {
236 0 : xptiInterfaceEntry* entry = iter.UserData();
237 0 : if (entry->GetScriptableFlag()) {
238 0 : nsCOMPtr<nsIInterfaceInfo> ii = entry->InterfaceInfo();
239 0 : aInterfaces.AppendElement(ii);
240 : }
241 : }
242 0 : }
|