OSDN Git Service

PR middle-end/30391
[pf3gnuchains/gcc-fork.git] / libjava / interpret.cc
index 1c4e21e..dbd5323 100644 (file)
@@ -1,6 +1,6 @@
 // interpret.cc - Code for the interpreter
 
-/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation
+/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation
 
    This file is part of libgcj.
 
@@ -37,7 +37,13 @@ details.  */
 #include <execution.h>
 #include <java/lang/reflect/Modifier.h>
 
+#include <jvmti.h>
+#include "jvmti-int.h"
+
 #include <gnu/classpath/jdwp/Jdwp.h>
+#include <gnu/gcj/jvmti/Breakpoint.h>
+#include <gnu/gcj/jvmti/BreakpointManager.h>
+#include <gnu/gcj/jvmti/ExceptionEvent.h>
 
 #ifdef INTERPRETER
 
@@ -75,6 +81,18 @@ _Jv_InitInterpreter()
 void _Jv_InitInterpreter() {}
 #endif
 
+// The breakpoint instruction. For the direct threaded case,
+// _Jv_InterpMethod::compile will initialize breakpoint_insn
+// the first time it is called.
+#ifdef DIRECT_THREADED
+insn_slot _Jv_InterpMethod::bp_insn_slot;
+pc_t _Jv_InterpMethod::breakpoint_insn = NULL;
+#else
+unsigned char _Jv_InterpMethod::bp_insn_opcode
+  = static_cast<unsigned char> (op_breakpoint);
+pc_t _Jv_InterpMethod::breakpoint_insn = &_Jv_InterpMethod::bp_insn_opcode;
+#endif
+
 extern "C" double __ieee754_fmod (double,double);
 
 static inline void dupx (_Jv_word *sp, int n, int x)
@@ -154,54 +172,56 @@ convert (FROM val, TO min, TO max)
 # define LOADD(I)  LOADL(I)
 #endif
 
-#define STOREA(I)              \
-do {                                   \
-DEBUG_LOCALS_INSN(I, 'o');             \
-locals[I].o = (--sp)->o;               \
-} while(0)
-#define STOREI(I)              \
-do {                                   \
-DEBUG_LOCALS_INSN (I, 'i');            \
-locals[I].i = (--sp)->i;               \
-} while(0)
-#define STOREF(I)              \
-do {                                   \
-DEBUG_LOCALS_INSN (I, 'f');            \
-locals[I].f = (--sp)->f;               \
-} while(0)
+#define STOREA(I)                              \
+  do {                                         \
+    DEBUG_LOCALS_INSN (I, 'o');                        \
+    locals[I].o = (--sp)->o;                   \
+  } while (0)
+#define STOREI(I)                              \
+  do {                                         \
+    DEBUG_LOCALS_INSN (I, 'i');                        \
+    locals[I].i = (--sp)->i;                   \
+  } while (0)
+#define STOREF(I)                              \
+  do {                                         \
+    DEBUG_LOCALS_INSN (I, 'f');                        \
+    locals[I].f = (--sp)->f;                   \
+  } while (0)
 #if SIZEOF_VOID_P == 8
-# define STOREL(I)                     \
-do {                                                   \
-DEBUG_LOCALS_INSN (I, 'l');                    \
-(sp -= 2, locals[I].l = sp->l);                \
-} while(0)
+# define STOREL(I)                             \
+  do {                                         \
+    DEBUG_LOCALS_INSN (I, 'l');                        \
+    (sp -= 2, locals[I].l = sp->l);            \
+  } while (0)
 # define STORED(I)                             \
-do {                                                   \
-DEBUG_LOCALS_INSN (I, 'd');                    \
-(sp -= 2, locals[I].d = sp->d);                \
-} while(0)
+  do {                                         \
+    DEBUG_LOCALS_INSN (I, 'd');                        \
+    (sp -= 2, locals[I].d = sp->d);            \
+  } while (0)
 
 #else
