[interp] intrinsify System.Array.UnsafeLoad
[mono-project.git] / mono / mini / interp / interp.c
blob87d1781d6abb280338506f8b3a357d9550c88a49
1 /**
2 * \file
3 * PLEASE NOTE: This is a research prototype.
6 * interp.c: Interpreter for CIL byte codes
8 * Authors:
9 * Paolo Molaro (lupus@ximian.com)
10 * Miguel de Icaza (miguel@ximian.com)
11 * Dietmar Maurer (dietmar@ximian.com)
13 * (C) 2001, 2002 Ximian, Inc.
15 #ifndef __USE_ISOC99
16 #define __USE_ISOC99
17 #endif
18 #include "config.h"
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <glib.h>
23 #include <setjmp.h>
24 #include <signal.h>
25 #include <math.h>
26 #include <locale.h>
28 #include <mono/utils/gc_wrapper.h>
30 #ifdef HAVE_ALLOCA_H
31 # include <alloca.h>
32 #else
33 # ifdef __CYGWIN__
34 # define alloca __builtin_alloca
35 # endif
36 #endif
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/reflection-internals.h>
52 #include <mono/metadata/exception.h>
53 #include <mono/metadata/verify.h>
54 #include <mono/metadata/opcodes.h>
55 #include <mono/metadata/debug-helpers.h>
56 #include <mono/metadata/mono-config.h>
57 #include <mono/metadata/marshal.h>
58 #include <mono/metadata/environment.h>
59 #include <mono/metadata/mono-debug.h>
60 #include <mono/utils/atomic.h>
62 #include "interp.h"
63 #include "interp-internals.h"
64 #include "mintops.h"
65 #include "hacks.h"
67 #include <mono/mini/mini.h>
68 #include <mono/mini/jit-icalls.h>
71 /* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */
72 #ifdef _WIN32
73 #define isnan _isnan
74 #define finite _finite
75 #endif
76 #ifndef HAVE_FINITE
77 #ifdef HAVE_ISFINITE
78 #define finite isfinite
79 #endif
80 #endif
82 static inline void
83 init_frame (MonoInvocation *frame, MonoInvocation *parent_frame, RuntimeMethod *rmethod, stackval *method_args, stackval *method_retval)
85 frame->parent = parent_frame;
86 frame->stack_args = method_args;
87 frame->retval = method_retval;
88 frame->runtime_method = rmethod;
89 frame->ex = NULL;
90 frame->ip = NULL;
91 frame->invoke_trap = 0;
94 #define INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error) do { \
95 RuntimeMethod *_rmethod = mono_interp_get_runtime_method ((domain), (mono_method), (error)); \
96 init_frame ((frame), (parent_frame), _rmethod, (method_args), (method_retval)); \
97 } while (0)
100 * List of classes whose methods will be executed by transitioning to JITted code.
101 * Used for testing.
103 GSList *jit_classes;
105 void ves_exec_method (MonoInvocation *frame);
107 static char* dump_frame (MonoInvocation *inv);
108 static MonoArray *get_trace_ips (MonoDomain *domain, MonoInvocation *top);
109 static void ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception, int exit_at_finally);
111 typedef void (*ICallMethod) (MonoInvocation *frame);
113 static guint32 die_on_exception = 0;
114 static MonoNativeTlsKey thread_context_id;
116 static char* dump_args (MonoInvocation *inv);
118 #define DEBUG_INTERP 0
119 #define COUNT_OPS 0
120 #if DEBUG_INTERP
121 int mono_interp_traceopt = 2;
122 /* If true, then we output the opcodes as we interpret them */
123 static int global_tracing = 2;
125 static int debug_indent_level = 0;
127 static int break_on_method = 0;
128 static int nested_trace = 0;
129 static GList *db_methods = NULL;
131 static void
132 output_indent (void)
134 int h;
136 for (h = 0; h < debug_indent_level; h++)
137 g_print (" ");
140 static void
141 db_match_method (gpointer data, gpointer user_data)
143 MonoMethod *m = (MonoMethod*)user_data;
144 MonoMethodDesc *desc = data;
146 if (mono_method_desc_full_match (desc, m))
147 break_on_method = 1;
150 static void
151 debug_enter (MonoInvocation *frame, int *tracing)
153 if (db_methods) {
154 g_list_foreach (db_methods, db_match_method, (gpointer)frame->runtime_method->method);
155 if (break_on_method)
156 *tracing = nested_trace ? (global_tracing = 2, 3) : 2;
157 break_on_method = 0;
159 if (*tracing) {
160 MonoMethod *method = frame->runtime_method->method;
161 char *mn, *args = dump_args (frame);
162 debug_indent_level++;
163 output_indent ();
164 mn = mono_method_full_name (method, FALSE);
165 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn);
166 g_free (mn);
167 g_print ("%s)\n", args);
168 g_free (args);
170 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE)
171 mono_profiler_method_enter (frame->runtime_method->method);
175 #define DEBUG_LEAVE() \
176 if (tracing) { \
177 char *mn, *args; \
178 args = dump_retval (frame); \
179 output_indent (); \
180 mn = mono_method_full_name (frame->runtime_method->method, FALSE); \
181 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
182 g_free (mn); \
183 g_print (" => %s\n", args); \
184 g_free (args); \
185 debug_indent_level--; \
186 if (tracing == 3) global_tracing = 0; \
188 if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \
189 mono_profiler_method_leave (frame->runtime_method->method);
191 #else
193 int mono_interp_traceopt = 0;
194 static void debug_enter (MonoInvocation *frame, int *tracing)
197 #define DEBUG_LEAVE()
199 #endif
201 /* Set the current execution state to the resume state in context */
202 #define SET_RESUME_STATE(context) do { \
203 ip = (context)->handler_ip; \
204 sp->data.p = frame->ex; \
205 ++sp; \
206 frame->ex = NULL; \
207 (context)->has_resume_state = 0; \
208 (context)->handler_frame = NULL; \
209 goto main_loop; \
210 } while (0)
212 static void
213 ves_real_abort (int line, MonoMethod *mh,
214 const unsigned short *ip, stackval *stack, stackval *sp)
216 MonoError error;
217 fprintf (stderr, "Execution aborted in method: %s::%s\n", mh->klass->name, mh->name);
218 fprintf (stderr, "Line=%d IP=0x%04lx, Aborted execution\n", line,
219 ip-(const unsigned short *)mono_method_get_header_checked (mh, &error)->code);
220 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
221 g_print ("0x%04x %02x\n",
222 ip-(const unsigned short *)mono_method_get_header_checked (mh, &error)->code, *ip);
223 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
224 if (sp > stack)
225 printf ("\t[%ld] 0x%08x %0.5f\n", sp-stack, sp[-1].data.i, sp[-1].data.f);
228 #define ves_abort() \
229 do {\
230 ves_real_abort(__LINE__, frame->runtime_method->method, ip, frame->stack, sp); \
231 THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
232 } while (0);
234 RuntimeMethod*
235 mono_interp_get_runtime_method (MonoDomain *domain, MonoMethod *method, MonoError *error)
237 RuntimeMethod *rtm;
238 MonoJitDomainInfo *info;
239 MonoMethodSignature *sig;
240 int i;
242 error_init (error);
244 info = domain_jit_info (domain);
245 mono_domain_jit_code_hash_lock (domain);
246 rtm = mono_internal_hash_table_lookup (&info->interp_code_hash, method);
247 mono_domain_jit_code_hash_unlock (domain);
248 if (rtm)
249 return rtm;
251 sig = mono_method_signature (method);
253 rtm = mono_domain_alloc0 (domain, sizeof (RuntimeMethod));
254 rtm->method = method;
255 rtm->param_count = sig->param_count;
256 rtm->hasthis = sig->hasthis;
257 rtm->rtype = mini_get_underlying_type (sig->ret);
258 rtm->param_types = mono_domain_alloc0 (domain, sizeof (MonoType*) * sig->param_count);
259 for (i = 0; i < sig->param_count; ++i)
260 rtm->param_types [i] = mini_get_underlying_type (sig->params [i]);
262 mono_domain_jit_code_hash_lock (domain);
263 if (!mono_internal_hash_table_lookup (&info->interp_code_hash, method))
264 mono_internal_hash_table_insert (&info->interp_code_hash, method, rtm);
265 mono_domain_jit_code_hash_unlock (domain);
267 return rtm;
270 gpointer
271 mono_interp_create_trampoline (MonoDomain *domain, MonoMethod *method, MonoError *error)
273 if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
274 method = mono_marshal_get_synchronized_wrapper (method);
275 return mono_interp_get_runtime_method (domain, method, error);
278 static inline RuntimeMethod*
279 get_virtual_method (MonoDomain *domain, RuntimeMethod *runtime_method, MonoObject *obj)
281 MonoMethod *m = runtime_method->method;
282 MonoError error;
284 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
285 RuntimeMethod *ret = NULL;
286 if (mono_object_is_transparent_proxy (obj)) {
287 ret = mono_interp_get_runtime_method (domain, mono_marshal_get_remoting_invoke (m), &error);
288 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
289 } else if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
290 ret = mono_interp_get_runtime_method (domain, mono_marshal_get_synchronized_wrapper (m), &error);
291 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
292 } else {
293 ret = runtime_method;
295 return ret;
298 mono_class_setup_vtable (obj->vtable->klass);
300 int slot = mono_method_get_vtable_slot (m);
301 if (mono_class_is_interface (m->klass)) {
302 g_assert (obj->vtable->klass != m->klass);
303 /* TODO: interface offset lookup is slow, go through IMT instead */
304 gboolean non_exact_match;
305 slot += mono_class_interface_offset_with_variance (obj->vtable->klass, m->klass, &non_exact_match);
308 MonoMethod *virtual_method = obj->vtable->klass->vtable [slot];
309 if (m->is_inflated && mono_method_get_context (m)->method_inst) {
310 MonoGenericContext context = { NULL, NULL };
312 if (mono_class_is_ginst (virtual_method->klass))
313 context.class_inst = mono_class_get_generic_class (virtual_method->klass)->context.class_inst;
314 else if (mono_class_is_gtd (virtual_method->klass))
315 context.class_inst = mono_class_get_generic_container (virtual_method->klass)->context.class_inst;
316 context.method_inst = mono_method_get_context (m)->method_inst;
318 virtual_method = mono_class_inflate_generic_method_checked (virtual_method, &context, &error);
319 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
322 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
323 virtual_method = mono_marshal_get_synchronized_wrapper (virtual_method);
326 RuntimeMethod *virtual_runtime_method = mono_interp_get_runtime_method (domain, virtual_method, &error);
327 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
328 return virtual_runtime_method;
331 static void inline
332 stackval_from_data (MonoType *type, stackval *result, char *data, gboolean pinvoke)
334 if (type->byref) {
335 switch (type->type) {
336 case MONO_TYPE_OBJECT:
337 case MONO_TYPE_CLASS:
338 case MONO_TYPE_STRING:
339 case MONO_TYPE_ARRAY:
340 case MONO_TYPE_SZARRAY:
341 break;
342 default:
343 break;
345 result->data.p = *(gpointer*)data;
346 return;
348 switch (type->type) {
349 case MONO_TYPE_VOID:
350 return;
351 case MONO_TYPE_I1:
352 result->data.i = *(gint8*)data;
353 return;
354 case MONO_TYPE_U1:
355 case MONO_TYPE_BOOLEAN:
356 result->data.i = *(guint8*)data;
357 return;
358 case MONO_TYPE_I2:
359 result->data.i = *(gint16*)data;
360 return;
361 case MONO_TYPE_U2:
362 case MONO_TYPE_CHAR:
363 result->data.i = *(guint16*)data;
364 return;
365 case MONO_TYPE_I4:
366 result->data.i = *(gint32*)data;
367 return;
368 case MONO_TYPE_U:
369 case MONO_TYPE_I:
370 result->data.nati = *(mono_i*)data;
371 return;
372 case MONO_TYPE_PTR:
373 result->data.p = *(gpointer*)data;
374 return;
375 case MONO_TYPE_U4:
376 result->data.i = *(guint32*)data;
377 return;
378 case MONO_TYPE_R4:
379 result->data.f = *(float*)data;
380 return;
381 case MONO_TYPE_I8:
382 case MONO_TYPE_U8:
383 result->data.l = *(gint64*)data;
384 return;
385 case MONO_TYPE_R8:
386 result->data.f = *(double*)data;
387 return;
388 case MONO_TYPE_STRING:
389 case MONO_TYPE_SZARRAY:
390 case MONO_TYPE_CLASS:
391 case MONO_TYPE_OBJECT:
392 case MONO_TYPE_ARRAY:
393 result->data.p = *(gpointer*)data;
394 return;
395 case MONO_TYPE_VALUETYPE:
396 if (type->data.klass->enumtype) {
397 stackval_from_data (mono_class_enum_basetype (type->data.klass), result, data, pinvoke);
398 return;
399 } else
400 mono_value_copy (result->data.vt, data, type->data.klass);
401 return;
402 case MONO_TYPE_GENERICINST:
403 stackval_from_data (&type->data.generic_class->container_class->byval_arg, result, data, pinvoke);
404 return;
405 default:
406 g_warning ("got type 0x%02x", type->type);
407 g_assert_not_reached ();
411 static void inline
412 stackval_to_data (MonoType *type, stackval *val, char *data, gboolean pinvoke)
414 if (type->byref) {
415 gpointer *p = (gpointer*)data;
416 *p = val->data.p;
417 return;
419 /* printf ("TODAT0 %p\n", data); */
420 switch (type->type) {
421 case MONO_TYPE_I1:
422 case MONO_TYPE_U1: {
423 guint8 *p = (guint8*)data;
424 *p = val->data.i;
425 return;
427 case MONO_TYPE_BOOLEAN: {
428 guint8 *p = (guint8*)data;
429 *p = (val->data.i != 0);
430 return;
432 case MONO_TYPE_I2:
433 case MONO_TYPE_U2:
434 case MONO_TYPE_CHAR: {
435 guint16 *p = (guint16*)data;
436 *p = val->data.i;
437 return;
439 case MONO_TYPE_I: {
440 mono_i *p = (mono_i*)data;
441 /* In theory the value used by stloc should match the local var type
442 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
443 a native int - both by csc and mcs). Not sure what to do about sign extension
444 as it is outside the spec... doing the obvious */
445 *p = (mono_i)val->data.nati;
446 return;
448 case MONO_TYPE_U: {
449 mono_u *p = (mono_u*)data;
450 /* see above. */
451 *p = (mono_u)val->data.nati;
452 return;
454 case MONO_TYPE_I4:
455 case MONO_TYPE_U4: {
456 gint32 *p = (gint32*)data;
457 *p = val->data.i;
458 return;
460 case MONO_TYPE_I8:
461 case MONO_TYPE_U8: {
462 gint64 *p = (gint64*)data;
463 *p = val->data.l;
464 return;
466 case MONO_TYPE_R4: {
467 float *p = (float*)data;
468 *p = val->data.f;
469 return;
471 case MONO_TYPE_R8: {
472 double *p = (double*)data;
473 *p = val->data.f;
474 return;
476 case MONO_TYPE_STRING:
477 case MONO_TYPE_SZARRAY:
478 case MONO_TYPE_CLASS:
479 case MONO_TYPE_OBJECT:
480 case MONO_TYPE_ARRAY: {
481 gpointer *p = (gpointer *) data;
482 mono_gc_wbarrier_generic_store (p, val->data.p);
483 return;
485 case MONO_TYPE_PTR: {
486 gpointer *p = (gpointer *) data;
487 *p = val->data.p;
488 return;
490 case MONO_TYPE_VALUETYPE:
491 if (type->data.klass->enumtype) {
492 stackval_to_data (mono_class_enum_basetype (type->data.klass), val, data, pinvoke);
493 return;
494 } else
495 mono_value_copy (data, val->data.vt, type->data.klass);
496 return;
497 case MONO_TYPE_GENERICINST: {
498 MonoClass *container_class = type->data.generic_class->container_class;
500 if (container_class->valuetype && !container_class->enumtype) {
501 mono_value_copy (data, val->data.vt, mono_class_from_mono_type (type));
502 return;
504 stackval_to_data (&type->data.generic_class->container_class->byval_arg, val, data, pinvoke);
505 return;
507 default:
508 g_warning ("got type %x", type->type);
509 g_assert_not_reached ();
513 static void
514 fill_in_trace (MonoException *exception, MonoInvocation *frame)
516 MonoError error;
517 char *stack_trace = dump_frame (frame);
518 MonoDomain *domain = mono_domain_get();
519 (exception)->stack_trace = mono_string_new_checked (domain, stack_trace, &error);
520 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
521 (exception)->trace_ips = get_trace_ips (domain, frame);
522 g_free (stack_trace);
525 #define FILL_IN_TRACE(exception, frame) fill_in_trace(exception, frame)
527 #define THROW_EX(exception,ex_ip) \
528 do {\
529 frame->ip = (ex_ip); \
530 frame->ex = (MonoException*)(exception); \
531 FILL_IN_TRACE(frame->ex, frame); \
532 goto handle_exception; \
533 } while (0)
535 static MonoObject*
536 ves_array_create (MonoInvocation *frame, MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
538 uintptr_t *lengths;
539 intptr_t *lower_bounds;
540 MonoObject *obj;
541 MonoError error;
542 int i;
544 lengths = alloca (sizeof (uintptr_t) * klass->rank * 2);
545 for (i = 0; i < sig->param_count; ++i) {
546 lengths [i] = values->data.i;
547 values ++;
549 if (klass->rank == sig->param_count) {
550 /* Only lengths provided. */
551 lower_bounds = NULL;
552 } else {
553 /* lower bounds are first. */
554 lower_bounds = (intptr_t *) lengths;
555 lengths += klass->rank;
557 obj = (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, &error);
558 if (!mono_error_ok (&error)) {
559 frame->ex = mono_error_convert_to_exception (&error);
560 FILL_IN_TRACE (frame->ex, frame);
562 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
563 return obj;
566 static gint32
567 ves_array_calculate_index (MonoArray *ao, stackval *sp, MonoInvocation *frame, gboolean safe)
569 g_assert (!frame->ex);
570 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
572 guint32 pos = 0;
573 if (ao->bounds) {
574 for (gint32 i = 0; i < ac->rank; i++) {
575 guint32 idx = sp [i].data.i;
576 guint32 lower = ao->bounds [i].lower_bound;
577 guint32 len = ao->bounds [i].length;
578 if (safe && (idx < lower || (idx - lower) >= len)) {
579 frame->ex = mono_get_exception_index_out_of_range ();
580 FILL_IN_TRACE (frame->ex, frame);
581 return -1;
583 pos = (pos * len) + idx - lower;
585 } else {
586 pos = sp [0].data.i;
587 if (safe && pos >= ao->max_length) {
588 frame->ex = mono_get_exception_index_out_of_range ();
589 FILL_IN_TRACE (frame->ex, frame);
590 return -1;
593 return pos;
596 static void
597 ves_array_set (MonoInvocation *frame)
599 stackval *sp = frame->stack_args + 1;
601 MonoObject *o = frame->stack_args->data.p;
602 MonoArray *ao = (MonoArray *) o;
603 MonoClass *ac = o->vtable->klass;
605 g_assert (ac->rank >= 1);
607 gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
608 if (frame->ex)
609 return;
611 if (sp [ac->rank].data.p && !mono_object_class (o)->element_class->valuetype) {
612 MonoError error;
613 MonoObject *isinst = mono_object_isinst_checked (sp [ac->rank].data.p, mono_object_class (o)->element_class, &error);
614 mono_error_cleanup (&error);
615 if (!isinst) {
616 frame->ex = mono_get_exception_array_type_mismatch ();
617 FILL_IN_TRACE (frame->ex, frame);
618 return;
622 gint32 esize = mono_array_element_size (ac);
623 gpointer ea = mono_array_addr_with_size (ao, esize, pos);
625 MonoType *mt = mono_method_signature (frame->runtime_method->method)->params [ac->rank];
626 stackval_to_data (mt, &sp [ac->rank], ea, FALSE);
629 static void
630 ves_array_get (MonoInvocation *frame, gboolean safe)
632 stackval *sp = frame->stack_args + 1;
634 MonoObject *o = frame->stack_args->data.p;
635 MonoArray *ao = (MonoArray *) o;
636 MonoClass *ac = o->vtable->klass;
638 g_assert (ac->rank >= 1);
640 gint32 pos = ves_array_calculate_index (ao, sp, frame, safe);
641 if (frame->ex)
642 return;
644 gint32 esize = mono_array_element_size (ac);
645 gpointer ea = mono_array_addr_with_size (ao, esize, pos);
647 MonoType *mt = mono_method_signature (frame->runtime_method->method)->ret;
648 stackval_from_data (mt, frame->retval, ea, FALSE);
651 static gpointer
652 ves_array_element_address (MonoInvocation *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
654 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
656 g_assert (ac->rank >= 1);
658 gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
659 if (frame->ex)
660 return NULL;
662 if (needs_typecheck && !mono_class_is_assignable_from (mono_object_class ((MonoObject *) ao)->element_class, required_type->element_class)) {
663 frame->ex = mono_get_exception_array_type_mismatch ();
664 FILL_IN_TRACE (frame->ex, frame);
665 return NULL;
667 gint32 esize = mono_array_element_size (ac);
668 return mono_array_addr_with_size (ao, esize, pos);
671 void
672 interp_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUnwindOptions options, void *user_data)
674 MonoError error;
675 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
677 if (!context)
678 return;
680 MonoInvocation *frame = context->current_frame;
682 while (frame) {
683 MonoStackFrameInfo fi;
684 memset (&fi, 0, sizeof (MonoStackFrameInfo));
686 /* TODO: hack to make some asserts happy. */
687 fi.ji = (MonoJitInfo *) frame->runtime_method;
689 if (frame->runtime_method)
690 fi.method = fi.actual_method = frame->runtime_method->method;
692 if (!fi.method || (fi.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (fi.method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
693 fi.il_offset = -1;
694 fi.type = FRAME_TYPE_MANAGED_TO_NATIVE;
695 } else {
696 MonoMethodHeader *hd = mono_method_get_header_checked (fi.method, &error);
697 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
698 fi.type = FRAME_TYPE_MANAGED;
699 fi.il_offset = frame->ip - (const unsigned short *) hd->code;
700 if (!fi.method->wrapper_type)
701 fi.managed = TRUE;
704 if (func (&fi, ctx, user_data))
705 return;
706 frame = frame->parent;
710 static MonoPIFunc mono_interp_enter_icall_trampoline = NULL;
712 static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvocation *frame)
714 InterpMethodArguments *margs = g_malloc0 (sizeof (InterpMethodArguments));
716 if (sig->hasthis)
717 margs->ilen++;
719 for (int i = 0; i < sig->param_count; i++) {
720 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
721 switch (ptype) {
722 case MONO_TYPE_BOOLEAN:
723 case MONO_TYPE_CHAR:
724 case MONO_TYPE_I1:
725 case MONO_TYPE_U1:
726 case MONO_TYPE_I2:
727 case MONO_TYPE_U2:
728 case MONO_TYPE_I4:
729 case MONO_TYPE_U4:
730 case MONO_TYPE_I:
731 case MONO_TYPE_U:
732 case MONO_TYPE_PTR:
733 case MONO_TYPE_SZARRAY:
734 case MONO_TYPE_CLASS:
735 case MONO_TYPE_OBJECT:
736 case MONO_TYPE_STRING:
737 case MONO_TYPE_VALUETYPE:
738 case MONO_TYPE_GENERICINST:
739 #if SIZEOF_VOID_P == 8
740 case MONO_TYPE_I8:
741 #endif
742 margs->ilen++;
743 break;
744 #if SIZEOF_VOID_P == 4
745 case MONO_TYPE_I8:
746 g_assert (0);
747 break;
748 #endif
749 case MONO_TYPE_R4:
750 #if SIZEOF_VOID_P == 8
751 case MONO_TYPE_R8:
752 #endif
753 margs->flen++;
754 break;
755 #if SIZEOF_VOID_P == 4
756 case MONO_TYPE_R8:
757 margs->flen += 2;
758 break;
759 #endif
760 default:
761 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
765 if (margs->ilen > 0)
766 margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen);
768 if (margs->flen > 0)
769 margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
771 if (margs->ilen > INTERP_ICALL_TRAMP_IARGS)
772 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
774 if (margs->flen > INTERP_ICALL_TRAMP_FARGS)
775 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen);
778 size_t int_i = 0;
779 size_t int_f = 0;
781 if (sig->hasthis) {
782 margs->iargs [0] = frame->stack_args->data.p;
783 int_i++;
786 for (int i = 0; i < sig->param_count; i++) {
787 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
788 switch (ptype) {
789 case MONO_TYPE_BOOLEAN:
790 case MONO_TYPE_CHAR:
791 case MONO_TYPE_I1:
792 case MONO_TYPE_U1:
793 case MONO_TYPE_I2:
794 case MONO_TYPE_U2:
795 case MONO_TYPE_I4:
796 case MONO_TYPE_U4:
797 case MONO_TYPE_I:
798 case MONO_TYPE_U:
799 case MONO_TYPE_PTR:
800 case MONO_TYPE_SZARRAY:
801 case MONO_TYPE_CLASS:
802 case MONO_TYPE_OBJECT:
803 case MONO_TYPE_STRING:
804 case MONO_TYPE_VALUETYPE:
805 case MONO_TYPE_GENERICINST:
806 #if SIZEOF_VOID_P == 8
807 case MONO_TYPE_I8:
808 #endif
809 margs->iargs [int_i] = frame->stack_args [i].data.p;
810 #if DEBUG_INTERP
811 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
812 #endif
813 int_i++;
814 break;
815 #if SIZEOF_VOID_P == 4
816 case MONO_TYPE_I8:
817 g_assert (0);
818 break;
819 #endif
820 case MONO_TYPE_R4:
821 case MONO_TYPE_R8:
822 if (ptype == MONO_TYPE_R4)
823 * (float *) &(margs->fargs [int_f]) = (float) frame->stack_args [i].data.f;
824 else
825 margs->fargs [int_f] = frame->stack_args [i].data.f;
826 #if DEBUG_INTERP
827 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);
828 #endif
829 #if SIZEOF_VOID_P == 4
830 int_f += 2;
831 #else
832 int_f++;
833 #endif
834 break;
835 default:
836 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
840 switch (sig->ret->type) {
841 case MONO_TYPE_BOOLEAN:
842 case MONO_TYPE_CHAR:
843 case MONO_TYPE_I1:
844 case MONO_TYPE_U1:
845 case MONO_TYPE_I2:
846 case MONO_TYPE_U2:
847 case MONO_TYPE_I4:
848 case MONO_TYPE_U4:
849 case MONO_TYPE_I:
850 case MONO_TYPE_U:
851 case MONO_TYPE_PTR:
852 case MONO_TYPE_SZARRAY:
853 case MONO_TYPE_CLASS:
854 case MONO_TYPE_OBJECT:
855 case MONO_TYPE_STRING:
856 case MONO_TYPE_I8:
857 case MONO_TYPE_VALUETYPE:
858 case MONO_TYPE_GENERICINST:
859 margs->retval = &(frame->retval->data.p);
860 margs->is_float_ret = 0;
861 break;
862 case MONO_TYPE_R4:
863 case MONO_TYPE_R8:
864 margs->retval = &(frame->retval->data.p);
865 margs->is_float_ret = 1;
866 break;
867 case MONO_TYPE_VOID:
868 margs->retval = NULL;
869 break;
870 default:
871 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type);
874 return margs;
877 static void
878 ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context)
880 jmp_buf env;
881 MonoInvocation *old_frame = context->current_frame;
882 MonoInvocation *old_env_frame = context->env_frame;
883 jmp_buf *old_env = context->current_env;
884 MonoLMFExt ext;
886 if (setjmp (env)) {
887 context->current_frame = old_frame;
888 context->env_frame = old_env_frame;
889 context->current_env = old_env;
890 context->managed_code = 1;
891 return;
894 frame->ex = NULL;
895 context->env_frame = frame;
896 context->current_env = &env;
898 g_assert (!frame->runtime_method);
899 if (!mono_interp_enter_icall_trampoline) {
900 MonoTrampInfo *info;
901 mono_interp_enter_icall_trampoline = mono_arch_get_enter_icall_trampoline (&info);
902 // TODO:
903 // mono_tramp_info_register (info, NULL);
906 InterpMethodArguments *margs = build_args_from_sig (sig, frame);
907 #if DEBUG_INTERP
908 g_print ("ICALL: mono_interp_enter_icall_trampoline = %p, addr = %p\n", mono_interp_enter_icall_trampoline, addr);
909 g_print ("margs(out): ilen=%d, flen=%d\n", margs->ilen, margs->flen);
910 #endif
912 context->current_frame = frame;
913 context->managed_code = 0;
916 * Push an LMF frame on the LMF stack
917 * to mark the transition to native code.
919 memset (&ext, 0, sizeof (ext));
920 ext.interp_exit = TRUE;
921 ext.interp_exit_data = frame;
923 mono_push_lmf (&ext);
925 mono_interp_enter_icall_trampoline (addr, margs);
927 mono_pop_lmf (&ext.lmf);
929 context->managed_code = 1;
930 /* domain can only be changed by native code */
931 context->domain = mono_domain_get ();
933 if (*mono_thread_interruption_request_flag ()) {
934 MonoException *exc = mono_thread_interruption_checkpoint ();
935 if (exc) {
936 frame->ex = exc;
937 context->search_for_handler = 1;
941 if (!frame->ex && !MONO_TYPE_ISSTRUCT (sig->ret))
942 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
944 context->current_frame = old_frame;
945 context->env_frame = old_env_frame;
946 context->current_env = old_env;
948 g_free (margs->iargs);
949 g_free (margs->fargs);
950 g_free (margs);
953 void
954 mono_interp_init_delegate (MonoDelegate *del)
956 if (del->method)
957 return;
958 /* shouldn't need a write barrier because we don't write a MonoObject into the field */
959 del->method = ((RuntimeMethod *) del->method_ptr)->method;
963 * From the spec:
964 * runtime specifies that the implementation of the method is automatically
965 * provided by the runtime and is primarily used for the methods of delegates.
967 static void
968 ves_runtime_method (MonoInvocation *frame, ThreadContext *context)
970 MonoMethod *method = frame->runtime_method->method;
971 const char *name = method->name;
972 MonoObject *obj = (MonoObject*) frame->stack_args->data.p;
973 MonoObject *isinst_obj;
974 MonoError error;
976 mono_class_init (method->klass);
978 if (method->klass == mono_defaults.array_class) {
979 if (!strcmp (method->name, "UnsafeMov")) {
980 /* TODO: layout checks */
981 MonoType *mt = mono_method_signature (method)->ret;
982 stackval_from_data (mt, frame->retval, (char *) frame->stack_args, FALSE);
983 return;
985 if (!strcmp (method->name, "UnsafeLoad")) {
986 ves_array_get (frame, FALSE);
987 return;
991 isinst_obj = mono_object_isinst_checked (obj, mono_defaults.array_class, &error);
992 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
993 if (obj && isinst_obj) {
994 if (*name == 'S' && (strcmp (name, "Set") == 0)) {
995 ves_array_set (frame);
996 return;
998 if (*name == 'G' && (strcmp (name, "Get") == 0)) {
999 ves_array_get (frame, TRUE);
1000 return;
1004 g_error ("Don't know how to exec runtime method %s.%s::%s",
1005 method->klass->name_space, method->klass->name,
1006 method->name);
1009 #if DEBUG_INTERP
1010 static char*
1011 dump_stack (stackval *stack, stackval *sp)
1013 stackval *s = stack;
1014 GString *str = g_string_new ("");
1016 if (sp == stack)
1017 return g_string_free (str, FALSE);
1019 while (s < sp) {
1020 g_string_append_printf (str, "[%p (%lld)] ", s->data.l, s->data.l);
1021 ++s;
1023 return g_string_free (str, FALSE);
1025 #endif
1027 static void
1028 dump_stackval (GString *str, stackval *s, MonoType *type)
1030 switch (type->type) {
1031 case MONO_TYPE_I1:
1032 case MONO_TYPE_U1:
1033 case MONO_TYPE_I2:
1034 case MONO_TYPE_U2:
1035 case MONO_TYPE_I4:
1036 case MONO_TYPE_U4:
1037 case MONO_TYPE_CHAR:
1038 case MONO_TYPE_BOOLEAN:
1039 g_string_append_printf (str, "[%d] ", s->data.i);
1040 break;
1041 case MONO_TYPE_STRING:
1042 case MONO_TYPE_SZARRAY:
1043 case MONO_TYPE_CLASS:
1044 case MONO_TYPE_OBJECT:
1045 case MONO_TYPE_ARRAY:
1046 case MONO_TYPE_PTR:
1047 case MONO_TYPE_I:
1048 case MONO_TYPE_U:
1049 g_string_append_printf (str, "[%p] ", s->data.p);
1050 break;
1051 case MONO_TYPE_VALUETYPE:
1052 if (type->data.klass->enumtype)
1053 g_string_append_printf (str, "[%d] ", s->data.i);
1054 else
1055 g_string_append_printf (str, "[vt:%p] ", s->data.p);
1056 break;
1057 case MONO_TYPE_R4:
1058 case MONO_TYPE_R8:
1059 g_string_append_printf (str, "[%g] ", s->data.f);
1060 break;
1061 case MONO_TYPE_I8:
1062 case MONO_TYPE_U8:
1063 default: {
1064 GString *res = g_string_new ("");
1065 mono_type_get_desc (res, type, TRUE);
1066 g_string_append_printf (str, "[{%s} %lld/0x%0llx] ", res->str, s->data.l, s->data.l);
1067 g_string_free (res, TRUE);
1068 break;
1073 #if DEBUG_INTERP
1074 static char*
1075 dump_retval (MonoInvocation *inv)
1077 GString *str = g_string_new ("");
1078 MonoType *ret = mono_method_signature (inv->runtime_method->method)->ret;
1080 if (ret->type != MONO_TYPE_VOID)
1081 dump_stackval (str, inv->retval, ret);
1083 return g_string_free (str, FALSE);
1085 #endif
1087 static char*
1088 dump_args (MonoInvocation *inv)
1090 GString *str = g_string_new ("");
1091 int i;
1092 MonoMethodSignature *signature = mono_method_signature (inv->runtime_method->method);
1094 if (signature->param_count == 0 && !signature->hasthis)
1095 return g_string_free (str, FALSE);
1097 if (signature->hasthis) {
1098 MonoMethod *method = inv->runtime_method->method;
1099 dump_stackval (str, inv->stack_args, &method->klass->byval_arg);
1102 for (i = 0; i < signature->param_count; ++i)
1103 dump_stackval (str, inv->stack_args + (!!signature->hasthis) + i, signature->params [i]);
1105 return g_string_free (str, FALSE);
1108 static char*
1109 dump_frame (MonoInvocation *inv)
1111 GString *str = g_string_new ("");
1112 int i;
1113 char *args;
1114 MonoError error;
1116 for (i = 0; inv; inv = inv->parent) {
1117 if (inv->runtime_method != NULL) {
1118 MonoMethod *method = inv->runtime_method->method;
1119 MonoClass *k;
1121 int codep = 0;
1122 const char * opname = "";
1123 char *name;
1124 gchar *source = NULL;
1126 k = method->klass;
1128 if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 &&
1129 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) == 0) {
1130 MonoMethodHeader *hd = mono_method_get_header_checked (method, &error);
1131 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1133 if (hd != NULL) {
1134 if (inv->ip) {
1135 opname = mono_interp_opname [*inv->ip];
1136 codep = inv->ip - inv->runtime_method->code;
1137 source = g_strdup_printf ("%s:%d // (TODO: proper stacktrace)", method->name, codep);
1138 } else
1139 opname = "";
1141 #if 0
1142 MonoDebugSourceLocation *minfo = mono_debug_lookup_method (method);
1143 source = mono_debug_method_lookup_location (minfo, codep);
1144 #endif
1147 args = dump_args (inv);
1148 name = mono_method_full_name (method, TRUE);
1149 if (source)
1150 g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s) at %s\n", i, codep, opname, name, args, source);
1151 else
1152 g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s)\n", i, codep, opname, name, args);
1153 g_free (name);
1154 g_free (args);
1155 g_free (source);
1156 ++i;
1159 return g_string_free (str, FALSE);
1162 static MonoArray *
1163 get_trace_ips (MonoDomain *domain, MonoInvocation *top)
1165 int i;
1166 MonoArray *res;
1167 MonoInvocation *inv;
1168 MonoError error;
1170 for (i = 0, inv = top; inv; inv = inv->parent)
1171 if (inv->runtime_method != NULL)
1172 ++i;
1174 res = mono_array_new_checked (domain, mono_defaults.int_class, 2 * i, &error);
1175 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1177 for (i = 0, inv = top; inv; inv = inv->parent)
1178 if (inv->runtime_method != NULL) {
1179 mono_array_set (res, gpointer, i, inv->runtime_method);
1180 ++i;
1181 mono_array_set (res, gpointer, i, (gpointer)inv->ip);
1182 ++i;
1185 return res;
1189 #define MYGUINT64_MAX 18446744073709551615ULL
1190 #define MYGINT64_MAX 9223372036854775807LL
1191 #define MYGINT64_MIN (-MYGINT64_MAX -1LL)
1193 #define MYGUINT32_MAX 4294967295U
1194 #define MYGINT32_MAX 2147483647
1195 #define MYGINT32_MIN (-MYGINT32_MAX -1)
1197 #define CHECK_ADD_OVERFLOW(a,b) \
1198 (gint32)(b) >= 0 ? (gint32)(MYGINT32_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1199 : (gint32)(MYGINT32_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0
1201 #define CHECK_SUB_OVERFLOW(a,b) \
1202 (gint32)(b) < 0 ? (gint32)(MYGINT32_MAX) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1203 : (gint32)(MYGINT32_MIN) + (gint32)(b) > (gint32)(a) ? +1 : 0
1205 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1206 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1208 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1209 (guint32)(a) < (guint32)(b) ? -1 : 0
1211 #define CHECK_ADD_OVERFLOW64(a,b) \
1212 (gint64)(b) >= 0 ? (gint64)(MYGINT64_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1213 : (gint64)(MYGINT64_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0
1215 #define CHECK_SUB_OVERFLOW64(a,b) \
1216 (gint64)(b) < 0 ? (gint64)(MYGINT64_MAX) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1217 : (gint64)(MYGINT64_MIN) + (gint64)(b) > (gint64)(a) ? +1 : 0
1219 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1220 (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
1222 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1223 (guint64)(a) < (guint64)(b) ? -1 : 0
1225 #if SIZEOF_VOID_P == 4
1226 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1227 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1228 #else
1229 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1230 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1231 #endif
1233 /* Resolves to TRUE if the operands would overflow */
1234 #define CHECK_MUL_OVERFLOW(a,b) \
1235 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1236 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1237 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == - MYGINT32_MAX) : \
1238 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((MYGINT32_MAX) / (gint32)(b)) : \
1239 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((MYGINT32_MIN) / (gint32)(b)) : \
1240 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((MYGINT32_MIN) / (gint32)(b)) : \
1241 (gint32)(a) < ((MYGINT32_MAX) / (gint32)(b))
1243 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1244 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1245 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1247 #define CHECK_MUL_OVERFLOW64(a,b) \
1248 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1249 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1250 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == - MYGINT64_MAX) : \
1251 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((MYGINT64_MAX) / (gint64)(b)) : \
1252 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((MYGINT64_MIN) / (gint64)(b)) : \
1253 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((MYGINT64_MIN) / (gint64)(b)) : \
1254 (gint64)(a) < ((MYGINT64_MAX) / (gint64)(b))
1256 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1257 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1258 (guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a))
1260 #if SIZEOF_VOID_P == 4
1261 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1262 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1263 #else
1264 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1265 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1266 #endif
1268 MonoObject*
1269 mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
1271 MonoInvocation frame;
1272 ThreadContext * volatile context = mono_native_tls_get_value (thread_context_id);
1273 MonoObject *retval = NULL;
1274 MonoMethodSignature *sig = mono_method_signature (method);
1275 MonoClass *klass = mono_class_from_mono_type (sig->ret);
1276 int i, type, isobject = 0;
1277 void *ret = NULL;
1278 stackval result;
1279 stackval *args = alloca (sizeof (stackval) * (sig->param_count + !!sig->hasthis));
1280 ThreadContext context_struct;
1281 MonoInvocation *old_frame = NULL;
1282 jmp_buf env;
1284 error_init (error);
1285 if (exc)
1286 *exc = NULL;
1288 frame.ex = NULL;
1290 if (setjmp(env)) {
1291 if (context != &context_struct) {
1292 context->domain = mono_domain_get ();
1293 context->current_frame = old_frame;
1294 context->managed_code = 0;
1295 } else
1296 mono_native_tls_set_value (thread_context_id, NULL);
1297 if (exc != NULL)
1298 *exc = (MonoObject *)frame.ex;
1299 return retval;
1302 if (context == NULL) {
1303 context = &context_struct;
1304 memset (context, 0, sizeof (ThreadContext));
1305 context_struct.base_frame = &frame;
1306 context_struct.env_frame = &frame;
1307 context_struct.current_env = &env;
1308 mono_native_tls_set_value (thread_context_id, context);
1310 else
1311 old_frame = context->current_frame;
1313 context->domain = mono_domain_get ();
1315 switch (sig->ret->type) {
1316 case MONO_TYPE_VOID:
1317 break;
1318 case MONO_TYPE_STRING:
1319 case MONO_TYPE_OBJECT:
1320 case MONO_TYPE_CLASS:
1321 case MONO_TYPE_ARRAY:
1322 case MONO_TYPE_SZARRAY:
1323 isobject = 1;
1324 break;
1325 case MONO_TYPE_VALUETYPE:
1326 retval = mono_object_new_checked (context->domain, klass, error);
1327 ret = mono_object_unbox (retval);
1328 if (!sig->ret->data.klass->enumtype)
1329 result.data.vt = ret;
1330 else
1331 result.data.vt = alloca (mono_class_instance_size (klass));
1332 break;
1333 case MONO_TYPE_GENERICINST:
1334 if (!MONO_TYPE_IS_REFERENCE (sig->ret)) {
1335 retval = mono_object_new_checked (context->domain, klass, error);
1336 ret = mono_object_unbox (retval);
1337 if (!sig->ret->data.klass->enumtype)
1338 result.data.vt = ret;
1339 else
1340 result.data.vt = alloca (mono_class_instance_size (klass));
1341 } else {
1342 isobject = 1;
1344 break;
1346 case MONO_TYPE_PTR:
1347 retval = mono_object_new_checked (context->domain, mono_defaults.int_class, error);
1348 ret = mono_object_unbox (retval);
1349 break;
1350 default:
1351 retval = mono_object_new_checked (context->domain, klass, error);
1352 ret = mono_object_unbox (retval);
1353 break;
1356 if (sig->hasthis)
1357 args [0].data.p = obj;
1359 for (i = 0; i < sig->param_count; ++i) {
1360 int a_index = i + !!sig->hasthis;
1361 if (sig->params [i]->byref) {
1362 args [a_index].data.p = params [i];
1363 continue;
1365 type = sig->params [i]->type;
1366 handle_enum:
1367 switch (type) {
1368 case MONO_TYPE_U1:
1369 case MONO_TYPE_I1:
1370 case MONO_TYPE_BOOLEAN:
1371 args [a_index].data.i = *(MonoBoolean*)params [i];
1372 break;
1373 case MONO_TYPE_U2:
1374 case MONO_TYPE_I2:
1375 case MONO_TYPE_CHAR:
1376 args [a_index].data.i = *(gint16*)params [i];
1377 break;
1378 #if SIZEOF_VOID_P == 4
1379 case MONO_TYPE_U: /* use VAL_POINTER? */
1380 case MONO_TYPE_I:
1381 #endif
1382 case MONO_TYPE_U4:
1383 case MONO_TYPE_I4:
1384 args [a_index].data.i = *(gint32*)params [i];
1385 break;
1386 #if SIZEOF_VOID_P == 8
1387 case MONO_TYPE_U:
1388 case MONO_TYPE_I:
1389 #endif
1390 case MONO_TYPE_U8:
1391 case MONO_TYPE_I8:
1392 args [a_index].data.l = *(gint64*)params [i];
1393 break;
1394 case MONO_TYPE_R4:
1395 args [a_index].data.f = *(gfloat *) params [i];
1396 break;
1397 case MONO_TYPE_R8:
1398 args [a_index].data.f = *(gdouble *) params [i];
1399 break;
1400 case MONO_TYPE_VALUETYPE:
1401 if (sig->params [i]->data.klass->enumtype) {
1402 type = mono_class_enum_basetype (sig->params [i]->data.klass)->type;
1403 goto handle_enum;
1404 } else {
1405 args [a_index].data.p = params [i];
1407 break;
1408 case MONO_TYPE_STRING:
1409 case MONO_TYPE_PTR:
1410 case MONO_TYPE_CLASS:
1411 case MONO_TYPE_ARRAY:
1412 case MONO_TYPE_SZARRAY:
1413 case MONO_TYPE_OBJECT:
1414 case MONO_TYPE_GENERICINST:
1415 args [a_index].data.p = params [i];
1416 break;
1417 default:
1418 g_error ("type 0x%x not handled in runtime invoke", sig->params [i]->type);
1422 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1423 method = mono_marshal_get_native_wrapper (method, FALSE, FALSE);
1424 INIT_FRAME (&frame,context->current_frame,args,&result,mono_get_root_domain (),method,error);
1425 if (exc)
1426 frame.invoke_trap = 1;
1427 context->managed_code = 1;
1428 ves_exec_method_with_context (&frame, context, NULL, NULL, -1);
1429 context->managed_code = 0;
1430 if (context == &context_struct)
1431 mono_native_tls_set_value (thread_context_id, NULL);
1432 else
1433 context->current_frame = old_frame;
1434 if (frame.ex != NULL) {
1435 if (exc != NULL) {
1436 *exc = (MonoObject*) frame.ex;
1437 return NULL;
1439 if (context->current_env != NULL) {
1440 context->env_frame->ex = frame.ex;
1441 longjmp(*context->current_env, 1);
1443 else
1444 printf("dropped exception...\n");
1446 if (sig->ret->type == MONO_TYPE_VOID && !method->string_ctor)
1447 return NULL;
1448 if (isobject || method->string_ctor)
1449 return result.data.p;
1450 stackval_to_data (sig->ret, &result, ret, sig->pinvoke);
1451 return retval;
1454 typedef struct {
1455 RuntimeMethod *rmethod;
1456 gpointer this_arg;
1457 gpointer res;
1458 gpointer args [16];
1459 gpointer *many_args;
1460 } InterpEntryData;
1462 /* Main function for entering the interpreter from compiled code */
1463 static void
1464 interp_entry (InterpEntryData *data)
1466 MonoInvocation frame;
1467 RuntimeMethod *rmethod = data->rmethod;
1468 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
1469 ThreadContext context_struct;
1470 MonoInvocation *old_frame;
1471 stackval result;
1472 stackval *args;
1473 MonoMethod *method;
1474 MonoMethodSignature *sig;
1475 MonoType *type;
1476 int i;
1478 method = rmethod->method;
1479 sig = mono_method_signature (method);
1481 // FIXME: Optimize this
1483 //printf ("%s\n", mono_method_full_name (method, 1));
1485 frame.ex = NULL;
1486 if (context == NULL) {
1487 context = &context_struct;
1488 memset (context, 0, sizeof (ThreadContext));
1489 context_struct.base_frame = &frame;
1490 context_struct.env_frame = &frame;
1491 mono_native_tls_set_value (thread_context_id, context);
1493 else
1494 old_frame = context->current_frame;
1495 context->domain = mono_domain_get ();
1497 args = alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
1498 if (sig->hasthis)
1499 args [0].data.p = data->this_arg;
1501 gpointer *params;
1502 if (data->many_args)
1503 params = data->many_args;
1504 else
1505 params = data->args;
1506 for (i = 0; i < sig->param_count; ++i) {
1507 int a_index = i + (sig->hasthis ? 1 : 0);
1508 if (sig->params [i]->byref) {
1509 args [a_index].data.p = params [i];
1510 continue;
1512 type = rmethod->param_types [i];
1513 switch (type->type) {
1514 case MONO_TYPE_U1:
1515 case MONO_TYPE_I1:
1516 args [a_index].data.i = *(MonoBoolean*)params [i];
1517 break;
1518 case MONO_TYPE_U2:
1519 case MONO_TYPE_I2:
1520 args [a_index].data.i = *(gint16*)params [i];
1521 break;
1522 case MONO_TYPE_U:
1523 #if SIZEOF_VOID_P == 4
1524 args [a_index].data.p = GINT_TO_POINTER (*(guint32*)params [i]);
1525 #else
1526 args [a_index].data.p = GINT_TO_POINTER (*(guint64*)params [i]);
1527 #endif
1528 break;
1529 case MONO_TYPE_I:
1530 #if SIZEOF_VOID_P == 4
1531 args [a_index].data.p = GINT_TO_POINTER (*(gint32*)params [i]);
1532 #else
1533 args [a_index].data.p = GINT_TO_POINTER (*(gint64*)params [i]);
1534 #endif
1535 break;
1536 case MONO_TYPE_U4:
1537 args [a_index].data.i = *(guint32*)params [i];
1538 break;
1539 case MONO_TYPE_I4:
1540 args [a_index].data.i = *(gint32*)params [i];
1541 break;
1542 case MONO_TYPE_U8:
1543 args [a_index].data.l = *(guint64*)params [i];
1544 break;
1545 case MONO_TYPE_I8:
1546 args [a_index].data.l = *(gint64*)params [i];
1547 break;
1548 case MONO_TYPE_PTR:
1549 case MONO_TYPE_OBJECT:
1550 args [a_index].data.p = *(MonoObject**)params [i];
1551 break;
1552 case MONO_TYPE_VALUETYPE:
1553 args [a_index].data.p = params [i];
1554 break;
1555 case MONO_TYPE_GENERICINST:
1556 if (MONO_TYPE_IS_REFERENCE (type))
1557 args [a_index].data.p = params [i];
1558 else
1559 args [a_index].data.vt = params [i];
1560 break;
1561 default:
1562 printf ("%s\n", mono_type_full_name (sig->params [i]));
1563 NOT_IMPLEMENTED;
1564 break;
1568 init_frame (&frame, NULL, data->rmethod, args, &result);
1569 context->managed_code = 1;
1571 type = rmethod->rtype;
1572 switch (type->type) {
1573 case MONO_TYPE_GENERICINST:
1574 if (!MONO_TYPE_IS_REFERENCE (type))
1575 frame.retval->data.vt = data->res;
1576 break;
1577 case MONO_TYPE_VALUETYPE:
1578 frame.retval->data.vt = data->res;
1579 break;
1580 default:
1581 break;
1584 ves_exec_method_with_context (&frame, context, NULL, NULL, -1);
1585 context->managed_code = 0;
1586 if (context == &context_struct)
1587 mono_native_tls_set_value (thread_context_id, NULL);
1588 else
1589 context->current_frame = old_frame;
1591 // FIXME:
1592 g_assert (frame.ex == NULL);
1594 type = rmethod->rtype;
1595 switch (type->type) {
1596 case MONO_TYPE_VOID:
1597 break;
1598 case MONO_TYPE_I1:
1599 *(gint8*)data->res = frame.retval->data.i;
1600 break;
1601 case MONO_TYPE_U1:
1602 *(guint8*)data->res = frame.retval->data.i;
1603 break;
1604 case MONO_TYPE_I2:
1605 *(gint16*)data->res = frame.retval->data.i;
1606 break;
1607 case MONO_TYPE_U2:
1608 *(guint16*)data->res = frame.retval->data.i;
1609 break;
1610 case MONO_TYPE_I4:
1611 *(gint32*)data->res = frame.retval->data.i;
1612 break;
1613 case MONO_TYPE_U4:
1614 *(guint64*)data->res = frame.retval->data.i;
1615 break;
1616 case MONO_TYPE_I8:
1617 *(gint64*)data->res = frame.retval->data.i;
1618 break;
1619 case MONO_TYPE_U8:
1620 *(guint64*)data->res = frame.retval->data.i;
1621 break;
1622 case MONO_TYPE_I:
1623 #if SIZEOF_VOID_P == 8
1624 *(gint64*)data->res = (gint64)frame.retval->data.p;
1625 #else
1626 *(gint32*)data->res = (gint32)frame.retval->data.p;
1627 #endif
1628 break;
1629 case MONO_TYPE_U:
1630 #if SIZEOF_VOID_P == 8
1631 *(guint64*)data->res = (guint64)frame.retval->data.p;
1632 #else
1633 *(guint32*)data->res = (guint32)frame.retval->data.p;
1634 #endif
1635 break;
1636 case MONO_TYPE_OBJECT:
1637 /* No need for a write barrier */
1638 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1639 break;
1640 case MONO_TYPE_GENERICINST:
1641 if (MONO_TYPE_IS_REFERENCE (type)) {
1642 *(MonoObject**)data->res = *(MonoObject**)frame.retval->data.p;
1643 } else {
1644 /* Already set before the call */
1646 break;
1647 case MONO_TYPE_VALUETYPE:
1648 /* Already set before the call */
1649 break;
1650 default:
1651 printf ("%s\n", mono_type_full_name (sig->ret));
1652 NOT_IMPLEMENTED;
1653 break;
1657 static stackval *
1658 do_icall (ThreadContext *context, int op, stackval *sp, gpointer ptr)
1660 MonoInvocation *old_frame = context->current_frame;
1661 MonoInvocation *old_env_frame = context->env_frame;
1662 jmp_buf *old_env = context->current_env;
1663 jmp_buf env;
1665 if (setjmp (env)) {
1666 context->current_frame = old_frame;
1667 context->env_frame = old_env_frame;
1668 context->current_env = old_env;
1669 context->managed_code = 1;
1670 return sp;
1673 context->env_frame = context->current_frame;
1674 context->current_env = &env;
1675 context->managed_code = 0;
1677 switch (op) {
1678 case MINT_ICALL_V_V: {
1679 void (*func)(void) = ptr;
1680 func ();
1681 break;
1683 case MINT_ICALL_V_P: {
1684 gpointer (*func)(void) = ptr;
1685 sp++;
1686 sp [-1].data.p = func ();
1687 break;
1689 case MINT_ICALL_P_V: {
1690 void (*func)(gpointer) = ptr;
1691 func (sp [-1].data.p);
1692 sp --;
1693 break;
1695 case MINT_ICALL_P_P: {
1696 gpointer (*func)(gpointer) = ptr;
1697 sp [-1].data.p = func (sp [-1].data.p);
1698 break;
1700 case MINT_ICALL_PP_V: {
1701 void (*func)(gpointer,gpointer) = ptr;
1702 sp -= 2;
1703 func (sp [0].data.p, sp [1].data.p);
1704 break;
1706 case MINT_ICALL_PI_V: {
1707 void (*func)(gpointer,int) = ptr;
1708 sp -= 2;
1709 func (sp [0].data.p, sp [1].data.i);
1710 break;
1712 case MINT_ICALL_PP_P: {
1713 gpointer (*func)(gpointer,gpointer) = ptr;
1714 --sp;
1715 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p);
1716 break;
1718 case MINT_ICALL_PI_P: {
1719 gpointer (*func)(gpointer,int) = ptr;
1720 --sp;
1721 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.i);
1722 break;
1724 case MINT_ICALL_PPP_V: {
1725 void (*func)(gpointer,gpointer,gpointer) = ptr;
1726 sp -= 3;
1727 func (sp [0].data.p, sp [1].data.p, sp [2].data.p);
1728 break;
1730 case MINT_ICALL_PPI_V: {
1731 void (*func)(gpointer,gpointer,int) = ptr;
1732 sp -= 3;
1733 func (sp [0].data.p, sp [1].data.p, sp [2].data.i);
1734 break;
1736 default:
1737 g_assert_not_reached ();
1740 context->env_frame = old_env_frame;
1741 context->current_env = old_env;
1743 return sp;
1747 * These functions are the entry points into the interpreter from compiled code.
1748 * They are called by the interp_in wrappers. They have the following signature:
1749 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
1750 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
1751 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
1752 * more wrappers then these functions.
1753 * this/static * ret/void * 16 arguments -> 64 functions.
1756 #define MAX_INTERP_ENTRY_ARGS 8
1758 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
1759 InterpEntryData data; \
1760 (data).rmethod = (_method); \
1761 (data).res = (_res); \
1762 (data).this_arg = (_this_arg); \
1763 (data).many_args = NULL;
1765 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
1766 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1767 interp_entry (&data); \
1769 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
1770 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1771 (data).args [0] = arg1; \
1772 interp_entry (&data); \
1774 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
1775 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1776 (data).args [0] = arg1; \
1777 (data).args [1] = arg2; \
1778 interp_entry (&data); \
1780 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
1781 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1782 (data).args [0] = arg1; \
1783 (data).args [1] = arg2; \
1784 (data).args [2] = arg3; \
1785 interp_entry (&data); \
1787 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
1788 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1789 (data).args [0] = arg1; \
1790 (data).args [1] = arg2; \
1791 (data).args [2] = arg3; \
1792 (data).args [3] = arg4; \
1793 interp_entry (&data); \
1795 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
1796 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1797 (data).args [0] = arg1; \
1798 (data).args [1] = arg2; \
1799 (data).args [2] = arg3; \
1800 (data).args [3] = arg4; \
1801 (data).args [4] = arg5; \
1802 interp_entry (&data); \
1804 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
1805 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1806 (data).args [0] = arg1; \
1807 (data).args [1] = arg2; \
1808 (data).args [2] = arg3; \
1809 (data).args [3] = arg4; \
1810 (data).args [4] = arg5; \
1811 (data).args [5] = arg6; \
1812 interp_entry (&data); \
1814 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
1815 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1816 (data).args [0] = arg1; \
1817 (data).args [1] = arg2; \
1818 (data).args [2] = arg3; \
1819 (data).args [3] = arg4; \
1820 (data).args [4] = arg5; \
1821 (data).args [5] = arg6; \
1822 (data).args [6] = arg7; \
1823 interp_entry (&data); \
1825 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
1826 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1827 (data).args [0] = arg1; \
1828 (data).args [1] = arg2; \
1829 (data).args [2] = arg3; \
1830 (data).args [3] = arg4; \
1831 (data).args [4] = arg5; \
1832 (data).args [5] = arg6; \
1833 (data).args [6] = arg7; \
1834 (data).args [7] = arg8; \
1835 interp_entry (&data); \
1838 #define ARGLIST0 RuntimeMethod *rmethod
1839 #define ARGLIST1 gpointer arg1, RuntimeMethod *rmethod
1840 #define ARGLIST2 gpointer arg1, gpointer arg2, RuntimeMethod *rmethod
1841 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, RuntimeMethod *rmethod
1842 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, RuntimeMethod *rmethod
1843 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, RuntimeMethod *rmethod
1844 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, RuntimeMethod *rmethod
1845 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, RuntimeMethod *rmethod
1846 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, RuntimeMethod *rmethod
1848 static void interp_entry_static_0 (ARGLIST0) INTERP_ENTRY0 (NULL, NULL, rmethod)
1849 static void interp_entry_static_1 (ARGLIST1) INTERP_ENTRY1 (NULL, NULL, rmethod)
1850 static void interp_entry_static_2 (ARGLIST2) INTERP_ENTRY2 (NULL, NULL, rmethod)
1851 static void interp_entry_static_3 (ARGLIST3) INTERP_ENTRY3 (NULL, NULL, rmethod)
1852 static void interp_entry_static_4 (ARGLIST4) INTERP_ENTRY4 (NULL, NULL, rmethod)
1853 static void interp_entry_static_5 (ARGLIST5) INTERP_ENTRY5 (NULL, NULL, rmethod)
1854 static void interp_entry_static_6 (ARGLIST6) INTERP_ENTRY6 (NULL, NULL, rmethod)
1855 static void interp_entry_static_7 (ARGLIST7) INTERP_ENTRY7 (NULL, NULL, rmethod)
1856 static void interp_entry_static_8 (ARGLIST8) INTERP_ENTRY8 (NULL, NULL, rmethod)
1857 static void interp_entry_static_ret_0 (gpointer res, ARGLIST0) INTERP_ENTRY0 (NULL, res, rmethod)
1858 static void interp_entry_static_ret_1 (gpointer res, ARGLIST1) INTERP_ENTRY1 (NULL, res, rmethod)
1859 static void interp_entry_static_ret_2 (gpointer res, ARGLIST2) INTERP_ENTRY2 (NULL, res, rmethod)
1860 static void interp_entry_static_ret_3 (gpointer res, ARGLIST3) INTERP_ENTRY3 (NULL, res, rmethod)
1861 static void interp_entry_static_ret_4 (gpointer res, ARGLIST4) INTERP_ENTRY4 (NULL, res, rmethod)
1862 static void interp_entry_static_ret_5 (gpointer res, ARGLIST5) INTERP_ENTRY5 (NULL, res, rmethod)
1863 static void interp_entry_static_ret_6 (gpointer res, ARGLIST6) INTERP_ENTRY6 (NULL, res, rmethod)
1864 static void interp_entry_static_ret_7 (gpointer res, ARGLIST7) INTERP_ENTRY7 (NULL, res, rmethod)
1865 static void interp_entry_static_ret_8 (gpointer res, ARGLIST8) INTERP_ENTRY8 (NULL, res, rmethod)
1866 static void interp_entry_instance_0 (gpointer this_arg, ARGLIST0) INTERP_ENTRY0 (this_arg, NULL, rmethod)
1867 static void interp_entry_instance_1 (gpointer this_arg, ARGLIST1) INTERP_ENTRY1 (this_arg, NULL, rmethod)
1868 static void interp_entry_instance_2 (gpointer this_arg, ARGLIST2) INTERP_ENTRY2 (this_arg, NULL, rmethod)
1869 static void interp_entry_instance_3 (gpointer this_arg, ARGLIST3) INTERP_ENTRY3 (this_arg, NULL, rmethod)
1870 static void interp_entry_instance_4 (gpointer this_arg, ARGLIST4) INTERP_ENTRY4 (this_arg, NULL, rmethod)
1871 static void interp_entry_instance_5 (gpointer this_arg, ARGLIST5) INTERP_ENTRY5 (this_arg, NULL, rmethod)
1872 static void interp_entry_instance_6 (gpointer this_arg, ARGLIST6) INTERP_ENTRY6 (this_arg, NULL, rmethod)
1873 static void interp_entry_instance_7 (gpointer this_arg, ARGLIST7) INTERP_ENTRY7 (this_arg, NULL, rmethod)
1874 static void interp_entry_instance_8 (gpointer this_arg, ARGLIST8) INTERP_ENTRY8 (this_arg, NULL, rmethod)
1875 static void interp_entry_instance_ret_0 (gpointer this_arg, gpointer res, ARGLIST0) INTERP_ENTRY0 (this_arg, res, rmethod)
1876 static void interp_entry_instance_ret_1 (gpointer this_arg, gpointer res, ARGLIST1) INTERP_ENTRY1 (this_arg, res, rmethod)
1877 static void interp_entry_instance_ret_2 (gpointer this_arg, gpointer res, ARGLIST2) INTERP_ENTRY2 (this_arg, res, rmethod)
1878 static void interp_entry_instance_ret_3 (gpointer this_arg, gpointer res, ARGLIST3) INTERP_ENTRY3 (this_arg, res, rmethod)
1879 static void interp_entry_instance_ret_4 (gpointer this_arg, gpointer res, ARGLIST4) INTERP_ENTRY4 (this_arg, res, rmethod)
1880 static void interp_entry_instance_ret_5 (gpointer this_arg, gpointer res, ARGLIST5) INTERP_ENTRY5 (this_arg, res, rmethod)
1881 static void interp_entry_instance_ret_6 (gpointer this_arg, gpointer res, ARGLIST6) INTERP_ENTRY6 (this_arg, res, rmethod)
1882 static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY6 (this_arg, res, rmethod)
1883 static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY6 (this_arg, res, rmethod)
1885 #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
1887 gpointer entry_funcs_static [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static) };
1888 gpointer entry_funcs_static_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static_ret) };
1889 gpointer entry_funcs_instance [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance) };
1890 gpointer entry_funcs_instance_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance_ret) };
1892 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
1893 static void
1894 interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
1896 INTERP_ENTRY_BASE (rmethod, this_arg, res);
1897 data.many_args = args;
1898 interp_entry (&data);
1902 * mono_interp_create_method_pointer:
1904 * Return a function pointer which can be used to call METHOD using the
1905 * interpreter. Return NULL for methods which are not supported.
1907 gpointer
1908 mono_interp_create_method_pointer (MonoMethod *method, MonoError *error)
1910 gpointer addr;
1911 MonoMethodSignature *sig = mono_method_signature (method);
1912 MonoMethod *wrapper;
1913 RuntimeMethod *rmethod;
1915 /* HACK: method_ptr of delegate should point to a runtime method*/
1916 if (method->wrapper_type && method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
1917 return mono_interp_get_runtime_method (mono_domain_get (), method, error);
1919 rmethod = mono_interp_get_runtime_method (mono_domain_get (), method, error);
1920 if (rmethod->jit_entry)
1921 return rmethod->jit_entry;
1922 wrapper = mini_get_interp_in_wrapper (sig);
1924 gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
1925 mono_error_assert_ok (error);
1927 //printf ("%s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
1928 gpointer entry_func;
1929 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
1930 entry_func = interp_entry_general;
1931 } else if (sig->hasthis) {
1932 if (sig->ret->type == MONO_TYPE_VOID)
1933 entry_func = entry_funcs_instance [sig->param_count];
1934 else
1935 entry_func = entry_funcs_instance_ret [sig->param_count];
1936 } else {
1937 if (sig->ret->type == MONO_TYPE_VOID)
1938 entry_func = entry_funcs_static [sig->param_count];
1939 else
1940 entry_func = entry_funcs_static_ret [sig->param_count];
1942 g_assert (entry_func);
1944 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
1945 MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
1946 ftndesc->addr = entry_func;
1947 ftndesc->arg = rmethod;
1948 mono_error_assert_ok (error);
1951 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
1952 * rgctx register using a trampoline.
1955 // FIXME: AOT
1956 g_assert (!mono_aot_only);
1957 addr = mono_arch_get_static_rgctx_trampoline (ftndesc, jit_wrapper);
1959 mono_memory_barrier ();
1960 rmethod->jit_entry = addr;
1962 return addr;
1965 #if COUNT_OPS
1966 static int opcode_counts[512];
1968 #define COUNT_OP(op) opcode_counts[op]++
1969 #else
1970 #define COUNT_OP(op)
1971 #endif
1973 #if DEBUG_INTERP
1974 #define DUMP_INSTR() \
1975 if (tracing > 1) { \
1976 char *ins; \
1977 if (sp > frame->stack) { \
1978 ins = dump_stack (frame->stack, sp); \
1979 } else { \
1980 ins = g_strdup (""); \
1982 sp->data.l = 0; \
1983 output_indent (); \
1984 char *mn = mono_method_full_name (frame->runtime_method->method, FALSE); \
1985 g_print ("(%p) %s -> ", mono_thread_internal_current (), mn); \
1986 g_free (mn); \
1987 mono_interp_dis_mintop(rtm->code, ip); \
1988 g_print ("\t%d:%s\n", vt_sp - vtalloc, ins); \
1989 g_free (ins); \
1991 #else
1992 #define DUMP_INSTR()
1993 #endif
1995 #ifdef __GNUC__
1996 #define USE_COMPUTED_GOTO 1
1997 #endif
1998 #if USE_COMPUTED_GOTO
1999 #define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op];
2000 #define MINT_IN_CASE(x) LAB_ ## x:
2001 #if DEBUG_INTERP
2002 #define MINT_IN_BREAK if (tracing > 1) goto main_loop; else { COUNT_OP(*ip); goto *in_labels[*ip]; }
2003 #else
2004 #define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; }
2005 #endif
2006 #define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
2007 #else
2008 #define MINT_IN_SWITCH(op) switch (op)
2009 #define MINT_IN_CASE(x) case x:
2010 #define MINT_IN_BREAK break
2011 #define MINT_IN_DEFAULT default:
2012 #endif
2015 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
2017 static void
2018 ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception, int exit_at_finally)
2020 MonoInvocation child_frame;
2021 GSList *finally_ips = NULL;
2022 const unsigned short *endfinally_ip = NULL;
2023 const unsigned short *ip = NULL;
2024 register stackval *sp;
2025 RuntimeMethod *rtm;
2026 #if DEBUG_INTERP
2027 gint tracing = global_tracing;
2028 unsigned char *vtalloc;
2029 #else
2030 gint tracing = 0;
2031 #endif
2032 int i32;
2033 unsigned char *vt_sp;
2034 unsigned char *locals;
2035 MonoError error;
2036 MonoObject *o = NULL;
2037 MonoClass *c;
2038 #if USE_COMPUTED_GOTO
2039 static void *in_labels[] = {
2040 #define OPDEF(a,b,c,d) \
2041 &&LAB_ ## a,
2042 #include "mintops.def"
2043 0 };
2044 #endif
2046 frame->ex = NULL;
2047 frame->ex_handler = NULL;
2048 frame->ip = NULL;
2049 context->current_frame = frame;
2051 debug_enter (frame, &tracing);
2053 if (!frame->runtime_method->transformed) {
2054 context->managed_code = 0;
2055 #if DEBUG_INTERP
2056 char *mn = mono_method_full_name (frame->runtime_method->method, TRUE);
2057 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
2058 g_free (mn);
2059 #endif
2060 frame->ex = mono_interp_transform_method (frame->runtime_method, context);
2061 context->managed_code = 1;
2062 if (frame->ex) {
2063 rtm = NULL;
2064 ip = NULL;
2065 goto exit_frame;
2069 rtm = frame->runtime_method;
2070 if (!start_with_ip ) {
2071 frame->args = alloca (rtm->alloca_size);
2072 memset (frame->args, 0, rtm->alloca_size);
2074 ip = rtm->code;
2075 } else {
2076 ip = start_with_ip;
2078 sp = frame->stack = (stackval *) ((char *) frame->args + rtm->args_size);
2079 vt_sp = (unsigned char *) sp + rtm->stack_size;
2080 #if DEBUG_INTERP
2081 vtalloc = vt_sp;
2082 #endif
2083 locals = (unsigned char *) vt_sp + rtm->vt_stack_size;
2084 child_frame.parent = frame;
2086 if (filter_exception) {
2087 sp->data.p = filter_exception;
2088 sp++;
2092 * using while (ip < end) may result in a 15% performance drop,
2093 * but it may be useful for debug
2095 while (1) {
2096 main_loop:
2097 /* g_assert (sp >= frame->stack); */
2098 /* g_assert(vt_sp - vtalloc <= rtm->vt_stack_size); */
2099 DUMP_INSTR();
2100 MINT_IN_SWITCH (*ip) {
2101 MINT_IN_CASE(MINT_INITLOCALS)
2102 memset (locals, 0, rtm->locals_size);
2103 ++ip;
2104 MINT_IN_BREAK;
2105 MINT_IN_CASE(MINT_NOP)
2106 ++ip;
2107 MINT_IN_BREAK;
2108 MINT_IN_CASE(MINT_BREAK)
2109 ++ip;
2110 G_BREAKPOINT (); /* this is not portable... */
2111 MINT_IN_BREAK;
2112 MINT_IN_CASE(MINT_LDNULL)
2113 sp->data.p = NULL;
2114 ++ip;
2115 ++sp;
2116 MINT_IN_BREAK;
2117 MINT_IN_CASE(MINT_VTRESULT) {
2118 int ret_size = * (guint16 *)(ip + 1);
2119 unsigned char *ret_vt_sp = vt_sp;
2120 vt_sp -= READ32(ip + 2);
2121 if (ret_size > 0) {
2122 memmove (vt_sp, ret_vt_sp, ret_size);
2123 sp [-1].data.p = vt_sp;
2124 vt_sp += (ret_size + 7) & ~7;
2126 ip += 4;
2127 MINT_IN_BREAK;
2129 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
2130 MINT_IN_CASE(MINT_LDC_I4_M1)
2131 LDC(-1);
2132 MINT_IN_BREAK;
2133 MINT_IN_CASE(MINT_LDC_I4_0)
2134 LDC(0);
2135 MINT_IN_BREAK;
2136 MINT_IN_CASE(MINT_LDC_I4_1)
2137 LDC(1);
2138 MINT_IN_BREAK;
2139 MINT_IN_CASE(MINT_LDC_I4_2)
2140 LDC(2);
2141 MINT_IN_BREAK;
2142 MINT_IN_CASE(MINT_LDC_I4_3)
2143 LDC(3);
2144 MINT_IN_BREAK;
2145 MINT_IN_CASE(MINT_LDC_I4_4)
2146 LDC(4);
2147 MINT_IN_BREAK;
2148 MINT_IN_CASE(MINT_LDC_I4_5)
2149 LDC(5);
2150 MINT_IN_BREAK;
2151 MINT_IN_CASE(MINT_LDC_I4_6)
2152 LDC(6);
2153 MINT_IN_BREAK;
2154 MINT_IN_CASE(MINT_LDC_I4_7)
2155 LDC(7);
2156 MINT_IN_BREAK;
2157 MINT_IN_CASE(MINT_LDC_I4_8)
2158 LDC(8);
2159 MINT_IN_BREAK;
2160 MINT_IN_CASE(MINT_LDC_I4_S)
2161 sp->data.i = *(const short *)(ip + 1);
2162 ip += 2;
2163 ++sp;
2164 MINT_IN_BREAK;
2165 MINT_IN_CASE(MINT_LDC_I4)
2166 ++ip;
2167 sp->data.i = READ32 (ip);
2168 ip += 2;
2169 ++sp;
2170 MINT_IN_BREAK;
2171 MINT_IN_CASE(MINT_LDC_I8)
2172 ++ip;
2173 sp->data.l = READ64 (ip);
2174 ip += 4;
2175 ++sp;
2176 MINT_IN_BREAK;
2177 MINT_IN_CASE(MINT_LDC_R4) {
2178 guint32 val;
2179 ++ip;
2180 val = READ32(ip);
2181 sp->data.f = * (float *)&val;
2182 ip += 2;
2183 ++sp;
2184 MINT_IN_BREAK;
2186 MINT_IN_CASE(MINT_LDC_R8)
2187 sp->data.l = READ64 (ip + 1); /* note union usage */
2188 ip += 5;
2189 ++sp;
2190 MINT_IN_BREAK;
2191 MINT_IN_CASE(MINT_DUP)
2192 sp [0] = sp[-1];
2193 ++sp;
2194 ++ip;
2195 MINT_IN_BREAK;
2196 MINT_IN_CASE(MINT_DUP_VT)
2197 i32 = READ32 (ip + 1);
2198 sp->data.p = vt_sp;
2199 memcpy(sp->data.p, sp [-1].data.p, i32);
2200 vt_sp += (i32 + 7) & ~7;
2201 ++sp;
2202 ip += 3;
2203 MINT_IN_BREAK;
2204 MINT_IN_CASE(MINT_POP) {
2205 guint16 u16 = (* (guint16 *)(ip + 1)) + 1;
2206 if (u16 > 1)
2207 memmove (sp - u16, sp - 1, (u16 - 1) * sizeof (stackval));
2208 sp--;
2209 ip += 2;
2210 MINT_IN_BREAK;
2212 MINT_IN_CASE(MINT_JMP) {
2213 RuntimeMethod *new_method = rtm->data_items [* (guint16 *)(ip + 1)];
2214 if (!new_method->transformed) {
2215 frame->ip = ip;
2216 frame->ex = mono_interp_transform_method (new_method, context);
2217 if (frame->ex)
2218 goto exit_frame;
2220 ip += 2;
2221 if (new_method->alloca_size > rtm->alloca_size)
2222 g_error ("MINT_JMP to method which needs more stack space (%d > %d)", new_method->alloca_size, rtm->alloca_size);
2223 rtm = frame->runtime_method = new_method;
2224 vt_sp = (unsigned char *) sp + rtm->stack_size;
2225 #if DEBUG_INTERP
2226 vtalloc = vt_sp;
2227 #endif
2228 locals = vt_sp + rtm->vt_stack_size;
2229 ip = rtm->new_body_start; /* bypass storing input args from callers frame */
2230 MINT_IN_BREAK;
2232 MINT_IN_CASE(MINT_CALLI) {
2233 MonoMethodSignature *csignature;
2234 stackval *endsp = sp;
2236 frame->ip = ip;
2238 csignature = rtm->data_items [* (guint16 *)(ip + 1)];
2239 ip += 2;
2240 --sp;
2241 --endsp;
2242 child_frame.runtime_method = sp->data.p;
2244 sp->data.p = vt_sp;
2245 child_frame.retval = sp;
2246 /* decrement by the actual number of args */
2247 sp -= csignature->param_count;
2248 if (csignature->hasthis)
2249 --sp;
2250 child_frame.stack_args = sp;
2252 /* `this' can be NULL for string:.ctor */
2253 if (csignature->hasthis && sp->data.p && mono_object_is_transparent_proxy (sp->data.p)) {
2254 child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error);
2255 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
2256 } else if (child_frame.runtime_method->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2257 child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_native_wrapper (child_frame.runtime_method->method, FALSE, FALSE), &error);
2258 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
2261 if (csignature->hasthis) {
2262 MonoObject *this_arg = sp->data.p;
2264 if (this_arg->vtable->klass->valuetype) {
2265 gpointer *unboxed = mono_object_unbox (this_arg);
2266 sp [0].data.p = unboxed;
2270 ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
2272 context->current_frame = frame;
2274 if (context->has_resume_state) {
2275 if (frame == context->handler_frame)
2276 SET_RESUME_STATE (context);
2277 else
2278 goto exit_frame;
2281 if (child_frame.ex) {
2283 * An exception occurred, need to run finally, fault and catch handlers..
2285 frame->ex = child_frame.ex;
2286 goto handle_finally;
2289 /* need to handle typedbyref ... */
2290 if (csignature->ret->type != MONO_TYPE_VOID) {
2291 *sp = *endsp;
2292 sp++;
2294 MINT_IN_BREAK;
2296 MINT_IN_CASE(MINT_CALLI_NAT) {
2297 MonoMethodSignature *csignature;
2298 stackval *endsp = sp;
2299 unsigned char *code = NULL;
2301 frame->ip = ip;
2303 csignature = rtm->data_items [* (guint16 *)(ip + 1)];
2304 ip += 2;
2305 --sp;
2306 --endsp;
2307 code = sp->data.p;
2308 child_frame.runtime_method = NULL;
2310 sp->data.p = vt_sp;
2311 child_frame.retval = sp;
2312 /* decrement by the actual number of args */
2313 sp -= csignature->param_count;
2314 if (csignature->hasthis)
2315 --sp;
2316 child_frame.stack_args = sp;
2317 ves_pinvoke_method (&child_frame, csignature, (MonoFuncV) code, FALSE, context);
2319 context->current_frame = frame;
2321 if (context->has_resume_state) {
2322 if (frame == context->handler_frame)
2323 SET_RESUME_STATE (context);
2324 else
2325 goto exit_frame;
2328 if (child_frame.ex) {
2330 * An exception occurred, need to run finally, fault and catch handlers..
2332 frame->ex = child_frame.ex;
2333 if (context->search_for_handler) {
2334 context->search_for_handler = 0;
2335 goto handle_exception;
2337 goto handle_finally;
2340 /* need to handle typedbyref ... */
2341 if (csignature->ret->type != MONO_TYPE_VOID) {
2342 *sp = *endsp;
2343 sp++;
2345 MINT_IN_BREAK;
2347 MINT_IN_CASE(MINT_CALL) {
2348 stackval *endsp = sp;
2350 frame->ip = ip;
2352 child_frame.runtime_method = rtm->data_items [* (guint16 *)(ip + 1)];
2353 ip += 2;
2354 sp->data.p = vt_sp;
2355 child_frame.retval = sp;
2356 /* decrement by the actual number of args */
2357 sp -= child_frame.runtime_method->param_count;
2358 if (child_frame.runtime_method->hasthis)
2359 --sp;
2360 child_frame.stack_args = sp;
2362 /* `this' can be NULL for string:.ctor */
2363 if (child_frame.runtime_method->hasthis && !child_frame.runtime_method->method->klass->valuetype && sp->data.p && mono_object_is_transparent_proxy (sp->data.p)) {
2364 child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error);
2365 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
2368 ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
2370 context->current_frame = frame;
2372 if (context->has_resume_state) {
2373 if (frame == context->handler_frame)
2374 SET_RESUME_STATE (context);
2375 else
2376 goto exit_frame;
2379 if (child_frame.ex) {
2381 * An exception occurred, need to run finally, fault and catch handlers..
2383 frame->ex = child_frame.ex;
2384 goto handle_exception;;
2387 /* need to handle typedbyref ... */
2388 *sp = *endsp;
2389 sp++;
2390 MINT_IN_BREAK;
2392 MINT_IN_CASE(MINT_VCALL) {
2393 frame->ip = ip;
2395 child_frame.runtime_method = rtm->data_items [* (guint16 *)(ip + 1)];
2396 ip += 2;
2398 sp->data.p = vt_sp;
2399 child_frame.retval = sp;
2400 /* decrement by the actual number of args */
2401 sp -= child_frame.runtime_method->param_count;
2402 if (child_frame.runtime_method->hasthis) {
2403 --sp;
2404 MonoObject *this_arg = sp->data.p;
2405 if (!this_arg)
2406 THROW_EX (mono_get_exception_null_reference(), ip - 2);
2408 child_frame.stack_args = sp;
2410 if (child_frame.runtime_method->hasthis && !child_frame.runtime_method->method->klass->valuetype && mono_object_is_transparent_proxy (sp->data.p)) {
2411 child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error);
2412 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
2415 ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
2417 context->current_frame = frame;
2419 if (context->has_resume_state) {
2420 if (frame == context->handler_frame)
2421 SET_RESUME_STATE (context);
2422 else
2423 goto exit_frame;
2426 if (child_frame.ex) {
2428 * An exception occurred, need to run finally, fault and catch handlers..
2430 frame->ex = child_frame.ex;
2431 goto handle_finally;
2433 MINT_IN_BREAK;
2436 MINT_IN_CASE(MINT_JIT_CALL) {
2437 MonoMethodSignature *sig;
2438 RuntimeMethod *rmethod = rtm->data_items [* (guint16 *)(ip + 1)];
2439 MonoFtnDesc ftndesc;
2440 guint8 res_buf [256];
2441 MonoType *type;
2442 MonoLMFExt ext;
2444 //printf ("%s\n", mono_method_full_name (rmethod->method, 1));
2447 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2448 * by ref and return a return value using an explicit return value argument.
2450 if (!rmethod->jit_wrapper) {
2451 MonoMethod *method = rmethod->method;
2452 MonoError error;
2454 sig = mono_method_signature (method);
2455 g_assert (sig);
2457 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2458 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2460 gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, &error);
2461 mono_error_assert_ok (&error);
2463 gpointer addr = mono_jit_compile_method_jit_only (method, &error);
2464 g_assert (addr);
2465 mono_error_assert_ok (&error);
2467 rmethod->jit_addr = addr;
2468 rmethod->jit_sig = sig;
2469 mono_memory_barrier ();
2470 rmethod->jit_wrapper = jit_wrapper;
2472 } else {
2473 sig = rmethod->jit_sig;
2476 frame->ip = ip;
2477 ip += 2;
2478 sp -= sig->param_count;
2479 if (sig->hasthis)
2480 --sp;
2482 ftndesc.addr = rmethod->jit_addr;
2483 ftndesc.arg = NULL;
2485 // FIXME: Optimize this
2487 gpointer args [32];
2488 int pindex = 0;
2489 int stack_index = 0;
2490 if (rmethod->hasthis) {
2491 args [pindex ++] = sp [0].data.p;
2492 stack_index ++;
2494 type = rmethod->rtype;
2495 if (type->type != MONO_TYPE_VOID) {
2496 if (MONO_TYPE_ISSTRUCT (type))
2497 args [pindex ++] = vt_sp;
2498 else
2499 args [pindex ++] = res_buf;
2501 for (int i = 0; i < rmethod->param_count; ++i) {
2502 MonoType *t = rmethod->param_types [i];
2503 stackval *sval = &sp [stack_index + i];
2504 if (sig->params [i]->byref) {
2505 args [pindex ++] = sval->data.p;
2506 } else if (MONO_TYPE_ISSTRUCT (t)) {
2507 args [pindex ++] = sval->data.p;
2508 } else if (MONO_TYPE_IS_REFERENCE (t)) {
2509 args [pindex ++] = &sval->data.p;
2510 } else {
2511 switch (t->type) {
2512 case MONO_TYPE_I1:
2513 case MONO_TYPE_U1:
2514 case MONO_TYPE_I2:
2515 case MONO_TYPE_U2:
2516 case MONO_TYPE_I4:
2517 case MONO_TYPE_U4:
2518 case MONO_TYPE_VALUETYPE:
2519 args [pindex ++] = &sval->data.i;
2520 break;
2521 case MONO_TYPE_PTR:
2522 case MONO_TYPE_FNPTR:
2523 case MONO_TYPE_I:
2524 case MONO_TYPE_U:
2525 case MONO_TYPE_OBJECT:
2526 args [pindex ++] = &sval->data.p;
2527 break;
2528 case MONO_TYPE_I8:
2529 case MONO_TYPE_U8:
2530 args [pindex ++] = &sval->data.l;
2531 break;
2532 default:
2533 printf ("%s\n", mono_type_full_name (t));
2534 g_assert_not_reached ();
2540 * Push an LMF frame on the LMF stack
2541 * to mark the transition to compiled code.
2543 memset (&ext, 0, sizeof (ext));
2544 ext.interp_exit = TRUE;
2545 ext.interp_exit_data = frame;
2547 mono_push_lmf (&ext);
2549 switch (pindex) {
2550 case 0: {
2551 void (*func)(gpointer) = rmethod->jit_wrapper;
2553 func (&ftndesc);
2554 break;
2556 case 1: {
2557 void (*func)(gpointer, gpointer) = rmethod->jit_wrapper;
2559 func (args [0], &ftndesc);
2560 break;
2562 case 2: {
2563 void (*func)(gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
2565 func (args [0], args [1], &ftndesc);
2566 break;
2568 case 3: {
2569 void (*func)(gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
2571 func (args [0], args [1], args [2], &ftndesc);
2572 break;
2574 case 4: {
2575 void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
2577 func (args [0], args [1], args [2], args [3], &ftndesc);
2578 break;
2580 case 5: {
2581 void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
2583 func (args [0], args [1], args [2], args [3], args [4], &ftndesc);
2584 break;
2586 case 6: {
2587 void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
2589 func (args [0], args [1], args [2], args [3], args [4], args [5], &ftndesc);
2590 break;
2592 case 7: {
2593 void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
2595 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], &ftndesc);
2596 break;
2598 default:
2599 g_assert_not_reached ();
2600 break;
2603 mono_pop_lmf (&ext.lmf);
2605 if (context->has_resume_state) {
2607 * If this bit is set, it means the call has thrown the exception, and we
2608 * reached this point because the EH code in mono_handle_exception ()
2609 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
2610 * has set the fields in context to indicate where we have to resume execution.
2612 if (frame == context->handler_frame)
2613 SET_RESUME_STATE (context);
2614 else
2615 goto exit_frame;
2618 MonoType *rtype = rmethod->rtype;
2619 switch (rtype->type) {
2620 case MONO_TYPE_VOID:
2621 case MONO_TYPE_OBJECT:
2622 case MONO_TYPE_STRING:
2623 case MONO_TYPE_CLASS:
2624 case MONO_TYPE_ARRAY:
2625 case MONO_TYPE_SZARRAY:
2626 case MONO_TYPE_I:
2627 case MONO_TYPE_U:
2628 sp->data.p = *(gpointer*)res_buf;
2629 break;
2630 case MONO_TYPE_I1:
2631 sp->data.i = *(gint8*)res_buf;
2632 break;
2633 case MONO_TYPE_U1:
2634 sp->data.i = *(guint8*)res_buf;
2635 break;
2636 case MONO_TYPE_I2:
2637 sp->data.i = *(gint16*)res_buf;
2638 break;
2639 case MONO_TYPE_U2:
2640 sp->data.i = *(guint16*)res_buf;
2641 break;
2642 case MONO_TYPE_I4:
2643 sp->data.i = *(gint32*)res_buf;
2644 break;
2645 case MONO_TYPE_U4:
2646 sp->data.i = *(guint32*)res_buf;
2647 break;
2648 case MONO_TYPE_VALUETYPE:
2649 /* The result was written to vt_sp */
2650 sp->data.p = vt_sp;
2651 break;
2652 case MONO_TYPE_GENERICINST:
2653 if (MONO_TYPE_IS_REFERENCE (rtype)) {
2654 sp->data.p = *(gpointer*)res_buf;
2655 } else {
2656 /* The result was written to vt_sp */
2657 sp->data.p = vt_sp;
2659 break;
2660 default:
2661 printf ("%s\n", mono_type_full_name (rtype));
2662 g_assert_not_reached ();
2663 break;
2665 if (rtype->type != MONO_TYPE_VOID)
2666 sp++;
2667 MINT_IN_BREAK;
2670 MINT_IN_CASE(MINT_CALLVIRT) {
2671 stackval *endsp = sp;
2672 MonoObject *this_arg;
2673 guint32 token;
2675 frame->ip = ip;
2677 token = * (unsigned short *)(ip + 1);
2678 ip += 2;
2679 child_frame.runtime_method = rtm->data_items [token];
2680 sp->data.p = vt_sp;
2681 child_frame.retval = sp;
2683 /* decrement by the actual number of args */
2684 sp -= child_frame.runtime_method->param_count + 1;
2685 child_frame.stack_args = sp;
2686 this_arg = sp->data.p;
2687 if (!this_arg)
2688 THROW_EX (mono_get_exception_null_reference(), ip - 2);
2689 child_frame.runtime_method = get_virtual_method (context->domain, child_frame.runtime_method, this_arg);
2691 MonoClass *this_class = this_arg->vtable->klass;
2692 if (this_class->valuetype && child_frame.runtime_method->method->klass->valuetype) {
2693 /* unbox */
2694 gpointer *unboxed = mono_object_unbox (this_arg);
2695 sp [0].data.p = unboxed;
2698 ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
2700 context->current_frame = frame;
2702 if (context->has_resume_state) {
2703 if (frame == context->handler_frame)
2704 SET_RESUME_STATE (context);
2705 else
2706 goto exit_frame;
2709 if (child_frame.ex) {
2711 * An exception occurred, need to run finally, fault and catch handlers..
2713 frame->ex = child_frame.ex;
2714 if (context->search_for_handler) {
2715 context->search_for_handler = 0;
2716 goto handle_exception;
2718 goto handle_finally;
2721 /* need to handle typedbyref ... */
2722 *sp = *endsp;
2723 sp++;
2724 MINT_IN_BREAK;
2726 MINT_IN_CASE(MINT_VCALLVIRT) {
2727 MonoObject *this_arg;
2728 guint32 token;
2730 frame->ip = ip;
2732 token = * (unsigned short *)(ip + 1);
2733 ip += 2;
2734 child_frame.runtime_method = rtm->data_items [token];
2735 sp->data.p = vt_sp;
2736 child_frame.retval = sp;
2738 /* decrement by the actual number of args */
2739 sp -= child_frame.runtime_method->param_count + 1;
2740 child_frame.stack_args = sp;
2741 this_arg = sp->data.p;
2742 if (!this_arg)
2743 THROW_EX (mono_get_exception_null_reference(), ip - 2);
2744 child_frame.runtime_method = get_virtual_method (context->domain, child_frame.runtime_method, this_arg);
2746 MonoClass *this_class = this_arg->vtable->klass;
2747 if (this_class->valuetype && child_frame.runtime_method->method->klass->valuetype) {
2748 gpointer *unboxed = mono_object_unbox (this_arg);
2749 sp [0].data.p = unboxed;
2752 ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
2754 context->current_frame = frame;
2756 if (context->has_resume_state) {
2757 if (frame == context->handler_frame)
2758 SET_RESUME_STATE (context);
2759 else
2760 goto exit_frame;
2763 if (child_frame.ex) {
2765 * An exception occurred, need to run finally, fault and catch handlers..
2767 frame->ex = child_frame.ex;
2768 if (context->search_for_handler) {
2769 context->search_for_handler = 0;
2770 goto handle_exception;
2772 goto handle_finally;
2774 MINT_IN_BREAK;
2776 MINT_IN_CASE(MINT_CALLRUN)
2777 ves_runtime_method (frame, context);
2778 if (frame->ex) {
2779 rtm = NULL;
2780 goto handle_exception;
2782 goto exit_frame;
2783 MINT_IN_CASE(MINT_RET)
2784 --sp;
2785 *frame->retval = *sp;
2786 if (sp > frame->stack)
2787 g_warning ("ret: more values on stack: %d", sp-frame->stack);
2788 goto exit_frame;
2789 MINT_IN_CASE(MINT_RET_VOID)
2790 if (sp > frame->stack)
2791 g_warning ("ret.void: more values on stack: %d", sp-frame->stack);
2792 goto exit_frame;
2793 MINT_IN_CASE(MINT_RET_VT)
2794 i32 = READ32(ip + 1);
2795 --sp;
2796 memcpy(frame->retval->data.p, sp->data.p, i32);
2797 if (sp > frame->stack)
2798 g_warning ("ret.vt: more values on stack: %d", sp-frame->stack);
2799 goto exit_frame;
2800 MINT_IN_CASE(MINT_BR_S)
2801 ip += (short) *(ip + 1);
2802 MINT_IN_BREAK;
2803 MINT_IN_CASE(MINT_BR)
2804 ip += (gint32) READ32(ip + 1);
2805 MINT_IN_BREAK;
2806 #define ZEROP_S(datamem, op) \
2807 --sp; \
2808 if (sp->data.datamem op 0) \
2809 ip += * (gint16 *)(ip + 1); \
2810 else \
2811 ip += 2;
2813 #define ZEROP(datamem, op) \
2814 --sp; \
2815 if (sp->data.datamem op 0) \
2816 ip += READ32(ip + 1); \
2817 else \
2818 ip += 3;
2820 MINT_IN_CASE(MINT_BRFALSE_I4_S)
2821 ZEROP_S(i, ==);
2822 MINT_IN_BREAK;
2823 MINT_IN_CASE(MINT_BRFALSE_I8_S)
2824 ZEROP_S(l, ==);
2825 MINT_IN_BREAK;
2826 MINT_IN_CASE(MINT_BRFALSE_R8_S)
2827 ZEROP_S(f, ==);
2828 MINT_IN_BREAK;
2829 MINT_IN_CASE(MINT_BRFALSE_I4)
2830 ZEROP(i, ==);
2831 MINT_IN_BREAK;
2832 MINT_IN_CASE(MINT_BRFALSE_I8)
2833 ZEROP(l, ==);
2834 MINT_IN_BREAK;
2835 MINT_IN_CASE(MINT_BRFALSE_R8)
2836 ZEROP_S(f, ==);
2837 MINT_IN_BREAK;
2838 MINT_IN_CASE(MINT_BRTRUE_I4_S)
2839 ZEROP_S(i, !=);
2840 MINT_IN_BREAK;
2841 MINT_IN_CASE(MINT_BRTRUE_I8_S)
2842 ZEROP_S(l, !=);
2843 MINT_IN_BREAK;
2844 MINT_IN_CASE(MINT_BRTRUE_R8_S)
2845 ZEROP_S(f, !=);
2846 MINT_IN_BREAK;
2847 MINT_IN_CASE(MINT_BRTRUE_I4)
2848 ZEROP(i, !=);
2849 MINT_IN_BREAK;
2850 MINT_IN_CASE(MINT_BRTRUE_I8)
2851 ZEROP(l, !=);
2852 MINT_IN_BREAK;
2853 MINT_IN_CASE(MINT_BRTRUE_R8)
2854 ZEROP(f, !=);
2855 MINT_IN_BREAK;
2856 #define CONDBR_S(cond) \
2857 sp -= 2; \
2858 if (cond) \
2859 ip += * (gint16 *)(ip + 1); \
2860 else \
2861 ip += 2;
2862 #define BRELOP_S(datamem, op) \
2863 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
2865 #define CONDBR(cond) \
2866 sp -= 2; \
2867 if (cond) \
2868 ip += READ32(ip + 1); \
2869 else \
2870 ip += 3;
2872 #define BRELOP(datamem, op) \
2873 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
2875 MINT_IN_CASE(MINT_BEQ_I4_S)
2876 BRELOP_S(i, ==)
2877 MINT_IN_BREAK;
2878 MINT_IN_CASE(MINT_BEQ_I8_S)
2879 BRELOP_S(l, ==)
2880 MINT_IN_BREAK;
2881 MINT_IN_CASE(MINT_BEQ_R8_S)
2882 CONDBR_S(!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_BEQ_I4)
2885 BRELOP(i, ==)
2886 MINT_IN_BREAK;
2887 MINT_IN_CASE(MINT_BEQ_I8)
2888 BRELOP(l, ==)
2889 MINT_IN_BREAK;
2890 MINT_IN_CASE(MINT_BEQ_R8)
2891 CONDBR(!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_S)
2894 BRELOP_S(i, >=)
2895 MINT_IN_BREAK;
2896 MINT_IN_CASE(MINT_BGE_I8_S)
2897 BRELOP_S(l, >=)
2898 MINT_IN_BREAK;
2899 MINT_IN_CASE(MINT_BGE_R8_S)
2900 CONDBR_S(!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_BGE_I4)
2903 BRELOP(i, >=)
2904 MINT_IN_BREAK;
2905 MINT_IN_CASE(MINT_BGE_I8)
2906 BRELOP(l, >=)
2907 MINT_IN_BREAK;
2908 MINT_IN_CASE(MINT_BGE_R8)
2909 CONDBR(!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_S)
2912 BRELOP_S(i, >)
2913 MINT_IN_BREAK;
2914 MINT_IN_CASE(MINT_BGT_I8_S)
2915 BRELOP_S(l, >)
2916 MINT_IN_BREAK;
2917 MINT_IN_CASE(MINT_BGT_R8_S)
2918 CONDBR_S(!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_BGT_I4)
2921 BRELOP(i, >)
2922 MINT_IN_BREAK;
2923 MINT_IN_CASE(MINT_BGT_I8)
2924 BRELOP(l, >)
2925 MINT_IN_BREAK;
2926 MINT_IN_CASE(MINT_BGT_R8)
2927 CONDBR(!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_S)
2930 BRELOP_S(i, <)
2931 MINT_IN_BREAK;
2932 MINT_IN_CASE(MINT_BLT_I8_S)
2933 BRELOP_S(l, <)
2934 MINT_IN_BREAK;
2935 MINT_IN_CASE(MINT_BLT_R8_S)
2936 CONDBR_S(!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_BLT_I4)
2939 BRELOP(i, <)
2940 MINT_IN_BREAK;
2941 MINT_IN_CASE(MINT_BLT_I8)
2942 BRELOP(l, <)
2943 MINT_IN_BREAK;
2944 MINT_IN_CASE(MINT_BLT_R8)
2945 CONDBR(!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_S)
2948 BRELOP_S(i, <=)
2949 MINT_IN_BREAK;
2950 MINT_IN_CASE(MINT_BLE_I8_S)
2951 BRELOP_S(l, <=)
2952 MINT_IN_BREAK;
2953 MINT_IN_CASE(MINT_BLE_R8_S)
2954 CONDBR_S(!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_BLE_I4)
2957 BRELOP(i, <=)
2958 MINT_IN_BREAK;
2959 MINT_IN_CASE(MINT_BLE_I8)
2960 BRELOP(l, <=)
2961 MINT_IN_BREAK;
2962 MINT_IN_CASE(MINT_BLE_R8)
2963 CONDBR(!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_S)
2966 BRELOP_S(i, !=)
2967 MINT_IN_BREAK;
2968 MINT_IN_CASE(MINT_BNE_UN_I8_S)
2969 BRELOP_S(l, !=)
2970 MINT_IN_BREAK;
2971 MINT_IN_CASE(MINT_BNE_UN_R8_S)
2972 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
2973 MINT_IN_BREAK;
2974 MINT_IN_CASE(MINT_BNE_UN_I4)
2975 BRELOP(i, !=)
2976 MINT_IN_BREAK;
2977 MINT_IN_CASE(MINT_BNE_UN_I8)
2978 BRELOP(l, !=)
2979 MINT_IN_BREAK;
2980 MINT_IN_CASE(MINT_BNE_UN_R8)
2981 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
2982 MINT_IN_BREAK;
2984 #define BRELOP_S_CAST(datamem, op, type) \
2985 sp -= 2; \
2986 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
2987 ip += * (gint16 *)(ip + 1); \
2988 else \
2989 ip += 2;
2991 #define BRELOP_CAST(datamem, op, type) \
2992 sp -= 2; \
2993 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
2994 ip += READ32(ip + 1); \
2995 else \
2996 ip += 3;
2998 MINT_IN_CASE(MINT_BGE_UN_I4_S)
2999 BRELOP_S_CAST(i, >=, guint32);
3000 MINT_IN_BREAK;
3001 MINT_IN_CASE(MINT_BGE_UN_I8_S)
3002 BRELOP_S_CAST(l, >=, guint64);
3003 MINT_IN_BREAK;
3004 MINT_IN_CASE(MINT_BGE_UN_R8_S)
3005 CONDBR_S(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_BGE_UN_I4)
3008 BRELOP_CAST(i, >=, guint32);
3009 MINT_IN_BREAK;
3010 MINT_IN_CASE(MINT_BGE_UN_I8)
3011 BRELOP_CAST(l, >=, guint64);
3012 MINT_IN_BREAK;
3013 MINT_IN_CASE(MINT_BGE_UN_R8)
3014 CONDBR(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_S)
3017 BRELOP_S_CAST(i, >, guint32);
3018 MINT_IN_BREAK;
3019 MINT_IN_CASE(MINT_BGT_UN_I8_S)
3020 BRELOP_S_CAST(l, >, guint64);
3021 MINT_IN_BREAK;
3022 MINT_IN_CASE(MINT_BGT_UN_R8_S)
3023 CONDBR_S(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_BGT_UN_I4)
3026 BRELOP_CAST(i, >, guint32);
3027 MINT_IN_BREAK;
3028 MINT_IN_CASE(MINT_BGT_UN_I8)
3029 BRELOP_CAST(l, >, guint64);
3030 MINT_IN_BREAK;
3031 MINT_IN_CASE(MINT_BGT_UN_R8)
3032 CONDBR(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_S)
3035 BRELOP_S_CAST(i, <=, guint32);
3036 MINT_IN_BREAK;
3037 MINT_IN_CASE(MINT_BLE_UN_I8_S)
3038 BRELOP_S_CAST(l, <=, guint64);
3039 MINT_IN_BREAK;
3040 MINT_IN_CASE(MINT_BLE_UN_R8_S)
3041 CONDBR_S(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_BLE_UN_I4)
3044 BRELOP_CAST(i, <=, guint32);
3045 MINT_IN_BREAK;
3046 MINT_IN_CASE(MINT_BLE_UN_I8)
3047 BRELOP_CAST(l, <=, guint64);
3048 MINT_IN_BREAK;
3049 MINT_IN_CASE(MINT_BLE_UN_R8)
3050 CONDBR(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_S)
3053 BRELOP_S_CAST(i, <, guint32);
3054 MINT_IN_BREAK;
3055 MINT_IN_CASE(MINT_BLT_UN_I8_S)
3056 BRELOP_S_CAST(l, <, guint64);
3057 MINT_IN_BREAK;
3058 MINT_IN_CASE(MINT_BLT_UN_R8_S)
3059 CONDBR_S(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_BLT_UN_I4)
3062 BRELOP_CAST(i, <, guint32);
3063 MINT_IN_BREAK;
3064 MINT_IN_CASE(MINT_BLT_UN_I8)
3065 BRELOP_CAST(l, <, guint64);
3066 MINT_IN_BREAK;
3067 MINT_IN_CASE(MINT_BLT_UN_R8)
3068 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
3069 MINT_IN_BREAK;
3070 MINT_IN_CASE(MINT_SWITCH) {
3071 guint32 n;
3072 const unsigned short *st;
3073 ++ip;
3074 n = READ32 (ip);
3075 ip += 2;
3076 st = ip + 2 * n;
3077 --sp;
3078 if ((guint32)sp->data.i < n) {
3079 gint offset;
3080 ip += 2 * (guint32)sp->data.i;
3081 offset = READ32 (ip);
3082 ip = st + offset;
3083 } else {
3084 ip = st;
3086 MINT_IN_BREAK;
3088 MINT_IN_CASE(MINT_LDIND_I1)
3089 ++ip;
3090 sp[-1].data.i = *(gint8*)sp[-1].data.p;
3091 MINT_IN_BREAK;
3092 MINT_IN_CASE(MINT_LDIND_U1)
3093 ++ip;
3094 sp[-1].data.i = *(guint8*)sp[-1].data.p;
3095 MINT_IN_BREAK;
3096 MINT_IN_CASE(MINT_LDIND_I2)
3097 ++ip;
3098 sp[-1].data.i = *(gint16*)sp[-1].data.p;
3099 MINT_IN_BREAK;
3100 MINT_IN_CASE(MINT_LDIND_U2)
3101 ++ip;
3102 sp[-1].data.i = *(guint16*)sp[-1].data.p;
3103 MINT_IN_BREAK;
3104 MINT_IN_CASE(MINT_LDIND_I4) /* Fall through */
3105 MINT_IN_CASE(MINT_LDIND_U4)
3106 ++ip;
3107 sp[-1].data.i = *(gint32*)sp[-1].data.p;
3108 MINT_IN_BREAK;
3109 MINT_IN_CASE(MINT_LDIND_I8)
3110 ++ip;
3111 sp[-1].data.l = *(gint64*)sp[-1].data.p;
3112 MINT_IN_BREAK;
3113 MINT_IN_CASE(MINT_LDIND_I) {
3114 guint16 offset = * (guint16 *)(ip + 1);
3115 sp[-1 - offset].data.p = *(gpointer*)sp[-1 - offset].data.p;
3116 ip += 2;
3117 MINT_IN_BREAK;
3119 MINT_IN_CASE(MINT_LDIND_R4)
3120 ++ip;
3121 sp[-1].data.f = *(gfloat*)sp[-1].data.p;
3122 MINT_IN_BREAK;
3123 MINT_IN_CASE(MINT_LDIND_R8)
3124 ++ip;
3125 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
3126 MINT_IN_BREAK;
3127 MINT_IN_CASE(MINT_LDIND_REF)
3128 ++ip;
3129 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
3130 MINT_IN_BREAK;
3131 MINT_IN_CASE(MINT_STIND_REF)
3132 ++ip;
3133 sp -= 2;
3134 mono_gc_wbarrier_generic_store (sp->data.p, sp [1].data.p);
3135 MINT_IN_BREAK;
3136 MINT_IN_CASE(MINT_STIND_I1)
3137 ++ip;
3138 sp -= 2;
3139 * (gint8 *) sp->data.p = (gint8)sp[1].data.i;
3140 MINT_IN_BREAK;
3141 MINT_IN_CASE(MINT_STIND_I2)
3142 ++ip;
3143 sp -= 2;
3144 * (gint16 *) sp->data.p = (gint16)sp[1].data.i;
3145 MINT_IN_BREAK;
3146 MINT_IN_CASE(MINT_STIND_I4)
3147 ++ip;
3148 sp -= 2;
3149 * (gint32 *) sp->data.p = sp[1].data.i;
3150 MINT_IN_BREAK;
3151 MINT_IN_CASE(MINT_STIND_I)
3152 ++ip;
3153 sp -= 2;
3154 * (mono_i *) sp->data.p = (mono_i)sp[1].data.p;
3155 MINT_IN_BREAK;
3156 MINT_IN_CASE(MINT_STIND_I8)
3157 ++ip;
3158 sp -= 2;
3159 * (gint64 *) sp->data.p = sp[1].data.l;
3160 MINT_IN_BREAK;
3161 MINT_IN_CASE(MINT_STIND_R4)
3162 ++ip;
3163 sp -= 2;
3164 * (float *) sp->data.p = (gfloat)sp[1].data.f;
3165 MINT_IN_BREAK;
3166 MINT_IN_CASE(MINT_STIND_R8)
3167 ++ip;
3168 sp -= 2;
3169 * (double *) sp->data.p = sp[1].data.f;
3170 MINT_IN_BREAK;
3171 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4)
3172 ++ip;
3173 sp -= 2;
3174 InterlockedWrite ((gint32 *) sp->data.p, sp [1].data.i);
3175 MINT_IN_BREAK;
3176 #define BINOP(datamem, op) \
3177 --sp; \
3178 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
3179 ++ip;
3180 MINT_IN_CASE(MINT_ADD_I4)
3181 BINOP(i, +);
3182 MINT_IN_BREAK;
3183 MINT_IN_CASE(MINT_ADD_I8)
3184 BINOP(l, +);
3185 MINT_IN_BREAK;
3186 MINT_IN_CASE(MINT_ADD_R8)
3187 BINOP(f, +);
3188 MINT_IN_BREAK;
3189 MINT_IN_CASE(MINT_ADD1_I4)
3190 ++sp [-1].data.i;
3191 ++ip;
3192 MINT_IN_BREAK;
3193 MINT_IN_CASE(MINT_SUB_I4)
3194 BINOP(i, -);
3195 MINT_IN_BREAK;
3196 MINT_IN_CASE(MINT_SUB_I8)
3197 BINOP(l, -);
3198 MINT_IN_BREAK;
3199 MINT_IN_CASE(MINT_SUB_R8)
3200 BINOP(f, -);
3201 MINT_IN_BREAK;
3202 MINT_IN_CASE(MINT_SUB1_I4)
3203 --sp [-1].data.i;
3204 ++ip;
3205 MINT_IN_BREAK;
3206 MINT_IN_CASE(MINT_MUL_I4)
3207 BINOP(i, *);
3208 MINT_IN_BREAK;
3209 MINT_IN_CASE(MINT_MUL_I8)
3210 BINOP(l, *);
3211 MINT_IN_BREAK;
3212 MINT_IN_CASE(MINT_MUL_R8)
3213 BINOP(f, *);
3214 MINT_IN_BREAK;
3215 MINT_IN_CASE(MINT_DIV_I4)
3216 if (sp [-1].data.i == 0)
3217 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3218 if (sp [-1].data.i == (-1))
3219 THROW_EX (mono_get_exception_overflow (), ip);
3220 BINOP(i, /);
3221 MINT_IN_BREAK;
3222 MINT_IN_CASE(MINT_DIV_I8)
3223 if (sp [-1].data.l == 0)
3224 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3225 if (sp [-1].data.l == (-1))
3226 THROW_EX (mono_get_exception_overflow (), ip);
3227 BINOP(l, /);
3228 MINT_IN_BREAK;
3229 MINT_IN_CASE(MINT_DIV_R8)
3230 BINOP(f, /);
3231 MINT_IN_BREAK;
3233 #define BINOP_CAST(datamem, op, type) \
3234 --sp; \
3235 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
3236 ++ip;
3237 MINT_IN_CASE(MINT_DIV_UN_I4)
3238 if (sp [-1].data.i == 0)
3239 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3240 BINOP_CAST(i, /, guint32);
3241 MINT_IN_BREAK;
3242 MINT_IN_CASE(MINT_DIV_UN_I8)
3243 if (sp [-1].data.l == 0)
3244 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3245 BINOP_CAST(l, /, guint64);
3246 MINT_IN_BREAK;
3247 MINT_IN_CASE(MINT_REM_I4)
3248 if (sp [-1].data.i == 0)
3249 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3250 if (sp [-1].data.i == (-1))
3251 THROW_EX (mono_get_exception_overflow (), ip);
3252 BINOP(i, %);
3253 MINT_IN_BREAK;
3254 MINT_IN_CASE(MINT_REM_I8)
3255 if (sp [-1].data.l == 0)
3256 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3257 if (sp [-1].data.l == (-1))
3258 THROW_EX (mono_get_exception_overflow (), ip);
3259 BINOP(l, %);
3260 MINT_IN_BREAK;
3261 MINT_IN_CASE(MINT_REM_R8)
3262 /* FIXME: what do we actually do here? */
3263 --sp;
3264 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
3265 ++ip;
3266 MINT_IN_BREAK;
3267 MINT_IN_CASE(MINT_REM_UN_I4)
3268 if (sp [-1].data.i == 0)
3269 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3270 BINOP_CAST(i, %, guint32);
3271 MINT_IN_BREAK;
3272 MINT_IN_CASE(MINT_REM_UN_I8)
3273 if (sp [-1].data.l == 0)
3274 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3275 BINOP_CAST(l, %, guint64);
3276 MINT_IN_BREAK;
3277 MINT_IN_CASE(MINT_AND_I4)
3278 BINOP(i, &);
3279 MINT_IN_BREAK;
3280 MINT_IN_CASE(MINT_AND_I8)
3281 BINOP(l, &);
3282 MINT_IN_BREAK;
3283 MINT_IN_CASE(MINT_OR_I4)
3284 BINOP(i, |);
3285 MINT_IN_BREAK;
3286 MINT_IN_CASE(MINT_OR_I8)
3287 BINOP(l, |);
3288 MINT_IN_BREAK;
3289 MINT_IN_CASE(MINT_XOR_I4)
3290 BINOP(i, ^);
3291 MINT_IN_BREAK;
3292 MINT_IN_CASE(MINT_XOR_I8)
3293 BINOP(l, ^);
3294 MINT_IN_BREAK;
3296 #define SHIFTOP(datamem, op) \
3297 --sp; \
3298 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
3299 ++ip;
3301 MINT_IN_CASE(MINT_SHL_I4)
3302 SHIFTOP(i, <<);
3303 MINT_IN_BREAK;
3304 MINT_IN_CASE(MINT_SHL_I8)
3305 SHIFTOP(l, <<);
3306 MINT_IN_BREAK;
3307 MINT_IN_CASE(MINT_SHR_I4)
3308 SHIFTOP(i, >>);
3309 MINT_IN_BREAK;
3310 MINT_IN_CASE(MINT_SHR_I8)
3311 SHIFTOP(l, >>);
3312 MINT_IN_BREAK;
3313 MINT_IN_CASE(MINT_SHR_UN_I4)
3314 --sp;
3315 sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i;
3316 ++ip;
3317 MINT_IN_BREAK;
3318 MINT_IN_CASE(MINT_SHR_UN_I8)
3319 --sp;
3320 sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i;
3321 ++ip;
3322 MINT_IN_BREAK;
3323 MINT_IN_CASE(MINT_NEG_I4)
3324 sp [-1].data.i = - sp [-1].data.i;
3325 ++ip;
3326 MINT_IN_BREAK;
3327 MINT_IN_CASE(MINT_NEG_I8)
3328 sp [-1].data.l = - sp [-1].data.l;
3329 ++ip;
3330 MINT_IN_BREAK;
3331 MINT_IN_CASE(MINT_NEG_R8)
3332 sp [-1].data.f = - sp [-1].data.f;
3333 ++ip;
3334 MINT_IN_BREAK;
3335 MINT_IN_CASE(MINT_NOT_I4)
3336 sp [-1].data.i = ~ sp [-1].data.i;
3337 ++ip;
3338 MINT_IN_BREAK;
3339 MINT_IN_CASE(MINT_NOT_I8)
3340 sp [-1].data.l = ~ sp [-1].data.l;
3341 ++ip;
3342 MINT_IN_BREAK;
3343 MINT_IN_CASE(MINT_CONV_I1_I4)
3344 sp [-1].data.i = (gint8)sp [-1].data.i;
3345 ++ip;
3346 MINT_IN_BREAK;
3347 MINT_IN_CASE(MINT_CONV_I1_I8)
3348 sp [-1].data.i = (gint8)sp [-1].data.l;
3349 ++ip;
3350 MINT_IN_BREAK;
3351 MINT_IN_CASE(MINT_CONV_I1_R8)
3352 sp [-1].data.i = (gint8)sp [-1].data.f;
3353 ++ip;
3354 MINT_IN_BREAK;
3355 MINT_IN_CASE(MINT_CONV_U1_I4)
3356 sp [-1].data.i = (guint8)sp [-1].data.i;
3357 ++ip;
3358 MINT_IN_BREAK;
3359 MINT_IN_CASE(MINT_CONV_U1_I8)
3360 sp [-1].data.i = (guint8)sp [-1].data.l;
3361 ++ip;
3362 MINT_IN_BREAK;
3363 MINT_IN_CASE(MINT_CONV_U1_R8)
3364 sp [-1].data.i = (guint8)sp [-1].data.f;
3365 ++ip;
3366 MINT_IN_BREAK;
3367 MINT_IN_CASE(MINT_CONV_I2_I4)
3368 sp [-1].data.i = (gint16)sp [-1].data.i;
3369 ++ip;
3370 MINT_IN_BREAK;
3371 MINT_IN_CASE(MINT_CONV_I2_I8)
3372 sp [-1].data.i = (gint16)sp [-1].data.l;
3373 ++ip;
3374 MINT_IN_BREAK;
3375 MINT_IN_CASE(MINT_CONV_I2_R8)
3376 sp [-1].data.i = (gint16)sp [-1].data.f;
3377 ++ip;
3378 MINT_IN_BREAK;
3379 MINT_IN_CASE(MINT_CONV_U2_I4)
3380 sp [-1].data.i = (guint16)sp [-1].data.i;
3381 ++ip;
3382 MINT_IN_BREAK;
3383 MINT_IN_CASE(MINT_CONV_U2_I8)
3384 sp [-1].data.i = (guint16)sp [-1].data.l;
3385 ++ip;
3386 MINT_IN_BREAK;
3387 MINT_IN_CASE(MINT_CONV_U2_R8)
3388 sp [-1].data.i = (guint16)sp [-1].data.f;
3389 ++ip;
3390 MINT_IN_BREAK;
3391 MINT_IN_CASE(MINT_CONV_I4_R8)
3392 sp [-1].data.i = (gint32)sp [-1].data.f;
3393 ++ip;
3394 MINT_IN_BREAK;
3395 MINT_IN_CASE(MINT_CONV_U4_I8)
3396 MINT_IN_CASE(MINT_CONV_I4_I8)
3397 sp [-1].data.i = (gint32)sp [-1].data.l;
3398 ++ip;
3399 MINT_IN_BREAK;
3400 MINT_IN_CASE(MINT_CONV_I4_I8_SP)
3401 sp [-2].data.i = (gint32)sp [-2].data.l;
3402 ++ip;
3403 MINT_IN_BREAK;
3404 MINT_IN_CASE(MINT_CONV_U4_R8)
3405 /* needed on arm64 */
3406 if (isinf (sp [-1].data.f))
3407 sp [-1].data.i = 0;
3408 else
3409 sp [-1].data.i = (guint32)sp [-1].data.f;
3410 ++ip;
3411 MINT_IN_BREAK;
3412 MINT_IN_CASE(MINT_CONV_I8_I4)
3413 sp [-1].data.l = sp [-1].data.i;
3414 ++ip;
3415 MINT_IN_BREAK;
3416 MINT_IN_CASE(MINT_CONV_I8_I4_SP)
3417 sp [-2].data.l = sp [-2].data.i;
3418 ++ip;
3419 MINT_IN_BREAK;
3420 MINT_IN_CASE(MINT_CONV_I8_U4)
3421 sp [-1].data.l = (guint32)sp [-1].data.i;
3422 ++ip;
3423 MINT_IN_BREAK;
3424 MINT_IN_CASE(MINT_CONV_I8_R8)
3425 sp [-1].data.l = (gint64)sp [-1].data.f;
3426 ++ip;
3427 MINT_IN_BREAK;
3428 MINT_IN_CASE(MINT_CONV_R4_I4)
3429 sp [-1].data.f = (float)sp [-1].data.i;
3430 ++ip;
3431 MINT_IN_BREAK;
3432 MINT_IN_CASE(MINT_CONV_R4_I8)
3433 sp [-1].data.f = (float)sp [-1].data.l;
3434 ++ip;
3435 MINT_IN_BREAK;
3436 MINT_IN_CASE(MINT_CONV_R4_R8)
3437 sp [-1].data.f = (float)sp [-1].data.f;
3438 ++ip;
3439 MINT_IN_BREAK;
3440 MINT_IN_CASE(MINT_CONV_R8_I4)
3441 sp [-1].data.f = (double)sp [-1].data.i;
3442 ++ip;
3443 MINT_IN_BREAK;
3444 MINT_IN_CASE(MINT_CONV_R8_I8)
3445 sp [-1].data.f = (double)sp [-1].data.l;
3446 ++ip;
3447 MINT_IN_BREAK;
3448 MINT_IN_CASE(MINT_CONV_U8_I4)
3449 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
3450 ++ip;
3451 MINT_IN_BREAK;
3452 MINT_IN_CASE(MINT_CONV_U8_R8)
3453 sp [-1].data.l = (guint64)sp [-1].data.f;
3454 ++ip;
3455 MINT_IN_BREAK;
3456 MINT_IN_CASE(MINT_CPOBJ) {
3457 c = rtm->data_items[* (guint16 *)(ip + 1)];
3458 g_assert (c->byval_arg.type == MONO_TYPE_VALUETYPE);
3459 /* if this assertion fails, we need to add a write barrier */
3460 g_assert (!MONO_TYPE_IS_REFERENCE (&c->byval_arg));
3461 stackval_from_data (&c->byval_arg, &sp [-2], sp [-1].data.p, FALSE);
3462 ip += 2;
3463 sp -= 2;
3464 MINT_IN_BREAK;
3466 MINT_IN_CASE(MINT_LDOBJ) {
3467 void *p;
3468 c = rtm->data_items[* (guint16 *)(ip + 1)];
3469 ip += 2;
3470 p = sp [-1].data.p;
3471 if (c->byval_arg.type == MONO_TYPE_VALUETYPE && !c->enumtype) {
3472 int size = mono_class_value_size (c, NULL);
3473 sp [-1].data.p = vt_sp;
3474 vt_sp += (size + 7) & ~7;
3476 stackval_from_data (&c->byval_arg, &sp [-1], p, FALSE);
3477 MINT_IN_BREAK;
3479 MINT_IN_CASE(MINT_LDSTR)
3480 sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)];
3481 ++sp;
3482 ip += 2;
3483 MINT_IN_BREAK;
3484 MINT_IN_CASE(MINT_NEWOBJ) {
3485 MonoClass *newobj_class;
3486 MonoMethodSignature *csig;
3487 stackval valuetype_this;
3488 guint32 token;
3489 stackval retval;
3491 frame->ip = ip;
3493 token = * (guint16 *)(ip + 1);
3494 ip += 2;
3496 child_frame.ip = NULL;
3497 child_frame.ex = NULL;
3499 child_frame.runtime_method = rtm->data_items [token];
3500 csig = mono_method_signature (child_frame.runtime_method->method);
3501 newobj_class = child_frame.runtime_method->method->klass;
3502 /*if (profiling_classes) {
3503 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3504 count++;
3505 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3508 if (newobj_class->parent == mono_defaults.array_class) {
3509 sp -= csig->param_count;
3510 child_frame.stack_args = sp;
3511 o = ves_array_create (&child_frame, context->domain, newobj_class, csig, sp);
3512 if (child_frame.ex)
3513 THROW_EX (child_frame.ex, ip);
3514 goto array_constructed;
3517 g_assert (csig->hasthis);
3518 if (csig->param_count) {
3519 sp -= csig->param_count;
3520 memmove (sp + 1, sp, csig->param_count * sizeof (stackval));
3522 child_frame.stack_args = sp;
3525 * First arg is the object.
3527 if (newobj_class->valuetype) {
3528 MonoType *t = &newobj_class->byval_arg;
3529 memset (&valuetype_this, 0, sizeof (stackval));
3530 if (!newobj_class->enumtype && (t->type == MONO_TYPE_VALUETYPE || (t->type == MONO_TYPE_GENERICINST && mono_type_generic_inst_is_valuetype (t)))) {
3531 sp->data.p = vt_sp;
3532 valuetype_this.data.p = vt_sp;
3533 } else {
3534 sp->data.p = &valuetype_this;
3536 } else {
3537 if (newobj_class != mono_defaults.string_class) {
3538 context->managed_code = 0;
3539 o = mono_object_new_checked (context->domain, newobj_class, &error);
3540 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3541 context->managed_code = 1;
3542 if (*mono_thread_interruption_request_flag ())
3543 mono_thread_interruption_checkpoint ();
3544 sp->data.p = o;
3545 } else {
3546 sp->data.p = NULL;
3547 child_frame.retval = &retval;
3551 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
3553 ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
3555 context->current_frame = frame;
3557 if (context->has_resume_state) {
3558 if (frame == context->handler_frame)
3559 SET_RESUME_STATE (context);
3560 else
3561 goto exit_frame;
3564 if (child_frame.ex) {
3566 * An exception occurred, need to run finally, fault and catch handlers..
3568 frame->ex = child_frame.ex;
3569 goto handle_finally;
3572 * a constructor returns void, but we need to return the object we created
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;
3582 ++sp;
3583 MINT_IN_BREAK;
3585 MINT_IN_CASE(MINT_CASTCLASS)
3586 c = rtm->data_items [*(guint16 *)(ip + 1)];
3587 if ((o = sp [-1].data.p)) {
3588 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error);
3589 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3590 if (!isinst_obj)
3591 THROW_EX (mono_get_exception_invalid_cast (), ip);
3593 ip += 2;
3594 MINT_IN_BREAK;
3595 MINT_IN_CASE(MINT_ISINST)
3596 c = rtm->data_items [*(guint16 *)(ip + 1)];
3597 if ((o = sp [-1].data.p)) {
3598 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error);
3599 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3600 if (!isinst_obj)
3601 sp [-1].data.p = NULL;
3603 ip += 2;
3604 MINT_IN_BREAK;
3605 MINT_IN_CASE(MINT_CONV_R_UN_I4)
3606 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
3607 ++ip;
3608 MINT_IN_BREAK;
3609 MINT_IN_CASE(MINT_CONV_R_UN_I8)
3610 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
3611 ++ip;
3612 MINT_IN_BREAK;
3613 MINT_IN_CASE(MINT_UNBOX)
3614 c = rtm->data_items[*(guint16 *)(ip + 1)];
3616 o = sp [-1].data.p;
3617 if (!o)
3618 THROW_EX (mono_get_exception_null_reference (), ip);
3620 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error);
3621 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3622 if (!(isinst_obj || ((o->vtable->klass->rank == 0) && (o->vtable->klass->element_class == c->element_class))))
3623 THROW_EX (mono_get_exception_invalid_cast (), ip);
3625 sp [-1].data.p = mono_object_unbox (o);
3626 ip += 2;
3627 MINT_IN_BREAK;
3628 MINT_IN_CASE(MINT_THROW)
3629 --sp;
3630 frame->ex_handler = NULL;
3631 if (!sp->data.p)
3632 sp->data.p = mono_get_exception_null_reference ();
3633 THROW_EX ((MonoException *)sp->data.p, ip);
3634 MINT_IN_BREAK;
3635 MINT_IN_CASE(MINT_LDFLDA_UNSAFE)
3636 o = sp [-1].data.p;
3637 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
3638 ip += 2;
3639 MINT_IN_BREAK;
3640 MINT_IN_CASE(MINT_LDFLDA)
3641 o = sp [-1].data.p;
3642 if (!o)
3643 THROW_EX (mono_get_exception_null_reference (), ip);
3644 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
3645 ip += 2;
3646 MINT_IN_BREAK;
3647 MINT_IN_CASE(MINT_CKNULL)
3648 o = sp [-1].data.p;
3649 if (!o)
3650 THROW_EX (mono_get_exception_null_reference (), ip);
3651 ++ip;
3652 MINT_IN_BREAK;
3654 #define LDFLD(datamem, fieldtype) \
3655 o = sp [-1].data.p; \
3656 if (!o) \
3657 THROW_EX (mono_get_exception_null_reference (), ip); \
3658 sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
3659 ip += 2;
3661 MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK;
3662 MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK;
3663 MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK;
3664 MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK;
3665 MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK;
3666 MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK;
3667 MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f, float); MINT_IN_BREAK;
3668 MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK;
3669 MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK;
3670 MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK;
3672 MINT_IN_CASE(MINT_LDFLD_VT)
3673 o = sp [-1].data.p;
3674 if (!o)
3675 THROW_EX (mono_get_exception_null_reference (), ip);
3676 i32 = READ32(ip + 2);
3677 sp [-1].data.p = vt_sp;
3678 memcpy(sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32);
3679 vt_sp += (i32 + 7) & ~7;
3680 ip += 4;
3681 MINT_IN_BREAK;
3683 MINT_IN_CASE(MINT_LDRMFLD) {
3684 gpointer tmp;
3685 MonoClassField *field;
3686 char *addr;
3688 o = sp [-1].data.p;
3689 if (!o)
3690 THROW_EX (mono_get_exception_null_reference (), ip);
3691 field = rtm->data_items[* (guint16 *)(ip + 1)];
3692 ip += 2;
3693 if (mono_object_is_transparent_proxy (o)) {
3694 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3696 addr = mono_load_remote_field_checked (o, klass, field, &tmp, &error);
3697 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3698 } else {
3699 addr = (char*)o + field->offset;
3702 stackval_from_data (field->type, &sp [-1], addr, FALSE);
3703 MINT_IN_BREAK;
3706 MINT_IN_CASE(MINT_LDRMFLD_VT) {
3707 MonoClassField *field;
3708 char *addr;
3709 gpointer tmp;
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 i32 = READ32(ip + 2);
3716 ip += 4;
3717 if (mono_object_is_transparent_proxy (o)) {
3718 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3719 addr = mono_load_remote_field_checked (o, klass, field, &tmp, &error);
3720 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3721 } else {
3722 addr = (char*)o + field->offset;
3725 sp [-1].data.p = vt_sp;
3726 memcpy(sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32);
3727 vt_sp += (i32 + 7) & ~7;
3728 memcpy(sp [-1].data.p, addr, i32);
3729 MINT_IN_BREAK;
3732 #define STFLD(datamem, fieldtype) \
3733 o = sp [-2].data.p; \
3734 if (!o) \
3735 THROW_EX (mono_get_exception_null_reference (), ip); \
3736 sp -= 2; \
3737 * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
3738 ip += 2;
3740 MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK;
3741 MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK;
3742 MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK;
3743 MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK;
3744 MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK;
3745 MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK;
3746 MINT_IN_CASE(MINT_STFLD_R4) STFLD(f, float); MINT_IN_BREAK;
3747 MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK;
3748 MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK;
3749 MINT_IN_CASE(MINT_STFLD_O)
3750 o = sp [-2].data.p;
3751 if (!o)
3752 THROW_EX (mono_get_exception_null_reference (), ip);
3753 sp -= 2;
3754 mono_gc_wbarrier_set_field (o, (char *) o + * (guint16 *)(ip + 1), sp [1].data.p);
3755 ip += 2;
3756 MINT_IN_BREAK;
3758 MINT_IN_CASE(MINT_STFLD_VT)
3759 o = sp [-2].data.p;
3760 if (!o)
3761 THROW_EX (mono_get_exception_null_reference (), ip);
3762 i32 = READ32(ip + 2);
3763 sp -= 2;
3764 memcpy((char *)o + * (guint16 *)(ip + 1), sp [1].data.p, i32);
3765 vt_sp -= (i32 + 7) & ~7;
3766 ip += 4;
3767 MINT_IN_BREAK;
3769 MINT_IN_CASE(MINT_STRMFLD) {
3770 MonoClassField *field;
3772 o = sp [-2].data.p;
3773 if (!o)
3774 THROW_EX (mono_get_exception_null_reference (), ip);
3776 field = rtm->data_items[* (guint16 *)(ip + 1)];
3777 ip += 2;
3779 if (mono_object_is_transparent_proxy (o)) {
3780 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3781 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, &error);
3782 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3783 } else
3784 stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE);
3786 sp -= 2;
3787 MINT_IN_BREAK;
3789 MINT_IN_CASE(MINT_STRMFLD_VT) {
3790 MonoClassField *field;
3792 o = sp [-2].data.p;
3793 if (!o)
3794 THROW_EX (mono_get_exception_null_reference (), ip);
3795 field = rtm->data_items[* (guint16 *)(ip + 1)];
3796 i32 = READ32(ip + 2);
3797 ip += 4;
3799 if (mono_object_is_transparent_proxy (o)) {
3800 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3801 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, &error);
3802 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3803 } else
3804 memcpy((char*)o + field->offset, sp [-1].data.p, i32);
3806 sp -= 2;
3807 vt_sp -= (i32 + 7) & ~7;
3808 MINT_IN_BREAK;
3810 MINT_IN_CASE(MINT_LDSFLDA) {
3811 MonoClassField *field = rtm->data_items[*(guint16 *)(ip + 1)];
3812 sp->data.p = mono_class_static_field_address (context->domain, field);
3813 ip += 2;
3814 ++sp;
3815 MINT_IN_BREAK;
3817 MINT_IN_CASE(MINT_LDSFLD) {
3818 MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3819 gpointer addr = mono_class_static_field_address (context->domain, field);
3820 stackval_from_data (field->type, sp, addr, FALSE);
3821 ip += 2;
3822 ++sp;
3823 MINT_IN_BREAK;
3825 MINT_IN_CASE(MINT_LDSFLD_VT) {
3826 MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3827 gpointer addr = mono_class_static_field_address (context->domain, field);
3828 int size = READ32 (ip + 2);
3829 ip += 4;
3831 sp->data.p = vt_sp;
3832 vt_sp += (size + 7) & ~7;
3833 stackval_from_data (field->type, sp, addr, FALSE);
3834 ++sp;
3835 MINT_IN_BREAK;
3837 MINT_IN_CASE(MINT_STSFLD) {
3838 MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3839 gpointer addr = mono_class_static_field_address (context->domain, field);
3840 ip += 2;
3841 --sp;
3842 stackval_to_data (field->type, sp, addr, FALSE);
3843 MINT_IN_BREAK;
3845 MINT_IN_CASE(MINT_STSFLD_VT) {
3846 MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3847 gpointer addr = mono_class_static_field_address (context->domain, field);
3848 int size = READ32 (ip + 2);
3849 ip += 4;
3851 --sp;
3852 stackval_to_data (field->type, sp, addr, FALSE);
3853 vt_sp -= (size + 7) & ~7;
3854 MINT_IN_BREAK;
3856 MINT_IN_CASE(MINT_STOBJ_VT) {
3857 int size;
3858 c = rtm->data_items[* (guint16 *)(ip + 1)];
3859 ip += 2;
3860 size = mono_class_value_size (c, NULL);
3861 memcpy(sp [-2].data.p, sp [-1].data.p, size);
3862 vt_sp -= (size + 7) & ~7;
3863 sp -= 2;
3864 MINT_IN_BREAK;
3866 MINT_IN_CASE(MINT_STOBJ) {
3867 c = rtm->data_items[* (guint16 *)(ip + 1)];
3868 ip += 2;
3870 g_assert (!c->byval_arg.byref);
3871 if (MONO_TYPE_IS_REFERENCE (&c->byval_arg))
3872 mono_gc_wbarrier_generic_store (sp [-2].data.p, sp [-1].data.p);
3873 else
3874 stackval_from_data (&c->byval_arg, sp [-2].data.p, (char *) &sp [-1].data.p, FALSE);
3875 sp -= 2;
3876 MINT_IN_BREAK;
3878 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8)
3879 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT32_MAX)
3880 THROW_EX (mono_get_exception_overflow (), ip);
3881 sp [-1].data.i = (guint32)sp [-1].data.f;
3882 ++ip;
3883 MINT_IN_BREAK;
3884 MINT_IN_CASE(MINT_CONV_OVF_U8_I4)
3885 if (sp [-1].data.i < 0)
3886 THROW_EX (mono_get_exception_overflow (), ip);
3887 sp [-1].data.l = sp [-1].data.i;
3888 ++ip;
3889 MINT_IN_BREAK;
3890 MINT_IN_CASE(MINT_CONV_OVF_U8_I8)
3891 if (sp [-1].data.l < 0)
3892 THROW_EX (mono_get_exception_overflow (), ip);
3893 ++ip;
3894 MINT_IN_BREAK;
3895 MINT_IN_CASE(MINT_CONV_OVF_I8_U8)
3896 if ((guint64) sp [-1].data.l > MYGINT64_MAX)
3897 THROW_EX (mono_get_exception_overflow (), ip);
3898 ++ip;
3899 MINT_IN_BREAK;
3900 MINT_IN_CASE(MINT_CONV_OVF_U8_R8)
3901 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8)
3902 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGINT64_MAX)
3903 THROW_EX (mono_get_exception_overflow (), ip);
3904 sp [-1].data.l = (guint64)sp [-1].data.f;
3905 ++ip;
3906 MINT_IN_BREAK;
3907 MINT_IN_CASE(MINT_CONV_OVF_I8_R8)
3908 if (sp [-1].data.f < MYGINT64_MIN || sp [-1].data.f > MYGINT64_MAX)
3909 THROW_EX (mono_get_exception_overflow (), ip);
3910 sp [-1].data.l = (gint64)sp [-1].data.f;
3911 ++ip;
3912 MINT_IN_BREAK;
3913 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8)
3914 if ((mono_u)sp [-1].data.l > MYGUINT32_MAX)
3915 THROW_EX (mono_get_exception_overflow (), ip);
3916 sp [-1].data.i = (mono_u)sp [-1].data.l;
3917 ++ip;
3918 MINT_IN_BREAK;
3919 MINT_IN_CASE(MINT_BOX) {
3920 c = rtm->data_items [* (guint16 *)(ip + 1)];
3921 guint16 offset = * (guint16 *)(ip + 2);
3923 if (c->byval_arg.type == MONO_TYPE_VALUETYPE && !c->enumtype) {
3924 int size = mono_class_value_size (c, NULL);
3925 sp [-1 - offset].data.p = mono_value_box_checked (context->domain, c, sp [-1 - offset].data.p, &error);
3926 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3927 size = (size + 7) & ~7;
3928 vt_sp -= size;
3929 } else {
3930 stackval_to_data (&c->byval_arg, &sp [-1 - offset], (char *) &sp [-1 - offset], FALSE);
3931 sp [-1 - offset].data.p = mono_value_box_checked (context->domain, c, &sp [-1 - offset], &error);
3932 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3934 ip += 3;
3935 MINT_IN_BREAK;
3937 MINT_IN_CASE(MINT_NEWARR)
3938 sp [-1].data.p = (MonoObject*) mono_array_new_checked (context->domain, rtm->data_items[*(guint16 *)(ip + 1)], sp [-1].data.i, &error);
3939 if (!mono_error_ok (&error)) {
3940 THROW_EX (mono_error_convert_to_exception (&error), ip);
3942 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3943 ip += 2;
3944 /*if (profiling_classes) {
3945 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
3946 count++;
3947 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
3950 MINT_IN_BREAK;
3951 MINT_IN_CASE(MINT_LDLEN)
3952 o = sp [-1].data.p;
3953 if (!o)
3954 THROW_EX (mono_get_exception_null_reference (), ip);
3955 sp [-1].data.nati = mono_array_length ((MonoArray *)o);
3956 ++ip;
3957 MINT_IN_BREAK;
3958 MINT_IN_CASE(MINT_GETCHR) {
3959 MonoString *s;
3960 s = sp [-2].data.p;
3961 if (!s)
3962 THROW_EX (mono_get_exception_null_reference (), ip);
3963 i32 = sp [-1].data.i;
3964 if (i32 < 0 || i32 >= mono_string_length (s))
3965 THROW_EX (mono_get_exception_index_out_of_range (), ip);
3966 --sp;
3967 sp [-1].data.i = mono_string_chars(s)[i32];
3968 ++ip;
3969 MINT_IN_BREAK;
3971 MINT_IN_CASE(MINT_STRLEN)
3972 ++ip;
3973 o = sp [-1].data.p;
3974 if (!o)
3975 THROW_EX (mono_get_exception_null_reference (), ip);
3976 sp [-1].data.i = mono_string_length ((MonoString*) o);
3977 MINT_IN_BREAK;
3978 MINT_IN_CASE(MINT_ARRAY_RANK)
3979 o = sp [-1].data.p;
3980 if (!o)
3981 THROW_EX (mono_get_exception_null_reference (), ip);
3982 sp [-1].data.i = mono_object_class (sp [-1].data.p)->rank;
3983 ip++;
3984 MINT_IN_BREAK;
3985 MINT_IN_CASE(MINT_LDELEMA)
3986 MINT_IN_CASE(MINT_LDELEMA_TC) {
3987 gboolean needs_typecheck = *ip == MINT_LDELEMA_TC;
3989 MonoClass *klass = rtm->data_items [*(guint16 *) (ip + 1)];
3990 guint16 numargs = *(guint16 *) (ip + 2);
3991 ip += 3;
3992 sp -= numargs;
3994 o = sp [0].data.p;
3995 sp->data.p = ves_array_element_address (frame, klass, (MonoArray *) o, &sp [1], needs_typecheck);
3996 if (frame->ex)
3997 THROW_EX (frame->ex, ip);
3998 ++sp;
4000 MINT_IN_BREAK;
4002 MINT_IN_CASE(MINT_LDELEM_I1) /* fall through */
4003 MINT_IN_CASE(MINT_LDELEM_U1) /* fall through */
4004 MINT_IN_CASE(MINT_LDELEM_I2) /* fall through */
4005 MINT_IN_CASE(MINT_LDELEM_U2) /* fall through */
4006 MINT_IN_CASE(MINT_LDELEM_I4) /* fall through */
4007 MINT_IN_CASE(MINT_LDELEM_U4) /* fall through */
4008 MINT_IN_CASE(MINT_LDELEM_I8) /* fall through */
4009 MINT_IN_CASE(MINT_LDELEM_I) /* fall through */
4010 MINT_IN_CASE(MINT_LDELEM_R4) /* fall through */
4011 MINT_IN_CASE(MINT_LDELEM_R8) /* fall through */
4012 MINT_IN_CASE(MINT_LDELEM_REF) /* fall through */
4013 MINT_IN_CASE(MINT_LDELEM_VT) {
4014 MonoArray *o;
4015 mono_u aindex;
4017 sp -= 2;
4019 o = sp [0].data.p;
4020 if (!o)
4021 THROW_EX (mono_get_exception_null_reference (), ip);
4023 aindex = sp [1].data.i;
4024 if (aindex >= mono_array_length (o))
4025 THROW_EX (mono_get_exception_index_out_of_range (), ip);
4028 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
4030 switch (*ip) {
4031 case MINT_LDELEM_I1:
4032 sp [0].data.i = mono_array_get (o, gint8, aindex);
4033 break;
4034 case MINT_LDELEM_U1:
4035 sp [0].data.i = mono_array_get (o, guint8, aindex);
4036 break;
4037 case MINT_LDELEM_I2:
4038 sp [0].data.i = mono_array_get (o, gint16, aindex);
4039 break;
4040 case MINT_LDELEM_U2:
4041 sp [0].data.i = mono_array_get (o, guint16, aindex);
4042 break;
4043 case MINT_LDELEM_I:
4044 sp [0].data.nati = mono_array_get (o, mono_i, aindex);
4045 break;
4046 case MINT_LDELEM_I4:
4047 sp [0].data.i = mono_array_get (o, gint32, aindex);
4048 break;
4049 case MINT_LDELEM_U4:
4050 sp [0].data.i = mono_array_get (o, guint32, aindex);
4051 break;
4052 case MINT_LDELEM_I8:
4053 sp [0].data.l = mono_array_get (o, guint64, aindex);
4054 break;
4055 case MINT_LDELEM_R4:
4056 sp [0].data.f = mono_array_get (o, float, aindex);
4057 break;
4058 case MINT_LDELEM_R8:
4059 sp [0].data.f = mono_array_get (o, double, aindex);
4060 break;
4061 case MINT_LDELEM_REF:
4062 sp [0].data.p = mono_array_get (o, gpointer, aindex);
4063 break;
4064 case MINT_LDELEM_VT: {
4065 MonoClass *klass_vt = rtm->data_items [*(guint16 *) (ip + 1)];
4066 i32 = READ32 (ip + 2);
4067 char *src_addr = mono_array_addr_with_size ((MonoArray *) o, i32, aindex);
4068 sp [0].data.vt = vt_sp;
4069 stackval_from_data (&klass_vt->byval_arg, sp, src_addr, FALSE);
4070 vt_sp += (i32 + 7) & ~7;
4071 ip += 3;
4072 break;
4074 default:
4075 ves_abort();
4078 ++ip;
4079 ++sp;
4080 MINT_IN_BREAK;
4082 MINT_IN_CASE(MINT_STELEM_I) /* fall through */
4083 MINT_IN_CASE(MINT_STELEM_I1) /* fall through */
4084 MINT_IN_CASE(MINT_STELEM_U1) /* fall through */
4085 MINT_IN_CASE(MINT_STELEM_I2) /* fall through */
4086 MINT_IN_CASE(MINT_STELEM_U2) /* fall through */
4087 MINT_IN_CASE(MINT_STELEM_I4) /* fall through */
4088 MINT_IN_CASE(MINT_STELEM_I8) /* fall through */
4089 MINT_IN_CASE(MINT_STELEM_R4) /* fall through */
4090 MINT_IN_CASE(MINT_STELEM_R8) /* fall through */
4091 MINT_IN_CASE(MINT_STELEM_REF) /* fall through */
4092 MINT_IN_CASE(MINT_STELEM_VT) {
4093 mono_u aindex;
4095 sp -= 3;
4097 o = sp [0].data.p;
4098 if (!o)
4099 THROW_EX (mono_get_exception_null_reference (), ip);
4101 aindex = sp [1].data.i;
4102 if (aindex >= mono_array_length ((MonoArray *)o))
4103 THROW_EX (mono_get_exception_index_out_of_range (), ip);
4105 switch (*ip) {
4106 case MINT_STELEM_I:
4107 mono_array_set ((MonoArray *)o, mono_i, aindex, sp [2].data.nati);
4108 break;
4109 case MINT_STELEM_I1:
4110 mono_array_set ((MonoArray *)o, gint8, aindex, sp [2].data.i);
4111 break;
4112 case MINT_STELEM_U1:
4113 mono_array_set ((MonoArray *) o, guint8, aindex, sp [2].data.i);
4114 break;
4115 case MINT_STELEM_I2:
4116 mono_array_set ((MonoArray *)o, gint16, aindex, sp [2].data.i);
4117 break;
4118 case MINT_STELEM_U2:
4119 mono_array_set ((MonoArray *)o, guint16, aindex, sp [2].data.i);
4120 break;
4121 case MINT_STELEM_I4:
4122 mono_array_set ((MonoArray *)o, gint32, aindex, sp [2].data.i);
4123 break;
4124 case MINT_STELEM_I8:
4125 mono_array_set ((MonoArray *)o, gint64, aindex, sp [2].data.l);
4126 break;
4127 case MINT_STELEM_R4:
4128 mono_array_set ((MonoArray *)o, float, aindex, sp [2].data.f);
4129 break;
4130 case MINT_STELEM_R8:
4131 mono_array_set ((MonoArray *)o, double, aindex, sp [2].data.f);
4132 break;
4133 case MINT_STELEM_REF: {
4134 MonoObject *isinst_obj = mono_object_isinst_checked (sp [2].data.p, mono_object_class (o)->element_class, &error);
4135 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4136 if (sp [2].data.p && !isinst_obj)
4137 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
4138 mono_array_setref ((MonoArray *) o, aindex, sp [2].data.p);
4139 break;
4141 case MINT_STELEM_VT: {
4142 MonoClass *klass_vt = rtm->data_items [*(guint16 *) (ip + 1)];
4143 i32 = READ32 (ip + 2);
4144 char *dst_addr = mono_array_addr_with_size ((MonoArray *) o, i32, aindex);
4146 stackval_to_data (&klass_vt->byval_arg, &sp [2], dst_addr, FALSE);
4147 vt_sp -= (i32 + 7) & ~7;
4148 ip += 3;
4149 break;
4151 default:
4152 ves_abort();
4155 ++ip;
4156 MINT_IN_BREAK;
4158 MINT_IN_CASE(MINT_CONV_OVF_I4_U4)
4159 if (sp [-1].data.i < 0)
4160 THROW_EX (mono_get_exception_overflow (), ip);
4161 ++ip;
4162 MINT_IN_BREAK;
4163 MINT_IN_CASE(MINT_CONV_OVF_I4_I8)
4164 if (sp [-1].data.l < MYGINT32_MIN || sp [-1].data.l > MYGINT32_MAX)
4165 THROW_EX (mono_get_exception_overflow (), ip);
4166 sp [-1].data.i = (gint32) sp [-1].data.l;
4167 ++ip;
4168 MINT_IN_BREAK;
4169 MINT_IN_CASE(MINT_CONV_OVF_I4_U8)
4170 if (sp [-1].data.l < 0 || sp [-1].data.l > MYGINT32_MAX)
4171 THROW_EX (mono_get_exception_overflow (), ip);
4172 sp [-1].data.i = (gint32) sp [-1].data.l;
4173 ++ip;
4174 MINT_IN_BREAK;
4175 MINT_IN_CASE(MINT_CONV_OVF_I4_R8)
4176 if (sp [-1].data.f < MYGINT32_MIN || sp [-1].data.f > MYGINT32_MAX)
4177 THROW_EX (mono_get_exception_overflow (), ip);
4178 sp [-1].data.i = (gint32) sp [-1].data.f;
4179 ++ip;
4180 MINT_IN_BREAK;
4181 MINT_IN_CASE(MINT_CONV_OVF_U4_I4)
4182 if (sp [-1].data.i < 0)
4183 THROW_EX (mono_get_exception_overflow (), ip);
4184 ++ip;
4185 MINT_IN_BREAK;
4186 MINT_IN_CASE(MINT_CONV_OVF_U4_I8)
4187 if (sp [-1].data.l < 0 || sp [-1].data.l > MYGUINT32_MAX)
4188 THROW_EX (mono_get_exception_overflow (), ip);
4189 sp [-1].data.i = (guint32) sp [-1].data.l;
4190 ++ip;
4191 MINT_IN_BREAK;
4192 MINT_IN_CASE(MINT_CONV_OVF_U4_R8)
4193 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT32_MAX)
4194 THROW_EX (mono_get_exception_overflow (), ip);
4195 sp [-1].data.i = (guint32) sp [-1].data.f;
4196 ++ip;
4197 MINT_IN_BREAK;
4198 MINT_IN_CASE(MINT_CONV_OVF_I2_I4)
4199 if (sp [-1].data.i < -32768 || sp [-1].data.i > 32767)
4200 THROW_EX (mono_get_exception_overflow (), ip);
4201 ++ip;
4202 MINT_IN_BREAK;
4203 MINT_IN_CASE(MINT_CONV_OVF_I2_I8)
4204 if (sp [-1].data.l < -32768 || sp [-1].data.l > 32767)
4205 THROW_EX (mono_get_exception_overflow (), ip);
4206 sp [-1].data.i = (gint16) sp [-1].data.l;
4207 ++ip;
4208 MINT_IN_BREAK;
4209 MINT_IN_CASE(MINT_CONV_OVF_I2_R8)
4210 if (sp [-1].data.f < -32768 || sp [-1].data.f > 32767)
4211 THROW_EX (mono_get_exception_overflow (), ip);
4212 sp [-1].data.i = (gint16) sp [-1].data.f;
4213 ++ip;
4214 MINT_IN_BREAK;
4215 MINT_IN_CASE(MINT_CONV_OVF_U2_I4)
4216 if (sp [-1].data.i < 0 || sp [-1].data.i > 65535)
4217 THROW_EX (mono_get_exception_overflow (), ip);
4218 ++ip;
4219 MINT_IN_BREAK;
4220 MINT_IN_CASE(MINT_CONV_OVF_U2_I8)
4221 if (sp [-1].data.l < 0 || sp [-1].data.l > 65535)
4222 THROW_EX (mono_get_exception_overflow (), ip);
4223 sp [-1].data.i = (guint16) sp [-1].data.l;
4224 ++ip;
4225 MINT_IN_BREAK;
4226 MINT_IN_CASE(MINT_CONV_OVF_U2_R8)
4227 if (sp [-1].data.f < 0 || sp [-1].data.f > 65535)
4228 THROW_EX (mono_get_exception_overflow (), ip);
4229 sp [-1].data.i = (guint16) sp [-1].data.f;
4230 ++ip;
4231 MINT_IN_BREAK;
4232 MINT_IN_CASE(MINT_CONV_OVF_I1_I4)
4233 if (sp [-1].data.i < -128 || sp [-1].data.i > 127)
4234 THROW_EX (mono_get_exception_overflow (), ip);
4235 ++ip;
4236 MINT_IN_BREAK;
4237 MINT_IN_CASE(MINT_CONV_OVF_I1_I8)
4238 if (sp [-1].data.l < -128 || sp [-1].data.l > 127)
4239 THROW_EX (mono_get_exception_overflow (), ip);
4240 sp [-1].data.i = (gint8) sp [-1].data.l;
4241 ++ip;
4242 MINT_IN_BREAK;
4243 MINT_IN_CASE(MINT_CONV_OVF_I1_R8)
4244 if (sp [-1].data.f < -128 || sp [-1].data.f > 127)
4245 THROW_EX (mono_get_exception_overflow (), ip);
4246 sp [-1].data.i = (gint8) sp [-1].data.f;
4247 ++ip;
4248 MINT_IN_BREAK;
4249 MINT_IN_CASE(MINT_CONV_OVF_U1_I4)
4250 if (sp [-1].data.i < 0 || sp [-1].data.i > 255)
4251 THROW_EX (mono_get_exception_overflow (), ip);
4252 ++ip;
4253 MINT_IN_BREAK;
4254 MINT_IN_CASE(MINT_CONV_OVF_U1_I8)
4255 if (sp [-1].data.l < 0 || sp [-1].data.l > 255)
4256 THROW_EX (mono_get_exception_overflow (), ip);
4257 sp [-1].data.i = (guint8) sp [-1].data.l;
4258 ++ip;
4259 MINT_IN_BREAK;
4260 MINT_IN_CASE(MINT_CONV_OVF_U1_R8)
4261 if (sp [-1].data.f < 0 || sp [-1].data.f > 255)
4262 THROW_EX (mono_get_exception_overflow (), ip);
4263 sp [-1].data.i = (guint8) sp [-1].data.f;
4264 ++ip;
4265 MINT_IN_BREAK;
4266 #if 0
4267 MINT_IN_CASE(MINT_LDELEM)
4268 MINT_IN_CASE(MINT_STELEM)
4269 MINT_IN_CASE(MINT_UNBOX_ANY)
4270 #endif
4271 MINT_IN_CASE(MINT_CKFINITE)
4272 if (!isfinite(sp [-1].data.f))
4273 THROW_EX (mono_get_exception_arithmetic (), ip);
4274 ++ip;
4275 MINT_IN_BREAK;
4276 MINT_IN_CASE(MINT_MKREFANY) {
4277 c = rtm->data_items [*(guint16 *)(ip + 1)];
4279 /* The value address is on the stack */
4280 gpointer addr = sp [-1].data.p;
4281 /* Push the typedref value on the stack */
4282 sp [-1].data.p = vt_sp;
4283 vt_sp += sizeof (MonoTypedRef);
4285 MonoTypedRef *tref = sp [-1].data.p;
4286 tref->klass = c;
4287 tref->type = &c->byval_arg;
4288 tref->value = addr;
4290 ip += 2;
4291 MINT_IN_BREAK;
4293 MINT_IN_CASE(MINT_REFANYTYPE) {
4294 MonoTypedRef *tref = sp [-1].data.p;
4295 MonoType *type = tref->type;
4297 vt_sp -= sizeof (MonoTypedRef);
4298 sp [-1].data.p = vt_sp;
4299 vt_sp += 8;
4300 *(gpointer*)sp [-1].data.p = type;
4301 ip ++;
4302 MINT_IN_BREAK;
4304 MINT_IN_CASE(MINT_REFANYVAL) {
4305 MonoTypedRef *tref = sp [-1].data.p;
4306 gpointer addr = tref->value;
4308 vt_sp -= sizeof (MonoTypedRef);
4310 sp [-1].data.p = addr;
4311 ip ++;
4312 MINT_IN_BREAK;
4314 MINT_IN_CASE(MINT_LDTOKEN)
4315 sp->data.p = vt_sp;
4316 vt_sp += 8;
4317 * (gpointer *)sp->data.p = rtm->data_items[*(guint16 *)(ip + 1)];
4318 ip += 2;
4319 ++sp;
4320 MINT_IN_BREAK;
4321 MINT_IN_CASE(MINT_ADD_OVF_I4)
4322 if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
4323 THROW_EX (mono_get_exception_overflow (), ip);
4324 BINOP(i, +);
4325 MINT_IN_BREAK;
4326 MINT_IN_CASE(MINT_ADD_OVF_I8)
4327 if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
4328 THROW_EX (mono_get_exception_overflow (), ip);
4329 BINOP(l, +);
4330 MINT_IN_BREAK;
4331 MINT_IN_CASE(MINT_ADD_OVF_UN_I4)
4332 if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
4333 THROW_EX (mono_get_exception_overflow (), ip);
4334 BINOP_CAST(i, +, guint32);
4335 MINT_IN_BREAK;
4336 MINT_IN_CASE(MINT_ADD_OVF_UN_I8)
4337 if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
4338 THROW_EX (mono_get_exception_overflow (), ip);
4339 BINOP_CAST(l, +, guint64);
4340 MINT_IN_BREAK;
4341 MINT_IN_CASE(MINT_MUL_OVF_I4)
4342 if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
4343 THROW_EX (mono_get_exception_overflow (), ip);
4344 BINOP(i, *);
4345 MINT_IN_BREAK;
4346 MINT_IN_CASE(MINT_MUL_OVF_I8)
4347 if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
4348 THROW_EX (mono_get_exception_overflow (), ip);
4349 BINOP(l, *);
4350 MINT_IN_BREAK;
4351 MINT_IN_CASE(MINT_MUL_OVF_UN_I4)
4352 if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
4353 THROW_EX (mono_get_exception_overflow (), ip);
4354 BINOP_CAST(i, *, guint32);
4355 MINT_IN_BREAK;
4356 MINT_IN_CASE(MINT_MUL_OVF_UN_I8)
4357 if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
4358 THROW_EX (mono_get_exception_overflow (), ip);
4359 BINOP_CAST(l, *, guint64);
4360 MINT_IN_BREAK;
4361 MINT_IN_CASE(MINT_SUB_OVF_I4)
4362 if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
4363 THROW_EX (mono_get_exception_overflow (), ip);
4364 BINOP(i, -);
4365 MINT_IN_BREAK;
4366 MINT_IN_CASE(MINT_SUB_OVF_I8)
4367 if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
4368 THROW_EX (mono_get_exception_overflow (), ip);
4369 BINOP(l, -);
4370 MINT_IN_BREAK;
4371 MINT_IN_CASE(MINT_SUB_OVF_UN_I4)
4372 if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
4373 THROW_EX (mono_get_exception_overflow (), ip);
4374 BINOP_CAST(i, -, guint32);
4375 MINT_IN_BREAK;
4376 MINT_IN_CASE(MINT_SUB_OVF_UN_I8)
4377 if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
4378 THROW_EX (mono_get_exception_overflow (), ip);
4379 BINOP_CAST(l, -, guint64);
4380 MINT_IN_BREAK;
4381 MINT_IN_CASE(MINT_ENDFINALLY)
4382 ip ++;
4383 int clause_index = *ip;
4384 if (clause_index == exit_at_finally)
4385 goto exit_frame;
4386 while (sp > frame->stack) {
4387 --sp;
4389 if (finally_ips) {
4390 ip = finally_ips->data;
4391 finally_ips = g_slist_remove (finally_ips, ip);
4392 goto main_loop;
4394 if (frame->ex)
4395 goto handle_fault;
4396 ves_abort();
4397 MINT_IN_BREAK;
4398 MINT_IN_CASE(MINT_LEAVE) /* Fall through */
4399 MINT_IN_CASE(MINT_LEAVE_S)
4400 while (sp > frame->stack) {
4401 --sp;
4403 frame->ip = ip;
4404 if (*ip == MINT_LEAVE_S) {
4405 ip += (short) *(ip + 1);
4406 } else {
4407 ip += (gint32) READ32 (ip + 1);
4409 endfinally_ip = ip;
4410 if (frame->ex_handler != NULL && MONO_OFFSET_IN_HANDLER(frame->ex_handler, frame->ip - rtm->code)) {
4411 frame->ex_handler = NULL;
4412 frame->ex = NULL;
4414 goto handle_finally;
4415 MINT_IN_BREAK;
4416 MINT_IN_CASE(MINT_ICALL_V_V)
4417 MINT_IN_CASE(MINT_ICALL_V_P)
4418 MINT_IN_CASE(MINT_ICALL_P_V)
4419 MINT_IN_CASE(MINT_ICALL_P_P)
4420 MINT_IN_CASE(MINT_ICALL_PP_V)
4421 MINT_IN_CASE(MINT_ICALL_PI_V)
4422 MINT_IN_CASE(MINT_ICALL_PP_P)
4423 MINT_IN_CASE(MINT_ICALL_PI_P)
4424 MINT_IN_CASE(MINT_ICALL_PPP_V)
4425 MINT_IN_CASE(MINT_ICALL_PPI_V)
4426 sp = do_icall (context, *ip, sp, rtm->data_items [*(guint16 *)(ip + 1)]);
4427 if (*mono_thread_interruption_request_flag ()) {
4428 MonoException *exc = mono_thread_interruption_checkpoint ();
4429 if (exc) {
4430 frame->ex = exc;
4431 context->search_for_handler = 1;
4434 if (frame->ex != NULL)
4435 goto handle_exception;
4436 ip += 2;
4437 MINT_IN_BREAK;
4438 MINT_IN_CASE(MINT_MONO_LDPTR)
4439 sp->data.p = rtm->data_items [*(guint16 *)(ip + 1)];
4440 ip += 2;
4441 ++sp;
4442 MINT_IN_BREAK;
4443 MINT_IN_CASE(MINT_MONO_NEWOBJ)
4444 sp->data.p = mono_object_new_checked (context->domain, rtm->data_items [*(guint16 *)(ip + 1)], &error);
4445 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4446 ip += 2;
4447 sp++;
4448 MINT_IN_BREAK;
4449 MINT_IN_CASE(MINT_MONO_FREE)
4450 ++ip;
4451 --sp;
4452 g_error ("that doesn't seem right");
4453 g_free (sp->data.p);
4454 MINT_IN_BREAK;
4455 MINT_IN_CASE(MINT_MONO_RETOBJ)
4456 ++ip;
4457 sp--;
4458 stackval_from_data (mono_method_signature (frame->runtime_method->method)->ret, frame->retval, sp->data.p,
4459 mono_method_signature (frame->runtime_method->method)->pinvoke);
4460 if (sp > frame->stack)
4461 g_warning ("retobj: more values on stack: %d", sp-frame->stack);
4462 goto exit_frame;
4463 MINT_IN_CASE(MINT_MONO_TLS) {
4464 MonoTlsKey key = *(gint32 *)(ip + 1);
4465 sp->data.p = ((gpointer (*)()) mono_tls_get_tls_getter (key, FALSE)) ();
4466 sp++;
4467 ip += 3;
4468 MINT_IN_BREAK;
4470 MINT_IN_CASE(MINT_MONO_JIT_ATTACH) {
4471 ++ip;
4473 context->original_domain = NULL;
4474 MonoDomain *tls_domain = (MonoDomain *) ((gpointer (*)()) mono_tls_get_tls_getter (TLS_KEY_DOMAIN, FALSE)) ();
4475 gpointer tls_jit = ((gpointer (*)()) mono_tls_get_tls_getter (TLS_KEY_DOMAIN, FALSE)) ();
4477 if (tls_domain != context->domain || !tls_jit)
4478 context->original_domain = mono_jit_thread_attach (context->domain);
4479 MINT_IN_BREAK;
4481 MINT_IN_CASE(MINT_MONO_JIT_DETACH)
4482 ++ip;
4483 mono_jit_set_domain (context->original_domain);
4484 MINT_IN_BREAK;
4486 #define RELOP(datamem, op) \
4487 --sp; \
4488 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
4489 ++ip;
4490 MINT_IN_CASE(MINT_CEQ_I4)
4491 RELOP(i, ==);
4492 MINT_IN_BREAK;
4493 MINT_IN_CASE(MINT_CEQ0_I4)
4494 sp [-1].data.i = (sp [-1].data.i == 0);
4495 ++ip;
4496 MINT_IN_BREAK;
4497 MINT_IN_CASE(MINT_CEQ_I8)
4498 RELOP(l, ==);
4499 MINT_IN_BREAK;
4500 MINT_IN_CASE(MINT_CEQ_R8)
4501 --sp;
4502 if (isunordered (sp [-1].data.f, sp [0].data.f))
4503 sp [-1].data.i = 0;
4504 else
4505 sp [-1].data.i = sp [-1].data.f == sp [0].data.f;
4506 ++ip;
4507 MINT_IN_BREAK;
4508 MINT_IN_CASE(MINT_CGT_I4)
4509 RELOP(i, >);
4510 MINT_IN_BREAK;
4511 MINT_IN_CASE(MINT_CGT_I8)
4512 RELOP(l, >);
4513 MINT_IN_BREAK;
4514 MINT_IN_CASE(MINT_CGT_R8)
4515 --sp;
4516 if (isunordered (sp [-1].data.f, sp [0].data.f))
4517 sp [-1].data.i = 0;
4518 else
4519 sp [-1].data.i = sp [-1].data.f > sp [0].data.f;
4520 ++ip;
4521 MINT_IN_BREAK;
4523 #define RELOP_CAST(datamem, op, type) \
4524 --sp; \
4525 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4526 ++ip;
4528 MINT_IN_CASE(MINT_CGT_UN_I4)
4529 RELOP_CAST(i, >, guint32);
4530 MINT_IN_BREAK;
4531 MINT_IN_CASE(MINT_CGT_UN_I8)
4532 RELOP_CAST(l, >, guint64);
4533 MINT_IN_BREAK;
4534 MINT_IN_CASE(MINT_CGT_UN_R8)
4535 --sp;
4536 if (isunordered (sp [-1].data.f, sp [0].data.f))
4537 sp [-1].data.i = 1;
4538 else
4539 sp [-1].data.i = sp [-1].data.f > sp [0].data.f;
4540 ++ip;
4541 MINT_IN_BREAK;
4542 MINT_IN_CASE(MINT_CLT_I4)
4543 RELOP(i, <);
4544 MINT_IN_BREAK;
4545 MINT_IN_CASE(MINT_CLT_I8)
4546 RELOP(l, <);
4547 MINT_IN_BREAK;
4548 MINT_IN_CASE(MINT_CLT_R8)
4549 --sp;
4550 if (isunordered (sp [-1].data.f, sp [0].data.f))
4551 sp [-1].data.i = 0;
4552 else
4553 sp [-1].data.i = sp [-1].data.f < sp [0].data.f;
4554 ++ip;
4555 MINT_IN_BREAK;
4556 MINT_IN_CASE(MINT_CLT_UN_I4)
4557 RELOP_CAST(i, <, guint32);
4558 MINT_IN_BREAK;
4559 MINT_IN_CASE(MINT_CLT_UN_I8)
4560 RELOP_CAST(l, <, guint64);
4561 MINT_IN_BREAK;
4562 MINT_IN_CASE(MINT_CLT_UN_R8)
4563 --sp;
4564 if (isunordered (sp [-1].data.f, sp [0].data.f))
4565 sp [-1].data.i = 1;
4566 else
4567 sp [-1].data.i = sp [-1].data.f < sp [0].data.f;
4568 ++ip;
4569 MINT_IN_BREAK;
4570 MINT_IN_CASE(MINT_LDFTN) {
4571 sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)];
4572 ++sp;
4573 ip += 2;
4574 MINT_IN_BREAK;
4576 MINT_IN_CASE(MINT_LDVIRTFTN) {
4577 RuntimeMethod *m = rtm->data_items [* (guint16 *)(ip + 1)];
4578 ip += 2;
4579 --sp;
4580 if (!sp->data.p)
4581 THROW_EX (mono_get_exception_null_reference (), ip - 2);
4583 sp->data.p = get_virtual_method (context->domain, m, sp->data.p);
4584 ++sp;
4585 MINT_IN_BREAK;
4588 #define LDARG(datamem, argtype) \
4589 sp->data.datamem = * (argtype *)(frame->args + * (guint16 *)(ip + 1)); \
4590 ip += 2; \
4591 ++sp;
4593 MINT_IN_CASE(MINT_LDARG_I1) LDARG(i, gint8); MINT_IN_BREAK;
4594 MINT_IN_CASE(MINT_LDARG_U1) LDARG(i, guint8); MINT_IN_BREAK;
4595 MINT_IN_CASE(MINT_LDARG_I2) LDARG(i, gint16); MINT_IN_BREAK;
4596 MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK;
4597 MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK;
4598 MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK;
4599 MINT_IN_CASE(MINT_LDARG_R4) LDARG(f, float); MINT_IN_BREAK;
4600 MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK;
4601 MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK;
4602 MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK;
4604 MINT_IN_CASE(MINT_LDARG_VT)
4605 sp->data.p = vt_sp;
4606 i32 = READ32(ip + 2);
4607 memcpy(sp->data.p, frame->args + * (guint16 *)(ip + 1), i32);
4608 vt_sp += (i32 + 7) & ~7;
4609 ip += 4;
4610 ++sp;
4611 MINT_IN_BREAK;
4613 #define STARG(datamem, argtype) \
4614 --sp; \
4615 * (argtype *)(frame->args + * (guint16 *)(ip + 1)) = sp->data.datamem; \
4616 ip += 2; \
4618 MINT_IN_CASE(MINT_STARG_I1) STARG(i, gint8); MINT_IN_BREAK;
4619 MINT_IN_CASE(MINT_STARG_U1) STARG(i, guint8); MINT_IN_BREAK;
4620 MINT_IN_CASE(MINT_STARG_I2) STARG(i, gint16); MINT_IN_BREAK;
4621 MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK;
4622 MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK;
4623 MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK;
4624 MINT_IN_CASE(MINT_STARG_R4) STARG(f, float); MINT_IN_BREAK;
4625 MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK;
4626 MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK;
4627 MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK;
4629 MINT_IN_CASE(MINT_STARG_VT)
4630 i32 = READ32(ip + 2);
4631 --sp;
4632 memcpy(frame->args + * (guint16 *)(ip + 1), sp->data.p, i32);
4633 vt_sp -= (i32 + 7) & ~7;
4634 ip += 4;
4635 MINT_IN_BREAK;
4637 #define STINARG(datamem, argtype) \
4638 do { \
4639 int n = * (guint16 *)(ip + 1); \
4640 * (argtype *)(frame->args + rtm->arg_offsets [n]) = frame->stack_args [n].data.datamem; \
4641 ip += 2; \
4642 } while (0)
4644 MINT_IN_CASE(MINT_STINARG_I1) STINARG(i, gint8); MINT_IN_BREAK;
4645 MINT_IN_CASE(MINT_STINARG_U1) STINARG(i, guint8); MINT_IN_BREAK;
4646 MINT_IN_CASE(MINT_STINARG_I2) STINARG(i, gint16); MINT_IN_BREAK;
4647 MINT_IN_CASE(MINT_STINARG_U2) STINARG(i, guint16); MINT_IN_BREAK;
4648 MINT_IN_CASE(MINT_STINARG_I4) STINARG(i, gint32); MINT_IN_BREAK;
4649 MINT_IN_CASE(MINT_STINARG_I8) STINARG(l, gint64); MINT_IN_BREAK;
4650 MINT_IN_CASE(MINT_STINARG_R4) STINARG(f, float); MINT_IN_BREAK;
4651 MINT_IN_CASE(MINT_STINARG_R8) STINARG(f, double); MINT_IN_BREAK;
4652 MINT_IN_CASE(MINT_STINARG_O) STINARG(p, gpointer); MINT_IN_BREAK;
4653 MINT_IN_CASE(MINT_STINARG_P) STINARG(p, gpointer); MINT_IN_BREAK;
4655 MINT_IN_CASE(MINT_STINARG_VT) {
4656 int n = * (guint16 *)(ip + 1);
4657 i32 = READ32(ip + 2);
4658 memcpy (frame->args + rtm->arg_offsets [n], frame->stack_args [n].data.p, i32);
4659 ip += 4;
4660 MINT_IN_BREAK;
4663 MINT_IN_CASE(MINT_LDARGA)
4664 sp->data.p = frame->args + * (guint16 *)(ip + 1);
4665 ip += 2;
4666 ++sp;
4667 MINT_IN_BREAK;
4669 #define LDLOC(datamem, argtype) \
4670 sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
4671 ip += 2; \
4672 ++sp;
4674 MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK;
4675 MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK;
4676 MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK;
4677 MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK;
4678 MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK;
4679 MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK;
4680 MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f, float); MINT_IN_BREAK;
4681 MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK;
4682 MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK;
4683 MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK;
4685 MINT_IN_CASE(MINT_LDLOC_VT)
4686 sp->data.p = vt_sp;
4687 i32 = READ32(ip + 2);
4688 memcpy(sp->data.p, locals + * (guint16 *)(ip + 1), i32);
4689 vt_sp += (i32 + 7) & ~7;
4690 ip += 4;
4691 ++sp;
4692 MINT_IN_BREAK;
4694 MINT_IN_CASE(MINT_LDLOCA_S)
4695 sp->data.p = locals + * (guint16 *)(ip + 1);
4696 ip += 2;
4697 ++sp;
4698 MINT_IN_BREAK;
4700 #define STLOC(datamem, argtype) \
4701 --sp; \
4702 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
4703 ip += 2;
4705 MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK;
4706 MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK;
4707 MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK;
4708 MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK;
4709 MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK;
4710 MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK;
4711 MINT_IN_CASE(MINT_STLOC_R4) STLOC(f, float); MINT_IN_BREAK;
4712 MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK;
4713 MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK;
4714 MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK;
4716 #define STLOC_NP(datamem, argtype) \
4717 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
4718 ip += 2;
4720 MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK;
4721 MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK;
4723 MINT_IN_CASE(MINT_STLOC_VT)
4724 i32 = READ32(ip + 2);
4725 --sp;
4726 memcpy(locals + * (guint16 *)(ip + 1), sp->data.p, i32);
4727 vt_sp -= (i32 + 7) & ~7;
4728 ip += 4;
4729 MINT_IN_BREAK;
4731 MINT_IN_CASE(MINT_LOCALLOC) {
4732 if (sp != frame->stack + 1) /*FIX?*/
4733 THROW_EX (mono_get_exception_execution_engine (NULL), ip);
4735 int len = sp [-1].data.i;
4736 sp [-1].data.p = alloca (len);
4737 MonoMethodHeader *header = mono_method_get_header_checked (frame->runtime_method->method, &error);
4738 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4739 if (header && header->init_locals)
4740 memset (sp [-1].data.p, 0, len);
4741 ++ip;
4742 MINT_IN_BREAK;
4744 MINT_IN_CASE(MINT_ENDFILTER)
4745 /* top of stack is result of filter */
4746 frame->retval = &sp [-1];
4747 goto exit_frame;
4748 MINT_IN_CASE(MINT_INITOBJ)
4749 --sp;
4750 memset (sp->data.vt, 0, READ32(ip + 1));
4751 ip += 3;
4752 MINT_IN_BREAK;
4753 MINT_IN_CASE(MINT_CPBLK)
4754 sp -= 3;
4755 if (!sp [0].data.p || !sp [1].data.p)
4756 THROW_EX (mono_get_exception_null_reference(), ip - 1);
4757 ++ip;
4758 /* FIXME: value and size may be int64... */
4759 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
4760 MINT_IN_BREAK;
4761 #if 0
4762 MINT_IN_CASE(MINT_CONSTRAINED_) {
4763 guint32 token;
4764 /* FIXME: implement */
4765 ++ip;
4766 token = READ32 (ip);
4767 ip += 2;
4768 MINT_IN_BREAK;
4770 #endif
4771 MINT_IN_CASE(MINT_INITBLK)
4772 sp -= 3;
4773 if (!sp [0].data.p)
4774 THROW_EX (mono_get_exception_null_reference(), ip - 1);
4775 ++ip;
4776 /* FIXME: value and size may be int64... */
4777 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
4778 MINT_IN_BREAK;
4779 #if 0
4780 MINT_IN_CASE(MINT_NO_)
4781 /* FIXME: implement */
4782 ip += 2;
4783 MINT_IN_BREAK;
4784 #endif
4785 MINT_IN_CASE(MINT_RETHROW)
4787 * need to clarify what this should actually do:
4788 * start the search from the last found handler in
4789 * this method or continue in the caller or what.
4790 * Also, do we need to run finally/fault handlers after a retrow?
4791 * Well, this implementation will follow the usual search
4792 * for an handler, considering the current ip as throw spot.
4793 * We need to NULL frame->ex_handler for the later code to
4794 * actually run the new found handler.
4796 frame->ex_handler = NULL;
4797 THROW_EX (frame->ex, ip - 1);
4798 MINT_IN_BREAK;
4799 MINT_IN_DEFAULT
4800 g_print ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname[*ip], ip-rtm->code);
4801 THROW_EX (mono_get_exception_execution_engine ("Unimplemented opcode"), ip);
4805 g_assert_not_reached ();
4807 * Exception handling code.
4808 * The exception object is stored in frame->ex.
4811 handle_exception:
4813 int i;
4814 guint32 ip_offset;
4815 MonoInvocation *inv;
4816 MonoExceptionClause *clause;
4817 /*char *message;*/
4818 MonoObject *ex_obj;
4820 #if DEBUG_INTERP
4821 if (tracing)
4822 g_print ("* Handling exception '%s' at IL_%04x\n",
4823 frame->ex == NULL ? "** Unknown **" : mono_object_class (frame->ex)->name,
4824 rtm == NULL ? 0 : frame->ip - rtm->code);
4825 #endif
4826 if (die_on_exception)
4827 goto die_on_ex;
4829 for (inv = frame; inv; inv = inv->parent) {
4830 MonoMethod *method;
4831 if (inv->runtime_method == NULL)
4832 continue;
4833 method = inv->runtime_method->method;
4834 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
4835 continue;
4836 if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))
4837 continue;
4838 if (inv->ip == NULL)
4839 continue;
4840 ip_offset = inv->ip - inv->runtime_method->code;
4841 inv->ex_handler = NULL; /* clear this in case we are trhowing an exception while handling one - this one wins */
4842 for (i = 0; i < inv->runtime_method->num_clauses; ++i) {
4843 clause = &inv->runtime_method->clauses [i];
4844 #if DEBUG_INTERP
4845 g_print ("* clause [%d]: %p\n", i, clause);
4846 #endif
4847 if (!MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
4848 continue;
4850 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4851 #if DEBUG_INTERP
4852 if (tracing)
4853 g_print ("* Filter found at '%s'\n", method->name);
4854 #endif
4855 MonoInvocation dup_frame;
4856 stackval retval;
4857 memcpy (&dup_frame, inv, sizeof (MonoInvocation));
4858 dup_frame.retval = &retval;
4859 ves_exec_method_with_context (&dup_frame, context, inv->runtime_method->code + clause->data.filter_offset, frame->ex, -1);
4860 if (dup_frame.retval->data.i) {
4861 #if DEBUG_INTERP
4862 if (tracing)
4863 g_print ("* Matched Filter at '%s'\n", method->name);
4864 #endif
4865 inv->ex_handler = clause;
4866 goto handle_finally;
4868 } else if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) {
4869 MonoObject *isinst_obj = mono_object_isinst_checked ((MonoObject*)frame->ex, clause->data.catch_class, &error);
4870 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4871 if (isinst_obj) {
4873 * OK, we found an handler, now we need to execute the finally
4874 * and fault blocks before branching to the handler code.
4876 #if DEBUG_INTERP
4877 if (tracing)
4878 g_print ("* Found handler at '%s'\n", method->name);
4879 #endif
4880 inv->ex_handler = clause;
4881 goto handle_finally;
4887 * If we get here, no handler was found: print a stack trace.
4889 for (inv = frame; inv; inv = inv->parent) {
4890 if (inv->invoke_trap)
4891 goto handle_finally;
4893 die_on_ex:
4894 ex_obj = (MonoObject *) frame->ex;
4895 mono_unhandled_exception (ex_obj);
4896 MonoJitTlsData *jit_tls = (MonoJitTlsData *) mono_tls_get_jit_tls ();
4897 jit_tls->abort_func (ex_obj);
4898 g_assert_not_reached ();
4900 handle_finally:
4902 int i;
4903 guint32 ip_offset;
4904 MonoExceptionClause *clause;
4905 GSList *old_list = finally_ips;
4906 MonoMethod *method = frame->runtime_method->method;
4907 MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
4908 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4910 #if DEBUG_INTERP
4911 if (tracing)
4912 g_print ("* Handle finally IL_%04x\n", endfinally_ip == NULL ? 0 : endfinally_ip - rtm->code);
4913 #endif
4914 if (rtm == NULL || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
4915 || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
4916 goto exit_frame;
4918 ip_offset = frame->ip - rtm->code;
4920 if (endfinally_ip != NULL)
4921 finally_ips = g_slist_prepend(finally_ips, (void *)endfinally_ip);
4922 for (i = 0; i < header->num_clauses; ++i)
4923 if (frame->ex_handler == &rtm->clauses [i])
4924 break;
4925 while (i > 0) {
4926 --i;
4927 clause = &rtm->clauses [i];
4928 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && (endfinally_ip == NULL || !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - rtm->code)))) {
4929 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
4930 ip = rtm->code + clause->handler_offset;
4931 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
4932 #if DEBUG_INTERP
4933 if (tracing)
4934 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
4935 #endif
4940 endfinally_ip = NULL;
4942 if (old_list != finally_ips && finally_ips) {
4943 ip = finally_ips->data;
4944 finally_ips = g_slist_remove (finally_ips, ip);
4945 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
4946 goto main_loop;
4950 * If an exception is set, we need to execute the fault handler, too,
4951 * otherwise, we continue normally.
4953 if (frame->ex)
4954 goto handle_fault;
4955 ves_abort();
4957 handle_fault:
4959 int i;
4960 guint32 ip_offset;
4961 MonoExceptionClause *clause;
4962 MonoMethod *method = frame->runtime_method->method;
4963 MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
4964 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4966 #if DEBUG_INTERP
4967 if (tracing)
4968 g_print ("* Handle fault\n");
4969 #endif
4970 ip_offset = frame->ip - rtm->code;
4971 for (i = 0; i < header->num_clauses; ++i) {
4972 clause = &rtm->clauses [i];
4973 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
4974 ip = rtm->code + clause->handler_offset;
4975 #if DEBUG_INTERP
4976 if (tracing)
4977 g_print ("* Executing handler at IL_%04x\n", clause->handler_offset);
4978 #endif
4979 goto main_loop;
4983 * If the handler for the exception was found in this method, we jump
4984 * to it right away, otherwise we return and let the caller run
4985 * the finally, fault and catch blocks.
4986 * This same code should be present in the endfault opcode, but it
4987 * is corrently not assigned in the ECMA specs: LAMESPEC.
4989 if (frame->ex_handler) {
4990 #if DEBUG_INTERP
4991 if (tracing)
4992 g_print ("* Executing handler at IL_%04x\n", frame->ex_handler->handler_offset);
4993 #endif
4994 ip = rtm->code + frame->ex_handler->handler_offset;
4995 sp = frame->stack;
4996 vt_sp = (unsigned char *) sp + rtm->stack_size;
4997 sp->data.p = frame->ex;
4998 ++sp;
4999 goto main_loop;
5001 goto exit_frame;
5003 exit_frame:
5004 DEBUG_LEAVE ();
5007 void
5008 ves_exec_method (MonoInvocation *frame)
5010 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
5011 ThreadContext context_struct;
5012 MonoError error;
5013 jmp_buf env;
5015 frame->ex = NULL;
5017 if (setjmp(env)) {
5018 mono_unhandled_exception ((MonoObject*)frame->ex);
5019 return;
5021 if (context == NULL) {
5022 context = &context_struct;
5023 context_struct.domain = mono_domain_get ();
5024 context_struct.base_frame = frame;
5025 context_struct.current_frame = NULL;
5026 context_struct.env_frame = frame;
5027 context_struct.current_env = &env;
5028 context_struct.search_for_handler = 0;
5029 context_struct.managed_code = 0;
5030 mono_native_tls_set_value (thread_context_id, context);
5032 frame->ip = NULL;
5033 frame->parent = context->current_frame;
5034 frame->runtime_method = mono_interp_get_runtime_method (context->domain, frame->method, &error);
5035 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
5036 context->managed_code = 1;
5037 ves_exec_method_with_context (frame, context, NULL, NULL, -1);
5038 context->managed_code = 0;
5039 if (frame->ex) {
5040 if (context != &context_struct && context->current_env) {
5041 context->env_frame->ex = frame->ex;
5042 longjmp (*context->current_env, 1);
5044 else
5045 mono_unhandled_exception ((MonoObject*)frame->ex);
5047 if (context->base_frame == frame)
5048 mono_native_tls_set_value (thread_context_id, NULL);
5049 else
5050 context->current_frame = frame->parent;
5053 void
5054 mono_interp_parse_options (const char *options)
5056 char **args, **ptr;
5058 args = g_strsplit (options, ",", -1);
5059 for (ptr = args; ptr && *ptr; ptr ++) {
5060 char *arg = *ptr;
5062 if (strncmp (arg, "jit=", 4) == 0)
5063 jit_classes = g_slist_prepend (jit_classes, arg + 4);
5067 void
5068 mono_interp_init ()
5070 mono_native_tls_alloc (&thread_context_id, NULL);
5071 mono_native_tls_set_value (thread_context_id, NULL);
5073 mono_interp_transform_init ();
5076 typedef int (*TestMethod) (void);
5078 static void
5079 interp_regression_step (MonoImage *image, int verbose, int *total_run, int *total, GTimer *timer, MonoDomain *domain)
5081 int result, expected, failed, cfailed, run;
5082 double elapsed, transform_time;
5083 int i;
5084 MonoObject *result_obj;
5085 static gboolean filter_method_init = FALSE;
5086 static const char *filter_method = NULL;
5088 g_print ("Test run: image=%s\n", mono_image_get_filename (image));
5089 cfailed = failed = run = 0;
5090 transform_time = elapsed = 0.0;
5092 g_timer_start (timer);
5093 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
5094 MonoObject *exc = NULL;
5095 MonoError error;
5096 MonoMethod *method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
5097 if (!method) {
5098 mono_error_cleanup (&error); /* FIXME don't swallow the error */
5099 continue;
5102 if (!filter_method_init) {
5103 filter_method = g_getenv ("INTERP_FILTER_METHOD");
5104 filter_method_init = TRUE;
5106 gboolean filter = FALSE;
5107 if (filter_method) {
5108 const char *name = filter_method;
5110 if ((strchr (name, '.') > name) || strchr (name, ':')) {
5111 MonoMethodDesc *desc = mono_method_desc_new (name, TRUE);
5112 filter = mono_method_desc_full_match (desc, method);
5113 mono_method_desc_free (desc);
5114 } else {
5115 filter = strcmp (method->name, name) == 0;
5117 } else { /* no filter, check for `Category' attribute on method */
5118 filter = TRUE;
5119 MonoCustomAttrInfo* ainfo = mono_custom_attrs_from_method_checked (method, &error);
5120 mono_error_cleanup (&error);
5122 if (ainfo) {
5123 int j;
5124 for (j = 0; j < ainfo->num_attrs && filter; ++j) {
5125 MonoCustomAttrEntry *centry = &ainfo->attrs [j];
5126 if (centry->ctor == NULL)
5127 continue;
5129 MonoClass *klass = centry->ctor->klass;
5130 if (strcmp (klass->name, "CategoryAttribute"))
5131 continue;
5133 MonoObject *obj = mono_custom_attrs_get_attr_checked (ainfo, klass, &error);
5134 /* FIXME: there is an ordering problem if there're multiple attributes, do this instead:
5135 * MonoObject *obj = create_custom_attr (ainfo->image, centry->ctor, centry->data, centry->data_size, &error); */
5136 mono_error_cleanup (&error);
5137 MonoMethod *getter = mono_class_get_method_from_name (klass, "get_Category", -1);
5138 MonoObject *str = mono_interp_runtime_invoke (getter, obj, NULL, &exc, &error);
5139 mono_error_cleanup (&error);
5140 char *utf8_str = mono_string_to_utf8_checked ((MonoString *) str, &error);
5141 mono_error_cleanup (&error);
5142 if (!strcmp (utf8_str, "!INTERPRETER")) {
5143 g_print ("skip %s...\n", method->name);
5144 filter = FALSE;
5149 if (strncmp (method->name, "test_", 5) == 0 && filter) {
5150 MonoError interp_error;
5151 MonoObject *exc = NULL;
5153 result_obj = mono_interp_runtime_invoke (method, NULL, NULL, &exc, &interp_error);
5154 if (!mono_error_ok (&interp_error)) {
5155 cfailed++;
5156 g_print ("Test '%s' execution failed.\n", method->name);
5157 } else if (exc != NULL) {
5158 g_print ("Exception in Test '%s' occured:\n", method->name);
5159 mono_object_describe (exc);
5160 run++;
5161 failed++;
5162 } else {
5163 result = *(gint32 *) mono_object_unbox (result_obj);
5164 expected = atoi (method->name + 5); // FIXME: oh no.
5165 run++;
5167 if (result != expected) {
5168 failed++;
5169 g_print ("Test '%s' failed result (got %d, expected %d).\n", method->name, result, expected);
5174 g_timer_stop (timer);
5175 elapsed = g_timer_elapsed (timer, NULL);
5176 if (failed > 0 || cfailed > 0){
5177 g_print ("Results: total tests: %d, failed: %d, cfailed: %d (pass: %.2f%%)\n",
5178 run, failed, cfailed, 100.0*(run-failed-cfailed)/run);
5179 } else {
5180 g_print ("Results: total tests: %d, all pass \n", run);
5183 g_print ("Elapsed time: %f secs (%f, %f)\n\n", elapsed,
5184 elapsed - transform_time, transform_time);
5185 *total += failed + cfailed;
5186 *total_run += run;
5189 static int
5190 interp_regression (MonoImage *image, int verbose, int *total_run)
5192 MonoMethod *method;
5193 GTimer *timer = g_timer_new ();
5194 MonoDomain *domain = mono_domain_get ();
5195 guint32 i;
5196 int total;
5198 /* load the metadata */
5199 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
5200 MonoError error;
5201 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
5202 if (!method) {
5203 mono_error_cleanup (&error);
5204 continue;
5206 mono_class_init (method->klass);
5209 total = 0;
5210 *total_run = 0;
5211 interp_regression_step (image, verbose, total_run, &total, timer, domain);
5213 g_timer_destroy (timer);
5214 return total;
5218 mono_interp_regression_list (int verbose, int count, char *images [])
5220 int i, total, total_run, run;
5222 total_run = total = 0;
5223 for (i = 0; i < count; ++i) {
5224 MonoAssembly *ass = mono_assembly_open_predicate (images [i], FALSE, FALSE, NULL, NULL, NULL);
5225 if (!ass) {
5226 g_warning ("failed to load assembly: %s", images [i]);
5227 continue;
5229 total += interp_regression (mono_assembly_get_image (ass), verbose, &run);
5230 total_run += run;
5232 if (total > 0) {
5233 g_print ("Overall results: tests: %d, failed: %d (pass: %.2f%%)\n", total_run, total, 100.0*(total_run-total)/total_run);
5234 } else {
5235 g_print ("Overall results: tests: %d, 100%% pass\n", total_run);
5238 return total;
5242 * mono_interp_set_resume_state:
5244 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
5246 void
5247 mono_interp_set_resume_state (MonoException *ex, StackFrameInfo *frame, gpointer handler_ip)
5249 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
5251 context->has_resume_state = TRUE;
5252 context->handler_frame = frame->interp_frame;
5253 /* This is on the stack, so it doesn't need a wbarrier */
5254 context->handler_frame->ex = ex;
5255 context->handler_ip = handler_ip;
5259 * mono_interp_run_finally:
5261 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
5262 * frame->interp_frame.
5264 void
5265 mono_interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip)
5267 MonoInvocation *iframe = frame->interp_frame;
5268 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
5270 ves_exec_method_with_context (iframe, context, handler_ip, NULL, clause_index);
5273 typedef struct {
5274 MonoInvocation *current;
5275 } StackIter;
5278 * mono_interp_frame_iter_init:
5280 * Initialize an iterator for iterating through interpreted frames.
5282 void
5283 mono_interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data)
5285 StackIter *stack_iter = (StackIter*)iter;
5287 stack_iter->current = (MonoInvocation*)interp_exit_data;
5290 gboolean
5291 mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
5293 StackIter *stack_iter = (StackIter*)iter;
5294 MonoInvocation *iframe = stack_iter->current;
5296 memset (frame, 0, sizeof (StackFrameInfo));
5297 /* pinvoke frames doesn't have runtime_method set */
5298 while (iframe && !iframe->runtime_method)
5299 iframe = iframe->parent;
5300 if (!iframe)
5301 return FALSE;
5303 frame->type = FRAME_TYPE_INTERP;
5304 frame->interp_frame = iframe;
5305 frame->method = iframe->runtime_method->method;
5306 frame->actual_method = frame->method;
5307 /* This is the offset in the interpreter IR */
5308 frame->native_offset = iframe->ip - iframe->runtime_method->code;
5309 frame->ji = iframe->runtime_method->jinfo;
5311 stack_iter->current = iframe->parent;
5313 return TRUE;