• 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,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