this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include "heap-profiler.h"
3
4#include "gtest/gtest.h"
5
6#include "dict-builtins.h"
7#include "object-builtins.h"
8#include "test-utils.h"
9
10namespace py {
11namespace testing {
12
13using HeapProfilerTest = RuntimeFixture;
14using HeapProfilerDeathTest = RuntimeFixture;
15
16TEST_F(HeapProfilerTest, ConstructorCreatesEmptyBuffer) {
17 HeapProfiler::Buffer buffer;
18 EXPECT_EQ(buffer.size(), 0);
19 EXPECT_EQ(buffer.data(), nullptr);
20}
21
22TEST_F(HeapProfilerTest, WriteWithEmptyBufferAllocatesSpace) {
23 HeapProfiler::Buffer buffer;
24 byte buf[] = {0, 1, 2, 3};
25 buffer.write(buf, 4);
26 EXPECT_NE(buffer.data(), nullptr);
27 EXPECT_EQ(buffer.size(), 4);
28 EXPECT_EQ(std::memcmp(buffer.data(), buf, 4), 0);
29}
30
31static void testWriter(const void* data, word size, void* stream) {
32 Vector<byte>* result = reinterpret_cast<Vector<byte>*>(stream);
33 for (word i = 0; i < size; i++) {
34 result->push_back(reinterpret_cast<const byte*>(data)[i]);
35 }
36}
37
38static uint8_t read8(const Vector<byte>& src, word* pos) {
39 EXPECT_LT(*pos, src.size());
40 return src[(*pos)++];
41}
42
43static int16_t read16(const Vector<byte>& src, word* pos) {
44 EXPECT_LT(*pos + 1, src.size());
45 uint16_t result = src[(*pos)++];
46 result <<= 8;
47 result |= src[(*pos)++];
48 return result;
49}
50
51static int32_t read32(const Vector<byte>& src, word* pos) {
52 EXPECT_LT(*pos + 3, src.size());
53 int32_t result = src[(*pos)++];
54 result <<= 8;
55 result |= src[(*pos)++];
56 result <<= 8;
57 result |= src[(*pos)++];
58 result <<= 8;
59 result |= src[(*pos)++];
60 return result;
61}
62
63static uint32_t readu32(const Vector<byte>& src, word* pos) {
64 return read32(src, pos);
65}
66
67static int64_t read64(const Vector<byte>& src, word* pos) {
68 EXPECT_LT(*pos + 7, src.size());
69 int64_t result = src[(*pos)++];
70 result <<= 8;
71 result |= src[(*pos)++];
72 result <<= 8;
73 result |= src[(*pos)++];
74 result <<= 8;
75 result |= src[(*pos)++];
76 result <<= 8;
77 result |= src[(*pos)++];
78 result <<= 8;
79 result |= src[(*pos)++];
80 result <<= 8;
81 result |= src[(*pos)++];
82 result <<= 8;
83 result |= src[(*pos)++];
84 return result;
85}
86
87static uint64_t readu64(const Vector<byte>& data, word* pos) {
88 return read64(data, pos);
89}
90
91TEST_F(HeapProfilerTest, WriteCallsWriteCallback) {
92 Vector<byte> result;
93 HeapProfiler profiler(thread_, testWriter, &result);
94 byte buf[] = {0, 1, 2, 3};
95 profiler.write(buf, 4);
96 word pos = 0;
97 EXPECT_EQ(read8(result, &pos), 0);
98 EXPECT_EQ(read8(result, &pos), 1);
99 EXPECT_EQ(read8(result, &pos), 2);
100 EXPECT_EQ(read8(result, &pos), 3);
101 EXPECT_EQ(pos, result.size());
102}
103
104static const char* tagStr(byte tag) {
105 switch (tag) {
106 case HeapProfiler::Tag::kStringInUtf8:
107 return "STRING IN UTF8";
108 case HeapProfiler::Tag::kLoadClass:
109 return "LOAD CLASS";
110 case HeapProfiler::Tag::kStackTrace:
111 return "STACK TRACE";
112 case HeapProfiler::Tag::kHeapDumpSegment:
113 return "HEAP DUMP SEGMENT";
114 case HeapProfiler::Tag::kHeapDumpEnd:
115 return "HEAP DUMP END";
116 default:
117 return "<UNKNOWN>";
118 }
119}
120
121static ::testing::AssertionResult readTag(const Vector<byte>& result, word* pos,
122 HeapProfiler::Tag expected) {
123 EXPECT_LT(*pos, result.size());
124 byte tag = result[(*pos)++];
125 if (tag != expected) {
126 return ::testing::AssertionFailure()
127 << "expected " << tagStr(expected) << " but found " << tagStr(tag)
128 << " (" << tag << ")";
129 }
130 return ::testing::AssertionSuccess();
131}
132
133static ::testing::AssertionResult readStringLiteral(const Vector<byte>& result,
134 word* pos,
135 const char* c_str) {
136 for (word char_idx = 0; *c_str != '\0'; (*pos)++, char_idx++, c_str++) {
137 if (*pos >= result.size()) {
138 return ::testing::AssertionFailure()
139 << "output (length " << result.size()
140 << ") not long enough to read c_str '" << c_str << "'";
141 }
142 char c = result[*pos];
143 if (c != *c_str) {
144 return ::testing::AssertionFailure()
145 << "char " << char_idx << " ('" << c
146 << "') differs from expected ('" << *c_str << "')";
147 }
148 }
149 return ::testing::AssertionSuccess();
150}
151
152static ::testing::AssertionResult readStringInUtf8(const Vector<byte>& result,
153 word* pos, uword address,
154 const char* value) {
155 EXPECT_TRUE(readTag(result, pos, HeapProfiler::kStringInUtf8));
156 EXPECT_EQ(read32(result, pos), 0);
157 EXPECT_EQ(readu32(result, pos), std::strlen(value) + kPointerSize);
158 EXPECT_EQ(readu64(result, pos), address);
159 EXPECT_TRUE(readStringLiteral(result, pos, value));
160 return ::testing::AssertionSuccess();
161}
162
163TEST_F(HeapProfilerTest, StringIdWritesStringInUTF8Once) {
164 Vector<byte> result;
165 HeapProfiler profiler(thread_, testWriter, &result);
166 RawStr str = Str::cast(SmallStr::fromCStr("foo"));
167 EXPECT_EQ(profiler.stringId(str), str.raw());
168
169 word pos = 0;
170 EXPECT_TRUE(readStringInUtf8(result, &pos, str.raw(), "foo"));
171 EXPECT_EQ(pos, result.size());
172
173 // Size shouldn't change
174 EXPECT_EQ(profiler.stringId(str), str.raw());
175 EXPECT_EQ(pos, result.size());
176}
177
178static ::testing::AssertionResult readLoadClass(const Vector<byte>& result,
179 word* pos, uword id,
180 uword name_id) {
181 EXPECT_TRUE(readTag(result, pos, HeapProfiler::kLoadClass));
182 EXPECT_EQ(read32(result, pos), 0); // time
183 EXPECT_EQ(read32(result, pos), 24); // data length
184 EXPECT_EQ(read32(result, pos), 1); // class serial number
185 EXPECT_EQ(readu64(result, pos), id); // class object ID
186 EXPECT_EQ(read32(result, pos), 0); // stack trace serial number
187 EXPECT_EQ(readu64(result, pos), name_id); // class name string ID
188 return ::testing::AssertionSuccess();
189}
190
191TEST_F(HeapProfilerTest, ClassIdWritesLoadClassOnce) {
192 Vector<byte> result;
193 HeapProfiler profiler(thread_, testWriter, &result);
194 RawLayout layout = Layout::cast(runtime_->layoutAt(LayoutId::kTuple));
195 EXPECT_EQ(profiler.classId(layout), layout.raw());
196
197 word pos = 0;
198 uword tuple_address = runtime_->symbols()->at(ID(tuple)).raw();
199 EXPECT_TRUE(readStringInUtf8(result, &pos, tuple_address, "tuple"));
200 EXPECT_TRUE(readLoadClass(result, &pos, layout.raw(), tuple_address));
201 EXPECT_EQ(pos, result.size());
202
203 // Size shouldn't change
204 EXPECT_EQ(profiler.classId(layout), layout.raw());
205 EXPECT_EQ(pos, result.size());
206}
207
208TEST_F(HeapProfilerTest, WriteStringInUTF8WithLargeStrWritesStringRecord) {
209 Vector<byte> result;
210 HeapProfiler profiler(thread_, testWriter, &result);
211 HandleScope scope(thread_);
212 Str str(&scope, runtime_->newStrFromCStr("deadbeef"));
213 profiler.writeStringInUTF8(*str);
214 word pos = 0;
215 EXPECT_TRUE(readStringInUtf8(result, &pos, str.raw(), "deadbeef"));
216
217 EXPECT_EQ(pos, result.size());
218}
219
220TEST_F(HeapProfilerTest, WriteCStringInUTF8WritesStringRecord) {
221 Vector<byte> result;
222 HeapProfiler profiler(thread_, testWriter, &result);
223 const char* str = "deadbeef";
224 profiler.writeCStringInUTF8(str);
225 word pos = 0;
226 EXPECT_TRUE(
227 readStringInUtf8(result, &pos, reinterpret_cast<uword>(str), str));
228
229 EXPECT_EQ(pos, result.size());
230}
231
232TEST_F(HeapProfilerTest, WriteEmptyRecordWritesRecord) {
233 Vector<byte> result;
234 HeapProfiler profiler(thread_, testWriter, &result);
235 {
236 HeapProfiler::Record record(static_cast<HeapProfiler::Tag>(10), &profiler);
237 }
238 word pos = 0;
239 EXPECT_EQ(read8(result, &pos), 0xa); // tag
240 EXPECT_EQ(read32(result, &pos), 0); // time
241 EXPECT_EQ(read32(result, &pos), 0); // length
242
243 EXPECT_EQ(pos, result.size());
244}
245
246TEST_F(HeapProfilerTest, WriteFakeStackTraceWritesStackTrace) {
247 Vector<byte> result;
248 HeapProfiler profiler(thread_, testWriter, &result);
249 profiler.writeFakeStackTrace();
250 word pos = 0;
251 EXPECT_TRUE(readTag(result, &pos, HeapProfiler::kStackTrace));
252 EXPECT_EQ(read32(result, &pos), 0); // time
253 EXPECT_EQ(read32(result, &pos), 12); // data length
254 EXPECT_EQ(read32(result, &pos), 0); // stack trace serial number
255 EXPECT_EQ(read32(result, &pos), 0); // thread serial number
256 EXPECT_EQ(read32(result, &pos), 0); // number of frames
257
258 EXPECT_EQ(pos, result.size());
259}
260
261TEST_F(HeapProfilerTest, WriteLoadClassWritesLoadClassRecord) {
262 Vector<byte> result;
263 HeapProfiler profiler(thread_, testWriter, &result);
264 RawLayout layout = Layout::cast(runtime_->layoutAt(LayoutId::kTuple));
265 profiler.writeLoadClass(layout);
266 word pos = 0;
267 uword tuple_address = runtime_->symbols()->at(ID(tuple)).raw();
268 EXPECT_TRUE(readStringInUtf8(result, &pos, tuple_address, "tuple"));
269 EXPECT_TRUE(readLoadClass(result, &pos, layout.raw(), tuple_address));
270
271 EXPECT_EQ(pos, result.size());
272}
273
274static const char* subtagStr(byte subtag) {
275 switch (subtag) {
276 case HeapProfiler::Subtag::kRootJniGlobal:
277 return "ROOT JNI GLOBAL";
278 case HeapProfiler::Subtag::kRootJniLocal:
279 return "ROOT JNI LOCAL";
280 case HeapProfiler::Subtag::kRootJavaFrame:
281 return "ROOT JAVA FRAME";
282 case HeapProfiler::Subtag::kRootNativeStack:
283 return "ROOT NATIVE STACK";
284 case HeapProfiler::Subtag::kRootStickyClass:
285 return "ROOT STICKY CLASS";
286 case HeapProfiler::Subtag::kRootThreadBlock:
287 return "ROOT THREAD BLOCK";
288 case HeapProfiler::Subtag::kRootMonitorUsed:
289 return "ROOT MONITOR USED";
290 case HeapProfiler::Subtag::kRootThreadObject:
291 return "ROOT THREAD OBJECT";
292 case HeapProfiler::Subtag::kRootUnknown:
293 return "ROOT UNKNOWN";
294 case HeapProfiler::Subtag::kClassDump:
295 return "CLASS DUMP";
296 case HeapProfiler::Subtag::kInstanceDump:
297 return "INSTANCE DUMP";
298 case HeapProfiler::Subtag::kObjectArrayDump:
299 return "OBJECT ARRAY DUMP";
300 case HeapProfiler::Subtag::kPrimitiveArrayDump:
301 return "PRIMITIVE ARRAY DUMP";
302 default:
303 return "<UNKNOWN>";
304 }
305}
306
307static ::testing::AssertionResult readSubtag(const Vector<byte>& result,
308 word* pos,
309 HeapProfiler::Subtag expected) {
310 EXPECT_LT(*pos, result.size());
311 byte tag = result[(*pos)++];
312 if (tag != expected) {
313 return ::testing::AssertionFailure()
314 << "expected " << subtagStr(expected) << " but found "
315 << subtagStr(tag) << " (" << tag << ")";
316 }
317 return ::testing::AssertionSuccess();
318}
319
320static ::testing::AssertionResult readClassDumpPrelude(
321 const Vector<byte>& result, word* pos, uword layout, uword super_layout) {
322 EXPECT_EQ(readu64(result, pos), layout); // class object ID
323 EXPECT_EQ(read32(result, pos), 0); // stack trace serial number
324 EXPECT_EQ(readu64(result, pos),
325 super_layout); // super class object ID
326 EXPECT_EQ(read64(result, pos), 0); // class loader object ID
327 EXPECT_EQ(read64(result, pos), 0); // signers object ID
328 EXPECT_EQ(read64(result, pos), 0); // protection domain object ID
329 EXPECT_EQ(read64(result, pos), 0); // reserved
330 EXPECT_EQ(read64(result, pos), 0); // reserved
331 return ::testing::AssertionSuccess();
332}
333
334TEST_F(HeapProfilerTest, WriteThreadRootWritesRootThreadSubRecord) {
335 Vector<byte> result;
336 HeapProfiler profiler(thread_, testWriter, &result);
337 {
338 HeapProfiler::Record record(HeapProfiler::kHeapDumpSegment, &profiler);
339 profiler.setRecord(&record);
340 profiler.writeThreadRoot(thread_);
341 profiler.clearRecord();
342 }
343 word pos = 0;
344
345 // Heap dump segment
346 EXPECT_TRUE(readTag(result, &pos, HeapProfiler::kHeapDumpSegment));
347 EXPECT_EQ(read32(result, &pos), 0); // time
348 EXPECT_EQ(read32(result, &pos), 17); // length
349
350 EXPECT_TRUE(readSubtag(result, &pos, HeapProfiler::kRootThreadObject));
351 EXPECT_EQ(readu64(result, &pos),
352 reinterpret_cast<uint64_t>(thread_)); // object id
353 // Thread serial numbers should start from 0. JHAT and probably other tools
354 // expect it.
355 EXPECT_EQ(read32(result, &pos), 0); // thread serial number
356 EXPECT_EQ(read32(result, &pos), 0); // stack trace serial number
357
358 EXPECT_EQ(pos, result.size());
359}
360
361TEST_F(HeapProfilerTest, WriteClassDumpWritesClassDumpSubRecord) {
362 Vector<byte> result;
363 HeapProfiler profiler(thread_, testWriter, &result);
364 RawLayout tuple_layout = Layout::cast(runtime_->layoutAt(LayoutId::kTuple));
365 {
366 HeapProfiler::Record record(HeapProfiler::kHeapDumpSegment, &profiler);
367 profiler.setRecord(&record);
368 profiler.writeClassDump(tuple_layout);
369 profiler.clearRecord();
370 }
371 word pos = 0;
372 // tuple
373 uword tuple_address = runtime_->symbols()->at(ID(tuple)).raw();
374 EXPECT_TRUE(readStringInUtf8(result, &pos, tuple_address, "tuple"));
375 EXPECT_TRUE(readLoadClass(result, &pos, tuple_layout.raw(), tuple_address));
376
377 // object
378 uword object_address = runtime_->symbols()->at(ID(object)).raw();
379 RawLayout object_layout = Layout::cast(runtime_->layoutAt(LayoutId::kObject));
380 EXPECT_TRUE(readStringInUtf8(result, &pos, object_address, "object"));
381 EXPECT_TRUE(readLoadClass(result, &pos, object_layout.raw(), object_address));
382
383 // _UserTuple__value
384 uword user_tuple_value_address =
385 runtime_->symbols()->at(ID(_UserTuple__value)).raw();
386 EXPECT_TRUE(readStringInUtf8(result, &pos, user_tuple_value_address,
387 "_UserTuple__value"));
388
389 // Heap dump segment
390 EXPECT_TRUE(readTag(result, &pos, HeapProfiler::kHeapDumpSegment));
391 EXPECT_EQ(read32(result, &pos), 0); // time
392 EXPECT_EQ(read32(result, &pos), 80); // length
393
394 // Class dump subrecord
395 EXPECT_TRUE(readSubtag(result, &pos, HeapProfiler::Subtag::kClassDump));
396 EXPECT_TRUE(readClassDumpPrelude(result, &pos, tuple_layout.raw(),
397 object_layout.raw()));
398 EXPECT_EQ(read32(result, &pos),
399 tuple_layout.instanceSize()); // instance size in bytes
400 EXPECT_EQ(read16(result, &pos),
401 0); // size of constant pool and number of records that follow
402 EXPECT_EQ(read16(result, &pos), 0); // number of static fields
403 EXPECT_EQ(read16(result, &pos), 1); // number of instance fields
404
405 // TODO(T61661597): Remove _UserTuple__value field from tuple layout
406 // Field 0 (u8 name, u1 type)
407 EXPECT_EQ(readu64(result, &pos), user_tuple_value_address);
408 EXPECT_EQ(read8(result, &pos), HeapProfiler::BasicType::kObject);
409
410 EXPECT_EQ(pos, result.size());
411}
412
413TEST_F(HeapProfilerTest, WriteClassDumpForUserClassWritesClassDumpRecord) {
414 ASSERT_FALSE(runFromCStr(runtime_, R"(
415class C:
416 def __init__(self):
417 self.a = 1
418 self.b = 2
419instance = C()
420)")
421 .isError());
422 HandleScope scope(thread_);
423 Object instance(&scope, mainModuleAt(runtime_, "instance"));
424 Layout c_layout(&scope, runtime_->layoutAt(instance.layoutId()));
425
426 Vector<byte> result;
427 HeapProfiler profiler(thread_, testWriter, &result);
428 {
429 HeapProfiler::Record record(HeapProfiler::kHeapDumpSegment, &profiler);
430 profiler.setRecord(&record);
431 profiler.writeClassDump(*c_layout);
432 profiler.clearRecord();
433 }
434 word pos = 0;
435
436 // C
437 word c_address = SmallStr::fromCStr("C").raw();
438 EXPECT_TRUE(readStringInUtf8(result, &pos, c_address, "C"));
439 EXPECT_TRUE(readLoadClass(result, &pos, c_layout.raw(), c_address));
440
441 // object
442 uword object_address = runtime_->symbols()->at(ID(object)).raw();
443 RawLayout object_layout = Layout::cast(runtime_->layoutAt(LayoutId::kObject));
444 EXPECT_TRUE(readStringInUtf8(result, &pos, object_address, "object"));
445 EXPECT_TRUE(readLoadClass(result, &pos, object_layout.raw(), object_address));
446
447 // a
448 word a_address = SmallStr::fromCStr("a").raw();
449 EXPECT_TRUE(readStringInUtf8(result, &pos, a_address, "a"));
450
451 // b
452 word b_address = SmallStr::fromCStr("b").raw();
453 EXPECT_TRUE(readStringInUtf8(result, &pos, b_address, "b"));
454
455 // <OVERFLOW>
456 EXPECT_TRUE(readStringInUtf8(result, &pos,
457 reinterpret_cast<uword>(HeapProfiler::kOverflow),
458 HeapProfiler::kOverflow));
459
460 // Heap dump segment
461 EXPECT_TRUE(readTag(result, &pos, HeapProfiler::kHeapDumpSegment));
462 EXPECT_EQ(read32(result, &pos), 0); // time
463 EXPECT_EQ(read32(result, &pos), 98); // length
464
465 // Class dump subrecord
466 EXPECT_TRUE(readSubtag(result, &pos, HeapProfiler::Subtag::kClassDump));
467 EXPECT_TRUE(
468 readClassDumpPrelude(result, &pos, c_layout.raw(), object_layout.raw()));
469 EXPECT_EQ(read32(result, &pos),
470 c_layout.instanceSize()); // instance size in bytes
471 EXPECT_EQ(read16(result, &pos),
472 0); // size of constant pool and number of records that follow
473 EXPECT_EQ(read16(result, &pos), 0); // number of static fields
474 EXPECT_EQ(read16(result, &pos), 3); // number of instance fields
475 // * Field 0 (u8 name, u1 type)
476 EXPECT_EQ(read64(result, &pos), a_address);
477 EXPECT_EQ(read8(result, &pos), HeapProfiler::BasicType::kObject);
478 // * Field 1 (u8 name, u1 type)
479 EXPECT_EQ(read64(result, &pos), b_address);
480 EXPECT_EQ(read8(result, &pos), HeapProfiler::BasicType::kObject);
481 // * Field 2 (u8 name, u1 type)
482 EXPECT_EQ(readu64(result, &pos),
483 reinterpret_cast<uword>(HeapProfiler::kOverflow));
484 EXPECT_EQ(read8(result, &pos), HeapProfiler::BasicType::kObject);
485
486 EXPECT_EQ(pos, result.size());
487}
488
489TEST_F(HeapProfilerTest, WriteClassDumpWithOverflowAttributes) {
490 HandleScope scope(thread_);
491 Layout empty(&scope, testing::layoutCreateEmpty(thread_));
492 runtime_->layoutSetTupleOverflow(*empty);
493
494 // Should fail to find an attribute that isn't present
495 Object attr(&scope, Runtime::internStrFromCStr(thread_, "a"));
496 AttributeInfo info;
497 ASSERT_FALSE(Runtime::layoutFindAttribute(*empty, attr, &info));
498
499 // Adding a new attribute should result in a new layout being created
500 AttributeInfo info2;
501 Layout layout(&scope,
502 runtime_->layoutAddAttribute(thread_, empty, attr, 0, &info2));
503 ASSERT_NE(*empty, *layout);
504 EXPECT_TRUE(info2.isOverflow());
505 EXPECT_EQ(info2.offset(), 0);
506
507 Type type(&scope, runtime_->newType());
508 type.setName(SmallStr::fromCStr("C"));
509 type.setInstanceLayout(*layout);
510 type.setInstanceLayoutId(layout.id());
511 layout.setDescribedType(*type);
512
513 Vector<byte> result;
514 HeapProfiler profiler(thread_, testWriter, &result);
515 {
516 HeapProfiler::Record record(HeapProfiler::kHeapDumpSegment, &profiler);
517 profiler.setRecord(&record);
518 profiler.writeClassDump(*layout);
519 profiler.clearRecord();
520 }
521 word pos = 0;
522
523 // C
524 word c_address = SmallStr::fromCStr("C").raw();
525 EXPECT_TRUE(readStringInUtf8(result, &pos, c_address, "C"));
526 EXPECT_TRUE(readLoadClass(result, &pos, layout.raw(), c_address));
527
528 // object
529 uword object_address = runtime_->symbols()->at(ID(object)).raw();
530 RawLayout object_layout = Layout::cast(runtime_->layoutAt(LayoutId::kObject));
531 EXPECT_TRUE(readStringInUtf8(result, &pos, object_address, "object"));
532 EXPECT_TRUE(readLoadClass(result, &pos, object_layout.raw(), object_address));
533
534 // <OVERFLOW>
535 EXPECT_TRUE(readStringInUtf8(result, &pos,
536 reinterpret_cast<uword>(HeapProfiler::kOverflow),
537 HeapProfiler::kOverflow));
538
539 // Heap dump segment
540 EXPECT_TRUE(readTag(result, &pos, HeapProfiler::kHeapDumpSegment));
541 EXPECT_EQ(read32(result, &pos), 0); // time
542 EXPECT_EQ(read32(result, &pos), 80); // length
543
544 // Class dump subrecord
545 EXPECT_TRUE(readSubtag(result, &pos, HeapProfiler::kClassDump));
546 EXPECT_TRUE(
547 readClassDumpPrelude(result, &pos, layout.raw(), object_layout.raw()));
548 EXPECT_EQ(read32(result, &pos),
549 layout.instanceSize()); // instance size in bytes
550 EXPECT_EQ(read16(result, &pos),
551 0); // size of constant pool and number of records that follow
552 EXPECT_EQ(read16(result, &pos), 0); // number of static fields
553 EXPECT_EQ(read16(result, &pos), 1); // number of instance fields
554 // * Field 0 (u8 name, u1 type)
555 EXPECT_EQ(readu64(result, &pos),
556 reinterpret_cast<uword>(HeapProfiler::kOverflow));
557 EXPECT_EQ(read8(result, &pos), HeapProfiler::BasicType::kObject);
558
559 EXPECT_EQ(pos, result.size());
560}
561
562TEST_F(HeapProfilerTest, WriteClassDumpWithDictOverflow) {
563 HandleScope scope(thread_);
564 // Make a new type, C
565 Layout layout(&scope, testing::layoutCreateEmpty(thread_));
566 layout.setDictOverflowOffset(10);
567 EXPECT_TRUE(layout.hasDictOverflow());
568 Type type(&scope, runtime_->newType());
569 type.setName(SmallStr::fromCStr("C"));
570 type.setInstanceLayout(*layout);
571 type.setInstanceLayoutId(layout.id());
572 layout.setDescribedType(*type);
573
574 Vector<byte> result;
575 HeapProfiler profiler(thread_, testWriter, &result);
576 {
577 HeapProfiler::Record record(HeapProfiler::kHeapDumpSegment, &profiler);
578 profiler.setRecord(&record);
579 profiler.writeClassDump(*layout);
580 profiler.clearRecord();
581 }
582 word pos = 0;
583
584 // C
585 word c_address = SmallStr::fromCStr("C").raw();
586 EXPECT_TRUE(readStringInUtf8(result, &pos, c_address, "C"));
587 EXPECT_TRUE(readLoadClass(result, &pos, layout.raw(), c_address));
588
589 // object
590 uword object_address = runtime_->symbols()->at(ID(object)).raw();
591 RawLayout object_layout = Layout::cast(runtime_->layoutAt(LayoutId::kObject));
592 EXPECT_TRUE(readStringInUtf8(result, &pos, object_address, "object"));
593 EXPECT_TRUE(readLoadClass(result, &pos, object_layout.raw(), object_address));
594
595 // Heap dump segment
596 EXPECT_TRUE(readTag(result, &pos, HeapProfiler::kHeapDumpSegment));
597 EXPECT_EQ(read32(result, &pos), 0); // time
598 EXPECT_EQ(read32(result, &pos), 71); // length
599
600 // Class dump subrecord
601 EXPECT_TRUE(readSubtag(result, &pos, HeapProfiler::kClassDump));
602 EXPECT_TRUE(
603 readClassDumpPrelude(result, &pos, layout.raw(), object_layout.raw()));
604 EXPECT_EQ(read32(result, &pos),
605 layout.instanceSize()); // instance size in bytes
606 EXPECT_EQ(read16(result, &pos),
607 0); // size of constant pool and number of records that follow
608 EXPECT_EQ(read16(result, &pos), 0); // number of static fields
609 EXPECT_EQ(read16(result, &pos), 0); // number of instance fields
610
611 EXPECT_EQ(pos, result.size());
612}
613
614TEST_F(HeapProfilerTest, WriteInstanceWithDictOverflow) {
615 HandleScope scope(thread_);
616 // Make a new type, C
617 Layout layout(&scope, testing::layoutCreateEmpty(thread_));
618 layout.setDictOverflowOffset(10);
619 EXPECT_FALSE(layout.hasTupleOverflow());
620 EXPECT_TRUE(layout.hasDictOverflow());
621 Type type(&scope, runtime_->newType());
622 type.setName(SmallStr::fromCStr("C"));
623 type.setInstanceLayout(*layout);
624 type.setInstanceLayoutId(layout.id());
625 layout.setDescribedType(*type);
626
627 // Make an instance with an overflow attribute
628 Instance instance(&scope, runtime_->newInstance(layout));
629
630 Vector<byte> result;
631 HeapProfiler profiler(thread_, testWriter, &result);
632 {
633 HeapProfiler::Record record(HeapProfiler::kHeapDumpSegment, &profiler);
634 profiler.setRecord(&record);
635 profiler.writeInstanceDump(*instance);
636 profiler.clearRecord();
637 }
638 word pos = 0;
639
640 // C
641 word c_address = SmallStr::fromCStr("C").raw();
642 EXPECT_TRUE(readStringInUtf8(result, &pos, c_address, "C"));
643 EXPECT_TRUE(readLoadClass(result, &pos, layout.raw(), c_address));
644
645 // Heap dump segment
646 EXPECT_TRUE(readTag(result, &pos, HeapProfiler::Tag::kHeapDumpSegment));
647 EXPECT_EQ(read32(result, &pos), 0); // time
648 EXPECT_EQ(read32(result, &pos), 25); // length
649
650 // Instance dump subrecord
651 EXPECT_TRUE(readSubtag(result, &pos, HeapProfiler::Subtag::kInstanceDump));
652 EXPECT_EQ(readu64(result, &pos), instance.raw()); // object ID
653 EXPECT_EQ(read32(result, &pos), 0); // stack trace serial number
654 EXPECT_EQ(readu64(result, &pos), layout.raw()); // class object ID
655 EXPECT_EQ(read32(result, &pos), 0); // number of bytes that follow
656
657 EXPECT_EQ(pos, result.size());
658}
659
660TEST_F(HeapProfilerTest, WriteInstanceWithOverflowAttributes) {
661 HandleScope scope(thread_);
662 // Make a new type, C
663 Layout empty(&scope, testing::layoutCreateEmpty(thread_));
664 runtime_->layoutSetTupleOverflow(*empty);
665 Type type(&scope, runtime_->newType());
666 type.setName(SmallStr::fromCStr("C"));
667 type.setInstanceLayout(*empty);
668 type.setInstanceLayoutId(empty.id());
669 empty.setDescribedType(*type);
670
671 // Make an instance with an overflow attribute
672 Instance instance(&scope, runtime_->newInstance(empty));
673 Object name(&scope, Runtime::internStrFromCStr(thread_, "a"));
674 Object value(&scope, SmallInt::fromWord(1234));
675 EXPECT_TRUE(instanceSetAttr(thread_, instance, name, value).isNoneType());
676 Layout layout(&scope, runtime_->layoutOf(*instance));
677 EXPECT_EQ(layout.inObjectAttributes(), runtime_->emptyTuple());
678 EXPECT_TRUE(layout.hasTupleOverflow());
679
680 Vector<byte> result;
681 HeapProfiler profiler(thread_, testWriter, &result);
682 {
683 HeapProfiler::Record record(HeapProfiler::kHeapDumpSegment, &profiler);
684 profiler.setRecord(&record);
685 profiler.writeInstanceDump(*instance);
686 profiler.clearRecord();
687 }
688 word pos = 0;
689
690 // C
691 word c_address = SmallStr::fromCStr("C").raw();
692 EXPECT_TRUE(readStringInUtf8(result, &pos, c_address, "C"));
693 EXPECT_TRUE(readLoadClass(result, &pos, layout.raw(), c_address));
694
695 // Heap dump segment
696 EXPECT_TRUE(readTag(result, &pos, HeapProfiler::Tag::kHeapDumpSegment));
697 EXPECT_EQ(read32(result, &pos), 0); // time
698 EXPECT_EQ(read32(result, &pos), 33); // length
699
700 // Instance dump subrecord
701 EXPECT_TRUE(readSubtag(result, &pos, HeapProfiler::Subtag::kInstanceDump));
702 EXPECT_EQ(readu64(result, &pos), instance.raw()); // object ID
703 EXPECT_EQ(read32(result, &pos), 0); // stack trace serial number
704 EXPECT_EQ(readu64(result, &pos), layout.raw()); // class object ID
705 EXPECT_EQ(read32(result, &pos),
706 kPointerSize); // number of bytes that follow
707 uword overflow_raw = read64(result, &pos);
708 Tuple overflow(&scope, RawObject{overflow_raw});
709 EXPECT_EQ(overflow.at(0), *value);
710
711 EXPECT_EQ(pos, result.size());
712}
713
714TEST_F(HeapProfilerTest,
715 WriteClassDumpForFloatWritesClassDumpRecordWithOneAttribute) {
716 Vector<byte> result;
717 HeapProfiler profiler(thread_, testWriter, &result);
718 RawLayout float_layout = Layout::cast(runtime_->layoutAt(LayoutId::kFloat));
719 {
720 HeapProfiler::Record record(HeapProfiler::kHeapDumpSegment, &profiler);
721 profiler.setRecord(&record);
722 profiler.writeClassDump(float_layout);
723 profiler.clearRecord();
724 }
725 word pos = 0;
726 // float
727 uword float_address = runtime_->symbols()->at(ID(float)).raw();
728 EXPECT_TRUE(readStringInUtf8(result, &pos, float_address, "float"));
729 EXPECT_TRUE(readLoadClass(result, &pos, float_layout.raw(), float_address));
730
731 // object
732 uword object_address = runtime_->symbols()->at(ID(object)).raw();
733 RawLayout object_layout = Layout::cast(runtime_->layoutAt(LayoutId::kObject));
734 EXPECT_TRUE(readStringInUtf8(result, &pos, object_address, "object"));
735 EXPECT_TRUE(readLoadClass(result, &pos, object_layout.raw(), object_address));
736
737 // value
738 uword value_address = runtime_->symbols()->at(ID(value)).raw();
739 EXPECT_TRUE(readStringInUtf8(result, &pos, value_address, "value"));
740
741 // Heap dump segment
742 EXPECT_TRUE(readTag(result, &pos, HeapProfiler::Tag::kHeapDumpSegment));
743 EXPECT_EQ(read32(result, &pos), 0); // time
744 EXPECT_EQ(read32(result, &pos), 80); // length
745
746 // Class dump subrecord
747 EXPECT_TRUE(readSubtag(result, &pos, HeapProfiler::Subtag::kClassDump));
748 EXPECT_TRUE(readClassDumpPrelude(result, &pos, float_layout.raw(),
749 object_layout.raw()));
750 EXPECT_EQ(read32(result, &pos),
751 float_layout.instanceSize()); // instance size in bytes
752 EXPECT_EQ(read16(result, &pos),
753 0); // size of constant pool and number of records that follow
754 EXPECT_EQ(read16(result, &pos), 0); // number of static fields
755 EXPECT_EQ(read16(result, &pos), 1); // number of instance fields
756
757 // Field 0 (u8 name, u1 type)
758 EXPECT_EQ(readu64(result, &pos), value_address);
759 EXPECT_EQ(read8(result, &pos), HeapProfiler::BasicType::kDouble);
760
761 EXPECT_EQ(pos, result.size());
762}
763
764TEST_F(HeapProfilerTest,
765 WriteInstanceDumpForUserClassWritesInstanceDumpRecord) {
766 ASSERT_FALSE(runFromCStr(runtime_, R"(
767class C:
768 def __init__(self):
769 self.a = 1
770 self.b = 2
771instance = C()
772)")
773 .isError());
774 HandleScope scope(thread_);
775 Object instance(&scope, mainModuleAt(runtime_, "instance"));
776 Layout c_layout(&scope, runtime_->layoutAt(instance.layoutId()));
777
778 Vector<byte> result;
779 HeapProfiler profiler(thread_, testWriter, &result);
780 {
781 HeapProfiler::Record record(HeapProfiler::kHeapDumpSegment, &profiler);
782 profiler.setRecord(&record);
783 profiler.writeInstanceDump(Instance::cast(*instance));
784 profiler.clearRecord();
785 }
786 word pos = 0;
787
788 // C
789 word c_address = SmallStr::fromCStr("C").raw();
790 EXPECT_TRUE(readStringInUtf8(result, &pos, c_address, "C"));
791 EXPECT_TRUE(readLoadClass(result, &pos, c_layout.raw(), c_address));
792
793 // Heap dump segment
794 EXPECT_TRUE(readTag(result, &pos, HeapProfiler::Tag::kHeapDumpSegment));
795 EXPECT_EQ(read32(result, &pos), 0); // time
796 EXPECT_EQ(read32(result, &pos), 49); // length
797
798 // Instance dump subrecord
799 EXPECT_TRUE(readSubtag(result, &pos, HeapProfiler::Subtag::kInstanceDump));
800 EXPECT_EQ(readu64(result, &pos), instance.raw()); // object ID
801 EXPECT_EQ(read32(result, &pos), 0); // stack trace serial number
802 EXPECT_EQ(readu64(result, &pos), c_layout.raw()); // class object ID
803 EXPECT_EQ(read32(result, &pos),
804 3 * kPointerSize); // number of bytes that follow
805 EXPECT_EQ(readu64(result, &pos), SmallInt::fromWord(1).raw());
806 EXPECT_EQ(readu64(result, &pos), SmallInt::fromWord(2).raw());
807 EXPECT_EQ(readu64(result, &pos), runtime_->emptyTuple().raw()); // overflow
808
809 EXPECT_EQ(pos, result.size());
810}
811
812TEST_F(HeapProfilerTest, WriteInstanceDumpForDictWritesInstanceDumpRecord) {
813 HandleScope scope(thread_);
814 Dict dict(&scope, runtime_->newDict());
815 Object key(&scope, SmallStr::fromCStr("foo"));
816 Object value(&scope, SmallStr::fromCStr("bar"));
817 word hash = Int::cast(Interpreter::hash(thread_, key)).asWord();
818 ASSERT_TRUE(dictAtPut(thread_, dict, key, hash, value).isNoneType());
819 Layout dict_layout(&scope, runtime_->layoutAt(dict.layoutId()));
820
821 Vector<byte> result;
822 HeapProfiler profiler(thread_, testWriter, &result);
823 {
824 HeapProfiler::Record record(HeapProfiler::kHeapDumpSegment, &profiler);
825 profiler.setRecord(&record);
826 profiler.writeInstanceDump(*dict);
827 profiler.clearRecord();
828 }
829 word pos = 0;
830
831 // dict
832 uword dict_address = runtime_->symbols()->at(ID(dict)).raw();
833 EXPECT_TRUE(readStringInUtf8(result, &pos, dict_address, "dict"));
834 EXPECT_TRUE(readLoadClass(result, &pos, dict_layout.raw(), dict_address));
835
836 // Heap dump segment
837 EXPECT_TRUE(readTag(result, &pos, HeapProfiler::Tag::kHeapDumpSegment));
838 EXPECT_EQ(read32(result, &pos), 0); // time
839 EXPECT_EQ(read32(result, &pos), 57); // length
840
841 // Instance dump subrecord
842 EXPECT_TRUE(readSubtag(result, &pos, HeapProfiler::Subtag::kInstanceDump));
843 EXPECT_EQ(readu64(result, &pos), dict.raw()); // object ID
844 EXPECT_EQ(read32(result, &pos), 0); // stack trace serial number
845 EXPECT_EQ(readu64(result, &pos), dict_layout.raw()); // class object ID
846 EXPECT_EQ(read32(result, &pos),
847 4 * kPointerSize); // number of bytes that follow
848 EXPECT_EQ(readu64(result, &pos), SmallInt::fromWord(1).raw()); // num items
849 EXPECT_EQ(readu64(result, &pos), dict.data().raw()); // data
850 EXPECT_EQ(readu64(result, &pos), dict.indices().raw()); // sparse
851 // first empty item index
852 EXPECT_EQ(readu64(result, &pos),
853 SmallInt::fromWord(dict.firstEmptyItemIndex()).raw());
854 EXPECT_EQ(pos, result.size());
855}
856
857TEST_F(HeapProfilerTest, WriteInstanceDumpForFloatWritesInstanceDumpRecord) {
858 HandleScope scope(thread_);
859 Float obj(&scope, runtime_->newFloat(1.5));
860 Layout float_layout(&scope, runtime_->layoutAt(obj.layoutId()));
861
862 Vector<byte> result;
863 HeapProfiler profiler(thread_, testWriter, &result);
864 {
865 HeapProfiler::Record record(HeapProfiler::kHeapDumpSegment, &profiler);
866 profiler.setRecord(&record);
867 profiler.writeFloat(*obj);
868 profiler.clearRecord();
869 }
870 word pos = 0;
871
872 // float
873 uword float_address = runtime_->symbols()->at(ID(float)).raw();
874 EXPECT_TRUE(readStringInUtf8(result, &pos, float_address, "float"));
875 EXPECT_TRUE(readLoadClass(result, &pos, float_layout.raw(), float_address));
876
877 // Heap dump segment
878 EXPECT_TRUE(readTag(result, &pos, HeapProfiler::Tag::kHeapDumpSegment));
879 EXPECT_EQ(read32(result, &pos), 0); // time
880 EXPECT_EQ(read32(result, &pos), 33); // length
881
882 // Instance dump subrecord
883 EXPECT_TRUE(readSubtag(result, &pos, HeapProfiler::Subtag::kInstanceDump));
884 EXPECT_EQ(readu64(result, &pos), obj.raw()); // object ID
885 EXPECT_EQ(read32(result, &pos), 0); // stack trace serial number
886 EXPECT_EQ(readu64(result, &pos), float_layout.raw()); // class object ID
887 EXPECT_EQ(read32(result, &pos),
888 1 * kPointerSize); // number of bytes that follow
889 uint64_t value = read64(result, &pos);
890 EXPECT_EQ(bit_cast<double>(value), obj.value()); // value
891
892 EXPECT_EQ(pos, result.size());
893}
894
895TEST_F(HeapProfilerTest, WriteEllipsisWritesInstanceDumpRecord) {
896 HandleScope scope(thread_);
897 Ellipsis instance(&scope, runtime_->ellipsis());
898 Layout ellipsis_layout(&scope, runtime_->layoutAt(instance.layoutId()));
899
900 Vector<byte> result;
901 HeapProfiler profiler(thread_, testWriter, &result);
902 {
903 HeapProfiler::Record record(HeapProfiler::kHeapDumpSegment, &profiler);
904 profiler.setRecord(&record);
905 profiler.writeEllipsis(*instance);
906 profiler.clearRecord();
907 }
908 word pos = 0;
909
910 // ellipsis
911 uword ellipsis_address = runtime_->symbols()->at(ID(ellipsis)).raw();
912 EXPECT_TRUE(readStringInUtf8(result, &pos, ellipsis_address, "ellipsis"));
913 EXPECT_TRUE(
914 readLoadClass(result, &pos, ellipsis_layout.raw(), ellipsis_address));
915
916 // Heap dump segment
917 EXPECT_TRUE(readTag(result, &pos, HeapProfiler::Tag::kHeapDumpSegment));
918 EXPECT_EQ(read32(result, &pos), 0); // time
919 EXPECT_EQ(read32(result, &pos), 25); // length
920
921 // Instance dump subrecord
922 EXPECT_TRUE(readSubtag(result, &pos, HeapProfiler::Subtag::kInstanceDump));
923 EXPECT_EQ(readu64(result, &pos), instance.raw()); // object ID
924 EXPECT_EQ(read32(result, &pos), 0); // stack trace serial number
925 EXPECT_EQ(readu64(result, &pos), ellipsis_layout.raw()); // class object ID
926 EXPECT_EQ(read32(result, &pos), 0); // number of bytes that follow
927
928 EXPECT_EQ(pos, result.size());
929}
930
931TEST_F(HeapProfilerTest, WriteImmediateWritesInstanceDump) {
932 Vector<byte> result;
933 RawObject obj = SmallInt::fromWord(1337);
934 RawLayout smallint_layout = Layout::cast(runtime_->layoutOf(obj));
935 HeapProfiler profiler(thread_, testWriter, &result);
936 {
937 HeapProfiler::Record record(HeapProfiler::kHeapDumpSegment, &profiler);
938 profiler.setRecord(&record);
939 profiler.writeImmediate(obj);
940 profiler.clearRecord();
941 }
942 word pos = 0;
943
944 // smallint
945 uword smallint_address = runtime_->symbols()->at(ID(smallint)).raw();
946 EXPECT_TRUE(readStringInUtf8(result, &pos, smallint_address, "smallint"));
947 EXPECT_TRUE(
948 readLoadClass(result, &pos, smallint_layout.raw(), smallint_address));
949
950 // Heap dump segment
951 EXPECT_TRUE(readTag(result, &pos, HeapProfiler::Tag::kHeapDumpSegment));
952 EXPECT_EQ(read32(result, &pos), 0); // time
953 EXPECT_EQ(read32(result, &pos), 25); // length
954
955 // Instance dump for 1337
956 EXPECT_TRUE(readSubtag(result, &pos, HeapProfiler::Subtag::kInstanceDump));
957 EXPECT_EQ(readu64(result, &pos), obj.raw()); // object ID
958 EXPECT_EQ(read32(result, &pos), 0); // stack trace serial number
959 EXPECT_EQ(readu64(result, &pos), smallint_layout.raw()); // class object ID
960 EXPECT_EQ(read32(result, &pos), 0); // number of bytes to follow
961
962 EXPECT_EQ(pos, result.size());
963}
964
965TEST_F(HeapProfilerTest, WriteFakeClassDumpWritesClassDump) {
966 Vector<byte> result;
967 HeapProfiler profiler(thread_, testWriter, &result);
968 {
969 HeapProfiler::Record record(HeapProfiler::kHeapDumpSegment, &profiler);
970 profiler.setRecord(&record);
971 profiler.writeFakeClassDump(HeapProfiler::FakeClass::kJavaLangClass,
972 HeapProfiler::kJavaLangClass,
973 HeapProfiler::FakeClass::kJavaLangObject);
974 profiler.clearRecord();
975 }
976 word pos = 0;
977
978 // java.lang.Class
979 uword java_lang_class_id =
980 reinterpret_cast<uword>(HeapProfiler::kJavaLangClass);
981 EXPECT_TRUE(
982 readStringInUtf8(result, &pos, java_lang_class_id, "java.lang.Class"));
983 EXPECT_TRUE(readLoadClass(
984 result, &pos, static_cast<uword>(HeapProfiler::FakeClass::kJavaLangClass),
985 java_lang_class_id));
986
987 // Heap dump segment
988 EXPECT_TRUE(readTag(result, &pos, HeapProfiler::Tag::kHeapDumpSegment));
989 EXPECT_EQ(read32(result, &pos), 0); // time
990 EXPECT_EQ(read32(result, &pos), 71); // length
991
992 // Class dump subrecord
993 EXPECT_TRUE(readSubtag(result, &pos, HeapProfiler::Subtag::kClassDump));
994 EXPECT_TRUE(readClassDumpPrelude(
995 result, &pos, static_cast<uword>(HeapProfiler::FakeClass::kJavaLangClass),
996 static_cast<uword>(HeapProfiler::FakeClass::kJavaLangObject)));
997 EXPECT_EQ(read32(result, &pos),
998 0); // instance size in bytes
999 EXPECT_EQ(read16(result, &pos),
1000 0); // size of constant pool and number of records that follow
1001 EXPECT_EQ(read16(result, &pos), 0); // number of static fields
1002 EXPECT_EQ(read16(result, &pos), 0); // number of instance fields
1003
1004 EXPECT_EQ(pos, result.size());
1005}
1006
1007TEST_F(HeapProfilerTest, WriteFakeLoadClassWritesLoadClass) {
1008 Vector<byte> result;
1009 HeapProfiler profiler(thread_, testWriter, &result);
1010 profiler.writeFakeLoadClass(HeapProfiler::FakeClass::kJavaLangClass,
1011 HeapProfiler::kJavaLangClass);
1012 word pos = 0;
1013
1014 // java.lang.Class
1015 uword java_lang_class_id =
1016 reinterpret_cast<uword>(HeapProfiler::kJavaLangClass);
1017 EXPECT_TRUE(
1018 readStringInUtf8(result, &pos, java_lang_class_id, "java.lang.Class"));
1019
1020 // Then write the LoadClass record
1021 EXPECT_TRUE(readLoadClass(
1022 result, &pos, static_cast<uword>(HeapProfiler::FakeClass::kJavaLangClass),
1023 java_lang_class_id));
1024
1025 EXPECT_EQ(pos, result.size());
1026}
1027
1028TEST_F(HeapProfilerTest, WriteHeaderWritesHeader) {
1029 Vector<byte> result;
1030 HeapProfiler profiler(thread_, testWriter, &result);
1031 profiler.writeHeader();
1032 word pos = 0;
1033 EXPECT_TRUE(readStringLiteral(result, &pos, "JAVA PROFILE 1.0.2"));
1034 EXPECT_EQ(read8(result, &pos), 0); // nul byte
1035 EXPECT_EQ(read32(result, &pos), 8); // ID length in bytes
1036 read32(result, &pos); // high value of current time in milliseconds
1037 read32(result, &pos); // low value of current time in milliseconds
1038
1039 EXPECT_EQ(pos, result.size());
1040}
1041
1042TEST_F(HeapProfilerTest, BeginAndEndHeapDumpSegmentWritesHeapDumpSegment) {
1043 Vector<byte> result;
1044 HeapProfiler profiler(thread_, testWriter, &result);
1045 {
1046 HeapProfiler::Record record(HeapProfiler::kHeapDumpSegment, &profiler);
1047 profiler.setRecord(&record);
1048 EXPECT_EQ(result.size(), 0);
1049 profiler.clearRecord();
1050 }
1051 word pos = 0;
1052
1053 EXPECT_TRUE(readTag(result, &pos, HeapProfiler::Tag::kHeapDumpSegment));
1054 EXPECT_EQ(read32(result, &pos), 0); // time
1055 EXPECT_EQ(read32(result, &pos), 0); // length
1056
1057 EXPECT_EQ(pos, result.size());
1058}
1059
1060TEST_F(HeapProfilerTest, RecordDestructorWritesRecord) {
1061 Vector<byte> result;
1062 HeapProfiler profiler(thread_, testWriter, &result);
1063 {
1064 HeapProfiler::Record record(static_cast<HeapProfiler::Tag>(10), &profiler);
1065 record.write32(0x12345678);
1066 }
1067 word pos = 0;
1068
1069 EXPECT_EQ(read8(result, &pos), 0xa);
1070 EXPECT_EQ(read32(result, &pos), 0); // time
1071 EXPECT_EQ(read32(result, &pos), 4); // length
1072 EXPECT_EQ(read32(result, &pos), 0x12345678);
1073
1074 EXPECT_EQ(pos, result.size());
1075}
1076
1077TEST_F(HeapProfilerTest, WriteHeapDumpEndWritesRecord) {
1078 Vector<byte> result;
1079 HeapProfiler profiler(thread_, testWriter, &result);
1080 profiler.writeHeapDumpEnd();
1081 word pos = 0;
1082
1083 // Heap dump segment
1084 EXPECT_TRUE(readTag(result, &pos, HeapProfiler::Tag::kHeapDumpEnd));
1085 EXPECT_EQ(read32(result, &pos), 0); // time
1086 EXPECT_EQ(read32(result, &pos), 0); // length
1087
1088 EXPECT_EQ(pos, result.size());
1089}
1090
1091TEST_F(HeapProfilerTest, WriteObjectArrayWritesObjectArrayRecord) {
1092 Vector<byte> result;
1093 HeapProfiler profiler(thread_, testWriter, &result);
1094 HandleScope scope(thread_);
1095 Object obj1(&scope, SmallInt::fromWord(0));
1096 Object obj2(&scope, SmallInt::fromWord(1));
1097 Object obj3(&scope, SmallInt::fromWord(2));
1098 Tuple tuple(&scope, runtime_->newTupleWith3(obj1, obj2, obj3));
1099 {
1100 HeapProfiler::Record record(HeapProfiler::kHeapDumpSegment, &profiler);
1101 profiler.setRecord(&record);
1102 profiler.writeObjectArray(*tuple);
1103 profiler.clearRecord();
1104 }
1105 word pos = 0;
1106
1107 // Heap dump segment
1108 EXPECT_TRUE(readTag(result, &pos, HeapProfiler::Tag::kHeapDumpSegment));
1109 EXPECT_EQ(read32(result, &pos), 0); // time
1110 EXPECT_EQ(read32(result, &pos), 49); // length
1111
1112 // Object array
1113 EXPECT_TRUE(readSubtag(result, &pos, HeapProfiler::Subtag::kObjectArrayDump));
1114 EXPECT_EQ(readu64(result, &pos), tuple.raw()); // array object ID
1115 EXPECT_EQ(read32(result, &pos), 0); // stack trace serial number
1116 EXPECT_EQ(read32(result, &pos), 3); // number of elements
1117 EXPECT_EQ(readu64(result, &pos),
1118 static_cast<uword>(
1119 HeapProfiler::FakeClass::kObjectArray)); // array class ID
1120 EXPECT_EQ(readu64(result, &pos), SmallInt::fromWord(0).raw()); // element 0
1121 EXPECT_EQ(readu64(result, &pos), SmallInt::fromWord(1).raw()); // element 1
1122 EXPECT_EQ(readu64(result, &pos), SmallInt::fromWord(2).raw()); // element 2
1123
1124 EXPECT_EQ(pos, result.size());
1125}
1126
1127TEST_F(HeapProfilerTest, WriteBytesWritesPrimitiveArrayRecord) {
1128 Vector<byte> result;
1129 HeapProfiler profiler(thread_, testWriter, &result);
1130 HandleScope scope(thread_);
1131 byte source[] = "hello";
1132 Bytes bytes(&scope, runtime_->newBytesWithAll(source));
1133 {
1134 HeapProfiler::Record record(HeapProfiler::kHeapDumpSegment, &profiler);
1135 profiler.setRecord(&record);
1136 profiler.writeBytes(*bytes);
1137 profiler.clearRecord();
1138 }
1139 word pos = 0;
1140
1141 // Heap dump segment
1142 EXPECT_TRUE(readTag(result, &pos, HeapProfiler::Tag::kHeapDumpSegment));
1143 EXPECT_EQ(read32(result, &pos), 0); // time
1144 EXPECT_EQ(read32(result, &pos), 24); // length
1145
1146 // Byte array
1147 EXPECT_TRUE(
1148 readSubtag(result, &pos, HeapProfiler::Subtag::kPrimitiveArrayDump));
1149 EXPECT_EQ(readu64(result, &pos), bytes.raw()); // array object ID
1150 EXPECT_EQ(read32(result, &pos), 0); // stack trace serial number
1151 EXPECT_EQ(readu32(result, &pos), sizeof(source)); // number of elements
1152 EXPECT_EQ(read8(result, &pos),
1153 HeapProfiler::BasicType::kByte); // element type
1154 EXPECT_EQ(read8(result, &pos), 'h'); // element 0
1155 EXPECT_EQ(read8(result, &pos), 'e'); // element 1
1156 EXPECT_EQ(read8(result, &pos), 'l'); // element 2
1157 EXPECT_EQ(read8(result, &pos), 'l'); // element 3
1158 EXPECT_EQ(read8(result, &pos), 'o'); // element 4
1159 EXPECT_EQ(read8(result, &pos), '\0'); // element 5
1160
1161 EXPECT_EQ(pos, result.size());
1162}
1163
1164TEST_F(HeapProfilerTest,
1165 WriteClassDumpForComplexWritesClassDumpRecordWithTwoAttributes) {
1166 Vector<byte> result;
1167 HeapProfiler profiler(thread_, testWriter, &result);
1168 RawLayout complex_layout =
1169 Layout::cast(runtime_->layoutAt(LayoutId::kComplex));
1170 {
1171 HeapProfiler::Record record(HeapProfiler::kHeapDumpSegment, &profiler);
1172 profiler.setRecord(&record);
1173 profiler.writeClassDump(complex_layout);
1174 profiler.clearRecord();
1175 }
1176 word pos = 0;
1177
1178 // complex
1179 uword complex_address = runtime_->symbols()->at(ID(complex)).raw();
1180 EXPECT_TRUE(readStringInUtf8(result, &pos, complex_address, "complex"));
1181 EXPECT_TRUE(
1182 readLoadClass(result, &pos, complex_layout.raw(), complex_address));
1183
1184 // object
1185 uword object_address = runtime_->symbols()->at(ID(object)).raw();
1186 RawLayout object_layout = Layout::cast(runtime_->layoutAt(LayoutId::kObject));
1187 EXPECT_TRUE(readStringInUtf8(result, &pos, object_address, "object"));
1188 EXPECT_TRUE(readLoadClass(result, &pos, object_layout.raw(), object_address));
1189
1190 // real
1191 uword real_address = runtime_->symbols()->at(ID(real)).raw();
1192 EXPECT_TRUE(readStringInUtf8(result, &pos, real_address, "real"));
1193
1194 // imag
1195 uword imag_address = runtime_->symbols()->at(ID(imag)).raw();
1196 EXPECT_TRUE(readStringInUtf8(result, &pos, imag_address, "imag"));
1197
1198 // Heap dump segment
1199 EXPECT_TRUE(readTag(result, &pos, HeapProfiler::Tag::kHeapDumpSegment));
1200 EXPECT_EQ(read32(result, &pos), 0); // time
1201 EXPECT_EQ(read32(result, &pos), 89); // length
1202
1203 // Class dump subrecord
1204 EXPECT_TRUE(readSubtag(result, &pos, HeapProfiler::Subtag::kClassDump));
1205 EXPECT_TRUE(readClassDumpPrelude(result, &pos, complex_layout.raw(),
1206 object_layout.raw()));
1207 EXPECT_EQ(read32(result, &pos),
1208 complex_layout.instanceSize()); // instance size in bytes
1209 EXPECT_EQ(read16(result, &pos),
1210 0); // size of constant pool and number of records that follow
1211 EXPECT_EQ(read16(result, &pos), 0); // number of static fields
1212 EXPECT_EQ(read16(result, &pos), 2); // number of instance fields
1213
1214 // Field 0 (u8 name, u1 type)
1215 EXPECT_EQ(readu64(result, &pos), real_address);
1216 EXPECT_EQ(read8(result, &pos), HeapProfiler::BasicType::kDouble);
1217
1218 // Field 1 (u8 name, u1 type)
1219 EXPECT_EQ(readu64(result, &pos), imag_address);
1220 EXPECT_EQ(read8(result, &pos), HeapProfiler::BasicType::kDouble);
1221
1222 EXPECT_EQ(pos, result.size());
1223}
1224
1225TEST_F(HeapProfilerTest, WriteComplexWritesInstanceDump) {
1226 Vector<byte> result;
1227 HeapProfiler profiler(thread_, testWriter, &result);
1228 HandleScope scope(thread_);
1229 Complex obj(&scope, runtime_->newComplex(1.0, 2.0));
1230 Layout complex_layout(&scope, runtime_->layoutOf(*obj));
1231 {
1232 HeapProfiler::Record record(HeapProfiler::kHeapDumpSegment, &profiler);
1233 profiler.setRecord(&record);
1234 profiler.writeComplex(*obj);
1235 profiler.clearRecord();
1236 }
1237 word pos = 0;
1238
1239 // complex
1240 uword complex_address = runtime_->symbols()->at(ID(complex)).raw();
1241 EXPECT_TRUE(readStringInUtf8(result, &pos, complex_address, "complex"));
1242 EXPECT_TRUE(
1243 readLoadClass(result, &pos, complex_layout.raw(), complex_address));
1244
1245 // Heap dump segment
1246 EXPECT_TRUE(readTag(result, &pos, HeapProfiler::Tag::kHeapDumpSegment));
1247 EXPECT_EQ(read32(result, &pos), 0); // time
1248 EXPECT_EQ(read32(result, &pos), 41); // length
1249
1250 // Complex "instance" dump
1251 EXPECT_TRUE(readSubtag(result, &pos, HeapProfiler::Subtag::kInstanceDump));
1252 EXPECT_EQ(readu64(result, &pos), obj.raw()); // object ID
1253 EXPECT_EQ(read32(result, &pos), 0); // stack trace serial number
1254 EXPECT_EQ(readu64(result, &pos), complex_layout.raw()); // class object ID
1255 EXPECT_EQ(read32(result, &pos),
1256 2 * kDoubleSize); // number of bytes that follow
1257 uint64_t real = readu64(result, &pos); // real
1258 EXPECT_EQ(bit_cast<double>(real), 1.0);
1259 uint64_t imag = readu64(result, &pos); // imag
1260 EXPECT_EQ(bit_cast<double>(imag), 2.0);
1261
1262 EXPECT_EQ(pos, result.size());
1263}
1264
1265TEST_F(HeapProfilerTest, WriteLargeIntWritesPrimitiveArrayRecord) {
1266 Vector<byte> result;
1267 HeapProfiler profiler(thread_, testWriter, &result);
1268 HandleScope scope(thread_);
1269 Int obj(&scope, runtime_->newInt(kMaxWord));
1270 Int two(&scope, SmallInt::fromWord(2));
1271 obj = runtime_->intMultiply(thread_, obj, two);
1272 CHECK(obj.isLargeInt(), "multiply failed");
1273 {
1274 HeapProfiler::Record record(HeapProfiler::kHeapDumpSegment, &profiler);
1275 profiler.setRecord(&record);
1276 profiler.writeLargeInt(LargeInt::cast(*obj));
1277 profiler.clearRecord();
1278 }
1279 word pos = 0;
1280
1281 // Heap dump segment
1282 EXPECT_TRUE(readTag(result, &pos, HeapProfiler::Tag::kHeapDumpSegment));
1283 EXPECT_EQ(read32(result, &pos), 0); // time
1284 EXPECT_EQ(read32(result, &pos), 34); // length
1285
1286 // Long array
1287 EXPECT_TRUE(
1288 readSubtag(result, &pos, HeapProfiler::Subtag::kPrimitiveArrayDump));
1289 EXPECT_EQ(readu64(result, &pos), obj.raw()); // array object ID
1290 EXPECT_EQ(read32(result, &pos), 0); // stack trace serial number
1291 EXPECT_EQ(read32(result, &pos), 2); // number of elements
1292 EXPECT_EQ(read8(result, &pos),
1293 HeapProfiler::BasicType::kLong); // element type
1294 EXPECT_EQ(read64(result, &pos), -2); // element 0
1295 EXPECT_EQ(read64(result, &pos), 0); // element 1
1296
1297 EXPECT_EQ(pos, result.size());
1298}
1299
1300TEST_F(HeapProfilerTest, WriteLargeStrWritesPrimitiveArrayRecord) {
1301 Vector<byte> result;
1302 HeapProfiler profiler(thread_, testWriter, &result);
1303 HandleScope scope(thread_);
1304 LargeStr obj(&scope, runtime_->newStrFromCStr("foobarbaz"));
1305 {
1306 HeapProfiler::Record record(HeapProfiler::kHeapDumpSegment, &profiler);
1307 profiler.setRecord(&record);
1308 profiler.writeLargeStr(*obj);
1309 profiler.clearRecord();
1310 }
1311 word pos = 0;
1312
1313 // Heap dump segment
1314 EXPECT_TRUE(readTag(result, &pos, HeapProfiler::Tag::kHeapDumpSegment));
1315 EXPECT_EQ(read32(result, &pos), 0); // time
1316 EXPECT_EQ(read32(result, &pos), 27); // length
1317
1318 // Byte array
1319 EXPECT_TRUE(
1320 readSubtag(result, &pos, HeapProfiler::Subtag::kPrimitiveArrayDump));
1321 EXPECT_EQ(readu64(result, &pos), obj.raw()); // array object ID
1322 EXPECT_EQ(read32(result, &pos), 0); // stack trace serial number
1323 EXPECT_EQ(read32(result, &pos), 9); // number of elements
1324 EXPECT_EQ(read8(result, &pos),
1325 HeapProfiler::BasicType::kByte); // element type
1326 EXPECT_EQ(read8(result, &pos), 'f'); // element 0
1327 EXPECT_EQ(read8(result, &pos), 'o'); // element 1
1328 EXPECT_EQ(read8(result, &pos), 'o'); // element 2
1329 EXPECT_EQ(read8(result, &pos), 'b'); // element 3
1330 EXPECT_EQ(read8(result, &pos), 'a'); // element 4
1331 EXPECT_EQ(read8(result, &pos), 'r'); // element 5
1332 EXPECT_EQ(read8(result, &pos), 'b'); // element 6
1333 EXPECT_EQ(read8(result, &pos), 'a'); // element 7
1334 EXPECT_EQ(read8(result, &pos), 'z'); // element 8
1335
1336 EXPECT_EQ(pos, result.size());
1337}
1338
1339TEST_F(HeapProfilerTest, RecordConstructorSetsFields) {
1340 HeapProfiler::Record record(static_cast<HeapProfiler::Tag>(10), nullptr);
1341 EXPECT_EQ(record.tag(), 10);
1342 EXPECT_EQ(record.length(), 0);
1343 EXPECT_EQ(record.body(), nullptr);
1344}
1345
1346static ::testing::AssertionResult recordEqualsBytes(
1347 const HeapProfiler::Record& record, View<byte> expected) {
1348 EXPECT_EQ(record.length(), expected.length());
1349 const uint8_t* body = record.body();
1350 for (word i = 0; i < record.length(); i++) {
1351 if (body[i] != expected.get(i)) {
1352 return ::testing::AssertionFailure() << "byte " << i << " differs";
1353 }
1354 }
1355 return ::testing::AssertionSuccess();
1356}
1357
1358TEST_F(HeapProfilerTest, RecordWriteWritesToBody) {
1359 HeapProfiler::Record record(static_cast<HeapProfiler::Tag>(10), nullptr);
1360 byte buf[] = {0, 1, 2, 3};
1361 record.write(buf, 4);
1362 EXPECT_TRUE(recordEqualsBytes(record, buf));
1363}
1364
1365TEST_F(HeapProfilerTest, RecordWrite8WritesToBody) {
1366 HeapProfiler::Record record(static_cast<HeapProfiler::Tag>(10), nullptr);
1367 record.write8(0x7d);
1368 EXPECT_EQ(record.length(), 1);
1369 EXPECT_EQ(*record.body(), 0x7d);
1370}
1371
1372TEST_F(HeapProfilerTest, RecordWrite16WritesToBodyInBigEndian) {
1373 HeapProfiler::Record record(static_cast<HeapProfiler::Tag>(10), nullptr);
1374 record.write16(0xbeef);
1375 byte expected[] = {0xbe, 0xef};
1376 EXPECT_TRUE(recordEqualsBytes(record, expected));
1377}
1378
1379TEST_F(HeapProfilerTest, RecordWrite32WritesToBodyInBigEndian) {
1380 HeapProfiler::Record record(static_cast<HeapProfiler::Tag>(10), nullptr);
1381 record.write32(0xdeadbeef);
1382 byte expected[] = {0xde, 0xad, 0xbe, 0xef};
1383 EXPECT_TRUE(recordEqualsBytes(record, expected));
1384}
1385
1386TEST_F(HeapProfilerTest, RecordWrite64WritesToBodyInBigEndian) {
1387 HeapProfiler::Record record(static_cast<HeapProfiler::Tag>(10), nullptr);
1388 record.write64(0xdec0ffeedeadbeef);
1389 byte expected[] = {0xde, 0xc0, 0xff, 0xee, 0xde, 0xad, 0xbe, 0xef};
1390 EXPECT_TRUE(recordEqualsBytes(record, expected));
1391}
1392
1393TEST_F(HeapProfilerTest, RecordWriteObjectIdWritesToBodyInBigEndian) {
1394 HeapProfiler::Record record(static_cast<HeapProfiler::Tag>(10), nullptr);
1395 record.writeObjectId(0xdec0ffeedeadbeef);
1396 byte expected[] = {0xde, 0xc0, 0xff, 0xee, 0xde, 0xad, 0xbe, 0xef};
1397 EXPECT_TRUE(recordEqualsBytes(record, expected));
1398}
1399
1400TEST_F(HeapProfilerTest, SubRecordConstructorWritesTag) {
1401 HeapProfiler::Record record(static_cast<HeapProfiler::Tag>(10), nullptr);
1402 HeapProfiler::SubRecord subrecord(static_cast<HeapProfiler::Subtag>(20),
1403 &record);
1404 EXPECT_EQ(record.length(), 1);
1405 EXPECT_EQ(*record.body(), 20);
1406}
1407
1408TEST_F(HeapProfilerTest, SubRecordWriteWritesToRecord) {
1409 HeapProfiler::Record record(static_cast<HeapProfiler::Tag>(10), nullptr);
1410 HeapProfiler::SubRecord subrecord(static_cast<HeapProfiler::Subtag>(20),
1411 &record);
1412 byte buf[] = {0, 1, 2, 3};
1413 subrecord.write(buf, 4);
1414 byte expected[] = {20, 0, 1, 2, 3};
1415 EXPECT_TRUE(recordEqualsBytes(record, expected));
1416}
1417
1418TEST_F(HeapProfilerTest, SubRecordWrite8WritesToRecord) {
1419 HeapProfiler::Record record(static_cast<HeapProfiler::Tag>(10), nullptr);
1420 HeapProfiler::SubRecord subrecord(static_cast<HeapProfiler::Subtag>(20),
1421 &record);
1422 subrecord.write8(0x7d);
1423 byte expected[] = {20, 0x7d};
1424 EXPECT_TRUE(recordEqualsBytes(record, expected));
1425}
1426
1427TEST_F(HeapProfilerTest, SubRecordWrite16WritesToRecordInBigEndian) {
1428 HeapProfiler::Record record(static_cast<HeapProfiler::Tag>(10), nullptr);
1429 HeapProfiler::SubRecord subrecord(static_cast<HeapProfiler::Subtag>(20),
1430 &record);
1431 subrecord.write16(0xbeef);
1432 byte expected[] = {20, 0xbe, 0xef};
1433 EXPECT_TRUE(recordEqualsBytes(record, expected));
1434}
1435
1436TEST_F(HeapProfilerTest, SubRecordWrite32WritesToRecordInBigEndian) {
1437 HeapProfiler::Record record(static_cast<HeapProfiler::Tag>(10), nullptr);
1438 HeapProfiler::SubRecord subrecord(static_cast<HeapProfiler::Subtag>(20),
1439 &record);
1440 subrecord.write32(0xdeadbeef);
1441 byte expected[] = {20, 0xde, 0xad, 0xbe, 0xef};
1442 EXPECT_TRUE(recordEqualsBytes(record, expected));
1443}
1444
1445TEST_F(HeapProfilerTest, SubRecordWrite64WritesToBodyInBigEndian) {
1446 HeapProfiler::Record record(static_cast<HeapProfiler::Tag>(10), nullptr);
1447 HeapProfiler::SubRecord subrecord(static_cast<HeapProfiler::Subtag>(20),
1448 &record);
1449 subrecord.write64(0xdec0ffeedeadbeef);
1450 byte expected[] = {20, 0xde, 0xc0, 0xff, 0xee, 0xde, 0xad, 0xbe, 0xef};
1451 EXPECT_TRUE(recordEqualsBytes(record, expected));
1452}
1453
1454TEST_F(HeapProfilerTest, HeapDumpAfterFullRuntimeBootDoesNotCrash) {
1455 // Create a __main__ and everything
1456 EXPECT_FALSE(runFromCStr(runtime_, R"(
1457import site
1458from _builtins import _heap_dump
1459_heap_dump("/dev/null")
1460)")
1461 .isError());
1462}
1463
1464class WordSetTest : public ::testing::Test {
1465 protected:
1466 WordSet ws;
1467 uword test_word1 = uword{1};
1468};
1469
1470TEST_F(WordSetTest, ContainsWithWordNotInSetReturnsFalse) {
1471 ASSERT_FALSE(ws.contains(test_word1));
1472}
1473
1474TEST_F(WordSetTest, ContainsWithWordInSetReturnsTrue) {
1475 ws.add(test_word1);
1476 ASSERT_TRUE(ws.contains(test_word1));
1477}
1478
1479TEST_F(WordSetTest, AddWithWordNotInSetReturnsFalse) {
1480 ASSERT_FALSE(ws.add(test_word1));
1481}
1482
1483TEST_F(WordSetTest, AddWithWordInSetReturnsTrue) {
1484 ws.add(test_word1);
1485 ASSERT_TRUE(ws.add(test_word1));
1486}
1487
1488TEST_F(WordSetTest,
1489 MapWithResizeAndRehashTriggeredContainsAllOriginalElements) {
1490 // Insert one element over the default capacity of 1000
1491 for (uword i = 0; i <= 1000; ++i) {
1492 if (i != kDummyVal) {
1493 ws.add(i);
1494 }
1495 }
1496 for (uword i = 0; i <= 1000; ++i) {
1497 if (i != kDummyVal) {
1498 ASSERT_TRUE(ws.contains(i));
1499 }
1500 }
1501}
1502
1503} // namespace testing
1504
1505} // namespace py