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