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 20namespace panda::ecmascript::kungfu { 21void 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 31void 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 38void 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 47void 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 65void 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 74void 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 84void 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 94void 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 122void 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 199void 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 213void 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 237void Gate::CheckFrameStateInput() const 238{ 239 size_t frameStateStart = GetInFrameStateStarts(); 240 if (meta_->HasFrameState()) { 241 CheckInputOpcode(frameStateStart, OpCode::FRAME_STATE); 242 } 243} 244 245std::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 295void 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 335void 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 363void 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 372void 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 399void 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 423void 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 438void 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 445Out *Out::GetNextOut() 446{ 447 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 448 return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + nextOut_); 449} 450 451const 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 457void 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 464Out *Out::GetPrevOut() 465{ 466 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 467 return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + prevOut_); 468} 469 470const 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 476void Out::SetIndex(OutIdx idx) 477{ 478 idx_ = idx; 479} 480 481OutIdx Out::GetIndex() const 482{ 483 return idx_; 484} 485 486Gate *Out::GetGate() 487{ 488 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 489 return reinterpret_cast<Gate *>(&this[idx_ + 1]); 490} 491 492const Gate *Out::GetGateConst() const 493{ 494 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 495 return reinterpret_cast<const Gate *>(&this[idx_ + 1]); 496} 497 498void Out::SetPrevOutNull() 499{ 500 prevOut_ = 0; 501} 502 503bool Out::IsPrevOutNull() const 504{ 505 return prevOut_ == 0; 506} 507 508void Out::SetNextOutNull() 509{ 510 nextOut_ = 0; 511} 512 513bool Out::IsNextOutNull() const 514{ 515 return nextOut_ == 0; 516} 517 518bool Out::IsStateEdge() const 519{ 520 return idx_ < GetGateConst()->GetStateCount(); 521} 522 523void 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 530Gate *In::GetGate() 531{ 532 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 533 return reinterpret_cast<Gate *>((reinterpret_cast<uint8_t *>(this)) + gatePtr_); 534} 535 536const 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 542void In::SetGateNull() 543{ 544 gatePtr_ = Gate::InvalidGateRef; 545} 546 547bool In::IsGateNull() const 548{ 549 return gatePtr_ == Gate::InvalidGateRef; 550} 551 552// NOLINTNEXTLINE(modernize-avoid-c-arrays) 553Gate::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 575void 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 589void Gate::ModifyIn(size_t idx, Gate *in) 590{ 591 DeleteIn(idx); 592 NewIn(idx, in); 593} 594 595void 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 611void Gate::DeleteGate() 612{ 613 auto numIns = GetNumIns(); 614 for (size_t idx = 0; idx < numIns; idx++) { 615 DeleteIn(idx); 616 } 617} 618 619Out *Gate::GetOut(size_t idx) 620{ 621 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 622 return &reinterpret_cast<Out *>(this)[-1 - idx]; 623} 624 625const 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 631Out *Gate::GetFirstOut() 632{ 633 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 634 return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + firstOut_); 635} 636 637const 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 643void Gate::SetFirstOutNull() 644{ 645 firstOut_ = 0; 646} 647 648bool Gate::IsFirstOutNull() const 649{ 650 return firstOut_ == 0; 651} 652 653void 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 660In *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 673const 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 686Gate *Gate::GetInGate(size_t idx) 687{ 688 return GetIn(idx)->GetGate(); 689} 690 691const Gate *Gate::GetInGateConst(size_t idx) const 692{ 693 return GetInConst(idx)->GetGateConst(); 694} 695 696bool Gate::IsInGateNull(size_t idx) const 697{ 698 return GetInConst(idx)->IsGateNull(); 699} 700 701GateId Gate::GetId() const 702{ 703 return id_; 704} 705 706OpCode Gate::GetOpCode() const 707{ 708 return meta_->GetOpCode(); 709} 710 711size_t Gate::GetNumIns() const 712{ 713 return meta_->GetNumIns(); 714} 715 716size_t Gate::GetInValueStarts() const 717{ 718 return meta_->GetInValueStarts(); 719} 720 721size_t Gate::GetInFrameStateStarts() const 722{ 723 return meta_->GetInFrameStateStarts(); 724} 725 726size_t Gate::GetStateCount() const 727{ 728 return meta_->GetStateCount(); 729} 730 731size_t Gate::GetDependCount() const 732{ 733 return meta_->GetDependCount(); 734} 735 736size_t Gate::GetInValueCount() const 737{ 738 return meta_->GetInValueCount(); 739} 740 741size_t Gate::GetInFrameStateCount() const 742{ 743 return meta_->GetInFrameStateCount(); 744} 745 746size_t Gate::GetRootCount() const 747{ 748 return meta_->GetRootCount(); 749} 750 751std::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 772std::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 791void 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 796void Gate::DumpHeader(std::ostringstream &oss, const std::string& additionOp) const 797{ 798 auto opcode = GetOpCode(); 799 ASSERT(opcode != OpCode::NOP && opcode != OpCode::DEAD); 800 801 oss << "{\"id\":" << std::to_string(id_) << ", \"op\":\"" << GateMetaData::Str(opcode) << "\", "; 802 if (additionOp.compare("") != 0) { 803 auto additionOpName = (opcode == OpCode::JS_BYTECODE) ? "bytecode" : "typedop"; 804 oss << "\"" << additionOpName << "\":\"" << additionOp; 805 oss << "\", "; 806 } 807 oss << "\"MType\":\"" << MachineTypeStr(GetMachineType()) << ", "; 808 809 oss << "bitfield=0x" << std::hex << TryGetValue() << std::dec << ", "; 810 oss << "type=" << GateTypeStr(type_) << ", "; 811 oss << "stamp=" << std::to_string(static_cast<uint32_t>(stamp_)) << ", "; 812 oss << "mark=" << std::to_string(static_cast<uint32_t>(mark_)) << ", "; 813} 814 815void Gate::DumpInputs(std::ostringstream &oss, bool inListPreview, size_t highlightIdx) const 816{ 817 [[maybe_unused]] auto opcode = GetOpCode(); 818 ASSERT(opcode != OpCode::NOP && opcode != OpCode::DEAD); 819 820 size_t idx = 0; 821 auto stateSize = GetStateCount(); 822 auto dependSize = GetDependCount(); 823 auto valueSize = GetInValueCount(); 824 auto frameStateSize = GetInFrameStateCount(); 825 auto rootSize = GetRootCount(); 826 size_t start = 0; 827 size_t end = stateSize; 828 829 oss << "\",\"in\":["; 830 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, oss); 831 end += dependSize; 832 start += stateSize; 833 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, oss); 834 end += valueSize; 835 start += dependSize; 836 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, oss); 837 end += frameStateSize; 838 start += valueSize; 839 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, oss); 840 end += rootSize; 841 start += frameStateSize; 842 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, oss, true); 843 oss << "]"; 844} 845 846void Gate::DumpOutputs(std::ostringstream &oss, bool inListPreview) const 847{ 848 auto opcode = GetOpCode(); 849 ASSERT(opcode != OpCode::NOP && opcode != OpCode::DEAD); 850 851 oss << ", \"out\":["; 852 if (!IsFirstOutNull()) { 853 const Out *curOut = GetFirstOutConst(); 854 opcode = curOut->GetGateConst()->GetOpCode(); 855 oss << std::to_string(curOut->GetGateConst()->GetId()) + 856 (inListPreview ? std::string(":" + GateMetaData::Str(opcode)) : std::string("")); 857 858 while (!curOut->IsNextOutNull()) { 859 curOut = curOut->GetNextOutConst(); 860 oss << ", " + std::to_string(curOut->GetGateConst()->GetId()) + 861 (inListPreview ? std::string(":" + GateMetaData::Str(opcode)) 862 : std::string("")); 863 } 864 } 865 oss << "]"; 866} 867 868static void DumpComment(std::ostringstream &oss, std::string_view comment) 869{ 870 oss << ", \"comment\":\"" << comment << "\""; 871} 872 873std::string Gate::ToString(std::string additionOp, bool inListPreview, size_t highlightIdx, 874 std::string_view comment) const 875{ 876 auto opcode = GetOpCode(); 877 if (opcode == OpCode::NOP || opcode == OpCode::DEAD) { 878 return ""; 879 } 880 881 std::ostringstream oss; 882 oss << std::dec; 883 DumpHeader(oss, additionOp); 884 DumpInputs(oss, inListPreview, highlightIdx); 885 DumpOutputs(oss, inListPreview); 886 if (!comment.empty()) { 887 DumpComment(oss, comment); 888 } 889 oss << "},"; 890 return oss.str(); 891} 892 893void Gate::ShortPrint(std::string bytecode, bool inListPreview, size_t highlightIdx) const 894{ 895 auto opcode = GetOpCode(); 896 if (opcode != OpCode::NOP && opcode != OpCode::DEAD) { 897 std::ostringstream log; 898 log << "(\"id\"=" << std::to_string(id_) << ", \"op\"=\"" << GateMetaData::Str(opcode) << "\", "; 899 log << ((bytecode.compare("") == 0) ? "" : "bytecode=") << bytecode; 900 log << ((bytecode.compare("") == 0) ? "" : ", "); 901 log << "\"MType\"=\"" + MachineTypeStr(GetMachineType()) + ", "; 902 log << "bitfield=0x" << std::hex << TryGetValue() << std::dec << ", "; 903 log << "type=" + GateTypeStr(type_) + ", "; 904 log << "\", in=["; 905 906 size_t idx = 0; 907 auto stateSize = GetStateCount(); 908 auto dependSize = GetDependCount(); 909 auto valueSize = GetInValueCount(); 910 auto frameStateSize = GetInFrameStateCount(); 911 auto rootSize = GetRootCount(); 912 size_t start = 0; 913 size_t end = stateSize; 914 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log); 915 end += dependSize; 916 start += stateSize; 917 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log); 918 end += valueSize; 919 start += dependSize; 920 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log); 921 end += frameStateSize; 922 start += valueSize; 923 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log); 924 end += rootSize; 925 start += frameStateSize; 926 idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log, true); 927 928 log << "], out=["; 929 930 if (!IsFirstOutNull()) { 931 const Out *curOut = GetFirstOutConst(); 932 opcode = curOut->GetGateConst()->GetOpCode(); 933 log << std::to_string(curOut->GetGateConst()->GetId()) << 934 (inListPreview ? std::string(":" + GateMetaData::Str(opcode)) : std::string("")); 935 936 while (!curOut->IsNextOutNull()) { 937 curOut = curOut->GetNextOutConst(); 938 log << ", " << std::to_string(curOut->GetGateConst()->GetId()) << 939 (inListPreview ? std::string(":" + GateMetaData::Str(opcode)) 940 : std::string("")); 941 } 942 } 943 log << "])"; 944 LOG_COMPILER(INFO) << std::dec << log.str(); 945 } 946} 947 948size_t Gate::PrintInGate(size_t numIns, size_t idx, size_t size, bool inListPreview, size_t highlightIdx, 949 std::ostringstream &log, bool isEnd) const 950{ 951 log << "["; 952 for (; idx < numIns; idx++) { 953 log << ((idx == size) ? "" : ", "); 954 log << ((idx == highlightIdx) ? "\033[4;31m" : ""); 955 log << ((IsInGateNull(idx) 956 ? "N" 957 : (std::to_string(GetInGateConst(idx)->GetId()) + 958 (inListPreview ? std::string(":" + GateMetaData::Str(GetInGateConst(idx)->GetOpCode())) 959 : std::string(""))))); 960 log << ((idx == highlightIdx) ? "\033[0m" : ""); 961 } 962 log << "]"; 963 log << ((isEnd) ? "" : ", "); 964 return idx; 965} 966 967std::string Gate::GetBytecodeStr() const 968{ 969 switch (GetOpCode()) { 970 case OpCode::JS_BYTECODE: { 971 return GetJSBytecodeMetaData()->Str(); 972 } 973 case OpCode::TYPED_BINARY_OP: { 974 auto typedOp = TypedBinaryAccessor(GetOneParameterMetaData()->GetValue()).GetTypedBinOp(); 975 return GateMetaData::Str(typedOp); 976 } 977 case OpCode::TYPED_UNARY_OP: { 978 auto typedOp = TypedUnaryAccessor(GetOneParameterMetaData()->GetValue()).GetTypedUnOp(); 979 return GateMetaData::Str(typedOp); 980 } 981 case OpCode::TYPED_CONDITION_JUMP: { 982 auto typedOp = TypedJumpAccessor(GetOneParameterMetaData()->GetValue()).GetTypedJumpOp(); 983 return GateMetaData::Str(typedOp); 984 } 985 case OpCode::LOAD_ELEMENT: { 986 auto typedOp = static_cast<TypedLoadOp>(GetOneParameterMetaData()->GetValue()); 987 return GateMetaData::Str(typedOp); 988 } 989 case OpCode::STORE_ELEMENT: { 990 auto typedOp = static_cast<TypedStoreOp>(GetOneParameterMetaData()->GetValue()); 991 return GateMetaData::Str(typedOp); 992 } 993 case OpCode::TYPED_CALLTARGETCHECK_OP: { 994 TypedCallTargetCheckAccessor accessor(GetOneParameterMetaData()->GetValue()); 995 auto typedOp = accessor.GetCallTargetCheckOp(); 996 return GateMetaData::Str(typedOp); 997 } 998 case OpCode::CONVERT: 999 case OpCode::CHECK_AND_CONVERT: { 1000 ValuePairTypeAccessor accessor(GetOneParameterMetaData()->GetValue()); 1001 return GateMetaData::Str(accessor.GetSrcType()) + "_TO_" + 1002 GateMetaData::Str(accessor.GetDstType()); 1003 } 1004 default: 1005 return ""; 1006 } 1007 return ""; 1008} 1009 1010void Gate::PrintWithBytecode(std::string_view comment) const 1011{ 1012 PrintGateWithAdditionOp(GetBytecodeStr(), comment); 1013} 1014 1015void Gate::PrintGateWithAdditionOp(std::string additionOp, std::string_view comment) const 1016{ 1017 Print(additionOp, false, -1, comment); 1018} 1019 1020MarkCode Gate::GetMark(TimeStamp stamp) const 1021{ 1022 return (stamp_ == stamp) ? mark_ : MarkCode::NO_MARK; 1023} 1024 1025void Gate::SetMark(MarkCode mark, TimeStamp stamp) 1026{ 1027 stamp_ = stamp; 1028 mark_ = mark; 1029} 1030} // namespace panda::ecmascript::kungfu 1031