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