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 |