[Mono-list] mint patch

Dietmar Maurer dietmar@ximian.com
26 Jul 2002 16:42:26 +0200


Hi Paolo,

here is a first patch for mint to use the architecture independent
marshaling/delegate/remoting code from marshal.c. There are still some
unresolved problems with arrays and exceptions in unmanaged code, but it
shows that we can really share large parts of "hard to maintain" code
with the JIT. It also makes porting much easier, since the whole PInvoke
stuff is done in architecture independent IL code.

The disadvantage is that it is slower because we interpret the PInvoke
marshaling code.

What do you think - should we go that way? 

- Dietmar


Index: mono/arch/x86/tramp.c
===================================================================
RCS file: /cvs/public/mono/mono/arch/x86/tramp.c,v
retrieving revision 1.33
diff -u -r1.33 tramp.c
--- mono/arch/x86/tramp.c	19 Jul 2002 12:21:01 -0000	1.33
+++ mono/arch/x86/tramp.c	26 Jul 2002 14:22:07 -0000
@@ -30,23 +30,13 @@
 #define ARG_SIZE	sizeof (stackval)
 
 MonoPIFunc
-mono_create_trampoline (MonoMethod *method, int runtime)
+mono_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor)
 {
-	MonoMethodSignature *sig;
 	unsigned char *p, *code_buffer;
 	guint32 local_size = 0, stack_size = 0, code_size = 50;
 	guint32 arg_pos, simpletype;
 	int i, stringp;
-	int need_marshal;
-	GList *free_locs = NULL;
 
-	if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime)
-		need_marshal = 0;
-	else
-		need_marshal = 1;
-
-	sig = method->signature;
-	
 	if (sig->hasthis) {
 		stack_size += sizeof (gpointer);
 		code_size += 5;
@@ -143,31 +133,7 @@
 	for (i = sig->param_count; i; --i) {
 		arg_pos = ARG_SIZE * (i - 1);
 		if (sig->params [i - 1]->byref) {
-			if (!need_marshal) {
-				x86_push_membase (p, X86_EDX, arg_pos);
-				continue;
-			}
-			if (sig->params [i - 1]->type == MONO_TYPE_SZARRAY &&
-			    sig->params [i - 1]->data.type->type == MONO_TYPE_STRING) {
-				x86_mov_reg_membase (p, X86_EAX, X86_EDX, arg_pos, 4);
-				x86_push_regp (p, X86_EAX);
-				x86_mov_reg_imm (p, X86_EDX, mono_marshal_string_array);
-				x86_call_reg (p, X86_EDX);
-				x86_alu_reg_imm (p, X86_ADD, X86_ESP, 4);
-				/*
-				 * Store the pointer in a local we'll free later.
-				 */
-				stringp++;
-				x86_mov_membase_reg (p, X86_EBP, LOC_POS * stringp, X86_EAX, 4);
-				free_locs = g_list_prepend (free_locs, GUINT_TO_POINTER (LOC_POS * stringp));
-				/* load the pointer and push it */
-				x86_lea_membase (p, X86_EAX, X86_EBP, LOC_POS * stringp);
-				x86_push_reg (p, X86_EAX);
-				/* restore pointer to args in EDX */
-				x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4);
-			} else {
-				x86_push_membase (p, X86_EDX, arg_pos);
-			}
+			x86_push_membase (p, X86_EDX, arg_pos);
 			continue;
 		}
 		simpletype = sig->params [i - 1]->type;
@@ -193,26 +159,10 @@
 			x86_fst_membase (p, X86_ESP, 0, FALSE, TRUE);
 			break;
 		case MONO_TYPE_CLASS:
-			if (need_marshal) {
-				if (sig->params [i - 1]->data.klass->delegate) {
-					/* should we use a wrapper to invoke the multicast delegates? */
-					x86_mov_reg_membase (p, X86_EAX, X86_EDX, arg_pos, 4);
-					x86_alu_reg_imm (p, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
-					x86_push_reg (p, X86_EAX);
-				} else
-					g_error ("unhandled case");
-			} else {
-				x86_push_membase (p, X86_EDX, arg_pos);
-			}
+			x86_push_membase (p, X86_EDX, arg_pos);
 			break;
 		case MONO_TYPE_SZARRAY:
-			if (need_marshal) {
-				x86_mov_reg_membase (p, X86_EAX, X86_EDX, arg_pos, 4);
-				x86_alu_reg_imm (p, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoArray, vector));
-				x86_push_reg (p, X86_EAX);
-			} else {
-				x86_push_membase (p, X86_EDX, arg_pos);
-			}
+			x86_push_membase (p, X86_EDX, arg_pos);
 			break;
 		case MONO_TYPE_VALUETYPE:
 			if (!sig->params [i - 1]->data.klass->enumtype) {
@@ -226,31 +176,7 @@
 			}
 			break;
 		case MONO_TYPE_STRING:
-			/* 
-			 * If it is an internalcall we assume it's the object we want.
-			 * Yet another reason why MONO_TYPE_STRING should not be used to indicate char*.
-			 */
-			if (!need_marshal) {
-				x86_push_membase (p, X86_EDX, arg_pos);
-				break;
-			}
-			/*if (frame->method->flags & PINVOKE_ATTRIBUTE_CHAR_SET_ANSI*/
 			x86_push_membase (p, X86_EDX, arg_pos);
-			x86_mov_reg_imm (p, X86_EDX, mono_string_to_utf8);
-			x86_call_reg (p, X86_EDX);
-			x86_alu_reg_imm (p, X86_ADD, X86_ESP, 4);
-			x86_push_reg (p, X86_EAX);
-			/*
-			 * Store the pointer in a local we'll free later.
-			 */
-			stringp++;
-			x86_mov_membase_reg (p, X86_EBP, LOC_POS * stringp, X86_EAX, 4);
-			free_locs = g_list_prepend (free_locs, GUINT_TO_POINTER (LOC_POS * stringp));
-			/*
-			 * we didn't save the reg: restore it here.
-			 */
-			if (i > 1)
-				x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4);
 			break;
 		case MONO_TYPE_I8:
 		case MONO_TYPE_U8:
@@ -285,14 +211,12 @@
 	 * FP values are on the FP stack.
 	 */
 
-	if (sig->ret->byref || 
-	    (method->klass == mono_defaults.string_class &&
-	     *method->name == '.' && !strcmp (method->name, ".ctor"))) {
+	if (sig->ret->byref || string_ctor) {
 		x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
 		x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
 	} else {
 		simpletype = sig->ret->type;
-enum_retvalue:
+	enum_retvalue:
 		switch (simpletype) {
 		case MONO_TYPE_BOOLEAN:
 		case MONO_TYPE_I1:
@@ -318,20 +242,6 @@
 			x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
 			break;
 		case MONO_TYPE_STRING: 
-			if (!need_marshal) {
-				x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
-				x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
-				break;
-			}
-
-			/* If the argument is non-null, then convert the value back */
-			x86_alu_reg_reg (p, X86_OR, X86_EAX, X86_EAX);
-			x86_branch8 (p, X86_CC_EQ, 11, FALSE);
-			x86_push_reg (p, X86_EAX);
-			x86_mov_reg_imm (p, X86_EDX, mono_string_new_wrapper);
-			x86_call_reg (p, X86_EDX);
-			x86_alu_reg_imm (p, X86_ADD, X86_ESP, 4);
-
 			x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
 			x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
 			break;
@@ -360,18 +270,6 @@
 		}
 	}
 
-	/*
-	 * free the allocated strings.
-	 */
-	if (need_marshal) {
-		GList* tmp;
-		for (tmp = free_locs; tmp; tmp = tmp->next) {
-			x86_mov_reg_imm (p, X86_EDX, g_free);
-			x86_push_membase (p, X86_EBP, GPOINTER_TO_UINT (tmp->data));
-			x86_call_reg (p, X86_EDX);
-		}
-		g_list_free (free_locs);
-	}
 	/*
 	 * Standard epilog.
 	 */
Index: mono/interpreter/interp.c
===================================================================
RCS file: /cvs/public/mono/mono/interpreter/interp.c,v
retrieving revision 1.206
diff -u -r1.206 interp.c
--- mono/interpreter/interp.c	24 Jul 2002 11:07:52 -0000	1.206
+++ mono/interpreter/interp.c	26 Jul 2002 14:22:08 -0000
@@ -55,6 +55,7 @@
 #include <mono/io-layer/io-layer.h>
 #include <mono/metadata/socket-io.h>
 #include <mono/metadata/mono-config.h>
+#include <mono/metadata/marshal.h>
 #include <mono/os/util.h>
 
 /*#include <mono/cli/types.h>*/
@@ -143,7 +144,7 @@
 		char *args = dump_stack (frame->stack_args, frame->stack_args+signature->param_count);	\
 		debug_indent_level++;	\
 		output_indent ();	\
-		g_print ("(%d) Entering %s.%s::%s (", GetCurrentThreadId(), klass->name_space, klass->name, frame->method->name);	\
+		g_print ("(%d) Entering %s (", GetCurrentThreadId(), mono_method_full_name (frame->method, FALSE));	\
 		if (signature->hasthis) { \
 			if (global_no_pointers) { \
 				g_print ("this%s ", frame->obj ? "" : "=null"); \
@@ -165,7 +166,7 @@
 		else	\
 			args = g_strdup ("");	\
 		output_indent ();	\
-		g_print ("(%d) Leaving %s.%s::%s", GetCurrentThreadId(), klass->name_space, klass->name, frame->method->name);	\
+		g_print ("(%d) Leaving %s", GetCurrentThreadId(),  mono_method_full_name (frame->method, FALSE));	\
 		g_print (" => %s\n", args);	\
 		g_free (args);	\
 		debug_indent_level--;	\
@@ -496,105 +497,24 @@
 	return (MonoObject*)mono_array_new_full (domain, klass, lengths, lower_bounds);
 }
 
-static void 
-ves_array_set (MonoInvocation *frame)
+/* this function is never called */
+static void
+ves_array_set (MonoArray *this, ...)
 {
-	stackval *sp = frame->stack_args;
-	MonoObject *o;
-	MonoArray *ao;
-	MonoClass *ac;
-	gint32 i, t, pos, esize;
-	gpointer ea;
-	MonoType *mt;
-
-	o = frame->obj;
-	ao = (MonoArray *)o;
-	ac = o->vtable->klass;
-
-	g_assert (ac->rank >= 1);
-
-	pos = sp [0].data.i;
-	if (ao->bounds != NULL) {
-		pos -= ao->bounds [0].lower_bound;
-		for (i = 1; i < ac->rank; i++) {
-			if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >= 
-			    ao->bounds [i].length) {
-				g_warning ("wrong array index");
-				g_assert_not_reached ();
-			}
-			pos = pos*ao->bounds [i].length + sp [i].data.i - 
-				ao->bounds [i].lower_bound;
-		}
-	}
-
-	esize = mono_array_element_size (ac);
-	ea = mono_array_addr_with_size (ao, esize, pos);
-
-	mt = frame->method->signature->params [ac->rank];
-	stackval_to_data (mt, &sp [ac->rank], ea);
+	g_assert_not_reached ();
 }
 
-static void 
-ves_array_get (MonoInvocation *frame)
+/* this function is never called */
+static void
+ves_array_get (MonoArray *this, ...)
 {
-	stackval *sp = frame->stack_args;
-	MonoObject *o;
-	MonoArray *ao;
-	MonoClass *ac;
-	gint32 i, pos, esize;
-	gpointer ea;
-	MonoType *mt;
-
-	o = frame->obj;
-	ao = (MonoArray *)o;
-	ac = o->vtable->klass;
-
-	g_assert (ac->rank >= 1);
-
-	pos = sp [0].data.i;
-	if (ao->bounds != NULL) {
-		pos -= ao->bounds [0].lower_bound;
-		for (i = 1; i < ac->rank; i++)
-			pos = pos*ao->bounds [i].length + sp [i].data.i - 
-				ao->bounds [i].lower_bound;
-	}
-
-	esize = mono_array_element_size (ac);
-	ea = mono_array_addr_with_size (ao, esize, pos);
-
-	mt = frame->method->signature->ret;
-	stackval_from_data (mt, frame->retval, ea);
+	g_assert_not_reached ();
 }
 
 static void
 ves_array_element_address (MonoInvocation *frame)
 {
-	stackval *sp = frame->stack_args;
-	MonoObject *o;
-	MonoArray *ao;
-	MonoClass *ac;
-	gint32 i, pos, esize;
-	gpointer ea;
-
-	o = frame->obj;
-	ao = (MonoArray *)o;
-	ac = o->vtable->klass;
-
-	g_assert (ac->rank >= 1);
-
-	pos = sp [0].data.i;
-	if (ao->bounds != NULL) {
-		pos -= ao->bounds [0].lower_bound;
-		for (i = 1; i < ac->rank; i++)
-			pos = pos*ao->bounds [i].length + sp [i].data.i - 
-				ao->bounds [i].lower_bound;
-	}
-
-	esize = mono_array_element_size (ac);
-	ea = mono_array_addr_with_size (ao, esize, pos);
-
-	frame->retval->type = VAL_TP;
-	frame->retval->data.p = ea;
+	g_assert_not_reached ();	
 }
 
 /* This is the implementation of the ldftn opcode
@@ -627,35 +547,6 @@
 	}
 }
 
-static void 
-ves_pinvoke_method (MonoInvocation *frame)
-{
-	jmp_buf env;
-	MonoPIFunc func;
-	
-	if (setjmp(env)) {
-		TlsSetValue (frame_thread_id, frame->args);
-		return;
-	}
-	if (!frame->method->info)
-		frame->method->info = mono_create_trampoline (frame->method, 0);
-	func = (MonoPIFunc)frame->method->info;
-
-	/* 
-	 * frame->locals and args are unused for P/Invoke methods, so we reuse them. 
-	 * locals will point to the jmp_buf, while args will point to the previous
-	 * MonoInvocation frame: this is needed to make exception searching work across
-	 * managed/unmanaged boundaries.
-	 */
-	frame->locals = (char*)&env;
-	frame->args = (char*)TlsGetValue (frame_thread_id);
-	TlsSetValue (frame_thread_id, frame);
-
-	func ((MonoFunc)frame->method->addr, &frame->retval->data.p, frame->obj, frame->stack_args);
-	stackval_from_data (frame->method->signature->ret, frame->retval, (char*)&frame->retval->data.p);
-	TlsSetValue (frame_thread_id, frame->args);
-}
-
 /*
  * From the spec:
  * runtime specifies that the implementation of the method is automatically
@@ -668,7 +559,7 @@
 	MonoObject *obj = (MonoObject*)frame->obj;
 	MonoMulticastDelegate *delegate = (MonoMulticastDelegate*)frame->obj;
 	MonoInvocation call;
-
+	
 	mono_class_init (frame->method->klass);
 	
 	if (*name == '.' && (strcmp (name, ".ctor") == 0) && obj &&
@@ -678,81 +569,33 @@
 		return;
 	}
 	if (*name == 'I' && (strcmp (name, "Invoke") == 0) && obj &&
-			mono_object_isinst (obj, mono_defaults.multicastdelegate_class)) {
-		guchar *code;
-		MonoJitInfo *ji;
+	    mono_object_isinst (obj, mono_defaults.multicastdelegate_class)) {
 		MonoMethod *method;
-		
-		while (delegate) {
 
-			code = (guchar*)delegate->delegate.method_ptr;
-			if ((ji = mono_jit_info_table_find (mono_root_domain, code))) {
-				method = ji->method;
-				INIT_FRAME(&call,frame,delegate->delegate.target,frame->stack_args,frame->retval,method);
-				ves_exec_method (&call);
-			} else {
-#if 0
-				if (!method->addr)
-					method->addr = mono_create_trampoline (method, 1);
-				func = method->addr;
-				/* FIXME: need to handle exceptions across managed/unmanaged boundaries */
-				func ((MonoFunc)delegate->method_ptr, &frame->retval->data.p, 
-				      delegate->target, frame->stack_args);
-				stackval_from_data (frame->method->signature->ret, frame->retval, 
-						    (char*)&frame->retval->data.p);
-#endif
-				g_assert_not_reached ();
-			}
+		method = mono_marshal_get_delegate_invoke (frame->method);
+		INIT_FRAME(&call,frame,obj,frame->stack_args,frame->retval,method);
+		ves_exec_method (&call);	
 