-# define STOREL(I)             \
-do { DEBUG_LOCALS_INSN(I, 'l');        \
-        jint __idx = (I);      \
-     locals[__idx+1].ia[0] = (--sp)->ia[0]; \
-     locals[__idx].ia[0] = (--sp)->ia[0];      \
-   } while (0)
-# define STORED(I)             \
-do { DEBUG_LOCALS_INSN(I, 'd');        \
-        jint __idx = (I);      \
-     locals[__idx+1].ia[0] = (--sp)->ia[0]; \
-     locals[__idx].ia[0] = (--sp)->ia[0];      \
-   } while (0)
+# define STOREL(I)                             \
+  do {                                         \
+    DEBUG_LOCALS_INSN (I, 'l');                        \
+    jint __idx = (I);                          \
+    locals[__idx+1].ia[0] = (--sp)->ia[0];     \
+    locals[__idx].ia[0] = (--sp)->ia[0];       \
+  } while (0)
+# define STORED(I)                             \
+  do {                                         \
+    DEBUG_LOCALS_INSN(I, 'd');                 \
+    jint __idx = (I);                          \
+    locals[__idx+1].ia[0] = (--sp)->ia[0];     \
+    locals[__idx].ia[0] = (--sp)->ia[0];       \
+  } while (0)
 #endif
 
 #define PEEKI(I)  (locals+(I))->i
 #define PEEKA(I)  (locals+(I))->o
 
-#define POKEI(I,V)     \
-DEBUG_LOCALS_INSN(I,'i'); \
-((locals+(I))->i = (V))
+#define POKEI(I,V)                             \
+  DEBUG_LOCALS_INSN(I,'i');                    \
+  ((locals+(I))->i = (V))
 
 
 #define BINOPI(OP) { \
@@ -228,23 +248,33 @@ DEBUG_LOCALS_INSN(I,'i'); \
    PUSHD(value1 OP value2); \
 }
 
