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