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