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