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