• 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/deoptimizer/deoptimizer.h"
19 
20 namespace panda::ecmascript::kungfu {
21 
ParseArkDeopt(const CallsiteHeader & callsiteHead,uint8_t * ptr,std::vector<ARKDeopt> & deopts) const22 void ArkStackMapParser::ParseArkDeopt(const CallsiteHeader& callsiteHead,
23                                       uint8_t *ptr,
24                                       std::vector<ARKDeopt> &deopts) const
25 {
26     ARKDeopt deopt;
27     uint32_t deoptOffset = callsiteHead.deoptOffset;
28     uint16_t deoptNum = callsiteHead.deoptNum;
29     LLVMStackMapType::KindType kindType;
30     LLVMStackMapType::DwarfRegType reg;
31     LLVMStackMapType::OffsetType offsetType;
32     ASSERT(deoptNum % DEOPT_ENTRY_SIZE == 0); // 2:<id, value>
33     for (uint32_t j = 0; j < deoptNum; j += DEOPT_ENTRY_SIZE) { // DEOPT_ENTRY_SIZE:<id, value>
34         auto [vregsInfo, vregsInfoSize, InfoIsFull] =
35             panda::leb128::DecodeSigned<LLVMStackMapType::SLeb128Type>(ptr + deoptOffset);
36         LLVMStackMapType::DecodeVRegsInfo(vregsInfo, deopt.id, kindType);
37         deoptOffset += vregsInfoSize;
38         ASSERT(kindType == LLVMStackMapType::CONSTANT_TYPE || kindType == LLVMStackMapType::OFFSET_TYPE);
39         if (kindType == LLVMStackMapType::CONSTANT_TYPE) {
40             auto [constant, constantSize, constIsFull] =
41                 panda::leb128::DecodeSigned<LLVMStackMapType::SLeb128Type>(ptr + deoptOffset);
42             if (constant > INT32_MAX || constant < INT32_MIN) {
43                 deopt.kind = LocationTy::Kind::CONSTANTNDEX;
44                 deopt.value = static_cast<LLVMStackMapType::LargeInt>(constant);
45             } else {
46                 deopt.kind = LocationTy::Kind::CONSTANT;
47                 deopt.value = static_cast<LLVMStackMapType::IntType>(constant);
48             }
49             deoptOffset += constantSize;
50         } else {
51             auto [regOffset, regOffsetSize, regOffIsFull] =
52                 panda::leb128::DecodeSigned<LLVMStackMapType::SLeb128Type>(ptr + deoptOffset);
53             LLVMStackMapType::DecodeRegAndOffset(regOffset, reg, offsetType);
54             deopt.kind = LocationTy::Kind::INDIRECT;
55             deopt.value = std::make_pair(reg, offsetType);
56             deoptOffset += regOffsetSize;
57         }
58         deopts.emplace_back(deopt);
59     }
60 }
61 
GetArkDeopt(uint8_t * stackmapAddr,const CallsiteHeader & callsiteHead,std::vector<ARKDeopt> & deopts) const62 void ArkStackMapParser::GetArkDeopt(uint8_t *stackmapAddr,
63                                     const CallsiteHeader& callsiteHead,
64                                     std::vector<ARKDeopt>& deopts) const
65 {
66     ParseArkDeopt(callsiteHead, stackmapAddr, deopts);
67 }
68 
69 // 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) const70 int ArkStackMapParser::BinaraySearch(CallsiteHeader *callsiteHead, uint32_t callsiteNum, uintptr_t callSiteAddr) const
71 {
72     int low = 0;
73     int high = static_cast<int>(callsiteNum) - 1;
74     int mid = 0;
75     uint32_t v = 0;
76     while (low <= high) {
77         mid = (low + high) / BINARY_SEARCH_DIVISOR;
78         v = callsiteHead[mid].calliteOffsetInTxtSec;
79         if (v == callSiteAddr) {
80             return mid;
81         } else if (v > callSiteAddr) {
82             high = mid - 1;
83         } else {
84             low = mid + 1;
85         }
86     }
87     return -1;
88 }
89 
GetArkDeopt(uintptr_t callSiteAddr,uint8_t * stackmapAddr,std::vector<ARKDeopt> & deopts) const90 void ArkStackMapParser::GetArkDeopt(uintptr_t callSiteAddr,
91                                     uint8_t *stackmapAddr,
92                                     std::vector<ARKDeopt>& deopts) const
93 {
94     ArkStackMapHeader *head = reinterpret_cast<ArkStackMapHeader *>(stackmapAddr);
95     ASSERT(head != nullptr);
96     if (head == nullptr) {
97         return;
98     }
99     uint32_t callsiteNum = head->callsiteNum;
100 
101     CallsiteHeader *callsiteHead = reinterpret_cast<CallsiteHeader *>(stackmapAddr + sizeof(ArkStackMapHeader));
102     int mid = BinaraySearch(callsiteHead, callsiteNum, callSiteAddr);
103     ASSERT(mid != -1);
104     if (mid == -1) {
105         return;
106     }
107     CallsiteHeader *found = callsiteHead + mid;
108     GetArkDeopt(stackmapAddr, *found, deopts);
109 }
110 
GetStackSlotAddress(const LLVMStackMapType::DwarfRegAndOffsetType info,uintptr_t callSiteSp,uintptr_t callsiteFp) const111 uintptr_t ArkStackMapParser::GetStackSlotAddress(const LLVMStackMapType::DwarfRegAndOffsetType info,
112                                                  uintptr_t callSiteSp,
113                                                  uintptr_t callsiteFp) const
114 {
115     uintptr_t address = 0;
116     if (info.first == GCStackMapRegisters::SP) {
117         address = callSiteSp + info.second;
118     } else if (info.first == GCStackMapRegisters::FP) {
119         address = callsiteFp + info.second;
120     } else {
121         LOG_ECMA(FATAL) << "this branch is unreachable";
122         UNREACHABLE();
123     }
124     return address;
125 }
126 
127 // this function will increase the value of 'offset'
GetStackSlotAddress(uint8_t * stackmapAddr,uintptr_t callSiteSp,uintptr_t callsiteFp,uint32_t & offset,bool & nextIsBase,size_t & regOffsetSize) const128 uintptr_t ArkStackMapParser::GetStackSlotAddress(uint8_t *stackmapAddr, uintptr_t callSiteSp, uintptr_t callsiteFp,
129                                                  uint32_t &offset, bool &nextIsBase, size_t &regOffsetSize) const
130 {
131     LLVMStackMapType::DwarfRegType regType;
132     LLVMStackMapType::OffsetType offsetType;
133     LLVMStackMapType::SLeb128Type regOffset;
134     [[maybe_unused]] bool isFull;
135     uintptr_t address = 0;
136     std::tie(regOffset, regOffsetSize, isFull) =
137         panda::leb128::DecodeSigned<LLVMStackMapType::SLeb128Type>(stackmapAddr + offset);
138     bool isBaseDerivedEq = LLVMStackMapType::DecodeRegAndOffset(regOffset, regType, offsetType);
139     if (regType == GCStackMapRegisters::SP) {
140         address = callSiteSp + offsetType;
141     } else if (regType == GCStackMapRegisters::FP) {
142         address = callsiteFp + offsetType;
143     } else {
144         LOG_ECMA(FATAL) << "this branch is unreachable";
145         UNREACHABLE();
146     }
147     nextIsBase = isBaseDerivedEq;
148     offset += regOffsetSize;
149 
150     return address;
151 }
152 
GetDeoptStackSlotAddress(uint8_t * stackmapAddr,uintptr_t callSiteSp,uintptr_t callsiteFp,uint32_t & offset) const153 uintptr_t ArkStackMapParser::GetDeoptStackSlotAddress(uint8_t *stackmapAddr,
154                                                       uintptr_t callSiteSp,
155                                                       uintptr_t callsiteFp,
156                                                       uint32_t &offset) const
157 {
158     ARKDeopt deopt;
159     LLVMStackMapType::KindType kindType;
160     LLVMStackMapType::DwarfRegType reg;
161     LLVMStackMapType::OffsetType offsetType;
162     auto [vregsInfo, vregsInfoSize, InfoIsFull] =
163         panda::leb128::DecodeSigned<LLVMStackMapType::SLeb128Type>(stackmapAddr + offset);
164     LLVMStackMapType::DecodeVRegsInfo(vregsInfo, deopt.id, kindType);
165     offset += vregsInfoSize;
166     ASSERT(kindType == LLVMStackMapType::CONSTANT_TYPE || kindType == LLVMStackMapType::OFFSET_TYPE);
167     if (kindType == LLVMStackMapType::CONSTANT_TYPE) {
168         auto [constant, constantSize, constIsFull] =
169             panda::leb128::DecodeSigned<LLVMStackMapType::SLeb128Type>(stackmapAddr + offset);
170         offset += constantSize;
171         return 0;
172     } else {
173         auto [regOffset, regOffsetSize, regOffIsFull] =
174             panda::leb128::DecodeSigned<LLVMStackMapType::SLeb128Type>(stackmapAddr + offset);
175         LLVMStackMapType::DecodeRegAndOffset(regOffset, reg, offsetType);
176         offset += regOffsetSize;
177         LLVMStackMapType::DwarfRegAndOffsetType info = std::make_pair(reg, offsetType);
178         return GetStackSlotAddress(info, callSiteSp, callsiteFp);
179     }
180 }
181 
GetPcOffset(const std::vector<ARKDeopt> & deopts,size_t currentDepth,size_t shift) const182 int32_t ArkStackMapParser::GetPcOffset(const std::vector<ARKDeopt> &deopts, size_t currentDepth, size_t shift) const
183 {
184     ARKDeopt target;
185     LLVMStackMapType::VRegId pcId = static_cast<LLVMStackMapType::VRegId>(SpecVregIndex::PC_OFFSET_INDEX);
186     target.id = Deoptimizier::EncodeDeoptVregIndex(pcId, currentDepth, shift);
187     auto it = std::lower_bound(deopts.begin(), deopts.end(), target,
188         [](const ARKDeopt& a, const ARKDeopt& b) {
189             return a.id < b.id;
190         });
191     if (it == deopts.end() || (it->id > target.id)) {
192         return -1;
193     }
194     ASSERT(it->kind == LocationTy::Kind::CONSTANT);
195     ASSERT(std::holds_alternative<LLVMStackMapType::IntType>(it->value));
196     auto v = std::get<LLVMStackMapType::IntType>(it->value);
197     return static_cast<int32_t>(v);
198 }
199 
GetFunction(const std::vector<ARKDeopt> & deopts,size_t currentDepth,size_t shift,uintptr_t callsiteSp,uintptr_t callsiteFp) const200 JSTaggedType ArkStackMapParser::GetFunction(const std::vector<ARKDeopt> &deopts, size_t currentDepth, size_t shift,
201                                             uintptr_t callsiteSp, uintptr_t callsiteFp) const
202 {
203     ARKDeopt target;
204     LLVMStackMapType::VRegId pcId = static_cast<LLVMStackMapType::VRegId>(SpecVregIndex::FUNC_INDEX);
205     target.id = Deoptimizier::EncodeDeoptVregIndex(pcId, currentDepth, shift);
206     auto it = std::lower_bound(deopts.begin(), deopts.end(), target,
207         [](const ARKDeopt& a, const ARKDeopt& b) {
208             return a.id < b.id;
209         });
210     if (it == deopts.end() || (it->id > target.id)) {
211         return 0;
212     }
213     ASSERT(it->kind == LocationTy::Kind::INDIRECT);
214     ASSERT(std::holds_alternative<LLVMStackMapType::DwarfRegAndOffsetType>(it->value));
215     auto value = std::get<LLVMStackMapType::DwarfRegAndOffsetType>(it->value);
216     uintptr_t addr = GetStackSlotAddress(value, callsiteSp, callsiteFp);
217     JSTaggedType v = *(reinterpret_cast<JSTaggedType *>(addr));
218     return v;
219 }
220 
CollectStackTraceInfos(uintptr_t callSiteAddr,std::vector<std::pair<JSTaggedType,uint32_t>> & info,uintptr_t callsiteSp,uintptr_t callsiteFp,uint8_t * stackmapAddr) const221 void ArkStackMapParser::CollectStackTraceInfos(uintptr_t callSiteAddr,
222                                                std::vector<std::pair<JSTaggedType, uint32_t>> &info,
223                                                uintptr_t callsiteSp,
224                                                uintptr_t callsiteFp,
225                                                uint8_t *stackmapAddr) const
226 {
227     std::vector<ARKDeopt> deopts;
228     GetArkDeopt(callSiteAddr, stackmapAddr, deopts);
229     if (deopts.empty()) {
230         return;
231     }
232     size_t depth = GetInlineDepth(deopts);
233     size_t shift = Deoptimizier::ComputeShift(depth);
234     for (int i = depth; i >= 0; i--) {
235         int32_t pcOffset = GetPcOffset(deopts, i, shift);
236         JSTaggedType function = GetFunction(deopts, i, shift, callsiteSp, callsiteFp);
237         if (pcOffset < 0 || function == 0) {
238             continue;
239         }
240         info.push_back(std::make_pair(function, pcOffset));
241     }
242 }
243 
GetInlineDepth(uintptr_t callSiteAddr,uint8_t * stackmapAddr) const244 size_t ArkStackMapParser::GetInlineDepth(uintptr_t callSiteAddr, uint8_t *stackmapAddr) const
245 {
246     std::vector<ARKDeopt> deopts;
247     GetArkDeopt(callSiteAddr, stackmapAddr, deopts);
248     return GetInlineDepth(deopts);
249 }
250 
GetInlineDepth(const std::vector<ARKDeopt> & deopts) const251 size_t ArkStackMapParser::GetInlineDepth(const std::vector<ARKDeopt> &deopts) const
252 {
253     if (deopts.empty()) {
254         return 0;
255     }
256 
257     ARKDeopt target;
258     LLVMStackMapType::VRegId id = static_cast<LLVMStackMapType::VRegId>(SpecVregIndex::INLINE_DEPTH);
259     target.id = id;
260     auto it = std::lower_bound(deopts.begin(), deopts.end(), target,
261         [](const ARKDeopt& a, const ARKDeopt& b) {
262             return a.id < b.id;
263         });
264     if (it == deopts.end() || (it->id > target.id)) {
265         LOG_ECMA(ERROR) << "Miss inline depth";
266         return 0;
267     }
268     ASSERT(it->kind == LocationTy::Kind::CONSTANT);
269     ASSERT(std::holds_alternative<LLVMStackMapType::IntType>(it->value));
270     auto v = std::get<LLVMStackMapType::IntType>(it->value);
271     return static_cast<size_t>(v);
272 }
273 
IteratorStackMap(RootVisitor & visitor,uintptr_t callsiteFp,uintptr_t callSiteSp,uint8_t * stackmapAddr,uint32_t offset,uint16_t stackmapNum,std::map<uintptr_t,uintptr_t> & baseSet) const274 void ArkStackMapParser::IteratorStackMap(RootVisitor& visitor, uintptr_t callsiteFp,
275                                          uintptr_t callSiteSp, uint8_t *stackmapAddr,
276                                          uint32_t offset, uint16_t stackmapNum,
277                                          std::map<uintptr_t, uintptr_t> &baseSet) const
278 {
279     ASSERT(callsiteFp != callSiteSp);
280 // Original layout: <base, base>..<base, derive>..
281 // +----------------------+  --
282 // |regNo: 6   offset: -40|    |
283 // +----------------------+    | <-- base ref1    Get base address anhd derived address (equal)
284 // |regNo: 6   offset: -40|    |
285 // +----------------------+ <--    When iterate, i+=2
286 // +----------------------+  --
287 // |regNo: 7   offset: -32|    |
288 // +----------------------+    | <-- derived ref1   Get base address anhd derived address (different)
289 // |regNo: 7   offset: -24|    |
290 // +----------------------+ <--
291 // ==========>after optimization, removed the repeated info for base reference in stackmap builder
292 // New layout: <base>..<base, derived>.., stackmap info are not in pair
293 // +----------------------+  --
294 // |regNo: 6   offset: -40|    |   When base ref, i+=1
295 // +----------------------+ <--
296 // +----------------------+  --    When derived ref, i+=2
297 // |regNo: 7   offset: -32|    |
298 // +----------------------+    |
299 // |regNo: 7   offset: -24|    |
300 // +----------------------+ <--
301     for (size_t i = 0; i < stackmapNum; i++) {
302         size_t regOffsetSize;
303         // nextIsBase decoded (updated) from DecodeRegAndOffset inside GetStackSlotAddress
304         bool nextIsBase = true;
305         uintptr_t base = GetStackSlotAddress(stackmapAddr, callSiteSp, callsiteFp, offset, nextIsBase, regOffsetSize);
306         uintptr_t derived;
307         if (nextIsBase) {
308             derived = base; // because the base=derive and the derived one have been removed.
309         } else {
310             derived = GetStackSlotAddress(stackmapAddr, callSiteSp, callsiteFp, offset, nextIsBase, regOffsetSize);
311             i++; // move to next entry
312         }
313         if (*reinterpret_cast<uintptr_t *>(base) == 0) {
314             base = derived;
315         }
316         if (*reinterpret_cast<uintptr_t *>(base) != 0) {
317             // The base address may be marked repeatedly
318             if (baseSet.find(base) == baseSet.end()) {
319                 baseSet.emplace(base, *reinterpret_cast<uintptr_t *>(base));
320                 visitor.VisitRoot(Root::ROOT_FRAME, ObjectSlot(base));
321             }
322 
323             if (base != derived) {
324                 baseSet.emplace(derived, *reinterpret_cast<uintptr_t *>(derived));
325                 visitor.VisitBaseAndDerivedRoot(Root::ROOT_FRAME, ObjectSlot(base), ObjectSlot(derived),
326                                                 baseSet[base]);
327             }
328         }
329     }
330 }
331 
IteratorDeopt(RootVisitor & visitor,uintptr_t callsiteFp,uintptr_t callSiteSp,uint8_t * stackmapAddr,uint32_t offset,uint16_t num,std::map<uintptr_t,uintptr_t> & baseSet) const332 void ArkStackMapParser::IteratorDeopt(RootVisitor& visitor, uintptr_t callsiteFp,
333                                       uintptr_t callSiteSp, uint8_t *stackmapAddr,
334                                       uint32_t offset, uint16_t num,
335                                       std::map<uintptr_t, uintptr_t> &baseSet) const
336 {
337     ASSERT(num % DEOPT_ENTRY_SIZE == 0);
338     ASSERT(callsiteFp != callSiteSp);
339     for (size_t i = 0; i < num; i += DEOPT_ENTRY_SIZE) { // DEOPT_ENTRY_SIZE=<id, value>
340         uintptr_t base = GetDeoptStackSlotAddress(stackmapAddr, callSiteSp, callsiteFp, offset);
341         if (base != 0 && *reinterpret_cast<uintptr_t *>(base) != 0) {
342             // The base address may be marked repeatedly
343             if (baseSet.find(base) == baseSet.end()) {
344                 baseSet.emplace(base, *reinterpret_cast<uintptr_t *>(base));
345                 visitor.VisitRoot(Root::ROOT_FRAME, ObjectSlot(base));
346             }
347         }
348     }
349 }
350 
IteratorStackMapAndDeopt(RootVisitor & visitor,uintptr_t callSiteAddr,uintptr_t callsiteFp,uintptr_t callSiteSp,uint8_t * stackmapAddr) const351 bool ArkStackMapParser::IteratorStackMapAndDeopt(RootVisitor& visitor,
352                                                  uintptr_t callSiteAddr,
353                                                  uintptr_t callsiteFp,
354                                                  uintptr_t callSiteSp,
355                                                  uint8_t *stackmapAddr) const
356 {
357     ArkStackMapHeader *head = reinterpret_cast<ArkStackMapHeader *>(stackmapAddr);
358     ASSERT(head != nullptr);
359     uint32_t callsiteNum = head->callsiteNum;
360     // BuiltinsStub current only sample stub, don't have stackmap&deopt.
361     if (callsiteNum == 0) {
362         return false;
363     }
364 
365     CallsiteHeader *callsiteHead = reinterpret_cast<CallsiteHeader *>(stackmapAddr + sizeof(ArkStackMapHeader));
366     int mid = BinaraySearch(callsiteHead, callsiteNum, callSiteAddr);
367     if (mid == -1) {
368         return false;
369     }
370     CallsiteHeader *found = callsiteHead + mid;
371     std::map<uintptr_t, uintptr_t> baseSet;
372 
373     uint32_t offset = found->stackmapOffsetInSMSec;
374     uint16_t num = found->stackmapNum;
375     if (num == 0) {
376         ASSERT(found->deoptNum == 0);
377         return false;
378     }
379     IteratorStackMap(visitor, callsiteFp, callSiteSp, stackmapAddr, offset, num, baseSet);
380 
381     // Not sure if this is necessary, but add it just to be on the safe side.
382     offset = found->deoptOffset;
383     num = found->deoptNum;
384     IteratorDeopt(visitor, callsiteFp, callSiteSp, stackmapAddr, offset, num, baseSet);
385 
386     baseSet.clear();
387     return true;
388 }
389 
390 #ifndef NDEBUG
ParseArkStackMap(const CallsiteHeader & callsiteHead,uint8_t * ptr,ArkStackMap & arkStackMaps) const391 void ArkStackMapParser::ParseArkStackMap(const CallsiteHeader& callsiteHead,
392                                          uint8_t *ptr,
393                                          ArkStackMap& arkStackMaps) const
394 {
395     LLVMStackMapType::DwarfRegType reg;
396     LLVMStackMapType::OffsetType offsetType;
397     uint32_t offset = callsiteHead.stackmapOffsetInSMSec;
398     uint16_t stackmapNum = callsiteHead.stackmapNum;
399     for (uint32_t j = 0; j < stackmapNum; j++) {
400         auto [regOffset, regOffsetSize, is_full] =
401             panda::leb128::DecodeSigned<LLVMStackMapType::SLeb128Type>(ptr + offset);
402         bool isBaseDerivedEq = LLVMStackMapType::DecodeRegAndOffset(regOffset, reg, offsetType);
403         offset += regOffsetSize;
404         LOG_COMPILER(VERBOSE) << " reg: " << std::dec << reg << " offset:" <<  offsetType;
405         if (isBaseDerivedEq) {
406             LOG_COMPILER(VERBOSE) << " reg(base): " << std::dec << reg << " offset(base):" <<  offsetType;
407         }
408         arkStackMaps.emplace_back(std::make_pair(reg, offsetType));
409     }
410     offset = AlignUp(offset, LLVMStackMapType::STACKMAP_ALIGN_BYTES);
411 }
412 
ParseArkStackMapAndDeopt(uint8_t * ptr,uint32_t length) const413 void ArkStackMapParser::ParseArkStackMapAndDeopt(uint8_t *ptr, uint32_t length) const
414 {
415     CallsiteHeader callsiteHead;
416     ArkStackMapHeader secHead;
417     BinaryBufferParser binBufparser(ptr, length);
418     binBufparser.ParseBuffer(&secHead, sizeof(ArkStackMapHeader));
419     for (uint32_t i = 0; i < secHead.callsiteNum; i++) {
420         binBufparser.ParseBuffer(&callsiteHead, sizeof(CallsiteHeader));
421         std::vector<ARKDeopt> deopts;
422         ArkStackMap arkStackMaps;
423         LOG_COMPILER(VERBOSE) << " calliteOffsetInTxtSec: 0x" << std::hex << callsiteHead.calliteOffsetInTxtSec
424                               << " stackmap offset: 0x" << std::hex << callsiteHead.stackmapOffsetInSMSec
425                               << " num:" << callsiteHead.stackmapNum
426                               << " deopt Offset: 0x" << std::hex << callsiteHead.deoptOffset
427                               << " num:" << callsiteHead.deoptNum;
428         ParseArkStackMap(callsiteHead, ptr, arkStackMaps);
429         ParseArkDeopt(callsiteHead, ptr, deopts);
430     }
431 }
432 #endif
433 } // namespace panda::ecmascript::kungfu