• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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