blob: 23e418d6d86a8bc0a19dfbf993c1cf90da3217ec [file] [log] [blame]
Steve Block1e0659c2011-05-24 12:43:12 +01001// 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
38namespace v8 {
39namespace internal {
40
41#ifdef LIVE_OBJECT_LIST
42
Ben Murdoche0cee9b2011-05-25 10:26:03 +010043#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
Steve Block1e0659c2011-05-24 12:43:12 +010048
Ben Murdoche0cee9b2011-05-25 10:26:03 +010049
50typedef int LiveObjectType;
51class LolFilter;
52class LiveObjectSummary;
53class DumpWriter;
54class 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.
Steve Block1e0659c2011-05-24 12:43:12 +010075class LiveObjectList {
76 public:
Ben Murdoche0cee9b2011-05-25 10:26:03 +010077 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();
Steve Block1e0659c2011-05-24 12:43:12 +010082
Ben Murdoche0cee9b2011-05-25 10:26:03 +010083 // 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);
Steve Block1e0659c2011-05-24 12:43:12 +010092 static MaybeObject* Dump(int id1,
93 int id2,
94 int start_idx,
95 int dump_limit,
Ben Murdoche0cee9b2011-05-25 10:26:03 +010096 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);
Steve Block1e0659c2011-05-24 12:43:12 +010099
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100100 static void Reset();
101 static Object* GetObj(int obj_id);
102 static int GetObjId(Object* obj);
103 static Object* GetObjId(Handle<String> address);
Steve Block1e0659c2011-05-24 12:43:12 +0100104 static MaybeObject* GetObjRetainers(int obj_id,
105 Handle<JSObject> instance_filter,
106 bool verbose,
107 int start,
108 int count,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100109 Handle<JSObject> filter_obj);
Steve Block1e0659c2011-05-24 12:43:12 +0100110
111 static Object* GetPath(int obj_id1,
112 int obj_id2,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100113 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
154 static bool NeedLOLProcessing() { return (last() != NULL); }
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());
Steve Block1e0659c2011-05-24 12:43:12 +0100165 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100166
167 LiveObjectList* prev() { return prev_; }
168 LiveObjectList* next() { return next_; }
169 int id() { return id_; }
170
171 static int list_count() { return list_count_; }
172 static LiveObjectList* last() { return last_; }
173
174 inline static LiveObjectList* FindLolForId(int id, LiveObjectList* start_lol);
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.
225class UpdateLiveObjectListVisitor: public ObjectVisitor {
226 public:
227
228 void VisitPointer(Object** p) { UpdatePointer(p); }
229
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.
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 }
Steve Block1e0659c2011-05-24 12:43:12 +0100262};
263
264
265#else // !LIVE_OBJECT_LIST
266
267
268class LiveObjectList {
269 public:
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100270 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
Steve Block44f0eee2011-05-26 01:26:41 +0100276 inline static MaybeObject* Capture() { return HEAP->undefined_value(); }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100277 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) {
Steve Block44f0eee2011-05-26 01:26:41 +0100283 return HEAP->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100284 }
285 inline static MaybeObject* Info(int start_idx, int dump_limit) {
Steve Block44f0eee2011-05-26 01:26:41 +0100286 return HEAP->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100287 }
288 inline static MaybeObject* Summarize(int id1,
289 int id2,
290 Handle<JSObject> filter_obj) {
Steve Block44f0eee2011-05-26 01:26:41 +0100291 return HEAP->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100292 }
293
294 inline static void Reset() {}
Steve Block44f0eee2011-05-26 01:26:41 +0100295 inline static Object* GetObj(int obj_id) { return HEAP->undefined_value(); }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100296 inline static Object* GetObjId(Handle<String> address) {
Steve Block44f0eee2011-05-26 01:26:41 +0100297 return HEAP->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100298 }
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) {
Steve Block44f0eee2011-05-26 01:26:41 +0100305 return HEAP->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100306 }
307
308 inline static Object* GetPath(int obj_id1,
309 int obj_id2,
310 Handle<JSObject> instance_filter) {
Steve Block44f0eee2011-05-26 01:26:41 +0100311 return HEAP->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100312 }
Steve Block44f0eee2011-05-26 01:26:41 +0100313 inline static Object* PrintObj(int obj_id) { return HEAP->undefined_value(); }
Steve Block1e0659c2011-05-24 12:43:12 +0100314};
315
316
317#endif // LIVE_OBJECT_LIST
318
319} } // namespace v8::internal
320
321#endif // V8_LIVEOBJECTLIST_H_
322