Mon Apr 6 14:09:53 CEST 2009 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / marshal.c
index e52181c4c50610109c2e2040cb1e240f06f48c4c..0e622038db80c04f7079df339dfe1027970c8b0f 100644 (file)
@@ -50,13 +50,6 @@ typedef enum {
        MONO_MARSHAL_SERIALIZE          /* Value needs to be serialized into the new domain */
 } MonoXDomainMarshalType;
 
-typedef enum {
-       MONO_COM_DEFAULT,
-       MONO_COM_MS
-} MonoCOMProvider;
-
-static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
-
 enum {
 #include "mono/cil/opcode.def"
        LAST = 0xff
@@ -104,12 +97,6 @@ mono_marshal_string_to_utf16_copy (MonoString *s);
 static gpointer
 mono_string_to_lpstr (MonoString *string_obj);
 
-static MonoString * 
-mono_string_from_bstr (gpointer bstr);
-
-static void 
-mono_free_bstr (gpointer bstr);
-
 static MonoStringBuilder *
 mono_string_utf8_to_builder2 (char *text);
 
@@ -217,9 +204,6 @@ mono_marshal_init (void)
                register_icall (mono_string_new_wrapper, "mono_string_new_wrapper", "obj ptr", FALSE);
                register_icall (mono_string_to_utf8, "mono_string_to_utf8", "ptr obj", FALSE);
                register_icall (mono_string_to_lpstr, "mono_string_to_lpstr", "ptr obj", FALSE);
-               register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
-               register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
-               register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
                register_icall (mono_string_to_ansibstr, "mono_string_to_ansibstr", "ptr object", FALSE);
                register_icall (mono_string_builder_to_utf8, "mono_string_builder_to_utf8", "ptr object", FALSE);
                register_icall (mono_string_builder_to_utf16, "mono_string_builder_to_utf16", "ptr object", FALSE);
@@ -330,6 +314,18 @@ mono_delegate_to_ftnptr (MonoDelegate *delegate)
 
        method = delegate->method;
 
+       if (mono_method_signature (method)->pinvoke) {
+               const char *exc_class, *exc_arg;
+               gpointer ftnptr;
+
+               ftnptr = mono_lookup_pinvoke_call (method, &exc_class, &exc_arg);
+               if (!ftnptr) {
+                       g_assert (exc_class);
+                       mono_raise_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
+               }
+               return ftnptr;
+       }
+
        wrapper = mono_marshal_get_managed_wrapper (method, klass, delegate->target);
 
        delegate->delegate_trampoline =  mono_compile_method (wrapper);
@@ -399,6 +395,9 @@ mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn)
 #endif
        MonoDelegate *d;
 
+       if (ftn == NULL)
+               return NULL;
+
        mono_marshal_lock ();
        if (delegate_hash_table == NULL)
                delegate_hash_table = delegate_hash_table_new ();
@@ -769,137 +768,6 @@ mono_string_to_ansibstr (MonoString *string_obj)
        return NULL;
 }
 
