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