// interpret.cc - Code for the interpreter /* Copyright (C) 1999 Cygnus Solutions 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 */ #include #pragma implementation "java-interp.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef INTERPRETER #include /* This should never happen. */ void gnu::gcj::runtime::MethodInvocation::continue1 (gnu::gcj::RawData *, gnu::gcj::RawData *) { JvFail ("no interpreter"); } #else #define ClassError _CL_Q34java4lang5Error extern java::lang::Class ClassError; static const int PUBLIC = 0x001; static const int PRIVATE = 0x002; static const int PROTECTED = 0x004; static const int STATIC = 0x008; static const int FINAL = 0x010; static const int SYNCHRONIZED = 0x020; static const int VOLATILE = 0x040; static const int TRANSIENT = 0x080; static const int NATIVE = 0x100; static const int INTERFACE = 0x200; static const int ABSTRACT = 0x400; static const int ALL_FLAGS = 0x7FF; static _Jv_Utf8Const *init_name = _Jv_makeUtf8Const ("", 6); static void throw_internal_error (char *msg) __attribute__ ((__noreturn__)); static void throw_incompatible_class_change_error (jstring msg) __attribute__ ((__noreturn__)); #if !HANDLE_SEGV static void throw_null_pointer_exception () __attribute__ ((__noreturn__)); #endif #if !HANDLE_FPE static void throw_arithmetic_exception () __attribute__ ((__noreturn__)); #endif 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) #define PUSHL(V) ({ _Jv_word2 w2; w2.l=(V); \ (sp++)->ia[0] = w2.ia[0]; \ (sp++)->ia[0] = w2.ia[1]; }) #define PUSHD(V) ({ _Jv_word2 w2; w2.d=(V); \ (sp++)->ia[0] = w2.ia[0]; \ (sp++)->ia[0] = w2.ia[1]; }) #define POPA() ((--sp)->o) #define POPI() ((jint) (--sp)->i) // cast since it may be promoted #define POPF() ((jfloat) (--sp)->f) #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; }) #define LOADA(I) (sp++)->o = locals[I].o #define LOADI(I) (sp++)->i = locals[I].i #define LOADF(I) (sp++)->f = locals[I].f #define LOADL(I) ({ jint __idx = (I); \ (sp++)->ia[0] = locals[__idx].ia[0]; \ (sp++)->ia[0] = locals[__idx+1].ia[0]; \ }) #define LOADD(I) LOADL(I) #define STOREA(I) locals[I].o = (--sp)->o #define STOREI(I) locals[I].i = (--sp)->i #define STOREF(I) locals[I].f = (--sp)->f #define STOREL(I) ({ jint __idx = (I); \ locals[__idx+1].ia[0] = (--sp)->ia[0]; \ locals[__idx].ia[0] = (--sp)->ia[0]; \ }) #define STORED(I) STOREL(I) #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); } #if HANDLE_SEGV #define NULLCHECK(X) #else #define NULLCHECK(X) \ do { if ((X)==NULL) throw_null_pointer_exception (); } while (0) #endif #if HANDLE_FPE #define ZEROCHECK(X) #else #define ZEROCHECK(X) \ do { if ((X) == 0) throw_arithmetic_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 leat, that's the idea. */ memcpy ((void*) locals, (void*) args, args_raw_size); next_segment: /* this will call the method _Jv_InterpMethod::continue0, see below */ jobject ex = gnu::gcj::runtime::MethodInvocation::continue0 ((gnu::gcj::RawData *)this, (gnu::gcj::RawData *)inv); 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; java::lang::System::out->println (_Jv_NewStringUTF (self->name->data)); 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*) alloca (sizeof (_Jv_InterpMethodInvocation) + storage_size * sizeof (_Jv_word)); jobject ex = _this->run (cif, ret, args, inv); if (ex != 0) _Jv_Throw (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*) 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) _Jv_Throw (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*) 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) _Jv_Throw (ex); } /* this is the exception handler hack, for the interpreter */ void gnu::gcj::runtime::MethodInvocation::continue1 (gnu::gcj::RawData *meth, gnu::gcj::RawData *inv) { _Jv_InterpMethod *meth0 = (_Jv_InterpMethod*)meth; _Jv_InterpMethodInvocation *inv0 = (_Jv_InterpMethodInvocation*)inv; meth0->continue1 (inv0); } /* 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. */ #ifdef __i386__ #define PC_REGISTER_ASM asm("%esi") #else #define PC_REGISTER_ASM #endif void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) { register _Jv_word *sp = inv->sp; register unsigned char *pc PC_REGISTER_ASM = 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), INSN_LABEL(putfield_1), INSN_LABEL(putfield_2), INSN_LABEL(putfield_4), INSN_LABEL(putfield_8), INSN_LABEL(putfield_a), INSN_LABEL(putstatic_1), INSN_LABEL(putstatic_2), INSN_LABEL(putstatic_4), INSN_LABEL(putstatic_8), INSN_LABEL(putstatic_a), INSN_LABEL(getfield_1), INSN_LABEL(getfield_2s), INSN_LABEL(getfield_2u), INSN_LABEL(getfield_4), INSN_LABEL(getfield_8), INSN_LABEL(getfield_a), INSN_LABEL(getstatic_1), INSN_LABEL(getstatic_2s), INSN_LABEL(getstatic_2u), INSN_LABEL(getstatic_4), INSN_LABEL(getstatic_8), INSN_LABEL(getstatic_a), }; #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 GOTO_INSN(*pc++) 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_getfield_4: // 0xd8 SAVE_PC; { jobject obj = POPA(); NULLCHECK(obj); jint field_offset = get2u (pc); pc += 2; PUSHI (*(jint*) ((char*)obj + field_offset)); } NEXT_INSN; insn_iload_1: // 0x1b LOADI (1); NEXT_INSN; insn_getfield_a: // 0xda SAVE_PC; { jobject obj = POPA(); NULLCHECK(obj); jint field_offset = get2u (pc); pc += 2; PUSHA(*(jobject*) ((char*)obj + field_offset)); } 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; NULLCHECK(sp[0]); 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->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; ffi_raw_call (cif, fun, (void*)&rvalue, raw); 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: STOREI (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(); ZEROCHECK (value2); jint res = value1 / value2; PUSHI (res); } NEXT_INSN; insn_ldiv: SAVE_PC; { jlong value2 = POPL(); jlong value1 = POPL(); ZEROCHECK (value2); jlong res = value1 / value2; PUSHL (res); } NEXT_INSN; insn_fdiv: SAVE_PC; { jfloat value2 = POPF(); jfloat value1 = POPF(); ZEROCHECK (value2); jfloat res = value1 / value2; PUSHF (res); } NEXT_INSN; insn_ddiv: SAVE_PC; { jdouble value2 = POPD(); jdouble value1 = POPD(); ZEROCHECK (value2); jdouble res = value1 / value2; PUSHD (res); } NEXT_INSN; insn_irem: SAVE_PC; { jint value2 = POPI(); jint value1 = POPI(); ZEROCHECK (value2); jint res = value1 % value2; PUSHI (res); } NEXT_INSN; insn_lrem: SAVE_PC; { jlong value2 = POPL(); jlong value1 = POPL(); ZEROCHECK (value2); jlong res = value1 % value2; PUSHL (res); } NEXT_INSN; insn_frem: SAVE_PC; { jfloat value2 = POPF(); jfloat value1 = POPF(); ZEROCHECK (value2); jfloat res = __ieee754_fmod (value1, value2); PUSHF (res); } NEXT_INSN; insn_drem: SAVE_PC; { jdouble value2 = POPD(); jdouble value1 = POPD(); ZEROCHECK (value2); 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; { unsigned char *base_pc = pc-1; jint fieldref_index = get2u (pc); pc += 2; _Jv_ResolvePoolEntry (defining_class, fieldref_index); _Jv_Field *field = pool_data[fieldref_index].field; if ((field->flags & 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: *base_pc = op_getstatic_1; break; case 2: if (type == JvPrimClass (char)) *base_pc = op_getstatic_2u; else *base_pc = op_getstatic_2s; break; case 4: *base_pc = op_getstatic_4; break; case 8: *base_pc = op_getstatic_8; break; } } else { *base_pc = op_getstatic_a; } pc = base_pc; } NEXT_INSN; insn_getfield: SAVE_PC; { unsigned char *base_pc = pc-1; jint fieldref_index = get2u (pc); pc += 2; _Jv_ResolvePoolEntry (defining_class, fieldref_index); _Jv_Field *field = pool_data[fieldref_index].field; if ((field->flags & STATIC) != 0) throw_incompatible_class_change_error (JvNewStringLatin1 ("field is static")); jclass type = field->type; if (type->isPrimitive ()) { switch (type->size_in_bytes) { case 1: *base_pc = op_getfield_1; break; case 2: if (type == JvPrimClass (char)) *base_pc = op_getfield_2u; else *base_pc = op_getfield_2s; break; case 4: *base_pc = op_getfield_4; break; case 8: *base_pc = op_getfield_8; break; } } else { *base_pc = op_getfield_a; } if (field->u.boffset > 0xffff) JvThrow (new java::lang::VirtualMachineError); base_pc[1] = (field->u.boffset>>8) & 0xff; base_pc[2] = field->u.boffset & 0xff; pc = base_pc; } NEXT_INSN; insn_putstatic: SAVE_PC; { unsigned char* base_pc = pc-1; 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 & STATIC) == 0) throw_incompatible_class_change_error (JvNewStringLatin1 ("field no longer static")); /* if this is patented, then maybe we could install a function in the constant pool, to do the right thing */ if (type->isPrimitive ()) { switch (type->size_in_bytes) { case 1: *base_pc = op_putstatic_1; break; case 2: *base_pc = op_putstatic_2; break; case 4: *base_pc = op_putstatic_4; break; case 8: *base_pc = op_putstatic_8; break; } } else { *base_pc = op_putstatic_a; } // do the instruction again! pc = base_pc; } NEXT_INSN; insn_putfield: SAVE_PC; { unsigned char* base_pc = pc-1; 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 & STATIC) != 0) throw_incompatible_class_change_error (JvNewStringLatin1 ("field is static")); if (type->isPrimitive ()) { switch (type->size_in_bytes) { case 1: *base_pc = op_putfield_1; break; case 2: *base_pc = op_putfield_2; break; case 4: *base_pc = op_putfield_4; break; case 8: *base_pc = op_putfield_8; break; } } else { *base_pc = op_putfield_a; } if (field->u.boffset > 0xffff) JvThrow (new java::lang::VirtualMachineError); base_pc[1] = (field->u.boffset>>8) & 0xff; base_pc[2] = field->u.boffset & 0xff; // do the instruction again! pc = base_pc; } NEXT_INSN; insn_getfield_1: SAVE_PC; { jobject obj = POPA(); NULLCHECK(obj); jint field_offset = get2u (pc); pc += 2; PUSHI (*(jbyte*) ((char*)obj + field_offset)); } NEXT_INSN; insn_getfield_2s: SAVE_PC; { jobject obj = POPA(); NULLCHECK(obj); jint field_offset = get2u (pc); pc += 2; PUSHI (*(jshort*) ((char*)obj + field_offset)); } NEXT_INSN; insn_getfield_2u: SAVE_PC; { jobject obj = POPA(); NULLCHECK(obj); jint field_offset = get2u (pc); pc += 2; PUSHI (*(jchar*) ((char*)obj + field_offset)); } NEXT_INSN; insn_getfield_8: SAVE_PC; { jobject obj = POPA(); NULLCHECK(obj); jint field_offset = get2u (pc); pc += 2; PUSHL(*(jlong*) ((char*)obj + field_offset)); } NEXT_INSN; insn_getstatic_1: { jint fieldref_index = get2u (pc); pc += 2; _Jv_Field *field = pool_data[fieldref_index].field; PUSHI (*(jbyte*) (field->u.addr)); } NEXT_INSN; insn_getstatic_2s: { jint fieldref_index = get2u (pc); pc += 2; _Jv_Field *field = pool_data[fieldref_index].field; PUSHI(*(jshort*) (field->u.addr)); } NEXT_INSN; insn_getstatic_2u: { jint fieldref_index = get2u (pc); pc += 2; _Jv_Field *field = pool_data[fieldref_index].field; PUSHI(*(jchar*) (field->u.addr)); } NEXT_INSN; insn_getstatic_4: { jint fieldref_index = get2u (pc); pc += 2; _Jv_Field *field = pool_data[fieldref_index].field; PUSHI(*(jint*) (field->u.addr)); } NEXT_INSN; insn_getstatic_8: { jint fieldref_index = get2u (pc); pc += 2; _Jv_Field *field = pool_data[fieldref_index].field; PUSHL(*(jlong*) (field->u.addr)); } NEXT_INSN; insn_getstatic_a: { jint fieldref_index = get2u (pc); pc += 2; _Jv_Field *field = pool_data[fieldref_index].field; PUSHA(*(jobject*) (field->u.addr)); } NEXT_INSN; insn_putfield_1: SAVE_PC; { jint value = POPI(); jobject obj = POPA(); NULLCHECK(obj); jint field_offset = get2u (pc); pc += 2; *(jbyte*) ((char*)obj + field_offset) = value; } NEXT_INSN; insn_putfield_2: SAVE_PC; { jint value = POPI(); jobject obj = POPA(); NULLCHECK(obj); jint field_offset = get2u (pc); pc += 2; *(jchar*) ((char*)obj + field_offset) = value; } NEXT_INSN; insn_putfield_4: SAVE_PC; { jint value = POPI(); jobject obj = POPA(); NULLCHECK(obj); jint field_offset = get2u (pc); pc += 2; *(jint*) ((char*)obj + field_offset) = value; } NEXT_INSN; insn_putfield_8: SAVE_PC; { jlong value = POPL(); jobject obj = POPA(); NULLCHECK(obj); jint field_offset = get2u (pc); pc += 2; *(jlong*) ((char*)obj + field_offset) = value; } NEXT_INSN; insn_putfield_a: SAVE_PC; { jobject value = POPA(); jobject obj = POPA(); NULLCHECK(obj); jint field_offset = get2u (pc); pc += 2; *(jobject*) ((char*)obj + field_offset) = value; } NEXT_INSN; insn_putstatic_1: { jint value = POPI(); jint fieldref_index = get2u (pc); pc += 2; _Jv_Field *field = pool_data[fieldref_index].field; *(jbyte*) (field->u.addr) = value; } NEXT_INSN; insn_putstatic_2: { jint value = POPI(); jint fieldref_index = get2u (pc); pc += 2; _Jv_Field *field = pool_data[fieldref_index].field; *(jchar*) (field->u.addr) = value; } NEXT_INSN; insn_putstatic_4: { jint value = POPI(); jint fieldref_index = get2u (pc); pc += 2; _Jv_Field *field = pool_data[fieldref_index].field; *(jint*) (field->u.addr) = value; } NEXT_INSN; insn_putstatic_8: { jlong value = POPL(); jint fieldref_index = get2u (pc); pc += 2; _Jv_Field *field = pool_data[fieldref_index].field; *(jlong*) (field->u.addr) = value; } NEXT_INSN; insn_putstatic_a: { jobject value = POPA(); jint fieldref_index = get2u (pc); pc += 2; _Jv_Field *field = pool_data[fieldref_index].field; *(jobject*) (field->u.addr) = 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]); 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; NULLCHECK(sp[0]); jobject rcv = sp[0].o; 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(); JvThrow (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)) { JvThrow (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*) 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) { JvThrow (new java::lang::InternalError (JvNewStringLatin1 (msg))); } static void throw_incompatible_class_change_error (jstring msg) { JvThrow (new java::lang::IncompatibleClassChangeError (msg)); } #if !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; JvThrow (null_pointer_exc); } #endif #if !HANDLE_FPE static java::lang::ArithmeticException *arithmetic_exc; static void throw_arithmetic_exception () { if (arithmetic_exc == NULL) arithmetic_exc = new java::lang::ArithmeticException (JvNewStringLatin1 ("/ by zero")); JvThrow (arithmetic_exc); } #endif #endif // INTERPRETER