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