Fri Sep 7 18:43:06 CEST 2001 Paolo Molaro <lupus@ximian.com>
authorPaolo Molaro <lupus@oddwiz.org>
Fri, 7 Sep 2001 12:53:34 +0000 (12:53 -0000)
committerPaolo Molaro <lupus@oddwiz.org>
Fri, 7 Sep 2001 12:53:34 +0000 (12:53 -0000)
* x86/x86-codegen.h: fixes and x86_mov_membase_imm ().
* x86/tramp.c: implemented mono_create_method_pointer ():
creates a native pointer to a method implementation that can be
used as a normal C callback.

Fri Sep 7 18:45:38 CEST 2001 Paolo Molaro <lupus@ximian.com>

* interp.c, interp.h: make ves_exec_method () and stackval_from_data ()
non static. Implement a couple of runtime methods needed to
use delegates (ves_runtime_method ()).
Implemented ldftn opcode.

svn path=/trunk/mono/; revision=745

mono/arch/ChangeLog
mono/arch/x86/tramp.c
mono/arch/x86/x86-codegen.h
mono/interpreter/ChangeLog
mono/interpreter/interp.c
mono/interpreter/interp.h

index cbcda7488fbd207a59d0a04d0a37dbccf38448ca..4f1f55a8df3d499cee184911468961c9eda42b61 100644 (file)
@@ -1,4 +1,11 @@
 
+Fri Sep 7 18:43:06 CEST 2001 Paolo Molaro <lupus@ximian.com>
+
+       * x86/x86-codegen.h: fixes and x86_mov_membase_imm ().
+       * x86/tramp.c: implemented mono_create_method_pointer ():
+       creates a native pointer to a method implementation that can be 
+       used as a normal C callback.
+
 Thu Sep 6 15:38:00 CEST 2001 Paolo Molaro <lupus@ximian.com>
 
        * x86/x86-codegen.h: added x86_rdtsc() and fixes.
index e655c18e50da95107813a564417e8a90f9606c21..5641a4712df179c9c5237c75e7752bfe92f2b90c 100644 (file)
@@ -122,14 +122,15 @@ mono_create_trampoline (MonoMethod *method)
        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)
+       if (local_size) {
                x86_alu_reg_imm (p, X86_SUB, X86_ESP, local_size * 4);
-
-       /*
-        * We'll need to align to at least 8 bytes boudary... (16 may be better)
-        * x86_alu_reg_imm (p, X86_SUB, X86_ESP, stack_size);
-        */
+               stack_size = (stack_size * local_size * 4) % 16;
+       } else {
+               stack_size = stack_size % 16;
+       }
+       x86_alu_reg_imm (p, X86_SUB, X86_ESP, stack_size);
 
        /*
         * EDX has the pointer to the args.
@@ -147,6 +148,10 @@ mono_create_trampoline (MonoMethod *method)
                        continue;
                }
                switch (sig->params [i - 1]->type) {
+               case MONO_TYPE_I1:
+               case MONO_TYPE_U1:
+               case MONO_TYPE_I2:
+               case MONO_TYPE_U2:
                case MONO_TYPE_I4:
                case MONO_TYPE_U4:
                case MONO_TYPE_I:
@@ -186,10 +191,6 @@ mono_create_trampoline (MonoMethod *method)
                        break;
                case MONO_TYPE_BOOLEAN:
                case MONO_TYPE_CHAR:
-               case MONO_TYPE_I1:
-               case MONO_TYPE_U1:
-               case MONO_TYPE_I2:
-               case MONO_TYPE_U2:
                default:
                        g_error ("Can't trampoline 0x%x", sig->params [i - 1]->type);
                }
@@ -226,6 +227,7 @@ mono_create_trampoline (MonoMethod *method)
                case MONO_TYPE_I:
                case MONO_TYPE_U:
                case MONO_TYPE_OBJECT:
+               case MONO_TYPE_STRING: /* this is going to cause large pains... */
                        x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
                        x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
                        break;
@@ -267,3 +269,161 @@ mono_create_trampoline (MonoMethod *method)
        return g_memdup (code_buffer, p - code_buffer);
 }
 
