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 byteCodeToJSGate_.resize(size, Circuit::NullGate());
44 regionsInfo_.InsertHead(0); // 0: start pc
45 for (iterator.GotoStart(); !iterator.Done(); ++iterator) {
46 auto index = iterator.Index();
47 auto &info = infoData_[index];
48 auto pc = pcOffsets_[index];
49 info.metaData_ = bytecodes_->GetBytecodeMetaData(pc);
50 BytecodeInfo::InitBytecodeInfo(this, info, pc);
51 CollectRegionInfo(index);
52 }
53 }
54
GetJumpOffset(uint32_t bcIndex) const55 int32_t BytecodeCircuitBuilder::GetJumpOffset(uint32_t bcIndex) const
56 {
57 auto pc = GetPCByIndex(bcIndex);
58 auto &info = GetBytecodeInfo(bcIndex);
59 int32_t offset = 0;
60 switch (info.GetOpcode()) {
61 case EcmaOpcode::JEQZ_IMM8:
62 case EcmaOpcode::JNEZ_IMM8:
63 case EcmaOpcode::JMP_IMM8:
64 offset = static_cast<int8_t>(READ_INST_8_0());
65 break;
66 case EcmaOpcode::JNEZ_IMM16:
67 case EcmaOpcode::JEQZ_IMM16:
68 case EcmaOpcode::JMP_IMM16:
69 offset = static_cast<int16_t>(READ_INST_16_0());
70 break;
71 case EcmaOpcode::JMP_IMM32:
72 case EcmaOpcode::JNEZ_IMM32:
73 case EcmaOpcode::JEQZ_IMM32:
74 offset = static_cast<int32_t>(READ_INST_32_0());
75 break;
76 case EcmaOpcode::RETURN:
77 case EcmaOpcode::RETURNUNDEFINED:
78 case EcmaOpcode::SUSPENDGENERATOR_V8:
79 case EcmaOpcode::DEPRECATED_SUSPENDGENERATOR_PREF_V8_V8:
80 offset = -(static_cast<int32_t>(pc - GetFirstPC()));
81 break;
82 default:
83 LOG_ECMA(FATAL) << "this branch is unreachable";
84 UNREACHABLE();
85 break;
86 }
87 return offset;
88 }
89
CollectRegionInfo(uint32_t bcIndex)90 void BytecodeCircuitBuilder::CollectRegionInfo(uint32_t bcIndex)
91 {
92 auto pc = pcOffsets_[bcIndex];
93 auto &info = infoData_[bcIndex];
94 int32_t offset = 0;
95 if (info.IsJump()) {
96 switch (info.GetOpcode()) {
97 case EcmaOpcode::JEQZ_IMM8:
98 case EcmaOpcode::JNEZ_IMM8:
99 case EcmaOpcode::JMP_IMM8:
100 offset = static_cast<int8_t>(READ_INST_8_0());
101 break;
102 case EcmaOpcode::JNEZ_IMM16:
103 case EcmaOpcode::JEQZ_IMM16:
104 case EcmaOpcode::JMP_IMM16:
105 offset = static_cast<int16_t>(READ_INST_16_0());
106 break;
107 case EcmaOpcode::JMP_IMM32:
108 case EcmaOpcode::JNEZ_IMM32:
109 case EcmaOpcode::JEQZ_IMM32:
110 offset = static_cast<int32_t>(READ_INST_32_0());
111 break;
112 default:
113 UNREACHABLE();
114 break;
115 }
116 auto nextIndex = bcIndex + 1; // 1: next pc
117 auto targetIndex = FindBcIndexByPc(pc + offset);
118 // condition branch current basic block end
119 if (info.IsCondJump()) {
120 regionsInfo_.InsertSplit(nextIndex);
121 regionsInfo_.InsertJump(targetIndex, bcIndex, false);
122 } else {
123 regionsInfo_.InsertHead(nextIndex);
124 regionsInfo_.InsertJump(targetIndex, bcIndex, true);
125 }
126 } else if (info.IsReturn() || info.IsThrow()) {
127 if (bcIndex != GetLastBcIndex()) {
128 auto nextIndex = bcIndex + 1; // 1: next pc
129 regionsInfo_.InsertHead(nextIndex);
130 }
131 }
132 }
133
CollectTryCatchBlockInfo(ExceptionInfo & byteCodeException)134 void BytecodeCircuitBuilder::CollectTryCatchBlockInfo(ExceptionInfo &byteCodeException)
135 {
136 panda_file::MethodDataAccessor mda(*pf_, method_->GetMethodId());
137 panda_file::CodeDataAccessor cda(*pf_, mda.GetCodeId().value());
138
139 cda.EnumerateTryBlocks([this, &byteCodeException](
140 panda_file::CodeDataAccessor::TryBlock &tryBlock) {
141 auto tryStartOffset = tryBlock.GetStartPc();
142 auto tryEndOffset = tryBlock.GetStartPc() + tryBlock.GetLength();
143
144 auto tryStartPc = const_cast<uint8_t *>(method_->GetBytecodeArray() + tryStartOffset);
145 auto tryEndPc = const_cast<uint8_t *>(method_->GetBytecodeArray() + tryEndOffset);
146 // skip try blocks with same pc in start and end label
147 if (tryStartPc == tryEndPc) {
148 return true;
149 }
150
151 auto tryStartBcIndex = FindBcIndexByPc(tryStartPc);
152 regionsInfo_.InsertSplit(tryStartBcIndex);
153 if (tryEndPc <= GetLastPC()) {
154 auto tryEndBcIndex = FindBcIndexByPc(tryEndPc);
155 regionsInfo_.InsertSplit(tryEndBcIndex);
156 }
157 byteCodeException.emplace_back(ExceptionItem { tryStartPc, tryEndPc, {} });
158 tryBlock.EnumerateCatchBlocks([&](panda_file::CodeDataAccessor::CatchBlock &catchBlock) {
159 auto pcOffset = catchBlock.GetHandlerPc();
160 auto catchBlockPc = const_cast<uint8_t *>(method_->GetBytecodeArray() + pcOffset);
161 auto catchBlockBcIndex = FindBcIndexByPc(catchBlockPc);
162 regionsInfo_.InsertHead(catchBlockBcIndex);
163 // try block associate catch block
164 byteCodeException.back().catchs.emplace_back(catchBlockPc);
165 return true;
166 });
167 return true;
168 });
169 }
170
BuildRegions(const ExceptionInfo & byteCodeException)171 void BytecodeCircuitBuilder::BuildRegions(const ExceptionInfo &byteCodeException)
172 {
173 auto &items = regionsInfo_.GetBlockItems();
174 auto blockSize = items.size();
175 graph_.resize(blockSize);
176 // build basic block
177 size_t blockId = 0;
178 for (const auto &item : items) {
179 auto &curBlock = GetBasicBlockById(blockId);
180 curBlock.id = blockId;
181 curBlock.start = item.GetStartBcIndex();
182 if (blockId != 0) {
183 auto &prevBlock = graph_[blockId - 1];
184 prevBlock.end = curBlock.start - 1;
185 prevBlock.bytecodeIterator_.Reset(this, prevBlock.start, prevBlock.end);
186 // fall through
187 if (!item.IsHeadBlock()) {
188 curBlock.preds.emplace_back(&prevBlock);
189 prevBlock.succs.emplace_back(&curBlock);
190 }
191 }
192 blockId++;
193 }
194 auto &lastBlock = graph_[blockId - 1]; // 1: last block
195 lastBlock.end = GetLastBcIndex();
196 lastBlock.bytecodeIterator_.Reset(this, lastBlock.start, lastBlock.end);
197
198 auto &splitItems = regionsInfo_.GetSplitItems();
199 for (const auto &item : splitItems) {
200 auto curIndex = regionsInfo_.FindBBIndexByBcIndex(item.startBcIndex);
201 auto &curBlock = GetBasicBlockById(curIndex);
202 auto predIndex = regionsInfo_.FindBBIndexByBcIndex(item.predBcIndex);
203 auto &predBlock = GetBasicBlockById(predIndex);
204 curBlock.preds.emplace_back(&predBlock);
205 predBlock.succs.emplace_back(&curBlock);
206 }
207
208 if (byteCodeException.size() != 0) {
209 BuildCatchBlocks(byteCodeException);
210 }
211 if (IsLogEnabled()) {
212 PrintGraph("Build Basic Block");
213 }
214 ComputeDominatorTree();
215 }
216
BuildCatchBlocks(const ExceptionInfo & byteCodeException)217 void BytecodeCircuitBuilder::BuildCatchBlocks(const ExceptionInfo &byteCodeException)
218 {
219 // try catch block associate
220 for (size_t i = 0; i < graph_.size(); i++) {
221 auto &bb = graph_[i];
222 auto startIndex = bb.start;
223 const auto pc = pcOffsets_[startIndex];
224 for (auto it = byteCodeException.cbegin(); it != byteCodeException.cend(); it++) {
225 if (pc < it->startPc || pc >= it->endPc) {
226 continue;
227 }
228 // try block interval
229 const auto &catchs = it->catchs; // catchs start pc
230 for (size_t j = i + 1; j < graph_.size(); j++) {
231 auto &catchBB = graph_[j];
232 const auto catchStart = pcOffsets_[catchBB.start];
233 if (std::find(catchs.cbegin(), catchs.cend(), catchStart) != catchs.cend()) {
234 bb.catchs.insert(bb.catchs.cbegin(), &catchBB);
235 bb.succs.emplace_back(&catchBB);
236 catchBB.preds.emplace_back(&bb);
237 }
238 }
239 }
240
241 // When there are multiple catch blocks in the current block, the set of catch blocks
242 // needs to be sorted to satisfy the order of execution of catch blocks.
243 bb.SortCatches();
244 }
245 }
246
ComputeDominatorTree()247 void BytecodeCircuitBuilder::ComputeDominatorTree()
248 {
249 // Construct graph backward order
250 std::unordered_map<size_t, size_t> bbIdToDfsTimestamp;
251 std::unordered_map<size_t, size_t> dfsFatherIdx;
252 std::unordered_map<size_t, size_t> bbDfsTimestampToIdx;
253 std::vector<size_t> basicBlockList;
254 size_t timestamp = 0;
255 std::deque<size_t> pendingList;
256 std::vector<size_t> visited(graph_.size(), 0);
257 auto basicBlockId = graph_[0].id;
258 visited[graph_[0].id] = 1;
259 pendingList.emplace_back(basicBlockId);
260 while (!pendingList.empty()) {
261 size_t curBlockId = pendingList.back();
262 pendingList.pop_back();
263 basicBlockList.emplace_back(curBlockId);
264 bbIdToDfsTimestamp[curBlockId] = timestamp++;
265 for (const auto &succBlock: graph_[curBlockId].succs) {
266 if (visited[succBlock->id] == 0) {
267 visited[succBlock->id] = 1;
268 pendingList.emplace_back(succBlock->id);
269 dfsFatherIdx[succBlock->id] = bbIdToDfsTimestamp[curBlockId];
270 }
271 }
272 }
273
274 for (size_t idx = 0; idx < basicBlockList.size(); idx++) {
275 bbDfsTimestampToIdx[basicBlockList[idx]] = idx;
276 }
277 RemoveDeadRegions(bbIdToDfsTimestamp);
278
279 std::vector<size_t> immDom(basicBlockList.size()); // immediate dominator with dfs order index
280 std::vector<size_t> semiDom(basicBlockList.size());
281 std::vector<size_t> realImmDom(graph_.size()); // immediate dominator with real index
282 std::vector<std::vector<size_t> > semiDomTree(basicBlockList.size());
283 {
284 std::vector<size_t> parent(basicBlockList.size());
285 std::iota(parent.begin(), parent.end(), 0);
286 std::vector<size_t> minIdx(basicBlockList.size());
287 std::function<size_t(size_t)> unionFind = [&] (size_t idx) -> size_t {
288 if (parent[idx] == idx) return idx;
289 size_t unionFindSetRoot = unionFind(parent[idx]);
290 if (semiDom[minIdx[idx]] > semiDom[minIdx[parent[idx]]]) {
291 minIdx[idx] = minIdx[parent[idx]];
292 }
293 return parent[idx] = unionFindSetRoot;
294 };
295 auto merge = [&] (size_t fatherIdx, size_t sonIdx) -> void {
296 size_t parentFatherIdx = unionFind(fatherIdx);
297 size_t parentSonIdx = unionFind(sonIdx);
298 parent[parentSonIdx] = parentFatherIdx;
299 };
300 std::iota(semiDom.begin(), semiDom.end(), 0);
301 semiDom[0] = semiDom.size();
302 for (size_t idx = basicBlockList.size() - 1; idx >= 1; idx--) {
303 for (const auto &preBlock : graph_[basicBlockList[idx]].preds) {
304 if (bbDfsTimestampToIdx[preBlock->id] < idx) {
305 semiDom[idx] = std::min(semiDom[idx], bbDfsTimestampToIdx[preBlock->id]);
306 } else {
307 unionFind(bbDfsTimestampToIdx[preBlock->id]);
308 semiDom[idx] = std::min(semiDom[idx], semiDom[minIdx[bbDfsTimestampToIdx[preBlock->id]]]);
309 }
310 }
311 for (const auto & succDomIdx : semiDomTree[idx]) {
312 unionFind(succDomIdx);
313 if (idx == semiDom[minIdx[succDomIdx]]) {
314 immDom[succDomIdx] = idx;
315 } else {
316 immDom[succDomIdx] = minIdx[succDomIdx];
317 }
318 }
319 minIdx[idx] = idx;
320 merge(dfsFatherIdx[basicBlockList[idx]], idx);
321 semiDomTree[semiDom[idx]].emplace_back(idx);
322 }
323 for (size_t idx = 1; idx < basicBlockList.size(); idx++) {
324 if (immDom[idx] != semiDom[idx]) {
325 immDom[idx] = immDom[immDom[idx]];
326 }
327 realImmDom[basicBlockList[idx]] = basicBlockList[immDom[idx]];
328 }
329 semiDom[0] = 0;
330 }
331
332 if (IsLogEnabled()) {
333 PrintGraph("Computed Dom Trees");
334 }
335
336 BuildImmediateDominator(realImmDom);
337 }
338
BuildImmediateDominator(const std::vector<size_t> & immDom)339 void BytecodeCircuitBuilder::BuildImmediateDominator(const std::vector<size_t> &immDom)
340 {
341 graph_[0].iDominator = &graph_[0];
342 for (size_t i = 1; i < immDom.size(); i++) {
343 auto dominatedBlock = &graph_[i];
344 if (dominatedBlock->isDead) {
345 continue;
346 }
347 auto immDomBlock = &graph_[immDom[i]];
348 dominatedBlock->iDominator = immDomBlock;
349 }
350
351 for (auto &block : graph_) {
352 if (block.isDead) {
353 continue;
354 }
355 if (block.iDominator->id != block.id) {
356 block.iDominator->immDomBlocks.emplace_back(&block);
357 }
358 }
359
360 ComputeDomFrontiers(immDom);
361 InsertPhi();
362 UpdateCFG();
363 BuildCircuit();
364 }
365
ComputeDomFrontiers(const std::vector<size_t> & immDom)366 void BytecodeCircuitBuilder::ComputeDomFrontiers(const std::vector<size_t> &immDom)
367 {
368 std::vector<std::set<BytecodeRegion *>> domFrontiers(immDom.size());
369 for (auto &bb : graph_) {
370 if (bb.isDead) {
371 continue;
372 }
373 if (bb.preds.size() < 2) { // 2: pred num
374 continue;
375 }
376 for (size_t i = 0; i < bb.preds.size(); i++) {
377 auto runner = bb.preds[i];
378 while (runner->id != immDom[bb.id]) {
379 domFrontiers[runner->id].insert(&bb);
380 runner = &graph_[immDom[runner->id]];
381 }
382 }
383 }
384
385 for (size_t i = 0; i < domFrontiers.size(); i++) {
386 for (auto iter = domFrontiers[i].cbegin(); iter != domFrontiers[i].cend(); iter++) {
387 graph_[i].domFrontiers.emplace_back(*iter);
388 }
389 }
390 }
391
RemoveDeadRegions(const std::unordered_map<size_t,size_t> & bbIdToDfsTimestamp)392 void BytecodeCircuitBuilder::RemoveDeadRegions(const std::unordered_map<size_t, size_t> &bbIdToDfsTimestamp)
393 {
394 for (auto &block: graph_) {
395 std::vector<BytecodeRegion *> newPreds;
396 for (auto &bb : block.preds) {
397 if (bbIdToDfsTimestamp.count(bb->id)) {
398 newPreds.emplace_back(bb);
399 }
400 }
401 block.preds = newPreds;
402 }
403
404 for (auto &block : graph_) {
405 block.isDead = !bbIdToDfsTimestamp.count(block.id);
406 if (block.isDead) {
407 block.succs.clear();
408 }
409 }
410 }
411
InsertPhi()412 void BytecodeCircuitBuilder::InsertPhi()
413 {
414 std::unordered_map<uint16_t, std::set<size_t>> defsitesInfo; // <vreg, bbs>
415 for (auto &bb : graph_) {
416 if (bb.isDead) {
417 continue;
418 }
419 EnumerateBlock(bb, [this, &defsitesInfo, &bb]
420 (const BytecodeInfo &bytecodeInfo) -> bool {
421 if (bytecodeInfo.IsBc(EcmaOpcode::RESUMEGENERATOR)) {
422 auto numVRegs = GetNumberVRegsWithEnv();
423 for (size_t i = 0; i < numVRegs; i++) {
424 defsitesInfo[i].insert(bb.id);
425 }
426 }
427 for (const auto &vreg: bytecodeInfo.vregOut) {
428 defsitesInfo[vreg].insert(bb.id);
429 }
430 return true;
431 });
432 }
433
434 // handle phi generated from multiple control flow in the same source block
435 InsertExceptionPhi(defsitesInfo);
436
437 for (const auto&[variable, defsites] : defsitesInfo) {
438 std::queue<uint16_t> workList;
439 for (auto blockId: defsites) {
440 workList.push(blockId);
441 }
442 while (!workList.empty()) {
443 auto currentId = workList.front();
444 workList.pop();
445 for (auto &block : graph_[currentId].domFrontiers) {
446 if (!block->phi.count(variable)) {
447 block->phi.insert(variable);
448 if (!defsitesInfo[variable].count(block->id)) {
449 workList.push(block->id);
450 }
451 }
452 }
453 }
454 }
455
456 if (IsLogEnabled()) {
457 PrintGraph("Inserted Phis");
458 }
459 }
460
InsertExceptionPhi(std::unordered_map<uint16_t,std::set<size_t>> & defsitesInfo)461 void BytecodeCircuitBuilder::InsertExceptionPhi(std::unordered_map<uint16_t, std::set<size_t>> &defsitesInfo)
462 {
463 // handle try catch defsite
464 for (auto &bb : graph_) {
465 if (bb.isDead) {
466 continue;
467 }
468 if (bb.catchs.size() == 0) {
469 continue;
470 }
471 std::set<size_t> vregs;
472 EnumerateBlock(bb, [this, &vregs]
473 (const BytecodeInfo &bytecodeInfo) -> bool {
474 if (bytecodeInfo.IsBc(EcmaOpcode::RESUMEGENERATOR)) {
475 auto numVRegs = GetNumberVRegsWithEnv();
476 for (size_t i = 0; i < numVRegs; i++) {
477 vregs.insert(i);
478 }
479 return false;
480 }
481 for (const auto &vreg: bytecodeInfo.vregOut) {
482 vregs.insert(vreg);
483 }
484 return true;
485 });
486
487 for (auto &vreg : vregs) {
488 defsitesInfo[vreg].insert(bb.catchs.at(0)->id);
489 bb.catchs.at(0)->phi.insert(vreg);
490 }
491 }
492 }
493
494 // Update CFG's predecessor, successor and try catch associations
UpdateCFG()495 void BytecodeCircuitBuilder::UpdateCFG()
496 {
497 for (auto &bb: graph_) {
498 if (bb.isDead) {
499 continue;
500 }
501 bb.preds.clear();
502 bb.trys.clear();
503 std::vector<BytecodeRegion *> newSuccs;
504 for (const auto &succ: bb.succs) {
505 if (std::count(bb.catchs.cbegin(), bb.catchs.cend(), succ)) {
506 continue;
507 }
508 newSuccs.emplace_back(succ);
509 }
510 bb.succs = newSuccs;
511 }
512 for (auto &bb: graph_) {
513 if (bb.isDead) {
514 continue;
515 }
516 for (auto &succ: bb.succs) {
517 succ->preds.emplace_back(&bb);
518 }
519 for (auto &catchBlock: bb.catchs) {
520 catchBlock->trys.emplace_back(&bb);
521 }
522 }
523 }
524
525 // build circuit
BuildCircuitArgs()526 void BytecodeCircuitBuilder::BuildCircuitArgs()
527 {
528 argAcc_.NewCommonArg(CommonArgIdx::GLUE, MachineType::I64, GateType::NJSValue());
529 argAcc_.NewCommonArg(CommonArgIdx::LEXENV, MachineType::I64, GateType::TaggedValue());
530 argAcc_.NewCommonArg(CommonArgIdx::ACTUAL_ARGC, MachineType::I64, GateType::NJSValue());
531 auto funcIdx = static_cast<size_t>(CommonArgIdx::FUNC);
532 const size_t actualNumArgs = argAcc_.GetActualNumArgs();
533 // new actual argument gates
534 for (size_t argIdx = funcIdx; argIdx < actualNumArgs; argIdx++) {
535 argAcc_.NewArg(argIdx);
536 }
537 argAcc_.CollectArgs();
538 if (HasTypes()) {
539 argAcc_.FillArgsGateType(&typeRecorder_);
540 }
541 }
542
ShouldBeDead(BytecodeRegion & curBlock)543 bool BytecodeCircuitBuilder::ShouldBeDead(BytecodeRegion &curBlock)
544 {
545 auto isDead = false;
546 for (auto bbPred : curBlock.preds) {
547 if (!bbPred->isDead) {
548 return false;
549 }
550 isDead = true;
551 }
552 for (auto bbTry : curBlock.trys) {
553 if (!bbTry->isDead) {
554 return false;
555 }
556 isDead = true;
557 }
558 return isDead;
559 }
560
CollectPredsInfo()561 void BytecodeCircuitBuilder::CollectPredsInfo()
562 {
563 for (auto &bb: graph_) {
564 if (bb.isDead) {
565 continue;
566 }
567 bb.numOfStatePreds = 0;
568 }
569 // get number of expanded state predicates of each block
570 // one block-level try catch edge may correspond to multiple bytecode-level edges
571 for (auto &bb: graph_) {
572 if (bb.isDead) {
573 continue;
574 }
575 if (ShouldBeDead(bb)) {
576 bb.UpdateTryCatchInfoForDeadBlock();
577 bb.isDead = true;
578 continue;
579 }
580 bool noThrow = true;
581 EnumerateBlock(bb, [&noThrow, &bb]
582 (const BytecodeInfo &bytecodeInfo) -> bool {
583 if (bytecodeInfo.IsGeneral()) {
584 noThrow = false;
585 if (!bb.catchs.empty()) {
586 bb.catchs.at(0)->numOfStatePreds++;
587 }
588 }
589 if (bytecodeInfo.IsCondJump() && bb.succs.size() == 1) {
590 ASSERT(bb.succs[0]->id == bb.id + 1);
591 bb.succs[0]->numOfStatePreds++;
592 }
593 return true;
594 });
595 bb.UpdateRedundantTryCatchInfo(noThrow);
596 bb.UpdateTryCatchInfoIfNoThrow(noThrow);
597 for (auto &succ: bb.succs) {
598 succ->numOfStatePreds++;
599 }
600 }
601 // collect loopback edges
602 std::vector<VisitState> visitState(graph_.size(), VisitState::UNVISITED);
603 std::function<void(size_t)> dfs = [&](size_t bbId) -> void {
604 visitState[bbId] = VisitState::PENDING;
605 std::vector<BytecodeRegion *> merge;
606 merge.insert(merge.end(), graph_[bbId].succs.begin(), graph_[bbId].succs.end());
607 merge.insert(merge.end(), graph_[bbId].catchs.begin(), graph_[bbId].catchs.end());
608 auto it = merge.crbegin();
609 while (it != merge.crend()) {
610 auto succBlock = *it;
611 it++;
612 if (visitState[succBlock->id] == VisitState::UNVISITED) {
613 dfs(succBlock->id);
614 } else {
615 if (visitState[succBlock->id] == VisitState::PENDING) {
616 graph_[succBlock->id].loopbackBlocks.insert(bbId);
617 }
618 }
619 }
620 visitState[bbId] = VisitState::VISITED;
621 };
622 dfs(graph_[0].id);
623 for (auto &bb: graph_) {
624 if (bb.isDead) {
625 continue;
626 }
627 bb.phiAcc = (bb.numOfStatePreds > 1) || (!bb.trys.empty());
628 bb.numOfLoopBacks = bb.loopbackBlocks.size();
629 }
630 }
631
NewMerge(GateRef & state,GateRef & depend,size_t numOfIns)632 void BytecodeCircuitBuilder::NewMerge(GateRef &state, GateRef &depend, size_t numOfIns)
633 {
634 state = circuit_->NewGate(circuit_->Merge(numOfIns),
635 std::vector<GateRef>(numOfIns, Circuit::NullGate()));
636 depend = circuit_->NewGate(circuit_->DependSelector(numOfIns),
637 std::vector<GateRef>(numOfIns + 1, Circuit::NullGate()));
638 gateAcc_.NewIn(depend, 0, state);
639 }
640
NewLoopBegin(BytecodeRegion & bb)641 void BytecodeCircuitBuilder::NewLoopBegin(BytecodeRegion &bb)
642 {
643 if (bb.id == 0 && bb.numOfStatePreds == 1) {
644 bb.mergeForwardEdges = circuit_->NewGate(circuit_->Merge(bb.numOfStatePreds),
645 std::vector<GateRef>(bb.numOfStatePreds,
646 circuit_->GetStateRoot()));
647 bb.depForward = circuit_->NewGate(circuit_->DependSelector(bb.numOfStatePreds),
648 std::vector<GateRef>(bb.numOfStatePreds + 1, Circuit::NullGate()));
649 gateAcc_.NewIn(bb.depForward, 0, bb.mergeForwardEdges);
650 gateAcc_.NewIn(bb.depForward, 1, circuit_->GetDependRoot());
651 } else {
652 NewMerge(bb.mergeForwardEdges, bb.depForward, bb.numOfStatePreds - bb.numOfLoopBacks);
653 }
654 NewMerge(bb.mergeLoopBackEdges, bb.depLoopBack, bb.numOfLoopBacks);
655 auto loopBack = circuit_->NewGate(circuit_->LoopBack(),
656 { bb.mergeLoopBackEdges });
657 bb.stateStart = circuit_->NewGate(circuit_->LoopBegin(),
658 { bb.mergeForwardEdges, loopBack });
659 // 2: the number of depend inputs and it is in accord with LOOP_BEGIN
660 bb.dependStart = circuit_->NewGate(circuit_->DependSelector(2),
661 { bb.stateStart, bb.depForward, bb.depLoopBack });
662 }
663
BuildBlockCircuitHead()664 void BytecodeCircuitBuilder::BuildBlockCircuitHead()
665 {
666 for (auto &bb: graph_) {
667 if (bb.isDead) {
668 continue;
669 }
670 if (bb.numOfStatePreds == 0) {
671 bb.stateStart = circuit_->GetStateRoot();
672 bb.dependStart = circuit_->GetDependRoot();
673 } else if (bb.numOfLoopBacks > 0) {
674 NewLoopBegin(bb);
675 } else {
676 NewMerge(bb.stateStart, bb.dependStart, bb.numOfStatePreds);
677 }
678 }
679 }
680
CreateGateInList(const BytecodeInfo & info,const GateMetaData * meta)681 std::vector<GateRef> BytecodeCircuitBuilder::CreateGateInList(
682 const BytecodeInfo &info, const GateMetaData *meta)
683 {
684 auto numValues = meta->GetNumIns();
685 const size_t length = meta->GetInValueStarts();
686 std::vector<GateRef> inList(numValues, Circuit::NullGate());
687 auto inputSize = info.inputs.size();
688 for (size_t i = 0; i < inputSize; i++) {
689 auto &input = info.inputs[i];
690 if (std::holds_alternative<ConstDataId>(input)) {
691 if (std::get<ConstDataId>(input).IsStringId()) {
692 inList[i + length] = circuit_->GetConstantDataGate(std::get<ConstDataId>(input).CaculateBitField(),
693 GateType::StringType());
694 } else {
695 inList[i + length] = circuit_->GetConstantGate(MachineType::I64,
696 std::get<ConstDataId>(input).GetId(),
697 GateType::NJSValue());
698 }
699 } else if (std::holds_alternative<Immediate>(input)) {
700 inList[i + length] = circuit_->GetConstantGate(MachineType::I64,
701 std::get<Immediate>(input).GetValue(),
702 GateType::NJSValue());
703 } else if (std::holds_alternative<ICSlotId>(input)) {
704 inList[i + length] = circuit_->GetConstantGate(MachineType::I16,
705 std::get<ICSlotId>(input).GetId(),
706 GateType::NJSValue());
707 } else {
708 ASSERT(std::holds_alternative<VirtualRegister>(input));
709 continue;
710 }
711 }
712 if (info.AccIn()) {
713 inputSize++;
714 }
715 if (info.ThisObjectIn()) {
716 inList[inputSize + length] = argAcc_.GetCommonArgGate(CommonArgIdx::THIS_OBJECT);
717 }
718 return inList;
719 }
720
SetBlockPred(BytecodeRegion & bbNext,const GateRef & state,const GateRef & depend,bool isLoopBack)721 void BytecodeCircuitBuilder::SetBlockPred(BytecodeRegion &bbNext, const GateRef &state,
722 const GateRef &depend, bool isLoopBack)
723 {
724 if (bbNext.numOfLoopBacks == 0) {
725 gateAcc_.NewIn(bbNext.stateStart, bbNext.statePredIndex, state);
726 gateAcc_.NewIn(bbNext.dependStart, bbNext.statePredIndex + 1, depend);
727 } else {
728 if (isLoopBack) {
729 gateAcc_.NewIn(bbNext.mergeLoopBackEdges, bbNext.loopBackIndex, state);
730 gateAcc_.NewIn(bbNext.depLoopBack, bbNext.loopBackIndex + 1, depend);
731 bbNext.loopBackIndex++;
732 ASSERT(bbNext.loopBackIndex <= bbNext.numOfLoopBacks);
733 } else {
734 gateAcc_.NewIn(bbNext.mergeForwardEdges, bbNext.forwardIndex, state);
735 gateAcc_.NewIn(bbNext.depForward, bbNext.forwardIndex + 1, depend);
736 bbNext.forwardIndex++;
737 ASSERT(bbNext.forwardIndex <= bbNext.numOfStatePreds - bbNext.numOfLoopBacks);
738 }
739 }
740 bbNext.statePredIndex++;
741 ASSERT(bbNext.statePredIndex <= bbNext.numOfStatePreds);
742 }
743
NewConst(const BytecodeInfo & info)744 GateRef BytecodeCircuitBuilder::NewConst(const BytecodeInfo &info)
745 {
746 auto opcode = info.GetOpcode();
747 GateRef gate = 0;
748 switch (opcode) {
749 case EcmaOpcode::LDNAN:
750 gate = circuit_->GetConstantGate(MachineType::I64,
751 base::NumberHelper::GetNaN(),
752 GateType::NumberType());
753 break;
754 case EcmaOpcode::LDINFINITY:
755 gate = circuit_->GetConstantGate(MachineType::I64,
756 base::NumberHelper::GetPositiveInfinity(),
757 GateType::NumberType());
758 break;
759 case EcmaOpcode::LDUNDEFINED:
760 gate = circuit_->GetConstantGate(MachineType::I64,
761 JSTaggedValue::VALUE_UNDEFINED,
762 GateType::UndefinedType());
763 break;
764 case EcmaOpcode::LDNULL:
765 gate = circuit_->GetConstantGate(MachineType::I64,
766 JSTaggedValue::VALUE_NULL,
767 GateType::NullType());
768 break;
769 case EcmaOpcode::LDTRUE:
770 gate = circuit_->GetConstantGate(MachineType::I64,
771 JSTaggedValue::VALUE_TRUE,
772 GateType::BooleanType());
773 break;
774 case EcmaOpcode::LDFALSE:
775 gate = circuit_->GetConstantGate(MachineType::I64,
776 JSTaggedValue::VALUE_FALSE,
777 GateType::BooleanType());
778 break;
779 case EcmaOpcode::LDHOLE:
780 gate = circuit_->GetConstantGate(MachineType::I64,
781 JSTaggedValue::VALUE_HOLE,
782 GateType::TaggedValue());
783 break;
784 case EcmaOpcode::LDAI_IMM32:
785 gate = circuit_->GetConstantGate(MachineType::I64,
786 std::get<Immediate>(info.inputs[0]).ToJSTaggedValueInt(),
787 GateType::IntType());
788 break;
789 case EcmaOpcode::FLDAI_IMM64:
790 gate = circuit_->GetConstantGate(MachineType::I64,
791 std::get<Immediate>(info.inputs.at(0)).ToJSTaggedValueDouble(),
792 GateType::DoubleType());
793 break;
794 case EcmaOpcode::LDFUNCTION:
795 gate = argAcc_.GetCommonArgGate(CommonArgIdx::FUNC);
796 break;
797 case EcmaOpcode::LDNEWTARGET:
798 gate = argAcc_.GetCommonArgGate(CommonArgIdx::NEW_TARGET);
799 break;
800 case EcmaOpcode::LDTHIS:
801 gate = argAcc_.GetCommonArgGate(CommonArgIdx::THIS_OBJECT);
802 break;
803 case EcmaOpcode::LDA_STR_ID16: {
804 auto input = std::get<ConstDataId>(info.inputs.at(0));
805 gate = circuit_->GetConstantDataGate(input.CaculateBitField(), GateType::StringType());
806 break;
807 }
808 default:
809 UNREACHABLE();
810 }
811 return gate;
812 }
813
NewJSGate(BytecodeRegion & bb,GateRef & state,GateRef & depend)814 void BytecodeCircuitBuilder::NewJSGate(BytecodeRegion &bb, GateRef &state, GateRef &depend)
815 {
816 auto &iterator = bb.GetBytecodeIterator();
817 const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
818 size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
819 GateRef gate = 0;
820 bool writable = !bytecodeInfo.NoSideEffects();
821 auto meta = circuit_->JSBytecode(numValueInputs,
822 bytecodeInfo.GetOpcode(), iterator.Index(), writable);
823 std::vector<GateRef> inList = CreateGateInList(bytecodeInfo, meta);
824 if (bytecodeInfo.IsDef()) {
825 gate = circuit_->NewGate(meta, MachineType::I64, inList.size(),
826 inList.data(), GateType::AnyType());
827 } else {
828 gate = circuit_->NewGate(meta, MachineType::NOVALUE, inList.size(),
829 inList.data(), GateType::Empty());
830 }
831 if (bytecodeInfo.IsSuspend()) {
832 auto offsetGate = circuit_->GetConstantGate(MachineType::I32,
833 GetJumpOffset(iterator.Index()),
834 GateType::NJSValue());
835 auto updateHotness = circuit_->NewGate(circuit_->UpdateHotness(), {state, depend, offsetGate});
836 gateAcc_.NewIn(gate, 0, updateHotness);
837 gateAcc_.NewIn(gate, 1, updateHotness);
838 } else {
839 gateAcc_.NewIn(gate, 0, state);
840 gateAcc_.NewIn(gate, 1, depend);
841 }
842 state = gate;
843 if (!bb.catchs.empty()) {
844 auto ifSuccess = circuit_->NewGate(circuit_->IfSuccess(), {gate});
845 auto ifException = circuit_->NewGate(circuit_->IfException(), {gate});
846
847 auto &bbNext = bb.catchs.at(0);
848 auto isLoopBack = bbNext->loopbackBlocks.count(bb.id);
849 SetBlockPred(*bbNext, ifException, gate, isLoopBack);
850 if (bytecodeInfo.GetOpcode() == EcmaOpcode::CREATEASYNCGENERATOROBJ_V8) {
851 bbNext->expandedPreds.push_back({bb.id, iterator.Index() + 1, true}); // 1: next pc
852 } else {
853 bbNext->expandedPreds.push_back({bb.id, iterator.Index(), true});
854 }
855 state = ifSuccess;
856 }
857 byteCodeToJSGate_[iterator.Index()] = gate;
858 if (bytecodeInfo.IsGeneratorRelative()) {
859 if (bytecodeInfo.GetOpcode() == EcmaOpcode::SUSPENDGENERATOR_V8) {
860 auto hole = circuit_->GetConstantGate(MachineType::I64,
861 JSTaggedValue::VALUE_HOLE,
862 GateType::TaggedValue());
863 uint32_t numRegs = GetNumberVRegsWithEnv();
864 std::vector<GateRef> vec(numRegs + 1, hole);
865 vec[0] = depend;
866 GateRef saveRegs =
867 circuit_->NewGate(circuit_->SaveRegister(numRegs), vec);
868 gateAcc_.ReplaceDependIn(gate, saveRegs);
869 }
870 suspendAndResumeGates_.emplace_back(gate);
871 }
872 depend = gate;
873 if (bytecodeInfo.IsThrow()) {
874 auto constant = circuit_->GetConstantGate(MachineType::I64,
875 JSTaggedValue::VALUE_EXCEPTION,
876 GateType::TaggedValue());
877 circuit_->NewGate(circuit_->Return(),
878 { state, depend, constant, circuit_->GetReturnRoot() });
879 return;
880 }
881 if (iterator.Index() == bb.end) {
882 auto &bbNext = graph_[bb.id + 1];
883 auto isLoopBack = bbNext.loopbackBlocks.count(bb.id);
884 SetBlockPred(bbNext, state, depend, isLoopBack);
885 bbNext.expandedPreds.push_back({bb.id, iterator.Index(), false});
886 }
887 }
888
NewJump(BytecodeRegion & bb,GateRef & state,GateRef & depend)889 void BytecodeCircuitBuilder::NewJump(BytecodeRegion &bb, GateRef &state, GateRef &depend)
890 {
891 auto &iterator = bb.GetBytecodeIterator();
892 const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
893 size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
894 auto offset = GetJumpOffset(iterator.Index());
895 if (bytecodeInfo.IsCondJump()) {
896 ASSERT(!bytecodeInfo.Deopt());
897 auto meta = circuit_->JSBytecode(numValueInputs,
898 bytecodeInfo.GetOpcode(), iterator.Index(), false);
899 auto numValues = meta->GetNumIns();
900 GateRef gate = circuit_->NewGate(meta, std::vector<GateRef>(numValues, Circuit::NullGate()));
901 gateAcc_.NewIn(gate, 0, state);
902 gateAcc_.NewIn(gate, 1, depend);
903 auto ifTrue = circuit_->NewGate(circuit_->IfTrue(), {gate});
904 auto trueRelay = circuit_->NewGate(circuit_->DependRelay(), {ifTrue, gate});
905 if (offset < 0) {
906 // place update hotness Gate when offset is negative.
907 auto offsetGate = circuit_->GetConstantGate(MachineType::I32,
908 offset,
909 GateType::NJSValue());
910 ifTrue = circuit_->NewGate(circuit_->UpdateHotness(), {ifTrue, trueRelay, offsetGate});
911 trueRelay = ifTrue;
912 }
913 auto ifFalse = circuit_->NewGate(circuit_->IfFalse(), {gate});
914 auto falseRelay = circuit_->NewGate(circuit_->DependRelay(), {ifFalse, gate});
915 if (bb.succs.size() == 1) {
916 auto &bbNext = bb.succs[0];
917 ASSERT(bbNext->id == bb.id + 1);
918 auto isLoopBack = bbNext->loopbackBlocks.count(bb.id);
919 SetBlockPred(*bbNext, ifFalse, falseRelay, isLoopBack);
920 SetBlockPred(*bbNext, ifTrue, trueRelay, isLoopBack);
921 bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
922 bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
923 } else {
924 ASSERT(bb.succs.size() == 2); // 2 : 2 num of successors
925 [[maybe_unused]] uint32_t bitSet = 0;
926 for (auto &bbNext: bb.succs) {
927 if (bbNext->id == bb.id + 1) {
928 auto isLoopBack = bbNext->loopbackBlocks.count(bb.id);
929 SetBlockPred(*bbNext, ifFalse, falseRelay, isLoopBack);
930 bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
931 bitSet |= 1;
932 } else {
933 auto isLoopBack = bbNext->loopbackBlocks.count(bb.id);
934 SetBlockPred(*bbNext, ifTrue, trueRelay, isLoopBack);
935 bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
936 bitSet |= 2; // 2:verify
937 }
938 }
939 ASSERT(bitSet == 3); // 3:Verify the number of successor blocks
940 }
941 byteCodeToJSGate_[iterator.Index()] = gate;
942 } else {
943 ASSERT(bb.succs.size() == 1);
944 auto &bbNext = bb.succs.at(0);
945 auto isLoopBack = bbNext->loopbackBlocks.count(bb.id);
946 if (offset < 0) {
947 // place update hotness Gate when offset is negative.
948 auto offsetGate = circuit_->GetConstantGate(MachineType::I32,
949 offset,
950 GateType::NJSValue());
951 auto updateHotness = circuit_->NewGate(circuit_->UpdateHotness(), {state, depend, offsetGate});
952 SetBlockPred(*bbNext, updateHotness, updateHotness, isLoopBack);
953 } else {
954 SetBlockPred(*bbNext, state, depend, isLoopBack);
955 }
956 bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
957 }
958 }
959
NewReturn(BytecodeRegion & bb,GateRef & state,GateRef & depend)960 void BytecodeCircuitBuilder::NewReturn(BytecodeRegion &bb, GateRef &state, GateRef &depend)
961 {
962 ASSERT(bb.succs.empty());
963 auto &iterator = bb.GetBytecodeIterator();
964 const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
965 auto offsetGate = circuit_->GetConstantGate(MachineType::I32,
966 GetJumpOffset(iterator.Index()),
967 GateType::NJSValue());
968 auto updateHotness = circuit_->NewGate(circuit_->UpdateHotness(), {state, depend, offsetGate});
969 if (bytecodeInfo.GetOpcode() == EcmaOpcode::RETURN) {
970 // handle return.dyn bytecode
971 auto gate = circuit_->NewGate(circuit_->Return(),
972 { updateHotness, updateHotness, Circuit::NullGate(), circuit_->GetReturnRoot() });
973 byteCodeToJSGate_[iterator.Index()] = gate;
974 } else if (bytecodeInfo.GetOpcode() == EcmaOpcode::RETURNUNDEFINED) {
975 // handle returnundefined bytecode
976 auto constant = circuit_->GetConstantGate(MachineType::I64,
977 JSTaggedValue::VALUE_UNDEFINED,
978 GateType::TaggedValue());
979 auto gate = circuit_->NewGate(circuit_->Return(),
980 { updateHotness, updateHotness, constant, circuit_->GetReturnRoot() });
981 byteCodeToJSGate_[iterator.Index()] = gate;
982 }
983 }
984
NewByteCode(BytecodeRegion & bb,GateRef & state,GateRef & depend)985 void BytecodeCircuitBuilder::NewByteCode(BytecodeRegion &bb, GateRef &state, GateRef &depend)
986 {
987 auto &iterator = bb.GetBytecodeIterator();
988 const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
989 if (bytecodeInfo.IsSetConstant()) {
990 // handle bytecode command to get constants
991 GateRef gate = NewConst(bytecodeInfo);
992 byteCodeToJSGate_[iterator.Index()] = gate;
993 if (iterator.Index() == bb.end) {
994 auto &bbNext = graph_[bb.id + 1];
995 auto isLoopBack = bbNext.loopbackBlocks.count(bb.id);
996 SetBlockPred(bbNext, state, depend, isLoopBack);
997 bbNext.expandedPreds.push_back({bb.id, iterator.Index(), false});
998 }
999 } else if (bytecodeInfo.IsGeneral()) {
1000 // handle general ecma.* bytecodes
1001 NewJSGate(bb, state, depend);
1002 } else if (bytecodeInfo.IsJump()) {
1003 // handle conditional jump and unconditional jump bytecodes
1004 NewJump(bb, state, depend);
1005 } else if (bytecodeInfo.IsReturn()) {
1006 // handle return.dyn and returnundefined bytecodes
1007 NewReturn(bb, state, depend);
1008 } else if (bytecodeInfo.IsMov()) {
1009 // handle mov.dyn lda.dyn sta.dyn bytecodes
1010 if (iterator.Index() == bb.end) {
1011 auto &bbNext = graph_[bb.id + 1];
1012 auto isLoopBack = bbNext.loopbackBlocks.count(bb.id);
1013 SetBlockPred(bbNext, state, depend, isLoopBack);
1014 bbNext.expandedPreds.push_back({bb.id, iterator.Index(), false});
1015 }
1016 } else if (bytecodeInfo.IsDiscarded()) {
1017 return;
1018 } else {
1019 UNREACHABLE();
1020 }
1021 }
1022
BuildSubCircuit()1023 void BytecodeCircuitBuilder::BuildSubCircuit()
1024 {
1025 for (auto &bb: graph_) {
1026 if (bb.isDead) {
1027 continue;
1028 }
1029 auto stateCur = bb.stateStart;
1030 auto dependCur = bb.dependStart;
1031 ASSERT(stateCur != Circuit::NullGate());
1032 ASSERT(dependCur != Circuit::NullGate());
1033 if (!bb.trys.empty()) {
1034 dependCur = circuit_->NewGate(circuit_->GetException(),
1035 MachineType::I64, {dependCur}, GateType::AnyType());
1036 }
1037 EnumerateBlock(bb, [this, &stateCur, &dependCur, &bb]
1038 (const BytecodeInfo &bytecodeInfo) -> bool {
1039 NewByteCode(bb, stateCur, dependCur);
1040 if (bytecodeInfo.IsJump() || bytecodeInfo.IsThrow()) {
1041 return false;
1042 }
1043 return true;
1044 });
1045 }
1046 }
1047
NewPhi(BytecodeRegion & bb,uint16_t reg,bool acc,GateRef & currentPhi)1048 void BytecodeCircuitBuilder::NewPhi(BytecodeRegion &bb, uint16_t reg, bool acc, GateRef ¤tPhi)
1049 {
1050 if (bb.numOfLoopBacks == 0) {
1051 auto inList = std::vector<GateRef>(1 + bb.numOfStatePreds, Circuit::NullGate());
1052 currentPhi =
1053 circuit_->NewGate(circuit_->ValueSelector(bb.numOfStatePreds), MachineType::I64,
1054 inList.size(), inList.data(), GateType::AnyType());
1055 gateAcc_.NewIn(currentPhi, 0, bb.stateStart);
1056 for (size_t i = 0; i < bb.numOfStatePreds; ++i) {
1057 auto &[predId, predBcIdx, isException] = bb.expandedPreds.at(i);
1058 gateAcc_.NewIn(currentPhi, i + 1, ResolveDef(predId, predBcIdx, reg, acc));
1059 }
1060 } else {
1061 // 2: the number of value inputs and it is in accord with LOOP_BEGIN
1062 currentPhi = circuit_->NewGate(circuit_->ValueSelector(2), MachineType::I64,
1063 {bb.stateStart, Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType());
1064 auto inList = std::vector<GateRef>(1 + bb.numOfLoopBacks, Circuit::NullGate());
1065 auto loopBackValue = circuit_->NewGate(circuit_->ValueSelector(bb.numOfLoopBacks),
1066 MachineType::I64, inList.size(), inList.data(), GateType::AnyType());
1067 gateAcc_.NewIn(loopBackValue, 0, bb.mergeLoopBackEdges);
1068 size_t loopBackIndex = 1; // 1: start index of value inputs
1069 for (size_t i = 0; i < bb.numOfStatePreds; ++i) {
1070 auto &[predId, predBcIdx, isException] = bb.expandedPreds.at(i);
1071 if (bb.loopbackBlocks.count(predId)) {
1072 gateAcc_.NewIn(loopBackValue, loopBackIndex++, ResolveDef(predId, predBcIdx, reg, acc));
1073 }
1074 }
1075 inList = std::vector<GateRef>(1 + bb.numOfStatePreds - bb.numOfLoopBacks, Circuit::NullGate());
1076 auto forwardValue = circuit_->NewGate(
1077 circuit_->ValueSelector(bb.numOfStatePreds - bb.numOfLoopBacks), MachineType::I64,
1078 inList.size(), inList.data(), GateType::AnyType());
1079 gateAcc_.NewIn(forwardValue, 0, bb.mergeForwardEdges);
1080 size_t forwardIndex = 1; // 1: start index of value inputs
1081 for (size_t i = 0; i < bb.numOfStatePreds; ++i) {
1082 auto &[predId, predBcIdx, isException] = bb.expandedPreds.at(i);
1083 if (!bb.loopbackBlocks.count(predId)) {
1084 gateAcc_.NewIn(forwardValue, forwardIndex++, ResolveDef(predId, predBcIdx, reg, acc));
1085 }
1086 }
1087 gateAcc_.NewIn(currentPhi, 1, forwardValue); // 1: index of forward value input
1088 gateAcc_.NewIn(currentPhi, 2, loopBackValue); // 2: index of loop-back value input
1089 }
1090 }
1091
1092 // recursive variables renaming algorithm
ResolveDef(const size_t bbId,int32_t bcId,const uint16_t reg,const bool acc)1093 GateRef BytecodeCircuitBuilder::ResolveDef(const size_t bbId, int32_t bcId, const uint16_t reg, const bool acc)
1094 {
1095 auto tmpReg = reg;
1096 // find def-site in bytecodes of basic block
1097 auto ans = Circuit::NullGate();
1098 auto &bb = graph_.at(bbId);
1099 GateType type = GateType::AnyType();
1100 auto tmpAcc = acc;
1101
1102 BytecodeIterator iterator(this, bb.start, bcId);
1103 for (iterator.Goto(bcId); !iterator.Done(); --iterator) {
1104 const BytecodeInfo& curInfo = iterator.GetBytecodeInfo();
1105 // original bc use acc as input && current bc use acc as output
1106 bool isTransByAcc = tmpAcc && curInfo.AccOut();
1107 // 0 : the index in vreg-out list
1108 bool isTransByVreg = (!tmpAcc && curInfo.IsOut(tmpReg, 0));
1109 if (isTransByAcc || isTransByVreg) {
1110 if (curInfo.IsMov()) {
1111 tmpAcc = curInfo.AccIn();
1112 if (!curInfo.inputs.empty()) {
1113 ASSERT(!tmpAcc);
1114 ASSERT(curInfo.inputs.size() == 1);
1115 tmpReg = std::get<VirtualRegister>(curInfo.inputs.at(0)).GetId();
1116 }
1117 if (HasTypes()) {
1118 type = typeRecorder_.UpdateType(iterator.Index(), type);
1119 }
1120 } else {
1121 ans = byteCodeToJSGate_.at(iterator.Index());
1122 auto oldType = gateAcc_.GetGateType(ans);
1123 if (HasTypes() && !type.IsAnyType() && oldType.IsAnyType()) {
1124 gateAcc_.SetGateType(ans, type);
1125 }
1126 break;
1127 }
1128 }
1129 if (curInfo.GetOpcode() != EcmaOpcode::RESUMEGENERATOR) {
1130 continue;
1131 }
1132 // New RESTORE_REGISTER HIR, used to restore the register content when processing resume instruction.
1133 // New SAVE_REGISTER HIR, used to save register content when processing suspend instruction.
1134 auto resumeGate = byteCodeToJSGate_.at(iterator.Index());
1135 ans = GetExistingRestore(resumeGate, tmpReg);
1136 if (ans != Circuit::NullGate()) {
1137 break;
1138 }
1139 GateRef resumeDependGate = gateAcc_.GetDep(resumeGate);
1140 ans = circuit_->NewGate(circuit_->RestoreRegister(tmpReg), MachineType::I64,
1141 { resumeDependGate }, GateType::AnyType());
1142 SetExistingRestore(resumeGate, tmpReg, ans);
1143 gateAcc_.SetDep(resumeGate, ans);
1144 auto saveRegGate = ResolveDef(bbId, iterator.Index() - 1, tmpReg, tmpAcc);
1145 ASSERT(Bytecodes::GetOpcode(iterator.PeekPrevPc(2)) == EcmaOpcode::SUSPENDGENERATOR_V8); // 2: prev bc
1146 GateRef suspendGate = byteCodeToJSGate_.at(iterator.Index() - 2); // 2: prev bc
1147 GateRef saveRegs = gateAcc_.GetDep(suspendGate);
1148 gateAcc_.ReplaceValueIn(saveRegs, saveRegGate, tmpReg);
1149 break;
1150 }
1151 // find GET_EXCEPTION gate if this is a catch block
1152 if (ans == Circuit::NullGate() && tmpAcc) {
1153 if (!bb.trys.empty()) {
1154 std::vector<GateRef> outList;
1155 gateAcc_.GetOuts(bb.dependStart, outList);
1156 ASSERT(outList.size() == 1);
1157 const auto &getExceptionGate = outList.at(0);
1158 ASSERT(gateAcc_.GetOpCode(getExceptionGate) == OpCode::GET_EXCEPTION);
1159 ans = getExceptionGate;
1160 }
1161 }
1162 // find def-site in value selectors of vregs
1163 if (ans == Circuit::NullGate() && !tmpAcc && bb.phi.count(tmpReg)) {
1164 if (!bb.vregToValSelectorGate.count(tmpReg)) {
1165 NewPhi(bb, tmpReg, tmpAcc, bb.vregToValSelectorGate[tmpReg]);
1166 }
1167 ans = bb.vregToValSelectorGate.at(tmpReg);
1168 }
1169 // find def-site in value selectors of acc
1170 if (ans == Circuit::NullGate() && tmpAcc && bb.phiAcc) {
1171 if (bb.valueSelectorAccGate == Circuit::NullGate()) {
1172 NewPhi(bb, tmpReg, tmpAcc, bb.valueSelectorAccGate);
1173 }
1174 ans = bb.valueSelectorAccGate;
1175 }
1176 if (ans == Circuit::NullGate() && IsEntryBlock(bbId)) { // entry block
1177 // find def-site in function args
1178 ASSERT(!tmpAcc);
1179 if (tmpReg == GetEnvVregIdx()) {
1180 ans = argAcc_.GetCommonArgGate(CommonArgIdx::LEXENV);
1181 } else {
1182 ans = argAcc_.GetArgGate(tmpReg);
1183 }
1184 return ans;
1185 }
1186 if (ans == Circuit::NullGate()) {
1187 // recursively find def-site in dominator block
1188 return ResolveDef(bb.iDominator->id, bb.iDominator->end, tmpReg, tmpAcc);
1189 } else {
1190 // def-site already found
1191 return ans;
1192 }
1193 }
1194
BuildCircuit()1195 void BytecodeCircuitBuilder::BuildCircuit()
1196 {
1197 // create arg gates array
1198 BuildCircuitArgs();
1199 CollectPredsInfo();
1200 BuildBlockCircuitHead();
1201 // build states sub-circuit of each block
1202 BuildSubCircuit();
1203 // verification of soundness of CFG
1204 for (auto &bb: graph_) {
1205 if (bb.isDead) {
1206 continue;
1207 }
1208 ASSERT(bb.statePredIndex == bb.numOfStatePreds);
1209 ASSERT(bb.loopBackIndex == bb.numOfLoopBacks);
1210 if (bb.numOfLoopBacks) {
1211 ASSERT(bb.forwardIndex == bb.numOfStatePreds - bb.numOfLoopBacks);
1212 }
1213 // resolve def-site of virtual regs and set all value inputs
1214 EnumerateBlock(bb, [&](const BytecodeInfo &bytecodeInfo) -> bool {
1215 auto &iterator = bb.GetBytecodeIterator();
1216 const auto bcIndex = iterator.Index();
1217 const auto bbIndex = bb.id;
1218 GateRef gate = GetGateByBcIndex(bcIndex);
1219 if (gate == Circuit::NullGate()) {
1220 return true;
1221 }
1222 if (gateAcc_.IsConstant(gate)) {
1223 return true;
1224 }
1225
1226 if (HasTypes()) {
1227 auto type = typeRecorder_.GetType(bcIndex);
1228 if (!type.IsAnyType()) {
1229 gateAcc_.SetGateType(gate, type);
1230 }
1231 }
1232 auto valueCount = gateAcc_.GetInValueCount(gate);
1233 [[maybe_unused]] size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
1234 [[maybe_unused]] size_t numValueOutputs = bytecodeInfo.ComputeOutCount();
1235 ASSERT(numValueInputs == valueCount);
1236 ASSERT(numValueOutputs <= 1 + (bytecodeInfo.EnvOut() ? 1 : 0));
1237 auto valueStarts = gateAcc_.GetInValueStarts(gate);
1238 for (size_t valueIdx = 0; valueIdx < valueCount; valueIdx++) {
1239 auto inIdx = valueIdx + valueStarts;
1240 if (!gateAcc_.IsInGateNull(gate, inIdx)) {
1241 continue;
1242 }
1243 if (valueIdx < bytecodeInfo.inputs.size()) {
1244 auto vregId = std::get<VirtualRegister>(bytecodeInfo.inputs.at(valueIdx)).GetId();
1245 GateRef defVreg = Circuit::NullGate();
1246 if (IsFirstBCEnvIn(bbIndex, bcIndex, vregId)) {
1247 defVreg = argAcc_.GetCommonArgGate(CommonArgIdx::LEXENV);
1248 } else {
1249 defVreg = ResolveDef(bbIndex, bcIndex - 1, vregId, false);
1250 }
1251 gateAcc_.NewIn(gate, inIdx, defVreg);
1252 } else {
1253 GateRef defAcc = ResolveDef(bbIndex, bcIndex - 1, 0, true);
1254 gateAcc_.NewIn(gate, inIdx, defAcc);
1255 }
1256 }
1257 return true;
1258 });
1259 }
1260
1261 if (IsTypeLoweringEnabled()) {
1262 frameStateBuilder_.BuildFrameState();
1263 }
1264
1265 if (IsLogEnabled()) {
1266 PrintGraph("Bytecode2Gate");
1267 LOG_COMPILER(INFO) << "\033[34m" << "============= "
1268 << "After bytecode2circuit lowering ["
1269 << methodName_ << "]"
1270 << " =============" << "\033[0m";
1271 circuit_->PrintAllGatesWithBytecode();
1272 LOG_COMPILER(INFO) << "\033[34m" << "=========================== End ===========================" << "\033[0m";
1273 }
1274 }
1275
GetExistingRestore(GateRef resumeGate,uint16_t tmpReg) const1276 GateRef BytecodeCircuitBuilder::GetExistingRestore(GateRef resumeGate, uint16_t tmpReg) const
1277 {
1278 auto pr = std::make_pair(resumeGate, tmpReg);
1279 if (resumeRegToRestore_.count(pr)) {
1280 return resumeRegToRestore_.at(pr);
1281 }
1282 return Circuit::NullGate();
1283 }
1284
SetExistingRestore(GateRef resumeGate,uint16_t tmpReg,GateRef restoreGate)1285 void BytecodeCircuitBuilder::SetExistingRestore(GateRef resumeGate, uint16_t tmpReg, GateRef restoreGate)
1286 {
1287 auto pr = std::make_pair(resumeGate, tmpReg);
1288 resumeRegToRestore_[pr] = restoreGate;
1289 }
1290
PrintGraph(const char * title)1291 void BytecodeCircuitBuilder::PrintGraph(const char* title)
1292 {
1293 LOG_COMPILER(INFO) << "======================== " << title << " ========================";
1294 for (size_t i = 0; i < graph_.size(); i++) {
1295 BytecodeRegion& bb = graph_[i];
1296 if (bb.isDead) {
1297 LOG_COMPILER(INFO) << "B" << bb.id << ": ;preds= invalid BB";
1298 LOG_COMPILER(INFO) << "\tBytecodePC: [" << std::to_string(bb.start) << ", "
1299 << std::to_string(bb.end) << ")";
1300 continue;
1301 }
1302 std::string log("B" + std::to_string(bb.id) + ": ;preds= ");
1303 for (size_t k = 0; k < bb.preds.size(); ++k) {
1304 log += std::to_string(bb.preds[k]->id) + ", ";
1305 }
1306 LOG_COMPILER(INFO) << log;
1307 LOG_COMPILER(INFO) << "\tBytecodePC: [" << std::to_string(bb.start) << ", "
1308 << std::to_string(bb.end) << ")";
1309
1310 std::string log1("\tSucces: ");
1311 for (size_t j = 0; j < bb.succs.size(); j++) {
1312 log1 += std::to_string(bb.succs[j]->id) + ", ";
1313 }
1314 LOG_COMPILER(INFO) << log1;
1315
1316 for (size_t j = 0; j < bb.catchs.size(); j++) {
1317 LOG_COMPILER(INFO) << "\tcatch [: " << std::to_string(bb.catchs[j]->start) << ", "
1318 << std::to_string(bb.catchs[j]->end) << ")";
1319 }
1320
1321 std::string log2("\tTrys: ");
1322 for (auto tryBlock: bb.trys) {
1323 log2 += std::to_string(tryBlock->id) + " , ";
1324 }
1325 LOG_COMPILER(INFO) << log2;
1326
1327 std::string log3 = "\tDom: ";
1328 for (size_t j = 0; j < bb.immDomBlocks.size(); j++) {
1329 log3 += "B" + std::to_string(bb.immDomBlocks[j]->id) + std::string(", ");
1330 }
1331 LOG_COMPILER(INFO) << log3;
1332
1333 if (bb.iDominator) {
1334 LOG_COMPILER(INFO) << "\tIDom B" << bb.iDominator->id;
1335 }
1336
1337 std::string log4("\tDom Frontiers: ");
1338 for (const auto &frontier: bb.domFrontiers) {
1339 log4 += std::to_string(frontier->id) + " , ";
1340 }
1341 LOG_COMPILER(INFO) << log4;
1342
1343 std::string log5("\tPhi: ");
1344 for (auto variable: bb.phi) {
1345 log5 += std::to_string(variable) + " , ";
1346 }
1347 LOG_COMPILER(INFO) << log5;
1348
1349 PrintBytecodeInfo(bb);
1350 LOG_COMPILER(INFO) << "";
1351 }
1352 }
1353
PrintBytecodeInfo(BytecodeRegion & bb)1354 void BytecodeCircuitBuilder::PrintBytecodeInfo(BytecodeRegion& bb)
1355 {
1356 if (bb.isDead) {
1357 return;
1358 }
1359 LOG_COMPILER(INFO) << "\tBytecode[] = ";
1360 EnumerateBlock(bb, [&](const BytecodeInfo &bytecodeInfo) -> bool {
1361 auto &iterator = bb.GetBytecodeIterator();
1362 std::string log;
1363 log += std::string("\t\t< ") + std::to_string(iterator.Index()) + ": ";
1364 log += GetEcmaOpcodeStr(iterator.GetBytecodeInfo().GetOpcode()) + ", " + "In=[";
1365 if (bytecodeInfo.AccIn()) {
1366 log += "acc,";
1367 }
1368 for (const auto &in: bytecodeInfo.inputs) {
1369 if (std::holds_alternative<VirtualRegister>(in)) {
1370 log += std::to_string(std::get<VirtualRegister>(in).GetId()) + ",";
1371 }
1372 }
1373 log += "], Out=[";
1374 if (bytecodeInfo.AccOut()) {
1375 log += "acc,";
1376 }
1377 for (const auto &out: bytecodeInfo.vregOut) {
1378 log += std::to_string(out) + ",";
1379 }
1380 log += "] >";
1381 LOG_COMPILER(INFO) << log;
1382
1383 auto gate = byteCodeToJSGate_[iterator.Index()];
1384 if (gate != Circuit::NullGate()) {
1385 this->gateAcc_.ShortPrint(gate);
1386 }
1387 return true;
1388 });
1389 }
1390 } // namespace panda::ecmascript::kungfu
1391