Logo Search packages:      
Sourcecode: jamvm version File versions

interp.c

/*
 * Copyright (C) 2003, 2004 Robert Lougher <rob@lougher.demon.co.uk>.
 *
 * This file is part of JamVM.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2,
 * or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#define _GNU_SOURCE
#include <stdio.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <limits.h>

#include "jam.h"
#include "thread.h"
#include "lock.h"

#define CP_SINDEX(p)  p[1]
#define CP_DINDEX(p)  (p[1]<<8)|p[2]
#define BRANCH(p)     (((signed char)p[1])<<8)|p[2]
#define BRANCH_W(p)   (((signed char)p[1])<<24)|(p[2]<<16)|(p[3]<<8)|p[4]
#define DSIGNED(p)    (((signed char)p[1])<<8)|p[2]

#define THROW_EXCEPTION(excep_name, message)                          \
{                                                                     \
    frame->last_pc = (unsigned char*)pc;                              \
    signalException(excep_name, message);                             \
    goto throwException;                                              \
}

#define NULL_POINTER_CHECK(ref)                                       \
    if(!ref)                                                          \
        THROW_EXCEPTION("java/lang/NullPointerException", NULL);

#define ARRAY_BOUNDS_CHECK(array, i)                                  \
    if(i >= *INST_DATA(array))                                        \
        THROW_OUT_OF_BOUNDS_EXCEPTION(i);

#define THROW_OUT_OF_BOUNDS_EXCEPTION(index)                          \
{                                                                     \
    char buff[10];                                                    \
    snprintf(buff, 10, "%d", index);                                  \
    THROW_EXCEPTION("java/lang/ArrayIndexOutOfBoundsException", buff);\
}

#define WITH_OPCODE_CHANGE_CP_DINDEX(pc, opcode, index)               \
    index = CP_DINDEX(pc);                                            \
    if(pc[0] != opcode)                                               \
        DISPATCH(0, 0);

#define OPCODE_REWRITE(pc, opcode)                                    \
    pc[0] = opcode 

#define OPCODE_REWRITE_OPERAND1(pc, opcode, operand1)                 \
{                                                                     \
    pc[0] = OPC_LOCK;                                                 \
    pc[1] = operand1;                                                 \
    pc[0] = opcode;                                                   \
}

#define OPCODE_REWRITE_OPERAND2(pc, opcode, operand1, operand2)       \
{                                                                     \
    pc[0] = OPC_LOCK;                                                 \
    pc[1] = operand1;                                                 \
    pc[2] = operand2;                                                 \
    pc[0] = opcode;                                                   \
}

#ifdef THREADED
/* Two levels of macros are needed to correctly produce the label
 * from the OPC_xxx macro passed into DEF_OPC as cpp doesn't 
 * prescan when concatenating with ##...
 *
 * On gcc <= 2.95, we also get a space inserted before the :
 * e.g DEF_OPC(OPC_NULL) -> opc0 : - the ##: is a hack to fix
 * this, but this generates warnings on >= 2.96...
 */
#if (__GNUC__ == 2) && (__GNUC_MINOR__ <= 95)
#define label(x, y)              \
opc##x##_##y##:
#else
#define label(x, y)              \
opc##x##_##y:
#endif

#define DEF_OPC(opcode, level)   \
label(opcode, level)

#define DISPATCH(level, ins_len) \
{                                \
    pc += ins_len;               \
    goto *handlers_##level[*pc]; \
}

#else /* THREADED */

#define DEF_OPC(opcode, level)   \
    case opcode:

#define DISPATCH(level, ins_len) \
{                                \
    pc += ins_len;               \
    break;                       \
}
#endif

u4 *executeJava() {
    ExecEnv *ee = getExecEnv();
    Frame *frame = ee->last_frame;
    MethodBlock *mb = frame->mb;
    u4 *lvars = frame->lvars;
    u4 *ostack = frame->ostack;
    volatile unsigned char *pc = mb->code;
    ConstantPool *cp = &(CLASS_CB(mb->class)->constant_pool);

    Object *this = (Object*)lvars[0];
    Class *new_class;
    MethodBlock *new_mb;
    u4 *arg1;

#ifdef USE_CACHE
    union {
        struct {
            int v1;
            int v2;
        } i;
        long long l;
    } cache;
#endif

#ifdef THREADED
#define L(opcode, level) &&opc##opcode##_##level

#define DEF_HANDLER_TABLE(level)                                              \
    void *handlers_##level[] = {                                              \
        L(0,level), L(1,level), L(2,level), L(3,level), L(4,level),           \
        L(5,level), L(6,level), L(7,level), L(8,level), L(9,level),           \
        L(10,level), L(11,level), L(12,level), L(13,level), L(14,level),      \
        L(15,level), L(16,level), L(17,level), L(18,level), L(19,level),      \
        L(20,level), L(21,level), L(22,level), L(23,level), L(24,level),      \
        L(25,level), L(26,level), L(27,level), L(28,level), L(29,level),      \
        L(30,level), L(31,level), L(32,level), L(33,level), L(34,level),      \
        L(35,level), L(36,level), L(37,level), L(38,level), L(39,level),      \
        L(40,level), L(41,level), L(42,level), L(43,level), L(44,level),      \
        L(45,level), L(46,level), L(47,level), L(48,level), L(49,level),      \
        L(50,level), L(51,level), L(52,level), L(53,level), L(54,level),      \
        L(55,level), L(56,level), L(57,level), L(58,level), L(59,level),      \
        L(60,level), L(61,level), L(62,level), L(63,level), L(64,level),      \
        L(65,level), L(66,level), L(67,level), L(68,level), L(69,level),      \
        L(70,level), L(71,level), L(72,level), L(73,level), L(74,level),      \
        L(75,level), L(76,level), L(77,level), L(78,level), L(79,level),      \
        L(80,level), L(81,level), L(82,level), L(83,level), L(84,level),      \
        L(85,level), L(86,level), L(87,level), L(88,level), L(89,level),      \
        L(90,level), L(91,level), L(92,level), L(93,level), L(94,level),      \
        L(95,level), L(96,level), L(97,level), L(98,level), L(99,level),      \
        L(100,level), L(101,level), L(102,level), L(103,level), L(104,level), \
        L(105,level), L(106,level), L(107,level), L(108,level), L(109,level), \
        L(110,level), L(111,level), L(112,level), L(113,level), L(114,level), \
        L(115,level), L(116,level), L(117,level), L(118,level), L(119,level), \
        L(120,level), L(121,level), L(122,level), L(123,level), L(124,level), \
        L(125,level), L(126,level), L(127,level), L(128,level), L(129,level), \
        L(130,level), L(131,level), L(132,level), L(133,level), L(134,level), \
        L(135,level), L(136,level), L(137,level), L(138,level), L(139,level), \
        L(140,level), L(141,level), L(142,level), L(143,level), L(144,level), \
        L(145,level), L(146,level), L(147,level), L(148,level), L(149,level), \
        L(150,level), L(151,level), L(152,level), L(153,level), L(154,level), \
        L(155,level), L(156,level), L(157,level), L(158,level), L(159,level), \
        L(160,level), L(161,level), L(162,level), L(163,level), L(164,level), \
        L(165,level), L(166,level), L(167,level), L(168,level), L(169,level), \
        L(170,level), L(171,level), L(172,level), L(173,level), L(174,level), \
        L(175,level), L(176,level), L(177,level), L(178,level), L(179,level), \
        L(180,level), L(181,level), L(182,level), L(183,level), L(184,level), \
        L(185,level), &&unused, L(187,level), L(188,level), L(189,level),     \
        L(190,level), L(191,level), L(192,level), L(193,level), L(194,level), \
        L(195,level), L(196,level), L(197,level), L(198,level), L(199,level), \
        L(200,level), L(201,level), &&unused, L(203,level), L(204,level),     \
        &&unused, L(206,level), L(207,level), L(208,level), L(209,level),     \
        L(210,level), L(211,level), L(212,level), L(213,level), L(214,level), \
        L(215,level), L(216,level), &&unused, &&unused, &&unused, &&unused,   \
        &&unused, &&unused, &&unused, &&unused, &&unused, L(226,level),       \
        L(227,level), L(228,level), L(229,level), L(230,level), L(231,level), \
        L(232,level), L(233,level), &&unused, L(235,level), &&unused,         \
        &&unused, L(238,level), L(239,level), &&unused, &&unused, &&unused,   \
        L(243,level), L(244,level), &&unused, &&unused, &&unused, &&unused,   \
        &&unused, &&unused, &&unused, &&unused, &&unused, &&unused, &&unused};

    DEF_HANDLER_TABLE(0);

#ifdef USE_CACHE
    DEF_HANDLER_TABLE(1);
    DEF_HANDLER_TABLE(2);
#endif

    DISPATCH(0, 0);

