* src/mm/memory.cpp,
[cacao.git] / src / vm / jit / intrp / engine.c
index f8078cff3e904f874cc0d82becaf0dda2dff1bdc..118883f720c09c21215ae8d55979395389073968 100644 (file)
@@ -1,40 +1,90 @@
+/* src/vm/jit/intrp/engine.c - #included by engine1.c and engine2.c
+
+   Copyright (C) 1996-2005, 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+   This file is part of CACAO.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+*/
+
+
+/* #define VM_DEBUG */
+
+#include "config.h"
+
 #include <assert.h>
 
-#define VM_DEBUG
+#include "vm/types.h"
+
+#include "arch.h"
 
-#include "vm/jit/intrp/arch.h"
 #include "vm/jit/intrp/intrp.h"
 
-#include "asmoffsets.h"
-#include "md-abi.h"
+#include "md-abi.h"                           /* required for TRACE_ARGS_NUM */
+
+#include "mm/memory.hpp"
 
-#include "cacao/cacao.h"
-#include "vm/builtin.h"
-#include "vm/exceptions.h"
-#include "vm/loader.h"
+#include "threads/thread.hpp"
+
+#include "vm/jit/builtin.hpp"
+#include "vm/loader.hpp"
 #include "vm/options.h"
+
+#include "vm/jit/methodheader.h"
 #include "vm/jit/patcher.h"
-#include "ffcall/avcall/avcall.h"
+#include "vm/jit/stacktrace.hpp"
+
+
+#if defined(ENABLE_THREADS)
+# include "threads/atomic.hpp"
+#endif
 
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-# include "machine-instr.h"
+#if !defined(STORE_ORDER_BARRIER) && !defined(ENABLE_THREADS)
+#define STORE_ORDER_BARRIER() /* nothing */
 #endif
 
 
 /* threading macros */
+#define GCC_PR15242_WORKAROUND
+#ifdef GCC_PR15242_WORKAROUND
+#  define NEXT_P1_5
+#  define DO_GOTO goto before_goto
+#else
+#  define NEXT_P1_5
+#  define DO_GOTO goto *ip[-1]
+#endif
+
 #  define NEXT_P0
 #  define IP           (ip)
-#  define SET_IP(p)    ({ip=(p); NEXT_P0;})
+#  define SET_IP(p)    do {ip=(p); NEXT_P0;} while (0)
 #  define NEXT_INST    (*IP)
-#  define INC_IP(const_inc)    ({ ip+=(const_inc);})
+#  define INC_IP(const_inc)    do { ip+=(const_inc);} while (0)
 #  define DEF_CA
 #  define NEXT_P1      (ip++)
-#  define NEXT_P2      ({goto **(ip-1);})
-#  define EXEC(XT)     ({goto *(XT);})
+#  define NEXT_P2   do {NEXT_P1_5; DO_GOTO;} while(0)
 
 #define NEXT ({DEF_CA NEXT_P1; NEXT_P2;})
 #define IPTOS NEXT_INST
 
+#if defined(__POWERPC__) || defined(__POWERPC64__) || defined(__SPARC__)
+# define USE_spTOS
+#endif
+
 #if defined(USE_spTOS)
 #define IF_spTOS(x) x
 #else
 #define spTOS (sp[0])
 #endif
 
+#if defined(__I386__)
+/* works with gcc-2.95.4 20011002 (Debian prerelease) without static supers */
+#define SPREG /* __asm__("%esi") */
+#define TOSREG /* __asm__("%ecx") */
+#elif defined(__X86_64__)
+/* works with gcc-4.0.2 (Debian 4.0.2-2) */
+#define SPREG /* __asm__("%r15") */
+#define TOSREG
+#else
+#define SPREG
+#define TOSREG
+#endif
+
+
 /* conversion on fetch */
 
 #ifdef VM_PROFILING
 #define vm_uncount_block(_ip)  /* nothing */
 #endif
 
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-
-#define global_sp    (*(Cell **)&(THREADINFO->_global_sp))
-
-#else /* defined(USE_THREADS) && defined(NATIVE_THREADS) */
-
-#define MAX_STACK_SIZE 128*1024
-static char stack[MAX_STACK_SIZE];
-
-static Cell *_global_sp = (Cell *)(stack+MAX_STACK_SIZE);
-#define global_sp    _global_sp
-
-#endif /* defined(USE_THREADS) && defined(NATIVE_THREADS) */
-
-#define CLEAR_global_sp (global_sp=NULL)
-
 
 #define THROW0       goto throw
