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