• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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/bytecode_circuit_builder.h"
17 
18 #include "ecmascript/base/number_helper.h"
19 #include "ecmascript/compiler/gate_accessor.h"
20 #include "ecmascript/ts_types/ts_manager.h"
21 #include "libpandafile/bytecode_instruction-inl.h"
22 
23 namespace panda::ecmascript::kungfu {
BytecodeToCircuit()24 void BytecodeCircuitBuilder::BytecodeToCircuit()
25 {
26     ExceptionInfo exceptionInfo = {};
27 
28     // collect try catch block info
29     CollectTryCatchBlockInfo(exceptionInfo);
30     hasTryCatch_ = exceptionInfo.size() != 0;
31     BuildRegionInfo();
32     // Building the basic block diagram of bytecode
33     BuildRegions(exceptionInfo);
34 }
35 
BuildRegionInfo()36 void BytecodeCircuitBuilder::BuildRegionInfo()
37 {
38     uint32_t size = pcOffsets_.size();
39     uint32_t end = size - 1;  // 1: end
40     BytecodeIterator iterator(this, 0, end);
41 
42     infoData_.resize(size);
43     byteCodeToJSGates_.resize(size, std::vector<GateRef>(0));
44     regionsInfo_.InsertHead(0); // 0: start pc
45     iterator.GotoStart();
46     while (!iterator.Done()) {
47         auto index = iterator.Index();
48         auto &info = infoData_[index];
49         auto pc = pcOffsets_[index];
50         info.metaData_ = bytecodes_->GetBytecodeMetaData(pc);
51         ASSERT(!info.metaData_.IsInvalid());
52         BytecodeInfo::InitBytecodeInfo(this, info, pc);
53         CollectRegionInfo(index);
54         ++iterator;
55     }
56 }
57 
CollectRegionInfo(uint32_t bcIndex)58 void BytecodeCircuitBuilder::CollectRegionInfo(uint32_t bcIndex)
59 {
60     auto pc = pcOffsets_[bcIndex];
61     auto &info = infoData_[bcIndex];
62     int32_t offset = 0;
63     if (info.IsJump()) {
64         switch (info.GetOpcode()) {
65             case EcmaOpcode::JEQZ_IMM8:
66             case EcmaOpcode::JNEZ_IMM8:
67             case EcmaOpcode::JMP_IMM8:
68                 offset = static_cast<int8_t>(READ_INST_8_0());
69                 break;
70             case EcmaOpcode::JNEZ_IMM16:
71             case EcmaOpcode::JEQZ_IMM16:
72             case EcmaOpcode::JMP_IMM16:
73                 offset = static_cast<int16_t>(READ_INST_16_0());
74                 break;
75             case EcmaOpcode::JMP_IMM32:
76             case EcmaOpcode::JNEZ_IMM32:
77             case EcmaOpcode::JEQZ_IMM32:
78                 offset = static_cast<int32_t>(READ_INST_32_0());
79                 break;
80             default:
81                 LOG_ECMA(FATAL) << "this branch is unreachable";
82                 UNREACHABLE();
83                 break;
84         }
85         auto nextIndex = bcIndex + 1; // 1: next pc
86         auto targetIndex = FindBcIndexByPc(pc + offset);
87         // condition branch current basic block end
88         if (info.IsCondJump()) {
89             regionsInfo_.InsertSplit(nextIndex);
90             regionsInfo_.InsertJump(targetIndex, bcIndex, false);
91         } else {
92             if (bcIndex != GetLastBcIndex()) {
93                 regionsInfo_.InsertHead(nextIndex);
94             }
95             regionsInfo_.InsertJump(targetIndex, bcIndex, true);
96         }
97     } else if (info.IsReturn() || info.IsThrow()) {
98         if (bcIndex != GetLastBcIndex()) {
99             auto nextIndex = bcIndex + 1; // 1: next pc
100             regionsInfo_.InsertHead(nextIndex);
101         }
102     }
103 }
104 
CollectTryCatchBlockInfo(ExceptionInfo & byteCodeException)105 void BytecodeCircuitBuilder::CollectTryCatchBlockInfo(ExceptionInfo &byteCodeException)
106 {
107     auto pf = file_->GetPandaFile();
108     panda_file::MethodDataAccessor mda(*pf, method_->GetMethodId());
109     panda_file::CodeDataAccessor cda(*pf, mda.GetCodeId().value());
110 
111     cda.EnumerateTryBlocks([this, &byteCodeException](
112         panda_file::CodeDataAccessor::TryBlock &tryBlock) {
113         auto tryStartOffset = tryBlock.GetStartPc();
114         auto tryEndOffset = tryBlock.GetStartPc() + tryBlock.GetLength();
115 
116         auto tryStartPc = const_cast<uint8_t *>(method_->GetBytecodeArray() + tryStartOffset);
117         auto tryEndPc = const_cast<uint8_t *>(method_->GetBytecodeArray() + tryEndOffset);
118         // skip try blocks with same pc in start and end label
119         if (tryStartPc == tryEndPc) {
120             return true;
121         }
122 
123         auto tryStartBcIndex = FindBcIndexByPc(tryStartPc);
124         regionsInfo_.InsertSplit(tryStartBcIndex);
125         if (tryEndPc <= GetLastPC()) {
126             auto tryEndBcIndex = FindBcIndexByPc(tryEndPc);
127             regionsInfo_.InsertSplit(tryEndBcIndex);
128         }
129         byteCodeException.emplace_back(ExceptionItem { tryStartPc, tryEndPc, {} });
130         tryBlock.EnumerateCatchBlocks([&](panda_file::CodeDataAccessor::CatchBlock &catchBlock) {
131             auto pcOffset = catchBlock.GetHandlerPc();
132             auto catchBlockPc = const_cast<uint8_t *>(method_->GetBytecodeArray() + pcOffset);
133             auto catchBlockBcIndex = FindBcIndexByPc(catchBlockPc);
134             regionsInfo_.InsertHead(catchBlockBcIndex);
135             // try block associate catch block
136             byteCodeException.back().catches.emplace_back(catchBlockPc);
137             return true;
138         });
139         return true;
140     });
141 }
142 
BuildEntryBlock()143 void BytecodeCircuitBuilder::BuildEntryBlock()
144 {
145     BytecodeRegion &entryBlock = RegionAt(0);
146     BytecodeRegion &nextBlock = RegionAt(1);
147     entryBlock.succs.emplace_back(&nextBlock);
148     nextBlock.preds.emplace_back(&entryBlock);
149     entryBlock.bytecodeIterator_.Reset(this, 0, BytecodeIterator::INVALID_INDEX);
150 }
151 
BuildRegions(const ExceptionInfo & byteCodeException)152 void BytecodeCircuitBuilder::BuildRegions(const ExceptionInfo &byteCodeException)
153 {
154     auto &items = regionsInfo_.GetBlockItems();
155     auto blockSize = items.size();
156 
157     // 1 : entry block. if the loop head is in the first bb block, the variables used in the head cannot correctly
158     // generate Phi nodes through the dominator-tree algorithm, resulting in an infinite loop. Therefore, an empty
159     // BB block is generated as an entry block
160     graph_.resize(blockSize + 1, nullptr);
161     for (size_t i = 0; i < graph_.size(); i++) {
162         graph_[i] = circuit_->chunk()->New<BytecodeRegion>(circuit_->chunk());
163     }
164 
165     // build entry block
166     BuildEntryBlock();
167 
168     // build basic block
169     size_t blockId = 1;
170     for (const auto &item : items) {
171         auto &curBlock = GetBasicBlockById(blockId);
172         curBlock.id = blockId;
173         curBlock.start = item.GetStartBcIndex();
174         if (blockId != 1) {
175             auto &prevBlock = RegionAt(blockId - 1);
176             prevBlock.end = curBlock.start - 1;
177             prevBlock.bytecodeIterator_.Reset(this, prevBlock.start, prevBlock.end);
178             // fall through
179             if (!item.IsHeadBlock()) {
180                 curBlock.preds.emplace_back(&prevBlock);
181                 prevBlock.succs.emplace_back(&curBlock);
182             }
183         }
184         blockId++;
185     }
186     auto &lastBlock = RegionAt(blockId - 1); // 1: last block
187     lastBlock.end = GetLastBcIndex();
188     lastBlock.bytecodeIterator_.Reset(this, lastBlock.start, lastBlock.end);
189 
190     auto &splitItems = regionsInfo_.GetSplitItems();
191     for (const auto &item : splitItems) {
192         auto curIndex = regionsInfo_.FindBBIndexByBcIndex(item.startBcIndex);
193         auto &curBlock = GetBasicBlockById(curIndex);
194         auto predIndex = regionsInfo_.FindBBIndexByBcIndex(item.predBcIndex);
195         auto &predBlock = GetBasicBlockById(predIndex);
196         curBlock.preds.emplace_back(&predBlock);
197         predBlock.succs.emplace_back(&curBlock);
198     }
199 
200     if (byteCodeException.size() != 0) {
201         BuildCatchBlocks(byteCodeException);
202     }
203     UpdateCFG();
204     if (HasTryCatch()) {
205         CollectTryPredsInfo();
206     }
207     RemoveUnreachableRegion();
208     if (IsLogEnabled()) {
209         PrintGraph("Update CFG");
210     }
211     BuildCircuit();
212 }
213 
BuildCatchBlocks(const ExceptionInfo & byteCodeException)214 void BytecodeCircuitBuilder::BuildCatchBlocks(const ExceptionInfo &byteCodeException)
215 {
216     // try catch block associate
217     for (size_t i = 0; i < graph_.size(); i++) {
218         auto &bb = RegionAt(i);
219         auto startIndex = bb.start;
220         const auto pc = pcOffsets_[startIndex];
221         for (auto it = byteCodeException.cbegin(); it != byteCodeException.cend(); it++) {
222             if (pc < it->startPc || pc >= it->endPc) {
223                 continue;
224             }
225             // try block interval
226             const auto &catches = it->catches; // catches start pc
227             for (size_t j = i + 1; j < graph_.size(); j++) {
228                 auto &catchBB = RegionAt(j);
229                 const auto catchStart = pcOffsets_[catchBB.start];
230                 if (std::find(catches.cbegin(), catches.cend(), catchStart) != catches.cend()) {
231                     bb.catches.insert(bb.catches.cbegin(), &catchBB);
232                     bb.succs.emplace_back(&catchBB);
233                     catchBB.preds.emplace_back(&bb);
234                 }
235             }
236         }
237 
238         // When there are multiple catch blocks in the current block, the set of catch blocks
239         // needs to be sorted to satisfy the order of execution of catch blocks.
240         bb.SortCatches();
241     }
242 }
243 
CollectTryPredsInfo()244 void BytecodeCircuitBuilder::CollectTryPredsInfo()
245 {
246     for (size_t i = 0; i < graph_.size(); i++) {
247         auto &bb = RegionAt(i);
248         if (bb.catches.empty()) {
249             continue;
250         } else if (bb.catches.size() > 1) { // 1: cache size
251             for (auto it = bb.catches.begin() + 1; it != bb.catches.end();) { // 1: invalid catch bb
252                 bb.EraseThisBlock((*it)->trys);
253                 it = bb.catches.erase(it);
254             }
255         }
256 
257         EnumerateBlock(bb, [&bb](const BytecodeInfo &bytecodeInfo) -> bool {
258             if (bytecodeInfo.IsGeneral()) {
259                 // if block which can throw exception has serval catchs block,
260                 // only the innermost catch block is useful
261                 ASSERT(bb.catches.size() == 1); // 1: cache size
262                 if (!bytecodeInfo.NoThrow()) {
263                     bb.catches.at(0)->numOfStatePreds++;
264                 }
265             }
266             return true;
267         });
268     }
269 }
270 
RemoveUnusedPredsInfo(BytecodeRegion & bb)271 void BytecodeCircuitBuilder::RemoveUnusedPredsInfo(BytecodeRegion& bb)
272 {
273     EnumerateBlock(bb, [&bb](const BytecodeInfo &bytecodeInfo) -> bool {
274         if (bytecodeInfo.IsGeneral()) {
275             ASSERT(bb.catches.size() == 1); // 1: cache size
276             if (!bytecodeInfo.NoThrow()) {
277                 bb.catches.at(0)->numOfStatePreds--;
278             }
279         }
280         return true;
281     });
282 }
283 
ClearUnreachableRegion(ChunkVector<BytecodeRegion * > & pendingList)284 void BytecodeCircuitBuilder::ClearUnreachableRegion(ChunkVector<BytecodeRegion*>& pendingList)
285 {
286     auto bb = pendingList.back();
287     pendingList.pop_back();
288     for (auto it = bb->preds.begin(); it != bb->preds.end(); it++) {
289         if ((*it)->numOfStatePreds != 0) {
290             bb->EraseThisBlock((*it)->succs);
291         }
292     }
293     for (auto it = bb->succs.begin(); it != bb->succs.end(); it++) {
294         auto bbNext = *it;
295         if (bbNext->numOfStatePreds != 0) {
296             bb->EraseThisBlock(bbNext->preds);
297             bbNext->numOfStatePreds--;
298             if (bbNext->numOfStatePreds == 0) {
299                 pendingList.emplace_back(bbNext);
300             }
301         }
302     }
303     for (auto it = bb->trys.begin(); it != bb->trys.end(); it++) {
304         if ((*it)->numOfStatePreds != 0) {
305             bb->EraseThisBlock((*it)->catches);
306         }
307     }
308     for (auto it = bb->catches.begin(); it != bb->catches.end(); it++) {
309         auto bbNext = *it;
310         if (bbNext->numOfStatePreds != 0) {
311             RemoveUnusedPredsInfo(*bb);
312             bb->EraseThisBlock(bbNext->trys);
313             if (bbNext->numOfStatePreds == 0) {
314                 pendingList.emplace_back(bbNext);
315             }
316         }
317     }
318     bb->preds.clear();
319     bb->succs.clear();
320     bb->trys.clear();
321     bb->catches.clear();
322     numOfLiveBB_--;
323 }
324 
RemoveUnreachableRegion()325 void BytecodeCircuitBuilder::RemoveUnreachableRegion()
326 {
327     numOfLiveBB_ = graph_.size();
328     ChunkVector<BytecodeRegion*> pendingList(circuit_->chunk());
329     for (size_t i = 1; i < graph_.size(); i++) { // 1: skip entry bb
330         auto &bb = RegionAt(i);
331         if (bb.numOfStatePreds == 0) {
332             pendingList.emplace_back(&bb);
333         }
334     }
335     while (!pendingList.empty()) {
336         ClearUnreachableRegion(pendingList);
337     }
338 }
339 
340 // Update CFG's predecessor, successor and try catch associations
UpdateCFG()341 void BytecodeCircuitBuilder::UpdateCFG()
342 {
343     for (size_t i = 0; i < graph_.size(); i++) {
344         auto &bb = RegionAt(i);
345         bb.preds.clear();
346         bb.trys.clear();
347         ChunkVector<BytecodeRegion *> newSuccs(circuit_->chunk());
348         for (const auto &succ: bb.succs) {
349             if (std::count(bb.catches.cbegin(), bb.catches.cend(), succ)) {
350                 continue;
351             }
352             newSuccs.emplace_back(succ);
353         }
354         bb.succs.clear();
355         bb.succs.insert(bb.succs.end(), newSuccs.begin(), newSuccs.end());
356     }
357     for (size_t i = 0; i < graph_.size(); i++) {
358         auto &bb = RegionAt(i);
359         for (auto &succ: bb.succs) {
360             succ->preds.emplace_back(&bb);
361             succ->numOfStatePreds++;
362         }
363         for (auto &catchBlock: bb.catches) {
364             catchBlock->trys.emplace_back(&bb);
365         }
366     }
367 }
368 
369 // build circuit
BuildCircuitArgs()370 void BytecodeCircuitBuilder::BuildCircuitArgs()
371 {
372     argAcc_.NewCommonArg(CommonArgIdx::GLUE, MachineType::I64, GateType::NJSValue());
373     if (!method_->IsFastCall()) {
374         argAcc_.NewCommonArg(CommonArgIdx::ACTUAL_ARGC, MachineType::I64, GateType::NJSValue());
375         auto funcIdx = static_cast<size_t>(CommonArgIdx::FUNC);
376         const size_t actualNumArgs = argAcc_.GetActualNumArgs();
377         // new actual argument gates
378         for (size_t argIdx = funcIdx; argIdx < actualNumArgs; argIdx++) {
379             argAcc_.NewArg(argIdx);
380         }
381     } else {
382         auto funcIdx = static_cast<size_t>(FastCallArgIdx::FUNC);
383         size_t actualNumArgs = static_cast<size_t>(FastCallArgIdx::NUM_OF_ARGS) + method_->GetNumArgsWithCallField();
384         for (size_t argIdx = funcIdx; argIdx < actualNumArgs; argIdx++) {
385             argAcc_.NewArg(argIdx);
386         }
387     }
388     argAcc_.CollectArgs();
389     if (HasTypes()) {
390         argAcc_.FillArgsGateType(&typeRecorder_);
391     }
392 
393     BuildFrameArgs();
394 }
395 
BuildFrameArgs()396 void BytecodeCircuitBuilder::BuildFrameArgs()
397 {
398     UInt32PairAccessor accessor(0, 0);
399     auto metaData = circuit_->FrameArgs(accessor.ToValue());
400     size_t numArgs = metaData->GetNumIns();
401     std::vector<GateRef> args(numArgs, Circuit::NullGate());
402     size_t idx = 0;
403     args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::FUNC);
404     args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::NEW_TARGET);
405     args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::THIS_OBJECT);
406     args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::ACTUAL_ARGC);
407     args[idx++] = GetPreFrameArgs();
408     GateRef frameArgs = circuit_->NewGate(metaData, args);
409     argAcc_.SetFrameArgs(frameArgs);
410 }
411 
CreateGateInList(const BytecodeInfo & info,const GateMetaData * meta)412 std::vector<GateRef> BytecodeCircuitBuilder::CreateGateInList(
413     const BytecodeInfo &info, const GateMetaData *meta)
414 {
415     auto numValues = meta->GetNumIns();
416     const size_t length = meta->GetInValueStarts();
417     std::vector<GateRef> inList(numValues, Circuit::NullGate());
418     auto inputSize = info.inputs.size();
419     for (size_t i = 0; i < inputSize; i++) {
420         auto &input = info.inputs[i];
421         if (std::holds_alternative<ConstDataId>(input)) {
422             inList[i + length] = circuit_->GetConstantGate(MachineType::I64,
423                                                            std::get<ConstDataId>(input).GetId(),
424                                                            GateType::NJSValue());
425         } else if (std::holds_alternative<Immediate>(input)) {
426             inList[i + length] = circuit_->GetConstantGate(MachineType::I64,
427                                                            std::get<Immediate>(input).GetValue(),
428                                                            GateType::NJSValue());
429         } else if (std::holds_alternative<ICSlotId>(input)) {
430             inList[i + length] = circuit_->GetConstantGate(MachineType::I16,
431                                                            std::get<ICSlotId>(input).GetId(),
432                                                            GateType::NJSValue());
433         } else {
434             ASSERT(std::holds_alternative<VirtualRegister>(input));
435             continue;
436         }
437     }
438     if (info.AccIn()) {
439         inputSize++;
440     }
441     if (meta->HasFrameState()) {
442         inList[inputSize + length] = GetFrameArgs();
443     }
444     return inList;
445 }
446 
NewConst(const BytecodeInfo & info)447 GateRef BytecodeCircuitBuilder::NewConst(const BytecodeInfo &info)
448 {
449     auto opcode = info.GetOpcode();
450     GateRef gate = 0;
451     switch (opcode) {
452         case EcmaOpcode::LDNAN:
453             gate = circuit_->GetConstantGate(MachineType::I64,
454                                              base::NumberHelper::GetNaN(),
455                                              GateType::NumberType());
456             break;
457         case EcmaOpcode::LDINFINITY:
458             gate = circuit_->GetConstantGate(MachineType::I64,
459                                              base::NumberHelper::GetPositiveInfinity(),
460                                              GateType::NumberType());
461             break;
462         case EcmaOpcode::LDUNDEFINED:
463             gate = circuit_->GetConstantGate(MachineType::I64,
464                                              JSTaggedValue::VALUE_UNDEFINED,
465                                              GateType::UndefinedType());
466             break;
467         case EcmaOpcode::LDNULL:
468             gate = circuit_->GetConstantGate(MachineType::I64,
469                                              JSTaggedValue::VALUE_NULL,
470                                              GateType::NullType());
471             break;
472         case EcmaOpcode::LDTRUE:
473             gate = circuit_->GetConstantGate(MachineType::I64,
474                                              JSTaggedValue::VALUE_TRUE,
475                                              GateType::BooleanType());
476             break;
477         case EcmaOpcode::LDFALSE:
478             gate = circuit_->GetConstantGate(MachineType::I64,
479                                              JSTaggedValue::VALUE_FALSE,
480                                              GateType::BooleanType());
481             break;
482         case EcmaOpcode::LDHOLE:
483             gate = circuit_->GetConstantGate(MachineType::I64,
484                                              JSTaggedValue::VALUE_HOLE,
485                                              GateType::TaggedValue());
486             break;
487         case EcmaOpcode::LDAI_IMM32:
488             gate = circuit_->GetConstantGate(MachineType::I64,
489                                              std::get<Immediate>(info.inputs[0]).ToJSTaggedValueInt(),
490                                              GateType::IntType());
491             break;
492         case EcmaOpcode::FLDAI_IMM64:
493             gate = circuit_->GetConstantGate(MachineType::I64,
494                                              std::get<Immediate>(info.inputs.at(0)).ToJSTaggedValueDouble(),
495                                              GateType::DoubleType());
496             break;
497         case EcmaOpcode::LDFUNCTION:
498             gate = argAcc_.GetCommonArgGate(CommonArgIdx::FUNC);
499             break;
500         case EcmaOpcode::LDNEWTARGET:
501             gate = argAcc_.GetCommonArgGate(CommonArgIdx::NEW_TARGET);
502             break;
503         case EcmaOpcode::LDTHIS:
504             gate = argAcc_.GetCommonArgGate(CommonArgIdx::THIS_OBJECT);
505             break;
506         default:
507             LOG_ECMA(FATAL) << "this branch is unreachable";
508             UNREACHABLE();
509     }
510     return gate;
511 }
512 
MergeThrowGate(BytecodeRegion & bb,uint32_t bcIndex)513 void BytecodeCircuitBuilder::MergeThrowGate(BytecodeRegion &bb, uint32_t bcIndex)
514 {
515     auto state = frameStateBuilder_.GetCurrentState();
516     auto depend = frameStateBuilder_.GetCurrentDepend();
517     if (!bb.catches.empty()) {
518         auto ifSuccess = circuit_->NewGate(circuit_->IfSuccess(), {state});
519         auto ifException = circuit_->NewGate(circuit_->IfException(), {state, depend});
520         frameStateBuilder_.UpdateStateDepend(ifException, ifException);
521         ASSERT(bb.catches.size() == 1); // 1: one catch
522         auto bbNext = bb.catches.at(0);
523         frameStateBuilder_.MergeIntoSuccessor(bb, *bbNext);
524         bbNext->expandedPreds.push_back({bb.id, bcIndex, true});
525         state = ifSuccess;
526     }
527     auto constant = circuit_->GetConstantGate(MachineType::I64,
528                                               JSTaggedValue::VALUE_EXCEPTION,
529                                               GateType::TaggedValue());
530     circuit_->NewGate(circuit_->Return(),
531         { state, depend, constant, circuit_->GetReturnRoot() });
532 }
533 
MergeExceptionGete(BytecodeRegion & bb,const BytecodeInfo & bytecodeInfo,uint32_t bcIndex)534 void BytecodeCircuitBuilder::MergeExceptionGete(BytecodeRegion &bb,
535     const BytecodeInfo& bytecodeInfo, uint32_t bcIndex)
536 {
537     auto state = frameStateBuilder_.GetCurrentState();
538     auto depend = frameStateBuilder_.GetCurrentDepend();
539     auto ifSuccess = circuit_->NewGate(circuit_->IfSuccess(), {state});
540     ASSERT(bb.catches.size() == 1); // 1: one catch
541     auto bbNext = bb.catches.at(0);
542     auto ifException = circuit_->NewGate(circuit_->IfException(), {state, depend});
543     frameStateBuilder_.UpdateStateDepend(ifException, ifException);
544     frameStateBuilder_.MergeIntoSuccessor(bb, *bbNext);
545     if (bytecodeInfo.GetOpcode() == EcmaOpcode::CREATEASYNCGENERATOROBJ_V8) {
546         bbNext->expandedPreds.push_back({bb.id, bcIndex + 1, true}); // 1: next pc
547     } else {
548         bbNext->expandedPreds.push_back({bb.id, bcIndex, true});
549     }
550     frameStateBuilder_.UpdateStateDepend(ifSuccess, depend);
551 }
552 
NewJSGate(BytecodeRegion & bb)553 void BytecodeCircuitBuilder::NewJSGate(BytecodeRegion &bb)
554 {
555     auto &iterator = bb.GetBytecodeIterator();
556     const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
557     GateRef state = frameStateBuilder_.GetCurrentState();
558     GateRef depend = frameStateBuilder_.GetCurrentDepend();
559     size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
560     GateRef gate = 0;
561     bool writable = !bytecodeInfo.NoSideEffects();
562     bool hasFrameState = bytecodeInfo.HasFrameState();
563     size_t pcOffset = GetPcOffset(iterator.Index());
564     auto methodOffset = method_->GetMethodId().GetOffset();
565     auto meta = circuit_->JSBytecode(
566         numValueInputs, methodOffset, bytecodeInfo.GetOpcode(), pcOffset, iterator.Index(), writable, hasFrameState);
567     std::vector<GateRef> inList = CreateGateInList(bytecodeInfo, meta);
568     if (bytecodeInfo.IsDef()) {
569         gate = circuit_->NewGate(meta, MachineType::I64, inList.size(),
570                                  inList.data(), GateType::AnyType());
571     } else {
572         gate = circuit_->NewGate(meta, MachineType::NOVALUE, inList.size(),
573                                  inList.data(), GateType::Empty());
574     }
575     byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
576     jsGatesToByteCode_[gate] = iterator.Index();
577     gateAcc_.NewIn(gate, 0, state);
578     gateAcc_.NewIn(gate, 1, depend);
579     frameStateBuilder_.UpdateStateDepend(gate, gate);
580     frameStateBuilder_.UpdateFrameValues(bytecodeInfo, iterator.Index(), gate);
581     if (bytecodeInfo.IsThrow()) {
582         MergeThrowGate(bb, iterator.Index());
583         return;
584     }
585 
586     if (!bb.catches.empty() && !bytecodeInfo.NoThrow()) {
587         MergeExceptionGete(bb, bytecodeInfo, iterator.Index());
588     }
589     if (bytecodeInfo.IsGeneratorRelative()) {
590         suspendAndResumeGates_.emplace_back(gate);
591     }
592 }
593 
NewJump(BytecodeRegion & bb)594 void BytecodeCircuitBuilder::NewJump(BytecodeRegion &bb)
595 {
596     auto &iterator = bb.GetBytecodeIterator();
597     const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
598     GateRef state = frameStateBuilder_.GetCurrentState();
599     GateRef depend = frameStateBuilder_.GetCurrentDepend();
600     size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
601     if (bytecodeInfo.IsCondJump() && bb.succs.size() == 2) { // 2: two succ
602         size_t pcOffset = GetPcOffset(iterator.Index());
603         auto methodOffset = method_->GetMethodId().GetOffset();
604         auto meta = circuit_->JSBytecode(
605             numValueInputs, methodOffset, bytecodeInfo.GetOpcode(), pcOffset, iterator.Index(), false, false);
606         auto numValues = meta->GetNumIns();
607         GateRef gate = circuit_->NewGate(meta, std::vector<GateRef>(numValues, Circuit::NullGate()));
608         gateAcc_.NewIn(gate, 0, state);
609         gateAcc_.NewIn(gate, 1, depend);
610         frameStateBuilder_.UpdateStateDepend(gate, gate);
611         frameStateBuilder_.UpdateFrameValues(bytecodeInfo, iterator.Index(), gate);
612 
613         auto ifTrue = circuit_->NewGate(circuit_->IfTrue(), {gate});
614         auto trueRelay = circuit_->NewGate(circuit_->DependRelay(), {ifTrue, gate});
615         auto ifFalse = circuit_->NewGate(circuit_->IfFalse(), {gate});
616         auto falseRelay = circuit_->NewGate(circuit_->DependRelay(), {ifFalse, gate});
617         for (auto &bbNext: bb.succs) {
618             if (iterator.Index() + 1 == bbNext->start) {
619                 frameStateBuilder_.UpdateStateDepend(ifFalse, falseRelay);
620                 frameStateBuilder_.MergeIntoSuccessor(bb, *bbNext);
621                 bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
622             } else {
623                 frameStateBuilder_.UpdateStateDepend(ifTrue, trueRelay);
624                 frameStateBuilder_.MergeIntoSuccessor(bb, *bbNext);
625                 bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
626             }
627         }
628         byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
629         jsGatesToByteCode_[gate] = iterator.Index();
630     } else {
631         ASSERT(bb.succs.size() == 1);
632         auto &bbNext = bb.succs.at(0);
633         frameStateBuilder_.MergeIntoSuccessor(bb, *bbNext);
634         bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
635     }
636 }
637 
NewReturn(BytecodeRegion & bb)638 GateRef BytecodeCircuitBuilder::NewReturn(BytecodeRegion &bb)
639 {
640     ASSERT(bb.succs.empty());
641     auto &iterator = bb.GetBytecodeIterator();
642     const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
643     GateRef state = frameStateBuilder_.GetCurrentState();
644     GateRef depend = frameStateBuilder_.GetCurrentDepend();
645     GateRef gate = Circuit::NullGate();
646     if (bytecodeInfo.GetOpcode() == EcmaOpcode::RETURN) {
647         // handle return.dyn bytecode
648         gate = circuit_->NewGate(circuit_->Return(),
649             { state, depend, Circuit::NullGate(), circuit_->GetReturnRoot() });
650         byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
651         jsGatesToByteCode_[gate] = iterator.Index();
652     } else if (bytecodeInfo.GetOpcode() == EcmaOpcode::RETURNUNDEFINED) {
653         // handle returnundefined bytecode
654         auto constant = circuit_->GetConstantGate(MachineType::I64,
655                                                   JSTaggedValue::VALUE_UNDEFINED,
656                                                   GateType::TaggedValue());
657         gate = circuit_->NewGate(circuit_->Return(),
658             { state, depend, constant, circuit_->GetReturnRoot() });
659         byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
660         jsGatesToByteCode_[gate] = iterator.Index();
661     }
662     return gate;
663 }
664 
NewByteCode(BytecodeRegion & bb)665 void BytecodeCircuitBuilder::NewByteCode(BytecodeRegion &bb)
666 {
667     auto &iterator = bb.GetBytecodeIterator();
668     const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
669     FrameLiveOut* liveout;
670     auto bcId = iterator.Index();
671     if (iterator.IsInRange(bcId - 1)) {
672         liveout = frameStateBuilder_.GetOrOCreateBCEndLiveOut(bcId - 1);
673     } else {
674         liveout = frameStateBuilder_.GetOrOCreateBBLiveOut(bb.id);
675     }
676     frameStateBuilder_.AdvanceToNextBc(bytecodeInfo, liveout, bcId);
677     GateRef gate = Circuit::NullGate();
678     if (bytecodeInfo.IsSetConstant()) {
679         // handle bytecode command to get constants
680         gate = NewConst(bytecodeInfo);
681         byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
682         jsGatesToByteCode_[gate] = iterator.Index();
683     } else if (bytecodeInfo.IsGeneral()) {
684         // handle general ecma.* bytecodes
685         NewJSGate(bb);
686     } else if (bytecodeInfo.IsJump()) {
687         // handle conditional jump and unconditional jump bytecodes
688         NewJump(bb);
689     } else if (bytecodeInfo.IsReturn()) {
690         // handle return.dyn and returnundefined bytecodes
691         gate = NewReturn(bb);
692     } else if (bytecodeInfo.IsMov()) {
693         frameStateBuilder_.UpdateMoveValues(bytecodeInfo, iterator.Index());
694     } else if (!bytecodeInfo.IsDiscarded()) {
695         LOG_ECMA(FATAL) << "this branch is unreachable";
696         UNREACHABLE();
697     }
698     if (gate != Circuit::NullGate()) {
699         frameStateBuilder_.UpdateFrameValues(bytecodeInfo, iterator.Index(), gate);
700     }
701 }
702 
BuildSubCircuit()703 void BytecodeCircuitBuilder::BuildSubCircuit()
704 {
705     auto &entryBlock = RegionAt(0);
706     frameStateBuilder_.InitEntryBB(entryBlock);
707     auto& rpoList = frameStateBuilder_.GetRpoList();
708     for (auto &bbId: rpoList) {
709         auto &bb = RegionAt(bbId);
710         frameStateBuilder_.AdvanceToNextBB(bb);
711         if (IsEntryBlock(bb.id)) {
712             if (NeedCheckSafePointAndStackOver()) {
713                 GateRef state = frameStateBuilder_.GetCurrentState();
714                 GateRef depend = frameStateBuilder_.GetCurrentDepend();
715                 auto stackCheck = circuit_->NewGate(circuit_->CheckSafePointAndStackOver(), {state, depend});
716                 bb.dependCache = stackCheck;
717                 frameStateBuilder_.UpdateStateDepend(stackCheck, stackCheck);
718             }
719             auto &bbNext = RegionAt(bb.id + 1);
720             frameStateBuilder_.MergeIntoSuccessor(bb, bbNext);
721             bbNext.expandedPreds.push_back({bb.id, bb.end, false});
722             continue;
723         }
724         if (!bb.trys.empty()) {
725             GateRef state = frameStateBuilder_.GetCurrentState();
726             GateRef depend = frameStateBuilder_.GetCurrentDepend();
727             auto getException = circuit_->NewGate(circuit_->GetException(),
728                 MachineType::I64, {state, depend}, GateType::AnyType());
729             frameStateBuilder_.UpdateAccumulator(getException);
730             frameStateBuilder_.UpdateStateDepend(state, getException);
731         }
732         EnumerateBlock(bb, [this, &bb]
733             (const BytecodeInfo &bytecodeInfo) -> bool {
734             NewByteCode(bb);
735             if (bytecodeInfo.IsJump() || bytecodeInfo.IsThrow()) {
736                 return false;
737             }
738             return true;
739         });
740         bool needFallThrough = true;
741         if (!bb.IsEmptryBlock()) {
742             const BytecodeInfo& bytecodeInfo = GetBytecodeInfo(bb.end);
743             needFallThrough = bytecodeInfo.needFallThrough();
744         }
745         // fallThrough or empty merge bb
746         if (needFallThrough) {
747             ASSERT(bb.succs.size() == 1); // 1: fall through
748             auto &bbNext = RegionAt(bb.succs[0]->id);
749             frameStateBuilder_.MergeIntoSuccessor(bb, bbNext);
750             bbNext.expandedPreds.push_back({bb.id, bb.end, false});
751         }
752     }
753 }
754 
BuildCircuit()755 void BytecodeCircuitBuilder::BuildCircuit()
756 {
757     // create arg gates array
758     BuildCircuitArgs();
759     frameStateBuilder_.DoBytecodeAnalysis();
760     // build states sub-circuit of each block
761     BuildSubCircuit();
762     if (IsLogEnabled()) {
763         PrintGraph("Bytecode2Gate");
764         LOG_COMPILER(INFO) << "\033[34m" << "============= "
765                            << "After bytecode2circuit lowering ["
766                            << methodName_ << "]"
767                            << " =============" << "\033[0m";
768         circuit_->PrintAllGatesWithBytecode();
769         LOG_COMPILER(INFO) << "\033[34m" << "=========================== End ===========================" << "\033[0m";
770     }
771 }
772 
PrintGraph(const char * title)773 void BytecodeCircuitBuilder::PrintGraph(const char* title)
774 {
775     LOG_COMPILER(INFO) << "======================== " << title << " ========================";
776     for (size_t i = 0; i < graph_.size(); i++) {
777         BytecodeRegion& bb = RegionAt(i);
778         if (!IsEntryBlock(bb.id) && bb.numOfStatePreds == 0) {
779             LOG_COMPILER(INFO) << "B" << bb.id << ":                               ;preds= invalid BB";
780             LOG_COMPILER(INFO) << "\tBytecodePC: [" << std::to_string(bb.start) << ", "
781                                << std::to_string(bb.end) << ")";
782             continue;
783         }
784         std::string log("B" + std::to_string(bb.id) + ":                               ;preds= ");
785         for (size_t k = 0; k < bb.preds.size(); ++k) {
786             log += std::to_string(bb.preds[k]->id) + ", ";
787         }
788         LOG_COMPILER(INFO) << log;
789         if (IsEntryBlock(bb.id)) {
790             LOG_COMPILER(INFO) << "\tBytecodePC: Empty";
791         } else {
792             LOG_COMPILER(INFO) << "\tBytecodePC: [" << std::to_string(bb.start) << ", "
793                 << std::to_string(bb.end) << ")";
794         }
795 
796         std::string log1("\tSucces: ");
797         for (size_t j = 0; j < bb.succs.size(); j++) {
798             log1 += std::to_string(bb.succs[j]->id) + ", ";
799         }
800         LOG_COMPILER(INFO) << log1;
801 
802         for (size_t j = 0; j < bb.catches.size(); j++) {
803             LOG_COMPILER(INFO) << "\tcatch [: " << std::to_string(bb.catches[j]->start) << ", "
804                                << std::to_string(bb.catches[j]->end) << ")";
805         }
806 
807         std::string log2("\tTrys: ");
808         for (auto tryBlock: bb.trys) {
809             log2 += std::to_string(tryBlock->id) + " , ";
810         }
811         LOG_COMPILER(INFO) << log2;
812 
813         PrintBytecodeInfo(bb);
814         LOG_COMPILER(INFO) << "";
815     }
816 }
817 
PrintBytecodeInfo(BytecodeRegion & bb)818 void BytecodeCircuitBuilder::PrintBytecodeInfo(BytecodeRegion& bb)
819 {
820     if (IsEntryBlock(bb.id)) {
821         LOG_COMPILER(INFO) << "\tBytecode[] = Empty";
822         return;
823     }
824     LOG_COMPILER(INFO) << "\tBytecode[] = ";
825     EnumerateBlock(bb, [&](const BytecodeInfo &bytecodeInfo) -> bool {
826         auto &iterator = bb.GetBytecodeIterator();
827         std::string log;
828         log += std::string("\t\t< ") + std::to_string(iterator.Index()) + ": ";
829         log += GetEcmaOpcodeStr(iterator.GetBytecodeInfo().GetOpcode()) + ", " + "In=[";
830         if (bytecodeInfo.AccIn()) {
831             log += "acc,";
832         }
833         for (const auto &in: bytecodeInfo.inputs) {
834             if (std::holds_alternative<VirtualRegister>(in)) {
835                 log += std::to_string(std::get<VirtualRegister>(in).GetId()) + ",";
836             }
837         }
838         log += "], Out=[";
839         if (bytecodeInfo.AccOut()) {
840             log += "acc,";
841         }
842         for (const auto &out: bytecodeInfo.vregOut) {
843             log += std::to_string(out) + ",";
844         }
845         log += "] >";
846         LOG_COMPILER(INFO) << log;
847 
848         auto gate = GetGateByBcIndex(iterator.Index());
849         if (gate != Circuit::NullGate()) {
850             this->gateAcc_.ShortPrint(gate);
851         }
852         return true;
853     });
854 }
855 }  // namespace panda::ecmascript::kungfu
856