Commit a4b4cfdc authored by loislo@chromium.org's avatar loislo@chromium.org

HeapProfiler: provide human readable names for code objects.

It is very hard to understand the structure of the heap even for about:blank page
because code objects in the heap have no names. This patch propagates the names
for Code::STUB and Code::BUILTIN code objects.
Also it assign function names from SharedFunctionInfo to the code objects.

BUG=
R=alph@chromium.org, svenpanne@chromium.org, yurys@chromium.org

Review URL: https://codereview.chromium.org/52643002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17486 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 6069b062
......@@ -364,6 +364,11 @@ class Builtins {
}
static const char* GetName(JavaScript id) { return javascript_names_[id]; }
const char* name(int index) {
ASSERT(index >= 0);
ASSERT(index < builtin_count);
return names_[index];
}
static int GetArgumentsCount(JavaScript id) { return javascript_argc_[id]; }
Handle<Code> GetCode(JavaScript id, bool* resolved);
static int NumberOfJavaScriptBuiltins() { return id_count; }
......
......@@ -30,6 +30,7 @@
#include "heap-snapshot-generator-inl.h"
#include "allocation-tracker.h"
#include "code-stubs.h"
#include "heap-profiler.h"
#include "debug.h"
#include "types.h"
......@@ -1110,7 +1111,7 @@ class IndexedReferencesExtractor : public ObjectVisitor {
void VisitCodeEntry(Address entry_address) {
Code* code = Code::cast(Code::GetObjectFromEntryAddress(entry_address));
generator_->SetInternalReference(parent_obj_, parent_, "code", code);
generator_->TagObject(code, "(code)");
generator_->TagCodeObject(code);
}
void VisitPointers(Object** start, Object** end) {
for (Object** p = start; p < end; p++) {
......@@ -1370,10 +1371,20 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
void V8HeapExplorer::ExtractSharedFunctionInfoReferences(
int entry, SharedFunctionInfo* shared) {
HeapObject* obj = shared;
StringsStorage* names = collection_->names();
String* shared_name = shared->DebugName();
const char* name = NULL;
if (shared_name != *heap_->isolate()->factory()->empty_string()) {
name = names->GetName(shared_name);
TagObject(shared->code(), names->GetFormatted("(code for %s)", name));
} else {
TagObject(shared->code(), names->GetFormatted("(%s code)",
Code::Kind2String(shared->code()->kind())));
}
SetInternalReference(obj, entry,
"name", shared->name(),
SharedFunctionInfo::kNameOffset);
TagObject(shared->code(), "(code)");
SetInternalReference(obj, entry,
"code", shared->code(),
SharedFunctionInfo::kCodeOffset);
......@@ -1387,7 +1398,10 @@ void V8HeapExplorer::ExtractSharedFunctionInfoReferences(
SetInternalReference(obj, entry,
"script", shared->script(),
SharedFunctionInfo::kScriptOffset);
TagObject(shared->construct_stub(), "(code)");
const char* construct_stub_name = name ?
names->GetFormatted("(construct stub code for %s)", name) :
"(construct stub code)";
TagObject(shared->construct_stub(), construct_stub_name);
SetInternalReference(obj, entry,
"construct_stub", shared->construct_stub(),
SharedFunctionInfo::kConstructStubOffset);
......@@ -1400,6 +1414,9 @@ void V8HeapExplorer::ExtractSharedFunctionInfoReferences(
SetInternalReference(obj, entry,
"inferred_name", shared->inferred_name(),
SharedFunctionInfo::kInferredNameOffset);
SetInternalReference(obj, entry,
"optimized_code_map", shared->optimized_code_map(),
SharedFunctionInfo::kOptimizedCodeMapOffset);
SetWeakReference(obj, entry,
1, shared->initial_map(),
SharedFunctionInfo::kInitialMapOffset);
......@@ -1449,7 +1466,23 @@ void V8HeapExplorer::ExtractCodeCacheReferences(
}
void V8HeapExplorer::TagCodeObject(Code* code, const char* external_name) {
TagObject(code, collection_->names()->GetFormatted("(%s code)",
external_name));
}
void V8HeapExplorer::TagCodeObject(Code* code) {
if (code->kind() == Code::STUB) {
TagObject(code, collection_->names()->GetFormatted(
"(%s code)", CodeStub::MajorName(
static_cast<CodeStub::Major>(code->major_key()), true)));
}
}
void V8HeapExplorer::ExtractCodeReferences(int entry, Code* code) {
TagCodeObject(code);
TagObject(code->relocation_info(), "(code relocation info)");
SetInternalReference(code, entry,
"relocation_info", code->relocation_info(),
......@@ -1695,9 +1728,10 @@ class RootsReferencesExtractor : public ObjectVisitor {
};
public:
RootsReferencesExtractor()
explicit RootsReferencesExtractor(Heap* heap)
: collecting_all_references_(false),
previous_reference_count_(0) {
previous_reference_count_(0),
heap_(heap) {
}
void VisitPointers(Object** start, Object** end) {
......@@ -1712,22 +1746,30 @@ class RootsReferencesExtractor : public ObjectVisitor {
void FillReferences(V8HeapExplorer* explorer) {
ASSERT(strong_references_.length() <= all_references_.length());
Builtins* builtins = heap_->isolate()->builtins();
for (int i = 0; i < reference_tags_.length(); ++i) {
explorer->SetGcRootsReference(reference_tags_[i].tag);
}
int strong_index = 0, all_index = 0, tags_index = 0;
int strong_index = 0, all_index = 0, tags_index = 0, builtin_index = 0;
while (all_index < all_references_.length()) {
if (strong_index < strong_references_.length() &&
strong_references_[strong_index] == all_references_[all_index]) {
explorer->SetGcSubrootReference(reference_tags_[tags_index].tag,
false,
all_references_[all_index++]);
all_references_[all_index]);
++strong_index;
} else {
explorer->SetGcSubrootReference(reference_tags_[tags_index].tag,
true,
all_references_[all_index++]);
all_references_[all_index]);
}
if (reference_tags_[tags_index].tag ==
VisitorSynchronization::kBuiltins) {
ASSERT(all_references_[all_index]->IsCode());
explorer->TagCodeObject(Code::cast(all_references_[all_index]),
builtins->name(builtin_index++));
}
++all_index;
if (reference_tags_[tags_index].index == all_index) ++tags_index;
}
}
......@@ -1746,6 +1788,7 @@ class RootsReferencesExtractor : public ObjectVisitor {
List<Object*> all_references_;
int previous_reference_count_;
List<IndexTag> reference_tags_;
Heap* heap_;
};
......@@ -1771,7 +1814,7 @@ bool V8HeapExplorer::IterateAndExtractReferences(
}
SetRootGcRootsReference();
RootsReferencesExtractor extractor;
RootsReferencesExtractor extractor(heap_);
heap_->IterateRoots(&extractor, VISIT_ONLY_STRONG);
extractor.SetCollectingAllReferences();
heap_->IterateRoots(&extractor, VISIT_ALL);
......
......@@ -447,6 +447,8 @@ class V8HeapExplorer : public HeapEntriesAllocator {
int EstimateObjectsCount(HeapIterator* iterator);
bool IterateAndExtractReferences(SnapshotFillerInterface* filler);
void TagGlobalObjects();
void TagCodeObject(Code* code);
void TagCodeObject(Code* code, const char* external_name);
static String* GetConstructorName(JSObject* object);
......
......@@ -2177,3 +2177,56 @@ TEST(TrackHeapAllocations) {
CHECK_GE(node->allocation_size(), 4 * node->allocation_count());
heap_profiler->StopRecordingHeapAllocations();
}
static const v8::HeapGraphNode* GetNodeByPath(const v8::HeapSnapshot* snapshot,
const char* path[],
int depth) {
const v8::HeapGraphNode* node = snapshot->GetRoot();
for (int current_depth = 0; current_depth < depth; ++current_depth) {
int i, count = node->GetChildrenCount();
for (i = 0; i < count; ++i) {
const v8::HeapGraphEdge* edge = node->GetChild(i);
const v8::HeapGraphNode* to_node = edge->GetToNode();
v8::String::Utf8Value edge_name(edge->GetName());
v8::String::Utf8Value node_name(to_node->GetName());
i::EmbeddedVector<char, 100> name;
i::OS::SNPrintF(name, "%s::%s", *edge_name, *node_name);
if (strstr(name.start(), path[current_depth])) {
node = to_node;
break;
}
}
if (i == count) return NULL;
}
return node;
}
TEST(CheckCodeNames) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
CompileRun("var a = 1.1;");
const v8::HeapSnapshot* snapshot =
heap_profiler->TakeHeapSnapshot(v8_str("CheckCodeNames"));
CHECK(ValidateSnapshot(snapshot));
const char* stub_path[] = {
"::(GC roots)",
"::(Strong roots)",
"code_stubs::",
"::(ArraySingleArgumentConstructorStub code)"
};
const v8::HeapGraphNode* node = GetNodeByPath(snapshot,
stub_path, ARRAY_SIZE(stub_path));
CHECK_NE(NULL, node);
const char* builtin_path[] = {
"::(GC roots)",
"::(Builtins)",
"::(KeyedLoadIC_Generic code)"
};
node = GetNodeByPath(snapshot, builtin_path, ARRAY_SIZE(builtin_path));
CHECK_NE(NULL, node);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment