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/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
GetCallSiteInfoByPc(uintptr_t callSiteAddr) const44 const CallSiteInfo* LLVMStackMapParser::GetCallSiteInfoByPc(uintptr_t callSiteAddr) const
45 {
46 for (auto &pc2CallSiteInfo: pc2CallSiteInfoVec_) {
47 auto it = pc2CallSiteInfo.find(callSiteAddr);
48 if (it != pc2CallSiteInfo.end()) {
49 return &(it->second);
50 }
51 }
52 return nullptr;
53 }
54
CalcCallSite()55 void LLVMStackMapParser::CalcCallSite()
56 {
57 uint64_t recordNum = 0;
58 Pc2CallSiteInfo pc2CallSiteInfo;
59 Pc2Deopt deoptbundles;
60 auto calStkMapRecordFunc =
61 [this, &recordNum, &pc2CallSiteInfo, &deoptbundles](uintptr_t address, uint32_t recordId) {
62 struct StkMapRecordHeadTy recordHead = llvmStackMap_.StkMapRecord[recordNum + recordId].head;
63 int lastDeoptIndex = -1;
64 for (int j = 0; j < recordHead.NumLocations; j++) {
65 struct LocationTy loc = llvmStackMap_.StkMapRecord[recordNum + recordId].Locations[j];
66 uint32_t instructionOffset = recordHead.InstructionOffset;
67 uintptr_t callsite = address + instructionOffset;
68 uint64_t patchPointID = recordHead.PatchPointID;
69 if (j == LocationTy::CONSTANT_DEOPT_CNT_INDEX) {
70 ASSERT(loc.location == LocationTy::Kind::CONSTANT);
71 lastDeoptIndex = loc.OffsetOrSmallConstant + LocationTy::CONSTANT_DEOPT_CNT_INDEX;
72 }
73 if (loc.location == LocationTy::Kind::INDIRECT) {
74 OPTIONAL_LOG_COMPILER(DEBUG) << "DwarfRegNum:" << loc.DwarfRegNum << " loc.OffsetOrSmallConstant:"
75 << loc.OffsetOrSmallConstant << "address:" << address << " instructionOffset:" <<
76 instructionOffset << " callsite:" << " patchPointID :" << std::hex << patchPointID <<
77 callsite;
78 DwarfRegAndOffsetType info(loc.DwarfRegNum, loc.OffsetOrSmallConstant);
79 auto it = pc2CallSiteInfo.find(callsite);
80 if (j > lastDeoptIndex) {
81 if (pc2CallSiteInfo.find(callsite) == pc2CallSiteInfo.end()) {
82 pc2CallSiteInfo.insert(std::pair<uintptr_t, CallSiteInfo>(callsite, {info}));
83 } else {
84 it->second.emplace_back(info);
85 }
86 } else if (j >= LocationTy::CONSTANT_FIRST_ELEMENT_INDEX) {
87 deoptbundles[callsite].push_back(info);
88 }
89 } else if (loc.location == LocationTy::Kind::CONSTANT) {
90 if (j >= LocationTy::CONSTANT_FIRST_ELEMENT_INDEX && j <= lastDeoptIndex) {
91 deoptbundles[callsite].push_back(loc.OffsetOrSmallConstant);
92 }
93 } else if (loc.location == LocationTy::Kind::DIRECT) {
94 if (j >= LocationTy::CONSTANT_FIRST_ELEMENT_INDEX && j <= lastDeoptIndex) {
95 DwarfRegAndOffsetType info(loc.DwarfRegNum, loc.OffsetOrSmallConstant);
96 deoptbundles[callsite].push_back(info);
97 }
98 } else if (loc.location == LocationTy::Kind::CONSTANTNDEX) {
99 if (j >= LocationTy::CONSTANT_FIRST_ELEMENT_INDEX && j <= lastDeoptIndex) {
100 LargeInt v = static_cast<LargeInt>(llvmStackMap_.
101 Constants[loc.OffsetOrSmallConstant].LargeConstant);
102 deoptbundles[callsite].push_back(v);
103 }
104 } else {
105 UNREACHABLE();
106 }
107 }
108 };
109 for (size_t i = 0; i < llvmStackMap_.StkSizeRecords.size(); i++) {
110 // relative offset
111 uintptr_t address = llvmStackMap_.StkSizeRecords[i].functionAddress;
112 uint64_t recordCount = llvmStackMap_.StkSizeRecords[i].recordCount;
113 fun2RecordNum_.emplace_back(std::make_pair(address, recordCount));
114 for (uint64_t k = 0; k < recordCount; k++) {
115 calStkMapRecordFunc(address, k);
116 }
117 recordNum += recordCount;
118 }
119 pc2CallSiteInfoVec_.emplace_back(pc2CallSiteInfo);
120 pc2DeoptVec_.emplace_back(deoptbundles);
121 }
122
CalculateStackMap(std::unique_ptr<uint8_t[]> stackMapAddr)123 bool LLVMStackMapParser::CalculateStackMap(std::unique_ptr<uint8_t []> stackMapAddr)
124 {
125 if (!stackMapAddr) {
126 LOG_COMPILER(ERROR) << "stackMapAddr nullptr error ! ";
127 return false;
128 }
129 dataInfo_ = std::make_unique<DataInfo>(std::move(stackMapAddr));
130 llvmStackMap_.head = dataInfo_->Read<struct Header>();
131 uint32_t numFunctions, numConstants, numRecords;
132 numFunctions = dataInfo_->Read<uint32_t>();
133 numConstants = dataInfo_->Read<uint32_t>();
134 numRecords = dataInfo_->Read<uint32_t>();
135 for (uint32_t i = 0; i < numFunctions; i++) {
136 auto stkRecord = dataInfo_->Read<struct StkSizeRecordTy>();
137 llvmStackMap_.StkSizeRecords.push_back(stkRecord);
138 }
139
140 for (uint32_t i = 0; i < numConstants; i++) {
141 auto val = dataInfo_->Read<struct ConstantsTy>();
142 llvmStackMap_.Constants.push_back(val);
143 }
144 for (uint32_t i = 0; i < numRecords; i++) {
145 struct StkMapRecordTy stkSizeRecord;
146 auto head = dataInfo_->Read<struct StkMapRecordHeadTy>();
147 stkSizeRecord.head = head;
148 for (uint16_t j = 0; j < head.NumLocations; j++) {
149 auto location = dataInfo_->Read<struct LocationTy>();
150 stkSizeRecord.Locations.push_back(location);
151 }
152 while (dataInfo_->GetOffset() & 7) { // 7: 8 byte align
153 dataInfo_->Read<uint16_t>();
154 }
155 uint32_t numLiveOuts = dataInfo_->Read<uint32_t>();
156 if (numLiveOuts > 0) {
157 for (uint32_t j = 0; j < numLiveOuts; j++) {
158 auto liveOut = dataInfo_->Read<struct LiveOutsTy>();
159 stkSizeRecord.LiveOuts.push_back(liveOut);
160 }
161 }
162 while (dataInfo_->GetOffset() & 7) { // 7: 8 byte align
163 dataInfo_->Read<uint16_t>();
164 }
165 llvmStackMap_.StkMapRecord.push_back(stkSizeRecord);
166 }
167 CalcCallSite();
168 return true;
169 }
170
CalHeadSize() const171 uint32_t ARKCallsite::CalHeadSize() const
172 {
173 uint32_t headSize = sizeof(head);
174 return headSize;
175 }
176
CalStackMapSize() const177 uint32_t ARKCallsite::CalStackMapSize() const
178 {
179 size_t stackmapSize = stackmaps.size() * (sizeof(OffsetType) + sizeof(DwarfRegType));
180 return stackmapSize;
181 }
182
CalculateStackMap(std::unique_ptr<uint8_t[]> stackMapAddr,uintptr_t hostCodeSectionAddr)183 bool LLVMStackMapParser::CalculateStackMap(std::unique_ptr<uint8_t []> stackMapAddr,
184 uintptr_t hostCodeSectionAddr)
185 {
186 bool ret = CalculateStackMap(std::move(stackMapAddr));
187 if (!ret) {
188 return false;
189 }
190
191 OPTIONAL_LOG_COMPILER(DEBUG) << "stackmap calculate update funcitonaddress ";
192
193 for (size_t i = 0; i < llvmStackMap_.StkSizeRecords.size(); i++) {
194 uintptr_t hostAddr = llvmStackMap_.StkSizeRecords[i].functionAddress;
195 uintptr_t offset = hostAddr - hostCodeSectionAddr;
196 llvmStackMap_.StkSizeRecords[i].functionAddress = offset;
197 OPTIONAL_LOG_COMPILER(DEBUG) << std::dec << i << "th function " << std::hex << hostAddr << " ---> "
198 << " offset:" << offset;
199 }
200 pc2CallSiteInfoVec_.clear();
201 fun2RecordNum_.clear();
202 pc2DeoptVec_.clear();
203 CalcCallSite();
204 return true;
205 }
206
CalculateFuncFpDelta(Func2FpDelta info,uint32_t moduleIndex)207 void LLVMStackMapParser::CalculateFuncFpDelta(Func2FpDelta info, uint32_t moduleIndex)
208 {
209 std::vector<Func2FpDelta> fun2FpDelta;
210 auto it = module2fun2FpDelta_.find(moduleIndex);
211 if (it != module2fun2FpDelta_.end()) {
212 fun2FpDelta = module2fun2FpDelta_.at(moduleIndex);
213 }
214 bool find = std::find(fun2FpDelta.begin(), fun2FpDelta.end(), info) == fun2FpDelta.end();
215 if (!info.empty() && find) {
216 fun2FpDelta.emplace_back(info);
217 }
218 module2fun2FpDelta_.erase(moduleIndex);
219 module2fun2FpDelta_[moduleIndex] = fun2FpDelta;
220
221 std::set<uintptr_t> funAddr;
222 auto i = module2funAddr_.find(moduleIndex);
223 if (i != module2funAddr_.end()) {
224 funAddr = module2funAddr_.at(moduleIndex);
225 module2funAddr_.erase(moduleIndex);
226 }
227 for (auto &iterator: info) {
228 funAddr.insert(iterator.first);
229 }
230 module2funAddr_[moduleIndex] = funAddr;
231 }
232 } // namespace panda::ecmascript::kungfu
233