• 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/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 CallsiteHead.
BinaraySearch(CallsiteHead * callsiteHead,uint32_t callsiteNum,uintptr_t callSiteAddr) const24 int ArkStackMapParser::BinaraySearch(CallsiteHead *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,uint32_t length,const CallsiteHead & callsiteHead,std::vector<kungfu::ARKDeopt> & deopts) const44 void ArkStackMapParser::GetArkDeopt(uint8_t *stackmapAddr, uint32_t length,
45     const CallsiteHead& callsiteHead, std::vector<kungfu::ARKDeopt> &deopts) const
46 {
47     BinaryBufferParser binBufparser(stackmapAddr, length);
48     ParseArkDeopt(callsiteHead, binBufparser, stackmapAddr, deopts);
49 }
50 
GetArkDeopt(uintptr_t callSiteAddr,uint8_t * stackmapAddr,std::vector<kungfu::ARKDeopt> & deopts) const51 void ArkStackMapParser::GetArkDeopt(uintptr_t callSiteAddr, uint8_t *stackmapAddr,
52     std::vector<kungfu::ARKDeopt> &deopts) const
53 {
54     StackMapSecHead *head = reinterpret_cast<StackMapSecHead *>(stackmapAddr);
55     ASSERT(head != nullptr);
56     uint32_t callsiteNum = head->callsiteNum;
57     uint32_t length = head->totalSize;
58     ASSERT((head->callsitEnd - head->callsitStart) == ((callsiteNum - 1) * sizeof(CallsiteHead)));
59 
60     CallsiteHead *callsiteHead = reinterpret_cast<CallsiteHead *>(stackmapAddr + sizeof(StackMapSecHead));
61     int mid = BinaraySearch(callsiteHead, callsiteNum, callSiteAddr);
62     if (mid == -1) {
63         return;
64     }
65     CallsiteHead *found = callsiteHead + mid;
66     GetArkDeopt(stackmapAddr, length, *found, deopts);
67 }
68 
GetConstInfo(uintptr_t callSiteAddr,ConstInfo & info,uint8_t * stackmapAddr) const69 void ArkStackMapParser::GetConstInfo(uintptr_t callSiteAddr, ConstInfo &info, uint8_t *stackmapAddr) const
70 {
71     std::vector<kungfu::ARKDeopt> deopts;
72     GetArkDeopt(callSiteAddr, stackmapAddr, deopts);
73     if (deopts.empty()) {
74         return;
75     }
76 
77     ARKDeopt target;
78     OffsetType id = static_cast<OffsetType>(SpecVregIndex::BC_OFFSET_INDEX);
79     target.Id = id;
80     auto it = std::lower_bound(deopts.begin(), deopts.end(), target,
81         [](const ARKDeopt& a, const ARKDeopt& b) {
82             return a.Id < b.Id;
83         });
84     if (it == deopts.end() || (it->Id > id)) {
85         return;
86     }
87     ASSERT(it->kind == LocationTy::Kind::CONSTANT);
88     ASSERT(std::holds_alternative<OffsetType>(it->value));
89     auto v = std::get<OffsetType>(it->value);
90     info.emplace_back(v);
91 }
92 
GetStackSlotAddress(const DwarfRegAndOffsetType info,uintptr_t callSiteSp,uintptr_t callsiteFp) const93 uintptr_t ArkStackMapParser::GetStackSlotAddress(const DwarfRegAndOffsetType info,
94     uintptr_t callSiteSp, uintptr_t callsiteFp) const
95 {
96     uintptr_t address = 0;
97     if (info.first == GCStackMapRegisters::SP) {
98         address = callSiteSp + info.second;
99     } else if (info.first == GCStackMapRegisters::FP) {
100         address = callsiteFp + info.second;
101     } else {
102         UNREACHABLE();
103     }
104     return address;
105 }
106 
IteratorStackMap(const RootVisitor & visitor,const RootBaseAndDerivedVisitor & derivedVisitor,uintptr_t callSiteAddr,uintptr_t callsiteFp,uintptr_t callSiteSp,uint8_t * stackmapAddr) const107 bool ArkStackMapParser::IteratorStackMap(const RootVisitor &visitor, const RootBaseAndDerivedVisitor &derivedVisitor,
108     uintptr_t callSiteAddr, uintptr_t callsiteFp, uintptr_t callSiteSp, uint8_t *stackmapAddr) const
109 {
110     StackMapSecHead *head = reinterpret_cast<StackMapSecHead *>(stackmapAddr);
111     ASSERT(head != nullptr);
112     uint32_t callsiteNum = head->callsiteNum;
113     uint32_t length = head->totalSize;
114     ArkStackMap arkStackMap;
115     // BuiltinsStub current only sample stub, don't have stackmap&deopt.
116     if (callsiteNum == 0) {
117         return false;
118     }
119     ASSERT((head->callsitEnd - head->callsitStart) == ((callsiteNum - 1) * sizeof(CallsiteHead)));
120 
121     CallsiteHead *callsiteHead = reinterpret_cast<CallsiteHead *>(stackmapAddr + sizeof(StackMapSecHead));
122     int mid = BinaraySearch(callsiteHead, callsiteNum, callSiteAddr);
123     if (mid == -1) {
124         return false;
125     }
126     CallsiteHead *found = callsiteHead + mid;
127     BinaryBufferParser binBufparser(stackmapAddr, length);
128     ParseArkStackMap(*found, binBufparser, stackmapAddr, arkStackMap);
129     if (arkStackMap.size() == 0) {
130         return false;
131     }
132     ASSERT(callsiteFp != callSiteSp);
133     std::map<uintptr_t, uintptr_t> baseSet;
134     for (size_t i = 0; i < arkStackMap.size(); i += 2) { // 2:base and derive
135         const DwarfRegAndOffsetType baseInfo = arkStackMap.at(i);
136         const DwarfRegAndOffsetType derivedInfo = arkStackMap.at(i + 1);
137         uintptr_t base = GetStackSlotAddress(baseInfo, callSiteSp, callsiteFp);
138         uintptr_t derived = GetStackSlotAddress(derivedInfo, callSiteSp, callsiteFp);
139         if (*reinterpret_cast<uintptr_t *>(base) == 0) {
140             base = derived;
141         }
142         if (*reinterpret_cast<uintptr_t *>(base) != 0) {
143             // The base address may be marked repeatedly
144             if (baseSet.find(base) == baseSet.end()) {
145                 baseSet.emplace(base, *reinterpret_cast<uintptr_t *>(base));
146                 visitor(Root::ROOT_FRAME, ObjectSlot(base));
147             }
148 
149             if (base != derived) {
150                 derivedVisitor(Root::ROOT_FRAME, ObjectSlot(base), ObjectSlot(derived), baseSet[base]);
151             }
152         }
153     }
154     baseSet.clear();
155     return true;
156 }
157 } // namespace panda::ecmascript::kungfu