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>
24 #include <mono/utils/unlocked.h>
26 #include <mono/mini/mini.h>
27 #include <mono/mini/mini-runtime.h>
30 #include "interp-internals.h"
33 #define INTERP_INST_FLAG_SEQ_POINT_NONEMPTY_STACK 1
34 #define INTERP_INST_FLAG_SEQ_POINT_METHOD_ENTRY 2
35 #define INTERP_INST_FLAG_SEQ_POINT_METHOD_EXIT 4
36 #define INTERP_INST_FLAG_SEQ_POINT_NESTED_CALL 8
38 MonoInterpStats mono_interp_stats
;
42 typedef struct InterpInst InterpInst
;
53 InterpInst
*next
, *prev
;
54 // If this is -1, this instruction is not logically associated with an IL offset, it is
55 // part of the IL instruction associated with the previous interp instruction.
58 guint16 data
[MONO_ZERO_LEN_ARRAY
];
65 SeqPoint
*last_seq_point
;
67 // This will hold a list of last sequence points of incoming basic blocks
68 SeqPoint
**pred_seq_points
;
69 guint num_pred_seq_points
;
80 /* In the interpreter IR */
89 MonoMethod
*inlined_method
;
90 MonoMethodHeader
*header
;
92 const unsigned char *il_code
;
93 const unsigned char *ip
;
94 const unsigned char *in_start
;
95 InterpInst
*last_ins
, *first_ins
;
98 StackInfo
**stack_state
;
101 unsigned char *is_bb_start
;
102 unsigned short *new_code
;
103 unsigned short *new_code_end
;
104 unsigned int max_code_size
;
107 unsigned int max_stack_height
;
108 unsigned int stack_capacity
;
110 unsigned int max_vt_sp
;
111 unsigned int total_locals_size
;
115 GHashTable
*data_hash
;
117 gboolean gen_sdb_seq_points
;
118 GPtrArray
*seq_points
;
119 InterpBasicBlock
**offset_to_bb
;
120 InterpBasicBlock
*entry_bb
;
121 MonoMemPool
*mempool
;
124 gboolean verbose_level
;
125 GArray
*line_numbers
;
128 #define STACK_TYPE_I4 0
129 #define STACK_TYPE_I8 1
130 #define STACK_TYPE_R4 2
131 #define STACK_TYPE_R8 3
132 #define STACK_TYPE_O 4
133 #define STACK_TYPE_VT 5
134 #define STACK_TYPE_MP 6
135 #define STACK_TYPE_F 7
137 static const char *stack_type_string
[] = { "I4", "I8", "R4", "R8", "O ", "VT", "MP", "F " };
139 #if SIZEOF_VOID_P == 8
140 #define STACK_TYPE_I STACK_TYPE_I8
142 #define STACK_TYPE_I STACK_TYPE_I4
145 static int stack_type
[] = {
146 STACK_TYPE_I4
, /*I1*/
147 STACK_TYPE_I4
, /*U1*/
148 STACK_TYPE_I4
, /*I2*/
149 STACK_TYPE_I4
, /*U2*/
150 STACK_TYPE_I4
, /*I4*/
151 STACK_TYPE_I8
, /*I8*/
152 STACK_TYPE_R4
, /*R4*/
153 STACK_TYPE_R8
, /*R8*/
159 #if SIZEOF_VOID_P == 8
160 #define MINT_NEG_P MINT_NEG_I8
161 #define MINT_NOT_P MINT_NOT_I8
163 #define MINT_NEG_FP MINT_NEG_R8
165 #define MINT_ADD_P MINT_ADD_I8
166 #define MINT_SUB_P MINT_SUB_I8
167 #define MINT_MUL_P MINT_MUL_I8
168 #define MINT_DIV_P MINT_DIV_I8
169 #define MINT_DIV_UN_P MINT_DIV_UN_I8
170 #define MINT_REM_P MINT_REM_I8
171 #define MINT_REM_UN_P MINT_REM_UN_I8
172 #define MINT_AND_P MINT_AND_I8
173 #define MINT_OR_P MINT_OR_I8
174 #define MINT_XOR_P MINT_XOR_I8
175 #define MINT_SHL_P MINT_SHL_I8
176 #define MINT_SHR_P MINT_SHR_I8
177 #define MINT_SHR_UN_P MINT_SHR_UN_I8
179 #define MINT_CEQ_P MINT_CEQ_I8
180 #define MINT_CNE_P MINT_CNE_I8
181 #define MINT_CLT_P MINT_CLT_I8
182 #define MINT_CLT_UN_P MINT_CLT_UN_I8
183 #define MINT_CGT_P MINT_CGT_I8
184 #define MINT_CGT_UN_P MINT_CGT_UN_I8
185 #define MINT_CLE_P MINT_CLE_I8
186 #define MINT_CLE_UN_P MINT_CLE_UN_I8
187 #define MINT_CGE_P MINT_CGE_I8
188 #define MINT_CGE_UN_P MINT_CGE_UN_I8
190 #define MINT_ADD_FP MINT_ADD_R8
191 #define MINT_SUB_FP MINT_SUB_R8
192 #define MINT_MUL_FP MINT_MUL_R8
193 #define MINT_DIV_FP MINT_DIV_R8
194 #define MINT_REM_FP MINT_REM_R8
196 #define MINT_CNE_FP MINT_CNE_R8
197 #define MINT_CEQ_FP MINT_CEQ_R8
198 #define MINT_CGT_FP MINT_CGT_R8
199 #define MINT_CGE_FP MINT_CGE_R8
200 #define MINT_CLT_FP MINT_CLT_R8
201 #define MINT_CLE_FP MINT_CLE_R8
205 #define MINT_NEG_P MINT_NEG_I4
206 #define MINT_NOT_P MINT_NOT_I4
208 #define MINT_NEG_FP MINT_NEG_R4
210 #define MINT_ADD_P MINT_ADD_I4
211 #define MINT_SUB_P MINT_SUB_I4
212 #define MINT_MUL_P MINT_MUL_I4
213 #define MINT_DIV_P MINT_DIV_I4
214 #define MINT_DIV_UN_P MINT_DIV_UN_I4
215 #define MINT_REM_P MINT_REM_I4
216 #define MINT_REM_UN_P MINT_REM_UN_I4
217 #define MINT_AND_P MINT_AND_I4
218 #define MINT_OR_P MINT_OR_I4
219 #define MINT_XOR_P MINT_XOR_I4
220 #define MINT_SHL_P MINT_SHL_I4
221 #define MINT_SHR_P MINT_SHR_I4
222 #define MINT_SHR_UN_P MINT_SHR_UN_I4
224 #define MINT_CEQ_P MINT_CEQ_I4
225 #define MINT_CNE_P MINT_CNE_I4
226 #define MINT_CLT_P MINT_CLT_I4
227 #define MINT_CLT_UN_P MINT_CLT_UN_I4
228 #define MINT_CGT_P MINT_CGT_I4
229 #define MINT_CGT_UN_P MINT_CGT_UN_I4
230 #define MINT_CLE_P MINT_CLE_I4
231 #define MINT_CLE_UN_P MINT_CLE_UN_I4
232 #define MINT_CGE_P MINT_CGE_I4
233 #define MINT_CGE_UN_P MINT_CGE_UN_I4
235 #define MINT_ADD_FP MINT_ADD_R4
236 #define MINT_SUB_FP MINT_SUB_R4
237 #define MINT_MUL_FP MINT_MUL_R4
238 #define MINT_DIV_FP MINT_DIV_R4
239 #define MINT_REM_FP MINT_REM_R4
241 #define MINT_CNE_FP MINT_CNE_R4
242 #define MINT_CEQ_FP MINT_CEQ_R4
243 #define MINT_CGT_FP MINT_CGT_R4
244 #define MINT_CGE_FP MINT_CGE_R4
245 #define MINT_CLT_FP MINT_CLT_R4
246 #define MINT_CLE_FP MINT_CLE_R4
251 const gchar
*op_name
;
255 // static const MagicIntrinsic int_binop[] = {
257 static const MagicIntrinsic int_unnop
[] = {
258 { "op_UnaryPlus", {MINT_NOP
, MINT_NOP
, MINT_NOP
}},
259 { "op_UnaryNegation", {MINT_NEG_P
, MINT_NEG_P
, MINT_NEG_FP
}},
260 { "op_OnesComplement", {MINT_NOT_P
, MINT_NOT_P
, MINT_NIY
}}
263 static const MagicIntrinsic int_binop
[] = {
264 { "op_Addition", {MINT_ADD_P
, MINT_ADD_P
, MINT_ADD_FP
}},
265 { "op_Subtraction", {MINT_SUB_P
, MINT_SUB_P
, MINT_SUB_FP
}},
266 { "op_Multiply", {MINT_MUL_P
, MINT_MUL_P
, MINT_MUL_FP
}},
267 { "op_Division", {MINT_DIV_P
, MINT_DIV_UN_P
, MINT_DIV_FP
}},
268 { "op_Modulus", {MINT_REM_P
, MINT_REM_UN_P
, MINT_REM_FP
}},
269 { "op_BitwiseAnd", {MINT_AND_P
, MINT_AND_P
, MINT_NIY
}},
270 { "op_BitwiseOr", {MINT_OR_P
, MINT_OR_P
, MINT_NIY
}},
271 { "op_ExclusiveOr", {MINT_XOR_P
, MINT_XOR_P
, MINT_NIY
}},
272 { "op_LeftShift", {MINT_SHL_P
, MINT_SHL_P
, MINT_NIY
}},
273 { "op_RightShift", {MINT_SHR_P
, MINT_SHR_UN_P
, MINT_NIY
}},
276 static const MagicIntrinsic int_cmpop
[] = {
277 { "op_Inequality", {MINT_CNE_P
, MINT_CNE_P
, MINT_CNE_FP
}},
278 { "op_Equality", {MINT_CEQ_P
, MINT_CEQ_P
, MINT_CEQ_FP
}},
279 { "op_GreaterThan", {MINT_CGT_P
, MINT_CGT_UN_P
, MINT_CGT_FP
}},
280 { "op_GreaterThanOrEqual", {MINT_CGE_P
, MINT_CGE_UN_P
, MINT_CGE_FP
}},
281 { "op_LessThan", {MINT_CLT_P
, MINT_CLT_UN_P
, MINT_CLT_FP
}},
282 { "op_LessThanOrEqual", {MINT_CLE_P
, MINT_CLE_UN_P
, MINT_CLE_FP
}}
285 static gboolean
generate_code (TransformData
*td
, MonoMethod
*method
, MonoMethodHeader
*header
, MonoGenericContext
*generic_context
, MonoError
*error
);
287 // This version need to be used with switch opcode, which doesn't have constant length
289 interp_add_ins_explicit (TransformData
*td
, guint16 opcode
, int len
)
291 InterpInst
*new_inst
;
293 // Size of data region of instruction is length of instruction minus 1 (the opcode slot)
294 new_inst
= mono_mempool_alloc0 (td
->mempool
, sizeof (InterpInst
) + sizeof (guint16
) * (len
- 1));
295 new_inst
->opcode
= opcode
;
296 // opcodes from inlined methods don't have il offset associated with them since the offset
297 // stored here is relevant only for the original method
298 if (!td
->inlined_method
)
299 new_inst
->il_offset
= td
->in_start
- td
->il_code
;
301 new_inst
->il_offset
= -1;
302 new_inst
->prev
= td
->last_ins
;
304 td
->last_ins
->next
= new_inst
;
306 td
->first_ins
= new_inst
;
307 td
->last_ins
= new_inst
;
312 interp_add_ins (TransformData
*td
, guint16 opcode
)
314 return interp_add_ins_explicit (td
, opcode
, mono_interp_oplen
[opcode
]);
317 #define CHECK_STACK(td, n) \
319 int stack_size = (td)->sp - (td)->stack; \
320 if (stack_size < (n)) \
321 g_warning ("%s.%s: not enough values (%d < %d) on stack at %04x", \
322 m_class_get_name ((td)->method->klass), (td)->method->name, \
323 stack_size, n, (td)->ip - (td)->il_code); \
326 #define ENSURE_I4(td, sp_off) \
328 if ((td)->sp [-sp_off].type == STACK_TYPE_I8) \
329 interp_add_ins (td, sp_off == 1 ? MINT_CONV_I4_I8 : MINT_CONV_I4_I8_SP); \
332 #define CHECK_TYPELOAD(klass) \
334 if (!(klass) || mono_class_has_failure (klass)) { \
335 mono_error_set_for_class_failure (error, klass); \
340 #if NO_UNALIGNED_ACCESS
341 #define WRITE32(ip, v) \
343 * (ip) = * (guint16 *)(v); \
344 * ((ip) + 1) = * ((guint16 *)(v) + 1); \
348 #define WRITE32_INS(ins, index, v) \
350 (ins)->data [index] = * (guint16 *)(v); \
351 (ins)->data [index + 1] = * ((guint16 *)(v) + 1); \
354 #define WRITE64_INS(ins, index, v) \
356 (ins)->data [index] = * (guint16 *)(v); \
357 (ins)->data [index + 1] = * ((guint16 *)(v) + 1); \
358 (ins)->data [index + 2] = * ((guint16 *)(v) + 2); \
359 (ins)->data [index + 3] = * ((guint16 *)(v) + 3); \
362 #define WRITE32(ip, v) \
364 * (guint32*)(ip) = * (guint32 *)(v); \
367 #define WRITE32_INS(ins, index, v) \
369 * (guint32 *)(&(ins)->data [index]) = * (guint32 *)(v); \
372 #define WRITE64_INS(ins, index, v) \
374 * (guint64 *)(&(ins)->data [index]) = * (guint64 *)(v); \
381 handle_branch (TransformData
*td
, int short_op
, int long_op
, int offset
)
383 int shorten_branch
= 0;
384 int target
= td
->ip
+ offset
- td
->il_code
;
385 if (target
< 0 || target
>= td
->code_size
)
386 g_assert_not_reached ();
387 /* Add exception checkpoint or safepoint for backward branches */
389 if (mono_threads_are_safepoints_enabled ())
390 interp_add_ins (td
, MINT_SAFEPOINT
);
392 interp_add_ins (td
, MINT_CHECKPOINT
);
394 if (offset
> 0 && td
->stack_height
[target
] < 0) {
395 td
->stack_height
[target
] = td
->sp
- td
->stack
;
396 if (td
->stack_height
[target
] > 0)
397 td
->stack_state
[target
] = (StackInfo
*)g_memdup (td
->stack
, td
->stack_height
[target
] * sizeof (td
->stack
[0]));
398 td
->vt_stack_size
[target
] = td
->vt_sp
;
401 if (td
->header
->code_size
<= 25000) /* FIX to be precise somehow? */
404 if (shorten_branch
) {
405 interp_add_ins (td
, short_op
);
406 td
->last_ins
->data
[0] = (guint16
) target
;
408 interp_add_ins (td
, long_op
);
409 WRITE32_INS (td
->last_ins
, 0, &target
);
414 one_arg_branch(TransformData
*td
, int mint_op
, int offset
)
416 int type
= td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
? STACK_TYPE_I
: td
->sp
[-1].type
;
417 int long_op
= mint_op
+ type
- STACK_TYPE_I4
;
418 int short_op
= long_op
+ MINT_BRFALSE_I4_S
- MINT_BRFALSE_I4
;
421 handle_branch (td
, short_op
, long_op
, offset
);
425 two_arg_branch(TransformData
*td
, int mint_op
, int offset
)
427 int type1
= td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
? STACK_TYPE_I
: td
->sp
[-1].type
;
428 int type2
= td
->sp
[-2].type
== STACK_TYPE_O
|| td
->sp
[-2].type
== STACK_TYPE_MP
? STACK_TYPE_I
: td
->sp
[-2].type
;
429 int long_op
= mint_op
+ type1
- STACK_TYPE_I4
;
430 int short_op
= long_op
+ MINT_BEQ_I4_S
- MINT_BEQ_I4
;
432 if (type1
== STACK_TYPE_I4
&& type2
== STACK_TYPE_I8
) {
433 interp_add_ins (td
, MINT_CONV_I8_I4
);
434 // The il instruction starts with the actual branch, and not with the conversion opcodes
435 td
->last_ins
->il_offset
= -1;
436 } else if (type1
== STACK_TYPE_I8
&& type2
== STACK_TYPE_I4
) {
437 interp_add_ins (td
, MINT_CONV_I8_I4_SP
);
438 td
->last_ins
->il_offset
= -1;
439 } else if (type1
== STACK_TYPE_R4
&& type2
== STACK_TYPE_R8
) {
440 interp_add_ins (td
, MINT_CONV_R8_R4
);
441 td
->last_ins
->il_offset
= -1;
442 } else if (type1
== STACK_TYPE_R8
&& type2
== STACK_TYPE_R4
) {
443 interp_add_ins (td
, MINT_CONV_R8_R4_SP
);
444 td
->last_ins
->il_offset
= -1;
445 } else if (type1
!= type2
) {
446 g_warning("%s.%s: branch type mismatch %d %d",
447 m_class_get_name (td
->method
->klass
), td
->method
->name
,
448 td
->sp
[-1].type
, td
->sp
[-2].type
);
451 handle_branch (td
, short_op
, long_op
, offset
);
455 unary_arith_op(TransformData
*td
, int mint_op
)
457 int op
= mint_op
+ td
->sp
[-1].type
- STACK_TYPE_I4
;
459 interp_add_ins (td
, op
);
463 binary_arith_op(TransformData
*td
, int mint_op
)
465 int type1
= td
->sp
[-2].type
;
466 int type2
= td
->sp
[-1].type
;
468 #if SIZEOF_VOID_P == 8
469 if ((type1
== STACK_TYPE_MP
|| type1
== STACK_TYPE_I8
) && type2
== STACK_TYPE_I4
) {
470 interp_add_ins (td
, MINT_CONV_I8_I4
);
471 type2
= STACK_TYPE_I8
;
473 if (type1
== STACK_TYPE_I4
&& (type2
== STACK_TYPE_MP
|| type2
== STACK_TYPE_I8
)) {
474 interp_add_ins (td
, MINT_CONV_I8_I4_SP
);
475 type1
= STACK_TYPE_I8
;
476 td
->sp
[-2].type
= STACK_TYPE_I8
;
479 if (type1
== STACK_TYPE_R8
&& type2
== STACK_TYPE_R4
) {
480 interp_add_ins (td
, MINT_CONV_R8_R4
);
481 type2
= STACK_TYPE_R8
;
483 if (type1
== STACK_TYPE_R4
&& type2
== STACK_TYPE_R8
) {
484 interp_add_ins (td
, MINT_CONV_R8_R4_SP
);
485 type1
= STACK_TYPE_R8
;
486 td
->sp
[-2].type
= STACK_TYPE_R8
;
488 if (type1
== STACK_TYPE_MP
)
489 type1
= STACK_TYPE_I
;
490 if (type2
== STACK_TYPE_MP
)
491 type2
= STACK_TYPE_I
;
492 if (type1
!= type2
) {
493 g_warning("%s.%s: %04x arith type mismatch %s %d %d",
494 m_class_get_name (td
->method
->klass
), td
->method
->name
,
495 td
->ip
- td
->il_code
, mono_interp_opname
[mint_op
], type1
, type2
);
497 op
= mint_op
+ type1
- STACK_TYPE_I4
;
499 interp_add_ins (td
, op
);
504 shift_op(TransformData
*td
, int mint_op
)
506 int op
= mint_op
+ td
->sp
[-2].type
- STACK_TYPE_I4
;
508 if (td
->sp
[-1].type
!= STACK_TYPE_I4
) {
509 g_warning("%s.%s: shift type mismatch %d",
510 m_class_get_name (td
->method
->klass
), td
->method
->name
,
513 interp_add_ins (td
, op
);
518 can_store (int st_value
, int vt_value
)
520 if (st_value
== STACK_TYPE_O
|| st_value
== STACK_TYPE_MP
)
521 st_value
= STACK_TYPE_I
;
522 if (vt_value
== STACK_TYPE_O
|| vt_value
== STACK_TYPE_MP
)
523 vt_value
= STACK_TYPE_I
;
524 return st_value
== vt_value
;
527 #define SET_SIMPLE_TYPE(s, ty) \
534 #define SET_TYPE(s, ty, k) \
541 #define REALLOC_STACK(td, sppos) \
543 (td)->stack_capacity *= 2; \
544 (td)->stack = (StackInfo*)realloc ((td)->stack, (td)->stack_capacity * sizeof (td->stack [0])); \
545 (td)->sp = (td)->stack + sppos; \
548 #define PUSH_SIMPLE_TYPE(td, ty) \
552 sp_height = (td)->sp - (td)->stack; \
553 if (sp_height > (td)->max_stack_height) \
554 (td)->max_stack_height = sp_height; \
555 if (sp_height > (td)->stack_capacity) \
556 REALLOC_STACK(td, sp_height); \
557 SET_SIMPLE_TYPE((td)->sp - 1, ty); \
560 #define PUSH_TYPE(td, ty, k) \
564 sp_height = (td)->sp - (td)->stack; \
565 if (sp_height > (td)->max_stack_height) \
566 (td)->max_stack_height = sp_height; \
567 if (sp_height > (td)->stack_capacity) \
568 REALLOC_STACK(td, sp_height); \
569 SET_TYPE((td)->sp - 1, ty, k); \
572 #define PUSH_VT(td, size) \
574 (td)->vt_sp += ALIGN_TO ((size), MINT_VT_ALIGNMENT); \
575 if ((td)->vt_sp > (td)->max_vt_sp) \
576 (td)->max_vt_sp = (td)->vt_sp; \
579 #define POP_VT(td, size) \
581 (td)->vt_sp -= ALIGN_TO ((size), MINT_VT_ALIGNMENT); \
585 get_arg_type_exact (TransformData
*td
, int n
, int *mt
)
588 gboolean hasthis
= mono_method_signature_internal (td
->method
)->hasthis
;
590 if (hasthis
&& n
== 0)
591 type
= m_class_get_byval_arg (td
->method
->klass
);
593 type
= mono_method_signature_internal (td
->method
)->params
[n
- !!hasthis
];
596 *mt
= mint_type (type
);
602 load_arg(TransformData
*td
, int n
)
605 MonoClass
*klass
= NULL
;
607 gboolean hasthis
= mono_method_signature_internal (td
->method
)->hasthis
;
609 type
= get_arg_type_exact (td
, n
, &mt
);
611 if (mt
== MINT_TYPE_VT
) {
613 klass
= mono_class_from_mono_type_internal (type
);
614 if (mono_method_signature_internal (td
->method
)->pinvoke
)
615 size
= mono_class_native_size (klass
, NULL
);
617 size
= mono_class_value_size (klass
, NULL
);
619 if (hasthis
&& n
== 0) {
621 interp_add_ins (td
, MINT_LDARG_P
);
622 td
->last_ins
->data
[0] = 0;
626 interp_add_ins (td
, MINT_LDARG_VT
);
627 td
->last_ins
->data
[0] = n
;
628 WRITE32_INS (td
->last_ins
, 1, &size
);
631 if (hasthis
&& n
== 0) {
633 interp_add_ins (td
, MINT_LDARG_P
);
634 td
->last_ins
->data
[0] = n
;
637 interp_add_ins (td
, MINT_LDARG_I1
+ (mt
- MINT_TYPE_I1
));
638 td
->last_ins
->data
[0] = n
;
639 if (mt
== MINT_TYPE_O
)
640 klass
= mono_class_from_mono_type_internal (type
);
643 PUSH_TYPE(td
, stack_type
[mt
], klass
);
647 store_arg(TransformData
*td
, int n
)
653 type
= get_arg_type_exact (td
, n
, &mt
);
655 if (mt
== MINT_TYPE_VT
) {
657 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
658 if (mono_method_signature_internal (td
->method
)->pinvoke
)
659 size
= mono_class_native_size (klass
, NULL
);
661 size
= mono_class_value_size (klass
, NULL
);
662 interp_add_ins (td
, MINT_STARG_VT
);
663 td
->last_ins
->data
[0] = n
;
664 WRITE32_INS (td
->last_ins
, 1, &size
);
665 if (td
->sp
[-1].type
== STACK_TYPE_VT
)
668 interp_add_ins (td
, MINT_STARG_I1
+ (mt
- MINT_TYPE_I1
));
669 td
->last_ins
->data
[0] = n
;
675 load_local_general (TransformData
*td
, int offset
, MonoType
*type
)
677 int mt
= mint_type (type
);
678 MonoClass
*klass
= NULL
;
679 if (mt
== MINT_TYPE_VT
) {
680 klass
= mono_class_from_mono_type_internal (type
);
681 gint32 size
= mono_class_value_size (klass
, NULL
);
683 interp_add_ins (td
, MINT_LDLOC_VT
);
684 td
->last_ins
->data
[0] = offset
;
685 WRITE32_INS (td
->last_ins
, 1, &size
);
687 g_assert (mt
< MINT_TYPE_VT
);
688 if (!td
->gen_sdb_seq_points
&&
689 mt
== MINT_TYPE_I4
&& !td
->is_bb_start
[td
->in_start
- td
->il_code
] && td
->last_ins
!= NULL
&&
690 td
->last_ins
->opcode
== MINT_STLOC_I4
&& td
->last_ins
->data
[0] == offset
) {
691 td
->last_ins
->opcode
= MINT_STLOC_NP_I4
;
692 } else if (!td
->gen_sdb_seq_points
&&
693 mt
== MINT_TYPE_O
&& !td
->is_bb_start
[td
->in_start
- td
->il_code
] && td
->last_ins
!= NULL
&&
694 td
->last_ins
->opcode
== MINT_STLOC_O
&& td
->last_ins
->data
[0] == offset
) {
695 td
->last_ins
->opcode
= MINT_STLOC_NP_O
;
697 interp_add_ins (td
, MINT_LDLOC_I1
+ (mt
- MINT_TYPE_I1
));
698 td
->last_ins
->data
[0] = offset
; /*FIX for large offset */
700 if (mt
== MINT_TYPE_O
)
701 klass
= mono_class_from_mono_type_internal (type
);
703 PUSH_TYPE(td
, stack_type
[mt
], klass
);
707 load_local (TransformData
*td
, int n
)
709 MonoType
*type
= td
->header
->locals
[n
];
710 int offset
= td
->rtm
->local_offsets
[n
];
711 load_local_general (td
, offset
, type
);
715 store_local_general (TransformData
*td
, int offset
, MonoType
*type
)
717 int mt
= mint_type (type
);
719 #if SIZEOF_VOID_P == 8
720 if (td
->sp
[-1].type
== STACK_TYPE_I4
&& stack_type
[mt
] == STACK_TYPE_I8
) {
721 interp_add_ins (td
, MINT_CONV_I8_I4
);
722 td
->sp
[-1].type
= STACK_TYPE_I8
;
725 if (!can_store(td
->sp
[-1].type
, stack_type
[mt
])) {
726 g_warning("%s.%s: Store local stack type mismatch %d %d",
727 m_class_get_name (td
->method
->klass
), td
->method
->name
,
728 stack_type
[mt
], td
->sp
[-1].type
);
730 if (mt
== MINT_TYPE_VT
) {
731 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
732 gint32 size
= mono_class_value_size (klass
, NULL
);
733 interp_add_ins (td
, MINT_STLOC_VT
);
734 td
->last_ins
->data
[0] = offset
; /*FIX for large offset */
735 WRITE32_INS (td
->last_ins
, 1, &size
);
736 if (td
->sp
[-1].type
== STACK_TYPE_VT
)
739 g_assert (mt
< MINT_TYPE_VT
);
740 interp_add_ins (td
, MINT_STLOC_I1
+ (mt
- MINT_TYPE_I1
));
741 td
->last_ins
->data
[0] = offset
; /*FIX for large offset */
747 store_local (TransformData
*td
, int n
)
749 MonoType
*type
= td
->header
->locals
[n
];
750 int offset
= td
->rtm
->local_offsets
[n
];
751 store_local_general (td
, offset
, type
);
754 #define SIMPLE_OP(td, op) \
756 interp_add_ins (td, op); \
761 get_data_item_index (TransformData
*td
, void *ptr
)
763 gpointer p
= g_hash_table_lookup (td
->data_hash
, ptr
);
766 return GPOINTER_TO_UINT (p
) - 1;
767 if (td
->max_data_items
== td
->n_data_items
) {
768 td
->max_data_items
= td
->n_data_items
== 0 ? 16 : 2 * td
->max_data_items
;
769 td
->data_items
= (gpointer
*)g_realloc (td
->data_items
, td
->max_data_items
* sizeof(td
->data_items
[0]));
771 index
= td
->n_data_items
;
772 td
->data_items
[index
] = ptr
;
774 g_hash_table_insert (td
->data_hash
, ptr
, GUINT_TO_POINTER (index
+ 1));
779 jit_call_supported (MonoMethod
*method
, MonoMethodSignature
*sig
)
783 if (sig
->param_count
> 6)
787 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
789 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
)
791 if (method
->is_inflated
)
793 if (method
->string_ctor
)
796 if (mono_aot_only
&& m_class_get_image (method
->klass
)->aot_module
&& !(method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)) {
798 gpointer addr
= mono_jit_compile_method_jit_only (method
, error
);
799 if (addr
&& mono_error_ok (error
))
803 for (l
= mono_interp_jit_classes
; l
; l
= l
->next
) {
804 const char *class_name
= (const char*)l
->data
;
806 if (!strcmp (m_class_get_name (method
->klass
), class_name
))
814 static int mono_class_get_magic_index (MonoClass
*k
)
816 if (mono_class_is_magic_int (k
))
817 return !strcmp ("nint", m_class_get_name (k
)) ? 0 : 1;
819 if (mono_class_is_magic_float (k
))
826 interp_generate_mae_throw (TransformData
*td
, MonoMethod
*method
, MonoMethod
*target_method
)
828 MonoJitICallInfo
*info
= mono_find_jit_icall_by_name ("mono_throw_method_access");
830 /* Inject code throwing MethodAccessException */
831 interp_add_ins (td
, MINT_MONO_LDPTR
);
832 td
->last_ins
->data
[0] = get_data_item_index (td
, method
);
833 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
835 interp_add_ins (td
, MINT_MONO_LDPTR
);
836 td
->last_ins
->data
[0] = get_data_item_index (td
, target_method
);
837 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
839 interp_add_ins (td
, MINT_ICALL_PP_V
);
840 td
->last_ins
->data
[0] = get_data_item_index (td
, (gpointer
)info
->func
);
846 * These are additional locals that can be allocated as we transform the code.
847 * They are allocated past the method locals so they are accessed in the same
848 * way, with an offset relative to the frame->locals.
851 create_interp_local (TransformData
*td
, MonoType
*type
)
854 int offset
= td
->total_locals_size
;
856 size
= mono_type_size (type
, &align
);
857 offset
= ALIGN_TO (offset
, align
);
859 td
->total_locals_size
= offset
+ size
;
865 dump_mint_code (const guint16
*start
, const guint16
* end
)
867 const guint16
*p
= start
;
869 char *ins
= mono_interp_dis_mintop (start
, p
);
870 g_print ("%s\n", ins
);
872 p
= mono_interp_dis_mintop_len (p
);
878 mono_interp_print_code (InterpMethod
*imethod
)
880 MonoJitInfo
*jinfo
= imethod
->jinfo
;
881 const guint16
*start
;
886 char *name
= mono_method_full_name (imethod
->method
, 1);
887 g_print ("Method : %s\n", name
);
890 start
= (guint16
*) jinfo
->code_start
;
891 dump_mint_code (start
, start
+ jinfo
->code_size
);
895 static MonoMethodHeader
*
896 interp_method_get_header (MonoMethod
* method
, MonoError
*error
)
898 /* An explanation: mono_method_get_header_internal returns an error if
899 * called on a method with no body (e.g. an abstract method, or an
900 * icall). We don't want that.
902 if (mono_method_has_no_body (method
))
905 return mono_method_get_header_internal (method
, error
);
908 /* stores top of stack as local and pushes address of it on stack */
910 emit_store_value_as_local (TransformData
*td
, MonoType
*src
)
912 int size
= mini_magic_type_size (NULL
, src
);
913 int local_offset
= create_interp_local (td
, mini_native_type_replace_type (src
));
915 store_local_general (td
, local_offset
, src
);
917 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
918 interp_add_ins (td
, MINT_LDLOC_VT
);
919 td
->last_ins
->data
[0] = local_offset
;
920 WRITE32_INS (td
->last_ins
, 1, &size
);
923 PUSH_TYPE (td
, STACK_TYPE_VT
, NULL
);
926 /* Return TRUE if call transformation is finished */
928 interp_handle_intrinsics (TransformData
*td
, MonoMethod
*target_method
, MonoMethodSignature
*csignature
, gboolean readonly
, int *op
)
930 const char *tm
= target_method
->name
;
932 int type_index
= mono_class_get_magic_index (target_method
->klass
);
933 gboolean in_corlib
= m_class_get_image (target_method
->klass
) == mono_defaults
.corlib
;
934 const char *klass_name_space
= m_class_get_name_space (target_method
->klass
);
935 const char *klass_name
= m_class_get_name (target_method
->klass
);
937 if (target_method
->klass
== mono_defaults
.string_class
) {
939 if (strcmp (tm
, "get_Chars") == 0)
941 else if (strcmp (tm
, "get_Length") == 0)
944 } else if (type_index
>= 0) {
945 MonoClass
*magic_class
= target_method
->klass
;
947 const int mt
= mint_type (m_class_get_byval_arg (magic_class
));
948 if (!strcmp (".ctor", tm
)) {
949 MonoType
*arg
= csignature
->params
[0];
950 /* depending on SIZEOF_VOID_P and the type of the value passed to the .ctor we either have to CONV it, or do nothing */
951 int arg_size
= mini_magic_type_size (NULL
, arg
);
953 if (arg_size
> SIZEOF_VOID_P
) { // 8 -> 4
954 switch (type_index
) {
956 interp_add_ins (td
, MINT_CONV_I4_I8
);
959 interp_add_ins (td
, MINT_CONV_R4_R8
);
964 if (arg_size
< SIZEOF_VOID_P
) { // 4 -> 8
965 switch (type_index
) {
967 interp_add_ins (td
, MINT_CONV_I8_I4
);
970 interp_add_ins (td
, MINT_CONV_I8_U4
);
973 interp_add_ins (td
, MINT_CONV_R8_R4
);
978 switch (type_index
) {
980 #if SIZEOF_VOID_P == 4
981 interp_add_ins (td
, MINT_STIND_I4
);
983 interp_add_ins (td
, MINT_STIND_I8
);
987 #if SIZEOF_VOID_P == 4
988 interp_add_ins (td
, MINT_STIND_R4
);
990 interp_add_ins (td
, MINT_STIND_R8
);
998 } else if (!strcmp ("op_Implicit", tm
) || !strcmp ("op_Explicit", tm
)) {
999 MonoType
*src
= csignature
->params
[0];
1000 MonoType
*dst
= csignature
->ret
;
1001 int src_size
= mini_magic_type_size (NULL
, src
);
1002 int dst_size
= mini_magic_type_size (NULL
, dst
);
1004 gboolean store_value_as_local
= FALSE
;
1006 switch (type_index
) {
1008 if (!mini_magic_is_int_type (src
) || !mini_magic_is_int_type (dst
)) {
1009 if (mini_magic_is_int_type (src
))
1010 store_value_as_local
= TRUE
;
1016 if (!mini_magic_is_float_type (src
) || !mini_magic_is_float_type (dst
)) {
1017 if (mini_magic_is_float_type (src
))
1018 store_value_as_local
= TRUE
;
1025 if (store_value_as_local
) {
1026 emit_store_value_as_local (td
, src
);
1028 /* emit call to managed conversion method */
1032 #if SIZEOF_VOID_P == 4
1033 if (src_size
> dst_size
) { // 8 -> 4
1034 switch (type_index
) {
1036 interp_add_ins (td
, MINT_CONV_I4_I8
);
1039 interp_add_ins (td
, MINT_CONV_R4_R8
);
1045 #if SIZEOF_VOID_P == 8
1046 if (src_size
< dst_size
) { // 4 -> 8
1047 switch (type_index
) {
1049 interp_add_ins (td
, MINT_CONV_I8_I4
);
1052 interp_add_ins (td
, MINT_CONV_I8_U4
);
1055 interp_add_ins (td
, MINT_CONV_R8_R4
);
1061 SET_TYPE (td
->sp
- 1, stack_type
[mt
], magic_class
);
1064 } else if (!strcmp ("op_Increment", tm
)) {
1065 g_assert (type_index
!= 2); // no nfloat
1066 #if SIZEOF_VOID_P == 8
1067 interp_add_ins (td
, MINT_ADD1_I8
);
1069 interp_add_ins (td
, MINT_ADD1_I4
);
1071 SET_TYPE (td
->sp
- 1, stack_type
[mt
], magic_class
);
1074 } else if (!strcmp ("op_Decrement", tm
)) {
1075 g_assert (type_index
!= 2); // no nfloat
1076 #if SIZEOF_VOID_P == 8
1077 interp_add_ins (td
, MINT_SUB1_I8
);
1079 interp_add_ins (td
, MINT_SUB1_I4
);
1081 SET_TYPE (td
->sp
- 1, stack_type
[mt
], magic_class
);
1084 } else if (!strcmp ("CompareTo", tm
) || !strcmp ("Equals", tm
)) {
1085 MonoType
*arg
= csignature
->params
[0];
1087 /* on 'System.n*::{CompareTo,Equals} (System.n*)' variant we need to push managed
1088 * pointer instead of value */
1089 if (arg
->type
== MONO_TYPE_VALUETYPE
)
1090 emit_store_value_as_local (td
, arg
);
1092 /* emit call to managed conversion method */
1094 } else if (!strcmp (".cctor", tm
)) {
1097 } else if (!strcmp ("Parse", tm
)) {
1100 } else if (!strcmp ("ToString", tm
)) {
1103 } else if (!strcmp ("GetHashCode", tm
)) {
1106 } else if (!strcmp ("IsNaN", tm
) || !strcmp ("IsInfinity", tm
) || !strcmp ("IsNegativeInfinity", tm
) || !strcmp ("IsPositiveInfinity", tm
)) {
1107 g_assert (type_index
== 2); // nfloat only
1112 for (i
= 0; i
< sizeof (int_unnop
) / sizeof (MagicIntrinsic
); ++i
) {
1113 if (!strcmp (int_unnop
[i
].op_name
, tm
)) {
1114 interp_add_ins (td
, int_unnop
[i
].insn
[type_index
]);
1115 SET_TYPE (td
->sp
- 1, stack_type
[mt
], magic_class
);
1121 for (i
= 0; i
< sizeof (int_binop
) / sizeof (MagicIntrinsic
); ++i
) {
1122 if (!strcmp (int_binop
[i
].op_name
, tm
)) {
1123 interp_add_ins (td
, int_binop
[i
].insn
[type_index
]);
1125 SET_TYPE (td
->sp
- 1, stack_type
[mt
], magic_class
);
1131 for (i
= 0; i
< sizeof (int_cmpop
) / sizeof (MagicIntrinsic
); ++i
) {
1132 if (!strcmp (int_cmpop
[i
].op_name
, tm
)) {
1133 MonoClass
*k
= mono_defaults
.boolean_class
;
1134 interp_add_ins (td
, int_cmpop
[i
].insn
[type_index
]);
1136 SET_TYPE (td
->sp
- 1, stack_type
[mint_type (m_class_get_byval_arg (k
))], k
);
1142 g_error ("TODO: interp_transform_call %s:%s", m_class_get_name (target_method
->klass
), tm
);
1143 } else if (mono_class_is_subclass_of (target_method
->klass
, mono_defaults
.array_class
, FALSE
)) {
1144 if (!strcmp (tm
, "get_Rank")) {
1145 *op
= MINT_ARRAY_RANK
;
1146 } else if (!strcmp (tm
, "get_Length")) {
1148 } else if (!strcmp (tm
, "Address")) {
1149 *op
= readonly
? MINT_LDELEMA
: MINT_LDELEMA_TC
;
1150 } else if (!strcmp (tm
, "UnsafeMov") || !strcmp (tm
, "UnsafeLoad") || !strcmp (tm
, "Set") || !strcmp (tm
, "Get")) {
1152 } else if (!strcmp (tm
, "UnsafeStore")) {
1153 g_error ("TODO ArrayClass::UnsafeStore");
1155 } else if (in_corlib
&&
1156 !strcmp (klass_name_space
, "System.Diagnostics") &&
1157 !strcmp (klass_name
, "Debugger")) {
1158 if (!strcmp (tm
, "Break") && csignature
->param_count
== 0) {
1159 if (mini_should_insert_breakpoint (td
->method
))
1162 } else if (in_corlib
&& !strcmp (klass_name_space
, "System") && !strcmp (klass_name
, "ByReference`1")) {
1163 *op
= MINT_INTRINS_BYREFERENCE_GET_VALUE
;
1164 } else if (in_corlib
&& !strcmp (klass_name_space
, "System") && !strcmp (klass_name
, "Math") && csignature
->param_count
== 1 && csignature
->params
[0]->type
== MONO_TYPE_R8
) {
1165 if (tm
[0] == 'A') {
1166 if (strcmp (tm
, "Abs") == 0 && csignature
->params
[0]->type
== MONO_TYPE_R8
) {
1168 } else if (strcmp (tm
, "Asin") == 0){
1170 } else if (strcmp (tm
, "Asinh") == 0){
1172 } else if (strcmp (tm
, "Acos") == 0){
1174 } else if (strcmp (tm
, "Acosh") == 0){
1176 } else if (strcmp (tm
, "Atan") == 0){
1178 } else if (strcmp (tm
, "Atanh") == 0){
1181 } else if (tm
[0] == 'C') {
1182 if (strcmp (tm
, "Cos") == 0) {
1184 } else if (strcmp (tm
, "Cbrt") == 0){
1186 } else if (strcmp (tm
, "Cosh") == 0){
1189 } else if (tm
[0] == 'S') {
1190 if (strcmp (tm
, "Sin") == 0) {
1192 } else if (strcmp (tm
, "Sqrt") == 0) {
1194 } else if (strcmp (tm
, "Sinh") == 0){
1197 } else if (tm
[0] == 'T') {
1198 if (strcmp (tm
, "Tan") == 0) {
1200 } else if (strcmp (tm
, "Tanh") == 0){
1204 } else if (in_corlib
&& !strcmp (klass_name_space
, "System") && (!strcmp (klass_name
, "Span`1") || !strcmp (klass_name
, "ReadOnlySpan`1"))) {
1205 if (!strcmp (tm
, "get_Item") && csignature
->params
[0]->type
!= MONO_TYPE_VALUETYPE
) {
1206 MonoGenericClass
*gclass
= mono_class_get_generic_class (target_method
->klass
);
1207 MonoClass
*param_class
= mono_class_from_mono_type_internal (gclass
->context
.class_inst
->type_argv
[0]);
1209 if (!mini_is_gsharedvt_variable_klass (param_class
)) {
1210 MonoClassField
*length_field
= mono_class_get_field_from_name_full (target_method
->klass
, "_length", NULL
);
1211 g_assert (length_field
);
1212 int offset_length
= length_field
->offset
- sizeof (MonoObject
);
1214 MonoClassField
*ptr_field
= mono_class_get_field_from_name_full (target_method
->klass
, "_pointer", NULL
);
1215 g_assert (ptr_field
);
1216 int offset_pointer
= ptr_field
->offset
- sizeof (MonoObject
);
1218 int size
= mono_class_array_element_size (param_class
);
1219 interp_add_ins (td
, MINT_GETITEM_SPAN
);
1220 td
->last_ins
->data
[0] = size
;
1221 td
->last_ins
->data
[1] = offset_length
;
1222 td
->last_ins
->data
[2] = offset_pointer
;
1224 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_MP
);
1229 } else if (!strcmp (tm
, "get_Length")) {
1230 MonoClassField
*length_field
= mono_class_get_field_from_name_full (target_method
->klass
, "_length", NULL
);
1231 g_assert (length_field
);
1232 int offset_length
= length_field
->offset
- sizeof (MonoObject
);
1233 interp_add_ins (td
, MINT_LDLEN_SPAN
);
1234 td
->last_ins
->data
[0] = offset_length
;
1235 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I4
);
1239 } else if (in_corlib
&& !strcmp (klass_name_space
, "Internal.Runtime.CompilerServices") && !strcmp (klass_name
, "Unsafe")) {
1240 #ifdef ENABLE_NETCORE
1241 if (!strcmp (tm
, "AddByteOffset"))
1242 *op
= MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET
;
1243 else if (!strcmp (tm
, "ByteOffset"))
1244 *op
= MINT_INTRINS_UNSAFE_BYTE_OFFSET
;
1245 else if (!strcmp (tm
, "As") || !strcmp (tm
, "AsRef"))
1247 else if (!strcmp (tm
, "SizeOf")) {
1248 MonoGenericContext
*ctx
= mono_method_get_context (target_method
);
1250 g_assert (ctx
->method_inst
);
1251 g_assert (ctx
->method_inst
->type_argc
== 1);
1252 MonoType
*t
= ctx
->method_inst
->type_argv
[0];
1254 int esize
= mono_type_size (t
, &align
);
1255 interp_add_ins (td
, MINT_LDC_I4
);
1256 WRITE32_INS (td
->last_ins
, 0, &esize
);
1257 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I4
);
1260 } else if (!strcmp (tm
, "AreSame")) {
1264 } else if (in_corlib
&& !strcmp (klass_name_space
, "System.Runtime.CompilerServices") && !strcmp (klass_name
, "RuntimeHelpers")) {
1265 #ifdef ENABLE_NETCORE
1266 if (!strcmp (tm
, "IsBitwiseEquatable")) {
1267 g_assert (csignature
->param_count
== 0);
1268 MonoGenericContext
*ctx
= mono_method_get_context (target_method
);
1270 g_assert (ctx
->method_inst
);
1271 g_assert (ctx
->method_inst
->type_argc
== 1);
1272 MonoType
*t
= mini_get_underlying_type (ctx
->method_inst
->type_argv
[0]);
1274 if (MONO_TYPE_IS_PRIMITIVE (t
) && t
->type
!= MONO_TYPE_R4
&& t
->type
!= MONO_TYPE_R8
)
1275 *op
= MINT_LDC_I4_1
;
1277 *op
= MINT_LDC_I4_0
;
1278 } else if (!strcmp (tm
, "ObjectHasComponentSize")) {
1279 *op
= MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE
;
1282 } else if (in_corlib
&& !strcmp (klass_name_space
, "System") && !strcmp (klass_name
, "RuntimeMethodHandle") && !strcmp (tm
, "GetFunctionPointer") && csignature
->param_count
== 1) {
1283 // We must intrinsify this method on interp so we don't return a pointer to native code entering interpreter
1284 *op
= MINT_LDFTN_DYNAMIC
;
1285 } else if (target_method
->klass
== mono_defaults
.object_class
) {
1286 if (!strcmp (tm
, "InternalGetHashCode"))
1287 *op
= MINT_INTRINS_GET_HASHCODE
;
1288 #ifdef DISABLE_REMOTING
1289 else if (!strcmp (tm
, "GetType"))
1290 *op
= MINT_INTRINS_GET_TYPE
;
1298 interp_transform_internal_calls (MonoMethod
*method
, MonoMethod
*target_method
, MonoMethodSignature
*csignature
, gboolean is_virtual
)
1300 if (method
->wrapper_type
== MONO_WRAPPER_NONE
&& target_method
!= NULL
) {
1301 if (target_method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
1302 target_method
= mono_marshal_get_native_wrapper (target_method
, FALSE
, FALSE
);
1303 if (!is_virtual
&& target_method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)
1304 target_method
= mono_marshal_get_synchronized_wrapper (target_method
);
1306 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)
1307 target_method
= mono_marshal_get_native_wrapper (target_method
, TRUE
, FALSE
);
1309 return target_method
;
1313 interp_type_as_ptr (MonoType
*tp
)
1315 if (MONO_TYPE_IS_POINTER (tp
))
1317 if (MONO_TYPE_IS_REFERENCE (tp
))
1319 if ((tp
)->type
== MONO_TYPE_I4
)
1321 #if SIZEOF_VOID_P == 8
1322 if ((tp
)->type
== MONO_TYPE_I8
)
1325 if ((tp
)->type
== MONO_TYPE_BOOLEAN
)
1327 if ((tp
)->type
== MONO_TYPE_CHAR
)
1329 if ((tp
)->type
== MONO_TYPE_VALUETYPE
&& m_class_is_enumtype (tp
->data
.klass
))
1334 #define INTERP_TYPE_AS_PTR(tp) interp_type_as_ptr (tp)
1337 interp_icall_op_for_sig (MonoMethodSignature
*sig
)
1340 switch (sig
->param_count
) {
1342 if (MONO_TYPE_IS_VOID (sig
->ret
))
1343 op
= MINT_ICALL_V_V
;
1344 else if (INTERP_TYPE_AS_PTR (sig
->ret
))
1345 op
= MINT_ICALL_V_P
;
1348 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1349 if (INTERP_TYPE_AS_PTR (sig
->params
[0]))
1350 op
= MINT_ICALL_P_V
;
1351 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1352 if (INTERP_TYPE_AS_PTR (sig
->params
[0]))
1353 op
= MINT_ICALL_P_P
;
1357 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1358 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1359 INTERP_TYPE_AS_PTR (sig
->params
[1]))
1360 op
= MINT_ICALL_PP_V
;
1361 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1362 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1363 INTERP_TYPE_AS_PTR (sig
->params
[1]))
1364 op
= MINT_ICALL_PP_P
;
1368 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1369 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1370 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1371 INTERP_TYPE_AS_PTR (sig
->params
[2]))
1372 op
= MINT_ICALL_PPP_V
;
1373 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1374 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1375 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1376 INTERP_TYPE_AS_PTR (sig
->params
[2]))
1377 op
= MINT_ICALL_PPP_P
;
1381 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1382 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1383 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1384 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1385 INTERP_TYPE_AS_PTR (sig
->params
[3]))
1386 op
= MINT_ICALL_PPPP_V
;
1387 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1388 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1389 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1390 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1391 INTERP_TYPE_AS_PTR (sig
->params
[3]))
1392 op
= MINT_ICALL_PPPP_P
;
1396 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1397 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1398 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1399 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1400 INTERP_TYPE_AS_PTR (sig
->params
[3]) &&
1401 INTERP_TYPE_AS_PTR (sig
->params
[4]))
1402 op
= MINT_ICALL_PPPPP_V
;
1403 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1404 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1405 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1406 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1407 INTERP_TYPE_AS_PTR (sig
->params
[3]) &&
1408 INTERP_TYPE_AS_PTR (sig
->params
[4]))
1409 op
= MINT_ICALL_PPPPP_P
;
1413 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1414 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1415 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1416 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1417 INTERP_TYPE_AS_PTR (sig
->params
[3]) &&
1418 INTERP_TYPE_AS_PTR (sig
->params
[4]) &&
1419 INTERP_TYPE_AS_PTR (sig
->params
[5]))
1420 op
= MINT_ICALL_PPPPPP_V
;
1421 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1422 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1423 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1424 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1425 INTERP_TYPE_AS_PTR (sig
->params
[3]) &&
1426 INTERP_TYPE_AS_PTR (sig
->params
[4]) &&
1427 INTERP_TYPE_AS_PTR (sig
->params
[5]))
1428 op
= MINT_ICALL_PPPPPP_P
;
1435 #define INLINE_LENGTH_LIMIT 20
1438 interp_method_check_inlining (TransformData
*td
, MonoMethod
*method
)
1440 MonoMethodHeaderSummary header
;
1442 if (td
->method
== method
)
1445 if (!mono_method_get_header_summary (method
, &header
))
1448 /*runtime, icall and pinvoke are checked by summary call*/
1449 if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_NOINLINING
) ||
1450 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) ||
1451 (mono_class_is_marshalbyref (method
->klass
)) ||
1452 header
.has_clauses
||
1456 if (header
.code_size
>= INLINE_LENGTH_LIMIT
)
1459 if (mono_class_needs_cctor_run (method
->klass
, NULL
)) {
1462 if (!m_class_get_runtime_info (method
->klass
))
1463 /* No vtable created yet */
1465 vtable
= mono_class_vtable_checked (td
->rtm
->domain
, method
->klass
, error
);
1466 if (!is_ok (error
)) {
1467 mono_error_cleanup (error
);
1470 if (!vtable
->initialized
)
1474 /* We currently access at runtime the wrapper data */
1475 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
1482 interp_inline_method (TransformData
*td
, MonoMethod
*target_method
, MonoMethodHeader
*header
, MonoError
*error
)
1484 const unsigned char *prev_ip
, *prev_il_code
, *prev_in_start
;
1485 StackInfo
**prev_stack_state
;
1486 int *prev_stack_height
, *prev_vt_stack_size
, *prev_clause_indexes
, *prev_in_offsets
;
1487 guint8
*prev_is_bb_start
;
1489 unsigned int prev_max_stack_height
, prev_max_vt_sp
, prev_total_locals_size
;
1490 int prev_n_data_items
;
1493 MonoGenericContext
*generic_context
= NULL
;
1494 StackInfo
*prev_param_area
;
1495 MonoMethod
*prev_inlined_method
;
1496 MonoMethodSignature
*csignature
= mono_method_signature_internal (target_method
);
1497 int nargs
= csignature
->param_count
+ !!csignature
->hasthis
;
1498 InterpInst
*prev_last_ins
;
1500 if (csignature
->is_inflated
)
1501 generic_context
= mono_method_get_context (target_method
);
1503 MonoGenericContainer
*generic_container
= mono_method_get_generic_container (target_method
);
1504 if (generic_container
)
1505 generic_context
= &generic_container
->context
;
1509 prev_il_code
= td
->il_code
;
1510 prev_in_start
= td
->in_start
;
1511 prev_sp_offset
= td
->sp
- td
->stack
;
1512 prev_vt_sp
= td
->vt_sp
;
1513 prev_stack_state
= td
->stack_state
;
1514 prev_stack_height
= td
->stack_height
;
1515 prev_vt_stack_size
= td
->vt_stack_size
;
1516 prev_clause_indexes
= td
->clause_indexes
;
1517 prev_inlined_method
= td
->inlined_method
;
1518 prev_last_ins
= td
->last_ins
;
1519 td
->inlined_method
= target_method
;
1521 prev_max_stack_height
= td
->max_stack_height
;
1522 prev_max_vt_sp
= td
->max_vt_sp
;
1523 prev_total_locals_size
= td
->total_locals_size
;
1525 prev_n_data_items
= td
->n_data_items
;
1526 prev_in_offsets
= td
->in_offsets
;
1527 td
->in_offsets
= (int*)g_malloc0((header
->code_size
+ 1) * sizeof(int));
1529 prev_is_bb_start
= td
->is_bb_start
;
1531 /* Inlining pops the arguments, restore the stack */
1532 prev_param_area
= (StackInfo
*)g_malloc (nargs
* sizeof (StackInfo
));
1533 memcpy (prev_param_area
, &td
->sp
[-nargs
], nargs
* sizeof (StackInfo
));
1535 if (td
->verbose_level
)
1536 g_print ("Inline start method %s.%s\n", m_class_get_name (target_method
->klass
), target_method
->name
);
1537 ret
= generate_code (td
, target_method
, header
, generic_context
, error
);
1540 if (td
->verbose_level
)
1541 g_print ("Inline aborted method %s.%s\n", m_class_get_name (target_method
->klass
), target_method
->name
);
1542 td
->max_stack_height
= prev_max_stack_height
;
1543 td
->max_vt_sp
= prev_max_vt_sp
;
1544 td
->total_locals_size
= prev_total_locals_size
;
1547 /* Remove any newly added items */
1548 for (i
= prev_n_data_items
; i
< td
->n_data_items
; i
++) {
1549 g_hash_table_remove (td
->data_hash
, td
->data_items
[i
]);
1551 td
->n_data_items
= prev_n_data_items
;
1552 td
->sp
= td
->stack
+ prev_sp_offset
;
1553 memcpy (&td
->sp
[-nargs
], prev_param_area
, nargs
* sizeof (StackInfo
));
1554 td
->vt_sp
= prev_vt_sp
;
1555 td
->last_ins
= prev_last_ins
;
1557 td
->last_ins
->next
= NULL
;
1558 UnlockedIncrement (&mono_interp_stats
.inline_failures
);
1560 if (td
->verbose_level
)
1561 g_print ("Inline end method %s.%s\n", m_class_get_name (target_method
->klass
), target_method
->name
);
1562 UnlockedIncrement (&mono_interp_stats
.inlined_methods
);
1563 // Make sure we have an IR instruction associated with the now removed IL CALL
1564 // FIXME This could be prettier. We might be able to make inlining saner now that
1565 // that we can easily tweak the instruction list.
1566 if (!prev_inlined_method
) {
1567 if (prev_last_ins
) {
1568 if (prev_last_ins
->next
)
1569 prev_last_ins
->next
->il_offset
= prev_in_start
- prev_il_code
;
1570 } else if (td
->first_ins
) {
1571 td
->first_ins
->il_offset
= prev_in_start
- prev_il_code
;
1577 td
->in_start
= prev_in_start
;
1578 td
->il_code
= prev_il_code
;
1579 td
->stack_state
= prev_stack_state
;
1580 td
->stack_height
= prev_stack_height
;
1581 td
->vt_stack_size
= prev_vt_stack_size
;
1582 td
->clause_indexes
= prev_clause_indexes
;
1583 td
->is_bb_start
= prev_is_bb_start
;
1584 td
->inlined_method
= prev_inlined_method
;
1586 g_free (td
->in_offsets
);
1587 td
->in_offsets
= prev_in_offsets
;
1589 g_free (prev_param_area
);
1593 /* Return FALSE if error, including inline failure */
1595 interp_transform_call (TransformData
*td
, MonoMethod
*method
, MonoMethod
*target_method
, MonoDomain
*domain
, MonoGenericContext
*generic_context
, unsigned char *is_bb_start
, MonoClass
*constrained_class
, gboolean readonly
, MonoError
*error
, gboolean check_visibility
)
1597 MonoImage
*image
= m_class_get_image (method
->klass
);
1598 MonoMethodSignature
*csignature
;
1599 int is_virtual
= *td
->ip
== CEE_CALLVIRT
;
1600 int calli
= *td
->ip
== CEE_CALLI
|| *td
->ip
== CEE_MONO_CALLI_EXTRA_ARG
;
1602 guint32 vt_stack_used
= 0;
1603 guint32 vt_res_size
= 0;
1607 int need_null_check
= is_virtual
;
1609 guint32 token
= read32 (td
->ip
+ 1);
1611 if (target_method
== NULL
) {
1614 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
1615 csignature
= (MonoMethodSignature
*)mono_method_get_wrapper_data (method
, token
);
1617 csignature
= mono_metadata_parse_signature_checked (image
, token
, error
);
1618 return_val_if_nok (error
, FALSE
);
1621 if (generic_context
) {
1622 csignature
= mono_inflate_generic_signature (csignature
, generic_context
, error
);
1623 return_val_if_nok (error
, FALSE
);
1627 * The compiled interp entry wrapper is passed to runtime_invoke instead of
1628 * the InterpMethod pointer. FIXME
1630 native
= csignature
->pinvoke
|| method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
;
1633 target_method
= NULL
;
1635 if (method
->wrapper_type
== MONO_WRAPPER_NONE
) {
1636 target_method
= mono_get_method_checked (image
, token
, NULL
, generic_context
, error
);
1637 return_val_if_nok (error
, FALSE
);
1639 target_method
= (MonoMethod
*)mono_method_get_wrapper_data (method
, token
);
1640 csignature
= mono_method_signature_internal (target_method
);
1642 if (generic_context
) {
1643 csignature
= mono_inflate_generic_signature (csignature
, generic_context
, error
);
1644 return_val_if_nok (error
, FALSE
);
1645 target_method
= mono_class_inflate_generic_method_checked (target_method
, generic_context
, error
);
1646 return_val_if_nok (error
, FALSE
);
1650 csignature
= mono_method_signature_internal (target_method
);
1653 if (check_visibility
&& target_method
&& !mono_method_can_access_method (method
, target_method
))
1654 interp_generate_mae_throw (td
, method
, target_method
);
1656 if (target_method
&& target_method
->string_ctor
) {
1657 /* Create the real signature */
1658 MonoMethodSignature
*ctor_sig
= mono_metadata_signature_dup_mempool (td
->mempool
, csignature
);
1659 ctor_sig
->ret
= m_class_get_byval_arg (mono_defaults
.string_class
);
1661 csignature
= ctor_sig
;
1665 if (target_method
&& interp_handle_intrinsics (td
, target_method
, csignature
, readonly
, &op
))
1668 if (constrained_class
) {
1669 if (m_class_is_enumtype (constrained_class
) && !strcmp (target_method
->name
, "GetHashCode")) {
1670 /* Use the corresponding method from the base type to avoid boxing */
1671 MonoType
*base_type
= mono_class_enum_basetype_internal (constrained_class
);
1672 g_assert (base_type
);
1673 constrained_class
= mono_class_from_mono_type_internal (base_type
);
1674 target_method
= mono_class_get_method_from_name_checked (constrained_class
, target_method
->name
, 0, 0, error
);
1675 mono_error_assert_ok (error
);
1676 g_assert (target_method
);
1680 if (constrained_class
) {
1681 mono_class_setup_vtable (constrained_class
);
1682 if (mono_class_has_failure (constrained_class
)) {
1683 mono_error_set_for_class_failure (error
, constrained_class
);
1687 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
);
1689 target_method
= mono_get_method_constrained_with_method (image
, target_method
, constrained_class
, generic_context
, error
);
1691 g_print (" : %s::%s. %s (%p)\n", target_method
->klass
->name
, target_method
->name
, mono_signature_full_name (target_method
->signature
), target_method
);
1693 /* Intrinsics: Try again, it could be that `mono_get_method_constrained_with_method` resolves to a method that we can substitute */
1694 if (target_method
&& interp_handle_intrinsics (td
, target_method
, csignature
, readonly
, &op
))
1697 return_val_if_nok (error
, FALSE
);
1698 mono_class_setup_vtable (target_method
->klass
);
1700 if (!m_class_is_valuetype (constrained_class
)) {
1701 /* managed pointer on the stack, we need to deref that puppy */
1702 interp_add_ins (td
, MINT_LDIND_I
);
1703 td
->last_ins
->data
[0] = csignature
->param_count
;
1704 } else if (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
) {
1705 if (target_method
->klass
== mono_defaults
.enum_class
&& (td
->sp
- csignature
->param_count
- 1)->type
== STACK_TYPE_MP
) {
1706 /* managed pointer on the stack, we need to deref that puppy */
1707 /* Always load the entire stackval, to handle also the case where the enum has long storage */
1708 interp_add_ins (td
, MINT_LDIND_I8
);
1709 td
->last_ins
->data
[0] = csignature
->param_count
;
1711 if (mint_type (m_class_get_byval_arg (constrained_class
)) == MINT_TYPE_VT
) {
1712 interp_add_ins (td
, MINT_BOX_VT
);
1713 td
->last_ins
->data
[0] = get_data_item_index (td
, constrained_class
);
1714 td
->last_ins
->data
[1] = csignature
->param_count
| ((td
->sp
- 1 - csignature
->param_count
)->type
!= STACK_TYPE_MP
? 0 : BOX_NOT_CLEAR_VT_SP
);
1716 interp_add_ins (td
, MINT_BOX
);
1717 td
->last_ins
->data
[0] = get_data_item_index (td
, constrained_class
);
1718 td
->last_ins
->data
[1] = csignature
->param_count
;
1721 if (target_method
->klass
!= constrained_class
) {
1723 * The type parameter is instantiated as a valuetype,
1724 * but that type doesn't override the method we're
1725 * calling, so we need to box `this'.
1727 if ((td
->sp
- csignature
->param_count
- 1)->type
== STACK_TYPE_MP
) {
1728 /* managed pointer on the stack, we need to deref that puppy */
1729 /* Always load the entire stackval, to handle also the case where the enum has long storage */
1730 interp_add_ins (td
, MINT_LDIND_I8
);
1731 td
->last_ins
->data
[0] = csignature
->param_count
;
1733 if (mint_type (m_class_get_byval_arg (constrained_class
)) == MINT_TYPE_VT
) {
1734 interp_add_ins (td
, MINT_BOX_VT
);
1735 td
->last_ins
->data
[0] = get_data_item_index (td
, constrained_class
);
1736 td
->last_ins
->data
[1] = csignature
->param_count
| ((td
->sp
- 1 - csignature
->param_count
)->type
!= STACK_TYPE_MP
? 0 : BOX_NOT_CLEAR_VT_SP
);
1738 interp_add_ins (td
, MINT_BOX
);
1739 td
->last_ins
->data
[0] = get_data_item_index (td
, constrained_class
);
1740 td
->last_ins
->data
[1] = csignature
->param_count
;
1748 mono_class_init_internal (target_method
->klass
);
1750 if (!is_virtual
&& target_method
&& (target_method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
))
1751 /* MS.NET seems to silently convert this to a callvirt */
1754 if (is_virtual
&& target_method
&& (!(target_method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) ||
1755 (MONO_METHOD_IS_FINAL (target_method
) &&
1756 target_method
->wrapper_type
!= MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
)) &&
1757 !(mono_class_is_marshalbyref (target_method
->klass
))) {
1758 /* Not really virtual, just needs a null check */
1760 need_null_check
= TRUE
;
1763 CHECK_STACK (td
, csignature
->param_count
+ csignature
->hasthis
);
1764 if (!calli
&& op
== -1 && (!is_virtual
|| (target_method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) == 0) &&
1765 (target_method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) == 0 &&
1766 (target_method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) == 0 &&
1767 !(target_method
->iflags
& METHOD_IMPL_ATTRIBUTE_NOINLINING
)) {
1768 (void)mono_class_vtable_checked (domain
, target_method
->klass
, error
);
1769 return_val_if_nok (error
, FALSE
);
1771 if (method
== target_method
&& *(td
->ip
+ 5) == CEE_RET
&& !(csignature
->hasthis
&& m_class_is_valuetype (target_method
->klass
))) {
1772 if (td
->inlined_method
)
1775 if (td
->verbose_level
)
1776 g_print ("Optimize tail call of %s.%s\n", m_class_get_name (target_method
->klass
), target_method
->name
);
1778 for (i
= csignature
->param_count
- 1 + !!csignature
->hasthis
; i
>= 0; --i
)
1781 interp_add_ins (td
, MINT_BR_S
);
1782 // We are branching to the beginning of the method
1783 td
->last_ins
->data
[0] = 0;
1784 if (!is_bb_start
[td
->ip
+ 5 - td
->il_code
])
1785 ++td
->ip
; /* gobble the CEE_RET if it isn't branched to */
1791 target_method
= interp_transform_internal_calls (method
, target_method
, csignature
, is_virtual
);
1793 if (csignature
->call_convention
== MONO_CALL_VARARG
) {
1794 csignature
= mono_method_get_signature_checked (target_method
, image
, token
, generic_context
, error
);
1795 int vararg_stack
= 0;
1797 * For vararg calls, ArgIterator expects the signature and the varargs to be
1798 * stored in a linear memory. We allocate the necessary vt_stack space for
1799 * this. All varargs will be pushed to the vt_stack at call site.
1801 vararg_stack
+= sizeof (gpointer
);
1802 for (i
= csignature
->sentinelpos
; i
< csignature
->param_count
; ++i
) {
1803 int align
, arg_size
;
1804 arg_size
= mono_type_stack_size (csignature
->params
[i
], &align
);
1805 vararg_stack
+= arg_size
;
1807 vt_stack_used
+= ALIGN_TO (vararg_stack
, MINT_VT_ALIGNMENT
);
1808 PUSH_VT (td
, vararg_stack
);
1811 if (need_null_check
) {
1812 interp_add_ins (td
, MINT_CKNULL_N
);
1813 td
->last_ins
->data
[0] = csignature
->param_count
+ 1;
1816 g_assert (csignature
->call_convention
!= MONO_CALL_FASTCALL
);
1817 if ((mono_interp_opt
& INTERP_OPT_INLINE
) && op
== -1 && !is_virtual
&& target_method
&& interp_method_check_inlining (td
, target_method
)) {
1818 MonoMethodHeader
*mheader
= interp_method_get_header (target_method
, error
);
1819 return_val_if_nok (error
, FALSE
);
1821 if (interp_inline_method (td
, target_method
, mheader
, error
)) {
1827 /* Don't inline methods that do calls */
1828 if (op
== -1 && td
->inlined_method
)
1831 td
->sp
-= csignature
->param_count
+ !!csignature
->hasthis
;
1832 for (i
= 0; i
< csignature
->param_count
; ++i
) {
1833 if (td
->sp
[i
+ !!csignature
->hasthis
].type
== STACK_TYPE_VT
) {
1835 MonoClass
*klass
= mono_class_from_mono_type_internal (csignature
->params
[i
]);
1836 if (csignature
->pinvoke
&& method
->wrapper_type
!= MONO_WRAPPER_NONE
)
1837 size
= mono_class_native_size (klass
, NULL
);
1839 size
= mono_class_value_size (klass
, NULL
);
1840 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
1841 vt_stack_used
+= size
;
1845 /* need to handle typedbyref ... */
1846 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
1847 int mt
= mint_type(csignature
->ret
);
1848 MonoClass
*klass
= mono_class_from_mono_type_internal (csignature
->ret
);
1849 if (mt
== MINT_TYPE_VT
) {
1850 if (csignature
->pinvoke
&& method
->wrapper_type
!= MONO_WRAPPER_NONE
)
1851 vt_res_size
= mono_class_native_size (klass
, NULL
);
1853 vt_res_size
= mono_class_value_size (klass
, NULL
);
1854 if (mono_class_has_failure (klass
)) {
1855 mono_error_set_for_class_failure (error
, klass
);
1858 PUSH_VT(td
, vt_res_size
);
1860 PUSH_TYPE(td
, stack_type
[mt
], klass
);
1864 /* We need to convert delegate invoke to a indirect call on the interp_invoke_impl field */
1865 if (target_method
&& m_class_get_parent (target_method
->klass
) == mono_defaults
.multicastdelegate_class
) {
1866 const char *name
= target_method
->name
;
1867 if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
1869 interp_add_ins (td
, MINT_LD_DELEGATE_INVOKE_IMPL
);
1870 td
->last_ins
->data
[0] = csignature
->param_count
+ 1;
1875 interp_add_ins (td
, op
);
1877 if (op
== MINT_LDLEN
) {
1878 #ifdef MONO_BIG_ARRAYS
1879 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I8
);
1881 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I4
);
1884 if (op
== MINT_LDELEMA
|| op
== MINT_LDELEMA_TC
) {
1885 td
->last_ins
->data
[0] = get_data_item_index (td
, m_class_get_element_class (target_method
->klass
));
1886 td
->last_ins
->data
[1] = 1 + m_class_get_rank (target_method
->klass
);
1889 if (op
== MINT_CALLRUN
) {
1890 td
->last_ins
->data
[0] = get_data_item_index (td
, target_method
);
1891 td
->last_ins
->data
[1] = get_data_item_index (td
, mono_method_signature_internal (target_method
));
1893 } else if (!calli
&& !is_virtual
&& jit_call_supported (target_method
, csignature
)) {
1894 interp_add_ins (td
, MINT_JIT_CALL
);
1895 td
->last_ins
->data
[0] = get_data_item_index (td
, (void *)mono_interp_get_imethod (domain
, target_method
, error
));
1896 mono_error_assert_ok (error
);
1898 #ifndef MONO_ARCH_HAS_NO_PROPER_MONOCTX
1899 /* Try using fast icall path for simple signatures */
1900 if (native
&& !method
->dynamic
)
1901 op
= interp_icall_op_for_sig (csignature
);
1903 if (csignature
->call_convention
== MONO_CALL_VARARG
)
1904 interp_add_ins (td
, MINT_CALL_VARARG
);
1906 interp_add_ins (td
, native
? ((op
!= -1) ? MINT_CALLI_NAT_FAST
: MINT_CALLI_NAT
) : MINT_CALLI
);
1907 else if (is_virtual
&& !mono_class_is_marshalbyref (target_method
->klass
))
1908 interp_add_ins (td
, is_void
? MINT_VCALLVIRT_FAST
: MINT_CALLVIRT_FAST
);
1909 else if (is_virtual
)
1910 interp_add_ins (td
, is_void
? MINT_VCALLVIRT
: MINT_CALLVIRT
);
1912 interp_add_ins (td
, is_void
? MINT_VCALL
: MINT_CALL
);
1915 td
->last_ins
->data
[0] = get_data_item_index (td
, (void *)csignature
);
1917 td
->last_ins
->data
[1] = op
;
1919 td
->last_ins
->data
[0] = get_data_item_index (td
, (void *)mono_interp_get_imethod (domain
, target_method
, error
));
1920 return_val_if_nok (error
, FALSE
);
1921 if (csignature
->call_convention
== MONO_CALL_VARARG
)
1922 td
->last_ins
->data
[1] = get_data_item_index (td
, (void *)csignature
);
1923 else if (is_virtual
&& !mono_class_is_marshalbyref (target_method
->klass
)) {
1924 /* FIXME Use fastpath also for MBRO. Asserts in mono_method_get_vtable_slot */
1925 if (mono_class_is_interface (target_method
->klass
))
1926 td
->last_ins
->data
[1] = -2 * MONO_IMT_SIZE
+ mono_method_get_imt_slot (target_method
);
1928 td
->last_ins
->data
[1] = mono_method_get_vtable_slot (target_method
);
1933 if (vt_stack_used
!= 0 || vt_res_size
!= 0) {
1934 interp_add_ins (td
, MINT_VTRESULT
);
1935 td
->last_ins
->data
[0] = vt_res_size
;
1936 WRITE32_INS (td
->last_ins
, 1, &vt_stack_used
);
1937 td
->vt_sp
-= vt_stack_used
;
1943 static MonoClassField
*
1944 interp_field_from_token (MonoMethod
*method
, guint32 token
, MonoClass
**klass
, MonoGenericContext
*generic_context
, MonoError
*error
)
1946 MonoClassField
*field
= NULL
;
1947 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
1948 field
= (MonoClassField
*) mono_method_get_wrapper_data (method
, token
);
1949 *klass
= field
->parent
;
1951 mono_class_setup_fields (field
->parent
);
1953 field
= mono_field_from_token_checked (m_class_get_image (method
->klass
), token
, klass
, generic_context
, error
);
1954 return_val_if_nok (error
, NULL
);
1957 if (!method
->skip_visibility
&& !mono_method_can_access_field (method
, field
)) {
1958 char *method_fname
= mono_method_full_name (method
, TRUE
);
1959 char *field_fname
= mono_field_full_name (field
);
1960 mono_error_set_generic_error (error
, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname
, method_fname
);
1961 g_free (method_fname
);
1962 g_free (field_fname
);
1969 static InterpBasicBlock
*
1970 get_bb (TransformData
*td
, InterpBasicBlock
*cbb
, unsigned char *ip
)
1972 int offset
= ip
- td
->il_code
;
1973 InterpBasicBlock
*bb
= td
->offset_to_bb
[offset
];
1976 bb
= (InterpBasicBlock
*)mono_mempool_alloc0 (td
->mempool
, sizeof (InterpBasicBlock
));
1978 td
->offset_to_bb
[offset
] = bb
;
1980 td
->basic_blocks
= g_list_append_mempool (td
->mempool
, td
->basic_blocks
, bb
);
1984 bb
->preds
= g_slist_prepend_mempool (td
->mempool
, bb
->preds
, cbb
);
1991 * Compute the set of IL level basic blocks.
1994 get_basic_blocks (TransformData
*td
)
1996 guint8
*start
= (guint8
*)td
->il_code
;
1997 guint8
*end
= (guint8
*)td
->il_code
+ td
->code_size
;
1999 unsigned char *target
;
2002 const MonoOpcode
*opcode
;
2003 InterpBasicBlock
*cbb
;
2005 td
->offset_to_bb
= (InterpBasicBlock
**)mono_mempool_alloc0 (td
->mempool
, sizeof (InterpBasicBlock
*) * (end
- start
+ 1));
2006 td
->entry_bb
= cbb
= get_bb (td
, NULL
, start
);
2009 cli_addr
= ip
- start
;
2010 td
->offset_to_bb
[cli_addr
] = cbb
;
2011 i
= mono_opcode_value ((const guint8
**)&ip
, end
);
2012 opcode
= &mono_opcodes
[i
];
2013 switch (opcode
->argument
) {
2014 case MonoInlineNone
:
2017 case MonoInlineString
:
2018 case MonoInlineType
:
2019 case MonoInlineField
:
2020 case MonoInlineMethod
:
2023 case MonoShortInlineR
:
2030 case MonoShortInlineVar
:
2031 case MonoShortInlineI
:
2034 case MonoShortInlineBrTarget
:
2035 target
= start
+ cli_addr
+ 2 + (signed char)ip
[1];
2036 get_bb (td
, cbb
, target
);
2038 cbb
= get_bb (td
, cbb
, ip
);
2040 case MonoInlineBrTarget
:
2041 target
= start
+ cli_addr
+ 5 + (gint32
)read32 (ip
+ 1);
2042 get_bb (td
, cbb
, target
);
2044 cbb
= get_bb (td
, cbb
, ip
);
2046 case MonoInlineSwitch
: {
2047 guint32 n
= read32 (ip
+ 1);
2050 cli_addr
+= 5 + 4 * n
;
2051 target
= start
+ cli_addr
;
2052 get_bb (td
, cbb
, target
);
2054 for (j
= 0; j
< n
; ++j
) {
2055 target
= start
+ cli_addr
+ (gint32
)read32 (ip
);
2056 get_bb (td
, cbb
, target
);
2059 cbb
= get_bb (td
, cbb
, ip
);
2067 g_assert_not_reached ();
2071 cbb
= get_bb (td
, NULL
, ip
);
2076 interp_save_debug_info (InterpMethod
*rtm
, MonoMethodHeader
*header
, TransformData
*td
, GArray
*line_numbers
)
2078 MonoDebugMethodJitInfo
*dinfo
;
2081 if (!mono_debug_enabled ())
2085 * We save the debug info in the same way the JIT does it, treating the interpreter IR as the native code.
2088 dinfo
= g_new0 (MonoDebugMethodJitInfo
, 1);
2089 dinfo
->num_params
= rtm
->param_count
;
2090 dinfo
->params
= g_new0 (MonoDebugVarInfo
, dinfo
->num_params
);
2091 dinfo
->num_locals
= header
->num_locals
;
2092 dinfo
->locals
= g_new0 (MonoDebugVarInfo
, header
->num_locals
);
2093 dinfo
->code_start
= (guint8
*)rtm
->code
;
2094 dinfo
->code_size
= td
->new_code_end
- td
->new_code
;
2095 dinfo
->epilogue_begin
= 0;
2096 dinfo
->has_var_info
= TRUE
;
2097 dinfo
->num_line_numbers
= line_numbers
->len
;
2098 dinfo
->line_numbers
= g_new0 (MonoDebugLineNumberEntry
, dinfo
->num_line_numbers
);
2100 for (i
= 0; i
< dinfo
->num_params
; i
++) {
2101 MonoDebugVarInfo
*var
= &dinfo
->params
[i
];
2102 var
->type
= rtm
->param_types
[i
];
2104 for (i
= 0; i
< dinfo
->num_locals
; i
++) {
2105 MonoDebugVarInfo
*var
= &dinfo
->locals
[i
];
2106 var
->type
= mono_metadata_type_dup (NULL
, header
->locals
[i
]);
2109 for (i
= 0; i
< dinfo
->num_line_numbers
; i
++)
2110 dinfo
->line_numbers
[i
] = g_array_index (line_numbers
, MonoDebugLineNumberEntry
, i
);
2111 mono_debug_add_method (rtm
->method
, dinfo
, rtm
->domain
);
2113 mono_debug_free_method_jit_info (dinfo
);
2116 /* Same as the code in seq-points.c */
2118 insert_pred_seq_point (SeqPoint
*last_sp
, SeqPoint
*sp
, GSList
**next
)
2121 int src_index
= last_sp
->next_offset
;
2122 int dst_index
= sp
->next_offset
;
2124 /* bb->in_bb might contain duplicates */
2125 for (l
= next
[src_index
]; l
; l
= l
->next
)
2126 if (GPOINTER_TO_UINT (l
->data
) == dst_index
)
2129 next
[src_index
] = g_slist_append (next
[src_index
], GUINT_TO_POINTER (dst_index
));
2133 recursively_make_pred_seq_points (TransformData
*td
, InterpBasicBlock
*bb
)
2135 SeqPoint
** const MONO_SEQ_SEEN_LOOP
= (SeqPoint
**)GINT_TO_POINTER(-1);
2138 GArray
*predecessors
= g_array_new (FALSE
, TRUE
, sizeof (gpointer
));
2139 GHashTable
*seen
= g_hash_table_new_full (g_direct_hash
, NULL
, NULL
, NULL
);
2141 // Insert/remove sentinel into the memoize table to detect loops containing bb
2142 bb
->pred_seq_points
= MONO_SEQ_SEEN_LOOP
;
2144 for (l
= bb
->preds
; l
; l
= l
->next
) {
2145 InterpBasicBlock
*in_bb
= (InterpBasicBlock
*)l
->data
;
2147 // This bb has the last seq point, append it and continue
2148 if (in_bb
->last_seq_point
!= NULL
) {
2149 predecessors
= g_array_append_val (predecessors
, in_bb
->last_seq_point
);
2153 // We've looped or handled this before, exit early.
2154 // No last sequence points to find.
2155 if (in_bb
->pred_seq_points
== MONO_SEQ_SEEN_LOOP
)
2158 // Take sequence points from incoming basic blocks
2160 if (in_bb
== td
->entry_bb
)
2163 if (in_bb
->pred_seq_points
== NULL
)
2164 recursively_make_pred_seq_points (td
, in_bb
);
2166 // Union sequence points with incoming bb's
2167 for (int i
=0; i
< in_bb
->num_pred_seq_points
; i
++) {
2168 if (!g_hash_table_lookup (seen
, in_bb
->pred_seq_points
[i
])) {
2169 g_array_append_val (predecessors
, in_bb
->pred_seq_points
[i
]);
2170 g_hash_table_insert (seen
, in_bb
->pred_seq_points
[i
], (gpointer
)&MONO_SEQ_SEEN_LOOP
);
2173 // predecessors = g_array_append_vals (predecessors, in_bb->pred_seq_points, in_bb->num_pred_seq_points);
2176 g_hash_table_destroy (seen
);
2178 if (predecessors
->len
!= 0) {
2179 bb
->pred_seq_points
= (SeqPoint
**)mono_mempool_alloc0 (td
->mempool
, sizeof (SeqPoint
*) * predecessors
->len
);
2180 bb
->num_pred_seq_points
= predecessors
->len
;
2182 for (int newer
= 0; newer
< bb
->num_pred_seq_points
; newer
++) {
2183 bb
->pred_seq_points
[newer
] = (SeqPoint
*)g_array_index (predecessors
, gpointer
, newer
);
2187 g_array_free (predecessors
, TRUE
);
2191 collect_pred_seq_points (TransformData
*td
, InterpBasicBlock
*bb
, SeqPoint
*seqp
, GSList
**next
)
2193 // Doesn't have a last sequence point, must find from incoming basic blocks
2194 if (bb
->pred_seq_points
== NULL
&& bb
!= td
->entry_bb
)
2195 recursively_make_pred_seq_points (td
, bb
);
2197 for (int i
= 0; i
< bb
->num_pred_seq_points
; i
++)
2198 insert_pred_seq_point (bb
->pred_seq_points
[i
], seqp
, next
);
2204 save_seq_points (TransformData
*td
, MonoJitInfo
*jinfo
)
2207 int i
, seq_info_size
;
2208 MonoSeqPointInfo
*info
;
2209 GSList
**next
= NULL
;
2212 if (!td
->gen_sdb_seq_points
)
2216 * For each sequence point, compute the list of sequence points immediately
2217 * following it, this is needed to implement 'step over' in the debugger agent.
2218 * Similar to the code in mono_save_seq_point_info ().
2220 for (i
= 0; i
< td
->seq_points
->len
; ++i
) {
2221 SeqPoint
*sp
= (SeqPoint
*)g_ptr_array_index (td
->seq_points
, i
);
2223 /* Store the seq point index here temporarily */
2224 sp
->next_offset
= i
;
2226 next
= (GSList
**)mono_mempool_alloc0 (td
->mempool
, sizeof (GList
*) * td
->seq_points
->len
);
2227 for (bblist
= td
->basic_blocks
; bblist
; bblist
= bblist
->next
) {
2228 InterpBasicBlock
*bb
= (InterpBasicBlock
*)bblist
->data
;
2230 GSList
*bb_seq_points
= g_slist_reverse (bb
->seq_points
);
2231 SeqPoint
*last
= NULL
;
2232 for (GSList
*l
= bb_seq_points
; l
; l
= l
->next
) {
2233 SeqPoint
*sp
= (SeqPoint
*)l
->data
;
2235 if (sp
->il_offset
== METHOD_ENTRY_IL_OFFSET
|| sp
->il_offset
== METHOD_EXIT_IL_OFFSET
)
2236 /* Used to implement method entry/exit events */
2240 /* Link with the previous seq point in the same bb */
2241 next
[last
->next_offset
] = g_slist_append_mempool (td
->mempool
, next
[last
->next_offset
], GINT_TO_POINTER (sp
->next_offset
));
2243 /* Link with the last bb in the previous bblocks */
2244 collect_pred_seq_points (td
, bb
, sp
, next
);
2250 /* Serialize the seq points into a byte array */
2251 array
= g_byte_array_new ();
2252 SeqPoint zero_seq_point
= {0};
2253 SeqPoint
* last_seq_point
= &zero_seq_point
;
2254 for (i
= 0; i
< td
->seq_points
->len
; ++i
) {
2255 SeqPoint
*sp
= (SeqPoint
*)g_ptr_array_index (td
->seq_points
, i
);
2257 sp
->next_offset
= 0;
2258 if (mono_seq_point_info_add_seq_point (array
, sp
, last_seq_point
, next
[i
], TRUE
))
2259 last_seq_point
= sp
;
2262 if (td
->verbose_level
) {
2263 g_print ("\nSEQ POINT MAP FOR %s: \n", td
->method
->name
);
2265 for (i
= 0; i
< td
->seq_points
->len
; ++i
) {
2266 SeqPoint
*sp
= (SeqPoint
*)g_ptr_array_index (td
->seq_points
, i
);
2272 g_print ("\tIL0x%x[0x%0x] ->", sp
->il_offset
, sp
->native_offset
);
2273 for (l
= next
[i
]; l
; l
= l
->next
) {
2274 int next_index
= GPOINTER_TO_UINT (l
->data
);
2275 g_print (" IL0x%x", ((SeqPoint
*)g_ptr_array_index (td
->seq_points
, next_index
))->il_offset
);
2281 info
= mono_seq_point_info_new (array
->len
, TRUE
, array
->data
, TRUE
, &seq_info_size
);
2282 mono_atomic_fetch_add_i32 (&mono_jit_stats
.allocated_seq_points_size
, seq_info_size
);
2284 g_byte_array_free (array
, TRUE
);
2286 jinfo
->seq_points
= info
;
2289 #define BARRIER_IF_VOLATILE(td) \
2292 interp_add_ins (td, MINT_MONO_MEMORY_BARRIER); \
2293 volatile_ = FALSE; \
2297 #define INLINE_FAILURE \
2299 if (td->method != method) \
2304 interp_method_compute_offsets (InterpMethod
*imethod
, MonoMethodSignature
*signature
, MonoMethodHeader
*header
)
2306 int i
, offset
, size
, align
;
2308 imethod
->local_offsets
= (guint32
*)g_malloc (header
->num_locals
* sizeof(guint32
));
2310 for (i
= 0; i
< header
->num_locals
; ++i
) {
2311 size
= mono_type_size (header
->locals
[i
], &align
);
2312 offset
+= align
- 1;
2313 offset
&= ~(align
- 1);
2314 imethod
->local_offsets
[i
] = offset
;
2317 offset
= (offset
+ 7) & ~7;
2319 imethod
->exvar_offsets
= (guint32
*)g_malloc (header
->num_clauses
* sizeof (guint32
));
2320 for (i
= 0; i
< header
->num_clauses
; i
++) {
2321 imethod
->exvar_offsets
[i
] = offset
;
2322 offset
+= sizeof (MonoObject
*);
2324 offset
= (offset
+ 7) & ~7;
2326 imethod
->locals_size
= offset
;
2327 g_assert (imethod
->locals_size
< 65536);
2331 get_arg_type (MonoMethodSignature
*signature
, int arg_n
)
2333 if (signature
->hasthis
&& arg_n
== 0)
2334 return mono_get_object_type ();
2335 return signature
->params
[arg_n
- !!signature
->hasthis
];
2339 init_bb_start (TransformData
*td
, MonoMethodHeader
*header
)
2341 const unsigned char *ip
, *end
;
2342 const MonoOpcode
*opcode
;
2343 int offset
, i
, in
, backwards
;
2345 /* intern the strings in the method. */
2347 end
= ip
+ header
->code_size
;
2349 td
->is_bb_start
[0] = 1;
2356 else if (in
== 0xf0) {
2358 in
= *ip
+ MONO_CEE_MONO_ICALL
;
2360 opcode
= &mono_opcodes
[in
];
2361 switch (opcode
->argument
) {
2362 case MonoInlineNone
:
2365 case MonoInlineString
:
2368 case MonoInlineType
:
2371 case MonoInlineMethod
:
2374 case MonoInlineField
:
2378 case MonoShortInlineR
:
2381 case MonoInlineBrTarget
:
2382 offset
= read32 (ip
+ 1);
2384 backwards
= offset
< 0;
2385 offset
+= ip
- header
->code
;
2386 g_assert (offset
>= 0 && offset
< header
->code_size
);
2387 td
->is_bb_start
[offset
] |= backwards
? 2 : 1;
2389 case MonoShortInlineBrTarget
:
2390 offset
= ((gint8
*)ip
) [1];
2392 backwards
= offset
< 0;
2393 offset
+= ip
- header
->code
;
2394 g_assert (offset
>= 0 && offset
< header
->code_size
);
2395 td
->is_bb_start
[offset
] |= backwards
? 2 : 1;
2400 case MonoShortInlineVar
:
2401 case MonoShortInlineI
:
2404 case MonoInlineSwitch
: {
2406 const unsigned char *next_ip
;
2410 next_ip
= ip
+ 4 * n
;
2411 for (i
= 0; i
< n
; i
++) {
2412 offset
= read32 (ip
);
2413 backwards
= offset
< 0;
2414 offset
+= next_ip
- header
->code
;
2415 g_assert (offset
>= 0 && offset
< header
->code_size
);
2416 td
->is_bb_start
[offset
] |= backwards
? 2 : 1;
2426 g_assert_not_reached ();
2431 #ifdef NO_UNALIGNED_ACCESS
2433 get_unaligned_opcode (int opcode
)
2437 return MINT_LDFLD_I8_UNALIGNED
;
2439 return MINT_LDFLD_R8_UNALIGNED
;
2441 return MINT_STFLD_I8_UNALIGNED
;
2443 return MINT_STFLD_R8_UNALIGNED
;
2445 g_assert_not_reached ();
2452 interp_handle_isinst (TransformData
*td
, MonoClass
*klass
, gboolean isinst_instr
)
2454 /* Follow the logic from jit's handle_isinst */
2455 if (!mono_class_has_variant_generic_params (klass
)) {
2456 if (mono_class_is_interface (klass
))
2457 interp_add_ins (td
, isinst_instr
? MINT_ISINST_INTERFACE
: MINT_CASTCLASS_INTERFACE
);
2458 else if (!mono_class_is_marshalbyref (klass
) && m_class_get_rank (klass
) == 0 && !mono_class_is_nullable (klass
))
2459 interp_add_ins (td
, isinst_instr
? MINT_ISINST_COMMON
: MINT_CASTCLASS_COMMON
);
2461 interp_add_ins (td
, isinst_instr
? MINT_ISINST
: MINT_CASTCLASS
);
2463 interp_add_ins (td
, isinst_instr
? MINT_ISINST
: MINT_CASTCLASS
);
2465 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
2470 interp_emit_ldobj (TransformData
*td
, MonoClass
*klass
)
2472 int mt
= mint_type (m_class_get_byval_arg (klass
));
2475 if (mt
== MINT_TYPE_VT
) {
2476 interp_add_ins (td
, MINT_LDOBJ_VT
);
2477 td
->last_ins
->data
[0] = get_data_item_index(td
, klass
);
2478 size
= mono_class_value_size (klass
, NULL
);
2483 case MINT_TYPE_I1
: opcode
= MINT_LDIND_I1_CHECK
; break;
2484 case MINT_TYPE_U1
: opcode
= MINT_LDIND_U1_CHECK
; break;
2485 case MINT_TYPE_I2
: opcode
= MINT_LDIND_I2_CHECK
; break;
2486 case MINT_TYPE_U2
: opcode
= MINT_LDIND_U2_CHECK
; break;
2487 case MINT_TYPE_I4
: opcode
= MINT_LDIND_I4_CHECK
; break;
2488 case MINT_TYPE_I8
: opcode
= MINT_LDIND_I8_CHECK
; break;
2489 case MINT_TYPE_R4
: opcode
= MINT_LDIND_R4_CHECK
; break;
2490 case MINT_TYPE_R8
: opcode
= MINT_LDIND_R8_CHECK
; break;
2491 case MINT_TYPE_O
: opcode
= MINT_LDIND_REF
; break;
2492 default: g_assert_not_reached (); break;
2494 interp_add_ins (td
, opcode
);
2497 SET_TYPE (td
->sp
- 1, stack_type
[mt
], klass
);
2501 interp_emit_stobj (TransformData
*td
, MonoClass
*klass
)
2503 int mt
= mint_type (m_class_get_byval_arg (klass
));
2505 if (mt
== MINT_TYPE_VT
) {
2507 interp_add_ins (td
, MINT_STOBJ_VT
);
2508 td
->last_ins
->data
[0] = get_data_item_index(td
, klass
);
2509 size
= mono_class_value_size (klass
, NULL
);
2516 opcode
= MINT_STIND_I1
;
2520 opcode
= MINT_STIND_I2
;
2523 opcode
= MINT_STIND_I4
;
2526 opcode
= MINT_STIND_I8
;
2529 opcode
= MINT_STIND_R4
;
2532 opcode
= MINT_STIND_R8
;
2535 opcode
= MINT_STIND_REF
;
2537 default: g_assert_not_reached (); break;
2539 interp_add_ins (td
, opcode
);
2545 interp_emit_ldsfld (TransformData
*td
, MonoClassField
*field
, MonoClass
*field_class
, int mt
, MonoError
*error
)
2547 if (mono_class_field_is_special_static (field
)) {
2548 interp_add_ins (td
, (mt
== MINT_TYPE_VT
) ? MINT_LDSSFLD_VT_SLOW
: MINT_LDSSFLD_SLOW
);
2549 td
->last_ins
->data
[0] = get_data_item_index (td
, field
);
2550 if (mt
== MINT_TYPE_VT
) {
2551 int size
= mono_class_value_size (field_class
, NULL
);
2552 WRITE32_INS(td
->last_ins
, 1, &size
);
2555 MonoVTable
*vtable
= mono_class_vtable_checked (td
->rtm
->domain
, field
->parent
, error
);
2556 return_if_nok (error
);
2558 interp_add_ins (td
, (mt
== MINT_TYPE_VT
) ? MINT_LDSFLD_VT
: (MINT_LDSFLD_I1
+ mt
- MINT_TYPE_I1
));
2559 td
->last_ins
->data
[0] = get_data_item_index (td
, vtable
);
2560 td
->last_ins
->data
[1] = get_data_item_index (td
, (char*)mono_vtable_get_static_field_data (vtable
) + field
->offset
);
2562 if (mt
== MINT_TYPE_VT
) {
2563 int size
= mono_class_value_size (field_class
, NULL
);
2564 WRITE32_INS(td
->last_ins
, 2, &size
);
2570 interp_emit_stsfld (TransformData
*td
, MonoClassField
*field
, MonoClass
*field_class
, int mt
, MonoError
*error
)
2572 if (mono_class_field_is_special_static (field
)) {
2573 interp_add_ins (td
, (mt
== MINT_TYPE_VT
) ? MINT_STSSFLD_VT_SLOW
: MINT_STSSFLD_SLOW
);
2574 td
->last_ins
->data
[0] = get_data_item_index (td
, field
);
2575 if (mt
== MINT_TYPE_VT
) {
2576 int size
= mono_class_value_size (field_class
, NULL
);
2577 WRITE32_INS(td
->last_ins
, 1, &size
);
2580 MonoVTable
*vtable
= mono_class_vtable_checked (td
->rtm
->domain
, field
->parent
, error
);
2581 return_if_nok (error
);
2583 interp_add_ins (td
, (mt
== MINT_TYPE_VT
) ? MINT_STSFLD_VT
: (MINT_STSFLD_I1
+ mt
- MINT_TYPE_I1
));
2584 td
->last_ins
->data
[0] = get_data_item_index (td
, vtable
);
2585 td
->last_ins
->data
[1] = get_data_item_index (td
, (char*)mono_vtable_get_static_field_data (vtable
) + field
->offset
);
2587 if (mt
== MINT_TYPE_VT
) {
2588 int size
= mono_class_value_size (field_class
, NULL
);
2589 WRITE32_INS(td
->last_ins
, 2, &size
);
2595 generate_code (TransformData
*td
, MonoMethod
*method
, MonoMethodHeader
*header
, MonoGenericContext
*generic_context
, MonoError
*error
)
2598 int offset
, mt
, i
, i32
;
2601 const unsigned char *end
;
2602 MonoSimpleBasicBlock
*bb
= NULL
, *original_bb
= NULL
;
2603 gboolean sym_seq_points
= FALSE
;
2604 MonoBitSet
*seq_point_locs
= NULL
;
2605 gboolean readonly
= FALSE
;
2606 gboolean volatile_
= FALSE
;
2607 MonoClass
*constrained_class
= NULL
;
2609 MonoClassField
*field
;
2610 MonoImage
*image
= m_class_get_image (method
->klass
);
2611 InterpMethod
*rtm
= td
->rtm
;
2612 MonoDomain
*domain
= rtm
->domain
;
2613 MonoMethodSignature
*signature
= mono_method_signature_internal (method
);
2614 gboolean ret
= TRUE
;
2615 gboolean emitted_funccall_seq_point
= FALSE
;
2616 guint32
*arg_offsets
= NULL
;
2617 InterpInst
*last_seq_point
= NULL
;
2619 original_bb
= bb
= mono_basic_block_split (method
, error
, header
);
2620 goto_if_nok (error
, exit
);
2623 td
->il_code
= header
->code
;
2624 td
->in_start
= td
->ip
= header
->code
;
2625 end
= td
->ip
+ header
->code_size
;
2626 td
->stack_state
= (StackInfo
**)g_malloc0(header
->code_size
* sizeof(StackInfo
*));
2627 td
->stack_height
= (int*)g_malloc(header
->code_size
* sizeof(int));
2628 td
->vt_stack_size
= (int*)g_malloc(header
->code_size
* sizeof(int));
2629 td
->clause_indexes
= (int*)g_malloc (header
->code_size
* sizeof (int));
2630 td
->is_bb_start
= (guint8
*)g_malloc0(header
->code_size
);
2632 init_bb_start (td
, header
);
2634 for (i
= 0; i
< header
->code_size
; i
++) {
2635 td
->stack_height
[i
] = -1;
2636 td
->clause_indexes
[i
] = -1;
2639 for (i
= 0; i
< header
->num_clauses
; i
++) {
2640 MonoExceptionClause
*c
= header
->clauses
+ i
;
2641 td
->stack_height
[c
->handler_offset
] = 0;
2642 td
->vt_stack_size
[c
->handler_offset
] = 0;
2643 td
->is_bb_start
[c
->handler_offset
] = 1;
2645 td
->stack_height
[c
->handler_offset
] = 1;
2646 td
->stack_state
[c
->handler_offset
] = (StackInfo
*)g_malloc0(sizeof(StackInfo
));
2647 td
->stack_state
[c
->handler_offset
][0].type
= STACK_TYPE_O
;
2648 td
->stack_state
[c
->handler_offset
][0].klass
= NULL
; /*FIX*/
2650 if (c
->flags
& MONO_EXCEPTION_CLAUSE_FILTER
) {
2651 td
->stack_height
[c
->data
.filter_offset
] = 0;
2652 td
->vt_stack_size
[c
->data
.filter_offset
] = 0;
2653 td
->is_bb_start
[c
->data
.filter_offset
] = 1;
2655 td
->stack_height
[c
->data
.filter_offset
] = 1;
2656 td
->stack_state
[c
->data
.filter_offset
] = (StackInfo
*)g_malloc0(sizeof(StackInfo
));
2657 td
->stack_state
[c
->data
.filter_offset
][0].type
= STACK_TYPE_O
;
2658 td
->stack_state
[c
->data
.filter_offset
][0].klass
= NULL
; /*FIX*/
2661 for (int j
= c
->handler_offset
; j
< c
->handler_offset
+ c
->handler_len
; ++j
) {
2662 if (td
->clause_indexes
[j
] == -1)
2663 td
->clause_indexes
[j
] = i
;
2667 if (td
->gen_sdb_seq_points
&& td
->method
== method
) {
2668 MonoDebugMethodInfo
*minfo
;
2669 get_basic_blocks (td
);
2671 minfo
= mono_debug_lookup_method (method
);
2674 MonoSymSeqPoint
*sps
;
2675 int i
, n_il_offsets
;
2677 mono_debug_get_seq_points (minfo
, NULL
, NULL
, NULL
, &sps
, &n_il_offsets
);
2679 seq_point_locs
= mono_bitset_mem_new (mono_mempool_alloc0 (td
->mempool
, mono_bitset_alloc_size (header
->code_size
, 0)), header
->code_size
, 0);
2680 sym_seq_points
= TRUE
;
2682 for (i
= 0; i
< n_il_offsets
; ++i
) {
2683 if (sps
[i
].il_offset
< header
->code_size
)
2684 mono_bitset_set_fast (seq_point_locs
, sps
[i
].il_offset
);
2688 MonoDebugMethodAsyncInfo
* asyncMethod
= mono_debug_lookup_method_async_debug_info (method
);
2690 for (i
= 0; asyncMethod
!= NULL
&& i
< asyncMethod
->num_awaits
; i
++) {
2691 mono_bitset_set_fast (seq_point_locs
, asyncMethod
->resume_offsets
[i
]);
2692 mono_bitset_set_fast (seq_point_locs
, asyncMethod
->yield_offsets
[i
]);
2694 mono_debug_free_method_async_debug_info (asyncMethod
);
2696 } else if (!method
->wrapper_type
&& !method
->dynamic
&& mono_debug_image_has_debug_info (m_class_get_image (method
->klass
))) {
2697 /* Methods without line number info like auto-generated property accessors */
2698 seq_point_locs
= mono_bitset_new (header
->code_size
, 0);
2699 sym_seq_points
= TRUE
;
2703 if (sym_seq_points
) {
2704 last_seq_point
= interp_add_ins (td
, MINT_SDB_SEQ_POINT
);
2705 last_seq_point
->flags
= INTERP_INST_FLAG_SEQ_POINT_METHOD_ENTRY
;
2708 if (mono_debugger_method_has_breakpoint (method
))
2709 interp_add_ins (td
, MINT_BREAKPOINT
);
2711 if (method
== td
->method
) {
2712 if (td
->verbose_level
) {
2713 char *tmp
= mono_disasm_code (NULL
, method
, td
->ip
, end
);
2714 char *name
= mono_method_full_name (method
, TRUE
);
2715 g_print ("Method %s, original code:\n", name
);
2716 g_print ("%s\n", tmp
);
2721 if (header
->num_locals
&& header
->init_locals
)
2722 interp_add_ins (td
, MINT_INITLOCALS
);
2724 if (rtm
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_ENTER
)
2725 interp_add_ins (td
, MINT_PROF_ENTER
);
2727 /* safepoint is required on method entry */
2728 if (mono_threads_are_safepoints_enabled ())
2729 interp_add_ins (td
, MINT_SAFEPOINT
);
2732 arg_offsets
= (guint32
*) g_malloc ((!!signature
->hasthis
+ signature
->param_count
) * sizeof (guint32
));
2733 /* Allocate locals to store inlined method args from stack */
2734 for (i
= signature
->param_count
- 1; i
>= 0; i
--) {
2735 offset
= create_interp_local (td
, signature
->params
[i
]);
2736 arg_offsets
[i
+ !!signature
->hasthis
] = offset
;
2737 store_local_general (td
, offset
, signature
->params
[i
]);
2740 if (signature
->hasthis
) {
2742 * If this is value type, it is passed by address and not by value.
2743 * FIXME We should use MINT_TYPE_P instead of MINT_TYPE_O
2745 MonoType
*type
= mono_get_object_type ();
2746 offset
= create_interp_local (td
, type
);
2747 arg_offsets
[0] = offset
;
2748 store_local_general (td
, offset
, type
);
2752 while (td
->ip
< end
) {
2753 g_assert (td
->sp
>= td
->stack
);
2754 g_assert (td
->vt_sp
< 0x10000000);
2755 in_offset
= td
->ip
- header
->code
;
2756 td
->in_start
= td
->ip
;
2757 InterpInst
*prev_last_ins
= td
->last_ins
;
2759 if (td
->stack_height
[in_offset
] >= 0) {
2760 g_assert (td
->is_bb_start
[in_offset
]);
2761 if (td
->stack_height
[in_offset
] > 0)
2762 memcpy (td
->stack
, td
->stack_state
[in_offset
], td
->stack_height
[in_offset
] * sizeof(td
->stack
[0]));
2763 td
->sp
= td
->stack
+ td
->stack_height
[in_offset
];
2764 td
->vt_sp
= td
->vt_stack_size
[in_offset
];
2767 if (in_offset
== bb
->end
)
2771 int op_size
= mono_opcode_size (td
->ip
, end
);
2772 g_assert (op_size
> 0); /* The BB formation pass must catch all bad ops */
2774 if (td
->verbose_level
> 1)
2775 g_print ("SKIPPING DEAD OP at %x\n", in_offset
);
2781 if (td
->verbose_level
> 1) {
2782 g_print ("IL_%04lx %s %-10s, sp %ld, %s %-12s vt_sp %u (max %u)\n",
2783 td
->ip
- td
->il_code
,
2784 td
->is_bb_start
[td
->ip
- td
->il_code
] == 3 ? "<>" :
2785 td
->is_bb_start
[td
->ip
- td
->il_code
] == 2 ? "< " :
2786 td
->is_bb_start
[td
->ip
- td
->il_code
] == 1 ? " >" : " ",
2787 mono_opcode_name (*td
->ip
), td
->sp
- td
->stack
,
2788 td
->sp
> td
->stack
? stack_type_string
[td
->sp
[-1].type
] : " ",
2789 (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
)) : "",
2790 td
->vt_sp
, td
->max_vt_sp
);
2793 if (sym_seq_points
&& mono_bitset_test_fast (seq_point_locs
, td
->ip
- header
->code
)) {
2794 InterpBasicBlock
*cbb
= td
->offset_to_bb
[td
->ip
- header
->code
];
2798 * Make methods interruptable at the beginning, and at the targets of
2799 * backward branches.
2801 if (in_offset
== 0 || g_slist_length (cbb
->preds
) > 1)
2802 interp_add_ins (td
, MINT_SDB_INTR_LOC
);
2804 last_seq_point
= interp_add_ins (td
, MINT_SDB_SEQ_POINT
);
2807 if (td
->is_bb_start
[in_offset
]) {
2808 int index
= td
->clause_indexes
[in_offset
];
2810 MonoExceptionClause
*clause
= &header
->clauses
[index
];
2811 if ((clause
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
||
2812 clause
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
) &&
2813 in_offset
== clause
->handler_offset
)
2814 interp_add_ins (td
, MINT_START_ABORT_PROT
);
2821 emitted_funccall_seq_point
= FALSE
;
2825 SIMPLE_OP(td
, MINT_BREAK
);
2831 int arg_n
= *td
->ip
- CEE_LDARG_0
;
2832 if (td
->method
== method
)
2833 load_arg (td
, arg_n
);
2835 load_local_general (td
, arg_offsets
[arg_n
], get_arg_type (signature
, arg_n
));
2843 load_local (td
, *td
->ip
- CEE_LDLOC_0
);
2850 store_local (td
, *td
->ip
- CEE_STLOC_0
);
2854 int arg_n
= ((guint8
*)td
->ip
)[1];
2855 if (td
->method
== method
)
2856 load_arg (td
, arg_n
);
2858 load_local_general (td
, arg_offsets
[arg_n
], get_arg_type (signature
, arg_n
));
2862 case CEE_LDARGA_S
: {
2863 /* NOTE: n includes this */
2864 INLINE_FAILURE
; // probably uncommon
2865 int n
= ((guint8
*) td
->ip
) [1];
2867 get_arg_type_exact (td
, n
, &mt
);
2868 interp_add_ins (td
, mt
== MINT_TYPE_VT
? MINT_LDARGA_VT
: MINT_LDARGA
);
2869 td
->last_ins
->data
[0] = n
;
2870 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
2875 int arg_n
= ((guint8
*)td
->ip
)[1];
2876 if (td
->method
== method
)
2877 store_arg (td
, arg_n
);
2879 store_local_general (td
, arg_offsets
[arg_n
], get_arg_type (signature
, arg_n
));
2884 load_local (td
, ((guint8
*)td
->ip
)[1]);
2888 interp_add_ins (td
, MINT_LDLOCA_S
);
2889 td
->last_ins
->data
[0] = td
->rtm
->local_offsets
[((guint8
*)td
->ip
)[1]];
2890 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
2894 store_local (td
, ((guint8
*)td
->ip
)[1]);
2898 SIMPLE_OP(td
, MINT_LDNULL
);
2899 PUSH_TYPE(td
, STACK_TYPE_O
, NULL
);
2902 SIMPLE_OP(td
, MINT_LDC_I4_M1
);
2903 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
2906 if (!td
->is_bb_start
[td
->ip
+ 1 - td
->il_code
] && td
->ip
[1] == 0xfe && td
->ip
[2] == CEE_CEQ
&&
2907 td
->sp
> td
->stack
&& td
->sp
[-1].type
== STACK_TYPE_I4
) {
2908 SIMPLE_OP(td
, MINT_CEQ0_I4
);
2911 SIMPLE_OP(td
, MINT_LDC_I4_0
);
2912 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
2916 if (!td
->is_bb_start
[td
->ip
+ 1 - td
->il_code
] &&
2917 (td
->ip
[1] == CEE_ADD
|| td
->ip
[1] == CEE_SUB
) && td
->sp
[-1].type
== STACK_TYPE_I4
) {
2918 interp_add_ins (td
, td
->ip
[1] == CEE_ADD
? MINT_ADD1_I4
: MINT_SUB1_I4
);
2921 SIMPLE_OP(td
, MINT_LDC_I4_1
);
2922 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
2932 SIMPLE_OP(td
, (*td
->ip
- CEE_LDC_I4_0
) + MINT_LDC_I4_0
);
2933 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
2936 interp_add_ins (td
, MINT_LDC_I4_S
);
2937 td
->last_ins
->data
[0] = ((gint8
*) td
->ip
) [1];
2939 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
2942 i32
= read32 (td
->ip
+ 1);
2943 interp_add_ins (td
, MINT_LDC_I4
);
2944 WRITE32_INS (td
->last_ins
, 0, &i32
);
2946 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
2949 gint64 val
= read64 (td
->ip
+ 1);
2950 interp_add_ins (td
, MINT_LDC_I8
);
2951 WRITE64_INS (td
->last_ins
, 0, &val
);
2953 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I8
);
2958 readr4 (td
->ip
+ 1, &val
);
2959 interp_add_ins (td
, MINT_LDC_R4
);
2960 WRITE32_INS (td
->last_ins
, 0, &val
);
2962 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_R4
);
2967 readr8 (td
->ip
+ 1, &val
);
2968 interp_add_ins (td
, MINT_LDC_R8
);
2969 WRITE64_INS (td
->last_ins
, 0, &val
);
2971 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_R8
);
2975 int type
= td
->sp
[-1].type
;
2976 MonoClass
*klass
= td
->sp
[-1].klass
;
2977 if (td
->sp
[-1].type
== STACK_TYPE_VT
) {
2978 gint32 size
= mono_class_value_size (klass
, NULL
);
2980 interp_add_ins (td
, MINT_DUP_VT
);
2981 WRITE32_INS (td
->last_ins
, 0, &size
);
2984 SIMPLE_OP(td
, MINT_DUP
);
2985 PUSH_TYPE(td
, type
, klass
);
2990 SIMPLE_OP(td
, MINT_POP
);
2991 td
->last_ins
->data
[0] = 0;
2992 if (td
->sp
[-1].type
== STACK_TYPE_VT
) {
2993 int size
= mono_class_value_size (td
->sp
[-1].klass
, NULL
);
2994 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
2995 interp_add_ins (td
, MINT_VTRESULT
);
2996 td
->last_ins
->data
[0] = 0;
2997 WRITE32_INS (td
->last_ins
, 1, &size
);
3005 if (td
->sp
> td
->stack
)
3006 g_warning ("CEE_JMP: stack must be empty");
3007 token
= read32 (td
->ip
+ 1);
3008 m
= mono_get_method_checked (image
, token
, NULL
, generic_context
, error
);
3009 goto_if_nok (error
, exit
);
3010 interp_add_ins (td
, MINT_JMP
);
3011 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
3012 goto_if_nok (error
, exit
);
3016 case CEE_CALLVIRT
: /* Fall through */
3017 case CEE_CALLI
: /* Fall through */
3019 gboolean need_seq_point
= FALSE
;
3021 if (sym_seq_points
&& !mono_bitset_test_fast (seq_point_locs
, td
->ip
+ 5 - header
->code
))
3022 need_seq_point
= TRUE
;
3024 if (!interp_transform_call (td
, method
, NULL
, domain
, generic_context
, td
->is_bb_start
, constrained_class
, readonly
, error
, TRUE
))
3027 if (need_seq_point
) {
3028 //check is is a nested call and remove the MONO_INST_NONEMPTY_STACK of the last breakpoint, only for non native methods
3029 if (!(method
->flags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)) {
3030 if (emitted_funccall_seq_point
) {
3032 last_seq_point
->flags
|= INTERP_INST_FLAG_SEQ_POINT_NESTED_CALL
;
3035 emitted_funccall_seq_point
= TRUE
;
3037 last_seq_point
= interp_add_ins (td
, MINT_SDB_SEQ_POINT
);
3038 // This seq point is actually associated with the instruction following the call
3039 last_seq_point
->il_offset
= td
->ip
- header
->code
;
3040 last_seq_point
->flags
= INTERP_INST_FLAG_SEQ_POINT_NONEMPTY_STACK
;
3043 constrained_class
= NULL
;
3048 /* Return from inlined method, return value is on top of stack */
3049 if (td
->method
!= method
) {
3055 MonoType
*ult
= mini_type_get_underlying_type (signature
->ret
);
3056 if (ult
->type
!= MONO_TYPE_VOID
) {
3057 CHECK_STACK (td
, 1);
3059 if (mint_type (ult
) == MINT_TYPE_VT
) {
3060 MonoClass
*klass
= mono_class_from_mono_type_internal (ult
);
3061 vt_size
= mono_class_value_size (klass
, NULL
);
3064 if (td
->sp
> td
->stack
) {
3065 mono_error_set_generic_error (error
, "System", "InvalidProgramException", "");
3068 if (td
->vt_sp
!= ALIGN_TO (vt_size
, MINT_VT_ALIGNMENT
))
3069 g_error ("%s: CEE_RET: value type stack: %d vs. %d", mono_method_full_name (td
->method
, TRUE
), td
->vt_sp
, vt_size
);
3071 if (sym_seq_points
) {
3072 last_seq_point
= interp_add_ins (td
, MINT_SDB_SEQ_POINT
);
3073 td
->last_ins
->flags
= INTERP_INST_FLAG_SEQ_POINT_METHOD_EXIT
;
3077 SIMPLE_OP(td
, ult
->type
== MONO_TYPE_VOID
? MINT_RET_VOID
: MINT_RET
);
3079 interp_add_ins (td
, MINT_RET_VT
);
3080 WRITE32_INS (td
->last_ins
, 0, &vt_size
);
3087 handle_branch (td
, MINT_BR_S
, MINT_BR
, 5 + read32 (td
->ip
+ 1));
3092 handle_branch (td
, MINT_BR_S
, MINT_BR
, 2 + (gint8
)td
->ip
[1]);
3097 one_arg_branch (td
, MINT_BRFALSE_I4
, 5 + read32 (td
->ip
+ 1));
3102 one_arg_branch (td
, MINT_BRFALSE_I4
, 2 + (gint8
)td
->ip
[1]);
3107 one_arg_branch (td
, MINT_BRTRUE_I4
, 5 + read32 (td
->ip
+ 1));
3112 one_arg_branch (td
, MINT_BRTRUE_I4
, 2 + (gint8
)td
->ip
[1]);
3117 two_arg_branch (td
, MINT_BEQ_I4
, 5 + read32 (td
->ip
+ 1));
3122 two_arg_branch (td
, MINT_BEQ_I4
, 2 + (gint8
) td
->ip
[1]);
3127 two_arg_branch (td
, MINT_BGE_I4
, 5 + read32 (td
->ip
+ 1));
3132 two_arg_branch (td
, MINT_BGE_I4
, 2 + (gint8
) td
->ip
[1]);
3137 two_arg_branch (td
, MINT_BGT_I4
, 5 + read32 (td
->ip
+ 1));
3142 two_arg_branch (td
, MINT_BGT_I4
, 2 + (gint8
) td
->ip
[1]);
3147 two_arg_branch (td
, MINT_BLT_I4
, 5 + read32 (td
->ip
+ 1));
3152 two_arg_branch (td
, MINT_BLT_I4
, 2 + (gint8
) td
->ip
[1]);
3157 two_arg_branch (td
, MINT_BLE_I4
, 5 + read32 (td
->ip
+ 1));
3162 two_arg_branch (td
, MINT_BLE_I4
, 2 + (gint8
) td
->ip
[1]);
3167 two_arg_branch (td
, MINT_BNE_UN_I4
, 5 + read32 (td
->ip
+ 1));
3172 two_arg_branch (td
, MINT_BNE_UN_I4
, 2 + (gint8
) td
->ip
[1]);
3177 two_arg_branch (td
, MINT_BGE_UN_I4
, 5 + read32 (td
->ip
+ 1));
3182 two_arg_branch (td
, MINT_BGE_UN_I4
, 2 + (gint8
) td
->ip
[1]);
3187 two_arg_branch (td
, MINT_BGT_UN_I4
, 5 + read32 (td
->ip
+ 1));
3192 two_arg_branch (td
, MINT_BGT_UN_I4
, 2 + (gint8
) td
->ip
[1]);
3197 two_arg_branch (td
, MINT_BLE_UN_I4
, 5 + read32 (td
->ip
+ 1));
3202 two_arg_branch (td
, MINT_BLE_UN_I4
, 2 + (gint8
) td
->ip
[1]);
3207 two_arg_branch (td
, MINT_BLT_UN_I4
, 5 + read32 (td
->ip
+ 1));
3212 two_arg_branch (td
, MINT_BLT_UN_I4
, 2 + (gint8
) td
->ip
[1]);
3218 const unsigned char *next_ip
;
3220 n
= read32 (td
->ip
);
3221 interp_add_ins_explicit (td
, MINT_SWITCH
, MINT_SWITCH_LEN (n
));
3222 WRITE32_INS (td
->last_ins
, 0, &n
);
3224 next_ip
= td
->ip
+ n
* 4;
3226 int stack_height
= td
->sp
- td
->stack
;
3227 for (i
= 0; i
< n
; i
++) {
3228 offset
= read32 (td
->ip
);
3229 target
= next_ip
- td
->il_code
+ offset
;
3232 if (stack_height
> 0 && stack_height
!= td
->stack_height
[target
])
3233 g_warning ("SWITCH with back branch and non-empty stack");
3236 td
->stack_height
[target
] = stack_height
;
3237 td
->vt_stack_size
[target
] = td
->vt_sp
;
3238 if (stack_height
> 0)
3239 td
->stack_state
[target
] = (StackInfo
*)g_memdup (td
->stack
, stack_height
* sizeof (td
->stack
[0]));
3241 WRITE32_INS (td
->last_ins
, 2 + i
* 2, &target
);
3247 CHECK_STACK (td
, 1);
3248 SIMPLE_OP (td
, MINT_LDIND_I1_CHECK
);
3249 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3250 BARRIER_IF_VOLATILE (td
);
3253 CHECK_STACK (td
, 1);
3254 SIMPLE_OP (td
, MINT_LDIND_U1_CHECK
);
3255 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3256 BARRIER_IF_VOLATILE (td
);
3259 CHECK_STACK (td
, 1);
3260 SIMPLE_OP (td
, MINT_LDIND_I2_CHECK
);
3261 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3262 BARRIER_IF_VOLATILE (td
);
3265 CHECK_STACK (td
, 1);
3266 SIMPLE_OP (td
, MINT_LDIND_U2_CHECK
);
3267 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3268 BARRIER_IF_VOLATILE (td
);
3271 CHECK_STACK (td
, 1);
3272 SIMPLE_OP (td
, MINT_LDIND_I4_CHECK
);
3273 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3274 BARRIER_IF_VOLATILE (td
);
3277 CHECK_STACK (td
, 1);
3278 SIMPLE_OP (td
, MINT_LDIND_U4_CHECK
);
3279 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3280 BARRIER_IF_VOLATILE (td
);
3283 CHECK_STACK (td
, 1);
3284 SIMPLE_OP (td
, MINT_LDIND_I8_CHECK
);
3285 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
3286 BARRIER_IF_VOLATILE (td
);
3289 CHECK_STACK (td
, 1);
3290 SIMPLE_OP (td
, MINT_LDIND_REF_CHECK
);
3291 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I
);
3292 BARRIER_IF_VOLATILE (td
);
3295 CHECK_STACK (td
, 1);
3296 SIMPLE_OP (td
, MINT_LDIND_R4_CHECK
);
3297 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R4
);
3298 BARRIER_IF_VOLATILE (td
);
3301 CHECK_STACK (td
, 1);
3302 SIMPLE_OP (td
, MINT_LDIND_R8_CHECK
);
3303 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
3304 BARRIER_IF_VOLATILE (td
);
3307 CHECK_STACK (td
, 1);
3308 SIMPLE_OP (td
, MINT_LDIND_REF_CHECK
);
3309 BARRIER_IF_VOLATILE (td
);
3310 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_O
);
3313 CHECK_STACK (td
, 2);
3314 BARRIER_IF_VOLATILE (td
);
3315 SIMPLE_OP (td
, MINT_STIND_REF
);
3319 CHECK_STACK (td
, 2);
3320 BARRIER_IF_VOLATILE (td
);
3321 SIMPLE_OP (td
, MINT_STIND_I1
);
3325 CHECK_STACK (td
, 2);
3326 BARRIER_IF_VOLATILE (td
);
3327 SIMPLE_OP (td
, MINT_STIND_I2
);
3331 CHECK_STACK (td
, 2);
3332 BARRIER_IF_VOLATILE (td
);
3333 SIMPLE_OP (td
, MINT_STIND_I4
);
3337 CHECK_STACK (td
, 2);
3338 BARRIER_IF_VOLATILE (td
);
3339 SIMPLE_OP (td
, MINT_STIND_I
);
3343 CHECK_STACK (td
, 2);
3344 BARRIER_IF_VOLATILE (td
);
3345 SIMPLE_OP (td
, MINT_STIND_I8
);
3349 CHECK_STACK (td
, 2);
3350 BARRIER_IF_VOLATILE (td
);
3351 SIMPLE_OP (td
, MINT_STIND_R4
);
3355 CHECK_STACK (td
, 2);
3356 BARRIER_IF_VOLATILE (td
);
3357 SIMPLE_OP (td
, MINT_STIND_R8
);
3361 binary_arith_op(td
, MINT_ADD_I4
);
3365 binary_arith_op(td
, MINT_SUB_I4
);
3369 binary_arith_op(td
, MINT_MUL_I4
);
3373 binary_arith_op(td
, MINT_DIV_I4
);
3377 binary_arith_op(td
, MINT_DIV_UN_I4
);
3381 binary_arith_op (td
, MINT_REM_I4
);
3385 binary_arith_op (td
, MINT_REM_UN_I4
);
3389 binary_arith_op (td
, MINT_AND_I4
);
3393 binary_arith_op (td
, MINT_OR_I4
);
3397 binary_arith_op (td
, MINT_XOR_I4
);
3401 shift_op (td
, MINT_SHL_I4
);
3405 shift_op (td
, MINT_SHR_I4
);
3409 shift_op (td
, MINT_SHR_UN_I4
);
3413 unary_arith_op (td
, MINT_NEG_I4
);
3417 unary_arith_op (td
, MINT_NOT_I4
);
3421 CHECK_STACK (td
, 1);
3422 switch (td
->sp
[-1].type
) {
3424 interp_add_ins (td
, MINT_CONV_U1_R4
);
3427 interp_add_ins (td
, MINT_CONV_U1_R8
);
3430 interp_add_ins (td
, MINT_CONV_U1_I4
);
3433 interp_add_ins (td
, MINT_CONV_U1_I8
);
3436 g_assert_not_reached ();
3439 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3442 CHECK_STACK (td
, 1);
3443 switch (td
->sp
[-1].type
) {
3445 interp_add_ins (td
, MINT_CONV_I1_R4
);
3448 interp_add_ins (td
, MINT_CONV_I1_R8
);
3451 interp_add_ins (td
, MINT_CONV_I1_I4
);
3454 interp_add_ins (td
, MINT_CONV_I1_I8
);
3457 g_assert_not_reached ();
3460 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3463 CHECK_STACK (td
, 1);
3464 switch (td
->sp
[-1].type
) {
3466 interp_add_ins (td
, MINT_CONV_U2_R4
);
3469 interp_add_ins (td
, MINT_CONV_U2_R8
);
3472 interp_add_ins (td
, MINT_CONV_U2_I4
);
3475 interp_add_ins (td
, MINT_CONV_U2_I8
);
3478 g_assert_not_reached ();
3481 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3484 CHECK_STACK (td
, 1);
3485 switch (td
->sp
[-1].type
) {
3487 interp_add_ins (td
, MINT_CONV_I2_R4
);
3490 interp_add_ins (td
, MINT_CONV_I2_R8
);
3493 interp_add_ins (td
, MINT_CONV_I2_I4
);
3496 interp_add_ins (td
, MINT_CONV_I2_I8
);
3499 g_assert_not_reached ();
3502 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3505 CHECK_STACK (td
, 1);
3506 switch (td
->sp
[-1].type
) {
3508 #if SIZEOF_VOID_P == 4
3509 interp_add_ins (td
, MINT_CONV_U4_R8
);
3511 interp_add_ins (td
, MINT_CONV_U8_R8
);
3515 #if SIZEOF_VOID_P == 8
3516 interp_add_ins (td
, MINT_CONV_U8_I4
);
3520 #if SIZEOF_VOID_P == 4
3521 interp_add_ins (td
, MINT_CONV_U4_I8
);
3528 g_assert_not_reached ();
3531 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I
);
3534 CHECK_STACK (td
, 1);
3535 switch (td
->sp
[-1].type
) {
3537 #if SIZEOF_VOID_P == 8
3538 interp_add_ins (td
, MINT_CONV_I8_R8
);
3540 interp_add_ins (td
, MINT_CONV_I4_R8
);
3544 #if SIZEOF_VOID_P == 8
3545 interp_add_ins (td
, MINT_CONV_I8_I4
);
3553 #if SIZEOF_VOID_P == 4
3554 interp_add_ins (td
, MINT_CONV_I4_I8
);
3558 g_assert_not_reached ();
3561 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I
);
3564 CHECK_STACK (td
, 1);
3565 switch (td
->sp
[-1].type
) {
3567 interp_add_ins (td
, MINT_CONV_U4_R4
);
3570 interp_add_ins (td
, MINT_CONV_U4_R8
);
3575 interp_add_ins (td
, MINT_CONV_U4_I8
);
3578 #if SIZEOF_VOID_P == 8
3579 interp_add_ins (td
, MINT_CONV_U4_I8
);
3583 g_assert_not_reached ();
3586 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3589 CHECK_STACK (td
, 1);
3590 switch (td
->sp
[-1].type
) {
3592 interp_add_ins (td
, MINT_CONV_I4_R4
);
3595 interp_add_ins (td
, MINT_CONV_I4_R8
);
3600 interp_add_ins (td
, MINT_CONV_I4_I8
);
3603 #if SIZEOF_VOID_P == 8
3604 interp_add_ins (td
, MINT_CONV_I4_I8
);
3608 g_assert_not_reached ();
3611 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3614 CHECK_STACK (td
, 1);
3615 switch (td
->sp
[-1].type
) {
3617 interp_add_ins (td
, MINT_CONV_I8_R4
);
3620 interp_add_ins (td
, MINT_CONV_I8_R8
);
3623 interp_add_ins (td
, MINT_CONV_I8_I4
);
3628 #if SIZEOF_VOID_P == 4
3629 interp_add_ins (td
, MINT_CONV_I8_I4
);
3633 g_assert_not_reached ();
3636 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
3639 CHECK_STACK (td
, 1);
3640 switch (td
->sp
[-1].type
) {
3642 interp_add_ins (td
, MINT_CONV_R4_R8
);
3645 interp_add_ins (td
, MINT_CONV_R4_I8
);
3648 interp_add_ins (td
, MINT_CONV_R4_I4
);
3654 g_assert_not_reached ();
3657 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R4
);
3660 CHECK_STACK (td
, 1);
3661 switch (td
->sp
[-1].type
) {
3663 interp_add_ins (td
, MINT_CONV_R8_I4
);
3666 interp_add_ins (td
, MINT_CONV_R8_I8
);
3669 interp_add_ins (td
, MINT_CONV_R8_R4
);
3674 g_assert_not_reached ();
3677 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
3680 CHECK_STACK (td
, 1);
3681 switch (td
->sp
[-1].type
) {
3683 interp_add_ins (td
, MINT_CONV_U8_I4
);
3688 interp_add_ins (td
, MINT_CONV_U8_R4
);
3691 interp_add_ins (td
, MINT_CONV_U8_R8
);
3694 #if SIZEOF_VOID_P == 4
3695 interp_add_ins (td
, MINT_CONV_U8_I4
);
3699 g_assert_not_reached ();
3702 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
3705 CHECK_STACK (td
, 2);
3707 token
= read32 (td
->ip
+ 1);
3708 klass
= mono_class_get_and_inflate_typespec_checked (image
, token
, generic_context
, error
);
3709 goto_if_nok (error
, exit
);
3711 if (m_class_is_valuetype (klass
)) {
3712 int mt
= mint_type (m_class_get_byval_arg (klass
));
3713 interp_add_ins (td
, (mt
== MINT_TYPE_VT
) ? MINT_CPOBJ_VT
: MINT_CPOBJ
);
3714 td
->last_ins
->data
[0] = get_data_item_index(td
, klass
);
3716 interp_add_ins (td
, MINT_LDIND_REF
);
3717 interp_add_ins (td
, MINT_STIND_REF
);
3724 CHECK_STACK (td
, 1);
3726 token
= read32 (td
->ip
+ 1);
3728 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
3729 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
3731 klass
= mono_class_get_and_inflate_typespec_checked (image
, token
, generic_context
, error
);
3732 goto_if_nok (error
, exit
);
3735 interp_emit_ldobj (td
, klass
);
3738 BARRIER_IF_VOLATILE (td
);
3742 token
= mono_metadata_token_index (read32 (td
->ip
+ 1));
3744 if (method
->wrapper_type
== MONO_WRAPPER_NONE
) {
3745 MonoString
*s
= mono_ldstr_checked (domain
, image
, token
, error
);
3746 goto_if_nok (error
, exit
);
3747 /* GC won't scan code stream, but reference is held by metadata
3748 * machinery so we are good here */
3749 interp_add_ins (td
, MINT_LDSTR
);
3750 td
->last_ins
->data
[0] = get_data_item_index (td
, s
);
3752 /* defer allocation to execution-time */
3753 interp_add_ins (td
, MINT_LDSTR_TOKEN
);
3754 td
->last_ins
->data
[0] = get_data_item_index (td
, GUINT_TO_POINTER (token
));
3756 PUSH_TYPE(td
, STACK_TYPE_O
, mono_defaults
.string_class
);
3761 MonoMethodSignature
*csignature
;
3762 guint32 vt_stack_used
= 0;
3763 guint32 vt_res_size
= 0;
3766 token
= read32 (td
->ip
);
3769 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
3770 m
= (MonoMethod
*)mono_method_get_wrapper_data (method
, token
);
3772 m
= mono_get_method_checked (image
, token
, NULL
, generic_context
, error
);
3773 goto_if_nok (error
, exit
);
3776 csignature
= mono_method_signature_internal (m
);
3779 if (!mono_class_init_internal (klass
)) {
3780 mono_error_set_for_class_failure (error
, klass
);
3781 goto_if_nok (error
, exit
);
3784 if (mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_ABSTRACT
) {
3785 char* full_name
= mono_type_get_full_name (klass
);
3786 mono_error_set_member_access (error
, "Cannot create an abstract class: %s", full_name
);
3788 goto_if_nok (error
, exit
);
3791 td
->sp
-= csignature
->param_count
;
3792 if (mono_class_is_magic_int (klass
) || mono_class_is_magic_float (klass
)) {
3793 #if SIZEOF_VOID_P == 8
3794 if (mono_class_is_magic_int (klass
) && td
->sp
[0].type
== STACK_TYPE_I4
)
3795 interp_add_ins (td
, MINT_CONV_I8_I4
);
3796 else if (mono_class_is_magic_float (klass
) && td
->sp
[0].type
== STACK_TYPE_R4
)
3797 interp_add_ins (td
, MINT_CONV_R8_R4
);
3799 interp_add_ins (td
, MINT_NEWOBJ_MAGIC
);
3800 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
3801 goto_if_nok (error
, exit
);
3803 PUSH_TYPE (td
, stack_type
[mint_type (m_class_get_byval_arg (klass
))], klass
);
3805 if (m_class_get_parent (klass
) == mono_defaults
.array_class
) {
3806 interp_add_ins (td
, MINT_NEWOBJ_ARRAY
);
3807 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
3808 td
->last_ins
->data
[1] = csignature
->param_count
;
3809 } else if (m_class_get_image (klass
) == mono_defaults
.corlib
&&
3810 !strcmp (m_class_get_name (m
->klass
), "ByReference`1") &&
3811 !strcmp (m
->name
, ".ctor")) {
3812 /* public ByReference(ref T value) */
3813 g_assert (csignature
->hasthis
&& csignature
->param_count
== 1);
3814 interp_add_ins (td
, MINT_INTRINS_BYREFERENCE_CTOR
);
3815 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
3816 } else if (klass
!= mono_defaults
.string_class
&&
3817 !mono_class_is_marshalbyref (klass
) &&
3818 !mono_class_has_finalizer (klass
) &&
3819 !m_class_has_weak_fields (klass
)) {
3820 if (!m_class_is_valuetype (klass
))
3821 interp_add_ins (td
, MINT_NEWOBJ_FAST
);
3822 else if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
)
3823 interp_add_ins (td
, MINT_NEWOBJ_VTST_FAST
);
3825 interp_add_ins (td
, MINT_NEWOBJ_VT_FAST
);
3827 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
3828 td
->last_ins
->data
[1] = csignature
->param_count
;
3830 if (!m_class_is_valuetype (klass
)) {
3831 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, klass
, error
);
3832 goto_if_nok (error
, exit
);
3833 td
->last_ins
->data
[2] = get_data_item_index (td
, vtable
);
3834 } else if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
) {
3835 td
->last_ins
->data
[2] = mono_class_value_size (klass
, NULL
);
3838 interp_add_ins (td
, MINT_NEWOBJ
);
3839 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
3841 goto_if_nok (error
, exit
);
3843 if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
) {
3844 vt_res_size
= mono_class_value_size (klass
, NULL
);
3845 PUSH_VT (td
, vt_res_size
);
3847 for (i
= 0; i
< csignature
->param_count
; ++i
) {
3848 int mt
= mint_type(csignature
->params
[i
]);
3849 if (mt
== MINT_TYPE_VT
) {
3850 MonoClass
*k
= mono_class_from_mono_type_internal (csignature
->params
[i
]);
3851 gint32 size
= mono_class_value_size (k
, NULL
);
3852 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
3853 vt_stack_used
+= size
;
3856 if (vt_stack_used
!= 0 || vt_res_size
!= 0) {
3857 interp_add_ins (td
, MINT_VTRESULT
);
3858 td
->last_ins
->data
[0] = vt_res_size
;
3859 WRITE32_INS (td
->last_ins
, 1, &vt_stack_used
);
3860 td
->vt_sp
-= vt_stack_used
;
3862 PUSH_TYPE (td
, stack_type
[mint_type (m_class_get_byval_arg (klass
))], klass
);
3868 gboolean isinst_instr
= *td
->ip
== CEE_ISINST
;
3869 CHECK_STACK (td
, 1);
3870 token
= read32 (td
->ip
+ 1);
3871 klass
= mini_get_class (method
, token
, generic_context
);
3872 CHECK_TYPELOAD (klass
);
3873 interp_handle_isinst (td
, klass
, isinst_instr
);
3875 td
->sp
[-1].klass
= klass
;
3879 switch (td
->sp
[-1].type
) {
3883 interp_add_ins (td
, MINT_CONV_R_UN_I8
);
3886 interp_add_ins (td
, MINT_CONV_R_UN_I4
);
3889 g_assert_not_reached ();
3891 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
3895 CHECK_STACK (td
, 1);
3896 token
= read32 (td
->ip
+ 1);
3898 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
3899 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
3901 klass
= mono_class_get_and_inflate_typespec_checked (image
, token
, generic_context
, error
);
3902 goto_if_nok (error
, exit
);
3905 if (mono_class_is_nullable (klass
)) {
3906 MonoMethod
*target_method
;
3907 if (m_class_is_enumtype (mono_class_get_nullable_param_internal (klass
)))
3908 target_method
= mono_class_get_method_from_name_checked (klass
, "UnboxExact", 1, 0, error
);
3910 target_method
= mono_class_get_method_from_name_checked (klass
, "Unbox", 1, 0, error
);
3911 goto_if_nok (error
, exit
);
3912 /* td->ip is incremented by interp_transform_call */
3913 if (!interp_transform_call (td
, method
, target_method
, domain
, generic_context
, td
->is_bb_start
, NULL
, FALSE
, error
, FALSE
))
3916 * CEE_UNBOX needs to push address of vtype while Nullable.Unbox returns the value type
3917 * We create a local variable in the frame so that we can fetch its address.
3919 int local_offset
= create_interp_local (td
, m_class_get_byval_arg (klass
));
3920 store_local_general (td
, local_offset
, m_class_get_byval_arg (klass
));
3921 interp_add_ins (td
, MINT_LDLOCA_S
);
3922 td
->last_ins
->data
[0] = local_offset
;
3923 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_MP
);
3925 interp_add_ins (td
, MINT_UNBOX
);
3926 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
3927 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_MP
);
3932 CHECK_STACK (td
, 1);
3933 token
= read32 (td
->ip
+ 1);
3935 klass
= mini_get_class (method
, token
, generic_context
);
3936 CHECK_TYPELOAD (klass
);
3938 if (mini_type_is_reference (m_class_get_byval_arg (klass
))) {
3939 int mt
= mint_type (m_class_get_byval_arg (klass
));
3940 interp_handle_isinst (td
, klass
, FALSE
);
3941 SET_TYPE (td
->sp
- 1, stack_type
[mt
], klass
);
3942 } else if (mono_class_is_nullable (klass
)) {
3943 MonoMethod
*target_method
;
3944 if (m_class_is_enumtype (mono_class_get_nullable_param_internal (klass
)))
3945 target_method
= mono_class_get_method_from_name_checked (klass
, "UnboxExact", 1, 0, error
);
3947 target_method
= mono_class_get_method_from_name_checked (klass
, "Unbox", 1, 0, error
);
3948 goto_if_nok (error
, exit
);
3949 /* td->ip is incremented by interp_transform_call */
3950 if (!interp_transform_call (td
, method
, target_method
, domain
, generic_context
, td
->is_bb_start
, NULL
, FALSE
, error
, FALSE
))
3953 interp_add_ins (td
, MINT_UNBOX
);
3954 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
3956 interp_emit_ldobj (td
, klass
);
3964 CHECK_STACK (td
, 1);
3965 SIMPLE_OP (td
, MINT_THROW
);
3969 CHECK_STACK (td
, 1);
3970 token
= read32 (td
->ip
+ 1);
3971 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
3972 goto_if_nok (error
, exit
);
3973 MonoType
*ftype
= mono_field_get_type_internal (field
);
3974 gboolean is_static
= !!(ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
);
3975 mono_class_init_internal (klass
);
3976 #ifndef DISABLE_REMOTING
3977 if (m_class_get_marshalbyref (klass
) || mono_class_is_contextbound (klass
) || klass
== mono_defaults
.marshalbyrefobject_class
) {
3978 g_assert (!is_static
);
3979 int offset
= m_class_is_valuetype (klass
) ? field
->offset
- MONO_ABI_SIZEOF (MonoObject
) : field
->offset
;
3981 interp_add_ins (td
, MINT_MONO_LDPTR
);
3982 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
3983 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
3984 interp_add_ins (td
, MINT_MONO_LDPTR
);
3985 td
->last_ins
->data
[0] = get_data_item_index (td
, field
);
3986 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
3987 interp_add_ins (td
, MINT_LDC_I4
);
3988 WRITE32_INS (td
->last_ins
, 0, &offset
);
3989 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I4
);
3990 #if SIZEOF_VOID_P == 8
3991 interp_add_ins (td
, MINT_CONV_I8_I4
);
3994 MonoMethod
*wrapper
= mono_marshal_get_ldflda_wrapper (field
->type
);
3995 /* td->ip is incremented by interp_transform_call */
3996 if (!interp_transform_call (td
, method
, wrapper
, domain
, generic_context
, td
->is_bb_start
, NULL
, FALSE
, error
, FALSE
))
4002 interp_add_ins (td
, MINT_POP
);
4003 td
->last_ins
->data
[0] = 0;
4004 interp_add_ins (td
, MINT_LDSFLDA
);
4005 td
->last_ins
->data
[0] = get_data_item_index (td
, field
);
4007 if ((td
->sp
- 1)->type
== STACK_TYPE_O
) {
4008 interp_add_ins (td
, MINT_LDFLDA
);
4010 g_assert ((td
->sp
-1)->type
== STACK_TYPE_MP
);
4011 interp_add_ins (td
, MINT_LDFLDA_UNSAFE
);
4013 td
->last_ins
->data
[0] = m_class_is_valuetype (klass
) ? field
->offset
- MONO_ABI_SIZEOF (MonoObject
) : field
->offset
;
4017 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
4021 CHECK_STACK (td
, 1);
4022 token
= read32 (td
->ip
+ 1);
4023 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
4024 goto_if_nok (error
, exit
);
4025 MonoType
*ftype
= mono_field_get_type_internal (field
);
4026 gboolean is_static
= !!(ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
);
4027 mono_class_init_internal (klass
);
4029 MonoClass
*field_klass
= mono_class_from_mono_type_internal (ftype
);
4030 mt
= mint_type (m_class_get_byval_arg (field_klass
));
4031 #ifndef DISABLE_REMOTING
4032 if (m_class_get_marshalbyref (klass
)) {
4033 g_assert (!is_static
);
4034 interp_add_ins (td
, mt
== MINT_TYPE_VT
? MINT_LDRMFLD_VT
: MINT_LDRMFLD
);
4035 td
->last_ins
->data
[0] = get_data_item_index (td
, field
);
4040 interp_add_ins (td
, MINT_POP
);
4041 td
->last_ins
->data
[0] = 0;
4042 interp_emit_ldsfld (td
, field
, field_klass
, mt
, error
);
4043 goto_if_nok (error
, exit
);
4045 int opcode
= MINT_LDFLD_I1
+ mt
- MINT_TYPE_I1
;
4046 #ifdef NO_UNALIGNED_ACCESS
4047 if ((mt
== MINT_TYPE_I8
|| mt
== MINT_TYPE_R8
) && field
->offset
% SIZEOF_VOID_P
!= 0)
4048 opcode
= get_unaligned_opcode (opcode
);
4050 interp_add_ins (td
, opcode
);
4051 td
->last_ins
->data
[0] = m_class_is_valuetype (klass
) ? field
->offset
- MONO_ABI_SIZEOF (MonoObject
) : field
->offset
;
4052 if (mt
== MINT_TYPE_VT
)
4053 td
->last_ins
->data
[1] = get_data_item_index (td
, field
);
4056 if (mt
== MINT_TYPE_VT
) {
4057 int size
= mono_class_value_size (field_klass
, NULL
);
4060 if (td
->sp
[-1].type
== STACK_TYPE_VT
) {
4061 int size
= mono_class_value_size (klass
, NULL
);
4062 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4063 int field_vt_size
= 0;
4064 if (mt
== MINT_TYPE_VT
) {
4066 * Pop the loaded field from the vtstack (it will still be present
4067 * at the same vtstack address) and we will load it in place of the
4068 * containing valuetype with the second MINT_VTRESULT.
4070 field_vt_size
= mono_class_value_size (field_klass
, NULL
);
4071 field_vt_size
= ALIGN_TO (field_vt_size
, MINT_VT_ALIGNMENT
);
4072 interp_add_ins (td
, MINT_VTRESULT
);
4073 td
->last_ins
->data
[0] = 0;
4074 WRITE32_INS (td
->last_ins
, 1, &field_vt_size
);
4077 interp_add_ins (td
, MINT_VTRESULT
);
4078 td
->last_ins
->data
[0] = field_vt_size
;
4079 WRITE32_INS (td
->last_ins
, 1, &size
);
4082 SET_TYPE (td
->sp
- 1, stack_type
[mt
], field_klass
);
4083 BARRIER_IF_VOLATILE (td
);
4087 CHECK_STACK (td
, 2);
4088 token
= read32 (td
->ip
+ 1);
4089 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
4090 goto_if_nok (error
, exit
);
4091 MonoType
*ftype
= mono_field_get_type_internal (field
);
4092 gboolean is_static
= !!(ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
);
4093 MonoClass
*field_klass
= mono_class_from_mono_type_internal (ftype
);
4094 mono_class_init_internal (klass
);
4095 mt
= mint_type (ftype
);
4097 BARRIER_IF_VOLATILE (td
);
4099 #ifndef DISABLE_REMOTING
4100 if (m_class_get_marshalbyref (klass
)) {
4101 g_assert (!is_static
);
4102 interp_add_ins (td
, mt
== MINT_TYPE_VT
? MINT_STRMFLD_VT
: MINT_STRMFLD
);
4103 td
->last_ins
->data
[0] = get_data_item_index (td
, field
);
4108 interp_add_ins (td
, MINT_POP
);
4109 td
->last_ins
->data
[0] = 1;
4110 interp_emit_stsfld (td
, field
, field_klass
, mt
, error
);
4111 goto_if_nok (error
, exit
);
4113 /* the vtable of the field might not be initialized at this point */
4114 mono_class_vtable_checked (domain
, field_klass
, error
);
4115 goto_if_nok (error
, exit
);
4117 int opcode
= MINT_STFLD_I1
+ mt
- MINT_TYPE_I1
;
4118 #ifdef NO_UNALIGNED_ACCESS
4119 if ((mt
== MINT_TYPE_I8
|| mt
== MINT_TYPE_R8
) && field
->offset
% SIZEOF_VOID_P
!= 0)
4120 opcode
= get_unaligned_opcode (opcode
);
4122 interp_add_ins (td
, opcode
);
4123 td
->last_ins
->data
[0] = m_class_is_valuetype (klass
) ? field
->offset
- MONO_ABI_SIZEOF (MonoObject
) : field
->offset
;
4124 if (mt
== MINT_TYPE_VT
) {
4125 td
->last_ins
->data
[1] = get_data_item_index (td
, field
);
4127 /* the vtable of the field might not be initialized at this point */
4128 mono_class_vtable_checked (domain
, field_klass
, error
);
4129 goto_if_nok (error
, exit
);
4133 if (mt
== MINT_TYPE_VT
) {
4134 int size
= mono_class_value_size (field_klass
, NULL
);
4142 token
= read32 (td
->ip
+ 1);
4143 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
4144 goto_if_nok (error
, exit
);
4145 mono_field_get_type_internal (field
);
4146 interp_add_ins (td
, MINT_LDSFLDA
);
4147 td
->last_ins
->data
[0] = get_data_item_index (td
, field
);
4149 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
4153 token
= read32 (td
->ip
+ 1);
4154 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
4155 goto_if_nok (error
, exit
);
4156 MonoType
*ftype
= mono_field_get_type_internal (field
);
4157 mt
= mint_type (ftype
);
4158 klass
= mono_class_from_mono_type_internal (ftype
);
4160 interp_emit_ldsfld (td
, field
, klass
, mt
, error
);
4161 goto_if_nok (error
, exit
);
4163 if (mt
== MINT_TYPE_VT
) {
4164 int size
= mono_class_value_size (klass
, NULL
);
4168 PUSH_TYPE(td
, stack_type
[mt
], klass
);
4172 CHECK_STACK (td
, 1);
4173 token
= read32 (td
->ip
+ 1);
4174 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
4175 goto_if_nok (error
, exit
);
4176 MonoType
*ftype
= mono_field_get_type_internal (field
);
4177 mt
= mint_type (ftype
);
4179 /* the vtable of the field might not be initialized at this point */
4180 MonoClass
*fld_klass
= mono_class_from_mono_type_internal (ftype
);
4181 mono_class_vtable_checked (domain
, fld_klass
, error
);
4182 goto_if_nok (error
, exit
);
4184 interp_emit_stsfld (td
, field
, fld_klass
, mt
, error
);
4185 goto_if_nok (error
, exit
);
4187 if (mt
== MINT_TYPE_VT
) {
4188 int size
= mono_class_value_size (fld_klass
, NULL
);
4196 token
= read32 (td
->ip
+ 1);
4198 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4199 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
4201 klass
= mini_get_class (method
, token
, generic_context
);
4202 CHECK_TYPELOAD (klass
);
4204 BARRIER_IF_VOLATILE (td
);
4206 interp_emit_stobj (td
, klass
);
4211 case CEE_CONV_OVF_I_UN
:
4212 case CEE_CONV_OVF_U_UN
:
4213 CHECK_STACK (td
, 1);
4214 switch (td
->sp
[-1].type
) {
4216 #if SIZEOF_VOID_P == 8
4217 interp_add_ins (td
, MINT_CONV_OVF_I8_UN_R8
);
4219 interp_add_ins (td
, MINT_CONV_OVF_I4_UN_R8
);
4223 #if SIZEOF_VOID_P == 4
4224 interp_add_ins (td
, MINT_CONV_OVF_I4_UN_I8
);
4228 #if SIZEOF_VOID_P == 8
4229 interp_add_ins (td
, MINT_CONV_I8_U4
);
4230 #elif SIZEOF_VOID_P == 4
4231 if (*td
->ip
== CEE_CONV_OVF_I_UN
)
4232 interp_add_ins (td
, MINT_CONV_OVF_I4_U4
);
4236 g_assert_not_reached ();
4239 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
4242 case CEE_CONV_OVF_I8_UN
:
4243 case CEE_CONV_OVF_U8_UN
:
4244 CHECK_STACK (td
, 1);
4245 switch (td
->sp
[-1].type
) {
4247 interp_add_ins (td
, MINT_CONV_OVF_I8_UN_R8
);
4250 if (*td
->ip
== CEE_CONV_OVF_I8_UN
)
4251 interp_add_ins (td
, MINT_CONV_OVF_I8_U8
);
4254 interp_add_ins (td
, MINT_CONV_I8_U4
);
4257 g_assert_not_reached ();
4260 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
4265 CHECK_STACK (td
, 1);
4266 token
= read32 (td
->ip
+ 1);
4267 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4268 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
4270 klass
= mini_get_class (method
, token
, generic_context
);
4271 CHECK_TYPELOAD (klass
);
4273 if (mono_class_is_nullable (klass
)) {
4274 MonoMethod
*target_method
= mono_class_get_method_from_name_checked (klass
, "Box", 1, 0, error
);
4275 goto_if_nok (error
, exit
);
4276 /* td->ip is incremented by interp_transform_call */
4277 if (!interp_transform_call (td
, method
, target_method
, domain
, generic_context
, td
->is_bb_start
, NULL
, FALSE
, error
, FALSE
))
4279 } else if (!m_class_is_valuetype (klass
)) {
4280 /* already boxed, do nothing. */
4283 if (G_UNLIKELY (m_class_is_byreflike (klass
))) {
4284 mono_error_set_bad_image (error
, image
, "Cannot box IsByRefLike type '%s.%s'", m_class_get_name_space (klass
), m_class_get_name (klass
));
4287 if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
&& !m_class_is_enumtype (klass
)) {
4288 size
= mono_class_value_size (klass
, NULL
);
4289 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4291 } else if (td
->sp
[-1].type
== STACK_TYPE_R8
&& m_class_get_byval_arg (klass
)->type
== MONO_TYPE_R4
) {
4292 interp_add_ins (td
, MINT_CONV_R4_R8
);
4294 if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
)
4295 interp_add_ins (td
, MINT_BOX_VT
);
4297 interp_add_ins (td
, MINT_BOX
);
4298 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
4299 td
->last_ins
->data
[1] = 0;
4300 SET_TYPE(td
->sp
- 1, STACK_TYPE_O
, klass
);
4307 CHECK_STACK (td
, 1);
4308 token
= read32 (td
->ip
+ 1);
4310 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4311 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
4313 klass
= mini_get_class (method
, token
, generic_context
);
4314 CHECK_TYPELOAD (klass
);
4316 unsigned char lentype
= (td
->sp
- 1)->type
;
4317 if (lentype
== STACK_TYPE_I8
) {
4318 /* mimic mini behaviour */
4319 interp_add_ins (td
, MINT_CONV_OVF_U4_I8
);
4321 g_assert (lentype
== STACK_TYPE_I4
);
4322 interp_add_ins (td
, MINT_CONV_OVF_U4_I4
);
4324 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I4
);
4325 interp_add_ins (td
, MINT_NEWARR
);
4326 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
4327 SET_TYPE (td
->sp
- 1, STACK_TYPE_O
, klass
);
4332 CHECK_STACK (td
, 1);
4333 SIMPLE_OP (td
, MINT_LDLEN
);
4334 #ifdef MONO_BIG_ARRAYS
4335 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I8
);
4337 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I4
);
4341 CHECK_STACK (td
, 2);
4343 token
= read32 (td
->ip
+ 1);
4345 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4346 klass
= (MonoClass
*) mono_method_get_wrapper_data (method
, token
);
4348 klass
= mini_get_class (method
, token
, generic_context
);
4350 CHECK_TYPELOAD (klass
);
4352 if (!m_class_is_valuetype (klass
) && method
->wrapper_type
== MONO_WRAPPER_NONE
&& !readonly
) {
4354 * Check the class for failures before the type check, which can
4355 * throw other exceptions.
4357 mono_class_setup_vtable (klass
);
4358 CHECK_TYPELOAD (klass
);
4359 interp_add_ins (td
, MINT_LDELEMA_TC
);
4361 interp_add_ins (td
, MINT_LDELEMA
);
4363 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
4364 /* according to spec, ldelema bytecode is only used for 1-dim arrays */
4365 td
->last_ins
->data
[1] = 2;
4370 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
4373 CHECK_STACK (td
, 2);
4375 SIMPLE_OP (td
, MINT_LDELEM_I1
);
4377 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4380 CHECK_STACK (td
, 2);
4382 SIMPLE_OP (td
, MINT_LDELEM_U1
);
4384 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4387 CHECK_STACK (td
, 2);
4389 SIMPLE_OP (td
, MINT_LDELEM_I2
);
4391 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4394 CHECK_STACK (td
, 2);
4396 SIMPLE_OP (td
, MINT_LDELEM_U2
);
4398 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4401 CHECK_STACK (td
, 2);
4403 SIMPLE_OP (td
, MINT_LDELEM_I4
);
4405 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4408 CHECK_STACK (td
, 2);
4410 SIMPLE_OP (td
, MINT_LDELEM_U4
);
4412 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4415 CHECK_STACK (td
, 2);
4417 SIMPLE_OP (td
, MINT_LDELEM_I8
);
4419 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
4422 CHECK_STACK (td
, 2);
4424 SIMPLE_OP (td
, MINT_LDELEM_I
);
4426 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I
);
4429 CHECK_STACK (td
, 2);
4431 SIMPLE_OP (td
, MINT_LDELEM_R4
);
4433 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R4
);
4436 CHECK_STACK (td
, 2);
4438 SIMPLE_OP (td
, MINT_LDELEM_R8
);
4440 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
4442 case CEE_LDELEM_REF
:
4443 CHECK_STACK (td
, 2);
4445 SIMPLE_OP (td
, MINT_LDELEM_REF
);
4447 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_O
);
4450 CHECK_STACK (td
, 2);
4451 token
= read32 (td
->ip
+ 1);
4452 klass
= mini_get_class (method
, token
, generic_context
);
4453 CHECK_TYPELOAD (klass
);
4454 switch (mint_type (m_class_get_byval_arg (klass
))) {
4457 SIMPLE_OP (td
, MINT_LDELEM_I1
);
4459 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4463 SIMPLE_OP (td
, MINT_LDELEM_U1
);
4465 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4469 SIMPLE_OP (td
, MINT_LDELEM_U2
);
4471 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4475 SIMPLE_OP (td
, MINT_LDELEM_I2
);
4477 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4481 SIMPLE_OP (td
, MINT_LDELEM_I4
);
4483 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4487 SIMPLE_OP (td
, MINT_LDELEM_I8
);
4489 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
4493 SIMPLE_OP (td
, MINT_LDELEM_R4
);
4495 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R4
);
4499 SIMPLE_OP (td
, MINT_LDELEM_R8
);
4501 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
4505 SIMPLE_OP (td
, MINT_LDELEM_REF
);
4507 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_O
);
4509 case MINT_TYPE_VT
: {
4510 int size
= mono_class_value_size (klass
, NULL
);
4512 SIMPLE_OP (td
, MINT_LDELEM_VT
);
4513 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
4514 WRITE32_INS (td
->last_ins
, 1, &size
);
4516 SET_TYPE (td
->sp
- 1, STACK_TYPE_VT
, klass
);
4521 GString
*res
= g_string_new ("");
4522 mono_type_get_desc (res
, m_class_get_byval_arg (klass
), TRUE
);
4523 g_print ("LDELEM: %s -> %d (%s)\n", m_class_get_name (klass
), mint_type (m_class_get_byval_arg (klass
)), res
->str
);
4524 g_string_free (res
, TRUE
);
4532 CHECK_STACK (td
, 3);
4534 SIMPLE_OP (td
, MINT_STELEM_I
);
4538 CHECK_STACK (td
, 3);
4540 SIMPLE_OP (td
, MINT_STELEM_I1
);
4544 CHECK_STACK (td
, 3);
4546 SIMPLE_OP (td
, MINT_STELEM_I2
);
4550 CHECK_STACK (td
, 3);
4552 SIMPLE_OP (td
, MINT_STELEM_I4
);
4556 CHECK_STACK (td
, 3);
4558 SIMPLE_OP (td
, MINT_STELEM_I8
);
4562 CHECK_STACK (td
, 3);
4564 SIMPLE_OP (td
, MINT_STELEM_R4
);
4568 CHECK_STACK (td
, 3);
4570 SIMPLE_OP (td
, MINT_STELEM_R8
);
4573 case CEE_STELEM_REF
:
4574 CHECK_STACK (td
, 3);
4576 SIMPLE_OP (td
, MINT_STELEM_REF
);
4580 CHECK_STACK (td
, 3);
4582 token
= read32 (td
->ip
+ 1);
4583 klass
= mini_get_class (method
, token
, generic_context
);
4584 CHECK_TYPELOAD (klass
);
4585 switch (mint_type (m_class_get_byval_arg (klass
))) {
4587 SIMPLE_OP (td
, MINT_STELEM_I1
);
4590 SIMPLE_OP (td
, MINT_STELEM_U1
);
4593 SIMPLE_OP (td
, MINT_STELEM_I2
);
4596 SIMPLE_OP (td
, MINT_STELEM_U2
);
4599 SIMPLE_OP (td
, MINT_STELEM_I4
);
4602 SIMPLE_OP (td
, MINT_STELEM_I8
);
4605 SIMPLE_OP (td
, MINT_STELEM_R4
);
4608 SIMPLE_OP (td
, MINT_STELEM_R8
);
4611 SIMPLE_OP (td
, MINT_STELEM_REF
);
4613 case MINT_TYPE_VT
: {
4614 int size
= mono_class_value_size (klass
, NULL
);
4615 SIMPLE_OP (td
, MINT_STELEM_VT
);
4616 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
4617 WRITE32_INS (td
->last_ins
, 1, &size
);
4622 GString
*res
= g_string_new ("");
4623 mono_type_get_desc (res
, m_class_get_byval_arg (klass
), TRUE
);
4624 g_print ("STELEM: %s -> %d (%s)\n", m_class_get_name (klass
), mint_type (m_class_get_byval_arg (klass
)), res
->str
);
4625 g_string_free (res
, TRUE
);
4634 case CEE_CONV_OVF_U1
:
4636 case CEE_CONV_OVF_I8
:
4638 #if SIZEOF_VOID_P == 8
4639 case CEE_CONV_OVF_U
:
4643 CHECK_STACK (td
, 1);
4644 SIMPLE_OP (td
, MINT_CKFINITE
);
4647 CHECK_STACK (td
, 1);
4649 token
= read32 (td
->ip
+ 1);
4650 klass
= mini_get_class (method
, token
, generic_context
);
4651 CHECK_TYPELOAD (klass
);
4653 interp_add_ins (td
, MINT_MKREFANY
);
4654 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
4657 PUSH_VT (td
, sizeof (MonoTypedRef
));
4658 SET_TYPE(td
->sp
- 1, STACK_TYPE_VT
, mono_defaults
.typed_reference_class
);
4660 case CEE_REFANYVAL
: {
4661 CHECK_STACK (td
, 1);
4663 token
= read32 (td
->ip
+ 1);
4664 klass
= mini_get_class (method
, token
, generic_context
);
4665 CHECK_TYPELOAD (klass
);
4667 interp_add_ins (td
, MINT_REFANYVAL
);
4668 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
4670 POP_VT (td
, sizeof (MonoTypedRef
));
4671 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
4676 case CEE_CONV_OVF_I1
:
4677 case CEE_CONV_OVF_I1_UN
: {
4678 gboolean is_un
= *td
->ip
== CEE_CONV_OVF_I1_UN
;
4679 CHECK_STACK (td
, 1);
4680 switch (td
->sp
[-1].type
) {
4682 interp_add_ins (td
, is_un
? MINT_CONV_OVF_I1_UN_R8
: MINT_CONV_OVF_I1_R8
);
4685 interp_add_ins (td
, is_un
? MINT_CONV_OVF_I1_U4
: MINT_CONV_OVF_I1_I4
);
4688 interp_add_ins (td
, is_un
? MINT_CONV_OVF_I1_U8
: MINT_CONV_OVF_I1_I8
);
4691 g_assert_not_reached ();
4694 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4697 case CEE_CONV_OVF_U1
:
4698 case CEE_CONV_OVF_U1_UN
:
4699 CHECK_STACK (td
, 1);
4700 switch (td
->sp
[-1].type
) {
4702 interp_add_ins (td
, MINT_CONV_OVF_U1_R8
);
4705 interp_add_ins (td
, MINT_CONV_OVF_U1_I4
);
4708 interp_add_ins (td
, MINT_CONV_OVF_U1_I8
);
4711 g_assert_not_reached ();
4714 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4716 case CEE_CONV_OVF_I2
:
4717 case CEE_CONV_OVF_I2_UN
: {
4718 gboolean is_un
= *td
->ip
== CEE_CONV_OVF_I2_UN
;
4719 CHECK_STACK (td
, 1);
4720 switch (td
->sp
[-1].type
) {
4722 interp_add_ins (td
, is_un
? MINT_CONV_OVF_I2_UN_R8
: MINT_CONV_OVF_I2_R8
);
4725 interp_add_ins (td
, is_un
? MINT_CONV_OVF_I2_U4
: MINT_CONV_OVF_I2_I4
);
4728 interp_add_ins (td
, is_un
? MINT_CONV_OVF_I2_U8
: MINT_CONV_OVF_I2_I8
);
4731 g_assert_not_reached ();
4734 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4737 case CEE_CONV_OVF_U2_UN
:
4738 case CEE_CONV_OVF_U2
:
4739 CHECK_STACK (td
, 1);
4740 switch (td
->sp
[-1].type
) {
4742 interp_add_ins (td
, MINT_CONV_OVF_U2_R8
);
4745 interp_add_ins (td
, MINT_CONV_OVF_U2_I4
);
4748 interp_add_ins (td
, MINT_CONV_OVF_U2_I8
);
4751 g_assert_not_reached ();
4754 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4756 #if SIZEOF_VOID_P == 4
4757 case CEE_CONV_OVF_I
:
4759 case CEE_CONV_OVF_I4
:
4760 case CEE_CONV_OVF_I4_UN
:
4761 CHECK_STACK (td
, 1);
4762 switch (td
->sp
[-1].type
) {
4764 interp_add_ins (td
, MINT_CONV_OVF_I4_R4
);
4767 interp_add_ins (td
, MINT_CONV_OVF_I4_R8
);
4770 if (*td
->ip
== CEE_CONV_OVF_I4_UN
)
4771 interp_add_ins (td
, MINT_CONV_OVF_I4_U4
);
4774 if (*td
->ip
== CEE_CONV_OVF_I4_UN
)
4775 interp_add_ins (td
, MINT_CONV_OVF_I4_U8
);
4777 interp_add_ins (td
, MINT_CONV_OVF_I4_I8
);
4780 g_assert_not_reached ();
4783 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4785 #if SIZEOF_VOID_P == 4
4786 case CEE_CONV_OVF_U
:
4788 case CEE_CONV_OVF_U4
:
4789 case CEE_CONV_OVF_U4_UN
:
4790 CHECK_STACK (td
, 1);
4791 switch (td
->sp
[-1].type
) {
4793 interp_add_ins (td
, MINT_CONV_OVF_U4_R4
);
4796 interp_add_ins (td
, MINT_CONV_OVF_U4_R8
);
4799 if (*td
->ip
!= CEE_CONV_OVF_U4_UN
)
4800 interp_add_ins (td
, MINT_CONV_OVF_U4_I4
);
4803 interp_add_ins (td
, MINT_CONV_OVF_U4_I8
);
4806 g_assert_not_reached ();
4809 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4811 #if SIZEOF_VOID_P == 8
4812 case CEE_CONV_OVF_I
:
4814 case CEE_CONV_OVF_I8
:
4815 CHECK_STACK (td
, 1);
4816 switch (td
->sp
[-1].type
) {
4818 interp_add_ins (td
, MINT_CONV_OVF_I8_R4
);
4821 interp_add_ins (td
, MINT_CONV_OVF_I8_R8
);
4824 interp_add_ins (td
, MINT_CONV_I8_I4
);
4829 g_assert_not_reached ();
4832 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
4834 #if SIZEOF_VOID_P == 8
4835 case CEE_CONV_OVF_U
:
4837 case CEE_CONV_OVF_U8
:
4838 CHECK_STACK (td
, 1);
4839 switch (td
->sp
[-1].type
) {
4841 interp_add_ins (td
, MINT_CONV_OVF_U8_R4
);
4844 interp_add_ins (td
, MINT_CONV_OVF_U8_R8
);
4847 interp_add_ins (td
, MINT_CONV_OVF_U8_I4
);
4850 interp_add_ins (td
, MINT_CONV_OVF_U8_I8
);
4853 g_assert_not_reached ();
4856 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
4861 token
= read32 (td
->ip
+ 1);
4862 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
|| method
->wrapper_type
== MONO_WRAPPER_SYNCHRONIZED
) {
4863 handle
= mono_method_get_wrapper_data (method
, token
);
4864 klass
= (MonoClass
*) mono_method_get_wrapper_data (method
, token
+ 1);
4865 if (klass
== mono_defaults
.typehandle_class
)
4866 handle
= m_class_get_byval_arg ((MonoClass
*) handle
);
4868 if (generic_context
) {
4869 handle
= mono_class_inflate_generic_type_checked ((MonoType
*)handle
, generic_context
, error
);
4870 goto_if_nok (error
, exit
);
4873 handle
= mono_ldtoken_checked (image
, token
, &klass
, generic_context
, error
);
4874 goto_if_nok (error
, exit
);
4876 mono_class_init_internal (klass
);
4877 mt
= mint_type (m_class_get_byval_arg (klass
));
4878 g_assert (mt
== MINT_TYPE_VT
);
4879 size
= mono_class_value_size (klass
, NULL
);
4880 g_assert (size
== sizeof(gpointer
));
4882 const unsigned char *next_ip
= td
->ip
+ 5;
4883 MonoMethod
*cmethod
;
4884 if (next_ip
< end
&&
4885 !td
->is_bb_start
[next_ip
- td
->il_code
] &&
4886 (*next_ip
== CEE_CALL
|| *next_ip
== CEE_CALLVIRT
) &&
4887 (cmethod
= mono_get_method_checked (image
, read32 (next_ip
+ 1), NULL
, generic_context
, error
)) &&
4888 (cmethod
->klass
== mono_defaults
.systemtype_class
) &&
4889 (strcmp (cmethod
->name
, "GetTypeFromHandle") == 0)) {
4890 interp_add_ins (td
, MINT_MONO_LDPTR
);
4891 gpointer systype
= mono_type_get_object_checked (domain
, (MonoType
*)handle
, error
);
4892 goto_if_nok (error
, exit
);
4893 td
->last_ins
->data
[0] = get_data_item_index (td
, systype
);
4894 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_MP
);
4895 td
->ip
= next_ip
+ 5;
4897 PUSH_VT (td
, sizeof(gpointer
));
4898 interp_add_ins (td
, MINT_LDTOKEN
);
4899 td
->last_ins
->data
[0] = get_data_item_index (td
, handle
);
4900 SET_TYPE (td
->sp
, stack_type
[mt
], klass
);
4908 binary_arith_op(td
, MINT_ADD_OVF_I4
);
4911 case CEE_ADD_OVF_UN
:
4912 binary_arith_op(td
, MINT_ADD_OVF_UN_I4
);
4916 binary_arith_op(td
, MINT_MUL_OVF_I4
);
4919 case CEE_MUL_OVF_UN
:
4920 binary_arith_op(td
, MINT_MUL_OVF_UN_I4
);
4924 binary_arith_op(td
, MINT_SUB_OVF_I4
);
4927 case CEE_SUB_OVF_UN
:
4928 binary_arith_op(td
, MINT_SUB_OVF_UN_I4
);
4931 case CEE_ENDFINALLY
: {
4932 g_assert (td
->clause_indexes
[in_offset
] != -1);
4934 SIMPLE_OP (td
, MINT_ENDFINALLY
);
4935 td
->last_ins
->data
[0] = td
->clause_indexes
[in_offset
];
4942 if (*td
->ip
== CEE_LEAVE
)
4943 offset
= 5 + read32 (td
->ip
+ 1);
4945 offset
= 2 + (gint8
)td
->ip
[1];
4948 if (td
->clause_indexes
[in_offset
] != -1) {
4949 /* LEAVE instructions in catch clauses need to check for abort exceptions */
4950 handle_branch (td
, MINT_LEAVE_S_CHECK
, MINT_LEAVE_CHECK
, offset
);
4952 handle_branch (td
, MINT_LEAVE_S
, MINT_LEAVE
, offset
);
4955 if (*td
->ip
== CEE_LEAVE
)
4961 case MONO_CUSTOM_PREFIX
:
4964 case CEE_MONO_RETHROW
:
4965 CHECK_STACK (td
, 1);
4966 SIMPLE_OP (td
, MINT_MONO_RETHROW
);
4970 case CEE_MONO_LD_DELEGATE_METHOD_PTR
:
4973 interp_add_ins (td
, MINT_LD_DELEGATE_METHOD_PTR
);
4974 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
4976 case CEE_MONO_CALLI_EXTRA_ARG
:
4977 /* Same as CEE_CALLI, except that we drop the extra arg required for llvm specific behaviour */
4978 interp_add_ins (td
, MINT_POP
);
4979 td
->last_ins
->data
[0] = 1;
4981 if (!interp_transform_call (td
, method
, NULL
, domain
, generic_context
, td
->is_bb_start
, NULL
, FALSE
, error
, FALSE
))
4984 case CEE_MONO_JIT_ICALL_ADDR
: {
4988 token
= read32 (td
->ip
+ 1);
4990 func
= mono_method_get_wrapper_data (method
, token
);
4992 interp_add_ins (td
, MINT_LDFTN
);
4993 td
->last_ins
->data
[0] = get_data_item_index (td
, func
);
4994 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
4997 case CEE_MONO_ICALL
: {
5000 MonoJitICallInfo
*info
;
5003 token
= read32 (td
->ip
+ 1);
5005 func
= mono_method_get_wrapper_data (method
, token
);
5006 info
= mono_find_jit_icall_by_addr (func
);
5009 CHECK_STACK (td
, info
->sig
->param_count
);
5010 if (!strcmp (info
->name
, "mono_threads_attach_coop")) {
5011 rtm
->needs_thread_attach
= 1;
5013 /* attach needs two arguments, and has one return value: leave one element on the stack */
5014 interp_add_ins (td
, MINT_POP
);
5015 td
->last_ins
->data
[0] = 0;
5016 } else if (!strcmp (info
->name
, "mono_threads_detach_coop")) {
5017 g_assert (rtm
->needs_thread_attach
);
5019 /* detach consumes two arguments, and no return value: drop both of them */
5020 interp_add_ins (td
, MINT_POP
);
5021 td
->last_ins
->data
[0] = 0;
5022 interp_add_ins (td
, MINT_POP
);
5023 td
->last_ins
->data
[0] = 0;
5025 icall_op
= interp_icall_op_for_sig (info
->sig
);
5026 g_assert (icall_op
!= -1);
5028 interp_add_ins (td
, icall_op
);
5029 td
->last_ins
->data
[0] = get_data_item_index (td
, func
);
5031 td
->sp
-= info
->sig
->param_count
;
5033 if (!MONO_TYPE_IS_VOID (info
->sig
->ret
)) {
5034 int mt
= mint_type (info
->sig
->ret
);
5036 SET_SIMPLE_TYPE(td
->sp
- 1, stack_type
[mt
]);
5040 case CEE_MONO_VTADDR
: {
5042 CHECK_STACK (td
, 1);
5043 if (method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
5044 size
= mono_class_native_size(td
->sp
[-1].klass
, NULL
);
5046 size
= mono_class_value_size(td
->sp
[-1].klass
, NULL
);
5047 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5048 interp_add_ins (td
, MINT_VTRESULT
);
5049 td
->last_ins
->data
[0] = 0;
5050 WRITE32_INS (td
->last_ins
, 1, &size
);
5053 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
5056 case CEE_MONO_LDPTR
:
5057 case CEE_MONO_CLASSCONST
:
5058 token
= read32 (td
->ip
+ 1);
5060 interp_add_ins (td
, MINT_MONO_LDPTR
);
5061 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_method_get_wrapper_data (method
, token
));
5062 td
->sp
[0].type
= STACK_TYPE_I
;
5065 case CEE_MONO_OBJADDR
:
5066 CHECK_STACK (td
, 1);
5068 td
->sp
[-1].type
= STACK_TYPE_MP
;
5071 case CEE_MONO_NEWOBJ
:
5072 token
= read32 (td
->ip
+ 1);
5074 interp_add_ins (td
, MINT_MONO_NEWOBJ
);
5075 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_method_get_wrapper_data (method
, token
));
5076 td
->sp
[0].type
= STACK_TYPE_O
;
5079 case CEE_MONO_RETOBJ
:
5080 CHECK_STACK (td
, 1);
5081 token
= read32 (td
->ip
+ 1);
5083 interp_add_ins (td
, MINT_MONO_RETOBJ
);
5086 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
5088 /*stackval_from_data (signature->ret, frame->retval, sp->data.vt, signature->pinvoke);*/
5090 if (td
->sp
> td
->stack
)
5091 g_warning ("CEE_MONO_RETOBJ: more values on stack: %d", td
->sp
-td
->stack
);
5093 case CEE_MONO_LDNATIVEOBJ
:
5094 token
= read32 (td
->ip
+ 1);
5096 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
5097 g_assert(m_class_is_valuetype (klass
));
5098 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
5100 case CEE_MONO_TLS
: {
5101 gint32 key
= read32 (td
->ip
+ 1);
5103 g_assert (key
< TLS_KEY_NUM
);
5104 interp_add_ins (td
, MINT_MONO_TLS
);
5105 WRITE32_INS (td
->last_ins
, 0, &key
);
5106 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_MP
);
5109 case CEE_MONO_ATOMIC_STORE_I4
:
5110 CHECK_STACK (td
, 2);
5111 SIMPLE_OP (td
, MINT_MONO_ATOMIC_STORE_I4
);
5115 case CEE_MONO_SAVE_LMF
:
5116 case CEE_MONO_RESTORE_LMF
:
5117 case CEE_MONO_NOT_TAKEN
:
5120 case CEE_MONO_LDPTR_INT_REQ_FLAG
:
5121 interp_add_ins (td
, MINT_MONO_LDPTR
);
5122 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_thread_interruption_request_flag ());
5123 PUSH_TYPE (td
, STACK_TYPE_MP
, NULL
);
5126 case CEE_MONO_MEMORY_BARRIER
:
5127 interp_add_ins (td
, MINT_MONO_MEMORY_BARRIER
);
5130 case CEE_MONO_LDDOMAIN
:
5131 interp_add_ins (td
, MINT_MONO_LDDOMAIN
);
5132 td
->sp
[0].type
= STACK_TYPE_I
;
5137 g_error ("transform.c: Unimplemented opcode: 0xF0 %02x at 0x%x\n", *td
->ip
, td
->ip
-header
->code
);
5147 case CEE_PREFIXREF
: ves_abort(); break;
5150 * Note: Exceptions thrown when executing a prefixed opcode need
5151 * to take into account the number of prefix bytes (usually the
5152 * throw point is just (ip - n_prefix_bytes).
5158 interp_add_ins (td
, MINT_ARGLIST
);
5159 PUSH_VT (td
, SIZEOF_VOID_P
);
5160 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_VT
);
5165 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
) {
5166 interp_add_ins (td
, MINT_CEQ_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
5168 if (td
->sp
[-1].type
== STACK_TYPE_R4
&& td
->sp
[-2].type
== STACK_TYPE_R8
)
5169 interp_add_ins (td
, MINT_CONV_R8_R4
);
5170 if (td
->sp
[-1].type
== STACK_TYPE_R8
&& td
->sp
[-2].type
== STACK_TYPE_R4
)
5171 interp_add_ins (td
, MINT_CONV_R8_R4_SP
);
5172 interp_add_ins (td
, MINT_CEQ_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
5175 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5180 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
)
5181 interp_add_ins (td
, MINT_CGT_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
5183 interp_add_ins (td
, MINT_CGT_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
5185 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5190 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
)
5191 interp_add_ins (td
, MINT_CGT_UN_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
5193 interp_add_ins (td
, MINT_CGT_UN_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
5195 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5200 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
)
5201 interp_add_ins (td
, MINT_CLT_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
5203 interp_add_ins (td
, MINT_CLT_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
5205 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5210 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
)
5211 interp_add_ins (td
, MINT_CLT_UN_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
5213 interp_add_ins (td
, MINT_CLT_UN_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
5215 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5218 case CEE_LDVIRTFTN
: /* fallthrough */
5221 if (*td
->ip
== CEE_LDVIRTFTN
) {
5222 CHECK_STACK (td
, 1);
5225 token
= read32 (td
->ip
+ 1);
5226 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
5227 m
= (MonoMethod
*)mono_method_get_wrapper_data (method
, token
);
5229 m
= mono_get_method_checked (image
, token
, NULL
, generic_context
, error
);
5230 goto_if_nok (error
, exit
);
5233 if (!mono_method_can_access_method (method
, m
))
5234 interp_generate_mae_throw (td
, method
, m
);
5236 if (method
->wrapper_type
== MONO_WRAPPER_NONE
&& m
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)
5237 m
= mono_marshal_get_synchronized_wrapper (m
);
5239 interp_add_ins (td
, *td
->ip
== CEE_LDFTN
? MINT_LDFTN
: MINT_LDVIRTFTN
);
5240 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
5241 goto_if_nok (error
, exit
);
5243 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_F
);
5247 int arg_n
= read16 (td
->ip
+ 1);
5248 if (td
->method
== method
)
5249 load_arg (td
, arg_n
);
5251 load_local_general (td
, arg_offsets
[arg_n
], get_arg_type (signature
, arg_n
));
5257 int n
= read16 (td
->ip
+ 1);
5259 get_arg_type_exact (td
, n
, &mt
);
5260 interp_add_ins (td
, mt
== MINT_TYPE_VT
? MINT_LDARGA_VT
: MINT_LDARGA
);
5261 td
->last_ins
->data
[0] = n
;
5262 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
5267 int arg_n
= read16 (td
->ip
+ 1);
5268 if (td
->method
== method
)
5269 store_arg (td
, arg_n
);
5271 store_local_general (td
, arg_offsets
[arg_n
], get_arg_type (signature
, arg_n
));
5276 load_local (td
, read16 (td
->ip
+ 1));
5280 interp_add_ins (td
, MINT_LDLOCA_S
);
5281 td
->last_ins
->data
[0] = td
->rtm
->local_offsets
[read16 (td
->ip
+ 1)];
5282 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
5286 store_local (td
, read16 (td
->ip
+ 1));
5290 CHECK_STACK (td
, 1);
5291 #if SIZEOF_VOID_P == 8
5292 if (td
->sp
[-1].type
== STACK_TYPE_I8
)
5293 interp_add_ins (td
, MINT_CONV_I4_I8
);
5295 interp_add_ins (td
, MINT_LOCALLOC
);
5296 if (td
->sp
!= td
->stack
+ 1)
5297 g_warning("CEE_LOCALLOC: stack not empty");
5299 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
5302 case CEE_UNUSED57
: ves_abort(); break;
5305 interp_add_ins (td
, MINT_ENDFILTER
);
5308 case CEE_UNALIGNED_
:
5317 /* FIX: should do something? */;
5318 // TODO: This should raise a method_tail_call profiler event.
5322 token
= read32 (td
->ip
+ 1);
5323 klass
= mini_get_class (method
, token
, generic_context
);
5324 CHECK_TYPELOAD (klass
);
5325 if (m_class_is_valuetype (klass
)) {
5326 interp_add_ins (td
, MINT_INITOBJ
);
5327 i32
= mono_class_value_size (klass
, NULL
);
5328 WRITE32_INS (td
->last_ins
, 0, &i32
);
5330 interp_add_ins (td
, MINT_LDNULL
);
5331 interp_add_ins (td
, MINT_STIND_REF
);
5338 /* FIX? convert length to I8? */
5340 interp_add_ins (td
, MINT_MONO_MEMORY_BARRIER
);
5341 interp_add_ins (td
, MINT_CPBLK
);
5342 BARRIER_IF_VOLATILE (td
);
5350 case CEE_CONSTRAINED_
:
5351 token
= read32 (td
->ip
+ 1);
5352 constrained_class
= mini_get_class (method
, token
, generic_context
);
5353 CHECK_TYPELOAD (constrained_class
);
5358 BARRIER_IF_VOLATILE (td
);
5359 interp_add_ins (td
, MINT_INITBLK
);
5364 /* FIXME: implement */
5368 int clause_index
= td
->clause_indexes
[in_offset
];
5369 g_assert (clause_index
!= -1);
5370 SIMPLE_OP (td
, MINT_RETHROW
);
5371 td
->last_ins
->data
[0] = rtm
->exvar_offsets
[clause_index
];
5377 token
= read32 (td
->ip
+ 1);
5379 if (mono_metadata_token_table (token
) == MONO_TABLE_TYPESPEC
&& !image_is_dynamic (m_class_get_image (method
->klass
)) && !generic_context
) {
5381 MonoType
*type
= mono_type_create_from_typespec_checked (image
, token
, error
);
5382 goto_if_nok (error
, exit
);
5383 size
= mono_type_size (type
, &align
);
5386 MonoClass
*szclass
= mini_get_class (method
, token
, generic_context
);
5387 CHECK_TYPELOAD (szclass
);
5389 if (!szclass
->valuetype
)
5390 THROW_EX (mono_exception_from_name (mono_defaults
.corlib
, "System", "InvalidProgramException"), ip
- 5);
5392 size
= mono_type_size (m_class_get_byval_arg (szclass
), &align
);
5394 interp_add_ins (td
, MINT_LDC_I4
);
5395 WRITE32_INS (td
->last_ins
, 0, &size
);
5396 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
5399 case CEE_REFANYTYPE
:
5400 interp_add_ins (td
, MINT_REFANYTYPE
);
5402 POP_VT (td
, sizeof (MonoTypedRef
));
5403 PUSH_VT (td
, sizeof (gpointer
));
5404 SET_TYPE(td
->sp
- 1, STACK_TYPE_VT
, NULL
);
5407 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
);
5411 g_error ("transform.c: Unimplemented opcode: %02x at 0x%x\n", *td
->ip
, td
->ip
-header
->code
);
5414 // No IR instructions were added as part of the IL instruction. Extend bb_start
5415 if (prev_last_ins
== td
->last_ins
&& td
->is_bb_start
[in_offset
] && td
->ip
< end
)
5416 td
->is_bb_start
[td
->ip
- td
->il_code
] = 1;
5419 g_assert (td
->ip
== end
);
5422 g_free (arg_offsets
);
5423 mono_basic_block_free (original_bb
);
5424 for (i
= 0; i
< header
->code_size
; ++i
)
5425 g_free (td
->stack_state
[i
]);
5426 g_free (td
->stack_state
);
5427 g_free (td
->stack_height
);
5428 g_free (td
->vt_stack_size
);
5429 g_free (td
->clause_indexes
);
5430 g_free (td
->is_bb_start
);
5438 // We are trying to branch to an il offset that has no associated ir instruction with it.
5439 // We will branch instead to the next instruction that we find
5441 resolve_in_offset (TransformData
*td
, int il_offset
)
5444 g_assert (!td
->in_offsets
[il_offset
]);
5445 while (!td
->in_offsets
[i
])
5447 td
->in_offsets
[il_offset
] = td
->in_offsets
[i
];
5448 return td
->in_offsets
[il_offset
];
5451 // We store in the in_offset array the native_offset + 1, so 0 can mean only that the il
5452 // offset is uninitialized. Otherwise 0 is valid value for first interp instruction.
5454 get_in_offset (TransformData
*td
, int il_offset
)
5456 int target_offset
= td
->in_offsets
[il_offset
];
5458 return target_offset
- 1;
5459 return resolve_in_offset (td
, il_offset
) - 1;
5463 handle_relocations (TransformData
*td
)
5465 // Handle relocations
5466 for (int i
= 0; i
< td
->relocs
->len
; ++i
) {
5467 Reloc
*reloc
= (Reloc
*)g_ptr_array_index (td
->relocs
, i
);
5468 int offset
= get_in_offset (td
, reloc
->target
) - reloc
->offset
;
5470 switch (reloc
->type
) {
5471 case RELOC_SHORT_BRANCH
:
5472 g_assert (td
->new_code
[reloc
->offset
+ 1] == 0xdead);
5473 td
->new_code
[reloc
->offset
+ 1] = offset
;
5475 case RELOC_LONG_BRANCH
: {
5476 guint16
*v
= (guint16
*) &offset
;
5477 g_assert (td
->new_code
[reloc
->offset
+ 1] == 0xdead);
5478 g_assert (td
->new_code
[reloc
->offset
+ 2] == 0xbeef);
5479 td
->new_code
[reloc
->offset
+ 1] = *(guint16
*) v
;
5480 td
->new_code
[reloc
->offset
+ 2] = *(guint16
*) (v
+ 1);
5483 case RELOC_SWITCH
: {
5484 guint16
*v
= (guint16
*)&offset
;
5485 g_assert (td
->new_code
[reloc
->offset
] == 0xdead);
5486 g_assert (td
->new_code
[reloc
->offset
+ 1] == 0xbeef);
5487 td
->new_code
[reloc
->offset
] = *(guint16
*)v
;
5488 td
->new_code
[reloc
->offset
+ 1] = *(guint16
*)(v
+ 1);
5492 g_assert_not_reached ();
5500 get_inst_length (InterpInst
*ins
)
5502 if (ins
->opcode
== MINT_SWITCH
)
5503 return MINT_SWITCH_LEN (READ32 (&ins
->data
[0]));
5505 return mono_interp_oplen
[ins
->opcode
];
5509 emit_compacted_instruction (TransformData
*td
, guint16
* start_ip
, InterpInst
*ins
)
5511 guint16 opcode
= ins
->opcode
;
5512 guint16
*ip
= start_ip
;
5514 // We know what IL offset this instruction was created for. We can now map the IL offset
5515 // to the IR offset. We use this array to resolve the relocations, which reference the IL.
5516 if (ins
->il_offset
!= -1 && !td
->in_offsets
[ins
->il_offset
]) {
5517 g_assert (ins
->il_offset
>= 0 && ins
->il_offset
< td
->header
->code_size
);
5518 td
->in_offsets
[ins
->il_offset
] = start_ip
- td
->new_code
+ 1;
5520 MonoDebugLineNumberEntry lne
;
5521 lne
.native_offset
= (guint8
*)start_ip
- (guint8
*)td
->new_code
;
5522 lne
.il_offset
= ins
->il_offset
;
5523 g_array_append_val (td
->line_numbers
, lne
);
5527 if (opcode
== MINT_SWITCH
) {
5528 int labels
= READ32 (&ins
->data
[0]);
5529 // Write number of switch labels
5530 *ip
++ = ins
->data
[0];
5531 *ip
++ = ins
->data
[1];
5532 // Add relocation for each label
5533 for (int i
= 0; i
< labels
; i
++) {
5534 Reloc
*reloc
= (Reloc
*)mono_mempool_alloc0 (td
->mempool
, sizeof (Reloc
));
5535 reloc
->type
= RELOC_SWITCH
;
5536 reloc
->offset
= ip
- td
->new_code
;
5537 reloc
->target
= READ32 (&ins
->data
[2 + i
* 2]);
5538 g_ptr_array_add (td
->relocs
, reloc
);
5542 } else if ((opcode
>= MINT_BRFALSE_I4_S
&& opcode
<= MINT_BRTRUE_R8_S
) ||
5543 (opcode
>= MINT_BEQ_I4_S
&& opcode
<= MINT_BLT_UN_R8_S
) ||
5544 opcode
== MINT_BR_S
|| opcode
== MINT_LEAVE_S
|| opcode
== MINT_LEAVE_S_CHECK
) {
5545 const int br_offset
= start_ip
- td
->new_code
;
5546 if (ins
->data
[0] < ins
->il_offset
) {
5547 // Backwards branch. We can already patch it.
5548 *ip
++ = get_in_offset (td
, ins
->data
[0]) - br_offset
;
5550 // We don't know the in_offset of the target, add a reloc
5551 Reloc
*reloc
= (Reloc
*)mono_mempool_alloc0 (td
->mempool
, sizeof (Reloc
));
5552 reloc
->type
= RELOC_SHORT_BRANCH
;
5553 reloc
->offset
= br_offset
;
5554 reloc
->target
= ins
->data
[0];
5555 g_ptr_array_add (td
->relocs
, reloc
);
5558 } else if ((opcode
>= MINT_BRFALSE_I4
&& opcode
<= MINT_BRTRUE_R8
) ||
5559 (opcode
>= MINT_BEQ_I4
&& opcode
<= MINT_BLT_UN_R8
) ||
5560 opcode
== MINT_BR
|| opcode
== MINT_LEAVE
|| opcode
== MINT_LEAVE_CHECK
) {
5561 const int br_offset
= start_ip
- td
->new_code
;
5562 int target_il
= READ32 (&ins
->data
[0]);
5563 if (target_il
< ins
->il_offset
) {
5564 // Backwards branch. We can already patch it
5565 const int br_offset
= start_ip
- td
->new_code
;
5566 int target_offset
= get_in_offset (td
, target_il
) - br_offset
;
5567 WRITE32 (ip
, &target_offset
);
5569 Reloc
*reloc
= (Reloc
*)mono_mempool_alloc0 (td
->mempool
, sizeof (Reloc
));
5570 reloc
->type
= RELOC_LONG_BRANCH
;
5571 reloc
->offset
= br_offset
;
5572 reloc
->target
= target_il
;
5573 g_ptr_array_add (td
->relocs
, reloc
);
5577 } else if (opcode
== MINT_SDB_SEQ_POINT
) {
5578 SeqPoint
*seqp
= (SeqPoint
*)mono_mempool_alloc0 (td
->mempool
, sizeof (SeqPoint
));
5579 InterpBasicBlock
*cbb
;
5581 if (ins
->flags
& INTERP_INST_FLAG_SEQ_POINT_METHOD_ENTRY
) {
5582 seqp
->il_offset
= METHOD_ENTRY_IL_OFFSET
;
5583 cbb
= td
->offset_to_bb
[0];
5585 if (ins
->flags
& INTERP_INST_FLAG_SEQ_POINT_METHOD_EXIT
)
5586 seqp
->il_offset
= METHOD_EXIT_IL_OFFSET
;
5588 seqp
->il_offset
= ins
->il_offset
;
5589 cbb
= td
->offset_to_bb
[ins
->il_offset
];
5591 seqp
->native_offset
= (guint8
*)start_ip
- (guint8
*)td
->new_code
;
5592 if (ins
->flags
& INTERP_INST_FLAG_SEQ_POINT_NONEMPTY_STACK
)
5593 seqp
->flags
|= MONO_SEQ_POINT_FLAG_NONEMPTY_STACK
;
5594 if (ins
->flags
& INTERP_INST_FLAG_SEQ_POINT_NESTED_CALL
)
5595 seqp
->flags
|= MONO_SEQ_POINT_FLAG_NESTED_CALL
;
5596 g_ptr_array_add (td
->seq_points
, seqp
);
5598 cbb
->seq_points
= g_slist_prepend_mempool (td
->mempool
, cbb
->seq_points
, seqp
);
5599 cbb
->last_seq_point
= seqp
;
5601 int size
= get_inst_length (ins
) - 1;
5602 // Emit the rest of the data
5603 for (int i
= 0; i
< size
; i
++)
5604 *ip
++ = ins
->data
[i
];
5609 // Generates the final code, after we are done with all the passes
5611 generate_compacted_code (TransformData
*td
)
5615 td
->relocs
= g_ptr_array_new ();
5617 // Iterate once to compute the exact size of the compacted code
5618 InterpInst
*ins
= td
->first_ins
;
5620 size
+= get_inst_length (ins
);
5624 // Generate the compacted stream of instructions
5625 td
->new_code
= ip
= (guint16
*)mono_domain_alloc0 (td
->rtm
->domain
, size
* sizeof (guint16
));
5626 ins
= td
->first_ins
;
5628 ip
= emit_compacted_instruction (td
, ip
, ins
);
5631 td
->new_code_end
= ip
;
5632 td
->in_offsets
[td
->header
->code_size
] = td
->new_code_end
- td
->new_code
;
5634 // Patch all branches
5635 handle_relocations (td
);
5637 g_ptr_array_free (td
->relocs
, TRUE
);
5641 generate (MonoMethod
*method
, MonoMethodHeader
*header
, InterpMethod
*rtm
, MonoGenericContext
*generic_context
, MonoError
*error
)
5643 MonoDomain
*domain
= rtm
->domain
;
5645 TransformData transform_data
;
5647 static gboolean verbose_method_inited
;
5648 static char* verbose_method_name
;
5650 if (!verbose_method_inited
) {
5651 verbose_method_name
= g_getenv ("MONO_VERBOSE_METHOD");
5652 verbose_method_inited
= TRUE
;
5655 memset (&transform_data
, 0, sizeof(transform_data
));
5656 td
= &transform_data
;
5658 td
->method
= method
;
5660 td
->code_size
= header
->code_size
;
5661 td
->header
= header
;
5662 td
->max_code_size
= td
->code_size
;
5663 td
->in_offsets
= (int*)g_malloc0((header
->code_size
+ 1) * sizeof(int));
5664 td
->mempool
= mono_mempool_new ();
5665 td
->n_data_items
= 0;
5666 td
->max_data_items
= 0;
5667 td
->data_items
= NULL
;
5668 td
->data_hash
= g_hash_table_new (NULL
, NULL
);
5669 td
->gen_sdb_seq_points
= mini_debug_options
.gen_sdb_seq_points
;
5670 td
->seq_points
= g_ptr_array_new ();
5671 td
->verbose_level
= mono_interp_traceopt
;
5672 td
->total_locals_size
= rtm
->locals_size
;
5673 rtm
->data_items
= td
->data_items
;
5675 if (verbose_method_name
) {
5676 const char *name
= verbose_method_name
;
5678 if ((strchr (name
, '.') > name
) || strchr (name
, ':')) {
5679 MonoMethodDesc
*desc
;
5681 desc
= mono_method_desc_new (name
, TRUE
);
5682 if (mono_method_desc_full_match (desc
, method
)) {
5683 td
->verbose_level
= 4;
5685 mono_method_desc_free (desc
);
5687 if (strcmp (method
->name
, name
) == 0)
5688 td
->verbose_level
= 4;
5692 td
->stack
= (StackInfo
*)g_malloc0 ((header
->max_stack
+ 1) * sizeof (td
->stack
[0]));
5693 td
->stack_capacity
= header
->max_stack
+ 1;
5695 td
->max_stack_height
= 0;
5696 td
->line_numbers
= g_array_new (FALSE
, TRUE
, sizeof (MonoDebugLineNumberEntry
));
5698 generate_code (td
, method
, header
, generic_context
, error
);
5699 goto_if_nok (error
, exit
);
5701 generate_compacted_code (td
);
5703 if (td
->verbose_level
) {
5704 g_print ("Runtime method: %s %p, VT stack size: %d\n", mono_method_full_name (method
, TRUE
), rtm
, td
->max_vt_sp
);
5705 g_print ("Calculated stack size: %d, stated size: %d\n", td
->max_stack_height
, header
->max_stack
);
5706 dump_mint_code (td
->new_code
, td
->new_code_end
);
5709 /* Check if we use excessive stack space */
5710 if (td
->max_stack_height
> header
->max_stack
* 3 && header
->max_stack
> 16)
5711 g_warning ("Excessive stack space usage for method %s, %d/%d", method
->name
, td
->max_stack_height
, header
->max_stack
);
5714 code_len
= td
->new_code_end
- td
->new_code
;
5716 rtm
->clauses
= (MonoExceptionClause
*)mono_domain_alloc0 (domain
, header
->num_clauses
* sizeof (MonoExceptionClause
));
5717 memcpy (rtm
->clauses
, header
->clauses
, header
->num_clauses
* sizeof(MonoExceptionClause
));
5718 rtm
->code
= (gushort
*)td
->new_code
;
5719 rtm
->init_locals
= header
->init_locals
;
5720 rtm
->num_clauses
= header
->num_clauses
;
5721 for (i
= 0; i
< header
->num_clauses
; i
++) {
5722 MonoExceptionClause
*c
= rtm
->clauses
+ i
;
5723 int end_off
= c
->try_offset
+ c
->try_len
;
5724 c
->try_offset
= get_in_offset (td
, c
->try_offset
);
5725 c
->try_len
= get_in_offset (td
, end_off
) - c
->try_offset
;
5726 g_assert ((c
->try_offset
+ c
->try_len
) < code_len
);
5727 end_off
= c
->handler_offset
+ c
->handler_len
;
5728 c
->handler_offset
= get_in_offset (td
, c
->handler_offset
);
5729 c
->handler_len
= get_in_offset (td
, end_off
) - c
->handler_offset
;
5730 g_assert (c
->handler_len
>= 0 && (c
->handler_offset
+ c
->handler_len
) <= code_len
);
5731 if (c
->flags
& MONO_EXCEPTION_CLAUSE_FILTER
)
5732 c
->data
.filter_offset
= get_in_offset (td
, c
->data
.filter_offset
);
5734 rtm
->stack_size
= (sizeof (stackval
)) * (td
->max_stack_height
+ 2); /* + 1 for returns of called functions + 1 for 0-ing in trace*/
5735 rtm
->stack_size
= ALIGN_TO (rtm
->stack_size
, MINT_VT_ALIGNMENT
);
5736 rtm
->vt_stack_size
= td
->max_vt_sp
;
5737 rtm
->total_locals_size
= td
->total_locals_size
;
5738 rtm
->alloca_size
= rtm
->total_locals_size
+ rtm
->vt_stack_size
+ rtm
->stack_size
;
5739 rtm
->data_items
= (gpointer
*)mono_domain_alloc0 (domain
, td
->n_data_items
* sizeof (td
->data_items
[0]));
5740 memcpy (rtm
->data_items
, td
->data_items
, td
->n_data_items
* sizeof (td
->data_items
[0]));
5742 /* Save debug info */
5743 interp_save_debug_info (rtm
, header
, td
, td
->line_numbers
);
5745 /* Create a MonoJitInfo for the interpreted method by creating the interpreter IR as the native code. */
5747 jinfo_len
= mono_jit_info_size ((MonoJitInfoFlags
)0, header
->num_clauses
, 0);
5749 jinfo
= (MonoJitInfo
*)mono_domain_alloc0 (domain
, jinfo_len
);
5750 jinfo
->is_interp
= 1;
5752 mono_jit_info_init (jinfo
, method
, (guint8
*)rtm
->code
, code_len
, (MonoJitInfoFlags
)0, header
->num_clauses
, 0);
5753 for (i
= 0; i
< jinfo
->num_clauses
; ++i
) {
5754 MonoJitExceptionInfo
*ei
= &jinfo
->clauses
[i
];
5755 MonoExceptionClause
*c
= rtm
->clauses
+ i
;
5757 ei
->flags
= c
->flags
;
5758 ei
->try_start
= (guint8
*)(rtm
->code
+ c
->try_offset
);
5759 ei
->try_end
= (guint8
*)(rtm
->code
+ c
->try_offset
+ c
->try_len
);
5760 ei
->handler_start
= (guint8
*)(rtm
->code
+ c
->handler_offset
);
5761 ei
->exvar_offset
= rtm
->exvar_offsets
[i
];
5762 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
5763 ei
->data
.filter
= (guint8
*)(rtm
->code
+ c
->data
.filter_offset
);
5764 } else if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
5765 ei
->data
.handler_end
= (guint8
*)(rtm
->code
+ c
->handler_offset
+ c
->handler_len
);
5767 ei
->data
.catch_class
= c
->data
.catch_class
;
5771 save_seq_points (td
, jinfo
);
5774 g_free (td
->in_offsets
);
5775 g_free (td
->data_items
);
5777 g_hash_table_destroy (td
->data_hash
);
5778 g_ptr_array_free (td
->seq_points
, TRUE
);
5779 g_array_free (td
->line_numbers
, TRUE
);
5780 mono_mempool_destroy (td
->mempool
);
5783 static mono_mutex_t calc_section
;
5786 mono_interp_transform_init (void)
5788 mono_os_mutex_init_recursive(&calc_section
);
5792 mono_interp_transform_method (InterpMethod
*imethod
, ThreadContext
*context
, MonoError
*error
)
5794 MonoMethod
*method
= imethod
->method
;
5795 MonoMethodHeader
*header
= NULL
;
5796 MonoMethodSignature
*signature
= mono_method_signature_internal (method
);
5797 MonoVTable
*method_class_vt
;
5798 MonoGenericContext
*generic_context
= NULL
;
5799 MonoDomain
*domain
= imethod
->domain
;
5800 InterpMethod tmp_imethod
;
5801 InterpMethod
*real_imethod
;
5805 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (method
->klass
))) {
5806 mono_error_set_invalid_operation (error
, "%s", "Could not execute the method because the containing type is not fully instantiated.");
5810 // g_printerr ("TRANSFORM(0x%016lx): begin %s::%s\n", mono_thread_current (), method->klass->name, method->name);
5811 method_class_vt
= mono_class_vtable_checked (domain
, imethod
->method
->klass
, error
);
5812 return_if_nok (error
);
5814 if (!method_class_vt
->initialized
) {
5815 mono_runtime_class_init_full (method_class_vt
, error
);
5816 return_if_nok (error
);
5819 MONO_PROFILER_RAISE (jit_begin
, (method
));
5821 if (mono_method_signature_internal (method
)->is_inflated
)
5822 generic_context
= mono_method_get_context (method
);
5824 MonoGenericContainer
*generic_container
= mono_method_get_generic_container (method
);
5825 if (generic_container
)
5826 generic_context
= &generic_container
->context
;
5829 if (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)) {
5830 MonoMethod
*nm
= NULL
;
5831 mono_os_mutex_lock (&calc_section
);
5832 if (imethod
->transformed
) {
5833 mono_os_mutex_unlock (&calc_section
);
5834 MONO_PROFILER_RAISE (jit_done
, (method
, imethod
->jinfo
));
5838 /* assumes all internal calls with an array this are built in... */
5839 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
&& (! mono_method_signature_internal (method
)->hasthis
|| m_class_get_rank (method
->klass
) == 0)) {
5840 nm
= mono_marshal_get_native_wrapper (method
, TRUE
, FALSE
);
5841 signature
= mono_method_signature_internal (nm
);
5843 const char *name
= method
->name
;
5844 if (m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) {
5845 if (*name
== '.' && (strcmp (name
, ".ctor") == 0)) {
5846 MonoJitICallInfo
*mi
= mono_find_jit_icall_by_name ("ves_icall_mono_delegate_ctor_interp");
5848 nm
= mono_marshal_get_icall_wrapper (mi
, TRUE
);
5849 } else if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
5851 * Usually handled during transformation of the caller, but
5852 * when the caller is handled by another execution engine
5853 * (for example fullAOT) we need to handle it here. That's
5854 * known to be wrong in cases where the reference to
5855 * `MonoDelegate` would be needed (FIXME).
5857 nm
= mono_marshal_get_delegate_invoke (method
, NULL
);
5858 } else if (*name
== 'B' && (strcmp (name
, "BeginInvoke") == 0)) {
5859 nm
= mono_marshal_get_delegate_begin_invoke (method
);
5860 } else if (*name
== 'E' && (strcmp (name
, "EndInvoke") == 0)) {
5861 nm
= mono_marshal_get_delegate_end_invoke (method
);
5865 g_assert_not_reached ();
5868 imethod
->stack_size
= sizeof (stackval
); /* for tracing */
5869 imethod
->alloca_size
= imethod
->stack_size
;
5870 imethod
->transformed
= TRUE
;
5871 mono_os_mutex_unlock(&calc_section
);
5872 MONO_PROFILER_RAISE (jit_done
, (method
, NULL
));
5876 header
= interp_method_get_header (nm
, error
);
5877 mono_os_mutex_unlock (&calc_section
);
5878 return_if_nok (error
);
5882 header
= mono_method_get_header_checked (method
, error
);
5883 return_if_nok (error
);
5886 g_assert ((signature
->param_count
+ signature
->hasthis
) < 1000);
5887 // g_printerr ("TRANSFORM(0x%016lx): end %s::%s\n", mono_thread_current (), method->klass->name, method->name);
5889 /* Make modifications to a copy of imethod, copy them back inside the lock */
5890 real_imethod
= imethod
;
5891 memcpy (&tmp_imethod
, imethod
, sizeof (InterpMethod
));
5892 imethod
= &tmp_imethod
;
5894 interp_method_compute_offsets (imethod
, signature
, header
);
5896 MONO_TIME_TRACK (mono_interp_stats
.transform_time
, generate (method
, header
, imethod
, generic_context
, error
));
5898 mono_metadata_free_mh (header
);
5900 return_if_nok (error
);
5902 /* Copy changes back */
5903 imethod
= real_imethod
;
5904 mono_os_mutex_lock (&calc_section
);
5905 if (!imethod
->transformed
) {
5906 InterpMethod
*hash
= imethod
->next_jit_code_hash
;
5907 memcpy (imethod
, &tmp_imethod
, sizeof (InterpMethod
));
5908 imethod
->next_jit_code_hash
= hash
;
5909 mono_memory_barrier ();
5910 imethod
->transformed
= TRUE
;
5911 mono_atomic_fetch_add_i32 (&mono_jit_stats
.methods_with_interp
, 1);
5914 mono_os_mutex_unlock (&calc_section
);
5916 mono_domain_lock (domain
);
5917 if (!g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, imethod
->method
))
5918 g_hash_table_insert (domain_jit_info (domain
)->seq_points
, imethod
->method
, imethod
->jinfo
->seq_points
);
5919 mono_domain_unlock (domain
);
5921 // FIXME: Add a different callback ?
5922 MONO_PROFILER_RAISE (jit_done
, (method
, imethod
->jinfo
));