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 MonoInterpStats mono_interp_stats
;
43 typedef struct InterpInst InterpInst
;
54 InterpInst
*next
, *prev
;
55 // If this is -1, this instruction is not logically associated with an IL offset, it is
56 // part of the IL instruction associated with the previous interp instruction.
59 guint16 data
[MONO_ZERO_LEN_ARRAY
];
66 SeqPoint
*last_seq_point
;
68 // This will hold a list of last sequence points of incoming basic blocks
69 SeqPoint
**pred_seq_points
;
70 guint num_pred_seq_points
;
81 /* In the interpreter IR */
90 MonoMethod
*inlined_method
;
91 MonoMethodHeader
*header
;
93 const unsigned char *il_code
;
94 const unsigned char *ip
;
95 const unsigned char *in_start
;
96 InterpInst
*last_ins
, *first_ins
;
99 StackInfo
**stack_state
;
102 unsigned char *is_bb_start
;
103 unsigned short *new_code
;
104 unsigned short *new_code_end
;
105 unsigned int max_code_size
;
108 unsigned int max_stack_height
;
109 unsigned int stack_capacity
;
111 unsigned int max_vt_sp
;
112 unsigned int total_locals_size
;
116 GHashTable
*data_hash
;
118 gboolean gen_sdb_seq_points
;
119 GPtrArray
*seq_points
;
120 InterpBasicBlock
**offset_to_bb
;
121 InterpBasicBlock
*entry_bb
;
122 MonoMemPool
*mempool
;
125 gboolean verbose_level
;
126 GArray
*line_numbers
;
129 #define STACK_TYPE_I4 0
130 #define STACK_TYPE_I8 1
131 #define STACK_TYPE_R4 2
132 #define STACK_TYPE_R8 3
133 #define STACK_TYPE_O 4
134 #define STACK_TYPE_VT 5
135 #define STACK_TYPE_MP 6
136 #define STACK_TYPE_F 7
138 static const char *stack_type_string
[] = { "I4", "I8", "R4", "R8", "O ", "VT", "MP", "F " };
140 #if SIZEOF_VOID_P == 8
141 #define STACK_TYPE_I STACK_TYPE_I8
143 #define STACK_TYPE_I STACK_TYPE_I4
146 static int stack_type
[] = {
147 STACK_TYPE_I4
, /*I1*/
148 STACK_TYPE_I4
, /*U1*/
149 STACK_TYPE_I4
, /*I2*/
150 STACK_TYPE_I4
, /*U2*/
151 STACK_TYPE_I4
, /*I4*/
152 STACK_TYPE_I8
, /*I8*/
153 STACK_TYPE_R4
, /*R4*/
154 STACK_TYPE_R8
, /*R8*/
160 #if SIZEOF_VOID_P == 8
161 #define MINT_NEG_P MINT_NEG_I8
162 #define MINT_NOT_P MINT_NOT_I8
164 #define MINT_NEG_FP MINT_NEG_R8
166 #define MINT_ADD_P MINT_ADD_I8
167 #define MINT_SUB_P MINT_SUB_I8
168 #define MINT_MUL_P MINT_MUL_I8
169 #define MINT_DIV_P MINT_DIV_I8
170 #define MINT_DIV_UN_P MINT_DIV_UN_I8
171 #define MINT_REM_P MINT_REM_I8
172 #define MINT_REM_UN_P MINT_REM_UN_I8
173 #define MINT_AND_P MINT_AND_I8
174 #define MINT_OR_P MINT_OR_I8
175 #define MINT_XOR_P MINT_XOR_I8
176 #define MINT_SHL_P MINT_SHL_I8
177 #define MINT_SHR_P MINT_SHR_I8
178 #define MINT_SHR_UN_P MINT_SHR_UN_I8
180 #define MINT_CEQ_P MINT_CEQ_I8
181 #define MINT_CNE_P MINT_CNE_I8
182 #define MINT_CLT_P MINT_CLT_I8
183 #define MINT_CLT_UN_P MINT_CLT_UN_I8
184 #define MINT_CGT_P MINT_CGT_I8
185 #define MINT_CGT_UN_P MINT_CGT_UN_I8
186 #define MINT_CLE_P MINT_CLE_I8
187 #define MINT_CLE_UN_P MINT_CLE_UN_I8
188 #define MINT_CGE_P MINT_CGE_I8
189 #define MINT_CGE_UN_P MINT_CGE_UN_I8
191 #define MINT_ADD_FP MINT_ADD_R8
192 #define MINT_SUB_FP MINT_SUB_R8
193 #define MINT_MUL_FP MINT_MUL_R8
194 #define MINT_DIV_FP MINT_DIV_R8
195 #define MINT_REM_FP MINT_REM_R8
197 #define MINT_CNE_FP MINT_CNE_R8
198 #define MINT_CEQ_FP MINT_CEQ_R8
199 #define MINT_CGT_FP MINT_CGT_R8
200 #define MINT_CGE_FP MINT_CGE_R8
201 #define MINT_CLT_FP MINT_CLT_R8
202 #define MINT_CLE_FP MINT_CLE_R8
204 #define MINT_CONV_OVF_U4_P MINT_CONV_OVF_U4_I8
207 #define MINT_NEG_P MINT_NEG_I4
208 #define MINT_NOT_P MINT_NOT_I4
210 #define MINT_NEG_FP MINT_NEG_R4
212 #define MINT_ADD_P MINT_ADD_I4
213 #define MINT_SUB_P MINT_SUB_I4
214 #define MINT_MUL_P MINT_MUL_I4
215 #define MINT_DIV_P MINT_DIV_I4
216 #define MINT_DIV_UN_P MINT_DIV_UN_I4
217 #define MINT_REM_P MINT_REM_I4
218 #define MINT_REM_UN_P MINT_REM_UN_I4
219 #define MINT_AND_P MINT_AND_I4
220 #define MINT_OR_P MINT_OR_I4
221 #define MINT_XOR_P MINT_XOR_I4
222 #define MINT_SHL_P MINT_SHL_I4
223 #define MINT_SHR_P MINT_SHR_I4
224 #define MINT_SHR_UN_P MINT_SHR_UN_I4
226 #define MINT_CEQ_P MINT_CEQ_I4
227 #define MINT_CNE_P MINT_CNE_I4
228 #define MINT_CLT_P MINT_CLT_I4
229 #define MINT_CLT_UN_P MINT_CLT_UN_I4
230 #define MINT_CGT_P MINT_CGT_I4
231 #define MINT_CGT_UN_P MINT_CGT_UN_I4
232 #define MINT_CLE_P MINT_CLE_I4
233 #define MINT_CLE_UN_P MINT_CLE_UN_I4
234 #define MINT_CGE_P MINT_CGE_I4
235 #define MINT_CGE_UN_P MINT_CGE_UN_I4
237 #define MINT_ADD_FP MINT_ADD_R4
238 #define MINT_SUB_FP MINT_SUB_R4
239 #define MINT_MUL_FP MINT_MUL_R4
240 #define MINT_DIV_FP MINT_DIV_R4
241 #define MINT_REM_FP MINT_REM_R4
243 #define MINT_CNE_FP MINT_CNE_R4
244 #define MINT_CEQ_FP MINT_CEQ_R4
245 #define MINT_CGT_FP MINT_CGT_R4
246 #define MINT_CGE_FP MINT_CGE_R4
247 #define MINT_CLT_FP MINT_CLT_R4
248 #define MINT_CLE_FP MINT_CLE_R4
250 #define MINT_CONV_OVF_U4_P MINT_CONV_OVF_U4_I4
254 const gchar
*op_name
;
258 // static const MagicIntrinsic int_binop[] = {
260 static const MagicIntrinsic int_unnop
[] = {
261 { "op_UnaryPlus", {MINT_NOP
, MINT_NOP
, MINT_NOP
}},
262 { "op_UnaryNegation", {MINT_NEG_P
, MINT_NEG_P
, MINT_NEG_FP
}},
263 { "op_OnesComplement", {MINT_NOT_P
, MINT_NOT_P
, MINT_NIY
}}
266 static const MagicIntrinsic int_binop
[] = {
267 { "op_Addition", {MINT_ADD_P
, MINT_ADD_P
, MINT_ADD_FP
}},
268 { "op_Subtraction", {MINT_SUB_P
, MINT_SUB_P
, MINT_SUB_FP
}},
269 { "op_Multiply", {MINT_MUL_P
, MINT_MUL_P
, MINT_MUL_FP
}},
270 { "op_Division", {MINT_DIV_P
, MINT_DIV_UN_P
, MINT_DIV_FP
}},
271 { "op_Modulus", {MINT_REM_P
, MINT_REM_UN_P
, MINT_REM_FP
}},
272 { "op_BitwiseAnd", {MINT_AND_P
, MINT_AND_P
, MINT_NIY
}},
273 { "op_BitwiseOr", {MINT_OR_P
, MINT_OR_P
, MINT_NIY
}},
274 { "op_ExclusiveOr", {MINT_XOR_P
, MINT_XOR_P
, MINT_NIY
}},
275 { "op_LeftShift", {MINT_SHL_P
, MINT_SHL_P
, MINT_NIY
}},
276 { "op_RightShift", {MINT_SHR_P
, MINT_SHR_UN_P
, MINT_NIY
}},
279 static const MagicIntrinsic int_cmpop
[] = {
280 { "op_Inequality", {MINT_CNE_P
, MINT_CNE_P
, MINT_CNE_FP
}},
281 { "op_Equality", {MINT_CEQ_P
, MINT_CEQ_P
, MINT_CEQ_FP
}},
282 { "op_GreaterThan", {MINT_CGT_P
, MINT_CGT_UN_P
, MINT_CGT_FP
}},
283 { "op_GreaterThanOrEqual", {MINT_CGE_P
, MINT_CGE_UN_P
, MINT_CGE_FP
}},
284 { "op_LessThan", {MINT_CLT_P
, MINT_CLT_UN_P
, MINT_CLT_FP
}},
285 { "op_LessThanOrEqual", {MINT_CLE_P
, MINT_CLE_UN_P
, MINT_CLE_FP
}}
288 static gboolean
generate_code (TransformData
*td
, MonoMethod
*method
, MonoMethodHeader
*header
, MonoGenericContext
*generic_context
, MonoError
*error
);
291 interp_new_ins (TransformData
*td
, guint16 opcode
, int len
)
293 InterpInst
*new_inst
;
295 // Size of data region of instruction is length of instruction minus 1 (the opcode slot)
296 new_inst
= mono_mempool_alloc0 (td
->mempool
, sizeof (InterpInst
) + sizeof (guint16
) * (len
- 1));
297 new_inst
->opcode
= opcode
;
298 // opcodes from inlined methods don't have il offset associated with them since the offset
299 // stored here is relevant only for the original method
300 if (!td
->inlined_method
)
301 new_inst
->il_offset
= td
->in_start
- td
->il_code
;
303 new_inst
->il_offset
= -1;
307 // This version need to be used with switch opcode, which doesn't have constant length
309 interp_add_ins_explicit (TransformData
*td
, guint16 opcode
, int len
)
311 InterpInst
*new_inst
= interp_new_ins (td
, opcode
, len
);
312 new_inst
->prev
= td
->last_ins
;
314 td
->last_ins
->next
= new_inst
;
316 td
->first_ins
= new_inst
;
317 td
->last_ins
= new_inst
;
322 interp_add_ins (TransformData
*td
, guint16 opcode
)
324 return interp_add_ins_explicit (td
, opcode
, mono_interp_oplen
[opcode
]);
327 // Inserts a new instruction inside the instruction stream
329 interp_insert_ins (TransformData
*td
, InterpInst
*prev_ins
, guint16 opcode
)
331 InterpInst
*new_inst
= interp_new_ins (td
, opcode
, mono_interp_oplen
[opcode
]);
332 g_assert (prev_ins
&& prev_ins
->next
);
334 new_inst
->prev
= prev_ins
;
335 new_inst
->next
= prev_ins
->next
;
336 prev_ins
->next
= new_inst
;
337 new_inst
->next
->prev
= new_inst
;
343 interp_remove_ins (TransformData
*td
, InterpInst
*ins
)
346 ins
->prev
->next
= ins
->next
;
348 td
->first_ins
= ins
->next
;
351 ins
->next
->prev
= ins
->prev
;
353 td
->last_ins
= ins
->prev
;
357 #define CHECK_STACK(td, n) \
359 int stack_size = (td)->sp - (td)->stack; \
360 if (stack_size < (n)) \
361 g_warning ("%s.%s: not enough values (%d < %d) on stack at %04x", \
362 m_class_get_name ((td)->method->klass), (td)->method->name, \
363 stack_size, n, (td)->ip - (td)->il_code); \
366 #define ENSURE_I4(td, sp_off) \
368 if ((td)->sp [-sp_off].type == STACK_TYPE_I8) \
369 interp_add_ins (td, sp_off == 1 ? MINT_CONV_I4_I8 : MINT_CONV_I4_I8_SP); \
372 #define CHECK_TYPELOAD(klass) \
374 if (!(klass) || mono_class_has_failure (klass)) { \
375 mono_error_set_for_class_failure (error, klass); \
380 #if NO_UNALIGNED_ACCESS
381 #define WRITE32(ip, v) \
383 * (ip) = * (guint16 *)(v); \
384 * ((ip) + 1) = * ((guint16 *)(v) + 1); \
388 #define WRITE32_INS(ins, index, v) \
390 (ins)->data [index] = * (guint16 *)(v); \
391 (ins)->data [index + 1] = * ((guint16 *)(v) + 1); \
394 #define WRITE64_INS(ins, index, v) \
396 (ins)->data [index] = * (guint16 *)(v); \
397 (ins)->data [index + 1] = * ((guint16 *)(v) + 1); \
398 (ins)->data [index + 2] = * ((guint16 *)(v) + 2); \
399 (ins)->data [index + 3] = * ((guint16 *)(v) + 3); \
402 #define WRITE32(ip, v) \
404 * (guint32*)(ip) = * (guint32 *)(v); \
407 #define WRITE32_INS(ins, index, v) \
409 * (guint32 *)(&(ins)->data [index]) = * (guint32 *)(v); \
412 #define WRITE64_INS(ins, index, v) \
414 * (guint64 *)(&(ins)->data [index]) = * (guint64 *)(v); \
421 handle_branch (TransformData
*td
, int short_op
, int long_op
, int offset
)
423 int shorten_branch
= 0;
424 int target
= td
->ip
+ offset
- td
->il_code
;
425 if (target
< 0 || target
>= td
->code_size
)
426 g_assert_not_reached ();
427 /* Add exception checkpoint or safepoint for backward branches */
429 if (mono_threads_are_safepoints_enabled ())
430 interp_add_ins (td
, MINT_SAFEPOINT
);
432 interp_add_ins (td
, MINT_CHECKPOINT
);
434 if (offset
> 0 && td
->stack_height
[target
] < 0) {
435 td
->stack_height
[target
] = td
->sp
- td
->stack
;
436 if (td
->stack_height
[target
] > 0)
437 td
->stack_state
[target
] = (StackInfo
*)g_memdup (td
->stack
, td
->stack_height
[target
] * sizeof (td
->stack
[0]));
438 td
->vt_stack_size
[target
] = td
->vt_sp
;
441 if (td
->header
->code_size
<= 25000) /* FIX to be precise somehow? */
444 if (shorten_branch
) {
445 interp_add_ins (td
, short_op
);
446 td
->last_ins
->data
[0] = (guint16
) target
;
448 interp_add_ins (td
, long_op
);
449 WRITE32_INS (td
->last_ins
, 0, &target
);
454 one_arg_branch(TransformData
*td
, int mint_op
, int offset
)
456 int type
= td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
? STACK_TYPE_I
: td
->sp
[-1].type
;
457 int long_op
= mint_op
+ type
- STACK_TYPE_I4
;
458 int short_op
= long_op
+ MINT_BRFALSE_I4_S
- MINT_BRFALSE_I4
;
461 handle_branch (td
, short_op
, long_op
, offset
);
465 two_arg_branch(TransformData
*td
, int mint_op
, int offset
)
467 int type1
= td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
? STACK_TYPE_I
: td
->sp
[-1].type
;
468 int type2
= td
->sp
[-2].type
== STACK_TYPE_O
|| td
->sp
[-2].type
== STACK_TYPE_MP
? STACK_TYPE_I
: td
->sp
[-2].type
;
469 int long_op
= mint_op
+ type1
- STACK_TYPE_I4
;
470 int short_op
= long_op
+ MINT_BEQ_I4_S
- MINT_BEQ_I4
;
472 if (type1
== STACK_TYPE_I4
&& type2
== STACK_TYPE_I8
) {
473 interp_add_ins (td
, MINT_CONV_I8_I4
);
474 // The il instruction starts with the actual branch, and not with the conversion opcodes
475 td
->last_ins
->il_offset
= -1;
476 } else if (type1
== STACK_TYPE_I8
&& type2
== STACK_TYPE_I4
) {
477 interp_add_ins (td
, MINT_CONV_I8_I4_SP
);
478 td
->last_ins
->il_offset
= -1;
479 } else if (type1
== STACK_TYPE_R4
&& type2
== STACK_TYPE_R8
) {
480 interp_add_ins (td
, MINT_CONV_R8_R4
);
481 td
->last_ins
->il_offset
= -1;
482 } else if (type1
== STACK_TYPE_R8
&& type2
== STACK_TYPE_R4
) {
483 interp_add_ins (td
, MINT_CONV_R8_R4_SP
);
484 td
->last_ins
->il_offset
= -1;
485 } else if (type1
!= type2
) {
486 g_warning("%s.%s: branch type mismatch %d %d",
487 m_class_get_name (td
->method
->klass
), td
->method
->name
,
488 td
->sp
[-1].type
, td
->sp
[-2].type
);
491 handle_branch (td
, short_op
, long_op
, offset
);
495 unary_arith_op(TransformData
*td
, int mint_op
)
497 int op
= mint_op
+ td
->sp
[-1].type
- STACK_TYPE_I4
;
499 interp_add_ins (td
, op
);
503 binary_arith_op(TransformData
*td
, int mint_op
)
505 int type1
= td
->sp
[-2].type
;
506 int type2
= td
->sp
[-1].type
;
508 #if SIZEOF_VOID_P == 8
509 if ((type1
== STACK_TYPE_MP
|| type1
== STACK_TYPE_I8
) && type2
== STACK_TYPE_I4
) {
510 interp_add_ins (td
, MINT_CONV_I8_I4
);
511 type2
= STACK_TYPE_I8
;
513 if (type1
== STACK_TYPE_I4
&& (type2
== STACK_TYPE_MP
|| type2
== STACK_TYPE_I8
)) {
514 interp_add_ins (td
, MINT_CONV_I8_I4_SP
);
515 type1
= STACK_TYPE_I8
;
516 td
->sp
[-2].type
= STACK_TYPE_I8
;
519 if (type1
== STACK_TYPE_R8
&& type2
== STACK_TYPE_R4
) {
520 interp_add_ins (td
, MINT_CONV_R8_R4
);
521 type2
= STACK_TYPE_R8
;
523 if (type1
== STACK_TYPE_R4
&& type2
== STACK_TYPE_R8
) {
524 interp_add_ins (td
, MINT_CONV_R8_R4_SP
);
525 type1
= STACK_TYPE_R8
;
526 td
->sp
[-2].type
= STACK_TYPE_R8
;
528 if (type1
== STACK_TYPE_MP
)
529 type1
= STACK_TYPE_I
;
530 if (type2
== STACK_TYPE_MP
)
531 type2
= STACK_TYPE_I
;
532 if (type1
!= type2
) {
533 g_warning("%s.%s: %04x arith type mismatch %s %d %d",
534 m_class_get_name (td
->method
->klass
), td
->method
->name
,
535 td
->ip
- td
->il_code
, mono_interp_opname
[mint_op
], type1
, type2
);
537 op
= mint_op
+ type1
- STACK_TYPE_I4
;
539 interp_add_ins (td
, op
);
544 shift_op(TransformData
*td
, int mint_op
)
546 int op
= mint_op
+ td
->sp
[-2].type
- STACK_TYPE_I4
;
548 if (td
->sp
[-1].type
!= STACK_TYPE_I4
) {
549 g_warning("%s.%s: shift type mismatch %d",
550 m_class_get_name (td
->method
->klass
), td
->method
->name
,
553 interp_add_ins (td
, op
);
558 can_store (int st_value
, int vt_value
)
560 if (st_value
== STACK_TYPE_O
|| st_value
== STACK_TYPE_MP
)
561 st_value
= STACK_TYPE_I
;
562 if (vt_value
== STACK_TYPE_O
|| vt_value
== STACK_TYPE_MP
)
563 vt_value
= STACK_TYPE_I
;
564 return st_value
== vt_value
;
567 #define SET_SIMPLE_TYPE(s, ty) \
574 #define SET_TYPE(s, ty, k) \
581 #define REALLOC_STACK(td, sppos) \
583 (td)->stack_capacity *= 2; \
584 (td)->stack = (StackInfo*)realloc ((td)->stack, (td)->stack_capacity * sizeof (td->stack [0])); \
585 (td)->sp = (td)->stack + sppos; \
588 #define PUSH_SIMPLE_TYPE(td, ty) \
592 sp_height = (td)->sp - (td)->stack; \
593 if (sp_height > (td)->max_stack_height) \
594 (td)->max_stack_height = sp_height; \
595 if (sp_height > (td)->stack_capacity) \
596 REALLOC_STACK(td, sp_height); \
597 SET_SIMPLE_TYPE((td)->sp - 1, ty); \
600 #define PUSH_TYPE(td, ty, k) \
604 sp_height = (td)->sp - (td)->stack; \
605 if (sp_height > (td)->max_stack_height) \
606 (td)->max_stack_height = sp_height; \
607 if (sp_height > (td)->stack_capacity) \
608 REALLOC_STACK(td, sp_height); \
609 SET_TYPE((td)->sp - 1, ty, k); \
612 #define PUSH_VT(td, size) \
614 (td)->vt_sp += ALIGN_TO ((size), MINT_VT_ALIGNMENT); \
615 if ((td)->vt_sp > (td)->max_vt_sp) \
616 (td)->max_vt_sp = (td)->vt_sp; \
619 #define POP_VT(td, size) \
621 (td)->vt_sp -= ALIGN_TO ((size), MINT_VT_ALIGNMENT); \
625 get_arg_type_exact (TransformData
*td
, int n
, int *mt
)
628 gboolean hasthis
= mono_method_signature_internal (td
->method
)->hasthis
;
630 if (hasthis
&& n
== 0)
631 type
= m_class_get_byval_arg (td
->method
->klass
);
633 type
= mono_method_signature_internal (td
->method
)->params
[n
- !!hasthis
];
636 *mt
= mint_type (type
);
642 load_arg(TransformData
*td
, int n
)
645 MonoClass
*klass
= NULL
;
647 gboolean hasthis
= mono_method_signature_internal (td
->method
)->hasthis
;
649 type
= get_arg_type_exact (td
, n
, &mt
);
651 if (mt
== MINT_TYPE_VT
) {
653 klass
= mono_class_from_mono_type_internal (type
);
654 if (mono_method_signature_internal (td
->method
)->pinvoke
)
655 size
= mono_class_native_size (klass
, NULL
);
657 size
= mono_class_value_size (klass
, NULL
);
659 if (hasthis
&& n
== 0) {
661 interp_add_ins (td
, MINT_LDARG_P
);
662 td
->last_ins
->data
[0] = 0;
666 interp_add_ins (td
, MINT_LDARG_VT
);
667 td
->last_ins
->data
[0] = n
;
668 WRITE32_INS (td
->last_ins
, 1, &size
);
671 if (hasthis
&& n
== 0) {
673 interp_add_ins (td
, MINT_LDARG_P
);
674 td
->last_ins
->data
[0] = n
;
677 interp_add_ins (td
, MINT_LDARG_I1
+ (mt
- MINT_TYPE_I1
));
678 td
->last_ins
->data
[0] = n
;
679 if (mt
== MINT_TYPE_O
)
680 klass
= mono_class_from_mono_type_internal (type
);
683 PUSH_TYPE(td
, stack_type
[mt
], klass
);
687 store_arg(TransformData
*td
, int n
)
693 type
= get_arg_type_exact (td
, n
, &mt
);
695 if (mt
== MINT_TYPE_VT
) {
697 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
698 if (mono_method_signature_internal (td
->method
)->pinvoke
)
699 size
= mono_class_native_size (klass
, NULL
);
701 size
= mono_class_value_size (klass
, NULL
);
702 interp_add_ins (td
, MINT_STARG_VT
);
703 td
->last_ins
->data
[0] = n
;
704 WRITE32_INS (td
->last_ins
, 1, &size
);
705 if (td
->sp
[-1].type
== STACK_TYPE_VT
)
708 interp_add_ins (td
, MINT_STARG_I1
+ (mt
- MINT_TYPE_I1
));
709 td
->last_ins
->data
[0] = n
;
715 load_local_general (TransformData
*td
, int offset
, MonoType
*type
)
717 int mt
= mint_type (type
);
718 MonoClass
*klass
= NULL
;
719 if (mt
== MINT_TYPE_VT
) {
720 klass
= mono_class_from_mono_type_internal (type
);
721 gint32 size
= mono_class_value_size (klass
, NULL
);
723 interp_add_ins (td
, MINT_LDLOC_VT
);
724 td
->last_ins
->data
[0] = offset
;
725 WRITE32_INS (td
->last_ins
, 1, &size
);
727 g_assert (mt
< MINT_TYPE_VT
);
728 if (!td
->gen_sdb_seq_points
&&
729 mt
== MINT_TYPE_I4
&& !td
->is_bb_start
[td
->in_start
- td
->il_code
] && td
->last_ins
!= NULL
&&
730 td
->last_ins
->opcode
== MINT_STLOC_I4
&& td
->last_ins
->data
[0] == offset
) {
731 td
->last_ins
->opcode
= MINT_STLOC_NP_I4
;
732 } else if (!td
->gen_sdb_seq_points
&&
733 mt
== MINT_TYPE_O
&& !td
->is_bb_start
[td
->in_start
- td
->il_code
] && td
->last_ins
!= NULL
&&
734 td
->last_ins
->opcode
== MINT_STLOC_O
&& td
->last_ins
->data
[0] == offset
) {
735 td
->last_ins
->opcode
= MINT_STLOC_NP_O
;
737 interp_add_ins (td
, MINT_LDLOC_I1
+ (mt
- MINT_TYPE_I1
));
738 td
->last_ins
->data
[0] = offset
; /*FIX for large offset */
740 if (mt
== MINT_TYPE_O
)
741 klass
= mono_class_from_mono_type_internal (type
);
743 PUSH_TYPE(td
, stack_type
[mt
], klass
);
747 load_local (TransformData
*td
, int n
)
749 MonoType
*type
= td
->header
->locals
[n
];
750 int offset
= td
->rtm
->local_offsets
[n
];
751 load_local_general (td
, offset
, type
);
755 store_local_general (TransformData
*td
, int offset
, MonoType
*type
)
757 int mt
= mint_type (type
);
759 #if SIZEOF_VOID_P == 8
760 if (td
->sp
[-1].type
== STACK_TYPE_I4
&& stack_type
[mt
] == STACK_TYPE_I8
) {
761 interp_add_ins (td
, MINT_CONV_I8_I4
);
762 td
->sp
[-1].type
= STACK_TYPE_I8
;
765 if (!can_store(td
->sp
[-1].type
, stack_type
[mt
])) {
766 g_warning("%s.%s: Store local stack type mismatch %d %d",
767 m_class_get_name (td
->method
->klass
), td
->method
->name
,
768 stack_type
[mt
], td
->sp
[-1].type
);
770 if (mt
== MINT_TYPE_VT
) {
771 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
772 gint32 size
= mono_class_value_size (klass
, NULL
);
773 interp_add_ins (td
, MINT_STLOC_VT
);
774 td
->last_ins
->data
[0] = offset
; /*FIX for large offset */
775 WRITE32_INS (td
->last_ins
, 1, &size
);
776 if (td
->sp
[-1].type
== STACK_TYPE_VT
)
779 g_assert (mt
< MINT_TYPE_VT
);
780 interp_add_ins (td
, MINT_STLOC_I1
+ (mt
- MINT_TYPE_I1
));
781 td
->last_ins
->data
[0] = offset
; /*FIX for large offset */
787 store_local (TransformData
*td
, int n
)
789 MonoType
*type
= td
->header
->locals
[n
];
790 int offset
= td
->rtm
->local_offsets
[n
];
791 store_local_general (td
, offset
, type
);
794 #define SIMPLE_OP(td, op) \
796 interp_add_ins (td, op); \
801 get_data_item_index (TransformData
*td
, void *ptr
)
803 gpointer p
= g_hash_table_lookup (td
->data_hash
, ptr
);
806 return GPOINTER_TO_UINT (p
) - 1;
807 if (td
->max_data_items
== td
->n_data_items
) {
808 td
->max_data_items
= td
->n_data_items
== 0 ? 16 : 2 * td
->max_data_items
;
809 td
->data_items
= (gpointer
*)g_realloc (td
->data_items
, td
->max_data_items
* sizeof(td
->data_items
[0]));
811 index
= td
->n_data_items
;
812 td
->data_items
[index
] = ptr
;
814 g_hash_table_insert (td
->data_hash
, ptr
, GUINT_TO_POINTER (index
+ 1));
819 jit_call_supported (MonoMethod
*method
, MonoMethodSignature
*sig
)
823 if (sig
->param_count
> 6)
827 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
829 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
)
831 if (method
->is_inflated
)
833 if (method
->string_ctor
)
836 if (mono_aot_only
&& m_class_get_image (method
->klass
)->aot_module
&& !(method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)) {
838 gpointer addr
= mono_jit_compile_method_jit_only (method
, error
);
839 if (addr
&& mono_error_ok (error
))
843 for (l
= mono_interp_jit_classes
; l
; l
= l
->next
) {
844 const char *class_name
= (const char*)l
->data
;
846 if (!strcmp (m_class_get_name (method
->klass
), class_name
))
854 static int mono_class_get_magic_index (MonoClass
*k
)
856 if (mono_class_is_magic_int (k
))
857 return !strcmp ("nint", m_class_get_name (k
)) ? 0 : 1;
859 if (mono_class_is_magic_float (k
))
866 interp_generate_mae_throw (TransformData
*td
, MonoMethod
*method
, MonoMethod
*target_method
)
868 MonoJitICallInfo
*info
= &mono_get_jit_icall_info ()->mono_throw_method_access
;
870 /* Inject code throwing MethodAccessException */
871 interp_add_ins (td
, MINT_MONO_LDPTR
);
872 td
->last_ins
->data
[0] = get_data_item_index (td
, method
);
873 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
875 interp_add_ins (td
, MINT_MONO_LDPTR
);
876 td
->last_ins
->data
[0] = get_data_item_index (td
, target_method
);
877 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
879 interp_add_ins (td
, MINT_ICALL_PP_V
);
880 td
->last_ins
->data
[0] = get_data_item_index (td
, (gpointer
)info
->func
);
886 * These are additional locals that can be allocated as we transform the code.
887 * They are allocated past the method locals so they are accessed in the same
888 * way, with an offset relative to the frame->locals.
891 create_interp_local (TransformData
*td
, MonoType
*type
)
894 int offset
= td
->total_locals_size
;
896 size
= mono_type_size (type
, &align
);
897 offset
= ALIGN_TO (offset
, align
);
899 td
->total_locals_size
= offset
+ size
;
905 dump_mint_code (const guint16
*start
, const guint16
* end
)
907 const guint16
*p
= start
;
909 char *ins
= mono_interp_dis_mintop (start
, p
);
910 g_print ("%s\n", ins
);
912 p
= mono_interp_dis_mintop_len (p
);
918 mono_interp_print_code (InterpMethod
*imethod
)
920 MonoJitInfo
*jinfo
= imethod
->jinfo
;
921 const guint16
*start
;
926 char *name
= mono_method_full_name (imethod
->method
, 1);
927 g_print ("Method : %s\n", name
);
930 start
= (guint16
*) jinfo
->code_start
;
931 dump_mint_code (start
, start
+ jinfo
->code_size
);
935 static MonoMethodHeader
*
936 interp_method_get_header (MonoMethod
* method
, MonoError
*error
)
938 /* An explanation: mono_method_get_header_internal returns an error if
939 * called on a method with no body (e.g. an abstract method, or an
940 * icall). We don't want that.
942 if (mono_method_has_no_body (method
))
945 return mono_method_get_header_internal (method
, error
);
948 /* stores top of stack as local and pushes address of it on stack */
950 emit_store_value_as_local (TransformData
*td
, MonoType
*src
)
952 int size
= mini_magic_type_size (NULL
, src
);
953 int local_offset
= create_interp_local (td
, mini_native_type_replace_type (src
));
955 store_local_general (td
, local_offset
, src
);
957 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
958 interp_add_ins (td
, MINT_LDLOC_VT
);
959 td
->last_ins
->data
[0] = local_offset
;
960 WRITE32_INS (td
->last_ins
, 1, &size
);
963 PUSH_TYPE (td
, STACK_TYPE_VT
, NULL
);
966 // Returns whether we can optimize away the instructions starting at start.
967 // If any instructions are part of a new basic block, we can't remove them.
969 interp_is_bb_start (TransformData
*td
, InterpInst
*start
, InterpInst
*end
)
971 InterpInst
*ins
= start
;
973 if (ins
->il_offset
!= -1) {
974 if (td
->is_bb_start
[ins
->il_offset
])
983 interp_ins_is_ldc (InterpInst
*ins
)
985 return ins
->opcode
>= MINT_LDC_I4_M1
&& ins
->opcode
<= MINT_LDC_I8
;
989 interp_ldc_i4_get_const (InterpInst
*ins
)
991 switch (ins
->opcode
) {
992 case MINT_LDC_I4_M1
: return -1;
993 case MINT_LDC_I4_0
: return 0;
994 case MINT_LDC_I4_1
: return 1;
995 case MINT_LDC_I4_2
: return 2;
996 case MINT_LDC_I4_3
: return 3;
997 case MINT_LDC_I4_4
: return 4;
998 case MINT_LDC_I4_5
: return 5;
999 case MINT_LDC_I4_6
: return 6;
1000 case MINT_LDC_I4_7
: return 7;
1001 case MINT_LDC_I4_8
: return 8;
1002 case MINT_LDC_I4_S
: return (gint32
)(gint8
)ins
->data
[0];
1003 case MINT_LDC_I4
: return READ32 (&ins
->data
[0]);
1005 g_assert_not_reached ();
1010 interp_get_ldind_for_mt (int mt
)
1013 case MINT_TYPE_I1
: return MINT_LDIND_I1_CHECK
;
1014 case MINT_TYPE_U1
: return MINT_LDIND_U1_CHECK
;
1015 case MINT_TYPE_I2
: return MINT_LDIND_I2_CHECK
;
1016 case MINT_TYPE_U2
: return MINT_LDIND_U2_CHECK
;
1017 case MINT_TYPE_I4
: return MINT_LDIND_I4_CHECK
;
1018 case MINT_TYPE_I8
: return MINT_LDIND_I8_CHECK
;
1019 case MINT_TYPE_R4
: return MINT_LDIND_R4_CHECK
;
1020 case MINT_TYPE_R8
: return MINT_LDIND_R8_CHECK
;
1021 case MINT_TYPE_O
: return MINT_LDIND_REF
;
1023 g_assert_not_reached ();
1028 /* Return TRUE if call transformation is finished */
1030 interp_handle_intrinsics (TransformData
*td
, MonoMethod
*target_method
, MonoClass
*constrained_class
, MonoMethodSignature
*csignature
, gboolean readonly
, int *op
)
1032 const char *tm
= target_method
->name
;
1034 int type_index
= mono_class_get_magic_index (target_method
->klass
);
1035 gboolean in_corlib
= m_class_get_image (target_method
->klass
) == mono_defaults
.corlib
;
1036 const char *klass_name_space
= m_class_get_name_space (target_method
->klass
);
1037 const char *klass_name
= m_class_get_name (target_method
->klass
);
1039 if (target_method
->klass
== mono_defaults
.string_class
) {
1040 if (tm
[0] == 'g') {
1041 if (strcmp (tm
, "get_Chars") == 0)
1043 else if (strcmp (tm
, "get_Length") == 0)
1046 } else if (type_index
>= 0) {
1047 MonoClass
*magic_class
= target_method
->klass
;
1049 const int mt
= mint_type (m_class_get_byval_arg (magic_class
));
1050 if (!strcmp (".ctor", tm
)) {
1051 MonoType
*arg
= csignature
->params
[0];
1052 /* depending on SIZEOF_VOID_P and the type of the value passed to the .ctor we either have to CONV it, or do nothing */
1053 int arg_size
= mini_magic_type_size (NULL
, arg
);
1055 if (arg_size
> SIZEOF_VOID_P
) { // 8 -> 4
1056 switch (type_index
) {
1058 interp_add_ins (td
, MINT_CONV_I4_I8
);
1061 interp_add_ins (td
, MINT_CONV_R4_R8
);
1066 if (arg_size
< SIZEOF_VOID_P
) { // 4 -> 8
1067 switch (type_index
) {
1069 interp_add_ins (td
, MINT_CONV_I8_I4
);
1072 interp_add_ins (td
, MINT_CONV_I8_U4
);
1075 interp_add_ins (td
, MINT_CONV_R8_R4
);
1080 switch (type_index
) {
1082 #if SIZEOF_VOID_P == 4
1083 interp_add_ins (td
, MINT_STIND_I4
);
1085 interp_add_ins (td
, MINT_STIND_I8
);
1089 #if SIZEOF_VOID_P == 4
1090 interp_add_ins (td
, MINT_STIND_R4
);
1092 interp_add_ins (td
, MINT_STIND_R8
);
1100 } else if (!strcmp ("op_Implicit", tm
) || !strcmp ("op_Explicit", tm
)) {
1101 MonoType
*src
= csignature
->params
[0];
1102 MonoType
*dst
= csignature
->ret
;
1103 MonoClass
*src_klass
= mono_class_from_mono_type_internal (src
);
1104 int src_size
= mini_magic_type_size (NULL
, src
);
1105 int dst_size
= mini_magic_type_size (NULL
, dst
);
1107 gboolean store_value_as_local
= FALSE
;
1109 switch (type_index
) {
1111 if (!mini_magic_is_int_type (src
) || !mini_magic_is_int_type (dst
)) {
1112 if (mini_magic_is_int_type (src
))
1113 store_value_as_local
= TRUE
;
1114 else if (mono_class_is_magic_float (src_klass
))
1115 store_value_as_local
= TRUE
;
1121 if (!mini_magic_is_float_type (src
) || !mini_magic_is_float_type (dst
)) {
1122 if (mini_magic_is_float_type (src
))
1123 store_value_as_local
= TRUE
;
1124 else if (mono_class_is_magic_int (src_klass
))
1125 store_value_as_local
= TRUE
;
1132 if (store_value_as_local
) {
1133 emit_store_value_as_local (td
, src
);
1135 /* emit call to managed conversion method */
1139 if (src_size
> dst_size
) { // 8 -> 4
1140 switch (type_index
) {
1142 interp_add_ins (td
, MINT_CONV_I4_I8
);
1145 interp_add_ins (td
, MINT_CONV_R4_R8
);
1150 if (src_size
< dst_size
) { // 4 -> 8
1151 switch (type_index
) {
1153 interp_add_ins (td
, MINT_CONV_I8_I4
);
1156 interp_add_ins (td
, MINT_CONV_I8_U4
);
1159 interp_add_ins (td
, MINT_CONV_R8_R4
);
1164 SET_TYPE (td
->sp
- 1, stack_type
[mint_type (dst
)], mono_class_from_mono_type_internal (dst
));
1167 } else if (!strcmp ("op_Increment", tm
)) {
1168 g_assert (type_index
!= 2); // no nfloat
1169 #if SIZEOF_VOID_P == 8
1170 interp_add_ins (td
, MINT_ADD1_I8
);
1172 interp_add_ins (td
, MINT_ADD1_I4
);
1174 SET_TYPE (td
->sp
- 1, stack_type
[mt
], magic_class
);
1177 } else if (!strcmp ("op_Decrement", tm
)) {
1178 g_assert (type_index
!= 2); // no nfloat
1179 #if SIZEOF_VOID_P == 8
1180 interp_add_ins (td
, MINT_SUB1_I8
);
1182 interp_add_ins (td
, MINT_SUB1_I4
);
1184 SET_TYPE (td
->sp
- 1, stack_type
[mt
], magic_class
);
1187 } else if (!strcmp ("CompareTo", tm
) || !strcmp ("Equals", tm
)) {
1188 MonoType
*arg
= csignature
->params
[0];
1190 /* on 'System.n*::{CompareTo,Equals} (System.n*)' variant we need to push managed
1191 * pointer instead of value */
1192 if (arg
->type
== MONO_TYPE_VALUETYPE
)
1193 emit_store_value_as_local (td
, arg
);
1195 /* emit call to managed conversion method */
1197 } else if (!strcmp (".cctor", tm
)) {
1200 } else if (!strcmp ("Parse", tm
)) {
1203 } else if (!strcmp ("ToString", tm
)) {
1206 } else if (!strcmp ("GetHashCode", tm
)) {
1209 } else if (!strcmp ("IsNaN", tm
) || !strcmp ("IsInfinity", tm
) || !strcmp ("IsNegativeInfinity", tm
) || !strcmp ("IsPositiveInfinity", tm
)) {
1210 g_assert (type_index
== 2); // nfloat only
1215 for (i
= 0; i
< sizeof (int_unnop
) / sizeof (MagicIntrinsic
); ++i
) {
1216 if (!strcmp (int_unnop
[i
].op_name
, tm
)) {
1217 interp_add_ins (td
, int_unnop
[i
].insn
[type_index
]);
1218 SET_TYPE (td
->sp
- 1, stack_type
[mt
], magic_class
);
1224 for (i
= 0; i
< sizeof (int_binop
) / sizeof (MagicIntrinsic
); ++i
) {
1225 if (!strcmp (int_binop
[i
].op_name
, tm
)) {
1226 interp_add_ins (td
, int_binop
[i
].insn
[type_index
]);
1228 SET_TYPE (td
->sp
- 1, stack_type
[mt
], magic_class
);
1234 for (i
= 0; i
< sizeof (int_cmpop
) / sizeof (MagicIntrinsic
); ++i
) {
1235 if (!strcmp (int_cmpop
[i
].op_name
, tm
)) {
1236 MonoClass
*k
= mono_defaults
.boolean_class
;
1237 interp_add_ins (td
, int_cmpop
[i
].insn
[type_index
]);
1239 SET_TYPE (td
->sp
- 1, stack_type
[mint_type (m_class_get_byval_arg (k
))], k
);
1245 g_error ("TODO: interp_transform_call %s:%s", m_class_get_name (target_method
->klass
), tm
);
1246 } else if (mono_class_is_subclass_of_internal (target_method
->klass
, mono_defaults
.array_class
, FALSE
)) {
1247 if (!strcmp (tm
, "get_Rank")) {
1248 *op
= MINT_ARRAY_RANK
;
1249 } else if (!strcmp (tm
, "get_Length")) {
1251 } else if (!strcmp (tm
, "Address")) {
1252 *op
= readonly
? MINT_LDELEMA
: MINT_LDELEMA_TC
;
1253 } else if (!strcmp (tm
, "UnsafeMov") || !strcmp (tm
, "UnsafeLoad") || !strcmp (tm
, "Set") || !strcmp (tm
, "Get")) {
1255 } else if (!strcmp (tm
, "UnsafeStore")) {
1256 g_error ("TODO ArrayClass::UnsafeStore");
1258 } else if (in_corlib
&&
1259 !strcmp (klass_name_space
, "System.Diagnostics") &&
1260 !strcmp (klass_name
, "Debugger")) {
1261 if (!strcmp (tm
, "Break") && csignature
->param_count
== 0) {
1262 if (mini_should_insert_breakpoint (td
->method
))
1265 } else if (in_corlib
&& !strcmp (klass_name_space
, "System") && !strcmp (klass_name
, "ByReference`1")) {
1266 g_assert (!strcmp (tm
, "get_Value"));
1267 *op
= MINT_INTRINS_BYREFERENCE_GET_VALUE
;
1268 } else if (in_corlib
&& !strcmp (klass_name_space
, "System") && !strcmp (klass_name
, "Math") && csignature
->param_count
== 1 && csignature
->params
[0]->type
== MONO_TYPE_R8
) {
1269 if (tm
[0] == 'A') {
1270 if (strcmp (tm
, "Abs") == 0 && csignature
->params
[0]->type
== MONO_TYPE_R8
) {
1272 } else if (strcmp (tm
, "Asin") == 0){
1274 } else if (strcmp (tm
, "Asinh") == 0){
1276 } else if (strcmp (tm
, "Acos") == 0){
1278 } else if (strcmp (tm
, "Acosh") == 0){
1280 } else if (strcmp (tm
, "Atan") == 0){
1282 } else if (strcmp (tm
, "Atanh") == 0){
1285 } else if (tm
[0] == 'C') {
1286 if (strcmp (tm
, "Cos") == 0) {
1288 } else if (strcmp (tm
, "Cbrt") == 0){
1290 } else if (strcmp (tm
, "Cosh") == 0){
1293 } else if (tm
[0] == 'S') {
1294 if (strcmp (tm
, "Sin") == 0) {
1296 } else if (strcmp (tm
, "Sqrt") == 0) {
1298 } else if (strcmp (tm
, "Sinh") == 0){
1301 } else if (tm
[0] == 'T') {
1302 if (strcmp (tm
, "Tan") == 0) {
1304 } else if (strcmp (tm
, "Tanh") == 0){
1308 } else if (in_corlib
&& !strcmp (klass_name_space
, "System") && (!strcmp (klass_name
, "Span`1") || !strcmp (klass_name
, "ReadOnlySpan`1"))) {
1309 if (!strcmp (tm
, "get_Item")) {
1310 MonoGenericClass
*gclass
= mono_class_get_generic_class (target_method
->klass
);
1311 MonoClass
*param_class
= mono_class_from_mono_type_internal (gclass
->context
.class_inst
->type_argv
[0]);
1313 if (!mini_is_gsharedvt_variable_klass (param_class
)) {
1314 MonoClassField
*length_field
= mono_class_get_field_from_name_full (target_method
->klass
, "_length", NULL
);
1315 g_assert (length_field
);
1316 int offset_length
= length_field
->offset
- sizeof (MonoObject
);
1318 MonoClassField
*ptr_field
= mono_class_get_field_from_name_full (target_method
->klass
, "_pointer", NULL
);
1319 g_assert (ptr_field
);
1320 int offset_pointer
= ptr_field
->offset
- sizeof (MonoObject
);
1322 int size
= mono_class_array_element_size (param_class
);
1323 interp_add_ins (td
, MINT_GETITEM_SPAN
);
1324 td
->last_ins
->data
[0] = size
;
1325 td
->last_ins
->data
[1] = offset_length
;
1326 td
->last_ins
->data
[2] = offset_pointer
;
1328 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_MP
);
1333 } else if (!strcmp (tm
, "get_Length")) {
1334 MonoClassField
*length_field
= mono_class_get_field_from_name_full (target_method
->klass
, "_length", NULL
);
1335 g_assert (length_field
);
1336 int offset_length
= length_field
->offset
- sizeof (MonoObject
);
1337 interp_add_ins (td
, MINT_LDLEN_SPAN
);
1338 td
->last_ins
->data
[0] = offset_length
;
1339 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I4
);
1343 } else if (in_corlib
&& !strcmp (klass_name_space
, "Internal.Runtime.CompilerServices") && !strcmp (klass_name
, "Unsafe")) {
1344 #ifdef ENABLE_NETCORE
1345 if (!strcmp (tm
, "AddByteOffset"))
1346 *op
= MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET
;
1347 else if (!strcmp (tm
, "ByteOffset"))
1348 *op
= MINT_INTRINS_UNSAFE_BYTE_OFFSET
;
1349 else if (!strcmp (tm
, "As") || !strcmp (tm
, "AsRef"))
1351 else if (!strcmp (tm
, "AsPointer")) {
1353 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_MP
);
1356 } else if (!strcmp (tm
, "IsAddressLessThan")) {
1357 MonoGenericContext
*ctx
= mono_method_get_context (target_method
);
1359 g_assert (ctx
->method_inst
);
1360 g_assert (ctx
->method_inst
->type_argc
== 1);
1362 MonoClass
*k
= mono_defaults
.boolean_class
;
1363 interp_add_ins (td
, MINT_CLT_UN_P
);
1365 SET_TYPE (td
->sp
- 1, stack_type
[mint_type (m_class_get_byval_arg (k
))], k
);
1368 } else if (!strcmp (tm
, "SizeOf")) {
1369 MonoGenericContext
*ctx
= mono_method_get_context (target_method
);
1371 g_assert (ctx
->method_inst
);
1372 g_assert (ctx
->method_inst
->type_argc
== 1);
1373 MonoType
*t
= ctx
->method_inst
->type_argv
[0];
1375 int esize
= mono_type_size (t
, &align
);
1376 interp_add_ins (td
, MINT_LDC_I4
);
1377 WRITE32_INS (td
->last_ins
, 0, &esize
);
1378 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I4
);
1381 } else if (!strcmp (tm
, "AreSame")) {
1385 } else if (in_corlib
&& !strcmp (klass_name_space
, "System.Runtime.CompilerServices") && !strcmp (klass_name
, "RuntimeHelpers")) {
1386 #ifdef ENABLE_NETCORE
1387 if (!strcmp (tm
, "IsBitwiseEquatable")) {
1388 g_assert (csignature
->param_count
== 0);
1389 MonoGenericContext
*ctx
= mono_method_get_context (target_method
);
1391 g_assert (ctx
->method_inst
);
1392 g_assert (ctx
->method_inst
->type_argc
== 1);
1393 MonoType
*t
= mini_get_underlying_type (ctx
->method_inst
->type_argv
[0]);
1395 if (MONO_TYPE_IS_PRIMITIVE (t
) && t
->type
!= MONO_TYPE_R4
&& t
->type
!= MONO_TYPE_R8
)
1396 *op
= MINT_LDC_I4_1
;
1398 *op
= MINT_LDC_I4_0
;
1399 } else if (!strcmp (tm
, "ObjectHasComponentSize")) {
1400 *op
= MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE
;
1403 } else if (in_corlib
&& !strcmp (klass_name_space
, "System") && !strcmp (klass_name
, "RuntimeMethodHandle") && !strcmp (tm
, "GetFunctionPointer") && csignature
->param_count
== 1) {
1404 // We must intrinsify this method on interp so we don't return a pointer to native code entering interpreter
1405 *op
= MINT_LDFTN_DYNAMIC
;
1406 } else if (in_corlib
&& target_method
->klass
== mono_defaults
.object_class
) {
1407 if (!strcmp (tm
, "InternalGetHashCode"))
1408 *op
= MINT_INTRINS_GET_HASHCODE
;
1409 #ifdef DISABLE_REMOTING
1410 else if (!strcmp (tm
, "GetType"))
1411 *op
= MINT_INTRINS_GET_TYPE
;
1413 #ifdef ENABLE_NETCORE
1414 else if (!strcmp (tm
, "GetRawData")) {
1415 #if SIZEOF_VOID_P == 8
1416 interp_add_ins (td
, MINT_LDC_I8_S
);
1418 interp_add_ins (td
, MINT_LDC_I4_S
);
1420 td
->last_ins
->data
[0] = (gint16
) MONO_ABI_SIZEOF (MonoObject
);
1422 interp_add_ins (td
, MINT_ADD_P
);
1423 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_MP
);
1429 } else if (in_corlib
&& target_method
->klass
== mono_defaults
.enum_class
&& !strcmp (tm
, "HasFlag")) {
1430 gboolean intrinsify
= FALSE
;
1431 MonoClass
*base_klass
= NULL
;
1432 if (td
->last_ins
&& td
->last_ins
->opcode
== MINT_BOX
&&
1433 td
->last_ins
->prev
&& interp_ins_is_ldc (td
->last_ins
->prev
) &&
1434 td
->last_ins
->prev
->prev
&& td
->last_ins
->prev
->prev
->opcode
== MINT_BOX
&&
1435 td
->sp
[-2].klass
== td
->sp
[-1].klass
&&
1436 !interp_is_bb_start (td
, td
->last_ins
->prev
->prev
, NULL
) &&
1437 !td
->is_bb_start
[td
->in_start
- td
->il_code
]) {
1438 // csc pattern : box, ldc, box, call HasFlag
1439 g_assert (m_class_is_enumtype (td
->sp
[-2].klass
));
1440 MonoType
*base_type
= mono_type_get_underlying_type (m_class_get_byval_arg (td
->sp
[-2].klass
));
1441 base_klass
= mono_class_from_mono_type_internal (base_type
);
1443 // Remove the boxing of valuetypes
1444 interp_remove_ins (td
, td
->last_ins
->prev
->prev
);
1445 interp_remove_ins (td
, td
->last_ins
);
1448 } else if (td
->last_ins
&& td
->last_ins
->opcode
== MINT_BOX
&&
1449 td
->last_ins
->prev
&& interp_ins_is_ldc (td
->last_ins
->prev
) &&
1450 constrained_class
&& td
->sp
[-1].klass
== constrained_class
&&
1451 !interp_is_bb_start (td
, td
->last_ins
->prev
, NULL
) &&
1452 !td
->is_bb_start
[td
->in_start
- td
->il_code
]) {
1453 // mcs pattern : ldc, box, constrained Enum, call HasFlag
1454 g_assert (m_class_is_enumtype (constrained_class
));
1455 MonoType
*base_type
= mono_type_get_underlying_type (m_class_get_byval_arg (constrained_class
));
1456 base_klass
= mono_class_from_mono_type_internal (base_type
);
1457 int mt
= mint_type (m_class_get_byval_arg (base_klass
));
1459 // Remove boxing and load the value of this
1460 interp_remove_ins (td
, td
->last_ins
);
1461 interp_insert_ins (td
, td
->last_ins
->prev
, interp_get_ldind_for_mt (mt
));
1466 interp_add_ins (td
, MINT_INTRINS_ENUM_HASFLAG
);
1467 td
->last_ins
->data
[0] = get_data_item_index (td
, base_klass
);
1469 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I4
);
1473 } else if (in_corlib
&& !strcmp (klass_name_space
, "System.Threading") && !strcmp (klass_name
, "Interlocked")) {
1475 if (!strcmp (tm
, "MemoryBarrier") && csignature
->param_count
== 0)
1476 *op
= MINT_MONO_MEMORY_BARRIER
;
1484 interp_transform_internal_calls (MonoMethod
*method
, MonoMethod
*target_method
, MonoMethodSignature
*csignature
, gboolean is_virtual
)
1486 if (method
->wrapper_type
== MONO_WRAPPER_NONE
&& target_method
!= NULL
) {
1487 if (target_method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
1488 target_method
= mono_marshal_get_native_wrapper (target_method
, FALSE
, FALSE
);
1489 if (!is_virtual
&& target_method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)
1490 target_method
= mono_marshal_get_synchronized_wrapper (target_method
);
1492 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)
1493 target_method
= mono_marshal_get_native_wrapper (target_method
, FALSE
, FALSE
);
1495 return target_method
;
1499 interp_type_as_ptr (MonoType
*tp
)
1501 if (MONO_TYPE_IS_POINTER (tp
))
1503 if (MONO_TYPE_IS_REFERENCE (tp
))
1505 if ((tp
)->type
== MONO_TYPE_I4
)
1507 #if SIZEOF_VOID_P == 8
1508 if ((tp
)->type
== MONO_TYPE_I8
)
1511 if ((tp
)->type
== MONO_TYPE_BOOLEAN
)
1513 if ((tp
)->type
== MONO_TYPE_CHAR
)
1515 if ((tp
)->type
== MONO_TYPE_VALUETYPE
&& m_class_is_enumtype (tp
->data
.klass
))
1520 #define INTERP_TYPE_AS_PTR(tp) interp_type_as_ptr (tp)
1523 interp_icall_op_for_sig (MonoMethodSignature
*sig
)
1526 switch (sig
->param_count
) {
1528 if (MONO_TYPE_IS_VOID (sig
->ret
))
1529 op
= MINT_ICALL_V_V
;
1530 else if (INTERP_TYPE_AS_PTR (sig
->ret
))
1531 op
= MINT_ICALL_V_P
;
1534 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1535 if (INTERP_TYPE_AS_PTR (sig
->params
[0]))
1536 op
= MINT_ICALL_P_V
;
1537 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1538 if (INTERP_TYPE_AS_PTR (sig
->params
[0]))
1539 op
= MINT_ICALL_P_P
;
1543 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1544 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1545 INTERP_TYPE_AS_PTR (sig
->params
[1]))
1546 op
= MINT_ICALL_PP_V
;
1547 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1548 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1549 INTERP_TYPE_AS_PTR (sig
->params
[1]))
1550 op
= MINT_ICALL_PP_P
;
1554 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1555 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1556 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1557 INTERP_TYPE_AS_PTR (sig
->params
[2]))
1558 op
= MINT_ICALL_PPP_V
;
1559 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1560 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1561 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1562 INTERP_TYPE_AS_PTR (sig
->params
[2]))
1563 op
= MINT_ICALL_PPP_P
;
1567 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1568 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1569 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1570 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1571 INTERP_TYPE_AS_PTR (sig
->params
[3]))
1572 op
= MINT_ICALL_PPPP_V
;
1573 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1574 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1575 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1576 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1577 INTERP_TYPE_AS_PTR (sig
->params
[3]))
1578 op
= MINT_ICALL_PPPP_P
;
1582 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1583 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1584 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1585 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1586 INTERP_TYPE_AS_PTR (sig
->params
[3]) &&
1587 INTERP_TYPE_AS_PTR (sig
->params
[4]))
1588 op
= MINT_ICALL_PPPPP_V
;
1589 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1590 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1591 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1592 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1593 INTERP_TYPE_AS_PTR (sig
->params
[3]) &&
1594 INTERP_TYPE_AS_PTR (sig
->params
[4]))
1595 op
= MINT_ICALL_PPPPP_P
;
1599 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1600 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1601 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1602 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1603 INTERP_TYPE_AS_PTR (sig
->params
[3]) &&
1604 INTERP_TYPE_AS_PTR (sig
->params
[4]) &&
1605 INTERP_TYPE_AS_PTR (sig
->params
[5]))
1606 op
= MINT_ICALL_PPPPPP_V
;
1607 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1608 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1609 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1610 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1611 INTERP_TYPE_AS_PTR (sig
->params
[3]) &&
1612 INTERP_TYPE_AS_PTR (sig
->params
[4]) &&
1613 INTERP_TYPE_AS_PTR (sig
->params
[5]))
1614 op
= MINT_ICALL_PPPPPP_P
;
1621 #define INLINE_LENGTH_LIMIT 20
1624 interp_method_check_inlining (TransformData
*td
, MonoMethod
*method
)
1626 MonoMethodHeaderSummary header
;
1628 if (td
->method
== method
)
1631 if (!mono_method_get_header_summary (method
, &header
))
1634 /*runtime, icall and pinvoke are checked by summary call*/
1635 if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_NOINLINING
) ||
1636 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) ||
1637 (mono_class_is_marshalbyref (method
->klass
)) ||
1641 if (header
.code_size
>= INLINE_LENGTH_LIMIT
)
1644 if (mono_class_needs_cctor_run (method
->klass
, NULL
)) {
1647 if (!m_class_get_runtime_info (method
->klass
))
1648 /* No vtable created yet */
1650 vtable
= mono_class_vtable_checked (td
->rtm
->domain
, method
->klass
, error
);
1651 if (!is_ok (error
)) {
1652 mono_error_cleanup (error
);
1655 if (!vtable
->initialized
)
1659 /* We currently access at runtime the wrapper data */
1660 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
1663 /* Our usage of `emit_store_value_as_local ()` for nint, nuint and nfloat
1664 * is kinda hacky, and doesn't work with the inliner */
1665 if (mono_class_get_magic_index (method
->klass
) >= 0)
1672 interp_inline_method (TransformData
*td
, MonoMethod
*target_method
, MonoMethodHeader
*header
, MonoError
*error
)
1674 const unsigned char *prev_ip
, *prev_il_code
, *prev_in_start
;
1675 StackInfo
**prev_stack_state
;
1676 int *prev_stack_height
, *prev_vt_stack_size
, *prev_clause_indexes
, *prev_in_offsets
;
1677 guint8
*prev_is_bb_start
;
1679 unsigned int prev_max_stack_height
, prev_max_vt_sp
, prev_total_locals_size
;
1680 int prev_n_data_items
;
1683 MonoGenericContext
*generic_context
= NULL
;
1684 StackInfo
*prev_param_area
;
1685 MonoMethod
*prev_inlined_method
;
1686 MonoMethodSignature
*csignature
= mono_method_signature_internal (target_method
);
1687 int nargs
= csignature
->param_count
+ !!csignature
->hasthis
;
1688 InterpInst
*prev_last_ins
;
1690 if (csignature
->is_inflated
)
1691 generic_context
= mono_method_get_context (target_method
);
1693 MonoGenericContainer
*generic_container
= mono_method_get_generic_container (target_method
);
1694 if (generic_container
)
1695 generic_context
= &generic_container
->context
;
1699 prev_il_code
= td
->il_code
;
1700 prev_in_start
= td
->in_start
;
1701 prev_sp_offset
= td
->sp
- td
->stack
;
1702 prev_vt_sp
= td
->vt_sp
;
1703 prev_stack_state
= td
->stack_state
;
1704 prev_stack_height
= td
->stack_height
;
1705 prev_vt_stack_size
= td
->vt_stack_size
;
1706 prev_clause_indexes
= td
->clause_indexes
;
1707 prev_inlined_method
= td
->inlined_method
;
1708 prev_last_ins
= td
->last_ins
;
1709 td
->inlined_method
= target_method
;
1711 prev_max_stack_height
= td
->max_stack_height
;
1712 prev_max_vt_sp
= td
->max_vt_sp
;
1713 prev_total_locals_size
= td
->total_locals_size
;
1715 prev_n_data_items
= td
->n_data_items
;
1716 prev_in_offsets
= td
->in_offsets
;
1717 td
->in_offsets
= (int*)g_malloc0((header
->code_size
+ 1) * sizeof(int));
1719 prev_is_bb_start
= td
->is_bb_start
;
1721 /* Inlining pops the arguments, restore the stack */
1722 prev_param_area
= (StackInfo
*)g_malloc (nargs
* sizeof (StackInfo
));
1723 memcpy (prev_param_area
, &td
->sp
[-nargs
], nargs
* sizeof (StackInfo
));
1725 if (td
->verbose_level
)
1726 g_print ("Inline start method %s.%s\n", m_class_get_name (target_method
->klass
), target_method
->name
);
1727 ret
= generate_code (td
, target_method
, header
, generic_context
, error
);
1730 if (td
->verbose_level
)
1731 g_print ("Inline aborted method %s.%s\n", m_class_get_name (target_method
->klass
), target_method
->name
);
1732 td
->max_stack_height
= prev_max_stack_height
;
1733 td
->max_vt_sp
= prev_max_vt_sp
;
1734 td
->total_locals_size
= prev_total_locals_size
;
1737 /* Remove any newly added items */
1738 for (i
= prev_n_data_items
; i
< td
->n_data_items
; i
++) {
1739 g_hash_table_remove (td
->data_hash
, td
->data_items
[i
]);
1741 td
->n_data_items
= prev_n_data_items
;
1742 td
->sp
= td
->stack
+ prev_sp_offset
;
1743 memcpy (&td
->sp
[-nargs
], prev_param_area
, nargs
* sizeof (StackInfo
));
1744 td
->vt_sp
= prev_vt_sp
;
1745 td
->last_ins
= prev_last_ins
;
1747 td
->last_ins
->next
= NULL
;
1748 UnlockedIncrement (&mono_interp_stats
.inline_failures
);
1750 if (td
->verbose_level
)
1751 g_print ("Inline end method %s.%s\n", m_class_get_name (target_method
->klass
), target_method
->name
);
1752 UnlockedIncrement (&mono_interp_stats
.inlined_methods
);
1753 // Make sure we have an IR instruction associated with the now removed IL CALL
1754 // FIXME This could be prettier. We might be able to make inlining saner now that
1755 // that we can easily tweak the instruction list.
1756 if (!prev_inlined_method
) {
1757 if (prev_last_ins
) {
1758 if (prev_last_ins
->next
)
1759 prev_last_ins
->next
->il_offset
= prev_in_start
- prev_il_code
;
1760 } else if (td
->first_ins
) {
1761 td
->first_ins
->il_offset
= prev_in_start
- prev_il_code
;
1767 td
->in_start
= prev_in_start
;
1768 td
->il_code
= prev_il_code
;
1769 td
->stack_state
= prev_stack_state
;
1770 td
->stack_height
= prev_stack_height
;
1771 td
->vt_stack_size
= prev_vt_stack_size
;
1772 td
->clause_indexes
= prev_clause_indexes
;
1773 td
->is_bb_start
= prev_is_bb_start
;
1774 td
->inlined_method
= prev_inlined_method
;
1776 g_free (td
->in_offsets
);
1777 td
->in_offsets
= prev_in_offsets
;
1779 g_free (prev_param_area
);
1784 interp_constrained_box (TransformData
*td
, MonoDomain
*domain
, MonoClass
*constrained_class
, MonoMethodSignature
*csignature
, MonoError
*error
)
1786 int mt
= mint_type (m_class_get_byval_arg (constrained_class
));
1787 if (mono_class_is_nullable (constrained_class
)) {
1788 g_assert (mt
== MINT_TYPE_VT
);
1789 interp_add_ins (td
, MINT_BOX_NULLABLE
);
1790 td
->last_ins
->data
[0] = get_data_item_index (td
, constrained_class
);
1791 td
->last_ins
->data
[1] = csignature
->param_count
| ((td
->sp
- 1 - csignature
->param_count
)->type
!= STACK_TYPE_MP
? 0 : BOX_NOT_CLEAR_VT_SP
);
1793 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, constrained_class
, error
);
1794 return_if_nok (error
);
1796 if (mt
== MINT_TYPE_VT
) {
1797 interp_add_ins (td
, MINT_BOX_VT
);
1798 td
->last_ins
->data
[0] = get_data_item_index (td
, vtable
);
1799 td
->last_ins
->data
[1] = csignature
->param_count
| ((td
->sp
- 1 - csignature
->param_count
)->type
!= STACK_TYPE_MP
? 0 : BOX_NOT_CLEAR_VT_SP
);
1801 interp_add_ins (td
, MINT_BOX
);
1802 td
->last_ins
->data
[0] = get_data_item_index (td
, vtable
);
1803 td
->last_ins
->data
[1] = csignature
->param_count
;
1808 /* Return FALSE if error, including inline failure */
1810 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
)
1812 MonoImage
*image
= m_class_get_image (method
->klass
);
1813 MonoMethodSignature
*csignature
;
1814 int is_virtual
= *td
->ip
== CEE_CALLVIRT
;
1815 int calli
= *td
->ip
== CEE_CALLI
|| *td
->ip
== CEE_MONO_CALLI_EXTRA_ARG
;
1817 guint32 vt_stack_used
= 0;
1818 guint32 vt_res_size
= 0;
1822 int need_null_check
= is_virtual
;
1824 guint32 token
= read32 (td
->ip
+ 1);
1826 if (target_method
== NULL
) {
1829 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
1830 csignature
= (MonoMethodSignature
*)mono_method_get_wrapper_data (method
, token
);
1832 csignature
= mono_metadata_parse_signature_checked (image
, token
, error
);
1833 return_val_if_nok (error
, FALSE
);
1836 if (generic_context
) {
1837 csignature
= mono_inflate_generic_signature (csignature
, generic_context
, error
);
1838 return_val_if_nok (error
, FALSE
);
1842 * The compiled interp entry wrapper is passed to runtime_invoke instead of
1843 * the InterpMethod pointer. FIXME
1845 native
= csignature
->pinvoke
|| method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
;
1848 target_method
= NULL
;
1850 if (method
->wrapper_type
== MONO_WRAPPER_NONE
) {
1851 target_method
= mono_get_method_checked (image
, token
, NULL
, generic_context
, error
);
1852 return_val_if_nok (error
, FALSE
);
1854 target_method
= (MonoMethod
*)mono_method_get_wrapper_data (method
, token
);
1855 csignature
= mono_method_signature_internal (target_method
);
1857 if (generic_context
) {
1858 csignature
= mono_inflate_generic_signature (csignature
, generic_context
, error
);
1859 return_val_if_nok (error
, FALSE
);
1860 target_method
= mono_class_inflate_generic_method_checked (target_method
, generic_context
, error
);
1861 return_val_if_nok (error
, FALSE
);
1865 csignature
= mono_method_signature_internal (target_method
);
1868 if (check_visibility
&& target_method
&& !mono_method_can_access_method (method
, target_method
))
1869 interp_generate_mae_throw (td
, method
, target_method
);
1871 if (target_method
&& target_method
->string_ctor
) {
1872 /* Create the real signature */
1873 MonoMethodSignature
*ctor_sig
= mono_metadata_signature_dup_mempool (td
->mempool
, csignature
);
1874 ctor_sig
->ret
= m_class_get_byval_arg (mono_defaults
.string_class
);
1876 csignature
= ctor_sig
;
1880 if (target_method
&& interp_handle_intrinsics (td
, target_method
, constrained_class
, csignature
, readonly
, &op
))
1883 if (constrained_class
) {
1884 if (m_class_is_enumtype (constrained_class
) && !strcmp (target_method
->name
, "GetHashCode")) {
1885 /* Use the corresponding method from the base type to avoid boxing */
1886 MonoType
*base_type
= mono_class_enum_basetype_internal (constrained_class
);
1887 g_assert (base_type
);
1888 constrained_class
= mono_class_from_mono_type_internal (base_type
);
1889 target_method
= mono_class_get_method_from_name_checked (constrained_class
, target_method
->name
, 0, 0, error
);
1890 mono_error_assert_ok (error
);
1891 g_assert (target_method
);
1895 if (constrained_class
) {
1896 mono_class_setup_vtable (constrained_class
);
1897 if (mono_class_has_failure (constrained_class
)) {
1898 mono_error_set_for_class_failure (error
, constrained_class
);
1902 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
);
1904 target_method
= mono_get_method_constrained_with_method (image
, target_method
, constrained_class
, generic_context
, error
);
1906 g_print (" : %s::%s. %s (%p)\n", target_method
->klass
->name
, target_method
->name
, mono_signature_full_name (target_method
->signature
), target_method
);
1908 /* Intrinsics: Try again, it could be that `mono_get_method_constrained_with_method` resolves to a method that we can substitute */
1909 if (target_method
&& interp_handle_intrinsics (td
, target_method
, constrained_class
, csignature
, readonly
, &op
))
1912 return_val_if_nok (error
, FALSE
);
1913 mono_class_setup_vtable (target_method
->klass
);
1915 if (!m_class_is_valuetype (constrained_class
)) {
1916 /* managed pointer on the stack, we need to deref that puppy */
1917 interp_add_ins (td
, MINT_LDIND_I
);
1918 td
->last_ins
->data
[0] = csignature
->param_count
;
1919 } 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
) {
1920 if (target_method
->klass
== mono_defaults
.enum_class
&& (td
->sp
- csignature
->param_count
- 1)->type
== STACK_TYPE_MP
) {
1921 /* managed pointer on the stack, we need to deref that puppy */
1922 /* Always load the entire stackval, to handle also the case where the enum has long storage */
1923 interp_add_ins (td
, MINT_LDIND_I8
);
1924 td
->last_ins
->data
[0] = csignature
->param_count
;
1927 interp_constrained_box (td
, domain
, constrained_class
, csignature
, error
);
1928 return_val_if_nok (error
, FALSE
);
1930 if (target_method
->klass
!= constrained_class
) {
1932 * The type parameter is instantiated as a valuetype,
1933 * but that type doesn't override the method we're
1934 * calling, so we need to box `this'.
1936 if (target_method
->klass
== mono_defaults
.enum_class
&& (td
->sp
- csignature
->param_count
- 1)->type
== STACK_TYPE_MP
) {
1937 /* managed pointer on the stack, we need to deref that puppy */
1938 /* Always load the entire stackval, to handle also the case where the enum has long storage */
1939 interp_add_ins (td
, MINT_LDIND_I8
);
1940 td
->last_ins
->data
[0] = csignature
->param_count
;
1943 interp_constrained_box (td
, domain
, constrained_class
, csignature
, error
);
1944 return_val_if_nok (error
, FALSE
);
1951 mono_class_init_internal (target_method
->klass
);
1953 if (!is_virtual
&& target_method
&& (target_method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
))
1954 /* MS.NET seems to silently convert this to a callvirt */
1957 if (is_virtual
&& target_method
&& (!(target_method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) ||
1958 (MONO_METHOD_IS_FINAL (target_method
) &&
1959 target_method
->wrapper_type
!= MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
)) &&
1960 !(mono_class_is_marshalbyref (target_method
->klass
))) {
1961 /* Not really virtual, just needs a null check */
1963 need_null_check
= TRUE
;
1966 CHECK_STACK (td
, csignature
->param_count
+ csignature
->hasthis
);
1967 if (!td
->gen_sdb_seq_points
&& !calli
&& op
== -1 && (!is_virtual
|| (target_method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) == 0) &&
1968 (target_method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) == 0 &&
1969 (target_method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) == 0 &&
1970 !(target_method
->iflags
& METHOD_IMPL_ATTRIBUTE_NOINLINING
)) {
1971 (void)mono_class_vtable_checked (domain
, target_method
->klass
, error
);
1972 return_val_if_nok (error
, FALSE
);
1974 if (method
== target_method
&& *(td
->ip
+ 5) == CEE_RET
&& !(csignature
->hasthis
&& m_class_is_valuetype (target_method
->klass
))) {
1975 if (td
->inlined_method
)
1978 if (td
->verbose_level
)
1979 g_print ("Optimize tail call of %s.%s\n", m_class_get_name (target_method
->klass
), target_method
->name
);
1981 for (i
= csignature
->param_count
- 1 + !!csignature
->hasthis
; i
>= 0; --i
)
1984 interp_add_ins (td
, MINT_BR_S
);
1985 // We are branching to the beginning of the method
1986 td
->last_ins
->data
[0] = 0;
1987 if (!is_bb_start
[td
->ip
+ 5 - td
->il_code
])
1988 ++td
->ip
; /* gobble the CEE_RET if it isn't branched to */
1994 target_method
= interp_transform_internal_calls (method
, target_method
, csignature
, is_virtual
);
1996 if (csignature
->call_convention
== MONO_CALL_VARARG
) {
1997 csignature
= mono_method_get_signature_checked (target_method
, image
, token
, generic_context
, error
);
1998 int vararg_stack
= 0;
2000 * For vararg calls, ArgIterator expects the signature and the varargs to be
2001 * stored in a linear memory. We allocate the necessary vt_stack space for
2002 * this. All varargs will be pushed to the vt_stack at call site.
2004 vararg_stack
+= sizeof (gpointer
);
2005 for (i
= csignature
->sentinelpos
; i
< csignature
->param_count
; ++i
) {
2006 int align
, arg_size
;
2007 arg_size
= mono_type_stack_size (csignature
->params
[i
], &align
);
2008 vararg_stack
+= arg_size
;
2010 vt_stack_used
+= ALIGN_TO (vararg_stack
, MINT_VT_ALIGNMENT
);
2011 PUSH_VT (td
, vararg_stack
);
2014 if (need_null_check
) {
2015 interp_add_ins (td
, MINT_CKNULL_N
);
2016 td
->last_ins
->data
[0] = csignature
->param_count
+ 1;
2019 g_assert (csignature
->call_convention
!= MONO_CALL_FASTCALL
);
2020 if ((mono_interp_opt
& INTERP_OPT_INLINE
) && op
== -1 && !is_virtual
&& target_method
&& interp_method_check_inlining (td
, target_method
)) {
2021 MonoMethodHeader
*mheader
= interp_method_get_header (target_method
, error
);
2022 return_val_if_nok (error
, FALSE
);
2024 if (interp_inline_method (td
, target_method
, mheader
, error
)) {
2030 /* Don't inline methods that do calls */
2031 if (op
== -1 && td
->inlined_method
)
2034 td
->sp
-= csignature
->param_count
+ !!csignature
->hasthis
;
2035 for (i
= 0; i
< csignature
->param_count
; ++i
) {
2036 if (td
->sp
[i
+ !!csignature
->hasthis
].type
== STACK_TYPE_VT
) {
2038 MonoClass
*klass
= mono_class_from_mono_type_internal (csignature
->params
[i
]);
2039 if (csignature
->pinvoke
&& method
->wrapper_type
!= MONO_WRAPPER_NONE
)
2040 size
= mono_class_native_size (klass
, NULL
);
2042 size
= mono_class_value_size (klass
, NULL
);
2043 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
2044 vt_stack_used
+= size
;
2048 /* need to handle typedbyref ... */
2049 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
2050 int mt
= mint_type(csignature
->ret
);
2051 MonoClass
*klass
= mono_class_from_mono_type_internal (csignature
->ret
);
2052 if (mt
== MINT_TYPE_VT
) {
2053 if (csignature
->pinvoke
&& method
->wrapper_type
!= MONO_WRAPPER_NONE
)
2054 vt_res_size
= mono_class_native_size (klass
, NULL
);
2056 vt_res_size
= mono_class_value_size (klass
, NULL
);
2057 if (mono_class_has_failure (klass
)) {
2058 mono_error_set_for_class_failure (error
, klass
);
2061 PUSH_VT(td
, vt_res_size
);
2063 PUSH_TYPE(td
, stack_type
[mt
], klass
);
2067 /* We need to convert delegate invoke to a indirect call on the interp_invoke_impl field */
2068 if (target_method
&& m_class_get_parent (target_method
->klass
) == mono_defaults
.multicastdelegate_class
) {
2069 const char *name
= target_method
->name
;
2070 if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
2072 interp_add_ins (td
, MINT_LD_DELEGATE_INVOKE_IMPL
);
2073 td
->last_ins
->data
[0] = csignature
->param_count
+ 1;
2078 interp_add_ins (td
, op
);
2080 if (op
== MINT_LDLEN
) {
2081 #ifdef MONO_BIG_ARRAYS
2082 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I8
);
2084 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I4
);
2087 if (op
== MINT_LDELEMA
|| op
== MINT_LDELEMA_TC
) {
2088 td
->last_ins
->data
[0] = get_data_item_index (td
, m_class_get_element_class (target_method
->klass
));
2089 td
->last_ins
->data
[1] = 1 + m_class_get_rank (target_method
->klass
);
2092 if (op
== MINT_CALLRUN
) {
2093 td
->last_ins
->data
[0] = get_data_item_index (td
, target_method
);
2094 td
->last_ins
->data
[1] = get_data_item_index (td
, mono_method_signature_internal (target_method
));
2096 } else if (!calli
&& !is_virtual
&& jit_call_supported (target_method
, csignature
)) {
2097 interp_add_ins (td
, MINT_JIT_CALL
);
2098 td
->last_ins
->data
[0] = get_data_item_index (td
, (void *)mono_interp_get_imethod (domain
, target_method
, error
));
2099 mono_error_assert_ok (error
);
2101 #ifndef MONO_ARCH_HAS_NO_PROPER_MONOCTX
2102 /* Try using fast icall path for simple signatures */
2103 if (native
&& !method
->dynamic
)
2104 op
= interp_icall_op_for_sig (csignature
);
2106 if (csignature
->call_convention
== MONO_CALL_VARARG
)
2107 interp_add_ins (td
, MINT_CALL_VARARG
);
2109 interp_add_ins (td
, native
? ((op
!= -1) ? MINT_CALLI_NAT_FAST
: MINT_CALLI_NAT
) : MINT_CALLI
);
2110 else if (is_virtual
&& !mono_class_is_marshalbyref (target_method
->klass
))
2111 interp_add_ins (td
, is_void
? MINT_VCALLVIRT_FAST
: MINT_CALLVIRT_FAST
);
2112 else if (is_virtual
)
2113 interp_add_ins (td
, is_void
? MINT_VCALLVIRT
: MINT_CALLVIRT
);
2115 interp_add_ins (td
, is_void
? MINT_VCALL
: MINT_CALL
);
2118 td
->last_ins
->data
[0] = get_data_item_index (td
, (void *)csignature
);
2120 td
->last_ins
->data
[1] = op
;
2122 td
->last_ins
->data
[0] = get_data_item_index (td
, (void *)mono_interp_get_imethod (domain
, target_method
, error
));
2123 return_val_if_nok (error
, FALSE
);
2124 if (csignature
->call_convention
== MONO_CALL_VARARG
)
2125 td
->last_ins
->data
[1] = get_data_item_index (td
, (void *)csignature
);
2126 else if (is_virtual
&& !mono_class_is_marshalbyref (target_method
->klass
)) {
2127 /* FIXME Use fastpath also for MBRO. Asserts in mono_method_get_vtable_slot */
2128 if (mono_class_is_interface (target_method
->klass
))
2129 td
->last_ins
->data
[1] = -2 * MONO_IMT_SIZE
+ mono_method_get_imt_slot (target_method
);
2131 td
->last_ins
->data
[1] = mono_method_get_vtable_slot (target_method
);
2136 if (vt_stack_used
!= 0 || vt_res_size
!= 0) {
2137 interp_add_ins (td
, MINT_VTRESULT
);
2138 td
->last_ins
->data
[0] = vt_res_size
;
2139 WRITE32_INS (td
->last_ins
, 1, &vt_stack_used
);
2140 td
->vt_sp
-= vt_stack_used
;
2146 static MonoClassField
*
2147 interp_field_from_token (MonoMethod
*method
, guint32 token
, MonoClass
**klass
, MonoGenericContext
*generic_context
, MonoError
*error
)
2149 MonoClassField
*field
= NULL
;
2150 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
2151 field
= (MonoClassField
*) mono_method_get_wrapper_data (method
, token
);
2152 *klass
= field
->parent
;
2154 mono_class_setup_fields (field
->parent
);
2156 field
= mono_field_from_token_checked (m_class_get_image (method
->klass
), token
, klass
, generic_context
, error
);
2157 return_val_if_nok (error
, NULL
);
2160 if (!method
->skip_visibility
&& !mono_method_can_access_field (method
, field
)) {
2161 char *method_fname
= mono_method_full_name (method
, TRUE
);
2162 char *field_fname
= mono_field_full_name (field
);
2163 mono_error_set_generic_error (error
, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname
, method_fname
);
2164 g_free (method_fname
);
2165 g_free (field_fname
);
2172 static InterpBasicBlock
*
2173 get_bb (TransformData
*td
, InterpBasicBlock
*cbb
, unsigned char *ip
)
2175 int offset
= ip
- td
->il_code
;
2176 InterpBasicBlock
*bb
= td
->offset_to_bb
[offset
];
2179 bb
= (InterpBasicBlock
*)mono_mempool_alloc0 (td
->mempool
, sizeof (InterpBasicBlock
));
2181 td
->offset_to_bb
[offset
] = bb
;
2183 td
->basic_blocks
= g_list_append_mempool (td
->mempool
, td
->basic_blocks
, bb
);
2187 bb
->preds
= g_slist_prepend_mempool (td
->mempool
, bb
->preds
, cbb
);
2194 * Compute the set of IL level basic blocks.
2197 get_basic_blocks (TransformData
*td
)
2199 guint8
*start
= (guint8
*)td
->il_code
;
2200 guint8
*end
= (guint8
*)td
->il_code
+ td
->code_size
;
2202 unsigned char *target
;
2205 const MonoOpcode
*opcode
;
2206 InterpBasicBlock
*cbb
;
2208 td
->offset_to_bb
= (InterpBasicBlock
**)mono_mempool_alloc0 (td
->mempool
, sizeof (InterpBasicBlock
*) * (end
- start
+ 1));
2209 td
->entry_bb
= cbb
= get_bb (td
, NULL
, start
);
2212 cli_addr
= ip
- start
;
2213 td
->offset_to_bb
[cli_addr
] = cbb
;
2214 i
= mono_opcode_value ((const guint8
**)&ip
, end
);
2215 opcode
= &mono_opcodes
[i
];
2216 switch (opcode
->argument
) {
2217 case MonoInlineNone
:
2220 case MonoInlineString
:
2221 case MonoInlineType
:
2222 case MonoInlineField
:
2223 case MonoInlineMethod
:
2226 case MonoShortInlineR
:
2233 case MonoShortInlineVar
:
2234 case MonoShortInlineI
:
2237 case MonoShortInlineBrTarget
:
2238 target
= start
+ cli_addr
+ 2 + (signed char)ip
[1];
2239 get_bb (td
, cbb
, target
);
2241 cbb
= get_bb (td
, cbb
, ip
);
2243 case MonoInlineBrTarget
:
2244 target
= start
+ cli_addr
+ 5 + (gint32
)read32 (ip
+ 1);
2245 get_bb (td
, cbb
, target
);
2247 cbb
= get_bb (td
, cbb
, ip
);
2249 case MonoInlineSwitch
: {
2250 guint32 n
= read32 (ip
+ 1);
2253 cli_addr
+= 5 + 4 * n
;
2254 target
= start
+ cli_addr
;
2255 get_bb (td
, cbb
, target
);
2257 for (j
= 0; j
< n
; ++j
) {
2258 target
= start
+ cli_addr
+ (gint32
)read32 (ip
);
2259 get_bb (td
, cbb
, target
);
2262 cbb
= get_bb (td
, cbb
, ip
);
2270 g_assert_not_reached ();
2274 cbb
= get_bb (td
, NULL
, ip
);
2279 interp_save_debug_info (InterpMethod
*rtm
, MonoMethodHeader
*header
, TransformData
*td
, GArray
*line_numbers
)
2281 MonoDebugMethodJitInfo
*dinfo
;
2284 if (!mono_debug_enabled ())
2288 * We save the debug info in the same way the JIT does it, treating the interpreter IR as the native code.
2291 dinfo
= g_new0 (MonoDebugMethodJitInfo
, 1);
2292 dinfo
->num_params
= rtm
->param_count
;
2293 dinfo
->params
= g_new0 (MonoDebugVarInfo
, dinfo
->num_params
);
2294 dinfo
->num_locals
= header
->num_locals
;
2295 dinfo
->locals
= g_new0 (MonoDebugVarInfo
, header
->num_locals
);
2296 dinfo
->code_start
= (guint8
*)rtm
->code
;
2297 dinfo
->code_size
= td
->new_code_end
- td
->new_code
;
2298 dinfo
->epilogue_begin
= 0;
2299 dinfo
->has_var_info
= TRUE
;
2300 dinfo
->num_line_numbers
= line_numbers
->len
;
2301 dinfo
->line_numbers
= g_new0 (MonoDebugLineNumberEntry
, dinfo
->num_line_numbers
);
2303 for (i
= 0; i
< dinfo
->num_params
; i
++) {
2304 MonoDebugVarInfo
*var
= &dinfo
->params
[i
];
2305 var
->type
= rtm
->param_types
[i
];
2307 for (i
= 0; i
< dinfo
->num_locals
; i
++) {
2308 MonoDebugVarInfo
*var
= &dinfo
->locals
[i
];
2309 var
->type
= mono_metadata_type_dup (NULL
, header
->locals
[i
]);
2312 for (i
= 0; i
< dinfo
->num_line_numbers
; i
++)
2313 dinfo
->line_numbers
[i
] = g_array_index (line_numbers
, MonoDebugLineNumberEntry
, i
);
2314 mono_debug_add_method (rtm
->method
, dinfo
, rtm
->domain
);
2316 mono_debug_free_method_jit_info (dinfo
);
2319 /* Same as the code in seq-points.c */
2321 insert_pred_seq_point (SeqPoint
*last_sp
, SeqPoint
*sp
, GSList
**next
)
2324 int src_index
= last_sp
->next_offset
;
2325 int dst_index
= sp
->next_offset
;
2327 /* bb->in_bb might contain duplicates */
2328 for (l
= next
[src_index
]; l
; l
= l
->next
)
2329 if (GPOINTER_TO_UINT (l
->data
) == dst_index
)
2332 next
[src_index
] = g_slist_append (next
[src_index
], GUINT_TO_POINTER (dst_index
));
2336 recursively_make_pred_seq_points (TransformData
*td
, InterpBasicBlock
*bb
)
2338 SeqPoint
** const MONO_SEQ_SEEN_LOOP
= (SeqPoint
**)GINT_TO_POINTER(-1);
2341 GArray
*predecessors
= g_array_new (FALSE
, TRUE
, sizeof (gpointer
));
2342 GHashTable
*seen
= g_hash_table_new_full (g_direct_hash
, NULL
, NULL
, NULL
);
2344 // Insert/remove sentinel into the memoize table to detect loops containing bb
2345 bb
->pred_seq_points
= MONO_SEQ_SEEN_LOOP
;
2347 for (l
= bb
->preds
; l
; l
= l
->next
) {
2348 InterpBasicBlock
*in_bb
= (InterpBasicBlock
*)l
->data
;
2350 // This bb has the last seq point, append it and continue
2351 if (in_bb
->last_seq_point
!= NULL
) {
2352 predecessors
= g_array_append_val (predecessors
, in_bb
->last_seq_point
);
2356 // We've looped or handled this before, exit early.
2357 // No last sequence points to find.
2358 if (in_bb
->pred_seq_points
== MONO_SEQ_SEEN_LOOP
)
2361 // Take sequence points from incoming basic blocks
2363 if (in_bb
== td
->entry_bb
)
2366 if (in_bb
->pred_seq_points
== NULL
)
2367 recursively_make_pred_seq_points (td
, in_bb
);
2369 // Union sequence points with incoming bb's
2370 for (int i
=0; i
< in_bb
->num_pred_seq_points
; i
++) {
2371 if (!g_hash_table_lookup (seen
, in_bb
->pred_seq_points
[i
])) {
2372 g_array_append_val (predecessors
, in_bb
->pred_seq_points
[i
]);
2373 g_hash_table_insert (seen
, in_bb
->pred_seq_points
[i
], (gpointer
)&MONO_SEQ_SEEN_LOOP
);
2376 // predecessors = g_array_append_vals (predecessors, in_bb->pred_seq_points, in_bb->num_pred_seq_points);
2379 g_hash_table_destroy (seen
);
2381 if (predecessors
->len
!= 0) {
2382 bb
->pred_seq_points
= (SeqPoint
**)mono_mempool_alloc0 (td
->mempool
, sizeof (SeqPoint
*) * predecessors
->len
);
2383 bb
->num_pred_seq_points
= predecessors
->len
;
2385 for (int newer
= 0; newer
< bb
->num_pred_seq_points
; newer
++) {
2386 bb
->pred_seq_points
[newer
] = (SeqPoint
*)g_array_index (predecessors
, gpointer
, newer
);
2390 g_array_free (predecessors
, TRUE
);
2394 collect_pred_seq_points (TransformData
*td
, InterpBasicBlock
*bb
, SeqPoint
*seqp
, GSList
**next
)
2396 // Doesn't have a last sequence point, must find from incoming basic blocks
2397 if (bb
->pred_seq_points
== NULL
&& bb
!= td
->entry_bb
)
2398 recursively_make_pred_seq_points (td
, bb
);
2400 for (int i
= 0; i
< bb
->num_pred_seq_points
; i
++)
2401 insert_pred_seq_point (bb
->pred_seq_points
[i
], seqp
, next
);
2407 save_seq_points (TransformData
*td
, MonoJitInfo
*jinfo
)
2410 int i
, seq_info_size
;
2411 MonoSeqPointInfo
*info
;
2412 GSList
**next
= NULL
;
2415 if (!td
->gen_sdb_seq_points
)
2419 * For each sequence point, compute the list of sequence points immediately
2420 * following it, this is needed to implement 'step over' in the debugger agent.
2421 * Similar to the code in mono_save_seq_point_info ().
2423 for (i
= 0; i
< td
->seq_points
->len
; ++i
) {
2424 SeqPoint
*sp
= (SeqPoint
*)g_ptr_array_index (td
->seq_points
, i
);
2426 /* Store the seq point index here temporarily */
2427 sp
->next_offset
= i
;
2429 next
= (GSList
**)mono_mempool_alloc0 (td
->mempool
, sizeof (GList
*) * td
->seq_points
->len
);
2430 for (bblist
= td
->basic_blocks
; bblist
; bblist
= bblist
->next
) {
2431 InterpBasicBlock
*bb
= (InterpBasicBlock
*)bblist
->data
;
2433 GSList
*bb_seq_points
= g_slist_reverse (bb
->seq_points
);
2434 SeqPoint
*last
= NULL
;
2435 for (GSList
*l
= bb_seq_points
; l
; l
= l
->next
) {
2436 SeqPoint
*sp
= (SeqPoint
*)l
->data
;
2438 if (sp
->il_offset
== METHOD_ENTRY_IL_OFFSET
|| sp
->il_offset
== METHOD_EXIT_IL_OFFSET
)
2439 /* Used to implement method entry/exit events */
2443 /* Link with the previous seq point in the same bb */
2444 next
[last
->next_offset
] = g_slist_append_mempool (td
->mempool
, next
[last
->next_offset
], GINT_TO_POINTER (sp
->next_offset
));
2446 /* Link with the last bb in the previous bblocks */
2447 collect_pred_seq_points (td
, bb
, sp
, next
);
2453 /* Serialize the seq points into a byte array */
2454 array
= g_byte_array_new ();
2455 SeqPoint zero_seq_point
= {0};
2456 SeqPoint
* last_seq_point
= &zero_seq_point
;
2457 for (i
= 0; i
< td
->seq_points
->len
; ++i
) {
2458 SeqPoint
*sp
= (SeqPoint
*)g_ptr_array_index (td
->seq_points
, i
);
2460 sp
->next_offset
= 0;
2461 if (mono_seq_point_info_add_seq_point (array
, sp
, last_seq_point
, next
[i
], TRUE
))
2462 last_seq_point
= sp
;
2465 if (td
->verbose_level
) {
2466 g_print ("\nSEQ POINT MAP FOR %s: \n", td
->method
->name
);
2468 for (i
= 0; i
< td
->seq_points
->len
; ++i
) {
2469 SeqPoint
*sp
= (SeqPoint
*)g_ptr_array_index (td
->seq_points
, i
);
2475 g_print ("\tIL0x%x[0x%0x] ->", sp
->il_offset
, sp
->native_offset
);
2476 for (l
= next
[i
]; l
; l
= l
->next
) {
2477 int next_index
= GPOINTER_TO_UINT (l
->data
);
2478 g_print (" IL0x%x", ((SeqPoint
*)g_ptr_array_index (td
->seq_points
, next_index
))->il_offset
);
2484 info
= mono_seq_point_info_new (array
->len
, TRUE
, array
->data
, TRUE
, &seq_info_size
);
2485 mono_atomic_fetch_add_i32 (&mono_jit_stats
.allocated_seq_points_size
, seq_info_size
);
2487 g_byte_array_free (array
, TRUE
);
2489 jinfo
->seq_points
= info
;
2492 #define BARRIER_IF_VOLATILE(td) \
2495 interp_add_ins (td, MINT_MONO_MEMORY_BARRIER); \
2496 volatile_ = FALSE; \
2500 #define INLINE_FAILURE \
2502 if (td->method != method) \
2507 interp_method_compute_offsets (InterpMethod
*imethod
, MonoMethodSignature
*signature
, MonoMethodHeader
*header
)
2509 int i
, offset
, size
, align
;
2511 imethod
->local_offsets
= (guint32
*)g_malloc (header
->num_locals
* sizeof(guint32
));
2513 for (i
= 0; i
< header
->num_locals
; ++i
) {
2514 size
= mono_type_size (header
->locals
[i
], &align
);
2515 offset
+= align
- 1;
2516 offset
&= ~(align
- 1);
2517 imethod
->local_offsets
[i
] = offset
;
2520 offset
= (offset
+ 7) & ~7;
2522 imethod
->exvar_offsets
= (guint32
*)g_malloc (header
->num_clauses
* sizeof (guint32
));
2523 for (i
= 0; i
< header
->num_clauses
; i
++) {
2524 imethod
->exvar_offsets
[i
] = offset
;
2525 offset
+= sizeof (MonoObject
*);
2527 offset
= (offset
+ 7) & ~7;
2529 imethod
->locals_size
= offset
;
2530 g_assert (imethod
->locals_size
< 65536);
2534 get_arg_type (MonoMethodSignature
*signature
, int arg_n
)
2536 if (signature
->hasthis
&& arg_n
== 0)
2537 return mono_get_object_type ();
2538 return signature
->params
[arg_n
- !!signature
->hasthis
];
2542 init_bb_start (TransformData
*td
, MonoMethodHeader
*header
)
2544 const unsigned char *ip
, *end
;
2545 const MonoOpcode
*opcode
;
2546 int offset
, i
, in
, backwards
;
2548 /* intern the strings in the method. */
2550 end
= ip
+ header
->code_size
;
2552 td
->is_bb_start
[0] = 1;
2559 else if (in
== 0xf0) {
2561 in
= *ip
+ MONO_CEE_MONO_ICALL
;
2563 opcode
= &mono_opcodes
[in
];
2564 switch (opcode
->argument
) {
2565 case MonoInlineNone
:
2568 case MonoInlineString
:
2571 case MonoInlineType
:
2574 case MonoInlineMethod
:
2577 case MonoInlineField
:
2581 case MonoShortInlineR
:
2584 case MonoInlineBrTarget
:
2585 offset
= read32 (ip
+ 1);
2587 backwards
= offset
< 0;
2588 offset
+= ip
- header
->code
;
2589 g_assert (offset
>= 0 && offset
< header
->code_size
);
2590 td
->is_bb_start
[offset
] |= backwards
? 2 : 1;
2592 case MonoShortInlineBrTarget
:
2593 offset
= ((gint8
*)ip
) [1];
2595 backwards
= offset
< 0;
2596 offset
+= ip
- header
->code
;
2597 g_assert (offset
>= 0 && offset
< header
->code_size
);
2598 td
->is_bb_start
[offset
] |= backwards
? 2 : 1;
2603 case MonoShortInlineVar
:
2604 case MonoShortInlineI
:
2607 case MonoInlineSwitch
: {
2609 const unsigned char *next_ip
;
2613 next_ip
= ip
+ 4 * n
;
2614 for (i
= 0; i
< n
; i
++) {
2615 offset
= read32 (ip
);
2616 backwards
= offset
< 0;
2617 offset
+= next_ip
- header
->code
;
2618 g_assert (offset
>= 0 && offset
< header
->code_size
);
2619 td
->is_bb_start
[offset
] |= backwards
? 2 : 1;
2629 g_assert_not_reached ();
2634 #ifdef NO_UNALIGNED_ACCESS
2636 get_unaligned_opcode (int opcode
)
2640 return MINT_LDFLD_I8_UNALIGNED
;
2642 return MINT_LDFLD_R8_UNALIGNED
;
2644 return MINT_STFLD_I8_UNALIGNED
;
2646 return MINT_STFLD_R8_UNALIGNED
;
2648 g_assert_not_reached ();
2655 interp_handle_isinst (TransformData
*td
, MonoClass
*klass
, gboolean isinst_instr
)
2657 /* Follow the logic from jit's handle_isinst */
2658 if (!mono_class_has_variant_generic_params (klass
)) {
2659 if (mono_class_is_interface (klass
))
2660 interp_add_ins (td
, isinst_instr
? MINT_ISINST_INTERFACE
: MINT_CASTCLASS_INTERFACE
);
2661 else if (!mono_class_is_marshalbyref (klass
) && m_class_get_rank (klass
) == 0 && !mono_class_is_nullable (klass
))
2662 interp_add_ins (td
, isinst_instr
? MINT_ISINST_COMMON
: MINT_CASTCLASS_COMMON
);
2664 interp_add_ins (td
, isinst_instr
? MINT_ISINST
: MINT_CASTCLASS
);
2666 interp_add_ins (td
, isinst_instr
? MINT_ISINST
: MINT_CASTCLASS
);
2668 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
2673 interp_emit_ldobj (TransformData
*td
, MonoClass
*klass
)
2675 int mt
= mint_type (m_class_get_byval_arg (klass
));
2678 if (mt
== MINT_TYPE_VT
) {
2679 interp_add_ins (td
, MINT_LDOBJ_VT
);
2680 size
= mono_class_value_size (klass
, NULL
);
2681 WRITE32_INS (td
->last_ins
, 0, &size
);
2684 int opcode
= interp_get_ldind_for_mt (mt
);
2685 interp_add_ins (td
, opcode
);
2688 SET_TYPE (td
->sp
- 1, stack_type
[mt
], klass
);
2692 interp_emit_stobj (TransformData
*td
, MonoClass
*klass
)
2694 int mt
= mint_type (m_class_get_byval_arg (klass
));
2696 if (mt
== MINT_TYPE_VT
) {
2698 interp_add_ins (td
, MINT_STOBJ_VT
);
2699 td
->last_ins
->data
[0] = get_data_item_index(td
, klass
);
2700 size
= mono_class_value_size (klass
, NULL
);
2707 opcode
= MINT_STIND_I1
;
2711 opcode
= MINT_STIND_I2
;
2714 opcode
= MINT_STIND_I4
;
2717 opcode
= MINT_STIND_I8
;
2720 opcode
= MINT_STIND_R4
;
2723 opcode
= MINT_STIND_R8
;
2726 opcode
= MINT_STIND_REF
;
2728 default: g_assert_not_reached (); break;
2730 interp_add_ins (td
, opcode
);
2736 interp_emit_ldsflda (TransformData
*td
, MonoClassField
*field
, MonoError
*error
)
2738 MonoDomain
*domain
= td
->rtm
->domain
;
2739 // Initialize the offset for the field
2740 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, field
->parent
, error
);
2741 return_if_nok (error
);
2743 if (mono_class_field_is_special_static (field
)) {
2746 mono_domain_lock (domain
);
2747 g_assert (domain
->special_static_fields
);
2748 offset
= GPOINTER_TO_UINT (g_hash_table_lookup (domain
->special_static_fields
, field
));
2749 mono_domain_unlock (domain
);
2752 interp_add_ins (td
, MINT_LDSSFLDA
);
2753 WRITE32_INS(td
->last_ins
, 0, &offset
);
2755 interp_add_ins (td
, MINT_LDSFLDA
);
2756 td
->last_ins
->data
[0] = get_data_item_index (td
, vtable
);
2757 td
->last_ins
->data
[1] = get_data_item_index (td
, (char*)mono_vtable_get_static_field_data (vtable
) + field
->offset
);
2762 interp_emit_sfld_access (TransformData
*td
, MonoClassField
*field
, MonoClass
*field_class
, int mt
, gboolean is_load
, MonoError
*error
)
2764 MonoDomain
*domain
= td
->rtm
->domain
;
2765 // Initialize the offset for the field
2766 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, field
->parent
, error
);
2767 return_if_nok (error
);
2769 if (mono_class_field_is_special_static (field
)) {
2772 mono_domain_lock (domain
);
2773 g_assert (domain
->special_static_fields
);
2774 offset
= GPOINTER_TO_UINT (g_hash_table_lookup (domain
->special_static_fields
, field
));
2775 mono_domain_unlock (domain
);
2778 // Offset is SpecialStaticOffset
2779 if ((offset
& 0x80000000) == 0 && mt
!= MINT_TYPE_VT
) {
2780 // This field is thread static
2781 interp_add_ins (td
, (is_load
? MINT_LDTSFLD_I1
: MINT_STTSFLD_I1
) + mt
);
2782 WRITE32_INS(td
->last_ins
, 0, &offset
);
2784 if (mt
== MINT_TYPE_VT
) {
2785 interp_add_ins (td
, is_load
? MINT_LDSSFLD_VT
: MINT_STSSFLD_VT
);
2786 WRITE32_INS(td
->last_ins
, 0, &offset
);
2788 int size
= mono_class_value_size (field_class
, NULL
);
2789 WRITE32_INS(td
->last_ins
, 2, &size
);
2791 interp_add_ins (td
, is_load
? MINT_LDSSFLD
: MINT_STSSFLD
);
2792 td
->last_ins
->data
[0] = get_data_item_index (td
, field
);
2793 WRITE32_INS(td
->last_ins
, 1, &offset
);
2798 interp_add_ins (td
, (mt
== MINT_TYPE_VT
) ? MINT_LDSFLD_VT
: (MINT_LDSFLD_I1
+ mt
- MINT_TYPE_I1
));
2800 interp_add_ins (td
, (mt
== MINT_TYPE_VT
) ? MINT_STSFLD_VT
: (MINT_STSFLD_I1
+ mt
- MINT_TYPE_I1
));
2802 td
->last_ins
->data
[0] = get_data_item_index (td
, vtable
);
2803 td
->last_ins
->data
[1] = get_data_item_index (td
, (char*)mono_vtable_get_static_field_data (vtable
) + field
->offset
);
2805 if (mt
== MINT_TYPE_VT
) {
2806 int size
= mono_class_value_size (field_class
, NULL
);
2807 WRITE32_INS(td
->last_ins
, 2, &size
);
2813 generate_code (TransformData
*td
, MonoMethod
*method
, MonoMethodHeader
*header
, MonoGenericContext
*generic_context
, MonoError
*error
)
2816 int offset
, mt
, i
, i32
;
2819 const unsigned char *end
;
2820 MonoSimpleBasicBlock
*bb
= NULL
, *original_bb
= NULL
;
2821 gboolean sym_seq_points
= FALSE
;
2822 MonoBitSet
*seq_point_locs
= NULL
;
2823 gboolean readonly
= FALSE
;
2824 gboolean volatile_
= FALSE
;
2825 MonoClass
*constrained_class
= NULL
;
2827 MonoClassField
*field
;
2828 MonoImage
*image
= m_class_get_image (method
->klass
);
2829 InterpMethod
*rtm
= td
->rtm
;
2830 MonoDomain
*domain
= rtm
->domain
;
2831 MonoMethodSignature
*signature
= mono_method_signature_internal (method
);
2832 gboolean ret
= TRUE
;
2833 gboolean emitted_funccall_seq_point
= FALSE
;
2834 guint32
*arg_offsets
= NULL
;
2835 guint32
*local_offsets
= NULL
;
2836 InterpInst
*last_seq_point
= NULL
;
2838 original_bb
= bb
= mono_basic_block_split (method
, error
, header
);
2839 goto_if_nok (error
, exit
);
2842 td
->il_code
= header
->code
;
2843 td
->in_start
= td
->ip
= header
->code
;
2844 end
= td
->ip
+ header
->code_size
;
2845 td
->stack_state
= (StackInfo
**)g_malloc0(header
->code_size
* sizeof(StackInfo
*));
2846 td
->stack_height
= (int*)g_malloc(header
->code_size
* sizeof(int));
2847 td
->vt_stack_size
= (int*)g_malloc(header
->code_size
* sizeof(int));
2848 td
->clause_indexes
= (int*)g_malloc (header
->code_size
* sizeof (int));
2849 td
->is_bb_start
= (guint8
*)g_malloc0(header
->code_size
);
2851 init_bb_start (td
, header
);
2853 for (i
= 0; i
< header
->code_size
; i
++) {
2854 td
->stack_height
[i
] = -1;
2855 td
->clause_indexes
[i
] = -1;
2858 for (i
= 0; i
< header
->num_clauses
; i
++) {
2859 MonoExceptionClause
*c
= header
->clauses
+ i
;
2860 td
->stack_height
[c
->handler_offset
] = 0;
2861 td
->vt_stack_size
[c
->handler_offset
] = 0;
2862 td
->is_bb_start
[c
->handler_offset
] = 1;
2864 td
->stack_height
[c
->handler_offset
] = 1;
2865 td
->stack_state
[c
->handler_offset
] = (StackInfo
*)g_malloc0(sizeof(StackInfo
));
2866 td
->stack_state
[c
->handler_offset
][0].type
= STACK_TYPE_O
;
2867 td
->stack_state
[c
->handler_offset
][0].klass
= NULL
; /*FIX*/
2869 if (c
->flags
& MONO_EXCEPTION_CLAUSE_FILTER
) {
2870 td
->stack_height
[c
->data
.filter_offset
] = 0;
2871 td
->vt_stack_size
[c
->data
.filter_offset
] = 0;
2872 td
->is_bb_start
[c
->data
.filter_offset
] = 1;
2874 td
->stack_height
[c
->data
.filter_offset
] = 1;
2875 td
->stack_state
[c
->data
.filter_offset
] = (StackInfo
*)g_malloc0(sizeof(StackInfo
));
2876 td
->stack_state
[c
->data
.filter_offset
][0].type
= STACK_TYPE_O
;
2877 td
->stack_state
[c
->data
.filter_offset
][0].klass
= NULL
; /*FIX*/
2880 for (int j
= c
->handler_offset
; j
< c
->handler_offset
+ c
->handler_len
; ++j
) {
2881 if (td
->clause_indexes
[j
] == -1)
2882 td
->clause_indexes
[j
] = i
;
2886 if (td
->gen_sdb_seq_points
&& td
->method
== method
) {
2887 MonoDebugMethodInfo
*minfo
;
2888 get_basic_blocks (td
);
2890 minfo
= mono_debug_lookup_method (method
);
2893 MonoSymSeqPoint
*sps
;
2894 int i
, n_il_offsets
;
2896 mono_debug_get_seq_points (minfo
, NULL
, NULL
, NULL
, &sps
, &n_il_offsets
);
2898 seq_point_locs
= mono_bitset_mem_new (mono_mempool_alloc0 (td
->mempool
, mono_bitset_alloc_size (header
->code_size
, 0)), header
->code_size
, 0);
2899 sym_seq_points
= TRUE
;
2901 for (i
= 0; i
< n_il_offsets
; ++i
) {
2902 if (sps
[i
].il_offset
< header
->code_size
)
2903 mono_bitset_set_fast (seq_point_locs
, sps
[i
].il_offset
);
2907 MonoDebugMethodAsyncInfo
* asyncMethod
= mono_debug_lookup_method_async_debug_info (method
);
2909 for (i
= 0; asyncMethod
!= NULL
&& i
< asyncMethod
->num_awaits
; i
++) {
2910 mono_bitset_set_fast (seq_point_locs
, asyncMethod
->resume_offsets
[i
]);
2911 mono_bitset_set_fast (seq_point_locs
, asyncMethod
->yield_offsets
[i
]);
2913 mono_debug_free_method_async_debug_info (asyncMethod
);
2915 } else if (!method
->wrapper_type
&& !method
->dynamic
&& mono_debug_image_has_debug_info (m_class_get_image (method
->klass
))) {
2916 /* Methods without line number info like auto-generated property accessors */
2917 seq_point_locs
= mono_bitset_new (header
->code_size
, 0);
2918 sym_seq_points
= TRUE
;
2922 if (sym_seq_points
) {
2923 last_seq_point
= interp_add_ins (td
, MINT_SDB_SEQ_POINT
);
2924 last_seq_point
->flags
= INTERP_INST_FLAG_SEQ_POINT_METHOD_ENTRY
;
2927 if (mono_debugger_method_has_breakpoint (method
))
2928 interp_add_ins (td
, MINT_BREAKPOINT
);
2930 if (method
== td
->method
) {
2931 if (td
->verbose_level
) {
2932 char *tmp
= mono_disasm_code (NULL
, method
, td
->ip
, end
);
2933 char *name
= mono_method_full_name (method
, TRUE
);
2934 g_print ("Method %s, original code:\n", name
);
2935 g_print ("%s\n", tmp
);
2940 if (header
->num_locals
&& header
->init_locals
)
2941 interp_add_ins (td
, MINT_INITLOCALS
);
2943 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (method
))
2944 interp_add_ins (td
, MINT_TRACE_ENTER
);
2945 else if (rtm
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_ENTER
)
2946 interp_add_ins (td
, MINT_PROF_ENTER
);
2948 /* safepoint is required on method entry */
2949 if (mono_threads_are_safepoints_enabled ())
2950 interp_add_ins (td
, MINT_SAFEPOINT
);
2953 arg_offsets
= (guint32
*) g_malloc ((!!signature
->hasthis
+ signature
->param_count
) * sizeof (guint32
));
2954 /* Allocate locals to store inlined method args from stack */
2955 for (i
= signature
->param_count
- 1; i
>= 0; i
--) {
2956 offset
= create_interp_local (td
, signature
->params
[i
]);
2957 arg_offsets
[i
+ !!signature
->hasthis
] = offset
;
2958 store_local_general (td
, offset
, signature
->params
[i
]);
2961 if (signature
->hasthis
) {
2963 * If this is value type, it is passed by address and not by value.
2964 * FIXME We should use MINT_TYPE_P instead of MINT_TYPE_O
2966 MonoType
*type
= mono_get_object_type ();
2967 offset
= create_interp_local (td
, type
);
2968 arg_offsets
[0] = offset
;
2969 store_local_general (td
, offset
, type
);
2972 local_offsets
= (guint32
*) g_malloc (header
->num_locals
* sizeof (guint32
));
2973 /* Allocate locals to store inlined method args from stack */
2974 for (i
= 0; i
< header
->num_locals
; i
++)
2975 local_offsets
[i
] = create_interp_local (td
, header
->locals
[i
]);
2978 while (td
->ip
< end
) {
2979 g_assert (td
->sp
>= td
->stack
);
2980 g_assert (td
->vt_sp
< 0x10000000);
2981 in_offset
= td
->ip
- header
->code
;
2982 td
->in_start
= td
->ip
;
2983 InterpInst
*prev_last_ins
= td
->last_ins
;
2985 if (td
->stack_height
[in_offset
] >= 0) {
2986 g_assert (td
->is_bb_start
[in_offset
]);
2987 if (td
->stack_height
[in_offset
] > 0)
2988 memcpy (td
->stack
, td
->stack_state
[in_offset
], td
->stack_height
[in_offset
] * sizeof(td
->stack
[0]));
2989 td
->sp
= td
->stack
+ td
->stack_height
[in_offset
];
2990 td
->vt_sp
= td
->vt_stack_size
[in_offset
];
2993 if (in_offset
== bb
->end
)
2997 int op_size
= mono_opcode_size (td
->ip
, end
);
2998 g_assert (op_size
> 0); /* The BB formation pass must catch all bad ops */
3000 if (td
->verbose_level
> 1)
3001 g_print ("SKIPPING DEAD OP at %x\n", in_offset
);
3007 if (td
->verbose_level
> 1) {
3008 g_print ("IL_%04lx %s %-10s, sp %ld, %s %-12s vt_sp %u (max %u)\n",
3009 td
->ip
- td
->il_code
,
3010 td
->is_bb_start
[td
->ip
- td
->il_code
] == 3 ? "<>" :
3011 td
->is_bb_start
[td
->ip
- td
->il_code
] == 2 ? "< " :
3012 td
->is_bb_start
[td
->ip
- td
->il_code
] == 1 ? " >" : " ",
3013 mono_opcode_name (*td
->ip
), td
->sp
- td
->stack
,
3014 td
->sp
> td
->stack
? stack_type_string
[td
->sp
[-1].type
] : " ",
3015 (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
)) : "",
3016 td
->vt_sp
, td
->max_vt_sp
);
3019 if (sym_seq_points
&& mono_bitset_test_fast (seq_point_locs
, td
->ip
- header
->code
)) {
3020 InterpBasicBlock
*cbb
= td
->offset_to_bb
[td
->ip
- header
->code
];
3024 * Make methods interruptable at the beginning, and at the targets of
3025 * backward branches.
3027 if (in_offset
== 0 || g_slist_length (cbb
->preds
) > 1)
3028 interp_add_ins (td
, MINT_SDB_INTR_LOC
);
3030 last_seq_point
= interp_add_ins (td
, MINT_SDB_SEQ_POINT
);
3033 if (td
->is_bb_start
[in_offset
]) {
3034 int index
= td
->clause_indexes
[in_offset
];
3036 MonoExceptionClause
*clause
= &header
->clauses
[index
];
3037 if ((clause
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
||
3038 clause
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
) &&
3039 in_offset
== clause
->handler_offset
)
3040 interp_add_ins (td
, MINT_START_ABORT_PROT
);
3047 emitted_funccall_seq_point
= FALSE
;
3051 SIMPLE_OP(td
, MINT_BREAK
);
3057 int arg_n
= *td
->ip
- CEE_LDARG_0
;
3058 if (td
->method
== method
)
3059 load_arg (td
, arg_n
);
3061 load_local_general (td
, arg_offsets
[arg_n
], get_arg_type (signature
, arg_n
));
3069 int loc_n
= *td
->ip
- CEE_LDLOC_0
;
3070 if (td
->method
== method
)
3071 load_local (td
, loc_n
);
3073 load_local_general (td
, local_offsets
[loc_n
], header
->locals
[loc_n
]);
3081 int loc_n
= *td
->ip
- CEE_STLOC_0
;
3082 if (td
->method
== method
)
3083 store_local (td
, loc_n
);
3085 store_local_general (td
, local_offsets
[loc_n
], header
->locals
[loc_n
]);
3090 int arg_n
= ((guint8
*)td
->ip
)[1];
3091 if (td
->method
== method
)
3092 load_arg (td
, arg_n
);
3094 load_local_general (td
, arg_offsets
[arg_n
], get_arg_type (signature
, arg_n
));
3098 case CEE_LDARGA_S
: {
3099 /* NOTE: n includes this */
3100 int n
= ((guint8
*) td
->ip
) [1];
3102 if (td
->method
== method
) {
3103 get_arg_type_exact (td
, n
, &mt
);
3104 interp_add_ins (td
, mt
== MINT_TYPE_VT
? MINT_LDARGA_VT
: MINT_LDARGA
);
3105 td
->last_ins
->data
[0] = n
;
3107 interp_add_ins (td
, MINT_LDLOCA_S
);
3108 td
->last_ins
->data
[0] = arg_offsets
[n
];
3110 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
3115 int arg_n
= ((guint8
*)td
->ip
)[1];
3116 if (td
->method
== method
)
3117 store_arg (td
, arg_n
);
3119 store_local_general (td
, arg_offsets
[arg_n
], get_arg_type (signature
, arg_n
));
3124 int loc_n
= ((guint8
*)td
->ip
)[1];
3125 if (td
->method
== method
)
3126 load_local (td
, loc_n
);
3128 load_local_general (td
, local_offsets
[loc_n
], header
->locals
[loc_n
]);
3132 case CEE_LDLOCA_S
: {
3133 int loc_n
= ((guint8
*)td
->ip
)[1];
3134 interp_add_ins (td
, MINT_LDLOCA_S
);
3135 if (td
->method
== method
)
3136 td
->last_ins
->data
[0] = td
->rtm
->local_offsets
[loc_n
];
3138 td
->last_ins
->data
[0] = local_offsets
[loc_n
];
3139 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
3144 int loc_n
= ((guint8
*)td
->ip
)[1];
3145 if (td
->method
== method
)
3146 store_local (td
, loc_n
);
3148 store_local_general (td
, local_offsets
[loc_n
], header
->locals
[loc_n
]);
3153 SIMPLE_OP(td
, MINT_LDNULL
);
3154 PUSH_TYPE(td
, STACK_TYPE_O
, NULL
);
3157 SIMPLE_OP(td
, MINT_LDC_I4_M1
);
3158 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
3161 if (!td
->is_bb_start
[td
->ip
+ 1 - td
->il_code
] && td
->ip
[1] == 0xfe && td
->ip
[2] == CEE_CEQ
&&
3162 td
->sp
> td
->stack
&& td
->sp
[-1].type
== STACK_TYPE_I4
) {
3163 SIMPLE_OP(td
, MINT_CEQ0_I4
);
3166 SIMPLE_OP(td
, MINT_LDC_I4_0
);
3167 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
3171 if (!td
->is_bb_start
[td
->ip
+ 1 - td
->il_code
] &&
3172 (td
->ip
[1] == CEE_ADD
|| td
->ip
[1] == CEE_SUB
) && td
->sp
[-1].type
== STACK_TYPE_I4
) {
3173 interp_add_ins (td
, td
->ip
[1] == CEE_ADD
? MINT_ADD1_I4
: MINT_SUB1_I4
);
3176 SIMPLE_OP(td
, MINT_LDC_I4_1
);
3177 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
3187 SIMPLE_OP(td
, (*td
->ip
- CEE_LDC_I4_0
) + MINT_LDC_I4_0
);
3188 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
3191 interp_add_ins (td
, MINT_LDC_I4_S
);
3192 td
->last_ins
->data
[0] = ((gint8
*) td
->ip
) [1];
3194 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
3197 i32
= read32 (td
->ip
+ 1);
3198 interp_add_ins (td
, MINT_LDC_I4
);
3199 WRITE32_INS (td
->last_ins
, 0, &i32
);
3201 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
3204 gint64 val
= read64 (td
->ip
+ 1);
3205 interp_add_ins (td
, MINT_LDC_I8
);
3206 WRITE64_INS (td
->last_ins
, 0, &val
);
3208 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I8
);
3213 readr4 (td
->ip
+ 1, &val
);
3214 interp_add_ins (td
, MINT_LDC_R4
);
3215 WRITE32_INS (td
->last_ins
, 0, &val
);
3217 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_R4
);
3222 readr8 (td
->ip
+ 1, &val
);
3223 interp_add_ins (td
, MINT_LDC_R8
);
3224 WRITE64_INS (td
->last_ins
, 0, &val
);
3226 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_R8
);
3230 int type
= td
->sp
[-1].type
;
3231 MonoClass
*klass
= td
->sp
[-1].klass
;
3232 if (td
->sp
[-1].type
== STACK_TYPE_VT
) {
3233 gint32 size
= mono_class_value_size (klass
, NULL
);
3235 interp_add_ins (td
, MINT_DUP_VT
);
3236 WRITE32_INS (td
->last_ins
, 0, &size
);
3239 SIMPLE_OP(td
, MINT_DUP
);
3240 PUSH_TYPE(td
, type
, klass
);
3245 SIMPLE_OP(td
, MINT_POP
);
3246 td
->last_ins
->data
[0] = 0;
3247 if (td
->sp
[-1].type
== STACK_TYPE_VT
) {
3248 int size
= mono_class_value_size (td
->sp
[-1].klass
, NULL
);
3249 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
3250 interp_add_ins (td
, MINT_VTRESULT
);
3251 td
->last_ins
->data
[0] = 0;
3252 WRITE32_INS (td
->last_ins
, 1, &size
);
3260 if (td
->sp
> td
->stack
)
3261 g_warning ("CEE_JMP: stack must be empty");
3262 token
= read32 (td
->ip
+ 1);
3263 m
= mono_get_method_checked (image
, token
, NULL
, generic_context
, error
);
3264 goto_if_nok (error
, exit
);
3265 interp_add_ins (td
, MINT_JMP
);
3266 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
3267 goto_if_nok (error
, exit
);
3271 case CEE_CALLVIRT
: /* Fall through */
3272 case CEE_CALLI
: /* Fall through */
3274 gboolean need_seq_point
= FALSE
;
3276 if (sym_seq_points
&& !mono_bitset_test_fast (seq_point_locs
, td
->ip
+ 5 - header
->code
))
3277 need_seq_point
= TRUE
;
3279 if (!interp_transform_call (td
, method
, NULL
, domain
, generic_context
, td
->is_bb_start
, constrained_class
, readonly
, error
, TRUE
))
3282 if (need_seq_point
) {
3283 //check is is a nested call and remove the MONO_INST_NONEMPTY_STACK of the last breakpoint, only for non native methods
3284 if (!(method
->flags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)) {
3285 if (emitted_funccall_seq_point
) {
3287 last_seq_point
->flags
|= INTERP_INST_FLAG_SEQ_POINT_NESTED_CALL
;
3290 emitted_funccall_seq_point
= TRUE
;
3292 last_seq_point
= interp_add_ins (td
, MINT_SDB_SEQ_POINT
);
3293 // This seq point is actually associated with the instruction following the call
3294 last_seq_point
->il_offset
= td
->ip
- header
->code
;
3295 last_seq_point
->flags
= INTERP_INST_FLAG_SEQ_POINT_NONEMPTY_STACK
;
3298 constrained_class
= NULL
;
3303 /* Return from inlined method, return value is on top of stack */
3304 if (td
->method
!= method
) {
3310 MonoType
*ult
= mini_type_get_underlying_type (signature
->ret
);
3311 if (ult
->type
!= MONO_TYPE_VOID
) {
3312 CHECK_STACK (td
, 1);
3314 if (mint_type (ult
) == MINT_TYPE_VT
) {
3315 MonoClass
*klass
= mono_class_from_mono_type_internal (ult
);
3316 vt_size
= mono_class_value_size (klass
, NULL
);
3319 if (td
->sp
> td
->stack
) {
3320 mono_error_set_generic_error (error
, "System", "InvalidProgramException", "");
3323 if (td
->vt_sp
!= ALIGN_TO (vt_size
, MINT_VT_ALIGNMENT
))
3324 g_error ("%s: CEE_RET: value type stack: %d vs. %d", mono_method_full_name (td
->method
, TRUE
), td
->vt_sp
, vt_size
);
3326 if (sym_seq_points
) {
3327 last_seq_point
= interp_add_ins (td
, MINT_SDB_SEQ_POINT
);
3328 td
->last_ins
->flags
= INTERP_INST_FLAG_SEQ_POINT_METHOD_EXIT
;
3331 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (method
)) {
3332 /* This does the return as well */
3333 interp_add_ins (td
, MINT_TRACE_EXIT
);
3334 if (ult
->type
== MONO_TYPE_VOID
)
3336 WRITE32_INS (td
->last_ins
, 0, &vt_size
);
3340 SIMPLE_OP(td
, ult
->type
== MONO_TYPE_VOID
? MINT_RET_VOID
: MINT_RET
);
3342 interp_add_ins (td
, MINT_RET_VT
);
3343 WRITE32_INS (td
->last_ins
, 0, &vt_size
);
3351 handle_branch (td
, MINT_BR_S
, MINT_BR
, 5 + read32 (td
->ip
+ 1));
3356 handle_branch (td
, MINT_BR_S
, MINT_BR
, 2 + (gint8
)td
->ip
[1]);
3361 one_arg_branch (td
, MINT_BRFALSE_I4
, 5 + read32 (td
->ip
+ 1));
3366 one_arg_branch (td
, MINT_BRFALSE_I4
, 2 + (gint8
)td
->ip
[1]);
3371 one_arg_branch (td
, MINT_BRTRUE_I4
, 5 + read32 (td
->ip
+ 1));
3376 one_arg_branch (td
, MINT_BRTRUE_I4
, 2 + (gint8
)td
->ip
[1]);
3381 two_arg_branch (td
, MINT_BEQ_I4
, 5 + read32 (td
->ip
+ 1));
3386 two_arg_branch (td
, MINT_BEQ_I4
, 2 + (gint8
) td
->ip
[1]);
3391 two_arg_branch (td
, MINT_BGE_I4
, 5 + read32 (td
->ip
+ 1));
3396 two_arg_branch (td
, MINT_BGE_I4
, 2 + (gint8
) td
->ip
[1]);
3401 two_arg_branch (td
, MINT_BGT_I4
, 5 + read32 (td
->ip
+ 1));
3406 two_arg_branch (td
, MINT_BGT_I4
, 2 + (gint8
) td
->ip
[1]);
3411 two_arg_branch (td
, MINT_BLT_I4
, 5 + read32 (td
->ip
+ 1));
3416 two_arg_branch (td
, MINT_BLT_I4
, 2 + (gint8
) td
->ip
[1]);
3421 two_arg_branch (td
, MINT_BLE_I4
, 5 + read32 (td
->ip
+ 1));
3426 two_arg_branch (td
, MINT_BLE_I4
, 2 + (gint8
) td
->ip
[1]);
3431 two_arg_branch (td
, MINT_BNE_UN_I4
, 5 + read32 (td
->ip
+ 1));
3436 two_arg_branch (td
, MINT_BNE_UN_I4
, 2 + (gint8
) td
->ip
[1]);
3441 two_arg_branch (td
, MINT_BGE_UN_I4
, 5 + read32 (td
->ip
+ 1));
3446 two_arg_branch (td
, MINT_BGE_UN_I4
, 2 + (gint8
) td
->ip
[1]);
3451 two_arg_branch (td
, MINT_BGT_UN_I4
, 5 + read32 (td
->ip
+ 1));
3456 two_arg_branch (td
, MINT_BGT_UN_I4
, 2 + (gint8
) td
->ip
[1]);
3461 two_arg_branch (td
, MINT_BLE_UN_I4
, 5 + read32 (td
->ip
+ 1));
3466 two_arg_branch (td
, MINT_BLE_UN_I4
, 2 + (gint8
) td
->ip
[1]);
3471 two_arg_branch (td
, MINT_BLT_UN_I4
, 5 + read32 (td
->ip
+ 1));
3476 two_arg_branch (td
, MINT_BLT_UN_I4
, 2 + (gint8
) td
->ip
[1]);
3482 const unsigned char *next_ip
;
3484 n
= read32 (td
->ip
);
3485 interp_add_ins_explicit (td
, MINT_SWITCH
, MINT_SWITCH_LEN (n
));
3486 WRITE32_INS (td
->last_ins
, 0, &n
);
3488 next_ip
= td
->ip
+ n
* 4;
3490 int stack_height
= td
->sp
- td
->stack
;
3491 for (i
= 0; i
< n
; i
++) {
3492 offset
= read32 (td
->ip
);
3493 target
= next_ip
- td
->il_code
+ offset
;
3496 if (stack_height
> 0 && stack_height
!= td
->stack_height
[target
])
3497 g_warning ("SWITCH with back branch and non-empty stack");
3500 td
->stack_height
[target
] = stack_height
;
3501 td
->vt_stack_size
[target
] = td
->vt_sp
;
3502 if (stack_height
> 0)
3503 td
->stack_state
[target
] = (StackInfo
*)g_memdup (td
->stack
, stack_height
* sizeof (td
->stack
[0]));
3505 WRITE32_INS (td
->last_ins
, 2 + i
* 2, &target
);
3511 CHECK_STACK (td
, 1);
3512 SIMPLE_OP (td
, MINT_LDIND_I1_CHECK
);
3513 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3514 BARRIER_IF_VOLATILE (td
);
3517 CHECK_STACK (td
, 1);
3518 SIMPLE_OP (td
, MINT_LDIND_U1_CHECK
);
3519 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3520 BARRIER_IF_VOLATILE (td
);
3523 CHECK_STACK (td
, 1);
3524 SIMPLE_OP (td
, MINT_LDIND_I2_CHECK
);
3525 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3526 BARRIER_IF_VOLATILE (td
);
3529 CHECK_STACK (td
, 1);
3530 SIMPLE_OP (td
, MINT_LDIND_U2_CHECK
);
3531 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3532 BARRIER_IF_VOLATILE (td
);
3535 CHECK_STACK (td
, 1);
3536 SIMPLE_OP (td
, MINT_LDIND_I4_CHECK
);
3537 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3538 BARRIER_IF_VOLATILE (td
);
3541 CHECK_STACK (td
, 1);
3542 SIMPLE_OP (td
, MINT_LDIND_U4_CHECK
);
3543 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3544 BARRIER_IF_VOLATILE (td
);
3547 CHECK_STACK (td
, 1);
3548 SIMPLE_OP (td
, MINT_LDIND_I8_CHECK
);
3549 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
3550 BARRIER_IF_VOLATILE (td
);
3553 CHECK_STACK (td
, 1);
3554 SIMPLE_OP (td
, MINT_LDIND_REF_CHECK
);
3555 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I
);
3556 BARRIER_IF_VOLATILE (td
);
3559 CHECK_STACK (td
, 1);
3560 SIMPLE_OP (td
, MINT_LDIND_R4_CHECK
);
3561 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R4
);
3562 BARRIER_IF_VOLATILE (td
);
3565 CHECK_STACK (td
, 1);
3566 SIMPLE_OP (td
, MINT_LDIND_R8_CHECK
);
3567 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
3568 BARRIER_IF_VOLATILE (td
);
3571 CHECK_STACK (td
, 1);
3572 SIMPLE_OP (td
, MINT_LDIND_REF_CHECK
);
3573 BARRIER_IF_VOLATILE (td
);
3574 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_O
);
3577 CHECK_STACK (td
, 2);
3578 BARRIER_IF_VOLATILE (td
);
3579 SIMPLE_OP (td
, MINT_STIND_REF
);
3583 CHECK_STACK (td
, 2);
3584 BARRIER_IF_VOLATILE (td
);
3585 SIMPLE_OP (td
, MINT_STIND_I1
);
3589 CHECK_STACK (td
, 2);
3590 BARRIER_IF_VOLATILE (td
);
3591 SIMPLE_OP (td
, MINT_STIND_I2
);
3595 CHECK_STACK (td
, 2);
3596 BARRIER_IF_VOLATILE (td
);
3597 SIMPLE_OP (td
, MINT_STIND_I4
);
3601 CHECK_STACK (td
, 2);
3602 BARRIER_IF_VOLATILE (td
);
3603 SIMPLE_OP (td
, MINT_STIND_I
);
3607 CHECK_STACK (td
, 2);
3608 BARRIER_IF_VOLATILE (td
);
3609 SIMPLE_OP (td
, MINT_STIND_I8
);
3613 CHECK_STACK (td
, 2);
3614 BARRIER_IF_VOLATILE (td
);
3615 SIMPLE_OP (td
, MINT_STIND_R4
);
3619 CHECK_STACK (td
, 2);
3620 BARRIER_IF_VOLATILE (td
);
3621 SIMPLE_OP (td
, MINT_STIND_R8
);
3625 binary_arith_op(td
, MINT_ADD_I4
);
3629 binary_arith_op(td
, MINT_SUB_I4
);
3633 binary_arith_op(td
, MINT_MUL_I4
);
3637 binary_arith_op(td
, MINT_DIV_I4
);
3641 binary_arith_op(td
, MINT_DIV_UN_I4
);
3645 binary_arith_op (td
, MINT_REM_I4
);
3649 binary_arith_op (td
, MINT_REM_UN_I4
);
3653 binary_arith_op (td
, MINT_AND_I4
);
3657 binary_arith_op (td
, MINT_OR_I4
);
3661 binary_arith_op (td
, MINT_XOR_I4
);
3665 shift_op (td
, MINT_SHL_I4
);
3669 shift_op (td
, MINT_SHR_I4
);
3673 shift_op (td
, MINT_SHR_UN_I4
);
3677 unary_arith_op (td
, MINT_NEG_I4
);
3681 unary_arith_op (td
, MINT_NOT_I4
);
3685 CHECK_STACK (td
, 1);
3686 switch (td
->sp
[-1].type
) {
3688 interp_add_ins (td
, MINT_CONV_U1_R4
);
3691 interp_add_ins (td
, MINT_CONV_U1_R8
);
3694 interp_add_ins (td
, MINT_CONV_U1_I4
);
3697 interp_add_ins (td
, MINT_CONV_U1_I8
);
3700 g_assert_not_reached ();
3703 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3706 CHECK_STACK (td
, 1);
3707 switch (td
->sp
[-1].type
) {
3709 interp_add_ins (td
, MINT_CONV_I1_R4
);
3712 interp_add_ins (td
, MINT_CONV_I1_R8
);
3715 interp_add_ins (td
, MINT_CONV_I1_I4
);
3718 interp_add_ins (td
, MINT_CONV_I1_I8
);
3721 g_assert_not_reached ();
3724 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3727 CHECK_STACK (td
, 1);
3728 switch (td
->sp
[-1].type
) {
3730 interp_add_ins (td
, MINT_CONV_U2_R4
);
3733 interp_add_ins (td
, MINT_CONV_U2_R8
);
3736 interp_add_ins (td
, MINT_CONV_U2_I4
);
3739 interp_add_ins (td
, MINT_CONV_U2_I8
);
3742 g_assert_not_reached ();
3745 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3748 CHECK_STACK (td
, 1);
3749 switch (td
->sp
[-1].type
) {
3751 interp_add_ins (td
, MINT_CONV_I2_R4
);
3754 interp_add_ins (td
, MINT_CONV_I2_R8
);
3757 interp_add_ins (td
, MINT_CONV_I2_I4
);
3760 interp_add_ins (td
, MINT_CONV_I2_I8
);
3763 g_assert_not_reached ();
3766 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3769 CHECK_STACK (td
, 1);
3770 switch (td
->sp
[-1].type
) {
3772 #if SIZEOF_VOID_P == 4
3773 interp_add_ins (td
, MINT_CONV_U4_R8
);
3775 interp_add_ins (td
, MINT_CONV_U8_R8
);
3779 #if SIZEOF_VOID_P == 8
3780 interp_add_ins (td
, MINT_CONV_U8_I4
);
3784 #if SIZEOF_VOID_P == 4
3785 interp_add_ins (td
, MINT_CONV_U4_I8
);
3792 g_assert_not_reached ();
3795 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I
);
3798 CHECK_STACK (td
, 1);
3799 switch (td
->sp
[-1].type
) {
3801 #if SIZEOF_VOID_P == 8
3802 interp_add_ins (td
, MINT_CONV_I8_R8
);
3804 interp_add_ins (td
, MINT_CONV_I4_R8
);
3808 #if SIZEOF_VOID_P == 8
3809 interp_add_ins (td
, MINT_CONV_I8_I4
);
3817 #if SIZEOF_VOID_P == 4
3818 interp_add_ins (td
, MINT_CONV_I4_I8
);
3822 g_assert_not_reached ();
3825 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I
);
3828 CHECK_STACK (td
, 1);
3829 switch (td
->sp
[-1].type
) {
3831 interp_add_ins (td
, MINT_CONV_U4_R4
);
3834 interp_add_ins (td
, MINT_CONV_U4_R8
);
3839 interp_add_ins (td
, MINT_CONV_U4_I8
);
3842 #if SIZEOF_VOID_P == 8
3843 interp_add_ins (td
, MINT_CONV_U4_I8
);
3847 g_assert_not_reached ();
3850 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3853 CHECK_STACK (td
, 1);
3854 switch (td
->sp
[-1].type
) {
3856 interp_add_ins (td
, MINT_CONV_I4_R4
);
3859 interp_add_ins (td
, MINT_CONV_I4_R8
);
3864 interp_add_ins (td
, MINT_CONV_I4_I8
);
3867 #if SIZEOF_VOID_P == 8
3868 interp_add_ins (td
, MINT_CONV_I4_I8
);
3872 g_assert_not_reached ();
3875 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3878 CHECK_STACK (td
, 1);
3879 switch (td
->sp
[-1].type
) {
3881 interp_add_ins (td
, MINT_CONV_I8_R4
);
3884 interp_add_ins (td
, MINT_CONV_I8_R8
);
3886 case STACK_TYPE_I4
: {
3887 if (interp_ins_is_ldc (td
->last_ins
) && !td
->is_bb_start
[in_offset
]) {
3888 gint64 ct
= interp_ldc_i4_get_const (td
->last_ins
);
3889 interp_remove_ins (td
, td
->last_ins
);
3891 interp_add_ins (td
, MINT_LDC_I8
);
3892 WRITE64_INS (td
->last_ins
, 0, &ct
);
3894 interp_add_ins (td
, MINT_CONV_I8_I4
);
3901 #if SIZEOF_VOID_P == 4
3902 interp_add_ins (td
, MINT_CONV_I8_I4
);
3906 g_assert_not_reached ();
3909 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
3912 CHECK_STACK (td
, 1);
3913 switch (td
->sp
[-1].type
) {
3915 interp_add_ins (td
, MINT_CONV_R4_R8
);
3918 interp_add_ins (td
, MINT_CONV_R4_I8
);
3921 interp_add_ins (td
, MINT_CONV_R4_I4
);
3927 g_assert_not_reached ();
3930 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R4
);
3933 CHECK_STACK (td
, 1);
3934 switch (td
->sp
[-1].type
) {
3936 interp_add_ins (td
, MINT_CONV_R8_I4
);
3939 interp_add_ins (td
, MINT_CONV_R8_I8
);
3942 interp_add_ins (td
, MINT_CONV_R8_R4
);
3947 g_assert_not_reached ();
3950 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
3953 CHECK_STACK (td
, 1);
3954 switch (td
->sp
[-1].type
) {
3956 if (interp_ins_is_ldc (td
->last_ins
) && !td
->is_bb_start
[in_offset
]) {
3957 gint64 ct
= (guint32
)interp_ldc_i4_get_const (td
->last_ins
);
3958 interp_remove_ins (td
, td
->last_ins
);
3960 interp_add_ins (td
, MINT_LDC_I8
);
3961 WRITE64_INS (td
->last_ins
, 0, &ct
);
3963 interp_add_ins (td
, MINT_CONV_U8_I4
);
3969 interp_add_ins (td
, MINT_CONV_U8_R4
);
3972 interp_add_ins (td
, MINT_CONV_U8_R8
);
3975 #if SIZEOF_VOID_P == 4
3976 interp_add_ins (td
, MINT_CONV_U8_I4
);
3980 g_assert_not_reached ();
3983 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
3986 CHECK_STACK (td
, 2);
3988 token
= read32 (td
->ip
+ 1);
3989 klass
= mono_class_get_and_inflate_typespec_checked (image
, token
, generic_context
, error
);
3990 goto_if_nok (error
, exit
);
3992 if (m_class_is_valuetype (klass
)) {
3993 int mt
= mint_type (m_class_get_byval_arg (klass
));
3994 interp_add_ins (td
, (mt
== MINT_TYPE_VT
) ? MINT_CPOBJ_VT
: MINT_CPOBJ
);
3995 td
->last_ins
->data
[0] = get_data_item_index(td
, klass
);
3997 interp_add_ins (td
, MINT_LDIND_REF
);
3998 interp_add_ins (td
, MINT_STIND_REF
);
4005 CHECK_STACK (td
, 1);
4007 token
= read32 (td
->ip
+ 1);
4009 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4010 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
4012 klass
= mono_class_get_and_inflate_typespec_checked (image
, token
, generic_context
, error
);
4013 goto_if_nok (error
, exit
);
4016 interp_emit_ldobj (td
, klass
);
4019 BARRIER_IF_VOLATILE (td
);
4023 token
= mono_metadata_token_index (read32 (td
->ip
+ 1));
4025 if (method
->wrapper_type
== MONO_WRAPPER_NONE
) {
4026 MonoString
*s
= mono_ldstr_checked (domain
, image
, token
, error
);
4027 goto_if_nok (error
, exit
);
4028 /* GC won't scan code stream, but reference is held by metadata
4029 * machinery so we are good here */
4030 interp_add_ins (td
, MINT_LDSTR
);
4031 td
->last_ins
->data
[0] = get_data_item_index (td
, s
);
4033 /* defer allocation to execution-time */
4034 interp_add_ins (td
, MINT_LDSTR_TOKEN
);
4035 td
->last_ins
->data
[0] = get_data_item_index (td
, GUINT_TO_POINTER (token
));
4037 PUSH_TYPE(td
, STACK_TYPE_O
, mono_defaults
.string_class
);
4042 MonoMethodSignature
*csignature
;
4043 guint32 vt_stack_used
= 0;
4044 guint32 vt_res_size
= 0;
4047 token
= read32 (td
->ip
);
4050 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4051 m
= (MonoMethod
*)mono_method_get_wrapper_data (method
, token
);
4053 m
= mono_get_method_checked (image
, token
, NULL
, generic_context
, error
);
4054 goto_if_nok (error
, exit
);
4057 csignature
= mono_method_signature_internal (m
);
4060 if (!mono_class_init_internal (klass
)) {
4061 mono_error_set_for_class_failure (error
, klass
);
4062 goto_if_nok (error
, exit
);
4065 if (mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_ABSTRACT
) {
4066 char* full_name
= mono_type_get_full_name (klass
);
4067 mono_error_set_member_access (error
, "Cannot create an abstract class: %s", full_name
);
4069 goto_if_nok (error
, exit
);
4072 td
->sp
-= csignature
->param_count
;
4073 if (mono_class_is_magic_int (klass
) || mono_class_is_magic_float (klass
)) {
4074 #if SIZEOF_VOID_P == 8
4075 if (mono_class_is_magic_int (klass
) && td
->sp
[0].type
== STACK_TYPE_I4
)
4076 interp_add_ins (td
, MINT_CONV_I8_I4
);
4077 else if (mono_class_is_magic_float (klass
) && td
->sp
[0].type
== STACK_TYPE_R4
)
4078 interp_add_ins (td
, MINT_CONV_R8_R4
);
4080 interp_add_ins (td
, MINT_NEWOBJ_MAGIC
);
4081 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
4082 goto_if_nok (error
, exit
);
4084 PUSH_TYPE (td
, stack_type
[mint_type (m_class_get_byval_arg (klass
))], klass
);
4086 if (m_class_get_parent (klass
) == mono_defaults
.array_class
) {
4087 interp_add_ins (td
, MINT_NEWOBJ_ARRAY
);
4088 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
4089 td
->last_ins
->data
[1] = csignature
->param_count
;
4090 } else if (m_class_get_image (klass
) == mono_defaults
.corlib
&&
4091 !strcmp (m_class_get_name (m
->klass
), "ByReference`1") &&
4092 !strcmp (m
->name
, ".ctor")) {
4093 /* public ByReference(ref T value) */
4094 g_assert (csignature
->hasthis
&& csignature
->param_count
== 1);
4095 interp_add_ins (td
, MINT_INTRINS_BYREFERENCE_CTOR
);
4096 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
4097 } else if (klass
!= mono_defaults
.string_class
&&
4098 !mono_class_is_marshalbyref (klass
) &&
4099 !mono_class_has_finalizer (klass
) &&
4100 !m_class_has_weak_fields (klass
)) {
4101 if (!m_class_is_valuetype (klass
))
4102 interp_add_ins (td
, MINT_NEWOBJ_FAST
);
4103 else if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
)
4104 interp_add_ins (td
, MINT_NEWOBJ_VTST_FAST
);
4106 interp_add_ins (td
, MINT_NEWOBJ_VT_FAST
);
4108 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
4109 td
->last_ins
->data
[1] = csignature
->param_count
;
4111 if (!m_class_is_valuetype (klass
)) {
4112 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, klass
, error
);
4113 goto_if_nok (error
, exit
);
4114 td
->last_ins
->data
[2] = get_data_item_index (td
, vtable
);
4115 } else if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
) {
4116 td
->last_ins
->data
[2] = mono_class_value_size (klass
, NULL
);
4119 interp_add_ins (td
, MINT_NEWOBJ
);
4120 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
4122 goto_if_nok (error
, exit
);
4124 if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
) {
4125 vt_res_size
= mono_class_value_size (klass
, NULL
);
4126 PUSH_VT (td
, vt_res_size
);
4128 for (i
= 0; i
< csignature
->param_count
; ++i
) {
4129 int mt
= mint_type(csignature
->params
[i
]);
4130 if (mt
== MINT_TYPE_VT
) {
4131 MonoClass
*k
= mono_class_from_mono_type_internal (csignature
->params
[i
]);
4132 gint32 size
= mono_class_value_size (k
, NULL
);
4133 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4134 vt_stack_used
+= size
;
4137 if (vt_stack_used
!= 0 || vt_res_size
!= 0) {
4138 interp_add_ins (td
, MINT_VTRESULT
);
4139 td
->last_ins
->data
[0] = vt_res_size
;
4140 WRITE32_INS (td
->last_ins
, 1, &vt_stack_used
);
4141 td
->vt_sp
-= vt_stack_used
;
4143 PUSH_TYPE (td
, stack_type
[mint_type (m_class_get_byval_arg (klass
))], klass
);
4149 gboolean isinst_instr
= *td
->ip
== CEE_ISINST
;
4150 CHECK_STACK (td
, 1);
4151 token
= read32 (td
->ip
+ 1);
4152 klass
= mini_get_class (method
, token
, generic_context
);
4153 CHECK_TYPELOAD (klass
);
4154 interp_handle_isinst (td
, klass
, isinst_instr
);
4156 td
->sp
[-1].klass
= klass
;
4160 switch (td
->sp
[-1].type
) {
4164 interp_add_ins (td
, MINT_CONV_R_UN_I8
);
4167 interp_add_ins (td
, MINT_CONV_R_UN_I4
);
4170 g_assert_not_reached ();
4172 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
4176 CHECK_STACK (td
, 1);
4177 token
= read32 (td
->ip
+ 1);
4179 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4180 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
4182 klass
= mono_class_get_and_inflate_typespec_checked (image
, token
, generic_context
, error
);
4183 goto_if_nok (error
, exit
);
4186 if (mono_class_is_nullable (klass
)) {
4187 MonoMethod
*target_method
;
4188 if (m_class_is_enumtype (mono_class_get_nullable_param_internal (klass
)))
4189 target_method
= mono_class_get_method_from_name_checked (klass
, "UnboxExact", 1, 0, error
);
4191 target_method
= mono_class_get_method_from_name_checked (klass
, "Unbox", 1, 0, error
);
4192 goto_if_nok (error
, exit
);
4193 /* td->ip is incremented by interp_transform_call */
4194 if (!interp_transform_call (td
, method
, target_method
, domain
, generic_context
, td
->is_bb_start
, NULL
, FALSE
, error
, FALSE
))
4197 * CEE_UNBOX needs to push address of vtype while Nullable.Unbox returns the value type
4198 * We create a local variable in the frame so that we can fetch its address.
4200 int local_offset
= create_interp_local (td
, m_class_get_byval_arg (klass
));
4201 store_local_general (td
, local_offset
, m_class_get_byval_arg (klass
));
4202 interp_add_ins (td
, MINT_LDLOCA_S
);
4203 td
->last_ins
->data
[0] = local_offset
;
4204 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_MP
);
4206 interp_add_ins (td
, MINT_UNBOX
);
4207 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
4208 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_MP
);
4213 CHECK_STACK (td
, 1);
4214 token
= read32 (td
->ip
+ 1);
4216 klass
= mini_get_class (method
, token
, generic_context
);
4217 CHECK_TYPELOAD (klass
);
4219 if (mini_type_is_reference (m_class_get_byval_arg (klass
))) {
4220 int mt
= mint_type (m_class_get_byval_arg (klass
));
4221 interp_handle_isinst (td
, klass
, FALSE
);
4222 SET_TYPE (td
->sp
- 1, stack_type
[mt
], klass
);
4223 } else if (mono_class_is_nullable (klass
)) {
4224 MonoMethod
*target_method
;
4225 if (m_class_is_enumtype (mono_class_get_nullable_param_internal (klass
)))
4226 target_method
= mono_class_get_method_from_name_checked (klass
, "UnboxExact", 1, 0, error
);
4228 target_method
= mono_class_get_method_from_name_checked (klass
, "Unbox", 1, 0, error
);
4229 goto_if_nok (error
, exit
);
4230 /* td->ip is incremented by interp_transform_call */
4231 if (!interp_transform_call (td
, method
, target_method
, domain
, generic_context
, td
->is_bb_start
, NULL
, FALSE
, error
, FALSE
))
4234 interp_add_ins (td
, MINT_UNBOX
);
4235 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
4237 interp_emit_ldobj (td
, klass
);
4245 CHECK_STACK (td
, 1);
4246 SIMPLE_OP (td
, MINT_THROW
);
4250 CHECK_STACK (td
, 1);
4251 token
= read32 (td
->ip
+ 1);
4252 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
4253 goto_if_nok (error
, exit
);
4254 MonoType
*ftype
= mono_field_get_type_internal (field
);
4255 gboolean is_static
= !!(ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
);
4256 mono_class_init_internal (klass
);
4257 #ifndef DISABLE_REMOTING
4258 if (m_class_get_marshalbyref (klass
) || mono_class_is_contextbound (klass
) || klass
== mono_defaults
.marshalbyrefobject_class
) {
4259 g_assert (!is_static
);
4260 int offset
= m_class_is_valuetype (klass
) ? field
->offset
- MONO_ABI_SIZEOF (MonoObject
) : field
->offset
;
4262 interp_add_ins (td
, MINT_MONO_LDPTR
);
4263 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
4264 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
4265 interp_add_ins (td
, MINT_MONO_LDPTR
);
4266 td
->last_ins
->data
[0] = get_data_item_index (td
, field
);
4267 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
4268 interp_add_ins (td
, MINT_LDC_I4
);
4269 WRITE32_INS (td
->last_ins
, 0, &offset
);
4270 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I4
);
4271 #if SIZEOF_VOID_P == 8
4272 interp_add_ins (td
, MINT_CONV_I8_I4
);
4275 MonoMethod
*wrapper
= mono_marshal_get_ldflda_wrapper (field
->type
);
4276 /* td->ip is incremented by interp_transform_call */
4277 if (!interp_transform_call (td
, method
, wrapper
, domain
, generic_context
, td
->is_bb_start
, NULL
, FALSE
, error
, FALSE
))
4283 interp_add_ins (td
, MINT_POP
);
4284 td
->last_ins
->data
[0] = 0;
4285 interp_emit_ldsflda (td
, field
, error
);
4286 goto_if_nok (error
, exit
);
4288 if ((td
->sp
- 1)->type
== STACK_TYPE_O
) {
4289 interp_add_ins (td
, MINT_LDFLDA
);
4291 g_assert ((td
->sp
-1)->type
== STACK_TYPE_MP
);
4292 interp_add_ins (td
, MINT_LDFLDA_UNSAFE
);
4294 td
->last_ins
->data
[0] = m_class_is_valuetype (klass
) ? field
->offset
- MONO_ABI_SIZEOF (MonoObject
) : field
->offset
;
4298 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
4302 CHECK_STACK (td
, 1);
4303 token
= read32 (td
->ip
+ 1);
4304 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
4305 goto_if_nok (error
, exit
);
4306 MonoType
*ftype
= mono_field_get_type_internal (field
);
4307 gboolean is_static
= !!(ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
);
4308 mono_class_init_internal (klass
);
4310 MonoClass
*field_klass
= mono_class_from_mono_type_internal (ftype
);
4311 mt
= mint_type (m_class_get_byval_arg (field_klass
));
4312 #ifndef DISABLE_REMOTING
4313 if (m_class_get_marshalbyref (klass
)) {
4314 g_assert (!is_static
);
4315 interp_add_ins (td
, mt
== MINT_TYPE_VT
? MINT_LDRMFLD_VT
: MINT_LDRMFLD
);
4316 td
->last_ins
->data
[0] = get_data_item_index (td
, field
);
4321 interp_add_ins (td
, MINT_POP
);
4322 td
->last_ins
->data
[0] = 0;
4323 interp_emit_sfld_access (td
, field
, field_klass
, mt
, TRUE
, error
);
4324 goto_if_nok (error
, exit
);
4326 int opcode
= MINT_LDFLD_I1
+ mt
- MINT_TYPE_I1
;
4327 #ifdef NO_UNALIGNED_ACCESS
4328 if ((mt
== MINT_TYPE_I8
|| mt
== MINT_TYPE_R8
) && field
->offset
% SIZEOF_VOID_P
!= 0)
4329 opcode
= get_unaligned_opcode (opcode
);
4331 interp_add_ins (td
, opcode
);
4332 td
->last_ins
->data
[0] = m_class_is_valuetype (klass
) ? field
->offset
- MONO_ABI_SIZEOF (MonoObject
) : field
->offset
;
4333 if (mt
== MINT_TYPE_VT
) {
4334 int size
= mono_class_value_size (field_klass
, NULL
);
4335 WRITE32_INS (td
->last_ins
, 1, &size
);
4339 if (mt
== MINT_TYPE_VT
) {
4340 int size
= mono_class_value_size (field_klass
, NULL
);
4343 if (td
->sp
[-1].type
== STACK_TYPE_VT
) {
4344 int size
= mono_class_value_size (klass
, NULL
);
4345 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4346 int field_vt_size
= 0;
4347 if (mt
== MINT_TYPE_VT
) {
4349 * Pop the loaded field from the vtstack (it will still be present
4350 * at the same vtstack address) and we will load it in place of the
4351 * containing valuetype with the second MINT_VTRESULT.
4353 field_vt_size
= mono_class_value_size (field_klass
, NULL
);
4354 field_vt_size
= ALIGN_TO (field_vt_size
, MINT_VT_ALIGNMENT
);
4355 interp_add_ins (td
, MINT_VTRESULT
);
4356 td
->last_ins
->data
[0] = 0;
4357 WRITE32_INS (td
->last_ins
, 1, &field_vt_size
);
4360 interp_add_ins (td
, MINT_VTRESULT
);
4361 td
->last_ins
->data
[0] = field_vt_size
;
4362 WRITE32_INS (td
->last_ins
, 1, &size
);
4365 SET_TYPE (td
->sp
- 1, stack_type
[mt
], field_klass
);
4366 BARRIER_IF_VOLATILE (td
);
4370 CHECK_STACK (td
, 2);
4371 token
= read32 (td
->ip
+ 1);
4372 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
4373 goto_if_nok (error
, exit
);
4374 MonoType
*ftype
= mono_field_get_type_internal (field
);
4375 gboolean is_static
= !!(ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
);
4376 MonoClass
*field_klass
= mono_class_from_mono_type_internal (ftype
);
4377 mono_class_init_internal (klass
);
4378 mt
= mint_type (ftype
);
4380 BARRIER_IF_VOLATILE (td
);
4382 #ifndef DISABLE_REMOTING
4383 if (m_class_get_marshalbyref (klass
)) {
4384 g_assert (!is_static
);
4385 interp_add_ins (td
, mt
== MINT_TYPE_VT
? MINT_STRMFLD_VT
: MINT_STRMFLD
);
4386 td
->last_ins
->data
[0] = get_data_item_index (td
, field
);
4391 interp_add_ins (td
, MINT_POP
);
4392 td
->last_ins
->data
[0] = 1;
4393 interp_emit_sfld_access (td
, field
, field_klass
, mt
, FALSE
, error
);
4394 goto_if_nok (error
, exit
);
4396 /* the vtable of the field might not be initialized at this point */
4397 mono_class_vtable_checked (domain
, field_klass
, error
);
4398 goto_if_nok (error
, exit
);
4400 int opcode
= MINT_STFLD_I1
+ mt
- MINT_TYPE_I1
;
4401 #ifdef NO_UNALIGNED_ACCESS
4402 if ((mt
== MINT_TYPE_I8
|| mt
== MINT_TYPE_R8
) && field
->offset
% SIZEOF_VOID_P
!= 0)
4403 opcode
= get_unaligned_opcode (opcode
);
4405 interp_add_ins (td
, opcode
);
4406 td
->last_ins
->data
[0] = m_class_is_valuetype (klass
) ? field
->offset
- MONO_ABI_SIZEOF (MonoObject
) : field
->offset
;
4407 if (mt
== MINT_TYPE_VT
) {
4408 /* the vtable of the field might not be initialized at this point */
4409 mono_class_vtable_checked (domain
, field_klass
, error
);
4410 goto_if_nok (error
, exit
);
4412 td
->last_ins
->data
[1] = get_data_item_index (td
, field_klass
);
4416 if (mt
== MINT_TYPE_VT
) {
4417 int size
= mono_class_value_size (field_klass
, NULL
);
4425 token
= read32 (td
->ip
+ 1);
4426 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
4427 goto_if_nok (error
, exit
);
4428 interp_emit_ldsflda (td
, field
, error
);
4429 goto_if_nok (error
, exit
);
4431 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
4435 token
= read32 (td
->ip
+ 1);
4436 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
4437 goto_if_nok (error
, exit
);
4438 MonoType
*ftype
= mono_field_get_type_internal (field
);
4439 mt
= mint_type (ftype
);
4440 klass
= mono_class_from_mono_type_internal (ftype
);
4442 interp_emit_sfld_access (td
, field
, klass
, mt
, TRUE
, error
);
4443 goto_if_nok (error
, exit
);
4445 if (mt
== MINT_TYPE_VT
) {
4446 int size
= mono_class_value_size (klass
, NULL
);
4450 PUSH_TYPE(td
, stack_type
[mt
], klass
);
4454 CHECK_STACK (td
, 1);
4455 token
= read32 (td
->ip
+ 1);
4456 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
4457 goto_if_nok (error
, exit
);
4458 MonoType
*ftype
= mono_field_get_type_internal (field
);
4459 mt
= mint_type (ftype
);
4461 /* the vtable of the field might not be initialized at this point */
4462 MonoClass
*fld_klass
= mono_class_from_mono_type_internal (ftype
);
4463 mono_class_vtable_checked (domain
, fld_klass
, error
);
4464 goto_if_nok (error
, exit
);
4466 interp_emit_sfld_access (td
, field
, fld_klass
, mt
, FALSE
, error
);
4467 goto_if_nok (error
, exit
);
4469 if (mt
== MINT_TYPE_VT
) {
4470 int size
= mono_class_value_size (fld_klass
, NULL
);
4478 token
= read32 (td
->ip
+ 1);
4480 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4481 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
4483 klass
= mini_get_class (method
, token
, generic_context
);
4484 CHECK_TYPELOAD (klass
);
4486 BARRIER_IF_VOLATILE (td
);
4488 interp_emit_stobj (td
, klass
);
4493 case CEE_CONV_OVF_I_UN
:
4494 case CEE_CONV_OVF_U_UN
:
4495 CHECK_STACK (td
, 1);
4496 switch (td
->sp
[-1].type
) {
4498 #if SIZEOF_VOID_P == 8
4499 interp_add_ins (td
, MINT_CONV_OVF_I8_UN_R8
);
4501 interp_add_ins (td
, MINT_CONV_OVF_I4_UN_R8
);
4505 #if SIZEOF_VOID_P == 4
4506 interp_add_ins (td
, MINT_CONV_OVF_I4_UN_I8
);
4510 #if SIZEOF_VOID_P == 8
4511 interp_add_ins (td
, MINT_CONV_I8_U4
);
4512 #elif SIZEOF_VOID_P == 4
4513 if (*td
->ip
== CEE_CONV_OVF_I_UN
)
4514 interp_add_ins (td
, MINT_CONV_OVF_I4_U4
);
4518 g_assert_not_reached ();
4521 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
4524 case CEE_CONV_OVF_I8_UN
:
4525 case CEE_CONV_OVF_U8_UN
:
4526 CHECK_STACK (td
, 1);
4527 switch (td
->sp
[-1].type
) {
4529 interp_add_ins (td
, MINT_CONV_OVF_I8_UN_R8
);
4532 if (*td
->ip
== CEE_CONV_OVF_I8_UN
)
4533 interp_add_ins (td
, MINT_CONV_OVF_I8_U8
);
4536 interp_add_ins (td
, MINT_CONV_I8_U4
);
4539 g_assert_not_reached ();
4542 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
4547 CHECK_STACK (td
, 1);
4548 token
= read32 (td
->ip
+ 1);
4549 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4550 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
4552 klass
= mini_get_class (method
, token
, generic_context
);
4553 CHECK_TYPELOAD (klass
);
4555 if (mono_class_is_nullable (klass
)) {
4556 MonoMethod
*target_method
= mono_class_get_method_from_name_checked (klass
, "Box", 1, 0, error
);
4557 goto_if_nok (error
, exit
);
4558 /* td->ip is incremented by interp_transform_call */
4559 if (!interp_transform_call (td
, method
, target_method
, domain
, generic_context
, td
->is_bb_start
, NULL
, FALSE
, error
, FALSE
))
4561 } else if (!m_class_is_valuetype (klass
)) {
4562 /* already boxed, do nothing. */
4565 if (G_UNLIKELY (m_class_is_byreflike (klass
))) {
4566 mono_error_set_bad_image (error
, image
, "Cannot box IsByRefLike type '%s.%s'", m_class_get_name_space (klass
), m_class_get_name (klass
));
4569 if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
) {
4570 size
= mono_class_value_size (klass
, NULL
);
4571 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4573 } else if (td
->sp
[-1].type
== STACK_TYPE_R8
&& m_class_get_byval_arg (klass
)->type
== MONO_TYPE_R4
) {
4574 interp_add_ins (td
, MINT_CONV_R4_R8
);
4576 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, klass
, error
);
4577 goto_if_nok (error
, exit
);
4579 if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
)
4580 interp_add_ins (td
, MINT_BOX_VT
);
4582 interp_add_ins (td
, MINT_BOX
);
4583 td
->last_ins
->data
[0] = get_data_item_index (td
, vtable
);
4584 td
->last_ins
->data
[1] = 0;
4585 SET_TYPE(td
->sp
- 1, STACK_TYPE_O
, klass
);
4592 CHECK_STACK (td
, 1);
4593 token
= read32 (td
->ip
+ 1);
4595 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4596 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
4598 klass
= mini_get_class (method
, token
, generic_context
);
4599 CHECK_TYPELOAD (klass
);
4601 unsigned char lentype
= (td
->sp
- 1)->type
;
4602 if (lentype
== STACK_TYPE_I8
) {
4603 /* mimic mini behaviour */
4604 interp_add_ins (td
, MINT_CONV_OVF_U4_I8
);
4606 g_assert (lentype
== STACK_TYPE_I4
);
4607 interp_add_ins (td
, MINT_CONV_OVF_U4_I4
);
4609 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I4
);
4610 interp_add_ins (td
, MINT_NEWARR
);
4611 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
4612 SET_TYPE (td
->sp
- 1, STACK_TYPE_O
, klass
);
4617 CHECK_STACK (td
, 1);
4618 SIMPLE_OP (td
, MINT_LDLEN
);
4619 #ifdef MONO_BIG_ARRAYS
4620 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I8
);
4622 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I4
);
4626 CHECK_STACK (td
, 2);
4628 token
= read32 (td
->ip
+ 1);
4630 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4631 klass
= (MonoClass
*) mono_method_get_wrapper_data (method
, token
);
4633 klass
= mini_get_class (method
, token
, generic_context
);
4635 CHECK_TYPELOAD (klass
);
4637 if (!m_class_is_valuetype (klass
) && method
->wrapper_type
== MONO_WRAPPER_NONE
&& !readonly
) {
4639 * Check the class for failures before the type check, which can
4640 * throw other exceptions.
4642 mono_class_setup_vtable (klass
);
4643 CHECK_TYPELOAD (klass
);
4644 interp_add_ins (td
, MINT_LDELEMA_TC
);
4646 interp_add_ins (td
, MINT_LDELEMA
);
4648 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
4649 /* according to spec, ldelema bytecode is only used for 1-dim arrays */
4650 td
->last_ins
->data
[1] = 2;
4655 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
4658 CHECK_STACK (td
, 2);
4660 SIMPLE_OP (td
, MINT_LDELEM_I1
);
4662 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4665 CHECK_STACK (td
, 2);
4667 SIMPLE_OP (td
, MINT_LDELEM_U1
);
4669 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4672 CHECK_STACK (td
, 2);
4674 SIMPLE_OP (td
, MINT_LDELEM_I2
);
4676 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4679 CHECK_STACK (td
, 2);
4681 SIMPLE_OP (td
, MINT_LDELEM_U2
);
4683 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4686 CHECK_STACK (td
, 2);
4688 SIMPLE_OP (td
, MINT_LDELEM_I4
);
4690 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4693 CHECK_STACK (td
, 2);
4695 SIMPLE_OP (td
, MINT_LDELEM_U4
);
4697 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4700 CHECK_STACK (td
, 2);
4702 SIMPLE_OP (td
, MINT_LDELEM_I8
);
4704 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
4707 CHECK_STACK (td
, 2);
4709 SIMPLE_OP (td
, MINT_LDELEM_I
);
4711 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I
);
4714 CHECK_STACK (td
, 2);
4716 SIMPLE_OP (td
, MINT_LDELEM_R4
);
4718 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R4
);
4721 CHECK_STACK (td
, 2);
4723 SIMPLE_OP (td
, MINT_LDELEM_R8
);
4725 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
4727 case CEE_LDELEM_REF
:
4728 CHECK_STACK (td
, 2);
4730 SIMPLE_OP (td
, MINT_LDELEM_REF
);
4732 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_O
);
4735 CHECK_STACK (td
, 2);
4736 token
= read32 (td
->ip
+ 1);
4737 klass
= mini_get_class (method
, token
, generic_context
);
4738 CHECK_TYPELOAD (klass
);
4739 switch (mint_type (m_class_get_byval_arg (klass
))) {
4742 SIMPLE_OP (td
, MINT_LDELEM_I1
);
4744 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4748 SIMPLE_OP (td
, MINT_LDELEM_U1
);
4750 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4754 SIMPLE_OP (td
, MINT_LDELEM_U2
);
4756 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4760 SIMPLE_OP (td
, MINT_LDELEM_I2
);
4762 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4766 SIMPLE_OP (td
, MINT_LDELEM_I4
);
4768 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4772 SIMPLE_OP (td
, MINT_LDELEM_I8
);
4774 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
4778 SIMPLE_OP (td
, MINT_LDELEM_R4
);
4780 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R4
);
4784 SIMPLE_OP (td
, MINT_LDELEM_R8
);
4786 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
4790 SIMPLE_OP (td
, MINT_LDELEM_REF
);
4792 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_O
);
4794 case MINT_TYPE_VT
: {
4795 int size
= mono_class_value_size (klass
, NULL
);
4797 SIMPLE_OP (td
, MINT_LDELEM_VT
);
4798 WRITE32_INS (td
->last_ins
, 0, &size
);
4800 SET_TYPE (td
->sp
- 1, STACK_TYPE_VT
, klass
);
4805 GString
*res
= g_string_new ("");
4806 mono_type_get_desc (res
, m_class_get_byval_arg (klass
), TRUE
);
4807 g_print ("LDELEM: %s -> %d (%s)\n", m_class_get_name (klass
), mint_type (m_class_get_byval_arg (klass
)), res
->str
);
4808 g_string_free (res
, TRUE
);
4816 CHECK_STACK (td
, 3);
4818 SIMPLE_OP (td
, MINT_STELEM_I
);
4822 CHECK_STACK (td
, 3);
4824 SIMPLE_OP (td
, MINT_STELEM_I1
);
4828 CHECK_STACK (td
, 3);
4830 SIMPLE_OP (td
, MINT_STELEM_I2
);
4834 CHECK_STACK (td
, 3);
4836 SIMPLE_OP (td
, MINT_STELEM_I4
);
4840 CHECK_STACK (td
, 3);
4842 SIMPLE_OP (td
, MINT_STELEM_I8
);
4846 CHECK_STACK (td
, 3);
4848 SIMPLE_OP (td
, MINT_STELEM_R4
);
4852 CHECK_STACK (td
, 3);
4854 SIMPLE_OP (td
, MINT_STELEM_R8
);
4857 case CEE_STELEM_REF
:
4858 CHECK_STACK (td
, 3);
4860 SIMPLE_OP (td
, MINT_STELEM_REF
);
4864 CHECK_STACK (td
, 3);
4866 token
= read32 (td
->ip
+ 1);
4867 klass
= mini_get_class (method
, token
, generic_context
);
4868 CHECK_TYPELOAD (klass
);
4869 switch (mint_type (m_class_get_byval_arg (klass
))) {
4871 SIMPLE_OP (td
, MINT_STELEM_I1
);
4874 SIMPLE_OP (td
, MINT_STELEM_U1
);
4877 SIMPLE_OP (td
, MINT_STELEM_I2
);
4880 SIMPLE_OP (td
, MINT_STELEM_U2
);
4883 SIMPLE_OP (td
, MINT_STELEM_I4
);
4886 SIMPLE_OP (td
, MINT_STELEM_I8
);
4889 SIMPLE_OP (td
, MINT_STELEM_R4
);
4892 SIMPLE_OP (td
, MINT_STELEM_R8
);
4895 SIMPLE_OP (td
, MINT_STELEM_REF
);
4897 case MINT_TYPE_VT
: {
4898 int size
= mono_class_value_size (klass
, NULL
);
4899 SIMPLE_OP (td
, MINT_STELEM_VT
);
4900 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
4901 WRITE32_INS (td
->last_ins
, 1, &size
);
4906 GString
*res
= g_string_new ("");
4907 mono_type_get_desc (res
, m_class_get_byval_arg (klass
), TRUE
);
4908 g_print ("STELEM: %s -> %d (%s)\n", m_class_get_name (klass
), mint_type (m_class_get_byval_arg (klass
)), res
->str
);
4909 g_string_free (res
, TRUE
);
4918 case CEE_CONV_OVF_U1
:
4920 case CEE_CONV_OVF_I8
:
4922 #if SIZEOF_VOID_P == 8
4923 case CEE_CONV_OVF_U
:
4927 CHECK_STACK (td
, 1);
4928 SIMPLE_OP (td
, MINT_CKFINITE
);
4931 CHECK_STACK (td
, 1);
4933 token
= read32 (td
->ip
+ 1);
4934 klass
= mini_get_class (method
, token
, generic_context
);
4935 CHECK_TYPELOAD (klass
);
4937 interp_add_ins (td
, MINT_MKREFANY
);
4938 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
4941 PUSH_VT (td
, sizeof (MonoTypedRef
));
4942 SET_TYPE(td
->sp
- 1, STACK_TYPE_VT
, mono_defaults
.typed_reference_class
);
4944 case CEE_REFANYVAL
: {
4945 CHECK_STACK (td
, 1);
4947 token
= read32 (td
->ip
+ 1);
4948 klass
= mini_get_class (method
, token
, generic_context
);
4949 CHECK_TYPELOAD (klass
);
4951 interp_add_ins (td
, MINT_REFANYVAL
);
4952 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
4954 POP_VT (td
, sizeof (MonoTypedRef
));
4955 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
4960 case CEE_CONV_OVF_I1
:
4961 case CEE_CONV_OVF_I1_UN
: {
4962 gboolean is_un
= *td
->ip
== CEE_CONV_OVF_I1_UN
;
4963 CHECK_STACK (td
, 1);
4964 switch (td
->sp
[-1].type
) {
4966 interp_add_ins (td
, is_un
? MINT_CONV_OVF_I1_UN_R8
: MINT_CONV_OVF_I1_R8
);
4969 interp_add_ins (td
, is_un
? MINT_CONV_OVF_I1_U4
: MINT_CONV_OVF_I1_I4
);
4972 interp_add_ins (td
, is_un
? MINT_CONV_OVF_I1_U8
: MINT_CONV_OVF_I1_I8
);
4975 g_assert_not_reached ();
4978 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4981 case CEE_CONV_OVF_U1
:
4982 case CEE_CONV_OVF_U1_UN
:
4983 CHECK_STACK (td
, 1);
4984 switch (td
->sp
[-1].type
) {
4986 interp_add_ins (td
, MINT_CONV_OVF_U1_R8
);
4989 interp_add_ins (td
, MINT_CONV_OVF_U1_I4
);
4992 interp_add_ins (td
, MINT_CONV_OVF_U1_I8
);
4995 g_assert_not_reached ();
4998 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5000 case CEE_CONV_OVF_I2
:
5001 case CEE_CONV_OVF_I2_UN
: {
5002 gboolean is_un
= *td
->ip
== CEE_CONV_OVF_I2_UN
;
5003 CHECK_STACK (td
, 1);
5004 switch (td
->sp
[-1].type
) {
5006 interp_add_ins (td
, is_un
? MINT_CONV_OVF_I2_UN_R8
: MINT_CONV_OVF_I2_R8
);
5009 interp_add_ins (td
, is_un
? MINT_CONV_OVF_I2_U4
: MINT_CONV_OVF_I2_I4
);
5012 interp_add_ins (td
, is_un
? MINT_CONV_OVF_I2_U8
: MINT_CONV_OVF_I2_I8
);
5015 g_assert_not_reached ();
5018 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5021 case CEE_CONV_OVF_U2_UN
:
5022 case CEE_CONV_OVF_U2
:
5023 CHECK_STACK (td
, 1);
5024 switch (td
->sp
[-1].type
) {
5026 interp_add_ins (td
, MINT_CONV_OVF_U2_R8
);
5029 interp_add_ins (td
, MINT_CONV_OVF_U2_I4
);
5032 interp_add_ins (td
, MINT_CONV_OVF_U2_I8
);
5035 g_assert_not_reached ();
5038 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5040 #if SIZEOF_VOID_P == 4
5041 case CEE_CONV_OVF_I
:
5043 case CEE_CONV_OVF_I4
:
5044 case CEE_CONV_OVF_I4_UN
:
5045 CHECK_STACK (td
, 1);
5046 switch (td
->sp
[-1].type
) {
5048 interp_add_ins (td
, MINT_CONV_OVF_I4_R4
);
5051 interp_add_ins (td
, MINT_CONV_OVF_I4_R8
);
5054 if (*td
->ip
== CEE_CONV_OVF_I4_UN
)
5055 interp_add_ins (td
, MINT_CONV_OVF_I4_U4
);
5058 if (*td
->ip
== CEE_CONV_OVF_I4_UN
)
5059 interp_add_ins (td
, MINT_CONV_OVF_I4_U8
);
5061 interp_add_ins (td
, MINT_CONV_OVF_I4_I8
);
5064 g_assert_not_reached ();
5067 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5069 #if SIZEOF_VOID_P == 4
5070 case CEE_CONV_OVF_U
:
5072 case CEE_CONV_OVF_U4
:
5073 case CEE_CONV_OVF_U4_UN
:
5074 CHECK_STACK (td
, 1);
5075 switch (td
->sp
[-1].type
) {
5077 interp_add_ins (td
, MINT_CONV_OVF_U4_R4
);
5080 interp_add_ins (td
, MINT_CONV_OVF_U4_R8
);
5083 if (*td
->ip
!= CEE_CONV_OVF_U4_UN
)
5084 interp_add_ins (td
, MINT_CONV_OVF_U4_I4
);
5087 interp_add_ins (td
, MINT_CONV_OVF_U4_I8
);
5090 interp_add_ins (td
, MINT_CONV_OVF_U4_P
);
5093 g_assert_not_reached ();
5096 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5098 #if SIZEOF_VOID_P == 8
5099 case CEE_CONV_OVF_I
:
5101 case CEE_CONV_OVF_I8
:
5102 CHECK_STACK (td
, 1);
5103 switch (td
->sp
[-1].type
) {
5105 interp_add_ins (td
, MINT_CONV_OVF_I8_R4
);
5108 interp_add_ins (td
, MINT_CONV_OVF_I8_R8
);
5111 interp_add_ins (td
, MINT_CONV_I8_I4
);
5116 g_assert_not_reached ();
5119 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
5121 #if SIZEOF_VOID_P == 8
5122 case CEE_CONV_OVF_U
:
5124 case CEE_CONV_OVF_U8
:
5125 CHECK_STACK (td
, 1);
5126 switch (td
->sp
[-1].type
) {
5128 interp_add_ins (td
, MINT_CONV_OVF_U8_R4
);
5131 interp_add_ins (td
, MINT_CONV_OVF_U8_R8
);
5134 interp_add_ins (td
, MINT_CONV_OVF_U8_I4
);
5137 interp_add_ins (td
, MINT_CONV_OVF_U8_I8
);
5140 g_assert_not_reached ();
5143 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
5148 token
= read32 (td
->ip
+ 1);
5149 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
|| method
->wrapper_type
== MONO_WRAPPER_SYNCHRONIZED
) {
5150 handle
= mono_method_get_wrapper_data (method
, token
);
5151 klass
= (MonoClass
*) mono_method_get_wrapper_data (method
, token
+ 1);
5152 if (klass
== mono_defaults
.typehandle_class
)
5153 handle
= m_class_get_byval_arg ((MonoClass
*) handle
);
5155 if (generic_context
) {
5156 handle
= mono_class_inflate_generic_type_checked ((MonoType
*)handle
, generic_context
, error
);
5157 goto_if_nok (error
, exit
);
5160 handle
= mono_ldtoken_checked (image
, token
, &klass
, generic_context
, error
);
5161 goto_if_nok (error
, exit
);
5163 mono_class_init_internal (klass
);
5164 mt
= mint_type (m_class_get_byval_arg (klass
));
5165 g_assert (mt
== MINT_TYPE_VT
);
5166 size
= mono_class_value_size (klass
, NULL
);
5167 g_assert (size
== sizeof(gpointer
));
5169 const unsigned char *next_ip
= td
->ip
+ 5;
5170 MonoMethod
*cmethod
;
5171 if (next_ip
< end
&&
5172 !td
->is_bb_start
[next_ip
- td
->il_code
] &&
5173 (*next_ip
== CEE_CALL
|| *next_ip
== CEE_CALLVIRT
) &&
5174 (cmethod
= mono_get_method_checked (image
, read32 (next_ip
+ 1), NULL
, generic_context
, error
)) &&
5175 (cmethod
->klass
== mono_defaults
.systemtype_class
) &&
5176 (strcmp (cmethod
->name
, "GetTypeFromHandle") == 0)) {
5177 interp_add_ins (td
, MINT_MONO_LDPTR
);
5178 gpointer systype
= mono_type_get_object_checked (domain
, (MonoType
*)handle
, error
);
5179 goto_if_nok (error
, exit
);
5180 td
->last_ins
->data
[0] = get_data_item_index (td
, systype
);
5181 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_MP
);
5182 td
->ip
= next_ip
+ 5;
5184 PUSH_VT (td
, sizeof(gpointer
));
5185 interp_add_ins (td
, MINT_LDTOKEN
);
5186 td
->last_ins
->data
[0] = get_data_item_index (td
, handle
);
5187 PUSH_TYPE (td
, stack_type
[mt
], klass
);
5194 binary_arith_op(td
, MINT_ADD_OVF_I4
);
5197 case CEE_ADD_OVF_UN
:
5198 binary_arith_op(td
, MINT_ADD_OVF_UN_I4
);
5202 binary_arith_op(td
, MINT_MUL_OVF_I4
);
5205 case CEE_MUL_OVF_UN
:
5206 binary_arith_op(td
, MINT_MUL_OVF_UN_I4
);
5210 binary_arith_op(td
, MINT_SUB_OVF_I4
);
5213 case CEE_SUB_OVF_UN
:
5214 binary_arith_op(td
, MINT_SUB_OVF_UN_I4
);
5217 case CEE_ENDFINALLY
: {
5218 g_assert (td
->clause_indexes
[in_offset
] != -1);
5220 SIMPLE_OP (td
, MINT_ENDFINALLY
);
5221 td
->last_ins
->data
[0] = td
->clause_indexes
[in_offset
];
5228 if (*td
->ip
== CEE_LEAVE
)
5229 offset
= 5 + read32 (td
->ip
+ 1);
5231 offset
= 2 + (gint8
)td
->ip
[1];
5234 if (td
->clause_indexes
[in_offset
] != -1) {
5235 /* LEAVE instructions in catch clauses need to check for abort exceptions */
5236 handle_branch (td
, MINT_LEAVE_S_CHECK
, MINT_LEAVE_CHECK
, offset
);
5238 handle_branch (td
, MINT_LEAVE_S
, MINT_LEAVE
, offset
);
5241 if (*td
->ip
== CEE_LEAVE
)
5247 case MONO_CUSTOM_PREFIX
:
5250 case CEE_MONO_RETHROW
:
5251 CHECK_STACK (td
, 1);
5252 SIMPLE_OP (td
, MINT_MONO_RETHROW
);
5256 case CEE_MONO_LD_DELEGATE_METHOD_PTR
:
5259 interp_add_ins (td
, MINT_LD_DELEGATE_METHOD_PTR
);
5260 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
5262 case CEE_MONO_CALLI_EXTRA_ARG
:
5263 /* Same as CEE_CALLI, except that we drop the extra arg required for llvm specific behaviour */
5264 interp_add_ins (td
, MINT_POP
);
5265 td
->last_ins
->data
[0] = 1;
5267 if (!interp_transform_call (td
, method
, NULL
, domain
, generic_context
, td
->is_bb_start
, NULL
, FALSE
, error
, FALSE
))
5270 case CEE_MONO_JIT_ICALL_ADDR
: {
5271 const guint32 token
= read32 (td
->ip
+ 1);
5273 const gconstpointer func
= mono_find_jit_icall_info ((MonoJitICallId
)token
)->func
;
5275 interp_add_ins (td
, MINT_LDFTN
);
5276 td
->last_ins
->data
[0] = get_data_item_index (td
, (gpointer
)func
);
5277 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
5280 case CEE_MONO_ICALL
: {
5281 MonoJitICallId
const jit_icall_id
= (MonoJitICallId
)read32 (td
->ip
+ 1);
5282 MonoJitICallInfo
const * const info
= mono_find_jit_icall_info (jit_icall_id
);
5285 CHECK_STACK (td
, info
->sig
->param_count
);
5286 if (!strcmp (info
->name
, "mono_threads_attach_coop")) {
5287 rtm
->needs_thread_attach
= 1;
5289 /* attach needs two arguments, and has one return value: leave one element on the stack */
5290 interp_add_ins (td
, MINT_POP
);
5291 td
->last_ins
->data
[0] = 0;
5292 } else if (!strcmp (info
->name
, "mono_threads_detach_coop")) {
5293 g_assert (rtm
->needs_thread_attach
);
5295 /* detach consumes two arguments, and no return value: drop both of them */
5296 interp_add_ins (td
, MINT_POP
);
5297 td
->last_ins
->data
[0] = 0;
5298 interp_add_ins (td
, MINT_POP
);
5299 td
->last_ins
->data
[0] = 0;
5301 int const icall_op
= interp_icall_op_for_sig (info
->sig
);
5302 g_assert (icall_op
!= -1);
5304 interp_add_ins (td
, icall_op
);
5305 // hash here is overkill
5306 td
->last_ins
->data
[0] = get_data_item_index (td
, (gpointer
)info
->func
);
5308 td
->sp
-= info
->sig
->param_count
;
5310 if (!MONO_TYPE_IS_VOID (info
->sig
->ret
)) {
5311 int mt
= mint_type (info
->sig
->ret
);
5312 PUSH_SIMPLE_TYPE(td
, stack_type
[mt
]);
5316 case CEE_MONO_VTADDR
: {
5318 CHECK_STACK (td
, 1);
5319 if (method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
5320 size
= mono_class_native_size(td
->sp
[-1].klass
, NULL
);
5322 size
= mono_class_value_size(td
->sp
[-1].klass
, NULL
);
5323 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5324 interp_add_ins (td
, MINT_VTRESULT
);
5325 td
->last_ins
->data
[0] = 0;
5326 WRITE32_INS (td
->last_ins
, 1, &size
);
5329 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
5332 case CEE_MONO_LDPTR
:
5333 case CEE_MONO_CLASSCONST
:
5334 token
= read32 (td
->ip
+ 1);
5336 interp_add_ins (td
, MINT_MONO_LDPTR
);
5337 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_method_get_wrapper_data (method
, token
));
5338 td
->sp
[0].type
= STACK_TYPE_I
;
5341 case CEE_MONO_OBJADDR
:
5342 CHECK_STACK (td
, 1);
5344 td
->sp
[-1].type
= STACK_TYPE_MP
;
5347 case CEE_MONO_NEWOBJ
:
5348 token
= read32 (td
->ip
+ 1);
5350 interp_add_ins (td
, MINT_MONO_NEWOBJ
);
5351 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_method_get_wrapper_data (method
, token
));
5352 td
->sp
[0].type
= STACK_TYPE_O
;
5355 case CEE_MONO_RETOBJ
:
5356 CHECK_STACK (td
, 1);
5357 token
= read32 (td
->ip
+ 1);
5359 interp_add_ins (td
, MINT_MONO_RETOBJ
);
5362 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
5364 /*stackval_from_data (signature->ret, frame->retval, sp->data.vt, signature->pinvoke);*/
5366 if (td
->sp
> td
->stack
)
5367 g_warning ("CEE_MONO_RETOBJ: more values on stack: %d", td
->sp
-td
->stack
);
5369 case CEE_MONO_LDNATIVEOBJ
:
5370 token
= read32 (td
->ip
+ 1);
5372 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
5373 g_assert(m_class_is_valuetype (klass
));
5374 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
5376 case CEE_MONO_TLS
: {
5377 gint32 key
= read32 (td
->ip
+ 1);
5379 g_assertf (key
== TLS_KEY_SGEN_THREAD_INFO
, "%d", key
);
5380 interp_add_ins (td
, MINT_MONO_SGEN_THREAD_INFO
);
5381 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_MP
);
5384 case CEE_MONO_ATOMIC_STORE_I4
:
5385 CHECK_STACK (td
, 2);
5386 SIMPLE_OP (td
, MINT_MONO_ATOMIC_STORE_I4
);
5390 case CEE_MONO_SAVE_LMF
:
5391 case CEE_MONO_RESTORE_LMF
:
5392 case CEE_MONO_NOT_TAKEN
:
5395 case CEE_MONO_LDPTR_INT_REQ_FLAG
:
5396 interp_add_ins (td
, MINT_MONO_LDPTR
);
5397 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_thread_interruption_request_flag ());
5398 PUSH_TYPE (td
, STACK_TYPE_MP
, NULL
);
5401 case CEE_MONO_MEMORY_BARRIER
:
5402 interp_add_ins (td
, MINT_MONO_MEMORY_BARRIER
);
5405 case CEE_MONO_LDDOMAIN
:
5406 interp_add_ins (td
, MINT_MONO_LDDOMAIN
);
5407 td
->sp
[0].type
= STACK_TYPE_I
;
5412 g_error ("transform.c: Unimplemented opcode: 0xF0 %02x at 0x%x\n", *td
->ip
, td
->ip
-header
->code
);
5422 case CEE_PREFIXREF
: ves_abort(); break;
5425 * Note: Exceptions thrown when executing a prefixed opcode need
5426 * to take into account the number of prefix bytes (usually the
5427 * throw point is just (ip - n_prefix_bytes).
5433 interp_add_ins (td
, MINT_ARGLIST
);
5434 PUSH_VT (td
, SIZEOF_VOID_P
);
5435 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_VT
);
5440 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
) {
5441 interp_add_ins (td
, MINT_CEQ_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
5443 if (td
->sp
[-1].type
== STACK_TYPE_R4
&& td
->sp
[-2].type
== STACK_TYPE_R8
)
5444 interp_add_ins (td
, MINT_CONV_R8_R4
);
5445 if (td
->sp
[-1].type
== STACK_TYPE_R8
&& td
->sp
[-2].type
== STACK_TYPE_R4
)
5446 interp_add_ins (td
, MINT_CONV_R8_R4_SP
);
5447 interp_add_ins (td
, MINT_CEQ_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
5450 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5455 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
)
5456 interp_add_ins (td
, MINT_CGT_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
5458 interp_add_ins (td
, MINT_CGT_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
5460 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5465 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
)
5466 interp_add_ins (td
, MINT_CGT_UN_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
5468 interp_add_ins (td
, MINT_CGT_UN_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
5470 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5475 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
)
5476 interp_add_ins (td
, MINT_CLT_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
5478 interp_add_ins (td
, MINT_CLT_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
5480 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5485 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
)
5486 interp_add_ins (td
, MINT_CLT_UN_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
5488 interp_add_ins (td
, MINT_CLT_UN_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
5490 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5493 case CEE_LDVIRTFTN
: /* fallthrough */
5496 if (*td
->ip
== CEE_LDVIRTFTN
) {
5497 CHECK_STACK (td
, 1);
5500 token
= read32 (td
->ip
+ 1);
5501 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
5502 m
= (MonoMethod
*)mono_method_get_wrapper_data (method
, token
);
5504 m
= mono_get_method_checked (image
, token
, NULL
, generic_context
, error
);
5505 goto_if_nok (error
, exit
);
5508 if (!mono_method_can_access_method (method
, m
))
5509 interp_generate_mae_throw (td
, method
, m
);
5511 if (method
->wrapper_type
== MONO_WRAPPER_NONE
&& m
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)
5512 m
= mono_marshal_get_synchronized_wrapper (m
);
5514 interp_add_ins (td
, *td
->ip
== CEE_LDFTN
? MINT_LDFTN
: MINT_LDVIRTFTN
);
5515 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
5516 goto_if_nok (error
, exit
);
5518 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_F
);
5522 int arg_n
= read16 (td
->ip
+ 1);
5523 if (td
->method
== method
)
5524 load_arg (td
, arg_n
);
5526 load_local_general (td
, arg_offsets
[arg_n
], get_arg_type (signature
, arg_n
));
5531 int n
= read16 (td
->ip
+ 1);
5533 if (td
->method
== method
) {
5534 get_arg_type_exact (td
, n
, &mt
);
5535 interp_add_ins (td
, mt
== MINT_TYPE_VT
? MINT_LDARGA_VT
: MINT_LDARGA
);
5536 td
->last_ins
->data
[0] = n
;
5538 interp_add_ins (td
, MINT_LDLOCA_S
);
5539 td
->last_ins
->data
[0] = arg_offsets
[n
];
5541 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
5546 int arg_n
= read16 (td
->ip
+ 1);
5547 if (td
->method
== method
)
5548 store_arg (td
, arg_n
);
5550 store_local_general (td
, arg_offsets
[arg_n
], get_arg_type (signature
, arg_n
));
5555 int loc_n
= read16 (td
->ip
+ 1);
5556 if (td
->method
== method
)
5557 load_local (td
, loc_n
);
5559 load_local_general (td
, local_offsets
[loc_n
], header
->locals
[loc_n
]);
5564 int loc_n
= read16 (td
->ip
+ 1);
5565 interp_add_ins (td
, MINT_LDLOCA_S
);
5566 if (td
->method
== method
)
5567 td
->last_ins
->data
[0] = td
->rtm
->local_offsets
[loc_n
];
5569 td
->last_ins
->data
[0] = local_offsets
[loc_n
];
5570 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
5575 int loc_n
= read16 (td
->ip
+ 1);
5576 if (td
->method
== method
)
5577 store_local (td
, loc_n
);
5579 store_local_general (td
, local_offsets
[loc_n
], header
->locals
[loc_n
]);
5585 CHECK_STACK (td
, 1);
5586 #if SIZEOF_VOID_P == 8
5587 if (td
->sp
[-1].type
== STACK_TYPE_I8
)
5588 interp_add_ins (td
, MINT_CONV_I4_I8
);
5590 interp_add_ins (td
, MINT_LOCALLOC
);
5591 if (td
->sp
!= td
->stack
+ 1)
5592 g_warning("CEE_LOCALLOC: stack not empty");
5594 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
5597 case CEE_UNUSED57
: ves_abort(); break;
5600 interp_add_ins (td
, MINT_ENDFILTER
);
5603 case CEE_UNALIGNED_
:
5612 /* FIX: should do something? */;
5613 // TODO: This should raise a method_tail_call profiler event.
5617 token
= read32 (td
->ip
+ 1);
5618 klass
= mini_get_class (method
, token
, generic_context
);
5619 CHECK_TYPELOAD (klass
);
5620 if (m_class_is_valuetype (klass
)) {
5621 interp_add_ins (td
, MINT_INITOBJ
);
5622 i32
= mono_class_value_size (klass
, NULL
);
5623 WRITE32_INS (td
->last_ins
, 0, &i32
);
5625 interp_add_ins (td
, MINT_LDNULL
);
5626 interp_add_ins (td
, MINT_STIND_REF
);
5633 /* FIX? convert length to I8? */
5635 interp_add_ins (td
, MINT_MONO_MEMORY_BARRIER
);
5636 interp_add_ins (td
, MINT_CPBLK
);
5637 BARRIER_IF_VOLATILE (td
);
5645 case CEE_CONSTRAINED_
:
5646 token
= read32 (td
->ip
+ 1);
5647 constrained_class
= mini_get_class (method
, token
, generic_context
);
5648 CHECK_TYPELOAD (constrained_class
);
5653 BARRIER_IF_VOLATILE (td
);
5654 interp_add_ins (td
, MINT_INITBLK
);
5659 /* FIXME: implement */
5663 int clause_index
= td
->clause_indexes
[in_offset
];
5664 g_assert (clause_index
!= -1);
5665 SIMPLE_OP (td
, MINT_RETHROW
);
5666 td
->last_ins
->data
[0] = rtm
->exvar_offsets
[clause_index
];
5672 token
= read32 (td
->ip
+ 1);
5674 if (mono_metadata_token_table (token
) == MONO_TABLE_TYPESPEC
&& !image_is_dynamic (m_class_get_image (method
->klass
)) && !generic_context
) {
5676 MonoType
*type
= mono_type_create_from_typespec_checked (image
, token
, error
);
5677 goto_if_nok (error
, exit
);
5678 size
= mono_type_size (type
, &align
);
5681 MonoClass
*szclass
= mini_get_class (method
, token
, generic_context
);
5682 CHECK_TYPELOAD (szclass
);
5684 if (!szclass
->valuetype
)
5685 THROW_EX (mono_exception_from_name (mono_defaults
.corlib
, "System", "InvalidProgramException"), ip
- 5);
5687 size
= mono_type_size (m_class_get_byval_arg (szclass
), &align
);
5689 interp_add_ins (td
, MINT_LDC_I4
);
5690 WRITE32_INS (td
->last_ins
, 0, &size
);
5691 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
5694 case CEE_REFANYTYPE
:
5695 interp_add_ins (td
, MINT_REFANYTYPE
);
5697 POP_VT (td
, sizeof (MonoTypedRef
));
5698 PUSH_VT (td
, sizeof (gpointer
));
5699 SET_TYPE(td
->sp
- 1, STACK_TYPE_VT
, NULL
);
5702 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
);
5706 g_error ("transform.c: Unimplemented opcode: %02x at 0x%x\n", *td
->ip
, td
->ip
-header
->code
);
5709 // No IR instructions were added as part of the IL instruction. Extend bb_start
5710 if (prev_last_ins
== td
->last_ins
&& td
->is_bb_start
[in_offset
] && td
->ip
< end
)
5711 td
->is_bb_start
[td
->ip
- td
->il_code
] = 1;
5714 g_assert (td
->ip
== end
);
5717 g_free (arg_offsets
);
5718 g_free (local_offsets
);
5719 mono_basic_block_free (original_bb
);
5720 for (i
= 0; i
< header
->code_size
; ++i
)
5721 g_free (td
->stack_state
[i
]);
5722 g_free (td
->stack_state
);
5723 g_free (td
->stack_height
);
5724 g_free (td
->vt_stack_size
);
5725 g_free (td
->clause_indexes
);
5726 g_free (td
->is_bb_start
);
5734 // We are trying to branch to an il offset that has no associated ir instruction with it.
5735 // We will branch instead to the next instruction that we find
5737 resolve_in_offset (TransformData
*td
, int il_offset
)
5740 g_assert (!td
->in_offsets
[il_offset
]);
5741 while (!td
->in_offsets
[i
])
5743 td
->in_offsets
[il_offset
] = td
->in_offsets
[i
];
5744 return td
->in_offsets
[il_offset
];
5747 // We store in the in_offset array the native_offset + 1, so 0 can mean only that the il
5748 // offset is uninitialized. Otherwise 0 is valid value for first interp instruction.
5750 get_in_offset (TransformData
*td
, int il_offset
)
5752 int target_offset
= td
->in_offsets
[il_offset
];
5754 return target_offset
- 1;
5755 return resolve_in_offset (td
, il_offset
) - 1;
5759 handle_relocations (TransformData
*td
)
5761 // Handle relocations
5762 for (int i
= 0; i
< td
->relocs
->len
; ++i
) {
5763 Reloc
*reloc
= (Reloc
*)g_ptr_array_index (td
->relocs
, i
);
5764 int offset
= get_in_offset (td
, reloc
->target
) - reloc
->offset
;
5766 switch (reloc
->type
) {
5767 case RELOC_SHORT_BRANCH
:
5768 g_assert (td
->new_code
[reloc
->offset
+ 1] == 0xdead);
5769 td
->new_code
[reloc
->offset
+ 1] = offset
;
5771 case RELOC_LONG_BRANCH
: {
5772 guint16
*v
= (guint16
*) &offset
;
5773 g_assert (td
->new_code
[reloc
->offset
+ 1] == 0xdead);
5774 g_assert (td
->new_code
[reloc
->offset
+ 2] == 0xbeef);
5775 td
->new_code
[reloc
->offset
+ 1] = *(guint16
*) v
;
5776 td
->new_code
[reloc
->offset
+ 2] = *(guint16
*) (v
+ 1);
5779 case RELOC_SWITCH
: {
5780 guint16
*v
= (guint16
*)&offset
;
5781 g_assert (td
->new_code
[reloc
->offset
] == 0xdead);
5782 g_assert (td
->new_code
[reloc
->offset
+ 1] == 0xbeef);
5783 td
->new_code
[reloc
->offset
] = *(guint16
*)v
;
5784 td
->new_code
[reloc
->offset
+ 1] = *(guint16
*)(v
+ 1);
5788 g_assert_not_reached ();
5796 get_inst_length (InterpInst
*ins
)
5798 if (ins
->opcode
== MINT_SWITCH
)
5799 return MINT_SWITCH_LEN (READ32 (&ins
->data
[0]));
5801 return mono_interp_oplen
[ins
->opcode
];
5805 emit_compacted_instruction (TransformData
*td
, guint16
* start_ip
, InterpInst
*ins
)
5807 guint16 opcode
= ins
->opcode
;
5808 guint16
*ip
= start_ip
;
5810 // We know what IL offset this instruction was created for. We can now map the IL offset
5811 // to the IR offset. We use this array to resolve the relocations, which reference the IL.
5812 if (ins
->il_offset
!= -1 && !td
->in_offsets
[ins
->il_offset
]) {
5813 g_assert (ins
->il_offset
>= 0 && ins
->il_offset
< td
->header
->code_size
);
5814 td
->in_offsets
[ins
->il_offset
] = start_ip
- td
->new_code
+ 1;
5816 MonoDebugLineNumberEntry lne
;
5817 lne
.native_offset
= (guint8
*)start_ip
- (guint8
*)td
->new_code
;
5818 lne
.il_offset
= ins
->il_offset
;
5819 g_array_append_val (td
->line_numbers
, lne
);
5823 if (opcode
== MINT_SWITCH
) {
5824 int labels
= READ32 (&ins
->data
[0]);
5825 // Write number of switch labels
5826 *ip
++ = ins
->data
[0];
5827 *ip
++ = ins
->data
[1];
5828 // Add relocation for each label
5829 for (int i
= 0; i
< labels
; i
++) {
5830 Reloc
*reloc
= (Reloc
*)mono_mempool_alloc0 (td
->mempool
, sizeof (Reloc
));
5831 reloc
->type
= RELOC_SWITCH
;
5832 reloc
->offset
= ip
- td
->new_code
;
5833 reloc
->target
= READ32 (&ins
->data
[2 + i
* 2]);
5834 g_ptr_array_add (td
->relocs
, reloc
);
5838 } else if ((opcode
>= MINT_BRFALSE_I4_S
&& opcode
<= MINT_BRTRUE_R8_S
) ||
5839 (opcode
>= MINT_BEQ_I4_S
&& opcode
<= MINT_BLT_UN_R8_S
) ||
5840 opcode
== MINT_BR_S
|| opcode
== MINT_LEAVE_S
|| opcode
== MINT_LEAVE_S_CHECK
) {
5841 const int br_offset
= start_ip
- td
->new_code
;
5842 if (ins
->data
[0] < ins
->il_offset
) {
5843 // Backwards branch. We can already patch it.
5844 *ip
++ = get_in_offset (td
, ins
->data
[0]) - br_offset
;
5846 // We don't know the in_offset of the target, add a reloc
5847 Reloc
*reloc
= (Reloc
*)mono_mempool_alloc0 (td
->mempool
, sizeof (Reloc
));
5848 reloc
->type
= RELOC_SHORT_BRANCH
;
5849 reloc
->offset
= br_offset
;
5850 reloc
->target
= ins
->data
[0];
5851 g_ptr_array_add (td
->relocs
, reloc
);
5854 } else if ((opcode
>= MINT_BRFALSE_I4
&& opcode
<= MINT_BRTRUE_R8
) ||
5855 (opcode
>= MINT_BEQ_I4
&& opcode
<= MINT_BLT_UN_R8
) ||
5856 opcode
== MINT_BR
|| opcode
== MINT_LEAVE
|| opcode
== MINT_LEAVE_CHECK
) {
5857 const int br_offset
= start_ip
- td
->new_code
;
5858 int target_il
= READ32 (&ins
->data
[0]);
5859 if (target_il
< ins
->il_offset
) {
5860 // Backwards branch. We can already patch it
5861 const int br_offset
= start_ip
- td
->new_code
;
5862 int target_offset
= get_in_offset (td
, target_il
) - br_offset
;
5863 WRITE32 (ip
, &target_offset
);
5865 Reloc
*reloc
= (Reloc
*)mono_mempool_alloc0 (td
->mempool
, sizeof (Reloc
));
5866 reloc
->type
= RELOC_LONG_BRANCH
;
5867 reloc
->offset
= br_offset
;
5868 reloc
->target
= target_il
;
5869 g_ptr_array_add (td
->relocs
, reloc
);
5873 } else if (opcode
== MINT_SDB_SEQ_POINT
) {
5874 SeqPoint
*seqp
= (SeqPoint
*)mono_mempool_alloc0 (td
->mempool
, sizeof (SeqPoint
));
5875 InterpBasicBlock
*cbb
;
5877 if (ins
->flags
& INTERP_INST_FLAG_SEQ_POINT_METHOD_ENTRY
) {
5878 seqp
->il_offset
= METHOD_ENTRY_IL_OFFSET
;
5879 cbb
= td
->offset_to_bb
[0];
5881 if (ins
->flags
& INTERP_INST_FLAG_SEQ_POINT_METHOD_EXIT
)
5882 seqp
->il_offset
= METHOD_EXIT_IL_OFFSET
;
5884 seqp
->il_offset
= ins
->il_offset
;
5885 cbb
= td
->offset_to_bb
[ins
->il_offset
];
5887 seqp
->native_offset
= (guint8
*)start_ip
- (guint8
*)td
->new_code
;
5888 if (ins
->flags
& INTERP_INST_FLAG_SEQ_POINT_NONEMPTY_STACK
)
5889 seqp
->flags
|= MONO_SEQ_POINT_FLAG_NONEMPTY_STACK
;
5890 if (ins
->flags
& INTERP_INST_FLAG_SEQ_POINT_NESTED_CALL
)
5891 seqp
->flags
|= MONO_SEQ_POINT_FLAG_NESTED_CALL
;
5892 g_ptr_array_add (td
->seq_points
, seqp
);
5894 cbb
->seq_points
= g_slist_prepend_mempool (td
->mempool
, cbb
->seq_points
, seqp
);
5895 cbb
->last_seq_point
= seqp
;
5897 int size
= get_inst_length (ins
) - 1;
5898 // Emit the rest of the data
5899 for (int i
= 0; i
< size
; i
++)
5900 *ip
++ = ins
->data
[i
];
5905 // Generates the final code, after we are done with all the passes
5907 generate_compacted_code (TransformData
*td
)
5911 td
->relocs
= g_ptr_array_new ();
5913 // Iterate once to compute the exact size of the compacted code
5914 InterpInst
*ins
= td
->first_ins
;
5916 size
+= get_inst_length (ins
);
5920 // Generate the compacted stream of instructions
5921 td
->new_code
= ip
= (guint16
*)mono_domain_alloc0 (td
->rtm
->domain
, size
* sizeof (guint16
));
5922 ins
= td
->first_ins
;
5924 ip
= emit_compacted_instruction (td
, ip
, ins
);
5927 td
->new_code_end
= ip
;
5928 td
->in_offsets
[td
->header
->code_size
] = td
->new_code_end
- td
->new_code
;
5930 // Patch all branches
5931 handle_relocations (td
);
5933 g_ptr_array_free (td
->relocs
, TRUE
);
5937 generate (MonoMethod
*method
, MonoMethodHeader
*header
, InterpMethod
*rtm
, MonoGenericContext
*generic_context
, MonoError
*error
)
5939 MonoDomain
*domain
= rtm
->domain
;
5941 TransformData transform_data
;
5943 static gboolean verbose_method_inited
;
5944 static char* verbose_method_name
;
5946 if (!verbose_method_inited
) {
5947 verbose_method_name
= g_getenv ("MONO_VERBOSE_METHOD");
5948 verbose_method_inited
= TRUE
;
5951 memset (&transform_data
, 0, sizeof(transform_data
));
5952 td
= &transform_data
;
5954 td
->method
= method
;
5956 td
->code_size
= header
->code_size
;
5957 td
->header
= header
;
5958 td
->max_code_size
= td
->code_size
;
5959 td
->in_offsets
= (int*)g_malloc0((header
->code_size
+ 1) * sizeof(int));
5960 td
->mempool
= mono_mempool_new ();
5961 td
->n_data_items
= 0;
5962 td
->max_data_items
= 0;
5963 td
->data_items
= NULL
;
5964 td
->data_hash
= g_hash_table_new (NULL
, NULL
);
5965 td
->gen_sdb_seq_points
= mini_debug_options
.gen_sdb_seq_points
;
5966 td
->seq_points
= g_ptr_array_new ();
5967 td
->verbose_level
= mono_interp_traceopt
;
5968 td
->total_locals_size
= rtm
->locals_size
;
5969 rtm
->data_items
= td
->data_items
;
5971 if (verbose_method_name
) {
5972 const char *name
= verbose_method_name
;
5974 if ((strchr (name
, '.') > name
) || strchr (name
, ':')) {
5975 MonoMethodDesc
*desc
;
5977 desc
= mono_method_desc_new (name
, TRUE
);
5978 if (mono_method_desc_full_match (desc
, method
)) {
5979 td
->verbose_level
= 4;
5981 mono_method_desc_free (desc
);
5983 if (strcmp (method
->name
, name
) == 0)
5984 td
->verbose_level
= 4;
5988 td
->stack
= (StackInfo
*)g_malloc0 ((header
->max_stack
+ 1) * sizeof (td
->stack
[0]));
5989 td
->stack_capacity
= header
->max_stack
+ 1;
5991 td
->max_stack_height
= 0;
5992 td
->line_numbers
= g_array_new (FALSE
, TRUE
, sizeof (MonoDebugLineNumberEntry
));
5994 generate_code (td
, method
, header
, generic_context
, error
);
5995 goto_if_nok (error
, exit
);
5997 generate_compacted_code (td
);
5999 if (td
->verbose_level
) {
6000 g_print ("Runtime method: %s %p, VT stack size: %d\n", mono_method_full_name (method
, TRUE
), rtm
, td
->max_vt_sp
);
6001 g_print ("Calculated stack size: %d, stated size: %d\n", td
->max_stack_height
, header
->max_stack
);
6002 dump_mint_code (td
->new_code
, td
->new_code_end
);
6005 /* Check if we use excessive stack space */
6006 if (td
->max_stack_height
> header
->max_stack
* 3 && header
->max_stack
> 16)
6007 g_warning ("Excessive stack space usage for method %s, %d/%d", method
->name
, td
->max_stack_height
, header
->max_stack
);
6010 code_len
= td
->new_code_end
- td
->new_code
;
6012 rtm
->clauses
= (MonoExceptionClause
*)mono_domain_alloc0 (domain
, header
->num_clauses
* sizeof (MonoExceptionClause
));
6013 memcpy (rtm
->clauses
, header
->clauses
, header
->num_clauses
* sizeof(MonoExceptionClause
));
6014 rtm
->code
= (gushort
*)td
->new_code
;
6015 rtm
->init_locals
= header
->init_locals
;
6016 rtm
->num_clauses
= header
->num_clauses
;
6017 for (i
= 0; i
< header
->num_clauses
; i
++) {
6018 MonoExceptionClause
*c
= rtm
->clauses
+ i
;
6019 int end_off
= c
->try_offset
+ c
->try_len
;
6020 c
->try_offset
= get_in_offset (td
, c
->try_offset
);
6021 c
->try_len
= get_in_offset (td
, end_off
) - c
->try_offset
;
6022 g_assert ((c
->try_offset
+ c
->try_len
) < code_len
);
6023 end_off
= c
->handler_offset
+ c
->handler_len
;
6024 c
->handler_offset
= get_in_offset (td
, c
->handler_offset
);
6025 c
->handler_len
= get_in_offset (td
, end_off
) - c
->handler_offset
;
6026 g_assert (c
->handler_len
>= 0 && (c
->handler_offset
+ c
->handler_len
) <= code_len
);
6027 if (c
->flags
& MONO_EXCEPTION_CLAUSE_FILTER
)
6028 c
->data
.filter_offset
= get_in_offset (td
, c
->data
.filter_offset
);
6030 rtm
->stack_size
= (sizeof (stackval
)) * (td
->max_stack_height
+ 2); /* + 1 for returns of called functions + 1 for 0-ing in trace*/
6031 rtm
->stack_size
= ALIGN_TO (rtm
->stack_size
, MINT_VT_ALIGNMENT
);
6032 rtm
->vt_stack_size
= td
->max_vt_sp
;
6033 rtm
->total_locals_size
= td
->total_locals_size
;
6034 rtm
->alloca_size
= rtm
->total_locals_size
+ rtm
->vt_stack_size
+ rtm
->stack_size
;
6035 rtm
->data_items
= (gpointer
*)mono_domain_alloc0 (domain
, td
->n_data_items
* sizeof (td
->data_items
[0]));
6036 memcpy (rtm
->data_items
, td
->data_items
, td
->n_data_items
* sizeof (td
->data_items
[0]));
6038 /* Save debug info */
6039 interp_save_debug_info (rtm
, header
, td
, td
->line_numbers
);
6041 /* Create a MonoJitInfo for the interpreted method by creating the interpreter IR as the native code. */
6043 jinfo_len
= mono_jit_info_size ((MonoJitInfoFlags
)0, header
->num_clauses
, 0);
6045 jinfo
= (MonoJitInfo
*)mono_domain_alloc0 (domain
, jinfo_len
);
6046 jinfo
->is_interp
= 1;
6048 mono_jit_info_init (jinfo
, method
, (guint8
*)rtm
->code
, code_len
, (MonoJitInfoFlags
)0, header
->num_clauses
, 0);
6049 for (i
= 0; i
< jinfo
->num_clauses
; ++i
) {
6050 MonoJitExceptionInfo
*ei
= &jinfo
->clauses
[i
];
6051 MonoExceptionClause
*c
= rtm
->clauses
+ i
;
6053 ei
->flags
= c
->flags
;
6054 ei
->try_start
= (guint8
*)(rtm
->code
+ c
->try_offset
);
6055 ei
->try_end
= (guint8
*)(rtm
->code
+ c
->try_offset
+ c
->try_len
);
6056 ei
->handler_start
= (guint8
*)(rtm
->code
+ c
->handler_offset
);
6057 ei
->exvar_offset
= rtm
->exvar_offsets
[i
];
6058 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
6059 ei
->data
.filter
= (guint8
*)(rtm
->code
+ c
->data
.filter_offset
);
6060 } else if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
6061 ei
->data
.handler_end
= (guint8
*)(rtm
->code
+ c
->handler_offset
+ c
->handler_len
);
6063 ei
->data
.catch_class
= c
->data
.catch_class
;
6067 save_seq_points (td
, jinfo
);
6070 g_free (td
->in_offsets
);
6071 g_free (td
->data_items
);
6073 g_hash_table_destroy (td
->data_hash
);
6074 g_ptr_array_free (td
->seq_points
, TRUE
);
6075 g_array_free (td
->line_numbers
, TRUE
);
6076 mono_mempool_destroy (td
->mempool
);
6079 static mono_mutex_t calc_section
;
6082 mono_interp_transform_init (void)
6084 mono_os_mutex_init_recursive(&calc_section
);
6088 mono_interp_transform_method (InterpMethod
*imethod
, ThreadContext
*context
, MonoError
*error
)
6090 MonoMethod
*method
= imethod
->method
;
6091 MonoMethodHeader
*header
= NULL
;
6092 MonoMethodSignature
*signature
= mono_method_signature_internal (method
);
6093 MonoVTable
*method_class_vt
;
6094 MonoGenericContext
*generic_context
= NULL
;
6095 MonoDomain
*domain
= imethod
->domain
;
6096 InterpMethod tmp_imethod
;
6097 InterpMethod
*real_imethod
;
6101 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (method
->klass
))) {
6102 mono_error_set_invalid_operation (error
, "%s", "Could not execute the method because the containing type is not fully instantiated.");
6106 // g_printerr ("TRANSFORM(0x%016lx): begin %s::%s\n", mono_thread_current (), method->klass->name, method->name);
6107 method_class_vt
= mono_class_vtable_checked (domain
, imethod
->method
->klass
, error
);
6108 return_if_nok (error
);
6110 if (!method_class_vt
->initialized
) {
6111 mono_runtime_class_init_full (method_class_vt
, error
);
6112 return_if_nok (error
);
6115 MONO_PROFILER_RAISE (jit_begin
, (method
));
6117 if (mono_method_signature_internal (method
)->is_inflated
)
6118 generic_context
= mono_method_get_context (method
);
6120 MonoGenericContainer
*generic_container
= mono_method_get_generic_container (method
);
6121 if (generic_container
)
6122 generic_context
= &generic_container
->context
;
6125 if (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)) {
6126 MonoMethod
*nm
= NULL
;
6127 if (imethod
->transformed
) {
6128 MONO_PROFILER_RAISE (jit_done
, (method
, imethod
->jinfo
));
6132 /* assumes all internal calls with an array this are built in... */
6133 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
&& (! mono_method_signature_internal (method
)->hasthis
|| m_class_get_rank (method
->klass
) == 0)) {
6134 nm
= mono_marshal_get_native_wrapper (method
, FALSE
, FALSE
);
6135 signature
= mono_method_signature_internal (nm
);
6137 const char *name
= method
->name
;
6138 if (m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) {
6139 if (*name
== '.' && (strcmp (name
, ".ctor") == 0)) {
6140 MonoJitICallInfo
*mi
= &mono_get_jit_icall_info ()->ves_icall_mono_delegate_ctor_interp
;
6141 nm
= mono_marshal_get_icall_wrapper (mi
, TRUE
);
6142 } else if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
6144 * Usually handled during transformation of the caller, but
6145 * when the caller is handled by another execution engine
6146 * (for example fullAOT) we need to handle it here. That's
6147 * known to be wrong in cases where the reference to
6148 * `MonoDelegate` would be needed (FIXME).
6150 nm
= mono_marshal_get_delegate_invoke (method
, NULL
);
6151 } else if (*name
== 'B' && (strcmp (name
, "BeginInvoke") == 0)) {
6152 nm
= mono_marshal_get_delegate_begin_invoke (method
);
6153 } else if (*name
== 'E' && (strcmp (name
, "EndInvoke") == 0)) {
6154 nm
= mono_marshal_get_delegate_end_invoke (method
);
6158 g_assert_not_reached ();
6161 mono_os_mutex_lock (&calc_section
);
6162 imethod
->stack_size
= sizeof (stackval
); /* for tracing */
6163 imethod
->alloca_size
= imethod
->stack_size
;
6164 mono_memory_barrier ();
6165 imethod
->transformed
= TRUE
;
6166 mono_os_mutex_unlock (&calc_section
);
6167 MONO_PROFILER_RAISE (jit_done
, (method
, NULL
));
6171 header
= interp_method_get_header (nm
, error
);
6172 return_if_nok (error
);
6176 header
= mono_method_get_header_checked (method
, error
);
6177 return_if_nok (error
);
6180 g_assert ((signature
->param_count
+ signature
->hasthis
) < 1000);
6181 // g_printerr ("TRANSFORM(0x%016lx): end %s::%s\n", mono_thread_current (), method->klass->name, method->name);
6183 /* Make modifications to a copy of imethod, copy them back inside the lock */
6184 real_imethod
= imethod
;
6185 memcpy (&tmp_imethod
, imethod
, sizeof (InterpMethod
));
6186 imethod
= &tmp_imethod
;
6188 interp_method_compute_offsets (imethod
, signature
, header
);
6190 MONO_TIME_TRACK (mono_interp_stats
.transform_time
, generate (method
, header
, imethod
, generic_context
, error
));
6192 mono_metadata_free_mh (header
);
6194 return_if_nok (error
);
6196 /* Copy changes back */
6197 imethod
= real_imethod
;
6198 mono_os_mutex_lock (&calc_section
);
6199 if (!imethod
->transformed
) {
6200 // Ignore the first two fields which are unchanged. next_jit_code_hash shouldn't
6201 // be modified because it is racy with internal hash table insert.
6202 const int start_offset
= 2 * sizeof (gpointer
);
6203 memcpy ((char*)imethod
+ start_offset
, (char*)&tmp_imethod
+ start_offset
, sizeof (InterpMethod
) - start_offset
);
6204 mono_memory_barrier ();
6205 imethod
->transformed
= TRUE
;
6206 mono_atomic_fetch_add_i32 (&mono_jit_stats
.methods_with_interp
, 1);
6209 mono_os_mutex_unlock (&calc_section
);
6211 mono_domain_lock (domain
);
6212 if (!g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, imethod
->method
))
6213 g_hash_table_insert (domain_jit_info (domain
)->seq_points
, imethod
->method
, imethod
->jinfo
->seq_points
);
6214 mono_domain_unlock (domain
);
6216 // FIXME: Add a different callback ?
6217 MONO_PROFILER_RAISE (jit_done
, (method
, imethod
->jinfo
));