• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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