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