* roottypes.cs: Rename from tree.cs.
[mono.git] / mono / arch / sparc / tramp.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Create trampolines to invoke arbitrary functions.
4  * 
5  * Copyright (C) Ximian Inc.
6  *
7  * Authors: Paolo Molaro (lupus@ximian.com)
8  *          Jeffrey Stedfast <fejj@ximian.com>
9  *          Mark Crichton <crichton@gimp.org>
10  *
11  */
12
13 #include "config.h"
14 #include <stdlib.h>
15 #include <string.h>
16 #include "sparc-codegen.h"
17 #include "mono/metadata/class.h"
18 #include "mono/metadata/tabledefs.h"
19 #include "mono/interpreter/interp.h"
20 #include "mono/metadata/appdomain.h"
21 #include "mono/metadata/debug-helpers.h"
22 #include "mono/metadata/marshal.h"
23
24
25 #define ARG_SIZE        sizeof (stackval)
26 #define PROLOG_INS 1
27 #define CALL_INS 3  /* Max 3.  1 for the jmpl and 1 for the nop and 1 for the possible unimp */
28 #define EPILOG_INS 2
29 #define FLOAT_REGS 32
30 #define OUT_REGS 6
31 #define LOCAL_REGS 8
32 #define SLOT_SIZE sizeof(gpointer)
33 #if SPARCV9
34 #define MINIMAL_STACK_SIZE 22
35 #define BIAS 2047
36 #define FRAME_ALIGN 16
37 #else
38 #define MINIMAL_STACK_SIZE 23
39 #define BIAS 0
40 #define FRAME_ALIGN 8
41 #endif
42
43 #define NOT_IMPL(x) g_error("FIXME: %s", x);
44 /*#define DEBUG(a) a*/
45 #define DEBUG(a)
46
47 /* Some assembly... */
48 #ifdef __GNUC__
49 #define flushi(addr)    __asm__ __volatile__ ("flush %0"::"r"(addr):"memory")
50 #else
51 static void flushi(void *addr)
52 {
53     asm("flush %i0");
54 }
55 #endif
56
57 static char*
58 sig_to_name (MonoMethodSignature *sig, const char *prefix)
59 {
60         int i;
61         char *result;
62         GString *res = g_string_new ("");
63         char *p;
64
65         if (prefix) {
66                 g_string_append (res, prefix);
67                 g_string_append_c (res, '_');
68         }
69
70         mono_type_get_desc (res, sig->ret, TRUE);
71
72         for (i = 0; i < sig->param_count; ++i) {
73                 g_string_append_c (res, '_');
74                 mono_type_get_desc (res, sig->params [i], TRUE);
75         }
76         result = res->str;
77         p = result;
78         /* remove chars Sun's asssembler doesn't like */
79         while (*p != '\0') {
80                 if (*p == '.' || *p == '/')
81                         *p = '_';
82                 else if (*p == '&')
83                         *p = '$';
84                 else if (*p == '[' || *p == ']')
85                         *p = 'X';
86                 p++;
87         }
88         g_string_free (res, FALSE);
89         return result;
90 }
91
92 static void
93 sparc_disassemble_code (guint32 *code_buffer, guint32 *p, const char *id)
94 {
95         guchar *cp;
96         FILE *ofd;
97
98         if (!(ofd = fopen ("/tmp/test.s", "w")))
99                 g_assert_not_reached();
100
101         fprintf (ofd, "%s:\n", id);
102
103         for (cp = (guchar *)code_buffer; cp < (guchar *)p; cp++)
104                 fprintf (ofd, ".byte %d\n", *cp);
105
106         fclose (ofd);
107
108 #ifdef __GNUC__
109         system ("as /tmp/test.s -o /tmp/test.o;objdump -d /tmp/test.o");
110 #else
111         /* this assumes we are using Sun tools as we aren't GCC */
112 #if SPARCV9
113         system ("as -xarch=v9 /tmp/test.s -o /tmp/test.o;dis /tmp/test.o");
114 #else
115         system ("as /tmp/test.s -o /tmp/test.o;dis /tmp/test.o");
116 #endif
117 #endif
118 }
119
120
121 static void
122 add_general (guint *gr, guint *stack_size, guint *code_size, gboolean simple)
123 {
124         if (simple) {
125                 if (*gr >= OUT_REGS) {
126                         *stack_size += SLOT_SIZE;
127                         *code_size += 12;
128                 } else {
129                         *code_size += 4;
130                 }
131         } else {
132                 if (*gr >= OUT_REGS - 1) {
133                         *stack_size += 8 + (*stack_size % 8); /* ???64 */
134                         *code_size += 16;
135                 } else {
136                         *code_size += 16;
137                 }
138                 (*gr)++;
139         }
140         (*gr)++;
141 }
142
143 static void
144 calculate_sizes (MonoMethodSignature *sig, guint *stack_size, guint *code_size,
145                  gboolean string_ctor, gboolean *use_memcpy)
146 {
147         guint i, fr, gr;
148         guint32 simpletype;
149         
150         fr = gr = 0;
151         *stack_size = MINIMAL_STACK_SIZE * SLOT_SIZE;
152         *code_size = (PROLOG_INS + CALL_INS + EPILOG_INS) * 4;
153         
154         /* function arguments */
155         if (sig->hasthis)
156                 add_general (&gr, stack_size, code_size, TRUE);
157         
158         for (i = 0; i < sig->param_count; i++) {
159                 if (sig->params[i]->byref) {
160                         add_general (&gr, stack_size, code_size, TRUE);
161                         continue;
162                 }
163                 simpletype = sig->params[i]->type;
164         enum_calc_size:
165                 switch (simpletype) {
166                 case MONO_TYPE_R4:
167 #if SPARCV9
168                         (*code_size) += 4; /* for the fdtos */
169 #else
170                         (*code_size) += 12;
171                         (*stack_size) += 4;
172 #endif
173                 case MONO_TYPE_BOOLEAN:
174                 case MONO_TYPE_CHAR:
175                 case MONO_TYPE_I1:
176                 case MONO_TYPE_U1:
177                 case MONO_TYPE_I2:
178                 case MONO_TYPE_U2:
179                 case MONO_TYPE_I4:
180                 case MONO_TYPE_U4:
181                 case MONO_TYPE_I:
182                 case MONO_TYPE_U:
183                 case MONO_TYPE_PTR:
184                 case MONO_TYPE_CLASS:
185                 case MONO_TYPE_OBJECT:
186                 case MONO_TYPE_STRING:
187                 case MONO_TYPE_SZARRAY:
188                         add_general (&gr, stack_size, code_size, TRUE);
189                         break;
190                 case MONO_TYPE_VALUETYPE: {
191                         gint size;
192                         guint32 align;
193                         if (sig->params[i]->data.klass->enumtype) {
194                                 simpletype = sig->params[i]->data.klass->enum_basetype->type;
195                                 goto enum_calc_size;
196                         }
197                         size = mono_class_native_size (sig->params[i]->data.klass, &align);
198 #if SPARCV9
199                         if (size != 4) {
200 #else
201                         if (1) {
202 #endif
203                                 DEBUG(fprintf(stderr, "copy %d byte struct on stack\n", size));
204                                 *use_memcpy = TRUE;
205                                 *code_size += 8*4;
206
207                                 *stack_size = (*stack_size + (align - 1)) & (~(align -1));
208                                 *stack_size += (size + 3) & (~3);
209                                 if (gr > OUT_REGS) {
210                                         *code_size += 4;
211                                         *stack_size += 4;
212                                 }
213                         } else {
214                                 add_general (&gr, stack_size, code_size, TRUE); 
215 #if SPARCV9
216                                 *code_size += 8;
217 #else
218                                 *code_size += 4;
219 #endif
220                         }
221                         break;
222                 }
223                 case MONO_TYPE_I8:
224                 case MONO_TYPE_R8:
225                         add_general (&gr, stack_size, code_size, FALSE);
226                         break;
227                 default:
228                         g_error ("Can't trampoline 0x%x", sig->params[i]->type);
229                 }
230         }
231         
232         /* function return value */
233         if (sig->ret->byref || string_ctor) {
234                 *code_size += 8;
235         } else {
236                 simpletype = sig->ret->type;
237         enum_retvalue:
238                 switch (simpletype) {
239                 case MONO_TYPE_BOOLEAN:
240                 case MONO_TYPE_I1:
241                 case MONO_TYPE_U1:
242                 case MONO_TYPE_I2:
243                 case MONO_TYPE_U2:
244                 case MONO_TYPE_CHAR:
245                 case MONO_TYPE_I4:
246                 case MONO_TYPE_U4:
247                 case MONO_TYPE_I:
248                 case MONO_TYPE_U:
249                 case MONO_TYPE_CLASS:
250                 case MONO_TYPE_OBJECT:
251                 case MONO_TYPE_PTR:
252                 case MONO_TYPE_STRING:
253                 case MONO_TYPE_R4:
254                 case MONO_TYPE_R8:
255                 case MONO_TYPE_SZARRAY:
256                 case MONO_TYPE_ARRAY:
257                         *code_size += 8;
258                         break;
259                 case MONO_TYPE_I8:
260                         *code_size += 12;
261                         break;
262                 case MONO_TYPE_VALUETYPE: {
263                         gint size;
264                         if (sig->ret->data.klass->enumtype) {
265                                 simpletype = sig->ret->data.klass->enum_basetype->type;
266                                 goto enum_retvalue;
267                         }
268                         size = mono_class_native_size (sig->ret->data.klass, NULL);
269 #if SPARCV9
270                         if (size <= 32)
271                                 *code_size += 8 + (size + 7) / 2;
272                         else
273                                 *code_size += 8;
274 #else
275                         *code_size += 8;
276 #endif
277                         break;
278                 }
279                 case MONO_TYPE_VOID:
280                         break;
281                 default:
282                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
283                 }
284         }
285         
286         if (*use_memcpy) {
287                 *stack_size += 8;
288                 *code_size += 24;
289                 if (sig->hasthis) {
290                         *stack_size += SLOT_SIZE;
291                         *code_size += 4;
292                 }
293         }
294         
295         *stack_size = (*stack_size + (FRAME_ALIGN - 1)) & (~(FRAME_ALIGN -1));
296 }       
297         
298 static inline guint32 *
299 emit_epilog (guint32 *p, MonoMethodSignature *sig, guint stack_size)
300 {
301         int ret_offset = 8;
302
303         /*
304          * Standard epilog.
305          * 8 may be 12 when returning structures (to skip unimp opcode).
306          */
307 #if !SPARCV9
308         if (sig != NULL && !sig->ret->byref && sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->data.klass->enumtype)
309                 ret_offset = 12;
310 #endif
311         sparc_jmpl_imm (p, sparc_i7, ret_offset, sparc_zero);
312         sparc_restore (p, sparc_zero, sparc_zero, sparc_zero);
313         
314         return p;
315 }
316
317 static inline guint32 *
318 emit_prolog (guint32 *p, MonoMethodSignature *sig, guint stack_size)
319 {
320         /* yes kids, it is this simple! */
321         sparc_save_imm (p, sparc_sp, -stack_size, sparc_sp);
322         return p;
323 }
324
325 #if SPARCV9
326 #define sparc_st_ptr(a,b,c,d) sparc_stx(a,b,c,d)
327 #define sparc_st_imm_ptr(a,b,c,d) sparc_stx_imm(a,b,c,d)
328 #define sparc_ld_ptr(a,b,c,d) sparc_ldx(a,b,c,d)
329 #define sparc_ld_imm_ptr(a,b,c,d) sparc_ldx_imm(a,b,c,d)
330 #else
331 #define sparc_st_ptr(a,b,c,d) sparc_st(a,b,c,d)
332 #define sparc_st_imm_ptr(a,b,c,d) sparc_st_imm(a,b,c,d)
333 #define sparc_ld_ptr(a,b,c,d) sparc_ld(a,b,c,d)
334 #define sparc_ld_imm_ptr(a,b,c,d) sparc_ld_imm(a,b,c,d)
335 #endif
336
337 /* synonyms for when values are really widened scalar values */
338 #define sparc_st_imm_word sparc_st_imm_ptr
339
340 #define ARG_BASE sparc_i3 /* pointer to args in i3 */
341 #define SAVE_PTR_IN_GENERIC_REGISTER \
342               if (gr < OUT_REGS) { \
343                       sparc_ld_imm_ptr (p, ARG_BASE, i*ARG_SIZE, sparc_o0 + gr); \
344                       gr++; \
345               } else { \
346                       sparc_ld_imm_ptr (p, ARG_BASE, i*ARG_SIZE, sparc_l0); \
347                       sparc_st_imm_ptr (p, sparc_l0, sparc_sp, stack_par_pos); \
348                       stack_par_pos += SLOT_SIZE; \
349               }
350
351 #if SPARCV9
352 /* This is a half hearted attempt at coping with structs by value - the 
353    actual convention is complicated when floats & doubles are involved as
354    you end up with fields in different registers on/off the stack.
355    It will take more time to get right... */
356 static guint32 *
357 v9_struct_arg(guint32 *p, int arg_index, MonoClass *klass, int size, guint *p_gr)
358 {
359         MonoMarshalType *info = mono_marshal_load_type_info (klass);
360         int off = 0;
361         int index = 0;
362         guint gr = *p_gr;
363         sparc_ld_imm_ptr (p, ARG_BASE, arg_index*ARG_SIZE, sparc_l0);
364         if (size > 8) {
365                 if (info->fields [index].field->type->type == MONO_TYPE_R8) {
366                         sparc_lddf_imm (p, sparc_l0, 0, sparc_f0 + 2 * gr);
367                         index++;
368                 }
369                 else {
370                         sparc_ldx_imm (p, sparc_l0, 0, sparc_o0 + gr);
371                         index++; /* FIXME could be multiple fields in one register */
372                 }
373                 gr++;
374                 size -= 8;
375                 off = 8;
376         }
377         if (size > 0) {
378                 if (info->fields [index].field->type->type == MONO_TYPE_R8) {
379                         sparc_lddf_imm (p, sparc_l0, off, sparc_f0 + 2 * gr);
380                         index++;
381                 }
382                 else {
383                         /* will load extra garbage off end of short structs ... */
384                         sparc_ldx_imm (p, sparc_l0, off, sparc_o0 + gr);
385                 }
386                 gr++;
387         } 
388         *p_gr = gr;
389         return p;
390 }
391 #endif
392
393 static inline guint32*
394 emit_save_parameters (guint32 *p, MonoMethodSignature *sig, guint stack_size,
395                       gboolean use_memcpy)
396 {
397         guint i, fr, gr, stack_par_pos, struct_pos, cur_struct_pos;
398         guint32 simpletype;
399
400         fr = gr = 0;
401         stack_par_pos = MINIMAL_STACK_SIZE * SLOT_SIZE + BIAS;
402
403         if (sig->hasthis) {
404                 if (use_memcpy) {
405                         /* we don't need to save a thing. */
406                 } else 
407                         sparc_mov_reg_reg (p, sparc_i2, sparc_o0);
408                 gr ++;
409         }
410
411         if (use_memcpy) {
412                 cur_struct_pos = struct_pos = stack_par_pos;
413                 for (i = 0; i < sig->param_count; i++) {
414                         if (sig->params[i]->byref)
415                                 continue;
416                         if (sig->params[i]->type == MONO_TYPE_VALUETYPE &&
417                             !sig->params[i]->data.klass->enumtype) {
418                                 gint size;
419                                 guint32 align;
420                                 
421                                 size = mono_class_native_size (sig->params[i]->data.klass, &align);
422 #if SPARCV9
423                                 if (size != 4) {
424 #else
425                                 if (1) {
426 #endif
427                                         /* Add alignment */
428                                         stack_par_pos = (stack_par_pos + (align - 1)) & (~(align - 1));
429                                         /* need to call memcpy here */
430                                         sparc_add_imm (p, 0, sparc_sp, stack_par_pos, sparc_o0);
431                                         sparc_ld_imm_ptr (p, sparc_i3, i*16, sparc_o1);
432                                         sparc_set (p, (guint32)size, sparc_o2);
433                                         sparc_set_ptr (p, (void *)memmove, sparc_l0);
434                                         sparc_jmpl_imm (p, sparc_l0, 0, sparc_callsite);
435                                         sparc_nop (p);
436                                         stack_par_pos += (size + (SLOT_SIZE - 1)) & (~(SLOT_SIZE - 1));
437                                 }
438                         }
439                 }
440         }
441
442         if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref) {
443                 MonoClass *klass = sig->ret->data.klass;
444                 if (!klass->enumtype) {
445                         gint size = mono_class_native_size (klass, NULL);
446
447                         DEBUG(fprintf(stderr, "retval value type size: %d\n", size));
448 #if SPARCV9
449                         if (size > 32) {
450 #else
451                         {
452 #endif
453                                 /* pass on buffer in interp.c to called function */
454                                 sparc_ld_imm_ptr (p, sparc_i1, 0, sparc_l0);
455                                 sparc_st_imm_ptr (p, sparc_l0, sparc_sp, 64);
456                         }
457                 }
458         }
459
460         DEBUG(fprintf(stderr, "%s\n", sig_to_name(sig, FALSE)));
461
462         for (i = 0; i < sig->param_count; i++) {
463                 if (sig->params[i]->byref) {
464                         SAVE_PTR_IN_GENERIC_REGISTER;
465                         continue;
466                 }
467                 simpletype = sig->params[i]->type;
468         enum_calc_size:
469                 switch (simpletype) {
470                 case MONO_TYPE_BOOLEAN:
471                 case MONO_TYPE_I1:
472                 case MONO_TYPE_U1:
473                 case MONO_TYPE_I2:
474                 case MONO_TYPE_U2:
475                 case MONO_TYPE_CHAR:
476                 case MONO_TYPE_I4:
477                 case MONO_TYPE_U4:
478                         if (gr < OUT_REGS) {
479                                 sparc_ld_imm (p, ARG_BASE, i*ARG_SIZE, sparc_o0 + gr);
480                                 gr++;
481                         } else {
482                                 sparc_ld_imm (p, ARG_BASE, i*ARG_SIZE, sparc_l0);
483                                 sparc_st_imm_word (p, sparc_l0, sparc_sp, stack_par_pos);
484                                 stack_par_pos += SLOT_SIZE;
485                         }
486                         break;
487
488                 case MONO_TYPE_R4:
489 #if SPARCV9
490                         sparc_lddf_imm (p, ARG_BASE, i*ARG_SIZE, sparc_f30); /* fix using this fixed reg */
491                         sparc_fdtos(p, sparc_f30, sparc_f0 + 2 * gr + 1);
492                         gr++;
493                         break;
494 #else
495                         /* Convert from double to single */
496                         sparc_lddf_imm (p, ARG_BASE, i*ARG_SIZE, sparc_f0);
497                         sparc_fdtos (p, sparc_f0, sparc_f0);
498
499                         /*
500                          * FIXME: Is there an easier way to do an
501                          * freg->ireg move ?
502                          */
503                         sparc_stf_imm (p, sparc_f0, sparc_sp, stack_par_pos);
504
505                         if (gr < OUT_REGS) {
506                                 sparc_ld_imm (p, sparc_sp, stack_par_pos, sparc_o0 + gr);
507                                 gr++;
508                         } else {
509                                 sparc_ldf_imm (p, sparc_sp, stack_par_pos, sparc_f0);
510                                 sparc_stf_imm (p, sparc_f0, sparc_sp, stack_par_pos);
511                                 stack_par_pos += SLOT_SIZE;
512                         }
513                         break;
514 #endif
515
516                 case MONO_TYPE_I:
517                 case MONO_TYPE_U:
518                 case MONO_TYPE_PTR:
519                 case MONO_TYPE_CLASS:
520                 case MONO_TYPE_OBJECT:
521                 case MONO_TYPE_STRING:
522                 case MONO_TYPE_SZARRAY:
523                         SAVE_PTR_IN_GENERIC_REGISTER;
524                         break;
525                 case MONO_TYPE_VALUETYPE: {
526                         gint size;
527                         guint32 align;
528                         MonoClass *klass = sig->params[i]->data.klass;
529                         if (klass->enumtype) {
530                                 simpletype = klass->enum_basetype->type;
531                                 goto enum_calc_size;
532                         }
533                         size = mono_class_native_size (klass, &align);
534 #if SPARCV9
535                         if (size <= 16) {
536                                 if (gr < OUT_REGS) {
537                                         p = v9_struct_arg(p, i, klass, size, &gr);
538                                 } else {
539                                         sparc_ld_imm_ptr (p, ARG_BASE, i*ARG_SIZE, sparc_l0);
540                                         sparc_ld_imm (p, sparc_l0, 0, sparc_l0);
541                                         sparc_st_imm_word (p, sparc_l0, sparc_sp, stack_par_pos);
542                                         stack_par_pos += SLOT_SIZE;
543                                 }
544                                 break;
545                         }
546 #else
547                         /* 
548                          * FIXME: The 32bit ABI docs do not mention that small
549                          * structures are passed in registers.
550                          */
551
552                         /*
553                         if (size == 4) {
554                                 if (gr < OUT_REGS) {
555                                         sparc_ld_imm_ptr (p, ARG_BASE, i*ARG_SIZE, sparc_l0);
556                                         sparc_ld_imm (p, sparc_l0, 0, sparc_o0 + gr);
557                                         gr++;
558                                 } else {
559                                         sparc_ld_imm_ptr (p, ARG_BASE, i*ARG_SIZE, sparc_l0);
560                                         sparc_ld_imm (p, sparc_l0, 0, sparc_l0);
561                                         sparc_st_imm_word (p, sparc_l0, sparc_sp, stack_par_pos);
562                                         stack_par_pos += SLOT_SIZE;
563                                 }
564                                 break;
565                         }
566                         */
567 #endif
568
569                         cur_struct_pos = (cur_struct_pos + (align - 1)) & (~(align - 1));
570                         if (gr < OUT_REGS) {
571                                 sparc_add_imm (p, 0, sparc_sp,
572                                                cur_struct_pos, sparc_o0 + gr);
573                                 gr ++;
574                         } else {
575                                 sparc_ld_imm_ptr (p, sparc_sp,
576                                                   cur_struct_pos,
577                                                   sparc_l1);
578                                 sparc_st_imm_ptr (p, sparc_l1,
579                                                   sparc_sp,
580                                                   stack_par_pos);
581                         }
582                         cur_struct_pos += (size + (SLOT_SIZE - 1)) & (~(SLOT_SIZE - 1));
583                         break;
584                 }
585
586 #if SPARCV9
587                 case MONO_TYPE_I8:
588                         if (gr < OUT_REGS) {
589                                 sparc_ldx_imm (p, ARG_BASE, i*ARG_SIZE, sparc_o0 + gr);
590                                 gr++;
591                         } else {
592                                 sparc_ldx_imm (p, ARG_BASE, i*ARG_SIZE, sparc_l0);
593                                 sparc_stx_imm (p, sparc_l0, sparc_sp, stack_par_pos);
594                                 stack_par_pos += SLOT_SIZE;
595                         }
596                         break;
597                 case MONO_TYPE_R8:
598                         sparc_lddf_imm (p, ARG_BASE, i*ARG_SIZE, sparc_f0 + 2 * i);
599                         break;
600 #else
601                 case MONO_TYPE_I8:
602                 case MONO_TYPE_R8:
603                         if (gr < (OUT_REGS - 1)) {
604                                 sparc_ld_imm (p, ARG_BASE, i*ARG_SIZE, sparc_o0 + gr);
605                                 gr ++;
606                                 
607                                 sparc_ld_imm (p, ARG_BASE, 
608                                               (i*ARG_SIZE) + 4,
609                                               sparc_o0 + gr);
610                                 gr ++;
611                         } else if (gr == (OUT_REGS - 1)) {
612                                 /* Split register/stack */
613                                 sparc_ld_imm (p, ARG_BASE, i*ARG_SIZE, sparc_o0 + gr);
614                                 gr ++;
615
616                                 sparc_ld_imm (p, ARG_BASE, (i*ARG_SIZE) + 4, sparc_l0);
617                                 sparc_st_imm (p, sparc_l0, sparc_sp, stack_par_pos);
618                                 stack_par_pos += SLOT_SIZE;
619                         } else {
620                                 sparc_ld_imm (p, ARG_BASE, i*ARG_SIZE, sparc_l0);
621                                 sparc_st_imm (p, sparc_l0, sparc_sp, stack_par_pos);
622                                 stack_par_pos += SLOT_SIZE;
623
624                                 sparc_ld_imm (p, ARG_BASE, (i*ARG_SIZE) + 4, sparc_l0);
625                                 sparc_st_imm (p, sparc_l0, sparc_sp, stack_par_pos);
626                                 stack_par_pos += SLOT_SIZE;
627                         }
628                         break;
629 #endif
630                 default:
631                         g_error ("Can't trampoline 0x%x", sig->params[i]->type);
632                 }
633         }
634
635         g_assert ((stack_par_pos - BIAS) <= stack_size);
636
637         return p;
638 }
639
640 static inline guint32 *
641 alloc_code_memory (guint code_size)
642 {
643         guint32 *p;
644
645         p = g_malloc(code_size);
646
647         return p;
648 }
649
650 static inline guint32 *
651 emit_call_and_store_retval (guint32 *p, MonoMethodSignature *sig,
652                             guint stack_size, gboolean string_ctor)
653 {
654         guint32 simpletype;
655
656         /* call "callme" */
657         sparc_jmpl_imm (p, sparc_i0, 0, sparc_callsite);
658         sparc_nop (p);
659 #if !SPARCV9
660         if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->data.klass->enumtype) {
661                 int size = mono_class_native_size (sig->ret->data.klass, NULL);
662                 sparc_unimp (p, size & 4095);
663         }
664 #endif
665
666         /* get return value */
667         if (sig->ret->byref || string_ctor) {
668                 sparc_st_ptr (p, sparc_o0, sparc_i1, 0);
669         } else {
670                 simpletype = sig->ret->type;
671         enum_retval:
672                 switch (simpletype) {
673                 case MONO_TYPE_BOOLEAN:
674                 case MONO_TYPE_I1:
675                 case MONO_TYPE_U1:
676                         sparc_stb (p, sparc_o0, sparc_i1, 0);
677                         break;
678                 case MONO_TYPE_CHAR:
679                 case MONO_TYPE_I2:
680                 case MONO_TYPE_U2:
681                         sparc_sth (p, sparc_o0, sparc_i1, 0);
682                         break;
683                 case MONO_TYPE_I4:
684                 case MONO_TYPE_U4:
685                         sparc_st (p, sparc_o0, sparc_i1, 0);
686                         break;
687                 case MONO_TYPE_I:
688                 case MONO_TYPE_U:
689                 case MONO_TYPE_CLASS:
690                 case MONO_TYPE_OBJECT:
691                 case MONO_TYPE_SZARRAY:
692                 case MONO_TYPE_ARRAY:
693                 case MONO_TYPE_STRING:
694                 case MONO_TYPE_PTR:
695                         sparc_st_ptr (p, sparc_o0, sparc_i1, 0);
696                         break;
697                 case MONO_TYPE_R4:
698                         sparc_stf (p, sparc_f0, sparc_i1, 0);
699                         break;
700                 case MONO_TYPE_R8:
701                         sparc_stdf (p, sparc_f0, sparc_i1, 0);
702                         break;
703                 case MONO_TYPE_I8:
704 #if SPARCV9
705                         sparc_stx (p, sparc_o0, sparc_i1, 0);
706 #else
707                         sparc_std (p, sparc_o0, sparc_i1, 0);
708 #endif
709                         break;
710                 case MONO_TYPE_VALUETYPE: {
711                         gint size;
712                         if (sig->ret->data.klass->enumtype) {
713                                 simpletype = sig->ret->data.klass->enum_basetype->type;
714                                 goto enum_retval;
715                         }
716 #if SPARCV9
717                         size = mono_class_native_size (sig->ret->data.klass, NULL);
718                         if (size <= 32) {
719                                 int n_regs = size / 8;
720                                 int j;
721                                 sparc_ldx_imm (p, sparc_i1, 0, sparc_i1);
722                                 /* wrong if there are floating values in the struct... */
723                                 for (j = 0; j < n_regs; j++) {
724                                         sparc_stx_imm (p, sparc_o0 + j, sparc_i1, j * 8);
725                                 }
726                                 size -= n_regs * 8;
727                                 if (size > 0) {
728                                         int last_reg = sparc_o0 + n_regs;
729                                         /* get value right aligned in register */
730                                         sparc_srlx_imm(p, last_reg, 64 - 8 * size, last_reg);
731                                         if ((size & 1) != 0) {
732                                                 sparc_stb_imm (p, last_reg, sparc_i1, n_regs * 8 + size - 1);
733                                                 size--;
734                                                 if (size > 0)
735                                                         sparc_srlx_imm(p, last_reg, 8, last_reg);
736                                         }
737                                         if ((size & 2) != 0) {
738                                                 sparc_sth_imm (p, last_reg, sparc_i1, n_regs * 8 + size - 2);
739                                                 size -= 2;
740                                                 if (size > 0)
741                                                         sparc_srlx_imm(p, last_reg, 16, last_reg);
742                                         }
743                                         if ((size & 4) != 0)
744                                                 sparc_st_imm (p, last_reg, sparc_i1, n_regs * 8);
745                                 }
746                         }
747 #endif
748                 }
749                 case MONO_TYPE_VOID:
750                         break;
751                 default:
752                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
753                 }
754         }
755         return p;
756 }
757
758 MonoPIFunc
759 mono_arch_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor)
760 {
761         guint32 *p, *code_buffer;
762         guint stack_size, code_size, i;
763         gboolean use_memcpy = FALSE;
764         static GHashTable *cache = NULL;
765         MonoPIFunc res;
766
767         if (!cache)
768                 cache = g_hash_table_new ((GHashFunc)mono_signature_hash,
769                                  (GCompareFunc)mono_metadata_signature_equal);
770         
771         if ((res = (MonoPIFunc)g_hash_table_lookup(cache, sig)))
772                 return res;
773
774         calculate_sizes (sig, &stack_size, &code_size, 
775                          string_ctor, &use_memcpy);
776
777         p = code_buffer = alloc_code_memory (code_size);
778         p = emit_prolog (p, sig, stack_size);
779         p = emit_save_parameters (p, sig, stack_size, use_memcpy);
780         p = emit_call_and_store_retval (p, sig, stack_size, string_ctor);
781         /* we don't return structs here so pass in NULL as signature */
782         p = emit_epilog (p, NULL, stack_size);
783
784         g_assert(p <= code_buffer + (code_size / 4));
785         
786         DEBUG(sparc_disassemble_code (code_buffer, p, sig_to_name(sig, NULL)));
787
788         /* So here's the deal...
789          * UltraSPARC will flush a whole cache line at a time
790          * BUT, older SPARCs won't.
791          * So, be compatable and flush dwords at a time...
792          */
793
794         for (i = 0; i < ((p - code_buffer)/2); i++)
795                 flushi((code_buffer + (i*8)));
796
797         g_hash_table_insert(cache, sig, code_buffer);
798
799         return (MonoPIFunc)code_buffer;
800 }
801
802 #define MINV_POS (MINIMAL_STACK_SIZE * SLOT_SIZE + BIAS)
803
804 void *
805 mono_arch_create_method_pointer (MonoMethod *method)
806 {
807         MonoMethodSignature *sig;
808         MonoJitInfo *ji;
809         guint stack_size, code_size, stackval_arg_pos, local_pos;
810         guint i, local_start, reg_param = 0, stack_param, cpos, vt_cur;
811         guint32 align = 0;
812         guint32 *p, *code_buffer;
813         gint *vtbuf;
814         gint32 simpletype;
815
816         code_size = 1024; /* these should be calculated... */
817         stack_size = 1024;
818         stack_param = 0;
819
820         sig = method->signature;
821
822         p = code_buffer = g_malloc (code_size);
823
824         DEBUG(fprintf(stderr, "Delegate [start emiting] %s\n", method->name));
825         DEBUG(fprintf(stderr, "%s\n", sig_to_name(sig, FALSE)));
826
827         p = emit_prolog (p, sig, stack_size);
828
829         /* fill MonoInvocation */
830         sparc_st_imm_ptr (p, sparc_g0, sparc_sp,
831                   (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex)));
832         sparc_st_imm_ptr (p, sparc_g0, sparc_sp,
833                   (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex_handler)));
834         sparc_st_imm_ptr (p, sparc_g0, sparc_sp,
835                   (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, parent)));
836
837         sparc_set_ptr (p, (void *)method, sparc_l0);
838         sparc_st_imm_ptr (p, sparc_l0, sparc_sp,
839                   (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, method)));
840
841         stackval_arg_pos = MINV_POS + sizeof (MonoInvocation);
842         local_start = local_pos = stackval_arg_pos + (sig->param_count + 1) * sizeof (stackval);
843
844         if (sig->hasthis) {
845                 sparc_st_imm_ptr (p, sparc_i0, sparc_sp,
846                           (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)));
847                 reg_param = 1;
848         } 
849
850         if (sig->param_count) {
851                 gint save_count = MIN (OUT_REGS, sig->param_count + sig->hasthis);
852                 for (i = reg_param; i < save_count; i++) {
853                         sparc_st_imm_ptr (p, sparc_i0 + i, sparc_sp, local_pos);
854                         local_pos += SLOT_SIZE;
855                 }
856         }
857
858         /* prepare space for valuetypes */
859         vt_cur = local_pos;
860         vtbuf = alloca (sizeof(int)*sig->param_count);
861         cpos = 0;
862         for (i = 0; i < sig->param_count; i++) {
863                 MonoType *type = sig->params [i];
864                 vtbuf [i] = -1;
865                 if (!sig->params[i]->byref && type->type == MONO_TYPE_VALUETYPE) {
866                         MonoClass *klass = type->data.klass;
867                         gint size;
868                         
869                         if (klass->enumtype)
870                                 continue;
871                         size = mono_class_native_size (klass, &align);
872                         cpos += align - 1;
873                         cpos &= ~(align - 1);
874                         vtbuf [i] = cpos;
875                         cpos += size;
876                 }
877         }
878         cpos += SLOT_SIZE - 1;
879         cpos &= ~(SLOT_SIZE - 1);
880         
881         local_pos += cpos;
882         
883         /* set MonoInvocation::stack_args */
884         sparc_add_imm (p, 0, sparc_sp, stackval_arg_pos, sparc_l0);
885         sparc_st_imm_ptr (p, sparc_l0, sparc_sp,
886                   (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, stack_args)));
887
888         /* add stackval arguments */
889         for (i=0; i < sig->param_count; i++) {
890                 int stack_offset;
891                 int type;
892                 if (reg_param < OUT_REGS) {
893                         stack_offset = local_start + i * SLOT_SIZE;
894                         reg_param++;
895                 } else {
896                         stack_offset = stack_size + 8 + stack_param;
897                         stack_param++;
898                 }
899
900                 if (!sig->params[i]->byref) {
901                         type = sig->params[i]->type;
902                 enum_arg:
903                         switch (type) {
904                         case MONO_TYPE_I8:
905                         case MONO_TYPE_U8:
906                         case MONO_TYPE_I:
907                         case MONO_TYPE_U:
908                         case MONO_TYPE_STRING:
909                         case MONO_TYPE_OBJECT:
910                         case MONO_TYPE_CLASS:
911                         case MONO_TYPE_SZARRAY:
912                         case MONO_TYPE_PTR:
913                         case MONO_TYPE_R8:
914                                 break;
915                         case MONO_TYPE_I4:
916                         case MONO_TYPE_U4:
917                                 stack_offset += SLOT_SIZE - 4;
918                                 break;
919                         case MONO_TYPE_CHAR:
920                         case MONO_TYPE_I2:
921                         case MONO_TYPE_U2:
922                                 stack_offset += SLOT_SIZE - 2;
923                                 break;
924                         case MONO_TYPE_I1:
925                         case MONO_TYPE_U1:
926                         case MONO_TYPE_BOOLEAN:
927                                 stack_offset += SLOT_SIZE - 1;
928                                 break;
929                         case MONO_TYPE_VALUETYPE:
930                                 if (sig->params[i]->data.klass->enumtype) {
931                                         type = sig->params[i]->data.klass->enum_basetype->type;
932                                         goto enum_arg;
933                                 }
934                                 g_assert(vtbuf[i] >= 0);
935                                 break;
936                         default:
937                                 g_error ("can not cope with delegate arg type %d", type);
938                         }
939                 }
940         
941                 sparc_add_imm (p, 0, sparc_sp, stack_offset, sparc_o2);
942
943                 if (vtbuf[i] >= 0) {
944                         sparc_add_imm (p, 0, sparc_sp, vt_cur, sparc_o1);
945                         sparc_st_imm_ptr (p, sparc_o1, sparc_sp, stackval_arg_pos);
946                         sparc_add_imm (p, 0, sparc_sp, stackval_arg_pos, 
947                                        sparc_o1);
948                         sparc_ld_imm_ptr (p, sparc_o2, 0, sparc_o2);
949                         vt_cur += vtbuf[i];
950                 } else {
951                         sparc_add_imm (p, 0, sparc_sp, stackval_arg_pos, 
952                                        sparc_o1);
953                 }
954
955                 sparc_set_ptr (p, (void *)sig->params[i], sparc_o0);
956                 sparc_set (p, (guint32)sig->pinvoke, sparc_o3);
957
958                 /* YOU make the CALL! */
959                 sparc_set_ptr (p, (void *)stackval_from_data, sparc_l0);
960                 sparc_jmpl_imm (p, sparc_l0, 0, sparc_callsite);
961                 sparc_nop (p);
962                 stackval_arg_pos += sizeof(stackval);
963         }
964
965         /* return value storage */
966         /* Align to dword */
967         stackval_arg_pos = (stackval_arg_pos + (8 - 1)) & (~(8 -1));
968         if (sig->param_count) {
969                 sparc_add_imm (p, 0, sparc_sp, stackval_arg_pos, sparc_l0);
970         }
971         if (!sig->ret->byref && sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->data.klass->enumtype) {
972 #if !SPARCV9
973                 /* pass on callers buffer */
974                 sparc_ld_imm_ptr (p, sparc_fp, 64, sparc_l1);
975                 sparc_st_imm_ptr (p, sparc_l1, sparc_l0, 0);
976 #else
977                 sparc_add_imm (p, 0, sparc_l0, sizeof(stackval), sparc_l1);
978                 sparc_st_imm_ptr (p, sparc_l1, sparc_l0, 0);
979 #endif
980         }
981
982         sparc_st_imm_ptr (p, sparc_l0, sparc_sp,
983                   (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)));
984
985         /* call ves_exec_method */
986         sparc_add_imm (p, 0, sparc_sp, MINV_POS, sparc_o0);
987         sparc_set_ptr (p, (void *)ves_exec_method, sparc_l0);
988         sparc_jmpl_imm (p, sparc_l0, 0, sparc_callsite);
989         sparc_nop (p);
990
991         /* move retval from stackval to proper place (r3/r4/...) */
992         if (sig->ret->byref) {
993                 sparc_ld_imm_ptr (p, sparc_sp, stackval_arg_pos, sparc_i0 );
994         } else {
995         enum_retvalue:
996                 switch (sig->ret->type) {
997                 case MONO_TYPE_VOID:
998                         break;
999                 case MONO_TYPE_BOOLEAN:
1000                 case MONO_TYPE_I1:
1001                 case MONO_TYPE_U1:
1002                 case MONO_TYPE_I2:
1003                 case MONO_TYPE_U2:
1004                 case MONO_TYPE_I4:
1005                 case MONO_TYPE_U4:
1006                         sparc_ld_imm (p, sparc_sp, stackval_arg_pos, sparc_i0);
1007                         break;
1008                 case MONO_TYPE_I:
1009                 case MONO_TYPE_U:
1010                 case MONO_TYPE_OBJECT:
1011                 case MONO_TYPE_STRING:
1012                 case MONO_TYPE_CLASS:
1013                         sparc_ld_imm_ptr (p, sparc_sp, stackval_arg_pos, sparc_i0);
1014                         break;
1015                 case MONO_TYPE_I8:
1016                 case MONO_TYPE_U8:
1017 #if SPARCV9
1018                         sparc_ldx_imm (p, sparc_sp, stackval_arg_pos, sparc_i0);
1019 #else
1020                         sparc_ld_imm (p, sparc_sp, stackval_arg_pos, sparc_i0);
1021                         sparc_ld_imm (p, sparc_sp, stackval_arg_pos + 4, sparc_i1);
1022 #endif
1023                         break;
1024                 case MONO_TYPE_R4:
1025                         sparc_lddf_imm (p, sparc_sp, stackval_arg_pos, sparc_f0);
1026                         sparc_fdtos(p, sparc_f0, sparc_f0);
1027                         break;
1028                 case MONO_TYPE_R8:
1029                         sparc_lddf_imm (p, sparc_sp, stackval_arg_pos, sparc_f0);
1030                         break;
1031                 case MONO_TYPE_VALUETYPE: {
1032                         gint size;
1033                         gint reg = sparc_i0;
1034                         if (sig->ret->data.klass->enumtype) {
1035                                 simpletype = sig->ret->data.klass->enum_basetype->type;
1036                                 goto enum_retvalue;
1037                         }
1038 #if SPARCV9
1039                         size = mono_class_native_size (sig->ret->data.klass, NULL);
1040                         sparc_ldx_imm (p, sparc_sp, stackval_arg_pos, sparc_l0);
1041                         if (size <= 16) {
1042                                 gint off = 0;
1043                                 if (size >= 8) {
1044                                         sparc_ldx_imm (p, sparc_l0, 0, reg);
1045                                         size -= 8;
1046                                         off += 8;
1047                                         reg++;
1048                                 }
1049                                 if (size > 0)
1050                                         sparc_ldx_imm (p, sparc_l0, off, reg);
1051                         } else
1052                                 NOT_IMPL("value type as ret val from delegate");
1053 #endif
1054                         break;
1055                 }
1056                 default: 
1057                         g_error ("Type 0x%x not handled yet in thunk creation",
1058                                  sig->ret->type);
1059                         break;
1060                 }
1061         }
1062
1063         p = emit_epilog (p, sig, stack_size);
1064
1065         for (i = 0; i < ((p - code_buffer)/2); i++)
1066                 flushi((code_buffer + (i*8)));
1067         
1068         ji = g_new0 (MonoJitInfo, 1);
1069         ji->method = method;
1070         ji->code_size = p - code_buffer;
1071         ji->code_start = code_buffer;
1072         
1073         mono_jit_info_table_add (mono_get_root_domain (), ji);
1074
1075         DEBUG(sparc_disassemble_code (code_buffer, p, method->name));
1076
1077         DEBUG(fprintf(stderr, "Delegate [end emiting] %s\n", method->name));
1078
1079         return ji->code_start;
1080 }