-#define THROW(_ball) \
-    { \
+#if 1
+#define THROW(_ball) do { \
+                       __asm__(""); /* work around gcc PR 25285 */ \
+                       goto *throw_##_ball; \
+                     } while (0)
+#else
+#define THROW(_ball) do { \
+                       goto throw_##_ball##1; \
+                     } while (0)
+#endif
+
+#define THROWCODE(_ball) \
+    throw_##_ball##1: \
         global_sp = sp; \
-        *exceptionptr = (stacktrace_inline_##_ball(NULL, (u1 *) fp, (functionptr) IP, (functionptr) IP)); \
+        *exceptionptr = (stacktrace_inline_##_ball(NULL, (u1 *) fp, (u1 *) IP, (u1 *) IP)); \
         CLEAR_global_sp; \
-        THROW0; \
-    }
+        THROW0;
 
 #define CHECK_NULL_PTR(ptr) \
     { \
@@ -84,13 +142,17 @@ static Cell *_global_sp = (Cell *)(stack+MAX_STACK_SIZE);
            } \
        }
 
+#define THROW_CLASSCASTEXCEPTION(o) \
+    { \
+               classcastexception_object = o; \
+        THROW(classcastexception); \
+       }
+
 #define CHECK_OUT_OF_BOUNDS(_array, _idx)              \
         {                                            \
           if (length_array(_array) <= (u4) (_idx)) { \
-            global_sp = sp; \
-            *exceptionptr = stacktrace_inline_arrayindexoutofboundsexception(NULL, (u1 *) fp, (functionptr) IP, (functionptr) IP, _idx); \
-                   CLEAR_global_sp; \
-            THROW0; \
+                arrayindexoutofbounds_index = (_idx); \
+                               THROW(arrayindexoutofboundsexception); \
           } \
        }
 
@@ -99,19 +161,10 @@ static Cell *_global_sp = (Cell *)(stack+MAX_STACK_SIZE);
       THROW(arithmeticexception); \
   } 
 
-#define access_local_int(_offset) \
-        ( *(Cell*)(fp - (_offset)) )
-
-#define access_local_ref(_offset) \
-        ( *(void **)(fp - (_offset)) )
-
-#define access_local_cell(_offset) \
-        ( *(Cell *)(fp - (_offset)) )
-
 #if 0
 /* !! alignment bug */
 #define access_local_long(_offset) \
-        ( *(s8 *)(fp - (_offset)) )
+        ( *(s8 *)(((u1 *)fp) + (_offset)) )
 #endif
 
 #define length_array(array)                          \
@@ -135,131 +188,19 @@ static Cell *_global_sp = (Cell *)(stack+MAX_STACK_SIZE);
 #define access_array_addr(array, index)               \
         ((((java_objectarray*)(array))->data)[index])
 
-#define MAXLOCALS(stub) (((Cell *)stub)[1])
-
-#if !defined(STORE_ORDER_BARRIER) && !defined(USE_THREADS)
-#define STORE_ORDER_BARRIER()
-#endif
-
+#define access_array_float(array, index)               \
+        ((((java_floatarray*)(array))->data)[index])
 
