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