Add support for z13 processor
[mono.git] / mono / arch / s390x / 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 "s390x-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
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
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_PTR:
155                 case MONO_TYPE_SZARRAY:
156                 case MONO_TYPE_ARRAY:
157                 case MONO_TYPE_STRING:
158                         sz->code_size += 4;
159                         break;
160                 case MONO_TYPE_I8:
161                         sz->code_size += 4;
162                         break;
163                 case MONO_TYPE_VALUETYPE:
164                         if (sig->ret->data.klass->enumtype) {
165                                 simpletype = sig->ret->data.klass->enum_basetype->type;
166                                 goto enum_retvalue;
167                         }
168                         gr++;
169                         if (sig->pinvoke)
170                                 size = mono_class_native_size (sig->ret->data.klass, &align);
171                         else
172                                 size = mono_class_value_size (sig->ret->data.klass, &align);
173                         if (align > 1)
174                                 sz->code_size += 10;
175                         switch (size) {
176                                 /*----------------------------------*/
177                                 /* On S/390, structures of size 1,  */
178                                 /* 2, 4, and 8 bytes are returned   */
179                                 /* in (a) register(s).              */
180                                 /*----------------------------------*/
181                                 case 1:
182                                 case 2:
183                                 case 4:
184                                 case 8:
185                                         sz->code_size  += 16;
186                                         sz->stack_size += 4;
187                                         break;
188                                 default:
189                                         sz->retStruct   = 1;
190                                         sz->code_size  += 32;
191                         }
192                         break;
193                 case MONO_TYPE_VOID:
194                         break;
195                 default:
196                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
197                 }
198         }
199
200         /*----------------------------------------------------------*/
201         /* We determine the size of the parameter code and stack    */
202         /* requirements by checking the types and sizes of the      */
203         /* parameters.                                              */
204         /*----------------------------------------------------------*/
205
206         for (i = 0; i < sig->param_count; ++i) {
207                 if (sig->params [i]->byref) {
208                         add_general (&gr, sz, TRUE);
209                         continue;
210                 }
211                 simpletype = sig->params [i]->type;
212         enum_calc_size:
213                 switch (simpletype) {
214                 case MONO_TYPE_BOOLEAN:
215                 case MONO_TYPE_CHAR:
216                 case MONO_TYPE_I1:
217                 case MONO_TYPE_U1:
218                 case MONO_TYPE_I2:
219                 case MONO_TYPE_U2:
220                 case MONO_TYPE_I4:
221                 case MONO_TYPE_U4:
222                 case MONO_TYPE_I:
223                 case MONO_TYPE_U:
224                 case MONO_TYPE_PTR:
225                 case MONO_TYPE_CLASS:
226                 case MONO_TYPE_OBJECT:
227                 case MONO_TYPE_STRING:
228                         add_general (&gr, sz, TRUE);
229                         break;
230                 case MONO_TYPE_SZARRAY:
231                         add_general (&gr, sz, TRUE);
232                         break;
233                 case MONO_TYPE_VALUETYPE:
234                         if (sig->params [i]->data.klass->enumtype) {
235                                 simpletype = sig->params [i]->data.klass->enum_basetype->type;
236                                 goto enum_calc_size;
237                         }
238                         if (sig->pinvoke)
239                                 size = mono_class_native_size (sig->params [i]->data.klass, &align);
240                         else
241                                 size = mono_class_value_size (sig->params [i]->data.klass, &align);
242                         DEBUG(printf("%d typesize: %d (%d)\n",i,size,align));
243                         switch (size) {
244                                 /*----------------------------------*/
245                                 /* On S/390, structures of size 1,  */
246                                 /* 2, 4, and 8 bytes are passed in  */
247                                 /* (a) register(s).                 */
248                                 /*----------------------------------*/
249                                 case 0:
250                                 case 1:
251                                 case 2:
252                                 case 4:
253                                         add_general(&gr, sz, TRUE);
254                                         break;
255                                 case 8:
256                                         add_general(&gr, sz, FALSE);
257                                         break;
258                                 default:
259                                         sz->local_size += (size + (size % align));
260                                         sz->code_size  += 40;
261                         }
262                         break;
263                 case MONO_TYPE_I8:
264                         add_general (&gr, sz, FALSE);
265                         break;
266                 case MONO_TYPE_R4:
267                         if (fr < FLOAT_REGS) {
268                                 sz->code_size += 4;
269                                 fr++;
270                         }
271                         else {
272                                 sz->code_size  += 4;
273                                 sz->stack_size += 8;
274                         }
275                         break;
276                 case MONO_TYPE_R8:
277                         if (fr < FLOAT_REGS) {
278                                 sz->code_size += 4;
279                                 fr++;
280                         } else {
281                                 sz->code_size  += 4;
282                                 sz->stack_size += 8 + (sz->stack_size % 8);
283                         }
284                         break;
285                 default:
286                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
287                 }
288         }
289
290
291         /* align stack size to 8 */
292         DEBUG (printf ("      stack size: %d (%d)\n"
293                        "       code size: %d\n" 
294                        "      local size: %d\n",
295                       (sz->stack_size + 8) & ~8, sz->stack_size, 
296                       (sz->code_size),(sz->local_size + 8) & ~8));
297         sz->stack_size = (sz->stack_size + 8) & ~8;
298         sz->local_size = (sz->local_size + 8) & ~8;
299 }
300
301 /*========================= End of Function ========================*/
302
303 /*------------------------------------------------------------------*/
304 /*                                                                  */
305 /* Name         - emit_prolog                                       */
306 /*                                                                  */
307 /* Function     - Create the instructions that implement the stand- */
308 /*                ard function prolog according to the S/390 ABI.   */
309 /*                                                                  */
310 /*------------------------------------------------------------------*/
311
312 static inline guint8 *
313 emit_prolog (guint8 *p, MonoMethodSignature *sig, size_data *sz)
314 {
315         guint stack_size;
316
317         stack_size = sz->stack_size + sz->local_size;
318
319         /* function prolog */
320         s390_stmg(p, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
321         s390_lg  (p, s390_r7, 0, STK_BASE, MINV_POS);
322         s390_lgr (p, s390_r11, STK_BASE);
323         s390_aghi(p, STK_BASE, -stack_size);
324         s390_stg (p, s390_r11, 0, STK_BASE, 0);
325
326         /*-----------------------------------------*/
327         /* Save:                                   */
328         /* - address of "callme"                   */
329         /* - address of "retval"                   */
330         /* - address of "arguments"                */
331         /*-----------------------------------------*/
332         s390_lgr (p, s390_r9, s390_r2);
333         s390_lgr (p, s390_r8, s390_r3);
334         s390_lgr (p, s390_r10, s390_r5);
335
336         return p;
337 }
338
339 /*========================= End of Function ========================*/
340
341 /*------------------------------------------------------------------*/
342 /*                                                                  */
343 /* Name         - emit_save_parameters                              */
344 /*                                                                  */
345 /* Function     - Create the instructions that load registers with  */ 
346 /*                parameters, place others on the stack according   */
347 /*                to the S/390 ABI.                                 */
348 /*                                                                  */
349 /*                The resulting function takes the form:            */
350 /*                void func (void (*callme)(), void *retval,        */
351 /*                           void *this_obj, stackval *arguments);  */
352 /*                                                                  */
353 /*------------------------------------------------------------------*/
354
355 inline static guint8*
356 emit_save_parameters (guint8 *p, MonoMethodSignature *sig, size_data *sz)
357 {
358         guint i, fr, gr, act_strs, align, 
359               stack_par_pos, size, local_pos;
360         guint32 simpletype;
361
362         /*----------------------------------------------------------*/
363         /* If a structure on stack is being returned, reserve r2    */ 
364         /* to point to an area where it can be passed.              */
365         /*----------------------------------------------------------*/
366         if (sz->retStruct)
367                 gr    = 1;
368         else
369                 gr    = 0;
370         fr            = 0;
371         act_strs      = 0;
372         stack_par_pos = S390_MINIMAL_STACK_SIZE;
373         local_pos     = sz->stack_size;
374
375         if (sig->hasthis) {
376                 s390_lr (p, s390_r2 + gr, s390_r4);
377                 gr++;
378         }
379
380         act_strs = 0;
381         for (i = 0; i < sig->param_count; ++i) {
382                 DEBUG(printf("par: %d type: %d ref: %d\n",i,sig->params[i]->type,sig->params[i]->byref));
383                 if (sig->params [i]->byref) {
384                         if (gr < GENERAL_REGS) {
385                                 s390_lg (p, s390_r2 + gr, 0, ARG_BASE, STKARG);
386                                 gr ++;
387                         } else {
388                                 s390_lg (p, s390_r0, 0, ARG_BASE, STKARG);
389                                 s390_stg(p, s390_r0, 0, STK_BASE, stack_par_pos);
390                                 stack_par_pos += sizeof(long);
391                         }
392                         continue;
393                 }
394                 simpletype = sig->params [i]->type;
395         enum_calc_size:
396                 switch (simpletype) {
397                 case MONO_TYPE_BOOLEAN:
398                 case MONO_TYPE_I1:
399                 case MONO_TYPE_U1:
400                 case MONO_TYPE_I2:
401                 case MONO_TYPE_U2:
402                 case MONO_TYPE_CHAR:
403                 case MONO_TYPE_I4:
404                 case MONO_TYPE_U4:
405                 case MONO_TYPE_I:
406                 case MONO_TYPE_U:
407                 case MONO_TYPE_PTR:
408                 case MONO_TYPE_CLASS:
409                 case MONO_TYPE_OBJECT:
410                 case MONO_TYPE_STRING:
411                 case MONO_TYPE_SZARRAY:
412                         if (gr < GENERAL_REGS) {
413                                 s390_lg (p, s390_r2 + gr, 0, ARG_BASE, STKARG);
414                                 gr ++;
415                         } else {
416                                 s390_lg (p, s390_r0, 0, ARG_BASE, STKARG);
417                                 s390_stg(p, s390_r0, 0, STK_BASE, stack_par_pos);
418                                 stack_par_pos += sizeof(long);
419                         }
420                         break;
421                 case MONO_TYPE_VALUETYPE:
422                         if (sig->params [i]->data.klass->enumtype) {
423                                 simpletype = sig->params [i]->data.klass->enum_basetype->type;
424                                 goto enum_calc_size;
425                         }
426                         if (sig->pinvoke) 
427                                 size = mono_class_native_size (sig->params [i]->data.klass, &align);
428                         else
429                                 size = mono_class_value_size (sig->params [i]->data.klass, &align);
430                         DEBUG(printf("parStruct - size %d pinvoke: %d\n",size,sig->pinvoke));
431                         switch (size) {
432                                 case 0:
433                                 case 1:
434                                 case 2:
435                                 case 4:
436                                         if (gr < GENERAL_REGS) {
437                                                 s390_lg (p, s390_r2 + gr, 0,ARG_BASE, STKARG);
438                                                 s390_lgf(p, s390_r2 + gr, 0, s390_r2 + gr, 0);
439                                                 gr++;
440                                         } else {
441                                                 stack_par_pos += (stack_par_pos % align);
442                                                 s390_lg (p, s390_r10, 0,ARG_BASE, STKARG);
443                                                 s390_lgf(p, s390_r10, 0, s390_r10, 0);
444                                                 s390_st (p, s390_r10, 0, STK_BASE, stack_par_pos);
445                                                 stack_par_pos += sizeof(long);
446                                         }
447                                         break;
448                                 case 8:
449                                         if (gr < GENERAL_REGS) {
450                                                 s390_lg (p, s390_r2 + gr, 0, ARG_BASE, STKARG);
451                                                 s390_lg (p, s390_r2 + gr, 0, s390_r2 + gr, 0);
452                                         } else {
453                                                 stack_par_pos += (stack_par_pos % align);
454                                                 s390_lg  (p, s390_r10, 0, ARG_BASE, STKARG);
455                                                 s390_mvc (p, sizeof(long long), STK_BASE, stack_par_pos, s390_r10, 0);
456                                                 stack_par_pos += sizeof(long long);
457                                         }
458                                         break;  
459                                 default:
460                                         if (size <= 256) {
461                                                 local_pos += (local_pos % align);
462                                                 s390_lg  (p, s390_r13, 0, ARG_BASE, STKARG);
463                                                 s390_mvc (p, size, STK_BASE, local_pos, s390_r13, 0);
464                                                 s390_la  (p, s390_r13, 0, STK_BASE, local_pos);
465                                                 local_pos += size;
466                                         } else {
467                                                 local_pos += (local_pos % align);
468                                                 s390_bras (p, s390_r13, 4);
469                                                 s390_llong(p, size);
470                                                 s390_lg   (p, s390_r1, 0, s390_r13, 0);
471                                                 s390_lg   (p, s390_r0, 0, ARG_BASE, STKARG);
472                                                 s390_lgr  (p, s390_r14, s390_r12);
473                                                 s390_la   (p, s390_r12, 0, STK_BASE, local_pos);
474                                                 s390_lgr  (p, s390_r13, s390_r1);
475                                                 s390_mvcl (p, s390_r12, s390_r0);
476                                                 s390_lgr  (p, s390_r12, s390_r14);
477                                                 s390_la   (p, s390_r13, 0, STK_BASE, local_pos);
478                                                 local_pos += size;
479                                         }
480                                         if (gr < GENERAL_REGS) {
481                                                 s390_lgr(p, s390_r2 + gr, s390_r13);
482                                                 gr++;
483                                         } else {
484                                                 s390_stg(p, s390_r13, 0, STK_BASE, stack_par_pos);
485                                                 stack_par_pos += sizeof(long);
486                                         }
487                         }
488                         break;
489                 case MONO_TYPE_I8:
490                         if (gr < GENERAL_REGS) {
491                                 s390_lg (p, s390_r2 + gr, 0, ARG_BASE, STKARG); 
492                                 gr += 2;
493                         } else {
494                                 *(guint32 *) p += 7;
495                                 *(guint32 *) p &= ~7;
496                                 s390_mvc (p, sizeof(long long), STK_BASE, stack_par_pos, ARG_BASE, STKARG); 
497                                 stack_par_pos += sizeof(long long) + (stack_par_pos % sizeof(long long));
498                         }
499                         break;
500                 case MONO_TYPE_R4:
501                         if (fr < FLOAT_REGS) {
502                                 s390_le  (p, s390_r0 + fr, 0, ARG_BASE, STKARG);
503                                 fr++;
504                         } else {
505                                 s390_mvc  (p, sizeof(float), STK_BASE, stack_par_pos, ARG_BASE, STKARG);
506                                 stack_par_pos += sizeof(float);
507                         }
508                         break;
509                 case MONO_TYPE_R8:
510                         if (fr < FLOAT_REGS) {
511                                 s390_ld  (p, s390_r0 + fr, 0, ARG_BASE, STKARG);
512                                 fr++;
513                         } else {
514                                 *(guint32 *) p += 7;
515                                 *(guint32 *) p &= ~7;
516                                 s390_mvc  (p, sizeof(double), STK_BASE, stack_par_pos, ARG_BASE, STKARG);
517                                 stack_par_pos += sizeof(long long) + (stack_par_pos % sizeof(long long));
518                         }
519                         break;
520                 default:
521                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
522                 }
523         }
524
525         /*----------------------------------------------------------*/
526         /* If we're returning a structure but not in a register     */ 
527         /* then point the result area for the called routine        */
528         /*----------------------------------------------------------*/
529         if (sz->retStruct) {
530                 s390_lg (p, s390_r2, 0, s390_r8, 0);
531         }
532
533         return p;
534 }
535
536 /*========================= End of Function ========================*/
537
538 /*------------------------------------------------------------------*/
539 /*                                                                  */
540 /* Name         - alloc_code_memory                                 */
541 /*                                                                  */
542 /* Function     - Allocate space to place the emitted code.         */
543 /*                                                                  */
544 /*------------------------------------------------------------------*/
545
546 static inline guint8 *
547 alloc_code_memory (guint code_size)
548 {
549         guint8 *p;
550
551 #ifdef NEED_MPROTECT
552         p = g_malloc (code_size + PAGESIZE - 1);
553
554         /* Align to a multiple of PAGESIZE, assumed to be a power of two */
555         p = (char *)(((int) p + PAGESIZE-1) & ~(PAGESIZE-1));
556 #else
557         p = g_malloc (code_size);
558 #endif
559         DEBUG (printf ("           align: %p (%d)\n", p, (guint)p % 4));
560
561         return p;
562 }
563
564 /*========================= End of Function ========================*/
565
566 /*------------------------------------------------------------------*/
567 /*                                                                  */
568 /* Name         - emit_call_and_store_retval                        */
569 /*                                                                  */
570 /* Function     - Emit code that will implement the call to the     */
571 /*                desired function, and unload the result according */
572 /*                to the S390 ABI for the type of value returned    */
573 /*                                                                  */
574 /*------------------------------------------------------------------*/
575
576 static inline guint8 *
577 emit_call_and_store_retval (guint8 *p, MonoMethodSignature *sig, 
578                             size_data *sz, gboolean string_ctor)
579 {
580         guint32 simpletype;
581         guint   retSize, align;
582
583         /* call "callme" */
584         s390_basr (p, s390_r14, s390_r9); 
585
586         /* get return value */
587         if (sig->ret->byref || string_ctor) {
588                 s390_stg(p, s390_r2, 0, s390_r8, 0);
589         } else {
590                 simpletype = sig->ret->type;
591 enum_retvalue:
592                 switch (simpletype) {
593                 case MONO_TYPE_BOOLEAN:
594                 case MONO_TYPE_I1:
595                 case MONO_TYPE_U1:
596                         s390_stc (p, s390_r2, 0, s390_r8, 0);
597                         break;
598                 case MONO_TYPE_I2:
599                 case MONO_TYPE_U2:
600                 case MONO_TYPE_CHAR:
601                         s390_sth (p, s390_r2, 0, s390_r8, 0);
602                         break;
603                 case MONO_TYPE_I4:
604                 case MONO_TYPE_U4:
605                 case MONO_TYPE_I:
606                 case MONO_TYPE_U:
607                 case MONO_TYPE_CLASS:
608                 case MONO_TYPE_OBJECT:
609                 case MONO_TYPE_SZARRAY:
610                 case MONO_TYPE_ARRAY:
611                 case MONO_TYPE_STRING:
612                         s390_st (p, s390_r2, 0, s390_r8, 0);
613                         break;
614                 case MONO_TYPE_R4:
615                         s390_ste (p, s390_f0, 0, s390_r8, 0);
616                         break;
617                 case MONO_TYPE_R8:
618                         s390_std (p, s390_f0, 0, s390_r8, 0);
619                         break;
620                 case MONO_TYPE_I8:
621                         s390_stg (p, s390_r2, 0, s390_r8, 0);
622                         break;
623                 case MONO_TYPE_VALUETYPE:
624                         if (sig->ret->data.klass->enumtype) {
625                                 simpletype = sig->ret->data.klass->enum_basetype->type;
626                                 goto enum_retvalue;
627                         }
628                         if (sig->pinvoke) 
629                                 retSize = mono_class_native_size (sig->ret->data.klass, &align);
630                         else
631                                 retSize = mono_class_value_size (sig->ret->data.klass, &align);
632 printf("Returning %d bytes for type %d (%d)\n",retSize,simpletype,sig->pinvoke);
633                         switch(retSize) {
634                         case 0:
635                                 break;
636                         case 1:
637                                 s390_stc (p, s390_r2, 0, s390_r8, 0);
638                                 break;
639                         case 2:
640                                 s390_sth (p, s390_r2, 0, s390_r8, 0);
641                                 break;
642                         case 4:
643                                 s390_st (p, s390_r2, 0, s390_r8, 0);
644                                 break;
645                         case 8:
646                                 s390_stg (p, s390_r2, 0, s390_r8, 0);
647                                 break;
648                         default: ;
649                                 /*------------------------------------------*/
650                                 /* The callee has already placed the result */
651                                 /* in the required area                     */
652                                 /*------------------------------------------*/
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
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_lg  (p, STK_BASE, 0, STK_BASE, 0);
682         s390_lg  (p, s390_r4, 0, STK_BASE, S390_RET_ADDR_OFFSET);
683         s390_lmg (p, s390_r6, STK_BASE, STK_BASE, S390_REG_SAVE_OFFSET);
684         s390_br  (p, s390_r4);
685
686         return p;
687 }
688
689 /*========================= End of Function ========================*/
690
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
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_stmg(p, s390_r6, STK_BASE, STK_BASE, S390_REG_SAVE_OFFSET);
813         s390_lg  (p, s390_r7, 0, STK_BASE, MINV_POS);
814         s390_lgr (p, s390_r0, STK_BASE);
815         s390_aghi(p, STK_BASE, -(sz.stack_size+MINV_POS));
816         s390_stg (p, s390_r0, 0, STK_BASE, 0);
817         s390_la  (p, s390_r8, 0, STK_BASE, 4);
818         s390_lgr (p, s390_r10, s390_r8);
819         s390_lghi(p, s390_r9, sz.stack_size+92);
820         s390_lghi(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_lghi (p, s390_r0, 0);
827         s390_stg  (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex)));
828         s390_stg  (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex_handler)));
829         s390_stg  (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, parent)));
830         s390_lghi (p, s390_r0, 1);
831         s390_stg  (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_llong(p, method);
838         s390_lg   (p, s390_r0, 0, s390_r13, 0);
839         s390_stg  (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_lgr(p, s390_r8, s390_r2);
866                                 reg_save = 1;
867                 }
868         } else  {
869                 reg_save = 0;
870         }
871
872         if (this_flag) {
873                 s390_stg (p, s390_r2 + reg_save, 0, STK_BASE, 
874                           (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)));
875                 reg_param++;
876         } else {
877                 s390_stg (p, s390_r2 + reg_save, 0, STK_BASE, local_pos);
878                 local_pos += sizeof(int);
879                 s390_stg (p, s390_r0, 0, STK_BASE, 
880                          (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)));
881         }
882
883         s390_stmg (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_stg (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_stg (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_llong(p, sig->params [i]);
988                 s390_llong(p, sig->pinvoke);
989                 s390_llong(p, stackval_from_data);
990                 s390_lg   (p, s390_r2, 0, s390_r13, 0);
991                 s390_lg   (p, s390_r5, 0, s390_r13, 4);
992                 s390_lg   (p, s390_r1, 0, s390_r13, 8);
993                 s390_basr (p, s390_r14, s390_r1);
994
995                 stackval_arg_pos += sizeof(stackval);
996
997                 /* fixme: alignment */
998                 DEBUG (printf ("arg_pos %d --> ", arg_pos));
999                 if (sig->pinvoke)
1000                         arg_pos += mono_type_native_stack_size (sig->params [i], &align);
1001                 else
1002                         arg_pos += mono_type_stack_size (sig->params [i], &align);
1003                 
1004                 DEBUG (printf ("%d\n", stackval_arg_pos));
1005         }
1006
1007         /*----------------------------------------------------------*/ 
1008         /* Set return area pointer.                                 */
1009         /*----------------------------------------------------------*/ 
1010         s390_la (p, s390_r10, 0, STK_BASE, stackval_arg_pos);
1011         s390_stg(p, s390_r10, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)));
1012         if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref) {
1013                 MonoClass *klass  = sig->ret->data.klass;
1014                 if (!klass->enumtype) {
1015                         s390_la (p, s390_r9, 0, s390_r10, sizeof(stackval));
1016                         s390_st (p, s390_r9, 0,STK_BASE, stackval_arg_pos);
1017                         stackval_arg_pos += sizeof(stackval);
1018                 }
1019         }
1020
1021         /*----------------------------------------------------------*/ 
1022         /* call ves_exec_method                                     */
1023         /*----------------------------------------------------------*/ 
1024         s390_bras (p, s390_r13, 4);
1025         s390_llong(p, ves_exec_method);
1026         s390_lg   (p, s390_r1, 0, s390_r13, 0);
1027         s390_la   (p, s390_r2, 0, STK_BASE, MINV_POS);
1028         s390_basr (p, s390_r14, s390_r1);
1029
1030         /*----------------------------------------------------------*/ 
1031         /* move retval from stackval to proper place (r3/r4/...)    */
1032         /*----------------------------------------------------------*/ 
1033         DEBUG(printf("retType: %d byRef: %d\n",sig->ret->type,sig->ret->byref));
1034         if (sig->ret->byref) {
1035                 DEBUG (printf ("ret by ref\n"));
1036                 s390_stg(p, s390_r2, 0, s390_r10, 0);
1037         } else {
1038         enum_retvalue:
1039                 switch (sig->ret->type) {
1040                 case MONO_TYPE_VOID:
1041                         break;
1042                 case MONO_TYPE_BOOLEAN:
1043                 case MONO_TYPE_U1:
1044                         s390_lghi(p, s390_r2, 0);
1045                         s390_ic  (p, s390_r2, 0, s390_r10, 0);
1046                         break;
1047                 case MONO_TYPE_I2:
1048                 case MONO_TYPE_U2:
1049                         s390_lh (p, s390_r2, 0,s390_r10, 0);
1050                         break;
1051                 case MONO_TYPE_I4:
1052                 case MONO_TYPE_U4:
1053                 case MONO_TYPE_I:
1054                 case MONO_TYPE_U:
1055                         s390_lgf(p, s390_r2, 0, s390_r10, 0);
1056                         break;
1057                 case MONO_TYPE_OBJECT:
1058                 case MONO_TYPE_STRING:
1059                 case MONO_TYPE_CLASS:
1060                 case MONO_TYPE_I8:
1061                         s390_lg (p, s390_r2, 0, s390_r10, 0);
1062                         break;
1063                 case MONO_TYPE_R4:
1064                         s390_le (p, s390_f0, 0, s390_r10, 0);
1065                         break;
1066                 case MONO_TYPE_R8:
1067                         s390_ld (p, s390_f0, 0, s390_r10, 0);
1068                         break;
1069                 case MONO_TYPE_VALUETYPE:
1070                         if (sig->ret->data.klass->enumtype) {
1071                                 simpletype = sig->ret->data.klass->enum_basetype->type;
1072                                 goto enum_retvalue;
1073                         }
1074                         /*---------------------------------*/
1075                         /* Call stackval_to_data to return */
1076                         /* the structure                   */
1077                         /*---------------------------------*/
1078                         s390_bras (p, s390_r13, 8);
1079                         s390_llong(p, sig->ret);
1080                         s390_llong(p, sig->pinvoke);
1081                         s390_llong(p, stackval_to_data);
1082                         s390_lg   (p, s390_r2, 0, s390_r13, 0);
1083                         s390_lg   (p, s390_r3, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)));
1084                         if (sz.retStruct) {     
1085                                 /*------------------------------------------*/
1086                                 /* Get stackval_to_data to set result area  */
1087                                 /*------------------------------------------*/
1088                                 s390_lgr (p, s390_r4, s390_r8);
1089                         } else {                
1090                                 /*------------------------------------------*/
1091                                 /* Give stackval_to_data a temp result area */
1092                                 /*------------------------------------------*/ 
1093                                 s390_la (p, s390_r4, 0, STK_BASE, stackval_arg_pos);
1094                         }
1095                         s390_lg   (p, s390_r5, 0,s390_r13, 4);
1096                         s390_lg   (p, s390_r1, 0, s390_r13, 8);
1097                         s390_basr (p, s390_r14, s390_r1);
1098                         switch (retSize) {
1099                                 case 0:
1100                                         break;
1101                                 case 1:
1102                                         s390_lghi(p, s390_r2, 0);
1103                                         s390_ic  (p, s390_r2, 0, s390_r10, 0);
1104                                         break;
1105                                 case 2:
1106                                         s390_lh (p, s390_r2, 0, s390_r10, 0);
1107                                         break;
1108                                 case 4:
1109                                         s390_lgf(p, s390_r2, 0, s390_r10, 0);
1110                                         break;
1111                                 case 8:
1112                                         s390_lg (p, s390_r2, 0, s390_r10, 0);
1113                                         break;
1114                                 default: ;
1115                                         /*-------------------------------------------------*/
1116                                         /* stackval_to_data has placed data in result area */
1117                                         /*-------------------------------------------------*/
1118                         }
1119                         break;
1120                 default:
1121                         g_error ("Type 0x%x not handled yet in thunk creation", 
1122                                  sig->ret->type);
1123                         break;
1124                 }
1125         }
1126
1127         /*----------------------------------------------------------*/ 
1128         /* epilog                                                   */
1129         /*----------------------------------------------------------*/ 
1130         s390_lg   (p, STK_BASE, 0, STK_BASE, 0);
1131         s390_lg   (p, s390_r4, 0, STK_BASE, S390_RET_ADDR_OFFSET);
1132         s390_lmg  (p, s390_r6, STK_BASE, STK_BASE, S390_REG_SAVE_OFFSET);
1133         s390_br   (p, s390_r4);
1134
1135         DEBUG (printf ("emited code size: %d\n", p - code_buffer));
1136
1137         DEBUG (printf ("Delegate [end emiting]\n"));
1138
1139         ji = g_new0 (MonoJitInfo, 1);
1140         ji->method = method;
1141         ji->code_size = p - code_buffer;
1142         ji->code_start = code_buffer;
1143
1144         mono_jit_info_table_add (mono_get_root_domain (), ji);
1145
1146         return ji->code_start;
1147 }
1148
1149 /*========================= End of Function ========================*/