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 410 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
421 bool has_A1; | 421 bool has_A1; |
422 bool has_B1; | 422 bool has_B1; |
423 bool has_C1; | 423 bool has_C1; |
424 bool has_A2; | 424 bool has_A2; |
425 bool has_B2; | 425 bool has_B2; |
426 bool has_C2; | 426 bool has_C2; |
427 }; | 427 }; |
428 | 428 |
429 } // namespace | 429 } // namespace |
430 | 430 |
| 431 |
| 432 static const v8::HeapGraphNode* GetGlobalObject( |
| 433 const v8::HeapSnapshot* snapshot) { |
| 434 if (i::Snapshot::IsEnabled()) { |
| 435 // In case if snapshots are enabled, there will present a |
| 436 // vanilla deserealized global object, without properties |
| 437 // added by the test code. |
| 438 CHECK_EQ(2, snapshot->GetHead()->GetChildrenCount()); |
| 439 // Choose the global object of a bigger size. |
| 440 const v8::HeapGraphNode* node0 = |
| 441 snapshot->GetHead()->GetChild(0)->GetToNode(); |
| 442 const v8::HeapGraphNode* node1 = |
| 443 snapshot->GetHead()->GetChild(1)->GetToNode(); |
| 444 return node0->GetTotalSize() > node1->GetTotalSize() ? node0 : node1; |
| 445 } else { |
| 446 CHECK_EQ(1, snapshot->GetHead()->GetChildrenCount()); |
| 447 return snapshot->GetHead()->GetChild(0)->GetToNode(); |
| 448 } |
| 449 } |
| 450 |
| 451 |
| 452 static const v8::HeapGraphNode* GetProperty(const v8::HeapGraphNode* node, |
| 453 v8::HeapGraphEdge::Type type, |
| 454 const char* name) { |
| 455 for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) { |
| 456 const v8::HeapGraphEdge* prop = node->GetChild(i); |
| 457 v8::String::AsciiValue prop_name(prop->GetName()); |
| 458 if (prop->GetType() == type && strcmp(name, *prop_name) == 0) |
| 459 return prop->GetToNode(); |
| 460 } |
| 461 return NULL; |
| 462 } |
| 463 |
| 464 |
| 465 static bool HasString(const v8::HeapGraphNode* node, const char* contents) { |
| 466 for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) { |
| 467 const v8::HeapGraphEdge* prop = node->GetChild(i); |
| 468 const v8::HeapGraphNode* node = prop->GetToNode(); |
| 469 if (node->GetType() == v8::HeapGraphNode::STRING) { |
| 470 v8::String::AsciiValue node_name(node->GetName()); |
| 471 if (strcmp(contents, *node_name) == 0) return true; |
| 472 } |
| 473 } |
| 474 return false; |
| 475 } |
| 476 |
| 477 |
431 TEST(HeapSnapshot) { | 478 TEST(HeapSnapshot) { |
432 v8::HandleScope scope; | 479 v8::HandleScope scope; |
433 | 480 |
434 v8::Handle<v8::String> token1 = v8::String::New("token1"); | 481 v8::Handle<v8::String> token1 = v8::String::New("token1"); |
435 v8::Handle<v8::Context> env1 = v8::Context::New(); | 482 v8::Handle<v8::Context> env1 = v8::Context::New(); |
436 env1->SetSecurityToken(token1); | 483 env1->SetSecurityToken(token1); |
437 env1->Enter(); | 484 env1->Enter(); |
438 | 485 |
439 CompileAndRunScript( | 486 CompileAndRunScript( |
440 "function A1() {}\n" | 487 "function A1() {}\n" |
(...skipping 10 matching lines...) Expand all Loading... |
451 | 498 |
452 CompileAndRunScript( | 499 CompileAndRunScript( |
453 "function A2() {}\n" | 500 "function A2() {}\n" |
454 "function B2(x) { return function() { return typeof x; }; }\n" | 501 "function B2(x) { return function() { return typeof x; }; }\n" |
455 "function C2(x) { this.x1 = x; this.x2 = x; this[1] = x; }\n" | 502 "function C2(x) { this.x1 = x; this.x2 = x; this[1] = x; }\n" |
456 "var a2 = new A2();\n" | 503 "var a2 = new A2();\n" |
457 "var b2_1 = new B2(a2), b2_2 = new B2(a2);\n" | 504 "var b2_1 = new B2(a2), b2_2 = new B2(a2);\n" |
458 "var c2 = new C2(a2);"); | 505 "var c2 = new C2(a2);"); |
459 const v8::HeapSnapshot* snapshot_env2 = | 506 const v8::HeapSnapshot* snapshot_env2 = |
460 v8::HeapProfiler::TakeSnapshot(v8::String::New("env2")); | 507 v8::HeapProfiler::TakeSnapshot(v8::String::New("env2")); |
461 const v8::HeapGraphNode* global_env2; | 508 const v8::HeapGraphNode* global_env2 = GetGlobalObject(snapshot_env2); |
462 if (i::Snapshot::IsEnabled()) { | |
463 // In case if snapshots are enabled, there will present a | |
464 // vanilla deserealized global object, without properties | |
465 // added by the test code. | |
466 CHECK_EQ(2, snapshot_env2->GetHead()->GetChildrenCount()); | |
467 // Choose the global object of a bigger size. | |
468 const v8::HeapGraphNode* node0 = | |
469 snapshot_env2->GetHead()->GetChild(0)->GetToNode(); | |
470 const v8::HeapGraphNode* node1 = | |
471 snapshot_env2->GetHead()->GetChild(1)->GetToNode(); | |
472 global_env2 = node0->GetTotalSize() > node1->GetTotalSize() ? | |
473 node0 : node1; | |
474 } else { | |
475 CHECK_EQ(1, snapshot_env2->GetHead()->GetChildrenCount()); | |
476 global_env2 = snapshot_env2->GetHead()->GetChild(0)->GetToNode(); | |
477 } | |
478 | 509 |
479 // Verify, that JS global object of env2 doesn't have '..1' | 510 // Verify, that JS global object of env2 doesn't have '..1' |
480 // properties, but has '..2' properties. | 511 // properties, but has '..2' properties. |
481 bool has_a1 = false, has_b1_1 = false, has_b1_2 = false, has_c1 = false; | 512 CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "a1")); |
482 bool has_a2 = false, has_b2_1 = false, has_b2_2 = false, has_c2 = false; | 513 CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "b1_1")); |
483 // This will be needed further. | 514 CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "b1_2")); |
484 const v8::HeapGraphNode* a2_node = NULL; | 515 CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "c1")); |
485 for (int i = 0, count = global_env2->GetChildrenCount(); i < count; ++i) { | 516 const v8::HeapGraphNode* a2_node = |
486 const v8::HeapGraphEdge* prop = global_env2->GetChild(i); | 517 GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "a2"); |
487 v8::String::AsciiValue prop_name(prop->GetName()); | 518 CHECK_NE(NULL, a2_node); |
488 if (strcmp("a1", *prop_name) == 0) has_a1 = true; | 519 CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "b2_1")); |
489 if (strcmp("b1_1", *prop_name) == 0) has_b1_1 = true; | 520 CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "b2_2")); |
490 if (strcmp("b1_2", *prop_name) == 0) has_b1_2 = true; | 521 CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "c2")); |
491 if (strcmp("c1", *prop_name) == 0) has_c1 = true; | |
492 if (strcmp("a2", *prop_name) == 0) { | |
493 has_a2 = true; | |
494 a2_node = prop->GetToNode(); | |
495 } | |
496 if (strcmp("b2_1", *prop_name) == 0) has_b2_1 = true; | |
497 if (strcmp("b2_2", *prop_name) == 0) has_b2_2 = true; | |
498 if (strcmp("c2", *prop_name) == 0) has_c2 = true; | |
499 } | |
500 CHECK(!has_a1); | |
501 CHECK(!has_b1_1); | |
502 CHECK(!has_b1_2); | |
503 CHECK(!has_c1); | |
504 CHECK(has_a2); | |
505 CHECK(has_b2_1); | |
506 CHECK(has_b2_2); | |
507 CHECK(has_c2); | |
508 | 522 |
509 // Verify that anything related to '[ABC]1' is not reachable. | 523 // Verify that anything related to '[ABC]1' is not reachable. |
510 NamedEntriesDetector det; | 524 NamedEntriesDetector det; |
511 i::HeapSnapshot* i_snapshot_env2 = | 525 i::HeapSnapshot* i_snapshot_env2 = |
512 const_cast<i::HeapSnapshot*>( | 526 const_cast<i::HeapSnapshot*>( |
513 reinterpret_cast<const i::HeapSnapshot*>(snapshot_env2)); | 527 reinterpret_cast<const i::HeapSnapshot*>(snapshot_env2)); |
514 i_snapshot_env2->IterateEntries(&det); | 528 i_snapshot_env2->IterateEntries(&det); |
515 CHECK(!det.has_A1); | 529 CHECK(!det.has_A1); |
516 CHECK(!det.has_B1); | 530 CHECK(!det.has_B1); |
517 CHECK(!det.has_C1); | 531 CHECK(!det.has_C1); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
558 && strcmp("b2_2", *prev_edge_name) == 0) has_b2_2_x_ref = true; | 572 && strcmp("b2_2", *prev_edge_name) == 0) has_b2_2_x_ref = true; |
559 } | 573 } |
560 CHECK(has_global_obj_a2_ref); | 574 CHECK(has_global_obj_a2_ref); |
561 CHECK(has_c2_x1_ref); | 575 CHECK(has_c2_x1_ref); |
562 CHECK(has_c2_x2_ref); | 576 CHECK(has_c2_x2_ref); |
563 CHECK(has_c2_1_ref); | 577 CHECK(has_c2_1_ref); |
564 CHECK(has_b2_1_x_ref); | 578 CHECK(has_b2_1_x_ref); |
565 CHECK(has_b2_2_x_ref); | 579 CHECK(has_b2_2_x_ref); |
566 } | 580 } |
567 | 581 |
| 582 |
| 583 TEST(HeapSnapshotCodeObjects) { |
| 584 v8::HandleScope scope; |
| 585 v8::Handle<v8::Context> env = v8::Context::New(); |
| 586 env->Enter(); |
| 587 |
| 588 CompileAndRunScript( |
| 589 "function lazy(x) { return x - 1; }\n" |
| 590 "function compiled(x) { return x + 1; }\n" |
| 591 "compiled(1)"); |
| 592 const v8::HeapSnapshot* snapshot = |
| 593 v8::HeapProfiler::TakeSnapshot(v8::String::New("code")); |
| 594 |
| 595 const v8::HeapGraphNode* global = GetGlobalObject(snapshot); |
| 596 const v8::HeapGraphNode* compiled = |
| 597 GetProperty(global, v8::HeapGraphEdge::PROPERTY, "compiled"); |
| 598 CHECK_NE(NULL, compiled); |
| 599 CHECK_EQ(v8::HeapGraphNode::CLOSURE, compiled->GetType()); |
| 600 const v8::HeapGraphNode* lazy = |
| 601 GetProperty(global, v8::HeapGraphEdge::PROPERTY, "lazy"); |
| 602 CHECK_NE(NULL, lazy); |
| 603 CHECK_EQ(v8::HeapGraphNode::CLOSURE, lazy->GetType()); |
| 604 |
| 605 // Find references to code. |
| 606 const v8::HeapGraphNode* compiled_code = |
| 607 GetProperty(compiled, v8::HeapGraphEdge::INTERNAL, "code"); |
| 608 CHECK_NE(NULL, compiled_code); |
| 609 const v8::HeapGraphNode* lazy_code = |
| 610 GetProperty(lazy, v8::HeapGraphEdge::INTERNAL, "code"); |
| 611 CHECK_NE(NULL, lazy_code); |
| 612 |
| 613 // Verify that non-compiled code doesn't contain references to "x" |
| 614 // literal, while compiled code does. |
| 615 bool compiled_references_x = false, lazy_references_x = false; |
| 616 for (int i = 0, count = compiled_code->GetChildrenCount(); i < count; ++i) { |
| 617 const v8::HeapGraphEdge* prop = compiled_code->GetChild(i); |
| 618 const v8::HeapGraphNode* node = prop->GetToNode(); |
| 619 if (node->GetType() == v8::HeapGraphNode::CODE) { |
| 620 if (HasString(node, "x")) { |
| 621 compiled_references_x = true; |
| 622 break; |
| 623 } |
| 624 } |
| 625 } |
| 626 for (int i = 0, count = lazy_code->GetChildrenCount(); i < count; ++i) { |
| 627 const v8::HeapGraphEdge* prop = lazy_code->GetChild(i); |
| 628 const v8::HeapGraphNode* node = prop->GetToNode(); |
| 629 if (node->GetType() == v8::HeapGraphNode::CODE) { |
| 630 if (HasString(node, "x")) { |
| 631 lazy_references_x = true; |
| 632 break; |
| 633 } |
| 634 } |
| 635 } |
| 636 CHECK(compiled_references_x); |
| 637 CHECK(!lazy_references_x); |
| 638 } |
| 639 |
568 #endif // ENABLE_LOGGING_AND_PROFILING | 640 #endif // ENABLE_LOGGING_AND_PROFILING |
OLD | NEW |