• 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::LOAD_WITHOUT_BARRIER:
158                 ASSERT(idx == valueStart);
159                 CheckInputMachineType(idx, MachineType::ARCH, isArch64);
160                 break;
161             case OpCode::STORE:
162                 if ((idx == valueStart + 1) || (idx == valueStart + 2)) { // 1:base, 2:offset
163                     CheckInputMachineType(idx, MachineType::ARCH, isArch64);
164                 }
165                 break;
166             case OpCode::STORE_WITHOUT_BARRIER:
167                 if (idx == valueStart) {
168                     CheckInputMachineType(idx, MachineType::ARCH, isArch64);
169                 }
170                 break;
171             case OpCode::HEAP_ALLOC: {
172                 if (idx == valueStart + 1) { // 1: size offset
173                     CheckInputMachineType(idx, MachineType::I64, isArch64);
174                 }
175                 break;
176             }
177             case OpCode::TAGGED_TO_INT64:
178             case OpCode::INT64_TO_TAGGED:
179                 ASSERT(idx == valueStart);
180                 CheckInputMachineType(valueStart, MachineType::I64, isArch64);
181                 break;
182             case OpCode::OBJECT_TYPE_CHECK:
183             case OpCode::LOAD_ELEMENT:
184             case OpCode::STORE_ELEMENT:
185                 if (idx == valueStart) { // 1: idx 1
186                     CheckInputMachineType(idx, MachineType::I64, isArch64);
187                 }
188                 break;
189             case OpCode::FCMP:
190                 CheckInputMachineType(idx, MachineType::F64, isArch64);
191                 break;
192             case OpCode::ICMP:
193                 CheckNotInputMachineType(idx, MachineType::F64);
194                 break;
195             default:
196                 break;
197         }
198     }
199 }
200 
CheckDependInput() const201 void Gate::CheckDependInput() const
202 {
203     size_t dependStart = GetStateCount();
204     size_t dependEnd = dependStart + GetDependCount();
205     for (size_t idx = dependStart; idx < dependEnd; idx++) {
206         if (GetInGateConst(idx)->GetDependCount() == 0 &&
207             GetInGateConst(idx)->GetOpCode() != OpCode::DEPEND_ENTRY) {
208             LOG_COMPILER(ERROR) << "depend in of " << GetId() << GateMetaData::Str(GetOpCode()) << "is "
209                 << GetInGateConst(idx)->GetId() << GateMetaData::Str(GetInGateConst(idx)->GetOpCode());
210             CheckFailed("Depend input is side-effect free", idx);
211         }
212     }
213 }
214 
CheckRootInput() const215 void Gate::CheckRootInput() const
216 {
217     size_t rootStart = GetInValueStarts() + GetInValueCount();
218     if (meta_->HasRoot()) {
219         switch (GetOpCode()) {
220             case OpCode::STATE_ENTRY:
221             case OpCode::DEPEND_ENTRY:
222             case OpCode::RETURN_LIST:
223             case OpCode::ARG_LIST:
224                 CheckInputOpcode(rootStart, OpCode::CIRCUIT_ROOT);
225                 break;
226             case OpCode::ARG:
227                 CheckInputOpcode(rootStart, OpCode::ARG_LIST);
228                 break;
229             case OpCode::RETURN:
230             case OpCode::RETURN_VOID:
231                 CheckInputOpcode(rootStart, OpCode::RETURN_LIST);
232                 break;
233             default:
234                 break;
235         }
236     }
237 }
238 
CheckFrameStateInput() const239 void Gate::CheckFrameStateInput() const
240 {
241     size_t frameStateStart = GetInFrameStateStarts();
242     if (meta_->HasFrameState()) {
243         CheckInputOpcode(frameStateStart, OpCode::FRAME_STATE);
244     }
245 }
246 
GetValueInAndOut(bool inListPreview,size_t highlightIdx) const247 std::string Gate::GetValueInAndOut(bool inListPreview, size_t highlightIdx) const
248 {
249     auto opcode = GetOpCode();
250     if (opcode != OpCode::NOP && opcode != OpCode::DEAD) {
251         std::ostringstream log("{\"id\":");
252         log << std::to_string(id_) << ", \"op\":\"" << GateMetaData::Str(opcode) << "\", ";
253         log << "\",\"in\":[";
254         size_t idx = 0;
255         auto stateSize = GetStateCount();
256         auto dependSize = GetDependCount();
257         auto valueSize = GetInValueCount();
258         auto frameStateSize = GetInFrameStateCount();
259         auto rootSize = GetRootCount();
260         size_t start = 0;
261         size_t end = stateSize;
262         idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
263         end += dependSize;
264         start += stateSize;
265         idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
266         end += valueSize;
267         start += dependSize;
268         idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
269         end += frameStateSize;
270         start += valueSize;
271         idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
272         end += rootSize;
273         start += frameStateSize;
274         idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log, true);
275 
276         log << "], \"out\":[";
277 
278         if (!IsFirstOutNull()) {
279             const Out *curOut = GetFirstOutConst();
280             opcode = curOut->GetGateConst()->GetOpCode();
281             log << std::to_string(curOut->GetGateConst()->GetId()) +
282                     (inListPreview ? std::string(":" + GateMetaData::Str(opcode)) : std::string(""));
283 
284             while (!curOut->IsNextOutNull()) {
285                 curOut = curOut->GetNextOutConst();
286                 log << ", " << std::to_string(curOut->GetGateConst()->GetId()) <<
287                        (inListPreview ? std::string(":" + GateMetaData::Str(opcode))
288                                        : std::string(""));
289             }
290         }
291         log << "]},";
292         return log.str();
293     }
294     return "";
295 }
296 
CheckStateOutput(const std::string & methodName) const297 void Gate::CheckStateOutput(const std::string& methodName) const
298 {
299     if (!GetMetaData()->IsState()) {
300         return;
301     }
302     size_t cnt = 0;
303     const Gate *curGate = this;
304     if (!curGate->IsFirstOutNull()) {
305         const Out *curOut = curGate->GetFirstOutConst();
306         auto meta = curOut->GetGateConst()->GetMetaData();
307         if (curOut->IsStateEdge() && meta->IsState()) {
308             cnt++;
309         }
310         while (!curOut->IsNextOutNull()) {
311             curOut = curOut->GetNextOutConst();
312             meta = curOut->GetGateConst()->GetMetaData();
313             if (curOut->IsStateEdge() && meta->IsState()) {
314                 cnt++;
315             }
316         }
317     }
318     size_t expected = 0;
319     bool needCheck = true;
320     if (GetMetaData()->IsTerminalState()) {
321         expected = 0;
322     } else if (GetOpCode() == OpCode::IF_BRANCH || GetOpCode() == OpCode::JS_BYTECODE) {
323         expected = 2; // 2: expected number of state out branches
324     } else if (GetOpCode() == OpCode::SWITCH_BRANCH) {
325         needCheck = false;
326     } else {
327         expected = 1;
328     }
329     if (needCheck && cnt != expected) {
330         curGate->Print();
331         std::string log = curGate->GetValueInAndOut(true);
332         CheckFailed("Number of state out branches is not valid (expected:" + std::to_string(expected) +
333             " actual:" + std::to_string(cnt) + ") methodName:" + methodName + " gateValue:" + log, -1);
334     }
335 }
336 
CheckBranchOutput() const337 void Gate::CheckBranchOutput() const
338 {
339     std::map<std::pair<OpCode, BitField>, size_t> setOfOps;
340     if (GetOpCode() == OpCode::IF_BRANCH) {
341         size_t cnt = 0;
342         const Gate *curGate = this;
343         if (!curGate->IsFirstOutNull()) {
344             const Out *curOut = curGate->GetFirstOutConst();
345             if (curOut->GetGateConst()->GetMetaData()->IsState() && curOut->IsStateEdge()) {
346                 ASSERT(!curOut->GetGateConst()->GetMetaData()->IsFixed());
347                 setOfOps[{curOut->GetGateConst()->GetOpCode(), curOut->GetGateConst()->GetStateCount()}]++;
348                 cnt++;
349             }
350             while (!curOut->IsNextOutNull()) {
351                 curOut = curOut->GetNextOutConst();
352                 if (curOut->GetGateConst()->GetMetaData()->IsState() && curOut->IsStateEdge()) {
353                     ASSERT(!curOut->GetGateConst()->GetMetaData()->IsFixed());
354                     setOfOps[{curOut->GetGateConst()->GetOpCode(), curOut->GetGateConst()->GetStateCount()}]++;
355                     cnt++;
356                 }
357             }
358         }
359         if (setOfOps.size() != cnt) {
360             CheckFailed("Duplicate state out branches", -1);
361         }
362     }
363 }
364 
CheckNOP() const365 void Gate::CheckNOP() const
366 {
367     if (GetOpCode() == OpCode::NOP || GetOpCode() == OpCode::DEAD) {
368         if (!IsFirstOutNull()) {
369             CheckFailed("NOP gate used by other gates", -1);
370         }
371     }
372 }
373 
CheckSelector() const374 void Gate::CheckSelector() const
375 {
376     if (GetOpCode() == OpCode::VALUE_SELECTOR || GetOpCode() == OpCode::DEPEND_SELECTOR) {
377         auto stateOp = GetInGateConst(0)->GetOpCode();
378         if (stateOp == OpCode::MERGE || stateOp == OpCode::LOOP_BEGIN) {
379             ASSERT(GetNumIns() > 0);
380             if (GetInGateConst(0)->GetNumIns() != GetNumIns() - 1) {
381                 if (GetOpCode() == OpCode::DEPEND_SELECTOR) {
382                     CheckFailed("Number of depend flows does not match control flows (expected:" +
383                             std::to_string(GetInGateConst(0)->GetNumIns()) +
384                             " actual:" + std::to_string(GetNumIns() - 1) + ")",
385                         -1);
386                 } else {
387                     CheckFailed("Number of data flows does not match control flows (expected:" +
388                             std::to_string(GetInGateConst(0)->GetNumIns()) +
389                             " actual:" + std::to_string(GetNumIns() - 1) + ")",
390                         -1);
391                 }
392             }
393         } else {
394             CheckFailed(
395                 "State input does not match (expected:[MERGE|LOOP_BEGIN] actual:" +
396                 GateMetaData::Str(stateOp) + ")", 0);
397         }
398     }
399 }
400 
CheckRelay() const401 void Gate::CheckRelay() const
402 {
403     if (GetOpCode() == OpCode::DEPEND_RELAY) {
404         auto stateOp = GetInGateConst(0)->GetOpCode();
405         switch (stateOp) {
406             case OpCode::IF_TRUE:
407             case OpCode::IF_FALSE:
408             case OpCode::SWITCH_CASE:
409             case OpCode::DEFAULT_CASE:
410             case OpCode::IF_SUCCESS:
411             case OpCode::IF_EXCEPTION:
412             case OpCode::ORDINARY_BLOCK:
413             case OpCode::DEOPT_CHECK:
414                 break;
415             default:
416                 CheckFailed("State input does not match ("
417                     "expected:[IF_TRUE|IF_FALSE|SWITCH_CASE|DEFAULT_CASE|"
418                     "IF_SUCCESS|IF_EXCEPTION|ORDINARY_BLOCK|DEOPT_CHECK] actual:" +
419                     GateMetaData::Str(stateOp) + ")", 0);
420                 break;
421         }
422     }
423 }
424 
Verify(bool isArch64,const std::string & methodName) const425 void Gate::Verify(bool isArch64, const std::string& methodName) const
426 {
427     CheckNullInput();
428     CheckStateInput();
429     CheckValueInput(isArch64);
430     CheckDependInput();
431     CheckFrameStateInput();
432     CheckRootInput();
433     CheckStateOutput(methodName);
434     CheckBranchOutput();
435     CheckNOP();
436     CheckSelector();
437     CheckRelay();
438 }
439 
SetNextOut(const Out * ptr)440 void Out::SetNextOut(const Out *ptr)
441 {
442     nextOut_ =
443         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
444         static_cast<GateRef>((reinterpret_cast<const uint8_t *>(ptr)) - (reinterpret_cast<const uint8_t *>(this)));
445 }
446 
GetNextOut()447 Out *Out::GetNextOut()
448 {
449     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
450     return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + nextOut_);
451 }
452 
GetNextOutConst() const453 const Out *Out::GetNextOutConst() const
454 {
455     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
456     return reinterpret_cast<const Out *>((reinterpret_cast<const uint8_t *>(this)) + nextOut_);
457 }
458 
SetPrevOut(const Out * ptr)459 void Out::SetPrevOut(const Out *ptr)
460 {
461     prevOut_ =
462         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
463         static_cast<GateRef>((reinterpret_cast<const uint8_t *>(ptr)) - (reinterpret_cast<const uint8_t *>(this)));
464 }
465 
GetPrevOut()466 Out *Out::GetPrevOut()
467 {
468     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
469     return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + prevOut_);
470 }
471 
GetPrevOutConst() const472 const Out *Out::GetPrevOutConst() const
473 {
474     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
475     return reinterpret_cast<const Out *>((reinterpret_cast<const uint8_t *>(this)) + prevOut_);
476 }
477 
SetIndex(OutIdx idx)478 void Out::SetIndex(OutIdx idx)
479 {
480     idx_ = idx;
481 }
482 
GetIndex() const483 OutIdx Out::GetIndex() const
484 {
485     return idx_;
486 }
487 
GetGate()488 Gate *Out::GetGate()
489 {
490     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
491     return reinterpret_cast<Gate *>(&this[idx_ + 1]);
492 }
493 
GetGateConst() const494 const Gate *Out::GetGateConst() const
495 {
496     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
497     return reinterpret_cast<const Gate *>(&this[idx_ + 1]);
498 }
499 
SetPrevOutNull()500 void Out::SetPrevOutNull()
501 {
502     prevOut_ = 0;
503 }
504 
IsPrevOutNull() const505 bool Out::IsPrevOutNull() const
506 {
507     return prevOut_ == 0;
508 }
509 
SetNextOutNull()510 void Out::SetNextOutNull()
511 {
512     nextOut_ = 0;
513 }
514 
IsNextOutNull() const515 bool Out::IsNextOutNull() const
516 {
517     return nextOut_ == 0;
518 }
519 
IsStateEdge() const520 bool Out::IsStateEdge() const
521 {
522     return idx_ < GetGateConst()->GetStateCount();
523 }
524 
SetGate(const Gate * ptr)525 void In::SetGate(const Gate *ptr)
526 {
527     gatePtr_ =
528         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
529         static_cast<GateRef>((reinterpret_cast<const uint8_t *>(ptr)) - (reinterpret_cast<const uint8_t *>(this)));
530 }
531 
GetGate()532 Gate *In::GetGate()
533 {
534     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
535     return reinterpret_cast<Gate *>((reinterpret_cast<uint8_t *>(this)) + gatePtr_);
536 }
537 
GetGateConst() const538 const Gate *In::GetGateConst() const
539 {
540     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
541     return reinterpret_cast<const Gate *>((reinterpret_cast<const uint8_t *>(this)) + gatePtr_);
542 }
543 
SetGateNull()544 void In::SetGateNull()
545 {
546     gatePtr_ = Gate::InvalidGateRef;
547 }
548 
IsGateNull() const549 bool In::IsGateNull() const
550 {
551     return gatePtr_ == Gate::InvalidGateRef;
552 }
553 
554 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
Gate(const GateMetaData * meta,GateId id,Gate * inList[],MachineType machineType,GateType type)555 Gate::Gate(const GateMetaData* meta, GateId id, Gate *inList[], MachineType machineType, GateType type)
556     : meta_(meta), id_(id), type_(type), machineType_(machineType)
557 {
558     auto numIns = GetNumIns();
559     if (numIns == 0) {
560         auto curOut = GetOut(0);
561         curOut->SetIndex(0);
562         return;
563     }
564     for (size_t idx = 0; idx < numIns; idx++) {
565         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
566         auto in = inList[idx];
567         if (in == nullptr) {
568             GetIn(idx)->SetGateNull();
569         } else {
570             NewIn(idx, in);
571         }
572         auto curOut = GetOut(idx);
573         curOut->SetIndex(idx);
574     }
575 }
576 
NewIn(size_t idx,Gate * in)577 void Gate::NewIn(size_t idx, Gate *in)
578 {
579     GetIn(idx)->SetGate(in);
580     auto curOut = GetOut(idx);
581     if (in->IsFirstOutNull()) {
582         curOut->SetNextOutNull();
583     } else {
584         curOut->SetNextOut(in->GetFirstOut());
585         in->GetFirstOut()->SetPrevOut(curOut);
586     }
587     curOut->SetPrevOutNull();
588     in->SetFirstOut(curOut);
589 }
590 
ModifyIn(size_t idx,Gate * in)591 void Gate::ModifyIn(size_t idx, Gate *in)
592 {
593     DeleteIn(idx);
594     NewIn(idx, in);
595 }
596 
DeleteIn(size_t idx)597 void Gate::DeleteIn(size_t idx)
598 {
599     if (!GetOut(idx)->IsNextOutNull() && !GetOut(idx)->IsPrevOutNull()) {
600         GetOut(idx)->GetPrevOut()->SetNextOut(GetOut(idx)->GetNextOut());
601         GetOut(idx)->GetNextOut()->SetPrevOut(GetOut(idx)->GetPrevOut());
602     } else if (GetOut(idx)->IsNextOutNull() && !GetOut(idx)->IsPrevOutNull()) {
603         GetOut(idx)->GetPrevOut()->SetNextOutNull();
604     } else if (!GetOut(idx)->IsNextOutNull()) {  // then GetOut(idx)->IsPrevOutNull() is true
605         GetIn(idx)->GetGate()->SetFirstOut(GetOut(idx)->GetNextOut());
606         GetOut(idx)->GetNextOut()->SetPrevOutNull();
607     } else {  // only this out now
608         GetIn(idx)->GetGate()->SetFirstOutNull();
609     }
610     GetIn(idx)->SetGateNull();
611 }
612 
DeleteGate()613 void Gate::DeleteGate()
614 {
615     auto numIns = GetNumIns();
616     for (size_t idx = 0; idx < numIns; idx++) {
617         DeleteIn(idx);
618     }
619 }
620 
GetOut(size_t idx)621 Out *Gate::GetOut(size_t idx)
622 {
623     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
624     return &reinterpret_cast<Out *>(this)[-1 - idx];
625 }
626 
GetOutConst(size_t idx) const627 const Out *Gate::GetOutConst(size_t idx) const
628 {
629     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
630     return &reinterpret_cast<const Out *>(this)[-1 - idx];
631 }
632 
GetFirstOut()633 Out *Gate::GetFirstOut()
634 {
635     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
636     return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + firstOut_);
637 }
638 
GetFirstOutConst() const639 const Out *Gate::GetFirstOutConst() const
640 {
641     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
642     return reinterpret_cast<const Out *>((reinterpret_cast<const uint8_t *>(this)) + firstOut_);
643 }
644 
SetFirstOutNull()645 void Gate::SetFirstOutNull()
646 {
647     firstOut_ = 0;
648 }
649 
IsFirstOutNull() const650 bool Gate::IsFirstOutNull() const
651 {
652     return firstOut_ == 0;
653 }
654 
SetFirstOut(const Out * firstOut)655 void Gate::SetFirstOut(const Out *firstOut)
656 {
657     firstOut_ =
658         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
659         static_cast<GateRef>(reinterpret_cast<const uint8_t *>(firstOut) - reinterpret_cast<const uint8_t *>(this));
660 }
661 
GetIn(size_t idx)662 In *Gate::GetIn(size_t idx)
663 {
664 #ifndef NDEBUG
665     if (idx >= GetNumIns()) {
666         LOG_COMPILER(INFO) << std::dec << "Gate In access out-of-bound! (idx=" << idx << ")";
667         Print();
668         ASSERT(false);
669     }
670 #endif
671     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
672     return &reinterpret_cast<In *>(this + 1)[idx];
673 }
674 
GetInConst(size_t idx) const675 const In *Gate::GetInConst(size_t idx) const
676 {
677 #ifndef NDEBUG
678     if (idx >= GetNumIns()) {
679         LOG_COMPILER(INFO) << std::dec << "Gate In access out-of-bound! (idx=" << idx << ")";
680         Print();
681         ASSERT(false);
682     }
683 #endif
684     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
685     return &reinterpret_cast<const In *>(this + 1)[idx];
686 }
687 
GetInGate(size_t idx)688 Gate *Gate::GetInGate(size_t idx)
689 {
690     return GetIn(idx)->GetGate();
691 }
692 
GetInGateConst(size_t idx) const693 const Gate *Gate::GetInGateConst(size_t idx) const
694 {
695     return GetInConst(idx)->GetGateConst();
696 }
697 
IsInGateNull(size_t idx) const698 bool Gate::IsInGateNull(size_t idx) const
699 {
700     return GetInConst(idx)->IsGateNull();
701 }
702 
GetId() const703 GateId Gate::GetId() const
704 {
705     return id_;
706 }
707 
GetOpCode() const708 OpCode Gate::GetOpCode() const
709 {
710     return meta_->GetOpCode();
711 }
712 
GetNumIns() const713 size_t Gate::GetNumIns() const
714 {
715     return meta_->GetNumIns();
716 }
717 
GetInValueStarts() const718 size_t Gate::GetInValueStarts() const
719 {
720     return meta_->GetInValueStarts();
721 }
722 
GetInFrameStateStarts() const723 size_t Gate::GetInFrameStateStarts() const
724 {
725     return meta_->GetInFrameStateStarts();
726 }
727 
GetStateCount() const728 size_t Gate::GetStateCount() const
729 {
730     return meta_->GetStateCount();
731 }
732 
GetDependCount() const733 size_t Gate::GetDependCount() const
734 {
735     return meta_->GetDependCount();
736 }
737 
GetInValueCount() const738 size_t Gate::GetInValueCount() const
739 {
740     return meta_->GetInValueCount();
741 }
742 
GetInFrameStateCount() const743 size_t Gate::GetInFrameStateCount() const
744 {
745     return meta_->GetInFrameStateCount();
746 }
747 
GetRootCount() const748 size_t Gate::GetRootCount() const
749 {
750     return meta_->GetRootCount();
751 }
752 
MachineTypeStr(MachineType machineType) const753 std::string Gate::MachineTypeStr(MachineType machineType) const
754 {
755     const std::map<MachineType, const char *> strMap = {
756         {NOVALUE, "NOVALUE"},
757         {ANYVALUE, "ANYVALUE"},
758         {ARCH, "ARCH"},
759         {FLEX, "FLEX"},
760         {I1, "I1"},
761         {I8, "I8"},
762         {I16, "I16"},
763         {I32, "I32"},
764         {I64, "I64"},
765         {F32, "F32"},
766         {F64, "F64"},
767     };
768     if (strMap.count(machineType) > 0) {
769         return strMap.at(machineType);
770     }
771     return "MachineType-" + std::to_string(machineType);
772 }
773 
GateTypeStr(GateType gateType) const774 std::string Gate::GateTypeStr(GateType gateType) const
775 {
776     static const std::map<GateType, const char *> strMap = {
777         {GateType::NJSValue(), "NJS_VALUE"},
778         {GateType::TaggedValue(), "TAGGED_VALUE"},
779         {GateType::TaggedPointer(), "TAGGED_POINTER"},
780         {GateType::TaggedNPointer(), "TAGGED_NPOINTER"},
781         {GateType::Empty(), "EMPTY"},
782         {GateType::AnyType(), "ANY_TYPE"},
783     };
784 
785     std::string name = "";
786     if (strMap.count(gateType) > 0) {
787         name = strMap.at(gateType);
788     }
789     uint32_t r = gateType.GetType();
790     return name + std::string("-gateType(") + std::to_string(r) + std::string(")");
791 }
792 
Print(std::string additionOp,bool inListPreview,size_t highlightIdx,std::string_view comment) const793 void Gate::Print(std::string additionOp, bool inListPreview, size_t highlightIdx, std::string_view comment) const
794 {
795     LOG_COMPILER(INFO) << ToString(additionOp, inListPreview, highlightIdx, comment);
796 }
797 
DumpHeader(std::ostringstream & oss,const std::string & additionOp) const798 void Gate::DumpHeader(std::ostringstream &oss, const std::string& additionOp) const
799 {
800     auto opcode = GetOpCode();
801     ASSERT(opcode != OpCode::NOP && opcode != OpCode::DEAD);
802 
803     oss << "{\"id\":" << std::to_string(id_) << ", \"op\":\"" << GateMetaData::Str(opcode) << "\", ";
804     if (additionOp.compare("") != 0) {
805         auto additionOpName = (opcode == OpCode::JS_BYTECODE) ? "bytecode" : "typedop";
806         oss << "\"" << additionOpName << "\":\"" << additionOp;
807         oss << "\", ";
808     }
809     oss << "\"MType\":\"" << MachineTypeStr(GetMachineType()) << ", ";
810 
811     oss << "bitfield=0x" << std::hex << TryGetValue() << std::dec << ", ";
812     oss << "type=" << GateTypeStr(type_) << ", ";
813     oss << "stamp=" << std::to_string(static_cast<uint32_t>(stamp_)) << ", ";
814     oss << "mark=" << std::to_string(static_cast<uint32_t>(mark_)) << ", ";
815 }
816 
DumpInputs(std::ostringstream & oss,bool inListPreview,size_t highlightIdx) const817 void Gate::DumpInputs(std::ostringstream &oss, bool inListPreview, size_t highlightIdx) const
818 {
819     [[maybe_unused]] auto opcode = GetOpCode();
820     ASSERT(opcode != OpCode::NOP && opcode != OpCode::DEAD);
821 
822     size_t idx = 0;
823     auto stateSize = GetStateCount();
824     auto dependSize = GetDependCount();
825     auto valueSize = GetInValueCount();
826     auto frameStateSize = GetInFrameStateCount();
827     auto rootSize = GetRootCount();
828     size_t start = 0;
829     size_t end = stateSize;
830 
831     oss << "\",\"in\":[";
832     idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, oss);
833     end += dependSize;
834     start += stateSize;
835     idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, oss);
836     end += valueSize;
837     start += dependSize;
838     idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, oss);
839     end += frameStateSize;
840     start += valueSize;
841     idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, oss);
842     end += rootSize;
843     start += frameStateSize;
844     idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, oss, true);
845     oss << "]";
846 }
847 
DumpOutputs(std::ostringstream & oss,bool inListPreview) const848 void Gate::DumpOutputs(std::ostringstream &oss, bool inListPreview) const
849 {
850     auto opcode = GetOpCode();
851     ASSERT(opcode != OpCode::NOP && opcode != OpCode::DEAD);
852 
853     oss << ", \"out\":[";
854     if (!IsFirstOutNull()) {
855         const Out *curOut = GetFirstOutConst();
856         opcode = curOut->GetGateConst()->GetOpCode();
857         oss << std::to_string(curOut->GetGateConst()->GetId()) +
858                 (inListPreview ? std::string(":" + GateMetaData::Str(opcode)) : std::string(""));
859 
860         while (!curOut->IsNextOutNull()) {
861             curOut = curOut->GetNextOutConst();
862             oss << ", " +  std::to_string(curOut->GetGateConst()->GetId()) +
863                     (inListPreview ? std::string(":" + GateMetaData::Str(opcode))
864                                     : std::string(""));
865         }
866     }
867     oss << "]";
868 }
869 
DumpComment(std::ostringstream & oss,std::string_view comment)870 static void DumpComment(std::ostringstream &oss, std::string_view comment)
871 {
872     oss << ", \"comment\":\"" << comment << "\"";
873 }
874 
ToString(std::string additionOp,bool inListPreview,size_t highlightIdx,std::string_view comment) const875 std::string Gate::ToString(std::string additionOp, bool inListPreview, size_t highlightIdx,
876     std::string_view comment) const
877 {
878     auto opcode = GetOpCode();
879     if (opcode == OpCode::NOP || opcode == OpCode::DEAD) {
880         return "";
881     }
882 
883     std::ostringstream oss;
884     oss << std::dec;
885     DumpHeader(oss, additionOp);
886     DumpInputs(oss, inListPreview, highlightIdx);
887     DumpOutputs(oss, inListPreview);
888     if (!comment.empty()) {
889         DumpComment(oss, comment);
890     }
891     oss << "},";
892     return oss.str();
893 }
894 
ShortPrint(std::string bytecode,bool inListPreview,size_t highlightIdx) const895 void Gate::ShortPrint(std::string bytecode, bool inListPreview, size_t highlightIdx) const
896 {
897     auto opcode = GetOpCode();
898     if (opcode != OpCode::NOP && opcode != OpCode::DEAD) {
899         std::ostringstream log;
900         log << "(\"id\"=" << std::to_string(id_) << ", \"op\"=\"" << GateMetaData::Str(opcode) << "\", ";
901         log << ((bytecode.compare("") == 0) ? "" : "bytecode=") << bytecode;
902         log << ((bytecode.compare("") == 0) ? "" : ", ");
903         log << "\"MType\"=\"" + MachineTypeStr(GetMachineType()) + ", ";
904         log << "bitfield=0x" << std::hex << TryGetValue() << std::dec << ", ";
905         log << "type=" + GateTypeStr(type_) + ", ";
906         log << "\", in=[";
907 
908         size_t idx = 0;
909         auto stateSize = GetStateCount();
910         auto dependSize = GetDependCount();
911         auto valueSize = GetInValueCount();
912         auto frameStateSize = GetInFrameStateCount();
913         auto rootSize = GetRootCount();
914         size_t start = 0;
915         size_t end = stateSize;
916         idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
917         end += dependSize;
918         start += stateSize;
919         idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
920         end += valueSize;
921         start += dependSize;
922         idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
923         end += frameStateSize;
924         start += valueSize;
925         idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
926         end += rootSize;
927         start += frameStateSize;
928         idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log, true);
929 
930         log << "], out=[";
931 
932         if (!IsFirstOutNull()) {
933             const Out *curOut = GetFirstOutConst();
934             opcode = curOut->GetGateConst()->GetOpCode();
935             log << std::to_string(curOut->GetGateConst()->GetId()) <<
936                    (inListPreview ? std::string(":" + GateMetaData::Str(opcode)) : std::string(""));
937 
938             while (!curOut->IsNextOutNull()) {
939                 curOut = curOut->GetNextOutConst();
940                 log << ", " <<  std::to_string(curOut->GetGateConst()->GetId()) <<
941                        (inListPreview ? std::string(":" + GateMetaData::Str(opcode))
942                                       : std::string(""));
943             }
944         }
945         log << "])";
946         LOG_COMPILER(INFO) << std::dec << log.str();
947     }
948 }
949 
PrintInGate(size_t numIns,size_t idx,size_t size,bool inListPreview,size_t highlightIdx,std::ostringstream & log,bool isEnd) const950 size_t Gate::PrintInGate(size_t numIns, size_t idx, size_t size, bool inListPreview, size_t highlightIdx,
951                          std::ostringstream &log, bool isEnd) const
952 {
953     log << "[";
954     for (; idx < numIns; idx++) {
955         log << ((idx == size) ? "" : ", ");
956         log << ((idx == highlightIdx) ? "\033[4;31m" : "");
957         log << ((IsInGateNull(idx)
958                 ? "N"
959                 : (std::to_string(GetInGateConst(idx)->GetId()) +
960                     (inListPreview ? std::string(":" + GateMetaData::Str(GetInGateConst(idx)->GetOpCode()))
961                                    : std::string("")))));
962         log << ((idx == highlightIdx) ? "\033[0m" : "");
963     }
964     log << "]";
965     log << ((isEnd) ? "" : ", ");
966     return idx;
967 }
968 
GetBytecodeStr() const969 std::string Gate::GetBytecodeStr() const
970 {
971     switch (GetOpCode()) {
972         case OpCode::JS_BYTECODE: {
973             return GetJSBytecodeMetaData()->Str();
974         }
975         case OpCode::TYPED_BINARY_OP: {
976             auto typedOp = TypedBinaryAccessor(GetOneParameterMetaData()->GetValue()).GetTypedBinOp();
977             return GateMetaData::Str(typedOp);
978         }
979         case OpCode::TYPED_UNARY_OP: {
980             auto typedOp = TypedUnaryAccessor(GetOneParameterMetaData()->GetValue()).GetTypedUnOp();
981             return GateMetaData::Str(typedOp);
982         }
983         case OpCode::TYPED_CONDITION_JUMP: {
984             auto typedOp = TypedJumpAccessor(GetOneParameterMetaData()->GetValue()).GetTypedJumpOp();
985             return GateMetaData::Str(typedOp);
986         }
987         case OpCode::LOAD_ELEMENT: {
988             auto typedOp = static_cast<TypedLoadOp>(GetOneParameterMetaData()->GetValue());
989             return GateMetaData::Str(typedOp);
990         }
991         case OpCode::STORE_ELEMENT: {
992             auto typedOp = static_cast<TypedStoreOp>(GetOneParameterMetaData()->GetValue());
993             return GateMetaData::Str(typedOp);
994         }
995         case OpCode::TYPED_CALLTARGETCHECK_OP: {
996             TypedCallTargetCheckAccessor accessor(GetOneParameterMetaData()->GetValue());
997             auto typedOp = accessor.GetCallTargetCheckOp();
998             return GateMetaData::Str(typedOp);
999         }
1000         case OpCode::CONVERT:
1001         case OpCode::CHECK_AND_CONVERT: {
1002             ValuePairTypeAccessor accessor(GetOneParameterMetaData()->GetValue());
1003             return GateMetaData::Str(accessor.GetSrcType()) + "_TO_" +
1004                 GateMetaData::Str(accessor.GetDstType());
1005         }
1006         default:
1007             return "";
1008     }
1009     return "";
1010 }
1011 
PrintWithBytecode(std::string_view comment) const1012 void Gate::PrintWithBytecode(std::string_view comment) const
1013 {
1014     PrintGateWithAdditionOp(GetBytecodeStr(), comment);
1015 }
1016 
PrintGateWithAdditionOp(std::string additionOp,std::string_view comment) const1017 void Gate::PrintGateWithAdditionOp(std::string additionOp, std::string_view comment) const
1018 {
1019     Print(additionOp, false, -1, comment);
1020 }
1021 
GetMark(TimeStamp stamp) const1022 MarkCode Gate::GetMark(TimeStamp stamp) const
1023 {
1024     return (stamp_ == stamp) ? mark_ : MarkCode::NO_MARK;
1025 }
1026 
SetMark(MarkCode mark,TimeStamp stamp)1027 void Gate::SetMark(MarkCode mark, TimeStamp stamp)
1028 {
1029     stamp_ = stamp;
1030     mark_ = mark;
1031 }
1032 }  // namespace panda::ecmascript::kungfu
1033