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