1 /*
2 * Copyright (c) 2021-2024 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 <algorithm>
19 #include <cstddef>
20
21 #include "ecmascript/base/number_helper.h"
22 #include "ecmascript/compiler/gate_accessor.h"
23 #include "ecmascript/deoptimizer/deoptimizer.h"
24 #include "ecmascript/interpreter/interpreter-inl.h"
25 #include "libpandafile/bytecode_instruction-inl.h"
26
27
28 namespace panda::ecmascript::kungfu {
BytecodeToCircuit()29 void BytecodeCircuitBuilder::BytecodeToCircuit()
30 {
31 ExceptionInfo exceptionInfo = {};
32
33 // collect try catch block info
34 CollectTryCatchBlockInfo(exceptionInfo);
35 hasTryCatch_ = exceptionInfo.size() != 0;
36 BuildRegionInfo();
37 // Building the basic block diagram of bytecode
38 BuildRegions(exceptionInfo);
39 }
40
BuildRegionInfo()41 void BytecodeCircuitBuilder::BuildRegionInfo()
42 {
43 uint32_t size = pcOffsets_.size();
44 ASSERT(size > 0);
45 uint32_t end = size - 1; // 1: end
46 BytecodeIterator iterator(this, 0, end);
47
48 infoData_.resize(size);
49 byteCodeToJSGates_.resize(size, std::vector<GateRef>(0));
50 regionsInfo_.InsertHead(0); // 0: start pc
51 iterator.GotoStart();
52 while (!iterator.Done()) {
53 auto index = iterator.Index();
54 auto &info = infoData_[index];
55 auto pc = pcOffsets_[index];
56 info.metaData_ = bytecodes_->GetBytecodeMetaData(pc);
57 ASSERT(!info.metaData_.IsInvalid());
58 BytecodeInfo::InitBytecodeInfo(this, info, pc);
59 CollectRegionInfo(index);
60 ++iterator;
61 }
62 }
63
CollectRegionInfo(uint32_t bcIndex)64 void BytecodeCircuitBuilder::CollectRegionInfo(uint32_t bcIndex)
65 {
66 auto pc = pcOffsets_[bcIndex];
67 auto &info = infoData_[bcIndex];
68 int32_t offset = 0;
69 if (info.IsJump()) {
70 switch (info.GetOpcode()) {
71 case EcmaOpcode::JEQZ_IMM8:
72 case EcmaOpcode::JNEZ_IMM8:
73 case EcmaOpcode::JMP_IMM8:
74 offset = static_cast<int8_t>(READ_INST_8_0());
75 break;
76 case EcmaOpcode::JNEZ_IMM16:
77 case EcmaOpcode::JEQZ_IMM16:
78 case EcmaOpcode::JMP_IMM16:
79 offset = static_cast<int16_t>(READ_INST_16_0());
80 break;
81 case EcmaOpcode::JMP_IMM32:
82 case EcmaOpcode::JNEZ_IMM32:
83 case EcmaOpcode::JEQZ_IMM32:
84 offset = static_cast<int32_t>(READ_INST_32_0());
85 break;
86 default:
87 LOG_ECMA(FATAL) << "this branch is unreachable";
88 UNREACHABLE();
89 break;
90 }
91 auto nextIndex = bcIndex + 1; // 1: next pc
92 auto targetIndex = FindBcIndexByPc(pc + offset);
93 auto it = candidateEmptyCatch_.find(targetIndex);
94 if (it != candidateEmptyCatch_.end()) {
95 it->second = true;
96 }
97 // condition branch current basic block end
98 if (info.IsCondJump()) {
99 regionsInfo_.InsertSplit(nextIndex);
100 regionsInfo_.InsertJump(targetIndex, bcIndex, false);
101 } else {
102 if (bcIndex != GetLastBcIndex()) {
103 regionsInfo_.InsertHead(nextIndex);
104 }
105 regionsInfo_.InsertJump(targetIndex, bcIndex, true);
106 }
107 } else if (info.IsReturn() || info.IsThrow()) {
108 if (bcIndex != GetLastBcIndex()) {
109 auto nextIndex = bcIndex + 1; // 1: next pc
110 regionsInfo_.InsertHead(nextIndex);
111 }
112 }
113 }
114
CollectTryCatchBlockInfo(ExceptionInfo & byteCodeException)115 void BytecodeCircuitBuilder::CollectTryCatchBlockInfo(ExceptionInfo &byteCodeException)
116 {
117 auto pf = file_->GetPandaFile();
118 panda_file::MethodDataAccessor mda(*pf, method_->GetMethodId());
119 panda_file::CodeDataAccessor cda(*pf, mda.GetCodeId().value());
120
121 cda.EnumerateTryBlocks([this, &byteCodeException](
122 panda_file::CodeDataAccessor::TryBlock &tryBlock) {
123 auto tryStartOffset = tryBlock.GetStartPc();
124 auto tryEndOffset = tryBlock.GetStartPc() + tryBlock.GetLength();
125
126 auto tryStartPc = const_cast<uint8_t *>(method_->GetBytecodeArray() + tryStartOffset);
127 auto tryEndPc = const_cast<uint8_t *>(method_->GetBytecodeArray() + tryEndOffset);
128 // skip try blocks with same pc in start and end label
129 if (tryStartPc == tryEndPc) {
130 return true;
131 }
132
133 auto tryStartBcIndex = FindBcIndexByPc(tryStartPc);
134 regionsInfo_.InsertSplit(tryStartBcIndex);
135 if (tryEndPc <= GetLastPC()) {
136 auto tryEndBcIndex = FindBcIndexByPc(tryEndPc);
137 regionsInfo_.InsertSplit(tryEndBcIndex);
138 }
139 byteCodeException.emplace_back(ExceptionItem { tryStartPc, tryEndPc, {} });
140 tryBlock.EnumerateCatchBlocks([&](panda_file::CodeDataAccessor::CatchBlock &catchBlock) {
141 auto pcOffset = catchBlock.GetHandlerPc();
142 auto catchBlockPc = const_cast<uint8_t *>(method_->GetBytecodeArray() + pcOffset);
143 auto catchBlockBcIndex = FindBcIndexByPc(catchBlockPc);
144 candidateEmptyCatch_.insert(std::pair<uint32_t, bool>(catchBlockBcIndex, false));
145 regionsInfo_.InsertHead(catchBlockBcIndex);
146 // try block associate catch block
147 byteCodeException.back().catches.emplace_back(catchBlockPc);
148 return true;
149 });
150 return true;
151 });
152 }
153
IsAncestor(size_t nodeA,size_t nodeB)154 bool BytecodeCircuitBuilder::IsAncestor(size_t nodeA, size_t nodeB)
155 {
156 return timeIn_[bbIdToDfsTimestamp_[nodeA]] <= timeIn_[bbIdToDfsTimestamp_[nodeB]] &&
157 timeOut_[bbIdToDfsTimestamp_[nodeA]] >= timeOut_[bbIdToDfsTimestamp_[nodeB]];
158 }
159
PerformDFS(const std::vector<size_t> & immDom,size_t listSize)160 void BytecodeCircuitBuilder::PerformDFS(const std::vector<size_t> &immDom, size_t listSize)
161 {
162 std::vector<std::vector<size_t>> sonList(listSize);
163 for (size_t idx = 1; idx < immDom.size(); idx++) {
164 sonList[immDom[idx]].push_back(idx);
165 }
166
167 {
168 size_t timestamp = 0;
169 struct DFSState {
170 size_t cur;
171 std::vector<size_t> &succList;
172 size_t idx;
173 };
174 std::stack<DFSState> dfsStack;
175 size_t root = 0;
176 dfsStack.push({root, sonList[root], 0});
177 timeIn_[root] = timestamp++;
178 while (!dfsStack.empty()) {
179 auto &curState = dfsStack.top();
180 auto &cur = curState.cur;
181 auto &succList = curState.succList;
182 auto &idx = curState.idx;
183 if (idx == succList.size()) {
184 timeOut_[cur] = timestamp++;
185 dfsStack.pop();
186 continue;
187 }
188 const auto &succ = succList[idx];
189 dfsStack.push({succ, sonList[succ], 0});
190 timeIn_[succ] = timestamp++;
191 idx++;
192 }
193 }
194 }
195
196
ReducibilityCheck()197 void BytecodeCircuitBuilder::ReducibilityCheck()
198 {
199 std::vector<size_t> basicBlockList;
200 std::vector<size_t> immDom;
201 std::unordered_map<size_t, size_t> bbDfsTimestampToIdx;
202 ComputeDominatorTree(basicBlockList, immDom, bbDfsTimestampToIdx);
203 timeIn_.resize(basicBlockList.size());
204 timeOut_.resize(basicBlockList.size());
205 PerformDFS(immDom, basicBlockList.size());
206 }
207
ComputeImmediateDominators(const std::vector<size_t> & basicBlockList,std::unordered_map<size_t,size_t> & dfsFatherIdx,std::vector<size_t> & immDom,std::unordered_map<size_t,size_t> & bbDfsTimestampToIdx)208 void BytecodeCircuitBuilder::ComputeImmediateDominators(const std::vector<size_t> &basicBlockList,
209 std::unordered_map<size_t, size_t> &dfsFatherIdx,
210 std::vector<size_t> &immDom,
211 std::unordered_map<size_t, size_t> &bbDfsTimestampToIdx)
212 {
213 std::vector<size_t> semiDom(basicBlockList.size());
214 std::vector<std::vector<size_t> > semiDomTree(basicBlockList.size());
215 {
216 std::vector<size_t> parent(basicBlockList.size());
217 std::iota(parent.begin(), parent.end(), 0);
218 std::vector<size_t> minIdx(basicBlockList.size());
219 std::function<size_t(size_t)> unionFind = [&] (size_t idx) -> size_t {
220 if (parent[idx] == idx) return idx;
221 size_t unionFindSetRoot = unionFind(parent[idx]);
222 if (semiDom[minIdx[idx]] > semiDom[minIdx[parent[idx]]]) {
223 minIdx[idx] = minIdx[parent[idx]];
224 }
225 return parent[idx] = unionFindSetRoot;
226 };
227 auto merge = [&] (size_t fatherIdx, size_t sonIdx) -> void {
228 size_t parentFatherIdx = unionFind(fatherIdx);
229 size_t parentSonIdx = unionFind(sonIdx);
230 parent[parentSonIdx] = parentFatherIdx;
231 };
232 auto calculateSemiDom = [&](size_t idx, const ChunkVector<BytecodeRegion *> &blocks) {
233 for (const auto &preBlock : blocks) {
234 if (bbDfsTimestampToIdx[preBlock->id] < idx) {
235 semiDom[idx] = std::min(semiDom[idx], bbDfsTimestampToIdx[preBlock->id]);
236 } else {
237 unionFind(bbDfsTimestampToIdx[preBlock->id]);
238 semiDom[idx] = std::min(semiDom[idx], semiDom[minIdx[bbDfsTimestampToIdx[preBlock->id]]]);
239 }
240 }
241 };
242 std::iota(semiDom.begin(), semiDom.end(), 0);
243 semiDom[0] = semiDom.size();
244 for (size_t idx = basicBlockList.size() - 1; idx >= 1; idx--) {
245 calculateSemiDom(idx, graph_[basicBlockList[idx]]->preds);
246 if (!graph_[basicBlockList[idx]]->trys.empty()) {
247 calculateSemiDom(idx, graph_[basicBlockList[idx]]->trys);
248 }
249 for (const auto &succDomIdx : semiDomTree[idx]) {
250 unionFind(succDomIdx);
251 if (idx == semiDom[minIdx[succDomIdx]]) {
252 immDom[succDomIdx] = idx;
253 } else {
254 immDom[succDomIdx] = minIdx[succDomIdx];
255 }
256 }
257 minIdx[idx] = idx;
258 merge(dfsFatherIdx[basicBlockList[idx]], idx);
259 semiDomTree[semiDom[idx]].emplace_back(idx);
260 }
261 for (size_t idx = 1; idx < basicBlockList.size(); idx++) {
262 if (immDom[idx] != semiDom[idx]) {
263 immDom[idx] = immDom[immDom[idx]];
264 }
265 }
266 semiDom[0] = 0;
267 }
268 }
269
ComputeDominatorTree(std::vector<size_t> & basicBlockList,std::vector<size_t> & immDom,std::unordered_map<size_t,size_t> & bbDfsTimestampToIdx)270 void BytecodeCircuitBuilder::ComputeDominatorTree(std::vector<size_t> &basicBlockList, std::vector<size_t> &immDom,
271 std::unordered_map<size_t, size_t> &bbDfsTimestampToIdx)
272 {
273 std::unordered_map<size_t, size_t> dfsFatherIdx;
274 size_t timestamp = 0;
275 std::deque<size_t> pendingList;
276 std::vector<size_t> visited(graph_.size(), 0);
277 auto basicBlockId = graph_[0]->id;
278 visited[graph_[0]->id] = 1;
279 pendingList.emplace_back(basicBlockId);
280
281 auto visitConnectedBlocks = [&](const ChunkVector<BytecodeRegion *> &succs, size_t curBlockId) {
282 for (const auto &succBlock : succs) {
283 if (visited[succBlock->id] == 0) {
284 visited[succBlock->id] = 1;
285 pendingList.emplace_back(succBlock->id);
286 dfsFatherIdx[succBlock->id] = bbIdToDfsTimestamp_[curBlockId];
287 }
288 }
289 };
290
291 while (!pendingList.empty()) {
292 size_t curBlockId = pendingList.back();
293 pendingList.pop_back();
294 basicBlockList.emplace_back(curBlockId);
295 bbIdToDfsTimestamp_[curBlockId] = timestamp++;
296 visitConnectedBlocks(graph_[curBlockId]->succs, curBlockId);
297 if (!graph_[curBlockId]->catches.empty()) {
298 visitConnectedBlocks(graph_[curBlockId]->catches, curBlockId);
299 }
300 }
301 for (size_t idx = 0; idx < basicBlockList.size(); idx++) {
302 bbDfsTimestampToIdx[basicBlockList[idx]] = idx;
303 }
304
305 immDom.resize(basicBlockList.size());
306 ComputeImmediateDominators(basicBlockList, dfsFatherIdx, immDom, bbDfsTimestampToIdx);
307 }
308
BuildEntryBlock()309 void BytecodeCircuitBuilder::BuildEntryBlock()
310 {
311 BytecodeRegion &entryBlock = RegionAt(0);
312 BytecodeRegion &nextBlock = RegionAt(1);
313 entryBlock.succs.emplace_back(&nextBlock);
314 nextBlock.preds.emplace_back(&entryBlock);
315 entryBlock.bytecodeIterator_.Reset(this, 0, BytecodeIterator::INVALID_INDEX);
316 }
317
BuildBasicBlock()318 void BytecodeCircuitBuilder::BuildBasicBlock()
319 {
320 auto &items = regionsInfo_.GetBlockItems();
321 size_t blockId = 1;
322 for (const auto &item : items) {
323 auto &curBlock = GetBasicBlockById(blockId);
324 curBlock.id = blockId;
325 curBlock.start = item.GetStartBcIndex();
326 if (blockId != 1) {
327 auto &prevBlock = RegionAt(blockId - 1);
328 ASSERT(curBlock.start >= 1);
329 prevBlock.end = curBlock.start - 1;
330 prevBlock.bytecodeIterator_.Reset(this, prevBlock.start, prevBlock.end);
331 // fall through
332 if (!item.IsHeadBlock()) {
333 curBlock.preds.emplace_back(&prevBlock);
334 prevBlock.succs.emplace_back(&curBlock);
335 }
336 }
337 blockId++;
338 }
339 auto &lastBlock = RegionAt(blockId - 1); // 1: last block
340 lastBlock.end = GetLastBcIndex();
341 lastBlock.bytecodeIterator_.Reset(this, lastBlock.start, lastBlock.end);
342 }
343
BuildRegions(const ExceptionInfo & byteCodeException)344 void BytecodeCircuitBuilder::BuildRegions(const ExceptionInfo &byteCodeException)
345 {
346 auto blockSize = regionsInfo_.GetBlockItems().size();
347
348 // 1 : entry block. if the loop head is in the first bb block, the variables used in the head cannot correctly
349 // generate Phi nodes through the dominator-tree algorithm, resulting in an infinite loop. Therefore, an empty
350 // BB block is generated as an entry block
351 graph_.resize(blockSize + 1, nullptr);
352 for (size_t i = 0; i < graph_.size(); i++) {
353 graph_[i] = circuit_->chunk()->New<BytecodeRegion>(circuit_->chunk());
354 }
355
356 // build entry block
357 BuildEntryBlock();
358
359 // build basic block
360 BuildBasicBlock();
361
362 auto &splitItems = regionsInfo_.GetSplitItems();
363 for (const auto &item : splitItems) {
364 auto curIndex = regionsInfo_.FindBBIndexByBcIndex(item.startBcIndex);
365 auto &curBlock = GetBasicBlockById(curIndex);
366 auto predIndex = regionsInfo_.FindBBIndexByBcIndex(item.predBcIndex);
367 auto &predBlock = GetBasicBlockById(predIndex);
368 curBlock.preds.emplace_back(&predBlock);
369 predBlock.succs.emplace_back(&curBlock);
370 }
371
372 if (byteCodeException.size() != 0) {
373 BuildCatchBlocks(byteCodeException);
374 }
375 UpdateCFG();
376 if (HasTryCatch()) {
377 CollectTryPredsInfo();
378 }
379 RemoveUnreachableRegion();
380 if (NeedIrreducibleLoopCheck()) {
381 ReducibilityCheck();
382 }
383 if (IsLogEnabled() && !IsPreAnalysis()) {
384 PrintGraph(std::string("Update CFG [" + methodName_ + "]").c_str());
385 }
386 BuildCircuit();
387 }
388
UpdateEmptyCatchBB()389 void BytecodeCircuitBuilder::UpdateEmptyCatchBB()
390 {
391 for (size_t i = 0; i < graph_.size(); i++) {
392 auto &bb = RegionAt(i);
393 auto it = candidateEmptyCatch_.find(bb.start);
394 if (it != candidateEmptyCatch_.end()) {
395 if (it->second) {
396 bb.IsEmptyCatchBB = true;
397 hasEmptyCatchBB_ = true;
398 }
399 }
400 }
401 }
402
BuildCatchBlocks(const ExceptionInfo & byteCodeException)403 void BytecodeCircuitBuilder::BuildCatchBlocks(const ExceptionInfo &byteCodeException)
404 {
405 // try catch block associate
406 for (size_t i = 0; i < graph_.size(); i++) {
407 auto &bb = RegionAt(i);
408 auto startIndex = bb.start;
409 bool noThrow = true;
410 EnumerateBlock(bb, [&noThrow](const BytecodeInfo &bytecodeInfo) -> bool {
411 if (bytecodeInfo.IsGeneral()) {
412 if (!bytecodeInfo.NoThrow()) {
413 noThrow = false;
414 return false;
415 }
416 }
417 return true;
418 });
419 if (noThrow) {
420 continue;
421 }
422 const auto pc = pcOffsets_[startIndex];
423 for (auto it = byteCodeException.cbegin(); it != byteCodeException.cend(); it++) {
424 if (pc < it->startPc || pc >= it->endPc) {
425 continue;
426 }
427 // try block interval
428 const auto &catches = it->catches; // catches start pc
429 for (size_t j = i + 1; j < graph_.size(); j++) {
430 auto &catchBB = RegionAt(j);
431 const auto catchStart = pcOffsets_[catchBB.start];
432 if (std::find(catches.cbegin(), catches.cend(), catchStart) != catches.cend()) {
433 bb.catches.insert(bb.catches.cbegin(), &catchBB);
434 }
435 }
436 }
437
438 // When there are multiple catch blocks in the current block, the set of catch blocks
439 // needs to be sorted to satisfy the order of execution of catch blocks.
440 bb.SortCatches();
441 }
442 }
443
CollectTryPredsInfo()444 void BytecodeCircuitBuilder::CollectTryPredsInfo()
445 {
446 for (size_t i = 0; i < graph_.size(); i++) {
447 auto &bb = RegionAt(i);
448 if (bb.catches.empty()) {
449 continue;
450 } else if (bb.catches.size() > 1) { // 1: cache size
451 for (auto it = bb.catches.begin() + 1; it != bb.catches.end();) { // 1: invalid catch bb
452 bb.EraseThisBlock((*it)->trys);
453 it = bb.catches.erase(it);
454 }
455 }
456
457 EnumerateBlock(bb, [&bb](const BytecodeInfo &bytecodeInfo) -> bool {
458 if (bytecodeInfo.IsGeneral()) {
459 // if block which can throw exception has serval catchs block,
460 // only the innermost catch block is useful
461 ASSERT(bb.catches.size() == 1); // 1: cache size
462 if (!bytecodeInfo.NoThrow()) {
463 bb.catches.at(0)->numOfStatePreds++;
464 }
465 }
466 return true;
467 });
468 }
469 }
470
RemoveUnusedPredsInfo(BytecodeRegion & bb)471 void BytecodeCircuitBuilder::RemoveUnusedPredsInfo(BytecodeRegion& bb)
472 {
473 EnumerateBlock(bb, [&bb](const BytecodeInfo &bytecodeInfo) -> bool {
474 if (bytecodeInfo.IsGeneral()) {
475 ASSERT(bb.catches.size() == 1); // 1: cache size
476 if (!bytecodeInfo.NoThrow()) {
477 bb.catches.at(0)->numOfStatePreds--;
478 }
479 }
480 return true;
481 });
482 }
483
ClearUnreachableRegion(ChunkVector<BytecodeRegion * > & pendingList)484 void BytecodeCircuitBuilder::ClearUnreachableRegion(ChunkVector<BytecodeRegion*>& pendingList)
485 {
486 auto bb = pendingList.back();
487 pendingList.pop_back();
488 for (auto it = bb->preds.begin(); it != bb->preds.end(); it++) {
489 ASSERT((*it)->numOfStatePreds >= 0);
490 if ((*it)->numOfStatePreds != 0) {
491 bb->EraseThisBlock((*it)->succs);
492 }
493 }
494 for (auto it = bb->succs.begin(); it != bb->succs.end(); it++) {
495 auto bbNext = *it;
496 ASSERT(bbNext->numOfStatePreds >= 0);
497 if (bbNext->numOfStatePreds != 0) {
498 bb->EraseThisBlock(bbNext->preds);
499 bbNext->numOfStatePreds--;
500 if (bbNext->numOfStatePreds == 0) {
501 pendingList.emplace_back(bbNext);
502 }
503 }
504 }
505 for (auto it = bb->trys.begin(); it != bb->trys.end(); it++) {
506 ASSERT((*it)->numOfStatePreds >= 0);
507 if ((*it)->numOfStatePreds != 0) {
508 bb->EraseThisBlock((*it)->catches);
509 }
510 }
511 for (auto it = bb->catches.begin(); it != bb->catches.end(); it++) {
512 auto bbNext = *it;
513 ASSERT(bbNext->numOfStatePreds >= 0);
514 if (bbNext->numOfStatePreds != 0) {
515 RemoveUnusedPredsInfo(*bb);
516 bb->EraseThisBlock(bbNext->trys);
517 if (bbNext->numOfStatePreds == 0) {
518 pendingList.emplace_back(bbNext);
519 }
520 }
521 }
522 bb->preds.clear();
523 bb->succs.clear();
524 bb->trys.clear();
525 bb->catches.clear();
526 numOfLiveBB_--;
527
528 RemoveIfInRpoList(bb);
529 }
530
RemoveIfInRpoList(BytecodeRegion * bb)531 void BytecodeCircuitBuilder::RemoveIfInRpoList(BytecodeRegion *bb)
532 {
533 auto& rpoList = frameStateBuilder_.GetRpoList();
534 for (auto iter = rpoList.begin(); iter != rpoList.end(); iter++) {
535 if (*iter == bb->id) {
536 rpoList.erase(iter);
537 break;
538 }
539 }
540 }
541
RemoveUnreachableRegion()542 void BytecodeCircuitBuilder::RemoveUnreachableRegion()
543 {
544 numOfLiveBB_ = graph_.size();
545 ChunkVector<BytecodeRegion*> pendingList(circuit_->chunk());
546 for (size_t i = 1; i < graph_.size(); i++) { // 1: skip entry bb
547 auto &bb = RegionAt(i);
548 ASSERT(bb.numOfStatePreds >= 0);
549 if (bb.numOfStatePreds == 0) {
550 pendingList.emplace_back(&bb);
551 }
552 }
553 while (!pendingList.empty()) {
554 ClearUnreachableRegion(pendingList);
555 }
556 }
557
ComputeNumOfLoopBack()558 void BytecodeCircuitBuilder::ComputeNumOfLoopBack()
559 {
560 for (size_t i = 0; i < graph_.size(); i++) {
561 auto &bb = RegionAt(i);
562 if (!IsEntryBlock(bb.id) && bb.numOfStatePreds == 0) {
563 continue;
564 }
565 for (auto &succ: bb.succs) {
566 if (succ->IsLoopBack(bb)) {
567 succ->numOfLoopBack++;
568 }
569 }
570 if (bb.catches.empty()) {
571 continue;
572 }
573
574 EnumerateBlock(bb, [&bb](const BytecodeInfo &bytecodeInfo) -> bool {
575 if (bytecodeInfo.IsGeneral() && !bytecodeInfo.NoThrow() && bb.catches.at(0)->IsLoopBack(bb)) {
576 // if block which can throw exception has serval catchs block,
577 // only the innermost catch block is useful
578 ASSERT(bb.catches.size() == 1); // 1: cache size
579 bb.catches.at(0)->numOfLoopBack++;
580 }
581 return true;
582 });
583 }
584 }
585 // Update CFG's predecessor, successor and try catch associations
UpdateCFG()586 void BytecodeCircuitBuilder::UpdateCFG()
587 {
588 for (size_t i = 0; i < graph_.size(); i++) {
589 auto &bb = RegionAt(i);
590 bb.preds.clear();
591 bb.trys.clear();
592 ChunkVector<BytecodeRegion *> newSuccs(circuit_->chunk());
593 for (const auto &succ: bb.succs) {
594 newSuccs.emplace_back(succ);
595 }
596 bb.succs.clear();
597 bb.succs.insert(bb.succs.end(), newSuccs.begin(), newSuccs.end());
598 }
599 for (size_t i = 0; i < graph_.size(); i++) {
600 auto &bb = RegionAt(i);
601 for (auto &succ: bb.succs) {
602 succ->preds.emplace_back(&bb);
603 succ->numOfStatePreds++;
604 }
605 for (auto &catchBlock: bb.catches) {
606 catchBlock->trys.emplace_back(&bb);
607 }
608 }
609 UpdateEmptyCatchBB();
610 }
611
612 // build circuit
BuildCircuitArgs()613 void BytecodeCircuitBuilder::BuildCircuitArgs()
614 {
615 argAcc_.NewCommonArg(CommonArgIdx::GLUE, MachineType::I64, GateType::NJSValue());
616 if (!method_->IsFastCall()) {
617 argAcc_.NewCommonArg(CommonArgIdx::ACTUAL_ARGC, MachineType::I64, GateType::NJSValue());
618 argAcc_.NewCommonArg(CommonArgIdx::ACTUAL_ARGV, MachineType::ARCH, GateType::NJSValue());
619 auto funcIdx = static_cast<size_t>(CommonArgIdx::FUNC);
620 const size_t actualNumArgs = argAcc_.GetActualNumArgs();
621 // new actual argument gates
622 for (size_t argIdx = funcIdx; argIdx < actualNumArgs; argIdx++) {
623 argAcc_.NewArg(argIdx);
624 }
625 } else {
626 auto funcIdx = static_cast<size_t>(FastCallArgIdx::FUNC);
627 size_t actualNumArgs = static_cast<size_t>(FastCallArgIdx::NUM_OF_ARGS) + method_->GetNumArgsWithCallField();
628 for (size_t argIdx = funcIdx; argIdx < actualNumArgs; argIdx++) {
629 argAcc_.NewArg(argIdx);
630 }
631 }
632 argAcc_.CollectArgs();
633 BuildFrameArgs();
634 }
635
BuildFrameArgs()636 void BytecodeCircuitBuilder::BuildFrameArgs()
637 {
638 UInt32PairAccessor accessor(0, 0);
639 auto metaData = circuit_->FrameArgs(accessor.ToValue());
640 size_t numArgs = metaData->GetNumIns();
641 std::vector<GateRef> args(numArgs, Circuit::NullGate());
642 size_t idx = 0;
643 args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::FUNC);
644 args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::NEW_TARGET);
645 args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::THIS_OBJECT);
646 args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::ACTUAL_ARGC);
647 args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::ACTUAL_ARGV);
648 GateRef sharedConstpool = Circuit::NullGate();
649 GateRef unSharedConstpool = Circuit::NullGate();
650 GetCurrentConstpool(argAcc_.GetCommonArgGate(CommonArgIdx::FUNC), sharedConstpool, unSharedConstpool);
651 args[idx++] = sharedConstpool;
652 args[idx++] = unSharedConstpool;
653 args[idx++] = GetPreFrameArgs();
654 GateRef frameArgs = circuit_->NewGate(metaData, args);
655 argAcc_.SetFrameArgs(frameArgs);
656 }
657
BuildOSRArgs()658 void BytecodeCircuitBuilder::BuildOSRArgs()
659 {
660 // offset -1 : glue
661 (void)circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_GLUE), MachineType::I64,
662 {circuit_->GetArgRoot()}, GateType::NJSValue());
663 // offset -2 : argc
664 GateRef argc = method_->IsFastCall()
665 ? circuit_->GetConstantGate(MachineType::I64, 0, GateType::NJSValue())
666 : circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_ARGS), MachineType::I64,
667 {circuit_->GetArgRoot()}, GateType::TaggedValue());
668 // offset -3 : argv
669 GateRef argv = method_->IsFastCall()
670 ? circuit_->GetConstantGate(MachineType::ARCH, 0, GateType::NJSValue())
671 : circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_ARGV), MachineType::I64,
672 {circuit_->GetArgRoot()}, GateType::TaggedValue());
673 // offset -4 : func
674 (void)circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_FUNCTION), MachineType::I64,
675 {circuit_->GetArgRoot()}, GateType::TaggedValue());
676 // offset -5 : new_target
677 GateRef newTarget =
678 method_->IsFastCall()
679 ? circuit_->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_UNDEFINED, GateType::UndefinedType())
680 : circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_NEW_TARGET), MachineType::I64,
681 {circuit_->GetArgRoot()}, GateType::TaggedValue());
682 // offset -6 : this_object
683 (void)circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_THIS_OBJECT), MachineType::I64,
684 {circuit_->GetArgRoot()}, GateType::TaggedValue());
685 // offset -7 : numargs
686 (void)circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_NUM_ARGS), MachineType::I64,
687 {circuit_->GetArgRoot()}, GateType::TaggedValue());
688 for (size_t argIdx = 1; argIdx <= method_->GetNumArgsWithCallField(); argIdx++) {
689 // common args
690 argAcc_.NewArg(method_->IsFastCall() ? static_cast<size_t>(FastCallArgIdx::NUM_OF_ARGS)
691 : static_cast<size_t>(CommonArgIdx::NUM_OF_ARGS) + argIdx);
692 }
693
694 auto &args = argAcc_.args_;
695 if (args.size() == 0) {
696 GateAccessor(circuit_).GetArgsOuts(args);
697 std::reverse(args.begin(), args.end());
698 if (method_->IsFastCall() && args.size() >= static_cast<uint8_t>(FastCallArgIdx::NUM_OF_ARGS)) {
699 args.insert(args.begin() + static_cast<uint8_t>(CommonArgIdx::ACTUAL_ARGC), argc);
700 args.insert(args.begin() + static_cast<uint8_t>(CommonArgIdx::ACTUAL_ARGV), argv);
701 // 3: newtarget index
702 args.insert(args.begin() + static_cast<uint8_t>(CommonArgIdx::NEW_TARGET), newTarget);
703 }
704 }
705
706 BuildFrameArgs();
707 }
708
CreateGateInList(const BytecodeInfo & info,const GateMetaData * meta)709 std::vector<GateRef> BytecodeCircuitBuilder::CreateGateInList(
710 const BytecodeInfo &info, const GateMetaData *meta)
711 {
712 auto numValues = meta->GetNumIns();
713 const size_t length = meta->GetInValueStarts();
714 std::vector<GateRef> inList(numValues, Circuit::NullGate());
715 auto inputSize = info.inputs.size();
716 for (size_t i = 0; i < inputSize; i++) {
717 auto &input = info.inputs[i];
718 if (std::holds_alternative<ConstDataId>(input)) {
719 inList[i + length] = circuit_->GetConstantGate(MachineType::I64,
720 std::get<ConstDataId>(input).GetId(),
721 GateType::NJSValue());
722 } else if (std::holds_alternative<Immediate>(input)) {
723 inList[i + length] = circuit_->GetConstantGate(MachineType::I64,
724 std::get<Immediate>(input).GetValue(),
725 GateType::NJSValue());
726 } else if (std::holds_alternative<ICSlotId>(input)) {
727 inList[i + length] = circuit_->GetConstantGate(MachineType::I16,
728 std::get<ICSlotId>(input).GetId(),
729 GateType::NJSValue());
730 } else {
731 ASSERT(std::holds_alternative<VirtualRegister>(input));
732 continue;
733 }
734 }
735 if (info.AccIn()) {
736 inputSize++;
737 }
738 if (meta->HasFrameState()) {
739 inList[inputSize + length] = GetFrameArgs();
740 }
741 return inList;
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 default:
804 LOG_ECMA(FATAL) << "this branch is unreachable";
805 UNREACHABLE();
806 }
807 return gate;
808 }
809
MergeThrowGate(BytecodeRegion & bb,uint32_t bcIndex)810 void BytecodeCircuitBuilder::MergeThrowGate(BytecodeRegion &bb, uint32_t bcIndex)
811 {
812 auto state = frameStateBuilder_.GetCurrentState();
813 auto depend = frameStateBuilder_.GetCurrentDepend();
814 if (!bb.catches.empty()) {
815 auto ifSuccess = circuit_->NewGate(circuit_->IfSuccess(), {state});
816 auto dependRelay = circuit_->NewGate(circuit_->DependRelay(), {ifSuccess, depend});
817 auto ifException = circuit_->NewGate(circuit_->IfException(), {state, depend});
818 frameStateBuilder_.UpdateStateDepend(ifException, ifException);
819 ASSERT(bb.catches.size() == 1); // 1: one catch
820 auto bbNext = bb.catches.at(0);
821 frameStateBuilder_.MergeIntoSuccessor(bb, *bbNext);
822 bbNext->expandedPreds.push_back({bb.id, bcIndex, true});
823 state = ifSuccess;
824 depend = dependRelay;
825 }
826 auto constant = circuit_->GetConstantGate(MachineType::I64,
827 JSTaggedValue::VALUE_EXCEPTION,
828 GateType::TaggedValue());
829 circuit_->NewGate(circuit_->Return(),
830 { state, depend, constant, circuit_->GetReturnRoot() });
831 }
832
MergeExceptionGete(BytecodeRegion & bb,const BytecodeInfo & bytecodeInfo,uint32_t bcIndex)833 void BytecodeCircuitBuilder::MergeExceptionGete(BytecodeRegion &bb,
834 const BytecodeInfo& bytecodeInfo, uint32_t bcIndex)
835 {
836 auto state = frameStateBuilder_.GetCurrentState();
837 auto depend = frameStateBuilder_.GetCurrentDepend();
838 auto ifSuccess = circuit_->NewGate(circuit_->IfSuccess(), {state});
839 auto dependRelay = circuit_->NewGate(circuit_->DependRelay(), {ifSuccess, depend});
840 ASSERT(bb.catches.size() == 1); // 1: one catch
841 auto bbNext = bb.catches.at(0);
842 auto ifException = circuit_->NewGate(circuit_->IfException(), {state, depend});
843 frameStateBuilder_.UpdateStateDepend(ifException, ifException);
844 frameStateBuilder_.MergeIntoSuccessor(bb, *bbNext);
845 if (bytecodeInfo.GetOpcode() == EcmaOpcode::CREATEASYNCGENERATOROBJ_V8) {
846 bbNext->expandedPreds.push_back({bb.id, bcIndex + 1, true}); // 1: next pc
847 } else {
848 bbNext->expandedPreds.push_back({bb.id, bcIndex, true});
849 }
850 depend = dependRelay;
851 frameStateBuilder_.UpdateStateDepend(ifSuccess, depend);
852 }
853
NewJSGate(BytecodeRegion & bb)854 void BytecodeCircuitBuilder::NewJSGate(BytecodeRegion &bb)
855 {
856 auto &iterator = bb.GetBytecodeIterator();
857 const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
858 GateRef state = frameStateBuilder_.GetCurrentState();
859 GateRef depend = frameStateBuilder_.GetCurrentDepend();
860 size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
861 GateRef gate = 0;
862 bool writable = !bytecodeInfo.NoSideEffects();
863 bool hasFrameState = bytecodeInfo.HasFrameState();
864 size_t pcOffset = GetPcOffset(iterator.Index());
865 auto methodOffset = method_->GetMethodId().GetOffset();
866 auto meta = circuit_->JSBytecode(
867 numValueInputs, methodOffset, bytecodeInfo.GetOpcode(), pcOffset, iterator.Index(), writable, hasFrameState);
868 std::vector<GateRef> inList = CreateGateInList(bytecodeInfo, meta);
869 if (bytecodeInfo.IsDef()) {
870 gate = circuit_->NewGate(meta, MachineType::I64, inList.size(),
871 inList.data(), GateType::AnyType());
872 } else {
873 gate = circuit_->NewGate(meta, MachineType::NOVALUE, inList.size(),
874 inList.data(), GateType::Empty());
875 }
876 byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
877 jsGatesToByteCode_[gate] = iterator.Index();
878 gateAcc_.NewIn(gate, 0, state);
879 gateAcc_.NewIn(gate, 1, depend);
880 frameStateBuilder_.UpdateStateDepend(gate, gate);
881 frameStateBuilder_.UpdateFrameValues(bytecodeInfo, iterator.Index(), gate);
882 if (bytecodeInfo.IsThrow()) {
883 MergeThrowGate(bb, iterator.Index());
884 return;
885 }
886
887 if (!bb.catches.empty() && !bytecodeInfo.NoThrow()) {
888 MergeExceptionGete(bb, bytecodeInfo, iterator.Index());
889 } else if (!bb.catches.empty()) {
890 frameStateBuilder_.GetOrOCreateMergedContext(bb.catches.at(0)->id);
891 }
892 if (bytecodeInfo.IsGeneratorRelative()) {
893 suspendAndResumeGates_.emplace_back(gate);
894 }
895 }
896
NewJump(BytecodeRegion & bb)897 void BytecodeCircuitBuilder::NewJump(BytecodeRegion &bb)
898 {
899 auto &iterator = bb.GetBytecodeIterator();
900 const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
901 GateRef state = frameStateBuilder_.GetCurrentState();
902 GateRef depend = frameStateBuilder_.GetCurrentDepend();
903 size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
904 if (bytecodeInfo.IsCondJump() && bb.succs.size() == 2) { // 2: two succ
905 size_t pcOffset = GetPcOffset(iterator.Index());
906 auto methodOffset = method_->GetMethodId().GetOffset();
907 auto meta = circuit_->JSBytecode(
908 numValueInputs, methodOffset, bytecodeInfo.GetOpcode(), pcOffset, iterator.Index(), false, false);
909 auto numValues = meta->GetNumIns();
910 GateRef gate = circuit_->NewGate(meta, std::vector<GateRef>(numValues, Circuit::NullGate()));
911 gateAcc_.NewIn(gate, 0, state);
912 gateAcc_.NewIn(gate, 1, depend);
913 frameStateBuilder_.UpdateStateDepend(gate, gate);
914 frameStateBuilder_.UpdateFrameValues(bytecodeInfo, iterator.Index(), gate);
915
916 auto ifTrue = circuit_->NewGate(circuit_->IfTrue(), {gate});
917 auto trueRelay = circuit_->NewGate(circuit_->DependRelay(), {ifTrue, gate});
918 auto ifFalse = circuit_->NewGate(circuit_->IfFalse(), {gate});
919 auto falseRelay = circuit_->NewGate(circuit_->DependRelay(), {ifFalse, gate});
920 for (auto &bbNext: bb.succs) {
921 if (iterator.Index() + 1 == bbNext->start) {
922 frameStateBuilder_.UpdateStateDepend(ifFalse, falseRelay);
923 frameStateBuilder_.MergeIntoSuccessor(bb, *bbNext);
924 bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
925 } else {
926 frameStateBuilder_.UpdateStateDepend(ifTrue, trueRelay);
927 frameStateBuilder_.MergeIntoSuccessor(bb, *bbNext);
928 bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
929 }
930 }
931 byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
932 jsGatesToByteCode_[gate] = iterator.Index();
933 } else {
934 ASSERT(bb.succs.size() == 1); // 1: only one succ if not condjump
935 auto &bbNext = bb.succs.at(0);
936 frameStateBuilder_.MergeIntoSuccessor(bb, *bbNext);
937 bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
938 }
939
940 if (!bb.catches.empty()) {
941 frameStateBuilder_.GetOrOCreateMergedContext(bb.catches.at(0)->id);
942 }
943 }
944
NewReturn(BytecodeRegion & bb)945 GateRef BytecodeCircuitBuilder::NewReturn(BytecodeRegion &bb)
946 {
947 ASSERT(bb.succs.empty());
948 auto &iterator = bb.GetBytecodeIterator();
949 const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
950 GateRef state = frameStateBuilder_.GetCurrentState();
951 GateRef depend = frameStateBuilder_.GetCurrentDepend();
952 GateRef gate = Circuit::NullGate();
953 if (bytecodeInfo.GetOpcode() == EcmaOpcode::RETURN) {
954 // handle return.dyn bytecode
955 gate = circuit_->NewGate(circuit_->Return(),
956 { state, depend, Circuit::NullGate(), circuit_->GetReturnRoot() });
957 byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
958 jsGatesToByteCode_[gate] = iterator.Index();
959 } else if (bytecodeInfo.GetOpcode() == EcmaOpcode::RETURNUNDEFINED) {
960 // handle returnundefined bytecode
961 auto constant = circuit_->GetConstantGate(MachineType::I64,
962 JSTaggedValue::VALUE_UNDEFINED,
963 GateType::TaggedValue());
964 gate = circuit_->NewGate(circuit_->Return(),
965 { state, depend, constant, circuit_->GetReturnRoot() });
966 byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
967 jsGatesToByteCode_[gate] = iterator.Index();
968 }
969 return gate;
970 }
971
NewByteCode(BytecodeRegion & bb)972 void BytecodeCircuitBuilder::NewByteCode(BytecodeRegion &bb)
973 {
974 auto &iterator = bb.GetBytecodeIterator();
975 const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
976 FrameLiveOut* liveout;
977 auto bcId = iterator.Index();
978 if (bcId != 0 && iterator.IsInRange(bcId - 1)) {
979 liveout = frameStateBuilder_.GetOrOCreateBCEndLiveOut(bcId - 1);
980 } else {
981 liveout = frameStateBuilder_.GetOrOCreateBBLiveOut(bb.id);
982 }
983 frameStateBuilder_.AdvanceToNextBc(bytecodeInfo, liveout, bcId);
984 GateRef gate = Circuit::NullGate();
985 if (bytecodeInfo.IsSetConstant()) {
986 // handle bytecode command to get constants
987 gate = NewConst(bytecodeInfo);
988 byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
989 jsGatesToByteCode_[gate] = iterator.Index();
990 } else if (bytecodeInfo.IsGeneral()) {
991 // handle general ecma.* bytecodes
992 NewJSGate(bb);
993 } else if (bytecodeInfo.IsJump()) {
994 // handle conditional jump and unconditional jump bytecodes
995 NewJump(bb);
996 } else if (bytecodeInfo.IsReturn()) {
997 // handle return.dyn and returnundefined bytecodes
998 gate = NewReturn(bb);
999 } else if (bytecodeInfo.IsMov()) {
1000 frameStateBuilder_.UpdateMoveValues(bytecodeInfo);
1001 } else if (!bytecodeInfo.IsDiscarded()) {
1002 LOG_ECMA(FATAL) << "this branch is unreachable";
1003 UNREACHABLE();
1004 }
1005 if (gate != Circuit::NullGate()) {
1006 frameStateBuilder_.UpdateFrameValues(bytecodeInfo, iterator.Index(), gate);
1007 }
1008 }
1009
BuildSubCircuit()1010 void BytecodeCircuitBuilder::BuildSubCircuit()
1011 {
1012 auto &entryBlock = RegionAt(0);
1013 frameStateBuilder_.InitEntryBB(entryBlock);
1014 auto& rpoList = frameStateBuilder_.GetRpoList();
1015 for (auto &bbId: rpoList) {
1016 auto &bb = RegionAt(bbId);
1017 frameStateBuilder_.AdvanceToNextBB(bb);
1018 if (IsEntryBlock(bb.id)) {
1019 if (NeedCheckSafePointAndStackOver()) {
1020 GateRef state = frameStateBuilder_.GetCurrentState();
1021 GateRef depend = frameStateBuilder_.GetCurrentDepend();
1022 auto stackCheck = circuit_->NewGate(circuit_->CheckSafePointAndStackOver(), {state, depend});
1023 bb.dependCache = stackCheck;
1024 frameStateBuilder_.UpdateStateDepend(stackCheck, stackCheck);
1025 }
1026 auto &bbNext = RegionAt(bb.id + 1);
1027 frameStateBuilder_.MergeIntoSuccessor(bb, bbNext);
1028 bbNext.expandedPreds.push_back({bb.id, bb.end, false});
1029 continue;
1030 }
1031 if (!bb.trys.empty()) {
1032 GateRef state = frameStateBuilder_.GetCurrentState();
1033 GateRef depend = frameStateBuilder_.GetCurrentDepend();
1034 auto getException = circuit_->NewGate(circuit_->GetException(),
1035 MachineType::I64, {state, depend}, GateType::AnyType());
1036 frameStateBuilder_.UpdateAccumulator(getException);
1037 frameStateBuilder_.UpdateStateDepend(state, getException);
1038 }
1039 EnumerateBlock(bb, [this, &bb]
1040 (const BytecodeInfo &bytecodeInfo) -> bool {
1041 NewByteCode(bb);
1042 if (bytecodeInfo.IsJump() || bytecodeInfo.IsThrow()) {
1043 return false;
1044 }
1045 return true;
1046 });
1047 bool needFallThrough = true;
1048 if (!bb.IsEmptryBlock()) {
1049 const BytecodeInfo& bytecodeInfo = GetBytecodeInfo(bb.end);
1050 needFallThrough = bytecodeInfo.needFallThrough();
1051 }
1052 // fallThrough or empty merge bb
1053 if (needFallThrough) {
1054 ASSERT(bb.succs.size() == 1); // 1: fall through
1055 auto &bbNext = RegionAt(bb.succs[0]->id);
1056 frameStateBuilder_.MergeIntoSuccessor(bb, bbNext);
1057 bbNext.expandedPreds.push_back({bb.id, bb.end, false});
1058 }
1059 }
1060 }
1061
FindOsrLoopHeadBB()1062 bool BytecodeCircuitBuilder::FindOsrLoopHeadBB()
1063 {
1064 int32_t loopBackBcIndex {-1};
1065 for (size_t k = 0; k < pcOffsets_.size(); k++) {
1066 if (static_cast<int32_t>(pcOffsets_[k] - pcOffsets_[0]) == osrOffset_) {
1067 loopBackBcIndex = static_cast<int32_t>(k);
1068 }
1069 }
1070 if (loopBackBcIndex == -1) {
1071 LOG_COMPILER(ERROR) << "Unable to find the loop back of OSR.";
1072 return false;
1073 }
1074 auto &rpoList = frameStateBuilder_.GetRpoList();
1075 for (auto &bbId : rpoList) {
1076 auto &bb = RegionAt(bbId);
1077 if (bb.end == static_cast<uint32_t>(loopBackBcIndex)) {
1078 frameStateBuilder_.SetOsrLoopHeadBB(bb);
1079 return true;
1080 }
1081 }
1082 LOG_COMPILER(ERROR) << "Unable to find the loop head bb of OSR.";
1083 return false;
1084 }
1085
GenDeoptAndReturnForOsrLoopExit(BytecodeRegion & osrLoopExitBB)1086 void BytecodeCircuitBuilder::GenDeoptAndReturnForOsrLoopExit(BytecodeRegion &osrLoopExitBB)
1087 {
1088 frameStateBuilder_.AdvanceToNextBB(osrLoopExitBB, true);
1089 GateRef state = frameStateBuilder_.GetCurrentState();
1090 GateRef depend = frameStateBuilder_.GetCurrentDepend();
1091 std::string comment = Deoptimizier::DisplayItems(DeoptType::OSRLOOPEXIT);
1092 GateRef type =
1093 circuit_->GetConstantGate(MachineType::I64, static_cast<int64_t>(DeoptType::OSRLOOPEXIT), GateType::NJSValue());
1094 GateRef condition = circuit_->GetConstantGate(MachineType::I1, 0, GateType::NJSValue());
1095 GateRef deopt = circuit_->NewGate(circuit_->DeoptCheck(), MachineType::I1,
1096 {state, depend, condition, gateAcc_.GetFrameState(depend), type},
1097 GateType::NJSValue(), comment.c_str());
1098 GateRef dependRelay = circuit_->NewGate(circuit_->DependRelay(), {deopt, depend});
1099 GateRef undef =
1100 circuit_->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_UNDEFINED, GateType::TaggedValue());
1101 circuit_->NewGate(circuit_->Return(), {state, dependRelay, undef, circuit_->GetReturnRoot()});
1102 }
1103
CollectCacheBBforOSRLoop(BytecodeRegion * bb)1104 void BytecodeCircuitBuilder::CollectCacheBBforOSRLoop(BytecodeRegion *bb)
1105 {
1106 catchBBOfOSRLoop_.insert(bb);
1107 for (BytecodeRegion *succBB : bb->succs) {
1108 CollectCacheBBforOSRLoop(succBB);
1109 }
1110 }
1111
HandleOsrLoopBody(BytecodeRegion & osrLoopBodyBB)1112 void BytecodeCircuitBuilder::HandleOsrLoopBody(BytecodeRegion &osrLoopBodyBB)
1113 {
1114 if (!osrLoopBodyBB.trys.empty()) {
1115 GateRef state = frameStateBuilder_.GetCurrentState();
1116 GateRef depend = frameStateBuilder_.GetCurrentDepend();
1117 auto getException =
1118 circuit_->NewGate(circuit_->GetException(), MachineType::I64, {state, depend}, GateType::AnyType());
1119 frameStateBuilder_.UpdateAccumulator(getException);
1120 frameStateBuilder_.UpdateStateDepend(state, getException);
1121 }
1122 // collect catch BB.
1123 if (!osrLoopBodyBB.catches.empty()) {
1124 for (BytecodeRegion *targetBB : osrLoopBodyBB.catches) {
1125 CollectCacheBBforOSRLoop(targetBB);
1126 }
1127 }
1128 EnumerateBlock(osrLoopBodyBB, [this, &osrLoopBodyBB](const BytecodeInfo &bytecodeInfo) -> bool {
1129 NewByteCode(osrLoopBodyBB);
1130 if (bytecodeInfo.IsJump() || bytecodeInfo.IsThrow()) {
1131 return false;
1132 }
1133 return true;
1134 });
1135 bool needFallThrough = true;
1136 if (!osrLoopBodyBB.IsEmptryBlock()) {
1137 const BytecodeInfo &bytecodeInfo = GetBytecodeInfo(osrLoopBodyBB.end);
1138 needFallThrough = bytecodeInfo.needFallThrough();
1139 }
1140 // fallThrough or empty merge osrLoopBodyBB
1141 if (needFallThrough) {
1142 ASSERT(osrLoopBodyBB.succs.size() == 1); // 1: fall through
1143 auto &bbNext = RegionAt(osrLoopBodyBB.succs[0]->id);
1144 frameStateBuilder_.MergeIntoSuccessor(osrLoopBodyBB, bbNext);
1145 bbNext.expandedPreds.push_back({osrLoopBodyBB.id, osrLoopBodyBB.end, false});
1146 }
1147 }
1148
BuildOsrCircuit()1149 void BytecodeCircuitBuilder::BuildOsrCircuit()
1150 {
1151 if (!FindOsrLoopHeadBB()) {
1152 LOG_COMPILER(FATAL) << "invalid osr offset";
1153 }
1154 circuit_->SetIsOsr();
1155 auto &entryBlock = RegionAt(0);
1156 frameStateBuilder_.InitEntryBB(entryBlock);
1157 std::set<size_t> osrLoopExitBBIds;
1158 auto &rpoList = frameStateBuilder_.GetRpoList();
1159 for (auto &bbId : rpoList) {
1160 auto &bb = RegionAt(bbId);
1161 if (frameStateBuilder_.IsOsrLoopExit(bb)) {
1162 // The loop exit BB is in front of the loop head BB. At this time,
1163 // the loop exit BB does not have the context object, and the processing of the loop exit BB is delayed.
1164 if (frameStateBuilder_.IsContextExists(bb.id)) {
1165 GenDeoptAndReturnForOsrLoopExit(bb);
1166 } else {
1167 osrLoopExitBBIds.insert(bbId);
1168 }
1169 continue;
1170 }
1171
1172 // Processes only the BBs related to the loop specified by the OSR.
1173 if (!IsEntryBlock(bb.id) && frameStateBuilder_.OutOfOsrLoop(bb) && !IsCacheBBOfOSRLoop(bb)) {
1174 continue;
1175 }
1176
1177 frameStateBuilder_.AdvanceToNextBB(bb);
1178 if (IsEntryBlock(bb.id)) {
1179 if (NeedCheckSafePointAndStackOver()) {
1180 GateRef state = frameStateBuilder_.GetCurrentState();
1181 GateRef depend = frameStateBuilder_.GetCurrentDepend();
1182 auto stackCheck = circuit_->NewGate(circuit_->CheckSafePointAndStackOver(), {state, depend});
1183 bb.dependCache = stackCheck;
1184 frameStateBuilder_.UpdateStateDepend(stackCheck, stackCheck);
1185 }
1186 auto *bbNext = &RegionAt(bb.id + 1);
1187 while (!IsEntryBlock(bbNext->id) && frameStateBuilder_.OutOfOsrLoop(*bbNext)) {
1188 bbNext = &RegionAt(bbNext->id + 1);
1189 }
1190 frameStateBuilder_.MergeIntoSuccessor(bb, *bbNext);
1191 bbNext->expandedPreds.push_back({bb.id, bb.end, false});
1192 continue;
1193 }
1194
1195 HandleOsrLoopBody(bb);
1196 }
1197 for (size_t bbId : osrLoopExitBBIds) {
1198 auto &bb = RegionAt(bbId);
1199 GenDeoptAndReturnForOsrLoopExit(bb);
1200 }
1201 }
1202
BuildCircuit()1203 void BytecodeCircuitBuilder::BuildCircuit()
1204 {
1205 if (IsOSR()) {
1206 // create osr arg gates array
1207 BuildOSRArgs();
1208 frameStateBuilder_.DoBytecodeAnalysis();
1209 if (TerminateAnalysis()) {
1210 return;
1211 }
1212 // build states sub-circuit of osr block
1213 BuildOsrCircuit();
1214 } else {
1215 // create arg gates array
1216 BuildCircuitArgs();
1217 frameStateBuilder_.DoBytecodeAnalysis();
1218 if (TerminateAnalysis()) {
1219 return;
1220 }
1221 // build states sub-circuit of each block
1222 BuildSubCircuit();
1223 }
1224 if (IsLogEnabled()) {
1225 PrintGraph(std::string("Bytecode2Gate [" + methodName_ + "]").c_str());
1226 LOG_COMPILER(INFO) << "\033[34m" << "============= "
1227 << "After bytecode2circuit lowering ["
1228 << methodName_ << "]"
1229 << " =============" << "\033[0m";
1230 circuit_->PrintAllGatesWithBytecode();
1231 LOG_COMPILER(INFO) << "\033[34m" << "=========================== End ===========================" << "\033[0m";
1232 }
1233 }
1234
PrintGraph(const char * title)1235 void BytecodeCircuitBuilder::PrintGraph(const char* title)
1236 {
1237 LOG_COMPILER(INFO) << "======================== " << title << " ========================";
1238 for (size_t i = 0; i < graph_.size(); i++) {
1239 BytecodeRegion& bb = RegionAt(i);
1240 if (!IsEntryBlock(bb.id) && bb.numOfStatePreds == 0) {
1241 LOG_COMPILER(INFO) << "B" << bb.id << ": ;preds= invalid BB";
1242 LOG_COMPILER(INFO) << "\tBytecodePC: [" << std::to_string(bb.start) << ", "
1243 << std::to_string(bb.end) << ")";
1244 continue;
1245 }
1246 std::string log("B" + std::to_string(bb.id) + ": ;preds= ");
1247 for (size_t k = 0; k < bb.preds.size(); ++k) {
1248 log += std::to_string(bb.preds[k]->id) + ", ";
1249 }
1250 LOG_COMPILER(INFO) << log;
1251 if (IsEntryBlock(bb.id)) {
1252 LOG_COMPILER(INFO) << "\tBytecodePC: Empty";
1253 } else {
1254 LOG_COMPILER(INFO) << "\tBytecodePC: [" << std::to_string(bb.start) << ", "
1255 << std::to_string(bb.end) << ")";
1256 }
1257
1258 std::string log1("\tSucces: ");
1259 for (size_t j = 0; j < bb.succs.size(); j++) {
1260 log1 += std::to_string(bb.succs[j]->id) + ", ";
1261 }
1262 LOG_COMPILER(INFO) << log1;
1263
1264 for (size_t j = 0; j < bb.catches.size(); j++) {
1265 LOG_COMPILER(INFO) << "\tcatch [: " << std::to_string(bb.catches[j]->start) << ", "
1266 << std::to_string(bb.catches[j]->end) << ")";
1267 }
1268
1269 std::string log2("\tTrys: ");
1270 for (auto tryBlock: bb.trys) {
1271 log2 += std::to_string(tryBlock->id) + " , ";
1272 }
1273 LOG_COMPILER(INFO) << log2;
1274
1275 PrintBytecodeInfo(bb);
1276 LOG_COMPILER(INFO) << "";
1277 }
1278 }
1279
PrintBytecodeInfo(BytecodeRegion & bb)1280 void BytecodeCircuitBuilder::PrintBytecodeInfo(BytecodeRegion& bb)
1281 {
1282 if (IsEntryBlock(bb.id)) {
1283 LOG_COMPILER(INFO) << "\tBytecode[] = Empty";
1284 return;
1285 }
1286 LOG_COMPILER(INFO) << "\tBytecode[] = ";
1287 EnumerateBlock(bb, [&](const BytecodeInfo &bytecodeInfo) -> bool {
1288 auto &iterator = bb.GetBytecodeIterator();
1289 std::string log;
1290 log += std::string("\t\t< ") + std::to_string(iterator.Index()) + ": ";
1291 log += GetEcmaOpcodeStr(iterator.GetBytecodeInfo().GetOpcode()) + ", " + "In=[";
1292 if (bytecodeInfo.AccIn()) {
1293 log += "acc,";
1294 }
1295 for (const auto &in: bytecodeInfo.inputs) {
1296 if (std::holds_alternative<VirtualRegister>(in)) {
1297 log += std::to_string(std::get<VirtualRegister>(in).GetId()) + ",";
1298 }
1299 }
1300 log += "], Out=[";
1301 if (bytecodeInfo.AccOut()) {
1302 log += "acc,";
1303 }
1304 for (const auto &out: bytecodeInfo.vregOut) {
1305 log += std::to_string(out) + ",";
1306 }
1307 log += "] >";
1308 LOG_COMPILER(INFO) << log;
1309
1310 auto gate = GetGateByBcIndex(iterator.Index());
1311 if (gate != Circuit::NullGate()) {
1312 this->gateAcc_.ShortPrint(gate);
1313 }
1314 return true;
1315 });
1316 }
1317 } // namespace panda::ecmascript::kungfu
1318