• 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 #include "ecmascript/compiler/bytecode_circuit_builder.h"
16 #include "ecmascript/compiler/frame_states.h"
17 
18 namespace panda::ecmascript::kungfu {
FrameStateBuilder(BytecodeCircuitBuilder * builder,Circuit * circuit,const MethodLiteral * literal)19 FrameStateBuilder::FrameStateBuilder(BytecodeCircuitBuilder *builder,
20     Circuit *circuit, const MethodLiteral *literal)
21     : builder_(builder),
22       numVregs_(literal->GetNumberVRegs() + 2), // 2: env and acc
23       accumulatorIndex_(literal->GetNumberVRegs() + 1), // 1: acc
24       circuit_(circuit),
25       gateAcc_(circuit),
26       argAcc_(circuit)
27 {
28 }
29 
~FrameStateBuilder()30 FrameStateBuilder::~FrameStateBuilder()
31 {
32     for (auto state : bcEndStateInfos_) {
33         if (state != nullptr) {
34             delete state;
35         }
36     }
37     for (auto state : bbBeginStateInfos_) {
38         if (state != nullptr) {
39             delete state;
40         }
41     }
42     if (liveOutResult_ != nullptr) {
43         delete liveOutResult_;
44     }
45     liveOutResult_ = nullptr;
46     bcEndStateInfos_.clear();
47     bbBeginStateInfos_.clear();
48     builder_ = nullptr;
49 }
50 
FrameState(size_t pcOffset,FrameStateInfo * stateInfo)51 GateRef FrameStateBuilder::FrameState(size_t pcOffset, FrameStateInfo *stateInfo)
52 {
53     size_t frameStateInputs = numVregs_ + 1; // +1: for pc
54     std::vector<GateRef> inList(frameStateInputs, Circuit::NullGate());
55     auto optimizedGate = circuit_->GetConstantGate(MachineType::I64,
56                                                    JSTaggedValue::VALUE_OPTIMIZED_OUT,
57                                                    GateType::TaggedValue());
58     for (size_t i = 0; i < numVregs_; i++) {
59         auto value = stateInfo->ValuesAt(i);
60         if (value == Circuit::NullGate()) {
61             value = optimizedGate;
62         }
63         inList[i] = value;
64     }
65     auto pcGate = circuit_->GetConstantGate(MachineType::I64,
66                                             pcOffset,
67                                             GateType::NJSValue());
68     inList[numVregs_] = pcGate;
69     return circuit_->NewGate(circuit_->FrameState(frameStateInputs), inList);
70 }
71 
BindStateSplit(GateRef gate,size_t pcOffset,FrameStateInfo * stateInfo)72 void FrameStateBuilder::BindStateSplit(GateRef gate, size_t pcOffset, FrameStateInfo *stateInfo)
73 {
74     auto depend = gateAcc_.GetDep(gate);
75     GateRef frameState = FrameState(pcOffset, stateInfo);
76     GateRef stateSplit = circuit_->NewGate(circuit_->StateSplit(), {depend, frameState});
77     gateAcc_.ReplaceDependIn(gate, stateSplit);
78     if (builder_->IsLogEnabled()) {
79         gateAcc_.ShortPrint(frameState);
80     }
81 }
82 
CreateEmptyStateInfo()83 FrameStateInfo *FrameStateBuilder::CreateEmptyStateInfo()
84 {
85     auto frameInfo = new FrameStateInfo(numVregs_);
86     for (size_t i = 0; i < numVregs_; i++) {
87         frameInfo->SetValuesAt(i, Circuit::NullGate());
88     }
89     return frameInfo;
90 }
91 
BuildPostOrderList(size_t size)92 void FrameStateBuilder::BuildPostOrderList(size_t size)
93 {
94     postOrderList_.clear();
95     std::deque<size_t> pendingList;
96     std::vector<bool> visited(size, false);
97     auto entryId = 0;
98     pendingList.emplace_back(entryId);
99 
100     while (!pendingList.empty()) {
101         size_t curBlockId = pendingList.back();
102         visited[curBlockId] = true;
103 
104         bool change = false;
105         auto &bb = builder_->GetBasicBlockById(curBlockId);
106         for (const auto &succBlock: bb.succs) {
107             if (!visited[succBlock->id]) {
108                 pendingList.emplace_back(succBlock->id);
109                 change = true;
110                 break;
111             }
112         }
113         if (change) {
114             continue;
115         }
116         for (const auto &succBlock: bb.catchs) {
117             if (!visited[succBlock->id]) {
118                 pendingList.emplace_back(succBlock->id);
119                 change = true;
120                 break;
121             }
122         }
123         if (!change) {
124             postOrderList_.emplace_back(curBlockId);
125             pendingList.pop_back();
126         }
127     }
128 }
129 
MergeIntoPredBC(uint32_t predPc)130 bool FrameStateBuilder::MergeIntoPredBC(uint32_t predPc)
131 {
132     // liveout next
133     auto frameInfo = GetOrOCreateBCEndStateInfo(predPc);
134     FrameStateInfo *predFrameInfo = liveOutResult_;
135     bool changed = frameInfo->MergeLiveout(predFrameInfo);
136     if (!changed) {
137         return changed;
138     }
139     for (size_t i = 0; i < numVregs_; i++) {
140         auto predValue = predFrameInfo->ValuesAt(i);
141         auto value = frameInfo->ValuesAt(i);
142         // if value not null, merge pred
143         if (value == Circuit::NullGate() && predValue != Circuit::NullGate()) {
144             frameInfo->SetValuesAt(i, predValue);
145             changed = true;
146         }
147     }
148     return changed;
149 }
150 
GetPhiComponent(BytecodeRegion * bb,BytecodeRegion * predBb,GateRef phi)151 GateRef FrameStateBuilder::GetPhiComponent(BytecodeRegion *bb, BytecodeRegion *predBb, GateRef phi)
152 {
153     ASSERT(gateAcc_.GetOpCode(phi) == OpCode::VALUE_SELECTOR);
154     if (bb->numOfLoopBacks != 0) {
155         ASSERT(bb->loopbackBlocks.size() != 0);
156         auto forwardValue = gateAcc_.GetValueIn(phi, 0); // 0: fowward
157         auto loopBackValue = gateAcc_.GetValueIn(phi, 1); // 1: back
158         size_t backIndex = 0;
159         size_t forwardIndex = 0;
160         for (size_t i = 0; i < bb->numOfStatePreds; ++i) {
161             auto predId = std::get<0>(bb->expandedPreds.at(i));
162             if (bb->loopbackBlocks.count(predId)) {
163                 if (predId == predBb->id) {
164                     return gateAcc_.GetValueIn(loopBackValue, backIndex);
165                 }
166                 backIndex++;
167             } else {
168                 if (predId == predBb->id) {
169                     return gateAcc_.GetValueIn(forwardValue, forwardIndex);
170                 }
171                 forwardIndex++;
172             }
173         }
174         return Circuit::NullGate();
175     }
176 
177     ASSERT(gateAcc_.GetNumValueIn(phi) == bb->numOfStatePreds);
178     for (size_t i = 0; i < bb->numOfStatePreds; ++i) {
179         auto predId = std::get<0>(bb->expandedPreds.at(i));
180         if (predId == predBb->id) {
181             return gateAcc_.GetValueIn(phi, i);
182         }
183     }
184     return Circuit::NullGate();
185 }
186 
MergeIntoPredBB(BytecodeRegion * bb,BytecodeRegion * predBb)187 bool FrameStateBuilder::MergeIntoPredBB(BytecodeRegion *bb, BytecodeRegion *predBb)
188 {
189     bool changed = MergeIntoPredBC(predBb->end);
190     if (!changed) {
191         return changed;
192     }
193     auto predLiveout = GetOrOCreateBCEndStateInfo(predBb->end);
194     // replace phi
195     if (bb->valueSelectorAccGate != Circuit::NullGate()) {
196         auto phi = bb->valueSelectorAccGate;
197         auto value = predLiveout->ValuesAt(accumulatorIndex_);
198         if (value == phi) {
199             auto target = GetPhiComponent(bb, predBb, phi);
200             ASSERT(target != Circuit::NullGate());
201             predLiveout->SetValuesAt(accumulatorIndex_, target);
202         }
203     }
204     for (auto &it : bb->vregToValSelectorGate) {
205         auto reg = it.first;
206         auto phi = it.second;
207         auto value = predLiveout->ValuesAt(reg);
208         if (value == phi) {
209             auto target = GetPhiComponent(bb, predBb, phi);
210             ASSERT(target != Circuit::NullGate());
211             predLiveout->SetValuesAt(reg, target);
212         }
213     }
214     return changed;
215 }
216 
ComputeLiveOut(size_t bbId)217 bool FrameStateBuilder::ComputeLiveOut(size_t bbId)
218 {
219     auto &bb = builder_->GetBasicBlockById(bbId);
220     bool changed = false;
221     ASSERT(!bb.isDead);
222     // iterator bc
223     auto &iterator = bb.GetBytecodeIterator();
224     iterator.GotoEnd();
225     ASSERT(bb.end == iterator.Index());
226     auto liveout = GetOrOCreateBCEndStateInfo(bb.end);
227     liveOutResult_->CopyFrom(liveout);
228     while (true) {
229         auto &bytecodeInfo = iterator.GetBytecodeInfo();
230         ComputeLiveOutBC(iterator.Index(), bytecodeInfo);
231         --iterator;
232         if (iterator.Done()) {
233             break;
234         }
235         auto prevPc = iterator.Index();
236         changed |= MergeIntoPredBC(prevPc);
237     }
238 
239     SaveBBBeginStateInfo(bbId);
240 
241     bool defPhi = bb.valueSelectorAccGate != Circuit::NullGate() ||
242         bb.vregToValSelectorGate.size() != 0;
243     // merge current into pred bb
244     for (auto bbPred : bb.preds) {
245         if (bbPred->isDead) {
246             continue;
247         }
248         if (defPhi) {
249             changed |= MergeIntoPredBB(&bb, bbPred);
250         } else {
251             changed |= MergeIntoPredBC(bbPred->end);
252         }
253     }
254     if (!bb.trys.empty()) {
255         // clear GET_EXCEPTION gate if this is a catch block
256         UpdateAccumulator(Circuit::NullGate());
257         for (auto bbPred : bb.trys) {
258             if (bbPred->isDead) {
259                 continue;
260             }
261             if (defPhi) {
262                 changed |= MergeIntoPredBB(&bb, bbPred);
263             } else {
264                 changed |= MergeIntoPredBC(bbPred->end);
265             }
266         }
267     }
268 
269     return changed;
270 }
271 
ComputeLiveState()272 void FrameStateBuilder::ComputeLiveState()
273 {
274     // recompute liveout
275     bool changed = true;
276     while (changed) {
277         changed = false;
278         for (size_t i = 0; i < postOrderList_.size(); i++) {
279             changed |= ComputeLiveOut(postOrderList_[i]);
280         }
281     }
282 }
283 
BuildFrameState()284 void FrameStateBuilder::BuildFrameState()
285 {
286     argAcc_.CollectArgs();
287     bcEndStateInfos_.resize(builder_->GetLastBcIndex() + 1, nullptr); // 1: +1 pcOffsets size
288     auto size = builder_->GetBasicBlockCount();
289     bbBeginStateInfos_.resize(size, nullptr);
290     liveOutResult_ = CreateEmptyStateInfo();
291     BuildPostOrderList(size);
292     ComputeLiveState();
293     BindStateSplit(size);
294 }
295 
ComputeLiveOutBC(uint32_t index,const BytecodeInfo & bytecodeInfo)296 void FrameStateBuilder::ComputeLiveOutBC(uint32_t index, const BytecodeInfo &bytecodeInfo)
297 {
298     if (bytecodeInfo.IsMov()) {
299         auto gate = Circuit::NullGate();
300         // variable kill
301         if (bytecodeInfo.AccOut()) {
302             gate = ValuesAtAccumulator();
303             UpdateAccumulator(Circuit::NullGate());
304         } else if (bytecodeInfo.vregOut.size() != 0) {
305             auto out = bytecodeInfo.vregOut[0];
306             gate = ValuesAt(out);
307             UpdateVirtualRegister(out, Circuit::NullGate());
308         }
309         // variable use
310         if (bytecodeInfo.AccIn()) {
311             UpdateAccumulator(gate);
312         } else if (bytecodeInfo.inputs.size() != 0) {
313             auto vreg = std::get<VirtualRegister>(bytecodeInfo.inputs.at(0)).GetId();
314             UpdateVirtualRegister(vreg, gate);
315         }
316         return;
317     }
318     if (!bytecodeInfo.IsGeneral() && !bytecodeInfo.IsReturn() && !bytecodeInfo.IsCondJump()) {
319         return;
320     }
321     GateRef gate = builder_->GetGateByBcIndex(index);
322     // variable kill
323     if (bytecodeInfo.AccOut()) {
324         UpdateAccumulator(Circuit::NullGate());
325     }
326     for (const auto &out: bytecodeInfo.vregOut) {
327         UpdateVirtualRegister(out, Circuit::NullGate());
328     }
329     if (bytecodeInfo.GetOpcode() == EcmaOpcode::RESUMEGENERATOR) {
330         UpdateVirtualRegistersOfResume(gate);
331     }
332 
333     // variable use
334     if (bytecodeInfo.AccIn()) {
335         auto id = bytecodeInfo.inputs.size();
336         GateRef def = gateAcc_.GetValueIn(gate, id);
337         UpdateAccumulator(def);
338     }
339     for (size_t i = 0; i < bytecodeInfo.inputs.size(); i++) {
340         auto in = bytecodeInfo.inputs[i];
341         if (std::holds_alternative<VirtualRegister>(in)) {
342             auto vreg = std::get<VirtualRegister>(in).GetId();
343             GateRef def = gateAcc_.GetValueIn(gate, i);
344             UpdateVirtualRegister(vreg, def);
345         }
346     }
347     if (bytecodeInfo.GetOpcode() == EcmaOpcode::SUSPENDGENERATOR_V8) {
348         UpdateVirtualRegistersOfSuspend(gate);
349     }
350 }
351 
BindStateSplit(size_t size)352 void FrameStateBuilder::BindStateSplit(size_t size)
353 {
354     for (size_t i = 0; i < size; i++) {
355         auto &bb = builder_->GetBasicBlockById(i);
356         if (bb.isDead) {
357             continue;
358         }
359         builder_->EnumerateBlock(bb, [&](const BytecodeInfo &bytecodeInfo) -> bool {
360             if (bytecodeInfo.Deopt()) {
361                 auto &iterator = bb.GetBytecodeIterator();
362                 auto index = iterator.Index();
363                 auto gate = builder_->GetGateByBcIndex(index);
364                 auto pcOffset = builder_->GetPcOffset(index);
365                 auto stateInfo = GetCurrentFrameInfo(bb, index);
366                 BindStateSplit(gate, pcOffset, stateInfo);
367             }
368             return true;
369         });
370     }
371 }
372 
GetCurrentFrameInfo(BytecodeRegion & bb,uint32_t bcId)373 FrameStateInfo *FrameStateBuilder::GetCurrentFrameInfo(BytecodeRegion &bb, uint32_t bcId)
374 {
375     if (bcId == bb.start) {
376         return GetBBBeginStateInfo(bb.id);
377     } else {
378         return GetOrOCreateBCEndStateInfo(bcId - 1); // 1: prev pc
379     }
380 }
381 
SaveBBBeginStateInfo(size_t bbId)382 void FrameStateBuilder::SaveBBBeginStateInfo(size_t bbId)
383 {
384     if (bbBeginStateInfos_[bbId] == nullptr) {
385         bbBeginStateInfos_[bbId] = CreateEmptyStateInfo();
386     }
387     bbBeginStateInfos_[bbId]->CopyFrom(liveOutResult_);
388 }
389 
UpdateVirtualRegistersOfSuspend(GateRef gate)390 void FrameStateBuilder::UpdateVirtualRegistersOfSuspend(GateRef gate)
391 {
392     auto saveRegsGate = gateAcc_.GetDep(gate);
393     size_t numOfRegs = gateAcc_.GetNumValueIn(saveRegsGate);
394     for (size_t i = 0; i < numOfRegs; i++) {
395         GateRef def = gateAcc_.GetValueIn(saveRegsGate, i);
396         UpdateVirtualRegister(i, def);
397     }
398 }
399 
UpdateVirtualRegistersOfResume(GateRef gate)400 void FrameStateBuilder::UpdateVirtualRegistersOfResume(GateRef gate)
401 {
402     auto restoreGate = gateAcc_.GetDep(gate);
403     while (gateAcc_.GetOpCode(restoreGate) == OpCode::RESTORE_REGISTER) {
404         auto vreg = static_cast<size_t>(gateAcc_.GetVirtualRegisterIndex(restoreGate));
405         UpdateVirtualRegister(vreg, Circuit::NullGate());
406         restoreGate = gateAcc_.GetDep(restoreGate);
407     }
408 }
409 }