| OLD | NEW |
| 1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
| 2 // | 2 // |
| 3 // Tests for heap profiler | 3 // Tests for heap profiler |
| 4 | 4 |
| 5 #ifdef ENABLE_LOGGING_AND_PROFILING | 5 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 6 | 6 |
| 7 #include "v8.h" | 7 #include "v8.h" |
| 8 #include "heap-profiler.h" | 8 #include "heap-profiler.h" |
| 9 #include "snapshot.h" | 9 #include "snapshot.h" |
| 10 #include "string-stream.h" | 10 #include "string-stream.h" |
| (...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 404 bool has_A2; | 404 bool has_A2; |
| 405 bool has_B2; | 405 bool has_B2; |
| 406 bool has_C2; | 406 bool has_C2; |
| 407 }; | 407 }; |
| 408 | 408 |
| 409 } // namespace | 409 } // namespace |
| 410 | 410 |
| 411 | 411 |
| 412 static const v8::HeapGraphNode* GetGlobalObject( | 412 static const v8::HeapGraphNode* GetGlobalObject( |
| 413 const v8::HeapSnapshot* snapshot) { | 413 const v8::HeapSnapshot* snapshot) { |
| 414 CHECK_EQ(1, snapshot->GetRoot()->GetChildrenCount()); | 414 CHECK_EQ(2, snapshot->GetRoot()->GetChildrenCount()); |
| 415 return snapshot->GetRoot()->GetChild(0)->GetToNode(); | 415 const v8::HeapGraphNode* global_obj = |
| 416 snapshot->GetRoot()->GetChild(0)->GetToNode(); |
| 417 CHECK_EQ("Object", const_cast<i::HeapEntry*>( |
| 418 reinterpret_cast<const i::HeapEntry*>(global_obj))->name()); |
| 419 return global_obj; |
| 416 } | 420 } |
| 417 | 421 |
| 418 | 422 |
| 419 static const v8::HeapGraphNode* GetProperty(const v8::HeapGraphNode* node, | 423 static const v8::HeapGraphNode* GetProperty(const v8::HeapGraphNode* node, |
| 420 v8::HeapGraphEdge::Type type, | 424 v8::HeapGraphEdge::Type type, |
| 421 const char* name) { | 425 const char* name) { |
| 422 for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) { | 426 for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) { |
| 423 const v8::HeapGraphEdge* prop = node->GetChild(i); | 427 const v8::HeapGraphEdge* prop = node->GetChild(i); |
| 424 v8::String::AsciiValue prop_name(prop->GetName()); | 428 v8::String::AsciiValue prop_name(prop->GetName()); |
| 425 if (prop->GetType() == type && strcmp(name, *prop_name) == 0) | 429 if (prop->GetType() == type && strcmp(name, *prop_name) == 0) |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 472 const_cast<i::HeapSnapshot*>( | 476 const_cast<i::HeapSnapshot*>( |
| 473 reinterpret_cast<const i::HeapSnapshot*>(snapshot_env2)); | 477 reinterpret_cast<const i::HeapSnapshot*>(snapshot_env2)); |
| 474 const v8::HeapGraphNode* global_env2 = GetGlobalObject(snapshot_env2); | 478 const v8::HeapGraphNode* global_env2 = GetGlobalObject(snapshot_env2); |
| 475 // Paint all nodes reachable from global object. | 479 // Paint all nodes reachable from global object. |
| 476 i_snapshot_env2->ClearPaint(); | 480 i_snapshot_env2->ClearPaint(); |
| 477 const_cast<i::HeapEntry*>( | 481 const_cast<i::HeapEntry*>( |
| 478 reinterpret_cast<const i::HeapEntry*>(global_env2))->PaintAllReachable(); | 482 reinterpret_cast<const i::HeapEntry*>(global_env2))->PaintAllReachable(); |
| 479 | 483 |
| 480 // Verify, that JS global object of env2 has '..2' properties. | 484 // Verify, that JS global object of env2 has '..2' properties. |
| 481 const v8::HeapGraphNode* a2_node = | 485 const v8::HeapGraphNode* a2_node = |
| 482 GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "a2"); | 486 GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "a2"); |
| 483 CHECK_NE(NULL, a2_node); | 487 CHECK_NE(NULL, a2_node); |
| 484 CHECK_NE( | 488 CHECK_NE( |
| 485 NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b2_1")); | 489 NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_1")); |
| 486 CHECK_NE( | 490 CHECK_NE( |
| 487 NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b2_2")); | 491 NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_2")); |
| 488 CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "c2")); | 492 CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "c2")); |
| 489 | 493 |
| 490 // Verify that anything related to '[ABC]1' is not reachable. | |
| 491 NamedEntriesDetector det; | 494 NamedEntriesDetector det; |
| 492 i_snapshot_env2->IterateEntries(&det); | 495 i_snapshot_env2->IterateEntries(&det); |
| 493 CHECK(det.has_A2); | 496 CHECK(det.has_A2); |
| 494 CHECK(det.has_B2); | 497 CHECK(det.has_B2); |
| 495 CHECK(det.has_C2); | 498 CHECK(det.has_C2); |
| 496 | 499 |
| 500 /* |
| 501 // Currently disabled. Too many retaining paths emerge, need to |
| 502 // reduce the amount. |
| 503 |
| 497 // Verify 'a2' object retainers. They are: | 504 // Verify 'a2' object retainers. They are: |
| 498 // - (global object).a2 | 505 // - (global object).a2 |
| 499 // - c2.x1, c2.x2, c2[1] | 506 // - c2.x1, c2.x2, c2[1] |
| 500 // - b2_1 and b2_2 closures: via 'x' variable | 507 // - b2_1 and b2_2 closures: via 'x' variable |
| 501 CHECK_EQ(6, a2_node->GetRetainingPathsCount()); | 508 CHECK_EQ(6, a2_node->GetRetainingPathsCount()); |
| 502 bool has_global_obj_a2_ref = false; | 509 bool has_global_obj_a2_ref = false; |
| 503 bool has_c2_x1_ref = false, has_c2_x2_ref = false, has_c2_1_ref = false; | 510 bool has_c2_x1_ref = false, has_c2_x2_ref = false, has_c2_1_ref = false; |
| 504 bool has_b2_1_x_ref = false, has_b2_2_x_ref = false; | 511 bool has_b2_1_x_ref = false, has_b2_2_x_ref = false; |
| 505 for (int i = 0; i < a2_node->GetRetainingPathsCount(); ++i) { | 512 for (int i = 0; i < a2_node->GetRetainingPathsCount(); ++i) { |
| 506 const v8::HeapGraphPath* path = a2_node->GetRetainingPath(i); | 513 const v8::HeapGraphPath* path = a2_node->GetRetainingPath(i); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 531 if (strcmp("x", *last_edge_name) == 0 | 538 if (strcmp("x", *last_edge_name) == 0 |
| 532 && last_edge->GetType() == v8::HeapGraphEdge::kContextVariable | 539 && last_edge->GetType() == v8::HeapGraphEdge::kContextVariable |
| 533 && strcmp("b2_2", *prev_edge_name) == 0) has_b2_2_x_ref = true; | 540 && strcmp("b2_2", *prev_edge_name) == 0) has_b2_2_x_ref = true; |
| 534 } | 541 } |
| 535 CHECK(has_global_obj_a2_ref); | 542 CHECK(has_global_obj_a2_ref); |
| 536 CHECK(has_c2_x1_ref); | 543 CHECK(has_c2_x1_ref); |
| 537 CHECK(has_c2_x2_ref); | 544 CHECK(has_c2_x2_ref); |
| 538 CHECK(has_c2_1_ref); | 545 CHECK(has_c2_1_ref); |
| 539 CHECK(has_b2_1_x_ref); | 546 CHECK(has_b2_1_x_ref); |
| 540 CHECK(has_b2_2_x_ref); | 547 CHECK(has_b2_2_x_ref); |
| 548 */ |
| 541 } | 549 } |
| 542 | 550 |
| 543 | 551 |
| 544 TEST(HeapSnapshotObjectSizes) { | 552 TEST(HeapSnapshotObjectSizes) { |
| 545 v8::HandleScope scope; | 553 v8::HandleScope scope; |
| 546 LocalContext env; | 554 LocalContext env; |
| 547 | 555 |
| 548 // -a-> X1 --a | 556 // -a-> X1 --a |
| 549 // x -b-> X2 <-| | 557 // x -b-> X2 <-| |
| 550 CompileRun( | 558 CompileRun( |
| 551 "function X(a, b) { this.a = a; this.b = b; }\n" | 559 "function X(a, b) { this.a = a; this.b = b; }\n" |
| 552 "x = new X(new X(), new X());\n" | 560 "x = new X(new X(), new X());\n" |
| 553 "x.a.a = x.b;"); | 561 "(function() { x.a.a = x.b; })();"); |
| 554 const v8::HeapSnapshot* snapshot = | 562 const v8::HeapSnapshot* snapshot = |
| 555 v8::HeapProfiler::TakeSnapshot(v8::String::New("sizes")); | 563 v8::HeapProfiler::TakeSnapshot(v8::String::New("sizes")); |
| 556 const v8::HeapGraphNode* global = GetGlobalObject(snapshot); | 564 const v8::HeapGraphNode* global = GetGlobalObject(snapshot); |
| 557 const v8::HeapGraphNode* x = | 565 const v8::HeapGraphNode* x = |
| 558 GetProperty(global, v8::HeapGraphEdge::kProperty, "x"); | 566 GetProperty(global, v8::HeapGraphEdge::kShortcut, "x"); |
| 559 CHECK_NE(NULL, x); | 567 CHECK_NE(NULL, x); |
| 560 const v8::HeapGraphNode* x_prototype = | 568 const v8::HeapGraphNode* x_prototype = |
| 561 GetProperty(x, v8::HeapGraphEdge::kProperty, "__proto__"); | 569 GetProperty(x, v8::HeapGraphEdge::kProperty, "__proto__"); |
| 562 CHECK_NE(NULL, x_prototype); | 570 CHECK_NE(NULL, x_prototype); |
| 563 const v8::HeapGraphNode* x1 = | 571 const v8::HeapGraphNode* x1 = |
| 564 GetProperty(x, v8::HeapGraphEdge::kProperty, "a"); | 572 GetProperty(x, v8::HeapGraphEdge::kProperty, "a"); |
| 565 CHECK_NE(NULL, x1); | 573 CHECK_NE(NULL, x1); |
| 566 const v8::HeapGraphNode* x2 = | 574 const v8::HeapGraphNode* x2 = |
| 567 GetProperty(x, v8::HeapGraphEdge::kProperty, "b"); | 575 GetProperty(x, v8::HeapGraphEdge::kProperty, "b"); |
| 568 CHECK_NE(NULL, x2); | 576 CHECK_NE(NULL, x2); |
| 569 CHECK_EQ( | 577 CHECK_EQ(x->GetSelfSize() * 3, x->GetRetainedSize()); |
| 570 x->GetSelfSize() * 3, | 578 CHECK_EQ(x1->GetSelfSize(), x1->GetRetainedSize()); |
| 571 x->GetReachableSize() - x_prototype->GetReachableSize()); | 579 CHECK_EQ(x2->GetSelfSize(), x2->GetRetainedSize()); |
| 572 CHECK_EQ( | |
| 573 x->GetSelfSize() * 3, x->GetRetainedSize()); | |
| 574 CHECK_EQ( | |
| 575 x1->GetSelfSize() * 2, | |
| 576 x1->GetReachableSize() - x_prototype->GetReachableSize()); | |
| 577 CHECK_EQ( | |
| 578 x1->GetSelfSize(), x1->GetRetainedSize()); | |
| 579 CHECK_EQ( | |
| 580 x2->GetSelfSize(), | |
| 581 x2->GetReachableSize() - x_prototype->GetReachableSize()); | |
| 582 CHECK_EQ( | |
| 583 x2->GetSelfSize(), x2->GetRetainedSize()); | |
| 584 } | 580 } |
| 585 | 581 |
| 586 | 582 |
| 587 TEST(HeapSnapshotEntryChildren) { | 583 TEST(HeapSnapshotEntryChildren) { |
| 588 v8::HandleScope scope; | 584 v8::HandleScope scope; |
| 589 LocalContext env; | 585 LocalContext env; |
| 590 | 586 |
| 591 CompileRun( | 587 CompileRun( |
| 592 "function A() { }\n" | 588 "function A() { }\n" |
| 593 "a = new A;"); | 589 "a = new A;"); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 615 CompileRun( | 611 CompileRun( |
| 616 "function lazy(x) { return x - 1; }\n" | 612 "function lazy(x) { return x - 1; }\n" |
| 617 "function compiled(x) { return x + 1; }\n" | 613 "function compiled(x) { return x + 1; }\n" |
| 618 "var anonymous = (function() { return function() { return 0; } })();\n" | 614 "var anonymous = (function() { return function() { return 0; } })();\n" |
| 619 "compiled(1)"); | 615 "compiled(1)"); |
| 620 const v8::HeapSnapshot* snapshot = | 616 const v8::HeapSnapshot* snapshot = |
| 621 v8::HeapProfiler::TakeSnapshot(v8::String::New("code")); | 617 v8::HeapProfiler::TakeSnapshot(v8::String::New("code")); |
| 622 | 618 |
| 623 const v8::HeapGraphNode* global = GetGlobalObject(snapshot); | 619 const v8::HeapGraphNode* global = GetGlobalObject(snapshot); |
| 624 const v8::HeapGraphNode* compiled = | 620 const v8::HeapGraphNode* compiled = |
| 625 GetProperty(global, v8::HeapGraphEdge::kProperty, "compiled"); | 621 GetProperty(global, v8::HeapGraphEdge::kShortcut, "compiled"); |
| 626 CHECK_NE(NULL, compiled); | 622 CHECK_NE(NULL, compiled); |
| 627 CHECK_EQ(v8::HeapGraphNode::kClosure, compiled->GetType()); | 623 CHECK_EQ(v8::HeapGraphNode::kClosure, compiled->GetType()); |
| 628 const v8::HeapGraphNode* lazy = | 624 const v8::HeapGraphNode* lazy = |
| 629 GetProperty(global, v8::HeapGraphEdge::kProperty, "lazy"); | 625 GetProperty(global, v8::HeapGraphEdge::kShortcut, "lazy"); |
| 630 CHECK_NE(NULL, lazy); | 626 CHECK_NE(NULL, lazy); |
| 631 CHECK_EQ(v8::HeapGraphNode::kClosure, lazy->GetType()); | 627 CHECK_EQ(v8::HeapGraphNode::kClosure, lazy->GetType()); |
| 632 const v8::HeapGraphNode* anonymous = | 628 const v8::HeapGraphNode* anonymous = |
| 633 GetProperty(global, v8::HeapGraphEdge::kProperty, "anonymous"); | 629 GetProperty(global, v8::HeapGraphEdge::kShortcut, "anonymous"); |
| 634 CHECK_NE(NULL, anonymous); | 630 CHECK_NE(NULL, anonymous); |
| 635 CHECK_EQ(v8::HeapGraphNode::kClosure, anonymous->GetType()); | 631 CHECK_EQ(v8::HeapGraphNode::kClosure, anonymous->GetType()); |
| 636 v8::String::AsciiValue anonymous_name(anonymous->GetName()); | 632 v8::String::AsciiValue anonymous_name(anonymous->GetName()); |
| 637 CHECK_EQ("", *anonymous_name); | 633 CHECK_EQ("", *anonymous_name); |
| 638 | 634 |
| 639 // Find references to code. | 635 // Find references to code. |
| 640 const v8::HeapGraphNode* compiled_code = | 636 const v8::HeapGraphNode* compiled_code = |
| 641 GetProperty(compiled, v8::HeapGraphEdge::kInternal, "code"); | 637 GetProperty(compiled, v8::HeapGraphEdge::kInternal, "code"); |
| 642 CHECK_NE(NULL, compiled_code); | 638 CHECK_NE(NULL, compiled_code); |
| 643 const v8::HeapGraphNode* lazy_code = | 639 const v8::HeapGraphNode* lazy_code = |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 675 | 671 |
| 676 TEST(HeapSnapshotHeapNumbers) { | 672 TEST(HeapSnapshotHeapNumbers) { |
| 677 v8::HandleScope scope; | 673 v8::HandleScope scope; |
| 678 LocalContext env; | 674 LocalContext env; |
| 679 CompileRun( | 675 CompileRun( |
| 680 "a = 1; // a is Smi\n" | 676 "a = 1; // a is Smi\n" |
| 681 "b = 2.5; // b is HeapNumber"); | 677 "b = 2.5; // b is HeapNumber"); |
| 682 const v8::HeapSnapshot* snapshot = | 678 const v8::HeapSnapshot* snapshot = |
| 683 v8::HeapProfiler::TakeSnapshot(v8::String::New("numbers")); | 679 v8::HeapProfiler::TakeSnapshot(v8::String::New("numbers")); |
| 684 const v8::HeapGraphNode* global = GetGlobalObject(snapshot); | 680 const v8::HeapGraphNode* global = GetGlobalObject(snapshot); |
| 685 CHECK_EQ(NULL, GetProperty(global, v8::HeapGraphEdge::kProperty, "a")); | 681 CHECK_EQ(NULL, GetProperty(global, v8::HeapGraphEdge::kShortcut, "a")); |
| 686 const v8::HeapGraphNode* b = | 682 const v8::HeapGraphNode* b = |
| 687 GetProperty(global, v8::HeapGraphEdge::kProperty, "b"); | 683 GetProperty(global, v8::HeapGraphEdge::kShortcut, "b"); |
| 688 CHECK_NE(NULL, b); | 684 CHECK_NE(NULL, b); |
| 689 CHECK_EQ(v8::HeapGraphNode::kHeapNumber, b->GetType()); | 685 CHECK_EQ(v8::HeapGraphNode::kHeapNumber, b->GetType()); |
| 690 } | 686 } |
| 691 | 687 |
| 692 | 688 |
| 693 TEST(HeapSnapshotInternalReferences) { | 689 TEST(HeapSnapshotInternalReferences) { |
| 694 v8::HandleScope scope; | 690 v8::HandleScope scope; |
| 695 v8::Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); | 691 v8::Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); |
| 696 global_template->SetInternalFieldCount(2); | 692 global_template->SetInternalFieldCount(2); |
| 697 LocalContext env(NULL, global_template); | 693 LocalContext env(NULL, global_template); |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 801 // Verify additions: ensure that addition of A and B was detected. | 797 // Verify additions: ensure that addition of A and B was detected. |
| 802 const v8::HeapGraphNode* additions_root = diff->GetAdditionsRoot(); | 798 const v8::HeapGraphNode* additions_root = diff->GetAdditionsRoot(); |
| 803 bool found_A = false, found_B = false; | 799 bool found_A = false, found_B = false; |
| 804 uint64_t s1_A_id = 0; | 800 uint64_t s1_A_id = 0; |
| 805 for (int i = 0, count = additions_root->GetChildrenCount(); i < count; ++i) { | 801 for (int i = 0, count = additions_root->GetChildrenCount(); i < count; ++i) { |
| 806 const v8::HeapGraphEdge* prop = additions_root->GetChild(i); | 802 const v8::HeapGraphEdge* prop = additions_root->GetChild(i); |
| 807 const v8::HeapGraphNode* node = prop->GetToNode(); | 803 const v8::HeapGraphNode* node = prop->GetToNode(); |
| 808 if (node->GetType() == v8::HeapGraphNode::kObject) { | 804 if (node->GetType() == v8::HeapGraphNode::kObject) { |
| 809 v8::String::AsciiValue node_name(node->GetName()); | 805 v8::String::AsciiValue node_name(node->GetName()); |
| 810 if (strcmp(*node_name, "A2") == 0) { | 806 if (strcmp(*node_name, "A2") == 0) { |
| 811 CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::kProperty, "a")); | 807 CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::kShortcut, "a")); |
| 812 CHECK(!found_A); | 808 CHECK(!found_A); |
| 813 found_A = true; | 809 found_A = true; |
| 814 s1_A_id = node->GetId(); | 810 s1_A_id = node->GetId(); |
| 815 } else if (strcmp(*node_name, "B") == 0) { | 811 } else if (strcmp(*node_name, "B") == 0) { |
| 816 CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::kProperty, "b2")); | 812 CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::kShortcut, "b2")); |
| 817 CHECK(!found_B); | 813 CHECK(!found_B); |
| 818 found_B = true; | 814 found_B = true; |
| 819 } | 815 } |
| 820 } | 816 } |
| 821 } | 817 } |
| 822 CHECK(found_A); | 818 CHECK(found_A); |
| 823 CHECK(found_B); | 819 CHECK(found_B); |
| 824 | 820 |
| 825 // Verify deletions: ensure that deletion of A was detected. | 821 // Verify deletions: ensure that deletion of A was detected. |
| 826 const v8::HeapGraphNode* deletions_root = diff->GetDeletionsRoot(); | 822 const v8::HeapGraphNode* deletions_root = diff->GetDeletionsRoot(); |
| 827 bool found_A_del = false; | 823 bool found_A_del = false; |
| 828 uint64_t s2_A_id = 0; | 824 uint64_t s2_A_id = 0; |
| 829 for (int i = 0, count = deletions_root->GetChildrenCount(); i < count; ++i) { | 825 for (int i = 0, count = deletions_root->GetChildrenCount(); i < count; ++i) { |
| 830 const v8::HeapGraphEdge* prop = deletions_root->GetChild(i); | 826 const v8::HeapGraphEdge* prop = deletions_root->GetChild(i); |
| 831 const v8::HeapGraphNode* node = prop->GetToNode(); | 827 const v8::HeapGraphNode* node = prop->GetToNode(); |
| 832 if (node->GetType() == v8::HeapGraphNode::kObject) { | 828 if (node->GetType() == v8::HeapGraphNode::kObject) { |
| 833 v8::String::AsciiValue node_name(node->GetName()); | 829 v8::String::AsciiValue node_name(node->GetName()); |
| 834 if (strcmp(*node_name, "A") == 0) { | 830 if (strcmp(*node_name, "A") == 0) { |
| 835 CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::kProperty, "a")); | 831 CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::kShortcut, "a")); |
| 836 CHECK(!found_A_del); | 832 CHECK(!found_A_del); |
| 837 found_A_del = true; | 833 found_A_del = true; |
| 838 s2_A_id = node->GetId(); | 834 s2_A_id = node->GetId(); |
| 839 } | 835 } |
| 840 } | 836 } |
| 841 } | 837 } |
| 842 CHECK(found_A_del); | 838 CHECK(found_A_del); |
| 843 CHECK_NE_UINT64_T(0, s1_A_id); | 839 CHECK_NE_UINT64_T(0, s1_A_id); |
| 844 CHECK(s1_A_id != s2_A_id); | 840 CHECK(s1_A_id != s2_A_id); |
| 845 } | 841 } |
| 846 | 842 |
| 847 | 843 |
| 848 TEST(HeapSnapshotRootPreservedAfterSorting) { | 844 TEST(HeapSnapshotRootPreservedAfterSorting) { |
| 849 v8::HandleScope scope; | 845 v8::HandleScope scope; |
| 850 LocalContext env; | 846 LocalContext env; |
| 851 const v8::HeapSnapshot* snapshot = | 847 const v8::HeapSnapshot* snapshot = |
| 852 v8::HeapProfiler::TakeSnapshot(v8::String::New("s")); | 848 v8::HeapProfiler::TakeSnapshot(v8::String::New("s")); |
| 853 const v8::HeapGraphNode* root1 = snapshot->GetRoot(); | 849 const v8::HeapGraphNode* root1 = snapshot->GetRoot(); |
| 854 const_cast<i::HeapSnapshot*>(reinterpret_cast<const i::HeapSnapshot*>( | 850 const_cast<i::HeapSnapshot*>(reinterpret_cast<const i::HeapSnapshot*>( |
| 855 snapshot))->GetSortedEntriesList(); | 851 snapshot))->GetSortedEntriesList(); |
| 856 const v8::HeapGraphNode* root2 = snapshot->GetRoot(); | 852 const v8::HeapGraphNode* root2 = snapshot->GetRoot(); |
| 857 CHECK_EQ(root1, root2); | 853 CHECK_EQ(root1, root2); |
| 858 } | 854 } |
| 859 | 855 |
| 860 | 856 |
| 861 namespace v8 { | |
| 862 namespace internal { | |
| 863 | |
| 864 class HeapSnapshotTester { | |
| 865 public: | |
| 866 static int CalculateNetworkSize(JSObject* obj) { | |
| 867 return HeapSnapshot::CalculateNetworkSize(obj); | |
| 868 } | |
| 869 }; | |
| 870 | |
| 871 } } // namespace v8::internal | |
| 872 | |
| 873 // http://code.google.com/p/v8/issues/detail?id=822 | |
| 874 // Trying to call CalculateNetworkSize on an object with elements set | |
| 875 // to non-FixedArray may cause an assertion error in debug builds. | |
| 876 TEST(Issue822) { | |
| 877 v8::HandleScope scope; | |
| 878 LocalContext context; | |
| 879 const int kElementCount = 260; | |
| 880 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount)); | |
| 881 i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount, | |
| 882 pixel_data); | |
| 883 v8::Handle<v8::Object> obj = v8::Object::New(); | |
| 884 // Set the elements to be the pixels. | |
| 885 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount); | |
| 886 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj); | |
| 887 // This call must not cause an assertion error in debug builds. | |
| 888 i::HeapSnapshotTester::CalculateNetworkSize(*jsobj); | |
| 889 } | |
| 890 | |
| 891 | |
| 892 static const v8::HeapGraphNode* GetChild( | 857 static const v8::HeapGraphNode* GetChild( |
| 893 const v8::HeapGraphNode* node, | 858 const v8::HeapGraphNode* node, |
| 894 v8::HeapGraphNode::Type type, | 859 v8::HeapGraphNode::Type type, |
| 895 const char* name, | 860 const char* name, |
| 896 const v8::HeapGraphNode* after = NULL) { | 861 const v8::HeapGraphNode* after = NULL) { |
| 897 bool ignore_child = after == NULL ? false : true; | 862 bool ignore_child = after == NULL ? false : true; |
| 898 for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) { | 863 for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) { |
| 899 const v8::HeapGraphEdge* prop = node->GetChild(i); | 864 const v8::HeapGraphEdge* prop = node->GetChild(i); |
| 900 const v8::HeapGraphNode* child = prop->GetToNode(); | 865 const v8::HeapGraphNode* child = prop->GetToNode(); |
| 901 v8::String::AsciiValue child_name(child->GetName()); | 866 v8::String::AsciiValue child_name(child->GetName()); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 925 | 890 |
| 926 CompileRun( | 891 CompileRun( |
| 927 "function A() {}\n" | 892 "function A() {}\n" |
| 928 "function B(x) { this.x = x; }\n" | 893 "function B(x) { this.x = x; }\n" |
| 929 "var a = new A();\n" | 894 "var a = new A();\n" |
| 930 "var b = new B(a);"); | 895 "var b = new B(a);"); |
| 931 const v8::HeapSnapshot* snapshot = | 896 const v8::HeapSnapshot* snapshot = |
| 932 v8::HeapProfiler::TakeSnapshot( | 897 v8::HeapProfiler::TakeSnapshot( |
| 933 v8::String::New("agg"), v8::HeapSnapshot::kAggregated); | 898 v8::String::New("agg"), v8::HeapSnapshot::kAggregated); |
| 934 const v8::HeapGraphNode* strings = GetChild(snapshot->GetRoot(), | 899 const v8::HeapGraphNode* strings = GetChild(snapshot->GetRoot(), |
| 935 v8::HeapGraphNode::kInternal, | 900 v8::HeapGraphNode::kHidden, |
| 936 "STRING_TYPE"); | 901 "STRING_TYPE"); |
| 937 CHECK_NE(NULL, strings); | 902 CHECK_NE(NULL, strings); |
| 938 CHECK_NE(0, strings->GetSelfSize()); | 903 CHECK_NE(0, strings->GetSelfSize()); |
| 939 CHECK_NE(0, strings->GetInstancesCount()); | 904 CHECK_NE(0, strings->GetInstancesCount()); |
| 940 const v8::HeapGraphNode* maps = GetChild(snapshot->GetRoot(), | 905 const v8::HeapGraphNode* maps = GetChild(snapshot->GetRoot(), |
| 941 v8::HeapGraphNode::kInternal, | 906 v8::HeapGraphNode::kHidden, |
| 942 "MAP_TYPE"); | 907 "MAP_TYPE"); |
| 943 CHECK_NE(NULL, maps); | 908 CHECK_NE(NULL, maps); |
| 944 CHECK_NE(0, maps->GetSelfSize()); | 909 CHECK_NE(0, maps->GetSelfSize()); |
| 945 CHECK_NE(0, maps->GetInstancesCount()); | 910 CHECK_NE(0, maps->GetInstancesCount()); |
| 946 | 911 |
| 947 const v8::HeapGraphNode* a = GetChild(snapshot->GetRoot(), | 912 const v8::HeapGraphNode* a = GetChild(snapshot->GetRoot(), |
| 948 v8::HeapGraphNode::kObject, | 913 v8::HeapGraphNode::kObject, |
| 949 "A"); | 914 "A"); |
| 950 CHECK_NE(NULL, a); | 915 CHECK_NE(NULL, a); |
| 951 CHECK_NE(0, a->GetSelfSize()); | 916 CHECK_NE(0, a->GetSelfSize()); |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1066 "var parsed = JSON.parse(json_snapshot); true;"); | 1031 "var parsed = JSON.parse(json_snapshot); true;"); |
| 1067 CHECK(!snapshot_parse_result.IsEmpty()); | 1032 CHECK(!snapshot_parse_result.IsEmpty()); |
| 1068 | 1033 |
| 1069 // Verify that snapshot object has required fields. | 1034 // Verify that snapshot object has required fields. |
| 1070 v8::Local<v8::Object> parsed_snapshot = | 1035 v8::Local<v8::Object> parsed_snapshot = |
| 1071 env->Global()->Get(v8::String::New("parsed"))->ToObject(); | 1036 env->Global()->Get(v8::String::New("parsed"))->ToObject(); |
| 1072 CHECK(parsed_snapshot->Has(v8::String::New("snapshot"))); | 1037 CHECK(parsed_snapshot->Has(v8::String::New("snapshot"))); |
| 1073 CHECK(parsed_snapshot->Has(v8::String::New("nodes"))); | 1038 CHECK(parsed_snapshot->Has(v8::String::New("nodes"))); |
| 1074 CHECK(parsed_snapshot->Has(v8::String::New("strings"))); | 1039 CHECK(parsed_snapshot->Has(v8::String::New("strings"))); |
| 1075 | 1040 |
| 1076 // Verify that nodes meta-info is valid JSON. | |
| 1077 v8::Local<v8::Value> nodes_meta_parse_result = CompileRun( | |
| 1078 "var parsed_meta = JSON.parse(parsed.nodes[0]); true;"); | |
| 1079 CHECK(!nodes_meta_parse_result.IsEmpty()); | |
| 1080 | |
| 1081 // Get node and edge "member" offsets. | 1041 // Get node and edge "member" offsets. |
| 1082 v8::Local<v8::Value> meta_analysis_result = CompileRun( | 1042 v8::Local<v8::Value> meta_analysis_result = CompileRun( |
| 1043 "var parsed_meta = parsed.nodes[0];\n" |
| 1083 "var children_count_offset =" | 1044 "var children_count_offset =" |
| 1084 " parsed_meta.fields.indexOf('children_count');\n" | 1045 " parsed_meta.fields.indexOf('children_count');\n" |
| 1085 "var children_offset =" | 1046 "var children_offset =" |
| 1086 " parsed_meta.fields.indexOf('children');\n" | 1047 " parsed_meta.fields.indexOf('children');\n" |
| 1087 "var children_meta =" | 1048 "var children_meta =" |
| 1088 " parsed_meta.types[children_offset];\n" | 1049 " parsed_meta.types[children_offset];\n" |
| 1089 "var child_fields_count = children_meta.fields.length;\n" | 1050 "var child_fields_count = children_meta.fields.length;\n" |
| 1090 "var child_type_offset =" | 1051 "var child_type_offset =" |
| 1091 " children_meta.fields.indexOf('type');\n" | 1052 " children_meta.fields.indexOf('type');\n" |
| 1092 "var child_name_offset =" | 1053 "var child_name_offset =" |
| 1093 " children_meta.fields.indexOf('name_or_index');\n" | 1054 " children_meta.fields.indexOf('name_or_index');\n" |
| 1094 "var child_to_node_offset =" | 1055 "var child_to_node_offset =" |
| 1095 " children_meta.fields.indexOf('to_node');\n" | 1056 " children_meta.fields.indexOf('to_node');\n" |
| 1096 "var property_type =" | 1057 "var property_type =" |
| 1097 " children_meta.types[child_type_offset].indexOf('property');"); | 1058 " children_meta.types[child_type_offset].indexOf('property');\n" |
| 1059 "var shortcut_type =" |
| 1060 " children_meta.types[child_type_offset].indexOf('shortcut');"); |
| 1098 CHECK(!meta_analysis_result.IsEmpty()); | 1061 CHECK(!meta_analysis_result.IsEmpty()); |
| 1099 | 1062 |
| 1100 // A helper function for processing encoded nodes. | 1063 // A helper function for processing encoded nodes. |
| 1101 CompileRun( | 1064 CompileRun( |
| 1102 "function GetChildPosByProperty(pos, prop_name) {\n" | 1065 "function GetChildPosByProperty(pos, prop_name, prop_type) {\n" |
| 1103 " var nodes = parsed.nodes;\n" | 1066 " var nodes = parsed.nodes;\n" |
| 1104 " var strings = parsed.strings;\n" | 1067 " var strings = parsed.strings;\n" |
| 1105 " for (var i = 0,\n" | 1068 " for (var i = 0,\n" |
| 1106 " count = nodes[pos + children_count_offset] * child_fields_count;\n" | 1069 " count = nodes[pos + children_count_offset] * child_fields_count;\n" |
| 1107 " i < count; i += child_fields_count) {\n" | 1070 " i < count; i += child_fields_count) {\n" |
| 1108 " var child_pos = pos + children_offset + i;\n" | 1071 " var child_pos = pos + children_offset + i;\n" |
| 1109 " if (nodes[child_pos + child_type_offset] === property_type\n" | 1072 " if (nodes[child_pos + child_type_offset] === prop_type\n" |
| 1110 " && strings[nodes[child_pos + child_name_offset]] === prop_name)\n" | 1073 " && strings[nodes[child_pos + child_name_offset]] === prop_name)\n" |
| 1111 " return nodes[child_pos + child_to_node_offset];\n" | 1074 " return nodes[child_pos + child_to_node_offset];\n" |
| 1112 " }\n" | 1075 " }\n" |
| 1113 " return null;\n" | 1076 " return null;\n" |
| 1114 "}\n"); | 1077 "}\n"); |
| 1115 // Get the string index using the path: <root> -> <global>.b.x.s | 1078 // Get the string index using the path: <root> -> <global>.b.x.s |
| 1116 v8::Local<v8::Value> string_obj_pos_val = CompileRun( | 1079 v8::Local<v8::Value> string_obj_pos_val = CompileRun( |
| 1117 "GetChildPosByProperty(\n" | 1080 "GetChildPosByProperty(\n" |
| 1118 " GetChildPosByProperty(\n" | 1081 " GetChildPosByProperty(\n" |
| 1119 " GetChildPosByProperty(" | 1082 " GetChildPosByProperty(" |
| 1120 " parsed.nodes[1 + children_offset + child_to_node_offset],\"b\"),\n" | 1083 " parsed.nodes[1 + children_offset + child_to_node_offset]," |
| 1121 " \"x\")," | 1084 " \"b\",shortcut_type),\n" |
| 1122 " \"s\")"); | 1085 " \"x\", property_type)," |
| 1086 " \"s\", property_type)"); |
| 1123 CHECK(!string_obj_pos_val.IsEmpty()); | 1087 CHECK(!string_obj_pos_val.IsEmpty()); |
| 1124 int string_obj_pos = | 1088 int string_obj_pos = |
| 1125 static_cast<int>(string_obj_pos_val->ToNumber()->Value()); | 1089 static_cast<int>(string_obj_pos_val->ToNumber()->Value()); |
| 1126 v8::Local<v8::Object> nodes_array = | 1090 v8::Local<v8::Object> nodes_array = |
| 1127 parsed_snapshot->Get(v8::String::New("nodes"))->ToObject(); | 1091 parsed_snapshot->Get(v8::String::New("nodes"))->ToObject(); |
| 1128 int string_index = static_cast<int>( | 1092 int string_index = static_cast<int>( |
| 1129 nodes_array->Get(string_obj_pos + 1)->ToNumber()->Value()); | 1093 nodes_array->Get(string_obj_pos + 1)->ToNumber()->Value()); |
| 1130 CHECK_GT(string_index, 0); | 1094 CHECK_GT(string_index, 0); |
| 1131 v8::Local<v8::Object> strings_array = | 1095 v8::Local<v8::Object> strings_array = |
| 1132 parsed_snapshot->Get(v8::String::New("strings"))->ToObject(); | 1096 parsed_snapshot->Get(v8::String::New("strings"))->ToObject(); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1144 LocalContext env; | 1108 LocalContext env; |
| 1145 const v8::HeapSnapshot* snapshot = | 1109 const v8::HeapSnapshot* snapshot = |
| 1146 v8::HeapProfiler::TakeSnapshot(v8::String::New("abort")); | 1110 v8::HeapProfiler::TakeSnapshot(v8::String::New("abort")); |
| 1147 TestJSONStream stream(5); | 1111 TestJSONStream stream(5); |
| 1148 snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON); | 1112 snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON); |
| 1149 CHECK_GT(stream.size(), 0); | 1113 CHECK_GT(stream.size(), 0); |
| 1150 CHECK_EQ(0, stream.eos_signaled()); | 1114 CHECK_EQ(0, stream.eos_signaled()); |
| 1151 } | 1115 } |
| 1152 | 1116 |
| 1153 #endif // ENABLE_LOGGING_AND_PROFILING | 1117 #endif // ENABLE_LOGGING_AND_PROFILING |
| OLD | NEW |