-			delegate = delegate->prev;
-		}
 		return;
 	}
 	if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0) && obj &&
 			mono_object_isinst (obj, mono_defaults.multicastdelegate_class)) {
-		MonoMethodMessage *msg;
-		MonoDelegate *async_callback;
-		MonoObject *state;
-		MonoMethod *im;
-		MonoAsyncResult *ares;
-	
-		im = mono_get_delegate_invoke (frame->method->klass);
-		msg = arch_method_call_message_new (frame->method, frame->obj, frame->stack_args, im, &async_callback, &state);
+		MonoMethod *method;
+
+		method = mono_marshal_get_delegate_begin_invoke (frame->method);
+		INIT_FRAME(&call,frame,obj,frame->stack_args,frame->retval,method);
+		ves_exec_method (&call);	
 
-		ares = mono_thread_pool_add (delegate, msg, async_callback, state);
-		frame->retval->data.p = ares;
 		return;
 	}
 	if (*name == 'E' && (strcmp (name, "EndInvoke") == 0) && obj &&
 			mono_object_isinst (obj, mono_defaults.multicastdelegate_class)) {
-		MonoAsyncResult *ares;
-		MonoMethodSignature *sig = frame->method->signature;
-		MonoMethodMessage *msg;
-		MonoObject *res, *exc;
-		MonoArray *out_args;
-
-		msg = arch_method_call_message_new (frame->method, frame->obj, frame->stack_args, NULL, NULL, NULL);
-
-		ares = mono_array_get (msg->args, gpointer, sig->param_count - 1);
-		g_assert (ares);
-
-		res = mono_thread_pool_finish (ares, &out_args, &exc);
-
-		if (exc) {
-			char *strace = mono_string_to_utf8 (((MonoException*)exc)->stack_trace);
-			char  *tmp;
-			tmp = g_strdup_printf ("%s\nException Rethrown at:\n", strace);
-			g_free (strace);	
-			((MonoException*)exc)->stack_trace = mono_string_new (mono_object_domain (exc), tmp);
-			g_free (tmp);
-			mono_raise_exception ((MonoException*)exc);
-		}
-
-		/* restore return value */
-		if (sig->ret->type != MONO_TYPE_VOID) {
-			g_assert (res);
-			/*arch_method_return_message_restore (method, &first_arg, res, out_args);*/
-		}
+		MonoMethod *method;
+
+		method = mono_marshal_get_delegate_end_invoke (frame->method);
+		INIT_FRAME(&call,frame,obj,frame->stack_args,frame->retval,method);
+		ves_exec_method (&call);	
+
 		return;
 	}
 	g_error ("Don't know how to exec runtime method %s.%s::%s", 
@@ -952,10 +795,12 @@
 			ip += 5;
 			break;
 		case MonoInlineType:
-			class = mono_class_get (image, read32 (ip + 1));
-			mono_class_init (class);
-			if (!(class->flags & TYPE_ATTRIBUTE_INTERFACE))
-				mono_class_vtable (domain, class);
+			if (method->wrapper_type == MONO_WRAPPER_NONE) {
+				class = mono_class_get (image, read32 (ip + 1));
+				mono_class_init (class);
+				if (!(class->flags & TYPE_ATTRIBUTE_INTERFACE))
+					mono_class_vtable (domain, class);
+			}
 			ip += 5;
 			break;
 		case MonoInlineField:
@@ -971,10 +816,12 @@
 			ip += 5;
 			break;
 		case MonoInlineMethod:
-			m = mono_get_method (image, read32 (ip + 1), NULL);
-			mono_class_init (m->klass);
-			if (!(m->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
-				mono_class_vtable (domain, m->klass);
+			if (method->wrapper_type == MONO_WRAPPER_NONE) {
+				m = mono_get_method (image, read32 (ip + 1), NULL);
+				mono_class_init (m->klass);
+				if (!(m->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
+					mono_class_vtable (domain, m->klass);
+			}
 			ip += 5;
 			break;
 		case MonoInlineTok:
@@ -1269,40 +1116,14 @@
 
 	signature = frame->method->signature;
 
-	DEBUG_ENTER ();
-
-	if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
-		if (!frame->method->addr) {
-			frame->ex = (MonoException*)mono_get_exception_missing_method ();
-			DEBUG_LEAVE ();
-			return;
-		}
-		if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
-			ves_pinvoke_method (frame);
-		} else {
-			ICallMethod icall = (ICallMethod)frame->method->addr;
-			icall (frame);
-		}
-		if (frame->ex)
-			goto handle_exception;
-		DEBUG_LEAVE ();
+	if ((frame->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
+	    (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
+		frame->method = mono_marshal_get_native_wrapper (frame->method);
+		ves_exec_method (frame);
 		return;
 	} 
 
-	if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
-		if (!frame->method->addr) {
-			if (!mono_lookup_pinvoke_call (frame->method)) {
-				frame->ex = (MonoException*)mono_get_exception_missing_method ();
-				DEBUG_LEAVE ();
-				return;
-			}
-		}
-		ves_pinvoke_method (frame);
-		if (frame->ex)
-			goto handle_exception;
-		DEBUG_LEAVE ();
-		return;
-	} 
+	DEBUG_ENTER ();
 
 	if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
 		ves_runtime_method (frame);
@@ -1606,6 +1427,7 @@
 			guint32 token;
 			int virtual = *ip == CEE_CALLVIRT;
 			int calli = *ip == CEE_CALLI;
+			unsigned char *code = NULL;
 
 			/*
 			 * We ignore tail recursion for now.
@@ -1619,16 +1441,18 @@
 			ip += 4;
 			if (calli) {
 				MonoJitInfo *ji;
-				unsigned char *code;
 				--sp;
 				code = sp->data.p;
+				if (frame->method->wrapper_type != MONO_WRAPPER_NONE) {
+					csignature = (MonoMethodSignature *)mono_method_get_wrapper_data (frame->method, token);
+					child_frame.method = NULL;
+				} else
 				if ((ji = mono_jit_info_table_find (mono_root_domain, code))) {
 					child_frame.method = ji->method;
-					csignature = child_frame.method->signature;
 				} else {
-					/* fixme: native code ? */
-					g_assert_not_reached ();
+						g_assert_not_reached ();
 				}
+				g_assert (code);
 			} else {
 				child_frame.method = mono_get_method (image, token, NULL);
 				if (!child_frame.method)
@@ -1643,6 +1467,7 @@
 						THROW_EX (mono_get_exception_missing_method (), ip -5);
 				}
 			}
+
 			g_assert (csignature->call_convention == MONO_CALL_DEFAULT);
 			/* decrement by the actual number of args */
 			if (csignature->param_count) {
@@ -1658,7 +1483,8 @@
 				 * It may also be a TP from LD(S)FLDA
 				 * g_assert (sp->type == VAL_OBJ || sp->type == VAL_VALUETA);
 				 */
-				if (sp->type == VAL_OBJ && child_frame.method->klass->valuetype) /* unbox it */
+				if (sp->type == VAL_OBJ && child_frame.method &&
+				    child_frame.method->klass->valuetype) /* unbox it */
 					child_frame.obj = (char*)sp->data.p + sizeof (MonoObject);
 				else
 					child_frame.obj = sp->data.p;
@@ -1675,40 +1501,55 @@
 			child_frame.ex = NULL;
 			child_frame.ex_handler = NULL;
 
-			if (csignature->hasthis && sp->type == VAL_OBJ &&
+			if (child_frame.method && csignature->hasthis && sp->type == VAL_OBJ &&
 					((MonoObject *)sp->data.p)->vtable->klass == mono_defaults.transparent_proxy_class) {
 				/* implement remoting */
-				invoke_remoting_trampoline (&child_frame);
+				g_assert (child_frame.method);
+				child_frame.method = mono_marshal_get_remoting_invoke (child_frame.method);
+				ves_exec_method (&child_frame);
+				//invoke_remoting_trampoline (&child_frame);
 			} else {
-				switch (GPOINTER_TO_UINT (child_frame.method->addr)) {
-				case INLINE_STRING_LENGTH:
-					retval.type = VAL_I32;
-					retval.data.i = ((MonoString*)sp->data.p)->length;
-					/*g_print ("length of '%s' is %d\n", mono_string_to_utf8 (sp->data.p), retval.data.i);*/
-					break;
-				case INLINE_ARRAY_LENGTH:
-					retval.type = VAL_I32;
-					retval.data.i = mono_array_length ((MonoArray*)sp->data.p);
-					break;
-				case INLINE_ARRAY_RANK:
-					retval.type = VAL_I32;
-					retval.data.i = mono_object_class (sp->data.p)->rank;
-					break;
-				case INLINE_TYPE_ELEMENT_TYPE:
-					retval.type = VAL_OBJ;
-					{
-						MonoClass *c = mono_class_from_mono_type (((MonoReflectionType*)sp->data.p)->type);
-						retval.data.vt.klass = NULL;
-						if (c->enumtype && c->enum_basetype) /* types that are modifierd typebuilkders may not have enum_basetype set */
-							retval.data.p = mono_type_get_object (domain, c->enum_basetype);
-						else if (c->element_class)
-							retval.data.p = mono_type_get_object (domain, &c->element_class->byval_arg);
-						else
-							retval.data.p = NULL;
+				if (child_frame.method) {
+					switch (GPOINTER_TO_UINT (child_frame.method->addr)) {
+					case INLINE_STRING_LENGTH:
+						retval.type = VAL_I32;
+						retval.data.i = ((MonoString*)sp->data.p)->length;
+						/*g_print ("length of '%s' is %d\n", mono_string_to_utf8 (sp->data.p), retval.data.i);*/
+						break;
+					case INLINE_ARRAY_LENGTH:
+						retval.type = VAL_I32;
+						retval.data.i = mono_array_length ((MonoArray*)sp->data.p);
+						break;
+					case INLINE_ARRAY_RANK:
+						retval.type = VAL_I32;
+						retval.data.i = mono_object_class (sp->data.p)->rank;
+						break;
+					case INLINE_TYPE_ELEMENT_TYPE:
+						retval.type = VAL_OBJ;
+						{
+							MonoClass *c = mono_class_from_mono_type (((MonoReflectionType*)sp->data.p)->type);
+							retval.data.vt.klass = NULL;
+							if (c->enumtype && c->enum_basetype) /* types that are modifierd typebuilkders may not have enum_basetype set */
+								retval.data.p = mono_type_get_object (domain, c->enum_basetype);
+							else if (c->element_class)
+								retval.data.p = mono_type_get_object (domain, &c->element_class->byval_arg);
+							else
+								retval.data.p = NULL;
+						}
+						break;
+					default:
+						ves_exec_method (&child_frame);
 					}
-					break;
-				default:
-					ves_exec_method (&child_frame);
+				} else {
+					MonoPIFunc func;
+					g_assert (code);
+
+					func = (MonoPIFunc)mono_create_trampoline (csignature, FALSE);
+
+					func ((MonoFunc)code, &child_frame.retval->data.p, child_frame.obj, 
+					      child_frame.stack_args);
+					stackval_from_data (csignature->ret, child_frame.retval, 
+							    (char*)&child_frame.retval->data.p);
 				}
 			}
 
@@ -2557,7 +2398,12 @@
 			++ip;
 			token = read32 (ip);
 			ip += 4;
-			c = mono_class_get (image, token);
+
+			if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
+				c = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
+			else
+				c = mono_class_get (image, token);
+
 			addr = sp [-1].data.vt.vt;
 			vt_alloc (&c->byval_arg, &sp [-1]);
 			stackval_from_data (&c->byval_arg, &sp [-1], addr);
@@ -2762,7 +2608,10 @@
 			++ip;
 			token = read32 (ip);
 			
-			c = mono_class_get (image, token);
+			if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
+				c = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
+			else 
+				c = mono_class_get (image, token);
 			
 			o = sp [-1].data.p;
 			if (!o)
@@ -3072,7 +2921,10 @@
 			ip++;
 			token = read32 (ip);
 
-			class = mono_class_get (image, token);
+			if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
+				class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
+			else
+				class = mono_class_get (image, token);
 			g_assert (class != NULL);
 
 			sp [-1].type = VAL_OBJ;
@@ -3095,7 +2947,12 @@
 
 			ip++;
 			token = read32 (ip);
-			class = mono_class_get (image, token);
+
+			if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
+				class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
+			else
+				class = mono_class_get (image, token);
+
 			o = (MonoObject*) mono_array_new (domain, class, sp [-1].data.i);
 			ip += 4;
 
@@ -3590,6 +3447,150 @@
 			goto handle_finally;
 			BREAK;
 #endif
+		CASE (CEE_UNUSED41)
+			++ip;
+		        switch (*ip) {
+			case CEE_MONO_FUNC1: {
+				MonoMarshalConv conv;
+				++ip;
+
+				conv = *ip;
+
+				++ip;
+
+				sp--;
+
+				sp->type = VAL_I32;
+				sp->data.vt.klass = NULL;
+
+				switch (conv) {
+				case MONO_MARSHAL_CONV_STR_LPWSTR:
+					sp->data.p = mono_string_to_utf16 (sp->data.p);
+					break;
+				case MONO_MARSHAL_CONV_LPSTR_STR:
+					sp->data.p = mono_string_new_wrapper (sp->data.p);
+					break;
+				case MONO_MARSHAL_CONV_STR_LPTSTR:
+				case MONO_MARSHAL_CONV_STR_LPSTR:
+					sp->data.p = mono_string_to_utf8 (sp->data.p);
+					break;
+				case MONO_MARSHAL_CONV_STR_BSTR:
+					sp->data.p = mono_string_to_bstr (sp->data.p);
+					break;
+				case MONO_MARSHAL_CONV_STR_TBSTR:
+				case MONO_MARSHAL_CONV_STR_ANSIBSTR:
+					sp->data.p = mono_string_to_ansibstr (sp->data.p);
+					break;
+				case MONO_MARSHAL_CONV_SB_LPSTR:
+					sp->data.p = mono_string_builder_to_utf8 (sp->data.p);
+					break;
+				case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
+					sp->data.p = mono_array_to_savearray (sp->data.p);
+					break;
+				case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
+					sp->data.p = mono_array_to_lparray (sp->data.p);
+					break;
+				case MONO_MARSHAL_CONV_DEL_FTN:
+					sp->data.p = mono_delegate_to_ftnptr (sp->data.p);
+					break;
+				case MONO_MARSHAL_CONV_STRARRAY_STRLPARRAY:
+					sp->data.p = mono_marshal_string_array (sp->data.p);
+					break;
+				default:
+					g_assert_not_reached ();
+				}
+				sp++; 
+				break;
+			}
+			case CEE_MONO_PROC2: {
+				MonoMarshalConv conv;
+				++ip;
+				conv = *ip;
+				++ip;
+
+				sp -= 2;
+
+				switch (conv) {
+				case MONO_MARSHAL_CONV_LPSTR_SB:
+					mono_string_utf8_to_builder (sp [0].data.p, sp [1].data.p);
+					break;
+				case MONO_MARSHAL_FREE_ARRAY:
+					mono_marshal_free_array (sp [0].data.p, sp [1].data.p);
+					break;
+				default:
+					g_assert_not_reached ();
+				}				 
+				break;
+			}
+			case CEE_MONO_PROC3: {
+				MonoMarshalConv conv;
+				++ip;
+				conv = *ip;
+				++ip;
+
+				sp -= 3;
+
+				switch (conv) {
+				case MONO_MARSHAL_CONV_STR_BYVALSTR:
+					mono_string_to_byvalstr (sp [0].data.p, sp [1].data.p, sp [2].data.p);
+					break;
+				case MONO_MARSHAL_CONV_STR_BYVALWSTR:
+					mono_string_to_byvalwstr (sp [0].data.p, sp [1].data.p, sp [2].data.p);
+					break;
+				default:
+					g_assert_not_reached ();
+				}
+				break;
+			}
+			case CEE_MONO_VTADDR: {
+				++ip;
+
+				/* do nothing? */
+				break;
+			}
+			case CEE_MONO_LDPTR: {
+				guint32 token;
+				++ip;
+				
+				token = read32 (ip);
+				ip += 4;
+				
+				sp->type = VAL_I32;
+				sp->data.p = mono_method_get_wrapper_data (frame->method, token);
+				sp->data.vt.klass = NULL;
+				++sp;
+				break;
+			}
+			case CEE_MONO_FREE: {
+				++ip;
+
+				sp -= 1;
+				g_free (sp->data.p);
+				break;
+			}
+			case CEE_MONO_OBJADDR: {
+				++ip;
+
+				/* do nothing? */
+				break;
+			}
+			case CEE_MONO_NEWOBJ: {
+				MonoClass *class;
+				guint32 token;
+
+				++ip;
+				token = read32 (ip);
+				ip += 4;
+
+				class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
+				sp->data.p = mono_object_new (domain, class);
+				sp++;
+				break;
+			}
+			default:
+				g_error ("Unimplemented opcode: 0xF0 %02x at 0x%x\n", *ip, ip-header->code);
+			}
+			BREAK;
 		CASE (CEE_UNUSED26) 
 		CASE (CEE_UNUSED27) 
 		CASE (CEE_UNUSED28) 
@@ -3605,7 +3606,6 @@
 		CASE (CEE_UNUSED38) 
 		CASE (CEE_UNUSED39) 
 		CASE (CEE_UNUSED40) 
-		CASE (CEE_UNUSED41) 
 		CASE (CEE_UNUSED42) 
 		CASE (CEE_UNUSED43) 
 		CASE (CEE_UNUSED44) 
@@ -3741,7 +3741,12 @@
 				++ip;
 				token = read32 (ip);
 				ip += 4;
-				m = mono_get_method (image, token, NULL);
+
+				if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
+					m = (MonoMethod *)mono_method_get_wrapper_data (frame->method, token);
+				else 
+					m = mono_get_method (image, token, NULL);
+
 				if (!m)
 					THROW_EX (mono_get_exception_missing_method (), ip - 5);
 				if (virtual) {
@@ -3840,11 +3845,13 @@
 				break;
 			}
 			case CEE_LOCALLOC:
+				--sp;
 				if (sp != frame->stack)
 					THROW_EX (mono_get_exception_execution_engine (NULL), ip - 1);
 				++ip;
 				sp->data.p = alloca (sp->data.i);
 				sp->type = VAL_TP;
+				sp++;
 				break;
 			case CEE_UNUSED57: ves_abort(); break;
 			case CEE_ENDFILTER: ves_abort(); break;
@@ -4259,6 +4266,7 @@
 	frame_thread_id = TlsAlloc ();
 	TlsSetValue (frame_thread_id, NULL);
 
+	mono_install_compile_method (mono_create_method_pointer);
 	mono_install_runtime_invoke (interp_mono_runtime_invoke);
 	mono_install_remoting_trampoline (interp_create_remoting_trampoline);
 
Index: mono/interpreter/interp.h
===================================================================
RCS file: /cvs/public/mono/mono/interpreter/interp.h,v
retrieving revision 1.17
diff -u -r1.17 interp.h
--- mono/interpreter/interp.h	23 May 2002 07:44:00 -0000	1.17
+++ mono/interpreter/interp.h	26 Jul 2002 14:22:08 -0000
@@ -74,5 +74,5 @@
 /*
  * defined in an arch specific file.
  */
-MonoPIFunc mono_create_trampoline (MonoMethod *method, int runtime);
+MonoPIFunc mono_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor);
 void *mono_create_method_pointer (MonoMethod *method);