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