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 #ifdef LIVE_OBJECT_LIST
     29 
     30 #include <ctype.h>
     31 #include <stdlib.h>
     32 
     33 #include "v8.h"
     34 
     35 #include "checks.h"
     36 #include "global-handles.h"
     37 #include "heap.h"
     38 #include "inspector.h"
     39 #include "list-inl.h"
     40 #include "liveobjectlist-inl.h"
     41 #include "string-stream.h"
     42 #include "top.h"
     43 #include "v8utils.h"
     44 
     45 namespace v8 {
     46 namespace internal {
     47 
     48 
     49 typedef int (*RawComparer)(const void*, const void*);
     50 
     51 
     52 #ifdef CHECK_ALL_OBJECT_TYPES
     53 
     54 #define DEBUG_LIVE_OBJECT_TYPES(v) \
     55   v(Smi, "unexpected: Smi") \
     56   \
     57   v(CodeCache, "unexpected: CodeCache") \
     58   v(BreakPointInfo, "unexpected: BreakPointInfo") \
     59   v(DebugInfo, "unexpected: DebugInfo") \
     60   v(TypeSwitchInfo, "unexpected: TypeSwitchInfo") \
     61   v(SignatureInfo, "unexpected: SignatureInfo") \
     62   v(Script, "unexpected: Script") \
     63   v(ObjectTemplateInfo, "unexpected: ObjectTemplateInfo") \
     64   v(FunctionTemplateInfo, "unexpected: FunctionTemplateInfo") \
     65   v(CallHandlerInfo, "unexpected: CallHandlerInfo") \
     66   v(InterceptorInfo, "unexpected: InterceptorInfo") \
     67   v(AccessCheckInfo, "unexpected: AccessCheckInfo") \
     68   v(AccessorInfo, "unexpected: AccessorInfo") \
     69   v(ExternalTwoByteString, "unexpected: ExternalTwoByteString") \
     70   v(ExternalAsciiString, "unexpected: ExternalAsciiString") \
     71   v(ExternalString, "unexpected: ExternalString") \
     72   v(SeqTwoByteString, "unexpected: SeqTwoByteString") \
     73   v(SeqAsciiString, "unexpected: SeqAsciiString") \
     74   v(SeqString, "unexpected: SeqString") \
     75   v(JSFunctionResultCache, "unexpected: JSFunctionResultCache") \
     76   v(GlobalContext, "unexpected: GlobalContext") \
     77   v(MapCache, "unexpected: MapCache") \
     78   v(CodeCacheHashTable, "unexpected: CodeCacheHashTable") \
     79   v(CompilationCacheTable, "unexpected: CompilationCacheTable") \
     80   v(SymbolTable, "unexpected: SymbolTable") \
     81   v(Dictionary, "unexpected: Dictionary") \
     82   v(HashTable, "unexpected: HashTable") \
     83   v(DescriptorArray, "unexpected: DescriptorArray") \
     84   v(ExternalFloatArray, "unexpected: ExternalFloatArray") \
     85   v(ExternalUnsignedIntArray, "unexpected: ExternalUnsignedIntArray") \
     86   v(ExternalIntArray, "unexpected: ExternalIntArray") \
     87   v(ExternalUnsignedShortArray, "unexpected: ExternalUnsignedShortArray") \
     88   v(ExternalShortArray, "unexpected: ExternalShortArray") \
     89   v(ExternalUnsignedByteArray, "unexpected: ExternalUnsignedByteArray") \
     90   v(ExternalByteArray, "unexpected: ExternalByteArray") \
     91   v(JSValue, "unexpected: JSValue")
     92 
     93 #else
     94 #define DEBUG_LIVE_OBJECT_TYPES(v)
     95 #endif
     96 
     97 
     98 #define FOR_EACH_LIVE_OBJECT_TYPE(v) \
     99   DEBUG_LIVE_OBJECT_TYPES(v) \
    100   \
    101   v(JSArray, "JSArray") \
    102   v(JSRegExp, "JSRegExp") \
    103   v(JSFunction, "JSFunction") \
    104   v(JSGlobalObject, "JSGlobal") \
    105   v(JSBuiltinsObject, "JSBuiltins") \
    106   v(GlobalObject, "Global") \
    107   v(JSGlobalProxy, "JSGlobalProxy") \
    108   v(JSObject, "JSObject") \
    109   \
    110   v(Context, "meta: Context") \
    111   v(ByteArray, "meta: ByteArray") \
    112   v(PixelArray, "meta: PixelArray") \
    113   v(ExternalArray, "meta: ExternalArray") \
    114   v(FixedArray, "meta: FixedArray") \
    115   v(String, "String") \
    116   v(HeapNumber, "HeapNumber") \
    117   \
    118   v(Code, "meta: Code") \
    119   v(Map, "meta: Map") \
    120   v(Oddball, "Oddball") \
    121   v(Proxy, "meta: Proxy") \
    122   v(SharedFunctionInfo, "meta: SharedFunctionInfo") \
    123   v(Struct, "meta: Struct") \
    124   \
    125   v(HeapObject, "HeapObject")
    126 
    127 
    128 enum /* LiveObjectType */ {
    129 #define DECLARE_OBJECT_TYPE_ENUM(type, name) kType##type,
    130   FOR_EACH_LIVE_OBJECT_TYPE(DECLARE_OBJECT_TYPE_ENUM)
    131   kInvalidLiveObjType,
    132   kNumberOfTypes
    133 #undef DECLARE_OBJECT_TYPE_ENUM
    134 };
    135 
    136 
    137 LiveObjectType GetObjectType(HeapObject* heap_obj) {
    138   // TODO(mlam): investigate usint Map::instance_type() instead.
    139 #define CHECK_FOR_OBJECT_TYPE(type, name) \
    140   if (heap_obj->Is##type()) return kType##type;
    141   FOR_EACH_LIVE_OBJECT_TYPE(CHECK_FOR_OBJECT_TYPE)
    142 #undef CHECK_FOR_OBJECT_TYPE
    143 
    144   UNREACHABLE();
    145   return kInvalidLiveObjType;
    146 }
    147 
    148 
    149 inline const char* GetObjectTypeDesc(LiveObjectType type) {
    150   static const char* const name[kNumberOfTypes] = {
    151   #define DEFINE_OBJECT_TYPE_NAME(type, name) name,
    152     FOR_EACH_LIVE_OBJECT_TYPE(DEFINE_OBJECT_TYPE_NAME)
    153     "invalid"
    154   #undef DEFINE_OBJECT_TYPE_NAME
    155   };
    156   ASSERT(type < kNumberOfTypes);
    157   return name[type];
    158 }
    159 
    160 
    161 const char* GetObjectTypeDesc(HeapObject* heap_obj) {
    162   LiveObjectType type = GetObjectType(heap_obj);
    163   return GetObjectTypeDesc(type);
    164 }
    165 
    166 
    167 bool IsOfType(LiveObjectType type, HeapObject *obj) {
    168   // Note: there are types that are more general (e.g. JSObject) that would
    169   // have passed the Is##type_() test for more specialized types (e.g.
    170   // JSFunction).  If we find a more specialized match but we're looking for
    171   // the general type, then we should reject the ones that matches the
    172   // specialized type.
    173 #define CHECK_OBJECT_TYPE(type_, name) \
    174   if (obj->Is##type_()) return (type == kType##type_);
    175 
    176   FOR_EACH_LIVE_OBJECT_TYPE(CHECK_OBJECT_TYPE)
    177 #undef CHECK_OBJECT_TYPE
    178 
    179   return false;
    180 }
    181 
    182 
    183 const AllocationSpace kInvalidSpace = static_cast<AllocationSpace>(-1);
    184 
    185 static AllocationSpace FindSpaceFor(String* space_str) {
    186   SmartPointer<char> s =
    187       space_str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
    188 
    189   const char* key_str = *s;
    190   switch (key_str[0]) {
    191     case 'c':
    192       if (strcmp(key_str, "cell") == 0) return CELL_SPACE;
    193       if (strcmp(key_str, "code") == 0) return CODE_SPACE;
    194       break;
    195     case 'l':
    196       if (strcmp(key_str, "lo") == 0) return LO_SPACE;
    197       break;
    198     case 'm':
    199       if (strcmp(key_str, "map") == 0) return MAP_SPACE;
    200       break;
    201     case 'n':
    202       if (strcmp(key_str, "new") == 0) return NEW_SPACE;
    203       break;
    204     case 'o':
    205       if (strcmp(key_str, "old-pointer") == 0) return OLD_POINTER_SPACE;
    206       if (strcmp(key_str, "old-data") == 0) return OLD_DATA_SPACE;
    207       break;
    208   }
    209   return kInvalidSpace;
    210 }
    211 
    212 
    213 static bool InSpace(AllocationSpace space, HeapObject *heap_obj) {
    214   if (space != LO_SPACE) {
    215     return Heap::InSpace(heap_obj, space);
    216   }
    217 
    218   // This is an optimization to speed up the check for an object in the LO
    219   // space by exclusion because we know that all object pointers passed in
    220   // here are guaranteed to be in the heap.  Hence, it is safe to infer
    221   // using an exclusion test.
    222   // Note: calling Heap::InSpace(heap_obj, LO_SPACE) is too slow for our
    223   // filters.
    224   int first_space = static_cast<int>(FIRST_SPACE);
    225   int last_space = static_cast<int>(LO_SPACE);
    226   for (int sp = first_space; sp < last_space; sp++) {
    227     if (Heap::InSpace(heap_obj, static_cast<AllocationSpace>(sp))) {
    228       return false;
    229     }
    230   }
    231   SLOW_ASSERT(Heap::InSpace(heap_obj, LO_SPACE));
    232   return true;
    233 }
    234 
    235 
    236 static LiveObjectType FindTypeFor(String* type_str) {
    237   SmartPointer<char> s =
    238       type_str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
    239 
    240 #define CHECK_OBJECT_TYPE(type_, name) { \
    241     const char* type_desc = GetObjectTypeDesc(kType##type_); \
    242     const char* key_str = *s; \
    243     if (strstr(type_desc, key_str) != NULL) return kType##type_; \
    244   }
    245   FOR_EACH_LIVE_OBJECT_TYPE(CHECK_OBJECT_TYPE)
    246 #undef CHECK_OBJECT_TYPE
    247 
    248   return kInvalidLiveObjType;
    249 }
    250 
    251 
    252 class LolFilter {
    253  public:
    254   explicit LolFilter(Handle<JSObject> filter_obj);
    255 
    256   inline bool is_active() const { return is_active_; }
    257   inline bool Matches(HeapObject* obj) {
    258     return !is_active() || MatchesSlow(obj);
    259   }
    260 
    261  private:
    262   void InitTypeFilter(Handle<JSObject> filter_obj);
    263   void InitSpaceFilter(Handle<JSObject> filter_obj);
    264   void InitPropertyFilter(Handle<JSObject> filter_obj);
    265   bool MatchesSlow(HeapObject* obj);
    266 
    267   bool is_active_;
    268   LiveObjectType type_;
    269   AllocationSpace space_;
    270   Handle<String> prop_;
    271 };
    272 
    273 
    274 LolFilter::LolFilter(Handle<JSObject> filter_obj)
    275     : is_active_(false),
    276       type_(kInvalidLiveObjType),
    277       space_(kInvalidSpace),
    278       prop_() {
    279   if (filter_obj.is_null()) return;
    280 
    281   InitTypeFilter(filter_obj);
    282   InitSpaceFilter(filter_obj);
    283   InitPropertyFilter(filter_obj);
    284 }
    285 
    286 
    287 void LolFilter::InitTypeFilter(Handle<JSObject> filter_obj) {
    288   Handle<String> type_sym = Factory::LookupAsciiSymbol("type");
    289   MaybeObject* maybe_result = filter_obj->GetProperty(*type_sym);
    290   Object* type_obj;
    291   if (maybe_result->ToObject(&type_obj)) {
    292     if (type_obj->IsString()) {
    293       String* type_str = String::cast(type_obj);
    294       type_ = FindTypeFor(type_str);
    295       if (type_ != kInvalidLiveObjType) {
    296         is_active_ = true;
    297       }
    298     }
    299   }
    300 }
    301 
    302 
    303 void LolFilter::InitSpaceFilter(Handle<JSObject> filter_obj) {
    304   Handle<String> space_sym = Factory::LookupAsciiSymbol("space");
    305   MaybeObject* maybe_result = filter_obj->GetProperty(*space_sym);
    306   Object* space_obj;
    307   if (maybe_result->ToObject(&space_obj)) {
    308     if (space_obj->IsString()) {
    309       String* space_str = String::cast(space_obj);
    310       space_ = FindSpaceFor(space_str);
    311       if (space_ != kInvalidSpace) {
    312         is_active_ = true;
    313       }
    314     }
    315   }
    316 }
    317 
    318 
    319 void LolFilter::InitPropertyFilter(Handle<JSObject> filter_obj) {
    320   Handle<String> prop_sym = Factory::LookupAsciiSymbol("prop");
    321   MaybeObject* maybe_result = filter_obj->GetProperty(*prop_sym);
    322   Object* prop_obj;
    323   if (maybe_result->ToObject(&prop_obj)) {
    324     if (prop_obj->IsString()) {
    325       prop_ = Handle<String>(String::cast(prop_obj));
    326       is_active_ = true;
    327     }
    328   }
    329 }
    330 
    331 
    332 bool LolFilter::MatchesSlow(HeapObject* obj) {
    333   if ((type_ != kInvalidLiveObjType) && !IsOfType(type_, obj)) {
    334     return false;  // Fail because obj is not of the type of interest.
    335   }
    336   if ((space_ != kInvalidSpace) && !InSpace(space_, obj)) {
    337     return false;  // Fail because obj is not in the space of interest.
    338   }
    339   if (!prop_.is_null() && obj->IsJSObject()) {
    340     LookupResult result;
    341     obj->Lookup(*prop_, &result);
    342     if (!result.IsProperty()) {
    343       return false;  // Fail because obj does not have the property of interest.
    344     }
    345   }
    346   return true;
    347 }
    348 
    349 
    350 class LolIterator {
    351  public:
    352   LolIterator(LiveObjectList* older, LiveObjectList* newer)
    353       : older_(older),
    354         newer_(newer),
    355         curr_(0),
    356         elements_(0),
    357         count_(0),
    358         index_(0) { }
    359 
    360   inline void Init() {
    361     SetCurrent(newer_);
    362     // If the elements_ list is empty, then move on to the next list as long
    363     // as we're not at the last list (indicated by done()).
    364     while ((elements_ == NULL) && !Done()) {
    365       SetCurrent(curr_->prev_);
    366     }
    367   }
    368 
    369   inline bool Done() const {
    370     return (curr_ == older_);
    371   }
    372 
    373   // Object level iteration.
    374   inline void Next() {
    375     index_++;
    376     if (index_ >= count_) {
    377       // Iterate backwards until we get to the oldest list.
    378       while (!Done()) {
    379         SetCurrent(curr_->prev_);
    380         // If we have elements to process, we're good to go.
    381         if (elements_ != NULL) break;
    382 
    383         // Else, we should advance to the next older list.
    384       }
    385     }
    386   }
    387 
    388   inline int Id() const {
    389     return elements_[index_].id_;
    390   }
    391   inline HeapObject* Obj() const {
    392     return elements_[index_].obj_;
    393   }
    394 
    395   inline int LolObjCount() const {
    396     if (curr_ != NULL) return curr_->obj_count_;
    397     return 0;
    398   }
    399 
    400  protected:
    401   inline void SetCurrent(LiveObjectList* new_curr) {
    402     curr_ = new_curr;
    403     if (curr_ != NULL) {
    404       elements_ = curr_->elements_;
    405       count_ = curr_->obj_count_;
    406       index_ = 0;
    407     }
    408   }
    409 
    410   LiveObjectList* older_;
    411   LiveObjectList* newer_;
    412   LiveObjectList* curr_;
    413   LiveObjectList::Element* elements_;
    414   int count_;
    415   int index_;
    416 };
    417 
    418 
    419 class LolForwardIterator : public LolIterator {
    420  public:
    421   LolForwardIterator(LiveObjectList* first, LiveObjectList* last)
    422       : LolIterator(first, last) {
    423   }
    424 
    425   inline void Init() {
    426     SetCurrent(older_);
    427     // If the elements_ list is empty, then move on to the next list as long
    428     // as we're not at the last list (indicated by Done()).
    429     while ((elements_ == NULL) && !Done()) {
    430       SetCurrent(curr_->next_);
    431     }
    432   }
    433 
    434   inline bool Done() const {
    435     return (curr_ == newer_);
    436   }
    437 
    438   // Object level iteration.
    439   inline void Next() {
    440     index_++;
    441     if (index_ >= count_) {
    442       // Done with current list.  Move on to the next.
    443       while (!Done()) {  // If not at the last list already, ...
    444         SetCurrent(curr_->next_);
    445         // If we have elements to process, we're good to go.
    446         if (elements_ != NULL) break;
    447 
    448         // Else, we should advance to the next list.
    449       }
    450     }
    451   }
    452 };
    453 
    454 
    455 // Minimizes the white space in a string.  Tabs and newlines are replaced
    456 // with a space where appropriate.
    457 static int CompactString(char* str) {
    458   char* src = str;
    459   char* dst = str;
    460   char prev_ch = 0;
    461   while (*dst != '\0') {
    462     char ch = *src++;
    463     // We will treat non-ascii chars as '?'.
    464     if ((ch & 0x80) != 0) {
    465       ch = '?';
    466     }
    467     // Compact contiguous whitespace chars into a single ' '.
    468     if (isspace(ch)) {
    469       if (prev_ch != ' ') *dst++ = ' ';
    470       prev_ch = ' ';
    471       continue;
    472     }
    473     *dst++ = ch;
    474     prev_ch = ch;
    475   }
    476   return (dst - str);
    477 }
    478 
    479 
    480 // Generates a custom description based on the specific type of
    481 // object we're looking at.  We only generate specialized
    482 // descriptions where we can.  In all other cases, we emit the
    483 // generic info.
    484 static void GenerateObjectDesc(HeapObject* obj,
    485                                char* buffer,
    486                                int buffer_size) {
    487   Vector<char> buffer_v(buffer, buffer_size);
    488   ASSERT(obj != NULL);
    489   if (obj->IsJSArray()) {
    490     JSArray* jsarray = JSArray::cast(obj);
    491     double length = jsarray->length()->Number();
    492     OS::SNPrintF(buffer_v,
    493                  "%p <%s> len %g",
    494                  reinterpret_cast<void*>(obj),
    495                  GetObjectTypeDesc(obj),
    496                  length);
    497 
    498   } else if (obj->IsString()) {
    499     String *str = String::cast(obj);
    500     // Only grab up to 160 chars in case they are double byte.
    501     // We'll only dump 80 of them after we compact them.
    502     const int kMaxCharToDump = 80;
    503     const int kMaxBufferSize = kMaxCharToDump * 2;
    504     SmartPointer<char> str_sp = str->ToCString(DISALLOW_NULLS,
    505                                                ROBUST_STRING_TRAVERSAL,
    506                                                0,
    507                                                kMaxBufferSize);
    508     char* str_cstr = *str_sp;
    509     int length = CompactString(str_cstr);
    510     OS::SNPrintF(buffer_v,
    511                  "%p <%s> '%.80s%s'",
    512                  reinterpret_cast<void*>(obj),
    513                  GetObjectTypeDesc(obj),
    514                  str_cstr,
    515                  (length > kMaxCharToDump) ? "..." : "");
    516 
    517   } else if (obj->IsJSFunction() || obj->IsSharedFunctionInfo()) {
    518     SharedFunctionInfo* sinfo;
    519     if (obj->IsJSFunction()) {
    520       JSFunction* func = JSFunction::cast(obj);
    521       sinfo = func->shared();
    522     } else {
    523       sinfo = SharedFunctionInfo::cast(obj);
    524     }
    525 
    526     String* name = sinfo->DebugName();
    527     SmartPointer<char> name_sp =
    528         name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
    529     char* name_cstr = *name_sp;
    530 
    531     HeapStringAllocator string_allocator;
    532     StringStream stream(&string_allocator);
    533     sinfo->SourceCodePrint(&stream, 50);
    534     SmartPointer<const char> source_sp = stream.ToCString();
    535     const char* source_cstr = *source_sp;
    536 
    537     OS::SNPrintF(buffer_v,
    538                  "%p <%s> '%s' %s",
    539                  reinterpret_cast<void*>(obj),
    540                  GetObjectTypeDesc(obj),
    541                  name_cstr,
    542                  source_cstr);
    543 
    544   } else if (obj->IsFixedArray()) {
    545     FixedArray* fixed = FixedArray::cast(obj);
    546 
    547     OS::SNPrintF(buffer_v,
    548                  "%p <%s> len %d",
    549                  reinterpret_cast<void*>(obj),
    550                  GetObjectTypeDesc(obj),
    551                  fixed->length());
    552 
    553   } else {
    554     OS::SNPrintF(buffer_v,
    555                  "%p <%s>",
    556                  reinterpret_cast<void*>(obj),
    557                  GetObjectTypeDesc(obj));
    558   }
    559 }
    560 
    561 
    562 // Utility function for filling in a line of detail in a verbose dump.
    563 static bool AddObjDetail(Handle<FixedArray> arr,
    564                          int index,
    565                          int obj_id,
    566                          Handle<HeapObject> target,
    567                          const char* desc_str,
    568                          Handle<String> id_sym,
    569                          Handle<String> desc_sym,
    570                          Handle<String> size_sym,
    571                          Handle<JSObject> detail,
    572                          Handle<String> desc,
    573                          Handle<Object> error) {
    574   detail = Factory::NewJSObject(Top::object_function());
    575   if (detail->IsFailure()) {
    576     error = detail;
    577     return false;
    578   }
    579 
    580   int size = 0;
    581   char buffer[512];
    582   if (desc_str == NULL) {
    583     ASSERT(!target.is_null());
    584     HeapObject* obj = *target;
    585     GenerateObjectDesc(obj, buffer, sizeof(buffer));
    586     desc_str = buffer;
    587     size = obj->Size();
    588   }
    589   desc = Factory::NewStringFromAscii(CStrVector(desc_str));
    590   if (desc->IsFailure()) {
    591     error = desc;
    592     return false;
    593   }
    594 
    595   { MaybeObject* maybe_result = detail->SetProperty(*id_sym,
    596                                                     Smi::FromInt(obj_id),
    597                                                     NONE,
    598                                                     kNonStrictMode);
    599     if (maybe_result->IsFailure()) return false;
    600   }
    601   { MaybeObject* maybe_result = detail->SetProperty(*desc_sym,
    602                                                     *desc,
    603                                                     NONE,
    604                                                     kNonStrictMode);
    605     if (maybe_result->IsFailure()) return false;
    606   }
    607   { MaybeObject* maybe_result = detail->SetProperty(*size_sym,
    608                                                     Smi::FromInt(size),
    609                                                     NONE,
    610                                                     kNonStrictMode);
    611     if (maybe_result->IsFailure()) return false;
    612   }
    613 
    614   arr->set(index, *detail);
    615   return true;
    616 }
    617 
    618 
    619 class DumpWriter {
    620  public:
    621   virtual ~DumpWriter() {}
    622 
    623   virtual void ComputeTotalCountAndSize(LolFilter* filter,
    624                                         int* count,
    625                                         int* size) = 0;
    626   virtual bool Write(Handle<FixedArray> elements_arr,
    627                      int start,
    628                      int dump_limit,
    629                      LolFilter* filter,
    630                      Handle<Object> error) = 0;
    631 };
    632 
    633 
    634 class LolDumpWriter: public DumpWriter {
    635  public:
    636   LolDumpWriter(LiveObjectList* older, LiveObjectList* newer)
    637       : older_(older), newer_(newer) {
    638   }
    639 
    640   void ComputeTotalCountAndSize(LolFilter* filter, int* count, int* size) {
    641     *count = 0;
    642     *size = 0;
    643 
    644     LolIterator it(older_, newer_);
    645     for (it.Init(); !it.Done(); it.Next()) {
    646       HeapObject* heap_obj = it.Obj();
    647       if (!filter->Matches(heap_obj)) {
    648         continue;
    649       }
    650 
    651       *size += heap_obj->Size();
    652       (*count)++;
    653     }
    654   }
    655 
    656   bool Write(Handle<FixedArray> elements_arr,
    657              int start,
    658              int dump_limit,
    659              LolFilter* filter,
    660              Handle<Object> error) {
    661     // The lols are listed in latest to earliest.  We want to dump from
    662     // earliest to latest.  So, compute the last element to start with.
    663     int index = 0;
    664     int count = 0;
    665 
    666     // Prefetch some needed symbols.
    667     Handle<String> id_sym = Factory::LookupAsciiSymbol("id");
    668     Handle<String> desc_sym = Factory::LookupAsciiSymbol("desc");
    669     Handle<String> size_sym = Factory::LookupAsciiSymbol("size");
    670 
    671     // Fill the array with the lol object details.
    672     Handle<JSObject> detail;
    673     Handle<String> desc;
    674     Handle<HeapObject> target;
    675 
    676     LiveObjectList* first_lol = (older_ != NULL) ?
    677                                 older_->next_ : LiveObjectList::first_;
    678     LiveObjectList* last_lol = (newer_ != NULL) ? newer_->next_ : NULL;
    679 
    680     LolForwardIterator it(first_lol, last_lol);
    681     for (it.Init(); !it.Done() && (index < dump_limit); it.Next()) {
    682       HeapObject* heap_obj = it.Obj();
    683 
    684       // Skip objects that have been filtered out.
    685       if (!filter->Matches(heap_obj)) {
    686         continue;
    687       }
    688 
    689       // Only report objects that are in the section of interest.
    690       if (count >= start) {
    691         target = Handle<HeapObject>(heap_obj);
    692         bool success = AddObjDetail(elements_arr,
    693                                     index++,
    694                                     it.Id(),
    695                                     target,
    696                                     NULL,
    697                                     id_sym,
    698                                     desc_sym,
    699                                     size_sym,
    700                                     detail,
    701                                     desc,
    702                                     error);
    703         if (!success) return false;
    704       }
    705       count++;
    706     }
    707     return true;
    708   }
    709 
    710  private:
    711   LiveObjectList* older_;
    712   LiveObjectList* newer_;
    713 };
    714 
    715 
    716 class RetainersDumpWriter: public DumpWriter {
    717  public:
    718   RetainersDumpWriter(Handle<HeapObject> target,
    719                       Handle<JSObject> instance_filter,
    720                       Handle<JSFunction> args_function)
    721       : target_(target),
    722         instance_filter_(instance_filter),
    723         args_function_(args_function) {
    724   }
    725 
    726   void ComputeTotalCountAndSize(LolFilter* filter, int* count, int* size) {
    727     Handle<FixedArray> retainers_arr;
    728     Handle<Object> error;
    729 
    730     *size = -1;
    731     LiveObjectList::GetRetainers(target_,
    732                                  instance_filter_,
    733                                  retainers_arr,
    734                                  0,
    735                                  Smi::kMaxValue,
    736                                  count,
    737                                  filter,
    738                                  NULL,
    739                                  *args_function_,
    740                                  error);
    741   }
    742 
    743   bool Write(Handle<FixedArray> elements_arr,
    744              int start,
    745              int dump_limit,
    746              LolFilter* filter,
    747              Handle<Object> error) {
    748     int dummy;
    749     int count;
    750 
    751     // Fill the retainer objects.
    752     count = LiveObjectList::GetRetainers(target_,
    753                                          instance_filter_,
    754                                          elements_arr,
    755                                          start,
    756                                          dump_limit,
    757                                          &dummy,
    758                                          filter,
    759                                          NULL,
    760                                          *args_function_,
    761                                          error);
    762     if (count < 0) {
    763         return false;
    764     }
    765     return true;
    766   }
    767 
    768  private:
    769   Handle<HeapObject> target_;
    770   Handle<JSObject> instance_filter_;
    771   Handle<JSFunction> args_function_;
    772 };
    773 
    774 
    775 class LiveObjectSummary {
    776  public:
    777   explicit LiveObjectSummary(LolFilter* filter)
    778       : total_count_(0),
    779         total_size_(0),
    780         found_root_(false),
    781         found_weak_root_(false),
    782         filter_(filter) {
    783     memset(counts_, 0, sizeof(counts_[0]) * kNumberOfEntries);
    784     memset(sizes_, 0, sizeof(sizes_[0]) * kNumberOfEntries);
    785   }
    786 
    787   void Add(HeapObject* heap_obj) {
    788     int size = heap_obj->Size();
    789     LiveObjectType type = GetObjectType(heap_obj);
    790     ASSERT(type != kInvalidLiveObjType);
    791     counts_[type]++;
    792     sizes_[type] += size;
    793     total_count_++;
    794     total_size_ += size;
    795   }
    796 
    797   void set_found_root() { found_root_ = true; }
    798   void set_found_weak_root() { found_weak_root_ = true; }
    799 
    800   inline int Count(LiveObjectType type) {
    801     return counts_[type];
    802   }
    803   inline int Size(LiveObjectType type) {
    804     return sizes_[type];
    805   }
    806   inline int total_count() {
    807     return total_count_;
    808   }
    809   inline int total_size() {
    810     return total_size_;
    811   }
    812   inline bool found_root() {
    813     return found_root_;
    814   }
    815   inline bool found_weak_root() {
    816     return found_weak_root_;
    817   }
    818   int GetNumberOfEntries() {
    819     int entries = 0;
    820     for (int i = 0; i < kNumberOfEntries; i++) {
    821       if (counts_[i]) entries++;
    822     }
    823     return entries;
    824   }
    825 
    826   inline LolFilter* filter() { return filter_; }
    827 
    828   static const int kNumberOfEntries = kNumberOfTypes;
    829 
    830  private:
    831   int counts_[kNumberOfEntries];
    832   int sizes_[kNumberOfEntries];
    833   int total_count_;
    834   int total_size_;
    835   bool found_root_;
    836   bool found_weak_root_;
    837 
    838   LolFilter *filter_;
    839 };
    840 
    841 
    842 // Abstraction for a summary writer.
    843 class SummaryWriter {
    844  public:
    845   virtual ~SummaryWriter() {}
    846   virtual void Write(LiveObjectSummary* summary) = 0;
    847 };
    848 
    849 
    850 // A summary writer for filling in a summary of lol lists and diffs.
    851 class LolSummaryWriter: public SummaryWriter {
    852  public:
    853   LolSummaryWriter(LiveObjectList *older_lol,
    854                    LiveObjectList *newer_lol)
    855       : older_(older_lol), newer_(newer_lol) {
    856   }
    857 
    858   void Write(LiveObjectSummary* summary) {
    859     LolFilter* filter = summary->filter();
    860 
    861     // Fill the summary with the lol object details.
    862     LolIterator it(older_, newer_);
    863     for (it.Init(); !it.Done(); it.Next()) {
    864       HeapObject* heap_obj = it.Obj();
    865       if (!filter->Matches(heap_obj)) {
    866         continue;
    867       }
    868       summary->Add(heap_obj);
    869     }
    870   }
    871 
    872  private:
    873   LiveObjectList* older_;
    874   LiveObjectList* newer_;
    875 };
    876 
    877 
    878 // A summary writer for filling in a retainers list.
    879 class RetainersSummaryWriter: public SummaryWriter {
    880  public:
    881   RetainersSummaryWriter(Handle<HeapObject> target,
    882                          Handle<JSObject> instance_filter,
    883                          Handle<JSFunction> args_function)
    884       : target_(target),
    885         instance_filter_(instance_filter),
    886         args_function_(args_function) {
    887   }
    888 
    889   void Write(LiveObjectSummary* summary) {
    890     Handle<FixedArray> retainers_arr;
    891     Handle<Object> error;
    892     int dummy_total_count;
    893     LiveObjectList::GetRetainers(target_,
    894                                  instance_filter_,
    895                                  retainers_arr,
    896                                  0,
    897                                  Smi::kMaxValue,
    898                                  &dummy_total_count,
    899                                  summary->filter(),
    900                                  summary,
    901                                  *args_function_,
    902                                  error);
    903   }
    904 
    905  private:
    906   Handle<HeapObject> target_;
    907   Handle<JSObject> instance_filter_;
    908   Handle<JSFunction> args_function_;
    909 };
    910 
    911 
    912 uint32_t LiveObjectList::next_element_id_ = 1;
    913 int LiveObjectList::list_count_ = 0;
    914 int LiveObjectList::last_id_ = 0;
    915 LiveObjectList* LiveObjectList::first_ = NULL;
    916 LiveObjectList* LiveObjectList::last_ = NULL;
    917 
    918 
    919 LiveObjectList::LiveObjectList(LiveObjectList* prev, int capacity)
    920     : prev_(prev),
    921       next_(NULL),
    922       capacity_(capacity),
    923       obj_count_(0) {
    924   elements_ = NewArray<Element>(capacity);
    925   id_ = ++last_id_;
    926 
    927   list_count_++;
    928 }
    929 
    930 
    931 LiveObjectList::~LiveObjectList() {
    932   DeleteArray<Element>(elements_);
    933   delete prev_;
    934 }
    935 
    936 
    937 int LiveObjectList::GetTotalObjCountAndSize(int* size_p) {
    938   int size = 0;
    939   int count = 0;
    940   LiveObjectList *lol = this;
    941   do {
    942     // Only compute total size if requested i.e. when size_p is not null.
    943     if (size_p != NULL) {
    944       Element* elements = lol->elements_;
    945       for (int i = 0; i < lol->obj_count_; i++) {
    946         HeapObject* heap_obj = elements[i].obj_;
    947         size += heap_obj->Size();
    948       }
    949     }
    950     count += lol->obj_count_;
    951     lol = lol->prev_;
    952   } while (lol != NULL);
    953 
    954   if (size_p != NULL) {
    955     *size_p = size;
    956   }
    957   return count;
    958 }
    959 
    960 
    961 // Adds an object to the lol.
    962 // Returns true if successful, else returns false.
    963 bool LiveObjectList::Add(HeapObject* obj) {
    964   // If the object is already accounted for in the prev list which we inherit
    965   // from, then no need to add it to this list.
    966   if ((prev() != NULL) && (prev()->Find(obj) != NULL)) {
    967     return true;
    968   }
    969   ASSERT(obj_count_ <= capacity_);
    970   if (obj_count_ == capacity_) {
    971     // The heap must have grown and we have more objects than capacity to store
    972     // them.
    973     return false;  // Fail this addition.
    974   }
    975   Element& element = elements_[obj_count_++];
    976   element.id_ = next_element_id_++;
    977   element.obj_ = obj;
    978   return true;
    979 }
    980 
    981 
    982 // Comparator used for sorting and searching the lol.
    983 int LiveObjectList::CompareElement(const Element* a, const Element* b) {
    984   const HeapObject* obj1 = a->obj_;
    985   const HeapObject* obj2 = b->obj_;
    986   // For lol elements, it doesn't matter which comes first if 2 elements point
    987   // to the same object (which gets culled later).  Hence, we only care about
    988   // the the greater than / less than relationships.
    989   return (obj1 > obj2) ? 1 : (obj1 == obj2) ? 0 : -1;
    990 }
    991 
    992 
    993 // Looks for the specified object in the lol, and returns its element if found.
    994 LiveObjectList::Element* LiveObjectList::Find(HeapObject* obj) {
    995   LiveObjectList* lol = this;
    996   Element key;
    997   Element* result = NULL;
    998 
    999   key.obj_ = obj;
   1000   // Iterate through the chain of lol's to look for the object.
   1001   while ((result == NULL) && (lol != NULL)) {
   1002     result = reinterpret_cast<Element*>(
   1003         bsearch(&key, lol->elements_, lol->obj_count_,
   1004                 sizeof(Element),
   1005                 reinterpret_cast<RawComparer>(CompareElement)));
   1006     lol = lol->prev_;
   1007   }
   1008   return result;
   1009 }
   1010 
   1011 
   1012 // "Nullifies" (convert the HeapObject* into an SMI) so that it will get cleaned
   1013 // up in the GCEpilogue, while preserving the sort order of the lol.
   1014 // NOTE: the lols need to be already sorted before NullifyMostRecent() is
   1015 // called.
   1016 void LiveObjectList::NullifyMostRecent(HeapObject* obj) {
   1017   LiveObjectList* lol = last();
   1018   Element key;
   1019   Element* result = NULL;
   1020 
   1021   key.obj_ = obj;
   1022   // Iterate through the chain of lol's to look for the object.
   1023   while (lol != NULL) {
   1024     result = reinterpret_cast<Element*>(
   1025         bsearch(&key, lol->elements_, lol->obj_count_,
   1026                 sizeof(Element),
   1027                 reinterpret_cast<RawComparer>(CompareElement)));
   1028     if (result != NULL) {
   1029       // Since there may be more than one (we are nullifying dup's after all),
   1030       // find the first in the current lol, and nullify that.  The lol should
   1031       // be sorted already to make this easy (see the use of SortAll()).
   1032       int i = result - lol->elements_;
   1033 
   1034       // NOTE: we sort the lol in increasing order.  So, if an object has been
   1035       // "nullified" (its lowest bit will be cleared to make it look like an
   1036       // SMI), it would/should show up before the equivalent dups that have not
   1037       // yet been "nullified".  Hence, we should be searching backwards for the
   1038       // first occurence of a matching object and nullify that instance.  This
   1039       // will ensure that we preserve the expected sorting order.
   1040       for (i--; i > 0; i--) {
   1041         Element* element = &lol->elements_[i];
   1042         HeapObject* curr_obj = element->obj_;
   1043         if (curr_obj != obj) {
   1044             break;  // No more matches.  Let's move on.
   1045         }
   1046         result = element;  // Let this earlier match be the result.
   1047       }
   1048 
   1049       // Nullify the object.
   1050       NullifyNonLivePointer(&result->obj_);
   1051       return;
   1052     }
   1053     lol = lol->prev_;
   1054   }
   1055 }
   1056 
   1057 
   1058 // Sorts the lol.
   1059 void LiveObjectList::Sort() {
   1060   if (obj_count_ > 0) {
   1061     Vector<Element> elements_v(elements_, obj_count_);
   1062     elements_v.Sort(CompareElement);
   1063   }
   1064 }
   1065 
   1066 
   1067 // Sorts all captured lols starting from the latest.
   1068 void LiveObjectList::SortAll() {
   1069   LiveObjectList* lol = last();
   1070   while (lol != NULL) {
   1071     lol->Sort();
   1072     lol = lol->prev_;
   1073   }
   1074 }
   1075 
   1076 
   1077 // Counts the number of objects in the heap.
   1078 static int CountHeapObjects() {
   1079   int count = 0;
   1080   // Iterate over all the heap spaces and count the number of objects.
   1081   HeapIterator iterator(HeapIterator::kFilterFreeListNodes);
   1082   HeapObject* heap_obj = NULL;
   1083   while ((heap_obj = iterator.next()) != NULL) {
   1084     count++;
   1085   }
   1086   return count;
   1087 }
   1088 
   1089 
   1090 // Captures a current snapshot of all objects in the heap.
   1091 MaybeObject* LiveObjectList::Capture() {
   1092   HandleScope scope;
   1093 
   1094   // Count the number of objects in the heap.
   1095   int total_count = CountHeapObjects();
   1096   int count = total_count;
   1097   int size = 0;
   1098 
   1099   LiveObjectList* last_lol = last();
   1100   if (last_lol != NULL) {
   1101     count -= last_lol->TotalObjCount();
   1102   }
   1103 
   1104   LiveObjectList* lol;
   1105 
   1106   // Create a lol large enough to track all the objects.
   1107   lol = new LiveObjectList(last_lol, count);
   1108   if (lol == NULL) {
   1109     return NULL;  // No memory to proceed.
   1110   }
   1111 
   1112   // The HeapIterator needs to be in its own scope because it disables
   1113   // allocation, and we need allocate below.
   1114   {
   1115     // Iterate over all the heap spaces and add the objects.
   1116     HeapIterator iterator(HeapIterator::kFilterFreeListNodes);
   1117     HeapObject* heap_obj = NULL;
   1118     bool failed = false;
   1119     while (!failed && (heap_obj = iterator.next()) != NULL) {
   1120       failed = !lol->Add(heap_obj);
   1121       size += heap_obj->Size();
   1122     }
   1123     ASSERT(!failed);
   1124 
   1125     lol->Sort();
   1126 
   1127     // Add the current lol to the list of lols.
   1128     if (last_ != NULL) {
   1129       last_->next_ = lol;
   1130     } else {
   1131       first_ = lol;
   1132     }
   1133     last_ = lol;
   1134 
   1135 #ifdef VERIFY_LOL
   1136     if (FLAG_verify_lol) {
   1137       Verify(true);
   1138     }
   1139 #endif
   1140   }
   1141 
   1142   Handle<String> id_sym = Factory::LookupAsciiSymbol("id");
   1143   Handle<String> count_sym = Factory::LookupAsciiSymbol("count");
   1144   Handle<String> size_sym = Factory::LookupAsciiSymbol("size");
   1145 
   1146   Handle<JSObject> result = Factory::NewJSObject(Top::object_function());
   1147   if (result->IsFailure()) return Object::cast(*result);
   1148 
   1149   { MaybeObject* maybe_result = result->SetProperty(*id_sym,
   1150                                                     Smi::FromInt(lol->id()),
   1151                                                     NONE,
   1152                                                     kNonStrictMode);
   1153     if (maybe_result->IsFailure()) return maybe_result;
   1154   }
   1155   { MaybeObject* maybe_result = result->SetProperty(*count_sym,
   1156                                                     Smi::FromInt(total_count),
   1157                                                     NONE,
   1158                                                     kNonStrictMode);
   1159     if (maybe_result->IsFailure()) return maybe_result;
   1160   }
   1161   { MaybeObject* maybe_result = result->SetProperty(*size_sym,
   1162                                                     Smi::FromInt(size),
   1163                                                     NONE,
   1164                                                     kNonStrictMode);
   1165     if (maybe_result->IsFailure()) return maybe_result;
   1166   }
   1167 
   1168   return *result;
   1169 }
   1170 
   1171 
   1172 // Delete doesn't actually deletes an lol.  It just marks it as invisible since
   1173 // its contents are considered to be part of subsequent lists as well.  The
   1174 // only time we'll actually delete the lol is when we Reset() or if the lol is
   1175 // invisible, and its element count reaches 0.
   1176 bool LiveObjectList::Delete(int id) {
   1177   LiveObjectList *lol = last();
   1178   while (lol != NULL) {
   1179     if (lol->id() == id) {
   1180       break;
   1181     }
   1182     lol = lol->prev_;
   1183   }
   1184 
   1185   // If no lol is found for this id, then we fail to delete.
   1186   if (lol == NULL) return false;
   1187 
   1188   // Else, mark the lol as invisible i.e. id == 0.
   1189   lol->id_ = 0;
   1190   list_count_--;
   1191   ASSERT(list_count_ >= 0);
   1192   if (lol->obj_count_ == 0) {
   1193     // Point the next lol's prev to this lol's prev.
   1194     LiveObjectList* next = lol->next_;
   1195     LiveObjectList* prev = lol->prev_;
   1196     // Point next's prev to prev.
   1197     if (next != NULL) {
   1198       next->prev_ = lol->prev_;
   1199     } else {
   1200       last_ = lol->prev_;
   1201     }
   1202     // Point prev's next to next.
   1203     if (prev != NULL) {
   1204       prev->next_ = lol->next_;
   1205     } else {
   1206       first_ = lol->next_;
   1207     }
   1208 
   1209     lol->prev_ = NULL;
   1210     lol->next_ = NULL;
   1211 
   1212     // Delete this now empty and invisible lol.
   1213     delete lol;
   1214   }
   1215 
   1216   // Just in case we've marked everything invisible, then clean up completely.
   1217   if (list_count_ == 0) {
   1218     Reset();
   1219   }
   1220 
   1221   return true;
   1222 }
   1223 
   1224 
   1225 MaybeObject* LiveObjectList::Dump(int older_id,
   1226                                   int newer_id,
   1227                                   int start_idx,
   1228                                   int dump_limit,
   1229                                   Handle<JSObject> filter_obj) {
   1230   if ((older_id < 0) || (newer_id < 0) || (last() == NULL)) {
   1231     return Failure::Exception();  // Fail: 0 is not a valid lol id.
   1232   }
   1233   if (newer_id < older_id) {
   1234     // They are not in the expected order.  Swap them.
   1235     int temp = older_id;
   1236     older_id = newer_id;
   1237     newer_id = temp;
   1238   }
   1239 
   1240   LiveObjectList *newer_lol = FindLolForId(newer_id, last());
   1241   LiveObjectList *older_lol = FindLolForId(older_id, newer_lol);
   1242 
   1243   // If the id is defined, and we can't find a LOL for it, then we have an
   1244   // invalid id.
   1245   if ((newer_id != 0) && (newer_lol == NULL)) {
   1246     return Failure::Exception();  // Fail: the newer lol id is invalid.
   1247   }
   1248   if ((older_id != 0) && (older_lol == NULL)) {
   1249     return Failure::Exception();  // Fail: the older lol id is invalid.
   1250   }
   1251 
   1252   LolFilter filter(filter_obj);
   1253   LolDumpWriter writer(older_lol, newer_lol);
   1254   return DumpPrivate(&writer, start_idx, dump_limit, &filter);
   1255 }
   1256 
   1257 
   1258 MaybeObject* LiveObjectList::DumpPrivate(DumpWriter* writer,
   1259                                          int start,
   1260                                          int dump_limit,
   1261                                          LolFilter* filter) {
   1262   HandleScope scope;
   1263 
   1264   // Calculate the number of entries of the dump.
   1265   int count = -1;
   1266   int size = -1;
   1267   writer->ComputeTotalCountAndSize(filter, &count, &size);
   1268 
   1269   // Adjust for where to start the dump.
   1270   if ((start < 0) || (start >= count)) {
   1271     return Failure::Exception();  // invalid start.
   1272   }
   1273 
   1274   int remaining_count = count - start;
   1275   if (dump_limit > remaining_count) {
   1276     dump_limit = remaining_count;
   1277   }
   1278 
   1279   // Allocate an array to hold the result.
   1280   Handle<FixedArray> elements_arr = Factory::NewFixedArray(dump_limit);
   1281   if (elements_arr->IsFailure()) return Object::cast(*elements_arr);
   1282 
   1283   // Fill in the dump.
   1284   Handle<Object> error;
   1285   bool success = writer->Write(elements_arr,
   1286                                start,
   1287                                dump_limit,
   1288                                filter,
   1289                                error);
   1290   if (!success) return Object::cast(*error);
   1291 
   1292   MaybeObject* maybe_result;
   1293 
   1294   // Allocate the result body.
   1295   Handle<JSObject> body = Factory::NewJSObject(Top::object_function());
   1296   if (body->IsFailure()) return Object::cast(*body);
   1297 
   1298   // Set the updated body.count.
   1299   Handle<String> count_sym = Factory::LookupAsciiSymbol("count");
   1300   maybe_result = body->SetProperty(*count_sym,
   1301                                    Smi::FromInt(count),
   1302                                    NONE,
   1303                                    kNonStrictMode);
   1304   if (maybe_result->IsFailure()) return maybe_result;
   1305 
   1306   // Set the updated body.size if appropriate.
   1307   if (size >= 0) {
   1308     Handle<String> size_sym = Factory::LookupAsciiSymbol("size");
   1309     maybe_result = body->SetProperty(*size_sym,
   1310                                      Smi::FromInt(size),
   1311                                      NONE,
   1312                                      kNonStrictMode);
   1313     if (maybe_result->IsFailure()) return maybe_result;
   1314   }
   1315 
   1316   // Set body.first_index.
   1317   Handle<String> first_sym = Factory::LookupAsciiSymbol("first_index");
   1318   maybe_result = body->SetProperty(*first_sym,
   1319                                    Smi::FromInt(start),
   1320                                    NONE,
   1321                                    kNonStrictMode);
   1322   if (maybe_result->IsFailure()) return maybe_result;
   1323 
   1324   // Allocate the JSArray of the elements.
   1325   Handle<JSObject> elements = Factory::NewJSObject(Top::array_function());
   1326   if (elements->IsFailure()) return Object::cast(*elements);
   1327   Handle<JSArray>::cast(elements)->SetContent(*elements_arr);
   1328 
   1329   // Set body.elements.
   1330   Handle<String> elements_sym = Factory::LookupAsciiSymbol("elements");
   1331   maybe_result = body->SetProperty(*elements_sym,
   1332                                    *elements,
   1333                                    NONE,
   1334                                    kNonStrictMode);
   1335   if (maybe_result->IsFailure()) return maybe_result;
   1336 
   1337   return *body;
   1338 }
   1339 
   1340 
   1341 MaybeObject* LiveObjectList::Summarize(int older_id,
   1342                                        int newer_id,
   1343                                        Handle<JSObject> filter_obj) {
   1344   if ((older_id < 0) || (newer_id < 0) || (last() == NULL)) {
   1345     return Failure::Exception();  // Fail: 0 is not a valid lol id.
   1346   }
   1347   if (newer_id < older_id) {
   1348     // They are not in the expected order.  Swap them.
   1349     int temp = older_id;
   1350     older_id = newer_id;
   1351     newer_id = temp;
   1352   }
   1353 
   1354   LiveObjectList *newer_lol = FindLolForId(newer_id, last());
   1355   LiveObjectList *older_lol = FindLolForId(older_id, newer_lol);
   1356 
   1357   // If the id is defined, and we can't find a LOL for it, then we have an
   1358   // invalid id.
   1359   if ((newer_id != 0) && (newer_lol == NULL)) {
   1360     return Failure::Exception();  // Fail: the newer lol id is invalid.
   1361   }
   1362   if ((older_id != 0) && (older_lol == NULL)) {
   1363     return Failure::Exception();  // Fail: the older lol id is invalid.
   1364   }
   1365 
   1366   LolFilter filter(filter_obj);
   1367   LolSummaryWriter writer(older_lol, newer_lol);
   1368   return SummarizePrivate(&writer, &filter, false);
   1369 }
   1370 
   1371 
   1372 // Creates a summary report for the debugger.
   1373 // Note: the SummaryWriter takes care of iterating over objects and filling in
   1374 // the summary.
   1375 MaybeObject* LiveObjectList::SummarizePrivate(SummaryWriter* writer,
   1376                                               LolFilter* filter,
   1377                                               bool is_tracking_roots) {
   1378   HandleScope scope;
   1379   MaybeObject* maybe_result;
   1380 
   1381   LiveObjectSummary summary(filter);
   1382   writer->Write(&summary);
   1383 
   1384   // The result body will look like this:
   1385   // body: {
   1386   //   count: <total_count>,
   1387   //   size: <total_size>,
   1388   //   found_root: <boolean>,       // optional.
   1389   //   found_weak_root: <boolean>,  // optional.
   1390   //   summary: [
   1391   //     {
   1392   //       desc: "<object type name>",
   1393   //       count: <count>,
   1394   //       size: size
   1395   //     },
   1396   //     ...
   1397   //   ]
   1398   // }
   1399 
   1400   // Prefetch some needed symbols.
   1401   Handle<String> desc_sym = Factory::LookupAsciiSymbol("desc");
   1402   Handle<String> count_sym = Factory::LookupAsciiSymbol("count");
   1403   Handle<String> size_sym = Factory::LookupAsciiSymbol("size");
   1404   Handle<String> summary_sym = Factory::LookupAsciiSymbol("summary");
   1405 
   1406   // Allocate the summary array.
   1407   int entries_count = summary.GetNumberOfEntries();
   1408   Handle<FixedArray> summary_arr =
   1409       Factory::NewFixedArray(entries_count);
   1410   if (summary_arr->IsFailure()) return Object::cast(*summary_arr);
   1411 
   1412   int idx = 0;
   1413   for (int i = 0; i < LiveObjectSummary::kNumberOfEntries; i++) {
   1414     // Allocate the summary record.
   1415     Handle<JSObject> detail = Factory::NewJSObject(Top::object_function());
   1416     if (detail->IsFailure()) return Object::cast(*detail);
   1417 
   1418     // Fill in the summary record.
   1419     LiveObjectType type = static_cast<LiveObjectType>(i);
   1420     int count = summary.Count(type);
   1421     if (count) {
   1422       const char* desc_cstr = GetObjectTypeDesc(type);
   1423       Handle<String> desc = Factory::LookupAsciiSymbol(desc_cstr);
   1424       int size = summary.Size(type);
   1425 
   1426       maybe_result = detail->SetProperty(*desc_sym,
   1427                                          *desc,
   1428                                          NONE,
   1429                                          kNonStrictMode);
   1430       if (maybe_result->IsFailure()) return maybe_result;
   1431       maybe_result = detail->SetProperty(*count_sym,
   1432                                          Smi::FromInt(count),
   1433                                          NONE,
   1434                                          kNonStrictMode);
   1435       if (maybe_result->IsFailure()) return maybe_result;
   1436       maybe_result = detail->SetProperty(*size_sym,
   1437                                          Smi::FromInt(size),
   1438                                          NONE,
   1439                                          kNonStrictMode);
   1440       if (maybe_result->IsFailure()) return maybe_result;
   1441 
   1442       summary_arr->set(idx++, *detail);
   1443     }
   1444   }
   1445 
   1446   // Wrap the summary fixed array in a JS array.
   1447   Handle<JSObject> summary_obj = Factory::NewJSObject(Top::array_function());
   1448   if (summary_obj->IsFailure()) return Object::cast(*summary_obj);
   1449   Handle<JSArray>::cast(summary_obj)->SetContent(*summary_arr);
   1450 
   1451   // Create the body object.
   1452   Handle<JSObject> body = Factory::NewJSObject(Top::object_function());
   1453   if (body->IsFailure()) return Object::cast(*body);
   1454 
   1455   // Fill out the body object.
   1456   int total_count = summary.total_count();
   1457   int total_size = summary.total_size();
   1458   maybe_result = body->SetProperty(*count_sym,
   1459                                    Smi::FromInt(total_count),
   1460                                    NONE,
   1461                                    kNonStrictMode);
   1462   if (maybe_result->IsFailure()) return maybe_result;
   1463 
   1464   maybe_result = body->SetProperty(*size_sym,
   1465                                    Smi::FromInt(total_size),
   1466                                    NONE,
   1467                                    kNonStrictMode);
   1468   if (maybe_result->IsFailure()) return maybe_result;
   1469 
   1470   if (is_tracking_roots) {
   1471     int found_root = summary.found_root();
   1472     int found_weak_root = summary.found_weak_root();
   1473     Handle<String> root_sym = Factory::LookupAsciiSymbol("found_root");
   1474     Handle<String> weak_root_sym =
   1475         Factory::LookupAsciiSymbol("found_weak_root");
   1476     maybe_result = body->SetProperty(*root_sym,
   1477                                      Smi::FromInt(found_root),
   1478                                      NONE,
   1479                                      kNonStrictMode);
   1480     if (maybe_result->IsFailure()) return maybe_result;
   1481     maybe_result = body->SetProperty(*weak_root_sym,
   1482                                      Smi::FromInt(found_weak_root),
   1483                                      NONE,
   1484                                      kNonStrictMode);
   1485     if (maybe_result->IsFailure()) return maybe_result;
   1486   }
   1487 
   1488   maybe_result = body->SetProperty(*summary_sym,
   1489                                    *summary_obj,
   1490                                    NONE,
   1491                                    kNonStrictMode);
   1492   if (maybe_result->IsFailure()) return maybe_result;
   1493 
   1494   return *body;
   1495 }
   1496 
   1497 
   1498 // Returns an array listing the captured lols.
   1499 // Note: only dumps the section starting at start_idx and only up to
   1500 // dump_limit entries.
   1501 MaybeObject* LiveObjectList::Info(int start_idx, int dump_limit) {
   1502   HandleScope scope;
   1503   MaybeObject* maybe_result;
   1504 
   1505   int total_count = LiveObjectList::list_count();
   1506   int dump_count = total_count;
   1507 
   1508   // Adjust for where to start the dump.
   1509   if (total_count == 0) {
   1510       start_idx = 0;  // Ensure this to get an empty list.
   1511   } else if ((start_idx < 0) || (start_idx >= total_count)) {
   1512     return Failure::Exception();  // invalid start.
   1513   }
   1514   dump_count -= start_idx;
   1515 
   1516   // Adjust for the dump limit.
   1517   if (dump_count > dump_limit) {
   1518     dump_count = dump_limit;
   1519   }
   1520 
   1521   // Allocate an array to hold the result.
   1522   Handle<FixedArray> list = Factory::NewFixedArray(dump_count);
   1523   if (list->IsFailure()) return Object::cast(*list);
   1524 
   1525   // Prefetch some needed symbols.
   1526   Handle<String> id_sym = Factory::LookupAsciiSymbol("id");
   1527   Handle<String> count_sym = Factory::LookupAsciiSymbol("count");
   1528   Handle<String> size_sym = Factory::LookupAsciiSymbol("size");
   1529 
   1530   // Fill the array with the lol details.
   1531   int idx = 0;
   1532   LiveObjectList* lol = first_;
   1533   while ((lol != NULL) && (idx < start_idx)) {  // Skip tail entries.
   1534     if (lol->id() != 0) {
   1535       idx++;
   1536     }
   1537     lol = lol->next();
   1538   }
   1539   idx = 0;
   1540   while ((lol != NULL) && (dump_limit != 0)) {
   1541     if (lol->id() != 0) {
   1542       int count;
   1543       int size;
   1544       count = lol->GetTotalObjCountAndSize(&size);
   1545 
   1546       Handle<JSObject> detail = Factory::NewJSObject(Top::object_function());
   1547       if (detail->IsFailure()) return Object::cast(*detail);
   1548 
   1549       maybe_result = detail->SetProperty(*id_sym,
   1550                                          Smi::FromInt(lol->id()),
   1551                                          NONE,
   1552                                          kNonStrictMode);
   1553       if (maybe_result->IsFailure()) return maybe_result;
   1554       maybe_result = detail->SetProperty(*count_sym,
   1555                                          Smi::FromInt(count),
   1556                                          NONE,
   1557                                          kNonStrictMode);
   1558       if (maybe_result->IsFailure()) return maybe_result;
   1559       maybe_result = detail->SetProperty(*size_sym,
   1560                                          Smi::FromInt(size),
   1561                                          NONE,
   1562                                          kNonStrictMode);
   1563       if (maybe_result->IsFailure()) return maybe_result;
   1564       list->set(idx++, *detail);
   1565       dump_limit--;
   1566     }
   1567     lol = lol->next();
   1568   }
   1569 
   1570   // Return the result as a JS array.
   1571   Handle<JSObject> lols = Factory::NewJSObject(Top::array_function());
   1572   Handle<JSArray>::cast(lols)->SetContent(*list);
   1573 
   1574   Handle<JSObject> result = Factory::NewJSObject(Top::object_function());
   1575   if (result->IsFailure()) return Object::cast(*result);
   1576 
   1577   maybe_result = result->SetProperty(*count_sym,
   1578                                      Smi::FromInt(total_count),
   1579                                      NONE,
   1580                                      kNonStrictMode);
   1581   if (maybe_result->IsFailure()) return maybe_result;
   1582 
   1583   Handle<String> first_sym = Factory::LookupAsciiSymbol("first_index");
   1584   maybe_result = result->SetProperty(*first_sym,
   1585                                      Smi::FromInt(start_idx),
   1586                                      NONE,
   1587                                      kNonStrictMode);
   1588   if (maybe_result->IsFailure()) return maybe_result;
   1589 
   1590   Handle<String> lists_sym = Factory::LookupAsciiSymbol("lists");
   1591   maybe_result = result->SetProperty(*lists_sym,
   1592                                      *lols,
   1593                                      NONE,
   1594                                      kNonStrictMode);
   1595   if (maybe_result->IsFailure()) return maybe_result;
   1596 
   1597   return *result;
   1598 }
   1599 
   1600 
   1601 // Deletes all captured lols.
   1602 void LiveObjectList::Reset() {
   1603   LiveObjectList *lol = last();
   1604   // Just delete the last.  Each lol will delete it's prev automatically.
   1605   delete lol;
   1606 
   1607   next_element_id_ = 1;
   1608   list_count_ = 0;
   1609   last_id_ = 0;
   1610   first_ = NULL;
   1611   last_ = NULL;
   1612 }
   1613 
   1614 
   1615 // Gets the object for the specified obj id.
   1616 Object* LiveObjectList::GetObj(int obj_id) {
   1617   Element* element = FindElementFor<int>(GetElementId, obj_id);
   1618   if (element != NULL) {
   1619     return Object::cast(element->obj_);
   1620   }
   1621   return Heap::undefined_value();
   1622 }
   1623 
   1624 
   1625 // Gets the obj id for the specified address if valid.
   1626 int LiveObjectList::GetObjId(Object* obj) {
   1627   // Make a heap object pointer from the address.
   1628   HeapObject* hobj = HeapObject::cast(obj);
   1629   Element* element = FindElementFor<HeapObject*>(GetElementObj, hobj);
   1630   if (element != NULL) {
   1631     return element->id_;
   1632   }
   1633   return 0;  // Invalid address.
   1634 }
   1635 
   1636 
   1637 // Gets the obj id for the specified address if valid.
   1638 Object* LiveObjectList::GetObjId(Handle<String> address) {
   1639   SmartPointer<char> addr_str =
   1640       address->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
   1641 
   1642   // Extract the address value from the string.
   1643   int value = static_cast<int>(StringToInt(*address, 16));
   1644   Object* obj = reinterpret_cast<Object*>(value);
   1645   return Smi::FromInt(GetObjId(obj));
   1646 }
   1647 
   1648 
   1649 // Helper class for copying HeapObjects.
   1650 class LolVisitor: public ObjectVisitor {
   1651  public:
   1652 
   1653   LolVisitor(HeapObject* target, Handle<HeapObject> handle_to_skip)
   1654       : target_(target), handle_to_skip_(handle_to_skip), found_(false) {}
   1655 
   1656   void VisitPointer(Object** p) { CheckPointer(p); }
   1657 
   1658   void VisitPointers(Object** start, Object** end) {
   1659     // Check all HeapObject pointers in [start, end).
   1660     for (Object** p = start; !found() && p < end; p++) CheckPointer(p);
   1661   }
   1662 
   1663   inline bool found() const { return found_; }
   1664   inline bool reset() { return found_ = false; }
   1665 
   1666  private:
   1667   inline void CheckPointer(Object** p) {
   1668     Object* object = *p;
   1669     if (HeapObject::cast(object) == target_) {
   1670       // We may want to skip this handle because the handle may be a local
   1671       // handle in a handle scope in one of our callers.  Once we return,
   1672       // that handle will be popped.  Hence, we don't want to count it as
   1673       // a root that would have kept the target object alive.
   1674       if (!handle_to_skip_.is_null() &&
   1675           handle_to_skip_.location() == reinterpret_cast<HeapObject**>(p)) {
   1676         return;  // Skip this handle.
   1677       }
   1678       found_ = true;
   1679     }
   1680   }
   1681 
   1682   HeapObject* target_;
   1683   Handle<HeapObject> handle_to_skip_;
   1684   bool found_;
   1685 };
   1686 
   1687 
   1688 inline bool AddRootRetainerIfFound(const LolVisitor& visitor,
   1689                                    LolFilter* filter,
   1690                                    LiveObjectSummary *summary,
   1691                                    void (*SetRootFound)(LiveObjectSummary *s),
   1692                                    int start,
   1693                                    int dump_limit,
   1694                                    int* total_count,
   1695                                    Handle<FixedArray> retainers_arr,
   1696                                    int* count,
   1697                                    int* index,
   1698                                    const char* root_name,
   1699                                    Handle<String> id_sym,
   1700                                    Handle<String> desc_sym,
   1701                                    Handle<String> size_sym,
   1702                                    Handle<Object> error) {
   1703   HandleScope scope;
   1704 
   1705   // Scratch handles.
   1706   Handle<JSObject> detail;
   1707   Handle<String> desc;
   1708   Handle<HeapObject> retainer;
   1709 
   1710   if (visitor.found()) {
   1711     if (!filter->is_active()) {
   1712       (*total_count)++;
   1713       if (summary) {
   1714         SetRootFound(summary);
   1715       } else if ((*total_count > start) && ((*index) < dump_limit)) {
   1716         (*count)++;
   1717         if (!retainers_arr.is_null()) {
   1718           return AddObjDetail(retainers_arr,
   1719                               (*index)++,
   1720                               0,
   1721                               retainer,
   1722                               root_name,
   1723                               id_sym,
   1724                               desc_sym,
   1725                               size_sym,
   1726                               detail,
   1727                               desc,
   1728                               error);
   1729         }
   1730       }
   1731     }
   1732   }
   1733   return true;
   1734 }
   1735 
   1736 
   1737 inline void SetFoundRoot(LiveObjectSummary *summary) {
   1738   summary->set_found_root();
   1739 }
   1740 
   1741 
   1742 inline void SetFoundWeakRoot(LiveObjectSummary *summary) {
   1743   summary->set_found_weak_root();
   1744 }
   1745 
   1746 
   1747 int LiveObjectList::GetRetainers(Handle<HeapObject> target,
   1748                                  Handle<JSObject> instance_filter,
   1749                                  Handle<FixedArray> retainers_arr,
   1750                                  int start,
   1751                                  int dump_limit,
   1752                                  int* total_count,
   1753                                  LolFilter* filter,
   1754                                  LiveObjectSummary *summary,
   1755                                  JSFunction* arguments_function,
   1756                                  Handle<Object> error) {
   1757   HandleScope scope;
   1758 
   1759   // Scratch handles.
   1760   Handle<JSObject> detail;
   1761   Handle<String> desc;
   1762   Handle<HeapObject> retainer;
   1763 
   1764   // Prefetch some needed symbols.
   1765   Handle<String> id_sym = Factory::LookupAsciiSymbol("id");
   1766   Handle<String> desc_sym = Factory::LookupAsciiSymbol("desc");
   1767   Handle<String> size_sym = Factory::LookupAsciiSymbol("size");
   1768 
   1769   NoHandleAllocation ha;
   1770   int count = 0;
   1771   int index = 0;
   1772   Handle<JSObject> last_obj;
   1773 
   1774   *total_count = 0;
   1775 
   1776   // Iterate roots.
   1777   LolVisitor lol_visitor(*target, target);
   1778   Heap::IterateStrongRoots(&lol_visitor, VISIT_ALL);
   1779   if (!AddRootRetainerIfFound(lol_visitor,
   1780                               filter,
   1781                               summary,
   1782                               SetFoundRoot,
   1783                               start,
   1784                               dump_limit,
   1785                               total_count,
   1786                               retainers_arr,
   1787                               &count,
   1788                               &index,
   1789                               "<root>",
   1790                               id_sym,
   1791                               desc_sym,
   1792                               size_sym,
   1793                               error)) {
   1794     return -1;
   1795   }
   1796 
   1797   lol_visitor.reset();
   1798   Heap::IterateWeakRoots(&lol_visitor, VISIT_ALL);
   1799   if (!AddRootRetainerIfFound(lol_visitor,
   1800                               filter,
   1801                               summary,
   1802                               SetFoundWeakRoot,
   1803                               start,
   1804                               dump_limit,
   1805                               total_count,
   1806                               retainers_arr,
   1807                               &count,
   1808                               &index,
   1809                               "<weak root>",
   1810                               id_sym,
   1811                               desc_sym,
   1812                               size_sym,
   1813                               error)) {
   1814     return -1;
   1815   }
   1816 
   1817   // Iterate the live object lists.
   1818   LolIterator it(NULL, last());
   1819   for (it.Init(); !it.Done() && (index < dump_limit); it.Next()) {
   1820     HeapObject* heap_obj = it.Obj();
   1821 
   1822     // Only look at all JSObjects.
   1823     if (heap_obj->IsJSObject()) {
   1824       // Skip context extension objects and argument arrays as these are
   1825       // checked in the context of functions using them.
   1826       JSObject* obj = JSObject::cast(heap_obj);
   1827       if (obj->IsJSContextExtensionObject() ||
   1828           obj->map()->constructor() == arguments_function) {
   1829         continue;
   1830       }
   1831 
   1832       // Check if the JS object has a reference to the object looked for.
   1833       if (obj->ReferencesObject(*target)) {
   1834         // Check instance filter if supplied. This is normally used to avoid
   1835         // references from mirror objects (see Runtime_IsInPrototypeChain).
   1836         if (!instance_filter->IsUndefined()) {
   1837           Object* V = obj;
   1838           while (true) {
   1839             Object* prototype = V->GetPrototype();
   1840             if (prototype->IsNull()) {
   1841               break;
   1842             }
   1843             if (*instance_filter == prototype) {
   1844               obj = NULL;  // Don't add this object.
   1845               break;
   1846             }
   1847             V = prototype;
   1848           }
   1849         }
   1850 
   1851         if (obj != NULL) {
   1852           // Skip objects that have been filtered out.
   1853           if (filter->Matches(heap_obj)) {
   1854             continue;
   1855           }
   1856 
   1857           // Valid reference found add to instance array if supplied an update
   1858           // count.
   1859           last_obj = Handle<JSObject>(obj);
   1860           (*total_count)++;
   1861 
   1862           if (summary != NULL) {
   1863             summary->Add(heap_obj);
   1864           } else if ((*total_count > start) && (index < dump_limit)) {
   1865             count++;
   1866             if (!retainers_arr.is_null()) {
   1867               retainer = Handle<HeapObject>(heap_obj);
   1868               bool success = AddObjDetail(retainers_arr,
   1869                                           index++,
   1870                                           it.Id(),
   1871                                           retainer,
   1872                                           NULL,
   1873                                           id_sym,
   1874                                           desc_sym,
   1875                                           size_sym,
   1876                                           detail,
   1877                                           desc,
   1878                                           error);
   1879               if (!success) return -1;
   1880             }
   1881           }
   1882         }
   1883       }
   1884     }
   1885   }
   1886 
   1887   // Check for circular reference only. This can happen when the object is only
   1888   // referenced from mirrors and has a circular reference in which case the
   1889   // object is not really alive and would have been garbage collected if not
   1890   // referenced from the mirror.
   1891 
   1892   if (*total_count == 1 && !last_obj.is_null() && *last_obj == *target) {
   1893     count = 0;
   1894     *total_count = 0;
   1895   }
   1896 
   1897   return count;
   1898 }
   1899 
   1900 
   1901 MaybeObject* LiveObjectList::GetObjRetainers(int obj_id,
   1902                                              Handle<JSObject> instance_filter,
   1903                                              bool verbose,
   1904                                              int start,
   1905                                              int dump_limit,
   1906                                              Handle<JSObject> filter_obj) {
   1907   HandleScope scope;
   1908 
   1909   // Get the target object.
   1910   HeapObject* heap_obj = HeapObject::cast(GetObj(obj_id));
   1911   if (heap_obj == Heap::undefined_value()) {
   1912     return heap_obj;
   1913   }
   1914 
   1915   Handle<HeapObject> target = Handle<HeapObject>(heap_obj);
   1916 
   1917   // Get the constructor function for context extension and arguments array.
   1918   JSObject* arguments_boilerplate =
   1919       Top::context()->global_context()->arguments_boilerplate();
   1920   JSFunction* arguments_function =
   1921       JSFunction::cast(arguments_boilerplate->map()->constructor());
   1922 
   1923   Handle<JSFunction> args_function = Handle<JSFunction>(arguments_function);
   1924   LolFilter filter(filter_obj);
   1925 
   1926   if (!verbose) {
   1927     RetainersSummaryWriter writer(target, instance_filter, args_function);
   1928     return SummarizePrivate(&writer, &filter, true);
   1929 
   1930   } else {
   1931     RetainersDumpWriter writer(target, instance_filter, args_function);
   1932     Object* body_obj;
   1933     MaybeObject* maybe_result =
   1934         DumpPrivate(&writer, start, dump_limit, &filter);
   1935     if (!maybe_result->ToObject(&body_obj)) {
   1936       return maybe_result;
   1937     }
   1938 
   1939     // Set body.id.
   1940     Handle<JSObject> body = Handle<JSObject>(JSObject::cast(body_obj));
   1941     Handle<String> id_sym = Factory::LookupAsciiSymbol("id");
   1942     maybe_result = body->SetProperty(*id_sym,
   1943                                      Smi::FromInt(obj_id),
   1944                                      NONE,
   1945                                      kNonStrictMode);
   1946     if (maybe_result->IsFailure()) return maybe_result;
   1947 
   1948     return *body;
   1949   }
   1950 }
   1951 
   1952 
   1953 Object* LiveObjectList::PrintObj(int obj_id) {
   1954   Object* obj = GetObj(obj_id);
   1955   if (!obj) {
   1956     return Heap::undefined_value();
   1957   }
   1958 
   1959   EmbeddedVector<char, 128> temp_filename;
   1960   static int temp_count = 0;
   1961   const char* path_prefix = ".";
   1962 
   1963   if (FLAG_lol_workdir) {
   1964     path_prefix = FLAG_lol_workdir;
   1965   }
   1966   OS::SNPrintF(temp_filename, "%s/lol-print-%d", path_prefix, ++temp_count);
   1967 
   1968   FILE* f = OS::FOpen(temp_filename.start(), "w+");
   1969 
   1970   PrintF(f, "@%d ", LiveObjectList::GetObjId(obj));
   1971 #ifdef OBJECT_PRINT
   1972 #ifdef INSPECTOR
   1973   Inspector::DumpObjectType(f, obj);
   1974 #endif  // INSPECTOR
   1975   PrintF(f, "\n");
   1976   obj->Print(f);
   1977 #else  // !OBJECT_PRINT
   1978   obj->ShortPrint(f);
   1979 #endif  // !OBJECT_PRINT
   1980   PrintF(f, "\n");
   1981   Flush(f);
   1982   fclose(f);
   1983 
   1984   // Create a string from the temp_file.
   1985   // Note: the mmapped resource will take care of closing the file.
   1986   MemoryMappedExternalResource* resource =
   1987       new MemoryMappedExternalResource(temp_filename.start(), true);
   1988   if (resource->exists() && !resource->is_empty()) {
   1989     ASSERT(resource->IsAscii());
   1990     Handle<String> dump_string =
   1991         Factory::NewExternalStringFromAscii(resource);
   1992     ExternalStringTable::AddString(*dump_string);
   1993     return *dump_string;
   1994   } else {
   1995     delete resource;
   1996   }
   1997   return Heap::undefined_value();
   1998 }
   1999 
   2000 
   2001 class LolPathTracer: public PathTracer {
   2002  public:
   2003   LolPathTracer(FILE* out,
   2004                 Object* search_target,
   2005                 WhatToFind what_to_find)
   2006       : PathTracer(search_target, what_to_find, VISIT_ONLY_STRONG), out_(out) {}
   2007 
   2008  private:
   2009   void ProcessResults();
   2010 
   2011   FILE* out_;
   2012 };
   2013 
   2014 
   2015 void LolPathTracer::ProcessResults() {
   2016   if (found_target_) {
   2017     PrintF(out_, "=====================================\n");
   2018     PrintF(out_, "====        Path to object       ====\n");
   2019     PrintF(out_, "=====================================\n\n");
   2020 
   2021     ASSERT(!object_stack_.is_empty());
   2022     Object* prev = NULL;
   2023     for (int i = 0, index = 0; i < object_stack_.length(); i++) {
   2024       Object* obj = object_stack_[i];
   2025 
   2026       // Skip this object if it is basically the internals of the
   2027       // previous object (which would have dumped its details already).
   2028       if (prev && prev->IsJSObject() &&
   2029           (obj != search_target_)) {
   2030         JSObject* jsobj = JSObject::cast(prev);
   2031         if (obj->IsFixedArray() &&
   2032             jsobj->properties() == FixedArray::cast(obj)) {
   2033           // Skip this one because it would have been printed as the
   2034           // properties of the last object already.
   2035           continue;
   2036         } else if (obj->IsHeapObject() &&
   2037                    jsobj->elements() == HeapObject::cast(obj)) {
   2038           // Skip this one because it would have been printed as the
   2039           // elements of the last object already.
   2040           continue;
   2041         }
   2042       }
   2043 
   2044       // Print a connecting arrow.
   2045       if (i > 0) PrintF(out_, "\n     |\n     |\n     V\n\n");
   2046 
   2047       // Print the object index.
   2048       PrintF(out_, "[%d] ", ++index);
   2049 
   2050       // Print the LOL object ID:
   2051       int id = LiveObjectList::GetObjId(obj);
   2052       if (id > 0) PrintF(out_, "@%d ", id);
   2053 
   2054 #ifdef OBJECT_PRINT
   2055 #ifdef INSPECTOR
   2056       Inspector::DumpObjectType(out_, obj);
   2057 #endif  // INSPECTOR
   2058       PrintF(out_, "\n");
   2059       obj->Print(out_);
   2060 #else  // !OBJECT_PRINT
   2061       obj->ShortPrint(out_);
   2062       PrintF(out_, "\n");
   2063 #endif  // !OBJECT_PRINT
   2064       Flush(out_);
   2065     }
   2066     PrintF(out_, "\n");
   2067     PrintF(out_, "=====================================\n\n");
   2068     Flush(out_);
   2069   }
   2070 }
   2071 
   2072 
   2073 Object* LiveObjectList::GetPathPrivate(HeapObject* obj1, HeapObject* obj2) {
   2074   EmbeddedVector<char, 128> temp_filename;
   2075   static int temp_count = 0;
   2076   const char* path_prefix = ".";
   2077 
   2078   if (FLAG_lol_workdir) {
   2079     path_prefix = FLAG_lol_workdir;
   2080   }
   2081   OS::SNPrintF(temp_filename, "%s/lol-getpath-%d", path_prefix, ++temp_count);
   2082 
   2083   FILE* f = OS::FOpen(temp_filename.start(), "w+");
   2084 
   2085   // Save the previous verbosity.
   2086   bool prev_verbosity = FLAG_use_verbose_printer;
   2087   FLAG_use_verbose_printer = false;
   2088 
   2089   // Dump the paths.
   2090   {
   2091     // The tracer needs to be scoped because its usage asserts no allocation,
   2092     // and we need to allocate the result string below.
   2093     LolPathTracer tracer(f, obj2, LolPathTracer::FIND_FIRST);
   2094 
   2095     bool found = false;
   2096     if (obj1 == NULL) {
   2097       // Check for ObjectGroups that references this object.
   2098       // TODO(mlam): refactor this to be more modular.
   2099       {
   2100         List<ObjectGroup*>* groups = GlobalHandles::ObjectGroups();
   2101         for (int i = 0; i < groups->length(); i++) {
   2102           ObjectGroup* group = groups->at(i);
   2103           if (group == NULL) continue;
   2104 
   2105           bool found_group = false;
   2106           List<Object**>& objects = group->objects_;
   2107           for (int j = 0; j < objects.length(); j++) {
   2108             Object* object = *objects[j];
   2109             HeapObject* hobj = HeapObject::cast(object);
   2110             if (obj2 == hobj) {
   2111               found_group = true;
   2112               break;
   2113             }
   2114           }
   2115 
   2116           if (found_group) {
   2117             PrintF(f,
   2118                    "obj %p is a member of object group %p {\n",
   2119                    reinterpret_cast<void*>(obj2),
   2120                    reinterpret_cast<void*>(group));
   2121             for (int j = 0; j < objects.length(); j++) {
   2122               Object* object = *objects[j];
   2123               if (!object->IsHeapObject()) continue;
   2124 
   2125               HeapObject* hobj = HeapObject::cast(object);
   2126               int id = GetObjId(hobj);
   2127               if (id != 0) {
   2128                 PrintF(f, "  @%d:", id);
   2129               } else {
   2130                 PrintF(f, "  <no id>:");
   2131               }
   2132 
   2133               char buffer[512];
   2134               GenerateObjectDesc(hobj, buffer, sizeof(buffer));
   2135               PrintF(f, " %s", buffer);
   2136               if (hobj == obj2) {
   2137                 PrintF(f, " <===");
   2138               }
   2139               PrintF(f, "\n");
   2140             }
   2141             PrintF(f, "}\n");
   2142           }
   2143         }
   2144       }
   2145 
   2146       PrintF(f, "path from roots to obj %p\n", reinterpret_cast<void*>(obj2));
   2147       Heap::IterateRoots(&tracer, VISIT_ONLY_STRONG);
   2148       found = tracer.found();
   2149 
   2150       if (!found) {
   2151         PrintF(f, "  No paths found. Checking symbol tables ...\n");
   2152         SymbolTable* symbol_table = Heap::raw_unchecked_symbol_table();
   2153         tracer.VisitPointers(reinterpret_cast<Object**>(&symbol_table),
   2154                              reinterpret_cast<Object**>(&symbol_table)+1);
   2155         found = tracer.found();
   2156         if (!found) {
   2157           symbol_table->IteratePrefix(&tracer);
   2158           found = tracer.found();
   2159         }
   2160       }
   2161 
   2162       if (!found) {
   2163         PrintF(f, "  No paths found. Checking weak roots ...\n");
   2164         // Check weak refs next.
   2165         GlobalHandles::IterateWeakRoots(&tracer);
   2166         found = tracer.found();
   2167       }
   2168 
   2169     } else {
   2170       PrintF(f, "path from obj %p to obj %p:\n",
   2171              reinterpret_cast<void*>(obj1), reinterpret_cast<void*>(obj2));
   2172       tracer.TracePathFrom(reinterpret_cast<Object**>(&obj1));
   2173       found = tracer.found();
   2174     }
   2175 
   2176     if (!found) {
   2177       PrintF(f, "  No paths found\n\n");
   2178     }
   2179   }
   2180 
   2181   // Flush and clean up the dumped file.
   2182   Flush(f);
   2183   fclose(f);
   2184 
   2185   // Restore the previous verbosity.
   2186   FLAG_use_verbose_printer = prev_verbosity;
   2187 
   2188   // Create a string from the temp_file.
   2189   // Note: the mmapped resource will take care of closing the file.
   2190   MemoryMappedExternalResource* resource =
   2191       new MemoryMappedExternalResource(temp_filename.start(), true);
   2192   if (resource->exists() && !resource->is_empty()) {
   2193     ASSERT(resource->IsAscii());
   2194     Handle<String> path_string =
   2195         Factory::NewExternalStringFromAscii(resource);
   2196     ExternalStringTable::AddString(*path_string);
   2197     return *path_string;
   2198   } else {
   2199     delete resource;
   2200   }
   2201   return Heap::undefined_value();
   2202 }
   2203 
   2204 
   2205 Object* LiveObjectList::GetPath(int obj_id1,
   2206                                 int obj_id2,
   2207                                 Handle<JSObject> instance_filter) {
   2208   HandleScope scope;
   2209 
   2210   // Get the target object.
   2211   HeapObject* obj1 = NULL;
   2212   if (obj_id1 != 0) {
   2213     obj1 = HeapObject::cast(GetObj(obj_id1));
   2214     if (obj1 == Heap::undefined_value()) {
   2215       return obj1;
   2216     }
   2217   }
   2218 
   2219   HeapObject* obj2 = HeapObject::cast(GetObj(obj_id2));
   2220   if (obj2 == Heap::undefined_value()) {
   2221     return obj2;
   2222   }
   2223 
   2224   return GetPathPrivate(obj1, obj2);
   2225 }
   2226 
   2227 
   2228 void LiveObjectList::DoProcessNonLive(HeapObject *obj) {
   2229   // We should only be called if we have at least one lol to search.
   2230   ASSERT(last() != NULL);
   2231   Element* element = last()->Find(obj);
   2232   if (element != NULL) {
   2233     NullifyNonLivePointer(&element->obj_);
   2234   }
   2235 }
   2236 
   2237 
   2238 void LiveObjectList::IterateElementsPrivate(ObjectVisitor* v) {
   2239   LiveObjectList* lol = last();
   2240   while (lol != NULL) {
   2241     Element* elements = lol->elements_;
   2242     int count = lol->obj_count_;
   2243     for (int i = 0; i < count; i++) {
   2244       HeapObject** p = &elements[i].obj_;
   2245       v->VisitPointer(reinterpret_cast<Object **>(p));
   2246     }
   2247     lol = lol->prev_;
   2248   }
   2249 }
   2250 
   2251 
   2252 // Purpose: Called by GCEpilogue to purge duplicates.  Not to be called by
   2253 // anyone else.
   2254 void LiveObjectList::PurgeDuplicates() {
   2255   bool is_sorted = false;
   2256   LiveObjectList* lol = last();
   2257   if (!lol) {
   2258     return;  // Nothing to purge.
   2259   }
   2260 
   2261   int total_count = lol->TotalObjCount();
   2262   if (!total_count) {
   2263     return;  // Nothing to purge.
   2264   }
   2265 
   2266   Element* elements = NewArray<Element>(total_count);
   2267   int count = 0;
   2268 
   2269   // Copy all the object elements into a consecutive array.
   2270   while (lol) {
   2271     memcpy(&elements[count], lol->elements_, lol->obj_count_ * sizeof(Element));
   2272     count += lol->obj_count_;
   2273     lol = lol->prev_;
   2274   }
   2275   qsort(elements, total_count, sizeof(Element),
   2276         reinterpret_cast<RawComparer>(CompareElement));
   2277 
   2278   ASSERT(count == total_count);
   2279 
   2280   // Iterate over all objects in the consolidated list and check for dups.
   2281   total_count--;
   2282   for (int i = 0; i < total_count; ) {
   2283     Element* curr = &elements[i];
   2284     HeapObject* curr_obj = curr->obj_;
   2285     int j = i+1;
   2286     bool done = false;
   2287 
   2288     while (!done && (j < total_count)) {
   2289       // Process if the element's object is still live after the current GC.
   2290       // Non-live objects will be converted to SMIs i.e. not HeapObjects.
   2291       if (curr_obj->IsHeapObject()) {
   2292         Element* next = &elements[j];
   2293         HeapObject* next_obj = next->obj_;
   2294         if (next_obj->IsHeapObject()) {
   2295           if (curr_obj != next_obj) {
   2296             done = true;
   2297             continue;  // Live object but no match.  Move on.
   2298           }
   2299 
   2300           // NOTE: we've just GCed the LOLs.  Hence, they are no longer sorted.
   2301           // Since we detected at least one need to search for entries, we'll
   2302           // sort it to enable the use of NullifyMostRecent() below.  We only
   2303           // need to sort it once (except for one exception ... see below).
   2304           if (!is_sorted) {
   2305             SortAll();
   2306             is_sorted = true;
   2307           }
   2308 
   2309           // We have a match.  Need to nullify the most recent ref to this
   2310           // object.  We'll keep the oldest ref:
   2311           // Note: we will nullify the element record in the LOL
   2312           // database, not in the local sorted copy of the elements.
   2313           NullifyMostRecent(curr_obj);
   2314         }
   2315       }
   2316       // Either the object was already marked for purging, or we just marked
   2317       // it.  Either way, if there's more than one dup, then we need to check
   2318       // the next element for another possible dup against the current as well
   2319       // before we move on.  So, here we go.
   2320       j++;
   2321     }
   2322 
   2323     // We can move on to checking the match on the next element.
   2324     i = j;
   2325   }
   2326 
   2327   DeleteArray<Element>(elements);
   2328 }
   2329 
   2330 
   2331 // Purpose: Purges dead objects and resorts the LOLs.
   2332 void LiveObjectList::GCEpiloguePrivate() {
   2333   // Note: During the GC, ConsStrings may be collected and pointers may be
   2334   // forwarded to its constituent string.  As a result, we may find dupes of
   2335   // objects references in the LOL list.
   2336   // Another common way we get dups is that free chunks that have been swept
   2337   // in the oldGen heap may be kept as ByteArray objects in a free list.
   2338   //
   2339   // When we promote live objects from the youngGen, the object may be moved
   2340   // to the start of these free chunks.  Since there is no free or move event
   2341   // for the free chunks, their addresses will show up 2 times: once for their
   2342   // original free ByteArray selves, and once for the newly promoted youngGen
   2343   // object.  Hence, we can get a duplicate address in the LOL again.
   2344   //
   2345   // We need to eliminate these dups because the LOL implementation expects to
   2346   // only have at most one unique LOL reference to any object at any time.
   2347   PurgeDuplicates();
   2348 
   2349   // After the GC, sweep away all free'd Elements and compact.
   2350   LiveObjectList *prev = NULL;
   2351   LiveObjectList *next = NULL;
   2352 
   2353   // Iterating from the youngest lol to the oldest lol.
   2354   for (LiveObjectList *lol = last(); lol; lol = prev) {
   2355     Element* elements = lol->elements_;
   2356     prev = lol->prev();  // Save the prev.
   2357 
   2358     // Remove any references to collected objects.
   2359     int i = 0;
   2360     while (i < lol->obj_count_) {
   2361       Element& element = elements[i];
   2362       if (!element.obj_->IsHeapObject()) {
   2363         // If the HeapObject address was converted into a SMI, then this
   2364         // is a dead object.  Copy the last element over this one.
   2365         element = elements[lol->obj_count_ - 1];
   2366         lol->obj_count_--;
   2367         // We've just moved the last element into this index.  We'll revisit
   2368         // this index again.  Hence, no need to increment the iterator.
   2369       } else {
   2370         i++;  // Look at the next element next.
   2371       }
   2372     }
   2373 
   2374     int new_count = lol->obj_count_;
   2375 
   2376     // Check if there are any more elements to keep after purging the dead ones.
   2377     if (new_count == 0) {
   2378       DeleteArray<Element>(elements);
   2379       lol->elements_ = NULL;
   2380       lol->capacity_ = 0;
   2381       ASSERT(lol->obj_count_ == 0);
   2382 
   2383       // If the list is also invisible, the clean up the list as well.
   2384       if (lol->id_ == 0) {
   2385         // Point the next lol's prev to this lol's prev.
   2386         if (next) {
   2387           next->prev_ = lol->prev_;
   2388         } else {
   2389           last_ = lol->prev_;
   2390         }
   2391 
   2392         // Delete this now empty and invisible lol.
   2393         delete lol;
   2394 
   2395         // Don't point the next to this lol since it is now deleted.
   2396         // Leave the next pointer pointing to the current lol.
   2397         continue;
   2398       }
   2399 
   2400     } else {
   2401       // If the obj_count_ is less than the capacity and the difference is
   2402       // greater than a specified threshold, then we should shrink the list.
   2403       int diff = lol->capacity_ - new_count;
   2404       const int kMaxUnusedSpace = 64;
   2405       if (diff > kMaxUnusedSpace) {  // Threshold for shrinking.
   2406         // Shrink the list.
   2407         Element *new_elements = NewArray<Element>(new_count);
   2408         memcpy(new_elements, elements, new_count * sizeof(Element));
   2409 
   2410         DeleteArray<Element>(elements);
   2411         lol->elements_ = new_elements;
   2412         lol->capacity_ = new_count;
   2413       }
   2414       ASSERT(lol->obj_count_ == new_count);
   2415 
   2416       lol->Sort();  // We've moved objects.  Re-sort in case.
   2417     }
   2418 
   2419     // Save the next (for the previous link) in case we need it later.
   2420     next = lol;
   2421   }
   2422 
   2423 #ifdef VERIFY_LOL
   2424   if (FLAG_verify_lol) {
   2425     Verify();
   2426   }
   2427 #endif
   2428 }
   2429 
   2430 
   2431 #ifdef VERIFY_LOL
   2432 void LiveObjectList::Verify(bool match_heap_exactly) {
   2433   OS::Print("Verifying the LiveObjectList database:\n");
   2434 
   2435   LiveObjectList* lol = last();
   2436   if (lol == NULL) {
   2437     OS::Print("  No lol database to verify\n");
   2438     return;
   2439   }
   2440 
   2441   OS::Print("  Preparing the lol database ...\n");
   2442   int total_count = lol->TotalObjCount();
   2443 
   2444   Element* elements = NewArray<Element>(total_count);
   2445   int count = 0;
   2446 
   2447   // Copy all the object elements into a consecutive array.
   2448   OS::Print("  Copying the lol database ...\n");
   2449   while (lol != NULL) {
   2450     memcpy(&elements[count], lol->elements_, lol->obj_count_ * sizeof(Element));
   2451     count += lol->obj_count_;
   2452     lol = lol->prev_;
   2453   }
   2454   qsort(elements, total_count, sizeof(Element),
   2455         reinterpret_cast<RawComparer>(CompareElement));
   2456 
   2457   ASSERT(count == total_count);
   2458 
   2459   // Iterate over all objects in the heap and check for:
   2460   // 1. object in LOL but not in heap i.e. error.
   2461   // 2. object in heap but not in LOL (possibly not an error).  Usually
   2462   //    just means that we don't have the a capture of the latest heap.
   2463   //    That is unless we did this verify immediately after a capture,
   2464   //    and specified match_heap_exactly = true.
   2465 
   2466   int number_of_heap_objects = 0;
   2467   int number_of_matches = 0;
   2468   int number_not_in_heap = total_count;
   2469   int number_not_in_lol = 0;
   2470 
   2471   OS::Print("  Start verify ...\n");
   2472   OS::Print("  Verifying ...");
   2473   Flush();
   2474   HeapIterator iterator(HeapIterator::kFilterFreeListNodes);
   2475   HeapObject* heap_obj = NULL;
   2476   while ((heap_obj = iterator.next()) != NULL) {
   2477     number_of_heap_objects++;
   2478 
   2479     // Check if the heap_obj is in the lol.
   2480     Element key;
   2481     key.obj_ = heap_obj;
   2482 
   2483     Element* result = reinterpret_cast<Element*>(
   2484         bsearch(&key, elements, total_count, sizeof(Element),
   2485                 reinterpret_cast<RawComparer>(CompareElement)));
   2486 
   2487     if (result != NULL) {
   2488       number_of_matches++;
   2489       number_not_in_heap--;
   2490       // Mark it as found by changing it into a SMI (mask off low bit).
   2491       // Note: we cannot use HeapObject::cast() here because it asserts that
   2492       // the HeapObject bit is set on the address, but we're unsetting it on
   2493       // purpose here for our marking.
   2494       result->obj_ = reinterpret_cast<HeapObject*>(heap_obj->address());
   2495 
   2496     } else {
   2497       number_not_in_lol++;
   2498       if (match_heap_exactly) {
   2499         OS::Print("heap object %p NOT in lol database\n", heap_obj);
   2500       }
   2501     }
   2502     // Show some sign of life.
   2503     if (number_of_heap_objects % 1000 == 0) {
   2504       OS::Print(".");
   2505       fflush(stdout);
   2506     }
   2507   }
   2508   OS::Print("\n");
   2509 
   2510   // Reporting lol objects not found in the heap.
   2511   if (number_not_in_heap) {
   2512     int found = 0;
   2513     for (int i = 0; (i < total_count) && (found < number_not_in_heap); i++) {
   2514       Element& element = elements[i];
   2515       if (element.obj_->IsHeapObject()) {
   2516         OS::Print("lol database object [%d of %d] %p NOT in heap\n",
   2517                   i, total_count, element.obj_);
   2518         found++;
   2519       }
   2520     }
   2521   }
   2522 
   2523   DeleteArray<Element>(elements);
   2524 
   2525   OS::Print("number of objects in lol database %d\n", total_count);
   2526   OS::Print("number of heap objects .......... %d\n", number_of_heap_objects);
   2527   OS::Print("number of matches ............... %d\n", number_of_matches);
   2528   OS::Print("number NOT in heap .............. %d\n", number_not_in_heap);
   2529   OS::Print("number NOT in lol database ...... %d\n", number_not_in_lol);
   2530 
   2531   if (number_of_matches != total_count) {
   2532     OS::Print("  *** ERROR: "
   2533               "NOT all lol database objects match heap objects.\n");
   2534   }
   2535   if (number_not_in_heap != 0) {
   2536     OS::Print("  *** ERROR: %d lol database objects not found in heap.\n",
   2537               number_not_in_heap);
   2538   }
   2539   if (match_heap_exactly) {
   2540     if (!(number_not_in_lol == 0)) {
   2541       OS::Print("  *** ERROR: %d heap objects NOT found in lol database.\n",
   2542                 number_not_in_lol);
   2543     }
   2544   }
   2545 
   2546   ASSERT(number_of_matches == total_count);
   2547   ASSERT(number_not_in_heap == 0);
   2548   ASSERT(number_not_in_lol == (number_of_heap_objects - total_count));
   2549   if (match_heap_exactly) {
   2550     ASSERT(total_count == number_of_heap_objects);
   2551     ASSERT(number_not_in_lol == 0);
   2552   }
   2553 
   2554   OS::Print("  Verify the lol database is sorted ...\n");
   2555   lol = last();
   2556   while (lol != NULL) {
   2557     Element* elements = lol->elements_;
   2558     for (int i = 0; i < lol->obj_count_ - 1; i++) {
   2559       if (elements[i].obj_ >= elements[i+1].obj_) {
   2560         OS::Print("  *** ERROR: lol %p obj[%d] %p > obj[%d] %p\n",
   2561                   lol, i, elements[i].obj_, i+1, elements[i+1].obj_);
   2562       }
   2563     }
   2564     lol = lol->prev_;
   2565   }
   2566 
   2567   OS::Print("  DONE verifying.\n\n\n");
   2568 }
   2569 
   2570 
   2571 void LiveObjectList::VerifyNotInFromSpace() {
   2572   OS::Print("VerifyNotInFromSpace() ...\n");
   2573   LolIterator it(NULL, last());
   2574   int i = 0;
   2575   for (it.Init(); !it.Done(); it.Next()) {
   2576     HeapObject* heap_obj = it.Obj();
   2577     if (Heap::InFromSpace(heap_obj)) {
   2578       OS::Print(" ERROR: VerifyNotInFromSpace: [%d] obj %p in From space %p\n",
   2579                 i++, heap_obj, Heap::new_space()->FromSpaceLow());
   2580     }
   2581   }
   2582 }
   2583 #endif  // VERIFY_LOL
   2584 
   2585 
   2586 } }  // namespace v8::internal
   2587 
   2588 #endif  // LIVE_OBJECT_LIST
   2589 
   2590