void BytecodeInterpreter::run()

in src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp [488:3201]


void BytecodeInterpreter::run(interpreterState istate) {
  intptr_t*        topOfStack = (intptr_t *)istate->stack(); /* access with STACK macros */
  address          pc = istate->bcp();
  jubyte opcode;
  intptr_t*        locals = istate->locals();
  ConstantPoolCache*    cp = istate->constants(); // method()->constants()->cache()
#ifdef LOTS_OF_REGS
  JavaThread*      THREAD = istate->thread();
#else
#undef THREAD
#define THREAD istate->thread()
#endif

#ifdef ASSERT
  assert(labs(istate->stack_base() - istate->stack_limit()) == (istate->method()->max_stack() + 1),
         "Bad stack limit");
  /* QQQ this should be a stack method so we don't know actual direction */
  assert(topOfStack >= istate->stack_limit() && topOfStack < istate->stack_base(),
         "Stack top out of range");

  // Verify linkages.
  interpreterState l = istate;
  do {
    assert(l == l->_self_link, "bad link");
    l = l->_prev_link;
  } while (l != nullptr);
  // Screwups with stack management usually cause us to overwrite istate
  // save a copy so we can verify it.
  interpreterState orig = istate;
#endif

#ifdef USELABELS
  const static void* const opclabels_data[256] = {
/* 0x00 */ &&opc_nop,           &&opc_aconst_null,      &&opc_iconst_m1,      &&opc_iconst_0,
/* 0x04 */ &&opc_iconst_1,      &&opc_iconst_2,         &&opc_iconst_3,       &&opc_iconst_4,
/* 0x08 */ &&opc_iconst_5,      &&opc_lconst_0,         &&opc_lconst_1,       &&opc_fconst_0,
/* 0x0C */ &&opc_fconst_1,      &&opc_fconst_2,         &&opc_dconst_0,       &&opc_dconst_1,

/* 0x10 */ &&opc_bipush,        &&opc_sipush,           &&opc_ldc,            &&opc_ldc_w,
/* 0x14 */ &&opc_ldc2_w,        &&opc_iload,            &&opc_lload,          &&opc_fload,
/* 0x18 */ &&opc_dload,         &&opc_aload,            &&opc_iload_0,        &&opc_iload_1,
/* 0x1C */ &&opc_iload_2,       &&opc_iload_3,          &&opc_lload_0,        &&opc_lload_1,

/* 0x20 */ &&opc_lload_2,       &&opc_lload_3,          &&opc_fload_0,        &&opc_fload_1,
/* 0x24 */ &&opc_fload_2,       &&opc_fload_3,          &&opc_dload_0,        &&opc_dload_1,
/* 0x28 */ &&opc_dload_2,       &&opc_dload_3,          &&opc_aload_0,        &&opc_aload_1,
/* 0x2C */ &&opc_aload_2,       &&opc_aload_3,          &&opc_iaload,         &&opc_laload,

/* 0x30 */ &&opc_faload,        &&opc_daload,           &&opc_aaload,         &&opc_baload,
/* 0x34 */ &&opc_caload,        &&opc_saload,           &&opc_istore,         &&opc_lstore,
/* 0x38 */ &&opc_fstore,        &&opc_dstore,           &&opc_astore,         &&opc_istore_0,
/* 0x3C */ &&opc_istore_1,      &&opc_istore_2,         &&opc_istore_3,       &&opc_lstore_0,

/* 0x40 */ &&opc_lstore_1,      &&opc_lstore_2,         &&opc_lstore_3,       &&opc_fstore_0,
/* 0x44 */ &&opc_fstore_1,      &&opc_fstore_2,         &&opc_fstore_3,       &&opc_dstore_0,
/* 0x48 */ &&opc_dstore_1,      &&opc_dstore_2,         &&opc_dstore_3,       &&opc_astore_0,
/* 0x4C */ &&opc_astore_1,      &&opc_astore_2,         &&opc_astore_3,       &&opc_iastore,

/* 0x50 */ &&opc_lastore,       &&opc_fastore,          &&opc_dastore,        &&opc_aastore,
/* 0x54 */ &&opc_bastore,       &&opc_castore,          &&opc_sastore,        &&opc_pop,
/* 0x58 */ &&opc_pop2,          &&opc_dup,              &&opc_dup_x1,         &&opc_dup_x2,
/* 0x5C */ &&opc_dup2,          &&opc_dup2_x1,          &&opc_dup2_x2,        &&opc_swap,

/* 0x60 */ &&opc_iadd,          &&opc_ladd,             &&opc_fadd,           &&opc_dadd,
/* 0x64 */ &&opc_isub,          &&opc_lsub,             &&opc_fsub,           &&opc_dsub,
/* 0x68 */ &&opc_imul,          &&opc_lmul,             &&opc_fmul,           &&opc_dmul,
/* 0x6C */ &&opc_idiv,          &&opc_ldiv,             &&opc_fdiv,           &&opc_ddiv,

/* 0x70 */ &&opc_irem,          &&opc_lrem,             &&opc_frem,           &&opc_drem,
/* 0x74 */ &&opc_ineg,          &&opc_lneg,             &&opc_fneg,           &&opc_dneg,
/* 0x78 */ &&opc_ishl,          &&opc_lshl,             &&opc_ishr,           &&opc_lshr,
/* 0x7C */ &&opc_iushr,         &&opc_lushr,            &&opc_iand,           &&opc_land,

/* 0x80 */ &&opc_ior,           &&opc_lor,              &&opc_ixor,           &&opc_lxor,
/* 0x84 */ &&opc_iinc,          &&opc_i2l,              &&opc_i2f,            &&opc_i2d,
/* 0x88 */ &&opc_l2i,           &&opc_l2f,              &&opc_l2d,            &&opc_f2i,
/* 0x8C */ &&opc_f2l,           &&opc_f2d,              &&opc_d2i,            &&opc_d2l,

/* 0x90 */ &&opc_d2f,           &&opc_i2b,              &&opc_i2c,            &&opc_i2s,
/* 0x94 */ &&opc_lcmp,          &&opc_fcmpl,            &&opc_fcmpg,          &&opc_dcmpl,
/* 0x98 */ &&opc_dcmpg,         &&opc_ifeq,             &&opc_ifne,           &&opc_iflt,
/* 0x9C */ &&opc_ifge,          &&opc_ifgt,             &&opc_ifle,           &&opc_if_icmpeq,

/* 0xA0 */ &&opc_if_icmpne,     &&opc_if_icmplt,        &&opc_if_icmpge,      &&opc_if_icmpgt,
/* 0xA4 */ &&opc_if_icmple,     &&opc_if_acmpeq,        &&opc_if_acmpne,      &&opc_goto,
/* 0xA8 */ &&opc_jsr,           &&opc_ret,              &&opc_tableswitch,    &&opc_lookupswitch,
/* 0xAC */ &&opc_ireturn,       &&opc_lreturn,          &&opc_freturn,        &&opc_dreturn,

/* 0xB0 */ &&opc_areturn,       &&opc_return,           &&opc_getstatic,      &&opc_putstatic,
/* 0xB4 */ &&opc_getfield,      &&opc_putfield,         &&opc_invokevirtual,  &&opc_invokespecial,
/* 0xB8 */ &&opc_invokestatic,  &&opc_invokeinterface,  &&opc_invokedynamic,  &&opc_new,
/* 0xBC */ &&opc_newarray,      &&opc_anewarray,        &&opc_arraylength,    &&opc_athrow,

/* 0xC0 */ &&opc_checkcast,     &&opc_instanceof,       &&opc_monitorenter,   &&opc_monitorexit,
/* 0xC4 */ &&opc_wide,          &&opc_multianewarray,   &&opc_ifnull,         &&opc_ifnonnull,
/* 0xC8 */ &&opc_goto_w,        &&opc_jsr_w,            &&opc_breakpoint,     &&opc_fast_agetfield,
/* 0xCC */ &&opc_fast_bgetfield,&&opc_fast_cgetfield,   &&opc_fast_dgetfield, &&opc_fast_fgetfield,

/* 0xD0 */ &&opc_fast_igetfield,&&opc_fast_lgetfield,   &&opc_fast_sgetfield, &&opc_fast_aputfield,
/* 0xD4 */ &&opc_fast_bputfield,&&opc_fast_zputfield,   &&opc_fast_cputfield, &&opc_fast_dputfield,
/* 0xD8 */ &&opc_fast_fputfield,&&opc_fast_iputfield,   &&opc_fast_lputfield, &&opc_fast_sputfield,
/* 0xDC */ &&opc_fast_aload_0,  &&opc_fast_iaccess_0,   &&opc_fast_aaccess_0, &&opc_fast_faccess_0,

/* 0xE0 */ &&opc_fast_iload,    &&opc_fast_iload2,      &&opc_fast_icaload,   &&opc_fast_invokevfinal,
/* 0xE4 */ &&opc_default,       &&opc_default,          &&opc_fast_aldc,      &&opc_fast_aldc_w,
/* 0xE8 */ &&opc_return_register_finalizer,
                                &&opc_invokehandle,     &&opc_nofast_getfield,&&opc_nofast_putfield,
/* 0xEC */ &&opc_nofast_aload_0,&&opc_nofast_iload,     &&opc_default,        &&opc_default,

/* 0xF0 */ &&opc_default,       &&opc_default,          &&opc_default,        &&opc_default,
/* 0xF4 */ &&opc_default,       &&opc_default,          &&opc_default,        &&opc_default,
/* 0xF8 */ &&opc_default,       &&opc_default,          &&opc_default,        &&opc_default,
/* 0xFC */ &&opc_default,       &&opc_default,          &&opc_default,        &&opc_default
  };
  uintptr_t *dispatch_table = (uintptr_t*)&opclabels_data[0];
#endif /* USELABELS */

  switch (istate->msg()) {
    case initialize: {
      ShouldNotCallThis();
      return;
    }
    case method_entry: {
      THREAD->set_do_not_unlock_if_synchronized(true);

      // Lock method if synchronized.
      if (METHOD->is_synchronized()) {
        // oop rcvr = locals[0].j.r;
        oop rcvr;
        if (METHOD->is_static()) {
          rcvr = METHOD->constants()->pool_holder()->java_mirror();
        } else {
          rcvr = LOCALS_OBJECT(0);
          VERIFY_OOP(rcvr);
        }

        // The initial monitor is ours for the taking.
        BasicObjectLock* mon = &istate->monitor_base()[-1];
        mon->set_obj(rcvr);
        CALL_VM(InterpreterRuntime::monitorenter(THREAD, mon), handle_exception);
      }
      THREAD->set_do_not_unlock_if_synchronized(false);

      // Notify jvmti.
      // Whenever JVMTI puts a thread in interp_only_mode, method
      // entry/exit events are sent for that thread to track stack depth.
      if (JVMTI_ENABLED && THREAD->is_interp_only_mode()) {
        CALL_VM(InterpreterRuntime::post_method_entry(THREAD),
                handle_exception);
      }

      goto run;
    }

    case popping_frame: {
      // returned from a java call to pop the frame, restart the call
      // clear the message so we don't confuse ourselves later
      assert(THREAD->pop_frame_in_process(), "wrong frame pop state");
      istate->set_msg(no_request);
      THREAD->clr_pop_frame_in_process();
      goto run;
    }

    case method_resume: {
      if ((istate->_stack_base - istate->_stack_limit) != istate->method()->max_stack() + 1) {
        // resume
        os::breakpoint();
      }
      // returned from a java call, continue executing.
      if (THREAD->has_pending_popframe() && !THREAD->pop_frame_in_process()) {
        goto handle_Pop_Frame;
      }
      if (THREAD->jvmti_thread_state() &&
          THREAD->jvmti_thread_state()->is_earlyret_pending()) {
        goto handle_Early_Return;
      }

      if (THREAD->has_pending_exception()) goto handle_exception;
      // Update the pc by the saved amount of the invoke bytecode size
      UPDATE_PC(istate->bcp_advance());
      goto run;
    }

    case deopt_resume2: {
      // Returned from an opcode that will reexecute. Deopt was
      // a result of a PopFrame request.
      //
      goto run;
    }

    case deopt_resume: {
      // Returned from an opcode that has completed. The stack has
      // the result all we need to do is skip across the bytecode
      // and continue (assuming there is no exception pending)
      //
      // compute continuation length
      //
      // Note: it is possible to deopt at a return_register_finalizer opcode
      // because this requires entering the vm to do the registering. While the
      // opcode is complete we can't advance because there are no more opcodes
      // much like trying to deopt at a poll return. In that has we simply
      // get out of here
      //
      if ( Bytecodes::code_at(METHOD, pc) == Bytecodes::_return_register_finalizer) {
        // this will do the right thing even if an exception is pending.
        goto handle_return;
      }
      UPDATE_PC(Bytecodes::length_at(METHOD, pc));
      if (THREAD->has_pending_exception()) goto handle_exception;
      goto run;
    }
    case got_monitors: {
      // continue locking now that we have a monitor to use
      // we expect to find newly allocated monitor at the "top" of the monitor stack.
      oop lockee = STACK_OBJECT(-1);
      VERIFY_OOP(lockee);
      // derefing's lockee ought to provoke implicit null check
      // find a free monitor
      BasicObjectLock* entry = (BasicObjectLock*) istate->stack_base();
      assert(entry->obj() == nullptr, "Frame manager didn't allocate the monitor");
      entry->set_obj(lockee);
      CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception);
      UPDATE_PC_AND_TOS(1, -1);
      goto run;
    }
    default: {
      fatal("Unexpected message from frame manager");
    }
  }

