1 /*
2 * Copyright (c) 2025 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 #include "ecmascript/base/dtoa_helper.h"
16 #include "ecmascript/base/string_helper.h"
17 #include "ecmascript/compiler/aot_file/aot_checksum_helper.h"
18 #include "ecmascript/log_wrapper.h"
19 #include "libpandabase/macros.h"
20
21 namespace panda::ecmascript {
22
SerializeChecksumMapToVector(const std::unordered_map<CString,uint32_t> & fileNameToChecksumMap,std::vector<char> & checksumDataVector)23 bool AOTChecksumHelper::SerializeChecksumMapToVector(const std::unordered_map<CString, uint32_t> &fileNameToChecksumMap,
24 std::vector<char> &checksumDataVector)
25 {
26 // save fileName to checksum relationship as like
27 // pandafileNormalizeDes:checksum
28 // /xxx/yyy/zzz.abc:123456
29 if (fileNameToChecksumMap.empty()) {
30 LOG_COMPILER(ERROR) << "abc file checksum map cant't be empty!";
31 return false;
32 }
33 uint32_t checksumVectorSize = CalculateChecksumVectorSize(fileNameToChecksumMap);
34 checksumDataVector.resize(checksumVectorSize);
35 if (!WriteChecksumInfoToVector(fileNameToChecksumMap, checksumDataVector)) {
36 checksumDataVector.resize(0);
37 LOG_COMPILER(ERROR) << "Serialize checksumMap to .an failed!";
38 return false;
39 }
40 return true;
41 }
42
CalculateChecksumVectorSize(const std::unordered_map<CString,uint32_t> & fileNameToChecksumMap)43 uint32_t AOTChecksumHelper::CalculateChecksumVectorSize(
44 const std::unordered_map<CString, uint32_t> &fileNameToChecksumMap)
45 {
46 uint32_t size = 0;
47 for (const auto &pair : fileNameToChecksumMap) {
48 // 2 for ':' and '\0'
49 size += pair.first.size() + FastUint32ToDigits(pair.second) + 2;
50 }
51 return size;
52 }
53
FastUint32ToDigits(uint32_t number)54 uint32_t AOTChecksumHelper::FastUint32ToDigits(uint32_t number)
55 {
56 return (number >= base::DtoaHelper::TEN9POW) ? 10 // 10 digits
57 : (number >= base::DtoaHelper::TEN8POW) ? 9 // 9 digits
58 : (number >= base::DtoaHelper::TEN7POW) ? 8 // 8 digits
59 : (number >= base::DtoaHelper::TEN6POW) ? 7 // 7 digits
60 : (number >= base::DtoaHelper::TEN5POW) ? 6 // 6 digits
61 : (number >= base::DtoaHelper::TEN4POW) ? 5 // 5 digits
62 : (number >= base::DtoaHelper::TEN3POW) ? 4 // 4 digits
63 : (number >= base::DtoaHelper::TEN2POW) ? 3 // 3 digits
64 : (number >= base::DtoaHelper::TEN) ? 2 // 2 digits
65 : 1; // 1 digit
66 }
67
WriteChecksumInfoToVector(const std::unordered_map<CString,uint32_t> & fileNameToChecksumMap,std::vector<char> & checksumDataVector)68 bool AOTChecksumHelper::WriteChecksumInfoToVector(const std::unordered_map<CString, uint32_t> &fileNameToChecksumMap,
69 std::vector<char> &checksumDataVector)
70 {
71 char *basePtr = checksumDataVector.data();
72 char *endPtr = basePtr + checksumDataVector.size();
73 char *writePtr = basePtr;
74 for (const auto &pair : fileNameToChecksumMap) {
75 size_t remainSize = endPtr - writePtr;
76 int written = snprintf_s(writePtr, remainSize, remainSize - 1, "%s:%u", pair.first.c_str(), pair.second);
77 if (written < 0 || static_cast<size_t>(written) >= remainSize) {
78 LOG_COMPILER(ERROR) << "wirte checksum info to AOT .an file failed!";
79 return false;
80 }
81 // 1 for '\0'
82 writePtr += written + 1;
83 }
84 if (writePtr != endPtr) {
85 LOG_COMPILER(ERROR) << "Checksum vector not fully filled: "
86 << "expected size=" << checksumDataVector.size()
87 << ", actual used=" << (writePtr - basePtr);
88 return false;
89 }
90 return true;
91 }
92
DeserializeChecksumMapFromChar(const char * checksumData,uint32_t checksumDataSize,std::unordered_map<CString,uint32_t> & fileNameToChecksumMap)93 bool AOTChecksumHelper::DeserializeChecksumMapFromChar(const char *checksumData, uint32_t checksumDataSize,
94 std::unordered_map<CString, uint32_t> &fileNameToChecksumMap)
95 {
96 if (checksumData == nullptr || checksumDataSize == 0) {
97 LOG_COMPILER(ERROR) << "Invalid checksum data";
98 return false;
99 }
100
101 const char *curPtr = checksumData;
102 const char *endPtr = checksumData + checksumDataSize;
103
104 while (curPtr < endPtr) {
105 const char *entryEnd = static_cast<const char *>(memchr(curPtr, '\0', endPtr - curPtr));
106 if (entryEnd == nullptr || entryEnd >= endPtr) {
107 LOG_COMPILER(ERROR) << "Corrupted checksum data: missing string terminator";
108 return false;
109 }
110
111 const char *separator = static_cast<const char *>(memchr(curPtr, ':', entryEnd - curPtr));
112 if (separator == nullptr || separator >= entryEnd) {
113 LOG_COMPILER(ERROR) << "Corrupted checksum data: missing separator";
114 return false;
115 }
116
117 if (separator == curPtr || separator + 1 == entryEnd) {
118 LOG_COMPILER(ERROR) << "Invalid entry format: empty filename or checksum";
119 return false;
120 }
121
122 CString filename(curPtr, separator - curPtr);
123
124 uint32_t checksum;
125 if (!base::StringHelper::StrToUInt32(separator + 1, &checksum)) {
126 LOG_COMPILER(ERROR) << "Invalid checksum value";
127 return false;
128 }
129
130 fileNameToChecksumMap.emplace(std::move(filename), checksum);
131
132 curPtr = entryEnd + 1;
133 }
134
135 if (fileNameToChecksumMap.empty()) {
136 LOG_COMPILER(ERROR) << "No valid entries found in checksum data";
137 return false;
138 }
139 return true;
140 }
141
142 } // namespace panda::ecmascript
143