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