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