• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #ifndef V8_LIVEOBJECTLIST_H_
29 #define V8_LIVEOBJECTLIST_H_
30 
31 #include "v8.h"
32 
33 #include "checks.h"
34 #include "heap.h"
35 #include "objects.h"
36 #include "globals.h"
37 
38 namespace v8 {
39 namespace internal {
40 
41 #ifdef LIVE_OBJECT_LIST
42 
43 #ifdef DEBUG
44 // The following symbol when defined enables thorough verification of lol data.
45 // FLAG_verify_lol will also need to set to true to enable the verification.
46 #define VERIFY_LOL
47 #endif
48 
49 
50 typedef int LiveObjectType;
51 class LolFilter;
52 class LiveObjectSummary;
53 class DumpWriter;
54 class SummaryWriter;
55 
56 
57 // The LiveObjectList is both a mechanism for tracking a live capture of
58 // objects in the JS heap, as well as is the data structure which represents
59 // each of those captures.  Unlike a snapshot, the lol is live.  For example,
60 // if an object in a captured lol dies and is collected by the GC, the lol
61 // will reflect that the object is no longer available.  The term
62 // LiveObjectList (and lol) is used to describe both the mechanism and the
63 // data structure depending on context of use.
64 //
65 // In captured lols, objects are tracked using their address and an object id.
66 // The object id is unique.  Once assigned to an object, the object id can never
67 // be assigned to another object.  That is unless all captured lols are deleted
68 // which allows the user to start over with a fresh set of lols and object ids.
69 // The uniqueness of the object ids allows the user to track specific objects
70 // and inspect its longevity while debugging JS code in execution.
71 //
72 // The lol comes with utility functions to capture, dump, summarize, and diff
73 // captured lols amongst other functionality.  These functionality are
74 // accessible via the v8 debugger interface.
75 class LiveObjectList {
76  public:
77   inline static void GCEpilogue();
78   inline static void GCPrologue();
79   inline static void IterateElements(ObjectVisitor* v);
80   inline static void ProcessNonLive(HeapObject *obj);
81   inline static void UpdateReferencesForScavengeGC();
82 
83   // Note: LOLs can be listed by calling Dump(0, <lol id>), and 2 LOLs can be
84   // compared/diff'ed using Dump(<lol id1>, <lol id2>, ...).  This will yield
85   // a verbose dump of all the objects in the resultant lists.
86   //   Similarly, a summarized result of a LOL listing or a diff can be
87   // attained using the Summarize(0, <lol id>) and Summarize(<lol id1,
88   // <lol id2>, ...) respectively.
89 
90   static MaybeObject* Capture();
91   static bool Delete(int id);
92   static MaybeObject* Dump(int id1,
93                            int id2,
94                            int start_idx,
95                            int dump_limit,
96                            Handle<JSObject> filter_obj);
97   static MaybeObject* Info(int start_idx, int dump_limit);
98   static MaybeObject* Summarize(int id1, int id2, Handle<JSObject> filter_obj);
99 
100   static void Reset();
101   static Object* GetObj(int obj_id);
102   static int GetObjId(Object* obj);
103   static Object* GetObjId(Handle<String> address);
104   static MaybeObject* GetObjRetainers(int obj_id,
105                                       Handle<JSObject> instance_filter,
106                                       bool verbose,
107                                       int start,
108                                       int count,
109                                       Handle<JSObject> filter_obj);
110 
111   static Object* GetPath(int obj_id1,
112                          int obj_id2,
113                          Handle<JSObject> instance_filter);
114   static Object* PrintObj(int obj_id);
115 
116  private:
117 
118   struct Element {
119     int id_;
120     HeapObject* obj_;
121   };
122 
123   explicit LiveObjectList(LiveObjectList* prev, int capacity);
124   ~LiveObjectList();
125 
126   static void GCEpiloguePrivate();
127   static void IterateElementsPrivate(ObjectVisitor* v);
128 
129   static void DoProcessNonLive(HeapObject *obj);
130 
131   static int CompareElement(const Element* a, const Element* b);
132 
133   static Object* GetPathPrivate(HeapObject* obj1, HeapObject* obj2);
134 
135   static int GetRetainers(Handle<HeapObject> target,
136                           Handle<JSObject> instance_filter,
137                           Handle<FixedArray> retainers_arr,
138                           int start,
139                           int dump_limit,
140                           int* total_count,
141                           LolFilter* filter,
142                           LiveObjectSummary *summary,
143                           JSFunction* arguments_function,
144                           Handle<Object> error);
145 
146   static MaybeObject* DumpPrivate(DumpWriter* writer,
147                                   int start,
148                                   int dump_limit,
149                                   LolFilter* filter);
150   static MaybeObject* SummarizePrivate(SummaryWriter* writer,
151                                        LolFilter* filter,
152                                        bool is_tracking_roots);
153 
NeedLOLProcessing()154   static bool NeedLOLProcessing() { return (last() != NULL); }
NullifyNonLivePointer(HeapObject ** p)155   static void NullifyNonLivePointer(HeapObject **p) {
156     // Mask out the low bit that marks this as a heap object.  We'll use this
157     // cleared bit as an indicator that this pointer needs to be collected.
158     //
159     // Meanwhile, we still preserve its approximate value so that we don't
160     // have to resort the elements list all the time.
161     //
162     // Note: Doing so also makes this HeapObject* look like an SMI.  Hence,
163     // GC pointer updater will ignore it when it gets scanned.
164     *p = reinterpret_cast<HeapObject*>((*p)->address());
165   }
166 
prev()167   LiveObjectList* prev() { return prev_; }
next()168   LiveObjectList* next() { return next_; }
id()169   int id() { return id_; }
170 
list_count()171   static int list_count() { return list_count_; }
last()172   static LiveObjectList* last() { return last_; }
173 
174   inline static LiveObjectList* FindLolForId(int id, LiveObjectList* start_lol);
TotalObjCount()175   int TotalObjCount() { return GetTotalObjCountAndSize(NULL); }
176   int GetTotalObjCountAndSize(int* size_p);
177 
178   bool Add(HeapObject* obj);
179   Element* Find(HeapObject* obj);
180   static void NullifyMostRecent(HeapObject* obj);
181   void Sort();
182   static void SortAll();
183 
184   static void PurgeDuplicates();  // Only to be called by GCEpilogue.
185 
186 #ifdef VERIFY_LOL
187   static void Verify(bool match_heap_exactly = false);
188   static void VerifyNotInFromSpace();
189 #endif
190 
191   // Iterates the elements in every lol and returns the one that matches the
192   // specified key.  If no matching element is found, then it returns NULL.
193   template <typename T>
194   inline static LiveObjectList::Element*
195       FindElementFor(T (*GetValue)(LiveObjectList::Element*), T key);
196 
197   inline static int GetElementId(Element* element);
198   inline static HeapObject* GetElementObj(Element* element);
199 
200   // Instance fields.
201   LiveObjectList* prev_;
202   LiveObjectList* next_;
203   int id_;
204   int capacity_;
205   int obj_count_;
206   Element *elements_;
207 
208   // Statics for managing all the lists.
209   static uint32_t next_element_id_;
210   static int list_count_;
211   static int last_id_;
212   static LiveObjectList* first_;
213   static LiveObjectList* last_;
214 
215   friend class LolIterator;
216   friend class LolForwardIterator;
217   friend class LolDumpWriter;
218   friend class RetainersDumpWriter;
219   friend class RetainersSummaryWriter;
220   friend class UpdateLiveObjectListVisitor;
221 };
222 
223 
224 // Helper class for updating the LiveObjectList HeapObject pointers.
225 class UpdateLiveObjectListVisitor: public ObjectVisitor {
226  public:
227 
VisitPointer(Object ** p)228   void VisitPointer(Object** p) { UpdatePointer(p); }
229 
VisitPointers(Object ** start,Object ** end)230   void VisitPointers(Object** start, Object** end) {
231     // Copy all HeapObject pointers in [start, end).
232     for (Object** p = start; p < end; p++) UpdatePointer(p);
233   }
234 
235  private:
236   // Based on Heap::ScavengeObject() but only does forwarding of pointers
237   // to live new space objects, and not actually keep them alive.
UpdatePointer(Object ** p)238   void UpdatePointer(Object** p) {
239     Object* object = *p;
240     if (!Heap::InNewSpace(object)) return;
241 
242     HeapObject* heap_obj = HeapObject::cast(object);
243     ASSERT(Heap::InFromSpace(heap_obj));
244 
245     // We use the first word (where the map pointer usually is) of a heap
246     // object to record the forwarding pointer.  A forwarding pointer can
247     // point to an old space, the code space, or the to space of the new
248     // generation.
249     MapWord first_word = heap_obj->map_word();
250 
251     // If the first word is a forwarding address, the object has already been
252     // copied.
253     if (first_word.IsForwardingAddress()) {
254       *p = first_word.ToForwardingAddress();
255       return;
256 
257     // Else, it's a dead object.
258     } else {
259       LiveObjectList::NullifyNonLivePointer(reinterpret_cast<HeapObject**>(p));
260     }
261   }
262 };
263 
264 
265 #else  // !LIVE_OBJECT_LIST
266 
267 
268 class LiveObjectList {
269  public:
270   inline static void GCEpilogue() {}
271   inline static void GCPrologue() {}
272   inline static void IterateElements(ObjectVisitor* v) {}
273   inline static void ProcessNonLive(HeapObject* obj) {}
274   inline static void UpdateReferencesForScavengeGC() {}
275 
276   inline static MaybeObject* Capture() { return HEAP->undefined_value(); }
277   inline static bool Delete(int id) { return false; }
278   inline static MaybeObject* Dump(int id1,
279                                   int id2,
280                                   int start_idx,
281                                   int dump_limit,
282                                   Handle<JSObject> filter_obj) {
283     return HEAP->undefined_value();
284   }
285   inline static MaybeObject* Info(int start_idx, int dump_limit) {
286     return HEAP->undefined_value();
287   }
288   inline static MaybeObject* Summarize(int id1,
289                                        int id2,
290                                        Handle<JSObject> filter_obj) {
291     return HEAP->undefined_value();
292   }
293 
294   inline static void Reset() {}
295   inline static Object* GetObj(int obj_id) { return HEAP->undefined_value(); }
296   inline static Object* GetObjId(Handle<String> address) {
297     return HEAP->undefined_value();
298   }
299   inline static MaybeObject* GetObjRetainers(int obj_id,
300                                              Handle<JSObject> instance_filter,
301                                              bool verbose,
302                                              int start,
303                                              int count,
304                                              Handle<JSObject> filter_obj) {
305     return HEAP->undefined_value();
306   }
307 
308   inline static Object* GetPath(int obj_id1,
309                                 int obj_id2,
310                                 Handle<JSObject> instance_filter) {
311     return HEAP->undefined_value();
312   }
313   inline static Object* PrintObj(int obj_id) { return HEAP->undefined_value(); }
314 };
315 
316 
317 #endif  // LIVE_OBJECT_LIST
318 
319 } }  // namespace v8::internal
320 
321 #endif  // V8_LIVEOBJECTLIST_H_
322 
323