1 /*
2 * Copyright (c) 2023 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/compiler/range_guard.h"
16
17 namespace panda::ecmascript::kungfu {
Run()18 void RangeGuard::Run()
19 {
20 dependChains_.resize(circuit_->GetMaxGateId() + 1, nullptr); // 1: +1 for size
21 GateRef entry = acc_.GetDependRoot();
22 VisitDependEntry(entry);
23 VisitGraph();
24 }
25
VisitGate(GateRef gate)26 GateRef RangeGuard::VisitGate(GateRef gate)
27 {
28 auto op = acc_.GetOpCode(gate);
29 switch (op) {
30 case OpCode::VALUE_SELECTOR:
31 case OpCode::TYPED_BINARY_OP:
32 case OpCode::TYPED_UNARY_OP:
33 case OpCode::INDEX_CHECK: {
34 return TryApplyRangeGuardGate(gate);
35 }
36 case OpCode::DEPEND_SELECTOR: {
37 return TraverseDependSelector(gate);
38 }
39 default: {
40 if (acc_.GetDependCount(gate) == 1) { // 1: depend in is 1
41 return TraverseOthers(gate);
42 }
43 break;
44 }
45 }
46 return Circuit::NullGate();
47 }
48
TraverseOthers(GateRef gate)49 GateRef RangeGuard::TraverseOthers(GateRef gate)
50 {
51 ASSERT(acc_.GetDependCount(gate) >= 1);
52 auto depIn = acc_.GetDep(gate);
53 auto dependChain = GetDependChain(depIn);
54 if (dependChain == nullptr) {
55 return Circuit::NullGate();
56 }
57
58 return UpdateDependChain(gate, dependChain);
59 }
60
TraverseDependSelector(GateRef gate)61 GateRef RangeGuard::TraverseDependSelector(GateRef gate)
62 {
63 auto state = acc_.GetState(gate);
64 if (acc_.IsLoopHead(state)) {
65 return TraverseOthers(gate);
66 }
67
68 auto dependCount = acc_.GetDependCount(gate);
69 for (size_t i = 0; i < dependCount; ++i) {
70 auto depend = acc_.GetDep(gate, i);
71 auto dependChain = GetDependChain(depend);
72 if (dependChain == nullptr) {
73 return Circuit::NullGate();
74 }
75 }
76
77 // all depend done.
78 auto depend = acc_.GetDep(gate);
79 auto dependChain = GetDependChain(depend);
80 DependChains* copy = new (chunk_) DependChains(chunk_);
81 copy->CopyFrom(dependChain);
82 for (size_t i = 1; i < dependCount; ++i) { // 1: second in
83 auto dependIn = acc_.GetDep(gate, i);
84 auto tempChain = GetDependChain(dependIn);
85 copy->Merge(tempChain);
86 }
87 return UpdateDependChain(gate, copy);
88 }
89
TryApplyRangeGuardForLength(DependChains * dependChain,GateRef gate,GateRef input)90 GateRef RangeGuard::TryApplyRangeGuardForLength(DependChains* dependChain, GateRef gate, GateRef input)
91 {
92 ASSERT(dependChain != nullptr);
93 uint32_t length = dependChain->FoundIndexCheckedForLength(this, input);
94 if (length) { // when length not equal to 0, then Found the IndexCheck Success
95 Environment env(gate, circuit_, &builder_);
96 // If the IndexCheck before the ArrayLength used, the ArrayLength must start by 1.
97 auto rangeGuardGate = builder_.RangeGuard(input, 1, length);
98 return rangeGuardGate;
99 }
100 return Circuit::NullGate();
101 }
102
TryApplyRangeGuardForIndex(DependChains * dependChain,GateRef gate,GateRef input)103 GateRef RangeGuard::TryApplyRangeGuardForIndex(DependChains* dependChain, GateRef gate, GateRef input)
104 {
105 ASSERT(dependChain != nullptr);
106 uint32_t length = dependChain->FoundIndexCheckedForIndex(this, input);
107 if (length) { // when length not equal to 0, then Found the IndexCheck Success
108 Environment env(gate, circuit_, &builder_);
109 // If the IndexCheck used in the Array, the index must in the Array range.
110 auto rangeGuardGate = builder_.RangeGuard(input, 0, length);
111 return rangeGuardGate;
112 }
113 return Circuit::NullGate();
114 }
115
TryApplyRangeGuardGate(GateRef gate)116 GateRef RangeGuard::TryApplyRangeGuardGate(GateRef gate)
117 {
118 if (acc_.GetDependCount(gate) < 1) {
119 return Circuit::NullGate();
120 }
121
122 auto depIn = acc_.GetDep(gate);
123 auto dependChain = GetDependChain(depIn);
124 // dependChain is null
125 if (dependChain == nullptr) {
126 return Circuit::NullGate();
127 }
128
129 auto numIns = acc_.GetInValueCount(gate);
130 for (size_t i = 0; i < numIns; ++i) {
131 auto originalInput = acc_.GetValueIn(gate, i);
132 auto originalInputOpcode = acc_.GetOpCode(originalInput);
133 auto rangeGuardGate = Circuit::NullGate();
134 if (originalInputOpcode == OpCode::LOAD_TYPED_ARRAY_LENGTH ||
135 originalInputOpcode == OpCode::LOAD_ARRAY_LENGTH) {
136 rangeGuardGate = TryApplyRangeGuardForLength(dependChain, gate, originalInput);
137 } else if (originalInputOpcode != OpCode::CONSTANT && rangeGuardGate == Circuit::NullGate()) {
138 rangeGuardGate = TryApplyRangeGuardForIndex(dependChain, gate, originalInput);
139 }
140 if (rangeGuardGate != Circuit::NullGate()) {
141 acc_.ReplaceValueIn(gate, rangeGuardGate, i);
142 }
143 }
144 dependChain = dependChain->UpdateNode(gate);
145 return UpdateDependChain(gate, dependChain);
146 }
147
VisitDependEntry(GateRef gate)148 GateRef RangeGuard::VisitDependEntry(GateRef gate)
149 {
150 auto empty = new (chunk_) DependChains(chunk_);
151 return UpdateDependChain(gate, empty);
152 }
153
UpdateDependChain(GateRef gate,DependChains * dependChain)154 GateRef RangeGuard::UpdateDependChain(GateRef gate, DependChains* dependChain)
155 {
156 ASSERT(dependChain != nullptr);
157 auto oldDependChain = GetDependChain(gate);
158 if (dependChain->Equals(oldDependChain)) {
159 return Circuit::NullGate();
160 }
161 dependChains_[acc_.GetId(gate)] = dependChain;
162 return gate;
163 }
164
CheckIndexCheckLengthInput(GateRef lhs,GateRef rhs)165 uint32_t RangeGuard::CheckIndexCheckLengthInput(GateRef lhs, GateRef rhs)
166 {
167 auto lhsOpcode = acc_.GetOpCode(lhs);
168 if (lhsOpcode == OpCode::INDEX_CHECK) {
169 auto indexCheckLengthInput = acc_.GetValueIn(lhs, 0); // length
170 auto indexCheckLengthInputOpcode = acc_.GetOpCode(indexCheckLengthInput);
171 if (indexCheckLengthInput == rhs && indexCheckLengthInputOpcode == OpCode::LOAD_TYPED_ARRAY_LENGTH) {
172 return RangeInfo::TYPED_ARRAY_ONHEAP_MAX;
173 } else if (indexCheckLengthInput == rhs && indexCheckLengthInputOpcode == OpCode::LOAD_ARRAY_LENGTH) {
174 return INT32_MAX;
175 }
176 }
177 return 0;
178 }
179
CheckIndexCheckIndexInput(GateRef lhs,GateRef rhs)180 uint32_t RangeGuard::CheckIndexCheckIndexInput(GateRef lhs, GateRef rhs)
181 {
182 auto lhsOpcode = acc_.GetOpCode(lhs);
183 if (lhsOpcode == OpCode::INDEX_CHECK) {
184 auto indexCheckLengthInput = acc_.GetValueIn(lhs, 0); // length
185 auto indexCheckIndexInput = acc_.GetValueIn(lhs, 1); // index
186 auto indexCheckLengthInputOpcode = acc_.GetOpCode(indexCheckLengthInput);
187 // TYPED_ARRAY
188 if (indexCheckIndexInput == rhs && indexCheckLengthInputOpcode == OpCode::LOAD_TYPED_ARRAY_LENGTH) {
189 return RangeInfo::TYPED_ARRAY_ONHEAP_MAX;
190 } else if (indexCheckIndexInput == rhs && indexCheckLengthInputOpcode == OpCode::LOAD_ARRAY_LENGTH) { // ARRAY
191 return INT32_MAX;
192 }
193 }
194 return 0;
195 }
196 } // namespace panda::ecmascript::kungfu
197