| // interpret.cc - Code for the interpreter |
| |
| /* Copyright (C) 1999, 2000, 2001 , 2002 Free Software Foundation |
| |
| This file is part of libgcj. |
| |
| This software is copyrighted work licensed under the terms of the |
| Libgcj License. Please consult the file "LIBGCJ_LICENSE" for |
| details. */ |
| |
| /* Author: Kresten Krab Thorup <krab@gnu.org> */ |
| |
| #include <config.h> |
| |
| #pragma implementation "java-interp.h" |
| |
| #include <jvm.h> |
| #include <java-cpool.h> |
| #include <java-interp.h> |
| // #include <java/lang/fdlibm.h> |
| #include <java/lang/System.h> |
| #include <java/lang/String.h> |
| #include <java/lang/Integer.h> |
| #include <java/lang/Long.h> |
| #include <java/lang/StringBuffer.h> |
| #include <java/lang/Class.h> |
| #include <java/lang/reflect/Modifier.h> |
| #include <java/lang/ClassCastException.h> |
| #include <java/lang/VirtualMachineError.h> |
| #include <java/lang/InternalError.h> |
| #include <java/lang/NullPointerException.h> |
| #include <java/lang/ArithmeticException.h> |
| #include <java/lang/IncompatibleClassChangeError.h> |
| #include <java-insns.h> |
| #include <java-signal.h> |
| |
| #ifdef INTERPRETER |
| |
| #include <stdlib.h> |
| |
| using namespace gcj; |
| |
| static void throw_internal_error (char *msg) |
| __attribute__ ((__noreturn__)); |
| static void throw_incompatible_class_change_error (jstring msg) |
| __attribute__ ((__noreturn__)); |
| #ifndef HANDLE_SEGV |
| static void throw_null_pointer_exception () |
| __attribute__ ((__noreturn__)); |
| #endif |
| |
| extern "C" double __ieee754_fmod (double,double); |
| |
| static inline void dupx (_Jv_word *sp, int n, int x) |
| { |
| // first "slide" n+x elements n to the right |
| int top = n-1; |
| for (int i = 0; i < n+x; i++) |
| { |
| sp[(top-i)] = sp[(top-i)-n]; |
| } |
| |
| // next, copy the n top elements, n+x down |
| for (int i = 0; i < n; i++) |
| { |
| sp[top-(n+x)-i] = sp[top-i]; |
| } |
| |
| }; |
| |
| // Used to convert from floating types to integral types. |
| template<typename TO, typename FROM> |
| static inline TO |
| convert (FROM val, TO min, TO max) |
| { |
| TO ret; |
| if (val >= (FROM) max) |
| ret = max; |
| else if (val <= (FROM) min) |
| ret = min; |
| else if (val != val) |
| ret = 0; |
| else |
| ret = (TO) val; |
| return ret; |
| } |
| |
| #define PUSHA(V) (sp++)->o = (V) |
| #define PUSHI(V) (sp++)->i = (V) |
| #define PUSHF(V) (sp++)->f = (V) |
| #if SIZEOF_VOID_P == 8 |
| # define PUSHL(V) (sp->l = (V), sp += 2) |
| # define PUSHD(V) (sp->d = (V), sp += 2) |
| #else |
| # define PUSHL(V) do { _Jv_word2 w2; w2.l=(V); \ |
| (sp++)->ia[0] = w2.ia[0]; \ |
| (sp++)->ia[0] = w2.ia[1]; } while (0) |
| # define PUSHD(V) do { _Jv_word2 w2; w2.d=(V); \ |
| (sp++)->ia[0] = w2.ia[0]; \ |
| (sp++)->ia[0] = w2.ia[1]; } while (0) |
| #endif |
| |
| #define POPA() ((--sp)->o) |
| #define POPI() ((jint) (--sp)->i) // cast since it may be promoted |
| #define POPF() ((jfloat) (--sp)->f) |
| #if SIZEOF_VOID_P == 8 |
| # define POPL() (sp -= 2, (jlong) sp->l) |
| # define POPD() (sp -= 2, (jdouble) sp->d) |
| #else |
| # define POPL() ({ _Jv_word2 w2; \ |
| w2.ia[1] = (--sp)->ia[0]; \ |
| w2.ia[0] = (--sp)->ia[0]; w2.l; }) |
| # define POPD() ({ _Jv_word2 w2; \ |
| w2.ia[1] = (--sp)->ia[0]; \ |
| w2.ia[0] = (--sp)->ia[0]; w2.d; }) |
| #endif |
| |
| #define LOADA(I) (sp++)->o = locals[I].o |
| #define LOADI(I) (sp++)->i = locals[I].i |
| #define LOADF(I) (sp++)->f = locals[I].f |
| #if SIZEOF_VOID_P == 8 |
| # define LOADL(I) (sp->l = locals[I].l, sp += 2) |
| # define LOADD(I) (sp->d = locals[I].d, sp += 2) |
| #else |
| # define LOADL(I) do { jint __idx = (I); \ |
| (sp++)->ia[0] = locals[__idx].ia[0]; \ |
| (sp++)->ia[0] = locals[__idx+1].ia[0]; \ |
| } while (0) |
| # define LOADD(I) LOADL(I) |
| #endif |
| |
| #define STOREA(I) locals[I].o = (--sp)->o |
| #define STOREI(I) locals[I].i = (--sp)->i |
| #define STOREF(I) locals[I].f = (--sp)->f |
| #if SIZEOF_VOID_P == 8 |
| # define STOREL(I) (sp -= 2, locals[I].l = sp->l) |
| # define STORED(I) (sp -= 2, locals[I].d = sp->d) |
| #else |
| # define STOREL(I) do { jint __idx = (I); \ |
| locals[__idx+1].ia[0] = (--sp)->ia[0]; \ |
| locals[__idx].ia[0] = (--sp)->ia[0]; \ |
| } while (0) |
| # define STORED(I) STOREL(I) |
| #endif |
| |
| #define PEEKI(I) (locals+(I))->i |
| #define PEEKA(I) (locals+(I))->o |
| |
| #define POKEI(I,V) ((locals+(I))->i = (V)) |
| |
| |
| #define BINOPI(OP) { \ |
| jint value2 = POPI(); \ |
| jint value1 = POPI(); \ |
| PUSHI(value1 OP value2); \ |
| } |
| |
| #define BINOPF(OP) { \ |
| jfloat value2 = POPF(); \ |
| jfloat value1 = POPF(); \ |
| PUSHF(value1 OP value2); \ |
| } |
| |
| #define BINOPL(OP) { \ |
| jlong value2 = POPL(); \ |
| jlong value1 = POPL(); \ |
| PUSHL(value1 OP value2); \ |
| } |
| |
| #define BINOPD(OP) { \ |
| jdouble value2 = POPD(); \ |
| jdouble value1 = POPD(); \ |
| PUSHD(value1 OP value2); \ |
| } |
| |
| static inline jint get1s(unsigned char* loc) { |
| return *(signed char*)loc; |
| } |
| |
| static inline jint get1u(unsigned char* loc) { |
| return *loc; |
| } |
| |
| static inline jint get2s(unsigned char* loc) { |
| return (((jint)*(signed char*)loc) << 8) | ((jint)*(loc+1)); |
| } |
| |
| static inline jint get2u(unsigned char* loc) { |
| return (((jint)(*loc)) << 8) | ((jint)*(loc+1)); |
| } |
| |
| static jint get4(unsigned char* loc) { |
| return (((jint)(loc[0])) << 24) |
| | (((jint)(loc[1])) << 16) |
| | (((jint)(loc[2])) << 8) |
| | (((jint)(loc[3])) << 0); |
| } |
| |
| |
| #ifdef HANDLE_SEGV |
| #define NULLCHECK(X) |
| #define NULLARRAYCHECK(X) do { SAVE_PC; } while (0) |
| #else |
| #define NULLCHECK(X) \ |
| do { if ((X)==NULL) throw_null_pointer_exception (); } while (0) |
| #define NULLARRAYCHECK(X) \ |
| do { if ((X)==NULL) { SAVE_PC; throw_null_pointer_exception (); } } while (0) |
| #endif |
| |
| #define ARRAYBOUNDSCHECK(array, index) \ |
| do \ |
| { \ |
| if (((unsigned) index) >= (unsigned) (array->length)) \ |
| _Jv_ThrowBadArrayIndex (index); \ |
| } \ |
| while (0) |
| |
| // this method starts the actual running of the method. It is inlined |
| // in three different variants in the static methods run_normal, |
| // run_sync_object and run_sync_class (see below). Those static methods |
| // are installed directly in the stub for this method (by |
| // _Jv_InterpMethod::ncode, in resolve.cc). |
| |
| inline jobject |
| _Jv_InterpMethod::run (ffi_cif* cif, |
| void *retp, |
| ffi_raw *args, |
| _Jv_InterpMethodInvocation *inv) |
| { |
| inv->running = this; |
| inv->pc = bytecode (); |
| inv->sp = inv->stack_base (); |
| _Jv_word *locals = inv->local_base (); |
| |
| /* Go straight at it! the ffi raw format matches the internal |
| stack representation exactly. At least, that's the idea. |
| */ |
| memcpy ((void*) locals, (void*) args, args_raw_size); |
| |
| next_segment: |
| |
| jobject ex = NULL; |
| |
| try |
| { |
| continue1 (inv); |
| } |
| catch (java::lang::Throwable *ex2) |
| { |
| ex = ex2; |
| } |
| |
| if (ex == 0) // no exception... |
| { |
| /* define sp locally, so the POP? macros will pick it up */ |
| _Jv_word *sp = inv->sp; |
| int rtype = cif->rtype->type; |
| |
| if (rtype == FFI_TYPE_POINTER) |
| { |
| jobject r = POPA(); |
| *(jobject*) retp = r; |
| return 0; |
| } |
| else if (rtype == FFI_TYPE_SINT32) |
| { |
| jint r = POPI(); |
| *(jint*)retp = r; |
| return 0; |
| } |
| else if (rtype == FFI_TYPE_VOID) |
| { |
| return 0; |
| } |
| else switch (rtype) |
| { |
| case FFI_TYPE_FLOAT: |
| { |
| jfloat r = POPF(); |
| *(jfloat*)retp = r; |
| return 0; |
| } |
| |
| case FFI_TYPE_DOUBLE: |
| { |
| jdouble r = POPD(); |
| *(jdouble*)retp = r; |
| return 0; |
| } |
| |
| case FFI_TYPE_UINT8: |
| case FFI_TYPE_UINT16: |
| case FFI_TYPE_UINT32: |
| case FFI_TYPE_SINT8: |
| case FFI_TYPE_SINT16: |
| { |
| jint r = POPI(); |
| *(jint*)retp = r; |
| return 0; |
| } |
| |
| case FFI_TYPE_SINT64: |
| { |
| jlong r = POPL(); |
| *(jlong*)retp = r; |
| return 0; |
| } |
| |
| default: |
| throw_internal_error ("unknown return type"); |
| } |
| } |
| |
| /** handle an exception */ |
| if ( find_exception (ex, inv) ) |
| goto next_segment; |
| |
| return ex; |
| } |
| |
| #define SAVE_PC inv->pc = pc |
| |
| bool _Jv_InterpMethod::find_exception (jobject ex, |
| _Jv_InterpMethodInvocation *inv) |
| { |
| // We subtract one because the PC was incremented before it was |
| // saved. |
| int logical_pc = inv->pc - 1 - bytecode (); |
| _Jv_InterpException *exc = exceptions (); |
| jclass exc_class = ex->getClass (); |
| |
| for (int i = 0; i < exc_count; i++) |
| { |
| if (exc[i].start_pc <= logical_pc && logical_pc < exc[i].end_pc) |
| { |
| jclass handler; |
| |
| if (exc[i].handler_type != 0) |
| handler = (_Jv_ResolvePoolEntry (defining_class, |
| exc[i].handler_type)).clazz; |
| else |
| handler = NULL; |
| |
| if (handler==NULL || handler->isAssignableFrom (exc_class)) |
| { |
| inv->pc = bytecode () + exc[i].handler_pc; |
| inv->sp = inv->stack_base (); // reset stack |
| (inv->sp++)->o = ex; // push exception |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| void _Jv_InterpMethod::run_normal (ffi_cif* cif, |
| void* ret, |
| ffi_raw * args, |
| void* __this) |
| { |
| _Jv_InterpMethod* _this = (_Jv_InterpMethod*)__this; |
| |
| // we do the alloca of the method invocation here, to allow the method |
| // "run" ro be inlined. Otherwise gcc will ignore the inline directive. |
| int storage_size = _this->max_stack+_this->max_locals; |
| _Jv_InterpMethodInvocation* inv = (_Jv_InterpMethodInvocation*) |
| __builtin_alloca (sizeof (_Jv_InterpMethodInvocation) |
| + storage_size * sizeof (_Jv_word)); |
| |
| jobject ex = _this->run (cif, ret, args, inv); |
| if (ex != 0) throw static_cast<jthrowable>(ex); |
| } |
| |
| void _Jv_InterpMethod::run_synch_object (ffi_cif* cif, |
| void* ret, |
| ffi_raw * args, |
| void* __this) |
| { |
| _Jv_InterpMethod* _this = (_Jv_InterpMethod*)__this; |
| jobject rcv = (jobject)args[0].ptr; |
| |
| int storage_size = _this->max_stack+_this->max_locals; |
| _Jv_InterpMethodInvocation* inv = (_Jv_InterpMethodInvocation*) |
| __builtin_alloca (sizeof (_Jv_InterpMethodInvocation) |
| + storage_size * sizeof (_Jv_word)); |
| |
| _Jv_MonitorEnter (rcv); |
| jobject ex = _this->run (cif, ret, args, inv); |
| _Jv_MonitorExit (rcv); |
| |
| if (ex != 0) throw static_cast<jthrowable>(ex); |
| } |
| |
| void _Jv_InterpMethod::run_synch_class (ffi_cif* cif, |
| void* ret, |
| ffi_raw * args, |
| void* __this) |
| { |
| _Jv_InterpMethod* _this = (_Jv_InterpMethod*)__this; |
| jclass sync = _this->defining_class; |
| |
| int storage_size = _this->max_stack+_this->max_locals; |
| _Jv_InterpMethodInvocation* inv = (_Jv_InterpMethodInvocation*) |
| __builtin_alloca (sizeof (_Jv_InterpMethodInvocation) |
| + storage_size * sizeof (_Jv_word)); |
| |
| _Jv_MonitorEnter (sync); |
| jobject ex = _this->run (cif, ret, args, inv); |
| _Jv_MonitorExit (sync); |
| |
| if (ex != 0) throw static_cast<jthrowable>(ex); |
| } |
| |
| /* |
| This proceeds execution, as designated in "inv". If an exception |
| happens, then it is simply thrown, and handled in Java. Thus, the pc |
| needs to be stored in the inv->pc at all times, so we can figure |
| out which handler (if any) to invoke. |
| |
| One design issue, which I have not completely considered, is if it |
| should be possible to have interpreted classes linked in! Seldom used |
| (or non-critical) classes could reasonably be interpreted. |
| */ |
| |
| |
| void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) |
| { |
| using namespace java::lang::reflect; |
| |
| _Jv_word *sp = inv->sp; |
| unsigned char *pc = inv->pc; |
| _Jv_word *locals = inv->local_base (); |
| |
| _Jv_word *pool_data = defining_class->constants.data; |
| |
| /* these two are used in the invokeXXX instructions */ |
| void (*fun)(); |
| _Jv_ResolvedMethod* rmeth; |
| |
| #define INSN_LABEL(op) &&insn_##op |
| #define GOTO_INSN(op) goto *(insn_target[op]) |
| |
| static const void *const insn_target[] = |
| { |
| INSN_LABEL(nop), |
| INSN_LABEL(aconst_null), |
| INSN_LABEL(iconst_m1), |
| INSN_LABEL(iconst_0), |
| INSN_LABEL(iconst_1), |
| INSN_LABEL(iconst_2), |
| INSN_LABEL(iconst_3), |
| INSN_LABEL(iconst_4), |
| INSN_LABEL(iconst_5), |
| INSN_LABEL(lconst_0), |
| INSN_LABEL(lconst_1), |
| INSN_LABEL(fconst_0), |
| INSN_LABEL(fconst_1), |
| INSN_LABEL(fconst_2), |
| INSN_LABEL(dconst_0), |
| INSN_LABEL(dconst_1), |
| INSN_LABEL(bipush), |
| INSN_LABEL(sipush), |
| INSN_LABEL(ldc), |
| INSN_LABEL(ldc_w), |
| INSN_LABEL(ldc2_w), |
| INSN_LABEL(iload), |
| INSN_LABEL(lload), |
| INSN_LABEL(fload), |
| INSN_LABEL(dload), |
| INSN_LABEL(aload), |
| INSN_LABEL(iload_0), |
| INSN_LABEL(iload_1), |
| INSN_LABEL(iload_2), |
| INSN_LABEL(iload_3), |
| INSN_LABEL(lload_0), |
| INSN_LABEL(lload_1), |
| INSN_LABEL(lload_2), |
| INSN_LABEL(lload_3), |
| INSN_LABEL(fload_0), |
| INSN_LABEL(fload_1), |
| INSN_LABEL(fload_2), |
| INSN_LABEL(fload_3), |
| INSN_LABEL(dload_0), |
| INSN_LABEL(dload_1), |
| INSN_LABEL(dload_2), |
| INSN_LABEL(dload_3), |
| INSN_LABEL(aload_0), |
| INSN_LABEL(aload_1), |
| INSN_LABEL(aload_2), |
| INSN_LABEL(aload_3), |
| INSN_LABEL(iaload), |
| INSN_LABEL(laload), |
| INSN_LABEL(faload), |
| INSN_LABEL(daload), |
| INSN_LABEL(aaload), |
| INSN_LABEL(baload), |
| INSN_LABEL(caload), |
| INSN_LABEL(saload), |
| INSN_LABEL(istore), |
| INSN_LABEL(lstore), |
| INSN_LABEL(fstore), |
| INSN_LABEL(dstore), |
| INSN_LABEL(astore), |
| INSN_LABEL(istore_0), |
| INSN_LABEL(istore_1), |
| INSN_LABEL(istore_2), |
| INSN_LABEL(istore_3), |
| INSN_LABEL(lstore_0), |
| INSN_LABEL(lstore_1), |
| INSN_LABEL(lstore_2), |
| INSN_LABEL(lstore_3), |
| INSN_LABEL(fstore_0), |
| INSN_LABEL(fstore_1), |
| INSN_LABEL(fstore_2), |
| INSN_LABEL(fstore_3), |
| INSN_LABEL(dstore_0), |
| INSN_LABEL(dstore_1), |
| INSN_LABEL(dstore_2), |
| INSN_LABEL(dstore_3), |
| INSN_LABEL(astore_0), |
| INSN_LABEL(astore_1), |
| INSN_LABEL(astore_2), |
| INSN_LABEL(astore_3), |
| INSN_LABEL(iastore), |
| INSN_LABEL(lastore), |
| INSN_LABEL(fastore), |
| INSN_LABEL(dastore), |
| INSN_LABEL(aastore), |
| INSN_LABEL(bastore), |
| INSN_LABEL(castore), |
| INSN_LABEL(sastore), |
| INSN_LABEL(pop), |
| INSN_LABEL(pop2), |
| INSN_LABEL(dup), |
| INSN_LABEL(dup_x1), |
| INSN_LABEL(dup_x2), |
| INSN_LABEL(dup2), |
| INSN_LABEL(dup2_x1), |
| INSN_LABEL(dup2_x2), |
| INSN_LABEL(swap), |
| INSN_LABEL(iadd), |
| INSN_LABEL(ladd), |
| INSN_LABEL(fadd), |
| INSN_LABEL(dadd), |
| INSN_LABEL(isub), |
| INSN_LABEL(lsub), |
| INSN_LABEL(fsub), |
| INSN_LABEL(dsub), |
| INSN_LABEL(imul), |
| INSN_LABEL(lmul), |
| INSN_LABEL(fmul), |
| INSN_LABEL(dmul), |
| INSN_LABEL(idiv), |
| INSN_LABEL(ldiv), |
| INSN_LABEL(fdiv), |
| INSN_LABEL(ddiv), |
| INSN_LABEL(irem), |
| INSN_LABEL(lrem), |
| INSN_LABEL(frem), |
| INSN_LABEL(drem), |
| INSN_LABEL(ineg), |
| INSN_LABEL(lneg), |
| INSN_LABEL(fneg), |
| INSN_LABEL(dneg), |
| INSN_LABEL(ishl), |
| INSN_LABEL(lshl), |
| INSN_LABEL(ishr), |
| INSN_LABEL(lshr), |
| INSN_LABEL(iushr), |
| INSN_LABEL(lushr), |
| INSN_LABEL(iand), |
| INSN_LABEL(land), |
| INSN_LABEL(ior), |
| INSN_LABEL(lor), |
| INSN_LABEL(ixor), |
| INSN_LABEL(lxor), |
| INSN_LABEL(iinc), |
| INSN_LABEL(i2l), |
| INSN_LABEL(i2f), |
| INSN_LABEL(i2d), |
| INSN_LABEL(l2i), |
| INSN_LABEL(l2f), |
| INSN_LABEL(l2d), |
| INSN_LABEL(f2i), |
| INSN_LABEL(f2l), |
| INSN_LABEL(f2d), |
| INSN_LABEL(d2i), |
| INSN_LABEL(d2l), |
| INSN_LABEL(d2f), |
| INSN_LABEL(i2b), |
| INSN_LABEL(i2c), |
| INSN_LABEL(i2s), |
| INSN_LABEL(lcmp), |
| INSN_LABEL(fcmpl), |
| INSN_LABEL(fcmpg), |
| INSN_LABEL(dcmpl), |
| INSN_LABEL(dcmpg), |
| INSN_LABEL(ifeq), |
| INSN_LABEL(ifne), |
| INSN_LABEL(iflt), |
| INSN_LABEL(ifge), |
| INSN_LABEL(ifgt), |
| INSN_LABEL(ifle), |
| INSN_LABEL(if_icmpeq), |
| INSN_LABEL(if_icmpne), |
| INSN_LABEL(if_icmplt), |
| INSN_LABEL(if_icmpge), |
| INSN_LABEL(if_icmpgt), |
| INSN_LABEL(if_icmple), |
| INSN_LABEL(if_acmpeq), |
| INSN_LABEL(if_acmpne), |
| INSN_LABEL(goto), |
| INSN_LABEL(jsr), |
| INSN_LABEL(ret), |
| INSN_LABEL(tableswitch), |
| INSN_LABEL(lookupswitch), |
| INSN_LABEL(ireturn), |
| INSN_LABEL(lreturn), |
| INSN_LABEL(freturn), |
| INSN_LABEL(dreturn), |
| INSN_LABEL(areturn), |
| INSN_LABEL(return), |
| INSN_LABEL(getstatic), |
| INSN_LABEL(putstatic), |
| INSN_LABEL(getfield), |
| INSN_LABEL(putfield), |
| INSN_LABEL(invokevirtual), |
| INSN_LABEL(invokespecial), |
| INSN_LABEL(invokestatic), |
| INSN_LABEL(invokeinterface), |
| 0, /* op_xxxunusedxxx1, */ |
| INSN_LABEL(new), |
| INSN_LABEL(newarray), |
| INSN_LABEL(anewarray), |
| INSN_LABEL(arraylength), |
| INSN_LABEL(athrow), |
| INSN_LABEL(checkcast), |
| INSN_LABEL(instanceof), |
| INSN_LABEL(monitorenter), |
| INSN_LABEL(monitorexit), |
| INSN_LABEL(wide), |
| INSN_LABEL(multianewarray), |
| INSN_LABEL(ifnull), |
| INSN_LABEL(ifnonnull), |
| INSN_LABEL(goto_w), |
| INSN_LABEL(jsr_w), |
| }; |
| |
| /* If the macro INLINE_SWITCH is not defined, then the main loop |
| operates as one big (normal) switch statement. If it is defined, |
| then the case selection is performed `inline' in the end of the |
| code for each case. The latter saves a native branch instruction |
| for each java-instruction, but expands the code size somewhat. |
| |
| NOTE: On i386 defining INLINE_SWITCH improves over all |
| performance approximately seven percent, but it may be different |
| for other machines. At some point, this may be made into a proper |
| configuration parameter. */ |
| |
| #define INLINE_SWITCH |
| |
| #ifdef INLINE_SWITCH |
| |
| #define NEXT_INSN do { GOTO_INSN(*pc++); } while (0) |
| |
| |
| NEXT_INSN; |
| #else |
| |
| #define NEXT_INSN goto next_insn |
| |
| next_insn: |
| GOTO_INSN (*pc++); |
| |
| #endif |
| |
| /* The first few instructions here are ordered according to their |
| frequency, in the hope that this will improve code locality a |
| little. */ |
| |
| insn_aload_0: // 0x2a |
| LOADA(0); |
| NEXT_INSN; |
| |
| insn_iload: // 0x15 |
| LOADI (get1u (pc++)); |
| NEXT_INSN; |
| |
| insn_iload_1: // 0x1b |
| LOADI (1); |
| NEXT_INSN; |
| |
| insn_invokevirtual: // 0xb6 |
| SAVE_PC; |
| { |
| int index = get2u (pc); pc += 2; |
| |
| /* _Jv_ResolvePoolEntry returns immediately if the value already |
| * is resolved. If we want to clutter up the code here to gain |
| * a little performance, then we can check the corresponding bit |
| * JV_CONSTANT_ResolvedFlag in the tag directly. For now, I |
| * don't think it is worth it. */ |
| |
| rmeth = (_Jv_ResolvePoolEntry (defining_class, index)).rmethod; |
| |
| sp -= rmeth->stack_item_count; |
| // We don't use NULLCHECK here because we can't rely on that |
| // working if the method is final. So instead we do an |
| // explicit test. |
| if (! sp[0].o) |
| throw new java::lang::NullPointerException; |
| |
| if (rmeth->vtable_index == -1) |
| { |
| // final methods do not appear in the vtable, |
| // if it does not appear in the superclass. |
| fun = (void (*)()) rmeth->method->ncode; |
| } |
| else |
| { |
| jobject rcv = sp[0].o; |
| _Jv_VTable *table = *(_Jv_VTable**)rcv; |
| fun = (void (*)()) table->get_method(rmeth->vtable_index); |
| } |
| } |
| goto perform_invoke; |
| |
| perform_invoke: |
| { |
| /* here goes the magic again... */ |
| ffi_cif *cif = &rmeth->cif; |
| ffi_raw *raw = (ffi_raw*) sp; |
| |
| jdouble rvalue; |
| |
| #if FFI_NATIVE_RAW_API |
| /* We assume that this is only implemented if it's correct */ |
| /* to use it here. On a 64 bit machine, it never is. */ |
| ffi_raw_call (cif, fun, (void*)&rvalue, raw); |
| #else |
| ffi_java_raw_call (cif, fun, (void*)&rvalue, raw); |
| #endif |
| |
| int rtype = cif->rtype->type; |
| |
| /* the likelyhood of object, int, or void return is very high, |
| * so those are checked before the switch */ |
| if (rtype == FFI_TYPE_POINTER) |
| { |
| PUSHA (*(jobject*)&rvalue); |
| } |
| else if (rtype == FFI_TYPE_SINT32) |
| { |
| PUSHI (*(jint*)&rvalue); |
| } |
| else if (rtype == FFI_TYPE_VOID) |
| { |
| /* skip */ |
| } |
| else switch (rtype) |
| { |
| case FFI_TYPE_SINT8: |
| { |
| jbyte value = (*(jint*)&rvalue) & 0xff; |
| PUSHI (value); |
| } |
| break; |
| |
| case FFI_TYPE_SINT16: |
| { |
| jshort value = (*(jint*)&rvalue) & 0xffff; |
| PUSHI (value); |
| } |
| break; |
| |
| case FFI_TYPE_UINT16: |
| { |
| jint value = (*(jint*)&rvalue) & 0xffff; |
| PUSHI (value); |
| } |
| break; |
| |
| case FFI_TYPE_FLOAT: |
| PUSHF (*(jfloat*)&rvalue); |
| break; |
| |
| case FFI_TYPE_DOUBLE: |
| PUSHD (rvalue); |
| break; |
| |
| case FFI_TYPE_SINT64: |
| PUSHL (*(jlong*)&rvalue); |
| break; |
| |
| default: |
| throw_internal_error ("unknown return type in invokeXXX"); |
| } |
| |
| } |
| NEXT_INSN; |
| |
| |
| insn_nop: |
| NEXT_INSN; |
| |
| insn_aconst_null: |
| PUSHA (NULL); |
| NEXT_INSN; |
| |
| insn_iconst_m1: |
| PUSHI (-1); |
| NEXT_INSN; |
| |
| insn_iconst_0: |
| PUSHI (0); |
| NEXT_INSN; |
| |
| insn_iconst_1: |
| PUSHI (1); |
| NEXT_INSN; |
| |
| insn_iconst_2: |
| PUSHI (2); |
| NEXT_INSN; |
| |
| insn_iconst_3: |
| PUSHI (3); |
| NEXT_INSN; |
| |
| insn_iconst_4: |
| PUSHI (4); |
| NEXT_INSN; |
| |
| insn_iconst_5: |
| PUSHI (5); |
| NEXT_INSN; |
| |
| insn_lconst_0: |
| PUSHL (0); |
| NEXT_INSN; |
| |
| insn_lconst_1: |
| PUSHL (1); |
| NEXT_INSN; |
| |
| insn_fconst_0: |
| PUSHF (0); |
| NEXT_INSN; |
| |
| insn_fconst_1: |
| PUSHF (1); |
| NEXT_INSN; |
| |
| insn_fconst_2: |
| PUSHF (2); |
| NEXT_INSN; |
| |
| insn_dconst_0: |
| PUSHD (0); |
| NEXT_INSN; |
| |
| insn_dconst_1: |
| PUSHD (1); |
| NEXT_INSN; |
| |
| insn_bipush: |
| PUSHI (get1s(pc++)); |
| NEXT_INSN; |
| |
| insn_sipush: |
| PUSHI (get2s(pc)); pc += 2; |
| NEXT_INSN; |
| |
| insn_ldc: |
| { |
| int index = get1u (pc++); |
| PUSHA(pool_data[index].o); |
| } |
| NEXT_INSN; |
| |
| insn_ldc_w: |
| { |
| int index = get2u (pc); pc += 2; |
| PUSHA(pool_data[index].o); |
| } |
| NEXT_INSN; |
| |
| insn_ldc2_w: |
| { |
| int index = get2u (pc); pc += 2; |
| memcpy (sp, &pool_data[index], 2*sizeof (_Jv_word)); |
| sp += 2; |
| } |
| NEXT_INSN; |
| |
| insn_lload: |
| LOADL (get1u (pc++)); |
| NEXT_INSN; |
| |
| insn_fload: |
| LOADF (get1u (pc++)); |
| NEXT_INSN; |
| |
| insn_dload: |
| LOADD (get1u (pc++)); |
| NEXT_INSN; |
| |
| insn_aload: |
| LOADA (get1u (pc++)); |
| NEXT_INSN; |
| |
| insn_iload_0: |
| LOADI (0); |
| NEXT_INSN; |
| |
| insn_iload_2: |
| LOADI (2); |
| NEXT_INSN; |
| |
| insn_iload_3: |
| LOADI (3); |
| NEXT_INSN; |
| |
| insn_lload_0: |
| LOADL (0); |
| NEXT_INSN; |
| |
| insn_lload_1: |
| LOADL (1); |
| NEXT_INSN; |
| |
| insn_lload_2: |
| LOADL (2); |
| NEXT_INSN; |
| |
| insn_lload_3: |
| LOADL (3); |
| NEXT_INSN; |
| |
| insn_fload_0: |
| LOADF (0); |
| NEXT_INSN; |
| |
| insn_fload_1: |
| LOADF (1); |
| NEXT_INSN; |
| |
| insn_fload_2: |
| LOADF (2); |
| NEXT_INSN; |
| |
| insn_fload_3: |
| LOADF (3); |
| NEXT_INSN; |
| |
| insn_dload_0: |
| LOADD (0); |
| NEXT_INSN; |
| |
| insn_dload_1: |
| LOADD (1); |
| NEXT_INSN; |
| |
| insn_dload_2: |
| LOADD (2); |
| NEXT_INSN; |
| |
| insn_dload_3: |
| LOADD (3); |
| NEXT_INSN; |
| |
| insn_aload_1: |
| LOADA(1); |
| NEXT_INSN; |
| |
| insn_aload_2: |
| LOADA(2); |
| NEXT_INSN; |
| |
| insn_aload_3: |
| LOADA(3); |
| NEXT_INSN; |
| |
| insn_iaload: |
| { |
| jint index = POPI(); |
| jintArray arr = (jintArray) POPA(); |
| NULLARRAYCHECK (arr); |
| ARRAYBOUNDSCHECK (arr, index); |
| PUSHI( elements(arr)[index] ); |
| } |
| NEXT_INSN; |
| |
| insn_laload: |
| { |
| jint index = POPI(); |
| jlongArray arr = (jlongArray) POPA(); |
| NULLARRAYCHECK (arr); |
| ARRAYBOUNDSCHECK (arr, index); |
| PUSHL( elements(arr)[index] ); |
| } |
| NEXT_INSN; |
| |
| insn_faload: |
| { |
| jint index = POPI(); |
| jfloatArray arr = (jfloatArray) POPA(); |
| NULLARRAYCHECK (arr); |
| ARRAYBOUNDSCHECK (arr, index); |
| PUSHF( elements(arr)[index] ); |
| } |
| NEXT_INSN; |
| |
| insn_daload: |
| { |
| jint index = POPI(); |
| jdoubleArray arr = (jdoubleArray) POPA(); |
| NULLARRAYCHECK (arr); |
| ARRAYBOUNDSCHECK (arr, index); |
| PUSHD( elements(arr)[index] ); |
| } |
| NEXT_INSN; |
| |
| insn_aaload: |
| { |
| jint index = POPI(); |
| jobjectArray arr = (jobjectArray) POPA(); |
| NULLARRAYCHECK (arr); |
| ARRAYBOUNDSCHECK (arr, index); |
| PUSHA( elements(arr)[index] ); |
| } |
| NEXT_INSN; |
| |
| insn_baload: |
| { |
| jint index = POPI(); |
| jbyteArray arr = (jbyteArray) POPA(); |
| NULLARRAYCHECK (arr); |
| ARRAYBOUNDSCHECK (arr, index); |
| PUSHI( elements(arr)[index] ); |
| } |
| NEXT_INSN; |
| |
| insn_caload: |
| { |
| jint index = POPI(); |
| jcharArray arr = (jcharArray) POPA(); |
| NULLARRAYCHECK (arr); |
| ARRAYBOUNDSCHECK (arr, index); |
| PUSHI( elements(arr)[index] ); |
| } |
| NEXT_INSN; |
| |
| insn_saload: |
| { |
| jint index = POPI(); |
| jshortArray arr = (jshortArray) POPA(); |
| NULLARRAYCHECK (arr); |
| ARRAYBOUNDSCHECK (arr, index); |
| PUSHI( elements(arr)[index] ); |
| } |
| NEXT_INSN; |
| |
| insn_istore: |
| STOREI (get1u (pc++)); |
| NEXT_INSN; |
| |
| insn_lstore: |
| STOREL (get1u (pc++)); |
| NEXT_INSN; |
| |
| insn_fstore: |
| STOREF (get1u (pc++)); |
| NEXT_INSN; |
| |
| insn_dstore: |
| STORED (get1u (pc++)); |
| NEXT_INSN; |
| |
| insn_astore: |
| STOREA (get1u (pc++)); |
| NEXT_INSN; |
| |
| insn_istore_0: |
| STOREI (0); |
| NEXT_INSN; |
| |
| insn_istore_1: |
| STOREI (1); |
| NEXT_INSN; |
| |
| insn_istore_2: |
| STOREI (2); |
| NEXT_INSN; |
| |
| insn_istore_3: |
| STOREI (3); |
| NEXT_INSN; |
| |
| insn_lstore_0: |
| STOREL (0); |
| NEXT_INSN; |
| |
| insn_lstore_1: |
| STOREL (1); |
| NEXT_INSN; |
| |
| insn_lstore_2: |
| STOREL (2); |
| NEXT_INSN; |
| |
| insn_lstore_3: |
| STOREL (3); |
| NEXT_INSN; |
| |
| insn_fstore_0: |
| STOREF (0); |
| NEXT_INSN; |
| |
| insn_fstore_1: |
| STOREF (1); |
| NEXT_INSN; |
| |
| insn_fstore_2: |
| STOREF (2); |
| NEXT_INSN; |
| |
| insn_fstore_3: |
| STOREF (3); |
| NEXT_INSN; |
| |
| insn_dstore_0: |
| STORED (0); |
| NEXT_INSN; |
| |
| insn_dstore_1: |
| STORED (1); |
| NEXT_INSN; |
| |
| insn_dstore_2: |
| STORED (2); |
| NEXT_INSN; |
| |
| insn_dstore_3: |
| STORED (3); |
| NEXT_INSN; |
| |
| insn_astore_0: |
| STOREA(0); |
| NEXT_INSN; |
| |
| insn_astore_1: |
| STOREA(1); |
| NEXT_INSN; |
| |
| insn_astore_2: |
| STOREA(2); |
| NEXT_INSN; |
| |
| insn_astore_3: |
| STOREA(3); |
| NEXT_INSN; |
| |
| insn_iastore: |
| { |
| jint value = POPI(); |
| jint index = POPI(); |
| jintArray arr = (jintArray) POPA(); |
| NULLARRAYCHECK (arr); |
| ARRAYBOUNDSCHECK (arr, index); |
| elements(arr)[index] = value; |
| } |
| NEXT_INSN; |
| |
| insn_lastore: |
| { |
| jlong value = POPL(); |
| jint index = POPI(); |
| jlongArray arr = (jlongArray) POPA(); |
| NULLARRAYCHECK (arr); |
| ARRAYBOUNDSCHECK (arr, index); |
| elements(arr)[index] = value; |
| } |
| NEXT_INSN; |
| |
| insn_fastore: |
| { |
| jfloat value = POPF(); |
| jint index = POPI(); |
| jfloatArray arr = (jfloatArray) POPA(); |
| NULLARRAYCHECK (arr); |
| ARRAYBOUNDSCHECK (arr, index); |
| elements(arr)[index] = value; |
| } |
| NEXT_INSN; |
| |
| insn_dastore: |
| { |
| jdouble value = POPD(); |
| jint index = POPI(); |
| jdoubleArray arr = (jdoubleArray) POPA(); |
| NULLARRAYCHECK (arr); |
| ARRAYBOUNDSCHECK (arr, index); |
| elements(arr)[index] = value; |
| } |
| NEXT_INSN; |
| |
| insn_aastore: |
| { |
| jobject value = POPA(); |
| jint index = POPI(); |
| jobjectArray arr = (jobjectArray) POPA(); |
| NULLARRAYCHECK (arr); |
| ARRAYBOUNDSCHECK (arr, index); |
| _Jv_CheckArrayStore (arr, value); |
| elements(arr)[index] = value; |
| } |
| NEXT_INSN; |
| |
| insn_bastore: |
| { |
| jbyte value = (jbyte) POPI(); |
| jint index = POPI(); |
| jbyteArray arr = (jbyteArray) POPA(); |
| NULLARRAYCHECK (arr); |
| ARRAYBOUNDSCHECK (arr, index); |
| elements(arr)[index] = value; |
| } |
| NEXT_INSN; |
| |
| insn_castore: |
| { |
| jchar value = (jchar) POPI(); |
| jint index = POPI(); |
| jcharArray arr = (jcharArray) POPA(); |
| NULLARRAYCHECK (arr); |
| ARRAYBOUNDSCHECK (arr, index); |
| elements(arr)[index] = value; |
| } |
| NEXT_INSN; |
| |
| insn_sastore: |
| { |
| jshort value = (jshort) POPI(); |
| jint index = POPI(); |
| jshortArray arr = (jshortArray) POPA(); |
| NULLARRAYCHECK (arr); |
| ARRAYBOUNDSCHECK (arr, index); |
| elements(arr)[index] = value; |
| } |
| NEXT_INSN; |
| |
| insn_pop: |
| sp -= 1; |
| NEXT_INSN; |
| |
| insn_pop2: |
| sp -= 2; |
| NEXT_INSN; |
| |
| insn_dup: |
| sp[0] = sp[-1]; |
| sp += 1; |
| NEXT_INSN; |
| |
| insn_dup_x1: |
| dupx (sp, 1, 1); sp+=1; |
| NEXT_INSN; |
| |
| insn_dup_x2: |
| dupx (sp, 1, 2); sp+=1; |
| NEXT_INSN; |
| |
| insn_dup2: |
| sp[0] = sp[-2]; |
| sp[1] = sp[-1]; |
| sp += 2; |
| NEXT_INSN; |
| |
| insn_dup2_x1: |
| dupx (sp, 2, 1); sp+=2; |
| NEXT_INSN; |
| |
| insn_dup2_x2: |
| dupx (sp, 2, 2); sp+=2; |
| NEXT_INSN; |
| |
| insn_swap: |
| { |
| jobject tmp1 = POPA(); |
| jobject tmp2 = POPA(); |
| PUSHA (tmp1); |
| PUSHA (tmp2); |
| } |
| NEXT_INSN; |
| |
| insn_iadd: |
| BINOPI(+); |
| NEXT_INSN; |
| |
| insn_ladd: |
| BINOPL(+); |
| NEXT_INSN; |
| |
| insn_fadd: |
| BINOPF(+); |
| NEXT_INSN; |
| |
| insn_dadd: |
| BINOPD(+); |
| NEXT_INSN; |
| |
| insn_isub: |
| BINOPI(-); |
| NEXT_INSN; |
| |
| insn_lsub: |
| BINOPL(-); |
| NEXT_INSN; |
| |
| insn_fsub: |
| BINOPF(-); |
| NEXT_INSN; |
| |
| insn_dsub: |
| BINOPD(-); |
| NEXT_INSN; |
| |
| insn_imul: |
| BINOPI(*); |
| NEXT_INSN; |
| |
| insn_lmul: |
| BINOPL(*); |
| NEXT_INSN; |
| |
| insn_fmul: |
| BINOPF(*); |
| NEXT_INSN; |
| |
| insn_dmul: |
| BINOPD(*); |
| NEXT_INSN; |
| |
| insn_idiv: |
| SAVE_PC; |
| { |
| jint value2 = POPI(); |
| jint value1 = POPI(); |
| jint res = _Jv_divI (value1, value2); |
| PUSHI (res); |
| } |
| NEXT_INSN; |
| |
| insn_ldiv: |
| SAVE_PC; |
| { |
| jlong value2 = POPL(); |
| jlong value1 = POPL(); |
| jlong res = _Jv_divJ (value1, value2); |
| PUSHL (res); |
| } |
| NEXT_INSN; |
| |
| insn_fdiv: |
| { |
| jfloat value2 = POPF(); |
| jfloat value1 = POPF(); |
| jfloat res = value1 / value2; |
| PUSHF (res); |
| } |
| NEXT_INSN; |
| |
| insn_ddiv: |
| { |
| jdouble value2 = POPD(); |
| jdouble value1 = POPD(); |
| jdouble res = value1 / value2; |
| PUSHD (res); |
| } |
| NEXT_INSN; |
| |
| insn_irem: |
| SAVE_PC; |
| { |
| jint value2 = POPI(); |
| jint value1 = POPI(); |
| jint res = _Jv_remI (value1, value2); |
| PUSHI (res); |
| } |
| NEXT_INSN; |
| |
| insn_lrem: |
| SAVE_PC; |
| { |
| jlong value2 = POPL(); |
| jlong value1 = POPL(); |
| jlong res = _Jv_remJ (value1, value2); |
| PUSHL (res); |
| } |
| NEXT_INSN; |
| |
| insn_frem: |
| { |
| jfloat value2 = POPF(); |
| jfloat value1 = POPF(); |
| jfloat res = __ieee754_fmod (value1, value2); |
| PUSHF (res); |
| } |
| NEXT_INSN; |
| |
| insn_drem: |
| { |
| jdouble value2 = POPD(); |
| jdouble value1 = POPD(); |
| jdouble res = __ieee754_fmod (value1, value2); |
| PUSHD (res); |
| } |
| NEXT_INSN; |
| |
| insn_ineg: |
| { |
| jint value = POPI(); |
| PUSHI (value * -1); |
| } |
| NEXT_INSN; |
| |
| insn_lneg: |
| { |
| jlong value = POPL(); |
| PUSHL (value * -1); |
| } |
| NEXT_INSN; |
| |
| insn_fneg: |
| { |
| jfloat value = POPF(); |
| PUSHF (value * -1); |
| } |
| NEXT_INSN; |
| |
| insn_dneg: |
| { |
| jdouble value = POPD(); |
| PUSHD (value * -1); |
| } |
| NEXT_INSN; |
| |
| insn_ishl: |
| { |
| jint shift = (POPI() & 0x1f); |
| jint value = POPI(); |
| PUSHI (value << shift); |
| } |
| NEXT_INSN; |
| |
| insn_lshl: |
| { |
| jint shift = (POPI() & 0x3f); |
| jlong value = POPL(); |
| PUSHL (value << shift); |
| } |
| NEXT_INSN; |
| |
| insn_ishr: |
| { |
| jint shift = (POPI() & 0x1f); |
| jint value = POPI(); |
| PUSHI (value >> shift); |
| } |
| NEXT_INSN; |
| |
| insn_lshr: |
| { |
| jint shift = (POPI() & 0x3f); |
| jlong value = POPL(); |
| PUSHL (value >> shift); |
| } |
| NEXT_INSN; |
| |
| insn_iushr: |
| { |
| jint shift = (POPI() & 0x1f); |
| unsigned long value = POPI(); |
| PUSHI ((jint) (value >> shift)); |
| } |
| NEXT_INSN; |
| |
| insn_lushr: |
| { |
| jint shift = (POPI() & 0x3f); |
| UINT64 value = (UINT64) POPL(); |
| PUSHL ((value >> shift)); |
| } |
| NEXT_INSN; |
| |
| insn_iand: |
| BINOPI (&); |
| NEXT_INSN; |
| |
| insn_land: |
| BINOPL (&); |
| NEXT_INSN; |
| |
| insn_ior: |
| BINOPI (|); |
| NEXT_INSN; |
| |
| insn_lor: |
| BINOPL (|); |
| NEXT_INSN; |
| |
| insn_ixor: |
| BINOPI (^); |
| NEXT_INSN; |
| |
| insn_lxor: |
| BINOPL (^); |
| NEXT_INSN; |
| |
| insn_iinc: |
| { |
| jint index = get1u (pc++); |
| jint amount = get1s (pc++); |
| locals[index].i += amount; |
| } |
| NEXT_INSN; |
| |
| insn_i2l: |
| {jlong value = POPI(); PUSHL (value);} |
| NEXT_INSN; |
| |
| insn_i2f: |
| {jfloat value = POPI(); PUSHF (value);} |
| NEXT_INSN; |
| |
| insn_i2d: |
| {jdouble value = POPI(); PUSHD (value);} |
| NEXT_INSN; |
| |
| insn_l2i: |
| {jint value = POPL(); PUSHI (value);} |
| NEXT_INSN; |
| |
| insn_l2f: |
| {jfloat value = POPL(); PUSHF (value);} |
| NEXT_INSN; |
| |
| insn_l2d: |
| {jdouble value = POPL(); PUSHD (value);} |
| NEXT_INSN; |
| |
| insn_f2i: |
| { |
| using namespace java::lang; |
| jint value = convert (POPF (), Integer::MIN_VALUE, Integer::MAX_VALUE); |
| PUSHI(value); |
| } |
| NEXT_INSN; |
| |
| insn_f2l: |
| { |
| using namespace java::lang; |
| jlong value = convert (POPF (), Long::MIN_VALUE, Long::MAX_VALUE); |
| PUSHL(value); |
| } |
| NEXT_INSN; |
| |
| insn_f2d: |
| { jdouble value = POPF (); PUSHD(value); } |
| NEXT_INSN; |
| |
| insn_d2i: |
| { |
| using namespace java::lang; |
| jint value = convert (POPD (), Integer::MIN_VALUE, Integer::MAX_VALUE); |
| PUSHI(value); |
| } |
| NEXT_INSN; |
| |
| insn_d2l: |
| { |
| using namespace java::lang; |
| jlong value = convert (POPD (), Long::MIN_VALUE, Long::MAX_VALUE); |
| PUSHL(value); |
| } |
| NEXT_INSN; |
| |
| insn_d2f: |
| { jfloat value = POPD (); PUSHF(value); } |
| NEXT_INSN; |
| |
| insn_i2b: |
| { jbyte value = POPI (); PUSHI(value); } |
| NEXT_INSN; |
| |
| insn_i2c: |
| { jchar value = POPI (); PUSHI(value); } |
| NEXT_INSN; |
| |
| insn_i2s: |
| { jshort value = POPI (); PUSHI(value); } |
| NEXT_INSN; |
| |
| insn_lcmp: |
| { |
| jlong value2 = POPL (); |
| jlong value1 = POPL (); |
| if (value1 > value2) |
| { PUSHI (1); } |
| else if (value1 == value2) |
| { PUSHI (0); } |
| else |
| { PUSHI (-1); } |
| } |
| NEXT_INSN; |
| |
| insn_fcmpl: |
| insn_fcmpg: |
| { |
| jfloat value2 = POPF (); |
| jfloat value1 = POPF (); |
| if (value1 > value2) |
| PUSHI (1); |
| else if (value1 == value2) |
| PUSHI (0); |
| else if (value1 < value2) |
| PUSHI (-1); |
| else if ((*(pc-1)) == op_fcmpg) |
| PUSHI (1); |
| else |
| PUSHI (-1); |
| } |
| NEXT_INSN; |
| |
| insn_dcmpl: |
| insn_dcmpg: |
| { |
| jdouble value2 = POPD (); |
| jdouble value1 = POPD (); |
| if (value1 > value2) |
| PUSHI (1); |
| else if (value1 == value2) |
| PUSHI (0); |
| else if (value1 < value2) |
| PUSHI (-1); |
| else if ((*(pc-1)) == op_dcmpg) |
| PUSHI (1); |
| else |
| PUSHI (-1); |
| } |
| NEXT_INSN; |
| |
| insn_ifeq: |
| { |
| jint offset = get2s (pc); |
| if (POPI() == 0) |
| pc = pc-1+offset; |
| else |
| pc = pc+2; |
| } |
| NEXT_INSN; |
| |
| insn_ifne: |
| { |
| jint offset = get2s (pc); |
| if (POPI() != 0) |
| pc = pc-1+offset; |
| else |
| pc = pc+2; |
| } |
| NEXT_INSN; |
| |
| insn_iflt: |
| { |
| jint offset = get2s (pc); |
| if (POPI() < 0) |
| pc = pc-1+offset; |
| else |
| pc = pc+2; |
| } |
| NEXT_INSN; |
| |
| insn_ifge: |
| { |
| jint offset = get2s (pc); |
| if (POPI() >= 0) |
| pc = pc-1+offset; |
| else |
| pc = pc+2; |
| } |
| NEXT_INSN; |
| |
| insn_ifgt: |
| { |
| jint offset = get2s (pc); |
| if (POPI() > 0) |
| pc = pc-1+offset; |
| else |
| pc = pc+2; |
| } |
| NEXT_INSN; |
| |
| insn_ifle: |
| { |
| jint offset = get2s (pc); |
| if (POPI() <= 0) |
| pc = pc-1+offset; |
| else |
| pc = pc+2; |
| } |
| NEXT_INSN; |
| |
| insn_if_icmpeq: |
| { |
| jint offset = get2s (pc); |
| jint value2 = POPI(); |
| jint value1 = POPI(); |
| if (value1 == value2) |
| pc = pc-1+offset; |
| else |
| pc = pc+2; |
| } |
| NEXT_INSN; |
| |
| insn_if_icmpne: |
| { |
| jint offset = get2s (pc); |
| jint value2 = POPI(); |
| jint value1 = POPI(); |
| if (value1 != value2) |
| pc = pc-1+offset; |
| else |
| pc = pc+2; |
| } |
| NEXT_INSN; |
| |
| insn_if_icmplt: |
| { |
| jint offset = get2s (pc); |
| jint value2 = POPI(); |
| jint value1 = POPI(); |
| if (value1 < value2) |
| pc = pc-1+offset; |
| else |
| pc = pc+2; |
| } |
| NEXT_INSN; |
| |
| insn_if_icmpge: |
| { |
| jint offset = get2s (pc); |
| jint value2 = POPI(); |
| jint value1 = POPI(); |
| if (value1 >= value2) |
| pc = pc-1+offset; |
| else |
| pc = pc+2; |
| } |
| NEXT_INSN; |
| |
| insn_if_icmpgt: |
| { |
| jint offset = get2s (pc); |
| jint value2 = POPI(); |
| jint value1 = POPI(); |
| if (value1 > value2) |
| pc = pc-1+offset; |
| else |
| pc = pc+2; |
| } |
| NEXT_INSN; |
| |
| insn_if_icmple: |
| { |
| jint offset = get2s (pc); |
| jint value2 = POPI(); |
| jint value1 = POPI(); |
| if (value1 <= value2) |
| pc = pc-1+offset; |
| else |
| pc = pc+2; |
| } |
| NEXT_INSN; |
| |
| insn_if_acmpeq: |
| { |
| jint offset = get2s (pc); |
| jobject value2 = POPA(); |
| jobject value1 = POPA(); |
| if (value1 == value2) |
| pc = pc-1+offset; |
| else |
| pc = pc+2; |
| } |
| NEXT_INSN; |
| |
| insn_if_acmpne: |
| { |
| jint offset = get2s (pc); |
| jobject value2 = POPA(); |
| jobject value1 = POPA(); |
| if (value1 != value2) |
| pc = pc-1+offset; |
| else |
| pc = pc+2; |
| } |
| NEXT_INSN; |
| |
| insn_goto: |
| { |
| jint offset = get2s (pc); |
| pc = pc-1+offset; |
| } |
| NEXT_INSN; |
| |
| insn_jsr: |
| { |
| unsigned char *base_pc = pc-1; |
| jint offset = get2s (pc); pc += 2; |
| PUSHA ((jobject)pc); |
| pc = base_pc+offset; |
| } |
| NEXT_INSN; |
| |
| insn_ret: |
| { |
| jint index = get1u (pc); |
| pc = (unsigned char*) PEEKA (index); |
| } |
| NEXT_INSN; |
| |
| insn_tableswitch: |
| { |
| unsigned char *base_pc = pc-1; |
| int index = POPI(); |
| |
| unsigned char* base = bytecode (); |
| while ((pc-base) % 4 != 0) |
| pc++; |
| |
| jint def = get4 (pc); |
| jint low = get4 (pc+4); |
| jint high = get4 (pc+8); |
| |
| if (index < low || index > high) |
| pc = base_pc + def; |
| else |
| pc = base_pc + get4 (pc+4*(index-low+3)); |
| } |
| NEXT_INSN; |
| |
| insn_lookupswitch: |
| { |
| unsigned char *base_pc = pc-1; |
| int index = POPI(); |
| |
| unsigned char* base = bytecode (); |
| while ((pc-base) % 4 != 0) |
| pc++; |
| |
| jint def = get4 (pc); |
| jint npairs = get4 (pc+4); |
| |
| int max = npairs-1; |
| int min = 0; |
| |
| // simple binary search... |
| while (min < max) |
| { |
| int half = (min+max)/2; |
| int match = get4 (pc+ 4*(2 + 2*half)); |
| |
| if (index == match) |
| min = max = half; |
| |
| else if (index < match) |
| max = half-1; |
| |
| else |
| min = half+1; |
| } |
| |
| if (index == get4 (pc+ 4*(2 + 2*min))) |
| pc = base_pc + get4 (pc+ 4*(2 + 2*min + 1)); |
| else |
| pc = base_pc + def; |
| } |
| NEXT_INSN; |
| |
| /* on return, just save the sp and return to caller */ |
| insn_ireturn: |
| insn_lreturn: |
| insn_freturn: |
| insn_dreturn: |
| insn_areturn: |
| insn_return: |
| inv->sp = sp; |
| return; |
| |
| insn_getstatic: |
| SAVE_PC; |
| { |
| jint fieldref_index = get2u (pc); pc += 2; |
| _Jv_ResolvePoolEntry (defining_class, fieldref_index); |
| _Jv_Field *field = pool_data[fieldref_index].field; |
| |
| if ((field->flags & Modifier::STATIC) == 0) |
| throw_incompatible_class_change_error |
| (JvNewStringLatin1 ("field no longer static")); |
| |
| jclass type = field->type; |
| |
| if (type->isPrimitive ()) |
| { |
| switch (type->size_in_bytes) |
| { |
| case 1: |
| PUSHI (*(jbyte*) (field->u.addr)); |
| break; |
| |
| case 2: |
| if (type == JvPrimClass (char)) |
| PUSHI(*(jchar*) (field->u.addr)); |
| else |
| PUSHI(*(jshort*) (field->u.addr)); |
| break; |
| |
| case 4: |
| PUSHI(*(jint*) (field->u.addr)); |
| break; |
| |
| case 8: |
| PUSHL(*(jlong*) (field->u.addr)); |
| break; |
| } |
| } |
| else |
| { |
| PUSHA(*(jobject*) (field->u.addr)); |
| } |
| } |
| NEXT_INSN; |
| |
| insn_getfield: |
| SAVE_PC; |
| { |
| jint fieldref_index = get2u (pc); pc += 2; |
| _Jv_ResolvePoolEntry (defining_class, fieldref_index); |
| _Jv_Field *field = pool_data[fieldref_index].field; |
| |
| if ((field->flags & Modifier::STATIC) != 0) |
| throw_incompatible_class_change_error |
| (JvNewStringLatin1 ("field is static")); |
| |
| jclass type = field->type; |
| jint field_offset = field->u.boffset; |
| if (field_offset > 0xffff) |
| throw new java::lang::VirtualMachineError; |
| |
| jobject obj = POPA(); |
| NULLCHECK(obj); |
| |
| if (type->isPrimitive ()) |
| { |
| switch (type->size_in_bytes) |
| { |
| case 1: |
| PUSHI (*(jbyte*) ((char*)obj + field_offset)); |
| break; |
| |
| case 2: |
| if (type == JvPrimClass (char)) |
| PUSHI (*(jchar*) ((char*)obj + field_offset)); |
| else |
| PUSHI (*(jshort*) ((char*)obj + field_offset)); |
| break; |
| |
| case 4: |
| PUSHI (*(jint*) ((char*)obj + field_offset)); |
| break; |
| |
| case 8: |
| PUSHL(*(jlong*) ((char*)obj + field_offset)); |
| break; |
| } |
| } |
| else |
| { |
| PUSHA(*(jobject*) ((char*)obj + field_offset)); |
| } |
| } |
| NEXT_INSN; |
| |
| insn_putstatic: |
| SAVE_PC; |
| { |
| jint fieldref_index = get2u (pc); pc += 2; |
| _Jv_ResolvePoolEntry (defining_class, fieldref_index); |
| _Jv_Field *field = pool_data[fieldref_index].field; |
| |
| jclass type = field->type; |
| |
| // ResolvePoolEntry cannot check this |
| if ((field->flags & Modifier::STATIC) == 0) |
| throw_incompatible_class_change_error |
| (JvNewStringLatin1 ("field no longer static")); |
| |
| if (type->isPrimitive ()) |
| { |
| switch (type->size_in_bytes) |
| { |
| case 1: |
| { |
| jint value = POPI(); |
| *(jbyte*) (field->u.addr) = value; |
| break; |
| } |
| |
| case 2: |
| { |
| jint value = POPI(); |
| *(jchar*) (field->u.addr) = value; |
| break; |
| } |
| |
| case 4: |
| { |
| jint value = POPI(); |
| *(jint*) (field->u.addr) = value; |
| break; |
| } |
| |
| case 8: |
| { |
| jlong value = POPL(); |
| *(jlong*) (field->u.addr) = value; |
| break; |
| } |
| } |
| } |
| else |
| { |
| jobject value = POPA(); |
| *(jobject*) (field->u.addr) = value; |
| } |
| } |
| NEXT_INSN; |
| |
| |
| insn_putfield: |
| SAVE_PC; |
| { |
| jint fieldref_index = get2u (pc); pc += 2; |
| _Jv_ResolvePoolEntry (defining_class, fieldref_index); |
| _Jv_Field *field = pool_data[fieldref_index].field; |
| |
| jclass type = field->type; |
| |
| if ((field->flags & Modifier::STATIC) != 0) |
| throw_incompatible_class_change_error |
| (JvNewStringLatin1 ("field is static")); |
| |
| jint field_offset = field->u.boffset; |
| if (field_offset > 0xffff) |
| throw new java::lang::VirtualMachineError; |
| |
| if (type->isPrimitive ()) |
| { |
| switch (type->size_in_bytes) |
| { |
| case 1: |
| { |
| jint value = POPI(); |
| jobject obj = POPA(); |
| NULLCHECK(obj); |
| *(jbyte*) ((char*)obj + field_offset) = value; |
| break; |
| } |
| |
| case 2: |
| { |
| jint value = POPI(); |
| jobject obj = POPA(); |
| NULLCHECK(obj); |
| *(jchar*) ((char*)obj + field_offset) = value; |
| break; |
| } |
| |
| case 4: |
| { |
| jint value = POPI(); |
| jobject obj = POPA(); |
| NULLCHECK(obj); |
| *(jint*) ((char*)obj + field_offset) = value; |
| break; |
| } |
| |
| case 8: |
| { |
| jlong value = POPL(); |
| jobject obj = POPA(); |
| NULLCHECK(obj); |
| *(jlong*) ((char*)obj + field_offset) = value; |
| break; |
| } |
| } |
| } |
| else |
| { |
| jobject value = POPA(); |
| jobject obj = POPA(); |
| NULLCHECK(obj); |
| *(jobject*) ((char*)obj + field_offset) = value; |
| } |
| } |
| NEXT_INSN; |
| |
| insn_invokespecial: |
| SAVE_PC; |
| { |
| int index = get2u (pc); pc += 2; |
| |
| rmeth = (_Jv_ResolvePoolEntry (defining_class, index)).rmethod; |
| |
| sp -= rmeth->stack_item_count; |
| |
| NULLCHECK (sp[0].o); |
| |
| fun = (void (*)()) rmeth->method->ncode; |
| } |
| goto perform_invoke; |
| |
| insn_invokestatic: |
| SAVE_PC; |
| { |
| int index = get2u (pc); pc += 2; |
| |
| rmeth = (_Jv_ResolvePoolEntry (defining_class, index)).rmethod; |
| |
| sp -= rmeth->stack_item_count; |
| |
| _Jv_InitClass (rmeth->klass); |
| fun = (void (*)()) rmeth->method->ncode; |
| } |
| goto perform_invoke; |
| |
| insn_invokeinterface: |
| SAVE_PC; |
| { |
| int index = get2u (pc); pc += 2; |
| |
| // invokeinterface has two unused bytes... |
| pc += 2; |
| |
| rmeth = (_Jv_ResolvePoolEntry (defining_class, index)).rmethod; |
| |
| sp -= rmeth->stack_item_count; |
| |
| jobject rcv = sp[0].o; |
| |
| NULLCHECK (rcv); |
| |
| fun = (void (*)()) |
| _Jv_LookupInterfaceMethod (rcv->getClass (), |
| rmeth->method->name, |
| rmeth->method->signature); |
| } |
| goto perform_invoke; |
| |
| |
| insn_new: |
| SAVE_PC; |
| { |
| int index = get2u (pc); pc += 2; |
| jclass klass = (_Jv_ResolvePoolEntry (defining_class, index)).clazz; |
| _Jv_InitClass (klass); |
| jobject res = _Jv_AllocObject (klass, klass->size_in_bytes); |
| PUSHA (res); |
| } |
| NEXT_INSN; |
| |
| insn_newarray: |
| SAVE_PC; |
| { |
| int atype = get1u (pc++); |
| int size = POPI(); |
| jobject result = _Jv_NewArray (atype, size); |
| PUSHA (result); |
| } |
| NEXT_INSN; |
| |
| insn_anewarray: |
| SAVE_PC; |
| { |
| int index = get2u (pc); pc += 2; |
| jclass klass = (_Jv_ResolvePoolEntry (defining_class, index)).clazz; |
| int size = POPI(); |
| _Jv_InitClass (klass); |
| jobject result = _Jv_NewObjectArray (size, klass, 0); |
| PUSHA (result); |
| } |
| NEXT_INSN; |
| |
| insn_arraylength: |
| { |
| __JArray *arr = (__JArray*)POPA(); |
| NULLARRAYCHECK (arr); |
| PUSHI (arr->length); |
| } |
| NEXT_INSN; |
| |
| insn_athrow: |
| SAVE_PC; |
| { |
| jobject value = POPA(); |
| throw static_cast<jthrowable>(value); |
| } |
| NEXT_INSN; |
| |
| insn_checkcast: |
| SAVE_PC; |
| { |
| jobject value = POPA(); |
| jint index = get2u (pc); pc += 2; |
| jclass to = (_Jv_ResolvePoolEntry (defining_class, index)).clazz; |
| |
| if (value != NULL && ! to->isInstance (value)) |
| { |
| throw new java::lang::ClassCastException (to->getName()); |
| } |
| |
| PUSHA (value); |
| } |
| NEXT_INSN; |
| |
| insn_instanceof: |
| SAVE_PC; |
| { |
| jobject value = POPA(); |
| jint index = get2u (pc); pc += 2; |
| jclass to = (_Jv_ResolvePoolEntry (defining_class, index)).clazz; |
| PUSHI (to->isInstance (value)); |
| } |
| NEXT_INSN; |
| |
| insn_monitorenter: |
| SAVE_PC; |
| { |
| jobject value = POPA(); |
| NULLCHECK(value); |
| _Jv_MonitorEnter (value); |
| } |
| NEXT_INSN; |
| |
| insn_monitorexit: |
| SAVE_PC; |
| { |
| jobject value = POPA(); |
| NULLCHECK(value); |
| _Jv_MonitorExit (value); |
| } |
| NEXT_INSN; |
| |
| insn_ifnull: |
| { |
| unsigned char* base_pc = pc-1; |
| jint offset = get2s (pc); pc += 2; |
| jobject val = POPA(); |
| if (val == NULL) |
| pc = base_pc+offset; |
| } |
| NEXT_INSN; |
| |
| insn_ifnonnull: |
| { |
| unsigned char* base_pc = pc-1; |
| jint offset = get2s (pc); pc += 2; |
| jobject val = POPA(); |
| if (val != NULL) |
| pc = base_pc+offset; |
| } |
| NEXT_INSN; |
| |
| insn_wide: |
| SAVE_PC; |
| { |
| jint the_mod_op = get1u (pc++); |
| jint wide = get2u (pc); pc += 2; |
| |
| switch (the_mod_op) |
| { |
| case op_istore: |
| STOREI (wide); |
| NEXT_INSN; |
| |
| case op_fstore: |
| STOREF (wide); |
| NEXT_INSN; |
| |
| case op_astore: |
| STOREA (wide); |
| NEXT_INSN; |
| |
| case op_lload: |
| LOADL (wide); |
| NEXT_INSN; |
| |
| case op_dload: |
| LOADD (wide); |
| NEXT_INSN; |
| |
| case op_iload: |
| LOADI (wide); |
| NEXT_INSN; |
| |
| case op_aload: |
| LOADA (wide); |
| NEXT_INSN; |
| |
| case op_lstore: |
| STOREL (wide); |
| NEXT_INSN; |
| |
| case op_dstore: |
| STORED (wide); |
| NEXT_INSN; |
| |
| case op_ret: |
| pc = (unsigned char*) PEEKA (wide); |
| NEXT_INSN; |
| |
| case op_iinc: |
| { |
| jint amount = get2s (pc); pc += 2; |
| jint value = PEEKI (wide); |
| POKEI (wide, value+amount); |
| } |
| NEXT_INSN; |
| |
| default: |
| throw_internal_error ("illegal bytecode modified by wide"); |
| } |
| |
| } |
| |
| insn_multianewarray: |
| SAVE_PC; |
| { |
| int kind_index = get2u (pc); pc += 2; |
| int dim = get1u (pc); pc += 1; |
| |
| jclass type |
| = (_Jv_ResolvePoolEntry (defining_class, kind_index)).clazz; |
| _Jv_InitClass (type); |
| jint *sizes = (jint*) __builtin_alloca (sizeof (jint)*dim); |
| |
| for (int i = dim - 1; i >= 0; i--) |
| { |
| sizes[i] = POPI (); |
| } |
| |
| jobject res = _Jv_NewMultiArray (type,dim, sizes); |
| |
| PUSHA (res); |
| } |
| NEXT_INSN; |
| |
| insn_goto_w: |
| { |
| unsigned char* base_pc = pc-1; |
| int offset = get4 (pc); pc += 4; |
| pc = base_pc+offset; |
| } |
| NEXT_INSN; |
| |
| insn_jsr_w: |
| { |
| unsigned char* base_pc = pc-1; |
| int offset = get4 (pc); pc += 4; |
| PUSHA((jobject)pc); |
| pc = base_pc+offset; |
| } |
| NEXT_INSN; |
| } |
| |
| |
| static void |
| throw_internal_error (char *msg) |
| { |
| throw new java::lang::InternalError (JvNewStringLatin1 (msg)); |
| } |
| |
| static void |
| throw_incompatible_class_change_error (jstring msg) |
| { |
| throw new java::lang::IncompatibleClassChangeError (msg); |
| } |
| |
| #ifndef HANDLE_SEGV |
| static java::lang::NullPointerException *null_pointer_exc; |
| static void |
| throw_null_pointer_exception () |
| { |
| if (null_pointer_exc == NULL) |
| null_pointer_exc = new java::lang::NullPointerException; |
| |
| throw null_pointer_exc; |
| } |
| #endif |
| |
| #endif // INTERPRETER |