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