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/bytecode_circuit_builder.h" 17#include "ecmascript/compiler/circuit.h" 18#include "ecmascript/compiler/debug_info.h" 19#include "ecmascript/compiler/ecma_opcode_des.h" 20#include "ecmascript/compiler/gate_accessor.h" 21#include "ecmascript/platform/map.h" 22 23namespace panda::ecmascript::kungfu { 24Circuit::Circuit(NativeAreaAllocator* allocator, DebugInfo* debugInfo, const char* funcName, 25 bool isArch64, panda::ecmascript::FrameType type) 26 : circuitSize_(0), 27 gateCount_(0), 28 time_(1), 29 frameType_(type), 30 isArch64_(isArch64), 31 chunk_(allocator), 32 root_(Circuit::NullGate()), 33 metaBuilder_(chunk()), 34 gateToDInfo_(chunk()), 35 debugInfo_(debugInfo) 36#ifndef NDEBUG 37 , allGates_(chunk()) 38#endif 39{ 40 if (funcName != nullptr && debugInfo_->IsEnable()) { 41 debugInfo_->AddFuncDebugInfo(funcName); 42 } 43 space_ = panda::ecmascript::PageMap(CIRCUIT_SPACE, PAGE_PROT_READWRITE).GetMem(); 44 InitRoot(); 45} 46 47Circuit::~Circuit() 48{ 49 panda::ecmascript::PageUnmap(MemMap(space_, CIRCUIT_SPACE)); 50 debugInfo_ = nullptr; 51 space_ = nullptr; 52} 53 54void Circuit::InitRoot() 55{ 56 root_ = NewGate(metaBuilder_.CircuitRoot(), MachineType::NOVALUE, {}, GateType::Empty()); 57 NewGate(metaBuilder_.StateEntry(), MachineType::NOVALUE, { root_ }, GateType::Empty()); 58 NewGate(metaBuilder_.DependEntry(), MachineType::NOVALUE, { root_ }, GateType::Empty()); 59 NewGate(metaBuilder_.ReturnList(), MachineType::NOVALUE, { root_ }, GateType::Empty()); 60 NewGate(metaBuilder_.ArgList(), MachineType::NOVALUE, { root_ }, GateType::Empty()); 61} 62 63uint8_t *Circuit::AllocateSpace(size_t gateSize) 64{ 65 circuitSize_ += gateSize; 66 if (circuitSize_ > CIRCUIT_SPACE) { 67 return nullptr; // abort compilation 68 } 69 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 70 return GetDataPtr(circuitSize_ - gateSize); 71} 72 73Gate *Circuit::AllocateGateSpace(size_t numIns) 74{ 75 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 76 return reinterpret_cast<Gate *>(AllocateSpace(Gate::GetGateSize(numIns)) + Gate::GetOutListSize(numIns)); 77} 78 79bool Circuit::AddComment(GateRef g, std::string &&str) 80{ 81 if (debugInfo_ == nullptr) { 82 return false; 83 } 84 if (!debugInfo_->IsEnable()) { 85 return false; 86 } 87 auto it = gateToDInfo_.find(g); 88 if (it == gateToDInfo_.end()) { 89 size_t index = debugInfo_->AddComment(std::move(str)); 90 gateToDInfo_[g] = index; 91 } else { 92 debugInfo_->AppendComment(it->second, std::move(str)); 93 } 94 return true; 95} 96 97std::string_view Circuit::GetComment(GateRef gate) const 98{ 99 if (debugInfo_ == nullptr || !debugInfo_->IsEnable()) { 100 return ""; 101 } 102 size_t index; 103 if (!GetDebugInfo(gate, index)) { 104 return ""; 105 } 106 return debugInfo_->GetComment(index); 107} 108 109bool Circuit::GetDebugInfo(GateRef g, size_t &index) const 110{ 111 auto it = gateToDInfo_.find(g); 112 if (it != gateToDInfo_.end()) { 113 index = it->second; 114 return true; 115 } else { 116 return false; 117 } 118} 119 120// NOLINTNEXTLINE(modernize-avoid-c-arrays) 121GateRef Circuit::NewGate(const GateMetaData *meta, MachineType machineType, size_t numIns, 122 const GateRef inList[], GateType type, const char* comment) 123{ 124#ifndef NDEBUG 125 if (numIns != meta->GetNumIns()) { 126 LOG_COMPILER(FATAL) << "Invalid input list!" 127 << " op=" << meta->GetOpCode() 128 << " expected_num_in=" << meta->GetNumIns() << " actual_num_in=" << numIns; 129 UNREACHABLE(); 130 } 131#endif 132 std::vector<Gate *> inPtrList(numIns); 133 auto gateSpace = AllocateGateSpace(numIns); 134 for (size_t idx = 0; idx < numIns; idx++) { 135 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 136 inPtrList[idx] = (inList[idx] == Circuit::NullGate()) ? nullptr : LoadGatePtr(inList[idx]); 137 } 138 auto newGate = new (gateSpace) Gate(meta, gateCount_++, inPtrList.data(), machineType, type); 139#ifndef NDEBUG 140 allGates_.push_back(GetGateRef(newGate)); 141#endif 142 GateRef result = GetGateRef(newGate); 143 if (comment != nullptr) { 144 AddComment(result, std::string(comment)); 145 } 146#ifndef NDEBUG 147 if (UNLIKELY(debugInfo_ != nullptr && !currentComment_.empty())) { 148 AddComment(result, std::string(currentComment_)); 149 } 150#endif 151 return result; 152} 153 154GateRef Circuit::NewGate(const GateMetaData *meta, const std::vector<GateRef> &inList, const char* comment) 155{ 156 return NewGate(meta, MachineType::NOVALUE, inList.size(), inList.data(), GateType::Empty(), comment); 157} 158 159GateRef Circuit::NewGate(const GateMetaData *meta, MachineType machineType, 160 const std::initializer_list<GateRef>& args, GateType type, const char* comment) 161{ 162 return NewGate(meta, machineType, args.size(), args.begin(), type, comment); 163} 164 165GateRef Circuit::NewGate(const GateMetaData *meta, MachineType machineType, 166 const std::vector<GateRef>& inList, GateType type, const char* comment) 167{ 168 return NewGate(meta, machineType, inList.size(), inList.data(), type, comment); 169} 170 171GateRef Circuit::NewGate(const GateMetaData *meta, MachineType machineType, GateType type, const char* comment) 172{ 173 return NewGate(meta, machineType, {}, type, comment); 174} 175 176void Circuit::PrintAllGates() const 177{ 178 std::vector<GateRef> gateList; 179 GetAllGates(gateList); 180 for (const auto &gate : gateList) { 181 LoadGatePtrConst(gate)->Print(); 182 } 183} 184 185void Circuit::PrintAllGatesWithBytecode() const 186{ 187 std::vector<GateRef> gateList; 188 GetAllGates(gateList); 189 for (const auto &gate : gateList) { 190 LoadGatePtrConst(gate)->PrintWithBytecode(GetComment(gate)); 191 } 192} 193 194void Circuit::GetAllGates(std::vector<GateRef>& gateList) const 195{ 196 gateList.clear(); 197 for (size_t out = 0; out < circuitSize_; 198 out += Gate::GetGateSize(reinterpret_cast<const Out *>(LoadGatePtrConst(GateRef(out)))->GetIndex() + 1)) { 199 auto gatePtr = reinterpret_cast<const Out *>(LoadGatePtrConst(GateRef(out)))->GetGateConst(); 200 if (!gatePtr->GetMetaData()->IsNop()) { 201 gateList.push_back(GetGateRef(gatePtr)); 202 } 203 } 204} 205 206GateRef Circuit::GetGateRef(const Gate *gate) const 207{ 208 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 209 return static_cast<GateRef>(reinterpret_cast<const uint8_t *>(gate) - GetDataPtrConst(0)); 210} 211 212Gate *Circuit::LoadGatePtr(GateRef shift) 213{ 214 ASSERT(shift != Circuit::NullGate()); 215 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 216 return reinterpret_cast<Gate *>(GetDataPtr(shift)); 217} 218 219const Gate *Circuit::LoadGatePtrConst(GateRef shift) const 220{ 221 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 222 return reinterpret_cast<const Gate *>(GetDataPtrConst(shift)); 223} 224 225void Circuit::AdvanceTime() const 226{ 227 auto &curTime = const_cast<TimeStamp &>(time_); 228 curTime++; 229 if (curTime == 0) { 230 curTime = 1; 231 ResetAllGateTimeStamps(); 232 } 233} 234 235void Circuit::ResetAllGateTimeStamps() const 236{ 237 std::vector<GateRef> gateList; 238 GetAllGates(gateList); 239 for (auto &gate : gateList) { 240 const_cast<Gate *>(LoadGatePtrConst(gate))->SetMark(MarkCode::NO_MARK, 0); 241 } 242} 243 244TimeStamp Circuit::GetTime() const 245{ 246 return time_; 247} 248 249MarkCode Circuit::GetMark(GateRef gate) const 250{ 251 return LoadGatePtrConst(gate)->GetMark(GetTime()); 252} 253 254void Circuit::SetMark(GateRef gate, MarkCode mark) const 255{ 256 const_cast<Gate *>(LoadGatePtrConst(gate))->SetMark(mark, GetTime()); 257} 258 259void Circuit::Verify(GateRef gate, const std::string& methodName) const 260{ 261 LoadGatePtrConst(gate)->Verify(IsArch64(), methodName); 262} 263 264GateRef Circuit::NullGate() 265{ 266 return Gate::InvalidGateRef; 267} 268 269bool Circuit::IsLoopHead(GateRef gate) const 270{ 271 if (gate != NullGate()) { 272 const Gate *curGate = LoadGatePtrConst(gate); 273 return curGate->GetMetaData()->IsLoopHead(); 274 } 275 return false; 276} 277 278bool Circuit::IsControlCase(GateRef gate) const 279{ 280 if (gate != NullGate()) { 281 const Gate *curGate = LoadGatePtrConst(gate); 282 return curGate->GetMetaData()->IsControlCase(); 283 } 284 return false; 285} 286 287bool Circuit::IsValueSelector(GateRef gate) const 288{ 289 if (gate != NullGate()) { 290 const Gate *curGate = LoadGatePtrConst(gate); 291 return curGate->GetOpCode() == OpCode::VALUE_SELECTOR; 292 } 293 return false; 294} 295 296bool Circuit::IsSelector(GateRef gate) const 297{ 298 if (gate != NullGate()) { 299 const Gate *curGate = LoadGatePtrConst(gate); 300 OpCode op = curGate->GetOpCode(); 301 return (op == OpCode::VALUE_SELECTOR) || (op == OpCode::DEPEND_SELECTOR); 302 } 303 return false; 304} 305 306GateRef Circuit::GetIn(GateRef gate, size_t idx) const 307{ 308 ASSERT(idx < LoadGatePtrConst(gate)->GetNumIns()); 309 if (IsInGateNull(gate, idx)) { 310 return NullGate(); 311 } 312 const Gate *curGate = LoadGatePtrConst(gate); 313 return GetGateRef(curGate->GetInGateConst(idx)); 314} 315 316bool Circuit::IsInGateNull(GateRef gate, size_t idx) const 317{ 318 const Gate *curGate = LoadGatePtrConst(gate); 319 return curGate->GetInConst(idx)->IsGateNull(); 320} 321 322bool Circuit::IsFirstOutNull(GateRef gate) const 323{ 324 const Gate *curGate = LoadGatePtrConst(gate); 325 return curGate->IsFirstOutNull(); 326} 327 328std::vector<GateRef> Circuit::GetOutVector(GateRef gate) const 329{ 330 std::vector<GateRef> result; 331 const Gate *curGate = LoadGatePtrConst(gate); 332 if (!curGate->IsFirstOutNull()) { 333 const Out *curOut = curGate->GetFirstOutConst(); 334 result.push_back(GetGateRef(curOut->GetGateConst())); 335 while (!curOut->IsNextOutNull()) { 336 curOut = curOut->GetNextOutConst(); 337 result.push_back(GetGateRef(curOut->GetGateConst())); 338 } 339 } 340 return result; 341} 342 343void Circuit::NewIn(GateRef gate, size_t idx, GateRef in) 344{ 345#ifndef NDEBUG 346 ASSERT(idx < LoadGatePtrConst(gate)->GetNumIns()); 347 ASSERT(Circuit::IsInGateNull(gate, idx)); 348#endif 349 LoadGatePtr(gate)->NewIn(idx, LoadGatePtr(in)); 350} 351 352void Circuit::ModifyIn(GateRef gate, size_t idx, GateRef in) 353{ 354#ifndef NDEBUG 355 ASSERT(idx < LoadGatePtrConst(gate)->GetNumIns()); 356 ASSERT(!Circuit::IsInGateNull(gate, idx) || (GetOpCode(gate) == OpCode::SAVE_REGISTER)); 357#endif 358 LoadGatePtr(gate)->ModifyIn(idx, LoadGatePtr(in)); 359} 360 361void Circuit::DeleteIn(GateRef gate, size_t idx) 362{ 363 ASSERT(idx < LoadGatePtrConst(gate)->GetNumIns()); 364 ASSERT(!Circuit::IsInGateNull(gate, idx)); 365 LoadGatePtr(gate)->DeleteIn(idx); 366} 367 368void Circuit::DeleteGate(GateRef gate) 369{ 370 // constant in constant cache, dont delete it. 371 if (GetOpCode(gate) != OpCode::CONSTANT) { 372 LoadGatePtr(gate)->DeleteGate(); 373 LoadGatePtr(gate)->SetMetaData(Nop()); 374 } 375} 376 377void Circuit::DecreaseIn(GateRef gate, size_t idx) 378{ 379 auto numIns = LoadGatePtrConst(gate)->GetNumIns(); 380 ASSERT(numIns > 0); 381 for (size_t i = idx; i < numIns - 1; i++) { 382 ModifyIn(gate, i, GetIn(gate, i + 1)); 383 } 384 DeleteIn(gate, numIns - 1); 385 GateMetaData *meta = const_cast<GateMetaData *>( 386 LoadGatePtr(gate)->GetMetaData()); 387 if (meta->GetKind() == GateMetaData::Kind::MUTABLE_WITH_SIZE) { 388 meta->DecreaseIn(idx); 389 } else { 390 meta = metaBuilder_.NewGateMetaData(meta); 391 meta->DecreaseIn(idx); 392 LoadGatePtr(gate)->SetMetaData(meta); 393 } 394} 395 396void Circuit::SetGateType(GateRef gate, GateType type) 397{ 398 LoadGatePtr(gate)->SetGateType(type); 399} 400 401void Circuit::SetMachineType(GateRef gate, MachineType machineType) 402{ 403 LoadGatePtr(gate)->SetMachineType(machineType); 404} 405 406GateType Circuit::GetGateType(GateRef gate) const 407{ 408 return LoadGatePtrConst(gate)->GetGateType(); 409} 410 411MachineType Circuit::GetMachineType(GateRef gate) const 412{ 413 return LoadGatePtrConst(gate)->GetMachineType(); 414} 415 416OpCode Circuit::GetOpCode(GateRef gate) const 417{ 418 return LoadGatePtrConst(gate)->GetOpCode(); 419} 420 421GateId Circuit::GetId(GateRef gate) const 422{ 423 return LoadGatePtrConst(gate)->GetId(); 424} 425 426#ifndef NDEBUG 427Circuit::ScopedComment::ScopedComment(std::string &&str, std::string_view *comment) 428 : old_(*comment), comment_(comment) 429{ 430 if (comment->empty()) { 431 str_ = std::move(str); 432 } else { 433 str_ = std::string{*comment} + " " + std::move(str); 434 } 435 *comment_ = {str_}; 436} 437 438Circuit::ScopedComment Circuit::VisitGateBegin(GateRef visitedGate) 439{ 440 return ScopedComment("old " + std::to_string(GetId(visitedGate)), ¤tComment_); 441} 442 443Circuit::ScopedComment Circuit::CommentBegin(std::string &&str) 444{ 445 return ScopedComment(std::move(str), ¤tComment_); 446} 447#endif 448 449void Circuit::Print(GateRef gate) const 450{ 451 LoadGatePtrConst(gate)->Print(); 452} 453 454size_t Circuit::GetCircuitDataSize() const 455{ 456 return circuitSize_; 457} 458 459const void *Circuit::GetSpaceDataStartPtrConst() const 460{ 461 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 462 return GetDataPtrConst(0); 463} 464 465const void *Circuit::GetSpaceDataEndPtrConst() const 466{ 467 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 468 return GetDataPtrConst(circuitSize_); 469} 470 471const uint8_t *Circuit::GetDataPtrConst(size_t offset) const 472{ 473 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 474 return static_cast<uint8_t *>(space_) + offset; 475} 476 477uint8_t *Circuit::GetDataPtr(size_t offset) 478{ 479 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 480 return static_cast<uint8_t *>(space_) + offset; 481} 482 483panda::ecmascript::FrameType Circuit::GetFrameType() const 484{ 485 return frameType_; 486} 487 488void Circuit::SetFrameType(panda::ecmascript::FrameType type) 489{ 490 frameType_ = type; 491} 492 493GateRef Circuit::GetConstantGate(MachineType machineType, uint64_t value, 494 GateType type) 495{ 496 auto search = constantCache_.find({machineType, value, type}); 497 if (search != constantCache_.end()) { 498 return search->second; 499 } 500 auto gate = NewGate(metaBuilder_.Constant(value), machineType, type); 501 constantCache_[{machineType, value, type}] = gate; 502 return gate; 503} 504 505GateRef Circuit::GetConstantGateWithoutCache(MachineType machineType, uint64_t value, GateType type) 506{ 507 auto gate = NewGate(metaBuilder_.Constant(value), machineType, type); 508 return gate; 509} 510 511void Circuit::ClearConstantCache(MachineType machineType, uint64_t value, GateType type) 512{ 513 auto search = constantCache_.find({machineType, value, type}); 514 if (search != constantCache_.end()) { 515 constantCache_.erase(search); 516 } 517} 518 519GateRef Circuit::GetConstantStringGate(MachineType machineType, std::string_view str, 520 GateType type) 521{ 522 auto gate = NewGate(metaBuilder_.ConstString(str), machineType, type); 523 return gate; 524} 525 526GateRef Circuit::GetInitialEnvGate(GateRef depend, GateRef jsFunc) 527{ 528 auto search = initialEnvCache_.find(jsFunc); 529 if (search != initialEnvCache_.end()) { 530 return initialEnvCache_.at(jsFunc); 531 } 532 auto gate = NewGate(GetEnv(), MachineType::I64, {depend, jsFunc}, GateType::AnyType()); 533 initialEnvCache_[jsFunc] = gate; 534 return gate; 535} 536 537GateRef Circuit::NewArg(MachineType machineType, size_t index, 538 GateType type, GateRef argRoot) 539{ 540 return NewGate(metaBuilder_.Arg(index), machineType, { argRoot }, type); 541} 542 543size_t Circuit::GetGateCount() const 544{ 545 return gateCount_; 546} 547 548GateRef Circuit::GetStateRoot() const 549{ 550 const GateAccessor acc(const_cast<Circuit*>(this)); 551 return acc.GetStateRoot(); 552} 553 554GateRef Circuit::GetDependRoot() const 555{ 556 const GateAccessor acc(const_cast<Circuit*>(this)); 557 return acc.GetDependRoot(); 558} 559 560GateRef Circuit::GetArgRoot() const 561{ 562 const GateAccessor acc(const_cast<Circuit*>(this)); 563 return acc.GetArgRoot(); 564} 565 566GateRef Circuit::GetReturnRoot() const 567{ 568 const GateAccessor acc(const_cast<Circuit*>(this)); 569 return acc.GetReturnRoot(); 570} 571} // namespace panda::ecmascript::kungfu 572