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; | |
| 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 const RawSmi* raw_smi = reinterpret_cast<const RawSmi*>(raw_obj); | |
| 143 if (smi_table_.find(raw_smi) == smi_table_.end()) { | |
| 144 smi_table_.insert(raw_smi); | |
|
turnidge
2012/05/29 17:50:01
Add comment?
cshapiro
2012/06/01 04:27:02
Done.
| |
| 145 } | |
| 146 } else if (raw_obj->GetClassIndex() == kNullClassIndex) { | |
| 147 return NULL; | |
| 148 } | |
| 149 return raw_obj; | |
| 150 } | |
| 151 | |
| 152 | |
| 153 const RawClass* HeapProfiler::ClassId(const RawClass* raw_class) { | |
| 154 if (class_table_.find(raw_class) == class_table_.end()) { | |
| 155 class_table_.insert(raw_class); | |
|
turnidge
2012/05/29 17:50:01
Add comment?
cshapiro
2012/06/01 04:27:02
Done.
| |
| 156 WriteLoadClass(raw_class); | |
| 157 } | |
| 158 return raw_class; | |
| 159 } | |
| 160 | |
| 161 | |
| 162 const char* HeapProfiler::StringId(const char* c_string) { | |
| 163 const RawString* ptr = reinterpret_cast<const RawString*>(c_string); | |
| 164 if (string_table_.find(ptr) == string_table_.end()) { | |
| 165 string_table_.insert(ptr); | |
|
turnidge
2012/05/29 17:50:01
Add comment?
cshapiro
2012/06/01 04:27:02
Done.
| |
| 166 WriteStringInUtf8(c_string); | |
| 167 } | |
| 168 return c_string; | |
| 169 } | |
| 170 | |
| 171 | |
| 172 const RawString* HeapProfiler::StringId(const RawString* raw_string) { | |
| 173 if (string_table_.find(raw_string) == string_table_.end()) { | |
| 174 string_table_.insert(raw_string); | |
| 175 WriteStringInUtf8(raw_string); | |
| 176 } | |
| 177 return raw_string; | |
| 178 } | |
| 179 | |
| 180 | |
| 181 void HeapProfiler::WriteRoot(const RawObject* raw_obj) { | |
| 182 SubRecord sub(kRootUnknown, this); | |
| 183 sub.WritePointer(ObjectId(raw_obj)); | |
| 184 } | |
| 185 | |
| 186 | |
| 187 void HeapProfiler::WriteObject(const RawObject* raw_obj) { | |
| 188 ASSERT(raw_obj->IsHeapObject()); | |
| 189 if (FreeListElement::IsSpecialClass(raw_obj)) { | |
|
turnidge
2012/05/29 17:50:01
What does this mean? Add comment?
cshapiro
2012/06/01 04:27:02
Good question. It means the raw_obj is actually a
| |
| 190 return; | |
| 191 } | |
| 192 ObjectKind kind = raw_obj->ptr()->class_->ptr()->instance_kind_; | |
| 193 switch (kind) { | |
| 194 case Class::kInstanceKind: { | |
| 195 WriteClassDump(reinterpret_cast<const RawClass*>(raw_obj)); | |
| 196 break; | |
| 197 } | |
| 198 case Array::kInstanceKind: | |
| 199 case ImmutableArray::kInstanceKind: { | |
| 200 WriteObjectArrayDump(reinterpret_cast<const RawArray*>(raw_obj)); | |
| 201 break; | |
| 202 } | |
| 203 case Int8Array::kInstanceKind: | |
| 204 case Uint8Array::kInstanceKind: { | |
| 205 const RawInt8Array* raw_int8_array = | |
| 206 reinterpret_cast<const RawInt8Array*>(raw_obj); | |
| 207 WritePrimitiveArrayDump(raw_int8_array, | |
| 208 kByte, | |
| 209 &raw_int8_array->data_[0]); | |
| 210 break; | |
| 211 } | |
| 212 case Int16Array::kInstanceKind: | |
| 213 case Uint16Array::kInstanceKind: { | |
| 214 const RawInt16Array* raw_int16_array = | |
| 215 reinterpret_cast<const RawInt16Array*>(raw_obj); | |
| 216 WritePrimitiveArrayDump(raw_int16_array, | |
| 217 kShort, | |
| 218 &raw_int16_array->data_[0]); | |
| 219 break; | |
| 220 } | |
| 221 case Int32Array::kInstanceKind: | |
| 222 case Uint32Array::kInstanceKind: { | |
| 223 const RawInt32Array* raw_int32_array = | |
| 224 reinterpret_cast<const RawInt32Array*>(raw_obj); | |
| 225 WritePrimitiveArrayDump(raw_int32_array, | |
| 226 kInt, | |
| 227 &raw_int32_array->data_[0]); | |
| 228 break; | |
| 229 } | |
| 230 case Int64Array::kInstanceKind: | |
| 231 case Uint64Array::kInstanceKind: { | |
| 232 const RawInt64Array* raw_int64_array = | |
| 233 reinterpret_cast<const RawInt64Array*>(raw_obj); | |
| 234 WritePrimitiveArrayDump(raw_int64_array, | |
| 235 kLong, | |
| 236 &raw_int64_array->data_[0]); | |
| 237 break; | |
| 238 } | |
| 239 case Float32Array::kInstanceKind: { | |
| 240 const RawFloat32Array* raw_float32_array = | |
| 241 reinterpret_cast<const RawFloat32Array*>(raw_obj); | |
| 242 WritePrimitiveArrayDump(raw_float32_array, | |
| 243 kFloat, | |
| 244 &raw_float32_array->data_[0]); | |
| 245 break; | |
| 246 } | |
| 247 case Float64Array::kInstanceKind: { | |
| 248 const RawFloat64Array* raw_float64_array = | |
| 249 reinterpret_cast<const RawFloat64Array*>(raw_obj); | |
| 250 WritePrimitiveArrayDump(raw_float64_array, | |
| 251 kDouble, | |
| 252 &raw_float64_array->data_[0]); | |
| 253 break; | |
| 254 } | |
| 255 case OneByteString::kInstanceKind: | |
| 256 case TwoByteString::kInstanceKind: | |
| 257 case FourByteString::kInstanceKind: | |
| 258 case ExternalOneByteString::kInstanceKind: | |
| 259 case ExternalTwoByteString::kInstanceKind: | |
| 260 case ExternalFourByteString::kInstanceKind: { | |
| 261 WriteInstanceDump(StringId(reinterpret_cast<const RawString*>(raw_obj))); | |
| 262 break; | |
| 263 } | |
| 264 default: | |
| 265 WriteInstanceDump(raw_obj); | |
| 266 } | |
| 267 } | |
| 268 | |
| 269 | |
| 270 void HeapProfiler::Write(const void* data, intptr_t size) { | |
| 271 (*write_callback_)(data, size, output_stream_); | |
| 272 } | |
| 273 | |
| 274 | |
| 275 // Header | |
| 276 // | |
| 277 // Format: | |
| 278 // [u1]* - format name | |
| 279 // u4 - size of identifiers | |
| 280 // u4 - high word of number of milliseconds since 0:00 GMT, 1/1/70 | |
| 281 // u4 - low word of number of milliseconds since 0:00 GMT, 1/1/70 | |
| 282 void HeapProfiler::WriteHeader() { | |
| 283 const char magic[] = "JAVA PROFILE 1.0.1"; | |
| 284 Write(magic, sizeof(magic)); | |
| 285 uint32_t size = htonl(kWordSize); | |
| 286 Write(&size, sizeof(size)); | |
| 287 timeval tv; | |
| 288 int result = gettimeofday(&tv, NULL); | |
| 289 ASSERT(result != -1); | |
| 290 uint64_t milliseconds = (uint64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000; | |
| 291 uint32_t hi = htonl((uint32_t)((milliseconds >> 32) & 0x00000000FFFFFFFF)); | |
| 292 Write(&hi, sizeof(hi)); | |
| 293 uint32_t lo = htonl((uint32_t)(milliseconds & 0x00000000FFFFFFFF)); | |
| 294 Write(&lo, sizeof(lo)); | |
| 295 } | |
| 296 | |
| 297 | |
| 298 // Record | |
| 299 // | |
| 300 // Format: | |
| 301 // u1 - TAG: denoting the type of the record | |
| 302 // u4 - TIME: number of microseconds since the time stamp in the header | |
| 303 // u4 - LENGTH: number of bytes that follow this u4 field and belong | |
| 304 // to this record | |
| 305 // [u1]* - BODY: as many bytes as specified in the above u4 field | |
| 306 void HeapProfiler::WriteRecord(const Record& record) { | |
| 307 uint8_t tag = record.Tag(); | |
| 308 Write(&tag, sizeof(tag)); | |
| 309 uint32_t time = htonl(record.Time()); | |
| 310 Write(&time, sizeof(time)); | |
| 311 uint32_t length = htonl(record.Length()); | |
| 312 Write(&length, sizeof(length)); | |
| 313 Write(record.Body(), record.Length()); | |
| 314 } | |
| 315 | |
| 316 | |
| 317 // STRING IN UTF8 - 0x01 | |
| 318 // | |
| 319 // Format: | |
| 320 // ID - ID for this string | |
| 321 // [u1]* - UTF8 characters for string (NOT NULL terminated) | |
| 322 void HeapProfiler::WriteStringInUtf8(const RawString* raw_string) { | |
| 323 intptr_t length = 0; | |
| 324 char* characters = NULL; | |
| 325 ObjectKind kind = raw_string->ptr()->class_->ptr()->instance_kind_; | |
| 326 if (kind == OneByteString::kInstanceKind) { | |
| 327 const RawOneByteString* onestr = | |
| 328 reinterpret_cast<const RawOneByteString*>(raw_string); | |
| 329 for (intptr_t i = 0; i < Smi::Value(onestr->ptr()->length_); ++i) { | |
| 330 length += Utf8::Length(onestr->ptr()->data_[i]); | |
| 331 } | |
| 332 characters = new char[length]; | |
| 333 for (intptr_t i = 0, j = 0; i < Smi::Value(onestr->ptr()->length_); ++i) { | |
| 334 int32_t ch = onestr->ptr()->data_[i]; | |
| 335 j += Utf8::Encode(ch, &characters[j]); | |
| 336 } | |
| 337 } else if (kind == TwoByteString::kInstanceKind) { | |
| 338 const RawTwoByteString* twostr = | |
| 339 reinterpret_cast<const RawTwoByteString*>(raw_string); | |
| 340 for (intptr_t i = 0; i < Smi::Value(twostr->ptr()->length_); ++i) { | |
| 341 length += Utf8::Length(twostr->ptr()->data_[i]); | |
| 342 } | |
| 343 characters = new char[length]; | |
| 344 for (intptr_t i = 0, j = 0; i < Smi::Value(twostr->ptr()->length_); ++i) { | |
| 345 int32_t ch = twostr->ptr()->data_[i]; | |
| 346 j += Utf8::Encode(ch, &characters[j]); | |
| 347 } | |
| 348 } else { | |
| 349 ASSERT(kind == FourByteString::kInstanceKind); | |
| 350 const RawFourByteString* fourstr = | |
| 351 reinterpret_cast<const RawFourByteString*>(raw_string); | |
| 352 for (intptr_t i = 0; i < Smi::Value(fourstr->ptr()->length_); ++i) { | |
| 353 length += Utf8::Length(fourstr->ptr()->data_[i]); | |
| 354 } | |
| 355 characters = new char[length]; | |
| 356 for (intptr_t i = 0, j = 0; i < Smi::Value(fourstr->ptr()->length_); ++i) { | |
| 357 int32_t ch = fourstr->ptr()->data_[i]; | |
| 358 j += Utf8::Encode(ch, &characters[j]); | |
| 359 } | |
| 360 } | |
| 361 Record record(kStringInUtf8, this); | |
| 362 record.WritePointer(ObjectId(raw_string)); | |
| 363 for (intptr_t i = 0; i < length; ++i) { | |
| 364 record.Write8(characters[i]); | |
| 365 } | |
| 366 delete[] characters; | |
| 367 } | |
| 368 | |
| 369 | |
| 370 void HeapProfiler::WriteStringInUtf8(const char* c_string) { | |
| 371 Record record(kStringInUtf8, this); | |
| 372 record.WritePointer(c_string); | |
| 373 for (; *c_string != '\0'; ++c_string) { | |
| 374 record.Write8(*c_string); | |
| 375 } | |
| 376 } | |
| 377 | |
| 378 | |
| 379 // LOAD CLASS - 0x02 | |
| 380 // | |
| 381 // Format: | |
| 382 // u4 - class serial number (always > 0) | |
| 383 // ID - class object ID | |
| 384 // u4 - stack trace serial number | |
| 385 // ID - class name string ID | |
| 386 void HeapProfiler::WriteLoadClass(const RawClass* raw_class) { | |
| 387 Record record(kLoadClass, this); | |
| 388 // class serial number (always > 0) | |
| 389 record.Write32(1); | |
| 390 // class object ID | |
| 391 record.WritePointer(raw_class); | |
| 392 // stack trace serial number | |
| 393 record.Write32(0); | |
| 394 if (raw_class->ptr()->name_ == String::null()) { | |
| 395 intptr_t class_index = Object::GetSingletonClassIndex(raw_class); | |
| 396 const char* name = Object::GetSingletonClassName(class_index); | |
| 397 record.WritePointer(StringId(name)); | |
| 398 } else { | |
| 399 record.WritePointer(StringId(raw_class->ptr()->name_)); | |
| 400 } | |
| 401 } | |
| 402 | |
| 403 | |
| 404 // STACK TRACE - 0x05 | |
| 405 // | |
| 406 // u4 - stack trace serial number | |
| 407 // u4 - thread serial number | |
| 408 // u4 - number of frames | |
| 409 // [ID]* - series of stack frame ID's | |
| 410 void HeapProfiler::WriteStackTrace() { | |
| 411 Record record(kStackTrace, this); | |
| 412 // stack trace serial number | |
| 413 record.Write32(0); | |
| 414 // thread serial number | |
| 415 record.Write32(0); | |
| 416 // number of frames | |
| 417 record.Write32(0); | |
| 418 } | |
| 419 | |
| 420 | |
| 421 // HEAP SUMMARY - 0x07 | |
| 422 // | |
| 423 // Format: | |
| 424 // u4 - total live bytes | |
| 425 // u4 - total live instances | |
| 426 // u8 - total bytes allocated | |
| 427 // u8 - total instances allocated | |
| 428 void HeapProfiler::WriteHeapSummary(uint32_t total_live_bytes, | |
| 429 uint32_t total_live_instances, | |
| 430 uint64_t total_bytes_allocated, | |
| 431 uint64_t total_instances_allocated) { | |
| 432 Record record(kHeapSummary, this); | |
| 433 record.Write32(total_live_bytes); | |
| 434 record.Write32(total_live_instances); | |
| 435 record.Write32(total_bytes_allocated); | |
| 436 record.Write32(total_instances_allocated); | |
| 437 } | |
| 438 | |
| 439 | |
| 440 // HEAP DUMP - 0x0C | |
| 441 // | |
| 442 // Format: | |
| 443 // []* | |
| 444 void HeapProfiler::WriteHeapDump() { | |
| 445 Record record(kHeapDump, this); | |
| 446 } | |
| 447 | |
| 448 | |
| 449 // CLASS DUMP - 0x20 | |
| 450 // | |
| 451 // Format: | |
| 452 // ID - class object ID | |
| 453 // u4 - stack trace serial number | |
| 454 // ID - super class object ID | |
| 455 // ID - class loader object ID | |
| 456 // ID - signers object ID | |
| 457 // ID - protection domain object ID | |
| 458 // ID - reserved | |
| 459 // ID - reserved | |
| 460 // u4 - instance size (in bytes) | |
| 461 // u2 - size of constant pool and number of records that follow: | |
| 462 // u2 - constant pool index | |
| 463 // u1 - type of entry: (See Basic Type) | |
| 464 // value - value of entry (u1, u2, u4, or u8 based on type of entry) | |
| 465 // u2 - Number of static fields: | |
| 466 // ID - static field name string ID | |
| 467 // u1 - type of field: (See Basic Type) | |
| 468 // value - value of entry (u1, u2, u4, or u8 based on type of field) | |
| 469 // u2 - Number of instance fields (not including super class's) | |
| 470 // ID - field name string ID | |
| 471 // u1 - type of field: (See Basic Type) | |
| 472 void HeapProfiler::WriteClassDump(const RawClass* raw_class) { | |
| 473 SubRecord sub(kClassDump, this); | |
| 474 // class object ID | |
| 475 sub.WritePointer(ClassId(raw_class)); | |
| 476 // stack trace serial number | |
| 477 sub.Write32(0); | |
| 478 // super class object ID | |
| 479 if (raw_class == raw_class->ptr()->class_) { | |
| 480 sub.WritePointer(NULL); | |
| 481 } else { | |
| 482 sub.WritePointer(ClassId(raw_class->ptr()->class_)); | |
| 483 } | |
| 484 // class loader object ID | |
| 485 sub.WritePointer(NULL); | |
| 486 // signers object ID | |
| 487 sub.WritePointer(NULL); | |
| 488 // protection domain object ID | |
| 489 sub.WritePointer(NULL); | |
| 490 // reserved | |
| 491 sub.WritePointer(NULL); | |
| 492 // reserved | |
| 493 sub.WritePointer(NULL); | |
| 494 | |
| 495 intptr_t num_static_fields = 0; | |
| 496 intptr_t num_instance_fields = 0; | |
| 497 | |
| 498 RawArray* raw_array = raw_class->ptr()->fields_; | |
| 499 if (raw_array != Array::null()) { | |
| 500 for (intptr_t i = 0; i < Smi::Value(raw_array->ptr()->length_); ++i) { | |
| 501 RawField* raw_field = | |
| 502 reinterpret_cast<RawField*>(raw_array->ptr()->data()[i]); | |
| 503 if (raw_field->ptr()->is_static_) { | |
| 504 ++num_static_fields; | |
| 505 } else { | |
| 506 ++num_instance_fields; | |
| 507 } | |
| 508 } | |
| 509 } | |
| 510 // instance size (in bytes) | |
| 511 sub.Write32(sizeof(RawClass)); | |
| 512 // size of constant pool and number of records that follow: | |
| 513 sub.Write16(0); | |
| 514 // Number of static fields | |
| 515 sub.Write16(num_static_fields); | |
| 516 // Static fields: | |
| 517 if (raw_array != Array::null()) { | |
| 518 for (intptr_t i = 0; i < Smi::Value(raw_array->ptr()->length_); ++i) { | |
| 519 RawField* raw_field = | |
| 520 reinterpret_cast<RawField*>(raw_array->ptr()->data()[i]); | |
| 521 if (raw_field->ptr()->is_static_) { | |
| 522 ASSERT(raw_field->ptr()->name_ != String::null()); | |
| 523 // static field name string ID | |
| 524 sub.WritePointer(StringId(raw_field->ptr()->name_)); | |
| 525 // type of static field | |
| 526 sub.Write8(kObject); | |
| 527 // value of entry | |
| 528 sub.WritePointer(ObjectId(raw_field->ptr()->value_)); | |
| 529 } | |
| 530 } | |
| 531 } | |
| 532 // Number of instance fields (not include super class's) | |
| 533 sub.Write16(num_instance_fields); | |
| 534 // Instance fields: | |
| 535 if (raw_array != Array::null()) { | |
| 536 for (intptr_t i = 0; i < Smi::Value(raw_array->ptr()->length_); ++i) { | |
| 537 RawField* raw_field = | |
| 538 reinterpret_cast<RawField*>(raw_array->ptr()->data()[i]); | |
| 539 if (!raw_field->ptr()->is_static_) { | |
| 540 ASSERT(raw_field->ptr()->name_ != String::null()); | |
| 541 // field name string ID | |
| 542 sub.WritePointer(StringId(raw_field->ptr()->name_)); | |
| 543 // type of field | |
| 544 sub.Write8(kObject); | |
| 545 } | |
| 546 } | |
| 547 } | |
| 548 } | |
| 549 | |
| 550 | |
| 551 // INSTANCE DUMP - 0x21 | |
| 552 // | |
| 553 // Format: | |
| 554 // ID - object ID | |
| 555 // u4 - stack trace serial number | |
| 556 // ID - class object ID | |
| 557 // u4 - number of bytes that follow | |
| 558 // [value]* - instance field values (this class, followed by super class, etc) | |
| 559 void HeapProfiler::WriteInstanceDump(const RawObject* raw_obj) { | |
| 560 SubRecord sub(kInstanceDump, this); | |
| 561 // object ID | |
| 562 sub.WritePointer(raw_obj); | |
| 563 // stack trace serial number | |
| 564 sub.Write32(0); | |
| 565 // class object ID | |
| 566 sub.WritePointer(ClassId(raw_obj->ptr()->class_)); | |
| 567 // number of bytes that follow | |
| 568 intptr_t num_instance_fields = 0; | |
| 569 for (RawClass* cls = raw_obj->ptr()->class_; | |
| 570 cls != cls->ptr()->class_; | |
| 571 cls = cls->ptr()->class_) { | |
| 572 RawArray* raw_array = cls->ptr()->fields_; | |
| 573 if (raw_array != Array::null()) { | |
| 574 intptr_t length = Smi::Value(raw_array->ptr()->length_); | |
| 575 for (intptr_t i = 0; i < length; ++i) { | |
| 576 RawField* raw_field = | |
| 577 reinterpret_cast<RawField*>(raw_array->ptr()->data()[i]); | |
| 578 if (!raw_field->ptr()->is_static_) { | |
| 579 ++num_instance_fields; | |
| 580 } | |
| 581 } | |
| 582 } | |
| 583 } | |
| 584 sub.Write32(num_instance_fields * kWordSize); | |
| 585 // instance field values (this class, followed by super class, etc) | |
| 586 for (RawClass* cls = raw_obj->ptr()->class_; | |
| 587 cls != cls->ptr()->class_; | |
| 588 cls = cls->ptr()->class_) { | |
| 589 RawArray* raw_array = cls->ptr()->fields_; | |
| 590 if (raw_array != Array::null()) { | |
| 591 intptr_t length = Smi::Value(raw_array->ptr()->length_); | |
| 592 uint8_t* base = reinterpret_cast<uint8_t*>(raw_obj->ptr()); | |
| 593 for (intptr_t i = 0; i < length; ++i) { | |
| 594 RawField* raw_field = | |
| 595 reinterpret_cast<RawField*>(raw_array->ptr()->data()[i]); | |
| 596 if (!raw_field->ptr()->is_static_) { | |
| 597 intptr_t offset = | |
| 598 Smi::Value(reinterpret_cast<RawSmi*>(raw_field->ptr()->value_)); | |
| 599 RawObject* ptr = *reinterpret_cast<RawObject**>(base + offset); | |
| 600 sub.WritePointer(ObjectId(ptr)); | |
| 601 } | |
| 602 } | |
| 603 } | |
| 604 } | |
| 605 } | |
| 606 | |
| 607 | |
| 608 // OBJECT ARRAY DUMP - 0x22 | |
| 609 // | |
| 610 // Format: | |
| 611 // ID - array object ID | |
| 612 // u4 - stack trace serial number | |
| 613 // u4 - number of elements | |
| 614 // ID - array class object ID | |
| 615 // [ID]* - elements | |
| 616 void HeapProfiler::WriteObjectArrayDump(const RawArray* raw_array) { | |
| 617 SubRecord sub(kObjectArrayDump, this); | |
| 618 // array object ID | |
| 619 sub.WritePointer(raw_array); | |
| 620 // stack trace serial number | |
| 621 sub.Write32(0); | |
| 622 // number of elements | |
| 623 intptr_t length = Smi::Value(raw_array->ptr()->length_); | |
| 624 sub.Write32(length); | |
| 625 // array class object ID | |
| 626 sub.WritePointer(NULL); | |
| 627 // elements | |
| 628 for (intptr_t i = 0; i < length; ++i) { | |
| 629 sub.WritePointer(ObjectId(raw_array->ptr()->data()[i])); | |
| 630 } | |
| 631 } | |
| 632 | |
| 633 | |
| 634 // PRIMITIVE ARRAY DUMP - 0x23 | |
| 635 // | |
| 636 // Format: | |
| 637 // ID - array object ID | |
| 638 // u4 - stack trace serial number | |
| 639 // u4 - number of elements | |
| 640 // u1 - element type | |
| 641 // [u1]* - elements | |
| 642 void HeapProfiler::WritePrimitiveArrayDump(const RawByteArray* raw_byte_array, | |
| 643 uint8_t tag, | |
| 644 const void* data) { | |
| 645 SubRecord sub(kPrimitiveArrayDump, this); | |
| 646 // array object ID | |
| 647 sub.WritePointer(raw_byte_array); | |
| 648 // stack trace serial number | |
| 649 sub.Write32(0); | |
| 650 // number of elements | |
| 651 intptr_t length = Smi::Value(raw_byte_array->ptr()->length_); | |
| 652 sub.Write32(length); | |
| 653 // element type | |
| 654 sub.Write8(tag); | |
| 655 // elements (packed) | |
| 656 for (intptr_t i = 0; i < length; ++i) { | |
| 657 if (tag == kByte) { | |
| 658 sub.Write8(reinterpret_cast<const int8_t*>(data)[i]); | |
| 659 } else if (tag == kShort) { | |
| 660 sub.Write16(reinterpret_cast<const int16_t*>(data)[i]); | |
| 661 break; | |
| 662 } else if (tag == kInt || tag == kFloat) { | |
| 663 sub.Write32(reinterpret_cast<const int32_t*>(data)[i]); | |
| 664 } else { | |
| 665 ASSERT(tag == kLong || tag == kDouble); | |
| 666 sub.Write64(reinterpret_cast<const int64_t*>(data)[i]); | |
| 667 } | |
| 668 } | |
| 669 } | |
| 670 | |
| 671 | |
| 672 void HeapProfilerRootVisitor::VisitPointers(RawObject** first, | |
| 673 RawObject** last) { | |
| 674 for (RawObject** current = first; current <= last; current++) { | |
| 675 RawObject* raw_obj = *current; | |
| 676 if (raw_obj->IsHeapObject()) { | |
| 677 // Skip visits of FreeListElements. | |
| 678 if (FreeListElement::IsSpecialClass(raw_obj)) { | |
| 679 // Only the class of the free list element should ever be visited. | |
| 680 ASSERT(first == last); | |
| 681 return; | |
| 682 } | |
| 683 uword obj_addr = RawObject::ToAddr(raw_obj); | |
| 684 if (!Isolate::Current()->heap()->Contains(obj_addr) && | |
| 685 !Dart::vm_isolate()->heap()->Contains(obj_addr)) { | |
| 686 FATAL1("Invalid object pointer encountered 0x%lx\n", obj_addr); | |
| 687 } | |
| 688 } | |
| 689 profiler_->WriteRoot(raw_obj); | |
| 690 } | |
| 691 } | |
| 692 | |
| 693 | |
| 694 void HeapProfilerWeakRootVisitor::VisitHandle(uword addr) { | |
| 695 FinalizablePersistentHandle* handle = | |
| 696 reinterpret_cast<FinalizablePersistentHandle*>(addr); | |
| 697 RawObject* raw_obj = handle->raw(); | |
| 698 visitor_->VisitPointer(&raw_obj); | |
| 699 } | |
| 700 | |
| 701 | |
| 702 void HeapProfilerObjectVisitor::VisitObject(RawObject* raw_obj) { | |
| 703 profiler_->WriteObject(raw_obj); | |
| 704 } | |
| 705 | |
| 706 } // namespace dart | |
| OLD | NEW |