* src/vm/jit/alpha/md.c (md_init): Smaller changes.
[cacao.git] / src / vm / jit / argument.c
index ea0fa17d660f78d0df70882fa706a4a9650e219b..8705e6be13cedcb8e1a9c0302df135e706b62d19 100644 (file)
 #include <assert.h>
 #include <stdint.h>
 
+#include "arch.h"
+
+#include "mm/memory.h"
+
+#include "native/llni.h"
+
+#include "vm/array.h"
 #include "vm/global.h"
+#include "vm/primitive.h"
+#include "vm/resolve.h"
 #include "vm/vm.h"
 
+#include "vm/jit/abi-asm.h"
+
 #include "vmcore/descriptor.h"
+#include "vmcore/method.h"
 
 
 /* argument_jitarray_load ******************************************************
@@ -186,6 +198,566 @@ void argument_jitreturn_store(methoddesc *md, uint64_t *return_regs, imm_union r
 }
 
 
+/* argument_vmarray_store_int **************************************************
+
+   Helper function to store an integer into the argument array, taking
+   care of architecture specific issues.
+
+*******************************************************************************/
+
+static void argument_vmarray_store_int(uint64_t *array, paramdesc *pd, int32_t value)
+{
+       int32_t index;
+
+       if (!pd->inmemory) {
+               index        = pd->index;
+               array[index] = (int64_t) value;
+       }
+       else {
+               index        = ARG_CNT + pd->index;
+#if SIZEOF_VOID_P == 8
+               array[index] = (int64_t) value;
+#else
+# if WORDS_BIGENDIAN == 1
+               array[index] = ((int64_t) value) << 32;
+# else
+               array[index] = (int64_t) value;
+# endif
+#endif
+       }
+}
+
+
+/* argument_vmarray_store_lng **************************************************
+
+   Helper function to store a long into the argument array, taking
+   care of architecture specific issues.
+
+*******************************************************************************/
+
+static void argument_vmarray_store_lng(uint64_t *array, paramdesc *pd, int64_t value)
+{
+       int32_t index;
+
+#if SIZEOF_VOID_P == 8
+       if (!pd->inmemory)
+               index = pd->index;
+       else
+               index = ARG_CNT + pd->index;
+
+       array[index] = value;
+#else
+       if (!pd->inmemory) {
+               /* move low and high 32-bits into it's own argument slot */
+
+               index        = GET_LOW_REG(pd->index);
+               array[index] = value & 0x00000000ffffffff;
+
+               index        = GET_HIGH_REG(pd->index);
+               array[index] = value >> 32;
+       }
+       else {
+               index        = ARG_CNT + pd->index;
+               array[index] = value;
+       }
+#endif
+}
+
+
+/* argument_vmarray_store_flt **************************************************
+
+   Helper function to store a float into the argument array, taking
+   care of architecture specific issues.
+
+*******************************************************************************/
+
+static void argument_vmarray_store_flt(uint64_t *array, paramdesc *pd, uint64_t value)
+{
+       int32_t index;
+
+       if (!pd->inmemory) {
+#if defined(SUPPORT_PASS_FLOATARGS_IN_INTREGS)
+               index        = pd->index;
+#else
+               index        = INT_ARG_CNT + pd->index;
+#endif
+#if WORDS_BIGENDIAN == 1 && !defined(__POWERPC__) && !defined(__POWERPC64__) && !defined(__S390__)
+               array[index] = value >> 32;
+#else
+               array[index] = value;
+#endif
+       }
+       else {
+               index        = ARG_CNT + pd->index;
+#if defined(__SPARC_64__)
+               array[index] = value >> 32;
+#else
+               array[index] = value;
+#endif
+       }
+}
+
+
+/* argument_vmarray_store_dbl **************************************************
+
+   Helper function to store a double into the argument array, taking
+   care of architecture specific issues.
+
+*******************************************************************************/
+
+static void argument_vmarray_store_dbl(uint64_t *array, paramdesc *pd, uint64_t value)
+{
+       int32_t index;
+
+       if (!pd->inmemory) {
+#if SIZEOF_VOID_P != 8 && defined(SUPPORT_PASS_FLOATARGS_IN_INTREGS)
+               index        = GET_LOW_REG(pd->index);
+               array[index] = value & 0x00000000ffffffff;
+
+               index        = GET_HIGH_REG(pd->index);
+               array[index] = value >> 32;
+#else
+               index        = INT_ARG_CNT + pd->index;
+               array[index] = value;
+#endif
+       }
+       else {
+               index        = ARG_CNT + pd->index;
+               array[index] = value;
+       }
+}
+
+
+/* argument_vmarray_store_adr **************************************************
+
+   Helper function to store an address into the argument array, taking
+   care of architecture specific issues.
+
+   ATTENTION: This function has to be used outside the nativeworld.
+
+*******************************************************************************/
+
+static void argument_vmarray_store_adr(uint64_t *array, paramdesc *pd, java_handle_t *h)
+{
+       void    *value;
+       int32_t  index;
+
+       /* Take the reference value out of the handle. */
+
+       value = LLNI_UNWRAP(h);
+
+       if (!pd->inmemory) {
+#if defined(HAS_ADDRESS_REGISTER_FILE)
+               /* When the architecture has address registers, place them
+                  after integer and float registers. */
+
+               index        = INT_ARG_CNT + FLT_ARG_CNT + pd->index;
+#else
+               index        = pd->index;
+#endif
+               array[index] = (uint64_t) (intptr_t) value;
+       }
+       else {
+               index        = ARG_CNT + pd->index;
+#if SIZEOF_VOID_P == 8
+               array[index] = (uint64_t) (intptr_t) value;
+#else
+# if WORDS_BIGENDIAN == 1
+               array[index] = ((uint64_t) (intptr_t) value) << 32;
+# else
+               array[index] = (uint64_t) (intptr_t) value;
+# endif
+#endif
+       }
+}
+
+
+/* argument_vmarray_from_valist ************************************************
+
+   Creates an argument array which can be passed to asm_vm_call_method.
+   The array is created from the passed valist.
+
+   ATTENTION: This function has to be used outside the native world.
+
+*******************************************************************************/
+
+uint64_t *argument_vmarray_from_valist(methodinfo *m, java_handle_t *o, va_list ap)
+{
+       methoddesc *md;
+       paramdesc  *pd;
+       typedesc   *td;
+       uint64_t   *array;
+       int32_t     i;
+       imm_union   value;
+
+       /* get the descriptors */
+
+       md = m->parseddesc;
+       pd = md->params;
+       td = md->paramtypes;
+
+       /* allocate argument array */
+
+       array = DMNEW(uint64_t, INT_ARG_CNT + FLT_ARG_CNT + md->memuse);
+
+       /* if method is non-static fill first block and skip `this' pointer */
+
+       i = 0;
+
+       if (o != NULL) {
+               /* the `this' pointer */
+               argument_vmarray_store_adr(array, pd, o);
+
+               pd++;
+               td++;
+               i++;
+       } 
+
+       for (; i < md->paramcount; i++, pd++, td++) {
+               switch (td->type) {
+               case TYPE_INT:
+                       value.i = va_arg(ap, int32_t);
+                       argument_vmarray_store_int(array, pd, value.i);
+                       break;
+
+               case TYPE_LNG:
+                       value.l = va_arg(ap, int64_t);
+                       argument_vmarray_store_lng(array, pd, value.l);
+                       break;
+
+               case TYPE_FLT:
+#if defined(__ALPHA__) || defined(__POWERPC__) || defined(__POWERPC64__)
+                       /* This is required to load the correct float value in
+                          assembler code. */
+
+                       value.d = (double) va_arg(ap, double);
+#else
+                       value.f = (float) va_arg(ap, double);
+#endif
+                       argument_vmarray_store_flt(array, pd, value.l);
+                       break;
+
+               case TYPE_DBL:
+                       value.d = va_arg(ap, double);
+                       argument_vmarray_store_dbl(array, pd, value.l);
+                       break;
+
+               case TYPE_ADR: 
+                       value.a = va_arg(ap, void*);
+                       argument_vmarray_store_adr(array, pd, value.a);
+                       break;
+               }
+       }
+
+       return array;
+}
+
+
+/* argument_vmarray_from_jvalue ************************************************
+
+   Creates an argument array which can be passed to asm_vm_call_method.
+   The array is created from the passed jvalue array.
+
+   ATTENTION: This function has to be used outside the native world.
+
+*******************************************************************************/
+
+uint64_t *argument_vmarray_from_jvalue(methodinfo *m, java_handle_t *o,
+                                                                          const jvalue *args)
+{
+       methoddesc *md;
+       paramdesc  *pd;
+       typedesc   *td;
+       uint64_t   *array;
+       int32_t     i;
+       int32_t     j;
+
+       /* get the descriptors */
+
+       md = m->parseddesc;
+       pd = md->params;
+       td = md->paramtypes;
+
+       /* allocate argument array */
+
+#if defined(HAS_ADDRESS_REGISTER_FILE)
+       array = DMNEW(uint64_t, INT_ARG_CNT + FLT_ARG_CNT + ADR_ARG_CNT + md->memuse);
+#else
+       array = DMNEW(uint64_t, INT_ARG_CNT + FLT_ARG_CNT + md->memuse);
+#endif
+
+       /* if method is non-static fill first block and skip `this' pointer */
+
+       i = 0;
+
+       if (o != NULL) {
+               /* the `this' pointer */
+               argument_vmarray_store_adr(array, pd, o);
+
+               pd++;
+               td++;
+               i++;
+       } 
+
+       for (j = 0; i < md->paramcount; i++, j++, pd++, td++) {
+               switch (td->decltype) {
+               case TYPE_INT:
+                       argument_vmarray_store_int(array, pd, args[j].i);
+                       break;
+
+               case TYPE_LNG:
+                       argument_vmarray_store_lng(array, pd, args[j].j);
+                       break;
+
+               case TYPE_FLT:
+                       argument_vmarray_store_flt(array, pd, args[j].j);
+                       break;
+
+               case TYPE_DBL:
+                       argument_vmarray_store_dbl(array, pd, args[j].j);
+                       break;
+
+               case TYPE_ADR: 
+                       argument_vmarray_store_adr(array, pd, (java_handle_t *) args[j].l);
+                       break;
+               }
+       }
+
+       return array;
+}
+
+
+/* argument_vmarray_from_objectarray *******************************************
+
+   Creates an argument array which can be passed to asm_vm_call_method.
+   The array is created from the passed objectarray of boxed values.
+
+   ATTENTION: This function has to be used outside the native world.
+
+   RETURN VALUE:
+      NULL.........indicates an error while creating the array
+      (-1).........no error, but an empty array
+      otherwise....array containing the argument values
+
+*******************************************************************************/
+
+uint64_t *argument_vmarray_from_objectarray(methodinfo *m, java_handle_t *o,
+                                                                                       java_handle_objectarray_t *params)
+{
+       methoddesc    *md;
+       paramdesc     *pd;
+       typedesc      *td;
+       uint64_t      *array;
+       java_handle_t *param;
+       classinfo     *c;
+       int            type;
+       int32_t        i;
+       int32_t        j;
+       imm_union      value;
+
+       /* get the descriptors */
+
+       md = m->parseddesc;
+       pd = md->params;
+       td = md->paramtypes;
+
+       /* allocate argument array */
+
+       array = DMNEW(uint64_t, INT_ARG_CNT + FLT_ARG_CNT + md->memuse);
+
+       /* The array can be NULL if we don't have any arguments to pass
+          and the architecture does not have any argument registers
+          (e.g. i386).  In that case we return (-1) to indicate
+          that no exception should be thrown */
+
+       if (array == NULL)
+               array = (uint64_t *)(-1);
+
+       /* if method is non-static fill first block and skip `this' pointer */
+
+       i = 0;
+
+       if (o != NULL) {
+               /* this pointer */
+               argument_vmarray_store_adr(array, pd, o);
+
+               pd++;
+               td++;
+               i++;
+       }
+
+       for (j = 0; i < md->paramcount; i++, j++, pd++, td++) {
+               /* XXX This function can throw an exception, which should not happend
+                  here, since we are outside the nativeworld. */
+               param = array_objectarray_element_get(params, j);
+
+               switch (td->type) {
+               case TYPE_INT:
+                       if (param == NULL)
+                               return NULL;
+
+                       /* convert the value according to its declared type */
+
+                       LLNI_class_get(param, c);
+                       type = primitive_type_get_by_wrapperclass(c);
+
+                       switch (td->decltype) {
+                       case PRIMITIVETYPE_BOOLEAN:
+                               switch (type) {
+                               case PRIMITIVETYPE_BOOLEAN:
+                                       /* This type is OK. */
+                                       break;
+                               default:
+                                       return NULL;
+                               }
+                               break;
+
+                       case PRIMITIVETYPE_BYTE:
+                               switch (type) {
+                               case PRIMITIVETYPE_BYTE:
+                                       /* This type is OK. */
+                                       break;
+                               default:
+                                       return NULL;
+                               }
+                               break;
+
+                       case PRIMITIVETYPE_CHAR:
+                               switch (type) {
+                               case PRIMITIVETYPE_CHAR:
+                                       /* This type is OK. */
+                                       break;
+                               default:
+                                       return NULL;
+                               }
+                               break;
+
+                       case PRIMITIVETYPE_SHORT:
+                               switch (type) {
+                               case PRIMITIVETYPE_BYTE:
+                               case PRIMITIVETYPE_SHORT:
+                                       /* These types are OK. */
+                                       break;
+                               default:
+                                       return NULL;
+                               }
+                               break;
+
+                       case PRIMITIVETYPE_INT:
+                               switch (type) {
+                               case PRIMITIVETYPE_BYTE:
+                               case PRIMITIVETYPE_SHORT:
+                               case PRIMITIVETYPE_INT:
+                                       /* These types are OK. */
+                                       break;
+                               default:
+                                       return NULL;
+                               }
+                               break;
+
+                       default:
+                               vm_abort("argument_vmarray_from_objectarray: invalid type %d",
+                                                td->decltype);
+                       }
+
+                       value = primitive_unbox(param);
+                       argument_vmarray_store_int(array, pd, value.i);
+                       break;
+
+               case TYPE_LNG:
+                       if (param == NULL)
+                               return NULL;
+
+                       LLNI_class_get(param, c);
+                       type = primitive_type_get_by_wrapperclass(c);
+
+                       assert(td->decltype == PRIMITIVETYPE_LONG);
+
+                       switch (type) {
+                       case PRIMITIVETYPE_BYTE:
+                       case PRIMITIVETYPE_SHORT:
+                       case PRIMITIVETYPE_INT:
+                       case PRIMITIVETYPE_LONG:
+                               /* These types are OK. */
+                               break;
+                       default:
+                               return NULL;
+                       }
+
+                       value = primitive_unbox(param);
+                       argument_vmarray_store_lng(array, pd, value.l);
+                       break;
+
+               case TYPE_FLT:
+                       if (param == NULL)
+                               return NULL;
+
+                       LLNI_class_get(param, c);
+                       type = primitive_type_get_by_wrapperclass(c);
+
+                       assert(td->decltype == PRIMITIVETYPE_FLOAT);
+
+                       switch (type) {
+                       case PRIMITIVETYPE_FLOAT:
+                               /* This type is OK. */
+                               break;
+                       default:
+                               return NULL;
+                       }
+
+                       value = primitive_unbox(param);
+                       argument_vmarray_store_flt(array, pd, value.l);
+                       break;
+
+               case TYPE_DBL:
+                       if (param == NULL)
+                               return NULL;
+
+                       LLNI_class_get(param, c);
+                       type = primitive_type_get_by_wrapperclass(c);
+
+                       assert(td->decltype == PRIMITIVETYPE_DOUBLE);
+
+                       switch (type) {
+                       case PRIMITIVETYPE_FLOAT:
+                       case PRIMITIVETYPE_DOUBLE:
+                               /* These types are OK. */
+                               break;
+                       default:
+                               return NULL;
+                       }
+
+                       value = primitive_unbox(param);
+                       argument_vmarray_store_dbl(array, pd, value.l);
+                       break;
+               
+               case TYPE_ADR:
+                       if (!resolve_class_from_typedesc(td, true, true, &c))
+                               return NULL;
+
+                       if (param != NULL) {
+                               if (td->arraydim > 0) {
+                                       if (!builtin_arrayinstanceof(param, c))
+                                               return NULL;
+                               }
+                               else {
+                                       if (!builtin_instanceof(param, c))
+                                               return NULL;
+                               }
+                       }
+
+                       argument_vmarray_store_adr(array, pd, param);
+                       break;
+
+               default:
+                       vm_abort("argument_vmarray_from_objectarray: invalid type %d", td->type);
+               }
+       }
+
+       return array;
+}
+
+
 /*
  * 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