#else /* THREADED */

    while(TRUE) {
        switch(*pc) {
            default:
#endif

unused:
    printf("Unrecognised opcode %d in: %s.%s\n", *pc, CLASS_CB(mb->class)->name, mb->name);
    exitVM(1);

#define MULTI_LEVEL_OPCODES(level)                         \
    DEF_OPC(OPC_ICONST_M1, level)                          \
        PUSH_##level(-1, 1);                               \
                                                           \
    DEF_OPC(OPC_ACONST_NULL, level)                        \
    DEF_OPC(OPC_ICONST_0, level)                           \
    DEF_OPC(OPC_FCONST_0, level)                           \
        PUSH_##level(0, 1);                                \
                                                           \
    DEF_OPC(OPC_ICONST_1, level)                           \
        PUSH_##level(1, 1);                                \
                                                           \
    DEF_OPC(OPC_ICONST_2, level)                           \
        PUSH_##level(2, 1);                                \
                                                           \
    DEF_OPC(OPC_ICONST_3, level)                           \
        PUSH_##level(3, 1);                                \
                                                           \
    DEF_OPC(OPC_ICONST_4, level)                           \
        PUSH_##level(4, 1);                                \
                                                           \
    DEF_OPC(OPC_ICONST_5, level)                           \
        PUSH_##level(5, 1);                                \
                                                           \
    DEF_OPC(OPC_FCONST_1, level)                           \
        PUSH_##level(0x3f800000, 1);                       \
                                                           \
    DEF_OPC(OPC_FCONST_2, level)                           \
        PUSH_##level(0x40000000, 1);                       \
                                                           \
    DEF_OPC(OPC_SIPUSH, level)                             \
        PUSH_##level((signed short)((pc[1]<<8)+pc[2]), 3); \
                                                           \
    DEF_OPC(OPC_BIPUSH, level)                             \
        PUSH_##level((signed char)pc[1], 2);               \
                                                           \
    DEF_OPC(OPC_LDC_QUICK, level)                          \
        PUSH_##level(CP_INFO(cp, CP_SINDEX(pc)), 2);       \
                                                           \
    DEF_OPC(OPC_LDC_W_QUICK, level)                        \
        PUSH_##level(CP_INFO(cp, CP_DINDEX(pc)), 3);       \
                                                           \
    DEF_OPC(OPC_ILOAD, level)                              \
    DEF_OPC(OPC_FLOAD, level)                              \
    DEF_OPC(OPC_ALOAD, level)                              \
        PUSH_##level(lvars[CP_SINDEX(pc)], 2);             \
                                                           \
    DEF_OPC(OPC_ALOAD_THIS, level)                         \
        if(pc[1] == OPC_GETFIELD_QUICK) {                  \
            OPCODE_REWRITE(pc, OPC_GETFIELD_THIS);         \
            DISPATCH(level, 0);                            \
        }                                                  \
                                                           \
    DEF_OPC(OPC_ILOAD_0, level)                            \
    DEF_OPC(OPC_FLOAD_0, level)                            \
        PUSH_##level(lvars[0], 1);                         \
                                                           \
    DEF_OPC(OPC_ILOAD_1, level)                            \
    DEF_OPC(OPC_FLOAD_1, level)                            \
    DEF_OPC(OPC_ALOAD_1, level)                            \
        PUSH_##level(lvars[1], 1);                         \
                                                           \
    DEF_OPC(OPC_ILOAD_2, level)                            \
    DEF_OPC(OPC_FLOAD_2, level)                            \
    DEF_OPC(OPC_ALOAD_2, level)                            \
        PUSH_##level(lvars[2], 1);                         \
                                                           \
    DEF_OPC(OPC_ILOAD_3, level)                            \
    DEF_OPC(OPC_FLOAD_3, level)                            \
    DEF_OPC(OPC_ALOAD_3, level)                            \
        PUSH_##level(lvars[3], 1);                         \
                                                           \
    DEF_OPC(OPC_ISTORE, level)                             \
    DEF_OPC(OPC_FSTORE, level)                             \
    DEF_OPC(OPC_ASTORE, level)                             \
        POP_##level(lvars[CP_SINDEX(pc)], 2);              \
                                                           \
    DEF_OPC(OPC_ISTORE_0, level)                           \
    DEF_OPC(OPC_ASTORE_0, level)                           \
    DEF_OPC(OPC_FSTORE_0, level)                           \
        POP_##level(lvars[0], 1);                          \
                                                           \
    DEF_OPC(OPC_ISTORE_1, level)                           \
    DEF_OPC(OPC_ASTORE_1, level)                           \
    DEF_OPC(OPC_FSTORE_1, level)                           \
        POP_##level(lvars[1], 1);                          \
                                                           \
    DEF_OPC(OPC_ISTORE_2, level)                           \
    DEF_OPC(OPC_ASTORE_2, level)                           \
    DEF_OPC(OPC_FSTORE_2, level)                           \
        POP_##level(lvars[2], 1);                          \
                                                           \
    DEF_OPC(OPC_ISTORE_3, level)                           \
    DEF_OPC(OPC_ASTORE_3, level)                           \
    DEF_OPC(OPC_FSTORE_3, level)                           \
        POP_##level(lvars[3], 1);                          \
                                                           \
    DEF_OPC(OPC_IADD, level)                               \
        BINARY_OP_##level(+);                              \
                                                           \
    DEF_OPC(OPC_ISUB, level)                               \
        BINARY_OP_##level(-);                              \
                                                           \
    DEF_OPC(OPC_IMUL, level)                               \
        BINARY_OP_##level(*);                              \
                                                           \
    DEF_OPC(OPC_IDIV, level)                               \
        ZERO_DIVISOR_CHECK_##level;                        \
        BINARY_OP_##level(/);                              \
                                                           \
    DEF_OPC(OPC_IREM, level)                               \
        ZERO_DIVISOR_CHECK_##level;                        \
        BINARY_OP_##level(%);                              \
                                                           \
    DEF_OPC(OPC_IAND, level)                               \
        BINARY_OP_##level(&);                              \
                                                           \
    DEF_OPC(OPC_IOR, level)                                \
        BINARY_OP_##level(|);                              \
                                                           \
    DEF_OPC(OPC_IXOR, level)                               \
        BINARY_OP_##level(^);                              \
                                                           \
    DEF_OPC(OPC_INEG, level)                               \
        UNARY_MINUS_##level;                               \
                                                           \
    DEF_OPC(OPC_ISHL, level)                               \
        SHIFT_OP_##level(int, <<);                         \
                                                           \
    DEF_OPC(OPC_ISHR, level)                               \
        SHIFT_OP_##level(int, >>);                         \
                                                           \
    DEF_OPC(OPC_IUSHR, level)                              \
        SHIFT_OP_##level(unsigned int, >>);                \
                                                           \
    DEF_OPC(OPC_IF_ACMPEQ, level)                          \
    DEF_OPC(OPC_IF_ICMPEQ, level)                          \
        IF_ICMP_##level(==);                               \
                                                           \
    DEF_OPC(OPC_IF_ACMPNE, level)                          \
    DEF_OPC(OPC_IF_ICMPNE, level)                          \
        IF_ICMP_##level(!=);                               \
                                                           \
    DEF_OPC(OPC_IF_ICMPLT, level)                          \
        IF_ICMP_##level(<);                                \
                                                           \
    DEF_OPC(OPC_IF_ICMPGE, level)                          \
        IF_ICMP_##level(>=);                               \
                                                           \
    DEF_OPC(OPC_IF_ICMPGT, level)                          \
        IF_ICMP_##level(>);                                \
                                                           \
    DEF_OPC(OPC_IF_ICMPLE, level)                          \
        IF_ICMP_##level(<=);                               \
                                                           \
    DEF_OPC(OPC_IFNE, level)                               \
    DEF_OPC(OPC_IFNONNULL, level)                          \
        IF_##level(!=);                                    \
                                                           \
    DEF_OPC(OPC_IFEQ, level)                               \
    DEF_OPC(OPC_IFNULL, level)                             \
        IF_##level(==);                                    \
                                                           \
    DEF_OPC(OPC_IFLT, level)                               \
        IF_##level(<);                                     \
                                                           \
    DEF_OPC(OPC_IFGE, level)                               \
        IF_##level(>=);                                    \
                                                           \
    DEF_OPC(OPC_IFGT, level)                               \
        IF_##level(>);                                     \
                                                           \
    DEF_OPC(OPC_IFLE, level)                               \
        IF_##level(<=);                                    \
                                                           \
    DEF_OPC(OPC_IINC, level)                               \
        lvars[CP_SINDEX(pc)] += (signed char)pc[2];        \
        DISPATCH(level, 3);                                \
                                                           \
    DEF_OPC(OPC_POP, level)                                \
        POP1_##level;                                      \
                                                           \
    DEF_OPC(OPC_POP2, level)                               \
        ostack -= 2 - level;                               \
        DISPATCH(0, 1);                                    \
                                                           \
    DEF_OPC(OPC_DUP, level)                                \
        DUP_##level;                                       \
                                                           \
    DEF_OPC(OPC_IRETURN, level)                            \
    DEF_OPC(OPC_ARETURN, level)                            \
    DEF_OPC(OPC_FRETURN, level)                            \
        RETURN_##level;                                    \
                                                           \
    DEF_OPC(OPC_RETURN, level)                             \
        goto methodReturn;                                 \
                                                           \
    DEF_OPC(OPC_GETSTATIC_QUICK, level)                    \
        PUSH_##level(((FieldBlock *)                       \
            CP_INFO(cp, CP_DINDEX(pc)))->static_value, 3); \
                                                           \
    DEF_OPC(OPC_PUTSTATIC_QUICK, level)                    \
        POP_##level(((FieldBlock *)                        \
            CP_INFO(cp, CP_DINDEX(pc)))->static_value, 3); \
                                                           \
    DEF_OPC(OPC_GETFIELD_THIS, level)                      \
        PUSH_##level(INST_DATA(this)[pc[2]], 4);           \
                                                           \
    DEF_OPC(OPC_GETFIELD_QUICK, level)                     \
        GETFIELD_QUICK_##level;

