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/gate.h"
17
18 namespace panda::ecmascript::kungfu {
CheckNullInput() const19 void Gate::CheckNullInput() const
20 {
21 const auto numIns = GetNumIns();
22 for (size_t idx = 0; idx < numIns; idx++) {
23 if (IsInGateNull(idx)) {
24 CheckFailed("In list contains null", idx);
25 }
26 }
27 }
28
CheckFailed(std::string errorString,size_t highlightIdx) const29 void Gate::CheckFailed(std::string errorString, size_t highlightIdx) const
30 {
31 LOG_COMPILER(ERROR) << "[Verifier][Error] Gate level input list schema verify failed";
32 Print("", true, highlightIdx);
33 LOG_COMPILER(FATAL) << "Note: " << errorString;
34 }
35
CheckInputOpcode(size_t idx,OpCode expected) const36 void Gate::CheckInputOpcode(size_t idx, OpCode expected) const
37 {
38 OpCode actual = GetInGateConst(idx)->GetOpCode();
39 if (actual != expected) {
40 CheckFailed("State input does not match (expected:" + GateMetaData::Str(expected) +
41 " actual:" + GateMetaData::Str(actual) + ")", idx);
42 }
43 }
44
CheckInputMachineType(size_t idx,MachineType expected,bool isArch64) const45 void Gate::CheckInputMachineType(size_t idx, MachineType expected, bool isArch64) const
46 {
47 MachineType actual = GetInGateConst(idx)->GetMachineType();
48 if (expected == MachineType::FLEX) {
49 expected = GetMachineType();
50 }
51 if (expected == MachineType::ARCH) {
52 expected = isArch64 ? MachineType::I64 : MachineType::I32;
53 }
54 if (actual == MachineType::ARCH) {
55 actual = isArch64 ? MachineType::I64 : MachineType::I32;
56 }
57 if (actual != expected) {
58 CheckFailed("Value input does not match (expected:" +
59 MachineTypeToStr(expected) + " actual:" + MachineTypeToStr(actual) + ")", idx);
60 }
61 }
62
CheckNotInputMachineType(size_t idx,MachineType notExpected) const63 void Gate::CheckNotInputMachineType(size_t idx, MachineType notExpected) const
64 {
65 MachineType actual = GetInGateConst(idx)->GetMachineType();
66 if (actual == notExpected) {
67 CheckFailed("Value input does not match (notExpected:" +
68 MachineTypeToStr(notExpected) + " actual:" + MachineTypeToStr(actual) + ")", idx);
69 }
70 }
71
CheckGeneralState(size_t idx) const72 void Gate::CheckGeneralState(size_t idx) const
73 {
74 auto gatePtr = GetInGateConst(idx);
75 OpCode actual = gatePtr->GetOpCode();
76 if (!gatePtr->meta_->IsGeneralState()) {
77 CheckFailed("State input does not match (expected:<General State> actual:" +
78 GateMetaData::Str(actual) + ")", idx);
79 }
80 }
81
CheckState(size_t idx) const82 void Gate::CheckState(size_t idx) const
83 {
84 auto gatePtr = GetInGateConst(idx);
85 OpCode actual = gatePtr->GetOpCode();
86 if ((actual != OpCode::STATE_ENTRY) && (!gatePtr->meta_->IsState())) {
87 CheckFailed("State input does not match (expected:<State> actual:" +
88 GateMetaData::Str(actual) + ")", idx);
89 }
90 }
91
CheckStateInput() const92 void Gate::CheckStateInput() const
93 {
94 size_t stateStart = 0;
95 size_t stateEnd = GetStateCount();
96 for (size_t idx = stateStart; idx < stateEnd; idx++) {
97 bool needCheck = true;
98 switch (GetOpCode()) {
99 case OpCode::IF_TRUE:
100 case OpCode::IF_FALSE:
101 ASSERT(idx == stateStart);
102 CheckInputOpcode(idx, OpCode::IF_BRANCH);
103 needCheck = false;
104 break;
105 case OpCode::SWITCH_CASE:
106 case OpCode::DEFAULT_CASE:
107 ASSERT(idx == stateStart);
108 CheckInputOpcode(idx, OpCode::SWITCH_BRANCH);
109 needCheck = false;
110 break;
111 default:
112 break;
113 }
114 if (needCheck) {
115 CheckState(idx);
116 }
117 }
118 }
119
CheckValueInput(bool isArch64) const120 void Gate::CheckValueInput(bool isArch64) const
121 {
122 size_t valueStart = GetInValueStarts();
123 size_t valueEnd = valueStart + GetInValueCount();
124 for (size_t idx = valueStart; idx < valueEnd; idx++) {
125 switch (GetOpCode()) {
126 case OpCode::IF_BRANCH:
127 ASSERT(idx == valueStart);
128 CheckInputMachineType(idx, MachineType::I1, isArch64);
129 break;
130 case OpCode::VALUE_SELECTOR:
131 case OpCode::ADD:
132 case OpCode::SUB:
133 case OpCode::MUL:
134 case OpCode::EXP:
135 case OpCode::SDIV:
136 case OpCode::SMOD:
137 case OpCode::UDIV:
138 case OpCode::UMOD:
139 case OpCode::FDIV:
140 case OpCode::FMOD:
141 case OpCode::AND:
142 case OpCode::XOR:
143 case OpCode::OR:
144 case OpCode::LSL:
145 case OpCode::LSR:
146 case OpCode::ASR:
147 CheckInputMachineType(idx, MachineType::FLEX, isArch64);
148 break;
149 case OpCode::REV:
150 ASSERT(idx == valueStart);
151 CheckInputMachineType(idx, MachineType::I1, isArch64);
152 break;
153 case OpCode::LOAD:
154 ASSERT(idx == valueStart);
155 CheckInputMachineType(idx, MachineType::ARCH, isArch64);
156 break;
157 case OpCode::STORE:
158 if ((idx == valueStart + 1) || (idx == valueStart + 2)) { // 1:base, 2:offset
159 CheckInputMachineType(idx, MachineType::ARCH, isArch64);
160 }
161 break;
162 case OpCode::STORE_WITHOUT_BARRIER:
163 if (idx == valueStart) {
164 CheckInputMachineType(idx, MachineType::ARCH, isArch64);
165 }
166 break;
167 case OpCode::HEAP_ALLOC: {
168 if (idx == valueStart + 1) { // 1: size offset
169 CheckInputMachineType(idx, MachineType::I64, isArch64);
170 }
171 break;
172 }
173 case OpCode::TAGGED_TO_INT64:
174 case OpCode::INT64_TO_TAGGED:
175 ASSERT(idx == valueStart);
176 CheckInputMachineType(valueStart, MachineType::I64, isArch64);
177 break;
178 case OpCode::OBJECT_TYPE_CHECK:
179 case OpCode::LOAD_ELEMENT:
180 case OpCode::STORE_ELEMENT:
181 if (idx == valueStart) { // 1: idx 1
182 CheckInputMachineType(idx, MachineType::I64, isArch64);
183 }
184 break;
185 case OpCode::FCMP:
186 CheckInputMachineType(idx, MachineType::F64, isArch64);
187 break;
188 case OpCode::ICMP:
189 CheckNotInputMachineType(idx, MachineType::F64);
190 break;
191 default:
192 break;
193 }
194 }
195 }
196
CheckDependInput() const197 void Gate::CheckDependInput() const
198 {
199 size_t dependStart = GetStateCount();
200 size_t dependEnd = dependStart + GetDependCount();
201 for (size_t idx = dependStart; idx < dependEnd; idx++) {
202 if (GetInGateConst(idx)->GetDependCount() == 0 &&
203 GetInGateConst(idx)->GetOpCode() != OpCode::DEPEND_ENTRY) {
204 LOG_COMPILER(ERROR) << "depend in of " << GetId() << GateMetaData::Str(GetOpCode()) << "is "
205 << GetInGateConst(idx)->GetId() << GateMetaData::Str(GetInGateConst(idx)->GetOpCode());
206 CheckFailed("Depend input is side-effect free", idx);
207 }
208 }
209 }
210
CheckRootInput() const211 void Gate::CheckRootInput() const
212 {
213 size_t rootStart = GetInValueStarts() + GetInValueCount();
214 if (meta_->HasRoot()) {
215 switch (GetOpCode()) {
216 case OpCode::STATE_ENTRY:
217 case OpCode::DEPEND_ENTRY:
218 case OpCode::RETURN_LIST:
219 case OpCode::ARG_LIST:
220 CheckInputOpcode(rootStart, OpCode::CIRCUIT_ROOT);
221 break;
222 case OpCode::ARG:
223 CheckInputOpcode(rootStart, OpCode::ARG_LIST);
224 break;
225 case OpCode::RETURN:
226 case OpCode::RETURN_VOID:
227 CheckInputOpcode(rootStart, OpCode::RETURN_LIST);
228 break;
229 default:
230 break;
231 }
232 }
233 }
234
CheckFrameStateInput() const235 void Gate::CheckFrameStateInput() const
236 {
237 size_t frameStateStart = GetInFrameStateStarts();
238 if (meta_->HasFrameState()) {
239 CheckInputOpcode(frameStateStart, OpCode::FRAME_STATE);
240 }
241 }
242
GetValueInAndOut(bool inListPreview,size_t highlightIdx) const243 std::string Gate::GetValueInAndOut(bool inListPreview, size_t highlightIdx) const
244 {
245 auto opcode = GetOpCode();
246 if (opcode != OpCode::NOP && opcode != OpCode::DEAD) {
247 std::ostringstream log("{\"id\":");
248 log << std::to_string(id_) << ", \"op\":\"" << GateMetaData::Str(opcode) << "\", ";
249 log << "\",\"in\":[";
250 size_t idx = 0;
251 auto stateSize = GetStateCount();
252 auto dependSize = GetDependCount();
253 auto valueSize = GetInValueCount();
254 auto frameStateSize = GetInFrameStateCount();
255 auto rootSize = GetRootCount();
256 size_t start = 0;
257 size_t end = stateSize;
258 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
259 end += dependSize;
260 start += stateSize;
261 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
262 end += valueSize;
263 start += dependSize;
264 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
265 end += frameStateSize;
266 start += valueSize;
267 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
268 end += rootSize;
269 start += frameStateSize;
270 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log, true);
271
272 log << "], \"out\":[";
273
274 if (!IsFirstOutNull()) {
275 const Out *curOut = GetFirstOutConst();
276 opcode = curOut->GetGateConst()->GetOpCode();
277 log << std::to_string(curOut->GetGateConst()->GetId()) +
278 (inListPreview ? std::string(":" + GateMetaData::Str(opcode)) : std::string(""));
279
280 while (!curOut->IsNextOutNull()) {
281 curOut = curOut->GetNextOutConst();
282 log << ", " << std::to_string(curOut->GetGateConst()->GetId()) <<
283 (inListPreview ? std::string(":" + GateMetaData::Str(opcode))
284 : std::string(""));
285 }
286 }
287 log << "]},";
288 return log.str();
289 }
290 return "";
291 }
292
CheckStateOutput(const std::string & methodName) const293 void Gate::CheckStateOutput(const std::string& methodName) const
294 {
295 if (!GetMetaData()->IsState()) {
296 return;
297 }
298 size_t cnt = 0;
299 const Gate *curGate = this;
300 if (!curGate->IsFirstOutNull()) {
301 const Out *curOut = curGate->GetFirstOutConst();
302 auto meta = curOut->GetGateConst()->GetMetaData();
303 if (curOut->IsStateEdge() && meta->IsState()) {
304 cnt++;
305 }
306 while (!curOut->IsNextOutNull()) {
307 curOut = curOut->GetNextOutConst();
308 meta = curOut->GetGateConst()->GetMetaData();
309 if (curOut->IsStateEdge() && meta->IsState()) {
310 cnt++;
311 }
312 }
313 }
314 size_t expected = 0;
315 bool needCheck = true;
316 if (GetMetaData()->IsTerminalState()) {
317 expected = 0;
318 } else if (GetOpCode() == OpCode::IF_BRANCH || GetOpCode() == OpCode::JS_BYTECODE) {
319 expected = 2; // 2: expected number of state out branches
320 } else if (GetOpCode() == OpCode::SWITCH_BRANCH) {
321 needCheck = false;
322 } else {
323 expected = 1;
324 }
325 if (needCheck && cnt != expected) {
326 curGate->Print();
327 std::string log = curGate->GetValueInAndOut(true);
328 CheckFailed("Number of state out branches is not valid (expected:" + std::to_string(expected) +
329 " actual:" + std::to_string(cnt) + ") methodName:" + methodName + " gateValue:" + log, -1);
330 }
331 }
332
CheckBranchOutput() const333 void Gate::CheckBranchOutput() const
334 {
335 std::map<std::pair<OpCode, BitField>, size_t> setOfOps;
336 if (GetOpCode() == OpCode::IF_BRANCH) {
337 size_t cnt = 0;
338 const Gate *curGate = this;
339 if (!curGate->IsFirstOutNull()) {
340 const Out *curOut = curGate->GetFirstOutConst();
341 if (curOut->GetGateConst()->GetMetaData()->IsState() && curOut->IsStateEdge()) {
342 ASSERT(!curOut->GetGateConst()->GetMetaData()->IsFixed());
343 setOfOps[{curOut->GetGateConst()->GetOpCode(), curOut->GetGateConst()->GetStateCount()}]++;
344 cnt++;
345 }
346 while (!curOut->IsNextOutNull()) {
347 curOut = curOut->GetNextOutConst();
348 if (curOut->GetGateConst()->GetMetaData()->IsState() && curOut->IsStateEdge()) {
349 ASSERT(!curOut->GetGateConst()->GetMetaData()->IsFixed());
350 setOfOps[{curOut->GetGateConst()->GetOpCode(), curOut->GetGateConst()->GetStateCount()}]++;
351 cnt++;
352 }
353 }
354 }
355 if (setOfOps.size() != cnt) {
356 CheckFailed("Duplicate state out branches", -1);
357 }
358 }
359 }
360
CheckNOP() const361 void Gate::CheckNOP() const
362 {
363 if (GetOpCode() == OpCode::NOP || GetOpCode() == OpCode::DEAD) {
364 if (!IsFirstOutNull()) {
365 CheckFailed("NOP gate used by other gates", -1);
366 }
367 }
368 }
369
CheckSelector() const370 void Gate::CheckSelector() const
371 {
372 if (GetOpCode() == OpCode::VALUE_SELECTOR || GetOpCode() == OpCode::DEPEND_SELECTOR) {
373 auto stateOp = GetInGateConst(0)->GetOpCode();
374 if (stateOp == OpCode::MERGE || stateOp == OpCode::LOOP_BEGIN) {
375 ASSERT(GetNumIns() > 0);
376 if (GetInGateConst(0)->GetNumIns() != GetNumIns() - 1) {
377 if (GetOpCode() == OpCode::DEPEND_SELECTOR) {
378 CheckFailed("Number of depend flows does not match control flows (expected:" +
379 std::to_string(GetInGateConst(0)->GetNumIns()) +
380 " actual:" + std::to_string(GetNumIns() - 1) + ")",
381 -1);
382 } else {
383 CheckFailed("Number of data flows does not match control flows (expected:" +
384 std::to_string(GetInGateConst(0)->GetNumIns()) +
385 " actual:" + std::to_string(GetNumIns() - 1) + ")",
386 -1);
387 }
388 }
389 } else {
390 CheckFailed(
391 "State input does not match (expected:[MERGE|LOOP_BEGIN] actual:" +
392 GateMetaData::Str(stateOp) + ")", 0);
393 }
394 }
395 }
396
CheckRelay() const397 void Gate::CheckRelay() const
398 {
399 if (GetOpCode() == OpCode::DEPEND_RELAY) {
400 auto stateOp = GetInGateConst(0)->GetOpCode();
401 switch (stateOp) {
402 case OpCode::IF_TRUE:
403 case OpCode::IF_FALSE:
404 case OpCode::SWITCH_CASE:
405 case OpCode::DEFAULT_CASE:
406 case OpCode::IF_SUCCESS:
407 case OpCode::IF_EXCEPTION:
408 case OpCode::ORDINARY_BLOCK:
409 case OpCode::DEOPT_CHECK:
410 break;
411 default:
412 CheckFailed("State input does not match ("
413 "expected:[IF_TRUE|IF_FALSE|SWITCH_CASE|DEFAULT_CASE|"
414 "IF_SUCCESS|IF_EXCEPTION|ORDINARY_BLOCK|DEOPT_CHECK] actual:" +
415 GateMetaData::Str(stateOp) + ")", 0);
416 break;
417 }
418 }
419 }
420
Verify(bool isArch64,const std::string & methodName) const421 void Gate::Verify(bool isArch64, const std::string& methodName) const
422 {
423 CheckNullInput();
424 CheckStateInput();
425 CheckValueInput(isArch64);
426 CheckDependInput();
427 CheckFrameStateInput();
428 CheckRootInput();
429 CheckStateOutput(methodName);
430 CheckBranchOutput();
431 CheckNOP();
432 CheckSelector();
433 CheckRelay();
434 }
435
SetNextOut(const Out * ptr)436 void Out::SetNextOut(const Out *ptr)
437 {
438 nextOut_ =
439 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
440 static_cast<GateRef>((reinterpret_cast<const uint8_t *>(ptr)) - (reinterpret_cast<const uint8_t *>(this)));
441 }
442
GetNextOut()443 Out *Out::GetNextOut()
444 {
445 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
446 return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + nextOut_);
447 }
448
GetNextOutConst() const449 const Out *Out::GetNextOutConst() const
450 {
451 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
452 return reinterpret_cast<const Out *>((reinterpret_cast<const uint8_t *>(this)) + nextOut_);
453 }
454
SetPrevOut(const Out * ptr)455 void Out::SetPrevOut(const Out *ptr)
456 {
457 prevOut_ =
458 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
459 static_cast<GateRef>((reinterpret_cast<const uint8_t *>(ptr)) - (reinterpret_cast<const uint8_t *>(this)));
460 }
461
GetPrevOut()462 Out *Out::GetPrevOut()
463 {
464 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
465 return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + prevOut_);
466 }
467
GetPrevOutConst() const468 const Out *Out::GetPrevOutConst() const
469 {
470 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
471 return reinterpret_cast<const Out *>((reinterpret_cast<const uint8_t *>(this)) + prevOut_);
472 }
473
SetIndex(OutIdx idx)474 void Out::SetIndex(OutIdx idx)
475 {
476 idx_ = idx;
477 }
478
GetIndex() const479 OutIdx Out::GetIndex() const
480 {
481 return idx_;
482 }
483
GetGate()484 Gate *Out::GetGate()
485 {
486 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
487 return reinterpret_cast<Gate *>(&this[idx_ + 1]);
488 }
489
GetGateConst() const490 const Gate *Out::GetGateConst() const
491 {
492 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
493 return reinterpret_cast<const Gate *>(&this[idx_ + 1]);
494 }
495
SetPrevOutNull()496 void Out::SetPrevOutNull()
497 {
498 prevOut_ = 0;
499 }
500
IsPrevOutNull() const501 bool Out::IsPrevOutNull() const
502 {
503 return prevOut_ == 0;
504 }
505
SetNextOutNull()506 void Out::SetNextOutNull()
507 {
508 nextOut_ = 0;
509 }
510
IsNextOutNull() const511 bool Out::IsNextOutNull() const
512 {
513 return nextOut_ == 0;
514 }
515
IsStateEdge() const516 bool Out::IsStateEdge() const
517 {
518 return idx_ < GetGateConst()->GetStateCount();
519 }
520
SetGate(const Gate * ptr)521 void In::SetGate(const Gate *ptr)
522 {
523 gatePtr_ =
524 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
525 static_cast<GateRef>((reinterpret_cast<const uint8_t *>(ptr)) - (reinterpret_cast<const uint8_t *>(this)));
526 }
527
GetGate()528 Gate *In::GetGate()
529 {
530 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
531 return reinterpret_cast<Gate *>((reinterpret_cast<uint8_t *>(this)) + gatePtr_);
532 }
533
GetGateConst() const534 const Gate *In::GetGateConst() const
535 {
536 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
537 return reinterpret_cast<const Gate *>((reinterpret_cast<const uint8_t *>(this)) + gatePtr_);
538 }
539
SetGateNull()540 void In::SetGateNull()
541 {
542 gatePtr_ = Gate::InvalidGateRef;
543 }
544
IsGateNull() const545 bool In::IsGateNull() const
546 {
547 return gatePtr_ == Gate::InvalidGateRef;
548 }
549
550 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
Gate(const GateMetaData * meta,GateId id,Gate * inList[],MachineType machineType,GateType type)551 Gate::Gate(const GateMetaData* meta, GateId id, Gate *inList[], MachineType machineType, GateType type)
552 : meta_(meta), id_(id), type_(type), machineType_(machineType)
553 {
554 auto numIns = GetNumIns();
555 if (numIns == 0) {
556 auto curOut = GetOut(0);
557 curOut->SetIndex(0);
558 return;
559 }
560 for (size_t idx = 0; idx < numIns; idx++) {
561 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
562 auto in = inList[idx];
563 if (in == nullptr) {
564 GetIn(idx)->SetGateNull();
565 } else {
566 NewIn(idx, in);
567 }
568 auto curOut = GetOut(idx);
569 curOut->SetIndex(idx);
570 }
571 }
572
NewIn(size_t idx,Gate * in)573 void Gate::NewIn(size_t idx, Gate *in)
574 {
575 GetIn(idx)->SetGate(in);
576 auto curOut = GetOut(idx);
577 if (in->IsFirstOutNull()) {
578 curOut->SetNextOutNull();
579 } else {
580 curOut->SetNextOut(in->GetFirstOut());
581 in->GetFirstOut()->SetPrevOut(curOut);
582 }
583 curOut->SetPrevOutNull();
584 in->SetFirstOut(curOut);
585 }
586
ModifyIn(size_t idx,Gate * in)587 void Gate::ModifyIn(size_t idx, Gate *in)
588 {
589 DeleteIn(idx);
590 NewIn(idx, in);
591 }
592
DeleteIn(size_t idx)593 void Gate::DeleteIn(size_t idx)
594 {
595 if (!GetOut(idx)->IsNextOutNull() && !GetOut(idx)->IsPrevOutNull()) {
596 GetOut(idx)->GetPrevOut()->SetNextOut(GetOut(idx)->GetNextOut());
597 GetOut(idx)->GetNextOut()->SetPrevOut(GetOut(idx)->GetPrevOut());
598 } else if (GetOut(idx)->IsNextOutNull() && !GetOut(idx)->IsPrevOutNull()) {
599 GetOut(idx)->GetPrevOut()->SetNextOutNull();
600 } else if (!GetOut(idx)->IsNextOutNull()) { // then GetOut(idx)->IsPrevOutNull() is true
601 GetIn(idx)->GetGate()->SetFirstOut(GetOut(idx)->GetNextOut());
602 GetOut(idx)->GetNextOut()->SetPrevOutNull();
603 } else { // only this out now
604 GetIn(idx)->GetGate()->SetFirstOutNull();
605 }
606 GetIn(idx)->SetGateNull();
607 }
608
DeleteGate()609 void Gate::DeleteGate()
610 {
611 auto numIns = GetNumIns();
612 for (size_t idx = 0; idx < numIns; idx++) {
613 DeleteIn(idx);
614 }
615 }
616
GetOut(size_t idx)617 Out *Gate::GetOut(size_t idx)
618 {
619 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
620 return &reinterpret_cast<Out *>(this)[-1 - idx];
621 }
622
GetOutConst(size_t idx) const623 const Out *Gate::GetOutConst(size_t idx) const
624 {
625 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
626 return &reinterpret_cast<const Out *>(this)[-1 - idx];
627 }
628
GetFirstOut()629 Out *Gate::GetFirstOut()
630 {
631 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
632 return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + firstOut_);
633 }
634
GetFirstOutConst() const635 const Out *Gate::GetFirstOutConst() const
636 {
637 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
638 return reinterpret_cast<const Out *>((reinterpret_cast<const uint8_t *>(this)) + firstOut_);
639 }
640
SetFirstOutNull()641 void Gate::SetFirstOutNull()
642 {
643 firstOut_ = 0;
644 }
645
IsFirstOutNull() const646 bool Gate::IsFirstOutNull() const
647 {
648 return firstOut_ == 0;
649 }
650
SetFirstOut(const Out * firstOut)651 void Gate::SetFirstOut(const Out *firstOut)
652 {
653 firstOut_ =
654 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
655 static_cast<GateRef>(reinterpret_cast<const uint8_t *>(firstOut) - reinterpret_cast<const uint8_t *>(this));
656 }
657
GetIn(size_t idx)658 In *Gate::GetIn(size_t idx)
659 {
660 #ifndef NDEBUG
661 if (idx >= GetNumIns()) {
662 LOG_COMPILER(INFO) << std::dec << "Gate In access out-of-bound! (idx=" << idx << ")";
663 Print();
664 ASSERT(false);
665 }
666 #endif
667 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
668 return &reinterpret_cast<In *>(this + 1)[idx];
669 }
670
GetInConst(size_t idx) const671 const In *Gate::GetInConst(size_t idx) const
672 {
673 #ifndef NDEBUG
674 if (idx >= GetNumIns()) {
675 LOG_COMPILER(INFO) << std::dec << "Gate In access out-of-bound! (idx=" << idx << ")";
676 Print();
677 ASSERT(false);
678 }
679 #endif
680 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
681 return &reinterpret_cast<const In *>(this + 1)[idx];
682 }
683
GetInGate(size_t idx)684 Gate *Gate::GetInGate(size_t idx)
685 {
686 return GetIn(idx)->GetGate();
687 }
688
GetInGateConst(size_t idx) const689 const Gate *Gate::GetInGateConst(size_t idx) const
690 {
691 return GetInConst(idx)->GetGateConst();
692 }
693
IsInGateNull(size_t idx) const694 bool Gate::IsInGateNull(size_t idx) const
695 {
696 return GetInConst(idx)->IsGateNull();
697 }
698
GetId() const699 GateId Gate::GetId() const
700 {
701 return id_;
702 }
703
GetOpCode() const704 OpCode Gate::GetOpCode() const
705 {
706 return meta_->GetOpCode();
707 }
708
GetNumIns() const709 size_t Gate::GetNumIns() const
710 {
711 return meta_->GetNumIns();
712 }
713
GetInValueStarts() const714 size_t Gate::GetInValueStarts() const
715 {
716 return meta_->GetInValueStarts();
717 }
718
GetInFrameStateStarts() const719 size_t Gate::GetInFrameStateStarts() const
720 {
721 return meta_->GetInFrameStateStarts();
722 }
723
GetStateCount() const724 size_t Gate::GetStateCount() const
725 {
726 return meta_->GetStateCount();
727 }
728
GetDependCount() const729 size_t Gate::GetDependCount() const
730 {
731 return meta_->GetDependCount();
732 }
733
GetInValueCount() const734 size_t Gate::GetInValueCount() const
735 {
736 return meta_->GetInValueCount();
737 }
738
GetInFrameStateCount() const739 size_t Gate::GetInFrameStateCount() const
740 {
741 return meta_->GetInFrameStateCount();
742 }
743
GetRootCount() const744 size_t Gate::GetRootCount() const
745 {
746 return meta_->GetRootCount();
747 }
748
MachineTypeStr(MachineType machineType) const749 std::string Gate::MachineTypeStr(MachineType machineType) const
750 {
751 const std::map<MachineType, const char *> strMap = {
752 {NOVALUE, "NOVALUE"},
753 {ANYVALUE, "ANYVALUE"},
754 {ARCH, "ARCH"},
755 {FLEX, "FLEX"},
756 {I1, "I1"},
757 {I8, "I8"},
758 {I16, "I16"},
759 {I32, "I32"},
760 {I64, "I64"},
761 {F32, "F32"},
762 {F64, "F64"},
763 };
764 if (strMap.count(machineType) > 0) {
765 return strMap.at(machineType);
766 }
767 return "MachineType-" + std::to_string(machineType);
768 }
769
GateTypeStr(GateType gateType) const770 std::string Gate::GateTypeStr(GateType gateType) const
771 {
772 static const std::map<GateType, const char *> strMap = {
773 {GateType::NJSValue(), "NJS_VALUE"},
774 {GateType::TaggedValue(), "TAGGED_VALUE"},
775 {GateType::TaggedPointer(), "TAGGED_POINTER"},
776 {GateType::TaggedNPointer(), "TAGGED_NPOINTER"},
777 {GateType::Empty(), "EMPTY"},
778 {GateType::AnyType(), "ANY_TYPE"},
779 };
780
781 std::string name = "";
782 if (strMap.count(gateType) > 0) {
783 name = strMap.at(gateType);
784 }
785 uint32_t r = gateType.GetType();
786 return name + std::string("-gateType(") + std::to_string(r) + std::string(")");
787 }
788
Print(std::string additionOp,bool inListPreview,size_t highlightIdx,std::string_view comment) const789 void Gate::Print(std::string additionOp, bool inListPreview, size_t highlightIdx, std::string_view comment) const
790 {
791 LOG_COMPILER(INFO) << ToString(additionOp, inListPreview, highlightIdx, comment);
792 }
793
DumpHeader(std::ostringstream & oss,const std::string & additionOp) const794 void Gate::DumpHeader(std::ostringstream &oss, const std::string& additionOp) const
795 {
796 auto opcode = GetOpCode();
797 ASSERT(opcode != OpCode::NOP && opcode != OpCode::DEAD);
798
799 oss << "{\"id\":" << std::to_string(id_) << ", \"op\":\"" << GateMetaData::Str(opcode) << "\", ";
800 if (additionOp.compare("") != 0) {
801 auto additionOpName = (opcode == OpCode::JS_BYTECODE) ? "bytecode" : "typedop";
802 oss << "\"" << additionOpName << "\":\"" << additionOp;
803 oss << "\", ";
804 }
805 oss << "\"MType\":\"" << MachineTypeStr(GetMachineType()) << ", ";
806
807 oss << "bitfield=0x" << std::hex << TryGetValue() << std::dec << ", ";
808 oss << "type=" << GateTypeStr(type_) << ", ";
809 oss << "stamp=" << std::to_string(static_cast<uint32_t>(stamp_)) << ", ";
810 oss << "mark=" << std::to_string(static_cast<uint32_t>(mark_)) << ", ";
811 }
812
DumpInputs(std::ostringstream & oss,bool inListPreview,size_t highlightIdx) const813 void Gate::DumpInputs(std::ostringstream &oss, bool inListPreview, size_t highlightIdx) const
814 {
815 [[maybe_unused]] auto opcode = GetOpCode();
816 ASSERT(opcode != OpCode::NOP && opcode != OpCode::DEAD);
817
818 size_t idx = 0;
819 auto stateSize = GetStateCount();
820 auto dependSize = GetDependCount();
821 auto valueSize = GetInValueCount();
822 auto frameStateSize = GetInFrameStateCount();
823 auto rootSize = GetRootCount();
824 size_t start = 0;
825 size_t end = stateSize;
826
827 oss << "\",\"in\":[";
828 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, oss);
829 end += dependSize;
830 start += stateSize;
831 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, oss);
832 end += valueSize;
833 start += dependSize;
834 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, oss);
835 end += frameStateSize;
836 start += valueSize;
837 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, oss);
838 end += rootSize;
839 start += frameStateSize;
840 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, oss, true);
841 oss << "]";
842 }
843
DumpOutputs(std::ostringstream & oss,bool inListPreview) const844 void Gate::DumpOutputs(std::ostringstream &oss, bool inListPreview) const
845 {
846 auto opcode = GetOpCode();
847 ASSERT(opcode != OpCode::NOP && opcode != OpCode::DEAD);
848
849 oss << ", \"out\":[";
850 if (!IsFirstOutNull()) {
851 const Out *curOut = GetFirstOutConst();
852 opcode = curOut->GetGateConst()->GetOpCode();
853 oss << std::to_string(curOut->GetGateConst()->GetId()) +
854 (inListPreview ? std::string(":" + GateMetaData::Str(opcode)) : std::string(""));
855
856 while (!curOut->IsNextOutNull()) {
857 curOut = curOut->GetNextOutConst();
858 oss << ", " + std::to_string(curOut->GetGateConst()->GetId()) +
859 (inListPreview ? std::string(":" + GateMetaData::Str(opcode))
860 : std::string(""));
861 }
862 }
863 oss << "]";
864 }
865
DumpComment(std::ostringstream & oss,std::string_view comment)866 static void DumpComment(std::ostringstream &oss, std::string_view comment)
867 {
868 oss << ", \"comment\":\"" << comment << "\"";
869 }
870
ToString(std::string additionOp,bool inListPreview,size_t highlightIdx,std::string_view comment) const871 std::string Gate::ToString(std::string additionOp, bool inListPreview, size_t highlightIdx,
872 std::string_view comment) const
873 {
874 auto opcode = GetOpCode();
875 if (opcode == OpCode::NOP || opcode == OpCode::DEAD) {
876 return "";
877 }
878
879 std::ostringstream oss;
880 oss << std::dec;
881 DumpHeader(oss, additionOp);
882 DumpInputs(oss, inListPreview, highlightIdx);
883 DumpOutputs(oss, inListPreview);
884 if (!comment.empty()) {
885 DumpComment(oss, comment);
886 }
887 oss << "},";
888 return oss.str();
889 }
890
ShortPrint(std::string bytecode,bool inListPreview,size_t highlightIdx) const891 void Gate::ShortPrint(std::string bytecode, bool inListPreview, size_t highlightIdx) const
892 {
893 auto opcode = GetOpCode();
894 if (opcode != OpCode::NOP && opcode != OpCode::DEAD) {
895 std::ostringstream log;
896 log << "(\"id\"=" << std::to_string(id_) << ", \"op\"=\"" << GateMetaData::Str(opcode) << "\", ";
897 log << ((bytecode.compare("") == 0) ? "" : "bytecode=") << bytecode;
898 log << ((bytecode.compare("") == 0) ? "" : ", ");
899 log << "\"MType\"=\"" + MachineTypeStr(GetMachineType()) + ", ";
900 log << "bitfield=0x" << std::hex << TryGetValue() << std::dec << ", ";
901 log << "type=" + GateTypeStr(type_) + ", ";
902 log << "\", in=[";
903
904 size_t idx = 0;
905 auto stateSize = GetStateCount();
906 auto dependSize = GetDependCount();
907 auto valueSize = GetInValueCount();
908 auto frameStateSize = GetInFrameStateCount();
909 auto rootSize = GetRootCount();
910 size_t start = 0;
911 size_t end = stateSize;
912 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
913 end += dependSize;
914 start += stateSize;
915 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
916 end += valueSize;
917 start += dependSize;
918 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
919 end += frameStateSize;
920 start += valueSize;
921 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
922 end += rootSize;
923 start += frameStateSize;
924 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log, true);
925
926 log << "], out=[";
927
928 if (!IsFirstOutNull()) {
929 const Out *curOut = GetFirstOutConst();
930 opcode = curOut->GetGateConst()->GetOpCode();
931 log << std::to_string(curOut->GetGateConst()->GetId()) <<
932 (inListPreview ? std::string(":" + GateMetaData::Str(opcode)) : std::string(""));
933
934 while (!curOut->IsNextOutNull()) {
935 curOut = curOut->GetNextOutConst();
936 log << ", " << std::to_string(curOut->GetGateConst()->GetId()) <<
937 (inListPreview ? std::string(":" + GateMetaData::Str(opcode))
938 : std::string(""));
939 }
940 }
941 log << "])";
942 LOG_COMPILER(INFO) << std::dec << log.str();
943 }
944 }
945
PrintInGate(size_t numIns,size_t idx,size_t size,bool inListPreview,size_t highlightIdx,std::ostringstream & log,bool isEnd) const946 size_t Gate::PrintInGate(size_t numIns, size_t idx, size_t size, bool inListPreview, size_t highlightIdx,
947 std::ostringstream &log, bool isEnd) const
948 {
949 log << "[";
950 for (; idx < numIns; idx++) {
951 log << ((idx == size) ? "" : ", ");
952 log << ((idx == highlightIdx) ? "\033[4;31m" : "");
953 log << ((IsInGateNull(idx)
954 ? "N"
955 : (std::to_string(GetInGateConst(idx)->GetId()) +
956 (inListPreview ? std::string(":" + GateMetaData::Str(GetInGateConst(idx)->GetOpCode()))
957 : std::string("")))));
958 log << ((idx == highlightIdx) ? "\033[0m" : "");
959 }
960 log << "]";
961 log << ((isEnd) ? "" : ", ");
962 return idx;
963 }
964
GetBytecodeStr() const965 std::string Gate::GetBytecodeStr() const
966 {
967 switch (GetOpCode()) {
968 case OpCode::JS_BYTECODE: {
969 return GetJSBytecodeMetaData()->Str();
970 }
971 case OpCode::TYPED_BINARY_OP: {
972 auto typedOp = TypedBinaryAccessor(GetOneParameterMetaData()->GetValue()).GetTypedBinOp();
973 return GateMetaData::Str(typedOp);
974 }
975 case OpCode::TYPED_UNARY_OP: {
976 auto typedOp = TypedUnaryAccessor(GetOneParameterMetaData()->GetValue()).GetTypedUnOp();
977 return GateMetaData::Str(typedOp);
978 }
979 case OpCode::TYPED_CONDITION_JUMP: {
980 auto typedOp = TypedJumpAccessor(GetOneParameterMetaData()->GetValue()).GetTypedJumpOp();
981 return GateMetaData::Str(typedOp);
982 }
983 case OpCode::LOAD_ELEMENT: {
984 auto typedOp = static_cast<TypedLoadOp>(GetOneParameterMetaData()->GetValue());
985 return GateMetaData::Str(typedOp);
986 }
987 case OpCode::STORE_ELEMENT: {
988 auto typedOp = static_cast<TypedStoreOp>(GetOneParameterMetaData()->GetValue());
989 return GateMetaData::Str(typedOp);
990 }
991 case OpCode::TYPED_CALLTARGETCHECK_OP: {
992 TypedCallTargetCheckAccessor accessor(GetOneParameterMetaData()->GetValue());
993 auto typedOp = accessor.GetCallTargetCheckOp();
994 return GateMetaData::Str(typedOp);
995 }
996 case OpCode::CONVERT:
997 case OpCode::CHECK_AND_CONVERT: {
998 ValuePairTypeAccessor accessor(GetOneParameterMetaData()->GetValue());
999 return GateMetaData::Str(accessor.GetSrcType()) + "_TO_" +
1000 GateMetaData::Str(accessor.GetDstType());
1001 }
1002 default:
1003 return "";
1004 }
1005 return "";
1006 }
1007
PrintWithBytecode(std::string_view comment) const1008 void Gate::PrintWithBytecode(std::string_view comment) const
1009 {
1010 PrintGateWithAdditionOp(GetBytecodeStr(), comment);
1011 }
1012
PrintGateWithAdditionOp(std::string additionOp,std::string_view comment) const1013 void Gate::PrintGateWithAdditionOp(std::string additionOp, std::string_view comment) const
1014 {
1015 Print(additionOp, false, -1, comment);
1016 }
1017
GetMark(TimeStamp stamp) const1018 MarkCode Gate::GetMark(TimeStamp stamp) const
1019 {
1020 return (stamp_ == stamp) ? mark_ : MarkCode::NO_MARK;
1021 }
1022
SetMark(MarkCode mark,TimeStamp stamp)1023 void Gate::SetMark(MarkCode mark, TimeStamp stamp)
1024 {
1025 stamp_ = stamp;
1026 mark_ = mark;
1027 }
1028 } // namespace panda::ecmascript::kungfu
1029