this repo has no description
at trunk 1505 lines 56 kB view raw
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