summaryrefslogtreecommitdiff
path: root/src/3rdparty/v8/src/liveobjectlist.h
blob: 23e418d6d86a8bc0a19dfbf993c1cf90da3217ec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef V8_LIVEOBJECTLIST_H_
#define V8_LIVEOBJECTLIST_H_

#include "v8.h"

#include "checks.h"
#include "heap.h"
#include "objects.h"
#include "globals.h"

namespace v8 {
namespace internal {

#ifdef LIVE_OBJECT_LIST

#ifdef DEBUG
// The following symbol when defined enables thorough verification of lol data.
// FLAG_verify_lol will also need to set to true to enable the verification.
#define VERIFY_LOL
#endif


typedef int LiveObjectType;
class LolFilter;
class LiveObjectSummary;
class DumpWriter;
class SummaryWriter;


// The LiveObjectList is both a mechanism for tracking a live capture of
// objects in the JS heap, as well as is the data structure which represents
// each of those captures.  Unlike a snapshot, the lol is live.  For example,
// if an object in a captured lol dies and is collected by the GC, the lol
// will reflect that the object is no longer available.  The term
// LiveObjectList (and lol) is used to describe both the mechanism and the
// data structure depending on context of use.
//
// In captured lols, objects are tracked using their address and an object id.
// The object id is unique.  Once assigned to an object, the object id can never
// be assigned to another object.  That is unless all captured lols are deleted
// which allows the user to start over with a fresh set of lols and object ids.
// The uniqueness of the object ids allows the user to track specific objects
// and inspect its longevity while debugging JS code in execution.
//
// The lol comes with utility functions to capture, dump, summarize, and diff
// captured lols amongst other functionality.  These functionality are
// accessible via the v8 debugger interface.
class LiveObjectList {
 public:
  inline static void GCEpilogue();
  inline static void GCPrologue();
  inline static void IterateElements(ObjectVisitor* v);
  inline static void ProcessNonLive(HeapObject *obj);
  inline static void UpdateReferencesForScavengeGC();

  // Note: LOLs can be listed by calling Dump(0, <lol id>), and 2 LOLs can be
  // compared/diff'ed using Dump(<lol id1>, <lol id2>, ...).  This will yield
  // a verbose dump of all the objects in the resultant lists.
  //   Similarly, a summarized result of a LOL listing or a diff can be
  // attained using the Summarize(0, <lol id>) and Summarize(<lol id1,
  // <lol id2>, ...) respectively.

  static MaybeObject* Capture();
  static bool Delete(int id);
  static MaybeObject* Dump(int id1,
                           int id2,
                           int start_idx,
                           int dump_limit,
                           Handle<JSObject> filter_obj);
  static MaybeObject* Info(int start_idx, int dump_limit);
  static MaybeObject* Summarize(int id1, int id2, Handle<JSObject> filter_obj);

  static void Reset();
  static Object* GetObj(int obj_id);
  static int GetObjId(Object* obj);
  static Object* GetObjId(Handle<String> address);
  static MaybeObject* GetObjRetainers(int obj_id,
                                      Handle<JSObject> instance_filter,
                                      bool verbose,
                                      int start,
                                      int count,
                                      Handle<JSObject> filter_obj);

  static Object* GetPath(int obj_id1,
                         int obj_id2,
                         Handle<JSObject> instance_filter);
  static Object* PrintObj(int obj_id);

 private:

  struct Element {
    int id_;
    HeapObject* obj_;
  };

  explicit LiveObjectList(LiveObjectList* prev, int capacity);
  ~LiveObjectList();

  static void GCEpiloguePrivate();
  static void IterateElementsPrivate(ObjectVisitor* v);

  static void DoProcessNonLive(HeapObject *obj);

  static int CompareElement(const Element* a, const Element* b);

  static Object* GetPathPrivate(HeapObject* obj1, HeapObject* obj2);

  static int GetRetainers(Handle<HeapObject> target,
                          Handle<JSObject> instance_filter,
                          Handle<FixedArray> retainers_arr,
                          int start,
                          int dump_limit,
                          int* total_count,
                          LolFilter* filter,
                          LiveObjectSummary *summary,
                          JSFunction* arguments_function,
                          Handle<Object> error);

  static MaybeObject* DumpPrivate(DumpWriter* writer,
                                  int start,
                                  int dump_limit,
                                  LolFilter* filter);
  static MaybeObject* SummarizePrivate(SummaryWriter* writer,
                                       LolFilter* filter,
                                       bool is_tracking_roots);

  static bool NeedLOLProcessing() { return (last() != NULL); }
  static void NullifyNonLivePointer(HeapObject **p) {
    // Mask out the low bit that marks this as a heap object.  We'll use this
    // cleared bit as an indicator that this pointer needs to be collected.
    //
    // Meanwhile, we still preserve its approximate value so that we don't
    // have to resort the elements list all the time.
    //
    // Note: Doing so also makes this HeapObject* look like an SMI.  Hence,
    // GC pointer updater will ignore it when it gets scanned.
    *p = reinterpret_cast<HeapObject*>((*p)->address());
  }