#define ZERO_DIVISOR_CHECK(value)                          \
    if(value == 0)                                         \
        THROW_EXCEPTION("java/lang/ArithmeticException",   \
                        "division by zero");

#define ZERO_DIVISOR_CHECK_0                               \
    ZERO_DIVISOR_CHECK(ostack[-1]);

#define ZERO_DIVISOR_CHECK_1                               \
    ZERO_DIVISOR_CHECK(cache.i.v1);

#define ZERO_DIVISOR_CHECK_2                               \
    ZERO_DIVISOR_CHECK(cache.i.v2);

#ifdef USE_CACHE
#define PUSH_0(value, ins_len)                             \
    cache.i.v1 = value;                                    \
    DISPATCH(1, ins_len);
#else
#define PUSH_0(value, ins_len)                             \
    *ostack++ = value;                                     \
    DISPATCH(0, ins_len);
#endif

#define PUSH_1(value, ins_len)                             \
    cache.i.v2 = value;                                    \
    DISPATCH(2, ins_len);

#define PUSH_2(value, ins_len)                             \
    *ostack++ = cache.i.v1;                                \
    cache.i.v1 = cache.i.v2;                               \
    cache.i.v2 = value;                                    \
    DISPATCH(2, ins_len);

#define POP_0(dest, ins_len)                               \
    dest = *--ostack;                                      \
    DISPATCH(0, ins_len);

#define POP_1(dest, ins_len)                               \
    dest = cache.i.v1;                                     \
    DISPATCH(0, ins_len);

#define POP_2(dest, ins_len)                               \
    dest = cache.i.v2;                                     \
    DISPATCH(1, ins_len);

#define POP1_0                                             \
    ostack--;                                              \
    DISPATCH(0, 1);

#define POP1_1                                             \
    DISPATCH(0, 1);

#define POP1_2                                             \
    DISPATCH(1, 1);

#define DUP_0                                              \
    PUSH_0(ostack[-1], 1);

#define DUP_1                                              \
    PUSH_1(cache.i.v1, 1);

#define DUP_2                                              \
    PUSH_2(cache.i.v2, 1);

#define RETURN_0                                           \
    *lvars++ = *--ostack;                                  \
    goto methodReturn;

#define RETURN_1                                           \
    *lvars++ = cache.i.v1;                                 \
    goto methodReturn;

#define RETURN_2                                           \
    *lvars++ = cache.i.v2;                                 \
    goto methodReturn;

#define GETFIELD_QUICK_0                                   \
{                                                          \
    Object *obj = (Object *)*--ostack;                     \
    NULL_POINTER_CHECK(obj);                               \
    PUSH_0(INST_DATA(obj)[pc[1]], 3);                      \
}

#define GETFIELD_QUICK_1                                   \
{                                                          \
    Object *obj = (Object *)cache.i.v1;                    \
    NULL_POINTER_CHECK(obj);                               \
    PUSH_0(INST_DATA(obj)[pc[1]], 3);                      \
}

#define GETFIELD_QUICK_2                                   \
{                                                          \
    Object *obj = (Object *)cache.i.v2;                    \
    NULL_POINTER_CHECK(obj);                               \
    PUSH_1(INST_DATA(obj)[pc[1]], 3);                      \
}

#define UNARY_MINUS_0                                      \
{                                                          \
    int v = (int)*--ostack;                                \
    PUSH_0(-v, 1);                                         \
}

#define UNARY_MINUS_1                                      \
    PUSH_0(-cache.i.v1, 1);

#define UNARY_MINUS_2                                      \
    PUSH_1(-cache.i.v2, 1);

#define BINARY_OP_0(OP)                                    \
    ostack -= 2;                                           \
    PUSH_0((int)ostack[0] OP (int)ostack[1], 1);

#define BINARY_OP_1(OP)                                    \
    PUSH_0((int)*--ostack OP cache.i.v1, 1);

#define BINARY_OP_2(OP)                                    \
    PUSH_0(cache.i.v1 OP cache.i.v2, 1);

#define SHIFT_OP_0(TYPE, OP)                               \
    ostack -= 2;                                           \
    PUSH_0((TYPE)ostack[0] OP ((int)ostack[1] & 0x1f), 1);

#define SHIFT_OP_1(TYPE, OP)                               \
    PUSH_0((TYPE)*--ostack OP (cache.i.v1 & 0x1f), 1);

#define SHIFT_OP_2(TYPE, OP)                               \
    PUSH_0((TYPE)cache.i.v1 OP (cache.i.v2 & 0x1f), 1);

#define IF_ICMP_0(COND)                                    \
    ostack -= 2;                                           \
    DISPATCH(0, ((int)ostack[0] COND (int)ostack[1]) ?     \
                               BRANCH(pc) : 3);

#define IF_ICMP_1(COND)                                    \
    DISPATCH(0, ((int)*--ostack COND cache.i.v1) ?         \
                               BRANCH(pc) : 3);

#define IF_ICMP_2(COND)                                    \
    DISPATCH(0, (cache.i.v1 COND cache.i.v2) ?             \
                               BRANCH(pc) : 3);

#define IF_0(COND)                                         \
    DISPATCH(0, ((int)*--ostack COND 0) ? BRANCH(pc) : 3);

#define IF_1(COND)                                         \
    DISPATCH(0, (cache.i.v1 COND 0) ? BRANCH(pc) : 3);

#define IF_2(COND)                                         \
    DISPATCH(1, (cache.i.v2 COND 0) ? BRANCH(pc) : 3);

    MULTI_LEVEL_OPCODES(0);

#ifdef USE_CACHE
    MULTI_LEVEL_OPCODES(1);
    MULTI_LEVEL_OPCODES(2);

#define DEF_OPC_012(opcode)           \
    DEF_OPC(opcode, 0)                \
        cache.i.v1 = *--ostack;       \
                                      \
    DEF_OPC(opcode, 1)                \
        cache.i.v2 = cache.i.v1;      \
        cache.i.v1 = *--ostack;       \
                                      \
    DEF_OPC(opcode, 2)

#define DEF_OPC_012_2(op1, op2)       \
    DEF_OPC(op1, 0)                   \
    DEF_OPC(op2, 0)                   \
        cache.i.v1 = *--ostack;       \
                                      \
    DEF_OPC(op1, 1)                   \
    DEF_OPC(op2, 1)                   \
        cache.i.v2 = cache.i.v1;      \
        cache.i.v1 = *--ostack;       \
                                      \
    DEF_OPC(op1, 2)                   \
    DEF_OPC(op2, 2)

#define DEF_OPC_012_3(op1, op2, op3)  \
    DEF_OPC(op1, 0)                   \
    DEF_OPC(op2, 0)                   \
    DEF_OPC(op3, 0)                   \
        cache.i.v1 = *--ostack;       \
                                      \
    DEF_OPC(op1, 1)                   \
    DEF_OPC(op2, 1)                   \
    DEF_OPC(op3, 1)                   \
        cache.i.v2 = cache.i.v1;      \
        cache.i.v1 = *--ostack;       \
                                      \
    DEF_OPC(op1, 2)                   \
    DEF_OPC(op2, 2)                   \
    DEF_OPC(op3, 2)

#define DEF_OPC_210(opcode)           \
    DEF_OPC(opcode, 2)                \
        *ostack++ = cache.i.v1;       \
        cache.i.v1 = cache.i.v2;      \
                                      \
    DEF_OPC(opcode, 1)                \
        *ostack++ = cache.i.v1;       \
                                      \
    DEF_OPC(opcode, 0)

#define DEF_OPC_210_2(op1, op2)       \
    DEF_OPC(op1, 2)                   \
    DEF_OPC(op2, 2)                   \
        *ostack++ = cache.i.v1;       \
        cache.i.v1 = cache.i.v2;      \
                                      \
    DEF_OPC(op1, 1)                   \
    DEF_OPC(op2, 1)                   \
        *ostack++ = cache.i.v1;       \
                                      \
    DEF_OPC(op1, 0)                   \
    DEF_OPC(op2, 0)

#define DEF_OPC_210_5(op1, op2, op3, op4, op5) \
    DEF_OPC(op1, 2)                            \
    DEF_OPC(op2, 2)                            \
    DEF_OPC(op3, 2)                            \
    DEF_OPC(op4, 2)                            \
    DEF_OPC(op5, 2)                            \
        *ostack++ = cache.i.v1;                \
        cache.i.v1 = cache.i.v2;               \
                                               \
    DEF_OPC(op1, 1)                            \
    DEF_OPC(op2, 1)                            \
    DEF_OPC(op3, 1)                            \
    DEF_OPC(op4, 1)                            \
    DEF_OPC(op5, 1)                            \
        *ostack++ = cache.i.v1;                \
                                               \
    DEF_OPC(op1, 0)                            \
    DEF_OPC(op2, 0)                            \
    DEF_OPC(op3, 0)                            \
    DEF_OPC(op4, 0)                            \
    DEF_OPC(op5, 0)

#else /* USE_CACHE */

#define DEF_OPC_012(opcode)           \
    DEF_OPC(opcode, 0)

