• 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  
CheckState(size_t idx) const84  void Gate::CheckState(size_t idx) const
85  {
86      auto gatePtr = GetInGateConst(idx);
87      OpCode actual = gatePtr->GetOpCode();
88      if ((actual != OpCode::STATE_ENTRY) && (!gatePtr->meta_->IsState())) {
89          CheckFailed("State input does not match (expected:<State> actual:" +
90                      GateMetaData::Str(actual) + ")", idx);
91      }
92  }
93  
CheckStateInput() const94  void Gate::CheckStateInput() const
95  {
96      size_t stateStart = 0;
97      size_t stateEnd = GetStateCount();
98      for (size_t idx = stateStart; idx < stateEnd; idx++) {
99          bool needCheck = true;
100          switch (GetOpCode()) {
101              case OpCode::IF_TRUE:
102              case OpCode::IF_FALSE:
103                  ASSERT(idx == stateStart);
104                  CheckInputOpcode(idx, OpCode::IF_BRANCH);
105                  needCheck = false;
106                  break;
107              case OpCode::SWITCH_CASE:
108              case OpCode::DEFAULT_CASE:
109                  ASSERT(idx == stateStart);
110                  CheckInputOpcode(idx, OpCode::SWITCH_BRANCH);
111                  needCheck = false;
112                  break;
113              default:
114                  break;
115          }
116          if (needCheck) {
117              CheckState(idx);
118          }
119      }
120  }
121  
CheckValueInput(bool isArch64) const122  void Gate::CheckValueInput(bool isArch64) const
123  {
124      size_t valueStart = GetInValueStarts();
125      size_t valueEnd = valueStart + GetInValueCount();
126      for (size_t idx = valueStart; idx < valueEnd; idx++) {
127          switch (GetOpCode()) {
128              case OpCode::IF_BRANCH:
129                  ASSERT(idx == valueStart);
130                  CheckInputMachineType(idx, MachineType::I1, isArch64);
131                  break;
132              case OpCode::VALUE_SELECTOR:
133              case OpCode::ADD:
134              case OpCode::SUB:
135              case OpCode::MUL:
136              case OpCode::EXP:
137              case OpCode::SDIV:
138              case OpCode::SMOD:
139              case OpCode::UDIV:
140              case OpCode::UMOD:
141              case OpCode::FDIV:
142              case OpCode::FMOD:
143              case OpCode::AND:
144              case OpCode::XOR:
145              case OpCode::OR:
146              case OpCode::LSL:
147              case OpCode::LSR:
148              case OpCode::ASR:
149                  CheckInputMachineType(idx, MachineType::FLEX, isArch64);
150                  break;
151              case OpCode::REV:
152                  ASSERT(idx == valueStart);
153                  CheckInputMachineType(idx, MachineType::I1, isArch64);
154                  break;
155              case OpCode::LOAD:
156                  ASSERT(idx == valueStart);
157                  CheckInputMachineType(idx, MachineType::ARCH, isArch64);
158                  break;
159              case OpCode::STORE:
160                  if (idx == valueStart + 1) { // 1: idx 1
161                      CheckInputMachineType(idx, MachineType::ARCH, isArch64);
162                  }
163                  break;
164              case OpCode::HEAP_ALLOC:
165              case OpCode::TAGGED_TO_INT64:
166              case OpCode::INT64_TO_TAGGED:
167                  ASSERT(idx == valueStart);
168                  CheckInputMachineType(valueStart, MachineType::I64, isArch64);
169                  break;
170              case OpCode::OBJECT_TYPE_CHECK:
171              case OpCode::LOAD_ELEMENT:
172              case OpCode::STORE_ELEMENT:
173                  if (idx == valueStart) { // 1: idx 1
174                      CheckInputMachineType(idx, MachineType::I64, isArch64);
175                  }
176                  break;
177              case OpCode::FCMP:
178                  CheckInputMachineType(idx, MachineType::F64, isArch64);
179                  break;
180              case OpCode::ICMP:
181                  CheckNotInputMachineType(idx, MachineType::F64);
182                  break;
183              default:
184                  break;
185          }
186      }
187  }
188  
CheckDependInput() const189  void Gate::CheckDependInput() const
190  {
191      size_t dependStart = GetStateCount();
192      size_t dependEnd = dependStart + GetDependCount();
193      for (size_t idx = dependStart; idx < dependEnd; idx++) {
194          if (GetInGateConst(idx)->GetDependCount() == 0 &&
195              GetInGateConst(idx)->GetOpCode() != OpCode::DEPEND_ENTRY) {
196              LOG_COMPILER(ERROR) << "depend in of " << GetId() << GateMetaData::Str(GetOpCode()) << "is "
197                  << GetInGateConst(idx)->GetId() << GateMetaData::Str(GetInGateConst(idx)->GetOpCode());
198              CheckFailed("Depend input is side-effect free", idx);
199          }
200      }
201  }
202  
CheckRootInput() const203  void Gate::CheckRootInput() const
204  {
205      size_t rootStart = GetInValueStarts() + GetInValueCount();
206      if (meta_->HasRoot()) {
207          switch (GetOpCode()) {
208              case OpCode::STATE_ENTRY:
209              case OpCode::DEPEND_ENTRY:
210              case OpCode::RETURN_LIST:
211              case OpCode::ARG_LIST:
212                  CheckInputOpcode(rootStart, OpCode::CIRCUIT_ROOT);
213                  break;
214              case OpCode::ARG:
215                  CheckInputOpcode(rootStart, OpCode::ARG_LIST);
216                  break;
217              case OpCode::RETURN:
218              case OpCode::RETURN_VOID:
219                  CheckInputOpcode(rootStart, OpCode::RETURN_LIST);
220                  break;
221              default:
222                  break;
223          }
224      }
225  }
226  
CheckFrameStateInput() const227  void Gate::CheckFrameStateInput() const
228  {
229      size_t frameStateStart = GetInFrameStateStarts();
230      if (meta_->HasFrameState()) {
231          CheckInputOpcode(frameStateStart, OpCode::FRAME_STATE);
232      }
233  }
234  
CheckStateOutput() const235  void Gate::CheckStateOutput() const
236  {
237      if (GetMetaData()->IsState()) {
238          size_t cnt = 0;
239          const Gate *curGate = this;
240          if (!curGate->IsFirstOutNull()) {
241              const Out *curOut = curGate->GetFirstOutConst();
242              auto meta = curOut->GetGateConst()->GetMetaData();
243              if (curOut->IsStateEdge() && meta->IsState()) {
244                  cnt++;
245              }
246              while (!curOut->IsNextOutNull()) {
247                  curOut = curOut->GetNextOutConst();
248                  meta = curOut->GetGateConst()->GetMetaData();
249                  if (curOut->IsStateEdge() && meta->IsState()) {
250                      cnt++;
251                  }
252              }
253          }
254          size_t expected = 0;
255          bool needCheck = true;
256          if (GetMetaData()->IsTerminalState()) {
257              expected = 0;
258          } else if (GetOpCode() == OpCode::IF_BRANCH || GetOpCode() == OpCode::JS_BYTECODE) {
259              expected = 2; // 2: expected number of state out branches
260          } else if (GetOpCode() == OpCode::SWITCH_BRANCH) {
261              needCheck = false;
262          } else {
263              expected = 1;
264          }
265          if (needCheck && cnt != expected) {
266              curGate->Print();
267              CheckFailed("Number of state out branches is not valid (expected:" + std::to_string(expected) +
268                  " actual:" + std::to_string(cnt) + ")", -1);
269          }
270      }
271  }
272  
CheckBranchOutput() const273  void Gate::CheckBranchOutput() const
274  {
275      std::map<std::pair<OpCode, BitField>, size_t> setOfOps;
276      if (GetOpCode() == OpCode::IF_BRANCH) {
277          size_t cnt = 0;
278          const Gate *curGate = this;
279          if (!curGate->IsFirstOutNull()) {
280              const Out *curOut = curGate->GetFirstOutConst();
281              if (curOut->GetGateConst()->GetMetaData()->IsState() && curOut->IsStateEdge()) {
282                  ASSERT(!curOut->GetGateConst()->GetMetaData()->IsFixed());
283                  setOfOps[{curOut->GetGateConst()->GetOpCode(), curOut->GetGateConst()->GetStateCount()}]++;
284                  cnt++;
285              }
286              while (!curOut->IsNextOutNull()) {
287                  curOut = curOut->GetNextOutConst();
288                  if (curOut->GetGateConst()->GetMetaData()->IsState() && curOut->IsStateEdge()) {
289                      ASSERT(!curOut->GetGateConst()->GetMetaData()->IsFixed());
290                      setOfOps[{curOut->GetGateConst()->GetOpCode(), curOut->GetGateConst()->GetStateCount()}]++;
291                      cnt++;
292                  }
293              }
294          }
295          if (setOfOps.size() != cnt) {
296              CheckFailed("Duplicate state out branches", -1);
297          }
298      }
299  }
300  
CheckNOP() const301  void Gate::CheckNOP() const
302  {
303      if (GetOpCode() == OpCode::NOP || GetOpCode() == OpCode::DEAD) {
304          if (!IsFirstOutNull()) {
305              CheckFailed("NOP gate used by other gates", -1);
306          }
307      }
308  }
309  
CheckSelector() const310  void Gate::CheckSelector() const
311  {
312      if (GetOpCode() == OpCode::VALUE_SELECTOR || GetOpCode() == OpCode::DEPEND_SELECTOR) {
313          auto stateOp = GetInGateConst(0)->GetOpCode();
314          if (stateOp == OpCode::MERGE || stateOp == OpCode::LOOP_BEGIN) {
315              if (GetInGateConst(0)->GetNumIns() != GetNumIns() - 1) {
316                  if (GetOpCode() == OpCode::DEPEND_SELECTOR) {
317                      CheckFailed("Number of depend flows does not match control flows (expected:" +
318                              std::to_string(GetInGateConst(0)->GetNumIns()) +
319                              " actual:" + std::to_string(GetNumIns() - 1) + ")",
320                          -1);
321                  } else {
322                      CheckFailed("Number of data flows does not match control flows (expected:" +
323                              std::to_string(GetInGateConst(0)->GetNumIns()) +
324                              " actual:" + std::to_string(GetNumIns() - 1) + ")",
325                          -1);
326                  }
327              }
328          } else {
329              CheckFailed(
330                  "State input does not match (expected:[MERGE|LOOP_BEGIN] actual:" +
331                  GateMetaData::Str(stateOp) + ")", 0);
332          }
333      }
334  }
335  
CheckRelay() const336  void Gate::CheckRelay() const
337  {
338      if (GetOpCode() == OpCode::DEPEND_RELAY) {
339          auto stateOp = GetInGateConst(0)->GetOpCode();
340          switch (stateOp) {
341              case OpCode::IF_TRUE:
342              case OpCode::IF_FALSE:
343              case OpCode::SWITCH_CASE:
344              case OpCode::DEFAULT_CASE:
345              case OpCode::IF_SUCCESS:
346              case OpCode::IF_EXCEPTION:
347              case OpCode::ORDINARY_BLOCK:
348              case OpCode::DEOPT_CHECK:
349                  break;
350              default:
351                  CheckFailed("State input does not match ("
352                      "expected:[IF_TRUE|IF_FALSE|SWITCH_CASE|DEFAULT_CASE|"
353                      "IF_SUCCESS|IF_EXCEPTION|ORDINARY_BLOCK|DEOPT_CHECK] actual:" +
354                      GateMetaData::Str(stateOp) + ")", 0);
355                  break;
356          }
357      }
358  }
359  
Verify(bool isArch64) const360  void Gate::Verify(bool isArch64) const
361  {
362      CheckNullInput();
363      CheckStateInput();
364      CheckValueInput(isArch64);
365      CheckDependInput();
366      CheckFrameStateInput();
367      CheckRootInput();
368      CheckStateOutput();
369      CheckBranchOutput();
370      CheckNOP();
371      CheckSelector();
372      CheckRelay();
373  }
374  
SetNextOut(const Out * ptr)375  void Out::SetNextOut(const Out *ptr)
376  {
377      nextOut_ =
378          // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
379          static_cast<GateRef>((reinterpret_cast<const uint8_t *>(ptr)) - (reinterpret_cast<const uint8_t *>(this)));
380  }
381  
GetNextOut()382  Out *Out::GetNextOut()
383  {
384      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
385      return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + nextOut_);
386  }
387  
GetNextOutConst() const388  const Out *Out::GetNextOutConst() const
389  {
390      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
391      return reinterpret_cast<const Out *>((reinterpret_cast<const uint8_t *>(this)) + nextOut_);
392  }
393  
SetPrevOut(const Out * ptr)394  void Out::SetPrevOut(const Out *ptr)
395  {
396      prevOut_ =
397          // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
398          static_cast<GateRef>((reinterpret_cast<const uint8_t *>(ptr)) - (reinterpret_cast<const uint8_t *>(this)));
399  }
400  
GetPrevOut()401  Out *Out::GetPrevOut()
402  {
403      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
404      return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + prevOut_);
405  }
406  
GetPrevOutConst() const407  const Out *Out::GetPrevOutConst() const
408  {
409      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
410      return reinterpret_cast<const Out *>((reinterpret_cast<const uint8_t *>(this)) + prevOut_);
411  }
412  
SetIndex(OutIdx idx)413  void Out::SetIndex(OutIdx idx)
414  {
415      idx_ = idx;
416  }
417  
GetIndex() const418  OutIdx Out::GetIndex() const
419  {
420      return idx_;
421  }
422  
GetGate()423  Gate *Out::GetGate()
424  {
425      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
426      return reinterpret_cast<Gate *>(&this[idx_ + 1]);
427  }
428  
GetGateConst() const429  const Gate *Out::GetGateConst() const
430  {
431      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
432      return reinterpret_cast<const Gate *>(&this[idx_ + 1]);
433  }
434  
SetPrevOutNull()435  void Out::SetPrevOutNull()
436  {
437      prevOut_ = 0;
438  }
439  
IsPrevOutNull() const440  bool Out::IsPrevOutNull() const
441  {
442      return prevOut_ == 0;
443  }
444  
SetNextOutNull()445  void Out::SetNextOutNull()
446  {
447      nextOut_ = 0;
448  }
449  
IsNextOutNull() const450  bool Out::IsNextOutNull() const
451  {
452      return nextOut_ == 0;
453  }
454  
IsStateEdge() const455  bool Out::IsStateEdge() const
456  {
457      return idx_ < GetGateConst()->GetStateCount();
458  }
459  
SetGate(const Gate * ptr)460  void In::SetGate(const Gate *ptr)
461  {
462      gatePtr_ =
463          // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
464          static_cast<GateRef>((reinterpret_cast<const uint8_t *>(ptr)) - (reinterpret_cast<const uint8_t *>(this)));
465  }
466  
GetGate()467  Gate *In::GetGate()
468  {
469      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
470      return reinterpret_cast<Gate *>((reinterpret_cast<uint8_t *>(this)) + gatePtr_);
471  }
472  
GetGateConst() const473  const Gate *In::GetGateConst() const
474  {
475      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
476      return reinterpret_cast<const Gate *>((reinterpret_cast<const uint8_t *>(this)) + gatePtr_);
477  }
478  
SetGateNull()479  void In::SetGateNull()
480  {
481      gatePtr_ = Gate::InvalidGateRef;
482  }
483  
IsGateNull() const484  bool In::IsGateNull() const
485  {
486      return gatePtr_ == Gate::InvalidGateRef;
487  }
488  
489  // NOLINTNEXTLINE(modernize-avoid-c-arrays)
Gate(const GateMetaData * meta,GateId id,Gate * inList[],MachineType machineType,GateType type)490  Gate::Gate(const GateMetaData* meta, GateId id, Gate *inList[], MachineType machineType, GateType type)
491      : meta_(meta), id_(id), type_(type), machineType_(machineType)
492  {
493      auto numIns = GetNumIns();
494      if (numIns == 0) {
495          auto curOut = GetOut(0);
496          curOut->SetIndex(0);
497          return;
498      }
499      for (size_t idx = 0; idx < numIns; idx++) {
500          // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
501          auto in = inList[idx];
502          if (in == nullptr) {
503              GetIn(idx)->SetGateNull();
504          } else {
505              NewIn(idx, in);
506          }
507          auto curOut = GetOut(idx);
508          curOut->SetIndex(idx);
509      }
510  }
511  
NewIn(size_t idx,Gate * in)512  void Gate::NewIn(size_t idx, Gate *in)
513  {
514      GetIn(idx)->SetGate(in);
515      auto curOut = GetOut(idx);
516      if (in->IsFirstOutNull()) {
517          curOut->SetNextOutNull();
518      } else {
519          curOut->SetNextOut(in->GetFirstOut());
520          in->GetFirstOut()->SetPrevOut(curOut);
521      }
522      curOut->SetPrevOutNull();
523      in->SetFirstOut(curOut);
524  }
525  
ModifyIn(size_t idx,Gate * in)526  void Gate::ModifyIn(size_t idx, Gate *in)
527  {
528      DeleteIn(idx);
529      NewIn(idx, in);
530  }
531  
DeleteIn(size_t idx)532  void Gate::DeleteIn(size_t idx)
533  {
534      if (!GetOut(idx)->IsNextOutNull() && !GetOut(idx)->IsPrevOutNull()) {
535          GetOut(idx)->GetPrevOut()->SetNextOut(GetOut(idx)->GetNextOut());
536          GetOut(idx)->GetNextOut()->SetPrevOut(GetOut(idx)->GetPrevOut());
537      } else if (GetOut(idx)->IsNextOutNull() && !GetOut(idx)->IsPrevOutNull()) {
538          GetOut(idx)->GetPrevOut()->SetNextOutNull();
539      } else if (!GetOut(idx)->IsNextOutNull()) {  // then GetOut(idx)->IsPrevOutNull() is true
540          GetIn(idx)->GetGate()->SetFirstOut(GetOut(idx)->GetNextOut());
541          GetOut(idx)->GetNextOut()->SetPrevOutNull();
542      } else {  // only this out now
543          GetIn(idx)->GetGate()->SetFirstOutNull();
544      }
545      GetIn(idx)->SetGateNull();
546  }
547  
DeleteGate()548  void Gate::DeleteGate()
549  {
550      auto numIns = GetNumIns();
551      for (size_t idx = 0; idx < numIns; idx++) {
552          DeleteIn(idx);
553      }
554  }
555  
GetOut(size_t idx)556  Out *Gate::GetOut(size_t idx)
557  {
558      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
559      return &reinterpret_cast<Out *>(this)[-1 - idx];
560  }
561  
GetOutConst(size_t idx) const562  const Out *Gate::GetOutConst(size_t idx) const
563  {
564      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
565      return &reinterpret_cast<const Out *>(this)[-1 - idx];
566  }
567  
GetFirstOut()568  Out *Gate::GetFirstOut()
569  {
570      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
571      return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + firstOut_);
572  }
573  
GetFirstOutConst() const574  const Out *Gate::GetFirstOutConst() const
575  {
576      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
577      return reinterpret_cast<const Out *>((reinterpret_cast<const uint8_t *>(this)) + firstOut_);
578  }
579  
SetFirstOutNull()580  void Gate::SetFirstOutNull()
581  {
582      firstOut_ = 0;
583  }
584  
IsFirstOutNull() const585  bool Gate::IsFirstOutNull() const
586  {
587      return firstOut_ == 0;
588  }
589  
SetFirstOut(const Out * firstOut)590  void Gate::SetFirstOut(const Out *firstOut)
591  {
592      firstOut_ =
593          // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
594          static_cast<GateRef>(reinterpret_cast<const uint8_t *>(firstOut) - reinterpret_cast<const uint8_t *>(this));
595  }
596  
GetIn(size_t idx)597  In *Gate::GetIn(size_t idx)
598  {
599  #ifndef NDEBUG
600      if (idx >= GetNumIns()) {
601          LOG_COMPILER(INFO) << std::dec << "Gate In access out-of-bound! (idx=" << idx << ")";
602          Print();
603          ASSERT(false);
604      }
605  #endif
606      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
607      return &reinterpret_cast<In *>(this + 1)[idx];
608  }
609  
GetInConst(size_t idx) const610  const In *Gate::GetInConst(size_t idx) const
611  {
612  #ifndef NDEBUG
613      if (idx >= GetNumIns()) {
614          LOG_COMPILER(INFO) << std::dec << "Gate In access out-of-bound! (idx=" << idx << ")";
615          Print();
616          ASSERT(false);
617      }
618  #endif
619      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
620      return &reinterpret_cast<const In *>(this + 1)[idx];
621  }
622  
GetInGate(size_t idx)623  Gate *Gate::GetInGate(size_t idx)
624  {
625      return GetIn(idx)->GetGate();
626  }
627  
GetInGateConst(size_t idx) const628  const Gate *Gate::GetInGateConst(size_t idx) const
629  {
630      return GetInConst(idx)->GetGateConst();
631  }
632  
IsInGateNull(size_t idx) const633  bool Gate::IsInGateNull(size_t idx) const
634  {
635      return GetInConst(idx)->IsGateNull();
636  }
637  
GetId() const638  GateId Gate::GetId() const
639  {
640      return id_;
641  }
642  
GetOpCode() const643  OpCode Gate::GetOpCode() const
644  {
645      return meta_->GetOpCode();
646  }
647  
GetNumIns() const648  size_t Gate::GetNumIns() const
649  {
650      return meta_->GetNumIns();
651  }
652  
GetInValueStarts() const653  size_t Gate::GetInValueStarts() const
654  {
655      return meta_->GetInValueStarts();
656  }
657  
GetInFrameStateStarts() const658  size_t Gate::GetInFrameStateStarts() const
659  {
660      return meta_->GetInFrameStateStarts();
661  }
662  
GetStateCount() const663  size_t Gate::GetStateCount() const
664  {
665      return meta_->GetStateCount();
666  }
667  
GetDependCount() const668  size_t Gate::GetDependCount() const
669  {
670      return meta_->GetDependCount();
671  }
672  
GetInValueCount() const673  size_t Gate::GetInValueCount() const
674  {
675      return meta_->GetInValueCount();
676  }
677  
GetInFrameStateCount() const678  size_t Gate::GetInFrameStateCount() const
679  {
680      return meta_->GetInFrameStateCount();
681  }
682  
GetRootCount() const683  size_t Gate::GetRootCount() const
684  {
685      return meta_->GetRootCount();
686  }
687  
MachineTypeStr(MachineType machineType) const688  std::string Gate::MachineTypeStr(MachineType machineType) const
689  {
690      const std::map<MachineType, const char *> strMap = {
691          {NOVALUE, "NOVALUE"},
692          {ANYVALUE, "ANYVALUE"},
693          {ARCH, "ARCH"},
694          {FLEX, "FLEX"},
695          {I1, "I1"},
696          {I8, "I8"},
697          {I16, "I16"},
698          {I32, "I32"},
699          {I64, "I64"},
700          {F32, "F32"},
701          {F64, "F64"},
702      };
703      if (strMap.count(machineType) > 0) {
704          return strMap.at(machineType);
705      }
706      return "MachineType-" + std::to_string(machineType);
707  }
708  
GateTypeStr(GateType gateType) const709  std::string Gate::GateTypeStr(GateType gateType) const
710  {
711      static const std::map<GateType, const char *> strMap = {
712          {GateType::NJSValue(), "NJS_VALUE"},
713          {GateType::TaggedValue(), "TAGGED_VALUE"},
714          {GateType::TaggedPointer(), "TAGGED_POINTER"},
715          {GateType::TaggedNPointer(), "TAGGED_NPOINTER"},
716          {GateType::Empty(), "EMPTY"},
717          {GateType::AnyType(), "ANY_TYPE"},
718      };
719  
720      std::string name = "";
721      if (strMap.count(gateType) > 0) {
722          name = strMap.at(gateType);
723      }
724      GlobalTSTypeRef r = gateType.GetGTRef();
725      uint32_t m = r.GetModuleId();
726      uint32_t l = r.GetLocalId();
727      return name + std::string("-GT(M=") + std::to_string(m) +
728             std::string(", L=") + std::to_string(l) + std::string(")");
729  }
730  
Print(std::string additionOp,bool inListPreview,size_t highlightIdx) const731  void Gate::Print(std::string additionOp, bool inListPreview, size_t highlightIdx) const
732  {
733      auto opcode = GetOpCode();
734      if (opcode != OpCode::NOP && opcode != OpCode::DEAD) {
735          std::string log("{\"id\":" + std::to_string(id_) + ", \"op\":\"" + GateMetaData::Str(opcode) + "\", ");
736          std::string additionOpName = (opcode == OpCode::JS_BYTECODE) ? "bytecode" : "typedop";
737          log += ((additionOp.compare("") == 0) ? "" : "\"" + additionOpName + "\":\"") + additionOp;
738          log += ((additionOp.compare("") == 0) ? "" : "\", ");
739          log += "\"MType\":\"" + MachineTypeStr(GetMachineType()) + ", ";
740  
741          std::ostringstream oss;
742          oss << std::hex << TryGetValue();
743          log += "bitfield=0x" + oss.str() + ", ";
744          log += "type=" + GateTypeStr(type_) + ", ";
745          log += "stamp=" + std::to_string(static_cast<uint32_t>(stamp_)) + ", ";
746          log += "mark=" + std::to_string(static_cast<uint32_t>(mark_)) + ", ";
747          log += "\",\"in\":[";
748  
749          size_t idx = 0;
750          auto stateSize = GetStateCount();
751          auto dependSize = GetDependCount();
752          auto valueSize = GetInValueCount();
753          auto frameStateSize = GetInFrameStateCount();
754          auto rootSize = GetRootCount();
755          size_t start = 0;
756          size_t end = stateSize;
757          idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
758          end += dependSize;
759          start += stateSize;
760          idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
761          end += valueSize;
762          start += dependSize;
763          idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
764          end += frameStateSize;
765          start += valueSize;
766          idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
767          end += rootSize;
768          start += frameStateSize;
769          idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log, true);
770  
771          log += "], \"out\":[";
772  
773          if (!IsFirstOutNull()) {
774              const Out *curOut = GetFirstOutConst();
775              opcode = curOut->GetGateConst()->GetOpCode();
776              log += std::to_string(curOut->GetGateConst()->GetId()) +
777                      (inListPreview ? std::string(":" + GateMetaData::Str(opcode)) : std::string(""));
778  
779              while (!curOut->IsNextOutNull()) {
780                  curOut = curOut->GetNextOutConst();
781                  log += ", " +  std::to_string(curOut->GetGateConst()->GetId()) +
782                         (inListPreview ? std::string(":" + GateMetaData::Str(opcode))
783                                         : std::string(""));
784              }
785          }
786          log += "]},";
787          LOG_COMPILER(INFO) << std::dec << log;
788      }
789  }
790  
ShortPrint(std::string bytecode,bool inListPreview,size_t highlightIdx) const791  void Gate::ShortPrint(std::string bytecode, bool inListPreview, size_t highlightIdx) const
792  {
793      auto opcode = GetOpCode();
794      if (opcode != OpCode::NOP && opcode != OpCode::DEAD) {
795          std::string log("(\"id\"=" + std::to_string(id_) + ", \"op\"=\"" + GateMetaData::Str(opcode) + "\", ");
796          log += ((bytecode.compare("") == 0) ? "" : "bytecode=") + bytecode;
797          log += ((bytecode.compare("") == 0) ? "" : ", ");
798          log += "\"MType\"=\"" + MachineTypeStr(GetMachineType()) + ", ";
799          std::ostringstream oss;
800          oss << std::hex << TryGetValue();
801          log += "bitfield=0x" + oss.str() + ", ";
802          log += "type=" + GateTypeStr(type_) + ", ";
803          log += "\", in=[";
804  
805          size_t idx = 0;
806          auto stateSize = GetStateCount();
807          auto dependSize = GetDependCount();
808          auto valueSize = GetInValueCount();
809          auto frameStateSize = GetInFrameStateCount();
810          auto rootSize = GetRootCount();
811          size_t start = 0;
812          size_t end = stateSize;
813          idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
814          end += dependSize;
815          start += stateSize;
816          idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
817          end += valueSize;
818          start += dependSize;
819          idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
820          end += frameStateSize;
821          start += valueSize;
822          idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
823          end += rootSize;
824          start += frameStateSize;
825          idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log, true);
826  
827          log += "], out=[";
828  
829          if (!IsFirstOutNull()) {
830              const Out *curOut = GetFirstOutConst();
831              opcode = curOut->GetGateConst()->GetOpCode();
832              log += std::to_string(curOut->GetGateConst()->GetId()) +
833                     (inListPreview ? std::string(":" + GateMetaData::Str(opcode)) : std::string(""));
834  
835              while (!curOut->IsNextOutNull()) {
836                  curOut = curOut->GetNextOutConst();
837                  log += ", " +  std::to_string(curOut->GetGateConst()->GetId()) +
838                         (inListPreview ? std::string(":" + GateMetaData::Str(opcode))
839                                        : std::string(""));
840              }
841          }
842          log += "])";
843          LOG_COMPILER(INFO) << std::dec << log;
844      }
845  }
846  
PrintInGate(size_t numIns,size_t idx,size_t size,bool inListPreview,size_t highlightIdx,std::string & log,bool isEnd) const847  size_t Gate::PrintInGate(size_t numIns, size_t idx, size_t size, bool inListPreview, size_t highlightIdx,
848                           std::string &log, bool isEnd) const
849  {
850      log += "[";
851      for (; idx < numIns; idx++) {
852          log += ((idx == size) ? "" : ", ");
853          log += ((idx == highlightIdx) ? "\033[4;31m" : "");
854          log += ((IsInGateNull(idx)
855                  ? "N"
856                  : (std::to_string(GetInGateConst(idx)->GetId()) +
857                      (inListPreview ? std::string(":" + GateMetaData::Str(GetInGateConst(idx)->GetOpCode()))
858                                     : std::string("")))));
859          log += ((idx == highlightIdx) ? "\033[0m" : "");
860      }
861      log += "]";
862      log += ((isEnd) ? "" : ", ");
863      return idx;
864  }
865  
PrintWithBytecode() const866  void Gate::PrintWithBytecode() const
867  {
868      auto opcode = GetOpCode();
869      std::string bytecodeStr = "";
870      switch (opcode) {
871          case OpCode::JS_BYTECODE: {
872              bytecodeStr = GetJSBytecodeMetaData()->Str();
873              break;
874          }
875          case OpCode::TYPED_BINARY_OP: {
876              bytecodeStr = GetTypedBinaryMetaData()->Str();
877              break;
878          }
879          case OpCode::TYPED_UNARY_OP: {
880              auto typedOp = TypedUnaryAccessor(GetOneParameterMetaData()->GetValue()).GetTypedUnOp();
881              bytecodeStr = GateMetaData::Str(typedOp);
882              break;
883          }
884          case OpCode::TYPED_CONDITION_JUMP: {
885              auto typedOp = TypedJumpAccessor(GetOneParameterMetaData()->GetValue()).GetTypedJumpOp();
886              bytecodeStr = GateMetaData::Str(typedOp);
887              break;
888          }
889          case OpCode::LOAD_ELEMENT: {
890              auto typedOp = static_cast<TypedLoadOp>(GetOneParameterMetaData()->GetValue());
891              bytecodeStr = GateMetaData::Str(typedOp);
892              break;
893          }
894          case OpCode::STORE_ELEMENT: {
895              auto typedOp = static_cast<TypedStoreOp>(GetOneParameterMetaData()->GetValue());
896              bytecodeStr = GateMetaData::Str(typedOp);
897              break;
898          }
899          case OpCode::TYPED_CALLTARGETCHECK_OP: {
900              auto typedOp = GetTypedCallTargetCheckMetaData()->GetTypedCallTargetCheckOp();
901              bytecodeStr = GateMetaData::Str(typedOp);
902              break;
903          }
904          case OpCode::CONVERT:
905          case OpCode::CHECK_AND_CONVERT: {
906              ValuePairTypeAccessor accessor(GetOneParameterMetaData()->GetValue());
907              bytecodeStr = GateMetaData::Str(accessor.GetSrcType()) + "_TO_" +
908                  GateMetaData::Str(accessor.GetDstType());
909              break;
910          }
911          default:
912              break;
913      }
914      PrintGateWithAdditionOp(bytecodeStr);
915  }
916  
PrintGateWithAdditionOp(std::string additionOp) const917  void Gate::PrintGateWithAdditionOp(std::string additionOp) const
918  {
919      Print(additionOp);
920  }
921  
GetMark(TimeStamp stamp) const922  MarkCode Gate::GetMark(TimeStamp stamp) const
923  {
924      return (stamp_ == stamp) ? mark_ : MarkCode::NO_MARK;
925  }
926  
SetMark(MarkCode mark,TimeStamp stamp)927  void Gate::SetMark(MarkCode mark, TimeStamp stamp)
928  {
929      stamp_ = stamp;
930      mark_ = mark;
931  }
932  }  // namespace panda::ecmascript::kungfu
933