+#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))
+
+/*
+ * Returns a pointer to a native function that can be used to
+ * call the specified method.
+ * The function created will receive the arguments according
+ * to the call convention specified in the method.
+ * This function works by creating a MonoInvocation structure,
+ * filling the fields in and calling ves_exec_method on it.
+ * Still need to figure out how to handle the exception stuff
+ * across the managed/unmanaged boundary.
+ */
+void *
+mono_create_method_pointer (MonoMethod *method)
+{
+       MonoMethodSignature *sig;
+       unsigned char *p, *code_buffer;
+       gint32 local_size;
+       gint32 stackval_pos, arg_pos = 8;
+       int i;
+
+       /*
+        * If it is a static P/Invoke method, we can just return the pointer
+        * to the method implementation.
+        */
+       sig = method->signature;
+
+       code_buffer = p = alloca (512); /* FIXME: check for overflows... */
+
+       local_size = sizeof (MonoInvocation) + sizeof (stackval) * (sig->param_count + 1);
+       stackval_pos = -local_size;
+
+       /*
+        * Standard function prolog with magic trick.
+        */
+       x86_jump_code (p, code_buffer + 8);
+       *p++ = 'M';
+       *p++ = 'o';
+       *(void**)p = method;
+       p += 4;
+       x86_push_reg (p, X86_EBP);
+       x86_mov_reg_reg (p, X86_EBP, X86_ESP, 4);
+       x86_alu_reg_imm (p, X86_SUB, X86_ESP, local_size);
+
+       /*
+        * Initialize MonoInvocation fields, first the ones known now.
+        */
+       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);
+
+       /*
+        * Handle this.
+        */
+       if (sig->hasthis) {
+               if (sig->call_convention != MONO_CALL_THISCALL) {
+                       /*
+                        * Grab it from the stack, otherwise it's already in ECX.
+                        */
+                       x86_mov_reg_membase (p, X86_ECX, X86_EBP, OBJ_POS, 4);
+                       arg_pos += 4;
+               }
+               x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)), X86_ECX, 4);
+       }
+       /*
+        * Handle the arguments. stackval_pos is the posset of the stackval array from EBP.
+        * arg_pos is the offset from EBP to the incoming arg on the stack.
+        * We just call stackval_from_data to handle all the (nasty) issues....
+        */
+       for (i = 0; i < sig->param_count; ++i) {
+               x86_mov_reg_imm (p, X86_ECX, stackval_from_data);
+               x86_lea_membase (p, X86_EDX, X86_EBP, arg_pos);
+               x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
+               x86_push_reg (p, X86_EDX);
+               x86_push_reg (p, X86_EAX);
+               x86_push_imm (p, sig->params [i]);
+               x86_call_reg (p, X86_ECX);
+               x86_alu_reg_imm (p, X86_SUB, X86_ESP, 12);
+               stackval_pos += sizeof (stackval);
+               arg_pos += 4;
+               if (!sig->params [i]->byref) {
+                       switch (sig->params [i]->type) {
+                       case MONO_TYPE_I8:
+                       case MONO_TYPE_R8:
+                               arg_pos += 4;
+                               break;
+                       case MONO_TYPE_VALUETYPE:
+                               g_assert_not_reached (); /* Not implemented yet. */
+                       default:
+                               break;
+                       }
+               }
+       }
+
+       /*
+        * Handle the return value storage area.
+        */
+       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);
+
+       /*
+        * Call the method.
+        */
+       x86_lea_membase (p, X86_EAX, X86_EBP, MINV_POS);
+       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.
+        */
+       x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
+       if (sig->ret->byref) {
+               x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
+       } else {
+               switch (sig->ret->type) {
+               case MONO_TYPE_VOID:
+                       break;
+               case MONO_TYPE_I4:
+               case MONO_TYPE_U4:
+               case MONO_TYPE_I:
+               case MONO_TYPE_U:
+               case MONO_TYPE_OBJECT:
+               case MONO_TYPE_STRING:
+                       x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
+                       break;
+               case MONO_TYPE_I8:
+                       x86_mov_reg_membase (p, X86_EDX, X86_EAX, 4, 4);
+                       x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
+                       break;
+               case MONO_TYPE_R8:
+                       x86_fld_membase (p, X86_EAX, 0, TRUE);
+                       break;
+               default:
+                       g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type);
+                       break;
+               }
+       }
+       
+       /*
+        * Standard epilog.
+        */
+       x86_leave (p);
+       x86_ret (p);
+
+       return g_memdup (code_buffer, p - code_buffer);
+}
+
+
index d320f41bde36e88f32eba6d8b50f0e7def8ddb4b..4051c7f8cbea741f5809a1a28154ad2fe8dd2544 100644 (file)
@@ -1,7 +1,7 @@
 /* Copyright (C)  2000 Intel Corporation.  All rights reserved.
    Copyright (C)  2001 Ximian, Inc. 
 //
-// $Header: /home/miguel/third-conversion/public/mono/mono/arch/x86/x86-codegen.h,v 1.6 2001/09/06 09:46:03 lupus Exp $
+// $Header: /home/miguel/third-conversion/public/mono/mono/arch/x86/x86-codegen.h,v 1.7 2001/09/07 12:53:34 lupus Exp $
 */
 
 #ifndef X86_H
