美文网首页
JVM 解释执行

JVM 解释执行

作者: asdf____ | 来源:发表于2020-04-25 13:54 被阅读0次

    JVM 字节码解释执行:
    hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp
    bytecodeInterpreter.cpp

    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 returing 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(NULL, 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):
          CASE(_fload):
              SET_STACK_SLOT(LOCALS_SLOT(pc[1]), 0);
              UPDATE_PC_AND_TOS_AND_CONTINUE(2, 1);
    
          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(_aload_##num):                                               \
              VERIFY_OOP(LOCALS_OBJECT(num));                               \
              SET_STACK_OBJECT(LOCALS_OBJECT(num), 0);                      \
              UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);                         \
                                                                            \
          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);
    
              /* 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];
              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) == NULL))                           \
                          ? (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) == NULL))                            \
                          ? (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;
              skip = ((uint32_t) key > (uint32_t)(high - low))
                          ? Bytes::get_Java_u4((address)&lpc[0])
                          : 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):
          {
              // Allow a safepoint before returning to frame manager.
              SAFEPOINT;
    
              goto handle_return;
          }
    
          CASE(_lreturn):
          CASE(_dreturn):
          {
              // Allow a safepoint before returning to frame manager.
              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;
          }
          CASE(_return): {
    
              // Allow a safepoint before returning to frame manager.
              SAFEPOINT;
              goto handle_return;
          }
    
          /* Array access byte-codes */
    
          /* 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);                               \
          char message[jintAsStringSize];                                          \
          CHECK_NULL(arrObj);                                                      \
          if ((uint32_t)index >= (uint32_t)arrObj->length()) {                     \
              sprintf(message, "%d", index);                                       \
              VM_JAVA_ERROR(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), \
                            message);                                              \
          }
    
          /* 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_LOADTO32(T_OBJECT, oop,   INTPTR_FORMAT, STACK_OBJECT, 0);
          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);
    
          /* 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 != NULL) {
                /* Check assignability of rhsObject into arrObj */
                Klass* rhsKlassOop = rhsObject->klass(); // EBX (subclass)
                Klass* elemKlassOop = ObjArrayKlass::cast(arrObj->klass())->element_klass(); // superklass EAX
                //
                // Check for compatibilty. This check must not GC!!
                // Seems way more expensive now that we must dispatch
                //
                if (rhsKlassOop != elemKlassOop && !rhsKlassOop->is_subtype_of(elemKlassOop)) { // ebx->is...
                  VM_JAVA_ERROR(vmSymbols::java_lang_ArrayStoreException(), "");
                }
              }
              oop* elem_loc = (oop*)(((address) arrObj->base(T_OBJECT)) + index * sizeof(oop));
              // *(oop*)(((address) arrObj->base(T_OBJECT)) + index * sizeof(oop)) = rhsObject;
              *elem_loc = rhsObject;
              // Mark the card
              OrderAccess::release_store(&BYTE_MAP_BASE[(uintptr_t)elem_loc >> CardTableModRefBS::card_shift], 0);
              UPDATE_PC_AND_TOS_AND_CONTINUE(1, -3);
          }
          CASE(_bastore):
              ARRAY_STOREFROM32(T_BYTE, jbyte,  "%d",   STACK_INT, 0);
          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 = NULL;
            while (most_recent != limit ) {
              if (most_recent->obj() == NULL) entry = most_recent;
              else if (most_recent->obj() == lockee) break;
              most_recent++;
            }
            if (entry != NULL) {
              entry->set_obj(lockee);
              markOop displaced = lockee->mark()->set_unlocked();
              entry->lock()->set_displaced_header(displaced);
              if (Atomic::cmpxchg_ptr(entry, lockee->mark_addr(), displaced) != displaced) {
                // Is it simple recursive case?
                if (THREAD->is_lock_owned((address) displaced->clear_lock_bits())) {
                  entry->lock()->set_displaced_header(NULL);
                } else {
                  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();
                markOop header = lock->displaced_header();
                most_recent->set_obj(NULL);
                // If it isn't recursive we either must swap old header or call the runtime
                if (header != NULL) {
                  if (Atomic::cmpxchg_ptr(header, lockee->mark_addr(), lock) != lock) {
                    // restore object for the slow case
                    most_recent->set_obj(lockee);
                    CALL_VM(InterpreterRuntime::monitorexit(THREAD, most_recent), handle_exception);
                  }
                }
                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(_getstatic):
            {
              u2 index;
              ConstantPoolCacheEntry* cache;
              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.
    
              cache = cp->entry_at(index);
              if (!cache->is_resolved((Bytecodes::Code)opcode)) {
                CALL_VM(InterpreterRuntime::resolve_get_put(THREAD, (Bytecodes::Code)opcode),
                        handle_exception);
                cache = cp->entry_at(index);
              }
    
    #ifdef VM_JVMTI
              if (_jvmti_interp_events) {
                int *count_addr;
                oop obj;
                // Check to see if a field modification watch has been set
                // before we take the time to call into the VM.
                count_addr = (int *)JvmtiExport::get_field_access_count_addr();
                if ( *count_addr > 0 ) {
                  if ((Bytecodes::Code)opcode == Bytecodes::_getstatic) {
                    obj = (oop)NULL;
                  } else {
                    obj = (oop) STACK_OBJECT(-1);
                    VERIFY_OOP(obj);
                  }
                  CALL_VM(InterpreterRuntime::post_field_access(THREAD,
                                              obj,
                                              cache),
                                              handle_exception);
                }
              }
    #endif /* VM_JVMTI */
    
              oop obj;
              if ((Bytecodes::Code)opcode == Bytecodes::_getstatic) {
                Klass* k = cache->f1_as_klass();
                obj = k->java_mirror();
                MORE_STACK(1);  // Assume single slot push
              } else {
                obj = (oop) STACK_OBJECT(-1);
                CHECK_NULL(obj);
              }
    
              //
              // Now store the result on the stack
              //
              TosState tos_type = cache->flag_state();
              int field_offset = cache->f2_as_index();
              if (cache->is_volatile()) {
                if (tos_type == atos) {
                  VERIFY_OOP(obj->obj_field_acquire(field_offset));
                  SET_STACK_OBJECT(obj->obj_field_acquire(field_offset), -1);
                } else if (tos_type == itos) {
                  SET_STACK_INT(obj->int_field_acquire(field_offset), -1);
                } else if (tos_type == ltos) {
                  SET_STACK_LONG(obj->long_field_acquire(field_offset), 0);
                  MORE_STACK(1);
                } else if (tos_type == btos) {
                  SET_STACK_INT(obj->byte_field_acquire(field_offset), -1);
                } else if (tos_type == ctos) {
                  SET_STACK_INT(obj->char_field_acquire(field_offset), -1);
                } else if (tos_type == stos) {
                  SET_STACK_INT(obj->short_field_acquire(field_offset), -1);
                } else if (tos_type == ftos) {
                  SET_STACK_FLOAT(obj->float_field_acquire(field_offset), -1);
                } else {
                  SET_STACK_DOUBLE(obj->double_field_acquire(field_offset), 0);
                  MORE_STACK(1);
                }
              } else {
                if (tos_type == atos) {
                  VERIFY_OOP(obj->obj_field(field_offset));
                  SET_STACK_OBJECT(obj->obj_field(field_offset), -1);
                } else if (tos_type == itos) {
                  SET_STACK_INT(obj->int_field(field_offset), -1);
                } else if (tos_type == ltos) {
                  SET_STACK_LONG(obj->long_field(field_offset), 0);
                  MORE_STACK(1);
                } else if (tos_type == btos) {
                  SET_STACK_INT(obj->byte_field(field_offset), -1);
                } else if (tos_type == ctos) {
                  SET_STACK_INT(obj->char_field(field_offset), -1);
                } else if (tos_type == stos) {
                  SET_STACK_INT(obj->short_field(field_offset), -1);
                } else if (tos_type == ftos) {
                  SET_STACK_FLOAT(obj->float_field(field_offset), -1);
                } else {
                  SET_STACK_DOUBLE(obj->double_field(field_offset), 0);
                  MORE_STACK(1);
                }
              }
    
              UPDATE_PC_AND_CONTINUE(3);
             }
    
          CASE(_putfield):
          CASE(_putstatic):
            {
              u2 index = Bytes::get_native_u2(pc+1);
              ConstantPoolCacheEntry* cache = cp->entry_at(index);
              if (!cache->is_resolved((Bytecodes::Code)opcode)) {
                CALL_VM(InterpreterRuntime::resolve_get_put(THREAD, (Bytecodes::Code)opcode),
                        handle_exception);
                cache = cp->entry_at(index);
              }
    
    #ifdef VM_JVMTI
              if (_jvmti_interp_events) {
                int *count_addr;
                oop obj;
                // Check to see if a field modification watch has been set
                // before we take the time to call into the VM.
                count_addr = (int *)JvmtiExport::get_field_modification_count_addr();
                if ( *count_addr > 0 ) {
                  if ((Bytecodes::Code)opcode == Bytecodes::_putstatic) {
                    obj = (oop)NULL;
                  }
                  else {
                    if (cache->is_long() || cache->is_double()) {
                      obj = (oop) STACK_OBJECT(-3);
                    } else {
                      obj = (oop) STACK_OBJECT(-2);
                    }
                    VERIFY_OOP(obj);
                  }
    
                  CALL_VM(InterpreterRuntime::post_field_modification(THREAD,
                                              obj,
                                              cache,
                                              (jvalue *)STACK_SLOT(-1)),
                                              handle_exception);
                }
              }
    #endif /* VM_JVMTI */
    
              // 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 = cache->flag_state();
    
              count = -1;
              if (tos_type == ltos || tos_type == dtos) {
                --count;
              }
              if ((Bytecodes::Code)opcode == Bytecodes::_putstatic) {
                Klass* k = cache->f1_as_klass();
                obj = k->java_mirror();
              } else {
                --count;
                obj = (oop) STACK_OBJECT(count);
                CHECK_NULL(obj);
              }
    
              //
              // Now store the result
              //
              int field_offset = cache->f2_as_index();
              if (cache->is_volatile()) {
                if (tos_type == itos) {
                  obj->release_int_field_put(field_offset, STACK_INT(-1));
                } else if (tos_type == atos) {
                  VERIFY_OOP(STACK_OBJECT(-1));
                  obj->release_obj_field_put(field_offset, STACK_OBJECT(-1));
                  OrderAccess::release_store(&BYTE_MAP_BASE[(uintptr_t)obj >> CardTableModRefBS::card_shift], 0);
                } else if (tos_type == btos) {
                  obj->release_byte_field_put(field_offset, STACK_INT(-1));
                } else if (tos_type == ltos) {
                  obj->release_long_field_put(field_offset, STACK_LONG(-1));
                } else if (tos_type == ctos) {
                  obj->release_char_field_put(field_offset, STACK_INT(-1));
                } else if (tos_type == stos) {
                  obj->release_short_field_put(field_offset, STACK_INT(-1));
                } else if (tos_type == ftos) {
                  obj->release_float_field_put(field_offset, STACK_FLOAT(-1));
                } else {
                  obj->release_double_field_put(field_offset, STACK_DOUBLE(-1));
                }
                OrderAccess::storeload();
              } else {
                if (tos_type == itos) {
                  obj->int_field_put(field_offset, STACK_INT(-1));
                } else if (tos_type == atos) {
                  VERIFY_OOP(STACK_OBJECT(-1));
                  obj->obj_field_put(field_offset, STACK_OBJECT(-1));
                  OrderAccess::release_store(&BYTE_MAP_BASE[(uintptr_t)obj >> CardTableModRefBS::card_shift], 0);
                } else if (tos_type == btos) {
                  obj->byte_field_put(field_offset, STACK_INT(-1));
                } else if (tos_type == ltos) {
                  obj->long_field_put(field_offset, STACK_LONG(-1));
                } else if (tos_type == ctos) {
                  obj->char_field_put(field_offset, STACK_INT(-1));
                } else if (tos_type == stos) {
                  obj->short_field_put(field_offset, STACK_INT(-1));
                } else if (tos_type == ftos) {
                  obj->float_field_put(field_offset, STACK_FLOAT(-1));
                } else {
                  obj->double_field_put(field_offset, STACK_DOUBLE(-1));
                }
              }
    
              UPDATE_PC_AND_TOS_AND_CONTINUE(3, count);
            }
    
          CASE(_new): {
            u2 index = Bytes::get_Java_u2(pc+1);
            ConstantPool* constants = istate->method()->constants();
            if (!constants->tag_at(index).is_unresolved_klass()) {
              // Make sure klass is initialized and doesn't have a finalizer
              Klass* entry = constants->slot_at(index).get_klass();
              assert(entry->is_klass(), "Should be resolved klass");
              Klass* k_entry = (Klass*) entry;
              assert(k_entry->oop_is_instance(), "Should be InstanceKlass");
              InstanceKlass* ik = (InstanceKlass*) k_entry;
              if ( ik->is_initialized() && ik->can_be_fastpath_allocated() ) {
                size_t obj_size = ik->size_helper();
                oop result = NULL;
                // If the TLAB isn't pre-zeroed then we'll have to do it
                bool need_zero = !ZeroTLAB;
                if (UseTLAB) {
                  result = (oop) THREAD->tlab().allocate(obj_size);
                }
                if (result == NULL) {
                  need_zero = true;
                  // Try allocate in shared eden
            retry:
                  HeapWord* compare_to = *Universe::heap()->top_addr();
                  HeapWord* new_top = compare_to + obj_size;
                  if (new_top <= *Universe::heap()->end_addr()) {
                    if (Atomic::cmpxchg_ptr(new_top, Universe::heap()->top_addr(), compare_to) != compare_to) {
                      goto retry;
                    }
                    result = (oop) compare_to;
                  }
                }
                if (result != NULL) {
                  // Initialize object (if nonzero size and need) and then the header
                  if (need_zero ) {
                    HeapWord* to_zero = (HeapWord*) result + sizeof(oopDesc) / oopSize;
                    obj_size -= sizeof(oopDesc) / oopSize;
                    if (obj_size > 0 ) {
                      memset(to_zero, 0, obj_size * HeapWordSize);
                    }
                  }
                  if (UseBiasedLocking) {
                    result->set_mark(ik->prototype_header());
                  } else {
                    result->set_mark(markOopDesc::prototype());
                  }
                  result->set_klass_gap(0);
                  result->set_klass(k_entry);
                  SET_STACK_OBJECT(result, 0);
                  UPDATE_PC_AND_TOS_AND_CONTINUE(3, 1);
                }
              }
            }
            // Slow case allocation
            CALL_VM(InterpreterRuntime::_new(THREAD, METHOD->constants(), index),
                    handle_exception);
            SET_STACK_OBJECT(THREAD->vm_result(), 0);
            THREAD->set_vm_result(NULL);
            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);
            SET_STACK_OBJECT(THREAD->vm_result(), -1);
            THREAD->set_vm_result(NULL);
            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);
            SET_STACK_OBJECT(THREAD->vm_result(), -dims);
            THREAD->set_vm_result(NULL);
            UPDATE_PC_AND_TOS_AND_CONTINUE(4, -(dims-1));
          }
          CASE(_checkcast):
              if (STACK_OBJECT(-1) != NULL) {
                VERIFY_OOP(STACK_OBJECT(-1));
                u2 index = Bytes::get_Java_u2(pc+1);
                if (ProfileInterpreter) {
                  // needs Profile_checkcast QQQ
                  ShouldNotReachHere();
                }
                // 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()->slot_at(index).get_klass();
                Klass* objKlassOop = STACK_OBJECT(-1)->klass(); //ebx
                //
                // Check for compatibilty. This check must not GC!!
                // Seems way more expensive now that we must dispatch
                //
                if (objKlassOop != klassOf &&
                    !objKlassOop->is_subtype_of(klassOf)) {
                  ResourceMark rm(THREAD);
                  const char* objName = objKlassOop->external_name();
                  const char* klassName = klassOf->external_name();
                  char* message = SharedRuntime::generate_class_cast_message(
                    objName, klassName);
                  VM_JAVA_ERROR(vmSymbols::java_lang_ClassCastException(), message);
                }
              } else {
                if (UncommonNullCast) {
    //              istate->method()->set_null_cast_seen();
    // [RGV] Not sure what to do here!
    
                }
              }
              UPDATE_PC_AND_CONTINUE(3);
    
          CASE(_instanceof):
              if (STACK_OBJECT(-1) == NULL) {
                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()->slot_at(index).get_klass();
                Klass* objKlassOop = STACK_OBJECT(-1)->klass();
                //
                // Check for compatibilty. This check must not GC!!
                // Seems way more expensive now that we must dispatch
                //
                if ( objKlassOop == klassOf || objKlassOop->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_references()->obj_at(index);
                  if (result == NULL) {
                    CALL_VM(InterpreterRuntime::resolve_ldc(THREAD, (Bytecodes::Code) opcode), handle_exception);
                    SET_STACK_OBJECT(THREAD->vm_result(), 0);
                    THREAD->set_vm_result(NULL);
                  } 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(), 0);
                THREAD->set_vm_result(NULL);
                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;
              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 f1 field 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_references()->obj_at(index);
            if (result == NULL) {
              CALL_VM(InterpreterRuntime::resolve_ldc(THREAD, (Bytecodes::Code) opcode),
                      handle_exception);
              result = THREAD->vm_result();
            }
    
            VERIFY_OOP(result);
            SET_STACK_OBJECT(result, 0);
            UPDATE_PC_AND_TOS_AND_CONTINUE(incr, 1);
          }
    
          CASE(_invokedynamic): {
    
            if (!EnableInvokeDynamic) {
              // We should not encounter this bytecode if !EnableInvokeDynamic.
              // The verifier will stop it.  However, if we get past the verifier,
              // this will stop the thread in a reasonable way, without crashing the JVM.
              CALL_VM(InterpreterRuntime::throw_IncompatibleClassChangeError(THREAD),
                      handle_exception);
              ShouldNotReachHere();
            }
    
            u4 index = Bytes::get_native_u4(pc+1);
            ConstantPoolCacheEntry* cache = cp->constant_pool()->invokedynamic_cp_cache_entry_at(index);
    
            // We are resolved if the resolved_references field 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.
            if (! cache->is_resolved((Bytecodes::Code) opcode)) {
              CALL_VM(InterpreterRuntime::resolve_invokedynamic(THREAD),
                      handle_exception);
              cache = cp->constant_pool()->invokedynamic_cp_cache_entry_at(index);
            }
    
            Method* method = cache->f1_as_method();
            if (VerifyOops) method->verify();
    
            if (cache->has_appendix()) {
              ConstantPool* constants = METHOD->constants();
              SET_STACK_OBJECT(cache->appendix_if_resolved(constants), 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): {
    
            if (!EnableInvokeDynamic) {
              ShouldNotReachHere();
            }
    
            u2 index = Bytes::get_native_u2(pc+1);
            ConstantPoolCacheEntry* cache = cp->entry_at(index);
    
            if (! cache->is_resolved((Bytecodes::Code) opcode)) {
              CALL_VM(InterpreterRuntime::resolve_invokehandle(THREAD),
                      handle_exception);
              cache = cp->entry_at(index);
            }
    
            Method* method = cache->f1_as_method();
            if (VerifyOops) method->verify();
    
            if (cache->has_appendix()) {
              ConstantPool* constants = METHOD->constants();
              SET_STACK_OBJECT(cache->appendix_if_resolved(constants), 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.
    
            ConstantPoolCacheEntry* cache = cp->entry_at(index);
            if (!cache->is_resolved((Bytecodes::Code)opcode)) {
              CALL_VM(InterpreterRuntime::resolve_invoke(THREAD, (Bytecodes::Code)opcode),
                      handle_exception);
              cache = cp->entry_at(index);
            }
    
            istate->set_msg(call_method);
    
            // Special case of invokeinterface called for virtual method of
            // java.lang.Object.  See cpCacheOop.cpp for details.
            // This code isn't produced by javac, but could be produced by
            // another compliant java compiler.
            if (cache->is_forced_virtual()) {
              Method* callee;
              CHECK_NULL(STACK_OBJECT(-(cache->parameter_size())));
              if (cache->is_vfinal()) {
                callee = cache->f2_as_vfinal_method();
              } else {
                // get receiver
                int parms = cache->parameter_size();
                // Same comments as invokevirtual apply here
                VERIFY_OOP(STACK_OBJECT(-parms));
                InstanceKlass* rcvrKlass = (InstanceKlass*)
                                     STACK_OBJECT(-parms)->klass();
                callee = (Method*) rcvrKlass->start_of_vtable()[ cache->f2_as_index()];
              }
              istate->set_callee(callee);
              istate->set_callee_entry_point(callee->from_interpreted_entry());
    #ifdef VM_JVMTI
              if (JvmtiExport::can_post_interpreter_events() && THREAD->is_interp_only_mode()) {
                istate->set_callee_entry_point(callee->interpreter_entry());
              }
    #endif /* VM_JVMTI */
              istate->set_bcp_advance(5);
              UPDATE_PC_AND_RETURN(0); // I'll be back...
            }
    
            // this could definitely be cleaned up QQQ
            Method* callee;
            Klass* iclass = cache->f1_as_klass();
            // InstanceKlass* interface = (InstanceKlass*) iclass;
            // get receiver
            int parms = cache->parameter_size();
            oop rcvr = STACK_OBJECT(-parms);
            CHECK_NULL(rcvr);
            InstanceKlass* int2 = (InstanceKlass*) rcvr->klass();
            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()) {
              VM_JAVA_ERROR(vmSymbols::java_lang_IncompatibleClassChangeError(), "");
            }
            int mindex = cache->f2_as_index();
            itableMethodEntry* im = ki->first_method_entry(rcvr->klass());
            callee = im[mindex].method();
            if (callee == NULL) {
              VM_JAVA_ERROR(vmSymbols::java_lang_AbstractMethodError(), "");
            }
    
            istate->set_callee(callee);
            istate->set_callee_entry_point(callee->from_interpreted_entry());
    #ifdef VM_JVMTI
            if (JvmtiExport::can_post_interpreter_events() && THREAD->is_interp_only_mode()) {
              istate->set_callee_entry_point(callee->interpreter_entry());
            }
    #endif /* VM_JVMTI */
            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);
    
            ConstantPoolCacheEntry* cache = cp->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 (!cache->is_resolved((Bytecodes::Code)opcode)) {
              CALL_VM(InterpreterRuntime::resolve_invoke(THREAD, (Bytecodes::Code)opcode),
                      handle_exception);
              cache = cp->entry_at(index);
            }
    
            istate->set_msg(call_method);
            {
              Method* callee;
              if ((Bytecodes::Code)opcode == Bytecodes::_invokevirtual) {
                CHECK_NULL(STACK_OBJECT(-(cache->parameter_size())));
                if (cache->is_vfinal()) callee = cache->f2_as_vfinal_method();
                else {
                  // get receiver
                  int parms = cache->parameter_size();
                  // 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
                  VERIFY_OOP(STACK_OBJECT(-parms));
                  InstanceKlass* rcvrKlass = (InstanceKlass*) STACK_OBJECT(-parms)->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()->oop_is_instance() == 0
                      However it seems to have a vtable in the right location. Huh?
    
                  */
                  callee = (Method*) rcvrKlass->start_of_vtable()[ cache->f2_as_index()];
                }
              } else {
                if ((Bytecodes::Code)opcode == Bytecodes::_invokespecial) {
                  CHECK_NULL(STACK_OBJECT(-(cache->parameter_size())));
                }
                callee = cache->f1_as_method();
              }
    
              istate->set_callee(callee);
              istate->set_callee_entry_point(callee->from_interpreted_entry());
    #ifdef VM_JVMTI
              if (JvmtiExport::can_post_interpreter_events() && THREAD->is_interp_only_mode()) {
                istate->set_callee_entry_point(callee->interpreter_entry());
              }
    #endif /* VM_JVMTI */
              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);
            SET_STACK_OBJECT(THREAD->vm_result(), -1);
            THREAD->set_vm_result(NULL);
    
            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, NULL, 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;
          }
    
          DEFAULT:
              fatal(err_msg("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 */
    

    可以看到,opcode 就是字节码指令中的操作数,根据操作码的不同,case 会进行匹配,调用对应的执行方法。

    相关文章

      网友评论

          本文标题:JVM 解释执行

          本文链接:https://www.haomeiwen.com/subject/mbtkwhtx.html