| // interpret.cc - Code for the interpreter | |
| /* Copyright (C) 1999, 2000, 2001 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/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]; | |
| } | |
| }; | |
| #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) | |
| #else | |
| #define NULLCHECK(X) \ | |
| do { if ((X)==NULL) throw_null_pointer_exception (); } while (0) | |
| #endif | |
| // 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; | |
| } | |
| bool _Jv_InterpMethod::find_exception (jobject ex, | |
| _Jv_InterpMethodInvocation *inv) | |
| { | |
| int logical_pc = inv->pc - 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), | |
| }; | |
| #define SAVE_PC inv->pc = pc-1 | |
| /* 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: | |
| SAVE_PC; | |
| { | |
| jint index = POPI(); | |
| jintArray arr = (jintArray) POPA(); | |
| NULLCHECK (arr); | |
| if (index < 0 || index >= arr->length) | |
| { | |
| _Jv_ThrowBadArrayIndex (index); | |
| } | |
| PUSHI( elements(arr)[index] ); | |
| } | |
| NEXT_INSN; | |
| insn_laload: | |
| SAVE_PC; | |
| { | |
| jint index = POPI(); | |
| jlongArray arr = (jlongArray) POPA(); | |
| NULLCHECK (arr); | |
| if (index < 0 || index >= arr->length) | |
| { | |
| _Jv_ThrowBadArrayIndex (index); | |
| } | |
| PUSHL( elements(arr)[index] ); | |
| } | |
| NEXT_INSN; | |
| insn_faload: | |
| SAVE_PC; | |
| { | |
| jint index = POPI(); | |
| jfloatArray arr = (jfloatArray) POPA(); | |
| NULLCHECK (arr); | |
| if (index < 0 || index >= arr->length) | |
| { | |
| _Jv_ThrowBadArrayIndex (index); | |
| } | |
| PUSHF( elements(arr)[index] ); | |
| } | |
| NEXT_INSN; | |
| insn_daload: | |
| SAVE_PC; | |
| { | |
| jint index = POPI(); | |
| jdoubleArray arr = (jdoubleArray) POPA(); | |
| NULLCHECK (arr); | |
| if (index < 0 || index >= arr->length) | |
| { | |
| _Jv_ThrowBadArrayIndex (index); | |
| } | |
| PUSHD( elements(arr)[index] ); | |
| } | |
| NEXT_INSN; | |
| insn_aaload: | |
| SAVE_PC; | |
| { | |
| jint index = POPI(); | |
| jobjectArray arr = (jobjectArray) POPA(); | |
| NULLCHECK (arr); | |
| if (index < 0 || index >= arr->length) | |
| { | |
| _Jv_ThrowBadArrayIndex (index); | |
| } | |
| PUSHA( elements(arr)[index] ); | |
| } | |
| NEXT_INSN; | |
| insn_baload: | |
| SAVE_PC; | |
| { | |
| jint index = POPI(); | |
| jbyteArray arr = (jbyteArray) POPA(); | |
| NULLCHECK (arr); | |
| if (index < 0 || index >= arr->length) | |
| { | |
| _Jv_ThrowBadArrayIndex (index); | |
| } | |
| PUSHI( elements(arr)[index] ); | |
| } | |
| NEXT_INSN; | |
| insn_caload: | |
| SAVE_PC; | |
| { | |
| jint index = POPI(); | |
| jcharArray arr = (jcharArray) POPA(); | |
| NULLCHECK (arr); | |
| if (index < 0 || index >= arr->length) | |
| { | |
| _Jv_ThrowBadArrayIndex (index); | |
| } | |
| PUSHI( elements(arr)[index] ); | |
| } | |
| NEXT_INSN; | |
| insn_saload: | |
| SAVE_PC; | |
| { | |
| jint index = POPI(); | |
| jshortArray arr = (jshortArray) POPA(); | |
| NULLCHECK (arr); | |
| if (index < 0 || index >= arr->length) | |
| { | |
| _Jv_ThrowBadArrayIndex (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: | |
| SAVE_PC; | |
| { | |
| jint value = POPI(); | |
| jint index = POPI(); | |
| jintArray arr = (jintArray) POPA(); | |
| NULLCHECK (arr); | |
| if (index < 0 || index >= arr->length) | |
| { | |
| _Jv_ThrowBadArrayIndex (index); | |
| } | |
| elements(arr)[index] = value; | |
| } | |
| NEXT_INSN; | |
| insn_lastore: | |
| SAVE_PC; | |
| { | |
| jlong value = POPL(); | |
| jint index = POPI(); | |
| jlongArray arr = (jlongArray) POPA(); | |
| NULLCHECK (arr); | |
| if (index < 0 || index >= arr->length) | |
| { | |
| _Jv_ThrowBadArrayIndex (index); | |
| } | |
| elements(arr)[index] = value; | |
| } | |
| NEXT_INSN; | |
| insn_fastore: | |
| SAVE_PC; | |
| { | |
| jfloat value = POPF(); | |
| jint index = POPI(); | |
| jfloatArray arr = (jfloatArray) POPA(); | |
| NULLCHECK (arr); | |
| if (index < 0 || index >= arr->length) | |
| { | |
| _Jv_ThrowBadArrayIndex (index); | |
| } | |
| elements(arr)[index] = value; | |
| } | |
| NEXT_INSN; | |
| insn_dastore: | |
| SAVE_PC; | |
| { | |
| jdouble value = POPD(); | |
| jint index = POPI(); | |
| jdoubleArray arr = (jdoubleArray) POPA(); | |
| NULLCHECK (arr); | |
| if (index < 0 || index >= arr->length) | |
| { | |
| _Jv_ThrowBadArrayIndex (index); | |
| } | |
| elements(arr)[index] = value; | |
| } | |
| NEXT_INSN; | |
| insn_aastore: | |
| SAVE_PC; | |
| { | |
| jobject value = POPA(); | |
| jint index = POPI(); | |
| jobjectArray arr = (jobjectArray) POPA(); | |
| NULLCHECK (arr); | |
| if (index < 0 || index >= arr->length) | |
| { | |
| _Jv_ThrowBadArrayIndex (index); | |
| } | |
| _Jv_CheckArrayStore (arr, value); | |
| elements(arr)[index] = value; | |
| } | |
| NEXT_INSN; | |
| insn_bastore: | |
| SAVE_PC; | |
| { | |
| jbyte value = (jbyte) POPI(); | |
| jint index = POPI(); | |
| jbyteArray arr = (jbyteArray) POPA(); | |
| NULLCHECK (arr); | |
| if (index < 0 || index >= arr->length) | |
| { | |
| _Jv_ThrowBadArrayIndex (index); | |
| } | |
| elements(arr)[index] = value; | |
| } | |
| NEXT_INSN; | |
| insn_castore: | |
| SAVE_PC; | |
| { | |
| jchar value = (jchar) POPI(); | |
| jint index = POPI(); | |
| jcharArray arr = (jcharArray) POPA(); | |
| NULLCHECK (arr); | |
| if (index < 0 || index >= arr->length) | |
| { | |
| _Jv_ThrowBadArrayIndex (index); | |
| } | |
| elements(arr)[index] = value; | |
| } | |
| NEXT_INSN; | |
| insn_sastore: | |
| SAVE_PC; | |
| { | |
| jshort value = (jshort) POPI(); | |
| jint index = POPI(); | |
| jshortArray arr = (jshortArray) POPA(); | |
| NULLCHECK (arr); | |
| if (index < 0 || index >= arr->length) | |
| { | |
| _Jv_ThrowBadArrayIndex (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: | |
| SAVE_PC; | |
| { | |
| jfloat value2 = POPF(); | |
| jfloat value1 = POPF(); | |
| jfloat res = value1 / value2; | |
| PUSHF (res); | |
| } | |
| NEXT_INSN; | |
| insn_ddiv: | |
| SAVE_PC; | |
| { | |
| 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: | |
| SAVE_PC; | |
| { | |
| jfloat value2 = POPF(); | |
| jfloat value1 = POPF(); | |
| jfloat res = __ieee754_fmod (value1, value2); | |
| PUSHF (res); | |
| } | |
| NEXT_INSN; | |
| insn_drem: | |
| SAVE_PC; | |
| { | |
| 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: | |
| { jint value = (jint)POPF (); PUSHI(value); } | |
| NEXT_INSN; | |
| insn_f2l: | |
| { jlong value = (jlong)POPF (); PUSHL(value); } | |
| NEXT_INSN; | |
| insn_f2d: | |
| { jdouble value = POPF (); PUSHD(value); } | |
| NEXT_INSN; | |
| insn_d2i: | |
| { jint value = (jint)POPD (); PUSHI(value); } | |
| NEXT_INSN; | |
| insn_d2l: | |
| { jlong value = (jlong)POPD (); 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: | |
| SAVE_PC; | |
| { | |
| __JArray *arr = (__JArray*)POPA(); | |
| 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 |