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 binary_int_op(TransformData *td, int mint_op)
265 int op = mint_op + td->sp [-1].type - STACK_TYPE_I4;
267 if (td->sp [-1].type != td->sp [-2].type)
268 g_warning("%s.%s: int type mismatch", td->method->klass->name, td->method->name);
274 shift_op(TransformData *td, int mint_op)
276 int op = mint_op + td->sp [-2].type - STACK_TYPE_I4;
278 if (td->sp [-1].type != STACK_TYPE_I4) {
279 g_warning("%s.%s: shift type mismatch %d",
280 td->method->klass->name, td->method->name,
288 mint_type(MonoType *type)
293 switch (type->type) {
297 case MONO_TYPE_BOOLEAN:
309 #if SIZEOF_VOID_P == 4
323 case MONO_TYPE_STRING:
324 case MONO_TYPE_SZARRAY:
325 case MONO_TYPE_CLASS:
326 case MONO_TYPE_OBJECT:
327 case MONO_TYPE_ARRAY:
329 case MONO_TYPE_VALUETYPE:
330 if (type->data.klass->enumtype) {
331 type = mono_class_enum_basetype (type->data.klass);
335 case MONO_TYPE_GENERICINST:
336 type = &type->data.generic_class->container_class->byval_arg;
339 g_warning ("got type 0x%02x", type->type);
340 g_assert_not_reached ();
346 can_store (int stack_type, int var_type)
348 if (stack_type == STACK_TYPE_O || stack_type == STACK_TYPE_MP)
349 stack_type = STACK_TYPE_I;
350 if (var_type == STACK_TYPE_O || var_type == STACK_TYPE_MP)
351 var_type = STACK_TYPE_I;
352 return stack_type == var_type;
355 #define SET_SIMPLE_TYPE(s, ty) \
362 #define SET_TYPE(s, ty, k) \
369 #define PUSH_SIMPLE_TYPE(td, ty) \
373 sp_height = (td)->sp - (td)->stack; \
374 if (sp_height > (td)->max_stack_height) \
375 (td)->max_stack_height = sp_height; \
376 SET_SIMPLE_TYPE((td)->sp - 1, ty); \
379 #define PUSH_TYPE(td, ty, k) \
383 sp_height = (td)->sp - (td)->stack; \
384 if (sp_height > (td)->max_stack_height) \
385 (td)->max_stack_height = sp_height; \
386 SET_TYPE((td)->sp - 1, ty, k); \
389 #define PUSH_VT(td, size) \
391 (td)->vt_sp += ((size) + 7) & ~7; \
392 if ((td)->vt_sp > (td)->max_vt_sp) \
393 (td)->max_vt_sp = (td)->vt_sp; \
396 #define POP_VT(td, size) \
398 (td)->vt_sp -= ((size) + 7) & ~7; \
401 #if NO_UNALIGNED_ACCESS
402 #define WRITE32(td, v) \
404 ENSURE_CODE(td, 2); \
405 * (guint16 *)((td)->new_ip) = * (guint16 *)(v); \
406 * ((guint16 *)((td)->new_ip) + 1) = * ((guint16 *)(v) + 1); \
410 #define WRITE64(td, v) \
412 ENSURE_CODE(td, 4); \
413 * (guint16 *)((td)->new_ip) = * (guint16 *)(v); \
414 * ((guint16 *)((td)->new_ip) + 1) = * ((guint16 *)(v) + 1); \
415 * ((guint16 *)((td)->new_ip) + 2) = * ((guint16 *)(v) + 2); \
416 * ((guint16 *)((td)->new_ip) + 3) = * ((guint16 *)(v) + 3); \
420 #define WRITE32(td, v) \
422 ENSURE_CODE(td, 2); \
423 * (guint32 *)((td)->new_ip) = * (guint32 *)(v); \
427 #define WRITE64(td, v) \
429 ENSURE_CODE(td, 4); \
430 * (guint64 *)((td)->new_ip) = * (guint64 *)(v); \
437 load_arg(TransformData *td, int n)
440 MonoClass *klass = NULL;
443 gboolean hasthis = mono_method_signature (td->method)->hasthis;
444 if (hasthis && n == 0)
445 type = &td->method->klass->byval_arg;
447 type = mono_method_signature (td->method)->params [hasthis ? n - 1 : n];
449 mt = mint_type (type);
450 if (mt == MINT_TYPE_VT) {
452 klass = mono_class_from_mono_type (type);
453 if (mono_method_signature (td->method)->pinvoke)
454 size = mono_class_native_size (klass, NULL);
456 size = mono_class_value_size (klass, NULL);
458 if (hasthis && n == 0) {
460 ADD_CODE (td, MINT_LDARG_P);
461 ADD_CODE (td, td->rtm->arg_offsets [n]); /* FIX for large offset */
465 ADD_CODE (td, MINT_LDARG_VT);
466 ADD_CODE (td, td->rtm->arg_offsets [n]); /* FIX for large offset */
470 if (hasthis && n == 0) {
472 ADD_CODE (td, MINT_LDARG_P);
473 ADD_CODE (td, td->rtm->arg_offsets [n]); /* FIX for large offset */
476 ADD_CODE(td, MINT_LDARG_I1 + (mt - MINT_TYPE_I1));
477 ADD_CODE(td, td->rtm->arg_offsets [n]); /* FIX for large offset */
478 if (mt == MINT_TYPE_O)
479 klass = mono_class_from_mono_type (type);
482 PUSH_TYPE(td, stack_type[mt], klass);
486 store_arg(TransformData *td, int n)
492 gboolean hasthis = mono_method_signature (td->method)->hasthis;
493 if (hasthis && n == 0)
494 type = &td->method->klass->byval_arg;
496 type = mono_method_signature (td->method)->params [n - !!hasthis];
498 mt = mint_type (type);
499 if (mt == MINT_TYPE_VT) {
501 MonoClass *klass = mono_class_from_mono_type (type);
502 if (mono_method_signature (td->method)->pinvoke)
503 size = mono_class_native_size (klass, NULL);
505 size = mono_class_value_size (klass, NULL);
506 ADD_CODE(td, MINT_STARG_VT);
507 ADD_CODE(td, td->rtm->arg_offsets [n]);
509 if (td->sp [-1].type == STACK_TYPE_VT)
512 ADD_CODE(td, MINT_STARG_I1 + (mt - MINT_TYPE_I1));
513 ADD_CODE(td, td->rtm->arg_offsets [n]);
519 store_inarg(TransformData *td, int n)
522 gboolean hasthis = mono_method_signature (td->method)->hasthis;
523 if (hasthis && n == 0)
524 type = &td->method->klass->byval_arg;
526 type = mono_method_signature (td->method)->params [n - !!hasthis];
528 int mt = mint_type (type);
529 if (hasthis && n == 0) {
530 ADD_CODE (td, MINT_STINARG_P);
534 if (mt == MINT_TYPE_VT) {
535 MonoClass *klass = mono_class_from_mono_type (type);
537 if (mono_method_signature (td->method)->pinvoke)
538 size = mono_class_native_size (klass, NULL);
540 size = mono_class_value_size (klass, NULL);
541 ADD_CODE(td, MINT_STINARG_VT);
545 ADD_CODE(td, MINT_STINARG_I1 + (mt - MINT_TYPE_I1));
551 load_local(TransformData *td, int n)
553 MonoType *type = td->header->locals [n];
554 int mt = mint_type (type);
555 int offset = td->rtm->local_offsets [n];
556 MonoClass *klass = NULL;
557 if (mt == MINT_TYPE_VT) {
558 klass = mono_class_from_mono_type (type);
559 gint32 size = mono_class_value_size (klass, NULL);
561 ADD_CODE(td, MINT_LDLOC_VT);
562 ADD_CODE(td, offset); /*FIX for large offset */
565 g_assert (mt < MINT_TYPE_VT);
566 if (mt == MINT_TYPE_I4 && !td->is_bb_start [td->in_start - td->il_code] && td->last_new_ip != NULL &&
567 td->last_new_ip [0] == MINT_STLOC_I4 && td->last_new_ip [1] == offset) {
568 td->last_new_ip [0] = MINT_STLOC_NP_I4;
569 } else if (mt == MINT_TYPE_O && !td->is_bb_start [td->in_start - td->il_code] && td->last_new_ip != NULL &&
570 td->last_new_ip [0] == MINT_STLOC_O && td->last_new_ip [1] == offset) {
571 td->last_new_ip [0] = MINT_STLOC_NP_O;
573 ADD_CODE(td, MINT_LDLOC_I1 + (mt - MINT_TYPE_I1));
574 ADD_CODE(td, offset); /*FIX for large offset */
576 if (mt == MINT_TYPE_O)
577 klass = mono_class_from_mono_type (type);
579 PUSH_TYPE(td, stack_type[mt], klass);
583 store_local(TransformData *td, int n)
585 MonoType *type = td->header->locals [n];
586 int mt = mint_type (type);
587 int offset = td->rtm->local_offsets [n];
589 #if SIZEOF_VOID_P == 8
590 if (td->sp [-1].type == STACK_TYPE_I4 && stack_type [mt] == STACK_TYPE_I8) {
591 ADD_CODE(td, MINT_CONV_I8_I4);
592 td->sp [-1].type = STACK_TYPE_I8;
595 if (!can_store(td->sp [-1].type, stack_type [mt])) {
596 g_warning("%s.%s: Store local stack type mismatch %d %d",
597 td->method->klass->name, td->method->name,
598 stack_type [mt], td->sp [-1].type);
600 if (mt == MINT_TYPE_VT) {
601 MonoClass *klass = mono_class_from_mono_type (type);
602 gint32 size = mono_class_value_size (klass, NULL);
603 ADD_CODE(td, MINT_STLOC_VT);
604 ADD_CODE(td, offset); /*FIX for large offset */
606 if (td->sp [-1].type == STACK_TYPE_VT)
609 g_assert (mt < MINT_TYPE_VT);
610 ADD_CODE(td, MINT_STLOC_I1 + (mt - MINT_TYPE_I1));
611 ADD_CODE(td, offset); /*FIX for large offset */
616 #define SIMPLE_OP(td, op) \
623 get_data_item_index (TransformData *td, void *ptr)
625 gpointer p = g_hash_table_lookup (td->data_hash, ptr);
628 return GPOINTER_TO_UINT (p) - 1;
629 if (td->max_data_items == td->n_data_items) {
630 td->max_data_items = td->n_data_items == 0 ? 16 : 2 * td->max_data_items;
631 td->data_items = g_realloc (td->data_items, td->max_data_items * sizeof(td->data_items [0]));
633 index = td->n_data_items;
634 td->data_items [index] = ptr;
636 g_hash_table_insert (td->data_hash, ptr, GUINT_TO_POINTER (index + 1));
641 jit_call_supported (MonoMethod *method, MonoMethodSignature *sig)
645 if (sig->param_count > 6)
649 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
651 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
653 if (method->is_inflated)
655 if (method->string_ctor)
658 for (l = jit_classes; l; l = l->next) {
659 char *class_name = l->data;
661 if (!strcmp (method->klass->name, class_name))
670 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)
672 MonoImage *image = method->klass->image;
673 MonoMethodSignature *csignature;
675 int virtual = *td->ip == CEE_CALLVIRT;
676 int calli = *td->ip == CEE_CALLI || *td->ip == CEE_MONO_CALLI_EXTRA_ARG;
678 guint32 vt_stack_used = 0;
679 guint32 vt_res_size = 0;
684 guint32 token = read32 (td->ip + 1);
686 if (target_method == NULL) {
689 native = (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE && td->sp [-1].type == STACK_TYPE_I);
691 if (method->wrapper_type != MONO_WRAPPER_NONE)
692 csignature = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
694 csignature = mono_metadata_parse_signature (image, token);
696 if (generic_context) {
697 csignature = mono_inflate_generic_signature (csignature, generic_context, &error);
698 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
701 target_method = NULL;
703 if (method->wrapper_type == MONO_WRAPPER_NONE)
704 target_method = mono_get_method_full (image, token, NULL, generic_context);
706 target_method = (MonoMethod *)mono_method_get_wrapper_data (method, token);
707 csignature = mono_method_signature (target_method);
708 if (target_method->klass == mono_defaults.string_class) {
709 if (target_method->name [0] == 'g') {
710 if (strcmp (target_method->name, "get_Chars") == 0)
712 else if (strcmp (target_method->name, "get_Length") == 0)
715 } else if (mono_class_is_subclass_of (target_method->klass, mono_defaults.array_class, FALSE)) {
716 if (!strcmp (target_method->name, "get_Rank")) {
717 op = MINT_ARRAY_RANK;
718 } else if (!strcmp (target_method->name, "get_Length")) {
720 } else if (!strcmp (target_method->name, "Address")) {
721 op = readonly ? MINT_LDELEMA : MINT_LDELEMA_TC;
723 } else if (target_method && generic_context) {
724 csignature = mono_inflate_generic_signature (csignature, generic_context, &error);
725 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
726 target_method = mono_class_inflate_generic_method_checked (target_method, generic_context, &error);
727 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
731 csignature = mono_method_signature (target_method);
734 if (constrained_class) {
735 if (constrained_class->enumtype && !strcmp (target_method->name, "GetHashCode")) {
736 /* Use the corresponding method from the base type to avoid boxing */
737 MonoType *base_type = mono_class_enum_basetype (constrained_class);
738 g_assert (base_type);
739 constrained_class = mono_class_from_mono_type (base_type);
740 target_method = mono_class_get_method_from_name (constrained_class, target_method->name, 0);
741 g_assert (target_method);
745 if (constrained_class) {
746 mono_class_setup_vtable (constrained_class);
748 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);
750 target_method = mono_get_method_constrained_with_method (image, target_method, constrained_class, generic_context, &error);
752 g_print (" : %s::%s. %s (%p)\n", target_method->klass->name, target_method->name, mono_signature_full_name (target_method->signature), target_method);
754 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
755 mono_class_setup_vtable (target_method->klass);
757 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)) {
758 if (target_method->klass == mono_defaults.enum_class && (td->sp - csignature->param_count - 1)->type == STACK_TYPE_MP) {
759 /* managed pointer on the stack, we need to deref that puppy */
760 ADD_CODE (td, MINT_LDIND_I);
761 ADD_CODE (td, csignature->param_count);
763 ADD_CODE (td, MINT_BOX);
764 ADD_CODE (td, get_data_item_index (td, constrained_class));
765 ADD_CODE (td, csignature->param_count);
766 } else if (!constrained_class->valuetype) {
767 /* managed pointer on the stack, we need to deref that puppy */
768 ADD_CODE (td, MINT_LDIND_I);
769 ADD_CODE (td, csignature->param_count);
771 if (target_method->klass->valuetype) {
774 /* Interface method */
777 mono_class_setup_vtable (constrained_class);
778 ioffset = mono_class_interface_offset (constrained_class, target_method->klass);
780 g_error ("type load error: constrained_class");
781 slot = mono_method_get_vtable_slot (target_method);
783 g_error ("type load error: target_method->klass");
784 target_method = constrained_class->vtable [ioffset + slot];
786 if (target_method->klass == mono_defaults.enum_class) {
787 if ((td->sp - csignature->param_count - 1)->type == STACK_TYPE_MP) {
788 /* managed pointer on the stack, we need to deref that puppy */
789 ADD_CODE (td, MINT_LDIND_I);
790 ADD_CODE (td, csignature->param_count);
792 ADD_CODE (td, MINT_BOX);
793 ADD_CODE (td, get_data_item_index (td, constrained_class));
794 ADD_CODE (td, csignature->param_count);
802 mono_class_init (target_method->klass);
804 CHECK_STACK (td, csignature->param_count + csignature->hasthis);
805 if (!calli && (!virtual || (target_method->flags & METHOD_ATTRIBUTE_VIRTUAL) == 0) &&
806 (target_method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 &&
807 (target_method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) == 0) {
808 int called_inited = mono_class_vtable (domain, target_method->klass)->initialized;
809 MonoMethodHeader *mheader = mono_method_get_header (target_method);
811 if (/*mono_metadata_signature_equal (method->signature, target_method->signature) */ method == target_method && *(td->ip + 5) == CEE_RET) {
813 if (mono_interp_traceopt)
814 g_print ("Optimize tail call of %s.%s\n", target_method->klass->name, target_method->name);
816 for (i = csignature->param_count - 1 + !!csignature->hasthis; i >= 0; --i)
819 ADD_CODE(td, MINT_BR_S);
820 offset = body_start_offset - ((td->new_ip - 1) - td->new_code);
821 ADD_CODE(td, offset);
822 if (!is_bb_start [td->ip + 5 - td->il_code])
823 ++td->ip; /* gobble the CEE_RET if it isn't branched to */
827 /* mheader might not exist if this is a delegate invoc, etc */
828 if (mheader && *mheader->code == CEE_RET && called_inited) {
829 if (mono_interp_traceopt)
830 g_print ("Inline (empty) call of %s.%s\n", target_method->klass->name, target_method->name);
831 for (i = 0; i < csignature->param_count; i++)
832 ADD_CODE (td, MINT_POP); /*FIX: vt */
834 if (csignature->hasthis) {
836 ADD_CODE(td, MINT_CKNULL);
837 ADD_CODE (td, MINT_POP);
840 td->sp -= csignature->param_count + csignature->hasthis;
846 if (method->wrapper_type == MONO_WRAPPER_NONE && target_method != NULL) {
847 if (target_method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
848 target_method = mono_marshal_get_native_wrapper (target_method, FALSE, FALSE);
849 if (!virtual && target_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
850 target_method = mono_marshal_get_synchronized_wrapper (target_method);
852 g_assert (csignature->call_convention == MONO_CALL_DEFAULT || csignature->call_convention == MONO_CALL_C);
853 td->sp -= csignature->param_count + !!csignature->hasthis;
854 for (i = 0; i < csignature->param_count; ++i) {
855 if (td->sp [i + !!csignature->hasthis].type == STACK_TYPE_VT) {
857 MonoClass *klass = mono_class_from_mono_type (csignature->params [i]);
858 if (csignature->pinvoke && method->wrapper_type != MONO_WRAPPER_NONE)
859 size = mono_class_native_size (klass, NULL);
861 size = mono_class_value_size (klass, NULL);
862 size = (size + 7) & ~7;
863 vt_stack_used += size;
867 /* need to handle typedbyref ... */
868 if (csignature->ret->type != MONO_TYPE_VOID) {
869 int mt = mint_type(csignature->ret);
870 MonoClass *klass = mono_class_from_mono_type (csignature->ret);
871 if (mt == MINT_TYPE_VT) {
872 if (csignature->pinvoke && method->wrapper_type != MONO_WRAPPER_NONE)
873 vt_res_size = mono_class_native_size (klass, NULL);
875 vt_res_size = mono_class_value_size (klass, NULL);
876 PUSH_VT(td, vt_res_size);
878 PUSH_TYPE(td, stack_type[mt], klass);
884 #if SIZEOF_VOID_P == 8
885 if (op == MINT_LDLEN)
886 ADD_CODE (td, MINT_CONV_I4_I8);
888 if (op == MINT_LDELEMA || op == MINT_LDELEMA_TC) {
889 ADD_CODE (td, get_data_item_index (td, target_method->klass));
890 ADD_CODE (td, 1 + target_method->klass->rank);
892 } else if (!calli && !virtual && jit_call_supported (target_method, csignature)) {
893 ADD_CODE(td, MINT_JIT_CALL);
894 ADD_CODE(td, get_data_item_index (td, (void *)mono_interp_get_runtime_method (domain, target_method, &error)));
895 mono_error_assert_ok (&error);
898 ADD_CODE(td, native ? MINT_CALLI_NAT : MINT_CALLI);
900 ADD_CODE(td, is_void ? MINT_VCALLVIRT : MINT_CALLVIRT);
902 ADD_CODE(td, is_void ? MINT_VCALL : MINT_CALL);
905 ADD_CODE(td, get_data_item_index (td, (void *)csignature));
907 ADD_CODE(td, get_data_item_index (td, (void *)mono_interp_get_runtime_method (domain, target_method, &error)));
908 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
912 if (vt_stack_used != 0 || vt_res_size != 0) {
913 ADD_CODE(td, MINT_VTRESULT);
914 ADD_CODE(td, vt_res_size);
915 WRITE32(td, &vt_stack_used);
916 td->vt_sp -= vt_stack_used;
920 static MonoClassField *
921 interp_field_from_token (MonoMethod *method, guint32 token, MonoClass **klass, MonoGenericContext *generic_context)
923 MonoClassField *field = NULL;
924 if (method->wrapper_type != MONO_WRAPPER_NONE) {
925 field = (MonoClassField *) mono_method_get_wrapper_data (method, token);
926 *klass = field->parent;
930 field = mono_field_from_token_checked (method->klass->image, token, klass, generic_context, &error);
931 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
937 interp_save_debug_info (RuntimeMethod *rtm, MonoMethodHeader *header, TransformData *td, GArray *line_numbers)
939 MonoDebugMethodJitInfo *dinfo;
942 if (!mono_debug_enabled ())
946 * We save the debug info in the same way the JIT does it, treating the interpreter IR as the native code.
949 dinfo = g_new0 (MonoDebugMethodJitInfo, 1);
950 dinfo->num_locals = header->num_locals;
951 dinfo->locals = g_new0 (MonoDebugVarInfo, header->num_locals);
952 dinfo->code_start = (guint8*)rtm->code;
953 dinfo->code_size = td->new_ip - td->new_code;
954 dinfo->epilogue_begin = 0;
955 dinfo->has_var_info = FALSE;
956 dinfo->num_line_numbers = line_numbers->len;
957 dinfo->line_numbers = g_new0 (MonoDebugLineNumberEntry, dinfo->num_line_numbers);
958 for (i = 0; i < dinfo->num_line_numbers; i++)
959 dinfo->line_numbers [i] = g_array_index (line_numbers, MonoDebugLineNumberEntry, i);
960 mono_debug_add_method (rtm->method, dinfo, mono_domain_get ());
962 mono_debug_free_method_jit_info (dinfo);
966 generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, MonoGenericContext *generic_context)
968 MonoMethodHeader *header = mono_method_get_header (method);
969 MonoMethodSignature *signature = mono_method_signature (method);
970 MonoImage *image = method->klass->image;
971 MonoDomain *domain = mono_domain_get ();
972 MonoClass *constrained_class = NULL;
974 int offset, mt, i, i32;
975 gboolean readonly = FALSE;
977 MonoClassField *field;
978 const unsigned char *end;
979 int new_in_start_offset;
980 int body_start_offset;
984 int generating_code = 1;
985 GArray *line_numbers;
987 memset(&td, 0, sizeof(td));
990 td.is_bb_start = is_bb_start;
991 td.il_code = header->code;
992 td.code_size = header->code_size;
994 td.max_code_size = td.code_size;
995 td.new_code = (unsigned short *)g_malloc(td.max_code_size * sizeof(gushort));
996 td.new_code_end = td.new_code + td.max_code_size;
997 td.in_offsets = g_malloc0(header->code_size * sizeof(int));
998 td.forward_refs = g_malloc(header->code_size * sizeof(int));
999 td.stack_state = g_malloc0(header->code_size * sizeof(StackInfo *));
1000 td.stack_height = g_malloc(header->code_size * sizeof(int));
1001 td.vt_stack_size = g_malloc(header->code_size * sizeof(int));
1002 td.n_data_items = 0;
1003 td.max_data_items = 0;
1004 td.data_items = NULL;
1005 td.data_hash = g_hash_table_new (NULL, NULL);
1006 td.clause_indexes = g_malloc (header->code_size * sizeof (int));
1007 rtm->data_items = td.data_items;
1008 for (i = 0; i < header->code_size; i++) {
1009 td.forward_refs [i] = -1;
1010 td.stack_height [i] = -1;
1011 td.clause_indexes [i] = -1;
1013 td.new_ip = td.new_code;
1014 td.last_new_ip = NULL;
1016 td.stack = g_malloc0 ((header->max_stack + 1) * sizeof (td.stack [0]));
1018 td.max_stack_height = 0;
1020 line_numbers = g_array_new (FALSE, TRUE, sizeof (MonoDebugLineNumberEntry));
1022 for (i = 0; i < header->num_clauses; i++) {
1023 MonoExceptionClause *c = header->clauses + i;
1024 td.stack_height [c->handler_offset] = 0;
1025 td.vt_stack_size [c->handler_offset] = 0;
1026 td.is_bb_start [c->handler_offset] = 1;
1028 td.stack_height [c->handler_offset] = 1;
1029 td.stack_state [c->handler_offset] = g_malloc0(sizeof(StackInfo));
1030 td.stack_state [c->handler_offset][0].type = STACK_TYPE_O;
1031 td.stack_state [c->handler_offset][0].klass = NULL; /*FIX*/
1033 if (c->flags & MONO_EXCEPTION_CLAUSE_FILTER) {
1034 td.stack_height [c->data.filter_offset] = 0;
1035 td.vt_stack_size [c->data.filter_offset] = 0;
1036 td.is_bb_start [c->data.filter_offset] = 1;
1038 td.stack_height [c->data.filter_offset] = 1;
1039 td.stack_state [c->data.filter_offset] = g_malloc0(sizeof(StackInfo));
1040 td.stack_state [c->data.filter_offset][0].type = STACK_TYPE_O;
1041 td.stack_state [c->data.filter_offset][0].klass = NULL; /*FIX*/
1044 if ((c->flags & MONO_EXCEPTION_CLAUSE_FINALLY) || (c->flags & MONO_EXCEPTION_CLAUSE_FAULT)) {
1045 for (int j = c->handler_offset; j < c->handler_offset + c->handler_len; ++j) {
1046 if (td.clause_indexes [j] == -1)
1047 td.clause_indexes [j] = i;
1052 td.ip = header->code;
1053 end = td.ip + header->code_size;
1055 if (mono_interp_traceopt) {
1056 char *tmp = mono_disasm_code (NULL, method, td.ip, end);
1057 char *name = mono_method_full_name (method, TRUE);
1058 g_print ("Method %s, original code:\n", name);
1059 g_print ("%s\n", tmp);
1064 if (signature->hasthis)
1065 store_inarg (&td, 0);
1066 for (i = 0; i < signature->param_count; i++)
1067 store_inarg (&td, i + !!signature->hasthis);
1069 body_start_offset = td.new_ip - td.new_code;
1071 for (i = 0; i < header->num_locals; i++) {
1072 int mt = mint_type(header->locals [i]);
1073 if (mt == MINT_TYPE_VT || mt == MINT_TYPE_O || mt == MINT_TYPE_P) {
1074 ADD_CODE(&td, MINT_INITLOCALS);
1079 while (td.ip < end) {
1082 g_assert (td.sp >= td.stack);
1083 g_assert (td.vt_sp < 0x10000000);
1084 in_offset = td.ip - header->code;
1085 td.in_offsets [in_offset] = td.new_ip - td.new_code;
1086 new_in_start_offset = td.new_ip - td.new_code;
1087 td.in_start = td.ip;
1089 MonoDebugLineNumberEntry lne;
1090 lne.native_offset = td.new_ip - td.new_code;
1091 lne.il_offset = td.ip - header->code;
1092 g_array_append_val (line_numbers, lne);
1094 while (td.forward_refs [in_offset] >= 0) {
1095 int j = td.forward_refs [in_offset];
1097 td.forward_refs [in_offset] = td.forward_refs [j];
1098 if (td.in_offsets [j] < 0) {
1099 int old_switch_offset = -td.in_offsets [j];
1100 int new_switch_offset = td.in_offsets [old_switch_offset];
1101 int switch_case = (j - old_switch_offset - 5) / 4;
1102 int n_cases = read32 (header->code + old_switch_offset + 1);
1103 offset = (td.new_ip - td.new_code) - (new_switch_offset + 2 * n_cases + 3);
1104 slot = new_switch_offset + 3 + 2 * switch_case;
1105 td.new_code [slot] = * (unsigned short *)(&offset);
1106 td.new_code [slot + 1] = * ((unsigned short *)&offset + 1);
1108 int op = td.new_code [td.in_offsets [j]];
1109 if (mono_interp_opargtype [op] == MintOpShortBranch) {
1110 offset = (td.new_ip - td.new_code) - td.in_offsets [j];
1111 g_assert (offset <= 32767);
1112 slot = td.in_offsets [j] + 1;
1113 td.new_code [slot] = offset;
1115 offset = (td.new_ip - td.new_code) - td.in_offsets [j];
1116 slot = td.in_offsets [j] + 1;
1117 td.new_code [slot] = * (unsigned short *)(&offset);
1118 td.new_code [slot + 1] = * ((unsigned short *)&offset + 1);
1122 if (td.stack_height [in_offset] >= 0) {
1123 g_assert (is_bb_start [in_offset]);
1124 if (td.stack_height [in_offset] > 0)
1125 memcpy (td.stack, td.stack_state [in_offset], td.stack_height [in_offset] * sizeof(td.stack [0]));
1126 td.sp = td.stack + td.stack_height [in_offset];
1127 td.vt_sp = td.vt_stack_size [in_offset];
1129 if (is_bb_start [in_offset]) {
1130 generating_code = 1;
1132 if (!generating_code) {
1133 while (td.ip < end && !is_bb_start [td.ip - td.il_code])
1137 if (mono_interp_traceopt > 1) {
1138 printf("IL_%04lx %s %-10s -> IL_%04lx, sp %ld, %s %-12s vt_sp %u (max %u)\n",
1140 td.is_bb_start [td.ip - td.il_code] == 3 ? "<>" :
1141 td.is_bb_start [td.ip - td.il_code] == 2 ? "< " :
1142 td.is_bb_start [td.ip - td.il_code] == 1 ? " >" : " ",
1143 mono_opcode_name (*td.ip), td.new_ip - td.new_code, td.sp - td.stack,
1144 td.sp > td.stack ? stack_type_string [td.sp [-1].type] : " ",
1145 (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) : "",
1146 td.vt_sp, td.max_vt_sp);
1154 SIMPLE_OP(td, MINT_BREAK);
1160 load_arg (&td, *td.ip - CEE_LDARG_0);
1167 load_local (&td, *td.ip - CEE_LDLOC_0);
1174 store_local (&td, *td.ip - CEE_STLOC_0);
1178 load_arg (&td, ((guint8 *)td.ip)[1]);
1181 case CEE_LDARGA_S: {
1182 /* NOTE: n includes this */
1183 int n = ((guint8 *) td.ip) [1];
1184 ADD_CODE (&td, MINT_LDARGA);
1185 ADD_CODE (&td, td.rtm->arg_offsets [n]);
1186 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_MP);
1191 store_arg (&td, ((guint8 *)td.ip)[1]);
1195 load_local (&td, ((guint8 *)td.ip)[1]);
1199 ADD_CODE(&td, MINT_LDLOCA_S);
1200 ADD_CODE(&td, td.rtm->local_offsets [((guint8 *)td.ip)[1]]);
1201 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_MP);
1205 store_local (&td, ((guint8 *)td.ip)[1]);
1209 SIMPLE_OP(td, MINT_LDNULL);
1210 PUSH_TYPE(&td, STACK_TYPE_O, NULL);
1213 SIMPLE_OP(td, MINT_LDC_I4_M1);
1214 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4);
1217 if (!td.is_bb_start[td.ip + 1 - td.il_code] && td.ip [1] == 0xfe && td.ip [2] == CEE_CEQ &&
1218 td.sp > td.stack && td.sp [-1].type == STACK_TYPE_I4) {
1219 SIMPLE_OP(td, MINT_CEQ0_I4);
1222 SIMPLE_OP(td, MINT_LDC_I4_0);
1223 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4);
1227 if (!td.is_bb_start[td.ip + 1 - td.il_code] &&
1228 (td.ip [1] == CEE_ADD || td.ip [1] == CEE_SUB) && td.sp [-1].type == STACK_TYPE_I4) {
1229 ADD_CODE(&td, td.ip [1] == CEE_ADD ? MINT_ADD1_I4 : MINT_SUB1_I4);
1232 SIMPLE_OP(td, MINT_LDC_I4_1);
1233 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4);
1243 SIMPLE_OP(td, (*td.ip - CEE_LDC_I4_0) + MINT_LDC_I4_0);
1244 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4);
1247 ADD_CODE(&td, MINT_LDC_I4_S);
1248 ADD_CODE(&td, ((gint8 *) td.ip) [1]);
1250 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4);
1253 i32 = read32 (td.ip + 1);
1254 ADD_CODE(&td, MINT_LDC_I4);
1257 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4);
1260 gint64 val = read64 (td.ip + 1);
1261 ADD_CODE(&td, MINT_LDC_I8);
1264 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I8);
1269 readr4 (td.ip + 1, &val);
1270 ADD_CODE(&td, MINT_LDC_R4);
1273 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_R8);
1278 readr8 (td.ip + 1, &val);
1279 ADD_CODE(&td, MINT_LDC_R8);
1282 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_R8);
1286 int type = td.sp [-1].type;
1287 MonoClass *klass = td.sp [-1].klass;
1288 if (td.sp [-1].type == STACK_TYPE_VT) {
1289 gint32 size = mono_class_value_size (klass, NULL);
1291 ADD_CODE(&td, MINT_DUP_VT);
1292 WRITE32(&td, &size);
1295 SIMPLE_OP(td, MINT_DUP);
1296 PUSH_TYPE(&td, type, klass);
1300 CHECK_STACK(&td, 1);
1301 SIMPLE_OP(td, MINT_POP);
1303 if (td.sp [-1].type == STACK_TYPE_VT) {
1304 int size = mono_class_value_size (td.sp [-1].klass, NULL);
1305 size = (size + 7) & ~7;
1306 ADD_CODE(&td, MINT_VTRESULT);
1308 WRITE32(&td, &size);
1315 if (td.sp > td.stack)
1316 g_warning ("CEE_JMP: stack must be empty");
1317 token = read32 (td.ip + 1);
1318 m = mono_get_method_full (image, token, NULL, generic_context);
1319 ADD_CODE (&td, MINT_JMP);
1320 ADD_CODE (&td, get_data_item_index (&td, mono_interp_get_runtime_method (domain, m, &error)));
1321 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1325 case CEE_CALLVIRT: /* Fall through */
1326 case CEE_CALLI: /* Fall through */
1328 interp_transform_call (&td, method, NULL, domain, generic_context, is_bb_start, body_start_offset, constrained_class, readonly);
1329 constrained_class = NULL;
1335 if (signature->ret->type != MONO_TYPE_VOID) {
1337 MonoClass *klass = mono_class_from_mono_type (signature->ret);
1338 if (mint_type (&klass->byval_arg) == MINT_TYPE_VT) {
1339 vt_size = mono_class_value_size (klass, NULL);
1340 vt_size = (vt_size + 7) & ~7;
1343 if (td.sp > td.stack)
1344 g_warning ("%s.%s: CEE_RET: more values on stack: %d", td.method->klass->name, td.method->name, td.sp - td.stack);
1345 if (td.vt_sp != vt_size)
1346 g_error ("%s.%s: CEE_RET: value type stack: %d vs. %d", td.method->klass->name, td.method->name, td.vt_sp, vt_size);
1348 SIMPLE_OP(td, signature->ret->type == MONO_TYPE_VOID ? MINT_RET_VOID : MINT_RET);
1350 ADD_CODE(&td, MINT_RET_VT);
1351 WRITE32(&td, &vt_size);
1354 generating_code = 0;
1358 handle_branch (&td, MINT_BR_S, MINT_BR, 5 + read32 (td.ip + 1));
1360 generating_code = 0;
1363 handle_branch (&td, MINT_BR_S, MINT_BR, 2 + (gint8)td.ip [1]);
1365 generating_code = 0;
1368 one_arg_branch (&td, MINT_BRFALSE_I4, 5 + read32 (td.ip + 1));
1372 one_arg_branch (&td, MINT_BRFALSE_I4, 2 + (gint8)td.ip [1]);
1376 one_arg_branch (&td, MINT_BRTRUE_I4, 5 + read32 (td.ip + 1));
1380 one_arg_branch (&td, MINT_BRTRUE_I4, 2 + (gint8)td.ip [1]);
1384 two_arg_branch (&td, MINT_BEQ_I4, 5 + read32 (td.ip + 1));
1388 two_arg_branch (&td, MINT_BEQ_I4, 2 + (gint8) td.ip [1]);
1392 two_arg_branch (&td, MINT_BGE_I4, 5 + read32 (td.ip + 1));
1396 two_arg_branch (&td, MINT_BGE_I4, 2 + (gint8) td.ip [1]);
1400 two_arg_branch (&td, MINT_BGT_I4, 5 + read32 (td.ip + 1));
1404 two_arg_branch (&td, MINT_BGT_I4, 2 + (gint8) td.ip [1]);
1408 two_arg_branch (&td, MINT_BLT_I4, 5 + read32 (td.ip + 1));
1412 two_arg_branch (&td, MINT_BLT_I4, 2 + (gint8) td.ip [1]);
1416 two_arg_branch (&td, MINT_BLE_I4, 5 + read32 (td.ip + 1));
1420 two_arg_branch (&td, MINT_BLE_I4, 2 + (gint8) td.ip [1]);
1424 two_arg_branch (&td, MINT_BNE_UN_I4, 5 + read32 (td.ip + 1));
1428 two_arg_branch (&td, MINT_BNE_UN_I4, 2 + (gint8) td.ip [1]);
1432 two_arg_branch (&td, MINT_BGE_UN_I4, 5 + read32 (td.ip + 1));
1436 two_arg_branch (&td, MINT_BGE_UN_I4, 2 + (gint8) td.ip [1]);
1440 two_arg_branch (&td, MINT_BGT_UN_I4, 5 + read32 (td.ip + 1));
1444 two_arg_branch (&td, MINT_BGT_UN_I4, 2 + (gint8) td.ip [1]);
1448 two_arg_branch (&td, MINT_BLE_UN_I4, 5 + read32 (td.ip + 1));
1452 two_arg_branch (&td, MINT_BLE_UN_I4, 2 + (gint8) td.ip [1]);
1456 two_arg_branch (&td, MINT_BLT_UN_I4, 5 + read32 (td.ip + 1));
1460 two_arg_branch (&td, MINT_BLT_UN_I4, 2 + (gint8) td.ip [1]);
1465 const unsigned char *next_ip;
1466 const unsigned char *base_ip = td.ip;
1467 unsigned short *next_new_ip;
1470 ADD_CODE (&td, MINT_SWITCH);
1473 next_ip = td.ip + n * 4;
1474 next_new_ip = td.new_ip + n * 2;
1476 int stack_height = td.sp - td.stack;
1477 for (i = 0; i < n; i++) {
1478 offset = read32 (td.ip);
1479 target = next_ip - td.il_code + offset;
1482 if (stack_height > 0 && stack_height != td.stack_height [target])
1483 g_warning ("SWITCH with back branch and non-empty stack");
1485 target = td.in_offsets [target] - (next_new_ip - td.new_code);
1487 td.stack_height [target] = stack_height;
1488 td.vt_stack_size [target] = td.vt_sp;
1489 if (stack_height > 0)
1490 td.stack_state [target] = g_memdup (td.stack, stack_height * sizeof (td.stack [0]));
1491 int prev = td.forward_refs [target];
1492 td.forward_refs [td.ip - td.il_code] = prev;
1493 td.forward_refs [target] = td.ip - td.il_code;
1494 td.in_offsets [td.ip - td.il_code] = - (base_ip - td.il_code);
1496 WRITE32 (&td, &target);
1502 CHECK_STACK (&td, 1);
1503 SIMPLE_OP (td, MINT_LDIND_I1);
1504 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
1507 CHECK_STACK (&td, 1);
1508 SIMPLE_OP (td, MINT_LDIND_U1);
1509 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
1512 CHECK_STACK (&td, 1);
1513 SIMPLE_OP (td, MINT_LDIND_I2);
1514 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
1517 CHECK_STACK (&td, 1);
1518 SIMPLE_OP (td, MINT_LDIND_U2);
1519 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
1522 CHECK_STACK (&td, 1);
1523 SIMPLE_OP (td, MINT_LDIND_I4);
1524 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
1527 CHECK_STACK (&td, 1);
1528 SIMPLE_OP (td, MINT_LDIND_U4);
1529 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
1532 CHECK_STACK (&td, 1);
1533 SIMPLE_OP (td, MINT_LDIND_I8);
1534 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8);
1537 CHECK_STACK (&td, 1);
1538 SIMPLE_OP (td, MINT_LDIND_I);
1540 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I);
1543 CHECK_STACK (&td, 1);
1544 SIMPLE_OP (td, MINT_LDIND_R4);
1545 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8);
1548 CHECK_STACK (&td, 1);
1549 SIMPLE_OP (td, MINT_LDIND_R8);
1550 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8);
1553 CHECK_STACK (&td, 1);
1554 SIMPLE_OP (td, MINT_LDIND_REF);
1555 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_O);
1558 CHECK_STACK (&td, 2);
1559 SIMPLE_OP (td, MINT_STIND_REF);
1563 CHECK_STACK (&td, 2);
1564 SIMPLE_OP (td, MINT_STIND_I1);
1568 CHECK_STACK (&td, 2);
1569 SIMPLE_OP (td, MINT_STIND_I2);
1573 CHECK_STACK (&td, 2);
1574 SIMPLE_OP (td, MINT_STIND_I4);
1578 CHECK_STACK (&td, 2);
1579 SIMPLE_OP (td, MINT_STIND_I);
1583 CHECK_STACK (&td, 2);
1584 SIMPLE_OP (td, MINT_STIND_I8);
1588 CHECK_STACK (&td, 2);
1589 SIMPLE_OP (td, MINT_STIND_R4);
1593 CHECK_STACK (&td, 2);
1594 SIMPLE_OP (td, MINT_STIND_R8);
1598 binary_arith_op(&td, MINT_ADD_I4);
1602 binary_arith_op(&td, MINT_SUB_I4);
1606 binary_arith_op(&td, MINT_MUL_I4);
1610 binary_arith_op(&td, MINT_DIV_I4);
1614 binary_arith_op(&td, MINT_DIV_UN_I4);
1618 binary_int_op (&td, MINT_REM_I4);
1622 binary_int_op (&td, MINT_REM_UN_I4);
1626 binary_int_op (&td, MINT_AND_I4);
1630 binary_int_op (&td, MINT_OR_I4);
1634 binary_int_op (&td, MINT_XOR_I4);
1638 shift_op (&td, MINT_SHL_I4);
1642 shift_op (&td, MINT_SHR_I4);
1646 shift_op (&td, MINT_SHR_UN_I4);
1650 unary_arith_op (&td, MINT_NEG_I4);
1654 unary_arith_op (&td, MINT_NOT_I4);
1658 CHECK_STACK (&td, 1);
1659 switch (td.sp [-1].type) {
1661 ADD_CODE(&td, MINT_CONV_U1_R8);
1664 ADD_CODE(&td, MINT_CONV_U1_I4);
1667 ADD_CODE(&td, MINT_CONV_U1_I8);
1670 g_assert_not_reached ();
1673 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
1676 CHECK_STACK (&td, 1);
1677 switch (td.sp [-1].type) {
1679 ADD_CODE(&td, MINT_CONV_I1_R8);
1682 ADD_CODE(&td, MINT_CONV_I1_I4);
1685 ADD_CODE(&td, MINT_CONV_I1_I8);
1688 g_assert_not_reached ();
1691 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
1694 CHECK_STACK (&td, 1);
1695 switch (td.sp [-1].type) {
1697 ADD_CODE(&td, MINT_CONV_U2_R8);
1700 ADD_CODE(&td, MINT_CONV_U2_I4);
1703 ADD_CODE(&td, MINT_CONV_U2_I8);
1706 g_assert_not_reached ();
1709 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
1712 CHECK_STACK (&td, 1);
1713 switch (td.sp [-1].type) {
1715 ADD_CODE(&td, MINT_CONV_I2_R8);
1718 ADD_CODE(&td, MINT_CONV_I2_I4);
1721 ADD_CODE(&td, MINT_CONV_I2_I8);
1724 g_assert_not_reached ();
1727 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
1730 CHECK_STACK (&td, 1);
1731 switch (td.sp [-1].type) {
1733 #if SIZEOF_VOID_P == 4
1734 ADD_CODE(&td, MINT_CONV_U4_R8);
1736 ADD_CODE(&td, MINT_CONV_U8_R8);
1740 #if SIZEOF_VOID_P == 8
1741 ADD_CODE(&td, MINT_CONV_U8_I4);
1745 #if SIZEOF_VOID_P == 4
1746 ADD_CODE(&td, MINT_CONV_U4_I8);
1752 g_assert_not_reached ();
1755 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I);
1758 CHECK_STACK (&td, 1);
1759 switch (td.sp [-1].type) {
1761 #if SIZEOF_VOID_P == 8
1762 ADD_CODE(&td, MINT_CONV_I8_R8);
1764 ADD_CODE(&td, MINT_CONV_I4_R8);
1768 #if SIZEOF_VOID_P == 8
1769 ADD_CODE(&td, MINT_CONV_I8_I4);
1777 #if SIZEOF_VOID_P == 4
1778 ADD_CODE(&td, MINT_CONV_I4_I8);
1782 g_assert_not_reached ();
1785 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I);
1788 CHECK_STACK (&td, 1);
1789 switch (td.sp [-1].type) {
1791 ADD_CODE(&td, MINT_CONV_U4_R8);
1796 ADD_CODE(&td, MINT_CONV_U4_I8);
1799 #if SIZEOF_VOID_P == 8
1800 ADD_CODE(&td, MINT_CONV_U4_I8);
1804 g_assert_not_reached ();
1807 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
1810 CHECK_STACK (&td, 1);
1811 switch (td.sp [-1].type) {
1813 ADD_CODE(&td, MINT_CONV_I4_R8);
1818 ADD_CODE(&td, MINT_CONV_I4_I8);
1821 #if SIZEOF_VOID_P == 8
1822 ADD_CODE(&td, MINT_CONV_I4_I8);
1826 g_assert_not_reached ();
1829 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
1832 CHECK_STACK (&td, 1);
1833 switch (td.sp [-1].type) {
1835 ADD_CODE(&td, MINT_CONV_I8_R8);
1838 ADD_CODE(&td, MINT_CONV_I8_I4);
1843 #if SIZEOF_VOID_P == 4
1844 ADD_CODE(&td, MINT_CONV_I8_I4);
1848 g_assert_not_reached ();
1851 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8);
1854 CHECK_STACK (&td, 1);
1855 switch (td.sp [-1].type) {
1857 ADD_CODE(&td, MINT_CONV_R4_R8);
1860 ADD_CODE(&td, MINT_CONV_R4_I8);
1863 ADD_CODE(&td, MINT_CONV_R4_I4);
1866 g_assert_not_reached ();
1869 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8);
1872 CHECK_STACK (&td, 1);
1873 switch (td.sp [-1].type) {
1875 ADD_CODE(&td, MINT_CONV_R8_I4);
1878 ADD_CODE(&td, MINT_CONV_R8_I8);
1883 g_assert_not_reached ();
1886 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8);
1889 CHECK_STACK (&td, 1);
1890 switch (td.sp [-1].type) {
1892 ADD_CODE(&td, MINT_CONV_U8_I4);
1897 ADD_CODE(&td, MINT_CONV_U8_R8);
1900 #if SIZEOF_VOID_P == 4
1901 ADD_CODE(&td, MINT_CONV_U8_I4);
1905 g_assert_not_reached ();
1908 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8);
1911 CHECK_STACK (&td, 2);
1913 token = read32 (td.ip + 1);
1914 klass = mono_class_get_full (image, token, generic_context);
1916 if (klass->valuetype) {
1917 ADD_CODE (&td, MINT_CPOBJ);
1918 ADD_CODE (&td, get_data_item_index(&td, klass));
1920 ADD_CODE (&td, MINT_LDIND_REF);
1921 ADD_CODE (&td, MINT_STIND_REF);
1929 CHECK_STACK (&td, 1);
1931 token = read32 (td.ip + 1);
1933 if (method->wrapper_type != MONO_WRAPPER_NONE)
1934 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
1936 klass = mono_class_get_full (image, token, generic_context);
1938 ADD_CODE(&td, MINT_LDOBJ);
1939 ADD_CODE(&td, get_data_item_index(&td, klass));
1940 if (mint_type (&klass->byval_arg) == MINT_TYPE_VT) {
1941 size = mono_class_value_size (klass, NULL);
1945 SET_TYPE(td.sp - 1, stack_type[mint_type(&klass->byval_arg)], klass);
1950 token = mono_metadata_token_index (read32 (td.ip + 1));
1952 if (method->wrapper_type != MONO_WRAPPER_NONE) {
1953 s = mono_string_new_wrapper(
1954 mono_method_get_wrapper_data (method, token));
1957 s = mono_ldstr (domain, image, token);
1958 ADD_CODE(&td, MINT_LDSTR);
1959 ADD_CODE(&td, get_data_item_index (&td, s));
1960 PUSH_TYPE(&td, STACK_TYPE_O, mono_defaults.string_class);
1965 MonoMethodSignature *csignature;
1966 guint32 vt_stack_used = 0;
1967 guint32 vt_res_size = 0;
1970 token = read32 (td.ip);
1973 if (method->wrapper_type != MONO_WRAPPER_NONE)
1974 m = (MonoMethod *)mono_method_get_wrapper_data (method, token);
1976 m = mono_get_method_full (image, token, NULL, generic_context);
1978 csignature = mono_method_signature (m);
1980 td.sp -= csignature->param_count;
1981 ADD_CODE(&td, MINT_NEWOBJ);
1982 ADD_CODE(&td, get_data_item_index (&td, mono_interp_get_runtime_method (domain, m, &error)));
1983 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1985 if (mint_type (&klass->byval_arg) == MINT_TYPE_VT) {
1986 vt_res_size = mono_class_value_size (klass, NULL);
1987 PUSH_VT (&td, vt_res_size);
1989 for (i = 0; i < csignature->param_count; ++i) {
1990 int mt = mint_type(csignature->params [i]);
1991 if (mt == MINT_TYPE_VT) {
1992 MonoClass *k = mono_class_from_mono_type (csignature->params [i]);
1993 gint32 size = mono_class_value_size (k, NULL);
1994 size = (size + 7) & ~7;
1995 vt_stack_used += size;
1998 if (vt_stack_used != 0 || vt_res_size != 0) {
1999 ADD_CODE(&td, MINT_VTRESULT);
2000 ADD_CODE(&td, vt_res_size);
2001 WRITE32(&td, &vt_stack_used);
2002 td.vt_sp -= vt_stack_used;
2004 PUSH_TYPE (&td, stack_type [mint_type (&klass->byval_arg)], klass);
2008 CHECK_STACK (&td, 1);
2009 token = read32 (td.ip + 1);
2010 klass = mini_get_class (method, token, generic_context);
2011 ADD_CODE(&td, MINT_CASTCLASS);
2012 ADD_CODE(&td, get_data_item_index (&td, klass));
2013 td.sp [-1].klass = klass;
2017 CHECK_STACK (&td, 1);
2018 token = read32 (td.ip + 1);
2019 klass = mini_get_class (method, token, generic_context);
2020 ADD_CODE(&td, MINT_ISINST);
2021 ADD_CODE(&td, get_data_item_index (&td, klass));
2025 switch (td.sp [-1].type) {
2029 ADD_CODE(&td, MINT_CONV_R_UN_I8);
2032 ADD_CODE(&td, MINT_CONV_R_UN_I4);
2035 g_assert_not_reached ();
2037 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8);
2041 CHECK_STACK (&td, 1);
2042 token = read32 (td.ip + 1);
2044 if (method->wrapper_type != MONO_WRAPPER_NONE)
2045 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
2047 klass = mono_class_get_full (image, token, generic_context);
2049 if (mono_class_is_nullable (klass)) {
2050 g_error ("cee_unbox: implement Nullable");
2053 ADD_CODE(&td, MINT_UNBOX);
2054 ADD_CODE(&td, get_data_item_index (&td, klass));
2055 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP);
2059 CHECK_STACK (&td, 1);
2060 token = read32 (td.ip + 1);
2062 klass = mini_get_class (method, token, generic_context);
2064 if (mini_type_is_reference (&klass->byval_arg)) {
2065 int mt = mint_type (&klass->byval_arg);
2066 ADD_CODE (&td, MINT_CASTCLASS);
2067 ADD_CODE (&td, get_data_item_index (&td, klass));
2068 SET_TYPE (td.sp - 1, stack_type [mt], klass);
2070 } else if (mono_class_is_nullable (klass)) {
2071 MonoMethod *target_method = mono_class_get_method_from_name (klass, "Unbox", 1);
2072 /* td.ip is incremented by interp_transform_call */
2073 interp_transform_call (&td, method, target_method, domain, generic_context, is_bb_start, body_start_offset, NULL, FALSE);
2075 int mt = mint_type (&klass->byval_arg);
2076 ADD_CODE (&td, MINT_UNBOX);
2077 ADD_CODE (&td, get_data_item_index (&td, klass));
2079 ADD_CODE (&td, MINT_LDOBJ);
2080 ADD_CODE (&td, get_data_item_index(&td, klass));
2081 SET_TYPE (td.sp - 1, stack_type [mt], klass);
2083 if (mt == MINT_TYPE_VT) {
2084 int size = mono_class_value_size (klass, NULL);
2085 PUSH_VT (&td, size);
2092 CHECK_STACK (&td, 1);
2093 SIMPLE_OP (td, MINT_THROW);
2095 generating_code = 0;
2098 CHECK_STACK (&td, 1);
2099 token = read32 (td.ip + 1);
2100 field = interp_field_from_token (method, token, &klass, generic_context);
2101 gboolean is_static = !!(field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2102 mono_class_init (klass);
2104 ADD_CODE (&td, MINT_POP);
2106 ADD_CODE (&td, MINT_LDSFLDA);
2107 ADD_CODE (&td, get_data_item_index (&td, field));
2109 if ((td.sp - 1)->type == STACK_TYPE_O) {
2110 ADD_CODE (&td, MINT_LDFLDA);
2112 g_assert ((td.sp -1)->type == STACK_TYPE_MP);
2113 ADD_CODE (&td, MINT_LDFLDA_UNSAFE);
2115 ADD_CODE (&td, klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
2118 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP);
2121 CHECK_STACK (&td, 1);
2122 token = read32 (td.ip + 1);
2123 field = interp_field_from_token (method, token, &klass, generic_context);
2124 gboolean is_static = !!(field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2125 mono_class_init (klass);
2127 MonoClass *field_klass = mono_class_from_mono_type (field->type);
2128 mt = mint_type (&field_klass->byval_arg);
2129 if (klass->marshalbyref) {
2130 g_assert (!is_static);
2131 ADD_CODE(&td, mt == MINT_TYPE_VT ? MINT_LDRMFLD_VT : MINT_LDRMFLD);
2132 ADD_CODE(&td, get_data_item_index (&td, field));
2135 ADD_CODE (&td, MINT_POP);
2137 ADD_CODE (&td, mt == MINT_TYPE_VT ? MINT_LDSFLD_VT : MINT_LDSFLD);
2138 ADD_CODE (&td, get_data_item_index (&td, field));
2140 ADD_CODE (&td, MINT_LDFLD_I1 + mt - MINT_TYPE_I1);
2141 ADD_CODE (&td, klass->valuetype ? field->offset - sizeof(MonoObject) : field->offset);
2144 if (mt == MINT_TYPE_VT) {
2145 int size = mono_class_value_size (field_klass, NULL);
2147 WRITE32(&td, &size);
2149 if (td.sp [-1].type == STACK_TYPE_VT) {
2150 int size = mono_class_value_size (klass, NULL);
2151 size = (size + 7) & ~7;
2153 ADD_CODE (&td, MINT_VTRESULT);
2155 WRITE32 (&td, &size);
2158 SET_TYPE(td.sp - 1, stack_type [mt], field_klass);
2162 CHECK_STACK (&td, 2);
2163 token = read32 (td.ip + 1);
2164 field = interp_field_from_token (method, token, &klass, generic_context);
2165 gboolean is_static = !!(field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2166 mono_class_init (klass);
2167 mt = mint_type(field->type);
2169 if (klass->marshalbyref) {
2170 g_assert (!is_static);
2171 ADD_CODE(&td, mt == MINT_TYPE_VT ? MINT_STRMFLD_VT : MINT_STRMFLD);
2172 ADD_CODE(&td, get_data_item_index (&td, field));
2175 ADD_CODE (&td, MINT_POP);
2177 ADD_CODE (&td, mt == MINT_TYPE_VT ? MINT_STSFLD_VT : MINT_STSFLD);
2178 ADD_CODE (&td, get_data_item_index (&td, field));
2180 ADD_CODE (&td, MINT_STFLD_I1 + mt - MINT_TYPE_I1);
2181 ADD_CODE (&td, klass->valuetype ? field->offset - sizeof(MonoObject) : field->offset);
2184 if (mt == MINT_TYPE_VT) {
2185 MonoClass *klass = mono_class_from_mono_type (field->type);
2186 int size = mono_class_value_size (klass, NULL);
2188 WRITE32(&td, &size);
2195 token = read32 (td.ip + 1);
2196 field = interp_field_from_token (method, token, &klass, generic_context);
2197 ADD_CODE(&td, MINT_LDSFLDA);
2198 ADD_CODE(&td, get_data_item_index (&td, field));
2200 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_MP);
2203 token = read32 (td.ip + 1);
2204 field = interp_field_from_token (method, token, &klass, generic_context);
2205 mt = mint_type(field->type);
2206 ADD_CODE(&td, mt == MINT_TYPE_VT ? MINT_LDSFLD_VT : MINT_LDSFLD);
2207 ADD_CODE(&td, get_data_item_index (&td, field));
2209 if (mt == MINT_TYPE_VT) {
2210 MonoClass *klass = mono_class_from_mono_type (field->type);
2211 int size = mono_class_value_size (klass, NULL);
2213 WRITE32(&td, &size);
2214 klass = field->type->data.klass;
2216 if (mt == MINT_TYPE_O)
2217 klass = mono_class_from_mono_type (field->type);
2220 PUSH_TYPE(&td, stack_type [mt], klass);
2223 CHECK_STACK (&td, 1);
2224 token = read32 (td.ip + 1);
2225 field = interp_field_from_token (method, token, &klass, generic_context);
2226 mt = mint_type(field->type);
2227 ADD_CODE(&td, mt == MINT_TYPE_VT ? MINT_STSFLD_VT : MINT_STSFLD);
2228 ADD_CODE(&td, get_data_item_index (&td, field));
2229 if (mt == MINT_TYPE_VT) {
2230 MonoClass *klass = mono_class_from_mono_type (field->type);
2231 int size = mono_class_value_size (klass, NULL);
2233 WRITE32 (&td, &size);
2240 token = read32 (td.ip + 1);
2242 if (method->wrapper_type != MONO_WRAPPER_NONE)
2243 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
2245 klass = mini_get_class (method, token, generic_context);
2247 ADD_CODE(&td, td.sp [-1].type == STACK_TYPE_VT ? MINT_STOBJ_VT : MINT_STOBJ);
2248 ADD_CODE(&td, get_data_item_index (&td, klass));
2249 if (td.sp [-1].type == STACK_TYPE_VT) {
2250 size = mono_class_value_size (klass, NULL);
2251 size = (size + 7) & ~7;
2258 case CEE_CONV_OVF_I_UN:
2259 case CEE_CONV_OVF_U_UN:
2260 CHECK_STACK (&td, 1);
2261 switch (td.sp [-1].type) {
2263 #if SIZEOF_VOID_P == 8
2264 ADD_CODE(&td, MINT_CONV_OVF_I8_UN_R8);
2266 ADD_CODE(&td, MINT_CONV_OVF_I4_UN_R8);
2270 #if SIZEOF_VOID_P == 4
2271 ADD_CODE (&td, MINT_CONV_OVF_I4_UN_I8);
2275 #if SIZEOF_VOID_P == 8
2276 ADD_CODE(&td, MINT_CONV_I8_U4);
2280 g_assert_not_reached ();
2283 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8);
2286 case CEE_CONV_OVF_I8_UN:
2287 case CEE_CONV_OVF_U8_UN:
2288 CHECK_STACK (&td, 1);
2289 switch (td.sp [-1].type) {
2291 ADD_CODE(&td, MINT_CONV_OVF_I8_UN_R8);
2294 if (*td.ip == CEE_CONV_OVF_I8_UN)
2295 ADD_CODE (&td, MINT_CONV_OVF_I8_U8);
2298 ADD_CODE(&td, MINT_CONV_I8_U4);
2301 g_assert_not_reached ();
2304 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8);
2309 CHECK_STACK (&td, 1);
2310 token = read32 (td.ip + 1);
2311 if (method->wrapper_type != MONO_WRAPPER_NONE)
2312 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
2314 klass = mini_get_class (method, token, generic_context);
2316 if (mono_class_is_nullable (klass)) {
2317 MonoMethod *target_method = mono_class_get_method_from_name (klass, "Box", 1);
2318 /* td.ip is incremented by interp_transform_call */
2319 interp_transform_call (&td, method, target_method, domain, generic_context, is_bb_start, body_start_offset, NULL, FALSE);
2320 } else if (!klass->valuetype) {
2321 /* already boxed, do nothing. */
2324 if (mint_type (&klass->byval_arg) == MINT_TYPE_VT && !klass->enumtype) {
2325 size = mono_class_value_size (klass, NULL);
2326 size = (size + 7) & ~7;
2329 ADD_CODE(&td, MINT_BOX);
2330 ADD_CODE(&td, get_data_item_index (&td, klass));
2332 SET_TYPE(td.sp - 1, STACK_TYPE_O, klass);
2339 CHECK_STACK (&td, 1);
2340 token = read32 (td.ip + 1);
2342 if (method->wrapper_type != MONO_WRAPPER_NONE)
2343 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
2345 klass = mini_get_class (method, token, generic_context);
2347 unsigned char lentype = (td.sp - 1)->type;
2348 if (lentype == STACK_TYPE_I8) {
2349 /* mimic mini behaviour */
2350 ADD_CODE (&td, MINT_CONV_OVF_U4_I8);
2352 g_assert (lentype == STACK_TYPE_I4);
2353 ADD_CODE (&td, MINT_CONV_OVF_U4_I4);
2355 SET_SIMPLE_TYPE (td.sp - 1, STACK_TYPE_I4);
2356 ADD_CODE (&td, MINT_NEWARR);
2357 ADD_CODE (&td, get_data_item_index (&td, klass));
2358 SET_TYPE (td.sp - 1, STACK_TYPE_O, klass);
2363 CHECK_STACK (&td, 1);
2364 SIMPLE_OP (td, MINT_LDLEN);
2365 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I);
2368 CHECK_STACK (&td, 2);
2370 token = read32 (td.ip + 1);
2372 if (method->wrapper_type != MONO_WRAPPER_NONE)
2373 klass = (MonoClass *) mono_method_get_wrapper_data (method, token);
2375 klass = mini_get_class (method, token, generic_context);
2377 if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
2378 ADD_CODE (&td, MINT_LDELEMA_TC);
2380 ADD_CODE (&td, MINT_LDELEMA);
2382 ADD_CODE (&td, get_data_item_index (&td, klass));
2383 /* according to spec, ldelema bytecode is only used for 1-dim arrays */
2389 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP);
2392 CHECK_STACK (&td, 2);
2394 SIMPLE_OP (td, MINT_LDELEM_I1);
2396 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2399 CHECK_STACK (&td, 2);
2401 SIMPLE_OP (td, MINT_LDELEM_U1);
2403 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2406 CHECK_STACK (&td, 2);
2408 SIMPLE_OP (td, MINT_LDELEM_I2);
2410 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2413 CHECK_STACK (&td, 2);
2415 SIMPLE_OP (td, MINT_LDELEM_U2);
2417 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2420 CHECK_STACK (&td, 2);
2422 SIMPLE_OP (td, MINT_LDELEM_I4);
2424 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2427 CHECK_STACK (&td, 2);
2429 SIMPLE_OP (td, MINT_LDELEM_U4);
2431 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2434 CHECK_STACK (&td, 2);
2436 SIMPLE_OP (td, MINT_LDELEM_I8);
2438 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8);
2441 CHECK_STACK (&td, 2);
2443 SIMPLE_OP (td, MINT_LDELEM_I);
2445 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I);
2448 CHECK_STACK (&td, 2);
2450 SIMPLE_OP (td, MINT_LDELEM_R4);
2452 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8);
2455 CHECK_STACK (&td, 2);
2457 SIMPLE_OP (td, MINT_LDELEM_R8);
2459 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8);
2461 case CEE_LDELEM_REF:
2462 CHECK_STACK (&td, 2);
2464 SIMPLE_OP (td, MINT_LDELEM_REF);
2466 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_O);
2469 CHECK_STACK (&td, 2);
2470 token = read32 (td.ip + 1);
2471 klass = mini_get_class (method, token, generic_context);
2472 switch (mint_type (&klass->byval_arg)) {
2475 SIMPLE_OP (td, MINT_LDELEM_I1);
2477 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2481 SIMPLE_OP (td, MINT_LDELEM_U1);
2483 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2487 SIMPLE_OP (td, MINT_LDELEM_U2);
2489 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2493 SIMPLE_OP (td, MINT_LDELEM_I2);
2495 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2499 SIMPLE_OP (td, MINT_LDELEM_I4);
2501 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2505 SIMPLE_OP (td, MINT_LDELEM_I8);
2507 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8);
2511 SIMPLE_OP (td, MINT_LDELEM_R4);
2513 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8);
2517 SIMPLE_OP (td, MINT_LDELEM_R8);
2519 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8);
2523 SIMPLE_OP (td, MINT_LDELEM_REF);
2525 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_O);
2527 case MINT_TYPE_VT: {
2528 int size = mono_class_value_size (klass, NULL);
2530 SIMPLE_OP (td, MINT_LDELEM_VT);
2531 ADD_CODE (&td, get_data_item_index (&td, klass));
2532 WRITE32 (&td, &size);
2534 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_VT);
2535 PUSH_VT (&td, size);
2539 GString *res = g_string_new ("");
2540 mono_type_get_desc (res, &klass->byval_arg, TRUE);
2541 g_print ("LDELEM: %s -> %d (%s)\n", klass->name, mint_type (&klass->byval_arg), res->str);
2542 g_string_free (res, TRUE);
2550 CHECK_STACK (&td, 3);
2552 SIMPLE_OP (td, MINT_STELEM_I);
2556 CHECK_STACK (&td, 3);
2558 SIMPLE_OP (td, MINT_STELEM_I1);
2562 CHECK_STACK (&td, 3);
2564 SIMPLE_OP (td, MINT_STELEM_I2);
2568 CHECK_STACK (&td, 3);
2570 SIMPLE_OP (td, MINT_STELEM_I4);
2574 CHECK_STACK (&td, 3);
2576 SIMPLE_OP (td, MINT_STELEM_I8);
2580 CHECK_STACK (&td, 3);
2582 SIMPLE_OP (td, MINT_STELEM_R4);
2586 CHECK_STACK (&td, 3);
2588 SIMPLE_OP (td, MINT_STELEM_R8);
2591 case CEE_STELEM_REF:
2592 CHECK_STACK (&td, 3);
2594 SIMPLE_OP (td, MINT_STELEM_REF);
2598 CHECK_STACK (&td, 3);
2600 token = read32 (td.ip + 1);
2601 klass = mini_get_class (method, token, generic_context);
2602 switch (mint_type (&klass->byval_arg)) {
2604 SIMPLE_OP (td, MINT_STELEM_U1);
2607 SIMPLE_OP (td, MINT_STELEM_U2);
2610 SIMPLE_OP (td, MINT_STELEM_I4);
2613 SIMPLE_OP (td, MINT_STELEM_I8);
2616 SIMPLE_OP (td, MINT_STELEM_REF);
2618 case MINT_TYPE_VT: {
2619 int size = mono_class_value_size (klass, NULL);
2620 SIMPLE_OP (td, MINT_STELEM_VT);
2621 ADD_CODE (&td, get_data_item_index (&td, klass));
2622 WRITE32 (&td, &size);
2627 GString *res = g_string_new ("");
2628 mono_type_get_desc (res, &klass->byval_arg, TRUE);
2629 g_print ("STELEM: %s -> %d (%s)\n", klass->name, mint_type (&klass->byval_arg), res->str);
2630 g_string_free (res, TRUE);
2639 case CEE_CONV_OVF_U1:
2641 case CEE_CONV_OVF_I8:
2643 #if SIZEOF_VOID_P == 8
2644 case CEE_CONV_OVF_U:
2646 case CEE_REFANYVAL: ves_abort(); break;
2649 CHECK_STACK (&td, 1);
2650 SIMPLE_OP (td, MINT_CKFINITE);
2652 case CEE_CONV_OVF_I1:
2653 case CEE_CONV_OVF_I1_UN:
2654 CHECK_STACK (&td, 1);
2655 switch (td.sp [-1].type) {
2657 ADD_CODE(&td, MINT_CONV_OVF_I1_R8);
2660 ADD_CODE(&td, MINT_CONV_OVF_I1_I4);
2663 ADD_CODE(&td, MINT_CONV_OVF_I1_I8);
2666 g_assert_not_reached ();
2669 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2671 case CEE_CONV_OVF_U1:
2672 case CEE_CONV_OVF_U1_UN:
2673 CHECK_STACK (&td, 1);
2674 switch (td.sp [-1].type) {
2676 ADD_CODE(&td, MINT_CONV_OVF_U1_R8);
2679 ADD_CODE(&td, MINT_CONV_OVF_U1_I4);
2682 ADD_CODE(&td, MINT_CONV_OVF_U1_I8);
2685 g_assert_not_reached ();
2688 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2690 case CEE_CONV_OVF_I2:
2691 case CEE_CONV_OVF_I2_UN:
2692 CHECK_STACK (&td, 1);
2693 switch (td.sp [-1].type) {
2695 ADD_CODE(&td, MINT_CONV_OVF_I2_R8);
2698 ADD_CODE(&td, MINT_CONV_OVF_I2_I4);
2701 ADD_CODE(&td, MINT_CONV_OVF_I2_I8);
2704 g_assert_not_reached ();
2707 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2709 case CEE_CONV_OVF_U2_UN:
2710 case CEE_CONV_OVF_U2:
2711 CHECK_STACK (&td, 1);
2712 switch (td.sp [-1].type) {
2714 ADD_CODE(&td, MINT_CONV_OVF_U2_R8);
2717 ADD_CODE(&td, MINT_CONV_OVF_U2_I4);
2720 ADD_CODE(&td, MINT_CONV_OVF_U2_I8);
2723 g_assert_not_reached ();
2726 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2728 #if SIZEOF_VOID_P == 4
2729 case CEE_CONV_OVF_I:
2731 case CEE_CONV_OVF_I4:
2732 case CEE_CONV_OVF_I4_UN:
2733 CHECK_STACK (&td, 1);
2734 switch (td.sp [-1].type) {
2736 ADD_CODE(&td, MINT_CONV_OVF_I4_R8);
2739 if (*td.ip == CEE_CONV_OVF_I4_UN)
2740 ADD_CODE(&td, MINT_CONV_OVF_I4_U4);
2743 if (*td.ip == CEE_CONV_OVF_I4_UN)
2744 ADD_CODE (&td, MINT_CONV_OVF_I4_U8);
2746 ADD_CODE (&td, MINT_CONV_OVF_I4_I8);
2749 g_assert_not_reached ();
2752 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2754 #if SIZEOF_VOID_P == 4
2755 case CEE_CONV_OVF_U:
2757 case CEE_CONV_OVF_U4:
2758 case CEE_CONV_OVF_U4_UN:
2759 CHECK_STACK (&td, 1);
2760 switch (td.sp [-1].type) {
2762 ADD_CODE(&td, MINT_CONV_OVF_U4_R8);
2765 if (*td.ip != CEE_CONV_OVF_U4_UN)
2766 ADD_CODE(&td, MINT_CONV_OVF_U4_I4);
2769 ADD_CODE(&td, MINT_CONV_OVF_U4_I8);
2772 g_assert_not_reached ();
2775 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
2777 #if SIZEOF_VOID_P == 8
2778 case CEE_CONV_OVF_I:
2780 case CEE_CONV_OVF_I8:
2781 CHECK_STACK (&td, 1);
2782 switch (td.sp [-1].type) {
2784 ADD_CODE(&td, MINT_CONV_OVF_I8_R8);
2787 ADD_CODE(&td, MINT_CONV_I8_I4);
2792 g_assert_not_reached ();
2795 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8);
2797 #if SIZEOF_VOID_P == 8
2798 case CEE_CONV_OVF_U:
2800 case CEE_CONV_OVF_U8:
2801 CHECK_STACK (&td, 1);
2802 switch (td.sp [-1].type) {
2804 ADD_CODE(&td, MINT_CONV_OVF_U8_R8);
2807 ADD_CODE(&td, MINT_CONV_OVF_U8_I4);
2810 ADD_CODE (&td, MINT_CONV_OVF_U8_I8);
2813 g_assert_not_reached ();
2816 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8);
2821 token = read32 (td.ip + 1);
2822 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
2823 handle = mono_method_get_wrapper_data (method, token);
2824 klass = (MonoClass *) mono_method_get_wrapper_data (method, token + 1);
2825 if (klass == mono_defaults.typehandle_class)
2826 handle = &((MonoClass *) handle)->byval_arg;
2828 if (generic_context) {
2829 handle = mono_class_inflate_generic_type_checked (handle, generic_context, &error);
2830 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
2833 handle = mono_ldtoken (image, token, &klass, generic_context);
2835 mono_class_init (klass);
2836 mt = mint_type (&klass->byval_arg);
2837 g_assert (mt == MINT_TYPE_VT);
2838 size = mono_class_value_size (klass, NULL);
2839 g_assert (size == sizeof(gpointer));
2840 PUSH_VT (&td, sizeof(gpointer));
2841 ADD_CODE (&td, MINT_LDTOKEN);
2842 ADD_CODE (&td, get_data_item_index (&td, handle));
2844 SET_TYPE (td.sp, stack_type [mt], klass);
2850 binary_arith_op(&td, MINT_ADD_OVF_I4);
2853 case CEE_ADD_OVF_UN:
2854 binary_arith_op(&td, MINT_ADD_OVF_UN_I4);
2858 binary_arith_op(&td, MINT_MUL_OVF_I4);
2861 case CEE_MUL_OVF_UN:
2862 binary_arith_op(&td, MINT_MUL_OVF_UN_I4);
2866 binary_arith_op(&td, MINT_SUB_OVF_I4);
2869 case CEE_SUB_OVF_UN:
2870 binary_arith_op(&td, MINT_SUB_OVF_UN_I4);
2873 case CEE_ENDFINALLY:
2874 g_assert (td.clause_indexes [in_offset] != -1);
2876 SIMPLE_OP (td, MINT_ENDFINALLY);
2877 ADD_CODE (&td, td.clause_indexes [in_offset]);
2878 generating_code = 0;
2882 handle_branch (&td, MINT_LEAVE_S, MINT_LEAVE, 5 + read32 (td.ip + 1));
2884 generating_code = 0;
2888 handle_branch (&td, MINT_LEAVE_S, MINT_LEAVE, 2 + (gint8)td.ip [1]);
2890 generating_code = 0;
2895 case CEE_MONO_CALLI_EXTRA_ARG:
2896 /* Same as CEE_CALLI, except that we drop the extra arg required for llvm specific behaviour */
2897 ADD_CODE (&td, MINT_POP);
2900 interp_transform_call (&td, method, NULL, domain, generic_context, is_bb_start, body_start_offset, NULL, FALSE);
2902 case CEE_MONO_JIT_ICALL_ADDR: {
2905 MonoJitICallInfo *info;
2907 token = read32 (td.ip + 1);
2909 func = mono_method_get_wrapper_data (method, token);
2910 info = mono_find_jit_icall_by_addr (func);
2912 ADD_CODE (&td, MINT_LDFTN);
2913 ADD_CODE (&td, get_data_item_index (&td, func));
2914 PUSH_SIMPLE_TYPE (&td, STACK_TYPE_I);
2917 case CEE_MONO_ICALL: {
2920 MonoJitICallInfo *info;
2922 token = read32 (td.ip + 1);
2924 func = mono_method_get_wrapper_data (method, token);
2925 info = mono_find_jit_icall_by_addr (func);
2928 CHECK_STACK (&td, info->sig->param_count);
2929 switch (info->sig->param_count) {
2931 if (MONO_TYPE_IS_VOID (info->sig->ret))
2932 ADD_CODE (&td,MINT_ICALL_V_V);
2934 ADD_CODE (&td, MINT_ICALL_V_P);
2937 if (MONO_TYPE_IS_VOID (info->sig->ret))
2938 ADD_CODE (&td,MINT_ICALL_P_V);
2940 ADD_CODE (&td,MINT_ICALL_P_P);
2943 if (MONO_TYPE_IS_VOID (info->sig->ret)) {
2944 if (info->sig->params [1]->type == MONO_TYPE_I4)
2945 ADD_CODE (&td,MINT_ICALL_PI_V);
2947 ADD_CODE (&td,MINT_ICALL_PP_V);
2949 if (info->sig->params [1]->type == MONO_TYPE_I4)
2950 ADD_CODE (&td,MINT_ICALL_PI_P);
2952 ADD_CODE (&td,MINT_ICALL_PP_P);
2956 g_assert (MONO_TYPE_IS_VOID (info->sig->ret));
2957 if (info->sig->params [2]->type == MONO_TYPE_I4)
2958 ADD_CODE (&td,MINT_ICALL_PPI_V);
2960 ADD_CODE (&td,MINT_ICALL_PPP_V);
2963 g_assert_not_reached ();
2966 if (func == mono_ftnptr_to_delegate) {
2967 g_error ("TODO: ?");
2969 ADD_CODE(&td, get_data_item_index (&td, func));
2970 td.sp -= info->sig->param_count;
2972 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
2974 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I);
2978 case CEE_MONO_VTADDR: {
2980 CHECK_STACK (&td, 1);
2981 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2982 size = mono_class_native_size(td.sp [-1].klass, NULL);
2984 size = mono_class_value_size(td.sp [-1].klass, NULL);
2985 size = (size + 7) & ~7;
2986 ADD_CODE(&td, MINT_VTRESULT);
2988 WRITE32(&td, &size);
2991 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP);
2994 case CEE_MONO_LDPTR:
2995 case CEE_MONO_CLASSCONST:
2996 token = read32 (td.ip + 1);
2998 ADD_CODE(&td, MINT_MONO_LDPTR);
2999 ADD_CODE(&td, get_data_item_index (&td, mono_method_get_wrapper_data (method, token)));
3000 td.sp [0].type = STACK_TYPE_I;
3003 case CEE_MONO_OBJADDR:
3004 CHECK_STACK (&td, 1);
3006 td.sp[-1].type = STACK_TYPE_MP;
3009 case CEE_MONO_NEWOBJ:
3010 token = read32 (td.ip + 1);
3012 ADD_CODE(&td, MINT_MONO_NEWOBJ);
3013 ADD_CODE(&td, get_data_item_index (&td, mono_method_get_wrapper_data (method, token)));
3014 td.sp [0].type = STACK_TYPE_O;
3017 case CEE_MONO_RETOBJ:
3018 CHECK_STACK (&td, 1);
3019 token = read32 (td.ip + 1);
3021 ADD_CODE(&td, MINT_MONO_RETOBJ);
3024 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3026 /*stackval_from_data (signature->ret, frame->retval, sp->data.vt, signature->pinvoke);*/
3028 if (td.sp > td.stack)
3029 g_warning ("CEE_MONO_RETOBJ: more values on stack: %d", td.sp-td.stack);
3031 case CEE_MONO_LDNATIVEOBJ:
3032 token = read32 (td.ip + 1);
3034 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3035 g_assert(klass->valuetype);
3036 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP);
3038 case CEE_MONO_TLS: {
3039 gint32 key = read32 (td.ip + 1);
3041 g_assert (key < TLS_KEY_NUM);
3042 ADD_CODE (&td, MINT_MONO_TLS);
3043 WRITE32 (&td, &key);
3044 PUSH_SIMPLE_TYPE (&td, STACK_TYPE_MP);
3047 case CEE_MONO_ATOMIC_STORE_I4:
3048 CHECK_STACK (&td, 2);
3049 SIMPLE_OP (td, MINT_MONO_ATOMIC_STORE_I4);
3053 case CEE_MONO_SAVE_LMF:
3054 case CEE_MONO_RESTORE_LMF:
3055 case CEE_MONO_NOT_TAKEN:
3058 case CEE_MONO_LDPTR_INT_REQ_FLAG:
3059 ADD_CODE (&td, MINT_MONO_LDPTR);
3060 ADD_CODE (&td, get_data_item_index (&td, mono_thread_interruption_request_flag ()));
3061 PUSH_TYPE (&td, STACK_TYPE_MP, NULL);
3064 case CEE_MONO_JIT_ATTACH:
3065 ADD_CODE (&td, MINT_MONO_JIT_ATTACH);
3068 case CEE_MONO_JIT_DETACH:
3069 ADD_CODE (&td, MINT_MONO_JIT_DETACH);
3073 g_error ("transform.c: Unimplemented opcode: 0xF0 %02x at 0x%x\n", *td.ip, td.ip-header->code);
3083 case CEE_PREFIXREF: ves_abort(); break;
3086 * Note: Exceptions thrown when executing a prefixed opcode need
3087 * to take into account the number of prefix bytes (usually the
3088 * throw point is just (ip - n_prefix_bytes).
3094 case CEE_ARGLIST: ves_abort(); break;
3097 CHECK_STACK(&td, 2);
3098 if (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_MP)
3099 ADD_CODE(&td, MINT_CEQ_I4 + STACK_TYPE_I - STACK_TYPE_I4);
3101 ADD_CODE(&td, MINT_CEQ_I4 + td.sp [-1].type - STACK_TYPE_I4);
3103 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
3107 CHECK_STACK(&td, 2);
3108 if (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_MP)
3109 ADD_CODE(&td, MINT_CGT_I4 + STACK_TYPE_I - STACK_TYPE_I4);
3111 ADD_CODE(&td, MINT_CGT_I4 + td.sp [-1].type - STACK_TYPE_I4);
3113 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
3117 CHECK_STACK(&td, 2);
3118 if (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_MP)
3119 ADD_CODE(&td, MINT_CGT_UN_I4 + STACK_TYPE_I - STACK_TYPE_I4);
3121 ADD_CODE(&td, MINT_CGT_UN_I4 + td.sp [-1].type - STACK_TYPE_I4);
3123 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
3127 CHECK_STACK(&td, 2);
3128 if (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_MP)
3129 ADD_CODE(&td, MINT_CLT_I4 + STACK_TYPE_I - STACK_TYPE_I4);
3131 ADD_CODE(&td, MINT_CLT_I4 + td.sp [-1].type - STACK_TYPE_I4);
3133 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
3137 CHECK_STACK(&td, 2);
3138 if (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_MP)
3139 ADD_CODE(&td, MINT_CLT_UN_I4 + STACK_TYPE_I - STACK_TYPE_I4);
3141 ADD_CODE(&td, MINT_CLT_UN_I4 + td.sp [-1].type - STACK_TYPE_I4);
3143 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
3146 case CEE_LDVIRTFTN: /* fallthrough */
3149 if (*td.ip == CEE_LDVIRTFTN) {
3150 CHECK_STACK (&td, 1);
3153 token = read32 (td.ip + 1);
3154 if (method->wrapper_type != MONO_WRAPPER_NONE)
3155 m = (MonoMethod *)mono_method_get_wrapper_data (method, token);
3157 m = mono_get_method_full (image, token, NULL, generic_context);
3159 if (method->wrapper_type == MONO_WRAPPER_NONE && m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
3160 m = mono_marshal_get_synchronized_wrapper (m);
3162 ADD_CODE(&td, *td.ip == CEE_LDFTN ? MINT_LDFTN : MINT_LDVIRTFTN);
3163 ADD_CODE(&td, get_data_item_index (&td, mono_interp_get_runtime_method (domain, m, &error)));
3164 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3166 PUSH_SIMPLE_TYPE (&td, STACK_TYPE_F);
3170 load_arg (&td, read16 (td.ip + 1));
3174 int n = read16 (td.ip + 1);
3175 ADD_CODE (&td, MINT_LDARGA);
3176 ADD_CODE (&td, td.rtm->arg_offsets [n]); /* FIX for large offsets */
3177 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_MP);
3182 store_arg (&td, read16 (td.ip + 1));
3186 load_local (&td, read16 (td.ip + 1));
3190 ADD_CODE(&td, MINT_LDLOCA_S);
3191 ADD_CODE(&td, td.rtm->local_offsets [read16 (td.ip + 1)]);
3192 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_MP);
3196 store_local (&td, read16 (td.ip + 1));
3200 CHECK_STACK (&td, 1);
3201 #if SIZEOF_VOID_P == 8
3202 if (td.sp [-1].type == STACK_TYPE_I8)
3203 ADD_CODE(&td, MINT_CONV_I4_I8);
3205 ADD_CODE(&td, MINT_LOCALLOC);
3206 if (td.sp != td.stack + 1)
3207 g_warning("CEE_LOCALLOC: stack not empty");
3209 SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP);
3212 case CEE_UNUSED57: ves_abort(); break;
3215 ADD_CODE (&td, MINT_ENDFILTER);
3218 case CEE_UNALIGNED_:
3220 /* FIX: should do something? */;
3224 /* FIX: should do something? */;
3228 /* FIX: should do something? */;
3231 CHECK_STACK(&td, 1);
3232 token = read32 (td.ip + 1);
3233 klass = mini_get_class (method, token, generic_context);
3234 if (klass->valuetype) {
3235 ADD_CODE (&td, MINT_INITOBJ);
3236 i32 = mono_class_value_size (klass, NULL);
3237 WRITE32 (&td, &i32);
3239 ADD_CODE (&td, MINT_LDNULL);
3240 ADD_CODE (&td, MINT_STIND_REF);
3246 CHECK_STACK(&td, 3);
3247 /* FIX? convert length to I8? */
3248 ADD_CODE(&td, MINT_CPBLK);
3256 case CEE_CONSTRAINED_:
3257 token = read32 (td.ip + 1);
3258 constrained_class = mini_get_class (method, token, generic_context);
3259 mono_class_init (constrained_class);
3263 CHECK_STACK(&td, 3);
3264 ADD_CODE(&td, MINT_INITBLK);
3270 /* FIXME: implement */
3275 SIMPLE_OP (td, MINT_RETHROW);
3276 generating_code = 0;
3280 token = read32 (td.ip + 1);
3282 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
3284 MonoType *type = mono_type_create_from_typespec (image, token);
3285 size = mono_type_size (type, &align);
3288 MonoClass *szclass = mini_get_class (method, token, generic_context);
3289 mono_class_init (szclass);
3291 if (!szclass->valuetype)
3292 THROW_EX (mono_exception_from_name (mono_defaults.corlib, "System", "InvalidProgramException"), ip - 5);
3294 size = mono_type_size (&szclass->byval_arg, &align);
3296 ADD_CODE(&td, MINT_LDC_I4);
3297 WRITE32(&td, &size);
3298 PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4);
3302 case CEE_REFANYTYPE: ves_abort(); break;
3305 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);
3309 g_error ("transform.c: Unimplemented opcode: %02x at 0x%x\n", *td.ip, td.ip-header->code);
3312 if (td.new_ip - td.new_code != new_in_start_offset)
3313 td.last_new_ip = td.new_code + new_in_start_offset;
3314 else if (td.is_bb_start [td.in_start - td.il_code])
3315 td.is_bb_start [td.ip - td.il_code] = 1;
3317 td.last_ip = td.in_start;
3320 if (mono_interp_traceopt) {
3321 const guint16 *p = td.new_code;
3322 printf("Runtime method: %p, VT stack size: %d\n", rtm, td.max_vt_sp);
3323 printf("Calculated stack size: %d, stated size: %d\n", td.max_stack_height, header->max_stack);
3324 while (p < td.new_ip) {
3325 p = mono_interp_dis_mintop(td.new_code, p);
3329 g_assert (td.max_stack_height <= (header->max_stack + 1));
3331 int code_len = td.new_ip - td.new_code;
3333 rtm->clauses = mono_domain_alloc0 (domain, header->num_clauses * sizeof (MonoExceptionClause));
3334 memcpy (rtm->clauses, header->clauses, header->num_clauses * sizeof(MonoExceptionClause));
3335 rtm->code = mono_domain_alloc0 (domain, (td.new_ip - td.new_code) * sizeof (gushort));
3336 memcpy (rtm->code, td.new_code, (td.new_ip - td.new_code) * sizeof(gushort));
3337 g_free (td.new_code);
3338 rtm->new_body_start = rtm->code + body_start_offset;
3339 rtm->num_clauses = header->num_clauses;
3340 for (i = 0; i < header->num_clauses; i++) {
3341 MonoExceptionClause *c = rtm->clauses + i;
3342 int end_off = c->try_offset + c->try_len;
3343 c->try_offset = td.in_offsets [c->try_offset];
3344 c->try_len = td.in_offsets [end_off] - c->try_offset;
3345 end_off = c->handler_offset + c->handler_len;
3346 c->handler_offset = td.in_offsets [c->handler_offset];
3347 c->handler_len = td.in_offsets [end_off] - c->handler_offset;
3348 if (c->flags & MONO_EXCEPTION_CLAUSE_FILTER)
3349 c->data.filter_offset = td.in_offsets [c->data.filter_offset];
3351 rtm->vt_stack_size = td.max_vt_sp;
3352 rtm->alloca_size = rtm->locals_size + rtm->args_size + rtm->vt_stack_size + rtm->stack_size;
3353 rtm->data_items = mono_domain_alloc0 (domain, td.n_data_items * sizeof (td.data_items [0]));
3354 memcpy (rtm->data_items, td.data_items, td.n_data_items * sizeof (td.data_items [0]));
3356 /* Save debug info */
3357 interp_save_debug_info (rtm, header, &td, line_numbers);
3359 /* Create a MonoJitInfo for the interpreted method by creating the interpreter IR as the native code. */
3360 int jinfo_len = mono_jit_info_size (0, header->num_clauses, 0);
3361 MonoJitInfo *jinfo = (MonoJitInfo *)mono_domain_alloc0 (domain, jinfo_len);
3363 mono_jit_info_init (jinfo, method, (guint8*)rtm->code, code_len, 0, header->num_clauses, 0);
3364 for (i = 0; i < jinfo->num_clauses; ++i) {
3365 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
3366 MonoExceptionClause *c = rtm->clauses + i;
3368 ei->flags = c->flags;
3369 ei->try_start = rtm->code + c->try_offset;
3370 ei->try_end = rtm->code + c->try_offset + c->try_len;
3371 ei->handler_start = rtm->code + c->handler_offset;
3372 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
3374 ei->data.catch_class = c->data.catch_class;
3378 g_free (td.in_offsets);
3379 g_free (td.forward_refs);
3380 for (i = 0; i < header->code_size; ++i)
3381 g_free (td.stack_state [i]);
3382 g_free (td.stack_state);
3383 g_free (td.stack_height);
3384 g_free (td.vt_stack_size);
3385 g_free (td.data_items);
3387 g_hash_table_destroy (td.data_hash);
3388 g_free (td.clause_indexes);
3389 g_array_free (line_numbers, TRUE);
3392 static mono_mutex_t calc_section;
3395 mono_interp_transform_init (void)
3397 mono_os_mutex_init_recursive(&calc_section);
3401 mono_interp_transform_method (RuntimeMethod *runtime_method, ThreadContext *context)
3403 int i, align, size, offset;
3404 MonoMethod *method = runtime_method->method;
3405 MonoImage *image = method->klass->image;
3406 MonoMethodHeader *header = mono_method_get_header (method);
3407 MonoMethodSignature *signature = mono_method_signature (method);
3408 register const unsigned char *ip, *end;
3409 const MonoOpcode *opcode;
3412 MonoDomain *domain = mono_domain_get ();
3413 unsigned char *is_bb_start;
3415 MonoVTable *method_class_vt;
3417 MonoGenericContext *generic_context = NULL;
3419 // g_printerr ("TRANSFORM(0x%016lx): begin %s::%s\n", mono_thread_current (), method->klass->name, method->name);
3420 method_class_vt = mono_class_vtable (domain, runtime_method->method->klass);
3421 if (!method_class_vt->initialized) {
3424 MonoInvocation *last_env_frame = context->env_frame;
3425 jmp_buf *old_env = context->current_env;
3426 error_init (&error);
3429 MonoException *failed = context->env_frame->ex;
3430 context->env_frame->ex = NULL;
3431 context->env_frame = last_env_frame;
3432 context->current_env = old_env;
3435 context->env_frame = context->current_frame;
3436 context->current_env = &env;
3437 mono_runtime_class_init_full (method_class_vt, &error);
3438 if (!mono_error_ok (&error)) {
3439 return mono_error_convert_to_exception (&error);
3441 context->env_frame = last_env_frame;
3442 context->current_env = old_env;
3445 mono_profiler_method_jit (method); /* sort of... */
3447 if (mono_method_signature (method)->is_inflated)
3448 generic_context = mono_method_get_context (method);
3450 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
3451 if (generic_container)
3452 generic_context = &generic_container->context;
3455 if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
3456 MonoMethod *nm = NULL;
3457 mono_os_mutex_lock(&calc_section);
3458 if (runtime_method->transformed) {
3459 mono_os_mutex_unlock(&calc_section);
3460 mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK);
3464 /* assumes all internal calls with an array this are built in... */
3465 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL && (! mono_method_signature (method)->hasthis || method->klass->rank == 0)) {
3466 nm = mono_marshal_get_native_wrapper (method, TRUE, FALSE);
3467 signature = mono_method_signature (nm);
3469 const char *name = method->name;
3470 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
3471 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
3472 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("ves_icall_mono_delegate_ctor");
3474 char *wrapper_name = g_strdup_printf ("__icall_wrapper_%s", mi->name);
3475 nm = mono_marshal_get_icall_wrapper (mi->sig, wrapper_name, mi->func, TRUE);
3476 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
3477 nm = mono_marshal_get_delegate_invoke (method, NULL);
3478 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
3479 nm = mono_marshal_get_delegate_begin_invoke (method);
3480 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
3481 nm = mono_marshal_get_delegate_end_invoke (method);
3485 runtime_method->code = g_malloc(sizeof(short));
3486 runtime_method->code[0] = MINT_CALLRUN;
3490 runtime_method->stack_size = sizeof (stackval); /* for tracing */
3491 runtime_method->alloca_size = runtime_method->stack_size;
3492 runtime_method->transformed = TRUE;
3493 mono_os_mutex_unlock(&calc_section);
3494 mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK);
3498 header = mono_method_get_header (nm);
3499 mono_os_mutex_unlock(&calc_section);
3500 } else if (method->klass == mono_defaults.array_class) {
3501 if (!strcmp (method->name, "UnsafeMov")) {
3502 mono_os_mutex_lock (&calc_section);
3503 if (!runtime_method->transformed) {
3504 runtime_method->code = g_malloc (sizeof (short));
3505 runtime_method->code[0] = MINT_CALLRUN;
3506 runtime_method->stack_size = sizeof (stackval); /* for tracing */
3507 runtime_method->alloca_size = runtime_method->stack_size;
3508 runtime_method->transformed = TRUE;
3510 mono_os_mutex_unlock(&calc_section);
3511 mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK);
3513 } else if (!strcmp (method->name, "UnsafeStore)")) {
3515 } else if (!strcmp (method->name, "UnsafeLoad)")) {
3519 g_assert ((signature->param_count + signature->hasthis) < 1000);
3520 g_assert (header->max_stack < 10000);
3521 /* intern the strings in the method. */
3523 end = ip + header->code_size;
3525 is_bb_start = g_malloc0(header->code_size);
3526 is_bb_start [0] = 1;
3533 else if (in == 0xf0) {
3535 in = *ip + MONO_CEE_MONO_ICALL;
3537 opcode = &mono_opcodes [in];
3538 switch (opcode->argument) {
3539 case MonoInlineNone:
3542 case MonoInlineString:
3543 if (method->wrapper_type == MONO_WRAPPER_NONE)
3544 mono_ldstr (domain, image, mono_metadata_token_index (read32 (ip + 1)));
3547 case MonoInlineType:
3548 if (method->wrapper_type == MONO_WRAPPER_NONE) {
3549 class = mini_get_class (method, read32 (ip + 1), generic_context);
3550 mono_class_init (class);
3551 /* quick fix to not do this for the fake ptr classes - probably should not be getting the vtable at all here */
3553 g_error ("FIXME: interface method lookup: %s (in method %s)", class->name, method->name);
3554 if (!(class->flags & TYPE_ATTRIBUTE_INTERFACE) && class->interface_offsets != NULL)
3555 mono_class_vtable (domain, class);
3560 case MonoInlineMethod:
3561 if (method->wrapper_type == MONO_WRAPPER_NONE && *ip != CEE_CALLI) {
3562 m = mono_get_method_full (image, read32 (ip + 1), NULL, generic_context);
3564 g_free (is_bb_start);
3565 g_error ("FIXME: where to get method and class string?");
3567 // return mono_get_exception_missing_method ();
3569 mono_class_init (m->klass);
3570 if (!mono_class_is_interface (m->klass))
3571 mono_class_vtable (domain, m->klass);
3575 case MonoInlineField:
3579 case MonoShortInlineR:
3582 case MonoInlineBrTarget:
3583 offset = read32 (ip + 1);
3585 backwards = offset < 0;
3586 offset += ip - header->code;
3587 g_assert (offset >= 0 && offset < header->code_size);
3588 is_bb_start [offset] |= backwards ? 2 : 1;
3590 case MonoShortInlineBrTarget:
3591 offset = ((gint8 *)ip) [1];
3593 backwards = offset < 0;
3594 offset += ip - header->code;
3595 g_assert (offset >= 0 && offset < header->code_size);
3596 is_bb_start [offset] |= backwards ? 2 : 1;
3601 case MonoShortInlineVar:
3602 case MonoShortInlineI:
3605 case MonoInlineSwitch: {
3607 const unsigned char *next_ip;
3611 next_ip = ip + 4 * n;
3612 for (i = 0; i < n; i++) {
3613 offset = read32 (ip);
3614 backwards = offset < 0;
3615 offset += next_ip - header->code;
3616 g_assert (offset >= 0 && offset < header->code_size);
3617 is_bb_start [offset] |= backwards ? 2 : 1;
3627 g_assert_not_reached ();
3630 // g_printerr ("TRANSFORM(0x%016lx): end %s::%s\n", mono_thread_current (), method->klass->name, method->name);
3632 /* the rest needs to be locked so it is only done once */
3633 mono_os_mutex_lock(&calc_section);
3634 if (runtime_method->transformed) {
3635 mono_os_mutex_unlock(&calc_section);
3636 g_free (is_bb_start);
3637 mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK);
3641 runtime_method->local_offsets = g_malloc (header->num_locals * sizeof(guint32));
3642 runtime_method->stack_size = (sizeof (stackval)) * (header->max_stack + 2); /* + 1 for returns of called functions + 1 for 0-ing in trace*/
3643 runtime_method->stack_size = (runtime_method->stack_size + 7) & ~7;
3645 for (i = 0; i < header->num_locals; ++i) {
3646 size = mono_type_size (header->locals [i], &align);
3647 offset += align - 1;
3648 offset &= ~(align - 1);
3649 runtime_method->local_offsets [i] = offset;
3652 offset = (offset + 7) & ~7;
3653 runtime_method->locals_size = offset;
3654 g_assert (runtime_method->locals_size < 65536);
3656 runtime_method->arg_offsets = g_malloc ((!!signature->hasthis + signature->param_count) * sizeof(guint32));
3658 if (signature->hasthis) {
3659 g_assert (!signature->pinvoke);
3660 size = mono_type_stack_size (&method->klass->byval_arg, &align);
3661 offset += align - 1;
3662 offset &= ~(align - 1);
3663 runtime_method->arg_offsets [0] = offset;
3667 for (i = 0; i < signature->param_count; ++i) {
3668 if (signature->pinvoke) {
3670 size = mono_type_native_stack_size (signature->params [i], &dummy);
3674 size = mono_type_stack_size (signature->params [i], &align);
3675 offset += align - 1;
3676 offset &= ~(align - 1);
3677 runtime_method->arg_offsets [i + !!signature->hasthis] = offset;
3680 offset = (offset + 7) & ~7;
3681 runtime_method->args_size = offset;
3682 g_assert (runtime_method->args_size < 10000);
3684 generate (method, runtime_method, is_bb_start, generic_context);
3686 g_free (is_bb_start);
3688 mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK);
3689 runtime_method->transformed = TRUE;
3690 mono_os_mutex_unlock(&calc_section);