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 (MonoMethodSignature *sig, gboolean string_ctor)
35 unsigned char *p, *code_buffer;
36 guint32 local_size = 0, stack_size = 0, code_size = 50;
37 guint32 arg_pos, simpletype;
39 static GHashTable *cache = NULL;
43 cache = g_hash_table_new ((GHashFunc)mono_signature_hash,
44 (GCompareFunc)mono_metadata_signature_equal);
46 if ((res = (MonoPIFunc)g_hash_table_lookup (cache, sig)))
50 stack_size += sizeof (gpointer);
54 for (i = 0; i < sig->param_count; ++i) {
55 if (sig->params [i]->byref) {
56 stack_size += sizeof (gpointer);
61 simpletype = sig->params [i]->type;
64 case MONO_TYPE_BOOLEAN:
76 case MONO_TYPE_SZARRAY:
78 case MONO_TYPE_OBJECT:
80 code_size += i < 10 ? 5 : 8;
82 case MONO_TYPE_VALUETYPE: {
84 if (sig->params [i]->data.klass->enumtype) {
85 simpletype = sig->params [i]->data.klass->enum_basetype->type;
88 if ((size = mono_class_value_size (sig->params [i]->data.klass, NULL)) != 4) {
89 stack_size += size + 3;
94 code_size += i < 10 ? 5 : 8;
98 case MONO_TYPE_STRING:
105 code_size += i < 10 ? 5 : 8;
109 code_size += i < 10 ? 7 : 10;
112 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
116 * FIXME: take into account large return values.
119 code_buffer = p = alloca (code_size);
122 * Standard function prolog.
124 x86_push_reg (p, X86_EBP);
125 x86_mov_reg_reg (p, X86_EBP, X86_ESP, 4);
127 * We store some local vars here to handle string pointers.
128 * and align to 16 byte boundary...
131 x86_alu_reg_imm (p, X86_SUB, X86_ESP, local_size * 4);
132 stack_size = (stack_size * local_size * 4) % 16;
134 stack_size = stack_size % 16;
137 x86_alu_reg_imm (p, X86_SUB, X86_ESP, stack_size);
140 * EDX has the pointer to the args.
142 x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4);
145 * Push arguments in reverse order.
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);
154 simpletype = sig->params [i - 1]->type;
156 switch (simpletype) {
157 case MONO_TYPE_BOOLEAN:
168 case MONO_TYPE_OBJECT:
169 x86_push_membase (p, X86_EDX, arg_pos);
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);
176 case MONO_TYPE_CLASS:
177 x86_push_membase (p, X86_EDX, arg_pos);
179 case MONO_TYPE_SZARRAY:
180 x86_push_membase (p, X86_EDX, arg_pos);
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);
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);
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);
204 /* it's an enum value */
205 simpletype = sig->params [i - 1]->data.klass->enum_basetype->type;
209 case MONO_TYPE_STRING:
210 x86_push_membase (p, X86_EDX, arg_pos);
215 x86_push_membase (p, X86_EDX, arg_pos + 4);
216 x86_push_membase (p, X86_EDX, arg_pos);
219 g_error ("Can't trampoline 0x%x", sig->params [i - 1]->type);
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);
228 x86_mov_reg_membase (p, X86_ECX, X86_EBP, THIS_POS, 4);
233 * Insert call to function
235 x86_mov_reg_membase (p, X86_EDX, X86_EBP, FUNC_ADDR_POS, 4);
236 x86_call_reg (p, X86_EDX);
240 * Small integer and pointer values are in EAX.
241 * Long integers are in EAX:EDX.
242 * FP values are on the FP stack.
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);
249 simpletype = sig->ret->type;
251 switch (simpletype) {
252 case MONO_TYPE_BOOLEAN:
255 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
256 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 1);
261 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
262 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 2);
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);
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);
280 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
281 x86_fst_membase (p, X86_ECX, 0, FALSE, TRUE);
284 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
285 x86_fst_membase (p, X86_ECX, 0, TRUE, TRUE);
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);
292 case MONO_TYPE_VALUETYPE:
293 if (sig->ret->data.klass->enumtype) {
294 simpletype = sig->ret->data.klass->enum_basetype->type;
300 g_error ("Can't handle as return value 0x%x", sig->ret->type);
310 g_assert (p - code_buffer < code_size);
311 res = (MonoPIFunc)g_memdup (code_buffer, p - code_buffer);
313 g_hash_table_insert (cache, sig, res);
318 #define MINV_POS (- sizeof (MonoInvocation))
319 #define STACK_POS (MINV_POS - sizeof (stackval) * sig->param_count)
321 #define TYPE_OFFSET (G_STRUCT_OFFSET (stackval, type))
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.
334 mono_create_method_pointer (MonoMethod *method)
336 MonoMethodSignature *sig;
338 unsigned char *p, *code_buffer;
340 gint32 stackval_pos, arg_pos = 8;
341 int i, size, align, cpos;
342 int vtbuf [sig->param_count];
345 * If it is a static P/Invoke method, we can just return the pointer
346 * to the method implementation.
348 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL && method->addr) {
349 ji = g_new0 (MonoJitInfo, 1);
352 ji->code_start = method->addr;
354 mono_jit_info_table_add (mono_root_domain, ji);
358 sig = method->signature;
360 code_buffer = p = alloca (512); /* FIXME: check for overflows... */
362 local_size = sizeof (MonoInvocation) + sizeof (stackval) * (sig->param_count + 1);
367 stackval_pos = -local_size;
370 for (i = 0; i < sig->param_count; i++) {
371 MonoType *type = sig->params [i];
373 if (type->type == MONO_TYPE_VALUETYPE) {
374 MonoClass *klass = type->data.klass;
377 size = mono_class_native_size (klass, &align);
379 cpos &= ~(align - 1);
391 * Standard function prolog.
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);
398 * Initialize MonoInvocation fields, first the ones known now.
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);
406 * Set the method pointer.
408 x86_mov_membase_imm (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, method)), (int)method, 4);
413 if (sig->call_convention != MONO_CALL_THISCALL) {
415 * Grab it from the stack, otherwise it's already in ECX.
417 x86_mov_reg_membase (p, X86_ECX, X86_EBP, OBJ_POS, 4);
420 x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)), X86_ECX, 4);
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....
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);
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);
445 arg_pos += mono_type_native_stack_size (sig->params [i], &align);
447 arg_pos += mono_type_stack_size (sig->params [i], &align);
451 * Handle the return value storage area.
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);
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);
465 * Move the return value to the proper place.
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);
471 int simpletype = sig->ret->type;
473 switch (sig->ret->type) {
476 case MONO_TYPE_BOOLEAN:
477 x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 1);
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);
489 x86_mov_reg_membase (p, X86_EDX, X86_EAX, 4, 4);
490 x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
493 x86_fld_membase (p, X86_EAX, 0, TRUE);
495 case MONO_TYPE_VALUETYPE:
496 if (sig->ret->data.klass->enumtype) {
497 simpletype = sig->ret->data.klass->enum_basetype->type;
503 g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type);
514 g_assert (p - code_buffer < 512);
516 ji = g_new0 (MonoJitInfo, 1);
518 ji->code_size = p - code_buffer;
519 ji->code_start = g_memdup (code_buffer, p - code_buffer);
521 mono_jit_info_table_add (mono_root_domain, ji);
523 return ji->code_start;