14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#include "ecmascript/dfx/hprof/heap_snapshot_json_serializer.h" 174514f5e3Sopenharmony_ci 184514f5e3Sopenharmony_ci#include "ecmascript/dfx/hprof/heap_snapshot.h" 194514f5e3Sopenharmony_ci#include "securec.h" 204514f5e3Sopenharmony_ci 214514f5e3Sopenharmony_cinamespace panda::ecmascript { 224514f5e3Sopenharmony_ci 234514f5e3Sopenharmony_cibool HeapSnapshotJSONSerializer::Serialize(HeapSnapshot *snapshot, Stream *stream) 244514f5e3Sopenharmony_ci{ 254514f5e3Sopenharmony_ci // Serialize Node/Edge/String-Table 264514f5e3Sopenharmony_ci LOG_ECMA(INFO) << "HeapSnapshotJSONSerializer::Serialize begin"; 274514f5e3Sopenharmony_ci ASSERT(snapshot->GetNodes() != nullptr && snapshot->GetEdges() != nullptr && 284514f5e3Sopenharmony_ci snapshot->GetEcmaStringTable() != nullptr); 294514f5e3Sopenharmony_ci auto writer = new StreamWriter(stream); 304514f5e3Sopenharmony_ci 314514f5e3Sopenharmony_ci SerializeSnapshotHeader(snapshot, writer); // 1. 324514f5e3Sopenharmony_ci SerializeNodes(snapshot, writer); // 2. 334514f5e3Sopenharmony_ci SerializeEdges(snapshot, writer); // 3. 344514f5e3Sopenharmony_ci SerializeTraceFunctionInfo(snapshot, writer); // 4. 354514f5e3Sopenharmony_ci SerializeTraceTree(snapshot, writer); // 5. 364514f5e3Sopenharmony_ci SerializeSamples(snapshot, writer); // 6. 374514f5e3Sopenharmony_ci SerializeLocations(writer); // 7. 384514f5e3Sopenharmony_ci SerializeStringTable(snapshot, writer); // 8. 394514f5e3Sopenharmony_ci SerializerSnapshotClosure(writer); // 9. 404514f5e3Sopenharmony_ci writer->End(); 414514f5e3Sopenharmony_ci 424514f5e3Sopenharmony_ci delete writer; 434514f5e3Sopenharmony_ci 444514f5e3Sopenharmony_ci LOG_ECMA(INFO) << "HeapSnapshotJSONSerializer::Serialize exit"; 454514f5e3Sopenharmony_ci return true; 464514f5e3Sopenharmony_ci} 474514f5e3Sopenharmony_ci 484514f5e3Sopenharmony_civoid HeapSnapshotJSONSerializer::DumpStringTable(HeapSnapshot *snapshot, Stream *stream) 494514f5e3Sopenharmony_ci{ 504514f5e3Sopenharmony_ci const StringHashMap *stringTable = snapshot->GetEcmaStringTable(); 514514f5e3Sopenharmony_ci ASSERT(stringTable != nullptr); 524514f5e3Sopenharmony_ci size_t size5MB = 5 * 1024 * 1024; 534514f5e3Sopenharmony_ci char *buf = new char[size5MB]; // 5MB buf use for string dump 544514f5e3Sopenharmony_ci auto strNum = stringTable->GetCapcity(); 554514f5e3Sopenharmony_ci auto ret = memcpy_s(buf, size5MB, &strNum, sizeof(size_t)); 564514f5e3Sopenharmony_ci if (ret != EOK) { 574514f5e3Sopenharmony_ci delete[] buf; 584514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "DumpStringTable: memcpy_s failed, strNum=" << strNum; 594514f5e3Sopenharmony_ci return; 604514f5e3Sopenharmony_ci } 614514f5e3Sopenharmony_ci size_t offset = sizeof(size_t); 624514f5e3Sopenharmony_ci for (auto key : stringTable->GetOrderedKeyStorage()) { 634514f5e3Sopenharmony_ci auto [strId, str] = stringTable->GetStringAndIdPair(key); 644514f5e3Sopenharmony_ci const char *s = str->data(); 654514f5e3Sopenharmony_ci auto currLen = str->size() + 1; 664514f5e3Sopenharmony_ci if (currLen + sizeof(uint64_t) > size5MB) { 674514f5e3Sopenharmony_ci stream->WriteBinBlock(buf, offset); 684514f5e3Sopenharmony_ci offset = 0; 694514f5e3Sopenharmony_ci delete[] buf; 704514f5e3Sopenharmony_ci size5MB = currLen + sizeof(uint64_t); 714514f5e3Sopenharmony_ci buf = new char[size5MB]; 724514f5e3Sopenharmony_ci } 734514f5e3Sopenharmony_ci if (offset + currLen + sizeof(uint64_t) > size5MB) { 744514f5e3Sopenharmony_ci stream->WriteBinBlock(buf, offset); 754514f5e3Sopenharmony_ci offset = 0; 764514f5e3Sopenharmony_ci } 774514f5e3Sopenharmony_ci auto strIdPtr = reinterpret_cast<uint64_t *>(buf + offset); 784514f5e3Sopenharmony_ci *strIdPtr = strId; 794514f5e3Sopenharmony_ci ret = memcpy_s(buf + offset + sizeof(uint64_t), size5MB - offset, s, currLen); 804514f5e3Sopenharmony_ci if (ret != EOK) { 814514f5e3Sopenharmony_ci delete[] buf; 824514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "DumpStringTable: memcpy_s failed"; 834514f5e3Sopenharmony_ci return; 844514f5e3Sopenharmony_ci } 854514f5e3Sopenharmony_ci offset += currLen + sizeof(uint64_t); 864514f5e3Sopenharmony_ci } 874514f5e3Sopenharmony_ci if (offset > 0) { 884514f5e3Sopenharmony_ci stream->WriteBinBlock(buf, offset); 894514f5e3Sopenharmony_ci } 904514f5e3Sopenharmony_ci delete[] buf; 914514f5e3Sopenharmony_ci} 924514f5e3Sopenharmony_ci 934514f5e3Sopenharmony_civoid HeapSnapshotJSONSerializer::SerializeSnapshotHeader(HeapSnapshot *snapshot, StreamWriter *writer) 944514f5e3Sopenharmony_ci{ 954514f5e3Sopenharmony_ci writer->WriteString("{\"snapshot\":\n"); // 1. 964514f5e3Sopenharmony_ci writer->WriteString("{\"meta\":\n"); // 2. 974514f5e3Sopenharmony_ci // NOLINTNEXTLINE(modernize-raw-string-literal) 984514f5e3Sopenharmony_ci writer->WriteString("{\"node_fields\":[\"type\",\"name\",\"id\",\"self_size\",\"edge_count\",\"trace_node_id\","); 994514f5e3Sopenharmony_ci writer->WriteString("\"detachedness\",\"native_size\"],\n"); // 3. 1004514f5e3Sopenharmony_ci // NOLINTNEXTLINE(modernize-raw-string-literal) 1014514f5e3Sopenharmony_ci writer->WriteString("\"node_types\":[[\"hidden\",\"array\",\"string\",\"object\",\"code\",\"closure\",\"regexp\","); 1024514f5e3Sopenharmony_ci // NOLINTNEXTLINE(modernize-raw-string-literal) 1034514f5e3Sopenharmony_ci writer->WriteString("\"number\",\"native\",\"synthetic\",\"concatenated string\",\"slicedstring\",\"symbol\","); 1044514f5e3Sopenharmony_ci // NOLINTNEXTLINE(modernize-raw-string-literal) 1054514f5e3Sopenharmony_ci writer->WriteString("\"bigint\"],\"string\",\"number\",\"number\",\"number\",\"number\",\"number\"],\n"); // 4. 1064514f5e3Sopenharmony_ci // NOLINTNEXTLINE(modernize-raw-string-literal) 1074514f5e3Sopenharmony_ci writer->WriteString("\"edge_fields\":[\"type\",\"name_or_index\",\"to_node\"],\n"); // 5. 1084514f5e3Sopenharmony_ci // NOLINTNEXTLINE(modernize-raw-string-literal) 1094514f5e3Sopenharmony_ci writer->WriteString("\"edge_types\":[[\"context\",\"element\",\"property\",\"internal\",\"hidden\",\"shortcut\","); 1104514f5e3Sopenharmony_ci // NOLINTNEXTLINE(modernize-raw-string-literal) 1114514f5e3Sopenharmony_ci writer->WriteString("\"weak\"],\"string_or_number\",\"node\"],\n"); // 6. 1124514f5e3Sopenharmony_ci // NOLINTNEXTLINE(modernize-raw-string-literal) 1134514f5e3Sopenharmony_ci writer->WriteString("\"trace_function_info_fields\":[\"function_id\",\"name\",\"script_name\",\"script_id\","); 1144514f5e3Sopenharmony_ci // NOLINTNEXTLINE(modernize-raw-string-literal) 1154514f5e3Sopenharmony_ci writer->WriteString("\"line\",\"column\"],\n"); // 7. 1164514f5e3Sopenharmony_ci // NOLINTNEXTLINE(modernize-raw-string-literal) 1174514f5e3Sopenharmony_ci writer->WriteString("\"trace_node_fields\":[\"id\",\"function_info_index\",\"count\",\"size\",\"children\"],\n"); 1184514f5e3Sopenharmony_ci // NOLINTNEXTLINE(modernize-raw-string-literal) 1194514f5e3Sopenharmony_ci writer->WriteString("\"sample_fields\":[\"timestamp_us\",\"last_assigned_id\"],\n"); // 9. 1204514f5e3Sopenharmony_ci // NOLINTNEXTLINE(modernize-raw-string-literal) 1214514f5e3Sopenharmony_ci // 10. 1224514f5e3Sopenharmony_ci writer->WriteString("\"location_fields\":[\"object_index\",\"script_id\",\"line\",\"column\"]},\n\"node_count\":"); 1234514f5e3Sopenharmony_ci writer->WriteNumber(snapshot->GetNodeCount()); // 11. 1244514f5e3Sopenharmony_ci writer->WriteString(",\n\"edge_count\":"); 1254514f5e3Sopenharmony_ci writer->WriteNumber(snapshot->GetEdgeCount()); // 12. 1264514f5e3Sopenharmony_ci writer->WriteString(",\n\"trace_function_count\":"); 1274514f5e3Sopenharmony_ci writer->WriteNumber(snapshot->GetTrackAllocationsStack().size()); // 13. 1284514f5e3Sopenharmony_ci writer->WriteString("\n},\n"); // 14. 1294514f5e3Sopenharmony_ci} 1304514f5e3Sopenharmony_ci 1314514f5e3Sopenharmony_civoid HeapSnapshotJSONSerializer::SerializeNodes(HeapSnapshot *snapshot, StreamWriter *writer) 1324514f5e3Sopenharmony_ci{ 1334514f5e3Sopenharmony_ci const CList<Node *> *nodes = snapshot->GetNodes(); 1344514f5e3Sopenharmony_ci const StringHashMap *stringTable = snapshot->GetEcmaStringTable(); 1354514f5e3Sopenharmony_ci ASSERT(nodes != nullptr); 1364514f5e3Sopenharmony_ci writer->WriteString("\"nodes\":["); // Section Header 1374514f5e3Sopenharmony_ci size_t i = 0; 1384514f5e3Sopenharmony_ci for (auto *node : *nodes) { 1394514f5e3Sopenharmony_ci if (i > 0) { 1404514f5e3Sopenharmony_ci writer->WriteChar(','); // add comma except first line 1414514f5e3Sopenharmony_ci } 1424514f5e3Sopenharmony_ci writer->WriteNumber(static_cast<int>(node->GetType())); // 1. 1434514f5e3Sopenharmony_ci writer->WriteChar(','); 1444514f5e3Sopenharmony_ci writer->WriteNumber(stringTable->GetStringId(node->GetName())); // 2. 1454514f5e3Sopenharmony_ci writer->WriteChar(','); 1464514f5e3Sopenharmony_ci writer->WriteNumber(node->GetId()); // 3. 1474514f5e3Sopenharmony_ci writer->WriteChar(','); 1484514f5e3Sopenharmony_ci writer->WriteNumber(node->GetSelfSize()); // 4. 1494514f5e3Sopenharmony_ci writer->WriteChar(','); 1504514f5e3Sopenharmony_ci writer->WriteNumber(node->GetEdgeCount()); // 5. 1514514f5e3Sopenharmony_ci writer->WriteChar(','); 1524514f5e3Sopenharmony_ci writer->WriteNumber(node->GetStackTraceId()); // 6. 1534514f5e3Sopenharmony_ci writer->WriteChar(','); 1544514f5e3Sopenharmony_ci writer->WriteChar('0'); // 7.detachedness default 0 1554514f5e3Sopenharmony_ci writer->WriteChar(','); 1564514f5e3Sopenharmony_ci writer->WriteNumber(node->GetNativeSize()); 1574514f5e3Sopenharmony_ci if (i == nodes->size() - 1) { // add comma at last the line 1584514f5e3Sopenharmony_ci writer->WriteString("],\n"); // 7. detachedness default 1594514f5e3Sopenharmony_ci } else { 1604514f5e3Sopenharmony_ci writer->WriteString("\n"); // 7. 1614514f5e3Sopenharmony_ci } 1624514f5e3Sopenharmony_ci i++; 1634514f5e3Sopenharmony_ci } 1644514f5e3Sopenharmony_ci} 1654514f5e3Sopenharmony_ci 1664514f5e3Sopenharmony_civoid HeapSnapshotJSONSerializer::SerializeEdges(HeapSnapshot *snapshot, StreamWriter *writer) 1674514f5e3Sopenharmony_ci{ 1684514f5e3Sopenharmony_ci const CList<Edge *> *edges = snapshot->GetEdges(); 1694514f5e3Sopenharmony_ci const StringHashMap *stringTable = snapshot->GetEcmaStringTable(); 1704514f5e3Sopenharmony_ci ASSERT(edges != nullptr); 1714514f5e3Sopenharmony_ci writer->WriteString("\"edges\":["); 1724514f5e3Sopenharmony_ci size_t i = 0; 1734514f5e3Sopenharmony_ci for (auto *edge : *edges) { 1744514f5e3Sopenharmony_ci StringId nameOrIndex = edge->GetType() == EdgeType::ELEMENT ? 1754514f5e3Sopenharmony_ci edge->GetIndex() : stringTable->GetStringId(edge->GetName()); 1764514f5e3Sopenharmony_ci if (i > 0) { // add comma except the first line 1774514f5e3Sopenharmony_ci writer->WriteChar(','); 1784514f5e3Sopenharmony_ci } 1794514f5e3Sopenharmony_ci writer->WriteNumber(static_cast<int>(edge->GetType())); // 1. 1804514f5e3Sopenharmony_ci writer->WriteChar(','); 1814514f5e3Sopenharmony_ci writer->WriteNumber(nameOrIndex); // 2. Use StringId 1824514f5e3Sopenharmony_ci writer->WriteChar(','); 1834514f5e3Sopenharmony_ci 1844514f5e3Sopenharmony_ci if (i == edges->size() - 1) { // add comma at last the line 1854514f5e3Sopenharmony_ci writer->WriteNumber(edge->GetTo()->GetIndex() * Node::NODE_FIELD_COUNT); // 3. 1864514f5e3Sopenharmony_ci writer->WriteString("],\n"); 1874514f5e3Sopenharmony_ci } else { 1884514f5e3Sopenharmony_ci writer->WriteNumber(edge->GetTo()->GetIndex() * Node::NODE_FIELD_COUNT); // 3. 1894514f5e3Sopenharmony_ci writer->WriteChar('\n'); 1904514f5e3Sopenharmony_ci } 1914514f5e3Sopenharmony_ci i++; 1924514f5e3Sopenharmony_ci } 1934514f5e3Sopenharmony_ci} 1944514f5e3Sopenharmony_ci 1954514f5e3Sopenharmony_civoid HeapSnapshotJSONSerializer::SerializeTraceFunctionInfo(HeapSnapshot *snapshot, StreamWriter *writer) 1964514f5e3Sopenharmony_ci{ 1974514f5e3Sopenharmony_ci const CVector<FunctionInfo> trackAllocationsStack = snapshot->GetTrackAllocationsStack(); 1984514f5e3Sopenharmony_ci const StringHashMap *stringTable = snapshot->GetEcmaStringTable(); 1994514f5e3Sopenharmony_ci 2004514f5e3Sopenharmony_ci writer->WriteString("\"trace_function_infos\":["); // Empty 2014514f5e3Sopenharmony_ci size_t i = 0; 2024514f5e3Sopenharmony_ci 2034514f5e3Sopenharmony_ci for (const auto &info : trackAllocationsStack) { 2044514f5e3Sopenharmony_ci if (i > 0) { // add comma except the first line 2054514f5e3Sopenharmony_ci writer->WriteChar(','); 2064514f5e3Sopenharmony_ci } 2074514f5e3Sopenharmony_ci writer->WriteNumber(info.functionId); 2084514f5e3Sopenharmony_ci writer->WriteChar(','); 2094514f5e3Sopenharmony_ci CString functionName(info.functionName.c_str()); 2104514f5e3Sopenharmony_ci writer->WriteNumber(stringTable->GetStringId(&functionName)); 2114514f5e3Sopenharmony_ci writer->WriteChar(','); 2124514f5e3Sopenharmony_ci CString scriptName(info.scriptName.c_str()); 2134514f5e3Sopenharmony_ci writer->WriteNumber(stringTable->GetStringId(&scriptName)); 2144514f5e3Sopenharmony_ci writer->WriteChar(','); 2154514f5e3Sopenharmony_ci writer->WriteNumber(info.scriptId); 2164514f5e3Sopenharmony_ci writer->WriteChar(','); 2174514f5e3Sopenharmony_ci writer->WriteNumber(info.lineNumber); 2184514f5e3Sopenharmony_ci writer->WriteChar(','); 2194514f5e3Sopenharmony_ci writer->WriteNumber(info.columnNumber); 2204514f5e3Sopenharmony_ci writer->WriteChar('\n'); 2214514f5e3Sopenharmony_ci i++; 2224514f5e3Sopenharmony_ci } 2234514f5e3Sopenharmony_ci writer->WriteString("],\n"); 2244514f5e3Sopenharmony_ci} 2254514f5e3Sopenharmony_ci 2264514f5e3Sopenharmony_civoid HeapSnapshotJSONSerializer::SerializeTraceTree(HeapSnapshot *snapshot, StreamWriter *writer) 2274514f5e3Sopenharmony_ci{ 2284514f5e3Sopenharmony_ci writer->WriteString("\"trace_tree\":["); 2294514f5e3Sopenharmony_ci TraceTree* tree = snapshot->GetTraceTree(); 2304514f5e3Sopenharmony_ci if ((tree != nullptr) && (snapshot->trackAllocations())) { 2314514f5e3Sopenharmony_ci SerializeTraceNode(tree->GetRoot(), writer); 2324514f5e3Sopenharmony_ci } 2334514f5e3Sopenharmony_ci writer->WriteString("],\n"); 2344514f5e3Sopenharmony_ci} 2354514f5e3Sopenharmony_ci 2364514f5e3Sopenharmony_civoid HeapSnapshotJSONSerializer::SerializeTraceNode(TraceNode* node, StreamWriter *writer) 2374514f5e3Sopenharmony_ci{ 2384514f5e3Sopenharmony_ci if (node == nullptr) { 2394514f5e3Sopenharmony_ci return; 2404514f5e3Sopenharmony_ci } 2414514f5e3Sopenharmony_ci 2424514f5e3Sopenharmony_ci writer->WriteNumber(node->GetId()); 2434514f5e3Sopenharmony_ci writer->WriteChar(','); 2444514f5e3Sopenharmony_ci writer->WriteNumber(node->GetNodeIndex()); 2454514f5e3Sopenharmony_ci writer->WriteChar(','); 2464514f5e3Sopenharmony_ci writer->WriteNumber(node->GetTotalCount()); 2474514f5e3Sopenharmony_ci writer->WriteChar(','); 2484514f5e3Sopenharmony_ci writer->WriteNumber(node->GetTotalSize()); 2494514f5e3Sopenharmony_ci writer->WriteString(",["); 2504514f5e3Sopenharmony_ci 2514514f5e3Sopenharmony_ci int i = 0; 2524514f5e3Sopenharmony_ci for (TraceNode* child : node->GetChildren()) { 2534514f5e3Sopenharmony_ci if (i > 0) { 2544514f5e3Sopenharmony_ci writer->WriteChar(','); 2554514f5e3Sopenharmony_ci } 2564514f5e3Sopenharmony_ci SerializeTraceNode(child, writer); 2574514f5e3Sopenharmony_ci i++; 2584514f5e3Sopenharmony_ci } 2594514f5e3Sopenharmony_ci writer->WriteChar(']'); 2604514f5e3Sopenharmony_ci} 2614514f5e3Sopenharmony_ci 2624514f5e3Sopenharmony_civoid HeapSnapshotJSONSerializer::SerializeSamples(HeapSnapshot *snapshot, StreamWriter *writer) 2634514f5e3Sopenharmony_ci{ 2644514f5e3Sopenharmony_ci writer->WriteString("\"samples\":["); 2654514f5e3Sopenharmony_ci const CVector<TimeStamp> &timeStamps = snapshot->GetTimeStamps(); 2664514f5e3Sopenharmony_ci if (!timeStamps.empty()) { 2674514f5e3Sopenharmony_ci auto firstTimeStamp = timeStamps[0]; 2684514f5e3Sopenharmony_ci bool isFirst = true; 2694514f5e3Sopenharmony_ci for (auto timeStamp : timeStamps) { 2704514f5e3Sopenharmony_ci if (!isFirst) { 2714514f5e3Sopenharmony_ci writer->WriteString("\n, "); 2724514f5e3Sopenharmony_ci } else { 2734514f5e3Sopenharmony_ci isFirst = false; 2744514f5e3Sopenharmony_ci } 2754514f5e3Sopenharmony_ci writer->WriteNumber(timeStamp.GetTimeStamp() - firstTimeStamp.GetTimeStamp()); 2764514f5e3Sopenharmony_ci writer->WriteString(", "); 2774514f5e3Sopenharmony_ci writer->WriteNumber(timeStamp.GetLastSequenceId()); 2784514f5e3Sopenharmony_ci } 2794514f5e3Sopenharmony_ci } 2804514f5e3Sopenharmony_ci writer->WriteString("],\n"); 2814514f5e3Sopenharmony_ci} 2824514f5e3Sopenharmony_ci 2834514f5e3Sopenharmony_civoid HeapSnapshotJSONSerializer::SerializeLocations(StreamWriter *writer) 2844514f5e3Sopenharmony_ci{ 2854514f5e3Sopenharmony_ci writer->WriteString("\"locations\":[],\n"); 2864514f5e3Sopenharmony_ci} 2874514f5e3Sopenharmony_ci 2884514f5e3Sopenharmony_civoid HeapSnapshotJSONSerializer::SerializeStringTable(HeapSnapshot *snapshot, StreamWriter *writer) 2894514f5e3Sopenharmony_ci{ 2904514f5e3Sopenharmony_ci const StringHashMap *stringTable = snapshot->GetEcmaStringTable(); 2914514f5e3Sopenharmony_ci ASSERT(stringTable != nullptr); 2924514f5e3Sopenharmony_ci writer->WriteString("\"strings\":[\"<dummy>\",\n"); 2934514f5e3Sopenharmony_ci writer->WriteString("\"\",\n"); 2944514f5e3Sopenharmony_ci writer->WriteString("\"GC roots\",\n"); 2954514f5e3Sopenharmony_ci // StringId Range from 3 2964514f5e3Sopenharmony_ci size_t capcity = stringTable->GetCapcity(); 2974514f5e3Sopenharmony_ci ASSERT(capcity > 0); 2984514f5e3Sopenharmony_ci size_t i = 0; 2994514f5e3Sopenharmony_ci for (auto key : stringTable->GetOrderedKeyStorage()) { 3004514f5e3Sopenharmony_ci if (i == capcity - 1) { 3014514f5e3Sopenharmony_ci writer->WriteChar('\"'); 3024514f5e3Sopenharmony_ci SerializeString(stringTable->GetStringByKey(key), writer); // No Comma for the last line 3034514f5e3Sopenharmony_ci writer->WriteString("\"\n"); 3044514f5e3Sopenharmony_ci } else { 3054514f5e3Sopenharmony_ci writer->WriteChar('\"'); 3064514f5e3Sopenharmony_ci SerializeString(stringTable->GetStringByKey(key), writer); 3074514f5e3Sopenharmony_ci writer->WriteString("\",\n"); 3084514f5e3Sopenharmony_ci } 3094514f5e3Sopenharmony_ci i++; 3104514f5e3Sopenharmony_ci } 3114514f5e3Sopenharmony_ci writer->WriteString("]\n"); 3124514f5e3Sopenharmony_ci} 3134514f5e3Sopenharmony_ci 3144514f5e3Sopenharmony_civoid HeapSnapshotJSONSerializer::SerializeString(CString *str, StreamWriter *writer) 3154514f5e3Sopenharmony_ci{ 3164514f5e3Sopenharmony_ci if (str == nullptr || writer == nullptr) { 3174514f5e3Sopenharmony_ci return; 3184514f5e3Sopenharmony_ci } 3194514f5e3Sopenharmony_ci const char *s = str->c_str(); 3204514f5e3Sopenharmony_ci while (*s != '\0') { 3214514f5e3Sopenharmony_ci if (*s == '\"' || *s == '\\') { 3224514f5e3Sopenharmony_ci writer->WriteChar('\\'); 3234514f5e3Sopenharmony_ci writer->WriteChar(*s); 3244514f5e3Sopenharmony_ci s++; 3254514f5e3Sopenharmony_ci } else if (*s == '\n') { 3264514f5e3Sopenharmony_ci writer->WriteString("\\n"); 3274514f5e3Sopenharmony_ci s++; 3284514f5e3Sopenharmony_ci } else if (*s == '\b') { 3294514f5e3Sopenharmony_ci writer->WriteString("\\b"); 3304514f5e3Sopenharmony_ci s++; 3314514f5e3Sopenharmony_ci } else if (*s == '\f') { 3324514f5e3Sopenharmony_ci writer->WriteString("\\f"); 3334514f5e3Sopenharmony_ci s++; 3344514f5e3Sopenharmony_ci } else if (*s == '\r') { 3354514f5e3Sopenharmony_ci writer->WriteString("\\r"); 3364514f5e3Sopenharmony_ci s++; 3374514f5e3Sopenharmony_ci } else if (*s == '\t') { 3384514f5e3Sopenharmony_ci writer->WriteString("\\t"); 3394514f5e3Sopenharmony_ci s++; 3404514f5e3Sopenharmony_ci } else if (*s > ASCII_US && *s < ASCII_DEL) { 3414514f5e3Sopenharmony_ci writer->WriteChar(*s); 3424514f5e3Sopenharmony_ci s++; 3434514f5e3Sopenharmony_ci } else if (*s <= ASCII_US || *s == ASCII_DEL) { 3444514f5e3Sopenharmony_ci // special char convert to \u unicode 3454514f5e3Sopenharmony_ci SerializeUnicodeChar(static_cast<uint32_t>(*s), writer); 3464514f5e3Sopenharmony_ci s++; 3474514f5e3Sopenharmony_ci } else { 3484514f5e3Sopenharmony_ci // convert utf-8 to \u unicode 3494514f5e3Sopenharmony_ci size_t len = 1; 3504514f5e3Sopenharmony_ci while (len <= UTF8_MAX_BYTES && *(s + len) != '\0') { 3514514f5e3Sopenharmony_ci len++; 3524514f5e3Sopenharmony_ci } 3534514f5e3Sopenharmony_ci auto [unicode, bytes] = 3544514f5e3Sopenharmony_ci base::utf_helper::ConvertUtf8ToUnicodeChar(reinterpret_cast<const uint8_t *>(s), len); 3554514f5e3Sopenharmony_ci if (unicode == base::utf_helper::INVALID_UTF8) { 3564514f5e3Sopenharmony_ci LOG_ECMA(WARN) << "HeapSnapshotJSONSerializer::SerializeString, str is not utf-8"; 3574514f5e3Sopenharmony_ci writer->WriteChar('?'); 3584514f5e3Sopenharmony_ci s++; 3594514f5e3Sopenharmony_ci } else { 3604514f5e3Sopenharmony_ci SerializeUnicodeChar(unicode, writer); 3614514f5e3Sopenharmony_ci s += bytes; 3624514f5e3Sopenharmony_ci } 3634514f5e3Sopenharmony_ci } 3644514f5e3Sopenharmony_ci } 3654514f5e3Sopenharmony_ci} 3664514f5e3Sopenharmony_ci 3674514f5e3Sopenharmony_civoid HeapSnapshotJSONSerializer::SerializeUnicodeChar(uint32_t unicodeChar, StreamWriter *writer) 3684514f5e3Sopenharmony_ci{ 3694514f5e3Sopenharmony_ci static const char hexChars[] = "0123456789ABCDEF"; 3704514f5e3Sopenharmony_ci writer->WriteString("\\u"); 3714514f5e3Sopenharmony_ci writer->WriteChar(hexChars[(unicodeChar >> 0xC) & 0xF]); 3724514f5e3Sopenharmony_ci writer->WriteChar(hexChars[(unicodeChar >> 0x8) & 0xF]); 3734514f5e3Sopenharmony_ci writer->WriteChar(hexChars[(unicodeChar >> 0x4) & 0xF]); 3744514f5e3Sopenharmony_ci writer->WriteChar(hexChars[unicodeChar & 0xF]); 3754514f5e3Sopenharmony_ci} 3764514f5e3Sopenharmony_ci 3774514f5e3Sopenharmony_civoid HeapSnapshotJSONSerializer::SerializerSnapshotClosure(StreamWriter *writer) 3784514f5e3Sopenharmony_ci{ 3794514f5e3Sopenharmony_ci writer->WriteString("}\n"); 3804514f5e3Sopenharmony_ci} 3814514f5e3Sopenharmony_ci} // namespace panda::ecmascript 382