• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/dfx/hprof/rawheap_translate/serializer.h"
17 #include "ecmascript/dfx/hprof/rawheap_translate/string_hashmap.h"
18 
19 namespace rawheap_translate {
Initialize(const std::string & filePath)20 bool StreamWriter::Initialize(const std::string &filePath)
21 {
22     if (filePath.empty() || filePath.size() > PATH_MAX) {
23         LOG_ERROR("filename is illegal!");
24         return false;
25     }
26 
27     fileStream_.open(filePath, std::ios::out);
28     if (fileStream_.fail()) {
29         LOG_ERROR("FileStream: open file failed");
30         return false;
31     }
32 
33     return true;
34 }
35 
WriteString(const std::string & str)36 void StreamWriter::WriteString(const std::string &str)
37 {
38     MaybeWriteChunk();
39     auto len = str.size();
40     if (len == 0) {
41         return;
42     }
43     const char *cur = str.c_str();
44     const char *end = cur + len;
45     while (cur < end) {
46         int dstSize = chunkSize_ - current_;
47         int writeSize = std::min(static_cast<int>(end - cur), dstSize);
48         if (writeSize <= 0) {
49             break;
50         }
51         if (memcpy_s(chunk_.data() + current_, dstSize, cur, writeSize) != EOK) {
52             LOG_ERROR("StreamWriter::WriteString: memcpy_s failed!");
53             break;
54         }
55         cur += writeSize;
56         current_ += writeSize;
57         MaybeWriteChunk();
58     }
59 }
60 
EndOfStream()61 void StreamWriter::EndOfStream()
62 {
63     if (current_ > 0) {
64         std::string str(chunk_.data(), current_);
65         fileStream_ << str;
66         current_ = 0;
67     }
68     if (fileStream_.is_open()) {
69         fileStream_.close();
70     }
71 }
72 
Serialize(RawHeapTranslate * snapshot,StreamWriter * writer)73 bool HeapSnapshotJSONSerializer::Serialize(RawHeapTranslate *snapshot, StreamWriter *writer)
74 {
75     // Serialize Node/Edge/String-Table
76     LOG_INFO("HeapSnapshotJSONSerializer::Serialize begin");
77 
78     SerializeSnapshotHeader(snapshot, writer);     // 1.
79     SerializeNodes(snapshot, writer);              // 2.
80     SerializeEdges(snapshot, writer);              // 3.
81 
82     writer->WriteString("\"trace_function_infos\":[],");  // 4.
83     writer->WriteString("\"trace_tree\":[],");
84     writer->WriteString("\"samples\":[],");
85     writer->WriteString("\"locations\":[],\n");
86 
87     SerializeStringTable(snapshot, writer);        // 8.
88     SerializerSnapshotClosure(writer);   // 9.
89 
90     LOG_INFO("HeapSnapshotJSONSerializer::Serialize exit");
91     return true;
92 }
93 
SerializeSnapshotHeader(RawHeapTranslate * snapshot,StreamWriter * writer)94 void HeapSnapshotJSONSerializer::SerializeSnapshotHeader(RawHeapTranslate *snapshot, StreamWriter *writer)
95 {
96     writer->WriteString("{\"snapshot\":\n");  // 1.
97     writer->WriteString("{\"meta\":\n");      // 2.
98     // NOLINTNEXTLINE(modernize-raw-string-literal)
99     writer->WriteString("{\"node_fields\":[\"type\",\"name\",\"id\",\"self_size\",\"edge_count\",\"trace_node_id\",");
100     writer->WriteString("\"detachedness\",\"native_size\"],\n");  // 3.
101     // NOLINTNEXTLINE(modernize-raw-string-literal)
102     writer->WriteString("\"node_types\":[[\"hidden\",\"array\",\"string\",\"object\",\"code\",\"closure\",\"regexp\",");
103     // NOLINTNEXTLINE(modernize-raw-string-literal)
104     writer->WriteString("\"number\",\"native\",\"synthetic\",\"concatenated string\",\"slicedstring\",\"symbol\",");
105     // NOLINTNEXTLINE(modernize-raw-string-literal)
106     writer->WriteString("\"bigint\"],\"string\",\"number\",\"number\",\"number\",\"number\",\"number\"],\n");  // 4.
107     // NOLINTNEXTLINE(modernize-raw-string-literal)
108     writer->WriteString("\"edge_fields\":[\"type\",\"name_or_index\",\"to_node\"],\n");  // 5.
109     // NOLINTNEXTLINE(modernize-raw-string-literal)
110     writer->WriteString("\"edge_types\":[[\"context\",\"element\",\"property\",\"internal\",\"hidden\",\"shortcut\",");
111     // NOLINTNEXTLINE(modernize-raw-string-literal)
112     writer->WriteString("\"weak\"],\"string_or_number\",\"node\"],\n");  // 6.
113     // NOLINTNEXTLINE(modernize-raw-string-literal)
114     writer->WriteString("\"trace_function_info_fields\":[\"function_id\",\"name\",\"script_name\",\"script_id\",");
115     // NOLINTNEXTLINE(modernize-raw-string-literal)
116     writer->WriteString("\"line\",\"column\"],\n");  // 7.
117     // NOLINTNEXTLINE(modernize-raw-string-literal)
118     writer->WriteString("\"trace_node_fields\":[\"id\",\"function_info_index\",\"count\",\"size\",\"children\"],\n");
119     // NOLINTNEXTLINE(modernize-raw-string-literal)
120     writer->WriteString("\"sample_fields\":[\"timestamp_us\",\"last_assigned_id\"],\n");  // 9.
121     // NOLINTNEXTLINE(modernize-raw-string-literal)
122     // 10.
123     writer->WriteString("\"location_fields\":[\"object_index\",\"script_id\",\"line\",\"column\"]},\n\"node_count\":");
124     writer->WriteNumber(snapshot->GetNodeCount());                         // 11.
125     writer->WriteString(",\n\"edge_count\":");
126     writer->WriteNumber(snapshot->GetEdgeCount());                         // 12.
127     writer->WriteString(",\n\"trace_function_count\":");
128     writer->WriteNumber(0);   // 13.
129     writer->WriteString("\n},\n");  // 14.
130 }
131 
SerializeNodes(RawHeapTranslate * snapshot,StreamWriter * writer)132 void HeapSnapshotJSONSerializer::SerializeNodes(RawHeapTranslate *snapshot, StreamWriter *writer)
133 {
134     auto nodes = snapshot->GetNodes();
135     writer->WriteString("\"nodes\":[");  // Section Header
136     size_t i = 0;
137     for (auto node : nodes) {
138         if (i > 0) {
139             writer->WriteChar(',');  // add comma except first line
140         }
141         writer->WriteNumber(node->type);  // 1.
142         writer->WriteChar(',');
143         writer->WriteNumber(node->strId);                      // 2.
144         writer->WriteChar(',');
145         writer->WriteNumber(node->nodeId);                                                  // 3.
146         writer->WriteChar(',');
147         writer->WriteNumber(node->size);                                            // 4.
148         writer->WriteChar(',');
149         writer->WriteNumber(node->edgeCount);                                           // 5.
150         writer->WriteChar(',');
151         writer->WriteNumber(0);                                        // 6.
152         writer->WriteChar(',');
153         writer->WriteChar('0');                                                              // 7.detachedness default 0
154         writer->WriteChar(',');
155         writer->WriteNumber(node->nativeSize);
156         if (i == nodes.size() - 1) {    // add comma at last the line
157             writer->WriteString("],\n"); // 7. detachedness default
158         } else {
159             writer->WriteString("\n");   // 7.
160         }
161         i++;
162     }
163 }
164 
SerializeEdges(RawHeapTranslate * snapshot,StreamWriter * writer)165 void HeapSnapshotJSONSerializer::SerializeEdges(RawHeapTranslate *snapshot, StreamWriter *writer)
166 {
167     auto edges = snapshot->GetEdges();
168     writer->WriteString("\"edges\":[");
169     size_t i = 0;
170     for (auto edge : edges) {
171         if (i > 0) {  // add comma except the first line
172             writer->WriteChar(',');
173         }
174         writer->WriteNumber(static_cast<int>(edge->type));          // 1.
175         writer->WriteChar(',');
176         writer->WriteNumber(static_cast<int>(edge->nameOrIndex));  // 2. Use StringId
177         writer->WriteChar(',');
178 
179         if (i == edges.size() - 1) {  // add comma at last the line
180             writer->WriteNumber(edge->to->index * NODE_FIELD_COUNT);  // 3.
181             writer->WriteString("],\n");
182         } else {
183             writer->WriteNumber(edge->to->index * NODE_FIELD_COUNT);    // 3.
184             writer->WriteChar('\n');
185         }
186         i++;
187     }
188 }
189 
SerializeStringTable(RawHeapTranslate * snapshot,StreamWriter * writer)190 void HeapSnapshotJSONSerializer::SerializeStringTable(RawHeapTranslate *snapshot, StreamWriter *writer)
191 {
192     auto stringTable = snapshot->GetEcmaStringTable();
193     writer->WriteString("\"strings\":[\"<dummy>\",\n");
194     writer->WriteString("\"\",\n");
195     writer->WriteString("\"GC roots\",\n");
196     // StringId Range from 3
197     size_t capcity = stringTable->GetCapcity();
198     if (capcity <= 0) {
199         return;
200     }
201     size_t i = 0;
202     for (auto key : stringTable->GetOrderedKeyStorage()) {
203         if (i == capcity - 1) {
204             writer->WriteChar('\"');
205             SerializeString(stringTable->GetStringByKey(key).c_str(), writer); // No Comma for the last line
206             writer->WriteString("\"\n");
207         } else {
208             writer->WriteChar('\"');
209             SerializeString(stringTable->GetStringByKey(key).c_str(), writer);
210             writer->WriteString("\",\n");
211         }
212         i++;
213     }
214     writer->WriteString("]\n");
215 }
216 
SerializeString(const char * str,StreamWriter * writer)217 void HeapSnapshotJSONSerializer::SerializeString(const char *str, StreamWriter *writer)
218 {
219     if (str == nullptr || writer == nullptr) {
220         return;
221     }
222     const char *s = str;
223     while (*s != '\0') {
224         if (*s == '\"' || *s == '\\') {
225             writer->WriteChar('\\');
226             writer->WriteChar(*s);
227             s++;
228         } else if (*s == '\n') {
229             writer->WriteString("\\n");
230             s++;
231         } else if (*s == '\b') {
232             writer->WriteString("\\b");
233             s++;
234         } else if (*s == '\f') {
235             writer->WriteString("\\f");
236             s++;
237         } else if (*s == '\r') {
238             writer->WriteString("\\r");
239             s++;
240         } else if (*s == '\t') {
241             writer->WriteString("\\t");
242             s++;
243         } else if (*s > ASCII_US && *s < ASCII_DEL) {
244             writer->WriteChar(*s);
245             s++;
246         } else {
247             writer->WriteChar(*s);
248             s++;
249         }
250     }
251 }
252 
SerializerSnapshotClosure(StreamWriter * writer)253 void HeapSnapshotJSONSerializer::SerializerSnapshotClosure(StreamWriter *writer)
254 {
255     writer->WriteString("}\n");
256 }
257 
258 }  // namespace rawheap_translate
259