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/async_function_lowering.h"
17
18 namespace panda::ecmascript::kungfu {
ProcessAll()19 void AsyncFunctionLowering::ProcessAll()
20 {
21 ProcessJumpTable();
22
23 if (IsLogEnabled()) {
24 LOG_COMPILER(INFO) << "";
25 LOG_COMPILER(INFO) << "\033[34m"
26 << "===================="
27 << " After async function lowering "
28 << "[" << GetMethodName() << "]"
29 << "===================="
30 << "\033[0m";
31 circuit_->PrintAllGatesWithBytecode();
32 LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
33 }
34 }
35
ProcessJumpTable()36 void AsyncFunctionLowering::ProcessJumpTable()
37 {
38 GateRef newTarget = argAccessor_.GetCommonArgGate(CommonArgIdx::NEW_TARGET);
39 GateRef isEqual = builder_.Equal(newTarget, builder_.Undefined());
40 GateRef stateEntryState = *accessor_.ConstUses(stateEntry_).begin();
41 GateRef ifBranchCondition = builder_.Branch(stateEntry_, isEqual);
42 GateRef ifTrueCondition = builder_.IfTrue(ifBranchCondition);
43 GateRef ifFalseCondition = builder_.IfFalse(ifBranchCondition);
44 accessor_.ReplaceStateIn(stateEntryState, ifTrueCondition);
45
46 GateRef contextOffset = builder_.IntPtr(JSGeneratorObject::GENERATOR_CONTEXT_OFFSET);
47 GateRef val = builder_.PtrAdd(newTarget, contextOffset);
48 GateRef dependStart = builder_.DependRelay(ifFalseCondition, dependEntry_);
49 GateRef contextGate = circuit_->NewGate(circuit_->Load(), MachineType::I64, {dependStart, val},
50 GateType::TaggedPointer());
51 GateRef bcOffset = builder_.IntPtr(GeneratorContext::GENERATOR_BC_OFFSET_OFFSET);
52 val = builder_.PtrAdd(contextGate, bcOffset);
53 GateRef restoreOffsetGate = circuit_->NewGate(circuit_->Load(), MachineType::I32, {contextGate, val},
54 GateType::NJSValue());
55 GateRef firstState = Circuit::NullGate();
56 const auto &suspendAndResumeGates = bcBuilder_->GetAsyncRelatedGates();
57 for (const auto &gate : suspendAndResumeGates) {
58 EcmaOpcode ecmaOpcode = accessor_.GetByteCodeOpcode(gate);
59 if (ecmaOpcode == EcmaOpcode::RESUMEGENERATOR) {
60 RebuildGeneratorCfg(gate, restoreOffsetGate, ifFalseCondition, newTarget, firstState);
61 }
62 }
63 }
64
RebuildGeneratorCfg(GateRef resumeGate,GateRef restoreOffsetGate,GateRef ifFalseCondition,GateRef newTarget,GateRef & firstState)65 void AsyncFunctionLowering::RebuildGeneratorCfg(GateRef resumeGate, GateRef restoreOffsetGate, GateRef ifFalseCondition,
66 GateRef newTarget, GateRef &firstState)
67 {
68 GateRef stateGate = accessor_.GetState(resumeGate);
69 GateRef suspendGate = stateGate;
70 if (accessor_.GetOpCode(suspendGate) == OpCode::IF_SUCCESS) {
71 suspendGate = accessor_.GetState(suspendGate);
72 }
73 GateRef firstRestoreRegGate = GetFirstRestoreRegister(resumeGate);
74 GateRef offsetConstantGate = accessor_.GetValueIn(suspendGate);
75 offsetConstantGate = builder_.TruncInt64ToInt32(offsetConstantGate);
76 auto stateInGate = accessor_.GetState(resumeGate);
77 bool flag = true;
78 GateRef prevLoopBeginGate = Circuit::NullGate();
79 GateRef loopBeginStateIn = Circuit::NullGate();
80 GateRef prevBcOffsetPhiGate = Circuit::NullGate();
81 while (true) {
82 auto opcode = accessor_.GetOpCode(stateInGate);
83 if (opcode == OpCode::STATE_ENTRY) {
84 GateRef condition = builder_.Equal(offsetConstantGate, restoreOffsetGate);
85 GateRef ifBranch = circuit_->NewGate(circuit_->IfBranch(), { ifFalseCondition, condition });
86 GateRef ifTrue = circuit_->NewGate(circuit_->IfTrue(), {ifBranch});
87 GateRef ifFalse = circuit_->NewGate(circuit_->IfFalse(), {ifBranch});
88 GateRef ifTrueDepend = builder_.DependRelay(ifTrue, restoreOffsetGate);
89 GateRef ifFalseDepend = builder_.DependRelay(ifFalse, restoreOffsetGate);
90 if (flag) {
91 accessor_.ReplaceStateIn(resumeGate, ifTrue);
92 accessor_.ReplaceValueIn(resumeGate, newTarget);
93 accessor_.ReplaceDependIn(firstRestoreRegGate, ifTrueDepend);
94 circuit_->NewGate(circuit_->Return(), MachineType::NOVALUE,
95 { stateGate, suspendGate, suspendGate, circuit_->GetReturnRoot() },
96 GateType::AnyType());
97 } else {
98 loopBeginStateIn = ifTrue;
99 }
100 accessor_.ReplaceStateIn(ifBranch, ifFalseCondition);
101 if (firstState != Circuit::NullGate()) {
102 accessor_.ReplaceStateIn(firstState, ifFalse);
103 } else {
104 auto constant = builder_.UndefineConstant();
105 circuit_->NewGate(circuit_->Return(), MachineType::NOVALUE,
106 { ifFalse, ifFalseDepend, constant, circuit_->GetReturnRoot() },
107 GateType::AnyType());
108 }
109 firstState = ifBranch;
110 }
111
112 if (opcode == OpCode::LOOP_BEGIN) {
113 // This constant gate must be created by the NewGate method to distinguish whether the while
114 // loop needs to modify the phi node or not.
115 GateRef emptyOffsetGate = circuit_->GetConstantGate(MachineType::I32, static_cast<uint64_t>(-1),
116 GateType::NJSValue());
117 // 2: valuesIn
118 GateRef bcOffsetPhiGate = circuit_->NewGate(circuit_->ValueSelector(2), MachineType::I32,
119 {stateInGate, restoreOffsetGate, emptyOffsetGate},
120 GateType::NJSValue());
121
122 GateRef condition = builder_.Equal(offsetConstantGate, bcOffsetPhiGate);
123 GateRef ifBranch = circuit_->NewGate(circuit_->IfBranch(), {stateInGate, condition});
124 GateRef ifTrue = circuit_->NewGate(circuit_->IfTrue(), {ifBranch});
125 GateRef ifFalse = circuit_->NewGate(circuit_->IfFalse(), {ifBranch});
126
127 GateRef resumeStateGate = accessor_.GetState(resumeGate);
128 if (accessor_.GetOpCode(resumeStateGate) != OpCode::IF_TRUE) {
129 accessor_.ReplaceStateIn(resumeGate, ifTrue);
130 accessor_.ReplaceValueIn(resumeGate, newTarget);
131 accessor_.ReplaceDependIn(firstRestoreRegGate, bcOffsetPhiGate);
132 circuit_->NewGate(circuit_->Return(), MachineType::NOVALUE,
133 { stateGate, suspendGate, suspendGate, circuit_->GetReturnRoot() },
134 GateType::AnyType());
135 } else {
136 // Handling multi-layer for loops
137 UpdateValueSelector(prevLoopBeginGate, ifTrue, prevBcOffsetPhiGate);
138 accessor_.ReplaceValueIn(prevBcOffsetPhiGate, bcOffsetPhiGate);
139 }
140 accessor_.ReplaceStateIn(ifBranch, stateInGate);
141
142 // Find the node with LOOP_BEGIN as State input and modify its
143 // state input to the newly created IF_FALSE node.
144 auto uses = accessor_.Uses(stateInGate);
145 for (auto useIt = uses.begin(); useIt != uses.end();) {
146 if (accessor_.GetMetaData(*useIt)->IsState() && *useIt != ifBranch) {
147 useIt = accessor_.ReplaceIn(useIt, ifFalse);
148 } else {
149 useIt++;
150 }
151 }
152
153 prevLoopBeginGate = stateInGate;
154 prevBcOffsetPhiGate = bcOffsetPhiGate;
155 stateInGate = accessor_.GetState(stateInGate);
156 flag = false;
157 continue;
158 }
159 if (loopBeginStateIn != Circuit::NullGate()) {
160 UpdateValueSelector(prevLoopBeginGate, loopBeginStateIn, prevBcOffsetPhiGate);
161 break;
162 }
163 if (accessor_.GetOpCode(stateInGate) == OpCode::STATE_ENTRY) {
164 break;
165 }
166 stateInGate = accessor_.GetState(stateInGate);
167 }
168 }
169
UpdateValueSelector(GateRef prevLoopBeginGate,GateRef controlStateGate,GateRef prevBcOffsetPhiGate)170 void AsyncFunctionLowering::UpdateValueSelector(GateRef prevLoopBeginGate,
171 GateRef controlStateGate,
172 GateRef prevBcOffsetPhiGate)
173 {
174 GateRef loopBeginFirstState = accessor_.GetState(prevLoopBeginGate);
175 // 2: statesIn
176 GateRef newGate = circuit_->NewGate(circuit_->Merge(2),
177 {controlStateGate, loopBeginFirstState});
178 GateRef emptyOffsetGate = circuit_->GetConstantGate(MachineType::I32,
179 static_cast<uint64_t>(-1), // -1: distinguish bcoffset
180 GateType::NJSValue());
181 GateRef restoreOffset = accessor_.GetValueIn(prevBcOffsetPhiGate);
182 // this value selector is compatible with await in the loop body
183 GateRef valueSelector = circuit_->NewGate(circuit_->ValueSelector(2), MachineType::I32, // 2: num of valueIn
184 {newGate, restoreOffset, emptyOffsetGate},
185 GateType::NJSValue());
186 accessor_.ReplaceValueIn(prevBcOffsetPhiGate, valueSelector);
187 accessor_.ReplaceStateIn(prevLoopBeginGate, newGate);
188 auto loopBeginUses = accessor_.Uses(prevLoopBeginGate);
189 for (auto use : loopBeginUses) {
190 if (accessor_.GetOpCode(use) == OpCode::VALUE_SELECTOR && use != prevBcOffsetPhiGate) {
191 auto machineType = accessor_.GetMachineType(use);
192 auto gateType = accessor_.GetGateType(use);
193 auto undefinedGate =
194 accessor_.GetConstantGate(machineType, JSTaggedValue::VALUE_UNDEFINED, gateType);
195 auto firstValueGate = accessor_.GetValueIn(use, 0);
196 auto newValueSelector = circuit_->NewGate(circuit_->ValueSelector(2), machineType, // 2: valuesIn
197 {newGate, undefinedGate, firstValueGate},
198 gateType);
199 accessor_.ReplaceValueIn(use, newValueSelector);
200 }
201 }
202 }
203
IsAsyncRelated() const204 bool AsyncFunctionLowering::IsAsyncRelated() const
205 {
206 return bcBuilder_->GetAsyncRelatedGates().size() > 0;
207 }
208
GetFirstRestoreRegister(GateRef gate) const209 GateRef AsyncFunctionLowering::GetFirstRestoreRegister(GateRef gate) const
210 {
211 GateRef firstRestoreGate = gate;
212 GateRef curRestoreGate = accessor_.GetDep(gate);
213 while (accessor_.GetOpCode(curRestoreGate) == OpCode::RESTORE_REGISTER) {
214 firstRestoreGate = curRestoreGate;
215 curRestoreGate = accessor_.GetDep(curRestoreGate);
216 }
217 return firstRestoreGate;
218 }
219 } // panda::ecmascript::kungfu
220
221