This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFC: direct threading


I'm not checking this in yet.  I'll probably check it in after the
branch is made.  It is too new right now, and I don't have the time to
test it as much as would be necessary.  I'm posting it for commentary.

This patch changes the libgcj interpreter to use direct threaded code
instead of a bytecode interpreter.  We do a couple passes over the
bytecode to build up a new structure which is then interpreted.  Some
routines, like invokestatic, then further rewrite the interpreted
structure to avoid repeatedly paying costs that only need to be paid
once.  For instance, a class will be initialized only once for any
given instance of invokestatic.  We also simply omit `nop' (and we
could easily do jump threading, too, if we wanted).

Running this against the infamous `prime' benchmark I saw around a 20%
speedup.  That seems good, except that the JDK 1.2 interpreter is
still nearly twice as fast.  My guess is that we're paying too much
for function calls, but I haven't really investigated (nor do I intend
to).

On the down side, this requires more startup the first time a method
is called, and it also requires more memory.  Perhaps it isn't
worthwhile on that basis?

Tom

Index: defineclass.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/defineclass.cc,v
retrieving revision 1.27
diff -u -r1.27 defineclass.cc
--- defineclass.cc 2001/12/10 01:18:30 1.27
+++ defineclass.cc 2002/02/17 19:32:17
@@ -1,6 +1,6 @@
 // defineclass.cc - defining a class from .class format.
 
-/* Copyright (C) 1999, 2000, 2001  Free Software Foundation
+/* Copyright (C) 1999, 2000, 2001, 2002  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -1262,6 +1262,7 @@
   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 (),
@@ -1279,10 +1280,10 @@
     (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 ()
Index: interpret.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/interpret.cc,v
retrieving revision 1.31
diff -u -r1.31 interpret.cc
--- interpret.cc 2002/02/10 18:32:48 1.31
+++ interpret.cc 2002/02/17 19:32:17
@@ -51,6 +51,18 @@
 
 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;
+};
+
 static inline void dupx (_Jv_word *sp, int n, int x)
 {
   // first "slide" n+x elements n to the right
@@ -228,7 +240,7 @@
 		       _Jv_InterpMethodInvocation *inv)
 {
   inv->running  = this;
-  inv->pc       = bytecode ();
+  inv->pc       = prepared;
   inv->sp       = inv->stack_base ();
   _Jv_word *locals = inv->local_base ();
 
@@ -280,7 +292,7 @@
 	    *(jfloat*)retp = r;
 	    return 0;
 	  }
-      
+
 	case FFI_TYPE_DOUBLE:
 	  {
 	    jdouble r = POPD();
@@ -298,21 +310,21 @@
 	    *(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) )
+  /* Handle an exception.  */
+  if (find_exception (ex, inv))
     goto next_segment;
 
   return ex;
@@ -320,30 +332,23 @@
 
 #define SAVE_PC   inv->pc = pc
 
-bool _Jv_InterpMethod::find_exception (jobject ex,
-				       _Jv_InterpMethodInvocation *inv)
+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 ();
+  void *logical_pc = (void *) ((insn_slot *) inv->pc - 1);
   _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)
+      if (exc[i].start_pc.p <= logical_pc && logical_pc < exc[i].end_pc.p)
 	{	
-	  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))
+	  jclass handler = (jclass) exc[i].handler_type.p;
+	  if (handler == NULL || handler->isAssignableFrom (exc_class))
 	    {
-	      inv->pc = bytecode () + exc[i].handler_pc;
+	      inv->pc = exc[i].handler_pc.p;
 	      inv->sp = inv->stack_base (); // reset stack
 	      (inv->sp++)->o = ex; // push exception
 	      return true;
@@ -411,6 +416,423 @@
   if (ex != 0) throw static_cast<jthrowable>(ex);
 }
 