run:

  DO_UPDATE_INSTRUCTION_COUNT(*pc)
  DEBUGGER_SINGLE_STEP_NOTIFY();
#ifdef PREFETCH_OPCCODE
  opcode = *pc;  /* prefetch first opcode */
#endif

#ifndef USELABELS
  while (1)
#endif
  {
#ifndef PREFETCH_OPCCODE
      opcode = *pc;
#endif
      // Seems like this happens twice per opcode. At worst this is only
      // need at entry to the loop.
      // DEBUGGER_SINGLE_STEP_NOTIFY();
      /* Using this labels avoids double breakpoints when quickening and
       * when returning from transition frames.
       */
  opcode_switch:
      assert(istate == orig, "Corrupted istate");
      /* QQQ Hmm this has knowledge of direction, ought to be a stack method */
      assert(topOfStack >= istate->stack_limit(), "Stack overrun");
      assert(topOfStack < istate->stack_base(), "Stack underrun");

#ifdef USELABELS
      DISPATCH(opcode);
#else
      switch (opcode)
#endif
      {
      CASE(_nop):
          UPDATE_PC_AND_CONTINUE(1);

          /* Push miscellaneous constants onto the stack. */

      CASE(_aconst_null):
          SET_STACK_OBJECT(nullptr, 0);
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);

#undef  OPC_CONST_n
#define OPC_CONST_n(opcode, const_type, value)                          \
      CASE(opcode):                                                     \
          SET_STACK_ ## const_type(value, 0);                           \
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);

          OPC_CONST_n(_iconst_m1,   INT,       -1);
          OPC_CONST_n(_iconst_0,    INT,        0);
          OPC_CONST_n(_iconst_1,    INT,        1);
          OPC_CONST_n(_iconst_2,    INT,        2);
          OPC_CONST_n(_iconst_3,    INT,        3);
          OPC_CONST_n(_iconst_4,    INT,        4);
          OPC_CONST_n(_iconst_5,    INT,        5);
          OPC_CONST_n(_fconst_0,    FLOAT,      0.0);
          OPC_CONST_n(_fconst_1,    FLOAT,      1.0);
          OPC_CONST_n(_fconst_2,    FLOAT,      2.0);

#undef  OPC_CONST2_n
#define OPC_CONST2_n(opcname, value, key, kind)                         \
      CASE(_##opcname):                                                 \
      {                                                                 \
          SET_STACK_ ## kind(VM##key##Const##value(), 1);               \
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 2);                         \
      }
         OPC_CONST2_n(dconst_0, Zero, double, DOUBLE);
         OPC_CONST2_n(dconst_1, One,  double, DOUBLE);
         OPC_CONST2_n(lconst_0, Zero, long, LONG);
         OPC_CONST2_n(lconst_1, One,  long, LONG);

         /* Load constant from constant pool: */

          /* Push a 1-byte signed integer value onto the stack. */
      CASE(_bipush):
          SET_STACK_INT((jbyte)(pc[1]), 0);
          UPDATE_PC_AND_TOS_AND_CONTINUE(2, 1);

          /* Push a 2-byte signed integer constant onto the stack. */
      CASE(_sipush):
          SET_STACK_INT((int16_t)Bytes::get_Java_u2(pc + 1), 0);
          UPDATE_PC_AND_TOS_AND_CONTINUE(3, 1);

          /* load from local variable */

      CASE(_aload):
          VERIFY_OOP(LOCALS_OBJECT(pc[1]));
          SET_STACK_OBJECT(LOCALS_OBJECT(pc[1]), 0);
          UPDATE_PC_AND_TOS_AND_CONTINUE(2, 1);

      CASE(_iload):
      {
        if (REWRITE_BYTECODES) {
          // Attempt to rewrite iload, iload -> fast_iload2
          //                    iload, caload -> fast_icaload
          // Normal iloads will be rewritten to fast_iload to avoid checking again.
          switch (*(pc + 2)) {
            case Bytecodes::_fast_iload:
              REWRITE_AT_PC(Bytecodes::_fast_iload2);
              break;
            case Bytecodes::_caload:
              REWRITE_AT_PC(Bytecodes::_fast_icaload);
              break;
            case Bytecodes::_iload:
              // Wait until rewritten to _fast_iload.
              break;
            default:
              // Last iload in a (potential) series, don't check again.
              REWRITE_AT_PC(Bytecodes::_fast_iload);
          }
        }
        // Normal iload handling.
        SET_STACK_SLOT(LOCALS_SLOT(pc[1]), 0);
        UPDATE_PC_AND_TOS_AND_CONTINUE(2, 1);
      }

      CASE(_nofast_iload):
      {
        // Normal, non-rewritable iload handling.
        SET_STACK_SLOT(LOCALS_SLOT(pc[1]), 0);
        UPDATE_PC_AND_TOS_AND_CONTINUE(2, 1);
      }

      CASE(_fast_iload):
      CASE(_fload):
          SET_STACK_SLOT(LOCALS_SLOT(pc[1]), 0);
          UPDATE_PC_AND_TOS_AND_CONTINUE(2, 1);

      CASE(_fast_iload2):
          SET_STACK_SLOT(LOCALS_SLOT(pc[1]), 0);
          SET_STACK_SLOT(LOCALS_SLOT(pc[3]), 1);
          UPDATE_PC_AND_TOS_AND_CONTINUE(4, 2);

      CASE(_lload):
          SET_STACK_LONG_FROM_ADDR(LOCALS_LONG_AT(pc[1]), 1);
          UPDATE_PC_AND_TOS_AND_CONTINUE(2, 2);

      CASE(_dload):
          SET_STACK_DOUBLE_FROM_ADDR(LOCALS_DOUBLE_AT(pc[1]), 1);
          UPDATE_PC_AND_TOS_AND_CONTINUE(2, 2);

#undef  OPC_LOAD_n
#define OPC_LOAD_n(num)                                                 \
      CASE(_iload_##num):                                               \
      CASE(_fload_##num):                                               \
          SET_STACK_SLOT(LOCALS_SLOT(num), 0);                          \
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);                         \
                                                                        \
      CASE(_lload_##num):                                               \
          SET_STACK_LONG_FROM_ADDR(LOCALS_LONG_AT(num), 1);             \
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 2);                         \
      CASE(_dload_##num):                                               \
          SET_STACK_DOUBLE_FROM_ADDR(LOCALS_DOUBLE_AT(num), 1);         \
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 2);

      OPC_LOAD_n(0);
      OPC_LOAD_n(1);
      OPC_LOAD_n(2);
      OPC_LOAD_n(3);

#undef  OPC_ALOAD_n
#define OPC_ALOAD_n(num)                                                \
      CASE(_aload_##num): {                                             \
          oop obj = LOCALS_OBJECT(num);                                 \
          VERIFY_OOP(obj);                                              \
          SET_STACK_OBJECT(obj, 0);                                     \
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);                         \
      }

      CASE(_aload_0):
      {
        /* Maybe rewrite if following bytecode is one of the supported _fast_Xgetfield bytecodes. */
        if (REWRITE_BYTECODES) {
          switch (*(pc + 1)) {
            case Bytecodes::_fast_agetfield:
              REWRITE_AT_PC(Bytecodes::_fast_aaccess_0);
              break;
            case Bytecodes::_fast_fgetfield:
              REWRITE_AT_PC(Bytecodes::_fast_faccess_0);
              break;
            case Bytecodes::_fast_igetfield:
              REWRITE_AT_PC(Bytecodes::_fast_iaccess_0);
              break;
            case Bytecodes::_getfield:
            case Bytecodes::_nofast_getfield: {
              /* Otherwise, do nothing here, wait until/if it gets rewritten to _fast_Xgetfield.
               * Unfortunately, this punishes volatile field access, because it never gets
               * rewritten. */
              break;
            }
            default:
              REWRITE_AT_PC(Bytecodes::_fast_aload_0);
              break;
          }
        }
        // Normal aload_0 handling.
        VERIFY_OOP(LOCALS_OBJECT(0));
        SET_STACK_OBJECT(LOCALS_OBJECT(0), 0);
        UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);
      }

      CASE(_nofast_aload_0):
      {
        // Normal, non-rewritable aload_0 handling.
        VERIFY_OOP(LOCALS_OBJECT(0));
        SET_STACK_OBJECT(LOCALS_OBJECT(0), 0);
        UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);
      }

      OPC_ALOAD_n(1);
      OPC_ALOAD_n(2);
      OPC_ALOAD_n(3);

          /* store to a local variable */

      CASE(_astore):
          astore(topOfStack, -1, locals, pc[1]);
          UPDATE_PC_AND_TOS_AND_CONTINUE(2, -1);

      CASE(_istore):
      CASE(_fstore):
          SET_LOCALS_SLOT(STACK_SLOT(-1), pc[1]);
          UPDATE_PC_AND_TOS_AND_CONTINUE(2, -1);

      CASE(_lstore):
          SET_LOCALS_LONG(STACK_LONG(-1), pc[1]);
          UPDATE_PC_AND_TOS_AND_CONTINUE(2, -2);

      CASE(_dstore):
          SET_LOCALS_DOUBLE(STACK_DOUBLE(-1), pc[1]);
          UPDATE_PC_AND_TOS_AND_CONTINUE(2, -2);

      CASE(_wide): {
          uint16_t reg = Bytes::get_Java_u2(pc + 2);

          opcode = pc[1];

          // Wide and it's sub-bytecode are counted as separate instructions. If we
          // don't account for this here, the bytecode trace skips the next bytecode.
          DO_UPDATE_INSTRUCTION_COUNT(opcode);

          switch(opcode) {
              case Bytecodes::_aload:
                  VERIFY_OOP(LOCALS_OBJECT(reg));
                  SET_STACK_OBJECT(LOCALS_OBJECT(reg), 0);
                  UPDATE_PC_AND_TOS_AND_CONTINUE(4, 1);

              case Bytecodes::_iload:
              case Bytecodes::_fload:
                  SET_STACK_SLOT(LOCALS_SLOT(reg), 0);
                  UPDATE_PC_AND_TOS_AND_CONTINUE(4, 1);

              case Bytecodes::_lload:
                  SET_STACK_LONG_FROM_ADDR(LOCALS_LONG_AT(reg), 1);
                  UPDATE_PC_AND_TOS_AND_CONTINUE(4, 2);

              case Bytecodes::_dload:
                  SET_STACK_DOUBLE_FROM_ADDR(LOCALS_LONG_AT(reg), 1);
                  UPDATE_PC_AND_TOS_AND_CONTINUE(4, 2);

              case Bytecodes::_astore:
                  astore(topOfStack, -1, locals, reg);
                  UPDATE_PC_AND_TOS_AND_CONTINUE(4, -1);

              case Bytecodes::_istore:
              case Bytecodes::_fstore:
                  SET_LOCALS_SLOT(STACK_SLOT(-1), reg);
                  UPDATE_PC_AND_TOS_AND_CONTINUE(4, -1);

              case Bytecodes::_lstore:
                  SET_LOCALS_LONG(STACK_LONG(-1), reg);
                  UPDATE_PC_AND_TOS_AND_CONTINUE(4, -2);

              case Bytecodes::_dstore:
                  SET_LOCALS_DOUBLE(STACK_DOUBLE(-1), reg);
                  UPDATE_PC_AND_TOS_AND_CONTINUE(4, -2);

              case Bytecodes::_iinc: {
                  int16_t offset = (int16_t)Bytes::get_Java_u2(pc+4);
                  // Be nice to see what this generates.... QQQ
                  SET_LOCALS_INT(LOCALS_INT(reg) + offset, reg);
                  UPDATE_PC_AND_CONTINUE(6);
              }
              case Bytecodes::_ret:
                  pc = istate->method()->code_base() + (intptr_t)(LOCALS_ADDR(reg));
                  UPDATE_PC_AND_CONTINUE(0);
              default:
                  VM_JAVA_ERROR(vmSymbols::java_lang_InternalError(), "undefined opcode");
          }
      }


