2002-08-01 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 <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 (MonoMethodSignature *sig, gboolean string_ctor)
34 {
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         static GHashTable *cache = NULL;
40         MonoPIFunc res;
41
42         if (!cache) 
43                 cache = g_hash_table_new ((GHashFunc)mono_signature_hash, 
44                                           (GCompareFunc)mono_metadata_signature_equal);
45
46         if ((res = (MonoPIFunc)g_hash_table_lookup (cache, sig)))
47                 return res;
48
49         if (sig->hasthis) {
50                 stack_size += sizeof (gpointer);
51                 code_size += 10;
52         }
53         
54         if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref && !sig->ret->data.klass->enumtype) {
55                 stack_size += sizeof (gpointer);
56                 code_size += 5;
57         }
58
59         for (i = 0; i < sig->param_count; ++i) {
60                 if (sig->params [i]->byref) {
61                         stack_size += sizeof (gpointer);
62                         code_size += 20;
63                         local_size++;
64                         continue;
65                 }
66                 simpletype = sig->params [i]->type;
67 enum_calc_size:
68                 switch (simpletype) {
69                 case MONO_TYPE_BOOLEAN:
70                 case MONO_TYPE_CHAR:
71                 case MONO_TYPE_I1:
72                 case MONO_TYPE_U1:
73                 case MONO_TYPE_I2:
74                 case MONO_TYPE_U2:
75                 case MONO_TYPE_I4:
76                 case MONO_TYPE_U4:
77                 case MONO_TYPE_I:
78                 case MONO_TYPE_U:
79                 case MONO_TYPE_PTR:
80                 case MONO_TYPE_R4:
81                 case MONO_TYPE_SZARRAY:
82                 case MONO_TYPE_CLASS:
83                 case MONO_TYPE_OBJECT:
84                         stack_size += 4;
85                         code_size += i < 10 ? 5 : 8;
86                         break;
87                 case MONO_TYPE_VALUETYPE: {
88                         int size;
89                         if (sig->params [i]->data.klass->enumtype) {
90                                 simpletype = sig->params [i]->data.klass->enum_basetype->type;
91                                 goto enum_calc_size;
92                         }
93                         if ((size = mono_class_value_size (sig->params [i]->data.klass, NULL)) != 4) {
94                                 stack_size += size + 3;
95                                 stack_size &= ~3;
96                                 code_size += 32;
97                         } else {
98                                 stack_size += 4;
99                                 code_size += i < 10 ? 5 : 8;
100                         }
101                         break;
102                 }
103                 case MONO_TYPE_STRING:
104                         stack_size += 4;
105                         code_size += 20;
106                         local_size++;
107                         break;
108                 case MONO_TYPE_I8:
109                         stack_size += 8;
110                         code_size += i < 10 ? 5 : 8;
111                         break;
112                 case MONO_TYPE_R8:
113                         stack_size += 8;
114                         code_size += i < 10 ? 7 : 10;
115                         break;
116                 default:
117                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
118                 }
119         }
120         /*
121          * FIXME: take into account large return values.
122          */
123
124         code_buffer = p = alloca (code_size);
125
126         /*
127          * Standard function prolog.
128          */
129         x86_push_reg (p, X86_EBP);
130         x86_mov_reg_reg (p, X86_EBP, X86_ESP, 4);
131         /*
132          * We store some local vars here to handle string pointers.
133          * and align to 16 byte boundary...
134          */
135         if (local_size) {
136                 x86_alu_reg_imm (p, X86_SUB, X86_ESP, local_size * 4);
137                 stack_size = (stack_size * local_size * 4) % 16;
138         } else {
139                 stack_size = stack_size % 16;
140         }
141         if (stack_size)
142                 x86_alu_reg_imm (p, X86_SUB, X86_ESP, stack_size);
143
144         /*
145          * EDX has the pointer to the args.
146          */
147         x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4);
148
149         /*
150          * Push arguments in reverse order.
151          */
152         stringp = 0;
153         for (i = sig->param_count; i; --i) {
154                 arg_pos = ARG_SIZE * (i - 1);
155                 if (sig->params [i - 1]->byref) {
156                         x86_push_membase (p, X86_EDX, arg_pos);
157                         continue;
158                 }
159                 simpletype = sig->params [i - 1]->type;
160 enum_marshal:
161                 switch (simpletype) {
162                 case MONO_TYPE_BOOLEAN:
163                 case MONO_TYPE_I1:
164                 case MONO_TYPE_U1:
165                 case MONO_TYPE_I2:
166                 case MONO_TYPE_U2:
167                 case MONO_TYPE_CHAR:
168                 case MONO_TYPE_I4:
169                 case MONO_TYPE_U4:
170                 case MONO_TYPE_I:
171                 case MONO_TYPE_U:
172                 case MONO_TYPE_PTR:
173                 case MONO_TYPE_OBJECT:
174                         x86_push_membase (p, X86_EDX, arg_pos);
175                         break;
176                 case MONO_TYPE_R4:
177                         x86_alu_reg_imm (p, X86_SUB, X86_ESP, 4);
178                         x86_fld_membase (p, X86_EDX, arg_pos, TRUE);
179                         x86_fst_membase (p, X86_ESP, 0, FALSE, TRUE);
180                         break;
181                 case MONO_TYPE_CLASS:
182                         x86_push_membase (p, X86_EDX, arg_pos);
183                         break;
184                 case MONO_TYPE_SZARRAY:
185                         x86_push_membase (p, X86_EDX, arg_pos);
186                         break;
187                 case MONO_TYPE_VALUETYPE:
188                         if (!sig->params [i - 1]->data.klass->enumtype) {
189                                 int size = mono_class_value_size (sig->params [i - 1]->data.klass, NULL);
190                                 if (size == 4) {
191                                         /* it's a structure that fits in 4 bytes, need to push the value pointed to */
192                                         x86_mov_reg_membase (p, X86_EAX, X86_EDX, arg_pos, 4);
193                                         x86_push_regp (p, X86_EAX);
194                                 } else {
195                                         int ss = size;
196                                         ss += 3;
197                                         ss &= ~3;
198
199                                         x86_alu_reg_imm (p, X86_SUB, X86_ESP, ss);
200                                         x86_push_imm (p, size);
201                                         x86_push_membase (p, X86_EDX, arg_pos);
202                                         x86_lea_membase (p, X86_EAX, X86_ESP, 2*4);
203                                         x86_push_reg (p, X86_EAX);
204                                         x86_mov_reg_imm (p, X86_EAX, memcpy);
205                                         x86_call_reg (p, X86_EAX);
206                                         x86_alu_reg_imm (p, X86_ADD, X86_ESP, 12);
207                                 }
208                         } else {
209                                 /* it's an enum value */
210                                 simpletype = sig->params [i - 1]->data.klass->enum_basetype->type;
211                                 goto enum_marshal;
212                         }
213                         break;
214                 case MONO_TYPE_STRING:
215                         x86_push_membase (p, X86_EDX, arg_pos);
216                         break;
217                 case MONO_TYPE_I8:
218                 case MONO_TYPE_U8:
219                 case MONO_TYPE_R8:
220                         x86_push_membase (p, X86_EDX, arg_pos + 4);
221                         x86_push_membase (p, X86_EDX, arg_pos);
222                         break;
223                 default:
224                         g_error ("Can't trampoline 0x%x", sig->params [i - 1]->type);
225                 }
226         }
227
228         if (sig->hasthis) {
229                 if (sig->call_convention != MONO_CALL_THISCALL) {
230                         x86_mov_reg_membase (p, X86_EDX, X86_EBP, THIS_POS, 4);
231                         x86_push_reg (p, X86_EDX);
232                 } else {
233                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, THIS_POS, 4);
234                 }
235         }
236
237         if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref) {
238                 MonoClass *klass = sig->ret->data.klass;
239                 if (!klass->enumtype) {
240                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
241                         x86_push_membase (p, X86_ECX, 0);
242                 }
243         }
244
245         /* 
246          * Insert call to function 
247          */
248         x86_mov_reg_membase (p, X86_EDX, X86_EBP, FUNC_ADDR_POS, 4);
249         x86_call_reg (p, X86_EDX);
250
251         /*
252          * Handle retval.
253          * Small integer and pointer values are in EAX.
254          * Long integers are in EAX:EDX.
255          * FP values are on the FP stack.
256          */
257
258         if (sig->ret->byref || string_ctor) {
259                 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
260                 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
261         } else {
262                 simpletype = sig->ret->type;
263         enum_retvalue:
264                 switch (simpletype) {
265                 case MONO_TYPE_BOOLEAN:
266                 case MONO_TYPE_I1:
267                 case MONO_TYPE_U1:
268                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
269                         x86_mov_regp_reg (p, X86_ECX, X86_EAX, 1);
270                         break;
271                 case MONO_TYPE_CHAR:
272                 case MONO_TYPE_I2:
273                 case MONO_TYPE_U2:
274                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
275                         x86_mov_regp_reg (p, X86_ECX, X86_EAX, 2);
276                         break;
277                 case MONO_TYPE_I4:
278                 case MONO_TYPE_U4:
279                 case MONO_TYPE_I:
280                 case MONO_TYPE_U:
281                 case MONO_TYPE_CLASS:
282                 case MONO_TYPE_OBJECT:
283                 case MONO_TYPE_SZARRAY:
284                 case MONO_TYPE_ARRAY:
285                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
286                         x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
287                         break;
288                 case MONO_TYPE_STRING: 
289                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
290                         x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
291                         break;
292                 case MONO_TYPE_R4:
293                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
294                         x86_fst_membase (p, X86_ECX, 0, FALSE, TRUE);
295                         break;
296                 case MONO_TYPE_R8:
297                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
298                         x86_fst_membase (p, X86_ECX, 0, TRUE, TRUE);
299                         break;
300                 case MONO_TYPE_I8:
301                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
302                         x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
303                         x86_mov_membase_reg (p, X86_ECX, 4, X86_EDX, 4);
304                         break;
305                 case MONO_TYPE_VALUETYPE:
306                         if (sig->ret->data.klass->enumtype) {
307                                 simpletype = sig->ret->data.klass->enum_basetype->type;
308                                 goto enum_retvalue;
309                         }
310                 case MONO_TYPE_VOID:
311                         break;
312                 default:
313                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
314                 }
315         }
316
317         /*
318          * Standard epilog.
319          */
320         x86_leave (p);
321         x86_ret (p);
322
323         g_assert (p - code_buffer < code_size);
324         res = (MonoPIFunc)g_memdup (code_buffer, p - code_buffer);
325
326         g_hash_table_insert (cache, sig, res);
327
328         return res;
329 }
330
331 #define MINV_POS  (- sizeof (MonoInvocation))
332 #define STACK_POS (MINV_POS - sizeof (stackval) * sig->param_count)
333 #define TYPE_OFFSET (G_STRUCT_OFFSET (stackval, type))
334
335 /*
336  * Returns a pointer to a native function that can be used to
337  * call the specified method.
338  * The function created will receive the arguments according
339  * to the call convention specified in the method.
340  * This function works by creating a MonoInvocation structure,
341  * filling the fields in and calling ves_exec_method on it.
342  * Still need to figure out how to handle the exception stuff
343  * across the managed/unmanaged boundary.
344  */
345 void *
346 mono_create_method_pointer (MonoMethod *method)
347 {
348         MonoMethodSignature *sig;
349         MonoJitInfo *ji;
350         unsigned char *p, *code_buffer;
351         gint32 local_size;
352         gint32 stackval_pos, arg_pos = 8;
353         int i, size, align, cpos;
354         int vtbuf [sig->param_count];
355
356         /*
357          * If it is a static P/Invoke method, we can just return the pointer
358          * to the method implementation.
359          */
360         if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL && method->addr) {
361                 ji = g_new0 (MonoJitInfo, 1);
362                 ji->method = method;
363                 ji->code_size = 1;
364                 ji->code_start = method->addr;
365
366                 mono_jit_info_table_add (mono_root_domain, ji);
367                 return method->addr;
368         }
369
370         sig = method->signature;
371
372         code_buffer = p = alloca (512); /* FIXME: check for overflows... */
373
374         local_size = sizeof (MonoInvocation) + sizeof (stackval) * (sig->param_count + 1);
375
376         local_size += 7;
377         local_size &= ~7;
378
379         stackval_pos = -local_size;
380
381         cpos = 0;
382         for (i = 0; i < sig->param_count; i++) {
383                 MonoType *type = sig->params [i];
384                 vtbuf [i] = -1;
385                 if (type->type == MONO_TYPE_VALUETYPE) {
386                         MonoClass *klass = type->data.klass;
387                         if (klass->enumtype)
388                                 continue;
389                         size = mono_class_native_size (klass, &align);
390                         cpos += align - 1;
391                         cpos &= ~(align - 1);
392                         vtbuf [i] = cpos;
393                         cpos += size;
394                 }       
395         }
396
397         cpos += 7;
398         cpos &= ~7;
399
400         local_size += cpos;
401
402         /*
403          * Standard function prolog.
404          */
405         x86_push_reg (p, X86_EBP);
406         x86_mov_reg_reg (p, X86_EBP, X86_ESP, 4);
407         x86_alu_reg_imm (p, X86_SUB, X86_ESP, local_size);
408
409         /*
410          * Initialize MonoInvocation fields, first the ones known now.
411          */
412         x86_mov_reg_imm (p, X86_EAX, 0);
413         x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex)), X86_EAX, 4);
414         x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex_handler)), X86_EAX, 4);
415         x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, child)), X86_EAX, 4);
416         x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, parent)), X86_EAX, 4);
417         /*
418          * Set the method pointer.
419          */
420         x86_mov_membase_imm (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, method)), (int)method, 4);
421
422         if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref && !sig->ret->data.klass->enumtype) 
423                 arg_pos += 4;
424
425         /*
426          * Handle this.
427          */
428         if (sig->hasthis) {
429                 if (sig->call_convention != MONO_CALL_THISCALL) {
430                         /*
431                          * Grab it from the stack, otherwise it's already in ECX.
432                          */
433                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, arg_pos, 4);
434                         arg_pos += 4;
435                 }
436                 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)), X86_ECX, 4);
437         }
438         /*
439          * Handle the arguments. stackval_pos is the posset of the stackval array from EBP.
440          * arg_pos is the offset from EBP to the incoming arg on the stack.
441          * We just call stackval_from_data to handle all the (nasty) issues....
442          */
443         x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
444         x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, stack_args)), X86_EAX, 4);
445         for (i = 0; i < sig->param_count; ++i) {
446                 if (vtbuf [i] >= 0) {
447                         x86_lea_membase (p, X86_EAX, X86_EBP, - local_size + vtbuf [i]);
448                         x86_mov_membase_reg (p, X86_EBP, stackval_pos, X86_EAX, 4);
449                 }
450                 x86_mov_reg_imm (p, X86_ECX, stackval_from_data);
451                 x86_lea_membase (p, X86_EDX, X86_EBP, arg_pos);
452                 x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
453                 x86_push_imm (p, sig->pinvoke);
454                 x86_push_reg (p, X86_EDX);
455                 x86_push_reg (p, X86_EAX);
456                 x86_push_imm (p, sig->params [i]);
457                 x86_call_reg (p, X86_ECX);
458                 x86_alu_reg_imm (p, X86_SUB, X86_ESP, 16);
459                 stackval_pos += sizeof (stackval);
460                 /* fixme: alignment */
461                 if (sig->pinvoke)
462                         arg_pos += mono_type_native_stack_size (sig->params [i], &align);
463                 else
464                         arg_pos += mono_type_stack_size (sig->params [i], &align);
465         }
466
467         /*
468          * Handle the return value storage area.
469          */
470         x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
471         x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)), X86_EAX, 4);
472         if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref) {
473                 MonoClass *klass  = sig->ret->data.klass;
474                 if (!klass->enumtype) {
475                         x86_mov_reg_membase (p, X86_ECX, X86_EBP, 8, 4);
476                         x86_mov_membase_reg (p, X86_EBP, stackval_pos, X86_ECX, 4);
477                 }
478         }
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                 int simpletype = sig->ret->type;        
496         enum_retvalue:
497                 switch (sig->ret->type) {
498                 case MONO_TYPE_VOID:
499                         break;
500                 case MONO_TYPE_BOOLEAN:
501                         x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 1);
502                         break;
503                 case MONO_TYPE_I4:
504                 case MONO_TYPE_U4:
505                 case MONO_TYPE_I:
506                 case MONO_TYPE_U:
507                 case MONO_TYPE_OBJECT:
508                 case MONO_TYPE_STRING:
509                 case MONO_TYPE_CLASS:
510                         x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
511                         break;
512                 case MONO_TYPE_I8:
513                         x86_mov_reg_membase (p, X86_EDX, X86_EAX, 4, 4);
514                         x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
515                         break;
516                 case MONO_TYPE_R8:
517                         x86_fld_membase (p, X86_EAX, 0, TRUE);
518                         break;
519                 case MONO_TYPE_VALUETYPE:
520                         if (sig->ret->data.klass->enumtype) {
521                                 simpletype = sig->ret->data.klass->enum_basetype->type;
522                                 goto enum_retvalue;
523                         }
524                 
525                         x86_push_imm (p, sig->pinvoke);
526                         x86_push_membase (p, X86_EBP, stackval_pos);
527                         x86_push_reg (p, X86_EAX);
528                         x86_push_imm (p, sig->ret);
529                         x86_mov_reg_imm (p, X86_ECX, stackval_to_data);
530                         x86_call_reg (p, X86_ECX);
531                         //x86_breakpoint (p);
532                         x86_alu_reg_imm (p, X86_SUB, X86_ESP, 16);
533                         
534                         break;
535                 default:
536                         g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type);
537                         break;
538                 }
539         }
540         
541         /*
542          * Standard epilog.
543          */
544         x86_leave (p);
545         x86_ret (p);
546
547         g_assert (p - code_buffer < 512);
548
549         ji = g_new0 (MonoJitInfo, 1);
550         ji->method = method;
551         ji->code_size = p - code_buffer;
552         ji->code_start = g_memdup (code_buffer, p - code_buffer);
553
554         mono_jit_info_table_add (mono_root_domain, ji);
555
556         return ji->code_start;
557 }