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