Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / v8 / src / heap-snapshot-generator.cc
index 10e177d..cafee77 100644 (file)
@@ -1,29 +1,6 @@
 // Copyright 2013 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-//       notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-//       copyright notice, this list of conditions and the following
-//       disclaimer in the documentation and/or other materials provided
-//       with the distribution.
-//     * Neither the name of Google Inc. nor the names of its
-//       contributors may be used to endorse or promote products derived
-//       from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
 #include "v8.h"
 
 
 #include "allocation-tracker.h"
 #include "code-stubs.h"
-#include "heap-profiler.h"
+#include "conversions.h"
 #include "debug.h"
+#include "heap-profiler.h"
 #include "types.h"
-#include "v8conversions.h"
 
 namespace v8 {
 namespace internal {
@@ -732,7 +709,7 @@ size_t HeapObjectsMap::GetUsedMemorySize() const {
 
 
 HeapEntriesMap::HeapEntriesMap()
-    : entries_(HeapThingsMatch) {
+    : entries_(HashMap::PointersMatch) {
 }
 
 
@@ -751,7 +728,7 @@ void HeapEntriesMap::Pair(HeapThing thing, int entry) {
 
 
 HeapObjectsSet::HeapObjectsSet()
-    : entries_(HeapEntriesMap::HeapThingsMatch) {
+    : entries_(HashMap::PointersMatch) {
 }
 
 
@@ -1079,21 +1056,30 @@ class IndexedReferencesExtractor : public ObjectVisitor {
   static void MarkVisitedField(HeapObject* obj, int offset) {
     if (offset < 0) return;
     Address field = obj->address() + offset;
-    ASSERT(!Memory::Object_at(field)->IsFailure());
     ASSERT(Memory::Object_at(field)->IsHeapObject());
-    *field |= kFailureTag;
+    intptr_t p = reinterpret_cast<intptr_t>(Memory::Object_at(field));
+    ASSERT(!IsMarked(p));
+    intptr_t p_tagged = p | kTag;
+    Memory::Object_at(field) = reinterpret_cast<Object*>(p_tagged);
   }
 
  private:
   bool CheckVisitedAndUnmark(Object** field) {
-    if ((*field)->IsFailure()) {
-      intptr_t untagged = reinterpret_cast<intptr_t>(*field) & ~kFailureTagMask;
-      *field = reinterpret_cast<Object*>(untagged | kHeapObjectTag);
+    intptr_t p = reinterpret_cast<intptr_t>(*field);
+    if (IsMarked(p)) {
+      intptr_t p_untagged = (p & ~kTaggingMask) | kHeapObjectTag;
+      *field = reinterpret_cast<Object*>(p_untagged);
       ASSERT((*field)->IsHeapObject());
       return true;
     }
     return false;
   }
+
+  static const intptr_t kTaggingMask = 3;
+  static const intptr_t kTag = 3;
+
+  static bool IsMarked(intptr_t p) { return (p & kTaggingMask) == kTag; }
+
   V8HeapExplorer* generator_;
   HeapObject* parent_obj_;
   int parent_;
@@ -1101,10 +1087,8 @@ class IndexedReferencesExtractor : public ObjectVisitor {
 };
 
 
-void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
-  HeapEntry* heap_entry = GetEntry(obj);
-  if (heap_entry == NULL) return;  // No interest in this object.
-  int entry = heap_entry->index();
+bool V8HeapExplorer::ExtractReferencesPass1(int entry, HeapObject* obj) {
+  if (obj->IsFixedArray()) return false;  // FixedArrays are processed on pass 2
 
   if (obj->IsJSGlobalProxy()) {
     ExtractJSGlobalProxyReferences(entry, JSGlobalProxy::cast(obj));
@@ -1114,8 +1098,6 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
     ExtractJSObjectReferences(entry, JSObject::cast(obj));
   } else if (obj->IsString()) {
     ExtractStringReferences(entry, String::cast(obj));
-  } else if (obj->IsContext()) {
-    ExtractContextReferences(entry, Context::cast(obj));
   } else if (obj->IsMap()) {
     ExtractMapReferences(entry, Map::cast(obj));
   } else if (obj->IsSharedFunctionInfo()) {
@@ -1137,12 +1119,19 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
   } else if (obj->IsAllocationSite()) {
     ExtractAllocationSiteReferences(entry, AllocationSite::cast(obj));
   }
-  SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset);
+  return true;
+}
+
 
-  // Extract unvisited fields as hidden references and restore tags
-  // of visited fields.
-  IndexedReferencesExtractor refs_extractor(this, obj, entry);
-  obj->Iterate(&refs_extractor);
+bool V8HeapExplorer::ExtractReferencesPass2(int entry, HeapObject* obj) {
+  if (!obj->IsFixedArray()) return false;
+
+  if (obj->IsContext()) {
+    ExtractContextReferences(entry, Context::cast(obj));
+  } else {
+    ExtractFixedArrayReferences(entry, FixedArray::cast(obj));
+  }
+  return true;
 }
 
 
@@ -1278,7 +1267,8 @@ void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) {
   }
 
 #define EXTRACT_CONTEXT_FIELD(index, type, name) \
-  if (Context::index < Context::FIRST_WEAK_SLOT) { \
+  if (Context::index < Context::FIRST_WEAK_SLOT || \
+      Context::index == Context::MAP_CACHE_INDEX) { \
     SetInternalReference(context, entry, #name, context->get(Context::index), \
         FixedArray::OffsetOfElementAt(Context::index)); \
   } else { \
@@ -1318,6 +1308,22 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
     TagObject(back_pointer, "(back pointer)");
     SetInternalReference(transitions, transitions_entry,
                          "back_pointer", back_pointer);
+
+    if (FLAG_collect_maps && map->CanTransition()) {
+      if (!transitions->IsSimpleTransition()) {
+        if (transitions->HasPrototypeTransitions()) {
+          FixedArray* prototype_transitions =
+              transitions->GetPrototypeTransitions();
+          MarkAsWeakContainer(prototype_transitions);
+          TagObject(prototype_transitions, "(prototype transitions");
+          SetInternalReference(transitions, transitions_entry,
+                               "prototype_transitions", prototype_transitions);
+        }
+        // TODO(alph): transitions keys are strong links.
+        MarkAsWeakContainer(transitions);
+      }
+    }
+
     TagObject(transitions, "(transition array)");
     SetInternalReference(map, entry,
                          "transitions", transitions,
@@ -1335,6 +1341,7 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
                        "descriptors", descriptors,
                        Map::kDescriptorsOffset);
 
+  MarkAsWeakContainer(map->code_cache());
   SetInternalReference(map, entry,
                        "code_cache", map->code_cache(),
                        Map::kCodeCacheOffset);
@@ -1344,6 +1351,7 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
                        "constructor", map->constructor(),
                        Map::kConstructorOffset);
   TagObject(map->dependent_code(), "(dependent code)");
+  MarkAsWeakContainer(map->dependent_code());
   SetInternalReference(map, entry,
                        "dependent_code", map->dependent_code(),
                        Map::kDependentCodeOffset);
@@ -1398,6 +1406,9 @@ void V8HeapExplorer::ExtractSharedFunctionInfoReferences(
   SetInternalReference(obj, entry,
                        "optimized_code_map", shared->optimized_code_map(),
                        SharedFunctionInfo::kOptimizedCodeMapOffset);
+  SetInternalReference(obj, entry,
+                       "feedback_vector", shared->feedback_vector(),
+                       SharedFunctionInfo::kFeedbackVectorOffset);
   SetWeakReference(obj, entry,
                    "initial_map", shared->initial_map(),
                    SharedFunctionInfo::kInitialMapOffset);
@@ -1505,6 +1516,7 @@ void V8HeapExplorer::ExtractPropertyCellReferences(int entry,
   ExtractCellReferences(entry, cell);
   SetInternalReference(cell, entry, "type", cell->type(),
                        PropertyCell::kTypeOffset);
+  MarkAsWeakContainer(cell->dependent_code());
   SetInternalReference(cell, entry, "dependent_code", cell->dependent_code(),
                        PropertyCell::kDependentCodeOffset);
 }
@@ -1516,6 +1528,7 @@ void V8HeapExplorer::ExtractAllocationSiteReferences(int entry,
                        AllocationSite::kTransitionInfoOffset);
   SetInternalReference(site, entry, "nested_site", site->nested_site(),
                        AllocationSite::kNestedSiteOffset);
+  MarkAsWeakContainer(site->dependent_code());
   SetInternalReference(site, entry, "dependent_code", site->dependent_code(),
                        AllocationSite::kDependentCodeOffset);
   // Do not visit weak_next as it is not visited by the StaticVisitor,
@@ -1561,6 +1574,20 @@ void V8HeapExplorer::ExtractJSArrayBufferReferences(
 }
 
 
+void V8HeapExplorer::ExtractFixedArrayReferences(int entry, FixedArray* array) {
+  bool is_weak = weak_containers_.Contains(array);
+  for (int i = 0, l = array->length(); i < l; ++i) {
+    if (is_weak) {
+      SetWeakReference(array, entry,
+                       i, array->get(i), array->OffsetOfElementAt(i));
+    } else {
+      SetInternalReference(array, entry,
+                           i, array->get(i), array->OffsetOfElementAt(i));
+    }
+  }
+}
+
+
 void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, int entry) {
   if (!js_obj->IsJSFunction()) return;
 
@@ -1633,7 +1660,6 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
         case HANDLER:  // only in lookup results, not in descriptors
         case INTERCEPTOR:  // only in lookup results, not in descriptors
           break;
-        case TRANSITION:
         case NONEXISTENT:
           UNREACHABLE();
           break;
@@ -1724,8 +1750,10 @@ String* V8HeapExplorer::GetConstructorName(JSObject* object) {
     // return its name. This is for instances of binding objects, which
     // have prototype constructor type "Object".
     Object* constructor_prop = NULL;
-    LookupResult result(heap->isolate());
-    object->LocalLookupRealNamedProperty(heap->constructor_string(), &result);
+    Isolate* isolate = heap->isolate();
+    LookupResult result(isolate);
+    object->LocalLookupRealNamedProperty(
+        isolate->factory()->constructor_string(), &result);
     if (!result.IsFound()) return object->constructor_name();
 
     constructor_prop = result.GetLazyValue();
@@ -1832,6 +1860,25 @@ bool V8HeapExplorer::IterateAndExtractReferences(
   heap_->IterateRoots(&extractor, VISIT_ALL);
   extractor.FillReferences(this);
 
+  // We have to do two passes as sometimes FixedArrays are used
+  // to weakly hold their items, and it's impossible to distinguish
+  // between these cases without processing the array owner first.
+  bool interrupted =
+      IterateAndExtractSinglePass<&V8HeapExplorer::ExtractReferencesPass1>() ||
+      IterateAndExtractSinglePass<&V8HeapExplorer::ExtractReferencesPass2>();
+
+  if (interrupted) {
+    filler_ = NULL;
+    return false;
+  }
+
+  filler_ = NULL;
+  return progress_->ProgressReport(true);
+}
+
+
+template<V8HeapExplorer::ExtractReferencesMethod extractor>
+bool V8HeapExplorer::IterateAndExtractSinglePass() {
   // Now iterate the whole heap.
   bool interrupted = false;
   HeapIterator iterator(heap_, HeapIterator::kFilterUnreachable);
@@ -1839,18 +1886,22 @@ bool V8HeapExplorer::IterateAndExtractReferences(
   for (HeapObject* obj = iterator.next();
        obj != NULL;
        obj = iterator.next(), progress_->ProgressStep()) {
-    if (!interrupted) {
-      ExtractReferences(obj);
-      if (!progress_->ProgressReport(false)) interrupted = true;
+    if (interrupted) continue;
+
+    HeapEntry* heap_entry = GetEntry(obj);
+    int entry = heap_entry->index();
+    if ((this->*extractor)(entry, obj)) {
+      SetInternalReference(obj, entry,
+                           "map", obj->map(), HeapObject::kMapOffset);
+      // Extract unvisited fields as hidden references and restore tags
+      // of visited fields.
+      IndexedReferencesExtractor refs_extractor(this, obj, entry);
+      obj->Iterate(&refs_extractor);
     }
-  }
-  if (interrupted) {
-    filler_ = NULL;
-    return false;
-  }
 
-  filler_ = NULL;
-  return progress_->ProgressReport(true);
+    if (!progress_->ProgressReport(false)) interrupted = true;
+  }
+  return interrupted;
 }
 
 
@@ -1986,6 +2037,24 @@ void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
 }
 
 
+void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
+                                      int parent_entry,
+                                      int index,
+                                      Object* child_obj,
+                                      int field_offset) {
+  ASSERT(parent_entry == GetEntry(parent_obj)->index());
+  HeapEntry* child_entry = GetEntry(child_obj);
+  if (child_entry == NULL) return;
+  if (IsEssentialObject(child_obj)) {
+    filler_->SetNamedReference(HeapGraphEdge::kWeak,
+                               parent_entry,
+                               names_->GetFormatted("%d", index),
+                               child_entry);
+  }
+  IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
+}
+
+
 void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
                                           int parent_entry,
                                           Name* reference_name,
@@ -2071,9 +2140,7 @@ void V8HeapExplorer::SetGcSubrootReference(
       GlobalObject* global = context->global_object();
       if (global->IsJSGlobalObject()) {
         bool is_debug_object = false;
-#ifdef ENABLE_DEBUGGER_SUPPORT
         is_debug_object = heap_->isolate()->debug()->IsDebugGlobal(global);
-#endif
         if (!is_debug_object && !user_roots_.Contains(global)) {
           user_roots_.Insert(global);
           SetUserGlobalReference(global);
@@ -2113,6 +2180,13 @@ void V8HeapExplorer::TagObject(Object* obj, const char* tag) {
 }
 
 
+void V8HeapExplorer::MarkAsWeakContainer(Object* object) {
+  if (IsEssentialObject(object) && object->IsFixedArray()) {
+    weak_containers_.Insert(object);
+  }
+}
+
+
 class GlobalObjectsEnumerator : public ObjectVisitor {
  public:
   virtual void VisitPointers(Object** start, Object** end) {
@@ -2503,7 +2577,7 @@ bool HeapSnapshotGenerator::GenerateSnapshot() {
   debug_heap->Verify();
 #endif
 
-  SetProgressTotal(1);  // 1 pass.
+  SetProgressTotal(2);  // 2 passes.
 
 #ifdef VERIFY_HEAP
   debug_heap->Verify();