#undef  OPC_STORE_n
#define OPC_STORE_n(num)                                                \
      CASE(_astore_##num):                                              \
          astore(topOfStack, -1, locals, num);                          \
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1);                        \
      CASE(_istore_##num):                                              \
      CASE(_fstore_##num):                                              \
          SET_LOCALS_SLOT(STACK_SLOT(-1), num);                         \
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1);

          OPC_STORE_n(0);
          OPC_STORE_n(1);
          OPC_STORE_n(2);
          OPC_STORE_n(3);

#undef  OPC_DSTORE_n
#define OPC_DSTORE_n(num)                                               \
      CASE(_dstore_##num):                                              \
          SET_LOCALS_DOUBLE(STACK_DOUBLE(-1), num);                     \
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, -2);                        \
      CASE(_lstore_##num):                                              \
          SET_LOCALS_LONG(STACK_LONG(-1), num);                         \
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, -2);

          OPC_DSTORE_n(0);
          OPC_DSTORE_n(1);
          OPC_DSTORE_n(2);
          OPC_DSTORE_n(3);

          /* stack pop, dup, and insert opcodes */


      CASE(_pop):                /* Discard the top item on the stack */
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1);


      CASE(_pop2):               /* Discard the top 2 items on the stack */
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, -2);


      CASE(_dup):               /* Duplicate the top item on the stack */
          dup(topOfStack);
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);

      CASE(_dup2):              /* Duplicate the top 2 items on the stack */
          dup2(topOfStack);
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 2);

      CASE(_dup_x1):    /* insert top word two down */
          dup_x1(topOfStack);
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);

      CASE(_dup_x2):    /* insert top word three down  */
          dup_x2(topOfStack);
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);

      CASE(_dup2_x1):   /* insert top 2 slots three down */
          dup2_x1(topOfStack);
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 2);

      CASE(_dup2_x2):   /* insert top 2 slots four down */
          dup2_x2(topOfStack);
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 2);

      CASE(_swap): {        /* swap top two elements on the stack */
          swap(topOfStack);
          UPDATE_PC_AND_CONTINUE(1);
      }

          /* Perform various binary integer operations */

#undef  OPC_INT_BINARY
#define OPC_INT_BINARY(opcname, opname, test)                           \
      CASE(_i##opcname):                                                \
          if (test && (STACK_INT(-1) == 0)) {                           \
              VM_JAVA_ERROR(vmSymbols::java_lang_ArithmeticException(), \
                            "/ by zero");                               \
          }                                                             \
          SET_STACK_INT(VMint##opname(STACK_INT(-2),                    \
                                      STACK_INT(-1)),                   \
                                      -2);                              \
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1);                        \
      CASE(_l##opcname):                                                \
      {                                                                 \
          if (test) {                                                   \
            jlong l1 = STACK_LONG(-1);                                  \
            if (VMlongEqz(l1)) {                                        \
              VM_JAVA_ERROR(vmSymbols::java_lang_ArithmeticException(), \
                            "/ by long zero");                          \
            }                                                           \
          }                                                             \
          /* First long at (-1,-2) next long at (-3,-4) */              \
          SET_STACK_LONG(VMlong##opname(STACK_LONG(-3),                 \
                                        STACK_LONG(-1)),                \
                                        -3);                            \
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, -2);                        \
      }

      OPC_INT_BINARY(add, Add, 0);
      OPC_INT_BINARY(sub, Sub, 0);
      OPC_INT_BINARY(mul, Mul, 0);
      OPC_INT_BINARY(and, And, 0);
      OPC_INT_BINARY(or,  Or,  0);
      OPC_INT_BINARY(xor, Xor, 0);
      OPC_INT_BINARY(div, Div, 1);
      OPC_INT_BINARY(rem, Rem, 1);


      /* Perform various binary floating number operations */
      /* On some machine/platforms/compilers div zero check can be implicit */

#undef  OPC_FLOAT_BINARY
#define OPC_FLOAT_BINARY(opcname, opname)                                  \
      CASE(_d##opcname): {                                                 \
          SET_STACK_DOUBLE(VMdouble##opname(STACK_DOUBLE(-3),              \
                                            STACK_DOUBLE(-1)),             \
                                            -3);                           \
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, -2);                           \
      }                                                                    \
      CASE(_f##opcname):                                                   \
          SET_STACK_FLOAT(VMfloat##opname(STACK_FLOAT(-2),                 \
                                          STACK_FLOAT(-1)),                \
                                          -2);                             \
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1);


     OPC_FLOAT_BINARY(add, Add);
     OPC_FLOAT_BINARY(sub, Sub);
     OPC_FLOAT_BINARY(mul, Mul);
     OPC_FLOAT_BINARY(div, Div);
     OPC_FLOAT_BINARY(rem, Rem);

      /* Shift operations
       * Shift left int and long: ishl, lshl
       * Logical shift right int and long w/zero extension: iushr, lushr
       * Arithmetic shift right int and long w/sign extension: ishr, lshr
       */

#undef  OPC_SHIFT_BINARY
#define OPC_SHIFT_BINARY(opcname, opname)                               \
      CASE(_i##opcname):                                                \
         SET_STACK_INT(VMint##opname(STACK_INT(-2),                     \
                                     STACK_INT(-1)),                    \
                                     -2);                               \
         UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1);                         \
      CASE(_l##opcname):                                                \
      {                                                                 \
         SET_STACK_LONG(VMlong##opname(STACK_LONG(-2),                  \
                                       STACK_INT(-1)),                  \
                                       -2);                             \
         UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1);                         \
      }

      OPC_SHIFT_BINARY(shl, Shl);
      OPC_SHIFT_BINARY(shr, Shr);
      OPC_SHIFT_BINARY(ushr, Ushr);

     /* Increment local variable by constant */
      CASE(_iinc):
      {
          // locals[pc[1]].j.i += (jbyte)(pc[2]);
          SET_LOCALS_INT(LOCALS_INT(pc[1]) + (jbyte)(pc[2]), pc[1]);
          UPDATE_PC_AND_CONTINUE(3);
      }

     /* negate the value on the top of the stack */

      CASE(_ineg):
         SET_STACK_INT(VMintNeg(STACK_INT(-1)), -1);
         UPDATE_PC_AND_CONTINUE(1);

      CASE(_fneg):
         SET_STACK_FLOAT(VMfloatNeg(STACK_FLOAT(-1)), -1);
         UPDATE_PC_AND_CONTINUE(1);

      CASE(_lneg):
      {
         SET_STACK_LONG(VMlongNeg(STACK_LONG(-1)), -1);
         UPDATE_PC_AND_CONTINUE(1);
      }

      CASE(_dneg):
      {
         SET_STACK_DOUBLE(VMdoubleNeg(STACK_DOUBLE(-1)), -1);
         UPDATE_PC_AND_CONTINUE(1);
      }

      /* Conversion operations */

      CASE(_i2f):       /* convert top of stack int to float */
         SET_STACK_FLOAT(VMint2Float(STACK_INT(-1)), -1);
         UPDATE_PC_AND_CONTINUE(1);

      CASE(_i2l):       /* convert top of stack int to long */
      {
          // this is ugly QQQ
          jlong r = VMint2Long(STACK_INT(-1));
          MORE_STACK(-1); // Pop
          SET_STACK_LONG(r, 1);

          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 2);
      }

      CASE(_i2d):       /* convert top of stack int to double */
      {
          // this is ugly QQQ (why cast to jlong?? )
          jdouble r = (jlong)STACK_INT(-1);
          MORE_STACK(-1); // Pop
          SET_STACK_DOUBLE(r, 1);

          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 2);
      }

      CASE(_l2i):       /* convert top of stack long to int */
      {
          jint r = VMlong2Int(STACK_LONG(-1));
          MORE_STACK(-2); // Pop
          SET_STACK_INT(r, 0);
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);
      }

      CASE(_l2f):   /* convert top of stack long to float */
      {
          jlong r = STACK_LONG(-1);
          MORE_STACK(-2); // Pop
          SET_STACK_FLOAT(VMlong2Float(r), 0);
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);
      }

      CASE(_l2d):       /* convert top of stack long to double */
      {
          jlong r = STACK_LONG(-1);
          MORE_STACK(-2); // Pop
          SET_STACK_DOUBLE(VMlong2Double(r), 1);
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 2);
      }

      CASE(_f2i):  /* Convert top of stack float to int */
          SET_STACK_INT(SharedRuntime::f2i(STACK_FLOAT(-1)), -1);
          UPDATE_PC_AND_CONTINUE(1);

      CASE(_f2l):  /* convert top of stack float to long */
      {
          jlong r = SharedRuntime::f2l(STACK_FLOAT(-1));
          MORE_STACK(-1); // POP
          SET_STACK_LONG(r, 1);
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 2);
      }

      CASE(_f2d):  /* convert top of stack float to double */
      {
          jfloat f;
          jdouble r;
          f = STACK_FLOAT(-1);
          r = (jdouble) f;
          MORE_STACK(-1); // POP
          SET_STACK_DOUBLE(r, 1);
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 2);
      }

      CASE(_d2i): /* convert top of stack double to int */
      {
          jint r1 = SharedRuntime::d2i(STACK_DOUBLE(-1));
          MORE_STACK(-2);
          SET_STACK_INT(r1, 0);
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);
      }

      CASE(_d2f): /* convert top of stack double to float */
      {
          jfloat r1 = VMdouble2Float(STACK_DOUBLE(-1));
          MORE_STACK(-2);
          SET_STACK_FLOAT(r1, 0);
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);
      }

      CASE(_d2l): /* convert top of stack double to long */
      {
          jlong r1 = SharedRuntime::d2l(STACK_DOUBLE(-1));
          MORE_STACK(-2);
          SET_STACK_LONG(r1, 1);
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 2);
      }

      CASE(_i2b):
          SET_STACK_INT(VMint2Byte(STACK_INT(-1)), -1);
          UPDATE_PC_AND_CONTINUE(1);

      CASE(_i2c):
          SET_STACK_INT(VMint2Char(STACK_INT(-1)), -1);
          UPDATE_PC_AND_CONTINUE(1);

      CASE(_i2s):
          SET_STACK_INT(VMint2Short(STACK_INT(-1)), -1);
          UPDATE_PC_AND_CONTINUE(1);

      /* comparison operators */


#define COMPARISON_OP(name, comparison)                                      \
      CASE(_if_icmp##name): {                                                \
          int skip = (STACK_INT(-2) comparison STACK_INT(-1))                \
                      ? (int16_t)Bytes::get_Java_u2(pc + 1) : 3;             \
          address branch_pc = pc;                                            \
          UPDATE_PC_AND_TOS(skip, -2);                                       \
          DO_BACKEDGE_CHECKS(skip, branch_pc);                               \
          CONTINUE;                                                          \
      }                                                                      \
      CASE(_if##name): {                                                     \
          int skip = (STACK_INT(-1) comparison 0)                            \
                      ? (int16_t)Bytes::get_Java_u2(pc + 1) : 3;             \
          address branch_pc = pc;                                            \
          UPDATE_PC_AND_TOS(skip, -1);                                       \
          DO_BACKEDGE_CHECKS(skip, branch_pc);                               \
          CONTINUE;                                                          \
      }

#define COMPARISON_OP2(name, comparison)                                     \
      COMPARISON_OP(name, comparison)                                        \
      CASE(_if_acmp##name): {                                                \
          int skip = (STACK_OBJECT(-2) comparison STACK_OBJECT(-1))          \
                       ? (int16_t)Bytes::get_Java_u2(pc + 1) : 3;            \
          address branch_pc = pc;                                            \
          UPDATE_PC_AND_TOS(skip, -2);                                       \
          DO_BACKEDGE_CHECKS(skip, branch_pc);                               \
          CONTINUE;                                                          \
      }

#define NULL_COMPARISON_NOT_OP(name)                                         \
      CASE(_if##name): {                                                     \
          int skip = (!(STACK_OBJECT(-1) == nullptr))                           \
                      ? (int16_t)Bytes::get_Java_u2(pc + 1) : 3;             \
          address branch_pc = pc;                                            \
          UPDATE_PC_AND_TOS(skip, -1);                                       \
          DO_BACKEDGE_CHECKS(skip, branch_pc);                               \
          CONTINUE;                                                          \
      }

