bc0e4bddeb550164c37ca1d02fb16f3aa2807647
[cacao.git] / src / vm / jit / argument.c
1 /* src/vm/jit/argument.c - argument passing from and to JIT methods
2
3    Copyright (C) 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27
28 #include <assert.h>
29 #include <stdint.h>
30
31 #include "arch.h"
32
33 #include "mm/memory.h"
34
35 #include "native/llni.h"
36
37 #include "vm/array.h"
38 #include "vm/global.h"
39 #include "vm/primitive.hpp"
40 #include "vm/resolve.h"
41 #include "vm/vm.h"
42
43 #include "vm/jit/abi-asm.h"
44
45 #include "vmcore/descriptor.h"
46 #include "vmcore/method.h"
47
48
49 /* argument_jitarray_load ******************************************************
50  
51    Returns the argument specified by index from one of the passed arrays
52    and returns it.
53
54 *******************************************************************************/
55
56 imm_union argument_jitarray_load(methoddesc *md, int32_t index,
57                                                                  uint64_t *arg_regs, uint64_t *stack)
58 {
59         imm_union  ret;
60         paramdesc *pd;
61
62         pd = &md->params[index];
63
64         switch (md->paramtypes[index].type) {
65                 case TYPE_INT:
66                 case TYPE_ADR:
67                         if (pd->inmemory) {
68 #if (SIZEOF_VOID_P == 8)
69                                 ret.l = (int64_t)stack[pd->index];
70 #else
71                                 ret.l = *(int32_t *)(stack + pd->index);
72 #endif
73                         } else {
74 #if (SIZEOF_VOID_P == 8)
75                                 ret.l = arg_regs[index];
76 #else
77                                 ret.l = *(int32_t *)(arg_regs + index);
78 #endif
79                         }
80                         break;
81                 case TYPE_LNG:
82                         if (pd->inmemory) {
83                                 ret.l = (int64_t)stack[pd->index];
84                         } else {
85                                 ret.l = (int64_t)arg_regs[index];
86                         }
87                         break;
88                 case TYPE_FLT:
89                         if (pd->inmemory) {
90                                 ret.l = (int64_t)stack[pd->index];
91                         } else {
92                                 ret.l = (int64_t)arg_regs[index];
93                         }
94                         break;
95                 case TYPE_DBL:
96                         if (pd->inmemory) {
97                                 ret.l = (int64_t)stack[pd->index];
98                         } else {
99                                 ret.l = (int64_t)arg_regs[index];
100                         }
101                         break;
102         }
103
104         return ret;
105 }
106
107
108 /* argument_jitarray_store *****************************************************
109  
110    Stores the argument into one of the passed arrays at a slot specified
111    by index.
112
113 *******************************************************************************/
114
115 void argument_jitarray_store(methoddesc *md, int32_t index,
116                                                          uint64_t *arg_regs, uint64_t *stack,
117                                                          imm_union param)
118 {
119         paramdesc *pd;
120
121         pd = &md->params[index];
122
123         switch (md->paramtypes[index].type) {
124                 case TYPE_ADR:
125                         if (pd->inmemory) {
126 #if (SIZEOF_VOID_P == 8)
127                                 stack[pd->index] = param.l;
128 #else
129                                 assert(0);
130 #endif
131                         } else {
132                                 arg_regs[index] = param.l;
133                         }
134                         break;
135                 default:
136                         vm_abort("argument_jitarray_store: type not implemented");
137                         break;
138         }
139 }
140
141
142 /* argument_jitreturn_load *****************************************************
143
144    Loads the proper return value form the return register and returns it.
145
146 *******************************************************************************/
147
148 imm_union argument_jitreturn_load(methoddesc *md, uint64_t *return_regs)
149 {
150         imm_union ret;
151
152         switch (md->returntype.type) {
153                 case TYPE_INT:
154                 case TYPE_ADR:
155 #if (SIZEOF_VOID_P == 8)
156                         ret.l = return_regs[0];
157 #else
158                         ret.l = *(int32_t *)return_regs;
159 #endif
160                         break;
161                 case TYPE_LNG:
162                         ret.l = *(int64_t *)return_regs;
163                         break;
164                 case TYPE_FLT:
165                         ret.l = *(int64_t *)return_regs;
166                         break;
167                 case TYPE_DBL:
168                         ret.l = *(int64_t *)return_regs;
169                         break;
170         }
171
172         return ret;
173 }
174
175
176 /* argument_jitreturn_store ****************************************************
177
178    Stores the proper return value into the return registers.
179
180 *******************************************************************************/
181
182 void argument_jitreturn_store(methoddesc *md, uint64_t *return_regs, imm_union ret)
183 {
184         switch (md->returntype.type) {
185                 case TYPE_ADR:
186 #if (SIZEOF_VOID_P == 8)
187                         return_regs[0] = ret.l;
188 #else
189                         assert(0);
190 #endif
191                         break;
192                 default:
193                         vm_abort("argument_jitreturn_store: type not implemented");
194                         break;
195         }
196 }
197
198
199 /* argument_vmarray_store_int **************************************************
200
201    Helper function to store an integer into the argument array, taking
202    care of architecture specific issues.
203
204 *******************************************************************************/
205
206 static void argument_vmarray_store_int(uint64_t *array, paramdesc *pd, int32_t value)
207 {
208         int32_t index;
209
210         if (!pd->inmemory) {
211                 index        = pd->index;
212                 array[index] = (int64_t) value;
213         }
214         else {
215                 index        = ARG_CNT + pd->index;
216 #if SIZEOF_VOID_P == 8
217                 array[index] = (int64_t) value;
218 #else
219 # if WORDS_BIGENDIAN == 1
220                 array[index] = ((int64_t) value) << 32;
221 # else
222                 array[index] = (int64_t) value;
223 # endif
224 #endif
225         }
226 }
227
228
229 /* argument_vmarray_store_lng **************************************************
230
231    Helper function to store a long into the argument array, taking
232    care of architecture specific issues.
233
234 *******************************************************************************/
235
236 static void argument_vmarray_store_lng(uint64_t *array, paramdesc *pd, int64_t value)
237 {
238         int32_t index;
239
240 #if SIZEOF_VOID_P == 8
241         if (!pd->inmemory)
242                 index = pd->index;
243         else
244                 index = ARG_CNT + pd->index;
245
246         array[index] = value;
247 #else
248         if (!pd->inmemory) {
249                 /* move low and high 32-bits into it's own argument slot */
250
251                 index        = GET_LOW_REG(pd->index);
252                 array[index] = value & 0x00000000ffffffff;
253
254                 index        = GET_HIGH_REG(pd->index);
255                 array[index] = value >> 32;
256         }
257         else {
258                 index        = ARG_CNT + pd->index;
259                 array[index] = value;
260         }
261 #endif
262 }
263
264
265 /* argument_vmarray_store_flt **************************************************
266
267    Helper function to store a float into the argument array, taking
268    care of architecture specific issues.
269
270 *******************************************************************************/
271
272 static void argument_vmarray_store_flt(uint64_t *array, paramdesc *pd, uint64_t value)
273 {
274         int32_t index;
275
276         if (!pd->inmemory) {
277 #if defined(SUPPORT_PASS_FLOATARGS_IN_INTREGS)
278                 index        = pd->index;
279 #else
280                 index        = INT_ARG_CNT + pd->index;
281 #endif
282 #if WORDS_BIGENDIAN == 1 && !defined(__POWERPC__) && !defined(__POWERPC64__) && !defined(__S390__)
283                 array[index] = value >> 32;
284 #else
285                 array[index] = value;
286 #endif
287         }
288         else {
289                 index        = ARG_CNT + pd->index;
290 #if defined(__SPARC_64__)
291                 array[index] = value >> 32;
292 #else
293                 array[index] = value;
294 #endif
295         }
296 }
297
298
299 /* argument_vmarray_store_dbl **************************************************
300
301    Helper function to store a double into the argument array, taking
302    care of architecture specific issues.
303
304 *******************************************************************************/
305
306 static void argument_vmarray_store_dbl(uint64_t *array, paramdesc *pd, uint64_t value)
307 {
308         int32_t index;
309
310         if (!pd->inmemory) {
311 #if SIZEOF_VOID_P != 8 && defined(SUPPORT_PASS_FLOATARGS_IN_INTREGS)
312                 index        = GET_LOW_REG(pd->index);
313                 array[index] = value & 0x00000000ffffffff;
314
315                 index        = GET_HIGH_REG(pd->index);
316                 array[index] = value >> 32;
317 #else
318                 index        = INT_ARG_CNT + pd->index;
319                 array[index] = value;
320 #endif
321         }
322         else {
323                 index        = ARG_CNT + pd->index;
324                 array[index] = value;
325         }
326 }
327
328
329 /* argument_vmarray_store_adr **************************************************
330
331    Helper function to store an address into the argument array, taking
332    care of architecture specific issues.
333
334    ATTENTION: This function has to be used outside the nativeworld.
335
336 *******************************************************************************/
337
338 static void argument_vmarray_store_adr(uint64_t *array, paramdesc *pd, java_handle_t *h)
339 {
340         void    *value;
341         int32_t  index;
342
343         /* Take the reference value out of the handle. */
344
345         value = LLNI_UNWRAP(h);
346
347         if (!pd->inmemory) {
348 #if defined(HAS_ADDRESS_REGISTER_FILE)
349                 /* When the architecture has address registers, place them
350                    after integer and float registers. */
351
352                 index        = INT_ARG_CNT + FLT_ARG_CNT + pd->index;
353 #else
354                 index        = pd->index;
355 #endif
356                 array[index] = (uint64_t) (intptr_t) value;
357         }
358         else {
359                 index        = ARG_CNT + pd->index;
360 #if SIZEOF_VOID_P == 8
361                 array[index] = (uint64_t) (intptr_t) value;
362 #else
363 # if WORDS_BIGENDIAN == 1
364                 array[index] = ((uint64_t) (intptr_t) value) << 32;
365 # else
366                 array[index] = (uint64_t) (intptr_t) value;
367 # endif
368 #endif
369         }
370 }
371
372
373 /* argument_vmarray_from_valist ************************************************
374
375    Creates an argument array which can be passed to asm_vm_call_method.
376    The array is created from the passed valist.
377
378    ATTENTION: This function has to be used outside the native world.
379
380 *******************************************************************************/
381
382 uint64_t *argument_vmarray_from_valist(methodinfo *m, java_handle_t *o, va_list ap)
383 {
384         methoddesc *md;
385         paramdesc  *pd;
386         typedesc   *td;
387         uint64_t   *array;
388         int32_t     i;
389         imm_union   value;
390
391         /* get the descriptors */
392
393         md = m->parseddesc;
394         pd = md->params;
395         td = md->paramtypes;
396
397         /* allocate argument array */
398
399         array = DMNEW(uint64_t, INT_ARG_CNT + FLT_ARG_CNT + md->memuse);
400
401         /* if method is non-static fill first block and skip `this' pointer */
402
403         i = 0;
404
405         if (o != NULL) {
406                 /* the `this' pointer */
407                 argument_vmarray_store_adr(array, pd, o);
408
409                 pd++;
410                 td++;
411                 i++;
412         } 
413
414         for (; i < md->paramcount; i++, pd++, td++) {
415                 switch (td->type) {
416                 case TYPE_INT:
417                         value.i = va_arg(ap, int32_t);
418                         argument_vmarray_store_int(array, pd, value.i);
419                         break;
420
421                 case TYPE_LNG:
422                         value.l = va_arg(ap, int64_t);
423                         argument_vmarray_store_lng(array, pd, value.l);
424                         break;
425
426                 case TYPE_FLT:
427 #if defined(__ALPHA__) || defined(__POWERPC__) || defined(__POWERPC64__)
428                         /* This is required to load the correct float value in
429                            assembler code. */
430
431                         value.d = (double) va_arg(ap, double);
432 #else
433                         value.f = (float) va_arg(ap, double);
434 #endif
435                         argument_vmarray_store_flt(array, pd, value.l);
436                         break;
437
438                 case TYPE_DBL:
439                         value.d = va_arg(ap, double);
440                         argument_vmarray_store_dbl(array, pd, value.l);
441                         break;
442
443                 case TYPE_ADR: 
444                         value.a = va_arg(ap, void*);
445                         argument_vmarray_store_adr(array, pd, value.a);
446                         break;
447                 }
448         }
449
450         return array;
451 }
452
453
454 /* argument_vmarray_from_jvalue ************************************************
455
456    Creates an argument array which can be passed to asm_vm_call_method.
457    The array is created from the passed jvalue array.
458
459    ATTENTION: This function has to be used outside the native world.
460
461 *******************************************************************************/
462
463 uint64_t *argument_vmarray_from_jvalue(methodinfo *m, java_handle_t *o,
464                                                                            const jvalue *args)
465 {
466         methoddesc *md;
467         paramdesc  *pd;
468         typedesc   *td;
469         uint64_t   *array;
470         int32_t     i;
471         int32_t     j;
472
473         /* get the descriptors */
474
475         md = m->parseddesc;
476         pd = md->params;
477         td = md->paramtypes;
478
479         /* allocate argument array */
480
481 #if defined(HAS_ADDRESS_REGISTER_FILE)
482         array = DMNEW(uint64_t, INT_ARG_CNT + FLT_ARG_CNT + ADR_ARG_CNT + md->memuse);
483 #else
484         array = DMNEW(uint64_t, INT_ARG_CNT + FLT_ARG_CNT + md->memuse);
485 #endif
486
487         /* if method is non-static fill first block and skip `this' pointer */
488
489         i = 0;
490
491         if (o != NULL) {
492                 /* the `this' pointer */
493                 argument_vmarray_store_adr(array, pd, o);
494
495                 pd++;
496                 td++;
497                 i++;
498         } 
499
500         for (j = 0; i < md->paramcount; i++, j++, pd++, td++) {
501                 switch (td->decltype) {
502                 case TYPE_INT:
503                         argument_vmarray_store_int(array, pd, args[j].i);
504                         break;
505
506                 case TYPE_LNG:
507                         argument_vmarray_store_lng(array, pd, args[j].j);
508                         break;
509
510                 case TYPE_FLT:
511                         argument_vmarray_store_flt(array, pd, args[j].j);
512                         break;
513
514                 case TYPE_DBL:
515                         argument_vmarray_store_dbl(array, pd, args[j].j);
516                         break;
517
518                 case TYPE_ADR: 
519                         argument_vmarray_store_adr(array, pd, (java_handle_t *) args[j].l);
520                         break;
521                 }
522         }
523
524         return array;
525 }
526
527
528 /* argument_vmarray_from_objectarray *******************************************
529
530    Creates an argument array which can be passed to asm_vm_call_method.
531    The array is created from the passed objectarray of boxed values.
532
533    ATTENTION: This function has to be used outside the native world.
534
535    RETURN VALUE:
536       NULL.........indicates an error while creating the array
537       (-1).........no error, but an empty array
538       otherwise....array containing the argument values
539
540 *******************************************************************************/
541
542 uint64_t *argument_vmarray_from_objectarray(methodinfo *m, java_handle_t *o,
543                                                                                         java_handle_objectarray_t *params)
544 {
545         methoddesc    *md;
546         paramdesc     *pd;
547         typedesc      *td;
548         uint64_t      *array;
549         java_handle_t *param;
550         classinfo     *c;
551         int            type;
552         int32_t        i;
553         int32_t        j;
554         imm_union      value;
555
556         /* get the descriptors */
557
558         md = m->parseddesc;
559         pd = md->params;
560         td = md->paramtypes;
561
562         /* allocate argument array */
563
564         array = DMNEW(uint64_t, INT_ARG_CNT + FLT_ARG_CNT + md->memuse);
565
566         /* The array can be NULL if we don't have any arguments to pass
567            and the architecture does not have any argument registers
568            (e.g. i386).  In that case we return (-1) to indicate
569            that no exception should be thrown */
570
571         if (array == NULL)
572                 array = (uint64_t *)(-1);
573
574         /* if method is non-static fill first block and skip `this' pointer */
575
576         i = 0;
577
578         if (o != NULL) {
579                 /* this pointer */
580                 argument_vmarray_store_adr(array, pd, o);
581
582                 pd++;
583                 td++;
584                 i++;
585         }
586
587         for (j = 0; i < md->paramcount; i++, j++, pd++, td++) {
588                 /* XXX This function can throw an exception, which should not happend
589                    here, since we are outside the nativeworld. */
590                 param = array_objectarray_element_get(params, j);
591
592                 switch (td->type) {
593                 case TYPE_INT:
594                         if (param == NULL)
595                                 return NULL;
596
597                         /* convert the value according to its declared type */
598
599                         LLNI_class_get(param, c);
600                         type = Primitive_get_type_by_wrapperclass(c);
601
602                         switch (td->decltype) {
603                         case PRIMITIVETYPE_BOOLEAN:
604                                 switch (type) {
605                                 case PRIMITIVETYPE_BOOLEAN:
606                                         /* This type is OK. */
607                                         break;
608                                 default:
609                                         return NULL;
610                                 }
611                                 break;
612
613                         case PRIMITIVETYPE_BYTE:
614                                 switch (type) {
615                                 case PRIMITIVETYPE_BYTE:
616                                         /* This type is OK. */
617                                         break;
618                                 default:
619                                         return NULL;
620                                 }
621                                 break;
622
623                         case PRIMITIVETYPE_CHAR:
624                                 switch (type) {
625                                 case PRIMITIVETYPE_CHAR:
626                                         /* This type is OK. */
627                                         break;
628                                 default:
629                                         return NULL;
630                                 }
631                                 break;
632
633                         case PRIMITIVETYPE_SHORT:
634                                 switch (type) {
635                                 case PRIMITIVETYPE_BYTE:
636                                 case PRIMITIVETYPE_SHORT:
637                                         /* These types are OK. */
638                                         break;
639                                 default:
640                                         return NULL;
641                                 }
642                                 break;
643
644                         case PRIMITIVETYPE_INT:
645                                 switch (type) {
646                                 case PRIMITIVETYPE_BYTE:
647                                 case PRIMITIVETYPE_SHORT:
648                                 case PRIMITIVETYPE_INT:
649                                         /* These types are OK. */
650                                         break;
651                                 default:
652                                         return NULL;
653                                 }
654                                 break;
655
656                         default:
657                                 vm_abort("argument_vmarray_from_objectarray: invalid type %d",
658                                                  td->decltype);
659                         }
660
661                         value = Primitive_unbox(param);
662                         argument_vmarray_store_int(array, pd, value.i);
663                         break;
664
665                 case TYPE_LNG:
666                         if (param == NULL)
667                                 return NULL;
668
669                         LLNI_class_get(param, c);
670                         type = Primitive_get_type_by_wrapperclass(c);
671
672                         assert(td->decltype == PRIMITIVETYPE_LONG);
673
674                         switch (type) {
675                         case PRIMITIVETYPE_BYTE:
676                         case PRIMITIVETYPE_SHORT:
677                         case PRIMITIVETYPE_INT:
678                         case PRIMITIVETYPE_LONG:
679                                 /* These types are OK. */
680                                 break;
681                         default:
682                                 return NULL;
683                         }
684
685                         value = Primitive_unbox(param);
686                         argument_vmarray_store_lng(array, pd, value.l);
687                         break;
688
689                 case TYPE_FLT:
690                         if (param == NULL)
691                                 return NULL;
692
693                         LLNI_class_get(param, c);
694                         type = Primitive_get_type_by_wrapperclass(c);
695
696                         assert(td->decltype == PRIMITIVETYPE_FLOAT);
697
698                         switch (type) {
699                         case PRIMITIVETYPE_FLOAT:
700                                 /* This type is OK. */
701                                 break;
702                         default:
703                                 return NULL;
704                         }
705
706                         value = Primitive_unbox(param);
707                         argument_vmarray_store_flt(array, pd, value.l);
708                         break;
709
710                 case TYPE_DBL:
711                         if (param == NULL)
712                                 return NULL;
713
714                         LLNI_class_get(param, c);
715                         type = Primitive_get_type_by_wrapperclass(c);
716
717                         assert(td->decltype == PRIMITIVETYPE_DOUBLE);
718
719                         switch (type) {
720                         case PRIMITIVETYPE_FLOAT:
721                         case PRIMITIVETYPE_DOUBLE:
722                                 /* These types are OK. */
723                                 break;
724                         default:
725                                 return NULL;
726                         }
727
728                         value = Primitive_unbox(param);
729                         argument_vmarray_store_dbl(array, pd, value.l);
730                         break;
731                 
732                 case TYPE_ADR:
733                         if (!resolve_class_from_typedesc(td, true, true, &c))
734                                 return NULL;
735
736                         if (param != NULL) {
737                                 if (td->arraydim > 0) {
738                                         if (!builtin_arrayinstanceof(param, c))
739                                                 return NULL;
740                                 }
741                                 else {
742                                         if (!builtin_instanceof(param, c))
743                                                 return NULL;
744                                 }
745                         }
746
747                         argument_vmarray_store_adr(array, pd, param);
748                         break;
749
750                 default:
751                         vm_abort("argument_vmarray_from_objectarray: invalid type %d", td->type);
752                 }
753         }
754
755         return array;
756 }
757
758
759 /*
760  * These are local overrides for various environment variables in Emacs.
761  * Please do not remove this and leave it at the end of the file, where
762  * Emacs will automagically detect them.
763  * ---------------------------------------------------------------------
764  * Local variables:
765  * mode: c
766  * indent-tabs-mode: t
767  * c-basic-offset: 4
768  * tab-width: 4
769  * End:
770  * vim:noexpandtab:sw=4:ts=4:
771  */