2008-10-31 Gonzalo Paniagua Javier <gonzalo@novell.com>
[mono.git] / mono / metadata / marshal.c
index 3ff2d1263a7a3641f25674d2770b8fa314000b23..22a160bd2c3c5b78651aaaa83b7fd76da5347eeb 100644 (file)
@@ -188,8 +188,8 @@ signature_dup (MonoImage *image, MonoMethodSignature *sig)
        return res;
 }
 
-static MonoMethodSignature*
-signature_no_pinvoke (MonoMethod *method)
+MonoMethodSignature*
+mono_signature_no_pinvoke (MonoMethod *method)
 {
        MonoMethodSignature *sig = mono_method_signature (method);
        if (sig->pinvoke) {
@@ -2950,7 +2950,7 @@ mono_marshal_get_delegate_begin_invoke (MonoMethod *method)
        g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
                  !strcmp (method->name, "BeginInvoke"));
 
-       sig = signature_no_pinvoke (method);
+       sig = mono_signature_no_pinvoke (method);
 
        cache = get_cache (&method->klass->image->delegate_begin_invoke_cache,
                                           (GHashFunc)mono_signature_hash, 
@@ -3003,7 +3003,7 @@ mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
        method = mono_class_get_method_from_name (klass, "EndInvoke", -1);
        g_assert (method != NULL);
 
-       sig = signature_no_pinvoke (method);
+       sig = mono_signature_no_pinvoke (method);
 
        msg = mono_method_call_message_new (method, params, NULL, NULL, NULL);
 
@@ -3112,7 +3112,7 @@ mono_marshal_get_delegate_end_invoke (MonoMethod *method)
        g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
                  !strcmp (method->name, "EndInvoke"));
 
-       sig = signature_no_pinvoke (method);
+       sig = mono_signature_no_pinvoke (method);
 
        cache = get_cache (&method->klass->image->delegate_end_invoke_cache,
                                           (GHashFunc)mono_signature_hash, 
@@ -3430,7 +3430,7 @@ cominterop_get_invoke (MonoMethod *method)
        if ((res = mono_marshal_find_in_cache (cache, method)))
                return res;
 
-       sig = signature_no_pinvoke (method);
+       sig = mono_signature_no_pinvoke (method);
 
        /* we cant remote methods without this pointer */
        if (!sig->hasthis)
@@ -3533,7 +3533,7 @@ mono_marshal_get_remoting_invoke (MonoMethod *method)
 #endif
        }
 
-       sig = signature_no_pinvoke (method);
+       sig = mono_signature_no_pinvoke (method);
 
        /* we cant remote methods without this pointer */
        if (!sig->hasthis)
@@ -4085,7 +4085,7 @@ mono_marshal_get_xappdomain_invoke (MonoMethod *method)
        if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_XDOMAIN_INVOKE)))
                return res;
        
-       sig = signature_no_pinvoke (method);
+       sig = mono_signature_no_pinvoke (method);
 
        mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_XDOMAIN_INVOKE);
        mb->method->save_lmf = 1;
@@ -4418,7 +4418,7 @@ mono_marshal_get_remoting_invoke_with_check (MonoMethod *method)
        if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)))
                return res;
 
-       sig = signature_no_pinvoke (method);
+       sig = mono_signature_no_pinvoke (method);
        
        mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK);
 
@@ -4524,7 +4524,7 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del)
        g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
                  !strcmp (method->name, "Invoke"));
                
-       sig = signature_no_pinvoke (method);
+       sig = mono_signature_no_pinvoke (method);
 
        if (callvirt) {
                /* We need to cache the signature+method pair */
@@ -4739,9 +4739,12 @@ add_string_ctor_signature (MonoMethod *method)
        return callsig;
 }
 
