1 /*
2 * Copyright (c) 2021 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 "llvm_stackmap_parser.h"
17
18 #include <iostream>
19 #include "ecmascript/compiler/compiler_macros.h"
20 #include "ecmascript/frames.h"
21 #include "ecmascript/mem/object_xray.h"
22 #include "ecmascript/mem/slots.h"
23
24 using namespace panda::ecmascript;
25
26 namespace panda::ecmascript::kungfu {
TypeToString(Kind loc) const27 std::string LocationTy::TypeToString(Kind loc) const
28 {
29 switch (loc) {
30 case Kind::REGISTER:
31 return "Register Reg Value in a register";
32 case Kind::DIRECT:
33 return "Direct Reg + Offset Frame index value";
34 case Kind::INDIRECT:
35 return "Indirect [Reg + Offset] Spilled value";
36 case Kind::CONSTANT:
37 return "Constant Offset Small constant";
38 case Kind::CONSTANTNDEX:
39 return "ConstIndex constants[Offset] Large constant";
40 default:
41 return "no know location";
42 }
43 }
44
GetCallSiteInfoByPc(uintptr_t callSiteAddr) const45 const CallSiteInfo* LLVMStackMapParser::GetCallSiteInfoByPc(uintptr_t callSiteAddr) const
46 {
47 auto it = pc2CallSiteInfo_.find(callSiteAddr);
48 if (it != pc2CallSiteInfo_.end()) {
49 return &(it->second);
50 }
51 return nullptr;
52 }
53
GetCallSiteInfoByPatchID(uint64_t patchPointId) const54 const CallSiteInfo* LLVMStackMapParser::GetCallSiteInfoByPatchID(uint64_t patchPointId) const
55 {
56 auto it = pid2CallSiteInfo_.find(patchPointId);
57 if (it != pid2CallSiteInfo_.end()) {
58 return &(it->second);
59 }
60 return nullptr;
61 }
62
PrintCallSiteInfo(const CallSiteInfo * infos,OptimizedLeaveFrame * frame) const63 void LLVMStackMapParser::PrintCallSiteInfo(const CallSiteInfo *infos, OptimizedLeaveFrame *frame) const
64 {
65 int i = 0;
66 uintptr_t address = 0;
67 uintptr_t base = 0;
68 uintptr_t derived = 0;
69 for (auto &info: *infos) {
70 if (info.first == FrameConstants::SP_DWARF_REG_NUM) {
71 uintptr_t rsp = frame->GetCallSiteSp();
72 address = rsp + info.second;
73 LOG_ECMA(DEBUG) << std::dec << "SP_DWARF_REG_NUM: info.second:" << info.second
74 << std::hex << "rsp :" << rsp;
75 } else if (info.first == FrameConstants::FP_DWARF_REG_NUM) {
76 uintptr_t fp = frame->callsiteFp;
77 address = fp + info.second;
78 LOG_ECMA(DEBUG) << std::dec << "FP_DWARF_REG_NUM: info.second:" << info.second
79 << std::hex << "rfp :" << fp;
80 } else {
81 LOG_ECMA(DEBUG) << "REG_NUM : info.first:" << info.first;
82 UNREACHABLE();
83 }
84
85 if (IsDeriveredPointer(i)) {
86 derived = reinterpret_cast<uintptr_t>(address);
87 if (base == derived) {
88 LOG_ECMA(INFO) << std::hex << "visit base:" << base << " base Value: " <<
89 *reinterpret_cast<uintptr_t *>(base);
90 } else {
91 LOG_ECMA(INFO) << std::hex << "push base:" << base << " base Value: " <<
92 *reinterpret_cast<uintptr_t *>(base) << " derived:" << derived;
93 }
94 } else {
95 base = reinterpret_cast<uintptr_t>(address);
96 }
97 i++;
98 }
99 i = 0;
100 }
101
CollectStackMapSlots(OptimizedLeaveFrame * frame,std::set<uintptr_t> & baseSet,ChunkMap<DerivedDataKey,uintptr_t> * data,bool isVerifying) const102 bool LLVMStackMapParser::CollectStackMapSlots(OptimizedLeaveFrame *frame,
103 std::set<uintptr_t> &baseSet, ChunkMap<DerivedDataKey, uintptr_t> *data, [[maybe_unused]] bool isVerifying) const
104 {
105 ASSERT(frame);
106 uint64_t patchpointId = frame->argPatchId;
107 const CallSiteInfo *infos = GetCallSiteInfoByPatchID(patchpointId);
108 if (infos == nullptr) {
109 return false;
110 }
111 uintptr_t address = 0;
112 uintptr_t base = 0;
113 uintptr_t derived = 0;
114 int i = 0;
115 #if ECMASCRIPT_ENABLE_COMPILER_LOG
116 PrintCallSiteInfo(infos, frame);
117 #endif
118
119 for (auto &info: *infos) {
120 if (info.first == FrameConstants::SP_DWARF_REG_NUM) {
121 uintptr_t rsp = frame->GetCallSiteSp();
122 address = rsp + info.second;
123 } else if (info.first == FrameConstants::FP_DWARF_REG_NUM) {
124 uintptr_t fp = frame->callsiteFp;
125 address = fp + info.second;
126 } else {
127 UNREACHABLE();
128 }
129 if (IsDeriveredPointer(i)) {
130 derived = reinterpret_cast<uintptr_t>(address);
131 if (base == derived) {
132 baseSet.emplace(base);
133 } else {
134 #if ECMASCRIPT_ENABLE_HEAP_VERIFY
135 if (!isVerifying) {
136 #endif
137 data->emplace(std::make_pair(base, derived), *reinterpret_cast<uintptr_t *>(base));
138 #if ECMASCRIPT_ENABLE_HEAP_VERIFY
139 }
140 #endif
141 }
142 } else {
143 base = reinterpret_cast<uintptr_t>(address);
144 }
145 i++;
146 }
147 return true;
148 }
149
PrintCallSiteInfo(const CallSiteInfo * infos,uintptr_t * fp) const150 void LLVMStackMapParser::PrintCallSiteInfo(const CallSiteInfo *infos, uintptr_t *fp) const
151 {
152 int i = 0;
153 uintptr_t address = 0;
154 uintptr_t base = 0;
155 uintptr_t derived = 0;
156
157 uintptr_t callsiteFp = *fp;
158 uintptr_t callsiteSp = *(reinterpret_cast<uintptr_t *>(callsiteFp) + FrameConstants::CALLSITE_SP_TO_FP_DELTA);
159
160 for (auto &info: *infos) {
161 if (info.first == FrameConstants::SP_DWARF_REG_NUM) {
162 address = callsiteSp + info.second;
163 } else if (info.first == FrameConstants::FP_DWARF_REG_NUM) {
164 address = callsiteFp + info.second;
165 } else {
166 UNREACHABLE();
167 }
168
169 if (IsDeriveredPointer(i)) {
170 derived = reinterpret_cast<uintptr_t>(address);
171 if (base == derived) {
172 LOG_ECMA(DEBUG) << std::hex << "visit base:" << base << " base Value: " <<
173 *reinterpret_cast<uintptr_t *>(base);
174 } else {
175 LOG_ECMA(DEBUG) << std::hex << "push base:" << base << " base Value: " <<
176 *reinterpret_cast<uintptr_t *>(base) << " derived:" << derived;
177 }
178 } else {
179 base = reinterpret_cast<uintptr_t>(address);
180 }
181 i++;
182 }
183 }
184
IsDeriveredPointer(int callsitetime) const185 bool LLVMStackMapParser::IsDeriveredPointer(int callsitetime) const
186 {
187 return callsitetime & 1;
188 }
189
CollectStackMapSlots(uintptr_t callSiteAddr,uintptr_t frameFp,std::set<uintptr_t> & baseSet,ChunkMap<DerivedDataKey,uintptr_t> * data,bool isVerifying) const190 bool LLVMStackMapParser::CollectStackMapSlots(uintptr_t callSiteAddr, uintptr_t frameFp,
191 std::set<uintptr_t> &baseSet, ChunkMap<DerivedDataKey, uintptr_t> *data, [[maybe_unused]] bool isVerifying) const
192 {
193 const CallSiteInfo *infos = GetCallSiteInfoByPc(callSiteAddr);
194 if (infos == nullptr) {
195 return false;
196 }
197 uintptr_t *fp = reinterpret_cast<uintptr_t *>(frameFp);
198 uintptr_t address = 0;
199 uintptr_t base = 0;
200 uintptr_t derived = 0;
201 int i = 0;
202 #if ECMASCRIPT_ENABLE_COMPILER_LOG
203 PrintCallSiteInfo(infos, fp);
204 #endif
205 uintptr_t callsiteFp = *fp;
206 uintptr_t callsiteSp = *(reinterpret_cast<uintptr_t *>(callsiteFp) + FrameConstants::CALLSITE_SP_TO_FP_DELTA);
207
208 for (auto &info: *infos) {
209 if (info.first == FrameConstants::SP_DWARF_REG_NUM) {
210 address = callsiteSp + info.second;
211 } else if (info.first == FrameConstants::FP_DWARF_REG_NUM) {
212 address = callsiteFp + info.second;
213 } else {
214 UNREACHABLE();
215 }
216
217 if (IsDeriveredPointer(i)) {
218 derived = reinterpret_cast<uintptr_t>(address);
219 if (base == derived) {
220 baseSet.emplace(base);
221 } else {
222 #if ECMASCRIPT_ENABLE_HEAP_VERIFY
223 if (!isVerifying) {
224 #endif
225 data->emplace(std::make_pair(base, derived), *reinterpret_cast<uintptr_t *>(base));
226 #if ECMASCRIPT_ENABLE_HEAP_VERIFY
227 }
228 #endif
229 }
230 } else {
231 base = reinterpret_cast<uintptr_t>(address);
232 }
233 i++;
234 }
235 return true;
236 }
237
CalcCallSite()238 void LLVMStackMapParser::CalcCallSite()
239 {
240 uint64_t recordNum = 0;
241 auto calStkMapRecordFunc = [this, &recordNum](uintptr_t address, int recordId) {
242 struct StkMapRecordHeadTy recordHead = llvmStackMap_.StkMapRecord[recordNum + recordId].head;
243 for (int j = 0; j < recordHead.NumLocations; j++) {
244 struct LocationTy loc = llvmStackMap_.StkMapRecord[recordNum + recordId].Locations[j];
245 uint32_t instructionOffset = recordHead.InstructionOffset;
246 uintptr_t callsite = address + instructionOffset;
247 uint64_t patchPointID = recordHead.PatchPointID;
248 if (loc.location == LocationTy::Kind::INDIRECT) {
249 #if ECMASCRIPT_ENABLE_COMPILER_LOG
250 LOG_ECMA(DEBUG) << "DwarfRegNum:" << loc.DwarfRegNum << " loc.OffsetOrSmallConstant:" <<
251 loc.OffsetOrSmallConstant << "address:" << address << " instructionOffset:" <<
252 instructionOffset << " callsite:" << " patchPointID :" << std::hex << patchPointID << callsite;
253 #endif
254 DwarfRegAndOffsetType info(loc.DwarfRegNum, loc.OffsetOrSmallConstant);
255 auto it = pc2CallSiteInfo_.find(callsite);
256 if (pc2CallSiteInfo_.find(callsite) == pc2CallSiteInfo_.end()) {
257 pc2CallSiteInfo_.insert(std::pair<uintptr_t, CallSiteInfo>(callsite, {info}));
258 } else {
259 it->second.emplace_back(info);
260 }
261
262 auto it2 = pid2CallSiteInfo_.find(patchPointID);
263 if (pid2CallSiteInfo_.find(patchPointID) == pid2CallSiteInfo_.end()) {
264 pid2CallSiteInfo_.insert(std::pair<uint64_t, CallSiteInfo>(patchPointID,
265 {info}));
266 } else {
267 it2->second.emplace_back(info);
268 }
269 }
270 }
271 };
272 for (size_t i = 0; i < llvmStackMap_.StkSizeRecords.size(); i++) {
273 uintptr_t address = llvmStackMap_.StkSizeRecords[i].functionAddress;
274 uint64_t recordCount = llvmStackMap_.StkSizeRecords[i].recordCount;
275 for (uint64_t k = 0; k < recordCount; k++) {
276 calStkMapRecordFunc(address, k);
277 }
278 recordNum += recordCount;
279 }
280 }
281
CalculateStackMap(std::unique_ptr<uint8_t[]> stackMapAddr)282 bool LLVMStackMapParser::CalculateStackMap(std::unique_ptr<uint8_t []> stackMapAddr)
283 {
284 stackMapAddr_ = std::move(stackMapAddr);
285 if (!stackMapAddr_) {
286 LOG_ECMA(ERROR) << "stackMapAddr_ nullptr error ! " << std::endl;
287 return false;
288 }
289 dataInfo_ = std::make_unique<DataInfo>(std::move(stackMapAddr_));
290 llvmStackMap_.head = dataInfo_->Read<struct Header>();
291 uint32_t numFunctions, numConstants, numRecords;
292 numFunctions = dataInfo_->Read<uint32_t>();
293 numConstants = dataInfo_->Read<uint32_t>();
294 numRecords = dataInfo_->Read<uint32_t>();
295 for (uint32_t i = 0; i < numFunctions; i++) {
296 auto stkRecord = dataInfo_->Read<struct StkSizeRecordTy>();
297 llvmStackMap_.StkSizeRecords.push_back(stkRecord);
298 }
299
300 for (uint32_t i = 0; i < numConstants; i++) {
301 auto val = dataInfo_->Read<struct ConstantsTy>();
302 llvmStackMap_.Constants.push_back(val);
303 }
304 for (uint32_t i = 0; i < numRecords; i++) {
305 struct StkMapRecordTy stkSizeRecord;
306 auto head = dataInfo_->Read<struct StkMapRecordHeadTy>();
307 stkSizeRecord.head = head;
308 for (uint16_t j = 0; j < head.NumLocations; j++) {
309 auto location = dataInfo_->Read<struct LocationTy>();
310 stkSizeRecord.Locations.push_back(location);
311 }
312 uint16_t padding;
313 while (dataInfo_->GetOffset() & 7) { // 7: 8 byte align
314 padding = dataInfo_->Read<uint16_t>();
315 }
316 uint32_t numLiveOuts = dataInfo_->Read<uint32_t>();
317 if (numLiveOuts > 0) {
318 for (uint32_t j = 0; j < numLiveOuts; j++) {
319 auto liveOut = dataInfo_->Read<struct LiveOutsTy>();
320 stkSizeRecord.LiveOuts.push_back(liveOut);
321 }
322 }
323 while (dataInfo_->GetOffset() & 7) { // 7: 8 byte align
324 padding = dataInfo_->Read<uint16_t>();
325 }
326 llvmStackMap_.StkMapRecord.push_back(stkSizeRecord);
327 }
328 CalcCallSite();
329 return true;
330 }
331
CalculateStackMap(std::unique_ptr<uint8_t[]> stackMapAddr,uintptr_t hostCodeSectionAddr,uintptr_t deviceCodeSectionAddr)332 bool LLVMStackMapParser::CalculateStackMap(std::unique_ptr<uint8_t []> stackMapAddr,
333 uintptr_t hostCodeSectionAddr, uintptr_t deviceCodeSectionAddr)
334 {
335 bool ret = CalculateStackMap(std::move(stackMapAddr));
336 if (!ret) {
337 return ret;
338 }
339 // update functionAddress from host side to device side
340 #if ECMASCRIPT_ENABLE_COMPILER_LOG
341 LOG_ECMA(DEBUG) << "stackmap calculate update funcitonaddress ";
342 #endif
343 for (size_t i = 0; i < llvmStackMap_.StkSizeRecords.size(); i++) {
344 uintptr_t hostAddr = llvmStackMap_.StkSizeRecords[i].functionAddress;
345 uintptr_t deviceAddr = hostAddr - hostCodeSectionAddr + deviceCodeSectionAddr;
346 llvmStackMap_.StkSizeRecords[i].functionAddress = deviceAddr;
347 #if ECMASCRIPT_ENABLE_COMPILER_LOG
348 LOG_ECMA(DEBUG) << std::dec << i << "th function " << std::hex << hostAddr << " ---> " << deviceAddr;
349 #endif
350 }
351 pc2CallSiteInfo_.clear();
352 pid2CallSiteInfo_.clear();
353 CalcCallSite();
354 return true;
355 }
356 } // namespace panda::ecmascript::kungfu
357