• 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