| // Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| #ifndef RUNTIME_VM_CONSTANTS_KBC_H_ | |
| #define RUNTIME_VM_CONSTANTS_KBC_H_ | |
| #include "platform/assert.h" | |
| #include "platform/globals.h" | |
| #include "platform/utils.h" | |
| namespace dart { | |
| // clang-format off | |
| // Bytecode instructions are specified using the following format: | |
| // | |
| // V(BytecodeName, OperandForm, BytecodeKind, Op1, Op2, Op3) | |
| // | |
| // - OperandForm specifies operand encoding and should be one of 0, A, D, X, T, | |
| // A_E, A_Y, D_F or A_B_C. | |
| // | |
| // - BytecodeKind is one of WIDE, RESV (reserved), ORDN (ordinary) | |
| // | |
| // - Op1, Op2, Op3 specify operand meaning. Possible values: | |
| // | |
| // ___ ignored / non-existent operand | |
| // num immediate operand | |
| // lit constant literal from object pool | |
| // reg register (unsigned FP relative local) | |
| // xeg x-register (signed FP relative local) | |
| // tgt jump target relative to the PC of the current instruction | |
| // | |
| // TODO(vegorov) jump targets should be encoded relative to PC of the next | |
| // instruction because PC is incremented immediately after fetch | |
| // and before decoding. | |
| // | |
| #define PUBLIC_KERNEL_BYTECODES_LIST(V) \ | |
| V(Trap, 0, ORDN, ___, ___, ___) \ | |
| V(Dup, 0, ORDN, ___, ___, ___) \ | |
| V(Entry, D, ORDN, num, ___, ___) \ | |
| V(Entry_Wide, D, WIDE, num, ___, ___) \ | |
| V(EntryOptional, A_B_C, ORDN, num, num, num) \ | |
| V(EntrySuspendable, A_B_C, ORDN, num, num, num) \ | |
| V(LoadConstant, A_E, ORDN, reg, lit, ___) \ | |
| V(LoadConstant_Wide, A_E, WIDE, reg, lit, ___) \ | |
| V(Frame, D, ORDN, num, ___, ___) \ | |
| V(Frame_Wide, D, WIDE, num, ___, ___) \ | |
| V(CheckFunctionTypeArgs, A_E, ORDN, num, reg, ___) \ | |
| V(CheckFunctionTypeArgs_Wide, A_E, WIDE, num, reg, ___) \ | |
| V(CheckStack, A, ORDN, num, ___, ___) \ | |
| V(Nop, 0, ORDN, ___, ___, ___) \ | |
| V(JumpIfUnchecked, T, ORDN, tgt, ___, ___) \ | |
| V(JumpIfUnchecked_Wide, T, WIDE, tgt, ___, ___) \ | |
| V(Allocate, D, ORDN, lit, ___, ___) \ | |
| V(Allocate_Wide, D, WIDE, lit, ___, ___) \ | |
| V(AllocateT, 0, ORDN, ___, ___, ___) \ | |
| V(CreateArrayTOS, 0, ORDN, ___, ___, ___) \ | |
| V(AllocateClosure, D, ORDN, lit, ___, ___) \ | |
| V(AllocateClosure_Wide, D, WIDE, lit, ___, ___) \ | |
| V(LoadClosureElement, D, ORDN, num, ___, ___) \ | |
| V(LoadClosureElement_Wide, D, WIDE, num, ___, ___) \ | |
| V(StoreClosureElement, D, ORDN, num, ___, ___) \ | |
| V(StoreClosureElement_Wide, D, WIDE, num, ___, ___) \ | |
| V(AllocateContext, A_E, ORDN, num, num, ___) \ | |
| V(AllocateContext_Wide, A_E, WIDE, num, num, ___) \ | |
| V(CloneContext, A_E, ORDN, num, num, ___) \ | |
| V(CloneContext_Wide, A_E, WIDE, num, num, ___) \ | |
| V(LoadContextParent, 0, ORDN, ___, ___, ___) \ | |
| V(StoreContextParent, 0, ORDN, ___, ___, ___) \ | |
| V(LoadContextVar, A_E, ORDN, num, num, ___) \ | |
| V(LoadContextVar_Wide, A_E, WIDE, num, num, ___) \ | |
| V(Unused04, 0, RESV, ___, ___, ___) \ | |
| V(Unused05, 0, RESV, ___, ___, ___) \ | |
| V(StoreContextVar, A_E, ORDN, num, num, ___) \ | |
| V(StoreContextVar_Wide, A_E, WIDE, num, num, ___) \ | |
| V(PushConstant, D, ORDN, lit, ___, ___) \ | |
| V(PushConstant_Wide, D, WIDE, lit, ___, ___) \ | |
| V(Unused06, 0, RESV, ___, ___, ___) \ | |
| V(Unused07, 0, RESV, ___, ___, ___) \ | |
| V(PushTrue, 0, ORDN, ___, ___, ___) \ | |
| V(PushFalse, 0, ORDN, ___, ___, ___) \ | |
| V(PushInt, X, ORDN, num, ___, ___) \ | |
| V(PushInt_Wide, X, WIDE, num, ___, ___) \ | |
| V(Unused08, 0, RESV, ___, ___, ___) \ | |
| V(Unused09, 0, RESV, ___, ___, ___) \ | |
| V(Unused10, 0, RESV, ___, ___, ___) \ | |
| V(Unused11, 0, RESV, ___, ___, ___) \ | |
| V(PushNull, 0, ORDN, ___, ___, ___) \ | |
| V(Drop1, 0, ORDN, ___, ___, ___) \ | |
| V(Push, X, ORDN, xeg, ___, ___) \ | |
| V(Push_Wide, X, WIDE, xeg, ___, ___) \ | |
| V(Unused12, 0, RESV, ___, ___, ___) \ | |
| V(Unused13, 0, RESV, ___, ___, ___) \ | |
| V(Unused14, 0, RESV, ___, ___, ___) \ | |
| V(Unused15, 0, RESV, ___, ___, ___) \ | |
| V(Unused16, 0, RESV, ___, ___, ___) \ | |
| V(Unused17, 0, RESV, ___, ___, ___) \ | |
| V(PopLocal, X, ORDN, xeg, ___, ___) \ | |
| V(PopLocal_Wide, X, WIDE, xeg, ___, ___) \ | |
| V(LoadStatic, D, ORDN, lit, ___, ___) \ | |
| V(LoadStatic_Wide, D, WIDE, lit, ___, ___) \ | |
| V(StoreLocal, X, ORDN, xeg, ___, ___) \ | |
| V(StoreLocal_Wide, X, WIDE, xeg, ___, ___) \ | |
| V(LoadFieldTOS, D, ORDN, lit, ___, ___) \ | |
| V(LoadFieldTOS_Wide, D, WIDE, lit, ___, ___) \ | |
| V(StoreFieldTOS, D, ORDN, lit, ___, ___) \ | |
| V(StoreFieldTOS_Wide, D, WIDE, lit, ___, ___) \ | |
| V(StoreIndexedTOS, 0, ORDN, ___, ___, ___) \ | |
| V(Unused20, 0, RESV, ___, ___, ___) \ | |
| V(JumpIfInitialized, T, ORDN, tgt, ___, ___) \ | |
| V(JumpIfInitialized_Wide, T, WIDE, tgt, ___, ___) \ | |
| V(PushUninitializedSentinel, 0, ORDN, ___, ___, ___) \ | |
| V(Unused21, 0, RESV, ___, ___, ___) \ | |
| V(InitLateField, D, ORDN, lit, ___, ___) \ | |
| V(InitLateField_Wide, D, WIDE, lit, ___, ___) \ | |
| V(StoreStaticTOS, D, ORDN, lit, ___, ___) \ | |
| V(StoreStaticTOS_Wide, D, WIDE, lit, ___, ___) \ | |
| V(Jump, T, ORDN, tgt, ___, ___) \ | |
| V(Jump_Wide, T, WIDE, tgt, ___, ___) \ | |
| V(JumpIfNoAsserts, T, ORDN, tgt, ___, ___) \ | |
| V(JumpIfNoAsserts_Wide, T, WIDE, tgt, ___, ___) \ | |
| V(JumpIfNotZeroTypeArgs, T, ORDN, tgt, ___, ___) \ | |
| V(JumpIfNotZeroTypeArgs_Wide, T, WIDE, tgt, ___, ___) \ | |
| V(JumpIfEqStrict, T, ORDN, tgt, ___, ___) \ | |
| V(JumpIfEqStrict_Wide, T, WIDE, tgt, ___, ___) \ | |
| V(JumpIfNeStrict, T, ORDN, tgt, ___, ___) \ | |
| V(JumpIfNeStrict_Wide, T, WIDE, tgt, ___, ___) \ | |
| V(JumpIfTrue, T, ORDN, tgt, ___, ___) \ | |
| V(JumpIfTrue_Wide, T, WIDE, tgt, ___, ___) \ | |
| V(JumpIfFalse, T, ORDN, tgt, ___, ___) \ | |
| V(JumpIfFalse_Wide, T, WIDE, tgt, ___, ___) \ | |
| V(JumpIfNull, T, ORDN, tgt, ___, ___) \ | |
| V(JumpIfNull_Wide, T, WIDE, tgt, ___, ___) \ | |
| V(JumpIfNotNull, T, ORDN, tgt, ___, ___) \ | |
| V(JumpIfNotNull_Wide, T, WIDE, tgt, ___, ___) \ | |
| V(Suspend, T, ORDN, tgt, ___, ___) \ | |
| V(Suspend_Wide, T, WIDE, tgt, ___, ___) \ | |
| V(DirectCall, D_F, ORDN, num, num, ___) \ | |
| V(DirectCall_Wide, D_F, WIDE, num, num, ___) \ | |
| V(UncheckedDirectCall, D_F, ORDN, num, num, ___) \ | |
| V(UncheckedDirectCall_Wide, D_F, WIDE, num, num, ___) \ | |
| V(InterfaceCall, D_F, ORDN, num, num, ___) \ | |
| V(InterfaceCall_Wide, D_F, WIDE, num, num, ___) \ | |
| V(ExternalCall, D, ORDN, lit, ___, ___) \ | |
| V(ExternalCall_Wide, D, WIDE, lit, ___, ___) \ | |
| V(InstantiatedInterfaceCall, D_F, ORDN, num, num, ___) \ | |
| V(InstantiatedInterfaceCall_Wide, D_F, WIDE, num, num, ___) \ | |
| V(UncheckedClosureCall, D_F, ORDN, num, num, ___) \ | |
| V(UncheckedClosureCall_Wide, D_F, WIDE, num, num, ___) \ | |
| V(UncheckedInterfaceCall, D_F, ORDN, num, num, ___) \ | |
| V(UncheckedInterfaceCall_Wide, D_F, WIDE, num, num, ___) \ | |
| V(DynamicCall, D_F, ORDN, num, num, ___) \ | |
| V(DynamicCall_Wide, D_F, WIDE, num, num, ___) \ | |
| V(ReturnTOS, 0, ORDN, ___, ___, ___) \ | |
| V(Unused25, 0, RESV, ___, ___, ___) \ | |
| V(AssertAssignable, A_E, ORDN, num, lit, ___) \ | |
| V(AssertAssignable_Wide, A_E, WIDE, num, lit, ___) \ | |
| V(AssertSubtype, 0, ORDN, ___, ___, ___) \ | |
| V(Unused30, 0, RESV, ___, ___, ___) \ | |
| V(LoadTypeArgumentsField, D, ORDN, lit, ___, ___) \ | |
| V(LoadTypeArgumentsField_Wide, D, WIDE, lit, ___, ___) \ | |
| V(InstantiateType, D, ORDN, lit, ___, ___) \ | |
| V(InstantiateType_Wide, D, WIDE, lit, ___, ___) \ | |
| V(InstantiateTypeArgumentsTOS, A_E, ORDN, num, lit, ___) \ | |
| V(InstantiateTypeArgumentsTOS_Wide, A_E, WIDE, num, lit, ___) \ | |
| V(Unused32, 0, RESV, ___, ___, ___) \ | |
| V(Unused33, 0, RESV, ___, ___, ___) \ | |
| V(Unused34, 0, RESV, ___, ___, ___) \ | |
| V(Unused35, 0, RESV, ___, ___, ___) \ | |
| V(Throw, A, ORDN, num, ___, ___) \ | |
| V(SetFrame, A, ORDN, num, ___, num) \ | |
| V(MoveSpecial, A_Y, ORDN, num, xeg, ___) \ | |
| V(MoveSpecial_Wide, A_Y, WIDE, num, xeg, ___) \ | |
| V(BooleanNegateTOS, 0, ORDN, ___, ___, ___) \ | |
| V(EqualsNull, 0, ORDN, ___, ___, ___) \ | |
| V(NullCheck, D, ORDN, lit, ___, ___) \ | |
| V(NullCheck_Wide, D, WIDE, lit, ___, ___) \ | |
| V(NegateInt, 0, ORDN, ___, ___, ___) \ | |
| V(AddInt, 0, ORDN, ___, ___, ___) \ | |
| V(SubInt, 0, ORDN, ___, ___, ___) \ | |
| V(MulInt, 0, ORDN, ___, ___, ___) \ | |
| V(TruncDivInt, 0, ORDN, ___, ___, ___) \ | |
| V(ModInt, 0, ORDN, ___, ___, ___) \ | |
| V(BitAndInt, 0, ORDN, ___, ___, ___) \ | |
| V(BitOrInt, 0, ORDN, ___, ___, ___) \ | |
| V(BitXorInt, 0, ORDN, ___, ___, ___) \ | |
| V(ShlInt, 0, ORDN, ___, ___, ___) \ | |
| V(ShrInt, 0, ORDN, ___, ___, ___) \ | |
| V(CompareIntEq, 0, ORDN, ___, ___, ___) \ | |
| V(CompareIntGt, 0, ORDN, ___, ___, ___) \ | |
| V(CompareIntLt, 0, ORDN, ___, ___, ___) \ | |
| V(CompareIntGe, 0, ORDN, ___, ___, ___) \ | |
| V(CompareIntLe, 0, ORDN, ___, ___, ___) \ | |
| V(NegateDouble, 0, ORDN, ___, ___, ___) \ | |
| V(AddDouble, 0, ORDN, ___, ___, ___) \ | |
| V(SubDouble, 0, ORDN, ___, ___, ___) \ | |
| V(MulDouble, 0, ORDN, ___, ___, ___) \ | |
| V(DivDouble, 0, ORDN, ___, ___, ___) \ | |
| V(CompareDoubleEq, 0, ORDN, ___, ___, ___) \ | |
| V(CompareDoubleGt, 0, ORDN, ___, ___, ___) \ | |
| V(CompareDoubleLt, 0, ORDN, ___, ___, ___) \ | |
| V(CompareDoubleGe, 0, ORDN, ___, ___, ___) \ | |
| V(CompareDoubleLe, 0, ORDN, ___, ___, ___) \ | |
| V(AllocateRecord, D, ORDN, lit, ___, ___) \ | |
| V(AllocateRecord_Wide, D, WIDE, lit, ___, ___) \ | |
| V(LoadRecordField, D, ORDN, num, ___, ___) \ | |
| V(LoadRecordField_Wide, D, WIDE, num, ___, ___) \ | |
| V(FfiCall, D, ORDN, lit, ___, ___) \ | |
| V(FfiCall_Wide, D, WIDE, lit, ___, ___) \ | |
| V(RecordCoverage, A_E, ORDN, num, num, ___) \ | |
| V(RecordCoverage_Wide, A_E, WIDE, num, num, ___) \ | |
| V(ResolveNativeFunction, D, ORDN, lit, ___, ___) \ | |
| V(ResolveNativeFunction_Wide, D, WIDE, lit, ___, ___) \ | |
| // These bytecodes are only generated within the VM. Reassigning their | |
| // opcodes is not a breaking change. | |
| #define INTERNAL_KERNEL_BYTECODES_WITH_CUSTOM_CODE(V) \ | |
| /* ImplicitConstructorClosure and ImplicitInstanceClosure instructions */ \ | |
| /* use D_F encoding as they may call target constructor or method and */ \ | |
| /* should be compatible with other ***Call instructions */ \ | |
| /* in order to support DecodeArgc when returning from a call. */ \ | |
| V(VMInternal_ImplicitConstructorClosure, D_F, ORDN, num, num, ___) \ | |
| V(VMInternal_ImplicitConstructorClosure_Wide, D_F, ORDN, num, num, ___) \ | |
| V(VMInternal_ImplicitInstanceClosure, D_F, ORDN, num, num, ___) \ | |
| V(VMInternal_ImplicitInstanceClosure_Wide, D_F, ORDN, num, num, ___) \ | |
| #define INTERNAL_KERNEL_BYTECODES_WITH_DEFAULT_CODE(V) \ | |
| V(VMInternal_ImplicitGetter, 0, ORDN, ___, ___, ___) \ | |
| V(VMInternal_ImplicitSetter, 0, ORDN, ___, ___, ___) \ | |
| V(VMInternal_ImplicitStaticGetter, 0, ORDN, ___, ___, ___) \ | |
| V(VMInternal_ImplicitSharedStaticGetter, 0, ORDN, ___, ___, ___) \ | |
| V(VMInternal_ImplicitStaticSetter, 0, ORDN, ___, ___, ___) \ | |
| V(VMInternal_ImplicitSharedStaticSetter, 0, ORDN, ___, ___, ___) \ | |
| V(VMInternal_MethodExtractorWithITA, 0, ORDN, ___, ___, ___) \ | |
| V(VMInternal_MethodExtractorWithoutITA, 0, ORDN, ___, ___, ___) \ | |
| V(VMInternal_InvokeClosure, 0, ORDN, ___, ___, ___) \ | |
| V(VMInternal_InvokeField, 0, ORDN, ___, ___, ___) \ | |
| V(VMInternal_ForwardDynamicInvocation, 0, ORDN, ___, ___, ___) \ | |
| V(VMInternal_ImplicitStaticClosure, 0, ORDN, ___, ___, ___) \ | |
| V(VMInternal_NoSuchMethodDispatcher, 0, ORDN, ___, ___, ___) \ | |
| // One breakpoint opcode for each instruction size. | |
| #define INTERNAL_KERNEL_BREAKPOINT_BYTECODES(V) \ | |
| V(VMInternal_Breakpoint_0, 0, ORDN, ___, ___, ___) \ | |
| V(VMInternal_Breakpoint_A_B_C, A_B_C, ORDN, num, num, num) \ | |
| V(VMInternal_Breakpoint_D, D, ORDN, num, ___, ___) \ | |
| V(VMInternal_Breakpoint_D_Wide, D, WIDE, num, ___, ___) \ | |
| V(VMInternal_Breakpoint_A_E, A_E, ORDN, num, num, ___) \ | |
| V(VMInternal_Breakpoint_A_E_Wide, A_E, WIDE, num, num, ___) \ | |
| #define INTERNAL_KERNEL_BYTECODES_LIST_WITH_NO_BREAKPOINTS(V) \ | |
| INTERNAL_KERNEL_BYTECODES_WITH_CUSTOM_CODE(V) \ | |
| INTERNAL_KERNEL_BYTECODES_WITH_DEFAULT_CODE(V) | |
| #define INTERNAL_KERNEL_BYTECODES_LIST(V) \ | |
| INTERNAL_KERNEL_BYTECODES_LIST_WITH_NO_BREAKPOINTS(V) \ | |
| INTERNAL_KERNEL_BREAKPOINT_BYTECODES(V) | |
| #define KERNEL_BYTECODES_LIST_WITH_NO_BREAKPOINTS(V) \ | |
| PUBLIC_KERNEL_BYTECODES_LIST(V) \ | |
| INTERNAL_KERNEL_BYTECODES_LIST_WITH_NO_BREAKPOINTS(V) | |
| #define KERNEL_BYTECODES_LIST(V) \ | |
| PUBLIC_KERNEL_BYTECODES_LIST(V) \ | |
| INTERNAL_KERNEL_BYTECODES_LIST(V) | |
| // clang-format on | |
| typedef uint8_t KBCInstr; | |
| class KernelBytecode { | |
| public: | |
| // Magic value of bytecode files. | |
| static const intptr_t kMagicValue = 0x44424333; // 'DBC3' | |
| // Bytecode format version supported by the VM | |
| // (should match pkg/dart2bytecode/lib/dbc.dart). | |
| static const intptr_t kBytecodeFormatVersion = 3; | |
| enum Opcode { | |
| #define DECLARE_BYTECODE(name, encoding, kind, op1, op2, op3) k##name, | |
| KERNEL_BYTECODES_LIST(DECLARE_BYTECODE) | |
| #undef DECLARE_BYTECODE | |
| kNumOpcodes, | |
| }; | |
| static const char* NameOf(Opcode op) { | |
| const char* names[] = { | |
| #define NAME(name, encoding, kind, op1, op2, op3) #name, | |
| KERNEL_BYTECODES_LIST(NAME) | |
| #undef NAME | |
| }; | |
| return names[op]; | |
| } | |
| static const intptr_t kMaxInstructionSize = 6; | |
| static const intptr_t kInstructionSize[]; | |
| enum SpecialIndex { | |
| kExceptionSpecialIndex, | |
| kStackTraceSpecialIndex, | |
| kSpecialIndexCount | |
| }; | |
| private: | |
| static const intptr_t kWideModifier = 1; | |
| // Should be used only on instructions with wide variants. | |
| DART_FORCE_INLINE static bool IsWide(const KBCInstr* instr) { | |
| return IsWide(DecodeOpcode(instr)); | |
| } | |
| // Should be used only on instructions with wide variants. | |
| DART_FORCE_INLINE static constexpr bool IsWide(Opcode opcode) { | |
| return ((opcode & kWideModifier) != 0); | |
| } | |
| public: | |
| DART_FORCE_INLINE static uint8_t DecodeA(const KBCInstr* bc) { return bc[1]; } | |
| DART_FORCE_INLINE static uint8_t DecodeB(const KBCInstr* bc) { return bc[2]; } | |
| DART_FORCE_INLINE static uint8_t DecodeC(const KBCInstr* bc) { return bc[3]; } | |
| DART_FORCE_INLINE static uint32_t DecodeD(const KBCInstr* bc) { | |
| if (IsWide(bc)) { | |
| return static_cast<uint32_t>(bc[1]) | | |
| (static_cast<uint32_t>(bc[2]) << 8) | | |
| (static_cast<uint32_t>(bc[3]) << 16) | | |
| (static_cast<uint32_t>(bc[4]) << 24); | |
| } else { | |
| return bc[1]; | |
| } | |
| } | |
| DART_FORCE_INLINE static int32_t DecodeX(const KBCInstr* bc) { | |
| if (IsWide(bc)) { | |
| return static_cast<int32_t>(static_cast<uint32_t>(bc[1]) | | |
| (static_cast<uint32_t>(bc[2]) << 8) | | |
| (static_cast<uint32_t>(bc[3]) << 16) | | |
| (static_cast<uint32_t>(bc[4]) << 24)); | |
| } else { | |
| return static_cast<int8_t>(bc[1]); | |
| } | |
| } | |
| DART_FORCE_INLINE static int32_t DecodeT(const KBCInstr* bc) { | |
| if (IsWide(bc)) { | |
| return static_cast<int32_t>((static_cast<uint32_t>(bc[1]) << 8) | | |
| (static_cast<uint32_t>(bc[2]) << 16) | | |
| (static_cast<uint32_t>(bc[3]) << 24)) >> | |
| 8; | |
| } else { | |
| return static_cast<int8_t>(bc[1]); | |
| } | |
| } | |
| DART_FORCE_INLINE static uint32_t DecodeE(const KBCInstr* bc) { | |
| if (IsWide(bc)) { | |
| return static_cast<uint32_t>(bc[2]) | | |
| (static_cast<uint32_t>(bc[3]) << 8) | | |
| (static_cast<uint32_t>(bc[4]) << 16) | | |
| (static_cast<uint32_t>(bc[5]) << 24); | |
| } else { | |
| return bc[2]; | |
| } | |
| } | |
| DART_FORCE_INLINE static int32_t DecodeY(const KBCInstr* bc) { | |
| if (IsWide(bc)) { | |
| return static_cast<int32_t>(static_cast<uint32_t>(bc[2]) | | |
| (static_cast<uint32_t>(bc[3]) << 8) | | |
| (static_cast<uint32_t>(bc[4]) << 16) | | |
| (static_cast<uint32_t>(bc[5]) << 24)); | |
| } else { | |
| return static_cast<int8_t>(bc[2]); | |
| } | |
| } | |
| DART_FORCE_INLINE static uint8_t DecodeF(const KBCInstr* bc) { | |
| if (IsWide(bc)) { | |
| return bc[5]; | |
| } else { | |
| return bc[2]; | |
| } | |
| } | |
| DART_FORCE_INLINE static Opcode DecodeOpcode(const KBCInstr* bc) { | |
| return static_cast<Opcode>(bc[0]); | |
| } | |
| DART_FORCE_INLINE static const KBCInstr* Next(const KBCInstr* bc) { | |
| return bc + kInstructionSize[DecodeOpcode(bc)]; | |
| } | |
| DART_FORCE_INLINE static uword Next(uword pc) { | |
| return pc + kInstructionSize[DecodeOpcode( | |
| reinterpret_cast<const KBCInstr*>(pc))]; | |
| } | |
| DART_FORCE_INLINE static bool IsLoadConstantOpcode(const KBCInstr* instr) { | |
| switch (DecodeOpcode(instr)) { | |
| case KernelBytecode::kLoadConstant: | |
| case KernelBytecode::kLoadConstant_Wide: | |
| return true; | |
| default: | |
| return false; | |
| } | |
| } | |
| DART_FORCE_INLINE static bool IsCheckStackOpcode(const KBCInstr* instr) { | |
| return DecodeOpcode(instr) == KernelBytecode::kCheckStack; | |
| } | |
| DART_FORCE_INLINE static bool IsCheckFunctionTypeArgs(const KBCInstr* instr) { | |
| switch (DecodeOpcode(instr)) { | |
| case KernelBytecode::kCheckFunctionTypeArgs: | |
| case KernelBytecode::kCheckFunctionTypeArgs_Wide: | |
| return true; | |
| default: | |
| return false; | |
| } | |
| } | |
| DART_FORCE_INLINE static bool IsEntryOpcode(const KBCInstr* instr) { | |
| switch (DecodeOpcode(instr)) { | |
| case KernelBytecode::kEntry: | |
| case KernelBytecode::kEntry_Wide: | |
| return true; | |
| default: | |
| return false; | |
| } | |
| } | |
| DART_FORCE_INLINE static bool IsEntryOptionalOpcode(const KBCInstr* instr) { | |
| return DecodeOpcode(instr) == KernelBytecode::kEntryOptional; | |
| } | |
| DART_FORCE_INLINE static bool IsFrameOpcode(const KBCInstr* instr) { | |
| switch (DecodeOpcode(instr)) { | |
| case KernelBytecode::kFrame: | |
| case KernelBytecode::kFrame_Wide: | |
| return true; | |
| default: | |
| return false; | |
| } | |
| } | |
| DART_FORCE_INLINE static bool IsSetFrameOpcode(const KBCInstr* instr) { | |
| return DecodeOpcode(instr) == KernelBytecode::kSetFrame; | |
| } | |
| DART_FORCE_INLINE static bool IsDirectCallOpcode(const KBCInstr* instr) { | |
| switch (DecodeOpcode(instr)) { | |
| case KernelBytecode::kDirectCall: | |
| case KernelBytecode::kDirectCall_Wide: | |
| case KernelBytecode::kUncheckedDirectCall: | |
| case KernelBytecode::kUncheckedDirectCall_Wide: | |
| return true; | |
| default: | |
| return false; | |
| } | |
| } | |
| DART_FORCE_INLINE static bool IsReturnOpcode(const KBCInstr* instr) { | |
| return DecodeOpcode(instr) == KernelBytecode::kReturnTOS; | |
| } | |
| DART_FORCE_INLINE static bool IsStackManipulationOpcode( | |
| const KBCInstr* instr) { | |
| switch (DecodeOpcode(instr)) { | |
| case KernelBytecode::kDrop1: | |
| case KernelBytecode::kDup: | |
| return true; | |
| default: | |
| return false; | |
| } | |
| } | |
| DART_FORCE_INLINE static uint8_t DecodeArgc(const KBCInstr* ret_addr) { | |
| // All call instructions have DF encoding, with argc being the last byte | |
| // regardless of whether the wide variant is used or not. | |
| return ret_addr[-1]; | |
| } | |
| // Converts bytecode PC into an offset. | |
| // For return addresses used in PcDescriptors, PC is also augmented by 1. | |
| // TODO(regis): Eliminate this correction. | |
| static intptr_t BytecodePcToOffset(uint32_t pc, bool is_return_address) { | |
| return pc + (is_return_address ? 1 : 0); | |
| } | |
| static uint32_t OffsetToBytecodePc(intptr_t offset, bool is_return_address) { | |
| return offset - (is_return_address ? 1 : 0); | |
| } | |
| static void GetVMInternalBytecodeInstructions(Opcode opcode, | |
| const KBCInstr** instructions, | |
| intptr_t* instructions_size); | |
| static Opcode BreakpointOpcode(Opcode opcode) { | |
| Opcode replacement; | |
| switch (kInstructionSize[opcode]) { | |
| case 1: | |
| replacement = kVMInternal_Breakpoint_0; | |
| break; | |
| case 2: | |
| replacement = kVMInternal_Breakpoint_D; | |
| break; | |
| case 3: | |
| replacement = kVMInternal_Breakpoint_A_E; | |
| break; | |
| case 4: | |
| replacement = kVMInternal_Breakpoint_A_B_C; | |
| break; | |
| case 5: | |
| replacement = kVMInternal_Breakpoint_D_Wide; | |
| break; | |
| case 6: | |
| replacement = kVMInternal_Breakpoint_A_E_Wide; | |
| break; | |
| default: | |
| UNREACHABLE(); | |
| return kTrap; | |
| } | |
| ASSERT_EQUAL(kInstructionSize[replacement], kInstructionSize[opcode]); | |
| return replacement; | |
| } | |
| static Opcode BreakpointOpcode(const KBCInstr* instr) { | |
| return BreakpointOpcode(DecodeOpcode(instr)); | |
| } | |
| private: | |
| friend class Interpreter; // for IsWide(Opcode) in static_asserts. | |
| DISALLOW_ALLOCATION(); | |
| DISALLOW_IMPLICIT_CONSTRUCTORS(KernelBytecode); | |
| }; | |
| } // namespace dart | |
| #endif // RUNTIME_VM_CONSTANTS_KBC_H_ |