1 /* 2 * Copyright (c) 2022 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 #ifndef ECMASCRIPT_COMPILER_BYTECODES_H 17 #define ECMASCRIPT_COMPILER_BYTECODES_H 18 19 #include <cstddef> 20 #include <array> 21 22 #include "libpandabase/macros.h" 23 #include "libpandabase/utils/bit_field.h" 24 #include "libpandafile/bytecode_instruction-inl.h" 25 #include "ecmascript/js_tagged_value.h" 26 27 namespace panda::ecmascript::kungfu { 28 using VRegIDType = uint32_t; 29 using ICSlotIdType = uint16_t; 30 using ImmValueType = uint64_t; 31 using EcmaOpcode = BytecodeInstruction::Opcode; 32 33 class BytecodeCircuitBuilder; 34 class Bytecodes; 35 class BytecodeInfo; 36 class BytecodeIterator; 37 enum BytecodeFlags : uint32_t { 38 READ_ACC = 1 << 0, // 1: flag bit 39 WRITE_ACC = 1 << 1, // 1: flag 1 40 SUPPORT_DEOPT = 1 << 2, // 2: flag 2 41 GENERAL_BC = 1 << 3, 42 READ_THIS_OBJECT = 1 << 4, 43 NO_SIDE_EFFECTS = 1 << 5, 44 READ_ENV = 1 << 7, 45 WRITE_ENV = 1 << 8, 46 }; 47 48 enum BytecodeKind : uint32_t { 49 GENERAL = 0, 50 THROW_BC, 51 RETURN_BC, 52 JUMP_IMM, 53 CONDITIONAL_JUMP, 54 MOV, 55 SET_CONSTANT, 56 SUSPEND, 57 RESUME, 58 DISCARDED, 59 }; 60 61 class BytecodeMetaData { 62 public: 63 static constexpr uint32_t MAX_OPCODE_SIZE = 16; 64 static constexpr uint32_t MAX_SIZE_BITS = 4; 65 static constexpr uint32_t BYTECODE_FLAGS_SIZE = 9; 66 static constexpr uint32_t BYTECODE_KIND_SIZE = 4; 67 68 using OpcodeField = panda::BitField<EcmaOpcode, 0, MAX_OPCODE_SIZE>; 69 using SizeField = OpcodeField::NextField<size_t, MAX_SIZE_BITS>; 70 using KindField = SizeField::NextField<BytecodeKind, BYTECODE_KIND_SIZE>; 71 using FlagsField = KindField::NextField<BytecodeFlags, BYTECODE_FLAGS_SIZE>; 72 HasAccIn()73 bool HasAccIn() const 74 { 75 return HasFlag(BytecodeFlags::READ_ACC); 76 } 77 IsNoSideEffects()78 bool IsNoSideEffects() const 79 { 80 return HasFlag(BytecodeFlags::NO_SIDE_EFFECTS); 81 } 82 HasThisIn()83 bool HasThisIn() const 84 { 85 return HasFlag(BytecodeFlags::READ_THIS_OBJECT); 86 } 87 HasAccOut()88 bool HasAccOut() const 89 { 90 return HasFlag(BytecodeFlags::WRITE_ACC); 91 } 92 HasEnvIn()93 bool HasEnvIn() const 94 { 95 return HasFlag(BytecodeFlags::READ_ENV); 96 } 97 HasEnvOut()98 bool HasEnvOut() const 99 { 100 return HasFlag(BytecodeFlags::WRITE_ENV); 101 } 102 IsMov()103 bool IsMov() const 104 { 105 return GetKind() == BytecodeKind::MOV; 106 } 107 IsReturn()108 bool IsReturn() const 109 { 110 return GetKind() == BytecodeKind::RETURN_BC; 111 } 112 IsThrow()113 bool IsThrow() const 114 { 115 return GetKind() == BytecodeKind::THROW_BC; 116 } 117 IsJump()118 bool IsJump() const 119 { 120 return IsJumpImm() || IsCondJump(); 121 } 122 IsCondJump()123 bool IsCondJump() const 124 { 125 return GetKind() == BytecodeKind::CONDITIONAL_JUMP; 126 } 127 IsJumpImm()128 bool IsJumpImm() const 129 { 130 return GetKind() == BytecodeKind::JUMP_IMM; 131 } 132 IsSuspend()133 bool IsSuspend() const 134 { 135 return GetKind() == BytecodeKind::SUSPEND; 136 } 137 IsSetConstant()138 bool IsSetConstant() const 139 { 140 return GetKind() == BytecodeKind::SET_CONSTANT; 141 } 142 SupportDeopt()143 bool SupportDeopt() const 144 { 145 return HasFlag(BytecodeFlags::SUPPORT_DEOPT); 146 } 147 GetSize()148 size_t GetSize() const 149 { 150 return SizeField::Get(value_); 151 } 152 IsGeneral()153 bool IsGeneral() const 154 { 155 return HasFlag(BytecodeFlags::GENERAL_BC); 156 } 157 IsGeneratorRelative()158 bool IsGeneratorRelative() const 159 { 160 return (GetKind() == BytecodeKind::RESUME) || (GetKind() == BytecodeKind::SUSPEND); 161 } 162 IsDiscarded()163 bool IsDiscarded() const 164 { 165 return GetKind() == BytecodeKind::DISCARDED; 166 } 167 GetOpcode()168 inline EcmaOpcode GetOpcode() const 169 { 170 return OpcodeField::Get(value_); 171 } 172 173 private: 174 BytecodeMetaData() = default; 175 DEFAULT_NOEXCEPT_MOVE_SEMANTIC(BytecodeMetaData); 176 DEFAULT_COPY_SEMANTIC(BytecodeMetaData); BytecodeMetaData(uint64_t value)177 BytecodeMetaData(uint64_t value) : value_(value) {} 178 179 static BytecodeMetaData InitBytecodeMetaData(const uint8_t *pc); 180 HasFlag(BytecodeFlags flag)181 inline bool HasFlag(BytecodeFlags flag) const 182 { 183 return (GetFlags() & flag) == flag; 184 } 185 GetFlags()186 inline BytecodeFlags GetFlags() const 187 { 188 return FlagsField::Get(value_); 189 } 190 GetKind()191 inline BytecodeKind GetKind() const 192 { 193 return KindField::Get(value_); 194 } 195 196 uint64_t value_ {0}; 197 friend class Bytecodes; 198 friend class BytecodeInfo; 199 friend class BytecodeCircuitBuilder; 200 }; 201 202 class Bytecodes { 203 public: 204 static constexpr uint32_t NUM_BYTECODES = 0xFF; 205 static constexpr uint32_t OPCODE_MASK = 0xFF00; 206 static constexpr uint32_t BYTE_SIZE = 8; 207 static constexpr uint32_t CALLRUNTIME_PREFIX_OPCODE_INDEX = 251; 208 static constexpr uint32_t DEPRECATED_PREFIX_OPCODE_INDEX = 252; 209 static constexpr uint32_t WIDE_PREFIX_OPCODE_INDEX = 253; 210 static constexpr uint32_t THROW_PREFIX_OPCODE_INDEX = 254; 211 static constexpr uint32_t MIN_PREFIX_OPCODE_INDEX = CALLRUNTIME_PREFIX_OPCODE_INDEX; 212 213 static constexpr uint32_t LAST_OPCODE = 214 static_cast<uint32_t>(EcmaOpcode::GETASYNCITERATOR_IMM8); 215 static constexpr uint32_t LAST_DEPRECATED_OPCODE = 216 static_cast<uint32_t>(EcmaOpcode::DEPRECATED_DYNAMICIMPORT_PREF_V8); 217 static constexpr uint32_t LAST_WIDE_OPCODE = 218 static_cast<uint32_t>(EcmaOpcode::WIDE_STPATCHVAR_PREF_IMM16); 219 static constexpr uint32_t LAST_THROW_OPCODE = 220 static_cast<uint32_t>(EcmaOpcode::THROW_UNDEFINEDIFHOLEWITHNAME_PREF_ID16); 221 static constexpr uint32_t LAST_CALLRUNTIME_OPCODE = 222 static_cast<uint32_t>(EcmaOpcode::CALLRUNTIME_NOTIFYCONCURRENTRESULT_PREF_NONE); 223 224 static_assert(CALLRUNTIME_PREFIX_OPCODE_INDEX == 225 static_cast<uint32_t>(EcmaOpcode::CALLRUNTIME_NOTIFYCONCURRENTRESULT_PREF_NONE)); 226 static_assert(DEPRECATED_PREFIX_OPCODE_INDEX == 227 static_cast<uint32_t>(EcmaOpcode::DEPRECATED_LDLEXENV_PREF_NONE)); 228 static_assert(WIDE_PREFIX_OPCODE_INDEX == 229 static_cast<uint32_t>(EcmaOpcode::WIDE_CREATEOBJECTWITHEXCLUDEDKEYS_PREF_IMM16_V8_V8)); 230 static_assert(THROW_PREFIX_OPCODE_INDEX == 231 static_cast<uint32_t>(EcmaOpcode::THROW_PREF_NONE)); 232 233 Bytecodes(); 234 Bytecodes(const Bytecodes&) = delete; 235 void operator=(const Bytecodes&) = delete; 236 GetOpcode(const uint8_t * pc)237 static EcmaOpcode GetOpcode(const uint8_t *pc) 238 { 239 uint8_t primary = ReadByte(pc); 240 if (primary >= MIN_PREFIX_OPCODE_INDEX) { 241 uint8_t secondary = ReadByte1(pc); 242 return static_cast<EcmaOpcode>((secondary << 8U) | primary); // 8: byte size 243 } 244 return static_cast<EcmaOpcode>(primary); 245 } 246 GetBytecodeMetaData(const uint8_t * pc)247 BytecodeMetaData GetBytecodeMetaData(const uint8_t *pc) const 248 { 249 uint8_t primary = ReadByte(pc); 250 if (primary >= MIN_PREFIX_OPCODE_INDEX) { 251 uint8_t secondary = ReadByte1(pc); 252 if (primary == CALLRUNTIME_PREFIX_OPCODE_INDEX) { 253 return callRuntimeBytecodes_[secondary]; 254 } else if (primary == DEPRECATED_PREFIX_OPCODE_INDEX) { 255 return deprecatedBytecodes_[secondary]; 256 } else if (primary == WIDE_PREFIX_OPCODE_INDEX) { 257 return wideBytecodes_[secondary]; 258 } else { 259 ASSERT(primary == THROW_PREFIX_OPCODE_INDEX); 260 return throwBytecodes_[secondary]; 261 } 262 } 263 return bytecodes_[primary]; 264 } 265 266 private: ReadByte(const uint8_t * pc)267 static uint8_t ReadByte(const uint8_t *pc) 268 { 269 return *pc; 270 } ReadByte1(const uint8_t * pc)271 static uint8_t ReadByte1(const uint8_t *pc) 272 { 273 return *(pc + 1); // 1: byte1 274 } 275 BytecodeMetaData InitBytecodeMetaData(const uint8_t *pc); 276 277 std::array<BytecodeMetaData, NUM_BYTECODES> bytecodes_{}; 278 std::array<BytecodeMetaData, NUM_BYTECODES> callRuntimeBytecodes_{}; 279 std::array<BytecodeMetaData, NUM_BYTECODES> deprecatedBytecodes_{}; 280 std::array<BytecodeMetaData, NUM_BYTECODES> wideBytecodes_{}; 281 std::array<BytecodeMetaData, NUM_BYTECODES> throwBytecodes_{}; 282 }; 283 284 enum class ConstDataIDType : uint8_t { 285 StringIDType, 286 MethodIDType, 287 ArrayLiteralIDType, 288 ObjectLiteralIDType, 289 ClassLiteralIDType, 290 }; 291 292 class VirtualRegister { 293 public: VirtualRegister(VRegIDType id)294 explicit VirtualRegister(VRegIDType id) : id_(id) 295 { 296 } 297 ~VirtualRegister() = default; 298 SetId(VRegIDType id)299 void SetId(VRegIDType id) 300 { 301 id_ = id; 302 } 303 GetId()304 VRegIDType GetId() const 305 { 306 return id_; 307 } 308 309 private: 310 VRegIDType id_; 311 }; 312 313 class Immediate { 314 public: Immediate(ImmValueType value)315 explicit Immediate(ImmValueType value) : value_(value) 316 { 317 } 318 ~Immediate() = default; 319 SetValue(ImmValueType value)320 void SetValue(ImmValueType value) 321 { 322 value_ = value; 323 } 324 ToJSTaggedValueInt()325 ImmValueType ToJSTaggedValueInt() const 326 { 327 return value_ | JSTaggedValue::TAG_INT; 328 } 329 ToJSTaggedValueDouble()330 ImmValueType ToJSTaggedValueDouble() const 331 { 332 return JSTaggedValue(bit_cast<double>(value_)).GetRawData(); 333 } 334 GetValue()335 ImmValueType GetValue() const 336 { 337 return value_; 338 } 339 340 private: 341 ImmValueType value_; 342 }; 343 344 345 class ICSlotId { 346 public: ICSlotId(ICSlotIdType id)347 explicit ICSlotId(ICSlotIdType id) : id_(id) 348 { 349 } 350 ~ICSlotId() = default; 351 SetId(ICSlotIdType id)352 void SetId(ICSlotIdType id) 353 { 354 id_ = id; 355 } 356 GetId()357 ICSlotIdType GetId() const 358 { 359 return id_; 360 } 361 362 private: 363 ICSlotIdType id_; 364 }; 365 366 class ConstDataId { 367 public: ConstDataId(ConstDataIDType type,uint16_t id)368 explicit ConstDataId(ConstDataIDType type, uint16_t id) 369 :type_(type), id_(id) 370 { 371 } 372 ConstDataId(uint64_t bitfield)373 explicit ConstDataId(uint64_t bitfield) 374 { 375 type_ = ConstDataIDType(bitfield >> TYPE_SHIFT); 376 id_ = bitfield & ((1 << TYPE_SHIFT) - 1); 377 } 378 379 ~ConstDataId() = default; 380 SetId(uint16_t id)381 void SetId(uint16_t id) 382 { 383 id_ = id; 384 } 385 GetId()386 uint16_t GetId() const 387 { 388 return id_; 389 } 390 SetType(ConstDataIDType type)391 void SetType(ConstDataIDType type) 392 { 393 type_ = type; 394 } 395 GetType()396 ConstDataIDType GetType() const 397 { 398 return type_; 399 } 400 IsStringId()401 bool IsStringId() const 402 { 403 return type_ == ConstDataIDType::StringIDType; 404 } 405 IsMethodId()406 bool IsMethodId() const 407 { 408 return type_ == ConstDataIDType::MethodIDType; 409 } 410 IsClassLiteraId()411 bool IsClassLiteraId() const 412 { 413 return type_ == ConstDataIDType::ClassLiteralIDType; 414 } 415 IsObjectLiteralID()416 bool IsObjectLiteralID() const 417 { 418 return type_ == ConstDataIDType::ObjectLiteralIDType; 419 } 420 IsArrayLiteralID()421 bool IsArrayLiteralID() const 422 { 423 return type_ == ConstDataIDType::ArrayLiteralIDType; 424 } 425 CaculateBitField()426 uint64_t CaculateBitField() const 427 { 428 return (static_cast<uint8_t>(type_) << TYPE_SHIFT) | id_; 429 } 430 431 private: 432 static constexpr int TYPE_SHIFT = 16; 433 ConstDataIDType type_; 434 uint16_t id_; 435 }; 436 437 class BytecodeInfo { 438 public: 439 // set of id, immediate and read register 440 std::vector<std::variant<ConstDataId, ICSlotId, Immediate, VirtualRegister>> inputs {}; 441 std::vector<VRegIDType> vregOut {}; // write register 442 Deopt()443 bool Deopt() const 444 { 445 return metaData_.SupportDeopt(); 446 } 447 AccOut()448 bool AccOut() const 449 { 450 return metaData_.HasAccOut(); 451 } 452 AccIn()453 bool AccIn() const 454 { 455 return metaData_.HasAccIn(); 456 } 457 EnvIn()458 bool EnvIn() const 459 { 460 return metaData_.HasEnvIn(); 461 } 462 EnvOut()463 bool EnvOut() const 464 { 465 return metaData_.HasEnvOut(); 466 } 467 NoSideEffects()468 bool NoSideEffects() const 469 { 470 return metaData_.IsNoSideEffects(); 471 } 472 ThisObjectIn()473 bool ThisObjectIn() const 474 { 475 return metaData_.HasThisIn(); 476 } 477 GetSize()478 size_t GetSize() const 479 { 480 return metaData_.GetSize(); 481 } 482 IsDef()483 bool IsDef() const 484 { 485 return (!vregOut.empty()) || AccOut(); 486 } 487 IsOut(VRegIDType reg,uint32_t index)488 bool IsOut(VRegIDType reg, uint32_t index) const 489 { 490 bool isDefined = (!vregOut.empty() && (reg == vregOut.at(index))); 491 return isDefined; 492 } 493 IsMov()494 bool IsMov() const 495 { 496 return metaData_.IsMov(); 497 } 498 IsJump()499 bool IsJump() const 500 { 501 return metaData_.IsJump(); 502 } 503 IsCondJump()504 bool IsCondJump() const 505 { 506 return metaData_.IsCondJump(); 507 } 508 IsReturn()509 bool IsReturn() const 510 { 511 return metaData_.IsReturn(); 512 } 513 IsThrow()514 bool IsThrow() const 515 { 516 return metaData_.IsThrow(); 517 } 518 IsSuspend()519 bool IsSuspend() const 520 { 521 return metaData_.IsSuspend(); 522 } 523 IsDiscarded()524 bool IsDiscarded() const 525 { 526 return metaData_.IsDiscarded(); 527 } 528 IsSetConstant()529 bool IsSetConstant() const 530 { 531 return metaData_.IsSetConstant(); 532 } 533 IsGeneral()534 bool IsGeneral() const 535 { 536 return metaData_.IsGeneral(); 537 } 538 IsGeneratorRelative()539 bool IsGeneratorRelative() const 540 { 541 return metaData_.IsGeneratorRelative(); 542 } 543 ComputeValueInputCount()544 size_t ComputeValueInputCount() const 545 { 546 return (AccIn() ? 1 : 0) + (ThisObjectIn() ? 1 : 0) + inputs.size(); 547 } 548 ComputeOutCount()549 size_t ComputeOutCount() const 550 { 551 return (AccOut() ? 1 : 0) + vregOut.size(); 552 } 553 IsBc(EcmaOpcode ecmaOpcode)554 bool IsBc(EcmaOpcode ecmaOpcode) const 555 { 556 return metaData_.GetOpcode() == ecmaOpcode; 557 } 558 GetOpcode()559 inline EcmaOpcode GetOpcode() const 560 { 561 return metaData_.GetOpcode(); 562 } 563 564 static void InitBytecodeInfo(BytecodeCircuitBuilder *builder, 565 BytecodeInfo &info, const uint8_t* pc); 566 567 private: 568 BytecodeMetaData metaData_ { 0 }; 569 friend class BytecodeCircuitBuilder; 570 }; 571 572 class BytecodeIterator { 573 public: 574 BytecodeIterator() = default; BytecodeIterator(BytecodeCircuitBuilder * builder,uint32_t start,uint32_t end)575 explicit BytecodeIterator(BytecodeCircuitBuilder *builder, 576 uint32_t start, uint32_t end) 577 : builder_(builder), start_(start), end_(end) {} Reset(BytecodeCircuitBuilder * builder,uint32_t start,uint32_t end)578 void Reset(BytecodeCircuitBuilder *builder, 579 uint32_t start, uint32_t end) 580 { 581 builder_ = builder; 582 start_ = start; 583 end_ = end; 584 } 585 586 BytecodeIterator& operator++() 587 { 588 if (InRange()) { 589 index_++; 590 } 591 return *this; 592 } 593 BytecodeIterator& operator--() 594 { 595 if (InRange()) { 596 index_--; 597 } 598 return *this; 599 } 600 Goto(uint32_t i)601 void Goto(uint32_t i) 602 { 603 index_ = i; 604 } 605 GotoStart()606 void GotoStart() 607 { 608 index_ = start_; 609 ASSERT(InRange()); 610 } 611 GotoEnd()612 void GotoEnd() 613 { 614 index_ = end_; 615 ASSERT(InRange()); 616 } 617 InRange()618 bool InRange() const 619 { 620 return (index_ <= end_) && (index_ >= start_); 621 } 622 Done()623 bool Done() const 624 { 625 return !InRange(); 626 } 627 Index()628 uint32_t Index() const 629 { 630 return index_; 631 } 632 633 const BytecodeInfo &GetBytecodeInfo() const; 634 const uint8_t *PeekNextPc(size_t i) const; 635 const uint8_t *PeekPrevPc(size_t i) const; 636 637 private: 638 static constexpr int32_t INVALID_INDEX = -1; 639 640 BytecodeCircuitBuilder *builder_ {nullptr}; 641 uint32_t start_ {0}; 642 uint32_t end_ {0}; 643 uint32_t index_{ INVALID_INDEX }; 644 }; 645 } // panda::ecmascript::kungfu 646 #endif // ECMASCRIPT_COMPILER_BYTECODES_H