• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <iostream>
18 #include <sstream>
19 
20 namespace panda::ecmascript::kungfu {
CheckNullInput() const21 void Gate::CheckNullInput() const
22 {
23     const auto numIns = GetNumIns();
24     for (size_t idx = 0; idx < numIns; idx++) {
25         if (IsInGateNull(idx)) {
26             CheckFailed("In list contains null", idx);
27         }
28     }
29 }
30 
CheckFailed(std::string errorString,size_t highlightIdx) const31 void Gate::CheckFailed(std::string errorString, size_t highlightIdx) const
32 {
33     LOG_COMPILER(ERROR) << "[Verifier][Error] Gate level input list schema verify failed";
34     Print("", true, highlightIdx);
35     LOG_COMPILER(FATAL) << "Note: " << errorString;
36 }
37 
CheckInputOpcode(size_t idx,OpCode expected) const38 void Gate::CheckInputOpcode(size_t idx, OpCode expected) const
39 {
40     OpCode actual = GetInGateConst(idx)->GetOpCode();
41     if (actual != expected) {
42         CheckFailed("State input does not match (expected:" + GateMetaData::Str(expected) +
43                     " actual:" + GateMetaData::Str(actual) + ")", idx);
44     }
45 }
46 
CheckInputMachineType(size_t idx,MachineType expected,bool isArch64) const47 void Gate::CheckInputMachineType(size_t idx, MachineType expected, bool isArch64) const
48 {
49     MachineType actual = GetInGateConst(idx)->GetMachineType();
50     if (expected == MachineType::FLEX) {
51         expected = GetMachineType();
52     }
53     if (expected == MachineType::ARCH) {
54         expected = isArch64 ? MachineType::I64 : MachineType::I32;
55     }
56     if (actual == MachineType::ARCH) {
57         actual = isArch64 ? MachineType::I64 : MachineType::I32;
58     }
59     if (actual != expected) {
60         CheckFailed("Value input does not match (expected:" +
61                     MachineTypeToStr(expected) + " actual:" + MachineTypeToStr(actual) + ")", idx);
62     }
63 }
64 
CheckNotInputMachineType(size_t idx,MachineType notExpected) const65 void Gate::CheckNotInputMachineType(size_t idx, MachineType notExpected) const
66 {
67     MachineType actual = GetInGateConst(idx)->GetMachineType();
68     if (actual == notExpected) {
69         CheckFailed("Value input does not match (notExpected:" +
70                     MachineTypeToStr(notExpected) + " actual:" + MachineTypeToStr(actual) + ")", idx);
71     }
72 }
73 
CheckGeneralState(size_t idx) const74 void Gate::CheckGeneralState(size_t idx) const
75 {
76     auto gatePtr = GetInGateConst(idx);
77     OpCode actual = gatePtr->GetOpCode();
78     if (!gatePtr->meta_->IsGeneralState()) {
79         CheckFailed("State input does not match (expected:<General State> actual:" +
80                     GateMetaData::Str(actual) + ")", idx);
81     }
82 }
83 
CheckStateInput() const84 void Gate::CheckStateInput() const
85 {
86     size_t stateStart = 0;
87     size_t stateEnd = GetStateCount();
88     for (size_t idx = stateStart; idx < stateEnd; idx++) {
89         bool needCheck = true;
90         switch (GetOpCode()) {
91             case OpCode::IF_TRUE:
92             case OpCode::IF_FALSE:
93                 ASSERT(idx == stateStart);
94                 CheckInputOpcode(idx, OpCode::IF_BRANCH);
95                 needCheck = false;
96                 break;
97             case OpCode::SWITCH_CASE:
98             case OpCode::DEFAULT_CASE:
99                 ASSERT(idx == stateStart);
100                 CheckInputOpcode(idx, OpCode::SWITCH_BRANCH);
101                 needCheck = false;
102                 break;
103             case OpCode::LOOP_BEGIN:
104                 if (idx == stateStart + 1) { // 1: idx 1
105                     CheckInputOpcode(idx, OpCode::LOOP_BACK);
106                     needCheck = false;
107                 }
108                 break;
109             default:
110                 break;
111         }
112         if (needCheck) {
113             CheckGeneralState(idx);
114         }
115     }
116 }
117 
CheckValueInput(bool isArch64) const118 void Gate::CheckValueInput(bool isArch64) const
119 {
120     size_t valueStart = GetInValueStarts();
121     size_t valueEnd = valueStart + GetInValueCount();
122     for (size_t idx = valueStart; idx < valueEnd; idx++) {
123         switch (GetOpCode()) {
124             case OpCode::IF_BRANCH:
125                 ASSERT(idx == valueStart);
126                 CheckInputMachineType(idx, MachineType::I1, isArch64);
127                 break;
128             case OpCode::VALUE_SELECTOR:
129             case OpCode::ADD:
130             case OpCode::SUB:
131             case OpCode::MUL:
132             case OpCode::EXP:
133             case OpCode::SDIV:
134             case OpCode::SMOD:
135             case OpCode::UDIV:
136             case OpCode::UMOD:
137             case OpCode::FDIV:
138             case OpCode::FMOD:
139             case OpCode::AND:
140             case OpCode::XOR:
141             case OpCode::OR:
142             case OpCode::LSL:
143             case OpCode::LSR:
144             case OpCode::ASR:
145                 CheckInputMachineType(idx, MachineType::FLEX, isArch64);
146                 break;
147             case OpCode::REV:
148                 ASSERT(idx == valueStart);
149                 CheckInputMachineType(idx, MachineType::I1, isArch64);
150                 break;
151             case OpCode::LOAD:
152                 ASSERT(idx == valueStart);
153                 CheckInputMachineType(idx, MachineType::ARCH, isArch64);
154                 break;
155             case OpCode::STORE:
156                 if (idx == valueStart + 1) { // 1: idx 1
157                     CheckInputMachineType(idx, MachineType::ARCH, isArch64);
158                 }
159                 break;
160             case OpCode::HEAP_ALLOC:
161             case OpCode::TAGGED_TO_INT64:
162             case OpCode::INT64_TO_TAGGED:
163                 ASSERT(idx == valueStart);
164                 CheckInputMachineType(valueStart, MachineType::I64, isArch64);
165                 break;
166             case OpCode::OBJECT_TYPE_CHECK:
167             case OpCode::LOAD_ELEMENT:
168             case OpCode::STORE_ELEMENT:
169                 if (idx == valueStart + 1) { // 1: idx 1
170                     CheckInputMachineType(idx, MachineType::I64, isArch64);
171                 }
172                 break;
173             case OpCode::FCMP:
174                 CheckInputMachineType(idx, MachineType::F64, isArch64);
175                 break;
176             case OpCode::ICMP:
177                 CheckNotInputMachineType(idx, MachineType::F64);
178                 break;
179             default:
180                 break;
181         }
182     }
183 }
184 
CheckDependInput() const185 void Gate::CheckDependInput() const
186 {
187     size_t dependStart = GetStateCount();
188     size_t dependEnd = dependStart + GetDependCount();
189     for (size_t idx = dependStart; idx < dependEnd; idx++) {
190         if (GetInGateConst(idx)->GetDependCount() == 0 &&
191             GetInGateConst(idx)->GetOpCode() != OpCode::DEPEND_ENTRY) {
192             CheckFailed("Depend input is side-effect free", idx);
193         }
194     }
195 }
196 
CheckRootInput() const197 void Gate::CheckRootInput() const
198 {
199     size_t rootStart = GetInValueStarts() + GetInValueCount();
200     if (meta_->HasRoot()) {
201         switch (GetOpCode()) {
202             case OpCode::STATE_ENTRY:
203             case OpCode::DEPEND_ENTRY:
204             case OpCode::RETURN_LIST:
205             case OpCode::ARG_LIST:
206                 CheckInputOpcode(rootStart, OpCode::CIRCUIT_ROOT);
207                 break;
208             case OpCode::ARG:
209                 CheckInputOpcode(rootStart, OpCode::ARG_LIST);
210                 break;
211             case OpCode::RETURN:
212             case OpCode::RETURN_VOID:
213                 CheckInputOpcode(rootStart, OpCode::RETURN_LIST);
214                 break;
215             default:
216                 break;
217         }
218     }
219 }
220 
CheckFrameStateInput() const221 void Gate::CheckFrameStateInput() const
222 {
223     size_t frameStateStart = GetInFrameStateStarts();
224     if (meta_->HasFrameState()) {
225         CheckInputOpcode(frameStateStart, OpCode::FRAME_STATE);
226     }
227 }
228 
CheckStateOutput() const229 void Gate::CheckStateOutput() const
230 {
231     if (GetMetaData()->IsState()) {
232         size_t cnt = 0;
233         const Gate *curGate = this;
234         if (!curGate->IsFirstOutNull()) {
235             const Out *curOut = curGate->GetFirstOutConst();
236             auto meta = curOut->GetGateConst()->GetMetaData();
237             if (curOut->IsStateEdge() && meta->IsState()) {
238                 cnt++;
239             }
240             while (!curOut->IsNextOutNull()) {
241                 curOut = curOut->GetNextOutConst();
242                 meta = curOut->GetGateConst()->GetMetaData();
243                 if (curOut->IsStateEdge() && meta->IsState()) {
244                     cnt++;
245                 }
246             }
247         }
248         size_t expected = 0;
249         bool needCheck = true;
250         if (GetMetaData()->IsTerminalState()) {
251             expected = 0;
252         } else if (GetOpCode() == OpCode::IF_BRANCH || GetOpCode() == OpCode::JS_BYTECODE) {
253             expected = 2; // 2: expected number of state out branches
254         } else if (GetOpCode() == OpCode::SWITCH_BRANCH) {
255             needCheck = false;
256         } else {
257             expected = 1;
258         }
259         if (needCheck && cnt != expected) {
260             curGate->Print();
261             CheckFailed("Number of state out branches is not valid (expected:" + std::to_string(expected) +
262                 " actual:" + std::to_string(cnt) + ")", -1);
263         }
264     }
265 }
266 
CheckBranchOutput() const267 void Gate::CheckBranchOutput() const
268 {
269     std::map<std::pair<OpCode, BitField>, size_t> setOfOps;
270     if (GetOpCode() == OpCode::IF_BRANCH) {
271         size_t cnt = 0;
272         const Gate *curGate = this;
273         if (!curGate->IsFirstOutNull()) {
274             const Out *curOut = curGate->GetFirstOutConst();
275             if (curOut->GetGateConst()->GetMetaData()->IsState() && curOut->IsStateEdge()) {
276                 ASSERT(!curOut->GetGateConst()->GetMetaData()->IsFixed());
277                 setOfOps[{curOut->GetGateConst()->GetOpCode(), curOut->GetGateConst()->GetStateCount()}]++;
278                 cnt++;
279             }
280             while (!curOut->IsNextOutNull()) {
281                 curOut = curOut->GetNextOutConst();
282                 if (curOut->GetGateConst()->GetMetaData()->IsState() && curOut->IsStateEdge()) {
283                     ASSERT(!curOut->GetGateConst()->GetMetaData()->IsFixed());
284                     setOfOps[{curOut->GetGateConst()->GetOpCode(), curOut->GetGateConst()->GetStateCount()}]++;
285                     cnt++;
286                 }
287             }
288         }
289         if (setOfOps.size() != cnt) {
290             CheckFailed("Duplicate state out branches", -1);
291         }
292     }
293 }
294 
CheckNOP() const295 void Gate::CheckNOP() const
296 {
297     if (GetOpCode() == OpCode::NOP || GetOpCode() == OpCode::DEAD) {
298         if (!IsFirstOutNull()) {
299             CheckFailed("NOP gate used by other gates", -1);
300         }
301     }
302 }
303 
CheckSelector() const304 void Gate::CheckSelector() const
305 {
306     if (GetOpCode() == OpCode::VALUE_SELECTOR || GetOpCode() == OpCode::DEPEND_SELECTOR) {
307         auto stateOp = GetInGateConst(0)->GetOpCode();
308         if (stateOp == OpCode::MERGE || stateOp == OpCode::LOOP_BEGIN) {
309             if (GetInGateConst(0)->GetNumIns() != GetNumIns() - 1) {
310                 if (GetOpCode() == OpCode::DEPEND_SELECTOR) {
311                     CheckFailed("Number of depend flows does not match control flows (expected:" +
312                             std::to_string(GetInGateConst(0)->GetNumIns()) +
313                             " actual:" + std::to_string(GetNumIns() - 1) + ")",
314                         -1);
315                 } else {
316                     CheckFailed("Number of data flows does not match control flows (expected:" +
317                             std::to_string(GetInGateConst(0)->GetNumIns()) +
318                             " actual:" + std::to_string(GetNumIns() - 1) + ")",
319                         -1);
320                 }
321             }
322         } else {
323             CheckFailed(
324                 "State input does not match (expected:[MERGE|LOOP_BEGIN] actual:" +
325                 GateMetaData::Str(stateOp) + ")", 0);
326         }
327     }
328 }
329 
CheckRelay() const330 void Gate::CheckRelay() const
331 {
332     if (GetOpCode() == OpCode::DEPEND_RELAY) {
333         auto stateOp = GetInGateConst(0)->GetOpCode();
334         if (!(stateOp == OpCode::IF_TRUE || stateOp == OpCode::IF_FALSE || stateOp == OpCode::SWITCH_CASE ||
335             stateOp == OpCode::DEFAULT_CASE || stateOp == OpCode::IF_SUCCESS || stateOp == OpCode::IF_EXCEPTION ||
336             stateOp == OpCode::ORDINARY_BLOCK)) {
337             CheckFailed("State input does not match ("
338                 "expected:[IF_TRUE|IF_FALSE|SWITCH_CASE|DEFAULT_CASE|IF_SUCCESS|IF_EXCEPTION|ORDINARY_BLOCK] actual:" +
339                 GateMetaData::Str(stateOp) + ")", 0);
340         }
341     }
342 }
343 
Verify(bool isArch64) const344 void Gate::Verify(bool isArch64) const
345 {
346     CheckNullInput();
347     CheckStateInput();
348     CheckValueInput(isArch64);
349     CheckDependInput();
350     CheckFrameStateInput();
351     CheckRootInput();
352     CheckStateOutput();
353     CheckBranchOutput();
354     CheckNOP();
355     CheckSelector();
356     CheckRelay();
357 }
358 
SetNextOut(const Out * ptr)359 void Out::SetNextOut(const Out *ptr)
360 {
361     nextOut_ =
362         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
363         static_cast<GateRef>((reinterpret_cast<const uint8_t *>(ptr)) - (reinterpret_cast<const uint8_t *>(this)));
364 }
365 
GetNextOut()366 Out *Out::GetNextOut()
367 {
368     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
369     return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + nextOut_);
370 }
371 
GetNextOutConst() const372 const Out *Out::GetNextOutConst() const
373 {
374     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
375     return reinterpret_cast<const Out *>((reinterpret_cast<const uint8_t *>(this)) + nextOut_);
376 }
377 
SetPrevOut(const Out * ptr)378 void Out::SetPrevOut(const Out *ptr)
379 {
380     prevOut_ =
381         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
382         static_cast<GateRef>((reinterpret_cast<const uint8_t *>(ptr)) - (reinterpret_cast<const uint8_t *>(this)));
383 }
384 
GetPrevOut()385 Out *Out::GetPrevOut()
386 {
387     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
388     return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + prevOut_);
389 }
390 
GetPrevOutConst() const391 const Out *Out::GetPrevOutConst() const
392 {
393     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
394     return reinterpret_cast<const Out *>((reinterpret_cast<const uint8_t *>(this)) + prevOut_);
395 }
396 
SetIndex(OutIdx idx)397 void Out::SetIndex(OutIdx idx)
398 {
399     idx_ = idx;
400 }
401 
GetIndex() const402 OutIdx Out::GetIndex() const
403 {
404     return idx_;
405 }
406 
GetGate()407 Gate *Out::GetGate()
408 {
409     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
410     return reinterpret_cast<Gate *>(&this[idx_ + 1]);
411 }
412 
GetGateConst() const413 const Gate *Out::GetGateConst() const
414 {
415     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
416     return reinterpret_cast<const Gate *>(&this[idx_ + 1]);
417 }
418 
SetPrevOutNull()419 void Out::SetPrevOutNull()
420 {
421     prevOut_ = 0;
422 }
423 
IsPrevOutNull() const424 bool Out::IsPrevOutNull() const
425 {
426     return prevOut_ == 0;
427 }
428 
SetNextOutNull()429 void Out::SetNextOutNull()
430 {
431     nextOut_ = 0;
432 }
433 
IsNextOutNull() const434 bool Out::IsNextOutNull() const
435 {
436     return nextOut_ == 0;
437 }
438 
IsStateEdge() const439 bool Out::IsStateEdge() const
440 {
441     return idx_ < GetGateConst()->GetStateCount();
442 }
443 
SetGate(const Gate * ptr)444 void In::SetGate(const Gate *ptr)
445 {
446     gatePtr_ =
447         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
448         static_cast<GateRef>((reinterpret_cast<const uint8_t *>(ptr)) - (reinterpret_cast<const uint8_t *>(this)));
449 }
450 
GetGate()451 Gate *In::GetGate()
452 {
453     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
454     return reinterpret_cast<Gate *>((reinterpret_cast<uint8_t *>(this)) + gatePtr_);
455 }
456 
GetGateConst() const457 const Gate *In::GetGateConst() const
458 {
459     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
460     return reinterpret_cast<const Gate *>((reinterpret_cast<const uint8_t *>(this)) + gatePtr_);
461 }
462 
SetGateNull()463 void In::SetGateNull()
464 {
465     gatePtr_ = Gate::InvalidGateRef;
466 }
467 
IsGateNull() const468 bool In::IsGateNull() const
469 {
470     return gatePtr_ == Gate::InvalidGateRef;
471 }
472 
473 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
Gate(const GateMetaData * meta,GateId id,Gate * inList[],MachineType machineType,GateType type)474 Gate::Gate(const GateMetaData* meta, GateId id, Gate *inList[], MachineType machineType, GateType type)
475     : meta_(meta), id_(id), type_(type), machineType_(machineType)
476 {
477     auto numIns = GetNumIns();
478     if (numIns == 0) {
479         auto curOut = GetOut(0);
480         curOut->SetIndex(0);
481         return;
482     }
483     for (size_t idx = 0; idx < numIns; idx++) {
484         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
485         auto in = inList[idx];
486         if (in == nullptr) {
487             GetIn(idx)->SetGateNull();
488         } else {
489             NewIn(idx, in);
490         }
491         auto curOut = GetOut(idx);
492         curOut->SetIndex(idx);
493     }
494 }
495 
NewIn(size_t idx,Gate * in)496 void Gate::NewIn(size_t idx, Gate *in)
497 {
498     GetIn(idx)->SetGate(in);
499     auto curOut = GetOut(idx);
500     if (in->IsFirstOutNull()) {
501         curOut->SetNextOutNull();
502     } else {
503         curOut->SetNextOut(in->GetFirstOut());
504         in->GetFirstOut()->SetPrevOut(curOut);
505     }
506     curOut->SetPrevOutNull();
507     in->SetFirstOut(curOut);
508 }
509 
ModifyIn(size_t idx,Gate * in)510 void Gate::ModifyIn(size_t idx, Gate *in)
511 {
512     DeleteIn(idx);
513     NewIn(idx, in);
514 }
515 
DeleteIn(size_t idx)516 void Gate::DeleteIn(size_t idx)
517 {
518     if (!GetOut(idx)->IsNextOutNull() && !GetOut(idx)->IsPrevOutNull()) {
519         GetOut(idx)->GetPrevOut()->SetNextOut(GetOut(idx)->GetNextOut());
520         GetOut(idx)->GetNextOut()->SetPrevOut(GetOut(idx)->GetPrevOut());
521     } else if (GetOut(idx)->IsNextOutNull() && !GetOut(idx)->IsPrevOutNull()) {
522         GetOut(idx)->GetPrevOut()->SetNextOutNull();
523     } else if (!GetOut(idx)->IsNextOutNull()) {  // then GetOut(idx)->IsPrevOutNull() is true
524         GetIn(idx)->GetGate()->SetFirstOut(GetOut(idx)->GetNextOut());
525         GetOut(idx)->GetNextOut()->SetPrevOutNull();
526     } else {  // only this out now
527         GetIn(idx)->GetGate()->SetFirstOutNull();
528     }
529     GetIn(idx)->SetGateNull();
530 }
531 
DeleteGate()532 void Gate::DeleteGate()
533 {
534     auto numIns = GetNumIns();
535     for (size_t idx = 0; idx < numIns; idx++) {
536         DeleteIn(idx);
537     }
538 }
539 
GetOut(size_t idx)540 Out *Gate::GetOut(size_t idx)
541 {
542     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
543     return &reinterpret_cast<Out *>(this)[-1 - idx];
544 }
545 
GetOutConst(size_t idx) const546 const Out *Gate::GetOutConst(size_t idx) const
547 {
548     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
549     return &reinterpret_cast<const Out *>(this)[-1 - idx];
550 }
551 
GetFirstOut()552 Out *Gate::GetFirstOut()
553 {
554     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
555     return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + firstOut_);
556 }
557 
GetFirstOutConst() const558 const Out *Gate::GetFirstOutConst() const
559 {
560     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
561     return reinterpret_cast<const Out *>((reinterpret_cast<const uint8_t *>(this)) + firstOut_);
562 }
563 
SetFirstOutNull()564 void Gate::SetFirstOutNull()
565 {
566     firstOut_ = 0;
567 }
568 
IsFirstOutNull() const569 bool Gate::IsFirstOutNull() const
570 {
571     return firstOut_ == 0;
572 }
573 
SetFirstOut(const Out * firstOut)574 void Gate::SetFirstOut(const Out *firstOut)
575 {
576     firstOut_ =
577         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
578         static_cast<GateRef>(reinterpret_cast<const uint8_t *>(firstOut) - reinterpret_cast<const uint8_t *>(this));
579 }
580 
GetIn(size_t idx)581 In *Gate::GetIn(size_t idx)
582 {
583 #ifndef NDEBUG
584     if (idx >= GetNumIns()) {
585         LOG_COMPILER(INFO) << std::dec << "Gate In access out-of-bound! (idx=" << idx << ")";
586         Print();
587         ASSERT(false);
588     }
589 #endif
590     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
591     return &reinterpret_cast<In *>(this + 1)[idx];
592 }
593 
GetInConst(size_t idx) const594 const In *Gate::GetInConst(size_t idx) const
595 {
596 #ifndef NDEBUG
597     if (idx >= GetNumIns()) {
598         LOG_COMPILER(INFO) << std::dec << "Gate In access out-of-bound! (idx=" << idx << ")";
599         Print();
600         ASSERT(false);
601     }
602 #endif
603     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
604     return &reinterpret_cast<const In *>(this + 1)[idx];
605 }
606 
GetInGate(size_t idx)607 Gate *Gate::GetInGate(size_t idx)
608 {
609     return GetIn(idx)->GetGate();
610 }
611 
GetInGateConst(size_t idx) const612 const Gate *Gate::GetInGateConst(size_t idx) const
613 {
614     return GetInConst(idx)->GetGateConst();
615 }
616 
IsInGateNull(size_t idx) const617 bool Gate::IsInGateNull(size_t idx) const
618 {
619     return GetInConst(idx)->IsGateNull();
620 }
621 
GetId() const622 GateId Gate::GetId() const
623 {
624     return id_;
625 }
626 
GetOpCode() const627 OpCode Gate::GetOpCode() const
628 {
629     return meta_->GetOpCode();
630 }
631 
GetNumIns() const632 size_t Gate::GetNumIns() const
633 {
634     return meta_->GetNumIns();
635 }
636 
GetInValueStarts() const637 size_t Gate::GetInValueStarts() const
638 {
639     return meta_->GetInValueStarts();
640 }
641 
GetInFrameStateStarts() const642 size_t Gate::GetInFrameStateStarts() const
643 {
644     return meta_->GetInFrameStateStarts();
645 }
646 
GetStateCount() const647 size_t Gate::GetStateCount() const
648 {
649     return meta_->GetStateCount();
650 }
651 
GetDependCount() const652 size_t Gate::GetDependCount() const
653 {
654     return meta_->GetDependCount();
655 }
656 
GetInValueCount() const657 size_t Gate::GetInValueCount() const
658 {
659     return meta_->GetInValueCount();
660 }
661 
GetInFrameStateCount() const662 size_t Gate::GetInFrameStateCount() const
663 {
664     return meta_->GetInFrameStateCount();
665 }
666 
GetRootCount() const667 size_t Gate::GetRootCount() const
668 {
669     return meta_->GetRootCount();
670 }
671 
MachineTypeStr(MachineType machineType) const672 std::string Gate::MachineTypeStr(MachineType machineType) const
673 {
674     const std::map<MachineType, const char *> strMap = {
675         {NOVALUE, "NOVALUE"},
676         {ANYVALUE, "ANYVALUE"},
677         {ARCH, "ARCH"},
678         {FLEX, "FLEX"},
679         {I1, "I1"},
680         {I8, "I8"},
681         {I16, "I16"},
682         {I32, "I32"},
683         {I64, "I64"},
684         {F32, "F32"},
685         {F64, "F64"},
686     };
687     if (strMap.count(machineType) > 0) {
688         return strMap.at(machineType);
689     }
690     return "MachineType-" + std::to_string(machineType);
691 }
692 
GateTypeStr(GateType gateType) const693 std::string Gate::GateTypeStr(GateType gateType) const
694 {
695     static const std::map<GateType, const char *> strMap = {
696         {GateType::NJSValue(), "NJS_VALUE"},
697         {GateType::TaggedValue(), "TAGGED_VALUE"},
698         {GateType::TaggedPointer(), "TAGGED_POINTER"},
699         {GateType::TaggedNPointer(), "TAGGED_NPOINTER"},
700         {GateType::Empty(), "EMPTY"},
701         {GateType::AnyType(), "ANY_TYPE"},
702     };
703 
704     std::string name = "";
705     if (strMap.count(gateType) > 0) {
706         name = strMap.at(gateType);
707     }
708     GlobalTSTypeRef r = gateType.GetGTRef();
709     uint32_t m = r.GetModuleId();
710     uint32_t l = r.GetLocalId();
711     return name + std::string("-GT(M=") + std::to_string(m) +
712            std::string(", L=") + std::to_string(l) + std::string(")");
713 }
714 
Print(std::string bytecode,bool inListPreview,size_t highlightIdx) const715 void Gate::Print(std::string bytecode, bool inListPreview, size_t highlightIdx) const
716 {
717     auto opcode = GetOpCode();
718     if (opcode != OpCode::NOP && opcode != OpCode::DEAD) {
719         std::string log("{\"id\":" + std::to_string(id_) + ", \"op\":\"" + GateMetaData::Str(opcode) + "\", ");
720         log += ((bytecode.compare("") == 0) ? "" : "\"bytecode\":\"") + bytecode;
721         log += ((bytecode.compare("") == 0) ? "" : "\", ");
722         log += "\"MType\":\"" + MachineTypeStr(GetMachineType()) + ", ";
723 
724         std::ostringstream oss;
725         oss << std::hex << TryGetValue();
726         log += "bitfield=0x" + oss.str() + ", ";
727         log += "type=" + GateTypeStr(type_) + ", ";
728         log += "stamp=" + std::to_string(static_cast<uint32_t>(stamp_)) + ", ";
729         log += "mark=" + std::to_string(static_cast<uint32_t>(mark_)) + ", ";
730         log += "\",\"in\":[";
731 
732         size_t idx = 0;
733         auto stateSize = GetStateCount();
734         auto dependSize = GetDependCount();
735         auto valueSize = GetInValueCount();
736         auto frameStateSize = GetInFrameStateCount();
737         auto rootSize = GetRootCount();
738         size_t start = 0;
739         size_t end = stateSize;
740         idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
741         end += dependSize;
742         start += stateSize;
743         idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
744         end += valueSize;
745         start += dependSize;
746         idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
747         end += frameStateSize;
748         start += valueSize;
749         idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
750         end += rootSize;
751         start += frameStateSize;
752         idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log, true);
753 
754         log += "], \"out\":[";
755 
756         if (!IsFirstOutNull()) {
757             const Out *curOut = GetFirstOutConst();
758             opcode = curOut->GetGateConst()->GetOpCode();
759             log += std::to_string(curOut->GetGateConst()->GetId()) +
760                     (inListPreview ? std::string(":" + GateMetaData::Str(opcode)) : std::string(""));
761 
762             while (!curOut->IsNextOutNull()) {
763                 curOut = curOut->GetNextOutConst();
764                 log += ", " +  std::to_string(curOut->GetGateConst()->GetId()) +
765                        (inListPreview ? std::string(":" + GateMetaData::Str(opcode))
766                                        : std::string(""));
767             }
768         }
769         log += "]},";
770         LOG_COMPILER(INFO) << std::dec << log;
771     }
772 }
773 
ShortPrint(std::string bytecode,bool inListPreview,size_t highlightIdx) const774 void Gate::ShortPrint(std::string bytecode, bool inListPreview, size_t highlightIdx) const
775 {
776     auto opcode = GetOpCode();
777     if (opcode != OpCode::NOP && opcode != OpCode::DEAD) {
778         std::string log("(\"id\"=" + std::to_string(id_) + ", \"op\"=\"" + GateMetaData::Str(opcode) + "\", ");
779         log += ((bytecode.compare("") == 0) ? "" : "bytecode=") + bytecode;
780         log += ((bytecode.compare("") == 0) ? "" : ", ");
781         log += "\"MType\"=\"" + MachineTypeStr(GetMachineType()) + ", ";
782         std::ostringstream oss;
783         oss << std::hex << TryGetValue();
784         log += "bitfield=0x" + oss.str() + ", ";
785         log += "type=" + GateTypeStr(type_) + ", ";
786         log += "\", in=[";
787 
788         size_t idx = 0;
789         auto stateSize = GetStateCount();
790         auto dependSize = GetDependCount();
791         auto valueSize = GetInValueCount();
792         auto frameStateSize = GetInFrameStateCount();
793         auto rootSize = GetRootCount();
794         size_t start = 0;
795         size_t end = stateSize;
796         idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
797         end += dependSize;
798         start += stateSize;
799         idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
800         end += valueSize;
801         start += dependSize;
802         idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
803         end += frameStateSize;
804         start += valueSize;
805         idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
806         end += rootSize;
807         start += frameStateSize;
808         idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log, true);
809 
810         log += "], out=[";
811 
812         if (!IsFirstOutNull()) {
813             const Out *curOut = GetFirstOutConst();
814             opcode = curOut->GetGateConst()->GetOpCode();
815             log += std::to_string(curOut->GetGateConst()->GetId()) +
816                    (inListPreview ? std::string(":" + GateMetaData::Str(opcode)) : std::string(""));
817 
818             while (!curOut->IsNextOutNull()) {
819                 curOut = curOut->GetNextOutConst();
820                 log += ", " +  std::to_string(curOut->GetGateConst()->GetId()) +
821                        (inListPreview ? std::string(":" + GateMetaData::Str(opcode))
822                                       : std::string(""));
823             }
824         }
825         log += "])";
826         LOG_COMPILER(INFO) << std::dec << log;
827     }
828 }
829 
PrintInGate(size_t numIns,size_t idx,size_t size,bool inListPreview,size_t highlightIdx,std::string & log,bool isEnd) const830 size_t Gate::PrintInGate(size_t numIns, size_t idx, size_t size, bool inListPreview, size_t highlightIdx,
831                          std::string &log, bool isEnd) const
832 {
833     log += "[";
834     for (; idx < numIns; idx++) {
835         log += ((idx == size) ? "" : ", ");
836         log += ((idx == highlightIdx) ? "\033[4;31m" : "");
837         log += ((IsInGateNull(idx)
838                 ? "N"
839                 : (std::to_string(GetInGateConst(idx)->GetId()) +
840                     (inListPreview ? std::string(":" + GateMetaData::Str(GetInGateConst(idx)->GetOpCode()))
841                                    : std::string("")))));
842         log += ((idx == highlightIdx) ? "\033[0m" : "");
843     }
844     log += "]";
845     log += ((isEnd) ? "" : ", ");
846     return idx;
847 }
848 
PrintByteCode(std::string bytecode) const849 void Gate::PrintByteCode(std::string bytecode) const
850 {
851     Print(bytecode);
852 }
853 
GetMark(TimeStamp stamp) const854 MarkCode Gate::GetMark(TimeStamp stamp) const
855 {
856     return (stamp_ == stamp) ? mark_ : MarkCode::NO_MARK;
857 }
858 
SetMark(MarkCode mark,TimeStamp stamp)859 void Gate::SetMark(MarkCode mark, TimeStamp stamp)
860 {
861     stamp_ = stamp;
862     mark_ = mark;
863 }
864 }  // namespace panda::ecmascript::kungfu
865