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