Home | History | Annotate | Download | only in src
      1 // Copyright 2009-2010 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/v8.h"
      6 
      7 #include "src/heap-profiler.h"
      8 
      9 #include "src/allocation-tracker.h"
     10 #include "src/heap-snapshot-generator-inl.h"
     11 
     12 namespace v8 {
     13 namespace internal {
     14 
     15 HeapProfiler::HeapProfiler(Heap* heap)
     16     : ids_(new HeapObjectsMap(heap)),
     17       names_(new StringsStorage(heap)),
     18       next_snapshot_uid_(1),
     19       is_tracking_object_moves_(false) {
     20 }
     21 
     22 
     23 static void DeleteHeapSnapshot(HeapSnapshot** snapshot_ptr) {
     24   delete *snapshot_ptr;
     25 }
     26 
     27 
     28 HeapProfiler::~HeapProfiler() {
     29   snapshots_.Iterate(DeleteHeapSnapshot);
     30   snapshots_.Clear();
     31 }
     32 
     33 
     34 void HeapProfiler::DeleteAllSnapshots() {
     35   snapshots_.Iterate(DeleteHeapSnapshot);
     36   snapshots_.Clear();
     37   names_.Reset(new StringsStorage(heap()));
     38 }
     39 
     40 
     41 void HeapProfiler::RemoveSnapshot(HeapSnapshot* snapshot) {
     42   snapshots_.RemoveElement(snapshot);
     43 }
     44 
     45 
     46 void HeapProfiler::DefineWrapperClass(
     47     uint16_t class_id, v8::HeapProfiler::WrapperInfoCallback callback) {
     48   DCHECK(class_id != v8::HeapProfiler::kPersistentHandleNoClassId);
     49   if (wrapper_callbacks_.length() <= class_id) {
     50     wrapper_callbacks_.AddBlock(
     51         NULL, class_id - wrapper_callbacks_.length() + 1);
     52   }
     53   wrapper_callbacks_[class_id] = callback;
     54 }
     55 
     56 
     57 v8::RetainedObjectInfo* HeapProfiler::ExecuteWrapperClassCallback(
     58     uint16_t class_id, Object** wrapper) {
     59   if (wrapper_callbacks_.length() <= class_id) return NULL;
     60   return wrapper_callbacks_[class_id](
     61       class_id, Utils::ToLocal(Handle<Object>(wrapper)));
     62 }
     63 
     64 
     65 HeapSnapshot* HeapProfiler::TakeSnapshot(
     66     const char* name,
     67     v8::ActivityControl* control,
     68     v8::HeapProfiler::ObjectNameResolver* resolver) {
     69   HeapSnapshot* result = new HeapSnapshot(this, name, next_snapshot_uid_++);
     70   {
     71     HeapSnapshotGenerator generator(result, control, resolver, heap());
     72     if (!generator.GenerateSnapshot()) {
     73       delete result;
     74       result = NULL;
     75     } else {
     76       snapshots_.Add(result);
     77     }
     78   }
     79   ids_->RemoveDeadEntries();
     80   is_tracking_object_moves_ = true;
     81   return result;
     82 }
     83 
     84 
     85 HeapSnapshot* HeapProfiler::TakeSnapshot(
     86     String* name,
     87     v8::ActivityControl* control,
     88     v8::HeapProfiler::ObjectNameResolver* resolver) {
     89   return TakeSnapshot(names_->GetName(name), control, resolver);
     90 }
     91 
     92 
     93 void HeapProfiler::StartHeapObjectsTracking(bool track_allocations) {
     94   ids_->UpdateHeapObjectsMap();
     95   is_tracking_object_moves_ = true;
     96   DCHECK(!is_tracking_allocations());
     97   if (track_allocations) {
     98     allocation_tracker_.Reset(new AllocationTracker(ids_.get(), names_.get()));
     99     heap()->DisableInlineAllocation();
    100   }
    101 }
    102 
    103 
    104 SnapshotObjectId HeapProfiler::PushHeapObjectsStats(OutputStream* stream) {
    105   return ids_->PushHeapObjectsStats(stream);
    106 }
    107 
    108 
    109 void HeapProfiler::StopHeapObjectsTracking() {
    110   ids_->StopHeapObjectsTracking();
    111   if (is_tracking_allocations()) {
    112     allocation_tracker_.Reset(NULL);
    113     heap()->EnableInlineAllocation();
    114   }
    115 }
    116 
    117 
    118 size_t HeapProfiler::GetMemorySizeUsedByProfiler() {
    119   size_t size = sizeof(*this);
    120   size += names_->GetUsedMemorySize();
    121   size += ids_->GetUsedMemorySize();
    122   size += GetMemoryUsedByList(snapshots_);
    123   for (int i = 0; i < snapshots_.length(); ++i) {
    124     size += snapshots_[i]->RawSnapshotSize();
    125   }
    126   return size;
    127 }
    128 
    129 
    130 int HeapProfiler::GetSnapshotsCount() {
    131   return snapshots_.length();
    132 }
    133 
    134 
    135 HeapSnapshot* HeapProfiler::GetSnapshot(int index) {
    136   return snapshots_.at(index);
    137 }
    138 
    139 
    140 SnapshotObjectId HeapProfiler::GetSnapshotObjectId(Handle<Object> obj) {
    141   if (!obj->IsHeapObject())
    142     return v8::HeapProfiler::kUnknownObjectId;
    143   return ids_->FindEntry(HeapObject::cast(*obj)->address());
    144 }
    145 
    146 
    147 void HeapProfiler::ObjectMoveEvent(Address from, Address to, int size) {
    148   bool known_object = ids_->MoveObject(from, to, size);
    149   if (!known_object && !allocation_tracker_.is_empty()) {
    150     allocation_tracker_->address_to_trace()->MoveObject(from, to, size);
    151   }
    152 }
    153 
    154 
    155 void HeapProfiler::AllocationEvent(Address addr, int size) {
    156   DisallowHeapAllocation no_allocation;
    157   if (!allocation_tracker_.is_empty()) {
    158     allocation_tracker_->AllocationEvent(addr, size);
    159   }
    160 }
    161 
    162 
    163 void HeapProfiler::UpdateObjectSizeEvent(Address addr, int size) {
    164   ids_->UpdateObjectSize(addr, size);
    165 }
    166 
    167 
    168 void HeapProfiler::SetRetainedObjectInfo(UniqueId id,
    169                                          RetainedObjectInfo* info) {
    170   // TODO(yurus, marja): Don't route this information through GlobalHandles.
    171   heap()->isolate()->global_handles()->SetRetainedObjectInfo(id, info);
    172 }
    173 
    174 
    175 Handle<HeapObject> HeapProfiler::FindHeapObjectById(SnapshotObjectId id) {
    176   HeapObject* object = NULL;
    177   HeapIterator iterator(heap(), HeapIterator::kFilterUnreachable);
    178   // Make sure that object with the given id is still reachable.
    179   for (HeapObject* obj = iterator.next();
    180        obj != NULL;
    181        obj = iterator.next()) {
    182     if (ids_->FindEntry(obj->address()) == id) {
    183       DCHECK(object == NULL);
    184       object = obj;
    185       // Can't break -- kFilterUnreachable requires full heap traversal.
    186     }
    187   }
    188   return object != NULL ? Handle<HeapObject>(object) : Handle<HeapObject>();
    189 }
    190 
    191 
    192 void HeapProfiler::ClearHeapObjectMap() {
    193   ids_.Reset(new HeapObjectsMap(heap()));
    194   if (!is_tracking_allocations()) is_tracking_object_moves_ = false;
    195 }
    196 
    197 
    198 } }  // namespace v8::internal
    199