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