Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2012 Google Inc. All Rights Reserved. | |
| 2 // Author: nricci@google.com (Nathan Ricci) | |
|
siva
2012/12/05 16:06:40
This copyright doesn't seem to be standard.
cshapiro
2012/12/08 03:23:08
Done.
| |
| 3 | |
| 4 #include "include/dart_api.h" | |
|
siva
2012/12/05 16:06:40
blank line.
cshapiro
2012/12/08 03:23:08
Done.
| |
| 5 #include "vm/dart_api_state.h" | |
| 6 #include "vm/debugger.h" | |
| 7 #include "vm/heap_trace.h" | |
| 8 #include "vm/isolate.h" | |
| 9 #include "vm/object.h" | |
| 10 #include "vm/object_set.h" | |
| 11 #include "vm/object_store.h" | |
| 12 #include "vm/os.h" | |
| 13 #include "vm/stack_frame.h" | |
| 14 #include "vm/unicode.h" | |
| 15 | |
| 16 namespace dart { | |
| 17 | |
| 18 Dart_FileOpenCallback HeapTrace::open_callback_ = NULL; | |
| 19 Dart_FileWriteCallback HeapTrace::write_callback_ = NULL; | |
| 20 Dart_FileCloseCallback HeapTrace::close_callback_ = NULL; | |
| 21 bool HeapTrace::tracing_enabled_ = false; | |
| 22 const char* HeapTrace::file_name_prefix_ = NULL; | |
| 23 | |
| 24 | |
| 25 class HeapTraceVisitor : public ObjectPointerVisitor { | |
| 26 public: | |
| 27 HeapTraceVisitor(Isolate* isolate, HeapTrace* tracer, ObjectSet* object_set) | |
| 28 : ObjectPointerVisitor(isolate), | |
| 29 tracer_(tracer), | |
| 30 vm_isolate_(Dart::vm_isolate()), | |
| 31 object_set_(object_set) { | |
| 32 } | |
| 33 | |
| 34 void VisitPointers(RawObject** first, RawObject** last) { | |
| 35 for (RawObject** current = first; current <= last; current++) { | |
| 36 RawObject* raw_obj = *current; | |
| 37 | |
| 38 // We only care about objects in the heap | |
| 39 // Also, since this visitor will frequently be encountering redudant | |
| 40 // roots, we use an object_set to skip the duplicates. | |
| 41 if (raw_obj->IsHeapObject() && | |
| 42 raw_obj != reinterpret_cast<RawObject*>(0x1) && | |
| 43 raw_obj != reinterpret_cast<RawObject*>(0xabababab) && | |
| 44 !object_set_->Contains(raw_obj) && | |
| 45 !vm_isolate_->heap()->Contains(RawObject::ToAddr(raw_obj))) { | |
| 46 object_set_->Add(raw_obj); | |
| 47 uword addr = RawObject::ToAddr(raw_obj); | |
| 48 tracer_->TraceSingleRoot(addr); | |
| 49 } | |
| 50 } | |
| 51 } | |
| 52 | |
| 53 private: | |
| 54 HeapTrace* tracer_; | |
| 55 Isolate* vm_isolate_; | |
| 56 // TODO(nricc): replace this with a map or something else sparse. | |
| 57 ObjectSet* object_set_; | |
| 58 }; | |
| 59 | |
| 60 | |
| 61 class HeapTraceScopedHandleVisitor : public ObjectPointerVisitor { | |
| 62 public: | |
| 63 HeapTraceScopedHandleVisitor(Isolate* isolate, HeapTrace* tracer) | |
| 64 : ObjectPointerVisitor(isolate), tracer_(tracer) { | |
| 65 } | |
| 66 | |
| 67 void VisitPointers(RawObject** first, RawObject** last) { | |
| 68 for (RawObject** current = first; current <= last; current++) { | |
| 69 RawObject* raw_obj = *current; | |
| 70 Heap* heap = isolate()->heap(); | |
| 71 | |
| 72 // We only care about objects in the heap | |
| 73 if (raw_obj->IsHeapObject() && | |
| 74 raw_obj != reinterpret_cast<RawObject*>(0x1) && | |
| 75 raw_obj != reinterpret_cast<RawObject*>(0xabababab) && | |
| 76 heap->Contains(RawObject::ToAddr(raw_obj))) { | |
| 77 uword addr = RawObject::ToAddr(raw_obj); | |
| 78 tracer_->TraceScopedHandle(addr); | |
| 79 } | |
| 80 } | |
| 81 } | |
| 82 | |
| 83 private: | |
| 84 HeapTrace* tracer_; | |
| 85 }; | |
| 86 | |
| 87 | |
| 88 class HeapTraceObjectStoreVisitor : public ObjectPointerVisitor { | |
| 89 public: | |
| 90 HeapTraceObjectStoreVisitor(Isolate* isolate, HeapTrace* tracer) | |
| 91 : ObjectPointerVisitor(isolate), tracer_(tracer) {} | |
| 92 | |
| 93 void VisitPointers(RawObject** first, RawObject** last) { | |
| 94 for (RawObject** current = first; current <= last; current++) { | |
| 95 RawObject* raw_obj = *current; | |
| 96 | |
| 97 // We only care about obects in the heap | |
| 98 if (raw_obj->IsHeapObject() && | |
| 99 raw_obj != reinterpret_cast<RawObject*>(0x1) && | |
| 100 raw_obj != reinterpret_cast<RawObject*>(0xabababab)) { | |
| 101 uword addr = RawObject::ToAddr(raw_obj); | |
| 102 tracer_->TraceObjectStorePointer(addr); | |
| 103 } | |
| 104 } | |
| 105 } | |
| 106 | |
| 107 private: | |
| 108 HeapTrace* tracer_; | |
| 109 }; | |
| 110 | |
| 111 | |
| 112 class HeapTraceInitialHeapVisitor : public ObjectVisitor { | |
| 113 public: | |
| 114 HeapTraceInitialHeapVisitor(Isolate* isolate, HeapTrace* tracer) | |
| 115 : ObjectVisitor(isolate), tracer_(tracer) {} | |
| 116 | |
| 117 void VisitObject(RawObject *raw_obj) { | |
| 118 tracer_->TraceSnapshotAlloc(raw_obj, raw_obj->Size()); | |
| 119 } | |
| 120 | |
| 121 private: | |
| 122 HeapTrace* tracer_; | |
| 123 }; | |
| 124 | |
| 125 | |
| 126 | |
| 127 HeapTrace::HeapTrace() : isolate_initialized_(false), | |
| 128 output_stream_(NULL) { | |
| 129 } | |
| 130 | |
| 131 | |
| 132 HeapTrace::~HeapTrace() { | |
| 133 if (isolate_initialized_) { | |
| 134 (*close_callback_)(output_stream_); | |
| 135 } | |
| 136 } | |
| 137 | |
| 138 | |
| 139 ObjectSet* HeapTrace::CreateEmptyObjectSet() const { | |
| 140 Isolate* isolate = Isolate::Current(); | |
| 141 uword start, end; | |
| 142 isolate->heap()->StartEndAddress(&start, &end); | |
| 143 | |
| 144 Isolate* vm_isolate = Dart::vm_isolate(); | |
| 145 uword vm_start, vm_end; | |
| 146 vm_isolate->heap()->StartEndAddress(&vm_start, &vm_end); | |
| 147 | |
| 148 ObjectSet* allocated_set = new ObjectSet(Utils::Minimum(start, vm_start), | |
| 149 Utils::Maximum(end, vm_end)); | |
| 150 | |
| 151 return allocated_set; | |
| 152 } | |
| 153 | |
| 154 | |
| 155 void HeapTrace::ResizeObjectSet() { | |
| 156 Isolate* isolate = Isolate::Current(); | |
| 157 uword start, end; | |
| 158 isolate->heap()->StartEndAddress(&start, &end); | |
| 159 Isolate* vm_isolate = Dart::vm_isolate(); | |
| 160 uword vm_start, vm_end; | |
| 161 vm_isolate->heap()->StartEndAddress(&vm_start, &vm_end); | |
| 162 object_set_.Resize(Utils::Minimum(start, vm_start), | |
| 163 Utils::Maximum(end, vm_end)); | |
| 164 } | |
| 165 | |
| 166 | |
| 167 // InitializeIsolate or ...? | |
| 168 void HeapTrace::InitializeIsolateTracing(Isolate* isolate) { | |
| 169 // Do not trace the VM isolate | |
| 170 if (isolate == Dart::vm_isolate()) { | |
| 171 return; | |
| 172 } | |
| 173 ASSERT(isolate_initialized_ == false); | |
| 174 const char* format = "%s_%p.trace"; | |
| 175 intptr_t len = OS::SNPrint(NULL, 0, format, file_name_prefix_, isolate); | |
|
siva
2012/12/05 16:06:40
This seems kind of ad-hoc to use the isolate point
cshapiro
2012/12/08 03:23:08
Good idea. Fixed.
| |
| 176 char* filename = new char[len + 1]; | |
| 177 OS::SNPrint(filename, len + 1, format, file_name_prefix_, isolate); | |
| 178 output_stream_ = (*open_callback_)(filename); | |
| 179 ASSERT(output_stream_ != NULL); | |
| 180 delete[] filename; | |
| 181 isolate_initialized_ = true; | |
| 182 | |
| 183 HeapTraceObjectStoreVisitor object_store_visitor(isolate, this); | |
| 184 isolate->object_store()->VisitObjectPointers(&object_store_visitor); | |
| 185 | |
| 186 // Visit any objects that may have been allocated during startup, | |
| 187 // before we started tracing. | |
| 188 HeapTraceInitialHeapVisitor heap_visitor(isolate, this); | |
| 189 isolate->heap()->IterateObjects(&heap_visitor); | |
| 190 TraceRoots(isolate); | |
| 191 } | |
| 192 | |
| 193 | |
| 194 // Allocation Record - 'A' (0x41) | |
| 195 // | |
| 196 // Format: | |
| 197 // 'A' | |
| 198 // uword - address of allocated object | |
| 199 // uword - size of allocated object | |
| 200 void HeapTrace::TraceAllocation(uword addr, intptr_t size) { | |
| 201 if (isolate_initialized_) { | |
| 202 { | |
| 203 AllocationRecord rec(this); | |
| 204 rec.Write(addr); | |
| 205 rec.Write(size); | |
| 206 } | |
| 207 TraceRoots(Isolate::Current()); | |
| 208 } | |
| 209 } | |
| 210 | |
| 211 | |
| 212 // Snapshot Allocation Record - 'B' (0x41) | |
| 213 // | |
| 214 // Format: | |
| 215 // 'B' | |
| 216 // uword - address of allocated object | |
| 217 // uword - size of allocated object | |
| 218 void HeapTrace::TraceSnapshotAlloc(RawObject* obj, intptr_t size) { | |
| 219 if (isolate_initialized_) { | |
| 220 SnapshotAllocationRecord rec(this); | |
| 221 rec.Write(RawObject::ToAddr(obj)); | |
| 222 rec.Write(static_cast<uword>(size)); | |
| 223 } | |
| 224 } | |
| 225 | |
| 226 | |
| 227 | |
| 228 // Allocate Zone Handle Record - 'Z' (0x5a) | |
| 229 // | |
| 230 // Format: | |
| 231 // 'Z' | |
| 232 // uword - handle address (where the handle is pointing) | |
| 233 // uword - zone address (address of the zone the handle is in) | |
| 234 void HeapTrace::TraceAllocateZoneHandle(uword handle, uword zone_addr) { | |
| 235 if (isolate_initialized_) { | |
| 236 AllocZoneHandleRecord rec(this); | |
| 237 rec.Write(handle); | |
| 238 rec.Write(zone_addr); | |
| 239 } | |
| 240 } | |
| 241 | |
| 242 | |
| 243 // Delete Zone Record - 'z' (0x7a) | |
| 244 // | |
| 245 // Format: | |
| 246 // 'z' | |
| 247 // uword - zone address (all the handles in that zone are now gone) | |
| 248 void HeapTrace::TraceDeleteZone(Zone* zone) { | |
| 249 if (isolate_initialized_) { | |
| 250 DeleteZoneRecord rec(this); | |
| 251 rec.Write(reinterpret_cast<uword>(zone)); | |
| 252 } | |
| 253 } | |
| 254 | |
| 255 | |
| 256 // Delete Scoped Hanldes Record - 's' (0x73) | |
| 257 // | |
| 258 // Format: | |
| 259 // 's' | |
| 260 void HeapTrace::TraceDeleteScopedHandles() { | |
| 261 if (isolate_initialized_) { | |
| 262 DeleteScopedHandlesRecord rec(this); | |
| 263 } | |
| 264 } | |
| 265 | |
| 266 | |
| 267 // Copy Record - 'C' (0x43) | |
| 268 // | |
| 269 // Format: | |
| 270 // 'C' | |
| 271 // uword - old address | |
| 272 // uword - new address | |
| 273 void HeapTrace::TraceCopy(uword from_addr, uword to_addr) { | |
| 274 if (isolate_initialized_) { | |
| 275 CopyRecord rec(this); | |
| 276 rec.Write(from_addr); | |
| 277 rec.Write(to_addr); | |
| 278 } | |
| 279 } | |
| 280 | |
| 281 | |
| 282 // Object Store Recorda - 'O'(0x4f) | |
| 283 // | |
| 284 // Format: | |
| 285 // 'O' | |
| 286 // uword - address | |
| 287 void HeapTrace::TraceObjectStorePointer(uword addr) { | |
| 288 if (isolate_initialized_) { | |
| 289 ObjectStoreRecord rec(this); | |
| 290 rec.Write(addr); | |
| 291 } | |
| 292 } | |
| 293 | |
| 294 | |
| 295 // Promotion Records - 'P' (0x50) | |
| 296 // | |
| 297 // Format: | |
| 298 // 'P' | |
| 299 // uword - old address | |
| 300 // uword - new address | |
| 301 void HeapTrace::TracePromotion(uword old_addr, uword promoted_addr) { | |
| 302 if (isolate_initialized_) { | |
| 303 PromotionRecord rec(this); | |
| 304 rec.Write(old_addr); | |
| 305 rec.Write(promoted_addr); | |
| 306 } | |
| 307 } | |
| 308 | |
| 309 | |
| 310 // Death Range Record - 'L' (0x4c) | |
| 311 // | |
| 312 // Format: | |
| 313 // 'L' | |
| 314 // uword - inclusive start address of the space being left | |
| 315 // uword - exclusive end address of the space being left | |
| 316 void HeapTrace::TraceDeathRange(uword inclusive_start, uword exclusive_end) { | |
| 317 if (isolate_initialized_) { | |
| 318 DeathRangeRecord rec(this); | |
| 319 rec.Write(inclusive_start); | |
| 320 rec.Write(exclusive_end); | |
| 321 } | |
| 322 } | |
| 323 | |
| 324 // Register Class Record - 'K' (0x4b) | |
| 325 // | |
| 326 // Format: | |
| 327 // 'K' | |
| 328 // uword - address ( the address of the class) | |
| 329 void HeapTrace::TraceRegisterClass(RawClass* klass) { | |
| 330 if (isolate_initialized_) { | |
| 331 RegisterClassRecord rec(this); | |
| 332 rec.Write(RawObject::ToAddr(klass)); | |
| 333 } | |
| 334 } | |
| 335 | |
| 336 // Scoped Handle Record - 'H' (0x48) | |
| 337 // | |
| 338 // Format: | |
| 339 // 'H' | |
| 340 // uword - adress of the scoped handle (where it is pointing) | |
| 341 void HeapTrace::TraceScopedHandle(uword handle) { | |
| 342 if (isolate_initialized_) { | |
| 343 AllocScopedHandleRecord rec(this); | |
| 344 rec.Write(handle); | |
| 345 } | |
| 346 } | |
| 347 | |
| 348 | |
| 349 // Root Record - 'R' (0x52) | |
| 350 // | |
| 351 // Format: | |
| 352 // 'R' | |
| 353 // uword - address | |
| 354 void HeapTrace::TraceSingleRoot(uword root_addr) { | |
| 355 if (isolate_initialized_) { | |
| 356 RootRecord rec(this); | |
| 357 rec.Write(root_addr); | |
| 358 } | |
| 359 } | |
| 360 | |
| 361 | |
| 362 | |
| 363 // Sweep Record - 'S' | |
| 364 // | |
| 365 // Format: | |
| 366 // 'S' | |
| 367 // uword - address | |
| 368 void HeapTrace::TraceSweep(uword sweept_addr) { | |
| 369 if (isolate_initialized_) { | |
| 370 SweepRecord rec(this); | |
| 371 rec.Write(sweept_addr); | |
| 372 } | |
| 373 } | |
| 374 | |
| 375 // Does not output any records directly, | |
| 376 // but does call TraceSingleRoot | |
| 377 void HeapTrace::TraceRoots(Isolate* isolate) { | |
| 378 if (isolate_initialized_) { | |
| 379 ResizeObjectSet(); // TODO(nricci): map or something? | |
| 380 HeapTraceVisitor visitor(isolate, this, &object_set_); | |
| 381 HeapTraceScopedHandleVisitor handle_visitor(isolate, this); | |
| 382 | |
| 383 bool visit_prologue_weak_handles = true; | |
| 384 bool validate_frames = false; | |
| 385 | |
| 386 // Visit objects in per isolate stubs. | |
| 387 StubCode::VisitObjectPointers(&visitor); | |
| 388 | |
| 389 // stack | |
| 390 StackFrameIterator frames_iterator(validate_frames); | |
| 391 StackFrame* frame = frames_iterator.NextFrame(); | |
| 392 while (frame != NULL) { | |
| 393 frame->VisitObjectPointers(&visitor); | |
| 394 frame = frames_iterator.NextFrame(); | |
| 395 } | |
| 396 | |
| 397 if (isolate->api_state() != NULL) { | |
| 398 isolate->api_state()->VisitObjectPointers(&visitor, | |
| 399 visit_prologue_weak_handles); | |
| 400 } | |
| 401 | |
| 402 // Visit the top context which is stored in the isolate. | |
| 403 RawContext* top_context = isolate->top_context(); | |
| 404 visitor.VisitPointer(reinterpret_cast<RawObject**>(&top_context)); | |
| 405 | |
| 406 // Visit the currently active IC data array. | |
| 407 RawArray* ic_data_array = isolate->ic_data_array(); | |
| 408 visitor.VisitPointer(reinterpret_cast<RawObject**>(&ic_data_array)); | |
| 409 | |
| 410 // Visit objects in the debugger. | |
| 411 isolate->debugger()->VisitObjectPointers(&visitor); | |
| 412 | |
| 413 isolate->current_zone()->handles()-> | |
| 414 VisitUnvisitedScopedHandles(&handle_visitor); | |
| 415 | |
| 416 object_set_.FastClear(); | |
| 417 } | |
| 418 } | |
| 419 | |
| 420 | |
| 421 // Store Record - 'U' (0x55) | |
| 422 // | |
| 423 // Format: | |
| 424 // 'U' | |
| 425 // uword - originating object address (where a pointer is being stored) | |
| 426 // uword - byte offset into origin where the pointer is being stored | |
| 427 // uword - value of the pointer being stored | |
| 428 void HeapTrace::TraceStoreIntoObject(uword object, | |
| 429 uword field_addr, | |
| 430 uword value) { | |
| 431 if (isolate_initialized_) { | |
| 432 // We don't care about pointers into the VM_Islate heap, so skip them. | |
| 433 // There should not be any pointers /out/ of the VM isolate; so we | |
| 434 // do not check object | |
| 435 if (Isolate::Current()->heap()->Contains(value)) { | |
| 436 StoreRecord rec(this); | |
| 437 uword slot_offset = field_addr - object; | |
| 438 | |
| 439 rec.Write(object); | |
| 440 rec.Write(slot_offset); | |
| 441 rec.Write(value); | |
| 442 } | |
| 443 } | |
| 444 } | |
| 445 | |
| 446 | |
| 447 // Mark Sweep Start Record - '{' (0x7b) | |
| 448 // | |
| 449 // Format: | |
| 450 // '{' | |
| 451 void HeapTrace::TraceMarkSweepStart() { | |
| 452 if (isolate_initialized_) { | |
| 453 MarkSweepStartRecord rec(this); | |
| 454 } | |
| 455 } | |
| 456 | |
| 457 | |
| 458 // Mark Sweep Finish Record - '}' (0x7d) | |
| 459 // | |
| 460 // Format: | |
| 461 // '}' | |
| 462 void HeapTrace::TraceMarkSweepFinish() { | |
| 463 if (isolate_initialized_) { | |
| 464 MarkSweepFinishRecord rec(this); | |
| 465 } | |
| 466 } | |
| 467 | |
| 468 | |
| 469 void HeapTrace::InitTracing(Dart_FileOpenCallback open_callback, | |
| 470 Dart_FileWriteCallback write_callback, | |
| 471 Dart_FileCloseCallback close_callback, | |
| 472 const char* prefix) { | |
| 473 HeapTrace::open_callback_ = open_callback; | |
| 474 HeapTrace::write_callback_ = write_callback; | |
| 475 HeapTrace::close_callback_ = close_callback; | |
| 476 HeapTrace::file_name_prefix_ = prefix; | |
| 477 HeapTrace::tracing_enabled_ = true; | |
| 478 } | |
| 479 | |
| 480 | |
| 481 } // namespace dart | |
| OLD | NEW |