3 * transform CIL into different opcodes for more
4 * efficient interpretation
6 * Written by Bernie Solomon (bernard@ugsolutions.com)
11 #include <mono/metadata/appdomain.h>
12 #include <mono/metadata/debug-helpers.h>
13 #include <mono/metadata/exception.h>
14 #include <mono/metadata/mono-endian.h>
15 #include <mono/metadata/marshal.h>
16 #include <mono/metadata/profiler-private.h>
17 #include <mono/metadata/tabledefs.h>
19 #include <mono/mini/mini.h>
22 #include "interp-internals.h"
25 // TODO: export from marshal.c
26 MonoDelegate* mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn);
40 MonoMethodHeader *header;
42 const unsigned char *il_code;
43 const unsigned char *ip;
44 const unsigned char *last_ip;
45 const unsigned char *in_start;
49 StackInfo **stack_state;
52 unsigned char *is_bb_start;
53 unsigned short *new_code;
54 unsigned short *new_code_end;
55 unsigned short *new_ip;
56 unsigned short *last_new_ip;
57 unsigned int max_code_size;
60 unsigned int max_stack_height;
62 unsigned int max_vt_sp;
66 GHashTable *data_hash;
70 #define MINT_TYPE_I1 0
71 #define MINT_TYPE_U1 1
72 #define MINT_TYPE_I2 2
73 #define MINT_TYPE_U2 3
74 #define MINT_TYPE_I4 4
75 #define MINT_TYPE_I8 5
76 #define MINT_TYPE_R4 6
77 #define MINT_TYPE_R8 7
80 #define MINT_TYPE_VT 10
82 #define STACK_TYPE_I4 0
83 #define STACK_TYPE_I8 1
84 #define STACK_TYPE_R8 2
85 #define STACK_TYPE_O 3
86 #define STACK_TYPE_VT 4
87 #define STACK_TYPE_MP 5
88 #define STACK_TYPE_F 6
90 static const char *stack_type_string [] = { "I4", "I8", "R8", "O ", "VT", "MP", "F " };
92 #if SIZEOF_VOID_P == 8
93 #define STACK_TYPE_I STACK_TYPE_I8
95 #define STACK_TYPE_I STACK_TYPE_I4
98 static int stack_type [] = {
100 STACK_TYPE_I4, /*U1*/
101 STACK_TYPE_I4, /*I2*/
102 STACK_TYPE_I4, /*U2*/
103 STACK_TYPE_I4, /*I4*/
104 STACK_TYPE_I8, /*I8*/
105 STACK_TYPE_R8, /*R4*/
106 STACK_TYPE_R8, /*R8*/
113 grow_code (TransformData *td)
115 unsigned int old_ip_offset = td->new_ip - td->new_code;
116 unsigned int old_last_ip_offset = td->last_new_ip - td->new_code;
117 g_assert (old_ip_offset <= td->max_code_size);
118 td->new_code = g_realloc (td->new_code, (td->max_code_size *= 2) * sizeof (td->new_code [0]));
119 td->new_code_end = td->new_code + td->max_code_size;
120 td->new_ip = td->new_code + old_ip_offset;
121 td->last_new_ip = td->new_code + old_last_ip_offset;
124 #define ENSURE_CODE(td, n) \
126 if ((td)->new_ip + (n) > (td)->new_code_end) \
130 #define ADD_CODE(td, n) \
132 if ((td)->new_ip == (td)->new_code_end) \
134 *(td)->new_ip++ = (n); \
137 #define CHECK_STACK(td, n) \
139 int stack_size = (td)->sp - (td)->stack; \
140 if (stack_size < (n)) \
141 g_warning ("%s.%s: not enough values (%d < %d) on stack at %04x", \
142 (td)->method->klass->name, (td)->method->name, \
143 stack_size, n, (td)->ip - (td)->il_code); \
146 #define ENSURE_I4(td, sp_off) \
148 if ((td)->sp [-sp_off].type == STACK_TYPE_I8) \
149 ADD_CODE(td, sp_off == 1 ? MINT_CONV_I4_I8 : MINT_CONV_I4_I8_SP); \
153 handle_branch(TransformData *td, int short_op, int long_op, int offset)
155 int shorten_branch = 0;
156 int target = td->ip + offset - td->il_code;
157 if (target < 0 || target >= td->code_size)
158 g_assert_not_reached ();
159 if (offset > 0 && td->stack_height [target] < 0) {
160 td->stack_height [target] = td->sp - td->stack;
161 if (td->stack_height [target] > 0)
162 td->stack_state [target] = g_memdup (td->stack, td->stack_height [target] * sizeof (td->stack [0]));
163 td->vt_stack_size [target] = td->vt_sp;
166 offset = td->in_offsets [target] - (td->new_ip - td->new_code);
167 if (offset >= -32768) {
171 int prev = td->forward_refs [target];
172 td->forward_refs [td->ip - td->il_code] = prev;
173 td->forward_refs [target] = td->ip - td->il_code;
175 if (td->header->code_size <= 25000) /* FIX to be precise somehow? */
178 if (shorten_branch) {
179 ADD_CODE(td, short_op);
180 ADD_CODE(td, offset);
182 ADD_CODE(td, long_op);
183 ADD_CODE(td, * (unsigned short *)(&offset));
184 ADD_CODE(td, * ((unsigned short *)&offset + 1));
189 one_arg_branch(TransformData *td, int mint_op, int offset)
191 int type = td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP ? STACK_TYPE_I : td->sp [-1].type;
192 int long_op = mint_op + type - STACK_TYPE_I4;
193 int short_op = long_op + MINT_BRFALSE_I4_S - MINT_BRFALSE_I4;
196 handle_branch (td, short_op, long_op, offset);
200 two_arg_branch(TransformData *td, int mint_op, int offset)
202 int type1 = td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP ? STACK_TYPE_I : td->sp [-1].type;
203 int type2 = td->sp [-2].type == STACK_TYPE_O || td->sp [-2].type == STACK_TYPE_MP ? STACK_TYPE_I : td->sp [-2].type;
204 int long_op = mint_op + type1 - STACK_TYPE_I4;
205 int short_op = long_op + MINT_BEQ_I4_S - MINT_BEQ_I4;
207 if (type1 == STACK_TYPE_I4 && type2 == STACK_TYPE_I8) {
208 ADD_CODE(td, MINT_CONV_I8_I4);
209 td->in_offsets [td->ip - td->il_code]++;
210 } else if (type1 == STACK_TYPE_I8 && type2 == STACK_TYPE_I4) {
211 ADD_CODE(td, MINT_CONV_I8_I4_SP);
212 td->in_offsets [td->ip - td->il_code]++;
213 } else if (type1 != type2) {
214 g_warning("%s.%s: branch type mismatch %d %d",
215 td->method->klass->name, td->method->name,
216 td->sp [-1].type, td->sp [-2].type);
219 handle_branch (td, short_op, long_op, offset);
223 unary_arith_op(TransformData *td, int mint_op)
225 int op = mint_op + td->sp [-1].type - STACK_TYPE_I4;
231 binary_arith_op(TransformData *td, int mint_op)
233 int type1 = td->sp [-2].type;
234 int type2 = td->sp [-1].type;
236 #if SIZEOF_VOID_P == 8
237 if ((type1 == STACK_TYPE_MP || type1 == STACK_TYPE_I8) && type2 == STACK_TYPE_I4) {
238 ADD_CODE(td, MINT_CONV_I8_I4);
239 type2 = STACK_TYPE_I8;
241 if (type1 == STACK_TYPE_I4 && (type2 == STACK_TYPE_MP || type2 == STACK_TYPE_I8)) {
242 ADD_CODE(td, MINT_CONV_I8_I4_SP);
243 type1 = STACK_TYPE_I8;
244 td->sp [-2].type = STACK_TYPE_I8;
247 if (type1 == STACK_TYPE_MP)
248 type1 = STACK_TYPE_I;
249 if (type2 == STACK_TYPE_MP)
250 type2 = STACK_TYPE_I;
251 if (type1 != type2) {
252 g_warning("%s.%s: %04x arith type mismatch %s %d %d",
253 td->method->klass->name, td->method->name,
254 td->ip - td->il_code, mono_interp_opname[mint_op], type1, type2);
256 op = mint_op + type1 - STACK_TYPE_I4;
263 shift_op(TransformData *td, int mint_op)
265 int op = mint_op + td->sp [-2].type - STACK_TYPE_I4;
267 if (td->sp [-1].type != STACK_TYPE_I4) {
268 g_warning("%s.%s: shift type mismatch %d",
269 td->method->klass->name, td->method->name,
277 mint_type(MonoType *type)
282 switch (type->type) {
286 case MONO_TYPE_BOOLEAN:
298 #if SIZEOF_VOID_P == 4
312 case MONO_TYPE_STRING:
313 case MONO_TYPE_SZARRAY:
314 case MONO_TYPE_CLASS:
315 case MONO_TYPE_OBJECT:
316 case MONO_TYPE_ARRAY:
318 case MONO_TYPE_VALUETYPE:
319 if (type->data.klass->enumtype) {
320 type = mono_class_enum_basetype (type->data.klass);
324 case MONO_TYPE_GENERICINST:
325 type = &type->data.generic_class->container_class->byval_arg;
328 g_warning ("got type 0x%02x", type->type);
329 g_assert_not_reached ();
335 can_store (int stack_type, int var_type)
337 if (stack_type == STACK_TYPE_O || stack_type == STACK_TYPE_MP)
338 stack_type = STACK_TYPE_I;
339 if (var_type == STACK_TYPE_O || var_type == STACK_TYPE_MP)
340 var_type = STACK_TYPE_I;
341 return stack_type == var_type;
344 #define SET_SIMPLE_TYPE(s, ty) \
351 #define SET_TYPE(s, ty, k) \
358 #define PUSH_SIMPLE_TYPE(td, ty) \
362 sp_height = (td)->sp - (td)->stack; \
363 if (sp_height > (td)->max_stack_height) \
364 (td)->max_stack_height = sp_height; \
365 SET_SIMPLE_TYPE((td)->sp - 1, ty); \
368 #define PUSH_TYPE(td, ty, k) \
372 sp_height = (td)->sp - (td)->stack; \
373 if (sp_height > (td)->max_stack_height) \
374 (td)->max_stack_height = sp_height; \
375 SET_TYPE((td)->sp - 1, ty, k); \
378 #define PUSH_VT(td, size) \
380 (td)->vt_sp += ((size) + 7) & ~7; \
381 if ((td)->vt_sp > (td)->max_vt_sp) \
382 (td)->max_vt_sp = (td)->vt_sp; \
385 #define POP_VT(td, size) \
387 (td)->vt_sp -= ((size) + 7) & ~7; \
390 #if NO_UNALIGNED_ACCESS
391 #define WRITE32(td, v) \
393 ENSURE_CODE(td, 2); \
394 * (guint16 *)((td)->new_ip) = * (guint16 *)(v); \
395 * ((guint16 *)((td)->new_ip) + 1) = * ((guint16 *)(v) + 1); \
399 #define WRITE64(td, v) \
401 ENSURE_CODE(td, 4); \
402 * (guint16 *)((td)->new_ip) = * (guint16 *)(v); \
403 * ((guint16 *)((td)->new_ip) + 1) = * ((guint16 *)(v) + 1); \
404 * ((guint16 *)((td)->new_ip) + 2) = * ((guint16 *)(v) + 2); \
405 * ((guint16 *)((td)->new_ip) + 3) = * ((guint16 *)(v) + 3); \
409 #define WRITE32(td, v) \
411 ENSURE_CODE(td, 2); \
412 * (guint32 *)((td)->new_ip) = * (guint32 *)(v); \
416 #define WRITE64(td, v) \
418 ENSURE_CODE(td, 4); \
419 * (guint64 *)((td)->new_ip) = * (guint64 *)(v); \
426 load_arg(TransformData *td, int n)
429 MonoClass *klass = NULL;
432 gboolean hasthis = mono_method_signature (td->method)->hasthis;
433 if (hasthis && n == 0)
434 type = &td->method->klass->byval_arg;
436 type = mono_method_signature (td->method)->params [hasthis ? n - 1 : n];
438 mt = mint_type (type);
439 if (mt == MINT_TYPE_VT) {
441 klass = mono_class_from_mono_type (type);
442 if (mono_method_signature (td->method)->pinvoke)
443 size = mono_class_native_size (klass, NULL);
445 size = mono_class_value_size (klass, NULL);
447 if (hasthis && n == 0) {
449 ADD_CODE (td, MINT_LDARG_P);
450 ADD_CODE (td, td->rtm->arg_offsets [n]); /* FIX for large offset */
454 ADD_CODE (td, MINT_LDARG_VT);
455 ADD_CODE (td, td->rtm->arg_offsets [n]); /* FIX for large offset */
459 if (hasthis && n == 0) {
461 ADD_CODE (td, MINT_LDARG_P);
462 ADD_CODE (td, td->rtm->arg_offsets [n]); /* FIX for large offset */
465 ADD_CODE(td, MINT_LDARG_I1 + (mt - MINT_TYPE_I1));
466 ADD_CODE(td, td->rtm->arg_offsets [n]); /* FIX for large offset */
467 if (mt == MINT_TYPE_O)
468 klass = mono_class_from_mono_type (type);
471 PUSH_TYPE(td, stack_type[mt], klass);
475 store_arg(TransformData *td, int n)
481 gboolean hasthis = mono_method_signature (td->method)->hasthis;
482 if (hasthis && n == 0)
483 type = &td->method->klass->byval_arg;
485 type = mono_method_signature (td->method)->params [n - !!hasthis];
487 mt = mint_type (type);
488 if (mt == MINT_TYPE_VT) {
490 MonoClass *klass = mono_class_from_mono_type (type);
491 if (mono_method_signature (td->method)->pinvoke)
492 size = mono_class_native_size (klass, NULL);
494 size = mono_class_value_size (klass, NULL);
495 ADD_CODE(td, MINT_STARG_VT);
496 ADD_CODE(td, td->rtm->arg_offsets [n]);
498 if (td->sp [-1].type == STACK_TYPE_VT)
501 ADD_CODE(td, MINT_STARG_I1 + (mt - MINT_TYPE_I1));
502 ADD_CODE(td, td->rtm->arg_offsets [n]);
508 store_inarg(TransformData *td, int n)
511 gboolean hasthis = mono_method_signature (td->method)->hasthis;
512 if (hasthis && n == 0)
513 type = &td->method->klass->byval_arg;
515 type = mono_method_signature (td->method)->params [n - !!hasthis];
517 int mt = mint_type (type);
518 if (hasthis && n == 0) {
519 ADD_CODE (td, MINT_STINARG_P);
523 if (mt == MINT_TYPE_VT) {
524 MonoClass *klass = mono_class_from_mono_type (type);
526 if (mono_method_signature (td->method)->pinvoke)
527 size = mono_class_native_size (klass, NULL);
529 size = mono_class_value_size (klass, NULL);
530 ADD_CODE(td, MINT_STINARG_VT);
534 ADD_CODE(td, MINT_STINARG_I1 + (mt - MINT_TYPE_I1));
540 load_local(TransformData *td, int n)
542 MonoType *type = td->header->locals [n];
543 int mt = mint_type (type);
544 int offset = td->rtm->local_offsets [n];
545 MonoClass *klass = NULL;
546 if (mt == MINT_TYPE_VT) {
547 klass = mono_class_from_mono_type (type);
548 gint32 size = mono_class_value_size (klass, NULL);
550 ADD_CODE(td, MINT_LDLOC_VT);
551 ADD_CODE(td, offset); /*FIX for large offset */
554 g_assert (mt < MINT_TYPE_VT);
555 if (mt == MINT_TYPE_I4 && !td->is_bb_start [td->in_start - td->il_code] && td->last_new_ip != NULL &&
556 td->last_new_ip [0] == MINT_STLOC_I4 && td->last_new_ip [1] == offset) {
557 td->last_new_ip [0] = MINT_STLOC_NP_I4;
558 } else if (mt == MINT_TYPE_O && !td->is_bb_start [td->in_start - td->il_code] && td->last_new_ip != NULL &&
559 td->last_new_ip [0] == MINT_STLOC_O && td->last_new_ip [1] == offset) {
560 td->last_new_ip [0] = MINT_STLOC_NP_O;
562 ADD_CODE(td, MINT_LDLOC_I1 + (mt - MINT_TYPE_I1));
563 ADD_CODE(td, offset); /*FIX for large offset */
565 if (mt == MINT_TYPE_O)
566 klass = mono_class_from_mono_type (type);
568 PUSH_TYPE(td, stack_type[mt], klass);
572 store_local(TransformData *td, int n)
574 MonoType *type = td->header->locals [n];
575 int mt = mint_type (type);
576 int offset = td->rtm->local_offsets [n];
578 #if SIZEOF_VOID_P == 8
579 if (td->sp [-1].type == STACK_TYPE_I4 && stack_type [mt] == STACK_TYPE_I8) {
580 ADD_CODE(td, MINT_CONV_I8_I4);
581 td->sp [-1].type = STACK_TYPE_I8;
584 if (!can_store(td->sp [-1].type, stack_type [mt])) {
585 g_warning("%s.%s: Store local stack type mismatch %d %d",
586 td->method->klass->name, td->method->name,
587 stack_type [mt], td->sp [-1].type);
589 if (mt == MINT_TYPE_VT) {
590 MonoClass *klass = mono_class_from_mono_type (type);
591 gint32 size = mono_class_value_size (klass, NULL);
592 ADD_CODE(td, MINT_STLOC_VT);
593 ADD_CODE(td, offset); /*FIX for large offset */
595 if (td->sp [-1].type == STACK_TYPE_VT)
598 g_assert (mt < MINT_TYPE_VT);
599 ADD_CODE(td, MINT_STLOC_I1 + (mt - MINT_TYPE_I1));
600 ADD_CODE(td, offset); /*FIX for large offset */
605 #define SIMPLE_OP(td, op) \
612 get_data_item_index (TransformData *td, void *ptr)
614 gpointer p = g_hash_table_lookup (td->data_hash, ptr);
617 return GPOINTER_TO_UINT (p) - 1;
618 if (td->max_data_items == td->n_data_items) {
619 td->max_data_items = td->n_data_items == 0 ? 16 : 2 * td->max_data_items;
620 td->data_items = g_realloc (td->data_items, td->max_data_items * sizeof(td->data_items [0]));
622 index = td->n_data_items;
623 td->data_items [index] = ptr;
625 g_hash_table_insert (td->data_hash, ptr, GUINT_TO_POINTER (index + 1));
630 jit_call_supported (MonoMethod *method, MonoMethodSignature *sig)
634 if (sig->param_count > 6)
638 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
640 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
642 if (method->is_inflated)
644 if (method->string_ctor)
647 for (l = jit_classes; l; l = l->next) {
648 char *class_name = l->data;
650 if (!strcmp (method->klass->name, class_name))
659 interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target_method, MonoDomain *domain, MonoGenericContext *generic_context, unsigned char *is_bb_start, int body_start_offset, MonoClass *constrained_class, gboolean readonly)
661 MonoImage *image = method->klass->image;
662 MonoMethodSignature *csignature;
664 int virtual = *td->ip == CEE_CALLVIRT;
665 int calli = *td->ip == CEE_CALLI || *td->ip == CEE_MONO_CALLI_EXTRA_ARG;
667 guint32 vt_stack_used = 0;
668 guint32 vt_res_size = 0;
673 guint32 token = read32 (td->ip + 1);
675 if (target_method == NULL) {
678 native = (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE && td->sp [-1].type == STACK_TYPE_I);
680 if (method->wrapper_type != MONO_WRAPPER_NONE)
681 csignature = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
683 csignature = mono_metadata_parse_signature (image, token);
685 if (generic_context) {
686 csignature = mono_inflate_generic_signature (csignature, generic_context, &error);
687 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
690 target_method = NULL;
692 if (method->wrapper_type == MONO_WRAPPER_NONE)
693 target_method = mono_get_method_full (image, token, NULL, generic_context);
695 target_method = (MonoMethod *)mono_method_get_wrapper_data (method, token);
696 csignature = mono_method_signature (target_method);
697 if (target_method->klass == mono_defaults.string_class) {
698 if (target_method->name [0] == 'g') {
699 if (strcmp (target_method->name, "get_Chars") == 0)
701 else if (strcmp (target_method->name, "get_Length") == 0)
704 } else if (mono_class_is_subclass_of (target_method->klass, mono_defaults.array_class, FALSE)) {
705 if (!strcmp (target_method->name, "get_Rank")) {
706 op = MINT_ARRAY_RANK;
707 } else if (!strcmp (target_method->name, "get_Length")) {
709 } else if (!strcmp (target_method->name, "Address")) {
710 op = readonly ? MINT_LDELEMA : MINT_LDELEMA_TC;
712 } else if (target_method && generic_context) {
713 csignature = mono_inflate_generic_signature (csignature, generic_context, &error);
714 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
715 target_method = mono_class_inflate_generic_method_checked (target_method, generic_context, &error);
716 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
720 csignature = mono_method_signature (target_method);
723 if (constrained_class) {
724 if (constrained_class->enumtype && !strcmp (target_method->name, "GetHashCode")) {
725 /* Use the corresponding method from the base type to avoid boxing */
726 MonoType *base_type = mono_class_enum_basetype (constrained_class);
727 g_assert (base_type);
728 constrained_class = mono_class_from_mono_type (base_type);
729 target_method = mono_class_get_method_from_name (constrained_class, target_method->name, 0);
730 g_assert (target_method);
734 if (constrained_class) {
735 mono_class_setup_vtable (constrained_class);
737 g_print ("CONSTRAINED.CALLVIRT: %s::%s. %s (%p) ->\n", target_method->klass->name, target_method->name, mono_signature_full_name (target_method->signature), target_method);
739 target_method = mono_get_method_constrained_with_method (image, target_method, constrained_class, generic_context, &error);
741 g_print (" : %s::%s. %s (%p)\n", target_method->klass->name, target_method->name, mono_signature_full_name (target_method->signature), target_method);
743 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
744 mono_class_setup_vtable (target_method->klass);
746 if (constrained_class->valuetype && (target_method->klass == mono_defaults.object_class || target_method->klass == mono_defaults.enum_class->parent || target_method->klass == mono_defaults.enum_class)) {
747 if (target_method->klass == mono_defaults.enum_class && (td->sp - csignature->param_count - 1)->type == STACK_TYPE_MP) {
748 /* managed pointer on the stack, we need to deref that puppy */
749 ADD_CODE (td, MINT_LDIND_I);
750 ADD_CODE (td, csignature->param_count);
752 ADD_CODE (td, MINT_BOX);
753 ADD_CODE (td, get_data_item_index (td, constrained_class));
754 ADD_CODE (td, csignature->param_count);
755 } else if (!constrained_class->valuetype) {
756 /* managed pointer on the stack, we need to deref that puppy */
757 ADD_CODE (td, MINT_LDIND_I);
758 ADD_CODE (td, csignature->param_count);
760 if (target_method->klass->valuetype) {
763 /* Interface method */
766 mono_class_setup_vtable (constrained_class);
767 ioffset = mono_class_interface_offset (constrained_class, target_method->klass);
769 g_error ("type load error: constrained_class");
770 slot = mono_method_get_vtable_slot (target_method);
772 g_error ("type load error: target_method->klass");
773 target_method = constrained_class->vtable [ioffset + slot];
775 if (target_method->klass == mono_defaults.enum_class) {
776 if ((td->sp - csignature->param_count - 1)->type == STACK_TYPE_MP) {
777 /* managed pointer on the stack, we need to deref that puppy */
778 ADD_CODE (td, MINT_LDIND_I);
779 ADD_CODE (td, csignature->param_count);
781 ADD_CODE (td, MINT_BOX);
782 ADD_CODE (td, get_data_item_index (td, constrained_class));
783 ADD_CODE (td, csignature->param_count);
791 mono_class_init (target_method->klass);
793 CHECK_STACK (td, csignature->param_count + csignature->hasthis);
794 if (!calli && (!virtual || (target_method->flags & METHOD_ATTRIBUTE_VIRTUAL) == 0) &&
795 (target_method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 &&
796 (target_method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) == 0) {
797 int called_inited = mono_class_vtable (domain, target_method->klass)->initialized;
798 MonoMethodHeader *mheader = mono_method_get_header (target_method);
800 if (/*mono_metadata_signature_equal (method->signature, target_method->signature) */ method == target_method && *(td->ip + 5) == CEE_RET) {
802 if (mono_interp_traceopt)
803 g_print ("Optimize tail call of %s.%s\n", target_method->klass->name, target_method->name);
805 for (i = csignature->param_count - 1 + !!csignature->hasthis; i >= 0; --i)
808 ADD_CODE(td, MINT_BR_S);
809 offset = body_start_offset - ((td->new_ip - 1) - td->new_code);
810 ADD_CODE(td, offset);
811 if (!is_bb_start [td->ip + 5 - td->il_code])
812 ++td->ip; /* gobble the CEE_RET if it isn't branched to */
816 /* mheader might not exist if this is a delegate invoc, etc */
817 if (mheader && *mheader->code == CEE_RET && called_inited) {
818 if (mono_interp_traceopt)
819 g_print ("Inline (empty) call of %s.%s\n", target_method->klass->name, target_method->name);
820 for (i = 0; i < csignature->param_count; i++)
821 ADD_CODE (td, MINT_POP); /*FIX: vt */
823 if (csignature->hasthis) {
825 ADD_CODE(td, MINT_CKNULL);
826 ADD_CODE (td, MINT_POP);
829 td->sp -= csignature->param_count + csignature->hasthis;
835 if (method->wrapper_type == MONO_WRAPPER_NONE && target_method != NULL) {
836 if (target_method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
837 target_method = mono_marshal_get_native_wrapper (target_method, FALSE, FALSE);
838 if (!virtual && target_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
839 target_method = mono_marshal_get_synchronized_wrapper (target_method);
841 g_assert (csignature->call_convention == MONO_CALL_DEFAULT || csignature->call_convention == MONO_CALL_C);
842 td->sp -= csignature->param_count + !!csignature->hasthis;
843 for (i = 0; i < csignature->param_count; ++i) {
844 if (td->sp [i + !!csignature->hasthis].type == STACK_TYPE_VT) {
846 MonoClass *klass = mono_class_from_mono_type (csignature->params [i]);
847 if (csignature->pinvoke && method->wrapper_type != MONO_WRAPPER_NONE)
848 size = mono_class_native_size (klass, NULL);
850 size = mono_class_value_size (klass, NULL);
851 size = (size + 7) & ~7;
852 vt_stack_used += size;
856 /* need to handle typedbyref ... */
857 if (csignature->ret->type != MONO_TYPE_VOID) {
858 int mt = mint_type(csignature->ret);
859 MonoClass *klass = mono_class_from_mono_type (csignature->ret);
860 if (mt == MINT_TYPE_VT) {
861 if (csignature->pinvoke && method->wrapper_type != MONO_WRAPPER_NONE)
862 vt_res_size = mono_class_native_size (klass, NULL);
864 vt_res_size = mono_class_value_size (klass, NULL);
865 PUSH_VT(td, vt_res_size);
867 PUSH_TYPE(td, stack_type[mt], klass);
873 #if SIZEOF_VOID_P == 8
874 if (op == MINT_LDLEN)
875 ADD_CODE (td, MINT_CONV_I4_I8);
877 if (op == MINT_LDELEMA || op == MINT_LDELEMA_TC) {
878 ADD_CODE (td, get_data_item_index (td, target_method->klass));
879 ADD_CODE (td, 1 + target_method->klass->rank);
881 } else if (!calli && !virtual && jit_call_supported (target_method, csignature)) {
882 ADD_CODE(td, MINT_JIT_CALL);
883 ADD_CODE(td, get_data_item_index (td, (void *)mono_interp_get_runtime_method (domain, target_method, &error)));
884 mono_error_assert_ok (&error);
887 ADD_CODE(td, native ? MINT_CALLI_NAT : MINT_CALLI);
889 ADD_CODE(td, is_void ? MINT_VCALLVIRT : MINT_CALLVIRT);
891 ADD_CODE(td, is_void ? MINT_VCALL : MINT_CALL);
894 ADD_CODE(td, get_data_item_index (td, (void *)csignature));
896 ADD_CODE(td, get_data_item_index (td, (void *)mono_interp_get_runtime_method (domain, target_method, &error)));
897 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
901 if (vt_stack_used != 0 || vt_res_size != 0) {
902 ADD_CODE(td, MINT_VTRESULT);
903 ADD_CODE(td, vt_res_size);
904 WRITE32(td, &vt_stack_used);
905 td->vt_sp -= vt_stack_used;
909 static MonoClassField *
910 interp_field_from_token (MonoMethod *method, guint32 token, MonoClass **klass, MonoGenericContext *generic_context)
912 MonoClassField *field = NULL;
913 if (method->wrapper_type != MONO_WRAPPER_NONE) {
914 field = (MonoClassField *) mono_method_get_wrapper_data (method, token);
915 *klass = field->parent;
919 field = mono_field_from_token_checked (method->klass->image, token, klass, generic_context, &error);
920 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
926 interp_save_debug_info (RuntimeMethod *rtm, MonoMethodHeader *header, TransformData *td, GArray *line_numbers)
928 MonoDebugMethodJitInfo *dinfo;
931 if (!mono_debug_enabled ())
935 * We save the debug info in the same way the JIT does it, treating the interpreter IR as the native code.
938 dinfo = g_new0 (MonoDebugMethodJitInfo, 1);
939 dinfo->num_locals = header->num_locals;
940 dinfo->locals = g_new0 (MonoDebugVarInfo, header->num_locals);
941 dinfo->code_start = (guint8*)rtm->code;
942 dinfo->code_size = td->new_ip - td->new_code;
943 dinfo->epilogue_begin = 0;
944 dinfo->has_var_info = FALSE;
945 dinfo->num_line_numbers = line_numbers->len;
946 dinfo->line_numbers = g_new0 (MonoDebugLineNumberEntry, dinfo->num_line_numbers);
947 for (i = 0; i < dinfo->num_line_numbers; i++)
948 dinfo->line_numbers [i] = g_array_index (line_numbers, MonoDebugLineNumberEntry, i);
949 mono_debug_add_method (rtm->method, dinfo, mono_domain_get ());
951 mono_debug_free_method_jit_info (dinfo);
955 generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, MonoGenericContext *generic_context)
957 MonoMethodHeader *header = mono_method_get_header (method);
958 MonoMethodSignature *signature = mono_method_signature (method);
959 MonoImage *image = method->klass->image;
960 MonoDomain *domain = mono_domain_get ();
961 MonoClass *constrained_class = NULL;
963 int offset, mt, i, i32;
964 gboolean readonly = FALSE;
966 MonoClassField *field;
967 const unsigned char *end;
968 int new_in_start_offset;
969 int body_start_offset;
973 int generating_code = 1;
974 GArray *line_numbers;
976 memset(&td, 0, sizeof(td));
979 td.is_bb_start = is_bb_start;
980 td.il_code = header->code;
981 td.code_size = header->code_size;
983 td.max_code_size = td.code_size;
984 td.new_code = (unsigned short *)g_malloc(td.max_code_size * sizeof(gushort));
985 td.new_code_end = td.new_code + td.max_code_size;
986 td.in_offsets = g_malloc0(header->code_size * sizeof(int));
987 td.forward_refs = g_malloc(header->code_size * sizeof(int));
988 td.stack_state = g_malloc0(header->code_size * sizeof(StackInfo *));
989 td.stack_height = g_malloc(header->code_size * sizeof(int));
990 td.vt_stack_size = g_malloc(header->code_size * sizeof(int));
992 td.max_data_items = 0;
993 td.data_items = NULL;
994 td.data_hash = g_hash_table_new (NULL, NULL);
995 td.clause_indexes = g_malloc (header->code_size * sizeof (int));
996 rtm->data_items = td.data_items;
997 for (i = 0; i < header->code_size; i++) {
998 td.forward_refs [i] = -1;
999 td.stack_height [i] = -1;
1000 td.clause_indexes [i] = -1;
1002 td.new_ip = td.new_code;
1003 td.last_new_ip = NULL;
1005 td.stack = g_malloc0 ((header->max_stack + 1) * sizeof (td.stack [0]));
1007 td.max_stack_height = 0;
1009 line_numbers = g_array_new (FALSE, TRUE, sizeof (MonoDebugLineNumberEntry));
1011 for (i = 0; i < header->num_clauses; i++) {
1012 MonoExceptionClause *c = header->clauses + i;
1013 td.stack_height [c->handler_offset] = 0;
1014 td.vt_stack_size [c->handler_offset] = 0;
1015 td.is_bb_start [c->handler_offset] = 1;
1017 td.stack_height [c->handler_offset] = 1;
1018 td.stack_state [c->handler_offset] = g_malloc0(sizeof(StackInfo));
1019 td.stack_state [c->handler_offset][0].type = STACK_TYPE_O;
1020 td.stack_state [c->handler_offset][0].klass = NULL; /*FIX*/
1022 if (c->flags & MONO_EXCEPTION_CLAUSE_FILTER) {
1023 td.stack_height [c->data.filter_offset] = 0;
1024 td.vt_stack_size [c->data.filter_offset] = 0;
1025 td.is_bb_start [c->data.filter_offset] = 1;
1027 td.stack_height [c->data.filter_offset] = 1;
1028 td.stack_state [c->data.filter_offset] = g_malloc0(sizeof(StackInfo));
1029 td.stack_state [c->data.filter_offset][0].type = STACK_TYPE_O;
1030 td.stack_state [c->data.filter_offset][0].klass = NULL; /*FIX*/
1033 if ((c->flags & MONO_EXCEPTION_CLAUSE_FINALLY) || (c->flags & MONO_EXCEPTION_CLAUSE_FAULT)) {
1034 for (int j = c->handler_offset; j < c->handler_offset + c->handler_len; ++j) {
1035 if (td.clause_indexes [j] == -1)
1036 td.clause_indexes [j] = i;
1041 td.ip = header->code;
1042 end = td.ip + header->code_size;
1044 if (mono_interp_traceopt) {
1045 char *tmp = mono_disasm_code (NULL, method, td.ip, end);
1046 char *name = mono_method_full_name (method, TRUE);
1047 g_print ("Method %s, original code:\n", name);
1048 g_print ("%s\n", tmp);
1053 if (signature->hasthis)
1054 store_inarg (&td, 0);
1055 for (i = 0; i < signature->param_count; i++)
1056 store_inarg (&td, i + !!signature->hasthis);
1058 body_start_offset = td.new_ip - td.new_code;
1060 for (i = 0; i < header->num_locals; i++) {
1061 int mt = mint_type(header->locals [i]);
1062 if (mt == MINT_TYPE_VT || mt == MINT_TYPE_O || mt == MINT_TYPE_P) {
1063 ADD_CODE(&td, MINT_INITLOCALS);
1068 while (td.ip < end) {
1071 g_assert (td.sp >= td.stack);
1072 g_assert (td.vt_sp < 0x10000000);
1073 in_offset = td.ip - header->code;
1074 td.in_offsets [in_offset] = td.new_ip - td.new_code;
1075 new_in_start_offset = td.new_ip - td.new_code;
1076 td.in_start = td.ip;
1078 MonoDebugLineNumberEntry lne;
1079 lne.native_offset = td.new_ip - td.new_code;
1080 lne.il_offset = td.ip - header->code;
1081 g_array_append_val (line_numbers, lne);
1083 while (td.forward_refs [in_offset] >= 0) {
1084 int j = td.forward_refs [in_offset];
1086 td.forward_refs [in_offset] = td.forward_refs [j];
1087 if (td.in_offsets [j] < 0) {
1088 int old_switch_offset = -td.in_offsets [j];
1089 int new_switch_offset = td.in_offsets [old_switch_offset];
1090 int switch_case = (j - old_switch_offset - 5) / 4;
1091 int n_cases = read32 (header->code + old_switch_offset + 1);
1092 offset = (td.new_ip - td.new_code) - (new_switch_offset + 2 * n_cases + 3);
1093 slot = new_switch_offset + 3 + 2 * switch_case;
1094 td.new_code [slot] = * (unsigned short *)(&offset);
1095 td.new_code [slot + 1] = * ((unsigned short *)&offset + 1);
1097 int op = td.new_code [td.in_offsets [j]];
1098 if (mono_interp_opargtype [op] == MintOpShortBranch) {
1099 offset = (td.new_ip - td.new_code) - td.in_offsets [j];
1100 g_assert (offset <= 32767);
1101 slot = td.in_offsets [j] + 1;
1102 td.new_code [slot] = offset;
1104 offset = (td.new_ip - td.new_code) - td.in_offsets [j];
1105 slot = td.in_offsets [j] + 1;
1106 td.new_code [slot] = * (unsigned short *)(&offset);
1107 td.new_code [slot + 1] = * ((unsigned short *)&offset + 1);
1111 if (td.stack_height [in_offset] >= 0) {
1112 g_assert (is_bb_start [in_offset]);
1113 if (td.stack_height [in_offset] > 0)
1114 memcpy (td.stack, td.stack_state [in_offset], td.stack_height [in_offset] * sizeof(td.stack [0]));
1115 td.sp = td.stack + td.stack_height [in_offset];
1116 td.vt_sp = td.vt_stack_size [in_offset];
1118 if (is_bb_start [in_offset]) {
1119 generating_code = 1;
1121 if (!generating_code) {
1122 while (td.ip < end && !is_bb_start [td.ip - td.il_code])
1126 if (mono_interp_traceopt > 1) {
1127 printf("IL_%04lx %s %-10s -> IL_%04lx, sp %ld, %s %-12s vt_sp %u (max %u)\n",
1129 td.is_bb_start [td.ip - td.il_code] == 3 ? "<>" :
1130 td.is_bb_start [td.ip - td.il_code] == 2 ? "< " :
1131 td.is_bb_start [td.ip - td.il_code] == 1 ? " >" : " ",
1132 mono_opcode_name (*td.ip), td.new_ip - td.new_code, td.sp - td.stack,
1133 td.sp > td.stack ? stack_type_string [td.sp [-1].type] : " ",
1134 (td.sp > td.stack && (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_VT)) ? (td.sp [-1].klass == NULL ? "?" : td.sp [-1].klass->name) : "",
1135 td.vt_sp, td.max_vt_sp);
1143 SIMPLE_OP(td, MINT_BREAK);
1149 load_arg (&td, *td.ip - CEE_LDARG_0);
1156 load_local (&td, *td.ip - CEE_LDLOC_0);
1163 store_local (&td, *td.ip - CEE_STLOC_0);
1167 load_arg (&td, ((guint8 *)td.ip)[1]);
1170 case CEE_LDARGA_S: {
1171 /* NOTE: n includes this */
1172 int n = ((guint8 *) td.ip) [1];
1173 ADD_CODE (&td, MINT_LDARGA);
1174 ADD_CODE (&td, td.rtm->arg_offsets [n]);
1175 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_MP);
1180 store_arg (&td, ((guint8 *)td.ip)[1]);
1184 load_local (&td, ((guint8 *)td.ip)[1]);
1188 ADD_CODE(&td, MINT_LDLOCA_S);
1189 ADD_CODE(&td, td.rtm->local_offsets [((guint8 *)td.ip)[1]]);
1190 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_MP);
1194 store_local (&td, ((guint8 *)td.ip)[1]);
1198 SIMPLE_OP(td, MINT_LDNULL);
1199 PUSH_TYPE(&td, STACK_TYPE_O, NULL);
1202 SIMPLE_OP(td, MINT_LDC_I4_M1);
1203 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4);
1206 if (!td.is_bb_start[td.ip + 1 - td.il_code] && td.ip [1] == 0xfe && td.ip [2] == CEE_CEQ &&
1207 td.sp > td.stack && td.sp [-1].type == STACK_TYPE_I4) {
1208 SIMPLE_OP(td, MINT_CEQ0_I4);
1211 SIMPLE_OP(td, MINT_LDC_I4_0);
1212 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4);
1216 if (!td.is_bb_start[td.ip + 1 - td.il_code] &&
1217 (td.ip [1] == CEE_ADD || td.ip [1] == CEE_SUB) && td.sp [-1].type == STACK_TYPE_I4) {
1218 ADD_CODE(&td, td.ip [1] == CEE_ADD ? MINT_ADD1_I4 : MINT_SUB1_I4);
1221 SIMPLE_OP(td, MINT_LDC_I4_1);
1222 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4);
1232 SIMPLE_OP(td, (*td.ip - CEE_LDC_I4_0) + MINT_LDC_I4_0);
1233 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4);
1236 ADD_CODE(&td, MINT_LDC_I4_S);
1237 ADD_CODE(&td, ((gint8 *) td.ip) [1]);
1239 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4);
1242 i32 = read32 (td.ip + 1);
1243 ADD_CODE(&td, MINT_LDC_I4);
1246 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4);
1249 gint64 val = read64 (td.ip + 1);
1250 ADD_CODE(&td, MINT_LDC_I8);
1253 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I8);
1258 readr4 (td.ip + 1, &val);
1259 ADD_CODE(&td, MINT_LDC_R4);
1262 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_R8);
1267 readr8 (td.ip + 1, &val);
1268 ADD_CODE(&td, MINT_LDC_R8);
1271 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_R8);
1275 int type = td.sp [-1].type;
1276 MonoClass *klass = td.sp [-1].klass;
1277 if (td.sp [-1].type == STACK_TYPE_VT) {
1278 gint32 size = mono_class_value_size (klass, NULL);
1280 ADD_CODE(&td, MINT_DUP_VT);
1281 WRITE32(&td, &size);
1284 SIMPLE_OP(td, MINT_DUP);
1285 PUSH_TYPE(&td, type, klass);
1289 CHECK_STACK(&td, 1);
1290 SIMPLE_OP(td, MINT_POP);
1292 if (td.sp [-1].type == STACK_TYPE_VT) {
1293 int size = mono_class_value_size (td.sp [-1].klass, NULL);
1294 size = (size + 7) & ~7;
1295 ADD_CODE(&td, MINT_VTRESULT);
1297 WRITE32(&td, &size);
1304 if (td.sp > td.stack)
1305 g_warning ("CEE_JMP: stack must be empty");
1306 token = read32 (td.ip + 1);
1307 m = mono_get_method_full (image, token, NULL, generic_context);
1308 ADD_CODE (&td, MINT_JMP);
1309 ADD_CODE (&td, get_data_item_index (&td, mono_interp_get_runtime_method (domain, m, &error)));
1310 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1314 case CEE_CALLVIRT: /* Fall through */
1315 case CEE_CALLI: /* Fall through */
1317 interp_transform_call (&td, method, NULL, domain, generic_context, is_bb_start, body_start_offset, constrained_class, readonly);
1318 constrained_class = NULL;
1324 if (signature->ret->type != MONO_TYPE_VOID) {
1326 MonoClass *klass = mono_class_from_mono_type (signature->ret);
1327 if (mint_type (&klass->byval_arg) == MINT_TYPE_VT) {
1328 vt_size = mono_class_value_size (klass, NULL);
1329 vt_size = (vt_size + 7) & ~7;
1332 if (td.sp > td.stack)
1333 g_warning ("%s.%s: CEE_RET: more values on stack: %d", td.method->klass->name, td.method->name, td.sp - td.stack);
1334 if (td.vt_sp != vt_size)
1335 g_error ("%s.%s: CEE_RET: value type stack: %d vs. %d", td.method->klass->name, td.method->name, td.vt_sp, vt_size);
1337 SIMPLE_OP(td, signature->ret->type == MONO_TYPE_VOID ? MINT_RET_VOID : MINT_RET);
1339 ADD_CODE(&td, MINT_RET_VT);
1340 WRITE32(&td, &vt_size);
1343 generating_code = 0;
1347 handle_branch (&td, MINT_BR_S, MINT_BR, 5 + read32 (td.ip + 1));
1349 generating_code = 0;
1352 handle_branch (&td, MINT_BR_S, MINT_BR, 2 + (gint8)td.ip [1]);
1354 generating_code = 0;
1357 one_arg_branch (&td, MINT_BRFALSE_I4, 5 + read32 (td.ip + 1));
1361 one_arg_branch (&td, MINT_BRFALSE_I4, 2 + (gint8)td.ip [1]);
1365 one_arg_branch (&td, MINT_BRTRUE_I4, 5 + read32 (td.ip + 1));
1369 one_arg_branch (&td, MINT_BRTRUE_I4, 2 + (gint8)td.ip [1]);
1373 two_arg_branch (&td, MINT_BEQ_I4, 5 + read32 (td.ip + 1));
1377 two_arg_branch (&td, MINT_BEQ_I4, 2 + (gint8) td.ip [1]);
1381 two_arg_branch (&td, MINT_BGE_I4, 5 + read32 (td.ip + 1));
1385 two_arg_branch (&td, MINT_BGE_I4, 2 + (gint8) td.ip [1]);
1389 two_arg_branch (&td, MINT_BGT_I4, 5 + read32 (td.ip + 1));
1393 two_arg_branch (&td, MINT_BGT_I4, 2 + (gint8) td.ip [1]);
1397 two_arg_branch (&td, MINT_BLT_I4, 5 + read32 (td.ip + 1));
1401 two_arg_branch (&td, MINT_BLT_I4, 2 + (gint8) td.ip [1]);
1405 two_arg_branch (&td, MINT_BLE_I4, 5 + read32 (td.ip + 1));
1409 two_arg_branch (&td, MINT_BLE_I4, 2 + (gint8) td.ip [1]);
1413 two_arg_branch (&td, MINT_BNE_UN_I4, 5 + read32 (td.ip + 1));
1417 two_arg_branch (&td, MINT_BNE_UN_I4, 2 + (gint8) td.ip [1]);
1421 two_arg_branch (&td, MINT_BGE_UN_I4, 5 + read32 (td.ip + 1));
1425 two_arg_branch (&td, MINT_BGE_UN_I4, 2 + (gint8) td.ip [1]);
1429 two_arg_branch (&td, MINT_BGT_UN_I4, 5 + read32 (td.ip + 1));
1433 two_arg_branch (&td, MINT_BGT_UN_I4, 2 + (gint8) td.ip [1]);
1437 two_arg_branch (&td, MINT_BLE_UN_I4, 5 + read32 (td.ip + 1));
1441 two_arg_branch (&td, MINT_BLE_UN_I4, 2 + (gint8) td.ip [1]);
1445 two_arg_branch (&td, MINT_BLT_UN_I4, 5 + read32 (td.ip + 1));
1449 two_arg_branch (&td, MINT_BLT_UN_I4, 2 + (gint8) td.ip [1]);
1454 const unsigned char *next_ip;
1455 const unsigned char *base_ip = td.ip;
1456 unsigned short *next_new_ip;
1459 ADD_CODE (&td, MINT_SWITCH);
1462 next_ip = td.ip + n * 4;
1463 next_new_ip = td.new_ip + n * 2;
1465 int stack_height = td.sp - td.stack;
1466 for (i = 0; i < n; i++) {
1467 offset = read32 (td.ip);
1468 target = next_ip - td.il_code + offset;
1471 if (stack_height > 0 && stack_height != td.stack_height [target])
1472 g_warning ("SWITCH with back branch and non-empty stack");
1474 target = td.in_offsets [target] - (next_new_ip - td.new_code);
1476 td.stack_height [target] = stack_height;
1477 td.vt_stack_size [target] = td.vt_sp;
1478 if (stack_height > 0)
1479 td.stack_state [target] = g_memdup (td.stack, stack_height * sizeof (td.stack [0]));
1480 int prev = td.forward_refs [target];
1481 td.forward_refs [td.ip - td.il_code] = prev;
1482 td.forward_refs [target] = td.ip - td.il_code;
1483 td.in_offsets [td.ip - td.il_code] = - (base_ip - td.il_code);
1485 WRITE32 (&td, &target);
1491 CHECK_STACK (&td, 1);
1492 SIMPLE_OP (td, MINT_LDIND_I1);
1493 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
1496 CHECK_STACK (&td, 1);
1497 SIMPLE_OP (td, MINT_LDIND_U1);
1498 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
1501 CHECK_STACK (&td, 1);
1502 SIMPLE_OP (td, MINT_LDIND_I2);
1503 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
1506 CHECK_STACK (&td, 1);
1507 SIMPLE_OP (td, MINT_LDIND_U2);
1508 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
1511 CHECK_STACK (&td, 1);
1512 SIMPLE_OP (td, MINT_LDIND_I4);
1513 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
1516 CHECK_STACK (&td, 1);
1517 SIMPLE_OP (td, MINT_LDIND_U4);
1518 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
1521 CHECK_STACK (&td, 1);
1522 SIMPLE_OP (td, MINT_LDIND_I8);
1523 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8);
1526 CHECK_STACK (&td, 1);
1527 SIMPLE_OP (td, MINT_LDIND_I);
1529 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I);
1532 CHECK_STACK (&td, 1);
1533 SIMPLE_OP (td, MINT_LDIND_R4);
1534 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8);
1537 CHECK_STACK (&td, 1);
1538 SIMPLE_OP (td, MINT_LDIND_R8);
1539 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8);
1542 CHECK_STACK (&td, 1);
1543 SIMPLE_OP (td, MINT_LDIND_REF);
1544 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_O);
1547 CHECK_STACK (&td, 2);
1548 SIMPLE_OP (td, MINT_STIND_REF);
1552 CHECK_STACK (&td, 2);
1553 SIMPLE_OP (td, MINT_STIND_I1);
1557 CHECK_STACK (&td, 2);
1558 SIMPLE_OP (td, MINT_STIND_I2);
1562 CHECK_STACK (&td, 2);
1563 SIMPLE_OP (td, MINT_STIND_I4);
1567 CHECK_STACK (&td, 2);
1568 SIMPLE_OP (td, MINT_STIND_I);
1572 CHECK_STACK (&td, 2);
1573 SIMPLE_OP (td, MINT_STIND_I8);
1577 CHECK_STACK (&td, 2);
1578 SIMPLE_OP (td, MINT_STIND_R4);
1582 CHECK_STACK (&td, 2);
1583 SIMPLE_OP (td, MINT_STIND_R8);
1587 binary_arith_op(&td, MINT_ADD_I4);
1591 binary_arith_op(&td, MINT_SUB_I4);
1595 binary_arith_op(&td, MINT_MUL_I4);
1599 binary_arith_op(&td, MINT_DIV_I4);
1603 binary_arith_op(&td, MINT_DIV_UN_I4);
1607 binary_arith_op (&td, MINT_REM_I4);
1611 binary_arith_op (&td, MINT_REM_UN_I4);
1615 binary_arith_op (&td, MINT_AND_I4);
1619 binary_arith_op (&td, MINT_OR_I4);
1623 binary_arith_op (&td, MINT_XOR_I4);
1627 shift_op (&td, MINT_SHL_I4);
1631 shift_op (&td, MINT_SHR_I4);
1635 shift_op (&td, MINT_SHR_UN_I4);
1639 unary_arith_op (&td, MINT_NEG_I4);
1643 unary_arith_op (&td, MINT_NOT_I4);
1647 CHECK_STACK (&td, 1);
1648 switch (td.sp [-1].type) {
1650 ADD_CODE(&td, MINT_CONV_U1_R8);
1653 ADD_CODE(&td, MINT_CONV_U1_I4);
1656 ADD_CODE(&td, MINT_CONV_U1_I8);
1659 g_assert_not_reached ();
1662 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
1665 CHECK_STACK (&td, 1);
1666 switch (td.sp [-1].type) {
1668 ADD_CODE(&td, MINT_CONV_I1_R8);
1671 ADD_CODE(&td, MINT_CONV_I1_I4);
1674 ADD_CODE(&td, MINT_CONV_I1_I8);
1677 g_assert_not_reached ();
1680 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
1683 CHECK_STACK (&td, 1);
1684 switch (td.sp [-1].type) {
1686 ADD_CODE(&td, MINT_CONV_U2_R8);
1689 ADD_CODE(&td, MINT_CONV_U2_I4);
1692 ADD_CODE(&td, MINT_CONV_U2_I8);
1695 g_assert_not_reached ();
1698 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
1701 CHECK_STACK (&td, 1);
1702 switch (td.sp [-1].type) {
1704 ADD_CODE(&td, MINT_CONV_I2_R8);
1707 ADD_CODE(&td, MINT_CONV_I2_I4);
1710 ADD_CODE(&td, MINT_CONV_I2_I8);
1713 g_assert_not_reached ();
1716 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
1719 CHECK_STACK (&td, 1);
1720 switch (td.sp [-1].type) {
1722 #if SIZEOF_VOID_P == 4
1723 ADD_CODE(&td, MINT_CONV_U4_R8);
1725 ADD_CODE(&td, MINT_CONV_U8_R8);
1729 #if SIZEOF_VOID_P == 8
1730 ADD_CODE(&td, MINT_CONV_U8_I4);
1734 #if SIZEOF_VOID_P == 4
1735 ADD_CODE(&td, MINT_CONV_U4_I8);
1741 g_assert_not_reached ();
1744 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I);
1747 CHECK_STACK (&td, 1);
1748 switch (td.sp [-1].type) {
1750 #if SIZEOF_VOID_P == 8
1751 ADD_CODE(&td, MINT_CONV_I8_R8);
1753 ADD_CODE(&td, MINT_CONV_I4_R8);
1757 #if SIZEOF_VOID_P == 8
1758 ADD_CODE(&td, MINT_CONV_I8_I4);
1766 #if SIZEOF_VOID_P == 4
1767 ADD_CODE(&td, MINT_CONV_I4_I8);
1771 g_assert_not_reached ();
1774 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I);
1777 CHECK_STACK (&td, 1);
1778 switch (td.sp [-1].type) {
1780 ADD_CODE(&td, MINT_CONV_U4_R8);
1785 ADD_CODE(&td, MINT_CONV_U4_I8);
1788 #if SIZEOF_VOID_P == 8
1789 ADD_CODE(&td, MINT_CONV_U4_I8);
1793 g_assert_not_reached ();
1796 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
1799 CHECK_STACK (&td, 1);
1800 switch (td.sp [-1].type) {
1802 ADD_CODE(&td, MINT_CONV_I4_R8);
1807 ADD_CODE(&td, MINT_CONV_I4_I8);
1810 #if SIZEOF_VOID_P == 8
1811 ADD_CODE(&td, MINT_CONV_I4_I8);
1815 g_assert_not_reached ();
1818 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
1821 CHECK_STACK (&td, 1);
1822 switch (td.sp [-1].type) {
1824 ADD_CODE(&td, MINT_CONV_I8_R8);
1827 ADD_CODE(&td, MINT_CONV_I8_I4);
1832 #if SIZEOF_VOID_P == 4
1833 ADD_CODE(&td, MINT_CONV_I8_I4);
1837 g_assert_not_reached ();
1840 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8);
1843 CHECK_STACK (&td, 1);
1844 switch (td.sp [-1].type) {
1846 ADD_CODE(&td, MINT_CONV_R4_R8);
1849 ADD_CODE(&td, MINT_CONV_R4_I8);
1852 ADD_CODE(&td, MINT_CONV_R4_I4);
1855 g_assert_not_reached ();
1858 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8);
1861 CHECK_STACK (&td, 1);
1862 switch (td.sp [-1].type) {
1864 ADD_CODE(&td, MINT_CONV_R8_I4);
1867 ADD_CODE(&td, MINT_CONV_R8_I8);
1872 g_assert_not_reached ();
1875 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8);
1878 CHECK_STACK (&td, 1);
1879 switch (td.sp [-1].type) {
1881 ADD_CODE(&td, MINT_CONV_U8_I4);
1886 ADD_CODE(&td, MINT_CONV_U8_R8);
1889 #if SIZEOF_VOID_P == 4
1890 ADD_CODE(&td, MINT_CONV_U8_I4);
1894 g_assert_not_reached ();
1897 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8);
1900 CHECK_STACK (&td, 2);
1902 token = read32 (td.ip + 1);
1903 klass = mono_class_get_full (image, token, generic_context);
1905 if (klass->valuetype) {
1906 ADD_CODE (&td, MINT_CPOBJ);
1907 ADD_CODE (&td, get_data_item_index(&td, klass));
1909 ADD_CODE (&td, MINT_LDIND_REF);
1910 ADD_CODE (&td, MINT_STIND_REF);
1918 CHECK_STACK (&td, 1);
1920 token = read32 (td.ip + 1);
1922 if (method->wrapper_type != MONO_WRAPPER_NONE)
1923 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
1925 klass = mono_class_get_full (image, token, generic_context);
1927 ADD_CODE(&td, MINT_LDOBJ);
1928 ADD_CODE(&td, get_data_item_index(&td, klass));
1929 if (mint_type (&klass->byval_arg) == MINT_TYPE_VT) {
1930 size = mono_class_value_size (klass, NULL);
1934 SET_TYPE(td.sp - 1, stack_type[mint_type(&klass->byval_arg)], klass);
1939 token = mono_metadata_token_index (read32 (td.ip + 1));
1941 if (method->wrapper_type != MONO_WRAPPER_NONE) {
1942 s = mono_string_new_wrapper(
1943 mono_method_get_wrapper_data (method, token));
1946 s = mono_ldstr (domain, image, token);
1947 ADD_CODE(&td, MINT_LDSTR);
1948 ADD_CODE(&td, get_data_item_index (&td, s));
1949 PUSH_TYPE(&td, STACK_TYPE_O, mono_defaults.string_class);
1954 MonoMethodSignature *csignature;
1955 guint32 vt_stack_used = 0;
1956 guint32 vt_res_size = 0;
1959 token = read32 (td.ip);
1962 if (method->wrapper_type != MONO_WRAPPER_NONE)
1963 m = (MonoMethod *)mono_method_get_wrapper_data (method, token);
1965 m = mono_get_method_full (image, token, NULL, generic_context);
1967 csignature = mono_method_signature (m);
1969 td.sp -= csignature->param_count;
1970 ADD_CODE(&td, MINT_NEWOBJ);
1971 ADD_CODE(&td, get_data_item_index (&td, mono_interp_get_runtime_method (domain, m, &error)));
1972 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1974 if (mint_type (&klass->byval_arg) == MINT_TYPE_VT) {
1975 vt_res_size = mono_class_value_size (klass, NULL);
1976 PUSH_VT (&td, vt_res_size);
1978 for (i = 0; i < csignature->param_count; ++i) {
1979 int mt = mint_type(csignature->params [i]);
1980 if (mt == MINT_TYPE_VT) {
1981 MonoClass *k = mono_class_from_mono_type (csignature->params [i]);
1982 gint32 size = mono_class_value_size (k, NULL);
1983 size = (size + 7) & ~7;
1984 vt_stack_used += size;
1987 if (vt_stack_used != 0 || vt_res_size != 0) {
1988 ADD_CODE(&td, MINT_VTRESULT);
1989 ADD_CODE(&td, vt_res_size);
1990 WRITE32(&td, &vt_stack_used);
1991 td.vt_sp -= vt_stack_used;
1993 PUSH_TYPE (&td, stack_type [mint_type (&klass->byval_arg)], klass);
1997 CHECK_STACK (&td, 1);
1998 token = read32 (td.ip + 1);
1999 klass = mini_get_class (method, token, generic_context);
2000 ADD_CODE(&td, MINT_CASTCLASS);
2001 ADD_CODE(&td, get_data_item_index (&td, klass));
2002 td.sp [-1].klass = klass;
2006 CHECK_STACK (&td, 1);
2007 token = read32 (td.ip + 1);
2008 klass = mini_get_class (method, token, generic_context);
2009 ADD_CODE(&td, MINT_ISINST);
2010 ADD_CODE(&td, get_data_item_index (&td, klass));
2014 switch (td.sp [-1].type) {
2018 ADD_CODE(&td, MINT_CONV_R_UN_I8);
2021 ADD_CODE(&td, MINT_CONV_R_UN_I4);
2024 g_assert_not_reached ();
2026 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8);
2030 CHECK_STACK (&td, 1);
2031 token = read32 (td.ip + 1);
2033 if (method->wrapper_type != MONO_WRAPPER_NONE)
2034 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
2036 klass = mono_class_get_full (image, token, generic_context);
2038 if (mono_class_is_nullable (klass)) {
2039 g_error ("cee_unbox: implement Nullable");
2042 ADD_CODE(&td, MINT_UNBOX);
2043 ADD_CODE(&td, get_data_item_index (&td, klass));
2044 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP);
2048 CHECK_STACK (&td, 1);
2049 token = read32 (td.ip + 1);
2051 klass = mini_get_class (method, token, generic_context);
2053 if (mini_type_is_reference (&klass->byval_arg)) {
2054 int mt = mint_type (&klass->byval_arg);
2055 ADD_CODE (&td, MINT_CASTCLASS);
2056 ADD_CODE (&td, get_data_item_index (&td, klass));
2057 SET_TYPE (td.sp - 1, stack_type [mt], klass);
2059 } else if (mono_class_is_nullable (klass)) {
2060 MonoMethod *target_method = mono_class_get_method_from_name (klass, "Unbox", 1);
2061 /* td.ip is incremented by interp_transform_call */
2062 interp_transform_call (&td, method, target_method, domain, generic_context, is_bb_start, body_start_offset, NULL, FALSE);
2064 int mt = mint_type (&klass->byval_arg);
2065 ADD_CODE (&td, MINT_UNBOX);
2066 ADD_CODE (&td, get_data_item_index (&td, klass));
2068 ADD_CODE (&td, MINT_LDOBJ);
2069 ADD_CODE (&td, get_data_item_index(&td, klass));
2070 SET_TYPE (td.sp - 1, stack_type [mt], klass);
2072 if (mt == MINT_TYPE_VT) {
2073 int size = mono_class_value_size (klass, NULL);
2074 PUSH_VT (&td, size);
2081 CHECK_STACK (&td, 1);
2082 SIMPLE_OP (td, MINT_THROW);
2084 generating_code = 0;
2087 CHECK_STACK (&td, 1);
2088 token = read32 (td.ip + 1);
2089 field = interp_field_from_token (method, token, &klass, generic_context);
2090 gboolean is_static = !!(field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2091 mono_class_init (klass);
2093 ADD_CODE (&td, MINT_POP);
2095 ADD_CODE (&td, MINT_LDSFLDA);
2096 ADD_CODE (&td, get_data_item_index (&td, field));
2098 if ((td.sp - 1)->type == STACK_TYPE_O) {
2099 ADD_CODE (&td, MINT_LDFLDA);
2101 g_assert ((td.sp -1)->type == STACK_TYPE_MP);
2102 ADD_CODE (&td, MINT_LDFLDA_UNSAFE);
2104 ADD_CODE (&td, klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
2107 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP);
2110 CHECK_STACK (&td, 1);
2111 token = read32 (td.ip + 1);
2112 field = interp_field_from_token (method, token, &klass, generic_context);
2113 gboolean is_static = !!(field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2114 mono_class_init (klass);
2116 MonoClass *field_klass = mono_class_from_mono_type (field->type);
2117 mt = mint_type (&field_klass->byval_arg);
2118 if (klass->marshalbyref) {
2119 g_assert (!is_static);
2120 ADD_CODE(&td, mt == MINT_TYPE_VT ? MINT_LDRMFLD_VT : MINT_LDRMFLD);
2121 ADD_CODE(&td, get_data_item_index (&td, field));
2124 ADD_CODE (&td, MINT_POP);
2126 ADD_CODE (&td, mt == MINT_TYPE_VT ? MINT_LDSFLD_VT : MINT_LDSFLD);
2127 ADD_CODE (&td, get_data_item_index (&td, field));
2129 ADD_CODE (&td, MINT_LDFLD_I1 + mt - MINT_TYPE_I1);
2130 ADD_CODE (&td, klass->valuetype ? field->offset - sizeof(MonoObject) : field->offset);
2133 if (mt == MINT_TYPE_VT) {
2134 int size = mono_class_value_size (field_klass, NULL);
2136 WRITE32(&td, &size);
2138 if (td.sp [-1].type == STACK_TYPE_VT) {
2139 int size = mono_class_value_size (klass, NULL);
2140 size = (size + 7) & ~7;
2142 ADD_CODE (&td, MINT_VTRESULT);
2144 WRITE32 (&td, &size);
2147 SET_TYPE(td.sp - 1, stack_type [mt], field_klass);
2151 CHECK_STACK (&td, 2);
2152 token = read32 (td.ip + 1);
2153 field = interp_field_from_token (method, token, &klass, generic_context);
2154 gboolean is_static = !!(field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2155 mono_class_init (klass);
2156 mt = mint_type(field->type);
2158 if (klass->marshalbyref) {
2159 g_assert (!is_static);
2160 ADD_CODE(&td, mt == MINT_TYPE_VT ? MINT_STRMFLD_VT : MINT_STRMFLD);
2161 ADD_CODE(&td, get_data_item_index (&td, field));
2164 ADD_CODE (&td, MINT_POP);
2166 ADD_CODE (&td, mt == MINT_TYPE_VT ? MINT_STSFLD_VT : MINT_STSFLD);
2167 ADD_CODE (&td, get_data_item_index (&td, field));
2169 ADD_CODE (&td, MINT_STFLD_I1 + mt - MINT_TYPE_I1);
2170 ADD_CODE (&td, klass->valuetype ? field->offset - sizeof(MonoObject) : field->offset);
2173 if (mt == MINT_TYPE_VT) {
2174 MonoClass *klass = mono_class_from_mono_type (field->type);
2175 int size = mono_class_value_size (klass, NULL);
2177 WRITE32(&td, &size);
2184 token = read32 (td.ip + 1);
2185 field = interp_field_from_token (method, token, &klass, generic_context);
2186 ADD_CODE(&td, MINT_LDSFLDA);
2187 ADD_CODE(&td, get_data_item_index (&td, field));
2189 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_MP);
2192 token = read32 (td.ip + 1);
2193 field = interp_field_from_token (method, token, &klass, generic_context);
2194 mt = mint_type(field->type);
2195 ADD_CODE(&td, mt == MINT_TYPE_VT ? MINT_LDSFLD_VT : MINT_LDSFLD);
2196 ADD_CODE(&td, get_data_item_index (&td, field));
2198 if (mt == MINT_TYPE_VT) {
2199 MonoClass *klass = mono_class_from_mono_type (field->type);
2200 int size = mono_class_value_size (klass, NULL);
2202 WRITE32(&td, &size);
2203 klass = field->type->data.klass;
2205 if (mt == MINT_TYPE_O)
2206 klass = mono_class_from_mono_type (field->type);
2209 PUSH_TYPE(&td, stack_type [mt], klass);
2212 CHECK_STACK (&td, 1);
2213 token = read32 (td.ip + 1);
2214 field = interp_field_from_token (method, token, &klass, generic_context);
2215 mt = mint_type(field->type);
2216 ADD_CODE(&td, mt == MINT_TYPE_VT ? MINT_STSFLD_VT : MINT_STSFLD);
2217 ADD_CODE(&td, get_data_item_index (&td, field));
2218 if (mt == MINT_TYPE_VT) {
2219 MonoClass *klass = mono_class_from_mono_type (field->type);
2220 int size = mono_class_value_size (klass, NULL);
2222 WRITE32 (&td, &size);
2229 token = read32 (td.ip + 1);
2231 if (method->wrapper_type != MONO_WRAPPER_NONE)
2232 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
2234 klass = mini_get_class (method, token, generic_context);
2236 ADD_CODE(&td, td.sp [-1].type == STACK_TYPE_VT ? MINT_STOBJ_VT : MINT_STOBJ);
2237 ADD_CODE(&td, get_data_item_index (&td, klass));
2238 if (td.sp [-1].type == STACK_TYPE_VT) {
2239 size = mono_class_value_size (klass, NULL);
2240 size = (size + 7) & ~7;
2247 case CEE_CONV_OVF_I_UN:
2248 case CEE_CONV_OVF_U_UN:
2249 CHECK_STACK (&td, 1);
2250 switch (td.sp [-1].type) {
2252 #if SIZEOF_VOID_P == 8
2253 ADD_CODE(&td, MINT_CONV_OVF_I8_UN_R8);
2255 ADD_CODE(&td, MINT_CONV_OVF_I4_UN_R8);
2259 #if SIZEOF_VOID_P == 4
2260 ADD_CODE (&td, MINT_CONV_OVF_I4_UN_I8);
2264 #if SIZEOF_VOID_P == 8
2265 ADD_CODE(&td, MINT_CONV_I8_U4);
2269 g_assert_not_reached ();
2272 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8);
2275 case CEE_CONV_OVF_I8_UN:
2276 case CEE_CONV_OVF_U8_UN:
2277 CHECK_STACK (&td, 1);
2278 switch (td.sp [-1].type) {
2280 ADD_CODE(&td, MINT_CONV_OVF_I8_UN_R8);
2283 if (*td.ip == CEE_CONV_OVF_I8_UN)
2284 ADD_CODE (&td, MINT_CONV_OVF_I8_U8);
2287 ADD_CODE(&td, MINT_CONV_I8_U4);
2290 g_assert_not_reached ();
2293 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8);
2298 CHECK_STACK (&td, 1);
2299 token = read32 (td.ip + 1);
2300 if (method->wrapper_type != MONO_WRAPPER_NONE)
2301 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
2303 klass = mini_get_class (method, token, generic_context);
2305 if (mono_class_is_nullable (klass)) {
2306 MonoMethod *target_method = mono_class_get_method_from_name (klass, "Box", 1);
2307 /* td.ip is incremented by interp_transform_call */
2308 interp_transform_call (&td, method, target_method, domain, generic_context, is_bb_start, body_start_offset, NULL, FALSE);
2309 } else if (!klass->valuetype) {
2310 /* already boxed, do nothing. */
2313 if (mint_type (&klass->byval_arg) == MINT_TYPE_VT && !klass->enumtype) {
2314 size = mono_class_value_size (klass, NULL);
2315 size = (size + 7) & ~7;
2318 ADD_CODE(&td, MINT_BOX);
2319 ADD_CODE(&td, get_data_item_index (&td, klass));
2321 SET_TYPE(td.sp - 1, STACK_TYPE_O, klass);
2328 CHECK_STACK (&td, 1);
2329 token = read32 (td.ip + 1);
2331 if (method->wrapper_type != MONO_WRAPPER_NONE)
2332 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
2334 klass = mini_get_class (method, token, generic_context);
2336 unsigned char lentype = (td.sp - 1)->type;
2337 if (lentype == STACK_TYPE_I8) {
2338 /* mimic mini behaviour */
2339 ADD_CODE (&td, MINT_CONV_OVF_U4_I8);
2341 g_assert (lentype == STACK_TYPE_I4);
2342 ADD_CODE (&td, MINT_CONV_OVF_U4_I4);
2344 SET_SIMPLE_TYPE (td.sp - 1, STACK_TYPE_I4);
2345 ADD_CODE (&td, MINT_NEWARR);
2346 ADD_CODE (&td, get_data_item_index (&td, klass));
2347 SET_TYPE (td.sp - 1, STACK_TYPE_O, klass);
2352 CHECK_STACK (&td, 1);
2353 SIMPLE_OP (td, MINT_LDLEN);
2354 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I);
2357 CHECK_STACK (&td, 2);
2359 token = read32 (td.ip + 1);
2361 if (method->wrapper_type != MONO_WRAPPER_NONE)
2362 klass = (MonoClass *) mono_method_get_wrapper_data (method, token);
2364 klass = mini_get_class (method, token, generic_context);
2366 if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
2367 ADD_CODE (&td, MINT_LDELEMA_TC);
2369 ADD_CODE (&td, MINT_LDELEMA);
2371 ADD_CODE (&td, get_data_item_index (&td, klass));
2372 /* according to spec, ldelema bytecode is only used for 1-dim arrays */
2378 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP);
2381 CHECK_STACK (&td, 2);
2383 SIMPLE_OP (td, MINT_LDELEM_I1);
2385 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2388 CHECK_STACK (&td, 2);
2390 SIMPLE_OP (td, MINT_LDELEM_U1);
2392 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2395 CHECK_STACK (&td, 2);
2397 SIMPLE_OP (td, MINT_LDELEM_I2);
2399 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2402 CHECK_STACK (&td, 2);
2404 SIMPLE_OP (td, MINT_LDELEM_U2);
2406 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2409 CHECK_STACK (&td, 2);
2411 SIMPLE_OP (td, MINT_LDELEM_I4);
2413 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2416 CHECK_STACK (&td, 2);
2418 SIMPLE_OP (td, MINT_LDELEM_U4);
2420 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2423 CHECK_STACK (&td, 2);
2425 SIMPLE_OP (td, MINT_LDELEM_I8);
2427 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8);
2430 CHECK_STACK (&td, 2);
2432 SIMPLE_OP (td, MINT_LDELEM_I);
2434 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I);
2437 CHECK_STACK (&td, 2);
2439 SIMPLE_OP (td, MINT_LDELEM_R4);
2441 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8);
2444 CHECK_STACK (&td, 2);
2446 SIMPLE_OP (td, MINT_LDELEM_R8);
2448 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8);
2450 case CEE_LDELEM_REF:
2451 CHECK_STACK (&td, 2);
2453 SIMPLE_OP (td, MINT_LDELEM_REF);
2455 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_O);
2458 CHECK_STACK (&td, 2);
2459 token = read32 (td.ip + 1);
2460 klass = mini_get_class (method, token, generic_context);
2461 switch (mint_type (&klass->byval_arg)) {
2464 SIMPLE_OP (td, MINT_LDELEM_I1);
2466 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2470 SIMPLE_OP (td, MINT_LDELEM_U1);
2472 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2476 SIMPLE_OP (td, MINT_LDELEM_U2);
2478 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2482 SIMPLE_OP (td, MINT_LDELEM_I2);
2484 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2488 SIMPLE_OP (td, MINT_LDELEM_I4);
2490 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2494 SIMPLE_OP (td, MINT_LDELEM_I8);
2496 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8);
2500 SIMPLE_OP (td, MINT_LDELEM_R4);
2502 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8);
2506 SIMPLE_OP (td, MINT_LDELEM_R8);
2508 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8);
2512 SIMPLE_OP (td, MINT_LDELEM_REF);
2514 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_O);
2516 case MINT_TYPE_VT: {
2517 int size = mono_class_value_size (klass, NULL);
2519 SIMPLE_OP (td, MINT_LDELEM_VT);
2520 ADD_CODE (&td, get_data_item_index (&td, klass));
2521 WRITE32 (&td, &size);
2523 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_VT);
2524 PUSH_VT (&td, size);
2528 GString *res = g_string_new ("");
2529 mono_type_get_desc (res, &klass->byval_arg, TRUE);
2530 g_print ("LDELEM: %s -> %d (%s)\n", klass->name, mint_type (&klass->byval_arg), res->str);
2531 g_string_free (res, TRUE);
2539 CHECK_STACK (&td, 3);
2541 SIMPLE_OP (td, MINT_STELEM_I);
2545 CHECK_STACK (&td, 3);
2547 SIMPLE_OP (td, MINT_STELEM_I1);
2551 CHECK_STACK (&td, 3);
2553 SIMPLE_OP (td, MINT_STELEM_I2);
2557 CHECK_STACK (&td, 3);
2559 SIMPLE_OP (td, MINT_STELEM_I4);
2563 CHECK_STACK (&td, 3);
2565 SIMPLE_OP (td, MINT_STELEM_I8);
2569 CHECK_STACK (&td, 3);
2571 SIMPLE_OP (td, MINT_STELEM_R4);
2575 CHECK_STACK (&td, 3);
2577 SIMPLE_OP (td, MINT_STELEM_R8);
2580 case CEE_STELEM_REF:
2581 CHECK_STACK (&td, 3);
2583 SIMPLE_OP (td, MINT_STELEM_REF);
2587 CHECK_STACK (&td, 3);
2589 token = read32 (td.ip + 1);
2590 klass = mini_get_class (method, token, generic_context);
2591 switch (mint_type (&klass->byval_arg)) {
2593 SIMPLE_OP (td, MINT_STELEM_U1);
2596 SIMPLE_OP (td, MINT_STELEM_U2);
2599 SIMPLE_OP (td, MINT_STELEM_I4);
2602 SIMPLE_OP (td, MINT_STELEM_I8);
2605 SIMPLE_OP (td, MINT_STELEM_REF);
2607 case MINT_TYPE_VT: {
2608 int size = mono_class_value_size (klass, NULL);
2609 SIMPLE_OP (td, MINT_STELEM_VT);
2610 ADD_CODE (&td, get_data_item_index (&td, klass));
2611 WRITE32 (&td, &size);
2616 GString *res = g_string_new ("");
2617 mono_type_get_desc (res, &klass->byval_arg, TRUE);
2618 g_print ("STELEM: %s -> %d (%s)\n", klass->name, mint_type (&klass->byval_arg), res->str);
2619 g_string_free (res, TRUE);
2628 case CEE_CONV_OVF_U1:
2630 case CEE_CONV_OVF_I8:
2632 #if SIZEOF_VOID_P == 8
2633 case CEE_CONV_OVF_U:
2635 case CEE_REFANYVAL: ves_abort(); break;
2638 CHECK_STACK (&td, 1);
2639 SIMPLE_OP (td, MINT_CKFINITE);
2641 case CEE_CONV_OVF_I1:
2642 case CEE_CONV_OVF_I1_UN:
2643 CHECK_STACK (&td, 1);
2644 switch (td.sp [-1].type) {
2646 ADD_CODE(&td, MINT_CONV_OVF_I1_R8);
2649 ADD_CODE(&td, MINT_CONV_OVF_I1_I4);
2652 ADD_CODE(&td, MINT_CONV_OVF_I1_I8);
2655 g_assert_not_reached ();
2658 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2660 case CEE_CONV_OVF_U1:
2661 case CEE_CONV_OVF_U1_UN:
2662 CHECK_STACK (&td, 1);
2663 switch (td.sp [-1].type) {
2665 ADD_CODE(&td, MINT_CONV_OVF_U1_R8);
2668 ADD_CODE(&td, MINT_CONV_OVF_U1_I4);
2671 ADD_CODE(&td, MINT_CONV_OVF_U1_I8);
2674 g_assert_not_reached ();
2677 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2679 case CEE_CONV_OVF_I2:
2680 case CEE_CONV_OVF_I2_UN:
2681 CHECK_STACK (&td, 1);
2682 switch (td.sp [-1].type) {
2684 ADD_CODE(&td, MINT_CONV_OVF_I2_R8);
2687 ADD_CODE(&td, MINT_CONV_OVF_I2_I4);
2690 ADD_CODE(&td, MINT_CONV_OVF_I2_I8);
2693 g_assert_not_reached ();
2696 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2698 case CEE_CONV_OVF_U2_UN:
2699 case CEE_CONV_OVF_U2:
2700 CHECK_STACK (&td, 1);
2701 switch (td.sp [-1].type) {
2703 ADD_CODE(&td, MINT_CONV_OVF_U2_R8);
2706 ADD_CODE(&td, MINT_CONV_OVF_U2_I4);
2709 ADD_CODE(&td, MINT_CONV_OVF_U2_I8);
2712 g_assert_not_reached ();
2715 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2717 #if SIZEOF_VOID_P == 4
2718 case CEE_CONV_OVF_I:
2720 case CEE_CONV_OVF_I4:
2721 case CEE_CONV_OVF_I4_UN:
2722 CHECK_STACK (&td, 1);
2723 switch (td.sp [-1].type) {
2725 ADD_CODE(&td, MINT_CONV_OVF_I4_R8);
2728 if (*td.ip == CEE_CONV_OVF_I4_UN)
2729 ADD_CODE(&td, MINT_CONV_OVF_I4_U4);
2732 if (*td.ip == CEE_CONV_OVF_I4_UN)
2733 ADD_CODE (&td, MINT_CONV_OVF_I4_U8);
2735 ADD_CODE (&td, MINT_CONV_OVF_I4_I8);
2738 g_assert_not_reached ();
2741 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2743 #if SIZEOF_VOID_P == 4
2744 case CEE_CONV_OVF_U:
2746 case CEE_CONV_OVF_U4:
2747 case CEE_CONV_OVF_U4_UN:
2748 CHECK_STACK (&td, 1);
2749 switch (td.sp [-1].type) {
2751 ADD_CODE(&td, MINT_CONV_OVF_U4_R8);
2754 if (*td.ip != CEE_CONV_OVF_U4_UN)
2755 ADD_CODE(&td, MINT_CONV_OVF_U4_I4);
2758 ADD_CODE(&td, MINT_CONV_OVF_U4_I8);
2761 g_assert_not_reached ();
2764 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2766 #if SIZEOF_VOID_P == 8
2767 case CEE_CONV_OVF_I:
2769 case CEE_CONV_OVF_I8:
2770 CHECK_STACK (&td, 1);
2771 switch (td.sp [-1].type) {
2773 ADD_CODE(&td, MINT_CONV_OVF_I8_R8);
2776 ADD_CODE(&td, MINT_CONV_I8_I4);
2781 g_assert_not_reached ();
2784 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8);
2786 #if SIZEOF_VOID_P == 8
2787 case CEE_CONV_OVF_U:
2789 case CEE_CONV_OVF_U8:
2790 CHECK_STACK (&td, 1);
2791 switch (td.sp [-1].type) {
2793 ADD_CODE(&td, MINT_CONV_OVF_U8_R8);
2796 ADD_CODE(&td, MINT_CONV_OVF_U8_I4);
2799 ADD_CODE (&td, MINT_CONV_OVF_U8_I8);
2802 g_assert_not_reached ();
2805 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8);
2810 token = read32 (td.ip + 1);
2811 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
2812 handle = mono_method_get_wrapper_data (method, token);
2813 klass = (MonoClass *) mono_method_get_wrapper_data (method, token + 1);
2814 if (klass == mono_defaults.typehandle_class)
2815 handle = &((MonoClass *) handle)->byval_arg;
2817 if (generic_context) {
2818 handle = mono_class_inflate_generic_type_checked (handle, generic_context, &error);
2819 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
2822 handle = mono_ldtoken (image, token, &klass, generic_context);
2824 mono_class_init (klass);
2825 mt = mint_type (&klass->byval_arg);
2826 g_assert (mt == MINT_TYPE_VT);
2827 size = mono_class_value_size (klass, NULL);
2828 g_assert (size == sizeof(gpointer));
2829 PUSH_VT (&td, sizeof(gpointer));
2830 ADD_CODE (&td, MINT_LDTOKEN);
2831 ADD_CODE (&td, get_data_item_index (&td, handle));
2833 SET_TYPE (td.sp, stack_type [mt], klass);
2839 binary_arith_op(&td, MINT_ADD_OVF_I4);
2842 case CEE_ADD_OVF_UN:
2843 binary_arith_op(&td, MINT_ADD_OVF_UN_I4);
2847 binary_arith_op(&td, MINT_MUL_OVF_I4);
2850 case CEE_MUL_OVF_UN:
2851 binary_arith_op(&td, MINT_MUL_OVF_UN_I4);
2855 binary_arith_op(&td, MINT_SUB_OVF_I4);
2858 case CEE_SUB_OVF_UN:
2859 binary_arith_op(&td, MINT_SUB_OVF_UN_I4);
2862 case CEE_ENDFINALLY:
2863 g_assert (td.clause_indexes [in_offset] != -1);
2865 SIMPLE_OP (td, MINT_ENDFINALLY);
2866 ADD_CODE (&td, td.clause_indexes [in_offset]);
2867 generating_code = 0;
2871 handle_branch (&td, MINT_LEAVE_S, MINT_LEAVE, 5 + read32 (td.ip + 1));
2873 generating_code = 0;
2877 handle_branch (&td, MINT_LEAVE_S, MINT_LEAVE, 2 + (gint8)td.ip [1]);
2879 generating_code = 0;
2884 case CEE_MONO_CALLI_EXTRA_ARG:
2885 /* Same as CEE_CALLI, except that we drop the extra arg required for llvm specific behaviour */
2886 ADD_CODE (&td, MINT_POP);
2889 interp_transform_call (&td, method, NULL, domain, generic_context, is_bb_start, body_start_offset, NULL, FALSE);
2891 case CEE_MONO_JIT_ICALL_ADDR: {
2894 MonoJitICallInfo *info;
2896 token = read32 (td.ip + 1);
2898 func = mono_method_get_wrapper_data (method, token);
2899 info = mono_find_jit_icall_by_addr (func);
2901 ADD_CODE (&td, MINT_LDFTN);
2902 ADD_CODE (&td, get_data_item_index (&td, func));
2903 PUSH_SIMPLE_TYPE (&td, STACK_TYPE_I);
2906 case CEE_MONO_ICALL: {
2909 MonoJitICallInfo *info;
2911 token = read32 (td.ip + 1);
2913 func = mono_method_get_wrapper_data (method, token);
2914 info = mono_find_jit_icall_by_addr (func);
2917 CHECK_STACK (&td, info->sig->param_count);
2918 switch (info->sig->param_count) {
2920 if (MONO_TYPE_IS_VOID (info->sig->ret))
2921 ADD_CODE (&td,MINT_ICALL_V_V);
2923 ADD_CODE (&td, MINT_ICALL_V_P);
2926 if (MONO_TYPE_IS_VOID (info->sig->ret))
2927 ADD_CODE (&td,MINT_ICALL_P_V);
2929 ADD_CODE (&td,MINT_ICALL_P_P);
2932 if (MONO_TYPE_IS_VOID (info->sig->ret)) {
2933 if (info->sig->params [1]->type == MONO_TYPE_I4)
2934 ADD_CODE (&td,MINT_ICALL_PI_V);
2936 ADD_CODE (&td,MINT_ICALL_PP_V);
2938 if (info->sig->params [1]->type == MONO_TYPE_I4)
2939 ADD_CODE (&td,MINT_ICALL_PI_P);
2941 ADD_CODE (&td,MINT_ICALL_PP_P);
2945 g_assert (MONO_TYPE_IS_VOID (info->sig->ret));
2946 if (info->sig->params [2]->type == MONO_TYPE_I4)
2947 ADD_CODE (&td,MINT_ICALL_PPI_V);
2949 ADD_CODE (&td,MINT_ICALL_PPP_V);
2952 g_assert_not_reached ();
2955 if (func == mono_ftnptr_to_delegate) {
2956 g_error ("TODO: ?");
2958 ADD_CODE(&td, get_data_item_index (&td, func));
2959 td.sp -= info->sig->param_count;
2961 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
2963 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I);
2967 case CEE_MONO_VTADDR: {
2969 CHECK_STACK (&td, 1);
2970 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2971 size = mono_class_native_size(td.sp [-1].klass, NULL);
2973 size = mono_class_value_size(td.sp [-1].klass, NULL);
2974 size = (size + 7) & ~7;
2975 ADD_CODE(&td, MINT_VTRESULT);
2977 WRITE32(&td, &size);
2980 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP);
2983 case CEE_MONO_LDPTR:
2984 case CEE_MONO_CLASSCONST:
2985 token = read32 (td.ip + 1);
2987 ADD_CODE(&td, MINT_MONO_LDPTR);
2988 ADD_CODE(&td, get_data_item_index (&td, mono_method_get_wrapper_data (method, token)));
2989 td.sp [0].type = STACK_TYPE_I;
2992 case CEE_MONO_OBJADDR:
2993 CHECK_STACK (&td, 1);
2995 td.sp[-1].type = STACK_TYPE_MP;
2998 case CEE_MONO_NEWOBJ:
2999 token = read32 (td.ip + 1);
3001 ADD_CODE(&td, MINT_MONO_NEWOBJ);
3002 ADD_CODE(&td, get_data_item_index (&td, mono_method_get_wrapper_data (method, token)));
3003 td.sp [0].type = STACK_TYPE_O;
3006 case CEE_MONO_RETOBJ:
3007 CHECK_STACK (&td, 1);
3008 token = read32 (td.ip + 1);
3010 ADD_CODE(&td, MINT_MONO_RETOBJ);
3013 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3015 /*stackval_from_data (signature->ret, frame->retval, sp->data.vt, signature->pinvoke);*/
3017 if (td.sp > td.stack)
3018 g_warning ("CEE_MONO_RETOBJ: more values on stack: %d", td.sp-td.stack);
3020 case CEE_MONO_LDNATIVEOBJ:
3021 token = read32 (td.ip + 1);
3023 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3024 g_assert(klass->valuetype);
3025 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP);
3027 case CEE_MONO_TLS: {
3028 gint32 key = read32 (td.ip + 1);
3030 g_assert (key < TLS_KEY_NUM);
3031 ADD_CODE (&td, MINT_MONO_TLS);
3032 WRITE32 (&td, &key);
3033 PUSH_SIMPLE_TYPE (&td, STACK_TYPE_MP);
3036 case CEE_MONO_ATOMIC_STORE_I4:
3037 CHECK_STACK (&td, 2);
3038 SIMPLE_OP (td, MINT_MONO_ATOMIC_STORE_I4);
3042 case CEE_MONO_SAVE_LMF:
3043 case CEE_MONO_RESTORE_LMF:
3044 case CEE_MONO_NOT_TAKEN:
3047 case CEE_MONO_LDPTR_INT_REQ_FLAG:
3048 ADD_CODE (&td, MINT_MONO_LDPTR);
3049 ADD_CODE (&td, get_data_item_index (&td, mono_thread_interruption_request_flag ()));
3050 PUSH_TYPE (&td, STACK_TYPE_MP, NULL);
3053 case CEE_MONO_JIT_ATTACH:
3054 ADD_CODE (&td, MINT_MONO_JIT_ATTACH);
3057 case CEE_MONO_JIT_DETACH:
3058 ADD_CODE (&td, MINT_MONO_JIT_DETACH);
3062 g_error ("transform.c: Unimplemented opcode: 0xF0 %02x at 0x%x\n", *td.ip, td.ip-header->code);
3072 case CEE_PREFIXREF: ves_abort(); break;
3075 * Note: Exceptions thrown when executing a prefixed opcode need
3076 * to take into account the number of prefix bytes (usually the
3077 * throw point is just (ip - n_prefix_bytes).
3083 case CEE_ARGLIST: ves_abort(); break;
3086 CHECK_STACK(&td, 2);
3087 if (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_MP)
3088 ADD_CODE(&td, MINT_CEQ_I4 + STACK_TYPE_I - STACK_TYPE_I4);
3090 ADD_CODE(&td, MINT_CEQ_I4 + td.sp [-1].type - STACK_TYPE_I4);
3092 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
3096 CHECK_STACK(&td, 2);
3097 if (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_MP)
3098 ADD_CODE(&td, MINT_CGT_I4 + STACK_TYPE_I - STACK_TYPE_I4);
3100 ADD_CODE(&td, MINT_CGT_I4 + td.sp [-1].type - STACK_TYPE_I4);
3102 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
3106 CHECK_STACK(&td, 2);
3107 if (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_MP)
3108 ADD_CODE(&td, MINT_CGT_UN_I4 + STACK_TYPE_I - STACK_TYPE_I4);
3110 ADD_CODE(&td, MINT_CGT_UN_I4 + td.sp [-1].type - STACK_TYPE_I4);
3112 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
3116 CHECK_STACK(&td, 2);
3117 if (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_MP)
3118 ADD_CODE(&td, MINT_CLT_I4 + STACK_TYPE_I - STACK_TYPE_I4);
3120 ADD_CODE(&td, MINT_CLT_I4 + td.sp [-1].type - STACK_TYPE_I4);
3122 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
3126 CHECK_STACK(&td, 2);
3127 if (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_MP)
3128 ADD_CODE(&td, MINT_CLT_UN_I4 + STACK_TYPE_I - STACK_TYPE_I4);
3130 ADD_CODE(&td, MINT_CLT_UN_I4 + td.sp [-1].type - STACK_TYPE_I4);
3132 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
3135 case CEE_LDVIRTFTN: /* fallthrough */
3138 if (*td.ip == CEE_LDVIRTFTN) {
3139 CHECK_STACK (&td, 1);
3142 token = read32 (td.ip + 1);
3143 if (method->wrapper_type != MONO_WRAPPER_NONE)
3144 m = (MonoMethod *)mono_method_get_wrapper_data (method, token);
3146 m = mono_get_method_full (image, token, NULL, generic_context);
3148 if (method->wrapper_type == MONO_WRAPPER_NONE && m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
3149 m = mono_marshal_get_synchronized_wrapper (m);
3151 ADD_CODE(&td, *td.ip == CEE_LDFTN ? MINT_LDFTN : MINT_LDVIRTFTN);
3152 ADD_CODE(&td, get_data_item_index (&td, mono_interp_get_runtime_method (domain, m, &error)));
3153 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3155 PUSH_SIMPLE_TYPE (&td, STACK_TYPE_F);
3159 load_arg (&td, read16 (td.ip + 1));
3163 int n = read16 (td.ip + 1);
3164 ADD_CODE (&td, MINT_LDARGA);
3165 ADD_CODE (&td, td.rtm->arg_offsets [n]); /* FIX for large offsets */
3166 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_MP);
3171 store_arg (&td, read16 (td.ip + 1));
3175 load_local (&td, read16 (td.ip + 1));
3179 ADD_CODE(&td, MINT_LDLOCA_S);
3180 ADD_CODE(&td, td.rtm->local_offsets [read16 (td.ip + 1)]);
3181 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_MP);
3185 store_local (&td, read16 (td.ip + 1));
3189 CHECK_STACK (&td, 1);
3190 #if SIZEOF_VOID_P == 8
3191 if (td.sp [-1].type == STACK_TYPE_I8)
3192 ADD_CODE(&td, MINT_CONV_I4_I8);
3194 ADD_CODE(&td, MINT_LOCALLOC);
3195 if (td.sp != td.stack + 1)
3196 g_warning("CEE_LOCALLOC: stack not empty");
3198 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP);
3201 case CEE_UNUSED57: ves_abort(); break;
3204 ADD_CODE (&td, MINT_ENDFILTER);
3207 case CEE_UNALIGNED_:
3209 /* FIX: should do something? */;
3213 /* FIX: should do something? */;
3217 /* FIX: should do something? */;
3220 CHECK_STACK(&td, 1);
3221 token = read32 (td.ip + 1);
3222 klass = mini_get_class (method, token, generic_context);
3223 if (klass->valuetype) {
3224 ADD_CODE (&td, MINT_INITOBJ);
3225 i32 = mono_class_value_size (klass, NULL);
3226 WRITE32 (&td, &i32);
3228 ADD_CODE (&td, MINT_LDNULL);
3229 ADD_CODE (&td, MINT_STIND_REF);
3235 CHECK_STACK(&td, 3);
3236 /* FIX? convert length to I8? */
3237 ADD_CODE(&td, MINT_CPBLK);
3245 case CEE_CONSTRAINED_:
3246 token = read32 (td.ip + 1);
3247 constrained_class = mini_get_class (method, token, generic_context);
3248 mono_class_init (constrained_class);
3252 CHECK_STACK(&td, 3);
3253 ADD_CODE(&td, MINT_INITBLK);
3259 /* FIXME: implement */
3264 SIMPLE_OP (td, MINT_RETHROW);
3265 generating_code = 0;
3269 token = read32 (td.ip + 1);
3271 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
3273 MonoType *type = mono_type_create_from_typespec (image, token);
3274 size = mono_type_size (type, &align);
3277 MonoClass *szclass = mini_get_class (method, token, generic_context);
3278 mono_class_init (szclass);
3280 if (!szclass->valuetype)
3281 THROW_EX (mono_exception_from_name (mono_defaults.corlib, "System", "InvalidProgramException"), ip - 5);
3283 size = mono_type_size (&szclass->byval_arg, &align);
3285 ADD_CODE(&td, MINT_LDC_I4);
3286 WRITE32(&td, &size);
3287 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4);
3291 case CEE_REFANYTYPE: ves_abort(); break;
3294 g_error ("transform.c: Unimplemented opcode: 0xFE %02x (%s) at 0x%x\n", *td.ip, mono_opcode_name (256 + *td.ip), td.ip-header->code);
3298 g_error ("transform.c: Unimplemented opcode: %02x at 0x%x\n", *td.ip, td.ip-header->code);
3301 if (td.new_ip - td.new_code != new_in_start_offset)
3302 td.last_new_ip = td.new_code + new_in_start_offset;
3303 else if (td.is_bb_start [td.in_start - td.il_code])
3304 td.is_bb_start [td.ip - td.il_code] = 1;
3306 td.last_ip = td.in_start;
3309 if (mono_interp_traceopt) {
3310 const guint16 *p = td.new_code;
3311 printf("Runtime method: %p, VT stack size: %d\n", rtm, td.max_vt_sp);
3312 printf("Calculated stack size: %d, stated size: %d\n", td.max_stack_height, header->max_stack);
3313 while (p < td.new_ip) {
3314 p = mono_interp_dis_mintop(td.new_code, p);
3318 g_assert (td.max_stack_height <= (header->max_stack + 1));
3320 int code_len = td.new_ip - td.new_code;
3322 rtm->clauses = mono_domain_alloc0 (domain, header->num_clauses * sizeof (MonoExceptionClause));
3323 memcpy (rtm->clauses, header->clauses, header->num_clauses * sizeof(MonoExceptionClause));
3324 rtm->code = mono_domain_alloc0 (domain, (td.new_ip - td.new_code) * sizeof (gushort));
3325 memcpy (rtm->code, td.new_code, (td.new_ip - td.new_code) * sizeof(gushort));
3326 g_free (td.new_code);
3327 rtm->new_body_start = rtm->code + body_start_offset;
3328 rtm->num_clauses = header->num_clauses;
3329 for (i = 0; i < header->num_clauses; i++) {
3330 MonoExceptionClause *c = rtm->clauses + i;
3331 int end_off = c->try_offset + c->try_len;
3332 c->try_offset = td.in_offsets [c->try_offset];
3333 c->try_len = td.in_offsets [end_off] - c->try_offset;
3334 end_off = c->handler_offset + c->handler_len;
3335 c->handler_offset = td.in_offsets [c->handler_offset];
3336 c->handler_len = td.in_offsets [end_off] - c->handler_offset;
3337 if (c->flags & MONO_EXCEPTION_CLAUSE_FILTER)
3338 c->data.filter_offset = td.in_offsets [c->data.filter_offset];
3340 rtm->vt_stack_size = td.max_vt_sp;
3341 rtm->alloca_size = rtm->locals_size + rtm->args_size + rtm->vt_stack_size + rtm->stack_size;
3342 rtm->data_items = mono_domain_alloc0 (domain, td.n_data_items * sizeof (td.data_items [0]));
3343 memcpy (rtm->data_items, td.data_items, td.n_data_items * sizeof (td.data_items [0]));
3345 /* Save debug info */
3346 interp_save_debug_info (rtm, header, &td, line_numbers);
3348 /* Create a MonoJitInfo for the interpreted method by creating the interpreter IR as the native code. */
3349 int jinfo_len = mono_jit_info_size (0, header->num_clauses, 0);
3350 MonoJitInfo *jinfo = (MonoJitInfo *)mono_domain_alloc0 (domain, jinfo_len);
3352 mono_jit_info_init (jinfo, method, (guint8*)rtm->code, code_len, 0, header->num_clauses, 0);
3353 for (i = 0; i < jinfo->num_clauses; ++i) {
3354 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
3355 MonoExceptionClause *c = rtm->clauses + i;
3357 ei->flags = c->flags;
3358 ei->try_start = rtm->code + c->try_offset;
3359 ei->try_end = rtm->code + c->try_offset + c->try_len;
3360 ei->handler_start = rtm->code + c->handler_offset;
3361 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
3363 ei->data.catch_class = c->data.catch_class;
3367 g_free (td.in_offsets);
3368 g_free (td.forward_refs);
3369 for (i = 0; i < header->code_size; ++i)
3370 g_free (td.stack_state [i]);
3371 g_free (td.stack_state);
3372 g_free (td.stack_height);
3373 g_free (td.vt_stack_size);
3374 g_free (td.data_items);
3376 g_hash_table_destroy (td.data_hash);
3377 g_free (td.clause_indexes);
3378 g_array_free (line_numbers, TRUE);
3381 static mono_mutex_t calc_section;
3384 mono_interp_transform_init (void)
3386 mono_os_mutex_init_recursive(&calc_section);
3390 mono_interp_transform_method (RuntimeMethod *runtime_method, ThreadContext *context)
3392 int i, align, size, offset;
3393 MonoMethod *method = runtime_method->method;
3394 MonoImage *image = method->klass->image;
3395 MonoMethodHeader *header = mono_method_get_header (method);
3396 MonoMethodSignature *signature = mono_method_signature (method);
3397 register const unsigned char *ip, *end;
3398 const MonoOpcode *opcode;
3401 MonoDomain *domain = mono_domain_get ();
3402 unsigned char *is_bb_start;
3404 MonoVTable *method_class_vt;
3406 MonoGenericContext *generic_context = NULL;
3408 // g_printerr ("TRANSFORM(0x%016lx): begin %s::%s\n", mono_thread_current (), method->klass->name, method->name);
3409 method_class_vt = mono_class_vtable (domain, runtime_method->method->klass);
3410 if (!method_class_vt->initialized) {
3413 MonoInvocation *last_env_frame = context->env_frame;
3414 jmp_buf *old_env = context->current_env;
3415 error_init (&error);
3418 MonoException *failed = context->env_frame->ex;
3419 context->env_frame->ex = NULL;
3420 context->env_frame = last_env_frame;
3421 context->current_env = old_env;
3424 context->env_frame = context->current_frame;
3425 context->current_env = &env;
3426 mono_runtime_class_init_full (method_class_vt, &error);
3427 if (!mono_error_ok (&error)) {
3428 return mono_error_convert_to_exception (&error);
3430 context->env_frame = last_env_frame;
3431 context->current_env = old_env;
3434 mono_profiler_method_jit (method); /* sort of... */
3436 if (mono_method_signature (method)->is_inflated)
3437 generic_context = mono_method_get_context (method);
3439 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
3440 if (generic_container)
3441 generic_context = &generic_container->context;
3444 if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
3445 MonoMethod *nm = NULL;
3446 mono_os_mutex_lock(&calc_section);
3447 if (runtime_method->transformed) {
3448 mono_os_mutex_unlock(&calc_section);
3449 mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK);
3453 /* assumes all internal calls with an array this are built in... */
3454 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL && (! mono_method_signature (method)->hasthis || method->klass->rank == 0)) {
3455 nm = mono_marshal_get_native_wrapper (method, TRUE, FALSE);
3456 signature = mono_method_signature (nm);
3458 const char *name = method->name;
3459 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
3460 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
3461 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("ves_icall_mono_delegate_ctor");
3463 char *wrapper_name = g_strdup_printf ("__icall_wrapper_%s", mi->name);
3464 nm = mono_marshal_get_icall_wrapper (mi->sig, wrapper_name, mi->func, TRUE);
3465 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
3466 nm = mono_marshal_get_delegate_invoke (method, NULL);
3467 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
3468 nm = mono_marshal_get_delegate_begin_invoke (method);
3469 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
3470 nm = mono_marshal_get_delegate_end_invoke (method);
3474 runtime_method->code = g_malloc(sizeof(short));
3475 runtime_method->code[0] = MINT_CALLRUN;
3479 runtime_method->stack_size = sizeof (stackval); /* for tracing */
3480 runtime_method->alloca_size = runtime_method->stack_size;
3481 runtime_method->transformed = TRUE;
3482 mono_os_mutex_unlock(&calc_section);
3483 mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK);
3487 header = mono_method_get_header (nm);
3488 mono_os_mutex_unlock(&calc_section);
3489 } else if (method->klass == mono_defaults.array_class) {
3490 if (!strcmp (method->name, "UnsafeMov")) {
3491 mono_os_mutex_lock (&calc_section);
3492 if (!runtime_method->transformed) {
3493 runtime_method->code = g_malloc (sizeof (short));
3494 runtime_method->code[0] = MINT_CALLRUN;
3495 runtime_method->stack_size = sizeof (stackval); /* for tracing */
3496 runtime_method->alloca_size = runtime_method->stack_size;
3497 runtime_method->transformed = TRUE;
3499 mono_os_mutex_unlock(&calc_section);
3500 mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK);
3502 } else if (!strcmp (method->name, "UnsafeStore)")) {
3504 } else if (!strcmp (method->name, "UnsafeLoad)")) {
3508 g_assert ((signature->param_count + signature->hasthis) < 1000);
3509 g_assert (header->max_stack < 10000);
3510 /* intern the strings in the method. */
3512 end = ip + header->code_size;
3514 is_bb_start = g_malloc0(header->code_size);
3515 is_bb_start [0] = 1;
3522 else if (in == 0xf0) {
3524 in = *ip + MONO_CEE_MONO_ICALL;
3526 opcode = &mono_opcodes [in];
3527 switch (opcode->argument) {
3528 case MonoInlineNone:
3531 case MonoInlineString:
3532 if (method->wrapper_type == MONO_WRAPPER_NONE)
3533 mono_ldstr (domain, image, mono_metadata_token_index (read32 (ip + 1)));
3536 case MonoInlineType:
3537 if (method->wrapper_type == MONO_WRAPPER_NONE) {
3538 class = mini_get_class (method, read32 (ip + 1), generic_context);
3539 mono_class_init (class);
3540 /* quick fix to not do this for the fake ptr classes - probably should not be getting the vtable at all here */
3542 g_error ("FIXME: interface method lookup: %s (in method %s)", class->name, method->name);
3543 if (!(class->flags & TYPE_ATTRIBUTE_INTERFACE) && class->interface_offsets != NULL)
3544 mono_class_vtable (domain, class);
3549 case MonoInlineMethod:
3550 if (method->wrapper_type == MONO_WRAPPER_NONE && *ip != CEE_CALLI) {
3551 m = mono_get_method_full (image, read32 (ip + 1), NULL, generic_context);
3553 g_free (is_bb_start);
3554 g_error ("FIXME: where to get method and class string?");
3556 // return mono_get_exception_missing_method ();
3558 mono_class_init (m->klass);
3559 if (!mono_class_is_interface (m->klass))
3560 mono_class_vtable (domain, m->klass);
3564 case MonoInlineField:
3568 case MonoShortInlineR:
3571 case MonoInlineBrTarget:
3572 offset = read32 (ip + 1);
3574 backwards = offset < 0;
3575 offset += ip - header->code;
3576 g_assert (offset >= 0 && offset < header->code_size);
3577 is_bb_start [offset] |= backwards ? 2 : 1;
3579 case MonoShortInlineBrTarget:
3580 offset = ((gint8 *)ip) [1];
3582 backwards = offset < 0;
3583 offset += ip - header->code;
3584 g_assert (offset >= 0 && offset < header->code_size);
3585 is_bb_start [offset] |= backwards ? 2 : 1;
3590 case MonoShortInlineVar:
3591 case MonoShortInlineI:
3594 case MonoInlineSwitch: {
3596 const unsigned char *next_ip;
3600 next_ip = ip + 4 * n;
3601 for (i = 0; i < n; i++) {
3602 offset = read32 (ip);
3603 backwards = offset < 0;
3604 offset += next_ip - header->code;
3605 g_assert (offset >= 0 && offset < header->code_size);
3606 is_bb_start [offset] |= backwards ? 2 : 1;
3616 g_assert_not_reached ();
3619 // g_printerr ("TRANSFORM(0x%016lx): end %s::%s\n", mono_thread_current (), method->klass->name, method->name);
3621 /* the rest needs to be locked so it is only done once */
3622 mono_os_mutex_lock(&calc_section);
3623 if (runtime_method->transformed) {
3624 mono_os_mutex_unlock(&calc_section);
3625 g_free (is_bb_start);
3626 mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK);
3630 runtime_method->local_offsets = g_malloc (header->num_locals * sizeof(guint32));
3631 runtime_method->stack_size = (sizeof (stackval)) * (header->max_stack + 2); /* + 1 for returns of called functions + 1 for 0-ing in trace*/
3632 runtime_method->stack_size = (runtime_method->stack_size + 7) & ~7;
3634 for (i = 0; i < header->num_locals; ++i) {
3635 size = mono_type_size (header->locals [i], &align);
3636 offset += align - 1;
3637 offset &= ~(align - 1);
3638 runtime_method->local_offsets [i] = offset;
3641 offset = (offset + 7) & ~7;
3642 runtime_method->locals_size = offset;
3643 g_assert (runtime_method->locals_size < 65536);
3645 runtime_method->arg_offsets = g_malloc ((!!signature->hasthis + signature->param_count) * sizeof(guint32));
3647 if (signature->hasthis) {
3648 g_assert (!signature->pinvoke);
3649 size = mono_type_stack_size (&method->klass->byval_arg, &align);
3650 offset += align - 1;
3651 offset &= ~(align - 1);
3652 runtime_method->arg_offsets [0] = offset;
3656 for (i = 0; i < signature->param_count; ++i) {
3657 if (signature->pinvoke) {
3659 size = mono_type_native_stack_size (signature->params [i], &dummy);
3663 size = mono_type_stack_size (signature->params [i], &align);
3664 offset += align - 1;
3665 offset &= ~(align - 1);
3666 runtime_method->arg_offsets [i + !!signature->hasthis] = offset;
3669 offset = (offset + 7) & ~7;
3670 runtime_method->args_size = offset;
3671 g_assert (runtime_method->args_size < 10000);
3673 generate (method, runtime_method, is_bb_start, generic_context);
3675 g_free (is_bb_start);
3677 mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK);
3678 runtime_method->transformed = TRUE;
3679 mono_os_mutex_unlock(&calc_section);