2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / arch / x86 / tramp.c
index f9d8658d59f46f97e5e50da31b110eb5e8847ca3..fab5a55325fa8ff4d140b51a8959f44f1ab714ad 100644 (file)
@@ -3,7 +3,9 @@
  * 
  * Copyright (C) Ximian Inc.
  * 
- * Author: Paolo Molaro (lupus@ximian.com)
+ * Authors: 
+ *   Paolo Molaro (lupus@ximian.com)
+ *   Dietmar Maurer (dietmar@ximian.com)
  * 
  */
 
 #define ARG_SIZE       sizeof (stackval)
 
 MonoPIFunc
-mono_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor)
+mono_arch_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor)
 {
        unsigned char *p, *code_buffer;
-       guint32 local_size = 0, stack_size = 0, code_size = 50;
+       guint32 stack_size = 0, code_size = 50;
        guint32 arg_pos, simpletype;
        int i, stringp;
        static GHashTable *cache = NULL;
@@ -48,14 +50,18 @@ mono_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor)
 
        if (sig->hasthis) {
                stack_size += sizeof (gpointer);
-               code_size += 5;
+               code_size += 10;
        }
        
+       if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref && !sig->ret->data.klass->enumtype) {
+               stack_size += sizeof (gpointer);
+               code_size += 5;
+       }
+
        for (i = 0; i < sig->param_count; ++i) {
                if (sig->params [i]->byref) {
                        stack_size += sizeof (gpointer);
                        code_size += 20;
-                       local_size++;
                        continue;
                }
                simpletype = sig->params [i]->type;
@@ -72,10 +78,10 @@ enum_calc_size:
                case MONO_TYPE_I:
                case MONO_TYPE_U:
                case MONO_TYPE_PTR:
-               case MONO_TYPE_R4:
                case MONO_TYPE_SZARRAY:
                case MONO_TYPE_CLASS:
                case MONO_TYPE_OBJECT:
+               case MONO_TYPE_STRING:
                        stack_size += 4;
                        code_size += i < 10 ? 5 : 8;
                        break;
@@ -85,7 +91,7 @@ enum_calc_size:
                                simpletype = sig->params [i]->data.klass->enum_basetype->type;
                                goto enum_calc_size;
                        }
-                       if ((size = mono_class_value_size (sig->params [i]->data.klass, NULL)) != 4) {
+                       if ((size = mono_class_native_size (sig->params [i]->data.klass, NULL)) != 4) {
                                stack_size += size + 3;
                                stack_size &= ~3;
                                code_size += 32;
@@ -95,15 +101,14 @@ enum_calc_size:
                        }
                        break;
                }
-               case MONO_TYPE_STRING:
-                       stack_size += 4;
-                       code_size += 20;
-                       local_size++;
-                       break;
                case MONO_TYPE_I8:
                        stack_size += 8;
                        code_size += i < 10 ? 5 : 8;
                        break;
+               case MONO_TYPE_R4:
+                       stack_size += 4;
+                       code_size += i < 10 ? 10 : 13;
+                       break;
                case MONO_TYPE_R8:
                        stack_size += 8;
                        code_size += i < 10 ? 7 : 10;
@@ -124,15 +129,11 @@ enum_calc_size:
        x86_push_reg (p, X86_EBP);
        x86_mov_reg_reg (p, X86_EBP, X86_ESP, 4);
        /*
-        * We store some local vars here to handle string pointers.
         * and align to 16 byte boundary...
         */
-       if (local_size) {
-               x86_alu_reg_imm (p, X86_SUB, X86_ESP, local_size * 4);
-               stack_size = (stack_size * local_size * 4) % 16;
-       } else {
-               stack_size = stack_size % 16;
-       }
+       stack_size += 15;
+       stack_size &= ~15;
+
        if (stack_size)
                x86_alu_reg_imm (p, X86_SUB, X86_ESP, stack_size);
 
