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_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);
206 /* it's an enum value */
207 simpletype = sig->params [i - 1]->data.klass->enum_basetype->type;
214 x86_push_membase (p, X86_EDX, arg_pos + 4);
215 x86_push_membase (p, X86_EDX, arg_pos);
218 g_error ("Can't trampoline 0x%x", sig->params [i - 1]->type);
223 if (sig->call_convention != MONO_CALL_THISCALL) {
224 x86_mov_reg_membase (p, X86_EDX, X86_EBP, THIS_POS, 4);
225 x86_push_reg (p, X86_EDX);
227 x86_mov_reg_membase (p, X86_ECX, X86_EBP, THIS_POS, 4);
231 if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref) {
232 MonoClass *klass = sig->ret->data.klass;
233 if (!klass->enumtype) {
234 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
235 x86_push_membase (p, X86_ECX, 0);
240 * Insert call to function
242 x86_mov_reg_membase (p, X86_EDX, X86_EBP, FUNC_ADDR_POS, 4);
243 x86_call_reg (p, X86_EDX);
247 * Small integer and pointer values are in EAX.
248 * Long integers are in EAX:EDX.
249 * FP values are on the FP stack.
252 if (sig->ret->byref || string_ctor) {
253 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
254 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
256 simpletype = sig->ret->type;
258 switch (simpletype) {
259 case MONO_TYPE_BOOLEAN:
262 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
263 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 1);
268 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
269 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 2);
275 case MONO_TYPE_CLASS:
276 case MONO_TYPE_OBJECT:
277 case MONO_TYPE_SZARRAY:
278 case MONO_TYPE_ARRAY:
279 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
280 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
282 case MONO_TYPE_STRING:
283 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
284 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
287 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
288 x86_fst_membase (p, X86_ECX, 0, FALSE, TRUE);
291 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
292 x86_fst_membase (p, X86_ECX, 0, TRUE, TRUE);
295 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
296 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
297 x86_mov_membase_reg (p, X86_ECX, 4, X86_EDX, 4);
299 case MONO_TYPE_VALUETYPE:
300 if (sig->ret->data.klass->enumtype) {
301 simpletype = sig->ret->data.klass->enum_basetype->type;
307 g_error ("Can't handle as return value 0x%x", sig->ret->type);
317 g_assert (p - code_buffer < code_size);
318 res = (MonoPIFunc)g_memdup (code_buffer, p - code_buffer);
320 g_hash_table_insert (cache, sig, res);
325 #define MINV_POS (- sizeof (MonoInvocation))
326 #define STACK_POS (MINV_POS - sizeof (stackval) * sig->param_count)
327 #define TYPE_OFFSET (G_STRUCT_OFFSET (stackval, type))
330 * Returns a pointer to a native function that can be used to
331 * call the specified method.
332 * The function created will receive the arguments according
333 * to the call convention specified in the method.
334 * This function works by creating a MonoInvocation structure,
335 * filling the fields in and calling ves_exec_method on it.
336 * Still need to figure out how to handle the exception stuff
337 * across the managed/unmanaged boundary.
340 mono_create_method_pointer (MonoMethod *method)
342 MonoMethodSignature *sig;
344 unsigned char *p, *code_buffer;
346 gint32 stackval_pos, arg_pos = 8;
347 int i, size, align, cpos;
351 * If it is a static P/Invoke method, we can just return the pointer
352 * to the method implementation.
354 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL && method->addr) {
355 ji = g_new0 (MonoJitInfo, 1);
358 ji->code_start = method->addr;
360 mono_jit_info_table_add (mono_root_domain, ji);
364 sig = method->signature;
366 code_buffer = p = alloca (512); /* FIXME: check for overflows... */
367 vtbuf = alloca (sizeof(int)*sig->param_count);
369 local_size = sizeof (MonoInvocation) + sizeof (stackval) * (sig->param_count + 1);
374 stackval_pos = -local_size;
377 for (i = 0; i < sig->param_count; i++) {
378 MonoType *type = sig->params [i];
380 if (type->type == MONO_TYPE_VALUETYPE) {
381 MonoClass *klass = type->data.klass;
384 size = mono_class_native_size (klass, &align);
386 cpos &= ~(align - 1);
398 * Standard function prolog.
400 x86_push_reg (p, X86_EBP);
401 x86_mov_reg_reg (p, X86_EBP, X86_ESP, 4);
402 x86_alu_reg_imm (p, X86_SUB, X86_ESP, local_size);
405 * Initialize MonoInvocation fields, first the ones known now.
407 x86_mov_reg_imm (p, X86_EAX, 0);
408 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex)), X86_EAX, 4);
409 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex_handler)), X86_EAX, 4);
410 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, child)), X86_EAX, 4);
411 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, parent)), X86_EAX, 4);
413 * Set the method pointer.
415 x86_mov_membase_imm (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, method)), (int)method, 4);
417 if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref && !sig->ret->data.klass->enumtype)
424 if (sig->call_convention != MONO_CALL_THISCALL) {
426 * Grab it from the stack, otherwise it's already in ECX.
428 x86_mov_reg_membase (p, X86_ECX, X86_EBP, arg_pos, 4);
431 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)), X86_ECX, 4);
434 * Handle the arguments. stackval_pos is the posset of the stackval array from EBP.
435 * arg_pos is the offset from EBP to the incoming arg on the stack.
436 * We just call stackval_from_data to handle all the (nasty) issues....
438 x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
439 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, stack_args)), X86_EAX, 4);
440 for (i = 0; i < sig->param_count; ++i) {
441 if (vtbuf [i] >= 0) {
442 x86_lea_membase (p, X86_EAX, X86_EBP, - local_size + vtbuf [i]);
443 x86_mov_membase_reg (p, X86_EBP, stackval_pos, X86_EAX, 4);
445 x86_mov_reg_imm (p, X86_ECX, stackval_from_data);
446 x86_lea_membase (p, X86_EDX, X86_EBP, arg_pos);
447 x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
448 x86_push_imm (p, sig->pinvoke);
449 x86_push_reg (p, X86_EDX);
450 x86_push_reg (p, X86_EAX);
451 x86_push_imm (p, sig->params [i]);
452 x86_call_reg (p, X86_ECX);
453 x86_alu_reg_imm (p, X86_SUB, X86_ESP, 16);
454 stackval_pos += sizeof (stackval);
455 /* fixme: alignment */
457 arg_pos += mono_type_native_stack_size (sig->params [i], &align);
459 arg_pos += mono_type_stack_size (sig->params [i], &align);
463 * Handle the return value storage area.
465 x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
466 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)), X86_EAX, 4);
467 if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref) {
468 MonoClass *klass = sig->ret->data.klass;
469 if (!klass->enumtype) {
470 x86_mov_reg_membase (p, X86_ECX, X86_EBP, 8, 4);
471 x86_mov_membase_reg (p, X86_EBP, stackval_pos, X86_ECX, 4);
478 x86_lea_membase (p, X86_EAX, X86_EBP, MINV_POS);
479 x86_push_reg (p, X86_EAX);
480 x86_mov_reg_imm (p, X86_EDX, ves_exec_method);
481 x86_call_reg (p, X86_EDX);
484 * Move the return value to the proper place.
486 x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
487 if (sig->ret->byref) {
488 x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
490 int simpletype = sig->ret->type;
492 switch (sig->ret->type) {
495 case MONO_TYPE_BOOLEAN:
496 x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 1);
502 case MONO_TYPE_OBJECT:
503 case MONO_TYPE_STRING:
504 case MONO_TYPE_CLASS:
505 x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
508 x86_mov_reg_membase (p, X86_EDX, X86_EAX, 4, 4);
509 x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
512 x86_fld_membase (p, X86_EAX, 0, TRUE);
514 case MONO_TYPE_VALUETYPE:
515 if (sig->ret->data.klass->enumtype) {
516 simpletype = sig->ret->data.klass->enum_basetype->type;
520 x86_push_imm (p, sig->pinvoke);
521 x86_push_membase (p, X86_EBP, stackval_pos);
522 x86_push_reg (p, X86_EAX);
523 x86_push_imm (p, sig->ret);
524 x86_mov_reg_imm (p, X86_ECX, stackval_to_data);
525 x86_call_reg (p, X86_ECX);
526 x86_alu_reg_imm (p, X86_SUB, X86_ESP, 16);
530 g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type);
541 g_assert (p - code_buffer < 512);
543 ji = g_new0 (MonoJitInfo, 1);
545 ji->code_size = p - code_buffer;
546 ji->code_start = g_memdup (code_buffer, p - code_buffer);
548 mono_jit_info_table_add (mono_root_domain, ji);
550 return ji->code_start;