#define DEF_OPC_012_2(op1, op2)       \
    DEF_OPC(op1, 0)                   \
    DEF_OPC(op2, 0)

#define DEF_OPC_012_3(op1, op2, op3)  \
    DEF_OPC(op1, 0)                   \
    DEF_OPC(op2, 0)                   \
    DEF_OPC(op3, 0)

#define DEF_OPC_210(opcode)           \
    DEF_OPC(opcode, 0)

#define DEF_OPC_210_2(op1, op2)       \
    DEF_OPC(op1, 0)                   \
    DEF_OPC(op2, 0)

#define DEF_OPC_210_5(op1, op2, op3, op4, op5) \
    DEF_OPC(op1, 0)                            \
    DEF_OPC(op2, 0)                            \
    DEF_OPC(op3, 0)                            \
    DEF_OPC(op4, 0)                            \
    DEF_OPC(op5, 0)

#endif /* USE_CACHE */

    DEF_OPC_210(OPC_NOP)
        DISPATCH(0, 1);

    DEF_OPC_210(OPC_LDC)
        frame->last_pc = (unsigned char*)pc;

        resolveSingleConstant(mb->class, CP_SINDEX(pc));

        if(exceptionOccured0(ee))
            goto throwException;

        OPCODE_REWRITE(pc, OPC_LDC_QUICK);
        DISPATCH(0, 0);

    DEF_OPC_210(OPC_LDC_W)
        frame->last_pc = (unsigned char*)pc;

        resolveSingleConstant(mb->class, CP_DINDEX(pc));

        if(exceptionOccured0(ee))
            goto throwException;

        OPCODE_REWRITE(pc, OPC_LDC_W_QUICK);
        DISPATCH(0, 0);

    DEF_OPC_210(OPC_ALOAD_0)
      if(mb->access_flags & ACC_STATIC)
            OPCODE_REWRITE(pc, OPC_ILOAD_0);
      else
            OPCODE_REWRITE(pc, OPC_ALOAD_THIS);
        DISPATCH(0, 0);

#ifdef USE_CACHE
#define PUSH_LONG(value, ins_len) \
    cache.l = value;              \
    DISPATCH(2, ins_len);
#else
#define PUSH_LONG(value, ins_len) \
    *(u8*)ostack = value;         \
    ostack += 2;                  \
    DISPATCH(0, ins_len);
#endif
    
    DEF_OPC_210_2(
            OPC_LCONST_0,
            OPC_DCONST_0)
        PUSH_LONG(0, 1);

    DEF_OPC_210(OPC_DCONST_1)
        PUSH_LONG(0x3ff0000000000000LL, 1);

    DEF_OPC_210(OPC_LCONST_1)
        PUSH_LONG(1, 1);

    DEF_OPC_210(OPC_LDC2_W)
        PUSH_LONG(CP_LONG(cp, CP_DINDEX(pc)), 3);

    DEF_OPC_210_2(
            OPC_LLOAD,
            OPC_DLOAD)
        PUSH_LONG(*(u8*)(&lvars[CP_SINDEX(pc)]), 2);

    DEF_OPC_210_2(
            OPC_LLOAD_0,
            OPC_DLOAD_0)
      PUSH_LONG(*(u8*)(&lvars[0]), 1);

    DEF_OPC_210_2(
            OPC_LLOAD_1,
            OPC_DLOAD_1)
      PUSH_LONG(*(u8*)(&lvars[1]), 1);

    DEF_OPC_210_2(
            OPC_LLOAD_2,
            OPC_DLOAD_2)
      PUSH_LONG(*(u8*)(&lvars[2]), 1);

    DEF_OPC_210_2(
            OPC_LLOAD_3,
            OPC_DLOAD_3)
      PUSH_LONG(*(u8*)(&lvars[3]), 1);

#ifdef USE_CACHE
#define POP_LONG(dest, ins_len) \
    dest = cache.l;             \
    DISPATCH(0, ins_len);
#else
#define POP_LONG(dest, ins_len) \
    ostack -= 2;                \
    dest = *(u8*)ostack;        \
    DISPATCH(0, ins_len);
#endif

    DEF_OPC_012_2(
            OPC_LSTORE,
            OPC_DSTORE)
      POP_LONG(*(u8*)(&lvars[CP_SINDEX(pc)]), 2);

    DEF_OPC_012_2(
            OPC_LSTORE_0,
            OPC_DSTORE_0)
        POP_LONG(*(u8*)(&lvars[0]), 1);

    DEF_OPC_012_2(
            OPC_LSTORE_1,
            OPC_DSTORE_1)
        POP_LONG(*(u8*)(&lvars[1]), 1);

    DEF_OPC_012_2(
            OPC_LSTORE_2,
            OPC_DSTORE_2)
        POP_LONG(*(u8*)(&lvars[2]), 1);

    DEF_OPC_012_2(
            OPC_LSTORE_3,
            OPC_DSTORE_3)
        POP_LONG(*(u8*)(&lvars[3]), 1);

#ifdef USE_CACHE
#define ARRAY_LOAD(TYPE)                                 \
{                                                        \
    TYPE *element;                                       \
    int idx = cache.i.v2;                                \
    Object *array = (Object *)cache.i.v1;          \
                                                         \
    NULL_POINTER_CHECK(array);                           \
    ARRAY_BOUNDS_CHECK(array, idx);                      \
    element = (TYPE *)(((char *)INST_DATA(array)) +      \
                              (idx * sizeof(TYPE)) + 4); \
    cache.i.v1 = *element;                               \
    DISPATCH(1, 1);                                      \
}
#else
#define ARRAY_LOAD(TYPE)                                 \
{                                                        \
    TYPE *element;                                       \
    int idx = *--ostack;                                 \
    Object *array = (Object *)*--ostack;           \
                                                         \
    NULL_POINTER_CHECK(array);                           \
    ARRAY_BOUNDS_CHECK(array, idx);                      \
    element = (TYPE *)(((char *)INST_DATA(array)) +      \
                              (idx * sizeof(TYPE)) + 4); \
    *ostack++ = *element;                                \
    DISPATCH(0, 1);                                      \
}
#endif

    DEF_OPC_012_3(
            OPC_IALOAD,
            OPC_AALOAD,
            OPC_FALOAD)
        ARRAY_LOAD(int);

    DEF_OPC_012(OPC_BALOAD)
        ARRAY_LOAD(signed char);

    DEF_OPC_012(OPC_CALOAD)
        ARRAY_LOAD(unsigned short);

    DEF_OPC_012(OPC_SALOAD)
        ARRAY_LOAD(short);

    DEF_OPC_012_2(
            OPC_LALOAD,
            OPC_DALOAD)
    {
#ifdef USE_CACHE
        int idx = cache.i.v2;
        Object *array = (Object *)cache.i.v1;
#else
        int idx = *--ostack;
        Object *array = (Object*)*--ostack;
#endif

        NULL_POINTER_CHECK(array);
        ARRAY_BOUNDS_CHECK(array, idx);
        PUSH_LONG(((u8 *)(INST_DATA(array) + 1))[idx], 1);
    }

#ifdef USE_CACHE
#define ARRAY_STORE(TYPE)                               \
{                                                       \
    int val = cache.i.v2;                       \
    int idx = cache.i.v1;                       \
    Object *array = (Object *)*--ostack;        \
                                                        \
    NULL_POINTER_CHECK(array);                          \
    ARRAY_BOUNDS_CHECK(array, idx);                     \
    *(TYPE *)(((char *)INST_DATA(array)) +              \
                       (idx * sizeof(TYPE)) + 4) = val; \
    DISPATCH(0, 1);                             \
}
#else
#define ARRAY_STORE(TYPE)                               \
{                                                       \
    int val = *--ostack;                        \
    int idx = *--ostack;                        \
    Object *array = (Object *)*--ostack;        \
                                                        \
    NULL_POINTER_CHECK(array);                          \
    ARRAY_BOUNDS_CHECK(array, idx);                     \
    *(TYPE *)(((char *)INST_DATA(array)) +              \
                       (idx * sizeof(TYPE)) + 4) = val; \
    DISPATCH(0, 1);                             \
}
#endif

    DEF_OPC_012_2(
            OPC_IASTORE,
            OPC_FASTORE)
        ARRAY_STORE(int);

    DEF_OPC_012(OPC_BASTORE)
        ARRAY_STORE(char);

    DEF_OPC_012_2(
            OPC_CASTORE,
            OPC_SASTORE)
        ARRAY_STORE(short);

    DEF_OPC_012(OPC_AASTORE)
    { 
#ifdef USE_CACHE
        int idx = cache.i.v1;
        Object *obj = (Object*)cache.i.v2;
#else
        Object *obj = (Object*)*--ostack;
        int idx = *--ostack;
#endif
        Object *array = (Object *)*--ostack;

        NULL_POINTER_CHECK(array);
        ARRAY_BOUNDS_CHECK(array, idx);

        if((obj != NULL) && !arrayStoreCheck(array->class, obj->class))
            THROW_EXCEPTION("java/lang/ArrayStoreException", NULL);

        INST_DATA(array)[idx + 1] = (u4) obj;
        DISPATCH(0, 1);
    }

