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 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()); 165 } 166 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. 225 class 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 } 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