-/* call jni function */
-static Cell *nativecall(functionptr f, methodinfo *m, Cell *sp, Inst *ra, Cell *fp)
-{
-       av_alist alist;
-       methoddesc *md;
-       Cell *p;
-       Cell *endsp;
-       s4 i;
-       stackframeinfo sfi;
-
-       md=m->parseddesc;
-       switch (md->returntype.type) {
-       case TYPE_INT:
-               endsp=sp-1+md->paramslots; av_start_int(alist, f, endsp); break;
-       case TYPE_LNG:
-               endsp=sp-2+md->paramslots; av_start_longlong(alist, f, endsp); break;
-       case TYPE_FLT:
-               endsp=sp-1+md->paramslots; av_start_float(alist, f, endsp); break;
-       case TYPE_DBL:
-               endsp=sp-2+md->paramslots; av_start_double(alist, f, endsp); break;
-       case TYPE_ADR:
-               endsp=sp-1+md->paramslots; av_start_ptr(alist, f, void *, endsp); break;
-       case TYPE_VOID:
-               endsp=sp-1+md->paramslots; av_start_void(alist, f); break;
-       default: assert(false);
-       }
-
-       av_ptr(alist, JNIEnv *, &env);
-       if (m->flags & ACC_STATIC)
-               av_ptr(alist, classinfo *, m->class);
-
-       for (i=0, p=sp+md->paramslots; i<md->paramcount; i++) {
-               switch (md->paramtypes[i].type) {
-               case TYPE_INT:
-                       p-=1; av_int(alist, *p); break;
-               case TYPE_LNG:
-                       p-=2; av_longlong(alist, *(s8 *)p); break;
-               case TYPE_FLT:
-                       p-=1; av_float(alist, *(float *)p); break;
-               case TYPE_DBL:
-                       p-=2; av_double(alist, *(double *)p); break;
-               case TYPE_ADR:
-                       p-=1; av_ptr(alist, void *, *(void **)p); break;
-               default: assert(false);
-               }
-       }
-
-       global_sp = sp;
-
-       /* create stackframe info structure */
-
-       stacktrace_create_native_stackframeinfo(&sfi, (u1 *) m->entrypoint,
-                                                                                       (u1 *)fp,
-                                                                                       (functionptr) ra);
-
-       av_call(alist);
-
-       stacktrace_remove_stackframeinfo(&sfi);
-
-       CLEAR_global_sp;
-
-       return endsp;
-}
-
-
-Inst *builtin_throw(Inst *ip, java_objectheader *o, Cell *fp, Cell **new_spp, Cell **new_fpp)
-{
-       classinfo      *c;
-       s4              framesize;
-       exceptionentry *ex;
-       s4              exceptiontablelength;
-       s4              i;
-
-  /* for a description of the stack see IRETURN in java.vmg */
-  for (; fp!=NULL;) {
-         functionptr f = codegen_findmethod((functionptr) (ip-1));
-
-         /* get methodinfo pointer from method header */
-         methodinfo *m = *(methodinfo **) (((u1 *) f) + MethodPointer);
-
-         framesize = (*((s4 *) (((u1 *) f) + FrameSize)))/sizeof(void *);
-         ex = (exceptionentry *) (((u1 *) f) + ExTableStart);
-         exceptiontablelength = *((s4 *) (((u1 *) f) + ExTableSize));
-
-         builtin_trace_exception(o, m, ip, 0, 0);
-
-         for (i = 0; i < exceptiontablelength; i++) {
-                 ex--;
-                 c = ex->catchtype;
-
-                 if (c != NULL) {
-                         if (!c->loaded)
-                                 /* XXX fix me! */
-                                 if (!load_class_bootstrap(c))
-                                         assert(0);
-
-                         if (!c->linked)
-                                 if (!link_class(c))
-                                         assert(0);
-                 }
-
-                 if (ip-1 >= (Inst *) ex->startpc && ip-1 < (Inst *) ex->endpc &&
-                         (c == NULL || builtin_instanceof(o, c))) {
-                         *new_spp = fp - framesize - 1;
-                         *new_fpp = fp;
-                         return (Inst *) (ex->handlerpc);
-                 }
-         }
-
-         ip = (Inst *)access_local_cell(framesize+1);
-         fp = (Cell *)access_local_cell(framesize);
-  }
-
-  return NULL; 
-}
+/* (see createcompilerstub in codegen.c) */
+#define FRAMESIZE(stub) (((Cell *)stub)[1])
 
