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
add_general(guint * gr,size_data * sz,gboolean simple)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
calculate_sizes(MonoMethodSignature * sig,size_data * sz,gboolean string_ctor)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 *
emit_prolog(guint8 * p,MonoMethodSignature * sig,size_data * sz)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*
emit_save_parameters(guint8 * p,MonoMethodSignature * sig,size_data * sz)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 *
alloc_code_memory(guint code_size)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 *
emit_call_and_store_retval(guint8 * p,MonoMethodSignature * sig,size_data * sz,gboolean string_ctor)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 *
emit_epilog(guint8 * p,MonoMethodSignature * sig,size_data * sz)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
mono_arch_create_trampoline(MonoMethodSignature * sig,gboolean string_ctor)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 *
mono_arch_create_method_pointer(MonoMethod * method)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 ========================*/
1150