Revision: 8111
Author: [email protected]
Date: Mon May 30 07:31:47 2011
Log: Heap profiler: fetch document.URL of global objects.
This allows to distinguish DOMWindow objects in browser from each other.
[email protected],[email protected]
BUG=https://bugs.webkit.org/show_bug.cgi?id=61177
TEST=cctest/test-heap-profiler/DocumentURL
Review URL: http://codereview.chromium.org/7082012
http://code.google.com/p/v8/source/detail?r=8111
Modified:
/branches/bleeding_edge/src/profile-generator.cc
/branches/bleeding_edge/src/profile-generator.h
/branches/bleeding_edge/test/cctest/test-heap-profiler.cc
=======================================
--- /branches/bleeding_edge/src/profile-generator.cc Mon May 23 15:23:50
2011
+++ /branches/bleeding_edge/src/profile-generator.cc Mon May 30 07:31:47
2011
@@ -1600,6 +1600,28 @@
cache_entry->value = HeapEntriesMap::kHeapEntryPlaceholder;
}
}
+
+
+const char* HeapObjectsSet::GetTag(Object* obj) {
+ HeapObject* object = HeapObject::cast(obj);
+ HashMap::Entry* cache_entry =
+ entries_.Lookup(object, HeapEntriesMap::Hash(object), false);
+ if (cache_entry != NULL
+ && cache_entry->value != HeapEntriesMap::kHeapEntryPlaceholder) {
+ return reinterpret_cast<const char*>(cache_entry->value);
+ } else {
+ return NULL;
+ }
+}
+
+
+void HeapObjectsSet::SetTag(Object* obj, const char* tag) {
+ if (!obj->IsHeapObject()) return;
+ HeapObject* object = HeapObject::cast(obj);
+ HashMap::Entry* cache_entry =
+ entries_.Lookup(object, HeapEntriesMap::Hash(object), true);
+ cache_entry->value = const_cast<char*>(tag);
+}
HeapObject *const V8HeapExplorer::kInternalRootObject =
@@ -1639,6 +1661,18 @@
return snapshot_->AddRootEntry(children_count);
} else if (object == kGcRootsObject) {
return snapshot_->AddGcRootsEntry(children_count, retainers_count);
+ } else if (object->IsJSGlobalObject()) {
+ const char* tag = objects_tags_.GetTag(object);
+ const char* name = collection_->names()->GetName(
+ GetConstructorNameForHeapProfile(JSObject::cast(object)));
+ if (tag != NULL) {
+ name = collection_->names()->GetFormatted("%s / %s", name, tag);
+ }
+ return AddEntry(object,
+ HeapEntry::kObject,
+ name,
+ children_count,
+ retainers_count);
} else if (object->IsJSFunction()) {
JSFunction* func = JSFunction::cast(object);
SharedFunctionInfo* shared = func->shared();
@@ -1780,6 +1814,7 @@
ASSERT(Memory::Object_at(field)->IsHeapObject());
*field |= kFailureTag;
}
+
private:
bool CheckVisitedAndUnmark(Object** field) {
if ((*field)->IsFailure()) {
@@ -2204,6 +2239,64 @@
child_obj, child_entry);
}
}
+
+
+class GlobalObjectsEnumerator : public ObjectVisitor {
+ public:
+ virtual void VisitPointers(Object** start, Object** end) {
+ for (Object** p = start; p < end; p++) {
+ if ((*p)->IsGlobalContext()) {
+ Context* context = Context::cast(*p);
+ JSObject* proxy = context->global_proxy();
+ if (proxy->IsJSGlobalProxy()) {
+ Object* global = proxy->map()->prototype();
+ if (global->IsJSGlobalObject()) {
+
objects_.Add(Handle<JSGlobalObject>(JSGlobalObject::cast(global)));
+ }
+ }
+ }
+ }
+ }
+ int count() { return objects_.length(); }
+ Handle<JSGlobalObject>& at(int i) { return objects_[i]; }
+
+ private:
+ List<Handle<JSGlobalObject> > objects_;
+};
+
+
+// Modifies heap. Must not be run during heap traversal.
+void V8HeapExplorer::TagGlobalObjects() {
+ Isolate* isolate = Isolate::Current();
+ GlobalObjectsEnumerator enumerator;
+ isolate->global_handles()->IterateAllRoots(&enumerator);
+ Handle<String> document_string =
+ isolate->factory()->NewStringFromAscii(CStrVector("document"));
+ Handle<String> url_string =
+ isolate->factory()->NewStringFromAscii(CStrVector("URL"));
+ const char** urls = NewArray<const char*>(enumerator.count());
+ for (int i = 0, l = enumerator.count(); i < l; ++i) {
+ urls[i] = NULL;
+ Handle<JSGlobalObject> global_obj = enumerator.at(i);
+ Object* obj_document;
+ if (global_obj->GetProperty(*document_string)->ToObject(&obj_document)
&&
+ obj_document->IsJSObject()) {
+ JSObject* document = JSObject::cast(obj_document);
+ Object* obj_url;
+ if (document->GetProperty(*url_string)->ToObject(&obj_url) &&
+ obj_url->IsString()) {
+ urls[i] = collection_->names()->GetName(String::cast(obj_url));
+ }
+ }
+ }
+
+ AssertNoAllocation no_allocation;
+ for (int i = 0, l = enumerator.count(); i < l; ++i) {
+ objects_tags_.SetTag(*enumerator.at(i), urls[i]);
+ }
+
+ DeleteArray(urls);
+}
class GlobalHandlesExtractor : public ObjectVisitor {
@@ -2448,6 +2541,7 @@
HeapEntry*) {
entries_->CountReference(parent_ptr, child_ptr);
}
+
private:
HeapEntriesMap* entries_;
};
@@ -2519,6 +2613,7 @@
child_entry,
retainer_index);
}
+
private:
HeapSnapshot* snapshot_;
HeapSnapshotsCollection* collection_;
@@ -2527,6 +2622,8 @@
bool HeapSnapshotGenerator::GenerateSnapshot() {
+ v8_heap_explorer_.TagGlobalObjects();
+
AssertNoAllocation no_alloc;
SetProgressTotal(4); // 2 passes + dominators + sizes.
=======================================
--- /branches/bleeding_edge/src/profile-generator.h Thu May 5 23:50:20 2011
+++ /branches/bleeding_edge/src/profile-generator.h Mon May 30 07:31:47 2011
@@ -859,6 +859,8 @@
void Clear();
bool Contains(Object* object);
void Insert(Object* obj);
+ const char* GetTag(Object* obj);
+ void SetTag(Object* obj, const char* tag);
private:
HashMap entries_;
@@ -920,6 +922,7 @@
void AddRootEntries(SnapshotFillerInterface* filler);
int EstimateObjectsCount();
bool IterateAndExtractReferences(SnapshotFillerInterface* filler);
+ void TagGlobalObjects();
static HeapObject* const kInternalRootObject;
@@ -978,6 +981,7 @@
HeapSnapshotsCollection* collection_;
SnapshottingProgressReportingInterface* progress_;
SnapshotFillerInterface* filler_;
+ HeapObjectsSet objects_tags_;
static HeapObject* const kGcRootsObject;
=======================================
--- /branches/bleeding_edge/test/cctest/test-heap-profiler.cc Mon May 23
15:23:50 2011
+++ /branches/bleeding_edge/test/cctest/test-heap-profiler.cc Mon May 30
07:31:47 2011
@@ -416,8 +416,8 @@
CHECK_EQ(2, snapshot->GetRoot()->GetChildrenCount());
const v8::HeapGraphNode* global_obj =
snapshot->GetRoot()->GetChild(0)->GetToNode();
- CHECK_EQ("Object", const_cast<i::HeapEntry*>(
- reinterpret_cast<const i::HeapEntry*>(global_obj))->name());
+ CHECK_EQ(0, strncmp("Object", const_cast<i::HeapEntry*>(
+ reinterpret_cast<const i::HeapEntry*>(global_obj))->name(), 6));
return global_obj;
}
@@ -1321,5 +1321,55 @@
CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid3));
}
+
+
+TEST(DocumentURL) {
+ v8::HandleScope scope;
+ LocalContext env;
+
+ CompileRun("document = { URL:\"abcdefgh\" };");
+
+ const v8::HeapSnapshot* snapshot =
+ v8::HeapProfiler::TakeSnapshot(v8::String::New("document"));
+ const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+ CHECK_NE(NULL, global);
+ CHECK_EQ("Object / abcdefgh",
+ const_cast<i::HeapEntry*>(
+ reinterpret_cast<const i::HeapEntry*>(global))->name());
+}
+
+
+TEST(DocumentWithException) {
+ v8::HandleScope scope;
+ LocalContext env;
+
+ CompileRun(
+ "this.__defineGetter__(\"document\", function() { throw new Error();
})");
+ const v8::HeapSnapshot* snapshot =
+ v8::HeapProfiler::TakeSnapshot(v8::String::New("document"));
+ const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+ CHECK_NE(NULL, global);
+ CHECK_EQ("Object",
+ const_cast<i::HeapEntry*>(
+ reinterpret_cast<const i::HeapEntry*>(global))->name());
+}
+
+
+TEST(DocumentURLWithException) {
+ v8::HandleScope scope;
+ LocalContext env;
+
+ CompileRun(
+ "function URLWithException() {}\n"
+ "URLWithException.prototype = { get URL() { throw new Error(); }
};\n"
+ "document = { URL: new URLWithException() };");
+ const v8::HeapSnapshot* snapshot =
+ v8::HeapProfiler::TakeSnapshot(v8::String::New("document"));
+ const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+ CHECK_NE(NULL, global);
+ CHECK_EQ("Object",
+ const_cast<i::HeapEntry*>(
+ reinterpret_cast<const i::HeapEntry*>(global))->name());
+}
#endif // ENABLE_LOGGING_AND_PROFILING
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev