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