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

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

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