From fdae83abe7a88e1f08ec25d3f4eb5eb21ec342bf Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Mon, 24 Jun 2002 20:38:47 +0000 Subject: [PATCH] verify.cc (branch_prepass): Updated for change to exception handler type. * verify.cc (branch_prepass): Updated for change to exception handler type. (verify_instructions_0): Likewise. * defineclass.cc (handleCodeAttribute): Initialize `prepared'. (handleExceptionTableEntry): Updated for change to exception handler type. * java/lang/Class.h (Class): Removed _Jv_InterpMethodInvocation. * include/java-interp.h (_Jv_InterpMethodInvocation): Removed. (union _Jv_InterpPC): New. (class _Jv_InterpException): Changed types to _Jv_InterpPC. (class _Jv_InterpMethod): Added new `prepared' field. (class _Jv_InterpMethod): Added `compile' method. Removed `continue1' and `find_exception'. Changed arguments to `run'. * interpret.cc (union insn_slot): New. (find_exception): Removed. (run_normal): Removed most logic. (run_synch_object): Likewise; also, use JvSynchronize. (run_synch_class): Likewise. (run): Removed. (continue1): Renamed as `run'. Compile bytecode if required. Add new code to allow refinement of direct-threaded code at runtime. Handle exceptions. (SAVE_PC): Removed. (compile): New method. (SET_ONE, SET_INSN, SET_INT, SET_DATUM): New defines. (NULLARRAYCHECK): Don't use SAVE_PC. (pc_t): New typedef. (TAKE_GOTO, GET1S, GET1U, GET2U, AVAL1U, AVAL2U, AVAL2UP, SKIP_GOTO, GOTO_VAL, PCVAL, AMPAMP): New macros. From-SVN: r54968 --- libjava/ChangeLog | 32 + libjava/defineclass.cc | 11 +- libjava/include/java-interp.h | 45 +- libjava/interpret.cc | 2112 ++++++++++++++++++++++----------- libjava/java/lang/Class.h | 1 - libjava/verify.cc | 24 +- 6 files changed, 1517 insertions(+), 708 deletions(-) diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 742488b5812..a7c6eb2e0b0 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,35 @@ +2002-06-24 Tom Tromey + + * verify.cc (branch_prepass): Updated for change to exception + handler type. + (verify_instructions_0): Likewise. + * defineclass.cc (handleCodeAttribute): Initialize `prepared'. + (handleExceptionTableEntry): Updated for change to exception + handler type. + * java/lang/Class.h (Class): Removed _Jv_InterpMethodInvocation. + * include/java-interp.h (_Jv_InterpMethodInvocation): Removed. + (union _Jv_InterpPC): New. + (class _Jv_InterpException): Changed types to _Jv_InterpPC. + (class _Jv_InterpMethod): Added new `prepared' field. + (class _Jv_InterpMethod): Added `compile' method. Removed + `continue1' and `find_exception'. Changed arguments to `run'. + * interpret.cc (union insn_slot): New. + (find_exception): Removed. + (run_normal): Removed most logic. + (run_synch_object): Likewise; also, use JvSynchronize. + (run_synch_class): Likewise. + (run): Removed. + (continue1): Renamed as `run'. Compile bytecode if required. + Add new code to allow refinement of direct-threaded code at + runtime. Handle exceptions. + (SAVE_PC): Removed. + (compile): New method. + (SET_ONE, SET_INSN, SET_INT, SET_DATUM): New defines. + (NULLARRAYCHECK): Don't use SAVE_PC. + (pc_t): New typedef. + (TAKE_GOTO, GET1S, GET1U, GET2U, AVAL1U, AVAL2U, AVAL2UP, + SKIP_GOTO, GOTO_VAL, PCVAL, AMPAMP): New macros. + 2002-06-23 Tom Tromey * configure: Rebuilt. diff --git a/libjava/defineclass.cc b/libjava/defineclass.cc index 190af6ac356..95e671f42a3 100644 --- a/libjava/defineclass.cc +++ b/libjava/defineclass.cc @@ -1258,6 +1258,7 @@ void _Jv_ClassReader::handleCodeAttribute method->exc_count = exc_table_length; method->defining_class = def; method->self = &def->methods[method_index]; + method->prepared = NULL; // grab the byte code! memcpy ((void*) method->bytecode (), @@ -1267,7 +1268,7 @@ void _Jv_ClassReader::handleCodeAttribute def->interpreted_methods[method_index] = method; } -void _Jv_ClassReader::handleExceptionTableEntry +void _Jv_ClassReader::handleExceptionTableEntry (int method_index, int exc_index, int start_pc, int end_pc, int handler_pc, int catch_type) { @@ -1275,10 +1276,10 @@ void _Jv_ClassReader::handleExceptionTableEntry (def->interpreted_methods[method_index]); _Jv_InterpException *exc = method->exceptions (); - exc[exc_index].start_pc = start_pc; - exc[exc_index].end_pc = end_pc; - exc[exc_index].handler_pc = handler_pc; - exc[exc_index].handler_type = catch_type; + exc[exc_index].start_pc.i = start_pc; + exc[exc_index].end_pc.i = end_pc; + exc[exc_index].handler_pc.i = handler_pc; + exc[exc_index].handler_type.i = catch_type; } void _Jv_ClassReader::handleMethodsEnd () diff --git a/libjava/include/java-interp.h b/libjava/include/java-interp.h index bc1f3ca1cf4..de1d88f452e 100644 --- a/libjava/include/java-interp.h +++ b/libjava/include/java-interp.h @@ -1,6 +1,6 @@ // java-interp.h - Header file for the bytecode interpreter. -*- c++ -*- -/* Copyright (C) 1999, 2000, 2001 Free Software Foundation +/* Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation This file is part of libgcj. @@ -49,14 +49,22 @@ void _Jv_VerifyMethod (_Jv_InterpMethod *method); class _Jv_InterpClass; class _Jv_InterpMethod; -class _Jv_InterpMethodInvocation; + +// Before a method is "compiled" we store values as the bytecode PC, +// an int. Afterwards we store them as pointers into the prepared +// code itself. +union _Jv_InterpPC +{ + int i; + void *p; +}; class _Jv_InterpException { - int start_pc; - int end_pc; - int handler_pc; - int handler_type; + _Jv_InterpPC start_pc; + _Jv_InterpPC end_pc; + _Jv_InterpPC handler_pc; + _Jv_InterpPC handler_type; friend class _Jv_ClassReader; friend class _Jv_InterpMethod; @@ -92,6 +100,8 @@ class _Jv_InterpMethod : public _Jv_MethodBase _Jv_ushort exc_count; + void *prepared; + unsigned char* bytecode () { return @@ -99,7 +109,7 @@ class _Jv_InterpMethod : public _Jv_MethodBase + ROUND((sizeof (_Jv_InterpMethod) + exc_count*sizeof (_Jv_InterpException)), 4); } - + _Jv_InterpException * exceptions () { return (_Jv_InterpException*) (this+1); @@ -115,40 +125,23 @@ class _Jv_InterpMethod : public _Jv_MethodBase // return the method's invocation pointer (a stub). void *ncode (); - void continue1 (_Jv_InterpMethodInvocation *inv); + void compile (const void * const *); static void run_normal (ffi_cif*, void*, ffi_raw*, void*); static void run_synch_object (ffi_cif*, void*, ffi_raw*, void*); static void run_synch_class (ffi_cif*, void*, ffi_raw*, void*); - inline jobject run (ffi_cif*, void*, ffi_raw*, - _Jv_InterpMethodInvocation*); - - bool find_exception (jobject ex, - _Jv_InterpMethodInvocation *inv); + void run (void*, ffi_raw *); public: static void dump_object(jobject o); friend class _Jv_ClassReader; - friend class _Jv_InterpMethodInvocation; friend class _Jv_BytecodeVerifier; friend void _Jv_PrepareClass(jclass); }; -class _Jv_InterpMethodInvocation { - _Jv_InterpMethod *running; - _Jv_word *sp; - unsigned char *pc; - _Jv_word state[0]; - - _Jv_word* stack_base () { return &state[0]; } - _Jv_word* local_base () { return &state[running->max_stack]; } - - friend class _Jv_InterpMethod; -}; - class _Jv_InterpClass : public java::lang::Class { _Jv_MethodBase **interpreted_methods; diff --git a/libjava/interpret.cc b/libjava/interpret.cc index 4db9dca08ec..e5c40cff150 100644 --- a/libjava/interpret.cc +++ b/libjava/interpret.cc @@ -1,6 +1,6 @@ // interpret.cc - Code for the interpreter -/* Copyright (C) 1999, 2000, 2001 , 2002 Free Software Foundation +/* Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation This file is part of libgcj. @@ -12,6 +12,11 @@ details. */ #include +// Define this to get the direct-threaded interpreter. If undefined, +// we revert to a basic bytecode interpreter. The former is faster +// but uses more memory. +#define DIRECT_THREADED + #pragma implementation "java-interp.h" #include @@ -51,6 +56,26 @@ static void throw_null_pointer_exception () extern "C" double __ieee754_fmod (double,double); +// This represents a single slot in the "compiled" form of the +// bytecode. +union insn_slot +{ + // Address of code. + void *insn; + // An integer value used by an instruction. + jint int_val; + // A pointer value used by an instruction. + void *datum; +}; + +// The type of the PC depends on whether we're doing direct threading +// or a more ordinary bytecode interpreter. +#ifdef DIRECT_THREADED +typedef insn_slot *pc_t; +#else +typedef unsigned char *pc_t; +#endif + static inline void dupx (_Jv_word *sp, int n, int x) { // first "slide" n+x elements n to the right @@ -199,12 +224,12 @@ static jint get4(unsigned char* loc) { #ifdef HANDLE_SEGV #define NULLCHECK(X) -#define NULLARRAYCHECK(X) do { SAVE_PC; } while (0) +#define NULLARRAYCHECK(X) #else #define NULLCHECK(X) \ do { if ((X)==NULL) throw_null_pointer_exception (); } while (0) #define NULLARRAYCHECK(X) \ - do { if ((X)==NULL) { SAVE_PC; throw_null_pointer_exception (); } } while (0) + do { if ((X)==NULL) { throw_null_pointer_exception (); } } while (0) #endif #define ARRAYBOUNDSCHECK(array, index) \ @@ -215,230 +240,534 @@ static jint get4(unsigned char* loc) { } \ while (0) -// this method starts the actual running of the method. It is inlined -// in three different variants in the static methods run_normal, -// run_sync_object and run_sync_class (see below). Those static methods -// are installed directly in the stub for this method (by -// _Jv_InterpMethod::ncode, in resolve.cc). - -inline jobject -_Jv_InterpMethod::run (ffi_cif* cif, - void *retp, - ffi_raw *args, - _Jv_InterpMethodInvocation *inv) +void _Jv_InterpMethod::run_normal (ffi_cif *, + void* ret, + ffi_raw * args, + void* __this) { - inv->running = this; - inv->pc = bytecode (); - inv->sp = inv->stack_base (); - _Jv_word *locals = inv->local_base (); + _Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this; + _this->run (ret, args); +} + +void _Jv_InterpMethod::run_synch_object (ffi_cif *, + void* ret, + ffi_raw * args, + void* __this) +{ + _Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this; + + jobject rcv = (jobject) args[0].ptr; + JvSynchronize mutex (rcv); + + _this->run (ret, args); +} + +void _Jv_InterpMethod::run_synch_class (ffi_cif *, + void* ret, + ffi_raw * args, + void* __this) +{ + _Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this; + + jclass sync = _this->defining_class; + JvSynchronize mutex (sync); + + _this->run (ret, args); +} + +#ifdef DIRECT_THREADED +// "Compile" a method by turning it from bytecode to direct-threaded +// code. +void +_Jv_InterpMethod::compile (const void * const *insn_targets) +{ + insn_slot *insns = NULL; + int next = 0; + unsigned char *codestart = bytecode (); + unsigned char *end = codestart + code_length; + _Jv_word *pool_data = defining_class->constants.data; + +#define SET_ONE(Field, Value) \ + do \ + { \ + if (first_pass) \ + ++next; \ + else \ + insns[next++].Field = Value; \ + } \ + while (0) + +#define SET_INSN(Value) SET_ONE (insn, (void *) Value) +#define SET_INT(Value) SET_ONE (int_val, Value) +#define SET_DATUM(Value) SET_ONE (datum, Value) + + // Map from bytecode PC to slot in INSNS. + int *pc_mapping = (int *) __builtin_alloca (sizeof (int) * code_length); + for (int i = 0; i < code_length; ++i) + pc_mapping[i] = -1; + + for (int i = 0; i < 2; ++i) + { + jboolean first_pass = i == 0; + + if (! first_pass) + { + insns = (insn_slot *) _Jv_Malloc (sizeof (insn_slot) * next); + next = 0; + } + + unsigned char *pc = codestart; + while (pc < end) + { + int base_pc_val = pc - codestart; + if (first_pass) + pc_mapping[base_pc_val] = next; + + java_opcode opcode = (java_opcode) *pc++; + // Just elide NOPs. + if (opcode == op_nop) + continue; + SET_INSN (insn_targets[opcode]); + + switch (opcode) + { + case op_nop: + case op_aconst_null: + case op_iconst_m1: + case op_iconst_0: + case op_iconst_1: + case op_iconst_2: + case op_iconst_3: + case op_iconst_4: + case op_iconst_5: + case op_lconst_0: + case op_lconst_1: + case op_fconst_0: + case op_fconst_1: + case op_fconst_2: + case op_dconst_0: + case op_dconst_1: + case op_iload_0: + case op_iload_1: + case op_iload_2: + case op_iload_3: + case op_lload_0: + case op_lload_1: + case op_lload_2: + case op_lload_3: + case op_fload_0: + case op_fload_1: + case op_fload_2: + case op_fload_3: + case op_dload_0: + case op_dload_1: + case op_dload_2: + case op_dload_3: + case op_aload_0: + case op_aload_1: + case op_aload_2: + case op_aload_3: + case op_iaload: + case op_laload: + case op_faload: + case op_daload: + case op_aaload: + case op_baload: + case op_caload: + case op_saload: + case op_istore_0: + case op_istore_1: + case op_istore_2: + case op_istore_3: + case op_lstore_0: + case op_lstore_1: + case op_lstore_2: + case op_lstore_3: + case op_fstore_0: + case op_fstore_1: + case op_fstore_2: + case op_fstore_3: + case op_dstore_0: + case op_dstore_1: + case op_dstore_2: + case op_dstore_3: + case op_astore_0: + case op_astore_1: + case op_astore_2: + case op_astore_3: + case op_iastore: + case op_lastore: + case op_fastore: + case op_dastore: + case op_aastore: + case op_bastore: + case op_castore: + case op_sastore: + case op_pop: + case op_pop2: + case op_dup: + case op_dup_x1: + case op_dup_x2: + case op_dup2: + case op_dup2_x1: + case op_dup2_x2: + case op_swap: + case op_iadd: + case op_isub: + case op_imul: + case op_idiv: + case op_irem: + case op_ishl: + case op_ishr: + case op_iushr: + case op_iand: + case op_ior: + case op_ixor: + case op_ladd: + case op_lsub: + case op_lmul: + case op_ldiv: + case op_lrem: + case op_lshl: + case op_lshr: + case op_lushr: + case op_land: + case op_lor: + case op_lxor: + case op_fadd: + case op_fsub: + case op_fmul: + case op_fdiv: + case op_frem: + case op_dadd: + case op_dsub: + case op_dmul: + case op_ddiv: + case op_drem: + case op_ineg: + case op_i2b: + case op_i2c: + case op_i2s: + case op_lneg: + case op_fneg: + case op_dneg: + case op_i2l: + case op_i2f: + case op_i2d: + case op_l2i: + case op_l2f: + case op_l2d: + case op_f2i: + case op_f2l: + case op_f2d: + case op_d2i: + case op_d2l: + case op_d2f: + case op_lcmp: + case op_fcmpl: + case op_fcmpg: + case op_dcmpl: + case op_dcmpg: + case op_monitorenter: + case op_monitorexit: + case op_ireturn: + case op_lreturn: + case op_freturn: + case op_dreturn: + case op_areturn: + case op_return: + case op_athrow: + case op_arraylength: + // No argument, nothing else to do. + break; + + case op_bipush: + SET_INT (get1s (pc)); + ++pc; + break; + + case op_ldc: + { + int index = get1u (pc); + ++pc; + SET_DATUM (pool_data[index].o); + } + break; + + case op_ret: + case op_iload: + case op_lload: + case op_fload: + case op_dload: + case op_aload: + case op_istore: + case op_lstore: + case op_fstore: + case op_dstore: + case op_astore: + case op_newarray: + SET_INT (get1u (pc)); + ++pc; + break; + + case op_iinc: + SET_INT (get1u (pc)); + SET_INT (get1s (pc + 1)); + pc += 2; + break; + + case op_ldc_w: + { + int index = get2u (pc); + pc += 2; + SET_DATUM (pool_data[index].o); + } + break; + + case op_ldc2_w: + { + int index = get2u (pc); + pc += 2; + SET_DATUM (&pool_data[index]); + } + break; + + case op_sipush: + SET_INT (get2s (pc)); + pc += 2; + break; + + case op_new: + case op_getstatic: + case op_getfield: + case op_putfield: + case op_putstatic: + case op_anewarray: + case op_instanceof: + case op_checkcast: + case op_invokespecial: + case op_invokestatic: + case op_invokevirtual: + SET_INT (get2u (pc)); + pc += 2; + break; + + case op_multianewarray: + SET_INT (get2u (pc)); + SET_INT (get1u (pc + 2)); + pc += 3; + break; + + case op_jsr: + case op_ifeq: + case op_ifne: + case op_iflt: + case op_ifge: + case op_ifgt: + case op_ifle: + case op_if_icmpeq: + case op_if_icmpne: + case op_if_icmplt: + case op_if_icmpge: + case op_if_icmpgt: + case op_if_icmple: + case op_if_acmpeq: + case op_if_acmpne: + case op_ifnull: + case op_ifnonnull: + case op_goto: + { + int offset = get2s (pc); + pc += 2; + + int new_pc = base_pc_val + offset; + + bool orig_was_goto = opcode == op_goto; + + // Thread jumps. We limit the loop count; this lets + // us avoid infinite loops if the bytecode contains + // such. `10' is arbitrary. + int count = 10; + while (codestart[new_pc] == op_goto && count-- > 0) + new_pc += get2s (&codestart[new_pc + 1]); + + // If the jump takes us to a `return' instruction and + // the original branch was an unconditional goto, then + // we hoist the return. + opcode = (java_opcode) codestart[new_pc]; + if (orig_was_goto + && (opcode == op_ireturn || opcode == op_lreturn + || opcode == op_freturn || opcode == op_dreturn + || opcode == op_areturn || opcode == op_return)) + { + --next; + SET_INSN (insn_targets[opcode]); + } + else + SET_DATUM (&insns[pc_mapping[new_pc]]); + } + break; + + case op_tableswitch: + { + while ((pc - codestart) % 4 != 0) + ++pc; + + jint def = get4 (pc); + SET_DATUM (&insns[pc_mapping[base_pc_val + def]]); + pc += 4; + + int low = get4 (pc); + SET_INT (low); + pc += 4; + int high = get4 (pc); + SET_INT (high); + pc += 4; + + for (int i = low; i <= high; ++i) + { + SET_DATUM (&insns[pc_mapping[base_pc_val + get4 (pc)]]); + pc += 4; + } + } + break; + + case op_lookupswitch: + { + while ((pc - codestart) % 4 != 0) + ++pc; + + jint def = get4 (pc); + SET_DATUM (&insns[pc_mapping[base_pc_val + def]]); + pc += 4; + + jint npairs = get4 (pc); + pc += 4; + SET_INT (npairs); + + while (npairs-- > 0) + { + jint match = get4 (pc); + jint offset = get4 (pc + 4); + SET_INT (match); + SET_DATUM (&insns[pc_mapping[base_pc_val + offset]]); + pc += 8; + } + } + break; + + case op_invokeinterface: + { + jint index = get2u (pc); + pc += 2; + // We ignore the next two bytes. + pc += 2; + SET_INT (index); + } + break; + + case op_wide: + { + opcode = (java_opcode) get1u (pc); + pc += 1; + jint val = get2u (pc); + pc += 2; + + // We implement narrow and wide instructions using the + // same code in the interpreter. So we rewrite the + // instruction slot here. + if (! first_pass) + insns[next - 1].insn = (void *) insn_targets[opcode]; + SET_INT (val); + + if (opcode == op_iinc) + { + SET_INT (get2s (pc)); + pc += 2; + } + } + break; + + case op_jsr_w: + case op_goto_w: + { + jint offset = get4 (pc); + pc += 4; + SET_DATUM (&insns[pc_mapping[base_pc_val + offset]]); + } + break; + + // Some "can't happen" cases that we include for + // error-checking purposes. + case op_putfield_1: + case op_putfield_2: + case op_putfield_4: + case op_putfield_8: + case op_putfield_a: + case op_putstatic_1: + case op_putstatic_2: + case op_putstatic_4: + case op_putstatic_8: + case op_putstatic_a: + case op_getfield_1: + case op_getfield_2s: + case op_getfield_2u: + case op_getfield_4: + case op_getfield_8: + case op_getfield_a: + case op_getstatic_1: + case op_getstatic_2s: + case op_getstatic_2u: + case op_getstatic_4: + case op_getstatic_8: + case op_getstatic_a: + default: + // Fail somehow. + break; + } + } + } + + // Now update exceptions. + _Jv_InterpException *exc = exceptions (); + for (int i = 0; i < exc_count; ++i) + { + exc[i].start_pc.p = &insns[pc_mapping[exc[i].start_pc.i]]; + exc[i].end_pc.p = &insns[pc_mapping[exc[i].end_pc.i]]; + exc[i].handler_pc.p = &insns[pc_mapping[exc[i].handler_pc.i]]; + jclass handler = (_Jv_ResolvePoolEntry (defining_class, + exc[i].handler_type.i)).clazz; + exc[i].handler_type.p = handler; + } + + prepared = insns; +} +#endif /* DIRECT_THREADED */ + +void +_Jv_InterpMethod::run (void *retp, ffi_raw *args) +{ + using namespace java::lang::reflect; + + _Jv_word stack[max_stack]; + _Jv_word *sp = stack; + + _Jv_word locals[max_locals]; /* 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: + _Jv_word *pool_data = defining_class->constants.data; - jobject ex = NULL; - - try - { - continue1 (inv); - } - catch (java::lang::Throwable *ex2) - { - ex = ex2; - } - - if (ex == 0) // no exception... - { - /* define sp locally, so the POP? macros will pick it up */ - _Jv_word *sp = inv->sp; - int rtype = cif->rtype->type; - - if (rtype == FFI_TYPE_POINTER) - { - jobject r = POPA(); - *(jobject*) retp = r; - return 0; - } - else if (rtype == FFI_TYPE_SINT32) - { - jint r = POPI(); - *(jint*)retp = r; - return 0; - } - else if (rtype == FFI_TYPE_VOID) - { - return 0; - } - else switch (rtype) - { - case FFI_TYPE_FLOAT: - { - jfloat r = POPF(); - *(jfloat*)retp = r; - return 0; - } - - case FFI_TYPE_DOUBLE: - { - jdouble r = POPD(); - *(jdouble*)retp = r; - return 0; - } - - case FFI_TYPE_UINT8: - case FFI_TYPE_UINT16: - case FFI_TYPE_UINT32: - case FFI_TYPE_SINT8: - case FFI_TYPE_SINT16: - { - jint r = POPI(); - *(jint*)retp = r; - return 0; - } - - case FFI_TYPE_SINT64: - { - jlong r = POPL(); - *(jlong*)retp = r; - return 0; - } - - default: - throw_internal_error ("unknown return type"); - } - } - - /** handle an exception */ - if ( find_exception (ex, inv) ) - goto next_segment; - - return ex; -} - -#define SAVE_PC inv->pc = pc - -bool _Jv_InterpMethod::find_exception (jobject ex, - _Jv_InterpMethodInvocation *inv) -{ - // We subtract one because the PC was incremented before it was - // saved. - int logical_pc = inv->pc - 1 - bytecode (); - _Jv_InterpException *exc = exceptions (); - jclass exc_class = ex->getClass (); - - for (int i = 0; i < exc_count; i++) - { - if (exc[i].start_pc <= logical_pc && logical_pc < exc[i].end_pc) - { - jclass handler; - - if (exc[i].handler_type != 0) - handler = (_Jv_ResolvePoolEntry (defining_class, - exc[i].handler_type)).clazz; - else - handler = NULL; - - if (handler==NULL || handler->isAssignableFrom (exc_class)) - { - inv->pc = bytecode () + exc[i].handler_pc; - inv->sp = inv->stack_base (); // reset stack - (inv->sp++)->o = ex; // push exception - return true; - } - } - } - return false; -} - -void _Jv_InterpMethod::run_normal (ffi_cif* cif, - void* ret, - ffi_raw * args, - void* __this) -{ - _Jv_InterpMethod* _this = (_Jv_InterpMethod*)__this; - - // we do the alloca of the method invocation here, to allow the method - // "run" ro be inlined. Otherwise gcc will ignore the inline directive. - int storage_size = _this->max_stack+_this->max_locals; - _Jv_InterpMethodInvocation* inv = (_Jv_InterpMethodInvocation*) - __builtin_alloca (sizeof (_Jv_InterpMethodInvocation) - + storage_size * sizeof (_Jv_word)); - - jobject ex = _this->run (cif, ret, args, inv); - if (ex != 0) throw static_cast(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(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(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 */ + /* These three are temporaries for common code used by several + instructions. */ void (*fun)(); _Jv_ResolvedMethod* rmeth; + int tmpval; #define INSN_LABEL(op) &&insn_##op -#define GOTO_INSN(op) goto *(insn_target[op]) static const void *const insn_target[] = { @@ -638,62 +967,92 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) INSN_LABEL(instanceof), INSN_LABEL(monitorenter), INSN_LABEL(monitorexit), +#ifdef DIRECT_THREADED + 0, // wide +#else INSN_LABEL(wide), +#endif INSN_LABEL(multianewarray), INSN_LABEL(ifnull), INSN_LABEL(ifnonnull), INSN_LABEL(goto_w), INSN_LABEL(jsr_w), + 0 }; - /* 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. + pc_t pc; - 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. */ +#ifdef DIRECT_THREADED -#define INLINE_SWITCH +#define NEXT_INSN goto *((pc++)->insn) +#define INTVAL() ((pc++)->int_val) +#define AVAL() ((pc++)->datum) -#ifdef INLINE_SWITCH +#define GET1S() INTVAL () +#define GET2S() INTVAL () +#define GET1U() INTVAL () +#define GET2U() INTVAL () +#define AVAL1U() AVAL () +#define AVAL2U() AVAL () +#define AVAL2UP() AVAL () +#define SKIP_GOTO ++pc +#define GOTO_VAL() (insn_slot *) pc->datum +#define PCVAL(unionval) unionval.p +#define AMPAMP(label) &&label -#define NEXT_INSN do { GOTO_INSN(*pc++); } while (0) + // Compile if we must. + if (prepared == NULL) + compile (insn_target); + pc = (insn_slot *) prepared; - - NEXT_INSN; #else -#define NEXT_INSN goto next_insn +#define NEXT_INSN goto *(insn_target[*pc++]) - next_insn: - GOTO_INSN (*pc++); +#define GET1S() get1s (pc++) +#define GET2S() (pc += 2, get2s (pc- 2)) +#define GET1U() get1u (pc++) +#define GET2U() (pc += 2, get2u (pc - 2)) +#define AVAL1U() ({ int index = get1u (pc++); pool_data[index].o; }) +#define AVAL2U() ({ int index = get2u (pc); pc += 2; pool_data[index].o; }) +#define AVAL2UP() ({ int index = get2u (pc); pc += 2; &pool_data[index]; }) +#define SKIP_GOTO pc += 2 +#define GOTO_VAL() pc - 1 + get2s (pc) +#define PCVAL(unionval) unionval.i +#define AMPAMP(label) NULL -#endif + pc = bytecode (); - /* The first few instructions here are ordered according to their - frequency, in the hope that this will improve code locality a - little. */ +#endif /* DIRECT_THREADED */ - insn_aload_0: // 0x2a - LOADA(0); +#define TAKE_GOTO pc = GOTO_VAL () + + try + { + // We keep nop around. It is used if we're interpreting the + // bytecodes and not doing direct threading. + insn_nop: NEXT_INSN; - insn_iload: // 0x15 - LOADI (get1u (pc++)); + /* 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_1: // 0x1b + insn_iload: // 0x15 + LOADI (GET1U ()); + NEXT_INSN; + + insn_iload_1: // 0x1b LOADI (1); NEXT_INSN; - insn_invokevirtual: // 0xb6 - SAVE_PC; + insn_invokevirtual: // 0xb6 { - int index = get2u (pc); pc += 2; + int index = GET2U (); /* _Jv_ResolvePoolEntry returns immediately if the value already * is resolved. If we want to clutter up the code here to gain @@ -719,13 +1078,47 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) else { jobject rcv = sp[0].o; - _Jv_VTable *table = *(_Jv_VTable**)rcv; - fun = (void (*)()) table->get_method(rmeth->vtable_index); + _Jv_VTable *table = *(_Jv_VTable**) rcv; + fun = (void (*)()) table->get_method (rmeth->vtable_index); } + +#ifdef DIRECT_THREADED + // Rewrite instruction so that we use a faster pre-resolved + // method. + pc[-2].insn = &&invokevirtual_resolved; + pc[-1].datum = rmeth; +#endif /* DIRECT_THREADED */ } goto perform_invoke; - perform_invoke: +#ifdef DIRECT_THREADED + invokevirtual_resolved: + { + rmeth = (_Jv_ResolvedMethod *) AVAL (); + 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; +#endif /* DIRECT_THREADED */ + + perform_invoke: { /* here goes the magic again... */ ffi_cif *cif = &rmeth->cif; @@ -757,231 +1150,227 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) { /* skip */ } - else switch (rtype) + else { - case FFI_TYPE_SINT8: - { - jbyte value = (*(jint*)&rvalue) & 0xff; - PUSHI (value); - } - break; + 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_SINT16: + { + jshort value = (*(jint*)&rvalue) & 0xffff; + PUSHI (value); + } + break; - case FFI_TYPE_UINT16: - { - jint 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_FLOAT: + PUSHF (*(jfloat*)&rvalue); + break; - case FFI_TYPE_DOUBLE: - PUSHD (rvalue); - break; + case FFI_TYPE_DOUBLE: + PUSHD (rvalue); + break; - case FFI_TYPE_SINT64: - PUSHL (*(jlong*)&rvalue); - break; + case FFI_TYPE_SINT64: + PUSHL (*(jlong*)&rvalue); + break; - default: - throw_internal_error ("unknown return type in invokeXXX"); + default: + throw_internal_error ("unknown return type in invokeXXX"); + } } - } NEXT_INSN; - - insn_nop: - NEXT_INSN; - - insn_aconst_null: + insn_aconst_null: PUSHA (NULL); NEXT_INSN; - insn_iconst_m1: + insn_iconst_m1: PUSHI (-1); NEXT_INSN; - insn_iconst_0: + insn_iconst_0: PUSHI (0); NEXT_INSN; - insn_iconst_1: + insn_iconst_1: PUSHI (1); NEXT_INSN; - insn_iconst_2: + insn_iconst_2: PUSHI (2); NEXT_INSN; - insn_iconst_3: + insn_iconst_3: PUSHI (3); NEXT_INSN; - insn_iconst_4: + insn_iconst_4: PUSHI (4); NEXT_INSN; - insn_iconst_5: + insn_iconst_5: PUSHI (5); NEXT_INSN; - insn_lconst_0: + insn_lconst_0: PUSHL (0); NEXT_INSN; - insn_lconst_1: + insn_lconst_1: PUSHL (1); NEXT_INSN; - insn_fconst_0: + insn_fconst_0: PUSHF (0); NEXT_INSN; - insn_fconst_1: + insn_fconst_1: PUSHF (1); NEXT_INSN; - insn_fconst_2: + insn_fconst_2: PUSHF (2); NEXT_INSN; - insn_dconst_0: + insn_dconst_0: PUSHD (0); NEXT_INSN; - insn_dconst_1: + insn_dconst_1: PUSHD (1); NEXT_INSN; - insn_bipush: - PUSHI (get1s(pc++)); + insn_bipush: + // For direct threaded, bipush and sipush are the same. +#ifndef DIRECT_THREADED + PUSHI (GET1S ()); + NEXT_INSN; +#endif /* DIRECT_THREADED */ + insn_sipush: + PUSHI (GET2S ()); NEXT_INSN; - insn_sipush: - PUSHI (get2s(pc)); pc += 2; + insn_ldc: + // For direct threaded, ldc and ldc_w are the same. +#ifndef DIRECT_THREADED + PUSHA ((jobject) AVAL1U ()); + NEXT_INSN; +#endif /* DIRECT_THREADED */ + insn_ldc_w: + PUSHA ((jobject) AVAL2U ()); NEXT_INSN; - insn_ldc: + insn_ldc2_w: { - 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)); + void *where = AVAL2UP (); + memcpy (sp, where, 2*sizeof (_Jv_word)); sp += 2; } NEXT_INSN; - insn_lload: - LOADL (get1u (pc++)); + insn_lload: + LOADL (GET1U ()); NEXT_INSN; - insn_fload: - LOADF (get1u (pc++)); + insn_fload: + LOADF (GET1U ()); NEXT_INSN; - insn_dload: - LOADD (get1u (pc++)); + insn_dload: + LOADD (GET1U ()); NEXT_INSN; - insn_aload: - LOADA (get1u (pc++)); + insn_aload: + LOADA (GET1U ()); NEXT_INSN; - insn_iload_0: + insn_iload_0: LOADI (0); NEXT_INSN; - insn_iload_2: + insn_iload_2: LOADI (2); NEXT_INSN; - insn_iload_3: + insn_iload_3: LOADI (3); NEXT_INSN; - insn_lload_0: + insn_lload_0: LOADL (0); NEXT_INSN; - insn_lload_1: + insn_lload_1: LOADL (1); NEXT_INSN; - insn_lload_2: + insn_lload_2: LOADL (2); NEXT_INSN; - insn_lload_3: + insn_lload_3: LOADL (3); NEXT_INSN; - insn_fload_0: + insn_fload_0: LOADF (0); NEXT_INSN; - insn_fload_1: + insn_fload_1: LOADF (1); NEXT_INSN; - insn_fload_2: + insn_fload_2: LOADF (2); NEXT_INSN; - insn_fload_3: + insn_fload_3: LOADF (3); NEXT_INSN; - insn_dload_0: + insn_dload_0: LOADD (0); NEXT_INSN; - insn_dload_1: + insn_dload_1: LOADD (1); NEXT_INSN; - insn_dload_2: + insn_dload_2: LOADD (2); NEXT_INSN; - insn_dload_3: + insn_dload_3: LOADD (3); NEXT_INSN; - insn_aload_1: + insn_aload_1: LOADA(1); NEXT_INSN; - insn_aload_2: + insn_aload_2: LOADA(2); NEXT_INSN; - insn_aload_3: + insn_aload_3: LOADA(3); NEXT_INSN; - insn_iaload: + insn_iaload: { jint index = POPI(); jintArray arr = (jintArray) POPA(); @@ -991,7 +1380,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_laload: + insn_laload: { jint index = POPI(); jlongArray arr = (jlongArray) POPA(); @@ -1001,7 +1390,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_faload: + insn_faload: { jint index = POPI(); jfloatArray arr = (jfloatArray) POPA(); @@ -1011,7 +1400,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_daload: + insn_daload: { jint index = POPI(); jdoubleArray arr = (jdoubleArray) POPA(); @@ -1021,7 +1410,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_aaload: + insn_aaload: { jint index = POPI(); jobjectArray arr = (jobjectArray) POPA(); @@ -1031,7 +1420,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_baload: + insn_baload: { jint index = POPI(); jbyteArray arr = (jbyteArray) POPA(); @@ -1041,7 +1430,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_caload: + insn_caload: { jint index = POPI(); jcharArray arr = (jcharArray) POPA(); @@ -1051,7 +1440,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_saload: + insn_saload: { jint index = POPI(); jshortArray arr = (jshortArray) POPA(); @@ -1061,107 +1450,107 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_istore: - STOREI (get1u (pc++)); + insn_istore: + STOREI (GET1U ()); NEXT_INSN; - insn_lstore: - STOREL (get1u (pc++)); + insn_lstore: + STOREL (GET1U ()); NEXT_INSN; - insn_fstore: - STOREF (get1u (pc++)); + insn_fstore: + STOREF (GET1U ()); NEXT_INSN; - insn_dstore: - STORED (get1u (pc++)); + insn_dstore: + STORED (GET1U ()); NEXT_INSN; - insn_astore: - STOREA (get1u (pc++)); + insn_astore: + STOREA (GET1U ()); NEXT_INSN; - insn_istore_0: + insn_istore_0: STOREI (0); NEXT_INSN; - insn_istore_1: + insn_istore_1: STOREI (1); NEXT_INSN; - insn_istore_2: + insn_istore_2: STOREI (2); NEXT_INSN; - insn_istore_3: + insn_istore_3: STOREI (3); NEXT_INSN; - insn_lstore_0: + insn_lstore_0: STOREL (0); NEXT_INSN; - insn_lstore_1: + insn_lstore_1: STOREL (1); NEXT_INSN; - insn_lstore_2: + insn_lstore_2: STOREL (2); NEXT_INSN; - insn_lstore_3: + insn_lstore_3: STOREL (3); NEXT_INSN; - insn_fstore_0: + insn_fstore_0: STOREF (0); NEXT_INSN; - insn_fstore_1: + insn_fstore_1: STOREF (1); NEXT_INSN; - insn_fstore_2: + insn_fstore_2: STOREF (2); NEXT_INSN; - insn_fstore_3: + insn_fstore_3: STOREF (3); NEXT_INSN; - insn_dstore_0: + insn_dstore_0: STORED (0); NEXT_INSN; - insn_dstore_1: + insn_dstore_1: STORED (1); NEXT_INSN; - insn_dstore_2: + insn_dstore_2: STORED (2); NEXT_INSN; - insn_dstore_3: + insn_dstore_3: STORED (3); NEXT_INSN; - insn_astore_0: + insn_astore_0: STOREA(0); NEXT_INSN; - insn_astore_1: + insn_astore_1: STOREA(1); NEXT_INSN; - insn_astore_2: + insn_astore_2: STOREA(2); NEXT_INSN; - insn_astore_3: + insn_astore_3: STOREA(3); NEXT_INSN; - insn_iastore: + insn_iastore: { jint value = POPI(); jint index = POPI(); @@ -1172,7 +1561,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_lastore: + insn_lastore: { jlong value = POPL(); jint index = POPI(); @@ -1183,7 +1572,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_fastore: + insn_fastore: { jfloat value = POPF(); jint index = POPI(); @@ -1194,7 +1583,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_dastore: + insn_dastore: { jdouble value = POPD(); jint index = POPI(); @@ -1205,7 +1594,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_aastore: + insn_aastore: { jobject value = POPA(); jint index = POPI(); @@ -1217,7 +1606,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_bastore: + insn_bastore: { jbyte value = (jbyte) POPI(); jint index = POPI(); @@ -1228,7 +1617,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_castore: + insn_castore: { jchar value = (jchar) POPI(); jint index = POPI(); @@ -1239,7 +1628,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_sastore: + insn_sastore: { jshort value = (jshort) POPI(); jint index = POPI(); @@ -1250,42 +1639,42 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_pop: + insn_pop: sp -= 1; NEXT_INSN; - insn_pop2: + insn_pop2: sp -= 2; NEXT_INSN; - insn_dup: + insn_dup: sp[0] = sp[-1]; sp += 1; NEXT_INSN; - insn_dup_x1: + insn_dup_x1: dupx (sp, 1, 1); sp+=1; NEXT_INSN; - insn_dup_x2: + insn_dup_x2: dupx (sp, 1, 2); sp+=1; NEXT_INSN; - insn_dup2: + insn_dup2: sp[0] = sp[-2]; sp[1] = sp[-1]; sp += 2; NEXT_INSN; - insn_dup2_x1: + insn_dup2_x1: dupx (sp, 2, 1); sp+=2; NEXT_INSN; - insn_dup2_x2: + insn_dup2_x2: dupx (sp, 2, 2); sp+=2; NEXT_INSN; - insn_swap: + insn_swap: { jobject tmp1 = POPA(); jobject tmp2 = POPA(); @@ -1294,56 +1683,55 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_iadd: + insn_iadd: BINOPI(+); NEXT_INSN; - insn_ladd: + insn_ladd: BINOPL(+); NEXT_INSN; - insn_fadd: + insn_fadd: BINOPF(+); NEXT_INSN; - insn_dadd: + insn_dadd: BINOPD(+); NEXT_INSN; - insn_isub: + insn_isub: BINOPI(-); NEXT_INSN; - insn_lsub: + insn_lsub: BINOPL(-); NEXT_INSN; - insn_fsub: + insn_fsub: BINOPF(-); NEXT_INSN; - insn_dsub: + insn_dsub: BINOPD(-); NEXT_INSN; - insn_imul: + insn_imul: BINOPI(*); NEXT_INSN; - insn_lmul: + insn_lmul: BINOPL(*); NEXT_INSN; - insn_fmul: + insn_fmul: BINOPF(*); NEXT_INSN; - insn_dmul: + insn_dmul: BINOPD(*); NEXT_INSN; - insn_idiv: - SAVE_PC; + insn_idiv: { jint value2 = POPI(); jint value1 = POPI(); @@ -1352,8 +1740,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_ldiv: - SAVE_PC; + insn_ldiv: { jlong value2 = POPL(); jlong value1 = POPL(); @@ -1362,7 +1749,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_fdiv: + insn_fdiv: { jfloat value2 = POPF(); jfloat value1 = POPF(); @@ -1371,7 +1758,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_ddiv: + insn_ddiv: { jdouble value2 = POPD(); jdouble value1 = POPD(); @@ -1380,8 +1767,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_irem: - SAVE_PC; + insn_irem: { jint value2 = POPI(); jint value1 = POPI(); @@ -1390,8 +1776,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_lrem: - SAVE_PC; + insn_lrem: { jlong value2 = POPL(); jlong value1 = POPL(); @@ -1400,7 +1785,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_frem: + insn_frem: { jfloat value2 = POPF(); jfloat value1 = POPF(); @@ -1409,7 +1794,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_drem: + insn_drem: { jdouble value2 = POPD(); jdouble value1 = POPD(); @@ -1418,35 +1803,35 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_ineg: + insn_ineg: { jint value = POPI(); PUSHI (value * -1); } NEXT_INSN; - insn_lneg: + insn_lneg: { jlong value = POPL(); PUSHL (value * -1); } NEXT_INSN; - insn_fneg: + insn_fneg: { jfloat value = POPF(); PUSHF (value * -1); } NEXT_INSN; - insn_dneg: + insn_dneg: { jdouble value = POPD(); PUSHD (value * -1); } NEXT_INSN; - insn_ishl: + insn_ishl: { jint shift = (POPI() & 0x1f); jint value = POPI(); @@ -1454,7 +1839,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_lshl: + insn_lshl: { jint shift = (POPI() & 0x3f); jlong value = POPL(); @@ -1462,7 +1847,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_ishr: + insn_ishr: { jint shift = (POPI() & 0x1f); jint value = POPI(); @@ -1470,7 +1855,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_lshr: + insn_lshr: { jint shift = (POPI() & 0x3f); jlong value = POPL(); @@ -1478,7 +1863,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_iushr: + insn_iushr: { jint shift = (POPI() & 0x1f); unsigned long value = POPI(); @@ -1486,7 +1871,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_lushr: + insn_lushr: { jint shift = (POPI() & 0x3f); UINT64 value = (UINT64) POPL(); @@ -1494,63 +1879,63 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_iand: + insn_iand: BINOPI (&); NEXT_INSN; - insn_land: + insn_land: BINOPL (&); NEXT_INSN; - insn_ior: + insn_ior: BINOPI (|); NEXT_INSN; - insn_lor: + insn_lor: BINOPL (|); NEXT_INSN; - insn_ixor: + insn_ixor: BINOPI (^); NEXT_INSN; - insn_lxor: + insn_lxor: BINOPL (^); NEXT_INSN; - insn_iinc: + insn_iinc: { - jint index = get1u (pc++); - jint amount = get1s (pc++); + jint index = GET1U (); + jint amount = GET1S (); locals[index].i += amount; } NEXT_INSN; - insn_i2l: + insn_i2l: {jlong value = POPI(); PUSHL (value);} NEXT_INSN; - insn_i2f: + insn_i2f: {jfloat value = POPI(); PUSHF (value);} NEXT_INSN; - insn_i2d: + insn_i2d: {jdouble value = POPI(); PUSHD (value);} NEXT_INSN; - insn_l2i: + insn_l2i: {jint value = POPL(); PUSHI (value);} NEXT_INSN; - insn_l2f: + insn_l2f: {jfloat value = POPL(); PUSHF (value);} NEXT_INSN; - insn_l2d: + insn_l2d: {jdouble value = POPL(); PUSHD (value);} NEXT_INSN; - insn_f2i: + insn_f2i: { using namespace java::lang; jint value = convert (POPF (), Integer::MIN_VALUE, Integer::MAX_VALUE); @@ -1558,7 +1943,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_f2l: + insn_f2l: { using namespace java::lang; jlong value = convert (POPF (), Long::MIN_VALUE, Long::MAX_VALUE); @@ -1566,11 +1951,11 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_f2d: + insn_f2d: { jdouble value = POPF (); PUSHD(value); } NEXT_INSN; - insn_d2i: + insn_d2i: { using namespace java::lang; jint value = convert (POPD (), Integer::MIN_VALUE, Integer::MAX_VALUE); @@ -1578,7 +1963,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_d2l: + insn_d2l: { using namespace java::lang; jlong value = convert (POPD (), Long::MIN_VALUE, Long::MAX_VALUE); @@ -1586,23 +1971,23 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_d2f: + insn_d2f: { jfloat value = POPD (); PUSHF(value); } NEXT_INSN; - insn_i2b: + insn_i2b: { jbyte value = POPI (); PUSHI(value); } NEXT_INSN; - insn_i2c: + insn_i2c: { jchar value = POPI (); PUSHI(value); } NEXT_INSN; - insn_i2s: + insn_i2s: { jshort value = POPI (); PUSHI(value); } NEXT_INSN; - insn_lcmp: + insn_lcmp: { jlong value2 = POPL (); jlong value1 = POPL (); @@ -1615,8 +2000,14 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_fcmpl: - insn_fcmpg: + insn_fcmpl: + tmpval = -1; + goto fcmp; + + insn_fcmpg: + tmpval = 1; + + fcmp: { jfloat value2 = POPF (); jfloat value1 = POPF (); @@ -1626,15 +2017,19 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) PUSHI (0); else if (value1 < value2) PUSHI (-1); - else if ((*(pc-1)) == op_fcmpg) - PUSHI (1); else - PUSHI (-1); + PUSHI (tmpval); } NEXT_INSN; - insn_dcmpl: - insn_dcmpg: + insn_dcmpl: + tmpval = 1; + goto dcmp; + + insn_dcmpg: + tmpval = -1; + + dcmp: { jdouble value2 = POPD (); jdouble value1 = POPD (); @@ -1644,220 +2039,267 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) PUSHI (0); else if (value1 < value2) PUSHI (-1); - else if ((*(pc-1)) == op_dcmpg) - PUSHI (1); else - PUSHI (-1); + PUSHI (tmpval); } NEXT_INSN; - insn_ifeq: + insn_ifeq: { - jint offset = get2s (pc); if (POPI() == 0) - pc = pc-1+offset; + TAKE_GOTO; else - pc = pc+2; + SKIP_GOTO; } NEXT_INSN; - insn_ifne: + insn_ifne: { - jint offset = get2s (pc); if (POPI() != 0) - pc = pc-1+offset; + TAKE_GOTO; else - pc = pc+2; + SKIP_GOTO; } NEXT_INSN; - insn_iflt: + insn_iflt: { - jint offset = get2s (pc); if (POPI() < 0) - pc = pc-1+offset; + TAKE_GOTO; else - pc = pc+2; + SKIP_GOTO; } NEXT_INSN; - insn_ifge: + insn_ifge: { - jint offset = get2s (pc); if (POPI() >= 0) - pc = pc-1+offset; + TAKE_GOTO; else - pc = pc+2; + SKIP_GOTO; } NEXT_INSN; - insn_ifgt: + insn_ifgt: { - jint offset = get2s (pc); if (POPI() > 0) - pc = pc-1+offset; + TAKE_GOTO; else - pc = pc+2; + SKIP_GOTO; } NEXT_INSN; - insn_ifle: + insn_ifle: { - jint offset = get2s (pc); if (POPI() <= 0) - pc = pc-1+offset; + TAKE_GOTO; else - pc = pc+2; + SKIP_GOTO; } NEXT_INSN; - insn_if_icmpeq: + insn_if_icmpeq: { - jint offset = get2s (pc); jint value2 = POPI(); jint value1 = POPI(); if (value1 == value2) - pc = pc-1+offset; + TAKE_GOTO; else - pc = pc+2; + SKIP_GOTO; } NEXT_INSN; - insn_if_icmpne: + insn_if_icmpne: { - jint offset = get2s (pc); jint value2 = POPI(); jint value1 = POPI(); if (value1 != value2) - pc = pc-1+offset; + TAKE_GOTO; else - pc = pc+2; + SKIP_GOTO; } NEXT_INSN; - insn_if_icmplt: + insn_if_icmplt: { - jint offset = get2s (pc); jint value2 = POPI(); jint value1 = POPI(); if (value1 < value2) - pc = pc-1+offset; + TAKE_GOTO; else - pc = pc+2; + SKIP_GOTO; } NEXT_INSN; - insn_if_icmpge: + insn_if_icmpge: { - jint offset = get2s (pc); jint value2 = POPI(); jint value1 = POPI(); if (value1 >= value2) - pc = pc-1+offset; + TAKE_GOTO; else - pc = pc+2; + SKIP_GOTO; } NEXT_INSN; - insn_if_icmpgt: + insn_if_icmpgt: { - jint offset = get2s (pc); jint value2 = POPI(); jint value1 = POPI(); if (value1 > value2) - pc = pc-1+offset; + TAKE_GOTO; else - pc = pc+2; + SKIP_GOTO; } NEXT_INSN; - insn_if_icmple: + insn_if_icmple: { - jint offset = get2s (pc); jint value2 = POPI(); jint value1 = POPI(); if (value1 <= value2) - pc = pc-1+offset; + TAKE_GOTO; else - pc = pc+2; + SKIP_GOTO; } NEXT_INSN; - insn_if_acmpeq: + insn_if_acmpeq: { - jint offset = get2s (pc); jobject value2 = POPA(); jobject value1 = POPA(); if (value1 == value2) - pc = pc-1+offset; + TAKE_GOTO; else - pc = pc+2; + SKIP_GOTO; } NEXT_INSN; - insn_if_acmpne: + insn_if_acmpne: { - jint offset = get2s (pc); jobject value2 = POPA(); jobject value1 = POPA(); if (value1 != value2) - pc = pc-1+offset; + TAKE_GOTO; else - pc = pc+2; + SKIP_GOTO; } NEXT_INSN; - insn_goto: + insn_goto_w: +#ifndef DIRECT_THREADED + // For direct threaded, goto and goto_w are the same. + pc = pc - 1 + get4 (pc); + NEXT_INSN; +#endif /* DIRECT_THREADED */ + insn_goto: + TAKE_GOTO; + NEXT_INSN; + + insn_jsr_w: +#ifndef DIRECT_THREADED + // For direct threaded, jsr and jsr_w are the same. { - jint offset = get2s (pc); - pc = pc-1+offset; + pc_t next = pc - 1 + get4 (pc); + pc += 4; + PUSHA ((jobject) pc); + pc = next; + } + NEXT_INSN; +#endif /* DIRECT_THREADED */ + insn_jsr: + { + pc_t next = GOTO_VAL(); + SKIP_GOTO; + PUSHA ((jobject) pc); + pc = next; } NEXT_INSN; - insn_jsr: + insn_ret: { - unsigned char *base_pc = pc-1; - jint offset = get2s (pc); pc += 2; - PUSHA ((jobject)pc); - pc = base_pc+offset; + jint index = GET1U (); + pc = (pc_t) PEEKA (index); } NEXT_INSN; - insn_ret: + insn_tableswitch: { - jint index = get1u (pc); - pc = (unsigned char*) PEEKA (index); - } - NEXT_INSN; +#ifdef DIRECT_THREADED + void *def = (pc++)->datum; - 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); + jint low = INTVAL (); + jint high = INTVAL (); if (index < low || index > high) - pc = base_pc + def; + pc = (insn_slot *) def; else - pc = base_pc + get4 (pc+4*(index-low+3)); + pc = (insn_slot *) ((pc + index - low)->datum); +#else + pc_t base_pc = pc - 1; + int index = POPI (); + + pc_t base = (pc_t) 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)); +#endif /* DIRECT_THREADED */ } NEXT_INSN; - insn_lookupswitch: + insn_lookupswitch: { +#ifdef DIRECT_THREADED + void *def = (pc++)->insn; + + int index = POPI(); + + jint npairs = INTVAL (); + + int max = npairs - 1; + int min = 0; + + // Simple binary search... + while (min < max) + { + int half = (min + max) / 2; + int match = pc[2 * half].int_val; + + if (index == match) + { + // Found it. + pc = (insn_slot *) pc[2 * half + 1].datum; + NEXT_INSN; + } + else if (index < match) + // We can use HALF - 1 here because we check again on + // loop exit. + max = half - 1; + else + // We can use HALF + 1 here because we check again on + // loop exit. + min = half + 1; + } + if (index == pc[2 * min].int_val) + pc = (insn_slot *) pc[2 * min + 1].datum; + else + pc = (insn_slot *) def; +#else unsigned char *base_pc = pc-1; int index = POPI(); unsigned char* base = bytecode (); while ((pc-base) % 4 != 0) - pc++; + ++pc; jint def = get4 (pc); jint npairs = get4 (pc+4); @@ -1865,7 +2307,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) int max = npairs-1; int min = 0; - // simple binary search... + // Simple binary search... while (min < max) { int half = (min+max)/2; @@ -1873,35 +2315,50 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) if (index == match) min = max = half; - else if (index < match) - max = half-1; - + // We can use HALF - 1 here because we check again on + // loop exit. + max = half - 1; else - min = half+1; + // We can use HALF + 1 here because we check again on + // loop exit. + 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; +#endif /* DIRECT_THREADED */ } 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; + insn_areturn: + *(jobject *) retp = POPA (); return; - insn_getstatic: - SAVE_PC; + insn_lreturn: + *(jlong *) retp = POPL (); + return; + + insn_freturn: + *(jfloat *) retp = POPF (); + return; + + insn_dreturn: + *(jdouble *) retp = POPD (); + return; + + insn_ireturn: + *(jint *) retp = POPI (); + return; + + insn_return: + return; + + insn_getstatic: { - jint fieldref_index = get2u (pc); pc += 2; + jint fieldref_index = GET2U (); _Jv_ResolvePoolEntry (defining_class, fieldref_index); _Jv_Field *field = pool_data[fieldref_index].field; @@ -1911,41 +2368,84 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) jclass type = field->type; + // We rewrite the instruction once we discover what it refers + // to. + void *newinsn = NULL; if (type->isPrimitive ()) { switch (type->size_in_bytes) { case 1: PUSHI (*(jbyte*) (field->u.addr)); + newinsn = AMPAMP (getstatic_resolved_1); break; case 2: if (type == JvPrimClass (char)) - PUSHI(*(jchar*) (field->u.addr)); + { + PUSHI(*(jchar*) (field->u.addr)); + newinsn = AMPAMP (getstatic_resolved_char); + } else - PUSHI(*(jshort*) (field->u.addr)); + { + PUSHI(*(jshort*) (field->u.addr)); + newinsn = AMPAMP (getstatic_resolved_short); + } break; case 4: PUSHI(*(jint*) (field->u.addr)); + newinsn = AMPAMP (getstatic_resolved_4); break; case 8: PUSHL(*(jlong*) (field->u.addr)); + newinsn = AMPAMP (getstatic_resolved_8); break; } } else { PUSHA(*(jobject*) (field->u.addr)); + newinsn = AMPAMP (getstatic_resolved_obj); } + +#ifdef DIRECT_THREADED + pc[-2].insn = newinsn; + pc[-1].datum = field->u.addr; +#endif /* DIRECT_THREADED */ } NEXT_INSN; - insn_getfield: - SAVE_PC; +#ifdef DIRECT_THREADED + getstatic_resolved_1: + PUSHI (*(jbyte *) AVAL ()); + NEXT_INSN; + + getstatic_resolved_char: + PUSHI (*(jchar *) AVAL ()); + NEXT_INSN; + + getstatic_resolved_short: + PUSHI (*(jshort *) AVAL ()); + NEXT_INSN; + + getstatic_resolved_4: + PUSHI (*(jint *) AVAL ()); + NEXT_INSN; + + getstatic_resolved_8: + PUSHL (*(jlong *) AVAL ()); + NEXT_INSN; + + getstatic_resolved_obj: + PUSHA (*(jobject *) AVAL ()); + NEXT_INSN; +#endif /* DIRECT_THREADED */ + + insn_getfield: { - jint fieldref_index = get2u (pc); pc += 2; + jint fieldref_index = GET2U (); _Jv_ResolvePoolEntry (defining_class, fieldref_index); _Jv_Field *field = pool_data[fieldref_index].field; @@ -1961,41 +2461,106 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) jobject obj = POPA(); NULLCHECK(obj); + void *newinsn = NULL; if (type->isPrimitive ()) { switch (type->size_in_bytes) { case 1: PUSHI (*(jbyte*) ((char*)obj + field_offset)); + newinsn = AMPAMP (getfield_resolved_1); break; case 2: if (type == JvPrimClass (char)) - PUSHI (*(jchar*) ((char*)obj + field_offset)); + { + PUSHI (*(jchar*) ((char*)obj + field_offset)); + newinsn = AMPAMP (getfield_resolved_char); + } else - PUSHI (*(jshort*) ((char*)obj + field_offset)); + { + PUSHI (*(jshort*) ((char*)obj + field_offset)); + newinsn = AMPAMP (getfield_resolved_short); + } break; case 4: PUSHI (*(jint*) ((char*)obj + field_offset)); + newinsn = AMPAMP (getfield_resolved_4); break; case 8: PUSHL(*(jlong*) ((char*)obj + field_offset)); + newinsn = AMPAMP (getfield_resolved_8); break; } } else { PUSHA(*(jobject*) ((char*)obj + field_offset)); + newinsn = AMPAMP (getfield_resolved_obj); } + +#ifdef DIRECT_THREADED + pc[-2].insn = newinsn; + pc[-1].int_val = field_offset; +#endif /* DIRECT_THREADED */ } NEXT_INSN; - insn_putstatic: - SAVE_PC; +#ifdef DIRECT_THREADED + getfield_resolved_1: { - jint fieldref_index = get2u (pc); pc += 2; + char *obj = (char *) POPA (); + NULLCHECK (obj); + PUSHI (*(jbyte *) (obj + INTVAL ())); + } + NEXT_INSN; + + getfield_resolved_char: + { + char *obj = (char *) POPA (); + NULLCHECK (obj); + PUSHI (*(jchar *) (obj + INTVAL ())); + } + NEXT_INSN; + + getfield_resolved_short: + { + char *obj = (char *) POPA (); + NULLCHECK (obj); + PUSHI (*(jshort *) (obj + INTVAL ())); + } + NEXT_INSN; + + getfield_resolved_4: + { + char *obj = (char *) POPA (); + NULLCHECK (obj); + PUSHI (*(jint *) (obj + INTVAL ())); + } + NEXT_INSN; + + getfield_resolved_8: + { + char *obj = (char *) POPA (); + NULLCHECK (obj); + PUSHL (*(jlong *) (obj + INTVAL ())); + } + NEXT_INSN; + + getfield_resolved_obj: + { + char *obj = (char *) POPA (); + NULLCHECK (obj); + PUSHA (*(jobject *) (obj + INTVAL ())); + } + NEXT_INSN; +#endif /* DIRECT_THREADED */ + + insn_putstatic: + { + jint fieldref_index = GET2U (); _Jv_ResolvePoolEntry (defining_class, fieldref_index); _Jv_Field *field = pool_data[fieldref_index].field; @@ -2006,6 +2571,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) throw_incompatible_class_change_error (JvNewStringLatin1 ("field no longer static")); + void *newinsn = NULL; if (type->isPrimitive ()) { switch (type->size_in_bytes) @@ -2014,6 +2580,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) { jint value = POPI(); *(jbyte*) (field->u.addr) = value; + newinsn = AMPAMP (putstatic_resolved_1); break; } @@ -2021,6 +2588,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) { jint value = POPI(); *(jchar*) (field->u.addr) = value; + newinsn = AMPAMP (putstatic_resolved_2); break; } @@ -2028,6 +2596,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) { jint value = POPI(); *(jint*) (field->u.addr) = value; + newinsn = AMPAMP (putstatic_resolved_4); break; } @@ -2035,6 +2604,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) { jlong value = POPL(); *(jlong*) (field->u.addr) = value; + newinsn = AMPAMP (putstatic_resolved_8); break; } } @@ -2043,15 +2613,41 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) { jobject value = POPA(); *(jobject*) (field->u.addr) = value; + newinsn = AMPAMP (putstatic_resolved_obj); } + +#ifdef DIRECT_THREADED + pc[-2].insn = newinsn; + pc[-1].datum = field->u.addr; +#endif /* DIRECT_THREADED */ } NEXT_INSN; +#ifdef DIRECT_THREADED + putstatic_resolved_1: + *(jbyte *) AVAL () = POPI (); + NEXT_INSN; - insn_putfield: - SAVE_PC; + putstatic_resolved_2: + *(jchar *) AVAL () = POPI (); + NEXT_INSN; + + putstatic_resolved_4: + *(jint *) AVAL () = POPI (); + NEXT_INSN; + + putstatic_resolved_8: + *(jlong *) AVAL () = POPL (); + NEXT_INSN; + + putstatic_resolved_obj: + *(jobject *) AVAL () = POPA (); + NEXT_INSN; +#endif /* DIRECT_THREADED */ + + insn_putfield: { - jint fieldref_index = get2u (pc); pc += 2; + jint fieldref_index = GET2U (); _Jv_ResolvePoolEntry (defining_class, fieldref_index); _Jv_Field *field = pool_data[fieldref_index].field; @@ -2065,6 +2661,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) if (field_offset > 0xffff) throw new java::lang::VirtualMachineError; + void *newinsn = NULL; if (type->isPrimitive ()) { switch (type->size_in_bytes) @@ -2075,6 +2672,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) jobject obj = POPA(); NULLCHECK(obj); *(jbyte*) ((char*)obj + field_offset) = value; + newinsn = AMPAMP (putfield_resolved_1); break; } @@ -2084,6 +2682,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) jobject obj = POPA(); NULLCHECK(obj); *(jchar*) ((char*)obj + field_offset) = value; + newinsn = AMPAMP (putfield_resolved_2); break; } @@ -2093,6 +2692,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) jobject obj = POPA(); NULLCHECK(obj); *(jint*) ((char*)obj + field_offset) = value; + newinsn = AMPAMP (putfield_resolved_4); break; } @@ -2102,6 +2702,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) jobject obj = POPA(); NULLCHECK(obj); *(jlong*) ((char*)obj + field_offset) = value; + newinsn = AMPAMP (putfield_resolved_8); break; } } @@ -2112,14 +2713,66 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) jobject obj = POPA(); NULLCHECK(obj); *(jobject*) ((char*)obj + field_offset) = value; + newinsn = AMPAMP (putfield_resolved_obj); } + +#ifdef DIRECT_THREADED + pc[-2].insn = newinsn; + pc[-1].int_val = field_offset; +#endif /* DIRECT_THREADED */ } NEXT_INSN; - insn_invokespecial: - SAVE_PC; +#ifdef DIRECT_THREADED + putfield_resolved_1: { - int index = get2u (pc); pc += 2; + jint val = POPI (); + char *obj = (char *) POPA (); + NULLCHECK (obj); + *(jbyte *) (obj + INTVAL ()) = val; + } + NEXT_INSN; + + putfield_resolved_2: + { + jint val = POPI (); + char *obj = (char *) POPA (); + NULLCHECK (obj); + *(jchar *) (obj + INTVAL ()) = val; + } + NEXT_INSN; + + putfield_resolved_4: + { + jint val = POPI (); + char *obj = (char *) POPA (); + NULLCHECK (obj); + *(jint *) (obj + INTVAL ()) = val; + } + NEXT_INSN; + + putfield_resolved_8: + { + jlong val = POPL (); + char *obj = (char *) POPA (); + NULLCHECK (obj); + *(jlong *) (obj + INTVAL ()) = val; + } + NEXT_INSN; + + putfield_resolved_obj: + { + jobject val = POPA (); + char *obj = (char *) POPA (); + NULLCHECK (obj); + *(jobject *) (obj + INTVAL ()) = val; + } + NEXT_INSN; +#endif /* DIRECT_THREADED */ + + insn_invokespecial: + { + int index = GET2U (); rmeth = (_Jv_ResolvePoolEntry (defining_class, index)).rmethod; @@ -2128,13 +2781,30 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) NULLCHECK (sp[0].o); fun = (void (*)()) rmeth->method->ncode; + +#ifdef DIRECT_THREADED + // Rewrite instruction so that we use a faster pre-resolved + // method. + pc[-2].insn = &&invokespecial_resolved; + pc[-1].datum = rmeth; +#endif /* DIRECT_THREADED */ } goto perform_invoke; - insn_invokestatic: - SAVE_PC; +#ifdef DIRECT_THREADED + invokespecial_resolved: { - int index = get2u (pc); pc += 2; + rmeth = (_Jv_ResolvedMethod *) AVAL (); + sp -= rmeth->stack_item_count; + NULLCHECK (sp[0].o); + fun = (void (*)()) rmeth->method->ncode; + } + goto perform_invoke; +#endif /* DIRECT_THREADED */ + + insn_invokestatic: + { + int index = GET2U (); rmeth = (_Jv_ResolvePoolEntry (defining_class, index)).rmethod; @@ -2142,16 +2812,29 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) _Jv_InitClass (rmeth->klass); fun = (void (*)()) rmeth->method->ncode; + +#ifdef DIRECT_THREADED + // Rewrite instruction so that we use a faster pre-resolved + // method. + pc[-2].insn = &&invokestatic_resolved; + pc[-1].datum = rmeth; +#endif /* DIRECT_THREADED */ } goto perform_invoke; - insn_invokeinterface: - SAVE_PC; +#ifdef DIRECT_THREADED + invokestatic_resolved: { - int index = get2u (pc); pc += 2; + rmeth = (_Jv_ResolvedMethod *) AVAL (); + sp -= rmeth->stack_item_count; + fun = (void (*)()) rmeth->method->ncode; + } + goto perform_invoke; +#endif /* DIRECT_THREADED */ - // invokeinterface has two unused bytes... - pc += 2; + insn_invokeinterface: + { + int index = GET2U (); rmeth = (_Jv_ResolvePoolEntry (defining_class, index)).rmethod; @@ -2165,44 +2848,96 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) _Jv_LookupInterfaceMethod (rcv->getClass (), rmeth->method->name, rmeth->method->signature); + +#ifdef DIRECT_THREADED + // Rewrite instruction so that we use a faster pre-resolved + // method. + pc[-2].insn = &&invokeinterface_resolved; + pc[-1].datum = rmeth; +#else + // Skip dummy bytes. + pc += 2; +#endif /* DIRECT_THREADED */ } goto perform_invoke; - - insn_new: - SAVE_PC; +#ifdef DIRECT_THREADED + invokeinterface_resolved: { - int index = get2u (pc); pc += 2; + rmeth = (_Jv_ResolvedMethod *) AVAL (); + 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; +#endif /* DIRECT_THREADED */ + + insn_new: + { + int index = GET2U (); jclass klass = (_Jv_ResolvePoolEntry (defining_class, index)).clazz; _Jv_InitClass (klass); jobject res = _Jv_AllocObject (klass, klass->size_in_bytes); PUSHA (res); + +#ifdef DIRECT_THREADED + pc[-2].insn = &&new_resolved; + pc[-1].datum = klass; +#endif /* DIRECT_THREADED */ } NEXT_INSN; - insn_newarray: - SAVE_PC; +#ifdef DIRECT_THREADED + new_resolved: { - int atype = get1u (pc++); + jclass klass = (jclass) AVAL (); + jobject res = _Jv_AllocObject (klass, klass->size_in_bytes); + PUSHA (res); + } + NEXT_INSN; +#endif /* DIRECT_THREADED */ + + insn_newarray: + { + int atype = GET1U (); int size = POPI(); jobject result = _Jv_NewArray (atype, size); PUSHA (result); } NEXT_INSN; - insn_anewarray: - SAVE_PC; + insn_anewarray: { - int index = get2u (pc); pc += 2; + int index = GET2U (); jclass klass = (_Jv_ResolvePoolEntry (defining_class, index)).clazz; int size = POPI(); _Jv_InitClass (klass); jobject result = _Jv_NewObjectArray (size, klass, 0); PUSHA (result); + +#ifdef DIRECT_THREADED + pc[-2].insn = &&anewarray_resolved; + pc[-1].datum = klass; +#endif /* DIRECT_THREADED */ } NEXT_INSN; - insn_arraylength: +#ifdef DIRECT_THREADED + anewarray_resolved: + { + jclass klass = (jclass) AVAL (); + int size = POPI (); + jobject result = _Jv_NewObjectArray (size, klass, 0); + PUSHA (result); + } + NEXT_INSN; +#endif /* DIRECT_THREADED */ + + insn_arraylength: { __JArray *arr = (__JArray*)POPA(); NULLARRAYCHECK (arr); @@ -2210,42 +2945,68 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_athrow: - SAVE_PC; + insn_athrow: { jobject value = POPA(); throw static_cast(value); } NEXT_INSN; - insn_checkcast: - SAVE_PC; + insn_checkcast: { jobject value = POPA(); - jint index = get2u (pc); pc += 2; + jint index = GET2U (); jclass to = (_Jv_ResolvePoolEntry (defining_class, index)).clazz; if (value != NULL && ! to->isInstance (value)) - { - throw new java::lang::ClassCastException (to->getName()); - } + throw new java::lang::ClassCastException (to->getName()); PUSHA (value); + +#ifdef DIRECT_THREADED + pc[-2].insn = &&checkcast_resolved; + pc[-1].datum = to; +#endif /* DIRECT_THREADED */ + } + NEXT_INSN; + +#ifdef DIRECT_THREADED + checkcast_resolved: + { + jobject value = POPA (); + jclass to = (jclass) AVAL (); + if (value != NULL && ! to->isInstance (value)) + throw new java::lang::ClassCastException (to->getName()); + PUSHA (value); } NEXT_INSN; +#endif /* DIRECT_THREADED */ - insn_instanceof: - SAVE_PC; + insn_instanceof: { jobject value = POPA(); - jint index = get2u (pc); pc += 2; + jint index = GET2U (); jclass to = (_Jv_ResolvePoolEntry (defining_class, index)).clazz; PUSHI (to->isInstance (value)); + +#ifdef DIRECT_THREADED + pc[-2].insn = &&instanceof_resolved; + pc[-1].datum = to; +#endif /* DIRECT_THREADED */ } NEXT_INSN; - insn_monitorenter: - SAVE_PC; +#ifdef DIRECT_THREADED + instanceof_resolved: + { + jobject value = POPA (); + jclass to = (jclass) AVAL (); + PUSHI (to->isInstance (value)); + } + NEXT_INSN; +#endif /* DIRECT_THREADED */ + + insn_monitorenter: { jobject value = POPA(); NULLCHECK(value); @@ -2253,8 +3014,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_monitorexit: - SAVE_PC; + insn_monitorexit: { jobject value = POPA(); NULLCHECK(value); @@ -2262,28 +3022,49 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } NEXT_INSN; - insn_ifnull: + insn_ifnull: { - unsigned char* base_pc = pc-1; - jint offset = get2s (pc); pc += 2; jobject val = POPA(); if (val == NULL) - pc = base_pc+offset; + TAKE_GOTO; + else + SKIP_GOTO; } NEXT_INSN; - insn_ifnonnull: + insn_ifnonnull: { - unsigned char* base_pc = pc-1; - jint offset = get2s (pc); pc += 2; jobject val = POPA(); if (val != NULL) - pc = base_pc+offset; + TAKE_GOTO; + else + SKIP_GOTO; } NEXT_INSN; - insn_wide: - SAVE_PC; + insn_multianewarray: + { + int kind_index = GET2U (); + int dim = GET1U (); + + 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; + +#ifndef DIRECT_THREADED + insn_wide: { jint the_mod_op = get1u (pc++); jint wide = get2u (pc); pc += 2; @@ -2343,48 +3124,51 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) } } +#endif /* DIRECT_THREADED */ + } + catch (java::lang::Throwable *ex) + { +#ifdef DIRECT_THREADED + void *logical_pc = (void *) ((insn_slot *) pc - 1); +#else + int logical_pc = pc - 1 - bytecode (); +#endif + _Jv_InterpException *exc = exceptions (); + jclass exc_class = ex->getClass (); - insn_multianewarray: - SAVE_PC; - { - int kind_index = get2u (pc); pc += 2; - int dim = get1u (pc); pc += 1; + for (int i = 0; i < exc_count; i++) + { + if (PCVAL (exc[i].start_pc) <= logical_pc + && logical_pc < PCVAL (exc[i].end_pc)) + { +#ifdef DIRECT_THREADED + jclass handler = (jclass) exc[i].handler_type.p; +#else + jclass handler = NULL; + if (exc[i].handler_type.i != 0) + handler = (_Jv_ResolvePoolEntry (defining_class, + exc[i].handler_type.i)).clazz; +#endif /* DIRECT_THREADED */ - jclass type - = (_Jv_ResolvePoolEntry (defining_class, kind_index)).clazz; - _Jv_InitClass (type); - jint *sizes = (jint*) __builtin_alloca (sizeof (jint)*dim); + if (handler == NULL || handler->isAssignableFrom (exc_class)) + { +#ifdef DIRECT_THREADED + pc = (insn_slot *) exc[i].handler_pc.p; +#else + pc = bytecode () + exc[i].handler_pc.i; +#endif /* DIRECT_THREADED */ + sp = stack; + sp++->o = ex; // Push exception. + NEXT_INSN; + } + } + } - 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; + // No handler, so re-throw. + throw ex; + } } - static void throw_internal_error (char *msg) { diff --git a/libjava/java/lang/Class.h b/libjava/java/lang/Class.h index 91a430a548b..eb33c93a732 100644 --- a/libjava/java/lang/Class.h +++ b/libjava/java/lang/Class.h @@ -338,7 +338,6 @@ private: friend class _Jv_ClassReader; friend class _Jv_InterpClass; friend class _Jv_InterpMethod; - friend class _Jv_InterpMethodInvocation; #endif #ifdef JV_MARKOBJ_DECL diff --git a/libjava/verify.cc b/libjava/verify.cc index 405481977d7..29f0f321a7f 100644 --- a/libjava/verify.cc +++ b/libjava/verify.cc @@ -1882,18 +1882,18 @@ private: // Verify exception handlers. for (int i = 0; i < current_method->exc_count; ++i) { - if (! (flags[exception[i].handler_pc] & FLAG_INSN_START)) + if (! (flags[exception[i].handler_pc.i] & FLAG_INSN_START)) verify_fail ("exception handler not at instruction start", - exception[i].handler_pc); - if (! (flags[exception[i].start_pc] & FLAG_INSN_START)) + exception[i].handler_pc.i); + if (! (flags[exception[i].start_pc.i] & FLAG_INSN_START)) verify_fail ("exception start not at instruction start", - exception[i].start_pc); - if (exception[i].end_pc != current_method->code_length - && ! (flags[exception[i].end_pc] & FLAG_INSN_START)) + exception[i].start_pc.i); + if (exception[i].end_pc.i != current_method->code_length + && ! (flags[exception[i].end_pc.i] & FLAG_INSN_START)) verify_fail ("exception end not at instruction start", - exception[i].end_pc); + exception[i].end_pc.i); - flags[exception[i].handler_pc] |= FLAG_BRANCH_TARGET; + flags[exception[i].handler_pc.i] |= FLAG_BRANCH_TARGET; } } @@ -2186,12 +2186,12 @@ private: // through them all. for (int i = 0; i < current_method->exc_count; ++i) { - if (PC >= exception[i].start_pc && PC < exception[i].end_pc) + if (PC >= exception[i].start_pc.i && PC < exception[i].end_pc.i) { type handler (&java::lang::Throwable::class$); - if (exception[i].handler_type != 0) - handler = check_class_constant (exception[i].handler_type); - push_exception_jump (handler, exception[i].handler_pc); + if (exception[i].handler_type.i != 0) + handler = check_class_constant (exception[i].handler_type.i); + push_exception_jump (handler, exception[i].handler_pc.i); } }