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
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.
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.
28 #ifndef V8_LIVEOBJECTLIST_H_
29 #define V8_LIVEOBJECTLIST_H_
41 #ifdef LIVE_OBJECT_LIST
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.
50 typedef int LiveObjectType;
52 class LiveObjectSummary;
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.
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.
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 {
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();
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.
90 static MaybeObject* Capture();
91 static bool Delete(int id);
92 static MaybeObject* Dump(int id1,
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);
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,
109 Handle<JSObject> filter_obj);
111 static Object* GetPath(int obj_id1,
113 Handle<JSObject> instance_filter);
114 static Object* PrintObj(int obj_id);
122 explicit LiveObjectList(LiveObjectList* prev, int capacity);
125 static void GCEpiloguePrivate();
126 static void IterateElementsPrivate(ObjectVisitor* v);
128 static void DoProcessNonLive(HeapObject* obj);
130 static int CompareElement(const Element* a, const Element* b);
132 static Object* GetPathPrivate(HeapObject* obj1, HeapObject* obj2);
134 static int GetRetainers(Handle<HeapObject> target,
135 Handle<JSObject> instance_filter,
136 Handle<FixedArray> retainers_arr,
141 LiveObjectSummary* summary,
142 JSFunction* arguments_function,
143 Handle<Object> error);
145 static MaybeObject* DumpPrivate(DumpWriter* writer,
149 static MaybeObject* SummarizePrivate(SummaryWriter* writer,
151 bool is_tracking_roots);
153 static bool NeedLOLProcessing() { return (last() != NULL); }
154 static void NullifyNonLivePointer(HeapObject** p) {
155 // Mask out the low bit that marks this as a heap object. We'll use this
156 // cleared bit as an indicator that this pointer needs to be collected.
158 // Meanwhile, we still preserve its approximate value so that we don't
159 // have to resort the elements list all the time.
161 // Note: Doing so also makes this HeapObject* look like an SMI. Hence,
162 // GC pointer updater will ignore it when it gets scanned.
163 *p = reinterpret_cast<HeapObject*>((*p)->address());
166 LiveObjectList* prev() { return prev_; }
167 LiveObjectList* next() { return next_; }
168 int id() { return id_; }
170 static int list_count() { return list_count_; }
171 static LiveObjectList* last() { return last_; }
173 inline static LiveObjectList* FindLolForId(int id, LiveObjectList* start_lol);
174 int TotalObjCount() { return GetTotalObjCountAndSize(NULL); }
175 int GetTotalObjCountAndSize(int* size_p);
177 bool Add(HeapObject* obj);
178 Element* Find(HeapObject* obj);
179 static void NullifyMostRecent(HeapObject* obj);
181 static void SortAll();
183 static void PurgeDuplicates(); // Only to be called by GCEpilogue.
186 static void Verify(bool match_heap_exactly = false);
187 static void VerifyNotInFromSpace();
190 // Iterates the elements in every lol and returns the one that matches the
191 // specified key. If no matching element is found, then it returns NULL.
192 template <typename T>
193 inline static LiveObjectList::Element*
194 FindElementFor(T (*GetValue)(LiveObjectList::Element*), T key);
196 inline static int GetElementId(Element* element);
197 inline static HeapObject* GetElementObj(Element* element);
200 LiveObjectList* prev_;
201 LiveObjectList* next_;
207 // Statics for managing all the lists.
208 static uint32_t next_element_id_;
209 static int list_count_;
211 static LiveObjectList* first_;
212 static LiveObjectList* last_;
214 friend class LolIterator;
215 friend class LolForwardIterator;
216 friend class LolDumpWriter;
217 friend class RetainersDumpWriter;
218 friend class RetainersSummaryWriter;
219 friend class UpdateLiveObjectListVisitor;
223 // Helper class for updating the LiveObjectList HeapObject pointers.
224 class UpdateLiveObjectListVisitor: public ObjectVisitor {
226 void VisitPointer(Object** p) { UpdatePointer(p); }
228 void VisitPointers(Object** start, Object** end) {
229 // Copy all HeapObject pointers in [start, end).
230 for (Object** p = start; p < end; p++) UpdatePointer(p);
234 // Based on Heap::ScavengeObject() but only does forwarding of pointers
235 // to live new space objects, and not actually keep them alive.
236 void UpdatePointer(Object** p) {
238 if (!HEAP->InNewSpace(object)) return;
240 HeapObject* heap_obj = HeapObject::cast(object);
241 ASSERT(HEAP->InFromSpace(heap_obj));
243 // We use the first word (where the map pointer usually is) of a heap
244 // object to record the forwarding pointer. A forwarding pointer can
245 // point to an old space, the code space, or the to space of the new
247 MapWord first_word = heap_obj->map_word();
249 // If the first word is a forwarding address, the object has already been
251 if (first_word.IsForwardingAddress()) {
252 *p = first_word.ToForwardingAddress();
255 // Else, it's a dead object.
257 LiveObjectList::NullifyNonLivePointer(reinterpret_cast<HeapObject**>(p));
263 #else // !LIVE_OBJECT_LIST
266 class LiveObjectList {
268 inline static void GCEpilogue() {}
269 inline static void GCPrologue() {}
270 inline static void IterateElements(ObjectVisitor* v) {}
271 inline static void ProcessNonLive(HeapObject* obj) {}
272 inline static void UpdateReferencesForScavengeGC() {}
274 inline static MaybeObject* Capture() { return HEAP->undefined_value(); }
275 inline static bool Delete(int id) { return false; }
276 inline static MaybeObject* Dump(int id1,
280 Handle<JSObject> filter_obj) {
281 return HEAP->undefined_value();
283 inline static MaybeObject* Info(int start_idx, int dump_limit) {
284 return HEAP->undefined_value();
286 inline static MaybeObject* Summarize(int id1,
288 Handle<JSObject> filter_obj) {
289 return HEAP->undefined_value();
292 inline static void Reset() {}
293 inline static Object* GetObj(int obj_id) { return HEAP->undefined_value(); }
294 inline static Object* GetObjId(Handle<String> address) {
295 return HEAP->undefined_value();
297 inline static MaybeObject* GetObjRetainers(int obj_id,
298 Handle<JSObject> instance_filter,
302 Handle<JSObject> filter_obj) {
303 return HEAP->undefined_value();
306 inline static Object* GetPath(int obj_id1,
308 Handle<JSObject> instance_filter) {
309 return HEAP->undefined_value();
311 inline static Object* PrintObj(int obj_id) { return HEAP->undefined_value(); }
315 #endif // LIVE_OBJECT_LIST
317 } } // namespace v8::internal
319 #endif // V8_LIVEOBJECTLIST_H_