1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/compiler/gate.h"
17 #include <iostream>
18 #include <sstream>
19
20 namespace panda::ecmascript::kungfu {
CheckNullInput() const21 void Gate::CheckNullInput() const
22 {
23 const auto numIns = GetNumIns();
24 for (size_t idx = 0; idx < numIns; idx++) {
25 if (IsInGateNull(idx)) {
26 CheckFailed("In list contains null", idx);
27 }
28 }
29 }
30
CheckFailed(std::string errorString,size_t highlightIdx) const31 void Gate::CheckFailed(std::string errorString, size_t highlightIdx) const
32 {
33 LOG_COMPILER(ERROR) << "[Verifier][Error] Gate level input list schema verify failed";
34 Print("", true, highlightIdx);
35 LOG_COMPILER(FATAL) << "Note: " << errorString;
36 }
37
CheckInputOpcode(size_t idx,OpCode expected) const38 void Gate::CheckInputOpcode(size_t idx, OpCode expected) const
39 {
40 OpCode actual = GetInGateConst(idx)->GetOpCode();
41 if (actual != expected) {
42 CheckFailed("State input does not match (expected:" + GateMetaData::Str(expected) +
43 " actual:" + GateMetaData::Str(actual) + ")", idx);
44 }
45 }
46
CheckInputMachineType(size_t idx,MachineType expected,bool isArch64) const47 void Gate::CheckInputMachineType(size_t idx, MachineType expected, bool isArch64) const
48 {
49 MachineType actual = GetInGateConst(idx)->GetMachineType();
50 if (expected == MachineType::FLEX) {
51 expected = GetMachineType();
52 }
53 if (expected == MachineType::ARCH) {
54 expected = isArch64 ? MachineType::I64 : MachineType::I32;
55 }
56 if (actual == MachineType::ARCH) {
57 actual = isArch64 ? MachineType::I64 : MachineType::I32;
58 }
59 if (actual != expected) {
60 CheckFailed("Value input does not match (expected:" +
61 MachineTypeToStr(expected) + " actual:" + MachineTypeToStr(actual) + ")", idx);
62 }
63 }
64
CheckNotInputMachineType(size_t idx,MachineType notExpected) const65 void Gate::CheckNotInputMachineType(size_t idx, MachineType notExpected) const
66 {
67 MachineType actual = GetInGateConst(idx)->GetMachineType();
68 if (actual == notExpected) {
69 CheckFailed("Value input does not match (notExpected:" +
70 MachineTypeToStr(notExpected) + " actual:" + MachineTypeToStr(actual) + ")", idx);
71 }
72 }
73
CheckGeneralState(size_t idx) const74 void Gate::CheckGeneralState(size_t idx) const
75 {
76 auto gatePtr = GetInGateConst(idx);
77 OpCode actual = gatePtr->GetOpCode();
78 if (!gatePtr->meta_->IsGeneralState()) {
79 CheckFailed("State input does not match (expected:<General State> actual:" +
80 GateMetaData::Str(actual) + ")", idx);
81 }
82 }
83
CheckState(size_t idx) const84 void Gate::CheckState(size_t idx) const
85 {
86 auto gatePtr = GetInGateConst(idx);
87 OpCode actual = gatePtr->GetOpCode();
88 if ((actual != OpCode::STATE_ENTRY) && (!gatePtr->meta_->IsState())) {
89 CheckFailed("State input does not match (expected:<State> actual:" +
90 GateMetaData::Str(actual) + ")", idx);
91 }
92 }
93
CheckStateInput() const94 void Gate::CheckStateInput() const
95 {
96 size_t stateStart = 0;
97 size_t stateEnd = GetStateCount();
98 for (size_t idx = stateStart; idx < stateEnd; idx++) {
99 bool needCheck = true;
100 switch (GetOpCode()) {
101 case OpCode::IF_TRUE:
102 case OpCode::IF_FALSE:
103 ASSERT(idx == stateStart);
104 CheckInputOpcode(idx, OpCode::IF_BRANCH);
105 needCheck = false;
106 break;
107 case OpCode::SWITCH_CASE:
108 case OpCode::DEFAULT_CASE:
109 ASSERT(idx == stateStart);
110 CheckInputOpcode(idx, OpCode::SWITCH_BRANCH);
111 needCheck = false;
112 break;
113 default:
114 break;
115 }
116 if (needCheck) {
117 CheckState(idx);
118 }
119 }
120 }
121
CheckValueInput(bool isArch64) const122 void Gate::CheckValueInput(bool isArch64) const
123 {
124 size_t valueStart = GetInValueStarts();
125 size_t valueEnd = valueStart + GetInValueCount();
126 for (size_t idx = valueStart; idx < valueEnd; idx++) {
127 switch (GetOpCode()) {
128 case OpCode::IF_BRANCH:
129 ASSERT(idx == valueStart);
130 CheckInputMachineType(idx, MachineType::I1, isArch64);
131 break;
132 case OpCode::VALUE_SELECTOR:
133 case OpCode::ADD:
134 case OpCode::SUB:
135 case OpCode::MUL:
136 case OpCode::EXP:
137 case OpCode::SDIV:
138 case OpCode::SMOD:
139 case OpCode::UDIV:
140 case OpCode::UMOD:
141 case OpCode::FDIV:
142 case OpCode::FMOD:
143 case OpCode::AND:
144 case OpCode::XOR:
145 case OpCode::OR:
146 case OpCode::LSL:
147 case OpCode::LSR:
148 case OpCode::ASR:
149 CheckInputMachineType(idx, MachineType::FLEX, isArch64);
150 break;
151 case OpCode::REV:
152 ASSERT(idx == valueStart);
153 CheckInputMachineType(idx, MachineType::I1, isArch64);
154 break;
155 case OpCode::LOAD:
156 ASSERT(idx == valueStart);
157 CheckInputMachineType(idx, MachineType::ARCH, isArch64);
158 break;
159 case OpCode::STORE:
160 if (idx == valueStart + 1) { // 1: idx 1
161 CheckInputMachineType(idx, MachineType::ARCH, isArch64);
162 }
163 break;
164 case OpCode::HEAP_ALLOC:
165 case OpCode::TAGGED_TO_INT64:
166 case OpCode::INT64_TO_TAGGED:
167 ASSERT(idx == valueStart);
168 CheckInputMachineType(valueStart, MachineType::I64, isArch64);
169 break;
170 case OpCode::OBJECT_TYPE_CHECK:
171 case OpCode::LOAD_ELEMENT:
172 case OpCode::STORE_ELEMENT:
173 if (idx == valueStart) { // 1: idx 1
174 CheckInputMachineType(idx, MachineType::I64, isArch64);
175 }
176 break;
177 case OpCode::FCMP:
178 CheckInputMachineType(idx, MachineType::F64, isArch64);
179 break;
180 case OpCode::ICMP:
181 CheckNotInputMachineType(idx, MachineType::F64);
182 break;
183 default:
184 break;
185 }
186 }
187 }
188
CheckDependInput() const189 void Gate::CheckDependInput() const
190 {
191 size_t dependStart = GetStateCount();
192 size_t dependEnd = dependStart + GetDependCount();
193 for (size_t idx = dependStart; idx < dependEnd; idx++) {
194 if (GetInGateConst(idx)->GetDependCount() == 0 &&
195 GetInGateConst(idx)->GetOpCode() != OpCode::DEPEND_ENTRY) {
196 LOG_COMPILER(ERROR) << "depend in of " << GetId() << GateMetaData::Str(GetOpCode()) << "is "
197 << GetInGateConst(idx)->GetId() << GateMetaData::Str(GetInGateConst(idx)->GetOpCode());
198 CheckFailed("Depend input is side-effect free", idx);
199 }
200 }
201 }
202
CheckRootInput() const203 void Gate::CheckRootInput() const
204 {
205 size_t rootStart = GetInValueStarts() + GetInValueCount();
206 if (meta_->HasRoot()) {
207 switch (GetOpCode()) {
208 case OpCode::STATE_ENTRY:
209 case OpCode::DEPEND_ENTRY:
210 case OpCode::RETURN_LIST:
211 case OpCode::ARG_LIST:
212 CheckInputOpcode(rootStart, OpCode::CIRCUIT_ROOT);
213 break;
214 case OpCode::ARG:
215 CheckInputOpcode(rootStart, OpCode::ARG_LIST);
216 break;
217 case OpCode::RETURN:
218 case OpCode::RETURN_VOID:
219 CheckInputOpcode(rootStart, OpCode::RETURN_LIST);
220 break;
221 default:
222 break;
223 }
224 }
225 }
226
CheckFrameStateInput() const227 void Gate::CheckFrameStateInput() const
228 {
229 size_t frameStateStart = GetInFrameStateStarts();
230 if (meta_->HasFrameState()) {
231 CheckInputOpcode(frameStateStart, OpCode::FRAME_STATE);
232 }
233 }
234
CheckStateOutput() const235 void Gate::CheckStateOutput() const
236 {
237 if (GetMetaData()->IsState()) {
238 size_t cnt = 0;
239 const Gate *curGate = this;
240 if (!curGate->IsFirstOutNull()) {
241 const Out *curOut = curGate->GetFirstOutConst();
242 auto meta = curOut->GetGateConst()->GetMetaData();
243 if (curOut->IsStateEdge() && meta->IsState()) {
244 cnt++;
245 }
246 while (!curOut->IsNextOutNull()) {
247 curOut = curOut->GetNextOutConst();
248 meta = curOut->GetGateConst()->GetMetaData();
249 if (curOut->IsStateEdge() && meta->IsState()) {
250 cnt++;
251 }
252 }
253 }
254 size_t expected = 0;
255 bool needCheck = true;
256 if (GetMetaData()->IsTerminalState()) {
257 expected = 0;
258 } else if (GetOpCode() == OpCode::IF_BRANCH || GetOpCode() == OpCode::JS_BYTECODE) {
259 expected = 2; // 2: expected number of state out branches
260 } else if (GetOpCode() == OpCode::SWITCH_BRANCH) {
261 needCheck = false;
262 } else {
263 expected = 1;
264 }
265 if (needCheck && cnt != expected) {
266 curGate->Print();
267 CheckFailed("Number of state out branches is not valid (expected:" + std::to_string(expected) +
268 " actual:" + std::to_string(cnt) + ")", -1);
269 }
270 }
271 }
272
CheckBranchOutput() const273 void Gate::CheckBranchOutput() const
274 {
275 std::map<std::pair<OpCode, BitField>, size_t> setOfOps;
276 if (GetOpCode() == OpCode::IF_BRANCH) {
277 size_t cnt = 0;
278 const Gate *curGate = this;
279 if (!curGate->IsFirstOutNull()) {
280 const Out *curOut = curGate->GetFirstOutConst();
281 if (curOut->GetGateConst()->GetMetaData()->IsState() && curOut->IsStateEdge()) {
282 ASSERT(!curOut->GetGateConst()->GetMetaData()->IsFixed());
283 setOfOps[{curOut->GetGateConst()->GetOpCode(), curOut->GetGateConst()->GetStateCount()}]++;
284 cnt++;
285 }
286 while (!curOut->IsNextOutNull()) {
287 curOut = curOut->GetNextOutConst();
288 if (curOut->GetGateConst()->GetMetaData()->IsState() && curOut->IsStateEdge()) {
289 ASSERT(!curOut->GetGateConst()->GetMetaData()->IsFixed());
290 setOfOps[{curOut->GetGateConst()->GetOpCode(), curOut->GetGateConst()->GetStateCount()}]++;
291 cnt++;
292 }
293 }
294 }
295 if (setOfOps.size() != cnt) {
296 CheckFailed("Duplicate state out branches", -1);
297 }
298 }
299 }
300
CheckNOP() const301 void Gate::CheckNOP() const
302 {
303 if (GetOpCode() == OpCode::NOP || GetOpCode() == OpCode::DEAD) {
304 if (!IsFirstOutNull()) {
305 CheckFailed("NOP gate used by other gates", -1);
306 }
307 }
308 }
309
CheckSelector() const310 void Gate::CheckSelector() const
311 {
312 if (GetOpCode() == OpCode::VALUE_SELECTOR || GetOpCode() == OpCode::DEPEND_SELECTOR) {
313 auto stateOp = GetInGateConst(0)->GetOpCode();
314 if (stateOp == OpCode::MERGE || stateOp == OpCode::LOOP_BEGIN) {
315 if (GetInGateConst(0)->GetNumIns() != GetNumIns() - 1) {
316 if (GetOpCode() == OpCode::DEPEND_SELECTOR) {
317 CheckFailed("Number of depend flows does not match control flows (expected:" +
318 std::to_string(GetInGateConst(0)->GetNumIns()) +
319 " actual:" + std::to_string(GetNumIns() - 1) + ")",
320 -1);
321 } else {
322 CheckFailed("Number of data flows does not match control flows (expected:" +
323 std::to_string(GetInGateConst(0)->GetNumIns()) +
324 " actual:" + std::to_string(GetNumIns() - 1) + ")",
325 -1);
326 }
327 }
328 } else {
329 CheckFailed(
330 "State input does not match (expected:[MERGE|LOOP_BEGIN] actual:" +
331 GateMetaData::Str(stateOp) + ")", 0);
332 }
333 }
334 }
335
CheckRelay() const336 void Gate::CheckRelay() const
337 {
338 if (GetOpCode() == OpCode::DEPEND_RELAY) {
339 auto stateOp = GetInGateConst(0)->GetOpCode();
340 switch (stateOp) {
341 case OpCode::IF_TRUE:
342 case OpCode::IF_FALSE:
343 case OpCode::SWITCH_CASE:
344 case OpCode::DEFAULT_CASE:
345 case OpCode::IF_SUCCESS:
346 case OpCode::IF_EXCEPTION:
347 case OpCode::ORDINARY_BLOCK:
348 case OpCode::DEOPT_CHECK:
349 break;
350 default:
351 CheckFailed("State input does not match ("
352 "expected:[IF_TRUE|IF_FALSE|SWITCH_CASE|DEFAULT_CASE|"
353 "IF_SUCCESS|IF_EXCEPTION|ORDINARY_BLOCK|DEOPT_CHECK] actual:" +
354 GateMetaData::Str(stateOp) + ")", 0);
355 break;
356 }
357 }
358 }
359
Verify(bool isArch64) const360 void Gate::Verify(bool isArch64) const
361 {
362 CheckNullInput();
363 CheckStateInput();
364 CheckValueInput(isArch64);
365 CheckDependInput();
366 CheckFrameStateInput();
367 CheckRootInput();
368 CheckStateOutput();
369 CheckBranchOutput();
370 CheckNOP();
371 CheckSelector();
372 CheckRelay();
373 }
374
SetNextOut(const Out * ptr)375 void Out::SetNextOut(const Out *ptr)
376 {
377 nextOut_ =
378 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
379 static_cast<GateRef>((reinterpret_cast<const uint8_t *>(ptr)) - (reinterpret_cast<const uint8_t *>(this)));
380 }
381
GetNextOut()382 Out *Out::GetNextOut()
383 {
384 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
385 return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + nextOut_);
386 }
387
GetNextOutConst() const388 const Out *Out::GetNextOutConst() const
389 {
390 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
391 return reinterpret_cast<const Out *>((reinterpret_cast<const uint8_t *>(this)) + nextOut_);
392 }
393
SetPrevOut(const Out * ptr)394 void Out::SetPrevOut(const Out *ptr)
395 {
396 prevOut_ =
397 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
398 static_cast<GateRef>((reinterpret_cast<const uint8_t *>(ptr)) - (reinterpret_cast<const uint8_t *>(this)));
399 }
400
GetPrevOut()401 Out *Out::GetPrevOut()
402 {
403 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
404 return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + prevOut_);
405 }
406
GetPrevOutConst() const407 const Out *Out::GetPrevOutConst() const
408 {
409 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
410 return reinterpret_cast<const Out *>((reinterpret_cast<const uint8_t *>(this)) + prevOut_);
411 }
412
SetIndex(OutIdx idx)413 void Out::SetIndex(OutIdx idx)
414 {
415 idx_ = idx;
416 }
417
GetIndex() const418 OutIdx Out::GetIndex() const
419 {
420 return idx_;
421 }
422
GetGate()423 Gate *Out::GetGate()
424 {
425 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
426 return reinterpret_cast<Gate *>(&this[idx_ + 1]);
427 }
428
GetGateConst() const429 const Gate *Out::GetGateConst() const
430 {
431 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
432 return reinterpret_cast<const Gate *>(&this[idx_ + 1]);
433 }
434
SetPrevOutNull()435 void Out::SetPrevOutNull()
436 {
437 prevOut_ = 0;
438 }
439
IsPrevOutNull() const440 bool Out::IsPrevOutNull() const
441 {
442 return prevOut_ == 0;
443 }
444
SetNextOutNull()445 void Out::SetNextOutNull()
446 {
447 nextOut_ = 0;
448 }
449
IsNextOutNull() const450 bool Out::IsNextOutNull() const
451 {
452 return nextOut_ == 0;
453 }
454
IsStateEdge() const455 bool Out::IsStateEdge() const
456 {
457 return idx_ < GetGateConst()->GetStateCount();
458 }
459
SetGate(const Gate * ptr)460 void In::SetGate(const Gate *ptr)
461 {
462 gatePtr_ =
463 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
464 static_cast<GateRef>((reinterpret_cast<const uint8_t *>(ptr)) - (reinterpret_cast<const uint8_t *>(this)));
465 }
466
GetGate()467 Gate *In::GetGate()
468 {
469 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
470 return reinterpret_cast<Gate *>((reinterpret_cast<uint8_t *>(this)) + gatePtr_);
471 }
472
GetGateConst() const473 const Gate *In::GetGateConst() const
474 {
475 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
476 return reinterpret_cast<const Gate *>((reinterpret_cast<const uint8_t *>(this)) + gatePtr_);
477 }
478
SetGateNull()479 void In::SetGateNull()
480 {
481 gatePtr_ = Gate::InvalidGateRef;
482 }
483
IsGateNull() const484 bool In::IsGateNull() const
485 {
486 return gatePtr_ == Gate::InvalidGateRef;
487 }
488
489 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
Gate(const GateMetaData * meta,GateId id,Gate * inList[],MachineType machineType,GateType type)490 Gate::Gate(const GateMetaData* meta, GateId id, Gate *inList[], MachineType machineType, GateType type)
491 : meta_(meta), id_(id), type_(type), machineType_(machineType)
492 {
493 auto numIns = GetNumIns();
494 if (numIns == 0) {
495 auto curOut = GetOut(0);
496 curOut->SetIndex(0);
497 return;
498 }
499 for (size_t idx = 0; idx < numIns; idx++) {
500 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
501 auto in = inList[idx];
502 if (in == nullptr) {
503 GetIn(idx)->SetGateNull();
504 } else {
505 NewIn(idx, in);
506 }
507 auto curOut = GetOut(idx);
508 curOut->SetIndex(idx);
509 }
510 }
511
NewIn(size_t idx,Gate * in)512 void Gate::NewIn(size_t idx, Gate *in)
513 {
514 GetIn(idx)->SetGate(in);
515 auto curOut = GetOut(idx);
516 if (in->IsFirstOutNull()) {
517 curOut->SetNextOutNull();
518 } else {
519 curOut->SetNextOut(in->GetFirstOut());
520 in->GetFirstOut()->SetPrevOut(curOut);
521 }
522 curOut->SetPrevOutNull();
523 in->SetFirstOut(curOut);
524 }
525
ModifyIn(size_t idx,Gate * in)526 void Gate::ModifyIn(size_t idx, Gate *in)
527 {
528 DeleteIn(idx);
529 NewIn(idx, in);
530 }
531
DeleteIn(size_t idx)532 void Gate::DeleteIn(size_t idx)
533 {
534 if (!GetOut(idx)->IsNextOutNull() && !GetOut(idx)->IsPrevOutNull()) {
535 GetOut(idx)->GetPrevOut()->SetNextOut(GetOut(idx)->GetNextOut());
536 GetOut(idx)->GetNextOut()->SetPrevOut(GetOut(idx)->GetPrevOut());
537 } else if (GetOut(idx)->IsNextOutNull() && !GetOut(idx)->IsPrevOutNull()) {
538 GetOut(idx)->GetPrevOut()->SetNextOutNull();
539 } else if (!GetOut(idx)->IsNextOutNull()) { // then GetOut(idx)->IsPrevOutNull() is true
540 GetIn(idx)->GetGate()->SetFirstOut(GetOut(idx)->GetNextOut());
541 GetOut(idx)->GetNextOut()->SetPrevOutNull();
542 } else { // only this out now
543 GetIn(idx)->GetGate()->SetFirstOutNull();
544 }
545 GetIn(idx)->SetGateNull();
546 }
547
DeleteGate()548 void Gate::DeleteGate()
549 {
550 auto numIns = GetNumIns();
551 for (size_t idx = 0; idx < numIns; idx++) {
552 DeleteIn(idx);
553 }
554 }
555
GetOut(size_t idx)556 Out *Gate::GetOut(size_t idx)
557 {
558 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
559 return &reinterpret_cast<Out *>(this)[-1 - idx];
560 }
561
GetOutConst(size_t idx) const562 const Out *Gate::GetOutConst(size_t idx) const
563 {
564 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
565 return &reinterpret_cast<const Out *>(this)[-1 - idx];
566 }
567
GetFirstOut()568 Out *Gate::GetFirstOut()
569 {
570 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
571 return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + firstOut_);
572 }
573
GetFirstOutConst() const574 const Out *Gate::GetFirstOutConst() const
575 {
576 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
577 return reinterpret_cast<const Out *>((reinterpret_cast<const uint8_t *>(this)) + firstOut_);
578 }
579
SetFirstOutNull()580 void Gate::SetFirstOutNull()
581 {
582 firstOut_ = 0;
583 }
584
IsFirstOutNull() const585 bool Gate::IsFirstOutNull() const
586 {
587 return firstOut_ == 0;
588 }
589
SetFirstOut(const Out * firstOut)590 void Gate::SetFirstOut(const Out *firstOut)
591 {
592 firstOut_ =
593 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
594 static_cast<GateRef>(reinterpret_cast<const uint8_t *>(firstOut) - reinterpret_cast<const uint8_t *>(this));
595 }
596
GetIn(size_t idx)597 In *Gate::GetIn(size_t idx)
598 {
599 #ifndef NDEBUG
600 if (idx >= GetNumIns()) {
601 LOG_COMPILER(INFO) << std::dec << "Gate In access out-of-bound! (idx=" << idx << ")";
602 Print();
603 ASSERT(false);
604 }
605 #endif
606 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
607 return &reinterpret_cast<In *>(this + 1)[idx];
608 }
609
GetInConst(size_t idx) const610 const In *Gate::GetInConst(size_t idx) const
611 {
612 #ifndef NDEBUG
613 if (idx >= GetNumIns()) {
614 LOG_COMPILER(INFO) << std::dec << "Gate In access out-of-bound! (idx=" << idx << ")";
615 Print();
616 ASSERT(false);
617 }
618 #endif
619 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
620 return &reinterpret_cast<const In *>(this + 1)[idx];
621 }
622
GetInGate(size_t idx)623 Gate *Gate::GetInGate(size_t idx)
624 {
625 return GetIn(idx)->GetGate();
626 }
627
GetInGateConst(size_t idx) const628 const Gate *Gate::GetInGateConst(size_t idx) const
629 {
630 return GetInConst(idx)->GetGateConst();
631 }
632
IsInGateNull(size_t idx) const633 bool Gate::IsInGateNull(size_t idx) const
634 {
635 return GetInConst(idx)->IsGateNull();
636 }
637
GetId() const638 GateId Gate::GetId() const
639 {
640 return id_;
641 }
642
GetOpCode() const643 OpCode Gate::GetOpCode() const
644 {
645 return meta_->GetOpCode();
646 }
647
GetNumIns() const648 size_t Gate::GetNumIns() const
649 {
650 return meta_->GetNumIns();
651 }
652
GetInValueStarts() const653 size_t Gate::GetInValueStarts() const
654 {
655 return meta_->GetInValueStarts();
656 }
657
GetInFrameStateStarts() const658 size_t Gate::GetInFrameStateStarts() const
659 {
660 return meta_->GetInFrameStateStarts();
661 }
662
GetStateCount() const663 size_t Gate::GetStateCount() const
664 {
665 return meta_->GetStateCount();
666 }
667
GetDependCount() const668 size_t Gate::GetDependCount() const
669 {
670 return meta_->GetDependCount();
671 }
672
GetInValueCount() const673 size_t Gate::GetInValueCount() const
674 {
675 return meta_->GetInValueCount();
676 }
677
GetInFrameStateCount() const678 size_t Gate::GetInFrameStateCount() const
679 {
680 return meta_->GetInFrameStateCount();
681 }
682
GetRootCount() const683 size_t Gate::GetRootCount() const
684 {
685 return meta_->GetRootCount();
686 }
687
MachineTypeStr(MachineType machineType) const688 std::string Gate::MachineTypeStr(MachineType machineType) const
689 {
690 const std::map<MachineType, const char *> strMap = {
691 {NOVALUE, "NOVALUE"},
692 {ANYVALUE, "ANYVALUE"},
693 {ARCH, "ARCH"},
694 {FLEX, "FLEX"},
695 {I1, "I1"},
696 {I8, "I8"},
697 {I16, "I16"},
698 {I32, "I32"},
699 {I64, "I64"},
700 {F32, "F32"},
701 {F64, "F64"},
702 };
703 if (strMap.count(machineType) > 0) {
704 return strMap.at(machineType);
705 }
706 return "MachineType-" + std::to_string(machineType);
707 }
708
GateTypeStr(GateType gateType) const709 std::string Gate::GateTypeStr(GateType gateType) const
710 {
711 static const std::map<GateType, const char *> strMap = {
712 {GateType::NJSValue(), "NJS_VALUE"},
713 {GateType::TaggedValue(), "TAGGED_VALUE"},
714 {GateType::TaggedPointer(), "TAGGED_POINTER"},
715 {GateType::TaggedNPointer(), "TAGGED_NPOINTER"},
716 {GateType::Empty(), "EMPTY"},
717 {GateType::AnyType(), "ANY_TYPE"},
718 };
719
720 std::string name = "";
721 if (strMap.count(gateType) > 0) {
722 name = strMap.at(gateType);
723 }
724 GlobalTSTypeRef r = gateType.GetGTRef();
725 uint32_t m = r.GetModuleId();
726 uint32_t l = r.GetLocalId();
727 return name + std::string("-GT(M=") + std::to_string(m) +
728 std::string(", L=") + std::to_string(l) + std::string(")");
729 }
730
Print(std::string additionOp,bool inListPreview,size_t highlightIdx) const731 void Gate::Print(std::string additionOp, bool inListPreview, size_t highlightIdx) const
732 {
733 auto opcode = GetOpCode();
734 if (opcode != OpCode::NOP && opcode != OpCode::DEAD) {
735 std::string log("{\"id\":" + std::to_string(id_) + ", \"op\":\"" + GateMetaData::Str(opcode) + "\", ");
736 std::string additionOpName = (opcode == OpCode::JS_BYTECODE) ? "bytecode" : "typedop";
737 log += ((additionOp.compare("") == 0) ? "" : "\"" + additionOpName + "\":\"") + additionOp;
738 log += ((additionOp.compare("") == 0) ? "" : "\", ");
739 log += "\"MType\":\"" + MachineTypeStr(GetMachineType()) + ", ";
740
741 std::ostringstream oss;
742 oss << std::hex << TryGetValue();
743 log += "bitfield=0x" + oss.str() + ", ";
744 log += "type=" + GateTypeStr(type_) + ", ";
745 log += "stamp=" + std::to_string(static_cast<uint32_t>(stamp_)) + ", ";
746 log += "mark=" + std::to_string(static_cast<uint32_t>(mark_)) + ", ";
747 log += "\",\"in\":[";
748
749 size_t idx = 0;
750 auto stateSize = GetStateCount();
751 auto dependSize = GetDependCount();
752 auto valueSize = GetInValueCount();
753 auto frameStateSize = GetInFrameStateCount();
754 auto rootSize = GetRootCount();
755 size_t start = 0;
756 size_t end = stateSize;
757 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
758 end += dependSize;
759 start += stateSize;
760 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
761 end += valueSize;
762 start += dependSize;
763 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
764 end += frameStateSize;
765 start += valueSize;
766 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
767 end += rootSize;
768 start += frameStateSize;
769 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log, true);
770
771 log += "], \"out\":[";
772
773 if (!IsFirstOutNull()) {
774 const Out *curOut = GetFirstOutConst();
775 opcode = curOut->GetGateConst()->GetOpCode();
776 log += std::to_string(curOut->GetGateConst()->GetId()) +
777 (inListPreview ? std::string(":" + GateMetaData::Str(opcode)) : std::string(""));
778
779 while (!curOut->IsNextOutNull()) {
780 curOut = curOut->GetNextOutConst();
781 log += ", " + std::to_string(curOut->GetGateConst()->GetId()) +
782 (inListPreview ? std::string(":" + GateMetaData::Str(opcode))
783 : std::string(""));
784 }
785 }
786 log += "]},";
787 LOG_COMPILER(INFO) << std::dec << log;
788 }
789 }
790
ShortPrint(std::string bytecode,bool inListPreview,size_t highlightIdx) const791 void Gate::ShortPrint(std::string bytecode, bool inListPreview, size_t highlightIdx) const
792 {
793 auto opcode = GetOpCode();
794 if (opcode != OpCode::NOP && opcode != OpCode::DEAD) {
795 std::string log("(\"id\"=" + std::to_string(id_) + ", \"op\"=\"" + GateMetaData::Str(opcode) + "\", ");
796 log += ((bytecode.compare("") == 0) ? "" : "bytecode=") + bytecode;
797 log += ((bytecode.compare("") == 0) ? "" : ", ");
798 log += "\"MType\"=\"" + MachineTypeStr(GetMachineType()) + ", ";
799 std::ostringstream oss;
800 oss << std::hex << TryGetValue();
801 log += "bitfield=0x" + oss.str() + ", ";
802 log += "type=" + GateTypeStr(type_) + ", ";
803 log += "\", in=[";
804
805 size_t idx = 0;
806 auto stateSize = GetStateCount();
807 auto dependSize = GetDependCount();
808 auto valueSize = GetInValueCount();
809 auto frameStateSize = GetInFrameStateCount();
810 auto rootSize = GetRootCount();
811 size_t start = 0;
812 size_t end = stateSize;
813 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
814 end += dependSize;
815 start += stateSize;
816 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
817 end += valueSize;
818 start += dependSize;
819 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
820 end += frameStateSize;
821 start += valueSize;
822 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
823 end += rootSize;
824 start += frameStateSize;
825 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log, true);
826
827 log += "], out=[";
828
829 if (!IsFirstOutNull()) {
830 const Out *curOut = GetFirstOutConst();
831 opcode = curOut->GetGateConst()->GetOpCode();
832 log += std::to_string(curOut->GetGateConst()->GetId()) +
833 (inListPreview ? std::string(":" + GateMetaData::Str(opcode)) : std::string(""));
834
835 while (!curOut->IsNextOutNull()) {
836 curOut = curOut->GetNextOutConst();
837 log += ", " + std::to_string(curOut->GetGateConst()->GetId()) +
838 (inListPreview ? std::string(":" + GateMetaData::Str(opcode))
839 : std::string(""));
840 }
841 }
842 log += "])";
843 LOG_COMPILER(INFO) << std::dec << log;
844 }
845 }
846
PrintInGate(size_t numIns,size_t idx,size_t size,bool inListPreview,size_t highlightIdx,std::string & log,bool isEnd) const847 size_t Gate::PrintInGate(size_t numIns, size_t idx, size_t size, bool inListPreview, size_t highlightIdx,
848 std::string &log, bool isEnd) const
849 {
850 log += "[";
851 for (; idx < numIns; idx++) {
852 log += ((idx == size) ? "" : ", ");
853 log += ((idx == highlightIdx) ? "\033[4;31m" : "");
854 log += ((IsInGateNull(idx)
855 ? "N"
856 : (std::to_string(GetInGateConst(idx)->GetId()) +
857 (inListPreview ? std::string(":" + GateMetaData::Str(GetInGateConst(idx)->GetOpCode()))
858 : std::string("")))));
859 log += ((idx == highlightIdx) ? "\033[0m" : "");
860 }
861 log += "]";
862 log += ((isEnd) ? "" : ", ");
863 return idx;
864 }
865
PrintWithBytecode() const866 void Gate::PrintWithBytecode() const
867 {
868 auto opcode = GetOpCode();
869 std::string bytecodeStr = "";
870 switch (opcode) {
871 case OpCode::JS_BYTECODE: {
872 bytecodeStr = GetJSBytecodeMetaData()->Str();
873 break;
874 }
875 case OpCode::TYPED_BINARY_OP: {
876 bytecodeStr = GetTypedBinaryMetaData()->Str();
877 break;
878 }
879 case OpCode::TYPED_UNARY_OP: {
880 auto typedOp = TypedUnaryAccessor(GetOneParameterMetaData()->GetValue()).GetTypedUnOp();
881 bytecodeStr = GateMetaData::Str(typedOp);
882 break;
883 }
884 case OpCode::TYPED_CONDITION_JUMP: {
885 auto typedOp = TypedJumpAccessor(GetOneParameterMetaData()->GetValue()).GetTypedJumpOp();
886 bytecodeStr = GateMetaData::Str(typedOp);
887 break;
888 }
889 case OpCode::LOAD_ELEMENT: {
890 auto typedOp = static_cast<TypedLoadOp>(GetOneParameterMetaData()->GetValue());
891 bytecodeStr = GateMetaData::Str(typedOp);
892 break;
893 }
894 case OpCode::STORE_ELEMENT: {
895 auto typedOp = static_cast<TypedStoreOp>(GetOneParameterMetaData()->GetValue());
896 bytecodeStr = GateMetaData::Str(typedOp);
897 break;
898 }
899 case OpCode::TYPED_CALLTARGETCHECK_OP: {
900 auto typedOp = GetTypedCallTargetCheckMetaData()->GetTypedCallTargetCheckOp();
901 bytecodeStr = GateMetaData::Str(typedOp);
902 break;
903 }
904 case OpCode::CONVERT:
905 case OpCode::CHECK_AND_CONVERT: {
906 ValuePairTypeAccessor accessor(GetOneParameterMetaData()->GetValue());
907 bytecodeStr = GateMetaData::Str(accessor.GetSrcType()) + "_TO_" +
908 GateMetaData::Str(accessor.GetDstType());
909 break;
910 }
911 default:
912 break;
913 }
914 PrintGateWithAdditionOp(bytecodeStr);
915 }
916
PrintGateWithAdditionOp(std::string additionOp) const917 void Gate::PrintGateWithAdditionOp(std::string additionOp) const
918 {
919 Print(additionOp);
920 }
921
GetMark(TimeStamp stamp) const922 MarkCode Gate::GetMark(TimeStamp stamp) const
923 {
924 return (stamp_ == stamp) ? mark_ : MarkCode::NO_MARK;
925 }
926
SetMark(MarkCode mark,TimeStamp stamp)927 void Gate::SetMark(MarkCode mark, TimeStamp stamp)
928 {
929 stamp_ = stamp;
930 mark_ = mark;
931 }
932 } // namespace panda::ecmascript::kungfu
933