+#if 0
+#define CLEARSTACK(_start, _end) \
+        do {Cell *__start=(_start); MSET(__start,0,u1,(_end)-__start); } while (0)
+#else
+#define CLEARSTACK(_start, _end)
+#endif
 
-FILE *vm_out = NULL;
 
 #ifdef VM_DEBUG
 #define NAME(_x) if (vm_debug) {fprintf(vm_out, "%lx: %-20s, ", (long)(ip-1), _x); fprintf(vm_out,"fp=%p, sp=%p", fp, sp);}
@@ -267,25 +208,80 @@ FILE *vm_out = NULL;
 #define NAME(_x)
 #endif
 
-#define LABEL(_inst) I_##_inst:
-#define INST_ADDR(_inst) (&&I_##_inst)
-#define LABEL2(_inst)
+#define LABEL2(name) J_##name: __asm__("");
+#define LABEL3(name) K_##name: __asm__("");
 
 
 java_objectheader *
-engine(Inst *ip0, Cell * sp, Cell * fp)
+engine(Inst *ip0, Cell * sp0, Cell * fp)
 {
-  Inst * ip;
-  IF_spTOS(Cell   spTOS);
+  Inst *ip;
+  register Cell *sp SPREG = sp0;
+  /* Inst ca1; XXX unused? */ /* code address; this is the next dispatched instruction */
+  IF_spTOS(register Cell spTOS TOSREG;)
   static Inst   labels[] = {
-#include "java-labels.i"
+#define INST_ADDR(_inst) (&&I_##_inst)
+#include <java-labels.i>
+#undef INST_ADDR
+         NULL,
+#define INST_ADDR(_inst) (&&J_##_inst)
+#include <java-labels.i>
+#undef INST_ADDR
+#define INST_ADDR(_inst) (&&K_##_inst)
+#include <java-labels.i>
+#undef INST_ADDR
+    (Label)&&after_last,
+    (Label)&&before_goto,
+    (Label)&&after_goto,
+#define INST_ADDR(_inst) (&&H_##_inst)
+#include <java-labels.i>
+#undef INST_ADDR
   };
+  /* local variables for the various throw codes; this helps make
+        potentially throwing instructions relocatable (instead of a
+        non-relocatable direct jump, they perform an indirect jump) */
+  Label throw_arithmeticexception            = &&throw_arithmeticexception1;
+  Label throw_arrayindexoutofboundsexception = &&throw_arrayindexoutofboundsexception1;
+  Label throw_classcastexception                        = &&throw_classcastexception1;  
+  Label throw_nullpointerexception                  = &&throw_nullpointerexception1;
+  Label throw_arraystoreexception            = &&throw_arraystoreexception1;
+  java_objectheader *classcastexception_object = NULL;
+  s4 arrayindexoutofbounds_index = 0; /* pass the index to the throw code */
 
   if (vm_debug)
       fprintf(vm_out,"entering engine(%p,%p,%p)\n",ip0,sp,fp);
   if (ip0 == NULL) {
-    vm_prim = labels;
-    return NULL;
+    return (java_objectheader *)labels;
+  }
+
+  if (0) {
+  before_goto:
+         goto *ip[-1];
+  after_goto:
+         /* ensure that gcc does not constant-propagate the contents of
+                these variables and thus undo our relocatability work */
+         throw_arithmeticexception = 0;
+         throw_arrayindexoutofboundsexception = 0;
+         throw_classcastexception = 0;
+         throw_nullpointerexception = 0;
+         throw_arraystoreexception = 0;
+
+      /* the actual codes jumped to through the ...exception variables */
+         THROWCODE(arithmeticexception);
+         THROWCODE(nullpointerexception);
+         THROWCODE(arraystoreexception);
+
+  throw_classcastexception1:
+         global_sp = sp;
+         *exceptionptr = stacktrace_inline_classcastexception(NULL, (u1 *) fp, (u1 *) IP, (u1 *) IP, classcastexception_object);
+         CLEAR_global_sp;
+         THROW0;
+
+  throw_arrayindexoutofboundsexception1:
+         global_sp = sp;
+         *exceptionptr = stacktrace_inline_arrayindexoutofboundsexception(NULL, (u1 *) fp, (u1 *) IP, (u1 *) IP, arrayindexoutofbounds_index);
+         CLEAR_global_sp;
+         THROW0;
   }
 
   /* I don't have a clue where these things come from,
@@ -295,209 +291,13 @@ engine(Inst *ip0, Cell * sp, Cell * fp)
   SET_IP(ip0);
   NEXT;
 
-#include "java-vm.i"
+#define INST_ADDR(_inst) (&&I_##_inst)
+#include <java-vm.i>
 #undef NAME
+ after_last: return NULL;
 }
 
 
-/* true on success, false on exception */
-static bool asm_calljavafunction_intern(methodinfo *m,
-                  void *arg1, void *arg2, void *arg3, void *arg4)
-{
-  java_objectheader *retval;
-  Cell *sp = global_sp;
-  methoddesc *md;
-  functionptr entrypoint;
-
-  md = m->parseddesc;
-
-  CLEAR_global_sp;
-  assert(sp != NULL);
-
-  /* XXX ugly hack: thread's run() needs 5 arguments */
-  assert(md->paramcount < 6);
-
-  if (md->paramcount > 0)
-    *--sp=(Cell)arg1;
-  if (md->paramcount > 1)
-    *--sp=(Cell)arg2;
-  if (md->paramcount > 2)
-    *--sp=(Cell)arg3;
-  if (md->paramcount > 3)
-    *--sp=(Cell)arg4;
-  if (md->paramcount > 4)
-    *--sp=(Cell) 0;
-
-  entrypoint = createcalljavafunction(m);
-
-  retval = engine((Inst *) entrypoint, sp, NULL);
-
-  /* XXX remove the method from the method table */
-
-  if (retval != NULL) {
-         (void)builtin_throw_exception(retval);
-         return false;
-  }
-  else 
-         return true;
-}
-
-s4 asm_calljavafunction_int(methodinfo *m,
-                  void *arg1, void *arg2, void *arg3, void *arg4)
-{
-       assert(m->parseddesc->returntype.type == TYPE_INT);
-       if (asm_calljavafunction_intern(m, arg1, arg2, arg3, arg4))
-               return (s4)(*global_sp++);
-       else
-               return 0;
-}
-
-java_objectheader *asm_calljavafunction(methodinfo *m,
-                  void *arg1, void *arg2, void *arg3, void *arg4)
-{
-       if (asm_calljavafunction_intern(m, arg1, arg2, arg3, arg4)) {
-               if (m->parseddesc->returntype.type == TYPE_ADR)
-                       return (java_objectheader *)(*global_sp++);
-               else {
-                       assert(m->parseddesc->returntype.type == TYPE_VOID);
-                       return NULL;
-               }
-       } else
-               return NULL;
-}
-
-/* true on success, false on exception */
-static bool jni_invoke_java_intern(methodinfo *m, u4 count, u4 size,
-                                          jni_callblock *callblock)
-{
-       java_objectheader *retval;
-       Cell *sp = global_sp;
-       Inst wrapper[5];
-       s4 i;
-       functionptr entrypoint;
-
-#if 0
-       codegendata *cd;
-       s4           dumpsize;
-
-       /* mark start of dump memory area */
-
-       dumpsize = dump_size();
-       
-       cd = DNEW(codegendata);
-    cd->mcodeptr = (u1 *) wrapper;
-#endif
-
-       CLEAR_global_sp;
-       assert(sp != NULL);
-
-       for (i = 0; i < count; i++) {
-               switch (callblock[i].itemtype) {
-               case TYPE_INT:
-               case TYPE_FLT:
-               case TYPE_ADR:
-                       *(--sp) = callblock[i].item;
-                       break;
-               case TYPE_LNG:
-               case TYPE_DBL:
-                       sp -= 2;
-                       *((u8 *) sp) = callblock[i].item;
-                       break;
-               }
-       }
-
-#if 0
-       gen_BBSTART;
-       gen_INVOKESTATIC((Inst **) cd, (Inst **)m->stubroutine, m->parseddesc->paramslots, NULL);
-       gen_END((Inst **) cd);
-
-       /* release dump area */
-
-       dump_release(dumpsize);
-#endif
-
-       entrypoint = createcalljavafunction(m);
-
-       retval = engine((Inst *) entrypoint, sp, NULL);
-
-       /* XXX remove the method from the method table */
-
-       if (retval != NULL) {
-               (void)builtin_throw_exception(retval);
-               return false;
-       }
-       else
-               return true;
-}
-
-java_objectheader *asm_calljavafunction2(methodinfo *m, u4 count, u4 size,
-                                         jni_callblock *callblock)
-{
-  java_objectheader *retval = NULL;
-  if (jni_invoke_java_intern(m, count, size, callblock)) {
-         if (m->parseddesc->returntype.type == TYPE_ADR)
-                 retval = (java_objectheader *)*global_sp++;
-         else
-                 assert(m->parseddesc->returntype.type == TYPE_VOID);
-         return retval;
-  } else
-         return NULL;
-}
-
-s4 asm_calljavafunction2int(methodinfo *m, u4 count, u4 size,
-                            jni_callblock *callblock)
-{
-  s4 retval=0;
-
-  if (jni_invoke_java_intern(m, count, size, callblock)) {
-         if (m->parseddesc->returntype.type == TYPE_INT)
-                 retval = *global_sp++;
-         else
-                 assert(m->parseddesc->returntype.type == TYPE_VOID);
-         return retval;
-  } else
-         return 0;
-}
-
-s8 asm_calljavafunction2long(methodinfo *m, u4 count, u4 size,
-                             jni_callblock *callblock)
-{
-  s8 retval;
-  assert(m->parseddesc->returntype.type == TYPE_LNG);
-  if (jni_invoke_java_intern(m, count, size, callblock)) {
-         retval = *(s8 *)global_sp;
-         global_sp += 2;
-         return retval;
-  } else
-         return 0;
-}
-
-float asm_calljavafunction2float(methodinfo *m, u4 count, u4 size,
-                                         jni_callblock *callblock)
-{
-  float retval;
-  assert(m->parseddesc->returntype.type == TYPE_FLT);
-  if (jni_invoke_java_intern(m, count, size, callblock)) {
-         retval = *(float *)global_sp;
-         global_sp += 1;
-         return retval;
-  } else
-         return 0.0;
-}
-
-double asm_calljavafunction2double(methodinfo *m, u4 count, u4 size,
-                                   jni_callblock *callblock)
-{
-  double retval;
-  assert(m->parseddesc->returntype.type == TYPE_DBL);
-  if (jni_invoke_java_intern(m, count, size, callblock)) {
-         retval = *(double *)global_sp;
-         global_sp += 2;
-         return retval;
-  } else
-         return 0.0;
-}
-
 /*
  * These are local overrides for various environment variables in Emacs.
  * Please do not remove this and leave it at the end of the file, where
@@ -509,4 +309,5 @@ double asm_calljavafunction2double(methodinfo *m, u4 count, u4 size,
  * c-basic-offset: 4
  * tab-width: 4
  * End:
+ * vim:noexpandtab:sw=4:ts=4:
  */