this repo has no description
at trunk 857 lines 28 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "heap-profiler.h" 3 4#include <cerrno> 5 6#include "file.h" 7#include "handles.h" 8#include "os.h" 9#include "runtime.h" 10#include "thread.h" 11 12namespace py { 13 14const char HeapProfiler::kBytearrayClassName[] = "byte[]"; 15const char HeapProfiler::kDoubleArrayClassName[] = "double[]"; 16const char HeapProfiler::kInvalid[] = "<INVALID>"; 17const char HeapProfiler::kOverflow[] = "<OVERFLOW>"; 18const char HeapProfiler::kJavaLangClass[] = "java.lang.Class"; 19const char HeapProfiler::kJavaLangClassLoader[] = "java.lang.ClassLoader"; 20const char HeapProfiler::kJavaLangObject[] = "java.lang.Object"; 21const char HeapProfiler::kJavaLangString[] = "java.lang.String"; 22const char HeapProfiler::kLongArrayClassName[] = "long[]"; 23const char HeapProfiler::kObjectArrayClassName[] = "java.lang.Object[]"; 24 25HeapProfiler::HeapProfiler(Thread* thread, HeapProfilerWriteCallback callback, 26 void* stream) 27 : thread_(thread), output_stream_(stream), write_callback_(callback) {} 28 29void HeapProfiler::write(const void* data, word size) { 30 (*write_callback_)(data, size, output_stream_); 31} 32 33// LOAD CLASS - 0x02 34// 35// Format: 36// u4 - class serial number (always > 0) 37// ID - class object ID 38// u4 - stack trace serial number 39// ID - class name string ID 40void HeapProfiler::writeFakeLoadClass(FakeClass fake_class, 41 const char* class_name) { 42 Record record(kLoadClass, this); 43 // class serial number (always > 0) 44 record.write32(1); 45 // class object ID 46 record.writeObjectId(static_cast<uword>(fake_class)); 47 // stack trace serial number 48 record.write32(0); 49 // TODO(T61807224): Dump type names discriminated by layout ID 50 // class name string ID 51 record.writeObjectId(cStringId(class_name)); 52} 53 54// CLASS DUMP - 0x20 55// 56// Format: 57// u4 - class serial number (always > 0) 58// ID - class object ID 59// u4 - stack trace serial number 60// ID - class name string ID 61void HeapProfiler::writeFakeClassDump(FakeClass fake_class, 62 const char* class_name, 63 FakeClass fake_super_class) { 64 writeFakeLoadClass(fake_class, class_name); 65 CHECK(!class_dump_table_.add(static_cast<uword>(fake_class)), 66 "cannot dump object twice"); 67 SubRecord sub(Subtag::kClassDump, current_record_); 68 // class object ID 69 sub.writeObjectId(static_cast<uword>(fake_class)); 70 // stack trace serial number 71 sub.write32(0); 72 // super class object ID 73 sub.writeObjectId(static_cast<uword>(fake_super_class)); 74 // class loader object ID 75 sub.writeObjectId(0); 76 // signers object ID 77 sub.writeObjectId(0); 78 // protection domain object ID 79 sub.writeObjectId(0); 80 // reserved 81 sub.writeObjectId(0); 82 // reserved 83 sub.writeObjectId(0); 84 // instance size (in bytes) 85 sub.write32(0); 86 // size of constant pool and number of records that follow 87 sub.write16(0); 88 // Number of static fields 89 sub.write16(0); 90 // Number of instance fields (not include super class's) 91 sub.write16(0); 92} 93 94// STACK TRACE - 0x05 95// 96// u4 - stack trace serial number 97// u4 - thread serial number 98// u4 - number of frames 99// [ID]* - series of stack frame ID's 100void HeapProfiler::writeFakeStackTrace() { 101 Record record(kStackTrace, this); 102 // stack trace serial number 103 record.write32(0); 104 // thread serial number 105 // TODO(T70833159): Support multiple threads in heap dumper. 106 record.write32(0); 107 // number of frames 108 record.write32(0); 109} 110 111void HeapProfiler::writeHeader() { 112 const char magic[] = "JAVA PROFILE 1.0.2"; 113 write(magic, sizeof(magic)); 114 write32(kPointerSize); 115 double seconds_double = OS::currentTime(); 116 uint64_t seconds = static_cast<uint64_t>(seconds_double); 117 seconds += (seconds_double - seconds); 118 uint64_t milliseconds = seconds * kMillisecondsPerSecond; 119 uint32_t hi = 120 static_cast<uint32_t>((milliseconds >> 32) & 0x00000000FFFFFFFF); 121 write32(hi); 122 uint32_t lo = static_cast<uint32_t>(milliseconds & 0x00000000FFFFFFFF); 123 write32(lo); 124} 125 126// LOAD CLASS - 0x02 127// 128// Format: 129// u4 - class serial number (always > 0) 130// ID - class object ID 131// u4 - stack trace serial number 132// ID - class name string ID 133void HeapProfiler::writeLoadClass(RawLayout layout) { 134 CHECK(!load_class_table_.add(layout.raw()), "cannot dump object twice"); 135 Record record(kLoadClass, this); 136 // class serial number (always > 0) 137 record.write32(1); 138 // class object ID 139 record.writeObjectId(objectId(layout)); 140 // stack trace serial number 141 record.write32(0); 142 // class name string ID 143 HandleScope scope(thread_); 144 Type type(&scope, thread_->runtime()->concreteTypeAt(layout.id())); 145 Str name(&scope, type.name()); 146 record.writeObjectId(stringId(*name)); 147} 148 149// CLASS DUMP - 0x20 150// 151// Format: 152// ID - class object ID 153// u4 - stack trace serial number 154// ID - super class object ID 155// ID - class loader object ID 156// ID - signers object ID 157// ID - protection domain object ID 158// ID - reserved 159// ID - reserved 160// u4 - instance size (in bytes) 161// u2 - size of constant pool and number of records that follow 162// u2 - constant pool index 163// u1 - type of entry: (See Basic Type) 164// value - value of entry (u1, u2, u4, or u8 based on type of entry) 165// u2 - Number of static fields: 166// ID - static field name string ID 167// u1 - type of field: (See Basic Type) 168// value - value of entry (u1, u2, u4, or u8 based on type of field) 169// u2 - Number of instance fields (not including super class's) 170// ID - field name string ID 171// u1 - type of field: (See Basic Type) 172void HeapProfiler::writeClassDump(RawLayout layout) { 173 CHECK(!class_dump_table_.add(layout.raw()), "cannot dump object twice"); 174 SubRecord sub(kClassDump, current_record_); 175 // class object ID 176 sub.writeObjectId(classId(layout)); 177 // stack trace serial number 178 sub.write32(0); 179 // super class object ID 180 if (layout.id() == LayoutId::kObject) { 181 // Superclass == 0 => object is java.lang.Object 182 sub.writeObjectId(0); 183 } else { 184 // Since there is not much of a concept of inheritance in the Layout 185 // system, pretend all Layouts' super is "object". This allows much easier 186 // dumping of attributes. 187 // TODO(emacs): Figure out how to dump class hierarchies 188 RawLayout super_layout = 189 Layout::cast(thread_->runtime()->layoutAt(LayoutId::kObject)); 190 sub.writeObjectId(classId(super_layout)); 191 } 192 // class loader object ID 193 sub.writeObjectId(0); 194 // signers object ID 195 sub.writeObjectId(0); 196 // protection domain object ID 197 sub.writeObjectId(0); 198 // reserved 199 sub.writeObjectId(0); 200 // reserved 201 sub.writeObjectId(0); 202 203 // instance size (in bytes) 204 sub.write32(layout.instanceSize()); 205 // size of constant pool and number of records that follow 206 // Constant pool is variable-length and empty here 207 sub.write16(0); 208 // number of static fields 209 // Static fields are variable-length and empty here 210 sub.write16(0); 211 Runtime* runtime = thread_->runtime(); 212 if (layout.id() == LayoutId::kComplex) { 213 // Two instance fields: "real", "imag" 214 sub.write16(2); 215 sub.writeObjectId(stringId(Str::cast(runtime->symbols()->at(ID(real))))); 216 sub.write8(BasicType::kDouble); 217 sub.writeObjectId(stringId(Str::cast(runtime->symbols()->at(ID(imag))))); 218 sub.write8(BasicType::kDouble); 219 return; 220 } 221 if (layout.id() == LayoutId::kFloat) { 222 // One instance field: "value" 223 sub.write16(1); 224 sub.writeObjectId(stringId(Str::cast(runtime->symbols()->at(ID(value))))); 225 sub.write8(BasicType::kDouble); 226 return; 227 } 228 // number of instance fields (not include super class's) 229 RawTuple in_object = Tuple::cast(layout.inObjectAttributes()); 230 word num_in_object = in_object.length(); 231 bool has_tuple_overflow = layout.hasTupleOverflow(); 232 word num_overflow = has_tuple_overflow ? 1 : 0; 233 word num_attributes = num_in_object + num_overflow; 234 sub.write16(num_attributes); 235 // instance fields 236 for (word i = 0; i < num_in_object; i++) { 237 // allocated on the layout for an attribute 238 RawObject name = Tuple::cast(in_object.at(i)).at(0); 239 if (name == SmallInt::fromWord(0)) { 240 sub.writeObjectId(cStringId(kInvalid)); 241 } else { 242 sub.writeObjectId(stringId(Str::cast(name))); 243 } 244 sub.write8(BasicType::kObject); 245 } 246 // TODO(emacs): Remove this special case once tuple overflow fits neatly into 247 // the allocated in-object attributes 248 if (has_tuple_overflow) { 249 sub.writeObjectId(cStringId(kOverflow)); 250 sub.write8(BasicType::kObject); 251 } 252} 253 254void HeapProfiler::writeInstanceDump(RawInstance obj) { 255 CHECK(!heap_object_table_.add(obj.raw()), "cannot dump object twice"); 256 SubRecord sub(kInstanceDump, current_record_); 257 RawLayout layout = Layout::cast(Thread::current()->runtime()->layoutOf(obj)); 258 RawTuple in_object = Tuple::cast(layout.inObjectAttributes()); 259 word num_in_object = in_object.length(); 260 bool has_tuple_overflow = layout.hasTupleOverflow(); 261 word num_overflow = has_tuple_overflow ? 1 : 0; 262 word num_attributes = num_in_object + num_overflow; 263 sub.beginInstanceDump(obj, /*stack_trace=*/0, num_attributes * kPointerSize, 264 classId(layout)); 265 // write in-object attributes 266 for (word i = 0; i < num_in_object; i++) { 267 RawTuple elt = Tuple::cast(in_object.at(i)); 268 AttributeInfo info(elt.at(1)); 269 sub.writeObjectId( 270 objectId(Instance::cast(obj).instanceVariableAt(info.offset()))); 271 } 272 // write tuple overflow (dict overflow is in-object) 273 if (has_tuple_overflow) { 274 sub.writeObjectId(objectId( 275 Instance::cast(obj).instanceVariableAt(layout.overflowOffset()))); 276 } 277} 278 279void HeapProfiler::writeImmediate(RawObject obj) { 280 DCHECK(!obj.isHeapObject(), "obj must be an immediate"); 281 SubRecord sub(kInstanceDump, current_record_); 282 RawLayout layout = Layout::cast(Thread::current()->runtime()->layoutOf(obj)); 283 sub.beginInstanceDump(obj, /*stack_trace=*/0, /*num_bytes=*/0, 284 classId(layout)); 285} 286 287class ImmediateVisitor : public WordVisitor { 288 public: 289 ImmediateVisitor(HeapProfiler* profiler) : profiler_(profiler) {} 290 void visit(uword element) { profiler_->writeImmediate(RawObject{element}); } 291 292 private: 293 HeapProfiler* profiler_; 294}; 295 296void HeapProfiler::writeImmediates() { 297 ImmediateVisitor visitor(this); 298 immediate_table_.visitElements(&visitor); 299} 300 301// OBJECT ARRAY DUMP - 0x22 302// 303// Format: 304// ID - array object ID 305// u4 - stack trace serial number 306// u4 - number of elements 307// ID - array class object id 308// [ID]* - elements 309void HeapProfiler::writeObjectArray(RawTuple tuple) { 310 SubRecord sub(kObjectArrayDump, current_record_); 311 // array object id 312 sub.writeObjectId(objectId(tuple)); 313 // stack trace serial number 314 sub.write32(0); 315 // number of elements 316 word length = tuple.length(); 317 CHECK(length < kMaxUint32, "length %ld too big for Java length field", 318 length); 319 sub.write32(static_cast<uint32_t>(length)); 320 // array class object id 321 sub.writeObjectId(static_cast<uword>(FakeClass::kObjectArray)); 322 // elements 323 for (word i = 0; i < length; i++) { 324 sub.writeObjectId(objectId(tuple.at(i))); 325 } 326} 327 328void HeapProfiler::writeBytes(RawBytes bytes) { 329 CHECK(!heap_object_table_.add(bytes.raw()), "cannot dump object twice"); 330 SubRecord sub(kPrimitiveArrayDump, current_record_); 331 sub.beginPrimitiveArrayDump(objectId(bytes), /*stack_trace=*/0, 332 bytes.length(), BasicType::kByte); 333 for (word i = 0; i < bytes.length(); i++) { 334 sub.write8(bytes.byteAt(i)); 335 } 336} 337 338void HeapProfiler::writeLargeStr(RawLargeStr str) { 339 CHECK(!heap_object_table_.add(str.raw()), "cannot dump object twice"); 340 SubRecord sub(kPrimitiveArrayDump, current_record_); 341 word length = str.length(); 342 sub.beginPrimitiveArrayDump(objectId(str), /*stack_trace=*/0, length, 343 BasicType::kByte); 344 for (word i = 0; i < length; i++) { 345 sub.write8(str.byteAt(i)); 346 } 347} 348 349void HeapProfiler::writeComplex(RawComplex obj) { 350 CHECK(!heap_object_table_.add(obj.raw()), "cannot dump object twice"); 351 SubRecord sub(kInstanceDump, current_record_); 352 RawLayout layout = Layout::cast(Thread::current()->runtime()->layoutOf(obj)); 353 sub.beginInstanceDump(obj, /*stack_trace=*/0, 2 * kDoubleSize, 354 classId(layout)); 355 sub.write64(bit_cast<uint64_t>(obj.real())); 356 sub.write64(bit_cast<uint64_t>(obj.imag())); 357} 358 359void HeapProfiler::writeEllipsis(RawEllipsis obj) { 360 CHECK(!heap_object_table_.add(obj.raw()), "cannot dump object twice"); 361 SubRecord sub(kInstanceDump, current_record_); 362 RawLayout layout = 363 Layout::cast(thread_->runtime()->layoutAt(LayoutId::kEllipsis)); 364 sub.beginInstanceDump(obj, /*stack_trace=*/0, layout.instanceSize(), 365 classId(layout)); 366 for (word i = 0; i < layout.instanceSize(); i += kPointerSize) { 367 sub.writeObjectId(objectId(Unbound::object())); 368 } 369} 370 371void HeapProfiler::writeFloat(RawFloat obj) { 372 CHECK(!heap_object_table_.add(obj.raw()), "cannot dump object twice"); 373 SubRecord sub(kInstanceDump, current_record_); 374 RawLayout layout = Layout::cast(Thread::current()->runtime()->layoutOf(obj)); 375 sub.beginInstanceDump(obj, /*stack_trace=*/0, kDoubleSize, classId(layout)); 376 sub.write64(bit_cast<uint64_t>(obj.value())); 377} 378 379void HeapProfiler::writeLargeInt(RawLargeInt obj) { 380 CHECK(!heap_object_table_.add(obj.raw()), "cannot dump object twice"); 381 SubRecord sub(kPrimitiveArrayDump, current_record_); 382 sub.beginPrimitiveArrayDump(objectId(obj), /*stack_trace=*/0, obj.numDigits(), 383 BasicType::kLong); 384 for (word i = 0; i < obj.numDigits(); i++) { 385 sub.write64(obj.digitAt(i)); 386 } 387} 388 389// HEAP DUMP SEGMENT - 0x1C 390void HeapProfiler::setRecord(Record* current_record) { 391 DCHECK(current_record != nullptr, "record should be non-null"); 392 DCHECK(current_record_ == nullptr, "current record already exists"); 393 current_record_ = current_record; 394} 395 396void HeapProfiler::clearRecord() { 397 DCHECK(current_record_ != nullptr, "current record does not exist"); 398 current_record_ = nullptr; 399} 400 401// HEAP DUMP END - 0x2C 402void HeapProfiler::writeHeapDumpEnd() { Record record(kHeapDumpEnd, this); } 403 404uword HeapProfiler::objectId(RawObject obj) { 405 uword id = obj.raw(); 406 if (obj.isHeader()) { 407 std::fprintf(stderr, 408 "objectId called on header @ 0x%lx, indicating misalignment\n", 409 id); 410 } 411 if (!obj.isError() && !obj.isHeapObject()) { 412 immediate_table_.add(id); 413 } 414 return id; 415} 416 417uword HeapProfiler::classId(RawLayout layout) { 418 uword id = layout.raw(); 419 if (!layout_table_.add(id)) { 420 writeLoadClass(layout); 421 } 422 return id; 423} 424 425uword HeapProfiler::cStringId(const char* c_str) { 426 uword id = reinterpret_cast<uword>(c_str); 427 if (!string_table_.add(id)) { 428 writeCStringInUTF8(c_str); 429 } 430 return id; 431} 432 433uword HeapProfiler::stringId(RawStr str) { 434 uword id = objectId(str); 435 if (!string_table_.add(id)) { 436 writeStringInUTF8(str); 437 } 438 return id; 439} 440 441// ROOT UNKNOWN - 0xFF 442// 443// Describes a root of unknown provenance. 444// 445// Format: 446// ID - object ID 447void HeapProfiler::writeRuntimeRoot(RawObject obj) { 448 SubRecord sub(kRootUnknown, current_record_); 449 // object ID 450 sub.writeObjectId(objectId(obj)); 451} 452 453// ROOT STICKY CLASS - 0x05 454// 455// Describes a built-in Layout. 456// 457// Format: 458// ID - object ID 459void HeapProfiler::writeStickyClassRoot(RawObject obj) { 460 SubRecord sub(kRootStickyClass, current_record_); 461 // object ID 462 sub.writeObjectId(objectId(obj)); 463} 464 465// ROOT JAVA FRAME - 0x03 466// 467// Describes a value found in a Frame in the Python stack. 468// 469// Format: 470// ID - object ID 471// u4 - thread serial number 472// u4 - frame number in stack trace (-1 for empty) 473void HeapProfiler::writeStackRoot(RawObject obj) { 474 SubRecord sub(kRootJavaFrame, current_record_); 475 // object ID 476 sub.writeObjectId(objectId(obj)); 477 // thread serial number 478 // TODO(T70833159): Support multiple threads in heap dumper. 479 sub.write32(0); 480 // frame number in stack trace 481 sub.write32(-1); 482} 483 484// ROOT THREAD OBJECT - 0x08 485// 486// Describes a Thread object. 487// 488// Format: 489// ID - object ID 490// u4 - thread serial number 491// u4 - stack trace serial number 492void HeapProfiler::writeThreadRoot(Thread* thread) { 493 SubRecord sub(kRootThreadObject, current_record_); 494 // object ID 495 sub.writeObjectId(reinterpret_cast<uword>(thread)); 496 // thread serial number 497 // TODO(T70833159): Support multiple threads in heap dumper. 498 sub.write32(0); 499 // stack trace serial number 500 sub.write32(0); 501} 502 503// ROOT JNI GLOBAL - 0x01 504// 505// Describes an object wrapped in an ApiHandle. 506// 507// Format: 508// ID - object ID 509// ID - ApiHandle address 510void HeapProfiler::writeApiHandleRoot(void* handle, RawObject obj) { 511 SubRecord sub(kRootJniGlobal, current_record_); 512 // object ID 513 sub.writeObjectId(objectId(obj)); 514 // ApiHandle address 515 sub.writeObjectId(reinterpret_cast<uword>(handle)); 516} 517 518// ROOT UNKNOWN - 0xFF 519// 520// Describes an object of unknown provenance (typically Runtime or Thread root). 521// 522// Format: 523// ID - object ID 524void HeapProfiler::writeUnknownRoot(RawObject obj) { 525 SubRecord sub(kRootUnknown, current_record_); 526 // object ID 527 sub.writeObjectId(objectId(obj)); 528} 529 530// ROOT NATIVE STACK - 0x04 531// 532// Describes an object inside a native frame (in a Handle). 533// 534// Format: 535// ID - object ID 536// u4 - thread serial number 537void HeapProfiler::writeHandleRoot(RawObject obj) { 538 SubRecord sub(kRootNativeStack, current_record_); 539 // object ID 540 sub.writeObjectId(objectId(obj)); 541 // thread serial number 542 // TODO(T70833159): Support multiple threads in heap dumper. 543 sub.write32(0); 544} 545 546// STRING IN UTF8 - 0x01 547// 548// Format: 549// ID - ID for this string 550// [u1]* - UTF8 characters for string (NOT NULL terminated) 551void HeapProfiler::writeStringInUTF8(RawStr str) { 552 Record record(kStringInUtf8, this); 553 record.writeObjectId(str.raw()); 554 for (word i = 0, length = str.length(); i < length; i++) { 555 record.write8(str.byteAt(i)); 556 } 557} 558 559void HeapProfiler::writeCStringInUTF8(const char* c_str) { 560 Record record(kStringInUtf8, this); 561 record.writeObjectId(reinterpret_cast<uword>(c_str)); 562 for (; *c_str != '\0'; ++c_str) { 563 record.write8(*c_str); 564 } 565} 566 567HeapProfiler::Buffer::Buffer() : data_(Vector<uint8_t>()) {} 568 569void HeapProfiler::Buffer::write(const uint8_t* data, word size) { 570 for (word i = 0; i < size; i++) { 571 data_.push_back(data[i]); 572 } 573} 574 575void HeapProfiler::write8(uint8_t value) { write(&value, sizeof(value)); } 576 577void HeapProfiler::write16(uint16_t value) { 578 for (word i = 1; i >= 0; i--) { 579 write8((value >> (i * kBitsPerByte)) & 0xff); 580 } 581} 582 583void HeapProfiler::write32(uint32_t value) { 584 for (word i = 3; i >= 0; i--) { 585 write8((value >> (i * kBitsPerByte)) & 0xff); 586 } 587} 588 589void HeapProfiler::write64(uint64_t value) { 590 for (word i = 7; i >= 0; i--) { 591 write8((value >> (i * kBitsPerByte)) & 0xff); 592 } 593} 594 595HeapProfiler::Record::Record(Tag tag, HeapProfiler* profiler) 596 : tag_(tag), profiler_(profiler) {} 597 598// Record 599// 600// Format: 601// u1 - TAG: denoting the type of the record 602// u4 - TIME: number of microseconds since the time stamp in the header 603// u4 - LENGTH: number of bytes that follow this u4 field and belong 604// to this record 605// [u1]* - BODY: as many bytes as specified in the above u4 field 606HeapProfiler::Record::~Record() { 607 if (profiler_) { 608 profiler_->write8(tag()); 609 profiler_->write32(time()); 610 profiler_->write32(length()); 611 if (length() > 0) { 612 profiler_->write(body(), length()); 613 } 614 } 615} 616 617void HeapProfiler::Record::write(const byte* value, word size) { 618 body_.write(value, size); 619} 620 621void HeapProfiler::Record::write8(uint8_t value) { 622 body_.write(&value, sizeof(value)); 623} 624 625void HeapProfiler::Record::write16(uint16_t value) { 626 for (word i = 1; i >= 0; i--) { 627 write8((value >> (i * kBitsPerByte)) & 0xff); 628 } 629} 630 631void HeapProfiler::Record::write32(uint32_t value) { 632 for (word i = 3; i >= 0; i--) { 633 write8((value >> (i * kBitsPerByte)) & 0xff); 634 } 635} 636 637void HeapProfiler::Record::write64(uint64_t value) { 638 for (word i = 7; i >= 0; i--) { 639 write8((value >> (i * kBitsPerByte)) & 0xff); 640 } 641} 642 643void HeapProfiler::Record::writeObjectId(uword value) { write64(value); } 644 645HeapProfiler::SubRecord::SubRecord(Subtag sub_tag, Record* record) 646 : record_(record) { 647 DCHECK(record_ != nullptr, "heap dump segment does not exist"); 648 record_->write8(sub_tag); 649} 650 651void HeapProfiler::SubRecord::beginInstanceDump(RawObject obj, 652 uword stack_trace, 653 uword num_bytes, 654 uword layout_id) { 655 // TODO(emacs): This is a hack that works around MAT expecting ClassLoader at 656 // 0. Once we have modified MAT to dump ClassLoader at a different location 657 // than 0, we should just dump SmallInt 0 normally. 658 word id = obj.raw() == 0 ? 73 : obj.raw(); 659 writeObjectId(id); 660 write32(stack_trace); 661 writeObjectId(layout_id); 662 write32(num_bytes); 663} 664 665void HeapProfiler::SubRecord::beginPrimitiveArrayDump(uword object_id, 666 uword stack_trace, 667 uword length, 668 BasicType type) { 669 writeObjectId(object_id); 670 write32(stack_trace); 671 CHECK(length < kMaxUint32, "length %ld too big for Java length field", 672 length); 673 write32(static_cast<uint32_t>(length)); 674 write8(type); 675} 676 677void HeapProfiler::SubRecord::write(const uint8_t* value, intptr_t size) { 678 record_->write(value, size); 679} 680 681void HeapProfiler::SubRecord::write8(uint8_t value) { record_->write8(value); } 682 683void HeapProfiler::SubRecord::write16(uint16_t value) { 684 record_->write16(value); 685} 686 687void HeapProfiler::SubRecord::write32(uint32_t value) { 688 record_->write32(value); 689} 690 691void HeapProfiler::SubRecord::write64(uint64_t value) { 692 record_->write64(value); 693} 694 695void HeapProfiler::SubRecord::writeObjectId(uword value) { 696 record_->writeObjectId(value); 697} 698 699static void writeToFileStream(const void* data, word length, void* stream) { 700 DCHECK(data != nullptr, "data must not be null"); 701 DCHECK(length > 0, "length must be positive"); 702 word fd = static_cast<int>(reinterpret_cast<word>(stream)); 703 int result = File::write(fd, data, length); 704 CHECK(result == length, "could not write the whole chunk to disk"); 705} 706 707class HeapProfilerHandleVisitor : public HandleVisitor { 708 public: 709 HeapProfilerHandleVisitor(HeapProfiler* profiler) : profiler_(profiler) {} 710 void visitHandle(void* handle, RawObject obj) { 711 return profiler_->writeApiHandleRoot(handle, obj); 712 } 713 714 protected: 715 HeapProfiler* profiler_; 716 717 DISALLOW_COPY_AND_ASSIGN(HeapProfilerHandleVisitor); 718}; 719 720class HeapProfilerRootVisitor : public PointerVisitor { 721 public: 722 HeapProfilerRootVisitor(HeapProfiler* profiler) : profiler_(profiler) {} 723 void visitPointer(RawObject* pointer, PointerKind kind) { 724 // TODO(emacs): This is a hack that works around MAT expecting ClassLoader 725 // at 0. Once we have modified MAT to dump ClassLoader at a different 726 // location than 0, we should just dump SmallInt 0 normally. 727 RawObject obj = RawObject{pointer->raw() == 0 ? 73 : pointer->raw()}; 728 switch (kind) { 729 case PointerKind::kRuntime: 730 case PointerKind::kThread: 731 case PointerKind::kUnknown: 732 return profiler_->writeUnknownRoot(obj); 733 case PointerKind::kHandle: 734 return profiler_->writeHandleRoot(obj); 735 case PointerKind::kStack: 736 return profiler_->writeStackRoot(obj); 737 case PointerKind::kApiHandle: 738 // Should only see handles in `HeapProfilerHandleVisitor`. 739 UNREACHABLE("should not be used"); 740 case PointerKind::kLayout: 741 return profiler_->writeStickyClassRoot(obj); 742 } 743 } 744 745 protected: 746 HeapProfiler* profiler_; 747 748 DISALLOW_COPY_AND_ASSIGN(HeapProfilerRootVisitor); 749}; 750 751class HeapProfilerObjectVisitor : public HeapObjectVisitor { 752 public: 753 HeapProfilerObjectVisitor(HeapProfiler* profiler) : profiler_(profiler) {} 754 void visitHeapObject(RawHeapObject obj) { 755 switch (obj.layoutId()) { 756 case LayoutId::kLayout: 757 return profiler_->writeClassDump(Layout::cast(obj)); 758 case LayoutId::kLargeInt: 759 return profiler_->writeLargeInt(LargeInt::cast(obj)); 760 case LayoutId::kLargeBytes: 761 case LayoutId::kMutableBytes: 762 return profiler_->writeBytes(Bytes::cast(obj)); 763 case LayoutId::kFloat: 764 return profiler_->writeFloat(Float::cast(obj)); 765 case LayoutId::kComplex: 766 return profiler_->writeComplex(Complex::cast(obj)); 767 case LayoutId::kTuple: 768 case LayoutId::kMutableTuple: 769 return profiler_->writeObjectArray(Tuple::cast(obj)); 770 case LayoutId::kLargeStr: 771 return profiler_->writeLargeStr(LargeStr::cast(obj)); 772 case LayoutId::kEllipsis: 773 return profiler_->writeEllipsis(Ellipsis::cast(obj)); 774 default: 775 CHECK(obj.isInstance(), "obj should be instance, but is %ld", 776 obj.layoutId()); 777 return profiler_->writeInstanceDump(Instance::cast(obj)); 778 } 779 } 780 781 protected: 782 HeapProfiler* profiler_; 783 784 DISALLOW_COPY_AND_ASSIGN(HeapProfilerObjectVisitor); 785}; 786 787RawObject heapDump(Thread* thread, const char* filename) { 788 int fd = File::open( 789 filename, 790 File::kBinaryFlag | File::kCreate | File::kTruncate | File::kWriteOnly, 791 0644); 792 if (fd < 0) { 793 int saved_errno = errno; 794 return thread->raiseOSErrorFromErrno(saved_errno); 795 } 796 797 HeapProfiler profiler(thread, writeToFileStream, reinterpret_cast<void*>(fd)); 798 profiler.writeHeader(); 799 profiler.writeFakeStackTrace(); 800 801 { 802 HeapProfiler::Record record(HeapProfiler::kHeapDumpSegment, &profiler); 803 profiler.setRecord(&record); 804 profiler.writeThreadRoot(thread); 805 // java.lang.Class 806 profiler.writeFakeClassDump(HeapProfiler::FakeClass::kJavaLangClass, 807 HeapProfiler::kJavaLangClass, 808 HeapProfiler::FakeClass::kJavaLangObject); 809 // java.lang.ClassLoader 810 profiler.writeFakeClassDump(HeapProfiler::FakeClass::kJavaLangClassLoader, 811 HeapProfiler::kJavaLangClassLoader, 812 HeapProfiler::FakeClass::kJavaLangObject); 813 // java.lang.Object 814 profiler.writeFakeClassDump(HeapProfiler::FakeClass::kJavaLangObject, 815 HeapProfiler::kJavaLangObject, 816 static_cast<HeapProfiler::FakeClass>(0x0)); 817 // java.lang.String 818 profiler.writeFakeClassDump(HeapProfiler::FakeClass::kJavaLangString, 819 HeapProfiler::kJavaLangString, 820 HeapProfiler::FakeClass::kJavaLangObject); 821 // byte[] 822 profiler.writeFakeClassDump(HeapProfiler::FakeClass::kBytearray, 823 HeapProfiler::kBytearrayClassName, 824 HeapProfiler::FakeClass::kJavaLangObject); 825 // double[] 826 profiler.writeFakeClassDump(HeapProfiler::FakeClass::kDoubleArray, 827 HeapProfiler::kDoubleArrayClassName, 828 HeapProfiler::FakeClass::kJavaLangObject); 829 // long[] 830 profiler.writeFakeClassDump(HeapProfiler::FakeClass::kLongArray, 831 HeapProfiler::kLongArrayClassName, 832 HeapProfiler::FakeClass::kJavaLangObject); 833 // java.lang.Object[] 834 profiler.writeFakeClassDump(HeapProfiler::FakeClass::kObjectArray, 835 HeapProfiler::kObjectArrayClassName, 836 HeapProfiler::FakeClass::kJavaLangObject); 837 838 Runtime* runtime = thread->runtime(); 839 840 HeapProfilerRootVisitor root_visitor(&profiler); 841 runtime->visitRootsWithoutApiHandles(&root_visitor); 842 HeapProfilerHandleVisitor handle_visitor(&profiler); 843 visitApiHandles(runtime, &handle_visitor); 844 845 HeapProfilerObjectVisitor object_visitor(&profiler); 846 runtime->heap()->visitAllObjects(&object_visitor); 847 848 profiler.writeImmediates(); 849 profiler.clearRecord(); 850 } 851 profiler.writeHeapDumpEnd(); 852 int result = File::close(fd); 853 CHECK(result == 0, "could not close file '%s'", filename); 854 return NoneType::object(); 855} 856 857} // namespace py