Home | History | Annotate | Download | only in src
      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