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 971 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
982 b_with_children, | 982 b_with_children, |
983 v8::HeapGraphNode::kObject, | 983 v8::HeapGraphNode::kObject, |
984 "A"); | 984 "A"); |
985 CHECK_NE(NULL, a_from_b); | 985 CHECK_NE(NULL, a_from_b); |
986 CHECK_EQ(0, a_from_b->GetSelfSize()); | 986 CHECK_EQ(0, a_from_b->GetSelfSize()); |
987 CHECK_EQ(0, a_from_b->GetInstancesCount()); | 987 CHECK_EQ(0, a_from_b->GetInstancesCount()); |
988 CHECK_EQ(0, a_from_b->GetChildrenCount()); // Retains nothing. | 988 CHECK_EQ(0, a_from_b->GetChildrenCount()); // Retains nothing. |
989 CHECK(IsNodeRetainedAs(a_from_b, 1)); // B has 1 ref to A. | 989 CHECK(IsNodeRetainedAs(a_from_b, 1)); // B has 1 ref to A. |
990 } | 990 } |
991 | 991 |
| 992 namespace { |
| 993 |
| 994 class TestJSONStream : public v8::OutputStream { |
| 995 public: |
| 996 TestJSONStream() : eos_signaled_(0) {} |
| 997 virtual ~TestJSONStream() {} |
| 998 virtual void EndOfStream() { ++eos_signaled_; } |
| 999 virtual void WriteAsciiChunk(char* buffer, int chars_written) { |
| 1000 CHECK_GT(chars_written, 0); |
| 1001 i::Vector<char> chunk = buffer_.AddBlock(chars_written, '\0'); |
| 1002 memcpy(chunk.start(), buffer, chars_written); |
| 1003 } |
| 1004 void WriteTo(i::Vector<char> dest) { buffer_.WriteTo(dest); } |
| 1005 int eos_signaled() { return eos_signaled_; } |
| 1006 int size() { return buffer_.size(); } |
| 1007 private: |
| 1008 i::Collector<char> buffer_; |
| 1009 int eos_signaled_; |
| 1010 }; |
| 1011 |
| 1012 class AsciiResource: public v8::String::ExternalAsciiStringResource { |
| 1013 public: |
| 1014 explicit AsciiResource(i::Vector<char> string): data_(string.start()) { |
| 1015 length_ = string.length(); |
| 1016 } |
| 1017 virtual const char* data() const { return data_; } |
| 1018 virtual size_t length() const { return length_; } |
| 1019 private: |
| 1020 const char* data_; |
| 1021 size_t length_; |
| 1022 }; |
| 1023 |
| 1024 } // namespace |
| 1025 |
| 1026 TEST(HeapSnapshotJSONSerialization) { |
| 1027 v8::HandleScope scope; |
| 1028 LocalContext env; |
| 1029 |
| 1030 #define STRING_LITERAL_FOR_TEST \ |
| 1031 "\"String \\n\\r\\u0008\\u0081\\u0101\\u0801\\u8001\"" |
| 1032 CompileAndRunScript( |
| 1033 "function A(s) { this.s = s; }\n" |
| 1034 "function B(x) { this.x = x; }\n" |
| 1035 "var a = new A(" STRING_LITERAL_FOR_TEST ");\n" |
| 1036 "var b = new B(a);"); |
| 1037 const v8::HeapSnapshot* snapshot = |
| 1038 v8::HeapProfiler::TakeSnapshot(v8::String::New("json")); |
| 1039 TestJSONStream stream; |
| 1040 snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON); |
| 1041 CHECK_GT(stream.size(), 0); |
| 1042 CHECK_EQ(1, stream.eos_signaled()); |
| 1043 i::ScopedVector<char> json(stream.size()); |
| 1044 stream.WriteTo(json); |
| 1045 |
| 1046 // Verify that snapshot string is valid JSON. |
| 1047 AsciiResource json_res(json); |
| 1048 v8::Local<v8::String> json_string = v8::String::NewExternal(&json_res); |
| 1049 env->Global()->Set(v8::String::New("json_snapshot"), json_string); |
| 1050 v8::Local<v8::Value> snapshot_parse_result = CompileRun( |
| 1051 "var parsed = JSON.parse(json_snapshot); true;"); |
| 1052 CHECK(!snapshot_parse_result.IsEmpty()); |
| 1053 |
| 1054 // Verify that snapshot object has required fields. |
| 1055 v8::Local<v8::Object> parsed_snapshot = |
| 1056 env->Global()->Get(v8::String::New("parsed"))->ToObject(); |
| 1057 CHECK(parsed_snapshot->Has(v8::String::New("snapshot"))); |
| 1058 CHECK(parsed_snapshot->Has(v8::String::New("nodes"))); |
| 1059 CHECK(parsed_snapshot->Has(v8::String::New("strings"))); |
| 1060 |
| 1061 // Verify that nodes meta-info is valid JSON. |
| 1062 v8::Local<v8::Value> nodes_meta_parse_result = CompileRun( |
| 1063 "var parsed_meta = JSON.parse(parsed.nodes[0]); true;"); |
| 1064 CHECK(!nodes_meta_parse_result.IsEmpty()); |
| 1065 |
| 1066 // Get node and edge "member" offsets. |
| 1067 v8::Local<v8::Value> meta_analysis_result = CompileRun( |
| 1068 "var children_count_offset =" |
| 1069 " parsed_meta.fields.indexOf('children_count');\n" |
| 1070 "var children_offset =" |
| 1071 " parsed_meta.fields.indexOf('children');\n" |
| 1072 "var children_meta =" |
| 1073 " parsed_meta.types[children_offset];\n" |
| 1074 "var child_fields_count = children_meta.fields.length;\n" |
| 1075 "var child_type_offset =" |
| 1076 " children_meta.fields.indexOf('type');\n" |
| 1077 "var child_name_offset =" |
| 1078 " children_meta.fields.indexOf('name_or_index');\n" |
| 1079 "var child_to_node_offset =" |
| 1080 " children_meta.fields.indexOf('to_node');\n" |
| 1081 "var property_type =" |
| 1082 " children_meta.types[child_type_offset].indexOf('property');"); |
| 1083 CHECK(!meta_analysis_result.IsEmpty()); |
| 1084 |
| 1085 // A helper function for processing encoded nodes. |
| 1086 CompileRun( |
| 1087 "function GetChildPosByProperty(pos, prop_name) {\n" |
| 1088 " var nodes = parsed.nodes;\n" |
| 1089 " var strings = parsed.strings;\n" |
| 1090 " for (var i = 0,\n" |
| 1091 " count = nodes[pos + children_count_offset] * child_fields_count;\n" |
| 1092 " i < count; i += child_fields_count) {\n" |
| 1093 " var child_pos = pos + children_offset + i;\n" |
| 1094 " if (nodes[child_pos + child_type_offset] === property_type\n" |
| 1095 " && strings[nodes[child_pos + child_name_offset]] === prop_name)\n" |
| 1096 " return nodes[child_pos + child_to_node_offset];\n" |
| 1097 " }\n" |
| 1098 " return null;\n" |
| 1099 "}\n"); |
| 1100 // Get the string index using the path: <root> -> <global>.b.x.s |
| 1101 v8::Local<v8::Value> string_obj_pos_val = CompileRun( |
| 1102 "GetChildPosByProperty(\n" |
| 1103 " GetChildPosByProperty(\n" |
| 1104 " GetChildPosByProperty(" |
| 1105 " parsed.nodes[1 + children_offset + child_to_node_offset],\"b\"),\n" |
| 1106 " \"x\")," |
| 1107 " \"s\")"); |
| 1108 CHECK(!string_obj_pos_val.IsEmpty()); |
| 1109 int string_obj_pos = string_obj_pos_val->ToNumber()->Value(); |
| 1110 v8::Local<v8::Object> nodes_array = |
| 1111 parsed_snapshot->Get(v8::String::New("nodes"))->ToObject(); |
| 1112 int string_index = |
| 1113 nodes_array->Get(string_obj_pos + 1)->ToNumber()->Value(); |
| 1114 CHECK_GT(string_index, 0); |
| 1115 v8::Local<v8::Object> strings_array = |
| 1116 parsed_snapshot->Get(v8::String::New("strings"))->ToObject(); |
| 1117 v8::Local<v8::String> string = strings_array->Get(string_index)->ToString(); |
| 1118 v8::Local<v8::String> ref_string = |
| 1119 CompileRun(STRING_LITERAL_FOR_TEST)->ToString(); |
| 1120 #undef STRING_LITERAL_FOR_TEST |
| 1121 CHECK_EQ(*v8::String::Utf8Value(ref_string), |
| 1122 *v8::String::Utf8Value(string)); |
| 1123 } |
| 1124 |
992 #endif // ENABLE_LOGGING_AND_PROFILING | 1125 #endif // ENABLE_LOGGING_AND_PROFILING |
OLD | NEW |