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 17namespace panda::ecmascript::kungfu { 18 19void RangeGuard::Initialize() 20{ 21 dependChains_.resize(circuit_->GetMaxGateId() + 1, nullptr); // 1: +1 for size 22 GateRef entry = acc_.GetDependRoot(); 23 VisitDependEntry(entry); 24} 25 26GateRef 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 49GateRef 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 61GateRef 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 90GateRef RangeGuard::TryApplyRangeGuardForLength(DependChains* dependChain, GateRef gate, GateRef input) 91{ 92 ASSERT(dependChain != nullptr); 93 uint32_t length = FoundIndexCheckedForLength(dependChain, 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 103GateRef RangeGuard::TryApplyRangeGuardForIndex(DependChains* dependChain, GateRef gate, GateRef input) 104{ 105 ASSERT(dependChain != nullptr); 106 uint32_t length = FoundIndexCheckedForIndex(dependChain, 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 116GateRef 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 148GateRef RangeGuard::VisitDependEntry(GateRef gate) 149{ 150 auto empty = new (chunk_) DependChains(chunk_); 151 return UpdateDependChain(gate, empty); 152} 153 154GateRef 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 165uint32_t RangeGuard::CheckIndexCheckLengthInput(GateRef lhs, GateRef rhs) const 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 TypedArrayMetaDataAccessor accessor = acc_.GetTypedArrayMetaDataAccessor(indexCheckLengthInput); 173 OnHeapMode onHeap = accessor.GetOnHeapMode(); 174 int32_t max = onHeap == OnHeapMode::ON_HEAP ? RangeInfo::TYPED_ARRAY_ONHEAP_MAX : INT32_MAX; 175 return max; 176 } else if (indexCheckLengthInput == rhs && indexCheckLengthInputOpcode == OpCode::LOAD_ARRAY_LENGTH) { 177 return INT32_MAX; 178 } 179 } 180 return 0; 181} 182 183uint32_t RangeGuard::CheckIndexCheckIndexInput(GateRef lhs, GateRef rhs) const 184{ 185 auto lhsOpcode = acc_.GetOpCode(lhs); 186 if (lhsOpcode == OpCode::INDEX_CHECK) { 187 auto indexCheckLengthInput = acc_.GetValueIn(lhs, 0); // length 188 auto indexCheckIndexInput = acc_.GetValueIn(lhs, 1); // index 189 auto indexCheckLengthInputOpcode = acc_.GetOpCode(indexCheckLengthInput); 190 // TYPED_ARRAY 191 if (indexCheckIndexInput == rhs && indexCheckLengthInputOpcode == OpCode::LOAD_TYPED_ARRAY_LENGTH) { 192 TypedArrayMetaDataAccessor accessor = acc_.GetTypedArrayMetaDataAccessor(indexCheckLengthInput); 193 OnHeapMode onHeap = accessor.GetOnHeapMode(); 194 int32_t max = onHeap == OnHeapMode::ON_HEAP ? RangeInfo::TYPED_ARRAY_ONHEAP_MAX : INT32_MAX; 195 return max; 196 } else if (indexCheckIndexInput == rhs && indexCheckLengthInputOpcode == OpCode::LOAD_ARRAY_LENGTH) { // ARRAY 197 return INT32_MAX; 198 } 199 } 200 return 0; 201} 202} // namespace panda::ecmascript::kungfu 203