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 }