@@ -166,6 +167,7 @@ enum_marshal:
                case MONO_TYPE_U:
                case MONO_TYPE_PTR:
                case MONO_TYPE_OBJECT:
+               case MONO_TYPE_STRING:
                        x86_push_membase (p, X86_EDX, arg_pos);
                        break;
                case MONO_TYPE_R4:
@@ -181,7 +183,7 @@ enum_marshal:
                        break;
                case MONO_TYPE_VALUETYPE:
                        if (!sig->params [i - 1]->data.klass->enumtype) {
-                               int size = mono_class_value_size (sig->params [i - 1]->data.klass, NULL);
+                               int size = mono_class_native_size (sig->params [i - 1]->data.klass, NULL);
                                if (size == 4) {
                                        /* it's a structure that fits in 4 bytes, need to push the value pointed to */
                                        x86_mov_reg_membase (p, X86_EAX, X86_EDX, arg_pos, 4);
@@ -199,6 +201,8 @@ enum_marshal:
                                        x86_mov_reg_imm (p, X86_EAX, memcpy);
                                        x86_call_reg (p, X86_EAX);
                                        x86_alu_reg_imm (p, X86_ADD, X86_ESP, 12);
+                                       /* memcpy might clobber EDX so restore it */
+                                       x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4);
                                }
                        } else {
                                /* it's an enum value */
@@ -206,9 +210,6 @@ enum_marshal:
                                goto enum_marshal;
                        }
                        break;
-               case MONO_TYPE_STRING:
-                       x86_push_membase (p, X86_EDX, arg_pos);
-                       break;
                case MONO_TYPE_I8:
                case MONO_TYPE_U8:
                case MONO_TYPE_R8:
@@ -229,6 +230,14 @@ enum_marshal:
                }
        }
 
+       if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref) {
+               MonoClass *klass = sig->ret->data.klass;
+               if (!klass->enumtype) {
+                       x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
+                       x86_push_membase (p, X86_ECX, 0);
+               }
+       }
+
        /* 
         * Insert call to function 
         */
@@ -317,7 +326,6 @@ enum_marshal:
 
 #define MINV_POS  (- sizeof (MonoInvocation))
 #define STACK_POS (MINV_POS - sizeof (stackval) * sig->param_count)
-#define OBJ_POS   8
 #define TYPE_OFFSET (G_STRUCT_OFFSET (stackval, type))
 
 /*
@@ -331,7 +339,7 @@ enum_marshal:
  * across the managed/unmanaged boundary.
  */
 void *
-mono_create_method_pointer (MonoMethod *method)
+mono_arch_create_method_pointer (MonoMethod *method)
 {
        MonoMethodSignature *sig;
        MonoJitInfo *ji;
@@ -339,25 +347,12 @@ mono_create_method_pointer (MonoMethod *method)
        gint32 local_size;
        gint32 stackval_pos, arg_pos = 8;
        int i, size, align, cpos;
-       int vtbuf [sig->param_count];
-
-       /*
-        * If it is a static P/Invoke method, we can just return the pointer
-        * to the method implementation.
-        */
-       if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL && method->addr) {
-               ji = g_new0 (MonoJitInfo, 1);
-               ji->method = method;
-               ji->code_size = 1;
-               ji->code_start = method->addr;
-
-               mono_jit_info_table_add (mono_root_domain, ji);
-               return method->addr;
-       }
+       int *vtbuf;
 
        sig = method->signature;
 
        code_buffer = p = alloca (512); /* FIXME: check for overflows... */
+       vtbuf = alloca (sizeof(int)*sig->param_count);
 
        local_size = sizeof (MonoInvocation) + sizeof (stackval) * (sig->param_count + 1);
 
@@ -400,12 +395,15 @@ mono_create_method_pointer (MonoMethod *method)
        x86_mov_reg_imm (p, X86_EAX, 0);
        x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex)), X86_EAX, 4);
        x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex_handler)), X86_EAX, 4);
