1 /*
2 * Copyright (c) 2022 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/stackmap/ark_stackmap_builder.h"
16 #include <map>
17 #include "ecmascript/aot_file_manager.h"
18 #include "ecmascript/compiler/assembler/assembler.h"
19 #include "ecmascript/stackmap/ark_stackmap_parser.h"
20 #include "ecmascript/stackmap/llvm_stackmap_parser.h"
21
22 namespace panda::ecmascript::kungfu {
WriteBuffer(const uint8_t * src,uint32_t count,bool flag)23 void BinaryBufferWriter::WriteBuffer(const uint8_t *src, uint32_t count, bool flag)
24 {
25 uint8_t *dst = buffer_ + offset_;
26 if (flag) {
27 std::cout << "buffer_:0x" << std::hex << buffer_ << " offset_:0x" << offset_ << std::endl;
28 }
29 if (dst >= buffer_ && dst + count <= buffer_ + length_) {
30 if (memcpy_s(dst, buffer_ + length_ - dst, src, count) != EOK) {
31 LOG_FULL(FATAL) << "memcpy_s failed";
32 return;
33 };
34 offset_ = offset_ + count;
35 } else {
36 LOG_FULL(FATAL) << "parse buffer error, length is 0 or overflow";
37 }
38 }
39
Run(std::unique_ptr<uint8_t[]> stackMapAddr,uintptr_t hostCodeSectionAddr)40 std::pair<std::shared_ptr<uint8_t>, uint32_t> ArkStackMapBuilder::Run(std::unique_ptr<uint8_t []> stackMapAddr,
41 uintptr_t hostCodeSectionAddr)
42 {
43 LLVMStackMapParser parser;
44 auto result = parser.CalculateStackMap(std::move(stackMapAddr), hostCodeSectionAddr);
45 if (!result) {
46 UNREACHABLE();
47 }
48 auto pc2stackMapVec = parser.GetPc2StackMapVec();
49 auto pc2DeoptVec = parser.GetPc2Deopt();
50 ARKCallsiteAOTFileInfo AOTFileInfo;
51 GenArkCallsiteAOTFileInfo(pc2stackMapVec, pc2DeoptVec, AOTFileInfo);
52 uint32_t totalSize = AOTFileInfo.secHead.totalSize;
53 uint8_t *p = new(std::nothrow) uint8_t[totalSize];
54 if (p == nullptr) {
55 LOG_FULL(FATAL) << "new totalSize:0x" << std::hex << totalSize << " failed";
56 }
57 std::shared_ptr<uint8_t> ptr(p, [](uint8_t *p) { delete []p;});
58 SaveArkCallsiteAOTFileInfo(ptr.get(), totalSize, AOTFileInfo);
59 return std::make_pair(ptr, totalSize);
60 }
61
SaveArkStackMap(const ARKCallsiteAOTFileInfo & info,BinaryBufferWriter & writer)62 void ArkStackMapBuilder::SaveArkStackMap(const ARKCallsiteAOTFileInfo& info, BinaryBufferWriter& writer)
63 {
64 size_t n = info.callsites.size();
65 for (size_t i = 0; i < n; i++) {
66 auto &callSite = info.callsites.at(i);
67 CallSiteInfo stackmaps = callSite.stackmaps;
68 size_t m = stackmaps.size();
69 for (size_t j = 0; j < m; j++) {
70 auto &stackmap = stackmaps.at(j);
71 DwarfRegType reg = stackmap.first;
72 OffsetType offset = stackmap.second;
73 if (j == 0) {
74 ASSERT(callSite.head.stackmapOffset == writer.GetOffset());
75 }
76 writer.WriteBuffer(reinterpret_cast<const uint8_t *>(&(reg)), sizeof(DwarfRegType));
77 writer.WriteBuffer(reinterpret_cast<const uint8_t *>(&(offset)), sizeof(OffsetType));
78 if (j == m - 1) {
79 ASSERT((callSite.head.stackmapOffset + callSite.CalStackMapSize()) == writer.GetOffset());
80 }
81 }
82 }
83 }
84
SaveArkDeopt(const ARKCallsiteAOTFileInfo & info,BinaryBufferWriter & writer)85 void ArkStackMapBuilder::SaveArkDeopt(const ARKCallsiteAOTFileInfo& info, BinaryBufferWriter& writer)
86 {
87 for (auto &it: info.callsites) {
88 auto& callsite2Deopt = it.callsite2Deopt;
89 size_t m = callsite2Deopt.size();
90 for (size_t j = 0; j < m; j++) {
91 auto &deopt = callsite2Deopt.at(j);
92 if (j == 0) {
93 ASSERT(it.head.deoptOffset == writer.GetOffset());
94 }
95 writer.WriteBuffer(reinterpret_cast<const uint8_t *>(&(deopt.Id)), sizeof(deopt.Id));
96 writer.WriteBuffer(reinterpret_cast<const uint8_t *>(&(deopt.kind)), sizeof(deopt.kind));
97 auto& value = deopt.value;
98 if (std::holds_alternative<OffsetType>(value)) {
99 OffsetType v = std::get<OffsetType>(value);
100 writer.WriteBuffer(reinterpret_cast<const uint8_t *>(&(v)), sizeof(v));
101 } else if (std::holds_alternative<LargeInt>(value)) {
102 LargeInt v = std::get<LargeInt>(value);
103 writer.WriteBuffer(reinterpret_cast<const uint8_t *>(&(v)), sizeof(v));
104 } else if (std::holds_alternative<DwarfRegAndOffsetType>(value)) {
105 DwarfRegAndOffsetType v = std::get<DwarfRegAndOffsetType>(value);
106 writer.WriteBuffer(reinterpret_cast<const uint8_t *>(&(v.first)), sizeof(v.first));
107 writer.WriteBuffer(reinterpret_cast<const uint8_t *>(&(v.second)), sizeof(v.second));
108 } else {
109 UNREACHABLE();
110 }
111 }
112 }
113 }
114
ParseArkStackMap(const CallsiteHead & callsiteHead,BinaryBufferParser & binBufparser,uint8_t * ptr,ArkStackMap & arkStackMaps) const115 void ArkStackMapParser::ParseArkStackMap(const CallsiteHead& callsiteHead, BinaryBufferParser& binBufparser,
116 uint8_t *ptr, ArkStackMap &arkStackMaps) const
117 {
118 DwarfRegType reg;
119 OffsetType offsetType;
120 uint32_t offset = callsiteHead.stackmapOffset;
121 uint32_t arkStackMapNum = callsiteHead.arkStackMapNum;
122 ASSERT(arkStackMapNum % 2 == 0); // 2:base and derive
123 for (uint32_t j = 0; j < arkStackMapNum; j++) {
124 binBufparser.ParseBuffer(reinterpret_cast<uint8_t *>(®), sizeof(DwarfRegType), ptr + offset);
125 offset += sizeof(DwarfRegType);
126 binBufparser.ParseBuffer(reinterpret_cast<uint8_t *>(&offsetType), sizeof(OffsetType), ptr + offset);
127 offset += sizeof(OffsetType);
128 LOG_COMPILER(VERBOSE) << " reg: " << std::dec << reg << " offset:" << offsetType;
129 arkStackMaps.emplace_back(std::make_pair(reg, offsetType));
130 }
131 }
132
ParseArkDeopt(const CallsiteHead & callsiteHead,BinaryBufferParser & binBufparser,uint8_t * ptr,std::vector<kungfu::ARKDeopt> & deopts) const133 void ArkStackMapParser::ParseArkDeopt(const CallsiteHead& callsiteHead,
134 BinaryBufferParser& binBufparser, uint8_t *ptr, std::vector<kungfu::ARKDeopt> &deopts) const
135 {
136 kungfu::ARKDeopt deopt;
137 uint32_t deoptOffset = callsiteHead.deoptOffset;
138 uint32_t deoptNum = callsiteHead.deoptNum;
139 OffsetType id;
140 LocationTy::Kind kind;
141 DwarfRegType reg;
142 OffsetType offsetType;
143 ASSERT(deoptNum % 2 == 0); // 2:<id, value>
144 for (uint32_t j = 0; j < deoptNum; j += 2) { // 2:<id, value>
145 binBufparser.ParseBuffer(reinterpret_cast<uint8_t *>(&id), sizeof(id), ptr + deoptOffset);
146 deoptOffset += sizeof(id);
147 deopt.Id = id;
148 binBufparser.ParseBuffer(reinterpret_cast<uint8_t *>(&kind), sizeof(kind), ptr + deoptOffset);
149 deoptOffset += sizeof(kind);
150 deopt.kind = kind;
151 switch (kind) {
152 case LocationTy::Kind::CONSTANT: {
153 OffsetType v;
154 binBufparser.ParseBuffer(reinterpret_cast<uint8_t *>(&v), sizeof(v), ptr + deoptOffset);
155 deoptOffset += sizeof(v);
156 LOG_COMPILER(VERBOSE) << "const offset:" << deoptOffset;
157 deopt.value = v;
158 break;
159 }
160 case LocationTy::Kind::CONSTANTNDEX: {
161 LargeInt v;
162 binBufparser.ParseBuffer(reinterpret_cast<uint8_t *>(&v), sizeof(v), ptr + deoptOffset);
163 deoptOffset += sizeof(v);
164 LOG_COMPILER(VERBOSE) << "large Int:" << v;
165 deopt.value = v;
166 break;
167 }
168 case LocationTy::Kind::INDIRECT: {
169 binBufparser.ParseBuffer(reinterpret_cast<uint8_t *>(®), sizeof(reg), ptr + deoptOffset);
170 deoptOffset += sizeof(reg);
171 binBufparser.ParseBuffer(reinterpret_cast<uint8_t *>(&offsetType),
172 sizeof(offsetType), ptr + deoptOffset);
173 deoptOffset += sizeof(offsetType);
174 LOG_COMPILER(VERBOSE) << " reg:" << std::dec << reg << " offset:" << static_cast<int>(offsetType);
175 deopt.value = std::make_pair(reg, offsetType);
176 break;
177 }
178 default: {
179 UNREACHABLE();
180 }
181 }
182 deopts.emplace_back(deopt);
183 }
184 }
185
ParseArkStackMapAndDeopt(uint8_t * ptr,uint32_t length) const186 void ArkStackMapParser::ParseArkStackMapAndDeopt(uint8_t *ptr, uint32_t length) const
187 {
188 CallsiteHead callsiteHead;
189 StackMapSecHead secHead;
190 BinaryBufferParser binBufparser(ptr, length);
191 binBufparser.ParseBuffer(&secHead, sizeof(StackMapSecHead));
192 for (uint32_t i = 0; i < secHead.callsiteNum; i++) {
193 binBufparser.ParseBuffer(&callsiteHead, sizeof(CallsiteHead));
194 uint32_t offset = callsiteHead.stackmapOffset;
195 uint32_t arkStackMapNum = callsiteHead.arkStackMapNum;
196 uint32_t deoptOffset = callsiteHead.deoptOffset;
197 uint32_t deoptNum = callsiteHead.deoptNum;
198 std::vector<kungfu::ARKDeopt> deopts;
199 ArkStackMap arkStackMaps;
200 LOG_COMPILER(VERBOSE) << " calliteOffset:0x" << std::hex << callsiteHead.calliteOffset
201 << " stackmap offset:0x" << std::hex << offset << " num:" << arkStackMapNum
202 << " deopt Offset:0x" << deoptOffset << " num:" << deoptNum;
203 ParseArkStackMap(callsiteHead, binBufparser, ptr, arkStackMaps);
204 ParseArkDeopt(callsiteHead, binBufparser, ptr, deopts);
205 }
206 }
207
SaveArkCallsiteAOTFileInfo(uint8_t * ptr,uint32_t length,const ARKCallsiteAOTFileInfo & info)208 void ArkStackMapBuilder::SaveArkCallsiteAOTFileInfo(uint8_t *ptr, uint32_t length, const ARKCallsiteAOTFileInfo& info)
209 {
210 BinaryBufferWriter writer(ptr, length);
211 ASSERT(length >= info.secHead.totalSize);
212 writer.WriteBuffer(reinterpret_cast<const uint8_t *>(&(info.secHead)), sizeof(StackMapSecHead));
213 for (auto &it: info.callsites) {
214 writer.WriteBuffer(reinterpret_cast<const uint8_t *>(&(it.head)), sizeof(CallsiteHead));
215 }
216 SaveArkStackMap(info, writer);
217 SaveArkDeopt(info, writer);
218 #ifndef NDEBUG
219 ArkStackMapParser parser;
220 parser.ParseArkStackMapAndDeopt(ptr, length);
221 #endif
222 }
223
224 template <class Vec>
SortCallSite(std::vector<std::unordered_map<uintptr_t,Vec>> & infos,std::vector<std::pair<uintptr_t,Vec>> & result)225 void ArkStackMapBuilder::SortCallSite(
226 std::vector<std::unordered_map<uintptr_t, Vec>> &infos,
227 std::vector<std::pair<uintptr_t, Vec>>& result)
228 {
229 ASSERT(infos.size() == 1);
230 for (auto &info: infos) {
231 for (auto &it: info) {
232 result.emplace_back(it);
233 }
234 }
235 std::sort(result.begin(), result.end(),
236 [](const std::pair<uintptr_t, Vec> &x, const std::pair<uintptr_t, Vec> &y) {
237 return x.first < y.first;
238 });
239 }
240
CalcCallsitePc(std::vector<std::pair<uintptr_t,DeoptInfoType>> & pc2Deopt,std::vector<std::pair<uintptr_t,CallSiteInfo>> & pc2StackMap,std::vector<intptr_t> & callsitePcs)241 void ArkStackMapBuilder::CalcCallsitePc(std::vector<std::pair<uintptr_t, DeoptInfoType>> &pc2Deopt,
242 std::vector<std::pair<uintptr_t, CallSiteInfo>> &pc2StackMap, std::vector<intptr_t> &callsitePcs)
243 {
244 std::set<uintptr_t> pcSet;
245 for (auto &it: pc2Deopt) {
246 pcSet.insert(it.first);
247 }
248 for (auto &it: pc2StackMap) {
249 pcSet.insert(it.first);
250 }
251 callsitePcs.assign(pcSet.begin(), pcSet.end());
252 }
253
FindLoc(std::vector<intptr_t> & CallsitePcs,intptr_t pc)254 int ArkStackMapBuilder::FindLoc(std::vector<intptr_t> &CallsitePcs, intptr_t pc)
255 {
256 for (size_t i = 0; i < CallsitePcs.size(); i++) {
257 if (CallsitePcs[i] == pc) {
258 return i;
259 }
260 }
261 return -1;
262 }
263
GenARKDeopt(const DeoptInfoType & deopt,std::pair<uint32_t,std::vector<kungfu::ARKDeopt>> & sizeAndArkDeopt)264 void ArkStackMapBuilder::GenARKDeopt(const DeoptInfoType& deopt, std::pair<uint32_t,
265 std::vector<kungfu::ARKDeopt>> &sizeAndArkDeopt)
266 {
267 ASSERT(deopt.size() % 2 == 0); // 2:<id, value>
268 uint32_t total = 0;
269 ARKDeopt v;
270 for (size_t i = 0; i < deopt.size(); i += 2) { // 2:<id, value>
271 ASSERT(std::holds_alternative<OffsetType>(deopt[i]));
272 const auto &id = std::get<OffsetType>(deopt[i]);
273 total += sizeof(OffsetType);
274 v.Id = id;
275 total += sizeof(LocationTy::Kind); // derive
276 auto value = deopt[i + 1];
277 if (std::holds_alternative<OffsetType>(value)) {
278 total += sizeof(OffsetType);
279 v.kind = LocationTy::Kind::CONSTANT;
280 v.value = std::get<OffsetType>(value);
281 } else if (std::holds_alternative<LargeInt>(value)) {
282 total += sizeof(LargeInt);
283 v.kind = LocationTy::Kind::CONSTANTNDEX;
284 v.value = std::get<LargeInt>(value);
285 } else if (std::holds_alternative<DwarfRegAndOffsetType>(value)) {
286 total += (sizeof(DwarfRegType) + sizeof(OffsetType));
287 v.kind = LocationTy::Kind::INDIRECT;
288 v.value = std::get<DwarfRegAndOffsetType>(value);
289 } else {
290 UNREACHABLE();
291 }
292 sizeAndArkDeopt.second.emplace_back(v);
293 }
294 std::sort(sizeAndArkDeopt.second.begin(), sizeAndArkDeopt.second.end(),
295 [](const ARKDeopt &a, const ARKDeopt &b) {
296 return a.Id < b.Id;
297 });
298 sizeAndArkDeopt.first = total;
299 }
300
GenArkCallsiteAOTFileInfo(std::vector<Pc2CallSiteInfo> & pc2stackMapVec,std::vector<Pc2Deopt> & pc2DeoptVec,ARKCallsiteAOTFileInfo & result)301 void ArkStackMapBuilder::GenArkCallsiteAOTFileInfo(std::vector<Pc2CallSiteInfo> &pc2stackMapVec,
302 std::vector<Pc2Deopt>& pc2DeoptVec, ARKCallsiteAOTFileInfo &result)
303 {
304 ARKCallsite callsite;
305 uint32_t totalSize = 0;
306 std::vector<std::pair<uintptr_t, CallSiteInfo>> pc2stackMaps;
307 std::vector<std::pair<uintptr_t, DeoptInfoType>> pc2Deopts;
308 std::vector<intptr_t> CallsitePcs;
309 SortCallSite(pc2stackMapVec, pc2stackMaps);
310 SortCallSite(pc2DeoptVec, pc2Deopts);
311 CalcCallsitePc(pc2Deopts, pc2stackMaps, CallsitePcs);
312 uint32_t callsiteNum = CallsitePcs.size();
313 result.callsites.resize(callsiteNum);
314 uint32_t stackmapOffset = sizeof(StackMapSecHead) + sizeof(CallsiteHead) * callsiteNum;
315 for (auto &x: pc2stackMaps) {
316 CallSiteInfo i = x.second;
317 callsite.head.calliteOffset = x.first;
318 callsite.head.arkStackMapNum = i.size();
319 callsite.head.stackmapOffset = stackmapOffset;
320 callsite.head.deoptOffset = 0;
321 callsite.head.deoptNum = 0;
322 callsite.stackmaps = i;
323 stackmapOffset += callsite.CalStackMapSize();
324 int loc = FindLoc(CallsitePcs, x.first);
325 ASSERT(loc >= 0 && loc < static_cast<int>(callsiteNum));
326 result.callsites[static_cast<uint32_t>(loc)] = callsite;
327 }
328 totalSize = stackmapOffset;
329 for (auto &x: pc2Deopts) {
330 int loc = FindLoc(CallsitePcs, x.first);
331 ASSERT(loc >= 0 && loc < static_cast<int>(callsiteNum));
332 DeoptInfoType deopt = x.second;
333 result.callsites[static_cast<uint32_t>(loc)].head.calliteOffset = x.first;
334 result.callsites[static_cast<uint32_t>(loc)].head.deoptNum = deopt.size();
335 result.callsites[static_cast<uint32_t>(loc)].head.deoptOffset = totalSize;
336 std::pair<uint32_t, std::vector<kungfu::ARKDeopt>> sizeAndArkDeopt;
337 GenARKDeopt(deopt, sizeAndArkDeopt);
338 totalSize += sizeAndArkDeopt.first;
339 result.callsites[static_cast<uint32_t>(loc)].callsite2Deopt = sizeAndArkDeopt.second;
340 }
341 result.secHead.callsiteNum = callsiteNum;
342 result.secHead.callsitStart = sizeof(StackMapSecHead);
343 result.secHead.callsitEnd = result.secHead.callsitStart + (result.secHead.callsiteNum - 1) * sizeof(CallsiteHead);
344 result.secHead.totalSize = totalSize;
345 }
346 } // namespace panda::ecmascript::kungfu
347