OSDN Git Service

2002-04-29 Gerhard Tonn <GerhardTonn@swol.de>
[pf3gnuchains/gcc-fork.git] / libjava / interpret.cc
index 069abdb..4db9dca 100644 (file)
@@ -1,6 +1,6 @@
 // interpret.cc - Code for the interpreter
 
-/* Copyright (C) 1999, 2000  Free Software Foundation
+/* Copyright (C) 1999, 2000, 2001 , 2002 Free Software Foundation
 
    This file is part of libgcj.
 
@@ -21,6 +21,7 @@ details.  */
 #include <java/lang/System.h>
 #include <java/lang/String.h>
 #include <java/lang/Integer.h>
+#include <java/lang/Long.h>
 #include <java/lang/StringBuffer.h>
 #include <java/lang/Class.h>
 #include <java/lang/reflect/Modifier.h>
@@ -35,12 +36,9 @@ details.  */
 
 #ifdef INTERPRETER
 
-#include <alloca.h>
+#include <stdlib.h>
 
-#define ClassError _CL_Q34java4lang5Error
-extern java::lang::Class ClassError;
-
-static _Jv_Utf8Const *init_name = _Jv_makeUtf8Const ("<init>", 6);
+using namespace gcj;
 
 static void throw_internal_error (char *msg)
   __attribute__ ((__noreturn__));
@@ -51,7 +49,7 @@ static void throw_null_pointer_exception ()
   __attribute__ ((__noreturn__));
 #endif
 
-extern "C" double __ieee754_fmod __P((double,double));
+extern "C" double __ieee754_fmod (double,double);
 
 static inline void dupx (_Jv_word *sp, int n, int x)
 {
@@ -70,6 +68,22 @@ static inline void dupx (_Jv_word *sp, int n, int x)
   
 };
 
+// Used to convert from floating types to integral types.
+template<typename TO, typename FROM>
+static inline TO
+convert (FROM val, TO min, TO max)
+{
+  TO ret;
+  if (val >= (FROM) max)
+    ret = max;
+  else if (val <= (FROM) min)
+    ret = min;
+  else if (val != val)
+    ret = 0;
+  else
+    ret = (TO) val;
+  return ret;
+}
 
 #define PUSHA(V)  (sp++)->o = (V)
 #define PUSHI(V)  (sp++)->i = (V)
@@ -185,11 +199,21 @@ static jint get4(unsigned char* loc) {
 
 #ifdef HANDLE_SEGV
 #define NULLCHECK(X) 
+#define NULLARRAYCHECK(X) do { SAVE_PC; } while (0)
 #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)
 #endif
 
+#define ARRAYBOUNDSCHECK(array, index)                                       \
+  do                                                                         \
+    {                                                                        \
+      if (((unsigned) index) >= (unsigned) (array->length))                  \
+       _Jv_ThrowBadArrayIndex (index);                                       \
+    }                                                                        \
+  while (0)
 
 // this method starts the actual running of the method.  It is inlined
 // in three different variants in the static methods run_normal,
@@ -294,10 +318,14 @@ _Jv_InterpMethod::run (ffi_cif* cif,
   return ex;
 }
 
+#define SAVE_PC   inv->pc = pc
+
 bool _Jv_InterpMethod::find_exception (jobject ex,
                                       _Jv_InterpMethodInvocation *inv)
 {
-  int logical_pc = inv->pc - bytecode ();
+  // 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 ();
 
@@ -336,11 +364,11 @@ void _Jv_InterpMethod::run_normal (ffi_cif* cif,
   // "run" ro be inlined.  Otherwise gcc will ignore the inline directive.
   int storage_size = _this->max_stack+_this->max_locals;
   _Jv_InterpMethodInvocation* inv = (_Jv_InterpMethodInvocation*) 
-    alloca (sizeof (_Jv_InterpMethodInvocation)
-           + storage_size * sizeof (_Jv_word));
+    __builtin_alloca (sizeof (_Jv_InterpMethodInvocation)
+                     + storage_size * sizeof (_Jv_word));
 
   jobject ex = _this->run (cif, ret, args, inv);
-  if (ex != 0) _Jv_Throw (ex);
+  if (ex != 0) throw static_cast<jthrowable>(ex);
 }
 
 void _Jv_InterpMethod::run_synch_object (ffi_cif* cif,
@@ -353,14 +381,14 @@ void _Jv_InterpMethod::run_synch_object (ffi_cif* cif,
 
   int storage_size = _this->max_stack+_this->max_locals;
   _Jv_InterpMethodInvocation* inv = (_Jv_InterpMethodInvocation*) 
-    alloca (sizeof (_Jv_InterpMethodInvocation)
-           + storage_size * sizeof (_Jv_word));
+    __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) _Jv_Throw (ex);
+  if (ex != 0) throw static_cast<jthrowable>(ex);
 }
 
 void _Jv_InterpMethod::run_synch_class (ffi_cif* cif,
@@ -373,14 +401,14 @@ void _Jv_InterpMethod::run_synch_class (ffi_cif* cif,
 
   int storage_size = _this->max_stack+_this->max_locals;
   _Jv_InterpMethodInvocation* inv = (_Jv_InterpMethodInvocation*) 
-    alloca (sizeof (_Jv_InterpMethodInvocation)
-           + storage_size * sizeof (_Jv_word));
+    __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) _Jv_Throw (ex);
+  if (ex != 0) throw static_cast<jthrowable>(ex);
 }
 
 /*
@@ -406,7 +434,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv)
   _Jv_word *pool_data   = defining_class->constants.data;
   
   /* these two are used in the invokeXXX instructions */
-  void (*fun)(...);
+  void (*fun)();
   _Jv_ResolvedMethod* rmeth;
 
 #define INSN_LABEL(op) &&insn_##op
@@ -600,7 +628,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv)
     INSN_LABEL(invokespecial),
     INSN_LABEL(invokestatic),
     INSN_LABEL(invokeinterface),
-    0, /* op_xxxunusedxxx1, */
+    0, /* Unused.  */
     INSN_LABEL(new),
     INSN_LABEL(newarray),
     INSN_LABEL(anewarray),
@@ -618,8 +646,6 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv)
     INSN_LABEL(jsr_w),
   };
 
