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