#define NULL_COMPARISON_OP(name)                                             \
      CASE(_if##name): {                                                     \
          int skip = ((STACK_OBJECT(-1) == nullptr))                            \
                      ? (int16_t)Bytes::get_Java_u2(pc + 1) : 3;             \
          address branch_pc = pc;                                            \
          UPDATE_PC_AND_TOS(skip, -1);                                       \
          DO_BACKEDGE_CHECKS(skip, branch_pc);                               \
          CONTINUE;                                                          \
      }
      COMPARISON_OP(lt, <);
      COMPARISON_OP(gt, >);
      COMPARISON_OP(le, <=);
      COMPARISON_OP(ge, >=);
      COMPARISON_OP2(eq, ==);  /* include ref comparison */
      COMPARISON_OP2(ne, !=);  /* include ref comparison */
      NULL_COMPARISON_OP(null);
      NULL_COMPARISON_NOT_OP(nonnull);

      /* Goto pc at specified offset in switch table. */

      CASE(_tableswitch): {
          jint* lpc  = (jint*)VMalignWordUp(pc+1);
          int32_t  key  = STACK_INT(-1);
          int32_t  low  = Bytes::get_Java_u4((address)&lpc[1]);
          int32_t  high = Bytes::get_Java_u4((address)&lpc[2]);
          int32_t  skip;
          key -= low;
          if (((uint32_t) key > (uint32_t)(high - low))) {
            skip = Bytes::get_Java_u4((address)&lpc[0]);
          } else {
            skip = Bytes::get_Java_u4((address)&lpc[key + 3]);
          }
          // Does this really need a full backedge check (osr)?
          address branch_pc = pc;
          UPDATE_PC_AND_TOS(skip, -1);
          DO_BACKEDGE_CHECKS(skip, branch_pc);
          CONTINUE;
      }

      /* Goto pc whose table entry matches specified key. */

      CASE(_lookupswitch): {
          jint* lpc  = (jint*)VMalignWordUp(pc+1);
          int32_t  key  = STACK_INT(-1);
          int32_t  skip = Bytes::get_Java_u4((address) lpc); /* default amount */
          int32_t  npairs = Bytes::get_Java_u4((address) &lpc[1]);
          while (--npairs >= 0) {
            lpc += 2;
            if (key == (int32_t)Bytes::get_Java_u4((address)lpc)) {
              skip = Bytes::get_Java_u4((address)&lpc[1]);
              break;
            }
          }
          address branch_pc = pc;
          UPDATE_PC_AND_TOS(skip, -1);
          DO_BACKEDGE_CHECKS(skip, branch_pc);
          CONTINUE;
      }

      CASE(_fcmpl):
      CASE(_fcmpg):
      {
          SET_STACK_INT(VMfloatCompare(STACK_FLOAT(-2),
                                        STACK_FLOAT(-1),
                                        (opcode == Bytecodes::_fcmpl ? -1 : 1)),
                        -2);
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1);
      }

      CASE(_dcmpl):
      CASE(_dcmpg):
      {
          int r = VMdoubleCompare(STACK_DOUBLE(-3),
                                  STACK_DOUBLE(-1),
                                  (opcode == Bytecodes::_dcmpl ? -1 : 1));
          MORE_STACK(-4); // Pop
          SET_STACK_INT(r, 0);
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);
      }

      CASE(_lcmp):
      {
          int r = VMlongCompare(STACK_LONG(-3), STACK_LONG(-1));
          MORE_STACK(-4);
          SET_STACK_INT(r, 0);
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);
      }


      /* Return from a method */

      CASE(_areturn):
      CASE(_ireturn):
      CASE(_freturn):
      CASE(_lreturn):
      CASE(_dreturn):
      CASE(_return): {
          // Allow a safepoint before returning to frame manager.
          RETURN_SAFEPOINT;
          goto handle_return;
      }

      CASE(_return_register_finalizer): {
          oop rcvr = LOCALS_OBJECT(0);
          VERIFY_OOP(rcvr);
          if (rcvr->klass()->has_finalizer()) {
            CALL_VM(InterpreterRuntime::register_finalizer(THREAD, rcvr), handle_exception);
          }
          goto handle_return;
      }

      /* Array access byte-codes */

#define ARRAY_INDEX_CHECK(arrObj, index)                                       \
      /* Two integers, the additional message, and the null-terminator */      \
      char message[2 * jintAsStringSize + 33];                                 \
      CHECK_NULL(arrObj);                                                      \
      if ((uint32_t)index >= (uint32_t)arrObj->length()) {                     \
          jio_snprintf(message, sizeof(message),                               \
                  "Index %d out of bounds for length %d",                      \
                  index, arrObj->length());                                    \
          VM_JAVA_ERROR(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), \
                        message);                                              \
      }

      /* Every array access byte-code starts out like this */
//        arrayOopDesc* arrObj = (arrayOopDesc*)STACK_OBJECT(arrayOff);
#define ARRAY_INTRO(arrayOff)                                                  \
      arrayOop arrObj = (arrayOop)STACK_OBJECT(arrayOff);                      \
      jint     index  = STACK_INT(arrayOff + 1);                               \
      ARRAY_INDEX_CHECK(arrObj, index)

      /* 32-bit loads. These handle conversion from < 32-bit types */
#define ARRAY_LOADTO32(T, T2, format, stackRes, extra)                                \
      {                                                                               \
          ARRAY_INTRO(-2);                                                            \
          (void)extra;                                                                \
          SET_ ## stackRes(*(T2 *)(((address) arrObj->base(T)) + index * sizeof(T2)), \
                           -2);                                                       \
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1);                                      \
      }

      /* 64-bit loads */
#define ARRAY_LOADTO64(T,T2, stackRes, extra)                                              \
      {                                                                                    \
          ARRAY_INTRO(-2);                                                                 \
          SET_ ## stackRes(*(T2 *)(((address) arrObj->base(T)) + index * sizeof(T2)), -1); \
          (void)extra;                                                                     \
          UPDATE_PC_AND_CONTINUE(1);                                                       \
      }

      CASE(_iaload):
          ARRAY_LOADTO32(T_INT, jint,   "%d",   STACK_INT, 0);
      CASE(_faload):
          ARRAY_LOADTO32(T_FLOAT, jfloat, "%f",   STACK_FLOAT, 0);
      CASE(_aaload): {
          ARRAY_INTRO(-2);
          SET_STACK_OBJECT(((objArrayOop) arrObj)->obj_at(index), -2);
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1);
      }
      CASE(_baload):
          ARRAY_LOADTO32(T_BYTE, jbyte,  "%d",   STACK_INT, 0);
      CASE(_caload):
          ARRAY_LOADTO32(T_CHAR,  jchar, "%d",   STACK_INT, 0);
      CASE(_saload):
          ARRAY_LOADTO32(T_SHORT, jshort, "%d",   STACK_INT, 0);
      CASE(_laload):
          ARRAY_LOADTO64(T_LONG, jlong, STACK_LONG, 0);
      CASE(_daload):
          ARRAY_LOADTO64(T_DOUBLE, jdouble, STACK_DOUBLE, 0);

      CASE(_fast_icaload): {
          // Custom fast access for iload,caload pair.
          arrayOop arrObj = (arrayOop) STACK_OBJECT(-1);
          jint index = LOCALS_INT(pc[1]);
          ARRAY_INDEX_CHECK(arrObj, index);
          SET_STACK_INT(*(jchar *)(((address) arrObj->base(T_CHAR)) + index * sizeof(jchar)), -1);
          UPDATE_PC_AND_TOS_AND_CONTINUE(3, 0);
      }

      /* 32-bit stores. These handle conversion to < 32-bit types */
#define ARRAY_STOREFROM32(T, T2, format, stackSrc, extra)                            \
      {                                                                              \
          ARRAY_INTRO(-3);                                                           \
          (void)extra;                                                               \
          *(T2 *)(((address) arrObj->base(T)) + index * sizeof(T2)) = stackSrc( -1); \
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, -3);                                     \
      }

      /* 64-bit stores */