#ifdef USE_CACHE
    DEF_OPC_012_2(
            OPC_LASTORE,
            OPC_DASTORE)
    {
        int idx = ostack[-1];
        Object *array = (Object *)ostack[-2];

        ostack -= 2;
        NULL_POINTER_CHECK(array);
        ARRAY_BOUNDS_CHECK(array, idx);

        ((u8 *)(INST_DATA(array) + 1))[idx] = cache.l;
        DISPATCH(0, 1);
    }
#else
    DEF_OPC_012_2(
            OPC_LASTORE,
            OPC_DASTORE)
    {
        int idx = ostack[-3];
        Object *array = (Object *)ostack[-4];

        ostack -= 4;
        NULL_POINTER_CHECK(array);
        ARRAY_BOUNDS_CHECK(array, idx);

        ((u8 *)(INST_DATA(array) + 1))[idx] = ((u8*)ostack)[1];
        DISPATCH(0, 1);
    }
#endif

#ifdef USE_CACHE
    DEF_OPC_012(OPC_DUP_X1)
        *ostack++ = cache.i.v2;
        DISPATCH(2, 1);

    DEF_OPC_012(OPC_DUP_X2)
        *ostack++ = ostack[-1];
        ostack[-2] = cache.i.v2;
        DISPATCH(2, 1);

    DEF_OPC_012(OPC_DUP2)
        *(u8*)ostack = cache.l;
        ostack += 2;
        DISPATCH(2, 1);

    DEF_OPC_012(OPC_DUP2_X1)
        ostack[0]  = cache.i.v2;
        ostack[1]  = ostack[-1];
        ostack[-1] = cache.i.v1;
        ostack += 2;
        DISPATCH(2, 1);

    DEF_OPC_012(OPC_DUP2_X2)
        ostack[0] = ostack[-2];
        ostack[1] = ostack[-1];
        ostack[-2] = cache.i.v1;
        ostack[-1] = cache.i.v2;
        ostack += 2;
        DISPATCH(2, 1);

    DEF_OPC_012(OPC_SWAP)
    {
        u4 word1 = cache.i.v1;
        cache.i.v1 = cache.i.v2;
        cache.i.v2 = word1;
        DISPATCH(2, 1);
    }
#else
    DEF_OPC_012(OPC_DUP_X1)
    {
        u4 word1 = ostack[-1];
        u4 word2 = ostack[-2];
        ostack[-2] = word1;
        ostack[-1] = word2;
        *ostack++ = word1;
        DISPATCH(0, 1);
    }

    DEF_OPC_012(OPC_DUP_X2)
    {
        u4 word1 = ostack[-1];
        u4 word2 = ostack[-2];
        u4 word3 = ostack[-3];
        ostack[-3] = word1;
        ostack[-2] = word3;
        ostack[-1] = word2;
        *ostack++ = word1;
        DISPATCH(0, 1);
    }

    DEF_OPC_012(OPC_DUP2)
        *(u8*)ostack = ((u8*)ostack)[-1];
        ostack += 2;
        DISPATCH(0, 1);

    DEF_OPC_012(OPC_DUP2_X1)
    {
        u4 word1 = ostack[-1];
        u4 word2 = ostack[-2];
        u4 word3 = ostack[-3];
        ostack[-3] = word2;
        ostack[-2] = word1;
        ostack[-1] = word3;
        ostack[0]  = word2;
        ostack[1]  = word1;
        ostack += 2;
        DISPATCH(0, 1);
    }

    DEF_OPC_012(OPC_DUP2_X2)
    {
        u4 word1 = ostack[-1];
        u4 word2 = ostack[-2];
        u4 word3 = ostack[-3];
        u4 word4 = ostack[-4];
        ostack[-4] = word2;
        ostack[-3] = word1;
        ostack[-2] = word4;
        ostack[-1] = word3;
        ostack[0]  = word2;
        ostack[1]  = word1;
        ostack += 2;
        DISPATCH(0, 1);
    }

    DEF_OPC_012(OPC_SWAP)
    {
        u4 word1 = ostack[-1];
        ostack[-1] = ostack[-2];
        ostack[-2] = word1;
        DISPATCH(0, 1)
    }
#endif

#define BINARY_OP_fp(TYPE, OP)                                        \
    ((TYPE*)ostack)[-2] = ((TYPE*)ostack)[-2] OP ((TYPE*)ostack)[-1]; \
    ostack -= sizeof(TYPE)/4;                                         \
    DISPATCH(0, 1);

    DEF_OPC_210(OPC_FADD)
        BINARY_OP_fp(float, +);

    DEF_OPC_210(OPC_DADD)
        BINARY_OP_fp(double, +);

    DEF_OPC_210(OPC_FSUB)
        BINARY_OP_fp(float, -);

    DEF_OPC_210(OPC_DSUB)
        BINARY_OP_fp(double, -);

    DEF_OPC_210(OPC_FMUL)
        BINARY_OP_fp(float, *);

    DEF_OPC_210(OPC_DMUL)
        BINARY_OP_fp(double, *);

    DEF_OPC_210(OPC_FDIV)
        BINARY_OP_fp(float, /);

    DEF_OPC_210(OPC_DDIV)
        BINARY_OP_fp(double, /);

#ifdef USE_CACHE
#define BINARY_OP_long(OP)                               \
    cache.l = ((long long*)ostack)[-1] OP cache.l;       \
    ostack -= 2;                                         \
    DISPATCH(2, 1);

#define ZERO_DIVISOR_CHECK_long                          \
    ZERO_DIVISOR_CHECK(cache.l);
#else
#define BINARY_OP_long(OP)                               \
    BINARY_OP_fp(long long, OP)

#define ZERO_DIVISOR_CHECK_long                          \
    ZERO_DIVISOR_CHECK(((u8*)ostack)[-1]);
#endif

    DEF_OPC_012(OPC_LADD)
        BINARY_OP_long(+);

    DEF_OPC_012(OPC_LSUB)
        BINARY_OP_long(-);

    DEF_OPC_012(OPC_LMUL)
        BINARY_OP_long(*);

    DEF_OPC_012(OPC_LDIV)
      ZERO_DIVISOR_CHECK_long;
        BINARY_OP_long(/);

    DEF_OPC_012(OPC_LREM)
      ZERO_DIVISOR_CHECK_long;
        BINARY_OP_long(%);

    DEF_OPC_012(OPC_LAND)
        BINARY_OP_long(&);

    DEF_OPC_012(OPC_LOR)
        BINARY_OP_long(|);

    DEF_OPC_012(OPC_LXOR)
        BINARY_OP_long(^);

#ifdef USE_CACHE
#define SHIFT_OP_long(TYPE, OP)       \
{                                     \
    int shift = cache.i.v2 & 0x3f;    \
    cache.i.v2 = cache.i.v1;          \
    cache.i.v1 = *--ostack;           \
    cache.l = (TYPE)cache.l OP shift; \
    DISPATCH(2, 1);                   \
}
#else
#define SHIFT_OP_long(TYPE, OP)       \
{                                     \
    int shift = *--ostack & 0x3f;     \
    ((TYPE*)ostack)[-1] =             \
        ((TYPE*)ostack)[-1] OP shift; \
    DISPATCH(0, 1);                   \
}
#endif

    DEF_OPC_012(OPC_LSHL)
        SHIFT_OP_long(long long, <<);

    DEF_OPC_012(OPC_LSHR)
        SHIFT_OP_long(long long, >>);

    DEF_OPC_012(OPC_LUSHR)
        SHIFT_OP_long(unsigned long long, >>);

    DEF_OPC_210(OPC_FREM)
    {
        float v2 = ((float *)ostack)[-1];
        float v1 = ((float *)ostack)[-2];

        ((float *)ostack)[-2] = fmod(v1, v2);
        ostack -= 1;
        DISPATCH(0, 1);
    }

    DEF_OPC_210(OPC_DREM)
    {
        double v2 = ((double *)ostack)[-1];
        double v1 = ((double *)ostack)[-2];

        ((double *)ostack)[-2] = fmod(v1, v2);
        ostack -= 2;
        DISPATCH(0, 1);
    }

#define UNARY_MINUS(TYPE)                       \
    ((TYPE*)ostack)[-1] = -((TYPE*)ostack)[-1]; \
    DISPATCH(0, 1);

    DEF_OPC_210(OPC_LNEG)
        UNARY_MINUS(long long);

    DEF_OPC_210(OPC_FNEG)
        UNARY_MINUS(float);

    DEF_OPC_210(OPC_DNEG)
        UNARY_MINUS(double);

#define OPC_X2Y(SRC_TYPE, DEST_TYPE)     \
{                                        \
    SRC_TYPE v;                          \
    ostack -= sizeof(SRC_TYPE)/4;        \
    v = *(SRC_TYPE *)ostack;             \
    *(DEST_TYPE *)ostack = (DEST_TYPE)v; \
    ostack += sizeof(DEST_TYPE)/4;       \
    DISPATCH(0, 1);                      \
}

    DEF_OPC_210(OPC_I2L)
        OPC_X2Y(int, long long);

    DEF_OPC_210(OPC_I2F)
        OPC_X2Y(int, float);

    DEF_OPC_210(OPC_I2D)
        OPC_X2Y(int, double);

    DEF_OPC_210(OPC_L2I)
        OPC_X2Y(long long, int);

    DEF_OPC_210(OPC_L2F)
        OPC_X2Y(long long, float);

    DEF_OPC_210(OPC_L2D)
        OPC_X2Y(long long, double);

    DEF_OPC_210(OPC_F2D)
        OPC_X2Y(float, double);

    DEF_OPC_210(OPC_D2F)
        OPC_X2Y(double, float);

