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