#define ARRAY_STOREFROM64(T, T2, stackSrc, extra)                                    \
      {                                                                              \
          ARRAY_INTRO(-4);                                                           \
          (void)extra;                                                               \
          *(T2 *)(((address) arrObj->base(T)) + index * sizeof(T2)) = stackSrc( -1); \
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, -4);                                     \
      }

      CASE(_iastore):
          ARRAY_STOREFROM32(T_INT, jint,   "%d",   STACK_INT, 0);
      CASE(_fastore):
          ARRAY_STOREFROM32(T_FLOAT, jfloat, "%f",   STACK_FLOAT, 0);
      /*
       * This one looks different because of the assignability check
       */
      CASE(_aastore): {
          oop rhsObject = STACK_OBJECT(-1);
          VERIFY_OOP(rhsObject);
          ARRAY_INTRO( -3);
          // arrObj, index are set
          if (rhsObject != nullptr) {
            /* Check assignability of rhsObject into arrObj */
            Klass* rhsKlass = rhsObject->klass(); // EBX (subclass)
            Klass* elemKlass = ObjArrayKlass::cast(arrObj->klass())->element_klass(); // superklass EAX
            //
            // Check for compatibility. This check must not GC!!
            // Seems way more expensive now that we must dispatch
            //
            if (rhsKlass != elemKlass && !rhsKlass->is_subtype_of(elemKlass)) { // ebx->is...
              VM_JAVA_ERROR(vmSymbols::java_lang_ArrayStoreException(), "");
            }
          }
          ((objArrayOop) arrObj)->obj_at_put(index, rhsObject);
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, -3);
      }
      CASE(_bastore): {
          ARRAY_INTRO(-3);
          int item = STACK_INT(-1);
          // if it is a T_BOOLEAN array, mask the stored value to 0/1
          if (arrObj->klass() == Universe::boolArrayKlass()) {
            item &= 1;
          } else {
            assert(arrObj->klass() == Universe::byteArrayKlass(),
                   "should be byte array otherwise");
          }
          ((typeArrayOop)arrObj)->byte_at_put(index, item);
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, -3);
      }
      CASE(_castore):
          ARRAY_STOREFROM32(T_CHAR, jchar,  "%d",   STACK_INT, 0);
      CASE(_sastore):
          ARRAY_STOREFROM32(T_SHORT, jshort, "%d",   STACK_INT, 0);
      CASE(_lastore):
          ARRAY_STOREFROM64(T_LONG, jlong, STACK_LONG, 0);
      CASE(_dastore):
          ARRAY_STOREFROM64(T_DOUBLE, jdouble, STACK_DOUBLE, 0);

      CASE(_arraylength):
      {
          arrayOop ary = (arrayOop) STACK_OBJECT(-1);
          CHECK_NULL(ary);
          SET_STACK_INT(ary->length(), -1);
          UPDATE_PC_AND_CONTINUE(1);
      }

      /* monitorenter and monitorexit for locking/unlocking an object */

      CASE(_monitorenter): {
        oop lockee = STACK_OBJECT(-1);
        // derefing's lockee ought to provoke implicit null check
        CHECK_NULL(lockee);
        // find a free monitor or one already allocated for this object
        // if we find a matching object then we need a new monitor
        // since this is recursive enter
        BasicObjectLock* limit = istate->monitor_base();
        BasicObjectLock* most_recent = (BasicObjectLock*) istate->stack_base();
        BasicObjectLock* entry = nullptr;
        while (most_recent != limit ) {
          if (most_recent->obj() == nullptr) entry = most_recent;
          else if (most_recent->obj() == lockee) break;
          most_recent++;
        }
        if (entry != nullptr) {
          entry->set_obj(lockee);
          CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception);
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1);
        } else {
          istate->set_msg(more_monitors);
          UPDATE_PC_AND_RETURN(0); // Re-execute
        }
      }

      CASE(_monitorexit): {
        oop lockee = STACK_OBJECT(-1);
        CHECK_NULL(lockee);
        // derefing's lockee ought to provoke implicit null check
        // find our monitor slot
        BasicObjectLock* limit = istate->monitor_base();
        BasicObjectLock* most_recent = (BasicObjectLock*) istate->stack_base();
        while (most_recent != limit ) {
          if ((most_recent)->obj() == lockee) {
            BasicLock* lock = most_recent->lock();
            InterpreterRuntime::monitorexit(most_recent);
            UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1);
          }
          most_recent++;
        }
        // Need to throw illegal monitor state exception
        CALL_VM(InterpreterRuntime::throw_illegal_monitor_state_exception(THREAD), handle_exception);
        ShouldNotReachHere();
      }

      /* All of the non-quick opcodes. */

      /* -Set clobbersCpIndex true if the quickened opcode clobbers the
       *  constant pool index in the instruction.
       */
      CASE(_getfield):
      CASE(_nofast_getfield):
      CASE(_getstatic):
        {
          u2 index;
          index = Bytes::get_native_u2(pc+1);
          ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index);

          // QQQ Need to make this as inlined as possible. Probably need to
          // split all the bytecode cases out so c++ compiler has a chance
          // for constant prop to fold everything possible away.

          // Interpreter runtime does not expect "nofast" opcodes,
          // prepare the vanilla opcode for it.
          Bytecodes::Code code = (Bytecodes::Code)opcode;
          if (code == Bytecodes::_nofast_getfield) {
            code = Bytecodes::_getfield;
          }

          if (!entry->is_resolved(code)) {
            CALL_VM(InterpreterRuntime::resolve_from_cache(THREAD, code),
                    handle_exception);
            entry = cp->resolved_field_entry_at(index);
          }

          oop obj;
          if ((Bytecodes::Code)opcode == Bytecodes::_getstatic) {
            Klass* k = entry->field_holder();
            obj = k->java_mirror();
            MORE_STACK(1);  // Assume single slot push
          } else {
            obj = STACK_OBJECT(-1);
            CHECK_NULL(obj);
            // Check if we can rewrite non-volatile _getfield to one of the _fast_Xgetfield.
            if (REWRITE_BYTECODES && !entry->is_volatile() &&
                  ((Bytecodes::Code)opcode != Bytecodes::_nofast_getfield)) {
              // Rewrite current BC to _fast_Xgetfield.
              REWRITE_AT_PC(fast_get_type((TosState)(entry->tos_state())));
            }
          }

          MAYBE_POST_FIELD_ACCESS(obj);

          //
          // Now store the result on the stack
          //
          TosState tos_type = (TosState)(entry->tos_state());
          int field_offset = entry->field_offset();
          if (entry->is_volatile()) {
            if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
              OrderAccess::fence();
            }
            switch (tos_type) {
              case btos:
              case ztos:
                SET_STACK_INT(obj->byte_field_acquire(field_offset), -1);
                break;
              case ctos:
                SET_STACK_INT(obj->char_field_acquire(field_offset), -1);
                break;
              case stos:
                SET_STACK_INT(obj->short_field_acquire(field_offset), -1);
                break;
              case itos:
                SET_STACK_INT(obj->int_field_acquire(field_offset), -1);
                break;
              case ftos:
                SET_STACK_FLOAT(obj->float_field_acquire(field_offset), -1);
                break;
              case ltos:
                SET_STACK_LONG(obj->long_field_acquire(field_offset), 0);
                MORE_STACK(1);
                break;
              case dtos:
                SET_STACK_DOUBLE(obj->double_field_acquire(field_offset), 0);
                MORE_STACK(1);
                break;
              case atos: {
                oop val = obj->obj_field_acquire(field_offset);
                VERIFY_OOP(val);
                SET_STACK_OBJECT(val, -1);
                break;
              }
              default:
                ShouldNotReachHere();
            }
          } else {
            switch (tos_type) {
              case btos:
              case ztos:
                SET_STACK_INT(obj->byte_field(field_offset), -1);
                break;
              case ctos:
                SET_STACK_INT(obj->char_field(field_offset), -1);
                break;
              case stos:
                SET_STACK_INT(obj->short_field(field_offset), -1);
                break;
              case itos:
                SET_STACK_INT(obj->int_field(field_offset), -1);
                break;
              case ftos:
                SET_STACK_FLOAT(obj->float_field(field_offset), -1);
                break;
              case ltos:
                SET_STACK_LONG(obj->long_field(field_offset), 0);
                MORE_STACK(1);
                break;
              case dtos:
                SET_STACK_DOUBLE(obj->double_field(field_offset), 0);
                MORE_STACK(1);
                break;
              case atos: {
                oop val = obj->obj_field(field_offset);
                VERIFY_OOP(val);
                SET_STACK_OBJECT(val, -1);
                break;
              }
              default:
                ShouldNotReachHere();
            }
          }

          UPDATE_PC_AND_CONTINUE(3);
        }

      CASE(_putfield):
      CASE(_nofast_putfield):
      CASE(_putstatic):
        {
          u2 index = Bytes::get_native_u2(pc+1);
          ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index);

          // Interpreter runtime does not expect "nofast" opcodes,
          // prepare the vanilla opcode for it.
          Bytecodes::Code code = (Bytecodes::Code)opcode;
          if (code == Bytecodes::_nofast_putfield) {
            code = Bytecodes::_putfield;
          }

          if (!entry->is_resolved(code)) {
            CALL_VM(InterpreterRuntime::resolve_from_cache(THREAD, code),
                    handle_exception);
            entry = cp->resolved_field_entry_at(index);
          }

          // QQQ Need to make this as inlined as possible. Probably need to split all the bytecode cases
          // out so c++ compiler has a chance for constant prop to fold everything possible away.

          oop obj;
          int count;
          TosState tos_type = (TosState)(entry->tos_state());

          count = -1;
          if (tos_type == ltos || tos_type == dtos) {
            --count;
          }
          if ((Bytecodes::Code)opcode == Bytecodes::_putstatic) {
            Klass* k = entry->field_holder();
            obj = k->java_mirror();
          } else {
            --count;
            obj = STACK_OBJECT(count);
            CHECK_NULL(obj);

            // Check if we can rewrite non-volatile _putfield to one of the _fast_Xputfield.
            if (REWRITE_BYTECODES && !entry->is_volatile() &&
                  ((Bytecodes::Code)opcode != Bytecodes::_nofast_putfield)) {
              // Rewrite current BC to _fast_Xputfield.
              REWRITE_AT_PC(fast_put_type((TosState)(entry->tos_state())));
            }
          }

          MAYBE_POST_FIELD_MODIFICATION(obj);

          //
          // Now store the result
          //
          int field_offset = entry->field_offset();
          if (entry->is_volatile()) {
            switch (tos_type) {
              case ztos:
                obj->release_byte_field_put(field_offset, (STACK_INT(-1) & 1)); // only store LSB
                break;
              case btos:
                obj->release_byte_field_put(field_offset, STACK_INT(-1));
                break;
              case ctos:
                obj->release_char_field_put(field_offset, STACK_INT(-1));
                break;
              case stos:
                obj->release_short_field_put(field_offset, STACK_INT(-1));
                break;
              case itos:
                obj->release_int_field_put(field_offset, STACK_INT(-1));
                break;
              case ftos:
                obj->release_float_field_put(field_offset, STACK_FLOAT(-1));
                break;
              case ltos:
                obj->release_long_field_put(field_offset, STACK_LONG(-1));
                break;
              case dtos:
                obj->release_double_field_put(field_offset, STACK_DOUBLE(-1));
                break;
              case atos: {
                oop val = STACK_OBJECT(-1);
                VERIFY_OOP(val);
                obj->release_obj_field_put(field_offset, val);
                break;
              }
              default:
                ShouldNotReachHere();
            }
            OrderAccess::storeload();
          } else {
            switch (tos_type) {
              case ztos:
                obj->byte_field_put(field_offset, (STACK_INT(-1) & 1)); // only store LSB
                break;
              case btos:
                obj->byte_field_put(field_offset, STACK_INT(-1));
                break;
              case ctos:
                obj->char_field_put(field_offset, STACK_INT(-1));
                break;
              case stos:
                obj->short_field_put(field_offset, STACK_INT(-1));
                break;
              case itos:
                obj->int_field_put(field_offset, STACK_INT(-1));
                break;
              case ftos:
                obj->float_field_put(field_offset, STACK_FLOAT(-1));
                break;
              case ltos:
                obj->long_field_put(field_offset, STACK_LONG(-1));
                break;
              case dtos:
                obj->double_field_put(field_offset, STACK_DOUBLE(-1));
                break;
              case atos: {
                oop val = STACK_OBJECT(-1);
                VERIFY_OOP(val);
                obj->obj_field_put(field_offset, val);
                break;
              }
              default:
                ShouldNotReachHere();
            }
          }

          UPDATE_PC_AND_TOS_AND_CONTINUE(3, count);
        }

      CASE(_new): {
        u2 index = Bytes::get_Java_u2(pc+1);

        // Attempt TLAB allocation first.
        //
        // To do this, we need to make sure:
        //   - klass is initialized
        //   - klass can be fastpath allocated (e.g. does not have finalizer)
        //   - TLAB accepts the allocation
        ConstantPool* constants = istate->method()->constants();
        if (UseTLAB && !constants->tag_at(index).is_unresolved_klass()) {
          Klass* entry = constants->resolved_klass_at(index);
          InstanceKlass* ik = InstanceKlass::cast(entry);
          if (ik->is_initialized() && ik->can_be_fastpath_allocated()) {
            size_t obj_size = ik->size_helper();
            HeapWord* result = THREAD->tlab().allocate(obj_size);
            if (result != nullptr) {
              // Initialize object field block.
              if (!ZeroTLAB) {
                // The TLAB was not pre-zeroed, we need to clear the memory here.
                size_t hdr_size = oopDesc::header_size();
                Copy::fill_to_words(result + hdr_size, obj_size - hdr_size, 0);
              }

              // Initialize header, mirrors MemAllocator.
              if (UseCompactObjectHeaders) {
                oopDesc::release_set_mark(result, ik->prototype_header());
              } else {
                oopDesc::set_mark(result, markWord::prototype());
                if (oopDesc::has_klass_gap()) {
                  oopDesc::set_klass_gap(result, 0);
                }
                oopDesc::release_set_klass(result, ik);
              }
              oop obj = cast_to_oop(result);

              // Must prevent reordering of stores for object initialization
              // with stores that publish the new object.
              OrderAccess::storestore();
              SET_STACK_OBJECT(obj, 0);
              UPDATE_PC_AND_TOS_AND_CONTINUE(3, 1);
            }
          }
        }
        // Slow case allocation
        CALL_VM(InterpreterRuntime::_new(THREAD, METHOD->constants(), index),
                handle_exception);
        // Must prevent reordering of stores for object initialization
        // with stores that publish the new object.
        OrderAccess::storestore();
        SET_STACK_OBJECT(THREAD->vm_result_oop(), 0);
        THREAD->set_vm_result_oop(nullptr);
        UPDATE_PC_AND_TOS_AND_CONTINUE(3, 1);
      }
      CASE(_anewarray): {
        u2 index = Bytes::get_Java_u2(pc+1);
        jint size = STACK_INT(-1);
        CALL_VM(InterpreterRuntime::anewarray(THREAD, METHOD->constants(), index, size),
                handle_exception);
        // Must prevent reordering of stores for object initialization
        // with stores that publish the new object.
        OrderAccess::storestore();
        SET_STACK_OBJECT(THREAD->vm_result_oop(), -1);
        THREAD->set_vm_result_oop(nullptr);
        UPDATE_PC_AND_CONTINUE(3);
      }
      CASE(_multianewarray): {
        jint dims = *(pc+3);
        jint size = STACK_INT(-1);
        // stack grows down, dimensions are up!
        jint *dimarray =
                   (jint*)&topOfStack[dims * Interpreter::stackElementWords+
                                      Interpreter::stackElementWords-1];
        //adjust pointer to start of stack element
        CALL_VM(InterpreterRuntime::multianewarray(THREAD, dimarray),
                handle_exception);
        // Must prevent reordering of stores for object initialization
        // with stores that publish the new object.
        OrderAccess::storestore();
        SET_STACK_OBJECT(THREAD->vm_result_oop(), -dims);
        THREAD->set_vm_result_oop(nullptr);
        UPDATE_PC_AND_TOS_AND_CONTINUE(4, -(dims-1));
      }
      CASE(_checkcast):
          if (STACK_OBJECT(-1) != nullptr) {
            VERIFY_OOP(STACK_OBJECT(-1));
            u2 index = Bytes::get_Java_u2(pc+1);
            // Constant pool may have actual klass or unresolved klass. If it is
            // unresolved we must resolve it.
            if (METHOD->constants()->tag_at(index).is_unresolved_klass()) {
              CALL_VM(InterpreterRuntime::quicken_io_cc(THREAD), handle_exception);
            }
            Klass* klassOf = (Klass*) METHOD->constants()->resolved_klass_at(index);
            Klass* objKlass = STACK_OBJECT(-1)->klass(); // ebx
            //
            // Check for compatibility. This check must not GC!!
            // Seems way more expensive now that we must dispatch.
            //
            if (objKlass != klassOf && !objKlass->is_subtype_of(klassOf)) {
              ResourceMark rm(THREAD);
              char* message = SharedRuntime::generate_class_cast_message(
                objKlass, klassOf);
              VM_JAVA_ERROR(vmSymbols::java_lang_ClassCastException(), message);
            }
          }
          UPDATE_PC_AND_CONTINUE(3);

      CASE(_instanceof):
          if (STACK_OBJECT(-1) == nullptr) {
            SET_STACK_INT(0, -1);
          } else {
            VERIFY_OOP(STACK_OBJECT(-1));
            u2 index = Bytes::get_Java_u2(pc+1);
            // Constant pool may have actual klass or unresolved klass. If it is
            // unresolved we must resolve it.
            if (METHOD->constants()->tag_at(index).is_unresolved_klass()) {
              CALL_VM(InterpreterRuntime::quicken_io_cc(THREAD), handle_exception);
            }
            Klass* klassOf = (Klass*) METHOD->constants()->resolved_klass_at(index);
            Klass* objKlass = STACK_OBJECT(-1)->klass();
            //
            // Check for compatibility. This check must not GC!!
            // Seems way more expensive now that we must dispatch.
            //
            if ( objKlass == klassOf || objKlass->is_subtype_of(klassOf)) {
              SET_STACK_INT(1, -1);
            } else {
              SET_STACK_INT(0, -1);
            }
          }
          UPDATE_PC_AND_CONTINUE(3);

      CASE(_ldc_w):
      CASE(_ldc):
        {
          u2 index;
          bool wide = false;
          int incr = 2; // frequent case
          if (opcode == Bytecodes::_ldc) {
            index = pc[1];
          } else {
            index = Bytes::get_Java_u2(pc+1);
            incr = 3;
            wide = true;
          }

          ConstantPool* constants = METHOD->constants();
          switch (constants->tag_at(index).value()) {
          case JVM_CONSTANT_Integer:
            SET_STACK_INT(constants->int_at(index), 0);
            break;

          case JVM_CONSTANT_Float:
            SET_STACK_FLOAT(constants->float_at(index), 0);
            break;

          case JVM_CONSTANT_String:
            {
              oop result = constants->resolved_reference_at(index);
              if (result == nullptr) {
                CALL_VM(InterpreterRuntime::resolve_ldc(THREAD, (Bytecodes::Code) opcode), handle_exception);
                SET_STACK_OBJECT(THREAD->vm_result_oop(), 0);
                THREAD->set_vm_result_oop(nullptr);
              } else {
                VERIFY_OOP(result);
                SET_STACK_OBJECT(result, 0);
              }
            break;
            }

          case JVM_CONSTANT_Class:
            VERIFY_OOP(constants->resolved_klass_at(index)->java_mirror());
            SET_STACK_OBJECT(constants->resolved_klass_at(index)->java_mirror(), 0);
            break;

          case JVM_CONSTANT_UnresolvedClass:
          case JVM_CONSTANT_UnresolvedClassInError:
            CALL_VM(InterpreterRuntime::ldc(THREAD, wide), handle_exception);
            SET_STACK_OBJECT(THREAD->vm_result_oop(), 0);
            THREAD->set_vm_result_oop(nullptr);
            break;

          case JVM_CONSTANT_Dynamic:
          case JVM_CONSTANT_DynamicInError:
            {
              CALL_VM(InterpreterRuntime::resolve_ldc(THREAD, (Bytecodes::Code) opcode), handle_exception);
              oop result = THREAD->vm_result_oop();
              VERIFY_OOP(result);

              jvalue value;
              BasicType type = java_lang_boxing_object::get_value(result, &value);
              switch (type) {
              case T_FLOAT:   SET_STACK_FLOAT(value.f, 0); break;
              case T_INT:     SET_STACK_INT(value.i, 0); break;
              case T_SHORT:   SET_STACK_INT(value.s, 0); break;
              case T_BYTE:    SET_STACK_INT(value.b, 0); break;
              case T_CHAR:    SET_STACK_INT(value.c, 0); break;
              case T_BOOLEAN: SET_STACK_INT(value.z, 0); break;
              default:  ShouldNotReachHere();
              }

              break;
            }

          default:  ShouldNotReachHere();
          }
          UPDATE_PC_AND_TOS_AND_CONTINUE(incr, 1);
        }

      CASE(_ldc2_w):
        {
          u2 index = Bytes::get_Java_u2(pc+1);

          ConstantPool* constants = METHOD->constants();
          switch (constants->tag_at(index).value()) {

          case JVM_CONSTANT_Long:
             SET_STACK_LONG(constants->long_at(index), 1);
            break;

          case JVM_CONSTANT_Double:
             SET_STACK_DOUBLE(constants->double_at(index), 1);
            break;

          case JVM_CONSTANT_Dynamic:
          case JVM_CONSTANT_DynamicInError:
            {
              CALL_VM(InterpreterRuntime::resolve_ldc(THREAD, (Bytecodes::Code) opcode), handle_exception);
              oop result = THREAD->vm_result_oop();
              VERIFY_OOP(result);

              jvalue value;
              BasicType type = java_lang_boxing_object::get_value(result, &value);
              switch (type) {
              case T_DOUBLE: SET_STACK_DOUBLE(value.d, 1); break;
              case T_LONG:   SET_STACK_LONG(value.j, 1); break;
              default:  ShouldNotReachHere();
              }

              break;
            }

          default:  ShouldNotReachHere();
          }
          UPDATE_PC_AND_TOS_AND_CONTINUE(3, 2);
        }

      CASE(_fast_aldc_w):
      CASE(_fast_aldc): {
        u2 index;
        int incr;
        if (opcode == Bytecodes::_fast_aldc) {
          index = pc[1];
          incr = 2;
        } else {
          index = Bytes::get_native_u2(pc+1);
          incr = 3;
        }

        // We are resolved if the resolved_references array contains a non-null object (CallSite, etc.)
        // This kind of CP cache entry does not need to match the flags byte, because
        // there is a 1-1 relation between bytecode type and CP entry type.
        ConstantPool* constants = METHOD->constants();
        oop result = constants->resolved_reference_at(index);
        if (result == nullptr) {
          CALL_VM(InterpreterRuntime::resolve_ldc(THREAD, (Bytecodes::Code) opcode),
                  handle_exception);
          result = THREAD->vm_result_oop();
        }
        if (result == Universe::the_null_sentinel())
          result = nullptr;

        VERIFY_OOP(result);
        SET_STACK_OBJECT(result, 0);
        UPDATE_PC_AND_TOS_AND_CONTINUE(incr, 1);
      }

      CASE(_invokedynamic): {
        u4 index = Bytes::get_native_u4(pc+1);
        ResolvedIndyEntry* indy_info = cp->resolved_indy_entry_at(index);
        if (!indy_info->is_resolved()) {
          CALL_VM(InterpreterRuntime::resolve_from_cache(THREAD, (Bytecodes::Code)opcode),
                  handle_exception);
          indy_info = cp->resolved_indy_entry_at(index); // get resolved entry
        }
        Method* method = indy_info->method();
        if (VerifyOops) method->verify();

        if (indy_info->has_appendix()) {
          constantPoolHandle cp(THREAD, METHOD->constants());
          SET_STACK_OBJECT(cp->resolved_reference_from_indy(index), 0);
          MORE_STACK(1);
        }

        istate->set_msg(call_method);
        istate->set_callee(method);
        istate->set_callee_entry_point(method->from_interpreted_entry());
        istate->set_bcp_advance(5);

        UPDATE_PC_AND_RETURN(0); // I'll be back...
      }

      CASE(_invokehandle): {

        u2 index = Bytes::get_native_u2(pc+1);
        ResolvedMethodEntry* entry = cp->resolved_method_entry_at(index);

        if (! entry->is_resolved((Bytecodes::Code) opcode)) {
          CALL_VM(InterpreterRuntime::resolve_from_cache(THREAD, (Bytecodes::Code)opcode),
                  handle_exception);
          entry = cp->resolved_method_entry_at(index);
        }

        Method* method = entry->method();
        if (VerifyOops) method->verify();

        if (entry->has_appendix()) {
          constantPoolHandle cp(THREAD, METHOD->constants());
          SET_STACK_OBJECT(cp->cache()->appendix_if_resolved(entry), 0);
          MORE_STACK(1);
        }

        istate->set_msg(call_method);
        istate->set_callee(method);
        istate->set_callee_entry_point(method->from_interpreted_entry());
        istate->set_bcp_advance(3);

        UPDATE_PC_AND_RETURN(0); // I'll be back...
      }

      CASE(_invokeinterface): {
        u2 index = Bytes::get_native_u2(pc+1);

        // QQQ Need to make this as inlined as possible. Probably need to split all the bytecode cases
        // out so c++ compiler has a chance for constant prop to fold everything possible away.

        ResolvedMethodEntry* entry = cp->resolved_method_entry_at(index);
        if (!entry->is_resolved((Bytecodes::Code)opcode)) {
          CALL_VM(InterpreterRuntime::resolve_from_cache(THREAD, (Bytecodes::Code)opcode),
                  handle_exception);
        }

        istate->set_msg(call_method);

        // Special case of invokeinterface called for virtual method of
        // java.lang.Object.  See cpCache.cpp for details.
        Method* callee = nullptr;
        if (entry->is_forced_virtual()) {
          CHECK_NULL(STACK_OBJECT(-(entry->number_of_parameters())));
          if (entry->is_vfinal()) {
            callee = entry->method();
          } else {
            // Get receiver.
            int parms = entry->number_of_parameters();
            // Same comments as invokevirtual apply here.
            oop rcvr = STACK_OBJECT(-parms);
            VERIFY_OOP(rcvr);
            Klass* rcvrKlass = rcvr->klass();
            callee = (Method*) rcvrKlass->method_at_vtable(entry->table_index());
          }
        } else if (entry->is_vfinal()) {
          // private interface method invocations
          //
          // Ensure receiver class actually implements
          // the resolved interface class. The link resolver
          // does this, but only for the first time this
          // interface is being called.
          int parms = entry->number_of_parameters();
          oop rcvr = STACK_OBJECT(-parms);
          CHECK_NULL(rcvr);
          Klass* recv_klass = rcvr->klass();
          Klass* resolved_klass = entry->interface_klass();
          if (!recv_klass->is_subtype_of(resolved_klass)) {
            ResourceMark rm(THREAD);
            char buf[200];
            jio_snprintf(buf, sizeof(buf), "Class %s does not implement the requested interface %s",
              recv_klass->external_name(),
              resolved_klass->external_name());
            VM_JAVA_ERROR(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
          }
          callee = entry->method();
        }
        if (callee != nullptr) {
          istate->set_callee(callee);
          istate->set_callee_entry_point(callee->from_interpreted_entry());
          if (JVMTI_ENABLED && THREAD->is_interp_only_mode()) {
            istate->set_callee_entry_point(callee->interpreter_entry());
          }
          istate->set_bcp_advance(5);
          UPDATE_PC_AND_RETURN(0); // I'll be back...
        }

        // this could definitely be cleaned up QQQ
        Method *interface_method = entry->method();
        InstanceKlass* iclass = interface_method->method_holder();

        // get receiver
        int parms = entry->number_of_parameters();
        oop rcvr = STACK_OBJECT(-parms);
        CHECK_NULL(rcvr);
        InstanceKlass* int2 = (InstanceKlass*) rcvr->klass();

        // Receiver subtype check against resolved interface klass (REFC).
        {
          Klass* refc = entry->interface_klass();
          itableOffsetEntry* scan;
          for (scan = (itableOffsetEntry*) int2->start_of_itable();
               scan->interface_klass() != nullptr;
               scan++) {
            if (scan->interface_klass() == refc) {
              break;
            }
          }
          // Check that the entry is non-null.  A null entry means
          // that the receiver class doesn't implement the
          // interface, and wasn't the same as when the caller was
          // compiled.
          if (scan->interface_klass() == nullptr) {
            VM_JAVA_ERROR(vmSymbols::java_lang_IncompatibleClassChangeError(), "");
          }
        }

        itableOffsetEntry* ki = (itableOffsetEntry*) int2->start_of_itable();
        int i;
        for ( i = 0 ; i < int2->itable_length() ; i++, ki++ ) {
          if (ki->interface_klass() == iclass) break;
        }
        // If the interface isn't found, this class doesn't implement this
        // interface. The link resolver checks this but only for the first
        // time this interface is called.
        if (i == int2->itable_length()) {
          CALL_VM(InterpreterRuntime::throw_IncompatibleClassChangeErrorVerbose(THREAD, rcvr->klass(), iclass),
                  handle_exception);
        }
        int mindex = interface_method->itable_index();

        itableMethodEntry* im = ki->first_method_entry(rcvr->klass());
        callee = im[mindex].method();
        if (callee == nullptr) {
          CALL_VM(InterpreterRuntime::throw_AbstractMethodErrorVerbose(THREAD, rcvr->klass(), interface_method),
                  handle_exception);
        }

        istate->set_callee(callee);
        istate->set_callee_entry_point(callee->from_interpreted_entry());
        if (JVMTI_ENABLED && THREAD->is_interp_only_mode()) {
          istate->set_callee_entry_point(callee->interpreter_entry());
        }
        istate->set_bcp_advance(5);
        UPDATE_PC_AND_RETURN(0); // I'll be back...
      }

      CASE(_invokevirtual):
      CASE(_invokespecial):
      CASE(_invokestatic): {
        u2 index = Bytes::get_native_u2(pc+1);

        ResolvedMethodEntry* entry = cp->resolved_method_entry_at(index);
        // QQQ Need to make this as inlined as possible. Probably need to split all the bytecode cases
        // out so c++ compiler has a chance for constant prop to fold everything possible away.

        if (!entry->is_resolved((Bytecodes::Code)opcode)) {
          CALL_VM(InterpreterRuntime::resolve_from_cache(THREAD, (Bytecodes::Code)opcode),
                  handle_exception);
          entry = cp->resolved_method_entry_at(index);
        }

        istate->set_msg(call_method);
        {
          Method* callee;
          if ((Bytecodes::Code)opcode == Bytecodes::_invokevirtual) {
            CHECK_NULL(STACK_OBJECT(-(entry->number_of_parameters())));
            if (entry->is_vfinal()) {
              callee = entry->method();
              if (REWRITE_BYTECODES && !CDSConfig::is_using_archive() && !CDSConfig::is_dumping_archive()) {
                // Rewrite to _fast_invokevfinal.
                REWRITE_AT_PC(Bytecodes::_fast_invokevfinal);
              }
            } else {
              // get receiver
              int parms = entry->number_of_parameters();
              // this works but needs a resourcemark and seems to create a vtable on every call:
              // Method* callee = rcvr->klass()->vtable()->method_at(cache->f2_as_index());
              //
              // this fails with an assert
              // InstanceKlass* rcvrKlass = InstanceKlass::cast(STACK_OBJECT(-parms)->klass());
              // but this works
              oop rcvr = STACK_OBJECT(-parms);
              VERIFY_OOP(rcvr);
              Klass* rcvrKlass = rcvr->klass();
              /*
                Executing this code in java.lang.String:
                    public String(char value[]) {
                          this.count = value.length;
                          this.value = (char[])value.clone();
                     }

                 a find on rcvr->klass() reports:
                 {type array char}{type array class}
                  - klass: {other class}

                  but using InstanceKlass::cast(STACK_OBJECT(-parms)->klass()) causes in assertion failure
                  because rcvr->klass()->is_instance_klass() == 0
                  However it seems to have a vtable in the right location. Huh?
                  Because vtables have the same offset for ArrayKlass and InstanceKlass.
              */
              callee = (Method*) rcvrKlass->method_at_vtable(entry->table_index());
            }
          } else {
            if ((Bytecodes::Code)opcode == Bytecodes::_invokespecial) {
              CHECK_NULL(STACK_OBJECT(-(entry->number_of_parameters())));
            }
            callee = entry->method();
          }

          istate->set_callee(callee);
          istate->set_callee_entry_point(callee->from_interpreted_entry());
          if (JVMTI_ENABLED && THREAD->is_interp_only_mode()) {
            istate->set_callee_entry_point(callee->interpreter_entry());
          }
          istate->set_bcp_advance(3);
          UPDATE_PC_AND_RETURN(0); // I'll be back...
        }
      }

      /* Allocate memory for a new java object. */

      CASE(_newarray): {
        BasicType atype = (BasicType) *(pc+1);
        jint size = STACK_INT(-1);
        CALL_VM(InterpreterRuntime::newarray(THREAD, atype, size),
                handle_exception);
        // Must prevent reordering of stores for object initialization
        // with stores that publish the new object.
        OrderAccess::storestore();
        SET_STACK_OBJECT(THREAD->vm_result_oop(), -1);
        THREAD->set_vm_result_oop(nullptr);

        UPDATE_PC_AND_CONTINUE(2);
      }

      /* Throw an exception. */

      CASE(_athrow): {
          oop except_oop = STACK_OBJECT(-1);
          CHECK_NULL(except_oop);
          // set pending_exception so we use common code
          THREAD->set_pending_exception(except_oop, nullptr, 0);
          goto handle_exception;
      }

      /* goto and jsr. They are exactly the same except jsr pushes
       * the address of the next instruction first.
       */

      CASE(_jsr): {
          /* push bytecode index on stack */
          SET_STACK_ADDR(((address)pc - (intptr_t)(istate->method()->code_base()) + 3), 0);
          MORE_STACK(1);
          /* FALL THROUGH */
      }

      CASE(_goto):
      {
          int16_t offset = (int16_t)Bytes::get_Java_u2(pc + 1);
          address branch_pc = pc;
          UPDATE_PC(offset);
          DO_BACKEDGE_CHECKS(offset, branch_pc);
          CONTINUE;
      }

      CASE(_jsr_w): {
          /* push return address on the stack */
          SET_STACK_ADDR(((address)pc - (intptr_t)(istate->method()->code_base()) + 5), 0);
          MORE_STACK(1);
          /* FALL THROUGH */
      }

      CASE(_goto_w):
      {
          int32_t offset = Bytes::get_Java_u4(pc + 1);
          address branch_pc = pc;
          UPDATE_PC(offset);
          DO_BACKEDGE_CHECKS(offset, branch_pc);
          CONTINUE;
      }

      /* return from a jsr or jsr_w */

      CASE(_ret): {
          pc = istate->method()->code_base() + (intptr_t)(LOCALS_ADDR(pc[1]));
          UPDATE_PC_AND_CONTINUE(0);
      }

      /* debugger breakpoint */

      CASE(_breakpoint): {
          Bytecodes::Code original_bytecode;
          DECACHE_STATE();
          SET_LAST_JAVA_FRAME();
          original_bytecode = InterpreterRuntime::get_original_bytecode_at(THREAD,
                              METHOD, pc);
          RESET_LAST_JAVA_FRAME();
          CACHE_STATE();
          if (THREAD->has_pending_exception()) goto handle_exception;
            CALL_VM(InterpreterRuntime::_breakpoint(THREAD, METHOD, pc),
                                                    handle_exception);

          opcode = (jubyte)original_bytecode;
          goto opcode_switch;
      }

      CASE(_fast_agetfield): {
        u2 index = Bytes::get_native_u2(pc+1);
        ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index);
        int field_offset = entry->field_offset();

        oop obj = STACK_OBJECT(-1);
        CHECK_NULL(obj);

        MAYBE_POST_FIELD_ACCESS(obj);

        VERIFY_OOP(obj->obj_field(field_offset));
        SET_STACK_OBJECT(obj->obj_field(field_offset), -1);
        UPDATE_PC_AND_CONTINUE(3);
      }

      CASE(_fast_bgetfield): {
        u2 index = Bytes::get_native_u2(pc+1);
        ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index);
        int field_offset = entry->field_offset();

        oop obj = STACK_OBJECT(-1);
        CHECK_NULL(obj);

        MAYBE_POST_FIELD_ACCESS(obj);

        SET_STACK_INT(obj->byte_field(field_offset), -1);
        UPDATE_PC_AND_CONTINUE(3);
      }

      CASE(_fast_cgetfield): {
        u2 index = Bytes::get_native_u2(pc+1);
        ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index);
        int field_offset = entry->field_offset();

        oop obj = STACK_OBJECT(-1);
        CHECK_NULL(obj);

        MAYBE_POST_FIELD_ACCESS(obj);

        SET_STACK_INT(obj->char_field(field_offset), -1);
        UPDATE_PC_AND_CONTINUE(3);
      }

      CASE(_fast_dgetfield): {
        u2 index = Bytes::get_native_u2(pc+1);
        ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index);
        int field_offset = entry->field_offset();

        oop obj = STACK_OBJECT(-1);
        CHECK_NULL(obj);

        MAYBE_POST_FIELD_ACCESS(obj);

        SET_STACK_DOUBLE(obj->double_field(field_offset), 0);
        MORE_STACK(1);
        UPDATE_PC_AND_CONTINUE(3);
      }

      CASE(_fast_fgetfield): {
        u2 index = Bytes::get_native_u2(pc+1);
        ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index);
        int field_offset = entry->field_offset();

        oop obj = STACK_OBJECT(-1);
        CHECK_NULL(obj);

        MAYBE_POST_FIELD_ACCESS(obj);

        SET_STACK_FLOAT(obj->float_field(field_offset), -1);
        UPDATE_PC_AND_CONTINUE(3);
      }

      CASE(_fast_igetfield): {
        u2 index = Bytes::get_native_u2(pc+1);
        ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index);
        int field_offset = entry->field_offset();

        oop obj = STACK_OBJECT(-1);
        CHECK_NULL(obj);

        MAYBE_POST_FIELD_ACCESS(obj);

        SET_STACK_INT(obj->int_field(field_offset), -1);
        UPDATE_PC_AND_CONTINUE(3);
      }

      CASE(_fast_lgetfield): {
        u2 index = Bytes::get_native_u2(pc+1);
        ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index);
        int field_offset = entry->field_offset();

        oop obj = STACK_OBJECT(-1);
        CHECK_NULL(obj);

        MAYBE_POST_FIELD_ACCESS(obj);

        SET_STACK_LONG(obj->long_field(field_offset), 0);
        MORE_STACK(1);
        UPDATE_PC_AND_CONTINUE(3);
      }

      CASE(_fast_sgetfield): {
        u2 index = Bytes::get_native_u2(pc+1);
        ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index);
        int field_offset = entry->field_offset();

        oop obj = STACK_OBJECT(-1);
        CHECK_NULL(obj);

        MAYBE_POST_FIELD_ACCESS(obj);

        SET_STACK_INT(obj->short_field(field_offset), -1);
        UPDATE_PC_AND_CONTINUE(3);
      }

      CASE(_fast_aputfield): {
        u2 index = Bytes::get_native_u2(pc+1);
        ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index);

        oop obj = STACK_OBJECT(-2);
        CHECK_NULL(obj);

        MAYBE_POST_FIELD_MODIFICATION(obj);

        int field_offset = entry->field_offset();
        obj->obj_field_put(field_offset, STACK_OBJECT(-1));

        UPDATE_PC_AND_TOS_AND_CONTINUE(3, -2);
      }

      CASE(_fast_bputfield): {
        u2 index = Bytes::get_native_u2(pc+1);
        ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index);

        oop obj = STACK_OBJECT(-2);
        CHECK_NULL(obj);

        MAYBE_POST_FIELD_MODIFICATION(obj);

        int field_offset = entry->field_offset();
        obj->byte_field_put(field_offset, STACK_INT(-1));

        UPDATE_PC_AND_TOS_AND_CONTINUE(3, -2);
      }

      CASE(_fast_zputfield): {
        u2 index = Bytes::get_native_u2(pc+1);
        ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index);

        oop obj = STACK_OBJECT(-2);
        CHECK_NULL(obj);

        MAYBE_POST_FIELD_MODIFICATION(obj);

        int field_offset = entry->field_offset();
        obj->byte_field_put(field_offset, (STACK_INT(-1) & 1)); // only store LSB

        UPDATE_PC_AND_TOS_AND_CONTINUE(3, -2);
      }

      CASE(_fast_cputfield): {
        u2 index = Bytes::get_native_u2(pc+1);
        ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index);

        oop obj = STACK_OBJECT(-2);
        CHECK_NULL(obj);

        MAYBE_POST_FIELD_MODIFICATION(obj);

        int field_offset = entry->field_offset();
        obj->char_field_put(field_offset, STACK_INT(-1));

        UPDATE_PC_AND_TOS_AND_CONTINUE(3, -2);
      }

      CASE(_fast_dputfield): {
        u2 index = Bytes::get_native_u2(pc+1);
        ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index);

        oop obj = STACK_OBJECT(-3);
        CHECK_NULL(obj);

        MAYBE_POST_FIELD_MODIFICATION(obj);

        int field_offset = entry->field_offset();
        obj->double_field_put(field_offset, STACK_DOUBLE(-1));

        UPDATE_PC_AND_TOS_AND_CONTINUE(3, -3);
      }

      CASE(_fast_fputfield): {
        u2 index = Bytes::get_native_u2(pc+1);
        ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index);

        oop obj = STACK_OBJECT(-2);
        CHECK_NULL(obj);

        MAYBE_POST_FIELD_MODIFICATION(obj);

        int field_offset = entry->field_offset();
        obj->float_field_put(field_offset, STACK_FLOAT(-1));

        UPDATE_PC_AND_TOS_AND_CONTINUE(3, -2);
      }

      CASE(_fast_iputfield): {
        u2 index = Bytes::get_native_u2(pc+1);
        ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index);

        oop obj = STACK_OBJECT(-2);
        CHECK_NULL(obj);

        MAYBE_POST_FIELD_MODIFICATION(obj);

        int field_offset = entry->field_offset();
        obj->int_field_put(field_offset, STACK_INT(-1));

        UPDATE_PC_AND_TOS_AND_CONTINUE(3, -2);
      }

      CASE(_fast_lputfield): {
        u2 index = Bytes::get_native_u2(pc+1);
        ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index);

        oop obj = STACK_OBJECT(-3);
        CHECK_NULL(obj);

        MAYBE_POST_FIELD_MODIFICATION(obj);

        int field_offset = entry->field_offset();
        obj->long_field_put(field_offset, STACK_LONG(-1));

        UPDATE_PC_AND_TOS_AND_CONTINUE(3, -3);
      }

      CASE(_fast_sputfield): {
        u2 index = Bytes::get_native_u2(pc+1);
        ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index);

        oop obj = STACK_OBJECT(-2);
        CHECK_NULL(obj);

        MAYBE_POST_FIELD_MODIFICATION(obj);

        int field_offset = entry->field_offset();
        obj->short_field_put(field_offset, STACK_INT(-1));

        UPDATE_PC_AND_TOS_AND_CONTINUE(3, -2);
      }

      CASE(_fast_aload_0): {
        oop obj = LOCALS_OBJECT(0);
        VERIFY_OOP(obj);
        SET_STACK_OBJECT(obj, 0);
        UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);
      }

      CASE(_fast_aaccess_0): {
        u2 index = Bytes::get_native_u2(pc+2);
        ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index);
        int field_offset = entry->field_offset();

        oop obj = LOCALS_OBJECT(0);
        CHECK_NULL(obj);
        VERIFY_OOP(obj);

        MAYBE_POST_FIELD_ACCESS(obj);

        VERIFY_OOP(obj->obj_field(field_offset));
        SET_STACK_OBJECT(obj->obj_field(field_offset), 0);
        UPDATE_PC_AND_TOS_AND_CONTINUE(4, 1);
      }

      CASE(_fast_iaccess_0): {
        u2 index = Bytes::get_native_u2(pc+2);
        ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index);
        int field_offset = entry->field_offset();

        oop obj = LOCALS_OBJECT(0);
        CHECK_NULL(obj);
        VERIFY_OOP(obj);

        MAYBE_POST_FIELD_ACCESS(obj);

        SET_STACK_INT(obj->int_field(field_offset), 0);
        UPDATE_PC_AND_TOS_AND_CONTINUE(4, 1);
      }

      CASE(_fast_faccess_0): {
        u2 index = Bytes::get_native_u2(pc+2);
        ResolvedFieldEntry* entry = cp->resolved_field_entry_at(index);
        int field_offset = entry->field_offset();

        oop obj = LOCALS_OBJECT(0);
        CHECK_NULL(obj);
        VERIFY_OOP(obj);

        MAYBE_POST_FIELD_ACCESS(obj);

        SET_STACK_FLOAT(obj->float_field(field_offset), 0);
        UPDATE_PC_AND_TOS_AND_CONTINUE(4, 1);
      }

      CASE(_fast_invokevfinal): {
        u2 index = Bytes::get_native_u2(pc+1);
        ResolvedMethodEntry* entry = cp->resolved_method_entry_at(index);

        assert(entry->is_resolved(Bytecodes::_invokevirtual), "Should be resolved before rewriting");

        istate->set_msg(call_method);

        CHECK_NULL(STACK_OBJECT(-(entry->number_of_parameters())));
        Method* callee = entry->method();
        istate->set_callee(callee);
        if (JVMTI_ENABLED && THREAD->is_interp_only_mode()) {
          istate->set_callee_entry_point(callee->interpreter_entry());
        } else {
          istate->set_callee_entry_point(callee->from_interpreted_entry());
        }
        istate->set_bcp_advance(3);
        UPDATE_PC_AND_RETURN(0);
      }

      DEFAULT:
          fatal("Unimplemented opcode %d = %s", opcode,
                Bytecodes::name((Bytecodes::Code)opcode));
          goto finish;

      } /* switch(opc) */