+// "Compile" a method by turning it from bytecode to direct-threaded
+// code.
+void
+_Jv_InterpMethod::compile (const void * const *insn_targets)
+{
+  insn_slot *insns;
+  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 = bytecode ();
+      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;
+		SET_DATUM (&insns[pc_mapping[base_pc_val + offset]]);
+	      }
+	      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]]);
+		  }
+	      }
+	      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;
+
+	    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;
+}
+
 /*
   This proceeds execution, as designated in "inv".  If an exception
   happens, then it is simply thrown, and handled in Java.  Thus, the pc
@@ -428,21 +850,21 @@
   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[] = 
   {
-    INSN_LABEL(nop),
+    0, // nop
     INSN_LABEL(aconst_null),
     INSN_LABEL(iconst_m1),
     INSN_LABEL(iconst_0),
@@ -638,52 +1060,41 @@
     INSN_LABEL(instanceof),
     INSN_LABEL(monitorenter),
     INSN_LABEL(monitorexit),
-    INSN_LABEL(wide),
+    0, // wide
     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.
-
-     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 
+  // Compile if we must.
+  if (inv->running->prepared == NULL)
+    {
+      compile (insn_target);
+      inv->pc = inv->running->prepared;
+    }
 
-#ifdef  INLINE_SWITCH
+  insn_slot *pc = (insn_slot *) inv->pc;
 
-#define NEXT_INSN do { GOTO_INSN(*pc++); } while (0)
+#define NEXT_INSN goto *((pc++)->insn)
 
+#define INTVAL() ((pc++)->int_val)
+#define AVAL() ((pc++)->datum)
 
   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);
+      LOADA (0);
       NEXT_INSN;
 
      insn_iload:		// 0x15
-      LOADI (get1u (pc++));
+      LOADI (INTVAL ());
       NEXT_INSN;
 
      insn_iload_1:		// 0x1b
@@ -693,7 +1104,7 @@
      insn_invokevirtual:	// 0xb6
       SAVE_PC;
       {
-	int index = get2u (pc); pc += 2;
+	int index = INTVAL ();
 
 	/* _Jv_ResolvePoolEntry returns immediately if the value already
 	 * is resolved.  If we want to clutter up the code here to gain
@@ -718,9 +1129,40 @@
 	  }
 	else
 	  {
+	    jobject rcv = sp[0].o;
+	    _Jv_VTable *table = *(_Jv_VTable**) rcv;
+	    fun = (void (*)()) table->get_method (rmeth->vtable_index);
+	  }
+
+	// Rewrite instruction so that we use a faster pre-resolved
+	// method.
+	pc[-2].insn = &&invokevirtual_resolved;
+	pc[-1].datum = rmeth;
+      }
+      goto perform_invoke;
+
+     invokevirtual_resolved:
+      SAVE_PC;
+      {
+	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);
+	    _Jv_VTable *table = *(_Jv_VTable**) rcv;
+	    fun = (void (*)()) table->get_method (rmeth->vtable_index);
 	  }
       }
       goto perform_invoke;
@@ -799,10 +1241,6 @@
       }
       NEXT_INSN;
 
-
-     insn_nop:
-      NEXT_INSN;
-
      insn_aconst_null:
       PUSHA (NULL);
       NEXT_INSN;
@@ -864,49 +1302,39 @@
       NEXT_INSN;
 
      insn_bipush:
-      PUSHI (get1s(pc++));
-      NEXT_INSN;
-
      insn_sipush:
-      PUSHI (get2s(pc)); pc += 2;
+      PUSHI (INTVAL ());
       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);
+	PUSHA ((jobject) AVAL ());
       }
       NEXT_INSN;
 
      insn_ldc2_w:
       {
-	int index = get2u (pc); pc += 2;
-	memcpy (sp, &pool_data[index], 2*sizeof (_Jv_word));
+	void *where = AVAL ();
+	memcpy (sp, where, 2*sizeof (_Jv_word));
 	sp += 2;
       }
       NEXT_INSN;
 
      insn_lload:
-      LOADL (get1u (pc++));
+      LOADL (INTVAL ());
       NEXT_INSN;
 
      insn_fload:
-      LOADF (get1u (pc++));
+      LOADF (INTVAL ());
       NEXT_INSN;
 
      insn_dload:
-      LOADD (get1u (pc++));
+      LOADD (INTVAL ());
       NEXT_INSN;
 
      insn_aload:
-      LOADA (get1u (pc++));
+      LOADA (INTVAL ());
       NEXT_INSN;
 
      insn_iload_0:
@@ -1062,23 +1490,23 @@
       NEXT_INSN;
 
      insn_istore:
-      STOREI (get1u (pc++));
+      STOREI (INTVAL ());
       NEXT_INSN;
 
      insn_lstore:
-      STOREL (get1u (pc++));
+      STOREL (INTVAL ());
       NEXT_INSN;
 
      insn_fstore:
-      STOREF (get1u (pc++));
+      STOREF (INTVAL ());
       NEXT_INSN;
 
      insn_dstore:
-      STORED (get1u (pc++));
+      STORED (INTVAL ());
       NEXT_INSN;
 
      insn_astore:
-      STOREA (get1u (pc++));
+      STOREA (INTVAL ());
       NEXT_INSN;
 
      insn_istore_0:
@@ -1520,8 +1948,8 @@
 
      insn_iinc:
       {
-	jint index  = get1u (pc++);
-	jint amount = get1s (pc++);
+	jint index  = INTVAL ();
+	jint amount = INTVAL ();
 	locals[index].i += amount;
       }
       NEXT_INSN;
@@ -1616,7 +2044,13 @@
       NEXT_INSN;
 
      insn_fcmpl:
+      tmpval = -1;
+      goto fcmp;
+
      insn_fcmpg:
+      tmpval = 1;
+
+     fcmp:
       {
 	jfloat value2 = POPF ();
 	jfloat value1 = POPF ();
@@ -1626,15 +2060,19 @@
 	  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:
+      tmpval = 1;
+      goto dcmp;
+
      insn_dcmpg:
+      tmpval = -1;
+
+     dcmp:
       {
 	jdouble value2 = POPD ();
 	jdouble value1 = POPD ();
@@ -1644,247 +2082,219 @@
 	  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:
       {
-	jint offset = get2s (pc); 
 	if (POPI() == 0)
-	  pc = pc-1+offset;
+	  pc = (insn_slot *) pc->datum;
 	else
-	  pc = pc+2;
+	  ++pc;
       }
       NEXT_INSN;
 
      insn_ifne:
       {
-	jint offset = get2s (pc); 
 	if (POPI() != 0)
-	  pc = pc-1+offset;
+	  pc = (insn_slot *) pc->datum;
 	else
-	  pc = pc+2;
+	  ++pc;
       }
       NEXT_INSN;
 
      insn_iflt:
       {
-	jint offset = get2s (pc); 
 	if (POPI() < 0)
-	  pc = pc-1+offset;
+	  pc = (insn_slot *) pc->datum;
 	else
-	  pc = pc+2;
+	  ++pc;
       }
       NEXT_INSN;
 
      insn_ifge:
       {
-	jint offset = get2s (pc); 
 	if (POPI() >= 0)
-	  pc = pc-1+offset;
+	  pc = (insn_slot *) pc->datum;
 	else
-	  pc = pc+2;
+	  ++pc;
       }
       NEXT_INSN;
 
      insn_ifgt:
       {
-	jint offset = get2s (pc); 
 	if (POPI() > 0)
-	  pc = pc-1+offset;
+	  pc = (insn_slot *) pc->datum;
 	else
-	  pc = pc+2;
+	  ++pc;
       }
       NEXT_INSN;
 
      insn_ifle:
       {
-	jint offset = get2s (pc); 
 	if (POPI() <= 0)
-	  pc = pc-1+offset;
+	  pc = (insn_slot *) pc->datum;
 	else
-	  pc = pc+2;
+	  ++pc;
       }
       NEXT_INSN;
 
      insn_if_icmpeq:
       {
-	jint offset = get2s (pc); 
 	jint value2 = POPI();
 	jint value1 = POPI();
 	if (value1 == value2)
-	  pc = pc-1+offset;
+	  pc = (insn_slot *) pc->datum;
 	else
-	  pc = pc+2;
+	  ++pc;
       }
       NEXT_INSN;
 
      insn_if_icmpne:
       {
-	jint offset = get2s (pc); 
 	jint value2 = POPI();
 	jint value1 = POPI();
 	if (value1 != value2)
-	  pc = pc-1+offset;
+	  pc = (insn_slot *) pc->datum;
 	else
-	  pc = pc+2;
+	  ++pc;
       }
       NEXT_INSN;
 
      insn_if_icmplt:
       {
-	jint offset = get2s (pc); 
 	jint value2 = POPI();
 	jint value1 = POPI();
 	if (value1 < value2)
-	  pc = pc-1+offset;
+	  pc = (insn_slot *) pc->datum;
 	else
-	  pc = pc+2;
+	  ++pc;
       }
       NEXT_INSN;
 
      insn_if_icmpge:
       {
-	jint offset = get2s (pc); 
 	jint value2 = POPI();
 	jint value1 = POPI();
 	if (value1 >= value2)
-	  pc = pc-1+offset;
+	  pc = (insn_slot *) pc->datum;
 	else
-	  pc = pc+2;
+	  ++pc;
       }
       NEXT_INSN;
 
      insn_if_icmpgt:
       {
-	jint offset = get2s (pc); 
 	jint value2 = POPI();
 	jint value1 = POPI();
 	if (value1 > value2)
-	  pc = pc-1+offset;
+	  pc = (insn_slot *) pc->datum;
 	else
-	  pc = pc+2;
+	  ++pc;
       }
       NEXT_INSN;
 
      insn_if_icmple:
       {
-	jint offset = get2s (pc); 
 	jint value2 = POPI();
 	jint value1 = POPI();
 	if (value1 <= value2)
-	  pc = pc-1+offset;
+	  pc = (insn_slot *) pc->datum;
 	else
-	  pc = pc+2;
+	  ++pc;
       }
       NEXT_INSN;
 
      insn_if_acmpeq:
       {
-	jint offset = get2s (pc); 
 	jobject value2 = POPA();
 	jobject value1 = POPA();
 	if (value1 == value2)
-	  pc = pc-1+offset;
+	  pc = (insn_slot *) pc->datum;
 	else
-	  pc = pc+2;
+	  ++pc;
       }
       NEXT_INSN;
 
      insn_if_acmpne:
       {
-	jint offset = get2s (pc); 
 	jobject value2 = POPA();
 	jobject value1 = POPA();
 	if (value1 != value2)
-	  pc = pc-1+offset;
+	  pc = (insn_slot *) pc->datum;
 	else
-	  pc = pc+2;
+	  ++pc;
       }
       NEXT_INSN;
 
-     insn_goto: 
-      {
-	jint offset = get2s (pc);
-	pc = pc-1+offset;
-      }
+     insn_goto:
+     insn_goto_w:
+      pc = (insn_slot *) pc->datum;
       NEXT_INSN;
 
      insn_jsr:
+     insn_jsr_w:
       {
-	unsigned char *base_pc = pc-1;
-	jint offset = get2s (pc); pc += 2;
-	PUSHA ((jobject)pc);
-	pc = base_pc+offset;
+	void *next = AVAL ();
+	PUSHA ((jobject) pc);
+	pc = (insn_slot *) next;
       }
       NEXT_INSN;
 
      insn_ret:
       {
-	jint index = get1u (pc);
-	pc = (unsigned char*) PEEKA (index);
+	jint index = INTVAL ();
+	pc = (insn_slot *) PEEKA (index);
       }
       NEXT_INSN;
 
      insn_tableswitch:
       {
-	unsigned char *base_pc = pc-1;
+	void *def = (pc++)->datum;
+
 	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);
       }
       NEXT_INSN;
 
      insn_lookupswitch:
       {
-	unsigned char *base_pc = pc-1;
-	int index = POPI();
+	void *def = (pc++)->insn;
 
-	unsigned char* base = bytecode ();
-	while ((pc-base) % 4 != 0)
-	  pc++;
+	int index = POPI();
 
-	jint def     = get4 (pc);
-	jint npairs  = get4 (pc+4);
+	jint npairs = INTVAL ();
 
-	int max = npairs-1;
+	int max = npairs - 1;
 	int min = 0;
 
-	// simple binary search...
+	// Simple binary search...
 	while (min < max)
 	  {
-	    int half = (min+max)/2;
-	    int match = get4 (pc+ 4*(2 + 2*half));
+	    int half = (min + max) / 2;
+	    int match = pc[2 * half].int_val;
 
 	    if (index == match)
-	      min = max = half;
-
+	      {
+		// Found it.
+		pc = (insn_slot *) pc[2 * half + 1].datum;
+		NEXT_INSN;
+	      }
 	    else if (index < match)
-	      max = half-1;
-
+	      max = half - 1;
 	    else
-	      min = half+1;
+	      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;    
+	pc = (insn_slot *) def;
       }
       NEXT_INSN;
 
@@ -1901,7 +2311,7 @@
      insn_getstatic:
       SAVE_PC;
       {
-	jint fieldref_index = get2u (pc); pc += 2;
+	jint fieldref_index = INTVAL ();
 	_Jv_ResolvePoolEntry (defining_class, fieldref_index);
 	_Jv_Field *field = pool_data[fieldref_index].field;
 
@@ -1911,41 +2321,81 @@
 
 	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 = &&getstatic_resolved_1;
 		break;
 
 	      case 2:
 		if (type == JvPrimClass (char))
-		  PUSHI(*(jchar*) (field->u.addr));
+		  {
+		    PUSHI(*(jchar*) (field->u.addr));
+		    newinsn = &&getstatic_resolved_char;
+		  }
 		else
-		  PUSHI(*(jshort*) (field->u.addr));
+		  {
+		    PUSHI(*(jshort*) (field->u.addr));
+		    newinsn = &&getstatic_resolved_short;
+		  }
 		break;
 
 	      case 4:
 		PUSHI(*(jint*) (field->u.addr));
+		newinsn = &&getstatic_resolved_4;
 		break;
 
 	      case 8:
 		PUSHL(*(jlong*) (field->u.addr));
+		newinsn = &&getstatic_resolved_8;
 		break;
 	      }
 	  }
 	else
 	  {
 	    PUSHA(*(jobject*) (field->u.addr));
+	    newinsn = &&getstatic_resolved_obj;
 	  }
+
+	pc[-2].insn = newinsn;
+	pc[-1].datum = field->u.addr;
       }
       NEXT_INSN;
 
+     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;
+
      insn_getfield:
       SAVE_PC;
       {
-	jint fieldref_index = get2u (pc); pc += 2;
+	jint fieldref_index = INTVAL ();
 	_Jv_ResolvePoolEntry (defining_class, fieldref_index);
 	_Jv_Field *field = pool_data[fieldref_index].field;
 
@@ -1961,41 +2411,109 @@
 	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 = &&getfield_resolved_1;
 		break;
 
 	      case 2:
 		if (type == JvPrimClass (char))
-		  PUSHI (*(jchar*) ((char*)obj + field_offset));
+		  {
+		    PUSHI (*(jchar*) ((char*)obj + field_offset));
+		    newinsn = &&getfield_resolved_char;
+		  }
 		else
-		  PUSHI (*(jshort*) ((char*)obj + field_offset));
+		  {
+		    PUSHI (*(jshort*) ((char*)obj + field_offset));
+		    newinsn = &&getfield_resolved_short;
+		  }
 		break;
 
 	      case 4:
 		PUSHI (*(jint*) ((char*)obj + field_offset));
+		newinsn = &&getfield_resolved_4;
 		break;
 
 	      case 8:
 		PUSHL(*(jlong*) ((char*)obj + field_offset));
+		newinsn = &&getfield_resolved_8;
 		break;
 	      }
 	  }
 	else
 	  {
 	    PUSHA(*(jobject*) ((char*)obj + field_offset));
+	    newinsn = &&getfield_resolved_obj;
 	  }
+
+	pc[-2].insn = newinsn;
+	pc[-1].int_val = field_offset;
       }
       NEXT_INSN;
 
+     getfield_resolved_1:
+      SAVE_PC;
+      {
+	char *obj = (char *) POPA ();
+	NULLCHECK (obj);
+	PUSHI (*(jbyte *) (obj + INTVAL ()));
+      }
+      NEXT_INSN;
+
+     getfield_resolved_char:
+      SAVE_PC;
+      {
+	char *obj = (char *) POPA ();
+	NULLCHECK (obj);
+	PUSHI (*(jchar *) (obj + INTVAL ()));
+      }
+      NEXT_INSN;
+
+     getfield_resolved_short:
+      SAVE_PC;
+      {
+	char *obj = (char *) POPA ();
+	NULLCHECK (obj);
+	PUSHI (*(jshort *) (obj + INTVAL ()));
+      }
+      NEXT_INSN;
+
+     getfield_resolved_4:
+      SAVE_PC;
+      {
+	char *obj = (char *) POPA ();
+	NULLCHECK (obj);
+	PUSHI (*(jint *) (obj + INTVAL ()));
+      }
+      NEXT_INSN;
+
+     getfield_resolved_8:
+      SAVE_PC;
+      {
+	char *obj = (char *) POPA ();
+	NULLCHECK (obj);
+	PUSHL (*(jlong *) (obj + INTVAL ()));
+      }
+      NEXT_INSN;
+
+     getfield_resolved_obj:
+      SAVE_PC;
+      {
+	char *obj = (char *) POPA ();
+	NULLCHECK (obj);
+	PUSHA (*(jobject *) (obj + INTVAL ()));
+      }
+      NEXT_INSN;
+
      insn_putstatic:
       SAVE_PC;
       {
-	jint fieldref_index = get2u (pc); pc += 2;
+	jint fieldref_index = INTVAL ();
 	_Jv_ResolvePoolEntry (defining_class, fieldref_index);
 	_Jv_Field *field = pool_data[fieldref_index].field;
 
@@ -2006,6 +2524,7 @@
 	  throw_incompatible_class_change_error 
 	    (JvNewStringLatin1 ("field no longer static"));
 
+	void *newinsn = NULL;
 	if (type->isPrimitive ())
 	  {
 	    switch (type->size_in_bytes) 
@@ -2014,6 +2533,7 @@
 		{
 		  jint value = POPI();
 		  *(jbyte*) (field->u.addr) = value;
+		  newinsn = &&putstatic_resolved_1;
 		  break;
 		}
 
@@ -2021,6 +2541,7 @@
 		{
 		  jint value = POPI();
 		  *(jchar*) (field->u.addr) = value;
+		  newinsn = &&putstatic_resolved_2;
 		  break;
 		}
 
@@ -2028,6 +2549,7 @@
 		{
 		  jint value = POPI();
 		  *(jint*) (field->u.addr) = value;
+		  newinsn = &&putstatic_resolved_4;
 		  break;
 		}
 
@@ -2035,6 +2557,7 @@
 		{
 		  jlong value = POPL();
 		  *(jlong*) (field->u.addr) = value;
+		  newinsn = &&putstatic_resolved_8;
 		  break;
 		}
 	      }
@@ -2043,15 +2566,38 @@
 	  {
 	    jobject value = POPA();
 	    *(jobject*) (field->u.addr) = value;
+	    newinsn = &&putstatic_resolved_obj;
 	  }
+
+	pc[-2].insn = newinsn;
+	pc[-1].datum = field->u.addr;
       }
       NEXT_INSN;
 
+     putstatic_resolved_1:
+      *(jbyte *) AVAL () = POPI ();
+      NEXT_INSN;
+
+     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;
 
      insn_putfield:
       SAVE_PC;
       {
-	jint fieldref_index = get2u (pc); pc += 2;
+	jint fieldref_index = INTVAL ();
 	_Jv_ResolvePoolEntry (defining_class, fieldref_index);
 	_Jv_Field *field = pool_data[fieldref_index].field;
 
@@ -2065,6 +2611,7 @@
 	if (field_offset > 0xffff)
 	  throw new java::lang::VirtualMachineError;
 
+	void *newinsn = NULL;
 	if (type->isPrimitive ())
 	  {
 	    switch (type->size_in_bytes) 
@@ -2075,6 +2622,7 @@
 		  jobject obj   = POPA();
 		  NULLCHECK(obj);
 		  *(jbyte*) ((char*)obj + field_offset) = value;
+		  newinsn = &&putfield_resolved_1;
 		  break;
 		}
 
@@ -2084,6 +2632,7 @@
 		  jobject obj   = POPA();
 		  NULLCHECK(obj);
 		  *(jchar*) ((char*)obj + field_offset) = value;
+		  newinsn = &&putfield_resolved_2;
 		  break;
 		}
 
@@ -2093,6 +2642,7 @@
 		  jobject obj   = POPA();
 		  NULLCHECK(obj);
 		  *(jint*) ((char*)obj + field_offset) = value;
+		  newinsn = &&putfield_resolved_4;
 		  break;
 		}
 
@@ -2102,6 +2652,7 @@
 		  jobject obj   = POPA();
 		  NULLCHECK(obj);
 		  *(jlong*) ((char*)obj + field_offset) = value;
+		  newinsn = &&putfield_resolved_8;
 		  break;
 		}
 	      }
@@ -2112,14 +2663,68 @@
 	    jobject obj   = POPA();
 	    NULLCHECK(obj);
 	    *(jobject*) ((char*)obj + field_offset) = value;
+	    newinsn = &&putfield_resolved_obj;
 	  }
+
+	pc[-2].insn = newinsn;
+	pc[-1].int_val = field_offset;
+      }
+      NEXT_INSN;
+
+     putfield_resolved_1:
+      SAVE_PC;
+      {
+	jint val = POPI ();
+	char *obj = (char *) POPA ();
+	NULLCHECK (obj);
+	*(jbyte *) (obj + INTVAL ()) = val;
+      }
+      NEXT_INSN;
+
+     putfield_resolved_2:
+      SAVE_PC;
+      {
+	jint val = POPI ();
+	char *obj = (char *) POPA ();
+	NULLCHECK (obj);
+	*(jchar *) (obj + INTVAL ()) = val;
+      }
+      NEXT_INSN;
+
+     putfield_resolved_4:
+      SAVE_PC;
+      {
+	jint val = POPI ();
+	char *obj = (char *) POPA ();
+	NULLCHECK (obj);
+	*(jint *) (obj + INTVAL ()) = val;
       }
       NEXT_INSN;
 
+     putfield_resolved_8:
+      SAVE_PC;
+      {
+	jlong val = POPL ();
+	char *obj = (char *) POPA ();
+	NULLCHECK (obj);
+	*(jlong *) (obj + INTVAL ()) = val;
+      }
+      NEXT_INSN;
+
+     putfield_resolved_obj:
+      SAVE_PC;
+      {
+	jobject val = POPA ();
+	char *obj = (char *) POPA ();
+	NULLCHECK (obj);
+	*(jobject *) (obj + INTVAL ()) = val;
+      }
+      NEXT_INSN;
+
      insn_invokespecial:
       SAVE_PC;
       {
-	int index = get2u (pc); pc += 2;
+	int index = INTVAL ();
 
 	rmeth = (_Jv_ResolvePoolEntry (defining_class, index)).rmethod;
 
@@ -2128,13 +2733,28 @@
 	NULLCHECK (sp[0].o);
 
 	fun = (void (*)()) rmeth->method->ncode;
+
+	// Rewrite instruction so that we use a faster pre-resolved
+	// method.
+	pc[-2].insn = &&invokespecial_resolved;
+	pc[-1].datum = rmeth;
+      }
+      goto perform_invoke;
+
+     invokespecial_resolved:
+      SAVE_PC;
+      {
+	rmeth = (_Jv_ResolvedMethod *) AVAL ();
+	sp -= rmeth->stack_item_count;
+	NULLCHECK (sp[0].o);
+	fun = (void (*)()) rmeth->method->ncode;
       }
       goto perform_invoke;
 
      insn_invokestatic:
       SAVE_PC;
       {
-	int index = get2u (pc); pc += 2;
+	int index = INTVAL ();
 
 	rmeth = (_Jv_ResolvePoolEntry (defining_class, index)).rmethod;
 
@@ -2142,16 +2762,27 @@
 
 	_Jv_InitClass (rmeth->klass);
 	fun = (void (*)()) rmeth->method->ncode;
+
+	// Rewrite instruction so that we use a faster pre-resolved
+	// method.
+	pc[-2].insn = &&invokestatic_resolved;
+	pc[-1].datum = rmeth;
       }
       goto perform_invoke;
 
-     insn_invokeinterface:
+     invokestatic_resolved:
       SAVE_PC;
       {
-	int index = get2u (pc); pc += 2;
+	rmeth = (_Jv_ResolvedMethod *) AVAL ();
+	sp -= rmeth->stack_item_count;
+	fun = (void (*)()) rmeth->method->ncode;
+      }
+      goto perform_invoke;
 
-	// invokeinterface has two unused bytes...
-	pc += 2;
+     insn_invokeinterface:
+      SAVE_PC;
+      {
+	int index = INTVAL ();
 
 	rmeth = (_Jv_ResolvePoolEntry (defining_class, index)).rmethod;
 
@@ -2165,25 +2796,56 @@
 	  _Jv_LookupInterfaceMethod (rcv->getClass (),
 				     rmeth->method->name,
 				     rmeth->method->signature);
+
+	// Rewrite instruction so that we use a faster pre-resolved
+	// method.
+	pc[-2].insn = &&invokeinterface_resolved;
+	pc[-1].datum = rmeth;
       }
       goto perform_invoke;
 
+     invokeinterface_resolved:
+      SAVE_PC;
+      {
+	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;
+
 
      insn_new:
       SAVE_PC;
       {
-	int index = get2u (pc); pc += 2;
+	int index = INTVAL ();
 	jclass klass = (_Jv_ResolvePoolEntry (defining_class, index)).clazz;
 	_Jv_InitClass (klass);
 	jobject res = _Jv_AllocObject (klass, klass->size_in_bytes);
 	PUSHA (res);
+
+	pc[-2].insn = &&new_resolved;
+	pc[-1].datum = klass;
       }
       NEXT_INSN;
 
+     new_resolved:
+      SAVE_PC;
+      {
+	jclass klass = (jclass) AVAL ();
+	jobject res = _Jv_AllocObject (klass, klass->size_in_bytes);
+	PUSHA (res);
+      }
+      NEXT_INSN;
+
      insn_newarray:
       SAVE_PC;
       {
-	int atype = get1u (pc++);
+	int atype = INTVAL ();
 	int size  = POPI();
 	jobject result = _Jv_NewArray (atype, size);
 	PUSHA (result);
@@ -2193,12 +2855,25 @@
      insn_anewarray:
       SAVE_PC;
       {
-	int index = get2u (pc); pc += 2;
+	int index = INTVAL ();
 	jclass klass = (_Jv_ResolvePoolEntry (defining_class, index)).clazz;
 	int size  = POPI();
 	_Jv_InitClass (klass);
 	jobject result = _Jv_NewObjectArray (size, klass, 0);
 	PUSHA (result);
+
+	pc[-2].insn = &&anewarray_resolved;
+	pc[-1].datum = klass;
+      }
+      NEXT_INSN;
+
+     anewarray_resolved:
+      SAVE_PC;
+      {
+	jclass klass = (jclass) AVAL ();
+	int size = POPI ();
+	jobject result = _Jv_NewObjectArray (size, klass, 0);
+	PUSHA (result);
       }
       NEXT_INSN;
 
@@ -2222,28 +2897,52 @@
       SAVE_PC;
       {
 	jobject value = POPA();
-	jint index = get2u (pc); pc += 2;
+	jint index = INTVAL ();
 	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);
+
+	pc[-2].insn = &&checkcast_resolved;
+	pc[-1].datum = to;
       }
       NEXT_INSN;
 
+     checkcast_resolved:
+      SAVE_PC;
+      {
+	jobject value = POPA ();
+	jclass to = (jclass) AVAL ();
+	if (value != NULL && ! to->isInstance (value))
+	  throw new java::lang::ClassCastException (to->getName());
+	PUSHA (value);
+      }
+      NEXT_INSN;
+
      insn_instanceof:
       SAVE_PC;
       {
 	jobject value = POPA();
-	jint index = get2u (pc); pc += 2;
+	jint index = INTVAL ();
 	jclass to = (_Jv_ResolvePoolEntry (defining_class, index)).clazz;
 	PUSHI (to->isInstance (value));
+
+	pc[-2].insn = &&instanceof_resolved;
+	pc[-1].datum = to;
       }
       NEXT_INSN;
 
+     instanceof_resolved:
+      SAVE_PC;
+      {
+	jobject value = POPA ();
+	jclass to = (jclass) AVAL ();
+	PUSHI (to->isInstance (value));
+      }
+      NEXT_INSN;
+
      insn_monitorenter:
       SAVE_PC;
       {
@@ -2264,91 +2963,25 @@
 
      insn_ifnull:
       {
-	unsigned char* base_pc = pc-1;
-	jint offset = get2s (pc); pc += 2;
 	jobject val = POPA();
 	if (val == NULL)
-	  pc = base_pc+offset;
+	  pc = (insn_slot *) pc->datum;
       }
       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;
+	  pc = (insn_slot *) pc->datum;
       }
       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;
+	int kind_index = INTVAL ();
+	int dim        = INTVAL ();
 
 	jclass type    
 	  = (_Jv_ResolvePoolEntry (defining_class, kind_index)).clazz;
@@ -2363,23 +2996,6 @@
 	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;
 }
Index: verify.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/verify.cc,v
retrieving revision 1.38
diff -u -r1.38 verify.cc
--- verify.cc 2002/02/15 06:55:42 1.38
+++ verify.cc 2002/02/17 19:32:19
@@ -1815,18 +1815,18 @@
     // 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;
       }
   }
 
@@ -2118,12 +2118,12 @@
 	// 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);
 	      }
 	  }
 
Index: include/java-interp.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/include/java-interp.h,v
retrieving revision 1.16
diff -u -r1.16 java-interp.h
--- include/java-interp.h 2001/11/26 06:40:05 1.16
+++ include/java-interp.h 2002/02/17 19:32:20
@@ -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.
 
@@ -51,12 +51,21 @@
 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 +101,8 @@
 
   _Jv_ushort       exc_count;
 
+  void *prepared;
+
   unsigned char* bytecode () 
   {
     return 
@@ -116,6 +127,7 @@
   // 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*);
@@ -140,7 +152,7 @@
 class _Jv_InterpMethodInvocation {
   _Jv_InterpMethod *running;
   _Jv_word         *sp;
-  unsigned char    *pc;
+  void             *pc;
   _Jv_word          state[0];
 
   _Jv_word*         stack_base () { return &state[0]; }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]