14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci#include "ecmascript/compiler/range_guard.h"
164514f5e3Sopenharmony_ci
174514f5e3Sopenharmony_cinamespace panda::ecmascript::kungfu {
184514f5e3Sopenharmony_ci
194514f5e3Sopenharmony_civoid RangeGuard::Initialize()
204514f5e3Sopenharmony_ci{
214514f5e3Sopenharmony_ci    dependChains_.resize(circuit_->GetMaxGateId() + 1, nullptr); // 1: +1 for size
224514f5e3Sopenharmony_ci    GateRef entry = acc_.GetDependRoot();
234514f5e3Sopenharmony_ci    VisitDependEntry(entry);
244514f5e3Sopenharmony_ci}
254514f5e3Sopenharmony_ci
264514f5e3Sopenharmony_ciGateRef RangeGuard::VisitGate(GateRef gate)
274514f5e3Sopenharmony_ci{
284514f5e3Sopenharmony_ci    auto op = acc_.GetOpCode(gate);
294514f5e3Sopenharmony_ci    switch (op) {
304514f5e3Sopenharmony_ci        case OpCode::VALUE_SELECTOR:
314514f5e3Sopenharmony_ci        case OpCode::TYPED_BINARY_OP:
324514f5e3Sopenharmony_ci        case OpCode::TYPED_UNARY_OP:
334514f5e3Sopenharmony_ci        case OpCode::INDEX_CHECK: {
344514f5e3Sopenharmony_ci            return TryApplyRangeGuardGate(gate);
354514f5e3Sopenharmony_ci        }
364514f5e3Sopenharmony_ci        case OpCode::DEPEND_SELECTOR: {
374514f5e3Sopenharmony_ci            return TraverseDependSelector(gate);
384514f5e3Sopenharmony_ci        }
394514f5e3Sopenharmony_ci        default: {
404514f5e3Sopenharmony_ci            if (acc_.GetDependCount(gate) == 1) { // 1: depend in is 1
414514f5e3Sopenharmony_ci                return TraverseOthers(gate);
424514f5e3Sopenharmony_ci            }
434514f5e3Sopenharmony_ci            break;
444514f5e3Sopenharmony_ci        }
454514f5e3Sopenharmony_ci    }
464514f5e3Sopenharmony_ci    return Circuit::NullGate();
474514f5e3Sopenharmony_ci}
484514f5e3Sopenharmony_ci
494514f5e3Sopenharmony_ciGateRef RangeGuard::TraverseOthers(GateRef gate)
504514f5e3Sopenharmony_ci{
514514f5e3Sopenharmony_ci    ASSERT(acc_.GetDependCount(gate) >= 1);
524514f5e3Sopenharmony_ci    auto depIn = acc_.GetDep(gate);
534514f5e3Sopenharmony_ci    auto dependChain = GetDependChain(depIn);
544514f5e3Sopenharmony_ci    if (dependChain == nullptr) {
554514f5e3Sopenharmony_ci        return Circuit::NullGate();
564514f5e3Sopenharmony_ci    }
574514f5e3Sopenharmony_ci
584514f5e3Sopenharmony_ci    return UpdateDependChain(gate, dependChain);
594514f5e3Sopenharmony_ci}
604514f5e3Sopenharmony_ci
614514f5e3Sopenharmony_ciGateRef RangeGuard::TraverseDependSelector(GateRef gate)
624514f5e3Sopenharmony_ci{
634514f5e3Sopenharmony_ci    auto state = acc_.GetState(gate);
644514f5e3Sopenharmony_ci    if (acc_.IsLoopHead(state)) {
654514f5e3Sopenharmony_ci        return TraverseOthers(gate);
664514f5e3Sopenharmony_ci    }
674514f5e3Sopenharmony_ci
684514f5e3Sopenharmony_ci    auto dependCount = acc_.GetDependCount(gate);
694514f5e3Sopenharmony_ci    for (size_t i = 0; i < dependCount; ++i) {
704514f5e3Sopenharmony_ci        auto depend = acc_.GetDep(gate, i);
714514f5e3Sopenharmony_ci        auto dependChain = GetDependChain(depend);
724514f5e3Sopenharmony_ci        if (dependChain == nullptr) {
734514f5e3Sopenharmony_ci            return Circuit::NullGate();
744514f5e3Sopenharmony_ci        }
754514f5e3Sopenharmony_ci    }
764514f5e3Sopenharmony_ci
774514f5e3Sopenharmony_ci    // all depend done.
784514f5e3Sopenharmony_ci    auto depend = acc_.GetDep(gate);
794514f5e3Sopenharmony_ci    auto dependChain = GetDependChain(depend);
804514f5e3Sopenharmony_ci    DependChains* copy = new (chunk_) DependChains(chunk_);
814514f5e3Sopenharmony_ci    copy->CopyFrom(dependChain);
824514f5e3Sopenharmony_ci    for (size_t i = 1; i < dependCount; ++i) { // 1: second in
834514f5e3Sopenharmony_ci        auto dependIn = acc_.GetDep(gate, i);
844514f5e3Sopenharmony_ci        auto tempChain = GetDependChain(dependIn);
854514f5e3Sopenharmony_ci        copy->Merge(tempChain);
864514f5e3Sopenharmony_ci    }
874514f5e3Sopenharmony_ci    return UpdateDependChain(gate, copy);
884514f5e3Sopenharmony_ci}
894514f5e3Sopenharmony_ci
904514f5e3Sopenharmony_ciGateRef RangeGuard::TryApplyRangeGuardForLength(DependChains* dependChain, GateRef gate, GateRef input)
914514f5e3Sopenharmony_ci{
924514f5e3Sopenharmony_ci    ASSERT(dependChain != nullptr);
934514f5e3Sopenharmony_ci    uint32_t length = FoundIndexCheckedForLength(dependChain, input);
944514f5e3Sopenharmony_ci    if (length) { // when length not equal to 0, then Found the IndexCheck Success
954514f5e3Sopenharmony_ci        Environment env(gate, circuit_, &builder_);
964514f5e3Sopenharmony_ci        // If the IndexCheck before the ArrayLength used, the ArrayLength must start by 1.
974514f5e3Sopenharmony_ci        auto rangeGuardGate = builder_.RangeGuard(input, 1, length);
984514f5e3Sopenharmony_ci        return rangeGuardGate;
994514f5e3Sopenharmony_ci    }
1004514f5e3Sopenharmony_ci    return Circuit::NullGate();
1014514f5e3Sopenharmony_ci}
1024514f5e3Sopenharmony_ci
1034514f5e3Sopenharmony_ciGateRef RangeGuard::TryApplyRangeGuardForIndex(DependChains* dependChain, GateRef gate, GateRef input)
1044514f5e3Sopenharmony_ci{
1054514f5e3Sopenharmony_ci    ASSERT(dependChain != nullptr);
1064514f5e3Sopenharmony_ci    uint32_t length = FoundIndexCheckedForIndex(dependChain, input);
1074514f5e3Sopenharmony_ci    if (length) { // when length not equal to 0, then Found the IndexCheck Success
1084514f5e3Sopenharmony_ci        Environment env(gate, circuit_, &builder_);
1094514f5e3Sopenharmony_ci        // If the IndexCheck used in the Array, the index must in the Array range.
1104514f5e3Sopenharmony_ci        auto rangeGuardGate = builder_.RangeGuard(input, 0, length);
1114514f5e3Sopenharmony_ci        return rangeGuardGate;
1124514f5e3Sopenharmony_ci    }
1134514f5e3Sopenharmony_ci    return Circuit::NullGate();
1144514f5e3Sopenharmony_ci}
1154514f5e3Sopenharmony_ci
1164514f5e3Sopenharmony_ciGateRef RangeGuard::TryApplyRangeGuardGate(GateRef gate)
1174514f5e3Sopenharmony_ci{
1184514f5e3Sopenharmony_ci    if (acc_.GetDependCount(gate) < 1) {
1194514f5e3Sopenharmony_ci        return Circuit::NullGate();
1204514f5e3Sopenharmony_ci    }
1214514f5e3Sopenharmony_ci
1224514f5e3Sopenharmony_ci    auto depIn = acc_.GetDep(gate);
1234514f5e3Sopenharmony_ci    auto dependChain = GetDependChain(depIn);
1244514f5e3Sopenharmony_ci    // dependChain is null
1254514f5e3Sopenharmony_ci    if (dependChain == nullptr) {
1264514f5e3Sopenharmony_ci        return Circuit::NullGate();
1274514f5e3Sopenharmony_ci    }
1284514f5e3Sopenharmony_ci
1294514f5e3Sopenharmony_ci    auto numIns = acc_.GetInValueCount(gate);
1304514f5e3Sopenharmony_ci    for (size_t i = 0; i < numIns; ++i) {
1314514f5e3Sopenharmony_ci        auto originalInput = acc_.GetValueIn(gate, i);
1324514f5e3Sopenharmony_ci        auto originalInputOpcode = acc_.GetOpCode(originalInput);
1334514f5e3Sopenharmony_ci        auto rangeGuardGate = Circuit::NullGate();
1344514f5e3Sopenharmony_ci        if (originalInputOpcode == OpCode::LOAD_TYPED_ARRAY_LENGTH ||
1354514f5e3Sopenharmony_ci            originalInputOpcode == OpCode::LOAD_ARRAY_LENGTH) {
1364514f5e3Sopenharmony_ci            rangeGuardGate = TryApplyRangeGuardForLength(dependChain, gate, originalInput);
1374514f5e3Sopenharmony_ci        } else if (originalInputOpcode != OpCode::CONSTANT && rangeGuardGate == Circuit::NullGate()) {
1384514f5e3Sopenharmony_ci            rangeGuardGate = TryApplyRangeGuardForIndex(dependChain, gate, originalInput);
1394514f5e3Sopenharmony_ci        }
1404514f5e3Sopenharmony_ci        if (rangeGuardGate != Circuit::NullGate()) {
1414514f5e3Sopenharmony_ci            acc_.ReplaceValueIn(gate, rangeGuardGate, i);
1424514f5e3Sopenharmony_ci        }
1434514f5e3Sopenharmony_ci    }
1444514f5e3Sopenharmony_ci    dependChain = dependChain->UpdateNode(gate);
1454514f5e3Sopenharmony_ci    return UpdateDependChain(gate, dependChain);
1464514f5e3Sopenharmony_ci}
1474514f5e3Sopenharmony_ci
1484514f5e3Sopenharmony_ciGateRef RangeGuard::VisitDependEntry(GateRef gate)
1494514f5e3Sopenharmony_ci{
1504514f5e3Sopenharmony_ci    auto empty = new (chunk_) DependChains(chunk_);
1514514f5e3Sopenharmony_ci    return UpdateDependChain(gate, empty);
1524514f5e3Sopenharmony_ci}
1534514f5e3Sopenharmony_ci
1544514f5e3Sopenharmony_ciGateRef RangeGuard::UpdateDependChain(GateRef gate, DependChains* dependChain)
1554514f5e3Sopenharmony_ci{
1564514f5e3Sopenharmony_ci    ASSERT(dependChain != nullptr);
1574514f5e3Sopenharmony_ci    auto oldDependChain = GetDependChain(gate);
1584514f5e3Sopenharmony_ci    if (dependChain->Equals(oldDependChain)) {
1594514f5e3Sopenharmony_ci        return Circuit::NullGate();
1604514f5e3Sopenharmony_ci    }
1614514f5e3Sopenharmony_ci    dependChains_[acc_.GetId(gate)] = dependChain;
1624514f5e3Sopenharmony_ci    return gate;
1634514f5e3Sopenharmony_ci}
1644514f5e3Sopenharmony_ci
1654514f5e3Sopenharmony_ciuint32_t RangeGuard::CheckIndexCheckLengthInput(GateRef lhs, GateRef rhs) const
1664514f5e3Sopenharmony_ci{
1674514f5e3Sopenharmony_ci    auto lhsOpcode = acc_.GetOpCode(lhs);
1684514f5e3Sopenharmony_ci    if (lhsOpcode == OpCode::INDEX_CHECK) {
1694514f5e3Sopenharmony_ci        auto indexCheckLengthInput = acc_.GetValueIn(lhs, 0); // length
1704514f5e3Sopenharmony_ci        auto indexCheckLengthInputOpcode = acc_.GetOpCode(indexCheckLengthInput);
1714514f5e3Sopenharmony_ci        if (indexCheckLengthInput == rhs && indexCheckLengthInputOpcode == OpCode::LOAD_TYPED_ARRAY_LENGTH) {
1724514f5e3Sopenharmony_ci            TypedArrayMetaDataAccessor accessor = acc_.GetTypedArrayMetaDataAccessor(indexCheckLengthInput);
1734514f5e3Sopenharmony_ci            OnHeapMode onHeap = accessor.GetOnHeapMode();
1744514f5e3Sopenharmony_ci            int32_t max = onHeap == OnHeapMode::ON_HEAP ? RangeInfo::TYPED_ARRAY_ONHEAP_MAX : INT32_MAX;
1754514f5e3Sopenharmony_ci            return max;
1764514f5e3Sopenharmony_ci        } else if (indexCheckLengthInput == rhs && indexCheckLengthInputOpcode == OpCode::LOAD_ARRAY_LENGTH) {
1774514f5e3Sopenharmony_ci            return INT32_MAX;
1784514f5e3Sopenharmony_ci        }
1794514f5e3Sopenharmony_ci    }
1804514f5e3Sopenharmony_ci    return 0;
1814514f5e3Sopenharmony_ci}
1824514f5e3Sopenharmony_ci
1834514f5e3Sopenharmony_ciuint32_t RangeGuard::CheckIndexCheckIndexInput(GateRef lhs, GateRef rhs) const
1844514f5e3Sopenharmony_ci{
1854514f5e3Sopenharmony_ci    auto lhsOpcode = acc_.GetOpCode(lhs);
1864514f5e3Sopenharmony_ci    if (lhsOpcode == OpCode::INDEX_CHECK) {
1874514f5e3Sopenharmony_ci        auto indexCheckLengthInput = acc_.GetValueIn(lhs, 0); // length
1884514f5e3Sopenharmony_ci        auto indexCheckIndexInput = acc_.GetValueIn(lhs, 1); // index
1894514f5e3Sopenharmony_ci        auto indexCheckLengthInputOpcode = acc_.GetOpCode(indexCheckLengthInput);
1904514f5e3Sopenharmony_ci        // TYPED_ARRAY
1914514f5e3Sopenharmony_ci        if (indexCheckIndexInput == rhs && indexCheckLengthInputOpcode == OpCode::LOAD_TYPED_ARRAY_LENGTH) {
1924514f5e3Sopenharmony_ci            TypedArrayMetaDataAccessor accessor = acc_.GetTypedArrayMetaDataAccessor(indexCheckLengthInput);
1934514f5e3Sopenharmony_ci            OnHeapMode onHeap = accessor.GetOnHeapMode();
1944514f5e3Sopenharmony_ci            int32_t max = onHeap == OnHeapMode::ON_HEAP ? RangeInfo::TYPED_ARRAY_ONHEAP_MAX : INT32_MAX;
1954514f5e3Sopenharmony_ci            return max;
1964514f5e3Sopenharmony_ci        } else if (indexCheckIndexInput == rhs && indexCheckLengthInputOpcode == OpCode::LOAD_ARRAY_LENGTH) { // ARRAY
1974514f5e3Sopenharmony_ci            return INT32_MAX;
1984514f5e3Sopenharmony_ci        }
1994514f5e3Sopenharmony_ci    }
2004514f5e3Sopenharmony_ci    return 0;
2014514f5e3Sopenharmony_ci}
2024514f5e3Sopenharmony_ci}  // namespace panda::ecmascript::kungfu
203