• 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 #include "ecmascript/stackmap/llvm/llvm_stackmap_parser.h"
16 
17 using namespace panda::ecmascript;
18 
19 namespace panda::ecmascript::kungfu {
TypeToString(Kind loc) const20 std::string LocationTy::TypeToString(Kind loc) const
21 {
22     switch (loc) {
23         case Kind::REGISTER:
24             return "Register	Reg	Value in a register";
25         case Kind::DIRECT:
26             return "Direct	Reg + Offset	Frame index value";
27         case Kind::INDIRECT:
28             return "Indirect	[Reg + Offset]	Spilled value";
29         case Kind::CONSTANT:
30             return "Constant	Offset	Small constant";
31         case Kind::CONSTANTNDEX:
32             return "ConstIndex	constants[Offset]	Large constant";
33         default:
34             return "no know location";
35     }
36 }
37 
FilterCallSiteInfo(LLVMStackMapType::CallSiteInfo & info)38 void LLVMStackMapParser::FilterCallSiteInfo(LLVMStackMapType::CallSiteInfo &info)
39 {
40     ASSERT(GC_PAIR_SIZE == 2); // 2 : The expected value of GC_PAIR_SIZE is 2
41     ASSERT(info.size() % GC_PAIR_SIZE == 0);
42     for (auto it = info.begin(); it != info.end();) {
43         auto base = it;
44         auto deri = ++it;
45         bool baseIsConst = (base->first == LLVMStackMapType::INVALID_DWARF_REG);
46         bool deriIsConst = (deri->first == LLVMStackMapType::INVALID_DWARF_REG);
47         if (baseIsConst && deriIsConst) {
48             it = info.erase(base, base + GC_PAIR_SIZE);
49         } else if (baseIsConst && !deriIsConst) {
50             base->first = deri->first;
51             base->second = deri->second;
52             it++;
53         } else if (!baseIsConst && deriIsConst) {
54             deri->first = base->first;
55             deri->second = base->second;
56             it++;
57         } else {
58             it++;
59         }
60     }
61     ASSERT(info.size() % GC_PAIR_SIZE == 0);
62 }
63 
CalcCallSite()64 void LLVMStackMapParser::CalcCallSite()
65 {
66     uint64_t recordNum = 0;
67     LLVMStackMapType::Pc2CallSiteInfo pc2CallSiteInfo;
68     LLVMStackMapType::Pc2Deopt deoptbundles;
69 
70     auto calStkMapRecordFunc = [this, &recordNum, &pc2CallSiteInfo, &deoptbundles](uintptr_t address,
71                                                                                    uint32_t recordId) {
72         struct StkMapRecordTy &record = llvmStackMap_.stkMapRecord[recordNum + recordId];
73         struct StkMapRecordHeadTy &recordHead = record.head;
74         uint32_t instructionOffset = recordHead.instructionOffset;
75         uintptr_t pc = address + instructionOffset;
76         uint64_t pID = recordHead.patchPointID;
77 
78         if (pc2CallSiteInfo.find(pc) == pc2CallSiteInfo.end()) {
79             auto p = std::pair<uintptr_t, LLVMStackMapType::CallSiteInfo>(pc, {});
80             pc2CallSiteInfo.insert(p);
81         }
82         LLVMStackMapType::CallSiteInfo& callSiteInfo = pc2CallSiteInfo.find(pc)->second;
83 
84         ASSERT(recordHead.numLocations > LocationTy::CONSTANT_DEOPT_CNT_INDEX);
85         const int lastDeoptIndex = record.locations[LocationTy::CONSTANT_DEOPT_CNT_INDEX].offsetOrSmallConstant +
86                                    LocationTy::CONSTANT_DEOPT_CNT_INDEX;
87 
88         for (int j = LocationTy::CONSTANT_FIRST_ELEMENT_INDEX; j < recordHead.numLocations; j++) {
89             const struct LocationTy &loc = record.locations[j];
90             if (j <= lastDeoptIndex) {
91                 switch (loc.location) {
92                     case LocationTy::Kind::REGISTER:
93                     case LocationTy::Kind::DIRECT: {
94                         LOG_ECMA(FATAL) << "this branch is unreachable";
95                         UNREACHABLE();
96                         break;
97                     }
98                     case LocationTy::Kind::INDIRECT: {
99                         OPTIONAL_LOG_COMPILER(DEBUG) << "DwarfRegNum:" << loc.dwarfRegNum
100                                                      << " loc.OffsetOrSmallConstant:" << loc.offsetOrSmallConstant
101                                                      << " address:" << address
102                                                      << " instructionOffset:" << instructionOffset
103                                                      << " callsite:" << "  patchPointID :" << std::hex
104                                                      << pID << pc;
105                         LLVMStackMapType::DwarfRegAndOffsetType info(loc.dwarfRegNum, loc.offsetOrSmallConstant);
106                         deoptbundles[pc].push_back(info);
107                         break;
108                     }
109                     case LocationTy::Kind::CONSTANT: {
110                         deoptbundles[pc].push_back(loc.offsetOrSmallConstant);
111                         break;
112                     }
113                     case LocationTy::Kind::CONSTANTNDEX: {
114                         auto v = llvmStackMap_.constants[loc.offsetOrSmallConstant].largeConstant;
115                         deoptbundles[pc].push_back(static_cast<LLVMStackMapType::LargeInt>(v));
116                         break;
117                     }
118                     default: {
119                         LOG_ECMA(FATAL) << "this branch is unreachable";
120                         UNREACHABLE();
121                         break;
122                     }
123                 }
124             } else {
125                 switch (loc.location) {
126                     case LocationTy::Kind::REGISTER:
127                     case LocationTy::Kind::DIRECT: {
128                         LOG_ECMA(FATAL) << "this branch is unreachable";
129                         UNREACHABLE();
130                         break;
131                     }
132                     case LocationTy::Kind::INDIRECT:
133                     case LocationTy::Kind::CONSTANT:
134                     case LocationTy::Kind::CONSTANTNDEX: {
135                         OPTIONAL_LOG_COMPILER(DEBUG) << "DwarfRegNum:" << loc.dwarfRegNum
136                                                      << " loc.OffsetOrSmallConstant:" << loc.offsetOrSmallConstant
137                                                      << " address:" << address
138                                                      << " instructionOffset:" << instructionOffset
139                                                      << " callsite:" << "  patchPointID :" << std::hex
140                                                      << pID << pc;
141                         uint16_t regNum = (loc.location == LocationTy::Kind::INDIRECT)
142                                           ? loc.dwarfRegNum
143                                           : LLVMStackMapType::INVALID_DWARF_REG;
144                         int offset = (loc.location == LocationTy::Kind::INDIRECT) ? loc.offsetOrSmallConstant : 0;
145                         LLVMStackMapType::DwarfRegAndOffsetType info(regNum, offset);
146                         callSiteInfo.emplace_back(info);
147                         break;
148                     }
149                     default: {
150                         LOG_ECMA(FATAL) << "this branch is unreachable";
151                         UNREACHABLE();
152                         break;
153                     }
154                 }
155             }
156         }
157         FilterCallSiteInfo(callSiteInfo);
158     };
159 
160     const size_t count = llvmStackMap_.stkSizeRecords.size();
161     for (size_t i = 0; i < count; i++) {
162         // relative offset
163         struct StkMapSizeRecordTy &sizeRec = llvmStackMap_.stkSizeRecords[i];
164         uintptr_t address = sizeRec.functionAddress;
165         uint64_t recordCount = sizeRec.recordCount;
166         fun2RecordNum_.emplace_back(std::make_pair(address, recordCount));
167         for (uint64_t k = 0; k < recordCount; k++) {
168             calStkMapRecordFunc(address, k);
169         }
170         recordNum += recordCount;
171     }
172 
173     stackMapInfo.AppendCallSiteInfo(pc2CallSiteInfo);
174     stackMapInfo.AppendDeoptInfo(deoptbundles);
175 }
176 
CalculateStackMap(std::unique_ptr<uint8_t[]> stackMapAddr)177 bool LLVMStackMapParser::CalculateStackMap(std::unique_ptr<uint8_t []> stackMapAddr)
178 {
179     if (!stackMapAddr) {
180         LOG_COMPILER(ERROR) << "stackMapAddr nullptr error ! ";
181         return false;
182     }
183     dataInfo_ = std::make_unique<DataInfo>(std::move(stackMapAddr));
184     llvmStackMap_.head = dataInfo_->Read<struct Header>();
185     uint32_t numFunctions = dataInfo_->Read<uint32_t>();
186     uint32_t numConstants = dataInfo_->Read<uint32_t>();
187     uint32_t numRecords = dataInfo_->Read<uint32_t>();
188     for (uint32_t i = 0; i < numFunctions; i++) {
189         auto stkRecord = dataInfo_->Read<struct StkMapSizeRecordTy>();
190         llvmStackMap_.stkSizeRecords.push_back(stkRecord);
191     }
192 
193     for (uint32_t i = 0; i < numConstants; i++) {
194         auto val = dataInfo_->Read<struct ConstantsTy>();
195         llvmStackMap_.constants.push_back(val);
196     }
197     for (uint32_t i = 0; i < numRecords; i++) {
198         struct StkMapRecordTy stkSizeRecord;
199         auto head = dataInfo_->Read<struct StkMapRecordHeadTy>();
200         stkSizeRecord.head = head;
201         for (uint16_t j = 0; j < head.numLocations; j++) {
202             auto location = dataInfo_->Read<struct LocationTy>();
203             stkSizeRecord.locations.push_back(location);
204         }
205         while (dataInfo_->GetOffset() & 7) { // 7: 8 byte align
206             dataInfo_->Read<uint16_t>();
207         }
208         uint32_t numLiveOuts = dataInfo_->Read<uint32_t>();
209         if (numLiveOuts > 0) {
210             for (uint32_t j = 0; j < numLiveOuts; j++) {
211                 auto liveOut = dataInfo_->Read<struct LiveOutsTy>();
212                 stkSizeRecord.liveOuts.push_back(liveOut);
213             }
214         }
215         while (dataInfo_->GetOffset() & 7) { // 7: 8 byte align
216             dataInfo_->Read<uint16_t>();
217         }
218         llvmStackMap_.stkMapRecord.push_back(stkSizeRecord);
219     }
220     CalcCallSite();
221     return true;
222 }
223 
CalHeadSize() const224 uint32_t ARKCallsite::CalHeadSize() const
225 {
226     uint32_t headSize = sizeof(head);
227     return headSize;
228 }
229 
CalStackMapSize(Triple triple,size_t & stackmapNumReduced) const230 uint32_t ARKCallsite::CalStackMapSize(Triple triple, size_t &stackmapNumReduced) const
231 {
232     size_t stackmapSize = 0;
233     size_t stackmapsNum = stackmaps.size();
234     for (size_t i = 0; i < stackmapsNum; i += LLVMStackMapType::STACKMAP_PAIR_SIZE) {
235         std::vector<uint8_t> valBase;
236         size_t valSizeBase = 0;
237         auto &stackmapBase = stackmaps.at(i);
238         auto &stackmapDerived = stackmaps.at(i + 1);
239         LLVMStackMapType::EncodeRegAndOffset(valBase, valSizeBase, stackmapBase.first, stackmapBase.second, triple);
240         stackmapSize += valBase.size();
241         if (stackmapBase.first != stackmapDerived.first || stackmapBase.second != stackmapDerived.second) {
242             std::vector<uint8_t> valDerived;
243             size_t valSizeDerived = 0;
244             LLVMStackMapType::EncodeRegAndOffset(valDerived, valSizeDerived, stackmapDerived.first,
245                 stackmapDerived.second, triple);
246             stackmapSize += valDerived.size();
247         } else {
248         // base ref, base ref and derived ref equal ===> remove repeated derived ref reg&offset
249             stackmapNumReduced++;
250         }
251     }
252     return stackmapSize;
253 }
254 
CalculateStackMap(std::unique_ptr<uint8_t[]> stackMapAddr,uintptr_t hostCodeSectionAddr,uintptr_t hostCodeSectionOffset)255 bool LLVMStackMapParser::CalculateStackMap(std::unique_ptr<uint8_t []> stackMapAddr,
256     uintptr_t hostCodeSectionAddr, uintptr_t hostCodeSectionOffset)
257 {
258     bool ret = CalculateStackMap(std::move(stackMapAddr));
259     if (!ret) {
260         return false;
261     }
262 
263     OPTIONAL_LOG_COMPILER(DEBUG) << "stackmap calculate update funcitonaddress ";
264 
265     for (size_t i = 0; i < llvmStackMap_.stkSizeRecords.size(); i++) {
266         uintptr_t hostAddr = llvmStackMap_.stkSizeRecords[i].functionAddress;
267         uintptr_t offset = hostAddr - hostCodeSectionAddr + hostCodeSectionOffset;
268         llvmStackMap_.stkSizeRecords[i].functionAddress = offset;
269         OPTIONAL_LOG_COMPILER(DEBUG) << std::dec << i << "th function " << std::hex << hostAddr << " ---> "
270                                      << " offset:" << offset;
271     }
272     stackMapInfo.PopCallSiteInfo();
273     stackMapInfo.PopDeoptInfo();
274     fun2RecordNum_.clear();
275     CalcCallSite();
276     return true;
277 }
278 }  // namespace panda::ecmascript::kungfu
279