• 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 "ecmascript/compiler/bytecode_circuit_builder.h"
18 
19 namespace panda::ecmascript::kungfu {
20 constexpr size_t ONE_DEPEND = 1;
21 constexpr size_t MANY_DEPEND = 2;
22 constexpr size_t NO_DEPEND = 0;
23 // NOLINTNEXTLINE(readability-function-size)
GetProperties() const24 Properties OpCode::GetProperties() const
25 {
26 // general schema: [STATE]s + [DEPEND]s + [VALUE]s + [ROOT]
27 // GENERAL_STATE for any opcode match in
28 // {IF_TRUE, IF_FALSE, SWITCH_CASE, DEFAULT_CASE, MERGE, LOOP_BEGIN, STATE_ENTRY}
29 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
30 #define STATE(...) (std::make_pair(std::vector<OpCode>{__VA_ARGS__}, false))
31 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
32 #define VALUE(...) (std::make_pair(std::vector<MachineType>{__VA_ARGS__}, false))
33 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
34 #define MANY_STATE(...) (std::make_pair(std::vector<OpCode>{__VA_ARGS__}, true))
35 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
36 #define MANY_VALUE(...) (std::make_pair(std::vector<MachineType>{__VA_ARGS__}, true))
37 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
38 #define NO_STATE (std::nullopt)
39 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
40 #define NO_VALUE (std::nullopt)
41 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
42 #define NO_ROOT (std::nullopt)
43 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
44 #define GENERAL_STATE (NOP)
45     switch (op_) {
46         // SHARED
47         case NOP:
48         case CIRCUIT_ROOT:
49             return {NOVALUE, NO_STATE, NO_DEPEND, NO_VALUE, NO_ROOT};
50         case STATE_ENTRY:
51         case DEPEND_ENTRY:
52         case FRAMESTATE_ENTRY:
53         case RETURN_LIST:
54         case THROW_LIST:
55         case CONSTANT_LIST:
56         case ALLOCA_LIST:
57         case ARG_LIST:
58             return {NOVALUE, NO_STATE, NO_DEPEND, NO_VALUE, OpCode(CIRCUIT_ROOT)};
59         case RETURN:
60             return {NOVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, VALUE(ANYVALUE), OpCode(RETURN_LIST)};
61         case RETURN_VOID:
62             return {NOVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, NO_VALUE, OpCode(RETURN_LIST)};
63         case THROW:
64             return {NOVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, VALUE(JSMachineType()), OpCode(THROW_LIST)};
65         case ORDINARY_BLOCK:
66             return {NOVALUE, STATE(OpCode(GENERAL_STATE)), NO_DEPEND, NO_VALUE, NO_ROOT};
67         case IF_BRANCH:
68             return {NOVALUE, STATE(OpCode(GENERAL_STATE)), NO_DEPEND, VALUE(I1), NO_ROOT};
69         case SWITCH_BRANCH:
70             return {NOVALUE, STATE(OpCode(GENERAL_STATE)), NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
71         case IF_TRUE:
72         case IF_FALSE:
73             return {NOVALUE, STATE(OpCode(IF_BRANCH)), NO_DEPEND, NO_VALUE, NO_ROOT};
74         case SWITCH_CASE:
75         case DEFAULT_CASE:
76             return {NOVALUE, STATE(OpCode(SWITCH_BRANCH)), NO_DEPEND, NO_VALUE, NO_ROOT};
77         case MERGE:
78             return {NOVALUE, MANY_STATE(OpCode(GENERAL_STATE)), NO_DEPEND, NO_VALUE, NO_ROOT};
79         case LOOP_BEGIN:
80             return {NOVALUE, STATE(OpCode(GENERAL_STATE), OpCode(LOOP_BACK)), NO_DEPEND, NO_VALUE, NO_ROOT};
81         case LOOP_BACK:
82             return {NOVALUE, STATE(OpCode(GENERAL_STATE)), NO_DEPEND, NO_VALUE, NO_ROOT};
83         case VALUE_SELECTOR:
84             return {FLEX, STATE(OpCode(GENERAL_STATE)), NO_DEPEND, MANY_VALUE(FLEX), NO_ROOT};
85         case DEPEND_SELECTOR:
86             return {NOVALUE, STATE(OpCode(GENERAL_STATE)), MANY_DEPEND, NO_VALUE, NO_ROOT};
87         case DEPEND_RELAY:
88             return {NOVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, NO_VALUE, NO_ROOT};
89         case DEPEND_AND:
90             return {NOVALUE, NO_STATE, MANY_DEPEND, NO_VALUE, NO_ROOT};
91         // High Level IR
92         case JS_BYTECODE:
93             return {FLEX, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, MANY_VALUE(ANYVALUE), NO_ROOT};
94         case IF_SUCCESS:
95         case IF_EXCEPTION:
96             return {NOVALUE, STATE(OpCode(GENERAL_STATE)), NO_DEPEND, NO_VALUE, NO_ROOT};
97         case GET_EXCEPTION:
98             return {I64, NO_STATE, ONE_DEPEND, NO_VALUE, NO_ROOT};
99         // Middle Level IR
100         case RUNTIME_CALL:
101         case BYTECODE_CALL:
102         case CALL:
103             return {FLEX, NO_STATE, ONE_DEPEND, MANY_VALUE(ANYVALUE, ANYVALUE), NO_ROOT};
104         case ALLOCA:
105             return {ARCH, NO_STATE, NO_DEPEND, NO_VALUE, OpCode(ALLOCA_LIST)};
106         case ARG:
107             return {FLEX, NO_STATE, NO_DEPEND, NO_VALUE, OpCode(ARG_LIST)};
108         case MUTABLE_DATA:
109         case CONST_DATA:
110             return {ARCH, NO_STATE, NO_DEPEND, NO_VALUE, OpCode(CONSTANT_LIST)};
111         case RELOCATABLE_DATA:
112             return {ARCH, NO_STATE, NO_DEPEND, NO_VALUE, OpCode(CONSTANT_LIST)};
113         case CONSTANT:
114             return {FLEX, NO_STATE, NO_DEPEND, NO_VALUE, OpCode(CONSTANT_LIST)};
115         case ZEXT_TO_INT64:
116             return {I64, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
117         case ZEXT_TO_INT32:
118             return {I32, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
119         case ZEXT_TO_INT16:
120             return {I16, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
121         case SEXT_TO_INT64:
122             return {I64, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
123         case SEXT_TO_INT32:
124             return {I32, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
125         case TRUNC_TO_INT32:
126             return {I32, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
127         case TRUNC_TO_INT1:
128             return {I1, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
129         case REV:
130             return {FLEX, NO_STATE, NO_DEPEND, VALUE(FLEX), NO_ROOT};
131         case ADD:
132         case SUB:
133         case MUL:
134         case EXP:
135         case SDIV:
136         case SMOD:
137         case UDIV:
138         case UMOD:
139         case FDIV:
140         case FMOD:
141         case AND:
142         case XOR:
143         case OR:
144         case LSL:
145         case LSR:
146         case ASR:
147             return {FLEX, NO_STATE, NO_DEPEND, VALUE(FLEX, FLEX), NO_ROOT};
148         case SLT:
149         case SLE:
150         case SGT:
151         case SGE:
152         case ULT:
153         case ULE:
154         case UGT:
155         case UGE:
156         case FLT:
157         case FLE:
158         case FGT:
159         case FGE:
160         case EQ:
161         case NE:
162             return {I1, NO_STATE, NO_DEPEND, VALUE(ANYVALUE, ANYVALUE), NO_ROOT};
163         case LOAD:
164             return {FLEX, NO_STATE, ONE_DEPEND, VALUE(ARCH), NO_ROOT};
165         case STORE:
166             return {NOVALUE, NO_STATE, ONE_DEPEND, VALUE(ANYVALUE, ARCH), NO_ROOT};
167         case TAGGED_TO_INT64:
168             return {I64, NO_STATE, NO_DEPEND, VALUE(I64), NO_ROOT};
169         case INT64_TO_TAGGED:
170             return {I64, NO_STATE, NO_DEPEND, VALUE(I64), NO_ROOT};
171         case SIGNED_INT_TO_FLOAT:
172         case UNSIGNED_INT_TO_FLOAT:
173             return {FLEX, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
174         case FLOAT_TO_SIGNED_INT:
175         case UNSIGNED_FLOAT_TO_INT:
176             return {FLEX, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
177         case BITCAST:
178             return {FLEX, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
179         default:
180             std::cerr << "Please complete OpCode properties (OpCode=" << op_ << ")" << std::endl;
181             UNREACHABLE();
182     }
183 #undef STATE
184 #undef VALUE
185 #undef MANY_STATE
186 #undef MANY_VALUE
187 #undef NO_STATE
188 #undef NO_VALUE
189 #undef NO_ROOT
190 #undef GENERAL_STATE
191 }
192 
Str() const193 std::string OpCode::Str() const
194 {
195     const std::map<GateOp, const char *> strMap = {
196         {NOP, "NOP"},
197         {CIRCUIT_ROOT, "CIRCUIT_ROOT"},
198         {STATE_ENTRY, "STATE_ENTRY"},
199         {DEPEND_ENTRY, "DEPEND_ENTRY"},
200         {FRAMESTATE_ENTRY, "FRAMESTATE_ENTRY"},
201         {RETURN_LIST, "RETURN_LIST"},
202         {THROW_LIST, "THROW_LIST"},
203         {CONSTANT_LIST, "CONSTANT_LIST"},
204         {ALLOCA_LIST, "ALLOCA_LIST"},
205         {ARG_LIST, "ARG_LIST"},
206         {RETURN, "RETURN"},
207         {RETURN_VOID, "RETURN_VOID"},
208         {THROW, "THROW"},
209         {ORDINARY_BLOCK, "ORDINARY_BLOCK"},
210         {IF_BRANCH, "IF_BRANCH"},
211         {SWITCH_BRANCH, "SWITCH_BRANCH"},
212         {IF_TRUE, "IF_TRUE"},
213         {IF_FALSE, "IF_FALSE"},
214         {SWITCH_CASE, "SWITCH_CASE"},
215         {DEFAULT_CASE, "DEFAULT_CASE"},
216         {MERGE, "MERGE"},
217         {LOOP_BEGIN, "LOOP_BEGIN"},
218         {LOOP_BACK, "LOOP_BACK"},
219         {VALUE_SELECTOR, "VALUE_SELECTOR"},
220         {DEPEND_SELECTOR, "DEPEND_SELECTOR"},
221         {DEPEND_RELAY, "DEPEND_RELAY"},
222         {DEPEND_AND, "DEPEND_AND"},
223         {JS_BYTECODE, "JS_BYTECODE"},
224         {IF_SUCCESS, "IF_SUCCESS"},
225         {IF_EXCEPTION, "IF_EXCEPTION"},
226         {GET_EXCEPTION, "GET_EXCEPTION"},
227         {RUNTIME_CALL, "RUNTIME_CALL"},
228         {CALL, "CALL"},
229         {BYTECODE_CALL, "BYTECODE_CALL"},
230         {ALLOCA, "ALLOCA"},
231         {ARG, "ARG"},
232         {MUTABLE_DATA, "MUTABLE_DATA"},
233         {RELOCATABLE_DATA, "RELOCATABLE_DATA"},
234         {CONST_DATA, "CONST_DATA"},
235         {CONSTANT, "CONSTANT"},
236         {ZEXT_TO_INT64, "ZEXT_TO_INT64"},
237         {ZEXT_TO_INT32, "ZEXT_TO_INT32"},
238         {ZEXT_TO_INT16, "ZEXT_TO_INT16"},
239         {SEXT_TO_INT64, "SEXT_TO_INT64"},
240         {SEXT_TO_INT32, "SEXT_TO_INT32"},
241         {TRUNC_TO_INT32, "TRUNC_TO_INT32"},
242         {TRUNC_TO_INT1, "TRUNC_TO_INT1"},
243         {REV, "REV"},
244         {ADD, "ADD"},
245         {SUB, "SUB"},
246         {MUL, "MUL"},
247         {EXP, "EXP"},
248         {SDIV, "SDIV"},
249         {SMOD, "SMOD"},
250         {UDIV, "UDIV"},
251         {UMOD, "UMOD"},
252         {FDIV, "FDIV"},
253         {FMOD, "FMOD"},
254         {AND, "AND"},
255         {XOR, "XOR"},
256         {OR, "OR"},
257         {LSL, "LSL"},
258         {LSR, "LSR"},
259         {ASR, "ASR"},
260         {SLT, "SLT"},
261         {SLE, "SLE"},
262         {SGT, "SGT"},
263         {SGE, "SGE"},
264         {ULT, "ULT"},
265         {ULE, "ULE"},
266         {UGT, "UGT"},
267         {UGE, "UGE"},
268         {FLT, "FLT"},
269         {FLE, "FLE"},
270         {FGT, "FGT"},
271         {FGE, "FGE"},
272         {EQ, "EQ"},
273         {NE, "NE"},
274         {LOAD, "LOAD"},
275         {STORE, "STORE"},
276         {TAGGED_TO_INT64, "TAGGED_TO_INT64"},
277         {INT64_TO_TAGGED, "INT64_TO_TAGGED"},
278         {SIGNED_INT_TO_FLOAT, "SIGNED_INT_TO_FLOAT"},
279         {UNSIGNED_INT_TO_FLOAT, "UNSIGNED_INT_TO_FLOAT"},
280         {FLOAT_TO_SIGNED_INT, "FLOAT_TO_SIGNED_INT"},
281         {UNSIGNED_FLOAT_TO_INT, "UNSIGNED_FLOAT_TO_INT"},
282         {BITCAST, "BITCAST"},
283     };
284     if (strMap.count(op_) > 0) {
285         return strMap.at(op_);
286     }
287     return "OP-" + std::to_string(op_);
288 }
289 // 4 : 4 means that there are 4 args in total
GetOpCodeNumInsArray(BitField bitfield) const290 std::array<size_t, 4> OpCode::GetOpCodeNumInsArray(BitField bitfield) const
291 {
292     const size_t manyDepend = 2;
293     auto properties = GetProperties();
294     auto stateProp = properties.statesIn;
295     auto dependProp = properties.dependsIn;
296     auto valueProp = properties.valuesIn;
297     auto rootProp = properties.states;
298     size_t stateSize = stateProp.has_value() ? (stateProp->second ? bitfield : stateProp->first.size()) : 0;
299     size_t dependSize = (dependProp == manyDepend) ? bitfield : dependProp;
300     size_t valueSize = valueProp.has_value() ? (valueProp->second ? bitfield : valueProp->first.size()) : 0;
301     size_t rootSize = rootProp.has_value() ? 1 : 0;
302     return {stateSize, dependSize, valueSize, rootSize};
303 }
304 
GetOpCodeNumIns(BitField bitfield) const305 size_t OpCode::GetOpCodeNumIns(BitField bitfield) const
306 {
307     auto numInsArray = GetOpCodeNumInsArray(bitfield);
308     // 0 : 0 means the first element
309     // 1 : 1 means the second element
310     // 2 : 2 means the third element
311     // 3 : 3 means the fourth element
312     return numInsArray[0] + numInsArray[1] + numInsArray[2] + numInsArray[3];
313 }
314 
GetMachineType() const315 MachineType OpCode::GetMachineType() const
316 {
317     return GetProperties().returnValue;
318 }
319 
GetInMachineType(BitField bitfield,size_t idx) const320 MachineType OpCode::GetInMachineType(BitField bitfield, size_t idx) const
321 {
322     auto numInsArray = GetOpCodeNumInsArray(bitfield);
323     auto valueProp = GetProperties().valuesIn;
324     idx -= numInsArray[0];
325     idx -= numInsArray[1];
326     ASSERT(valueProp.has_value());
327     if (valueProp->second) {
328         return valueProp->first.at(std::min(idx, valueProp->first.size() - 1));
329     }
330     return valueProp->first.at(idx);
331 }
332 
GetInStateCode(size_t idx) const333 OpCode OpCode::GetInStateCode(size_t idx) const
334 {
335     auto stateProp = GetProperties().statesIn;
336     ASSERT(stateProp.has_value());
337     if (stateProp->second) {
338         return stateProp->first.at(std::min(idx, stateProp->first.size() - 1));
339     }
340     return stateProp->first.at(idx);
341 }
342 
MachineTypeToStr(MachineType machineType)343 std::string MachineTypeToStr(MachineType machineType)
344 {
345     switch (machineType) {
346         case NOVALUE:
347             return "NOVALUE";
348         case ANYVALUE:
349             return "ANYVALUE";
350         case I1:
351             return "I1";
352         case I8:
353             return "I8";
354         case I16:
355             return "I16";
356         case I32:
357             return "I32";
358         case I64:
359             return "I64";
360         case F32:
361             return "F32";
362         case F64:
363             return "F64";
364         default:
365             return "???";
366     }
367 }
368 
CheckNullInput() const369 std::optional<std::pair<std::string, size_t>> Gate::CheckNullInput() const
370 {
371     const auto numIns = GetNumIns();
372     for (size_t idx = 0; idx < numIns; idx++) {
373         if (IsInGateNull(idx)) {
374             return std::make_pair("In list contains null", idx);
375         }
376     }
377     return std::nullopt;
378 }
379 
CheckStateInput() const380 std::optional<std::pair<std::string, size_t>> Gate::CheckStateInput() const
381 {
382     const auto numInsArray = GetOpCode().GetOpCodeNumInsArray(GetBitField());
383     size_t stateStart = 0;
384     size_t stateEnd = numInsArray[0];
385     for (size_t idx = stateStart; idx < stateEnd; idx++) {
386         auto stateProp = GetOpCode().GetProperties().statesIn;
387         ASSERT(stateProp.has_value());
388         auto expectedIn = GetOpCode().GetInStateCode(idx);
389         auto actualIn = GetInGateConst(idx)->GetOpCode();
390         if (expectedIn == OpCode::NOP) {  // general
391             if (!actualIn.IsGeneralState()) {
392                 return std::make_pair(
393                     "State input does not match (expected:<General State> actual:" + actualIn.Str() + ")", idx);
394             }
395         } else {
396             if (expectedIn != actualIn) {
397                 return std::make_pair(
398                     "State input does not match (expected:" + expectedIn.Str() + " actual:" + actualIn.Str() + ")",
399                     idx);
400             }
401         }
402     }
403     return std::nullopt;
404 }
405 
CheckValueInput() const406 std::optional<std::pair<std::string, size_t>> Gate::CheckValueInput() const
407 {
408     const auto numInsArray = GetOpCode().GetOpCodeNumInsArray(GetBitField());
409     size_t valueStart = numInsArray[0] + numInsArray[1];
410     size_t valueEnd = numInsArray[0] + numInsArray[1] + numInsArray[2]; // 2 : 2 means the third element.
411     for (size_t idx = valueStart; idx < valueEnd; idx++) {
412         auto expectedIn = GetOpCode().GetInMachineType(GetBitField(), idx);
413         auto actualIn = GetInGateConst(idx)->GetOpCode().GetMachineType();
414         if (expectedIn == MachineType::FLEX) {
415             expectedIn = GetMachineType();
416         }
417         if (actualIn == MachineType::FLEX) {
418             actualIn = GetInGateConst(idx)->GetMachineType();
419         }
420 
421         if ((expectedIn != actualIn) && (expectedIn != ANYVALUE)) {
422             return std::make_pair("Value input does not match (expected: " + MachineTypeToStr(expectedIn) +
423                     " actual: " + MachineTypeToStr(actualIn) + ")",
424                 idx);
425         }
426     }
427     return std::nullopt;
428 }
429 
CheckDependInput() const430 std::optional<std::pair<std::string, size_t>> Gate::CheckDependInput() const
431 {
432     const auto numInsArray = GetOpCode().GetOpCodeNumInsArray(GetBitField());
433     size_t dependStart = numInsArray[0];
434     size_t dependEnd = dependStart + numInsArray[1];
435     for (size_t idx = dependStart; idx < dependEnd; idx++) {
436         if (GetInGateConst(idx)->GetNumInsArray()[1] == 0 &&
437             GetInGateConst(idx)->GetOpCode() != OpCode::DEPEND_ENTRY) {
438             return std::make_pair("Depend input is side-effect free", idx);
439         }
440     }
441     return std::nullopt;
442 }
443 
CheckStateOutput() const444 std::optional<std::pair<std::string, size_t>> Gate::CheckStateOutput() const
445 {
446     if (GetOpCode().IsState()) {
447         size_t cnt = 0;
448         const Gate *curGate = this;
449         if (!curGate->IsFirstOutNull()) {
450             const Out *curOut = curGate->GetFirstOutConst();
451             if (curOut->GetGateConst()->GetOpCode().IsState()) {
452                 cnt++;
453             }
454             while (!curOut->IsNextOutNull()) {
455                 curOut = curOut->GetNextOutConst();
456                 if (curOut->GetGateConst()->GetOpCode().IsState()) {
457                     cnt++;
458                 }
459             }
460         }
461         size_t expected = 0;
462         bool needCheck = true;
463         if (GetOpCode().IsTerminalState()) {
464             expected = 0;
465         } else if (GetOpCode() == OpCode::IF_BRANCH) {
466             expected = 2; // 2: expected number of state out branches
467         } else if (GetOpCode() == OpCode::SWITCH_BRANCH) {
468             needCheck = false;
469         } else {
470             expected = 1;
471         }
472         if (needCheck && cnt != expected) {
473             return std::make_pair("Number of state out branches is not valid (expected:" + std::to_string(expected) +
474                     " actual:" + std::to_string(cnt) + ")",
475                 -1);
476         }
477     }
478     return std::nullopt;
479 }
480 
CheckBranchOutput() const481 std::optional<std::pair<std::string, size_t>> Gate::CheckBranchOutput() const
482 {
483     std::map<std::pair<OpCode, BitField>, size_t> setOfOps;
484     if (GetOpCode() == OpCode::IF_BRANCH || GetOpCode() == OpCode::SWITCH_BRANCH) {
485         size_t cnt = 0;
486         const Gate *curGate = this;
487         if (!curGate->IsFirstOutNull()) {
488             const Out *curOut = curGate->GetFirstOutConst();
489             if (curOut->GetGateConst()->GetOpCode().IsState()) {
490                 setOfOps[{curOut->GetGateConst()->GetOpCode(), curOut->GetGateConst()->GetBitField()}]++;
491                 cnt++;
492             }
493             while (!curOut->IsNextOutNull()) {
494                 curOut = curOut->GetNextOutConst();
495                 if (curOut->GetGateConst()->GetOpCode().IsState()) {
496                     setOfOps[{curOut->GetGateConst()->GetOpCode(), curOut->GetGateConst()->GetBitField()}]++;
497                     cnt++;
498                 }
499             }
500         }
501         if (setOfOps.size() != cnt) {
502             return std::make_pair("Duplicate state out branches", -1);
503         }
504     }
505     return std::nullopt;
506 }
507 
CheckNOP() const508 std::optional<std::pair<std::string, size_t>> Gate::CheckNOP() const
509 {
510     if (GetOpCode() == OpCode::NOP) {
511         if (!IsFirstOutNull()) {
512             return std::make_pair("NOP gate used by other gates", -1);
513         }
514     }
515     return std::nullopt;
516 }
517 
CheckSelector() const518 std::optional<std::pair<std::string, size_t>> Gate::CheckSelector() const
519 {
520     if (GetOpCode() == OpCode::VALUE_SELECTOR || GetOpCode() == OpCode::DEPEND_SELECTOR) {
521         auto stateOp = GetInGateConst(0)->GetOpCode();
522         if (stateOp == OpCode::MERGE || stateOp == OpCode::LOOP_BEGIN) {
523             if (GetInGateConst(0)->GetNumIns() != GetNumIns() - 1) {
524                 if (GetOpCode() == OpCode::DEPEND_SELECTOR) {
525                     return std::make_pair("Number of depend flows does not match control flows (expected:" +
526                             std::to_string(GetInGateConst(0)->GetNumIns()) +
527                             " actual:" + std::to_string(GetNumIns() - 1) + ")",
528                         -1);
529                 } else {
530                     return std::make_pair("Number of data flows does not match control flows (expected:" +
531                             std::to_string(GetInGateConst(0)->GetNumIns()) +
532                             " actual:" + std::to_string(GetNumIns() - 1) + ")",
533                         -1);
534                 }
535             }
536         } else {
537             return std::make_pair(
538                 "State input does not match (expected:[MERGE|LOOP_BEGIN] actual:" + stateOp.Str() + ")", 0);
539         }
540     }
541     return std::nullopt;
542 }
543 
CheckRelay() const544 std::optional<std::pair<std::string, size_t>> Gate::CheckRelay() const
545 {
546     if (GetOpCode() == OpCode::DEPEND_RELAY) {
547         auto stateOp = GetInGateConst(0)->GetOpCode();
548         if (!(stateOp == OpCode::IF_TRUE || stateOp == OpCode::IF_FALSE || stateOp == OpCode::SWITCH_CASE ||
549             stateOp == OpCode::DEFAULT_CASE || stateOp == OpCode::IF_SUCCESS || stateOp == OpCode::IF_EXCEPTION)) {
550             return std::make_pair("State input does not match ("
551                 "expected:[IF_TRUE|IF_FALSE|SWITCH_CASE|DEFAULT_CASE|IF_SUCCESS|IF_EXCEPTION] actual:" +
552                 stateOp.Str() + ")", 0);
553         }
554     }
555     return std::nullopt;
556 }
557 
SpecialCheck() const558 std::optional<std::pair<std::string, size_t>> Gate::SpecialCheck() const
559 {
560     {
561         auto ret = CheckNOP();
562         if (ret.has_value()) {
563             return ret;
564         }
565     }
566     {
567         auto ret = CheckSelector();
568         if (ret.has_value()) {
569             return ret;
570         }
571     }
572     {
573         auto ret = CheckRelay();
574         if (ret.has_value()) {
575             return ret;
576         }
577     }
578     return std::nullopt;
579 }
580 
Verify() const581 bool Gate::Verify() const
582 {
583     std::string errorString;
584     size_t highlightIdx = -1;
585     bool failed = false;
586     {
587         auto ret = CheckNullInput();
588         if (ret.has_value()) {
589             failed = true;
590             std::tie(errorString, highlightIdx) = ret.value();
591         }
592     }
593     if (!failed) {
594         auto ret = CheckStateInput();
595         if (ret.has_value()) {
596             failed = true;
597             std::tie(errorString, highlightIdx) = ret.value();
598         }
599     }
600     if (!failed) {
601         auto ret = CheckValueInput();
602         if (ret.has_value()) {
603             failed = true;
604             std::tie(errorString, highlightIdx) = ret.value();
605         }
606     }
607     if (!failed) {
608         auto ret = CheckDependInput();
609         if (ret.has_value()) {
610             failed = true;
611             std::tie(errorString, highlightIdx) = ret.value();
612         }
613     }
614     if (!failed) {
615         auto ret = CheckStateOutput();
616         if (ret.has_value()) {
617             failed = true;
618             std::tie(errorString, highlightIdx) = ret.value();
619         }
620     }
621     if (!failed) {
622         auto ret = CheckBranchOutput();
623         if (ret.has_value()) {
624             failed = true;
625             std::tie(errorString, highlightIdx) = ret.value();
626         }
627     }
628     if (!failed) {
629         auto ret = SpecialCheck();
630         if (ret.has_value()) {
631             failed = true;
632             std::tie(errorString, highlightIdx) = ret.value();
633         }
634     }
635     if (failed) {
636         std::cerr << "[Verifier][Error] Gate level input list schema verify failed" << std::endl;
637         Print("", true, highlightIdx);
638         std::cerr << "Note: " << errorString << std::endl;
639     }
640     return !failed;
641 }
642 
JSMachineType()643 MachineType JSMachineType()
644 {
645     return MachineType::I64;
646 }
647 
GetOpCodeNumIns(OpCode opcode,BitField bitfield)648 size_t GetOpCodeNumIns(OpCode opcode, BitField bitfield)
649 {
650     return opcode.GetOpCodeNumIns(bitfield);
651 }
652 
SetNextOut(const Out * ptr)653 void Out::SetNextOut(const Out *ptr)
654 {
655     nextOut_ =
656         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
657         static_cast<GateRef>((reinterpret_cast<const uint8_t *>(ptr)) - (reinterpret_cast<const uint8_t *>(this)));
658 }
659 
GetNextOut()660 Out *Out::GetNextOut()
661 {
662     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
663     return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + nextOut_);
664 }
665 
GetNextOutConst() const666 const Out *Out::GetNextOutConst() const
667 {
668     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
669     return reinterpret_cast<const Out *>((reinterpret_cast<const uint8_t *>(this)) + nextOut_);
670 }
671 
SetPrevOut(const Out * ptr)672 void Out::SetPrevOut(const Out *ptr)
673 {
674     prevOut_ =
675         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
676         static_cast<GateRef>((reinterpret_cast<const uint8_t *>(ptr)) - (reinterpret_cast<const uint8_t *>(this)));
677 }
678 
GetPrevOut()679 Out *Out::GetPrevOut()
680 {
681     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
682     return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + prevOut_);
683 }
684 
GetPrevOutConst() const685 const Out *Out::GetPrevOutConst() const
686 {
687     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
688     return reinterpret_cast<const Out *>((reinterpret_cast<const uint8_t *>(this)) + prevOut_);
689 }
690 
SetIndex(OutIdx idx)691 void Out::SetIndex(OutIdx idx)
692 {
693     idx_ = idx;
694 }
695 
GetIndex() const696 OutIdx Out::GetIndex() const
697 {
698     return idx_;
699 }
700 
GetGate()701 Gate *Out::GetGate()
702 {
703     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
704     return reinterpret_cast<Gate *>(&this[idx_ + 1]);
705 }
706 
GetGateConst() const707 const Gate *Out::GetGateConst() const
708 {
709     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
710     return reinterpret_cast<const Gate *>(&this[idx_ + 1]);
711 }
712 
SetPrevOutNull()713 void Out::SetPrevOutNull()
714 {
715     prevOut_ = 0;
716 }
717 
IsPrevOutNull() const718 bool Out::IsPrevOutNull() const
719 {
720     return prevOut_ == 0;
721 }
722 
SetNextOutNull()723 void Out::SetNextOutNull()
724 {
725     nextOut_ = 0;
726 }
727 
IsNextOutNull() const728 bool Out::IsNextOutNull() const
729 {
730     return nextOut_ == 0;
731 }
732 
SetGate(const Gate * ptr)733 void In::SetGate(const Gate *ptr)
734 {
735     gatePtr_ =
736         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
737         static_cast<GateRef>((reinterpret_cast<const uint8_t *>(ptr)) - (reinterpret_cast<const uint8_t *>(this)));
738 }
739 
GetGate()740 Gate *In::GetGate()
741 {
742     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
743     return reinterpret_cast<Gate *>((reinterpret_cast<uint8_t *>(this)) + gatePtr_);
744 }
745 
GetGateConst() const746 const Gate *In::GetGateConst() const
747 {
748     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
749     return reinterpret_cast<const Gate *>((reinterpret_cast<const uint8_t *>(this)) + gatePtr_);
750 }
751 
SetGateNull()752 void In::SetGateNull()
753 {
754     gatePtr_ = 0;
755 }
756 
IsGateNull() const757 bool In::IsGateNull() const
758 {
759     return gatePtr_ == 0;
760 }
761 
762 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
Gate(GateId id,OpCode opcode,MachineType bitValue,BitField bitfield,Gate * inList[],GateType type,MarkCode mark)763 Gate::Gate(GateId id, OpCode opcode, MachineType bitValue, BitField bitfield, Gate *inList[], GateType type,
764            MarkCode mark)
765     : id_(id), opcode_(opcode), bitValue_(bitValue), type_(type), stamp_(1), mark_(mark), bitfield_(bitfield),
766     firstOut_(0)
767 {
768     auto numIns = GetNumIns();
769     for (size_t idx = 0; idx < numIns; idx++) {
770         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
771         auto in = inList[idx];
772         if (in == nullptr) {
773             GetIn(idx)->SetGateNull();
774         } else {
775             NewIn(idx, in);
776         }
777         auto curOut = GetOut(idx);
778         curOut->SetIndex(idx);
779     }
780 }
781 
Gate(GateId id,OpCode opcode,BitField bitfield,Gate * inList[],GateType type,MarkCode mark)782 Gate::Gate(GateId id, OpCode opcode, BitField bitfield, Gate *inList[], GateType type, MarkCode mark)
783     : id_(id), opcode_(opcode), type_(type), stamp_(1), mark_(mark), bitfield_(bitfield), firstOut_(0)
784 {
785     auto numIns = GetNumIns();
786     for (size_t idx = 0; idx < numIns; idx++) {
787         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
788         auto in = inList[idx];
789         if (in == nullptr) {
790             GetIn(idx)->SetGateNull();
791         } else {
792             NewIn(idx, in);
793         }
794         auto curOut = GetOut(idx);
795         curOut->SetIndex(idx);
796     }
797 }
798 
GetOutListSize(size_t numIns)799 size_t Gate::GetOutListSize(size_t numIns)
800 {
801     return numIns * sizeof(Out);
802 }
803 
GetOutListSize() const804 size_t Gate::GetOutListSize() const
805 {
806     return Gate::GetOutListSize(GetNumIns());
807 }
808 
GetInListSize(size_t numIns)809 size_t Gate::GetInListSize(size_t numIns)
810 {
811     return numIns * sizeof(In);
812 }
813 
GetInListSize() const814 size_t Gate::GetInListSize() const
815 {
816     return Gate::GetInListSize(GetNumIns());
817 }
818 
GetGateSize(size_t numIns)819 size_t Gate::GetGateSize(size_t numIns)
820 {
821     return Gate::GetOutListSize(numIns) + Gate::GetInListSize(numIns) + sizeof(Gate);
822 }
823 
GetGateSize() const824 size_t Gate::GetGateSize() const
825 {
826     return Gate::GetGateSize(GetNumIns());
827 }
828 
NewIn(size_t idx,Gate * in)829 void Gate::NewIn(size_t idx, Gate *in)
830 {
831     GetIn(idx)->SetGate(in);
832     auto curOut = GetOut(idx);
833     if (in->IsFirstOutNull()) {
834         curOut->SetNextOutNull();
835     } else {
836         curOut->SetNextOut(in->GetFirstOut());
837         in->GetFirstOut()->SetPrevOut(curOut);
838     }
839     curOut->SetPrevOutNull();
840     in->SetFirstOut(curOut);
841 }
842 
ModifyIn(size_t idx,Gate * in)843 void Gate::ModifyIn(size_t idx, Gate *in)
844 {
845     DeleteIn(idx);
846     NewIn(idx, in);
847 }
848 
DeleteIn(size_t idx)849 void Gate::DeleteIn(size_t idx)
850 {
851     if (!GetOut(idx)->IsNextOutNull() && !GetOut(idx)->IsPrevOutNull()) {
852         GetOut(idx)->GetPrevOut()->SetNextOut(GetOut(idx)->GetNextOut());
853         GetOut(idx)->GetNextOut()->SetPrevOut(GetOut(idx)->GetPrevOut());
854     } else if (GetOut(idx)->IsNextOutNull() && !GetOut(idx)->IsPrevOutNull()) {
855         GetOut(idx)->GetPrevOut()->SetNextOutNull();
856     } else if (!GetOut(idx)->IsNextOutNull()) {  // then GetOut(idx)->IsPrevOutNull() is true
857         GetIn(idx)->GetGate()->SetFirstOut(GetOut(idx)->GetNextOut());
858         GetOut(idx)->GetNextOut()->SetPrevOutNull();
859     } else {  // only this out now
860         GetIn(idx)->GetGate()->SetFirstOutNull();
861     }
862     GetIn(idx)->SetGateNull();
863 }
864 
DeleteGate()865 void Gate::DeleteGate()
866 {
867     auto numIns = GetNumIns();
868     for (size_t idx = 0; idx < numIns; idx++) {
869         DeleteIn(idx);
870     }
871     SetOpCode(OpCode(OpCode::NOP));
872 }
873 
GetOut(size_t idx)874 Out *Gate::GetOut(size_t idx)
875 {
876     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
877     return &reinterpret_cast<Out *>(this)[-1 - idx];
878 }
879 
GetFirstOut()880 Out *Gate::GetFirstOut()
881 {
882     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
883     return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + firstOut_);
884 }
885 
GetFirstOutConst() const886 const Out *Gate::GetFirstOutConst() const
887 {
888     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
889     return reinterpret_cast<const Out *>((reinterpret_cast<const uint8_t *>(this)) + firstOut_);
890 }
891 
SetFirstOutNull()892 void Gate::SetFirstOutNull()
893 {
894     firstOut_ = 0;
895 }
896 
IsFirstOutNull() const897 bool Gate::IsFirstOutNull() const
898 {
899     return firstOut_ == 0;
900 }
901 
SetFirstOut(const Out * firstOut)902 void Gate::SetFirstOut(const Out *firstOut)
903 {
904     firstOut_ =
905         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
906         static_cast<GateRef>(reinterpret_cast<const uint8_t *>(firstOut) - reinterpret_cast<const uint8_t *>(this));
907 }
908 
GetIn(size_t idx)909 In *Gate::GetIn(size_t idx)
910 {
911 #ifndef NDEBUG
912     if (idx >= GetNumIns()) {
913         std::cerr << std::dec << "Gate In access out-of-bound! (idx=" << idx << ")" << std::endl;
914         Print();
915         ASSERT(false);
916     }
917 #endif
918     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
919     return &reinterpret_cast<In *>(this + 1)[idx];
920 }
921 
GetInConst(size_t idx) const922 const In *Gate::GetInConst(size_t idx) const
923 {
924 #ifndef NDEBUG
925     if (idx >= GetNumIns()) {
926         std::cerr << std::dec << "Gate In access out-of-bound! (idx=" << idx << ")" << std::endl;
927         Print();
928         ASSERT(false);
929     }
930 #endif
931     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
932     return &reinterpret_cast<const In *>(this + 1)[idx];
933 }
934 
GetInGate(size_t idx)935 Gate *Gate::GetInGate(size_t idx)
936 {
937     return GetIn(idx)->GetGate();
938 }
939 
GetInGateConst(size_t idx) const940 const Gate *Gate::GetInGateConst(size_t idx) const
941 {
942     return GetInConst(idx)->GetGateConst();
943 }
944 
IsInGateNull(size_t idx) const945 bool Gate::IsInGateNull(size_t idx) const
946 {
947     return GetInConst(idx)->IsGateNull();
948 }
949 
GetId() const950 GateId Gate::GetId() const
951 {
952     return id_;
953 }
954 
GetOpCode() const955 OpCode Gate::GetOpCode() const
956 {
957     return opcode_;
958 }
959 
GetMachineType() const960 MachineType Gate::GetMachineType() const
961 {
962     return bitValue_;
963 }
964 
SetMachineType(MachineType MachineType)965 void Gate::SetMachineType(MachineType MachineType)
966 {
967     bitValue_ = MachineType;
968 }
969 
SetOpCode(OpCode opcode)970 void Gate::SetOpCode(OpCode opcode)
971 {
972     opcode_ = opcode;
973 }
974 
GetGateType() const975 GateType Gate::GetGateType() const
976 {
977     return type_;
978 }
979 
SetGateType(GateType type)980 void Gate::SetGateType(GateType type)
981 {
982     type_ = type;
983 }
984 
GetNumIns() const985 size_t Gate::GetNumIns() const
986 {
987     return GetOpCodeNumIns(GetOpCode(), GetBitField());
988 }
989 
GetNumInsArray() const990 std::array<size_t, 4> Gate::GetNumInsArray() const // 4 : 4 means that there are 4 args.
991 {
992     return GetOpCode().GetOpCodeNumInsArray(GetBitField());
993 }
994 
GetBitField() const995 BitField Gate::GetBitField() const
996 {
997     return bitfield_;
998 }
999 
SetBitField(BitField bitfield)1000 void Gate::SetBitField(BitField bitfield)
1001 {
1002     bitfield_ = bitfield;
1003 }
1004 
MachineTypeStr(MachineType machineType) const1005 std::string Gate::MachineTypeStr(MachineType machineType) const
1006 {
1007     const std::map<MachineType, const char *> strMap = {
1008         {NOVALUE, "NOVALUE"},
1009         {ANYVALUE, "ANYVALUE"},
1010         {ARCH, "ARCH"},
1011         {FLEX, "FLEX"},
1012         {I1, "I1"},
1013         {I8, "I8"},
1014         {I16, "I16"},
1015         {I32, "I32"},
1016         {I64, "I64"},
1017         {F32, "F32"},
1018         {F64, "F64"},
1019     };
1020     if (strMap.count(machineType) > 0) {
1021         return strMap.at(machineType);
1022     }
1023     return "MachineType-" + std::to_string(machineType);
1024 }
1025 
GateTypeStr(GateType gateType) const1026 std::string Gate::GateTypeStr(GateType gateType) const
1027 {
1028     const std::map<GateType, const char *> strMap = {
1029         {C_VALUE, "C_VALUE"},
1030         {TAGGED_VALUE, "TAGGED_VALUE"},
1031         {TAGGED_POINTER, "TAGGED_POINTER"},
1032         {TAGGED_NO_POINTER, "TAGGED_NO_POINTER"},
1033         {EMPTY, "EMPTY"},
1034         {JS_ANY, "JS_ANY"},
1035     };
1036 
1037     if (strMap.count(gateType) > 0) {
1038         return strMap.at(gateType);
1039     }
1040     return "GateType-" + std::to_string(gateType);
1041 }
1042 
Print(std::string bytecode,bool inListPreview,size_t highlightIdx) const1043 void Gate::Print(std::string bytecode, bool inListPreview, size_t highlightIdx) const
1044 {
1045     if (GetOpCode() != OpCode::NOP) {
1046         std::cerr << std::dec << "("
1047                   << "id=" << id_ << ", "
1048                   << "op=" << GetOpCode().Str() << ", "
1049                   << ((bytecode.compare("") == 0) ? "" : "bytecode=") << bytecode
1050                   << ((bytecode.compare("") == 0) ? "" : ", ")
1051                   << "machineType=" << MachineTypeStr(GetMachineType()) << ", "
1052                   << "bitfield=" << std::to_string(bitfield_) << ", "
1053                   << "type=" << GateTypeStr(type_) << ", "
1054                   << "stamp=" << static_cast<uint32_t>(stamp_) << ", "
1055                   << "mark=" << static_cast<uint32_t>(mark_) << ", ";
1056         std::cerr << "in="
1057                   << "[";
1058         auto numInsArray = GetOpCode().GetOpCodeNumInsArray(GetBitField());
1059         size_t idx = 0;
1060         auto stateSize = numInsArray[0];
1061         auto dependSize = numInsArray[1];
1062         auto valueSize = numInsArray[2]; // 2 : 2 means the third element.
1063         auto rootSize = numInsArray[3]; // 3 : 3 means the four element.
1064         idx = PrintInGate(stateSize, idx, 0, inListPreview, highlightIdx);
1065         idx = PrintInGate(stateSize + dependSize, idx, stateSize, inListPreview, highlightIdx);
1066         idx = PrintInGate(stateSize + dependSize + valueSize, idx, stateSize + dependSize, inListPreview, highlightIdx);
1067         PrintInGate(stateSize + dependSize + valueSize + rootSize, idx, stateSize + dependSize + valueSize,
1068                     inListPreview, highlightIdx, true);
1069 
1070         std::cerr << "]"
1071                   << ", ";
1072         std::cerr << "out="
1073                   << "[";
1074         if (!IsFirstOutNull()) {
1075             const Out *curOut = GetFirstOutConst();
1076             std::cerr << std::dec << ""
1077                       << std::to_string(curOut->GetGateConst()->GetId()) +
1078                     (inListPreview ? std::string(":" + curOut->GetGateConst()->GetOpCode().Str()) : std::string(""));
1079             while (!curOut->IsNextOutNull()) {
1080                 curOut = curOut->GetNextOutConst();
1081                 std::cerr << std::dec << " "
1082                           << std::to_string(curOut->GetGateConst()->GetId()) +
1083                         (inListPreview ? std::string(":" + curOut->GetGateConst()->GetOpCode().Str())
1084                                        : std::string(""));
1085             }
1086         }
1087         std::cerr << "]"
1088                   << ")" << std::endl;
1089     }
1090 }
1091 
PrintInGate(size_t numIns,size_t idx,size_t size,bool inListPreview,size_t highlightIdx,bool isEnd) const1092 size_t Gate::PrintInGate(size_t numIns, size_t idx, size_t size, bool inListPreview, size_t highlightIdx,
1093                          bool isEnd) const
1094 {
1095     std::cerr << "[";
1096     for (; idx < numIns; idx++) {
1097         std::cerr << std::dec << ((idx == size) ? "" : " ") << ((idx == highlightIdx) ? "\033[4;31m" : "")
1098                   << ((IsInGateNull(idx)
1099                        ? "N"
1100                        : (std::to_string(GetInGateConst(idx)->GetId()) +
1101                           (inListPreview ? std::string(":" + GetInGateConst(idx)->GetOpCode().Str())
1102                                          : std::string("")))))
1103                   << ((idx == highlightIdx) ? "\033[0m" : "");
1104     }
1105     std::cerr << "]"
1106               << ((isEnd) ? "" : ", ");
1107     return idx;
1108 }
1109 
PrintByteCode(std::string bytecode) const1110 void Gate::PrintByteCode(std::string bytecode) const
1111 {
1112     Print(bytecode);
1113 }
1114 
GetMark(TimeStamp stamp) const1115 MarkCode Gate::GetMark(TimeStamp stamp) const
1116 {
1117     return (stamp_ == stamp) ? mark_ : MarkCode::NO_MARK;
1118 }
1119 
SetMark(MarkCode mark,TimeStamp stamp)1120 void Gate::SetMark(MarkCode mark, TimeStamp stamp)
1121 {
1122     stamp_ = stamp;
1123     mark_ = mark;
1124 }
1125 
IsRoot() const1126 bool OpCode::IsRoot() const
1127 {
1128     return (GetProperties().states == OpCode::CIRCUIT_ROOT) || (op_ == OpCode::CIRCUIT_ROOT);
1129 }
1130 
IsProlog() const1131 bool OpCode::IsProlog() const
1132 {
1133     return (GetProperties().states == OpCode::ARG_LIST);
1134 }
1135 
IsFixed() const1136 bool OpCode::IsFixed() const
1137 {
1138     return (GetOpCodeNumInsArray(1)[0] > 0) &&
1139         ((GetMachineType() != NOVALUE) ||
1140             ((GetOpCodeNumInsArray(1)[1] > 0) && (GetOpCodeNumInsArray(1)[2] == 0) &&
1141              (GetOpCodeNumInsArray(1)[3] == 0)));
1142 }
1143 
IsSchedulable() const1144 bool OpCode::IsSchedulable() const
1145 {
1146     return (op_ != OpCode::NOP) && (!IsProlog()) && (!IsRoot()) && (!IsFixed()) &&
1147         (GetOpCodeNumInsArray(1)[0] == 0);
1148 }
1149 
IsState() const1150 bool OpCode::IsState() const
1151 {
1152     return (op_ != OpCode::NOP) && (!IsProlog()) && (!IsRoot()) && (!IsFixed()) &&
1153         (GetOpCodeNumInsArray(1)[0] > 0);
1154 }
1155 
IsGeneralState() const1156 bool OpCode::IsGeneralState() const
1157 {
1158     return ((op_ == OpCode::IF_TRUE) || (op_ == OpCode::IF_FALSE) || (op_ == OpCode::IF_SUCCESS) ||
1159             (op_ == OpCode::IF_EXCEPTION) || (op_ == OpCode::SWITCH_CASE) ||
1160             (op_ == OpCode::DEFAULT_CASE) || (op_ == OpCode::MERGE) || (op_ == OpCode::LOOP_BEGIN) ||
1161             (op_ == OpCode::ORDINARY_BLOCK) || (op_ == OpCode::STATE_ENTRY));
1162 }
1163 
IsTerminalState() const1164 bool OpCode::IsTerminalState() const
1165 {
1166     return ((op_ == OpCode::RETURN) || (op_ == OpCode::THROW) || (op_ == OpCode::RETURN_VOID));
1167 }
1168 
IsCFGMerge() const1169 bool OpCode::IsCFGMerge() const
1170 {
1171     return (op_ == OpCode::MERGE) || (op_ == OpCode::LOOP_BEGIN);
1172 }
1173 
IsControlCase() const1174 bool OpCode::IsControlCase() const
1175 {
1176     return (op_ == OpCode::IF_BRANCH) || (op_ == OpCode::SWITCH_BRANCH) || (op_ == OpCode::IF_TRUE) ||
1177            (op_ == OpCode::IF_FALSE) || (op_ == OpCode::IF_SUCCESS) || (op_ == OpCode::IF_EXCEPTION) ||
1178            (op_ == OpCode::SWITCH_CASE) || (op_ == OpCode::DEFAULT_CASE);
1179 }
1180 
IsLoopHead() const1181 bool OpCode::IsLoopHead() const
1182 {
1183     return (op_ == OpCode::LOOP_BEGIN);
1184 }
1185 
IsNop() const1186 bool OpCode::IsNop() const
1187 {
1188     return (op_ == OpCode::NOP);
1189 }
1190 }  // namespace panda::ecmascript::kungfu
1191