#define OPC_fp2int(SRC_TYPE)            \
{                                       \
    int res;                            \
    SRC_TYPE value;                     \
    ostack -= sizeof(SRC_TYPE)/4;       \
    value = *(SRC_TYPE *)ostack;        \
                                        \
    if(value >= (SRC_TYPE)INT_MAX)      \
        res = INT_MAX;                  \
    else if(value <= (SRC_TYPE)INT_MIN) \
        res = INT_MIN;                  \
    else if(value != value)             \
        res = 0;                        \
    else                                \
        res = (int) value;              \
                                        \
    PUSH_0(res, 1);                     \
}

    DEF_OPC_210(OPC_F2I)
        OPC_fp2int(float);

    DEF_OPC_210(OPC_D2I)
        OPC_fp2int(double);

#define OPC_fp2long(SRC_TYPE)                  \
{                                              \
    long long res;                             \
    SRC_TYPE value;                            \
    ostack -= sizeof(SRC_TYPE)/4;              \
    value = *(SRC_TYPE *)ostack;               \
                                               \
    if(value >= (SRC_TYPE)LONG_LONG_MAX)       \
        res = LONG_LONG_MAX;                   \
    else if(value <= (SRC_TYPE)LONG_LONG_MIN)  \
        res = LONG_LONG_MIN;                   \
    else if(value != value)                    \
        res = 0;                               \
    else                                       \
        res = (long long) value;               \
                                               \
    PUSH_LONG(res, 1);                         \
}

    DEF_OPC_210(OPC_F2L)
        OPC_fp2long(float);

    DEF_OPC_210(OPC_D2L)
        OPC_fp2long(double);

    DEF_OPC_210(OPC_I2B)
    {
        signed char v = *--ostack & 0xff;
        PUSH_0(v, 1);
    }

    DEF_OPC_210(OPC_I2C)
    {
        int v = *--ostack & 0xffff;
        PUSH_0(v, 1);
    }

    DEF_OPC_210(OPC_I2S)
    {
        signed short v = *--ostack & 0xffff;
        PUSH_0((int) v, 1);
    }

#ifdef USE_CACHE
    DEF_OPC_012(OPC_LCMP)
    {
        long long v1 = ((long long*)ostack)[-1];
        int r = (v1 == cache.l) ? 0 : ((v1 < cache.l) ? -1 : 1);
        cache.i.v1 = r;
        ostack -= 2;
        DISPATCH(1, 1);
    }
#else
    DEF_OPC_012(OPC_LCMP)
    {
        long long v2 = ((long long*)ostack)[-1];
        long long v1 = ((long long*)ostack)[-2];
        ostack[-4] = (v1 == v2) ? 0 : ((v1 < v2) ? -1 : 1);
        ostack -= 3;
        DISPATCH(0, 1);
    }
#endif

#define FCMP(TYPE, isNan)                                 \
{                                                         \
    int res;                                              \
    TYPE v1, v2;                                          \
    ostack -= sizeof(TYPE)/4; v2 = *(TYPE *)ostack;       \
    ostack -= sizeof(TYPE)/4; v1 = *(TYPE *)ostack;       \
    if(v1 == v2)                                          \
        res = 0;                                          \
    else if(v1 < v2)                                      \
        res = -1;                                         \
    else if(v1 > v2)                                      \
         res = 1;                                         \
    else                                                  \
         res = isNan;                                     \
    PUSH_0(res, 1);                                       \
}

    DEF_OPC_210_2(
            OPC_DCMPG,
            OPC_DCMPL)
        FCMP(double, (*pc == OPC_DCMPG ? 1 : -1));

    DEF_OPC_210_2(
            OPC_FCMPG,
            OPC_FCMPL)
        FCMP(float, (*pc == OPC_FCMPG ? 1 : -1));

    DEF_OPC_210(OPC_GOTO)
        DISPATCH(0, BRANCH(pc));

    DEF_OPC_210(OPC_JSR)
        *ostack++ = (u4)pc+3;
        DISPATCH(0, BRANCH(pc));

    DEF_OPC_210(OPC_RET)
        pc = (unsigned char*)lvars[CP_SINDEX(pc)];
        DISPATCH(0, 0);

    DEF_OPC_210(OPC_TABLESWITCH)
    {
        int *aligned_pc = (int*)((int)(pc + 4) & ~0x3);
        int deflt = ntohl(aligned_pc[0]);
        int low   = ntohl(aligned_pc[1]);
        int high  = ntohl(aligned_pc[2]);
        int index = *--ostack;

        DISPATCH(0, (index < low || index > high) ?
                        deflt : ntohl(aligned_pc[index - low + 3]));
    }

    DEF_OPC_210(OPC_LOOKUPSWITCH)
    {
        int *aligned_pc = (int*)((int)(pc + 4) & ~0x3);
        int deflt  = ntohl(aligned_pc[0]);
        int npairs = ntohl(aligned_pc[1]);
        int key    = *--ostack;
        int i;

        for(i = 2; (i < npairs*2+2) && (key != ntohl(aligned_pc[i])); i += 2);

        DISPATCH(0, i == npairs*2+2 ? deflt : ntohl(aligned_pc[i+1]));
    }

    DEF_OPC_012_2(
            OPC_LRETURN,
            OPC_DRETURN)
#ifdef USE_CACHE
      *(u8*)lvars = cache.l;
#else
        ostack -= 2;
      *(u8*)lvars = *(u8*)ostack;
#endif
        lvars += 2;
        goto methodReturn;

    DEF_OPC_210(OPC_GETSTATIC) 
    {
        FieldBlock *fb;
             
        frame->last_pc = (unsigned char*)pc;
      fb = resolveField(mb->class, CP_DINDEX(pc));

        if(exceptionOccured0(ee))
            goto throwException;

        if((*fb->type == 'J') || (*fb->type == 'D'))
            OPCODE_REWRITE(pc, OPC_GETSTATIC2_QUICK);
        else
            OPCODE_REWRITE(pc, OPC_GETSTATIC_QUICK);
        DISPATCH(0, 0);
    }

    DEF_OPC_210(OPC_PUTSTATIC) 
    {
        FieldBlock *fb;
             
        frame->last_pc = (unsigned char*)pc;
      fb = resolveField(mb->class, CP_DINDEX(pc));

        if(exceptionOccured0(ee))
            goto throwException;

        if((*fb->type == 'J') || (*fb->type == 'D'))
            OPCODE_REWRITE(pc, OPC_PUTSTATIC2_QUICK);
        else
            OPCODE_REWRITE(pc, OPC_PUTSTATIC_QUICK);
        DISPATCH(0, 0);
    }

    DEF_OPC_210(OPC_GETSTATIC2_QUICK) 
    {
        FieldBlock *fb = (FieldBlock *)CP_INFO(cp, CP_DINDEX(pc));
        PUSH_LONG(*(u8*)&fb->static_value, 3);
    }

    DEF_OPC_012(OPC_PUTSTATIC2_QUICK) 
    {
        FieldBlock *fb = (FieldBlock *)CP_INFO(cp, CP_DINDEX(pc));
        POP_LONG(*(u8*)&fb->static_value, 3);
    }

    DEF_OPC_210(OPC_GETFIELD)
    {
        int idx;
        FieldBlock *fb;

        WITH_OPCODE_CHANGE_CP_DINDEX(pc, OPC_GETFIELD, idx);

        frame->last_pc = (unsigned char*)pc;
        fb = resolveField(mb->class, idx);

        if(exceptionOccured0(ee))
            goto throwException;

        if(fb->offset > 255)
            OPCODE_REWRITE(pc, OPC_GETFIELD_QUICK_W);
        else
            OPCODE_REWRITE_OPERAND1(pc, ((*fb->type == 'J') || (*fb->type == 'D') ? 
                 OPC_GETFIELD2_QUICK : OPC_GETFIELD_QUICK), fb->offset);

        DISPATCH(0, 0);
    }

    DEF_OPC_210(OPC_PUTFIELD)
    {
        int idx;
        FieldBlock *fb;

      WITH_OPCODE_CHANGE_CP_DINDEX(pc, OPC_PUTFIELD, idx);

        frame->last_pc = (unsigned char*)pc;
        fb = resolveField(mb->class, idx);

        if(exceptionOccured0(ee))
            goto throwException;

        if(fb->offset > 255)
            OPCODE_REWRITE(pc, OPC_PUTFIELD_QUICK_W);
        else
            OPCODE_REWRITE_OPERAND1(pc, ((*fb->type == 'J') || (*fb->type == 'D') ? 
                 OPC_PUTFIELD2_QUICK : OPC_PUTFIELD_QUICK), fb->offset);

        DISPATCH(0, 0);
    }

    DEF_OPC_210(OPC_GETFIELD2_QUICK)
    {
        Object *obj = (Object *)*--ostack;
      NULL_POINTER_CHECK(obj);
            
        PUSH_LONG(*(u8*)(&(INST_DATA(obj)[pc[1]])), 3);
    }

    DEF_OPC_210(OPC_GETFIELD_QUICK_W)
    {
        FieldBlock *fb = (FieldBlock*)CP_INFO(cp, CP_DINDEX(pc));
        Object *obj = (Object *)*--ostack;
        u4 *addr;

      NULL_POINTER_CHECK(obj);
        addr = &(INST_DATA(obj)[fb->offset]);

        if((*fb->type == 'J') || (*fb->type == 'D')) {
            PUSH_LONG(*(u8*)addr, 3);
        } else {
            PUSH_0(*addr, 3);
        }
    }

