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 auto firstUse = accessor_.ConstUses(stateEntry_).begin();
41 GateRef ifBranchCondition = builder_.Branch(stateEntry_, isEqual);
42 GateRef ifTrueCondition = builder_.IfTrue(ifBranchCondition);
43 GateRef ifFalseCondition = builder_.IfFalse(ifBranchCondition);
44 while (accessor_.GetOpCode(*firstUse) == OpCode::STATE_SPLIT) {
45 firstUse++;
46 }
47 accessor_.ReplaceStateIn(*firstUse, ifTrueCondition);
48
49 GateRef contextOffset = builder_.IntPtr(JSGeneratorObject::GENERATOR_CONTEXT_OFFSET);
50 GateRef val = builder_.PtrAdd(newTarget, contextOffset);
51 GateRef dependStart = builder_.DependRelay(ifFalseCondition, dependEntry_);
52 GateRef contextGate = circuit_->NewGate(circuit_->Load(), MachineType::I64, {dependStart, val},
53 GateType::TaggedPointer());
54 GateRef bcOffset = builder_.IntPtr(GeneratorContext::GENERATOR_BC_OFFSET_OFFSET);
55 val = builder_.PtrAdd(contextGate, bcOffset);
56 GateRef restoreOffsetGate = circuit_->NewGate(circuit_->Load(), MachineType::I32, {contextGate, val},
57 GateType::NJSValue());
58 GateRef firstState = Circuit::NullGate();
59 const auto &suspendAndResumeGates = bcBuilder_->GetAsyncRelatedGates();
60 for (const auto &gate : suspendAndResumeGates) {
61 EcmaOpcode ecmaOpcode = accessor_.GetByteCodeOpcode(gate);
62 if (ecmaOpcode == EcmaOpcode::RESUMEGENERATOR) {
63 RebuildGeneratorCfg(gate, restoreOffsetGate, ifFalseCondition, newTarget, firstState);
64 }
65 }
66 }
67
RebuildGeneratorCfg(GateRef resumeGate,GateRef restoreOffsetGate,GateRef ifFalseCondition,GateRef newTarget,GateRef & firstState)68 void AsyncFunctionLowering::RebuildGeneratorCfg(GateRef resumeGate, GateRef restoreOffsetGate, GateRef ifFalseCondition,
69 GateRef newTarget, GateRef &firstState)
70 {
71 GateRef stateGate = accessor_.GetState(resumeGate);
72 GateRef suspendGate = stateGate;
73 if (accessor_.GetOpCode(suspendGate) == OpCode::IF_SUCCESS) {
74 suspendGate = accessor_.GetState(suspendGate);
75 }
76 GateRef offsetConstantGate = accessor_.GetValueIn(suspendGate);
77 offsetConstantGate = builder_.TruncInt64ToInt32(offsetConstantGate);
78 auto stateInGate = accessor_.GetState(resumeGate);
79 bool flag = true;
80 GateRef prevLoopBeginGate = Circuit::NullGate();
81 GateRef loopBeginStateIn = Circuit::NullGate();
82 GateRef prevBcOffsetPhiGate = Circuit::NullGate();
83 while (true) {
84 if (stateInGate == GetEntryBBStateOut()) { // from state entry
85 GateRef condition = builder_.Equal(offsetConstantGate, restoreOffsetGate);
86 GateRef ifBranch = circuit_->NewGate(circuit_->IfBranch(), { ifFalseCondition, condition });
87 GateRef ifTrue = circuit_->NewGate(circuit_->IfTrue(), {ifBranch});
88 GateRef ifFalse = circuit_->NewGate(circuit_->IfFalse(), {ifBranch});
89 GateRef ifTrueDepend = builder_.DependRelay(ifTrue, restoreOffsetGate);
90 GateRef ifFalseDepend = builder_.DependRelay(ifFalse, restoreOffsetGate);
91 if (flag) {
92 accessor_.ReplaceStateIn(resumeGate, ifTrue);
93 accessor_.ReplaceValueIn(resumeGate, newTarget);
94 accessor_.ReplaceDependIn(resumeGate, ifTrueDepend);
95 circuit_->NewGate(circuit_->Return(), MachineType::NOVALUE,
96 { stateGate, suspendGate, suspendGate, circuit_->GetReturnRoot() },
97 GateType::AnyType());
98 } else {
99 loopBeginStateIn = ifTrue;
100 }
101 accessor_.ReplaceStateIn(ifBranch, ifFalseCondition);
102 if (firstState != Circuit::NullGate()) {
103 accessor_.ReplaceStateIn(firstState, ifFalse);
104 } else {
105 auto constant = builder_.UndefineConstant();
106 circuit_->NewGate(circuit_->Return(), MachineType::NOVALUE,
107 { ifFalse, ifFalseDepend, constant, circuit_->GetReturnRoot() },
108 GateType::AnyType());
109 }
110 firstState = ifBranch;
111 }
112 auto opcode = accessor_.GetOpCode(stateInGate);
113 if (opcode == OpCode::LOOP_BEGIN) {
114 bool resumeInLoopBody = false;
115 CheckResumeInLoopBody(stateInGate, resumeInLoopBody);
116 if (resumeInLoopBody) {
117 // This constant gate must be created by the NewGate method to distinguish whether the while
118 // loop needs to modify the phi node or not.
119 GateRef emptyOffsetGate = circuit_->NewGate(circuit_->GetMetaBuilder()->Constant(-1),
120 MachineType::I32, GateType::NJSValue());
121 // 2: valuesIn
122 GateRef bcOffsetPhiGate = circuit_->NewGate(circuit_->ValueSelector(2), MachineType::I32,
123 {stateInGate, restoreOffsetGate, emptyOffsetGate},
124 GateType::NJSValue());
125
126 GateRef condition = builder_.Equal(offsetConstantGate, bcOffsetPhiGate);
127 GateRef ifBranch = circuit_->NewGate(circuit_->IfBranch(), {stateInGate, condition});
128 GateRef ifTrue = circuit_->NewGate(circuit_->IfTrue(), {ifBranch});
129 GateRef ifFalse = circuit_->NewGate(circuit_->IfFalse(), {ifBranch});
130
131 GateRef resumeStateGate = accessor_.GetState(resumeGate);
132 if (accessor_.GetOpCode(resumeStateGate) != OpCode::IF_TRUE) {
133 accessor_.ReplaceStateIn(resumeGate, ifTrue);
134 accessor_.ReplaceValueIn(resumeGate, newTarget);
135 accessor_.ReplaceDependIn(resumeGate, GetDependPhiFromLoopBegin(stateInGate));
136 circuit_->NewGate(circuit_->Return(), MachineType::NOVALUE,
137 { stateGate, suspendGate, suspendGate, circuit_->GetReturnRoot() },
138 GateType::AnyType());
139 } else {
140 // Handling multi-layer for loops
141 // When in a multi-layer loop, the value-selector node of the prev-loop
142 // should be used directly instead of generating a new node
143 UpdateValueSelector(prevLoopBeginGate, ifTrue, prevBcOffsetPhiGate, false);
144 accessor_.ReplaceValueIn(prevBcOffsetPhiGate, bcOffsetPhiGate);
145 }
146 accessor_.ReplaceStateIn(ifBranch, stateInGate);
147 ModifyStateInput(stateInGate, ifBranch, ifFalse);
148
149 prevLoopBeginGate = stateInGate;
150 prevBcOffsetPhiGate = bcOffsetPhiGate;
151 stateInGate = accessor_.GetState(stateInGate);
152 flag = false;
153 continue;
154 }
155 }
156 if (loopBeginStateIn != Circuit::NullGate()) {
157 UpdateValueSelector(prevLoopBeginGate, loopBeginStateIn, prevBcOffsetPhiGate);
158 break;
159 }
160 if (stateInGate == GetEntryBBStateOut()) {
161 break;
162 }
163 stateInGate = accessor_.GetState(stateInGate);
164 }
165 }
166
UpdateValueSelector(GateRef prevLoopBeginGate,GateRef controlStateGate,GateRef prevBcOffsetPhiGate,bool genNewValuePhiGate)167 void AsyncFunctionLowering::UpdateValueSelector(GateRef prevLoopBeginGate,
168 GateRef controlStateGate,
169 GateRef prevBcOffsetPhiGate,
170 bool genNewValuePhiGate)
171 {
172 GateRef loopBeginFirstState = accessor_.GetState(prevLoopBeginGate);
173 // 2: statesIn
174 GateRef newGate = circuit_->NewGate(circuit_->Merge(2),
175 {controlStateGate, loopBeginFirstState});
176
177 if (genNewValuePhiGate) {
178 GateRef emptyOffsetGate =
179 circuit_->NewGate(circuit_->GetMetaBuilder()->Constant(-1), // -1: distinguish bcoffset
180 MachineType::I32, 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 }
188 accessor_.ReplaceStateIn(prevLoopBeginGate, newGate);
189 auto loopBeginUses = accessor_.Uses(prevLoopBeginGate);
190 for (auto use : loopBeginUses) {
191 if (accessor_.GetOpCode(use) == OpCode::VALUE_SELECTOR && use != prevBcOffsetPhiGate) {
192 auto machineType = accessor_.GetMachineType(use);
193 auto gateType = accessor_.GetGateType(use);
194 GateRef undefinedGate = Circuit::NullGate();
195 if (gateType.IsNumberType()) {
196 undefinedGate =
197 circuit_->NewGate(circuit_->GetMetaBuilder()->Constant(JSTaggedValue::VALUE_ZERO),
198 machineType, GateType::IntType());
199 } else {
200 undefinedGate =
201 circuit_->NewGate(circuit_->GetMetaBuilder()->Constant(JSTaggedValue::VALUE_UNDEFINED),
202 machineType, gateType);
203 }
204 auto firstValueGate = accessor_.GetValueIn(use, 0);
205 auto newValueSelector = circuit_->NewGate(circuit_->ValueSelector(2), machineType, // 2: valuesIn
206 {newGate, undefinedGate, firstValueGate},
207 gateType);
208 accessor_.ReplaceValueIn(use, newValueSelector);
209 } else if (accessor_.GetOpCode(use) == OpCode::DEPEND_SELECTOR) {
210 // if there is a dependSelector in the use node of the loop-begin, a new dependSelector node needs
211 // to be generated. This node is bound to the merge node (newGate) before the loop-begin, and its
212 // input corresponds to the 'dependEntry' (not the frist time enter the function) and
213 // 'dependGate' (the first time enter the function) nodes.
214 auto dependGate = accessor_.GetDep(use);
215 auto newDependSelector = circuit_->NewGate(circuit_->DependSelector(2), // 2: num of dependIn
216 {newGate, circuit_->GetDependRoot(), dependGate});
217 accessor_.ReplaceDependIn(use, newDependSelector);
218 }
219 }
220 }
221
IsAsyncRelated() const222 bool AsyncFunctionLowering::IsAsyncRelated() const
223 {
224 return bcBuilder_->GetAsyncRelatedGates().size() > 0;
225 }
226
ModifyStateInput(GateRef stateInGate,GateRef ifBranch,GateRef ifFalse)227 void AsyncFunctionLowering::ModifyStateInput(GateRef stateInGate, GateRef ifBranch, GateRef ifFalse)
228 {
229 // Find the node with LOOP_BEGIN as State input and modify its
230 // state input to the newly created IF_FALSE node.
231 auto uses = accessor_.Uses(stateInGate);
232 for (auto useIt = uses.begin(); useIt != uses.end();) {
233 GateRef use = *useIt;
234 if (accessor_.IsState(use) && use != ifBranch) {
235 useIt = accessor_.ReplaceIn(useIt, ifFalse);
236 } else {
237 useIt++;
238 }
239 }
240 }
241
CheckResumeInLoopBody(GateRef stateInGate,bool & resumeInLoopBody)242 void AsyncFunctionLowering::CheckResumeInLoopBody(GateRef stateInGate, bool &resumeInLoopBody)
243 {
244 ASSERT(accessor_.GetOpCode(stateInGate) == OpCode::LOOP_BEGIN);
245 GateRef loopBack = accessor_.GetIn(stateInGate, 0);
246 if (accessor_.GetOpCode(loopBack) != OpCode::LOOP_BACK) {
247 loopBack = accessor_.GetIn(stateInGate, 1);
248 }
249 ChunkQueue<GateRef> resuemList(circuit_->chunk());
250 resuemList.push(loopBack);
251 ChunkVector<VisitState> visited(circuit_->GetMaxGateId() + 1, VisitState::UNVISITED, circuit_->chunk());
252 auto loopBeginId = accessor_.GetId(stateInGate);
253 visited[loopBeginId] = VisitState::VISITED;
254 auto loopBackId = accessor_.GetId(loopBack);
255 visited[loopBackId] = VisitState::VISITED;
256 while (!resuemList.empty()) {
257 GateRef curGate = resuemList.front();
258 if (accessor_.GetOpCode(curGate) == OpCode::JS_BYTECODE &&
259 accessor_.GetByteCodeOpcode(curGate) == EcmaOpcode::RESUMEGENERATOR) {
260 resumeInLoopBody = true;
261 break;
262 }
263 resuemList.pop();
264 size_t stateStart = 0;
265 size_t stateEnd = accessor_.GetStateCount(curGate);
266 for (size_t idx = stateStart; idx < stateEnd; idx++) {
267 GateRef gate = accessor_.GetState(curGate, idx);
268 auto id = accessor_.GetId(gate);
269 if (visited[id] == VisitState::UNVISITED) {
270 visited[id] = VisitState::VISITED;
271 resuemList.push(gate);
272 }
273 }
274 }
275 }
276
GetDependPhiFromLoopBegin(GateRef gate) const277 GateRef AsyncFunctionLowering::GetDependPhiFromLoopBegin(GateRef gate) const
278 {
279 auto loopBeginUses = accessor_.ConstUses(gate);
280 for (auto use : loopBeginUses) {
281 if (accessor_.GetOpCode(use) == OpCode::DEPEND_SELECTOR) {
282 return use;
283 }
284 }
285 LOG_COMPILER(FATAL) << "Can not find depend-selector from loopbegin";
286 return Circuit::NullGate();
287 }
288
GetEntryBBStateOut() const289 GateRef AsyncFunctionLowering::GetEntryBBStateOut() const
290 {
291 auto bb = bcBuilder_->GetBasicBlockById(1); // 1 : First Block Id
292 auto state = bb.stateCurrent;
293 if (accessor_.IsCFGMerge(state)) {
294 return accessor_.GetState(state);
295 } else {
296 return state;
297 }
298 }
299
GetEntryBBDependOut() const300 GateRef AsyncFunctionLowering::GetEntryBBDependOut() const
301 {
302 auto bb = bcBuilder_->GetBasicBlockById(1); // 1 : First Block Id
303 auto depend = bb.dependCurrent;
304 if (accessor_.IsDependSelector(depend)) {
305 return accessor_.GetDep(depend);
306 } else {
307 return depend;
308 }
309 }
310 } // panda::ecmascript::kungfu
311
312