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/class-internals.h>
14 #include <mono/metadata/debug-helpers.h>
15 #include <mono/metadata/exception.h>
16 #include <mono/metadata/exception-internals.h>
17 #include <mono/metadata/mono-endian.h>
18 #include <mono/metadata/marshal.h>
19 #include <mono/metadata/profiler-private.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/seq-points-data.h>
22 #include <mono/metadata/mono-basic-block.h>
23 #include <mono/metadata/abi-details.h>
24 #include <mono/metadata/reflection-internals.h>
25 #include <mono/utils/unlocked.h>
27 #include <mono/mini/mini.h>
28 #include <mono/mini/mini-runtime.h>
31 #include "interp-internals.h"
34 #define INTERP_INST_FLAG_SEQ_POINT_NONEMPTY_STACK 1
35 #define INTERP_INST_FLAG_SEQ_POINT_METHOD_ENTRY 2
36 #define INTERP_INST_FLAG_SEQ_POINT_METHOD_EXIT 4
37 #define INTERP_INST_FLAG_SEQ_POINT_NESTED_CALL 8
39 #define INTERP_LOCAL_FLAG_INDIRECT 1
41 MonoInterpStats mono_interp_stats
;
45 typedef struct InterpInst InterpInst
;
61 InterpInst
*next
, *prev
;
62 // If this is -1, this instruction is not logically associated with an IL offset, it is
63 // part of the IL instruction associated with the previous interp instruction.
66 guint16 data
[MONO_ZERO_LEN_ARRAY
];
73 SeqPoint
*last_seq_point
;
75 // This will hold a list of last sequence points of incoming basic blocks
76 SeqPoint
**pred_seq_points
;
77 guint num_pred_seq_points
;
88 /* In the interpreter IR */
103 MonoMethod
*inlined_method
;
104 MonoMethodHeader
*header
;
106 const unsigned char *il_code
;
107 const unsigned char *ip
;
108 const unsigned char *in_start
;
109 InterpInst
*last_ins
, *first_ins
;
112 int current_il_offset
;
113 StackInfo
**stack_state
;
116 unsigned char *is_bb_start
;
117 unsigned short *new_code
;
118 unsigned short *new_code_end
;
119 unsigned int max_code_size
;
122 unsigned int max_stack_height
;
123 unsigned int stack_capacity
;
125 unsigned int max_vt_sp
;
126 unsigned int total_locals_size
;
128 unsigned int locals_size
;
129 unsigned int locals_capacity
;
133 GHashTable
*data_hash
;
135 gboolean gen_sdb_seq_points
;
136 GPtrArray
*seq_points
;
137 InterpBasicBlock
**offset_to_bb
;
138 InterpBasicBlock
*entry_bb
;
139 MonoMemPool
*mempool
;
142 gboolean verbose_level
;
143 GArray
*line_numbers
;
146 #define STACK_TYPE_I4 0
147 #define STACK_TYPE_I8 1
148 #define STACK_TYPE_R4 2
149 #define STACK_TYPE_R8 3
150 #define STACK_TYPE_O 4
151 #define STACK_TYPE_VT 5
152 #define STACK_TYPE_MP 6
153 #define STACK_TYPE_F 7
155 static const char *stack_type_string
[] = { "I4", "I8", "R4", "R8", "O ", "VT", "MP", "F " };
157 #if SIZEOF_VOID_P == 8
158 #define STACK_TYPE_I STACK_TYPE_I8
160 #define STACK_TYPE_I STACK_TYPE_I4
163 static int stack_type
[] = {
164 STACK_TYPE_I4
, /*I1*/
165 STACK_TYPE_I4
, /*U1*/
166 STACK_TYPE_I4
, /*I2*/
167 STACK_TYPE_I4
, /*U2*/
168 STACK_TYPE_I4
, /*I4*/
169 STACK_TYPE_I8
, /*I8*/
170 STACK_TYPE_R4
, /*R4*/
171 STACK_TYPE_R8
, /*R8*/
177 #if SIZEOF_VOID_P == 8
178 #define MINT_NEG_P MINT_NEG_I8
179 #define MINT_NOT_P MINT_NOT_I8
181 #define MINT_NEG_FP MINT_NEG_R8
183 #define MINT_ADD_P MINT_ADD_I8
184 #define MINT_SUB_P MINT_SUB_I8
185 #define MINT_MUL_P MINT_MUL_I8
186 #define MINT_DIV_P MINT_DIV_I8
187 #define MINT_DIV_UN_P MINT_DIV_UN_I8
188 #define MINT_REM_P MINT_REM_I8
189 #define MINT_REM_UN_P MINT_REM_UN_I8
190 #define MINT_AND_P MINT_AND_I8
191 #define MINT_OR_P MINT_OR_I8
192 #define MINT_XOR_P MINT_XOR_I8
193 #define MINT_SHL_P MINT_SHL_I8
194 #define MINT_SHR_P MINT_SHR_I8
195 #define MINT_SHR_UN_P MINT_SHR_UN_I8
197 #define MINT_CEQ_P MINT_CEQ_I8
198 #define MINT_CNE_P MINT_CNE_I8
199 #define MINT_CLT_P MINT_CLT_I8
200 #define MINT_CLT_UN_P MINT_CLT_UN_I8
201 #define MINT_CGT_P MINT_CGT_I8
202 #define MINT_CGT_UN_P MINT_CGT_UN_I8
203 #define MINT_CLE_P MINT_CLE_I8
204 #define MINT_CLE_UN_P MINT_CLE_UN_I8
205 #define MINT_CGE_P MINT_CGE_I8
206 #define MINT_CGE_UN_P MINT_CGE_UN_I8
208 #define MINT_ADD_FP MINT_ADD_R8
209 #define MINT_SUB_FP MINT_SUB_R8
210 #define MINT_MUL_FP MINT_MUL_R8
211 #define MINT_DIV_FP MINT_DIV_R8
212 #define MINT_REM_FP MINT_REM_R8
214 #define MINT_CNE_FP MINT_CNE_R8
215 #define MINT_CEQ_FP MINT_CEQ_R8
216 #define MINT_CGT_FP MINT_CGT_R8
217 #define MINT_CGE_FP MINT_CGE_R8
218 #define MINT_CLT_FP MINT_CLT_R8
219 #define MINT_CLE_FP MINT_CLE_R8
221 #define MINT_CONV_OVF_U4_P MINT_CONV_OVF_U4_I8
224 #define MINT_NEG_P MINT_NEG_I4
225 #define MINT_NOT_P MINT_NOT_I4
227 #define MINT_NEG_FP MINT_NEG_R4
229 #define MINT_ADD_P MINT_ADD_I4
230 #define MINT_SUB_P MINT_SUB_I4
231 #define MINT_MUL_P MINT_MUL_I4
232 #define MINT_DIV_P MINT_DIV_I4
233 #define MINT_DIV_UN_P MINT_DIV_UN_I4
234 #define MINT_REM_P MINT_REM_I4
235 #define MINT_REM_UN_P MINT_REM_UN_I4
236 #define MINT_AND_P MINT_AND_I4
237 #define MINT_OR_P MINT_OR_I4
238 #define MINT_XOR_P MINT_XOR_I4
239 #define MINT_SHL_P MINT_SHL_I4
240 #define MINT_SHR_P MINT_SHR_I4
241 #define MINT_SHR_UN_P MINT_SHR_UN_I4
243 #define MINT_CEQ_P MINT_CEQ_I4
244 #define MINT_CNE_P MINT_CNE_I4
245 #define MINT_CLT_P MINT_CLT_I4
246 #define MINT_CLT_UN_P MINT_CLT_UN_I4
247 #define MINT_CGT_P MINT_CGT_I4
248 #define MINT_CGT_UN_P MINT_CGT_UN_I4
249 #define MINT_CLE_P MINT_CLE_I4
250 #define MINT_CLE_UN_P MINT_CLE_UN_I4
251 #define MINT_CGE_P MINT_CGE_I4
252 #define MINT_CGE_UN_P MINT_CGE_UN_I4
254 #define MINT_ADD_FP MINT_ADD_R4
255 #define MINT_SUB_FP MINT_SUB_R4
256 #define MINT_MUL_FP MINT_MUL_R4
257 #define MINT_DIV_FP MINT_DIV_R4
258 #define MINT_REM_FP MINT_REM_R4
260 #define MINT_CNE_FP MINT_CNE_R4
261 #define MINT_CEQ_FP MINT_CEQ_R4
262 #define MINT_CGT_FP MINT_CGT_R4
263 #define MINT_CGE_FP MINT_CGE_R4
264 #define MINT_CLT_FP MINT_CLT_R4
265 #define MINT_CLE_FP MINT_CLE_R4
267 #define MINT_CONV_OVF_U4_P MINT_CONV_OVF_U4_I4
271 const gchar
*op_name
;
275 // static const MagicIntrinsic int_binop[] = {
277 static const MagicIntrinsic int_unnop
[] = {
278 { "op_UnaryPlus", {MINT_NOP
, MINT_NOP
, MINT_NOP
}},
279 { "op_UnaryNegation", {MINT_NEG_P
, MINT_NEG_P
, MINT_NEG_FP
}},
280 { "op_OnesComplement", {MINT_NOT_P
, MINT_NOT_P
, MINT_NIY
}}
283 static const MagicIntrinsic int_binop
[] = {
284 { "op_Addition", {MINT_ADD_P
, MINT_ADD_P
, MINT_ADD_FP
}},
285 { "op_Subtraction", {MINT_SUB_P
, MINT_SUB_P
, MINT_SUB_FP
}},
286 { "op_Multiply", {MINT_MUL_P
, MINT_MUL_P
, MINT_MUL_FP
}},
287 { "op_Division", {MINT_DIV_P
, MINT_DIV_UN_P
, MINT_DIV_FP
}},
288 { "op_Modulus", {MINT_REM_P
, MINT_REM_UN_P
, MINT_REM_FP
}},
289 { "op_BitwiseAnd", {MINT_AND_P
, MINT_AND_P
, MINT_NIY
}},
290 { "op_BitwiseOr", {MINT_OR_P
, MINT_OR_P
, MINT_NIY
}},
291 { "op_ExclusiveOr", {MINT_XOR_P
, MINT_XOR_P
, MINT_NIY
}},
292 { "op_LeftShift", {MINT_SHL_P
, MINT_SHL_P
, MINT_NIY
}},
293 { "op_RightShift", {MINT_SHR_P
, MINT_SHR_UN_P
, MINT_NIY
}},
296 static const MagicIntrinsic int_cmpop
[] = {
297 { "op_Inequality", {MINT_CNE_P
, MINT_CNE_P
, MINT_CNE_FP
}},
298 { "op_Equality", {MINT_CEQ_P
, MINT_CEQ_P
, MINT_CEQ_FP
}},
299 { "op_GreaterThan", {MINT_CGT_P
, MINT_CGT_UN_P
, MINT_CGT_FP
}},
300 { "op_GreaterThanOrEqual", {MINT_CGE_P
, MINT_CGE_UN_P
, MINT_CGE_FP
}},
301 { "op_LessThan", {MINT_CLT_P
, MINT_CLT_UN_P
, MINT_CLT_FP
}},
302 { "op_LessThanOrEqual", {MINT_CLE_P
, MINT_CLE_UN_P
, MINT_CLE_FP
}}
305 static gboolean
generate_code (TransformData
*td
, MonoMethod
*method
, MonoMethodHeader
*header
, MonoGenericContext
*generic_context
, MonoError
*error
);
308 interp_new_ins (TransformData
*td
, guint16 opcode
, int len
)
310 InterpInst
*new_inst
;
311 // Size of data region of instruction is length of instruction minus 1 (the opcode slot)
312 new_inst
= mono_mempool_alloc0 (td
->mempool
, sizeof (InterpInst
) + sizeof (guint16
) * ((len
> 0) ? (len
- 1) : 0));
313 new_inst
->opcode
= opcode
;
314 new_inst
->il_offset
= td
->current_il_offset
;
318 // This version need to be used with switch opcode, which doesn't have constant length
320 interp_add_ins_explicit (TransformData
*td
, guint16 opcode
, int len
)
322 InterpInst
*new_inst
= interp_new_ins (td
, opcode
, len
);
323 new_inst
->prev
= td
->last_ins
;
325 td
->last_ins
->next
= new_inst
;
327 td
->first_ins
= new_inst
;
328 td
->last_ins
= new_inst
;
333 interp_add_ins (TransformData
*td
, guint16 opcode
)
335 return interp_add_ins_explicit (td
, opcode
, mono_interp_oplen
[opcode
]);
338 // This instruction will have the il_offset of the previous instruction
340 interp_insert_ins (TransformData
*td
, InterpInst
*prev_ins
, guint16 opcode
)
342 InterpInst
*new_inst
= interp_new_ins (td
, opcode
, mono_interp_oplen
[opcode
]);
344 new_inst
->il_offset
= prev_ins
->il_offset
;
346 new_inst
->prev
= prev_ins
;
347 new_inst
->next
= prev_ins
->next
;
348 prev_ins
->next
= new_inst
;
350 if (new_inst
->next
== NULL
)
351 td
->last_ins
= new_inst
;
353 new_inst
->next
->prev
= new_inst
;
359 interp_clear_ins (TransformData
*td
, InterpInst
*ins
)
361 // Clearing instead of removing from the list makes everything easier.
362 // We don't change structure of the instruction list, we don't need
363 // to worry about updating the il_offset, or whether this instruction
364 // was at the start of a basic block etc.
365 ins
->opcode
= MINT_NOP
;
368 #define CHECK_STACK(td, n) \
370 int stack_size = (td)->sp - (td)->stack; \
371 if (stack_size < (n)) \
372 g_warning ("%s.%s: not enough values (%d < %d) on stack at %04x", \
373 m_class_get_name ((td)->method->klass), (td)->method->name, \
374 stack_size, n, (td)->ip - (td)->il_code); \
377 #define ENSURE_I4(td, sp_off) \
379 if ((td)->sp [-sp_off].type == STACK_TYPE_I8) \
380 interp_add_ins (td, sp_off == 1 ? MINT_CONV_I4_I8 : MINT_CONV_I4_I8_SP); \
383 #define CHECK_TYPELOAD(klass) \
385 if (!(klass) || mono_class_has_failure (klass)) { \
386 mono_error_set_for_class_failure (error, klass); \
391 #if NO_UNALIGNED_ACCESS
392 #define WRITE32(ip, v) \
394 * (ip) = * (guint16 *)(v); \
395 * ((ip) + 1) = * ((guint16 *)(v) + 1); \
399 #define WRITE32_INS(ins, index, v) \
401 (ins)->data [index] = * (guint16 *)(v); \
402 (ins)->data [index + 1] = * ((guint16 *)(v) + 1); \
405 #define WRITE64_INS(ins, index, v) \
407 (ins)->data [index] = * (guint16 *)(v); \
408 (ins)->data [index + 1] = * ((guint16 *)(v) + 1); \
409 (ins)->data [index + 2] = * ((guint16 *)(v) + 2); \
410 (ins)->data [index + 3] = * ((guint16 *)(v) + 3); \
413 #define WRITE32(ip, v) \
415 * (guint32*)(ip) = * (guint32 *)(v); \
418 #define WRITE32_INS(ins, index, v) \
420 * (guint32 *)(&(ins)->data [index]) = * (guint32 *)(v); \
423 #define WRITE64_INS(ins, index, v) \
425 * (guint64 *)(&(ins)->data [index]) = * (guint64 *)(v); \
432 handle_branch (TransformData
*td
, int short_op
, int long_op
, int offset
)
434 int shorten_branch
= 0;
435 int target
= td
->ip
+ offset
- td
->il_code
;
436 if (target
< 0 || target
>= td
->code_size
)
437 g_assert_not_reached ();
438 /* Add exception checkpoint or safepoint for backward branches */
440 if (mono_threads_are_safepoints_enabled ())
441 interp_add_ins (td
, MINT_SAFEPOINT
);
443 interp_add_ins (td
, MINT_CHECKPOINT
);
445 if (offset
> 0 && td
->stack_height
[target
] < 0) {
446 td
->stack_height
[target
] = td
->sp
- td
->stack
;
447 if (td
->stack_height
[target
] > 0)
448 td
->stack_state
[target
] = (StackInfo
*)g_memdup (td
->stack
, td
->stack_height
[target
] * sizeof (td
->stack
[0]));
449 td
->vt_stack_size
[target
] = td
->vt_sp
;
452 if (td
->header
->code_size
<= 25000) /* FIX to be precise somehow? */
455 if (shorten_branch
) {
456 interp_add_ins (td
, short_op
);
457 td
->last_ins
->data
[0] = (guint16
) target
;
459 interp_add_ins (td
, long_op
);
460 WRITE32_INS (td
->last_ins
, 0, &target
);
465 one_arg_branch(TransformData
*td
, int mint_op
, int offset
)
467 int type
= td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
? STACK_TYPE_I
: td
->sp
[-1].type
;
468 int long_op
= mint_op
+ type
- STACK_TYPE_I4
;
469 int short_op
= long_op
+ MINT_BRFALSE_I4_S
- MINT_BRFALSE_I4
;
472 handle_branch (td
, short_op
, long_op
, offset
);
476 two_arg_branch(TransformData
*td
, int mint_op
, int offset
)
478 int type1
= td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
? STACK_TYPE_I
: td
->sp
[-1].type
;
479 int type2
= td
->sp
[-2].type
== STACK_TYPE_O
|| td
->sp
[-2].type
== STACK_TYPE_MP
? STACK_TYPE_I
: td
->sp
[-2].type
;
480 int long_op
= mint_op
+ type1
- STACK_TYPE_I4
;
481 int short_op
= long_op
+ MINT_BEQ_I4_S
- MINT_BEQ_I4
;
483 if (type1
== STACK_TYPE_I4
&& type2
== STACK_TYPE_I8
) {
484 // The il instruction starts with the actual branch, and not with the conversion opcodes
485 interp_insert_ins (td
, td
->last_ins
, MINT_CONV_I8_I4
);
486 } else if (type1
== STACK_TYPE_I8
&& type2
== STACK_TYPE_I4
) {
487 interp_insert_ins (td
, td
->last_ins
, MINT_CONV_I8_I4_SP
);
488 } else if (type1
== STACK_TYPE_R4
&& type2
== STACK_TYPE_R8
) {
489 interp_insert_ins (td
, td
->last_ins
, MINT_CONV_R8_R4
);
490 } else if (type1
== STACK_TYPE_R8
&& type2
== STACK_TYPE_R4
) {
491 interp_insert_ins (td
, td
->last_ins
, MINT_CONV_R8_R4_SP
);
492 } else if (type1
!= type2
) {
493 g_warning("%s.%s: branch type mismatch %d %d",
494 m_class_get_name (td
->method
->klass
), td
->method
->name
,
495 td
->sp
[-1].type
, td
->sp
[-2].type
);
498 handle_branch (td
, short_op
, long_op
, offset
);
502 unary_arith_op(TransformData
*td
, int mint_op
)
504 int op
= mint_op
+ td
->sp
[-1].type
- STACK_TYPE_I4
;
506 interp_add_ins (td
, op
);
510 binary_arith_op(TransformData
*td
, int mint_op
)
512 int type1
= td
->sp
[-2].type
;
513 int type2
= td
->sp
[-1].type
;
515 #if SIZEOF_VOID_P == 8
516 if ((type1
== STACK_TYPE_MP
|| type1
== STACK_TYPE_I8
) && type2
== STACK_TYPE_I4
) {
517 interp_add_ins (td
, MINT_CONV_I8_I4
);
518 type2
= STACK_TYPE_I8
;
520 if (type1
== STACK_TYPE_I4
&& (type2
== STACK_TYPE_MP
|| type2
== STACK_TYPE_I8
)) {
521 interp_add_ins (td
, MINT_CONV_I8_I4_SP
);
522 type1
= STACK_TYPE_I8
;
523 td
->sp
[-2].type
= STACK_TYPE_I8
;
526 if (type1
== STACK_TYPE_R8
&& type2
== STACK_TYPE_R4
) {
527 interp_add_ins (td
, MINT_CONV_R8_R4
);
528 type2
= STACK_TYPE_R8
;
530 if (type1
== STACK_TYPE_R4
&& type2
== STACK_TYPE_R8
) {
531 interp_add_ins (td
, MINT_CONV_R8_R4_SP
);
532 type1
= STACK_TYPE_R8
;
533 td
->sp
[-2].type
= STACK_TYPE_R8
;
535 if (type1
== STACK_TYPE_MP
)
536 type1
= STACK_TYPE_I
;
537 if (type2
== STACK_TYPE_MP
)
538 type2
= STACK_TYPE_I
;
539 if (type1
!= type2
) {
540 g_warning("%s.%s: %04x arith type mismatch %s %d %d",
541 m_class_get_name (td
->method
->klass
), td
->method
->name
,
542 td
->ip
- td
->il_code
, mono_interp_opname (mint_op
), type1
, type2
);
544 op
= mint_op
+ type1
- STACK_TYPE_I4
;
546 interp_add_ins (td
, op
);
551 shift_op(TransformData
*td
, int mint_op
)
553 int op
= mint_op
+ td
->sp
[-2].type
- STACK_TYPE_I4
;
555 if (td
->sp
[-1].type
!= STACK_TYPE_I4
) {
556 g_warning("%s.%s: shift type mismatch %d",
557 m_class_get_name (td
->method
->klass
), td
->method
->name
,
560 interp_add_ins (td
, op
);
565 can_store (int st_value
, int vt_value
)
567 if (st_value
== STACK_TYPE_O
|| st_value
== STACK_TYPE_MP
)
568 st_value
= STACK_TYPE_I
;
569 if (vt_value
== STACK_TYPE_O
|| vt_value
== STACK_TYPE_MP
)
570 vt_value
= STACK_TYPE_I
;
571 return st_value
== vt_value
;
574 #define SET_SIMPLE_TYPE(s, ty) \
581 #define SET_TYPE(s, ty, k) \
588 #define REALLOC_STACK(td, sppos) \
590 (td)->stack_capacity *= 2; \
591 (td)->stack = (StackInfo*)realloc ((td)->stack, (td)->stack_capacity * sizeof (td->stack [0])); \
592 (td)->sp = (td)->stack + (sppos); \
595 #define PUSH_SIMPLE_TYPE(td, ty) \
599 sp_height = (td)->sp - (td)->stack; \
600 if (sp_height > (td)->max_stack_height) \
601 (td)->max_stack_height = sp_height; \
602 if (sp_height > (td)->stack_capacity) \
603 REALLOC_STACK(td, sp_height); \
604 SET_SIMPLE_TYPE((td)->sp - 1, ty); \
607 #define PUSH_TYPE(td, ty, k) \
611 sp_height = (td)->sp - (td)->stack; \
612 if (sp_height > (td)->max_stack_height) \
613 (td)->max_stack_height = sp_height; \
614 if (sp_height > (td)->stack_capacity) \
615 REALLOC_STACK(td, sp_height); \
616 SET_TYPE((td)->sp - 1, ty, k); \
620 move_stack (TransformData
*td
, int start
, int amount
)
622 int sp_height
= td
->sp
- td
->stack
;
623 int to_move
= sp_height
- start
;
628 if (sp_height
> td
->max_stack_height
)
629 td
->max_stack_height
= sp_height
;
630 if (sp_height
> td
->stack_capacity
)
631 REALLOC_STACK (td
, sp_height
);
633 g_assert (td
->sp
>= td
->stack
);
637 memmove (td
->stack
+ start
+ amount
, td
->stack
+ start
, to_move
* sizeof (StackInfo
));
640 #define PUSH_VT(td, size) \
642 (td)->vt_sp += ALIGN_TO ((size), MINT_VT_ALIGNMENT); \
643 if ((td)->vt_sp > (td)->max_vt_sp) \
644 (td)->max_vt_sp = (td)->vt_sp; \
647 #define POP_VT(td, size) \
649 (td)->vt_sp -= ALIGN_TO ((size), MINT_VT_ALIGNMENT); \
653 get_arg_type_exact (TransformData
*td
, int n
, int *mt
)
656 gboolean hasthis
= mono_method_signature_internal (td
->method
)->hasthis
;
658 if (hasthis
&& n
== 0)
659 type
= m_class_get_byval_arg (td
->method
->klass
);
661 type
= mono_method_signature_internal (td
->method
)->params
[n
- !!hasthis
];
664 *mt
= mint_type (type
);
670 load_arg(TransformData
*td
, int n
)
673 MonoClass
*klass
= NULL
;
675 gboolean hasthis
= mono_method_signature_internal (td
->method
)->hasthis
;
677 type
= get_arg_type_exact (td
, n
, &mt
);
679 if (mt
== MINT_TYPE_VT
) {
681 klass
= mono_class_from_mono_type_internal (type
);
682 if (mono_method_signature_internal (td
->method
)->pinvoke
)
683 size
= mono_class_native_size (klass
, NULL
);
685 size
= mono_class_value_size (klass
, NULL
);
687 if (hasthis
&& n
== 0) {
689 interp_add_ins (td
, MINT_LDARG_P0
);
693 interp_add_ins (td
, MINT_LDARG_VT
);
694 td
->last_ins
->data
[0] = n
;
695 WRITE32_INS (td
->last_ins
, 1, &size
);
698 if ((hasthis
|| mt
== MINT_TYPE_P
) && n
== 0) {
700 interp_add_ins (td
, MINT_LDARG_P0
);
702 interp_add_ins (td
, MINT_LDARG_I1
+ (mt
- MINT_TYPE_I1
));
703 td
->last_ins
->data
[0] = n
;
704 if (mt
== MINT_TYPE_O
)
705 klass
= mono_class_from_mono_type_internal (type
);
708 PUSH_TYPE(td
, stack_type
[mt
], klass
);
712 store_arg(TransformData
*td
, int n
)
718 type
= get_arg_type_exact (td
, n
, &mt
);
720 if (mt
== MINT_TYPE_VT
) {
722 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
723 if (mono_method_signature_internal (td
->method
)->pinvoke
)
724 size
= mono_class_native_size (klass
, NULL
);
726 size
= mono_class_value_size (klass
, NULL
);
727 interp_add_ins (td
, MINT_STARG_VT
);
728 td
->last_ins
->data
[0] = n
;
729 WRITE32_INS (td
->last_ins
, 1, &size
);
730 if (td
->sp
[-1].type
== STACK_TYPE_VT
)
733 interp_add_ins (td
, MINT_STARG_I1
+ (mt
- MINT_TYPE_I1
));
734 td
->last_ins
->data
[0] = n
;
740 load_local_general (TransformData
*td
, int local
, MonoType
*type
)
742 int mt
= mint_type (type
);
743 MonoClass
*klass
= NULL
;
744 if (mt
== MINT_TYPE_VT
) {
745 klass
= mono_class_from_mono_type_internal (type
);
746 gint32 size
= mono_class_value_size (klass
, NULL
);
748 interp_add_ins (td
, MINT_LDLOC_VT
);
749 td
->last_ins
->data
[0] = local
;
750 WRITE32_INS (td
->last_ins
, 1, &size
);
752 g_assert (mt
< MINT_TYPE_VT
);
753 interp_add_ins (td
, MINT_LDLOC_I1
+ (mt
- MINT_TYPE_I1
));
754 td
->last_ins
->data
[0] = local
;
755 if (mt
== MINT_TYPE_O
)
756 klass
= mono_class_from_mono_type_internal (type
);
758 PUSH_TYPE(td
, stack_type
[mt
], klass
);
762 load_local (TransformData
*td
, int n
)
764 MonoType
*type
= td
->header
->locals
[n
];
765 load_local_general (td
, n
, type
);
769 store_local_general (TransformData
*td
, int local
, MonoType
*type
)
771 int mt
= mint_type (type
);
773 #if SIZEOF_VOID_P == 8
774 if (td
->sp
[-1].type
== STACK_TYPE_I4
&& stack_type
[mt
] == STACK_TYPE_I8
) {
775 interp_add_ins (td
, MINT_CONV_I8_I4
);
776 td
->sp
[-1].type
= STACK_TYPE_I8
;
779 if (!can_store(td
->sp
[-1].type
, stack_type
[mt
])) {
780 g_warning("%s.%s: Store local stack type mismatch %d %d",
781 m_class_get_name (td
->method
->klass
), td
->method
->name
,
782 stack_type
[mt
], td
->sp
[-1].type
);
784 if (mt
== MINT_TYPE_VT
) {
785 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
786 gint32 size
= mono_class_value_size (klass
, NULL
);
787 interp_add_ins (td
, MINT_STLOC_VT
);
788 td
->last_ins
->data
[0] = local
;
789 WRITE32_INS (td
->last_ins
, 1, &size
);
790 if (td
->sp
[-1].type
== STACK_TYPE_VT
)
793 g_assert (mt
< MINT_TYPE_VT
);
794 interp_add_ins (td
, MINT_STLOC_I1
+ (mt
- MINT_TYPE_I1
));
795 td
->last_ins
->data
[0] = local
;
801 store_local (TransformData
*td
, int n
)
803 MonoType
*type
= td
->header
->locals
[n
];
804 store_local_general (td
, n
, type
);
807 #define SIMPLE_OP(td, op) \
809 interp_add_ins (td, op); \
814 get_data_item_index (TransformData
*td
, void *ptr
)
816 gpointer p
= g_hash_table_lookup (td
->data_hash
, ptr
);
819 return GPOINTER_TO_UINT (p
) - 1;
820 if (td
->max_data_items
== td
->n_data_items
) {
821 td
->max_data_items
= td
->n_data_items
== 0 ? 16 : 2 * td
->max_data_items
;
822 td
->data_items
= (gpointer
*)g_realloc (td
->data_items
, td
->max_data_items
* sizeof(td
->data_items
[0]));
824 index
= td
->n_data_items
;
825 td
->data_items
[index
] = ptr
;
827 g_hash_table_insert (td
->data_hash
, ptr
, GUINT_TO_POINTER (index
+ 1));
832 jit_call_supported (MonoMethod
*method
, MonoMethodSignature
*sig
)
836 if (sig
->param_count
> 6)
840 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
842 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
)
844 if (method
->is_inflated
)
846 if (method
->string_ctor
)
849 if (mono_aot_only
&& m_class_get_image (method
->klass
)->aot_module
&& !(method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)) {
851 gpointer addr
= mono_jit_compile_method_jit_only (method
, error
);
852 if (addr
&& is_ok (error
))
856 for (l
= mono_interp_jit_classes
; l
; l
= l
->next
) {
857 const char *class_name
= (const char*)l
->data
;
859 if (!strcmp (m_class_get_name (method
->klass
), class_name
))
867 static int mono_class_get_magic_index (MonoClass
*k
)
869 if (mono_class_is_magic_int (k
))
870 return !strcmp ("nint", m_class_get_name (k
)) ? 0 : 1;
872 if (mono_class_is_magic_float (k
))
879 interp_generate_mae_throw (TransformData
*td
, MonoMethod
*method
, MonoMethod
*target_method
)
881 MonoJitICallInfo
*info
= &mono_get_jit_icall_info ()->mono_throw_method_access
;
883 /* Inject code throwing MethodAccessException */
884 interp_add_ins (td
, MINT_MONO_LDPTR
);
885 td
->last_ins
->data
[0] = get_data_item_index (td
, method
);
886 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
888 interp_add_ins (td
, MINT_MONO_LDPTR
);
889 td
->last_ins
->data
[0] = get_data_item_index (td
, target_method
);
890 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
892 interp_add_ins (td
, MINT_ICALL_PP_V
);
893 td
->last_ins
->data
[0] = get_data_item_index (td
, (gpointer
)info
->func
);
899 interp_generate_bie_throw (TransformData
*td
)
901 MonoJitICallInfo
*info
= &mono_get_jit_icall_info ()->mono_throw_bad_image
;
903 interp_add_ins (td
, MINT_ICALL_V_V
);
904 td
->last_ins
->data
[0] = get_data_item_index (td
, (gpointer
)info
->func
);
908 * These are additional locals that can be allocated as we transform the code.
909 * They are allocated past the method locals so they are accessed in the same
910 * way, with an offset relative to the frame->locals.
913 create_interp_local (TransformData
*td
, MonoType
*type
)
915 if (td
->locals_size
== td
->locals_capacity
) {
916 td
->locals_capacity
*= 2;
917 if (td
->locals_capacity
== 0)
918 td
->locals_capacity
= 2;
919 td
->locals
= (InterpLocal
*) g_realloc (td
->locals
, td
->locals_capacity
* sizeof (InterpLocal
));
921 td
->locals
[td
->locals_size
].type
= type
;
922 td
->locals
[td
->locals_size
].flags
= 0;
923 td
->locals
[td
->locals_size
].offset
= -1;
925 return td
->locals_size
- 1;
929 get_interp_local_offset (TransformData
*td
, int local
)
931 int align
, size
, offset
;
933 if (td
->locals
[local
].offset
!= -1)
934 return td
->locals
[local
].offset
;
936 offset
= td
->total_locals_size
;
937 size
= mono_type_size (td
->locals
[local
].type
, &align
);
938 offset
= ALIGN_TO (offset
, align
);
940 td
->locals
[local
].offset
= offset
;
942 td
->total_locals_size
= offset
+ size
;
943 g_assert (td
->total_locals_size
< G_MAXUINT16
);
949 dump_mint_code (const guint16
*start
, const guint16
* end
)
951 const guint16
*p
= start
;
953 char *ins
= mono_interp_dis_mintop (start
, p
);
954 g_print ("%s\n", ins
);
956 p
= mono_interp_dis_mintop_len (p
);
962 mono_interp_print_code (InterpMethod
*imethod
)
964 MonoJitInfo
*jinfo
= imethod
->jinfo
;
965 const guint16
*start
;
970 char *name
= mono_method_full_name (imethod
->method
, 1);
971 g_print ("Method : %s\n", name
);
974 start
= (guint16
*) jinfo
->code_start
;
975 dump_mint_code (start
, start
+ jinfo
->code_size
);
979 static MonoMethodHeader
*
980 interp_method_get_header (MonoMethod
* method
, MonoError
*error
)
982 /* An explanation: mono_method_get_header_internal returns an error if
983 * called on a method with no body (e.g. an abstract method, or an
984 * icall). We don't want that.
986 if (mono_method_has_no_body (method
))
989 return mono_method_get_header_internal (method
, error
);
992 /* stores top of stack as local and pushes address of it on stack */
994 emit_store_value_as_local (TransformData
*td
, MonoType
*src
)
996 int size
= mini_magic_type_size (NULL
, src
);
997 int local
= create_interp_local (td
, mini_native_type_replace_type (src
));
999 store_local_general (td
, local
, src
);
1001 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
1002 interp_add_ins (td
, MINT_LDLOC_VT
);
1003 td
->last_ins
->data
[0] = local
;
1004 WRITE32_INS (td
->last_ins
, 1, &size
);
1007 PUSH_TYPE (td
, STACK_TYPE_VT
, NULL
);
1010 // Returns whether we can optimize away the instructions starting at start.
1011 // If any instructions are part of a new basic block, we can't remove them.
1013 interp_is_bb_start (TransformData
*td
, InterpInst
*start
, InterpInst
*end
)
1015 InterpInst
*ins
= start
;
1016 while (ins
!= end
) {
1017 if (ins
->il_offset
!= -1) {
1018 if (td
->is_bb_start
[ins
->il_offset
])
1027 interp_ins_is_ldc (InterpInst
*ins
)
1029 return ins
->opcode
>= MINT_LDC_I4_M1
&& ins
->opcode
<= MINT_LDC_I8
;
1033 interp_ldc_i4_get_const (InterpInst
*ins
)
1035 switch (ins
->opcode
) {
1036 case MINT_LDC_I4_M1
: return -1;
1037 case MINT_LDC_I4_0
: return 0;
1038 case MINT_LDC_I4_1
: return 1;
1039 case MINT_LDC_I4_2
: return 2;
1040 case MINT_LDC_I4_3
: return 3;
1041 case MINT_LDC_I4_4
: return 4;
1042 case MINT_LDC_I4_5
: return 5;
1043 case MINT_LDC_I4_6
: return 6;
1044 case MINT_LDC_I4_7
: return 7;
1045 case MINT_LDC_I4_8
: return 8;
1046 case MINT_LDC_I4_S
: return (gint32
)(gint8
)ins
->data
[0];
1047 case MINT_LDC_I4
: return READ32 (&ins
->data
[0]);
1049 g_assert_not_reached ();
1054 interp_get_ldind_for_mt (int mt
)
1057 case MINT_TYPE_I1
: return MINT_LDIND_I1_CHECK
;
1058 case MINT_TYPE_U1
: return MINT_LDIND_U1_CHECK
;
1059 case MINT_TYPE_I2
: return MINT_LDIND_I2_CHECK
;
1060 case MINT_TYPE_U2
: return MINT_LDIND_U2_CHECK
;
1061 case MINT_TYPE_I4
: return MINT_LDIND_I4_CHECK
;
1062 case MINT_TYPE_I8
: return MINT_LDIND_I8_CHECK
;
1063 case MINT_TYPE_R4
: return MINT_LDIND_R4_CHECK
;
1064 case MINT_TYPE_R8
: return MINT_LDIND_R8_CHECK
;
1065 case MINT_TYPE_O
: return MINT_LDIND_REF
;
1067 g_assert_not_reached ();
1073 interp_emit_ldobj (TransformData
*td
, MonoClass
*klass
)
1075 int mt
= mint_type (m_class_get_byval_arg (klass
));
1078 if (mt
== MINT_TYPE_VT
) {
1079 interp_add_ins (td
, MINT_LDOBJ_VT
);
1080 size
= mono_class_value_size (klass
, NULL
);
1081 WRITE32_INS (td
->last_ins
, 0, &size
);
1084 int opcode
= interp_get_ldind_for_mt (mt
);
1085 interp_add_ins (td
, opcode
);
1088 SET_TYPE (td
->sp
- 1, stack_type
[mt
], klass
);
1092 interp_emit_stobj (TransformData
*td
, MonoClass
*klass
)
1094 int mt
= mint_type (m_class_get_byval_arg (klass
));
1096 if (mt
== MINT_TYPE_VT
) {
1098 interp_add_ins (td
, MINT_STOBJ_VT
);
1099 td
->last_ins
->data
[0] = get_data_item_index(td
, klass
);
1100 size
= mono_class_value_size (klass
, NULL
);
1107 opcode
= MINT_STIND_I1
;
1111 opcode
= MINT_STIND_I2
;
1114 opcode
= MINT_STIND_I4
;
1117 opcode
= MINT_STIND_I8
;
1120 opcode
= MINT_STIND_R4
;
1123 opcode
= MINT_STIND_R8
;
1126 opcode
= MINT_STIND_REF
;
1128 default: g_assert_not_reached (); break;
1130 interp_add_ins (td
, opcode
);
1136 interp_emit_ldelema (TransformData
*td
, MonoClass
*array_class
, MonoClass
*check_class
)
1138 MonoClass
*element_class
= m_class_get_element_class (array_class
);
1139 int rank
= m_class_get_rank (array_class
);
1140 int size
= mono_class_array_element_size (element_class
);
1142 // We only need type checks when writing to array of references
1143 if (!check_class
|| m_class_is_valuetype (element_class
)) {
1145 interp_add_ins (td
, MINT_LDELEMA1
);
1146 WRITE32_INS (td
->last_ins
, 0, &size
);
1148 interp_add_ins (td
, MINT_LDELEMA
);
1149 td
->last_ins
->data
[0] = rank
;
1150 WRITE32_INS (td
->last_ins
, 1, &size
);
1153 interp_add_ins (td
, MINT_LDELEMA_TC
);
1154 td
->last_ins
->data
[0] = rank
;
1155 td
->last_ins
->data
[1] = get_data_item_index (td
, check_class
);
1159 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_MP
);
1162 /* Return TRUE if call transformation is finished */
1164 interp_handle_intrinsics (TransformData
*td
, MonoMethod
*target_method
, MonoClass
*constrained_class
, MonoMethodSignature
*csignature
, gboolean readonly
, int *op
)
1166 const char *tm
= target_method
->name
;
1168 int type_index
= mono_class_get_magic_index (target_method
->klass
);
1169 gboolean in_corlib
= m_class_get_image (target_method
->klass
) == mono_defaults
.corlib
;
1170 const char *klass_name_space
= m_class_get_name_space (target_method
->klass
);
1171 const char *klass_name
= m_class_get_name (target_method
->klass
);
1173 if (target_method
->klass
== mono_defaults
.string_class
) {
1174 if (tm
[0] == 'g') {
1175 if (strcmp (tm
, "get_Chars") == 0)
1177 else if (strcmp (tm
, "get_Length") == 0)
1180 } else if (type_index
>= 0) {
1181 MonoClass
*magic_class
= target_method
->klass
;
1183 const int mt
= mint_type (m_class_get_byval_arg (magic_class
));
1184 if (!strcmp (".ctor", tm
)) {
1185 MonoType
*arg
= csignature
->params
[0];
1186 /* depending on SIZEOF_VOID_P and the type of the value passed to the .ctor we either have to CONV it, or do nothing */
1187 int arg_size
= mini_magic_type_size (NULL
, arg
);
1189 if (arg_size
> SIZEOF_VOID_P
) { // 8 -> 4
1190 switch (type_index
) {
1192 interp_add_ins (td
, MINT_CONV_I4_I8
);
1195 interp_add_ins (td
, MINT_CONV_R4_R8
);
1200 if (arg_size
< SIZEOF_VOID_P
) { // 4 -> 8
1201 switch (type_index
) {
1203 interp_add_ins (td
, MINT_CONV_I8_I4
);
1206 interp_add_ins (td
, MINT_CONV_I8_U4
);
1209 interp_add_ins (td
, MINT_CONV_R8_R4
);
1214 switch (type_index
) {
1216 #if SIZEOF_VOID_P == 4
1217 interp_add_ins (td
, MINT_STIND_I4
);
1219 interp_add_ins (td
, MINT_STIND_I8
);
1223 #if SIZEOF_VOID_P == 4
1224 interp_add_ins (td
, MINT_STIND_R4
);
1226 interp_add_ins (td
, MINT_STIND_R8
);
1234 } else if (!strcmp ("op_Implicit", tm
) || !strcmp ("op_Explicit", tm
)) {
1235 MonoType
*src
= csignature
->params
[0];
1236 MonoType
*dst
= csignature
->ret
;
1237 MonoClass
*src_klass
= mono_class_from_mono_type_internal (src
);
1238 int src_size
= mini_magic_type_size (NULL
, src
);
1239 int dst_size
= mini_magic_type_size (NULL
, dst
);
1241 gboolean store_value_as_local
= FALSE
;
1243 switch (type_index
) {
1245 if (!mini_magic_is_int_type (src
) || !mini_magic_is_int_type (dst
)) {
1246 if (mini_magic_is_int_type (src
))
1247 store_value_as_local
= TRUE
;
1248 else if (mono_class_is_magic_float (src_klass
))
1249 store_value_as_local
= TRUE
;
1255 if (!mini_magic_is_float_type (src
) || !mini_magic_is_float_type (dst
)) {
1256 if (mini_magic_is_float_type (src
))
1257 store_value_as_local
= TRUE
;
1258 else if (mono_class_is_magic_int (src_klass
))
1259 store_value_as_local
= TRUE
;
1266 if (store_value_as_local
) {
1267 emit_store_value_as_local (td
, src
);
1269 /* emit call to managed conversion method */
1273 if (src_size
> dst_size
) { // 8 -> 4
1274 switch (type_index
) {
1276 interp_add_ins (td
, MINT_CONV_I4_I8
);
1279 interp_add_ins (td
, MINT_CONV_R4_R8
);
1284 if (src_size
< dst_size
) { // 4 -> 8
1285 switch (type_index
) {
1287 interp_add_ins (td
, MINT_CONV_I8_I4
);
1290 interp_add_ins (td
, MINT_CONV_I8_U4
);
1293 interp_add_ins (td
, MINT_CONV_R8_R4
);
1298 SET_TYPE (td
->sp
- 1, stack_type
[mint_type (dst
)], mono_class_from_mono_type_internal (dst
));
1301 } else if (!strcmp ("op_Increment", tm
)) {
1302 g_assert (type_index
!= 2); // no nfloat
1303 #if SIZEOF_VOID_P == 8
1304 interp_add_ins (td
, MINT_ADD1_I8
);
1306 interp_add_ins (td
, MINT_ADD1_I4
);
1308 SET_TYPE (td
->sp
- 1, stack_type
[mt
], magic_class
);
1311 } else if (!strcmp ("op_Decrement", tm
)) {
1312 g_assert (type_index
!= 2); // no nfloat
1313 #if SIZEOF_VOID_P == 8
1314 interp_add_ins (td
, MINT_SUB1_I8
);
1316 interp_add_ins (td
, MINT_SUB1_I4
);
1318 SET_TYPE (td
->sp
- 1, stack_type
[mt
], magic_class
);
1321 } else if (!strcmp ("CompareTo", tm
) || !strcmp ("Equals", tm
)) {
1322 MonoType
*arg
= csignature
->params
[0];
1324 /* on 'System.n*::{CompareTo,Equals} (System.n*)' variant we need to push managed
1325 * pointer instead of value */
1326 if (arg
->type
== MONO_TYPE_VALUETYPE
)
1327 emit_store_value_as_local (td
, arg
);
1329 /* emit call to managed conversion method */
1331 } else if (!strcmp (".cctor", tm
)) {
1334 } else if (!strcmp ("Parse", tm
)) {
1337 } else if (!strcmp ("ToString", tm
)) {
1340 } else if (!strcmp ("GetHashCode", tm
)) {
1343 } else if (!strcmp ("IsNaN", tm
) || !strcmp ("IsInfinity", tm
) || !strcmp ("IsNegativeInfinity", tm
) || !strcmp ("IsPositiveInfinity", tm
)) {
1344 g_assert (type_index
== 2); // nfloat only
1349 for (i
= 0; i
< sizeof (int_unnop
) / sizeof (MagicIntrinsic
); ++i
) {
1350 if (!strcmp (int_unnop
[i
].op_name
, tm
)) {
1351 interp_add_ins (td
, int_unnop
[i
].insn
[type_index
]);
1352 SET_TYPE (td
->sp
- 1, stack_type
[mt
], magic_class
);
1358 for (i
= 0; i
< sizeof (int_binop
) / sizeof (MagicIntrinsic
); ++i
) {
1359 if (!strcmp (int_binop
[i
].op_name
, tm
)) {
1360 interp_add_ins (td
, int_binop
[i
].insn
[type_index
]);
1362 SET_TYPE (td
->sp
- 1, stack_type
[mt
], magic_class
);
1368 for (i
= 0; i
< sizeof (int_cmpop
) / sizeof (MagicIntrinsic
); ++i
) {
1369 if (!strcmp (int_cmpop
[i
].op_name
, tm
)) {
1370 MonoClass
*k
= mono_defaults
.boolean_class
;
1371 interp_add_ins (td
, int_cmpop
[i
].insn
[type_index
]);
1373 SET_TYPE (td
->sp
- 1, stack_type
[mint_type (m_class_get_byval_arg (k
))], k
);
1379 g_error ("TODO: interp_transform_call %s:%s", m_class_get_name (target_method
->klass
), tm
);
1380 } else if (mono_class_is_subclass_of_internal (target_method
->klass
, mono_defaults
.array_class
, FALSE
)) {
1381 if (!strcmp (tm
, "get_Rank")) {
1382 *op
= MINT_ARRAY_RANK
;
1383 } else if (!strcmp (tm
, "get_Length")) {
1385 } else if (!strcmp (tm
, "Address")) {
1386 MonoClass
*check_class
= readonly
? NULL
: m_class_get_element_class (target_method
->klass
);
1387 interp_emit_ldelema (td
, target_method
->klass
, check_class
);
1390 } else if (!strcmp (tm
, "UnsafeMov") || !strcmp (tm
, "UnsafeLoad")) {
1392 } else if (!strcmp (tm
, "Get")) {
1393 interp_emit_ldelema (td
, target_method
->klass
, NULL
);
1394 interp_emit_ldobj (td
, m_class_get_element_class (target_method
->klass
));
1397 } else if (!strcmp (tm
, "Set")) {
1398 MonoClass
*element_class
= m_class_get_element_class (target_method
->klass
);
1399 MonoType
*local_type
= m_class_get_byval_arg (element_class
);
1400 MonoClass
*value_class
= td
->sp
[-1].klass
;
1401 // If value_class is NULL it means the top of stack is a simple type (valuetype)
1402 // which doesn't require type checks, or that we have no type information because
1403 // the code is unsafe (like in some wrappers). In that case we assume the type
1404 // of the array and don't do any checks.
1406 int local
= create_interp_local (td
, local_type
);
1408 store_local_general (td
, local
, local_type
);
1409 interp_emit_ldelema (td
, target_method
->klass
, value_class
);
1410 load_local_general (td
, local
, local_type
);
1411 interp_emit_stobj (td
, element_class
);
1414 } else if (!strcmp (tm
, "UnsafeStore")) {
1415 g_error ("TODO ArrayClass::UnsafeStore");
1417 } else if (in_corlib
&&
1418 !strcmp (klass_name_space
, "System.Diagnostics") &&
1419 !strcmp (klass_name
, "Debugger")) {
1420 if (!strcmp (tm
, "Break") && csignature
->param_count
== 0) {
1421 if (mini_should_insert_breakpoint (td
->method
))
1424 } else if (in_corlib
&& !strcmp (klass_name_space
, "System") && !strcmp (klass_name
, "ByReference`1")) {
1425 g_assert (!strcmp (tm
, "get_Value"));
1426 *op
= MINT_INTRINS_BYREFERENCE_GET_VALUE
;
1427 } else if (in_corlib
&& !strcmp (klass_name_space
, "System") && !strcmp (klass_name
, "Math") && csignature
->param_count
== 1 && csignature
->params
[0]->type
== MONO_TYPE_R8
) {
1428 if (tm
[0] == 'A') {
1429 if (strcmp (tm
, "Abs") == 0 && csignature
->params
[0]->type
== MONO_TYPE_R8
) {
1431 } else if (strcmp (tm
, "Asin") == 0){
1433 } else if (strcmp (tm
, "Asinh") == 0){
1435 } else if (strcmp (tm
, "Acos") == 0){
1437 } else if (strcmp (tm
, "Acosh") == 0){
1439 } else if (strcmp (tm
, "Atan") == 0){
1441 } else if (strcmp (tm
, "Atanh") == 0){
1444 } else if (tm
[0] == 'C') {
1445 if (strcmp (tm
, "Cos") == 0) {
1447 } else if (strcmp (tm
, "Cbrt") == 0){
1449 } else if (strcmp (tm
, "Cosh") == 0){
1452 } else if (tm
[0] == 'S') {
1453 if (strcmp (tm
, "Sin") == 0) {
1455 } else if (strcmp (tm
, "Sqrt") == 0) {
1457 } else if (strcmp (tm
, "Sinh") == 0){
1460 } else if (tm
[0] == 'T') {
1461 if (strcmp (tm
, "Tan") == 0) {
1463 } else if (strcmp (tm
, "Tanh") == 0){
1467 } else if (in_corlib
&& !strcmp (klass_name_space
, "System") && (!strcmp (klass_name
, "Span`1") || !strcmp (klass_name
, "ReadOnlySpan`1"))) {
1468 if (!strcmp (tm
, "get_Item")) {
1469 MonoGenericClass
*gclass
= mono_class_get_generic_class (target_method
->klass
);
1470 MonoClass
*param_class
= mono_class_from_mono_type_internal (gclass
->context
.class_inst
->type_argv
[0]);
1472 if (!mini_is_gsharedvt_variable_klass (param_class
)) {
1473 MonoClassField
*length_field
= mono_class_get_field_from_name_full (target_method
->klass
, "_length", NULL
);
1474 g_assert (length_field
);
1475 int offset_length
= length_field
->offset
- sizeof (MonoObject
);
1477 MonoClassField
*ptr_field
= mono_class_get_field_from_name_full (target_method
->klass
, "_pointer", NULL
);
1478 g_assert (ptr_field
);
1479 int offset_pointer
= ptr_field
->offset
- sizeof (MonoObject
);
1481 int size
= mono_class_array_element_size (param_class
);
1482 interp_add_ins (td
, MINT_GETITEM_SPAN
);
1483 td
->last_ins
->data
[0] = size
;
1484 td
->last_ins
->data
[1] = offset_length
;
1485 td
->last_ins
->data
[2] = offset_pointer
;
1487 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_MP
);
1492 } else if (!strcmp (tm
, "get_Length")) {
1493 MonoClassField
*length_field
= mono_class_get_field_from_name_full (target_method
->klass
, "_length", NULL
);
1494 g_assert (length_field
);
1495 int offset_length
= length_field
->offset
- sizeof (MonoObject
);
1496 interp_add_ins (td
, MINT_LDLEN_SPAN
);
1497 td
->last_ins
->data
[0] = offset_length
;
1498 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I4
);
1502 } else if (in_corlib
&& !strcmp (klass_name_space
, "Internal.Runtime.CompilerServices") && !strcmp (klass_name
, "Unsafe")) {
1503 #ifdef ENABLE_NETCORE
1504 if (!strcmp (tm
, "AddByteOffset"))
1505 *op
= MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET
;
1506 else if (!strcmp (tm
, "ByteOffset"))
1507 *op
= MINT_INTRINS_UNSAFE_BYTE_OFFSET
;
1508 else if (!strcmp (tm
, "As") || !strcmp (tm
, "AsRef"))
1510 else if (!strcmp (tm
, "AsPointer")) {
1512 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_MP
);
1515 } else if (!strcmp (tm
, "IsAddressLessThan")) {
1516 MonoGenericContext
*ctx
= mono_method_get_context (target_method
);
1518 g_assert (ctx
->method_inst
);
1519 g_assert (ctx
->method_inst
->type_argc
== 1);
1521 MonoClass
*k
= mono_defaults
.boolean_class
;
1522 interp_add_ins (td
, MINT_CLT_UN_P
);
1524 SET_TYPE (td
->sp
- 1, stack_type
[mint_type (m_class_get_byval_arg (k
))], k
);
1527 } else if (!strcmp (tm
, "SizeOf")) {
1528 MonoGenericContext
*ctx
= mono_method_get_context (target_method
);
1530 g_assert (ctx
->method_inst
);
1531 g_assert (ctx
->method_inst
->type_argc
== 1);
1532 MonoType
*t
= ctx
->method_inst
->type_argv
[0];
1534 int esize
= mono_type_size (t
, &align
);
1535 interp_add_ins (td
, MINT_LDC_I4
);
1536 WRITE32_INS (td
->last_ins
, 0, &esize
);
1537 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I4
);
1540 } else if (!strcmp (tm
, "AreSame")) {
1544 } else if (in_corlib
&& !strcmp (klass_name_space
, "System.Runtime.CompilerServices") && !strcmp (klass_name
, "RuntimeHelpers")) {
1545 #ifdef ENABLE_NETCORE
1546 if (!strcmp (tm
, "IsBitwiseEquatable")) {
1547 g_assert (csignature
->param_count
== 0);
1548 MonoGenericContext
*ctx
= mono_method_get_context (target_method
);
1550 g_assert (ctx
->method_inst
);
1551 g_assert (ctx
->method_inst
->type_argc
== 1);
1552 MonoType
*t
= mini_get_underlying_type (ctx
->method_inst
->type_argv
[0]);
1554 if (MONO_TYPE_IS_PRIMITIVE (t
) && t
->type
!= MONO_TYPE_R4
&& t
->type
!= MONO_TYPE_R8
)
1555 *op
= MINT_LDC_I4_1
;
1557 *op
= MINT_LDC_I4_0
;
1558 } else if (!strcmp (tm
, "ObjectHasComponentSize")) {
1559 *op
= MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE
;
1562 } else if (in_corlib
&& !strcmp (klass_name_space
, "System") && !strcmp (klass_name
, "RuntimeMethodHandle") && !strcmp (tm
, "GetFunctionPointer") && csignature
->param_count
== 1) {
1563 // We must intrinsify this method on interp so we don't return a pointer to native code entering interpreter
1564 *op
= MINT_LDFTN_DYNAMIC
;
1565 } else if (in_corlib
&& target_method
->klass
== mono_defaults
.object_class
) {
1566 if (!strcmp (tm
, "InternalGetHashCode"))
1567 *op
= MINT_INTRINS_GET_HASHCODE
;
1568 #ifdef DISABLE_REMOTING
1569 else if (!strcmp (tm
, "GetType"))
1570 *op
= MINT_INTRINS_GET_TYPE
;
1572 #ifdef ENABLE_NETCORE
1573 else if (!strcmp (tm
, "GetRawData")) {
1574 #if SIZEOF_VOID_P == 8
1575 interp_add_ins (td
, MINT_LDC_I8_S
);
1577 interp_add_ins (td
, MINT_LDC_I4_S
);
1579 td
->last_ins
->data
[0] = (gint16
) MONO_ABI_SIZEOF (MonoObject
);
1581 interp_add_ins (td
, MINT_ADD_P
);
1582 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_MP
);
1588 } else if (in_corlib
&& target_method
->klass
== mono_defaults
.enum_class
&& !strcmp (tm
, "HasFlag")) {
1589 gboolean intrinsify
= FALSE
;
1590 MonoClass
*base_klass
= NULL
;
1591 if (td
->last_ins
&& td
->last_ins
->opcode
== MINT_BOX
&&
1592 td
->last_ins
->prev
&& interp_ins_is_ldc (td
->last_ins
->prev
) &&
1593 td
->last_ins
->prev
->prev
&& td
->last_ins
->prev
->prev
->opcode
== MINT_BOX
&&
1594 td
->sp
[-2].klass
== td
->sp
[-1].klass
&&
1595 !interp_is_bb_start (td
, td
->last_ins
->prev
->prev
, NULL
) &&
1596 !td
->is_bb_start
[td
->in_start
- td
->il_code
]) {
1597 // csc pattern : box, ldc, box, call HasFlag
1598 g_assert (m_class_is_enumtype (td
->sp
[-2].klass
));
1599 MonoType
*base_type
= mono_type_get_underlying_type (m_class_get_byval_arg (td
->sp
[-2].klass
));
1600 base_klass
= mono_class_from_mono_type_internal (base_type
);
1602 // Remove the boxing of valuetypes
1603 interp_clear_ins (td
, td
->last_ins
->prev
->prev
);
1604 interp_clear_ins (td
, td
->last_ins
);
1607 } else if (td
->last_ins
&& td
->last_ins
->opcode
== MINT_BOX
&&
1608 td
->last_ins
->prev
&& interp_ins_is_ldc (td
->last_ins
->prev
) &&
1609 constrained_class
&& td
->sp
[-1].klass
== constrained_class
&&
1610 !interp_is_bb_start (td
, td
->last_ins
->prev
, NULL
) &&
1611 !td
->is_bb_start
[td
->in_start
- td
->il_code
]) {
1612 // mcs pattern : ldc, box, constrained Enum, call HasFlag
1613 g_assert (m_class_is_enumtype (constrained_class
));
1614 MonoType
*base_type
= mono_type_get_underlying_type (m_class_get_byval_arg (constrained_class
));
1615 base_klass
= mono_class_from_mono_type_internal (base_type
);
1616 int mt
= mint_type (m_class_get_byval_arg (base_klass
));
1618 // Remove boxing and load the value of this
1619 interp_clear_ins (td
, td
->last_ins
);
1620 interp_insert_ins (td
, td
->last_ins
->prev
->prev
, interp_get_ldind_for_mt (mt
));
1625 interp_add_ins (td
, MINT_INTRINS_ENUM_HASFLAG
);
1626 td
->last_ins
->data
[0] = get_data_item_index (td
, base_klass
);
1628 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I4
);
1632 } else if (in_corlib
&& !strcmp (klass_name_space
, "System.Threading") && !strcmp (klass_name
, "Interlocked")) {
1634 if (!strcmp (tm
, "MemoryBarrier") && csignature
->param_count
== 0)
1635 *op
= MINT_MONO_MEMORY_BARRIER
;
1637 } else if (in_corlib
&&
1638 !strcmp (klass_name_space
, "System.Runtime.CompilerServices") &&
1639 !strcmp (klass_name
, "JitHelpers") &&
1640 (!strcmp (tm
, "EnumEquals") || !strcmp (tm
, "EnumCompareTo"))) {
1641 MonoGenericContext
*ctx
= mono_method_get_context (target_method
);
1643 g_assert (ctx
->method_inst
);
1644 g_assert (ctx
->method_inst
->type_argc
== 1);
1645 g_assert (csignature
->param_count
== 2);
1647 MonoType
*t
= ctx
->method_inst
->type_argv
[0];
1648 t
= mini_get_underlying_type (t
);
1650 gboolean is_i8
= (t
->type
== MONO_TYPE_I8
|| t
->type
== MONO_TYPE_U8
);
1651 gboolean is_unsigned
= (t
->type
== MONO_TYPE_U1
|| t
->type
== MONO_TYPE_U2
|| t
->type
== MONO_TYPE_U4
|| t
->type
== MONO_TYPE_U8
|| t
->type
== MONO_TYPE_U
);
1653 gboolean is_compareto
= strcmp (tm
, "EnumCompareTo") == 0;
1656 locala
= create_interp_local (td
, t
);
1657 localb
= create_interp_local (td
, t
);
1660 store_local_general (td
, localb
, t
);
1661 store_local_general (td
, locala
, t
);
1663 load_local_general (td
, locala
, t
);
1664 load_local_general (td
, localb
, t
);
1666 interp_add_ins (td
, is_i8
? MINT_CGT_UN_I8
: MINT_CGT_UN_I4
);
1668 interp_add_ins (td
, is_i8
? MINT_CGT_I8
: MINT_CGT_I4
);
1670 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I4
);
1672 load_local_general (td
, locala
, t
);
1673 load_local_general (td
, localb
, t
);
1675 interp_add_ins (td
, is_i8
? MINT_CLT_UN_I8
: MINT_CLT_UN_I4
);
1677 interp_add_ins (td
, is_i8
? MINT_CLT_I8
: MINT_CLT_I4
);
1679 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I4
);
1680 // (a > b) - (a < b)
1681 interp_add_ins (td
, MINT_SUB_I4
);
1698 interp_transform_internal_calls (MonoMethod
*method
, MonoMethod
*target_method
, MonoMethodSignature
*csignature
, gboolean is_virtual
)
1700 if (method
->wrapper_type
== MONO_WRAPPER_NONE
&& target_method
!= NULL
) {
1701 if (target_method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
1702 target_method
= mono_marshal_get_native_wrapper (target_method
, FALSE
, FALSE
);
1703 if (!is_virtual
&& target_method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)
1704 target_method
= mono_marshal_get_synchronized_wrapper (target_method
);
1706 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)
1707 target_method
= mono_marshal_get_native_wrapper (target_method
, FALSE
, FALSE
);
1709 return target_method
;
1713 interp_type_as_ptr (MonoType
*tp
)
1715 if (MONO_TYPE_IS_POINTER (tp
))
1717 if (MONO_TYPE_IS_REFERENCE (tp
))
1719 if ((tp
)->type
== MONO_TYPE_I4
)
1721 #if SIZEOF_VOID_P == 8
1722 if ((tp
)->type
== MONO_TYPE_I8
)
1725 if ((tp
)->type
== MONO_TYPE_BOOLEAN
)
1727 if ((tp
)->type
== MONO_TYPE_CHAR
)
1729 if ((tp
)->type
== MONO_TYPE_VALUETYPE
&& m_class_is_enumtype (tp
->data
.klass
))
1734 #define INTERP_TYPE_AS_PTR(tp) interp_type_as_ptr (tp)
1737 interp_icall_op_for_sig (MonoMethodSignature
*sig
)
1740 switch (sig
->param_count
) {
1742 if (MONO_TYPE_IS_VOID (sig
->ret
))
1743 op
= MINT_ICALL_V_V
;
1744 else if (INTERP_TYPE_AS_PTR (sig
->ret
))
1745 op
= MINT_ICALL_V_P
;
1748 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1749 if (INTERP_TYPE_AS_PTR (sig
->params
[0]))
1750 op
= MINT_ICALL_P_V
;
1751 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1752 if (INTERP_TYPE_AS_PTR (sig
->params
[0]))
1753 op
= MINT_ICALL_P_P
;
1757 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1758 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1759 INTERP_TYPE_AS_PTR (sig
->params
[1]))
1760 op
= MINT_ICALL_PP_V
;
1761 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1762 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1763 INTERP_TYPE_AS_PTR (sig
->params
[1]))
1764 op
= MINT_ICALL_PP_P
;
1768 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1769 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1770 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1771 INTERP_TYPE_AS_PTR (sig
->params
[2]))
1772 op
= MINT_ICALL_PPP_V
;
1773 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1774 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1775 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1776 INTERP_TYPE_AS_PTR (sig
->params
[2]))
1777 op
= MINT_ICALL_PPP_P
;
1781 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1782 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1783 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1784 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1785 INTERP_TYPE_AS_PTR (sig
->params
[3]))
1786 op
= MINT_ICALL_PPPP_V
;
1787 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1788 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1789 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1790 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1791 INTERP_TYPE_AS_PTR (sig
->params
[3]))
1792 op
= MINT_ICALL_PPPP_P
;
1796 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1797 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1798 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1799 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1800 INTERP_TYPE_AS_PTR (sig
->params
[3]) &&
1801 INTERP_TYPE_AS_PTR (sig
->params
[4]))
1802 op
= MINT_ICALL_PPPPP_V
;
1803 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1804 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1805 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1806 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1807 INTERP_TYPE_AS_PTR (sig
->params
[3]) &&
1808 INTERP_TYPE_AS_PTR (sig
->params
[4]))
1809 op
= MINT_ICALL_PPPPP_P
;
1813 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1814 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1815 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1816 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1817 INTERP_TYPE_AS_PTR (sig
->params
[3]) &&
1818 INTERP_TYPE_AS_PTR (sig
->params
[4]) &&
1819 INTERP_TYPE_AS_PTR (sig
->params
[5]))
1820 op
= MINT_ICALL_PPPPPP_V
;
1821 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1822 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1823 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1824 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1825 INTERP_TYPE_AS_PTR (sig
->params
[3]) &&
1826 INTERP_TYPE_AS_PTR (sig
->params
[4]) &&
1827 INTERP_TYPE_AS_PTR (sig
->params
[5]))
1828 op
= MINT_ICALL_PPPPPP_P
;
1835 #define INLINE_LENGTH_LIMIT 20
1838 interp_method_check_inlining (TransformData
*td
, MonoMethod
*method
)
1840 MonoMethodHeaderSummary header
;
1842 if (td
->method
== method
)
1845 if (!mono_method_get_header_summary (method
, &header
))
1848 /*runtime, icall and pinvoke are checked by summary call*/
1849 if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_NOINLINING
) ||
1850 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) ||
1851 (mono_class_is_marshalbyref (method
->klass
)) ||
1855 if (header
.code_size
>= INLINE_LENGTH_LIMIT
)
1858 if (mono_class_needs_cctor_run (method
->klass
, NULL
)) {
1861 if (!m_class_get_runtime_info (method
->klass
))
1862 /* No vtable created yet */
1864 vtable
= mono_class_vtable_checked (td
->rtm
->domain
, method
->klass
, error
);
1865 if (!is_ok (error
)) {
1866 mono_error_cleanup (error
);
1869 if (!vtable
->initialized
)
1873 /* We currently access at runtime the wrapper data */
1874 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
1877 /* Our usage of `emit_store_value_as_local ()` for nint, nuint and nfloat
1878 * is kinda hacky, and doesn't work with the inliner */
1879 if (mono_class_get_magic_index (method
->klass
) >= 0)
1886 interp_inline_method (TransformData
*td
, MonoMethod
*target_method
, MonoMethodHeader
*header
, MonoError
*error
)
1888 const unsigned char *prev_ip
, *prev_il_code
, *prev_in_start
;
1889 int *prev_in_offsets
;
1891 unsigned int prev_max_stack_height
, prev_max_vt_sp
, prev_locals_size
;
1892 int prev_n_data_items
;
1895 MonoGenericContext
*generic_context
= NULL
;
1896 StackInfo
*prev_param_area
;
1897 MonoMethod
*prev_inlined_method
;
1898 MonoMethodSignature
*csignature
= mono_method_signature_internal (target_method
);
1899 int nargs
= csignature
->param_count
+ !!csignature
->hasthis
;
1900 InterpInst
*prev_last_ins
;
1902 if (csignature
->is_inflated
)
1903 generic_context
= mono_method_get_context (target_method
);
1905 MonoGenericContainer
*generic_container
= mono_method_get_generic_container (target_method
);
1906 if (generic_container
)
1907 generic_context
= &generic_container
->context
;
1911 prev_il_code
= td
->il_code
;
1912 prev_in_start
= td
->in_start
;
1913 prev_sp_offset
= td
->sp
- td
->stack
;
1914 prev_vt_sp
= td
->vt_sp
;
1915 prev_inlined_method
= td
->inlined_method
;
1916 prev_last_ins
= td
->last_ins
;
1917 td
->inlined_method
= target_method
;
1919 prev_max_stack_height
= td
->max_stack_height
;
1920 prev_max_vt_sp
= td
->max_vt_sp
;
1921 prev_locals_size
= td
->locals_size
;
1923 prev_n_data_items
= td
->n_data_items
;
1924 prev_in_offsets
= td
->in_offsets
;
1925 td
->in_offsets
= (int*)g_malloc0((header
->code_size
+ 1) * sizeof(int));
1927 /* Inlining pops the arguments, restore the stack */
1928 prev_param_area
= (StackInfo
*)g_malloc (nargs
* sizeof (StackInfo
));
1929 memcpy (prev_param_area
, &td
->sp
[-nargs
], nargs
* sizeof (StackInfo
));
1931 int const prev_code_size
= td
->code_size
;
1932 td
->code_size
= header
->code_size
;
1934 if (td
->verbose_level
)
1935 g_print ("Inline start method %s.%s\n", m_class_get_name (target_method
->klass
), target_method
->name
);
1936 ret
= generate_code (td
, target_method
, header
, generic_context
, error
);
1939 if (td
->verbose_level
)
1940 g_print ("Inline aborted method %s.%s\n", m_class_get_name (target_method
->klass
), target_method
->name
);
1941 td
->max_stack_height
= prev_max_stack_height
;
1942 td
->max_vt_sp
= prev_max_vt_sp
;
1943 td
->locals_size
= prev_locals_size
;
1946 /* Remove any newly added items */
1947 for (i
= prev_n_data_items
; i
< td
->n_data_items
; i
++) {
1948 g_hash_table_remove (td
->data_hash
, td
->data_items
[i
]);
1950 td
->n_data_items
= prev_n_data_items
;
1951 td
->sp
= td
->stack
+ prev_sp_offset
;
1952 memcpy (&td
->sp
[-nargs
], prev_param_area
, nargs
* sizeof (StackInfo
));
1953 td
->vt_sp
= prev_vt_sp
;
1954 td
->last_ins
= prev_last_ins
;
1956 td
->last_ins
->next
= NULL
;
1957 UnlockedIncrement (&mono_interp_stats
.inline_failures
);
1959 if (td
->verbose_level
)
1960 g_print ("Inline end method %s.%s\n", m_class_get_name (target_method
->klass
), target_method
->name
);
1961 UnlockedIncrement (&mono_interp_stats
.inlined_methods
);
1962 // Make sure we have an IR instruction associated with the now removed IL CALL
1963 // FIXME This could be prettier. We might be able to make inlining saner now that
1964 // that we can easily tweak the instruction list.
1965 if (!prev_inlined_method
) {
1966 if (prev_last_ins
) {
1967 if (prev_last_ins
->next
)
1968 prev_last_ins
->next
->il_offset
= prev_in_start
- prev_il_code
;
1969 } else if (td
->first_ins
) {
1970 td
->first_ins
->il_offset
= prev_in_start
- prev_il_code
;
1976 td
->in_start
= prev_in_start
;
1977 td
->il_code
= prev_il_code
;
1978 td
->inlined_method
= prev_inlined_method
;
1979 td
->code_size
= prev_code_size
;
1981 g_free (td
->in_offsets
);
1982 td
->in_offsets
= prev_in_offsets
;
1984 g_free (prev_param_area
);
1989 interp_constrained_box (TransformData
*td
, MonoDomain
*domain
, MonoClass
*constrained_class
, MonoMethodSignature
*csignature
, MonoError
*error
)
1991 int mt
= mint_type (m_class_get_byval_arg (constrained_class
));
1992 if (mono_class_is_nullable (constrained_class
)) {
1993 g_assert (mt
== MINT_TYPE_VT
);
1994 interp_add_ins (td
, MINT_BOX_NULLABLE
);
1995 td
->last_ins
->data
[0] = get_data_item_index (td
, constrained_class
);
1996 td
->last_ins
->data
[1] = csignature
->param_count
| ((td
->sp
- 1 - csignature
->param_count
)->type
!= STACK_TYPE_MP
? 0 : BOX_NOT_CLEAR_VT_SP
);
1998 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, constrained_class
, error
);
1999 return_if_nok (error
);
2001 if (mt
== MINT_TYPE_VT
) {
2002 interp_add_ins (td
, MINT_BOX_VT
);
2003 td
->last_ins
->data
[0] = get_data_item_index (td
, vtable
);
2004 td
->last_ins
->data
[1] = csignature
->param_count
| ((td
->sp
- 1 - csignature
->param_count
)->type
!= STACK_TYPE_MP
? 0 : BOX_NOT_CLEAR_VT_SP
);
2006 interp_add_ins (td
, MINT_BOX
);
2007 td
->last_ins
->data
[0] = get_data_item_index (td
, vtable
);
2008 td
->last_ins
->data
[1] = csignature
->param_count
;
2013 /* Return FALSE if error, including inline failure */
2015 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
, gboolean save_last_error
)
2017 MonoImage
*image
= m_class_get_image (method
->klass
);
2018 MonoMethodSignature
*csignature
;
2019 int is_virtual
= *td
->ip
== CEE_CALLVIRT
;
2020 int calli
= *td
->ip
== CEE_CALLI
|| *td
->ip
== CEE_MONO_CALLI_EXTRA_ARG
;
2022 guint32 vt_stack_used
= 0;
2023 guint32 vt_res_size
= 0;
2027 int need_null_check
= is_virtual
;
2029 guint32 token
= read32 (td
->ip
+ 1);
2031 if (target_method
== NULL
) {
2034 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
2035 csignature
= (MonoMethodSignature
*)mono_method_get_wrapper_data (method
, token
);
2037 csignature
= mono_metadata_parse_signature_checked (image
, token
, error
);
2038 return_val_if_nok (error
, FALSE
);
2041 if (generic_context
) {
2042 csignature
= mono_inflate_generic_signature (csignature
, generic_context
, error
);
2043 return_val_if_nok (error
, FALSE
);
2047 * The compiled interp entry wrapper is passed to runtime_invoke instead of
2048 * the InterpMethod pointer. FIXME
2050 native
= csignature
->pinvoke
|| method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
;
2052 target_method
= NULL
;
2054 if (method
->wrapper_type
== MONO_WRAPPER_NONE
) {
2055 target_method
= mono_get_method_checked (image
, token
, NULL
, generic_context
, error
);
2056 return_val_if_nok (error
, FALSE
);
2058 target_method
= (MonoMethod
*)mono_method_get_wrapper_data (method
, token
);
2059 csignature
= mono_method_signature_internal (target_method
);
2061 if (generic_context
) {
2062 csignature
= mono_inflate_generic_signature (csignature
, generic_context
, error
);
2063 return_val_if_nok (error
, FALSE
);
2064 target_method
= mono_class_inflate_generic_method_checked (target_method
, generic_context
, error
);
2065 return_val_if_nok (error
, FALSE
);
2069 csignature
= mono_method_signature_internal (target_method
);
2072 if (check_visibility
&& target_method
&& !mono_method_can_access_method (method
, target_method
))
2073 interp_generate_mae_throw (td
, method
, target_method
);
2075 if (target_method
&& target_method
->string_ctor
) {
2076 /* Create the real signature */
2077 MonoMethodSignature
*ctor_sig
= mono_metadata_signature_dup_mempool (td
->mempool
, csignature
);
2078 ctor_sig
->ret
= m_class_get_byval_arg (mono_defaults
.string_class
);
2080 csignature
= ctor_sig
;
2084 if (target_method
&& interp_handle_intrinsics (td
, target_method
, constrained_class
, csignature
, readonly
, &op
))
2087 if (constrained_class
) {
2088 if (m_class_is_enumtype (constrained_class
) && !strcmp (target_method
->name
, "GetHashCode")) {
2089 /* Use the corresponding method from the base type to avoid boxing */
2090 MonoType
*base_type
= mono_class_enum_basetype_internal (constrained_class
);
2091 g_assert (base_type
);
2092 constrained_class
= mono_class_from_mono_type_internal (base_type
);
2093 target_method
= mono_class_get_method_from_name_checked (constrained_class
, target_method
->name
, 0, 0, error
);
2094 mono_error_assert_ok (error
);
2095 g_assert (target_method
);
2099 if (constrained_class
) {
2100 mono_class_setup_vtable (constrained_class
);
2101 if (mono_class_has_failure (constrained_class
)) {
2102 mono_error_set_for_class_failure (error
, constrained_class
);
2106 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
);
2108 target_method
= mono_get_method_constrained_with_method (image
, target_method
, constrained_class
, generic_context
, error
);
2110 g_print (" : %s::%s. %s (%p)\n", target_method
->klass
->name
, target_method
->name
, mono_signature_full_name (target_method
->signature
), target_method
);
2112 /* Intrinsics: Try again, it could be that `mono_get_method_constrained_with_method` resolves to a method that we can substitute */
2113 if (target_method
&& interp_handle_intrinsics (td
, target_method
, constrained_class
, csignature
, readonly
, &op
))
2116 return_val_if_nok (error
, FALSE
);
2117 mono_class_setup_vtable (target_method
->klass
);
2119 if (!m_class_is_valuetype (constrained_class
)) {
2120 /* managed pointer on the stack, we need to deref that puppy */
2121 interp_add_ins (td
, MINT_LDIND_I
);
2122 td
->last_ins
->data
[0] = csignature
->param_count
;
2123 } 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
) {
2124 if (target_method
->klass
== mono_defaults
.enum_class
&& (td
->sp
- csignature
->param_count
- 1)->type
== STACK_TYPE_MP
) {
2125 /* managed pointer on the stack, we need to deref that puppy */
2126 /* Always load the entire stackval, to handle also the case where the enum has long storage */
2127 interp_add_ins (td
, MINT_LDIND_I8
);
2128 td
->last_ins
->data
[0] = csignature
->param_count
;
2131 interp_constrained_box (td
, domain
, constrained_class
, csignature
, error
);
2132 return_val_if_nok (error
, FALSE
);
2134 if (target_method
->klass
!= constrained_class
) {
2136 * The type parameter is instantiated as a valuetype,
2137 * but that type doesn't override the method we're
2138 * calling, so we need to box `this'.
2140 if (target_method
->klass
== mono_defaults
.enum_class
&& (td
->sp
- csignature
->param_count
- 1)->type
== STACK_TYPE_MP
) {
2141 /* managed pointer on the stack, we need to deref that puppy */
2142 /* Always load the entire stackval, to handle also the case where the enum has long storage */
2143 interp_add_ins (td
, MINT_LDIND_I8
);
2144 td
->last_ins
->data
[0] = csignature
->param_count
;
2147 interp_constrained_box (td
, domain
, constrained_class
, csignature
, error
);
2148 return_val_if_nok (error
, FALSE
);
2155 mono_class_init_internal (target_method
->klass
);
2157 if (!is_virtual
&& target_method
&& (target_method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
)) {
2158 if (!mono_class_is_interface (method
->klass
))
2159 interp_generate_bie_throw (td
);
2164 if (is_virtual
&& target_method
&& (!(target_method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) ||
2165 (MONO_METHOD_IS_FINAL (target_method
) &&
2166 target_method
->wrapper_type
!= MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
)) &&
2167 !(mono_class_is_marshalbyref (target_method
->klass
))) {
2168 /* Not really virtual, just needs a null check */
2170 need_null_check
= TRUE
;
2173 CHECK_STACK (td
, csignature
->param_count
+ csignature
->hasthis
);
2174 if (!td
->gen_sdb_seq_points
&& !calli
&& op
== -1 && (!is_virtual
|| (target_method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) == 0) &&
2175 (target_method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) == 0 &&
2176 (target_method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) == 0 &&
2177 !(target_method
->iflags
& METHOD_IMPL_ATTRIBUTE_NOINLINING
)) {
2178 (void)mono_class_vtable_checked (domain
, target_method
->klass
, error
);
2179 return_val_if_nok (error
, FALSE
);
2181 if (method
== target_method
&& *(td
->ip
+ 5) == CEE_RET
&& !(csignature
->hasthis
&& m_class_is_valuetype (target_method
->klass
))) {
2182 if (td
->inlined_method
)
2185 if (td
->verbose_level
)
2186 g_print ("Optimize tail call of %s.%s\n", m_class_get_name (target_method
->klass
), target_method
->name
);
2188 for (i
= csignature
->param_count
- 1 + !!csignature
->hasthis
; i
>= 0; --i
)
2191 interp_add_ins (td
, MINT_BR_S
);
2192 // We are branching to the beginning of the method
2193 td
->last_ins
->data
[0] = 0;
2194 if (!is_bb_start
[td
->ip
+ 5 - td
->il_code
])
2195 ++td
->ip
; /* gobble the CEE_RET if it isn't branched to */
2201 target_method
= interp_transform_internal_calls (method
, target_method
, csignature
, is_virtual
);
2203 if (csignature
->call_convention
== MONO_CALL_VARARG
) {
2204 csignature
= mono_method_get_signature_checked (target_method
, image
, token
, generic_context
, error
);
2205 int vararg_stack
= 0;
2207 * For vararg calls, ArgIterator expects the signature and the varargs to be
2208 * stored in a linear memory. We allocate the necessary vt_stack space for
2209 * this. All varargs will be pushed to the vt_stack at call site.
2211 vararg_stack
+= sizeof (gpointer
);
2212 for (i
= csignature
->sentinelpos
; i
< csignature
->param_count
; ++i
) {
2213 int align
, arg_size
;
2214 arg_size
= mono_type_stack_size (csignature
->params
[i
], &align
);
2215 vararg_stack
+= ALIGN_TO (arg_size
, align
);
2217 /* allocate space for the pointer to varargs space start */
2218 vararg_stack
+= sizeof (gpointer
);
2219 vt_stack_used
+= ALIGN_TO (vararg_stack
, MINT_VT_ALIGNMENT
);
2220 PUSH_VT (td
, vararg_stack
);
2223 if (need_null_check
) {
2224 interp_add_ins (td
, MINT_CKNULL_N
);
2225 td
->last_ins
->data
[0] = csignature
->param_count
+ 1;
2228 g_assert (csignature
->call_convention
!= MONO_CALL_FASTCALL
);
2229 if ((mono_interp_opt
& INTERP_OPT_INLINE
) && op
== -1 && !is_virtual
&& target_method
&& interp_method_check_inlining (td
, target_method
)) {
2230 MonoMethodHeader
*mheader
= interp_method_get_header (target_method
, error
);
2231 return_val_if_nok (error
, FALSE
);
2233 if (interp_inline_method (td
, target_method
, mheader
, error
)) {
2239 /* Don't inline methods that do calls */
2240 if (op
== -1 && td
->inlined_method
)
2243 /* We need to convert delegate invoke to a indirect call on the interp_invoke_impl field */
2244 if (target_method
&& m_class_get_parent (target_method
->klass
) == mono_defaults
.multicastdelegate_class
) {
2245 const char *name
= target_method
->name
;
2246 if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
2248 interp_add_ins (td
, MINT_LD_DELEGATE_INVOKE_IMPL
);
2249 td
->last_ins
->data
[0] = csignature
->param_count
+ 1;
2250 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
2254 /* Pop the function pointer */
2258 td
->sp
-= csignature
->param_count
+ !!csignature
->hasthis
;
2259 for (i
= 0; i
< csignature
->param_count
; ++i
) {
2260 if (td
->sp
[i
+ !!csignature
->hasthis
].type
== STACK_TYPE_VT
) {
2262 MonoClass
*klass
= mono_class_from_mono_type_internal (csignature
->params
[i
]);
2263 if (csignature
->pinvoke
&& method
->wrapper_type
!= MONO_WRAPPER_NONE
)
2264 size
= mono_class_native_size (klass
, NULL
);
2266 size
= mono_class_value_size (klass
, NULL
);
2267 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
2268 vt_stack_used
+= size
;
2272 /* need to handle typedbyref ... */
2273 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
2274 int mt
= mint_type(csignature
->ret
);
2275 MonoClass
*klass
= mono_class_from_mono_type_internal (csignature
->ret
);
2276 if (mt
== MINT_TYPE_VT
) {
2277 if (csignature
->pinvoke
&& method
->wrapper_type
!= MONO_WRAPPER_NONE
)
2278 vt_res_size
= mono_class_native_size (klass
, NULL
);
2280 vt_res_size
= mono_class_value_size (klass
, NULL
);
2281 if (mono_class_has_failure (klass
)) {
2282 mono_error_set_for_class_failure (error
, klass
);
2285 PUSH_VT(td
, vt_res_size
);
2287 PUSH_TYPE(td
, stack_type
[mt
], klass
);
2292 interp_add_ins (td
, op
);
2294 if (op
== MINT_LDLEN
) {
2295 #ifdef MONO_BIG_ARRAYS
2296 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I8
);
2298 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I4
);
2302 if (op
== MINT_CALLRUN
) {
2303 td
->last_ins
->data
[0] = get_data_item_index (td
, target_method
);
2304 td
->last_ins
->data
[1] = get_data_item_index (td
, mono_method_signature_internal (target_method
));
2306 } else if (!calli
&& !is_virtual
&& jit_call_supported (target_method
, csignature
)) {
2307 interp_add_ins (td
, MINT_JIT_CALL
);
2308 td
->last_ins
->data
[0] = get_data_item_index (td
, (void *)mono_interp_get_imethod (domain
, target_method
, error
));
2309 mono_error_assert_ok (error
);
2311 #ifndef MONO_ARCH_HAS_NO_PROPER_MONOCTX
2312 /* Try using fast icall path for simple signatures */
2313 if (native
&& !method
->dynamic
)
2314 op
= interp_icall_op_for_sig (csignature
);
2316 if (csignature
->call_convention
== MONO_CALL_VARARG
)
2317 interp_add_ins (td
, MINT_CALL_VARARG
);
2319 interp_add_ins (td
, native
? ((op
!= -1) ? MINT_CALLI_NAT_FAST
: MINT_CALLI_NAT
) : MINT_CALLI
);
2320 else if (is_virtual
&& !mono_class_is_marshalbyref (target_method
->klass
))
2321 interp_add_ins (td
, is_void
? MINT_VCALLVIRT_FAST
: MINT_CALLVIRT_FAST
);
2322 else if (is_virtual
)
2323 interp_add_ins (td
, is_void
? MINT_VCALLVIRT
: MINT_CALLVIRT
);
2325 interp_add_ins (td
, is_void
? MINT_VCALL
: MINT_CALL
);
2328 td
->last_ins
->data
[0] = get_data_item_index (td
, (void *)csignature
);
2330 td
->last_ins
->data
[1] = op
;
2331 if (td
->last_ins
->opcode
== MINT_CALLI_NAT_FAST
)
2332 td
->last_ins
->data
[2] = save_last_error
;
2333 } else if (op
== -1 && td
->last_ins
->opcode
== MINT_CALLI_NAT
) {
2334 td
->last_ins
->data
[1] = save_last_error
;
2337 td
->last_ins
->data
[0] = get_data_item_index (td
, (void *)mono_interp_get_imethod (domain
, target_method
, error
));
2338 return_val_if_nok (error
, FALSE
);
2339 if (csignature
->call_convention
== MONO_CALL_VARARG
)
2340 td
->last_ins
->data
[1] = get_data_item_index (td
, (void *)csignature
);
2341 else if (is_virtual
&& !mono_class_is_marshalbyref (target_method
->klass
)) {
2342 /* FIXME Use fastpath also for MBRO. Asserts in mono_method_get_vtable_slot */
2343 if (mono_class_is_interface (target_method
->klass
))
2344 td
->last_ins
->data
[1] = -2 * MONO_IMT_SIZE
+ mono_method_get_imt_slot (target_method
);
2346 td
->last_ins
->data
[1] = mono_method_get_vtable_slot (target_method
);
2351 if (vt_stack_used
!= 0 || vt_res_size
!= 0) {
2352 interp_add_ins (td
, MINT_VTRESULT
);
2353 td
->last_ins
->data
[0] = vt_res_size
;
2354 WRITE32_INS (td
->last_ins
, 1, &vt_stack_used
);
2355 td
->vt_sp
-= vt_stack_used
;
2361 static MonoClassField
*
2362 interp_field_from_token (MonoMethod
*method
, guint32 token
, MonoClass
**klass
, MonoGenericContext
*generic_context
, MonoError
*error
)
2364 MonoClassField
*field
= NULL
;
2365 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
2366 field
= (MonoClassField
*) mono_method_get_wrapper_data (method
, token
);
2367 *klass
= field
->parent
;
2369 mono_class_setup_fields (field
->parent
);
2371 field
= mono_field_from_token_checked (m_class_get_image (method
->klass
), token
, klass
, generic_context
, error
);
2372 return_val_if_nok (error
, NULL
);
2375 if (!method
->skip_visibility
&& !mono_method_can_access_field (method
, field
)) {
2376 char *method_fname
= mono_method_full_name (method
, TRUE
);
2377 char *field_fname
= mono_field_full_name (field
);
2378 mono_error_set_generic_error (error
, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname
, method_fname
);
2379 g_free (method_fname
);
2380 g_free (field_fname
);
2387 static InterpBasicBlock
*
2388 get_bb (TransformData
*td
, InterpBasicBlock
*cbb
, unsigned char *ip
)
2390 int offset
= ip
- td
->il_code
;
2391 InterpBasicBlock
*bb
= td
->offset_to_bb
[offset
];
2394 bb
= (InterpBasicBlock
*)mono_mempool_alloc0 (td
->mempool
, sizeof (InterpBasicBlock
));
2396 td
->offset_to_bb
[offset
] = bb
;
2398 td
->basic_blocks
= g_list_append_mempool (td
->mempool
, td
->basic_blocks
, bb
);
2402 bb
->preds
= g_slist_prepend_mempool (td
->mempool
, bb
->preds
, cbb
);
2409 * Compute the set of IL level basic blocks.
2412 get_basic_blocks (TransformData
*td
)
2414 guint8
*start
= (guint8
*)td
->il_code
;
2415 guint8
*end
= (guint8
*)td
->il_code
+ td
->code_size
;
2417 unsigned char *target
;
2420 const MonoOpcode
*opcode
;
2421 InterpBasicBlock
*cbb
;
2423 td
->offset_to_bb
= (InterpBasicBlock
**)mono_mempool_alloc0 (td
->mempool
, sizeof (InterpBasicBlock
*) * (end
- start
+ 1));
2424 td
->entry_bb
= cbb
= get_bb (td
, NULL
, start
);
2427 cli_addr
= ip
- start
;
2428 td
->offset_to_bb
[cli_addr
] = cbb
;
2429 i
= mono_opcode_value ((const guint8
**)&ip
, end
);
2430 opcode
= &mono_opcodes
[i
];
2431 switch (opcode
->argument
) {
2432 case MonoInlineNone
:
2435 case MonoInlineString
:
2436 case MonoInlineType
:
2437 case MonoInlineField
:
2438 case MonoInlineMethod
:
2441 case MonoShortInlineR
:
2448 case MonoShortInlineVar
:
2449 case MonoShortInlineI
:
2452 case MonoShortInlineBrTarget
:
2453 target
= start
+ cli_addr
+ 2 + (signed char)ip
[1];
2454 get_bb (td
, cbb
, target
);
2456 cbb
= get_bb (td
, cbb
, ip
);
2458 case MonoInlineBrTarget
:
2459 target
= start
+ cli_addr
+ 5 + (gint32
)read32 (ip
+ 1);
2460 get_bb (td
, cbb
, target
);
2462 cbb
= get_bb (td
, cbb
, ip
);
2464 case MonoInlineSwitch
: {
2465 guint32 n
= read32 (ip
+ 1);
2468 cli_addr
+= 5 + 4 * n
;
2469 target
= start
+ cli_addr
;
2470 get_bb (td
, cbb
, target
);
2472 for (j
= 0; j
< n
; ++j
) {
2473 target
= start
+ cli_addr
+ (gint32
)read32 (ip
);
2474 get_bb (td
, cbb
, target
);
2477 cbb
= get_bb (td
, cbb
, ip
);
2485 g_assert_not_reached ();
2489 cbb
= get_bb (td
, NULL
, ip
);
2494 interp_save_debug_info (InterpMethod
*rtm
, MonoMethodHeader
*header
, TransformData
*td
, GArray
*line_numbers
)
2496 MonoDebugMethodJitInfo
*dinfo
;
2499 if (!mono_debug_enabled ())
2503 * We save the debug info in the same way the JIT does it, treating the interpreter IR as the native code.
2506 dinfo
= g_new0 (MonoDebugMethodJitInfo
, 1);
2507 dinfo
->num_params
= rtm
->param_count
;
2508 dinfo
->params
= g_new0 (MonoDebugVarInfo
, dinfo
->num_params
);
2509 dinfo
->num_locals
= header
->num_locals
;
2510 dinfo
->locals
= g_new0 (MonoDebugVarInfo
, header
->num_locals
);
2511 dinfo
->code_start
= (guint8
*)rtm
->code
;
2512 dinfo
->code_size
= td
->new_code_end
- td
->new_code
;
2513 dinfo
->epilogue_begin
= 0;
2514 dinfo
->has_var_info
= TRUE
;
2515 dinfo
->num_line_numbers
= line_numbers
->len
;
2516 dinfo
->line_numbers
= g_new0 (MonoDebugLineNumberEntry
, dinfo
->num_line_numbers
);
2518 for (i
= 0; i
< dinfo
->num_params
; i
++) {
2519 MonoDebugVarInfo
*var
= &dinfo
->params
[i
];
2520 var
->type
= rtm
->param_types
[i
];
2522 for (i
= 0; i
< dinfo
->num_locals
; i
++) {
2523 MonoDebugVarInfo
*var
= &dinfo
->locals
[i
];
2524 var
->type
= mono_metadata_type_dup (NULL
, header
->locals
[i
]);
2527 for (i
= 0; i
< dinfo
->num_line_numbers
; i
++)
2528 dinfo
->line_numbers
[i
] = g_array_index (line_numbers
, MonoDebugLineNumberEntry
, i
);
2529 mono_debug_add_method (rtm
->method
, dinfo
, rtm
->domain
);
2531 mono_debug_free_method_jit_info (dinfo
);
2534 /* Same as the code in seq-points.c */
2536 insert_pred_seq_point (SeqPoint
*last_sp
, SeqPoint
*sp
, GSList
**next
)
2539 int src_index
= last_sp
->next_offset
;
2540 int dst_index
= sp
->next_offset
;
2542 /* bb->in_bb might contain duplicates */
2543 for (l
= next
[src_index
]; l
; l
= l
->next
)
2544 if (GPOINTER_TO_UINT (l
->data
) == dst_index
)
2547 next
[src_index
] = g_slist_append (next
[src_index
], GUINT_TO_POINTER (dst_index
));
2551 recursively_make_pred_seq_points (TransformData
*td
, InterpBasicBlock
*bb
)
2553 SeqPoint
** const MONO_SEQ_SEEN_LOOP
= (SeqPoint
**)GINT_TO_POINTER(-1);
2556 GArray
*predecessors
= g_array_new (FALSE
, TRUE
, sizeof (gpointer
));
2557 GHashTable
*seen
= g_hash_table_new_full (g_direct_hash
, NULL
, NULL
, NULL
);
2559 // Insert/remove sentinel into the memoize table to detect loops containing bb
2560 bb
->pred_seq_points
= MONO_SEQ_SEEN_LOOP
;
2562 for (l
= bb
->preds
; l
; l
= l
->next
) {
2563 InterpBasicBlock
*in_bb
= (InterpBasicBlock
*)l
->data
;
2565 // This bb has the last seq point, append it and continue
2566 if (in_bb
->last_seq_point
!= NULL
) {
2567 predecessors
= g_array_append_val (predecessors
, in_bb
->last_seq_point
);
2571 // We've looped or handled this before, exit early.
2572 // No last sequence points to find.
2573 if (in_bb
->pred_seq_points
== MONO_SEQ_SEEN_LOOP
)
2576 // Take sequence points from incoming basic blocks
2578 if (in_bb
== td
->entry_bb
)
2581 if (in_bb
->pred_seq_points
== NULL
)
2582 recursively_make_pred_seq_points (td
, in_bb
);
2584 // Union sequence points with incoming bb's
2585 for (int i
=0; i
< in_bb
->num_pred_seq_points
; i
++) {
2586 if (!g_hash_table_lookup (seen
, in_bb
->pred_seq_points
[i
])) {
2587 g_array_append_val (predecessors
, in_bb
->pred_seq_points
[i
]);
2588 g_hash_table_insert (seen
, in_bb
->pred_seq_points
[i
], (gpointer
)&MONO_SEQ_SEEN_LOOP
);
2591 // predecessors = g_array_append_vals (predecessors, in_bb->pred_seq_points, in_bb->num_pred_seq_points);
2594 g_hash_table_destroy (seen
);
2596 if (predecessors
->len
!= 0) {
2597 bb
->pred_seq_points
= (SeqPoint
**)mono_mempool_alloc0 (td
->mempool
, sizeof (SeqPoint
*) * predecessors
->len
);
2598 bb
->num_pred_seq_points
= predecessors
->len
;
2600 for (int newer
= 0; newer
< bb
->num_pred_seq_points
; newer
++) {
2601 bb
->pred_seq_points
[newer
] = (SeqPoint
*)g_array_index (predecessors
, gpointer
, newer
);
2605 g_array_free (predecessors
, TRUE
);
2609 collect_pred_seq_points (TransformData
*td
, InterpBasicBlock
*bb
, SeqPoint
*seqp
, GSList
**next
)
2611 // Doesn't have a last sequence point, must find from incoming basic blocks
2612 if (bb
->pred_seq_points
== NULL
&& bb
!= td
->entry_bb
)
2613 recursively_make_pred_seq_points (td
, bb
);
2615 for (int i
= 0; i
< bb
->num_pred_seq_points
; i
++)
2616 insert_pred_seq_point (bb
->pred_seq_points
[i
], seqp
, next
);
2622 save_seq_points (TransformData
*td
, MonoJitInfo
*jinfo
)
2625 int i
, seq_info_size
;
2626 MonoSeqPointInfo
*info
;
2627 GSList
**next
= NULL
;
2630 if (!td
->gen_sdb_seq_points
)
2634 * For each sequence point, compute the list of sequence points immediately
2635 * following it, this is needed to implement 'step over' in the debugger agent.
2636 * Similar to the code in mono_save_seq_point_info ().
2638 for (i
= 0; i
< td
->seq_points
->len
; ++i
) {
2639 SeqPoint
*sp
= (SeqPoint
*)g_ptr_array_index (td
->seq_points
, i
);
2641 /* Store the seq point index here temporarily */
2642 sp
->next_offset
= i
;
2644 next
= (GSList
**)mono_mempool_alloc0 (td
->mempool
, sizeof (GList
*) * td
->seq_points
->len
);
2645 for (bblist
= td
->basic_blocks
; bblist
; bblist
= bblist
->next
) {
2646 InterpBasicBlock
*bb
= (InterpBasicBlock
*)bblist
->data
;
2648 GSList
*bb_seq_points
= g_slist_reverse (bb
->seq_points
);
2649 SeqPoint
*last
= NULL
;
2650 for (GSList
*l
= bb_seq_points
; l
; l
= l
->next
) {
2651 SeqPoint
*sp
= (SeqPoint
*)l
->data
;
2653 if (sp
->il_offset
== METHOD_ENTRY_IL_OFFSET
|| sp
->il_offset
== METHOD_EXIT_IL_OFFSET
)
2654 /* Used to implement method entry/exit events */
2658 /* Link with the previous seq point in the same bb */
2659 next
[last
->next_offset
] = g_slist_append_mempool (td
->mempool
, next
[last
->next_offset
], GINT_TO_POINTER (sp
->next_offset
));
2661 /* Link with the last bb in the previous bblocks */
2662 collect_pred_seq_points (td
, bb
, sp
, next
);
2668 /* Serialize the seq points into a byte array */
2669 array
= g_byte_array_new ();
2670 SeqPoint zero_seq_point
= {0};
2671 SeqPoint
* last_seq_point
= &zero_seq_point
;
2672 for (i
= 0; i
< td
->seq_points
->len
; ++i
) {
2673 SeqPoint
*sp
= (SeqPoint
*)g_ptr_array_index (td
->seq_points
, i
);
2675 sp
->next_offset
= 0;
2676 if (mono_seq_point_info_add_seq_point (array
, sp
, last_seq_point
, next
[i
], TRUE
))
2677 last_seq_point
= sp
;
2680 if (td
->verbose_level
) {
2681 g_print ("\nSEQ POINT MAP FOR %s: \n", td
->method
->name
);
2683 for (i
= 0; i
< td
->seq_points
->len
; ++i
) {
2684 SeqPoint
*sp
= (SeqPoint
*)g_ptr_array_index (td
->seq_points
, i
);
2690 g_print ("\tIL0x%x[0x%0x] ->", sp
->il_offset
, sp
->native_offset
);
2691 for (l
= next
[i
]; l
; l
= l
->next
) {
2692 int next_index
= GPOINTER_TO_UINT (l
->data
);
2693 g_print (" IL0x%x", ((SeqPoint
*)g_ptr_array_index (td
->seq_points
, next_index
))->il_offset
);
2699 info
= mono_seq_point_info_new (array
->len
, TRUE
, array
->data
, TRUE
, &seq_info_size
);
2700 mono_atomic_fetch_add_i32 (&mono_jit_stats
.allocated_seq_points_size
, seq_info_size
);
2702 g_byte_array_free (array
, TRUE
);
2704 jinfo
->seq_points
= info
;
2707 #define BARRIER_IF_VOLATILE(td) \
2710 interp_add_ins (td, MINT_MONO_MEMORY_BARRIER); \
2711 volatile_ = FALSE; \
2715 #define INLINE_FAILURE \
2722 interp_method_compute_offsets (TransformData
*td
, InterpMethod
*imethod
, MonoMethodSignature
*signature
, MonoMethodHeader
*header
)
2724 int i
, offset
, size
, align
;
2726 imethod
->local_offsets
= (guint32
*)g_malloc (header
->num_locals
* sizeof(guint32
));
2727 td
->locals
= (InterpLocal
*)g_malloc (header
->num_locals
* sizeof (InterpLocal
));
2728 td
->locals_size
= header
->num_locals
;
2729 td
->locals_capacity
= td
->locals_size
;
2731 for (i
= 0; i
< header
->num_locals
; ++i
) {
2732 size
= mono_type_size (header
->locals
[i
], &align
);
2733 offset
+= align
- 1;
2734 offset
&= ~(align
- 1);
2735 imethod
->local_offsets
[i
] = offset
;
2736 td
->locals
[i
].offset
= offset
;
2737 td
->locals
[i
].flags
= 0;
2740 offset
= (offset
+ 7) & ~7;
2742 imethod
->exvar_offsets
= (guint32
*)g_malloc (header
->num_clauses
* sizeof (guint32
));
2743 for (i
= 0; i
< header
->num_clauses
; i
++) {
2744 imethod
->exvar_offsets
[i
] = offset
;
2745 offset
+= sizeof (MonoObject
*);
2747 offset
= (offset
+ 7) & ~7;
2749 imethod
->locals_size
= offset
;
2750 g_assert (imethod
->locals_size
< 65536);
2751 td
->total_locals_size
= offset
;
2755 get_arg_type (MonoMethodSignature
*signature
, int arg_n
)
2757 if (signature
->hasthis
&& arg_n
== 0)
2758 return mono_get_object_type ();
2759 return signature
->params
[arg_n
- !!signature
->hasthis
];
2762 /* Return false is failure to init basic blocks due to being in inline method */
2764 init_bb_start (TransformData
*td
, MonoMethodHeader
*header
, gboolean inlining
)
2766 const unsigned char *ip
, *end
;
2767 const MonoOpcode
*opcode
;
2768 int offset
, i
, in
, backwards
;
2770 /* intern the strings in the method. */
2772 end
= ip
+ header
->code_size
;
2774 /* inlined method continues the basic block of parent method */
2776 td
->is_bb_start
[0] = 1;
2783 else if (in
== 0xf0) {
2785 in
= *ip
+ MONO_CEE_MONO_ICALL
;
2787 opcode
= &mono_opcodes
[in
];
2788 switch (opcode
->argument
) {
2789 case MonoInlineNone
:
2792 case MonoInlineString
:
2795 case MonoInlineType
:
2798 case MonoInlineMethod
:
2801 case MonoInlineField
:
2805 case MonoShortInlineR
:
2808 case MonoInlineBrTarget
:
2809 offset
= read32 (ip
+ 1);
2811 /* this branch is ignored */
2812 if (offset
== 0 && in
== MONO_CEE_BR
)
2814 backwards
= offset
< 0;
2815 offset
+= ip
- header
->code
;
2816 g_assert (offset
>= 0 && offset
< header
->code_size
);
2819 td
->is_bb_start
[offset
] |= backwards
? 2 : 1;
2821 case MonoShortInlineBrTarget
:
2822 offset
= ((gint8
*)ip
) [1];
2824 /* this branch is ignored */
2825 if (offset
== 0 && in
== MONO_CEE_BR_S
)
2827 backwards
= offset
< 0;
2828 offset
+= ip
- header
->code
;
2829 g_assert (offset
>= 0 && offset
< header
->code_size
);
2832 td
->is_bb_start
[offset
] |= backwards
? 2 : 1;
2837 case MonoShortInlineVar
:
2838 case MonoShortInlineI
:
2841 case MonoInlineSwitch
: {
2843 const unsigned char *next_ip
;
2847 next_ip
= ip
+ 4 * n
;
2848 for (i
= 0; i
< n
; i
++) {
2849 offset
= read32 (ip
);
2850 backwards
= offset
< 0;
2851 offset
+= next_ip
- header
->code
;
2852 g_assert (offset
>= 0 && offset
< header
->code_size
);
2855 td
->is_bb_start
[offset
] |= backwards
? 2 : 1;
2865 g_assert_not_reached ();
2871 #ifdef NO_UNALIGNED_ACCESS
2873 get_unaligned_opcode (int opcode
)
2877 return MINT_LDFLD_I8_UNALIGNED
;
2879 return MINT_LDFLD_R8_UNALIGNED
;
2881 return MINT_STFLD_I8_UNALIGNED
;
2883 return MINT_STFLD_R8_UNALIGNED
;
2885 g_assert_not_reached ();
2892 interp_handle_isinst (TransformData
*td
, MonoClass
*klass
, gboolean isinst_instr
)
2894 /* Follow the logic from jit's handle_isinst */
2895 if (!mono_class_has_variant_generic_params (klass
)) {
2896 if (mono_class_is_interface (klass
))
2897 interp_add_ins (td
, isinst_instr
? MINT_ISINST_INTERFACE
: MINT_CASTCLASS_INTERFACE
);
2898 else if (!mono_class_is_marshalbyref (klass
) && m_class_get_rank (klass
) == 0 && !mono_class_is_nullable (klass
))
2899 interp_add_ins (td
, isinst_instr
? MINT_ISINST_COMMON
: MINT_CASTCLASS_COMMON
);
2901 interp_add_ins (td
, isinst_instr
? MINT_ISINST
: MINT_CASTCLASS
);
2903 interp_add_ins (td
, isinst_instr
? MINT_ISINST
: MINT_CASTCLASS
);
2905 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
2910 interp_emit_ldsflda (TransformData
*td
, MonoClassField
*field
, MonoError
*error
)
2912 MonoDomain
*domain
= td
->rtm
->domain
;
2913 // Initialize the offset for the field
2914 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, field
->parent
, error
);
2915 return_if_nok (error
);
2917 if (mono_class_field_is_special_static (field
)) {
2920 mono_domain_lock (domain
);
2921 g_assert (domain
->special_static_fields
);
2922 offset
= GPOINTER_TO_UINT (g_hash_table_lookup (domain
->special_static_fields
, field
));
2923 mono_domain_unlock (domain
);
2926 interp_add_ins (td
, MINT_LDSSFLDA
);
2927 WRITE32_INS(td
->last_ins
, 0, &offset
);
2929 interp_add_ins (td
, MINT_LDSFLDA
);
2930 td
->last_ins
->data
[0] = get_data_item_index (td
, vtable
);
2931 td
->last_ins
->data
[1] = get_data_item_index (td
, (char*)mono_vtable_get_static_field_data (vtable
) + field
->offset
);
2936 interp_emit_sfld_access (TransformData
*td
, MonoClassField
*field
, MonoClass
*field_class
, int mt
, gboolean is_load
, MonoError
*error
)
2938 MonoDomain
*domain
= td
->rtm
->domain
;
2939 // Initialize the offset for the field
2940 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, field
->parent
, error
);
2941 return_if_nok (error
);
2943 if (mono_class_field_is_special_static (field
)) {
2946 mono_domain_lock (domain
);
2947 g_assert (domain
->special_static_fields
);
2948 offset
= GPOINTER_TO_UINT (g_hash_table_lookup (domain
->special_static_fields
, field
));
2949 mono_domain_unlock (domain
);
2952 // Offset is SpecialStaticOffset
2953 if ((offset
& 0x80000000) == 0 && mt
!= MINT_TYPE_VT
) {
2954 // This field is thread static
2955 interp_add_ins (td
, (is_load
? MINT_LDTSFLD_I1
: MINT_STTSFLD_I1
) + mt
);
2956 WRITE32_INS(td
->last_ins
, 0, &offset
);
2958 if (mt
== MINT_TYPE_VT
) {
2959 interp_add_ins (td
, is_load
? MINT_LDSSFLD_VT
: MINT_STSSFLD_VT
);
2960 WRITE32_INS(td
->last_ins
, 0, &offset
);
2962 int size
= mono_class_value_size (field_class
, NULL
);
2963 WRITE32_INS(td
->last_ins
, 2, &size
);
2965 interp_add_ins (td
, is_load
? MINT_LDSSFLD
: MINT_STSSFLD
);
2966 td
->last_ins
->data
[0] = get_data_item_index (td
, field
);
2967 WRITE32_INS(td
->last_ins
, 1, &offset
);
2972 interp_add_ins (td
, (mt
== MINT_TYPE_VT
) ? MINT_LDSFLD_VT
: (MINT_LDSFLD_I1
+ mt
- MINT_TYPE_I1
));
2974 interp_add_ins (td
, (mt
== MINT_TYPE_VT
) ? MINT_STSFLD_VT
: (MINT_STSFLD_I1
+ mt
- MINT_TYPE_I1
));
2976 td
->last_ins
->data
[0] = get_data_item_index (td
, vtable
);
2977 td
->last_ins
->data
[1] = get_data_item_index (td
, (char*)mono_vtable_get_static_field_data (vtable
) + field
->offset
);
2979 if (mt
== MINT_TYPE_VT
) {
2980 int size
= mono_class_value_size (field_class
, NULL
);
2981 WRITE32_INS(td
->last_ins
, 2, &size
);
2987 generate_code (TransformData
*td
, MonoMethod
*method
, MonoMethodHeader
*header
, MonoGenericContext
*generic_context
, MonoError
*error
)
2990 int offset
, mt
, i
, i32
;
2993 const unsigned char *end
;
2994 MonoSimpleBasicBlock
*bb
= NULL
, *original_bb
= NULL
;
2995 gboolean sym_seq_points
= FALSE
;
2996 MonoBitSet
*seq_point_locs
= NULL
;
2997 gboolean readonly
= FALSE
;
2998 gboolean volatile_
= FALSE
;
2999 MonoClass
*constrained_class
= NULL
;
3001 MonoClassField
*field
;
3002 MonoImage
*image
= m_class_get_image (method
->klass
);
3003 InterpMethod
*rtm
= td
->rtm
;
3004 MonoDomain
*domain
= rtm
->domain
;
3005 MonoMethodSignature
*signature
= mono_method_signature_internal (method
);
3006 gboolean ret
= TRUE
;
3007 gboolean emitted_funccall_seq_point
= FALSE
;
3008 guint32
*arg_locals
= NULL
;
3009 guint32
*local_locals
= NULL
;
3010 InterpInst
*last_seq_point
= NULL
;
3011 gboolean save_last_error
= FALSE
;
3012 gboolean inlining
= td
->method
!= method
;
3014 original_bb
= bb
= mono_basic_block_split (method
, error
, header
);
3015 goto_if_nok (error
, exit
);
3018 td
->il_code
= header
->code
;
3019 td
->in_start
= td
->ip
= header
->code
;
3020 end
= td
->ip
+ header
->code_size
;
3022 if (!init_bb_start (td
, header
, inlining
))
3026 for (i
= 0; i
< header
->code_size
; i
++) {
3027 td
->stack_height
[i
] = -1;
3028 td
->clause_indexes
[i
] = -1;
3032 for (i
= 0; i
< header
->num_clauses
; i
++) {
3033 MonoExceptionClause
*c
= header
->clauses
+ i
;
3034 td
->stack_height
[c
->handler_offset
] = 0;
3035 td
->vt_stack_size
[c
->handler_offset
] = 0;
3036 td
->is_bb_start
[c
->handler_offset
] = 1;
3037 td
->is_bb_start
[c
->try_offset
] = 1;
3039 td
->stack_height
[c
->handler_offset
] = 1;
3040 td
->stack_state
[c
->handler_offset
] = (StackInfo
*)g_malloc0(sizeof(StackInfo
));
3041 td
->stack_state
[c
->handler_offset
][0].type
= STACK_TYPE_O
;
3042 td
->stack_state
[c
->handler_offset
][0].klass
= NULL
; /*FIX*/
3044 if (c
->flags
& MONO_EXCEPTION_CLAUSE_FILTER
) {
3045 td
->stack_height
[c
->data
.filter_offset
] = 0;
3046 td
->vt_stack_size
[c
->data
.filter_offset
] = 0;
3047 td
->is_bb_start
[c
->data
.filter_offset
] = 1;
3049 td
->stack_height
[c
->data
.filter_offset
] = 1;
3050 td
->stack_state
[c
->data
.filter_offset
] = (StackInfo
*)g_malloc0(sizeof(StackInfo
));
3051 td
->stack_state
[c
->data
.filter_offset
][0].type
= STACK_TYPE_O
;
3052 td
->stack_state
[c
->data
.filter_offset
][0].klass
= NULL
; /*FIX*/
3055 for (int j
= c
->handler_offset
; j
< c
->handler_offset
+ c
->handler_len
; ++j
) {
3056 if (td
->clause_indexes
[j
] == -1)
3057 td
->clause_indexes
[j
] = i
;
3061 if (td
->gen_sdb_seq_points
&& !inlining
) {
3062 MonoDebugMethodInfo
*minfo
;
3063 get_basic_blocks (td
);
3065 minfo
= mono_debug_lookup_method (method
);
3068 MonoSymSeqPoint
*sps
;
3069 int i
, n_il_offsets
;
3071 mono_debug_get_seq_points (minfo
, NULL
, NULL
, NULL
, &sps
, &n_il_offsets
);
3073 seq_point_locs
= mono_bitset_mem_new (mono_mempool_alloc0 (td
->mempool
, mono_bitset_alloc_size (header
->code_size
, 0)), header
->code_size
, 0);
3074 sym_seq_points
= TRUE
;
3076 for (i
= 0; i
< n_il_offsets
; ++i
) {
3077 if (sps
[i
].il_offset
< header
->code_size
)
3078 mono_bitset_set_fast (seq_point_locs
, sps
[i
].il_offset
);
3082 MonoDebugMethodAsyncInfo
* asyncMethod
= mono_debug_lookup_method_async_debug_info (method
);
3084 for (i
= 0; asyncMethod
!= NULL
&& i
< asyncMethod
->num_awaits
; i
++) {
3085 mono_bitset_set_fast (seq_point_locs
, asyncMethod
->resume_offsets
[i
]);
3086 mono_bitset_set_fast (seq_point_locs
, asyncMethod
->yield_offsets
[i
]);
3088 mono_debug_free_method_async_debug_info (asyncMethod
);
3090 } else if (!method
->wrapper_type
&& !method
->dynamic
&& mono_debug_image_has_debug_info (m_class_get_image (method
->klass
))) {
3091 /* Methods without line number info like auto-generated property accessors */
3092 seq_point_locs
= mono_bitset_new (header
->code_size
, 0);
3093 sym_seq_points
= TRUE
;
3097 if (sym_seq_points
) {
3098 last_seq_point
= interp_add_ins (td
, MINT_SDB_SEQ_POINT
);
3099 last_seq_point
->flags
= INTERP_INST_FLAG_SEQ_POINT_METHOD_ENTRY
;
3102 if (mono_debugger_method_has_breakpoint (method
))
3103 interp_add_ins (td
, MINT_BREAKPOINT
);
3106 if (td
->verbose_level
) {
3107 char *tmp
= mono_disasm_code (NULL
, method
, td
->ip
, end
);
3108 char *name
= mono_method_full_name (method
, TRUE
);
3109 g_print ("Method %s, original code:\n", name
);
3110 g_print ("%s\n", tmp
);
3115 if (header
->num_locals
&& header
->init_locals
)
3116 interp_add_ins (td
, MINT_INITLOCALS
);
3118 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (method
))
3119 interp_add_ins (td
, MINT_TRACE_ENTER
);
3120 else if (rtm
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_ENTER
)
3121 interp_add_ins (td
, MINT_PROF_ENTER
);
3123 /* safepoint is required on method entry */
3124 if (mono_threads_are_safepoints_enabled ())
3125 interp_add_ins (td
, MINT_SAFEPOINT
);
3128 arg_locals
= (guint32
*) g_malloc ((!!signature
->hasthis
+ signature
->param_count
) * sizeof (guint32
));
3129 /* Allocate locals to store inlined method args from stack */
3130 for (i
= signature
->param_count
- 1; i
>= 0; i
--) {
3131 local
= create_interp_local (td
, signature
->params
[i
]);
3132 arg_locals
[i
+ !!signature
->hasthis
] = local
;
3133 store_local_general (td
, local
, signature
->params
[i
]);
3136 if (signature
->hasthis
) {
3138 * If this is value type, it is passed by address and not by value.
3139 * FIXME We should use MINT_TYPE_P instead of MINT_TYPE_O
3141 MonoType
*type
= mono_get_object_type ();
3142 local
= create_interp_local (td
, type
);
3143 arg_locals
[0] = local
;
3144 store_local_general (td
, local
, type
);
3147 local_locals
= (guint32
*) g_malloc (header
->num_locals
* sizeof (guint32
));
3148 /* Allocate locals to store inlined method args from stack */
3149 for (i
= 0; i
< header
->num_locals
; i
++)
3150 local_locals
[i
] = create_interp_local (td
, header
->locals
[i
]);
3153 while (td
->ip
< end
) {
3154 g_assert (td
->sp
>= td
->stack
);
3155 g_assert (td
->vt_sp
< 0x10000000);
3156 in_offset
= td
->ip
- header
->code
;
3158 td
->current_il_offset
= in_offset
;
3159 td
->in_start
= td
->ip
;
3160 InterpInst
*prev_last_ins
= td
->last_ins
;
3162 // Inlined method doesn't have clauses or branches
3163 if (!inlining
&& td
->stack_height
[in_offset
] >= 0) {
3164 g_assert (td
->is_bb_start
[in_offset
]);
3165 if (td
->stack_height
[in_offset
] > 0)
3166 memcpy (td
->stack
, td
->stack_state
[in_offset
], td
->stack_height
[in_offset
] * sizeof(td
->stack
[0]));
3167 td
->sp
= td
->stack
+ td
->stack_height
[in_offset
];
3168 td
->vt_sp
= td
->vt_stack_size
[in_offset
];
3171 if (in_offset
== bb
->end
)
3175 int op_size
= mono_opcode_size (td
->ip
, end
);
3176 g_assert (op_size
> 0); /* The BB formation pass must catch all bad ops */
3178 if (td
->verbose_level
> 1)
3179 g_print ("SKIPPING DEAD OP at %x\n", in_offset
);
3185 if (td
->verbose_level
> 1) {
3186 g_print ("IL_%04lx %s %-10s, sp %ld, %s %-12s vt_sp %u (max %u)\n",
3187 td
->ip
- td
->il_code
,
3188 td
->is_bb_start
[td
->ip
- td
->il_code
] == 3 ? "<>" :
3189 td
->is_bb_start
[td
->ip
- td
->il_code
] == 2 ? "< " :
3190 td
->is_bb_start
[td
->ip
- td
->il_code
] == 1 ? " >" : " ",
3191 mono_opcode_name (*td
->ip
), td
->sp
- td
->stack
,
3192 td
->sp
> td
->stack
? stack_type_string
[td
->sp
[-1].type
] : " ",
3193 (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
)) : "",
3194 td
->vt_sp
, td
->max_vt_sp
);
3197 if (sym_seq_points
&& mono_bitset_test_fast (seq_point_locs
, td
->ip
- header
->code
)) {
3198 InterpBasicBlock
*cbb
= td
->offset_to_bb
[td
->ip
- header
->code
];
3202 * Make methods interruptable at the beginning, and at the targets of
3203 * backward branches.
3205 if (in_offset
== 0 || g_slist_length (cbb
->preds
) > 1)
3206 interp_add_ins (td
, MINT_SDB_INTR_LOC
);
3208 last_seq_point
= interp_add_ins (td
, MINT_SDB_SEQ_POINT
);
3211 if (!inlining
&& td
->is_bb_start
[in_offset
]) {
3212 int index
= td
->clause_indexes
[in_offset
];
3214 MonoExceptionClause
*clause
= &header
->clauses
[index
];
3215 if ((clause
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
||
3216 clause
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
) &&
3217 in_offset
== clause
->handler_offset
)
3218 interp_add_ins (td
, MINT_START_ABORT_PROT
);
3225 emitted_funccall_seq_point
= FALSE
;
3229 SIMPLE_OP(td
, MINT_BREAK
);
3235 int arg_n
= *td
->ip
- CEE_LDARG_0
;
3237 load_arg (td
, arg_n
);
3239 load_local_general (td
, arg_locals
[arg_n
], get_arg_type (signature
, arg_n
));
3247 int loc_n
= *td
->ip
- CEE_LDLOC_0
;
3249 load_local (td
, loc_n
);
3251 load_local_general (td
, local_locals
[loc_n
], header
->locals
[loc_n
]);
3259 int loc_n
= *td
->ip
- CEE_STLOC_0
;
3261 store_local (td
, loc_n
);
3263 store_local_general (td
, local_locals
[loc_n
], header
->locals
[loc_n
]);
3268 int arg_n
= ((guint8
*)td
->ip
)[1];
3270 load_arg (td
, arg_n
);
3272 load_local_general (td
, arg_locals
[arg_n
], get_arg_type (signature
, arg_n
));
3276 case CEE_LDARGA_S
: {
3277 /* NOTE: n includes this */
3278 int n
= ((guint8
*) td
->ip
) [1];
3281 get_arg_type_exact (td
, n
, &mt
);
3282 interp_add_ins (td
, mt
== MINT_TYPE_VT
? MINT_LDARGA_VT
: MINT_LDARGA
);
3283 td
->last_ins
->data
[0] = n
;
3285 int loc_n
= arg_locals
[n
];
3286 interp_add_ins (td
, MINT_LDLOCA_S
);
3287 td
->last_ins
->data
[0] = loc_n
;
3288 td
->locals
[loc_n
].flags
|= INTERP_LOCAL_FLAG_INDIRECT
;
3290 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
3295 int arg_n
= ((guint8
*)td
->ip
)[1];
3297 store_arg (td
, arg_n
);
3299 store_local_general (td
, arg_locals
[arg_n
], get_arg_type (signature
, arg_n
));
3304 int loc_n
= ((guint8
*)td
->ip
)[1];
3306 load_local (td
, loc_n
);
3308 load_local_general (td
, local_locals
[loc_n
], header
->locals
[loc_n
]);
3312 case CEE_LDLOCA_S
: {
3313 int loc_n
= ((guint8
*)td
->ip
)[1];
3314 interp_add_ins (td
, MINT_LDLOCA_S
);
3316 loc_n
= local_locals
[loc_n
];
3317 td
->last_ins
->data
[0] = loc_n
;
3318 td
->locals
[loc_n
].flags
|= INTERP_LOCAL_FLAG_INDIRECT
;
3319 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
3324 int loc_n
= ((guint8
*)td
->ip
)[1];
3326 store_local (td
, loc_n
);
3328 store_local_general (td
, local_locals
[loc_n
], header
->locals
[loc_n
]);
3333 SIMPLE_OP(td
, MINT_LDNULL
);
3334 PUSH_TYPE(td
, STACK_TYPE_O
, NULL
);
3337 SIMPLE_OP(td
, MINT_LDC_I4_M1
);
3338 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
3341 // Only single basic block functions are inlined.
3342 if (td
->ip
- td
->il_code
+ 2 < td
->code_size
&& (inlining
|| !td
->is_bb_start
[td
->ip
+ 1 - td
->il_code
]) && td
->ip
[1] == 0xfe && td
->ip
[2] == CEE_CEQ
&&
3343 td
->sp
> td
->stack
&& td
->sp
[-1].type
== STACK_TYPE_I4
) {
3344 SIMPLE_OP(td
, MINT_CEQ0_I4
);
3347 SIMPLE_OP(td
, MINT_LDC_I4_0
);
3348 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
3352 // Only single basic block functions are inlined.
3353 if (td
->ip
- td
->il_code
+ 1 < td
->code_size
&& (inlining
|| !td
->is_bb_start
[td
->ip
+ 1 - td
->il_code
]) &&
3354 (td
->ip
[1] == CEE_ADD
|| td
->ip
[1] == CEE_SUB
) && td
->sp
[-1].type
== STACK_TYPE_I4
) {
3355 interp_add_ins (td
, td
->ip
[1] == CEE_ADD
? MINT_ADD1_I4
: MINT_SUB1_I4
);
3358 SIMPLE_OP(td
, MINT_LDC_I4_1
);
3359 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
3369 SIMPLE_OP(td
, (*td
->ip
- CEE_LDC_I4_0
) + MINT_LDC_I4_0
);
3370 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
3373 interp_add_ins (td
, MINT_LDC_I4_S
);
3374 td
->last_ins
->data
[0] = ((gint8
*) td
->ip
) [1];
3376 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
3379 i32
= read32 (td
->ip
+ 1);
3380 interp_add_ins (td
, MINT_LDC_I4
);
3381 WRITE32_INS (td
->last_ins
, 0, &i32
);
3383 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
3386 gint64 val
= read64 (td
->ip
+ 1);
3387 interp_add_ins (td
, MINT_LDC_I8
);
3388 WRITE64_INS (td
->last_ins
, 0, &val
);
3390 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I8
);
3395 readr4 (td
->ip
+ 1, &val
);
3396 interp_add_ins (td
, MINT_LDC_R4
);
3397 WRITE32_INS (td
->last_ins
, 0, &val
);
3399 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_R4
);
3404 readr8 (td
->ip
+ 1, &val
);
3405 interp_add_ins (td
, MINT_LDC_R8
);
3406 WRITE64_INS (td
->last_ins
, 0, &val
);
3408 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_R8
);
3412 int type
= td
->sp
[-1].type
;
3413 MonoClass
*klass
= td
->sp
[-1].klass
;
3414 if (td
->sp
[-1].type
== STACK_TYPE_VT
) {
3415 gint32 size
= mono_class_value_size (klass
, NULL
);
3417 interp_add_ins (td
, MINT_DUP_VT
);
3418 WRITE32_INS (td
->last_ins
, 0, &size
);
3421 SIMPLE_OP(td
, MINT_DUP
);
3422 PUSH_TYPE(td
, type
, klass
);
3427 SIMPLE_OP(td
, MINT_POP
);
3428 td
->last_ins
->data
[0] = 0;
3429 if (td
->sp
[-1].type
== STACK_TYPE_VT
) {
3430 int size
= mono_class_value_size (td
->sp
[-1].klass
, NULL
);
3431 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
3432 interp_add_ins (td
, MINT_VTRESULT
);
3433 td
->last_ins
->data
[0] = 0;
3434 WRITE32_INS (td
->last_ins
, 1, &size
);
3442 if (td
->sp
> td
->stack
)
3443 g_warning ("CEE_JMP: stack must be empty");
3444 token
= read32 (td
->ip
+ 1);
3445 m
= mono_get_method_checked (image
, token
, NULL
, generic_context
, error
);
3446 goto_if_nok (error
, exit
);
3447 interp_add_ins (td
, MINT_JMP
);
3448 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
3449 goto_if_nok (error
, exit
);
3453 case CEE_CALLVIRT
: /* Fall through */
3454 case CEE_CALLI
: /* Fall through */
3456 gboolean need_seq_point
= FALSE
;
3458 if (sym_seq_points
&& !mono_bitset_test_fast (seq_point_locs
, td
->ip
+ 5 - header
->code
))
3459 need_seq_point
= TRUE
;
3461 if (!interp_transform_call (td
, method
, NULL
, domain
, generic_context
, td
->is_bb_start
, constrained_class
, readonly
, error
, TRUE
, save_last_error
))
3464 if (need_seq_point
) {
3465 //check is is a nested call and remove the MONO_INST_NONEMPTY_STACK of the last breakpoint, only for non native methods
3466 if (!(method
->flags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)) {
3467 if (emitted_funccall_seq_point
) {
3469 last_seq_point
->flags
|= INTERP_INST_FLAG_SEQ_POINT_NESTED_CALL
;
3472 emitted_funccall_seq_point
= TRUE
;
3474 last_seq_point
= interp_add_ins (td
, MINT_SDB_SEQ_POINT
);
3475 // This seq point is actually associated with the instruction following the call
3476 last_seq_point
->il_offset
= td
->ip
- header
->code
;
3477 last_seq_point
->flags
= INTERP_INST_FLAG_SEQ_POINT_NONEMPTY_STACK
;
3480 constrained_class
= NULL
;
3482 save_last_error
= FALSE
;
3486 /* Return from inlined method, return value is on top of stack */
3487 if (td
->method
!= method
) {
3493 MonoType
*ult
= mini_type_get_underlying_type (signature
->ret
);
3494 if (ult
->type
!= MONO_TYPE_VOID
) {
3495 CHECK_STACK (td
, 1);
3497 if (mint_type (ult
) == MINT_TYPE_VT
) {
3498 MonoClass
*klass
= mono_class_from_mono_type_internal (ult
);
3499 vt_size
= mono_class_value_size (klass
, NULL
);
3502 if (td
->sp
> td
->stack
) {
3503 mono_error_set_generic_error (error
, "System", "InvalidProgramException", "");
3506 if (td
->vt_sp
!= ALIGN_TO (vt_size
, MINT_VT_ALIGNMENT
))
3507 g_error ("%s: CEE_RET: value type stack: %d vs. %d", mono_method_full_name (td
->method
, TRUE
), td
->vt_sp
, vt_size
);
3509 if (sym_seq_points
) {
3510 last_seq_point
= interp_add_ins (td
, MINT_SDB_SEQ_POINT
);
3511 td
->last_ins
->flags
= INTERP_INST_FLAG_SEQ_POINT_METHOD_EXIT
;
3514 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (method
)) {
3515 /* This does the return as well */
3516 interp_add_ins (td
, MINT_TRACE_EXIT
);
3517 if (ult
->type
== MONO_TYPE_VOID
)
3519 WRITE32_INS (td
->last_ins
, 0, &vt_size
);
3523 SIMPLE_OP(td
, ult
->type
== MONO_TYPE_VOID
? MINT_RET_VOID
: MINT_RET
);
3525 interp_add_ins (td
, MINT_RET_VT
);
3526 WRITE32_INS (td
->last_ins
, 0, &vt_size
);
3533 int offset
= read32 (td
->ip
+ 1);
3536 handle_branch (td
, MINT_BR_S
, MINT_BR
, 5 + offset
);
3542 int offset
= (gint8
)td
->ip
[1];
3545 handle_branch (td
, MINT_BR_S
, MINT_BR
, 2 + (gint8
)td
->ip
[1]);
3552 one_arg_branch (td
, MINT_BRFALSE_I4
, 5 + read32 (td
->ip
+ 1));
3557 one_arg_branch (td
, MINT_BRFALSE_I4
, 2 + (gint8
)td
->ip
[1]);
3562 one_arg_branch (td
, MINT_BRTRUE_I4
, 5 + read32 (td
->ip
+ 1));
3567 one_arg_branch (td
, MINT_BRTRUE_I4
, 2 + (gint8
)td
->ip
[1]);
3572 two_arg_branch (td
, MINT_BEQ_I4
, 5 + read32 (td
->ip
+ 1));
3577 two_arg_branch (td
, MINT_BEQ_I4
, 2 + (gint8
) td
->ip
[1]);
3582 two_arg_branch (td
, MINT_BGE_I4
, 5 + read32 (td
->ip
+ 1));
3587 two_arg_branch (td
, MINT_BGE_I4
, 2 + (gint8
) td
->ip
[1]);
3592 two_arg_branch (td
, MINT_BGT_I4
, 5 + read32 (td
->ip
+ 1));
3597 two_arg_branch (td
, MINT_BGT_I4
, 2 + (gint8
) td
->ip
[1]);
3602 two_arg_branch (td
, MINT_BLT_I4
, 5 + read32 (td
->ip
+ 1));
3607 two_arg_branch (td
, MINT_BLT_I4
, 2 + (gint8
) td
->ip
[1]);
3612 two_arg_branch (td
, MINT_BLE_I4
, 5 + read32 (td
->ip
+ 1));
3617 two_arg_branch (td
, MINT_BLE_I4
, 2 + (gint8
) td
->ip
[1]);
3622 two_arg_branch (td
, MINT_BNE_UN_I4
, 5 + read32 (td
->ip
+ 1));
3627 two_arg_branch (td
, MINT_BNE_UN_I4
, 2 + (gint8
) td
->ip
[1]);
3632 two_arg_branch (td
, MINT_BGE_UN_I4
, 5 + read32 (td
->ip
+ 1));
3637 two_arg_branch (td
, MINT_BGE_UN_I4
, 2 + (gint8
) td
->ip
[1]);
3642 two_arg_branch (td
, MINT_BGT_UN_I4
, 5 + read32 (td
->ip
+ 1));
3647 two_arg_branch (td
, MINT_BGT_UN_I4
, 2 + (gint8
) td
->ip
[1]);
3652 two_arg_branch (td
, MINT_BLE_UN_I4
, 5 + read32 (td
->ip
+ 1));
3657 two_arg_branch (td
, MINT_BLE_UN_I4
, 2 + (gint8
) td
->ip
[1]);
3662 two_arg_branch (td
, MINT_BLT_UN_I4
, 5 + read32 (td
->ip
+ 1));
3667 two_arg_branch (td
, MINT_BLT_UN_I4
, 2 + (gint8
) td
->ip
[1]);
3673 const unsigned char *next_ip
;
3675 n
= read32 (td
->ip
);
3676 interp_add_ins_explicit (td
, MINT_SWITCH
, MINT_SWITCH_LEN (n
));
3677 WRITE32_INS (td
->last_ins
, 0, &n
);
3679 next_ip
= td
->ip
+ n
* 4;
3681 int stack_height
= td
->sp
- td
->stack
;
3682 for (i
= 0; i
< n
; i
++) {
3683 offset
= read32 (td
->ip
);
3684 target
= next_ip
- td
->il_code
+ offset
;
3687 if (stack_height
> 0 && stack_height
!= td
->stack_height
[target
])
3688 g_warning ("SWITCH with back branch and non-empty stack");
3691 td
->stack_height
[target
] = stack_height
;
3692 td
->vt_stack_size
[target
] = td
->vt_sp
;
3693 if (stack_height
> 0)
3694 td
->stack_state
[target
] = (StackInfo
*)g_memdup (td
->stack
, stack_height
* sizeof (td
->stack
[0]));
3696 WRITE32_INS (td
->last_ins
, 2 + i
* 2, &target
);
3702 CHECK_STACK (td
, 1);
3703 SIMPLE_OP (td
, MINT_LDIND_I1_CHECK
);
3704 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3705 BARRIER_IF_VOLATILE (td
);
3708 CHECK_STACK (td
, 1);
3709 SIMPLE_OP (td
, MINT_LDIND_U1_CHECK
);
3710 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3711 BARRIER_IF_VOLATILE (td
);
3714 CHECK_STACK (td
, 1);
3715 SIMPLE_OP (td
, MINT_LDIND_I2_CHECK
);
3716 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3717 BARRIER_IF_VOLATILE (td
);
3720 CHECK_STACK (td
, 1);
3721 SIMPLE_OP (td
, MINT_LDIND_U2_CHECK
);
3722 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3723 BARRIER_IF_VOLATILE (td
);
3726 CHECK_STACK (td
, 1);
3727 SIMPLE_OP (td
, MINT_LDIND_I4_CHECK
);
3728 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3729 BARRIER_IF_VOLATILE (td
);
3732 CHECK_STACK (td
, 1);
3733 SIMPLE_OP (td
, MINT_LDIND_U4_CHECK
);
3734 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3735 BARRIER_IF_VOLATILE (td
);
3738 CHECK_STACK (td
, 1);
3739 SIMPLE_OP (td
, MINT_LDIND_I8_CHECK
);
3740 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
3741 BARRIER_IF_VOLATILE (td
);
3744 CHECK_STACK (td
, 1);
3745 SIMPLE_OP (td
, MINT_LDIND_REF_CHECK
);
3746 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I
);
3747 BARRIER_IF_VOLATILE (td
);
3750 CHECK_STACK (td
, 1);
3751 SIMPLE_OP (td
, MINT_LDIND_R4_CHECK
);
3752 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R4
);
3753 BARRIER_IF_VOLATILE (td
);
3756 CHECK_STACK (td
, 1);
3757 SIMPLE_OP (td
, MINT_LDIND_R8_CHECK
);
3758 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
3759 BARRIER_IF_VOLATILE (td
);
3762 CHECK_STACK (td
, 1);
3763 SIMPLE_OP (td
, MINT_LDIND_REF_CHECK
);
3764 BARRIER_IF_VOLATILE (td
);
3765 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_O
);
3768 CHECK_STACK (td
, 2);
3769 BARRIER_IF_VOLATILE (td
);
3770 SIMPLE_OP (td
, MINT_STIND_REF
);
3774 CHECK_STACK (td
, 2);
3775 BARRIER_IF_VOLATILE (td
);
3776 SIMPLE_OP (td
, MINT_STIND_I1
);
3780 CHECK_STACK (td
, 2);
3781 BARRIER_IF_VOLATILE (td
);
3782 SIMPLE_OP (td
, MINT_STIND_I2
);
3786 CHECK_STACK (td
, 2);
3787 BARRIER_IF_VOLATILE (td
);
3788 SIMPLE_OP (td
, MINT_STIND_I4
);
3792 CHECK_STACK (td
, 2);
3793 BARRIER_IF_VOLATILE (td
);
3794 SIMPLE_OP (td
, MINT_STIND_I
);
3798 CHECK_STACK (td
, 2);
3799 BARRIER_IF_VOLATILE (td
);
3800 SIMPLE_OP (td
, MINT_STIND_I8
);
3804 CHECK_STACK (td
, 2);
3805 BARRIER_IF_VOLATILE (td
);
3806 SIMPLE_OP (td
, MINT_STIND_R4
);
3810 CHECK_STACK (td
, 2);
3811 BARRIER_IF_VOLATILE (td
);
3812 SIMPLE_OP (td
, MINT_STIND_R8
);
3816 binary_arith_op(td
, MINT_ADD_I4
);
3820 binary_arith_op(td
, MINT_SUB_I4
);
3824 binary_arith_op(td
, MINT_MUL_I4
);
3828 binary_arith_op(td
, MINT_DIV_I4
);
3832 binary_arith_op(td
, MINT_DIV_UN_I4
);
3836 binary_arith_op (td
, MINT_REM_I4
);
3840 binary_arith_op (td
, MINT_REM_UN_I4
);
3844 binary_arith_op (td
, MINT_AND_I4
);
3848 binary_arith_op (td
, MINT_OR_I4
);
3852 binary_arith_op (td
, MINT_XOR_I4
);
3856 shift_op (td
, MINT_SHL_I4
);
3860 shift_op (td
, MINT_SHR_I4
);
3864 shift_op (td
, MINT_SHR_UN_I4
);
3868 unary_arith_op (td
, MINT_NEG_I4
);
3872 unary_arith_op (td
, MINT_NOT_I4
);
3876 CHECK_STACK (td
, 1);
3877 switch (td
->sp
[-1].type
) {
3879 interp_add_ins (td
, MINT_CONV_U1_R4
);
3882 interp_add_ins (td
, MINT_CONV_U1_R8
);
3885 interp_add_ins (td
, MINT_CONV_U1_I4
);
3888 interp_add_ins (td
, MINT_CONV_U1_I8
);
3891 g_assert_not_reached ();
3894 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3897 CHECK_STACK (td
, 1);
3898 switch (td
->sp
[-1].type
) {
3900 interp_add_ins (td
, MINT_CONV_I1_R4
);
3903 interp_add_ins (td
, MINT_CONV_I1_R8
);
3906 interp_add_ins (td
, MINT_CONV_I1_I4
);
3909 interp_add_ins (td
, MINT_CONV_I1_I8
);
3912 g_assert_not_reached ();
3915 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3918 CHECK_STACK (td
, 1);
3919 switch (td
->sp
[-1].type
) {
3921 interp_add_ins (td
, MINT_CONV_U2_R4
);
3924 interp_add_ins (td
, MINT_CONV_U2_R8
);
3927 interp_add_ins (td
, MINT_CONV_U2_I4
);
3930 interp_add_ins (td
, MINT_CONV_U2_I8
);
3933 g_assert_not_reached ();
3936 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3939 CHECK_STACK (td
, 1);
3940 switch (td
->sp
[-1].type
) {
3942 interp_add_ins (td
, MINT_CONV_I2_R4
);
3945 interp_add_ins (td
, MINT_CONV_I2_R8
);
3948 interp_add_ins (td
, MINT_CONV_I2_I4
);
3951 interp_add_ins (td
, MINT_CONV_I2_I8
);
3954 g_assert_not_reached ();
3957 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3960 CHECK_STACK (td
, 1);
3961 switch (td
->sp
[-1].type
) {
3963 #if SIZEOF_VOID_P == 4
3964 interp_add_ins (td
, MINT_CONV_U4_R8
);
3966 interp_add_ins (td
, MINT_CONV_U8_R8
);
3970 #if SIZEOF_VOID_P == 8
3971 interp_add_ins (td
, MINT_CONV_U8_I4
);
3975 #if SIZEOF_VOID_P == 4
3976 interp_add_ins (td
, MINT_CONV_U4_I8
);
3983 g_assert_not_reached ();
3986 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I
);
3989 CHECK_STACK (td
, 1);
3990 switch (td
->sp
[-1].type
) {
3992 #if SIZEOF_VOID_P == 8
3993 interp_add_ins (td
, MINT_CONV_I8_R8
);
3995 interp_add_ins (td
, MINT_CONV_I4_R8
);
3999 #if SIZEOF_VOID_P == 8
4000 interp_add_ins (td
, MINT_CONV_I8_I4
);
4008 #if SIZEOF_VOID_P == 4
4009 interp_add_ins (td
, MINT_CONV_I4_I8
);
4013 g_assert_not_reached ();
4016 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I
);
4019 CHECK_STACK (td
, 1);
4020 switch (td
->sp
[-1].type
) {
4022 interp_add_ins (td
, MINT_CONV_U4_R4
);
4025 interp_add_ins (td
, MINT_CONV_U4_R8
);
4030 interp_add_ins (td
, MINT_CONV_U4_I8
);
4033 #if SIZEOF_VOID_P == 8
4034 interp_add_ins (td
, MINT_CONV_U4_I8
);
4038 g_assert_not_reached ();
4041 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4044 CHECK_STACK (td
, 1);
4045 switch (td
->sp
[-1].type
) {
4047 interp_add_ins (td
, MINT_CONV_I4_R4
);
4050 interp_add_ins (td
, MINT_CONV_I4_R8
);
4055 interp_add_ins (td
, MINT_CONV_I4_I8
);
4058 #if SIZEOF_VOID_P == 8
4059 interp_add_ins (td
, MINT_CONV_I4_I8
);
4063 g_assert_not_reached ();
4066 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4069 CHECK_STACK (td
, 1);
4070 switch (td
->sp
[-1].type
) {
4072 interp_add_ins (td
, MINT_CONV_I8_R4
);
4075 interp_add_ins (td
, MINT_CONV_I8_R8
);
4077 case STACK_TYPE_I4
: {
4078 if (interp_ins_is_ldc (td
->last_ins
) && (inlining
|| !td
->is_bb_start
[in_offset
])) {
4079 gint64 ct
= interp_ldc_i4_get_const (td
->last_ins
);
4080 interp_clear_ins (td
, td
->last_ins
);
4082 interp_add_ins (td
, MINT_LDC_I8
);
4083 WRITE64_INS (td
->last_ins
, 0, &ct
);
4085 interp_add_ins (td
, MINT_CONV_I8_I4
);
4092 #if SIZEOF_VOID_P == 4
4093 interp_add_ins (td
, MINT_CONV_I8_I4
);
4097 g_assert_not_reached ();
4100 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
4103 CHECK_STACK (td
, 1);
4104 switch (td
->sp
[-1].type
) {
4106 interp_add_ins (td
, MINT_CONV_R4_R8
);
4109 interp_add_ins (td
, MINT_CONV_R4_I8
);
4112 interp_add_ins (td
, MINT_CONV_R4_I4
);
4118 g_assert_not_reached ();
4121 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R4
);
4124 CHECK_STACK (td
, 1);
4125 switch (td
->sp
[-1].type
) {
4127 interp_add_ins (td
, MINT_CONV_R8_I4
);
4130 interp_add_ins (td
, MINT_CONV_R8_I8
);
4133 interp_add_ins (td
, MINT_CONV_R8_R4
);
4138 g_assert_not_reached ();
4141 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
4144 CHECK_STACK (td
, 1);
4145 switch (td
->sp
[-1].type
) {
4147 if (interp_ins_is_ldc (td
->last_ins
) && (inlining
|| !td
->is_bb_start
[in_offset
])) {
4148 gint64 ct
= (guint32
)interp_ldc_i4_get_const (td
->last_ins
);
4149 interp_clear_ins (td
, td
->last_ins
);
4151 interp_add_ins (td
, MINT_LDC_I8
);
4152 WRITE64_INS (td
->last_ins
, 0, &ct
);
4154 interp_add_ins (td
, MINT_CONV_U8_I4
);
4160 interp_add_ins (td
, MINT_CONV_U8_R4
);
4163 interp_add_ins (td
, MINT_CONV_U8_R8
);
4166 #if SIZEOF_VOID_P == 4
4167 interp_add_ins (td
, MINT_CONV_U8_I4
);
4171 g_assert_not_reached ();
4174 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
4177 CHECK_STACK (td
, 2);
4179 token
= read32 (td
->ip
+ 1);
4180 klass
= mono_class_get_and_inflate_typespec_checked (image
, token
, generic_context
, error
);
4181 goto_if_nok (error
, exit
);
4183 if (m_class_is_valuetype (klass
)) {
4184 int mt
= mint_type (m_class_get_byval_arg (klass
));
4185 interp_add_ins (td
, (mt
== MINT_TYPE_VT
) ? MINT_CPOBJ_VT
: MINT_CPOBJ
);
4186 td
->last_ins
->data
[0] = get_data_item_index(td
, klass
);
4188 interp_add_ins (td
, MINT_LDIND_REF
);
4189 interp_add_ins (td
, MINT_STIND_REF
);
4196 CHECK_STACK (td
, 1);
4198 token
= read32 (td
->ip
+ 1);
4200 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4201 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
4203 klass
= mono_class_get_and_inflate_typespec_checked (image
, token
, generic_context
, error
);
4204 goto_if_nok (error
, exit
);
4207 interp_emit_ldobj (td
, klass
);
4210 BARRIER_IF_VOLATILE (td
);
4214 token
= mono_metadata_token_index (read32 (td
->ip
+ 1));
4216 if (method
->wrapper_type
== MONO_WRAPPER_NONE
) {
4217 MonoString
*s
= mono_ldstr_checked (domain
, image
, token
, error
);
4218 goto_if_nok (error
, exit
);
4219 /* GC won't scan code stream, but reference is held by metadata
4220 * machinery so we are good here */
4221 interp_add_ins (td
, MINT_LDSTR
);
4222 td
->last_ins
->data
[0] = get_data_item_index (td
, s
);
4224 /* defer allocation to execution-time */
4225 interp_add_ins (td
, MINT_LDSTR_TOKEN
);
4226 td
->last_ins
->data
[0] = get_data_item_index (td
, GUINT_TO_POINTER (token
));
4228 PUSH_TYPE(td
, STACK_TYPE_O
, mono_defaults
.string_class
);
4233 MonoMethodSignature
*csignature
;
4234 guint32 vt_stack_used
= 0;
4235 guint32 vt_res_size
= 0;
4238 token
= read32 (td
->ip
);
4241 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4242 m
= (MonoMethod
*)mono_method_get_wrapper_data (method
, token
);
4244 m
= mono_get_method_checked (image
, token
, NULL
, generic_context
, error
);
4245 goto_if_nok (error
, exit
);
4248 csignature
= mono_method_signature_internal (m
);
4251 if (!mono_class_init_internal (klass
)) {
4252 mono_error_set_for_class_failure (error
, klass
);
4253 goto_if_nok (error
, exit
);
4256 if (mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_ABSTRACT
) {
4257 char* full_name
= mono_type_get_full_name (klass
);
4258 mono_error_set_member_access (error
, "Cannot create an abstract class: %s", full_name
);
4260 goto_if_nok (error
, exit
);
4263 if (mono_class_is_magic_int (klass
) || mono_class_is_magic_float (klass
)) {
4264 td
->sp
-= csignature
->param_count
;
4265 #if SIZEOF_VOID_P == 8
4266 if (mono_class_is_magic_int (klass
) && td
->sp
[0].type
== STACK_TYPE_I4
)
4267 interp_add_ins (td
, MINT_CONV_I8_I4
);
4268 else if (mono_class_is_magic_float (klass
) && td
->sp
[0].type
== STACK_TYPE_R4
)
4269 interp_add_ins (td
, MINT_CONV_R8_R4
);
4271 interp_add_ins (td
, MINT_NEWOBJ_MAGIC
);
4272 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
4273 goto_if_nok (error
, exit
);
4275 PUSH_TYPE (td
, stack_type
[mint_type (m_class_get_byval_arg (klass
))], klass
);
4277 if (m_class_get_parent (klass
) == mono_defaults
.array_class
) {
4278 interp_add_ins (td
, MINT_NEWOBJ_ARRAY
);
4279 td
->last_ins
->data
[0] = get_data_item_index (td
, m
->klass
);
4280 td
->last_ins
->data
[1] = csignature
->param_count
;
4281 } else if (m_class_get_image (klass
) == mono_defaults
.corlib
&&
4282 !strcmp (m_class_get_name (m
->klass
), "ByReference`1") &&
4283 !strcmp (m
->name
, ".ctor")) {
4284 /* public ByReference(ref T value) */
4285 g_assert (csignature
->hasthis
&& csignature
->param_count
== 1);
4286 interp_add_ins (td
, MINT_INTRINS_BYREFERENCE_CTOR
);
4287 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
4288 } else if (klass
!= mono_defaults
.string_class
&&
4289 !mono_class_is_marshalbyref (klass
) &&
4290 !mono_class_has_finalizer (klass
) &&
4291 !m_class_has_weak_fields (klass
)) {
4292 if (!m_class_is_valuetype (klass
)) {
4293 InterpInst
*newobj_fast
= interp_add_ins (td
, MINT_NEWOBJ_FAST
);
4295 newobj_fast
->data
[1] = csignature
->param_count
;
4297 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, klass
, error
);
4298 goto_if_nok (error
, exit
);
4299 newobj_fast
->data
[2] = get_data_item_index (td
, vtable
);
4301 move_stack (td
, (td
->sp
- td
->stack
) - csignature
->param_count
, 2);
4303 StackInfo
*tmp_sp
= td
->sp
- csignature
->param_count
- 2;
4304 SET_TYPE (tmp_sp
, STACK_TYPE_O
, klass
);
4305 SET_TYPE (tmp_sp
+ 1, STACK_TYPE_O
, klass
);
4307 if ((mono_interp_opt
& INTERP_OPT_INLINE
) && interp_method_check_inlining (td
, m
)) {
4308 MonoMethodHeader
*mheader
= interp_method_get_header (m
, error
);
4309 goto_if_nok (error
, exit
);
4311 if (interp_inline_method (td
, m
, mheader
, error
)) {
4312 newobj_fast
->data
[0] = 0xffff;
4316 // If inlining failed we need to restore the stack
4317 move_stack (td
, (td
->sp
- td
->stack
) - csignature
->param_count
, -2);
4318 // Set the method to be executed as part of newobj instruction
4319 newobj_fast
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
4321 if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
)
4322 interp_add_ins (td
, MINT_NEWOBJ_VTST_FAST
);
4324 interp_add_ins (td
, MINT_NEWOBJ_VT_FAST
);
4326 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
4327 td
->last_ins
->data
[1] = csignature
->param_count
;
4329 if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
) {
4330 td
->last_ins
->data
[2] = mono_class_value_size (klass
, NULL
);
4334 interp_add_ins (td
, MINT_NEWOBJ
);
4335 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
4337 goto_if_nok (error
, exit
);
4338 /* The constructor was not inlined, abort inlining of current method */
4341 td
->sp
-= csignature
->param_count
;
4342 if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
) {
4343 vt_res_size
= mono_class_value_size (klass
, NULL
);
4344 PUSH_VT (td
, vt_res_size
);
4346 for (i
= 0; i
< csignature
->param_count
; ++i
) {
4347 int mt
= mint_type(csignature
->params
[i
]);
4348 if (mt
== MINT_TYPE_VT
) {
4349 MonoClass
*k
= mono_class_from_mono_type_internal (csignature
->params
[i
]);
4350 gint32 size
= mono_class_value_size (k
, NULL
);
4351 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4352 vt_stack_used
+= size
;
4355 if (vt_stack_used
!= 0 || vt_res_size
!= 0) {
4356 interp_add_ins (td
, MINT_VTRESULT
);
4357 td
->last_ins
->data
[0] = vt_res_size
;
4358 WRITE32_INS (td
->last_ins
, 1, &vt_stack_used
);
4359 td
->vt_sp
-= vt_stack_used
;
4361 PUSH_TYPE (td
, stack_type
[mint_type (m_class_get_byval_arg (klass
))], klass
);
4367 gboolean isinst_instr
= *td
->ip
== CEE_ISINST
;
4368 CHECK_STACK (td
, 1);
4369 token
= read32 (td
->ip
+ 1);
4370 klass
= mini_get_class (method
, token
, generic_context
);
4371 CHECK_TYPELOAD (klass
);
4372 interp_handle_isinst (td
, klass
, isinst_instr
);
4374 td
->sp
[-1].klass
= klass
;
4378 switch (td
->sp
[-1].type
) {
4382 interp_add_ins (td
, MINT_CONV_R_UN_I8
);
4385 interp_add_ins (td
, MINT_CONV_R_UN_I4
);
4388 g_assert_not_reached ();
4390 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
4394 CHECK_STACK (td
, 1);
4395 token
= read32 (td
->ip
+ 1);
4397 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4398 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
4400 klass
= mono_class_get_and_inflate_typespec_checked (image
, token
, generic_context
, error
);
4401 goto_if_nok (error
, exit
);
4404 if (mono_class_is_nullable (klass
)) {
4405 MonoMethod
*target_method
;
4406 if (m_class_is_enumtype (mono_class_get_nullable_param_internal (klass
)))
4407 target_method
= mono_class_get_method_from_name_checked (klass
, "UnboxExact", 1, 0, error
);
4409 target_method
= mono_class_get_method_from_name_checked (klass
, "Unbox", 1, 0, error
);
4410 goto_if_nok (error
, exit
);
4411 /* td->ip is incremented by interp_transform_call */
4412 if (!interp_transform_call (td
, method
, target_method
, domain
, generic_context
, td
->is_bb_start
, NULL
, FALSE
, error
, FALSE
, FALSE
))
4415 * CEE_UNBOX needs to push address of vtype while Nullable.Unbox returns the value type
4416 * We create a local variable in the frame so that we can fetch its address.
4418 int local
= create_interp_local (td
, m_class_get_byval_arg (klass
));
4419 store_local_general (td
, local
, m_class_get_byval_arg (klass
));
4420 interp_add_ins (td
, MINT_LDLOCA_S
);
4421 td
->last_ins
->data
[0] = local
;
4422 td
->locals
[local
].flags
|= INTERP_LOCAL_FLAG_INDIRECT
;
4423 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_MP
);
4425 interp_add_ins (td
, MINT_UNBOX
);
4426 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
4427 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_MP
);
4432 CHECK_STACK (td
, 1);
4433 token
= read32 (td
->ip
+ 1);
4435 klass
= mini_get_class (method
, token
, generic_context
);
4436 CHECK_TYPELOAD (klass
);
4438 if (mini_type_is_reference (m_class_get_byval_arg (klass
))) {
4439 int mt
= mint_type (m_class_get_byval_arg (klass
));
4440 interp_handle_isinst (td
, klass
, FALSE
);
4441 SET_TYPE (td
->sp
- 1, stack_type
[mt
], klass
);
4442 } else if (mono_class_is_nullable (klass
)) {
4443 MonoMethod
*target_method
;
4444 if (m_class_is_enumtype (mono_class_get_nullable_param_internal (klass
)))
4445 target_method
= mono_class_get_method_from_name_checked (klass
, "UnboxExact", 1, 0, error
);
4447 target_method
= mono_class_get_method_from_name_checked (klass
, "Unbox", 1, 0, error
);
4448 goto_if_nok (error
, exit
);
4449 /* td->ip is incremented by interp_transform_call */
4450 if (!interp_transform_call (td
, method
, target_method
, domain
, generic_context
, td
->is_bb_start
, NULL
, FALSE
, error
, FALSE
, FALSE
))
4453 interp_add_ins (td
, MINT_UNBOX
);
4454 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
4456 interp_emit_ldobj (td
, klass
);
4464 CHECK_STACK (td
, 1);
4465 SIMPLE_OP (td
, MINT_THROW
);
4469 CHECK_STACK (td
, 1);
4470 token
= read32 (td
->ip
+ 1);
4471 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
4472 goto_if_nok (error
, exit
);
4473 MonoType
*ftype
= mono_field_get_type_internal (field
);
4474 gboolean is_static
= !!(ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
);
4475 mono_class_init_internal (klass
);
4476 #ifndef DISABLE_REMOTING
4477 if (m_class_get_marshalbyref (klass
) || mono_class_is_contextbound (klass
) || klass
== mono_defaults
.marshalbyrefobject_class
) {
4478 g_assert (!is_static
);
4479 int offset
= m_class_is_valuetype (klass
) ? field
->offset
- MONO_ABI_SIZEOF (MonoObject
) : field
->offset
;
4481 interp_add_ins (td
, MINT_MONO_LDPTR
);
4482 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
4483 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
4484 interp_add_ins (td
, MINT_MONO_LDPTR
);
4485 td
->last_ins
->data
[0] = get_data_item_index (td
, field
);
4486 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
4487 interp_add_ins (td
, MINT_LDC_I4
);
4488 WRITE32_INS (td
->last_ins
, 0, &offset
);
4489 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I4
);
4490 #if SIZEOF_VOID_P == 8
4491 interp_add_ins (td
, MINT_CONV_I8_I4
);
4494 MonoMethod
*wrapper
= mono_marshal_get_ldflda_wrapper (field
->type
);
4495 /* td->ip is incremented by interp_transform_call */
4496 if (!interp_transform_call (td
, method
, wrapper
, domain
, generic_context
, td
->is_bb_start
, NULL
, FALSE
, error
, FALSE
, FALSE
))
4502 interp_add_ins (td
, MINT_POP
);
4503 td
->last_ins
->data
[0] = 0;
4504 interp_emit_ldsflda (td
, field
, error
);
4505 goto_if_nok (error
, exit
);
4507 if ((td
->sp
- 1)->type
== STACK_TYPE_O
) {
4508 interp_add_ins (td
, MINT_LDFLDA
);
4510 g_assert ((td
->sp
-1)->type
== STACK_TYPE_MP
);
4511 interp_add_ins (td
, MINT_LDFLDA_UNSAFE
);
4513 td
->last_ins
->data
[0] = m_class_is_valuetype (klass
) ? field
->offset
- MONO_ABI_SIZEOF (MonoObject
) : field
->offset
;
4517 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
4521 CHECK_STACK (td
, 1);
4522 token
= read32 (td
->ip
+ 1);
4523 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
4524 goto_if_nok (error
, exit
);
4525 MonoType
*ftype
= mono_field_get_type_internal (field
);
4526 gboolean is_static
= !!(ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
);
4527 mono_class_init_internal (klass
);
4529 MonoClass
*field_klass
= mono_class_from_mono_type_internal (ftype
);
4530 mt
= mint_type (m_class_get_byval_arg (field_klass
));
4531 #ifndef DISABLE_REMOTING
4532 if (m_class_get_marshalbyref (klass
)) {
4533 g_assert (!is_static
);
4534 interp_add_ins (td
, mt
== MINT_TYPE_VT
? MINT_LDRMFLD_VT
: MINT_LDRMFLD
);
4535 td
->last_ins
->data
[0] = get_data_item_index (td
, field
);
4540 interp_add_ins (td
, MINT_POP
);
4541 td
->last_ins
->data
[0] = 0;
4542 interp_emit_sfld_access (td
, field
, field_klass
, mt
, TRUE
, error
);
4543 goto_if_nok (error
, exit
);
4545 int opcode
= MINT_LDFLD_I1
+ mt
- MINT_TYPE_I1
;
4546 #ifdef NO_UNALIGNED_ACCESS
4547 if ((mt
== MINT_TYPE_I8
|| mt
== MINT_TYPE_R8
) && field
->offset
% SIZEOF_VOID_P
!= 0)
4548 opcode
= get_unaligned_opcode (opcode
);
4550 interp_add_ins (td
, opcode
);
4551 td
->last_ins
->data
[0] = m_class_is_valuetype (klass
) ? field
->offset
- MONO_ABI_SIZEOF (MonoObject
) : field
->offset
;
4552 if (mt
== MINT_TYPE_VT
) {
4553 int size
= mono_class_value_size (field_klass
, NULL
);
4554 WRITE32_INS (td
->last_ins
, 1, &size
);
4558 if (mt
== MINT_TYPE_VT
) {
4559 int size
= mono_class_value_size (field_klass
, NULL
);
4562 if (td
->sp
[-1].type
== STACK_TYPE_VT
) {
4563 int size
= mono_class_value_size (klass
, NULL
);
4564 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4565 int field_vt_size
= 0;
4566 if (mt
== MINT_TYPE_VT
) {
4568 * Pop the loaded field from the vtstack (it will still be present
4569 * at the same vtstack address) and we will load it in place of the
4570 * containing valuetype with the second MINT_VTRESULT.
4572 field_vt_size
= mono_class_value_size (field_klass
, NULL
);
4573 field_vt_size
= ALIGN_TO (field_vt_size
, MINT_VT_ALIGNMENT
);
4574 interp_add_ins (td
, MINT_VTRESULT
);
4575 td
->last_ins
->data
[0] = 0;
4576 WRITE32_INS (td
->last_ins
, 1, &field_vt_size
);
4579 interp_add_ins (td
, MINT_VTRESULT
);
4580 td
->last_ins
->data
[0] = field_vt_size
;
4581 WRITE32_INS (td
->last_ins
, 1, &size
);
4584 SET_TYPE (td
->sp
- 1, stack_type
[mt
], field_klass
);
4585 BARRIER_IF_VOLATILE (td
);
4589 CHECK_STACK (td
, 2);
4590 token
= read32 (td
->ip
+ 1);
4591 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
4592 goto_if_nok (error
, exit
);
4593 MonoType
*ftype
= mono_field_get_type_internal (field
);
4594 gboolean is_static
= !!(ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
);
4595 MonoClass
*field_klass
= mono_class_from_mono_type_internal (ftype
);
4596 mono_class_init_internal (klass
);
4597 mt
= mint_type (ftype
);
4599 BARRIER_IF_VOLATILE (td
);
4601 #ifndef DISABLE_REMOTING
4602 if (m_class_get_marshalbyref (klass
)) {
4603 g_assert (!is_static
);
4604 interp_add_ins (td
, mt
== MINT_TYPE_VT
? MINT_STRMFLD_VT
: MINT_STRMFLD
);
4605 td
->last_ins
->data
[0] = get_data_item_index (td
, field
);
4610 interp_add_ins (td
, MINT_POP
);
4611 td
->last_ins
->data
[0] = 1;
4612 interp_emit_sfld_access (td
, field
, field_klass
, mt
, FALSE
, error
);
4613 goto_if_nok (error
, exit
);
4615 /* the vtable of the field might not be initialized at this point */
4616 mono_class_vtable_checked (domain
, field_klass
, error
);
4617 goto_if_nok (error
, exit
);
4619 int opcode
= MINT_STFLD_I1
+ mt
- MINT_TYPE_I1
;
4620 #ifdef NO_UNALIGNED_ACCESS
4621 if ((mt
== MINT_TYPE_I8
|| mt
== MINT_TYPE_R8
) && field
->offset
% SIZEOF_VOID_P
!= 0)
4622 opcode
= get_unaligned_opcode (opcode
);
4624 interp_add_ins (td
, opcode
);
4625 td
->last_ins
->data
[0] = m_class_is_valuetype (klass
) ? field
->offset
- MONO_ABI_SIZEOF (MonoObject
) : field
->offset
;
4626 if (mt
== MINT_TYPE_VT
) {
4627 /* the vtable of the field might not be initialized at this point */
4628 mono_class_vtable_checked (domain
, field_klass
, error
);
4629 goto_if_nok (error
, exit
);
4631 td
->last_ins
->data
[1] = get_data_item_index (td
, field_klass
);
4635 if (mt
== MINT_TYPE_VT
) {
4636 int size
= mono_class_value_size (field_klass
, NULL
);
4644 token
= read32 (td
->ip
+ 1);
4645 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
4646 goto_if_nok (error
, exit
);
4647 interp_emit_ldsflda (td
, field
, error
);
4648 goto_if_nok (error
, exit
);
4650 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
4654 token
= read32 (td
->ip
+ 1);
4655 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
4656 goto_if_nok (error
, exit
);
4657 MonoType
*ftype
= mono_field_get_type_internal (field
);
4658 mt
= mint_type (ftype
);
4659 klass
= mono_class_from_mono_type_internal (ftype
);
4661 interp_emit_sfld_access (td
, field
, klass
, mt
, TRUE
, error
);
4662 goto_if_nok (error
, exit
);
4664 if (mt
== MINT_TYPE_VT
) {
4665 int size
= mono_class_value_size (klass
, NULL
);
4669 PUSH_TYPE(td
, stack_type
[mt
], klass
);
4673 CHECK_STACK (td
, 1);
4674 token
= read32 (td
->ip
+ 1);
4675 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
4676 goto_if_nok (error
, exit
);
4677 MonoType
*ftype
= mono_field_get_type_internal (field
);
4678 mt
= mint_type (ftype
);
4680 /* the vtable of the field might not be initialized at this point */
4681 MonoClass
*fld_klass
= mono_class_from_mono_type_internal (ftype
);
4682 mono_class_vtable_checked (domain
, fld_klass
, error
);
4683 goto_if_nok (error
, exit
);
4685 interp_emit_sfld_access (td
, field
, fld_klass
, mt
, FALSE
, error
);
4686 goto_if_nok (error
, exit
);
4688 if (mt
== MINT_TYPE_VT
) {
4689 int size
= mono_class_value_size (fld_klass
, NULL
);
4697 token
= read32 (td
->ip
+ 1);
4699 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4700 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
4702 klass
= mini_get_class (method
, token
, generic_context
);
4703 CHECK_TYPELOAD (klass
);
4705 BARRIER_IF_VOLATILE (td
);
4707 interp_emit_stobj (td
, klass
);
4712 case CEE_CONV_OVF_I_UN
:
4713 case CEE_CONV_OVF_U_UN
:
4714 CHECK_STACK (td
, 1);
4715 switch (td
->sp
[-1].type
) {
4717 #if SIZEOF_VOID_P == 8
4718 interp_add_ins (td
, MINT_CONV_OVF_I8_UN_R8
);
4720 interp_add_ins (td
, MINT_CONV_OVF_I4_UN_R8
);
4724 #if SIZEOF_VOID_P == 4
4725 interp_add_ins (td
, MINT_CONV_OVF_I4_UN_I8
);
4729 #if SIZEOF_VOID_P == 8
4730 interp_add_ins (td
, MINT_CONV_I8_U4
);
4731 #elif SIZEOF_VOID_P == 4
4732 if (*td
->ip
== CEE_CONV_OVF_I_UN
)
4733 interp_add_ins (td
, MINT_CONV_OVF_I4_U4
);
4737 g_assert_not_reached ();
4740 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
4743 case CEE_CONV_OVF_I8_UN
:
4744 case CEE_CONV_OVF_U8_UN
:
4745 CHECK_STACK (td
, 1);
4746 switch (td
->sp
[-1].type
) {
4748 interp_add_ins (td
, MINT_CONV_OVF_I8_UN_R8
);
4751 if (*td
->ip
== CEE_CONV_OVF_I8_UN
)
4752 interp_add_ins (td
, MINT_CONV_OVF_I8_U8
);
4755 interp_add_ins (td
, MINT_CONV_I8_U4
);
4758 interp_add_ins (td
, MINT_CONV_OVF_I8_UN_R4
);
4761 g_assert_not_reached ();
4764 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
4769 CHECK_STACK (td
, 1);
4770 token
= read32 (td
->ip
+ 1);
4771 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4772 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
4774 klass
= mini_get_class (method
, token
, generic_context
);
4775 CHECK_TYPELOAD (klass
);
4777 if (mono_class_is_nullable (klass
)) {
4778 MonoMethod
*target_method
= mono_class_get_method_from_name_checked (klass
, "Box", 1, 0, error
);
4779 goto_if_nok (error
, exit
);
4780 /* td->ip is incremented by interp_transform_call */
4781 if (!interp_transform_call (td
, method
, target_method
, domain
, generic_context
, td
->is_bb_start
, NULL
, FALSE
, error
, FALSE
, FALSE
))
4783 } else if (!m_class_is_valuetype (klass
)) {
4784 /* already boxed, do nothing. */
4787 if (G_UNLIKELY (m_class_is_byreflike (klass
))) {
4788 mono_error_set_bad_image (error
, image
, "Cannot box IsByRefLike type '%s.%s'", m_class_get_name_space (klass
), m_class_get_name (klass
));
4791 if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
) {
4792 size
= mono_class_value_size (klass
, NULL
);
4793 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4795 } else if (td
->sp
[-1].type
== STACK_TYPE_R8
&& m_class_get_byval_arg (klass
)->type
== MONO_TYPE_R4
) {
4796 interp_add_ins (td
, MINT_CONV_R4_R8
);
4798 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, klass
, error
);
4799 goto_if_nok (error
, exit
);
4801 if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
)
4802 interp_add_ins (td
, MINT_BOX_VT
);
4804 interp_add_ins (td
, MINT_BOX
);
4805 td
->last_ins
->data
[0] = get_data_item_index (td
, vtable
);
4806 td
->last_ins
->data
[1] = 0;
4807 SET_TYPE(td
->sp
- 1, STACK_TYPE_O
, klass
);
4814 CHECK_STACK (td
, 1);
4815 token
= read32 (td
->ip
+ 1);
4817 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4818 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
4820 klass
= mini_get_class (method
, token
, generic_context
);
4821 CHECK_TYPELOAD (klass
);
4823 MonoClass
*array_class
= mono_class_create_array (klass
, 1);
4824 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, array_class
, error
);
4825 goto_if_nok (error
, exit
);
4827 unsigned char lentype
= (td
->sp
- 1)->type
;
4828 if (lentype
== STACK_TYPE_I8
) {
4829 /* mimic mini behaviour */
4830 interp_add_ins (td
, MINT_CONV_OVF_U4_I8
);
4832 g_assert (lentype
== STACK_TYPE_I4
);
4833 interp_add_ins (td
, MINT_CONV_OVF_U4_I4
);
4835 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I4
);
4836 interp_add_ins (td
, MINT_NEWARR
);
4837 td
->last_ins
->data
[0] = get_data_item_index (td
, vtable
);
4838 SET_TYPE (td
->sp
- 1, STACK_TYPE_O
, array_class
);
4843 CHECK_STACK (td
, 1);
4844 SIMPLE_OP (td
, MINT_LDLEN
);
4845 #ifdef MONO_BIG_ARRAYS
4846 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I8
);
4848 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I4
);
4853 CHECK_STACK (td
, 2);
4855 token
= read32 (td
->ip
+ 1);
4857 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4858 klass
= (MonoClass
*) mono_method_get_wrapper_data (method
, token
);
4860 klass
= mini_get_class (method
, token
, generic_context
);
4862 CHECK_TYPELOAD (klass
);
4864 if (!m_class_is_valuetype (klass
) && method
->wrapper_type
== MONO_WRAPPER_NONE
&& !readonly
) {
4866 * Check the class for failures before the type check, which can
4867 * throw other exceptions.
4869 mono_class_setup_vtable (klass
);
4870 CHECK_TYPELOAD (klass
);
4871 interp_add_ins (td
, MINT_LDELEMA_TC
);
4872 td
->last_ins
->data
[0] = 1;
4873 td
->last_ins
->data
[1] = get_data_item_index (td
, klass
);
4875 interp_add_ins (td
, MINT_LDELEMA1
);
4876 mono_class_init_internal (klass
);
4877 size
= mono_class_array_element_size (klass
);
4878 WRITE32_INS (td
->last_ins
, 0, &size
);
4885 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
4889 CHECK_STACK (td
, 2);
4891 SIMPLE_OP (td
, MINT_LDELEM_I1
);
4893 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4896 CHECK_STACK (td
, 2);
4898 SIMPLE_OP (td
, MINT_LDELEM_U1
);
4900 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4903 CHECK_STACK (td
, 2);
4905 SIMPLE_OP (td
, MINT_LDELEM_I2
);
4907 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4910 CHECK_STACK (td
, 2);
4912 SIMPLE_OP (td
, MINT_LDELEM_U2
);
4914 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4917 CHECK_STACK (td
, 2);
4919 SIMPLE_OP (td
, MINT_LDELEM_I4
);
4921 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4924 CHECK_STACK (td
, 2);
4926 SIMPLE_OP (td
, MINT_LDELEM_U4
);
4928 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4931 CHECK_STACK (td
, 2);
4933 SIMPLE_OP (td
, MINT_LDELEM_I8
);
4935 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
4938 CHECK_STACK (td
, 2);
4940 SIMPLE_OP (td
, MINT_LDELEM_I
);
4942 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I
);
4945 CHECK_STACK (td
, 2);
4947 SIMPLE_OP (td
, MINT_LDELEM_R4
);
4949 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R4
);
4952 CHECK_STACK (td
, 2);
4954 SIMPLE_OP (td
, MINT_LDELEM_R8
);
4956 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
4958 case CEE_LDELEM_REF
:
4959 CHECK_STACK (td
, 2);
4961 SIMPLE_OP (td
, MINT_LDELEM_REF
);
4963 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_O
);
4966 CHECK_STACK (td
, 2);
4967 token
= read32 (td
->ip
+ 1);
4968 klass
= mini_get_class (method
, token
, generic_context
);
4969 CHECK_TYPELOAD (klass
);
4970 switch (mint_type (m_class_get_byval_arg (klass
))) {
4973 SIMPLE_OP (td
, MINT_LDELEM_I1
);
4975 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4979 SIMPLE_OP (td
, MINT_LDELEM_U1
);
4981 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4985 SIMPLE_OP (td
, MINT_LDELEM_U2
);
4987 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4991 SIMPLE_OP (td
, MINT_LDELEM_I2
);
4993 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4997 SIMPLE_OP (td
, MINT_LDELEM_I4
);
4999 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5003 SIMPLE_OP (td
, MINT_LDELEM_I8
);
5005 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
5009 SIMPLE_OP (td
, MINT_LDELEM_R4
);
5011 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R4
);
5015 SIMPLE_OP (td
, MINT_LDELEM_R8
);
5017 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
5021 SIMPLE_OP (td
, MINT_LDELEM_REF
);
5023 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_O
);
5025 case MINT_TYPE_VT
: {
5026 int size
= mono_class_value_size (klass
, NULL
);
5028 SIMPLE_OP (td
, MINT_LDELEM_VT
);
5029 WRITE32_INS (td
->last_ins
, 0, &size
);
5031 SET_TYPE (td
->sp
- 1, STACK_TYPE_VT
, klass
);
5036 GString
*res
= g_string_new ("");
5037 mono_type_get_desc (res
, m_class_get_byval_arg (klass
), TRUE
);
5038 g_print ("LDELEM: %s -> %d (%s)\n", m_class_get_name (klass
), mint_type (m_class_get_byval_arg (klass
)), res
->str
);
5039 g_string_free (res
, TRUE
);
5047 CHECK_STACK (td
, 3);
5049 SIMPLE_OP (td
, MINT_STELEM_I
);
5053 CHECK_STACK (td
, 3);
5055 SIMPLE_OP (td
, MINT_STELEM_I1
);
5059 CHECK_STACK (td
, 3);
5061 SIMPLE_OP (td
, MINT_STELEM_I2
);
5065 CHECK_STACK (td
, 3);
5067 SIMPLE_OP (td
, MINT_STELEM_I4
);
5071 CHECK_STACK (td
, 3);
5073 SIMPLE_OP (td
, MINT_STELEM_I8
);
5077 CHECK_STACK (td
, 3);
5079 SIMPLE_OP (td
, MINT_STELEM_R4
);
5083 CHECK_STACK (td
, 3);
5085 SIMPLE_OP (td
, MINT_STELEM_R8
);
5088 case CEE_STELEM_REF
:
5089 CHECK_STACK (td
, 3);
5091 SIMPLE_OP (td
, MINT_STELEM_REF
);
5095 CHECK_STACK (td
, 3);
5097 token
= read32 (td
->ip
+ 1);
5098 klass
= mini_get_class (method
, token
, generic_context
);
5099 CHECK_TYPELOAD (klass
);
5100 switch (mint_type (m_class_get_byval_arg (klass
))) {
5102 SIMPLE_OP (td
, MINT_STELEM_I1
);
5105 SIMPLE_OP (td
, MINT_STELEM_U1
);
5108 SIMPLE_OP (td
, MINT_STELEM_I2
);
5111 SIMPLE_OP (td
, MINT_STELEM_U2
);
5114 SIMPLE_OP (td
, MINT_STELEM_I4
);
5117 SIMPLE_OP (td
, MINT_STELEM_I8
);
5120 SIMPLE_OP (td
, MINT_STELEM_R4
);
5123 SIMPLE_OP (td
, MINT_STELEM_R8
);
5126 SIMPLE_OP (td
, MINT_STELEM_REF
);
5128 case MINT_TYPE_VT
: {
5129 int size
= mono_class_value_size (klass
, NULL
);
5130 SIMPLE_OP (td
, MINT_STELEM_VT
);
5131 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
5132 WRITE32_INS (td
->last_ins
, 1, &size
);
5137 GString
*res
= g_string_new ("");
5138 mono_type_get_desc (res
, m_class_get_byval_arg (klass
), TRUE
);
5139 g_print ("STELEM: %s -> %d (%s)\n", m_class_get_name (klass
), mint_type (m_class_get_byval_arg (klass
)), res
->str
);
5140 g_string_free (res
, TRUE
);
5149 case CEE_CONV_OVF_U1
:
5151 case CEE_CONV_OVF_I8
:
5153 #if SIZEOF_VOID_P == 8
5154 case CEE_CONV_OVF_U
:
5158 CHECK_STACK (td
, 1);
5159 SIMPLE_OP (td
, MINT_CKFINITE
);
5162 CHECK_STACK (td
, 1);
5164 token
= read32 (td
->ip
+ 1);
5165 klass
= mini_get_class (method
, token
, generic_context
);
5166 CHECK_TYPELOAD (klass
);
5168 interp_add_ins (td
, MINT_MKREFANY
);
5169 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
5172 PUSH_VT (td
, sizeof (MonoTypedRef
));
5173 SET_TYPE(td
->sp
- 1, STACK_TYPE_VT
, mono_defaults
.typed_reference_class
);
5175 case CEE_REFANYVAL
: {
5176 CHECK_STACK (td
, 1);
5178 token
= read32 (td
->ip
+ 1);
5179 klass
= mini_get_class (method
, token
, generic_context
);
5180 CHECK_TYPELOAD (klass
);
5182 interp_add_ins (td
, MINT_REFANYVAL
);
5183 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
5185 POP_VT (td
, sizeof (MonoTypedRef
));
5186 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
5191 case CEE_CONV_OVF_I1
:
5192 case CEE_CONV_OVF_I1_UN
: {
5193 gboolean is_un
= *td
->ip
== CEE_CONV_OVF_I1_UN
;
5194 CHECK_STACK (td
, 1);
5195 switch (td
->sp
[-1].type
) {
5197 interp_add_ins (td
, is_un
? MINT_CONV_OVF_I1_UN_R8
: MINT_CONV_OVF_I1_R8
);
5200 interp_add_ins (td
, is_un
? MINT_CONV_OVF_I1_U4
: MINT_CONV_OVF_I1_I4
);
5203 interp_add_ins (td
, is_un
? MINT_CONV_OVF_I1_U8
: MINT_CONV_OVF_I1_I8
);
5206 g_assert_not_reached ();
5209 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5212 case CEE_CONV_OVF_U1
:
5213 case CEE_CONV_OVF_U1_UN
:
5214 CHECK_STACK (td
, 1);
5215 switch (td
->sp
[-1].type
) {
5217 interp_add_ins (td
, MINT_CONV_OVF_U1_R8
);
5220 interp_add_ins (td
, MINT_CONV_OVF_U1_I4
);
5223 interp_add_ins (td
, MINT_CONV_OVF_U1_I8
);
5226 g_assert_not_reached ();
5229 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5231 case CEE_CONV_OVF_I2
:
5232 case CEE_CONV_OVF_I2_UN
: {
5233 gboolean is_un
= *td
->ip
== CEE_CONV_OVF_I2_UN
;
5234 CHECK_STACK (td
, 1);
5235 switch (td
->sp
[-1].type
) {
5237 interp_add_ins (td
, is_un
? MINT_CONV_OVF_I2_UN_R8
: MINT_CONV_OVF_I2_R8
);
5240 interp_add_ins (td
, is_un
? MINT_CONV_OVF_I2_U4
: MINT_CONV_OVF_I2_I4
);
5243 interp_add_ins (td
, is_un
? MINT_CONV_OVF_I2_U8
: MINT_CONV_OVF_I2_I8
);
5246 g_assert_not_reached ();
5249 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5252 case CEE_CONV_OVF_U2_UN
:
5253 case CEE_CONV_OVF_U2
:
5254 CHECK_STACK (td
, 1);
5255 switch (td
->sp
[-1].type
) {
5257 interp_add_ins (td
, MINT_CONV_OVF_U2_R8
);
5260 interp_add_ins (td
, MINT_CONV_OVF_U2_I4
);
5263 interp_add_ins (td
, MINT_CONV_OVF_U2_I8
);
5266 g_assert_not_reached ();
5269 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5271 #if SIZEOF_VOID_P == 4
5272 case CEE_CONV_OVF_I
:
5274 case CEE_CONV_OVF_I4
:
5275 case CEE_CONV_OVF_I4_UN
:
5276 CHECK_STACK (td
, 1);
5277 switch (td
->sp
[-1].type
) {
5279 interp_add_ins (td
, MINT_CONV_OVF_I4_R4
);
5282 interp_add_ins (td
, MINT_CONV_OVF_I4_R8
);
5285 if (*td
->ip
== CEE_CONV_OVF_I4_UN
)
5286 interp_add_ins (td
, MINT_CONV_OVF_I4_U4
);
5289 if (*td
->ip
== CEE_CONV_OVF_I4_UN
)
5290 interp_add_ins (td
, MINT_CONV_OVF_I4_U8
);
5292 interp_add_ins (td
, MINT_CONV_OVF_I4_I8
);
5295 g_assert_not_reached ();
5298 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5300 #if SIZEOF_VOID_P == 4
5301 case CEE_CONV_OVF_U
:
5303 case CEE_CONV_OVF_U4
:
5304 case CEE_CONV_OVF_U4_UN
:
5305 CHECK_STACK (td
, 1);
5306 switch (td
->sp
[-1].type
) {
5308 interp_add_ins (td
, MINT_CONV_OVF_U4_R4
);
5311 interp_add_ins (td
, MINT_CONV_OVF_U4_R8
);
5314 if (*td
->ip
!= CEE_CONV_OVF_U4_UN
)
5315 interp_add_ins (td
, MINT_CONV_OVF_U4_I4
);
5318 interp_add_ins (td
, MINT_CONV_OVF_U4_I8
);
5321 interp_add_ins (td
, MINT_CONV_OVF_U4_P
);
5324 g_assert_not_reached ();
5327 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5329 #if SIZEOF_VOID_P == 8
5330 case CEE_CONV_OVF_I
:
5332 case CEE_CONV_OVF_I8
:
5333 CHECK_STACK (td
, 1);
5334 switch (td
->sp
[-1].type
) {
5336 interp_add_ins (td
, MINT_CONV_OVF_I8_R4
);
5339 interp_add_ins (td
, MINT_CONV_OVF_I8_R8
);
5342 interp_add_ins (td
, MINT_CONV_I8_I4
);
5347 g_assert_not_reached ();
5350 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
5352 #if SIZEOF_VOID_P == 8
5353 case CEE_CONV_OVF_U
:
5355 case CEE_CONV_OVF_U8
:
5356 CHECK_STACK (td
, 1);
5357 switch (td
->sp
[-1].type
) {
5359 interp_add_ins (td
, MINT_CONV_OVF_U8_R4
);
5362 interp_add_ins (td
, MINT_CONV_OVF_U8_R8
);
5365 interp_add_ins (td
, MINT_CONV_OVF_U8_I4
);
5368 interp_add_ins (td
, MINT_CONV_OVF_U8_I8
);
5371 g_assert_not_reached ();
5374 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
5379 token
= read32 (td
->ip
+ 1);
5380 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
|| method
->wrapper_type
== MONO_WRAPPER_SYNCHRONIZED
) {
5381 handle
= mono_method_get_wrapper_data (method
, token
);
5382 klass
= (MonoClass
*) mono_method_get_wrapper_data (method
, token
+ 1);
5383 if (klass
== mono_defaults
.typehandle_class
)
5384 handle
= m_class_get_byval_arg ((MonoClass
*) handle
);
5386 if (generic_context
) {
5387 handle
= mono_class_inflate_generic_type_checked ((MonoType
*)handle
, generic_context
, error
);
5388 goto_if_nok (error
, exit
);
5391 handle
= mono_ldtoken_checked (image
, token
, &klass
, generic_context
, error
);
5392 goto_if_nok (error
, exit
);
5394 mono_class_init_internal (klass
);
5395 mt
= mint_type (m_class_get_byval_arg (klass
));
5396 g_assert (mt
== MINT_TYPE_VT
);
5397 size
= mono_class_value_size (klass
, NULL
);
5398 g_assert (size
== sizeof(gpointer
));
5400 const unsigned char *next_ip
= td
->ip
+ 5;
5401 MonoMethod
*cmethod
;
5402 if (next_ip
< end
&&
5403 (inlining
|| !td
->is_bb_start
[next_ip
- td
->il_code
]) &&
5404 (*next_ip
== CEE_CALL
|| *next_ip
== CEE_CALLVIRT
) &&
5405 (cmethod
= mono_get_method_checked (image
, read32 (next_ip
+ 1), NULL
, generic_context
, error
)) &&
5406 (cmethod
->klass
== mono_defaults
.systemtype_class
) &&
5407 (strcmp (cmethod
->name
, "GetTypeFromHandle") == 0)) {
5408 interp_add_ins (td
, MINT_MONO_LDPTR
);
5409 gpointer systype
= mono_type_get_object_checked (domain
, (MonoType
*)handle
, error
);
5410 goto_if_nok (error
, exit
);
5411 td
->last_ins
->data
[0] = get_data_item_index (td
, systype
);
5412 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_MP
);
5413 td
->ip
= next_ip
+ 5;
5415 PUSH_VT (td
, sizeof(gpointer
));
5416 interp_add_ins (td
, MINT_LDTOKEN
);
5417 td
->last_ins
->data
[0] = get_data_item_index (td
, handle
);
5418 PUSH_TYPE (td
, stack_type
[mt
], klass
);
5425 binary_arith_op(td
, MINT_ADD_OVF_I4
);
5428 case CEE_ADD_OVF_UN
:
5429 binary_arith_op(td
, MINT_ADD_OVF_UN_I4
);
5433 binary_arith_op(td
, MINT_MUL_OVF_I4
);
5436 case CEE_MUL_OVF_UN
:
5437 binary_arith_op(td
, MINT_MUL_OVF_UN_I4
);
5441 binary_arith_op(td
, MINT_SUB_OVF_I4
);
5444 case CEE_SUB_OVF_UN
:
5445 binary_arith_op(td
, MINT_SUB_OVF_UN_I4
);
5448 case CEE_ENDFINALLY
: {
5449 g_assert (td
->clause_indexes
[in_offset
] != -1);
5451 SIMPLE_OP (td
, MINT_ENDFINALLY
);
5452 td
->last_ins
->data
[0] = td
->clause_indexes
[in_offset
];
5453 // next instructions, if they exist, are always part of new bb
5454 // endfinally can be the last instruction in a function.
5455 // functions with clauses/endfinally are never inlined.
5456 // is_bb_start is not valid while inlining.
5457 g_assert (!inlining
);
5458 if (td
->ip
- td
->il_code
< td
->code_size
)
5459 td
->is_bb_start
[td
->ip
- header
->code
] = 1;
5466 if (*td
->ip
== CEE_LEAVE
)
5467 offset
= 5 + read32 (td
->ip
+ 1);
5469 offset
= 2 + (gint8
)td
->ip
[1];
5472 if (td
->clause_indexes
[in_offset
] != -1) {
5473 /* LEAVE instructions in catch clauses need to check for abort exceptions */
5474 handle_branch (td
, MINT_LEAVE_S_CHECK
, MINT_LEAVE_CHECK
, offset
);
5476 handle_branch (td
, MINT_LEAVE_S
, MINT_LEAVE
, offset
);
5479 if (*td
->ip
== CEE_LEAVE
)
5485 case MONO_CUSTOM_PREFIX
:
5488 case CEE_MONO_RETHROW
:
5489 CHECK_STACK (td
, 1);
5490 SIMPLE_OP (td
, MINT_MONO_RETHROW
);
5494 case CEE_MONO_LD_DELEGATE_METHOD_PTR
:
5497 interp_add_ins (td
, MINT_LD_DELEGATE_METHOD_PTR
);
5498 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
5500 case CEE_MONO_CALLI_EXTRA_ARG
:
5501 /* Same as CEE_CALLI, except that we drop the extra arg required for llvm specific behaviour */
5502 interp_add_ins (td
, MINT_POP
);
5503 td
->last_ins
->data
[0] = 1;
5505 if (!interp_transform_call (td
, method
, NULL
, domain
, generic_context
, td
->is_bb_start
, NULL
, FALSE
, error
, FALSE
, FALSE
))
5508 case CEE_MONO_JIT_ICALL_ADDR
: {
5509 const guint32 token
= read32 (td
->ip
+ 1);
5511 const gconstpointer func
= mono_find_jit_icall_info ((MonoJitICallId
)token
)->func
;
5513 interp_add_ins (td
, MINT_LDFTN
);
5514 td
->last_ins
->data
[0] = get_data_item_index (td
, (gpointer
)func
);
5515 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
5518 case CEE_MONO_ICALL
: {
5519 MonoJitICallId
const jit_icall_id
= (MonoJitICallId
)read32 (td
->ip
+ 1);
5520 MonoJitICallInfo
const * const info
= mono_find_jit_icall_info (jit_icall_id
);
5523 CHECK_STACK (td
, info
->sig
->param_count
);
5524 if (jit_icall_id
== MONO_JIT_ICALL_mono_threads_attach_coop
) {
5525 rtm
->needs_thread_attach
= 1;
5527 /* attach needs two arguments, and has one return value: leave one element on the stack */
5528 interp_add_ins (td
, MINT_POP
);
5529 td
->last_ins
->data
[0] = 0;
5530 } else if (jit_icall_id
== MONO_JIT_ICALL_mono_threads_detach_coop
) {
5531 g_assert (rtm
->needs_thread_attach
);
5533 /* detach consumes two arguments, and no return value: drop both of them */
5534 interp_add_ins (td
, MINT_POP
);
5535 td
->last_ins
->data
[0] = 0;
5536 interp_add_ins (td
, MINT_POP
);
5537 td
->last_ins
->data
[0] = 0;
5539 int const icall_op
= interp_icall_op_for_sig (info
->sig
);
5540 g_assert (icall_op
!= -1);
5542 interp_add_ins (td
, icall_op
);
5543 // hash here is overkill
5544 td
->last_ins
->data
[0] = get_data_item_index (td
, (gpointer
)info
->func
);
5546 td
->sp
-= info
->sig
->param_count
;
5548 if (!MONO_TYPE_IS_VOID (info
->sig
->ret
)) {
5549 int mt
= mint_type (info
->sig
->ret
);
5550 PUSH_SIMPLE_TYPE(td
, stack_type
[mt
]);
5554 case CEE_MONO_VTADDR
: {
5556 CHECK_STACK (td
, 1);
5557 if (method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
5558 size
= mono_class_native_size(td
->sp
[-1].klass
, NULL
);
5560 size
= mono_class_value_size(td
->sp
[-1].klass
, NULL
);
5561 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5562 interp_add_ins (td
, MINT_VTRESULT
);
5563 td
->last_ins
->data
[0] = 0;
5564 WRITE32_INS (td
->last_ins
, 1, &size
);
5567 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
5570 case CEE_MONO_LDPTR
:
5571 case CEE_MONO_CLASSCONST
:
5572 token
= read32 (td
->ip
+ 1);
5574 interp_add_ins (td
, MINT_MONO_LDPTR
);
5575 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_method_get_wrapper_data (method
, token
));
5576 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
5578 case CEE_MONO_OBJADDR
:
5579 CHECK_STACK (td
, 1);
5581 td
->sp
[-1].type
= STACK_TYPE_MP
;
5584 case CEE_MONO_NEWOBJ
:
5585 token
= read32 (td
->ip
+ 1);
5587 interp_add_ins (td
, MINT_MONO_NEWOBJ
);
5588 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_method_get_wrapper_data (method
, token
));
5589 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_O
);
5591 case CEE_MONO_RETOBJ
:
5592 CHECK_STACK (td
, 1);
5593 token
= read32 (td
->ip
+ 1);
5595 interp_add_ins (td
, MINT_MONO_RETOBJ
);
5598 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
5600 /*stackval_from_data (signature->ret, frame->retval, sp->data.vt, signature->pinvoke);*/
5602 if (td
->sp
> td
->stack
)
5603 g_warning ("CEE_MONO_RETOBJ: more values on stack: %d", td
->sp
-td
->stack
);
5605 case CEE_MONO_LDNATIVEOBJ
:
5606 token
= read32 (td
->ip
+ 1);
5608 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
5609 g_assert(m_class_is_valuetype (klass
));
5610 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
5612 case CEE_MONO_TLS
: {
5613 gint32 key
= read32 (td
->ip
+ 1);
5615 g_assertf (key
== TLS_KEY_SGEN_THREAD_INFO
, "%d", key
);
5616 interp_add_ins (td
, MINT_MONO_SGEN_THREAD_INFO
);
5617 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_MP
);
5620 case CEE_MONO_ATOMIC_STORE_I4
:
5621 CHECK_STACK (td
, 2);
5622 SIMPLE_OP (td
, MINT_MONO_ATOMIC_STORE_I4
);
5626 case CEE_MONO_SAVE_LMF
:
5627 case CEE_MONO_RESTORE_LMF
:
5628 case CEE_MONO_NOT_TAKEN
:
5631 case CEE_MONO_LDPTR_INT_REQ_FLAG
:
5632 interp_add_ins (td
, MINT_MONO_LDPTR
);
5633 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_thread_interruption_request_flag ());
5634 PUSH_TYPE (td
, STACK_TYPE_MP
, NULL
);
5637 case CEE_MONO_MEMORY_BARRIER
:
5638 interp_add_ins (td
, MINT_MONO_MEMORY_BARRIER
);
5641 case CEE_MONO_LDDOMAIN
:
5642 interp_add_ins (td
, MINT_MONO_LDDOMAIN
);
5643 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
5646 case CEE_MONO_SAVE_LAST_ERROR
:
5647 save_last_error
= TRUE
;
5651 g_error ("transform.c: Unimplemented opcode: 0xF0 %02x at 0x%x\n", *td
->ip
, td
->ip
-header
->code
);
5661 case CEE_PREFIXREF
: ves_abort(); break;
5664 * Note: Exceptions thrown when executing a prefixed opcode need
5665 * to take into account the number of prefix bytes (usually the
5666 * throw point is just (ip - n_prefix_bytes).
5672 interp_add_ins (td
, MINT_ARGLIST
);
5673 PUSH_VT (td
, SIZEOF_VOID_P
);
5674 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_VT
);
5679 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
) {
5680 interp_add_ins (td
, MINT_CEQ_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
5682 if (td
->sp
[-1].type
== STACK_TYPE_R4
&& td
->sp
[-2].type
== STACK_TYPE_R8
)
5683 interp_add_ins (td
, MINT_CONV_R8_R4
);
5684 if (td
->sp
[-1].type
== STACK_TYPE_R8
&& td
->sp
[-2].type
== STACK_TYPE_R4
)
5685 interp_add_ins (td
, MINT_CONV_R8_R4_SP
);
5686 interp_add_ins (td
, MINT_CEQ_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
5689 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5694 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
)
5695 interp_add_ins (td
, MINT_CGT_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
5697 interp_add_ins (td
, MINT_CGT_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
5699 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5704 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
)
5705 interp_add_ins (td
, MINT_CGT_UN_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
5707 interp_add_ins (td
, MINT_CGT_UN_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
5709 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5714 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
)
5715 interp_add_ins (td
, MINT_CLT_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
5717 interp_add_ins (td
, MINT_CLT_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
5719 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5724 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
)
5725 interp_add_ins (td
, MINT_CLT_UN_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
5727 interp_add_ins (td
, MINT_CLT_UN_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
5729 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5732 case CEE_LDVIRTFTN
: /* fallthrough */
5735 if (*td
->ip
== CEE_LDVIRTFTN
) {
5736 CHECK_STACK (td
, 1);
5739 token
= read32 (td
->ip
+ 1);
5740 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
5741 m
= (MonoMethod
*)mono_method_get_wrapper_data (method
, token
);
5743 m
= mono_get_method_checked (image
, token
, NULL
, generic_context
, error
);
5744 goto_if_nok (error
, exit
);
5747 if (!mono_method_can_access_method (method
, m
))
5748 interp_generate_mae_throw (td
, method
, m
);
5750 if (method
->wrapper_type
== MONO_WRAPPER_NONE
&& m
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)
5751 m
= mono_marshal_get_synchronized_wrapper (m
);
5753 interp_add_ins (td
, *td
->ip
== CEE_LDFTN
? MINT_LDFTN
: MINT_LDVIRTFTN
);
5754 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
5755 goto_if_nok (error
, exit
);
5757 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_F
);
5761 int arg_n
= read16 (td
->ip
+ 1);
5763 load_arg (td
, arg_n
);
5765 load_local_general (td
, arg_locals
[arg_n
], get_arg_type (signature
, arg_n
));
5770 int n
= read16 (td
->ip
+ 1);
5773 get_arg_type_exact (td
, n
, &mt
);
5774 interp_add_ins (td
, mt
== MINT_TYPE_VT
? MINT_LDARGA_VT
: MINT_LDARGA
);
5775 td
->last_ins
->data
[0] = n
;
5777 int loc_n
= arg_locals
[n
];
5778 interp_add_ins (td
, MINT_LDLOCA_S
);
5779 td
->last_ins
->data
[0] = loc_n
;
5780 td
->locals
[loc_n
].flags
|= INTERP_LOCAL_FLAG_INDIRECT
;
5782 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
5787 int arg_n
= read16 (td
->ip
+ 1);
5789 store_arg (td
, arg_n
);
5791 store_local_general (td
, arg_locals
[arg_n
], get_arg_type (signature
, arg_n
));
5796 int loc_n
= read16 (td
->ip
+ 1);
5798 load_local (td
, loc_n
);
5800 load_local_general (td
, local_locals
[loc_n
], header
->locals
[loc_n
]);
5805 int loc_n
= read16 (td
->ip
+ 1);
5806 interp_add_ins (td
, MINT_LDLOCA_S
);
5808 loc_n
= local_locals
[loc_n
];
5809 td
->last_ins
->data
[0] = loc_n
;
5810 td
->locals
[loc_n
].flags
|= INTERP_LOCAL_FLAG_INDIRECT
;
5811 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
5816 int loc_n
= read16 (td
->ip
+ 1);
5818 store_local (td
, loc_n
);
5820 store_local_general (td
, local_locals
[loc_n
], header
->locals
[loc_n
]);
5826 CHECK_STACK (td
, 1);
5827 #if SIZEOF_VOID_P == 8
5828 if (td
->sp
[-1].type
== STACK_TYPE_I8
)
5829 interp_add_ins (td
, MINT_CONV_I4_I8
);
5831 interp_add_ins (td
, MINT_LOCALLOC
);
5832 if (td
->sp
!= td
->stack
+ 1)
5833 g_warning("CEE_LOCALLOC: stack not empty");
5835 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
5838 case CEE_UNUSED57
: ves_abort(); break;
5841 interp_add_ins (td
, MINT_ENDFILTER
);
5844 case CEE_UNALIGNED_
:
5853 /* FIX: should do something? */;
5854 // TODO: This should raise a method_tail_call profiler event.
5858 token
= read32 (td
->ip
+ 1);
5859 klass
= mini_get_class (method
, token
, generic_context
);
5860 CHECK_TYPELOAD (klass
);
5861 if (m_class_is_valuetype (klass
)) {
5862 interp_add_ins (td
, MINT_INITOBJ
);
5863 i32
= mono_class_value_size (klass
, NULL
);
5864 WRITE32_INS (td
->last_ins
, 0, &i32
);
5867 interp_add_ins (td
, MINT_LDNULL
);
5868 PUSH_TYPE(td
, STACK_TYPE_O
, NULL
);
5869 interp_add_ins (td
, MINT_STIND_REF
);
5876 /* FIX? convert length to I8? */
5878 interp_add_ins (td
, MINT_MONO_MEMORY_BARRIER
);
5879 interp_add_ins (td
, MINT_CPBLK
);
5880 BARRIER_IF_VOLATILE (td
);
5888 case CEE_CONSTRAINED_
:
5889 token
= read32 (td
->ip
+ 1);
5890 constrained_class
= mini_get_class (method
, token
, generic_context
);
5891 CHECK_TYPELOAD (constrained_class
);
5896 BARRIER_IF_VOLATILE (td
);
5897 interp_add_ins (td
, MINT_INITBLK
);
5902 /* FIXME: implement */
5906 int clause_index
= td
->clause_indexes
[in_offset
];
5907 g_assert (clause_index
!= -1);
5908 SIMPLE_OP (td
, MINT_RETHROW
);
5909 td
->last_ins
->data
[0] = rtm
->exvar_offsets
[clause_index
];
5915 token
= read32 (td
->ip
+ 1);
5917 if (mono_metadata_token_table (token
) == MONO_TABLE_TYPESPEC
&& !image_is_dynamic (m_class_get_image (method
->klass
)) && !generic_context
) {
5919 MonoType
*type
= mono_type_create_from_typespec_checked (image
, token
, error
);
5920 goto_if_nok (error
, exit
);
5921 size
= mono_type_size (type
, &align
);
5924 MonoClass
*szclass
= mini_get_class (method
, token
, generic_context
);
5925 CHECK_TYPELOAD (szclass
);
5927 if (!szclass
->valuetype
)
5928 THROW_EX (mono_exception_from_name (mono_defaults
.corlib
, "System", "InvalidProgramException"), ip
- 5);
5930 size
= mono_type_size (m_class_get_byval_arg (szclass
), &align
);
5932 interp_add_ins (td
, MINT_LDC_I4
);
5933 WRITE32_INS (td
->last_ins
, 0, &size
);
5934 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
5937 case CEE_REFANYTYPE
:
5938 interp_add_ins (td
, MINT_REFANYTYPE
);
5940 POP_VT (td
, sizeof (MonoTypedRef
));
5941 PUSH_VT (td
, sizeof (gpointer
));
5942 SET_TYPE(td
->sp
- 1, STACK_TYPE_VT
, NULL
);
5945 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
);
5949 g_error ("transform.c: Unimplemented opcode: %02x at 0x%x\n", *td
->ip
, td
->ip
-header
->code
);
5952 // No IR instructions were added as part of a bb_start IL instruction. Add a MINT_NOP
5953 // so we always have an instruction associated with a bb_start. This is simple and avoids
5954 // any complications associated with il_offset tracking.
5955 if (prev_last_ins
== td
->last_ins
&& (!inlining
&& td
->is_bb_start
[in_offset
]) && td
->ip
< end
)
5956 interp_add_ins (td
, MINT_NOP
);
5959 g_assert (td
->ip
== end
);
5962 g_free (arg_locals
);
5963 g_free (local_locals
);
5964 mono_basic_block_free (original_bb
);
5972 // Find the offset of the first interp instruction generated starting il_offset
5973 // This is needed to find the end of clauses.
5975 find_in_offset (TransformData
*td
, int il_offset
)
5978 while (!td
->in_offsets
[i
])
5980 return td
->in_offsets
[i
] - 1;
5983 // We store in the in_offset array the native_offset + 1, so 0 can mean only that the il
5984 // offset is uninitialized. Otherwise 0 is valid value for first interp instruction.
5986 get_in_offset (TransformData
*td
, int il_offset
)
5988 int target_offset
= td
->in_offsets
[il_offset
];
5989 g_assert (target_offset
);
5990 return target_offset
- 1;
5994 handle_relocations (TransformData
*td
)
5996 // Handle relocations
5997 for (int i
= 0; i
< td
->relocs
->len
; ++i
) {
5998 Reloc
*reloc
= (Reloc
*)g_ptr_array_index (td
->relocs
, i
);
5999 int offset
= get_in_offset (td
, reloc
->target
) - reloc
->offset
;
6001 switch (reloc
->type
) {
6002 case RELOC_SHORT_BRANCH
:
6003 g_assert (td
->new_code
[reloc
->offset
+ 1] == 0xdead);
6004 td
->new_code
[reloc
->offset
+ 1] = offset
;
6006 case RELOC_LONG_BRANCH
: {
6007 guint16
*v
= (guint16
*) &offset
;
6008 g_assert (td
->new_code
[reloc
->offset
+ 1] == 0xdead);
6009 g_assert (td
->new_code
[reloc
->offset
+ 2] == 0xbeef);
6010 td
->new_code
[reloc
->offset
+ 1] = *(guint16
*) v
;
6011 td
->new_code
[reloc
->offset
+ 2] = *(guint16
*) (v
+ 1);
6014 case RELOC_SWITCH
: {
6015 guint16
*v
= (guint16
*)&offset
;
6016 g_assert (td
->new_code
[reloc
->offset
] == 0xdead);
6017 g_assert (td
->new_code
[reloc
->offset
+ 1] == 0xbeef);
6018 td
->new_code
[reloc
->offset
] = *(guint16
*)v
;
6019 td
->new_code
[reloc
->offset
+ 1] = *(guint16
*)(v
+ 1);
6023 g_assert_not_reached ();
6031 get_inst_length (InterpInst
*ins
)
6033 if (ins
->opcode
== MINT_SWITCH
)
6034 return MINT_SWITCH_LEN (READ32 (&ins
->data
[0]));
6036 return mono_interp_oplen
[ins
->opcode
];
6040 get_inst_stack_usage (TransformData
*td
, InterpInst
*ins
, int *pop
, int *push
)
6042 guint16 opcode
= ins
->opcode
;
6043 if (mono_interp_oppop
[opcode
] == MINT_VAR_POP
||
6044 mono_interp_oppush
[opcode
] == MINT_VAR_PUSH
) {
6049 case MINT_CALLVIRT_FAST
:
6051 case MINT_VCALLVIRT
:
6052 case MINT_VCALLVIRT_FAST
: {
6053 InterpMethod
*imethod
= (InterpMethod
*) td
->data_items
[ins
->data
[0]];
6054 *pop
= imethod
->param_count
+ imethod
->hasthis
;
6055 if (opcode
== MINT_JIT_CALL
)
6056 *push
= imethod
->rtype
->type
!= MONO_TYPE_VOID
;
6058 *push
= opcode
== MINT_CALL
|| opcode
== MINT_CALLVIRT
|| opcode
== MINT_CALLVIRT_FAST
;
6061 case MINT_CALLRUN
: {
6062 MonoMethodSignature
*csignature
= (MonoMethodSignature
*) td
->data_items
[ins
->data
[1]];
6063 *pop
= csignature
->param_count
+ csignature
->hasthis
;
6064 *push
= csignature
->ret
->type
!= MONO_TYPE_VOID
;
6068 case MINT_CALLI_NAT
:
6069 case MINT_CALLI_NAT_FAST
: {
6070 MonoMethodSignature
*csignature
= (MonoMethodSignature
*) td
->data_items
[ins
->data
[0]];
6071 *pop
= csignature
->param_count
+ csignature
->hasthis
+ 1;
6072 *push
= csignature
->ret
->type
!= MONO_TYPE_VOID
;
6075 case MINT_CALL_VARARG
: {
6076 InterpMethod
*imethod
= (InterpMethod
*) td
->data_items
[ins
->data
[0]];
6077 MonoMethodSignature
*csignature
= (MonoMethodSignature
*) td
->data_items
[ins
->data
[1]];
6078 *pop
= imethod
->param_count
+ imethod
->hasthis
+ csignature
->param_count
- csignature
->sentinelpos
;
6079 *push
= imethod
->rtype
->type
!= MONO_TYPE_VOID
;
6082 case MINT_NEWOBJ_FAST
: {
6083 int param_count
= ins
->data
[1];
6084 gboolean is_inlined
= ins
->data
[0] == 0xffff;
6087 // We lose track of the contents of the stack because the newobj references are pushed below
6088 // the ctor arguments. We should keep track of stack contents to enable ctor optimization.
6090 *push
= param_count
+ 2;
6097 case MINT_NEWOBJ_ARRAY
:
6098 case MINT_NEWOBJ_VT_FAST
:
6099 case MINT_NEWOBJ_VTST_FAST
:
6100 *pop
= ins
->data
[1];
6104 case MINT_LDELEMA_TC
:
6105 *pop
= ins
->data
[0] + 1;
6109 InterpMethod
*imethod
= (InterpMethod
*) td
->data_items
[ins
->data
[0]];
6110 *pop
= imethod
->param_count
;
6116 case MINT_BOX_NULLABLE
:
6117 *pop
= (ins
->data
[1] & ~BOX_NOT_CLEAR_VT_SP
) + 1;
6121 *pop
= ins
->data
[0];
6122 *push
= ins
->data
[0];
6124 case MINT_LD_DELEGATE_INVOKE_IMPL
:
6125 *pop
= ins
->data
[0];
6126 *push
= ins
->data
[0] + 1;
6128 case MINT_INTRINS_BYREFERENCE_CTOR
: {
6129 InterpMethod
*imethod
= (InterpMethod
*) td
->data_items
[ins
->data
[0]];
6130 *pop
= imethod
->param_count
;
6135 g_assert_not_reached ();
6138 *pop
= mono_interp_oppop
[opcode
];
6139 *push
= mono_interp_oppush
[opcode
];
6144 emit_compacted_instruction (TransformData
*td
, guint16
* start_ip
, InterpInst
*ins
)
6146 guint16 opcode
= ins
->opcode
;
6147 guint16
*ip
= start_ip
;
6149 // We know what IL offset this instruction was created for. We can now map the IL offset
6150 // to the IR offset. We use this array to resolve the relocations, which reference the IL.
6151 if (ins
->il_offset
!= -1 && !td
->in_offsets
[ins
->il_offset
]) {
6152 g_assert (ins
->il_offset
>= 0 && ins
->il_offset
< td
->header
->code_size
);
6153 td
->in_offsets
[ins
->il_offset
] = start_ip
- td
->new_code
+ 1;
6155 MonoDebugLineNumberEntry lne
;
6156 lne
.native_offset
= (guint8
*)start_ip
- (guint8
*)td
->new_code
;
6157 lne
.il_offset
= ins
->il_offset
;
6158 g_array_append_val (td
->line_numbers
, lne
);
6161 if (opcode
== MINT_NOP
)
6165 if (opcode
== MINT_SWITCH
) {
6166 int labels
= READ32 (&ins
->data
[0]);
6167 // Write number of switch labels
6168 *ip
++ = ins
->data
[0];
6169 *ip
++ = ins
->data
[1];
6170 // Add relocation for each label
6171 for (int i
= 0; i
< labels
; i
++) {
6172 Reloc
*reloc
= (Reloc
*)mono_mempool_alloc0 (td
->mempool
, sizeof (Reloc
));
6173 reloc
->type
= RELOC_SWITCH
;
6174 reloc
->offset
= ip
- td
->new_code
;
6175 reloc
->target
= READ32 (&ins
->data
[2 + i
* 2]);
6176 g_ptr_array_add (td
->relocs
, reloc
);
6180 } else if ((opcode
>= MINT_BRFALSE_I4_S
&& opcode
<= MINT_BRTRUE_R8_S
) ||
6181 (opcode
>= MINT_BEQ_I4_S
&& opcode
<= MINT_BLT_UN_R8_S
) ||
6182 opcode
== MINT_BR_S
|| opcode
== MINT_LEAVE_S
|| opcode
== MINT_LEAVE_S_CHECK
) {
6183 const int br_offset
= start_ip
- td
->new_code
;
6184 if (ins
->data
[0] < ins
->il_offset
) {
6185 // Backwards branch. We can already patch it.
6186 *ip
++ = get_in_offset (td
, ins
->data
[0]) - br_offset
;
6188 // We don't know the in_offset of the target, add a reloc
6189 Reloc
*reloc
= (Reloc
*)mono_mempool_alloc0 (td
->mempool
, sizeof (Reloc
));
6190 reloc
->type
= RELOC_SHORT_BRANCH
;
6191 reloc
->offset
= br_offset
;
6192 reloc
->target
= ins
->data
[0];
6193 g_ptr_array_add (td
->relocs
, reloc
);
6196 } else if ((opcode
>= MINT_BRFALSE_I4
&& opcode
<= MINT_BRTRUE_R8
) ||
6197 (opcode
>= MINT_BEQ_I4
&& opcode
<= MINT_BLT_UN_R8
) ||
6198 opcode
== MINT_BR
|| opcode
== MINT_LEAVE
|| opcode
== MINT_LEAVE_CHECK
) {
6199 const int br_offset
= start_ip
- td
->new_code
;
6200 int target_il
= READ32 (&ins
->data
[0]);
6201 if (target_il
< ins
->il_offset
) {
6202 // Backwards branch. We can already patch it
6203 const int br_offset
= start_ip
- td
->new_code
;
6204 int target_offset
= get_in_offset (td
, target_il
) - br_offset
;
6205 WRITE32 (ip
, &target_offset
);
6207 Reloc
*reloc
= (Reloc
*)mono_mempool_alloc0 (td
->mempool
, sizeof (Reloc
));
6208 reloc
->type
= RELOC_LONG_BRANCH
;
6209 reloc
->offset
= br_offset
;
6210 reloc
->target
= target_il
;
6211 g_ptr_array_add (td
->relocs
, reloc
);
6215 } else if (opcode
== MINT_SDB_SEQ_POINT
) {
6216 SeqPoint
*seqp
= (SeqPoint
*)mono_mempool_alloc0 (td
->mempool
, sizeof (SeqPoint
));
6217 InterpBasicBlock
*cbb
;
6219 if (ins
->flags
& INTERP_INST_FLAG_SEQ_POINT_METHOD_ENTRY
) {
6220 seqp
->il_offset
= METHOD_ENTRY_IL_OFFSET
;
6221 cbb
= td
->offset_to_bb
[0];
6223 if (ins
->flags
& INTERP_INST_FLAG_SEQ_POINT_METHOD_EXIT
)
6224 seqp
->il_offset
= METHOD_EXIT_IL_OFFSET
;
6226 seqp
->il_offset
= ins
->il_offset
;
6227 cbb
= td
->offset_to_bb
[ins
->il_offset
];
6229 seqp
->native_offset
= (guint8
*)start_ip
- (guint8
*)td
->new_code
;
6230 if (ins
->flags
& INTERP_INST_FLAG_SEQ_POINT_NONEMPTY_STACK
)
6231 seqp
->flags
|= MONO_SEQ_POINT_FLAG_NONEMPTY_STACK
;
6232 if (ins
->flags
& INTERP_INST_FLAG_SEQ_POINT_NESTED_CALL
)
6233 seqp
->flags
|= MONO_SEQ_POINT_FLAG_NESTED_CALL
;
6234 g_ptr_array_add (td
->seq_points
, seqp
);
6236 cbb
->seq_points
= g_slist_prepend_mempool (td
->mempool
, cbb
->seq_points
, seqp
);
6237 cbb
->last_seq_point
= seqp
;
6239 if (MINT_IS_LDLOC (opcode
) || MINT_IS_STLOC (opcode
) || MINT_IS_STLOC_NP (opcode
) || opcode
== MINT_LDLOCA_S
) {
6240 ins
->data
[0] = get_interp_local_offset (td
, ins
->data
[0]);
6241 } else if (MINT_IS_MOVLOC (opcode
)) {
6242 ins
->data
[0] = get_interp_local_offset (td
, ins
->data
[0]);
6243 ins
->data
[1] = get_interp_local_offset (td
, ins
->data
[1]);
6246 int size
= get_inst_length (ins
) - 1;
6247 // Emit the rest of the data
6248 for (int i
= 0; i
< size
; i
++)
6249 *ip
++ = ins
->data
[i
];
6254 // Generates the final code, after we are done with all the passes
6256 generate_compacted_code (TransformData
*td
)
6260 td
->relocs
= g_ptr_array_new ();
6262 // Iterate once to compute the exact size of the compacted code
6263 InterpInst
*ins
= td
->first_ins
;
6265 size
+= get_inst_length (ins
);
6269 // Generate the compacted stream of instructions
6270 td
->new_code
= ip
= (guint16
*)mono_domain_alloc0 (td
->rtm
->domain
, size
* sizeof (guint16
));
6271 ins
= td
->first_ins
;
6273 ip
= emit_compacted_instruction (td
, ip
, ins
);
6276 td
->new_code_end
= ip
;
6277 td
->in_offsets
[td
->header
->code_size
] = td
->new_code_end
- td
->new_code
;
6279 // Patch all branches
6280 handle_relocations (td
);
6282 g_ptr_array_free (td
->relocs
, TRUE
);
6286 get_movloc_for_type (int mt
)
6291 return MINT_MOVLOC_1
;
6294 return MINT_MOVLOC_2
;
6297 return MINT_MOVLOC_4
;
6300 return MINT_MOVLOC_8
;
6303 #if SIZEOF_VOID_P == 8
6304 return MINT_MOVLOC_8
;
6306 return MINT_MOVLOC_4
;
6309 return MINT_MOVLOC_VT
;
6311 g_assert_not_reached ();
6314 // The value of local has changed. This means the contents of the stack where the
6315 // local was loaded, no longer contain the value of the local. Clear them.
6317 clear_stack_content_info_for_local (StackContentInfo
*start
, StackContentInfo
*end
, int local
)
6319 StackContentInfo
*si
;
6320 for (si
= start
; si
< end
; si
++) {
6322 g_assert (MINT_IS_LDLOC (si
->ins
->opcode
));
6323 if (si
->ins
->data
[0] == local
)
6329 // The value of local has changed. This means we can no longer assume that any other local
6330 // is a copy of this local.
6332 clear_local_content_info_for_local (StackContentInfo
*start
, StackContentInfo
*end
, int local
)
6334 StackContentInfo
*si
;
6335 for (si
= start
; si
< end
; si
++) {
6337 g_assert (MINT_IS_MOVLOC (si
->ins
->opcode
));
6338 g_assert (si
->ins
->data
[1] == (guint16
)(si
- start
));
6339 if (si
->ins
->data
[0] == local
)
6346 interp_local_deadce (TransformData
*td
, int *local_ref_count
)
6349 gboolean needs_dce
= FALSE
;
6351 for (int i
= 0; i
< td
->locals_size
; i
++) {
6352 g_assert (local_ref_count
[i
] >= 0);
6353 if (!local_ref_count
[i
] && (td
->locals
[i
].flags
& INTERP_LOCAL_FLAG_INDIRECT
) == 0) {
6359 // Return early if all locals are alive
6363 // Kill instructions that don't use stack and are storing into dead locals
6364 for (ins
= td
->first_ins
; ins
!= NULL
; ins
= ins
->next
) {
6365 if (MINT_IS_STLOC_NP (ins
->opcode
)) {
6366 if (!local_ref_count
[ins
->data
[0]] && (td
->locals
[ins
->data
[0]].flags
& INTERP_LOCAL_FLAG_INDIRECT
) == 0) {
6367 interp_clear_ins (td
, ins
);
6368 mono_interp_stats
.killed_instructions
++;
6370 } else if (MINT_IS_MOVLOC (ins
->opcode
)) {
6371 if (!local_ref_count
[ins
->data
[1]] && (td
->locals
[ins
->data
[1]].flags
& INTERP_LOCAL_FLAG_INDIRECT
) == 0) {
6372 interp_clear_ins (td
, ins
);
6373 mono_interp_stats
.killed_instructions
++;
6380 interp_cprop (TransformData
*td
)
6382 if (!td
->max_stack_height
|| !td
->locals_size
)
6384 StackContentInfo
*stack
= (StackContentInfo
*) g_malloc (td
->max_stack_height
* sizeof (StackContentInfo
));
6385 StackContentInfo
*stack_end
= stack
+ td
->max_stack_height
;
6386 StackContentInfo
*sp
= stack
;
6387 StackContentInfo
*locals
= (StackContentInfo
*) g_malloc (td
->locals_size
* sizeof (StackContentInfo
));
6388 int *local_ref_count
= (int*) g_malloc0 (td
->locals_size
* sizeof (int));
6390 int last_il_offset
= -1;
6392 for (ins
= td
->first_ins
; ins
!= NULL
; ins
= ins
->next
) {
6394 int il_offset
= ins
->il_offset
;
6395 // Optimizations take place only inside a single basic block
6396 // If two instructions have the same il_offset, then the second one
6397 // cannot be part the start of a basic block.
6398 gboolean is_bb_start
= il_offset
!= -1 && td
->is_bb_start
[il_offset
] && il_offset
!= last_il_offset
;
6400 if (td
->stack_height
[il_offset
] >= 0) {
6401 sp
= stack
+ td
->stack_height
[il_offset
];
6402 g_assert (sp
>= stack
);
6403 memset (stack
, 0, (sp
- stack
) * sizeof (StackContentInfo
));
6405 memset (locals
, 0, td
->locals_size
* sizeof (StackContentInfo
));
6407 // The instruction pops some values then pushes some other
6408 get_inst_stack_usage (td
, ins
, &pop
, &push
);
6409 if (MINT_IS_LDLOC (ins
->opcode
)) {
6411 int loaded_local
= ins
->data
[0];
6412 local_ref_count
[loaded_local
]++;
6413 if (!is_bb_start
&& MINT_IS_STLOC (ins
->prev
->opcode
) && ins
->prev
->data
[0] == loaded_local
) {
6414 int mt
= ins
->prev
->opcode
- MINT_STLOC_I1
;
6415 if (ins
->opcode
- MINT_LDLOC_I1
== mt
) {
6416 if (mt
== MINT_TYPE_I4
)
6417 replace_op
= MINT_STLOC_NP_I4
;
6418 else if (mt
== MINT_TYPE_O
|| mt
== MINT_TYPE_P
)
6419 replace_op
= MINT_STLOC_NP_O
;
6421 if (td
->verbose_level
)
6422 g_print ("Add stloc.np : ldloc (off %p), stloc (off %p)\n", ins
->il_offset
, ins
->prev
->il_offset
);
6423 interp_clear_ins (td
, ins
->prev
);
6424 ins
->opcode
= replace_op
;
6425 mono_interp_stats
.stloc_nps
++;
6426 local_ref_count
[loaded_local
]--;
6427 // FIXME We know what local is on the stack now. Track it
6430 } else if (locals
[loaded_local
].ins
!= NULL
&& !(td
->locals
[loaded_local
].flags
& INTERP_LOCAL_FLAG_INDIRECT
)) {
6431 g_assert (MINT_IS_MOVLOC (locals
[loaded_local
].ins
->opcode
));
6432 // do copy propagation of the original source
6433 if (td
->verbose_level
)
6434 g_print ("cprop %d -> %d\n", loaded_local
, locals
[loaded_local
].ins
->data
[0]);
6435 mono_interp_stats
.copy_propagations
++;
6436 local_ref_count
[loaded_local
]--;
6437 ins
->data
[0] = locals
[loaded_local
].ins
->data
[0];
6438 local_ref_count
[ins
->data
[0]]++;
6441 // Save the ldloc on the stack if it wasn't optimized away
6442 // For simplicity we don't track locals that have their address taken
6443 // since it is hard to detect instructions that change the local value.
6444 if (td
->locals
[loaded_local
].flags
& INTERP_LOCAL_FLAG_INDIRECT
)
6450 } else if (MINT_IS_STLOC (ins
->opcode
)) {
6451 int dest_local
= ins
->data
[0];
6453 if (sp
->ins
!= NULL
) {
6454 int mt
= sp
->ins
->opcode
- MINT_LDLOC_I1
;
6455 if (ins
->opcode
- MINT_STLOC_I1
== mt
) {
6456 // Same local, same type of load and store, convert to movloc
6457 if (td
->verbose_level
)
6458 g_print ("Add movloc : ldloc (off %p), stloc (off %p)\n", sp
->ins
->il_offset
, ins
->il_offset
);
6459 int src_local
= sp
->ins
->data
[0];
6460 interp_clear_ins (td
, sp
->ins
);
6461 interp_clear_ins (td
, ins
);
6463 ins
= interp_insert_ins (td
, ins
, get_movloc_for_type (mt
));
6464 ins
->data
[0] = src_local
;
6465 ins
->data
[1] = dest_local
;
6466 if (ins
->opcode
== MINT_MOVLOC_VT
)
6467 ins
->data
[2] = sp
->ins
->data
[1];
6468 mono_interp_stats
.movlocs
++;
6469 // Track what exactly is stored into local
6470 locals
[dest_local
].ins
= ins
;
6472 locals
[dest_local
].ins
= NULL
;
6475 locals
[dest_local
].ins
= NULL
;
6477 clear_stack_content_info_for_local (stack
, sp
, dest_local
);
6478 clear_local_content_info_for_local (locals
, locals
+ td
->locals_size
, dest_local
);
6480 if (pop
== MINT_POP_ALL
)
6483 g_assert (sp
>= stack
&& sp
<= stack_end
);
6484 g_assert ((sp
- push
) >= stack
&& (sp
- push
) <= stack_end
);
6485 memset (sp
- push
, 0, push
* sizeof (StackContentInfo
));
6488 last_il_offset
= ins
->il_offset
;
6491 interp_local_deadce (td
, local_ref_count
);
6495 g_free (local_ref_count
);
6499 interp_optimize_code (TransformData
*td
)
6501 if (mono_interp_opt
& INTERP_OPT_CPROP
)
6502 MONO_TIME_TRACK (mono_interp_stats
.cprop_time
, interp_cprop (td
));
6506 generate (MonoMethod
*method
, MonoMethodHeader
*header
, InterpMethod
*rtm
, MonoGenericContext
*generic_context
, MonoError
*error
)
6508 MonoDomain
*domain
= rtm
->domain
;
6510 TransformData transform_data
;
6512 static gboolean verbose_method_inited
;
6513 static char* verbose_method_name
;
6515 if (!verbose_method_inited
) {
6516 verbose_method_name
= g_getenv ("MONO_VERBOSE_METHOD");
6517 verbose_method_inited
= TRUE
;
6520 memset (&transform_data
, 0, sizeof(transform_data
));
6521 td
= &transform_data
;
6523 td
->method
= method
;
6525 td
->code_size
= header
->code_size
;
6526 td
->header
= header
;
6527 td
->max_code_size
= td
->code_size
;
6528 td
->in_offsets
= (int*)g_malloc0((header
->code_size
+ 1) * sizeof(int));
6529 td
->stack_height
= (int*)g_malloc(header
->code_size
* sizeof(int));
6530 td
->stack_state
= (StackInfo
**)g_malloc0(header
->code_size
* sizeof(StackInfo
*));
6531 td
->vt_stack_size
= (int*)g_malloc(header
->code_size
* sizeof(int));
6532 td
->clause_indexes
= (int*)g_malloc (header
->code_size
* sizeof (int));
6533 td
->is_bb_start
= (guint8
*)g_malloc0(header
->code_size
);
6534 td
->mempool
= mono_mempool_new ();
6535 td
->n_data_items
= 0;
6536 td
->max_data_items
= 0;
6537 td
->data_items
= NULL
;
6538 td
->data_hash
= g_hash_table_new (NULL
, NULL
);
6539 td
->gen_sdb_seq_points
= mini_debug_options
.gen_sdb_seq_points
;
6540 td
->seq_points
= g_ptr_array_new ();
6541 td
->verbose_level
= mono_interp_traceopt
;
6542 rtm
->data_items
= td
->data_items
;
6544 interp_method_compute_offsets (td
, rtm
, mono_method_signature_internal (method
), header
);
6546 if (verbose_method_name
) {
6547 const char *name
= verbose_method_name
;
6549 if ((strchr (name
, '.') > name
) || strchr (name
, ':')) {
6550 MonoMethodDesc
*desc
;
6552 desc
= mono_method_desc_new (name
, TRUE
);
6553 if (mono_method_desc_full_match (desc
, method
)) {
6554 td
->verbose_level
= 4;
6556 mono_method_desc_free (desc
);
6558 if (strcmp (method
->name
, name
) == 0)
6559 td
->verbose_level
= 4;
6563 td
->stack
= (StackInfo
*)g_malloc0 ((header
->max_stack
+ 1) * sizeof (td
->stack
[0]));
6564 td
->stack_capacity
= header
->max_stack
+ 1;
6566 td
->max_stack_height
= 0;
6567 td
->line_numbers
= g_array_new (FALSE
, TRUE
, sizeof (MonoDebugLineNumberEntry
));
6568 td
->current_il_offset
= -1;
6570 generate_code (td
, method
, header
, generic_context
, error
);
6571 goto_if_nok (error
, exit
);
6573 interp_optimize_code (td
);
6575 generate_compacted_code (td
);
6577 if (td
->verbose_level
) {
6578 g_print ("Runtime method: %s %p, VT stack size: %d\n", mono_method_full_name (method
, TRUE
), rtm
, td
->max_vt_sp
);
6579 g_print ("Calculated stack size: %d, stated size: %d\n", td
->max_stack_height
, header
->max_stack
);
6580 dump_mint_code (td
->new_code
, td
->new_code_end
);
6583 /* Check if we use excessive stack space */
6584 if (td
->max_stack_height
> header
->max_stack
* 3 && header
->max_stack
> 16)
6585 g_warning ("Excessive stack space usage for method %s, %d/%d", method
->name
, td
->max_stack_height
, header
->max_stack
);
6588 code_len
= td
->new_code_end
- td
->new_code
;
6590 rtm
->clauses
= (MonoExceptionClause
*)mono_domain_alloc0 (domain
, header
->num_clauses
* sizeof (MonoExceptionClause
));
6591 memcpy (rtm
->clauses
, header
->clauses
, header
->num_clauses
* sizeof(MonoExceptionClause
));
6592 rtm
->code
= (gushort
*)td
->new_code
;
6593 rtm
->init_locals
= header
->init_locals
;
6594 rtm
->num_clauses
= header
->num_clauses
;
6595 for (i
= 0; i
< header
->num_clauses
; i
++) {
6596 MonoExceptionClause
*c
= rtm
->clauses
+ i
;
6597 int end_off
= c
->try_offset
+ c
->try_len
;
6598 c
->try_offset
= get_in_offset (td
, c
->try_offset
);
6599 c
->try_len
= find_in_offset (td
, end_off
) - c
->try_offset
;
6600 g_assert ((c
->try_offset
+ c
->try_len
) < code_len
);
6601 end_off
= c
->handler_offset
+ c
->handler_len
;
6602 c
->handler_offset
= get_in_offset (td
, c
->handler_offset
);
6603 c
->handler_len
= find_in_offset (td
, end_off
) - c
->handler_offset
;
6604 g_assert (c
->handler_len
>= 0 && (c
->handler_offset
+ c
->handler_len
) <= code_len
);
6605 if (c
->flags
& MONO_EXCEPTION_CLAUSE_FILTER
)
6606 c
->data
.filter_offset
= get_in_offset (td
, c
->data
.filter_offset
);
6608 rtm
->stack_size
= (sizeof (stackval
)) * (td
->max_stack_height
+ 2); /* + 1 for returns of called functions + 1 for 0-ing in trace*/
6609 rtm
->stack_size
= ALIGN_TO (rtm
->stack_size
, MINT_VT_ALIGNMENT
);
6610 rtm
->vt_stack_size
= td
->max_vt_sp
;
6611 rtm
->total_locals_size
= td
->total_locals_size
;
6612 rtm
->alloca_size
= rtm
->total_locals_size
+ rtm
->vt_stack_size
+ rtm
->stack_size
;
6613 rtm
->data_items
= (gpointer
*)mono_domain_alloc0 (domain
, td
->n_data_items
* sizeof (td
->data_items
[0]));
6614 memcpy (rtm
->data_items
, td
->data_items
, td
->n_data_items
* sizeof (td
->data_items
[0]));
6616 /* Save debug info */
6617 interp_save_debug_info (rtm
, header
, td
, td
->line_numbers
);
6619 /* Create a MonoJitInfo for the interpreted method by creating the interpreter IR as the native code. */
6621 jinfo_len
= mono_jit_info_size ((MonoJitInfoFlags
)0, header
->num_clauses
, 0);
6623 jinfo
= (MonoJitInfo
*)mono_domain_alloc0 (domain
, jinfo_len
);
6624 jinfo
->is_interp
= 1;
6626 mono_jit_info_init (jinfo
, method
, (guint8
*)rtm
->code
, code_len
, (MonoJitInfoFlags
)0, header
->num_clauses
, 0);
6627 for (i
= 0; i
< jinfo
->num_clauses
; ++i
) {
6628 MonoJitExceptionInfo
*ei
= &jinfo
->clauses
[i
];
6629 MonoExceptionClause
*c
= rtm
->clauses
+ i
;
6631 ei
->flags
= c
->flags
;
6632 ei
->try_start
= (guint8
*)(rtm
->code
+ c
->try_offset
);
6633 ei
->try_end
= (guint8
*)(rtm
->code
+ c
->try_offset
+ c
->try_len
);
6634 ei
->handler_start
= (guint8
*)(rtm
->code
+ c
->handler_offset
);
6635 ei
->exvar_offset
= rtm
->exvar_offsets
[i
];
6636 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
6637 ei
->data
.filter
= (guint8
*)(rtm
->code
+ c
->data
.filter_offset
);
6638 } else if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
6639 ei
->data
.handler_end
= (guint8
*)(rtm
->code
+ c
->handler_offset
+ c
->handler_len
);
6641 ei
->data
.catch_class
= c
->data
.catch_class
;
6645 save_seq_points (td
, jinfo
);
6648 g_free (td
->in_offsets
);
6649 g_free (td
->stack_height
);
6650 for (i
= 0; i
< header
->code_size
; ++i
)
6651 g_free (td
->stack_state
[i
]);
6652 g_free (td
->stack_state
);
6653 g_free (td
->vt_stack_size
);
6654 g_free (td
->clause_indexes
);
6655 g_free (td
->data_items
);
6657 g_free (td
->is_bb_start
);
6658 g_free (td
->locals
);
6659 g_hash_table_destroy (td
->data_hash
);
6660 g_ptr_array_free (td
->seq_points
, TRUE
);
6661 g_array_free (td
->line_numbers
, TRUE
);
6662 mono_mempool_destroy (td
->mempool
);
6665 static mono_mutex_t calc_section
;
6668 mono_interp_transform_init (void)
6670 mono_os_mutex_init_recursive(&calc_section
);
6674 mono_interp_transform_method (InterpMethod
*imethod
, ThreadContext
*context
, MonoError
*error
)
6676 MonoMethod
*method
= imethod
->method
;
6677 MonoMethodHeader
*header
= NULL
;
6678 MonoMethodSignature
*signature
= mono_method_signature_internal (method
);
6679 MonoVTable
*method_class_vt
;
6680 MonoGenericContext
*generic_context
= NULL
;
6681 MonoDomain
*domain
= imethod
->domain
;
6682 InterpMethod tmp_imethod
;
6683 InterpMethod
*real_imethod
;
6687 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (method
->klass
))) {
6688 mono_error_set_invalid_operation (error
, "%s", "Could not execute the method because the containing type is not fully instantiated.");
6692 // g_printerr ("TRANSFORM(0x%016lx): begin %s::%s\n", mono_thread_current (), method->klass->name, method->name);
6693 method_class_vt
= mono_class_vtable_checked (domain
, imethod
->method
->klass
, error
);
6694 return_if_nok (error
);
6696 if (!method_class_vt
->initialized
) {
6697 mono_runtime_class_init_full (method_class_vt
, error
);
6698 return_if_nok (error
);
6701 MONO_PROFILER_RAISE (jit_begin
, (method
));
6703 if (mono_method_signature_internal (method
)->is_inflated
)
6704 generic_context
= mono_method_get_context (method
);
6706 MonoGenericContainer
*generic_container
= mono_method_get_generic_container (method
);
6707 if (generic_container
)
6708 generic_context
= &generic_container
->context
;
6711 if (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)) {
6712 MonoMethod
*nm
= NULL
;
6713 if (imethod
->transformed
) {
6714 MONO_PROFILER_RAISE (jit_done
, (method
, imethod
->jinfo
));
6718 /* assumes all internal calls with an array this are built in... */
6719 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
&& (! mono_method_signature_internal (method
)->hasthis
|| m_class_get_rank (method
->klass
) == 0)) {
6720 nm
= mono_marshal_get_native_wrapper (method
, FALSE
, FALSE
);
6721 signature
= mono_method_signature_internal (nm
);
6723 const char *name
= method
->name
;
6724 if (m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) {
6725 if (*name
== '.' && (strcmp (name
, ".ctor") == 0)) {
6726 MonoJitICallInfo
*mi
= &mono_get_jit_icall_info ()->ves_icall_mono_delegate_ctor_interp
;
6727 nm
= mono_marshal_get_icall_wrapper (mi
, TRUE
);
6728 } else if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
6730 * Usually handled during transformation of the caller, but
6731 * when the caller is handled by another execution engine
6732 * (for example fullAOT) we need to handle it here. That's
6733 * known to be wrong in cases where the reference to
6734 * `MonoDelegate` would be needed (FIXME).
6736 nm
= mono_marshal_get_delegate_invoke (method
, NULL
);
6737 } else if (*name
== 'B' && (strcmp (name
, "BeginInvoke") == 0)) {
6738 nm
= mono_marshal_get_delegate_begin_invoke (method
);
6739 } else if (*name
== 'E' && (strcmp (name
, "EndInvoke") == 0)) {
6740 nm
= mono_marshal_get_delegate_end_invoke (method
);
6744 g_assert_not_reached ();
6747 mono_os_mutex_lock (&calc_section
);
6748 imethod
->stack_size
= sizeof (stackval
); /* for tracing */
6749 imethod
->alloca_size
= imethod
->stack_size
;
6750 mono_memory_barrier ();
6751 imethod
->transformed
= TRUE
;
6752 mono_os_mutex_unlock (&calc_section
);
6753 MONO_PROFILER_RAISE (jit_done
, (method
, NULL
));
6757 header
= interp_method_get_header (nm
, error
);
6758 return_if_nok (error
);
6762 header
= mono_method_get_header_checked (method
, error
);
6763 return_if_nok (error
);
6766 g_assert ((signature
->param_count
+ signature
->hasthis
) < 1000);
6767 // g_printerr ("TRANSFORM(0x%016lx): end %s::%s\n", mono_thread_current (), method->klass->name, method->name);
6769 /* Make modifications to a copy of imethod, copy them back inside the lock */
6770 real_imethod
= imethod
;
6771 memcpy (&tmp_imethod
, imethod
, sizeof (InterpMethod
));
6772 imethod
= &tmp_imethod
;
6774 MONO_TIME_TRACK (mono_interp_stats
.transform_time
, generate (method
, header
, imethod
, generic_context
, error
));
6776 mono_metadata_free_mh (header
);
6778 return_if_nok (error
);
6780 /* Copy changes back */
6781 imethod
= real_imethod
;
6782 mono_os_mutex_lock (&calc_section
);
6783 if (!imethod
->transformed
) {
6784 // Ignore the first two fields which are unchanged. next_jit_code_hash shouldn't
6785 // be modified because it is racy with internal hash table insert.
6786 const int start_offset
= 2 * sizeof (gpointer
);
6787 memcpy ((char*)imethod
+ start_offset
, (char*)&tmp_imethod
+ start_offset
, sizeof (InterpMethod
) - start_offset
);
6788 mono_memory_barrier ();
6789 imethod
->transformed
= TRUE
;
6790 mono_atomic_fetch_add_i32 (&mono_jit_stats
.methods_with_interp
, 1);
6793 mono_os_mutex_unlock (&calc_section
);
6795 mono_domain_lock (domain
);
6796 if (!g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, imethod
->method
))
6797 g_hash_table_insert (domain_jit_info (domain
)->seq_points
, imethod
->method
, imethod
->jinfo
->seq_points
);
6798 mono_domain_unlock (domain
);
6800 // FIXME: Add a different callback ?
6801 MONO_PROFILER_RAISE (jit_done
, (method
, imethod
->jinfo
));