-#define SAVE_PC   inv->pc = pc-1
-
   /* If the macro INLINE_SWITCH is not defined, then the main loop
      operates as one big (normal) switch statement.  If it is defined,
      then the case selection is performed `inline' in the end of the
@@ -678,19 +704,23 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv)
        rmeth = (_Jv_ResolvePoolEntry (defining_class, index)).rmethod;
 
        sp -= rmeth->stack_item_count;
-       NULLCHECK(sp[0]);
+       // 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;
+           fun = (void (*)()) rmeth->method->ncode;
          }
        else
          {
            jobject rcv = sp[0].o;
            _Jv_VTable *table = *(_Jv_VTable**)rcv;
-           fun = (void (*) (...))table->method[rmeth->vtable_index];
+           fun = (void (*)()) table->get_method(rmeth->vtable_index);
          }
       }
       goto perform_invoke;
@@ -952,113 +982,81 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv)
       NEXT_INSN;
 
      insn_iaload:
-      SAVE_PC;
       {
        jint index = POPI();
        jintArray arr = (jintArray) POPA();
-       NULLCHECK (arr);
-       if (index < 0 || index >= arr->length)
-         {
-           _Jv_ThrowBadArrayIndex (index);
-         }
+       NULLARRAYCHECK (arr);
+       ARRAYBOUNDSCHECK (arr, index);
        PUSHI( elements(arr)[index] );
       }
       NEXT_INSN;
 
      insn_laload:
-      SAVE_PC;
       {
        jint index = POPI();
        jlongArray arr = (jlongArray) POPA();
-       NULLCHECK (arr);
-       if (index < 0 || index >= arr->length)
-         {
-           _Jv_ThrowBadArrayIndex (index);
-         }
+       NULLARRAYCHECK (arr);
+       ARRAYBOUNDSCHECK (arr, index);
        PUSHL( elements(arr)[index] );
       }
       NEXT_INSN;
 
      insn_faload:
-      SAVE_PC;
       {
        jint index = POPI();
        jfloatArray arr = (jfloatArray) POPA();
-       NULLCHECK (arr);
-       if (index < 0 || index >= arr->length)
-         {
-           _Jv_ThrowBadArrayIndex (index);
-         }
+       NULLARRAYCHECK (arr);
+       ARRAYBOUNDSCHECK (arr, index);
        PUSHF( elements(arr)[index] );
       }
       NEXT_INSN;
 
      insn_daload:
-      SAVE_PC;
       {
        jint index = POPI();
        jdoubleArray arr = (jdoubleArray) POPA();
-       NULLCHECK (arr);
-       if (index < 0 || index >= arr->length)
-         {
-           _Jv_ThrowBadArrayIndex (index);
-         }
+       NULLARRAYCHECK (arr);
+       ARRAYBOUNDSCHECK (arr, index);
        PUSHD( elements(arr)[index] );
       }
       NEXT_INSN;
 
      insn_aaload:
-      SAVE_PC;
       {
        jint index = POPI();
        jobjectArray arr = (jobjectArray) POPA();
-       NULLCHECK (arr);
-       if (index < 0 || index >= arr->length)
-         {
-           _Jv_ThrowBadArrayIndex (index);
-         }
+       NULLARRAYCHECK (arr);
+       ARRAYBOUNDSCHECK (arr, index);
        PUSHA( elements(arr)[index] );
       }
       NEXT_INSN;
 
      insn_baload:
-      SAVE_PC;
       {
        jint index = POPI();
        jbyteArray arr = (jbyteArray) POPA();
-       NULLCHECK (arr);
-       if (index < 0 || index >= arr->length)
-         {
-           _Jv_ThrowBadArrayIndex (index);
-         }
+       NULLARRAYCHECK (arr);
+       ARRAYBOUNDSCHECK (arr, index);
        PUSHI( elements(arr)[index] );
       }
       NEXT_INSN;
 
      insn_caload:
-      SAVE_PC;
       {
        jint index = POPI();
        jcharArray arr = (jcharArray) POPA();
-       NULLCHECK (arr);
-       if (index < 0 || index >= arr->length)
-         {
-           _Jv_ThrowBadArrayIndex (index);
-         }
+       NULLARRAYCHECK (arr);
+       ARRAYBOUNDSCHECK (arr, index);
        PUSHI( elements(arr)[index] );
       }
       NEXT_INSN;
 
      insn_saload:
-      SAVE_PC;
       {
        jint index = POPI();
        jshortArray arr = (jshortArray) POPA();
-       NULLCHECK (arr);
-       if (index < 0 || index >= arr->length)
-         {
-           _Jv_ThrowBadArrayIndex (index);
-         }
+       NULLARRAYCHECK (arr);
+       ARRAYBOUNDSCHECK (arr, index);
        PUSHI( elements(arr)[index] );
       }
       NEXT_INSN;
@@ -1164,122 +1162,90 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv)
       NEXT_INSN;
 
      insn_iastore:
-      SAVE_PC;
       {
        jint value = POPI();
        jint index  = POPI();
        jintArray arr = (jintArray) POPA();
-       NULLCHECK (arr);
-       if (index < 0 || index >= arr->length)
-         {
-           _Jv_ThrowBadArrayIndex (index);
-         }
+       NULLARRAYCHECK (arr);
+       ARRAYBOUNDSCHECK (arr, index);
        elements(arr)[index] = value;
       }
       NEXT_INSN;
 
      insn_lastore:
-      SAVE_PC;
       {
        jlong value = POPL();
        jint index  = POPI();
        jlongArray arr = (jlongArray) POPA();
-       NULLCHECK (arr);
-       if (index < 0 || index >= arr->length)
-         {
-           _Jv_ThrowBadArrayIndex (index);
-         }
+       NULLARRAYCHECK (arr);
+       ARRAYBOUNDSCHECK (arr, index);
        elements(arr)[index] = value;
       }
       NEXT_INSN;
 
      insn_fastore:
-      SAVE_PC;
       {
        jfloat value = POPF();
        jint index  = POPI();
        jfloatArray arr = (jfloatArray) POPA();
-       NULLCHECK (arr);
-       if (index < 0 || index >= arr->length)
-         {
-           _Jv_ThrowBadArrayIndex (index);
-         }
+       NULLARRAYCHECK (arr);
+       ARRAYBOUNDSCHECK (arr, index);
        elements(arr)[index] = value;
       }
       NEXT_INSN;
 
      insn_dastore:
-      SAVE_PC;
       {
        jdouble value = POPD();
        jint index  = POPI();
        jdoubleArray arr = (jdoubleArray) POPA();
-       NULLCHECK (arr);
-       if (index < 0 || index >= arr->length)
-         {
-           _Jv_ThrowBadArrayIndex (index);
-         }
+       NULLARRAYCHECK (arr);
+       ARRAYBOUNDSCHECK (arr, index);
        elements(arr)[index] = value;
       }
       NEXT_INSN;
 
      insn_aastore:
-      SAVE_PC;
       {
        jobject value = POPA();
        jint index  = POPI();
        jobjectArray arr = (jobjectArray) POPA();
-       NULLCHECK (arr);
-       if (index < 0 || index >= arr->length)
-         {
-           _Jv_ThrowBadArrayIndex (index);
-         }
+       NULLARRAYCHECK (arr);
+       ARRAYBOUNDSCHECK (arr, index);
        _Jv_CheckArrayStore (arr, value);
        elements(arr)[index] = value;
       }
       NEXT_INSN;
 
      insn_bastore:
-      SAVE_PC;
       {
        jbyte value = (jbyte) POPI();
        jint index  = POPI();
        jbyteArray arr = (jbyteArray) POPA();
-       NULLCHECK (arr);
-       if (index < 0 || index >= arr->length)
-         {
-           _Jv_ThrowBadArrayIndex (index);
-         }
+       NULLARRAYCHECK (arr);
+       ARRAYBOUNDSCHECK (arr, index);
        elements(arr)[index] = value;
       }
       NEXT_INSN;
 
      insn_castore:
-      SAVE_PC;
       {
        jchar value = (jchar) POPI();
        jint index  = POPI();
        jcharArray arr = (jcharArray) POPA();
-       NULLCHECK (arr);
-       if (index < 0 || index >= arr->length)
-         {
-           _Jv_ThrowBadArrayIndex (index);
-         }
+       NULLARRAYCHECK (arr);
+       ARRAYBOUNDSCHECK (arr, index);
        elements(arr)[index] = value;
       }
       NEXT_INSN;
 
      insn_sastore:
-      SAVE_PC;
       {
        jshort value = (jshort) POPI();
        jint index  = POPI();
        jshortArray arr = (jshortArray) POPA();
-       NULLCHECK (arr);
-       if (index < 0 || index >= arr->length)
-         {
-           _Jv_ThrowBadArrayIndex (index);
-         }
+       NULLARRAYCHECK (arr);
+       ARRAYBOUNDSCHECK (arr, index);
        elements(arr)[index] = value;
       }
       NEXT_INSN;
@@ -1397,7 +1363,6 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv)
       NEXT_INSN;
 
      insn_fdiv:
-      SAVE_PC;
       {
        jfloat value2 = POPF();
        jfloat value1 = POPF();
@@ -1407,7 +1372,6 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv)
       NEXT_INSN;
 
      insn_ddiv:
-      SAVE_PC;
       {
        jdouble value2 = POPD();
        jdouble value1 = POPD();
@@ -1437,7 +1401,6 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv)
       NEXT_INSN;
 
      insn_frem:
-      SAVE_PC;
       {
        jfloat value2 = POPF();
        jfloat value1 = POPF();
@@ -1447,7 +1410,6 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv)
       NEXT_INSN;
 
      insn_drem:
-      SAVE_PC;
       {
        jdouble value2 = POPD();
        jdouble value1 = POPD();
@@ -1589,11 +1551,19 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv)
       NEXT_INSN;
 
      insn_f2i:
-      { jint value = (jint)POPF (); PUSHI(value); }
+      {
+       using namespace java::lang;
+       jint value = convert (POPF (), Integer::MIN_VALUE, Integer::MAX_VALUE);
+       PUSHI(value);
+      }
       NEXT_INSN;
 
      insn_f2l:
-      { jlong value = (jlong)POPF (); PUSHL(value); }
+      {
+       using namespace java::lang;
+       jlong value = convert (POPF (), Long::MIN_VALUE, Long::MAX_VALUE);
+       PUSHL(value);
+      }
       NEXT_INSN;
 
      insn_f2d:
@@ -1601,11 +1571,19 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv)
       NEXT_INSN;
 
      insn_d2i:
-      { jint value = (jint)POPD (); PUSHI(value); }
+      {
+       using namespace java::lang;
+       jint value = convert (POPD (), Integer::MIN_VALUE, Integer::MAX_VALUE);
+       PUSHI(value);
+      }
       NEXT_INSN;
 
      insn_d2l:
-      { jlong value = (jlong)POPD (); PUSHL(value); }
+      {
+       using namespace java::lang;
+       jlong value = convert (POPD (), Long::MIN_VALUE, Long::MAX_VALUE);
+       PUSHL(value);
+      }
       NEXT_INSN;
 
      insn_d2f:
@@ -1978,7 +1956,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv)
        jclass type = field->type;
        jint field_offset = field->u.boffset;
        if (field_offset > 0xffff)
-         JvThrow (new java::lang::VirtualMachineError);
+         throw new java::lang::VirtualMachineError;
 
        jobject obj   = POPA();
        NULLCHECK(obj);
@@ -2085,7 +2063,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv)
 
        jint field_offset = field->u.boffset;
        if (field_offset > 0xffff)
-         JvThrow (new java::lang::VirtualMachineError);
+         throw new java::lang::VirtualMachineError;
 
        if (type->isPrimitive ())
          {
@@ -2147,9 +2125,9 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv)
 
        sp -= rmeth->stack_item_count;
 
-       NULLCHECK(sp[0]);
+       NULLCHECK (sp[0].o);
 
-       fun = (void (*) (...))rmeth->method->ncode;
+       fun = (void (*)()) rmeth->method->ncode;
       }
       goto perform_invoke;
 
@@ -2163,7 +2141,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv)
        sp -= rmeth->stack_item_count;
 
        _Jv_InitClass (rmeth->klass);
-       fun = (void (*) (...))rmeth->method->ncode;
+       fun = (void (*)()) rmeth->method->ncode;
       }
       goto perform_invoke;
 
@@ -2178,11 +2156,12 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv)
        rmeth = (_Jv_ResolvePoolEntry (defining_class, index)).rmethod;
 
        sp -= rmeth->stack_item_count;
-       NULLCHECK(sp[0]);
 
        jobject rcv = sp[0].o;
 
-       fun = (void (*) (...))
+       NULLCHECK (rcv);
+
+       fun = (void (*)())
          _Jv_LookupInterfaceMethod (rcv->getClass (),
                                     rmeth->method->name,
                                     rmeth->method->signature);
@@ -2224,9 +2203,9 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv)
       NEXT_INSN;
 
      insn_arraylength:
-      SAVE_PC;
       {
        __JArray *arr = (__JArray*)POPA();
+       NULLARRAYCHECK (arr);
        PUSHI (arr->length);
       }
       NEXT_INSN;
@@ -2235,7 +2214,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv)
       SAVE_PC;
       {
        jobject value = POPA();
-       JvThrow (value);
+       throw static_cast<jthrowable>(value);
       }
       NEXT_INSN;
 
@@ -2248,8 +2227,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv)
 
        if (value != NULL && ! to->isInstance (value))
          {
-           JvThrow (new java::lang::ClassCastException
-                    (to->getName()));
+           throw new java::lang::ClassCastException (to->getName());
          }
 
        PUSHA (value);
@@ -2375,7 +2353,7 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv)
        jclass type    
          = (_Jv_ResolvePoolEntry (defining_class, kind_index)).clazz;
        _Jv_InitClass (type);
-       jint *sizes    = (jint*) alloca (sizeof (jint)*dim);
+       jint *sizes    = (jint*) __builtin_alloca (sizeof (jint)*dim);
 
        for (int i = dim - 1; i >= 0; i--)
          {
@@ -2410,13 +2388,13 @@ void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv)
 static void
 throw_internal_error (char *msg)
 {
-  JvThrow (new java::lang::InternalError (JvNewStringLatin1 (msg)));
+  throw new java::lang::InternalError (JvNewStringLatin1 (msg));
 }
 
 static void 
 throw_incompatible_class_change_error (jstring msg)
 {
-  JvThrow (new java::lang::IncompatibleClassChangeError (msg));
+  throw new java::lang::IncompatibleClassChangeError (msg);
 }
 
 #ifndef HANDLE_SEGV
@@ -2427,7 +2405,7 @@ throw_null_pointer_exception ()
   if (null_pointer_exc == NULL)
     null_pointer_exc = new java::lang::NullPointerException;
 
-  JvThrow (null_pointer_exc);
+  throw null_pointer_exc;
 }
 #endif