  LiveObjectList* prev() { return prev_; }
  LiveObjectList* next() { return next_; }
  int id() { return id_; }

  static int list_count() { return list_count_; }
  static LiveObjectList* last() { return last_; }

  inline static LiveObjectList* FindLolForId(int id, LiveObjectList* start_lol);
  int TotalObjCount() { return GetTotalObjCountAndSize(NULL); }
  int GetTotalObjCountAndSize(int* size_p);

  bool Add(HeapObject* obj);
  Element* Find(HeapObject* obj);
  static void NullifyMostRecent(HeapObject* obj);
  void Sort();
  static void SortAll();

  static void PurgeDuplicates();  // Only to be called by GCEpilogue.

#ifdef VERIFY_LOL
  static void Verify(bool match_heap_exactly = false);
  static void VerifyNotInFromSpace();
#endif

  // Iterates the elements in every lol and returns the one that matches the
  // specified key.  If no matching element is found, then it returns NULL.
  template <typename T>
  inline static LiveObjectList::Element*
      FindElementFor(T (*GetValue)(LiveObjectList::Element*), T key);

  inline static int GetElementId(Element* element);
  inline static HeapObject* GetElementObj(Element* element);

  // Instance fields.
  LiveObjectList* prev_;
  LiveObjectList* next_;
  int id_;
  int capacity_;
  int obj_count_;
  Element *elements_;

  // Statics for managing all the lists.
  static uint32_t next_element_id_;
  static int list_count_;
  static int last_id_;
  static LiveObjectList* first_;
  static LiveObjectList* last_;

  friend class LolIterator;
  friend class LolForwardIterator;
  friend class LolDumpWriter;
  friend class RetainersDumpWriter;
  friend class RetainersSummaryWriter;
  friend class UpdateLiveObjectListVisitor;
};


// Helper class for updating the LiveObjectList HeapObject pointers.
class UpdateLiveObjectListVisitor: public ObjectVisitor {
 public:

  void VisitPointer(Object** p) { UpdatePointer(p); }

  void VisitPointers(Object** start, Object** end) {
    // Copy all HeapObject pointers in [start, end).
    for (Object** p = start; p < end; p++) UpdatePointer(p);
  }

 private:
  // Based on Heap::ScavengeObject() but only does forwarding of pointers
  // to live new space objects, and not actually keep them alive.
  void UpdatePointer(Object** p) {
    Object* object = *p;
    if (!Heap::InNewSpace(object)) return;

    HeapObject* heap_obj = HeapObject::cast(object);
    ASSERT(Heap::InFromSpace(heap_obj));

    // We use the first word (where the map pointer usually is) of a heap
    // object to record the forwarding pointer.  A forwarding pointer can
    // point to an old space, the code space, or the to space of the new
    // generation.
    MapWord first_word = heap_obj->map_word();

    // If the first word is a forwarding address, the object has already been
    // copied.
    if (first_word.IsForwardingAddress()) {
      *p = first_word.ToForwardingAddress();
      return;

    // Else, it's a dead object.
    } else {
      LiveObjectList::NullifyNonLivePointer(reinterpret_cast<HeapObject**>(p));
    }
  }
};


#else  // !LIVE_OBJECT_LIST


class LiveObjectList {
 public:
  inline static void GCEpilogue() {}
  inline static void GCPrologue() {}
  inline static void IterateElements(ObjectVisitor* v) {}
  inline static void ProcessNonLive(HeapObject* obj) {}
  inline static void UpdateReferencesForScavengeGC() {}

  inline static MaybeObject* Capture() { return HEAP->undefined_value(); }
  inline static bool Delete(int id) { return false; }
  inline static MaybeObject* Dump(int id1,
                                  int id2,
                                  int start_idx,
                                  int dump_limit,
                                  Handle<JSObject> filter_obj) {
    return HEAP->undefined_value();
  }
  inline static MaybeObject* Info(int start_idx, int dump_limit) {
    return HEAP->undefined_value();
  }
  inline static MaybeObject* Summarize(int id1,
                                       int id2,
                                       Handle<JSObject> filter_obj) {
    return HEAP->undefined_value();
  }

  inline static void Reset() {}
  inline static Object* GetObj(int obj_id) { return HEAP->undefined_value(); }
  inline static Object* GetObjId(Handle<String> address) {
    return HEAP->undefined_value();
  }
  inline static MaybeObject* GetObjRetainers(int obj_id,
                                             Handle<JSObject> instance_filter,
                                             bool verbose,
                                             int start,
                                             int count,
                                             Handle<JSObject> filter_obj) {
    return HEAP->undefined_value();
  }

  inline static Object* GetPath(int obj_id1,
                                int obj_id2,
                                Handle<JSObject> instance_filter) {
    return HEAP->undefined_value();
  }
  inline static Object* PrintObj(int obj_id) { return HEAP->undefined_value(); }
};


#endif  // LIVE_OBJECT_LIST

} }  // namespace v8::internal

#endif  // V8_LIVEOBJECTLIST_H_