2002-08-19 Dick Porter <dick@ximian.com>
[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  * 
10  */
11
12 #include "config.h"
13 #include <stdlib.h>
14 #include "sparc-codegen.h"
15 #include "mono/metadata/class.h"
16 #include "mono/metadata/tabledefs.h"
17 #include "mono/interpreter/interp.h"
18 #include "mono/metadata/appdomain.h"
19
20
21 #define FUNC_ADDR_POS   sparc_i0
22 #define RETVAL_POS      sparc_i1
23 #define THIS_POS        sparc_i2
24 #define ARGP_POS        sparc_i3
25 #define LOC_POS -4
26
27 #define ARG_SIZE        sizeof (stackval)
28
29 static void
30 fake_func (void (*callme)(gpointer, gpointer), stackval *retval, void *this_obj, stackval *arguments)
31 {
32         /*
33            *(gpointer*)retval = (gpointer)(*callme) (arguments [0].data.p, arguments [1].data.p, arguments [2].data.p);
34            *(gdouble*) retval = (gdouble)(*callme) (arguments [0].data.f);
35         */
36         
37         /* internal_from_handle() */
38         /* return (gpointer)(*callme) (((MonoType *)arguments [0].data.p)->data.klass); */
39         
40         /* InitializeArray() */
41         (*callme) (arguments [0].data.p, arguments [1].data.p);
42 }
43
44 static const char *
45 mono_type (int type)
46 {
47         switch (type) {
48         case MONO_TYPE_END:
49                 return "MONO_TYPE_END";
50         case MONO_TYPE_VOID:
51                 return "MONO_TYPE_VOID";
52         case MONO_TYPE_BOOLEAN:
53                 return "MONO_TYPE_BOOLEAN";
54         case MONO_TYPE_CHAR:
55                 return "MONO_TYPE_CHAR";
56         case MONO_TYPE_I1:
57                 return "MONO_TYPE_I1";
58         case MONO_TYPE_U1:
59                 return "MONO_TYPE_U1";
60         case MONO_TYPE_I2:
61                 return "MONO_TYPE_I2";
62         case MONO_TYPE_U2:
63                 return "MONO_TYPE_U2";
64         case MONO_TYPE_I4:
65                 return "MONO_TYPE_I4";
66         case MONO_TYPE_U4:
67                 return "MONO_TYPE_U4";
68         case MONO_TYPE_I8:
69                 return "MONO_TYPE_I8";
70         case MONO_TYPE_U8:
71                 return "MONO_TYPE_U8";
72         case MONO_TYPE_R4:
73                 return "MONO_TYPE_R4";
74         case MONO_TYPE_R8:
75                 return "MONO_TYPE_R8";
76         case MONO_TYPE_STRING:
77                 return "MONO_TYPE_STRING";
78         case MONO_TYPE_PTR:
79                 return "MONO_TYPE_PTR";
80         case MONO_TYPE_BYREF:
81                 return "MONO_TYPE_BYREF";
82         case MONO_TYPE_VALUETYPE:
83                 return "MONO_TYPE_VALUETYPE";
84         case MONO_TYPE_CLASS:
85                 return "MONO_TYPE_CLASS";
86         case MONO_TYPE_ARRAY:
87                 return "MONO_TYPE_ARRAY";
88         case MONO_TYPE_TYPEDBYREF:
89                 return "MONO_TYPE_TYPEBYREF";
90         case MONO_TYPE_I:
91                 return "MONO_TYPE_I";
92         case MONO_TYPE_U:
93                 return "MONO_TYPE_U";
94         case MONO_TYPE_FNPTR:
95                 return "MONO_TYPE_FNPTR";
96         case MONO_TYPE_OBJECT:
97                 return "MONO_TYPE_OBJECT";
98         case MONO_TYPE_SZARRAY:
99                 return "MONO_TYPE_SZARRAY";
100         case MONO_TYPE_CMOD_REQD:
101                 return "MONO_TYPE_CMOD_REQD";
102         case MONO_TYPE_CMOD_OPT:
103                 return "MONO_TYPE_CMOD_OPT";
104         case MONO_TYPE_INTERNAL:
105                 return "MONO_TYPE_INTERNAL";
106         case MONO_TYPE_MODIFIER:
107                 return "MONO_TYPE_MODIFIER";
108         case MONO_TYPE_SENTINEL:
109                 return "MONO_TYPE_SENTINEL";
110         case MONO_TYPE_PINNED:
111                 return "MONO_TYPE_PINNED";
112         }
113         
114         return "??";
115 }
116
117 static void
118 calculate_sizes (MonoMethod *method, guint32 *local_size, guint32 *stack_size, guint32 *code_size, int runtime)
119 {
120         MonoMethodSignature *sig = method->signature;
121         guint32 local = 0, stack = 0, code = 6;
122         guint32 simpletype;
123         int i;
124         
125         /* function arguments */
126         if (sig->hasthis)
127                 code++;
128         
129         for (i = 0; i < sig->param_count; i++) {
130                 if (sig->params[i]->byref) {
131                         stack += sizeof (gpointer);
132                         code += i < 6 ? 1 : 3;
133                         continue;
134                 }
135                 
136                 simpletype = sig->params[i]->type;
137         enum_calc_size:
138                 switch (simpletype) {
139                 case MONO_TYPE_BOOLEAN:
140                 case MONO_TYPE_CHAR:
141                 case MONO_TYPE_I1:
142                 case MONO_TYPE_U1:
143                 case MONO_TYPE_I2:
144                 case MONO_TYPE_U2:
145                 case MONO_TYPE_I4:
146                 case MONO_TYPE_U4:
147                 case MONO_TYPE_I:
148                 case MONO_TYPE_U:
149                 case MONO_TYPE_PTR:
150                 case MONO_TYPE_R4:
151                 case MONO_TYPE_SZARRAY:
152                 case MONO_TYPE_CLASS:
153                 case MONO_TYPE_OBJECT:
154                         stack += 4;
155                         code += i < 6 ? 1 : 3;
156                         break;
157                 case MONO_TYPE_VALUETYPE:
158                         if (sig->params[i]->data.klass->enumtype) {
159                                 simpletype = sig->params[i]->data.klass->enum_basetype->type;
160                                 goto enum_calc_size;
161                         }
162                         if (mono_class_value_size (sig->params[i]->data.klass, NULL) != 4)
163                                 g_error ("can only marshal enums, not generic structures (size: %d)",
164                                          mono_class_value_size (sig->params[i]->data.klass, NULL));
165                         stack += 4;
166                         code += i < 6 ? 1 : 3;
167                         break;
168                 case MONO_TYPE_STRING:
169                         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime) {
170                                 stack += 4;
171                                 code += i < 6 ? 1 : 3;
172                                 break;
173                         }
174                         
175                         stack += 4;
176                         code += 5;
177                         local++;
178                         break;
179                 case MONO_TYPE_I8:
180                         stack += 8;
181                         code += i < 6 ? 2 : 3;
182                         break;
183                 case MONO_TYPE_R8:
184                         stack += 8;
185                         code += i < 6 ? 2 : 3;
186                         break;
187                 default:
188                         g_error ("Can't trampoline 0x%x", sig->params[i]->type);
189                 }
190         }
191         
192         /* function return value */
193         if (sig->ret->byref) {
194                 code += 2;
195         } else {
196                 simpletype = sig->ret->type;
197         enum_retvalue:
198                 switch (simpletype) {
199                 case MONO_TYPE_BOOLEAN:
200                 case MONO_TYPE_I1:
201                 case MONO_TYPE_U1:
202                 case MONO_TYPE_I2:
203                 case MONO_TYPE_U2:
204                 case MONO_TYPE_CHAR:
205                 case MONO_TYPE_I4:
206                 case MONO_TYPE_U4:
207                 case MONO_TYPE_I:
208                 case MONO_TYPE_U:
209                 case MONO_TYPE_CLASS:
210                 case MONO_TYPE_OBJECT:
211                 case MONO_TYPE_R4:
212                 case MONO_TYPE_R8:
213                 case MONO_TYPE_SZARRAY:
214                 case MONO_TYPE_ARRAY:
215                         code += 2;
216                         break;
217 #if 0
218                 case MONO_TYPE_STRING:
219                         code += 2;
220                         if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && !runtime) {
221                                 code += 4;
222                         }
223                         break;
224 #endif
225                 case MONO_TYPE_I8:
226                         code += 3;
227                         break;
228                 case MONO_TYPE_VALUETYPE:
229                         if (sig->ret->data.klass->enumtype) {
230                                 simpletype = sig->ret->data.klass->enum_basetype->type;
231                                 goto enum_retvalue;
232                         }
233                         code += 2;
234                         break;
235                 case MONO_TYPE_VOID:
236                         break;
237                 default:
238                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
239                 }
240         }
241         
242 #define STACKALIGN(x) (((x) + 15) & (~15))
243 #define MINFRAME      ((16 + 1 + 6) * 4)      /* minimum size stack frame, in bytes:
244                                                * 16 for registers, 1 for "hidden param",
245                                                * and 6 in which a callee can store it's
246                                                * arguments.
247                                                */
248         
249         stack += MINFRAME + (local * 4);
250         
251         fprintf (stderr, "\tstack size: %d (%d)\n\tcode size: %d\n", STACKALIGN(stack), stack, code);
252         
253         *local_size = local;
254         *stack_size = STACKALIGN(stack);
255         *code_size = code;
256 }
257
258 static MonoString *
259 mono_string_new_wrapper (const char *text)
260 {
261         return text ? mono_string_new (mono_domain_get (), text) : NULL;
262 }
263
264 MonoPIFunc
265 mono_create_trampoline (MonoMethod *method, int runtime)
266 {
267         MonoMethodSignature *sig;
268         guint32 *p, *code_buffer;
269         guint32 local_size, stack_size, code_size;
270         guint32 arg_pos, simpletype;
271         int i, stringp, cur_out_reg;
272         
273         sig = method->signature;
274         
275         fprintf (stderr, "\nPInvoke [start emiting] %s\n", method->name);
276         calculate_sizes (method, &local_size, &stack_size, &code_size, runtime);
277         
278         code_buffer = p = alloca (code_size * 4);
279         cur_out_reg = sparc_o0;
280         
281         /* Standard function prolog. */
282         sparc_save_imm (p, sparc_sp, -stack_size, sparc_sp);
283 #if 0
284         /* gcc seems to want to store %i0 through %i3 for some reason */
285         sparc_st_imm (p, sparc_i0, sparc_fp, 68);
286         sparc_st_imm (p, sparc_i1, sparc_fp, 72);
287         sparc_st_imm (p, sparc_i2, sparc_fp, 76);
288         sparc_st_imm (p, sparc_i3, sparc_fp, 80);
289 #endif
290         
291         /*
292          * We store some local vars here to handle string pointers.
293          * and align to 16 byte boundary...
294          */
295 #if 0
296         if (local_size) {
297                 x86_alu_reg_imm (p, X86_SUB, X86_ESP, local_size * 4);
298                 stack_size = (stack_size * local_size * 4) % 16;
299         } else {
300                 stack_size = stack_size % 16;
301         }
302         if (stack_size)
303                 x86_alu_reg_imm (p, X86_SUB, X86_ESP, stack_size);
304 #endif
305         
306         /*
307          * %i3 has the pointer to the args.
308          */
309         
310         if (sig->hasthis) {
311                 sparc_mov_reg_reg (p, sparc_i2, cur_out_reg);
312                 cur_out_reg++;
313         }
314         
315         /* Push arguments in reverse order. */
316         stringp = 0;
317         for (i = 0; i < sig->param_count; i++) {
318                 arg_pos = ARG_SIZE * i;
319                 
320                 if (sig->params[i]->byref) {
321                         fprintf (stderr, "\tpushing params[%d] (byref): type=%s;\n", i, mono_type (sig->params[i]->type));
322                         sparc_ld_imm (p, sparc_i3, arg_pos, cur_out_reg);
323                         cur_out_reg++;
324                         continue;
325                 }
326                 
327                 simpletype = sig->params[i]->type;
328 enum_marshal:
329                 fprintf (stderr, "\tpushing params[%d]: type=%s;\n", i, mono_type (simpletype));
330                 switch (simpletype) {
331                 case MONO_TYPE_BOOLEAN:
332                 case MONO_TYPE_I1:
333                 case MONO_TYPE_U1:
334                 case MONO_TYPE_I2:
335                 case MONO_TYPE_U2:
336                 case MONO_TYPE_CHAR:
337                 case MONO_TYPE_I4:
338                 case MONO_TYPE_U4:
339                 case MONO_TYPE_I:
340                 case MONO_TYPE_U:
341                 case MONO_TYPE_PTR:
342                 case MONO_TYPE_R4:
343                 case MONO_TYPE_SZARRAY:
344                 case MONO_TYPE_CLASS:
345                 case MONO_TYPE_OBJECT:
346                         sparc_ld_imm (p, sparc_i3, arg_pos, cur_out_reg);
347                         cur_out_reg++;
348                         break;
349                 case MONO_TYPE_VALUETYPE:
350                         if (sig->params[i]->data.klass->enumtype) {
351                                 /* it's an enum value */
352                                 simpletype = sig->params[i]->data.klass->enum_basetype->type;
353                                 goto enum_marshal;
354                         } else {
355                                 /*sparc_ld_imm (p, sparc_i3, arg_pos, cur_out_reg);*/
356                                 sparc_ld_imm (p, sparc_i3, arg_pos, sparc_l0);
357                                 sparc_ld (p, sparc_l0, 0, cur_out_reg);
358                                 cur_out_reg++;
359                         }
360                         break;
361                 case MONO_TYPE_STRING:
362                         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime) {
363                                 sparc_ld_imm (p, sparc_i3, arg_pos, cur_out_reg);
364                                 cur_out_reg++;
365                                 break;
366                         }
367                         
368 #if 0
369                         sparc_sethi (p, mono_string_to_utf8, sparc_l0);
370                         sparc_or_imm (p, 0, sparc_l0, mono_string_to_utf8, sparc_l1);
371                         
372                         x86_push_membase (p, X86_EDX, arg_pos);
373                         x86_mov_reg_imm (p, X86_EDX, mono_string_to_utf8);
374                         x86_call_reg (p, X86_EDX);
375                         x86_alu_reg_imm (p, X86_ADD, X86_ESP, 4);
376                         x86_push_reg (p, X86_EAX);
377                         /*
378                          * Store the pointer in a local we'll free later.
379                          */
380                         stringp++;
381                         x86_mov_membase_reg (p, X86_EBP, LOC_POS * stringp, X86_EAX, 4);
382                         /*
383                          * we didn't save the reg: restore it here.
384                          */
385                         if (i > 1)
386                                 x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4);
387 #endif
388                         fprintf (stderr, "MONO_TYPE_STRING not yet fully supported.\n");
389                         exit (1);
390                         break;
391                 case MONO_TYPE_I8:
392                         sparc_ld_imm (p, sparc_i3, arg_pos, cur_out_reg);
393                         cur_out_reg++;
394                         sparc_ld_imm (p, sparc_i3, arg_pos + 4, cur_out_reg);
395                         cur_out_reg++;
396                         break;
397                 case MONO_TYPE_R8:
398                         sparc_ld_imm (p, sparc_i3, arg_pos, cur_out_reg);
399                         cur_out_reg++;
400                         sparc_ld_imm (p, sparc_i3, arg_pos + 4, cur_out_reg);
401                         cur_out_reg++;
402                         break;
403                 default:
404                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
405                 }
406         }
407         
408         /* call the function */
409         sparc_jmpl_imm (p, sparc_i0, 0, sparc_callsite);
410         sparc_nop (p);
411         
412         /*
413          * Handle retval.
414          * Small integer and pointer values are in EAX.
415          * Long integers are in EAX:EDX.
416          * FP values are on the FP stack.
417          */
418 #if 0
419         if (sig->ret->byref) {
420                 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
421                 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
422         } else {
423                 simpletype = sig->ret->type;
424 enum_retvalue:
425                 switch (simpletype) {
426                 case MONO_TYPE_BOOLEAN:
427                 case MONO_TYPE_I1:
428                 case MONO_TYPE_U1:
429                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
430                         x86_mov_regp_reg (p, X86_ECX, X86_EAX, 1);
431                         break;
432                 case MONO_TYPE_CHAR:
433                 case MONO_TYPE_I2:
434                 case MONO_TYPE_U2:
435                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
436                         x86_mov_regp_reg (p, X86_ECX, X86_EAX, 2);
437                         break;
438                 case MONO_TYPE_I4:
439                 case MONO_TYPE_U4:
440                 case MONO_TYPE_I:
441                 case MONO_TYPE_U:
442                 case MONO_TYPE_CLASS:
443                 case MONO_TYPE_OBJECT:
444                 case MONO_TYPE_SZARRAY:
445                 case MONO_TYPE_ARRAY:
446                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
447                         x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
448                         break;
449                 case MONO_TYPE_STRING: 
450                         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime) {
451                                 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
452                                 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
453                                 break;
454                         }
455                         
456                         /* If the argument is non-null, then convert the value back */
457                         x86_alu_reg_reg (p, X86_OR, X86_EAX, X86_EAX);
458                         x86_branch8 (p, X86_CC_EQ, 11, FALSE);
459                         x86_push_reg (p, X86_EAX);
460                         x86_mov_reg_imm (p, X86_EDX, mono_string_new);
461                         x86_call_reg (p, X86_EDX);
462                         x86_alu_reg_imm (p, X86_ADD, X86_ESP, 4);
463                         
464                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
465                         x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
466                         break;
467                 case MONO_TYPE_R4:
468                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
469                         x86_fst_membase (p, X86_ECX, 0, FALSE, TRUE);
470                         break;
471                 case MONO_TYPE_R8:
472                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
473                         x86_fst_membase (p, X86_ECX, 0, TRUE, TRUE);
474                         break;
475                 case MONO_TYPE_I8:
476                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
477                         x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
478                         x86_mov_membase_reg (p, X86_ECX, 4, X86_EDX, 4);
479                         break;
480                 case MONO_TYPE_VALUETYPE:
481                         if (sig->ret->data.klass->enumtype) {
482                                 simpletype = sig->ret->data.klass->enum_basetype->type;
483                                 goto enum_retvalue;
484                         }
485                 case MONO_TYPE_VOID:
486                         break;
487                 default:
488                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
489                 }
490         }
491 #endif
492         
493 #if 0
494         /* free the allocated strings... */
495         if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
496                 if (local_size)
497                         x86_mov_reg_imm (p, X86_EDX, g_free);
498                 for (i = 1; i <= local_size; ++i) {
499                         x86_push_membase (p, X86_EBP, LOC_POS * i);
500                         x86_call_reg (p, X86_EDX);
501                 }
502         }
503 #endif
504         /*
505          * Standard epilog.
506          * 8 may be 12 when returning structures (to skip unimp opcode).
507          */
508         sparc_jmpl_imm (p, sparc_i7, 8, sparc_zero);
509         sparc_restore (p, sparc_zero, sparc_zero, sparc_zero);
510         
511         {
512                 unsigned char *inptr, *inend;
513                 
514                 inptr = (unsigned char *) code_buffer;
515                 inend = (unsigned char *) p;
516                 
517                 printf (".text\n.align 4\n.globl main\n.type main,function\nmain:\n");
518                 while (inptr < inend) {
519                         printf (".byte 0x%x\n", *inptr);
520                         inptr++;
521                 }
522                 fflush (stdout);
523         }
524         
525         fprintf (stderr, "PInvoke [finish emiting] %s\n", method->name);
526         
527         /* FIXME: need to flush */
528         return g_memdup (code_buffer, 4 * (p - code_buffer));
529 }
530
531 void *
532 mono_create_method_pointer (MonoMethod *method)
533 {
534         return NULL;
535 }
536
537 MonoMethod*
538 mono_method_pointer_get (void *code)
539 {
540         return NULL;
541 }