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