#ifdef USE_CACHE
    DEF_OPC_012(OPC_PUTFIELD_QUICK_W)
    {
        FieldBlock *fb = (FieldBlock *)CP_INFO(cp, CP_DINDEX(pc));
 
        if((*fb->type == 'J') || (*fb->type == 'D')) {
            Object *obj = (Object *)*--ostack;

          NULL_POINTER_CHECK(obj);
            *(u8*)(&(INST_DATA(obj)[fb->offset])) = cache.l;
        } else {
            Object *obj = (Object *)cache.i.v1;

          NULL_POINTER_CHECK(obj);
            INST_DATA(obj)[fb->offset] = cache.i.v2;
        }
        DISPATCH(0, 3);
    }

    DEF_OPC_012(OPC_PUTFIELD2_QUICK)
    {
        Object *obj = (Object *)*--ostack;
      NULL_POINTER_CHECK(obj);

        *(u8*)(&(INST_DATA(obj)[pc[1]])) = cache.l;
        DISPATCH(0, 3);
    }

    DEF_OPC_012(OPC_PUTFIELD_QUICK)
    {
        Object *obj = (Object *)cache.i.v1;
      NULL_POINTER_CHECK(obj);
            
        INST_DATA(obj)[pc[1]] = cache.i.v2;
        DISPATCH(0, 3);
    }
#else
    DEF_OPC_012(OPC_PUTFIELD_QUICK_W)
    {
        FieldBlock *fb = (FieldBlock *)CP_INFO(cp, CP_DINDEX(pc));
 
        if((*fb->type == 'J') || (*fb->type == 'D')) {
            Object *obj = (Object *)ostack[-3];

            ostack -= 3;
          NULL_POINTER_CHECK(obj);
            *(u8*)(&(INST_DATA(obj)[fb->offset])) = *(u8*)&ostack[1];
        } else {
            Object *obj = (Object *)ostack[-2];

            ostack -= 2;
          NULL_POINTER_CHECK(obj);
            INST_DATA(obj)[fb->offset] = ostack[1];
        }
        DISPATCH(0, 3);
    }

    DEF_OPC_012(OPC_PUTFIELD2_QUICK)
    {
        Object *obj = (Object *)ostack[-3];

        ostack -= 3;
      NULL_POINTER_CHECK(obj);
        *(u8*)(&(INST_DATA(obj)[pc[1]])) = *(u8*)&ostack[1];
        DISPATCH(0, 3);
    }

    DEF_OPC_012(OPC_PUTFIELD_QUICK)
    {
        Object *obj = (Object *)ostack[-2];

        ostack -= 2;
      NULL_POINTER_CHECK(obj);
        INST_DATA(obj)[pc[1]] = ostack[1];
        DISPATCH(0, 3);
    }
#endif

    DEF_OPC_210(OPC_INVOKEVIRTUAL)
    {
        int idx;
        WITH_OPCODE_CHANGE_CP_DINDEX(pc, OPC_INVOKEVIRTUAL, idx);

        frame->last_pc = (unsigned char*)pc;
        new_mb = resolveMethod(mb->class, idx);
 
        if(exceptionOccured0(ee))
            goto throwException;

        if((new_mb->args_count < 256) && (new_mb->method_table_index < 256)) {
            OPCODE_REWRITE_OPERAND2(pc, OPC_INVOKEVIRTUAL_QUICK,
                                    new_mb->method_table_index, new_mb->args_count);
      } else
            OPCODE_REWRITE(pc, OPC_INVOKEVIRTUAL_QUICK_W);
        DISPATCH(0, 0);
    }

    DEF_OPC_210(OPC_INVOKEVIRTUAL_QUICK_W)
        new_mb = (MethodBlock *)CP_INFO(cp, CP_DINDEX(pc));
        arg1 = ostack - (new_mb->args_count);
      NULL_POINTER_CHECK(*arg1);

        new_class = (*(Object **)arg1)->class;
        new_mb = CLASS_CB(new_class)->method_table[new_mb->method_table_index];

        goto invokeMethod;

    DEF_OPC_210(OPC_INVOKESPECIAL)
    {
        int idx;
        WITH_OPCODE_CHANGE_CP_DINDEX(pc, OPC_INVOKESPECIAL, idx);

        frame->last_pc = (unsigned char*)pc;
        new_mb = resolveMethod(mb->class, idx);
 
        if(exceptionOccured0(ee))
            goto throwException;

        /* Check if invoking a super method... */
      if((CLASS_CB(mb->class)->access_flags & ACC_SUPER) &&
              ((new_mb->access_flags & ACC_PRIVATE) == 0) && (new_mb->name[0] != '<')) {
            OPCODE_REWRITE_OPERAND2(pc, OPC_INVOKESUPER_QUICK,
                    new_mb->method_table_index >> 8,
                    new_mb->method_table_index & 0xff);
      } else
            OPCODE_REWRITE(pc, OPC_INVOKENONVIRTUAL_QUICK);
        DISPATCH(0, 0);
    }

    DEF_OPC_210(OPC_INVOKESUPER_QUICK)
        new_mb = CLASS_CB(CLASS_CB(mb->class)->super)->method_table[CP_DINDEX(pc)];
        arg1 = ostack - (new_mb->args_count);
      NULL_POINTER_CHECK(*arg1);
      goto invokeMethod;

    DEF_OPC_210(OPC_INVOKENONVIRTUAL_QUICK)
        new_mb = (MethodBlock *)CP_INFO(cp, CP_DINDEX(pc));
        arg1 = ostack - (new_mb->args_count);
      NULL_POINTER_CHECK(*arg1);
      goto invokeMethod;

    DEF_OPC_210(OPC_INVOKESTATIC)
        frame->last_pc = (unsigned char*)pc;
        new_mb = resolveMethod(mb->class, CP_DINDEX(pc));
 
        if(exceptionOccured0(ee))
            goto throwException;

        OPCODE_REWRITE(pc, OPC_INVOKESTATIC_QUICK);
        DISPATCH(0, 0);

    DEF_OPC_210(OPC_INVOKESTATIC_QUICK)
        new_mb = (MethodBlock *)CP_INFO(cp, CP_DINDEX(pc));
        arg1 = ostack - new_mb->args_count;
        goto invokeMethod;

    DEF_OPC_210(OPC_INVOKEINTERFACE)
        frame->last_pc = (unsigned char*)pc;
        new_mb = resolveInterfaceMethod(mb->class, CP_DINDEX(pc));
 
        if(exceptionOccured0(ee))
            goto throwException;

        if(CLASS_CB(new_mb->class)->access_flags & ACC_INTERFACE)
            OPCODE_REWRITE(pc, OPC_INVOKEINTERFACE_QUICK);
        else {
            pc[3] = pc[4] = OPC_NOP;
            OPCODE_REWRITE(pc, OPC_INVOKEVIRTUAL);
        }

        DISPATCH(0, 0);

    DEF_OPC_210(OPC_INVOKEINTERFACE_QUICK)
    {
        int mtbl_idx;
        ClassBlock *cb;
        int cache = pc[4];
        arg1 = ostack - pc[3];

      NULL_POINTER_CHECK(*arg1);

        cb = CLASS_CB(new_class = (*(Object **)arg1)->class);
        new_mb = (MethodBlock *)CP_INFO(cp, CP_DINDEX(pc));

      if((cache >= cb->imethod_table_size) ||
                  (new_mb->class != cb->imethod_table[cache].interface)) {
            for(cache = 0; (cache < cb->imethod_table_size) &&
                     (new_mb->class != cb->imethod_table[cache].interface); cache++);
          if(cache == cb->imethod_table_size)
                THROW_EXCEPTION("java/lang/IncompatibleClassChangeError",
                               "unimplemented interface");

            pc[4] = cache;
      }

        mtbl_idx = cb->imethod_table[cache].offsets[new_mb->method_table_index];
        new_mb = cb->method_table[mtbl_idx];

      if(new_mb->access_flags & ACC_ABSTRACT)
            THROW_EXCEPTION("java/lang/AbstractMethodError",
                            "unimplemented interface method");

        goto invokeMethod;
    }

    DEF_OPC_210(OPC_ARRAYLENGTH)
    {
        Object *array = (Object *)*--ostack;

      NULL_POINTER_CHECK(array);
        PUSH_0(*INST_DATA(array), 1);
    }

    DEF_OPC_210(OPC_ATHROW)
    {
        Object *obj = (Object *)ostack[-1];
        frame->last_pc = (unsigned char*)pc;
      NULL_POINTER_CHECK(obj);
            
        ee->exception = obj;
        goto throwException;
    }

    DEF_OPC_210_5(
            OPC_NEW,
            OPC_ANEWARRAY,
            OPC_CHECKCAST,
            OPC_INSTANCEOF,
            OPC_MULTIANEWARRAY)
        frame->last_pc = (unsigned char*)pc;
        resolveClass(mb->class, CP_DINDEX(pc), *pc == OPC_NEW);

        if(exceptionOccured0(ee))
            goto throwException;
        
        OPCODE_REWRITE(pc, (pc[0] + OPC_NEW_QUICK-OPC_NEW));
        DISPATCH(0, 0);

    DEF_OPC_210(OPC_NEW_QUICK)
    {
        Class *class = (Class *)CP_INFO(cp, CP_DINDEX(pc));
        Object *obj;

        frame->last_pc = (unsigned char*)pc;
        if((obj = allocObject(class)) == NULL)
            goto throwException;

        PUSH_0((u4)obj, 3);
    }
 
    DEF_OPC_210(OPC_NEWARRAY)
    {
        int type = pc[1];
        int count = *--ostack;
        Object *obj;

        frame->last_pc = (unsigned char*)pc;
        if((obj = allocTypeArray(type, count)) == NULL)
            goto throwException;

        PUSH_0((u4)obj, 2);
    }

    DEF_OPC_210(OPC_ANEWARRAY_QUICK)
    {
        Class *class = (Class *)CP_INFO(cp, CP_DINDEX(pc));
        char *name = CLASS_CB(class)->name;
        int count = *--ostack;
        Class *array_class;
        char *ac_name;
        Object *obj;

        frame->last_pc = (unsigned char*)pc;

        if(count < 0) {
            signalException("java/lang/NegativeArraySizeException", NULL);
            goto throwException;
        }

        ac_name = sysMalloc(strlen(name) + 4);

        if(name[0] == '[')
            strcat(strcpy(ac_name, "["), name);
        else
            strcat(strcat(strcpy(ac_name, "[L"), name), ";");

        array_class = findArrayClassFromClass(ac_name, class);
        free(ac_name);

        if(exceptionOccured0(ee))
            goto throwException;

        if((obj = allocArray(array_class, count, 4)) == NULL)
            goto throwException;

        PUSH_0((u4)obj, 3);
    }

    DEF_OPC_210(OPC_CHECKCAST_QUICK)
    {
        Class *class = (Class *)CP_INFO(cp, CP_DINDEX(pc));
        Object *obj = (Object*)ostack[-1]; 
             
        if((obj != NULL) && !isInstanceOf(class, obj->class))
            THROW_EXCEPTION("java/lang/ClassCastException", CLASS_CB(obj->class)->name);
    
        DISPATCH(0, 3);
    }

    DEF_OPC_210(OPC_INSTANCEOF_QUICK)
    {
        Class *class = (Class *)CP_INFO(cp, CP_DINDEX(pc));
        Object *obj = (Object*)ostack[-1]; 
             
        if(obj != NULL)
            ostack[-1] = isInstanceOf(class, obj->class); 

        DISPATCH(0, 3);
    }

    DEF_OPC_210(OPC_MONITORENTER)
    {
        Object *obj = (Object *)*--ostack;
      NULL_POINTER_CHECK(obj);
      objectLock(obj);
      DISPATCH(0, 1);
    }

    DEF_OPC_210(OPC_MONITOREXIT)
    {
        Object *obj = (Object *)*--ostack;
      NULL_POINTER_CHECK(obj);
      objectUnlock(obj);
      DISPATCH(0, 1);
    }

    DEF_OPC_210(OPC_WIDE)
    {
       int opcode = pc[1];
        switch(opcode) {
            case OPC_ILOAD:
            case OPC_FLOAD:
            case OPC_ALOAD:
                *ostack++ = lvars[CP_DINDEX((pc+1))];
                pc += 4;
            break;

            case OPC_LLOAD:
            case OPC_DLOAD:
                *(u8*)ostack = *(u8*)(&lvars[CP_DINDEX((pc+1))]);
                ostack += 2;
                pc += 4;
            break;

            case OPC_ISTORE:
            case OPC_FSTORE:
            case OPC_ASTORE:
                lvars[CP_DINDEX((pc+1))] = *--ostack;
                pc += 4;
            break;

            case OPC_LSTORE:
            case OPC_DSTORE:
                ostack -= 2;
                *(u8*)(&lvars[CP_DINDEX((pc+1))]) = *(u8*)ostack;
                pc += 4;
            break;

            case OPC_RET:
                pc = (unsigned char*)lvars[CP_DINDEX((pc+1))];
            break;

            case OPC_IINC:
                lvars[CP_DINDEX((pc+1))] += DSIGNED((pc+3));
                pc += 6;
            break;
        }
        DISPATCH(0, 0);
    }

    DEF_OPC_210(OPC_MULTIANEWARRAY_QUICK)
    {
        Class *class = (Class *)CP_INFO(cp, CP_DINDEX(pc));
        int i, dim = pc[3];
      Object *obj;

        ostack -= dim;
        frame->last_pc = (unsigned char*)pc;

        for(i = 0; i < dim; i++)
            if((int)ostack[i] < 0) {
                signalException("java/lang/NegativeArraySizeException", NULL);
                goto throwException;
            }

        if((obj = allocMultiArray(class, dim, ostack)) == NULL)
            goto throwException;

        PUSH_0((u4)obj, 4);
    }

    DEF_OPC_210(OPC_GOTO_W)
        DISPATCH(0, BRANCH_W(pc));

    DEF_OPC_210(OPC_JSR_W)
        PUSH_0((u4)pc+3, BRANCH_W(pc));

    DEF_OPC_210(OPC_LOCK)
        DISPATCH(0, 0);

    DEF_OPC_210(OPC_INVOKEVIRTUAL_QUICK)
        arg1 = ostack - pc[2];

      NULL_POINTER_CHECK(*arg1);

        new_class = (*(Object **)arg1)->class;
        new_mb = CLASS_CB(new_class)->method_table[pc[1]];

