Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 #include "vm/heap_profiler.h" | |
| 6 | |
| 7 #include <stdio.h> | |
| 8 #include <arpa/inet.h> | |
| 9 #include <sys/time.h> | |
| 10 | |
| 11 #include "vm/dart_api_state.h" | |
| 12 #include "vm/object.h" | |
| 13 #include "vm/raw_object.h" | |
| 14 #include "vm/stack_frame.h" | |
| 15 #include "vm/unicode.h" | |
| 16 | |
| 17 namespace dart { | |
| 18 | |
| 19 HeapProfiler::Buffer::~Buffer() { | |
| 20 delete[] data_; | |
| 21 } | |
| 22 | |
| 23 | |
| 24 void HeapProfiler::Buffer::Write(const uint8_t* data, intptr_t size) { | |
| 25 EnsureCapacity(size); | |
| 26 memmove(&data_[size_], data, size); | |
| 27 size_ += size; | |
|
turnidge
2012/06/12 17:02:19
It's a bit confusing to me to have both "name_" an
cshapiro
2012/06/14 00:08:36
I see where you are coming from. I would like thi
| |
| 28 } | |
| 29 | |
| 30 | |
| 31 void HeapProfiler::Buffer::EnsureCapacity(intptr_t size) { | |
| 32 if ((size + size_) > capacity_) { | |
| 33 intptr_t new_capacity = Utils::RoundUpToPowerOfTwo(capacity_ + size); | |
| 34 uint8_t* new_data = new uint8_t[new_capacity]; | |
| 35 memmove(new_data, data_, size_); | |
| 36 capacity_ = new_capacity; | |
| 37 data_ = new_data; | |
| 38 } | |
| 39 } | |
| 40 | |
| 41 | |
| 42 void HeapProfiler::Record::Write(const uint8_t* value, intptr_t size) { | |
| 43 body_.Write(value, size); | |
| 44 } | |
| 45 | |
| 46 | |
| 47 void HeapProfiler::Record::Write8(uint8_t value) { | |
| 48 body_.Write(&value, sizeof(value)); | |
| 49 } | |
| 50 | |
| 51 | |
| 52 void HeapProfiler::Record::Write16(uint16_t value) { | |
| 53 value = htons(value); | |
| 54 body_.Write(reinterpret_cast<uint8_t*>(&value), sizeof(value)); | |
| 55 } | |
| 56 | |
| 57 | |
| 58 void HeapProfiler::Record::Write32(uint32_t value) { | |
| 59 value = htonl(value); | |
| 60 body_.Write(reinterpret_cast<uint8_t*>(&value), sizeof(value)); | |
| 61 } | |
| 62 | |
| 63 | |
| 64 void HeapProfiler::Record::Write64(uint64_t value) { | |
| 65 uint16_t x = 0xFF; | |
| 66 if (*reinterpret_cast<uint8_t*>(&x) == 0xFF) { | |
| 67 uint64_t hi = static_cast<uint64_t>(htonl(value & 0xFFFFFFFF)) << 32; | |
| 68 uint64_t lo = htonl(value >> 32); | |
| 69 value = hi | lo; | |
| 70 } | |
| 71 body_.Write(reinterpret_cast<uint8_t*>(&value), sizeof(value)); | |
| 72 } | |
| 73 | |
| 74 | |
| 75 void HeapProfiler::Record::WritePointer(const void* value) { | |
| 76 if (sizeof(value) == 4) { | |
| 77 Write32(reinterpret_cast<uint32_t>(value)); | |
| 78 } else { | |
| 79 ASSERT(sizeof(value) == 8); | |
| 80 Write64(reinterpret_cast<uint64_t>(value)); | |
| 81 } | |
| 82 } | |
| 83 | |
| 84 | |
| 85 HeapProfiler::SubRecord::SubRecord(uint8_t sub_tag, HeapProfiler* profiler) | |
| 86 : record_(profiler->heap_dump_record_) { | |
| 87 record_->Write8(sub_tag); | |
| 88 } | |
| 89 | |
| 90 | |
| 91 HeapProfiler::SubRecord::~SubRecord() { | |
| 92 } | |
| 93 | |
| 94 | |
| 95 void HeapProfiler::SubRecord::Write(const uint8_t* value, intptr_t size) { | |
| 96 record_->Write(value, size); | |
| 97 } | |
| 98 | |
| 99 | |
| 100 void HeapProfiler::SubRecord::Write8(uint8_t value) { | |
| 101 record_->Write8(value); | |
| 102 } | |
| 103 | |
| 104 | |
| 105 void HeapProfiler::SubRecord::Write16(uint16_t value) { | |
| 106 record_->Write16(value); | |
| 107 } | |
| 108 | |
| 109 | |
| 110 void HeapProfiler::SubRecord::Write32(uint32_t value) { | |
| 111 record_->Write32(value); | |
| 112 } | |
| 113 | |
| 114 | |
| 115 void HeapProfiler::SubRecord::Write64(uint64_t value) { | |
| 116 record_->Write64(value); | |
| 117 } | |
| 118 | |
| 119 | |
| 120 void HeapProfiler::SubRecord::WritePointer(const void* value) { | |
| 121 record_->WritePointer(value); | |
| 122 } | |
| 123 | |
| 124 | |
| 125 HeapProfiler::HeapProfiler(Dart_HeapProfileWriteCallback callback, void* stream) | |
| 126 : write_callback_(callback), | |
| 127 output_stream_(stream), | |
| 128 heap_dump_record_(NULL) { | |
| 129 WriteHeader(); | |
| 130 WriteStackTrace(); | |
| 131 heap_dump_record_ = new Record(kHeapDump, this); | |
| 132 } | |
| 133 | |
| 134 | |
| 135 HeapProfiler::~HeapProfiler() { | |
| 136 delete heap_dump_record_; | |
| 137 } | |
| 138 | |
| 139 | |
| 140 const RawObject* HeapProfiler::ObjectId(const RawObject* raw_obj) { | |
| 141 if (!raw_obj->IsHeapObject()) { | |
| 142 // To describe an immediate object in HPROF we record its value | |
| 143 // and write fake INSTANCE_DUMP subrecord in the HEAP_DUMP record. | |
| 144 const RawSmi* raw_smi = reinterpret_cast<const RawSmi*>(raw_obj); | |
| 145 if (smi_table_.find(raw_smi) == smi_table_.end()) { | |
| 146 smi_table_.insert(raw_smi); | |
| 147 } | |
| 148 } else if (raw_obj->GetClassId() == kNullClassId) { | |
| 149 // Instances of the Null type are translated to NULL so they can | |
| 150 // be printed as "null" in HAT. | |
| 151 return NULL; | |
| 152 } | |
| 153 return raw_obj; | |
| 154 } | |
| 155 | |
| 156 | |
| 157 const RawClass* HeapProfiler::ClassId(const RawClass* raw_class) { | |
| 158 // A unique LOAD_CLASS record must be written for each class object. | |
| 159 if (class_table_.find(raw_class) == class_table_.end()) { | |
| 160 class_table_.insert(raw_class); | |
| 161 WriteLoadClass(raw_class); | |
| 162 } | |
| 163 return raw_class; | |
| 164 } | |
| 165 | |
| 166 | |
| 167 // A built-in class may have its name encoded in a C-string. These | |
| 168 // strings should only be found in class objects. We emit a unique | |
| 169 // STRING_IN_UTF8 so HAT will properly display the class name. | |
| 170 const char* HeapProfiler::StringId(const char* c_string) { | |
| 171 const RawString* ptr = reinterpret_cast<const RawString*>(c_string); | |
| 172 if (string_table_.find(ptr) == string_table_.end()) { | |
| 173 string_table_.insert(ptr); | |
| 174 WriteStringInUtf8(c_string); | |
| 175 } | |
| 176 return c_string; | |
| 177 } | |
| 178 | |
| 179 | |
| 180 const RawString* HeapProfiler::StringId(const RawString* raw_string) { | |
| 181 // A unique STRING_IN_UTF8 record must be written for each string | |
| 182 // object. | |
| 183 if (string_table_.find(raw_string) == string_table_.end()) { | |
| 184 string_table_.insert(raw_string); | |
| 185 WriteStringInUtf8(raw_string); | |
| 186 } | |
| 187 return raw_string; | |
| 188 } | |
| 189 | |
| 190 | |
| 191 void HeapProfiler::WriteRoot(const RawObject* raw_obj) { | |
| 192 SubRecord sub(kRootUnknown, this); | |
| 193 sub.WritePointer(ObjectId(raw_obj)); | |
| 194 } | |
| 195 | |
| 196 | |
| 197 void HeapProfiler::WriteObject(const RawObject* raw_obj) { | |
| 198 ASSERT(raw_obj->IsHeapObject()); | |
| 199 if (FreeListElement::IsSpecialClass(raw_obj)) { | |
| 200 // Free space has an object-like encoding. Heap profiles only | |
| 201 // care about live objects so we skip over these records. | |
| 202 return; | |
| 203 } | |
| 204 ObjectKind kind = raw_obj->ptr()->class_->ptr()->instance_kind_; | |
| 205 switch (kind) { | |
| 206 case Class::kInstanceKind: { | |
| 207 WriteClassDump(reinterpret_cast<const RawClass*>(raw_obj)); | |
| 208 break; | |
| 209 } | |
| 210 case Array::kInstanceKind: | |
| 211 case ImmutableArray::kInstanceKind: { | |
| 212 WriteObjectArrayDump(reinterpret_cast<const RawArray*>(raw_obj)); | |
| 213 break; | |
| 214 } | |
| 215 case Int8Array::kInstanceKind: | |
| 216 case Uint8Array::kInstanceKind: { | |
| 217 const RawInt8Array* raw_int8_array = | |
| 218 reinterpret_cast<const RawInt8Array*>(raw_obj); | |
| 219 WritePrimitiveArrayDump(raw_int8_array, | |
| 220 kByte, | |
| 221 &raw_int8_array->data_[0]); | |
| 222 break; | |
| 223 } | |
| 224 case Int16Array::kInstanceKind: | |
| 225 case Uint16Array::kInstanceKind: { | |
| 226 const RawInt16Array* raw_int16_array = | |
| 227 reinterpret_cast<const RawInt16Array*>(raw_obj); | |
| 228 WritePrimitiveArrayDump(raw_int16_array, | |
| 229 kShort, | |
| 230 &raw_int16_array->data_[0]); | |
| 231 break; | |
| 232 } | |
| 233 case Int32Array::kInstanceKind: | |
| 234 case Uint32Array::kInstanceKind: { | |
| 235 const RawInt32Array* raw_int32_array = | |
| 236 reinterpret_cast<const RawInt32Array*>(raw_obj); | |
| 237 WritePrimitiveArrayDump(raw_int32_array, | |
| 238 kInt, | |
| 239 &raw_int32_array->data_[0]); | |
| 240 break; | |
| 241 } | |
| 242 case Int64Array::kInstanceKind: | |
| 243 case Uint64Array::kInstanceKind: { | |
| 244 const RawInt64Array* raw_int64_array = | |
| 245 reinterpret_cast<const RawInt64Array*>(raw_obj); | |
| 246 WritePrimitiveArrayDump(raw_int64_array, | |
| 247 kLong, | |
| 248 &raw_int64_array->data_[0]); | |
| 249 break; | |
| 250 } | |
| 251 case Float32Array::kInstanceKind: { | |
| 252 const RawFloat32Array* raw_float32_array = | |
| 253 reinterpret_cast<const RawFloat32Array*>(raw_obj); | |
| 254 WritePrimitiveArrayDump(raw_float32_array, | |
| 255 kFloat, | |
| 256 &raw_float32_array->data_[0]); | |
| 257 break; | |
| 258 } | |
| 259 case Float64Array::kInstanceKind: { | |
| 260 const RawFloat64Array* raw_float64_array = | |
| 261 reinterpret_cast<const RawFloat64Array*>(raw_obj); | |
| 262 WritePrimitiveArrayDump(raw_float64_array, | |
| 263 kDouble, | |
| 264 &raw_float64_array->data_[0]); | |
| 265 break; | |
| 266 } | |
| 267 case OneByteString::kInstanceKind: | |
| 268 case TwoByteString::kInstanceKind: | |
| 269 case FourByteString::kInstanceKind: | |
| 270 case ExternalOneByteString::kInstanceKind: | |
| 271 case ExternalTwoByteString::kInstanceKind: | |
| 272 case ExternalFourByteString::kInstanceKind: { | |
| 273 WriteInstanceDump(StringId(reinterpret_cast<const RawString*>(raw_obj))); | |
| 274 break; | |
| 275 } | |
| 276 default: | |
| 277 WriteInstanceDump(raw_obj); | |
| 278 } | |
| 279 } | |
| 280 | |
| 281 | |
| 282 void HeapProfiler::Write(const void* data, intptr_t size) { | |
| 283 (*write_callback_)(data, size, output_stream_); | |
| 284 } | |
| 285 | |
| 286 | |
| 287 // Header | |
| 288 // | |
| 289 // Format: | |
| 290 // [u1]* - format name | |
| 291 // u4 - size of identifiers | |
| 292 // u4 - high word of number of milliseconds since 0:00 GMT, 1/1/70 | |
| 293 // u4 - low word of number of milliseconds since 0:00 GMT, 1/1/70 | |
| 294 void HeapProfiler::WriteHeader() { | |
| 295 const char magic[] = "JAVA PROFILE 1.0.1"; | |
| 296 Write(magic, sizeof(magic)); | |
| 297 uint32_t size = htonl(kWordSize); | |
| 298 Write(&size, sizeof(size)); | |
| 299 uint64_t milliseconds = OS::GetCurrentTimeMillis(); | |
| 300 uint32_t hi = htonl((uint32_t)((milliseconds >> 32) & 0x00000000FFFFFFFF)); | |
| 301 Write(&hi, sizeof(hi)); | |
| 302 uint32_t lo = htonl((uint32_t)(milliseconds & 0x00000000FFFFFFFF)); | |
| 303 Write(&lo, sizeof(lo)); | |
| 304 } | |
| 305 | |
| 306 | |
| 307 // Record | |
| 308 // | |
| 309 // Format: | |
| 310 // u1 - TAG: denoting the type of the record | |
| 311 // u4 - TIME: number of microseconds since the time stamp in the header | |
| 312 // u4 - LENGTH: number of bytes that follow this u4 field and belong | |
| 313 // to this record | |
| 314 // [u1]* - BODY: as many bytes as specified in the above u4 field | |
| 315 void HeapProfiler::WriteRecord(const Record& record) { | |
| 316 uint8_t tag = record.Tag(); | |
| 317 Write(&tag, sizeof(tag)); | |
| 318 uint32_t time = htonl(record.Time()); | |
| 319 Write(&time, sizeof(time)); | |
| 320 uint32_t length = htonl(record.Length()); | |
| 321 Write(&length, sizeof(length)); | |
| 322 Write(record.Body(), record.Length()); | |
| 323 } | |
| 324 | |
| 325 | |
| 326 // STRING IN UTF8 - 0x01 | |
| 327 // | |
| 328 // Format: | |
| 329 // ID - ID for this string | |
| 330 // [u1]* - UTF8 characters for string (NOT NULL terminated) | |
| 331 void HeapProfiler::WriteStringInUtf8(const RawString* raw_string) { | |
| 332 intptr_t length = 0; | |
| 333 char* characters = NULL; | |
| 334 ObjectKind kind = raw_string->ptr()->class_->ptr()->instance_kind_; | |
| 335 if (kind == OneByteString::kInstanceKind) { | |
| 336 const RawOneByteString* onestr = | |
| 337 reinterpret_cast<const RawOneByteString*>(raw_string); | |
| 338 for (intptr_t i = 0; i < Smi::Value(onestr->ptr()->length_); ++i) { | |
| 339 length += Utf8::Length(onestr->ptr()->data_[i]); | |
| 340 } | |
| 341 characters = new char[length]; | |
| 342 for (intptr_t i = 0, j = 0; i < Smi::Value(onestr->ptr()->length_); ++i) { | |
| 343 int32_t ch = onestr->ptr()->data_[i]; | |
| 344 j += Utf8::Encode(ch, &characters[j]); | |
| 345 } | |
| 346 } else if (kind == TwoByteString::kInstanceKind) { | |
| 347 const RawTwoByteString* twostr = | |
| 348 reinterpret_cast<const RawTwoByteString*>(raw_string); | |
| 349 for (intptr_t i = 0; i < Smi::Value(twostr->ptr()->length_); ++i) { | |
| 350 length += Utf8::Length(twostr->ptr()->data_[i]); | |
| 351 } | |
| 352 characters = new char[length]; | |
| 353 for (intptr_t i = 0, j = 0; i < Smi::Value(twostr->ptr()->length_); ++i) { | |
| 354 int32_t ch = twostr->ptr()->data_[i]; | |
| 355 j += Utf8::Encode(ch, &characters[j]); | |
| 356 } | |
| 357 } else { | |
| 358 ASSERT(kind == FourByteString::kInstanceKind); | |
| 359 const RawFourByteString* fourstr = | |
| 360 reinterpret_cast<const RawFourByteString*>(raw_string); | |
| 361 for (intptr_t i = 0; i < Smi::Value(fourstr->ptr()->length_); ++i) { | |
| 362 length += Utf8::Length(fourstr->ptr()->data_[i]); | |
| 363 } | |
| 364 characters = new char[length]; | |
| 365 for (intptr_t i = 0, j = 0; i < Smi::Value(fourstr->ptr()->length_); ++i) { | |
| 366 int32_t ch = fourstr->ptr()->data_[i]; | |
| 367 j += Utf8::Encode(ch, &characters[j]); | |
| 368 } | |
| 369 } | |
| 370 Record record(kStringInUtf8, this); | |
| 371 record.WritePointer(ObjectId(raw_string)); | |
| 372 for (intptr_t i = 0; i < length; ++i) { | |
| 373 record.Write8(characters[i]); | |
| 374 } | |
| 375 delete[] characters; | |
| 376 } | |
| 377 | |
| 378 | |
| 379 void HeapProfiler::WriteStringInUtf8(const char* c_string) { | |
| 380 Record record(kStringInUtf8, this); | |
| 381 record.WritePointer(c_string); | |
| 382 for (; *c_string != '\0'; ++c_string) { | |
| 383 record.Write8(*c_string); | |
| 384 } | |
| 385 } | |
| 386 | |
| 387 | |
| 388 // LOAD CLASS - 0x02 | |
| 389 // | |
| 390 // Format: | |
| 391 // u4 - class serial number (always > 0) | |
| 392 // ID - class object ID | |
| 393 // u4 - stack trace serial number | |
| 394 // ID - class name string ID | |
| 395 void HeapProfiler::WriteLoadClass(const RawClass* raw_class) { | |
| 396 Record record(kLoadClass, this); | |
| 397 // class serial number (always > 0) | |
| 398 record.Write32(1); | |
| 399 // class object ID | |
| 400 record.WritePointer(raw_class); | |
| 401 // stack trace serial number | |
| 402 record.Write32(0); | |
| 403 if (raw_class->ptr()->name_ == String::null()) { | |
| 404 intptr_t class_index = Object::GetSingletonClassIndex(raw_class); | |
| 405 const char* name = Object::GetSingletonClassName(class_index); | |
| 406 record.WritePointer(StringId(name)); | |
| 407 } else { | |
| 408 record.WritePointer(StringId(raw_class->ptr()->name_)); | |
| 409 } | |
| 410 } | |
| 411 | |
| 412 | |
| 413 // STACK TRACE - 0x05 | |
| 414 // | |
| 415 // u4 - stack trace serial number | |
| 416 // u4 - thread serial number | |
| 417 // u4 - number of frames | |
| 418 // [ID]* - series of stack frame ID's | |
| 419 void HeapProfiler::WriteStackTrace() { | |
| 420 Record record(kStackTrace, this); | |
| 421 // stack trace serial number | |
| 422 record.Write32(0); | |
| 423 // thread serial number | |
| 424 record.Write32(0); | |
| 425 // number of frames | |
| 426 record.Write32(0); | |
| 427 } | |
| 428 | |
| 429 | |
| 430 // HEAP SUMMARY - 0x07 | |
| 431 // | |
| 432 // Format: | |
| 433 // u4 - total live bytes | |
| 434 // u4 - total live instances | |
| 435 // u8 - total bytes allocated | |
| 436 // u8 - total instances allocated | |
| 437 void HeapProfiler::WriteHeapSummary(uint32_t total_live_bytes, | |
| 438 uint32_t total_live_instances, | |
| 439 uint64_t total_bytes_allocated, | |
| 440 uint64_t total_instances_allocated) { | |
| 441 Record record(kHeapSummary, this); | |
| 442 record.Write32(total_live_bytes); | |
| 443 record.Write32(total_live_instances); | |
| 444 record.Write32(total_bytes_allocated); | |
| 445 record.Write32(total_instances_allocated); | |
| 446 } | |
| 447 | |
| 448 | |
| 449 // HEAP DUMP - 0x0C | |
| 450 // | |
| 451 // Format: | |
| 452 // []* | |
| 453 void HeapProfiler::WriteHeapDump() { | |
| 454 Record record(kHeapDump, this); | |
| 455 } | |
| 456 | |
| 457 | |
| 458 // CLASS DUMP - 0x20 | |
| 459 // | |
| 460 // Format: | |
| 461 // ID - class object ID | |
| 462 // u4 - stack trace serial number | |
| 463 // ID - super class object ID | |
| 464 // ID - class loader object ID | |
| 465 // ID - signers object ID | |
| 466 // ID - protection domain object ID | |
| 467 // ID - reserved | |
| 468 // ID - reserved | |
| 469 // u4 - instance size (in bytes) | |
| 470 // u2 - size of constant pool and number of records that follow: | |
| 471 // u2 - constant pool index | |
| 472 // u1 - type of entry: (See Basic Type) | |
| 473 // value - value of entry (u1, u2, u4, or u8 based on type of entry) | |
| 474 // u2 - Number of static fields: | |
| 475 // ID - static field name string ID | |
| 476 // u1 - type of field: (See Basic Type) | |
| 477 // value - value of entry (u1, u2, u4, or u8 based on type of field) | |
| 478 // u2 - Number of instance fields (not including super class's) | |
| 479 // ID - field name string ID | |
| 480 // u1 - type of field: (See Basic Type) | |
| 481 void HeapProfiler::WriteClassDump(const RawClass* raw_class) { | |
| 482 SubRecord sub(kClassDump, this); | |
| 483 // class object ID | |
| 484 sub.WritePointer(ClassId(raw_class)); | |
| 485 // stack trace serial number | |
| 486 sub.Write32(0); | |
| 487 // super class object ID | |
| 488 if (raw_class == raw_class->ptr()->class_) { | |
| 489 sub.WritePointer(NULL); | |
| 490 } else { | |
| 491 sub.WritePointer(ClassId(raw_class->ptr()->class_)); | |
| 492 } | |
| 493 // class loader object ID | |
| 494 sub.WritePointer(NULL); | |
| 495 // signers object ID | |
| 496 sub.WritePointer(NULL); | |
| 497 // protection domain object ID | |
| 498 sub.WritePointer(NULL); | |
| 499 // reserved | |
| 500 sub.WritePointer(NULL); | |
| 501 // reserved | |
| 502 sub.WritePointer(NULL); | |
| 503 | |
| 504 intptr_t num_static_fields = 0; | |
| 505 intptr_t num_instance_fields = 0; | |
| 506 | |
| 507 RawArray* raw_array = raw_class->ptr()->fields_; | |
| 508 if (raw_array != Array::null()) { | |
| 509 for (intptr_t i = 0; i < Smi::Value(raw_array->ptr()->length_); ++i) { | |
| 510 RawField* raw_field = | |
| 511 reinterpret_cast<RawField*>(raw_array->ptr()->data()[i]); | |
| 512 if (raw_field->ptr()->is_static_) { | |
| 513 ++num_static_fields; | |
| 514 } else { | |
| 515 ++num_instance_fields; | |
| 516 } | |
| 517 } | |
| 518 } | |
| 519 // instance size (in bytes) | |
| 520 sub.Write32(sizeof(RawClass)); | |
|
turnidge
2012/06/12 17:02:19
What is the instance size supposed to mean for a c
cshapiro
2012/06/14 00:08:36
It is the size of instances, not the size of the c
| |
| 521 // size of constant pool and number of records that follow: | |
| 522 sub.Write16(0); | |
| 523 // Number of static fields | |
| 524 sub.Write16(num_static_fields); | |
| 525 // Static fields: | |
| 526 if (raw_array != Array::null()) { | |
| 527 for (intptr_t i = 0; i < Smi::Value(raw_array->ptr()->length_); ++i) { | |
| 528 RawField* raw_field = | |
| 529 reinterpret_cast<RawField*>(raw_array->ptr()->data()[i]); | |
| 530 if (raw_field->ptr()->is_static_) { | |
| 531 ASSERT(raw_field->ptr()->name_ != String::null()); | |
| 532 // static field name string ID | |
| 533 sub.WritePointer(StringId(raw_field->ptr()->name_)); | |
| 534 // type of static field | |
| 535 sub.Write8(kObject); | |
| 536 // value of entry | |
| 537 sub.WritePointer(ObjectId(raw_field->ptr()->value_)); | |
| 538 } | |
| 539 } | |
| 540 } | |
| 541 // Number of instance fields (not include super class's) | |
| 542 sub.Write16(num_instance_fields); | |
| 543 // Instance fields: | |
| 544 if (raw_array != Array::null()) { | |
| 545 for (intptr_t i = 0; i < Smi::Value(raw_array->ptr()->length_); ++i) { | |
| 546 RawField* raw_field = | |
| 547 reinterpret_cast<RawField*>(raw_array->ptr()->data()[i]); | |
| 548 if (!raw_field->ptr()->is_static_) { | |
| 549 ASSERT(raw_field->ptr()->name_ != String::null()); | |
| 550 // field name string ID | |
| 551 sub.WritePointer(StringId(raw_field->ptr()->name_)); | |
| 552 // type of field | |
| 553 sub.Write8(kObject); | |
| 554 } | |
| 555 } | |
| 556 } | |
| 557 } | |
| 558 | |
| 559 | |
| 560 // INSTANCE DUMP - 0x21 | |
| 561 // | |
| 562 // Format: | |
| 563 // ID - object ID | |
| 564 // u4 - stack trace serial number | |
| 565 // ID - class object ID | |
| 566 // u4 - number of bytes that follow | |
| 567 // [value]* - instance field values (this class, followed by super class, etc) | |
| 568 void HeapProfiler::WriteInstanceDump(const RawObject* raw_obj) { | |
| 569 SubRecord sub(kInstanceDump, this); | |
| 570 // object ID | |
| 571 sub.WritePointer(raw_obj); | |
| 572 // stack trace serial number | |
| 573 sub.Write32(0); | |
| 574 // class object ID | |
| 575 sub.WritePointer(ClassId(raw_obj->ptr()->class_)); | |
| 576 // number of bytes that follow | |
| 577 intptr_t num_instance_fields = 0; | |
| 578 for (RawClass* cls = raw_obj->ptr()->class_; | |
| 579 cls != cls->ptr()->class_; | |
| 580 cls = cls->ptr()->class_) { | |
| 581 RawArray* raw_array = cls->ptr()->fields_; | |
| 582 if (raw_array != Array::null()) { | |
| 583 intptr_t length = Smi::Value(raw_array->ptr()->length_); | |
| 584 for (intptr_t i = 0; i < length; ++i) { | |
| 585 RawField* raw_field = | |
| 586 reinterpret_cast<RawField*>(raw_array->ptr()->data()[i]); | |
| 587 if (!raw_field->ptr()->is_static_) { | |
| 588 ++num_instance_fields; | |
| 589 } | |
| 590 } | |
| 591 } | |
| 592 } | |
| 593 sub.Write32(num_instance_fields * kWordSize); | |
| 594 // instance field values (this class, followed by super class, etc) | |
| 595 for (RawClass* cls = raw_obj->ptr()->class_; | |
| 596 cls != cls->ptr()->class_; | |
| 597 cls = cls->ptr()->class_) { | |
| 598 RawArray* raw_array = cls->ptr()->fields_; | |
| 599 if (raw_array != Array::null()) { | |
| 600 intptr_t length = Smi::Value(raw_array->ptr()->length_); | |
| 601 uint8_t* base = reinterpret_cast<uint8_t*>(raw_obj->ptr()); | |
| 602 for (intptr_t i = 0; i < length; ++i) { | |
| 603 RawField* raw_field = | |
| 604 reinterpret_cast<RawField*>(raw_array->ptr()->data()[i]); | |
| 605 if (!raw_field->ptr()->is_static_) { | |
| 606 intptr_t offset = | |
| 607 Smi::Value(reinterpret_cast<RawSmi*>(raw_field->ptr()->value_)); | |
| 608 RawObject* ptr = *reinterpret_cast<RawObject**>(base + offset); | |
| 609 sub.WritePointer(ObjectId(ptr)); | |
| 610 } | |
| 611 } | |
| 612 } | |
| 613 } | |
| 614 } | |
| 615 | |
| 616 | |
| 617 // OBJECT ARRAY DUMP - 0x22 | |
| 618 // | |
| 619 // Format: | |
| 620 // ID - array object ID | |
| 621 // u4 - stack trace serial number | |
| 622 // u4 - number of elements | |
| 623 // ID - array class object ID | |
| 624 // [ID]* - elements | |
| 625 void HeapProfiler::WriteObjectArrayDump(const RawArray* raw_array) { | |
| 626 SubRecord sub(kObjectArrayDump, this); | |
| 627 // array object ID | |
| 628 sub.WritePointer(raw_array); | |
| 629 // stack trace serial number | |
| 630 sub.Write32(0); | |
| 631 // number of elements | |
| 632 intptr_t length = Smi::Value(raw_array->ptr()->length_); | |
| 633 sub.Write32(length); | |
| 634 // array class object ID | |
| 635 sub.WritePointer(NULL); | |
| 636 // elements | |
| 637 for (intptr_t i = 0; i < length; ++i) { | |
| 638 sub.WritePointer(ObjectId(raw_array->ptr()->data()[i])); | |
| 639 } | |
| 640 } | |
| 641 | |
| 642 | |
| 643 // PRIMITIVE ARRAY DUMP - 0x23 | |
| 644 // | |
| 645 // Format: | |
| 646 // ID - array object ID | |
| 647 // u4 - stack trace serial number | |
| 648 // u4 - number of elements | |
| 649 // u1 - element type | |
| 650 // [u1]* - elements | |
| 651 void HeapProfiler::WritePrimitiveArrayDump(const RawByteArray* raw_byte_array, | |
| 652 uint8_t tag, | |
| 653 const void* data) { | |
| 654 SubRecord sub(kPrimitiveArrayDump, this); | |
| 655 // array object ID | |
| 656 sub.WritePointer(raw_byte_array); | |
| 657 // stack trace serial number | |
| 658 sub.Write32(0); | |
| 659 // number of elements | |
| 660 intptr_t length = Smi::Value(raw_byte_array->ptr()->length_); | |
| 661 sub.Write32(length); | |
| 662 // element type | |
| 663 sub.Write8(tag); | |
| 664 // elements (packed) | |
| 665 for (intptr_t i = 0; i < length; ++i) { | |
| 666 if (tag == kByte) { | |
| 667 sub.Write8(reinterpret_cast<const int8_t*>(data)[i]); | |
| 668 } else if (tag == kShort) { | |
| 669 sub.Write16(reinterpret_cast<const int16_t*>(data)[i]); | |
| 670 break; | |
| 671 } else if (tag == kInt || tag == kFloat) { | |
| 672 sub.Write32(reinterpret_cast<const int32_t*>(data)[i]); | |
| 673 } else { | |
| 674 ASSERT(tag == kLong || tag == kDouble); | |
| 675 sub.Write64(reinterpret_cast<const int64_t*>(data)[i]); | |
| 676 } | |
| 677 } | |
| 678 } | |
| 679 | |
| 680 | |
| 681 void HeapProfilerRootVisitor::VisitPointers(RawObject** first, | |
| 682 RawObject** last) { | |
| 683 for (RawObject** current = first; current <= last; current++) { | |
| 684 RawObject* raw_obj = *current; | |
| 685 if (raw_obj->IsHeapObject()) { | |
| 686 // Skip visits of FreeListElements. | |
| 687 if (FreeListElement::IsSpecialClass(raw_obj)) { | |
| 688 // Only the class of the free list element should ever be visited. | |
| 689 ASSERT(first == last); | |
| 690 return; | |
| 691 } | |
| 692 uword obj_addr = RawObject::ToAddr(raw_obj); | |
| 693 if (!Isolate::Current()->heap()->Contains(obj_addr) && | |
| 694 !Dart::vm_isolate()->heap()->Contains(obj_addr)) { | |
| 695 FATAL1("Invalid object pointer encountered 0x%lx\n", obj_addr); | |
| 696 } | |
| 697 } | |
| 698 profiler_->WriteRoot(raw_obj); | |
| 699 } | |
| 700 } | |
| 701 | |
| 702 | |
| 703 void HeapProfilerWeakRootVisitor::VisitHandle(uword addr) { | |
| 704 FinalizablePersistentHandle* handle = | |
| 705 reinterpret_cast<FinalizablePersistentHandle*>(addr); | |
| 706 RawObject* raw_obj = handle->raw(); | |
| 707 visitor_->VisitPointer(&raw_obj); | |
| 708 } | |
| 709 | |
| 710 | |
| 711 void HeapProfilerObjectVisitor::VisitObject(RawObject* raw_obj) { | |
| 712 profiler_->WriteObject(raw_obj); | |
| 713 } | |
| 714 | |
| 715 } // namespace dart | |
| OLD | NEW |