summaryrefslogtreecommitdiff
path: root/deps/v8/test/cctest/test-heap-profiler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/test/cctest/test-heap-profiler.cc')
-rw-r--r--deps/v8/test/cctest/test-heap-profiler.cc310
1 files changed, 284 insertions, 26 deletions
diff --git a/deps/v8/test/cctest/test-heap-profiler.cc b/deps/v8/test/cctest/test-heap-profiler.cc
index d9f919fbee..2e755dc32c 100644
--- a/deps/v8/test/cctest/test-heap-profiler.cc
+++ b/deps/v8/test/cctest/test-heap-profiler.cc
@@ -98,7 +98,6 @@ class NamedEntriesDetector {
static const v8::HeapGraphNode* GetGlobalObject(
const v8::HeapSnapshot* snapshot) {
- CHECK_EQ(2, snapshot->GetRoot()->GetChildrenCount());
// The 0th-child is (GC Roots), 1st is the user root.
const v8::HeapGraphNode* global_obj =
snapshot->GetRoot()->GetChild(1)->GetToNode();
@@ -107,6 +106,32 @@ static const v8::HeapGraphNode* GetGlobalObject(
return global_obj;
}
+static const char* GetName(const v8::HeapGraphNode* node) {
+ return const_cast<i::HeapEntry*>(reinterpret_cast<const i::HeapEntry*>(node))
+ ->name();
+}
+
+static size_t GetSize(const v8::HeapGraphNode* node) {
+ return const_cast<i::HeapEntry*>(reinterpret_cast<const i::HeapEntry*>(node))
+ ->self_size();
+}
+
+static const v8::HeapGraphNode* GetChildByName(const v8::HeapGraphNode* node,
+ const char* name) {
+ for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
+ const v8::HeapGraphNode* child = node->GetChild(i)->GetToNode();
+ if (!strcmp(name, GetName(child))) {
+ return child;
+ }
+ }
+ return nullptr;
+}
+
+static const v8::HeapGraphNode* GetRootChild(const v8::HeapSnapshot* snapshot,
+ const char* name) {
+ return GetChildByName(snapshot->GetRoot(), name);
+}
+
static const v8::HeapGraphNode* GetProperty(v8::Isolate* isolate,
const v8::HeapGraphNode* node,
v8::HeapGraphEdge::Type type,
@@ -173,6 +198,11 @@ static bool ValidateSnapshot(const v8::HeapSnapshot* snapshot, int depth = 3) {
return unretained_entries_count == 0;
}
+bool EndsWith(const char* a, const char* b) {
+ size_t length_a = strlen(a);
+ size_t length_b = strlen(b);
+ return (length_a >= length_b) && !strcmp(a + length_a - length_b, b);
+}
TEST(HeapSnapshot) {
LocalContext env2;
@@ -694,6 +724,38 @@ TEST(HeapSnapshotInternalReferences) {
v8::HeapGraphEdge::kInternal, "1"));
}
+TEST(HeapSnapshotEphemeron) {
+ LocalContext env;
+ v8::HandleScope scope(env->GetIsolate());
+ v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
+
+ CompileRun(
+ "class KeyClass{};\n"
+ "class ValueClass{};\n"
+ "var wm = new WeakMap();\n"
+ "function foo(key) { wm.set(key, new ValueClass()); }\n"
+ "var key = new KeyClass();\n"
+ "foo(key);");
+ const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
+ CHECK(ValidateSnapshot(snapshot));
+ const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+
+ const v8::HeapGraphNode* key = GetProperty(
+ env->GetIsolate(), global, v8::HeapGraphEdge::kProperty, "key");
+ CHECK(key);
+ bool success = false;
+ for (int i = 0, count = key->GetChildrenCount(); i < count; ++i) {
+ const v8::HeapGraphEdge* edge = key->GetChild(i);
+ const v8::HeapGraphNode* child = edge->GetToNode();
+ if (!strcmp("ValueClass", GetName(child))) {
+ v8::String::Utf8Value edge_name(CcTest::isolate(), edge->GetName());
+ CHECK(EndsWith(*edge_name, " / WeakMap"));
+ success = true;
+ break;
+ }
+ }
+ CHECK(success);
+}
TEST(HeapSnapshotAddressReuse) {
LocalContext env;
@@ -2256,14 +2318,12 @@ TEST(AllocationSitesAreVisible) {
const v8::HeapGraphNode* fun_code = GetProperty(
env->GetIsolate(), global, v8::HeapGraphEdge::kProperty, "fun");
CHECK(fun_code);
- const v8::HeapGraphNode* vector_cell =
+ const v8::HeapGraphNode* feedback_cell =
GetProperty(env->GetIsolate(), fun_code, v8::HeapGraphEdge::kInternal,
- "feedback_vector_cell");
- // TODO(mvstanton): I'm not sure if this is the best way to expose
- // literals. Is it too much to expose the Cell?
- CHECK(vector_cell);
+ "feedback_cell");
+ CHECK(feedback_cell);
const v8::HeapGraphNode* vector = GetProperty(
- env->GetIsolate(), vector_cell, v8::HeapGraphEdge::kInternal, "value");
+ env->GetIsolate(), feedback_cell, v8::HeapGraphEdge::kInternal, "value");
CHECK_EQ(v8::HeapGraphNode::kArray, vector->GetType());
CHECK_EQ(3, vector->GetChildrenCount());
@@ -2769,21 +2829,17 @@ TEST(JSPromise) {
const v8::HeapGraphNode* resolved = GetProperty(
env->GetIsolate(), global, v8::HeapGraphEdge::kProperty, "resolved");
CHECK(GetProperty(env->GetIsolate(), resolved, v8::HeapGraphEdge::kInternal,
- "result"));
+ "reactions_or_result"));
const v8::HeapGraphNode* rejected = GetProperty(
env->GetIsolate(), global, v8::HeapGraphEdge::kProperty, "rejected");
CHECK(GetProperty(env->GetIsolate(), rejected, v8::HeapGraphEdge::kInternal,
- "result"));
+ "reactions_or_result"));
const v8::HeapGraphNode* pending = GetProperty(
env->GetIsolate(), global, v8::HeapGraphEdge::kProperty, "pending");
CHECK(GetProperty(env->GetIsolate(), pending, v8::HeapGraphEdge::kInternal,
- "deferred_promise"));
- CHECK(GetProperty(env->GetIsolate(), pending, v8::HeapGraphEdge::kInternal,
- "fulfill_reactions"));
- CHECK(GetProperty(env->GetIsolate(), pending, v8::HeapGraphEdge::kInternal,
- "reject_reactions"));
+ "reactions_or_result"));
const char* objectNames[] = {"resolved", "rejected", "pending", "chained"};
for (auto objectName : objectNames) {
@@ -2793,11 +2849,213 @@ TEST(JSPromise) {
}
}
+class EmbedderNode : public v8::EmbedderGraph::Node {
+ public:
+ EmbedderNode(const char* name, size_t size,
+ v8::EmbedderGraph::Node* wrapper_node = nullptr)
+ : name_(name), size_(size), wrapper_node_(wrapper_node) {}
+
+ // Graph::Node overrides.
+ const char* Name() override { return name_; }
+ size_t SizeInBytes() override { return size_; }
+ Node* WrapperNode() override { return wrapper_node_; }
+
+ private:
+ const char* name_;
+ size_t size_;
+ Node* wrapper_node_;
+};
+
+class EmbedderRootNode : public EmbedderNode {
+ public:
+ explicit EmbedderRootNode(const char* name) : EmbedderNode(name, 0) {}
+ // Graph::Node override.
+ bool IsRootNode() { return true; }
+};
+
+// Used to pass the global object to the BuildEmbedderGraph callback.
+// Otherwise, the callback has to iterate the global handles to find the
+// global object.
+v8::Local<v8::Value>* global_object_pointer;
+
+void BuildEmbedderGraph(v8::Isolate* v8_isolate, v8::EmbedderGraph* graph) {
+ using Node = v8::EmbedderGraph::Node;
+ Node* global_node = graph->V8Node(*global_object_pointer);
+ Node* embedder_node_A = graph->AddNode(
+ std::unique_ptr<Node>(new EmbedderNode("EmbedderNodeA", 10)));
+ Node* embedder_node_B = graph->AddNode(
+ std::unique_ptr<Node>(new EmbedderNode("EmbedderNodeB", 20)));
+ Node* embedder_node_C = graph->AddNode(
+ std::unique_ptr<Node>(new EmbedderNode("EmbedderNodeC", 30)));
+ Node* embedder_root = graph->AddNode(
+ std::unique_ptr<Node>(new EmbedderRootNode("EmbedderRoot")));
+ graph->AddEdge(global_node, embedder_node_A);
+ graph->AddEdge(embedder_node_A, embedder_node_B);
+ graph->AddEdge(embedder_root, embedder_node_C);
+ graph->AddEdge(embedder_node_C, global_node);
+}
+
+void CheckEmbedderGraphSnapshot(v8::Isolate* isolate,
+ const v8::HeapSnapshot* snapshot) {
+ const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+ const v8::HeapGraphNode* embedder_node_A =
+ GetChildByName(global, "EmbedderNodeA");
+ CHECK_EQ(10, GetSize(embedder_node_A));
+ const v8::HeapGraphNode* embedder_node_B =
+ GetChildByName(embedder_node_A, "EmbedderNodeB");
+ CHECK_EQ(20, GetSize(embedder_node_B));
+ const v8::HeapGraphNode* embedder_root =
+ GetRootChild(snapshot, "EmbedderRoot");
+ CHECK(embedder_root);
+ const v8::HeapGraphNode* embedder_node_C =
+ GetChildByName(embedder_root, "EmbedderNodeC");
+ CHECK_EQ(30, GetSize(embedder_node_C));
+ const v8::HeapGraphNode* global_reference =
+ GetChildByName(embedder_node_C, "Object");
+ CHECK(global_reference);
+}
+
+TEST(EmbedderGraph) {
+ i::FLAG_heap_profiler_use_embedder_graph = true;
+ LocalContext env;
+ v8::HandleScope scope(env->GetIsolate());
+ i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate());
+ v8::Local<v8::Value> global_object =
+ v8::Utils::ToLocal(i::Handle<i::JSObject>(
+ (isolate->context()->native_context()->global_object())));
+ global_object_pointer = &global_object;
+ v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
+ heap_profiler->SetBuildEmbedderGraphCallback(BuildEmbedderGraph);
+ const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
+ CHECK(ValidateSnapshot(snapshot));
+ CheckEmbedderGraphSnapshot(env->GetIsolate(), snapshot);
+}
+
+TEST(StrongHandleAnnotation) {
+ LocalContext env;
+ v8::HandleScope scope(env->GetIsolate());
+ v8::Persistent<v8::Object> handle1, handle2;
+ handle1.Reset(env->GetIsolate(), v8::Object::New(env->GetIsolate()));
+ handle2.Reset(env->GetIsolate(), v8::Object::New(env->GetIsolate()));
+ handle1.AnnotateStrongRetainer("my_label");
+ handle2.AnnotateStrongRetainer("my_label");
+ v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
+ const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
+ const v8::HeapGraphNode* gc_roots = GetRootChild(snapshot, "(GC roots)");
+ CHECK(gc_roots);
+ const v8::HeapGraphNode* global_handles =
+ GetChildByName(gc_roots, "(Global handles)");
+ CHECK(global_handles);
+ int found = 0;
+ for (int i = 0, count = global_handles->GetChildrenCount(); i < count; ++i) {
+ const v8::HeapGraphEdge* edge = global_handles->GetChild(i);
+ v8::String::Utf8Value edge_name(CcTest::isolate(), edge->GetName());
+ if (EndsWith(*edge_name, "my_label")) ++found;
+ }
+ CHECK_EQ(2, found);
+}
+
+void BuildEmbedderGraphWithWrapperNode(v8::Isolate* v8_isolate,
+ v8::EmbedderGraph* graph) {
+ using Node = v8::EmbedderGraph::Node;
+ Node* global_node = graph->V8Node(*global_object_pointer);
+ Node* wrapper_node = graph->AddNode(
+ std::unique_ptr<Node>(new EmbedderNode("WrapperNode / TAG", 10)));
+ Node* embedder_node = graph->AddNode(std::unique_ptr<Node>(
+ new EmbedderNode("EmbedderNode", 10, wrapper_node)));
+ Node* other_node =
+ graph->AddNode(std::unique_ptr<Node>(new EmbedderNode("OtherNode", 20)));
+ graph->AddEdge(global_node, embedder_node);
+ graph->AddEdge(wrapper_node, other_node);
+
+ Node* wrapper_node2 = graph->AddNode(
+ std::unique_ptr<Node>(new EmbedderNode("WrapperNode2", 10)));
+ Node* embedder_node2 = graph->AddNode(std::unique_ptr<Node>(
+ new EmbedderNode("EmbedderNode2", 10, wrapper_node2)));
+ graph->AddEdge(global_node, embedder_node2);
+ graph->AddEdge(embedder_node2, wrapper_node2);
+ graph->AddEdge(wrapper_node2, other_node);
+}
+
+TEST(EmbedderGraphWithWrapperNode) {
+ i::FLAG_heap_profiler_use_embedder_graph = true;
+ LocalContext env;
+ v8::HandleScope scope(env->GetIsolate());
+ i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate());
+ v8::Local<v8::Value> global_object =
+ v8::Utils::ToLocal(i::Handle<i::JSObject>(
+ (isolate->context()->native_context()->global_object())));
+ global_object_pointer = &global_object;
+ v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
+ heap_profiler->SetBuildEmbedderGraphCallback(
+ BuildEmbedderGraphWithWrapperNode);
+ const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
+ CHECK(ValidateSnapshot(snapshot));
+ const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+ const v8::HeapGraphNode* embedder_node =
+ GetChildByName(global, "EmbedderNode / TAG");
+ const v8::HeapGraphNode* other_node =
+ GetChildByName(embedder_node, "OtherNode");
+ CHECK(other_node);
+ const v8::HeapGraphNode* wrapper_node =
+ GetChildByName(embedder_node, "WrapperNode / TAG");
+ CHECK(!wrapper_node);
+
+ const v8::HeapGraphNode* embedder_node2 =
+ GetChildByName(global, "EmbedderNode2");
+ other_node = GetChildByName(embedder_node2, "OtherNode");
+ CHECK(other_node);
+ const v8::HeapGraphNode* wrapper_node2 =
+ GetChildByName(embedder_node, "WrapperNode2");
+ CHECK(!wrapper_node2);
+}
+
+class EmbedderNodeWithPrefix : public v8::EmbedderGraph::Node {
+ public:
+ EmbedderNodeWithPrefix(const char* prefix, const char* name)
+ : prefix_(prefix), name_(name) {}
+
+ // Graph::Node overrides.
+ const char* Name() override { return name_; }
+ size_t SizeInBytes() override { return 0; }
+ const char* NamePrefix() override { return prefix_; }
+
+ private:
+ const char* prefix_;
+ const char* name_;
+};
+
+void BuildEmbedderGraphWithPrefix(v8::Isolate* v8_isolate,
+ v8::EmbedderGraph* graph) {
+ using Node = v8::EmbedderGraph::Node;
+ Node* global_node = graph->V8Node(*global_object_pointer);
+ Node* node = graph->AddNode(
+ std::unique_ptr<Node>(new EmbedderNodeWithPrefix("Detached", "Node")));
+ graph->AddEdge(global_node, node);
+}
+
+TEST(EmbedderGraphWithPrefix) {
+ i::FLAG_heap_profiler_use_embedder_graph = true;
+ LocalContext env;
+ v8::HandleScope scope(env->GetIsolate());
+ i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate());
+ v8::Local<v8::Value> global_object =
+ v8::Utils::ToLocal(i::Handle<i::JSObject>(
+ (isolate->context()->native_context()->global_object())));
+ global_object_pointer = &global_object;
+ v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
+ heap_profiler->SetBuildEmbedderGraphCallback(BuildEmbedderGraphWithPrefix);
+ const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
+ CHECK(ValidateSnapshot(snapshot));
+ const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+ const v8::HeapGraphNode* node = GetChildByName(global, "Detached Node");
+ CHECK(node);
+}
+
static inline i::Address ToAddress(int n) {
return reinterpret_cast<i::Address>(n);
}
-
TEST(AddressToTraceMap) {
i::AddressToTraceMap map;
@@ -3161,6 +3419,17 @@ TEST(SamplingHeapProfilerLargeInterval) {
heap_profiler->StopSamplingHeapProfiler();
}
+TEST(HeapSnapshotPrototypeNotJSReceiver) {
+ LocalContext env;
+ v8::HandleScope scope(env->GetIsolate());
+ v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
+ CompileRun(
+ "function object() {}"
+ "object.prototype = 42;");
+ const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
+ CHECK(ValidateSnapshot(snapshot));
+}
+
TEST(SamplingHeapProfilerSampleDuringDeopt) {
i::FLAG_allow_natives_syntax = true;
@@ -3206,14 +3475,3 @@ TEST(SamplingHeapProfilerSampleDuringDeopt) {
CHECK(profile);
heap_profiler->StopSamplingHeapProfiler();
}
-
-TEST(HeapSnapshotPrototypeNotJSReceiver) {
- LocalContext env;
- v8::HandleScope scope(env->GetIsolate());
- v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
- CompileRun(
- "function object() {}"
- "object.prototype = 42;");
- const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
- CHECK(ValidateSnapshot(snapshot));
-}