invokeMethod:
{
    /* Create new frame first.  This is also created for natives
       so that they appear correctly in the stack trace */

    Frame *new_frame = (Frame *)(arg1 + new_mb->max_locals);
    Object *sync_ob = NULL;

    frame->last_pc = (unsigned char*)pc;
    ostack = (u4*)(new_frame+1);

    if((char*)(ostack + new_mb->max_stack) > ee->stack_end) {
        if(ee->overflow++) {
            /* Overflow when we're already throwing stack overflow.
               Stack extension should be enough to throw exception,
               so something's seriously gone wrong - abort the VM! */
            printf("Fatal stack overflow!  Aborting VM.\n");
            exitVM(1);
        }
        ee->stack_end += STACK_RED_ZONE_SIZE;
        THROW_EXCEPTION("java/lang/StackOverflowError", NULL);
    }

    new_frame->mb = new_mb;
    new_frame->lvars = arg1;
    new_frame->ostack = ostack;
    new_frame->prev = frame;

    ee->last_frame = new_frame;

    if(new_mb->access_flags & ACC_SYNCHRONIZED) {
        sync_ob = new_mb->access_flags & ACC_STATIC ? (Object*)new_mb->class : (Object*)*arg1;
      objectLock(sync_ob);
    }

    if(new_mb->access_flags & ACC_NATIVE) {
        ostack = (*(u4 *(*)(Class*, MethodBlock*, u4*))
                   new_mb->native_invoker)(new_mb->class, new_mb, arg1);

      if(sync_ob)
          objectUnlock(sync_ob);

        ee->last_frame = frame;

      if(exceptionOccured0(ee))
            goto throwException;
      pc += *pc == OPC_INVOKEINTERFACE_QUICK ? 5 : 3;
    } else {
        frame = new_frame;
        mb = new_mb;
        lvars = new_frame->lvars;
        this = (Object*)lvars[0];
        pc = mb->code;
        cp = &(CLASS_CB(mb->class)->constant_pool);
    }
    DISPATCH(0, 0);
}

methodReturn:
    /* Set interpreter state to previous frame */

    frame = frame->prev;

    if(frame->mb == NULL) {
        /* The previous frame is a dummy frame - this indicates
           top of this Java invocation. */
        return ostack;
    }

    if(mb->access_flags & ACC_SYNCHRONIZED) {
        Object *sync_ob = mb->access_flags & ACC_STATIC ? (Object*)mb->class : this;
      objectUnlock(sync_ob);
    }

    mb = frame->mb;
    ostack = lvars;
    lvars = frame->lvars;
    this = (Object*)lvars[0];
    pc = frame->last_pc;
    cp = &(CLASS_CB(mb->class)->constant_pool);

    /* Pop frame */ 
    ee->last_frame = frame;

    DISPATCH(0, *pc == OPC_INVOKEINTERFACE_QUICK ? 5 : 3);

throwException:
    {
        Object *excep = ee->exception;
        ee->exception = NULL;

        pc = findCatchBlock(excep->class);

        /* If we didn't find a handler, restore exception and
           return to previous invocation */

        if(pc == NULL) {
            ee->exception = excep;
            return NULL;
        }

        /* If we're handling a stack overflow, reduce the stack
           back past the red zone to enable handling of further
           overflows */

        if(ee->overflow) {
            ee->overflow = FALSE;
            ee->stack_end -= STACK_RED_ZONE_SIZE;
        }

        /* Setup intepreter to run the found catch block */

        frame = ee->last_frame;
        mb = frame->mb;
        ostack = frame->ostack;
        lvars = frame->lvars;
        this = (Object*)lvars[0];
        cp = &(CLASS_CB(mb->class)->constant_pool);

        *ostack++ = (u4)excep;

        /* Dispatch to the first bytecode */

        DISPATCH(0, 0);
    }
#ifndef THREADED
  }}
#endif
}

Generated by  Doxygen 1.6.0   Back to index