Mon Apr 6 14:09:53 CEST 2009 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / marshal.c
index 15884e2aabaa27284173131d360594eff6a2b5e2..0e622038db80c04f7079df339dfe1027970c8b0f 100644 (file)
@@ -314,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);
@@ -3827,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;
@@ -3857,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;
@@ -3879,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) {
                        /* 
@@ -3974,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);
 
@@ -3993,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);
@@ -4082,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);
@@ -5827,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)) {
@@ -7319,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);