Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(312)

Side by Side Diff: runtime/vm/heap_profiler.cc

Issue 139043003: - Address warnings about 64-bit to 32-bit conversions. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/heap_profiler.h ('k') | runtime/vm/heap_profiler_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 "vm/dart_api_state.h"
8 #include "vm/object.h"
9 #include "vm/raw_object.h"
10 #include "vm/stack_frame.h"
11 #include "vm/unicode.h"
12
13 namespace dart {
14
15 HeapProfiler::Buffer::~Buffer() {
16 delete[] data_;
17 }
18
19
20 void HeapProfiler::Buffer::Write(const uint8_t* data, intptr_t size) {
21 EnsureCapacity(size);
22 memmove(&data_[size_], data, size);
23 size_ += size;
24 }
25
26
27 void HeapProfiler::Buffer::EnsureCapacity(intptr_t size) {
28 if ((size + size_) > capacity_) {
29 intptr_t new_capacity = Utils::RoundUpToPowerOfTwo(capacity_ + size);
30 uint8_t* new_data = new uint8_t[new_capacity];
31 memmove(new_data, data_, size_);
32 capacity_ = new_capacity;
33 delete[] data_;
34 data_ = new_data;
35 }
36 }
37
38
39 void HeapProfiler::Record::Write(const uint8_t* value, intptr_t size) {
40 body_.Write(value, size);
41 }
42
43
44 void HeapProfiler::Record::Write8(uint8_t value) {
45 body_.Write(&value, sizeof(value));
46 }
47
48
49 void HeapProfiler::Record::Write16(uint16_t value) {
50 value = htons(value);
51 body_.Write(reinterpret_cast<uint8_t*>(&value), sizeof(value));
52 }
53
54
55 void HeapProfiler::Record::Write32(uint32_t value) {
56 value = htonl(value);
57 body_.Write(reinterpret_cast<uint8_t*>(&value), sizeof(value));
58 }
59
60
61 void HeapProfiler::Record::Write64(uint64_t value) {
62 uint16_t x = 0xFF;
63 if (*reinterpret_cast<uint8_t*>(&x) == 0xFF) {
64 uint64_t hi = static_cast<uint64_t>(htonl(value & 0xFFFFFFFF)) << 32;
65 uint64_t lo = htonl(value >> 32);
66 value = hi | lo;
67 }
68 body_.Write(reinterpret_cast<uint8_t*>(&value), sizeof(value));
69 }
70
71
72 void HeapProfiler::Record::WriteObjectId(const void* value) {
73 Write64(reinterpret_cast<uint64_t>(value));
74 }
75
76
77 HeapProfiler::SubRecord::SubRecord(uint8_t sub_tag, HeapProfiler* profiler)
78 : record_(profiler->heap_dump_record_) {
79 record_->Write8(sub_tag);
80 }
81
82
83 HeapProfiler::SubRecord::~SubRecord() {
84 }
85
86
87 void HeapProfiler::SubRecord::Write(const uint8_t* value, intptr_t size) {
88 record_->Write(value, size);
89 }
90
91
92 void HeapProfiler::SubRecord::Write8(uint8_t value) {
93 record_->Write8(value);
94 }
95
96
97 void HeapProfiler::SubRecord::Write16(uint16_t value) {
98 record_->Write16(value);
99 }
100
101
102 void HeapProfiler::SubRecord::Write32(uint32_t value) {
103 record_->Write32(value);
104 }
105
106
107 void HeapProfiler::SubRecord::Write64(uint64_t value) {
108 record_->Write64(value);
109 }
110
111
112 void HeapProfiler::SubRecord::WriteObjectId(const void* value) {
113 record_->WriteObjectId(value);
114 }
115
116
117 HeapProfiler::HeapProfiler(Dart_FileWriteCallback callback, void* stream)
118 : write_callback_(callback),
119 output_stream_(stream),
120 heap_dump_record_(NULL) {
121 WriteHeader();
122 WriteStackTrace();
123 WriteFakeLoadClass(kJavaLangClass, "java.lang.Class");
124 WriteFakeLoadClass(kJavaLangClassLoader, "java.lang.ClassLoader");
125 WriteFakeLoadClass(kJavaLangObject, "java.lang.Object");
126 WriteFakeLoadClass(kJavaLangString, "java.lang.String");
127 WriteFakeLoadClass(kArrayObject, "Object[]");
128 WriteFakeLoadClass(kArrayBoolean, "bool[]");
129 WriteFakeLoadClass(kArrayChar, "char[]");
130 WriteFakeLoadClass(kArrayFloat, "float[]");
131 WriteFakeLoadClass(kArrayDouble, "double[]");
132 WriteFakeLoadClass(kArrayByte, "byte[]");
133 WriteFakeLoadClass(kArrayShort, "short[]");
134 WriteFakeLoadClass(kArrayInt, "int[]");
135 WriteFakeLoadClass(kArrayLong, "long[]");
136 heap_dump_record_ = new Record(kHeapDump, this);
137 WriteFakeClassDump(kJavaLangClass, static_cast<FakeClass>(0));
138 WriteFakeClassDump(kJavaLangClassLoader, kJavaLangObject);
139 WriteFakeClassDump(kJavaLangObject, static_cast<FakeClass>(0));
140 WriteFakeClassDump(kJavaLangString, kJavaLangObject);
141 }
142
143
144 HeapProfiler::~HeapProfiler() {
145 for (std::set<const RawSmi*>::iterator it = smi_table_.begin();
146 it != smi_table_.end();
147 ++it) {
148 WriteSmiInstanceDump(*it);
149 }
150 delete heap_dump_record_;
151 }
152
153
154 const RawObject* HeapProfiler::ObjectId(const RawObject* raw_obj) {
155 if (!raw_obj->IsHeapObject()) {
156 // To describe an immediate object in HPROF we record its value
157 // and write fake INSTANCE_DUMP subrecord in the HEAP_DUMP record.
158 const RawSmi* raw_smi = reinterpret_cast<const RawSmi*>(raw_obj);
159 if (smi_table_.find(raw_smi) == smi_table_.end()) {
160 smi_table_.insert(raw_smi);
161 }
162 } else if (raw_obj->GetClassId() == kNullCid) {
163 // Instances of the Null type are translated to NULL so they can
164 // be printed as "null" in HAT.
165 return NULL;
166 }
167 return raw_obj;
168 }
169
170
171 const RawClass* HeapProfiler::ClassId(const RawClass* raw_class) {
172 // A unique LOAD_CLASS record must be written for each class object.
173 if (class_table_.find(raw_class) == class_table_.end()) {
174 class_table_.insert(raw_class);
175 WriteLoadClass(raw_class);
176 }
177 return raw_class;
178 }
179
180
181 // A built-in class may have its name encoded in a C-string. These
182 // strings should only be found in class objects. We emit a unique
183 // STRING_IN_UTF8 so HAT will properly display the class name.
184 const char* HeapProfiler::StringId(const char* c_string) {
185 const RawString* ptr = reinterpret_cast<const RawString*>(c_string);
186 if (string_table_.find(ptr) == string_table_.end()) {
187 string_table_.insert(ptr);
188 WriteStringInUtf8(c_string);
189 }
190 return c_string;
191 }
192
193
194 const RawString* HeapProfiler::StringId(const RawString* raw_string) {
195 // A unique STRING_IN_UTF8 record must be written for each string
196 // object.
197 if (string_table_.find(raw_string) == string_table_.end()) {
198 string_table_.insert(raw_string);
199 WriteStringInUtf8(raw_string);
200 }
201 return raw_string;
202 }
203
204
205 const RawClass* HeapProfiler::GetClass(const RawObject* raw_obj) {
206 return Isolate::Current()->class_table()->At(raw_obj->GetClassId());
207 }
208
209
210 const RawClass* HeapProfiler::GetSuperClass(const RawClass* raw_class) {
211 ASSERT(raw_class != Class::null());
212 const RawAbstractType* super_type = raw_class->ptr()->super_type_;
213 if (super_type == AbstractType::null()) {
214 return Class::null();
215 }
216 while (super_type->GetClassId() == kBoundedTypeCid) {
217 super_type =
218 reinterpret_cast<const RawBoundedType*>(super_type)->ptr()->type_;
219 }
220 ASSERT(super_type->GetClassId() == kTypeCid);
221 return reinterpret_cast<const RawClass*>(
222 reinterpret_cast<const RawType*>(super_type)->ptr()->type_class_);
223 }
224
225
226 void HeapProfiler::WriteRoot(const RawObject* raw_obj) {
227 SubRecord sub(kRootUnknown, this);
228 sub.WriteObjectId(ObjectId(raw_obj));
229 }
230
231
232 void HeapProfiler::WriteObject(const RawObject* raw_obj) {
233 ASSERT(raw_obj->IsHeapObject());
234 intptr_t class_id = raw_obj->GetClassId();
235 switch (class_id) {
236 case kFreeListElement: {
237 // Free space has an object-like encoding. Heap profiles only
238 // care about live objects so we skip over these records.
239 break;
240 }
241 case kClassCid: {
242 const RawClass* raw_class = reinterpret_cast<const RawClass*>(raw_obj);
243 if (raw_class->ptr()->id_ == kFreeListElement) {
244 // Skip over the FreeListElement class. This class exists to
245 // describe free space.
246 break;
247 }
248 WriteClassDump(raw_class);
249 break;
250 }
251 case kArrayCid:
252 case kImmutableArrayCid: {
253 WriteObjectArrayDump(reinterpret_cast<const RawArray*>(raw_obj));
254 break;
255 }
256 case kTypedDataInt8ArrayCid:
257 case kTypedDataUint8ArrayCid:
258 case kTypedDataUint8ClampedArrayCid: {
259 const RawTypedData* raw_int8_array =
260 reinterpret_cast<const RawTypedData*>(raw_obj);
261 WritePrimitiveArrayDump(raw_int8_array, kByte);
262 break;
263 }
264 case kTypedDataInt16ArrayCid:
265 case kTypedDataUint16ArrayCid: {
266 const RawTypedData* raw_int16_array =
267 reinterpret_cast<const RawTypedData*>(raw_obj);
268 WritePrimitiveArrayDump(raw_int16_array, kShort);
269 break;
270 }
271 case kTypedDataInt32ArrayCid:
272 case kTypedDataUint32ArrayCid: {
273 const RawTypedData* raw_int32_array =
274 reinterpret_cast<const RawTypedData*>(raw_obj);
275 WritePrimitiveArrayDump(raw_int32_array, kInt);
276 break;
277 }
278 case kTypedDataInt64ArrayCid:
279 case kTypedDataUint64ArrayCid: {
280 const RawTypedData* raw_int64_array =
281 reinterpret_cast<const RawTypedData*>(raw_obj);
282 WritePrimitiveArrayDump(raw_int64_array, kLong);
283 break;
284 }
285 case kTypedDataFloat32ArrayCid: {
286 const RawTypedData* raw_float32_array =
287 reinterpret_cast<const RawTypedData*>(raw_obj);
288 WritePrimitiveArrayDump(raw_float32_array, kFloat);
289 break;
290 }
291 case kTypedDataFloat64ArrayCid: {
292 const RawTypedData* raw_float64_array =
293 reinterpret_cast<const RawTypedData*>(raw_obj);
294 WritePrimitiveArrayDump(raw_float64_array, kDouble);
295 break;
296 }
297 case kOneByteStringCid:
298 case kTwoByteStringCid:
299 case kExternalOneByteStringCid:
300 case kExternalTwoByteStringCid: {
301 WriteInstanceDump(StringId(reinterpret_cast<const RawString*>(raw_obj)));
302 break;
303 }
304 default:
305 WriteInstanceDump(raw_obj);
306 }
307 }
308
309
310 void HeapProfiler::Write(const void* data, intptr_t size) {
311 (*write_callback_)(data, size, output_stream_);
312 }
313
314
315 // Header
316 //
317 // Format:
318 // [u1]* - format name
319 // u4 - size of identifiers
320 // u4 - high word of number of milliseconds since 0:00 GMT, 1/1/70
321 // u4 - low word of number of milliseconds since 0:00 GMT, 1/1/70
322 void HeapProfiler::WriteHeader() {
323 const char magic[] = "JAVA PROFILE 1.0.1";
324 Write(magic, sizeof(magic));
325 uint32_t size = htonl(kObjectIdSize);
326 Write(&size, sizeof(size));
327 uint64_t milliseconds = OS::GetCurrentTimeMillis();
328 uint32_t hi = htonl(
329 static_cast<uint32_t>((milliseconds >> 32) & 0x00000000FFFFFFFF));
330 Write(&hi, sizeof(hi));
331 uint32_t lo = htonl(
332 static_cast<uint32_t>(milliseconds & 0x00000000FFFFFFFF));
333 Write(&lo, sizeof(lo));
334 }
335
336
337 // Record
338 //
339 // Format:
340 // u1 - TAG: denoting the type of the record
341 // u4 - TIME: number of microseconds since the time stamp in the header
342 // u4 - LENGTH: number of bytes that follow this u4 field and belong
343 // to this record
344 // [u1]* - BODY: as many bytes as specified in the above u4 field
345 void HeapProfiler::WriteRecord(const Record& record) {
346 uint8_t tag = record.Tag();
347 Write(&tag, sizeof(tag));
348 uint32_t time = htonl(record.Time());
349 Write(&time, sizeof(time));
350 uint32_t length = htonl(record.Length());
351 Write(&length, sizeof(length));
352 Write(record.Body(), record.Length());
353 }
354
355
356 // STRING IN UTF8 - 0x01
357 //
358 // Format:
359 // ID - ID for this string
360 // [u1]* - UTF8 characters for string (NOT NULL terminated)
361 void HeapProfiler::WriteStringInUtf8(const RawString* raw_string) {
362 intptr_t length = 0;
363 char* characters = NULL;
364 intptr_t class_id = raw_string->GetClassId();
365 if (class_id == kOneByteStringCid) {
366 const RawOneByteString* onestr =
367 reinterpret_cast<const RawOneByteString*>(raw_string);
368 for (intptr_t i = 0; i < Smi::Value(onestr->ptr()->length_); ++i) {
369 length += Utf8::Length(onestr->ptr()->data_[i]);
370 }
371 characters = new char[length];
372 for (intptr_t i = 0, j = 0; i < Smi::Value(onestr->ptr()->length_); ++i) {
373 int32_t ch = onestr->ptr()->data_[i];
374 j += Utf8::Encode(ch, &characters[j]);
375 }
376 } else {
377 ASSERT(class_id == kTwoByteStringCid);
378 const RawTwoByteString* twostr =
379 reinterpret_cast<const RawTwoByteString*>(raw_string);
380 for (intptr_t i = 0; i < Smi::Value(twostr->ptr()->length_); ++i) {
381 length += Utf8::Length(twostr->ptr()->data_[i]);
382 }
383 characters = new char[length];
384 for (intptr_t i = 0, j = 0; i < Smi::Value(twostr->ptr()->length_); ++i) {
385 int32_t ch = twostr->ptr()->data_[i];
386 j += Utf8::Encode(ch, &characters[j]);
387 }
388 }
389 Record record(kStringInUtf8, this);
390 record.WriteObjectId(ObjectId(raw_string));
391 for (intptr_t i = 0; i < length; ++i) {
392 record.Write8(characters[i]);
393 }
394 delete[] characters;
395 }
396
397
398 void HeapProfiler::WriteStringInUtf8(const char* c_string) {
399 Record record(kStringInUtf8, this);
400 record.WriteObjectId(c_string);
401 for (; *c_string != '\0'; ++c_string) {
402 record.Write8(*c_string);
403 }
404 }
405
406
407 // LOAD CLASS - 0x02
408 //
409 // Format:
410 // u4 - class serial number (always > 0)
411 // ID - class object ID
412 // u4 - stack trace serial number
413 // ID - class name string ID
414 void HeapProfiler::WriteLoadClass(const RawClass* raw_class) {
415 Record record(kLoadClass, this);
416 // class serial number (always > 0)
417 record.Write32(1);
418 // class object ID
419 record.WriteObjectId(raw_class);
420 // stack trace serial number
421 record.Write32(0);
422 // class name string ID
423 if (raw_class->ptr()->name_ != String::null()) {
424 record.WriteObjectId(StringId(raw_class->ptr()->name_));
425 } else {
426 const char* format = "<an unnamed class with id %d>";
427 intptr_t len = OS::SNPrint(NULL, 0, format, raw_class->ptr()->id_);
428 char* str = new char[len + 1];
429 OS::SNPrint(str, len + 1, format, raw_class->ptr()->id_);
430 record.WriteObjectId(StringId(str));
431 delete[] str;
432 }
433 }
434
435
436 void HeapProfiler::WriteFakeLoadClass(FakeClass fake_class,
437 const char* class_name) {
438 Record record(kLoadClass, this);
439 // class serial number (always > 0)
440 record.Write32(1);
441 // class object ID
442 record.WriteObjectId(reinterpret_cast<void*>(fake_class));
443 // stack trace serial number
444 record.Write32(0);
445 // class name string ID
446 record.WriteObjectId(StringId(class_name));
447 }
448
449
450 // STACK TRACE - 0x05
451 //
452 // u4 - stack trace serial number
453 // u4 - thread serial number
454 // u4 - number of frames
455 // [ID]* - series of stack frame ID's
456 void HeapProfiler::WriteStackTrace() {
457 Record record(kStackTrace, this);
458 // stack trace serial number
459 record.Write32(0);
460 // thread serial number
461 record.Write32(0);
462 // number of frames
463 record.Write32(0);
464 }
465
466
467 // HEAP SUMMARY - 0x07
468 //
469 // Format:
470 // u4 - total live bytes
471 // u4 - total live instances
472 // u8 - total bytes allocated
473 // u8 - total instances allocated
474 void HeapProfiler::WriteHeapSummary(uint32_t total_live_bytes,
475 uint32_t total_live_instances,
476 uint64_t total_bytes_allocated,
477 uint64_t total_instances_allocated) {
478 Record record(kHeapSummary, this);
479 record.Write32(total_live_bytes);
480 record.Write32(total_live_instances);
481 record.Write32(total_bytes_allocated);
482 record.Write32(total_instances_allocated);
483 }
484
485
486 // HEAP DUMP - 0x0C
487 //
488 // Format:
489 // []*
490 void HeapProfiler::WriteHeapDump() {
491 Record record(kHeapDump, this);
492 }
493
494
495 // CLASS DUMP - 0x20
496 //
497 // Format:
498 // ID - class object ID
499 // u4 - stack trace serial number
500 // ID - super class object ID
501 // ID - class loader object ID
502 // ID - signers object ID
503 // ID - protection domain object ID
504 // ID - reserved
505 // ID - reserved
506 // u4 - instance size (in bytes)
507 // u2 - size of constant pool and number of records that follow:
508 // u2 - constant pool index
509 // u1 - type of entry: (See Basic Type)
510 // value - value of entry (u1, u2, u4, or u8 based on type of entry)
511 // u2 - Number of static fields:
512 // ID - static field name string ID
513 // u1 - type of field: (See Basic Type)
514 // value - value of entry (u1, u2, u4, or u8 based on type of field)
515 // u2 - Number of instance fields (not including super class's)
516 // ID - field name string ID
517 // u1 - type of field: (See Basic Type)
518 void HeapProfiler::WriteClassDump(const RawClass* raw_class) {
519 SubRecord sub(kClassDump, this);
520 // class object ID
521 sub.WriteObjectId(ClassId(raw_class));
522 // stack trace serial number
523 sub.Write32(0);
524 // super class object ID
525 const RawClass* super_class = GetSuperClass(raw_class);
526 if (super_class == Class::null()) {
527 sub.WriteObjectId(NULL);
528 } else {
529 sub.WriteObjectId(ClassId(super_class));
530 }
531 // class loader object ID
532 sub.WriteObjectId(NULL);
533 // signers object ID
534 sub.WriteObjectId(NULL);
535 // protection domain object ID
536 sub.WriteObjectId(NULL);
537 // reserved
538 sub.WriteObjectId(NULL);
539 // reserved
540 sub.WriteObjectId(NULL);
541
542 intptr_t num_static_fields = 0;
543 intptr_t num_instance_fields = 0;
544
545 RawArray* raw_array = raw_class->ptr()->fields_;
546 if (raw_array != Array::null()) {
547 for (intptr_t i = 0; i < Smi::Value(raw_array->ptr()->length_); ++i) {
548 RawField* raw_field =
549 reinterpret_cast<RawField*>(raw_array->ptr()->data()[i]);
550 if (Field::StaticBit::decode(raw_field->ptr()->kind_bits_)) {
551 ++num_static_fields;
552 } else {
553 ++num_instance_fields;
554 }
555 }
556 }
557 // instance size (in bytes)
558 intptr_t instance_size_in_words = raw_class->ptr()->instance_size_in_words_;
559 if (instance_size_in_words == 0) {
560 // TODO(iposva): Better accounting of variable sized VM classes.
561 instance_size_in_words = num_instance_fields;
562 }
563 sub.Write32(instance_size_in_words * kWordSize);
564 // size of constant pool and number of records that follow:
565 sub.Write16(0);
566 // Number of static fields
567 sub.Write16(num_static_fields);
568 // Static fields:
569 if (raw_array != Array::null()) {
570 for (intptr_t i = 0; i < Smi::Value(raw_array->ptr()->length_); ++i) {
571 RawField* raw_field =
572 reinterpret_cast<RawField*>(raw_array->ptr()->data()[i]);
573 if (Field::StaticBit::decode(raw_field->ptr()->kind_bits_)) {
574 ASSERT(raw_field->ptr()->name_ != String::null());
575 // static field name string ID
576 sub.WriteObjectId(StringId(raw_field->ptr()->name_));
577 // type of static field
578 sub.Write8(kObject);
579 // value of entry
580 sub.WriteObjectId(ObjectId(raw_field->ptr()->value_));
581 }
582 }
583 }
584 // Number of instance fields (not include super class's)
585 sub.Write16(num_instance_fields);
586 // Instance fields:
587 if (raw_array != Array::null()) {
588 for (intptr_t i = 0; i < Smi::Value(raw_array->ptr()->length_); ++i) {
589 RawField* raw_field =
590 reinterpret_cast<RawField*>(raw_array->ptr()->data()[i]);
591 if (!Field::StaticBit::decode(raw_field->ptr()->kind_bits_)) {
592 ASSERT(raw_field->ptr()->name_ != String::null());
593 // field name string ID
594 sub.WriteObjectId(StringId(raw_field->ptr()->name_));
595 // type of field
596 sub.Write8(kObject);
597 }
598 }
599 }
600 }
601
602 void HeapProfiler::WriteFakeClassDump(FakeClass fake_class,
603 FakeClass fake_super_class) {
604 SubRecord sub(kClassDump, this);
605 // class object ID
606 sub.WriteObjectId(reinterpret_cast<void*>(fake_class));
607 // stack trace serial number
608 sub.Write32(0);
609 // super class object ID
610 sub.WriteObjectId(reinterpret_cast<void*>(fake_super_class));
611 // class loader object ID
612 sub.WriteObjectId(NULL);
613 // signers object ID
614 sub.WriteObjectId(NULL);
615 // protection domain object ID
616 sub.WriteObjectId(NULL);
617 // reserved
618 sub.WriteObjectId(NULL);
619 // reserved
620 sub.WriteObjectId(NULL);
621 // instance size (in bytes)
622 sub.Write32(0);
623 // size of constant pool and number of records that follow:
624 sub.Write16(0);
625 // Number of static fields
626 sub.Write16(0);
627 // Number of instance fields (not include super class's)
628 sub.Write16(0);
629 }
630
631
632
633 // INSTANCE DUMP - 0x21
634 //
635 // Format:
636 // ID - object ID
637 // u4 - stack trace serial number
638 // ID - class object ID
639 // u4 - number of bytes that follow
640 // [value]* - instance field values (this class, followed by super class, etc)
641 void HeapProfiler::WriteInstanceDump(const RawObject* raw_obj) {
642 ASSERT(raw_obj->IsHeapObject());
643 SubRecord sub(kInstanceDump, this);
644 // object ID
645 sub.WriteObjectId(raw_obj);
646 // stack trace serial number
647 sub.Write32(0);
648 // class object ID
649 sub.WriteObjectId(ClassId(GetClass(raw_obj)));
650 // number of bytes that follow
651 intptr_t num_instance_fields = 0;
652 for (const RawClass* cls = GetClass(raw_obj);
653 cls != Class::null();
654 cls = GetSuperClass(cls)) {
655 RawArray* raw_array = cls->ptr()->fields_;
656 if (raw_array != Array::null()) {
657 intptr_t length = Smi::Value(raw_array->ptr()->length_);
658 for (intptr_t i = 0; i < length; ++i) {
659 RawField* raw_field =
660 reinterpret_cast<RawField*>(raw_array->ptr()->data()[i]);
661 if (!Field::StaticBit::decode(raw_field->ptr()->kind_bits_)) {
662 ++num_instance_fields;
663 }
664 }
665 }
666 }
667 int64_t num_instance_bytes = num_instance_fields * kObjectIdSize;
668 ASSERT(num_instance_bytes <= kMaxUint32);
669 sub.Write32(num_instance_bytes);
670 // instance field values (this class, followed by super class, etc)
671 for (const RawClass* cls = GetClass(raw_obj);
672 cls != Class::null();
673 cls = GetSuperClass(cls)) {
674 RawArray* raw_array = cls->ptr()->fields_;
675 if (raw_array != Array::null()) {
676 intptr_t length = Smi::Value(raw_array->ptr()->length_);
677 uint8_t* base = reinterpret_cast<uint8_t*>(raw_obj->ptr());
678 for (intptr_t i = 0; i < length; ++i) {
679 RawField* raw_field =
680 reinterpret_cast<RawField*>(raw_array->ptr()->data()[i]);
681 if (!Field::StaticBit::decode(raw_field->ptr()->kind_bits_)) {
682 intptr_t offset_in_words =
683 Smi::Value(reinterpret_cast<RawSmi*>(raw_field->ptr()->value_));
684 intptr_t offset = offset_in_words * kWordSize;
685 RawObject* ptr = *reinterpret_cast<RawObject**>(base + offset);
686 sub.WriteObjectId(ObjectId(ptr));
687 }
688 }
689 }
690 }
691 }
692
693
694 // Write a specialized instance dump for "referenced" Smi objects.
695 void HeapProfiler::WriteSmiInstanceDump(const RawSmi* raw_smi) {
696 ASSERT(!raw_smi->IsHeapObject());
697 SubRecord sub(kInstanceDump, this);
698 // object ID
699 sub.WriteObjectId(raw_smi);
700 // stack trace serial number
701 sub.Write32(0);
702 // class object ID
703 sub.WriteObjectId(Isolate::Current()->class_table()->At(kSmiCid));
704 // number of bytes that follow
705 sub.Write32(0);
706 }
707
708
709 // OBJECT ARRAY DUMP - 0x22
710 //
711 // Format:
712 // ID - array object ID
713 // u4 - stack trace serial number
714 // u4 - number of elements
715 // ID - array class object ID
716 // [ID]* - elements
717 void HeapProfiler::WriteObjectArrayDump(const RawArray* raw_array) {
718 SubRecord sub(kObjectArrayDump, this);
719 // array object ID
720 sub.WriteObjectId(raw_array);
721 // stack trace serial number
722 sub.Write32(0);
723 // number of elements
724 intptr_t length = Smi::Value(raw_array->ptr()->length_);
725 sub.Write32(length);
726 // array class object ID
727 sub.WriteObjectId(reinterpret_cast<void*>(kArrayObject));
728 // elements
729 for (intptr_t i = 0; i < length; ++i) {
730 sub.WriteObjectId(ObjectId(raw_array->ptr()->data()[i]));
731 }
732 }
733
734
735 // PRIMITIVE ARRAY DUMP - 0x23
736 //
737 // Format:
738 // ID - array object ID
739 // u4 - stack trace serial number
740 // u4 - number of elements
741 // u1 - element type
742 // [u1]* - elements
743 void HeapProfiler::WritePrimitiveArrayDump(const RawTypedData* raw_byte_array,
744 uint8_t tag) {
745 SubRecord sub(kPrimitiveArrayDump, this);
746 // array object ID
747 sub.WriteObjectId(raw_byte_array);
748 // stack trace serial number
749 sub.Write32(0);
750 // number of elements
751 intptr_t length = Smi::Value(raw_byte_array->ptr()->length_);
752 const void* data = &(raw_byte_array->ptr()->data_[0]);
753 sub.Write32(length);
754 // element type
755 sub.Write8(tag);
756 // elements (packed)
757 for (intptr_t i = 0; i < length; ++i) {
758 if (tag == kByte) {
759 sub.Write8(reinterpret_cast<const int8_t*>(data)[i]);
760 } else if (tag == kShort) {
761 sub.Write16(reinterpret_cast<const int16_t*>(data)[i]);
762 break;
763 } else if (tag == kInt || tag == kFloat) {
764 sub.Write32(reinterpret_cast<const int32_t*>(data)[i]);
765 } else {
766 ASSERT(tag == kLong || tag == kDouble);
767 sub.Write64(reinterpret_cast<const int64_t*>(data)[i]);
768 }
769 }
770 }
771
772
773 void HeapProfilerRootVisitor::VisitPointers(RawObject** first,
774 RawObject** last) {
775 for (RawObject** current = first; current <= last; current++) {
776 RawObject* raw_obj = *current;
777 if (raw_obj->IsHeapObject()) {
778 // Skip visits of FreeListElements.
779 if (raw_obj->GetClassId() == kFreeListElement) {
780 // Only the class of the free list element should ever be visited.
781 ASSERT(first == last);
782 return;
783 }
784 uword obj_addr = RawObject::ToAddr(raw_obj);
785 if (!Isolate::Current()->heap()->Contains(obj_addr) &&
786 !Dart::vm_isolate()->heap()->Contains(obj_addr)) {
787 FATAL1("Invalid object pointer encountered %#" Px "\n", obj_addr);
788 }
789 }
790 profiler_->WriteRoot(raw_obj);
791 }
792 }
793
794
795 void HeapProfilerWeakRootVisitor::VisitHandle(uword addr) {
796 FinalizablePersistentHandle* handle =
797 reinterpret_cast<FinalizablePersistentHandle*>(addr);
798 RawObject* raw_obj = handle->raw();
799 visitor_->VisitPointer(&raw_obj);
800 }
801
802
803 void HeapProfilerObjectVisitor::VisitObject(RawObject* raw_obj) {
804 profiler_->WriteObject(raw_obj);
805 }
806
807 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/heap_profiler.h ('k') | runtime/vm/heap_profiler_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698