• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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/ark_stackmap_parser.h"
16 
17 #include "ecmascript/compiler/aot_file/aot_file_manager.h"
18 #include "ecmascript/compiler/assembler/assembler.h"
19 #include "ecmascript/deoptimizer/deoptimizer.h"
20 #include "ecmascript/stackmap/ark_stackmap_builder.h"
21 
22 namespace panda::ecmascript::kungfu {
23 // implement simple binary-search is improve performance. if use std api, it'll trigger copy CallsiteHeader.
BinaraySearch(CallsiteHeader * callsiteHead,uint32_t callsiteNum,uintptr_t callSiteAddr) const24 int ArkStackMapParser::BinaraySearch(CallsiteHeader *callsiteHead, uint32_t callsiteNum, uintptr_t callSiteAddr) const
25 {
26     int slow = 0;
27     int high = static_cast<int>(callsiteNum) - 1;
28     int mid = 0;
29     uint32_t v = 0;
30     while (slow <= high) {
31         mid = (slow + high) >> 1;
32         v = callsiteHead[mid].calliteOffset;
33         if (v == callSiteAddr) {
34             return mid;
35         } else if (v > callSiteAddr) {
36             high = mid - 1;
37         } else {
38             slow = mid + 1;
39         }
40     }
41     return -1;
42 }
43 
GetArkDeopt(uint8_t * stackmapAddr,const CallsiteHeader & callsiteHead,std::vector<ARKDeopt> & deopts) const44 void ArkStackMapParser::GetArkDeopt(uint8_t *stackmapAddr,
45     const CallsiteHeader& callsiteHead, std::vector<ARKDeopt>& deopts) const
46 {
47     ParseArkDeopt(callsiteHead, stackmapAddr, deopts);
48 }
49 
GetArkDeopt(uintptr_t callSiteAddr,uint8_t * stackmapAddr,std::vector<ARKDeopt> & deopts) const50 void ArkStackMapParser::GetArkDeopt(uintptr_t callSiteAddr, uint8_t *stackmapAddr,
51     std::vector<ARKDeopt>& deopts) const
52 {
53     ArkStackMapHeader *head = reinterpret_cast<ArkStackMapHeader *>(stackmapAddr);
54     ASSERT(head != nullptr);
55     if (head == nullptr) {
56         return;
57     }
58     uint32_t callsiteNum = head->callsiteNum;
59 
60     CallsiteHeader *callsiteHead = reinterpret_cast<CallsiteHeader *>(stackmapAddr + sizeof(ArkStackMapHeader));
61     int mid = BinaraySearch(callsiteHead, callsiteNum, callSiteAddr);
62     if (mid == -1) {
63         return;
64     }
65     CallsiteHeader *found = callsiteHead + mid;
66     GetArkDeopt(stackmapAddr, *found, deopts);
67 }
68 
GetConstInfo(uintptr_t callSiteAddr,LLVMStackMapType::ConstInfo & info,uint8_t * stackmapAddr) const69 void ArkStackMapParser::GetConstInfo(uintptr_t callSiteAddr, LLVMStackMapType::ConstInfo& info,
70     uint8_t *stackmapAddr) const
71 {
72     std::vector<ARKDeopt> deopts;
73     GetArkDeopt(callSiteAddr, stackmapAddr, deopts);
74     if (deopts.empty()) {
75         return;
76     }
77 
78     ARKDeopt target;
79     LLVMStackMapType::VRegId id = static_cast<LLVMStackMapType::VRegId>(SpecVregIndex::PC_OFFSET_INDEX);
80     target.id = id;
81     auto it = std::lower_bound(deopts.begin(), deopts.end(), target,
82         [](const ARKDeopt& a, const ARKDeopt& b) {
83             return a.id < b.id;
84         });
85     if (it == deopts.end() || (it->id > id)) {
86         return;
87     }
88     ASSERT(it->kind == LocationTy::Kind::CONSTANT);
89     ASSERT(std::holds_alternative<LLVMStackMapType::IntType>(it->value));
90     auto v = std::get<LLVMStackMapType::IntType>(it->value);
91     info.emplace_back(v);
92 }
93 
GetStackSlotAddress(const LLVMStackMapType::DwarfRegAndOffsetType info,uintptr_t callSiteSp,uintptr_t callsiteFp) const94 uintptr_t ArkStackMapParser::GetStackSlotAddress(const LLVMStackMapType::DwarfRegAndOffsetType info,
95     uintptr_t callSiteSp, uintptr_t callsiteFp) const
96 {
97     uintptr_t address = 0;
98     if (info.first == GCStackMapRegisters::SP) {
99         address = callSiteSp + info.second;
100     } else if (info.first == GCStackMapRegisters::FP) {
101         address = callsiteFp + info.second;
102     } else {
103         LOG_ECMA(FATAL) << "this branch is unreachable";
104         UNREACHABLE();
105     }
106     return address;
107 }
108 
IteratorStackMap(const RootVisitor & visitor,const RootBaseAndDerivedVisitor & derivedVisitor,uintptr_t callSiteAddr,uintptr_t callsiteFp,uintptr_t callSiteSp,uint8_t * stackmapAddr) const109 bool ArkStackMapParser::IteratorStackMap(const RootVisitor& visitor, const RootBaseAndDerivedVisitor& derivedVisitor,
110     uintptr_t callSiteAddr, uintptr_t callsiteFp, uintptr_t callSiteSp, uint8_t *stackmapAddr) const
111 {
112     ArkStackMapHeader *head = reinterpret_cast<ArkStackMapHeader *>(stackmapAddr);
113     ASSERT(head != nullptr);
114     uint32_t callsiteNum = head->callsiteNum;
115     ArkStackMap arkStackMap;
116     // BuiltinsStub current only sample stub, don't have stackmap&deopt.
117     if (callsiteNum == 0) {
118         return false;
119     }
120 
121     CallsiteHeader *callsiteHead = reinterpret_cast<CallsiteHeader *>(stackmapAddr + sizeof(ArkStackMapHeader));
122     int mid = BinaraySearch(callsiteHead, callsiteNum, callSiteAddr);
123     if (mid == -1) {
124         return false;
125     }
126     CallsiteHeader *found = callsiteHead + mid;
127     ParseArkStackMap(*found, stackmapAddr, arkStackMap);
128     if (arkStackMap.size() == 0) {
129         return false;
130     }
131     ASSERT(callsiteFp != callSiteSp);
132     std::map<uintptr_t, uintptr_t> baseSet;
133     for (size_t i = 0; i < arkStackMap.size(); i += 2) { // 2:base and derive
134         const LLVMStackMapType::DwarfRegAndOffsetType baseInfo = arkStackMap.at(i);
135         const LLVMStackMapType::DwarfRegAndOffsetType derivedInfo = arkStackMap.at(i + 1);
136         uintptr_t base = GetStackSlotAddress(baseInfo, callSiteSp, callsiteFp);
137         uintptr_t derived = GetStackSlotAddress(derivedInfo, callSiteSp, callsiteFp);
138         if (*reinterpret_cast<uintptr_t *>(base) == 0) {
139             base = derived;
140         }
141         if (*reinterpret_cast<uintptr_t *>(base) != 0) {
142             // The base address may be marked repeatedly
143             if (baseSet.find(base) == baseSet.end()) {
144                 baseSet.emplace(base, *reinterpret_cast<uintptr_t *>(base));
145                 visitor(Root::ROOT_FRAME, ObjectSlot(base));
146             }
147 
148             if (base != derived) {
149                 derivedVisitor(Root::ROOT_FRAME, ObjectSlot(base), ObjectSlot(derived), baseSet[base]);
150             }
151         }
152     }
153     baseSet.clear();
154     return true;
155 }
156 
ParseArkStackMap(const CallsiteHeader & callsiteHead,uint8_t * ptr,ArkStackMap & arkStackMaps) const157 void ArkStackMapParser::ParseArkStackMap(const CallsiteHeader& callsiteHead, uint8_t *ptr,
158     ArkStackMap& arkStackMaps) const
159 {
160     LLVMStackMapType::DwarfRegType reg;
161     LLVMStackMapType::OffsetType offsetType;
162     uint32_t offset = callsiteHead.stackmapOffset;
163     uint16_t stackmapNum = callsiteHead.stackmapNum;
164     ASSERT(stackmapNum % 2 == 0); // 2:base and derive
165     for (uint32_t j = 0; j < stackmapNum; j++) {
166         auto [regOffset, regOffsetSize, is_full] =
167             panda::leb128::DecodeSigned<LLVMStackMapType::SLeb128Type>(ptr + offset);
168         LLVMStackMapType::DecodeRegAndOffset(regOffset, reg, offsetType);
169         offset += regOffsetSize;
170         LOG_COMPILER(VERBOSE) << " reg: " << std::dec << reg << " offset:" <<  offsetType;
171         arkStackMaps.emplace_back(std::make_pair(reg, offsetType));
172     }
173     offset = AlignUp(offset, LLVMStackMapType::STACKMAP_ALIGN_BYTES);
174 }
175 
ParseArkDeopt(const CallsiteHeader & callsiteHead,uint8_t * ptr,std::vector<ARKDeopt> & deopts) const176 void ArkStackMapParser::ParseArkDeopt(const CallsiteHeader& callsiteHead, uint8_t *ptr,
177     std::vector<ARKDeopt> &deopts) const
178 {
179     ARKDeopt deopt;
180     uint32_t deoptOffset = callsiteHead.deoptOffset;
181     uint16_t deoptNum = callsiteHead.deoptNum;
182     LLVMStackMapType::KindType kindType;
183     LLVMStackMapType::DwarfRegType reg;
184     LLVMStackMapType::OffsetType offsetType;
185     ASSERT(deoptNum % 2 == 0); // 2:<id, value>
186     for (uint32_t j = 0; j < deoptNum; j += 2) { // 2:<id, value>
187         auto [vregsInfo, vregsInfoSize, InfoIsFull] =
188             panda::leb128::DecodeSigned<LLVMStackMapType::SLeb128Type>(ptr + deoptOffset);
189         LLVMStackMapType::DecodeVRegsInfo(vregsInfo, deopt.id, kindType);
190         deoptOffset += vregsInfoSize;
191         ASSERT(kindType == LLVMStackMapType::CONSTANT_TYPE || kindType == LLVMStackMapType::OFFSET_TYPE);
192         if (kindType == LLVMStackMapType::CONSTANT_TYPE) {
193             auto [constant, constantSize, constIsFull] =
194                 panda::leb128::DecodeSigned<LLVMStackMapType::SLeb128Type>(ptr + deoptOffset);
195             if (constant > INT32_MAX || constant < INT32_MIN) {
196                 deopt.kind = LocationTy::Kind::CONSTANTNDEX;
197                 deopt.value = static_cast<LLVMStackMapType::LargeInt>(constant);
198             } else {
199                 deopt.kind = LocationTy::Kind::CONSTANT;
200                 deopt.value = static_cast<LLVMStackMapType::IntType>(constant);
201             }
202             deoptOffset += constantSize;
203         } else {
204             auto [regOffset, regOffsetSize, regOffIsFull] =
205                 panda::leb128::DecodeSigned<LLVMStackMapType::SLeb128Type>(ptr + deoptOffset);
206             LLVMStackMapType::DecodeRegAndOffset(regOffset, reg, offsetType);
207             deopt.kind = LocationTy::Kind::INDIRECT;
208             deopt.value = std::make_pair(reg, offsetType);
209             deoptOffset += regOffsetSize;
210         }
211         deopts.emplace_back(deopt);
212     }
213 }
214 
ParseArkStackMapAndDeopt(uint8_t * ptr,uint32_t length) const215 void ArkStackMapParser::ParseArkStackMapAndDeopt(uint8_t *ptr, uint32_t length) const
216 {
217     CallsiteHeader callsiteHead;
218     ArkStackMapHeader secHead;
219     BinaryBufferParser binBufparser(ptr, length);
220     binBufparser.ParseBuffer(&secHead, sizeof(ArkStackMapHeader));
221     for (uint32_t i = 0; i < secHead.callsiteNum; i++) {
222         binBufparser.ParseBuffer(&callsiteHead, sizeof(CallsiteHeader));
223         std::vector<ARKDeopt> deopts;
224         ArkStackMap arkStackMaps;
225         LOG_COMPILER(VERBOSE) << " calliteOffset:0x" << std::hex << callsiteHead.calliteOffset
226                               << " stackmap offset:0x" << std::hex << callsiteHead.stackmapOffset
227                               << " num:" << callsiteHead.stackmapNum
228                               << " deopt Offset:0x" << std::hex << callsiteHead.deoptOffset
229                               << " num:" << callsiteHead.deoptNum;
230         ParseArkStackMap(callsiteHead, ptr, arkStackMaps);
231         ParseArkDeopt(callsiteHead, ptr, deopts);
232     }
233 }
234 } // namespace panda::ecmascript::kungfu