1 /**
2  * \file
3  * PLEASE NOTE: This is a research prototype.
4  *
5  *
6  * interp.c: Interpreter for CIL byte codes
7  *
8  * Authors:
9  *   Paolo Molaro (lupus@ximian.com)
10  *   Miguel de Icaza (miguel@ximian.com)
11  *   Dietmar Maurer (dietmar@ximian.com)
12  *
13  * (C) 2001, 2002 Ximian, Inc.
14  */
15 #ifndef __USE_ISOC99
16 #define __USE_ISOC99
17 #endif
18 #include "config.h"
19 
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <glib.h>
24 #include <signal.h>
25 #include <math.h>
26 #include <locale.h>
27 
28 #include <mono/utils/gc_wrapper.h>
29 
30 #ifdef HAVE_ALLOCA_H
31 #   include <alloca.h>
32 #else
33 #   ifdef __CYGWIN__
34 #      define alloca __builtin_alloca
35 #   endif
36 #endif
37 
38 /* trim excessive headers */
39 #include <mono/metadata/image.h>
40 #include <mono/metadata/assembly-internals.h>
41 #include <mono/metadata/cil-coff.h>
42 #include <mono/metadata/mono-endian.h>
43 #include <mono/metadata/tabledefs.h>
44 #include <mono/metadata/tokentype.h>
45 #include <mono/metadata/loader.h>
46 #include <mono/metadata/threads.h>
47 #include <mono/metadata/threadpool.h>
48 #include <mono/metadata/profiler-private.h>
49 #include <mono/metadata/appdomain.h>
50 #include <mono/metadata/reflection.h>
51 #include <mono/metadata/exception.h>
52 #include <mono/metadata/verify.h>
53 #include <mono/metadata/opcodes.h>
54 #include <mono/metadata/debug-helpers.h>
55 #include <mono/metadata/mono-config.h>
56 #include <mono/metadata/marshal.h>
57 #include <mono/metadata/environment.h>
58 #include <mono/metadata/mono-debug.h>
59 #include <mono/utils/atomic.h>
60 
61 #include "interp.h"
62 #include "interp-internals.h"
63 #include "mintops.h"
64 #include "hacks.h"
65 
66 #include <mono/mini/mini.h>
67 #include <mono/mini/mini-runtime.h>
68 #include <mono/mini/aot-runtime.h>
69 #include <mono/mini/jit-icalls.h>
70 #include <mono/mini/debugger-agent.h>
71 
72 #ifdef TARGET_ARM
73 #include <mono/mini/mini-arm.h>
74 #endif
75 
76 /* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */
77 #ifdef _WIN32
78 #define isnan _isnan
79 #define finite _finite
80 #endif
81 #ifndef HAVE_FINITE
82 #ifdef HAVE_ISFINITE
83 #define finite isfinite
84 #endif
85 #endif
86 
87 static inline void
init_frame(InterpFrame * frame,InterpFrame * parent_frame,InterpMethod * rmethod,stackval * method_args,stackval * method_retval)88 init_frame (InterpFrame *frame, InterpFrame *parent_frame, InterpMethod *rmethod, stackval *method_args, stackval *method_retval)
89 {
90 	frame->parent = parent_frame;
91 	frame->stack_args = method_args;
92 	frame->retval = method_retval;
93 	frame->imethod = rmethod;
94 	frame->ex = NULL;
95 	frame->ip = NULL;
96 	frame->invoke_trap = 0;
97 }
98 
99 #define INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error) do { \
100 	InterpMethod *_rmethod = mono_interp_get_imethod ((domain), (mono_method), (error));	\
101 	init_frame ((frame), (parent_frame), _rmethod, (method_args), (method_retval)); \
102 	} while (0)
103 
104 /*
105  * List of classes whose methods will be executed by transitioning to JITted code.
106  * Used for testing.
107  */
108 GSList *jit_classes;
109 /* If TRUE, interpreted code will be interrupted at function entry/backward branches */
110 static gboolean ss_enabled;
111 
112 static char* dump_frame (InterpFrame *inv);
113 static MonoArray *get_trace_ips (MonoDomain *domain, InterpFrame *top);
114 static void interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *start_with_ip, MonoException *filter_exception, int exit_at_finally, InterpFrame *base_frame);
115 static void interp_exec_method (InterpFrame *frame, ThreadContext *context);
116 
117 typedef void (*ICallMethod) (InterpFrame *frame);
118 
119 static MonoNativeTlsKey thread_context_id;
120 
121 static char* dump_args (InterpFrame *inv);
122 
123 #define DEBUG_INTERP 0
124 #define COUNT_OPS 0
125 #if DEBUG_INTERP
126 int mono_interp_traceopt = 2;
127 /* If true, then we output the opcodes as we interpret them */
128 static int global_tracing = 2;
129 
130 static int debug_indent_level = 0;
131 
132 static int break_on_method = 0;
133 static int nested_trace = 0;
134 static GList *db_methods = NULL;
135 
136 static void
output_indent(void)137 output_indent (void)
138 {
139 	int h;
140 
141 	for (h = 0; h < debug_indent_level; h++)
142 		g_print ("  ");
143 }
144 
145 static void
db_match_method(gpointer data,gpointer user_data)146 db_match_method (gpointer data, gpointer user_data)
147 {
148 	MonoMethod *m = (MonoMethod*)user_data;
149 	MonoMethodDesc *desc = data;
150 
151 	if (mono_method_desc_full_match (desc, m))
152 		break_on_method = 1;
153 }
154 
155 static void
debug_enter(InterpFrame * frame,int * tracing)156 debug_enter (InterpFrame *frame, int *tracing)
157 {
158 	if (db_methods) {
159 		g_list_foreach (db_methods, db_match_method, (gpointer)frame->imethod->method);
160 		if (break_on_method)
161 			*tracing = nested_trace ? (global_tracing = 2, 3) : 2;
162 		break_on_method = 0;
163 	}
164 	if (*tracing) {
165 		MonoMethod *method = frame->imethod->method;
166 		char *mn, *args = dump_args (frame);
167 		debug_indent_level++;
168 		output_indent ();
169 		mn = mono_method_full_name (method, FALSE);
170 		g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn);
171 		g_free (mn);
172 		g_print  ("%s)\n", args);
173 		g_free (args);
174 	}
175 }
176 
177 
178 #define DEBUG_LEAVE()	\
179 	if (tracing) {	\
180 		char *mn, *args;	\
181 		args = dump_retval (frame);	\
182 		output_indent ();	\
183 		mn = mono_method_full_name (frame->imethod->method, FALSE); \
184 		g_print  ("(%p) Leaving %s", mono_thread_internal_current (),  mn);	\
185 		g_free (mn); \
186 		g_print  (" => %s\n", args);	\
187 		g_free (args);	\
188 		debug_indent_level--;	\
189 		if (tracing == 3) global_tracing = 0; \
190 	}
191 
192 #else
193 
194 int mono_interp_traceopt = 0;
debug_enter(InterpFrame * frame,int * tracing)195 static void debug_enter (InterpFrame *frame, int *tracing)
196 {
197 }
198 #define DEBUG_LEAVE()
199 
200 #endif
201 
202 static void
set_resume_state(ThreadContext * context,InterpFrame * frame)203 set_resume_state (ThreadContext *context, InterpFrame *frame)
204 {
205 	frame->ex = NULL;
206 	context->has_resume_state = 0;
207 	context->handler_frame = NULL;
208 }
209 
210 /* Set the current execution state to the resume state in context */
211 #define SET_RESUME_STATE(context) do { \
212 		ip = (context)->handler_ip;						\
213 		/* spec says stack should be empty at endfinally so it should be at the start too */ \
214 		sp = frame->stack; \
215 		vt_sp = (unsigned char *) sp + rtm->stack_size; \
216 		if (frame->ex) { \
217 		sp->data.p = frame->ex;											\
218 		++sp;															\
219 		} \
220 		set_resume_state ((context), (frame));							\
221 		goto main_loop;													\
222 	} while (0)
223 
224 static void
set_context(ThreadContext * context)225 set_context (ThreadContext *context)
226 {
227 	MonoJitTlsData *jit_tls;
228 
229 	mono_native_tls_set_value (thread_context_id, context);
230 	jit_tls = mono_tls_get_jit_tls ();
231 	if (jit_tls)
232 		jit_tls->interp_context = context;
233 }
234 
235 static void
ves_real_abort(int line,MonoMethod * mh,const unsigned short * ip,stackval * stack,stackval * sp)236 ves_real_abort (int line, MonoMethod *mh,
237 		const unsigned short *ip, stackval *stack, stackval *sp)
238 {
239 	MonoError error;
240 	MonoMethodHeader *header = mono_method_get_header_checked (mh, &error);
241 	mono_error_cleanup (&error); /* FIXME: don't swallow the error */
242 	g_printerr ("Execution aborted in method: %s::%s\n", mh->klass->name, mh->name);
243 	g_printerr ("Line=%d IP=0x%04lx, Aborted execution\n", line, ip-(const unsigned short *) header->code);
244 	g_print ("0x%04x %02x\n", ip-(const unsigned short *) header->code, *ip);
245 	mono_metadata_free_mh (header);
246 	if (sp > stack)
247 		printf ("\t[%ld] 0x%08x %0.5f\n", sp-stack, sp[-1].data.i, sp[-1].data.f);
248 }
249 
250 #define ves_abort() \
251 	do {\
252 		ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
253 		THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
254 	} while (0);
255 
256 static InterpMethod*
lookup_imethod(MonoDomain * domain,MonoMethod * method)257 lookup_imethod (MonoDomain *domain, MonoMethod *method)
258 {
259 	InterpMethod *rtm;
260 	MonoJitDomainInfo *info;
261 
262 	info = domain_jit_info (domain);
263 	mono_domain_jit_code_hash_lock (domain);
264 	rtm = mono_internal_hash_table_lookup (&info->interp_code_hash, method);
265 	mono_domain_jit_code_hash_unlock (domain);
266 	return rtm;
267 }
268 
269 #ifndef DISABLE_REMOTING
270 static gpointer
interp_get_remoting_invoke(gpointer imethod,MonoError * error)271 interp_get_remoting_invoke (gpointer imethod, MonoError *error)
272 {
273 	InterpMethod *imethod_cast = (InterpMethod*) imethod;
274 
275 	g_assert (mono_use_interpreter);
276 
277 	return mono_interp_get_imethod (mono_domain_get (), mono_marshal_get_remoting_invoke (imethod_cast->method), error);
278 }
279 #endif
280 
281 InterpMethod*
mono_interp_get_imethod(MonoDomain * domain,MonoMethod * method,MonoError * error)282 mono_interp_get_imethod (MonoDomain *domain, MonoMethod *method, MonoError *error)
283 {
284 	InterpMethod *rtm;
285 	MonoJitDomainInfo *info;
286 	MonoMethodSignature *sig;
287 	int i;
288 
289 	error_init (error);
290 
291 	info = domain_jit_info (domain);
292 	mono_domain_jit_code_hash_lock (domain);
293 	rtm = mono_internal_hash_table_lookup (&info->interp_code_hash, method);
294 	mono_domain_jit_code_hash_unlock (domain);
295 	if (rtm)
296 		return rtm;
297 
298 	sig = mono_method_signature (method);
299 
300 	rtm = mono_domain_alloc0 (domain, sizeof (InterpMethod));
301 	rtm->method = method;
302 	rtm->domain = domain;
303 	rtm->param_count = sig->param_count;
304 	rtm->hasthis = sig->hasthis;
305 	rtm->rtype = mini_get_underlying_type (sig->ret);
306 	rtm->param_types = mono_domain_alloc0 (domain, sizeof (MonoType*) * sig->param_count);
307 	for (i = 0; i < sig->param_count; ++i)
308 		rtm->param_types [i] = mini_get_underlying_type (sig->params [i]);
309 
310 	mono_domain_jit_code_hash_lock (domain);
311 	if (!mono_internal_hash_table_lookup (&info->interp_code_hash, method))
312 		mono_internal_hash_table_insert (&info->interp_code_hash, method, rtm);
313 	mono_domain_jit_code_hash_unlock (domain);
314 
315 	rtm->prof_flags = mono_profiler_get_call_instrumentation_flags (rtm->method);
316 
317 	return rtm;
318 }
319 
320 static gpointer
interp_create_trampoline(MonoDomain * domain,MonoMethod * method,MonoError * error)321 interp_create_trampoline (MonoDomain *domain, MonoMethod *method, MonoError *error)
322 {
323 	if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
324 		method = mono_marshal_get_synchronized_wrapper (method);
325 	return mono_interp_get_imethod (domain, method, error);
326 }
327 
328 /*
329  * interp_push_lmf:
330  *
331  * Push an LMF frame on the LMF stack
332  * to mark the transition to native code.
333  * This is needed for the native code to
334  * be able to do stack walks.
335  */
336 static void
interp_push_lmf(MonoLMFExt * ext,InterpFrame * frame)337 interp_push_lmf (MonoLMFExt *ext, InterpFrame *frame)
338 {
339 	memset (ext, 0, sizeof (MonoLMFExt));
340 	ext->interp_exit = TRUE;
341 	ext->interp_exit_data = frame;
342 
343 	mono_push_lmf (ext);
344 }
345 
346 static void
interp_pop_lmf(MonoLMFExt * ext)347 interp_pop_lmf (MonoLMFExt *ext)
348 {
349 	mono_pop_lmf (&ext->lmf);
350 }
351 
352 static inline InterpMethod*
get_virtual_method(InterpMethod * imethod,MonoObject * obj)353 get_virtual_method (InterpMethod *imethod, MonoObject *obj)
354 {
355 	MonoMethod *m = imethod->method;
356 	MonoDomain *domain = imethod->domain;
357 	InterpMethod *ret = NULL;
358 	MonoError error;
359 
360 #ifndef DISABLE_REMOTING
361 	if (mono_object_is_transparent_proxy (obj)) {
362 		ret = mono_interp_get_imethod (domain, mono_marshal_get_remoting_invoke_with_check (m), &error);
363 		mono_error_assert_ok (&error);
364 		return ret;
365 	}
366 #endif
367 
368 	if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
369 		if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
370 			ret = mono_interp_get_imethod (domain, mono_marshal_get_synchronized_wrapper (m), &error);
371 			mono_error_cleanup (&error); /* FIXME: don't swallow the error */
372 		} else {
373 			ret = imethod;
374 		}
375 		return ret;
376 	}
377 
378 	mono_class_setup_vtable (obj->vtable->klass);
379 
380 	int slot = mono_method_get_vtable_slot (m);
381 	if (mono_class_is_interface (m->klass)) {
382 		g_assert (obj->vtable->klass != m->klass);
383 		/* TODO: interface offset lookup is slow, go through IMT instead */
384 		gboolean non_exact_match;
385 		slot += mono_class_interface_offset_with_variance (obj->vtable->klass, m->klass, &non_exact_match);
386 	}
387 
388 	MonoMethod *virtual_method = obj->vtable->klass->vtable [slot];
389 	if (m->is_inflated && mono_method_get_context (m)->method_inst) {
390 		MonoGenericContext context = { NULL, NULL };
391 
392 		if (mono_class_is_ginst (virtual_method->klass))
393 			context.class_inst = mono_class_get_generic_class (virtual_method->klass)->context.class_inst;
394 		else if (mono_class_is_gtd (virtual_method->klass))
395 			context.class_inst = mono_class_get_generic_container (virtual_method->klass)->context.class_inst;
396 		context.method_inst = mono_method_get_context (m)->method_inst;
397 
398 		virtual_method = mono_class_inflate_generic_method_checked (virtual_method, &context, &error);
399 		mono_error_cleanup (&error); /* FIXME: don't swallow the error */
400 	}
401 
402 	if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
403 		virtual_method = mono_marshal_get_synchronized_wrapper (virtual_method);
404 	}
405 
406 	InterpMethod *virtual_imethod = mono_interp_get_imethod (domain, virtual_method, &error);
407 	mono_error_cleanup (&error); /* FIXME: don't swallow the error */
408 	return virtual_imethod;
409 }
410 
411 static void inline
stackval_from_data(MonoType * type_,stackval * result,char * data,gboolean pinvoke)412 stackval_from_data (MonoType *type_, stackval *result, char *data, gboolean pinvoke)
413 {
414 	MonoType *type = mini_native_type_replace_type (type_);
415 	if (type->byref) {
416 		switch (type->type) {
417 		case MONO_TYPE_OBJECT:
418 		case MONO_TYPE_CLASS:
419 		case MONO_TYPE_STRING:
420 		case MONO_TYPE_ARRAY:
421 		case MONO_TYPE_SZARRAY:
422 			break;
423 		default:
424 			break;
425 		}
426 		result->data.p = *(gpointer*)data;
427 		return;
428 	}
429 	switch (type->type) {
430 	case MONO_TYPE_VOID:
431 		return;
432 	case MONO_TYPE_I1:
433 		result->data.i = *(gint8*)data;
434 		return;
435 	case MONO_TYPE_U1:
436 	case MONO_TYPE_BOOLEAN:
437 		result->data.i = *(guint8*)data;
438 		return;
439 	case MONO_TYPE_I2:
440 		result->data.i = *(gint16*)data;
441 		return;
442 	case MONO_TYPE_U2:
443 	case MONO_TYPE_CHAR:
444 		result->data.i = *(guint16*)data;
445 		return;
446 	case MONO_TYPE_I4:
447 		result->data.i = *(gint32*)data;
448 		return;
449 	case MONO_TYPE_U:
450 	case MONO_TYPE_I:
451 		result->data.nati = *(mono_i*)data;
452 		return;
453 	case MONO_TYPE_PTR:
454 		result->data.p = *(gpointer*)data;
455 		return;
456 	case MONO_TYPE_U4:
457 		result->data.i = *(guint32*)data;
458 		return;
459 	case MONO_TYPE_R4: {
460 		float tmp;
461 		/* memmove handles unaligned case */
462 		memmove (&tmp, data, sizeof (float));
463 		result->data.f = tmp;
464 		return;
465     }
466 	case MONO_TYPE_I8:
467 	case MONO_TYPE_U8:
468 		memmove (&result->data.l, data, sizeof (gint64));
469 		return;
470 	case MONO_TYPE_R8:
471 		memmove (&result->data.f, data, sizeof (double));
472 		return;
473 	case MONO_TYPE_STRING:
474 	case MONO_TYPE_SZARRAY:
475 	case MONO_TYPE_CLASS:
476 	case MONO_TYPE_OBJECT:
477 	case MONO_TYPE_ARRAY:
478 		result->data.p = *(gpointer*)data;
479 		return;
480 	case MONO_TYPE_VALUETYPE:
481 		if (type->data.klass->enumtype) {
482 			stackval_from_data (mono_class_enum_basetype (type->data.klass), result, data, pinvoke);
483 			return;
484 		} else
485 			mono_value_copy (result->data.vt, data, type->data.klass);
486 		return;
487 	case MONO_TYPE_GENERICINST: {
488 		if (mono_type_generic_inst_is_valuetype (type)) {
489 			mono_value_copy (result->data.vt, data, mono_class_from_mono_type (type));
490 			return;
491 		}
492 		stackval_from_data (&type->data.generic_class->container_class->byval_arg, result, data, pinvoke);
493 		return;
494 	}
495 	default:
496 		g_warning ("got type 0x%02x", type->type);
497 		g_assert_not_reached ();
498 	}
499 }
500 
501 static void inline
stackval_to_data(MonoType * type_,stackval * val,char * data,gboolean pinvoke)502 stackval_to_data (MonoType *type_, stackval *val, char *data, gboolean pinvoke)
503 {
504 	MonoType *type = mini_native_type_replace_type (type_);
505 	if (type->byref) {
506 		gpointer *p = (gpointer*)data;
507 		*p = val->data.p;
508 		return;
509 	}
510 	/* printf ("TODAT0 %p\n", data); */
511 	switch (type->type) {
512 	case MONO_TYPE_I1:
513 	case MONO_TYPE_U1: {
514 		guint8 *p = (guint8*)data;
515 		*p = val->data.i;
516 		return;
517 	}
518 	case MONO_TYPE_BOOLEAN: {
519 		guint8 *p = (guint8*)data;
520 		*p = (val->data.i != 0);
521 		return;
522 	}
523 	case MONO_TYPE_I2:
524 	case MONO_TYPE_U2:
525 	case MONO_TYPE_CHAR: {
526 		guint16 *p = (guint16*)data;
527 		*p = val->data.i;
528 		return;
529 	}
530 	case MONO_TYPE_I: {
531 		mono_i *p = (mono_i*)data;
532 		/* In theory the value used by stloc should match the local var type
533 	 	   but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
534 		   a native int - both by csc and mcs). Not sure what to do about sign extension
535 		   as it is outside the spec... doing the obvious */
536 		*p = (mono_i)val->data.nati;
537 		return;
538 	}
539 	case MONO_TYPE_U: {
540 		mono_u *p = (mono_u*)data;
541 		/* see above. */
542 		*p = (mono_u)val->data.nati;
543 		return;
544 	}
545 	case MONO_TYPE_I4:
546 	case MONO_TYPE_U4: {
547 		gint32 *p = (gint32*)data;
548 		*p = val->data.i;
549 		return;
550 	}
551 	case MONO_TYPE_I8:
552 	case MONO_TYPE_U8: {
553 		gint64 *p = (gint64*)data;
554 		*p = val->data.l;
555 		return;
556 	}
557 	case MONO_TYPE_R4: {
558 		float *p = (float*)data;
559 		*p = val->data.f;
560 		return;
561 	}
562 	case MONO_TYPE_R8: {
563 		double *p = (double*)data;
564 		*p = val->data.f;
565 		return;
566 	}
567 	case MONO_TYPE_STRING:
568 	case MONO_TYPE_SZARRAY:
569 	case MONO_TYPE_CLASS:
570 	case MONO_TYPE_OBJECT:
571 	case MONO_TYPE_ARRAY: {
572 		gpointer *p = (gpointer *) data;
573 		mono_gc_wbarrier_generic_store (p, val->data.p);
574 		return;
575 	}
576 	case MONO_TYPE_PTR: {
577 		gpointer *p = (gpointer *) data;
578 		*p = val->data.p;
579 		return;
580 	}
581 	case MONO_TYPE_VALUETYPE:
582 		if (type->data.klass->enumtype) {
583 			stackval_to_data (mono_class_enum_basetype (type->data.klass), val, data, pinvoke);
584 			return;
585 		} else
586 			mono_value_copy (data, val->data.vt, type->data.klass);
587 		return;
588 	case MONO_TYPE_GENERICINST: {
589 		MonoClass *container_class = type->data.generic_class->container_class;
590 
591 		if (container_class->valuetype && !container_class->enumtype) {
592 			mono_value_copy (data, val->data.vt, mono_class_from_mono_type (type));
593 			return;
594 		}
595 		stackval_to_data (&type->data.generic_class->container_class->byval_arg, val, data, pinvoke);
596 		return;
597 	}
598 	default:
599 		g_warning ("got type %x", type->type);
600 		g_assert_not_reached ();
601 	}
602 }
603 
604 /*
605  * interp_throw:
606  *   Throw an exception from the interpreter.
607  */
608 static void
interp_throw(ThreadContext * context,MonoException * ex,InterpFrame * frame,gconstpointer ip,gboolean rethrow)609 interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, gconstpointer ip, gboolean rethrow)
610 {
611 	MonoLMFExt ext;
612 
613 	interp_push_lmf (&ext, frame);
614 	frame->ip = ip;
615 	frame->ex = ex;
616 
617 	if (!rethrow) {
618 		ex->stack_trace = NULL;
619 		ex->trace_ips = NULL;
620 	}
621 
622 	MonoContext ctx;
623 	memset (&ctx, 0, sizeof (MonoContext));
624 	MONO_CONTEXT_SET_SP (&ctx, frame);
625 
626 	/*
627 	 * Call the JIT EH code. The EH code will call back to us using:
628 	 * - mono_interp_set_resume_state ()/run_finally ()/run_filter ().
629 	 * Since ctx.ip is 0, this will start unwinding from the LMF frame
630 	 * pushed above, which points to our frames.
631 	 */
632 	mono_handle_exception (&ctx, (MonoObject*)ex);
633 
634 	interp_pop_lmf (&ext);
635 
636 	g_assert (context->has_resume_state);
637 }
638 
639 static void
fill_in_trace(MonoException * exception,InterpFrame * frame)640 fill_in_trace (MonoException *exception, InterpFrame *frame)
641 {
642 	MonoError error;
643 	char *stack_trace = dump_frame (frame);
644 	MonoDomain *domain = frame->imethod->domain;
645 	(exception)->stack_trace = mono_string_new_checked (domain, stack_trace, &error);
646 	mono_error_cleanup (&error); /* FIXME: don't swallow the error */
647 	(exception)->trace_ips = get_trace_ips (domain, frame);
648 	g_free (stack_trace);
649 }
650 
651 #define FILL_IN_TRACE(exception, frame) fill_in_trace(exception, frame)
652 
653 #define THROW_EX_GENERAL(exception,ex_ip, rethrow)		\
654 	do {							\
655 		interp_throw (context, (exception), (frame), (ex_ip), (rethrow)); \
656 		if (frame == context->handler_frame) \
657 			SET_RESUME_STATE (context); \
658 		else \
659 			goto exit_frame; \
660 	} while (0)
661 
662 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
663 
664 /*
665  * Its possible for child_frame.ex to contain an unthrown exception, if the transform phase
666  * produced one.
667  */
668 #define CHECK_CHILD_EX(child_frame, ip) do { \
669 	if ((child_frame).ex) \
670 		THROW_EX ((child_frame).ex, (ip)); \
671 	} while (0)
672 
673 static MonoObject*
ves_array_create(InterpFrame * frame,MonoDomain * domain,MonoClass * klass,MonoMethodSignature * sig,stackval * values)674 ves_array_create (InterpFrame *frame, MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
675 {
676 	uintptr_t *lengths;
677 	intptr_t *lower_bounds;
678 	MonoObject *obj;
679 	MonoError error;
680 	int i;
681 
682 	lengths = alloca (sizeof (uintptr_t) * klass->rank * 2);
683 	for (i = 0; i < sig->param_count; ++i) {
684 		lengths [i] = values->data.i;
685 		values ++;
686 	}
687 	if (klass->rank == sig->param_count) {
688 		/* Only lengths provided. */
689 		lower_bounds = NULL;
690 	} else {
691 		/* lower bounds are first. */
692 		lower_bounds = (intptr_t *) lengths;
693 		lengths += klass->rank;
694 	}
695 	obj = (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, &error);
696 	if (!mono_error_ok (&error)) {
697 		frame->ex = mono_error_convert_to_exception (&error);
698 		FILL_IN_TRACE (frame->ex, frame);
699 	}
700 	mono_error_cleanup (&error); /* FIXME: don't swallow the error */
701 	return obj;
702 }
703 
704 static gint32
ves_array_calculate_index(MonoArray * ao,stackval * sp,InterpFrame * frame,gboolean safe)705 ves_array_calculate_index (MonoArray *ao, stackval *sp, InterpFrame *frame, gboolean safe)
706 {
707 	g_assert (!frame->ex);
708 	MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
709 
710 	guint32 pos = 0;
711 	if (ao->bounds) {
712 		for (gint32 i = 0; i < ac->rank; i++) {
713 			guint32 idx = sp [i].data.i;
714 			guint32 lower = ao->bounds [i].lower_bound;
715 			guint32 len = ao->bounds [i].length;
716 			if (safe && (idx < lower || (idx - lower) >= len)) {
717 				frame->ex = mono_get_exception_index_out_of_range ();
718 				FILL_IN_TRACE (frame->ex, frame);
719 				return -1;
720 			}
721 			pos = (pos * len) + idx - lower;
722 		}
723 	} else {
724 		pos = sp [0].data.i;
725 		if (safe && pos >= ao->max_length) {
726 			frame->ex = mono_get_exception_index_out_of_range ();
727 			FILL_IN_TRACE (frame->ex, frame);
728 			return -1;
729 		}
730 	}
731 	return pos;
732 }
733 
734 static void
ves_array_set(InterpFrame * frame)735 ves_array_set (InterpFrame *frame)
736 {
737 	stackval *sp = frame->stack_args + 1;
738 
739 	MonoObject *o = frame->stack_args->data.p;
740 	MonoArray *ao = (MonoArray *) o;
741 	MonoClass *ac = o->vtable->klass;
742 
743 	g_assert (ac->rank >= 1);
744 
745 	gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
746 	if (frame->ex)
747 		return;
748 
749 	if (sp [ac->rank].data.p && !mono_object_class (o)->element_class->valuetype) {
750 		MonoError error;
751 		MonoObject *isinst = mono_object_isinst_checked (sp [ac->rank].data.p, mono_object_class (o)->element_class, &error);
752 		mono_error_cleanup (&error);
753 		if (!isinst) {
754 			frame->ex = mono_get_exception_array_type_mismatch ();
755 			FILL_IN_TRACE (frame->ex, frame);
756 			return;
757 		}
758 	}
759 
760 	gint32 esize = mono_array_element_size (ac);
761 	gpointer ea = mono_array_addr_with_size (ao, esize, pos);
762 
763 	MonoType *mt = mono_method_signature (frame->imethod->method)->params [ac->rank];
764 	stackval_to_data (mt, &sp [ac->rank], ea, FALSE);
765 }
766 
767 static void
ves_array_get(InterpFrame * frame,gboolean safe)768 ves_array_get (InterpFrame *frame, gboolean safe)
769 {
770 	stackval *sp = frame->stack_args + 1;
771 
772 	MonoObject *o = frame->stack_args->data.p;
773 	MonoArray *ao = (MonoArray *) o;
774 	MonoClass *ac = o->vtable->klass;
775 
776 	g_assert (ac->rank >= 1);
777 
778 	gint32 pos = ves_array_calculate_index (ao, sp, frame, safe);
779 	if (frame->ex)
780 		return;
781 
782 	gint32 esize = mono_array_element_size (ac);
783 	gpointer ea = mono_array_addr_with_size (ao, esize, pos);
784 
785 	MonoType *mt = mono_method_signature (frame->imethod->method)->ret;
786 	stackval_from_data (mt, frame->retval, ea, FALSE);
787 }
788 
789 static gpointer
ves_array_element_address(InterpFrame * frame,MonoClass * required_type,MonoArray * ao,stackval * sp,gboolean needs_typecheck)790 ves_array_element_address (InterpFrame *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
791 {
792 	MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
793 
794 	g_assert (ac->rank >= 1);
795 
796 	gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
797 	if (frame->ex)
798 		return NULL;
799 
800 	if (needs_typecheck && !mono_class_is_assignable_from (mono_object_class ((MonoObject *) ao)->element_class, required_type->element_class)) {
801 		frame->ex = mono_get_exception_array_type_mismatch ();
802 		FILL_IN_TRACE (frame->ex, frame);
803 		return NULL;
804 	}
805 	gint32 esize = mono_array_element_size (ac);
806 	return mono_array_addr_with_size (ao, esize, pos);
807 }
808 
809 static void
interp_walk_stack_with_ctx(MonoInternalStackWalk func,MonoContext * ctx,MonoUnwindOptions options,void * user_data)810 interp_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUnwindOptions options, void *user_data)
811 {
812 	ThreadContext *context = mono_native_tls_get_value (thread_context_id);
813 
814 	if (!context)
815 		return;
816 
817 	InterpFrame *frame = context->current_frame;
818 
819 	while (frame) {
820 		MonoStackFrameInfo fi;
821 		memset (&fi, 0, sizeof (MonoStackFrameInfo));
822 
823 		/* TODO: hack to make some asserts happy. */
824 		fi.ji = (MonoJitInfo *) frame->imethod;
825 
826 		if (frame->imethod)
827 			fi.method = fi.actual_method = frame->imethod->method;
828 
829 		if (!fi.method || (fi.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (fi.method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
830 			fi.native_offset = -1;
831 			fi.type = FRAME_TYPE_MANAGED_TO_NATIVE;
832 		} else {
833 			fi.type = FRAME_TYPE_MANAGED;
834 			fi.native_offset = frame->ip - frame->imethod->code;
835 			if (!fi.method->wrapper_type)
836 				fi.managed = TRUE;
837 		}
838 
839 		if (func (&fi, ctx, user_data))
840 			return;
841 		frame = frame->parent;
842 	}
843 }
844 
845 static MonoPIFunc mono_interp_enter_icall_trampoline = NULL;
846 
build_args_from_sig(MonoMethodSignature * sig,InterpFrame * frame)847 static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, InterpFrame *frame)
848 {
849 	InterpMethodArguments *margs = g_malloc0 (sizeof (InterpMethodArguments));
850 
851 #ifdef TARGET_ARM
852 	g_assert (mono_arm_eabi_supported ());
853 	int i8_align = mono_arm_i8_align ();
854 #endif
855 
856 #ifdef TARGET_WASM
857 	margs->sig = sig;
858 #endif
859 
860 	if (sig->hasthis)
861 		margs->ilen++;
862 
863 	for (int i = 0; i < sig->param_count; i++) {
864 		guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
865 		switch (ptype) {
866 		case MONO_TYPE_BOOLEAN:
867 		case MONO_TYPE_CHAR:
868 		case MONO_TYPE_I1:
869 		case MONO_TYPE_U1:
870 		case MONO_TYPE_I2:
871 		case MONO_TYPE_U2:
872 		case MONO_TYPE_I4:
873 		case MONO_TYPE_U4:
874 		case MONO_TYPE_I:
875 		case MONO_TYPE_U:
876 		case MONO_TYPE_PTR:
877 		case MONO_TYPE_SZARRAY:
878 		case MONO_TYPE_CLASS:
879 		case MONO_TYPE_OBJECT:
880 		case MONO_TYPE_STRING:
881 		case MONO_TYPE_VALUETYPE:
882 		case MONO_TYPE_GENERICINST:
883 #if SIZEOF_VOID_P == 8
884 		case MONO_TYPE_I8:
885 		case MONO_TYPE_U8:
886 #endif
887 			margs->ilen++;
888 			break;
889 #if SIZEOF_VOID_P == 4
890 		case MONO_TYPE_I8:
891 		case MONO_TYPE_U8:
892 #ifdef TARGET_ARM
893 			/* pairs begin at even registers */
894 			if (i8_align == 8 && margs->ilen & 1)
895 				margs->ilen++;
896 #endif
897 			margs->ilen += 2;
898 			break;
899 #endif
900 		case MONO_TYPE_R4:
901 #if SIZEOF_VOID_P == 8
902 		case MONO_TYPE_R8:
903 #endif
904 			margs->flen++;
905 			break;
906 #if SIZEOF_VOID_P == 4
907 		case MONO_TYPE_R8:
908 			margs->flen += 2;
909 			break;
910 #endif
911 		default:
912 			g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
913 		}
914 	}
915 
916 	if (margs->ilen > 0)
917 		margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen);
918 
919 	if (margs->flen > 0)
920 		margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
921 
922 	if (margs->ilen > INTERP_ICALL_TRAMP_IARGS)
923 		g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
924 
925 	if (margs->flen > INTERP_ICALL_TRAMP_FARGS)
926 		g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen);
927 
928 
929 	size_t int_i = 0;
930 	size_t int_f = 0;
931 
932 	if (sig->hasthis) {
933 		margs->iargs [0] = frame->stack_args->data.p;
934 		int_i++;
935 	}
936 
937 	for (int i = 0; i < sig->param_count; i++) {
938 		guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
939 		switch (ptype) {
940 		case MONO_TYPE_BOOLEAN:
941 		case MONO_TYPE_CHAR:
942 		case MONO_TYPE_I1:
943 		case MONO_TYPE_U1:
944 		case MONO_TYPE_I2:
945 		case MONO_TYPE_U2:
946 		case MONO_TYPE_I4:
947 		case MONO_TYPE_U4:
948 		case MONO_TYPE_I:
949 		case MONO_TYPE_U:
950 		case MONO_TYPE_PTR:
951 		case MONO_TYPE_SZARRAY:
952 		case MONO_TYPE_CLASS:
953 		case MONO_TYPE_OBJECT:
954 		case MONO_TYPE_STRING:
955 		case MONO_TYPE_VALUETYPE:
956 		case MONO_TYPE_GENERICINST:
957 #if SIZEOF_VOID_P == 8
958 		case MONO_TYPE_I8:
959 		case MONO_TYPE_U8:
960 #endif
961 			margs->iargs [int_i] = frame->stack_args [i].data.p;
962 #if DEBUG_INTERP
963 			g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
964 #endif
965 			int_i++;
966 			break;
967 #if SIZEOF_VOID_P == 4
968 		case MONO_TYPE_I8:
969 		case MONO_TYPE_U8: {
970 			stackval *sarg = &frame->stack_args [i];
971 #ifdef TARGET_ARM
972 			/* pairs begin at even registers */
973 			if (i8_align == 8 && int_i & 1)
974 				int_i++;
975 #endif
976 			margs->iargs [int_i] = (gpointer) sarg->data.pair.lo;
977 			int_i++;
978 			margs->iargs [int_i] = (gpointer) sarg->data.pair.hi;
979 #if DEBUG_INTERP
980 			g_print ("build_args_from_sig: margs->iargs [%d/%d]: 0x%016llx, hi=0x%08x lo=0x%08x (frame @ %d)\n", int_i - 1, int_i, *((guint64 *) &margs->iargs [int_i - 1]), sarg->data.pair.hi, sarg->data.pair.lo, i);
981 #endif
982 			int_i++;
983 			break;
984 		}
985 #endif
986 		case MONO_TYPE_R4:
987 		case MONO_TYPE_R8:
988 			if (ptype == MONO_TYPE_R4)
989 				* (float *) &(margs->fargs [int_f]) = (float) frame->stack_args [i].data.f;
990 			else
991 				margs->fargs [int_f] = frame->stack_args [i].data.f;
992 #if DEBUG_INTERP
993 			g_print ("build_args_from_sig: margs->fargs [%d]: %p (%f) (frame @ %d)\n", int_f, margs->fargs [int_f], margs->fargs [int_f], i);
994 #endif
995 #if SIZEOF_VOID_P == 4
996 			int_f += 2;
997 #else
998 			int_f++;
999 #endif
1000 			break;
1001 		default:
1002 			g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
1003 		}
1004 	}
1005 
1006 	switch (sig->ret->type) {
1007 		case MONO_TYPE_BOOLEAN:
1008 		case MONO_TYPE_CHAR:
1009 		case MONO_TYPE_I1:
1010 		case MONO_TYPE_U1:
1011 		case MONO_TYPE_I2:
1012 		case MONO_TYPE_U2:
1013 		case MONO_TYPE_I4:
1014 		case MONO_TYPE_U4:
1015 		case MONO_TYPE_I:
1016 		case MONO_TYPE_U:
1017 		case MONO_TYPE_PTR:
1018 		case MONO_TYPE_SZARRAY:
1019 		case MONO_TYPE_CLASS:
1020 		case MONO_TYPE_OBJECT:
1021 		case MONO_TYPE_STRING:
1022 		case MONO_TYPE_I8:
1023 		case MONO_TYPE_U8:
1024 		case MONO_TYPE_VALUETYPE:
1025 		case MONO_TYPE_GENERICINST:
1026 			margs->retval = &(frame->retval->data.p);
1027 			margs->is_float_ret = 0;
1028 			break;
1029 		case MONO_TYPE_R4:
1030 		case MONO_TYPE_R8:
1031 			margs->retval = &(frame->retval->data.p);
1032 			margs->is_float_ret = 1;
1033 			break;
1034 		case MONO_TYPE_VOID:
1035 			margs->retval = NULL;
1036 			break;
1037 		default:
1038 			g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type);
1039 	}
1040 
1041 	return margs;
1042 }
1043 
1044 static void
ves_pinvoke_method(InterpFrame * frame,MonoMethodSignature * sig,MonoFuncV addr,gboolean string_ctor,ThreadContext * context)1045 ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context)
1046 {
1047 	MonoLMFExt ext;
1048 
1049 	frame->ex = NULL;
1050 
1051 	g_assert (!frame->imethod);
1052 	if (!mono_interp_enter_icall_trampoline) {
1053 		if (mono_aot_only) {
1054 			mono_interp_enter_icall_trampoline = mono_aot_get_trampoline ("enter_icall_trampoline");
1055 		} else {
1056 			MonoTrampInfo *info;
1057 			mono_interp_enter_icall_trampoline = mono_arch_get_enter_icall_trampoline (&info);
1058 			// TODO:
1059 			// mono_tramp_info_register (info, NULL);
1060 		}
1061 	}
1062 
1063 	InterpMethodArguments *margs = build_args_from_sig (sig, frame);
1064 #if DEBUG_INTERP
1065 	g_print ("ICALL: mono_interp_enter_icall_trampoline = %p, addr = %p\n", mono_interp_enter_icall_trampoline, addr);
1066 	g_print ("margs(out): ilen=%d, flen=%d\n", margs->ilen, margs->flen);
1067 #endif
1068 
1069 	context->current_frame = frame;
1070 
1071 	interp_push_lmf (&ext, frame);
1072 	mono_interp_enter_icall_trampoline (addr, margs);
1073 	interp_pop_lmf (&ext);
1074 
1075 	if (*mono_thread_interruption_request_flag ()) {
1076 		MonoException *exc = mono_thread_interruption_checkpoint ();
1077 		if (exc) {
1078 			frame->ex = exc;
1079 			context->search_for_handler = 1;
1080 		}
1081 	}
1082 
1083 	if (!frame->ex && !MONO_TYPE_ISSTRUCT (sig->ret))
1084 		stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
1085 
1086 	g_free (margs->iargs);
1087 	g_free (margs->fargs);
1088 	g_free (margs);
1089 }
1090 
1091 static void
interp_init_delegate(MonoDelegate * del)1092 interp_init_delegate (MonoDelegate *del)
1093 {
1094 	if (del->method)
1095 		return;
1096 	/* shouldn't need a write barrier because we don't write a MonoObject into the field */
1097 	del->method = ((InterpMethod *) del->method_ptr)->method;
1098 }
1099 
1100 /*
1101  * From the spec:
1102  * runtime specifies that the implementation of the method is automatically
1103  * provided by the runtime and is primarily used for the methods of delegates.
1104  */
1105 static void
ves_imethod(InterpFrame * frame,ThreadContext * context)1106 ves_imethod (InterpFrame *frame, ThreadContext *context)
1107 {
1108 	MonoMethod *method = frame->imethod->method;
1109 	const char *name = method->name;
1110 	MonoObject *obj = (MonoObject*) frame->stack_args->data.p;
1111 	MonoObject *isinst_obj;
1112 	MonoError error;
1113 
1114 	mono_class_init (method->klass);
1115 
1116 	if (method->klass == mono_defaults.array_class) {
1117 		if (!strcmp (method->name, "UnsafeMov")) {
1118 			/* TODO: layout checks */
1119 			MonoType *mt = mono_method_signature (method)->ret;
1120 			stackval_from_data (mt, frame->retval, (char *) frame->stack_args, FALSE);
1121 			return;
1122 		}
1123 		if (!strcmp (method->name, "UnsafeLoad")) {
1124 			ves_array_get (frame, FALSE);
1125 			return;
1126 		}
1127 	}
1128 
1129 	isinst_obj = mono_object_isinst_checked (obj, mono_defaults.array_class, &error);
1130 	mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1131 	if (obj && isinst_obj) {
1132 		if (*name == 'S' && (strcmp (name, "Set") == 0)) {
1133 			ves_array_set (frame);
1134 			return;
1135 		}
1136 		if (*name == 'G' && (strcmp (name, "Get") == 0)) {
1137 			ves_array_get (frame, TRUE);
1138 			return;
1139 		}
1140 	}
1141 
1142 	g_error ("Don't know how to exec runtime method %s.%s::%s",
1143 			method->klass->name_space, method->klass->name,
1144 			method->name);
1145 }
1146 
1147 #if DEBUG_INTERP
1148 static char*
dump_stack(stackval * stack,stackval * sp)1149 dump_stack (stackval *stack, stackval *sp)
1150 {
1151 	stackval *s = stack;
1152 	GString *str = g_string_new ("");
1153 
1154 	if (sp == stack)
1155 		return g_string_free (str, FALSE);
1156 
1157 	while (s < sp) {
1158 		g_string_append_printf (str, "[%p (%lld)] ", s->data.l, s->data.l);
1159 		++s;
1160 	}
1161 	return g_string_free (str, FALSE);
1162 }
1163 #endif
1164 
1165 static void
dump_stackval(GString * str,stackval * s,MonoType * type)1166 dump_stackval (GString *str, stackval *s, MonoType *type)
1167 {
1168 	switch (type->type) {
1169 	case MONO_TYPE_I1:
1170 	case MONO_TYPE_U1:
1171 	case MONO_TYPE_I2:
1172 	case MONO_TYPE_U2:
1173 	case MONO_TYPE_I4:
1174 	case MONO_TYPE_U4:
1175 	case MONO_TYPE_CHAR:
1176 	case MONO_TYPE_BOOLEAN:
1177 		g_string_append_printf (str, "[%d] ", s->data.i);
1178 		break;
1179 	case MONO_TYPE_STRING:
1180 	case MONO_TYPE_SZARRAY:
1181 	case MONO_TYPE_CLASS:
1182 	case MONO_TYPE_OBJECT:
1183 	case MONO_TYPE_ARRAY:
1184 	case MONO_TYPE_PTR:
1185 	case MONO_TYPE_I:
1186 	case MONO_TYPE_U:
1187 		g_string_append_printf (str, "[%p] ", s->data.p);
1188 		break;
1189 	case MONO_TYPE_VALUETYPE:
1190 		if (type->data.klass->enumtype)
1191 			g_string_append_printf (str, "[%d] ", s->data.i);
1192 		else
1193 			g_string_append_printf (str, "[vt:%p] ", s->data.p);
1194 		break;
1195 	case MONO_TYPE_R4:
1196 	case MONO_TYPE_R8:
1197 		g_string_append_printf (str, "[%g] ", s->data.f);
1198 		break;
1199 	case MONO_TYPE_I8:
1200 	case MONO_TYPE_U8:
1201 	default: {
1202 		GString *res = g_string_new ("");
1203 		mono_type_get_desc (res, type, TRUE);
1204 		g_string_append_printf (str, "[{%s} %lld/0x%0llx] ", res->str, s->data.l, s->data.l);
1205 		g_string_free (res, TRUE);
1206 		break;
1207 	}
1208 	}
1209 }
1210 
1211 #if DEBUG_INTERP
1212 static char*
dump_retval(InterpFrame * inv)1213 dump_retval (InterpFrame *inv)
1214 {
1215 	GString *str = g_string_new ("");
1216 	MonoType *ret = mono_method_signature (inv->imethod->method)->ret;
1217 
1218 	if (ret->type != MONO_TYPE_VOID)
1219 		dump_stackval (str, inv->retval, ret);
1220 
1221 	return g_string_free (str, FALSE);
1222 }
1223 #endif
1224 
1225 static char*
dump_args(InterpFrame * inv)1226 dump_args (InterpFrame *inv)
1227 {
1228 	GString *str = g_string_new ("");
1229 	int i;
1230 	MonoMethodSignature *signature = mono_method_signature (inv->imethod->method);
1231 
1232 	if (signature->param_count == 0 && !signature->hasthis)
1233 		return g_string_free (str, FALSE);
1234 
1235 	if (signature->hasthis) {
1236 		MonoMethod *method = inv->imethod->method;
1237 		dump_stackval (str, inv->stack_args, &method->klass->byval_arg);
1238 	}
1239 
1240 	for (i = 0; i < signature->param_count; ++i)
1241 		dump_stackval (str, inv->stack_args + (!!signature->hasthis) + i, signature->params [i]);
1242 
1243 	return g_string_free (str, FALSE);
1244 }
1245 
1246 static char*
dump_frame(InterpFrame * inv)1247 dump_frame (InterpFrame *inv)
1248 {
1249 	GString *str = g_string_new ("");
1250 	int i;
1251 	char *args;
1252 	MonoError error;
1253 
1254 	for (i = 0; inv; inv = inv->parent) {
1255 		if (inv->imethod != NULL) {
1256 			MonoMethod *method = inv->imethod->method;
1257 			MonoClass *k;
1258 
1259 			int codep = 0;
1260 			const char * opname = "";
1261 			char *name;
1262 			gchar *source = NULL;
1263 
1264 			k = method->klass;
1265 
1266 			if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 &&
1267 				(method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) == 0) {
1268 				MonoMethodHeader *hd = mono_method_get_header_checked (method, &error);
1269 				mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1270 
1271 				if (hd != NULL) {
1272 					if (inv->ip) {
1273 						opname = mono_interp_opname [*inv->ip];
1274 						codep = inv->ip - inv->imethod->code;
1275 						source = g_strdup_printf ("%s:%d // (TODO: proper stacktrace)", method->name, codep);
1276 					} else
1277 						opname = "";
1278 
1279 #if 0
1280 					MonoDebugSourceLocation *minfo = mono_debug_lookup_method (method);
1281 					source = mono_debug_method_lookup_location (minfo, codep);
1282 #endif
1283 					mono_metadata_free_mh (hd);
1284 				}
1285 			}
1286 			args = dump_args (inv);
1287 			name = mono_method_full_name (method, TRUE);
1288 			if (source)
1289 				g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s) at %s\n", i, codep, opname, name, args, source);
1290 			else
1291 				g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s)\n", i, codep, opname, name, args);
1292 			g_free (name);
1293 			g_free (args);
1294 			g_free (source);
1295 			++i;
1296 		}
1297 	}
1298 	return g_string_free (str, FALSE);
1299 }
1300 
1301 static MonoArray *
get_trace_ips(MonoDomain * domain,InterpFrame * top)1302 get_trace_ips (MonoDomain *domain, InterpFrame *top)
1303 {
1304 	int i;
1305 	MonoArray *res;
1306 	InterpFrame *inv;
1307 	MonoError error;
1308 
1309 	for (i = 0, inv = top; inv; inv = inv->parent)
1310 		if (inv->imethod != NULL)
1311 			++i;
1312 
1313 	res = mono_array_new_checked (domain, mono_defaults.int_class, 3 * i, &error);
1314 	mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1315 
1316 	for (i = 0, inv = top; inv; inv = inv->parent)
1317 		if (inv->imethod != NULL) {
1318 			mono_array_set (res, gpointer, i, inv->imethod);
1319 			++i;
1320 			mono_array_set (res, gpointer, i, (gpointer)inv->ip);
1321 			++i;
1322 			mono_array_set (res, gpointer, i, NULL);
1323 			++i;
1324 		}
1325 
1326 	return res;
1327 }
1328 
1329 
1330 #define MYGUINT64_MAX 18446744073709551615ULL
1331 #define MYGINT64_MAX 9223372036854775807LL
1332 #define MYGINT64_MIN (-MYGINT64_MAX -1LL)
1333 
1334 #define MYGUINT32_MAX 4294967295U
1335 #define MYGINT32_MAX 2147483647
1336 #define MYGINT32_MIN (-MYGINT32_MAX -1)
1337 
1338 #define CHECK_ADD_OVERFLOW(a,b) \
1339 	(gint32)(b) >= 0 ? (gint32)(MYGINT32_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0	\
1340 	: (gint32)(MYGINT32_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0
1341 
1342 #define CHECK_SUB_OVERFLOW(a,b) \
1343 	(gint32)(b) < 0 ? (gint32)(MYGINT32_MAX) + (gint32)(b) < (gint32)(a) ? -1 : 0	\
1344 	: (gint32)(MYGINT32_MIN) + (gint32)(b) > (gint32)(a) ? +1 : 0
1345 
1346 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1347 	(guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1348 
1349 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1350 	(guint32)(a) < (guint32)(b) ? -1 : 0
1351 
1352 #define CHECK_ADD_OVERFLOW64(a,b) \
1353 	(gint64)(b) >= 0 ? (gint64)(MYGINT64_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0	\
1354 	: (gint64)(MYGINT64_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0
1355 
1356 #define CHECK_SUB_OVERFLOW64(a,b) \
1357 	(gint64)(b) < 0 ? (gint64)(MYGINT64_MAX) + (gint64)(b) < (gint64)(a) ? -1 : 0	\
1358 	: (gint64)(MYGINT64_MIN) + (gint64)(b) > (gint64)(a) ? +1 : 0
1359 
1360 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1361 	(guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
1362 
1363 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1364 	(guint64)(a) < (guint64)(b) ? -1 : 0
1365 
1366 #if SIZEOF_VOID_P == 4
1367 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1368 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1369 #else
1370 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1371 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1372 #endif
1373 
1374 /* Resolves to TRUE if the operands would overflow */
1375 #define CHECK_MUL_OVERFLOW(a,b) \
1376 	((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1377 	(((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1378 	(((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == - MYGINT32_MAX) : \
1379 	(((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((MYGINT32_MAX) / (gint32)(b)) : \
1380 	(((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((MYGINT32_MIN) / (gint32)(b)) : \
1381 	(((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((MYGINT32_MIN) / (gint32)(b)) : \
1382 	(gint32)(a) < ((MYGINT32_MAX) / (gint32)(b))
1383 
1384 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1385 	((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1386 	(guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1387 
1388 #define CHECK_MUL_OVERFLOW64(a,b) \
1389 	((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1390 	(((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1391 	(((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == - MYGINT64_MAX) : \
1392 	(((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((MYGINT64_MAX) / (gint64)(b)) : \
1393 	(((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((MYGINT64_MIN) / (gint64)(b)) : \
1394 	(((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((MYGINT64_MIN) / (gint64)(b)) : \
1395 	(gint64)(a) < ((MYGINT64_MAX) / (gint64)(b))
1396 
1397 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1398 	((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1399 	(guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a))
1400 
1401 #if SIZEOF_VOID_P == 4
1402 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1403 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1404 #else
1405 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1406 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1407 #endif
1408 
1409 static MonoObject*
interp_runtime_invoke(MonoMethod * method,void * obj,void ** params,MonoObject ** exc,MonoError * error)1410 interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
1411 {
1412 	InterpFrame frame, *old_frame;
1413 	ThreadContext * volatile context = mono_native_tls_get_value (thread_context_id);
1414 	MonoMethodSignature *sig = mono_method_signature (method);
1415 	MonoClass *klass = mono_class_from_mono_type (sig->ret);
1416 	stackval result;
1417 	stackval *args;
1418 	ThreadContext context_struct;
1419 
1420 	error_init (error);
1421 	if (exc)
1422 		*exc = NULL;
1423 
1424 	frame.ex = NULL;
1425 
1426 	if (context == NULL) {
1427 		context = &context_struct;
1428 		memset (context, 0, sizeof (ThreadContext));
1429 		set_context (context);
1430 	} else {
1431 		old_frame = context->current_frame;
1432 	}
1433 
1434 	MonoDomain *domain = mono_domain_get ();
1435 
1436 	MonoMethod *invoke_wrapper = mono_marshal_get_runtime_invoke_full (method, FALSE, TRUE);
1437 
1438 	//* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1439 
1440 	result.data.vt = alloca (mono_class_instance_size (klass));
1441 	args = alloca (sizeof (stackval) * 4);
1442 
1443 	if (sig->hasthis)
1444 		args [0].data.p = obj;
1445 	else
1446 		args [0].data.p = NULL;
1447 	args [1].data.p = params;
1448 	args [2].data.p = exc;
1449 	args [3].data.p = method;
1450 
1451 	INIT_FRAME (&frame, context->current_frame, args, &result, domain, invoke_wrapper, error);
1452 
1453 	if (exc)
1454 		frame.invoke_trap = 1;
1455 
1456 	interp_exec_method (&frame, context);
1457 
1458 	if (context == &context_struct)
1459 		set_context (NULL);
1460 	else
1461 		context->current_frame = old_frame;
1462 
1463 	if (frame.ex) {
1464 		if (exc) {
1465 			*exc = (MonoObject*) frame.ex;
1466 			return NULL;
1467 		}
1468 		mono_error_set_exception_instance (error, frame.ex);
1469 		return NULL;
1470 	}
1471 	return result.data.p;
1472 }
1473 
1474 typedef struct {
1475 	InterpMethod *rmethod;
1476 	gpointer this_arg;
1477 	gpointer res;
1478 	gpointer args [16];
1479 	gpointer *many_args;
1480 } InterpEntryData;
1481 
1482 /* Main function for entering the interpreter from compiled code */
1483 static void
interp_entry(InterpEntryData * data)1484 interp_entry (InterpEntryData *data)
1485 {
1486 	InterpFrame frame;
1487 	InterpMethod *rmethod = data->rmethod;
1488 	ThreadContext *context = mono_native_tls_get_value (thread_context_id);
1489 	ThreadContext context_struct;
1490 	InterpFrame *old_frame;
1491 	stackval result;
1492 	stackval *args;
1493 	MonoMethod *method;
1494 	MonoMethodSignature *sig;
1495 	MonoType *type;
1496 	int i;
1497 
1498 	method = rmethod->method;
1499 	sig = mono_method_signature (method);
1500 
1501 	// FIXME: Optimize this
1502 
1503 	//printf ("%s\n", mono_method_full_name (method, 1));
1504 
1505 	frame.ex = NULL;
1506 	if (context == NULL) {
1507 		context = &context_struct;
1508 		memset (context, 0, sizeof (ThreadContext));
1509 		set_context (context);
1510 	} else {
1511 		old_frame = context->current_frame;
1512 	}
1513 
1514 	args = alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
1515 	if (sig->hasthis)
1516 		args [0].data.p = data->this_arg;
1517 
1518 	gpointer *params;
1519 	if (data->many_args)
1520 		params = data->many_args;
1521 	else
1522 		params = data->args;
1523 	for (i = 0; i < sig->param_count; ++i) {
1524 		int a_index = i + (sig->hasthis ? 1 : 0);
1525 		if (sig->params [i]->byref) {
1526 			args [a_index].data.p = params [i];
1527 			continue;
1528 		}
1529 		type = rmethod->param_types [i];
1530 		switch (type->type) {
1531 		case MONO_TYPE_U1:
1532 		case MONO_TYPE_I1:
1533 			args [a_index].data.i = *(MonoBoolean*)params [i];
1534 			break;
1535 		case MONO_TYPE_U2:
1536 		case MONO_TYPE_I2:
1537 			args [a_index].data.i = *(gint16*)params [i];
1538 			break;
1539 		case MONO_TYPE_U:
1540 #if SIZEOF_VOID_P == 4
1541 			args [a_index].data.p = GINT_TO_POINTER (*(guint32*)params [i]);
1542 #else
1543 			args [a_index].data.p = GINT_TO_POINTER (*(guint64*)params [i]);
1544 #endif
1545 			break;
1546 		case MONO_TYPE_I:
1547 #if SIZEOF_VOID_P == 4
1548 			args [a_index].data.p = GINT_TO_POINTER (*(gint32*)params [i]);
1549 #else
1550 			args [a_index].data.p = GINT_TO_POINTER (*(gint64*)params [i]);
1551 #endif
1552 			break;
1553 		case MONO_TYPE_U4:
1554 			args [a_index].data.i = *(guint32*)params [i];
1555 			break;
1556 		case MONO_TYPE_I4:
1557 			args [a_index].data.i = *(gint32*)params [i];
1558 			break;
1559 		case MONO_TYPE_U8:
1560 			args [a_index].data.l = *(guint64*)params [i];
1561 			break;
1562 		case MONO_TYPE_I8:
1563 			args [a_index].data.l = *(gint64*)params [i];
1564 			break;
1565 		case MONO_TYPE_PTR:
1566 		case MONO_TYPE_OBJECT:
1567 			args [a_index].data.p = *(MonoObject**)params [i];
1568 			break;
1569 		case MONO_TYPE_VALUETYPE:
1570 			args [a_index].data.p = params [i];
1571 			break;
1572 		case MONO_TYPE_GENERICINST:
1573 			if (MONO_TYPE_IS_REFERENCE (type))
1574 				args [a_index].data.p = params [i];
1575 			else
1576 				args [a_index].data.vt = params [i];
1577 			break;
1578 		default:
1579 			printf ("%s\n", mono_type_full_name (sig->params [i]));
1580 			NOT_IMPLEMENTED;
1581 			break;
1582 		}
1583 	}
1584 
1585 	init_frame (&frame, NULL, data->rmethod, args, &result);
1586 
1587 	type = rmethod->rtype;
1588 	switch (type->type) {
1589 	case MONO_TYPE_GENERICINST:
1590 		if (!MONO_TYPE_IS_REFERENCE (type))
1591 			frame.retval->data.vt = data->res;
1592 		break;
1593 	case MONO_TYPE_VALUETYPE:
1594 		frame.retval->data.vt = data->res;
1595 		break;
1596 	default:
1597 		break;
1598 	}
1599 
1600 	interp_exec_method (&frame, context);
1601 	if (context == &context_struct)
1602 		set_context (NULL);
1603 	else
1604 		context->current_frame = old_frame;
1605 
1606 	// FIXME:
1607 	g_assert (frame.ex == NULL);
1608 
1609 	type = rmethod->rtype;
1610 	switch (type->type) {
1611 	case MONO_TYPE_VOID:
1612 		break;
1613 	case MONO_TYPE_I1:
1614 		*(gint8*)data->res = frame.retval->data.i;
1615 		break;
1616 	case MONO_TYPE_U1:
1617 		*(guint8*)data->res = frame.retval->data.i;
1618 		break;
1619 	case MONO_TYPE_I2:
1620 		*(gint16*)data->res = frame.retval->data.i;
1621 		break;
1622 	case MONO_TYPE_U2:
1623 		*(guint16*)data->res = frame.retval->data.i;
1624 		break;
1625 	case MONO_TYPE_I4:
1626 		*(gint32*)data->res = frame.retval->data.i;
1627 		break;
1628 	case MONO_TYPE_U4:
1629 		*(guint64*)data->res = frame.retval->data.i;
1630 		break;
1631 	case MONO_TYPE_I8:
1632 		*(gint64*)data->res = frame.retval->data.i;
1633 		break;
1634 	case MONO_TYPE_U8:
1635 		*(guint64*)data->res = frame.retval->data.i;
1636 		break;
1637 	case MONO_TYPE_I:
1638 #if SIZEOF_VOID_P == 8
1639 		*(gint64*)data->res = (gint64)frame.retval->data.p;
1640 #else
1641 		*(gint32*)data->res = (gint32)frame.retval->data.p;
1642 #endif
1643 		break;
1644 	case MONO_TYPE_U:
1645 #if SIZEOF_VOID_P == 8
1646 		*(guint64*)data->res = (guint64)frame.retval->data.p;
1647 #else
1648 		*(guint32*)data->res = (guint32)frame.retval->data.p;
1649 #endif
1650 		break;
1651 	case MONO_TYPE_OBJECT:
1652 		/* No need for a write barrier */
1653 		*(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1654 		break;
1655 	case MONO_TYPE_GENERICINST:
1656 		if (MONO_TYPE_IS_REFERENCE (type)) {
1657 			*(MonoObject**)data->res = *(MonoObject**)frame.retval->data.p;
1658 		} else {
1659 			/* Already set before the call */
1660 		}
1661 		break;
1662 	case MONO_TYPE_VALUETYPE:
1663 		/* Already set before the call */
1664 		break;
1665 	default:
1666 		printf ("%s\n", mono_type_full_name (sig->ret));
1667 		NOT_IMPLEMENTED;
1668 		break;
1669 	}
1670 }
1671 
1672 static stackval *
do_icall(ThreadContext * context,int op,stackval * sp,gpointer ptr)1673 do_icall (ThreadContext *context, int op, stackval *sp, gpointer ptr)
1674 {
1675 	MonoLMFExt ext;
1676 	interp_push_lmf (&ext, context->current_frame);
1677 
1678 	switch (op) {
1679 	case MINT_ICALL_V_V: {
1680 		void (*func)(void) = ptr;
1681         	func ();
1682 		break;
1683 	}
1684 	case MINT_ICALL_V_P: {
1685 		gpointer (*func)(void) = ptr;
1686 		sp++;
1687 		sp [-1].data.p = func ();
1688 		break;
1689 	}
1690 	case MINT_ICALL_P_V: {
1691 		void (*func)(gpointer) = ptr;
1692         	func (sp [-1].data.p);
1693 		sp --;
1694 		break;
1695 	}
1696 	case MINT_ICALL_P_P: {
1697 		gpointer (*func)(gpointer) = ptr;
1698 		sp [-1].data.p = func (sp [-1].data.p);
1699 		break;
1700 	}
1701 	case MINT_ICALL_PP_V: {
1702 		void (*func)(gpointer,gpointer) = ptr;
1703 		sp -= 2;
1704 		func (sp [0].data.p, sp [1].data.p);
1705 		break;
1706 	}
1707 	case MINT_ICALL_PI_V: {
1708 		void (*func)(gpointer,int) = ptr;
1709 		sp -= 2;
1710 		func (sp [0].data.p, sp [1].data.i);
1711 		break;
1712 	}
1713 	case MINT_ICALL_PP_P: {
1714 		gpointer (*func)(gpointer,gpointer) = ptr;
1715 		--sp;
1716 		sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p);
1717 		break;
1718 	}
1719 	case MINT_ICALL_PI_P: {
1720 		gpointer (*func)(gpointer,int) = ptr;
1721 		--sp;
1722 		sp [-1].data.p = func (sp [-1].data.p, sp [0].data.i);
1723 		break;
1724 	}
1725 	case MINT_ICALL_PPP_V: {
1726 		void (*func)(gpointer,gpointer,gpointer) = ptr;
1727 		sp -= 3;
1728 		func (sp [0].data.p, sp [1].data.p, sp [2].data.p);
1729 		break;
1730 	}
1731 	case MINT_ICALL_PPI_V: {
1732 		void (*func)(gpointer,gpointer,int) = ptr;
1733 		sp -= 3;
1734 		func (sp [0].data.p, sp [1].data.p, sp [2].data.i);
1735 		break;
1736 	}
1737 	default:
1738 		g_assert_not_reached ();
1739 	}
1740 
1741 	interp_pop_lmf (&ext);
1742 	return sp;
1743 }
1744 
1745 static stackval *
do_jit_call(stackval * sp,unsigned char * vt_sp,ThreadContext * context,InterpFrame * frame,InterpMethod * rmethod)1746 do_jit_call (stackval *sp, unsigned char *vt_sp, ThreadContext *context, InterpFrame *frame, InterpMethod *rmethod)
1747 {
1748 	MonoMethodSignature *sig;
1749 	MonoFtnDesc ftndesc;
1750 	guint8 res_buf [256];
1751 	MonoType *type;
1752 	MonoLMFExt ext;
1753 
1754 	//printf ("%s\n", mono_method_full_name (rmethod->method, 1));
1755 
1756 	/*
1757 	 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
1758 	 * by ref and return a return value using an explicit return value argument.
1759 	 */
1760 	if (!rmethod->jit_wrapper) {
1761 		MonoMethod *method = rmethod->method;
1762 		MonoError error;
1763 
1764 		sig = mono_method_signature (method);
1765 		g_assert (sig);
1766 
1767 		MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
1768 		//printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
1769 
1770 		gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, &error);
1771 		mono_error_assert_ok (&error);
1772 
1773 		gpointer addr = mono_jit_compile_method_jit_only (method, &error);
1774 		g_assert (addr);
1775 		mono_error_assert_ok (&error);
1776 
1777 		rmethod->jit_addr = addr;
1778 		rmethod->jit_sig = sig;
1779 		mono_memory_barrier ();
1780 		rmethod->jit_wrapper = jit_wrapper;
1781 
1782 	} else {
1783 		sig = rmethod->jit_sig;
1784 	}
1785 
1786 	sp -= sig->param_count;
1787 	if (sig->hasthis)
1788 		--sp;
1789 
1790 	ftndesc.addr = rmethod->jit_addr;
1791 	ftndesc.arg = NULL;
1792 
1793 	// FIXME: Optimize this
1794 
1795 	gpointer args [32];
1796 	int pindex = 0;
1797 	int stack_index = 0;
1798 	if (rmethod->hasthis) {
1799 		args [pindex ++] = sp [0].data.p;
1800 		stack_index ++;
1801 	}
1802 	type = rmethod->rtype;
1803 	if (type->type != MONO_TYPE_VOID) {
1804 		if (MONO_TYPE_ISSTRUCT (type))
1805 			args [pindex ++] = vt_sp;
1806 		else
1807 			args [pindex ++] = res_buf;
1808 	}
1809 	for (int i = 0; i < rmethod->param_count; ++i) {
1810 		MonoType *t = rmethod->param_types [i];
1811 		stackval *sval = &sp [stack_index + i];
1812 		if (sig->params [i]->byref) {
1813 			args [pindex ++] = sval->data.p;
1814 		} else if (MONO_TYPE_ISSTRUCT (t)) {
1815 			args [pindex ++] = sval->data.p;
1816 		} else if (MONO_TYPE_IS_REFERENCE (t)) {
1817 			args [pindex ++] = &sval->data.p;
1818 		} else {
1819 			switch (t->type) {
1820 			case MONO_TYPE_I1:
1821 			case MONO_TYPE_U1:
1822 			case MONO_TYPE_I2:
1823 			case MONO_TYPE_U2:
1824 			case MONO_TYPE_I4:
1825 			case MONO_TYPE_U4:
1826 			case MONO_TYPE_VALUETYPE:
1827 				args [pindex ++] = &sval->data.i;
1828 				break;
1829 			case MONO_TYPE_PTR:
1830 			case MONO_TYPE_FNPTR:
1831 			case MONO_TYPE_I:
1832 			case MONO_TYPE_U:
1833 			case MONO_TYPE_OBJECT:
1834 				args [pindex ++] = &sval->data.p;
1835 				break;
1836 			case MONO_TYPE_I8:
1837 			case MONO_TYPE_U8:
1838 				args [pindex ++] = &sval->data.l;
1839 				break;
1840 			default:
1841 				printf ("%s\n", mono_type_full_name (t));
1842 				g_assert_not_reached ();
1843 			}
1844 		}
1845 	}
1846 
1847 	interp_push_lmf (&ext, frame);
1848 
1849 	switch (pindex) {
1850 	case 0: {
1851 		void (*func)(gpointer) = rmethod->jit_wrapper;
1852 
1853 		func (&ftndesc);
1854 		break;
1855 	}
1856 	case 1: {
1857 		void (*func)(gpointer, gpointer) = rmethod->jit_wrapper;
1858 
1859 		func (args [0], &ftndesc);
1860 		break;
1861 	}
1862 	case 2: {
1863 		void (*func)(gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
1864 
1865 		func (args [0], args [1], &ftndesc);
1866 		break;
1867 	}
1868 	case 3: {
1869 		void (*func)(gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
1870 
1871 		func (args [0], args [1], args [2], &ftndesc);
1872 		break;
1873 	}
1874 	case 4: {
1875 		void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
1876 
1877 		func (args [0], args [1], args [2], args [3], &ftndesc);
1878 		break;
1879 	}
1880 	case 5: {
1881 		void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
1882 
1883 		func (args [0], args [1], args [2], args [3], args [4], &ftndesc);
1884 		break;
1885 	}
1886 	case 6: {
1887 		void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
1888 
1889 		func (args [0], args [1], args [2], args [3], args [4], args [5], &ftndesc);
1890 		break;
1891 	}
1892 	case 7: {
1893 		void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
1894 
1895 		func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], &ftndesc);
1896 		break;
1897 	}
1898 	default:
1899 		g_assert_not_reached ();
1900 		break;
1901 	}
1902 
1903 	interp_pop_lmf (&ext);
1904 
1905 	MonoType *rtype = rmethod->rtype;
1906 	switch (rtype->type) {
1907 	case MONO_TYPE_VOID:
1908 	case MONO_TYPE_OBJECT:
1909 	case MONO_TYPE_STRING:
1910 	case MONO_TYPE_CLASS:
1911 	case MONO_TYPE_ARRAY:
1912 	case MONO_TYPE_SZARRAY:
1913 	case MONO_TYPE_I:
1914 	case MONO_TYPE_U:
1915 		sp->data.p = *(gpointer*)res_buf;
1916 		break;
1917 	case MONO_TYPE_I1:
1918 		sp->data.i = *(gint8*)res_buf;
1919 		break;
1920 	case MONO_TYPE_U1:
1921 		sp->data.i = *(guint8*)res_buf;
1922 		break;
1923 	case MONO_TYPE_I2:
1924 		sp->data.i = *(gint16*)res_buf;
1925 		break;
1926 	case MONO_TYPE_U2:
1927 		sp->data.i = *(guint16*)res_buf;
1928 		break;
1929 	case MONO_TYPE_I4:
1930 		sp->data.i = *(gint32*)res_buf;
1931 		break;
1932 	case MONO_TYPE_U4:
1933 		sp->data.i = *(guint32*)res_buf;
1934 		break;
1935 	case MONO_TYPE_VALUETYPE:
1936 		/* The result was written to vt_sp */
1937 		sp->data.p = vt_sp;
1938 		break;
1939 	case MONO_TYPE_GENERICINST:
1940 		if (MONO_TYPE_IS_REFERENCE (rtype)) {
1941 			sp->data.p = *(gpointer*)res_buf;
1942 		} else {
1943 			/* The result was written to vt_sp */
1944 			sp->data.p = vt_sp;
1945 		}
1946 		break;
1947 	default:
1948 		g_print ("%s\n", mono_type_full_name (rtype));
1949 		g_assert_not_reached ();
1950 		break;
1951 	}
1952 
1953 	return sp;
1954 }
1955 
1956 static void
do_debugger_tramp(void (* tramp)(void),InterpFrame * frame)1957 do_debugger_tramp (void (*tramp) (void), InterpFrame *frame)
1958 {
1959 	MonoLMFExt ext;
1960 	interp_push_lmf (&ext, frame);
1961 	tramp ();
1962 	interp_pop_lmf (&ext);
1963 }
1964 
1965 static void
do_transform_method(InterpFrame * frame,ThreadContext * context)1966 do_transform_method (InterpFrame *frame, ThreadContext *context)
1967 {
1968 	MonoLMFExt ext;
1969 
1970 	/* Use the parent frame as the current frame is not complete yet */
1971 	interp_push_lmf (&ext, frame->parent);
1972 
1973 	frame->ex = mono_interp_transform_method (frame->imethod, context, frame);
1974 
1975 	interp_pop_lmf (&ext);
1976 }
1977 
1978 /*
1979  * These functions are the entry points into the interpreter from compiled code.
1980  * They are called by the interp_in wrappers. They have the following signature:
1981  * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
1982  * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
1983  * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
1984  * more wrappers then these functions.
1985  * this/static * ret/void * 16 arguments -> 64 functions.
1986  */
1987 
1988 #define MAX_INTERP_ENTRY_ARGS 8
1989 
1990 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
1991 	InterpEntryData data; \
1992 	(data).rmethod = (_method); \
1993 	(data).res = (_res); \
1994 	(data).this_arg = (_this_arg); \
1995 	(data).many_args = NULL;
1996 
1997 #define INTERP_ENTRY0(_this_arg, _res, _method) {	\
1998 	INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1999 	interp_entry (&data); \
2000 	}
2001 #define INTERP_ENTRY1(_this_arg, _res, _method) {	  \
2002 	INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2003 	(data).args [0] = arg1; \
2004 	interp_entry (&data); \
2005 	}
2006 #define INTERP_ENTRY2(_this_arg, _res, _method) {  \
2007 	INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2008 	(data).args [0] = arg1; \
2009 	(data).args [1] = arg2; \
2010 	interp_entry (&data); \
2011 	}
2012 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2013 	INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2014 	(data).args [0] = arg1; \
2015 	(data).args [1] = arg2; \
2016 	(data).args [2] = arg3; \
2017 	interp_entry (&data); \
2018 	}
2019 #define INTERP_ENTRY4(_this_arg, _res, _method) {	\
2020 	INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2021 	(data).args [0] = arg1; \
2022 	(data).args [1] = arg2; \
2023 	(data).args [2] = arg3; \
2024 	(data).args [3] = arg4; \
2025 	interp_entry (&data); \
2026 	}
2027 #define INTERP_ENTRY5(_this_arg, _res, _method) {	\
2028 	INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2029 	(data).args [0] = arg1; \
2030 	(data).args [1] = arg2; \
2031 	(data).args [2] = arg3; \
2032 	(data).args [3] = arg4; \
2033 	(data).args [4] = arg5; \
2034 	interp_entry (&data); \
2035 	}
2036 #define INTERP_ENTRY6(_this_arg, _res, _method) {	\
2037 	INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2038 	(data).args [0] = arg1; \
2039 	(data).args [1] = arg2; \
2040 	(data).args [2] = arg3; \
2041 	(data).args [3] = arg4; \
2042 	(data).args [4] = arg5; \
2043 	(data).args [5] = arg6; \
2044 	interp_entry (&data); \
2045 	}
2046 #define INTERP_ENTRY7(_this_arg, _res, _method) {	\
2047 	INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2048 	(data).args [0] = arg1; \
2049 	(data).args [1] = arg2; \
2050 	(data).args [2] = arg3; \
2051 	(data).args [3] = arg4; \
2052 	(data).args [4] = arg5; \
2053 	(data).args [5] = arg6; \
2054 	(data).args [6] = arg7; \
2055 	interp_entry (&data); \
2056 	}
2057 #define INTERP_ENTRY8(_this_arg, _res, _method) {	\
2058 	INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2059 	(data).args [0] = arg1; \
2060 	(data).args [1] = arg2; \
2061 	(data).args [2] = arg3; \
2062 	(data).args [3] = arg4; \
2063 	(data).args [4] = arg5; \
2064 	(data).args [5] = arg6; \
2065 	(data).args [6] = arg7; \
2066 	(data).args [7] = arg8; \
2067 	interp_entry (&data); \
2068 	}
2069 
2070 #define ARGLIST0 InterpMethod *rmethod
2071 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2072 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2073 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2074 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2075 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2076 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2077 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2078 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2079 
2080 static void interp_entry_static_0 (ARGLIST0) INTERP_ENTRY0 (NULL, NULL, rmethod)
2081 static void interp_entry_static_1 (ARGLIST1) INTERP_ENTRY1 (NULL, NULL, rmethod)
2082 static void interp_entry_static_2 (ARGLIST2) INTERP_ENTRY2 (NULL, NULL, rmethod)
2083 static void interp_entry_static_3 (ARGLIST3) INTERP_ENTRY3 (NULL, NULL, rmethod)
2084 static void interp_entry_static_4 (ARGLIST4) INTERP_ENTRY4 (NULL, NULL, rmethod)
2085 static void interp_entry_static_5 (ARGLIST5) INTERP_ENTRY5 (NULL, NULL, rmethod)
2086 static void interp_entry_static_6 (ARGLIST6) INTERP_ENTRY6 (NULL, NULL, rmethod)
2087 static void interp_entry_static_7 (ARGLIST7) INTERP_ENTRY7 (NULL, NULL, rmethod)
2088 static void interp_entry_static_8 (ARGLIST8) INTERP_ENTRY8 (NULL, NULL, rmethod)
2089 static void interp_entry_static_ret_0 (gpointer res, ARGLIST0) INTERP_ENTRY0 (NULL, res, rmethod)
2090 static void interp_entry_static_ret_1 (gpointer res, ARGLIST1) INTERP_ENTRY1 (NULL, res, rmethod)
2091 static void interp_entry_static_ret_2 (gpointer res, ARGLIST2) INTERP_ENTRY2 (NULL, res, rmethod)
2092 static void interp_entry_static_ret_3 (gpointer res, ARGLIST3) INTERP_ENTRY3 (NULL, res, rmethod)
2093 static void interp_entry_static_ret_4 (gpointer res, ARGLIST4) INTERP_ENTRY4 (NULL, res, rmethod)
2094 static void interp_entry_static_ret_5 (gpointer res, ARGLIST5) INTERP_ENTRY5 (NULL, res, rmethod)
2095 static void interp_entry_static_ret_6 (gpointer res, ARGLIST6) INTERP_ENTRY6 (NULL, res, rmethod)
2096 static void interp_entry_static_ret_7 (gpointer res, ARGLIST7) INTERP_ENTRY7 (NULL, res, rmethod)
2097 static void interp_entry_static_ret_8 (gpointer res, ARGLIST8) INTERP_ENTRY8 (NULL, res, rmethod)
2098 static void interp_entry_instance_0 (gpointer this_arg, ARGLIST0) INTERP_ENTRY0 (this_arg, NULL, rmethod)
2099 static void interp_entry_instance_1 (gpointer this_arg, ARGLIST1) INTERP_ENTRY1 (this_arg, NULL, rmethod)
2100 static void interp_entry_instance_2 (gpointer this_arg, ARGLIST2) INTERP_ENTRY2 (this_arg, NULL, rmethod)
2101 static void interp_entry_instance_3 (gpointer this_arg, ARGLIST3) INTERP_ENTRY3 (this_arg, NULL, rmethod)
2102 static void interp_entry_instance_4 (gpointer this_arg, ARGLIST4) INTERP_ENTRY4 (this_arg, NULL, rmethod)
2103 static void interp_entry_instance_5 (gpointer this_arg, ARGLIST5) INTERP_ENTRY5 (this_arg, NULL, rmethod)
2104 static void interp_entry_instance_6 (gpointer this_arg, ARGLIST6) INTERP_ENTRY6 (this_arg, NULL, rmethod)
2105 static void interp_entry_instance_7 (gpointer this_arg, ARGLIST7) INTERP_ENTRY7 (this_arg, NULL, rmethod)
2106 static void interp_entry_instance_8 (gpointer this_arg, ARGLIST8) INTERP_ENTRY8 (this_arg, NULL, rmethod)
2107 static void interp_entry_instance_ret_0 (gpointer this_arg, gpointer res, ARGLIST0) INTERP_ENTRY0 (this_arg, res, rmethod)
2108 static void interp_entry_instance_ret_1 (gpointer this_arg, gpointer res, ARGLIST1) INTERP_ENTRY1 (this_arg, res, rmethod)
2109 static void interp_entry_instance_ret_2 (gpointer this_arg, gpointer res, ARGLIST2) INTERP_ENTRY2 (this_arg, res, rmethod)
2110 static void interp_entry_instance_ret_3 (gpointer this_arg, gpointer res, ARGLIST3) INTERP_ENTRY3 (this_arg, res, rmethod)
2111 static void interp_entry_instance_ret_4 (gpointer this_arg, gpointer res, ARGLIST4) INTERP_ENTRY4 (this_arg, res, rmethod)
2112 static void interp_entry_instance_ret_5 (gpointer this_arg, gpointer res, ARGLIST5) INTERP_ENTRY5 (this_arg, res, rmethod)
2113 static void interp_entry_instance_ret_6 (gpointer this_arg, gpointer res, ARGLIST6) INTERP_ENTRY6 (this_arg, res, rmethod)
2114 static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY7 (this_arg, res, rmethod)
2115 static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY8 (this_arg, res, rmethod)
2116 
2117 #define INTERP_ENTRY_FUNCLIST(type) interp_entry_ ## type ## _0, interp_entry_ ## type ## _1, interp_entry_ ## type ## _2, interp_entry_ ## type ## _3, interp_entry_ ## type ## _4, interp_entry_ ## type ## _5, interp_entry_ ## type ## _6, interp_entry_ ## type ## _7, interp_entry_ ## type ## _8
2118 
2119 gpointer entry_funcs_static [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static) };
2120 gpointer entry_funcs_static_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static_ret) };
2121 gpointer entry_funcs_instance [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance) };
2122 gpointer entry_funcs_instance_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance_ret) };
2123 
2124 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2125 static void
interp_entry_general(gpointer this_arg,gpointer res,gpointer * args,gpointer rmethod)2126 interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
2127 {
2128 	INTERP_ENTRY_BASE (rmethod, this_arg, res);
2129 	data.many_args = args;
2130 	interp_entry (&data);
2131 }
2132 
2133 /*
2134  * interp_create_method_pointer:
2135  *
2136  * Return a function pointer which can be used to call METHOD using the
2137  * interpreter. Return NULL for methods which are not supported.
2138  */
2139 static gpointer
interp_create_method_pointer(MonoMethod * method,MonoError * error)2140 interp_create_method_pointer (MonoMethod *method, MonoError *error)
2141 {
2142 	gpointer addr;
2143 	MonoMethodSignature *sig = mono_method_signature (method);
2144 	MonoMethod *wrapper;
2145 	InterpMethod *rmethod = mono_interp_get_imethod (mono_domain_get (), method, error);
2146 
2147 	/* HACK: method_ptr of delegate should point to a runtime method*/
2148 	if (method->wrapper_type && method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
2149 		return rmethod;
2150 
2151 	if (rmethod->jit_entry)
2152 		return rmethod->jit_entry;
2153 	wrapper = mini_get_interp_in_wrapper (sig);
2154 
2155 	gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2156 	if (!mono_error_ok (error))
2157 		g_error ("couldn't compile wrapper \"%s\" for \"%s\" (error: %s)\n", mono_method_get_full_name (wrapper), mono_method_get_full_name (method), mono_error_get_message (error));
2158 
2159 	gpointer entry_func;
2160 	if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2161 		entry_func = interp_entry_general;
2162 	} else if (sig->hasthis) {
2163 		if (sig->ret->type == MONO_TYPE_VOID)
2164 			entry_func = entry_funcs_instance [sig->param_count];
2165 		else
2166 			entry_func = entry_funcs_instance_ret [sig->param_count];
2167 	} else {
2168 		if (sig->ret->type == MONO_TYPE_VOID)
2169 			entry_func = entry_funcs_static [sig->param_count];
2170 		else
2171 			entry_func = entry_funcs_static_ret [sig->param_count];
2172 	}
2173 	g_assert (entry_func);
2174 
2175 	/* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2176 	MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
2177 	ftndesc->addr = entry_func;
2178 	ftndesc->arg = rmethod;
2179 	mono_error_assert_ok (error);
2180 
2181 	/*
2182 	 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2183 	 * rgctx register using a trampoline.
2184 	 */
2185 
2186 	if (mono_aot_only)
2187 		addr = mono_aot_get_static_rgctx_trampoline (ftndesc, jit_wrapper);
2188 	else
2189 		addr = mono_arch_get_static_rgctx_trampoline (ftndesc, jit_wrapper);
2190 
2191 	mono_memory_barrier ();
2192 	rmethod->jit_entry = addr;
2193 
2194 	return addr;
2195 }
2196 
2197 #if COUNT_OPS
2198 static int opcode_counts[512];
2199 
2200 #define COUNT_OP(op) opcode_counts[op]++
2201 #else
2202 #define COUNT_OP(op)
2203 #endif
2204 
2205 #if DEBUG_INTERP
2206 #define DUMP_INSTR() \
2207 	if (tracing > 1) { \
2208 		char *ins; \
2209 		if (sp > frame->stack) { \
2210 			ins = dump_stack (frame->stack, sp); \
2211 		} else { \
2212 			ins = g_strdup (""); \
2213 		} \
2214 		sp->data.l = 0; \
2215 		output_indent (); \
2216 		char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
2217 		char *disasm = mono_interp_dis_mintop(rtm->code, ip); \
2218 		g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
2219 		g_free (mn); \
2220 		g_free (ins); \
2221 		g_free (disasm); \
2222 	}
2223 #else
2224 #define DUMP_INSTR()
2225 #endif
2226 
2227 #ifdef __GNUC__
2228 #define USE_COMPUTED_GOTO 1
2229 #endif
2230 #if USE_COMPUTED_GOTO
2231 #define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op];
2232 #define MINT_IN_CASE(x) LAB_ ## x:
2233 #if DEBUG_INTERP
2234 #define MINT_IN_BREAK if (tracing > 1) goto main_loop; else { COUNT_OP(*ip); goto *in_labels[*ip]; }
2235 #else
2236 #define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; }
2237 #endif
2238 #define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
2239 #else
2240 #define MINT_IN_SWITCH(op) switch (op)
2241 #define MINT_IN_CASE(x) case x:
2242 #define MINT_IN_BREAK break
2243 #define MINT_IN_DEFAULT default:
2244 #endif
2245 
2246 /*
2247  * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
2248  * If BASE_FRAME is not NULL, copy arguments/locals from BASE_FRAME.
2249  */
2250 static void
interp_exec_method_full(InterpFrame * frame,ThreadContext * context,guint16 * start_with_ip,MonoException * filter_exception,int exit_at_finally,InterpFrame * base_frame)2251 interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *start_with_ip, MonoException *filter_exception, int exit_at_finally, InterpFrame *base_frame)
2252 {
2253 	InterpFrame child_frame;
2254 	GSList *finally_ips = NULL;
2255 	const unsigned short *endfinally_ip = NULL;
2256 	const unsigned short *ip = NULL;
2257 	register stackval *sp;
2258 	InterpMethod *rtm;
2259 #if DEBUG_INTERP
2260 	gint tracing = global_tracing;
2261 	unsigned char *vtalloc;
2262 #else
2263 	gint tracing = 0;
2264 #endif
2265 	int i32;
2266 	unsigned char *vt_sp;
2267 	unsigned char *locals;
2268 	MonoError error;
2269 	MonoObject *o = NULL;
2270 	MonoClass *c;
2271 #if USE_COMPUTED_GOTO
2272 	static void *in_labels[] = {
2273 #define OPDEF(a,b,c,d) \
2274 	&&LAB_ ## a,
2275 #include "mintops.def"
2276 	0 };
2277 #endif
2278 
2279 	frame->ex = NULL;
2280 	frame->ex_handler = NULL;
2281 	frame->ip = NULL;
2282 	frame->domain = mono_domain_get ();
2283 	context->current_frame = frame;
2284 
2285 	debug_enter (frame, &tracing);
2286 
2287 	if (!frame->imethod->transformed) {
2288 #if DEBUG_INTERP
2289 		char *mn = mono_method_full_name (frame->imethod->method, TRUE);
2290 		g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
2291 		g_free (mn);
2292 #endif
2293 
2294 		do_transform_method (frame, context);
2295 		if (frame->ex) {
2296 			context->search_for_handler = 1;
2297 			rtm = NULL;
2298 			ip = NULL;
2299 			goto exit_frame;
2300 		}
2301 	}
2302 
2303 	rtm = frame->imethod;
2304 	if (!start_with_ip) {
2305 		frame->args = alloca (rtm->alloca_size);
2306 		memset (frame->args, 0, rtm->alloca_size);
2307 
2308 		ip = rtm->code;
2309 	} else {
2310 		ip = start_with_ip;
2311 		if (base_frame) {
2312 			frame->args = alloca (rtm->alloca_size);
2313 			memcpy (frame->args, base_frame->args, rtm->alloca_size);
2314 		}
2315 	}
2316 	sp = frame->stack = (stackval *) ((char *) frame->args + rtm->args_size);
2317 	vt_sp = (unsigned char *) sp + rtm->stack_size;
2318 #if DEBUG_INTERP
2319 	vtalloc = vt_sp;
2320 #endif
2321 	locals = (unsigned char *) vt_sp + rtm->vt_stack_size;
2322 	frame->locals = locals;
2323 	child_frame.parent = frame;
2324 
2325 	if (filter_exception) {
2326 		sp->data.p = filter_exception;
2327 		sp++;
2328 	}
2329 
2330 	/*
2331 	 * using while (ip < end) may result in a 15% performance drop,
2332 	 * but it may be useful for debug
2333 	 */
2334 	while (1) {
2335 	main_loop:
2336 		/* g_assert (sp >= frame->stack); */
2337 		/* g_assert(vt_sp - vtalloc <= rtm->vt_stack_size); */
2338 		DUMP_INSTR();
2339 		MINT_IN_SWITCH (*ip) {
2340 		MINT_IN_CASE(MINT_INITLOCALS)
2341 			memset (locals, 0, rtm->locals_size);
2342 			++ip;
2343 			MINT_IN_BREAK;
2344 		MINT_IN_CASE(MINT_NOP)
2345 			++ip;
2346 			MINT_IN_BREAK;
2347 		MINT_IN_CASE(MINT_NIY)
2348 			g_error ("mint_niy: instruction not implemented yet.  This shouldn't happen.");
2349 			MINT_IN_BREAK;
2350 		MINT_IN_CASE(MINT_BREAK)
2351 			++ip;
2352 			do_debugger_tramp (mono_debugger_agent_user_break, frame);
2353 			MINT_IN_BREAK;
2354 		MINT_IN_CASE(MINT_LDNULL)
2355 			sp->data.p = NULL;
2356 			++ip;
2357 			++sp;
2358 			MINT_IN_BREAK;
2359 		MINT_IN_CASE(MINT_VTRESULT) {
2360 			int ret_size = * (guint16 *)(ip + 1);
2361 			unsigned char *ret_vt_sp = vt_sp;
2362 			vt_sp -= READ32(ip + 2);
2363 			if (ret_size > 0) {
2364 				memmove (vt_sp, ret_vt_sp, ret_size);
2365 				sp [-1].data.p = vt_sp;
2366 				vt_sp += (ret_size + 7) & ~7;
2367 			}
2368 			ip += 4;
2369 			MINT_IN_BREAK;
2370 		}
2371 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
2372 		MINT_IN_CASE(MINT_LDC_I4_M1)
2373 			LDC(-1);
2374 			MINT_IN_BREAK;
2375 		MINT_IN_CASE(MINT_LDC_I4_0)
2376 			LDC(0);
2377 			MINT_IN_BREAK;
2378 		MINT_IN_CASE(MINT_LDC_I4_1)
2379 			LDC(1);
2380 			MINT_IN_BREAK;
2381 		MINT_IN_CASE(MINT_LDC_I4_2)
2382 			LDC(2);
2383 			MINT_IN_BREAK;
2384 		MINT_IN_CASE(MINT_LDC_I4_3)
2385 			LDC(3);
2386 			MINT_IN_BREAK;
2387 		MINT_IN_CASE(MINT_LDC_I4_4)
2388 			LDC(4);
2389 			MINT_IN_BREAK;
2390 		MINT_IN_CASE(MINT_LDC_I4_5)
2391 			LDC(5);
2392 			MINT_IN_BREAK;
2393 		MINT_IN_CASE(MINT_LDC_I4_6)
2394 			LDC(6);
2395 			MINT_IN_BREAK;
2396 		MINT_IN_CASE(MINT_LDC_I4_7)
2397 			LDC(7);
2398 			MINT_IN_BREAK;
2399 		MINT_IN_CASE(MINT_LDC_I4_8)
2400 			LDC(8);
2401 			MINT_IN_BREAK;
2402 		MINT_IN_CASE(MINT_LDC_I4_S)
2403 			sp->data.i = *(const short *)(ip + 1);
2404 			ip += 2;
2405 			++sp;
2406 			MINT_IN_BREAK;
2407 		MINT_IN_CASE(MINT_LDC_I4)
2408 			++ip;
2409 			sp->data.i = READ32 (ip);
2410 			ip += 2;
2411 			++sp;
2412 			MINT_IN_BREAK;
2413 		MINT_IN_CASE(MINT_LDC_I8)
2414 			++ip;
2415 			sp->data.l = READ64 (ip);
2416 			ip += 4;
2417 			++sp;
2418 			MINT_IN_BREAK;
2419 		MINT_IN_CASE(MINT_LDC_R4) {
2420 			guint32 val;
2421 			++ip;
2422 			val = READ32(ip);
2423 			sp->data.f = * (float *)&val;
2424 			ip += 2;
2425 			++sp;
2426 			MINT_IN_BREAK;
2427 		}
2428 		MINT_IN_CASE(MINT_LDC_R8)
2429 			sp->data.l = READ64 (ip + 1); /* note union usage */
2430 			ip += 5;
2431 			++sp;
2432 			MINT_IN_BREAK;
2433 		MINT_IN_CASE(MINT_DUP)
2434 			sp [0] = sp[-1];
2435 			++sp;
2436 			++ip;
2437 			MINT_IN_BREAK;
2438 		MINT_IN_CASE(MINT_DUP_VT)
2439 			i32 = READ32 (ip + 1);
2440 			sp->data.p = vt_sp;
2441 			memcpy(sp->data.p, sp [-1].data.p, i32);
2442 			vt_sp += (i32 + 7) & ~7;
2443 			++sp;
2444 			ip += 3;
2445 			MINT_IN_BREAK;
2446 		MINT_IN_CASE(MINT_POP) {
2447 			guint16 u16 = (* (guint16 *)(ip + 1)) + 1;
2448 			if (u16 > 1)
2449 				memmove (sp - u16, sp - 1, (u16 - 1) * sizeof (stackval));
2450 			sp--;
2451 			ip += 2;
2452 			MINT_IN_BREAK;
2453 		}
2454 		MINT_IN_CASE(MINT_JMP) {
2455 			InterpMethod *new_method = rtm->data_items [* (guint16 *)(ip + 1)];
2456 
2457 			if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL)
2458 				MONO_PROFILER_RAISE (method_tail_call, (frame->imethod->method, new_method->method));
2459 
2460 			if (!new_method->transformed) {
2461 				frame->ip = ip;
2462 				frame->ex = mono_interp_transform_method (new_method, context, NULL);
2463 				if (frame->ex)
2464 					goto exit_frame;
2465 			}
2466 			ip += 2;
2467 			if (new_method->alloca_size > rtm->alloca_size)
2468 				g_error ("MINT_JMP to method which needs more stack space (%d > %d)", new_method->alloca_size, rtm->alloca_size);
2469 			rtm = frame->imethod = new_method;
2470 			vt_sp = (unsigned char *) sp + rtm->stack_size;
2471 #if DEBUG_INTERP
2472 			vtalloc = vt_sp;
2473 #endif
2474 			locals = vt_sp + rtm->vt_stack_size;
2475 			frame->locals = locals;
2476 			ip = rtm->new_body_start; /* bypass storing input args from callers frame */
2477 			MINT_IN_BREAK;
2478 		}
2479 		MINT_IN_CASE(MINT_CALLI) {
2480 			MonoMethodSignature *csignature;
2481 			stackval *endsp = sp;
2482 
2483 			frame->ip = ip;
2484 
2485 			csignature = rtm->data_items [* (guint16 *)(ip + 1)];
2486 			ip += 2;
2487 			--sp;
2488 			--endsp;
2489 			child_frame.imethod = sp->data.p;
2490 
2491 			sp->data.p = vt_sp;
2492 			child_frame.retval = sp;
2493 			/* decrement by the actual number of args */
2494 			sp -= csignature->param_count;
2495 			if (csignature->hasthis)
2496 				--sp;
2497 			child_frame.stack_args = sp;
2498 
2499 			if (child_frame.imethod->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2500 				child_frame.imethod = mono_interp_get_imethod (rtm->domain, mono_marshal_get_native_wrapper (child_frame.imethod->method, FALSE, FALSE), &error);
2501 				mono_error_cleanup (&error); /* FIXME: don't swallow the error */
2502 			}
2503 
2504 			if (csignature->hasthis) {
2505 				MonoObject *this_arg = sp->data.p;
2506 
2507 				if (this_arg->vtable->klass->valuetype) {
2508 					gpointer *unboxed = mono_object_unbox (this_arg);
2509 					sp [0].data.p = unboxed;
2510 				}
2511 			}
2512 
2513 			interp_exec_method (&child_frame, context);
2514 
2515 			context->current_frame = frame;
2516 
2517 			if (context->has_resume_state) {
2518 				if (frame == context->handler_frame)
2519 					SET_RESUME_STATE (context);
2520 				else
2521 					goto exit_frame;
2522 			}
2523 
2524 			CHECK_CHILD_EX (child_frame, ip - 2);
2525 
2526 			/* need to handle typedbyref ... */
2527 			if (csignature->ret->type != MONO_TYPE_VOID) {
2528 				*sp = *endsp;
2529 				sp++;
2530 			}
2531 			MINT_IN_BREAK;
2532 		}
2533 		MINT_IN_CASE(MINT_CALLI_NAT) {
2534 			MonoMethodSignature *csignature;
2535 			stackval *endsp = sp;
2536 			unsigned char *code = NULL;
2537 
2538 			frame->ip = ip;
2539 
2540 			csignature = rtm->data_items [* (guint16 *)(ip + 1)];
2541 			ip += 2;
2542 			--sp;
2543 			--endsp;
2544 			code = sp->data.p;
2545 			child_frame.imethod = NULL;
2546 
2547 			sp->data.p = vt_sp;
2548 			child_frame.retval = sp;
2549 			/* decrement by the actual number of args */
2550 			sp -= csignature->param_count;
2551 			if (csignature->hasthis)
2552 				--sp;
2553 			child_frame.stack_args = sp;
2554 			ves_pinvoke_method (&child_frame, csignature, (MonoFuncV) code, FALSE, context);
2555 
2556 			context->current_frame = frame;
2557 
2558 			if (context->has_resume_state) {
2559 				if (frame == context->handler_frame)
2560 					SET_RESUME_STATE (context);
2561 				else
2562 					goto exit_frame;
2563 			}
2564 
2565 			CHECK_CHILD_EX (child_frame, ip - 2);
2566 
2567 			/* need to handle typedbyref ... */
2568 			if (csignature->ret->type != MONO_TYPE_VOID) {
2569 				*sp = *endsp;
2570 				sp++;
2571 			}
2572 			MINT_IN_BREAK;
2573 		}
2574 		MINT_IN_CASE(MINT_CALL) {
2575 			stackval *endsp = sp;
2576 
2577 			frame->ip = ip;
2578 
2579 			child_frame.imethod = rtm->data_items [* (guint16 *)(ip + 1)];
2580 			ip += 2;
2581 			sp->data.p = vt_sp;
2582 			child_frame.retval = sp;
2583 			/* decrement by the actual number of args */
2584 			sp -= child_frame.imethod->param_count;
2585 			if (child_frame.imethod->hasthis) {
2586 				--sp;
2587 				MonoObject *this_arg = sp->data.p;
2588 				if (!this_arg && (child_frame.imethod->method->flags & METHOD_ATTRIBUTE_VIRTUAL))
2589 					THROW_EX (mono_get_exception_null_reference(), ip - 2);
2590 			}
2591 
2592 			child_frame.stack_args = sp;
2593 
2594 			interp_exec_method (&child_frame, context);
2595 
2596 			context->current_frame = frame;
2597 
2598 			if (context->has_resume_state) {
2599 				if (frame == context->handler_frame)
2600 					SET_RESUME_STATE (context);
2601 				else
2602 					goto exit_frame;
2603 			}
2604 			CHECK_CHILD_EX (child_frame, ip - 2);
2605 
2606 			/* need to handle typedbyref ... */
2607 			*sp = *endsp;
2608 			sp++;
2609 			MINT_IN_BREAK;
2610 		}
2611 		MINT_IN_CASE(MINT_VCALL) {
2612 			frame->ip = ip;
2613 
2614 			child_frame.imethod = rtm->data_items [* (guint16 *)(ip + 1)];
2615 			ip += 2;
2616 
2617 			sp->data.p = vt_sp;
2618 			child_frame.retval = sp;
2619 			/* decrement by the actual number of args */
2620 			sp -= child_frame.imethod->param_count;
2621 			if (child_frame.imethod->hasthis) {
2622 				--sp;
2623 				MonoObject *this_arg = sp->data.p;
2624 				if (!this_arg)
2625 					THROW_EX (mono_get_exception_null_reference(), ip - 2);
2626 			}
2627 			child_frame.stack_args = sp;
2628 
2629 			interp_exec_method (&child_frame, context);
2630 
2631 			context->current_frame = frame;
2632 
2633 			if (context->has_resume_state) {
2634 				if (frame == context->handler_frame)
2635 					SET_RESUME_STATE (context);
2636 				else
2637 					goto exit_frame;
2638 			}
2639 
2640 			CHECK_CHILD_EX (child_frame, ip - 2);
2641 			MINT_IN_BREAK;
2642 		}
2643 
2644 		MINT_IN_CASE(MINT_JIT_CALL) {
2645 			InterpMethod *rmethod = rtm->data_items [* (guint16 *)(ip + 1)];
2646 			frame->ip = ip;
2647 			ip += 2;
2648 			sp = do_jit_call (sp, vt_sp, context, frame, rmethod);
2649 
2650 			if (context->has_resume_state) {
2651 				/*
2652 				 * If this bit is set, it means the call has thrown the exception, and we
2653 				 * reached this point because the EH code in mono_handle_exception ()
2654 				 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
2655 				 * has set the fields in context to indicate where we have to resume execution.
2656 				 */
2657 				if (frame == context->handler_frame)
2658 					SET_RESUME_STATE (context);
2659 				else
2660 					goto exit_frame;
2661 			}
2662 			if (rmethod->rtype->type != MONO_TYPE_VOID)
2663 				sp++;
2664 
2665 			MINT_IN_BREAK;
2666 		}
2667 
2668 		MINT_IN_CASE(MINT_CALLVIRT) {
2669 			stackval *endsp = sp;
2670 			MonoObject *this_arg;
2671 			guint32 token;
2672 
2673 			frame->ip = ip;
2674 
2675 			token = * (unsigned short *)(ip + 1);
2676 			ip += 2;
2677 			child_frame.imethod = rtm->data_items [token];
2678 			sp->data.p = vt_sp;
2679 			child_frame.retval = sp;
2680 
2681 			/* decrement by the actual number of args */
2682 			sp -= child_frame.imethod->param_count + 1;
2683 			child_frame.stack_args = sp;
2684 			this_arg = sp->data.p;
2685 			if (!this_arg)
2686 				THROW_EX (mono_get_exception_null_reference(), ip - 2);
2687 			child_frame.imethod = get_virtual_method (child_frame.imethod, this_arg);
2688 
2689 			MonoClass *this_class = this_arg->vtable->klass;
2690 			if (this_class->valuetype && child_frame.imethod->method->klass->valuetype) {
2691 				/* unbox */
2692 				gpointer *unboxed = mono_object_unbox (this_arg);
2693 				sp [0].data.p = unboxed;
2694 			}
2695 
2696 			interp_exec_method (&child_frame, context);
2697 
2698 			context->current_frame = frame;
2699 
2700 			if (context->has_resume_state) {
2701 				if (frame == context->handler_frame)
2702 					SET_RESUME_STATE (context);
2703 				else
2704 					goto exit_frame;
2705 			}
2706 
2707 			CHECK_CHILD_EX (child_frame, ip - 2);
2708 
2709 			/* need to handle typedbyref ... */
2710 			*sp = *endsp;
2711 			sp++;
2712 			MINT_IN_BREAK;
2713 		}
2714 		MINT_IN_CASE(MINT_VCALLVIRT) {
2715 			MonoObject *this_arg;
2716 			guint32 token;
2717 
2718 			frame->ip = ip;
2719 
2720 			token = * (unsigned short *)(ip + 1);
2721 			ip += 2;
2722 			child_frame.imethod = rtm->data_items [token];
2723 			sp->data.p = vt_sp;
2724 			child_frame.retval = sp;
2725 
2726 			/* decrement by the actual number of args */
2727 			sp -= child_frame.imethod->param_count + 1;
2728 			child_frame.stack_args = sp;
2729 			this_arg = sp->data.p;
2730 			if (!this_arg)
2731 				THROW_EX (mono_get_exception_null_reference(), ip - 2);
2732 			child_frame.imethod = get_virtual_method (child_frame.imethod, this_arg);
2733 
2734 			MonoClass *this_class = this_arg->vtable->klass;
2735 			if (this_class->valuetype && child_frame.imethod->method->klass->valuetype) {
2736 				gpointer *unboxed = mono_object_unbox (this_arg);
2737 				sp [0].data.p = unboxed;
2738 			}
2739 
2740 			interp_exec_method (&child_frame, context);
2741 
2742 			context->current_frame = frame;
2743 
2744 			if (context->has_resume_state) {
2745 				if (frame == context->handler_frame)
2746 					SET_RESUME_STATE (context);
2747 				else
2748 					goto exit_frame;
2749 			}
2750 
2751 			CHECK_CHILD_EX (child_frame, ip - 2);
2752 			MINT_IN_BREAK;
2753 		}
2754 		MINT_IN_CASE(MINT_CALLRUN)
2755 			ves_imethod (frame, context);
2756 			if (frame->ex) {
2757 				MonoException *fex = frame->ex;
2758 				//frame = frame->parent;
2759 				THROW_EX (fex, frame->ip);
2760 			}
2761 			goto exit_frame;
2762 		MINT_IN_CASE(MINT_RET)
2763 			--sp;
2764 			*frame->retval = *sp;
2765 			if (sp > frame->stack)
2766 				g_warning ("ret: more values on stack: %d", sp-frame->stack);
2767 			goto exit_frame;
2768 		MINT_IN_CASE(MINT_RET_VOID)
2769 			if (sp > frame->stack)
2770 				g_warning ("ret.void: more values on stack: %d %s", sp-frame->stack, mono_method_full_name (frame->imethod->method, TRUE));
2771 			goto exit_frame;
2772 		MINT_IN_CASE(MINT_RET_VT)
2773 			i32 = READ32(ip + 1);
2774 			--sp;
2775 			memcpy(frame->retval->data.p, sp->data.p, i32);
2776 			if (sp > frame->stack)
2777 				g_warning ("ret.vt: more values on stack: %d", sp-frame->stack);
2778 			goto exit_frame;
2779 		MINT_IN_CASE(MINT_BR_S)
2780 			/* Checkpoint to be able to handle aborts */
2781 			if (*mono_thread_interruption_request_flag ()) {
2782 				MonoException *exc = mono_thread_interruption_checkpoint ();
2783 				if (exc)
2784 					THROW_EX (exc, ip);
2785 			}
2786 			ip += (short) *(ip + 1);
2787 			MINT_IN_BREAK;
2788 		MINT_IN_CASE(MINT_BR)
2789 			/* Checkpoint to be able to handle aborts */
2790 			if (*mono_thread_interruption_request_flag ()) {
2791 				MonoException *exc = mono_thread_interruption_checkpoint ();
2792 				if (exc)
2793 					THROW_EX (exc, ip);
2794 			}
2795 			ip += (gint32) READ32(ip + 1);
2796 			MINT_IN_BREAK;
2797 #define ZEROP_S(datamem, op) \
2798 	--sp; \
2799 	if (sp->data.datamem op 0) \
2800 		ip += * (gint16 *)(ip + 1); \
2801 	else \
2802 		ip += 2;
2803 
2804 #define ZEROP(datamem, op) \
2805 	--sp; \
2806 	if (sp->data.datamem op 0) \
2807 		ip += READ32(ip + 1); \
2808 	else \
2809 		ip += 3;
2810 
2811 		MINT_IN_CASE(MINT_BRFALSE_I4_S)
2812 			ZEROP_S(i, ==);
2813 			MINT_IN_BREAK;
2814 		MINT_IN_CASE(MINT_BRFALSE_I8_S)
2815 			ZEROP_S(l, ==);
2816 			MINT_IN_BREAK;
2817 		MINT_IN_CASE(MINT_BRFALSE_R8_S)
2818 			ZEROP_S(f, ==);
2819 			MINT_IN_BREAK;
2820 		MINT_IN_CASE(MINT_BRFALSE_I4)
2821 			ZEROP(i, ==);
2822 			MINT_IN_BREAK;
2823 		MINT_IN_CASE(MINT_BRFALSE_I8)
2824 			ZEROP(l, ==);
2825 			MINT_IN_BREAK;
2826 		MINT_IN_CASE(MINT_BRFALSE_R8)
2827 			ZEROP_S(f, ==);
2828 			MINT_IN_BREAK;
2829 		MINT_IN_CASE(MINT_BRTRUE_I4_S)
2830 			ZEROP_S(i, !=);
2831 			MINT_IN_BREAK;
2832 		MINT_IN_CASE(MINT_BRTRUE_I8_S)
2833 			ZEROP_S(l, !=);
2834 			MINT_IN_BREAK;
2835 		MINT_IN_CASE(MINT_BRTRUE_R8_S)
2836 			ZEROP_S(f, !=);
2837 			MINT_IN_BREAK;
2838 		MINT_IN_CASE(MINT_BRTRUE_I4)
2839 			ZEROP(i, !=);
2840 			MINT_IN_BREAK;
2841 		MINT_IN_CASE(MINT_BRTRUE_I8)
2842 			ZEROP(l, !=);
2843 			MINT_IN_BREAK;
2844 		MINT_IN_CASE(MINT_BRTRUE_R8)
2845 			ZEROP(f, !=);
2846 			MINT_IN_BREAK;
2847 #define CONDBR_S(cond) \
2848 	sp -= 2; \
2849 	if (cond) \
2850 		ip += * (gint16 *)(ip + 1); \
2851 	else \
2852 		ip += 2;
2853 #define BRELOP_S(datamem, op) \
2854 	CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
2855 
2856 #define CONDBR(cond) \
2857 	sp -= 2; \
2858 	if (cond) \
2859 		ip += READ32(ip + 1); \
2860 	else \
2861 		ip += 3;
2862 
2863 #define BRELOP(datamem, op) \
2864 	CONDBR(sp[0].data.datamem op sp[1].data.datamem)
2865 
2866 		MINT_IN_CASE(MINT_BEQ_I4_S)
2867 			BRELOP_S(i, ==)
2868 			MINT_IN_BREAK;
2869 		MINT_IN_CASE(MINT_BEQ_I8_S)
2870 			BRELOP_S(l, ==)
2871 			MINT_IN_BREAK;
2872 		MINT_IN_CASE(MINT_BEQ_R8_S)
2873 			CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
2874 			MINT_IN_BREAK;
2875 		MINT_IN_CASE(MINT_BEQ_I4)
2876 			BRELOP(i, ==)
2877 			MINT_IN_BREAK;
2878 		MINT_IN_CASE(MINT_BEQ_I8)
2879 			BRELOP(l, ==)
2880 			MINT_IN_BREAK;
2881 		MINT_IN_CASE(MINT_BEQ_R8)
2882 			CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
2883 			MINT_IN_BREAK;
2884 		MINT_IN_CASE(MINT_BGE_I4_S)
2885 			BRELOP_S(i, >=)
2886 			MINT_IN_BREAK;
2887 		MINT_IN_CASE(MINT_BGE_I8_S)
2888 			BRELOP_S(l, >=)
2889 			MINT_IN_BREAK;
2890 		MINT_IN_CASE(MINT_BGE_R8_S)
2891 			CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
2892 			MINT_IN_BREAK;
2893 		MINT_IN_CASE(MINT_BGE_I4)
2894 			BRELOP(i, >=)
2895 			MINT_IN_BREAK;
2896 		MINT_IN_CASE(MINT_BGE_I8)
2897 			BRELOP(l, >=)
2898 			MINT_IN_BREAK;
2899 		MINT_IN_CASE(MINT_BGE_R8)
2900 			CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
2901 			MINT_IN_BREAK;
2902 		MINT_IN_CASE(MINT_BGT_I4_S)
2903 			BRELOP_S(i, >)
2904 			MINT_IN_BREAK;
2905 		MINT_IN_CASE(MINT_BGT_I8_S)
2906 			BRELOP_S(l, >)
2907 			MINT_IN_BREAK;
2908 		MINT_IN_CASE(MINT_BGT_R8_S)
2909 			CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
2910 			MINT_IN_BREAK;
2911 		MINT_IN_CASE(MINT_BGT_I4)
2912 			BRELOP(i, >)
2913 			MINT_IN_BREAK;
2914 		MINT_IN_CASE(MINT_BGT_I8)
2915 			BRELOP(l, >)
2916 			MINT_IN_BREAK;
2917 		MINT_IN_CASE(MINT_BGT_R8)
2918 			CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
2919 			MINT_IN_BREAK;
2920 		MINT_IN_CASE(MINT_BLT_I4_S)
2921 			BRELOP_S(i, <)
2922 			MINT_IN_BREAK;
2923 		MINT_IN_CASE(MINT_BLT_I8_S)
2924 			BRELOP_S(l, <)
2925 			MINT_IN_BREAK;
2926 		MINT_IN_CASE(MINT_BLT_R8_S)
2927 			CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
2928 			MINT_IN_BREAK;
2929 		MINT_IN_CASE(MINT_BLT_I4)
2930 			BRELOP(i, <)
2931 			MINT_IN_BREAK;
2932 		MINT_IN_CASE(MINT_BLT_I8)
2933 			BRELOP(l, <)
2934 			MINT_IN_BREAK;
2935 		MINT_IN_CASE(MINT_BLT_R8)
2936 			CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
2937 			MINT_IN_BREAK;
2938 		MINT_IN_CASE(MINT_BLE_I4_S)
2939 			BRELOP_S(i, <=)
2940 			MINT_IN_BREAK;
2941 		MINT_IN_CASE(MINT_BLE_I8_S)
2942 			BRELOP_S(l, <=)
2943 			MINT_IN_BREAK;
2944 		MINT_IN_CASE(MINT_BLE_R8_S)
2945 			CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
2946 			MINT_IN_BREAK;
2947 		MINT_IN_CASE(MINT_BLE_I4)
2948 			BRELOP(i, <=)
2949 			MINT_IN_BREAK;
2950 		MINT_IN_CASE(MINT_BLE_I8)
2951 			BRELOP(l, <=)
2952 			MINT_IN_BREAK;
2953 		MINT_IN_CASE(MINT_BLE_R8)
2954 			CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
2955 			MINT_IN_BREAK;
2956 		MINT_IN_CASE(MINT_BNE_UN_I4_S)
2957 			BRELOP_S(i, !=)
2958 			MINT_IN_BREAK;
2959 		MINT_IN_CASE(MINT_BNE_UN_I8_S)
2960 			BRELOP_S(l, !=)
2961 			MINT_IN_BREAK;
2962 		MINT_IN_CASE(MINT_BNE_UN_R8_S)
2963 			CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
2964 			MINT_IN_BREAK;
2965 		MINT_IN_CASE(MINT_BNE_UN_I4)
2966 			BRELOP(i, !=)
2967 			MINT_IN_BREAK;
2968 		MINT_IN_CASE(MINT_BNE_UN_I8)
2969 			BRELOP(l, !=)
2970 			MINT_IN_BREAK;
2971 		MINT_IN_CASE(MINT_BNE_UN_R8)
2972 			CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
2973 			MINT_IN_BREAK;
2974 
2975 #define BRELOP_S_CAST(datamem, op, type) \
2976 	sp -= 2; \
2977 	if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
2978 		ip += * (gint16 *)(ip + 1); \
2979 	else \
2980 		ip += 2;
2981 
2982 #define BRELOP_CAST(datamem, op, type) \
2983 	sp -= 2; \
2984 	if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
2985 		ip += READ32(ip + 1); \
2986 	else \
2987 		ip += 3;
2988 
2989 		MINT_IN_CASE(MINT_BGE_UN_I4_S)
2990 			BRELOP_S_CAST(i, >=, guint32);
2991 			MINT_IN_BREAK;
2992 		MINT_IN_CASE(MINT_BGE_UN_I8_S)
2993 			BRELOP_S_CAST(l, >=, guint64);
2994 			MINT_IN_BREAK;
2995 		MINT_IN_CASE(MINT_BGE_UN_R8_S)
2996 			CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
2997 			MINT_IN_BREAK;
2998 		MINT_IN_CASE(MINT_BGE_UN_I4)
2999 			BRELOP_CAST(i, >=, guint32);
3000 			MINT_IN_BREAK;
3001 		MINT_IN_CASE(MINT_BGE_UN_I8)
3002 			BRELOP_CAST(l, >=, guint64);
3003 			MINT_IN_BREAK;
3004 		MINT_IN_CASE(MINT_BGE_UN_R8)
3005 			CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3006 			MINT_IN_BREAK;
3007 		MINT_IN_CASE(MINT_BGT_UN_I4_S)
3008 			BRELOP_S_CAST(i, >, guint32);
3009 			MINT_IN_BREAK;
3010 		MINT_IN_CASE(MINT_BGT_UN_I8_S)
3011 			BRELOP_S_CAST(l, >, guint64);
3012 			MINT_IN_BREAK;
3013 		MINT_IN_CASE(MINT_BGT_UN_R8_S)
3014 			CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
3015 			MINT_IN_BREAK;
3016 		MINT_IN_CASE(MINT_BGT_UN_I4)
3017 			BRELOP_CAST(i, >, guint32);
3018 			MINT_IN_BREAK;
3019 		MINT_IN_CASE(MINT_BGT_UN_I8)
3020 			BRELOP_CAST(l, >, guint64);
3021 			MINT_IN_BREAK;
3022 		MINT_IN_CASE(MINT_BGT_UN_R8)
3023 			CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
3024 			MINT_IN_BREAK;
3025 		MINT_IN_CASE(MINT_BLE_UN_I4_S)
3026 			BRELOP_S_CAST(i, <=, guint32);
3027 			MINT_IN_BREAK;
3028 		MINT_IN_CASE(MINT_BLE_UN_I8_S)
3029 			BRELOP_S_CAST(l, <=, guint64);
3030 			MINT_IN_BREAK;
3031 		MINT_IN_CASE(MINT_BLE_UN_R8_S)
3032 			CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
3033 			MINT_IN_BREAK;
3034 		MINT_IN_CASE(MINT_BLE_UN_I4)
3035 			BRELOP_CAST(i, <=, guint32);
3036 			MINT_IN_BREAK;
3037 		MINT_IN_CASE(MINT_BLE_UN_I8)
3038 			BRELOP_CAST(l, <=, guint64);
3039 			MINT_IN_BREAK;
3040 		MINT_IN_CASE(MINT_BLE_UN_R8)
3041 			CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
3042 			MINT_IN_BREAK;
3043 		MINT_IN_CASE(MINT_BLT_UN_I4_S)
3044 			BRELOP_S_CAST(i, <, guint32);
3045 			MINT_IN_BREAK;
3046 		MINT_IN_CASE(MINT_BLT_UN_I8_S)
3047 			BRELOP_S_CAST(l, <, guint64);
3048 			MINT_IN_BREAK;
3049 		MINT_IN_CASE(MINT_BLT_UN_R8_S)
3050 			CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
3051 			MINT_IN_BREAK;
3052 		MINT_IN_CASE(MINT_BLT_UN_I4)
3053 			BRELOP_CAST(i, <, guint32);
3054 			MINT_IN_BREAK;
3055 		MINT_IN_CASE(MINT_BLT_UN_I8)
3056 			BRELOP_CAST(l, <, guint64);
3057 			MINT_IN_BREAK;
3058 		MINT_IN_CASE(MINT_BLT_UN_R8)
3059 			CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
3060 			MINT_IN_BREAK;
3061 		MINT_IN_CASE(MINT_SWITCH) {
3062 			guint32 n;
3063 			const unsigned short *st;
3064 			++ip;
3065 			n = READ32 (ip);
3066 			ip += 2;
3067 			st = ip + 2 * n;
3068 			--sp;
3069 			if ((guint32)sp->data.i < n) {
3070 				gint offset;
3071 				ip += 2 * (guint32)sp->data.i;
3072 				offset = READ32 (ip);
3073 				ip = ip + offset;
3074 			} else {
3075 				ip = st;
3076 			}
3077 			MINT_IN_BREAK;
3078 		}
3079 		MINT_IN_CASE(MINT_LDIND_I1)
3080 			++ip;
3081 			sp[-1].data.i = *(gint8*)sp[-1].data.p;
3082 			MINT_IN_BREAK;
3083 		MINT_IN_CASE(MINT_LDIND_U1)
3084 			++ip;
3085 			sp[-1].data.i = *(guint8*)sp[-1].data.p;
3086 			MINT_IN_BREAK;
3087 		MINT_IN_CASE(MINT_LDIND_I2)
3088 			++ip;
3089 			sp[-1].data.i = *(gint16*)sp[-1].data.p;
3090 			MINT_IN_BREAK;
3091 		MINT_IN_CASE(MINT_LDIND_U2)
3092 			++ip;
3093 			sp[-1].data.i = *(guint16*)sp[-1].data.p;
3094 			MINT_IN_BREAK;
3095 		MINT_IN_CASE(MINT_LDIND_I4) /* Fall through */
3096 		MINT_IN_CASE(MINT_LDIND_U4)
3097 			++ip;
3098 			sp[-1].data.i = *(gint32*)sp[-1].data.p;
3099 			MINT_IN_BREAK;
3100 		MINT_IN_CASE(MINT_LDIND_I8)
3101 			++ip;
3102 			/* memmove handles unaligned case */
3103 			memmove (&sp [-1].data.l, sp [-1].data.p, sizeof (gint64));
3104 			MINT_IN_BREAK;
3105 		MINT_IN_CASE(MINT_LDIND_I) {
3106 			guint16 offset = * (guint16 *)(ip + 1);
3107 			sp[-1 - offset].data.p = *(gpointer*)sp[-1 - offset].data.p;
3108 			ip += 2;
3109 			MINT_IN_BREAK;
3110 		}
3111 		MINT_IN_CASE(MINT_LDIND_R4)
3112 			++ip;
3113 			sp[-1].data.f = *(gfloat*)sp[-1].data.p;
3114 			MINT_IN_BREAK;
3115 		MINT_IN_CASE(MINT_LDIND_R8)
3116 			++ip;
3117 			sp[-1].data.f = *(gdouble*)sp[-1].data.p;
3118 			MINT_IN_BREAK;
3119 		MINT_IN_CASE(MINT_LDIND_REF)
3120 			++ip;
3121 			sp[-1].data.p = *(gpointer*)sp[-1].data.p;
3122 			MINT_IN_BREAK;
3123 		MINT_IN_CASE(MINT_STIND_REF)
3124 			++ip;
3125 			sp -= 2;
3126 			mono_gc_wbarrier_generic_store (sp->data.p, sp [1].data.p);
3127 			MINT_IN_BREAK;
3128 		MINT_IN_CASE(MINT_STIND_I1)
3129 			++ip;
3130 			sp -= 2;
3131 			* (gint8 *) sp->data.p = (gint8)sp[1].data.i;
3132 			MINT_IN_BREAK;
3133 		MINT_IN_CASE(MINT_STIND_I2)
3134 			++ip;
3135 			sp -= 2;
3136 			* (gint16 *) sp->data.p = (gint16)sp[1].data.i;
3137 			MINT_IN_BREAK;
3138 		MINT_IN_CASE(MINT_STIND_I4)
3139 			++ip;
3140 			sp -= 2;
3141 			* (gint32 *) sp->data.p = sp[1].data.i;
3142 			MINT_IN_BREAK;
3143 		MINT_IN_CASE(MINT_STIND_I)
3144 			++ip;
3145 			sp -= 2;
3146 			* (mono_i *) sp->data.p = (mono_i)sp[1].data.p;
3147 			MINT_IN_BREAK;
3148 		MINT_IN_CASE(MINT_STIND_I8)
3149 			++ip;
3150 			sp -= 2;
3151 			* (gint64 *) sp->data.p = sp[1].data.l;
3152 			MINT_IN_BREAK;
3153 		MINT_IN_CASE(MINT_STIND_R4)
3154 			++ip;
3155 			sp -= 2;
3156 			* (float *) sp->data.p = (gfloat)sp[1].data.f;
3157 			MINT_IN_BREAK;
3158 		MINT_IN_CASE(MINT_STIND_R8)
3159 			++ip;
3160 			sp -= 2;
3161 			* (double *) sp->data.p = sp[1].data.f;
3162 			MINT_IN_BREAK;
3163 		MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4)
3164 			++ip;
3165 			sp -= 2;
3166 			mono_atomic_store_i32 ((gint32 *) sp->data.p, sp [1].data.i);
3167 			MINT_IN_BREAK;
3168 #define BINOP(datamem, op) \
3169 	--sp; \
3170 	sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
3171 	++ip;
3172 		MINT_IN_CASE(MINT_ADD_I4)
3173 			BINOP(i, +);
3174 			MINT_IN_BREAK;
3175 		MINT_IN_CASE(MINT_ADD_I8)
3176 			BINOP(l, +);
3177 			MINT_IN_BREAK;
3178 		MINT_IN_CASE(MINT_ADD_R8)
3179 			BINOP(f, +);
3180 			MINT_IN_BREAK;
3181 		MINT_IN_CASE(MINT_ADD1_I4)
3182 			++sp [-1].data.i;
3183 			++ip;
3184 			MINT_IN_BREAK;
3185 		MINT_IN_CASE(MINT_SUB_I4)
3186 			BINOP(i, -);
3187 			MINT_IN_BREAK;
3188 		MINT_IN_CASE(MINT_SUB_I8)
3189 			BINOP(l, -);
3190 			MINT_IN_BREAK;
3191 		MINT_IN_CASE(MINT_SUB_R8)
3192 			BINOP(f, -);
3193 			MINT_IN_BREAK;
3194 		MINT_IN_CASE(MINT_SUB1_I4)
3195 			--sp [-1].data.i;
3196 			++ip;
3197 			MINT_IN_BREAK;
3198 		MINT_IN_CASE(MINT_MUL_I4)
3199 			BINOP(i, *);
3200 			MINT_IN_BREAK;
3201 		MINT_IN_CASE(MINT_MUL_I8)
3202 			BINOP(l, *);
3203 			MINT_IN_BREAK;
3204 		MINT_IN_CASE(MINT_MUL_R8)
3205 			BINOP(f, *);
3206 			MINT_IN_BREAK;
3207 		MINT_IN_CASE(MINT_DIV_I4)
3208 			if (sp [-1].data.i == 0)
3209 				THROW_EX (mono_get_exception_divide_by_zero (), ip);
3210 			if (sp [-1].data.i == (-1))
3211 				THROW_EX (mono_get_exception_overflow (), ip);
3212 			BINOP(i, /);
3213 			MINT_IN_BREAK;
3214 		MINT_IN_CASE(MINT_DIV_I8)
3215 			if (sp [-1].data.l == 0)
3216 				THROW_EX (mono_get_exception_divide_by_zero (), ip);
3217 			if (sp [-1].data.l == (-1))
3218 				THROW_EX (mono_get_exception_overflow (), ip);
3219 			BINOP(l, /);
3220 			MINT_IN_BREAK;
3221 		MINT_IN_CASE(MINT_DIV_R8)
3222 			BINOP(f, /);
3223 			MINT_IN_BREAK;
3224 
3225 #define BINOP_CAST(datamem, op, type) \
3226 	--sp; \
3227 	sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
3228 	++ip;
3229 		MINT_IN_CASE(MINT_DIV_UN_I4)
3230 			if (sp [-1].data.i == 0)
3231 				THROW_EX (mono_get_exception_divide_by_zero (), ip);
3232 			BINOP_CAST(i, /, guint32);
3233 			MINT_IN_BREAK;
3234 		MINT_IN_CASE(MINT_DIV_UN_I8)
3235 			if (sp [-1].data.l == 0)
3236 				THROW_EX (mono_get_exception_divide_by_zero (), ip);
3237 			BINOP_CAST(l, /, guint64);
3238 			MINT_IN_BREAK;
3239 		MINT_IN_CASE(MINT_REM_I4)
3240 			if (sp [-1].data.i == 0)
3241 				THROW_EX (mono_get_exception_divide_by_zero (), ip);
3242 			if (sp [-1].data.i == (-1))
3243 				THROW_EX (mono_get_exception_overflow (), ip);
3244 			BINOP(i, %);
3245 			MINT_IN_BREAK;
3246 		MINT_IN_CASE(MINT_REM_I8)
3247 			if (sp [-1].data.l == 0)
3248 				THROW_EX (mono_get_exception_divide_by_zero (), ip);
3249 			if (sp [-1].data.l == (-1))
3250 				THROW_EX (mono_get_exception_overflow (), ip);
3251 			BINOP(l, %);
3252 			MINT_IN_BREAK;
3253 		MINT_IN_CASE(MINT_REM_R8)
3254 			/* FIXME: what do we actually do here? */
3255 			--sp;
3256 			sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
3257 			++ip;
3258 			MINT_IN_BREAK;
3259 		MINT_IN_CASE(MINT_REM_UN_I4)
3260 			if (sp [-1].data.i == 0)
3261 				THROW_EX (mono_get_exception_divide_by_zero (), ip);
3262 			BINOP_CAST(i, %, guint32);
3263 			MINT_IN_BREAK;
3264 		MINT_IN_CASE(MINT_REM_UN_I8)
3265 			if (sp [-1].data.l == 0)
3266 				THROW_EX (mono_get_exception_divide_by_zero (), ip);
3267 			BINOP_CAST(l, %, guint64);
3268 			MINT_IN_BREAK;
3269 		MINT_IN_CASE(MINT_AND_I4)
3270 			BINOP(i, &);
3271 			MINT_IN_BREAK;
3272 		MINT_IN_CASE(MINT_AND_I8)
3273 			BINOP(l, &);
3274 			MINT_IN_BREAK;
3275 		MINT_IN_CASE(MINT_OR_I4)
3276 			BINOP(i, |);
3277 			MINT_IN_BREAK;
3278 		MINT_IN_CASE(MINT_OR_I8)
3279 			BINOP(l, |);
3280 			MINT_IN_BREAK;
3281 		MINT_IN_CASE(MINT_XOR_I4)
3282 			BINOP(i, ^);
3283 			MINT_IN_BREAK;
3284 		MINT_IN_CASE(MINT_XOR_I8)
3285 			BINOP(l, ^);
3286 			MINT_IN_BREAK;
3287 
3288 #define SHIFTOP(datamem, op) \
3289 	--sp; \
3290 	sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
3291 	++ip;
3292 
3293 		MINT_IN_CASE(MINT_SHL_I4)
3294 			SHIFTOP(i, <<);
3295 			MINT_IN_BREAK;
3296 		MINT_IN_CASE(MINT_SHL_I8)
3297 			SHIFTOP(l, <<);
3298 			MINT_IN_BREAK;
3299 		MINT_IN_CASE(MINT_SHR_I4)
3300 			SHIFTOP(i, >>);
3301 			MINT_IN_BREAK;
3302 		MINT_IN_CASE(MINT_SHR_I8)
3303 			SHIFTOP(l, >>);
3304 			MINT_IN_BREAK;
3305 		MINT_IN_CASE(MINT_SHR_UN_I4)
3306 			--sp;
3307 			sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i;
3308 			++ip;
3309 			MINT_IN_BREAK;
3310 		MINT_IN_CASE(MINT_SHR_UN_I8)
3311 			--sp;
3312 			sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i;
3313 			++ip;
3314 			MINT_IN_BREAK;
3315 		MINT_IN_CASE(MINT_NEG_I4)
3316 			sp [-1].data.i = - sp [-1].data.i;
3317 			++ip;
3318 			MINT_IN_BREAK;
3319 		MINT_IN_CASE(MINT_NEG_I8)
3320 			sp [-1].data.l = - sp [-1].data.l;
3321 			++ip;
3322 			MINT_IN_BREAK;
3323 		MINT_IN_CASE(MINT_NEG_R8)
3324 			sp [-1].data.f = - sp [-1].data.f;
3325 			++ip;
3326 			MINT_IN_BREAK;
3327 		MINT_IN_CASE(MINT_NOT_I4)
3328 			sp [-1].data.i = ~ sp [-1].data.i;
3329 			++ip;
3330 			MINT_IN_BREAK;
3331 		MINT_IN_CASE(MINT_NOT_I8)
3332 			sp [-1].data.l = ~ sp [-1].data.l;
3333 			++ip;
3334 			MINT_IN_BREAK;
3335 		MINT_IN_CASE(MINT_CONV_I1_I4)
3336 			sp [-1].data.i = (gint8)sp [-1].data.i;
3337 			++ip;
3338 			MINT_IN_BREAK;
3339 		MINT_IN_CASE(MINT_CONV_I1_I8)
3340 			sp [-1].data.i = (gint8)sp [-1].data.l;
3341 			++ip;
3342 			MINT_IN_BREAK;
3343 		MINT_IN_CASE(MINT_CONV_I1_R8)
3344 			sp [-1].data.i = (gint8)sp [-1].data.f;
3345 			++ip;
3346 			MINT_IN_BREAK;
3347 		MINT_IN_CASE(MINT_CONV_U1_I4)
3348 			sp [-1].data.i = (guint8)sp [-1].data.i;
3349 			++ip;
3350 			MINT_IN_BREAK;
3351 		MINT_IN_CASE(MINT_CONV_U1_I8)
3352 			sp [-1].data.i = (guint8)sp [-1].data.l;
3353 			++ip;
3354 			MINT_IN_BREAK;
3355 		MINT_IN_CASE(MINT_CONV_U1_R8)
3356 			sp [-1].data.i = (guint8)sp [-1].data.f;
3357 			++ip;
3358 			MINT_IN_BREAK;
3359 		MINT_IN_CASE(MINT_CONV_I2_I4)
3360 			sp [-1].data.i = (gint16)sp [-1].data.i;
3361 			++ip;
3362 			MINT_IN_BREAK;
3363 		MINT_IN_CASE(MINT_CONV_I2_I8)
3364 			sp [-1].data.i = (gint16)sp [-1].data.l;
3365 			++ip;
3366 			MINT_IN_BREAK;
3367 		MINT_IN_CASE(MINT_CONV_I2_R8)
3368 			sp [-1].data.i = (gint16)sp [-1].data.f;
3369 			++ip;
3370 			MINT_IN_BREAK;
3371 		MINT_IN_CASE(MINT_CONV_U2_I4)
3372 			sp [-1].data.i = (guint16)sp [-1].data.i;
3373 			++ip;
3374 			MINT_IN_BREAK;
3375 		MINT_IN_CASE(MINT_CONV_U2_I8)
3376 			sp [-1].data.i = (guint16)sp [-1].data.l;
3377 			++ip;
3378 			MINT_IN_BREAK;
3379 		MINT_IN_CASE(MINT_CONV_U2_R8)
3380 			sp [-1].data.i = (guint16)sp [-1].data.f;
3381 			++ip;
3382 			MINT_IN_BREAK;
3383 		MINT_IN_CASE(MINT_CONV_I4_R8)
3384 			sp [-1].data.i = (gint32)sp [-1].data.f;
3385 			++ip;
3386 			MINT_IN_BREAK;
3387 		MINT_IN_CASE(MINT_CONV_U4_I8)
3388 		MINT_IN_CASE(MINT_CONV_I4_I8)
3389 			sp [-1].data.i = (gint32)sp [-1].data.l;
3390 			++ip;
3391 			MINT_IN_BREAK;
3392 		MINT_IN_CASE(MINT_CONV_I4_I8_SP)
3393 			sp [-2].data.i = (gint32)sp [-2].data.l;
3394 			++ip;
3395 			MINT_IN_BREAK;
3396 		MINT_IN_CASE(MINT_CONV_U4_R8)
3397 			/* needed on arm64 */
3398 			if (isinf (sp [-1].data.f))
3399 				sp [-1].data.i = 0;
3400 			/* needed by wasm */
3401 			else if (isnan (sp [-1].data.f))
3402 				sp [-1].data.i = 0;
3403 			else
3404 				sp [-1].data.i = (guint32)sp [-1].data.f;
3405 			++ip;
3406 			MINT_IN_BREAK;
3407 		MINT_IN_CASE(MINT_CONV_I8_I4)
3408 			sp [-1].data.l = sp [-1].data.i;
3409 			++ip;
3410 			MINT_IN_BREAK;
3411 		MINT_IN_CASE(MINT_CONV_I8_I4_SP)
3412 			sp [-2].data.l = sp [-2].data.i;
3413 			++ip;
3414 			MINT_IN_BREAK;
3415 		MINT_IN_CASE(MINT_CONV_I8_U4)
3416 			sp [-1].data.l = (guint32)sp [-1].data.i;
3417 			++ip;
3418 			MINT_IN_BREAK;
3419 		MINT_IN_CASE(MINT_CONV_I8_R8)
3420 			sp [-1].data.l = (gint64)sp [-1].data.f;
3421 			++ip;
3422 			MINT_IN_BREAK;
3423 		MINT_IN_CASE(MINT_CONV_R4_I4)
3424 			sp [-1].data.f = (float)sp [-1].data.i;
3425 			++ip;
3426 			MINT_IN_BREAK;
3427 		MINT_IN_CASE(MINT_CONV_R4_I8)
3428 			sp [-1].data.f = (float)sp [-1].data.l;
3429 			++ip;
3430 			MINT_IN_BREAK;
3431 		MINT_IN_CASE(MINT_CONV_R4_R8)
3432 			sp [-1].data.f = (float)sp [-1].data.f;
3433 			++ip;
3434 			MINT_IN_BREAK;
3435 		MINT_IN_CASE(MINT_CONV_R8_I4)
3436 			sp [-1].data.f = (double)sp [-1].data.i;
3437 			++ip;
3438 			MINT_IN_BREAK;
3439 		MINT_IN_CASE(MINT_CONV_R8_I8)
3440 			sp [-1].data.f = (double)sp [-1].data.l;
3441 			++ip;
3442 			MINT_IN_BREAK;
3443 		MINT_IN_CASE(MINT_CONV_U8_I4)
3444 			sp [-1].data.l = sp [-1].data.i & 0xffffffff;
3445 			++ip;
3446 			MINT_IN_BREAK;
3447 		MINT_IN_CASE(MINT_CONV_U8_R8)
3448 			sp [-1].data.l = (guint64)sp [-1].data.f;
3449 			++ip;
3450 			MINT_IN_BREAK;
3451 		MINT_IN_CASE(MINT_CPOBJ) {
3452 			c = rtm->data_items[* (guint16 *)(ip + 1)];
3453 			g_assert (c->valuetype);
3454 			/* if this assertion fails, we need to add a write barrier */
3455 			g_assert (!MONO_TYPE_IS_REFERENCE (&c->byval_arg));
3456 			if (mint_type (&c->byval_arg) == MINT_TYPE_VT)
3457 				stackval_from_data (&c->byval_arg, &sp [-2], sp [-1].data.p, FALSE);
3458 			else
3459 				stackval_from_data (&c->byval_arg, sp [-2].data.p, sp [-1].data.p, FALSE);
3460 			ip += 2;
3461 			sp -= 2;
3462 			MINT_IN_BREAK;
3463 		}
3464 		MINT_IN_CASE(MINT_LDOBJ) {
3465 			void *p;
3466 			c = rtm->data_items[* (guint16 *)(ip + 1)];
3467 			ip += 2;
3468 			p = sp [-1].data.p;
3469 			if (mint_type (&c->byval_arg) == MINT_TYPE_VT && !c->enumtype) {
3470 				int size = mono_class_value_size (c, NULL);
3471 				sp [-1].data.p = vt_sp;
3472 				vt_sp += (size + 7) & ~7;
3473 			}
3474 			stackval_from_data (&c->byval_arg, &sp [-1], p, FALSE);
3475 			MINT_IN_BREAK;
3476 		}
3477 		MINT_IN_CASE(MINT_LDSTR)
3478 			sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)];
3479 			++sp;
3480 			ip += 2;
3481 			MINT_IN_BREAK;
3482 		MINT_IN_CASE(MINT_NEWOBJ) {
3483 			MonoClass *newobj_class;
3484 			MonoMethodSignature *csig;
3485 			stackval valuetype_this;
3486 			guint32 token;
3487 			stackval retval;
3488 
3489 			frame->ip = ip;
3490 
3491 			token = * (guint16 *)(ip + 1);
3492 			ip += 2;
3493 
3494 			child_frame.ip = NULL;
3495 			child_frame.ex = NULL;
3496 
3497 			child_frame.imethod = rtm->data_items [token];
3498 			csig = mono_method_signature (child_frame.imethod->method);
3499 			newobj_class = child_frame.imethod->method->klass;
3500 			/*if (profiling_classes) {
3501 				guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3502 				count++;
3503 				g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3504 			}*/
3505 
3506 			if (newobj_class->parent == mono_defaults.array_class) {
3507 				sp -= csig->param_count;
3508 				child_frame.stack_args = sp;
3509 				o = ves_array_create (&child_frame, rtm->domain, newobj_class, csig, sp);
3510 				CHECK_CHILD_EX (child_frame, ip - 2);
3511 				goto array_constructed;
3512 			}
3513 
3514 			g_assert (csig->hasthis);
3515 			if (csig->param_count) {
3516 				sp -= csig->param_count;
3517 				memmove (sp + 1, sp, csig->param_count * sizeof (stackval));
3518 			}
3519 			child_frame.stack_args = sp;
3520 
3521 			/*
3522 			 * First arg is the object.
3523 			 */
3524 			if (newobj_class->valuetype) {
3525 				MonoType *t = &newobj_class->byval_arg;
3526 				memset (&valuetype_this, 0, sizeof (stackval));
3527 				if (!newobj_class->enumtype && (t->type == MONO_TYPE_VALUETYPE || (t->type == MONO_TYPE_GENERICINST && mono_type_generic_inst_is_valuetype (t)))) {
3528 					sp->data.p = vt_sp;
3529 					valuetype_this.data.p = vt_sp;
3530 				} else {
3531 					sp->data.p = &valuetype_this;
3532 				}
3533 			} else {
3534 				if (newobj_class != mono_defaults.string_class) {
3535 					o = mono_object_new_checked (rtm->domain, newobj_class, &error);
3536 					mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3537 					if (*mono_thread_interruption_request_flag ()) {
3538 						MonoException *exc = mono_thread_interruption_checkpoint ();
3539 						if (exc) {
3540 							frame->ex = exc;
3541 							context->search_for_handler = 1;
3542 						}
3543 					}
3544 					sp->data.p = o;
3545 #ifndef DISABLE_REMOTING
3546 					if (mono_object_is_transparent_proxy (o)) {
3547 						child_frame.imethod = mono_interp_get_imethod (rtm->domain, mono_marshal_get_remoting_invoke_with_check (child_frame.imethod->method), &error);
3548 						mono_error_assert_ok (&error);
3549 					}
3550 #endif
3551 				} else {
3552 					sp->data.p = NULL;
3553 					child_frame.retval = &retval;
3554 				}
3555 			}
3556 
3557 			g_assert (csig->call_convention == MONO_CALL_DEFAULT);
3558 
3559 			interp_exec_method (&child_frame, context);
3560 
3561 			context->current_frame = frame;
3562 
3563 			if (context->has_resume_state) {
3564 				if (frame == context->handler_frame)
3565 					SET_RESUME_STATE (context);
3566 				else
3567 					goto exit_frame;
3568 			}
3569 
3570 			CHECK_CHILD_EX (child_frame, ip - 2);
3571 			/*
3572 			 * a constructor returns void, but we need to return the object we created
3573 			 */
3574 array_constructed:
3575 			if (newobj_class->valuetype && !newobj_class->enumtype) {
3576 				*sp = valuetype_this;
3577 			} else if (newobj_class == mono_defaults.string_class) {
3578 				*sp = retval;
3579 			} else {
3580 				sp->data.p = o;
3581 			}
3582 			++sp;
3583 			MINT_IN_BREAK;
3584 		}
3585 		MINT_IN_CASE(MINT_NEWOBJ_MAGIC) {
3586 			guint32 token;
3587 
3588 			frame->ip = ip;
3589 			token = * (guint16 *)(ip + 1);
3590 			ip += 2;
3591 
3592 			MINT_IN_BREAK;
3593 		}
3594 		MINT_IN_CASE(MINT_CASTCLASS)
3595 			c = rtm->data_items [*(guint16 *)(ip + 1)];
3596 			if ((o = sp [-1].data.p)) {
3597 				MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error);
3598 				mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3599 				if (!isinst_obj)
3600 					THROW_EX (mono_get_exception_invalid_cast (), ip);
3601 			}
3602 			ip += 2;
3603 			MINT_IN_BREAK;
3604 		MINT_IN_CASE(MINT_ISINST)
3605 			c = rtm->data_items [*(guint16 *)(ip + 1)];
3606 			if ((o = sp [-1].data.p)) {
3607 				MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error);
3608 				mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3609 				if (!isinst_obj)
3610 					sp [-1].data.p = NULL;
3611 			}
3612 			ip += 2;
3613 			MINT_IN_BREAK;
3614 		MINT_IN_CASE(MINT_CONV_R_UN_I4)
3615 			sp [-1].data.f = (double)(guint32)sp [-1].data.i;
3616 			++ip;
3617 			MINT_IN_BREAK;
3618 		MINT_IN_CASE(MINT_CONV_R_UN_I8)
3619 			sp [-1].data.f = (double)(guint64)sp [-1].data.l;
3620 			++ip;
3621 			MINT_IN_BREAK;
3622 		MINT_IN_CASE(MINT_UNBOX)
3623 			c = rtm->data_items[*(guint16 *)(ip + 1)];
3624 
3625 			o = sp [-1].data.p;
3626 			if (!o)
3627 				THROW_EX (mono_get_exception_null_reference (), ip);
3628 
3629 			MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error);
3630 			mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3631 			if (!(isinst_obj || ((o->vtable->klass->rank == 0) && (o->vtable->klass->element_class == c->element_class))))
3632 				THROW_EX (mono_get_exception_invalid_cast (), ip);
3633 
3634 			sp [-1].data.p = mono_object_unbox (o);
3635 			ip += 2;
3636 			MINT_IN_BREAK;
3637 		MINT_IN_CASE(MINT_THROW)
3638 			--sp;
3639 			frame->ex_handler = NULL;
3640 			if (!sp->data.p)
3641 				sp->data.p = mono_get_exception_null_reference ();
3642 
3643 			THROW_EX ((MonoException *)sp->data.p, ip);
3644 			MINT_IN_BREAK;
3645 		MINT_IN_CASE(MINT_LDFLDA_UNSAFE)
3646 			o = sp [-1].data.p;
3647 			sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
3648 			ip += 2;
3649 			MINT_IN_BREAK;
3650 		MINT_IN_CASE(MINT_LDFLDA)
3651 			o = sp [-1].data.p;
3652 			if (!o)
3653 				THROW_EX (mono_get_exception_null_reference (), ip);
3654 			sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
3655 			ip += 2;
3656 			MINT_IN_BREAK;
3657 		MINT_IN_CASE(MINT_CKNULL)
3658 			o = sp [-1].data.p;
3659 			if (!o)
3660 				THROW_EX (mono_get_exception_null_reference (), ip);
3661 			++ip;
3662 			MINT_IN_BREAK;
3663 		MINT_IN_CASE(MINT_CKNULL_N) {
3664 			/* Same as CKNULL, but further down the stack */
3665 			int n = *(guint16*)(ip + 1);
3666 			o = sp [-n].data.p;
3667 			if (!o)
3668 				THROW_EX (mono_get_exception_null_reference (), ip);
3669 			ip += 2;
3670 			MINT_IN_BREAK;
3671 		}
3672 
3673 #define LDFLD(datamem, fieldtype) \
3674 	o = sp [-1].data.p; \
3675 	if (!o) \
3676 		THROW_EX (mono_get_exception_null_reference (), ip); \
3677 	sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
3678 	ip += 2;
3679 
3680 		MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK;
3681 		MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK;
3682 		MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK;
3683 		MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK;
3684 		MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK;
3685 		MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK;
3686 		MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f, float); MINT_IN_BREAK;
3687 		MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK;
3688 		MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK;
3689 		MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK;
3690 
3691 		MINT_IN_CASE(MINT_LDFLD_VT)
3692 			o = sp [-1].data.p;
3693 			if (!o)
3694 				THROW_EX (mono_get_exception_null_reference (), ip);
3695 
3696 			MonoClassField *field = rtm->data_items[* (guint16 *)(ip + 2)];
3697 			MonoClass *klass = mono_class_from_mono_type (field->type);
3698 			i32 = mono_class_value_size (klass, NULL);
3699 
3700 			sp [-1].data.p = vt_sp;
3701 			memcpy (sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32);
3702 			vt_sp += (i32 + 7) & ~7;
3703 			ip += 3;
3704 			MINT_IN_BREAK;
3705 
3706 		MINT_IN_CASE(MINT_LDRMFLD) {
3707 			gpointer tmp;
3708 			MonoClassField *field;
3709 			char *addr;
3710 
3711 			o = sp [-1].data.p;
3712 			if (!o)
3713 				THROW_EX (mono_get_exception_null_reference (), ip);
3714 			field = rtm->data_items[* (guint16 *)(ip + 1)];
3715 			ip += 2;
3716 #ifndef DISABLE_REMOTING
3717 			if (mono_object_is_transparent_proxy (o)) {
3718 				MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3719 
3720 				addr = mono_load_remote_field_checked (o, klass, field, &tmp, &error);
3721 				mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3722 			} else
3723 #endif
3724 				addr = (char*)o + field->offset;
3725 
3726 			stackval_from_data (field->type, &sp [-1], addr, FALSE);
3727 			MINT_IN_BREAK;
3728 		}
3729 
3730 		MINT_IN_CASE(MINT_LDRMFLD_VT) {
3731 			MonoClassField *field;
3732 			char *addr;
3733 			gpointer tmp;
3734 
3735 			o = sp [-1].data.p;
3736 			if (!o)
3737 				THROW_EX (mono_get_exception_null_reference (), ip);
3738 
3739 			field = rtm->data_items[* (guint16 *)(ip + 1)];
3740 			MonoClass *klass = mono_class_from_mono_type (field->type);
3741 			i32 = mono_class_value_size (klass, NULL);
3742 
3743 			ip += 2;
3744 #ifndef DISABLE_REMOTING
3745 			if (mono_object_is_transparent_proxy (o)) {
3746 				MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3747 				addr = mono_load_remote_field_checked (o, klass, field, &tmp, &error);
3748 				mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3749 			} else
3750 #endif
3751 				addr = (char*)o + field->offset;
3752 
3753 			sp [-1].data.p = vt_sp;
3754 			memcpy(sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32);
3755 			vt_sp += (i32 + 7) & ~7;
3756 			memcpy(sp [-1].data.p, addr, i32);
3757 			MINT_IN_BREAK;
3758 		}
3759 
3760 #define STFLD(datamem, fieldtype) \
3761 	o = sp [-2].data.p; \
3762 	if (!o) \
3763 		THROW_EX (mono_get_exception_null_reference (), ip); \
3764 	sp -= 2; \
3765 	* (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
3766 	ip += 2;
3767 
3768 		MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK;
3769 		MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK;
3770 		MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK;
3771 		MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK;
3772 		MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK;
3773 		MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK;
3774 		MINT_IN_CASE(MINT_STFLD_R4) STFLD(f, float); MINT_IN_BREAK;
3775 		MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK;
3776 		MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK;
3777 		MINT_IN_CASE(MINT_STFLD_O)
3778 			o = sp [-2].data.p;
3779 			if (!o)
3780 				THROW_EX (mono_get_exception_null_reference (), ip);
3781 			sp -= 2;
3782 			mono_gc_wbarrier_set_field (o, (char *) o + * (guint16 *)(ip + 1), sp [1].data.p);
3783 			ip += 2;
3784 			MINT_IN_BREAK;
3785 
3786 		MINT_IN_CASE(MINT_STFLD_VT) {
3787 			o = sp [-2].data.p;
3788 			if (!o)
3789 				THROW_EX (mono_get_exception_null_reference (), ip);
3790 			sp -= 2;
3791 
3792 			MonoClassField *field = rtm->data_items[* (guint16 *)(ip + 2)];
3793 			MonoClass *klass = mono_class_from_mono_type (field->type);
3794 			i32 = mono_class_value_size (klass, NULL);
3795 
3796 			guint16 offset = * (guint16 *)(ip + 1);
3797 			mono_value_copy ((char *) o + offset, sp [1].data.p, klass);
3798 
3799 			vt_sp -= (i32 + 7) & ~7;
3800 			ip += 3;
3801 			MINT_IN_BREAK;
3802 		}
3803 		MINT_IN_CASE(MINT_STRMFLD) {
3804 			MonoClassField *field;
3805 
3806 			o = sp [-2].data.p;
3807 			if (!o)
3808 				THROW_EX (mono_get_exception_null_reference (), ip);
3809 
3810 			field = rtm->data_items[* (guint16 *)(ip + 1)];
3811 			ip += 2;
3812 
3813 #ifndef DISABLE_REMOTING
3814 			if (mono_object_is_transparent_proxy (o)) {
3815 				MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3816 				mono_store_remote_field_checked (o, klass, field, &sp [-1].data, &error);
3817 				mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3818 			} else
3819 #endif
3820 				stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE);
3821 
3822 			sp -= 2;
3823 			MINT_IN_BREAK;
3824 		}
3825 		MINT_IN_CASE(MINT_STRMFLD_VT) {
3826 			MonoClassField *field;
3827 
3828 			o = sp [-2].data.p;
3829 			if (!o)
3830 				THROW_EX (mono_get_exception_null_reference (), ip);
3831 			field = rtm->data_items[* (guint16 *)(ip + 1)];
3832 			MonoClass *klass = mono_class_from_mono_type (field->type);
3833 			i32 = mono_class_value_size (klass, NULL);
3834 			ip += 2;
3835 
3836 #ifndef DISABLE_REMOTING
3837 			if (mono_object_is_transparent_proxy (o)) {
3838 				MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3839 				mono_store_remote_field_checked (o, klass, field, &sp [-1].data, &error);
3840 				mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3841 			} else
3842 #endif
3843 				mono_value_copy ((char *) o + field->offset, sp [-1].data.p, klass);
3844 
3845 			sp -= 2;
3846 			vt_sp -= (i32 + 7) & ~7;
3847 			MINT_IN_BREAK;
3848 		}
3849 		MINT_IN_CASE(MINT_LDSFLDA) {
3850 			MonoClassField *field = rtm->data_items[*(guint16 *)(ip + 1)];
3851 			sp->data.p = mono_class_static_field_address (rtm->domain, field);
3852 			ip += 2;
3853 			++sp;
3854 			MINT_IN_BREAK;
3855 		}
3856 		MINT_IN_CASE(MINT_LDSFLD) {
3857 			MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3858 			gpointer addr = mono_class_static_field_address (rtm->domain, field);
3859 			stackval_from_data (field->type, sp, addr, FALSE);
3860 			ip += 2;
3861 			++sp;
3862 			MINT_IN_BREAK;
3863 		}
3864 		MINT_IN_CASE(MINT_LDSFLD_VT) {
3865 			MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3866 			gpointer addr = mono_class_static_field_address (rtm->domain, field);
3867 			int size = READ32 (ip + 2);
3868 			ip += 4;
3869 
3870 			sp->data.p = vt_sp;
3871 			vt_sp += (size + 7) & ~7;
3872 			stackval_from_data (field->type, sp, addr, FALSE);
3873 			++sp;
3874 			MINT_IN_BREAK;
3875 		}
3876 		MINT_IN_CASE(MINT_STSFLD) {
3877 			MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3878 			gpointer addr = mono_class_static_field_address (rtm->domain, field);
3879 			ip += 2;
3880 			--sp;
3881 			stackval_to_data (field->type, sp, addr, FALSE);
3882 			MINT_IN_BREAK;
3883 		}
3884 		MINT_IN_CASE(MINT_STSFLD_VT) {
3885 			MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3886 			gpointer addr = mono_class_static_field_address (rtm->domain, field);
3887 			MonoClass *klass = mono_class_from_mono_type (field->type);
3888 			i32 = mono_class_value_size (klass, NULL);
3889 			ip += 2;
3890 
3891 			--sp;
3892 			stackval_to_data (field->type, sp, addr, FALSE);
3893 			vt_sp -= (i32 + 7) & ~7;
3894 			MINT_IN_BREAK;
3895 		}
3896 		MINT_IN_CASE(MINT_STOBJ_VT) {
3897 			int size;
3898 			c = rtm->data_items[* (guint16 *)(ip + 1)];
3899 			ip += 2;
3900 			size = mono_class_value_size (c, NULL);
3901 			memcpy(sp [-2].data.p, sp [-1].data.p, size);
3902 			vt_sp -= (size + 7) & ~7;
3903 			sp -= 2;
3904 			MINT_IN_BREAK;
3905 		}
3906 		MINT_IN_CASE(MINT_STOBJ) {
3907 			c = rtm->data_items[* (guint16 *)(ip + 1)];
3908 			ip += 2;
3909 
3910 			g_assert (!c->byval_arg.byref);
3911 			if (MONO_TYPE_IS_REFERENCE (&c->byval_arg))
3912 				mono_gc_wbarrier_generic_store (sp [-2].data.p, sp [-1].data.p);
3913 			else
3914 				stackval_from_data (&c->byval_arg, sp [-2].data.p, (char *) &sp [-1].data.p, FALSE);
3915 			sp -= 2;
3916 			MINT_IN_BREAK;
3917 		}
3918 		MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8)
3919 			if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT32_MAX)
3920 				THROW_EX (mono_get_exception_overflow (), ip);
3921 			sp [-1].data.i = (guint32)sp [-1].data.f;
3922 			++ip;
3923 			MINT_IN_BREAK;
3924 		MINT_IN_CASE(MINT_CONV_OVF_U8_I4)
3925 			if (sp [-1].data.i < 0)
3926 				THROW_EX (mono_get_exception_overflow (), ip);
3927 			sp [-1].data.l = sp [-1].data.i;
3928 			++ip;
3929 			MINT_IN_BREAK;
3930 		MINT_IN_CASE(MINT_CONV_OVF_U8_I8)
3931 			if (sp [-1].data.l < 0)
3932 				THROW_EX (mono_get_exception_overflow (), ip);
3933 			++ip;
3934 			MINT_IN_BREAK;
3935 		MINT_IN_CASE(MINT_CONV_OVF_I8_U8)
3936 			if ((guint64) sp [-1].data.l > MYGINT64_MAX)
3937 				THROW_EX (mono_get_exception_overflow (), ip);
3938 			++ip;
3939 			MINT_IN_BREAK;
3940 		MINT_IN_CASE(MINT_CONV_OVF_U8_R8)
3941 		MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8)
3942 			if (sp [-1].data.f < 0 || sp [-1].data.f > MYGINT64_MAX)
3943 				THROW_EX (mono_get_exception_overflow (), ip);
3944 			sp [-1].data.l = (guint64)sp [-1].data.f;
3945 			++ip;
3946 			MINT_IN_BREAK;
3947 		MINT_IN_CASE(MINT_CONV_OVF_I8_R8)
3948 			if (sp [-1].data.f < MYGINT64_MIN || sp [-1].data.f > MYGINT64_MAX)
3949 				THROW_EX (mono_get_exception_overflow (), ip);
3950 			sp [-1].data.l = (gint64)sp [-1].data.f;
3951 			++ip;
3952 			MINT_IN_BREAK;
3953 		MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8)
3954 			if ((mono_u)sp [-1].data.l > MYGUINT32_MAX)
3955 				THROW_EX (mono_get_exception_overflow (), ip);
3956 			sp [-1].data.i = (mono_u)sp [-1].data.l;
3957 			++ip;
3958 			MINT_IN_BREAK;
3959 		MINT_IN_CASE(MINT_BOX) {
3960 			c = rtm->data_items [* (guint16 *)(ip + 1)];
3961 			guint16 offset = * (guint16 *)(ip + 2);
3962 			gboolean pop_vt_sp = !(offset & BOX_NOT_CLEAR_VT_SP);
3963 			offset &= ~BOX_NOT_CLEAR_VT_SP;
3964 
3965 			if (mint_type (&c->byval_arg) == MINT_TYPE_VT && !c->enumtype && !(mono_class_is_magic_int (c) || mono_class_is_magic_float (c))) {
3966 				int size = mono_class_value_size (c, NULL);
3967 				sp [-1 - offset].data.p = mono_value_box_checked (rtm->domain, c, sp [-1 - offset].data.p, &error);
3968 				mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3969 				size = (size + 7) & ~7;
3970 				if (pop_vt_sp)
3971 					vt_sp -= size;
3972 			} else {
3973 				stackval_to_data (&c->byval_arg, &sp [-1 - offset], (char *) &sp [-1 - offset], FALSE);
3974 				sp [-1 - offset].data.p = mono_value_box_checked (rtm->domain, c, &sp [-1 - offset], &error);
3975 				mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3976 			}
3977 			ip += 3;
3978 			MINT_IN_BREAK;
3979 		}
3980 		MINT_IN_CASE(MINT_NEWARR)
3981 			sp [-1].data.p = (MonoObject*) mono_array_new_checked (rtm->domain, rtm->data_items[*(guint16 *)(ip + 1)], sp [-1].data.i, &error);
3982 			if (!mono_error_ok (&error)) {
3983 				THROW_EX (mono_error_convert_to_exception (&error), ip);
3984 			}
3985 			mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3986 			ip += 2;
3987 			/*if (profiling_classes) {
3988 				guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
3989 				count++;
3990 				g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
3991 			}*/
3992 
3993 			MINT_IN_BREAK;
3994 		MINT_IN_CASE(MINT_LDLEN)
3995 			o = sp [-1].data.p;
3996 			if (!o)
3997 				THROW_EX (mono_get_exception_null_reference (), ip);
3998 			sp [-1].data.nati = mono_array_length ((MonoArray *)o);
3999 			++ip;
4000 			MINT_IN_BREAK;
4001 		MINT_IN_CASE(MINT_GETCHR) {
4002 			MonoString *s;
4003 			s = sp [-2].data.p;
4004 			if (!s)
4005 				THROW_EX (mono_get_exception_null_reference (), ip);
4006 			i32 = sp [-1].data.i;
4007 			if (i32 < 0 || i32 >= mono_string_length (s))
4008 				THROW_EX (mono_get_exception_index_out_of_range (), ip);
4009 			--sp;
4010 			sp [-1].data.i = mono_string_chars(s)[i32];
4011 			++ip;
4012 			MINT_IN_BREAK;
4013 		}
4014 		MINT_IN_CASE(MINT_STRLEN)
4015 			++ip;
4016 			o = sp [-1].data.p;
4017 			if (!o)
4018 				THROW_EX (mono_get_exception_null_reference (), ip);
4019 			sp [-1].data.i = mono_string_length ((MonoString*) o);
4020 			MINT_IN_BREAK;
4021 		MINT_IN_CASE(MINT_ARRAY_RANK)
4022 			o = sp [-1].data.p;
4023 			if (!o)
4024 				THROW_EX (mono_get_exception_null_reference (), ip);
4025 			sp [-1].data.i = mono_object_class (sp [-1].data.p)->rank;
4026 			ip++;
4027 			MINT_IN_BREAK;
4028 		MINT_IN_CASE(MINT_LDELEMA)
4029 		MINT_IN_CASE(MINT_LDELEMA_TC) {
4030 			gboolean needs_typecheck = *ip == MINT_LDELEMA_TC;
4031 
4032 			MonoClass *klass = rtm->data_items [*(guint16 *) (ip + 1)];
4033 			guint16 numargs = *(guint16 *) (ip + 2);
4034 			ip += 3;
4035 			sp -= numargs;
4036 
4037 			o = sp [0].data.p;
4038 			sp->data.p = ves_array_element_address (frame, klass, (MonoArray *) o, &sp [1], needs_typecheck);
4039 			if (frame->ex)
4040 				THROW_EX (frame->ex, ip);
4041 			++sp;
4042 
4043 			MINT_IN_BREAK;
4044 		}
4045 		MINT_IN_CASE(MINT_LDELEM_I1) /* fall through */
4046 		MINT_IN_CASE(MINT_LDELEM_U1) /* fall through */
4047 		MINT_IN_CASE(MINT_LDELEM_I2) /* fall through */
4048 		MINT_IN_CASE(MINT_LDELEM_U2) /* fall through */
4049 		MINT_IN_CASE(MINT_LDELEM_I4) /* fall through */
4050 		MINT_IN_CASE(MINT_LDELEM_U4) /* fall through */
4051 		MINT_IN_CASE(MINT_LDELEM_I8)  /* fall through */
4052 		MINT_IN_CASE(MINT_LDELEM_I)  /* fall through */
4053 		MINT_IN_CASE(MINT_LDELEM_R4) /* fall through */
4054 		MINT_IN_CASE(MINT_LDELEM_R8) /* fall through */
4055 		MINT_IN_CASE(MINT_LDELEM_REF) /* fall through */
4056 		MINT_IN_CASE(MINT_LDELEM_VT) {
4057 			MonoArray *o;
4058 			mono_u aindex;
4059 
4060 			sp -= 2;
4061 
4062 			o = sp [0].data.p;
4063 			if (!o)
4064 				THROW_EX (mono_get_exception_null_reference (), ip);
4065 
4066 			aindex = sp [1].data.i;
4067 			if (aindex >= mono_array_length (o))
4068 				THROW_EX (mono_get_exception_index_out_of_range (), ip);
4069 
4070 			/*
4071 			 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
4072 			 */
4073 			switch (*ip) {
4074 			case MINT_LDELEM_I1:
4075 				sp [0].data.i = mono_array_get (o, gint8, aindex);
4076 				break;
4077 			case MINT_LDELEM_U1:
4078 				sp [0].data.i = mono_array_get (o, guint8, aindex);
4079 				break;
4080 			case MINT_LDELEM_I2:
4081 				sp [0].data.i = mono_array_get (o, gint16, aindex);
4082 				break;
4083 			case MINT_LDELEM_U2:
4084 				sp [0].data.i = mono_array_get (o, guint16, aindex);
4085 				break;
4086 			case MINT_LDELEM_I:
4087 				sp [0].data.nati = mono_array_get (o, mono_i, aindex);
4088 				break;
4089 			case MINT_LDELEM_I4:
4090 				sp [0].data.i = mono_array_get (o, gint32, aindex);
4091 				break;
4092 			case MINT_LDELEM_U4:
4093 				sp [0].data.i = mono_array_get (o, guint32, aindex);
4094 				break;
4095 			case MINT_LDELEM_I8:
4096 				sp [0].data.l = mono_array_get (o, guint64, aindex);
4097 				break;
4098 			case MINT_LDELEM_R4:
4099 				sp [0].data.f = mono_array_get (o, float, aindex);
4100 				break;
4101 			case MINT_LDELEM_R8:
4102 				sp [0].data.f = mono_array_get (o, double, aindex);
4103 				break;
4104 			case MINT_LDELEM_REF:
4105 				sp [0].data.p = mono_array_get (o, gpointer, aindex);
4106 				break;
4107 			case MINT_LDELEM_VT: {
4108 				MonoClass *klass_vt = rtm->data_items [*(guint16 *) (ip + 1)];
4109 				i32 = READ32 (ip + 2);
4110 				char *src_addr = mono_array_addr_with_size ((MonoArray *) o, i32, aindex);
4111 				sp [0].data.vt = vt_sp;
4112 				stackval_from_data (&klass_vt->byval_arg, sp, src_addr, FALSE);
4113 				vt_sp += (i32 + 7) & ~7;
4114 				ip += 3;
4115 				break;
4116 			}
4117 			default:
4118 				ves_abort();
4119 			}
4120 
4121 			++ip;
4122 			++sp;
4123 			MINT_IN_BREAK;
4124 		}
4125 		MINT_IN_CASE(MINT_STELEM_I)  /* fall through */
4126 		MINT_IN_CASE(MINT_STELEM_I1) /* fall through */
4127 		MINT_IN_CASE(MINT_STELEM_U1) /* fall through */
4128 		MINT_IN_CASE(MINT_STELEM_I2) /* fall through */
4129 		MINT_IN_CASE(MINT_STELEM_U2) /* fall through */
4130 		MINT_IN_CASE(MINT_STELEM_I4) /* fall through */
4131 		MINT_IN_CASE(MINT_STELEM_I8) /* fall through */
4132 		MINT_IN_CASE(MINT_STELEM_R4) /* fall through */
4133 		MINT_IN_CASE(MINT_STELEM_R8) /* fall through */
4134 		MINT_IN_CASE(MINT_STELEM_REF) /* fall through */
4135 		MINT_IN_CASE(MINT_STELEM_VT) {
4136 			mono_u aindex;
4137 
4138 			sp -= 3;
4139 
4140 			o = sp [0].data.p;
4141 			if (!o)
4142 				THROW_EX (mono_get_exception_null_reference (), ip);
4143 
4144 			aindex = sp [1].data.i;
4145 			if (aindex >= mono_array_length ((MonoArray *)o))
4146 				THROW_EX (mono_get_exception_index_out_of_range (), ip);
4147 
4148 			switch (*ip) {
4149 			case MINT_STELEM_I:
4150 				mono_array_set ((MonoArray *)o, mono_i, aindex, sp [2].data.nati);
4151 				break;
4152 			case MINT_STELEM_I1:
4153 				mono_array_set ((MonoArray *)o, gint8, aindex, sp [2].data.i);
4154 				break;
4155 			case MINT_STELEM_U1:
4156 				mono_array_set ((MonoArray *) o, guint8, aindex, sp [2].data.i);
4157 				break;
4158 			case MINT_STELEM_I2:
4159 				mono_array_set ((MonoArray *)o, gint16, aindex, sp [2].data.i);
4160 				break;
4161 			case MINT_STELEM_U2:
4162 				mono_array_set ((MonoArray *)o, guint16, aindex, sp [2].data.i);
4163 				break;
4164 			case MINT_STELEM_I4:
4165 				mono_array_set ((MonoArray *)o, gint32, aindex, sp [2].data.i);
4166 				break;
4167 			case MINT_STELEM_I8:
4168 				mono_array_set ((MonoArray *)o, gint64, aindex, sp [2].data.l);
4169 				break;
4170 			case MINT_STELEM_R4:
4171 				mono_array_set ((MonoArray *)o, float, aindex, sp [2].data.f);
4172 				break;
4173 			case MINT_STELEM_R8:
4174 				mono_array_set ((MonoArray *)o, double, aindex, sp [2].data.f);
4175 				break;
4176 			case MINT_STELEM_REF: {
4177 				MonoObject *isinst_obj = mono_object_isinst_checked (sp [2].data.p, mono_object_class (o)->element_class, &error);
4178 				mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4179 				if (sp [2].data.p && !isinst_obj)
4180 					THROW_EX (mono_get_exception_array_type_mismatch (), ip);
4181 				mono_array_setref ((MonoArray *) o, aindex, sp [2].data.p);
4182 				break;
4183 			}
4184 			case MINT_STELEM_VT: {
4185 				MonoClass *klass_vt = rtm->data_items [*(guint16 *) (ip + 1)];
4186 				i32 = READ32 (ip + 2);
4187 				char *dst_addr = mono_array_addr_with_size ((MonoArray *) o, i32, aindex);
4188 
4189 				stackval_to_data (&klass_vt->byval_arg, &sp [2], dst_addr, FALSE);
4190 				vt_sp -= (i32 + 7) & ~7;
4191 				ip += 3;
4192 				break;
4193 			}
4194 			default:
4195 				ves_abort();
4196 			}
4197 
4198 			++ip;
4199 			MINT_IN_BREAK;
4200 		}
4201 		MINT_IN_CASE(MINT_CONV_OVF_I4_U4)
4202 			if (sp [-1].data.i < 0)
4203 				THROW_EX (mono_get_exception_overflow (), ip);
4204 			++ip;
4205 			MINT_IN_BREAK;
4206 		MINT_IN_CASE(MINT_CONV_OVF_I4_I8)
4207 			if (sp [-1].data.l < MYGINT32_MIN || sp [-1].data.l > MYGINT32_MAX)
4208 				THROW_EX (mono_get_exception_overflow (), ip);
4209 			sp [-1].data.i = (gint32) sp [-1].data.l;
4210 			++ip;
4211 			MINT_IN_BREAK;
4212 		MINT_IN_CASE(MINT_CONV_OVF_I4_U8)
4213 			if (sp [-1].data.l < 0 || sp [-1].data.l > MYGINT32_MAX)
4214 				THROW_EX (mono_get_exception_overflow (), ip);
4215 			sp [-1].data.i = (gint32) sp [-1].data.l;
4216 			++ip;
4217 			MINT_IN_BREAK;
4218 		MINT_IN_CASE(MINT_CONV_OVF_I4_R8)
4219 			if (sp [-1].data.f < MYGINT32_MIN || sp [-1].data.f > MYGINT32_MAX)
4220 				THROW_EX (mono_get_exception_overflow (), ip);
4221 			sp [-1].data.i = (gint32) sp [-1].data.f;
4222 			++ip;
4223 			MINT_IN_BREAK;
4224 		MINT_IN_CASE(MINT_CONV_OVF_U4_I4)
4225 			if (sp [-1].data.i < 0)
4226 				THROW_EX (mono_get_exception_overflow (), ip);
4227 			++ip;
4228 			MINT_IN_BREAK;
4229 		MINT_IN_CASE(MINT_CONV_OVF_U4_I8)
4230 			if (sp [-1].data.l < 0 || sp [-1].data.l > MYGUINT32_MAX)
4231 				THROW_EX (mono_get_exception_overflow (), ip);
4232 			sp [-1].data.i = (guint32) sp [-1].data.l;
4233 			++ip;
4234 			MINT_IN_BREAK;
4235 		MINT_IN_CASE(MINT_CONV_OVF_U4_R8)
4236 			if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT32_MAX)
4237 				THROW_EX (mono_get_exception_overflow (), ip);
4238 			sp [-1].data.i = (guint32) sp [-1].data.f;
4239 			++ip;
4240 			MINT_IN_BREAK;
4241 		MINT_IN_CASE(MINT_CONV_OVF_I2_I4)
4242 			if (sp [-1].data.i < -32768 || sp [-1].data.i > 32767)
4243 				THROW_EX (mono_get_exception_overflow (), ip);
4244 			++ip;
4245 			MINT_IN_BREAK;
4246 		MINT_IN_CASE(MINT_CONV_OVF_I2_I8)
4247 			if (sp [-1].data.l < -32768 || sp [-1].data.l > 32767)
4248 				THROW_EX (mono_get_exception_overflow (), ip);
4249 			sp [-1].data.i = (gint16) sp [-1].data.l;
4250 			++ip;
4251 			MINT_IN_BREAK;
4252 		MINT_IN_CASE(MINT_CONV_OVF_I2_R8)
4253 			if (sp [-1].data.f < -32768 || sp [-1].data.f > 32767)
4254 				THROW_EX (mono_get_exception_overflow (), ip);
4255 			sp [-1].data.i = (gint16) sp [-1].data.f;
4256 			++ip;
4257 			MINT_IN_BREAK;
4258 		MINT_IN_CASE(MINT_CONV_OVF_U2_I4)
4259 			if (sp [-1].data.i < 0 || sp [-1].data.i > 65535)
4260 				THROW_EX (mono_get_exception_overflow (), ip);
4261 			++ip;
4262 			MINT_IN_BREAK;
4263 		MINT_IN_CASE(MINT_CONV_OVF_U2_I8)
4264 			if (sp [-1].data.l < 0 || sp [-1].data.l > 65535)
4265 				THROW_EX (mono_get_exception_overflow (), ip);
4266 			sp [-1].data.i = (guint16) sp [-1].data.l;
4267 			++ip;
4268 			MINT_IN_BREAK;
4269 		MINT_IN_CASE(MINT_CONV_OVF_U2_R8)
4270 			if (sp [-1].data.f < 0 || sp [-1].data.f > 65535)
4271 				THROW_EX (mono_get_exception_overflow (), ip);
4272 			sp [-1].data.i = (guint16) sp [-1].data.f;
4273 			++ip;
4274 			MINT_IN_BREAK;
4275 		MINT_IN_CASE(MINT_CONV_OVF_I1_I4)
4276 			if (sp [-1].data.i < -128 || sp [-1].data.i > 127)
4277 				THROW_EX (mono_get_exception_overflow (), ip);
4278 			++ip;
4279 			MINT_IN_BREAK;
4280 		MINT_IN_CASE(MINT_CONV_OVF_I1_I8)
4281 			if (sp [-1].data.l < -128 || sp [-1].data.l > 127)
4282 				THROW_EX (mono_get_exception_overflow (), ip);
4283 			sp [-1].data.i = (gint8) sp [-1].data.l;
4284 			++ip;
4285 			MINT_IN_BREAK;
4286 		MINT_IN_CASE(MINT_CONV_OVF_I1_R8)
4287 			if (sp [-1].data.f < -128 || sp [-1].data.f > 127)
4288 				THROW_EX (mono_get_exception_overflow (), ip);
4289 			sp [-1].data.i = (gint8) sp [-1].data.f;
4290 			++ip;
4291 			MINT_IN_BREAK;
4292 		MINT_IN_CASE(MINT_CONV_OVF_U1_I4)
4293 			if (sp [-1].data.i < 0 || sp [-1].data.i > 255)
4294 				THROW_EX (mono_get_exception_overflow (), ip);
4295 			++ip;
4296 			MINT_IN_BREAK;
4297 		MINT_IN_CASE(MINT_CONV_OVF_U1_I8)
4298 			if (sp [-1].data.l < 0 || sp [-1].data.l > 255)
4299 				THROW_EX (mono_get_exception_overflow (), ip);
4300 			sp [-1].data.i = (guint8) sp [-1].data.l;
4301 			++ip;
4302 			MINT_IN_BREAK;
4303 		MINT_IN_CASE(MINT_CONV_OVF_U1_R8)
4304 			if (sp [-1].data.f < 0 || sp [-1].data.f > 255)
4305 				THROW_EX (mono_get_exception_overflow (), ip);
4306 			sp [-1].data.i = (guint8) sp [-1].data.f;
4307 			++ip;
4308 			MINT_IN_BREAK;
4309 #if 0
4310 		MINT_IN_CASE(MINT_LDELEM)
4311 		MINT_IN_CASE(MINT_STELEM)
4312 		MINT_IN_CASE(MINT_UNBOX_ANY)
4313 #endif
4314 		MINT_IN_CASE(MINT_CKFINITE)
4315 			if (!isfinite(sp [-1].data.f))
4316 				THROW_EX (mono_get_exception_arithmetic (), ip);
4317 			++ip;
4318 			MINT_IN_BREAK;
4319 		MINT_IN_CASE(MINT_MKREFANY) {
4320 			c = rtm->data_items [*(guint16 *)(ip + 1)];
4321 
4322 			/* The value address is on the stack */
4323 			gpointer addr = sp [-1].data.p;
4324 			/* Push the typedref value on the stack */
4325 			sp [-1].data.p = vt_sp;
4326 			vt_sp += sizeof (MonoTypedRef);
4327 
4328 			MonoTypedRef *tref = sp [-1].data.p;
4329 			tref->klass = c;
4330 			tref->type = &c->byval_arg;
4331 			tref->value = addr;
4332 
4333 			ip += 2;
4334 			MINT_IN_BREAK;
4335 		}
4336 		MINT_IN_CASE(MINT_REFANYTYPE) {
4337 			MonoTypedRef *tref = sp [-1].data.p;
4338 			MonoType *type = tref->type;
4339 
4340 			vt_sp -= sizeof (MonoTypedRef);
4341 			sp [-1].data.p = vt_sp;
4342 			vt_sp += 8;
4343 			*(gpointer*)sp [-1].data.p = type;
4344 			ip ++;
4345 			MINT_IN_BREAK;
4346 		}
4347 		MINT_IN_CASE(MINT_REFANYVAL) {
4348 			MonoTypedRef *tref = sp [-1].data.p;
4349 			gpointer addr = tref->value;
4350 
4351 			vt_sp -= sizeof (MonoTypedRef);
4352 
4353 			sp [-1].data.p = addr;
4354 			ip ++;
4355 			MINT_IN_BREAK;
4356 		}
4357 		MINT_IN_CASE(MINT_LDTOKEN)
4358 			sp->data.p = vt_sp;
4359 			vt_sp += 8;
4360 			* (gpointer *)sp->data.p = rtm->data_items[*(guint16 *)(ip + 1)];
4361 			ip += 2;
4362 			++sp;
4363 			MINT_IN_BREAK;
4364 		MINT_IN_CASE(MINT_ADD_OVF_I4)
4365 			if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
4366 				THROW_EX (mono_get_exception_overflow (), ip);
4367 			BINOP(i, +);
4368 			MINT_IN_BREAK;
4369 		MINT_IN_CASE(MINT_ADD_OVF_I8)
4370 			if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
4371 				THROW_EX (mono_get_exception_overflow (), ip);
4372 			BINOP(l, +);
4373 			MINT_IN_BREAK;
4374 		MINT_IN_CASE(MINT_ADD_OVF_UN_I4)
4375 			if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
4376 				THROW_EX (mono_get_exception_overflow (), ip);
4377 			BINOP_CAST(i, +, guint32);
4378 			MINT_IN_BREAK;
4379 		MINT_IN_CASE(MINT_ADD_OVF_UN_I8)
4380 			if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
4381 				THROW_EX (mono_get_exception_overflow (), ip);
4382 			BINOP_CAST(l, +, guint64);
4383 			MINT_IN_BREAK;
4384 		MINT_IN_CASE(MINT_MUL_OVF_I4)
4385 			if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
4386 				THROW_EX (mono_get_exception_overflow (), ip);
4387 			BINOP(i, *);
4388 			MINT_IN_BREAK;
4389 		MINT_IN_CASE(MINT_MUL_OVF_I8)
4390 			if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
4391 				THROW_EX (mono_get_exception_overflow (), ip);
4392 			BINOP(l, *);
4393 			MINT_IN_BREAK;
4394 		MINT_IN_CASE(MINT_MUL_OVF_UN_I4)
4395 			if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
4396 				THROW_EX (mono_get_exception_overflow (), ip);
4397 			BINOP_CAST(i, *, guint32);
4398 			MINT_IN_BREAK;
4399 		MINT_IN_CASE(MINT_MUL_OVF_UN_I8)
4400 			if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
4401 				THROW_EX (mono_get_exception_overflow (), ip);
4402 			BINOP_CAST(l, *, guint64);
4403 			MINT_IN_BREAK;
4404 		MINT_IN_CASE(MINT_SUB_OVF_I4)
4405 			if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
4406 				THROW_EX (mono_get_exception_overflow (), ip);
4407 			BINOP(i, -);
4408 			MINT_IN_BREAK;
4409 		MINT_IN_CASE(MINT_SUB_OVF_I8)
4410 			if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
4411 				THROW_EX (mono_get_exception_overflow (), ip);
4412 			BINOP(l, -);
4413 			MINT_IN_BREAK;
4414 		MINT_IN_CASE(MINT_SUB_OVF_UN_I4)
4415 			if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
4416 				THROW_EX (mono_get_exception_overflow (), ip);
4417 			BINOP_CAST(i, -, guint32);
4418 			MINT_IN_BREAK;
4419 		MINT_IN_CASE(MINT_SUB_OVF_UN_I8)
4420 			if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
4421 				THROW_EX (mono_get_exception_overflow (), ip);
4422 			BINOP_CAST(l, -, guint64);
4423 			MINT_IN_BREAK;
4424 		MINT_IN_CASE(MINT_ENDFINALLY)
4425 			ip ++;
4426 			int clause_index = *ip;
4427 			if (clause_index == exit_at_finally)
4428 				goto exit_frame;
4429 			while (sp > frame->stack) {
4430 				--sp;
4431 			}
4432 			if (finally_ips) {
4433 				ip = finally_ips->data;
4434 				finally_ips = g_slist_remove (finally_ips, ip);
4435 				goto main_loop;
4436 			}
4437 			if (frame->ex)
4438 				goto handle_catch;
4439 			ves_abort();
4440 			MINT_IN_BREAK;
4441 		MINT_IN_CASE(MINT_LEAVE) /* Fall through */
4442 		MINT_IN_CASE(MINT_LEAVE_S)
4443 			while (sp > frame->stack) {
4444 				--sp;
4445 			}
4446 			frame->ip = ip;
4447 
4448 			if (frame->ex_handler != NULL && MONO_OFFSET_IN_HANDLER(frame->ex_handler, frame->ip - rtm->code)) {
4449 				frame->ex_handler = NULL;
4450 				frame->ex = NULL;
4451 				if (frame->imethod->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
4452 					MonoException *abort_exc = mono_thread_get_undeniable_exception ();
4453 					if (abort_exc)
4454 						THROW_EX (abort_exc, frame->ip);
4455 				}
4456 
4457 			}
4458 
4459 			if (*ip == MINT_LEAVE_S) {
4460 				ip += (short) *(ip + 1);
4461 			} else {
4462 				ip += (gint32) READ32 (ip + 1);
4463 			}
4464 			endfinally_ip = ip;
4465 			goto handle_finally;
4466 			MINT_IN_BREAK;
4467 		MINT_IN_CASE(MINT_LEAVE_CHECK)
4468 		MINT_IN_CASE(MINT_LEAVE_S_CHECK)
4469 			while (sp > frame->stack) {
4470 				--sp;
4471 			}
4472 			frame->ip = ip;
4473 
4474 			if (frame->ex_handler != NULL && MONO_OFFSET_IN_HANDLER(frame->ex_handler, frame->ip - rtm->code)) {
4475 				frame->ex_handler = NULL;
4476 				frame->ex = NULL;
4477 			}
4478 
4479 			if (frame->imethod->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
4480 				MonoException *abort_exc = mono_thread_get_undeniable_exception ();
4481 				if (abort_exc)
4482 					THROW_EX (abort_exc, frame->ip);
4483 			}
4484 
4485 			if (*ip == MINT_LEAVE_S_CHECK) {
4486 				ip += (short) *(ip + 1);
4487 			} else {
4488 				ip += (gint32) READ32 (ip + 1);
4489 			}
4490 			endfinally_ip = ip;
4491 			goto handle_finally;
4492 			MINT_IN_BREAK;
4493 		MINT_IN_CASE(MINT_ICALL_V_V)
4494 		MINT_IN_CASE(MINT_ICALL_V_P)
4495 		MINT_IN_CASE(MINT_ICALL_P_V)
4496 		MINT_IN_CASE(MINT_ICALL_P_P)
4497 		MINT_IN_CASE(MINT_ICALL_PP_V)
4498 		MINT_IN_CASE(MINT_ICALL_PI_V)
4499 		MINT_IN_CASE(MINT_ICALL_PP_P)
4500 		MINT_IN_CASE(MINT_ICALL_PI_P)
4501 		MINT_IN_CASE(MINT_ICALL_PPP_V)
4502 		MINT_IN_CASE(MINT_ICALL_PPI_V)
4503 			sp = do_icall (context, *ip, sp, rtm->data_items [*(guint16 *)(ip + 1)]);
4504 			if (*mono_thread_interruption_request_flag ()) {
4505 				MonoException *exc = mono_thread_interruption_checkpoint ();
4506 				if (exc)
4507 					THROW_EX (exc, ip);
4508 			}
4509 			if (context->has_resume_state) {
4510 				if (frame == context->handler_frame)
4511 					SET_RESUME_STATE (context);
4512 				else
4513 					goto exit_frame;
4514 			}
4515 			ip += 2;
4516 			MINT_IN_BREAK;
4517 		MINT_IN_CASE(MINT_MONO_LDPTR)
4518 			sp->data.p = rtm->data_items [*(guint16 *)(ip + 1)];
4519 			ip += 2;
4520 			++sp;
4521 			MINT_IN_BREAK;
4522 		MINT_IN_CASE(MINT_MONO_NEWOBJ)
4523 			sp->data.p = mono_object_new_checked (rtm->domain, rtm->data_items [*(guint16 *)(ip + 1)], &error);
4524 			mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4525 			ip += 2;
4526 			sp++;
4527 			MINT_IN_BREAK;
4528 		MINT_IN_CASE(MINT_MONO_FREE)
4529 			++ip;
4530 			--sp;
4531 			g_error ("that doesn't seem right");
4532 			g_free (sp->data.p);
4533 			MINT_IN_BREAK;
4534 		MINT_IN_CASE(MINT_MONO_RETOBJ)
4535 			++ip;
4536 			sp--;
4537 			stackval_from_data (mono_method_signature (frame->imethod->method)->ret, frame->retval, sp->data.p,
4538 			     mono_method_signature (frame->imethod->method)->pinvoke);
4539 			if (sp > frame->stack)
4540 				g_warning ("retobj: more values on stack: %d", sp-frame->stack);
4541 			goto exit_frame;
4542 		MINT_IN_CASE(MINT_MONO_TLS) {
4543 			MonoTlsKey key = *(gint32 *)(ip + 1);
4544 			sp->data.p = ((gpointer (*)(void)) mono_tls_get_tls_getter (key, FALSE)) ();
4545 			sp++;
4546 			ip += 3;
4547 			MINT_IN_BREAK;
4548 		}
4549 		MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER) {
4550 			++ip;
4551 			mono_memory_barrier ();
4552 			MINT_IN_BREAK;
4553 		}
4554 		MINT_IN_CASE(MINT_MONO_JIT_ATTACH) {
4555 			++ip;
4556 
4557 			context->original_domain = NULL;
4558 			MonoDomain *tls_domain = (MonoDomain *) ((gpointer (*)(void)) mono_tls_get_tls_getter (TLS_KEY_DOMAIN, FALSE)) ();
4559 			gpointer tls_jit = ((gpointer (*)(void)) mono_tls_get_tls_getter (TLS_KEY_JIT_TLS, FALSE)) ();
4560 
4561 			if (tls_domain != rtm->domain || !tls_jit)
4562 				context->original_domain = mono_jit_thread_attach (rtm->domain);
4563 			MINT_IN_BREAK;
4564 		}
4565 		MINT_IN_CASE(MINT_MONO_JIT_DETACH)
4566 			++ip;
4567 			mono_jit_set_domain (context->original_domain);
4568 			MINT_IN_BREAK;
4569 		MINT_IN_CASE(MINT_MONO_LDDOMAIN)
4570 			sp->data.p = mono_domain_get ();
4571 			++sp;
4572 			++ip;
4573 			MINT_IN_BREAK;
4574 		MINT_IN_CASE(MINT_SDB_INTR_LOC)
4575 			if (G_UNLIKELY (ss_enabled)) {
4576 				static void (*ss_tramp) (void);
4577 
4578 				if (!ss_tramp) {
4579 					void *tramp = mini_get_single_step_trampoline ();
4580 					mono_memory_barrier ();
4581 					ss_tramp = tramp;
4582 				}
4583 
4584 				/*
4585 				 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
4586 				 * the address of that instruction is stored as the seq point address.
4587 				 */
4588 				frame->ip = ip + 1;
4589 
4590 				/*
4591 				 * Use the same trampoline as the JIT. This ensures that
4592 				 * the debugger has the context for the last interpreter
4593 				 * native frame.
4594 				 */
4595 				do_debugger_tramp (ss_tramp, frame);
4596 
4597 				if (context->has_resume_state) {
4598 					if (frame == context->handler_frame)
4599 						SET_RESUME_STATE (context);
4600 					else
4601 						goto exit_frame;
4602 				}
4603 			}
4604 			++ip;
4605 			MINT_IN_BREAK;
4606 		MINT_IN_CASE(MINT_SDB_SEQ_POINT)
4607 			/* Just a placeholder for a breakpoint */
4608 			++ip;
4609 			MINT_IN_BREAK;
4610 		MINT_IN_CASE(MINT_SDB_BREAKPOINT) {
4611 			static void (*bp_tramp) (void);
4612 			if (!bp_tramp) {
4613 				void *tramp = mini_get_breakpoint_trampoline ();
4614 				mono_memory_barrier ();
4615 				bp_tramp = tramp;
4616 			}
4617 
4618 			frame->ip = ip;
4619 
4620 			/* Use the same trampoline as the JIT */
4621 			do_debugger_tramp (bp_tramp, frame);
4622 
4623 			if (context->has_resume_state) {
4624 				if (frame == context->handler_frame)
4625 					SET_RESUME_STATE (context);
4626 				else
4627 					goto exit_frame;
4628 			}
4629 
4630 			++ip;
4631 			MINT_IN_BREAK;
4632 		}
4633 
4634 #define RELOP(datamem, op) \
4635 	--sp; \
4636 	sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
4637 	++ip;
4638 
4639 #define RELOP_FP(datamem, op, noorder) \
4640 	--sp; \
4641 	if (isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
4642 		sp [-1].data.i = noorder; \
4643 	else \
4644 		sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
4645 	++ip;
4646 
4647 		MINT_IN_CASE(MINT_CEQ_I4)
4648 			RELOP(i, ==);
4649 			MINT_IN_BREAK;
4650 		MINT_IN_CASE(MINT_CEQ0_I4)
4651 			sp [-1].data.i = (sp [-1].data.i == 0);
4652 			++ip;
4653 			MINT_IN_BREAK;
4654 		MINT_IN_CASE(MINT_CEQ_I8)
4655 			RELOP(l, ==);
4656 			MINT_IN_BREAK;
4657 		MINT_IN_CASE(MINT_CEQ_R8)
4658 			RELOP_FP(f, ==, 0);
4659 			MINT_IN_BREAK;
4660 		MINT_IN_CASE(MINT_CNE_I4)
4661 			RELOP(i, !=);
4662 			MINT_IN_BREAK;
4663 		MINT_IN_CASE(MINT_CNE_I8)
4664 			RELOP(l, !=);
4665 			MINT_IN_BREAK;
4666 		MINT_IN_CASE(MINT_CNE_R8)
4667 			RELOP_FP(f, !=, 0);
4668 			MINT_IN_BREAK;
4669 		MINT_IN_CASE(MINT_CGT_I4)
4670 			RELOP(i, >);
4671 			MINT_IN_BREAK;
4672 		MINT_IN_CASE(MINT_CGT_I8)
4673 			RELOP(l, >);
4674 			MINT_IN_BREAK;
4675 		MINT_IN_CASE(MINT_CGT_R8)
4676 			RELOP_FP(f, >, 0);
4677 			MINT_IN_BREAK;
4678 		MINT_IN_CASE(MINT_CGE_I4)
4679 			RELOP(i, >=);
4680 			MINT_IN_BREAK;
4681 		MINT_IN_CASE(MINT_CGE_I8)
4682 			RELOP(l, >=);
4683 			MINT_IN_BREAK;
4684 		MINT_IN_CASE(MINT_CGE_R8)
4685 			RELOP_FP(f, >=, 0);
4686 			MINT_IN_BREAK;
4687 
4688 #define RELOP_CAST(datamem, op, type) \
4689 	--sp; \
4690 	sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4691 	++ip;
4692 
4693 		MINT_IN_CASE(MINT_CGE_UN_I4)
4694 			RELOP_CAST(l, >=, guint32);
4695 			MINT_IN_BREAK;
4696 		MINT_IN_CASE(MINT_CGE_UN_I8)
4697 			RELOP_CAST(l, >=, guint64);
4698 			MINT_IN_BREAK;
4699 
4700 		MINT_IN_CASE(MINT_CGT_UN_I4)
4701 			RELOP_CAST(i, >, guint32);
4702 			MINT_IN_BREAK;
4703 		MINT_IN_CASE(MINT_CGT_UN_I8)
4704 			RELOP_CAST(l, >, guint64);
4705 			MINT_IN_BREAK;
4706 		MINT_IN_CASE(MINT_CGT_UN_R8)
4707 			RELOP_FP(f, >, 1);
4708 			MINT_IN_BREAK;
4709 		MINT_IN_CASE(MINT_CLT_I4)
4710 			RELOP(i, <);
4711 			MINT_IN_BREAK;
4712 		MINT_IN_CASE(MINT_CLT_I8)
4713 			RELOP(l, <);
4714 			MINT_IN_BREAK;
4715 		MINT_IN_CASE(MINT_CLT_R8)
4716 			RELOP_FP(f, <, 0);
4717 			MINT_IN_BREAK;
4718 		MINT_IN_CASE(MINT_CLT_UN_I4)
4719 			RELOP_CAST(i, <, guint32);
4720 			MINT_IN_BREAK;
4721 		MINT_IN_CASE(MINT_CLT_UN_I8)
4722 			RELOP_CAST(l, <, guint64);
4723 			MINT_IN_BREAK;
4724 		MINT_IN_CASE(MINT_CLT_UN_R8)
4725 			RELOP_FP(f, <, 1);
4726 			MINT_IN_BREAK;
4727 		MINT_IN_CASE(MINT_CLE_I4)
4728 			RELOP(i, <=);
4729 			MINT_IN_BREAK;
4730 		MINT_IN_CASE(MINT_CLE_I8)
4731 			RELOP(l, <=);
4732 			MINT_IN_BREAK;
4733 		MINT_IN_CASE(MINT_CLE_UN_I4)
4734 			RELOP_CAST(l, <=, guint32);
4735 			MINT_IN_BREAK;
4736 		MINT_IN_CASE(MINT_CLE_UN_I8)
4737 			RELOP_CAST(l, <=, guint64);
4738 			MINT_IN_BREAK;
4739 		MINT_IN_CASE(MINT_CLE_R8)
4740 			RELOP_FP(f, <=, 0);
4741 			MINT_IN_BREAK;
4742 
4743 #undef RELOP
4744 #undef RELOP_FP
4745 #undef RELOP_CAST
4746 
4747 		MINT_IN_CASE(MINT_LDFTN) {
4748 			sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)];
4749 			++sp;
4750 			ip += 2;
4751 			MINT_IN_BREAK;
4752 		}
4753 		MINT_IN_CASE(MINT_LDVIRTFTN) {
4754 			InterpMethod *m = rtm->data_items [* (guint16 *)(ip + 1)];
4755 			ip += 2;
4756 			--sp;
4757 			if (!sp->data.p)
4758 				THROW_EX (mono_get_exception_null_reference (), ip - 2);
4759 
4760 			sp->data.p = get_virtual_method (m, sp->data.p);
4761 			++sp;
4762 			MINT_IN_BREAK;
4763 		}
4764 
4765 #define LDARG(datamem, argtype) \
4766 	sp->data.datamem = * (argtype *)(frame->args + * (guint16 *)(ip + 1)); \
4767 	ip += 2; \
4768 	++sp;
4769 
4770 		MINT_IN_CASE(MINT_LDARG_I1) LDARG(i, gint8); MINT_IN_BREAK;
4771 		MINT_IN_CASE(MINT_LDARG_U1) LDARG(i, guint8); MINT_IN_BREAK;
4772 		MINT_IN_CASE(MINT_LDARG_I2) LDARG(i, gint16); MINT_IN_BREAK;
4773 		MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK;
4774 		MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK;
4775 		MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK;
4776 		MINT_IN_CASE(MINT_LDARG_R4) LDARG(f, float); MINT_IN_BREAK;
4777 		MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK;
4778 		MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK;
4779 		MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK;
4780 
4781 		MINT_IN_CASE(MINT_LDARG_VT)
4782 			sp->data.p = vt_sp;
4783 			i32 = READ32(ip + 2);
4784 			memcpy(sp->data.p, frame->args + * (guint16 *)(ip + 1), i32);
4785 			vt_sp += (i32 + 7) & ~7;
4786 			ip += 4;
4787 			++sp;
4788 			MINT_IN_BREAK;
4789 
4790 #define STARG(datamem, argtype) \
4791 	--sp; \
4792 	* (argtype *)(frame->args + * (guint16 *)(ip + 1)) = sp->data.datamem; \
4793 	ip += 2; \
4794 
4795 		MINT_IN_CASE(MINT_STARG_I1) STARG(i, gint8); MINT_IN_BREAK;
4796 		MINT_IN_CASE(MINT_STARG_U1) STARG(i, guint8); MINT_IN_BREAK;
4797 		MINT_IN_CASE(MINT_STARG_I2) STARG(i, gint16); MINT_IN_BREAK;
4798 		MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK;
4799 		MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK;
4800 		MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK;
4801 		MINT_IN_CASE(MINT_STARG_R4) STARG(f, float); MINT_IN_BREAK;
4802 		MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK;
4803 		MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK;
4804 		MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK;
4805 
4806 		MINT_IN_CASE(MINT_STARG_VT)
4807 			i32 = READ32(ip + 2);
4808 			--sp;
4809 			memcpy(frame->args + * (guint16 *)(ip + 1), sp->data.p, i32);
4810 			vt_sp -= (i32 + 7) & ~7;
4811 			ip += 4;
4812 			MINT_IN_BREAK;
4813 
4814 #define STINARG(datamem, argtype) \
4815 	do { \
4816 		int n = * (guint16 *)(ip + 1); \
4817 		* (argtype *)(frame->args + rtm->arg_offsets [n]) = frame->stack_args [n].data.datamem; \
4818 		ip += 2; \
4819 	} while (0)
4820 
4821 		MINT_IN_CASE(MINT_STINARG_I1) STINARG(i, gint8); MINT_IN_BREAK;
4822 		MINT_IN_CASE(MINT_STINARG_U1) STINARG(i, guint8); MINT_IN_BREAK;
4823 		MINT_IN_CASE(MINT_STINARG_I2) STINARG(i, gint16); MINT_IN_BREAK;
4824 		MINT_IN_CASE(MINT_STINARG_U2) STINARG(i, guint16); MINT_IN_BREAK;
4825 		MINT_IN_CASE(MINT_STINARG_I4) STINARG(i, gint32); MINT_IN_BREAK;
4826 		MINT_IN_CASE(MINT_STINARG_I8) STINARG(l, gint64); MINT_IN_BREAK;
4827 		MINT_IN_CASE(MINT_STINARG_R4) STINARG(f, float); MINT_IN_BREAK;
4828 		MINT_IN_CASE(MINT_STINARG_R8) STINARG(f, double); MINT_IN_BREAK;
4829 		MINT_IN_CASE(MINT_STINARG_O) STINARG(p, gpointer); MINT_IN_BREAK;
4830 		MINT_IN_CASE(MINT_STINARG_P) STINARG(p, gpointer); MINT_IN_BREAK;
4831 
4832 		MINT_IN_CASE(MINT_STINARG_VT) {
4833 			int n = * (guint16 *)(ip + 1);
4834 			i32 = READ32(ip + 2);
4835 			memcpy (frame->args + rtm->arg_offsets [n], frame->stack_args [n].data.p, i32);
4836 			ip += 4;
4837 			MINT_IN_BREAK;
4838 		}
4839 
4840 		MINT_IN_CASE(MINT_PROF_ENTER) {
4841 			ip += 1;
4842 
4843 			if (MONO_PROFILER_ENABLED (method_enter)) {
4844 				MonoProfilerCallContext *prof_ctx = NULL;
4845 
4846 				if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT) {
4847 					prof_ctx = g_new0 (MonoProfilerCallContext, 1);
4848 					prof_ctx->interp_frame = frame;
4849 					prof_ctx->method = frame->imethod->method;
4850 				}
4851 
4852 				MONO_PROFILER_RAISE (method_enter, (frame->imethod->method, prof_ctx));
4853 
4854 				g_free (prof_ctx);
4855 			}
4856 
4857 			MINT_IN_BREAK;
4858 		}
4859 
4860 		MINT_IN_CASE(MINT_LDARGA)
4861 			sp->data.p = frame->args + * (guint16 *)(ip + 1);
4862 			ip += 2;
4863 			++sp;
4864 			MINT_IN_BREAK;
4865 
4866 #define LDLOC(datamem, argtype) \
4867 	sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
4868 	ip += 2; \
4869 	++sp;
4870 
4871 		MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK;
4872 		MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK;
4873 		MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK;
4874 		MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK;
4875 		MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK;
4876 		MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK;
4877 		MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f, float); MINT_IN_BREAK;
4878 		MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK;
4879 		MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK;
4880 		MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK;
4881 
4882 		MINT_IN_CASE(MINT_LDLOC_VT)
4883 			sp->data.p = vt_sp;
4884 			i32 = READ32(ip + 2);
4885 			memcpy(sp->data.p, locals + * (guint16 *)(ip + 1), i32);
4886 			vt_sp += (i32 + 7) & ~7;
4887 			ip += 4;
4888 			++sp;
4889 			MINT_IN_BREAK;
4890 
4891 		MINT_IN_CASE(MINT_LDLOCA_S)
4892 			sp->data.p = locals + * (guint16 *)(ip + 1);
4893 			ip += 2;
4894 			++sp;
4895 			MINT_IN_BREAK;
4896 
4897 #define STLOC(datamem, argtype) \
4898 	--sp; \
4899 	* (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
4900 	ip += 2;
4901 
4902 		MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK;
4903 		MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK;
4904 		MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK;
4905 		MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK;
4906 		MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK;
4907 		MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK;
4908 		MINT_IN_CASE(MINT_STLOC_R4) STLOC(f, float); MINT_IN_BREAK;
4909 		MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK;
4910 		MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK;
4911 		MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK;
4912 
4913 #define STLOC_NP(datamem, argtype) \
4914 	* (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
4915 	ip += 2;
4916 
4917 		MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK;
4918 		MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK;
4919 
4920 		MINT_IN_CASE(MINT_STLOC_VT)
4921 			i32 = READ32(ip + 2);
4922 			--sp;
4923 			memcpy(locals + * (guint16 *)(ip + 1), sp->data.p, i32);
4924 			vt_sp -= (i32 + 7) & ~7;
4925 			ip += 4;
4926 			MINT_IN_BREAK;
4927 
4928 		MINT_IN_CASE(MINT_LOCALLOC) {
4929 			if (sp != frame->stack + 1) /*FIX?*/
4930 				THROW_EX (mono_get_exception_execution_engine (NULL), ip);
4931 
4932 			int len = sp [-1].data.i;
4933 			sp [-1].data.p = alloca (len);
4934 
4935 			if (frame->imethod->init_locals)
4936 				memset (sp [-1].data.p, 0, len);
4937 			++ip;
4938 			MINT_IN_BREAK;
4939 		}
4940 		MINT_IN_CASE(MINT_ENDFILTER)
4941 			/* top of stack is result of filter */
4942 			frame->retval = &sp [-1];
4943 			goto exit_frame;
4944 		MINT_IN_CASE(MINT_INITOBJ)
4945 			--sp;
4946 			memset (sp->data.vt, 0, READ32(ip + 1));
4947 			ip += 3;
4948 			MINT_IN_BREAK;
4949 		MINT_IN_CASE(MINT_CPBLK)
4950 			sp -= 3;
4951 			if (!sp [0].data.p || !sp [1].data.p)
4952 				THROW_EX (mono_get_exception_null_reference(), ip - 1);
4953 			++ip;
4954 			/* FIXME: value and size may be int64... */
4955 			memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
4956 			MINT_IN_BREAK;
4957 #if 0
4958 		MINT_IN_CASE(MINT_CONSTRAINED_) {
4959 			guint32 token;
4960 			/* FIXME: implement */
4961 			++ip;
4962 			token = READ32 (ip);
4963 			ip += 2;
4964 			MINT_IN_BREAK;
4965 		}
4966 #endif
4967 		MINT_IN_CASE(MINT_INITBLK)
4968 			sp -= 3;
4969 			if (!sp [0].data.p)
4970 				THROW_EX (mono_get_exception_null_reference(), ip - 1);
4971 			++ip;
4972 			/* FIXME: value and size may be int64... */
4973 			memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
4974 			MINT_IN_BREAK;
4975 #if 0
4976 		MINT_IN_CASE(MINT_NO_)
4977 			/* FIXME: implement */
4978 			ip += 2;
4979 			MINT_IN_BREAK;
4980 #endif
4981 	   MINT_IN_CASE(MINT_RETHROW) {
4982 			/*
4983 			 * need to clarify what this should actually do:
4984 			 * start the search from the last found handler in
4985 			 * this method or continue in the caller or what.
4986 			 * Also, do we need to run finally/fault handlers after a retrow?
4987 			 * Well, this implementation will follow the usual search
4988 			 * for an handler, considering the current ip as throw spot.
4989 			 * We need to NULL frame->ex_handler for the later code to
4990 			 * actually run the new found handler.
4991 			 */
4992 			int exvar_offset = *(guint16*)(ip + 1);
4993 			frame->ex_handler = NULL;
4994 			THROW_EX_GENERAL (*(MonoException**)(frame->locals + exvar_offset), ip - 1, TRUE);
4995 			MINT_IN_BREAK;
4996 	   }
4997 		MINT_IN_DEFAULT
4998 			g_print ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname[*ip], ip-rtm->code);
4999 			THROW_EX (mono_get_exception_execution_engine ("Unimplemented opcode"), ip);
5000 		}
5001 	}
5002 
5003 	g_assert_not_reached ();
5004 	handle_finally:
5005 	{
5006 		int i;
5007 		guint32 ip_offset;
5008 		MonoExceptionClause *clause;
5009 		GSList *old_list = finally_ips;
5010 		MonoMethod *method = frame->imethod->method;
5011 
5012 #if DEBUG_INTERP
5013 		if (tracing)
5014 			g_print ("* Handle finally IL_%04x\n", endfinally_ip == NULL ? 0 : endfinally_ip - rtm->code);
5015 #endif
5016 		if (rtm == NULL || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
5017 				|| (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
5018 			goto exit_frame;
5019 		}
5020 		ip_offset = frame->ip - rtm->code;
5021 
5022 		if (endfinally_ip != NULL)
5023 			finally_ips = g_slist_prepend(finally_ips, (void *)endfinally_ip);
5024 		for (i = 0; i < rtm->num_clauses; ++i)
5025 			if (frame->ex_handler == &rtm->clauses [i])
5026 				break;
5027 
5028 		while (i > 0) {
5029 			--i;
5030 			clause = &rtm->clauses [i];
5031 			if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && (endfinally_ip == NULL || !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - rtm->code)))) {
5032 				if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
5033 					ip = rtm->code + clause->handler_offset;
5034 					finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
5035 #if DEBUG_INTERP
5036 					if (tracing)
5037 						g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
5038 #endif
5039 				}
5040 			}
5041 		}
5042 
5043 		endfinally_ip = NULL;
5044 
5045 		if (old_list != finally_ips && finally_ips) {
5046 			ip = finally_ips->data;
5047 			finally_ips = g_slist_remove (finally_ips, ip);
5048 			sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
5049 			vt_sp = (unsigned char *) sp + rtm->stack_size;
5050 			goto main_loop;
5051 		}
5052 
5053 		/*
5054 		 * If an exception is set, we need to execute the fault handler, too,
5055 		 * otherwise, we continue normally.
5056 		 */
5057 		if (frame->ex)
5058 			goto handle_fault;
5059 		ves_abort();
5060 	}
5061 	handle_fault:
5062 	{
5063 		int i;
5064 		guint32 ip_offset;
5065 		MonoExceptionClause *clause;
5066 		GSList *old_list = finally_ips;
5067 
5068 #if DEBUG_INTERP
5069 		if (tracing)
5070 			g_print ("* Handle fault\n");
5071 #endif
5072 		ip_offset = frame->ip - rtm->code;
5073 
5074 		for (i = 0; i < rtm->num_clauses; ++i) {
5075 			clause = &rtm->clauses [i];
5076 			if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
5077 				ip = rtm->code + clause->handler_offset;
5078 				finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
5079 #if DEBUG_INTERP
5080 				if (tracing)
5081 					g_print ("* Executing handler at IL_%04x\n", clause->handler_offset);
5082 #endif
5083 			}
5084 		}
5085 
5086 		if (old_list != finally_ips && finally_ips) {
5087 			ip = finally_ips->data;
5088 			finally_ips = g_slist_remove (finally_ips, ip);
5089 			sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
5090 			vt_sp = (unsigned char *) sp + rtm->stack_size;
5091 			goto main_loop;
5092 		}
5093 	}
5094 	handle_catch:
5095 	{
5096 		/*
5097 		 * If the handler for the exception was found in this method, we jump
5098 		 * to it right away, otherwise we return and let the caller run
5099 		 * the finally, fault and catch blocks.
5100 		 * This same code should be present in the endfault opcode, but it
5101 		 * is corrently not assigned in the ECMA specs: LAMESPEC.
5102 		 */
5103 		if (frame->ex_handler) {
5104 #if DEBUG_INTERP
5105 			if (tracing)
5106 				g_print ("* Executing handler at IL_%04x\n", frame->ex_handler->handler_offset);
5107 #endif
5108 			ip = rtm->code + frame->ex_handler->handler_offset;
5109 			sp = frame->stack;
5110 			vt_sp = (unsigned char *) sp + rtm->stack_size;
5111 			sp->data.p = frame->ex;
5112 			++sp;
5113 			goto main_loop;
5114 		}
5115 		goto check_lmf;
5116 	}
5117 
5118 check_lmf:
5119 	{
5120 		/* make sure we don't miss to pop a LMF */
5121 		MonoLMF *lmf= mono_get_lmf ();
5122 		if (lmf && (gsize) lmf->previous_lmf & 2) {
5123 			MonoLMFExt *ext = (MonoLMFExt *) lmf;
5124 			if (ext->interp_exit && ext->interp_exit_data == frame->parent)
5125 				interp_pop_lmf (ext);
5126 		}
5127 	}
5128 
5129 exit_frame:
5130 
5131 	if (base_frame)
5132 		memcpy (base_frame->args, frame->args, rtm->alloca_size);
5133 
5134 	if (!frame->ex && MONO_PROFILER_ENABLED (method_leave) &&
5135 	    frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE) {
5136 		MonoProfilerCallContext *prof_ctx = NULL;
5137 
5138 		if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT) {
5139 			prof_ctx = g_new0 (MonoProfilerCallContext, 1);
5140 			prof_ctx->interp_frame = frame;
5141 			prof_ctx->method = frame->imethod->method;
5142 
5143 			MonoType *rtype = mono_method_signature (frame->imethod->method)->ret;
5144 
5145 			switch (rtype->type) {
5146 			case MONO_TYPE_VOID:
5147 				break;
5148 			case MONO_TYPE_VALUETYPE:
5149 				prof_ctx->return_value = frame->retval->data.p;
5150 				break;
5151 			default:
5152 				prof_ctx->return_value = frame->retval;
5153 				break;
5154 			}
5155 		}
5156 
5157 		MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, prof_ctx));
5158 
5159 		g_free (prof_ctx);
5160 	} else if (frame->ex && frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE)
5161 		MONO_PROFILER_RAISE (method_exception_leave, (frame->imethod->method, &frame->ex->object));
5162 
5163 	DEBUG_LEAVE ();
5164 }
5165 
5166 static void
interp_exec_method(InterpFrame * frame,ThreadContext * context)5167 interp_exec_method (InterpFrame *frame, ThreadContext *context)
5168 {
5169 	interp_exec_method_full (frame, context, NULL, NULL, -1, NULL);
5170 }
5171 
5172 void
mono_interp_parse_options(const char * options)5173 mono_interp_parse_options (const char *options)
5174 {
5175 	char **args, **ptr;
5176 
5177 	args = g_strsplit (options, ",", -1);
5178 	for (ptr = args; ptr && *ptr; ptr ++) {
5179 		char *arg = *ptr;
5180 
5181 		if (strncmp (arg, "jit=", 4) == 0)
5182 			jit_classes = g_slist_prepend (jit_classes, arg + 4);
5183 	}
5184 }
5185 
5186 typedef int (*TestMethod) (void);
5187 
5188 /*
5189  * interp_set_resume_state:
5190  *
5191  *   Set the state the interpeter will continue to execute from after execution returns to the interpreter.
5192  */
5193 static void
interp_set_resume_state(MonoJitTlsData * jit_tls,MonoException * ex,MonoJitExceptionInfo * ei,MonoInterpFrameHandle interp_frame,gpointer handler_ip)5194 interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip)
5195 {
5196 	ThreadContext *context;
5197 
5198 	g_assert (jit_tls);
5199 	context = jit_tls->interp_context;
5200 	g_assert (context);
5201 
5202 	context->has_resume_state = TRUE;
5203 	context->handler_frame = interp_frame;
5204 	/* This is on the stack, so it doesn't need a wbarrier */
5205 	context->handler_frame->ex = ex;
5206 	/* Ditto */
5207 	if (ei)
5208 		*(MonoException**)(context->handler_frame->locals + ei->exvar_offset) = ex;
5209 	context->handler_ip = handler_ip;
5210 }
5211 
5212 /*
5213  * interp_run_finally:
5214  *
5215  *   Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
5216  * frame->interp_frame.
5217  * Return TRUE if the finally clause threw an exception.
5218  */
5219 static gboolean
interp_run_finally(StackFrameInfo * frame,int clause_index,gpointer handler_ip)5220 interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip)
5221 {
5222 	InterpFrame *iframe = frame->interp_frame;
5223 	ThreadContext *context = mono_native_tls_get_value (thread_context_id);
5224 
5225 	interp_exec_method_full (iframe, context, handler_ip, NULL, clause_index, NULL);
5226 	if (context->has_resume_state)
5227 		return TRUE;
5228 	else
5229 		return FALSE;
5230 }
5231 
5232 /*
5233  * interp_run_filter:
5234  *
5235  *   Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
5236  * frame->interp_frame.
5237  */
5238 static gboolean
interp_run_filter(StackFrameInfo * frame,MonoException * ex,int clause_index,gpointer handler_ip)5239 interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip)
5240 {
5241 	InterpFrame *iframe = frame->interp_frame;
5242 	ThreadContext *context = mono_native_tls_get_value (thread_context_id);
5243 	InterpFrame child_frame;
5244 	stackval retval;
5245 
5246 	/*
5247 	 * Have to run the clause in a new frame which is a copy of IFRAME, since
5248 	 * during debugging, there are two copies of the frame on the stack.
5249 	 */
5250 	memset (&child_frame, 0, sizeof (InterpFrame));
5251 	child_frame.imethod = iframe->imethod;
5252 	child_frame.retval = &retval;
5253 	child_frame.parent = iframe;
5254 
5255 	interp_exec_method_full (&child_frame, context, handler_ip, ex, clause_index, iframe);
5256 	/* ENDFILTER stores the result into child_frame->retval */
5257 	return child_frame.retval->data.i ? TRUE : FALSE;
5258 }
5259 
5260 typedef struct {
5261 	InterpFrame *current;
5262 } StackIter;
5263 
5264 /*
5265  * interp_frame_iter_init:
5266  *
5267  *   Initialize an iterator for iterating through interpreted frames.
5268  */
5269 static void
interp_frame_iter_init(MonoInterpStackIter * iter,gpointer interp_exit_data)5270 interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data)
5271 {
5272 	StackIter *stack_iter = (StackIter*)iter;
5273 
5274 	stack_iter->current = (InterpFrame*)interp_exit_data;
5275 }
5276 
5277 /*
5278  * interp_frame_iter_next:
5279  *
5280  *   Fill out FRAME with date for the next interpreter frame.
5281  */
5282 static gboolean
interp_frame_iter_next(MonoInterpStackIter * iter,StackFrameInfo * frame)5283 interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
5284 {
5285 	StackIter *stack_iter = (StackIter*)iter;
5286 	InterpFrame *iframe = stack_iter->current;
5287 
5288 	memset (frame, 0, sizeof (StackFrameInfo));
5289 	/* pinvoke frames doesn't have imethod set */
5290 	while (iframe && !(iframe->imethod && iframe->imethod->code && iframe->imethod->jinfo))
5291 		iframe = iframe->parent;
5292 	if (!iframe)
5293 		return FALSE;
5294 
5295 	frame->type = FRAME_TYPE_INTERP;
5296 	frame->domain = iframe->domain;
5297 	frame->interp_frame = iframe;
5298 	frame->method = iframe->imethod->method;
5299 	frame->actual_method = frame->method;
5300 	/* This is the offset in the interpreter IR */
5301 	frame->native_offset = (guint8*)iframe->ip - (guint8*)iframe->imethod->code;
5302 	frame->ji = iframe->imethod->jinfo;
5303 
5304 	stack_iter->current = iframe->parent;
5305 
5306 	return TRUE;
5307 }
5308 
5309 static MonoJitInfo*
interp_find_jit_info(MonoDomain * domain,MonoMethod * method)5310 interp_find_jit_info (MonoDomain *domain, MonoMethod *method)
5311 {
5312 	InterpMethod* rtm;
5313 
5314 	rtm = lookup_imethod (domain, method);
5315 	if (rtm)
5316 		return rtm->jinfo;
5317 	else
5318 		return NULL;
5319 }
5320 
5321 static void
interp_set_breakpoint(MonoJitInfo * jinfo,gpointer ip)5322 interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip)
5323 {
5324 	guint16 *code = (guint16*)ip;
5325 	g_assert (*code == MINT_SDB_SEQ_POINT);
5326 	*code = MINT_SDB_BREAKPOINT;
5327 }
5328 
5329 static void
interp_clear_breakpoint(MonoJitInfo * jinfo,gpointer ip)5330 interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip)
5331 {
5332 	guint16 *code = (guint16*)ip;
5333 	g_assert (*code == MINT_SDB_BREAKPOINT);
5334 	*code = MINT_SDB_SEQ_POINT;
5335 }
5336 
5337 static MonoJitInfo*
interp_frame_get_jit_info(MonoInterpFrameHandle frame)5338 interp_frame_get_jit_info (MonoInterpFrameHandle frame)
5339 {
5340 	InterpFrame *iframe = (InterpFrame*)frame;
5341 
5342 	g_assert (iframe->imethod);
5343 	return iframe->imethod->jinfo;
5344 }
5345 
5346 static gpointer
interp_frame_get_ip(MonoInterpFrameHandle frame)5347 interp_frame_get_ip (MonoInterpFrameHandle frame)
5348 {
5349 	InterpFrame *iframe = (InterpFrame*)frame;
5350 
5351 	g_assert (iframe->imethod);
5352 	return (gpointer)iframe->ip;
5353 }
5354 
5355 static gpointer
interp_frame_get_arg(MonoInterpFrameHandle frame,int pos)5356 interp_frame_get_arg (MonoInterpFrameHandle frame, int pos)
5357 {
5358 	InterpFrame *iframe = (InterpFrame*)frame;
5359 
5360 	g_assert (iframe->imethod);
5361 
5362 	int arg_offset = iframe->imethod->arg_offsets [pos + (iframe->imethod->hasthis ? 1 : 0)];
5363 
5364 	return iframe->args + arg_offset;
5365 }
5366 
5367 static gpointer
interp_frame_get_local(MonoInterpFrameHandle frame,int pos)5368 interp_frame_get_local (MonoInterpFrameHandle frame, int pos)
5369 {
5370 	InterpFrame *iframe = (InterpFrame*)frame;
5371 
5372 	g_assert (iframe->imethod);
5373 
5374 	return iframe->locals + iframe->imethod->local_offsets [pos];
5375 }
5376 
5377 static gpointer
interp_frame_get_this(MonoInterpFrameHandle frame)5378 interp_frame_get_this (MonoInterpFrameHandle frame)
5379 {
5380 	InterpFrame *iframe = (InterpFrame*)frame;
5381 
5382 	g_assert (iframe->imethod);
5383 	g_assert (iframe->imethod->hasthis);
5384 
5385 	int arg_offset = iframe->imethod->arg_offsets [0];
5386 
5387 	return iframe->args + arg_offset;
5388 }
5389 
5390 static MonoInterpFrameHandle
interp_frame_get_parent(MonoInterpFrameHandle frame)5391 interp_frame_get_parent (MonoInterpFrameHandle frame)
5392 {
5393 	InterpFrame *iframe = (InterpFrame*)frame;
5394 
5395 	return iframe->parent;
5396 }
5397 
5398 static void
interp_start_single_stepping(void)5399 interp_start_single_stepping (void)
5400 {
5401 	ss_enabled = TRUE;
5402 }
5403 
5404 static void
interp_stop_single_stepping(void)5405 interp_stop_single_stepping (void)
5406 {
5407 	ss_enabled = FALSE;
5408 }
5409 
5410 void
mono_interp_init()5411 mono_interp_init ()
5412 {
5413 	mono_native_tls_alloc (&thread_context_id, NULL);
5414 	set_context (NULL);
5415 
5416 	mono_interp_transform_init ();
5417 
5418 	MonoInterpCallbacks c;
5419 	c.create_method_pointer = interp_create_method_pointer;
5420 	c.runtime_invoke = interp_runtime_invoke;
5421 	c.init_delegate = interp_init_delegate;
5422 #ifndef DISABLE_REMOTING
5423 	c.get_remoting_invoke = interp_get_remoting_invoke;
5424 #endif
5425 	c.create_trampoline = interp_create_trampoline;
5426 	c.walk_stack_with_ctx = interp_walk_stack_with_ctx;
5427 	c.set_resume_state = interp_set_resume_state;
5428 	c.run_finally = interp_run_finally;
5429 	c.run_filter = interp_run_filter;
5430 	c.frame_iter_init = interp_frame_iter_init;
5431 	c.frame_iter_next = interp_frame_iter_next;
5432 	c.find_jit_info = interp_find_jit_info;
5433 	c.set_breakpoint = interp_set_breakpoint;
5434 	c.clear_breakpoint = interp_clear_breakpoint;
5435 	c.frame_get_jit_info = interp_frame_get_jit_info;
5436 	c.frame_get_ip = interp_frame_get_ip;
5437 	c.frame_get_arg = interp_frame_get_arg;
5438 	c.frame_get_local = interp_frame_get_local;
5439 	c.frame_get_this = interp_frame_get_this;
5440 	c.frame_get_parent = interp_frame_get_parent;
5441 	c.start_single_stepping = interp_start_single_stepping;
5442 	c.stop_single_stepping = interp_stop_single_stepping;
5443 	mini_install_interp_callbacks (&c);
5444 }
5445