text: // Copyright (c) 2018, 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
  // List of KernelBytecode instructions.
  //
  // INTERPRETER STATE
  //
  //      current frame info (see stack_frame_kbc.h for layout)
  //        v-----^-----v
  //   ~----+----~ ~----+-------+-------+-~ ~-+-------+-------+-~
  //   ~    |    ~ ~    | FP[0] | FP[1] | ~ ~ | SP[-1]| SP[0] |
  //   ~----+----~ ~----+-------+-------+-~ ~-+-------+-------+-~
  //                    ^                             ^
  //                    FP                            SP
  //
  //
  // The state of execution is captured in few interpreter registers:
  //
  //   FP - base of the current frame
  //   SP - top of the stack (TOS) for the current frame
  //   PP - object pool for the currently execution function
  //
  // Frame info stored below FP additionally contains pointers to the currently
  // executing function and code.
  //
  // In the unoptimized code most of bytecodes take operands implicitly from
  // stack and store results again on the stack. Constant operands are usually
  // taken from the object pool by index.
  //
  // ENCODING
  //
  // Each instruction starts with opcode byte. Certain instructions have
  // wide encoding variant. In such case, the least significant bit of opcode is
  // not set for compact variant and set for wide variant.
  //
  // The following operand encodings are used:
  //
  //   0........8.......16.......24.......32.......40.......48
  //   +--------+
  //   | opcode |                              0: no operands
  //   +--------+
  //
  //   +--------+--------+
  //   | opcode |    A   |                     A: unsigned 8-bit operand
  //   +--------+--------+
  //
  //   +--------+--------+
  //   | opcode |   D    |                     D: unsigned 8/32-bit operand
  //   +--------+--------+
  //
  //   +--------+----------------------------------+
  //   | opcode |                D                 |            D (wide)
  //   +--------+----------------------------------+
  //
  //   +--------+--------+
  //   | opcode |   X    |                     X: signed 8/32-bit operand
  //   +--------+--------+
  //
  //   +--------+----------------------------------+
  //   | opcode |                X                 |            X (wide)
  //   +--------+----------------------------------+
  //
  //   +--------+--------+
  //   | opcode |    T   |                     T: signed 8/24-bit operand
  //   +--------+--------+
  //
  //   +--------+--------------------------+
  //   | opcode |            T             |   T (wide)
  //   +--------+--------------------------+
  //
  //   +--------+--------+--------+
  //   | opcode |    A   |   E    |            A_E: unsigned 8-bit operand and
  //   +--------+--------+--------+                 unsigned 8/32-bit operand
  //
  //   +--------+--------+----------------------------------+
  //   | opcode |    A   |                 E                |   A_E (wide)
  //   +--------+--------+----------------------------------+
  //
  //   +--------+--------+--------+
  //   | opcode |    A   |   Y    |            A_Y: unsigned 8-bit operand and
  //   +--------+--------+--------+                 signed 8/32-bit operand
  //
  //   +--------+--------+----------------------------------+
  //   | opcode |    A   |                 Y                |   A_Y (wide)
  //   +--------+--------+----------------------------------+
  //
  //   +--------+--------+--------+
  //   | opcode |    D   |   F    |            D_F: unsigned 8/32-bit operand and
  //   +--------+--------+--------+                 unsigned 8-bit operand
  //
  //   +--------+----------------------------------+--------+
  //   | opcode |                 D                |    F   |   D_F (wide)
  //   +--------+----------------------------------+--------+
  //
  //   +--------+--------+--------+--------+
  //   | opcode |    A   |    B   |    C   |   A_B_C: 3 unsigned 8-bit operands
  //   +--------+--------+--------+--------+
  //
  //
  // INSTRUCTIONS
  //
  //  - Trap
  //
  //    Unreachable instruction.
  //
  //  - Entry rD
  //
  //    Function prologue for the function
  //        rD - number of local slots to reserve;
  //
  //  - EntryFixed A, D
  //
  //    Function prologue for functions without optional arguments.
  //    Checks number of arguments.
  //        A - expected number of positional arguments;
  //        D - number of local slots to reserve;
  //
  //  - EntryOptional A, B, C
  //
  //    Function prologue for the function with optional or named arguments:
  //        A - expected number of positional arguments;
  //        B - number of optional arguments;
  //        C - number of named arguments;
  //
  //    Only one of B and C can be not 0.
  //
  //    If B is not 0 then EntryOptional bytecode is followed by B LoadConstant
  //    bytecodes specifying default values for optional arguments.
  //
  //    If C is not 0 then EntryOptional is followed by 2 * C LoadConstant
  //    bytecodes.
  //    Bytecode at 2 * i specifies name of the i-th named argument and at
  //    2 * i + 1 default value. rA part of the LoadConstant bytecode specifies
  //    the location of the parameter on the stack. Here named arguments are
  //    sorted alphabetically to enable linear matching similar to how function
  //    prologues are implemented on other architectures.
  //
  //    Note: Unlike Entry bytecode EntryOptional does not setup the frame for
  //    local variables this is done by a separate bytecode Frame, which should
  //    follow EntryOptional and its LoadConstant instructions.
  //
  //  - LoadConstant rA, D
  //
  //    Used in conjunction with EntryOptional instruction to describe names and
  //    default values of optional parameters.
  //
  //  - Frame D
  //
  //    Reserve and initialize with null space for D local variables.
  //
  //  - CheckFunctionTypeArgs A, D
  //
  //    Check for a passed-in type argument vector of length A and
  //    store it at FP[D].
  //
  //  - CheckStack A
  //
  //    Compare SP against isolate stack limit and call StackOverflow handler if
  //    necessary. Should be used in prologue (A = 0), or at the beginning of
  //    a loop with depth A.
  //
  //  - Allocate D
  //
  //    Allocate object of class PP[D] with no type arguments.
  //
  //  - AllocateT
  //
  //    Allocate object of class SP[0] with type arguments SP[-1].
  //
  //  - CreateArrayTOS
  //
  //    Allocate array of length SP[0] with type arguments SP[-1].
  //
  //  - AllocateContext A, D
  //
  //    Allocate Context object holding D context variables.
  //    A is a static ID of the context. Static ID of a context may be used to
  //    disambiguate accesses to different context objects.
  //    Context objects with the same ID should have the same number of
  //    context variables.
  //
  //  - CloneContext A, D
  //
  //    Clone Context object SP[0] holding D context variables.
  //    A is a static ID of the context. Cloned context has the same ID.
  //
  //  - LoadContextParent
  //
  //    Load parent from context SP[0].
  //
  //  - StoreContextParent
  //
  //    Store context SP[0] into `parent` field of context SP[-1].
  //
  //  - LoadContextVar A, D
  //
  //    Load value from context SP[0] at index D.
  //    A is a static ID of the context.
  //
  //  - StoreContextVar A, D
  //
  //    Store value SP[0] into context SP[-1] at index D.
  //    A is a static ID of the context.
  //
  //  - PushConstant D
  //
  //    Push value at index D from constant pool onto the stack.
  //
  //  - PushNull
  //
  //    Push `null` onto the stack.
  //
  //  - PushTrue
  //
  //    Push `true` onto the stack.
  //
  //  - PushFalse
  //
  //    Push `false` onto the stack.
  //
  //  - PushInt rX
  //
  //    Push int rX onto the stack.
  //
  //  - Drop1
  //
  //    Drop 1 value from the stack
  //
  //  - Push rX
  //
  //    Push FP[rX] to the stack.
  //
  //  - StoreLocal rX; PopLocal rX
  //
  //    Store top of the stack into FP[rX] and pop it if needed.
  //
  //  - LoadFieldTOS D
  //
  //    Push value at offset (in words) PP[D] from object SP[0].
  //
  //  - StoreFieldTOS D
  //
  //    Store value SP[0] into object SP[-1] at offset (in words) PP[D].
  //
  //  - StoreIndexedTOS
  //
  //    Store SP[0] into array SP[-2] at index SP[-1]. No typechecking is done.
  //    SP[-2] is assumed to be a RawArray, SP[-1] to be a smi.
  //
  //  - PushStatic D
  //
  //    Pushes value of the static field PP[D] on to the stack.
  //
  //  - StoreStaticTOS D
  //
  //    Stores TOS into the static field PP[D].
  //
  //  - Jump target
  //
  //    Jump to the given target. Target is specified as offset from the PC of the
  //    jump instruction.
  //
  //  - JumpIfNoAsserts target
  //
  //    Jump to the given target if assertions are not enabled.
  //    Target is specified as offset from the PC of the jump instruction.
  //
  //  - JumpIfNotZeroTypeArgs target
  //
  //    Jump to the given target if number of passed function type
  //    arguments is not zero.
  //    Target is specified as offset from the PC of the jump instruction.
  //
  //  - JumpIfEqStrict target; JumpIfNeStrict target
  //
  //    Jump to the given target if SP[-1] is the same (JumpIfEqStrict) /
  //    not the same (JumpIfNeStrict) object as SP[0].
  //
  //  - JumpIfTrue target; JumpIfFalse target
  //  - JumpIfNull target; JumpIfNotNull target
  //
  //    Jump to the given target if SP[0] is true/false/null/not null.
  //
  //  - IndirectStaticCall ArgC, D
  //
  //    Invoke the function given by the ICData in SP[0] with arguments
  //    SP[-(1+ArgC)], ..., SP[-1] and argument descriptor PP[D], which
  //    indicates whether the first argument is a type argument vector.
  //
  //  - DirectCall ArgC, D
  //
  //    Invoke the function PP[D] with arguments
  //    SP[-(ArgC-1)], ..., SP[0] and argument descriptor PP[D+1].
  //
  //  - InterfaceCall ArgC, D
  //
  //    Lookup and invoke method using ICData in PP[D]
  //    with arguments SP[-(1+ArgC)], ..., SP[-1].
  //    Method has to be declared (explicitly or implicitly) in an interface
  //    implemented by a receiver, and passed arguments are valid for the
  //    interface method declaration.
  //    The ICData indicates whether the first argument is a type argument vector.
  //
  //  - UncheckedInterfaceCall ArgC, D
  //
  //    Same as InterfaceCall, but can omit type checks of generic-covariant
  //    parameters.
  //
  //  - DynamicCall ArgC, D
  //
  //    Lookup and invoke method using ICData in PP[D]
  //    with arguments SP[-(1+ArgC)], ..., SP[-1].
  //    The ICData indicates whether the first argument is a type argument vector.
  //
  //  - NativeCall D
  //
  //    Invoke native function described by array at pool[D].
  //    array[0] is wrapper, array[1] is function, array[2] is argc_tag.
  //
  //  - ReturnTOS
  //
  //    Return to the caller using a value from the top-of-stack as a result.
  //
  //    Note: return instruction knows how many arguments to remove from the
  //    stack because it can look at the call instruction at caller's PC and
  //    take argument count from it.
  //
  //  - AssertAssignable A, D
  //
  //    Assert that instance SP[-4] is assignable to variable named SP[0] of
  //    type SP[-1] with instantiator type arguments SP[-3] and function type
  //    arguments SP[-2] using SubtypeTestCache PP[D].
  //    If A is 1, then the instance may be a Smi.
  //
  //    Instance remains on stack. Other arguments are consumed.
  //
  //  - AssertBoolean A
  //
  //    Assert that TOS is a boolean (A = 1) or that TOS is not null (A = 0).
  //
  //  - AssertSubtype
  //
  //    Assert that one type is a subtype of another.  Throws a TypeError
  //    otherwise.  The stack has the following arguments on it:
  //
  //        SP[-4]  instantiator type args
  //        SP[-3]  function type args
  //        SP[-2]  sub_type
  //        SP[-1]  super_type
  //        SP[-0]  dst_name
  //
  //    All 5 arguments are consumed from the stack and no results is pushed.
  //
  //  - LoadTypeArgumentsField D
  //
  //    Load instantiator type arguments from an instance SP[0].
  //    PP[D] = offset (in words) of type arguments field corresponding
  //    to an instance's class.
  //
  //  - InstantiateType D
  //
  //    Instantiate type PP[D] with instantiator type arguments SP[-1] and
  //    function type arguments SP[0].
  //
  //  - InstantiateTypeArgumentsTOS A, D
  //
  //    Instantiate type arguments PP[D] with instantiator type arguments SP[-1]
  //    and function type arguments SP[0]. A != 0 indicates that resulting type
  //    arguments are all dynamic if both instantiator and function type
  //    arguments are all dynamic.
  //
  //  - Throw A
  //
  //    Throw (Rethrow if A != 0) exception. Exception object and stack object
  //    are taken from TOS.
  //
  //  - MoveSpecial A, rX
  //
  //    Copy value from special variable to FP[rX]. Currently only
  //    used to pass exception object (A = 0) and stack trace object (A = 1) to
  //    catch handler.
  //
  //  - SetFrame A
  //
  //    Reinitialize SP assuming that current frame has size A.
  //    Used to drop temporaries from the stack in the exception handler.
  //
  //  - BooleanNegateTOS
  //
  //    SP[0] = !SP[0]
  //
  //  - EqualsNull
  //
  //    SP[0] = (SP[0] == null) ? true : false
  //
  //  - NegateInt
  //
  //    Equivalent to invocation of unary int operator-.
  //    Receiver should have static type int.
  //    Check SP[0] for null; SP[0] = -SP[0].
  //
  //  - AddInt; SubInt; MulInt; TruncDivInt; ModInt; BitAndInt; BitOrInt;
  //    BitXorInt; ShlInt; ShrInt
  //
  //    Equivalent to invocation of binary int operator +, -, *, ~/, %, &, |,
  //    ^, << or >>. Receiver and argument should have static type int.
  //    Check SP[-1] and SP[0] for null; push SP[-1] <op> SP[0].
  //
  //  - CompareIntEq; CompareIntGt; CompareIntLt; CompareIntGe; CompareIntLe
  //
  //    Equivalent to invocation of binary int operator ==, >, <, >= or <=.
  //    Receiver and argument should have static type int.
  //    Check SP[-1] and SP[0] for null; push SP[-1] <op> SP[0] ? true : false.
  //
  //  - NegateDouble
  //
  //    Equivalent to invocation of unary double operator-.
  //    Receiver should have static type double.
  //    Check SP[0] for null; SP[0] = -SP[0].
  //
  //  - AddDouble; SubDouble; MulDouble; DivDouble
  //
  //    Equivalent to invocation of binary int operator +, -, *, /.
  //    Receiver and argument should have static type double.
  //    Check SP[-1] and SP[0] for null; push SP[-1] <op> SP[0].
  //
  //  - CompareDoubleEq; CompareDoubleGt; CompareDoubleLt; CompareDoubleGe;
  //    CompareDoubleLe
  //
  //    Equivalent to invocation of binary double operator ==, >, <, >= or <=.
  //    Receiver and argument should have static type double.
  //    Check SP[-1] and SP[0] for null; push SP[-1] <op> SP[0] ? true : false.
  //
  //  - AllocateClosure D
  //
  //    Allocate closure object for closure function ConstantPool[D].
  //
  // BYTECODE LIST FORMAT
  //
  // KernelBytecode list below is 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 (see ENCODING section above).
  //
  // - 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(UnusedOpcode000,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode001,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode002,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode003,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode004,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode005,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode006,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode007,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode008,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode009,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode010,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode011,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode012,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode013,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode014,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode015,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode016,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode017,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode018,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode019,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode020,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode021,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode022,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode023,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode024,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode025,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode026,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode027,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode028,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode029,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode030,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode031,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode032,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode033,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode034,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode035,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode036,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode037,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode038,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode039,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode040,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode041,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode042,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode043,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode044,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode045,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode046,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode047,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode048,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode049,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode050,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode051,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode052,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode053,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode054,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode055,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode056,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode057,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode058,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode059,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode060,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode061,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode062,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode063,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode064,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode065,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode066,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode067,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode068,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode069,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode070,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode071,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode072,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode073,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode074,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode075,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode076,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode077,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode078,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode079,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode080,                       0, RESV, ___, ___, ___)             \
    V(UnusedOpcode081,                       0, RESV, ___, ___, ___)             \
    V(JumpIfInitialized,                     T, ORDN, tgt, ___, ___)             \
    V(JumpIfInitialized_Wide,                T, WIDE, tgt, ___, ___)             \
    V(PushUninitializedSentinel,             0, ORDN, ___, ___, ___)             \
    V(Trap,                                  0, ORDN, ___, ___, ___)             \
    V(Entry,                                 D, ORDN, num, ___, ___)             \
    V(Entry_Wide,                            D, WIDE, num, ___, ___)             \
    V(EntryFixed,                          A_E, ORDN, num, num, ___)             \
    V(EntryFixed_Wide,                     A_E, WIDE, num, num, ___)             \
    V(EntryOptional,                     A_B_C, ORDN, num, num, num)             \
    V(Unused00,                              0, RESV, ___, ___, ___)             \
    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(DebugCheck,                            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(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(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(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(Unused23,                              0, RESV, ___, ___, ___)             \
    V(Unused24,                              0, RESV, ___, ___, ___)             \
    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(NativeCall,                            D, ORDN, lit, ___, ___)             \
    V(NativeCall_Wide,                       D, WIDE, lit, ___, ___)             \
    V(ReturnTOS,                             0, ORDN, ___, ___, ___)             \
    V(Unused29,                              0, RESV, ___, ___, ___)             \
    V(AssertAssignable,                    A_E, ORDN, num, lit, ___)             \
    V(AssertAssignable_Wide,               A_E, WIDE, num, lit, ___)             \
    V(Unused30,                              0, RESV, ___, ___, ___)             \
    V(Unused31,                              0, RESV, ___, ___, ___)             \
    V(AssertBoolean,                         A, ORDN, num, ___, ___)             \
    V(AssertSubtype,                         0, ORDN, ___, ___, ___)             \
    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, ___, ___, ___)             \
  
    // These bytecodes are only generated within the VM. Reassigning their
    // opcodes is not a breaking change.
  #define INTERNAL_KERNEL_BYTECODES_LIST(V)                                      \
    V(VMInternal_ImplicitGetter,             0, ORDN, ___, ___, ___)             \
    V(VMInternal_ImplicitSetter,             0, ORDN, ___, ___, ___)             \
    V(VMInternal_ImplicitStaticGetter,       0, ORDN, ___, ___, ___)             \
    V(VMInternal_MethodExtractor,            0, ORDN, ___, ___, ___)             \
    V(VMInternal_InvokeClosure,              0, ORDN, ___, ___, ___)             \
    V(VMInternal_InvokeField,                0, ORDN, ___, ___, ___)             \
    V(VMInternal_ForwardDynamicInvocation,   0, ORDN, ___, ___, ___)             \
    V(VMInternal_NoSuchMethodDispatcher,     0, ORDN, ___, ___, ___)             \
    V(VMInternal_ImplicitStaticClosure,      0, ORDN, ___, ___, ___)             \
    V(VMInternal_ImplicitInstanceClosure,    0, ORDN, ___, ___, ___)             \
  
  #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 = 0x44424332;  // 'DBC2'
    // Minimum bytecode format version supported by VM.
    static const intptr_t kMinSupportedBytecodeFormatVersion = 28;
    // Maximum bytecode format version supported by VM.
    // The range of supported versions should include version produced by bytecode
    // generator (currentBytecodeFormatVersion in pkg/vm/lib/bytecode/dbc.dart).
    static const intptr_t kMaxSupportedBytecodeFormatVersion = 28;
  
    enum Opcode {
  #define DECLARE_BYTECODE(name, encoding, kind, op1, op2, op3) k##name,
      KERNEL_BYTECODES_LIST(DECLARE_BYTECODE)
  #undef DECLARE_BYTECODE
    };
  
    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 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 ((DecodeOpcode(instr) & 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 IsJumpOpcode(const KBCInstr* instr) {
      switch (DecodeOpcode(instr)) {
        case KernelBytecode::kJump:
        case KernelBytecode::kJump_Wide:
        case KernelBytecode::kJumpIfNoAsserts:
        case KernelBytecode::kJumpIfNoAsserts_Wide:
        case KernelBytecode::kJumpIfNotZeroTypeArgs:
        case KernelBytecode::kJumpIfNotZeroTypeArgs_Wide:
        case KernelBytecode::kJumpIfEqStrict:
        case KernelBytecode::kJumpIfEqStrict_Wide:
        case KernelBytecode::kJumpIfNeStrict:
        case KernelBytecode::kJumpIfNeStrict_Wide:
        case KernelBytecode::kJumpIfTrue:
        case KernelBytecode::kJumpIfTrue_Wide:
        case KernelBytecode::kJumpIfFalse:
        case KernelBytecode::kJumpIfFalse_Wide:
        case KernelBytecode::kJumpIfNull:
        case KernelBytecode::kJumpIfNull_Wide:
        case KernelBytecode::kJumpIfNotNull:
        case KernelBytecode::kJumpIfNotNull_Wide:
        case KernelBytecode::kJumpIfUnchecked:
        case KernelBytecode::kJumpIfUnchecked_Wide:
        case KernelBytecode::kJumpIfInitialized:
        case KernelBytecode::kJumpIfInitialized_Wide:
          return true;
  
        default:
          return false;
      }
    }
  
    DART_FORCE_INLINE static bool IsJumpIfUncheckedOpcode(const KBCInstr* instr) {
      switch (DecodeOpcode(instr)) {
        case KernelBytecode::kJumpIfUnchecked:
        case KernelBytecode::kJumpIfUnchecked_Wide:
          return true;
        default:
          return false;
      }
    }
  
    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 IsEntryFixedOpcode(const KBCInstr* instr) {
      switch (DecodeOpcode(instr)) {
        case KernelBytecode::kEntryFixed:
        case KernelBytecode::kEntryFixed_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 IsNativeCallOpcode(const KBCInstr* instr) {
      switch (DecodeOpcode(instr)) {
        case KernelBytecode::kNativeCall:
        case KernelBytecode::kNativeCall_Wide:
          return true;
        default:
          return false;
      }
    }
  
    DART_FORCE_INLINE static bool IsDebugCheckOpcode(const KBCInstr* instr) {
      return DecodeOpcode(instr) == KernelBytecode::kDebugCheck;
    }
  
    // The interpreter, the bytecode generator, the bytecode compiler, and this
    // function must agree on this list of opcodes.
    // For each instruction with listed opcode:
    // - The interpreter checks for a debug break.
    // - The bytecode generator emits a source position.
    // - The bytecode compiler may emit a DebugStepCheck call.
    DART_FORCE_INLINE static bool IsDebugCheckedOpcode(const KBCInstr* instr) {
      switch (DecodeOpcode(instr)) {
        case KernelBytecode::kDebugCheck:
        case KernelBytecode::kDirectCall:
        case KernelBytecode::kDirectCall_Wide:
        case KernelBytecode::kUncheckedDirectCall:
        case KernelBytecode::kUncheckedDirectCall_Wide:
        case KernelBytecode::kInterfaceCall:
        case KernelBytecode::kInterfaceCall_Wide:
        case KernelBytecode::kInstantiatedInterfaceCall:
        case KernelBytecode::kInstantiatedInterfaceCall_Wide:
        case KernelBytecode::kUncheckedClosureCall:
        case KernelBytecode::kUncheckedClosureCall_Wide:
        case KernelBytecode::kUncheckedInterfaceCall:
        case KernelBytecode::kUncheckedInterfaceCall_Wide:
        case KernelBytecode::kDynamicCall:
        case KernelBytecode::kDynamicCall_Wide:
        case KernelBytecode::kReturnTOS:
        case KernelBytecode::kEqualsNull:
        case KernelBytecode::kNegateInt:
        case KernelBytecode::kNegateDouble:
        case KernelBytecode::kAddInt:
        case KernelBytecode::kSubInt:
        case KernelBytecode::kMulInt:
        case KernelBytecode::kTruncDivInt:
        case KernelBytecode::kModInt:
        case KernelBytecode::kBitAndInt:
        case KernelBytecode::kBitOrInt:
        case KernelBytecode::kBitXorInt:
        case KernelBytecode::kShlInt:
        case KernelBytecode::kShrInt:
        case KernelBytecode::kCompareIntEq:
        case KernelBytecode::kCompareIntGt:
        case KernelBytecode::kCompareIntLt:
        case KernelBytecode::kCompareIntGe:
        case KernelBytecode::kCompareIntLe:
        case KernelBytecode::kAddDouble:
        case KernelBytecode::kSubDouble:
        case KernelBytecode::kMulDouble:
        case KernelBytecode::kDivDouble:
        case KernelBytecode::kCompareDoubleEq:
        case KernelBytecode::kCompareDoubleGt:
        case KernelBytecode::kCompareDoubleLt:
        case KernelBytecode::kCompareDoubleGe:
        case KernelBytecode::kCompareDoubleLe:
          return true;
        default:
          return false;
      }
    }
  
    static const uint8_t kNativeCallToGrowableListArgc = 2;
  
    // Returns a fake return address which points after the 2-argument
    // bytecode call, followed by ReturnTOS instructions.
    static const KBCInstr* GetNativeCallToGrowableListReturnTrampoline();
  
    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);
  
   private:
    DISALLOW_ALLOCATION();
    DISALLOW_IMPLICIT_CONSTRUCTORS(KernelBytecode);
  };
  
  }  // namespace dart
  
  #endif  // RUNTIME_VM_CONSTANTS_KBC_H_
  