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