2 * Create trampolines to invoke arbitrary functions.
4 * Copyright (C) Ximian Inc.
7 * Paolo Molaro (lupus@ximian.com)
8 * Dietmar Maurer (dietmar@ximian.com)
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"
23 * The resulting function takes the form:
24 * void func (void (*callme)(), void *retval, void *this_obj, stackval *arguments);
26 #define FUNC_ADDR_POS 8
32 #define ARG_SIZE sizeof (stackval)
35 mono_arch_create_trampoline (MonoMethodSignature
*sig
, gboolean string_ctor
)
37 unsigned char *p
, *code_buffer
;
38 guint32 stack_size
= 0, code_size
= 50;
39 guint32 arg_pos
, simpletype
;
41 static GHashTable
*cache
= NULL
;
45 cache
= g_hash_table_new ((GHashFunc
)mono_signature_hash
,
46 (GCompareFunc
)mono_metadata_signature_equal
);
48 if ((res
= (MonoPIFunc
)g_hash_table_lookup (cache
, sig
)))
52 stack_size
+= sizeof (gpointer
);
56 if (sig
->ret
->type
== MONO_TYPE_VALUETYPE
&& !sig
->ret
->byref
&& !sig
->ret
->data
.klass
->enumtype
) {
57 stack_size
+= sizeof (gpointer
);
61 for (i
= 0; i
< sig
->param_count
; ++i
) {
62 if (sig
->params
[i
]->byref
) {
63 stack_size
+= sizeof (gpointer
);
67 simpletype
= sig
->params
[i
]->type
;
70 case MONO_TYPE_BOOLEAN
:
81 case MONO_TYPE_SZARRAY
:
83 case MONO_TYPE_OBJECT
:
84 case MONO_TYPE_STRING
:
86 code_size
+= i
< 10 ? 5 : 8;
88 case MONO_TYPE_VALUETYPE
: {
90 if (sig
->params
[i
]->data
.klass
->enumtype
) {
91 simpletype
= sig
->params
[i
]->data
.klass
->enum_basetype
->type
;
94 if ((size
= mono_class_native_size (sig
->params
[i
]->data
.klass
, NULL
)) != 4) {
95 stack_size
+= size
+ 3;
100 code_size
+= i
< 10 ? 5 : 8;
106 code_size
+= i
< 10 ? 5 : 8;
110 code_size
+= i
< 10 ? 10 : 13;
114 code_size
+= i
< 10 ? 7 : 10;
117 g_error ("Can't trampoline 0x%x", sig
->params
[i
]->type
);
121 * FIXME: take into account large return values.
124 code_buffer
= p
= alloca (code_size
);
127 * Standard function prolog.
129 x86_push_reg (p
, X86_EBP
);
130 x86_mov_reg_reg (p
, X86_EBP
, X86_ESP
, 4);
132 * and align to 16 byte boundary...
138 x86_alu_reg_imm (p
, X86_SUB
, X86_ESP
, stack_size
);
141 * EDX has the pointer to the args.
143 x86_mov_reg_membase (p
, X86_EDX
, X86_EBP
, ARGP_POS
, 4);
146 * Push arguments in reverse order.
149 for (i
= sig
->param_count
; i
; --i
) {
150 arg_pos
= ARG_SIZE
* (i
- 1);
151 if (sig
->params
[i
- 1]->byref
) {
152 x86_push_membase (p
, X86_EDX
, arg_pos
);
155 simpletype
= sig
->params
[i
- 1]->type
;
157 switch (simpletype
) {
158 case MONO_TYPE_BOOLEAN
:
169 case MONO_TYPE_OBJECT
:
170 case MONO_TYPE_STRING
:
171 x86_push_membase (p
, X86_EDX
, arg_pos
);
174 x86_alu_reg_imm (p
, X86_SUB
, X86_ESP
, 4);
175 x86_fld_membase (p
, X86_EDX
, arg_pos
, TRUE
);
176 x86_fst_membase (p
, X86_ESP
, 0, FALSE
, TRUE
);
178 case MONO_TYPE_CLASS
:
179 x86_push_membase (p
, X86_EDX
, arg_pos
);
181 case MONO_TYPE_SZARRAY
:
182 x86_push_membase (p
, X86_EDX
, arg_pos
);
184 case MONO_TYPE_VALUETYPE
:
185 if (!sig
->params
[i
- 1]->data
.klass
->enumtype
) {
186 int size
= mono_class_native_size (sig
->params
[i
- 1]->data
.klass
, NULL
);
188 /* it's a structure that fits in 4 bytes, need to push the value pointed to */
189 x86_mov_reg_membase (p
, X86_EAX
, X86_EDX
, arg_pos
, 4);
190 x86_push_regp (p
, X86_EAX
);
196 x86_alu_reg_imm (p
, X86_SUB
, X86_ESP
, ss
);
197 x86_push_imm (p
, size
);
198 x86_push_membase (p
, X86_EDX
, arg_pos
);
199 x86_lea_membase (p
, X86_EAX
, X86_ESP
, 2*4);
200 x86_push_reg (p
, X86_EAX
);
201 x86_mov_reg_imm (p
, X86_EAX
, memcpy
);
202 x86_call_reg (p
, X86_EAX
);
203 x86_alu_reg_imm (p
, X86_ADD
, X86_ESP
, 12);
204 /* memcpy might clobber EDX so restore it */
205 x86_mov_reg_membase (p
, X86_EDX
, X86_EBP
, ARGP_POS
, 4);
208 /* it's an enum value */
209 simpletype
= sig
->params
[i
- 1]->data
.klass
->enum_basetype
->type
;
216 x86_push_membase (p
, X86_EDX
, arg_pos
+ 4);
217 x86_push_membase (p
, X86_EDX
, arg_pos
);
220 g_error ("Can't trampoline 0x%x", sig
->params
[i
- 1]->type
);
225 if (sig
->call_convention
!= MONO_CALL_THISCALL
) {
226 x86_mov_reg_membase (p
, X86_EDX
, X86_EBP
, THIS_POS
, 4);
227 x86_push_reg (p
, X86_EDX
);
229 x86_mov_reg_membase (p
, X86_ECX
, X86_EBP
, THIS_POS
, 4);
233 if (sig
->ret
->type
== MONO_TYPE_VALUETYPE
&& !sig
->ret
->byref
) {
234 MonoClass
*klass
= sig
->ret
->data
.klass
;
235 if (!klass
->enumtype
) {
236 x86_mov_reg_membase (p
, X86_ECX
, X86_EBP
, RETVAL_POS
, 4);
237 x86_push_membase (p
, X86_ECX
, 0);
242 * Insert call to function
244 x86_mov_reg_membase (p
, X86_EDX
, X86_EBP
, FUNC_ADDR_POS
, 4);
245 x86_call_reg (p
, X86_EDX
);
249 * Small integer and pointer values are in EAX.
250 * Long integers are in EAX:EDX.
251 * FP values are on the FP stack.
254 if (sig
->ret
->byref
|| string_ctor
) {
255 x86_mov_reg_membase (p
, X86_ECX
, X86_EBP
, RETVAL_POS
, 4);
256 x86_mov_regp_reg (p
, X86_ECX
, X86_EAX
, 4);
258 simpletype
= sig
->ret
->type
;
260 switch (simpletype
) {
261 case MONO_TYPE_BOOLEAN
:
264 x86_mov_reg_membase (p
, X86_ECX
, X86_EBP
, RETVAL_POS
, 4);
265 x86_mov_regp_reg (p
, X86_ECX
, X86_EAX
, 1);
270 x86_mov_reg_membase (p
, X86_ECX
, X86_EBP
, RETVAL_POS
, 4);
271 x86_mov_regp_reg (p
, X86_ECX
, X86_EAX
, 2);
277 case MONO_TYPE_CLASS
:
278 case MONO_TYPE_OBJECT
:
279 case MONO_TYPE_SZARRAY
:
280 case MONO_TYPE_ARRAY
:
281 x86_mov_reg_membase (p
, X86_ECX
, X86_EBP
, RETVAL_POS
, 4);
282 x86_mov_regp_reg (p
, X86_ECX
, X86_EAX
, 4);
284 case MONO_TYPE_STRING
:
285 x86_mov_reg_membase (p
, X86_ECX
, X86_EBP
, RETVAL_POS
, 4);
286 x86_mov_regp_reg (p
, X86_ECX
, X86_EAX
, 4);
289 x86_mov_reg_membase (p
, X86_ECX
, X86_EBP
, RETVAL_POS
, 4);
290 x86_fst_membase (p
, X86_ECX
, 0, FALSE
, TRUE
);
293 x86_mov_reg_membase (p
, X86_ECX
, X86_EBP
, RETVAL_POS
, 4);
294 x86_fst_membase (p
, X86_ECX
, 0, TRUE
, TRUE
);
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 x86_mov_membase_reg (p
, X86_ECX
, 4, X86_EDX
, 4);
301 case MONO_TYPE_VALUETYPE
:
302 if (sig
->ret
->data
.klass
->enumtype
) {
303 simpletype
= sig
->ret
->data
.klass
->enum_basetype
->type
;
309 g_error ("Can't handle as return value 0x%x", sig
->ret
->type
);
319 g_assert (p
- code_buffer
< code_size
);
320 res
= (MonoPIFunc
)g_memdup (code_buffer
, p
- code_buffer
);
322 g_hash_table_insert (cache
, sig
, res
);
327 #define MINV_POS (- sizeof (MonoInvocation))
328 #define STACK_POS (MINV_POS - sizeof (stackval) * sig->param_count)
329 #define TYPE_OFFSET (G_STRUCT_OFFSET (stackval, type))
332 * Returns a pointer to a native function that can be used to
333 * call the specified method.
334 * The function created will receive the arguments according
335 * to the call convention specified in the method.
336 * This function works by creating a MonoInvocation structure,
337 * filling the fields in and calling ves_exec_method on it.
338 * Still need to figure out how to handle the exception stuff
339 * across the managed/unmanaged boundary.
342 mono_arch_create_method_pointer (MonoMethod
*method
)
344 MonoMethodSignature
*sig
;
346 unsigned char *p
, *code_buffer
;
348 gint32 stackval_pos
, arg_pos
= 8;
349 int i
, size
, align
, cpos
;
352 sig
= method
->signature
;
354 code_buffer
= p
= alloca (512); /* FIXME: check for overflows... */
355 vtbuf
= alloca (sizeof(int)*sig
->param_count
);
357 local_size
= sizeof (MonoInvocation
) + sizeof (stackval
) * (sig
->param_count
+ 1);
362 stackval_pos
= -local_size
;
365 for (i
= 0; i
< sig
->param_count
; i
++) {
366 MonoType
*type
= sig
->params
[i
];
368 if (type
->type
== MONO_TYPE_VALUETYPE
) {
369 MonoClass
*klass
= type
->data
.klass
;
372 size
= mono_class_native_size (klass
, &align
);
374 cpos
&= ~(align
- 1);
386 * Standard function prolog.
388 x86_push_reg (p
, X86_EBP
);
389 x86_mov_reg_reg (p
, X86_EBP
, X86_ESP
, 4);
390 x86_alu_reg_imm (p
, X86_SUB
, X86_ESP
, local_size
);
393 * Initialize MonoInvocation fields, first the ones known now.
395 x86_mov_reg_imm (p
, X86_EAX
, 0);
396 x86_mov_membase_reg (p
, X86_EBP
, (MINV_POS
+ G_STRUCT_OFFSET (MonoInvocation
, ex
)), X86_EAX
, 4);
397 x86_mov_membase_reg (p
, X86_EBP
, (MINV_POS
+ G_STRUCT_OFFSET (MonoInvocation
, ex_handler
)), X86_EAX
, 4);
398 x86_mov_membase_reg (p
, X86_EBP
, (MINV_POS
+ G_STRUCT_OFFSET (MonoInvocation
, parent
)), X86_EAX
, 4);
400 * Set the method pointer.
402 x86_mov_membase_imm (p
, X86_EBP
, (MINV_POS
+ G_STRUCT_OFFSET (MonoInvocation
, method
)), (int)method
, 4);
404 if (sig
->ret
->type
== MONO_TYPE_VALUETYPE
&& !sig
->ret
->byref
&& !sig
->ret
->data
.klass
->enumtype
)
411 if (sig
->call_convention
!= MONO_CALL_THISCALL
) {
413 * Grab it from the stack, otherwise it's already in ECX.
415 x86_mov_reg_membase (p
, X86_ECX
, X86_EBP
, arg_pos
, 4);
418 x86_mov_membase_reg (p
, X86_EBP
, (MINV_POS
+ G_STRUCT_OFFSET (MonoInvocation
, obj
)), X86_ECX
, 4);
421 * Handle the arguments. stackval_pos is the posset of the stackval array from EBP.
422 * arg_pos is the offset from EBP to the incoming arg on the stack.
423 * We just call stackval_from_data to handle all the (nasty) issues....
425 x86_lea_membase (p
, X86_EAX
, X86_EBP
, stackval_pos
);
426 x86_mov_membase_reg (p
, X86_EBP
, (MINV_POS
+ G_STRUCT_OFFSET (MonoInvocation
, stack_args
)), X86_EAX
, 4);
427 for (i
= 0; i
< sig
->param_count
; ++i
) {
428 if (vtbuf
[i
] >= 0) {
429 x86_lea_membase (p
, X86_EAX
, X86_EBP
, - local_size
+ vtbuf
[i
]);
430 x86_mov_membase_reg (p
, X86_EBP
, stackval_pos
, X86_EAX
, 4);
432 x86_mov_reg_imm (p
, X86_ECX
, stackval_from_data
);
433 x86_lea_membase (p
, X86_EDX
, X86_EBP
, arg_pos
);
434 x86_lea_membase (p
, X86_EAX
, X86_EBP
, stackval_pos
);
435 x86_push_imm (p
, sig
->pinvoke
);
436 x86_push_reg (p
, X86_EDX
);
437 x86_push_reg (p
, X86_EAX
);
438 x86_push_imm (p
, sig
->params
[i
]);
439 x86_call_reg (p
, X86_ECX
);
440 x86_alu_reg_imm (p
, X86_SUB
, X86_ESP
, 16);
441 stackval_pos
+= sizeof (stackval
);
442 /* fixme: alignment */
444 arg_pos
+= mono_type_native_stack_size (sig
->params
[i
], &align
);
446 arg_pos
+= mono_type_stack_size (sig
->params
[i
], &align
);
450 * Handle the return value storage area.
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 if (sig
->ret
->type
== MONO_TYPE_VALUETYPE
&& !sig
->ret
->byref
) {
455 MonoClass
*klass
= sig
->ret
->data
.klass
;
456 if (!klass
->enumtype
) {
457 x86_mov_reg_membase (p
, X86_ECX
, X86_EBP
, 8, 4);
458 x86_mov_membase_reg (p
, X86_EBP
, stackval_pos
, X86_ECX
, 4);
465 x86_lea_membase (p
, X86_EAX
, X86_EBP
, MINV_POS
);
466 x86_push_reg (p
, X86_EAX
);
467 x86_mov_reg_imm (p
, X86_EDX
, ves_exec_method
);
468 x86_call_reg (p
, X86_EDX
);
471 * Move the return value to the proper place.
473 x86_lea_membase (p
, X86_EAX
, X86_EBP
, stackval_pos
);
474 if (sig
->ret
->byref
) {
475 x86_mov_reg_membase (p
, X86_EAX
, X86_EAX
, 0, 4);
477 int simpletype
= sig
->ret
->type
;
479 switch (sig
->ret
->type
) {
482 case MONO_TYPE_BOOLEAN
:
485 x86_mov_reg_membase (p
, X86_EAX
, X86_EAX
, 0, 1);
490 x86_mov_reg_membase (p
, X86_EAX
, X86_EAX
, 0, 2);
496 case MONO_TYPE_OBJECT
:
497 case MONO_TYPE_STRING
:
498 case MONO_TYPE_CLASS
:
499 x86_mov_reg_membase (p
, X86_EAX
, X86_EAX
, 0, 4);
502 x86_mov_reg_membase (p
, X86_EDX
, X86_EAX
, 4, 4);
503 x86_mov_reg_membase (p
, X86_EAX
, X86_EAX
, 0, 4);
506 x86_fld_membase (p
, X86_EAX
, 0, TRUE
);
508 case MONO_TYPE_VALUETYPE
:
509 if (sig
->ret
->data
.klass
->enumtype
) {
510 simpletype
= sig
->ret
->data
.klass
->enum_basetype
->type
;
514 x86_push_imm (p
, sig
->pinvoke
);
515 x86_push_membase (p
, X86_EBP
, stackval_pos
);
516 x86_push_reg (p
, X86_EAX
);
517 x86_push_imm (p
, sig
->ret
);
518 x86_mov_reg_imm (p
, X86_ECX
, stackval_to_data
);
519 x86_call_reg (p
, X86_ECX
);
520 x86_alu_reg_imm (p
, X86_SUB
, X86_ESP
, 16);
524 g_error ("Type 0x%x not handled yet in thunk creation", sig
->ret
->type
);
535 g_assert (p
- code_buffer
< 512);
537 ji
= g_new0 (MonoJitInfo
, 1);
539 ji
->code_size
= p
- code_buffer
;
540 ji
->code_start
= g_memdup (code_buffer
, p
- code_buffer
);
542 mono_jit_info_table_add (mono_get_root_domain (), ji
);
544 return ji
->code_start
;