• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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