-       x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, child)), X86_EAX, 4);
        x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, parent)), X86_EAX, 4);
        /*
         * Set the method pointer.
         */
        x86_mov_membase_imm (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, method)), (int)method, 4);
+
+       if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref && !sig->ret->data.klass->enumtype) 
+               arg_pos += 4;
+
        /*
         * Handle this.
         */
@@ -414,7 +412,7 @@ mono_create_method_pointer (MonoMethod *method)
                        /*
                         * Grab it from the stack, otherwise it's already in ECX.
                         */
-                       x86_mov_reg_membase (p, X86_ECX, X86_EBP, OBJ_POS, 4);
+                       x86_mov_reg_membase (p, X86_ECX, X86_EBP, arg_pos, 4);
                        arg_pos += 4;
                }
                x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)), X86_ECX, 4);
@@ -441,6 +439,7 @@ mono_create_method_pointer (MonoMethod *method)
                x86_call_reg (p, X86_ECX);
                x86_alu_reg_imm (p, X86_SUB, X86_ESP, 16);
                stackval_pos += sizeof (stackval);
+               /* fixme: alignment */
                if (sig->pinvoke)
                        arg_pos += mono_type_native_stack_size (sig->params [i], &align);
                else
@@ -452,6 +451,13 @@ mono_create_method_pointer (MonoMethod *method)
         */
        x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
        x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)), X86_EAX, 4);
+       if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref) {
+               MonoClass *klass  = sig->ret->data.klass;
+               if (!klass->enumtype) {
+                       x86_mov_reg_membase (p, X86_ECX, X86_EBP, 8, 4);
+                       x86_mov_membase_reg (p, X86_EBP, stackval_pos, X86_ECX, 4);
+               }
+       }
 
        /*
         * Call the method.
@@ -460,7 +466,7 @@ mono_create_method_pointer (MonoMethod *method)
        x86_push_reg (p, X86_EAX);
        x86_mov_reg_imm (p, X86_EDX, ves_exec_method);
        x86_call_reg (p, X86_EDX);
-
+       
        /*
         * Move the return value to the proper place.
         */
@@ -474,8 +480,15 @@ mono_create_method_pointer (MonoMethod *method)
                case MONO_TYPE_VOID:
                        break;
                case MONO_TYPE_BOOLEAN:
+               case MONO_TYPE_I1:
+               case MONO_TYPE_U1:
                        x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 1);
                        break;
+               case MONO_TYPE_CHAR:
+               case MONO_TYPE_I2:
+               case MONO_TYPE_U2:
+                       x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 2);
+                       break;
                case MONO_TYPE_I4:
                case MONO_TYPE_U4:
                case MONO_TYPE_I:
@@ -497,7 +510,15 @@ mono_create_method_pointer (MonoMethod *method)
                                simpletype = sig->ret->data.klass->enum_basetype->type;
                                goto enum_retvalue;
                        }
-                       /* do nothing ? */
+               
+                       x86_push_imm (p, sig->pinvoke);
+                       x86_push_membase (p, X86_EBP, stackval_pos);
+                       x86_push_reg (p, X86_EAX);
+                       x86_push_imm (p, sig->ret);
+                       x86_mov_reg_imm (p, X86_ECX, stackval_to_data);
+                       x86_call_reg (p, X86_ECX);
+                       x86_alu_reg_imm (p, X86_SUB, X86_ESP, 16);
+                       
                        break;
                default:
                        g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type);
@@ -518,7 +539,7 @@ mono_create_method_pointer (MonoMethod *method)
        ji->code_size = p - code_buffer;
        ji->code_start = g_memdup (code_buffer, p - code_buffer);
 
-       mono_jit_info_table_add (mono_root_domain, ji);
+       mono_jit_info_table_add (mono_get_root_domain (), ji);
 
        return ji->code_start;
 }