* support-test-*.cs: Rename from test-*-p2.cs.
[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                                 break;
653                         }
654                         break;
655                 case MONO_TYPE_VOID:
656                         break;
657                 default:
658                         g_error ("Can't handle as return value 0x%x", 
659                                  sig->ret->type);
660                 }
661         }
662
663         return p;
664 }
665
666 /*========================= End of Function ========================*/
667 \f
668 /*------------------------------------------------------------------*/
669 /*                                                                  */
670 /* Name         - emit_epilog                                       */
671 /*                                                                  */
672 /* Function     - Create the instructions that implement the stand- */
673 /*                ard function epilog according to the S/390 ABI.   */
674 /*                                                                  */
675 /*------------------------------------------------------------------*/
676
677 static inline guint8 *
678 emit_epilog (guint8 *p, MonoMethodSignature *sig, size_data *sz)
679 {
680         /* function epilog */
681         s390_l   (p, STK_BASE, 0, STK_BASE, 0);
682         s390_l   (p, s390_r4, 0, STK_BASE, 56);
683         s390_lm  (p, s390_r6, STK_BASE, STK_BASE, 24);
684         s390_br  (p, s390_r4);
685
686         return p;
687 }
688
689 /*========================= End of Function ========================*/
690 \f
691 /*------------------------------------------------------------------*/
692 /*                                                                  */
693 /* Name         - mono_arch_create_trampoline.                      */
694 /*                                                                  */
695 /* Function     - Create the code that will allow a mono method to  */
696 /*                invoke a system subroutine.                       */
697 /*                                                                  */
698 /*------------------------------------------------------------------*/
699
700 MonoPIFunc
701 mono_arch_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor)
702 {
703         guint8 *p, *code_buffer;
704         size_data sz;
705
706         DEBUG (printf ("\nPInvoke [start emiting]\n"));
707         calculate_sizes (sig, &sz, string_ctor);
708
709         p = code_buffer = alloc_code_memory (sz.code_size);
710         p = emit_prolog (p, sig, &sz);
711         p = emit_save_parameters (p, sig, &sz);
712         p = emit_call_and_store_retval (p, sig, &sz, string_ctor);
713         p = emit_epilog (p, sig, &sz);
714
715 #ifdef NEED_MPROTECT
716         if (mprotect (code_buffer, 1024, PROT_READ | PROT_WRITE | PROT_EXEC)) {
717                 g_error ("Cannot mprotect trampoline\n");
718         }
719 #endif
720
721         DEBUG (printf ("emited code size: %d\n", p - code_buffer));
722
723         DEBUG (printf ("PInvoke [end emiting]\n"));
724
725         return (MonoPIFunc) code_buffer;
726 }
727
728 /*========================= End of Function ========================*/
729 \f
730 /*------------------------------------------------------------------*/
731 /*                                                                  */
732 /* Name         - mono_arch_create_method_pointer                   */
733 /*                                                                  */
734 /* Function     - Returns a pointer to a native function that can   */
735 /*                be used to call the specified method.             */
736 /*                                                                  */
737 /*                The function created will receive the arguments   */
738 /*                according to the calling convention specified in  */
739 /*                in the method.                                    */
740 /*                                                                  */
741 /*                This function works by creating a MonoInvocation  */
742 /*                structure, filling the fields in and calling      */
743 /*                ves_exec_method() on it.                          */
744 /*                                                                  */
745 /* Logic:                                                           */
746 /* ------                                                           */
747 /*  mono_arch_create_method_pointer (MonoMethod *method)            */
748 /*      create the unmanaged->managed wrapper                       */
749 /*      register it with mono_jit_info_table_add()                  */
750 /*                                                                  */
751 /*  What does the unmanaged->managed wrapper do?                    */
752 /*      allocate a MonoInvocation structure (inv) on the stack      */
753 /*      allocate an array of stackval on the stack with length =    */
754 /*          method->signature->param_count + 1 [call it stack_args] */
755 /*      set inv->ex, inv->ex_handler, inv->parent to NULL           */
756 /*      set inv->method to method                                   */
757 /*      if method is an instance method, set inv->obj to the        */
758 /*          'this' argument (the first argument) else set to NULL   */
759 /*      for each argument to the method call:                       */
760 /*              stackval_from_data (sig->params[i], &stack_args[i], */
761 /*                                  arg, sig->pinvoke);             */
762 /*              Where:                                              */
763 /*              ------                                              */
764 /*              sig             - is method->signature              */
765 /*              &stack_args[i]  - is the pointer to the ith element */
766 /*                                in the stackval array             */
767 /*              arg             - is a pointer to the argument re-  */
768 /*                                ceived by the function according  */
769 /*                                to the call convention. If it     */
770 /*                                gets passed in a register, save   */
771 /*                                on the stack first.               */
772 /*                                                                  */
773 /*      set inv->retval to the address of the last element of       */
774 /*          stack_args [recall we allocated param_count+1 of them]  */
775 /*      call ves_exec_method(inv)                                   */
776 /*      copy the returned value from inv->retval where the calling  */
777 /*          convention expects to find it on return from the wrap-  */
778 /*          per [if it's a structure, use stackval_to_data]         */
779 /*                                                                  */
780 /*------------------------------------------------------------------*/
781
782 void *
783 mono_arch_create_method_pointer (MonoMethod *method)
784 {
785         MonoMethodSignature *sig;
786         MonoJitInfo *ji;
787         guint8 *p, *code_buffer;
788         guint i, align = 0, simple_type, retSize, reg_save = 0,
789                 stackval_arg_pos, local_pos, float_pos,
790                 local_start, reg_param = 0, stack_param,
791                 this_flag, arg_pos, fpr_param, parSize;
792         guint32 simpletype;
793         size_data sz;
794         int *vtbuf, cpos, vt_cur;
795
796         sz.code_size   = 1024;
797         sz.stack_size  = 1024;
798         stack_param     = 0;
799         fpr_param       = 0;
800         arg_pos         = 0;
801
802         sig = method->signature;
803
804         p = code_buffer = g_malloc (sz.code_size);
805
806         DEBUG (printf ("\nDelegate [start emiting] %s at 0x%08x\n", 
807                        method->name,p));
808
809         /*----------------------------------------------------------*/ 
810         /* prolog                                                   */
811         /*----------------------------------------------------------*/ 
812         s390_stm (p, s390_r6, STK_BASE, STK_BASE, 24);
813         s390_l   (p, s390_r7, 0, STK_BASE, MINV_POS);
814         s390_lr  (p, s390_r0, STK_BASE);
815         s390_ahi (p, STK_BASE, -(sz.stack_size+MINV_POS));
816         s390_st  (p, s390_r0, 0, STK_BASE, 0);
817         s390_la  (p, s390_r8, 0, STK_BASE, 4);
818         s390_lr  (p, s390_r10, s390_r8);
819         s390_lhi (p, s390_r9, sz.stack_size+92);
820         s390_lhi (p, s390_r11, 0);
821         s390_mvcl(p, s390_r8, s390_r10);
822
823         /*----------------------------------------------------------*/ 
824         /* Let's fill MonoInvocation - first zero some fields       */
825         /*----------------------------------------------------------*/ 
826         s390_lhi (p, s390_r0, 0);
827         s390_st  (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex)));
828         s390_st  (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex_handler)));
829         s390_st  (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, parent)));
830         s390_lhi (p, s390_r0, 1);
831         s390_st  (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, invoke_trap)));
832
833         /*----------------------------------------------------------*/ 
834         /* set method pointer                                       */
835         /*----------------------------------------------------------*/ 
836         s390_bras (p, s390_r13, 4);
837         s390_word (p, method);
838         s390_l    (p, s390_r0, 0, s390_r13, 0);
839         s390_st   (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, method)));
840
841         local_start = local_pos = MINV_POS + 
842                       sizeof (MonoInvocation) + (sig->param_count + 1) * sizeof (stackval);
843         this_flag   = (sig->hasthis ? 1 : 0);
844
845         /*----------------------------------------------------------*/
846         /* if we are returning a structure, checks it's length to   */
847         /* see if there's a "hidden" parameter that points to the   */
848         /* area. If necessary save this hidden parameter for later  */
849         /*----------------------------------------------------------*/
850         if (MONO_TYPE_ISSTRUCT(sig->ret)) {
851                 if (sig->pinvoke) 
852                         retSize = mono_class_native_size (sig->ret->data.klass, &align);
853                 else
854                         retSize = mono_class_value_size (sig->ret->data.klass, &align);
855                 switch(retSize) {
856                         case 0:
857                         case 1:
858                         case 2:
859                         case 4:
860                         case 8:
861                                 sz.retStruct = 0;
862                                 break;
863                         default:
864                                 sz.retStruct = 1;
865                                 s390_lr(p, s390_r8, s390_r2);
866                                 reg_save = 1;
867                 }
868         } else  {
869                 reg_save = 0;
870         }
871
872         if (this_flag) {
873                 s390_st  (p, s390_r2 + reg_save, 0, STK_BASE, 
874                           (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)));
875                 reg_param++;
876         } else {
877                 s390_st (p, s390_r2 + reg_save, 0, STK_BASE, local_pos);
878                 local_pos += sizeof(int);
879                 s390_st (p, s390_r0, 0, STK_BASE, 
880                          (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)));
881         }
882
883         s390_stm (p, s390_r3 + reg_param, s390_r6, STK_BASE, local_pos);
884         local_pos += 4 * sizeof(long);
885         float_pos  = local_pos;
886         s390_std (p, s390_f0, 0, STK_BASE, local_pos);
887         local_pos += sizeof(double);
888         s390_std (p, s390_f2, 0, STK_BASE, local_pos);
889         local_pos += sizeof(double);
890
891         /*----------------------------------------------------------*/ 
892         /* prepare space for valuetypes                             */
893         /*----------------------------------------------------------*/ 
894         vt_cur = local_pos;
895         vtbuf  = alloca (sizeof(int)*sig->param_count);
896         cpos   = 0;
897         for (i = 0; i < sig->param_count; i++) {
898                 MonoType *type = sig->params [i];
899                 vtbuf [i] = -1;
900                 DEBUG(printf("par: %d type: %d ref: %d\n",i,type->type,type->byref));
901                 if (type->type == MONO_TYPE_VALUETYPE) {
902                         MonoClass *klass = type->data.klass;
903                         gint size;
904
905                         if (klass->enumtype)
906                                 continue;
907                         size = mono_class_native_size (klass, &align);
908                         cpos += align - 1;
909                         cpos &= ~(align - 1);
910                         vtbuf [i] = cpos;
911                         cpos += size;
912                 }
913         }
914         cpos += 3;
915         cpos &= ~3;
916
917         local_pos += cpos;
918
919         /*----------------------------------------------------------*/ 
920         /* set MonoInvocation::stack_args                           */
921         /*----------------------------------------------------------*/ 
922         stackval_arg_pos = MINV_POS + sizeof (MonoInvocation);
923         s390_la  (p, s390_r0, 0, STK_BASE, stackval_arg_pos);
924         s390_st  (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, stack_args)));
925
926         /*----------------------------------------------------------*/ 
927         /* add stackval arguments                                   */  
928         /*----------------------------------------------------------*/ 
929         for (i = 0; i < sig->param_count; ++i) {
930                 if (sig->params [i]->byref) {
931                         ADD_ISTACK_PARM(0, 1);
932                 } else {
933                         simple_type = sig->params [i]->type;
934                 enum_savechk:
935                         switch (simple_type) {
936                         case MONO_TYPE_I8:
937                                 ADD_ISTACK_PARM(-1, 2);
938                                 break;
939                         case MONO_TYPE_R4:
940                                 ADD_RSTACK_PARM(1);
941                                 break;
942                         case MONO_TYPE_R8:
943                                 ADD_RSTACK_PARM(2);
944                                 break;
945                         case MONO_TYPE_VALUETYPE:
946                                 if (sig->params [i]->data.klass->enumtype) {
947                                         simple_type = sig->params [i]->data.klass->enum_basetype->type;
948                                         goto enum_savechk;
949                                 }
950                                 if (sig->pinvoke)
951                                         parSize = mono_class_native_size (sig->params [i]->data.klass, &align);
952                                 else
953                                         parSize = mono_class_value_size (sig->params [i]->data.klass, &align);
954                                 switch(parSize) {
955                                 case 0:
956                                 case 1:
957                                 case 2:
958                                 case 4:
959                                         ADD_PSTACK_PARM(0, 1);
960                                         break;
961                                 case 8:
962                                         ADD_PSTACK_PARM(-1, 2);
963                                         break;
964                                 default:
965                                         ADD_TSTACK_PARM;
966                                 }
967                                 break;
968                         default:
969                                 ADD_ISTACK_PARM(0, 1);
970                         }
971                 }
972                                 
973                 if (vtbuf [i] >= 0) {
974                         s390_la  (p, s390_r3, 0, STK_BASE, vt_cur);
975                         s390_st  (p, s390_r3, 0, STK_BASE, stackval_arg_pos);
976                         s390_la  (p, s390_r3, 0, STK_BASE, stackval_arg_pos);
977                         vt_cur += vtbuf [i];
978                 } else {
979                         s390_la  (p, s390_r3, 0, STK_BASE, stackval_arg_pos);
980                 }
981
982                 /*--------------------------------------*/
983                 /* Load the parameter registers for the */
984                 /* call to stackval_from_data           */
985                 /*--------------------------------------*/
986                 s390_bras (p, s390_r13, 8);
987                 s390_word (p, sig->params [i]);
988                 s390_word (p, sig->pinvoke);
989                 s390_word (p, stackval_from_data);
990                 s390_l    (p, s390_r2, 0, s390_r13, 0);
991
992                 s390_l    (p, s390_r5, 0, s390_r13, 4);
993
994                 s390_l    (p, s390_r1, 0, s390_r13, 8);
995                 s390_basr (p, s390_r14, s390_r1);
996
997                 stackval_arg_pos += sizeof(stackval);
998
999                 /* fixme: alignment */
1000                 DEBUG (printf ("arg_pos %d --> ", arg_pos));
1001                 if (sig->pinvoke)
1002                         arg_pos += mono_type_native_stack_size (sig->params [i], &align);
1003                 else
1004                         arg_pos += mono_type_stack_size (sig->params [i], &align);
1005                 
1006                 DEBUG (printf ("%d\n", stackval_arg_pos));
1007         }
1008
1009         /*----------------------------------------------------------*/ 
1010         /* Set return area pointer.                                 */
1011         /*----------------------------------------------------------*/ 
1012         s390_la (p, s390_r10, 0, STK_BASE, stackval_arg_pos);
1013         s390_st (p, s390_r10, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)));
1014         if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref) {
1015                 MonoClass *klass  = sig->ret->data.klass;
1016                 if (!klass->enumtype) {
1017                         s390_la (p, s390_r9, 0, s390_r10, sizeof(stackval));
1018                         s390_st (p, s390_r9, 0,STK_BASE, stackval_arg_pos);
1019                         stackval_arg_pos += sizeof(stackval);
1020                 }
1021         }
1022
1023         /*----------------------------------------------------------*/ 
1024         /* call ves_exec_method                                     */
1025         /*----------------------------------------------------------*/ 
1026         s390_bras (p, s390_r13, 4);
1027         s390_word (p, ves_exec_method);
1028         s390_l    (p, s390_r1, 0, s390_r13, 0);
1029         s390_la   (p, s390_r2, 0, STK_BASE, MINV_POS);
1030         s390_basr (p, s390_r14, s390_r1);
1031
1032         /*----------------------------------------------------------*/ 
1033         /* move retval from stackval to proper place (r3/r4/...)    */
1034         /*----------------------------------------------------------*/ 
1035         DEBUG(printf("retType: %d byRef: %d\n",sig->ret->type,sig->ret->byref));
1036         if (sig->ret->byref) {
1037                 DEBUG (printf ("ret by ref\n"));
1038                 s390_st (p, s390_r2, 0, s390_r10, 0);
1039         } else {
1040         enum_retvalue:
1041 DEBUG(printf("Returns: %d\n",sig->ret->type));
1042                 switch (sig->ret->type) {
1043                 case MONO_TYPE_VOID:
1044                         break;
1045                 case MONO_TYPE_BOOLEAN:
1046                 case MONO_TYPE_U1:
1047                         s390_lhi (p, s390_r2, 0);
1048                         s390_ic  (p, s390_r2, 0, s390_r10, 0);
1049                         break;
1050                 case MONO_TYPE_I2:
1051                 case MONO_TYPE_U2:
1052                         s390_lh (p, s390_r2, 0,s390_r10, 0);
1053                         break;
1054                 case MONO_TYPE_I4:
1055                 case MONO_TYPE_U4:
1056                 case MONO_TYPE_I:
1057                 case MONO_TYPE_U:
1058                 case MONO_TYPE_OBJECT:
1059                 case MONO_TYPE_STRING:
1060                 case MONO_TYPE_CLASS:
1061                         s390_l (p, s390_r2, 0, s390_r10, 0);
1062                         break;
1063                 case MONO_TYPE_I8:
1064                         s390_lm (p, s390_r2, s390_r3, s390_r10, 0);
1065                         break;
1066                 case MONO_TYPE_R4:
1067                         s390_le (p, s390_f0, 0, s390_r10, 0);
1068                         break;
1069                 case MONO_TYPE_R8:
1070                         s390_ld (p, s390_f0, 0, s390_r10, 0);
1071                         break;
1072                 case MONO_TYPE_VALUETYPE:
1073                         if (sig->ret->data.klass->enumtype) {
1074                                 simpletype = sig->ret->data.klass->enum_basetype->type;
1075                                 goto enum_retvalue;
1076                         }
1077                         /*---------------------------------*/
1078                         /* Call stackval_to_data to return */
1079                         /* the structure                   */
1080                         /*---------------------------------*/
1081                         s390_bras (p, s390_r13, 8);
1082                         s390_word (p, sig->ret);
1083                         s390_word (p, sig->pinvoke);
1084                         s390_word (p, stackval_to_data);
1085                         s390_l    (p, s390_r2, 0, s390_r13, 0);
1086                         s390_l    (p, s390_r3, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)));
1087                         if (sz.retStruct) {     
1088                                 /*------------------------------------------*/
1089                                 /* Get stackval_to_data to set result area  */
1090                                 /*------------------------------------------*/
1091                                 s390_lr (p, s390_r4, s390_r8);
1092                         } else {                
1093                                 /*------------------------------------------*/
1094                                 /* Give stackval_to_data a temp result area */
1095                                 /*------------------------------------------*/ 
1096                                 s390_la (p, s390_r4, 0, STK_BASE, stackval_arg_pos);
1097                         }
1098                         s390_l    (p, s390_r5, 0,s390_r13, 4);
1099                         s390_l    (p, s390_r1, 0, s390_r13, 8);
1100                         s390_basr (p, s390_r14, s390_r1);
1101                         switch (retSize) {
1102                                 case 0:
1103                                         break;
1104                                 case 1:
1105                                         s390_lhi (p, s390_r2, 0);
1106                                         s390_ic  (p, s390_r2, 0, s390_r10, 0);
1107                                         break;
1108                                 case 2:
1109                                         s390_lh (p, s390_r2, 0, s390_r10, 0);
1110                                         break;
1111                                 case 4:
1112                                         s390_l (p, s390_r2, 0, s390_r10, 0);
1113                                         break;
1114                                 case 8:
1115                                         s390_lm (p, s390_r2, s390_r3, s390_r10, 0);
1116                                         break;
1117                                 default: ;
1118                                         /*-------------------------------------------------*/
1119                                         /* stackval_to_data has placed data in result area */
1120                                         /*-------------------------------------------------*/
1121                                         break;
1122                         }
1123                         break;
1124                 default:
1125                         g_error ("Type 0x%x not handled yet in thunk creation", 
1126                                  sig->ret->type);
1127                         break;
1128                 }
1129         }
1130
1131         /*----------------------------------------------------------*/ 
1132         /* epilog                                                   */
1133         /*----------------------------------------------------------*/ 
1134         s390_l   (p, STK_BASE, 0, STK_BASE, 0);
1135         s390_l   (p, s390_r4, 0, STK_BASE, S390_RET_ADDR_OFFSET);
1136         s390_lm  (p, s390_r6, STK_BASE, STK_BASE, S390_REG_SAVE_OFFSET);
1137         s390_br  (p, s390_r4);
1138
1139         DEBUG (printf ("emited code size: %d\n", p - code_buffer));
1140
1141         DEBUG (printf ("Delegate [end emiting]\n"));
1142
1143         ji = g_new0 (MonoJitInfo, 1);
1144         ji->method = method;
1145         ji->code_size = p - code_buffer;
1146         ji->code_start = code_buffer;
1147
1148         mono_jit_info_table_add (mono_get_root_domain (), ji);
1149
1150         return ji->code_start;
1151 }
1152
1153 /*========================= End of Function ========================*/