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 
18 namespace panda::ecmascript::kungfu {
NewCommonArg(const CommonArgIdx argIndex, MachineType machineType, GateType gateType)19 void ArgumentAccessor::NewCommonArg(const CommonArgIdx argIndex, MachineType machineType, GateType gateType)
20 {
21     circuit_->NewArg(machineType, static_cast<size_t>(argIndex), gateType, argRoot_);
22 }
23 
NewArg(const size_t argIndex)24 void ArgumentAccessor::NewArg(const size_t argIndex)
25 {
26     circuit_->NewArg(MachineType::I64, argIndex, GateType::TaggedValue(), argRoot_);
27 }
28 
29 // method must be set
GetActualNumArgs() const30 size_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
GetArgGate(const size_t currentVreg) const38 GateRef 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 
ArgGateNotExisted(const size_t currentVreg)51 bool 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 
GetCommonArgGate(const CommonArgIdx arg) const60 GateRef ArgumentAccessor::GetCommonArgGate(const CommonArgIdx arg) const
61 {
62     return args_.at(static_cast<size_t>(arg));
63 }
64 
GetFunctionArgIndex(const size_t currentVreg, const bool haveFunc, const bool haveNewTarget, const bool haveThis) const65 size_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 
CollectArgs()108 void 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 
GetFrameArgsIn(GateRef gate, FrameArgIdx idx)131 GateRef 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