-static inline MonoType*
-get_basic_type (MonoType *t)
+static MonoType*
+get_runtime_invoke_type (MonoType *t)
 {
+       if (t->byref)
+               return &mono_defaults.int_class->byval_arg;
+
        switch (t->type) {
        case MONO_TYPE_U1:
                return &mono_defaults.sbyte_class->byval_arg;
@@ -4763,96 +4766,38 @@ get_basic_type (MonoType *t)
                else
                        return t;
        default:
+               if (MONO_TYPE_IS_REFERENCE (t))
+                       return &mono_defaults.object_class->byval_arg;
                return t;
        }
 }
 
-static inline gboolean
-runtime_invoke_type_equal (MonoType *t1, MonoType *t2)
-{
-       if (MONO_TYPE_IS_REFERENCE (t1) && MONO_TYPE_IS_REFERENCE (t2))
-               return TRUE;
-       else if (t1->byref != t2->byref)
-               return FALSE;
-       else if (t1->byref && t2->byref)
-               return TRUE;
-       else if (t1->type == MONO_TYPE_PTR && t2->type == MONO_TYPE_PTR)
-               return TRUE;
-       else {
-               t1 = get_basic_type (t1);
-               t2 = get_basic_type (t2);
-
-               return mono_metadata_type_equal (t1, t2);
-       }
-}
-
-static inline guint
-runtime_invoke_type_hash (MonoType *t1)
-{
-       if (MONO_TYPE_IS_REFERENCE (t1))
-               return 0;
-       else if (t1->byref)
-               return 1;
-       else if (t1->type == MONO_TYPE_PTR)
-               return 2;
-       else
-               return mono_metadata_type_hash (get_basic_type (t1));
-}
-
 /*
- * runtime_invoke_signature_equal:
+ * mono_marshal_get_runtime_invoke_sig:
  *
- *   Same as mono_metadata_signature_equal, but consider reference types equal.
+ *   Return a common signature used for sharing runtime invoke wrappers.
  */
-static gboolean
-runtime_invoke_signature_equal (MonoMethodSignature *sig1, MonoMethodSignature *sig2)
+static MonoMethodSignature*
+mono_marshal_get_runtime_invoke_sig (MonoMethodSignature *sig)
 {
+       MonoMethodSignature *res = mono_metadata_signature_dup (sig);
        int i;
 
-       if (sig1->hasthis != sig2->hasthis || sig1->param_count != sig2->param_count)
-               return FALSE;
-
-       if (sig1->generic_param_count != sig2->generic_param_count)
-               return FALSE;
-
-       /*
-        * We're just comparing the signatures of two methods here:
-        *
-        * If we have two generic methods `void Foo<U> (U u)' and `void Bar<V> (V v)',
-        * U and V are equal here.
-        *
-        * That's what the `signature_only' argument of do_mono_metadata_type_equal() is for.
-        */
-
-       for (i = 0; i < sig1->param_count; i++) { 
-               MonoType *p1 = sig1->params[i];
-               MonoType *p2 = sig2->params[i];
-               
-               /* if (p1->attrs != p2->attrs)
-                       return FALSE;
-               */
-               if (!runtime_invoke_type_equal (p1, p2))
-                       return FALSE;
-       }
+       res->ret = get_runtime_invoke_type (sig->ret);
+       for (i = 0; i < res->param_count; ++i)
+               res->params [i] = get_runtime_invoke_type (sig->params [i]);
 
-       /* Can't share wrappers which return a vtype since it needs to be boxed */
-       if (sig1->ret == sig2->ret)
-               return TRUE;
-       else if (MONO_TYPE_IS_REFERENCE (sig1->ret) && MONO_TYPE_IS_REFERENCE (sig2->ret))
-               return TRUE;
-       else
-               return FALSE;
+       return res;
 }
 
