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

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: added basic test code 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
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;
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698