• 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     GateRef stateEntryState = *accessor_.ConstUses(stateEntry_).begin();
41     GateRef ifBranchCondition = builder_.Branch(stateEntry_, isEqual);
42     GateRef ifTrueCondition = builder_.IfTrue(ifBranchCondition);
43     GateRef ifFalseCondition = builder_.IfFalse(ifBranchCondition);
44     accessor_.ReplaceStateIn(stateEntryState, ifTrueCondition);
45 
46     GateRef contextOffset = builder_.IntPtr(JSGeneratorObject::GENERATOR_CONTEXT_OFFSET);
47     GateRef val = builder_.PtrAdd(newTarget, contextOffset);
48     GateRef dependStart = builder_.DependRelay(ifFalseCondition, dependEntry_);
49     GateRef contextGate = circuit_->NewGate(circuit_->Load(), MachineType::I64, {dependStart, val},
50                                             GateType::TaggedPointer());
51     GateRef bcOffset = builder_.IntPtr(GeneratorContext::GENERATOR_BC_OFFSET_OFFSET);
52     val = builder_.PtrAdd(contextGate, bcOffset);
53     GateRef restoreOffsetGate = circuit_->NewGate(circuit_->Load(), MachineType::I32, {contextGate, val},
54                                                   GateType::NJSValue());
55     GateRef firstState = Circuit::NullGate();
56     const auto &suspendAndResumeGates = bcBuilder_->GetAsyncRelatedGates();
57     for (const auto &gate : suspendAndResumeGates) {
58         EcmaOpcode ecmaOpcode = accessor_.GetByteCodeOpcode(gate);
59         if (ecmaOpcode == EcmaOpcode::RESUMEGENERATOR) {
60             RebuildGeneratorCfg(gate, restoreOffsetGate, ifFalseCondition, newTarget, firstState);
61         }
62     }
63 }
64 
RebuildGeneratorCfg(GateRef resumeGate,GateRef restoreOffsetGate,GateRef ifFalseCondition,GateRef newTarget,GateRef & firstState)65 void AsyncFunctionLowering::RebuildGeneratorCfg(GateRef resumeGate, GateRef restoreOffsetGate, GateRef ifFalseCondition,
66                                                 GateRef newTarget, GateRef &firstState)
67 {
68     GateRef stateGate = accessor_.GetState(resumeGate);
69     GateRef suspendGate = stateGate;
70     if (accessor_.GetOpCode(suspendGate) == OpCode::IF_SUCCESS) {
71         suspendGate = accessor_.GetState(suspendGate);
72     }
73     GateRef firstRestoreRegGate = GetFirstRestoreRegister(resumeGate);
74     GateRef offsetConstantGate = accessor_.GetValueIn(suspendGate);
75     offsetConstantGate = builder_.TruncInt64ToInt32(offsetConstantGate);
76     auto stateInGate = accessor_.GetState(resumeGate);
77     bool flag = true;
78     GateRef prevLoopBeginGate = Circuit::NullGate();
79     GateRef loopBeginStateIn = Circuit::NullGate();
80     GateRef prevBcOffsetPhiGate = Circuit::NullGate();
81     while (true) {
82         auto opcode = accessor_.GetOpCode(stateInGate);
83         if (opcode == OpCode::STATE_ENTRY) {
84             GateRef condition = builder_.Equal(offsetConstantGate, restoreOffsetGate);
85             GateRef ifBranch = circuit_->NewGate(circuit_->IfBranch(), { ifFalseCondition, condition });
86             GateRef ifTrue = circuit_->NewGate(circuit_->IfTrue(), {ifBranch});
87             GateRef ifFalse = circuit_->NewGate(circuit_->IfFalse(), {ifBranch});
88             GateRef ifTrueDepend = builder_.DependRelay(ifTrue, restoreOffsetGate);
89             GateRef ifFalseDepend = builder_.DependRelay(ifFalse, restoreOffsetGate);
90             if (flag) {
91                 accessor_.ReplaceStateIn(resumeGate, ifTrue);
92                 accessor_.ReplaceValueIn(resumeGate, newTarget);
93                 accessor_.ReplaceDependIn(firstRestoreRegGate, ifTrueDepend);
94                 circuit_->NewGate(circuit_->Return(), MachineType::NOVALUE,
95                     { stateGate, suspendGate, suspendGate, circuit_->GetReturnRoot() },
96                     GateType::AnyType());
97             } else {
98                 loopBeginStateIn = ifTrue;
99             }
100             accessor_.ReplaceStateIn(ifBranch, ifFalseCondition);
101             if (firstState != Circuit::NullGate()) {
102                 accessor_.ReplaceStateIn(firstState, ifFalse);
103             } else {
104                 auto constant = builder_.UndefineConstant();
105                 circuit_->NewGate(circuit_->Return(), MachineType::NOVALUE,
106                     { ifFalse, ifFalseDepend, constant, circuit_->GetReturnRoot() },
107                     GateType::AnyType());
108             }
109             firstState = ifBranch;
110         }
111 
112         if (opcode == OpCode::LOOP_BEGIN) {
113             // This constant gate must be created by the NewGate method to distinguish whether the while
114             // loop needs to modify the phi node or not.
115             GateRef emptyOffsetGate = circuit_->GetConstantGate(MachineType::I32, static_cast<uint64_t>(-1),
116                                                                 GateType::NJSValue());
117             // 2: valuesIn
118             GateRef bcOffsetPhiGate = circuit_->NewGate(circuit_->ValueSelector(2), MachineType::I32,
119                                                         {stateInGate, restoreOffsetGate, emptyOffsetGate},
120                                                         GateType::NJSValue());
121 
122             GateRef condition = builder_.Equal(offsetConstantGate, bcOffsetPhiGate);
123             GateRef ifBranch = circuit_->NewGate(circuit_->IfBranch(), {stateInGate, condition});
124             GateRef ifTrue = circuit_->NewGate(circuit_->IfTrue(), {ifBranch});
125             GateRef ifFalse = circuit_->NewGate(circuit_->IfFalse(), {ifBranch});
126 
127             GateRef resumeStateGate = accessor_.GetState(resumeGate);
128             if (accessor_.GetOpCode(resumeStateGate) != OpCode::IF_TRUE) {
129                 accessor_.ReplaceStateIn(resumeGate, ifTrue);
130                 accessor_.ReplaceValueIn(resumeGate, newTarget);
131                 accessor_.ReplaceDependIn(firstRestoreRegGate, bcOffsetPhiGate);
132                 circuit_->NewGate(circuit_->Return(), MachineType::NOVALUE,
133                     { stateGate, suspendGate, suspendGate, circuit_->GetReturnRoot() },
134                     GateType::AnyType());
135             } else {
136                 // Handling multi-layer for loops
137                 UpdateValueSelector(prevLoopBeginGate, ifTrue, prevBcOffsetPhiGate);
138                 accessor_.ReplaceValueIn(prevBcOffsetPhiGate, bcOffsetPhiGate);
139             }
140             accessor_.ReplaceStateIn(ifBranch, stateInGate);
141 
142             // Find the node with LOOP_BEGIN as State input and modify its
143             // state input to the newly created IF_FALSE node.
144             auto uses = accessor_.Uses(stateInGate);
145             for (auto useIt = uses.begin(); useIt != uses.end();) {
146                 if (accessor_.GetMetaData(*useIt)->IsState() && *useIt != ifBranch) {
147                     useIt = accessor_.ReplaceIn(useIt, ifFalse);
148                 } else {
149                     useIt++;
150                 }
151             }
152 
153             prevLoopBeginGate = stateInGate;
154             prevBcOffsetPhiGate = bcOffsetPhiGate;
155             stateInGate = accessor_.GetState(stateInGate);
156             flag = false;
157             continue;
158         }
159         if (loopBeginStateIn != Circuit::NullGate()) {
160             UpdateValueSelector(prevLoopBeginGate, loopBeginStateIn, prevBcOffsetPhiGate);
161             break;
162         }
163         if (accessor_.GetOpCode(stateInGate) == OpCode::STATE_ENTRY) {
164             break;
165         }
166         stateInGate = accessor_.GetState(stateInGate);
167     }
168 }
169 
UpdateValueSelector(GateRef prevLoopBeginGate,GateRef controlStateGate,GateRef prevBcOffsetPhiGate)170 void AsyncFunctionLowering::UpdateValueSelector(GateRef prevLoopBeginGate,
171                                                 GateRef controlStateGate,
172                                                 GateRef prevBcOffsetPhiGate)
173 {
174     GateRef loopBeginFirstState = accessor_.GetState(prevLoopBeginGate);
175     // 2: statesIn
176     GateRef newGate = circuit_->NewGate(circuit_->Merge(2),
177                                         {controlStateGate, loopBeginFirstState});
178     GateRef emptyOffsetGate = circuit_->GetConstantGate(MachineType::I32,
179                                                         static_cast<uint64_t>(-1), // -1: distinguish bcoffset
180                                                         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     accessor_.ReplaceStateIn(prevLoopBeginGate, newGate);
188     auto loopBeginUses = accessor_.Uses(prevLoopBeginGate);
189     for (auto use : loopBeginUses) {
190         if (accessor_.GetOpCode(use) == OpCode::VALUE_SELECTOR && use != prevBcOffsetPhiGate) {
191             auto machineType = accessor_.GetMachineType(use);
192             auto gateType = accessor_.GetGateType(use);
193             auto undefinedGate =
194                 accessor_.GetConstantGate(machineType, JSTaggedValue::VALUE_UNDEFINED, gateType);
195             auto firstValueGate = accessor_.GetValueIn(use, 0);
196             auto newValueSelector = circuit_->NewGate(circuit_->ValueSelector(2), machineType, // 2: valuesIn
197                                                       {newGate, undefinedGate, firstValueGate},
198                                                       gateType);
199             accessor_.ReplaceValueIn(use, newValueSelector);
200         }
201     }
202 }
203 
IsAsyncRelated() const204 bool AsyncFunctionLowering::IsAsyncRelated() const
205 {
206     return  bcBuilder_->GetAsyncRelatedGates().size() > 0;
207 }
208 
GetFirstRestoreRegister(GateRef gate) const209 GateRef AsyncFunctionLowering::GetFirstRestoreRegister(GateRef gate) const
210 {
211     GateRef firstRestoreGate = gate;
212     GateRef curRestoreGate = accessor_.GetDep(gate);
213     while (accessor_.GetOpCode(curRestoreGate) == OpCode::RESTORE_REGISTER) {
214         firstRestoreGate = curRestoreGate;
215         curRestoreGate = accessor_.GetDep(curRestoreGate);
216     }
217     return firstRestoreGate;
218 }
219 }  // panda::ecmascript::kungfu
220 
221