#ifdef USELABELS
    check_for_exception:
#endif
    {
      if (!THREAD->has_pending_exception()) {
        CONTINUE;
      }
      /* We will be gcsafe soon, so flush our state. */
      DECACHE_PC();
      goto handle_exception;
    }
  do_continue: ;

  } /* while (1) interpreter loop */


  // An exception exists in the thread state see whether this activation can handle it
  handle_exception: {

    HandleMarkCleaner __hmc(THREAD);
    Handle except_oop(THREAD, THREAD->pending_exception());
    // Prevent any subsequent HandleMarkCleaner in the VM
    // from freeing the except_oop handle.
    HandleMark __hm(THREAD);

    THREAD->clear_pending_exception();
    assert(except_oop() != nullptr, "No exception to process");
    intptr_t continuation_bci;
    // expression stack is emptied
    topOfStack = istate->stack_base() - Interpreter::stackElementWords;
    CALL_VM(continuation_bci = (intptr_t)InterpreterRuntime::exception_handler_for_exception(THREAD, except_oop()),
            handle_exception);

    except_oop = Handle(THREAD, THREAD->vm_result_oop());
    THREAD->set_vm_result_oop(nullptr);
    if (continuation_bci >= 0) {
      // Place exception on top of stack
      SET_STACK_OBJECT(except_oop(), 0);
      MORE_STACK(1);
      pc = METHOD->code_base() + continuation_bci;
      if (log_is_enabled(Info, exceptions)) {
        ResourceMark rm(THREAD);
        stringStream tempst;
        tempst.print("interpreter method <%s>\n"
                     " at bci %d, continuing at %d for thread " INTPTR_FORMAT,
                     METHOD->print_value_string(),
                     (int)(istate->bcp() - METHOD->code_base()),
                     (int)continuation_bci, p2i(THREAD));
        Exceptions::log_exception(except_oop, tempst.as_string());
      }
      // for AbortVMOnException flag
      Exceptions::debug_check_abort(except_oop);
      goto run;
    }
    if (log_is_enabled(Info, exceptions)) {
      ResourceMark rm;
      stringStream tempst;
      tempst.print("interpreter method <%s>\n"
             " at bci %d, unwinding for thread " INTPTR_FORMAT,
             METHOD->print_value_string(),
             (int)(istate->bcp() - METHOD->code_base()),
             p2i(THREAD));
      Exceptions::log_exception(except_oop, tempst.as_string());
    }
    // for AbortVMOnException flag
    Exceptions::debug_check_abort(except_oop);

    // No handler in this activation, unwind and try again
    THREAD->set_pending_exception(except_oop(), nullptr, 0);
    goto handle_return;
  }  // handle_exception:

  // Return from an interpreter invocation with the result of the interpretation
  // on the top of the Java Stack (or a pending exception)

  handle_Pop_Frame: {

    // We don't really do anything special here except we must be aware
    // that we can get here without ever locking the method (if sync).
    // Also we skip the notification of the exit.

    istate->set_msg(popping_frame);
    // Clear pending so while the pop is in process
    // we don't start another one if a call_vm is done.
    THREAD->clear_popframe_condition();
    // Let interpreter (only) see the we're in the process of popping a frame
    THREAD->set_pop_frame_in_process();

    goto handle_return;

  } // handle_Pop_Frame

  // ForceEarlyReturn ends a method, and returns to the caller with a return value
  // given by the invoker of the early return.
  handle_Early_Return: {

    istate->set_msg(early_return);

    // Clear expression stack.
    topOfStack = istate->stack_base() - Interpreter::stackElementWords;

    JvmtiThreadState *ts = THREAD->jvmti_thread_state();

    // Push the value to be returned.
    switch (istate->method()->result_type()) {
      case T_BOOLEAN:
      case T_SHORT:
      case T_BYTE:
      case T_CHAR:
      case T_INT:
        SET_STACK_INT(ts->earlyret_value().i, 0);
        MORE_STACK(1);
        break;
      case T_LONG:
        SET_STACK_LONG(ts->earlyret_value().j, 1);
        MORE_STACK(2);
        break;
      case T_FLOAT:
        SET_STACK_FLOAT(ts->earlyret_value().f, 0);
        MORE_STACK(1);
        break;
      case T_DOUBLE:
        SET_STACK_DOUBLE(ts->earlyret_value().d, 1);
        MORE_STACK(2);
        break;
      case T_ARRAY:
      case T_OBJECT:
        SET_STACK_OBJECT(ts->earlyret_oop(), 0);
        MORE_STACK(1);
        break;
      default:
        ShouldNotReachHere();
    }

    ts->clr_earlyret_value();
    ts->set_earlyret_oop(nullptr);
    ts->clr_earlyret_pending();

    // Fall through to handle_return.

  } // handle_Early_Return

  handle_return: {
    // A storestore barrier is required to order initialization of
    // final fields with publishing the reference to the object that
    // holds the field. Without the barrier the value of final fields
    // can be observed to change.
    OrderAccess::storestore();

    DECACHE_STATE();

    bool suppress_error = istate->msg() == popping_frame || istate->msg() == early_return;
    bool suppress_exit_event = THREAD->has_pending_exception() || istate->msg() == popping_frame;
    Handle original_exception(THREAD, THREAD->pending_exception());
    Handle illegal_state_oop(THREAD, nullptr);

    // We'd like a HandleMark here to prevent any subsequent HandleMarkCleaner
    // in any following VM entries from freeing our live handles, but illegal_state_oop
    // isn't really allocated yet and so doesn't become live until later and
    // in unpredictable places. Instead we must protect the places where we enter the
    // VM. It would be much simpler (and safer) if we could allocate a real handle with
    // a null oop in it and then overwrite the oop later as needed. This isn't
    // unfortunately isn't possible.

    if (THREAD->has_pending_exception()) {
      THREAD->clear_pending_exception();
    }

    //
    // As far as we are concerned we have returned. If we have a pending exception
    // that will be returned as this invocation's result. However if we get any
    // exception(s) while checking monitor state one of those IllegalMonitorStateExceptions
    // will be our final result (i.e. monitor exception trumps a pending exception).
    //

    // If we never locked the method (or really passed the point where we would have),
    // there is no need to unlock it (or look for other monitors), since that
    // could not have happened.

    if (THREAD->do_not_unlock_if_synchronized()) {

      // Never locked, reset the flag now because obviously any caller must
      // have passed their point of locking for us to have gotten here.

      THREAD->set_do_not_unlock_if_synchronized(false);
    } else {
      // At this point we consider that we have returned. We now check that the
      // locks were properly block structured. If we find that they were not
      // used properly we will return with an illegal monitor exception.
      // The exception is checked by the caller not the callee since this
      // checking is considered to be part of the invocation and therefore
      // in the callers scope (JVM spec 8.13).
      //
      // Another weird thing to watch for is if the method was locked
      // recursively and then not exited properly. This means we must
      // examine all the entries in reverse time(and stack) order and
      // unlock as we find them. If we find the method monitor before
      // we are at the initial entry then we should throw an exception.
      // It is not clear the template based interpreter does this
      // correctly

      BasicObjectLock* base = istate->monitor_base();
      BasicObjectLock* end = (BasicObjectLock*) istate->stack_base();
      bool method_unlock_needed = METHOD->is_synchronized();
      // We know the initial monitor was used for the method don't check that
      // slot in the loop
      if (method_unlock_needed) base--;

      // Check all the monitors to see they are unlocked. Install exception if found to be locked.
      while (end < base) {
        oop lockee = end->obj();
        if (lockee != nullptr) {
          InterpreterRuntime::monitorexit(end);

          // One error is plenty
          if (illegal_state_oop() == nullptr && !suppress_error) {
            {
              // Prevent any HandleMarkCleaner from freeing our live handles
              HandleMark __hm(THREAD);
              CALL_VM_NOCHECK(InterpreterRuntime::throw_illegal_monitor_state_exception(THREAD));
            }
            assert(THREAD->has_pending_exception(), "Lost our exception!");
            illegal_state_oop = Handle(THREAD, THREAD->pending_exception());
            THREAD->clear_pending_exception();
          }
        }
        end++;
      }
      // Unlock the method if needed
      if (method_unlock_needed) {
        if (base->obj() == nullptr) {
          // The method is already unlocked this is not good.
          if (illegal_state_oop() == nullptr && !suppress_error) {
            {
              // Prevent any HandleMarkCleaner from freeing our live handles
              HandleMark __hm(THREAD);
              CALL_VM_NOCHECK(InterpreterRuntime::throw_illegal_monitor_state_exception(THREAD));
            }
            assert(THREAD->has_pending_exception(), "Lost our exception!");
            illegal_state_oop = Handle(THREAD, THREAD->pending_exception());
            THREAD->clear_pending_exception();
          }
        } else {
          //
          // The initial monitor is always used for the method
          // However if that slot is no longer the oop for the method it was unlocked
          // and reused by something that wasn't unlocked!
          //
          // deopt can come in with rcvr dead because c2 knows
          // its value is preserved in the monitor. So we can't use locals[0] at all
          // and must use first monitor slot.
          //
          oop rcvr = base->obj();
          if (rcvr == nullptr) {
            if (!suppress_error) {
              VM_JAVA_ERROR_NO_JUMP(vmSymbols::java_lang_NullPointerException(), "");
              illegal_state_oop = Handle(THREAD, THREAD->pending_exception());
              THREAD->clear_pending_exception();
            }
          } else {
            InterpreterRuntime::monitorexit(base);
            if (THREAD->has_pending_exception()) {
              if (!suppress_error) illegal_state_oop = Handle(THREAD, THREAD->pending_exception());
              THREAD->clear_pending_exception();
            }
          }
        }
      }
    }
    // Clear the do_not_unlock flag now.
    THREAD->set_do_not_unlock_if_synchronized(false);

    //
    // Notify jvmti/jvmdi
    //
    // NOTE: we do not notify a method_exit if we have a pending exception,
    // including an exception we generate for unlocking checks.  In the former
    // case, JVMDI has already been notified by our call for the exception handler
    // and in both cases as far as JVMDI is concerned we have already returned.
    // If we notify it again JVMDI will be all confused about how many frames
    // are still on the stack (4340444).
    //
    // NOTE Further! It turns out the JVMTI spec in fact expects to see
    // method_exit events whenever we leave an activation unless it was done
    // for popframe. This is nothing like jvmdi. However we are passing the
    // tests at the moment (apparently because they are jvmdi based) so rather
    // than change this code and possibly fail tests we will leave it alone
    // (with this note) in anticipation of changing the vm and the tests
    // simultaneously.

    suppress_exit_event = suppress_exit_event || illegal_state_oop() != nullptr;

    // Whenever JVMTI puts a thread in interp_only_mode, method
    // entry/exit events are sent for that thread to track stack depth.

    if (JVMTI_ENABLED && !suppress_exit_event && THREAD->is_interp_only_mode()) {
      // Prevent any HandleMarkCleaner from freeing our live handles
      HandleMark __hm(THREAD);
      CALL_VM_NOCHECK(InterpreterRuntime::post_method_exit(THREAD));
    }

    //
    // See if we are returning any exception
    // A pending exception that was pending prior to a possible popping frame
    // overrides the popping frame.
    //
    assert(!suppress_error || (suppress_error && illegal_state_oop() == nullptr), "Error was not suppressed");
    if (illegal_state_oop() != nullptr || original_exception() != nullptr) {
      // Inform the frame manager we have no result.
      istate->set_msg(throwing_exception);
      if (illegal_state_oop() != nullptr)
        THREAD->set_pending_exception(illegal_state_oop(), nullptr, 0);
      else
        THREAD->set_pending_exception(original_exception(), nullptr, 0);
      UPDATE_PC_AND_RETURN(0);
    }

    if (istate->msg() == popping_frame) {
      // Make it simpler on the assembly code and set the message for the frame pop.
      // returns
      if (istate->prev() == nullptr) {
        // We must be returning to a deoptimized frame (because popframe only happens between
        // two interpreted frames). We need to save the current arguments in C heap so that
        // the deoptimized frame when it restarts can copy the arguments to its expression
        // stack and re-execute the call. We also have to notify deoptimization that this
        // has occurred and to pick the preserved args copy them to the deoptimized frame's
        // java expression stack. Yuck.
        //
        THREAD->popframe_preserve_args(in_ByteSize(METHOD->size_of_parameters() * wordSize),
                                LOCALS_SLOT(METHOD->size_of_parameters() - 1));
        THREAD->set_popframe_condition_bit(JavaThread::popframe_force_deopt_reexecution_bit);
      }
    } else {
      istate->set_msg(return_from_method);
    }

    // Normal return
    // Advance the pc and return to frame manager
    UPDATE_PC_AND_RETURN(1);
  } /* handle_return: */

// This is really a fatal error return

finish:
  DECACHE_TOS();
  DECACHE_PC();

  return;
}