Proper x86_64 mnemonics
[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/array.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    Creates an argument array which can be passed to asm_vm_call_method.
378    The array is created from the passed valist.
379
380    ATTENTION: This function has to be used outside the native world.
381
382 *******************************************************************************/
383
384 uint64_t *argument_vmarray_from_valist(methodinfo *m, java_handle_t *o, va_list ap)
385 {
386         methoddesc *md;
387         paramdesc  *pd;
388         typedesc   *td;
389         uint64_t   *array;
390         int32_t     i;
391         imm_union   value;
392
393         /* get the descriptors */
394
395         md = m->parseddesc;
396         pd = md->params;
397         td = md->paramtypes;
398
399         /* allocate argument array */
400
401         array = DMNEW(uint64_t, INT_ARG_CNT + FLT_ARG_CNT + md->memuse);
402
403         /* if method is non-static fill first block and skip `this' pointer */
404
405         i = 0;
406
407         if (o != NULL) {
408                 /* the `this' pointer */
409                 argument_vmarray_store_adr(array, pd, o);
410
411                 pd++;
412                 td++;
413                 i++;
414         } 
415
416         for (; i < md->paramcount; i++, pd++, td++) {
417                 switch (td->type) {
418                 case TYPE_INT:
419                         value.i = va_arg(ap, int32_t);
420                         argument_vmarray_store_int(array, pd, value.i);
421                         break;
422
423                 case TYPE_LNG:
424                         value.l = va_arg(ap, int64_t);
425                         argument_vmarray_store_lng(array, pd, value.l);
426                         break;
427
428                 case TYPE_FLT:
429 #if defined(__ALPHA__) || defined(__POWERPC__) || defined(__POWERPC64__)
430                         /* This is required to load the correct float value in
431                            assembler code. */
432
433                         value.d = (double) va_arg(ap, double);
434 #else
435                         value.f = (float) va_arg(ap, double);
436 #endif
437                         argument_vmarray_store_flt(array, pd, value.l);
438                         break;
439
440                 case TYPE_DBL:
441                         value.d = va_arg(ap, double);
442                         argument_vmarray_store_dbl(array, pd, value.l);
443                         break;
444
445                 case TYPE_ADR: 
446                         value.a = va_arg(ap, void*);
447                         argument_vmarray_store_adr(array, pd, value.a);
448                         break;
449                 }
450         }
451
452         return array;
453 }
454
455
456 /* argument_vmarray_from_jvalue ************************************************
457
458    Creates an argument array which can be passed to asm_vm_call_method.
459    The array is created from the passed jvalue array.
460
461    ATTENTION: This function has to be used outside the native world.
462
463 *******************************************************************************/
464
465 uint64_t *argument_vmarray_from_jvalue(methodinfo *m, java_handle_t *o,
466                                                                            const jvalue *args)
467 {
468         methoddesc *md;
469         paramdesc  *pd;
470         typedesc   *td;
471         uint64_t   *array;
472         int32_t     i;
473         int32_t     j;
474
475         /* get the descriptors */
476
477         md = m->parseddesc;
478         pd = md->params;
479         td = md->paramtypes;
480
481         /* allocate argument array */
482
483 #if defined(HAS_ADDRESS_REGISTER_FILE)
484         array = DMNEW(uint64_t, INT_ARG_CNT + FLT_ARG_CNT + ADR_ARG_CNT + md->memuse);
485 #else
486         array = DMNEW(uint64_t, INT_ARG_CNT + FLT_ARG_CNT + md->memuse);
487 #endif
488
489         /* if method is non-static fill first block and skip `this' pointer */
490
491         i = 0;
492
493         if (o != NULL) {
494                 /* the `this' pointer */
495                 argument_vmarray_store_adr(array, pd, o);
496
497                 pd++;
498                 td++;
499                 i++;
500         } 
501
502         for (j = 0; i < md->paramcount; i++, j++, pd++, td++) {
503                 switch (td->decltype) {
504                 case TYPE_INT:
505                         argument_vmarray_store_int(array, pd, args[j].i);
506                         break;
507
508                 case TYPE_LNG:
509                         argument_vmarray_store_lng(array, pd, args[j].j);
510                         break;
511
512                 case TYPE_FLT:
513                         argument_vmarray_store_flt(array, pd, args[j].j);
514                         break;
515
516                 case TYPE_DBL:
517                         argument_vmarray_store_dbl(array, pd, args[j].j);
518                         break;
519
520                 case TYPE_ADR: 
521                         argument_vmarray_store_adr(array, pd, (java_handle_t *) args[j].l);
522                         break;
523                 }
524         }
525
526         return array;
527 }
528
529
530 /* argument_vmarray_from_objectarray *******************************************
531
532    Creates an argument array which can be passed to asm_vm_call_method.
533    The array is created from the passed objectarray of boxed values.
534
535    ATTENTION: This function has to be used outside the native world.
536
537    RETURN VALUE:
538       NULL.........indicates an error while creating the array
539       (-1).........no error, but an empty array
540       otherwise....array containing the argument values
541
542 *******************************************************************************/
543
544 uint64_t *argument_vmarray_from_objectarray(methodinfo *m, java_handle_t *o,
545                                                                                         java_handle_objectarray_t *params)
546 {
547         methoddesc    *md;
548         paramdesc     *pd;
549         typedesc      *td;
550         uint64_t      *array;
551         java_handle_t *param;
552         classinfo     *c;
553         int            type;
554         int32_t        i;
555         int32_t        j;
556         imm_union      value;
557
558         /* get the descriptors */
559
560         md = m->parseddesc;
561         pd = md->params;
562         td = md->paramtypes;
563
564         /* allocate argument array */
565
566         array = DMNEW(uint64_t, INT_ARG_CNT + FLT_ARG_CNT + md->memuse);
567
568         /* The array can be NULL if we don't have any arguments to pass
569            and the architecture does not have any argument registers
570            (e.g. i386).  In that case we return (-1) to indicate
571            that no exception should be thrown */
572
573         if (array == NULL)
574                 array = (uint64_t *)(-1);
575
576         /* if method is non-static fill first block and skip `this' pointer */
577
578         i = 0;
579
580         if (o != NULL) {
581                 /* this pointer */
582                 argument_vmarray_store_adr(array, pd, o);
583
584                 pd++;
585                 td++;
586                 i++;
587         }
588
589         for (j = 0; i < md->paramcount; i++, j++, pd++, td++) {
590                 /* XXX This function can throw an exception, which should not happend
591                    here, since we are outside the nativeworld. */
592                 param = array_objectarray_element_get(params, j);
593
594                 switch (td->type) {
595                 case TYPE_INT:
596                         if (param == NULL)
597                                 return NULL;
598
599                         /* convert the value according to its declared type */
600
601                         LLNI_class_get(param, c);
602                         type = primitive_type_get_by_wrapperclass(c);
603
604                         switch (td->decltype) {
605                         case PRIMITIVETYPE_BOOLEAN:
606                                 switch (type) {
607                                 case PRIMITIVETYPE_BOOLEAN:
608                                         /* This type is OK. */
609                                         break;
610                                 default:
611                                         return NULL;
612                                 }
613                                 break;
614
615                         case PRIMITIVETYPE_BYTE:
616                                 switch (type) {
617                                 case PRIMITIVETYPE_BYTE:
618                                         /* This type is OK. */
619                                         break;
620                                 default:
621                                         return NULL;
622                                 }
623                                 break;
624
625                         case PRIMITIVETYPE_CHAR:
626                                 switch (type) {
627                                 case PRIMITIVETYPE_CHAR:
628                                         /* This type is OK. */
629                                         break;
630                                 default:
631                                         return NULL;
632                                 }
633                                 break;
634
635                         case PRIMITIVETYPE_SHORT:
636                                 switch (type) {
637                                 case PRIMITIVETYPE_BYTE:
638                                 case PRIMITIVETYPE_SHORT:
639                                         /* These types are OK. */
640                                         break;
641                                 default:
642                                         return NULL;
643                                 }
644                                 break;
645
646                         case PRIMITIVETYPE_INT:
647                                 switch (type) {
648                                 case PRIMITIVETYPE_BYTE:
649                                 case PRIMITIVETYPE_SHORT:
650                                 case PRIMITIVETYPE_INT:
651                                         /* These types are OK. */
652                                         break;
653                                 default:
654                                         return NULL;
655                                 }
656                                 break;
657
658                         default:
659                                 vm_abort("argument_vmarray_from_objectarray: invalid type %d",
660                                                  td->decltype);
661                         }
662
663                         value = primitive_unbox(param);
664                         argument_vmarray_store_int(array, pd, value.i);
665                         break;
666
667                 case TYPE_LNG:
668                         if (param == NULL)
669                                 return NULL;
670
671                         LLNI_class_get(param, c);
672                         type = primitive_type_get_by_wrapperclass(c);
673
674                         assert(td->decltype == PRIMITIVETYPE_LONG);
675
676                         switch (type) {
677                         case PRIMITIVETYPE_BYTE:
678                         case PRIMITIVETYPE_SHORT:
679                         case PRIMITIVETYPE_INT:
680                         case PRIMITIVETYPE_LONG:
681                                 /* These types are OK. */
682                                 break;
683                         default:
684                                 return NULL;
685                         }
686
687                         value = primitive_unbox(param);
688                         argument_vmarray_store_lng(array, pd, value.l);
689                         break;
690
691                 case TYPE_FLT:
692                         if (param == NULL)
693                                 return NULL;
694
695                         LLNI_class_get(param, c);
696                         type = primitive_type_get_by_wrapperclass(c);
697
698                         assert(td->decltype == PRIMITIVETYPE_FLOAT);
699
700                         switch (type) {
701                         case PRIMITIVETYPE_FLOAT:
702                                 /* This type is OK. */
703                                 break;
704                         default:
705                                 return NULL;
706                         }
707
708                         value = primitive_unbox(param);
709                         argument_vmarray_store_flt(array, pd, value.l);
710                         break;
711
712                 case TYPE_DBL:
713                         if (param == NULL)
714                                 return NULL;
715
716                         LLNI_class_get(param, c);
717                         type = primitive_type_get_by_wrapperclass(c);
718
719                         assert(td->decltype == PRIMITIVETYPE_DOUBLE);
720
721                         switch (type) {
722                         case PRIMITIVETYPE_FLOAT:
723                         case PRIMITIVETYPE_DOUBLE:
724                                 /* These types are OK. */
725                                 break;
726                         default:
727                                 return NULL;
728                         }
729
730                         value = primitive_unbox(param);
731                         argument_vmarray_store_dbl(array, pd, value.l);
732                         break;
733                 
734                 case TYPE_ADR:
735                         if (!resolve_class_from_typedesc(td, true, true, &c))
736                                 return NULL;
737
738                         if (param != NULL) {
739                                 if (td->arraydim > 0) {
740                                         if (!builtin_arrayinstanceof(param, c))
741                                                 return NULL;
742                                 }
743                                 else {
744                                         if (!builtin_instanceof(param, c))
745                                                 return NULL;
746                                 }
747                         }
748
749                         argument_vmarray_store_adr(array, pd, param);
750                         break;
751
752                 default:
753                         vm_abort("argument_vmarray_from_objectarray: invalid type %d", td->type);
754                 }
755         }
756
757         return array;
758 }
759
760
761 /*
762  * These are local overrides for various environment variables in Emacs.
763  * Please do not remove this and leave it at the end of the file, where
764  * Emacs will automagically detect them.
765  * ---------------------------------------------------------------------
766  * Local variables:
767  * mode: c
768  * indent-tabs-mode: t
769  * c-basic-offset: 4
770  * tab-width: 4
771  * End:
772  * vim:noexpandtab:sw=4:ts=4:
773  */