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