-static guint
-runtime_invoke_signature_hash (MonoMethodSignature *sig)
+static gboolean
+runtime_invoke_signature_equal (MonoMethodSignature *sig1, MonoMethodSignature *sig2)
 {
-       guint i, res = sig->ret->type;
-
-       for (i = 0; i < sig->param_count; i++)
-               res = (res << 5) - res + runtime_invoke_type_hash (sig->params[i]);
-
-       return res;
+       /* Can't share wrappers which return a vtype since it needs to be boxed */
+       if (sig1->ret != sig2->ret && !(MONO_TYPE_IS_REFERENCE (sig1->ret) && MONO_TYPE_IS_REFERENCE (sig2->ret)))
+               return FALSE;
+       else
+               return mono_metadata_signature_equal (sig1, sig2);
 }
 
 /*
@@ -4954,19 +4899,26 @@ mono_marshal_get_runtime_invoke (MonoMethod *method)
        if (need_direct_wrapper) {
                cache = get_cache (&target_klass->image->runtime_invoke_direct_cache, mono_aligned_addr_hash, NULL);
                res = mono_marshal_find_in_cache (cache, method);
+               if (res)
+                       return res;
        } else {
+               callsig = mono_marshal_get_runtime_invoke_sig (callsig);
+
                cache = get_cache (&target_klass->image->runtime_invoke_cache, 
-                                                  (GHashFunc)runtime_invoke_signature_hash, 
+                                                  (GHashFunc)mono_signature_hash, 
                                                   (GCompareFunc)runtime_invoke_signature_equal);
 
                /* from mono_marshal_find_in_cache */
                mono_marshal_lock ();
                res = g_hash_table_lookup (cache, callsig);
                mono_marshal_unlock ();
-       }
 
-       if (res) {
-               return res;
+               if (res) {
+                       g_free (callsig);
+                       return res;
+               }
+
+               // FIXME: When to free callsig ?
        }
        
        /* to make it work with our special string constructors */
@@ -9720,7 +9672,7 @@ mono_marshal_get_struct_to_ptr (MonoClass *klass)
 
        mono_mb_emit_byte (mb, CEE_RET);
 
-       res = mono_mb_create_method (mb, signature_no_pinvoke (stoptr), 0);
+       res = mono_mb_create_method (mb, mono_signature_no_pinvoke (stoptr), 0);
        mono_mb_free (mb);
 
        klass->marshal_info->str_to_ptr = res;
@@ -9804,7 +9756,7 @@ mono_marshal_get_ptr_to_struct (MonoClass *klass)
 MonoMethod *
 mono_marshal_get_synchronized_wrapper (MonoMethod *method)
 {
-       static MonoMethod *enter_method, *exit_method;
+       static MonoMethod *enter_method, *exit_method, *gettypefromhandle_method;
        MonoMethodSignature *sig;
        MonoExceptionClause *clause;
        MonoMethodHeader *header;
@@ -9864,21 +9816,27 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method)
                enter_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
                g_assert (enter_method);
                mono_method_desc_free (desc);
+
                desc = mono_method_desc_new ("Monitor:Exit", FALSE);
                exit_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
                g_assert (exit_method);
                mono_method_desc_free (desc);
+
+               desc = mono_method_desc_new ("Type:GetTypeFromHandle", FALSE);
+               gettypefromhandle_method = mono_method_desc_search_in_class (desc, mono_defaults.monotype_class->parent);
+               g_assert (gettypefromhandle_method);
+               mono_method_desc_free (desc);
        }
 
        /* Push this or the type object */
        if (method->flags & METHOD_ATTRIBUTE_STATIC) {
-               /*
-                * GetTypeFromHandle isn't called as a managed method because it has
-                * a funky calling sequence, e.g. ldtoken+GetTypeFromHandle gets
-                * transformed into something else by the JIT.
-                */
-               mono_mb_emit_ptr (mb, &method->klass->byval_arg);
-               mono_mb_emit_icall (mb, type_from_handle);
+               /* We have special handling for this in the JIT */
+               int index = mono_mb_add_data (mb, method->klass);
+               mono_mb_add_data (mb, mono_defaults.typehandle_class);
+               mono_mb_emit_byte (mb, CEE_LDTOKEN);
+               mono_mb_emit_i4 (mb, index);
+
+               mono_mb_emit_managed_call (mb, gettypefromhandle_method, NULL);
        }
        else
                mono_mb_emit_ldarg (mb, 0);