-typedef gpointer (*SysAllocStringLenFunc)(gunichar* str, guint32 len);
-typedef guint32 (*SysStringLenFunc)(gpointer bstr);
-typedef void (*SysFreeStringFunc)(gunichar* str);
-
-static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
-static SysStringLenFunc sys_string_len_ms = NULL;
-static SysFreeStringFunc sys_free_string_ms = NULL;
-
-static gboolean
-init_com_provider_ms (void)
-{
-       static gboolean initialized = FALSE;
-       char *error_msg;
-       MonoDl *module = NULL;
-       const char* scope = "liboleaut32.so";
-
-       if (initialized)
-               return TRUE;
-
-       module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
-       if (error_msg) {
-               g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
-               g_assert_not_reached ();
-               return FALSE;
-       }
-       error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
-       if (error_msg) {
-               g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
-               g_assert_not_reached ();
-               return FALSE;
-       }
-
-       error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
-       if (error_msg) {
-               g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
-               g_assert_not_reached ();
-               return FALSE;
-       }
-
-       error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
-       if (error_msg) {
-               g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
-               g_assert_not_reached ();
-               return FALSE;
-       }
-
-       initialized = TRUE;
-       return TRUE;
-}
-
-gpointer
-mono_string_to_bstr (MonoString *string_obj)
-{
-       if (!string_obj)
-               return NULL;
-#ifdef PLATFORM_WIN32
-       return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
-#else
-       if (com_provider == MONO_COM_DEFAULT) {
-               int slen = mono_string_length (string_obj);
-               /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
-               char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
-               if (ret == NULL)
-                       return NULL;
-               memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
-               * ((guint32 *) ret) = slen * sizeof(gunichar2);
-               ret [4 + slen * sizeof(gunichar2)] = 0;
-               ret [5 + slen * sizeof(gunichar2)] = 0;
-
-               return ret + 4;
-       } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
-               gpointer ret = NULL;
-               gunichar* str = NULL;
-               guint32 len;
-               len = mono_string_length (string_obj);
-               str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
-                       NULL, NULL, NULL);
-               ret = sys_alloc_string_len_ms (str, len);
-               g_free(str);
-               return ret;
-       } else {
-               g_assert_not_reached ();
-       }
-#endif
-}
-
-MonoString *
-mono_string_from_bstr (gpointer bstr)
-{
-       if (!bstr)
-               return NULL;
-#ifdef PLATFORM_WIN32
-       return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
-#else
-       if (com_provider == MONO_COM_DEFAULT) {
-               return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
-       } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
-               MonoString* str = NULL;
-               glong written = 0;
-               gunichar2* utf16 = NULL;
-
-               utf16 = g_ucs4_to_utf16 (bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
-               str = mono_string_new_utf16 (mono_domain_get (), utf16, written);
-               g_free (utf16);
-               return str;
-       } else {
-               g_assert_not_reached ();
-       }
-
-#endif
-}
-
-void
-mono_free_bstr (gpointer bstr)
-{
-       if (!bstr)
-               return;
-#ifdef PLATFORM_WIN32
-       SysFreeString ((BSTR)bstr);
-#else
-       if (com_provider == MONO_COM_DEFAULT) {
-               g_free (((char *)bstr) - 4);
-       } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
-               sys_free_string_ms (bstr);
-       } else {
-               g_assert_not_reached ();
-       }
-
-#endif
-}
-
 /**
  * mono_string_to_byvalstr:
  * @dst: Where to store the null-terminated utf8 decoded string.
@@ -3971,9 +3839,13 @@ runtime_invoke_signature_equal (MonoMethodSignature *sig1, MonoMethodSignature *
  * MonoObject *runtime_invoke (MonoObject *this, void **params, MonoObject **exc, void* method)
  *
  * we also catch exceptions if exc != null
+ * If VIRTUAL is TRUE, then METHOD is invoked virtually on THIS. This is useful since
+ * it means that the compiled code for METHOD does not have to be looked up 
+ * before calling the runtime invoke wrapper. In this case, the wrapper ignores
+ * its METHOD argument.
  */
 MonoMethod *
-mono_marshal_get_runtime_invoke (MonoMethod *method)
+mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual)
 {
        MonoMethodSignature *sig, *csig, *callsig;
        MonoExceptionClause *clause;
@@ -4001,11 +3873,17 @@ mono_marshal_get_runtime_invoke (MonoMethod *method)
                finalize_signature->hasthis = 1;
        }
 
+       if (virtual)
+               need_direct_wrapper = TRUE;
+
        /* 
         * Use a separate cache indexed by methods to speed things up and to avoid the
         * boundless mempool growth caused by the signature_dup stuff below.
         */
-       cache = get_cache (&method->klass->image->runtime_invoke_direct_cache, mono_aligned_addr_hash, NULL);
+       if (virtual)
+               cache = get_cache (&method->klass->image->runtime_invoke_vcall_cache, mono_aligned_addr_hash, NULL);
+       else
+               cache = get_cache (&method->klass->image->runtime_invoke_direct_cache, mono_aligned_addr_hash, NULL);
        res = mono_marshal_find_in_cache (cache, method);
        if (res)
                return res;
@@ -4023,6 +3901,8 @@ mono_marshal_get_runtime_invoke (MonoMethod *method)
                callsig = lookup_string_ctor_signature (mono_method_signature (method));
                if (!callsig)
                        callsig = add_string_ctor_signature (method);