@@ -737,6 +737,24 @@ typedef union {
                }       \
        } while (0)
 
+#define x86_mov_membase_imm(inst,basereg,disp,imm,size)        \
+       do {    \
+               if ((size) == 1) {      \
+                       *(inst)++ = (unsigned char)0xc6;        \
+                       x86_membase_emit ((inst), 0, (basereg), (disp));        \
+                       x86_imm_emit8 ((inst), (imm));  \
+               } else if ((size) == 2) {       \
+                       *(inst)++ = (unsigned char)0x66;        \
+                       *(inst)++ = (unsigned char)0xc7;        \
+                       x86_membase_emit ((inst), 0, (basereg), (disp));        \
+                       x86_imm_emit16 ((inst), (imm)); \
+               } else {        \
+                       *(inst)++ = (unsigned char)0xc7;        \
+                       x86_membase_emit ((inst), 0, (basereg), (disp));        \
+                       x86_imm_emit32 ((inst), (imm)); \
+               }       \
+       } while (0)
+
 #define x86_lea_mem(inst,reg,mem)      \
        do {    \
                *(inst)++ = (unsigned char)0x8d;        \
@@ -766,7 +784,7 @@ typedef union {
                if ((is_signed)) op += 0x08;    \
                if ((is_half)) op += 0x01;      \
                *(inst)++ = op; \
-               x86_mem_emit ((inst), (reg), (mem));    \
+               x86_mem_emit ((inst), (dreg), (mem));   \
        } while (0)
 
 #define x86_widen_membase(inst,dreg,basereg,disp,is_signed,is_half)    \
@@ -776,7 +794,7 @@ typedef union {
                if ((is_signed)) op += 0x08;    \
                if ((is_half)) op += 0x01;      \
                *(inst)++ = op; \
-               x86_membase_emit ((inst), (reg), (basereg), (disp));    \
+               x86_membase_emit ((inst), (dreg), (basereg), (disp));   \
        } while (0)
 
 #define x86_cdq(inst)  do { *(inst)++ = (unsigned char)0x99; } while (0)
index 7fc3be7e43e6ead40c781c0664979ed974e88170..b4e04955e554797d512c45b0722a8a2d51f9136c 100644 (file)
@@ -1,4 +1,11 @@
 
+Fri Sep 7 18:45:38 CEST 2001 Paolo Molaro <lupus@ximian.com>
+
+       * interp.c, interp.h: make ves_exec_method () and stackval_from_data ()
+       non static. Implement a couple of runtime methods needed to
+       use delegates (ves_runtime_method ()).
+       Implemented ldftn opcode.
+
 Thu Sep 6 15:41:24 CEST 2001 Paolo Molaro <lupus@ximian.com>
 
        * Makefile.am: link to libmonoarch.
index 39f1738ddfd3b9cbc402ec5626931b21bc20df57..dd1a286b55caf142c1495296e0e0561e2ff221c9 100644 (file)
@@ -80,7 +80,7 @@ static char *opcode_names[] = {
                (frame)->child = NULL;  \
        } while (0)
 
-static void ves_exec_method (MonoInvocation *frame);
+void ves_exec_method (MonoInvocation *frame);
 
 typedef void (*ICallMethod) (MonoInvocation *frame);
 
@@ -351,7 +351,7 @@ get_exception_invalid_cast ()
        return ex;
 }
 
