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