Make nested type loading lazier.
[mono.git] / mono / metadata / marshal.c
index c664d129b41a7f26f4bc1b08814124e554214c16..2b66637c2bf6c5368ed6039407034fd3a918e68b 100644 (file)
@@ -164,7 +164,14 @@ register_icall (gpointer func, const char *name, const char *sigstr, gboolean sa
 static MonoMethodSignature*
 signature_dup (MonoImage *image, MonoMethodSignature *sig)
 {
-       return mono_metadata_signature_dup_full (image, sig);
+       MonoMethodSignature *res;
+       int sigsize;
+
+       res = mono_metadata_signature_alloc (image, sig->param_count);
+       sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
+       memcpy (res, sig, sigsize);
+
+       return res;
 }
 
 MonoMethodSignature*
@@ -564,10 +571,10 @@ mono_array_to_lparray (MonoArray *array)
        case MONO_TYPE_R4:
        case MONO_TYPE_R8:
        case MONO_TYPE_VALUETYPE:
+       case MONO_TYPE_PTR:
                /* nothing to do */
                break;
        case MONO_TYPE_GENERICINST:
-       case MONO_TYPE_PTR:
        case MONO_TYPE_OBJECT:
        case MONO_TYPE_ARRAY: 
        case MONO_TYPE_SZARRAY:
@@ -2276,15 +2283,13 @@ mono_marshal_need_free (MonoType *t, MonoMethodPInvoke *piinfo, MonoMarshalSpec
  * Return the hash table pointed to by VAR, lazily creating it if neccesary.
  */
 static GHashTable*
-get_cache_full (GHashTable **var, GHashFunc hash_func, GCompareFunc equal_func,
-                               GDestroyNotify  key_destroy_func,
-                               GDestroyNotify  value_destroy_func)
+get_cache (GHashTable **var, GHashFunc hash_func, GCompareFunc equal_func)
 {
        if (!(*var)) {
                mono_marshal_lock ();
                if (!(*var)) {
                        GHashTable *cache = 
-                               g_hash_table_new_full (hash_func, equal_func, key_destroy_func, value_destroy_func);
+                               g_hash_table_new (hash_func, equal_func);
                        mono_memory_barrier ();
                        *var = cache;
                }
@@ -2293,12 +2298,6 @@ get_cache_full (GHashTable **var, GHashFunc hash_func, GCompareFunc equal_func,
        return *var;
 }
 
-static GHashTable*
-get_cache (GHashTable **var, GHashFunc hash_func, GCompareFunc equal_func)
-{
-       return get_cache_full (var, hash_func, equal_func, NULL, NULL);
-}
-
 GHashTable*
 mono_marshal_get_cache (GHashTable **var, GHashFunc hash_func, GCompareFunc equal_func)
 {
@@ -2423,14 +2422,25 @@ MonoMethod *
 mono_marshal_method_from_wrapper (MonoMethod *wrapper)
 {
        gpointer res;
+       int wrapper_type = wrapper->wrapper_type;
 
-       if (wrapper->wrapper_type == MONO_WRAPPER_NONE || wrapper->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
+       if (wrapper_type == MONO_WRAPPER_NONE || wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
                return wrapper;
 
-       res = mono_method_get_wrapper_data (wrapper, 1);
-       if (res == NULL)
-               return wrapper;
-       return res;
+       switch (wrapper_type) {
+       case MONO_WRAPPER_REMOTING_INVOKE:
+       case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
+       case MONO_WRAPPER_XDOMAIN_INVOKE:
+       case MONO_WRAPPER_SYNCHRONIZED:
+       case MONO_WRAPPER_MANAGED_TO_NATIVE:
+       case MONO_WRAPPER_RUNTIME_INVOKE:
+               res = mono_method_get_wrapper_data (wrapper, 1);
+               if (res == NULL)
+                       return wrapper;
+               return res;
+       default:
+               return NULL;
+       }
 }
 
 /*
@@ -3755,6 +3765,7 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del)
        MonoMethod *target_method = NULL;
        MonoClass *target_class = NULL;
        gboolean callvirt = FALSE;
+       gboolean closed_over_null = FALSE;
 
        /*
         * If the delegate target is null, and the target method is not static, a virtual 
@@ -3781,6 +3792,9 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del)
                
        sig = mono_signature_no_pinvoke (method);
 
+       if (callvirt)
+               closed_over_null = sig->param_count == mono_method_signature (del->method)->param_count;
+
        if (callvirt) {
                /* We need to cache the signature+method pair */
                mono_marshal_lock ();
@@ -3878,11 +3892,18 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del)
        mono_mb_patch_branch (mb, pos0);
 
        if (callvirt) {
-               mono_mb_emit_ldarg (mb, 1);
-               mono_mb_emit_op (mb, CEE_CASTCLASS, target_class);
-               for (i = 1; i < sig->param_count; ++i)
-                       mono_mb_emit_ldarg (mb, i + 1);
-               mono_mb_emit_op (mb, CEE_CALLVIRT, target_method);
+               if (!closed_over_null) {
+                       mono_mb_emit_ldarg (mb, 1);
+                       mono_mb_emit_op (mb, CEE_CASTCLASS, target_class);
+                       for (i = 1; i < sig->param_count; ++i)
+                               mono_mb_emit_ldarg (mb, i + 1);
+                       mono_mb_emit_op (mb, CEE_CALLVIRT, target_method);
+               } else {
+                       mono_mb_emit_byte (mb, CEE_LDNULL);
+                       for (i = 0; i < sig->param_count; ++i)
+                               mono_mb_emit_ldarg (mb, i + 1);
+                       mono_mb_emit_op (mb, CEE_CALL, target_method);
+               }
        } else {
                for (i = 0; i < sig->param_count; ++i)
                        mono_mb_emit_ldarg (mb, i + 1);
@@ -4232,14 +4253,6 @@ mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual)
        /* allocate local 1 (object) exc */
        mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
 
-       /* cond set *exc to null */
-       mono_mb_emit_byte (mb, CEE_LDARG_2);
-       mono_mb_emit_byte (mb, CEE_BRFALSE_S);
-       mono_mb_emit_byte (mb, 3);      
-       mono_mb_emit_byte (mb, CEE_LDARG_2);
-       mono_mb_emit_byte (mb, CEE_LDNULL);
-       mono_mb_emit_byte (mb, CEE_STIND_REF);
-
        emit_thread_force_interrupt_checkpoint (mb);
 
        if (virtual) {
@@ -10703,7 +10716,7 @@ mono_marshal_asany (MonoObject *o, MonoMarshalNative string_encoding, int param_
        case MONO_TYPE_STRING:
                switch (string_encoding) {
                case MONO_NATIVE_LPWSTR:
-                       return mono_string_to_utf16 ((MonoString*)o);
+                       return mono_marshal_string_to_utf16_copy ((MonoString*)o);
                        break;
                case MONO_NATIVE_LPSTR:
                        return mono_string_to_lpstr ((MonoString*)o);
@@ -10802,20 +10815,6 @@ mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_e
        }
 }
 
-/*
- * free_wrapper:
- *
- *   Wrappers of generic instances need to be dynamic, since they cannot be freed when their
- * image is unloaded, since the generic instance they are based on does not belong to any
- * image. This function should be the value dtor of caches holding such wrappers.
- */
-static void
-free_wrapper (MonoMethod *method)
-{
-       if (method->dynamic)
-               mono_free_method (method);
-}
-
 MonoMethod *
 mono_marshal_get_generic_array_helper (MonoClass *class, MonoClass *iface, gchar *name, MonoMethod *method)
 {
@@ -10823,22 +10822,15 @@ mono_marshal_get_generic_array_helper (MonoClass *class, MonoClass *iface, gchar
        MonoMethodBuilder *mb;
        MonoMethod *res;
        int i;
-       GHashTable *cache;
 
-       cache = get_cache_full (&method->klass->image->generic_array_helper_cache, mono_aligned_addr_hash, NULL, NULL, (GDestroyNotify)free_wrapper);
-
-       if ((res = mono_marshal_find_in_cache (cache, method)))
-               return res;
-
-       mb = mono_mb_new (class, name, MONO_WRAPPER_MANAGED_TO_MANAGED);
+       mb = mono_mb_new_no_dup_name (class, name, MONO_WRAPPER_MANAGED_TO_MANAGED);
        mb->method->slot = -1;
-       mb->dynamic = TRUE;
 
        mb->method->flags = METHOD_ATTRIBUTE_PRIVATE | METHOD_ATTRIBUTE_VIRTUAL |
                METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_HIDE_BY_SIG | METHOD_ATTRIBUTE_FINAL;
 
        sig = mono_method_signature (method);
-       csig = signature_dup (NULL, sig);
+       csig = signature_dup (method->klass->image, sig);
        csig->generic_param_count = 0;
 
        mono_mb_emit_ldarg (mb, 0);
@@ -10850,7 +10842,7 @@ mono_marshal_get_generic_array_helper (MonoClass *class, MonoClass *iface, gchar
        /* We can corlib internal methods */
        mb->skip_visibility = TRUE;
 
-       res = mono_mb_create_and_cache (cache, method, mb, csig, csig->param_count + 16);
+       res = mono_mb_create_method (mb, csig, csig->param_count + 16);
 
        mono_mb_free (mb);
 
@@ -11156,8 +11148,6 @@ mono_marshal_free_inflated_wrappers (MonoMethod *method)
                g_hash_table_remove (method->klass->image->cominterop_wrapper_cache, method);
        if (method->klass->image->thunk_invoke_cache)
                g_hash_table_remove (method->klass->image->thunk_invoke_cache, method);
-       if (method->klass->image->generic_array_helper_cache)
-               g_hash_table_remove (method->klass->image->generic_array_helper_cache, method);
 
        mono_marshal_unlock ();
 }