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