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
16#include "ecmascript/compiler/argument_accessor.h"
17
18namespace panda::ecmascript::kungfu {
19void ArgumentAccessor::NewCommonArg(const CommonArgIdx argIndex, MachineType machineType, GateType gateType)
20{
21    circuit_->NewArg(machineType, static_cast<size_t>(argIndex), gateType, argRoot_);
22}
23
24void ArgumentAccessor::NewArg(const size_t argIndex)
25{
26    circuit_->NewArg(MachineType::I64, argIndex, GateType::TaggedValue(), argRoot_);
27}
28
29// method must be set
30size_t ArgumentAccessor::GetActualNumArgs() const
31{
32    ASSERT(method_ != nullptr);
33    auto numArgs = method_->GetNumArgsWithCallField();
34    return static_cast<size_t>(CommonArgIdx::NUM_OF_ARGS) + numArgs;
35}
36
37// method must be set
38GateRef ArgumentAccessor::GetArgGate(const size_t currentVreg) const
39{
40    ASSERT(method_ != nullptr);
41    const size_t offsetArgs = method_->GetNumVregsWithCallField();
42    ASSERT(currentVreg >= offsetArgs && currentVreg < offsetArgs + method_->GetNumArgs());
43    auto reg = currentVreg - offsetArgs;
44    auto haveFunc = method_->HaveFuncWithCallField();
45    auto haveNewTarget = method_->HaveNewTargetWithCallField();
46    auto haveThis = method_->HaveThisWithCallField();
47    auto index = GetFunctionArgIndex(reg, haveFunc, haveNewTarget, haveThis);
48    return args_.at(index);
49}
50
51bool ArgumentAccessor::ArgGateNotExisted(const size_t currentVreg)
52{
53    const size_t offsetArgs = method_->GetNumVregsWithCallField();
54    if (currentVreg < offsetArgs || currentVreg >= offsetArgs + method_->GetNumArgs()) {
55        return true;
56    }
57    return false;
58}
59
60GateRef ArgumentAccessor::GetCommonArgGate(const CommonArgIdx arg) const
61{
62    return args_.at(static_cast<size_t>(arg));
63}
64
65size_t ArgumentAccessor::GetFunctionArgIndex(const size_t currentVreg, const bool haveFunc,
66                                             const bool haveNewTarget, const bool haveThis) const
67{
68    size_t numCommonArgs = haveFunc + haveNewTarget + haveThis;
69    // 2: number of common args
70    if (numCommonArgs == 2) {
71        if (!haveFunc && currentVreg == 0) {
72            return static_cast<size_t>(CommonArgIdx::NEW_TARGET);
73        }
74        if (!haveFunc && currentVreg == 1) {
75            return static_cast<size_t>(CommonArgIdx::THIS_OBJECT);
76        }
77        if (!haveNewTarget && currentVreg == 0) {
78            return static_cast<size_t>(CommonArgIdx::FUNC);
79        }
80        if (!haveNewTarget && currentVreg == 1) {
81            return static_cast<size_t>(CommonArgIdx::THIS_OBJECT);
82        }
83        if (!haveThis && currentVreg == 0) {
84            return static_cast<size_t>(CommonArgIdx::FUNC);
85        }
86        if (!haveThis && currentVreg == 1) {
87            return static_cast<size_t>(CommonArgIdx::NEW_TARGET);
88        }
89    }
90    // 1: number of common args, 0: the index of currentVreg
91    if (numCommonArgs == 1 && currentVreg == 0) {
92        if (haveFunc) {
93            return static_cast<size_t>(CommonArgIdx::FUNC);
94        }
95        if (haveNewTarget) {
96            return static_cast<size_t>(CommonArgIdx::NEW_TARGET);
97        }
98        if (haveThis) {
99            return static_cast<size_t>(CommonArgIdx::THIS_OBJECT);
100        }
101    }
102
103    size_t numOfArgs = static_cast<size_t>(CommonArgIdx::NUM_OF_ARGS);
104    ASSERT(currentVreg + numOfArgs >= numCommonArgs);
105    return currentVreg + numOfArgs - numCommonArgs;
106}
107
108void ArgumentAccessor::CollectArgs()
109{
110    if (args_.size() == 0) {
111        GateAccessor(circuit_).GetArgsOuts(args_);
112        std::reverse(args_.begin(), args_.end());
113        if (method_ == nullptr) {
114            return;
115        }
116        if (method_->IsFastCall() && args_.size() > 2) { // 2: mean have func and glue
117            GateRef actualArgcGate = circuit_->GetConstantGate(MachineType::I64, 0, GateType::NJSValue());
118            GateRef actualArgvGate = circuit_->GetConstantGate(MachineType::ARCH, 0, GateType::NJSValue());
119            GateRef newTargetGate = circuit_->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_UNDEFINED,
120                GateType::UndefinedType());
121            if (method_->GetFunctionKind() == FunctionKind::CLASS_CONSTRUCTOR) {
122                newTargetGate = args_[1]; // 1: mean func index
123            }
124            args_.insert(args_.begin() + static_cast<size_t>(CommonArgIdx::ACTUAL_ARGC), actualArgcGate);
125            args_.insert(args_.begin() + static_cast<size_t>(CommonArgIdx::ACTUAL_ARGV), actualArgvGate);
126            args_.insert(args_.begin() + static_cast<size_t>(CommonArgIdx::NEW_TARGET), newTargetGate);
127        }
128    }
129}
130
131GateRef ArgumentAccessor::GetFrameArgsIn(GateRef gate, FrameArgIdx idx)
132{
133    GateAccessor gateAcc(circuit_);
134    OpCode opCode = gateAcc.GetOpCode(gate);
135    ASSERT(opCode == OpCode::JS_BYTECODE || opCode == OpCode::FRAME_STATE);
136    GateRef frameArgs = Circuit::NullGate();
137    if (opCode == OpCode::JS_BYTECODE) {
138        GateRef frameState = gateAcc.GetFrameState(gate);
139        OpCode op = gateAcc.GetOpCode(frameState);
140        if (op == OpCode::FRAME_STATE) {
141            frameArgs = gateAcc.GetValueIn(frameState, 0); // 0: frame args
142        } else {
143            ASSERT(op == OpCode::FRAME_ARGS);
144            frameArgs = frameState;
145        }
146    } else {
147        frameArgs = gateAcc.GetValueIn(gate, 0); // 0: frame args
148    }
149    return gateAcc.GetValueIn(frameArgs, static_cast<size_t>(idx));
150}
151}  // namespace panda::ecmascript::kungfu
152