Fri Jul 19 14:18:36 CEST 2002 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / arch / x86 / tramp.c
1 /*
2  * Create trampolines to invoke arbitrary functions.
3  * 
4  * Copyright (C) Ximian Inc.
5  * 
6  * Author: Paolo Molaro (lupus@ximian.com)
7  * 
8  */
9
10 #include "config.h"
11 #include <stdlib.h>
12 #include <string.h>
13 #include "x86-codegen.h"
14 #include "mono/metadata/class.h"
15 #include "mono/metadata/tabledefs.h"
16 #include "mono/interpreter/interp.h"
17 #include "mono/metadata/appdomain.h"
18 #include "mono/metadata/marshal.h"
19
20 /*
21  * The resulting function takes the form:
22  * void func (void (*callme)(), void *retval, void *this_obj, stackval *arguments);
23  */
24 #define FUNC_ADDR_POS   8
25 #define RETVAL_POS      12
26 #define THIS_POS        16
27 #define ARGP_POS        20
28 #define LOC_POS -4
29
30 #define ARG_SIZE        sizeof (stackval)
31
32 MonoPIFunc
33 mono_create_trampoline (MonoMethod *method, int runtime)
34 {
35         MonoMethodSignature *sig;
36         unsigned char *p, *code_buffer;
37         guint32 local_size = 0, stack_size = 0, code_size = 50;
38         guint32 arg_pos, simpletype;
39         int i, stringp;
40         int need_marshal;
41         GList *free_locs = NULL;
42
43         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime)
44                 need_marshal = 0;
45         else
46                 need_marshal = 1;
47
48         sig = method->signature;
49         
50         if (sig->hasthis) {
51                 stack_size += sizeof (gpointer);
52                 code_size += 5;
53         }
54         
55         for (i = 0; i < sig->param_count; ++i) {
56                 if (sig->params [i]->byref) {
57                         stack_size += sizeof (gpointer);
58                         code_size += 20;
59                         local_size++;
60                         continue;
61                 }
62                 simpletype = sig->params [i]->type;
63 enum_calc_size:
64                 switch (simpletype) {
65                 case MONO_TYPE_BOOLEAN:
66                 case MONO_TYPE_CHAR:
67                 case MONO_TYPE_I1:
68                 case MONO_TYPE_U1:
69                 case MONO_TYPE_I2:
70                 case MONO_TYPE_U2:
71                 case MONO_TYPE_I4:
72                 case MONO_TYPE_U4:
73                 case MONO_TYPE_I:
74                 case MONO_TYPE_U:
75                 case MONO_TYPE_PTR:
76                 case MONO_TYPE_R4:
77                 case MONO_TYPE_SZARRAY:
78                 case MONO_TYPE_CLASS:
79                 case MONO_TYPE_OBJECT:
80                         stack_size += 4;
81                         code_size += i < 10 ? 5 : 8;
82                         break;
83                 case MONO_TYPE_VALUETYPE:
84                         if (sig->params [i]->data.klass->enumtype) {
85                                 simpletype = sig->params [i]->data.klass->enum_basetype->type;
86                                 goto enum_calc_size;
87                         }
88                         if (mono_class_value_size (sig->params [i]->data.klass, NULL) != 4)
89                                 g_error ("can only marshal enums, not generic structures (size: %d)", mono_class_value_size (sig->params [i]->data.klass, NULL));
90                         stack_size += 4;
91                         code_size += i < 10 ? 5 : 8;
92                         break;
93                 case MONO_TYPE_STRING:
94                         stack_size += 4;
95                         code_size += 20;
96                         local_size++;
97                         break;
98                 case MONO_TYPE_I8:
99                         stack_size += 8;
100                         code_size += i < 10 ? 5 : 8;
101                         break;
102                 case MONO_TYPE_R8:
103                         stack_size += 8;
104                         code_size += i < 10 ? 7 : 10;
105                         break;
106                 default:
107                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
108                 }
109         }
110         /*
111          * FIXME: take into account large return values.
112          */
113
114         code_buffer = p = alloca (code_size);
115
116         /*
117          * Standard function prolog.
118          */
119         x86_push_reg (p, X86_EBP);
120         x86_mov_reg_reg (p, X86_EBP, X86_ESP, 4);
121         /*
122          * We store some local vars here to handle string pointers.
123          * and align to 16 byte boundary...
124          */
125         if (local_size) {
126                 x86_alu_reg_imm (p, X86_SUB, X86_ESP, local_size * 4);
127                 stack_size = (stack_size * local_size * 4) % 16;
128         } else {
129                 stack_size = stack_size % 16;
130         }
131         if (stack_size)
132                 x86_alu_reg_imm (p, X86_SUB, X86_ESP, stack_size);
133
134         /*
135          * EDX has the pointer to the args.
136          */
137         x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4);
138
139         /*
140          * Push arguments in reverse order.
141          */
142         stringp = 0;
143         for (i = sig->param_count; i; --i) {
144                 arg_pos = ARG_SIZE * (i - 1);
145                 if (sig->params [i - 1]->byref) {
146                         if (!need_marshal) {
147                                 x86_push_membase (p, X86_EDX, arg_pos);
148                                 continue;
149                         }
150                         if (sig->params [i - 1]->type == MONO_TYPE_SZARRAY &&
151                             sig->params [i - 1]->data.type->type == MONO_TYPE_STRING) {
152                                 x86_mov_reg_membase (p, X86_EAX, X86_EDX, arg_pos, 4);
153                                 x86_push_regp (p, X86_EAX);
154                                 x86_mov_reg_imm (p, X86_EDX, mono_marshal_string_array);
155                                 x86_call_reg (p, X86_EDX);
156                                 x86_alu_reg_imm (p, X86_ADD, X86_ESP, 4);
157                                 /*
158                                  * Store the pointer in a local we'll free later.
159                                  */
160                                 stringp++;
161                                 x86_mov_membase_reg (p, X86_EBP, LOC_POS * stringp, X86_EAX, 4);
162                                 free_locs = g_list_prepend (free_locs, GUINT_TO_POINTER (LOC_POS * stringp));
163                                 /* load the pointer and push it */
164                                 x86_lea_membase (p, X86_EAX, X86_EBP, LOC_POS * stringp);
165                                 x86_push_reg (p, X86_EAX);
166                                 /* restore pointer to args in EDX */
167                                 x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4);
168                         } else {
169                                 x86_push_membase (p, X86_EDX, arg_pos);
170                         }
171                         continue;
172                 }
173                 simpletype = sig->params [i - 1]->type;
174 enum_marshal:
175                 switch (simpletype) {
176                 case MONO_TYPE_BOOLEAN:
177                 case MONO_TYPE_I1:
178                 case MONO_TYPE_U1:
179                 case MONO_TYPE_I2:
180                 case MONO_TYPE_U2:
181                 case MONO_TYPE_CHAR:
182                 case MONO_TYPE_I4:
183                 case MONO_TYPE_U4:
184                 case MONO_TYPE_I:
185                 case MONO_TYPE_U:
186                 case MONO_TYPE_PTR:
187                 case MONO_TYPE_OBJECT:
188                         x86_push_membase (p, X86_EDX, arg_pos);
189                         break;
190                 case MONO_TYPE_R4:
191                         x86_alu_reg_imm (p, X86_SUB, X86_ESP, 4);
192                         x86_fld_membase (p, X86_EDX, arg_pos, TRUE);
193                         x86_fst_membase (p, X86_ESP, 0, FALSE, TRUE);
194                         break;
195                 case MONO_TYPE_CLASS:
196                         if (need_marshal) {
197                                 if (sig->params [i - 1]->data.klass->delegate) {
198                                         /* should we use a wrapper to invoke the multicast delegates? */
199                                         x86_mov_reg_membase (p, X86_EAX, X86_EDX, arg_pos, 4);
200                                         x86_alu_reg_imm (p, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
201                                         x86_push_reg (p, X86_EAX);
202                                 } else
203                                         g_error ("unhandled case");
204                         } else {
205                                 x86_push_membase (p, X86_EDX, arg_pos);
206                         }
207                         break;
208                 case MONO_TYPE_SZARRAY:
209                         if (need_marshal) {
210                                 x86_mov_reg_membase (p, X86_EAX, X86_EDX, arg_pos, 4);
211                                 x86_alu_reg_imm (p, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoArray, vector));
212                                 x86_push_reg (p, X86_EAX);
213                         } else {
214                                 x86_push_membase (p, X86_EDX, arg_pos);
215                         }
216                         break;
217                 case MONO_TYPE_VALUETYPE:
218                         if (!sig->params [i - 1]->data.klass->enumtype) {
219                                 /* it's a structure that fits in 4 bytes, need to push the value pointed to */
220                                 x86_mov_reg_membase (p, X86_EAX, X86_EDX, arg_pos, 4);
221                                 x86_push_regp (p, X86_EAX);
222                         } else {
223                                 /* it's an enum value */
224                                 simpletype = sig->params [i - 1]->data.klass->enum_basetype->type;
225                                 goto enum_marshal;
226                         }
227                         break;
228                 case MONO_TYPE_STRING:
229                         /* 
230                          * If it is an internalcall we assume it's the object we want.
231                          * Yet another reason why MONO_TYPE_STRING should not be used to indicate char*.
232                          */
233                         if (!need_marshal) {
234                                 x86_push_membase (p, X86_EDX, arg_pos);
235                                 break;
236                         }
237                         /*if (frame->method->flags & PINVOKE_ATTRIBUTE_CHAR_SET_ANSI*/
238                         x86_push_membase (p, X86_EDX, arg_pos);
239                         x86_mov_reg_imm (p, X86_EDX, mono_string_to_utf8);
240                         x86_call_reg (p, X86_EDX);
241                         x86_alu_reg_imm (p, X86_ADD, X86_ESP, 4);
242                         x86_push_reg (p, X86_EAX);
243                         /*
244                          * Store the pointer in a local we'll free later.
245                          */
246                         stringp++;
247                         x86_mov_membase_reg (p, X86_EBP, LOC_POS * stringp, X86_EAX, 4);
248                         free_locs = g_list_prepend (free_locs, GUINT_TO_POINTER (LOC_POS * stringp));
249                         /*
250                          * we didn't save the reg: restore it here.
251                          */
252                         if (i > 1)
253                                 x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4);
254                         break;
255                 case MONO_TYPE_I8:
256                 case MONO_TYPE_U8:
257                 case MONO_TYPE_R8:
258                         x86_push_membase (p, X86_EDX, arg_pos + 4);
259                         x86_push_membase (p, X86_EDX, arg_pos);
260                         break;
261                 default:
262                         g_error ("Can't trampoline 0x%x", sig->params [i - 1]->type);
263                 }
264         }
265
266         if (sig->hasthis) {
267                 if (sig->call_convention != MONO_CALL_THISCALL) {
268                         x86_mov_reg_membase (p, X86_EDX, X86_EBP, THIS_POS, 4);
269                         x86_push_reg (p, X86_EDX);
270                 } else {
271                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, THIS_POS, 4);
272                 }
273         }
274
275         /* 
276          * Insert call to function 
277          */
278         x86_mov_reg_membase (p, X86_EDX, X86_EBP, FUNC_ADDR_POS, 4);
279         x86_call_reg (p, X86_EDX);
280
281         /*
282          * Handle retval.
283          * Small integer and pointer values are in EAX.
284          * Long integers are in EAX:EDX.
285          * FP values are on the FP stack.
286          */
287
288         if (sig->ret->byref || 
289             (method->klass == mono_defaults.string_class &&
290              *method->name == '.' && !strcmp (method->name, ".ctor"))) {
291                 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
292                 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
293         } else {
294                 simpletype = sig->ret->type;
295 enum_retvalue:
296                 switch (simpletype) {
297                 case MONO_TYPE_BOOLEAN:
298                 case MONO_TYPE_I1:
299                 case MONO_TYPE_U1:
300                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
301                         x86_mov_regp_reg (p, X86_ECX, X86_EAX, 1);
302                         break;
303                 case MONO_TYPE_CHAR:
304                 case MONO_TYPE_I2:
305                 case MONO_TYPE_U2:
306                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
307                         x86_mov_regp_reg (p, X86_ECX, X86_EAX, 2);
308                         break;
309                 case MONO_TYPE_I4:
310                 case MONO_TYPE_U4:
311                 case MONO_TYPE_I:
312                 case MONO_TYPE_U:
313                 case MONO_TYPE_CLASS:
314                 case MONO_TYPE_OBJECT:
315                 case MONO_TYPE_SZARRAY:
316                 case MONO_TYPE_ARRAY:
317                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
318                         x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
319                         break;
320                 case MONO_TYPE_STRING: 
321                         if (!need_marshal) {
322                                 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
323                                 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
324                                 break;
325                         }
326
327                         /* If the argument is non-null, then convert the value back */
328                         x86_alu_reg_reg (p, X86_OR, X86_EAX, X86_EAX);
329                         x86_branch8 (p, X86_CC_EQ, 11, FALSE);
330                         x86_push_reg (p, X86_EAX);
331                         x86_mov_reg_imm (p, X86_EDX, mono_string_new_wrapper);
332                         x86_call_reg (p, X86_EDX);
333                         x86_alu_reg_imm (p, X86_ADD, X86_ESP, 4);
334
335                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
336                         x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
337                         break;
338                 case MONO_TYPE_R4:
339                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
340                         x86_fst_membase (p, X86_ECX, 0, FALSE, TRUE);
341                         break;
342                 case MONO_TYPE_R8:
343                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
344                         x86_fst_membase (p, X86_ECX, 0, TRUE, TRUE);
345                         break;
346                 case MONO_TYPE_I8:
347                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
348                         x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
349                         x86_mov_membase_reg (p, X86_ECX, 4, X86_EDX, 4);
350                         break;
351                 case MONO_TYPE_VALUETYPE:
352                         if (sig->ret->data.klass->enumtype) {
353                                 simpletype = sig->ret->data.klass->enum_basetype->type;
354                                 goto enum_retvalue;
355                         }
356                 case MONO_TYPE_VOID:
357                         break;
358                 default:
359                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
360                 }
361         }
362
363         /*
364          * free the allocated strings.
365          */
366         if (need_marshal) {
367                 GList* tmp;
368                 for (tmp = free_locs; tmp; tmp = tmp->next) {
369                         x86_mov_reg_imm (p, X86_EDX, g_free);
370                         x86_push_membase (p, X86_EBP, GPOINTER_TO_UINT (tmp->data));
371                         x86_call_reg (p, X86_EDX);
372                 }
373                 g_list_free (free_locs);
374         }
375         /*
376          * Standard epilog.
377          */
378         x86_leave (p);
379         x86_ret (p);
380
381         g_assert (p - code_buffer < code_size);
382         return g_memdup (code_buffer, p - code_buffer);
383 }
384
385 #define MINV_POS  (- sizeof (MonoInvocation))
386 #define STACK_POS (MINV_POS - sizeof (stackval) * sig->param_count)
387 #define OBJ_POS   8
388 #define TYPE_OFFSET (G_STRUCT_OFFSET (stackval, type))
389
390 /*
391  * Returns a pointer to a native function that can be used to
392  * call the specified method.
393  * The function created will receive the arguments according
394  * to the call convention specified in the method.
395  * This function works by creating a MonoInvocation structure,
396  * filling the fields in and calling ves_exec_method on it.
397  * Still need to figure out how to handle the exception stuff
398  * across the managed/unmanaged boundary.
399  */
400 void *
401 mono_create_method_pointer (MonoMethod *method)
402 {
403         MonoMethodSignature *sig;
404         MonoJitInfo *ji;
405         unsigned char *p, *code_buffer;
406         gint32 local_size;
407         gint32 stackval_pos, arg_pos = 8;
408         int i, align;
409
410         /*
411          * If it is a static P/Invoke method, we can just return the pointer
412          * to the method implementation.
413          */
414         sig = method->signature;
415
416         code_buffer = p = alloca (512); /* FIXME: check for overflows... */
417
418         local_size = sizeof (MonoInvocation) + sizeof (stackval) * (sig->param_count + 1);
419         stackval_pos = -local_size;
420
421         /*
422          * Standard function prolog.
423          */
424         x86_push_reg (p, X86_EBP);
425         x86_mov_reg_reg (p, X86_EBP, X86_ESP, 4);
426         x86_alu_reg_imm (p, X86_SUB, X86_ESP, local_size);
427
428         /*
429          * Initialize MonoInvocation fields, first the ones known now.
430          */
431         x86_mov_reg_imm (p, X86_EAX, 0);
432         x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex)), X86_EAX, 4);
433         x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex_handler)), X86_EAX, 4);
434         x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, child)), X86_EAX, 4);
435         x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, parent)), X86_EAX, 4);
436         /*
437          * Set the method pointer.
438          */
439         x86_mov_membase_imm (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, method)), (int)method, 4);
440
441         /*
442          * Handle this.
443          */
444         if (sig->hasthis) {
445                 if (sig->call_convention != MONO_CALL_THISCALL) {
446                         /*
447                          * Grab it from the stack, otherwise it's already in ECX.
448                          */
449                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, OBJ_POS, 4);
450                         arg_pos += 4;
451                 }
452                 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)), X86_ECX, 4);
453         }
454         /*
455          * Handle the arguments. stackval_pos is the posset of the stackval array from EBP.
456          * arg_pos is the offset from EBP to the incoming arg on the stack.
457          * We just call stackval_from_data to handle all the (nasty) issues....
458          */
459         x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
460         x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, stack_args)), X86_EAX, 4);
461         for (i = 0; i < sig->param_count; ++i) {
462                 x86_mov_reg_imm (p, X86_ECX, stackval_from_data);
463                 x86_lea_membase (p, X86_EDX, X86_EBP, arg_pos);
464                 x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
465                 x86_push_reg (p, X86_EDX);
466                 x86_push_reg (p, X86_EAX);
467                 x86_push_imm (p, sig->params [i]);
468                 x86_call_reg (p, X86_ECX);
469                 x86_alu_reg_imm (p, X86_SUB, X86_ESP, 12);
470                 stackval_pos += sizeof (stackval);
471                 arg_pos += mono_type_stack_size (sig->params [i], &align);
472         }
473
474         /*
475          * Handle the return value storage area.
476          */
477         x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
478         x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)), X86_EAX, 4);
479
480         /*
481          * Call the method.
482          */
483         x86_lea_membase (p, X86_EAX, X86_EBP, MINV_POS);
484         x86_push_reg (p, X86_EAX);
485         x86_mov_reg_imm (p, X86_EDX, ves_exec_method);
486         x86_call_reg (p, X86_EDX);
487
488         /*
489          * Move the return value to the proper place.
490          */
491         x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
492         if (sig->ret->byref) {
493                 x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
494         } else {
495                 switch (sig->ret->type) {
496                 case MONO_TYPE_VOID:
497                         break;
498                 case MONO_TYPE_BOOLEAN:
499                         x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 1);
500                         break;
501                 case MONO_TYPE_I4:
502                 case MONO_TYPE_U4:
503                 case MONO_TYPE_I:
504                 case MONO_TYPE_U:
505                 case MONO_TYPE_OBJECT:
506                 case MONO_TYPE_STRING:
507                 case MONO_TYPE_CLASS:
508                         x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
509                         break;
510                 case MONO_TYPE_I8:
511                         x86_mov_reg_membase (p, X86_EDX, X86_EAX, 4, 4);
512                         x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
513                         break;
514                 case MONO_TYPE_R8:
515                         x86_fld_membase (p, X86_EAX, 0, TRUE);
516                         break;
517                 default:
518                         g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type);
519                         break;
520                 }
521         }
522         
523         /*
524          * Standard epilog.
525          */
526         x86_leave (p);
527         x86_ret (p);
528
529         g_assert (p - code_buffer < 512);
530
531         ji = g_new0 (MonoJitInfo, 1);
532         ji->method = method;
533         ji->code_size = p - code_buffer;
534         ji->code_start = g_memdup (code_buffer, p - code_buffer);
535
536         mono_jit_info_table_add (mono_root_domain, ji);
537
538         return ji->code_start;
539 }