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