-static inline jint get1s(unsigned char* loc) {
+static inline jint
+get1s (unsigned char* loc)
+{
   return *(signed char*)loc;
 }
 
-static inline jint get1u(unsigned char* loc) {
+static inline jint
+get1u (unsigned char* loc)
+{
   return *loc;
 }
 
-static inline jint get2s(unsigned char* loc) {
+static inline jint
+get2s(unsigned char* loc)
+{
   return (((jint)*(signed char*)loc) << 8) | ((jint)*(loc+1));
 }
 
-static inline jint get2u(unsigned char* loc) {
+static inline jint
+get2u (unsigned char* loc)
+{
   return (((jint)(*loc)) << 8) | ((jint)*(loc+1));
 }
 
-static jint get4(unsigned char* loc) {
+static jint
+get4 (unsigned char* loc)
+{
   return (((jint)(loc[0])) << 24) 
        | (((jint)(loc[1])) << 16) 
        | (((jint)(loc[2])) << 8) 
@@ -267,23 +297,26 @@ static jint get4(unsigned char* loc) {
 #ifdef HANDLE_SEGV
 #define NULLARRAYCHECK(X) SAVE_PC()
 #else
-#define NULLARRAYCHECK(X) \
-  do { SAVE_PC(); if ((X)==NULL) { throw_null_pointer_exception (); } } while (0)
+#define NULLARRAYCHECK(X)                                      \
+  do                                                           \
+    {                                                          \
+      SAVE_PC();                                               \
+      if ((X) == NULL) { throw_null_pointer_exception (); }    \
+    } while (0)
 #endif
 
-#define ARRAYBOUNDSCHECK(array, index)                                       \
-  do                                                                         \
-    {                                                                        \
-      if (((unsigned) index) >= (unsigned) (array->length))                  \
-       _Jv_ThrowBadArrayIndex (index);                                       \
-    }                                                                        \
-  while (0)
+#define ARRAYBOUNDSCHECK(array, index)                         \
+  do                                                           \
+    {                                                          \
+      if (((unsigned) index) >= (unsigned) (array->length))    \
+       _Jv_ThrowBadArrayIndex (index);                         \
+    } while (0)
 
 void
 _Jv_InterpMethod::run_normal (ffi_cif *,
-                             voidret,
-                             ffi_raw * args,
-                             void__this)
+                             void *ret,
+                             ffi_raw *args,
+                             void *__this)
 {
   _Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this;
   run (ret, args, _this);
@@ -291,9 +324,9 @@ _Jv_InterpMethod::run_normal (ffi_cif *,
 
 void
 _Jv_InterpMethod::run_normal_debug (ffi_cif *,
-                             void* ret,
-                             ffi_raw * args,
-                             void* __this)
+                                   void *ret,
+                                   ffi_raw *args,
+                                   void *__this)
 {
   _Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this;
   run_debug (ret, args, _this);
@@ -301,9 +334,9 @@ _Jv_InterpMethod::run_normal_debug (ffi_cif *,
 
 void
 _Jv_InterpMethod::run_synch_object (ffi_cif *,
-                                   voidret,
-                                   ffi_raw * args,
-                                   void__this)
+                                   void *ret,
+                                   ffi_raw *args,
+                                   void *__this)
 {
   _Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this;
 
@@ -315,9 +348,9 @@ _Jv_InterpMethod::run_synch_object (ffi_cif *,
 
 void
 _Jv_InterpMethod::run_synch_object_debug (ffi_cif *,
-                                   void* ret,
-                                   ffi_raw * args,
-                                   void* __this)
+                                         void *ret,
+                                         ffi_raw *args,
+                                         void *__this)
 {
   _Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this;
 
@@ -329,9 +362,9 @@ _Jv_InterpMethod::run_synch_object_debug (ffi_cif *,
 
 void
 _Jv_InterpMethod::run_class (ffi_cif *,
-                            voidret,
-                            ffi_raw * args,
-                            void__this)
+                            void *ret,
+                            ffi_raw *args,
+                            void *__this)
 {
   _Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this;
   _Jv_InitClass (_this->defining_class);
@@ -340,9 +373,9 @@ _Jv_InterpMethod::run_class (ffi_cif *,
 
 void
 _Jv_InterpMethod::run_class_debug (ffi_cif *,
-                            void* ret,
-                            ffi_raw * args,
-                            void* __this)
+                                  void *ret,
+                                  ffi_raw *args,
+                                  void *__this)
 {
   _Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this;
   _Jv_InitClass (_this->defining_class);
@@ -351,9 +384,9 @@ _Jv_InterpMethod::run_class_debug (ffi_cif *,
 
 void
 _Jv_InterpMethod::run_synch_class (ffi_cif *,
-                                  voidret,
-                                  ffi_raw * args,
-                                  void__this)
+                                  void *ret,
+                                  ffi_raw *args,
+                                  void *__this)
 {
   _Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this;
 
@@ -366,9 +399,9 @@ _Jv_InterpMethod::run_synch_class (ffi_cif *,
 
 void
 _Jv_InterpMethod::run_synch_class_debug (ffi_cif *,
-                                  void* ret,
-                                  ffi_raw * args,
-                                  void* __this)
+                                        void *ret,
+                                        ffi_raw *args,
+                                        void *__this)
 {
   _Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this;
 
@@ -844,6 +877,7 @@ _Jv_InterpMethod::compile (const void * const *insn_targets)
            case op_getstatic_4:
            case op_getstatic_8:
            case op_getstatic_a:
+           case op_breakpoint:
            default:
              // Fail somehow.
              break;
@@ -879,6 +913,12 @@ _Jv_InterpMethod::compile (const void * const *insn_targets)
     }  
 
   prepared = insns;
+
+  if (breakpoint_insn == NULL)
+    {
+      bp_insn_slot.insn = const_cast<void *> (insn_targets[op_breakpoint]);
+      breakpoint_insn = &bp_insn_slot;
+    }
 }
 #endif /* DIRECT_THREADED */
 
@@ -897,15 +937,6 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args, _Jv_InterpMethod *meth)
 void
 _Jv_InterpMethod::run_debug (void *retp, ffi_raw *args, _Jv_InterpMethod *meth)
 {
-/* Used to keep track of local variable type
- * 
- * Possible Types:
- * o object
- * i integer
- * f float
- * l long 
- * d double 
- */
 #define DEBUG
 #undef DEBUG_LOCALS_INSN
 #define DEBUG_LOCALS_INSN(s, t) do {} while(0)
@@ -1160,13 +1191,13 @@ _Jv_count_arguments (_Jv_Utf8Const *signature,
  * caller.
  */
 
-static int 
-init_cif (_Jv_Utf8Const* signature,
-         int arg_count,
-         jboolean staticp,
-         ffi_cif *cif,
-         ffi_type **arg_types,
-         ffi_type **rtype_p)
+int 
+_Jv_init_cif (_Jv_Utf8Const* signature,
+             int arg_count,
+             jboolean staticp,
+             ffi_cif *cif,
+             ffi_type **arg_types,
+             ffi_type **rtype_p)
 {
   unsigned char *ptr = (unsigned char*) signature->chars();
 
@@ -1250,12 +1281,12 @@ _Jv_InterpMethod::ncode ()
     (ncode_closure*)_Jv_AllocBytes (sizeof (ncode_closure)
                                        + arg_count * sizeof (ffi_type*));
 
-  init_cif (self->signature,
-           arg_count,
-           staticp,
-           &closure->cif,
-           &closure->arg_types[0],
-           NULL);
+  _Jv_init_cif (self->signature,
+               arg_count,
+               staticp,
+               &closure->cif,
+               &closure->arg_types[0],
+               NULL);
 
   ffi_closure_fun fun;
 
@@ -1267,34 +1298,34 @@ _Jv_InterpMethod::ncode ()
     {
       if (staticp)
         {
-        if (::gnu::classpath::jdwp::Jdwp::isDebugging)
-                 fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_class_debug;
-               else
-                 fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_class;
+         if (JVMTI::enabled)
+           fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_class_debug;
+         else
+           fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_class;
         }
       else
         {
-             if (::gnu::classpath::jdwp::Jdwp::isDebugging)
-                   fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_object_debug;
-                 else
-                       fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_object;
-        } 
+         if (JVMTI::enabled)
+           fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_object_debug;
+         else
+           fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_object;
+        }
     }
   else
     {
       if (staticp)
         {
-             if (::gnu::classpath::jdwp::Jdwp::isDebugging)
-                   fun = (ffi_closure_fun)&_Jv_InterpMethod::run_class_debug;
-                 else
-                   fun = (ffi_closure_fun)&_Jv_InterpMethod::run_class;
+         if (JVMTI::enabled)
+           fun = (ffi_closure_fun)&_Jv_InterpMethod::run_class_debug;
+         else
+           fun = (ffi_closure_fun)&_Jv_InterpMethod::run_class;
         }
       else
         {
-             if (::gnu::classpath::jdwp::Jdwp::isDebugging)
-                   fun = (ffi_closure_fun)&_Jv_InterpMethod::run_normal_debug;
-                 else
-                   fun = (ffi_closure_fun)&_Jv_InterpMethod::run_normal;
+         if (JVMTI::enabled)
+           fun = (ffi_closure_fun)&_Jv_InterpMethod::run_normal_debug;
+         else
+           fun = (ffi_closure_fun)&_Jv_InterpMethod::run_normal;
         }
     }
 
@@ -1336,6 +1367,51 @@ _Jv_InterpMethod::insn_index (pc_t pc)
   return -1;
 }
 
+// Method to check if an exception is caught at some location in a method
+// (meth).  Returns true if this method (meth) contains a catch block for the
+// exception (ex). False otherwise.  If there is a catch block, it sets the pc
+// to the location of the beginning of the catch block.
+jboolean
+_Jv_InterpMethod::check_handler (pc_t *pc, _Jv_InterpMethod *meth,
+                                java::lang::Throwable *ex)
+{
+#ifdef DIRECT_THREADED
+  void *logical_pc = (void *) ((insn_slot *) (*pc) - 1);
+#else
+  int logical_pc = (*pc) - 1 - meth->bytecode ();
+#endif
+  _Jv_InterpException *exc = meth->exceptions ();
+  jclass exc_class = ex->getClass ();
+
+  for (int i = 0; i < meth->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_Linker::resolve_pool_entry (meth->defining_class,
+                                                                             ex$
+#endif /* DIRECT_THREADED */
+              if (handler == NULL || handler->isAssignableFrom (exc_class))
+                {
+#ifdef DIRECT_THREADED
+                  (*pc) = (insn_slot *) exc[i].handler_pc.p;
+#else
+                  (*pc) = meth->bytecode () + exc[i].handler_pc.i;
+#endif /* DIRECT_THREADED */
+                  return true;
+                }
+          }
+      }
+  return false;
+}
+
+
 void
 _Jv_InterpMethod::get_line_table (jlong& start, jlong& end,
                                  jintArray& line_numbers,
@@ -1384,6 +1460,76 @@ _Jv_InterpMethod::get_line_table (jlong& start, jlong& end,
 #endif // !DIRECT_THREADED
 }
 
+int 
+_Jv_InterpMethod::get_local_var_table (char **name, char **sig, 
+                                       char **generic_sig, jlong *startloc,
+                                       jint *length, jint *slot, 
+                                       int table_slot)
+{      
+  if (local_var_table == NULL)
+    return -2;
+  if (table_slot >= local_var_table_len)
+    return -1;
+  else
+    {
+      *name = local_var_table[table_slot].name;
+      *sig = local_var_table[table_slot].descriptor;
+      *generic_sig = local_var_table[table_slot].descriptor;
+
+      *startloc = static_cast<jlong> 
+                    (local_var_table[table_slot].bytecode_start_pc);
+      *length = static_cast<jint> (local_var_table[table_slot].length);
+      *slot = static_cast<jint> (local_var_table[table_slot].slot);
+    }
+  return local_var_table_len - table_slot -1;
+}
+
+pc_t
+_Jv_InterpMethod::install_break (jlong index)
+{
+  return set_insn (index, breakpoint_insn);
+}
+
+pc_t
+_Jv_InterpMethod::get_insn (jlong index)
+{
+  pc_t code;
+
+#ifdef DIRECT_THREADED
+  if (index >= number_insn_slots || index < 0)
+    return NULL;
+
+  code = prepared;
+#else // !DIRECT_THREADED
+  if (index >= code_length || index < 0)
+    return NULL;
+
+  code = reinterpret_cast<pc_t> (bytecode ());
+#endif // !DIRECT_THREADED
+
+  return &code[index];
+}
+
+pc_t
+_Jv_InterpMethod::set_insn (jlong index, pc_t insn)
+{
+#ifdef DIRECT_THREADED
+  if (index >= number_insn_slots || index < 0)
+    return NULL;
+
+  pc_t code = prepared;
+  code[index].insn = insn->insn;
+#else // !DIRECT_THREADED
+  if (index >= code_length || index < 0)
+    return NULL;
+
+  pc_t code = reinterpret_cast<pc_t> (bytecode ());
+  code[index] = *insn;
+#endif // !DIRECT_THREADED
+
+  return &code[index];
+}
+
 void *
 _Jv_JNIMethod::ncode ()
 {
@@ -1400,12 +1546,12 @@ _Jv_JNIMethod::ncode ()
                                    + arg_count * sizeof (ffi_type*));
 
   ffi_type *rtype;
-  init_cif (self->signature,
-           arg_count,
-           staticp,
-           &closure->cif,
-           &closure->arg_types[0],
-           &rtype);
+  _Jv_init_cif (self->signature,
+               arg_count,
+               staticp,
+               &closure->cif,
+               &closure->arg_types[0],
+               &rtype);
 
   ffi_closure_fun fun;
 
@@ -1567,12 +1713,12 @@ _Jv_InterpreterEngine::do_resolve_method (_Jv_Method *method, jclass klass,
                    + arg_count*sizeof (ffi_type*));
 
   result->stack_item_count
-    = init_cif (method->signature,
-               arg_count,
-               staticp,
-               &result->cif,
-               &result->arg_types[0],
-               NULL);
+    = _Jv_init_cif (method->signature,
+                   arg_count,
+                   staticp,
+                   &result->cif,
+                   &result->arg_types[0],
+                   NULL);
 
   result->method              = method;
   result->klass               = klass;
@@ -1604,7 +1750,12 @@ void
 _Jv_CompileMethod (_Jv_InterpMethod* method)
 {
   if (method->prepared == NULL)
-    _Jv_InterpMethod::run (NULL, NULL, method);
+    {
+      if (JVMTI::enabled)
+       _Jv_InterpMethod::run_debug (NULL, NULL, method);
+      else
+      _Jv_InterpMethod::run (NULL, NULL, method);
+    }
 }
 #endif // DIRECT_THREADED