-static void inline
+void inline
 stackval_from_data (MonoType *type, stackval *result, const char *data)
 {
        if (type->byref) {
@@ -450,6 +450,7 @@ stackval_to_data (MonoType *type, stackval *val, char *data)
                return;
        case MONO_TYPE_I2:
        case MONO_TYPE_U2:
+       case MONO_TYPE_CHAR:
                *(guint16*)data = val->data.i;
                return;
        case MONO_TYPE_I: /* FIXME: not 64 bit clean */
@@ -561,6 +562,43 @@ ves_pinvoke_method (MonoInvocation *frame)
        g_free (func);
 }
 
+/*
+ * This is a hack, you don't want to see the code in this function. Go away.
+ *
+ * We need a way to easily find the offset in an object of a field we may be
+ * interested in: it's needed here and in several other code where the C#
+ * implementation is highly tied to the internals (Array and String are other good 
+ * examples).
+ */
+static void
+ves_runtime_method (MonoInvocation *frame)
+{
+       const char *name = frame->method->name;
+       MonoObject *obj = frame->obj;
+       
+       if (*name == '.' && (strcmp (name, ".ctor") == 0) && obj &&
+                       mono_object_isinst (obj, mono_defaults.delegate_class)) {
+               /* 
+                * FIXME: query the offsets at runtime. 
+                */
+               *(gpointer*)(((char*)obj) + sizeof (MonoObject) + 4) = frame->stack_args[0].data.p;
+               *(gpointer*)(((char*)obj) + sizeof (MonoObject) + 12) = frame->stack_args[1].data.p;
+               return;
+       }
+       if (*name == 'I' && (strcmp (name, "Invoke") == 0) && obj &&
+                       mono_object_isinst (obj, mono_defaults.delegate_class)) {
+               MonoPIFunc func = mono_create_trampoline (frame->method);
+               void* faddr = *(gpointer*)(((char*)obj) + sizeof (MonoObject) + 12);
+               func (faddr, &frame->retval->data.p, frame->obj, frame->stack_args);
+               stackval_from_data (frame->method->signature->ret, frame->retval, (const char*)&frame->retval->data.p);
+               g_free (func);
+               return;
+       }
+       g_error ("Don't know how to exec runtime method %s.%s::%s", 
+                       frame->method->klass->name_space, frame->method->klass->name,
+                       frame->method->name);
+}
+
 static void
 dump_stack (stackval *stack, stackval *sp)
 {
@@ -676,7 +714,7 @@ struct _vtallocation {
  * duplication.
  * 
  */
-static void 
+void 
 ves_exec_method (MonoInvocation *frame)
 {
        MonoInvocation child_frame;
@@ -715,7 +753,13 @@ ves_exec_method (MonoInvocation *frame)
                DEBUG_LEAVE ();
                return;
        } 
-               
+
+       if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
+               ves_runtime_method (frame);
+               DEBUG_LEAVE ();
+               return;
+       } 
+
        header = ((MonoMethodNormal *)frame->method)->header;
        signature = frame->method->signature;
        image = frame->method->klass->image;
@@ -2459,7 +2503,17 @@ ves_exec_method (MonoInvocation *frame)
                                break;
                        }
                        case CEE_CLT_UN: ves_abort(); break;
-                       case CEE_LDFTN: ves_abort(); break;
+                       case CEE_LDFTN: {
+                               guint32 token;
+                               ++ip;
+                               token = read32 (ip);
+                               ip += 4;
+                               sp->type = VAL_NATI;
+                               sp->data.p = mono_create_method_pointer (mono_get_method (image, token, NULL));
+                               sp->data.vt.klass = NULL;
+                               ++sp;
+                               break;
+                       }
                        case CEE_LDVIRTFTN: ves_abort(); break;
                        case CEE_UNUSED56: ves_abort(); break;
                        case CEE_LDARG: {
index 4fd6bfe66c3fc1d142a98593a0492d8101ec4758..087e2d8950aa0333256aa7150860b9454913240d 100644 (file)
@@ -57,6 +57,9 @@ struct _MonoInvocation {
 
 void mono_init_icall (void);
 
+void inline stackval_from_data (MonoType *type, stackval *result, const char *data);
+void ves_exec_method (MonoInvocation *frame);
+
 typedef void (*MonoFunc) ();
 typedef void (*MonoPIFunc) (MonoFunc callme, void *retval, void *obj_this, stackval *arguments);
 
@@ -64,3 +67,5 @@ typedef void (*MonoPIFunc) (MonoFunc callme, void *retval, void *obj_this, stack
  * defined in an arch specific file.
  */
 MonoPIFunc mono_create_trampoline (MonoMethod *method);
+void *mono_create_method_pointer (MonoMethod *method);
+