From: alexeif@chromium.org Date: Mon, 16 Apr 2012 14:31:13 +0000 (+0000) Subject: External references should not affect dominance relation. X-Git-Tag: upstream/4.7.83~16885 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f4c15c4ec26233e6e00b7bddea0d36c2863d7a1d;p=platform%2Fupstream%2Fv8.git External references should not affect dominance relation. Separate objects into two groups: reachable from a window (user), and unreachable (system). Then do not take into account links that come from system group to the user group when calculating dominance relation. Review URL: https://chromiumcodereview.appspot.com/10086006 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11335 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/api.cc b/src/api.cc index 067609a..921368b 100644 --- a/src/api.cc +++ b/src/api.cc @@ -5998,7 +5998,7 @@ Handle HeapGraphEdge::GetName() const { const HeapGraphNode* HeapGraphEdge::GetFromNode() const { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::HeapGraphEdge::GetFromNode"); - const i::HeapEntry* from = ToInternal(this)->From(); + const i::HeapEntry* from = ToInternal(this)->from(); return reinterpret_cast(from); } diff --git a/src/profile-generator-inl.h b/src/profile-generator-inl.h index 65369be..284e2df 100644 --- a/src/profile-generator-inl.h +++ b/src/profile-generator-inl.h @@ -95,6 +95,12 @@ CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) { } +HeapEntry* HeapGraphEdge::from() const { + return const_cast( + reinterpret_cast(this - child_index_) - 1); +} + + SnapshotObjectId HeapObjectsMap::GetNthGcSubrootId(int delta) { return kGcRootsFirstSubrootId + delta * kObjectIdStep; } diff --git a/src/profile-generator.cc b/src/profile-generator.cc index cd8a82b..173f42e 100644 --- a/src/profile-generator.cc +++ b/src/profile-generator.cc @@ -957,11 +957,6 @@ void HeapGraphEdge::Init(int child_index, int index, HeapEntry* to) { } -HeapEntry* HeapGraphEdge::From() { - return reinterpret_cast(this - child_index_) - 1; -} - - void HeapEntry::Init(HeapSnapshot* snapshot, Type type, const char* name, @@ -972,6 +967,7 @@ void HeapEntry::Init(HeapSnapshot* snapshot, snapshot_ = snapshot; type_ = type; painted_ = false; + reachable_from_window_ = false; name_ = name; self_size_ = self_size; retained_size_ = 0; @@ -1991,7 +1987,7 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { // We use JSGlobalProxy because this is what embedder (e.g. browser) // uses for the global object. JSGlobalProxy* proxy = JSGlobalProxy::cast(obj); - SetRootShortcutReference(proxy->map()->prototype()); + SetWindowReference(proxy->map()->prototype()); } else if (obj->IsJSObject()) { JSObject* js_obj = JSObject::cast(obj); ExtractClosureReferences(js_obj, entry); @@ -2259,15 +2255,15 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, Object* k = dictionary->KeyAt(i); if (dictionary->IsKey(k)) { Object* target = dictionary->ValueAt(i); - SetPropertyReference( - js_obj, entry, String::cast(k), target); // We assume that global objects can only have slow properties. - if (target->IsJSGlobalPropertyCell()) { - SetPropertyShortcutReference(js_obj, - entry, - String::cast(k), - JSGlobalPropertyCell::cast( - target)->value()); + Object* value = target->IsJSGlobalPropertyCell() + ? JSGlobalPropertyCell::cast(target)->value() + : target; + if (String::cast(k)->length() > 0) { + SetPropertyReference(js_obj, entry, String::cast(k), value); + } else { + TagObject(value, "(hidden properties)"); + SetInternalReference(js_obj, entry, "hidden_properties", value); } } } @@ -2636,7 +2632,7 @@ void V8HeapExplorer::SetRootGcRootsReference() { } -void V8HeapExplorer::SetRootShortcutReference(Object* child_obj) { +void V8HeapExplorer::SetWindowReference(Object* child_obj) { HeapEntry* child_entry = GetEntry(child_obj); ASSERT(child_entry != NULL); filler_->SetNamedAutoIndexReference( @@ -2718,7 +2714,7 @@ void V8HeapExplorer::TagGlobalObjects() { Handle global_obj = enumerator.at(i); Object* obj_document; if (global_obj->GetProperty(*document_string)->ToObject(&obj_document) && - obj_document->IsJSObject()) { + obj_document->IsJSObject()) { JSObject* document = JSObject::cast(obj_document); Object* obj_url; if (document->GetProperty(*url_string)->ToObject(&obj_url) && @@ -3272,19 +3268,61 @@ bool HeapSnapshotGenerator::FillReferences() { } -void HeapSnapshotGenerator::FillReversePostorderIndexes( +bool HeapSnapshotGenerator::IsWindowReference(const HeapGraphEdge& edge) { + ASSERT(edge.from() == snapshot_->root()); + return edge.type() == HeapGraphEdge::kShortcut; +} + + +void HeapSnapshotGenerator::MarkWindowReachableObjects() { + List worklist; + + Vector children = snapshot_->root()->children(); + for (int i = 0; i < children.length(); ++i) { + if (IsWindowReference(children[i])) { + worklist.Add(children[i].to()); + } + } + + while (!worklist.is_empty()) { + HeapEntry* entry = worklist.RemoveLast(); + if (entry->reachable_from_window()) continue; + entry->set_reachable_from_window(); + Vector children = entry->children(); + for (int i = 0; i < children.length(); ++i) { + HeapEntry* child = children[i].to(); + if (!child->reachable_from_window()) { + worklist.Add(child); + } + } + } +} + + +static bool IsRetainingEdge(HeapGraphEdge* edge) { + if (edge->type() == HeapGraphEdge::kShortcut) return false; + // The edge is not retaining if it goes from system domain + // (i.e. an object not reachable from window) to the user domain + // (i.e. a reachable object). + return edge->from()->reachable_from_window() + || !edge->to()->reachable_from_window(); +} + + +void HeapSnapshotGenerator::FillPostorderIndexes( Vector* entries) { snapshot_->ClearPaint(); int current_entry = 0; List nodes_to_visit; - nodes_to_visit.Add(snapshot_->root()); + HeapEntry* root = snapshot_->root(); + nodes_to_visit.Add(root); snapshot_->root()->paint(); while (!nodes_to_visit.is_empty()) { HeapEntry* entry = nodes_to_visit.last(); Vector children = entry->children(); bool has_new_edges = false; for (int i = 0; i < children.length(); ++i) { - if (children[i].type() == HeapGraphEdge::kShortcut) continue; + if (entry != root && !IsRetainingEdge(&children[i])) continue; HeapEntry* child = children[i].to(); if (!child->painted()) { nodes_to_visit.Add(child); @@ -3319,6 +3357,7 @@ bool HeapSnapshotGenerator::BuildDominatorTree( const Vector& entries, Vector* dominators) { if (entries.length() == 0) return true; + HeapEntry* root = snapshot_->root(); const int entries_length = entries.length(), root_index = entries_length - 1; static const int kNoDominator = -1; for (int i = 0; i < root_index; ++i) (*dominators)[i] = kNoDominator; @@ -3347,8 +3386,8 @@ bool HeapSnapshotGenerator::BuildDominatorTree( int new_idom_index = kNoDominator; Vector rets = entries[i]->retainers(); for (int j = 0; j < rets.length(); ++j) { - if (rets[j]->type() == HeapGraphEdge::kShortcut) continue; - int ret_index = rets[j]->From()->ordered_index(); + if (rets[j]->from() != root && !IsRetainingEdge(rets[j])) continue; + int ret_index = rets[j]->from()->ordered_index(); if (dominators->at(ret_index) != kNoDominator) { new_idom_index = new_idom_index == kNoDominator ? ret_index @@ -3374,9 +3413,10 @@ bool HeapSnapshotGenerator::BuildDominatorTree( bool HeapSnapshotGenerator::SetEntriesDominators() { - // This array is used for maintaining reverse postorder of nodes. + MarkWindowReachableObjects(); + // This array is used for maintaining postorder of nodes. ScopedVector ordered_entries(snapshot_->entries()->length()); - FillReversePostorderIndexes(&ordered_entries); + FillPostorderIndexes(&ordered_entries); ScopedVector dominators(ordered_entries.length()); if (!BuildDominatorTree(ordered_entries, &dominators)) return false; for (int i = 0; i < ordered_entries.length(); ++i) { diff --git a/src/profile-generator.h b/src/profile-generator.h index cda0306..80e9295 100644 --- a/src/profile-generator.h +++ b/src/profile-generator.h @@ -464,21 +464,20 @@ class HeapGraphEdge BASE_EMBEDDED { void Init(int child_index, Type type, int index, HeapEntry* to); void Init(int child_index, int index, HeapEntry* to); - Type type() { return static_cast(type_); } - int index() { + Type type() const { return static_cast(type_); } + int index() const { ASSERT(type_ == kElement || type_ == kHidden || type_ == kWeak); return index_; } - const char* name() { + const char* name() const { ASSERT(type_ == kContextVariable || type_ == kProperty || type_ == kInternal || type_ == kShortcut); return name_; } - HeapEntry* to() { return to_; } - - HeapEntry* From(); + HeapEntry* to() const { return to_; } + INLINE(HeapEntry* from() const); private: int child_index_ : 29; @@ -564,6 +563,8 @@ class HeapEntry BASE_EMBEDDED { void clear_paint() { painted_ = false; } bool painted() { return painted_; } void paint() { painted_ = true; } + bool reachable_from_window() { return reachable_from_window_; } + void set_reachable_from_window() { reachable_from_window_ = true; } void SetIndexedReference(HeapGraphEdge::Type type, int child_index, @@ -600,8 +601,9 @@ class HeapEntry BASE_EMBEDDED { const char* TypeAsString(); unsigned painted_: 1; + unsigned reachable_from_window_: 1; unsigned type_: 4; - int children_count_: 27; + int children_count_: 26; int retainers_count_; int self_size_; union { @@ -1016,7 +1018,7 @@ class V8HeapExplorer : public HeapEntriesAllocator { HeapEntry* parent, String* reference_name, Object* child); - void SetRootShortcutReference(Object* child); + void SetWindowReference(Object* window); void SetRootGcRootsReference(); void SetGcRootsReference(VisitorSynchronization::SyncTag tag); void SetGcSubrootReference( @@ -1120,7 +1122,9 @@ class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface { bool CalculateRetainedSizes(); bool CountEntriesAndReferences(); bool FillReferences(); - void FillReversePostorderIndexes(Vector* entries); + void FillPostorderIndexes(Vector* entries); + bool IsWindowReference(const HeapGraphEdge& edge); + void MarkWindowReachableObjects(); void ProgressStep(); bool ProgressReport(bool force = false); bool SetEntriesDominators(); diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc index 05098a3..b6e98e5 100644 --- a/test/cctest/test-heap-profiler.cc +++ b/test/cctest/test-heap-profiler.cc @@ -109,13 +109,13 @@ TEST(HeapSnapshot) { // Verify, that JS global object of env2 has '..2' properties. const v8::HeapGraphNode* a2_node = - GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "a2"); + GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "a2"); CHECK_NE(NULL, a2_node); CHECK_NE( - NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_1")); + NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b2_1")); CHECK_NE( - NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_2")); - CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "c2")); + NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b2_2")); + CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "c2")); // Paint all nodes reachable from global object. NamedEntriesDetector det; @@ -137,12 +137,13 @@ TEST(HeapSnapshotObjectSizes) { CompileRun( "function X(a, b) { this.a = a; this.b = b; }\n" "x = new X(new X(), new X());\n" + "dummy = new X();\n" "(function() { x.a.a = x.b; })();"); const v8::HeapSnapshot* snapshot = v8::HeapProfiler::TakeSnapshot(v8_str("sizes")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* x = - GetProperty(global, v8::HeapGraphEdge::kShortcut, "x"); + GetProperty(global, v8::HeapGraphEdge::kProperty, "x"); CHECK_NE(NULL, x); const v8::HeapGraphNode* x1 = GetProperty(x, v8::HeapGraphEdge::kProperty, "a"); @@ -169,7 +170,7 @@ TEST(BoundFunctionInSnapshot) { v8::HeapProfiler::TakeSnapshot(v8_str("sizes")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* f = - GetProperty(global, v8::HeapGraphEdge::kShortcut, "boundFunction"); + GetProperty(global, v8::HeapGraphEdge::kProperty, "boundFunction"); CHECK(f); CHECK_EQ(v8::String::New("native_bind"), f->GetName()); const v8::HeapGraphNode* bindings = @@ -233,15 +234,15 @@ TEST(HeapSnapshotCodeObjects) { const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* compiled = - GetProperty(global, v8::HeapGraphEdge::kShortcut, "compiled"); + GetProperty(global, v8::HeapGraphEdge::kProperty, "compiled"); CHECK_NE(NULL, compiled); CHECK_EQ(v8::HeapGraphNode::kClosure, compiled->GetType()); const v8::HeapGraphNode* lazy = - GetProperty(global, v8::HeapGraphEdge::kShortcut, "lazy"); + GetProperty(global, v8::HeapGraphEdge::kProperty, "lazy"); CHECK_NE(NULL, lazy); CHECK_EQ(v8::HeapGraphNode::kClosure, lazy->GetType()); const v8::HeapGraphNode* anonymous = - GetProperty(global, v8::HeapGraphEdge::kShortcut, "anonymous"); + GetProperty(global, v8::HeapGraphEdge::kProperty, "anonymous"); CHECK_NE(NULL, anonymous); CHECK_EQ(v8::HeapGraphNode::kClosure, anonymous->GetType()); v8::String::AsciiValue anonymous_name(anonymous->GetName()); @@ -293,9 +294,9 @@ TEST(HeapSnapshotHeapNumbers) { const v8::HeapSnapshot* snapshot = v8::HeapProfiler::TakeSnapshot(v8_str("numbers")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); - CHECK_EQ(NULL, GetProperty(global, v8::HeapGraphEdge::kShortcut, "a")); + CHECK_EQ(NULL, GetProperty(global, v8::HeapGraphEdge::kProperty, "a")); const v8::HeapGraphNode* b = - GetProperty(global, v8::HeapGraphEdge::kShortcut, "b"); + GetProperty(global, v8::HeapGraphEdge::kProperty, "b"); CHECK_NE(NULL, b); CHECK_EQ(v8::HeapGraphNode::kHeapNumber, b->GetType()); } @@ -313,10 +314,10 @@ TEST(HeapSnapshotSlicedString) { v8::HeapProfiler::TakeSnapshot(v8_str("strings")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* parent_string = - GetProperty(global, v8::HeapGraphEdge::kShortcut, "parent_string"); + GetProperty(global, v8::HeapGraphEdge::kProperty, "parent_string"); CHECK_NE(NULL, parent_string); const v8::HeapGraphNode* child_string = - GetProperty(global, v8::HeapGraphEdge::kShortcut, "child_string"); + GetProperty(global, v8::HeapGraphEdge::kProperty, "child_string"); CHECK_NE(NULL, child_string); const v8::HeapGraphNode* parent = GetProperty(child_string, v8::HeapGraphEdge::kInternal, "parent"); @@ -384,24 +385,17 @@ TEST(HeapEntryIdsAndArrayShift) { const v8::HeapGraphNode* a1 = GetProperty(global1, v8::HeapGraphEdge::kProperty, "a"); CHECK_NE(NULL, a1); - const v8::HeapGraphNode* e1 = - GetProperty(a1, v8::HeapGraphEdge::kHidden, "1"); - CHECK_NE(NULL, e1); const v8::HeapGraphNode* k1 = - GetProperty(e1, v8::HeapGraphEdge::kInternal, "elements"); + GetProperty(a1, v8::HeapGraphEdge::kInternal, "elements"); CHECK_NE(NULL, k1); const v8::HeapGraphNode* a2 = GetProperty(global2, v8::HeapGraphEdge::kProperty, "a"); CHECK_NE(NULL, a2); - const v8::HeapGraphNode* e2 = - GetProperty(a2, v8::HeapGraphEdge::kHidden, "1"); - CHECK_NE(NULL, e2); const v8::HeapGraphNode* k2 = - GetProperty(e2, v8::HeapGraphEdge::kInternal, "elements"); + GetProperty(a2, v8::HeapGraphEdge::kInternal, "elements"); CHECK_NE(NULL, k2); CHECK_EQ_SNAPSHOT_OBJECT_ID(a1->GetId(), a2->GetId()); - CHECK_EQ_SNAPSHOT_OBJECT_ID(e1->GetId(), e2->GetId()); CHECK_EQ_SNAPSHOT_OBJECT_ID(k1->GetId(), k2->GetId()); } @@ -514,7 +508,7 @@ TEST(HeapEntryDominator) { const v8::HeapGraphNode* global = GetGlobalObject(snapshot); CHECK_NE(NULL, global); const v8::HeapGraphNode* node6 = - GetProperty(global, v8::HeapGraphEdge::kShortcut, "node6"); + GetProperty(global, v8::HeapGraphEdge::kProperty, "node6"); CHECK_NE(NULL, node6); const v8::HeapGraphNode* node5 = GetProperty(node6, v8::HeapGraphEdge::kProperty, "a"); @@ -659,7 +653,7 @@ TEST(HeapSnapshotJSONSerialization) { " GetChildPosByProperty(" " parsed.edges[parsed.nodes[edges_index_offset]" " + edge_to_node_offset]," - " \"b\", shortcut_type),\n" + " \"b\", property_type),\n" " \"x\", property_type)," " \"s\", property_type)"); CHECK(!string_obj_pos_val.IsEmpty()); @@ -1153,9 +1147,8 @@ TEST(HeapSnapshotImplicitReferences) { v8::HeapProfiler::TakeSnapshot(v8_str("implicit_refs")); const v8::HeapGraphNode* global_object = GetGlobalObject(snapshot); - // Use kShortcut type to skip intermediate JSGlobalPropertyCell const v8::HeapGraphNode* obj0 = GetProperty( - global_object, v8::HeapGraphEdge::kShortcut, "root_object"); + global_object, v8::HeapGraphEdge::kProperty, "root_object"); CHECK(obj0); CHECK_EQ(v8::HeapGraphNode::kObject, obj0->GetType()); const v8::HeapGraphNode* obj1 = GetProperty( @@ -1328,7 +1321,7 @@ TEST(GetHeapValue) { env->Global()->GetPrototype().As(); CHECK(js_global == global->GetHeapValue()); const v8::HeapGraphNode* obj = GetProperty( - global, v8::HeapGraphEdge::kShortcut, "a"); + global, v8::HeapGraphEdge::kProperty, "a"); CHECK(obj->GetHeapValue()->IsObject()); v8::Local js_obj = js_global->Get(v8_str("a")).As(); CHECK(js_obj == obj->GetHeapValue()); @@ -1357,7 +1350,7 @@ TEST(GetHeapValueForDeletedObject) { v8::HeapProfiler::TakeSnapshot(v8_str("snapshot")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* obj = GetProperty( - global, v8::HeapGraphEdge::kShortcut, "a"); + global, v8::HeapGraphEdge::kProperty, "a"); const v8::HeapGraphNode* prop = GetProperty( obj, v8::HeapGraphEdge::kProperty, "p"); { @@ -1444,7 +1437,7 @@ TEST(FastCaseGetter) { const v8::HeapGraphNode* global = GetGlobalObject(snapshot); CHECK_NE(NULL, global); const v8::HeapGraphNode* obj1 = - GetProperty(global, v8::HeapGraphEdge::kShortcut, "obj1"); + GetProperty(global, v8::HeapGraphEdge::kProperty, "obj1"); CHECK_NE(NULL, obj1); const v8::HeapGraphNode* getterFunction = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get-propWithGetter"); @@ -1526,7 +1519,7 @@ TEST(SfiAndJsFunctionWeakRefs) { const v8::HeapGraphNode* global = GetGlobalObject(snapshot); CHECK_NE(NULL, global); const v8::HeapGraphNode* fun = - GetProperty(global, v8::HeapGraphEdge::kShortcut, "fun"); + GetProperty(global, v8::HeapGraphEdge::kProperty, "fun"); CHECK(HasWeakEdge(fun)); const v8::HeapGraphNode* shared = GetProperty(fun, v8::HeapGraphEdge::kInternal, "shared");