svn path=/branches/mono-1-1-9/mono/; revision=51217
[mono.git] / mono / arch / s390 / tramp.c
1 /*------------------------------------------------------------------*/
2 /*                                                                  */
3 /* Name        - tramp.c                                            */
4 /*                                                                  */
5 /* Function    - Create trampolines to invoke arbitrary functions.  */
6 /*                                                                  */
7 /* Name        - Neale Ferguson.                                    */
8 /*                                                                  */
9 /* Date        - October, 2002                                      */
10 /*                                                                  */
11 /*                                                                  */
12 /*------------------------------------------------------------------*/
13
14 /*------------------------------------------------------------------*/
15 /*                 D e f i n e s                                    */
16 /*------------------------------------------------------------------*/
17
18 #define PROLOG_INS      24      /* Size of emitted prolog           */
19 #define CALL_INS        4       /* Size of emitted call             */
20 #define EPILOG_INS      18      /* Size of emitted epilog           */
21
22 #define DEBUG(x)
23
24 /*========================= End of Defines =========================*/
25
26 /*------------------------------------------------------------------*/
27 /*                 I n c l u d e s                                  */
28 /*------------------------------------------------------------------*/
29
30 #ifdef NEED_MPROTECT
31 # include <sys/mman.h>
32 # include <limits.h>    /* for PAGESIZE */
33 # ifndef PAGESIZE
34 #  define PAGESIZE 4096
35 # endif
36 #endif
37
38 #include "config.h"
39 #include <stdlib.h>
40 #include <string.h>
41 #include "s390-codegen.h"
42 #include "mono/metadata/class.h"
43 #include "mono/metadata/tabledefs.h"
44 #include "mono/interpreter/interp.h"
45 #include "mono/metadata/appdomain.h"
46 #include "mono/metadata/marshal.h"
47
48 /*========================= End of Includes ========================*/
49
50 /*------------------------------------------------------------------*/
51 /*                 T y p e d e f s                                  */
52 /*------------------------------------------------------------------*/
53
54 /*------------------------------------------------------------------*/
55 /* Structure used to accummulate size of stack, code, and locals    */
56 /*------------------------------------------------------------------*/
57 typedef struct {
58         guint stack_size,
59               local_size,
60               code_size,
61               retStruct;
62 } size_data;    
63
64 /*========================= End of Typedefs ========================*/
65 \f
66 /*------------------------------------------------------------------*/
67 /*                                                                  */
68 /* Name         - add_general                                       */
69 /*                                                                  */
70 /* Function     - Determine code and stack size incremements for a  */
71 /*                parameter.                                        */
72 /*                                                                  */
73 /*------------------------------------------------------------------*/
74
75 static void inline
76 add_general (guint *gr, size_data *sz, gboolean simple)
77 {
78         if (simple) {
79                 if (*gr >= GENERAL_REGS) {
80                         sz->stack_size += sizeof(long);
81                         sz->code_size  += 12;    
82                 } else {
83                         sz->code_size += 8;    
84                 }
85         } else {
86                 if (*gr >= GENERAL_REGS - 1) {
87                         sz->stack_size += 8 + (sz->stack_size % 8);
88                         sz->code_size  += 10;   
89                 } else {
90                         sz->code_size += 8;
91                 }
92                 (*gr) ++;
93         }
94         (*gr) ++;
95 }
96
97 /*========================= End of Function ========================*/
98 \f
99 /*------------------------------------------------------------------*/
100 /*                                                                  */
101 /* Name         - calculate_sizes                                   */
102 /*                                                                  */
103 /* Function     - Determine the amount of space required for code   */
104 /*                and stack. In addition determine starting points  */
105 /*                for stack-based parameters, and area for struct-  */
106 /*                ures being returned on the stack.                 */
107 /*                                                                  */
108 /*------------------------------------------------------------------*/
109
110 static void inline
111 calculate_sizes (MonoMethodSignature *sig, size_data *sz, 
112                  gboolean string_ctor)
113 {
114         guint i, fr, gr, size;
115         guint32 simpletype, align;
116
117         fr             = 0;
118         gr             = 2;
119         sz->retStruct  = 0;
120         sz->stack_size = S390_MINIMAL_STACK_SIZE;
121         sz->code_size  = (PROLOG_INS + CALL_INS + EPILOG_INS);
122         sz->local_size = 0;
123
124         if (sig->hasthis) {
125                 add_general (&gr, sz, TRUE);
126         }
127
128         /*----------------------------------------------------------*/
129         /* We determine the size of the return code/stack in case we*/
130         /* need to reserve a register to be used to address a stack */
131         /* area that the callee will use.                           */
132         /*----------------------------------------------------------*/
133
134         if (sig->ret->byref || string_ctor) {
135                 sz->code_size += 8;
136         } else {
137                 simpletype = sig->ret->type;
138 enum_retvalue:
139                 switch (simpletype) {
140                 case MONO_TYPE_BOOLEAN:
141                 case MONO_TYPE_I1:
142                 case MONO_TYPE_U1:
143                 case MONO_TYPE_I2:
144                 case MONO_TYPE_U2:
145                 case MONO_TYPE_CHAR:
146                 case MONO_TYPE_I4:
147                 case MONO_TYPE_U4:
148                 case MONO_TYPE_I:
149                 case MONO_TYPE_U:
150                 case MONO_TYPE_CLASS:
151                 case MONO_TYPE_OBJECT:
152                 case MONO_TYPE_R4:
153                 case MONO_TYPE_R8:
154                 case MONO_TYPE_SZARRAY:
155                 case MONO_TYPE_ARRAY:
156                 case MONO_TYPE_STRING:
157                         sz->code_size += 4;
158                         break;
159                 case MONO_TYPE_I8:
160                         sz->code_size += 4;
161                         break;
162                 case MONO_TYPE_VALUETYPE:
163                         if (sig->ret->data.klass->enumtype) {
164                                 simpletype = sig->ret->data.klass->enum_basetype->type;
165                                 goto enum_retvalue;
166                         }
167                         gr++;
168                         if (sig->pinvoke)
169                                 size = mono_class_native_size (sig->ret->data.klass, &align);
170                         else
171                                 size = mono_class_value_size (sig->ret->data.klass, &align);
172                         if (align > 1)
173                                 sz->code_size += 10;
174                         switch (size) {
175                                 /*----------------------------------*/
176                                 /* On S/390, structures of size 1,  */
177                                 /* 2, 4, and 8 bytes are returned   */
178                                 /* in (a) register(s).              */
179                                 /*----------------------------------*/
180                                 case 1:
181                                 case 2:
182                                 case 4:
183                                 case 8:
184                                         sz->code_size  += 16;
185                                         sz->stack_size += 4;
186                                         break;
187                                 default:
188                                         sz->retStruct   = 1;
189                                         sz->code_size  += 32;
190                         }
191                         break;
192                 case MONO_TYPE_VOID:
193                         break;
194                 default:
195                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
196                 }
197         }
198
199         /*----------------------------------------------------------*/
200         /* We determine the size of the parameter code and stack    */
201         /* requirements by checking the types and sizes of the      */
202         /* parameters.                                              */
203         /*----------------------------------------------------------*/
204
205         for (i = 0; i < sig->param_count; ++i) {
206                 if (sig->params [i]->byref) {
207                         add_general (&gr, sz, TRUE);
208                         continue;
209                 }
210                 simpletype = sig->params [i]->type;
211         enum_calc_size:
212                 switch (simpletype) {
213                 case MONO_TYPE_BOOLEAN:
214                 case MONO_TYPE_CHAR:
215                 case MONO_TYPE_I1:
216                 case MONO_TYPE_U1:
217                 case MONO_TYPE_I2:
218                 case MONO_TYPE_U2:
219                 case MONO_TYPE_I4:
220                 case MONO_TYPE_U4:
221                 case MONO_TYPE_I:
222                 case MONO_TYPE_U:
223                 case MONO_TYPE_PTR:
224                 case MONO_TYPE_CLASS:
225                 case MONO_TYPE_OBJECT:
226                 case MONO_TYPE_STRING:
227                         add_general (&gr, sz, TRUE);
228                         break;
229                 case MONO_TYPE_SZARRAY:
230                         add_general (&gr, sz, TRUE);
231                         break;
232                 case MONO_TYPE_VALUETYPE:
233                         if (sig->params [i]->data.klass->enumtype) {
234                                 simpletype = sig->params [i]->data.klass->enum_basetype->type;
235                                 goto enum_calc_size;
236                         }
237                         if (sig->pinvoke)
238                                 size = mono_class_native_size (sig->params [i]->data.klass, &align);
239                         else
240                                 size = mono_class_value_size (sig->params [i]->data.klass, &align);
241                         DEBUG(printf("%d typesize: %d (%d)\n",i,size,align));
242                         switch (size) {
243                                 /*----------------------------------*/
244                                 /* On S/390, structures of size 1,  */
245                                 /* 2, 4, and 8 bytes are passed in  */
246                                 /* (a) register(s).                 */
247                                 /*----------------------------------*/
248                                 case 0:
249                                 case 1:
250                                 case 2:
251                                 case 4:
252                                         add_general(&gr, sz, TRUE);
253                                         break;
254                                 case 8:
255                                         add_general(&gr, sz, FALSE);
256                                         break;
257                                 default:
258                                         sz->local_size += (size + (size % align));
259                                         sz->code_size  += 40;
260                         }
261                         break;
262                 case MONO_TYPE_I8:
263                         add_general (&gr, sz, FALSE);
264                         break;
265                 case MONO_TYPE_R4:
266                         if (fr < FLOAT_REGS) {
267                                 sz->code_size += 4;
268                                 fr++;
269                         }
270                         else {
271                                 sz->code_size  += 4;
272                                 sz->stack_size += 8;
273                         }
274                         break;
275                 case MONO_TYPE_R8:
276                         if (fr < FLOAT_REGS) {
277                                 sz->code_size += 4;
278                                 fr++;
279                         } else {
280                                 sz->code_size  += 4;
281                                 sz->stack_size += 8 + (sz->stack_size % 8);
282                         }
283                         break;
284                 default:
285                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
286                 }
287         }
288
289
290         /* align stack size to 8 */
291         DEBUG (printf ("      stack size: %d (%d)\n"
292                        "       code size: %d\n" 
293                        "      local size: %d\n",
294                       (sz->stack_size + 8) & ~8, sz->stack_size, 
295                       (sz->code_size),(sz->local_size + 8) & ~8));
296         sz->stack_size = (sz->stack_size + 8) & ~8;
297         sz->local_size = (sz->local_size + 8) & ~8;
298 }
299
300 /*========================= End of Function ========================*/
301 \f
302 /*------------------------------------------------------------------*/
303 /*                                                                  */
304 /* Name         - emit_prolog                                       */
305 /*                                                                  */
306 /* Function     - Create the instructions that implement the stand- */
307 /*                ard function prolog according to the S/390 ABI.   */
308 /*                                                                  */
309 /*------------------------------------------------------------------*/
310
311 static inline guint8 *
312 emit_prolog (guint8 *p, MonoMethodSignature *sig, size_data *sz)
313 {
314         guint stack_size;
315
316         stack_size = sz->stack_size + sz->local_size;
317
318         /* function prolog */
319         s390_stm (p, s390_r6, STK_BASE, STK_BASE, 24);
320         s390_l   (p, s390_r7, 0, STK_BASE, MINV_POS);
321         s390_lr  (p, s390_r11, STK_BASE);
322         s390_ahi (p, STK_BASE, -stack_size);
323         s390_st  (p, s390_r11, 0, STK_BASE, 0);
324
325         /*-----------------------------------------*/
326         /* Save:                                   */
327         /* - address of "callme"                   */
328         /* - address of "retval"                   */
329         /* - address of "arguments"                */
330         /*-----------------------------------------*/
331         s390_lr  (p, s390_r9, s390_r2);
332         s390_lr  (p, s390_r8, s390_r3);
333         s390_lr  (p, s390_r10, s390_r5);
334
335         return p;
336 }
337
338 /*========================= End of Function ========================*/
339 \f
340 /*------------------------------------------------------------------*/
341 /*                                                                  */
342 /* Name         - emit_save_parameters                              */
343 /*                                                                  */
344 /* Function     - Create the instructions that load registers with  */ 
345 /*                parameters, place others on the stack according   */
346 /*                to the S/390 ABI.                                 */
347 /*                                                                  */
348 /*                The resulting function takes the form:            */
349 /*                void func (void (*callme)(), void *retval,        */
350 /*                           void *this_obj, stackval *arguments);  */
351 /*                                                                  */
352 /*------------------------------------------------------------------*/
353
354 inline static guint8*
355 emit_save_parameters (guint8 *p, MonoMethodSignature *sig, size_data *sz)
356 {
357         guint i, fr, gr, act_strs, align, 
358               stack_par_pos, size, local_pos;
359         guint32 simpletype;
360
361         /*----------------------------------------------------------*/
362         /* If a structure on stack is being returned, reserve r2    */ 
363         /* to point to an area where it can be passed.              */
364         /*----------------------------------------------------------*/
365         if (sz->retStruct)
366                 gr    = 1;
367         else
368                 gr    = 0;
369         fr            = 0;
370         act_strs      = 0;
371         stack_par_pos = S390_MINIMAL_STACK_SIZE;
372         local_pos     = sz->stack_size;
373
374         if (sig->hasthis) {
375                 s390_lr (p, s390_r2 + gr, s390_r4);
376                 gr++;
377         }
378
379         act_strs = 0;
380         for (i = 0; i < sig->param_count; ++i) {
381                 DEBUG(printf("par: %d type: %d ref: %d\n",i,sig->params[i]->type,sig->params[i]->byref));
382                 if (sig->params [i]->byref) {
383                         if (gr < GENERAL_REGS) {
384                                 s390_l  (p, s390_r2 + gr, 0, ARG_BASE, STKARG);
385                                 gr ++;
386                         } else {
387                                 s390_l  (p, s390_r0, 0, ARG_BASE, STKARG);
388                                 s390_st (p, s390_r0, 0, STK_BASE, stack_par_pos);
389                                 stack_par_pos += sizeof(long);
390                         }
391                         continue;
392                 }
393                 simpletype = sig->params [i]->type;
394         enum_calc_size:
395                 switch (simpletype) {
396                 case MONO_TYPE_BOOLEAN:
397                 case MONO_TYPE_I1:
398                 case MONO_TYPE_U1:
399                 case MONO_TYPE_I2:
400                 case MONO_TYPE_U2:
401                 case MONO_TYPE_CHAR:
402                 case MONO_TYPE_I4:
403                 case MONO_TYPE_U4:
404                 case MONO_TYPE_I:
405                 case MONO_TYPE_U:
406                 case MONO_TYPE_PTR:
407                 case MONO_TYPE_CLASS:
408                 case MONO_TYPE_OBJECT:
409                 case MONO_TYPE_STRING:
410                 case MONO_TYPE_SZARRAY:
411                         if (gr < GENERAL_REGS) {
412                                 s390_l  (p, s390_r2 + gr, 0, ARG_BASE, STKARG);
413                                 gr ++;
414                         } else {
415                                 s390_l  (p, s390_r0, 0, ARG_BASE, STKARG);
416                                 s390_st (p, s390_r0, 0, STK_BASE, stack_par_pos);
417                                 stack_par_pos += sizeof(long);
418                         }
419                         break;
420                 case MONO_TYPE_VALUETYPE:
421                         if (sig->params [i]->data.klass->enumtype) {
422                                 simpletype = sig->params [i]->data.klass->enum_basetype->type;
423                                 goto enum_calc_size;
424                         }
425                         if (sig->pinvoke) 
426                                 size = mono_class_native_size (sig->params [i]->data.klass, &align);
427                         else
428                                 size = mono_class_value_size (sig->params [i]->data.klass, &align);
429                         DEBUG(printf("parStruct - size %d pinvoke: %d\n",size,sig->pinvoke));
430                         switch (size) {
431                                 case 0:
432                                 case 1:
433                                 case 2:
434                                 case 4:
435                                         if (gr < GENERAL_REGS) {
436                                                 s390_l  (p, s390_r2 + gr, 0,ARG_BASE, STKARG);
437                                                 s390_l  (p, s390_r2 + gr, 0, s390_r2 + gr, 0);
438                                                 gr++;
439                                         } else {
440                                                 stack_par_pos += (stack_par_pos % align);
441                                                 s390_l  (p, s390_r10, 0,ARG_BASE, STKARG);
442                                                 s390_l  (p, s390_r10, 0, s390_r10, 0);
443                                                 s390_st (p, s390_r10, 0, STK_BASE, stack_par_pos);
444                                                 stack_par_pos += sizeof(long);
445                                         }
446                                         break;
447                                 case 8:
448                                         if (gr < GENERAL_REGS-1) {
449                                                 s390_l  (p, s390_r2 + gr, 0, ARG_BASE, STKARG);
450                                                 s390_lm (p, s390_r2 + gr, s390_r3 + gr, s390_r2 + gr, 0);
451                                         } else {
452                                                 stack_par_pos += (stack_par_pos % align);
453                                                 s390_l   (p, s390_r10, 0, ARG_BASE, STKARG);
454                                                 s390_mvc (p, sizeof(long long), STK_BASE, stack_par_pos, s390_r10, 0);
455                                                 stack_par_pos += sizeof(long long);
456                                         }
457                                         break;  
458                                 default:
459                                         if (size <= 256) {
460                                                 local_pos += (local_pos % align);
461                                                 s390_l   (p, s390_r13, 0, ARG_BASE, STKARG);
462                                                 s390_mvc (p, size, STK_BASE, local_pos, s390_r13, 0);
463                                                 s390_la  (p, s390_r13, 0, STK_BASE, local_pos);
464                                                 local_pos += size;
465                                         } else {
466                                                 local_pos += (local_pos % align);
467                                                 s390_bras (p, s390_r13, 4);
468                                                 s390_word (p, size);
469                                                 s390_l    (p, s390_r1, 0, s390_r13, 0);
470                                                 s390_l    (p, s390_r0, 0, ARG_BASE, STKARG);
471                                                 s390_lr   (p, s390_r14, s390_r12);
472                                                 s390_la   (p, s390_r12, 0, STK_BASE, local_pos);
473                                                 s390_lr   (p, s390_r13, s390_r1);
474                                                 s390_mvcl (p, s390_r12, s390_r0);
475                                                 s390_lr   (p, s390_r12, s390_r14);
476                                                 s390_la   (p, s390_r13, 0, STK_BASE, local_pos);
477                                                 local_pos += size;
478                                         }
479                                         if (gr < GENERAL_REGS) {
480                                                 s390_lr (p, s390_r2 + gr, s390_r13);
481                                                 gr++;
482                                         } else {
483                                                 s390_st (p, s390_r13, 0, STK_BASE, stack_par_pos);
484                                                 stack_par_pos += sizeof(long);
485                                         }
486                         }
487                         break;
488                 case MONO_TYPE_I8:
489                         if (gr < GENERAL_REGS-1) {
490                                 s390_lm  (p, s390_r2 + gr, s390_r2 + gr + 1, ARG_BASE, STKARG); 
491                                 gr += 2;
492                         } else {
493                                 *(guint32 *) p += 7;
494                                 *(guint32 *) p &= ~7;
495                                 s390_mvc (p, sizeof(long long), STK_BASE, stack_par_pos, ARG_BASE, STKARG); 
496                                 stack_par_pos += sizeof(long long) + (stack_par_pos % sizeof(long long));
497                         }
498                         break;
499                 case MONO_TYPE_R4:
500                         if (fr < FLOAT_REGS) {
501                                 s390_le  (p, s390_r0 + fr, 0, ARG_BASE, STKARG);
502                                 fr++;
503                         } else {
504                                 s390_mvc  (p, sizeof(float), STK_BASE, stack_par_pos, ARG_BASE, STKARG);
505                                 stack_par_pos += sizeof(float);
506                         }
507                         break;
508                 case MONO_TYPE_R8:
509                         if (fr < FLOAT_REGS) {
510                                 s390_ld  (p, s390_r0 + fr, 0, ARG_BASE, STKARG);
511                                 fr++;
512                         } else {
513                                 *(guint32 *) p += 7;
514                                 *(guint32 *) p &= ~7;
515                                 s390_mvc  (p, sizeof(double), STK_BASE, stack_par_pos, ARG_BASE, STKARG);
516                                 stack_par_pos += sizeof(long long) + (stack_par_pos % sizeof(long long));
517                         }
518                         break;
519                 default:
520                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
521                 }
522         }
523
524         /*----------------------------------------------------------*/
525         /* If we're returning a structure but not in a register     */ 
526         /* then point the result area for the called routine        */
527         /*----------------------------------------------------------*/
528         if (sz->retStruct) {
529                 s390_l  (p, s390_r2, 0, s390_r8, 0);
530         }
531
532         return p;
533 }
534
535 /*========================= End of Function ========================*/
536 \f
537 /*------------------------------------------------------------------*/
538 /*                                                                  */
539 /* Name         - alloc_code_memory                                 */
540 /*                                                                  */
541 /* Function     - Allocate space to place the emitted code.         */
542 /*                                                                  */
543 /*------------------------------------------------------------------*/
544
545 static inline guint8 *
546 alloc_code_memory (guint code_size)
547 {
548         guint8 *p;
549
550 #ifdef NEED_MPROTECT
551         p = g_malloc (code_size + PAGESIZE - 1);
552
553         /* Align to a multiple of PAGESIZE, assumed to be a power of two */
554         p = (char *)(((int) p + PAGESIZE-1) & ~(PAGESIZE-1));
555 #else
556         p = g_malloc (code_size);
557 #endif
558         DEBUG (printf ("           align: %p (%d)\n", p, (guint)p % 4));
559
560         return p;
561 }
562
563 /*========================= End of Function ========================*/
564 \f
565 /*------------------------------------------------------------------*/
566 /*                                                                  */
567 /* Name         - emit_call_and_store_retval                        */
568 /*                                                                  */
569 /* Function     - Emit code that will implement the call to the     */
570 /*                desired function, and unload the result according */
571 /*                to the S390 ABI for the type of value returned    */
572 /*                                                                  */
573 /*------------------------------------------------------------------*/
574
575 static inline guint8 *
576 emit_call_and_store_retval (guint8 *p, MonoMethodSignature *sig, 
577                             size_data *sz, gboolean string_ctor)
578 {
579         guint32 simpletype;
580         guint   retSize, align;
581
582         /* call "callme" */
583         s390_basr (p, s390_r14, s390_r9); 
584
585         /* get return value */
586         if (sig->ret->byref || string_ctor) {
587                 s390_st (p, s390_r2, 0, s390_r8, 0);
588         } else {
589                 simpletype = sig->ret->type;
590 enum_retvalue:
591                 switch (simpletype) {
592                 case MONO_TYPE_BOOLEAN:
593                 case MONO_TYPE_I1:
594                 case MONO_TYPE_U1:
595                         s390_stc (p, s390_r2, 0, s390_r8, 0);
596                         break;
597                 case MONO_TYPE_I2:
598                 case MONO_TYPE_U2:
599                 case MONO_TYPE_CHAR:
600                         s390_sth (p, s390_r2, 0, s390_r8, 0);
601                         break;
602                 case MONO_TYPE_I4:
603                 case MONO_TYPE_U4:
604                 case MONO_TYPE_I:
605                 case MONO_TYPE_U:
606                 case MONO_TYPE_CLASS:
607                 case MONO_TYPE_OBJECT:
608                 case MONO_TYPE_SZARRAY:
609                 case MONO_TYPE_ARRAY:
610                 case MONO_TYPE_STRING:
611                         s390_st (p, s390_r2, 0, s390_r8, 0);
612                         break;
613                 case MONO_TYPE_R4:
614                         s390_ste (p, s390_f0, 0, s390_r8, 0);
615                         break;
616                 case MONO_TYPE_R8:
617                         s390_std (p, s390_f0, 0, s390_r8, 0);
618                         break;
619                 case MONO_TYPE_I8:
620                         s390_stm (p, s390_r2, s390_r3, s390_r8, 0);
621                         break;
622                 case MONO_TYPE_VALUETYPE:
623                         if (sig->ret->data.klass->enumtype) {
624                                 simpletype = sig->ret->data.klass->enum_basetype->type;
625                                 goto enum_retvalue;
626                         }
627                         if (sig->pinvoke) 
628                                 retSize = mono_class_native_size (sig->ret->data.klass, &align);
629                         else
630                                 retSize = mono_class_value_size (sig->ret->data.klass, &align);
631 printf("Returning %d bytes for type %d (%d)\n",retSize,simpletype,sig->pinvoke);
632                         switch(retSize) {
633                         case 0:
634                                 break;
635                         case 1:
636                                 s390_stc (p, s390_r2, 0, s390_r8, 0);
637                                 break;
638                         case 2:
639                                 s390_sth (p, s390_r2, 0, s390_r8, 0);
640                                 break;
641                         case 4:
642                                 s390_st (p, s390_r2, 0, s390_r8, 0);
643                                 break;
644                         case 8:
645                                 s390_stm (p, s390_r2, s390_r3, s390_r8, 0);
646                                 break;
647                         default:
648                                 /*------------------------------------------*/
649                                 /* The callee has already placed the result */
650                                 /* in the required area                     */
651                                 /*------------------------------------------*/
652                         }
653                         break;
654                 case MONO_TYPE_VOID:
655                         break;
656                 default:
657                         g_error ("Can't handle as return value 0x%x", 
658                                  sig->ret->type);
659                 }
660         }
661
662         return p;
663 }
664
665 /*========================= End of Function ========================*/
666 \f
667 /*------------------------------------------------------------------*/
668 /*                                                                  */
669 /* Name         - emit_epilog                                       */
670 /*                                                                  */
671 /* Function     - Create the instructions that implement the stand- */
672 /*                ard function epilog according to the S/390 ABI.   */
673 /*                                                                  */
674 /*------------------------------------------------------------------*/
675
676 static inline guint8 *
677 emit_epilog (guint8 *p, MonoMethodSignature *sig, size_data *sz)
678 {
679         /* function epilog */
680         s390_l   (p, STK_BASE, 0, STK_BASE, 0);
681         s390_l   (p, s390_r4, 0, STK_BASE, 56);
682         s390_lm  (p, s390_r6, STK_BASE, STK_BASE, 24);
683         s390_br  (p, s390_r4);
684
685         return p;
686 }
687
688 /*========================= End of Function ========================*/
689 \f
690 /*------------------------------------------------------------------*/
691 /*                                                                  */
692 /* Name         - mono_arch_create_trampoline.                      */
693 /*                                                                  */
694 /* Function     - Create the code that will allow a mono method to  */
695 /*                invoke a system subroutine.                       */
696 /*                                                                  */
697 /*------------------------------------------------------------------*/
698
699 MonoPIFunc
700 mono_arch_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor)
701 {
702         guint8 *p, *code_buffer;
703         size_data sz;
704
705         DEBUG (printf ("\nPInvoke [start emiting]\n"));
706         calculate_sizes (sig, &sz, string_ctor);
707
708         p = code_buffer = alloc_code_memory (sz.code_size);
709         p = emit_prolog (p, sig, &sz);
710         p = emit_save_parameters (p, sig, &sz);
711         p = emit_call_and_store_retval (p, sig, &sz, string_ctor);
712         p = emit_epilog (p, sig, &sz);
713
714 #ifdef NEED_MPROTECT
715         if (mprotect (code_buffer, 1024, PROT_READ | PROT_WRITE | PROT_EXEC)) {
716                 g_error ("Cannot mprotect trampoline\n");
717         }
718 #endif
719
720         DEBUG (printf ("emited code size: %d\n", p - code_buffer));
721
722         DEBUG (printf ("PInvoke [end emiting]\n"));
723
724         return (MonoPIFunc) code_buffer;
725 }
726
727 /*========================= End of Function ========================*/
728 \f
729 /*------------------------------------------------------------------*/
730 /*                                                                  */
731 /* Name         - mono_arch_create_method_pointer                   */
732 /*                                                                  */
733 /* Function     - Returns a pointer to a native function that can   */
734 /*                be used to call the specified method.             */
735 /*                                                                  */
736 /*                The function created will receive the arguments   */
737 /*                according to the calling convention specified in  */
738 /*                in the method.                                    */
739 /*                                                                  */
740 /*                This function works by creating a MonoInvocation  */
741 /*                structure, filling the fields in and calling      */
742 /*                ves_exec_method() on it.                          */
743 /*                                                                  */
744 /* Logic:                                                           */
745 /* ------                                                           */
746 /*  mono_arch_create_method_pointer (MonoMethod *method)            */
747 /*      create the unmanaged->managed wrapper                       */
748 /*      register it with mono_jit_info_table_add()                  */
749 /*                                                                  */
750 /*  What does the unmanaged->managed wrapper do?                    */
751 /*      allocate a MonoInvocation structure (inv) on the stack      */
752 /*      allocate an array of stackval on the stack with length =    */
753 /*          method->signature->param_count + 1 [call it stack_args] */
754 /*      set inv->ex, inv->ex_handler, inv->parent to NULL           */
755 /*      set inv->method to method                                   */
756 /*      if method is an instance method, set inv->obj to the        */
757 /*          'this' argument (the first argument) else set to NULL   */
758 /*      for each argument to the method call:                       */
759 /*              stackval_from_data (sig->params[i], &stack_args[i], */
760 /*                                  arg, sig->pinvoke);             */
761 /*              Where:                                              */
762 /*              ------                                              */
763 /*              sig             - is method->signature              */
764 /*              &stack_args[i]  - is the pointer to the ith element */
765 /*                                in the stackval array             */
766 /*              arg             - is a pointer to the argument re-  */
767 /*                                ceived by the function according  */
768 /*                                to the call convention. If it     */
769 /*                                gets passed in a register, save   */
770 /*                                on the stack first.               */
771 /*                                                                  */
772 /*      set inv->retval to the address of the last element of       */
773 /*          stack_args [recall we allocated param_count+1 of them]  */
774 /*      call ves_exec_method(inv)                                   */
775 /*      copy the returned value from inv->retval where the calling  */
776 /*          convention expects to find it on return from the wrap-  */
777 /*          per [if it's a structure, use stackval_to_data]         */
778 /*                                                                  */
779 /*------------------------------------------------------------------*/
780
781 void *
782 mono_arch_create_method_pointer (MonoMethod *method)
783 {
784         MonoMethodSignature *sig;
785         MonoJitInfo *ji;
786         guint8 *p, *code_buffer;
787         guint i, align = 0, simple_type, retSize, reg_save = 0,
788                 stackval_arg_pos, local_pos, float_pos,
789                 local_start, reg_param = 0, stack_param,
790                 this_flag, arg_pos, fpr_param, parSize;
791         guint32 simpletype;
792         size_data sz;
793         int *vtbuf, cpos, vt_cur;
794
795         sz.code_size   = 1024;
796         sz.stack_size  = 1024;
797         stack_param     = 0;
798         fpr_param       = 0;
799         arg_pos         = 0;
800
801         sig = method->signature;
802
803         p = code_buffer = g_malloc (sz.code_size);
804
805         DEBUG (printf ("\nDelegate [start emiting] %s at 0x%08x\n", 
806                        method->name,p));
807
808         /*----------------------------------------------------------*/ 
809         /* prolog                                                   */
810         /*----------------------------------------------------------*/ 
811         s390_stm (p, s390_r6, STK_BASE, STK_BASE, 24);
812         s390_l   (p, s390_r7, 0, STK_BASE, MINV_POS);
813         s390_lr  (p, s390_r0, STK_BASE);
814         s390_ahi (p, STK_BASE, -(sz.stack_size+MINV_POS));
815         s390_st  (p, s390_r0, 0, STK_BASE, 0);
816         s390_la  (p, s390_r8, 0, STK_BASE, 4);
817         s390_lr  (p, s390_r10, s390_r8);
818         s390_lhi (p, s390_r9, sz.stack_size+92);
819         s390_lhi (p, s390_r11, 0);
820         s390_mvcl(p, s390_r8, s390_r10);
821
822         /*----------------------------------------------------------*/ 
823         /* Let's fill MonoInvocation - first zero some fields       */
824         /*----------------------------------------------------------*/ 
825         s390_lhi (p, s390_r0, 0);
826         s390_st  (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex)));
827         s390_st  (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex_handler)));
828         s390_st  (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, parent)));
829         s390_lhi (p, s390_r0, 1);
830         s390_st  (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, invoke_trap)));
831
832         /*----------------------------------------------------------*/ 
833         /* set method pointer                                       */
834         /*----------------------------------------------------------*/ 
835         s390_bras (p, s390_r13, 4);
836         s390_word (p, method);
837         s390_l    (p, s390_r0, 0, s390_r13, 0);
838         s390_st   (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, method)));
839
840         local_start = local_pos = MINV_POS + 
841                       sizeof (MonoInvocation) + (sig->param_count + 1) * sizeof (stackval);
842         this_flag   = (sig->hasthis ? 1 : 0);
843
844         /*----------------------------------------------------------*/
845         /* if we are returning a structure, checks it's length to   */
846         /* see if there's a "hidden" parameter that points to the   */
847         /* area. If necessary save this hidden parameter for later  */
848         /*----------------------------------------------------------*/
849         if (MONO_TYPE_ISSTRUCT(sig->ret)) {
850                 if (sig->pinvoke) 
851                         retSize = mono_class_native_size (sig->ret->data.klass, &align);
852                 else
853                         retSize = mono_class_value_size (sig->ret->data.klass, &align);
854                 switch(retSize) {
855                         case 0:
856                         case 1:
857                         case 2:
858                         case 4:
859                         case 8:
860                                 sz.retStruct = 0;
861                                 break;
862                         default:
863                                 sz.retStruct = 1;
864                                 s390_lr(p, s390_r8, s390_r2);
865                                 reg_save = 1;
866                 }
867         } else  {
868                 reg_save = 0;
869         }
870
871         if (this_flag) {
872                 s390_st  (p, s390_r2 + reg_save, 0, STK_BASE, 
873                           (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)));
874                 reg_param++;
875         } else {
876                 s390_st (p, s390_r2 + reg_save, 0, STK_BASE, local_pos);
877                 local_pos += sizeof(int);
878                 s390_st (p, s390_r0, 0, STK_BASE, 
879                          (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)));
880         }
881
882         s390_stm (p, s390_r3 + reg_param, s390_r6, STK_BASE, local_pos);
883         local_pos += 4 * sizeof(long);
884         float_pos  = local_pos;
885         s390_std (p, s390_f0, 0, STK_BASE, local_pos);
886         local_pos += sizeof(double);
887         s390_std (p, s390_f2, 0, STK_BASE, local_pos);
888         local_pos += sizeof(double);
889
890         /*----------------------------------------------------------*/ 
891         /* prepare space for valuetypes                             */
892         /*----------------------------------------------------------*/ 
893         vt_cur = local_pos;
894         vtbuf  = alloca (sizeof(int)*sig->param_count);
895         cpos   = 0;
896         for (i = 0; i < sig->param_count; i++) {
897                 MonoType *type = sig->params [i];
898                 vtbuf [i] = -1;
899                 DEBUG(printf("par: %d type: %d ref: %d\n",i,type->type,type->byref));
900                 if (type->type == MONO_TYPE_VALUETYPE) {
901                         MonoClass *klass = type->data.klass;
902                         gint size;
903
904                         if (klass->enumtype)
905                                 continue;
906                         size = mono_class_native_size (klass, &align);
907                         cpos += align - 1;
908                         cpos &= ~(align - 1);
909                         vtbuf [i] = cpos;
910                         cpos += size;
911                 }
912         }
913         cpos += 3;
914         cpos &= ~3;
915
916         local_pos += cpos;
917
918         /*----------------------------------------------------------*/ 
919         /* set MonoInvocation::stack_args                           */
920         /*----------------------------------------------------------*/ 
921         stackval_arg_pos = MINV_POS + sizeof (MonoInvocation);
922         s390_la  (p, s390_r0, 0, STK_BASE, stackval_arg_pos);
923         s390_st  (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, stack_args)));
924
925         /*----------------------------------------------------------*/ 
926         /* add stackval arguments                                   */  
927         /*----------------------------------------------------------*/ 
928         for (i = 0; i < sig->param_count; ++i) {
929                 if (sig->params [i]->byref) {
930                         ADD_ISTACK_PARM(0, 1);
931                 } else {
932                         simple_type = sig->params [i]->type;
933                 enum_savechk:
934                         switch (simple_type) {
935                         case MONO_TYPE_I8:
936                                 ADD_ISTACK_PARM(-1, 2);
937                                 break;
938                         case MONO_TYPE_R4:
939                                 ADD_RSTACK_PARM(1);
940                                 break;
941                         case MONO_TYPE_R8:
942                                 ADD_RSTACK_PARM(2);
943                                 break;
944                         case MONO_TYPE_VALUETYPE:
945                                 if (sig->params [i]->data.klass->enumtype) {
946                                         simple_type = sig->params [i]->data.klass->enum_basetype->type;
947                                         goto enum_savechk;
948                                 }
949                                 if (sig->pinvoke)
950                                         parSize = mono_class_native_size (sig->params [i]->data.klass, &align);
951                                 else
952                                         parSize = mono_class_value_size (sig->params [i]->data.klass, &align);
953                                 switch(parSize) {
954                                 case 0:
955                                 case 1:
956                                 case 2:
957                                 case 4:
958                                         ADD_PSTACK_PARM(0, 1);
959                                         break;
960                                 case 8:
961                                         ADD_PSTACK_PARM(-1, 2);
962                                         break;
963                                 default:
964                                         ADD_TSTACK_PARM;
965                                 }
966                                 break;
967                         default:
968                                 ADD_ISTACK_PARM(0, 1);
969                         }
970                 }
971                                 
972                 if (vtbuf [i] >= 0) {
973                         s390_la  (p, s390_r3, 0, STK_BASE, vt_cur);
974                         s390_st  (p, s390_r3, 0, STK_BASE, stackval_arg_pos);
975                         s390_la  (p, s390_r3, 0, STK_BASE, stackval_arg_pos);
976                         vt_cur += vtbuf [i];
977                 } else {
978                         s390_la  (p, s390_r3, 0, STK_BASE, stackval_arg_pos);
979                 }
980
981                 /*--------------------------------------*/
982                 /* Load the parameter registers for the */
983                 /* call to stackval_from_data           */
984                 /*--------------------------------------*/
985                 s390_bras (p, s390_r13, 8);
986                 s390_word (p, sig->params [i]);
987                 s390_word (p, sig->pinvoke);
988                 s390_word (p, stackval_from_data);
989                 s390_l    (p, s390_r2, 0, s390_r13, 0);
990
991                 s390_l    (p, s390_r5, 0, s390_r13, 4);
992
993                 s390_l    (p, s390_r1, 0, s390_r13, 8);
994                 s390_basr (p, s390_r14, s390_r1);
995
996                 stackval_arg_pos += sizeof(stackval);
997
998                 /* fixme: alignment */
999                 DEBUG (printf ("arg_pos %d --> ", arg_pos));
1000                 if (sig->pinvoke)
1001                         arg_pos += mono_type_native_stack_size (sig->params [i], &align);
1002                 else
1003                         arg_pos += mono_type_stack_size (sig->params [i], &align);
1004                 
1005                 DEBUG (printf ("%d\n", stackval_arg_pos));
1006         }
1007
1008         /*----------------------------------------------------------*/ 
1009         /* Set return area pointer.                                 */
1010         /*----------------------------------------------------------*/ 
1011         s390_la (p, s390_r10, 0, STK_BASE, stackval_arg_pos);
1012         s390_st (p, s390_r10, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)));
1013         if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref) {
1014                 MonoClass *klass  = sig->ret->data.klass;
1015                 if (!klass->enumtype) {
1016                         s390_la (p, s390_r9, 0, s390_r10, sizeof(stackval));
1017                         s390_st (p, s390_r9, 0,STK_BASE, stackval_arg_pos);
1018                         stackval_arg_pos += sizeof(stackval);
1019                 }
1020         }
1021
1022         /*----------------------------------------------------------*/ 
1023         /* call ves_exec_method                                     */
1024         /*----------------------------------------------------------*/ 
1025         s390_bras (p, s390_r13, 4);
1026         s390_word (p, ves_exec_method);
1027         s390_l    (p, s390_r1, 0, s390_r13, 0);
1028         s390_la   (p, s390_r2, 0, STK_BASE, MINV_POS);
1029         s390_basr (p, s390_r14, s390_r1);
1030
1031         /*----------------------------------------------------------*/ 
1032         /* move retval from stackval to proper place (r3/r4/...)    */
1033         /*----------------------------------------------------------*/ 
1034         DEBUG(printf("retType: %d byRef: %d\n",sig->ret->type,sig->ret->byref));
1035         if (sig->ret->byref) {
1036                 DEBUG (printf ("ret by ref\n"));
1037                 s390_st (p, s390_r2, 0, s390_r10, 0);
1038         } else {
1039         enum_retvalue:
1040 DEBUG(printf("Returns: %d\n",sig->ret->type));
1041                 switch (sig->ret->type) {
1042                 case MONO_TYPE_VOID:
1043                         break;
1044                 case MONO_TYPE_BOOLEAN:
1045                 case MONO_TYPE_U1:
1046                         s390_lhi (p, s390_r2, 0);
1047                         s390_ic  (p, s390_r2, 0, s390_r10, 0);
1048                         break;
1049                 case MONO_TYPE_I2:
1050                 case MONO_TYPE_U2:
1051                         s390_lh (p, s390_r2, 0,s390_r10, 0);
1052                         break;
1053                 case MONO_TYPE_I4:
1054                 case MONO_TYPE_U4:
1055                 case MONO_TYPE_I:
1056                 case MONO_TYPE_U:
1057                 case MONO_TYPE_OBJECT:
1058                 case MONO_TYPE_STRING:
1059                 case MONO_TYPE_CLASS:
1060                         s390_l (p, s390_r2, 0, s390_r10, 0);
1061                         break;
1062                 case MONO_TYPE_I8:
1063                         s390_lm (p, s390_r2, s390_r3, s390_r10, 0);
1064                         break;
1065                 case MONO_TYPE_R4:
1066                         s390_le (p, s390_f0, 0, s390_r10, 0);
1067                         break;
1068                 case MONO_TYPE_R8:
1069                         s390_ld (p, s390_f0, 0, s390_r10, 0);
1070                         break;
1071                 case MONO_TYPE_VALUETYPE:
1072                         if (sig->ret->data.klass->enumtype) {
1073                                 simpletype = sig->ret->data.klass->enum_basetype->type;
1074                                 goto enum_retvalue;
1075                         }
1076                         /*---------------------------------*/
1077                         /* Call stackval_to_data to return */
1078                         /* the structure                   */
1079                         /*---------------------------------*/
1080                         s390_bras (p, s390_r13, 8);
1081                         s390_word (p, sig->ret);
1082                         s390_word (p, sig->pinvoke);
1083                         s390_word (p, stackval_to_data);
1084                         s390_l    (p, s390_r2, 0, s390_r13, 0);
1085                         s390_l    (p, s390_r3, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)));
1086                         if (sz.retStruct) {     
1087                                 /*------------------------------------------*/
1088                                 /* Get stackval_to_data to set result area  */
1089                                 /*------------------------------------------*/
1090                                 s390_lr (p, s390_r4, s390_r8);
1091                         } else {                
1092                                 /*------------------------------------------*/
1093                                 /* Give stackval_to_data a temp result area */
1094                                 /*------------------------------------------*/ 
1095                                 s390_la (p, s390_r4, 0, STK_BASE, stackval_arg_pos);
1096                         }
1097                         s390_l    (p, s390_r5, 0,s390_r13, 4);
1098                         s390_l    (p, s390_r1, 0, s390_r13, 8);
1099                         s390_basr (p, s390_r14, s390_r1);
1100                         switch (retSize) {
1101                                 case 0:
1102                                         break;
1103                                 case 1:
1104                                         s390_lhi (p, s390_r2, 0);
1105                                         s390_ic  (p, s390_r2, 0, s390_r10, 0);
1106                                         break;
1107                                 case 2:
1108                                         s390_lh (p, s390_r2, 0, s390_r10, 0);
1109                                         break;
1110                                 case 4:
1111                                         s390_l (p, s390_r2, 0, s390_r10, 0);
1112                                         break;
1113                                 case 8:
1114                                         s390_lm (p, s390_r2, s390_r3, s390_r10, 0);
1115                                         break;
1116                                 default:
1117                                         /*-------------------------------------------------*/
1118                                         /* stackval_to_data has placed data in result area */
1119                                         /*-------------------------------------------------*/
1120                         }
1121                         break;
1122                 default:
1123                         g_error ("Type 0x%x not handled yet in thunk creation", 
1124                                  sig->ret->type);
1125                         break;
1126                 }
1127         }
1128
1129         /*----------------------------------------------------------*/ 
1130         /* epilog                                                   */
1131         /*----------------------------------------------------------*/ 
1132         s390_l   (p, STK_BASE, 0, STK_BASE, 0);
1133         s390_l   (p, s390_r4, 0, STK_BASE, S390_RET_ADDR_OFFSET);
1134         s390_lm  (p, s390_r6, STK_BASE, STK_BASE, S390_REG_SAVE_OFFSET);
1135         s390_br  (p, s390_r4);
1136
1137         DEBUG (printf ("emited code size: %d\n", p - code_buffer));
1138
1139         DEBUG (printf ("Delegate [end emiting]\n"));
1140
1141         ji = g_new0 (MonoJitInfo, 1);
1142         ji->method = method;
1143         ji->code_size = p - code_buffer;
1144         ji->code_start = code_buffer;
1145
1146         mono_jit_info_table_add (mono_get_root_domain (), ji);
1147
1148         return ji->code_start;
1149 }
1150
1151 /*========================= End of Function ========================*/