3 * transform CIL into different opcodes for more
4 * efficient interpretation
6 * Written by Bernie Solomon (bernard@ugsolutions.com)
12 #include <mono/metadata/appdomain.h>
13 #include <mono/metadata/debug-helpers.h>
14 #include <mono/metadata/exception.h>
15 #include <mono/metadata/exception-internals.h>
16 #include <mono/metadata/mono-endian.h>
17 #include <mono/metadata/marshal.h>
18 #include <mono/metadata/profiler-private.h>
19 #include <mono/metadata/tabledefs.h>
20 #include <mono/metadata/seq-points-data.h>
21 #include <mono/metadata/mono-basic-block.h>
22 #include <mono/metadata/abi-details.h>
23 #include <mono/metadata/reflection-internals.h>
25 #include <mono/mini/mini.h>
26 #include <mono/mini/mini-runtime.h>
29 #include "interp-internals.h"
45 SeqPoint
*last_seq_point
;
47 // This will hold a list of last sequence points of incoming basic blocks
48 SeqPoint
**pred_seq_points
;
49 guint num_pred_seq_points
;
60 /* In the interpreter IR */
69 MonoMethodHeader
*header
;
71 const unsigned char *il_code
;
72 const unsigned char *ip
;
73 const unsigned char *last_ip
;
74 const unsigned char *in_start
;
77 StackInfo
**stack_state
;
80 unsigned char *is_bb_start
;
81 unsigned short *new_code
;
82 unsigned short *new_code_end
;
83 unsigned short *new_ip
;
84 unsigned short *last_new_ip
;
85 unsigned int max_code_size
;
88 unsigned int max_stack_height
;
89 unsigned int stack_capacity
;
91 unsigned int max_vt_sp
;
92 unsigned int total_locals_size
;
96 GHashTable
*data_hash
;
98 gboolean gen_sdb_seq_points
;
99 GPtrArray
*seq_points
;
100 InterpBasicBlock
**offset_to_bb
;
101 InterpBasicBlock
*entry_bb
;
102 MonoMemPool
*mempool
;
105 gboolean verbose_level
;
108 #define STACK_TYPE_I4 0
109 #define STACK_TYPE_I8 1
110 #define STACK_TYPE_R4 2
111 #define STACK_TYPE_R8 3
112 #define STACK_TYPE_O 4
113 #define STACK_TYPE_VT 5
114 #define STACK_TYPE_MP 6
115 #define STACK_TYPE_F 7
117 static const char *stack_type_string
[] = { "I4", "I8", "R4", "R8", "O ", "VT", "MP", "F " };
119 #if SIZEOF_VOID_P == 8
120 #define STACK_TYPE_I STACK_TYPE_I8
122 #define STACK_TYPE_I STACK_TYPE_I4
125 static int stack_type
[] = {
126 STACK_TYPE_I4
, /*I1*/
127 STACK_TYPE_I4
, /*U1*/
128 STACK_TYPE_I4
, /*I2*/
129 STACK_TYPE_I4
, /*U2*/
130 STACK_TYPE_I4
, /*I4*/
131 STACK_TYPE_I8
, /*I8*/
132 STACK_TYPE_R4
, /*R4*/
133 STACK_TYPE_R8
, /*R8*/
139 #if SIZEOF_VOID_P == 8
140 #define MINT_NEG_P MINT_NEG_I8
141 #define MINT_NOT_P MINT_NOT_I8
143 #define MINT_NEG_FP MINT_NEG_R8
145 #define MINT_ADD_P MINT_ADD_I8
146 #define MINT_SUB_P MINT_SUB_I8
147 #define MINT_MUL_P MINT_MUL_I8
148 #define MINT_DIV_P MINT_DIV_I8
149 #define MINT_DIV_UN_P MINT_DIV_UN_I8
150 #define MINT_REM_P MINT_REM_I8
151 #define MINT_REM_UN_P MINT_REM_UN_I8
152 #define MINT_AND_P MINT_AND_I8
153 #define MINT_OR_P MINT_OR_I8
154 #define MINT_XOR_P MINT_XOR_I8
155 #define MINT_SHL_P MINT_SHL_I8
156 #define MINT_SHR_P MINT_SHR_I8
157 #define MINT_SHR_UN_P MINT_SHR_UN_I8
159 #define MINT_CEQ_P MINT_CEQ_I8
160 #define MINT_CNE_P MINT_CNE_I8
161 #define MINT_CLT_P MINT_CLT_I8
162 #define MINT_CLT_UN_P MINT_CLT_UN_I8
163 #define MINT_CGT_P MINT_CGT_I8
164 #define MINT_CGT_UN_P MINT_CGT_UN_I8
165 #define MINT_CLE_P MINT_CLE_I8
166 #define MINT_CLE_UN_P MINT_CLE_UN_I8
167 #define MINT_CGE_P MINT_CGE_I8
168 #define MINT_CGE_UN_P MINT_CGE_UN_I8
170 #define MINT_ADD_FP MINT_ADD_R8
171 #define MINT_SUB_FP MINT_SUB_R8
172 #define MINT_MUL_FP MINT_MUL_R8
173 #define MINT_DIV_FP MINT_DIV_R8
174 #define MINT_REM_FP MINT_REM_R8
176 #define MINT_CNE_FP MINT_CNE_R8
177 #define MINT_CEQ_FP MINT_CEQ_R8
178 #define MINT_CGT_FP MINT_CGT_R8
179 #define MINT_CGE_FP MINT_CGE_R8
180 #define MINT_CLT_FP MINT_CLT_R8
181 #define MINT_CLE_FP MINT_CLE_R8
185 #define MINT_NEG_P MINT_NEG_I4
186 #define MINT_NOT_P MINT_NOT_I4
188 #define MINT_NEG_FP MINT_NEG_R4
190 #define MINT_ADD_P MINT_ADD_I4
191 #define MINT_SUB_P MINT_SUB_I4
192 #define MINT_MUL_P MINT_MUL_I4
193 #define MINT_DIV_P MINT_DIV_I4
194 #define MINT_DIV_UN_P MINT_DIV_UN_I4
195 #define MINT_REM_P MINT_REM_I4
196 #define MINT_REM_UN_P MINT_REM_UN_I4
197 #define MINT_AND_P MINT_AND_I4
198 #define MINT_OR_P MINT_OR_I4
199 #define MINT_XOR_P MINT_XOR_I4
200 #define MINT_SHL_P MINT_SHL_I4
201 #define MINT_SHR_P MINT_SHR_I4
202 #define MINT_SHR_UN_P MINT_SHR_UN_I4
204 #define MINT_CEQ_P MINT_CEQ_I4
205 #define MINT_CNE_P MINT_CNE_I4
206 #define MINT_CLT_P MINT_CLT_I4
207 #define MINT_CLT_UN_P MINT_CLT_UN_I4
208 #define MINT_CGT_P MINT_CGT_I4
209 #define MINT_CGT_UN_P MINT_CGT_UN_I4
210 #define MINT_CLE_P MINT_CLE_I4
211 #define MINT_CLE_UN_P MINT_CLE_UN_I4
212 #define MINT_CGE_P MINT_CGE_I4
213 #define MINT_CGE_UN_P MINT_CGE_UN_I4
215 #define MINT_ADD_FP MINT_ADD_R4
216 #define MINT_SUB_FP MINT_SUB_R4
217 #define MINT_MUL_FP MINT_MUL_R4
218 #define MINT_DIV_FP MINT_DIV_R4
219 #define MINT_REM_FP MINT_REM_R4
221 #define MINT_CNE_FP MINT_CNE_R4
222 #define MINT_CEQ_FP MINT_CEQ_R4
223 #define MINT_CGT_FP MINT_CGT_R4
224 #define MINT_CGE_FP MINT_CGE_R4
225 #define MINT_CLT_FP MINT_CLT_R4
226 #define MINT_CLE_FP MINT_CLE_R4
231 const gchar
*op_name
;
235 // static const MagicIntrinsic int_binop[] = {
237 static const MagicIntrinsic int_unnop
[] = {
238 { "op_UnaryPlus", {MINT_NOP
, MINT_NOP
, MINT_NOP
}},
239 { "op_UnaryNegation", {MINT_NEG_P
, MINT_NEG_P
, MINT_NEG_FP
}},
240 { "op_OnesComplement", {MINT_NOT_P
, MINT_NOT_P
, MINT_NIY
}}
243 static const MagicIntrinsic int_binop
[] = {
244 { "op_Addition", {MINT_ADD_P
, MINT_ADD_P
, MINT_ADD_FP
}},
245 { "op_Subtraction", {MINT_SUB_P
, MINT_SUB_P
, MINT_SUB_FP
}},
246 { "op_Multiply", {MINT_MUL_P
, MINT_MUL_P
, MINT_MUL_FP
}},
247 { "op_Division", {MINT_DIV_P
, MINT_DIV_UN_P
, MINT_DIV_FP
}},
248 { "op_Modulus", {MINT_REM_P
, MINT_REM_UN_P
, MINT_REM_FP
}},
249 { "op_BitwiseAnd", {MINT_AND_P
, MINT_AND_P
, MINT_NIY
}},
250 { "op_BitwiseOr", {MINT_OR_P
, MINT_OR_P
, MINT_NIY
}},
251 { "op_ExclusiveOr", {MINT_XOR_P
, MINT_XOR_P
, MINT_NIY
}},
252 { "op_LeftShift", {MINT_SHL_P
, MINT_SHL_P
, MINT_NIY
}},
253 { "op_RightShift", {MINT_SHR_P
, MINT_SHR_UN_P
, MINT_NIY
}},
256 static const MagicIntrinsic int_cmpop
[] = {
257 { "op_Inequality", {MINT_CNE_P
, MINT_CNE_P
, MINT_CNE_FP
}},
258 { "op_Equality", {MINT_CEQ_P
, MINT_CEQ_P
, MINT_CEQ_FP
}},
259 { "op_GreaterThan", {MINT_CGT_P
, MINT_CGT_UN_P
, MINT_CGT_FP
}},
260 { "op_GreaterThanOrEqual", {MINT_CGE_P
, MINT_CGE_UN_P
, MINT_CGE_FP
}},
261 { "op_LessThan", {MINT_CLT_P
, MINT_CLT_UN_P
, MINT_CLT_FP
}},
262 { "op_LessThanOrEqual", {MINT_CLE_P
, MINT_CLE_UN_P
, MINT_CLE_FP
}}
266 grow_code (TransformData
*td
)
268 unsigned int old_ip_offset
= td
->new_ip
- td
->new_code
;
269 unsigned int old_last_ip_offset
= td
->last_new_ip
- td
->new_code
;
270 g_assert (old_ip_offset
<= td
->max_code_size
);
271 td
->new_code
= (guint16
*)g_realloc (td
->new_code
, (td
->max_code_size
*= 2) * sizeof (td
->new_code
[0]));
272 td
->new_code_end
= td
->new_code
+ td
->max_code_size
;
273 td
->new_ip
= td
->new_code
+ old_ip_offset
;
274 td
->last_new_ip
= td
->new_code
+ old_last_ip_offset
;
277 #define ENSURE_CODE(td, n) \
279 if ((td)->new_ip + (n) > (td)->new_code_end) \
283 #define ADD_CODE(td, n) \
285 if ((td)->new_ip == (td)->new_code_end) \
287 *(td)->new_ip++ = (n); \
290 #define CHECK_STACK(td, n) \
292 int stack_size = (td)->sp - (td)->stack; \
293 if (stack_size < (n)) \
294 g_warning ("%s.%s: not enough values (%d < %d) on stack at %04x", \
295 m_class_get_name ((td)->method->klass), (td)->method->name, \
296 stack_size, n, (td)->ip - (td)->il_code); \
299 #define ENSURE_I4(td, sp_off) \
301 if ((td)->sp [-sp_off].type == STACK_TYPE_I8) \
302 ADD_CODE(td, sp_off == 1 ? MINT_CONV_I4_I8 : MINT_CONV_I4_I8_SP); \
305 #define CHECK_TYPELOAD(klass) \
307 if (!(klass) || mono_class_has_failure (klass)) { \
308 mono_error_set_for_class_failure (error, klass); \
315 handle_branch (TransformData
*td
, int short_op
, int long_op
, int offset
)
317 int shorten_branch
= 0;
318 int target
= td
->ip
+ offset
- td
->il_code
;
319 if (target
< 0 || target
>= td
->code_size
)
320 g_assert_not_reached ();
321 /* Add exception checkpoint or safepoint for backward branches */
323 if (mono_threads_are_safepoints_enabled ())
324 ADD_CODE (td
, MINT_SAFEPOINT
);
326 ADD_CODE (td
, MINT_CHECKPOINT
);
328 if (offset
> 0 && td
->stack_height
[target
] < 0) {
329 td
->stack_height
[target
] = td
->sp
- td
->stack
;
330 if (td
->stack_height
[target
] > 0)
331 td
->stack_state
[target
] = (StackInfo
*)g_memdup (td
->stack
, td
->stack_height
[target
] * sizeof (td
->stack
[0]));
332 td
->vt_stack_size
[target
] = td
->vt_sp
;
335 offset
= td
->in_offsets
[target
] - (td
->new_ip
- td
->new_code
);
336 if (offset
>= -32768) {
340 if (td
->header
->code_size
<= 25000) /* FIX to be precise somehow? */
343 Reloc
*reloc
= (Reloc
*)mono_mempool_alloc0 (td
->mempool
, sizeof (Reloc
));
344 if (shorten_branch
) {
346 reloc
->type
= RELOC_SHORT_BRANCH
;
349 reloc
->type
= RELOC_LONG_BRANCH
;
351 reloc
->offset
= td
->new_ip
- td
->new_code
;
352 reloc
->target
= target
;
353 g_ptr_array_add (td
->relocs
, reloc
);
355 if (shorten_branch
) {
356 ADD_CODE(td
, short_op
);
357 ADD_CODE(td
, offset
);
359 ADD_CODE(td
, long_op
);
360 ADD_CODE(td
, * (unsigned short *)(&offset
));
361 ADD_CODE(td
, * ((unsigned short *)&offset
+ 1));
366 one_arg_branch(TransformData
*td
, int mint_op
, int offset
)
368 int type
= td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
? STACK_TYPE_I
: td
->sp
[-1].type
;
369 int long_op
= mint_op
+ type
- STACK_TYPE_I4
;
370 int short_op
= long_op
+ MINT_BRFALSE_I4_S
- MINT_BRFALSE_I4
;
373 handle_branch (td
, short_op
, long_op
, offset
);
377 two_arg_branch(TransformData
*td
, int mint_op
, int offset
)
379 int type1
= td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
? STACK_TYPE_I
: td
->sp
[-1].type
;
380 int type2
= td
->sp
[-2].type
== STACK_TYPE_O
|| td
->sp
[-2].type
== STACK_TYPE_MP
? STACK_TYPE_I
: td
->sp
[-2].type
;
381 int long_op
= mint_op
+ type1
- STACK_TYPE_I4
;
382 int short_op
= long_op
+ MINT_BEQ_I4_S
- MINT_BEQ_I4
;
384 if (type1
== STACK_TYPE_I4
&& type2
== STACK_TYPE_I8
) {
385 ADD_CODE(td
, MINT_CONV_I8_I4
);
386 td
->in_offsets
[td
->ip
- td
->il_code
]++;
387 } else if (type1
== STACK_TYPE_I8
&& type2
== STACK_TYPE_I4
) {
388 ADD_CODE(td
, MINT_CONV_I8_I4_SP
);
389 td
->in_offsets
[td
->ip
- td
->il_code
]++;
390 } else if (type1
== STACK_TYPE_R4
&& type2
== STACK_TYPE_R8
) {
391 ADD_CODE (td
, MINT_CONV_R8_R4
);
392 td
->in_offsets
[td
->ip
- td
->il_code
]++;
393 } else if (type1
== STACK_TYPE_R8
&& type2
== STACK_TYPE_R4
) {
394 ADD_CODE (td
, MINT_CONV_R8_R4_SP
);
395 td
->in_offsets
[td
->ip
- td
->il_code
]++;
396 } else if (type1
!= type2
) {
397 g_warning("%s.%s: branch type mismatch %d %d",
398 m_class_get_name (td
->method
->klass
), td
->method
->name
,
399 td
->sp
[-1].type
, td
->sp
[-2].type
);
402 handle_branch (td
, short_op
, long_op
, offset
);
406 unary_arith_op(TransformData
*td
, int mint_op
)
408 int op
= mint_op
+ td
->sp
[-1].type
- STACK_TYPE_I4
;
414 binary_arith_op(TransformData
*td
, int mint_op
)
416 int type1
= td
->sp
[-2].type
;
417 int type2
= td
->sp
[-1].type
;
419 #if SIZEOF_VOID_P == 8
420 if ((type1
== STACK_TYPE_MP
|| type1
== STACK_TYPE_I8
) && type2
== STACK_TYPE_I4
) {
421 ADD_CODE(td
, MINT_CONV_I8_I4
);
422 type2
= STACK_TYPE_I8
;
424 if (type1
== STACK_TYPE_I4
&& (type2
== STACK_TYPE_MP
|| type2
== STACK_TYPE_I8
)) {
425 ADD_CODE(td
, MINT_CONV_I8_I4_SP
);
426 type1
= STACK_TYPE_I8
;
427 td
->sp
[-2].type
= STACK_TYPE_I8
;
430 if (type1
== STACK_TYPE_R8
&& type2
== STACK_TYPE_R4
) {
431 ADD_CODE (td
, MINT_CONV_R8_R4
);
432 type2
= STACK_TYPE_R8
;
434 if (type1
== STACK_TYPE_R4
&& type2
== STACK_TYPE_R8
) {
435 ADD_CODE (td
, MINT_CONV_R8_R4_SP
);
436 type1
= STACK_TYPE_R8
;
437 td
->sp
[-2].type
= STACK_TYPE_R8
;
439 if (type1
== STACK_TYPE_MP
)
440 type1
= STACK_TYPE_I
;
441 if (type2
== STACK_TYPE_MP
)
442 type2
= STACK_TYPE_I
;
443 if (type1
!= type2
) {
444 g_warning("%s.%s: %04x arith type mismatch %s %d %d",
445 m_class_get_name (td
->method
->klass
), td
->method
->name
,
446 td
->ip
- td
->il_code
, mono_interp_opname
[mint_op
], type1
, type2
);
448 op
= mint_op
+ type1
- STACK_TYPE_I4
;
455 shift_op(TransformData
*td
, int mint_op
)
457 int op
= mint_op
+ td
->sp
[-2].type
- STACK_TYPE_I4
;
459 if (td
->sp
[-1].type
!= STACK_TYPE_I4
) {
460 g_warning("%s.%s: shift type mismatch %d",
461 m_class_get_name (td
->method
->klass
), td
->method
->name
,
469 can_store (int stack_type
, int var_type
)
471 if (stack_type
== STACK_TYPE_O
|| stack_type
== STACK_TYPE_MP
)
472 stack_type
= STACK_TYPE_I
;
473 if (var_type
== STACK_TYPE_O
|| var_type
== STACK_TYPE_MP
)
474 var_type
= STACK_TYPE_I
;
475 return stack_type
== var_type
;
478 #define SET_SIMPLE_TYPE(s, ty) \
485 #define SET_TYPE(s, ty, k) \
492 #define REALLOC_STACK(td, sppos) \
494 (td)->stack_capacity *= 2; \
495 (td)->stack = (StackInfo*)realloc ((td)->stack, (td)->stack_capacity * sizeof (td->stack [0])); \
496 (td)->sp = (td)->stack + sppos; \
499 #define PUSH_SIMPLE_TYPE(td, ty) \
503 sp_height = (td)->sp - (td)->stack; \
504 if (sp_height > (td)->max_stack_height) \
505 (td)->max_stack_height = sp_height; \
506 if (sp_height > (td)->stack_capacity) \
507 REALLOC_STACK(td, sp_height); \
508 SET_SIMPLE_TYPE((td)->sp - 1, ty); \
511 #define PUSH_TYPE(td, ty, k) \
515 sp_height = (td)->sp - (td)->stack; \
516 if (sp_height > (td)->max_stack_height) \
517 (td)->max_stack_height = sp_height; \
518 if (sp_height > (td)->stack_capacity) \
519 REALLOC_STACK(td, sp_height); \
520 SET_TYPE((td)->sp - 1, ty, k); \
523 #define PUSH_VT(td, size) \
525 (td)->vt_sp += ALIGN_TO ((size), MINT_VT_ALIGNMENT); \
526 if ((td)->vt_sp > (td)->max_vt_sp) \
527 (td)->max_vt_sp = (td)->vt_sp; \
530 #define POP_VT(td, size) \
532 (td)->vt_sp -= ALIGN_TO ((size), MINT_VT_ALIGNMENT); \
535 #if NO_UNALIGNED_ACCESS
536 #define WRITE32(td, v) \
538 ENSURE_CODE(td, 2); \
539 * (guint16 *)((td)->new_ip) = * (guint16 *)(v); \
540 * ((guint16 *)((td)->new_ip) + 1) = * ((guint16 *)(v) + 1); \
544 #define WRITE64(td, v) \
546 ENSURE_CODE(td, 4); \
547 * (guint16 *)((td)->new_ip) = * (guint16 *)(v); \
548 * ((guint16 *)((td)->new_ip) + 1) = * ((guint16 *)(v) + 1); \
549 * ((guint16 *)((td)->new_ip) + 2) = * ((guint16 *)(v) + 2); \
550 * ((guint16 *)((td)->new_ip) + 3) = * ((guint16 *)(v) + 3); \
554 #define WRITE32(td, v) \
556 ENSURE_CODE(td, 2); \
557 * (guint32 *)((td)->new_ip) = * (guint32 *)(v); \
561 #define WRITE64(td, v) \
563 ENSURE_CODE(td, 4); \
564 * (guint64 *)((td)->new_ip) = * (guint64 *)(v); \
571 load_arg(TransformData
*td
, int n
)
574 MonoClass
*klass
= NULL
;
577 gboolean hasthis
= mono_method_signature_internal (td
->method
)->hasthis
;
578 if (hasthis
&& n
== 0)
579 type
= m_class_get_byval_arg (td
->method
->klass
);
581 type
= mono_method_signature_internal (td
->method
)->params
[hasthis
? n
- 1 : n
];
583 mt
= mint_type (type
);
584 if (mt
== MINT_TYPE_VT
) {
586 klass
= mono_class_from_mono_type_internal (type
);
587 if (mono_method_signature_internal (td
->method
)->pinvoke
)
588 size
= mono_class_native_size (klass
, NULL
);
590 size
= mono_class_value_size (klass
, NULL
);
592 if (hasthis
&& n
== 0) {
594 ADD_CODE (td
, MINT_LDARG_P
);
595 ADD_CODE (td
, td
->rtm
->arg_offsets
[n
]); /* FIX for large offset */
599 ADD_CODE (td
, MINT_LDARG_VT
);
600 ADD_CODE (td
, td
->rtm
->arg_offsets
[n
]); /* FIX for large offset */
604 if (hasthis
&& n
== 0) {
606 ADD_CODE (td
, MINT_LDARG_P
);
607 ADD_CODE (td
, td
->rtm
->arg_offsets
[n
]); /* FIX for large offset */
610 ADD_CODE(td
, MINT_LDARG_I1
+ (mt
- MINT_TYPE_I1
));
611 ADD_CODE(td
, td
->rtm
->arg_offsets
[n
]); /* FIX for large offset */
612 if (mt
== MINT_TYPE_O
)
613 klass
= mono_class_from_mono_type_internal (type
);
616 PUSH_TYPE(td
, stack_type
[mt
], klass
);
620 store_arg(TransformData
*td
, int n
)
626 gboolean hasthis
= mono_method_signature_internal (td
->method
)->hasthis
;
627 if (hasthis
&& n
== 0)
628 type
= m_class_get_byval_arg (td
->method
->klass
);
630 type
= mono_method_signature_internal (td
->method
)->params
[n
- !!hasthis
];
632 mt
= mint_type (type
);
633 if (mt
== MINT_TYPE_VT
) {
635 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
636 if (mono_method_signature_internal (td
->method
)->pinvoke
)
637 size
= mono_class_native_size (klass
, NULL
);
639 size
= mono_class_value_size (klass
, NULL
);
640 ADD_CODE(td
, MINT_STARG_VT
);
641 ADD_CODE(td
, td
->rtm
->arg_offsets
[n
]);
643 if (td
->sp
[-1].type
== STACK_TYPE_VT
)
646 ADD_CODE(td
, MINT_STARG_I1
+ (mt
- MINT_TYPE_I1
));
647 ADD_CODE(td
, td
->rtm
->arg_offsets
[n
]);
653 store_inarg(TransformData
*td
, int n
)
656 gboolean hasthis
= mono_method_signature_internal (td
->method
)->hasthis
;
657 if (hasthis
&& n
== 0)
658 type
= m_class_get_byval_arg (td
->method
->klass
);
660 type
= mono_method_signature_internal (td
->method
)->params
[n
- !!hasthis
];
662 int mt
= mint_type (type
);
663 if (hasthis
&& n
== 0) {
664 ADD_CODE (td
, MINT_STINARG_P
);
668 if (mt
== MINT_TYPE_VT
) {
669 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
671 if (mono_method_signature_internal (td
->method
)->pinvoke
)
672 size
= mono_class_native_size (klass
, NULL
);
674 size
= mono_class_value_size (klass
, NULL
);
675 ADD_CODE(td
, MINT_STINARG_VT
);
679 ADD_CODE(td
, MINT_STINARG_I1
+ (mt
- MINT_TYPE_I1
));
685 load_local(TransformData
*td
, int n
)
687 MonoType
*type
= td
->header
->locals
[n
];
688 int mt
= mint_type (type
);
689 int offset
= td
->rtm
->local_offsets
[n
];
690 MonoClass
*klass
= NULL
;
691 if (mt
== MINT_TYPE_VT
) {
692 klass
= mono_class_from_mono_type_internal (type
);
693 gint32 size
= mono_class_value_size (klass
, NULL
);
695 ADD_CODE(td
, MINT_LDLOC_VT
);
696 ADD_CODE(td
, offset
); /*FIX for large offset */
699 g_assert (mt
< MINT_TYPE_VT
);
700 if (!td
->gen_sdb_seq_points
&&
701 mt
== MINT_TYPE_I4
&& !td
->is_bb_start
[td
->in_start
- td
->il_code
] && td
->last_new_ip
!= NULL
&&
702 td
->last_new_ip
[0] == MINT_STLOC_I4
&& td
->last_new_ip
[1] == offset
) {
703 td
->last_new_ip
[0] = MINT_STLOC_NP_I4
;
704 } else if (!td
->gen_sdb_seq_points
&&
705 mt
== MINT_TYPE_O
&& !td
->is_bb_start
[td
->in_start
- td
->il_code
] && td
->last_new_ip
!= NULL
&&
706 td
->last_new_ip
[0] == MINT_STLOC_O
&& td
->last_new_ip
[1] == offset
) {
707 td
->last_new_ip
[0] = MINT_STLOC_NP_O
;
709 ADD_CODE(td
, MINT_LDLOC_I1
+ (mt
- MINT_TYPE_I1
));
710 ADD_CODE(td
, offset
); /*FIX for large offset */
712 if (mt
== MINT_TYPE_O
)
713 klass
= mono_class_from_mono_type_internal (type
);
715 PUSH_TYPE(td
, stack_type
[mt
], klass
);
719 store_local_general (TransformData
*td
, int offset
, MonoType
*type
)
721 int mt
= mint_type (type
);
723 #if SIZEOF_VOID_P == 8
724 if (td
->sp
[-1].type
== STACK_TYPE_I4
&& stack_type
[mt
] == STACK_TYPE_I8
) {
725 ADD_CODE(td
, MINT_CONV_I8_I4
);
726 td
->sp
[-1].type
= STACK_TYPE_I8
;
729 if (!can_store(td
->sp
[-1].type
, stack_type
[mt
])) {
730 g_warning("%s.%s: Store local stack type mismatch %d %d",
731 m_class_get_name (td
->method
->klass
), td
->method
->name
,
732 stack_type
[mt
], td
->sp
[-1].type
);
734 if (mt
== MINT_TYPE_VT
) {
735 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
736 gint32 size
= mono_class_value_size (klass
, NULL
);
737 ADD_CODE(td
, MINT_STLOC_VT
);
738 ADD_CODE(td
, offset
); /*FIX for large offset */
740 if (td
->sp
[-1].type
== STACK_TYPE_VT
)
743 g_assert (mt
< MINT_TYPE_VT
);
744 ADD_CODE(td
, MINT_STLOC_I1
+ (mt
- MINT_TYPE_I1
));
745 ADD_CODE(td
, offset
); /*FIX for large offset */
751 store_local (TransformData
*td
, int n
)
753 MonoType
*type
= td
->header
->locals
[n
];
754 int offset
= td
->rtm
->local_offsets
[n
];
755 store_local_general (td
, offset
, type
);
758 #define SIMPLE_OP(td, op) \
765 get_data_item_index (TransformData
*td
, void *ptr
)
767 gpointer p
= g_hash_table_lookup (td
->data_hash
, ptr
);
770 return GPOINTER_TO_UINT (p
) - 1;
771 if (td
->max_data_items
== td
->n_data_items
) {
772 td
->max_data_items
= td
->n_data_items
== 0 ? 16 : 2 * td
->max_data_items
;
773 td
->data_items
= (gpointer
*)g_realloc (td
->data_items
, td
->max_data_items
* sizeof(td
->data_items
[0]));
775 index
= td
->n_data_items
;
776 td
->data_items
[index
] = ptr
;
778 g_hash_table_insert (td
->data_hash
, ptr
, GUINT_TO_POINTER (index
+ 1));
783 jit_call_supported (MonoMethod
*method
, MonoMethodSignature
*sig
)
787 if (sig
->param_count
> 6)
791 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
793 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
)
795 if (method
->is_inflated
)
797 if (method
->string_ctor
)
800 if (mono_aot_only
&& m_class_get_image (method
->klass
)->aot_module
) {
802 gpointer addr
= mono_jit_compile_method_jit_only (method
, error
);
803 if (addr
&& mono_error_ok (error
))
807 for (l
= mono_interp_jit_classes
; l
; l
= l
->next
) {
808 const char *class_name
= (const char*)l
->data
;
810 if (!strcmp (m_class_get_name (method
->klass
), class_name
))
818 static int mono_class_get_magic_index (MonoClass
*k
)
820 if (mono_class_is_magic_int (k
))
821 return !strcmp ("nint", m_class_get_name (k
)) ? 0 : 1;
823 if (mono_class_is_magic_float (k
))
830 interp_generate_mae_throw (TransformData
*td
, MonoMethod
*method
, MonoMethod
*target_method
)
832 MonoJitICallInfo
*info
= mono_find_jit_icall_by_name ("mono_throw_method_access");
834 /* Inject code throwing MethodAccessException */
835 ADD_CODE (td
, MINT_MONO_LDPTR
);
836 ADD_CODE (td
, get_data_item_index (td
, method
));
837 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
839 ADD_CODE (td
, MINT_MONO_LDPTR
);
840 ADD_CODE (td
, get_data_item_index (td
, target_method
));
841 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
843 ADD_CODE (td
, MINT_ICALL_PP_V
);
844 ADD_CODE (td
, get_data_item_index (td
, (gpointer
)info
->func
));
850 * These are additional locals that can be allocated as we transform the code.
851 * They are allocated past the method locals so they are accessed in the same
852 * way, with an offset relative to the frame->locals.
855 create_interp_local (TransformData
*td
, MonoType
*type
)
858 int offset
= td
->total_locals_size
;
860 size
= mono_type_size (type
, &align
);
861 offset
= ALIGN_TO (offset
, align
);
863 td
->total_locals_size
= offset
+ size
;
869 dump_mint_code (TransformData
*td
)
871 const guint16
*p
= td
->new_code
;
872 while (p
< td
->new_ip
) {
873 char *ins
= mono_interp_dis_mintop (td
->new_code
, p
);
874 g_print ("%s\n", ins
);
876 p
= mono_interp_dis_mintop_len (p
);
880 static MonoMethodHeader
*
881 interp_method_get_header (MonoMethod
* method
, MonoError
*error
)
883 /* An explanation: mono_method_get_header_internal returns an error if
884 * called on a method with no body (e.g. an abstract method, or an
885 * icall). We don't want that.
887 if (mono_method_has_no_body (method
))
890 return mono_method_get_header_internal (method
, error
);
893 /* stores top of stack as local and pushes address of it on stack */
895 emit_store_value_as_local (TransformData
*td
, MonoType
*src
)
897 int size
= mini_magic_type_size (NULL
, src
);
898 int local_offset
= create_interp_local (td
, mini_native_type_replace_type (src
));
900 store_local_general (td
, local_offset
, src
);
902 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
903 ADD_CODE (td
, MINT_LDLOC_VT
);
904 ADD_CODE (td
, local_offset
);
908 PUSH_TYPE (td
, STACK_TYPE_VT
, NULL
);
911 /* Return TRUE if call transformation is finished */
913 interp_handle_intrinsics (TransformData
*td
, MonoMethod
*target_method
, MonoMethodSignature
*csignature
, gboolean readonly
, int *op
)
915 const char *tm
= target_method
->name
;
917 int type_index
= mono_class_get_magic_index (target_method
->klass
);
918 gboolean in_corlib
= m_class_get_image (target_method
->klass
) == mono_defaults
.corlib
;
919 const char *klass_name_space
= m_class_get_name_space (target_method
->klass
);
920 const char *klass_name
= m_class_get_name (target_method
->klass
);
922 if (target_method
->klass
== mono_defaults
.string_class
) {
924 if (strcmp (tm
, "get_Chars") == 0)
926 else if (strcmp (tm
, "get_Length") == 0)
929 } else if (type_index
>= 0) {
930 MonoClass
*magic_class
= target_method
->klass
;
932 const int mt
= mint_type (m_class_get_byval_arg (magic_class
));
933 if (!strcmp (".ctor", tm
)) {
934 MonoType
*arg
= csignature
->params
[0];
935 /* depending on SIZEOF_VOID_P and the type of the value passed to the .ctor we either have to CONV it, or do nothing */
936 int arg_size
= mini_magic_type_size (NULL
, arg
);
938 if (arg_size
> SIZEOF_VOID_P
) { // 8 -> 4
939 switch (type_index
) {
941 ADD_CODE (td
, MINT_CONV_I4_I8
);
944 ADD_CODE (td
, MINT_CONV_R4_R8
);
949 if (arg_size
< SIZEOF_VOID_P
) { // 4 -> 8
950 switch (type_index
) {
952 ADD_CODE (td
, MINT_CONV_I8_I4
);
955 ADD_CODE (td
, MINT_CONV_I8_U4
);
958 ADD_CODE (td
, MINT_CONV_R8_R4
);
963 switch (type_index
) {
965 #if SIZEOF_VOID_P == 4
966 ADD_CODE (td
, MINT_STIND_I4
);
968 ADD_CODE (td
, MINT_STIND_I8
);
972 #if SIZEOF_VOID_P == 4
973 ADD_CODE (td
, MINT_STIND_R4
);
975 ADD_CODE (td
, MINT_STIND_R8
);
983 } else if (!strcmp ("op_Implicit", tm
) || !strcmp ("op_Explicit", tm
)) {
984 MonoType
*src
= csignature
->params
[0];
985 MonoType
*dst
= csignature
->ret
;
986 int src_size
= mini_magic_type_size (NULL
, src
);
987 int dst_size
= mini_magic_type_size (NULL
, dst
);
989 gboolean store_value_as_local
= FALSE
;
991 switch (type_index
) {
993 if (!mini_magic_is_int_type (src
) || !mini_magic_is_int_type (dst
)) {
994 if (mini_magic_is_int_type (src
))
995 store_value_as_local
= TRUE
;
1001 if (!mini_magic_is_float_type (src
) || !mini_magic_is_float_type (dst
)) {
1002 if (mini_magic_is_float_type (src
))
1003 store_value_as_local
= TRUE
;
1010 if (store_value_as_local
) {
1011 emit_store_value_as_local (td
, src
);
1013 /* emit call to managed conversion method */
1017 #if SIZEOF_VOID_P == 4
1018 if (src_size
> dst_size
) { // 8 -> 4
1019 switch (type_index
) {
1021 ADD_CODE (td
, MINT_CONV_I4_I8
);
1024 ADD_CODE (td
, MINT_CONV_R4_R8
);
1030 #if SIZEOF_VOID_P == 8
1031 if (src_size
< dst_size
) { // 4 -> 8
1032 switch (type_index
) {
1034 ADD_CODE (td
, MINT_CONV_I8_I4
);
1037 ADD_CODE (td
, MINT_CONV_I8_U4
);
1040 ADD_CODE (td
, MINT_CONV_R8_R4
);
1046 SET_TYPE (td
->sp
- 1, stack_type
[mt
], magic_class
);
1049 } else if (!strcmp ("op_Increment", tm
)) {
1050 g_assert (type_index
!= 2); // no nfloat
1051 #if SIZEOF_VOID_P == 8
1052 ADD_CODE (td
, MINT_ADD1_I8
);
1054 ADD_CODE (td
, MINT_ADD1_I4
);
1056 SET_TYPE (td
->sp
- 1, stack_type
[mt
], magic_class
);
1059 } else if (!strcmp ("op_Decrement", tm
)) {
1060 g_assert (type_index
!= 2); // no nfloat
1061 #if SIZEOF_VOID_P == 8
1062 ADD_CODE (td
, MINT_SUB1_I8
);
1064 ADD_CODE (td
, MINT_SUB1_I4
);
1066 SET_TYPE (td
->sp
- 1, stack_type
[mt
], magic_class
);
1069 } else if (!strcmp ("CompareTo", tm
) || !strcmp ("Equals", tm
)) {
1070 MonoType
*arg
= csignature
->params
[0];
1072 /* on 'System.n*::{CompareTo,Equals} (System.n*)' variant we need to push managed
1073 * pointer instead of value */
1074 if (arg
->type
== MONO_TYPE_VALUETYPE
)
1075 emit_store_value_as_local (td
, arg
);
1077 /* emit call to managed conversion method */
1079 } else if (!strcmp (".cctor", tm
)) {
1082 } else if (!strcmp ("Parse", tm
)) {
1085 } else if (!strcmp ("ToString", tm
)) {
1088 } else if (!strcmp ("IsNaN", tm
) || !strcmp ("IsInfinity", tm
) || !strcmp ("IsNegativeInfinity", tm
) || !strcmp ("IsPositiveInfinity", tm
)) {
1089 g_assert (type_index
== 2); // nfloat only
1094 for (i
= 0; i
< sizeof (int_unnop
) / sizeof (MagicIntrinsic
); ++i
) {
1095 if (!strcmp (int_unnop
[i
].op_name
, tm
)) {
1096 ADD_CODE (td
, int_unnop
[i
].insn
[type_index
]);
1097 SET_TYPE (td
->sp
- 1, stack_type
[mt
], magic_class
);
1103 for (i
= 0; i
< sizeof (int_binop
) / sizeof (MagicIntrinsic
); ++i
) {
1104 if (!strcmp (int_binop
[i
].op_name
, tm
)) {
1105 ADD_CODE (td
, int_binop
[i
].insn
[type_index
]);
1107 SET_TYPE (td
->sp
- 1, stack_type
[mt
], magic_class
);
1113 for (i
= 0; i
< sizeof (int_cmpop
) / sizeof (MagicIntrinsic
); ++i
) {
1114 if (!strcmp (int_cmpop
[i
].op_name
, tm
)) {
1115 MonoClass
*k
= mono_defaults
.boolean_class
;
1116 ADD_CODE (td
, int_cmpop
[i
].insn
[type_index
]);
1118 SET_TYPE (td
->sp
- 1, stack_type
[mint_type (m_class_get_byval_arg (k
))], k
);
1124 g_error ("TODO: interp_transform_call %s:%s", m_class_get_name (target_method
->klass
), tm
);
1125 } else if (mono_class_is_subclass_of (target_method
->klass
, mono_defaults
.array_class
, FALSE
)) {
1126 if (!strcmp (tm
, "get_Rank")) {
1127 *op
= MINT_ARRAY_RANK
;
1128 } else if (!strcmp (tm
, "get_Length")) {
1130 } else if (!strcmp (tm
, "Address")) {
1131 *op
= readonly
? MINT_LDELEMA
: MINT_LDELEMA_TC
;
1132 } else if (!strcmp (tm
, "UnsafeMov") || !strcmp (tm
, "UnsafeLoad") || !strcmp (tm
, "Set") || !strcmp (tm
, "Get")) {
1134 } else if (!strcmp (tm
, "UnsafeStore")) {
1135 g_error ("TODO ArrayClass::UnsafeStore");
1137 } else if (in_corlib
&&
1138 !strcmp (klass_name_space
, "System.Diagnostics") &&
1139 !strcmp (klass_name
, "Debugger")) {
1140 if (!strcmp (tm
, "Break") && csignature
->param_count
== 0) {
1141 if (mini_should_insert_breakpoint (td
->method
))
1144 } else if (in_corlib
&& !strcmp (klass_name_space
, "System") && !strcmp (klass_name
, "ByReference`1")) {
1145 *op
= MINT_INTRINS_BYREFERENCE_GET_VALUE
;
1146 } else if (in_corlib
&& !strcmp (klass_name_space
, "System") && (!strcmp (klass_name
, "Span`1") || !strcmp (klass_name
, "ReadOnlySpan`1"))) {
1147 if (!strcmp (tm
, "get_Item")) {
1148 MonoGenericClass
*gclass
= mono_class_get_generic_class (target_method
->klass
);
1149 MonoClass
*param_class
= mono_class_from_mono_type_internal (gclass
->context
.class_inst
->type_argv
[0]);
1151 if (!mini_is_gsharedvt_variable_klass (param_class
)) {
1152 MonoClassField
*length_field
= mono_class_get_field_from_name_full (target_method
->klass
, "_length", NULL
);
1153 g_assert (length_field
);
1154 int offset_length
= length_field
->offset
- sizeof (MonoObject
);
1156 MonoClassField
*ptr_field
= mono_class_get_field_from_name_full (target_method
->klass
, "_pointer", NULL
);
1157 g_assert (ptr_field
);
1158 int offset_pointer
= ptr_field
->offset
- sizeof (MonoObject
);
1160 int size
= mono_class_array_element_size (param_class
);
1161 ADD_CODE (td
, MINT_GETITEM_SPAN
);
1162 ADD_CODE (td
, size
);
1163 ADD_CODE (td
, offset_length
);
1164 ADD_CODE (td
, offset_pointer
);
1166 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_MP
);
1171 } else if (!strcmp (tm
, "get_Length")) {
1172 MonoClassField
*length_field
= mono_class_get_field_from_name_full (target_method
->klass
, "_length", NULL
);
1173 g_assert (length_field
);
1174 int offset_length
= length_field
->offset
- sizeof (MonoObject
);
1175 ADD_CODE (td
, MINT_LDLEN_SPAN
);
1176 ADD_CODE (td
, offset_length
);
1177 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I4
);
1186 interp_transform_internal_calls (MonoMethod
*method
, MonoMethod
*target_method
, MonoMethodSignature
*csignature
, gboolean is_virtual
)
1188 if (method
->wrapper_type
== MONO_WRAPPER_NONE
&& target_method
!= NULL
) {
1189 if (target_method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
1190 target_method
= mono_marshal_get_native_wrapper (target_method
, FALSE
, FALSE
);
1191 if (!is_virtual
&& target_method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)
1192 target_method
= mono_marshal_get_synchronized_wrapper (target_method
);
1194 if (target_method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
&& !is_virtual
&& !mono_class_is_marshalbyref (target_method
->klass
) && m_class_get_rank (target_method
->klass
) == 0)
1195 target_method
= mono_marshal_get_native_wrapper (target_method
, TRUE
, FALSE
);
1197 return target_method
;
1201 interp_type_as_ptr (MonoType
*tp
)
1203 if (MONO_TYPE_IS_POINTER (tp
))
1205 if (MONO_TYPE_IS_REFERENCE (tp
))
1207 if ((tp
)->type
== MONO_TYPE_I4
)
1209 #if SIZEOF_VOID_P == 8
1210 if ((tp
)->type
== MONO_TYPE_I8
)
1213 if ((tp
)->type
== MONO_TYPE_BOOLEAN
)
1215 if ((tp
)->type
== MONO_TYPE_CHAR
)
1217 if ((tp
)->type
== MONO_TYPE_VALUETYPE
&& m_class_is_enumtype (tp
->data
.klass
))
1222 #define INTERP_TYPE_AS_PTR(tp) interp_type_as_ptr (tp)
1225 interp_icall_op_for_sig (MonoMethodSignature
*sig
)
1228 switch (sig
->param_count
) {
1230 if (MONO_TYPE_IS_VOID (sig
->ret
))
1231 op
= MINT_ICALL_V_V
;
1232 else if (INTERP_TYPE_AS_PTR (sig
->ret
))
1233 op
= MINT_ICALL_V_P
;
1236 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1237 if (INTERP_TYPE_AS_PTR (sig
->params
[0]))
1238 op
= MINT_ICALL_P_V
;
1239 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1240 if (INTERP_TYPE_AS_PTR (sig
->params
[0]))
1241 op
= MINT_ICALL_P_P
;
1245 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1246 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1247 INTERP_TYPE_AS_PTR (sig
->params
[1]))
1248 op
= MINT_ICALL_PP_V
;
1249 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1250 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1251 INTERP_TYPE_AS_PTR (sig
->params
[1]))
1252 op
= MINT_ICALL_PP_P
;
1256 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1257 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1258 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1259 INTERP_TYPE_AS_PTR (sig
->params
[2]))
1260 op
= MINT_ICALL_PPP_V
;
1261 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1262 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1263 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1264 INTERP_TYPE_AS_PTR (sig
->params
[2]))
1265 op
= MINT_ICALL_PPP_P
;
1269 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1270 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1271 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1272 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1273 INTERP_TYPE_AS_PTR (sig
->params
[3]))
1274 op
= MINT_ICALL_PPPP_V
;
1275 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1276 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1277 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1278 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1279 INTERP_TYPE_AS_PTR (sig
->params
[3]))
1280 op
= MINT_ICALL_PPPP_P
;
1284 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1285 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1286 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1287 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1288 INTERP_TYPE_AS_PTR (sig
->params
[3]) &&
1289 INTERP_TYPE_AS_PTR (sig
->params
[4]))
1290 op
= MINT_ICALL_PPPPP_V
;
1291 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1292 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1293 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1294 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1295 INTERP_TYPE_AS_PTR (sig
->params
[3]) &&
1296 INTERP_TYPE_AS_PTR (sig
->params
[4]))
1297 op
= MINT_ICALL_PPPPP_P
;
1301 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1302 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1303 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1304 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1305 INTERP_TYPE_AS_PTR (sig
->params
[3]) &&
1306 INTERP_TYPE_AS_PTR (sig
->params
[4]) &&
1307 INTERP_TYPE_AS_PTR (sig
->params
[5]))
1308 op
= MINT_ICALL_PPPPPP_V
;
1309 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1310 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1311 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1312 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1313 INTERP_TYPE_AS_PTR (sig
->params
[3]) &&
1314 INTERP_TYPE_AS_PTR (sig
->params
[4]) &&
1315 INTERP_TYPE_AS_PTR (sig
->params
[5]))
1316 op
= MINT_ICALL_PPPPPP_P
;
1324 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
, MonoError
*error
, gboolean check_visibility
)
1326 MonoImage
*image
= m_class_get_image (method
->klass
);
1327 MonoMethodSignature
*csignature
;
1328 int is_virtual
= *td
->ip
== CEE_CALLVIRT
;
1329 int calli
= *td
->ip
== CEE_CALLI
|| *td
->ip
== CEE_MONO_CALLI_EXTRA_ARG
;
1331 guint32 vt_stack_used
= 0;
1332 guint32 vt_res_size
= 0;
1336 int need_null_check
= is_virtual
;
1338 guint32 token
= read32 (td
->ip
+ 1);
1340 if (target_method
== NULL
) {
1343 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
1344 csignature
= (MonoMethodSignature
*)mono_method_get_wrapper_data (method
, token
);
1346 csignature
= mono_metadata_parse_signature_checked (image
, token
, error
);
1347 return_if_nok (error
);
1350 if (generic_context
) {
1351 csignature
= mono_inflate_generic_signature (csignature
, generic_context
, error
);
1352 return_if_nok (error
);
1356 * The compiled interp entry wrapper is passed to runtime_invoke instead of
1357 * the InterpMethod pointer. FIXME
1359 native
= csignature
->pinvoke
|| method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
;
1362 target_method
= NULL
;
1364 if (method
->wrapper_type
== MONO_WRAPPER_NONE
) {
1365 target_method
= mono_get_method_checked (image
, token
, NULL
, generic_context
, error
);
1366 return_if_nok (error
);
1368 target_method
= (MonoMethod
*)mono_method_get_wrapper_data (method
, token
);
1369 csignature
= mono_method_signature_internal (target_method
);
1371 if (generic_context
) {
1372 csignature
= mono_inflate_generic_signature (csignature
, generic_context
, error
);
1373 return_if_nok (error
);
1374 target_method
= mono_class_inflate_generic_method_checked (target_method
, generic_context
, error
);
1375 return_if_nok (error
);
1379 csignature
= mono_method_signature_internal (target_method
);
1382 if (check_visibility
&& target_method
&& !mono_method_can_access_method (method
, target_method
))
1383 interp_generate_mae_throw (td
, method
, target_method
);
1385 if (target_method
&& target_method
->string_ctor
) {
1386 /* Create the real signature */
1387 MonoMethodSignature
*ctor_sig
= mono_metadata_signature_dup_mempool (td
->mempool
, csignature
);
1388 ctor_sig
->ret
= m_class_get_byval_arg (mono_defaults
.string_class
);
1390 csignature
= ctor_sig
;
1394 if (target_method
&& interp_handle_intrinsics (td
, target_method
, csignature
, readonly
, &op
))
1397 if (constrained_class
) {
1398 if (m_class_is_enumtype (constrained_class
) && !strcmp (target_method
->name
, "GetHashCode")) {
1399 /* Use the corresponding method from the base type to avoid boxing */
1400 MonoType
*base_type
= mono_class_enum_basetype_internal (constrained_class
);
1401 g_assert (base_type
);
1402 constrained_class
= mono_class_from_mono_type_internal (base_type
);
1403 target_method
= mono_class_get_method_from_name_checked (constrained_class
, target_method
->name
, 0, 0, error
);
1404 mono_error_assert_ok (error
);
1405 g_assert (target_method
);
1409 if (constrained_class
) {
1410 mono_class_setup_vtable (constrained_class
);
1411 if (mono_class_has_failure (constrained_class
)) {
1412 mono_error_set_for_class_failure (error
, constrained_class
);
1416 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
);
1418 target_method
= mono_get_method_constrained_with_method (image
, target_method
, constrained_class
, generic_context
, error
);
1420 g_print (" : %s::%s. %s (%p)\n", target_method
->klass
->name
, target_method
->name
, mono_signature_full_name (target_method
->signature
), target_method
);
1422 return_if_nok (error
);
1423 mono_class_setup_vtable (target_method
->klass
);
1425 if (m_class_is_valuetype (constrained_class
) && (target_method
->klass
== mono_defaults
.object_class
|| target_method
->klass
== m_class_get_parent (mono_defaults
.enum_class
) || target_method
->klass
== mono_defaults
.enum_class
)) {
1426 if (target_method
->klass
== mono_defaults
.enum_class
&& (td
->sp
- csignature
->param_count
- 1)->type
== STACK_TYPE_MP
) {
1427 /* managed pointer on the stack, we need to deref that puppy */
1428 ADD_CODE (td
, MINT_LDIND_I
);
1429 ADD_CODE (td
, csignature
->param_count
);
1431 if (mint_type (m_class_get_byval_arg (constrained_class
)) == MINT_TYPE_VT
) {
1432 ADD_CODE (td
, MINT_BOX_VT
);
1433 ADD_CODE (td
, get_data_item_index (td
, constrained_class
));
1434 ADD_CODE (td
, csignature
->param_count
| ((td
->sp
- 1 - csignature
->param_count
)->type
!= STACK_TYPE_MP
? 0 : BOX_NOT_CLEAR_VT_SP
));
1436 ADD_CODE (td
, MINT_BOX
);
1437 ADD_CODE (td
, get_data_item_index (td
, constrained_class
));
1438 ADD_CODE (td
, csignature
->param_count
);
1440 } else if (!m_class_is_valuetype (constrained_class
)) {
1441 /* managed pointer on the stack, we need to deref that puppy */
1442 ADD_CODE (td
, MINT_LDIND_I
);
1443 ADD_CODE (td
, csignature
->param_count
);
1445 if (m_class_is_valuetype (target_method
->klass
)) {
1448 /* Interface method */
1451 mono_class_setup_vtable (constrained_class
);
1452 ioffset
= mono_class_interface_offset (constrained_class
, target_method
->klass
);
1454 g_error ("type load error: constrained_class");
1455 slot
= mono_method_get_vtable_slot (target_method
);
1457 g_error ("type load error: target_method->klass");
1458 target_method
= m_class_get_vtable (constrained_class
) [ioffset
+ slot
];
1460 if (target_method
->klass
== mono_defaults
.enum_class
) {
1461 if ((td
->sp
- csignature
->param_count
- 1)->type
== STACK_TYPE_MP
) {
1462 /* managed pointer on the stack, we need to deref that puppy */
1463 ADD_CODE (td
, MINT_LDIND_I
);
1464 ADD_CODE (td
, csignature
->param_count
);
1466 if (mint_type (m_class_get_byval_arg (constrained_class
)) == MINT_TYPE_VT
) {
1467 ADD_CODE (td
, MINT_BOX_VT
);
1468 ADD_CODE (td
, get_data_item_index (td
, constrained_class
));
1469 ADD_CODE (td
, csignature
->param_count
| ((td
->sp
- 1 - csignature
->param_count
)->type
!= STACK_TYPE_MP
? 0 : BOX_NOT_CLEAR_VT_SP
));
1471 ADD_CODE (td
, MINT_BOX
);
1472 ADD_CODE (td
, get_data_item_index (td
, constrained_class
));
1473 ADD_CODE (td
, csignature
->param_count
);
1482 mono_class_init (target_method
->klass
);
1484 if (!is_virtual
&& target_method
&& (target_method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
))
1485 /* MS.NET seems to silently convert this to a callvirt */
1488 if (is_virtual
&& target_method
&& (!(target_method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) ||
1489 (MONO_METHOD_IS_FINAL (target_method
) &&
1490 target_method
->wrapper_type
!= MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
)) &&
1491 !(mono_class_is_marshalbyref (target_method
->klass
))) {
1492 /* Not really virtual, just needs a null check */
1494 need_null_check
= TRUE
;
1497 CHECK_STACK (td
, csignature
->param_count
+ csignature
->hasthis
);
1498 if (!calli
&& op
== -1 && (!is_virtual
|| (target_method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) == 0) &&
1499 (target_method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) == 0 &&
1500 (target_method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) == 0 &&
1501 !(target_method
->iflags
& METHOD_IMPL_ATTRIBUTE_NOINLINING
)) {
1502 MonoVTable
*vt
= mono_class_vtable_checked (domain
, target_method
->klass
, error
);
1503 return_if_nok (error
);
1504 int called_inited
= vt
->initialized
;
1506 if (method
== target_method
&& *(td
->ip
+ 5) == CEE_RET
&& !(csignature
->hasthis
&& m_class_is_valuetype (target_method
->klass
))) {
1508 if (td
->verbose_level
)
1509 g_print ("Optimize tail call of %s.%s\n", m_class_get_name (target_method
->klass
), target_method
->name
);
1511 for (i
= csignature
->param_count
- 1 + !!csignature
->hasthis
; i
>= 0; --i
)
1514 ADD_CODE(td
, MINT_BR_S
);
1515 offset
= body_start_offset
- ((td
->new_ip
- 1) - td
->new_code
);
1516 ADD_CODE(td
, offset
);
1517 if (!is_bb_start
[td
->ip
+ 5 - td
->il_code
])
1518 ++td
->ip
; /* gobble the CEE_RET if it isn't branched to */
1522 MonoMethodHeader
*mheader
= interp_method_get_header (target_method
, error
);
1523 return_if_nok (error
);
1524 /* mheader might not exist if this is a delegate invoc, etc */
1525 gboolean has_vt_arg
= FALSE
;
1526 for (i
= 0; i
< csignature
->param_count
; i
++)
1527 has_vt_arg
|= !mini_type_is_reference (csignature
->params
[i
]);
1529 gboolean empty_callee
= mheader
&& *mheader
->code
== CEE_RET
;
1530 mono_metadata_free_mh (mheader
);
1532 if (empty_callee
&& called_inited
&& !has_vt_arg
) {
1533 if (td
->verbose_level
)
1534 g_print ("Inline (empty) call of %s.%s\n", m_class_get_name (target_method
->klass
), target_method
->name
);
1535 for (i
= 0; i
< csignature
->param_count
; i
++) {
1536 ADD_CODE (td
, MINT_POP
); /*FIX: vt */
1539 if (csignature
->hasthis
) {
1540 if (is_virtual
|| need_null_check
)
1541 ADD_CODE (td
, MINT_CKNULL
);
1542 ADD_CODE (td
, MINT_POP
);
1545 td
->sp
-= csignature
->param_count
+ csignature
->hasthis
;
1552 target_method
= interp_transform_internal_calls (method
, target_method
, csignature
, is_virtual
);
1554 if (csignature
->call_convention
== MONO_CALL_VARARG
) {
1555 csignature
= mono_method_get_signature_checked (target_method
, image
, token
, generic_context
, error
);
1556 int vararg_stack
= 0;
1558 * For vararg calls, ArgIterator expects the signature and the varargs to be
1559 * stored in a linear memory. We allocate the necessary vt_stack space for
1560 * this. All varargs will be pushed to the vt_stack at call site.
1562 vararg_stack
+= sizeof (gpointer
);
1563 for (i
= csignature
->sentinelpos
; i
< csignature
->param_count
; ++i
) {
1564 int align
, arg_size
;
1565 arg_size
= mono_type_stack_size (csignature
->params
[i
], &align
);
1566 vararg_stack
+= arg_size
;
1568 vt_stack_used
+= ALIGN_TO (vararg_stack
, MINT_VT_ALIGNMENT
);
1569 PUSH_VT (td
, vararg_stack
);
1572 g_assert (csignature
->call_convention
!= MONO_CALL_FASTCALL
);
1573 td
->sp
-= csignature
->param_count
+ !!csignature
->hasthis
;
1574 for (i
= 0; i
< csignature
->param_count
; ++i
) {
1575 if (td
->sp
[i
+ !!csignature
->hasthis
].type
== STACK_TYPE_VT
) {
1577 MonoClass
*klass
= mono_class_from_mono_type_internal (csignature
->params
[i
]);
1578 if (csignature
->pinvoke
&& method
->wrapper_type
!= MONO_WRAPPER_NONE
)
1579 size
= mono_class_native_size (klass
, NULL
);
1581 size
= mono_class_value_size (klass
, NULL
);
1582 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
1583 vt_stack_used
+= size
;
1587 if (need_null_check
) {
1588 ADD_CODE (td
, MINT_CKNULL_N
);
1589 ADD_CODE (td
, csignature
->param_count
+ 1);
1592 /* need to handle typedbyref ... */
1593 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
1594 int mt
= mint_type(csignature
->ret
);
1595 MonoClass
*klass
= mono_class_from_mono_type_internal (csignature
->ret
);
1596 if (mt
== MINT_TYPE_VT
) {
1597 if (csignature
->pinvoke
&& method
->wrapper_type
!= MONO_WRAPPER_NONE
)
1598 vt_res_size
= mono_class_native_size (klass
, NULL
);
1600 vt_res_size
= mono_class_value_size (klass
, NULL
);
1601 if (mono_class_has_failure (klass
)) {
1602 mono_error_set_for_class_failure (error
, klass
);
1605 PUSH_VT(td
, vt_res_size
);
1607 PUSH_TYPE(td
, stack_type
[mt
], klass
);
1611 /* We need to convert delegate invoke to a indirect call on the interp_invoke_impl field */
1612 if (target_method
&& m_class_get_parent (target_method
->klass
) == mono_defaults
.multicastdelegate_class
) {
1613 const char *name
= target_method
->name
;
1614 if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
1616 ADD_CODE (td
, MINT_LD_DELEGATE_INVOKE_IMPL
);
1617 ADD_CODE (td
, csignature
->param_count
+ 1);
1624 if (op
== MINT_LDLEN
) {
1625 #ifdef MONO_BIG_ARRAYS
1626 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I8
);
1628 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I4
);
1631 if (op
== MINT_LDELEMA
|| op
== MINT_LDELEMA_TC
) {
1632 ADD_CODE (td
, get_data_item_index (td
, target_method
->klass
));
1633 ADD_CODE (td
, 1 + m_class_get_rank (target_method
->klass
));
1636 if (op
== MINT_CALLRUN
) {
1637 ADD_CODE (td
, get_data_item_index (td
, target_method
));
1638 ADD_CODE (td
, get_data_item_index (td
, mono_method_signature_internal (target_method
)));
1640 } else if (!calli
&& !is_virtual
&& jit_call_supported (target_method
, csignature
)) {
1641 ADD_CODE(td
, MINT_JIT_CALL
);
1642 ADD_CODE(td
, get_data_item_index (td
, (void *)mono_interp_get_imethod (domain
, target_method
, error
)));
1643 mono_error_assert_ok (error
);
1645 /* Try using fast icall path for simple signatures */
1646 if (native
&& !method
->dynamic
)
1647 op
= interp_icall_op_for_sig (csignature
);
1649 ADD_CODE(td
, native
? ((op
!= -1) ? MINT_CALLI_NAT_FAST
: MINT_CALLI_NAT
) : MINT_CALLI
);
1650 else if (is_virtual
)
1651 ADD_CODE(td
, is_void
? MINT_VCALLVIRT
: MINT_CALLVIRT
);
1653 ADD_CODE(td
, is_void
? MINT_VCALL
: MINT_CALL
);
1656 ADD_CODE(td
, get_data_item_index (td
, (void *)csignature
));
1660 ADD_CODE(td
, get_data_item_index (td
, (void *)mono_interp_get_imethod (domain
, target_method
, error
)));
1661 return_if_nok (error
);
1662 if (csignature
->call_convention
== MONO_CALL_VARARG
)
1663 ADD_CODE(td
, get_data_item_index (td
, (void *)csignature
));
1667 if (vt_stack_used
!= 0 || vt_res_size
!= 0) {
1668 ADD_CODE(td
, MINT_VTRESULT
);
1669 ADD_CODE(td
, vt_res_size
);
1670 WRITE32(td
, &vt_stack_used
);
1671 td
->vt_sp
-= vt_stack_used
;
1675 static MonoClassField
*
1676 interp_field_from_token (MonoMethod
*method
, guint32 token
, MonoClass
**klass
, MonoGenericContext
*generic_context
, MonoError
*error
)
1678 MonoClassField
*field
= NULL
;
1679 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
1680 field
= (MonoClassField
*) mono_method_get_wrapper_data (method
, token
);
1681 *klass
= field
->parent
;
1683 field
= mono_field_from_token_checked (m_class_get_image (method
->klass
), token
, klass
, generic_context
, error
);
1684 return_val_if_nok (error
, NULL
);
1687 if (!method
->skip_visibility
&& !mono_method_can_access_field (method
, field
)) {
1688 char *method_fname
= mono_method_full_name (method
, TRUE
);
1689 char *field_fname
= mono_field_full_name (field
);
1690 mono_error_set_generic_error (error
, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname
, method_fname
);
1691 g_free (method_fname
);
1692 g_free (field_fname
);
1699 static InterpBasicBlock
*
1700 get_bb (TransformData
*td
, InterpBasicBlock
*cbb
, unsigned char *ip
)
1702 int offset
= ip
- td
->il_code
;
1703 InterpBasicBlock
*bb
= td
->offset_to_bb
[offset
];
1706 bb
= (InterpBasicBlock
*)mono_mempool_alloc0 (td
->mempool
, sizeof (InterpBasicBlock
));
1708 td
->offset_to_bb
[offset
] = bb
;
1710 td
->basic_blocks
= g_list_append_mempool (td
->mempool
, td
->basic_blocks
, bb
);
1714 bb
->preds
= g_slist_prepend_mempool (td
->mempool
, bb
->preds
, cbb
);
1721 * Compute the set of IL level basic blocks.
1724 get_basic_blocks (TransformData
*td
)
1726 guint8
*start
= (guint8
*)td
->il_code
;
1727 guint8
*end
= (guint8
*)td
->il_code
+ td
->code_size
;
1729 unsigned char *target
;
1732 const MonoOpcode
*opcode
;
1733 InterpBasicBlock
*cbb
;
1735 td
->offset_to_bb
= (InterpBasicBlock
**)mono_mempool_alloc0 (td
->mempool
, sizeof (InterpBasicBlock
*) * (end
- start
+ 1));
1736 td
->entry_bb
= cbb
= get_bb (td
, NULL
, start
);
1739 cli_addr
= ip
- start
;
1740 td
->offset_to_bb
[cli_addr
] = cbb
;
1741 i
= mono_opcode_value ((const guint8
**)&ip
, end
);
1742 opcode
= &mono_opcodes
[i
];
1743 switch (opcode
->argument
) {
1744 case MonoInlineNone
:
1747 case MonoInlineString
:
1748 case MonoInlineType
:
1749 case MonoInlineField
:
1750 case MonoInlineMethod
:
1753 case MonoShortInlineR
:
1760 case MonoShortInlineVar
:
1761 case MonoShortInlineI
:
1764 case MonoShortInlineBrTarget
:
1765 target
= start
+ cli_addr
+ 2 + (signed char)ip
[1];
1766 get_bb (td
, cbb
, target
);
1768 cbb
= get_bb (td
, cbb
, ip
);
1770 case MonoInlineBrTarget
:
1771 target
= start
+ cli_addr
+ 5 + (gint32
)read32 (ip
+ 1);
1772 get_bb (td
, cbb
, target
);
1774 cbb
= get_bb (td
, cbb
, ip
);
1776 case MonoInlineSwitch
: {
1777 guint32 n
= read32 (ip
+ 1);
1780 cli_addr
+= 5 + 4 * n
;
1781 target
= start
+ cli_addr
;
1782 get_bb (td
, cbb
, target
);
1784 for (j
= 0; j
< n
; ++j
) {
1785 target
= start
+ cli_addr
+ (gint32
)read32 (ip
);
1786 get_bb (td
, cbb
, target
);
1789 cbb
= get_bb (td
, cbb
, ip
);
1797 g_assert_not_reached ();
1801 cbb
= get_bb (td
, NULL
, ip
);
1806 interp_save_debug_info (InterpMethod
*rtm
, MonoMethodHeader
*header
, TransformData
*td
, GArray
*line_numbers
)
1808 MonoDebugMethodJitInfo
*dinfo
;
1811 if (!mono_debug_enabled ())
1815 * We save the debug info in the same way the JIT does it, treating the interpreter IR as the native code.
1818 dinfo
= g_new0 (MonoDebugMethodJitInfo
, 1);
1819 dinfo
->num_params
= rtm
->param_count
;
1820 dinfo
->params
= g_new0 (MonoDebugVarInfo
, dinfo
->num_params
);
1821 dinfo
->num_locals
= header
->num_locals
;
1822 dinfo
->locals
= g_new0 (MonoDebugVarInfo
, header
->num_locals
);
1823 dinfo
->code_start
= (guint8
*)rtm
->code
;
1824 dinfo
->code_size
= td
->new_ip
- td
->new_code
;
1825 dinfo
->epilogue_begin
= 0;
1826 dinfo
->has_var_info
= TRUE
;
1827 dinfo
->num_line_numbers
= line_numbers
->len
;
1828 dinfo
->line_numbers
= g_new0 (MonoDebugLineNumberEntry
, dinfo
->num_line_numbers
);
1830 for (i
= 0; i
< dinfo
->num_params
; i
++) {
1831 MonoDebugVarInfo
*var
= &dinfo
->params
[i
];
1832 var
->type
= rtm
->param_types
[i
];
1834 for (i
= 0; i
< dinfo
->num_locals
; i
++) {
1835 MonoDebugVarInfo
*var
= &dinfo
->locals
[i
];
1836 var
->type
= mono_metadata_type_dup (NULL
, header
->locals
[i
]);
1839 for (i
= 0; i
< dinfo
->num_line_numbers
; i
++)
1840 dinfo
->line_numbers
[i
] = g_array_index (line_numbers
, MonoDebugLineNumberEntry
, i
);
1841 mono_debug_add_method (rtm
->method
, dinfo
, rtm
->domain
);
1843 mono_debug_free_method_jit_info (dinfo
);
1846 /* Same as the code in seq-points.c */
1848 insert_pred_seq_point (SeqPoint
*last_sp
, SeqPoint
*sp
, GSList
**next
)
1851 int src_index
= last_sp
->next_offset
;
1852 int dst_index
= sp
->next_offset
;
1854 /* bb->in_bb might contain duplicates */
1855 for (l
= next
[src_index
]; l
; l
= l
->next
)
1856 if (GPOINTER_TO_UINT (l
->data
) == dst_index
)
1859 next
[src_index
] = g_slist_append (next
[src_index
], GUINT_TO_POINTER (dst_index
));
1863 recursively_make_pred_seq_points (TransformData
*td
, InterpBasicBlock
*bb
)
1865 SeqPoint
** const MONO_SEQ_SEEN_LOOP
= (SeqPoint
**)GINT_TO_POINTER(-1);
1868 GArray
*predecessors
= g_array_new (FALSE
, TRUE
, sizeof (gpointer
));
1869 GHashTable
*seen
= g_hash_table_new_full (g_direct_hash
, NULL
, NULL
, NULL
);
1871 // Insert/remove sentinel into the memoize table to detect loops containing bb
1872 bb
->pred_seq_points
= MONO_SEQ_SEEN_LOOP
;
1874 for (l
= bb
->preds
; l
; l
= l
->next
) {
1875 InterpBasicBlock
*in_bb
= (InterpBasicBlock
*)l
->data
;
1877 // This bb has the last seq point, append it and continue
1878 if (in_bb
->last_seq_point
!= NULL
) {
1879 predecessors
= g_array_append_val (predecessors
, in_bb
->last_seq_point
);
1883 // We've looped or handled this before, exit early.
1884 // No last sequence points to find.
1885 if (in_bb
->pred_seq_points
== MONO_SEQ_SEEN_LOOP
)
1888 // Take sequence points from incoming basic blocks
1890 if (in_bb
== td
->entry_bb
)
1893 if (in_bb
->pred_seq_points
== NULL
)
1894 recursively_make_pred_seq_points (td
, in_bb
);
1896 // Union sequence points with incoming bb's
1897 for (int i
=0; i
< in_bb
->num_pred_seq_points
; i
++) {
1898 if (!g_hash_table_lookup (seen
, in_bb
->pred_seq_points
[i
])) {
1899 g_array_append_val (predecessors
, in_bb
->pred_seq_points
[i
]);
1900 g_hash_table_insert (seen
, in_bb
->pred_seq_points
[i
], (gpointer
)&MONO_SEQ_SEEN_LOOP
);
1903 // predecessors = g_array_append_vals (predecessors, in_bb->pred_seq_points, in_bb->num_pred_seq_points);
1906 g_hash_table_destroy (seen
);
1908 if (predecessors
->len
!= 0) {
1909 bb
->pred_seq_points
= (SeqPoint
**)mono_mempool_alloc0 (td
->mempool
, sizeof (SeqPoint
*) * predecessors
->len
);
1910 bb
->num_pred_seq_points
= predecessors
->len
;
1912 for (int newer
= 0; newer
< bb
->num_pred_seq_points
; newer
++) {
1913 bb
->pred_seq_points
[newer
] = (SeqPoint
*)g_array_index (predecessors
, gpointer
, newer
);
1917 g_array_free (predecessors
, TRUE
);
1921 collect_pred_seq_points (TransformData
*td
, InterpBasicBlock
*bb
, SeqPoint
*seqp
, GSList
**next
)
1923 // Doesn't have a last sequence point, must find from incoming basic blocks
1924 if (bb
->pred_seq_points
== NULL
&& bb
!= td
->entry_bb
)
1925 recursively_make_pred_seq_points (td
, bb
);
1927 for (int i
= 0; i
< bb
->num_pred_seq_points
; i
++)
1928 insert_pred_seq_point (bb
->pred_seq_points
[i
], seqp
, next
);
1934 save_seq_points (TransformData
*td
, MonoJitInfo
*jinfo
)
1936 InterpMethod
*rtm
= td
->rtm
;
1938 int i
, seq_info_size
;
1939 MonoSeqPointInfo
*info
;
1940 MonoDomain
*domain
= mono_domain_get ();
1941 GSList
**next
= NULL
;
1944 if (!td
->gen_sdb_seq_points
)
1948 * For each sequence point, compute the list of sequence points immediately
1949 * following it, this is needed to implement 'step over' in the debugger agent.
1950 * Similar to the code in mono_save_seq_point_info ().
1952 for (i
= 0; i
< td
->seq_points
->len
; ++i
) {
1953 SeqPoint
*sp
= (SeqPoint
*)g_ptr_array_index (td
->seq_points
, i
);
1955 /* Store the seq point index here temporarily */
1956 sp
->next_offset
= i
;
1958 next
= (GSList
**)mono_mempool_alloc0 (td
->mempool
, sizeof (GList
*) * td
->seq_points
->len
);
1959 for (bblist
= td
->basic_blocks
; bblist
; bblist
= bblist
->next
) {
1960 InterpBasicBlock
*bb
= (InterpBasicBlock
*)bblist
->data
;
1962 GSList
*bb_seq_points
= g_slist_reverse (bb
->seq_points
);
1963 SeqPoint
*last
= NULL
;
1964 for (GSList
*l
= bb_seq_points
; l
; l
= l
->next
) {
1965 SeqPoint
*sp
= (SeqPoint
*)l
->data
;
1967 if (sp
->il_offset
== METHOD_ENTRY_IL_OFFSET
|| sp
->il_offset
== METHOD_EXIT_IL_OFFSET
)
1968 /* Used to implement method entry/exit events */
1972 /* Link with the previous seq point in the same bb */
1973 next
[last
->next_offset
] = g_slist_append_mempool (td
->mempool
, next
[last
->next_offset
], GINT_TO_POINTER (sp
->next_offset
));
1975 /* Link with the last bb in the previous bblocks */
1976 collect_pred_seq_points (td
, bb
, sp
, next
);
1982 /* Serialize the seq points into a byte array */
1983 array
= g_byte_array_new ();
1984 SeqPoint zero_seq_point
= {0};
1985 SeqPoint
* last_seq_point
= &zero_seq_point
;
1986 for (i
= 0; i
< td
->seq_points
->len
; ++i
) {
1987 SeqPoint
*sp
= (SeqPoint
*)g_ptr_array_index (td
->seq_points
, i
);
1989 sp
->next_offset
= 0;
1990 if (mono_seq_point_info_add_seq_point (array
, sp
, last_seq_point
, next
[i
], TRUE
))
1991 last_seq_point
= sp
;
1994 if (td
->verbose_level
) {
1995 g_print ("\nSEQ POINT MAP FOR %s: \n", td
->method
->name
);
1997 for (i
= 0; i
< td
->seq_points
->len
; ++i
) {
1998 SeqPoint
*sp
= (SeqPoint
*)g_ptr_array_index (td
->seq_points
, i
);
2004 g_print ("\tIL0x%x[0x%0x] ->", sp
->il_offset
, sp
->native_offset
);
2005 for (l
= next
[i
]; l
; l
= l
->next
) {
2006 int next_index
= GPOINTER_TO_UINT (l
->data
);
2007 g_print (" IL0x%x", ((SeqPoint
*)g_ptr_array_index (td
->seq_points
, next_index
))->il_offset
);
2013 info
= mono_seq_point_info_new (array
->len
, TRUE
, array
->data
, TRUE
, &seq_info_size
);
2014 mono_atomic_fetch_add_i32 (&mono_jit_stats
.allocated_seq_points_size
, seq_info_size
);
2016 g_byte_array_free (array
, TRUE
);
2018 mono_domain_lock (domain
);
2019 g_hash_table_insert (domain_jit_info (domain
)->seq_points
, rtm
->method
, info
);
2020 mono_domain_unlock (domain
);
2022 jinfo
->seq_points
= info
;
2026 emit_seq_point (TransformData
*td
, int il_offset
, InterpBasicBlock
*cbb
, gboolean nonempty_stack
)
2030 seqp
= (SeqPoint
*)mono_mempool_alloc0 (td
->mempool
, sizeof (SeqPoint
));
2031 seqp
->il_offset
= il_offset
;
2032 seqp
->native_offset
= (guint8
*)td
->new_ip
- (guint8
*)td
->new_code
;
2034 seqp
->flags
|= MONO_SEQ_POINT_FLAG_NONEMPTY_STACK
;
2036 ADD_CODE (td
, MINT_SDB_SEQ_POINT
);
2037 g_ptr_array_add (td
->seq_points
, seqp
);
2039 cbb
->seq_points
= g_slist_prepend_mempool (td
->mempool
, cbb
->seq_points
, seqp
);
2040 cbb
->last_seq_point
= seqp
;
2043 #define BARRIER_IF_VOLATILE(td) \
2046 ADD_CODE (td, MINT_MONO_MEMORY_BARRIER); \
2047 volatile_ = FALSE; \
2052 generate (MonoMethod
*method
, MonoMethodHeader
*header
, InterpMethod
*rtm
, unsigned char *is_bb_start
, MonoGenericContext
*generic_context
, MonoError
*error
)
2054 MonoMethodSignature
*signature
= mono_method_signature_internal (method
);
2055 MonoImage
*image
= m_class_get_image (method
->klass
);
2056 MonoDomain
*domain
= rtm
->domain
;
2057 MonoClass
*constrained_class
= NULL
;
2058 MonoSimpleBasicBlock
*bb
= NULL
, *original_bb
= NULL
;
2059 int offset
, mt
, i
, i32
;
2060 gboolean readonly
= FALSE
;
2061 gboolean volatile_
= FALSE
;
2063 MonoClassField
*field
;
2064 const unsigned char *end
;
2065 int new_in_start_offset
;
2066 int body_start_offset
;
2069 TransformData transform_data
;
2071 GArray
*line_numbers
;
2072 MonoDebugMethodInfo
*minfo
;
2073 MonoBitSet
*seq_point_locs
= NULL
;
2074 MonoBitSet
*seq_point_set_locs
= NULL
;
2075 gboolean sym_seq_points
= FALSE
;
2076 InterpBasicBlock
*bb_exit
= NULL
;
2077 static gboolean verbose_method_inited
;
2078 static char* verbose_method_name
;
2080 if (!verbose_method_inited
) {
2081 verbose_method_name
= g_getenv ("MONO_VERBOSE_METHOD");
2082 verbose_method_inited
= TRUE
;
2085 memset (&transform_data
, 0, sizeof(transform_data
));
2086 td
= &transform_data
;
2088 td
->method
= method
;
2090 td
->is_bb_start
= is_bb_start
;
2091 td
->il_code
= header
->code
;
2092 td
->code_size
= header
->code_size
;
2093 td
->header
= header
;
2094 td
->max_code_size
= td
->code_size
;
2095 td
->new_code
= (unsigned short *)g_malloc(td
->max_code_size
* sizeof(gushort
));
2096 td
->new_code_end
= td
->new_code
+ td
->max_code_size
;
2097 td
->mempool
= mono_mempool_new ();
2098 td
->in_offsets
= (int*)g_malloc0((header
->code_size
+ 1) * sizeof(int));
2099 td
->stack_state
= (StackInfo
**)g_malloc0(header
->code_size
* sizeof(StackInfo
*));
2100 td
->stack_height
= (int*)g_malloc(header
->code_size
* sizeof(int));
2101 td
->vt_stack_size
= (int*)g_malloc(header
->code_size
* sizeof(int));
2102 td
->n_data_items
= 0;
2103 td
->max_data_items
= 0;
2104 td
->data_items
= NULL
;
2105 td
->data_hash
= g_hash_table_new (NULL
, NULL
);
2106 td
->clause_indexes
= (int*)g_malloc (header
->code_size
* sizeof (int));
2107 td
->gen_sdb_seq_points
= mini_debug_options
.gen_sdb_seq_points
;
2108 td
->seq_points
= g_ptr_array_new ();
2109 td
->relocs
= g_ptr_array_new ();
2110 td
->verbose_level
= mono_interp_traceopt
;
2111 td
->total_locals_size
= rtm
->locals_size
;
2112 rtm
->data_items
= td
->data_items
;
2113 for (i
= 0; i
< header
->code_size
; i
++) {
2114 td
->stack_height
[i
] = -1;
2115 td
->clause_indexes
[i
] = -1;
2118 if (verbose_method_name
) {
2119 const char *name
= verbose_method_name
;
2121 if ((strchr (name
, '.') > name
) || strchr (name
, ':')) {
2122 MonoMethodDesc
*desc
;
2124 desc
= mono_method_desc_new (name
, TRUE
);
2125 if (mono_method_desc_full_match (desc
, method
)) {
2126 td
->verbose_level
= 4;
2128 mono_method_desc_free (desc
);
2130 if (strcmp (method
->name
, name
) == 0)
2131 td
->verbose_level
= 4;
2135 if (td
->gen_sdb_seq_points
) {
2136 get_basic_blocks (td
);
2138 minfo
= mono_debug_lookup_method (method
);
2141 MonoSymSeqPoint
*sps
;
2142 int i
, n_il_offsets
;
2144 mono_debug_get_seq_points (minfo
, NULL
, NULL
, NULL
, &sps
, &n_il_offsets
);
2146 seq_point_locs
= mono_bitset_mem_new (mono_mempool_alloc0 (td
->mempool
, mono_bitset_alloc_size (header
->code_size
, 0)), header
->code_size
, 0);
2147 seq_point_set_locs
= mono_bitset_mem_new (mono_mempool_alloc0 (td
->mempool
, mono_bitset_alloc_size (header
->code_size
, 0)), header
->code_size
, 0);
2148 sym_seq_points
= TRUE
;
2150 for (i
= 0; i
< n_il_offsets
; ++i
) {
2151 if (sps
[i
].il_offset
< header
->code_size
)
2152 mono_bitset_set_fast (seq_point_locs
, sps
[i
].il_offset
);
2156 MonoDebugMethodAsyncInfo
* asyncMethod
= mono_debug_lookup_method_async_debug_info (method
);
2158 for (i
= 0; asyncMethod
!= NULL
&& i
< asyncMethod
->num_awaits
; i
++) {
2159 mono_bitset_set_fast (seq_point_locs
, asyncMethod
->resume_offsets
[i
]);
2160 mono_bitset_set_fast (seq_point_locs
, asyncMethod
->yield_offsets
[i
]);
2162 mono_debug_free_method_async_debug_info (asyncMethod
);
2164 } else if (!method
->wrapper_type
&& !method
->dynamic
&& mono_debug_image_has_debug_info (m_class_get_image (method
->klass
))) {
2165 /* Methods without line number info like auto-generated property accessors */
2166 seq_point_locs
= mono_bitset_new (header
->code_size
, 0);
2167 seq_point_set_locs
= mono_bitset_new (header
->code_size
, 0);
2168 sym_seq_points
= TRUE
;
2172 td
->new_ip
= td
->new_code
;
2173 td
->last_new_ip
= NULL
;
2175 td
->stack
= (StackInfo
*)g_malloc0 ((header
->max_stack
+ 1) * sizeof (td
->stack
[0]));
2176 td
->stack_capacity
= header
->max_stack
+ 1;
2178 td
->max_stack_height
= 0;
2180 line_numbers
= g_array_new (FALSE
, TRUE
, sizeof (MonoDebugLineNumberEntry
));
2182 for (i
= 0; i
< header
->num_clauses
; i
++) {
2183 MonoExceptionClause
*c
= header
->clauses
+ i
;
2184 td
->stack_height
[c
->handler_offset
] = 0;
2185 td
->vt_stack_size
[c
->handler_offset
] = 0;
2186 td
->is_bb_start
[c
->handler_offset
] = 1;
2188 td
->stack_height
[c
->handler_offset
] = 1;
2189 td
->stack_state
[c
->handler_offset
] = (StackInfo
*)g_malloc0(sizeof(StackInfo
));
2190 td
->stack_state
[c
->handler_offset
][0].type
= STACK_TYPE_O
;
2191 td
->stack_state
[c
->handler_offset
][0].klass
= NULL
; /*FIX*/
2193 if (c
->flags
& MONO_EXCEPTION_CLAUSE_FILTER
) {
2194 td
->stack_height
[c
->data
.filter_offset
] = 0;
2195 td
->vt_stack_size
[c
->data
.filter_offset
] = 0;
2196 td
->is_bb_start
[c
->data
.filter_offset
] = 1;
2198 td
->stack_height
[c
->data
.filter_offset
] = 1;
2199 td
->stack_state
[c
->data
.filter_offset
] = (StackInfo
*)g_malloc0(sizeof(StackInfo
));
2200 td
->stack_state
[c
->data
.filter_offset
][0].type
= STACK_TYPE_O
;
2201 td
->stack_state
[c
->data
.filter_offset
][0].klass
= NULL
; /*FIX*/
2204 for (int j
= c
->handler_offset
; j
< c
->handler_offset
+ c
->handler_len
; ++j
) {
2205 if (td
->clause_indexes
[j
] == -1)
2206 td
->clause_indexes
[j
] = i
;
2210 td
->ip
= header
->code
;
2211 end
= td
->ip
+ header
->code_size
;
2213 if (td
->verbose_level
) {
2214 char *tmp
= mono_disasm_code (NULL
, method
, td
->ip
, end
);
2215 char *name
= mono_method_full_name (method
, TRUE
);
2216 g_print ("Method %s, original code:\n", name
);
2217 g_print ("%s\n", tmp
);
2222 if (signature
->hasthis
)
2223 store_inarg (td
, 0);
2224 for (i
= 0; i
< signature
->param_count
; i
++)
2225 store_inarg (td
, i
+ !!signature
->hasthis
);
2227 body_start_offset
= td
->new_ip
- td
->new_code
;
2229 for (i
= 0; i
< header
->num_locals
; i
++) {
2230 int mt
= mint_type(header
->locals
[i
]);
2231 if (mt
== MINT_TYPE_VT
|| mt
== MINT_TYPE_O
|| mt
== MINT_TYPE_P
) {
2232 ADD_CODE(td
, MINT_INITLOCALS
);
2237 if (rtm
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_ENTER
)
2238 ADD_CODE (td
, MINT_PROF_ENTER
);
2240 /* safepoint is required on method entry */
2241 if (mono_threads_are_safepoints_enabled ())
2242 ADD_CODE (td
, MINT_SAFEPOINT
);
2244 if (sym_seq_points
) {
2245 InterpBasicBlock
*cbb
= td
->offset_to_bb
[0];
2247 emit_seq_point (td
, METHOD_ENTRY_IL_OFFSET
, cbb
, FALSE
);
2250 original_bb
= bb
= mono_basic_block_split (method
, error
, header
);
2251 goto_if_nok (error
, exit
);
2255 while (td
->ip
< end
) {
2256 g_assert (td
->sp
>= td
->stack
);
2257 g_assert (td
->vt_sp
< 0x10000000);
2258 in_offset
= td
->ip
- header
->code
;
2259 td
->in_offsets
[in_offset
] = td
->new_ip
- td
->new_code
;
2260 new_in_start_offset
= td
->new_ip
- td
->new_code
;
2261 td
->in_start
= td
->ip
;
2263 MonoDebugLineNumberEntry lne
;
2264 lne
.native_offset
= (guint8
*)td
->new_ip
- (guint8
*)td
->new_code
;
2265 lne
.il_offset
= in_offset
;
2266 g_array_append_val (line_numbers
, lne
);
2268 if (td
->stack_height
[in_offset
] >= 0) {
2269 g_assert (is_bb_start
[in_offset
]);
2270 if (td
->stack_height
[in_offset
] > 0)
2271 memcpy (td
->stack
, td
->stack_state
[in_offset
], td
->stack_height
[in_offset
] * sizeof(td
->stack
[0]));
2272 td
->sp
= td
->stack
+ td
->stack_height
[in_offset
];
2273 td
->vt_sp
= td
->vt_stack_size
[in_offset
];
2276 if (in_offset
== bb
->end
)
2280 int op_size
= mono_opcode_size (td
->ip
, end
);
2281 g_assert (op_size
> 0); /* The BB formation pass must catch all bad ops */
2283 if (td
->verbose_level
> 1)
2284 g_print ("SKIPPING DEAD OP at %x\n", in_offset
);
2290 if (td
->verbose_level
> 1) {
2291 g_print ("IL_%04lx %s %-10s -> IL_%04lx, sp %ld, %s %-12s vt_sp %u (max %u)\n",
2292 td
->ip
- td
->il_code
,
2293 td
->is_bb_start
[td
->ip
- td
->il_code
] == 3 ? "<>" :
2294 td
->is_bb_start
[td
->ip
- td
->il_code
] == 2 ? "< " :
2295 td
->is_bb_start
[td
->ip
- td
->il_code
] == 1 ? " >" : " ",
2296 mono_opcode_name (*td
->ip
), td
->new_ip
- td
->new_code
, td
->sp
- td
->stack
,
2297 td
->sp
> td
->stack
? stack_type_string
[td
->sp
[-1].type
] : " ",
2298 (td
->sp
> td
->stack
&& (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_VT
)) ? (td
->sp
[-1].klass
== NULL
? "?" : m_class_get_name (td
->sp
[-1].klass
)) : "",
2299 td
->vt_sp
, td
->max_vt_sp
);
2302 if (sym_seq_points
&& mono_bitset_test_fast (seq_point_locs
, td
->ip
- header
->code
)) {
2303 InterpBasicBlock
*cbb
= td
->offset_to_bb
[td
->ip
- header
->code
];
2307 * Make methods interruptable at the beginning, and at the targets of
2308 * backward branches.
2310 if (in_offset
== 0 || g_slist_length (cbb
->preds
) > 1)
2311 ADD_CODE (td
, MINT_SDB_INTR_LOC
);
2313 emit_seq_point (td
, in_offset
, cbb
, FALSE
);
2315 mono_bitset_set_fast (seq_point_set_locs
, td
->ip
- header
->code
);
2319 bb_exit
= td
->offset_to_bb
[td
->ip
- header
->code
];
2321 if (is_bb_start
[in_offset
]) {
2322 int index
= td
->clause_indexes
[in_offset
];
2324 MonoExceptionClause
*clause
= &header
->clauses
[index
];
2325 if ((clause
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
||
2326 clause
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
) &&
2327 in_offset
== clause
->handler_offset
)
2328 ADD_CODE (td
, MINT_START_ABORT_PROT
);
2338 SIMPLE_OP(td
, MINT_BREAK
);
2344 load_arg (td
, *td
->ip
- CEE_LDARG_0
);
2351 load_local (td
, *td
->ip
- CEE_LDLOC_0
);
2358 store_local (td
, *td
->ip
- CEE_STLOC_0
);
2362 load_arg (td
, ((guint8
*)td
->ip
)[1]);
2365 case CEE_LDARGA_S
: {
2366 /* NOTE: n includes this */
2367 int n
= ((guint8
*) td
->ip
) [1];
2368 ADD_CODE (td
, MINT_LDARGA
);
2369 ADD_CODE (td
, td
->rtm
->arg_offsets
[n
]);
2370 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
2375 store_arg (td
, ((guint8
*)td
->ip
)[1]);
2379 load_local (td
, ((guint8
*)td
->ip
)[1]);
2383 ADD_CODE(td
, MINT_LDLOCA_S
);
2384 ADD_CODE(td
, td
->rtm
->local_offsets
[((guint8
*)td
->ip
)[1]]);
2385 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
2389 store_local (td
, ((guint8
*)td
->ip
)[1]);
2393 SIMPLE_OP(td
, MINT_LDNULL
);
2394 PUSH_TYPE(td
, STACK_TYPE_O
, NULL
);
2397 SIMPLE_OP(td
, MINT_LDC_I4_M1
);
2398 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
2401 if (!td
->is_bb_start
[td
->ip
+ 1 - td
->il_code
] && td
->ip
[1] == 0xfe && td
->ip
[2] == CEE_CEQ
&&
2402 td
->sp
> td
->stack
&& td
->sp
[-1].type
== STACK_TYPE_I4
) {
2403 SIMPLE_OP(td
, MINT_CEQ0_I4
);
2406 SIMPLE_OP(td
, MINT_LDC_I4_0
);
2407 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
2411 if (!td
->is_bb_start
[td
->ip
+ 1 - td
->il_code
] &&
2412 (td
->ip
[1] == CEE_ADD
|| td
->ip
[1] == CEE_SUB
) && td
->sp
[-1].type
== STACK_TYPE_I4
) {
2413 ADD_CODE(td
, td
->ip
[1] == CEE_ADD
? MINT_ADD1_I4
: MINT_SUB1_I4
);
2416 SIMPLE_OP(td
, MINT_LDC_I4_1
);
2417 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
2427 SIMPLE_OP(td
, (*td
->ip
- CEE_LDC_I4_0
) + MINT_LDC_I4_0
);
2428 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
2431 ADD_CODE(td
, MINT_LDC_I4_S
);
2432 ADD_CODE(td
, ((gint8
*) td
->ip
) [1]);
2434 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
2437 i32
= read32 (td
->ip
+ 1);
2438 ADD_CODE(td
, MINT_LDC_I4
);
2441 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
2444 gint64 val
= read64 (td
->ip
+ 1);
2445 ADD_CODE(td
, MINT_LDC_I8
);
2448 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I8
);
2453 readr4 (td
->ip
+ 1, &val
);
2454 ADD_CODE(td
, MINT_LDC_R4
);
2457 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_R4
);
2462 readr8 (td
->ip
+ 1, &val
);
2463 ADD_CODE(td
, MINT_LDC_R8
);
2466 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_R8
);
2470 int type
= td
->sp
[-1].type
;
2471 MonoClass
*klass
= td
->sp
[-1].klass
;
2472 if (td
->sp
[-1].type
== STACK_TYPE_VT
) {
2473 gint32 size
= mono_class_value_size (klass
, NULL
);
2475 ADD_CODE(td
, MINT_DUP_VT
);
2479 SIMPLE_OP(td
, MINT_DUP
);
2480 PUSH_TYPE(td
, type
, klass
);
2485 SIMPLE_OP(td
, MINT_POP
);
2487 if (td
->sp
[-1].type
== STACK_TYPE_VT
) {
2488 int size
= mono_class_value_size (td
->sp
[-1].klass
, NULL
);
2489 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
2490 ADD_CODE(td
, MINT_VTRESULT
);
2499 if (td
->sp
> td
->stack
)
2500 g_warning ("CEE_JMP: stack must be empty");
2501 token
= read32 (td
->ip
+ 1);
2502 m
= mono_get_method_checked (image
, token
, NULL
, generic_context
, error
);
2503 goto_if_nok (error
, exit
);
2504 ADD_CODE (td
, MINT_JMP
);
2505 ADD_CODE (td
, get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
)));
2506 goto_if_nok (error
, exit
);
2510 case CEE_CALLVIRT
: /* Fall through */
2511 case CEE_CALLI
: /* Fall through */
2513 gboolean need_seq_point
= FALSE
;
2515 if (sym_seq_points
&& !mono_bitset_test_fast (seq_point_locs
, td
->ip
+ 5 - header
->code
))
2516 need_seq_point
= TRUE
;
2518 interp_transform_call (td
, method
, NULL
, domain
, generic_context
, is_bb_start
, body_start_offset
, constrained_class
, readonly
, error
, TRUE
);
2519 goto_if_nok (error
, exit
);
2521 if (need_seq_point
) {
2522 InterpBasicBlock
*cbb
= td
->offset_to_bb
[td
->ip
- header
->code
];
2525 emit_seq_point (td
, td
->ip
- header
->code
, cbb
, TRUE
);
2528 constrained_class
= NULL
;
2534 MonoType
*ult
= mini_type_get_underlying_type (signature
->ret
);
2535 if (ult
->type
!= MONO_TYPE_VOID
) {
2536 CHECK_STACK (td
, 1);
2538 if (mint_type (ult
) == MINT_TYPE_VT
) {
2539 MonoClass
*klass
= mono_class_from_mono_type_internal (ult
);
2540 vt_size
= mono_class_value_size (klass
, NULL
);
2543 if (td
->sp
> td
->stack
) {
2544 mono_error_set_generic_error (error
, "System", "InvalidProgramException", "");
2547 if (td
->vt_sp
!= ALIGN_TO (vt_size
, MINT_VT_ALIGNMENT
))
2548 g_error ("%s: CEE_RET: value type stack: %d vs. %d", mono_method_full_name (td
->method
, TRUE
), td
->vt_sp
, vt_size
);
2550 if (sym_seq_points
) {
2551 InterpBasicBlock
*cbb
= td
->offset_to_bb
[td
->ip
- header
->code
];
2553 emit_seq_point (td
, METHOD_EXIT_IL_OFFSET
, bb_exit
, FALSE
);
2557 SIMPLE_OP(td
, ult
->type
== MONO_TYPE_VOID
? MINT_RET_VOID
: MINT_RET
);
2559 ADD_CODE(td
, MINT_RET_VT
);
2560 WRITE32(td
, &vt_size
);
2566 handle_branch (td
, MINT_BR_S
, MINT_BR
, 5 + read32 (td
->ip
+ 1));
2570 handle_branch (td
, MINT_BR_S
, MINT_BR
, 2 + (gint8
)td
->ip
[1]);
2574 one_arg_branch (td
, MINT_BRFALSE_I4
, 5 + read32 (td
->ip
+ 1));
2578 one_arg_branch (td
, MINT_BRFALSE_I4
, 2 + (gint8
)td
->ip
[1]);
2582 one_arg_branch (td
, MINT_BRTRUE_I4
, 5 + read32 (td
->ip
+ 1));
2586 one_arg_branch (td
, MINT_BRTRUE_I4
, 2 + (gint8
)td
->ip
[1]);
2590 two_arg_branch (td
, MINT_BEQ_I4
, 5 + read32 (td
->ip
+ 1));
2594 two_arg_branch (td
, MINT_BEQ_I4
, 2 + (gint8
) td
->ip
[1]);
2598 two_arg_branch (td
, MINT_BGE_I4
, 5 + read32 (td
->ip
+ 1));
2602 two_arg_branch (td
, MINT_BGE_I4
, 2 + (gint8
) td
->ip
[1]);
2606 two_arg_branch (td
, MINT_BGT_I4
, 5 + read32 (td
->ip
+ 1));
2610 two_arg_branch (td
, MINT_BGT_I4
, 2 + (gint8
) td
->ip
[1]);
2614 two_arg_branch (td
, MINT_BLT_I4
, 5 + read32 (td
->ip
+ 1));
2618 two_arg_branch (td
, MINT_BLT_I4
, 2 + (gint8
) td
->ip
[1]);
2622 two_arg_branch (td
, MINT_BLE_I4
, 5 + read32 (td
->ip
+ 1));
2626 two_arg_branch (td
, MINT_BLE_I4
, 2 + (gint8
) td
->ip
[1]);
2630 two_arg_branch (td
, MINT_BNE_UN_I4
, 5 + read32 (td
->ip
+ 1));
2634 two_arg_branch (td
, MINT_BNE_UN_I4
, 2 + (gint8
) td
->ip
[1]);
2638 two_arg_branch (td
, MINT_BGE_UN_I4
, 5 + read32 (td
->ip
+ 1));
2642 two_arg_branch (td
, MINT_BGE_UN_I4
, 2 + (gint8
) td
->ip
[1]);
2646 two_arg_branch (td
, MINT_BGT_UN_I4
, 5 + read32 (td
->ip
+ 1));
2650 two_arg_branch (td
, MINT_BGT_UN_I4
, 2 + (gint8
) td
->ip
[1]);
2654 two_arg_branch (td
, MINT_BLE_UN_I4
, 5 + read32 (td
->ip
+ 1));
2658 two_arg_branch (td
, MINT_BLE_UN_I4
, 2 + (gint8
) td
->ip
[1]);
2662 two_arg_branch (td
, MINT_BLT_UN_I4
, 5 + read32 (td
->ip
+ 1));
2666 two_arg_branch (td
, MINT_BLT_UN_I4
, 2 + (gint8
) td
->ip
[1]);
2671 const unsigned char *next_ip
;
2673 n
= read32 (td
->ip
);
2674 ADD_CODE (td
, MINT_SWITCH
);
2677 next_ip
= td
->ip
+ n
* 4;
2679 int stack_height
= td
->sp
- td
->stack
;
2680 for (i
= 0; i
< n
; i
++) {
2681 offset
= read32 (td
->ip
);
2682 target
= next_ip
- td
->il_code
+ offset
;
2685 if (stack_height
> 0 && stack_height
!= td
->stack_height
[target
])
2686 g_warning ("SWITCH with back branch and non-empty stack");
2688 target
= td
->in_offsets
[target
] - (td
->new_ip
- td
->new_code
);
2690 td
->stack_height
[target
] = stack_height
;
2691 td
->vt_stack_size
[target
] = td
->vt_sp
;
2692 if (stack_height
> 0)
2693 td
->stack_state
[target
] = (StackInfo
*)g_memdup (td
->stack
, stack_height
* sizeof (td
->stack
[0]));
2695 Reloc
*reloc
= (Reloc
*)mono_mempool_alloc0 (td
->mempool
, sizeof (Reloc
));
2696 reloc
->type
= RELOC_SWITCH
;
2697 reloc
->offset
= td
->new_ip
- td
->new_code
;
2698 reloc
->target
= target
;
2699 g_ptr_array_add (td
->relocs
, reloc
);
2702 WRITE32 (td
, &target
);
2708 CHECK_STACK (td
, 1);
2709 SIMPLE_OP (td
, MINT_LDIND_I1_CHECK
);
2710 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
2711 BARRIER_IF_VOLATILE (td
);
2714 CHECK_STACK (td
, 1);
2715 SIMPLE_OP (td
, MINT_LDIND_U1_CHECK
);
2716 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
2717 BARRIER_IF_VOLATILE (td
);
2720 CHECK_STACK (td
, 1);
2721 SIMPLE_OP (td
, MINT_LDIND_I2_CHECK
);
2722 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
2723 BARRIER_IF_VOLATILE (td
);
2726 CHECK_STACK (td
, 1);
2727 SIMPLE_OP (td
, MINT_LDIND_U2_CHECK
);
2728 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
2729 BARRIER_IF_VOLATILE (td
);
2732 CHECK_STACK (td
, 1);
2733 SIMPLE_OP (td
, MINT_LDIND_I4_CHECK
);
2734 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
2735 BARRIER_IF_VOLATILE (td
);
2738 CHECK_STACK (td
, 1);
2739 SIMPLE_OP (td
, MINT_LDIND_U4_CHECK
);
2740 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
2741 BARRIER_IF_VOLATILE (td
);
2744 CHECK_STACK (td
, 1);
2745 SIMPLE_OP (td
, MINT_LDIND_I8_CHECK
);
2746 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
2747 BARRIER_IF_VOLATILE (td
);
2750 CHECK_STACK (td
, 1);
2751 ADD_CODE (td
, MINT_CKNULL
);
2752 SIMPLE_OP (td
, MINT_LDIND_I
);
2754 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I
);
2755 BARRIER_IF_VOLATILE (td
);
2758 CHECK_STACK (td
, 1);
2759 SIMPLE_OP (td
, MINT_LDIND_R4_CHECK
);
2760 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R4
);
2761 BARRIER_IF_VOLATILE (td
);
2764 CHECK_STACK (td
, 1);
2765 SIMPLE_OP (td
, MINT_LDIND_R8_CHECK
);
2766 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
2767 BARRIER_IF_VOLATILE (td
);
2770 CHECK_STACK (td
, 1);
2771 ADD_CODE (td
, MINT_CKNULL
);
2772 SIMPLE_OP (td
, MINT_LDIND_REF
);
2773 BARRIER_IF_VOLATILE (td
);
2774 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_O
);
2777 CHECK_STACK (td
, 2);
2778 BARRIER_IF_VOLATILE (td
);
2779 SIMPLE_OP (td
, MINT_STIND_REF
);
2783 CHECK_STACK (td
, 2);
2784 BARRIER_IF_VOLATILE (td
);
2785 SIMPLE_OP (td
, MINT_STIND_I1
);
2789 CHECK_STACK (td
, 2);
2790 BARRIER_IF_VOLATILE (td
);
2791 SIMPLE_OP (td
, MINT_STIND_I2
);
2795 CHECK_STACK (td
, 2);
2796 BARRIER_IF_VOLATILE (td
);
2797 SIMPLE_OP (td
, MINT_STIND_I4
);
2801 CHECK_STACK (td
, 2);
2802 BARRIER_IF_VOLATILE (td
);
2803 SIMPLE_OP (td
, MINT_STIND_I
);
2807 CHECK_STACK (td
, 2);
2808 BARRIER_IF_VOLATILE (td
);
2809 SIMPLE_OP (td
, MINT_STIND_I8
);
2813 CHECK_STACK (td
, 2);
2814 BARRIER_IF_VOLATILE (td
);
2815 SIMPLE_OP (td
, MINT_STIND_R4
);
2819 CHECK_STACK (td
, 2);
2820 BARRIER_IF_VOLATILE (td
);
2821 SIMPLE_OP (td
, MINT_STIND_R8
);
2825 binary_arith_op(td
, MINT_ADD_I4
);
2829 binary_arith_op(td
, MINT_SUB_I4
);
2833 binary_arith_op(td
, MINT_MUL_I4
);
2837 binary_arith_op(td
, MINT_DIV_I4
);
2841 binary_arith_op(td
, MINT_DIV_UN_I4
);
2845 binary_arith_op (td
, MINT_REM_I4
);
2849 binary_arith_op (td
, MINT_REM_UN_I4
);
2853 binary_arith_op (td
, MINT_AND_I4
);
2857 binary_arith_op (td
, MINT_OR_I4
);
2861 binary_arith_op (td
, MINT_XOR_I4
);
2865 shift_op (td
, MINT_SHL_I4
);
2869 shift_op (td
, MINT_SHR_I4
);
2873 shift_op (td
, MINT_SHR_UN_I4
);
2877 unary_arith_op (td
, MINT_NEG_I4
);
2881 unary_arith_op (td
, MINT_NOT_I4
);
2885 CHECK_STACK (td
, 1);
2886 switch (td
->sp
[-1].type
) {
2888 ADD_CODE (td
, MINT_CONV_U1_R4
);
2891 ADD_CODE(td
, MINT_CONV_U1_R8
);
2894 ADD_CODE(td
, MINT_CONV_U1_I4
);
2897 ADD_CODE(td
, MINT_CONV_U1_I8
);
2900 g_assert_not_reached ();
2903 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
2906 CHECK_STACK (td
, 1);
2907 switch (td
->sp
[-1].type
) {
2909 ADD_CODE(td
, MINT_CONV_I1_R4
);
2912 ADD_CODE(td
, MINT_CONV_I1_R8
);
2915 ADD_CODE(td
, MINT_CONV_I1_I4
);
2918 ADD_CODE(td
, MINT_CONV_I1_I8
);
2921 g_assert_not_reached ();
2924 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
2927 CHECK_STACK (td
, 1);
2928 switch (td
->sp
[-1].type
) {
2930 ADD_CODE(td
, MINT_CONV_U2_R4
);
2933 ADD_CODE(td
, MINT_CONV_U2_R8
);
2936 ADD_CODE(td
, MINT_CONV_U2_I4
);
2939 ADD_CODE(td
, MINT_CONV_U2_I8
);
2942 g_assert_not_reached ();
2945 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
2948 CHECK_STACK (td
, 1);
2949 switch (td
->sp
[-1].type
) {
2951 ADD_CODE(td
, MINT_CONV_I2_R4
);
2954 ADD_CODE(td
, MINT_CONV_I2_R8
);
2957 ADD_CODE(td
, MINT_CONV_I2_I4
);
2960 ADD_CODE(td
, MINT_CONV_I2_I8
);
2963 g_assert_not_reached ();
2966 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
2969 CHECK_STACK (td
, 1);
2970 switch (td
->sp
[-1].type
) {
2972 #if SIZEOF_VOID_P == 4
2973 ADD_CODE(td
, MINT_CONV_U4_R8
);
2975 ADD_CODE(td
, MINT_CONV_U8_R8
);
2979 #if SIZEOF_VOID_P == 8
2980 ADD_CODE(td
, MINT_CONV_U8_I4
);
2984 #if SIZEOF_VOID_P == 4
2985 ADD_CODE(td
, MINT_CONV_U4_I8
);
2992 g_assert_not_reached ();
2995 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I
);
2998 CHECK_STACK (td
, 1);
2999 switch (td
->sp
[-1].type
) {
3001 #if SIZEOF_VOID_P == 8
3002 ADD_CODE(td
, MINT_CONV_I8_R8
);
3004 ADD_CODE(td
, MINT_CONV_I4_R8
);
3008 #if SIZEOF_VOID_P == 8
3009 ADD_CODE(td
, MINT_CONV_I8_I4
);
3017 #if SIZEOF_VOID_P == 4
3018 ADD_CODE(td
, MINT_CONV_I4_I8
);
3022 g_assert_not_reached ();
3025 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I
);
3028 CHECK_STACK (td
, 1);
3029 switch (td
->sp
[-1].type
) {
3031 ADD_CODE(td
, MINT_CONV_U4_R4
);
3034 ADD_CODE(td
, MINT_CONV_U4_R8
);
3039 ADD_CODE(td
, MINT_CONV_U4_I8
);
3042 #if SIZEOF_VOID_P == 8
3043 ADD_CODE(td
, MINT_CONV_U4_I8
);
3047 g_assert_not_reached ();
3050 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3053 CHECK_STACK (td
, 1);
3054 switch (td
->sp
[-1].type
) {
3056 ADD_CODE (td
, MINT_CONV_I4_R4
);
3059 ADD_CODE(td
, MINT_CONV_I4_R8
);
3064 ADD_CODE(td
, MINT_CONV_I4_I8
);
3067 #if SIZEOF_VOID_P == 8
3068 ADD_CODE(td
, MINT_CONV_I4_I8
);
3072 g_assert_not_reached ();
3075 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3078 CHECK_STACK (td
, 1);
3079 switch (td
->sp
[-1].type
) {
3081 ADD_CODE(td
, MINT_CONV_I8_R4
);
3084 ADD_CODE(td
, MINT_CONV_I8_R8
);
3087 ADD_CODE(td
, MINT_CONV_I8_I4
);
3092 #if SIZEOF_VOID_P == 4
3093 ADD_CODE(td
, MINT_CONV_I8_I4
);
3097 g_assert_not_reached ();
3100 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
3103 CHECK_STACK (td
, 1);
3104 switch (td
->sp
[-1].type
) {
3106 ADD_CODE(td
, MINT_CONV_R4_R8
);
3109 ADD_CODE(td
, MINT_CONV_R4_I8
);
3112 ADD_CODE(td
, MINT_CONV_R4_I4
);
3118 g_assert_not_reached ();
3121 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R4
);
3124 CHECK_STACK (td
, 1);
3125 switch (td
->sp
[-1].type
) {
3127 ADD_CODE(td
, MINT_CONV_R8_I4
);
3130 ADD_CODE(td
, MINT_CONV_R8_I8
);
3133 ADD_CODE (td
, MINT_CONV_R8_R4
);
3138 g_assert_not_reached ();
3141 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
3144 CHECK_STACK (td
, 1);
3145 switch (td
->sp
[-1].type
) {
3147 ADD_CODE(td
, MINT_CONV_U8_I4
);
3152 ADD_CODE (td
, MINT_CONV_U8_R4
);
3155 ADD_CODE(td
, MINT_CONV_U8_R8
);
3158 #if SIZEOF_VOID_P == 4
3159 ADD_CODE(td
, MINT_CONV_U8_I4
);
3163 g_assert_not_reached ();
3166 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
3169 CHECK_STACK (td
, 2);
3171 token
= read32 (td
->ip
+ 1);
3172 klass
= mono_class_get_and_inflate_typespec_checked (image
, token
, generic_context
, error
);
3173 goto_if_nok (error
, exit
);
3175 if (m_class_is_valuetype (klass
)) {
3176 int mt
= mint_type (m_class_get_byval_arg (klass
));
3177 ADD_CODE (td
, (mt
== MINT_TYPE_VT
) ? MINT_CPOBJ_VT
: MINT_CPOBJ
);
3178 ADD_CODE (td
, get_data_item_index(td
, klass
));
3180 ADD_CODE (td
, MINT_LDIND_REF
);
3181 ADD_CODE (td
, MINT_STIND_REF
);
3189 CHECK_STACK (td
, 1);
3191 token
= read32 (td
->ip
+ 1);
3193 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
3194 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
3196 klass
= mono_class_get_and_inflate_typespec_checked (image
, token
, generic_context
, error
);
3197 goto_if_nok (error
, exit
);
3200 MonoClass
*tos_klass
= td
->sp
[-1].klass
;
3201 if (tos_klass
&& td
->sp
[-1].type
== STACK_TYPE_VT
) {
3202 int tos_size
= mono_class_value_size (tos_klass
, NULL
);
3203 POP_VT (td
, tos_size
);
3206 int mt
= mint_type (m_class_get_byval_arg (klass
));
3208 ADD_CODE(td
, (mt
== MINT_TYPE_VT
) ? MINT_LDOBJ_VT
: MINT_LDOBJ
);
3209 ADD_CODE(td
, get_data_item_index(td
, klass
));
3211 if (mt
== MINT_TYPE_VT
) {
3212 size
= mono_class_value_size (klass
, NULL
);
3216 SET_TYPE (td
->sp
- 1, stack_type
[mt
], klass
);
3217 BARRIER_IF_VOLATILE (td
);
3221 token
= mono_metadata_token_index (read32 (td
->ip
+ 1));
3223 if (method
->wrapper_type
== MONO_WRAPPER_NONE
) {
3224 MonoString
*s
= mono_ldstr_checked (domain
, image
, token
, error
);
3225 goto_if_nok (error
, exit
);
3226 /* GC won't scan code stream, but reference is held by metadata
3227 * machinery so we are good here */
3228 ADD_CODE (td
, MINT_LDSTR
);
3229 ADD_CODE (td
, get_data_item_index (td
, s
));
3231 /* defer allocation to execution-time */
3232 ADD_CODE (td
, MINT_LDSTR_TOKEN
);
3233 ADD_CODE (td
, get_data_item_index (td
, GUINT_TO_POINTER (token
)));
3235 PUSH_TYPE(td
, STACK_TYPE_O
, mono_defaults
.string_class
);
3240 MonoMethodSignature
*csignature
;
3241 guint32 vt_stack_used
= 0;
3242 guint32 vt_res_size
= 0;
3245 token
= read32 (td
->ip
);
3248 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
3249 m
= (MonoMethod
*)mono_method_get_wrapper_data (method
, token
);
3251 m
= mono_get_method_checked (image
, token
, NULL
, generic_context
, error
);
3252 goto_if_nok (error
, exit
);
3255 csignature
= mono_method_signature_internal (m
);
3258 if (!mono_class_init (klass
)) {
3259 mono_error_set_for_class_failure (error
, klass
);
3260 goto_if_nok (error
, exit
);
3263 if (mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_ABSTRACT
) {
3264 char* full_name
= mono_type_get_full_name (klass
);
3265 mono_error_set_member_access (error
, "Cannot create an abstract class: %s", full_name
);
3267 goto_if_nok (error
, exit
);
3270 td
->sp
-= csignature
->param_count
;
3271 if (mono_class_is_magic_int (klass
) || mono_class_is_magic_float (klass
)) {
3272 #if SIZEOF_VOID_P == 8
3273 if (mono_class_is_magic_int (klass
) && td
->sp
[0].type
== STACK_TYPE_I4
)
3274 ADD_CODE (td
, MINT_CONV_I8_I4
);
3275 else if (mono_class_is_magic_float (klass
) && td
->sp
[0].type
== STACK_TYPE_R4
)
3276 ADD_CODE (td
, MINT_CONV_R8_R4
);
3278 ADD_CODE (td
, MINT_NEWOBJ_MAGIC
);
3279 ADD_CODE (td
, get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
)));
3280 goto_if_nok (error
, exit
);
3282 PUSH_TYPE (td
, stack_type
[mint_type (m_class_get_byval_arg (klass
))], klass
);
3284 if (m_class_get_parent (klass
) == mono_defaults
.array_class
) {
3285 ADD_CODE(td
, MINT_NEWOBJ_ARRAY
);
3286 ADD_CODE(td
, get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
)));
3287 ADD_CODE(td
, csignature
->param_count
);
3288 } else if (m_class_get_image (klass
) == mono_defaults
.corlib
&&
3289 !strcmp (m_class_get_name (m
->klass
), "ByReference`1") &&
3290 !strcmp (m
->name
, ".ctor")) {
3291 /* public ByReference(ref T value) */
3292 g_assert (csignature
->hasthis
&& csignature
->param_count
== 1);
3293 ADD_CODE(td
, MINT_INTRINS_BYREFERENCE_CTOR
);
3294 ADD_CODE(td
, get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
)));
3295 } else if (klass
!= mono_defaults
.string_class
&&
3296 !mono_class_is_marshalbyref (klass
) &&
3297 !mono_class_has_finalizer (klass
) &&
3298 !m_class_has_weak_fields (klass
)) {
3299 if (!m_class_is_valuetype (klass
))
3300 ADD_CODE(td
, MINT_NEWOBJ_FAST
);
3301 else if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
)
3302 ADD_CODE(td
, MINT_NEWOBJ_VTST_FAST
);
3304 ADD_CODE(td
, MINT_NEWOBJ_VT_FAST
);
3306 ADD_CODE(td
, get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
)));
3307 ADD_CODE(td
, csignature
->param_count
);
3309 if (!m_class_is_valuetype (klass
)) {
3310 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, klass
, error
);
3311 goto_if_nok (error
, exit
);
3312 ADD_CODE(td
, get_data_item_index (td
, vtable
));
3313 } else if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
) {
3314 ADD_CODE(td
, mono_class_value_size (klass
, NULL
));
3317 ADD_CODE(td
, MINT_NEWOBJ
);
3318 ADD_CODE(td
, get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
)));
3320 goto_if_nok (error
, exit
);
3322 if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
) {
3323 vt_res_size
= mono_class_value_size (klass
, NULL
);
3324 PUSH_VT (td
, vt_res_size
);
3326 for (i
= 0; i
< csignature
->param_count
; ++i
) {
3327 int mt
= mint_type(csignature
->params
[i
]);
3328 if (mt
== MINT_TYPE_VT
) {
3329 MonoClass
*k
= mono_class_from_mono_type_internal (csignature
->params
[i
]);
3330 gint32 size
= mono_class_value_size (k
, NULL
);
3331 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
3332 vt_stack_used
+= size
;
3335 if (vt_stack_used
!= 0 || vt_res_size
!= 0) {
3336 ADD_CODE(td
, MINT_VTRESULT
);
3337 ADD_CODE(td
, vt_res_size
);
3338 WRITE32(td
, &vt_stack_used
);
3339 td
->vt_sp
-= vt_stack_used
;
3341 PUSH_TYPE (td
, stack_type
[mint_type (m_class_get_byval_arg (klass
))], klass
);
3346 CHECK_STACK (td
, 1);
3347 token
= read32 (td
->ip
+ 1);
3348 klass
= mini_get_class (method
, token
, generic_context
);
3349 CHECK_TYPELOAD (klass
);
3350 ADD_CODE(td
, MINT_CASTCLASS
);
3351 ADD_CODE(td
, get_data_item_index (td
, klass
));
3352 td
->sp
[-1].klass
= klass
;
3356 CHECK_STACK (td
, 1);
3357 token
= read32 (td
->ip
+ 1);
3358 klass
= mini_get_class (method
, token
, generic_context
);
3359 CHECK_TYPELOAD (klass
);
3360 ADD_CODE(td
, MINT_ISINST
);
3361 ADD_CODE(td
, get_data_item_index (td
, klass
));
3365 switch (td
->sp
[-1].type
) {
3369 ADD_CODE(td
, MINT_CONV_R_UN_I8
);
3372 ADD_CODE(td
, MINT_CONV_R_UN_I4
);
3375 g_assert_not_reached ();
3377 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
3381 CHECK_STACK (td
, 1);
3382 token
= read32 (td
->ip
+ 1);
3384 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
3385 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
3387 klass
= mono_class_get_and_inflate_typespec_checked (image
, token
, generic_context
, error
);
3388 goto_if_nok (error
, exit
);
3391 if (mono_class_is_nullable (klass
)) {
3392 MonoMethod
*target_method
;
3393 if (m_class_is_enumtype (mono_class_get_nullable_param (klass
)))
3394 target_method
= mono_class_get_method_from_name_checked (klass
, "UnboxExact", 1, 0, error
);
3396 target_method
= mono_class_get_method_from_name_checked (klass
, "Unbox", 1, 0, error
);
3397 goto_if_nok (error
, exit
);
3398 /* td->ip is incremented by interp_transform_call */
3399 interp_transform_call (td
, method
, target_method
, domain
, generic_context
, is_bb_start
, body_start_offset
, NULL
, FALSE
, error
, FALSE
);
3400 goto_if_nok (error
, exit
);
3402 * CEE_UNBOX needs to push address of vtype while Nullable.Unbox returns the value type
3403 * We create a local variable in the frame so that we can fetch its address.
3405 int local_offset
= create_interp_local (td
, m_class_get_byval_arg (klass
));
3406 store_local_general (td
, local_offset
, m_class_get_byval_arg (klass
));
3407 ADD_CODE (td
, MINT_LDLOCA_S
);
3408 ADD_CODE (td
, local_offset
);
3409 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_MP
);
3411 ADD_CODE (td
, MINT_UNBOX
);
3412 ADD_CODE (td
, get_data_item_index (td
, klass
));
3413 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_MP
);
3418 CHECK_STACK (td
, 1);
3419 token
= read32 (td
->ip
+ 1);
3421 klass
= mini_get_class (method
, token
, generic_context
);
3422 CHECK_TYPELOAD (klass
);
3424 if (mini_type_is_reference (m_class_get_byval_arg (klass
))) {
3425 int mt
= mint_type (m_class_get_byval_arg (klass
));
3426 ADD_CODE (td
, MINT_CASTCLASS
);
3427 ADD_CODE (td
, get_data_item_index (td
, klass
));
3428 SET_TYPE (td
->sp
- 1, stack_type
[mt
], klass
);
3430 } else if (mono_class_is_nullable (klass
)) {
3431 MonoMethod
*target_method
;
3432 if (m_class_is_enumtype (mono_class_get_nullable_param (klass
)))
3433 target_method
= mono_class_get_method_from_name_checked (klass
, "UnboxExact", 1, 0, error
);
3435 target_method
= mono_class_get_method_from_name_checked (klass
, "Unbox", 1, 0, error
);
3436 goto_if_nok (error
, exit
);
3437 /* td->ip is incremented by interp_transform_call */
3438 interp_transform_call (td
, method
, target_method
, domain
, generic_context
, is_bb_start
, body_start_offset
, NULL
, FALSE
, error
, FALSE
);
3440 goto_if_nok (error
, exit
);
3442 int mt
= mint_type (m_class_get_byval_arg (klass
));
3443 ADD_CODE (td
, MINT_UNBOX
);
3444 ADD_CODE (td
, get_data_item_index (td
, klass
));
3446 ADD_CODE (td
, (mt
== MINT_TYPE_VT
) ? MINT_LDOBJ_VT
: MINT_LDOBJ
);
3447 ADD_CODE (td
, get_data_item_index(td
, klass
));
3448 SET_TYPE (td
->sp
- 1, stack_type
[mt
], klass
);
3450 if (mt
== MINT_TYPE_VT
) {
3451 int size
= mono_class_value_size (klass
, NULL
);
3459 CHECK_STACK (td
, 1);
3460 SIMPLE_OP (td
, MINT_THROW
);
3464 CHECK_STACK (td
, 1);
3465 token
= read32 (td
->ip
+ 1);
3466 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
3467 goto_if_nok (error
, exit
);
3468 MonoType
*ftype
= mono_field_get_type_internal (field
);
3469 gboolean is_static
= !!(ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
);
3470 mono_class_init (klass
);
3471 #ifndef DISABLE_REMOTING
3472 if (m_class_get_marshalbyref (klass
) || mono_class_is_contextbound (klass
) || klass
== mono_defaults
.marshalbyrefobject_class
) {
3473 g_assert (!is_static
);
3474 int offset
= m_class_is_valuetype (klass
) ? field
->offset
- MONO_ABI_SIZEOF (MonoObject
) : field
->offset
;
3476 ADD_CODE (td
, MINT_MONO_LDPTR
);
3477 ADD_CODE (td
, get_data_item_index (td
, klass
));
3478 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
3479 ADD_CODE (td
, MINT_MONO_LDPTR
);
3480 ADD_CODE (td
, get_data_item_index (td
, field
));
3481 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
3482 ADD_CODE (td
, MINT_LDC_I4
);
3483 WRITE32 (td
, &offset
);
3484 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I4
);
3485 #if SIZEOF_VOID_P == 8
3486 ADD_CODE(td
, MINT_CONV_I8_I4
);
3489 MonoMethod
*wrapper
= mono_marshal_get_ldflda_wrapper (field
->type
);
3490 /* td->ip is incremented by interp_transform_call */
3491 interp_transform_call (td
, method
, wrapper
, domain
, generic_context
, is_bb_start
, body_start_offset
, NULL
, FALSE
, error
, FALSE
);
3492 goto_if_nok (error
, exit
);
3497 ADD_CODE (td
, MINT_POP
);
3499 ADD_CODE (td
, MINT_LDSFLDA
);
3500 ADD_CODE (td
, get_data_item_index (td
, field
));
3502 if ((td
->sp
- 1)->type
== STACK_TYPE_O
) {
3503 ADD_CODE (td
, MINT_LDFLDA
);
3505 g_assert ((td
->sp
-1)->type
== STACK_TYPE_MP
);
3506 ADD_CODE (td
, MINT_LDFLDA_UNSAFE
);
3508 ADD_CODE (td
, m_class_is_valuetype (klass
) ? field
->offset
- MONO_ABI_SIZEOF (MonoObject
) : field
->offset
);
3512 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
3516 CHECK_STACK (td
, 1);
3517 token
= read32 (td
->ip
+ 1);
3518 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
3519 goto_if_nok (error
, exit
);
3520 MonoType
*ftype
= mono_field_get_type_internal (field
);
3521 gboolean is_static
= !!(ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
);
3522 mono_class_init (klass
);
3524 MonoClass
*field_klass
= mono_class_from_mono_type_internal (ftype
);
3525 mt
= mint_type (m_class_get_byval_arg (field_klass
));
3526 #ifndef DISABLE_REMOTING
3527 if (m_class_get_marshalbyref (klass
)) {
3528 g_assert (!is_static
);
3529 ADD_CODE(td
, mt
== MINT_TYPE_VT
? MINT_LDRMFLD_VT
: MINT_LDRMFLD
);
3530 ADD_CODE(td
, get_data_item_index (td
, field
));
3535 ADD_CODE (td
, MINT_POP
);
3537 ADD_CODE (td
, mt
== MINT_TYPE_VT
? MINT_LDSFLD_VT
: MINT_LDSFLD
);
3538 ADD_CODE (td
, get_data_item_index (td
, field
));
3540 ADD_CODE (td
, MINT_LDFLD_I1
+ mt
- MINT_TYPE_I1
);
3541 ADD_CODE (td
, m_class_is_valuetype (klass
) ? field
->offset
- MONO_ABI_SIZEOF (MonoObject
) : field
->offset
);
3542 if (mt
== MINT_TYPE_VT
)
3543 ADD_CODE (td
, get_data_item_index (td
, field
));
3546 if (mt
== MINT_TYPE_VT
) {
3547 int size
= mono_class_value_size (field_klass
, NULL
);
3550 if (td
->sp
[-1].type
== STACK_TYPE_VT
) {
3551 int size
= mono_class_value_size (klass
, NULL
);
3552 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
3553 int field_vt_size
= 0;
3554 if (mt
== MINT_TYPE_VT
) {
3556 * Pop the loaded field from the vtstack (it will still be present
3557 * at the same vtstack address) and we will load it in place of the
3558 * containing valuetype with the second MINT_VTRESULT.
3560 field_vt_size
= mono_class_value_size (field_klass
, NULL
);
3561 field_vt_size
= ALIGN_TO (field_vt_size
, MINT_VT_ALIGNMENT
);
3562 ADD_CODE (td
, MINT_VTRESULT
);
3564 WRITE32 (td
, &field_vt_size
);
3567 ADD_CODE (td
, MINT_VTRESULT
);
3568 ADD_CODE (td
, field_vt_size
);
3569 WRITE32 (td
, &size
);
3572 SET_TYPE (td
->sp
- 1, stack_type
[mt
], field_klass
);
3573 BARRIER_IF_VOLATILE (td
);
3577 CHECK_STACK (td
, 2);
3578 token
= read32 (td
->ip
+ 1);
3579 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
3580 goto_if_nok (error
, exit
);
3581 MonoType
*ftype
= mono_field_get_type_internal (field
);
3582 gboolean is_static
= !!(ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
);
3583 mono_class_init (klass
);
3584 mt
= mint_type (ftype
);
3586 BARRIER_IF_VOLATILE (td
);
3588 #ifndef DISABLE_REMOTING
3589 if (m_class_get_marshalbyref (klass
)) {
3590 g_assert (!is_static
);
3591 ADD_CODE(td
, mt
== MINT_TYPE_VT
? MINT_STRMFLD_VT
: MINT_STRMFLD
);
3592 ADD_CODE(td
, get_data_item_index (td
, field
));
3597 ADD_CODE (td
, MINT_POP
);
3599 ADD_CODE (td
, mt
== MINT_TYPE_VT
? MINT_STSFLD_VT
: MINT_STSFLD
);
3600 ADD_CODE (td
, get_data_item_index (td
, field
));
3602 /* the vtable of the field might not be initialized at this point */
3603 MonoClass
*fld_klass
= mono_class_from_mono_type_internal (field
->type
);
3604 mono_class_vtable_checked (domain
, fld_klass
, error
);
3605 goto_if_nok (error
, exit
);
3607 ADD_CODE (td
, MINT_STFLD_I1
+ mt
- MINT_TYPE_I1
);
3608 ADD_CODE (td
, m_class_is_valuetype (klass
) ? field
->offset
- MONO_ABI_SIZEOF (MonoObject
) : field
->offset
);
3609 if (mt
== MINT_TYPE_VT
) {
3610 ADD_CODE (td
, get_data_item_index (td
, field
));
3612 /* the vtable of the field might not be initialized at this point */
3613 MonoClass
*fld_klass
= mono_class_from_mono_type_internal (field
->type
);
3614 mono_class_vtable_checked (domain
, fld_klass
, error
);
3615 goto_if_nok (error
, exit
);
3619 if (mt
== MINT_TYPE_VT
) {
3620 MonoClass
*klass
= mono_class_from_mono_type_internal (ftype
);
3621 int size
= mono_class_value_size (klass
, NULL
);
3629 token
= read32 (td
->ip
+ 1);
3630 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
3631 goto_if_nok (error
, exit
);
3632 mono_field_get_type_internal (field
);
3633 ADD_CODE(td
, MINT_LDSFLDA
);
3634 ADD_CODE(td
, get_data_item_index (td
, field
));
3636 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
3640 token
= read32 (td
->ip
+ 1);
3641 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
3642 goto_if_nok (error
, exit
);
3643 MonoType
*ftype
= mono_field_get_type_internal (field
);
3644 mt
= mint_type (ftype
);
3646 if (mt
== MINT_TYPE_VT
) {
3647 ADD_CODE(td
, MINT_LDSFLD_VT
);
3648 ADD_CODE(td
, get_data_item_index (td
, field
));
3649 klass
= mono_class_from_mono_type_internal (ftype
);
3650 int size
= mono_class_value_size (klass
, NULL
);
3654 if (mono_class_field_is_special_static (field
)) {
3655 ADD_CODE(td
, MINT_LDSFLD
);
3656 ADD_CODE(td
, get_data_item_index (td
, field
));
3658 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, field
->parent
, error
);
3659 goto_if_nok (error
, exit
);
3661 ADD_CODE(td
, MINT_LDSFLD_I1
+ mt
- MINT_TYPE_I1
);
3662 ADD_CODE(td
, get_data_item_index (td
, vtable
));
3663 ADD_CODE(td
, get_data_item_index (td
, (char*)mono_vtable_get_static_field_data (vtable
) + field
->offset
));
3665 if (mt
== MINT_TYPE_O
)
3666 klass
= mono_class_from_mono_type_internal (ftype
);
3669 PUSH_TYPE(td
, stack_type
[mt
], klass
);
3673 CHECK_STACK (td
, 1);
3674 token
= read32 (td
->ip
+ 1);
3675 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
3676 goto_if_nok (error
, exit
);
3677 MonoType
*ftype
= mono_field_get_type_internal (field
);
3678 mt
= mint_type (ftype
);
3680 /* the vtable of the field might not be initialized at this point */
3681 MonoClass
*fld_klass
= mono_class_from_mono_type_internal (field
->type
);
3682 mono_class_vtable_checked (domain
, fld_klass
, error
);
3683 goto_if_nok (error
, exit
);
3685 if (mt
== MINT_TYPE_VT
) {
3686 MonoClass
*klass
= mono_class_from_mono_type_internal (ftype
);
3687 int size
= mono_class_value_size (klass
, NULL
);
3688 ADD_CODE(td
, MINT_STSFLD_VT
);
3689 ADD_CODE(td
, get_data_item_index (td
, field
));
3692 if (mono_class_field_is_special_static (field
)) {
3693 ADD_CODE(td
, MINT_STSFLD
);
3694 ADD_CODE(td
, get_data_item_index (td
, field
));
3696 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, field
->parent
, error
);
3697 goto_if_nok (error
, exit
);
3699 ADD_CODE(td
, MINT_STSFLD_I1
+ mt
- MINT_TYPE_I1
);
3700 ADD_CODE(td
, get_data_item_index (td
, vtable
));
3701 ADD_CODE(td
, get_data_item_index (td
, (char*)mono_vtable_get_static_field_data (vtable
) + field
->offset
));
3711 token
= read32 (td
->ip
+ 1);
3713 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
3714 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
3716 klass
= mini_get_class (method
, token
, generic_context
);
3717 CHECK_TYPELOAD (klass
);
3719 BARRIER_IF_VOLATILE (td
);
3720 ADD_CODE(td
, td
->sp
[-1].type
== STACK_TYPE_VT
? MINT_STOBJ_VT
: MINT_STOBJ
);
3721 ADD_CODE(td
, get_data_item_index (td
, klass
));
3722 if (td
->sp
[-1].type
== STACK_TYPE_VT
) {
3723 size
= mono_class_value_size (klass
, NULL
);
3730 case CEE_CONV_OVF_I_UN
:
3731 case CEE_CONV_OVF_U_UN
:
3732 CHECK_STACK (td
, 1);
3733 switch (td
->sp
[-1].type
) {
3735 #if SIZEOF_VOID_P == 8
3736 ADD_CODE(td
, MINT_CONV_OVF_I8_UN_R8
);
3738 ADD_CODE(td
, MINT_CONV_OVF_I4_UN_R8
);
3742 #if SIZEOF_VOID_P == 4
3743 ADD_CODE (td
, MINT_CONV_OVF_I4_UN_I8
);
3747 #if SIZEOF_VOID_P == 8
3748 ADD_CODE(td
, MINT_CONV_I8_U4
);
3749 #elif SIZEOF_VOID_P == 4
3750 if (*td
->ip
== CEE_CONV_OVF_I_UN
)
3751 ADD_CODE(td
, MINT_CONV_OVF_I4_U4
);
3755 g_assert_not_reached ();
3758 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
3761 case CEE_CONV_OVF_I8_UN
:
3762 case CEE_CONV_OVF_U8_UN
:
3763 CHECK_STACK (td
, 1);
3764 switch (td
->sp
[-1].type
) {
3766 ADD_CODE(td
, MINT_CONV_OVF_I8_UN_R8
);
3769 if (*td
->ip
== CEE_CONV_OVF_I8_UN
)
3770 ADD_CODE (td
, MINT_CONV_OVF_I8_U8
);
3773 ADD_CODE(td
, MINT_CONV_I8_U4
);
3776 g_assert_not_reached ();
3779 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
3784 CHECK_STACK (td
, 1);
3785 token
= read32 (td
->ip
+ 1);
3786 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
3787 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
3789 klass
= mini_get_class (method
, token
, generic_context
);
3790 CHECK_TYPELOAD (klass
);
3792 if (mono_class_is_nullable (klass
)) {
3793 MonoMethod
*target_method
= mono_class_get_method_from_name_checked (klass
, "Box", 1, 0, error
);
3794 goto_if_nok (error
, exit
);
3795 /* td->ip is incremented by interp_transform_call */
3796 interp_transform_call (td
, method
, target_method
, domain
, generic_context
, is_bb_start
, body_start_offset
, NULL
, FALSE
, error
, FALSE
);
3797 goto_if_nok (error
, exit
);
3798 } else if (!m_class_is_valuetype (klass
)) {
3799 /* already boxed, do nothing. */
3802 if (G_UNLIKELY (m_class_is_byreflike (klass
))) {
3803 mono_error_set_bad_image (error
, image
, "Cannot box IsByRefLike type '%s.%s'", m_class_get_name_space (klass
), m_class_get_name (klass
));
3806 if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
&& !m_class_is_enumtype (klass
)) {
3807 size
= mono_class_value_size (klass
, NULL
);
3808 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
3810 } else if (td
->sp
[-1].type
== STACK_TYPE_R8
&& m_class_get_byval_arg (klass
)->type
== MONO_TYPE_R4
) {
3811 ADD_CODE (td
, MINT_CONV_R4_R8
);
3813 if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
)
3814 ADD_CODE (td
, MINT_BOX_VT
);
3816 ADD_CODE (td
, MINT_BOX
);
3817 ADD_CODE(td
, get_data_item_index (td
, klass
));
3819 SET_TYPE(td
->sp
- 1, STACK_TYPE_O
, klass
);
3826 CHECK_STACK (td
, 1);
3827 token
= read32 (td
->ip
+ 1);
3829 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
3830 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
3832 klass
= mini_get_class (method
, token
, generic_context
);
3833 CHECK_TYPELOAD (klass
);
3835 unsigned char lentype
= (td
->sp
- 1)->type
;
3836 if (lentype
== STACK_TYPE_I8
) {
3837 /* mimic mini behaviour */
3838 ADD_CODE (td
, MINT_CONV_OVF_U4_I8
);
3840 g_assert (lentype
== STACK_TYPE_I4
);
3841 ADD_CODE (td
, MINT_CONV_OVF_U4_I4
);
3843 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I4
);
3844 ADD_CODE (td
, MINT_NEWARR
);
3845 ADD_CODE (td
, get_data_item_index (td
, klass
));
3846 SET_TYPE (td
->sp
- 1, STACK_TYPE_O
, klass
);
3851 CHECK_STACK (td
, 1);
3852 SIMPLE_OP (td
, MINT_LDLEN
);
3853 #ifdef MONO_BIG_ARRAYS
3854 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I8
);
3856 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I4
);
3860 CHECK_STACK (td
, 2);
3862 token
= read32 (td
->ip
+ 1);
3864 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
3865 klass
= (MonoClass
*) mono_method_get_wrapper_data (method
, token
);
3867 klass
= mini_get_class (method
, token
, generic_context
);
3869 CHECK_TYPELOAD (klass
);
3871 if (!m_class_is_valuetype (klass
) && method
->wrapper_type
== MONO_WRAPPER_NONE
&& !readonly
) {
3873 * Check the class for failures before the type check, which can
3874 * throw other exceptions.
3876 mono_class_setup_vtable (klass
);
3877 CHECK_TYPELOAD (klass
);
3878 ADD_CODE (td
, MINT_LDELEMA_TC
);
3880 ADD_CODE (td
, MINT_LDELEMA
);
3882 ADD_CODE (td
, get_data_item_index (td
, klass
));
3883 /* according to spec, ldelema bytecode is only used for 1-dim arrays */
3889 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
3892 CHECK_STACK (td
, 2);
3894 SIMPLE_OP (td
, MINT_LDELEM_I1
);
3896 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3899 CHECK_STACK (td
, 2);
3901 SIMPLE_OP (td
, MINT_LDELEM_U1
);
3903 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3906 CHECK_STACK (td
, 2);
3908 SIMPLE_OP (td
, MINT_LDELEM_I2
);
3910 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3913 CHECK_STACK (td
, 2);
3915 SIMPLE_OP (td
, MINT_LDELEM_U2
);
3917 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3920 CHECK_STACK (td
, 2);
3922 SIMPLE_OP (td
, MINT_LDELEM_I4
);
3924 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3927 CHECK_STACK (td
, 2);
3929 SIMPLE_OP (td
, MINT_LDELEM_U4
);
3931 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3934 CHECK_STACK (td
, 2);
3936 SIMPLE_OP (td
, MINT_LDELEM_I8
);
3938 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
3941 CHECK_STACK (td
, 2);
3943 SIMPLE_OP (td
, MINT_LDELEM_I
);
3945 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I
);
3948 CHECK_STACK (td
, 2);
3950 SIMPLE_OP (td
, MINT_LDELEM_R4
);
3952 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R4
);
3955 CHECK_STACK (td
, 2);
3957 SIMPLE_OP (td
, MINT_LDELEM_R8
);
3959 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
3961 case CEE_LDELEM_REF
:
3962 CHECK_STACK (td
, 2);
3964 SIMPLE_OP (td
, MINT_LDELEM_REF
);
3966 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_O
);
3969 CHECK_STACK (td
, 2);
3970 token
= read32 (td
->ip
+ 1);
3971 klass
= mini_get_class (method
, token
, generic_context
);
3972 CHECK_TYPELOAD (klass
);
3973 switch (mint_type (m_class_get_byval_arg (klass
))) {
3976 SIMPLE_OP (td
, MINT_LDELEM_I1
);
3978 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3982 SIMPLE_OP (td
, MINT_LDELEM_U1
);
3984 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3988 SIMPLE_OP (td
, MINT_LDELEM_U2
);
3990 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3994 SIMPLE_OP (td
, MINT_LDELEM_I2
);
3996 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4000 SIMPLE_OP (td
, MINT_LDELEM_I4
);
4002 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4006 SIMPLE_OP (td
, MINT_LDELEM_I8
);
4008 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
4012 SIMPLE_OP (td
, MINT_LDELEM_R4
);
4014 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R4
);
4018 SIMPLE_OP (td
, MINT_LDELEM_R8
);
4020 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
4024 SIMPLE_OP (td
, MINT_LDELEM_REF
);
4026 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_O
);
4028 case MINT_TYPE_VT
: {
4029 int size
= mono_class_value_size (klass
, NULL
);
4031 SIMPLE_OP (td
, MINT_LDELEM_VT
);
4032 ADD_CODE (td
, get_data_item_index (td
, klass
));
4033 WRITE32 (td
, &size
);
4035 SET_TYPE (td
->sp
- 1, STACK_TYPE_VT
, klass
);
4040 GString
*res
= g_string_new ("");
4041 mono_type_get_desc (res
, m_class_get_byval_arg (klass
), TRUE
);
4042 g_print ("LDELEM: %s -> %d (%s)\n", m_class_get_name (klass
), mint_type (m_class_get_byval_arg (klass
)), res
->str
);
4043 g_string_free (res
, TRUE
);
4051 CHECK_STACK (td
, 3);
4053 SIMPLE_OP (td
, MINT_STELEM_I
);
4057 CHECK_STACK (td
, 3);
4059 SIMPLE_OP (td
, MINT_STELEM_I1
);
4063 CHECK_STACK (td
, 3);
4065 SIMPLE_OP (td
, MINT_STELEM_I2
);
4069 CHECK_STACK (td
, 3);
4071 SIMPLE_OP (td
, MINT_STELEM_I4
);
4075 CHECK_STACK (td
, 3);
4077 SIMPLE_OP (td
, MINT_STELEM_I8
);
4081 CHECK_STACK (td
, 3);
4083 SIMPLE_OP (td
, MINT_STELEM_R4
);
4087 CHECK_STACK (td
, 3);
4089 SIMPLE_OP (td
, MINT_STELEM_R8
);
4092 case CEE_STELEM_REF
:
4093 CHECK_STACK (td
, 3);
4095 SIMPLE_OP (td
, MINT_STELEM_REF
);
4099 CHECK_STACK (td
, 3);
4101 token
= read32 (td
->ip
+ 1);
4102 klass
= mini_get_class (method
, token
, generic_context
);
4103 CHECK_TYPELOAD (klass
);
4104 switch (mint_type (m_class_get_byval_arg (klass
))) {
4106 SIMPLE_OP (td
, MINT_STELEM_I1
);
4109 SIMPLE_OP (td
, MINT_STELEM_U1
);
4112 SIMPLE_OP (td
, MINT_STELEM_I2
);
4115 SIMPLE_OP (td
, MINT_STELEM_U2
);
4118 SIMPLE_OP (td
, MINT_STELEM_I4
);
4121 SIMPLE_OP (td
, MINT_STELEM_I8
);
4124 SIMPLE_OP (td
, MINT_STELEM_R4
);
4127 SIMPLE_OP (td
, MINT_STELEM_R8
);
4130 SIMPLE_OP (td
, MINT_STELEM_REF
);
4132 case MINT_TYPE_VT
: {
4133 int size
= mono_class_value_size (klass
, NULL
);
4134 SIMPLE_OP (td
, MINT_STELEM_VT
);
4135 ADD_CODE (td
, get_data_item_index (td
, klass
));
4136 WRITE32 (td
, &size
);
4141 GString
*res
= g_string_new ("");
4142 mono_type_get_desc (res
, m_class_get_byval_arg (klass
), TRUE
);
4143 g_print ("STELEM: %s -> %d (%s)\n", m_class_get_name (klass
), mint_type (m_class_get_byval_arg (klass
)), res
->str
);
4144 g_string_free (res
, TRUE
);
4153 case CEE_CONV_OVF_U1
:
4155 case CEE_CONV_OVF_I8
:
4157 #if SIZEOF_VOID_P == 8
4158 case CEE_CONV_OVF_U
:
4162 CHECK_STACK (td
, 1);
4163 SIMPLE_OP (td
, MINT_CKFINITE
);
4166 CHECK_STACK (td
, 1);
4168 token
= read32 (td
->ip
+ 1);
4169 klass
= mini_get_class (method
, token
, generic_context
);
4170 CHECK_TYPELOAD (klass
);
4172 ADD_CODE (td
, MINT_MKREFANY
);
4173 ADD_CODE (td
, get_data_item_index (td
, klass
));
4176 PUSH_VT (td
, sizeof (MonoTypedRef
));
4177 SET_TYPE(td
->sp
- 1, STACK_TYPE_VT
, mono_defaults
.typed_reference_class
);
4179 case CEE_REFANYVAL
: {
4180 CHECK_STACK (td
, 1);
4182 token
= read32 (td
->ip
+ 1);
4183 klass
= mini_get_class (method
, token
, generic_context
);
4184 CHECK_TYPELOAD (klass
);
4186 ADD_CODE (td
, MINT_REFANYVAL
);
4187 ADD_CODE (td
, get_data_item_index (td
, klass
));
4189 POP_VT (td
, sizeof (MonoTypedRef
));
4190 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
4195 case CEE_CONV_OVF_I1
:
4196 case CEE_CONV_OVF_I1_UN
: {
4197 gboolean is_un
= *td
->ip
== CEE_CONV_OVF_I1_UN
;
4198 CHECK_STACK (td
, 1);
4199 switch (td
->sp
[-1].type
) {
4201 ADD_CODE(td
, is_un
? MINT_CONV_OVF_I1_UN_R8
: MINT_CONV_OVF_I1_R8
);
4204 ADD_CODE(td
, is_un
? MINT_CONV_OVF_I1_U4
: MINT_CONV_OVF_I1_I4
);
4207 ADD_CODE(td
, is_un
? MINT_CONV_OVF_I1_U8
: MINT_CONV_OVF_I1_I8
);
4210 g_assert_not_reached ();
4213 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4216 case CEE_CONV_OVF_U1
:
4217 case CEE_CONV_OVF_U1_UN
:
4218 CHECK_STACK (td
, 1);
4219 switch (td
->sp
[-1].type
) {
4221 ADD_CODE(td
, MINT_CONV_OVF_U1_R8
);
4224 ADD_CODE(td
, MINT_CONV_OVF_U1_I4
);
4227 ADD_CODE(td
, MINT_CONV_OVF_U1_I8
);
4230 g_assert_not_reached ();
4233 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4235 case CEE_CONV_OVF_I2
:
4236 case CEE_CONV_OVF_I2_UN
: {
4237 gboolean is_un
= *td
->ip
== CEE_CONV_OVF_I2_UN
;
4238 CHECK_STACK (td
, 1);
4239 switch (td
->sp
[-1].type
) {
4241 ADD_CODE(td
, is_un
? MINT_CONV_OVF_I2_UN_R8
: MINT_CONV_OVF_I2_R8
);
4244 ADD_CODE(td
, is_un
? MINT_CONV_OVF_I2_U4
: MINT_CONV_OVF_I2_I4
);
4247 ADD_CODE(td
, is_un
? MINT_CONV_OVF_I2_U8
: MINT_CONV_OVF_I2_I8
);
4250 g_assert_not_reached ();
4253 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4256 case CEE_CONV_OVF_U2_UN
:
4257 case CEE_CONV_OVF_U2
:
4258 CHECK_STACK (td
, 1);
4259 switch (td
->sp
[-1].type
) {
4261 ADD_CODE(td
, MINT_CONV_OVF_U2_R8
);
4264 ADD_CODE(td
, MINT_CONV_OVF_U2_I4
);
4267 ADD_CODE(td
, MINT_CONV_OVF_U2_I8
);
4270 g_assert_not_reached ();
4273 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4275 #if SIZEOF_VOID_P == 4
4276 case CEE_CONV_OVF_I
:
4278 case CEE_CONV_OVF_I4
:
4279 case CEE_CONV_OVF_I4_UN
:
4280 CHECK_STACK (td
, 1);
4281 switch (td
->sp
[-1].type
) {
4283 ADD_CODE(td
, MINT_CONV_OVF_I4_R4
);
4286 ADD_CODE(td
, MINT_CONV_OVF_I4_R8
);
4289 if (*td
->ip
== CEE_CONV_OVF_I4_UN
)
4290 ADD_CODE(td
, MINT_CONV_OVF_I4_U4
);
4293 if (*td
->ip
== CEE_CONV_OVF_I4_UN
)
4294 ADD_CODE (td
, MINT_CONV_OVF_I4_U8
);
4296 ADD_CODE (td
, MINT_CONV_OVF_I4_I8
);
4299 g_assert_not_reached ();
4302 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4304 #if SIZEOF_VOID_P == 4
4305 case CEE_CONV_OVF_U
:
4307 case CEE_CONV_OVF_U4
:
4308 case CEE_CONV_OVF_U4_UN
:
4309 CHECK_STACK (td
, 1);
4310 switch (td
->sp
[-1].type
) {
4312 ADD_CODE(td
, MINT_CONV_OVF_U4_R4
);
4315 ADD_CODE(td
, MINT_CONV_OVF_U4_R8
);
4318 if (*td
->ip
!= CEE_CONV_OVF_U4_UN
)
4319 ADD_CODE(td
, MINT_CONV_OVF_U4_I4
);
4322 ADD_CODE(td
, MINT_CONV_OVF_U4_I8
);
4325 g_assert_not_reached ();
4328 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4330 #if SIZEOF_VOID_P == 8
4331 case CEE_CONV_OVF_I
:
4333 case CEE_CONV_OVF_I8
:
4334 CHECK_STACK (td
, 1);
4335 switch (td
->sp
[-1].type
) {
4337 ADD_CODE(td
, MINT_CONV_OVF_I8_R4
);
4340 ADD_CODE(td
, MINT_CONV_OVF_I8_R8
);
4343 ADD_CODE(td
, MINT_CONV_I8_I4
);
4348 g_assert_not_reached ();
4351 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
4353 #if SIZEOF_VOID_P == 8
4354 case CEE_CONV_OVF_U
:
4356 case CEE_CONV_OVF_U8
:
4357 CHECK_STACK (td
, 1);
4358 switch (td
->sp
[-1].type
) {
4360 ADD_CODE(td
, MINT_CONV_OVF_U8_R4
);
4363 ADD_CODE(td
, MINT_CONV_OVF_U8_R8
);
4366 ADD_CODE(td
, MINT_CONV_OVF_U8_I4
);
4369 ADD_CODE (td
, MINT_CONV_OVF_U8_I8
);
4372 g_assert_not_reached ();
4375 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
4380 token
= read32 (td
->ip
+ 1);
4381 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
|| method
->wrapper_type
== MONO_WRAPPER_SYNCHRONIZED
) {
4382 handle
= mono_method_get_wrapper_data (method
, token
);
4383 klass
= (MonoClass
*) mono_method_get_wrapper_data (method
, token
+ 1);
4384 if (klass
== mono_defaults
.typehandle_class
)
4385 handle
= m_class_get_byval_arg ((MonoClass
*) handle
);
4387 if (generic_context
) {
4388 handle
= mono_class_inflate_generic_type_checked ((MonoType
*)handle
, generic_context
, error
);
4389 goto_if_nok (error
, exit
);
4392 handle
= mono_ldtoken_checked (image
, token
, &klass
, generic_context
, error
);
4393 goto_if_nok (error
, exit
);
4395 mono_class_init (klass
);
4396 mt
= mint_type (m_class_get_byval_arg (klass
));
4397 g_assert (mt
== MINT_TYPE_VT
);
4398 size
= mono_class_value_size (klass
, NULL
);
4399 g_assert (size
== sizeof(gpointer
));
4401 const unsigned char *next_ip
= td
->ip
+ 5;
4402 MonoMethod
*cmethod
;
4403 if (next_ip
< end
&&
4404 !is_bb_start
[next_ip
- td
->il_code
] &&
4405 (*next_ip
== CEE_CALL
|| *next_ip
== CEE_CALLVIRT
) &&
4406 (cmethod
= mono_get_method_checked (image
, read32 (next_ip
+ 1), NULL
, generic_context
, error
)) &&
4407 (cmethod
->klass
== mono_defaults
.systemtype_class
) &&
4408 (strcmp (cmethod
->name
, "GetTypeFromHandle") == 0)) {
4409 ADD_CODE (td
, MINT_MONO_LDPTR
);
4410 gpointer systype
= mono_type_get_object_checked (domain
, (MonoType
*)handle
, error
);
4411 goto_if_nok (error
, exit
);
4412 ADD_CODE (td
, get_data_item_index (td
, systype
));
4413 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_MP
);
4414 td
->ip
= next_ip
+ 5;
4416 PUSH_VT (td
, sizeof(gpointer
));
4417 ADD_CODE (td
, MINT_LDTOKEN
);
4418 ADD_CODE (td
, get_data_item_index (td
, handle
));
4419 SET_TYPE (td
->sp
, stack_type
[mt
], klass
);
4427 binary_arith_op(td
, MINT_ADD_OVF_I4
);
4430 case CEE_ADD_OVF_UN
:
4431 binary_arith_op(td
, MINT_ADD_OVF_UN_I4
);
4435 binary_arith_op(td
, MINT_MUL_OVF_I4
);
4438 case CEE_MUL_OVF_UN
:
4439 binary_arith_op(td
, MINT_MUL_OVF_UN_I4
);
4443 binary_arith_op(td
, MINT_SUB_OVF_I4
);
4446 case CEE_SUB_OVF_UN
:
4447 binary_arith_op(td
, MINT_SUB_OVF_UN_I4
);
4450 case CEE_ENDFINALLY
: {
4451 g_assert (td
->clause_indexes
[in_offset
] != -1);
4453 SIMPLE_OP (td
, MINT_ENDFINALLY
);
4454 ADD_CODE (td
, td
->clause_indexes
[in_offset
]);
4461 if (*td
->ip
== CEE_LEAVE
)
4462 offset
= 5 + read32 (td
->ip
+ 1);
4464 offset
= 2 + (gint8
)td
->ip
[1];
4467 if (td
->clause_indexes
[in_offset
] != -1) {
4468 /* LEAVE instructions in catch clauses need to check for abort exceptions */
4469 handle_branch (td
, MINT_LEAVE_S_CHECK
, MINT_LEAVE_CHECK
, offset
);
4471 handle_branch (td
, MINT_LEAVE_S
, MINT_LEAVE
, offset
);
4474 if (*td
->ip
== CEE_LEAVE
)
4480 case MONO_CUSTOM_PREFIX
:
4483 case CEE_MONO_RETHROW
:
4484 CHECK_STACK (td
, 1);
4485 SIMPLE_OP (td
, MINT_MONO_RETHROW
);
4489 case CEE_MONO_LD_DELEGATE_METHOD_PTR
:
4492 ADD_CODE (td
, MINT_LD_DELEGATE_METHOD_PTR
);
4493 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
4495 case CEE_MONO_CALLI_EXTRA_ARG
:
4496 /* Same as CEE_CALLI, except that we drop the extra arg required for llvm specific behaviour */
4497 ADD_CODE (td
, MINT_POP
);
4500 interp_transform_call (td
, method
, NULL
, domain
, generic_context
, is_bb_start
, body_start_offset
, NULL
, FALSE
, error
, FALSE
);
4501 goto_if_nok (error
, exit
);
4503 case CEE_MONO_JIT_ICALL_ADDR
: {
4506 MonoJitICallInfo
*info
;
4508 token
= read32 (td
->ip
+ 1);
4510 func
= mono_method_get_wrapper_data (method
, token
);
4511 info
= mono_find_jit_icall_by_addr (func
);
4513 ADD_CODE (td
, MINT_LDFTN
);
4514 ADD_CODE (td
, get_data_item_index (td
, func
));
4515 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
4518 case CEE_MONO_ICALL
: {
4521 MonoJitICallInfo
*info
;
4524 token
= read32 (td
->ip
+ 1);
4526 func
= mono_method_get_wrapper_data (method
, token
);
4527 info
= mono_find_jit_icall_by_addr (func
);
4530 CHECK_STACK (td
, info
->sig
->param_count
);
4531 if (!strcmp (info
->name
, "mono_threads_attach_coop")) {
4532 rtm
->needs_thread_attach
= 1;
4534 /* attach needs two arguments, and has one return value: leave one element on the stack */
4535 ADD_CODE (td
, MINT_POP
);
4537 } else if (!strcmp (info
->name
, "mono_threads_detach_coop")) {
4538 g_assert (rtm
->needs_thread_attach
);
4540 /* detach consumes two arguments, and no return value: drop both of them */
4541 ADD_CODE (td
, MINT_POP
);
4543 ADD_CODE (td
, MINT_POP
);
4546 icall_op
= interp_icall_op_for_sig (info
->sig
);
4547 g_assert (icall_op
!= -1);
4549 ADD_CODE(td
, icall_op
);
4550 ADD_CODE(td
, get_data_item_index (td
, func
));
4552 td
->sp
-= info
->sig
->param_count
;
4554 if (!MONO_TYPE_IS_VOID (info
->sig
->ret
)) {
4555 int mt
= mint_type (info
->sig
->ret
);
4557 SET_SIMPLE_TYPE(td
->sp
- 1, stack_type
[mt
]);
4561 case CEE_MONO_VTADDR
: {
4563 CHECK_STACK (td
, 1);
4564 if (method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
4565 size
= mono_class_native_size(td
->sp
[-1].klass
, NULL
);
4567 size
= mono_class_value_size(td
->sp
[-1].klass
, NULL
);
4568 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4569 ADD_CODE(td
, MINT_VTRESULT
);
4574 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
4577 case CEE_MONO_LDPTR
:
4578 case CEE_MONO_CLASSCONST
:
4579 token
= read32 (td
->ip
+ 1);
4581 ADD_CODE(td
, MINT_MONO_LDPTR
);
4582 ADD_CODE(td
, get_data_item_index (td
, mono_method_get_wrapper_data (method
, token
)));
4583 td
->sp
[0].type
= STACK_TYPE_I
;
4586 case CEE_MONO_OBJADDR
:
4587 CHECK_STACK (td
, 1);
4589 td
->sp
[-1].type
= STACK_TYPE_MP
;
4592 case CEE_MONO_NEWOBJ
:
4593 token
= read32 (td
->ip
+ 1);
4595 ADD_CODE(td
, MINT_MONO_NEWOBJ
);
4596 ADD_CODE(td
, get_data_item_index (td
, mono_method_get_wrapper_data (method
, token
)));
4597 td
->sp
[0].type
= STACK_TYPE_O
;
4600 case CEE_MONO_RETOBJ
:
4601 CHECK_STACK (td
, 1);
4602 token
= read32 (td
->ip
+ 1);
4604 ADD_CODE(td
, MINT_MONO_RETOBJ
);
4607 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
4609 /*stackval_from_data (signature->ret, frame->retval, sp->data.vt, signature->pinvoke);*/
4611 if (td
->sp
> td
->stack
)
4612 g_warning ("CEE_MONO_RETOBJ: more values on stack: %d", td
->sp
-td
->stack
);
4614 case CEE_MONO_LDNATIVEOBJ
:
4615 token
= read32 (td
->ip
+ 1);
4617 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
4618 g_assert(m_class_is_valuetype (klass
));
4619 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
4621 case CEE_MONO_TLS
: {
4622 gint32 key
= read32 (td
->ip
+ 1);
4624 g_assert (key
< TLS_KEY_NUM
);
4625 ADD_CODE (td
, MINT_MONO_TLS
);
4627 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_MP
);
4630 case CEE_MONO_ATOMIC_STORE_I4
:
4631 CHECK_STACK (td
, 2);
4632 SIMPLE_OP (td
, MINT_MONO_ATOMIC_STORE_I4
);
4636 case CEE_MONO_SAVE_LMF
:
4637 case CEE_MONO_RESTORE_LMF
:
4638 case CEE_MONO_NOT_TAKEN
:
4641 case CEE_MONO_LDPTR_INT_REQ_FLAG
:
4642 ADD_CODE (td
, MINT_MONO_LDPTR
);
4643 ADD_CODE (td
, get_data_item_index (td
, mono_thread_interruption_request_flag ()));
4644 PUSH_TYPE (td
, STACK_TYPE_MP
, NULL
);
4647 case CEE_MONO_MEMORY_BARRIER
:
4648 ADD_CODE (td
, MINT_MONO_MEMORY_BARRIER
);
4651 case CEE_MONO_LDDOMAIN
:
4652 ADD_CODE (td
, MINT_MONO_LDDOMAIN
);
4653 td
->sp
[0].type
= STACK_TYPE_I
;
4658 g_error ("transform.c: Unimplemented opcode: 0xF0 %02x at 0x%x\n", *td
->ip
, td
->ip
-header
->code
);
4668 case CEE_PREFIXREF
: ves_abort(); break;
4671 * Note: Exceptions thrown when executing a prefixed opcode need
4672 * to take into account the number of prefix bytes (usually the
4673 * throw point is just (ip - n_prefix_bytes).
4679 ADD_CODE (td
, MINT_ARGLIST
);
4680 PUSH_VT (td
, SIZEOF_VOID_P
);
4681 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_VT
);
4686 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
) {
4687 ADD_CODE(td
, MINT_CEQ_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
4689 if (td
->sp
[-1].type
== STACK_TYPE_R4
&& td
->sp
[-2].type
== STACK_TYPE_R8
)
4690 ADD_CODE (td
, MINT_CONV_R8_R4
);
4691 if (td
->sp
[-1].type
== STACK_TYPE_R8
&& td
->sp
[-2].type
== STACK_TYPE_R4
)
4692 ADD_CODE (td
, MINT_CONV_R8_R4_SP
);
4693 ADD_CODE(td
, MINT_CEQ_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
4696 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4701 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
)
4702 ADD_CODE(td
, MINT_CGT_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
4704 ADD_CODE(td
, MINT_CGT_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
4706 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4711 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
)
4712 ADD_CODE(td
, MINT_CGT_UN_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
4714 ADD_CODE(td
, MINT_CGT_UN_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
4716 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4721 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
)
4722 ADD_CODE(td
, MINT_CLT_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
4724 ADD_CODE(td
, MINT_CLT_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
4726 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4731 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
)
4732 ADD_CODE(td
, MINT_CLT_UN_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
4734 ADD_CODE(td
, MINT_CLT_UN_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
4736 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4739 case CEE_LDVIRTFTN
: /* fallthrough */
4742 if (*td
->ip
== CEE_LDVIRTFTN
) {
4743 CHECK_STACK (td
, 1);
4746 token
= read32 (td
->ip
+ 1);
4747 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4748 m
= (MonoMethod
*)mono_method_get_wrapper_data (method
, token
);
4750 m
= mono_get_method_checked (image
, token
, NULL
, generic_context
, error
);
4751 goto_if_nok (error
, exit
);
4754 if (!mono_method_can_access_method (method
, m
))
4755 interp_generate_mae_throw (td
, method
, m
);
4757 if (method
->wrapper_type
== MONO_WRAPPER_NONE
&& m
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)
4758 m
= mono_marshal_get_synchronized_wrapper (m
);
4760 ADD_CODE(td
, *td
->ip
== CEE_LDFTN
? MINT_LDFTN
: MINT_LDVIRTFTN
);
4761 ADD_CODE(td
, get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
)));
4762 goto_if_nok (error
, exit
);
4764 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_F
);
4768 load_arg (td
, read16 (td
->ip
+ 1));
4772 int n
= read16 (td
->ip
+ 1);
4773 ADD_CODE (td
, MINT_LDARGA
);
4774 ADD_CODE (td
, td
->rtm
->arg_offsets
[n
]); /* FIX for large offsets */
4775 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
4780 store_arg (td
, read16 (td
->ip
+ 1));
4784 load_local (td
, read16 (td
->ip
+ 1));
4788 ADD_CODE(td
, MINT_LDLOCA_S
);
4789 ADD_CODE(td
, td
->rtm
->local_offsets
[read16 (td
->ip
+ 1)]);
4790 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
4794 store_local (td
, read16 (td
->ip
+ 1));
4798 CHECK_STACK (td
, 1);
4799 #if SIZEOF_VOID_P == 8
4800 if (td
->sp
[-1].type
== STACK_TYPE_I8
)
4801 ADD_CODE(td
, MINT_CONV_I4_I8
);
4803 ADD_CODE(td
, MINT_LOCALLOC
);
4804 if (td
->sp
!= td
->stack
+ 1)
4805 g_warning("CEE_LOCALLOC: stack not empty");
4807 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
4810 case CEE_UNUSED57
: ves_abort(); break;
4813 ADD_CODE (td
, MINT_ENDFILTER
);
4816 case CEE_UNALIGNED_
:
4825 /* FIX: should do something? */;
4826 // TODO: This should raise a method_tail_call profiler event.
4830 token
= read32 (td
->ip
+ 1);
4831 klass
= mini_get_class (method
, token
, generic_context
);
4832 CHECK_TYPELOAD (klass
);
4833 if (m_class_is_valuetype (klass
)) {
4834 ADD_CODE (td
, MINT_INITOBJ
);
4835 i32
= mono_class_value_size (klass
, NULL
);
4838 ADD_CODE (td
, MINT_LDNULL
);
4839 ADD_CODE (td
, MINT_STIND_REF
);
4846 /* FIX? convert length to I8? */
4848 ADD_CODE (td
, MINT_MONO_MEMORY_BARRIER
);
4849 ADD_CODE(td
, MINT_CPBLK
);
4850 BARRIER_IF_VOLATILE (td
);
4858 case CEE_CONSTRAINED_
:
4859 token
= read32 (td
->ip
+ 1);
4860 constrained_class
= mini_get_class (method
, token
, generic_context
);
4861 CHECK_TYPELOAD (constrained_class
);
4866 BARRIER_IF_VOLATILE (td
);
4867 ADD_CODE(td
, MINT_INITBLK
);
4872 /* FIXME: implement */
4876 int clause_index
= td
->clause_indexes
[in_offset
];
4877 g_assert (clause_index
!= -1);
4878 SIMPLE_OP (td
, MINT_RETHROW
);
4879 ADD_CODE (td
, rtm
->exvar_offsets
[clause_index
]);
4885 token
= read32 (td
->ip
+ 1);
4887 if (mono_metadata_token_table (token
) == MONO_TABLE_TYPESPEC
&& !image_is_dynamic (m_class_get_image (method
->klass
)) && !generic_context
) {
4889 MonoType
*type
= mono_type_create_from_typespec_checked (image
, token
, error
);
4890 goto_if_nok (error
, exit
);
4891 size
= mono_type_size (type
, &align
);
4894 MonoClass
*szclass
= mini_get_class (method
, token
, generic_context
);
4895 CHECK_TYPELOAD (szclass
);
4897 if (!szclass
->valuetype
)
4898 THROW_EX (mono_exception_from_name (mono_defaults
.corlib
, "System", "InvalidProgramException"), ip
- 5);
4900 size
= mono_type_size (m_class_get_byval_arg (szclass
), &align
);
4902 ADD_CODE(td
, MINT_LDC_I4
);
4904 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
4907 case CEE_REFANYTYPE
:
4908 ADD_CODE (td
, MINT_REFANYTYPE
);
4910 POP_VT (td
, sizeof (MonoTypedRef
));
4911 PUSH_VT (td
, sizeof (gpointer
));
4912 SET_TYPE(td
->sp
- 1, STACK_TYPE_VT
, NULL
);
4915 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
);
4919 g_error ("transform.c: Unimplemented opcode: %02x at 0x%x\n", *td
->ip
, td
->ip
-header
->code
);
4922 if (td
->new_ip
- td
->new_code
!= new_in_start_offset
)
4923 td
->last_new_ip
= td
->new_code
+ new_in_start_offset
;
4924 else if (td
->is_bb_start
[td
->in_start
- td
->il_code
])
4925 td
->is_bb_start
[td
->ip
- td
->il_code
] = 1;
4927 td
->last_ip
= td
->in_start
;
4929 in_offset
= td
->ip
- header
->code
;
4930 g_assert (td
->ip
== end
);
4931 td
->in_offsets
[in_offset
] = td
->new_ip
- td
->new_code
;
4933 /* Handle relocations */
4934 for (int i
= 0; i
< td
->relocs
->len
; ++i
) {
4935 Reloc
*reloc
= (Reloc
*)g_ptr_array_index (td
->relocs
, i
);
4937 int offset
= td
->in_offsets
[reloc
->target
] - reloc
->offset
;
4939 switch (reloc
->type
) {
4940 case RELOC_SHORT_BRANCH
:
4941 g_assert (td
->new_code
[reloc
->offset
+ 1] == 0xffff);
4942 td
->new_code
[reloc
->offset
+ 1] = offset
;
4944 case RELOC_LONG_BRANCH
: {
4945 guint16
*v
= (guint16
*) &offset
;
4946 g_assert (td
->new_code
[reloc
->offset
+ 1] == 0xbeef);
4947 g_assert (td
->new_code
[reloc
->offset
+ 2] == 0xdead);
4948 td
->new_code
[reloc
->offset
+ 1] = *(guint16
*) v
;
4949 td
->new_code
[reloc
->offset
+ 2] = *(guint16
*) (v
+ 1);
4952 case RELOC_SWITCH
: {
4953 guint16
*v
= (guint16
*)&offset
;
4954 td
->new_code
[reloc
->offset
] = *(guint16
*)v
;
4955 td
->new_code
[reloc
->offset
+ 1] = *(guint16
*)(v
+ 1);
4959 g_assert_not_reached ();
4964 if (td
->verbose_level
) {
4965 g_print ("Runtime method: %s %p, VT stack size: %d\n", mono_method_full_name (method
, TRUE
), rtm
, td
->max_vt_sp
);
4966 g_print ("Calculated stack size: %d, stated size: %d\n", td
->max_stack_height
, header
->max_stack
);
4967 dump_mint_code (td
);
4970 /* Check if we use excessive stack space */
4971 if (td
->max_stack_height
> header
->max_stack
* 3 && header
->max_stack
> 16)
4972 g_warning ("Excessive stack space usage for method %s, %d/%d", method
->name
, td
->max_stack_height
, header
->max_stack
);
4975 code_len
= td
->new_ip
- td
->new_code
;
4977 rtm
->clauses
= (MonoExceptionClause
*)mono_domain_alloc0 (domain
, header
->num_clauses
* sizeof (MonoExceptionClause
));
4978 memcpy (rtm
->clauses
, header
->clauses
, header
->num_clauses
* sizeof(MonoExceptionClause
));
4979 rtm
->code
= (gushort
*)mono_domain_alloc0 (domain
, (td
->new_ip
- td
->new_code
) * sizeof (gushort
));
4980 memcpy (rtm
->code
, td
->new_code
, (td
->new_ip
- td
->new_code
) * sizeof(gushort
));
4981 g_free (td
->new_code
);
4982 rtm
->new_body_start
= rtm
->code
+ body_start_offset
;
4983 rtm
->init_locals
= header
->init_locals
;
4984 rtm
->num_clauses
= header
->num_clauses
;
4985 for (i
= 0; i
< header
->num_clauses
; i
++) {
4986 MonoExceptionClause
*c
= rtm
->clauses
+ i
;
4987 int end_off
= c
->try_offset
+ c
->try_len
;
4988 c
->try_offset
= td
->in_offsets
[c
->try_offset
];
4989 c
->try_len
= td
->in_offsets
[end_off
] - c
->try_offset
;
4990 end_off
= c
->handler_offset
+ c
->handler_len
;
4991 c
->handler_offset
= td
->in_offsets
[c
->handler_offset
];
4992 c
->handler_len
= td
->in_offsets
[end_off
] - c
->handler_offset
;
4993 if (c
->flags
& MONO_EXCEPTION_CLAUSE_FILTER
)
4994 c
->data
.filter_offset
= td
->in_offsets
[c
->data
.filter_offset
];
4996 rtm
->stack_size
= (sizeof (stackval
)) * (td
->max_stack_height
+ 2); /* + 1 for returns of called functions + 1 for 0-ing in trace*/
4997 rtm
->stack_size
= ALIGN_TO (rtm
->stack_size
, MINT_VT_ALIGNMENT
);
4998 rtm
->vt_stack_size
= td
->max_vt_sp
;
4999 rtm
->total_locals_size
= td
->total_locals_size
;
5000 rtm
->alloca_size
= rtm
->total_locals_size
+ rtm
->args_size
+ rtm
->vt_stack_size
+ rtm
->stack_size
;
5001 rtm
->data_items
= (gpointer
*)mono_domain_alloc0 (domain
, td
->n_data_items
* sizeof (td
->data_items
[0]));
5002 memcpy (rtm
->data_items
, td
->data_items
, td
->n_data_items
* sizeof (td
->data_items
[0]));
5004 /* Save debug info */
5005 interp_save_debug_info (rtm
, header
, td
, line_numbers
);
5007 /* Create a MonoJitInfo for the interpreted method by creating the interpreter IR as the native code. */
5009 jinfo_len
= mono_jit_info_size ((MonoJitInfoFlags
)0, header
->num_clauses
, 0);
5011 jinfo
= (MonoJitInfo
*)mono_domain_alloc0 (domain
, jinfo_len
);
5012 jinfo
->is_interp
= 1;
5014 mono_jit_info_init (jinfo
, method
, (guint8
*)rtm
->code
, code_len
, (MonoJitInfoFlags
)0, header
->num_clauses
, 0);
5015 for (i
= 0; i
< jinfo
->num_clauses
; ++i
) {
5016 MonoJitExceptionInfo
*ei
= &jinfo
->clauses
[i
];
5017 MonoExceptionClause
*c
= rtm
->clauses
+ i
;
5019 ei
->flags
= c
->flags
;
5020 ei
->try_start
= (guint8
*)(rtm
->code
+ c
->try_offset
);
5021 ei
->try_end
= (guint8
*)(rtm
->code
+ c
->try_offset
+ c
->try_len
);
5022 ei
->handler_start
= (guint8
*)(rtm
->code
+ c
->handler_offset
);
5023 ei
->exvar_offset
= rtm
->exvar_offsets
[i
];
5024 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
5025 ei
->data
.filter
= (guint8
*)(rtm
->code
+ c
->data
.filter_offset
);
5026 } else if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
5027 ei
->data
.handler_end
= (guint8
*)(rtm
->code
+ c
->handler_offset
+ c
->handler_len
);
5029 ei
->data
.catch_class
= c
->data
.catch_class
;
5033 save_seq_points (td
, jinfo
);
5036 mono_basic_block_free (original_bb
);
5037 g_free (td
->in_offsets
);
5038 for (i
= 0; i
< header
->code_size
; ++i
)
5039 g_free (td
->stack_state
[i
]);
5040 g_free (td
->stack_state
);
5041 g_free (td
->stack_height
);
5042 g_free (td
->vt_stack_size
);
5043 g_free (td
->data_items
);
5045 g_hash_table_destroy (td
->data_hash
);
5046 g_free (td
->clause_indexes
);
5047 g_ptr_array_free (td
->seq_points
, TRUE
);
5048 g_array_free (line_numbers
, TRUE
);
5049 g_ptr_array_free (td
->relocs
, TRUE
);
5050 mono_mempool_destroy (td
->mempool
);
5053 static mono_mutex_t calc_section
;
5056 mono_interp_transform_init (void)
5058 mono_os_mutex_init_recursive(&calc_section
);
5062 mono_interp_transform_method (InterpMethod
*imethod
, ThreadContext
*context
, MonoError
*error
)
5064 int i
, align
, size
, offset
;
5065 MonoMethod
*method
= imethod
->method
;
5066 MonoImage
*image
= m_class_get_image (method
->klass
);
5067 MonoMethodHeader
*header
= NULL
;
5068 MonoMethodSignature
*signature
= mono_method_signature_internal (method
);
5069 const unsigned char *ip
, *end
;
5070 const MonoOpcode
*opcode
;
5073 unsigned char *is_bb_start
;
5075 MonoVTable
*method_class_vt
;
5077 MonoGenericContext
*generic_context
= NULL
;
5078 MonoDomain
*domain
= imethod
->domain
;
5079 InterpMethod tmp_imethod
;
5080 InterpMethod
*real_imethod
;
5084 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (method
->klass
))) {
5085 mono_error_set_invalid_operation (error
, "%s", "Could not execute the method because the containing type is not fully instantiated.");
5089 // g_printerr ("TRANSFORM(0x%016lx): begin %s::%s\n", mono_thread_current (), method->klass->name, method->name);
5090 method_class_vt
= mono_class_vtable_checked (domain
, imethod
->method
->klass
, error
);
5091 return_if_nok (error
);
5093 if (!method_class_vt
->initialized
) {
5094 mono_runtime_class_init_full (method_class_vt
, error
);
5095 return_if_nok (error
);
5098 MONO_PROFILER_RAISE (jit_begin
, (method
));
5100 if (mono_method_signature_internal (method
)->is_inflated
)
5101 generic_context
= mono_method_get_context (method
);
5103 MonoGenericContainer
*generic_container
= mono_method_get_generic_container (method
);
5104 if (generic_container
)
5105 generic_context
= &generic_container
->context
;
5108 if (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)) {
5109 MonoMethod
*nm
= NULL
;
5110 mono_os_mutex_lock (&calc_section
);
5111 if (imethod
->transformed
) {
5112 mono_os_mutex_unlock (&calc_section
);
5113 MONO_PROFILER_RAISE (jit_done
, (method
, imethod
->jinfo
));
5117 /* assumes all internal calls with an array this are built in... */
5118 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
&& (! mono_method_signature_internal (method
)->hasthis
|| m_class_get_rank (method
->klass
) == 0)) {
5119 nm
= mono_marshal_get_native_wrapper (method
, TRUE
, FALSE
);
5120 signature
= mono_method_signature_internal (nm
);
5122 const char *name
= method
->name
;
5123 if (m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) {
5124 if (*name
== '.' && (strcmp (name
, ".ctor") == 0)) {
5125 MonoJitICallInfo
*mi
= mono_find_jit_icall_by_name ("ves_icall_mono_delegate_ctor_interp");
5127 char *wrapper_name
= g_strdup_printf ("__icall_wrapper_%s", mi
->name
);
5128 nm
= mono_marshal_get_icall_wrapper (mi
->sig
, wrapper_name
, mi
->func
, TRUE
);
5129 g_free (wrapper_name
);
5130 } else if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
5132 * Usually handled during transformation of the caller, but
5133 * when the caller is handled by another execution engine
5134 * (for example fullAOT) we need to handle it here. That's
5135 * known to be wrong in cases where the reference to
5136 * `MonoDelegate` would be needed (FIXME).
5138 nm
= mono_marshal_get_delegate_invoke (method
, NULL
);
5139 } else if (*name
== 'B' && (strcmp (name
, "BeginInvoke") == 0)) {
5140 nm
= mono_marshal_get_delegate_begin_invoke (method
);
5141 } else if (*name
== 'E' && (strcmp (name
, "EndInvoke") == 0)) {
5142 nm
= mono_marshal_get_delegate_end_invoke (method
);
5146 g_assert_not_reached ();
5149 imethod
->stack_size
= sizeof (stackval
); /* for tracing */
5150 imethod
->alloca_size
= imethod
->stack_size
;
5151 imethod
->transformed
= TRUE
;
5152 mono_os_mutex_unlock(&calc_section
);
5153 MONO_PROFILER_RAISE (jit_done
, (method
, NULL
));
5157 header
= interp_method_get_header (nm
, error
);
5158 mono_os_mutex_unlock (&calc_section
);
5159 return_if_nok (error
);
5163 header
= mono_method_get_header_checked (method
, error
);
5164 return_if_nok (error
);
5167 g_assert ((signature
->param_count
+ signature
->hasthis
) < 1000);
5168 /* intern the strings in the method. */
5170 end
= ip
+ header
->code_size
;
5172 is_bb_start
= (guint8
*)g_malloc0(header
->code_size
);
5173 is_bb_start
[0] = 1;
5180 else if (in
== 0xf0) {
5182 in
= *ip
+ MONO_CEE_MONO_ICALL
;
5184 opcode
= &mono_opcodes
[in
];
5185 switch (opcode
->argument
) {
5186 case MonoInlineNone
:
5189 case MonoInlineString
:
5190 if (method
->wrapper_type
== MONO_WRAPPER_NONE
) {
5191 mono_ldstr_checked (domain
, image
, mono_metadata_token_index (read32 (ip
+ 1)), error
);
5192 if (!is_ok (error
)) {
5193 g_free (is_bb_start
);
5194 mono_metadata_free_mh (header
);
5200 case MonoInlineType
:
5201 if (method
->wrapper_type
== MONO_WRAPPER_NONE
) {
5202 klass
= mini_get_class (method
, read32 (ip
+ 1), generic_context
);
5203 mono_class_init (klass
);
5204 /* quick fix to not do this for the fake ptr classes - probably should not be getting the vtable at all here */
5206 g_error ("FIXME: interface method lookup: %s (in method %s)", klass
->name
, method
->name
);
5207 if (!(klass
->flags
& TYPE_ATTRIBUTE_INTERFACE
) && klass
->interface_offsets
!= NULL
)
5208 mono_class_vtable (domain
, klass
);
5213 case MonoInlineMethod
:
5214 if (method
->wrapper_type
== MONO_WRAPPER_NONE
&& *ip
!= CEE_CALLI
) {
5215 m
= mono_get_method_checked (image
, read32 (ip
+ 1), NULL
, generic_context
, error
);
5216 if (!is_ok (error
)) {
5217 g_free (is_bb_start
);
5218 mono_metadata_free_mh (header
);
5221 mono_class_init (m
->klass
);
5222 if (!mono_class_is_interface (m
->klass
)) {
5223 mono_class_vtable_checked (domain
, m
->klass
, error
);
5224 if (!is_ok (error
)) {
5225 g_free (is_bb_start
);
5226 mono_metadata_free_mh (header
);
5233 case MonoInlineField
:
5237 case MonoShortInlineR
:
5240 case MonoInlineBrTarget
:
5241 offset
= read32 (ip
+ 1);
5243 backwards
= offset
< 0;
5244 offset
+= ip
- header
->code
;
5245 g_assert (offset
>= 0 && offset
< header
->code_size
);
5246 is_bb_start
[offset
] |= backwards
? 2 : 1;
5248 case MonoShortInlineBrTarget
:
5249 offset
= ((gint8
*)ip
) [1];
5251 backwards
= offset
< 0;
5252 offset
+= ip
- header
->code
;
5253 g_assert (offset
>= 0 && offset
< header
->code_size
);
5254 is_bb_start
[offset
] |= backwards
? 2 : 1;
5259 case MonoShortInlineVar
:
5260 case MonoShortInlineI
:
5263 case MonoInlineSwitch
: {
5265 const unsigned char *next_ip
;
5269 next_ip
= ip
+ 4 * n
;
5270 for (i
= 0; i
< n
; i
++) {
5271 offset
= read32 (ip
);
5272 backwards
= offset
< 0;
5273 offset
+= next_ip
- header
->code
;
5274 g_assert (offset
>= 0 && offset
< header
->code_size
);
5275 is_bb_start
[offset
] |= backwards
? 2 : 1;
5285 g_assert_not_reached ();
5288 // g_printerr ("TRANSFORM(0x%016lx): end %s::%s\n", mono_thread_current (), method->klass->name, method->name);
5290 /* Make modifications to a copy of imethod, copy them back inside the lock */
5291 real_imethod
= imethod
;
5292 memcpy (&tmp_imethod
, imethod
, sizeof (InterpMethod
));
5293 imethod
= &tmp_imethod
;
5295 imethod
->local_offsets
= (guint32
*)g_malloc (header
->num_locals
* sizeof(guint32
));
5297 for (i
= 0; i
< header
->num_locals
; ++i
) {
5298 size
= mono_type_size (header
->locals
[i
], &align
);
5299 offset
+= align
- 1;
5300 offset
&= ~(align
- 1);
5301 imethod
->local_offsets
[i
] = offset
;
5304 offset
= (offset
+ 7) & ~7;
5306 imethod
->exvar_offsets
= (guint32
*)g_malloc (header
->num_clauses
* sizeof (guint32
));
5307 for (i
= 0; i
< header
->num_clauses
; i
++) {
5308 imethod
->exvar_offsets
[i
] = offset
;
5309 offset
+= sizeof (MonoObject
*);
5311 offset
= (offset
+ 7) & ~7;
5313 imethod
->locals_size
= offset
;
5314 g_assert (imethod
->locals_size
< 65536);
5316 imethod
->arg_offsets
= (guint32
*)g_malloc ((!!signature
->hasthis
+ signature
->param_count
) * sizeof(guint32
));
5318 if (signature
->hasthis
) {
5319 g_assert (!signature
->pinvoke
);
5320 size
= align
= SIZEOF_VOID_P
;
5321 offset
+= align
- 1;
5322 offset
&= ~(align
- 1);
5323 imethod
->arg_offsets
[0] = offset
;
5327 for (i
= 0; i
< signature
->param_count
; ++i
) {
5328 if (signature
->pinvoke
) {
5330 size
= mono_type_native_stack_size (signature
->params
[i
], &dummy
);
5334 size
= mono_type_stack_size (signature
->params
[i
], &align
);
5335 offset
+= align
- 1;
5336 offset
&= ~(align
- 1);
5337 imethod
->arg_offsets
[i
+ !!signature
->hasthis
] = offset
;
5340 offset
= (offset
+ 7) & ~7;
5341 imethod
->args_size
= offset
;
5342 g_assert (imethod
->args_size
< 10000);
5344 generate (method
, header
, imethod
, is_bb_start
, generic_context
, error
);
5346 mono_metadata_free_mh (header
);
5347 g_free (is_bb_start
);
5349 return_if_nok (error
);
5351 // FIXME: Add a different callback ?
5352 MONO_PROFILER_RAISE (jit_done
, (method
, imethod
->jinfo
));
5354 /* Copy changes back */
5355 imethod
= real_imethod
;
5356 mono_os_mutex_lock (&calc_section
);
5357 if (!imethod
->transformed
) {
5358 InterpMethod
*hash
= imethod
->next_jit_code_hash
;
5359 memcpy (imethod
, &tmp_imethod
, sizeof (InterpMethod
));
5360 imethod
->next_jit_code_hash
= hash
;
5361 mono_memory_barrier ();
5362 imethod
->transformed
= TRUE
;
5363 mono_atomic_fetch_add_i32 (&mono_jit_stats
.methods_with_interp
, 1);
5365 mono_os_mutex_unlock (&calc_section
);