2 * Create trampolines to invoke arbitrary functions.
4 * Copyright (C) Ximian Inc.
6 * Author: Paolo Molaro (lupus@ximian.com)
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"
21 * The resulting function takes the form:
22 * void func (void (*callme)(), void *retval, void *this_obj, stackval *arguments);
24 #define FUNC_ADDR_POS 8
30 #define ARG_SIZE sizeof (stackval)
33 mono_create_trampoline (MonoMethod *method, int runtime)
35 MonoMethodSignature *sig;
36 unsigned char *p, *code_buffer;
37 guint32 local_size = 0, stack_size = 0, code_size = 50;
38 guint32 arg_pos, simpletype;
41 GList *free_locs = NULL;
43 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime)
48 sig = method->signature;
51 stack_size += sizeof (gpointer);
55 for (i = 0; i < sig->param_count; ++i) {
56 if (sig->params [i]->byref) {
57 stack_size += sizeof (gpointer);
62 simpletype = sig->params [i]->type;
65 case MONO_TYPE_BOOLEAN:
77 case MONO_TYPE_SZARRAY:
79 case MONO_TYPE_OBJECT:
81 code_size += i < 10 ? 5 : 8;
83 case MONO_TYPE_VALUETYPE:
84 if (sig->params [i]->data.klass->enumtype) {
85 simpletype = sig->params [i]->data.klass->enum_basetype->type;
88 if (mono_class_value_size (sig->params [i]->data.klass, NULL) != 4)
89 g_error ("can only marshal enums, not generic structures (size: %d)", mono_class_value_size (sig->params [i]->data.klass, NULL));
91 code_size += i < 10 ? 5 : 8;
93 case MONO_TYPE_STRING:
100 code_size += i < 10 ? 5 : 8;
104 code_size += i < 10 ? 7 : 10;
107 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
111 * FIXME: take into account large return values.
114 code_buffer = p = alloca (code_size);
117 * Standard function prolog.
119 x86_push_reg (p, X86_EBP);
120 x86_mov_reg_reg (p, X86_EBP, X86_ESP, 4);
122 * We store some local vars here to handle string pointers.
123 * and align to 16 byte boundary...
126 x86_alu_reg_imm (p, X86_SUB, X86_ESP, local_size * 4);
127 stack_size = (stack_size * local_size * 4) % 16;
129 stack_size = stack_size % 16;
132 x86_alu_reg_imm (p, X86_SUB, X86_ESP, stack_size);
135 * EDX has the pointer to the args.
137 x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4);
140 * Push arguments in reverse order.
143 for (i = sig->param_count; i; --i) {
144 arg_pos = ARG_SIZE * (i - 1);
145 if (sig->params [i - 1]->byref) {
147 x86_push_membase (p, X86_EDX, arg_pos);
150 if (sig->params [i - 1]->type == MONO_TYPE_SZARRAY &&
151 sig->params [i - 1]->data.type->type == MONO_TYPE_STRING) {
152 x86_mov_reg_membase (p, X86_EAX, X86_EDX, arg_pos, 4);
153 x86_push_regp (p, X86_EAX);
154 x86_mov_reg_imm (p, X86_EDX, mono_marshal_string_array);
155 x86_call_reg (p, X86_EDX);
156 x86_alu_reg_imm (p, X86_ADD, X86_ESP, 4);
158 * Store the pointer in a local we'll free later.
161 x86_mov_membase_reg (p, X86_EBP, LOC_POS * stringp, X86_EAX, 4);
162 free_locs = g_list_prepend (free_locs, GUINT_TO_POINTER (LOC_POS * stringp));
163 /* load the pointer and push it */
164 x86_lea_membase (p, X86_EAX, X86_EBP, LOC_POS * stringp);
165 x86_push_reg (p, X86_EAX);
166 /* restore pointer to args in EDX */
167 x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4);
169 x86_push_membase (p, X86_EDX, arg_pos);
173 simpletype = sig->params [i - 1]->type;
175 switch (simpletype) {
176 case MONO_TYPE_BOOLEAN:
187 case MONO_TYPE_OBJECT:
188 x86_push_membase (p, X86_EDX, arg_pos);
191 x86_alu_reg_imm (p, X86_SUB, X86_ESP, 4);
192 x86_fld_membase (p, X86_EDX, arg_pos, TRUE);
193 x86_fst_membase (p, X86_ESP, 0, FALSE, TRUE);
195 case MONO_TYPE_CLASS:
197 if (sig->params [i - 1]->data.klass->delegate) {
198 /* should we use a wrapper to invoke the multicast delegates? */
199 x86_mov_reg_membase (p, X86_EAX, X86_EDX, arg_pos, 4);
200 x86_alu_reg_imm (p, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
201 x86_push_reg (p, X86_EAX);
203 g_error ("unhandled case");
205 x86_push_membase (p, X86_EDX, arg_pos);
208 case MONO_TYPE_SZARRAY:
210 x86_mov_reg_membase (p, X86_EAX, X86_EDX, arg_pos, 4);
211 x86_alu_reg_imm (p, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoArray, vector));
212 x86_push_reg (p, X86_EAX);
214 x86_push_membase (p, X86_EDX, arg_pos);
217 case MONO_TYPE_VALUETYPE:
218 if (!sig->params [i - 1]->data.klass->enumtype) {
219 /* it's a structure that fits in 4 bytes, need to push the value pointed to */
220 x86_mov_reg_membase (p, X86_EAX, X86_EDX, arg_pos, 4);
221 x86_push_regp (p, X86_EAX);
223 /* it's an enum value */
224 simpletype = sig->params [i - 1]->data.klass->enum_basetype->type;
228 case MONO_TYPE_STRING:
230 * If it is an internalcall we assume it's the object we want.
231 * Yet another reason why MONO_TYPE_STRING should not be used to indicate char*.
234 x86_push_membase (p, X86_EDX, arg_pos);
237 /*if (frame->method->flags & PINVOKE_ATTRIBUTE_CHAR_SET_ANSI*/
238 x86_push_membase (p, X86_EDX, arg_pos);
239 x86_mov_reg_imm (p, X86_EDX, mono_string_to_utf8);
240 x86_call_reg (p, X86_EDX);
241 x86_alu_reg_imm (p, X86_ADD, X86_ESP, 4);
242 x86_push_reg (p, X86_EAX);
244 * Store the pointer in a local we'll free later.
247 x86_mov_membase_reg (p, X86_EBP, LOC_POS * stringp, X86_EAX, 4);
248 free_locs = g_list_prepend (free_locs, GUINT_TO_POINTER (LOC_POS * stringp));
250 * we didn't save the reg: restore it here.
253 x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4);
258 x86_push_membase (p, X86_EDX, arg_pos + 4);
259 x86_push_membase (p, X86_EDX, arg_pos);
262 g_error ("Can't trampoline 0x%x", sig->params [i - 1]->type);
267 if (sig->call_convention != MONO_CALL_THISCALL) {
268 x86_mov_reg_membase (p, X86_EDX, X86_EBP, THIS_POS, 4);
269 x86_push_reg (p, X86_EDX);
271 x86_mov_reg_membase (p, X86_ECX, X86_EBP, THIS_POS, 4);
276 * Insert call to function
278 x86_mov_reg_membase (p, X86_EDX, X86_EBP, FUNC_ADDR_POS, 4);
279 x86_call_reg (p, X86_EDX);
283 * Small integer and pointer values are in EAX.
284 * Long integers are in EAX:EDX.
285 * FP values are on the FP stack.
288 if (sig->ret->byref ||
289 (method->klass == mono_defaults.string_class &&
290 *method->name == '.' && !strcmp (method->name, ".ctor"))) {
291 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
292 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
294 simpletype = sig->ret->type;
296 switch (simpletype) {
297 case MONO_TYPE_BOOLEAN:
300 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
301 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 1);
306 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
307 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 2);
313 case MONO_TYPE_CLASS:
314 case MONO_TYPE_OBJECT:
315 case MONO_TYPE_SZARRAY:
316 case MONO_TYPE_ARRAY:
317 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
318 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
320 case MONO_TYPE_STRING:
322 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
323 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
327 /* If the argument is non-null, then convert the value back */
328 x86_alu_reg_reg (p, X86_OR, X86_EAX, X86_EAX);
329 x86_branch8 (p, X86_CC_EQ, 11, FALSE);
330 x86_push_reg (p, X86_EAX);
331 x86_mov_reg_imm (p, X86_EDX, mono_string_new_wrapper);
332 x86_call_reg (p, X86_EDX);
333 x86_alu_reg_imm (p, X86_ADD, X86_ESP, 4);
335 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
336 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
339 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
340 x86_fst_membase (p, X86_ECX, 0, FALSE, TRUE);
343 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
344 x86_fst_membase (p, X86_ECX, 0, TRUE, TRUE);
347 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
348 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
349 x86_mov_membase_reg (p, X86_ECX, 4, X86_EDX, 4);
351 case MONO_TYPE_VALUETYPE:
352 if (sig->ret->data.klass->enumtype) {
353 simpletype = sig->ret->data.klass->enum_basetype->type;
359 g_error ("Can't handle as return value 0x%x", sig->ret->type);
364 * free the allocated strings.
368 for (tmp = free_locs; tmp; tmp = tmp->next) {
369 x86_mov_reg_imm (p, X86_EDX, g_free);
370 x86_push_membase (p, X86_EBP, GPOINTER_TO_UINT (tmp->data));
371 x86_call_reg (p, X86_EDX);
373 g_list_free (free_locs);
381 g_assert (p - code_buffer < code_size);
382 return g_memdup (code_buffer, p - code_buffer);
385 #define MINV_POS (- sizeof (MonoInvocation))
386 #define STACK_POS (MINV_POS - sizeof (stackval) * sig->param_count)
388 #define TYPE_OFFSET (G_STRUCT_OFFSET (stackval, type))
391 * Returns a pointer to a native function that can be used to
392 * call the specified method.
393 * The function created will receive the arguments according
394 * to the call convention specified in the method.
395 * This function works by creating a MonoInvocation structure,
396 * filling the fields in and calling ves_exec_method on it.
397 * Still need to figure out how to handle the exception stuff
398 * across the managed/unmanaged boundary.
401 mono_create_method_pointer (MonoMethod *method)
403 MonoMethodSignature *sig;
405 unsigned char *p, *code_buffer;
407 gint32 stackval_pos, arg_pos = 8;
411 * If it is a static P/Invoke method, we can just return the pointer
412 * to the method implementation.
414 sig = method->signature;
416 code_buffer = p = alloca (512); /* FIXME: check for overflows... */
418 local_size = sizeof (MonoInvocation) + sizeof (stackval) * (sig->param_count + 1);
419 stackval_pos = -local_size;
422 * Standard function prolog.
424 x86_push_reg (p, X86_EBP);
425 x86_mov_reg_reg (p, X86_EBP, X86_ESP, 4);
426 x86_alu_reg_imm (p, X86_SUB, X86_ESP, local_size);
429 * Initialize MonoInvocation fields, first the ones known now.
431 x86_mov_reg_imm (p, X86_EAX, 0);
432 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex)), X86_EAX, 4);
433 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex_handler)), X86_EAX, 4);
434 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, child)), X86_EAX, 4);
435 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, parent)), X86_EAX, 4);
437 * Set the method pointer.
439 x86_mov_membase_imm (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, method)), (int)method, 4);
445 if (sig->call_convention != MONO_CALL_THISCALL) {
447 * Grab it from the stack, otherwise it's already in ECX.
449 x86_mov_reg_membase (p, X86_ECX, X86_EBP, OBJ_POS, 4);
452 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)), X86_ECX, 4);
455 * Handle the arguments. stackval_pos is the posset of the stackval array from EBP.
456 * arg_pos is the offset from EBP to the incoming arg on the stack.
457 * We just call stackval_from_data to handle all the (nasty) issues....
459 x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
460 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, stack_args)), X86_EAX, 4);
461 for (i = 0; i < sig->param_count; ++i) {
462 x86_mov_reg_imm (p, X86_ECX, stackval_from_data);
463 x86_lea_membase (p, X86_EDX, X86_EBP, arg_pos);
464 x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
465 x86_push_reg (p, X86_EDX);
466 x86_push_reg (p, X86_EAX);
467 x86_push_imm (p, sig->params [i]);
468 x86_call_reg (p, X86_ECX);
469 x86_alu_reg_imm (p, X86_SUB, X86_ESP, 12);
470 stackval_pos += sizeof (stackval);
471 arg_pos += mono_type_stack_size (sig->params [i], &align);
475 * Handle the return value storage area.
477 x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
478 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)), X86_EAX, 4);
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);
489 * Move the return value to the proper place.
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);
495 switch (sig->ret->type) {
498 case MONO_TYPE_BOOLEAN:
499 x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 1);
505 case MONO_TYPE_OBJECT:
506 case MONO_TYPE_STRING:
507 case MONO_TYPE_CLASS:
508 x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
511 x86_mov_reg_membase (p, X86_EDX, X86_EAX, 4, 4);
512 x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
515 x86_fld_membase (p, X86_EAX, 0, TRUE);
518 g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type);
529 g_assert (p - code_buffer < 512);
531 ji = g_new0 (MonoJitInfo, 1);
533 ji->code_size = p - code_buffer;
534 ji->code_start = g_memdup (code_buffer, p - code_buffer);
536 mono_jit_info_table_add (mono_root_domain, ji);
538 return ji->code_start;