+               /* Can't share this as we push a string as this */
+               need_direct_wrapper = TRUE;
        } else {
                if (method->klass->valuetype && mono_method_signature (method)->hasthis) {
                        /* 
@@ -4118,7 +3998,7 @@ mono_marshal_get_runtime_invoke (MonoMethod *method)
        csig->params [2] = &mono_defaults.int_class->byval_arg;
        csig->params [3] = &mono_defaults.int_class->byval_arg;
 
-       name = mono_signature_to_name (callsig, "runtime_invoke");
+       name = mono_signature_to_name (callsig, virtual ? "runtime_invoke_virtual" : "runtime_invoke");
        mb = mono_mb_new (target_klass, name,  MONO_WRAPPER_RUNTIME_INVOKE);
        g_free (name);
 
@@ -4137,6 +4017,11 @@ mono_marshal_get_runtime_invoke (MonoMethod *method)
 
        emit_thread_force_interrupt_checkpoint (mb);
 
+       if (virtual) {
+               g_assert (sig->hasthis);
+               g_assert (method->flags & METHOD_ATTRIBUTE_VIRTUAL);
+       }
+
        if (sig->hasthis) {
                if (method->string_ctor) {
                        mono_mb_emit_ptr (mb, string_dummy);
@@ -4226,7 +4111,9 @@ handle_enum:
                }               
        }
        
-       if (need_direct_wrapper) {
+       if (virtual) {
+               mono_mb_emit_op (mb, CEE_CALLVIRT, method);
+       } else if (need_direct_wrapper) {
                mono_mb_emit_op (mb, CEE_CALL, method);
        } else {
                mono_mb_emit_ldarg (mb, 3);
@@ -4414,7 +4301,7 @@ mono_marshal_get_static_rgctx_invoke (MonoMethod *method)
                return res;
 
        if (!inited) {
-               mono_counters_register ("static rgctx invoke wrappers",
+               mono_counters_register ("Static rgctx invoke wrappers",
                                MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_wrappers);
                inited = TRUE;
        }
@@ -5971,17 +5858,19 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
        MonoClass *klass = mono_class_from_mono_type (t);
        int pos, pos2, loc;
 
-       if (mono_class_from_mono_type (t) == mono_defaults.object_class) {
-               mono_raise_exception (mono_get_exception_not_implemented ("Marshalling of type object is not implemented"));
-       }
-
        switch (action) {
        case MARSHAL_ACTION_CONV_IN:
                *conv_arg_type = &mono_defaults.int_class->byval_arg;
                conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
 
                m->orig_conv_args [argnum] = 0;
-               
+
+               if (mono_class_from_mono_type (t) == mono_defaults.object_class) {
+                       char *msg = g_strdup_printf ("Marshalling of type object is not implemented");
+                       mono_mb_emit_exception_marshal_directive (mb, msg);
+                       break;
+               }
+
                if (klass->delegate) {
                        if (t->byref) {
                                if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) {
@@ -7263,6 +7152,8 @@ emit_marshal_boolean (EmitMarshalContext *m, int argnum, MonoType *t,
        case MARSHAL_ACTION_MANAGED_CONV_IN: {
                gint variant_bool = 0;
                guint8 ldop = CEE_LDIND_I4;
+               int label1;
+
                if (!t->byref)
                        break;
 
@@ -7288,6 +7179,10 @@ emit_marshal_boolean (EmitMarshalContext *m, int argnum, MonoType *t,
                                g_warning ("marshalling bool as native type %x is currently not supported", spec->native);
                        }
                }
+
+               /* Check null */
+               mono_mb_emit_ldarg (mb, argnum);
+               label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
                
                mono_mb_emit_ldarg (mb, argnum);
                mono_mb_emit_byte (mb, ldop);   
@@ -7295,11 +7190,15 @@ emit_marshal_boolean (EmitMarshalContext *m, int argnum, MonoType *t,
                if (variant_bool)
                        mono_mb_emit_byte (mb, CEE_NEG);
                mono_mb_emit_stloc (mb, conv_arg);
+
+               mono_mb_patch_branch (mb, label1);
                break;
        }
 
        case MARSHAL_ACTION_MANAGED_CONV_OUT: {
                guint8 stop = CEE_STIND_I4;
+               int label1;
+
                if (!t->byref)
                        break;
                if (spec) {
@@ -7315,12 +7214,18 @@ emit_marshal_boolean (EmitMarshalContext *m, int argnum, MonoType *t,
                                break;
                        }
                }
+               
+               /* Check null */
+               mono_mb_emit_ldarg (mb, argnum);
+               label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
 
                mono_mb_emit_ldarg (mb, argnum);
                mono_mb_emit_ldloc (mb, conv_arg);
                if (spec != NULL && spec->native == MONO_NATIVE_VARIANTBOOL)
                        mono_mb_emit_byte (mb, CEE_NEG);
                mono_mb_emit_byte (mb, stop);
+
+               mono_mb_patch_branch (mb, label1);
                break;
        }
 
@@ -7447,7 +7352,7 @@ emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t,
                        return mono_cominterop_emit_marshal_com_interface (m, argnum, t, spec, conv_arg, conv_arg_type, action);
 #endif
 
-               if (mono_defaults.safehandle_class != NULL &&
+               if (mono_defaults.safehandle_class != NULL && t->data.klass &&
                    mono_class_is_subclass_of (t->data.klass,  mono_defaults.safehandle_class, FALSE))
                        return emit_marshal_safehandle (m, argnum, t, spec, conv_arg, conv_arg_type, action);
                
@@ -9473,30 +9378,6 @@ ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (guint16 *pt
        }
 }
 
-MonoString *
-ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
-{
-       MONO_ARCH_SAVE_REGS;
-
-       return mono_string_from_bstr(ptr);
-}
-
-gpointer
-ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
-{
-       MONO_ARCH_SAVE_REGS;
-
-       return mono_string_to_bstr(ptr);
-}
-
-void
-ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
-{
-       MONO_ARCH_SAVE_REGS;
-
-       mono_free_bstr (ptr);
-}
-
 guint32 
 ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void)
 {