OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2012 Google Inc. All rights reserved. | |
3 * | |
4 * Redistribution and use in source and binary forms, with or without | |
5 * modification, are permitted provided that the following conditions are | |
6 * met: | |
7 * | |
8 * * Redistributions of source code must retain the above copyright | |
9 * notice, this list of conditions and the following disclaimer. | |
10 * * Redistributions in binary form must reproduce the above | |
11 * copyright notice, this list of conditions and the following disclaimer | |
12 * in the documentation and/or other materials provided with the | |
13 * distribution. | |
14 * * Neither the name of Google Inc. nor the names of its | |
15 * contributors may be used to endorse or promote products derived from | |
16 * this software without specific prior written permission. | |
17 * | |
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 */ | |
30 | |
31 #include "config.h" | |
32 | |
33 #include "wtf/ArrayBuffer.h" | |
34 #include "wtf/HashCountedSet.h" | |
35 #include "wtf/HashMap.h" | |
36 #include "wtf/HashSet.h" | |
37 #include "wtf/ListHashSet.h" | |
38 #include "wtf/MemoryInstrumentation.h" | |
39 #include "wtf/MemoryInstrumentationArrayBufferView.h" | |
40 #include "wtf/MemoryInstrumentationHashCountedSet.h" | |
41 #include "wtf/MemoryInstrumentationHashMap.h" | |
42 #include "wtf/MemoryInstrumentationHashSet.h" | |
43 #include "wtf/MemoryInstrumentationListHashSet.h" | |
44 #include "wtf/MemoryInstrumentationString.h" | |
45 #include "wtf/MemoryInstrumentationVector.h" | |
46 #include "wtf/MemoryObjectInfo.h" | |
47 #include "wtf/RefCounted.h" | |
48 #include "wtf/Vector.h" | |
49 #include "wtf/text/AtomicString.h" | |
50 #include "wtf/text/CString.h" | |
51 #include "wtf/text/StringBuffer.h" | |
52 #include "wtf/text/StringHash.h" | |
53 #include "wtf/text/StringImpl.h" | |
54 #include "wtf/text/WTFString.h" | |
55 #include <gtest/gtest.h> | |
56 | |
57 namespace { | |
58 enum TestEnum { ONE = 1, TWO, THREE, MY_ENUM_MAX }; | |
59 } | |
60 | |
61 namespace WTF { | |
62 | |
63 template<> struct DefaultHash<TestEnum> { | |
64 typedef IntHash<unsigned> Hash; | |
65 }; | |
66 | |
67 template<> struct HashTraits<TestEnum> : GenericHashTraits<TestEnum> { | |
68 static const bool emptyValueIsZero = true; | |
69 static const bool needsDestruction = false; | |
70 static void constructDeletedValue(TestEnum& slot) { slot = static_cast<TestE
num>(MY_ENUM_MAX + 1); } | |
71 static bool isDeletedValue(TestEnum value) { return value == (MY_ENUM_MAX +
1); } | |
72 }; | |
73 | |
74 } | |
75 | |
76 namespace { | |
77 | |
78 using WTF::MemoryObjectInfo; | |
79 using WTF::MemoryClassInfo; | |
80 using WTF::MemoryObjectType; | |
81 using WTF::MemberType; | |
82 | |
83 MemoryObjectType TestType = "TestType"; | |
84 | |
85 class MemoryInstrumentationTestClient : public WTF::MemoryInstrumentationClient
{ | |
86 public: | |
87 MemoryInstrumentationTestClient() : m_links(WTF::LastMemberTypeEntry) | |
88 { | |
89 m_links[WTF::PointerMember] = 0; | |
90 m_links[WTF::ReferenceMember] = 0; | |
91 m_links[WTF::RetainingPointer] = 0; | |
92 } | |
93 | |
94 virtual void countObjectSize(const void*, MemoryObjectType objectType, size_
t size) | |
95 { | |
96 TypeToSizeMap::AddResult result = m_totalSizes.add(objectType, size); | |
97 if (!result.isNewEntry) | |
98 result.iterator->value += size; | |
99 } | |
100 virtual bool visited(const void* object) { return !m_visitedObjects.add(obje
ct).isNewEntry; } | |
101 virtual bool checkCountedObject(const void*) { return true; } | |
102 virtual void reportNode(const MemoryObjectInfo&) OVERRIDE { } | |
103 virtual void reportEdge(const void*, const char*, MemberType memberType) OVE
RRIDE | |
104 { | |
105 ++m_links[memberType]; | |
106 } | |
107 virtual void reportLeaf(const MemoryObjectInfo&, const char*) OVERRIDE | |
108 { | |
109 ++m_links[WTF::RetainingPointer]; | |
110 } | |
111 virtual void reportBaseAddress(const void*, const void*) OVERRIDE { } | |
112 virtual int registerString(const char*) OVERRIDE { return -1; } | |
113 | |
114 size_t visitedObjects() const { return m_visitedObjects.size(); } | |
115 size_t totalSize(const MemoryObjectType objectType) const | |
116 { | |
117 TypeToSizeMap::const_iterator i = m_totalSizes.find(objectType); | |
118 return i == m_totalSizes.end() ? 0 : i->value; | |
119 } | |
120 | |
121 size_t linksCount(const WTF::MemberType memberType) const | |
122 { | |
123 return m_links[memberType]; | |
124 } | |
125 | |
126 size_t reportedSizeForAllTypes() const | |
127 { | |
128 size_t size = 0; | |
129 for (TypeToSizeMap::const_iterator i = m_totalSizes.begin(); i != m_tota
lSizes.end(); ++i) | |
130 size += i->value; | |
131 return size; | |
132 } | |
133 | |
134 private: | |
135 typedef HashMap<MemoryObjectType, size_t> TypeToSizeMap; | |
136 TypeToSizeMap m_totalSizes; | |
137 WTF::HashSet<const void*> m_visitedObjects; | |
138 WTF::Vector<size_t, WTF::LastMemberTypeEntry> m_links; | |
139 }; | |
140 | |
141 class InstrumentationTestImpl : public WTF::MemoryInstrumentation { | |
142 public: | |
143 explicit InstrumentationTestImpl(MemoryInstrumentationTestClient* client) | |
144 : MemoryInstrumentation(client) | |
145 , m_client(client) { } | |
146 | |
147 virtual void processDeferredObjects(); | |
148 virtual void deferObject(PassOwnPtr<WrapperBase>); | |
149 | |
150 size_t visitedObjects() const { return m_client->visitedObjects(); } | |
151 size_t reportedSizeForAllTypes() const { return m_client->reportedSizeForAll
Types(); } | |
152 size_t totalSize(const MemoryObjectType objectType) const { return m_client-
>totalSize(objectType); } | |
153 size_t linksCount(const WTF::MemberType memberType) const { return m_client
->linksCount(memberType); } | |
154 | |
155 private: | |
156 MemoryInstrumentationTestClient* m_client; | |
157 Vector<OwnPtr<WrapperBase> > m_deferredObjects; | |
158 }; | |
159 | |
160 class InstrumentationTestHelper : public InstrumentationTestImpl { | |
161 public: | |
162 InstrumentationTestHelper() : InstrumentationTestImpl(&m_client) { } | |
163 | |
164 private: | |
165 MemoryInstrumentationTestClient m_client; | |
166 }; | |
167 | |
168 void InstrumentationTestImpl::processDeferredObjects() | |
169 { | |
170 while (!m_deferredObjects.isEmpty()) { | |
171 OwnPtr<WrapperBase> pointer = m_deferredObjects.last().release(); | |
172 m_deferredObjects.removeLast(); | |
173 pointer->process(this); | |
174 } | |
175 } | |
176 | |
177 void InstrumentationTestImpl::deferObject(PassOwnPtr<WrapperBase> pointer) | |
178 { | |
179 m_deferredObjects.append(pointer); | |
180 } | |
181 | |
182 class NotInstrumented { | |
183 public: | |
184 NotInstrumented(const char* = 0) { } | |
185 char m_data[42]; | |
186 }; | |
187 | |
188 class Instrumented { | |
189 public: | |
190 Instrumented() : m_notInstrumented(new NotInstrumented) { } | |
191 virtual ~Instrumented() { disposeOwnedObject(); } | |
192 | |
193 virtual void reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const | |
194 { | |
195 MemoryClassInfo info(memoryObjectInfo, this, TestType); | |
196 memoryObjectInfo->setClassName("Instrumented"); | |
197 info.addMember(m_notInstrumented, "m_notInstrumented", WTF::RetainingPoi
nter); | |
198 } | |
199 | |
200 void disposeOwnedObject() | |
201 { | |
202 delete m_notInstrumented; | |
203 m_notInstrumented = 0; | |
204 } | |
205 | |
206 NotInstrumented* m_notInstrumented; | |
207 }; | |
208 | |
209 TEST(MemoryInstrumentationTest, sizeOf) | |
210 { | |
211 InstrumentationTestHelper helper; | |
212 Instrumented instrumented; | |
213 helper.addRootObject(instrumented); | |
214 EXPECT_EQ(sizeof(NotInstrumented), helper.reportedSizeForAllTypes()); | |
215 EXPECT_EQ(1u, helper.visitedObjects()); | |
216 EXPECT_EQ(1u, helper.linksCount(WTF::RetainingPointer)); | |
217 } | |
218 | |
219 TEST(MemoryInstrumentationTest, nullCheck) | |
220 { | |
221 InstrumentationTestHelper helper; | |
222 Instrumented* instrumented = 0; | |
223 helper.addRootObject(instrumented); | |
224 EXPECT_EQ(0u, helper.reportedSizeForAllTypes()); | |
225 EXPECT_EQ(0u, helper.visitedObjects()); | |
226 EXPECT_EQ(0u, helper.linksCount(WTF::RetainingPointer)); | |
227 } | |
228 | |
229 TEST(MemoryInstrumentationTest, ptrVsRef) | |
230 { | |
231 { | |
232 InstrumentationTestHelper helper; | |
233 Instrumented instrumented; | |
234 helper.addRootObject(&instrumented); | |
235 EXPECT_EQ(sizeof(Instrumented) + sizeof(NotInstrumented), helper.reporte
dSizeForAllTypes()); | |
236 EXPECT_EQ(2u, helper.visitedObjects()); | |
237 EXPECT_EQ(1u, helper.linksCount(WTF::RetainingPointer)); | |
238 } | |
239 { | |
240 InstrumentationTestHelper helper; | |
241 Instrumented instrumented; | |
242 helper.addRootObject(instrumented); | |
243 EXPECT_EQ(sizeof(NotInstrumented), helper.reportedSizeForAllTypes()); | |
244 EXPECT_EQ(1u, helper.visitedObjects()); | |
245 EXPECT_EQ(1u, helper.linksCount(WTF::RetainingPointer)); | |
246 } | |
247 } | |
248 | |
249 class InstrumentedWithOwnPtr : public Instrumented { | |
250 public: | |
251 InstrumentedWithOwnPtr() : m_notInstrumentedOwnPtr(adoptPtr(new NotInstrumen
ted)) { } | |
252 | |
253 virtual void reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const | |
254 { | |
255 MemoryClassInfo info(memoryObjectInfo, this, TestType); | |
256 Instrumented::reportMemoryUsage(memoryObjectInfo); | |
257 info.addMember(m_notInstrumentedOwnPtr); | |
258 } | |
259 OwnPtr<NotInstrumented> m_notInstrumentedOwnPtr; | |
260 }; | |
261 | |
262 TEST(MemoryInstrumentationTest, ownPtrNotInstrumented) | |
263 { | |
264 InstrumentationTestHelper helper; | |
265 InstrumentedWithOwnPtr instrumentedWithOwnPtr; | |
266 helper.addRootObject(instrumentedWithOwnPtr); | |
267 EXPECT_EQ(2u * sizeof(NotInstrumented), helper.reportedSizeForAllTypes()); | |
268 EXPECT_EQ(2u, helper.visitedObjects()); | |
269 EXPECT_EQ(2u, helper.linksCount(WTF::RetainingPointer)); | |
270 } | |
271 | |
272 class InstrumentedUndefined { | |
273 public: | |
274 InstrumentedUndefined() : m_data(0) { } | |
275 | |
276 void reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const | |
277 { | |
278 MemoryClassInfo info(memoryObjectInfo, this); | |
279 } | |
280 int m_data; | |
281 }; | |
282 | |
283 class InstrumentedDOM { | |
284 public: | |
285 InstrumentedDOM() : m_instrumentedUndefined(adoptPtr(new InstrumentedUndefin
ed)) { } | |
286 | |
287 void reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const | |
288 { | |
289 MemoryClassInfo info(memoryObjectInfo, this, TestType); | |
290 info.addMember(m_instrumentedUndefined); | |
291 } | |
292 OwnPtr<InstrumentedUndefined> m_instrumentedUndefined; | |
293 }; | |
294 | |
295 TEST(MemoryInstrumentationTest, ownerTypePropagation) | |
296 { | |
297 InstrumentationTestHelper helper; | |
298 OwnPtr<InstrumentedDOM> instrumentedDOM(adoptPtr(new InstrumentedDOM)); | |
299 helper.addRootObject(instrumentedDOM.get()); | |
300 EXPECT_EQ(sizeof(InstrumentedDOM) + sizeof(InstrumentedUndefined), helper.re
portedSizeForAllTypes()); | |
301 EXPECT_EQ(sizeof(InstrumentedDOM) + sizeof(InstrumentedUndefined), helper.to
talSize(TestType)); | |
302 EXPECT_EQ(2u, helper.visitedObjects()); | |
303 } | |
304 | |
305 class NonVirtualInstrumented { | |
306 public: | |
307 void reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const | |
308 { | |
309 MemoryClassInfo info(memoryObjectInfo, this, TestType); | |
310 info.addMember(m_instrumented); | |
311 } | |
312 | |
313 Instrumented m_instrumented; | |
314 }; | |
315 | |
316 TEST(MemoryInstrumentationTest, visitFirstMemberInNonVirtualClass) | |
317 { | |
318 InstrumentationTestHelper helper; | |
319 NonVirtualInstrumented nonVirtualInstrumented; | |
320 helper.addRootObject(&nonVirtualInstrumented); | |
321 EXPECT_EQ(sizeof(NonVirtualInstrumented) + sizeof(NotInstrumented), helper.r
eportedSizeForAllTypes()); | |
322 EXPECT_EQ(2u, helper.visitedObjects()); | |
323 } | |
324 | |
325 template<typename T> | |
326 class InstrumentedOwner { | |
327 public: | |
328 template<typename V> | |
329 InstrumentedOwner(const V& value) : m_value(value) { } | |
330 InstrumentedOwner() { } | |
331 void reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const | |
332 { | |
333 MemoryClassInfo info(memoryObjectInfo, this, TestType); | |
334 info.addMember(m_value, "value", WTF::RetainingPointer); | |
335 } | |
336 | |
337 T m_value; | |
338 }; | |
339 | |
340 TEST(MemoryInstrumentationTest, visitStrings) | |
341 { | |
342 { // 8-bit string. | |
343 InstrumentationTestHelper helper; | |
344 InstrumentedOwner<String> stringInstrumentedOwner("String"); | |
345 helper.addRootObject(stringInstrumentedOwner); | |
346 EXPECT_EQ(sizeof(StringImpl) + stringInstrumentedOwner.m_value.length(),
helper.reportedSizeForAllTypes()); | |
347 EXPECT_EQ(1u, helper.visitedObjects()); | |
348 } | |
349 | |
350 { // 8-bit string with 16bit shadow. | |
351 InstrumentationTestHelper helper; | |
352 InstrumentedOwner<String> stringInstrumentedOwner("String"); | |
353 stringInstrumentedOwner.m_value.characters(); | |
354 helper.addRootObject(stringInstrumentedOwner); | |
355 EXPECT_EQ(sizeof(StringImpl) + stringInstrumentedOwner.m_value.length()
* (sizeof(LChar) + sizeof(UChar)), helper.reportedSizeForAllTypes()); | |
356 EXPECT_EQ(2u, helper.visitedObjects()); | |
357 } | |
358 | |
359 { // 16 bit string. | |
360 InstrumentationTestHelper helper; | |
361 String string("String"); | |
362 InstrumentedOwner<String> stringInstrumentedOwner(String(string.characte
rs(), string.length())); | |
363 helper.addRootObject(stringInstrumentedOwner); | |
364 EXPECT_EQ(sizeof(StringImpl) + stringInstrumentedOwner.m_value.length()
* sizeof(UChar), helper.reportedSizeForAllTypes()); | |
365 EXPECT_EQ(1u, helper.visitedObjects()); | |
366 } | |
367 | |
368 { // ASCIILiteral | |
369 InstrumentationTestHelper helper; | |
370 ASCIILiteral literal("String"); | |
371 InstrumentedOwner<String> stringInstrumentedOwner(literal); | |
372 helper.addRootObject(stringInstrumentedOwner); | |
373 EXPECT_EQ(sizeof(StringImpl), helper.reportedSizeForAllTypes()); | |
374 EXPECT_EQ(1u, helper.visitedObjects()); | |
375 } | |
376 | |
377 { // Zero terminated internal buffer. | |
378 InstrumentationTestHelper helper; | |
379 InstrumentedOwner<String> stringInstrumentedOwner("string"); | |
380 stringInstrumentedOwner.m_value.charactersWithNullTermination(); | |
381 helper.addRootObject(stringInstrumentedOwner); | |
382 EXPECT_EQ(sizeof(StringImpl) + (stringInstrumentedOwner.m_value.length()
+ 1) * (sizeof(LChar) + sizeof(UChar)), helper.reportedSizeForAllTypes()); | |
383 EXPECT_EQ(2u, helper.visitedObjects()); | |
384 } | |
385 | |
386 { // Substring | |
387 InstrumentationTestHelper helper; | |
388 String baseString("String"); | |
389 baseString.characters(); // Force 16 shadow creation. | |
390 InstrumentedOwner<String> stringInstrumentedOwner(baseString.substringSh
aringImpl(1, 4)); | |
391 helper.addRootObject(stringInstrumentedOwner); | |
392 EXPECT_EQ(sizeof(StringImpl) * 2 + baseString.length() * (sizeof(LChar)
+ sizeof(UChar)), helper.reportedSizeForAllTypes()); | |
393 EXPECT_EQ(3u, helper.visitedObjects()); | |
394 } | |
395 | |
396 { // Owned buffer. | |
397 InstrumentationTestHelper helper; | |
398 StringBuffer<LChar> buffer(6); | |
399 InstrumentedOwner<String> stringInstrumentedOwner(String::adopt(buffer))
; | |
400 helper.addRootObject(stringInstrumentedOwner); | |
401 EXPECT_EQ(sizeof(StringImpl) + stringInstrumentedOwner.m_value.length(),
helper.reportedSizeForAllTypes()); | |
402 EXPECT_EQ(2u, helper.visitedObjects()); | |
403 } | |
404 | |
405 { | |
406 InstrumentationTestHelper helper; | |
407 InstrumentedOwner<AtomicString> atomicStringInstrumentedOwner("AtomicStr
ing"); | |
408 atomicStringInstrumentedOwner.m_value.string().characters(); // Force 16
bit shadow creation. | |
409 helper.addRootObject(atomicStringInstrumentedOwner); | |
410 EXPECT_EQ(sizeof(StringImpl) + atomicStringInstrumentedOwner.m_value.len
gth() * (sizeof(LChar) + sizeof(UChar)), helper.reportedSizeForAllTypes()); | |
411 EXPECT_EQ(2u, helper.visitedObjects()); | |
412 } | |
413 | |
414 { | |
415 InstrumentationTestHelper helper; | |
416 InstrumentedOwner<CString> cStringInstrumentedOwner("CString"); | |
417 helper.addRootObject(cStringInstrumentedOwner); | |
418 EXPECT_EQ(sizeof(WTF::CStringBuffer) + cStringInstrumentedOwner.m_value.
length(), helper.reportedSizeForAllTypes()); | |
419 EXPECT_EQ(1u, helper.visitedObjects()); | |
420 } | |
421 } | |
422 | |
423 class TwoPointersToRefPtr { | |
424 public: | |
425 TwoPointersToRefPtr(const RefPtr<StringImpl>& value) : m_ptr1(&value), m_ptr
2(&value) { } | |
426 void reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const | |
427 { | |
428 MemoryClassInfo info(memoryObjectInfo, this, TestType); | |
429 info.addMember(m_ptr1); | |
430 info.addMember(m_ptr2); | |
431 } | |
432 | |
433 const RefPtr<StringImpl>* m_ptr1; | |
434 const RefPtr<StringImpl>* m_ptr2; | |
435 }; | |
436 | |
437 TEST(MemoryInstrumentationTest, refPtrPtr) | |
438 { | |
439 InstrumentationTestHelper helper; | |
440 RefPtr<StringImpl> refPtr; | |
441 TwoPointersToRefPtr root(refPtr); | |
442 helper.addRootObject(root); | |
443 EXPECT_EQ(sizeof(RefPtr<StringImpl>), helper.reportedSizeForAllTypes()); | |
444 EXPECT_EQ(1u, helper.visitedObjects()); | |
445 } | |
446 | |
447 class TwoPointersToOwnPtr { | |
448 public: | |
449 TwoPointersToOwnPtr(const OwnPtr<NotInstrumented>& value) : m_ptr1(&value),
m_ptr2(&value) { } | |
450 void reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const | |
451 { | |
452 MemoryClassInfo info(memoryObjectInfo, this, TestType); | |
453 info.addMember(m_ptr1); | |
454 info.addMember(m_ptr2); | |
455 } | |
456 | |
457 const OwnPtr<NotInstrumented>* m_ptr1; | |
458 const OwnPtr<NotInstrumented>* m_ptr2; | |
459 }; | |
460 | |
461 TEST(MemoryInstrumentationTest, ownPtrPtr) | |
462 { | |
463 InstrumentationTestHelper helper; | |
464 OwnPtr<NotInstrumented> ownPtr; | |
465 TwoPointersToOwnPtr root(ownPtr); | |
466 helper.addRootObject(root); | |
467 EXPECT_EQ(sizeof(OwnPtr<NotInstrumented>), helper.reportedSizeForAllTypes())
; | |
468 EXPECT_EQ(1u, helper.visitedObjects()); | |
469 } | |
470 | |
471 template<typename T> | |
472 class InstrumentedTemplate { | |
473 public: | |
474 template<typename V> | |
475 InstrumentedTemplate(const V& value) : m_value(value) { } | |
476 | |
477 template<typename MemoryObjectInfo> | |
478 void reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const | |
479 { | |
480 typename MemoryObjectInfo::ClassInfo info(memoryObjectInfo, this, TestTy
pe); | |
481 info.addMember(m_value); | |
482 } | |
483 | |
484 T m_value; | |
485 }; | |
486 | |
487 TEST(MemoryInstrumentationTest, detectReportMemoryUsageMethod) | |
488 { | |
489 { | |
490 InstrumentationTestHelper helper; | |
491 | |
492 OwnPtr<InstrumentedTemplate<String> > value(adoptPtr(new InstrumentedTem
plate<String>(""))); | |
493 InstrumentedOwner<InstrumentedTemplate<String>* > root(value.get()); | |
494 helper.addRootObject(root); | |
495 EXPECT_EQ(sizeof(InstrumentedTemplate<String>) + sizeof(StringImpl), hel
per.reportedSizeForAllTypes()); | |
496 // FIXME: it is failing on Chromium Canary bots but works fine locally. | |
497 // EXPECT_EQ(2, helper.visitedObjects()); | |
498 } | |
499 { | |
500 InstrumentationTestHelper helper; | |
501 | |
502 OwnPtr<InstrumentedTemplate<NotInstrumented> > value(adoptPtr(new Instru
mentedTemplate<NotInstrumented>(""))); | |
503 InstrumentedOwner<InstrumentedTemplate<NotInstrumented>* > root(value.ge
t()); | |
504 helper.addRootObject(root); | |
505 EXPECT_EQ(sizeof(InstrumentedTemplate<NotInstrumented>), helper.reported
SizeForAllTypes()); | |
506 EXPECT_EQ(1u, helper.visitedObjects()); | |
507 } | |
508 } | |
509 | |
510 TEST(MemoryInstrumentationTest, vectorZeroInlineCapacity) | |
511 { | |
512 InstrumentationTestHelper helper; | |
513 InstrumentedOwner<Vector<int> > vectorOwner(16); | |
514 helper.addRootObject(vectorOwner); | |
515 EXPECT_EQ(16 * sizeof(int), helper.reportedSizeForAllTypes()); | |
516 EXPECT_EQ(1u, helper.visitedObjects()); | |
517 } | |
518 | |
519 TEST(MemoryInstrumentationTest, vectorFieldWithInlineCapacity) | |
520 { | |
521 InstrumentationTestHelper helper; | |
522 InstrumentedOwner<Vector<int, 4> > vectorOwner; | |
523 helper.addRootObject(vectorOwner); | |
524 EXPECT_EQ(static_cast<size_t>(0), helper.reportedSizeForAllTypes()); | |
525 EXPECT_EQ(0u, helper.visitedObjects()); | |
526 } | |
527 | |
528 TEST(MemoryInstrumentationTest, vectorFieldWithInlineCapacityResized) | |
529 { | |
530 InstrumentationTestHelper helper; | |
531 InstrumentedOwner<Vector<int, 4> > vectorOwner; | |
532 vectorOwner.m_value.reserveCapacity(8); | |
533 helper.addRootObject(vectorOwner); | |
534 EXPECT_EQ(8u * sizeof(int), helper.reportedSizeForAllTypes()); | |
535 EXPECT_EQ(1u, helper.visitedObjects()); | |
536 } | |
537 | |
538 TEST(MemoryInstrumentationTest, heapAllocatedVectorWithInlineCapacity) | |
539 { | |
540 InstrumentationTestHelper helper; | |
541 InstrumentedOwner<OwnPtr<Vector<int, 4> > > vectorOwner; | |
542 vectorOwner.m_value = adoptPtr(new Vector<int, 4>()); | |
543 helper.addRootObject(vectorOwner); | |
544 EXPECT_EQ(sizeof(Vector<int, 4>), helper.reportedSizeForAllTypes()); | |
545 EXPECT_EQ(1u, helper.visitedObjects()); | |
546 } | |
547 | |
548 TEST(MemoryInstrumentationTest, heapAllocatedVectorWithInlineCapacityResized) | |
549 { | |
550 InstrumentationTestHelper helper; | |
551 InstrumentedOwner<OwnPtr<Vector<int, 4> > > vectorOwner; | |
552 vectorOwner.m_value = adoptPtr(new Vector<int, 4>()); | |
553 vectorOwner.m_value->reserveCapacity(8); | |
554 helper.addRootObject(vectorOwner); | |
555 EXPECT_EQ(8u * sizeof(int) + sizeof(Vector<int, 4>), helper.reportedSizeForA
llTypes()); | |
556 EXPECT_EQ(2u, helper.visitedObjects()); | |
557 } | |
558 | |
559 TEST(MemoryInstrumentationTest, vectorWithInstrumentedType) | |
560 { | |
561 InstrumentationTestHelper helper; | |
562 | |
563 typedef Vector<String> StringVector; | |
564 OwnPtr<StringVector> value = adoptPtr(new StringVector()); | |
565 size_t count = 10; | |
566 for (size_t i = 0; i < count; ++i) | |
567 value->append("string"); | |
568 InstrumentedOwner<StringVector* > root(value.get()); | |
569 helper.addRootObject(root); | |
570 EXPECT_EQ(sizeof(StringVector) + sizeof(String) * value->capacity() + (sizeo
f(StringImpl) + 6) * value->size(), helper.reportedSizeForAllTypes()); | |
571 EXPECT_EQ(count + 2, (size_t)helper.visitedObjects()); | |
572 } | |
573 | |
574 TEST(MemoryInstrumentationTest, hashSetWithInstrumentedType) | |
575 { | |
576 InstrumentationTestHelper helper; | |
577 | |
578 typedef HashSet<String> ValueType; | |
579 OwnPtr<ValueType> value = adoptPtr(new ValueType()); | |
580 size_t count = 10; | |
581 for (size_t i = 0; i < count; ++i) | |
582 value->add(String::number(i)); | |
583 InstrumentedOwner<ValueType* > root(value.get()); | |
584 helper.addRootObject(root); | |
585 EXPECT_EQ(sizeof(ValueType) + sizeof(String) * value->capacity() + (sizeof(S
tringImpl) + 1) * value->size(), helper.reportedSizeForAllTypes()); | |
586 EXPECT_EQ(count + 1, (size_t)helper.visitedObjects()); | |
587 } | |
588 | |
589 TEST(MemoryInstrumentationTest, hashMapWithNotInstrumentedKeysAndValues) | |
590 { | |
591 InstrumentationTestHelper helper; | |
592 | |
593 typedef HashMap<int, int> IntToIntMap; | |
594 OwnPtr<IntToIntMap> value = adoptPtr(new IntToIntMap()); | |
595 size_t count = 10; | |
596 for (size_t i = 1; i <= count; ++i) | |
597 value->set(i, i); | |
598 InstrumentedOwner<IntToIntMap* > root(value.get()); | |
599 helper.addRootObject(root); | |
600 EXPECT_EQ(sizeof(IntToIntMap) + sizeof(IntToIntMap::ValueType) * value->capa
city(), helper.reportedSizeForAllTypes()); | |
601 EXPECT_EQ(1u, helper.visitedObjects()); | |
602 } | |
603 | |
604 TEST(MemoryInstrumentationTest, hashMapWithInstrumentedKeys) | |
605 { | |
606 InstrumentationTestHelper helper; | |
607 | |
608 typedef HashMap<String, int> StringToIntMap; | |
609 OwnPtr<StringToIntMap> value = adoptPtr(new StringToIntMap()); | |
610 size_t count = 10; | |
611 for (size_t i = 10; i < 10 + count; ++i) | |
612 value->set(String::number(i), i); | |
613 InstrumentedOwner<StringToIntMap* > root(value.get()); | |
614 helper.addRootObject(root); | |
615 EXPECT_EQ(sizeof(StringToIntMap) + sizeof(StringToIntMap::ValueType) * value
->capacity() + (sizeof(StringImpl) + 2) * value->size(), helper.reportedSizeForA
llTypes()); | |
616 EXPECT_EQ(count + 1, helper.visitedObjects()); | |
617 } | |
618 | |
619 TEST(MemoryInstrumentationTest, hashMapWithInstrumentedValues) | |
620 { | |
621 InstrumentationTestHelper helper; | |
622 | |
623 typedef HashMap<int, String> IntToStringMap; | |
624 OwnPtr<IntToStringMap> value = adoptPtr(new IntToStringMap()); | |
625 size_t count = 10; | |
626 for (size_t i = 10; i < 10 + count; ++i) | |
627 value->set(i, String::number(i)); | |
628 InstrumentedOwner<IntToStringMap* > root(value.get()); | |
629 helper.addRootObject(root); | |
630 EXPECT_EQ(sizeof(IntToStringMap) + sizeof(IntToStringMap::ValueType) * value
->capacity() + (sizeof(StringImpl) + 2) * value->size(), helper.reportedSizeForA
llTypes()); | |
631 EXPECT_EQ(count + 1, helper.visitedObjects()); | |
632 } | |
633 | |
634 TEST(MemoryInstrumentationTest, hashMapWithInstrumentedKeysAndValues) | |
635 { | |
636 InstrumentationTestHelper helper; | |
637 | |
638 typedef HashMap<String, String> StringToStringMap; | |
639 OwnPtr<StringToStringMap> value = adoptPtr(new StringToStringMap()); | |
640 size_t count = 10; | |
641 for (size_t i = 10; i < 10 + count; ++i) | |
642 value->set(String::number(count + i), String::number(i)); | |
643 InstrumentedOwner<StringToStringMap* > root(value.get()); | |
644 helper.addRootObject(root); | |
645 EXPECT_EQ(sizeof(StringToStringMap) + sizeof(StringToStringMap::ValueType) *
value->capacity() + 2 * (sizeof(StringImpl) + 2) * value->size(), helper.report
edSizeForAllTypes()); | |
646 EXPECT_EQ(2u * count + 1, helper.visitedObjects()); | |
647 } | |
648 | |
649 class InstrumentedRefCounted : public RefCounted<InstrumentedRefCounted> { | |
650 public: | |
651 InstrumentedRefCounted() : m_notInstrumented(new NotInstrumented) { } | |
652 ~InstrumentedRefCounted() { delete m_notInstrumented; } | |
653 | |
654 void reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const | |
655 { | |
656 MemoryClassInfo info(memoryObjectInfo, this, TestType); | |
657 info.addMember(m_notInstrumented, "m_notInstrumented", WTF::RetainingPoi
nter); | |
658 } | |
659 private: | |
660 NotInstrumented* m_notInstrumented; | |
661 }; | |
662 | |
663 TEST(MemoryInstrumentationTest, hashMapWithInstrumentedPointerKeysAndPointerValu
es) | |
664 { | |
665 InstrumentationTestHelper helper; | |
666 | |
667 typedef HashMap<RefPtr<InstrumentedRefCounted>, RefPtr<InstrumentedRefCounte
d> > InstrumentedToInstrumentedMap; | |
668 OwnPtr<InstrumentedToInstrumentedMap> value(adoptPtr(new InstrumentedToInstr
umentedMap())); | |
669 size_t count = 10; | |
670 for (size_t i = 0; i < count; ++i) | |
671 value->set(adoptRef(new InstrumentedRefCounted()), adoptRef(new Instrume
ntedRefCounted())); | |
672 InstrumentedOwner<InstrumentedToInstrumentedMap* > root(value.get()); | |
673 helper.addRootObject(root); | |
674 EXPECT_EQ(sizeof(InstrumentedToInstrumentedMap) | |
675 + sizeof(InstrumentedToInstrumentedMap::ValueType) * value->capacity() | |
676 + 2 * (sizeof(InstrumentedRefCounted) + sizeof(NotInstrumented)) * value
->size(), | |
677 helper.reportedSizeForAllTypes()); | |
678 EXPECT_EQ(2u * 2u * count + 1, helper.visitedObjects()); | |
679 } | |
680 | |
681 TEST(MemoryInstrumentationTest, listHashSetWithInstrumentedType) | |
682 { | |
683 InstrumentationTestHelper helper; | |
684 | |
685 typedef ListHashSet<String, 8> TestSet; | |
686 OwnPtr<TestSet> value = adoptPtr(new TestSet()); | |
687 size_t count = 10; | |
688 for (size_t i = 0; i < count; ++i) | |
689 value->add(String::number(i)); | |
690 InstrumentedOwner<TestSet* > root(value.get()); | |
691 helper.addRootObject(root); | |
692 EXPECT_EQ(sizeof(TestSet) + sizeof(String) * value->capacity() + (sizeof(Str
ingImpl) + 1 * sizeof(LChar)) * count + | |
693 sizeof(WTF::ListHashSetNodeAllocator<String, 8>) + sizeof(WTF::ListHashS
etNode<String, 8>) * (count - 8), | |
694 helper.reportedSizeForAllTypes()); | |
695 EXPECT_EQ(1 + count, helper.visitedObjects()); | |
696 } | |
697 | |
698 TEST(MemoryInstrumentationTest, listHashSetWithInstrumentedTypeAfterValuesRemova
l) | |
699 { | |
700 InstrumentationTestHelper helper; | |
701 | |
702 typedef ListHashSet<String, 8> TestSet; | |
703 OwnPtr<TestSet> value = adoptPtr(new TestSet()); | |
704 size_t count = 20; | |
705 for (size_t i = 0; i < count; ++i) | |
706 value->add(String::number(i)); | |
707 // Remove 10 values, 8 of which were allocated in the internal buffer. | |
708 for (size_t i = 0; i < 10; ++i) | |
709 value->remove(String::number(i)); | |
710 InstrumentedOwner<TestSet* > root(value.get()); | |
711 helper.addRootObject(root); | |
712 EXPECT_EQ(sizeof(TestSet) + sizeof(String) * value->capacity() + (sizeof(Str
ingImpl) + 2 * sizeof(LChar)) * (count - 10) + | |
713 sizeof(WTF::ListHashSetNodeAllocator<String, 8>) + sizeof(WTF::ListHashS
etNode<String, 8>) * (count - 10), | |
714 helper.reportedSizeForAllTypes()); | |
715 EXPECT_EQ(1 + (count - 10), helper.visitedObjects()); | |
716 } | |
717 | |
718 class InstrumentedConvertibleToInt : public RefCounted<InstrumentedConvertibleTo
Int> { | |
719 public: | |
720 InstrumentedConvertibleToInt() : m_notInstrumented(new NotInstrumented) { } | |
721 virtual ~InstrumentedConvertibleToInt() { delete m_notInstrumented; } | |
722 | |
723 virtual void reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const | |
724 { | |
725 MemoryClassInfo info(memoryObjectInfo, this, TestType); | |
726 info.addMember(m_notInstrumented); | |
727 } | |
728 | |
729 operator int() const { return 2012; } | |
730 | |
731 NotInstrumented* m_notInstrumented; | |
732 }; | |
733 | |
734 // This test checks if reportMemoryUsage method will be called on a class | |
735 // that can be implicitly cast to int. Currently objects of such classes are | |
736 // treated as integers when they are stored in a HashMap by value and | |
737 // reportMemoryUsage will not be called on them. We may fix that later. | |
738 TEST(MemoryInstrumentationTest, hashMapWithValuesConvertibleToInt) | |
739 { | |
740 InstrumentationTestHelper helper; | |
741 | |
742 typedef HashMap<RefPtr<InstrumentedConvertibleToInt>, int> TestMap; | |
743 OwnPtr<TestMap> value(adoptPtr(new TestMap())); | |
744 size_t count = 10; | |
745 for (size_t i = 0; i < count; ++i) | |
746 value->set(adoptRef(new InstrumentedConvertibleToInt()), 0); | |
747 InstrumentedOwner<TestMap* > root(value.get()); | |
748 helper.addRootObject(root); | |
749 EXPECT_EQ(sizeof(TestMap) + sizeof(TestMap::ValueType) * value->capacity() + | |
750 sizeof(InstrumentedConvertibleToInt) * count /* + sizeof(NotInstrumented
) * count */, helper.reportedSizeForAllTypes()); | |
751 EXPECT_EQ(count + 1, helper.visitedObjects()); | |
752 } | |
753 | |
754 TEST(MemoryInstrumentationTest, hashMapWithEnumKeysAndInstrumentedValues) | |
755 { | |
756 InstrumentationTestHelper helper; | |
757 | |
758 typedef HashMap<TestEnum, String> EnumToStringMap; | |
759 OwnPtr<EnumToStringMap> value(adoptPtr(new EnumToStringMap())); | |
760 size_t count = MY_ENUM_MAX; | |
761 for (size_t i = ONE; i <= count; ++i) | |
762 value->set(static_cast<TestEnum>(i), String::number(i)); | |
763 InstrumentedOwner<EnumToStringMap* > root(value.get()); | |
764 helper.addRootObject(root); | |
765 EXPECT_EQ(sizeof(EnumToStringMap) | |
766 + sizeof(EnumToStringMap::ValueType) * value->capacity() | |
767 + (sizeof(StringImpl) + 1) * value->size(), | |
768 helper.reportedSizeForAllTypes()); | |
769 EXPECT_EQ(count + 1, helper.visitedObjects()); | |
770 } | |
771 | |
772 TEST(MemoryInstrumentationTest, hashCountedSetWithInstrumentedValues) | |
773 { | |
774 InstrumentationTestHelper helper; | |
775 | |
776 typedef HashCountedSet<RefPtr<InstrumentedRefCounted> > TestSet; | |
777 OwnPtr<TestSet> set(adoptPtr(new TestSet())); | |
778 size_t count = 10; | |
779 for (size_t i = 0; i < count; ++i) { | |
780 RefPtr<InstrumentedRefCounted> instrumentedRefCounted = adoptRef(new Ins
trumentedRefCounted()); | |
781 for (size_t j = 0; j <= i; j++) | |
782 set->add(instrumentedRefCounted); | |
783 } | |
784 InstrumentedOwner<TestSet* > root(set.get()); | |
785 helper.addRootObject(root); | |
786 EXPECT_EQ(sizeof(TestSet) | |
787 + sizeof(HashMap<RefPtr<InstrumentedRefCounted>, unsigned>::ValueType) *
set->capacity() | |
788 + (sizeof(InstrumentedRefCounted) + sizeof(NotInstrumented)) * set->siz
e(), | |
789 helper.reportedSizeForAllTypes()); | |
790 EXPECT_EQ(2u * count + 1, helper.visitedObjects()); | |
791 } | |
792 | |
793 TEST(MemoryInstrumentationTest, arrayBuffer) | |
794 { | |
795 InstrumentationTestHelper helper; | |
796 | |
797 typedef InstrumentedTemplate<RefPtr<ArrayBuffer> > ValueType; | |
798 ValueType value(ArrayBuffer::create(1000, sizeof(int))); | |
799 helper.addRootObject(value); | |
800 EXPECT_EQ(sizeof(int) * 1000 + sizeof(ArrayBuffer), helper.reportedSizeForAl
lTypes()); | |
801 EXPECT_EQ(2u, helper.visitedObjects()); | |
802 EXPECT_EQ(2u, helper.linksCount(WTF::RetainingPointer)); | |
803 } | |
804 | |
805 class AncestorWithVirtualMethod { | |
806 public: | |
807 virtual char* data() { return m_data; } | |
808 | |
809 private: | |
810 char m_data[10]; | |
811 }; | |
812 | |
813 class ClassWithTwoAncestors : public AncestorWithVirtualMethod, public Instrumen
ted { | |
814 public: | |
815 virtual void reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const | |
816 { | |
817 MemoryClassInfo info(memoryObjectInfo, this, TestType); | |
818 Instrumented::reportMemoryUsage(memoryObjectInfo); | |
819 } | |
820 }; | |
821 | |
822 TEST(MemoryInstrumentationTest, instrumentedWithMultipleAncestors) | |
823 { | |
824 InstrumentationTestHelper helper; | |
825 OwnPtr<ClassWithTwoAncestors> instance = adoptPtr(new ClassWithTwoAncestors(
)); | |
826 ClassWithTwoAncestors* descendantPointer = instance.get(); | |
827 InstrumentedOwner<ClassWithTwoAncestors*> descendantPointerOwner(descendantP
ointer); | |
828 Instrumented* ancestorPointer = descendantPointer; | |
829 InstrumentedOwner<Instrumented*> ancestorPointerOwner(ancestorPointer); | |
830 EXPECT_NE(static_cast<void*>(ancestorPointer), static_cast<void*>(descendant
Pointer)); | |
831 | |
832 helper.addRootObject(descendantPointerOwner); | |
833 helper.addRootObject(ancestorPointerOwner); | |
834 EXPECT_EQ(sizeof(ClassWithTwoAncestors) + sizeof(NotInstrumented), helper.re
portedSizeForAllTypes()); | |
835 EXPECT_EQ(3u, helper.visitedObjects()); | |
836 } | |
837 | |
838 class CheckCountedObjectsClient : public MemoryInstrumentationTestClient { | |
839 public: | |
840 CheckCountedObjectsClient(const void* expectedPointer) : m_expectedPointer(e
xpectedPointer), m_expectedPointerFound(false) { } | |
841 virtual bool checkCountedObject(const void* pointer) | |
842 { | |
843 EXPECT_EQ(pointer, m_expectedPointer); | |
844 m_expectedPointerFound = true; | |
845 return true; | |
846 } | |
847 bool expectedPointerFound() { return m_expectedPointerFound; } | |
848 | |
849 private: | |
850 const void* m_expectedPointer; | |
851 bool m_expectedPointerFound; | |
852 }; | |
853 | |
854 TEST(MemoryInstrumentationTest, checkCountedObjectWithMultipleAncestors) | |
855 { | |
856 OwnPtr<ClassWithTwoAncestors> instance = adoptPtr(new ClassWithTwoAncestors(
)); | |
857 instance->disposeOwnedObject(); | |
858 ClassWithTwoAncestors* descendantPointer = instance.get(); | |
859 InstrumentedOwner<ClassWithTwoAncestors*> descendantPointerOwner(descendantP
ointer); | |
860 Instrumented* ancestorPointer = descendantPointer; | |
861 InstrumentedOwner<Instrumented*> ancestorPointerOwner(ancestorPointer); | |
862 EXPECT_NE(static_cast<void*>(ancestorPointer), static_cast<void*>(descendant
Pointer)); | |
863 | |
864 CheckCountedObjectsClient client(instance.get()); | |
865 InstrumentationTestImpl instrumentation(&client); | |
866 instrumentation.addRootObject(descendantPointerOwner); | |
867 instrumentation.addRootObject(ancestorPointerOwner); | |
868 EXPECT_TRUE(client.expectedPointerFound()); | |
869 } | |
870 | |
871 class TwoPointersToSameInsrumented { | |
872 public: | |
873 TwoPointersToSameInsrumented() | |
874 : m_ownPtr(adoptPtr(new ClassWithTwoAncestors())) | |
875 , m_baseClassPtr(m_ownPtr.get()) | |
876 { | |
877 EXPECT_NE(static_cast<void*>(m_ownPtr.get()), static_cast<void*>(m_baseC
lassPtr)); | |
878 } | |
879 void reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const | |
880 { | |
881 MemoryClassInfo info(memoryObjectInfo, this, TestType); | |
882 info.addMember(m_ownPtr); | |
883 info.addMember(m_baseClassPtr); | |
884 } | |
885 | |
886 private: | |
887 OwnPtr<ClassWithTwoAncestors> m_ownPtr; | |
888 Instrumented* m_baseClassPtr; | |
889 }; | |
890 | |
891 class CountLinksFromInstrumentedObject : public MemoryInstrumentationTestClient
{ | |
892 public: | |
893 CountLinksFromInstrumentedObject() : m_linkCount(0) { } | |
894 virtual void reportEdge(const void*, const char* name, MemberType) OVERRIDE | |
895 { | |
896 if (name && !strcmp("m_notInstrumented", name)) | |
897 m_linkCount++; | |
898 } | |
899 int linkCount() const { return m_linkCount; } | |
900 | |
901 private: | |
902 int m_linkCount; | |
903 }; | |
904 | |
905 | |
906 TEST(MemoryInstrumentationTest, doNotReportEdgeTwice) | |
907 { | |
908 OwnPtr<TwoPointersToSameInsrumented> instance = adoptPtr(new TwoPointersToSa
meInsrumented()); | |
909 | |
910 CountLinksFromInstrumentedObject client; | |
911 InstrumentationTestImpl instrumentation(&client); | |
912 instrumentation.addRootObject(instance.get()); | |
913 EXPECT_EQ(1, client.linkCount()); | |
914 } | |
915 | |
916 class DerivedClass : public Instrumented { | |
917 public: | |
918 size_t m_member; | |
919 }; | |
920 | |
921 TEST(MemoryInstrumentationTest, detectBaseClassInstrumentation) | |
922 { | |
923 OwnPtr<DerivedClass> instance = adoptPtr(new DerivedClass()); | |
924 | |
925 InstrumentationTestHelper helper; | |
926 helper.addRootObject(instance.get(), TestType); | |
927 EXPECT_EQ(sizeof(Instrumented) + sizeof(NotInstrumented), helper.reportedSiz
eForAllTypes()); | |
928 EXPECT_EQ(2u, helper.visitedObjects()); | |
929 } | |
930 | |
931 } // namespace | |
OLD | NEW |