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 int current_il_offset
;
100 StackInfo
**stack_state
;
103 unsigned char *is_bb_start
;
104 unsigned short *new_code
;
105 unsigned short *new_code_end
;
106 unsigned int max_code_size
;
109 unsigned int max_stack_height
;
110 unsigned int stack_capacity
;
112 unsigned int max_vt_sp
;
113 unsigned int total_locals_size
;
117 GHashTable
*data_hash
;
119 gboolean gen_sdb_seq_points
;
120 GPtrArray
*seq_points
;
121 InterpBasicBlock
**offset_to_bb
;
122 InterpBasicBlock
*entry_bb
;
123 MonoMemPool
*mempool
;
126 gboolean verbose_level
;
127 GArray
*line_numbers
;
130 #define STACK_TYPE_I4 0
131 #define STACK_TYPE_I8 1
132 #define STACK_TYPE_R4 2
133 #define STACK_TYPE_R8 3
134 #define STACK_TYPE_O 4
135 #define STACK_TYPE_VT 5
136 #define STACK_TYPE_MP 6
137 #define STACK_TYPE_F 7
139 static const char *stack_type_string
[] = { "I4", "I8", "R4", "R8", "O ", "VT", "MP", "F " };
141 #if SIZEOF_VOID_P == 8
142 #define STACK_TYPE_I STACK_TYPE_I8
144 #define STACK_TYPE_I STACK_TYPE_I4
147 static int stack_type
[] = {
148 STACK_TYPE_I4
, /*I1*/
149 STACK_TYPE_I4
, /*U1*/
150 STACK_TYPE_I4
, /*I2*/
151 STACK_TYPE_I4
, /*U2*/
152 STACK_TYPE_I4
, /*I4*/
153 STACK_TYPE_I8
, /*I8*/
154 STACK_TYPE_R4
, /*R4*/
155 STACK_TYPE_R8
, /*R8*/
161 #if SIZEOF_VOID_P == 8
162 #define MINT_NEG_P MINT_NEG_I8
163 #define MINT_NOT_P MINT_NOT_I8
165 #define MINT_NEG_FP MINT_NEG_R8
167 #define MINT_ADD_P MINT_ADD_I8
168 #define MINT_SUB_P MINT_SUB_I8
169 #define MINT_MUL_P MINT_MUL_I8
170 #define MINT_DIV_P MINT_DIV_I8
171 #define MINT_DIV_UN_P MINT_DIV_UN_I8
172 #define MINT_REM_P MINT_REM_I8
173 #define MINT_REM_UN_P MINT_REM_UN_I8
174 #define MINT_AND_P MINT_AND_I8
175 #define MINT_OR_P MINT_OR_I8
176 #define MINT_XOR_P MINT_XOR_I8
177 #define MINT_SHL_P MINT_SHL_I8
178 #define MINT_SHR_P MINT_SHR_I8
179 #define MINT_SHR_UN_P MINT_SHR_UN_I8
181 #define MINT_CEQ_P MINT_CEQ_I8
182 #define MINT_CNE_P MINT_CNE_I8
183 #define MINT_CLT_P MINT_CLT_I8
184 #define MINT_CLT_UN_P MINT_CLT_UN_I8
185 #define MINT_CGT_P MINT_CGT_I8
186 #define MINT_CGT_UN_P MINT_CGT_UN_I8
187 #define MINT_CLE_P MINT_CLE_I8
188 #define MINT_CLE_UN_P MINT_CLE_UN_I8
189 #define MINT_CGE_P MINT_CGE_I8
190 #define MINT_CGE_UN_P MINT_CGE_UN_I8
192 #define MINT_ADD_FP MINT_ADD_R8
193 #define MINT_SUB_FP MINT_SUB_R8
194 #define MINT_MUL_FP MINT_MUL_R8
195 #define MINT_DIV_FP MINT_DIV_R8
196 #define MINT_REM_FP MINT_REM_R8
198 #define MINT_CNE_FP MINT_CNE_R8
199 #define MINT_CEQ_FP MINT_CEQ_R8
200 #define MINT_CGT_FP MINT_CGT_R8
201 #define MINT_CGE_FP MINT_CGE_R8
202 #define MINT_CLT_FP MINT_CLT_R8
203 #define MINT_CLE_FP MINT_CLE_R8
205 #define MINT_CONV_OVF_U4_P MINT_CONV_OVF_U4_I8
208 #define MINT_NEG_P MINT_NEG_I4
209 #define MINT_NOT_P MINT_NOT_I4
211 #define MINT_NEG_FP MINT_NEG_R4
213 #define MINT_ADD_P MINT_ADD_I4
214 #define MINT_SUB_P MINT_SUB_I4
215 #define MINT_MUL_P MINT_MUL_I4
216 #define MINT_DIV_P MINT_DIV_I4
217 #define MINT_DIV_UN_P MINT_DIV_UN_I4
218 #define MINT_REM_P MINT_REM_I4
219 #define MINT_REM_UN_P MINT_REM_UN_I4
220 #define MINT_AND_P MINT_AND_I4
221 #define MINT_OR_P MINT_OR_I4
222 #define MINT_XOR_P MINT_XOR_I4
223 #define MINT_SHL_P MINT_SHL_I4
224 #define MINT_SHR_P MINT_SHR_I4
225 #define MINT_SHR_UN_P MINT_SHR_UN_I4
227 #define MINT_CEQ_P MINT_CEQ_I4
228 #define MINT_CNE_P MINT_CNE_I4
229 #define MINT_CLT_P MINT_CLT_I4
230 #define MINT_CLT_UN_P MINT_CLT_UN_I4
231 #define MINT_CGT_P MINT_CGT_I4
232 #define MINT_CGT_UN_P MINT_CGT_UN_I4
233 #define MINT_CLE_P MINT_CLE_I4
234 #define MINT_CLE_UN_P MINT_CLE_UN_I4
235 #define MINT_CGE_P MINT_CGE_I4
236 #define MINT_CGE_UN_P MINT_CGE_UN_I4
238 #define MINT_ADD_FP MINT_ADD_R4
239 #define MINT_SUB_FP MINT_SUB_R4
240 #define MINT_MUL_FP MINT_MUL_R4
241 #define MINT_DIV_FP MINT_DIV_R4
242 #define MINT_REM_FP MINT_REM_R4
244 #define MINT_CNE_FP MINT_CNE_R4
245 #define MINT_CEQ_FP MINT_CEQ_R4
246 #define MINT_CGT_FP MINT_CGT_R4
247 #define MINT_CGE_FP MINT_CGE_R4
248 #define MINT_CLT_FP MINT_CLT_R4
249 #define MINT_CLE_FP MINT_CLE_R4
251 #define MINT_CONV_OVF_U4_P MINT_CONV_OVF_U4_I4
255 const gchar
*op_name
;
259 // static const MagicIntrinsic int_binop[] = {
261 static const MagicIntrinsic int_unnop
[] = {
262 { "op_UnaryPlus", {MINT_NOP
, MINT_NOP
, MINT_NOP
}},
263 { "op_UnaryNegation", {MINT_NEG_P
, MINT_NEG_P
, MINT_NEG_FP
}},
264 { "op_OnesComplement", {MINT_NOT_P
, MINT_NOT_P
, MINT_NIY
}}
267 static const MagicIntrinsic int_binop
[] = {
268 { "op_Addition", {MINT_ADD_P
, MINT_ADD_P
, MINT_ADD_FP
}},
269 { "op_Subtraction", {MINT_SUB_P
, MINT_SUB_P
, MINT_SUB_FP
}},
270 { "op_Multiply", {MINT_MUL_P
, MINT_MUL_P
, MINT_MUL_FP
}},
271 { "op_Division", {MINT_DIV_P
, MINT_DIV_UN_P
, MINT_DIV_FP
}},
272 { "op_Modulus", {MINT_REM_P
, MINT_REM_UN_P
, MINT_REM_FP
}},
273 { "op_BitwiseAnd", {MINT_AND_P
, MINT_AND_P
, MINT_NIY
}},
274 { "op_BitwiseOr", {MINT_OR_P
, MINT_OR_P
, MINT_NIY
}},
275 { "op_ExclusiveOr", {MINT_XOR_P
, MINT_XOR_P
, MINT_NIY
}},
276 { "op_LeftShift", {MINT_SHL_P
, MINT_SHL_P
, MINT_NIY
}},
277 { "op_RightShift", {MINT_SHR_P
, MINT_SHR_UN_P
, MINT_NIY
}},
280 static const MagicIntrinsic int_cmpop
[] = {
281 { "op_Inequality", {MINT_CNE_P
, MINT_CNE_P
, MINT_CNE_FP
}},
282 { "op_Equality", {MINT_CEQ_P
, MINT_CEQ_P
, MINT_CEQ_FP
}},
283 { "op_GreaterThan", {MINT_CGT_P
, MINT_CGT_UN_P
, MINT_CGT_FP
}},
284 { "op_GreaterThanOrEqual", {MINT_CGE_P
, MINT_CGE_UN_P
, MINT_CGE_FP
}},
285 { "op_LessThan", {MINT_CLT_P
, MINT_CLT_UN_P
, MINT_CLT_FP
}},
286 { "op_LessThanOrEqual", {MINT_CLE_P
, MINT_CLE_UN_P
, MINT_CLE_FP
}}
289 static gboolean
generate_code (TransformData
*td
, MonoMethod
*method
, MonoMethodHeader
*header
, MonoGenericContext
*generic_context
, MonoError
*error
);
292 interp_new_ins (TransformData
*td
, guint16 opcode
, int len
)
294 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
> 0) ? (len
- 1) : 0));
297 new_inst
->opcode
= opcode
;
298 new_inst
->il_offset
= td
->current_il_offset
;
302 // This version need to be used with switch opcode, which doesn't have constant length
304 interp_add_ins_explicit (TransformData
*td
, guint16 opcode
, int len
)
306 InterpInst
*new_inst
= interp_new_ins (td
, opcode
, len
);
307 new_inst
->prev
= td
->last_ins
;
309 td
->last_ins
->next
= new_inst
;
311 td
->first_ins
= new_inst
;
312 td
->last_ins
= new_inst
;
317 interp_add_ins (TransformData
*td
, guint16 opcode
)
319 return interp_add_ins_explicit (td
, opcode
, mono_interp_oplen
[opcode
]);
322 // This instruction will have the il_offset of the previous instruction
324 interp_insert_ins (TransformData
*td
, InterpInst
*prev_ins
, guint16 opcode
)
326 InterpInst
*new_inst
= interp_new_ins (td
, opcode
, mono_interp_oplen
[opcode
]);
328 new_inst
->il_offset
= prev_ins
->il_offset
;
330 new_inst
->prev
= prev_ins
;
331 new_inst
->next
= prev_ins
->next
;
332 prev_ins
->next
= new_inst
;
334 if (new_inst
->next
== NULL
)
335 td
->last_ins
= new_inst
;
337 new_inst
->next
->prev
= new_inst
;
343 interp_clear_ins (TransformData
*td
, InterpInst
*ins
)
345 // Clearing instead of removing from the list makes everything easier.
346 // We don't change structure of the instruction list, we don't need
347 // to worry about updating the il_offset, or whether this instruction
348 // was at the start of a basic block etc.
349 ins
->opcode
= MINT_NOP
;
352 #define CHECK_STACK(td, n) \
354 int stack_size = (td)->sp - (td)->stack; \
355 if (stack_size < (n)) \
356 g_warning ("%s.%s: not enough values (%d < %d) on stack at %04x", \
357 m_class_get_name ((td)->method->klass), (td)->method->name, \
358 stack_size, n, (td)->ip - (td)->il_code); \
361 #define ENSURE_I4(td, sp_off) \
363 if ((td)->sp [-sp_off].type == STACK_TYPE_I8) \
364 interp_add_ins (td, sp_off == 1 ? MINT_CONV_I4_I8 : MINT_CONV_I4_I8_SP); \
367 #define CHECK_TYPELOAD(klass) \
369 if (!(klass) || mono_class_has_failure (klass)) { \
370 mono_error_set_for_class_failure (error, klass); \
375 #if NO_UNALIGNED_ACCESS
376 #define WRITE32(ip, v) \
378 * (ip) = * (guint16 *)(v); \
379 * ((ip) + 1) = * ((guint16 *)(v) + 1); \
383 #define WRITE32_INS(ins, index, v) \
385 (ins)->data [index] = * (guint16 *)(v); \
386 (ins)->data [index + 1] = * ((guint16 *)(v) + 1); \
389 #define WRITE64_INS(ins, index, v) \
391 (ins)->data [index] = * (guint16 *)(v); \
392 (ins)->data [index + 1] = * ((guint16 *)(v) + 1); \
393 (ins)->data [index + 2] = * ((guint16 *)(v) + 2); \
394 (ins)->data [index + 3] = * ((guint16 *)(v) + 3); \
397 #define WRITE32(ip, v) \
399 * (guint32*)(ip) = * (guint32 *)(v); \
402 #define WRITE32_INS(ins, index, v) \
404 * (guint32 *)(&(ins)->data [index]) = * (guint32 *)(v); \
407 #define WRITE64_INS(ins, index, v) \
409 * (guint64 *)(&(ins)->data [index]) = * (guint64 *)(v); \
416 handle_branch (TransformData
*td
, int short_op
, int long_op
, int offset
)
418 int shorten_branch
= 0;
419 int target
= td
->ip
+ offset
- td
->il_code
;
420 if (target
< 0 || target
>= td
->code_size
)
421 g_assert_not_reached ();
422 /* Add exception checkpoint or safepoint for backward branches */
424 if (mono_threads_are_safepoints_enabled ())
425 interp_add_ins (td
, MINT_SAFEPOINT
);
427 interp_add_ins (td
, MINT_CHECKPOINT
);
429 if (offset
> 0 && td
->stack_height
[target
] < 0) {
430 td
->stack_height
[target
] = td
->sp
- td
->stack
;
431 if (td
->stack_height
[target
] > 0)
432 td
->stack_state
[target
] = (StackInfo
*)g_memdup (td
->stack
, td
->stack_height
[target
] * sizeof (td
->stack
[0]));
433 td
->vt_stack_size
[target
] = td
->vt_sp
;
436 if (td
->header
->code_size
<= 25000) /* FIX to be precise somehow? */
439 if (shorten_branch
) {
440 interp_add_ins (td
, short_op
);
441 td
->last_ins
->data
[0] = (guint16
) target
;
443 interp_add_ins (td
, long_op
);
444 WRITE32_INS (td
->last_ins
, 0, &target
);
449 one_arg_branch(TransformData
*td
, int mint_op
, int offset
)
451 int type
= td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
? STACK_TYPE_I
: td
->sp
[-1].type
;
452 int long_op
= mint_op
+ type
- STACK_TYPE_I4
;
453 int short_op
= long_op
+ MINT_BRFALSE_I4_S
- MINT_BRFALSE_I4
;
456 handle_branch (td
, short_op
, long_op
, offset
);
460 two_arg_branch(TransformData
*td
, int mint_op
, int offset
)
462 int type1
= td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
? STACK_TYPE_I
: td
->sp
[-1].type
;
463 int type2
= td
->sp
[-2].type
== STACK_TYPE_O
|| td
->sp
[-2].type
== STACK_TYPE_MP
? STACK_TYPE_I
: td
->sp
[-2].type
;
464 int long_op
= mint_op
+ type1
- STACK_TYPE_I4
;
465 int short_op
= long_op
+ MINT_BEQ_I4_S
- MINT_BEQ_I4
;
467 if (type1
== STACK_TYPE_I4
&& type2
== STACK_TYPE_I8
) {
468 // The il instruction starts with the actual branch, and not with the conversion opcodes
469 interp_insert_ins (td
, td
->last_ins
, MINT_CONV_I8_I4
);
470 } else if (type1
== STACK_TYPE_I8
&& type2
== STACK_TYPE_I4
) {
471 interp_insert_ins (td
, td
->last_ins
, MINT_CONV_I8_I4_SP
);
472 } else if (type1
== STACK_TYPE_R4
&& type2
== STACK_TYPE_R8
) {
473 interp_insert_ins (td
, td
->last_ins
, MINT_CONV_R8_R4
);
474 } else if (type1
== STACK_TYPE_R8
&& type2
== STACK_TYPE_R4
) {
475 interp_insert_ins (td
, td
->last_ins
, MINT_CONV_R8_R4_SP
);
476 } else if (type1
!= type2
) {
477 g_warning("%s.%s: branch type mismatch %d %d",
478 m_class_get_name (td
->method
->klass
), td
->method
->name
,
479 td
->sp
[-1].type
, td
->sp
[-2].type
);
482 handle_branch (td
, short_op
, long_op
, offset
);
486 unary_arith_op(TransformData
*td
, int mint_op
)
488 int op
= mint_op
+ td
->sp
[-1].type
- STACK_TYPE_I4
;
490 interp_add_ins (td
, op
);
494 binary_arith_op(TransformData
*td
, int mint_op
)
496 int type1
= td
->sp
[-2].type
;
497 int type2
= td
->sp
[-1].type
;
499 #if SIZEOF_VOID_P == 8
500 if ((type1
== STACK_TYPE_MP
|| type1
== STACK_TYPE_I8
) && type2
== STACK_TYPE_I4
) {
501 interp_add_ins (td
, MINT_CONV_I8_I4
);
502 type2
= STACK_TYPE_I8
;
504 if (type1
== STACK_TYPE_I4
&& (type2
== STACK_TYPE_MP
|| type2
== STACK_TYPE_I8
)) {
505 interp_add_ins (td
, MINT_CONV_I8_I4_SP
);
506 type1
= STACK_TYPE_I8
;
507 td
->sp
[-2].type
= STACK_TYPE_I8
;
510 if (type1
== STACK_TYPE_R8
&& type2
== STACK_TYPE_R4
) {
511 interp_add_ins (td
, MINT_CONV_R8_R4
);
512 type2
= STACK_TYPE_R8
;
514 if (type1
== STACK_TYPE_R4
&& type2
== STACK_TYPE_R8
) {
515 interp_add_ins (td
, MINT_CONV_R8_R4_SP
);
516 type1
= STACK_TYPE_R8
;
517 td
->sp
[-2].type
= STACK_TYPE_R8
;
519 if (type1
== STACK_TYPE_MP
)
520 type1
= STACK_TYPE_I
;
521 if (type2
== STACK_TYPE_MP
)
522 type2
= STACK_TYPE_I
;
523 if (type1
!= type2
) {
524 g_warning("%s.%s: %04x arith type mismatch %s %d %d",
525 m_class_get_name (td
->method
->klass
), td
->method
->name
,
526 td
->ip
- td
->il_code
, mono_interp_opname (mint_op
), type1
, type2
);
528 op
= mint_op
+ type1
- STACK_TYPE_I4
;
530 interp_add_ins (td
, op
);
535 shift_op(TransformData
*td
, int mint_op
)
537 int op
= mint_op
+ td
->sp
[-2].type
- STACK_TYPE_I4
;
539 if (td
->sp
[-1].type
!= STACK_TYPE_I4
) {
540 g_warning("%s.%s: shift type mismatch %d",
541 m_class_get_name (td
->method
->klass
), td
->method
->name
,
544 interp_add_ins (td
, op
);
549 can_store (int st_value
, int vt_value
)
551 if (st_value
== STACK_TYPE_O
|| st_value
== STACK_TYPE_MP
)
552 st_value
= STACK_TYPE_I
;
553 if (vt_value
== STACK_TYPE_O
|| vt_value
== STACK_TYPE_MP
)
554 vt_value
= STACK_TYPE_I
;
555 return st_value
== vt_value
;
558 #define SET_SIMPLE_TYPE(s, ty) \
565 #define SET_TYPE(s, ty, k) \
572 #define REALLOC_STACK(td, sppos) \
574 (td)->stack_capacity *= 2; \
575 (td)->stack = (StackInfo*)realloc ((td)->stack, (td)->stack_capacity * sizeof (td->stack [0])); \
576 (td)->sp = (td)->stack + (sppos); \
579 #define PUSH_SIMPLE_TYPE(td, ty) \
583 sp_height = (td)->sp - (td)->stack; \
584 if (sp_height > (td)->max_stack_height) \
585 (td)->max_stack_height = sp_height; \
586 if (sp_height > (td)->stack_capacity) \
587 REALLOC_STACK(td, sp_height); \
588 SET_SIMPLE_TYPE((td)->sp - 1, ty); \
591 #define PUSH_TYPE(td, ty, k) \
595 sp_height = (td)->sp - (td)->stack; \
596 if (sp_height > (td)->max_stack_height) \
597 (td)->max_stack_height = sp_height; \
598 if (sp_height > (td)->stack_capacity) \
599 REALLOC_STACK(td, sp_height); \
600 SET_TYPE((td)->sp - 1, ty, k); \
604 move_stack (TransformData
*td
, int start
, int amount
)
606 int sp_height
= td
->sp
- td
->stack
;
607 int to_move
= sp_height
- start
;
612 if (sp_height
> td
->max_stack_height
)
613 td
->max_stack_height
= sp_height
;
614 if (sp_height
> td
->stack_capacity
)
615 REALLOC_STACK (td
, sp_height
);
617 g_assert (td
->sp
>= td
->stack
);
621 memmove (td
->stack
+ start
+ amount
, td
->stack
+ start
, to_move
* sizeof (StackInfo
));
624 #define PUSH_VT(td, size) \
626 (td)->vt_sp += ALIGN_TO ((size), MINT_VT_ALIGNMENT); \
627 if ((td)->vt_sp > (td)->max_vt_sp) \
628 (td)->max_vt_sp = (td)->vt_sp; \
631 #define POP_VT(td, size) \
633 (td)->vt_sp -= ALIGN_TO ((size), MINT_VT_ALIGNMENT); \
637 get_arg_type_exact (TransformData
*td
, int n
, int *mt
)
640 gboolean hasthis
= mono_method_signature_internal (td
->method
)->hasthis
;
642 if (hasthis
&& n
== 0)
643 type
= m_class_get_byval_arg (td
->method
->klass
);
645 type
= mono_method_signature_internal (td
->method
)->params
[n
- !!hasthis
];
648 *mt
= mint_type (type
);
654 load_arg(TransformData
*td
, int n
)
657 MonoClass
*klass
= NULL
;
659 gboolean hasthis
= mono_method_signature_internal (td
->method
)->hasthis
;
661 type
= get_arg_type_exact (td
, n
, &mt
);
663 if (mt
== MINT_TYPE_VT
) {
665 klass
= mono_class_from_mono_type_internal (type
);
666 if (mono_method_signature_internal (td
->method
)->pinvoke
)
667 size
= mono_class_native_size (klass
, NULL
);
669 size
= mono_class_value_size (klass
, NULL
);
671 if (hasthis
&& n
== 0) {
673 interp_add_ins (td
, MINT_LDARG_P
);
674 td
->last_ins
->data
[0] = 0;
678 interp_add_ins (td
, MINT_LDARG_VT
);
679 td
->last_ins
->data
[0] = n
;
680 WRITE32_INS (td
->last_ins
, 1, &size
);
683 if (hasthis
&& n
== 0) {
685 interp_add_ins (td
, MINT_LDARG_P
);
686 td
->last_ins
->data
[0] = n
;
689 interp_add_ins (td
, MINT_LDARG_I1
+ (mt
- MINT_TYPE_I1
));
690 td
->last_ins
->data
[0] = n
;
691 if (mt
== MINT_TYPE_O
)
692 klass
= mono_class_from_mono_type_internal (type
);
695 PUSH_TYPE(td
, stack_type
[mt
], klass
);
699 store_arg(TransformData
*td
, int n
)
705 type
= get_arg_type_exact (td
, n
, &mt
);
707 if (mt
== MINT_TYPE_VT
) {
709 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
710 if (mono_method_signature_internal (td
->method
)->pinvoke
)
711 size
= mono_class_native_size (klass
, NULL
);
713 size
= mono_class_value_size (klass
, NULL
);
714 interp_add_ins (td
, MINT_STARG_VT
);
715 td
->last_ins
->data
[0] = n
;
716 WRITE32_INS (td
->last_ins
, 1, &size
);
717 if (td
->sp
[-1].type
== STACK_TYPE_VT
)
720 interp_add_ins (td
, MINT_STARG_I1
+ (mt
- MINT_TYPE_I1
));
721 td
->last_ins
->data
[0] = n
;
727 load_local_general (TransformData
*td
, int offset
, MonoType
*type
)
729 int mt
= mint_type (type
);
730 MonoClass
*klass
= NULL
;
731 if (mt
== MINT_TYPE_VT
) {
732 klass
= mono_class_from_mono_type_internal (type
);
733 gint32 size
= mono_class_value_size (klass
, NULL
);
735 interp_add_ins (td
, MINT_LDLOC_VT
);
736 td
->last_ins
->data
[0] = offset
;
737 WRITE32_INS (td
->last_ins
, 1, &size
);
739 g_assert (mt
< MINT_TYPE_VT
);
740 if (!td
->gen_sdb_seq_points
&&
741 mt
== MINT_TYPE_I4
&& !td
->is_bb_start
[td
->in_start
- td
->il_code
] && td
->last_ins
!= NULL
&&
742 td
->last_ins
->opcode
== MINT_STLOC_I4
&& td
->last_ins
->data
[0] == offset
) {
743 td
->last_ins
->opcode
= MINT_STLOC_NP_I4
;
744 } else if (!td
->gen_sdb_seq_points
&&
745 mt
== MINT_TYPE_O
&& !td
->is_bb_start
[td
->in_start
- td
->il_code
] && td
->last_ins
!= NULL
&&
746 td
->last_ins
->opcode
== MINT_STLOC_O
&& td
->last_ins
->data
[0] == offset
) {
747 td
->last_ins
->opcode
= MINT_STLOC_NP_O
;
749 interp_add_ins (td
, MINT_LDLOC_I1
+ (mt
- MINT_TYPE_I1
));
750 td
->last_ins
->data
[0] = offset
; /*FIX for large offset */
752 if (mt
== MINT_TYPE_O
)
753 klass
= mono_class_from_mono_type_internal (type
);
755 PUSH_TYPE(td
, stack_type
[mt
], klass
);
759 load_local (TransformData
*td
, int n
)
761 MonoType
*type
= td
->header
->locals
[n
];
762 int offset
= td
->rtm
->local_offsets
[n
];
763 load_local_general (td
, offset
, type
);
767 store_local_general (TransformData
*td
, int offset
, MonoType
*type
)
769 int mt
= mint_type (type
);
771 #if SIZEOF_VOID_P == 8
772 if (td
->sp
[-1].type
== STACK_TYPE_I4
&& stack_type
[mt
] == STACK_TYPE_I8
) {
773 interp_add_ins (td
, MINT_CONV_I8_I4
);
774 td
->sp
[-1].type
= STACK_TYPE_I8
;
777 if (!can_store(td
->sp
[-1].type
, stack_type
[mt
])) {
778 g_warning("%s.%s: Store local stack type mismatch %d %d",
779 m_class_get_name (td
->method
->klass
), td
->method
->name
,
780 stack_type
[mt
], td
->sp
[-1].type
);
782 if (mt
== MINT_TYPE_VT
) {
783 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
784 gint32 size
= mono_class_value_size (klass
, NULL
);
785 interp_add_ins (td
, MINT_STLOC_VT
);
786 td
->last_ins
->data
[0] = offset
; /*FIX for large offset */
787 WRITE32_INS (td
->last_ins
, 1, &size
);
788 if (td
->sp
[-1].type
== STACK_TYPE_VT
)
791 g_assert (mt
< MINT_TYPE_VT
);
792 interp_add_ins (td
, MINT_STLOC_I1
+ (mt
- MINT_TYPE_I1
));
793 td
->last_ins
->data
[0] = offset
; /*FIX for large offset */
799 store_local (TransformData
*td
, int n
)
801 MonoType
*type
= td
->header
->locals
[n
];
802 int offset
= td
->rtm
->local_offsets
[n
];
803 store_local_general (td
, offset
, type
);
806 #define SIMPLE_OP(td, op) \
808 interp_add_ins (td, op); \
813 get_data_item_index (TransformData
*td
, void *ptr
)
815 gpointer p
= g_hash_table_lookup (td
->data_hash
, ptr
);
818 return GPOINTER_TO_UINT (p
) - 1;
819 if (td
->max_data_items
== td
->n_data_items
) {
820 td
->max_data_items
= td
->n_data_items
== 0 ? 16 : 2 * td
->max_data_items
;
821 td
->data_items
= (gpointer
*)g_realloc (td
->data_items
, td
->max_data_items
* sizeof(td
->data_items
[0]));
823 index
= td
->n_data_items
;
824 td
->data_items
[index
] = ptr
;
826 g_hash_table_insert (td
->data_hash
, ptr
, GUINT_TO_POINTER (index
+ 1));
831 jit_call_supported (MonoMethod
*method
, MonoMethodSignature
*sig
)
835 if (sig
->param_count
> 6)
839 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
841 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
)
843 if (method
->is_inflated
)
845 if (method
->string_ctor
)
848 if (mono_aot_only
&& m_class_get_image (method
->klass
)->aot_module
&& !(method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)) {
850 gpointer addr
= mono_jit_compile_method_jit_only (method
, error
);
851 if (addr
&& is_ok (error
))
855 for (l
= mono_interp_jit_classes
; l
; l
= l
->next
) {
856 const char *class_name
= (const char*)l
->data
;
858 if (!strcmp (m_class_get_name (method
->klass
), class_name
))
866 static int mono_class_get_magic_index (MonoClass
*k
)
868 if (mono_class_is_magic_int (k
))
869 return !strcmp ("nint", m_class_get_name (k
)) ? 0 : 1;
871 if (mono_class_is_magic_float (k
))
878 interp_generate_mae_throw (TransformData
*td
, MonoMethod
*method
, MonoMethod
*target_method
)
880 MonoJitICallInfo
*info
= &mono_get_jit_icall_info ()->mono_throw_method_access
;
882 /* Inject code throwing MethodAccessException */
883 interp_add_ins (td
, MINT_MONO_LDPTR
);
884 td
->last_ins
->data
[0] = get_data_item_index (td
, method
);
885 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
887 interp_add_ins (td
, MINT_MONO_LDPTR
);
888 td
->last_ins
->data
[0] = get_data_item_index (td
, target_method
);
889 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
891 interp_add_ins (td
, MINT_ICALL_PP_V
);
892 td
->last_ins
->data
[0] = get_data_item_index (td
, (gpointer
)info
->func
);
898 interp_generate_bie_throw (TransformData
*td
)
900 MonoJitICallInfo
*info
= &mono_get_jit_icall_info ()->mono_throw_bad_image
;
902 interp_add_ins (td
, MINT_ICALL_V_V
);
903 td
->last_ins
->data
[0] = get_data_item_index (td
, (gpointer
)info
->func
);
907 * These are additional locals that can be allocated as we transform the code.
908 * They are allocated past the method locals so they are accessed in the same
909 * way, with an offset relative to the frame->locals.
912 create_interp_local (TransformData
*td
, MonoType
*type
)
915 int offset
= td
->total_locals_size
;
917 size
= mono_type_size (type
, &align
);
918 offset
= ALIGN_TO (offset
, align
);
920 td
->total_locals_size
= offset
+ size
;
926 dump_mint_code (const guint16
*start
, const guint16
* end
)
928 const guint16
*p
= start
;
930 char *ins
= mono_interp_dis_mintop (start
, p
);
931 g_print ("%s\n", ins
);
933 p
= mono_interp_dis_mintop_len (p
);
939 mono_interp_print_code (InterpMethod
*imethod
)
941 MonoJitInfo
*jinfo
= imethod
->jinfo
;
942 const guint16
*start
;
947 char *name
= mono_method_full_name (imethod
->method
, 1);
948 g_print ("Method : %s\n", name
);
951 start
= (guint16
*) jinfo
->code_start
;
952 dump_mint_code (start
, start
+ jinfo
->code_size
);
956 static MonoMethodHeader
*
957 interp_method_get_header (MonoMethod
* method
, MonoError
*error
)
959 /* An explanation: mono_method_get_header_internal returns an error if
960 * called on a method with no body (e.g. an abstract method, or an
961 * icall). We don't want that.
963 if (mono_method_has_no_body (method
))
966 return mono_method_get_header_internal (method
, error
);
969 /* stores top of stack as local and pushes address of it on stack */
971 emit_store_value_as_local (TransformData
*td
, MonoType
*src
)
973 int size
= mini_magic_type_size (NULL
, src
);
974 int local_offset
= create_interp_local (td
, mini_native_type_replace_type (src
));
976 store_local_general (td
, local_offset
, src
);
978 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
979 interp_add_ins (td
, MINT_LDLOC_VT
);
980 td
->last_ins
->data
[0] = local_offset
;
981 WRITE32_INS (td
->last_ins
, 1, &size
);
984 PUSH_TYPE (td
, STACK_TYPE_VT
, NULL
);
987 // Returns whether we can optimize away the instructions starting at start.
988 // If any instructions are part of a new basic block, we can't remove them.
990 interp_is_bb_start (TransformData
*td
, InterpInst
*start
, InterpInst
*end
)
992 InterpInst
*ins
= start
;
994 if (ins
->il_offset
!= -1) {
995 if (td
->is_bb_start
[ins
->il_offset
])
1004 interp_ins_is_ldc (InterpInst
*ins
)
1006 return ins
->opcode
>= MINT_LDC_I4_M1
&& ins
->opcode
<= MINT_LDC_I8
;
1010 interp_ldc_i4_get_const (InterpInst
*ins
)
1012 switch (ins
->opcode
) {
1013 case MINT_LDC_I4_M1
: return -1;
1014 case MINT_LDC_I4_0
: return 0;
1015 case MINT_LDC_I4_1
: return 1;
1016 case MINT_LDC_I4_2
: return 2;
1017 case MINT_LDC_I4_3
: return 3;
1018 case MINT_LDC_I4_4
: return 4;
1019 case MINT_LDC_I4_5
: return 5;
1020 case MINT_LDC_I4_6
: return 6;
1021 case MINT_LDC_I4_7
: return 7;
1022 case MINT_LDC_I4_8
: return 8;
1023 case MINT_LDC_I4_S
: return (gint32
)(gint8
)ins
->data
[0];
1024 case MINT_LDC_I4
: return READ32 (&ins
->data
[0]);
1026 g_assert_not_reached ();
1031 interp_get_ldind_for_mt (int mt
)
1034 case MINT_TYPE_I1
: return MINT_LDIND_I1_CHECK
;
1035 case MINT_TYPE_U1
: return MINT_LDIND_U1_CHECK
;
1036 case MINT_TYPE_I2
: return MINT_LDIND_I2_CHECK
;
1037 case MINT_TYPE_U2
: return MINT_LDIND_U2_CHECK
;
1038 case MINT_TYPE_I4
: return MINT_LDIND_I4_CHECK
;
1039 case MINT_TYPE_I8
: return MINT_LDIND_I8_CHECK
;
1040 case MINT_TYPE_R4
: return MINT_LDIND_R4_CHECK
;
1041 case MINT_TYPE_R8
: return MINT_LDIND_R8_CHECK
;
1042 case MINT_TYPE_O
: return MINT_LDIND_REF
;
1044 g_assert_not_reached ();
1049 /* Return TRUE if call transformation is finished */
1051 interp_handle_intrinsics (TransformData
*td
, MonoMethod
*target_method
, MonoClass
*constrained_class
, MonoMethodSignature
*csignature
, gboolean readonly
, int *op
)
1053 const char *tm
= target_method
->name
;
1055 int type_index
= mono_class_get_magic_index (target_method
->klass
);
1056 gboolean in_corlib
= m_class_get_image (target_method
->klass
) == mono_defaults
.corlib
;
1057 const char *klass_name_space
= m_class_get_name_space (target_method
->klass
);
1058 const char *klass_name
= m_class_get_name (target_method
->klass
);
1060 if (target_method
->klass
== mono_defaults
.string_class
) {
1061 if (tm
[0] == 'g') {
1062 if (strcmp (tm
, "get_Chars") == 0)
1064 else if (strcmp (tm
, "get_Length") == 0)
1067 } else if (type_index
>= 0) {
1068 MonoClass
*magic_class
= target_method
->klass
;
1070 const int mt
= mint_type (m_class_get_byval_arg (magic_class
));
1071 if (!strcmp (".ctor", tm
)) {
1072 MonoType
*arg
= csignature
->params
[0];
1073 /* depending on SIZEOF_VOID_P and the type of the value passed to the .ctor we either have to CONV it, or do nothing */
1074 int arg_size
= mini_magic_type_size (NULL
, arg
);
1076 if (arg_size
> SIZEOF_VOID_P
) { // 8 -> 4
1077 switch (type_index
) {
1079 interp_add_ins (td
, MINT_CONV_I4_I8
);
1082 interp_add_ins (td
, MINT_CONV_R4_R8
);
1087 if (arg_size
< SIZEOF_VOID_P
) { // 4 -> 8
1088 switch (type_index
) {
1090 interp_add_ins (td
, MINT_CONV_I8_I4
);
1093 interp_add_ins (td
, MINT_CONV_I8_U4
);
1096 interp_add_ins (td
, MINT_CONV_R8_R4
);
1101 switch (type_index
) {
1103 #if SIZEOF_VOID_P == 4
1104 interp_add_ins (td
, MINT_STIND_I4
);
1106 interp_add_ins (td
, MINT_STIND_I8
);
1110 #if SIZEOF_VOID_P == 4
1111 interp_add_ins (td
, MINT_STIND_R4
);
1113 interp_add_ins (td
, MINT_STIND_R8
);
1121 } else if (!strcmp ("op_Implicit", tm
) || !strcmp ("op_Explicit", tm
)) {
1122 MonoType
*src
= csignature
->params
[0];
1123 MonoType
*dst
= csignature
->ret
;
1124 MonoClass
*src_klass
= mono_class_from_mono_type_internal (src
);
1125 int src_size
= mini_magic_type_size (NULL
, src
);
1126 int dst_size
= mini_magic_type_size (NULL
, dst
);
1128 gboolean store_value_as_local
= FALSE
;
1130 switch (type_index
) {
1132 if (!mini_magic_is_int_type (src
) || !mini_magic_is_int_type (dst
)) {
1133 if (mini_magic_is_int_type (src
))
1134 store_value_as_local
= TRUE
;
1135 else if (mono_class_is_magic_float (src_klass
))
1136 store_value_as_local
= TRUE
;
1142 if (!mini_magic_is_float_type (src
) || !mini_magic_is_float_type (dst
)) {
1143 if (mini_magic_is_float_type (src
))
1144 store_value_as_local
= TRUE
;
1145 else if (mono_class_is_magic_int (src_klass
))
1146 store_value_as_local
= TRUE
;
1153 if (store_value_as_local
) {
1154 emit_store_value_as_local (td
, src
);
1156 /* emit call to managed conversion method */
1160 if (src_size
> dst_size
) { // 8 -> 4
1161 switch (type_index
) {
1163 interp_add_ins (td
, MINT_CONV_I4_I8
);
1166 interp_add_ins (td
, MINT_CONV_R4_R8
);
1171 if (src_size
< dst_size
) { // 4 -> 8
1172 switch (type_index
) {
1174 interp_add_ins (td
, MINT_CONV_I8_I4
);
1177 interp_add_ins (td
, MINT_CONV_I8_U4
);
1180 interp_add_ins (td
, MINT_CONV_R8_R4
);
1185 SET_TYPE (td
->sp
- 1, stack_type
[mint_type (dst
)], mono_class_from_mono_type_internal (dst
));
1188 } else if (!strcmp ("op_Increment", tm
)) {
1189 g_assert (type_index
!= 2); // no nfloat
1190 #if SIZEOF_VOID_P == 8
1191 interp_add_ins (td
, MINT_ADD1_I8
);
1193 interp_add_ins (td
, MINT_ADD1_I4
);
1195 SET_TYPE (td
->sp
- 1, stack_type
[mt
], magic_class
);
1198 } else if (!strcmp ("op_Decrement", tm
)) {
1199 g_assert (type_index
!= 2); // no nfloat
1200 #if SIZEOF_VOID_P == 8
1201 interp_add_ins (td
, MINT_SUB1_I8
);
1203 interp_add_ins (td
, MINT_SUB1_I4
);
1205 SET_TYPE (td
->sp
- 1, stack_type
[mt
], magic_class
);
1208 } else if (!strcmp ("CompareTo", tm
) || !strcmp ("Equals", tm
)) {
1209 MonoType
*arg
= csignature
->params
[0];
1211 /* on 'System.n*::{CompareTo,Equals} (System.n*)' variant we need to push managed
1212 * pointer instead of value */
1213 if (arg
->type
== MONO_TYPE_VALUETYPE
)
1214 emit_store_value_as_local (td
, arg
);
1216 /* emit call to managed conversion method */
1218 } else if (!strcmp (".cctor", tm
)) {
1221 } else if (!strcmp ("Parse", tm
)) {
1224 } else if (!strcmp ("ToString", tm
)) {
1227 } else if (!strcmp ("GetHashCode", tm
)) {
1230 } else if (!strcmp ("IsNaN", tm
) || !strcmp ("IsInfinity", tm
) || !strcmp ("IsNegativeInfinity", tm
) || !strcmp ("IsPositiveInfinity", tm
)) {
1231 g_assert (type_index
== 2); // nfloat only
1236 for (i
= 0; i
< sizeof (int_unnop
) / sizeof (MagicIntrinsic
); ++i
) {
1237 if (!strcmp (int_unnop
[i
].op_name
, tm
)) {
1238 interp_add_ins (td
, int_unnop
[i
].insn
[type_index
]);
1239 SET_TYPE (td
->sp
- 1, stack_type
[mt
], magic_class
);
1245 for (i
= 0; i
< sizeof (int_binop
) / sizeof (MagicIntrinsic
); ++i
) {
1246 if (!strcmp (int_binop
[i
].op_name
, tm
)) {
1247 interp_add_ins (td
, int_binop
[i
].insn
[type_index
]);
1249 SET_TYPE (td
->sp
- 1, stack_type
[mt
], magic_class
);
1255 for (i
= 0; i
< sizeof (int_cmpop
) / sizeof (MagicIntrinsic
); ++i
) {
1256 if (!strcmp (int_cmpop
[i
].op_name
, tm
)) {
1257 MonoClass
*k
= mono_defaults
.boolean_class
;
1258 interp_add_ins (td
, int_cmpop
[i
].insn
[type_index
]);
1260 SET_TYPE (td
->sp
- 1, stack_type
[mint_type (m_class_get_byval_arg (k
))], k
);
1266 g_error ("TODO: interp_transform_call %s:%s", m_class_get_name (target_method
->klass
), tm
);
1267 } else if (mono_class_is_subclass_of_internal (target_method
->klass
, mono_defaults
.array_class
, FALSE
)) {
1268 if (!strcmp (tm
, "get_Rank")) {
1269 *op
= MINT_ARRAY_RANK
;
1270 } else if (!strcmp (tm
, "get_Length")) {
1272 } else if (!strcmp (tm
, "Address")) {
1273 *op
= readonly
? MINT_LDELEMA
: MINT_LDELEMA_TC
;
1274 } else if (!strcmp (tm
, "UnsafeMov") || !strcmp (tm
, "UnsafeLoad") || !strcmp (tm
, "Set") || !strcmp (tm
, "Get")) {
1276 } else if (!strcmp (tm
, "UnsafeStore")) {
1277 g_error ("TODO ArrayClass::UnsafeStore");
1279 } else if (in_corlib
&&
1280 !strcmp (klass_name_space
, "System.Diagnostics") &&
1281 !strcmp (klass_name
, "Debugger")) {
1282 if (!strcmp (tm
, "Break") && csignature
->param_count
== 0) {
1283 if (mini_should_insert_breakpoint (td
->method
))
1286 } else if (in_corlib
&& !strcmp (klass_name_space
, "System") && !strcmp (klass_name
, "ByReference`1")) {
1287 g_assert (!strcmp (tm
, "get_Value"));
1288 *op
= MINT_INTRINS_BYREFERENCE_GET_VALUE
;
1289 } else if (in_corlib
&& !strcmp (klass_name_space
, "System") && !strcmp (klass_name
, "Math") && csignature
->param_count
== 1 && csignature
->params
[0]->type
== MONO_TYPE_R8
) {
1290 if (tm
[0] == 'A') {
1291 if (strcmp (tm
, "Abs") == 0 && csignature
->params
[0]->type
== MONO_TYPE_R8
) {
1293 } else if (strcmp (tm
, "Asin") == 0){
1295 } else if (strcmp (tm
, "Asinh") == 0){
1297 } else if (strcmp (tm
, "Acos") == 0){
1299 } else if (strcmp (tm
, "Acosh") == 0){
1301 } else if (strcmp (tm
, "Atan") == 0){
1303 } else if (strcmp (tm
, "Atanh") == 0){
1306 } else if (tm
[0] == 'C') {
1307 if (strcmp (tm
, "Cos") == 0) {
1309 } else if (strcmp (tm
, "Cbrt") == 0){
1311 } else if (strcmp (tm
, "Cosh") == 0){
1314 } else if (tm
[0] == 'S') {
1315 if (strcmp (tm
, "Sin") == 0) {
1317 } else if (strcmp (tm
, "Sqrt") == 0) {
1319 } else if (strcmp (tm
, "Sinh") == 0){
1322 } else if (tm
[0] == 'T') {
1323 if (strcmp (tm
, "Tan") == 0) {
1325 } else if (strcmp (tm
, "Tanh") == 0){
1329 } else if (in_corlib
&& !strcmp (klass_name_space
, "System") && (!strcmp (klass_name
, "Span`1") || !strcmp (klass_name
, "ReadOnlySpan`1"))) {
1330 if (!strcmp (tm
, "get_Item")) {
1331 MonoGenericClass
*gclass
= mono_class_get_generic_class (target_method
->klass
);
1332 MonoClass
*param_class
= mono_class_from_mono_type_internal (gclass
->context
.class_inst
->type_argv
[0]);
1334 if (!mini_is_gsharedvt_variable_klass (param_class
)) {
1335 MonoClassField
*length_field
= mono_class_get_field_from_name_full (target_method
->klass
, "_length", NULL
);
1336 g_assert (length_field
);
1337 int offset_length
= length_field
->offset
- sizeof (MonoObject
);
1339 MonoClassField
*ptr_field
= mono_class_get_field_from_name_full (target_method
->klass
, "_pointer", NULL
);
1340 g_assert (ptr_field
);
1341 int offset_pointer
= ptr_field
->offset
- sizeof (MonoObject
);
1343 int size
= mono_class_array_element_size (param_class
);
1344 interp_add_ins (td
, MINT_GETITEM_SPAN
);
1345 td
->last_ins
->data
[0] = size
;
1346 td
->last_ins
->data
[1] = offset_length
;
1347 td
->last_ins
->data
[2] = offset_pointer
;
1349 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_MP
);
1354 } else if (!strcmp (tm
, "get_Length")) {
1355 MonoClassField
*length_field
= mono_class_get_field_from_name_full (target_method
->klass
, "_length", NULL
);
1356 g_assert (length_field
);
1357 int offset_length
= length_field
->offset
- sizeof (MonoObject
);
1358 interp_add_ins (td
, MINT_LDLEN_SPAN
);
1359 td
->last_ins
->data
[0] = offset_length
;
1360 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I4
);
1364 } else if (in_corlib
&& !strcmp (klass_name_space
, "Internal.Runtime.CompilerServices") && !strcmp (klass_name
, "Unsafe")) {
1365 #ifdef ENABLE_NETCORE
1366 if (!strcmp (tm
, "AddByteOffset"))
1367 *op
= MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET
;
1368 else if (!strcmp (tm
, "ByteOffset"))
1369 *op
= MINT_INTRINS_UNSAFE_BYTE_OFFSET
;
1370 else if (!strcmp (tm
, "As") || !strcmp (tm
, "AsRef"))
1372 else if (!strcmp (tm
, "AsPointer")) {
1374 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_MP
);
1377 } else if (!strcmp (tm
, "IsAddressLessThan")) {
1378 MonoGenericContext
*ctx
= mono_method_get_context (target_method
);
1380 g_assert (ctx
->method_inst
);
1381 g_assert (ctx
->method_inst
->type_argc
== 1);
1383 MonoClass
*k
= mono_defaults
.boolean_class
;
1384 interp_add_ins (td
, MINT_CLT_UN_P
);
1386 SET_TYPE (td
->sp
- 1, stack_type
[mint_type (m_class_get_byval_arg (k
))], k
);
1389 } else if (!strcmp (tm
, "SizeOf")) {
1390 MonoGenericContext
*ctx
= mono_method_get_context (target_method
);
1392 g_assert (ctx
->method_inst
);
1393 g_assert (ctx
->method_inst
->type_argc
== 1);
1394 MonoType
*t
= ctx
->method_inst
->type_argv
[0];
1396 int esize
= mono_type_size (t
, &align
);
1397 interp_add_ins (td
, MINT_LDC_I4
);
1398 WRITE32_INS (td
->last_ins
, 0, &esize
);
1399 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I4
);
1402 } else if (!strcmp (tm
, "AreSame")) {
1406 } else if (in_corlib
&& !strcmp (klass_name_space
, "System.Runtime.CompilerServices") && !strcmp (klass_name
, "RuntimeHelpers")) {
1407 #ifdef ENABLE_NETCORE
1408 if (!strcmp (tm
, "IsBitwiseEquatable")) {
1409 g_assert (csignature
->param_count
== 0);
1410 MonoGenericContext
*ctx
= mono_method_get_context (target_method
);
1412 g_assert (ctx
->method_inst
);
1413 g_assert (ctx
->method_inst
->type_argc
== 1);
1414 MonoType
*t
= mini_get_underlying_type (ctx
->method_inst
->type_argv
[0]);
1416 if (MONO_TYPE_IS_PRIMITIVE (t
) && t
->type
!= MONO_TYPE_R4
&& t
->type
!= MONO_TYPE_R8
)
1417 *op
= MINT_LDC_I4_1
;
1419 *op
= MINT_LDC_I4_0
;
1420 } else if (!strcmp (tm
, "ObjectHasComponentSize")) {
1421 *op
= MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE
;
1424 } else if (in_corlib
&& !strcmp (klass_name_space
, "System") && !strcmp (klass_name
, "RuntimeMethodHandle") && !strcmp (tm
, "GetFunctionPointer") && csignature
->param_count
== 1) {
1425 // We must intrinsify this method on interp so we don't return a pointer to native code entering interpreter
1426 *op
= MINT_LDFTN_DYNAMIC
;
1427 } else if (in_corlib
&& target_method
->klass
== mono_defaults
.object_class
) {
1428 if (!strcmp (tm
, "InternalGetHashCode"))
1429 *op
= MINT_INTRINS_GET_HASHCODE
;
1430 #ifdef DISABLE_REMOTING
1431 else if (!strcmp (tm
, "GetType"))
1432 *op
= MINT_INTRINS_GET_TYPE
;
1434 #ifdef ENABLE_NETCORE
1435 else if (!strcmp (tm
, "GetRawData")) {
1436 #if SIZEOF_VOID_P == 8
1437 interp_add_ins (td
, MINT_LDC_I8_S
);
1439 interp_add_ins (td
, MINT_LDC_I4_S
);
1441 td
->last_ins
->data
[0] = (gint16
) MONO_ABI_SIZEOF (MonoObject
);
1443 interp_add_ins (td
, MINT_ADD_P
);
1444 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_MP
);
1450 } else if (in_corlib
&& target_method
->klass
== mono_defaults
.enum_class
&& !strcmp (tm
, "HasFlag")) {
1451 gboolean intrinsify
= FALSE
;
1452 MonoClass
*base_klass
= NULL
;
1453 if (td
->last_ins
&& td
->last_ins
->opcode
== MINT_BOX
&&
1454 td
->last_ins
->prev
&& interp_ins_is_ldc (td
->last_ins
->prev
) &&
1455 td
->last_ins
->prev
->prev
&& td
->last_ins
->prev
->prev
->opcode
== MINT_BOX
&&
1456 td
->sp
[-2].klass
== td
->sp
[-1].klass
&&
1457 !interp_is_bb_start (td
, td
->last_ins
->prev
->prev
, NULL
) &&
1458 !td
->is_bb_start
[td
->in_start
- td
->il_code
]) {
1459 // csc pattern : box, ldc, box, call HasFlag
1460 g_assert (m_class_is_enumtype (td
->sp
[-2].klass
));
1461 MonoType
*base_type
= mono_type_get_underlying_type (m_class_get_byval_arg (td
->sp
[-2].klass
));
1462 base_klass
= mono_class_from_mono_type_internal (base_type
);
1464 // Remove the boxing of valuetypes
1465 interp_clear_ins (td
, td
->last_ins
->prev
->prev
);
1466 interp_clear_ins (td
, td
->last_ins
);
1469 } else if (td
->last_ins
&& td
->last_ins
->opcode
== MINT_BOX
&&
1470 td
->last_ins
->prev
&& interp_ins_is_ldc (td
->last_ins
->prev
) &&
1471 constrained_class
&& td
->sp
[-1].klass
== constrained_class
&&
1472 !interp_is_bb_start (td
, td
->last_ins
->prev
, NULL
) &&
1473 !td
->is_bb_start
[td
->in_start
- td
->il_code
]) {
1474 // mcs pattern : ldc, box, constrained Enum, call HasFlag
1475 g_assert (m_class_is_enumtype (constrained_class
));
1476 MonoType
*base_type
= mono_type_get_underlying_type (m_class_get_byval_arg (constrained_class
));
1477 base_klass
= mono_class_from_mono_type_internal (base_type
);
1478 int mt
= mint_type (m_class_get_byval_arg (base_klass
));
1480 // Remove boxing and load the value of this
1481 interp_clear_ins (td
, td
->last_ins
);
1482 interp_insert_ins (td
, td
->last_ins
->prev
->prev
, interp_get_ldind_for_mt (mt
));
1487 interp_add_ins (td
, MINT_INTRINS_ENUM_HASFLAG
);
1488 td
->last_ins
->data
[0] = get_data_item_index (td
, base_klass
);
1490 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I4
);
1494 } else if (in_corlib
&& !strcmp (klass_name_space
, "System.Threading") && !strcmp (klass_name
, "Interlocked")) {
1496 if (!strcmp (tm
, "MemoryBarrier") && csignature
->param_count
== 0)
1497 *op
= MINT_MONO_MEMORY_BARRIER
;
1499 } else if (in_corlib
&&
1500 !strcmp (klass_name_space
, "System.Runtime.CompilerServices") &&
1501 !strcmp (klass_name
, "JitHelpers") &&
1502 (!strcmp (tm
, "EnumEquals") || !strcmp (tm
, "EnumCompareTo"))) {
1503 MonoGenericContext
*ctx
= mono_method_get_context (target_method
);
1505 g_assert (ctx
->method_inst
);
1506 g_assert (ctx
->method_inst
->type_argc
== 1);
1507 g_assert (csignature
->param_count
== 2);
1509 MonoType
*t
= ctx
->method_inst
->type_argv
[0];
1510 t
= mini_get_underlying_type (t
);
1512 gboolean is_i8
= (t
->type
== MONO_TYPE_I8
|| t
->type
== MONO_TYPE_U8
);
1513 gboolean is_unsigned
= (t
->type
== MONO_TYPE_U1
|| t
->type
== MONO_TYPE_U2
|| t
->type
== MONO_TYPE_U4
|| t
->type
== MONO_TYPE_U8
|| t
->type
== MONO_TYPE_U
);
1515 gboolean is_compareto
= strcmp (tm
, "EnumCompareTo") == 0;
1517 int offseta
, offsetb
;
1518 offseta
= create_interp_local (td
, t
);
1519 offsetb
= create_interp_local (td
, t
);
1522 store_local_general (td
, offsetb
, t
);
1523 store_local_general (td
, offseta
, t
);
1525 load_local_general (td
, offseta
, t
);
1526 load_local_general (td
, offsetb
, t
);
1528 interp_add_ins (td
, is_i8
? MINT_CGT_UN_I8
: MINT_CGT_UN_I4
);
1530 interp_add_ins (td
, is_i8
? MINT_CGT_I8
: MINT_CGT_I4
);
1532 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I4
);
1534 load_local_general (td
, offseta
, t
);
1535 load_local_general (td
, offsetb
, t
);
1537 interp_add_ins (td
, is_i8
? MINT_CLT_UN_I8
: MINT_CLT_UN_I4
);
1539 interp_add_ins (td
, is_i8
? MINT_CLT_I8
: MINT_CLT_I4
);
1541 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I4
);
1542 // (a > b) - (a < b)
1543 interp_add_ins (td
, MINT_SUB_I4
);
1560 interp_transform_internal_calls (MonoMethod
*method
, MonoMethod
*target_method
, MonoMethodSignature
*csignature
, gboolean is_virtual
)
1562 if (method
->wrapper_type
== MONO_WRAPPER_NONE
&& target_method
!= NULL
) {
1563 if (target_method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
1564 target_method
= mono_marshal_get_native_wrapper (target_method
, FALSE
, FALSE
);
1565 if (!is_virtual
&& target_method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)
1566 target_method
= mono_marshal_get_synchronized_wrapper (target_method
);
1568 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)
1569 target_method
= mono_marshal_get_native_wrapper (target_method
, FALSE
, FALSE
);
1571 return target_method
;
1575 interp_type_as_ptr (MonoType
*tp
)
1577 if (MONO_TYPE_IS_POINTER (tp
))
1579 if (MONO_TYPE_IS_REFERENCE (tp
))
1581 if ((tp
)->type
== MONO_TYPE_I4
)
1583 #if SIZEOF_VOID_P == 8
1584 if ((tp
)->type
== MONO_TYPE_I8
)
1587 if ((tp
)->type
== MONO_TYPE_BOOLEAN
)
1589 if ((tp
)->type
== MONO_TYPE_CHAR
)
1591 if ((tp
)->type
== MONO_TYPE_VALUETYPE
&& m_class_is_enumtype (tp
->data
.klass
))
1596 #define INTERP_TYPE_AS_PTR(tp) interp_type_as_ptr (tp)
1599 interp_icall_op_for_sig (MonoMethodSignature
*sig
)
1602 switch (sig
->param_count
) {
1604 if (MONO_TYPE_IS_VOID (sig
->ret
))
1605 op
= MINT_ICALL_V_V
;
1606 else if (INTERP_TYPE_AS_PTR (sig
->ret
))
1607 op
= MINT_ICALL_V_P
;
1610 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1611 if (INTERP_TYPE_AS_PTR (sig
->params
[0]))
1612 op
= MINT_ICALL_P_V
;
1613 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1614 if (INTERP_TYPE_AS_PTR (sig
->params
[0]))
1615 op
= MINT_ICALL_P_P
;
1619 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1620 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1621 INTERP_TYPE_AS_PTR (sig
->params
[1]))
1622 op
= MINT_ICALL_PP_V
;
1623 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1624 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1625 INTERP_TYPE_AS_PTR (sig
->params
[1]))
1626 op
= MINT_ICALL_PP_P
;
1630 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1631 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1632 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1633 INTERP_TYPE_AS_PTR (sig
->params
[2]))
1634 op
= MINT_ICALL_PPP_V
;
1635 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1636 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1637 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1638 INTERP_TYPE_AS_PTR (sig
->params
[2]))
1639 op
= MINT_ICALL_PPP_P
;
1643 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1644 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1645 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1646 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1647 INTERP_TYPE_AS_PTR (sig
->params
[3]))
1648 op
= MINT_ICALL_PPPP_V
;
1649 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1650 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1651 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1652 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1653 INTERP_TYPE_AS_PTR (sig
->params
[3]))
1654 op
= MINT_ICALL_PPPP_P
;
1658 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1659 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1660 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1661 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1662 INTERP_TYPE_AS_PTR (sig
->params
[3]) &&
1663 INTERP_TYPE_AS_PTR (sig
->params
[4]))
1664 op
= MINT_ICALL_PPPPP_V
;
1665 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1666 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1667 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1668 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1669 INTERP_TYPE_AS_PTR (sig
->params
[3]) &&
1670 INTERP_TYPE_AS_PTR (sig
->params
[4]))
1671 op
= MINT_ICALL_PPPPP_P
;
1675 if (MONO_TYPE_IS_VOID (sig
->ret
)) {
1676 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1677 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1678 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1679 INTERP_TYPE_AS_PTR (sig
->params
[3]) &&
1680 INTERP_TYPE_AS_PTR (sig
->params
[4]) &&
1681 INTERP_TYPE_AS_PTR (sig
->params
[5]))
1682 op
= MINT_ICALL_PPPPPP_V
;
1683 } else if (INTERP_TYPE_AS_PTR (sig
->ret
)) {
1684 if (INTERP_TYPE_AS_PTR (sig
->params
[0]) &&
1685 INTERP_TYPE_AS_PTR (sig
->params
[1]) &&
1686 INTERP_TYPE_AS_PTR (sig
->params
[2]) &&
1687 INTERP_TYPE_AS_PTR (sig
->params
[3]) &&
1688 INTERP_TYPE_AS_PTR (sig
->params
[4]) &&
1689 INTERP_TYPE_AS_PTR (sig
->params
[5]))
1690 op
= MINT_ICALL_PPPPPP_P
;
1697 #define INLINE_LENGTH_LIMIT 20
1700 interp_method_check_inlining (TransformData
*td
, MonoMethod
*method
)
1702 MonoMethodHeaderSummary header
;
1704 if (td
->method
== method
)
1707 if (!mono_method_get_header_summary (method
, &header
))
1710 /*runtime, icall and pinvoke are checked by summary call*/
1711 if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_NOINLINING
) ||
1712 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) ||
1713 (mono_class_is_marshalbyref (method
->klass
)) ||
1717 if (header
.code_size
>= INLINE_LENGTH_LIMIT
)
1720 if (mono_class_needs_cctor_run (method
->klass
, NULL
)) {
1723 if (!m_class_get_runtime_info (method
->klass
))
1724 /* No vtable created yet */
1726 vtable
= mono_class_vtable_checked (td
->rtm
->domain
, method
->klass
, error
);
1727 if (!is_ok (error
)) {
1728 mono_error_cleanup (error
);
1731 if (!vtable
->initialized
)
1735 /* We currently access at runtime the wrapper data */
1736 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
1739 /* Our usage of `emit_store_value_as_local ()` for nint, nuint and nfloat
1740 * is kinda hacky, and doesn't work with the inliner */
1741 if (mono_class_get_magic_index (method
->klass
) >= 0)
1748 interp_inline_method (TransformData
*td
, MonoMethod
*target_method
, MonoMethodHeader
*header
, MonoError
*error
)
1750 const unsigned char *prev_ip
, *prev_il_code
, *prev_in_start
;
1751 int *prev_in_offsets
;
1753 unsigned int prev_max_stack_height
, prev_max_vt_sp
, prev_total_locals_size
;
1754 int prev_n_data_items
;
1757 MonoGenericContext
*generic_context
= NULL
;
1758 StackInfo
*prev_param_area
;
1759 MonoMethod
*prev_inlined_method
;
1760 MonoMethodSignature
*csignature
= mono_method_signature_internal (target_method
);
1761 int nargs
= csignature
->param_count
+ !!csignature
->hasthis
;
1762 InterpInst
*prev_last_ins
;
1764 if (csignature
->is_inflated
)
1765 generic_context
= mono_method_get_context (target_method
);
1767 MonoGenericContainer
*generic_container
= mono_method_get_generic_container (target_method
);
1768 if (generic_container
)
1769 generic_context
= &generic_container
->context
;
1773 prev_il_code
= td
->il_code
;
1774 prev_in_start
= td
->in_start
;
1775 prev_sp_offset
= td
->sp
- td
->stack
;
1776 prev_vt_sp
= td
->vt_sp
;
1777 prev_inlined_method
= td
->inlined_method
;
1778 prev_last_ins
= td
->last_ins
;
1779 td
->inlined_method
= target_method
;
1781 prev_max_stack_height
= td
->max_stack_height
;
1782 prev_max_vt_sp
= td
->max_vt_sp
;
1783 prev_total_locals_size
= td
->total_locals_size
;
1785 prev_n_data_items
= td
->n_data_items
;
1786 prev_in_offsets
= td
->in_offsets
;
1787 td
->in_offsets
= (int*)g_malloc0((header
->code_size
+ 1) * sizeof(int));
1789 /* Inlining pops the arguments, restore the stack */
1790 prev_param_area
= (StackInfo
*)g_malloc (nargs
* sizeof (StackInfo
));
1791 memcpy (prev_param_area
, &td
->sp
[-nargs
], nargs
* sizeof (StackInfo
));
1793 if (td
->verbose_level
)
1794 g_print ("Inline start method %s.%s\n", m_class_get_name (target_method
->klass
), target_method
->name
);
1795 ret
= generate_code (td
, target_method
, header
, generic_context
, error
);
1798 if (td
->verbose_level
)
1799 g_print ("Inline aborted method %s.%s\n", m_class_get_name (target_method
->klass
), target_method
->name
);
1800 td
->max_stack_height
= prev_max_stack_height
;
1801 td
->max_vt_sp
= prev_max_vt_sp
;
1802 td
->total_locals_size
= prev_total_locals_size
;
1805 /* Remove any newly added items */
1806 for (i
= prev_n_data_items
; i
< td
->n_data_items
; i
++) {
1807 g_hash_table_remove (td
->data_hash
, td
->data_items
[i
]);
1809 td
->n_data_items
= prev_n_data_items
;
1810 td
->sp
= td
->stack
+ prev_sp_offset
;
1811 memcpy (&td
->sp
[-nargs
], prev_param_area
, nargs
* sizeof (StackInfo
));
1812 td
->vt_sp
= prev_vt_sp
;
1813 td
->last_ins
= prev_last_ins
;
1815 td
->last_ins
->next
= NULL
;
1816 UnlockedIncrement (&mono_interp_stats
.inline_failures
);
1818 if (td
->verbose_level
)
1819 g_print ("Inline end method %s.%s\n", m_class_get_name (target_method
->klass
), target_method
->name
);
1820 UnlockedIncrement (&mono_interp_stats
.inlined_methods
);
1821 // Make sure we have an IR instruction associated with the now removed IL CALL
1822 // FIXME This could be prettier. We might be able to make inlining saner now that
1823 // that we can easily tweak the instruction list.
1824 if (!prev_inlined_method
) {
1825 if (prev_last_ins
) {
1826 if (prev_last_ins
->next
)
1827 prev_last_ins
->next
->il_offset
= prev_in_start
- prev_il_code
;
1828 } else if (td
->first_ins
) {
1829 td
->first_ins
->il_offset
= prev_in_start
- prev_il_code
;
1835 td
->in_start
= prev_in_start
;
1836 td
->il_code
= prev_il_code
;
1837 td
->inlined_method
= prev_inlined_method
;
1839 g_free (td
->in_offsets
);
1840 td
->in_offsets
= prev_in_offsets
;
1842 g_free (prev_param_area
);
1847 interp_constrained_box (TransformData
*td
, MonoDomain
*domain
, MonoClass
*constrained_class
, MonoMethodSignature
*csignature
, MonoError
*error
)
1849 int mt
= mint_type (m_class_get_byval_arg (constrained_class
));
1850 if (mono_class_is_nullable (constrained_class
)) {
1851 g_assert (mt
== MINT_TYPE_VT
);
1852 interp_add_ins (td
, MINT_BOX_NULLABLE
);
1853 td
->last_ins
->data
[0] = get_data_item_index (td
, constrained_class
);
1854 td
->last_ins
->data
[1] = csignature
->param_count
| ((td
->sp
- 1 - csignature
->param_count
)->type
!= STACK_TYPE_MP
? 0 : BOX_NOT_CLEAR_VT_SP
);
1856 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, constrained_class
, error
);
1857 return_if_nok (error
);
1859 if (mt
== MINT_TYPE_VT
) {
1860 interp_add_ins (td
, MINT_BOX_VT
);
1861 td
->last_ins
->data
[0] = get_data_item_index (td
, vtable
);
1862 td
->last_ins
->data
[1] = csignature
->param_count
| ((td
->sp
- 1 - csignature
->param_count
)->type
!= STACK_TYPE_MP
? 0 : BOX_NOT_CLEAR_VT_SP
);
1864 interp_add_ins (td
, MINT_BOX
);
1865 td
->last_ins
->data
[0] = get_data_item_index (td
, vtable
);
1866 td
->last_ins
->data
[1] = csignature
->param_count
;
1871 /* Return FALSE if error, including inline failure */
1873 interp_transform_call (TransformData
*td
, MonoMethod
*method
, MonoMethod
*target_method
, MonoDomain
*domain
, MonoGenericContext
*generic_context
, unsigned char *is_bb_start
, MonoClass
*constrained_class
, gboolean readonly
, MonoError
*error
, gboolean check_visibility
, gboolean save_last_error
)
1875 MonoImage
*image
= m_class_get_image (method
->klass
);
1876 MonoMethodSignature
*csignature
;
1877 int is_virtual
= *td
->ip
== CEE_CALLVIRT
;
1878 int calli
= *td
->ip
== CEE_CALLI
|| *td
->ip
== CEE_MONO_CALLI_EXTRA_ARG
;
1880 guint32 vt_stack_used
= 0;
1881 guint32 vt_res_size
= 0;
1885 int need_null_check
= is_virtual
;
1887 guint32 token
= read32 (td
->ip
+ 1);
1889 if (target_method
== NULL
) {
1892 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
1893 csignature
= (MonoMethodSignature
*)mono_method_get_wrapper_data (method
, token
);
1895 csignature
= mono_metadata_parse_signature_checked (image
, token
, error
);
1896 return_val_if_nok (error
, FALSE
);
1899 if (generic_context
) {
1900 csignature
= mono_inflate_generic_signature (csignature
, generic_context
, error
);
1901 return_val_if_nok (error
, FALSE
);
1905 * The compiled interp entry wrapper is passed to runtime_invoke instead of
1906 * the InterpMethod pointer. FIXME
1908 native
= csignature
->pinvoke
|| method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
;
1910 target_method
= NULL
;
1912 if (method
->wrapper_type
== MONO_WRAPPER_NONE
) {
1913 target_method
= mono_get_method_checked (image
, token
, NULL
, generic_context
, error
);
1914 return_val_if_nok (error
, FALSE
);
1916 target_method
= (MonoMethod
*)mono_method_get_wrapper_data (method
, token
);
1917 csignature
= mono_method_signature_internal (target_method
);
1919 if (generic_context
) {
1920 csignature
= mono_inflate_generic_signature (csignature
, generic_context
, error
);
1921 return_val_if_nok (error
, FALSE
);
1922 target_method
= mono_class_inflate_generic_method_checked (target_method
, generic_context
, error
);
1923 return_val_if_nok (error
, FALSE
);
1927 csignature
= mono_method_signature_internal (target_method
);
1930 if (check_visibility
&& target_method
&& !mono_method_can_access_method (method
, target_method
))
1931 interp_generate_mae_throw (td
, method
, target_method
);
1933 if (target_method
&& target_method
->string_ctor
) {
1934 /* Create the real signature */
1935 MonoMethodSignature
*ctor_sig
= mono_metadata_signature_dup_mempool (td
->mempool
, csignature
);
1936 ctor_sig
->ret
= m_class_get_byval_arg (mono_defaults
.string_class
);
1938 csignature
= ctor_sig
;
1942 if (target_method
&& interp_handle_intrinsics (td
, target_method
, constrained_class
, csignature
, readonly
, &op
))
1945 if (constrained_class
) {
1946 if (m_class_is_enumtype (constrained_class
) && !strcmp (target_method
->name
, "GetHashCode")) {
1947 /* Use the corresponding method from the base type to avoid boxing */
1948 MonoType
*base_type
= mono_class_enum_basetype_internal (constrained_class
);
1949 g_assert (base_type
);
1950 constrained_class
= mono_class_from_mono_type_internal (base_type
);
1951 target_method
= mono_class_get_method_from_name_checked (constrained_class
, target_method
->name
, 0, 0, error
);
1952 mono_error_assert_ok (error
);
1953 g_assert (target_method
);
1957 if (constrained_class
) {
1958 mono_class_setup_vtable (constrained_class
);
1959 if (mono_class_has_failure (constrained_class
)) {
1960 mono_error_set_for_class_failure (error
, constrained_class
);
1964 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
);
1966 target_method
= mono_get_method_constrained_with_method (image
, target_method
, constrained_class
, generic_context
, error
);
1968 g_print (" : %s::%s. %s (%p)\n", target_method
->klass
->name
, target_method
->name
, mono_signature_full_name (target_method
->signature
), target_method
);
1970 /* Intrinsics: Try again, it could be that `mono_get_method_constrained_with_method` resolves to a method that we can substitute */
1971 if (target_method
&& interp_handle_intrinsics (td
, target_method
, constrained_class
, csignature
, readonly
, &op
))
1974 return_val_if_nok (error
, FALSE
);
1975 mono_class_setup_vtable (target_method
->klass
);
1977 if (!m_class_is_valuetype (constrained_class
)) {
1978 /* managed pointer on the stack, we need to deref that puppy */
1979 interp_add_ins (td
, MINT_LDIND_I
);
1980 td
->last_ins
->data
[0] = csignature
->param_count
;
1981 } 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
) {
1982 if (target_method
->klass
== mono_defaults
.enum_class
&& (td
->sp
- csignature
->param_count
- 1)->type
== STACK_TYPE_MP
) {
1983 /* managed pointer on the stack, we need to deref that puppy */
1984 /* Always load the entire stackval, to handle also the case where the enum has long storage */
1985 interp_add_ins (td
, MINT_LDIND_I8
);
1986 td
->last_ins
->data
[0] = csignature
->param_count
;
1989 interp_constrained_box (td
, domain
, constrained_class
, csignature
, error
);
1990 return_val_if_nok (error
, FALSE
);
1992 if (target_method
->klass
!= constrained_class
) {
1994 * The type parameter is instantiated as a valuetype,
1995 * but that type doesn't override the method we're
1996 * calling, so we need to box `this'.
1998 if (target_method
->klass
== mono_defaults
.enum_class
&& (td
->sp
- csignature
->param_count
- 1)->type
== STACK_TYPE_MP
) {
1999 /* managed pointer on the stack, we need to deref that puppy */
2000 /* Always load the entire stackval, to handle also the case where the enum has long storage */
2001 interp_add_ins (td
, MINT_LDIND_I8
);
2002 td
->last_ins
->data
[0] = csignature
->param_count
;
2005 interp_constrained_box (td
, domain
, constrained_class
, csignature
, error
);
2006 return_val_if_nok (error
, FALSE
);
2013 mono_class_init_internal (target_method
->klass
);
2015 if (!is_virtual
&& target_method
&& (target_method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
)) {
2016 if (!mono_class_is_interface (method
->klass
))
2017 interp_generate_bie_throw (td
);
2022 if (is_virtual
&& target_method
&& (!(target_method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) ||
2023 (MONO_METHOD_IS_FINAL (target_method
) &&
2024 target_method
->wrapper_type
!= MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
)) &&
2025 !(mono_class_is_marshalbyref (target_method
->klass
))) {
2026 /* Not really virtual, just needs a null check */
2028 need_null_check
= TRUE
;
2031 CHECK_STACK (td
, csignature
->param_count
+ csignature
->hasthis
);
2032 if (!td
->gen_sdb_seq_points
&& !calli
&& op
== -1 && (!is_virtual
|| (target_method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) == 0) &&
2033 (target_method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) == 0 &&
2034 (target_method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) == 0 &&
2035 !(target_method
->iflags
& METHOD_IMPL_ATTRIBUTE_NOINLINING
)) {
2036 (void)mono_class_vtable_checked (domain
, target_method
->klass
, error
);
2037 return_val_if_nok (error
, FALSE
);
2039 if (method
== target_method
&& *(td
->ip
+ 5) == CEE_RET
&& !(csignature
->hasthis
&& m_class_is_valuetype (target_method
->klass
))) {
2040 if (td
->inlined_method
)
2043 if (td
->verbose_level
)
2044 g_print ("Optimize tail call of %s.%s\n", m_class_get_name (target_method
->klass
), target_method
->name
);
2046 for (i
= csignature
->param_count
- 1 + !!csignature
->hasthis
; i
>= 0; --i
)
2049 interp_add_ins (td
, MINT_BR_S
);
2050 // We are branching to the beginning of the method
2051 td
->last_ins
->data
[0] = 0;
2052 if (!is_bb_start
[td
->ip
+ 5 - td
->il_code
])
2053 ++td
->ip
; /* gobble the CEE_RET if it isn't branched to */
2059 target_method
= interp_transform_internal_calls (method
, target_method
, csignature
, is_virtual
);
2061 if (csignature
->call_convention
== MONO_CALL_VARARG
) {
2062 csignature
= mono_method_get_signature_checked (target_method
, image
, token
, generic_context
, error
);
2063 int vararg_stack
= 0;
2065 * For vararg calls, ArgIterator expects the signature and the varargs to be
2066 * stored in a linear memory. We allocate the necessary vt_stack space for
2067 * this. All varargs will be pushed to the vt_stack at call site.
2069 vararg_stack
+= sizeof (gpointer
);
2070 for (i
= csignature
->sentinelpos
; i
< csignature
->param_count
; ++i
) {
2071 int align
, arg_size
;
2072 arg_size
= mono_type_stack_size (csignature
->params
[i
], &align
);
2073 vararg_stack
+= ALIGN_TO (arg_size
, align
);
2075 /* allocate space for the pointer to varargs space start */
2076 vararg_stack
+= sizeof (gpointer
);
2077 vt_stack_used
+= ALIGN_TO (vararg_stack
, MINT_VT_ALIGNMENT
);
2078 PUSH_VT (td
, vararg_stack
);
2081 if (need_null_check
) {
2082 interp_add_ins (td
, MINT_CKNULL_N
);
2083 td
->last_ins
->data
[0] = csignature
->param_count
+ 1;
2086 g_assert (csignature
->call_convention
!= MONO_CALL_FASTCALL
);
2087 if ((mono_interp_opt
& INTERP_OPT_INLINE
) && op
== -1 && !is_virtual
&& target_method
&& interp_method_check_inlining (td
, target_method
)) {
2088 MonoMethodHeader
*mheader
= interp_method_get_header (target_method
, error
);
2089 return_val_if_nok (error
, FALSE
);
2091 if (interp_inline_method (td
, target_method
, mheader
, error
)) {
2097 /* Don't inline methods that do calls */
2098 if (op
== -1 && td
->inlined_method
)
2101 /* We need to convert delegate invoke to a indirect call on the interp_invoke_impl field */
2102 if (target_method
&& m_class_get_parent (target_method
->klass
) == mono_defaults
.multicastdelegate_class
) {
2103 const char *name
= target_method
->name
;
2104 if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
2106 interp_add_ins (td
, MINT_LD_DELEGATE_INVOKE_IMPL
);
2107 td
->last_ins
->data
[0] = csignature
->param_count
+ 1;
2108 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
2112 /* Pop the function pointer */
2116 td
->sp
-= csignature
->param_count
+ !!csignature
->hasthis
;
2117 for (i
= 0; i
< csignature
->param_count
; ++i
) {
2118 if (td
->sp
[i
+ !!csignature
->hasthis
].type
== STACK_TYPE_VT
) {
2120 MonoClass
*klass
= mono_class_from_mono_type_internal (csignature
->params
[i
]);
2121 if (csignature
->pinvoke
&& method
->wrapper_type
!= MONO_WRAPPER_NONE
)
2122 size
= mono_class_native_size (klass
, NULL
);
2124 size
= mono_class_value_size (klass
, NULL
);
2125 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
2126 vt_stack_used
+= size
;
2130 /* need to handle typedbyref ... */
2131 if (csignature
->ret
->type
!= MONO_TYPE_VOID
) {
2132 int mt
= mint_type(csignature
->ret
);
2133 MonoClass
*klass
= mono_class_from_mono_type_internal (csignature
->ret
);
2134 if (mt
== MINT_TYPE_VT
) {
2135 if (csignature
->pinvoke
&& method
->wrapper_type
!= MONO_WRAPPER_NONE
)
2136 vt_res_size
= mono_class_native_size (klass
, NULL
);
2138 vt_res_size
= mono_class_value_size (klass
, NULL
);
2139 if (mono_class_has_failure (klass
)) {
2140 mono_error_set_for_class_failure (error
, klass
);
2143 PUSH_VT(td
, vt_res_size
);
2145 PUSH_TYPE(td
, stack_type
[mt
], klass
);
2150 interp_add_ins (td
, op
);
2152 if (op
== MINT_LDLEN
) {
2153 #ifdef MONO_BIG_ARRAYS
2154 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I8
);
2156 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I4
);
2159 if (op
== MINT_LDELEMA
|| op
== MINT_LDELEMA_TC
) {
2160 td
->last_ins
->data
[0] = get_data_item_index (td
, m_class_get_element_class (target_method
->klass
));
2161 td
->last_ins
->data
[1] = 1 + m_class_get_rank (target_method
->klass
);
2164 if (op
== MINT_CALLRUN
) {
2165 td
->last_ins
->data
[0] = get_data_item_index (td
, target_method
);
2166 td
->last_ins
->data
[1] = get_data_item_index (td
, mono_method_signature_internal (target_method
));
2168 } else if (!calli
&& !is_virtual
&& jit_call_supported (target_method
, csignature
)) {
2169 interp_add_ins (td
, MINT_JIT_CALL
);
2170 td
->last_ins
->data
[0] = get_data_item_index (td
, (void *)mono_interp_get_imethod (domain
, target_method
, error
));
2171 mono_error_assert_ok (error
);
2173 #ifndef MONO_ARCH_HAS_NO_PROPER_MONOCTX
2174 /* Try using fast icall path for simple signatures */
2175 if (native
&& !method
->dynamic
)
2176 op
= interp_icall_op_for_sig (csignature
);
2178 if (csignature
->call_convention
== MONO_CALL_VARARG
)
2179 interp_add_ins (td
, MINT_CALL_VARARG
);
2181 interp_add_ins (td
, native
? ((op
!= -1) ? MINT_CALLI_NAT_FAST
: MINT_CALLI_NAT
) : MINT_CALLI
);
2182 else if (is_virtual
&& !mono_class_is_marshalbyref (target_method
->klass
))
2183 interp_add_ins (td
, is_void
? MINT_VCALLVIRT_FAST
: MINT_CALLVIRT_FAST
);
2184 else if (is_virtual
)
2185 interp_add_ins (td
, is_void
? MINT_VCALLVIRT
: MINT_CALLVIRT
);
2187 interp_add_ins (td
, is_void
? MINT_VCALL
: MINT_CALL
);
2190 td
->last_ins
->data
[0] = get_data_item_index (td
, (void *)csignature
);
2192 td
->last_ins
->data
[1] = op
;
2193 if (td
->last_ins
->opcode
== MINT_CALLI_NAT_FAST
)
2194 td
->last_ins
->data
[2] = save_last_error
;
2195 } else if (op
== -1 && td
->last_ins
->opcode
== MINT_CALLI_NAT
) {
2196 td
->last_ins
->data
[1] = save_last_error
;
2199 td
->last_ins
->data
[0] = get_data_item_index (td
, (void *)mono_interp_get_imethod (domain
, target_method
, error
));
2200 return_val_if_nok (error
, FALSE
);
2201 if (csignature
->call_convention
== MONO_CALL_VARARG
)
2202 td
->last_ins
->data
[1] = get_data_item_index (td
, (void *)csignature
);
2203 else if (is_virtual
&& !mono_class_is_marshalbyref (target_method
->klass
)) {
2204 /* FIXME Use fastpath also for MBRO. Asserts in mono_method_get_vtable_slot */
2205 if (mono_class_is_interface (target_method
->klass
))
2206 td
->last_ins
->data
[1] = -2 * MONO_IMT_SIZE
+ mono_method_get_imt_slot (target_method
);
2208 td
->last_ins
->data
[1] = mono_method_get_vtable_slot (target_method
);
2213 if (vt_stack_used
!= 0 || vt_res_size
!= 0) {
2214 interp_add_ins (td
, MINT_VTRESULT
);
2215 td
->last_ins
->data
[0] = vt_res_size
;
2216 WRITE32_INS (td
->last_ins
, 1, &vt_stack_used
);
2217 td
->vt_sp
-= vt_stack_used
;
2223 static MonoClassField
*
2224 interp_field_from_token (MonoMethod
*method
, guint32 token
, MonoClass
**klass
, MonoGenericContext
*generic_context
, MonoError
*error
)
2226 MonoClassField
*field
= NULL
;
2227 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
2228 field
= (MonoClassField
*) mono_method_get_wrapper_data (method
, token
);
2229 *klass
= field
->parent
;
2231 mono_class_setup_fields (field
->parent
);
2233 field
= mono_field_from_token_checked (m_class_get_image (method
->klass
), token
, klass
, generic_context
, error
);
2234 return_val_if_nok (error
, NULL
);
2237 if (!method
->skip_visibility
&& !mono_method_can_access_field (method
, field
)) {
2238 char *method_fname
= mono_method_full_name (method
, TRUE
);
2239 char *field_fname
= mono_field_full_name (field
);
2240 mono_error_set_generic_error (error
, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname
, method_fname
);
2241 g_free (method_fname
);
2242 g_free (field_fname
);
2249 static InterpBasicBlock
*
2250 get_bb (TransformData
*td
, InterpBasicBlock
*cbb
, unsigned char *ip
)
2252 int offset
= ip
- td
->il_code
;
2253 InterpBasicBlock
*bb
= td
->offset_to_bb
[offset
];
2256 bb
= (InterpBasicBlock
*)mono_mempool_alloc0 (td
->mempool
, sizeof (InterpBasicBlock
));
2258 td
->offset_to_bb
[offset
] = bb
;
2260 td
->basic_blocks
= g_list_append_mempool (td
->mempool
, td
->basic_blocks
, bb
);
2264 bb
->preds
= g_slist_prepend_mempool (td
->mempool
, bb
->preds
, cbb
);
2271 * Compute the set of IL level basic blocks.
2274 get_basic_blocks (TransformData
*td
)
2276 guint8
*start
= (guint8
*)td
->il_code
;
2277 guint8
*end
= (guint8
*)td
->il_code
+ td
->code_size
;
2279 unsigned char *target
;
2282 const MonoOpcode
*opcode
;
2283 InterpBasicBlock
*cbb
;
2285 td
->offset_to_bb
= (InterpBasicBlock
**)mono_mempool_alloc0 (td
->mempool
, sizeof (InterpBasicBlock
*) * (end
- start
+ 1));
2286 td
->entry_bb
= cbb
= get_bb (td
, NULL
, start
);
2289 cli_addr
= ip
- start
;
2290 td
->offset_to_bb
[cli_addr
] = cbb
;
2291 i
= mono_opcode_value ((const guint8
**)&ip
, end
);
2292 opcode
= &mono_opcodes
[i
];
2293 switch (opcode
->argument
) {
2294 case MonoInlineNone
:
2297 case MonoInlineString
:
2298 case MonoInlineType
:
2299 case MonoInlineField
:
2300 case MonoInlineMethod
:
2303 case MonoShortInlineR
:
2310 case MonoShortInlineVar
:
2311 case MonoShortInlineI
:
2314 case MonoShortInlineBrTarget
:
2315 target
= start
+ cli_addr
+ 2 + (signed char)ip
[1];
2316 get_bb (td
, cbb
, target
);
2318 cbb
= get_bb (td
, cbb
, ip
);
2320 case MonoInlineBrTarget
:
2321 target
= start
+ cli_addr
+ 5 + (gint32
)read32 (ip
+ 1);
2322 get_bb (td
, cbb
, target
);
2324 cbb
= get_bb (td
, cbb
, ip
);
2326 case MonoInlineSwitch
: {
2327 guint32 n
= read32 (ip
+ 1);
2330 cli_addr
+= 5 + 4 * n
;
2331 target
= start
+ cli_addr
;
2332 get_bb (td
, cbb
, target
);
2334 for (j
= 0; j
< n
; ++j
) {
2335 target
= start
+ cli_addr
+ (gint32
)read32 (ip
);
2336 get_bb (td
, cbb
, target
);
2339 cbb
= get_bb (td
, cbb
, ip
);
2347 g_assert_not_reached ();
2351 cbb
= get_bb (td
, NULL
, ip
);
2356 interp_save_debug_info (InterpMethod
*rtm
, MonoMethodHeader
*header
, TransformData
*td
, GArray
*line_numbers
)
2358 MonoDebugMethodJitInfo
*dinfo
;
2361 if (!mono_debug_enabled ())
2365 * We save the debug info in the same way the JIT does it, treating the interpreter IR as the native code.
2368 dinfo
= g_new0 (MonoDebugMethodJitInfo
, 1);
2369 dinfo
->num_params
= rtm
->param_count
;
2370 dinfo
->params
= g_new0 (MonoDebugVarInfo
, dinfo
->num_params
);
2371 dinfo
->num_locals
= header
->num_locals
;
2372 dinfo
->locals
= g_new0 (MonoDebugVarInfo
, header
->num_locals
);
2373 dinfo
->code_start
= (guint8
*)rtm
->code
;
2374 dinfo
->code_size
= td
->new_code_end
- td
->new_code
;
2375 dinfo
->epilogue_begin
= 0;
2376 dinfo
->has_var_info
= TRUE
;
2377 dinfo
->num_line_numbers
= line_numbers
->len
;
2378 dinfo
->line_numbers
= g_new0 (MonoDebugLineNumberEntry
, dinfo
->num_line_numbers
);
2380 for (i
= 0; i
< dinfo
->num_params
; i
++) {
2381 MonoDebugVarInfo
*var
= &dinfo
->params
[i
];
2382 var
->type
= rtm
->param_types
[i
];
2384 for (i
= 0; i
< dinfo
->num_locals
; i
++) {
2385 MonoDebugVarInfo
*var
= &dinfo
->locals
[i
];
2386 var
->type
= mono_metadata_type_dup (NULL
, header
->locals
[i
]);
2389 for (i
= 0; i
< dinfo
->num_line_numbers
; i
++)
2390 dinfo
->line_numbers
[i
] = g_array_index (line_numbers
, MonoDebugLineNumberEntry
, i
);
2391 mono_debug_add_method (rtm
->method
, dinfo
, rtm
->domain
);
2393 mono_debug_free_method_jit_info (dinfo
);
2396 /* Same as the code in seq-points.c */
2398 insert_pred_seq_point (SeqPoint
*last_sp
, SeqPoint
*sp
, GSList
**next
)
2401 int src_index
= last_sp
->next_offset
;
2402 int dst_index
= sp
->next_offset
;
2404 /* bb->in_bb might contain duplicates */
2405 for (l
= next
[src_index
]; l
; l
= l
->next
)
2406 if (GPOINTER_TO_UINT (l
->data
) == dst_index
)
2409 next
[src_index
] = g_slist_append (next
[src_index
], GUINT_TO_POINTER (dst_index
));
2413 recursively_make_pred_seq_points (TransformData
*td
, InterpBasicBlock
*bb
)
2415 SeqPoint
** const MONO_SEQ_SEEN_LOOP
= (SeqPoint
**)GINT_TO_POINTER(-1);
2418 GArray
*predecessors
= g_array_new (FALSE
, TRUE
, sizeof (gpointer
));
2419 GHashTable
*seen
= g_hash_table_new_full (g_direct_hash
, NULL
, NULL
, NULL
);
2421 // Insert/remove sentinel into the memoize table to detect loops containing bb
2422 bb
->pred_seq_points
= MONO_SEQ_SEEN_LOOP
;
2424 for (l
= bb
->preds
; l
; l
= l
->next
) {
2425 InterpBasicBlock
*in_bb
= (InterpBasicBlock
*)l
->data
;
2427 // This bb has the last seq point, append it and continue
2428 if (in_bb
->last_seq_point
!= NULL
) {
2429 predecessors
= g_array_append_val (predecessors
, in_bb
->last_seq_point
);
2433 // We've looped or handled this before, exit early.
2434 // No last sequence points to find.
2435 if (in_bb
->pred_seq_points
== MONO_SEQ_SEEN_LOOP
)
2438 // Take sequence points from incoming basic blocks
2440 if (in_bb
== td
->entry_bb
)
2443 if (in_bb
->pred_seq_points
== NULL
)
2444 recursively_make_pred_seq_points (td
, in_bb
);
2446 // Union sequence points with incoming bb's
2447 for (int i
=0; i
< in_bb
->num_pred_seq_points
; i
++) {
2448 if (!g_hash_table_lookup (seen
, in_bb
->pred_seq_points
[i
])) {
2449 g_array_append_val (predecessors
, in_bb
->pred_seq_points
[i
]);
2450 g_hash_table_insert (seen
, in_bb
->pred_seq_points
[i
], (gpointer
)&MONO_SEQ_SEEN_LOOP
);
2453 // predecessors = g_array_append_vals (predecessors, in_bb->pred_seq_points, in_bb->num_pred_seq_points);
2456 g_hash_table_destroy (seen
);
2458 if (predecessors
->len
!= 0) {
2459 bb
->pred_seq_points
= (SeqPoint
**)mono_mempool_alloc0 (td
->mempool
, sizeof (SeqPoint
*) * predecessors
->len
);
2460 bb
->num_pred_seq_points
= predecessors
->len
;
2462 for (int newer
= 0; newer
< bb
->num_pred_seq_points
; newer
++) {
2463 bb
->pred_seq_points
[newer
] = (SeqPoint
*)g_array_index (predecessors
, gpointer
, newer
);
2467 g_array_free (predecessors
, TRUE
);
2471 collect_pred_seq_points (TransformData
*td
, InterpBasicBlock
*bb
, SeqPoint
*seqp
, GSList
**next
)
2473 // Doesn't have a last sequence point, must find from incoming basic blocks
2474 if (bb
->pred_seq_points
== NULL
&& bb
!= td
->entry_bb
)
2475 recursively_make_pred_seq_points (td
, bb
);
2477 for (int i
= 0; i
< bb
->num_pred_seq_points
; i
++)
2478 insert_pred_seq_point (bb
->pred_seq_points
[i
], seqp
, next
);
2484 save_seq_points (TransformData
*td
, MonoJitInfo
*jinfo
)
2487 int i
, seq_info_size
;
2488 MonoSeqPointInfo
*info
;
2489 GSList
**next
= NULL
;
2492 if (!td
->gen_sdb_seq_points
)
2496 * For each sequence point, compute the list of sequence points immediately
2497 * following it, this is needed to implement 'step over' in the debugger agent.
2498 * Similar to the code in mono_save_seq_point_info ().
2500 for (i
= 0; i
< td
->seq_points
->len
; ++i
) {
2501 SeqPoint
*sp
= (SeqPoint
*)g_ptr_array_index (td
->seq_points
, i
);
2503 /* Store the seq point index here temporarily */
2504 sp
->next_offset
= i
;
2506 next
= (GSList
**)mono_mempool_alloc0 (td
->mempool
, sizeof (GList
*) * td
->seq_points
->len
);
2507 for (bblist
= td
->basic_blocks
; bblist
; bblist
= bblist
->next
) {
2508 InterpBasicBlock
*bb
= (InterpBasicBlock
*)bblist
->data
;
2510 GSList
*bb_seq_points
= g_slist_reverse (bb
->seq_points
);
2511 SeqPoint
*last
= NULL
;
2512 for (GSList
*l
= bb_seq_points
; l
; l
= l
->next
) {
2513 SeqPoint
*sp
= (SeqPoint
*)l
->data
;
2515 if (sp
->il_offset
== METHOD_ENTRY_IL_OFFSET
|| sp
->il_offset
== METHOD_EXIT_IL_OFFSET
)
2516 /* Used to implement method entry/exit events */
2520 /* Link with the previous seq point in the same bb */
2521 next
[last
->next_offset
] = g_slist_append_mempool (td
->mempool
, next
[last
->next_offset
], GINT_TO_POINTER (sp
->next_offset
));
2523 /* Link with the last bb in the previous bblocks */
2524 collect_pred_seq_points (td
, bb
, sp
, next
);
2530 /* Serialize the seq points into a byte array */
2531 array
= g_byte_array_new ();
2532 SeqPoint zero_seq_point
= {0};
2533 SeqPoint
* last_seq_point
= &zero_seq_point
;
2534 for (i
= 0; i
< td
->seq_points
->len
; ++i
) {
2535 SeqPoint
*sp
= (SeqPoint
*)g_ptr_array_index (td
->seq_points
, i
);
2537 sp
->next_offset
= 0;
2538 if (mono_seq_point_info_add_seq_point (array
, sp
, last_seq_point
, next
[i
], TRUE
))
2539 last_seq_point
= sp
;
2542 if (td
->verbose_level
) {
2543 g_print ("\nSEQ POINT MAP FOR %s: \n", td
->method
->name
);
2545 for (i
= 0; i
< td
->seq_points
->len
; ++i
) {
2546 SeqPoint
*sp
= (SeqPoint
*)g_ptr_array_index (td
->seq_points
, i
);
2552 g_print ("\tIL0x%x[0x%0x] ->", sp
->il_offset
, sp
->native_offset
);
2553 for (l
= next
[i
]; l
; l
= l
->next
) {
2554 int next_index
= GPOINTER_TO_UINT (l
->data
);
2555 g_print (" IL0x%x", ((SeqPoint
*)g_ptr_array_index (td
->seq_points
, next_index
))->il_offset
);
2561 info
= mono_seq_point_info_new (array
->len
, TRUE
, array
->data
, TRUE
, &seq_info_size
);
2562 mono_atomic_fetch_add_i32 (&mono_jit_stats
.allocated_seq_points_size
, seq_info_size
);
2564 g_byte_array_free (array
, TRUE
);
2566 jinfo
->seq_points
= info
;
2569 #define BARRIER_IF_VOLATILE(td) \
2572 interp_add_ins (td, MINT_MONO_MEMORY_BARRIER); \
2573 volatile_ = FALSE; \
2577 #define INLINE_FAILURE \
2584 interp_method_compute_offsets (InterpMethod
*imethod
, MonoMethodSignature
*signature
, MonoMethodHeader
*header
)
2586 int i
, offset
, size
, align
;
2588 imethod
->local_offsets
= (guint32
*)g_malloc (header
->num_locals
* sizeof(guint32
));
2590 for (i
= 0; i
< header
->num_locals
; ++i
) {
2591 size
= mono_type_size (header
->locals
[i
], &align
);
2592 offset
+= align
- 1;
2593 offset
&= ~(align
- 1);
2594 imethod
->local_offsets
[i
] = offset
;
2597 offset
= (offset
+ 7) & ~7;
2599 imethod
->exvar_offsets
= (guint32
*)g_malloc (header
->num_clauses
* sizeof (guint32
));
2600 for (i
= 0; i
< header
->num_clauses
; i
++) {
2601 imethod
->exvar_offsets
[i
] = offset
;
2602 offset
+= sizeof (MonoObject
*);
2604 offset
= (offset
+ 7) & ~7;
2606 imethod
->locals_size
= offset
;
2607 g_assert (imethod
->locals_size
< 65536);
2611 get_arg_type (MonoMethodSignature
*signature
, int arg_n
)
2613 if (signature
->hasthis
&& arg_n
== 0)
2614 return mono_get_object_type ();
2615 return signature
->params
[arg_n
- !!signature
->hasthis
];
2618 /* Return false is failure to init basic blocks due to being in inline method */
2620 init_bb_start (TransformData
*td
, MonoMethodHeader
*header
, gboolean inlining
)
2622 const unsigned char *ip
, *end
;
2623 const MonoOpcode
*opcode
;
2624 int offset
, i
, in
, backwards
;
2626 /* intern the strings in the method. */
2628 end
= ip
+ header
->code_size
;
2630 /* inlined method continues the basic block of parent method */
2632 td
->is_bb_start
[0] = 1;
2639 else if (in
== 0xf0) {
2641 in
= *ip
+ MONO_CEE_MONO_ICALL
;
2643 opcode
= &mono_opcodes
[in
];
2644 switch (opcode
->argument
) {
2645 case MonoInlineNone
:
2648 case MonoInlineString
:
2651 case MonoInlineType
:
2654 case MonoInlineMethod
:
2657 case MonoInlineField
:
2661 case MonoShortInlineR
:
2664 case MonoInlineBrTarget
:
2665 offset
= read32 (ip
+ 1);
2667 /* this branch is ignored */
2668 if (offset
== 0 && in
== MONO_CEE_BR
)
2670 backwards
= offset
< 0;
2671 offset
+= ip
- header
->code
;
2672 g_assert (offset
>= 0 && offset
< header
->code_size
);
2675 td
->is_bb_start
[offset
] |= backwards
? 2 : 1;
2677 case MonoShortInlineBrTarget
:
2678 offset
= ((gint8
*)ip
) [1];
2680 /* this branch is ignored */
2681 if (offset
== 0 && in
== MONO_CEE_BR_S
)
2683 backwards
= offset
< 0;
2684 offset
+= ip
- header
->code
;
2685 g_assert (offset
>= 0 && offset
< header
->code_size
);
2688 td
->is_bb_start
[offset
] |= backwards
? 2 : 1;
2693 case MonoShortInlineVar
:
2694 case MonoShortInlineI
:
2697 case MonoInlineSwitch
: {
2699 const unsigned char *next_ip
;
2703 next_ip
= ip
+ 4 * n
;
2704 for (i
= 0; i
< n
; i
++) {
2705 offset
= read32 (ip
);
2706 backwards
= offset
< 0;
2707 offset
+= next_ip
- header
->code
;
2708 g_assert (offset
>= 0 && offset
< header
->code_size
);
2711 td
->is_bb_start
[offset
] |= backwards
? 2 : 1;
2721 g_assert_not_reached ();
2727 #ifdef NO_UNALIGNED_ACCESS
2729 get_unaligned_opcode (int opcode
)
2733 return MINT_LDFLD_I8_UNALIGNED
;
2735 return MINT_LDFLD_R8_UNALIGNED
;
2737 return MINT_STFLD_I8_UNALIGNED
;
2739 return MINT_STFLD_R8_UNALIGNED
;
2741 g_assert_not_reached ();
2748 interp_handle_isinst (TransformData
*td
, MonoClass
*klass
, gboolean isinst_instr
)
2750 /* Follow the logic from jit's handle_isinst */
2751 if (!mono_class_has_variant_generic_params (klass
)) {
2752 if (mono_class_is_interface (klass
))
2753 interp_add_ins (td
, isinst_instr
? MINT_ISINST_INTERFACE
: MINT_CASTCLASS_INTERFACE
);
2754 else if (!mono_class_is_marshalbyref (klass
) && m_class_get_rank (klass
) == 0 && !mono_class_is_nullable (klass
))
2755 interp_add_ins (td
, isinst_instr
? MINT_ISINST_COMMON
: MINT_CASTCLASS_COMMON
);
2757 interp_add_ins (td
, isinst_instr
? MINT_ISINST
: MINT_CASTCLASS
);
2759 interp_add_ins (td
, isinst_instr
? MINT_ISINST
: MINT_CASTCLASS
);
2761 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
2766 interp_emit_ldobj (TransformData
*td
, MonoClass
*klass
)
2768 int mt
= mint_type (m_class_get_byval_arg (klass
));
2771 if (mt
== MINT_TYPE_VT
) {
2772 interp_add_ins (td
, MINT_LDOBJ_VT
);
2773 size
= mono_class_value_size (klass
, NULL
);
2774 WRITE32_INS (td
->last_ins
, 0, &size
);
2777 int opcode
= interp_get_ldind_for_mt (mt
);
2778 interp_add_ins (td
, opcode
);
2781 SET_TYPE (td
->sp
- 1, stack_type
[mt
], klass
);
2785 interp_emit_stobj (TransformData
*td
, MonoClass
*klass
)
2787 int mt
= mint_type (m_class_get_byval_arg (klass
));
2789 if (mt
== MINT_TYPE_VT
) {
2791 interp_add_ins (td
, MINT_STOBJ_VT
);
2792 td
->last_ins
->data
[0] = get_data_item_index(td
, klass
);
2793 size
= mono_class_value_size (klass
, NULL
);
2800 opcode
= MINT_STIND_I1
;
2804 opcode
= MINT_STIND_I2
;
2807 opcode
= MINT_STIND_I4
;
2810 opcode
= MINT_STIND_I8
;
2813 opcode
= MINT_STIND_R4
;
2816 opcode
= MINT_STIND_R8
;
2819 opcode
= MINT_STIND_REF
;
2821 default: g_assert_not_reached (); break;
2823 interp_add_ins (td
, opcode
);
2829 interp_emit_ldsflda (TransformData
*td
, MonoClassField
*field
, MonoError
*error
)
2831 MonoDomain
*domain
= td
->rtm
->domain
;
2832 // Initialize the offset for the field
2833 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, field
->parent
, error
);
2834 return_if_nok (error
);
2836 if (mono_class_field_is_special_static (field
)) {
2839 mono_domain_lock (domain
);
2840 g_assert (domain
->special_static_fields
);
2841 offset
= GPOINTER_TO_UINT (g_hash_table_lookup (domain
->special_static_fields
, field
));
2842 mono_domain_unlock (domain
);
2845 interp_add_ins (td
, MINT_LDSSFLDA
);
2846 WRITE32_INS(td
->last_ins
, 0, &offset
);
2848 interp_add_ins (td
, MINT_LDSFLDA
);
2849 td
->last_ins
->data
[0] = get_data_item_index (td
, vtable
);
2850 td
->last_ins
->data
[1] = get_data_item_index (td
, (char*)mono_vtable_get_static_field_data (vtable
) + field
->offset
);
2855 interp_emit_sfld_access (TransformData
*td
, MonoClassField
*field
, MonoClass
*field_class
, int mt
, gboolean is_load
, MonoError
*error
)
2857 MonoDomain
*domain
= td
->rtm
->domain
;
2858 // Initialize the offset for the field
2859 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, field
->parent
, error
);
2860 return_if_nok (error
);
2862 if (mono_class_field_is_special_static (field
)) {
2865 mono_domain_lock (domain
);
2866 g_assert (domain
->special_static_fields
);
2867 offset
= GPOINTER_TO_UINT (g_hash_table_lookup (domain
->special_static_fields
, field
));
2868 mono_domain_unlock (domain
);
2871 // Offset is SpecialStaticOffset
2872 if ((offset
& 0x80000000) == 0 && mt
!= MINT_TYPE_VT
) {
2873 // This field is thread static
2874 interp_add_ins (td
, (is_load
? MINT_LDTSFLD_I1
: MINT_STTSFLD_I1
) + mt
);
2875 WRITE32_INS(td
->last_ins
, 0, &offset
);
2877 if (mt
== MINT_TYPE_VT
) {
2878 interp_add_ins (td
, is_load
? MINT_LDSSFLD_VT
: MINT_STSSFLD_VT
);
2879 WRITE32_INS(td
->last_ins
, 0, &offset
);
2881 int size
= mono_class_value_size (field_class
, NULL
);
2882 WRITE32_INS(td
->last_ins
, 2, &size
);
2884 interp_add_ins (td
, is_load
? MINT_LDSSFLD
: MINT_STSSFLD
);
2885 td
->last_ins
->data
[0] = get_data_item_index (td
, field
);
2886 WRITE32_INS(td
->last_ins
, 1, &offset
);
2891 interp_add_ins (td
, (mt
== MINT_TYPE_VT
) ? MINT_LDSFLD_VT
: (MINT_LDSFLD_I1
+ mt
- MINT_TYPE_I1
));
2893 interp_add_ins (td
, (mt
== MINT_TYPE_VT
) ? MINT_STSFLD_VT
: (MINT_STSFLD_I1
+ mt
- MINT_TYPE_I1
));
2895 td
->last_ins
->data
[0] = get_data_item_index (td
, vtable
);
2896 td
->last_ins
->data
[1] = get_data_item_index (td
, (char*)mono_vtable_get_static_field_data (vtable
) + field
->offset
);
2898 if (mt
== MINT_TYPE_VT
) {
2899 int size
= mono_class_value_size (field_class
, NULL
);
2900 WRITE32_INS(td
->last_ins
, 2, &size
);
2906 generate_code (TransformData
*td
, MonoMethod
*method
, MonoMethodHeader
*header
, MonoGenericContext
*generic_context
, MonoError
*error
)
2909 int offset
, mt
, i
, i32
;
2912 const unsigned char *end
;
2913 MonoSimpleBasicBlock
*bb
= NULL
, *original_bb
= NULL
;
2914 gboolean sym_seq_points
= FALSE
;
2915 MonoBitSet
*seq_point_locs
= NULL
;
2916 gboolean readonly
= FALSE
;
2917 gboolean volatile_
= FALSE
;
2918 MonoClass
*constrained_class
= NULL
;
2920 MonoClassField
*field
;
2921 MonoImage
*image
= m_class_get_image (method
->klass
);
2922 InterpMethod
*rtm
= td
->rtm
;
2923 MonoDomain
*domain
= rtm
->domain
;
2924 MonoMethodSignature
*signature
= mono_method_signature_internal (method
);
2925 gboolean ret
= TRUE
;
2926 gboolean emitted_funccall_seq_point
= FALSE
;
2927 guint32
*arg_offsets
= NULL
;
2928 guint32
*local_offsets
= NULL
;
2929 InterpInst
*last_seq_point
= NULL
;
2930 gboolean save_last_error
= FALSE
;
2931 gboolean inlining
= td
->method
!= method
;
2933 original_bb
= bb
= mono_basic_block_split (method
, error
, header
);
2934 goto_if_nok (error
, exit
);
2937 td
->il_code
= header
->code
;
2938 td
->in_start
= td
->ip
= header
->code
;
2939 end
= td
->ip
+ header
->code_size
;
2941 if (!init_bb_start (td
, header
, inlining
))
2945 for (i
= 0; i
< header
->code_size
; i
++) {
2946 td
->stack_height
[i
] = -1;
2947 td
->clause_indexes
[i
] = -1;
2951 for (i
= 0; i
< header
->num_clauses
; i
++) {
2952 MonoExceptionClause
*c
= header
->clauses
+ i
;
2953 td
->stack_height
[c
->handler_offset
] = 0;
2954 td
->vt_stack_size
[c
->handler_offset
] = 0;
2955 td
->is_bb_start
[c
->handler_offset
] = 1;
2956 td
->is_bb_start
[c
->try_offset
] = 1;
2958 td
->stack_height
[c
->handler_offset
] = 1;
2959 td
->stack_state
[c
->handler_offset
] = (StackInfo
*)g_malloc0(sizeof(StackInfo
));
2960 td
->stack_state
[c
->handler_offset
][0].type
= STACK_TYPE_O
;
2961 td
->stack_state
[c
->handler_offset
][0].klass
= NULL
; /*FIX*/
2963 if (c
->flags
& MONO_EXCEPTION_CLAUSE_FILTER
) {
2964 td
->stack_height
[c
->data
.filter_offset
] = 0;
2965 td
->vt_stack_size
[c
->data
.filter_offset
] = 0;
2966 td
->is_bb_start
[c
->data
.filter_offset
] = 1;
2968 td
->stack_height
[c
->data
.filter_offset
] = 1;
2969 td
->stack_state
[c
->data
.filter_offset
] = (StackInfo
*)g_malloc0(sizeof(StackInfo
));
2970 td
->stack_state
[c
->data
.filter_offset
][0].type
= STACK_TYPE_O
;
2971 td
->stack_state
[c
->data
.filter_offset
][0].klass
= NULL
; /*FIX*/
2974 for (int j
= c
->handler_offset
; j
< c
->handler_offset
+ c
->handler_len
; ++j
) {
2975 if (td
->clause_indexes
[j
] == -1)
2976 td
->clause_indexes
[j
] = i
;
2980 if (td
->gen_sdb_seq_points
&& !inlining
) {
2981 MonoDebugMethodInfo
*minfo
;
2982 get_basic_blocks (td
);
2984 minfo
= mono_debug_lookup_method (method
);
2987 MonoSymSeqPoint
*sps
;
2988 int i
, n_il_offsets
;
2990 mono_debug_get_seq_points (minfo
, NULL
, NULL
, NULL
, &sps
, &n_il_offsets
);
2992 seq_point_locs
= mono_bitset_mem_new (mono_mempool_alloc0 (td
->mempool
, mono_bitset_alloc_size (header
->code_size
, 0)), header
->code_size
, 0);
2993 sym_seq_points
= TRUE
;
2995 for (i
= 0; i
< n_il_offsets
; ++i
) {
2996 if (sps
[i
].il_offset
< header
->code_size
)
2997 mono_bitset_set_fast (seq_point_locs
, sps
[i
].il_offset
);
3001 MonoDebugMethodAsyncInfo
* asyncMethod
= mono_debug_lookup_method_async_debug_info (method
);
3003 for (i
= 0; asyncMethod
!= NULL
&& i
< asyncMethod
->num_awaits
; i
++) {
3004 mono_bitset_set_fast (seq_point_locs
, asyncMethod
->resume_offsets
[i
]);
3005 mono_bitset_set_fast (seq_point_locs
, asyncMethod
->yield_offsets
[i
]);
3007 mono_debug_free_method_async_debug_info (asyncMethod
);
3009 } else if (!method
->wrapper_type
&& !method
->dynamic
&& mono_debug_image_has_debug_info (m_class_get_image (method
->klass
))) {
3010 /* Methods without line number info like auto-generated property accessors */
3011 seq_point_locs
= mono_bitset_new (header
->code_size
, 0);
3012 sym_seq_points
= TRUE
;
3016 if (sym_seq_points
) {
3017 last_seq_point
= interp_add_ins (td
, MINT_SDB_SEQ_POINT
);
3018 last_seq_point
->flags
= INTERP_INST_FLAG_SEQ_POINT_METHOD_ENTRY
;
3021 if (mono_debugger_method_has_breakpoint (method
))
3022 interp_add_ins (td
, MINT_BREAKPOINT
);
3025 if (td
->verbose_level
) {
3026 char *tmp
= mono_disasm_code (NULL
, method
, td
->ip
, end
);
3027 char *name
= mono_method_full_name (method
, TRUE
);
3028 g_print ("Method %s, original code:\n", name
);
3029 g_print ("%s\n", tmp
);
3034 if (header
->num_locals
&& header
->init_locals
)
3035 interp_add_ins (td
, MINT_INITLOCALS
);
3037 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (method
))
3038 interp_add_ins (td
, MINT_TRACE_ENTER
);
3039 else if (rtm
->prof_flags
& MONO_PROFILER_CALL_INSTRUMENTATION_ENTER
)
3040 interp_add_ins (td
, MINT_PROF_ENTER
);
3042 /* safepoint is required on method entry */
3043 if (mono_threads_are_safepoints_enabled ())
3044 interp_add_ins (td
, MINT_SAFEPOINT
);
3047 arg_offsets
= (guint32
*) g_malloc ((!!signature
->hasthis
+ signature
->param_count
) * sizeof (guint32
));
3048 /* Allocate locals to store inlined method args from stack */
3049 for (i
= signature
->param_count
- 1; i
>= 0; i
--) {
3050 offset
= create_interp_local (td
, signature
->params
[i
]);
3051 arg_offsets
[i
+ !!signature
->hasthis
] = offset
;
3052 store_local_general (td
, offset
, signature
->params
[i
]);
3055 if (signature
->hasthis
) {
3057 * If this is value type, it is passed by address and not by value.
3058 * FIXME We should use MINT_TYPE_P instead of MINT_TYPE_O
3060 MonoType
*type
= mono_get_object_type ();
3061 offset
= create_interp_local (td
, type
);
3062 arg_offsets
[0] = offset
;
3063 store_local_general (td
, offset
, type
);
3066 local_offsets
= (guint32
*) g_malloc (header
->num_locals
* sizeof (guint32
));
3067 /* Allocate locals to store inlined method args from stack */
3068 for (i
= 0; i
< header
->num_locals
; i
++)
3069 local_offsets
[i
] = create_interp_local (td
, header
->locals
[i
]);
3072 while (td
->ip
< end
) {
3073 g_assert (td
->sp
>= td
->stack
);
3074 g_assert (td
->vt_sp
< 0x10000000);
3075 in_offset
= td
->ip
- header
->code
;
3077 td
->current_il_offset
= in_offset
;
3078 td
->in_start
= td
->ip
;
3079 InterpInst
*prev_last_ins
= td
->last_ins
;
3081 // Inlined method doesn't have clauses or branches
3082 if (!inlining
&& td
->stack_height
[in_offset
] >= 0) {
3083 g_assert (td
->is_bb_start
[in_offset
]);
3084 if (td
->stack_height
[in_offset
] > 0)
3085 memcpy (td
->stack
, td
->stack_state
[in_offset
], td
->stack_height
[in_offset
] * sizeof(td
->stack
[0]));
3086 td
->sp
= td
->stack
+ td
->stack_height
[in_offset
];
3087 td
->vt_sp
= td
->vt_stack_size
[in_offset
];
3090 if (in_offset
== bb
->end
)
3094 int op_size
= mono_opcode_size (td
->ip
, end
);
3095 g_assert (op_size
> 0); /* The BB formation pass must catch all bad ops */
3097 if (td
->verbose_level
> 1)
3098 g_print ("SKIPPING DEAD OP at %x\n", in_offset
);
3104 if (td
->verbose_level
> 1) {
3105 g_print ("IL_%04lx %s %-10s, sp %ld, %s %-12s vt_sp %u (max %u)\n",
3106 td
->ip
- td
->il_code
,
3107 td
->is_bb_start
[td
->ip
- td
->il_code
] == 3 ? "<>" :
3108 td
->is_bb_start
[td
->ip
- td
->il_code
] == 2 ? "< " :
3109 td
->is_bb_start
[td
->ip
- td
->il_code
] == 1 ? " >" : " ",
3110 mono_opcode_name (*td
->ip
), td
->sp
- td
->stack
,
3111 td
->sp
> td
->stack
? stack_type_string
[td
->sp
[-1].type
] : " ",
3112 (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
)) : "",
3113 td
->vt_sp
, td
->max_vt_sp
);
3116 if (sym_seq_points
&& mono_bitset_test_fast (seq_point_locs
, td
->ip
- header
->code
)) {
3117 InterpBasicBlock
*cbb
= td
->offset_to_bb
[td
->ip
- header
->code
];
3121 * Make methods interruptable at the beginning, and at the targets of
3122 * backward branches.
3124 if (in_offset
== 0 || g_slist_length (cbb
->preds
) > 1)
3125 interp_add_ins (td
, MINT_SDB_INTR_LOC
);
3127 last_seq_point
= interp_add_ins (td
, MINT_SDB_SEQ_POINT
);
3130 if (!inlining
&& td
->is_bb_start
[in_offset
]) {
3131 int index
= td
->clause_indexes
[in_offset
];
3133 MonoExceptionClause
*clause
= &header
->clauses
[index
];
3134 if ((clause
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
||
3135 clause
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
) &&
3136 in_offset
== clause
->handler_offset
)
3137 interp_add_ins (td
, MINT_START_ABORT_PROT
);
3144 emitted_funccall_seq_point
= FALSE
;
3148 SIMPLE_OP(td
, MINT_BREAK
);
3154 int arg_n
= *td
->ip
- CEE_LDARG_0
;
3156 load_arg (td
, arg_n
);
3158 load_local_general (td
, arg_offsets
[arg_n
], get_arg_type (signature
, arg_n
));
3166 int loc_n
= *td
->ip
- CEE_LDLOC_0
;
3168 load_local (td
, loc_n
);
3170 load_local_general (td
, local_offsets
[loc_n
], header
->locals
[loc_n
]);
3178 int loc_n
= *td
->ip
- CEE_STLOC_0
;
3180 store_local (td
, loc_n
);
3182 store_local_general (td
, local_offsets
[loc_n
], header
->locals
[loc_n
]);
3187 int arg_n
= ((guint8
*)td
->ip
)[1];
3189 load_arg (td
, arg_n
);
3191 load_local_general (td
, arg_offsets
[arg_n
], get_arg_type (signature
, arg_n
));
3195 case CEE_LDARGA_S
: {
3196 /* NOTE: n includes this */
3197 int n
= ((guint8
*) td
->ip
) [1];
3200 get_arg_type_exact (td
, n
, &mt
);
3201 interp_add_ins (td
, mt
== MINT_TYPE_VT
? MINT_LDARGA_VT
: MINT_LDARGA
);
3202 td
->last_ins
->data
[0] = n
;
3204 interp_add_ins (td
, MINT_LDLOCA_S
);
3205 td
->last_ins
->data
[0] = arg_offsets
[n
];
3207 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
3212 int arg_n
= ((guint8
*)td
->ip
)[1];
3214 store_arg (td
, arg_n
);
3216 store_local_general (td
, arg_offsets
[arg_n
], get_arg_type (signature
, arg_n
));
3221 int loc_n
= ((guint8
*)td
->ip
)[1];
3223 load_local (td
, loc_n
);
3225 load_local_general (td
, local_offsets
[loc_n
], header
->locals
[loc_n
]);
3229 case CEE_LDLOCA_S
: {
3230 int loc_n
= ((guint8
*)td
->ip
)[1];
3231 interp_add_ins (td
, MINT_LDLOCA_S
);
3233 td
->last_ins
->data
[0] = td
->rtm
->local_offsets
[loc_n
];
3235 td
->last_ins
->data
[0] = local_offsets
[loc_n
];
3236 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
3241 int loc_n
= ((guint8
*)td
->ip
)[1];
3243 store_local (td
, loc_n
);
3245 store_local_general (td
, local_offsets
[loc_n
], header
->locals
[loc_n
]);
3250 SIMPLE_OP(td
, MINT_LDNULL
);
3251 PUSH_TYPE(td
, STACK_TYPE_O
, NULL
);
3254 SIMPLE_OP(td
, MINT_LDC_I4_M1
);
3255 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
3258 if (!td
->is_bb_start
[td
->ip
+ 1 - td
->il_code
] && td
->ip
[1] == 0xfe && td
->ip
[2] == CEE_CEQ
&&
3259 td
->sp
> td
->stack
&& td
->sp
[-1].type
== STACK_TYPE_I4
) {
3260 SIMPLE_OP(td
, MINT_CEQ0_I4
);
3263 SIMPLE_OP(td
, MINT_LDC_I4_0
);
3264 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
3268 if (!td
->is_bb_start
[td
->ip
+ 1 - td
->il_code
] &&
3269 (td
->ip
[1] == CEE_ADD
|| td
->ip
[1] == CEE_SUB
) && td
->sp
[-1].type
== STACK_TYPE_I4
) {
3270 interp_add_ins (td
, td
->ip
[1] == CEE_ADD
? MINT_ADD1_I4
: MINT_SUB1_I4
);
3273 SIMPLE_OP(td
, MINT_LDC_I4_1
);
3274 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
3284 SIMPLE_OP(td
, (*td
->ip
- CEE_LDC_I4_0
) + MINT_LDC_I4_0
);
3285 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
3288 interp_add_ins (td
, MINT_LDC_I4_S
);
3289 td
->last_ins
->data
[0] = ((gint8
*) td
->ip
) [1];
3291 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
3294 i32
= read32 (td
->ip
+ 1);
3295 interp_add_ins (td
, MINT_LDC_I4
);
3296 WRITE32_INS (td
->last_ins
, 0, &i32
);
3298 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
3301 gint64 val
= read64 (td
->ip
+ 1);
3302 interp_add_ins (td
, MINT_LDC_I8
);
3303 WRITE64_INS (td
->last_ins
, 0, &val
);
3305 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I8
);
3310 readr4 (td
->ip
+ 1, &val
);
3311 interp_add_ins (td
, MINT_LDC_R4
);
3312 WRITE32_INS (td
->last_ins
, 0, &val
);
3314 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_R4
);
3319 readr8 (td
->ip
+ 1, &val
);
3320 interp_add_ins (td
, MINT_LDC_R8
);
3321 WRITE64_INS (td
->last_ins
, 0, &val
);
3323 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_R8
);
3327 int type
= td
->sp
[-1].type
;
3328 MonoClass
*klass
= td
->sp
[-1].klass
;
3329 if (td
->sp
[-1].type
== STACK_TYPE_VT
) {
3330 gint32 size
= mono_class_value_size (klass
, NULL
);
3332 interp_add_ins (td
, MINT_DUP_VT
);
3333 WRITE32_INS (td
->last_ins
, 0, &size
);
3336 SIMPLE_OP(td
, MINT_DUP
);
3337 PUSH_TYPE(td
, type
, klass
);
3342 SIMPLE_OP(td
, MINT_POP
);
3343 td
->last_ins
->data
[0] = 0;
3344 if (td
->sp
[-1].type
== STACK_TYPE_VT
) {
3345 int size
= mono_class_value_size (td
->sp
[-1].klass
, NULL
);
3346 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
3347 interp_add_ins (td
, MINT_VTRESULT
);
3348 td
->last_ins
->data
[0] = 0;
3349 WRITE32_INS (td
->last_ins
, 1, &size
);
3357 if (td
->sp
> td
->stack
)
3358 g_warning ("CEE_JMP: stack must be empty");
3359 token
= read32 (td
->ip
+ 1);
3360 m
= mono_get_method_checked (image
, token
, NULL
, generic_context
, error
);
3361 goto_if_nok (error
, exit
);
3362 interp_add_ins (td
, MINT_JMP
);
3363 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
3364 goto_if_nok (error
, exit
);
3368 case CEE_CALLVIRT
: /* Fall through */
3369 case CEE_CALLI
: /* Fall through */
3371 gboolean need_seq_point
= FALSE
;
3373 if (sym_seq_points
&& !mono_bitset_test_fast (seq_point_locs
, td
->ip
+ 5 - header
->code
))
3374 need_seq_point
= TRUE
;
3376 if (!interp_transform_call (td
, method
, NULL
, domain
, generic_context
, td
->is_bb_start
, constrained_class
, readonly
, error
, TRUE
, save_last_error
))
3379 if (need_seq_point
) {
3380 //check is is a nested call and remove the MONO_INST_NONEMPTY_STACK of the last breakpoint, only for non native methods
3381 if (!(method
->flags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)) {
3382 if (emitted_funccall_seq_point
) {
3384 last_seq_point
->flags
|= INTERP_INST_FLAG_SEQ_POINT_NESTED_CALL
;
3387 emitted_funccall_seq_point
= TRUE
;
3389 last_seq_point
= interp_add_ins (td
, MINT_SDB_SEQ_POINT
);
3390 // This seq point is actually associated with the instruction following the call
3391 last_seq_point
->il_offset
= td
->ip
- header
->code
;
3392 last_seq_point
->flags
= INTERP_INST_FLAG_SEQ_POINT_NONEMPTY_STACK
;
3395 constrained_class
= NULL
;
3397 save_last_error
= FALSE
;
3401 /* Return from inlined method, return value is on top of stack */
3402 if (td
->method
!= method
) {
3408 MonoType
*ult
= mini_type_get_underlying_type (signature
->ret
);
3409 if (ult
->type
!= MONO_TYPE_VOID
) {
3410 CHECK_STACK (td
, 1);
3412 if (mint_type (ult
) == MINT_TYPE_VT
) {
3413 MonoClass
*klass
= mono_class_from_mono_type_internal (ult
);
3414 vt_size
= mono_class_value_size (klass
, NULL
);
3417 if (td
->sp
> td
->stack
) {
3418 mono_error_set_generic_error (error
, "System", "InvalidProgramException", "");
3421 if (td
->vt_sp
!= ALIGN_TO (vt_size
, MINT_VT_ALIGNMENT
))
3422 g_error ("%s: CEE_RET: value type stack: %d vs. %d", mono_method_full_name (td
->method
, TRUE
), td
->vt_sp
, vt_size
);
3424 if (sym_seq_points
) {
3425 last_seq_point
= interp_add_ins (td
, MINT_SDB_SEQ_POINT
);
3426 td
->last_ins
->flags
= INTERP_INST_FLAG_SEQ_POINT_METHOD_EXIT
;
3429 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (method
)) {
3430 /* This does the return as well */
3431 interp_add_ins (td
, MINT_TRACE_EXIT
);
3432 if (ult
->type
== MONO_TYPE_VOID
)
3434 WRITE32_INS (td
->last_ins
, 0, &vt_size
);
3438 SIMPLE_OP(td
, ult
->type
== MONO_TYPE_VOID
? MINT_RET_VOID
: MINT_RET
);
3440 interp_add_ins (td
, MINT_RET_VT
);
3441 WRITE32_INS (td
->last_ins
, 0, &vt_size
);
3448 int offset
= read32 (td
->ip
+ 1);
3451 handle_branch (td
, MINT_BR_S
, MINT_BR
, 5 + offset
);
3457 int offset
= (gint8
)td
->ip
[1];
3460 handle_branch (td
, MINT_BR_S
, MINT_BR
, 2 + (gint8
)td
->ip
[1]);
3467 one_arg_branch (td
, MINT_BRFALSE_I4
, 5 + read32 (td
->ip
+ 1));
3472 one_arg_branch (td
, MINT_BRFALSE_I4
, 2 + (gint8
)td
->ip
[1]);
3477 one_arg_branch (td
, MINT_BRTRUE_I4
, 5 + read32 (td
->ip
+ 1));
3482 one_arg_branch (td
, MINT_BRTRUE_I4
, 2 + (gint8
)td
->ip
[1]);
3487 two_arg_branch (td
, MINT_BEQ_I4
, 5 + read32 (td
->ip
+ 1));
3492 two_arg_branch (td
, MINT_BEQ_I4
, 2 + (gint8
) td
->ip
[1]);
3497 two_arg_branch (td
, MINT_BGE_I4
, 5 + read32 (td
->ip
+ 1));
3502 two_arg_branch (td
, MINT_BGE_I4
, 2 + (gint8
) td
->ip
[1]);
3507 two_arg_branch (td
, MINT_BGT_I4
, 5 + read32 (td
->ip
+ 1));
3512 two_arg_branch (td
, MINT_BGT_I4
, 2 + (gint8
) td
->ip
[1]);
3517 two_arg_branch (td
, MINT_BLT_I4
, 5 + read32 (td
->ip
+ 1));
3522 two_arg_branch (td
, MINT_BLT_I4
, 2 + (gint8
) td
->ip
[1]);
3527 two_arg_branch (td
, MINT_BLE_I4
, 5 + read32 (td
->ip
+ 1));
3532 two_arg_branch (td
, MINT_BLE_I4
, 2 + (gint8
) td
->ip
[1]);
3537 two_arg_branch (td
, MINT_BNE_UN_I4
, 5 + read32 (td
->ip
+ 1));
3542 two_arg_branch (td
, MINT_BNE_UN_I4
, 2 + (gint8
) td
->ip
[1]);
3547 two_arg_branch (td
, MINT_BGE_UN_I4
, 5 + read32 (td
->ip
+ 1));
3552 two_arg_branch (td
, MINT_BGE_UN_I4
, 2 + (gint8
) td
->ip
[1]);
3557 two_arg_branch (td
, MINT_BGT_UN_I4
, 5 + read32 (td
->ip
+ 1));
3562 two_arg_branch (td
, MINT_BGT_UN_I4
, 2 + (gint8
) td
->ip
[1]);
3567 two_arg_branch (td
, MINT_BLE_UN_I4
, 5 + read32 (td
->ip
+ 1));
3572 two_arg_branch (td
, MINT_BLE_UN_I4
, 2 + (gint8
) td
->ip
[1]);
3577 two_arg_branch (td
, MINT_BLT_UN_I4
, 5 + read32 (td
->ip
+ 1));
3582 two_arg_branch (td
, MINT_BLT_UN_I4
, 2 + (gint8
) td
->ip
[1]);
3588 const unsigned char *next_ip
;
3590 n
= read32 (td
->ip
);
3591 interp_add_ins_explicit (td
, MINT_SWITCH
, MINT_SWITCH_LEN (n
));
3592 WRITE32_INS (td
->last_ins
, 0, &n
);
3594 next_ip
= td
->ip
+ n
* 4;
3596 int stack_height
= td
->sp
- td
->stack
;
3597 for (i
= 0; i
< n
; i
++) {
3598 offset
= read32 (td
->ip
);
3599 target
= next_ip
- td
->il_code
+ offset
;
3602 if (stack_height
> 0 && stack_height
!= td
->stack_height
[target
])
3603 g_warning ("SWITCH with back branch and non-empty stack");
3606 td
->stack_height
[target
] = stack_height
;
3607 td
->vt_stack_size
[target
] = td
->vt_sp
;
3608 if (stack_height
> 0)
3609 td
->stack_state
[target
] = (StackInfo
*)g_memdup (td
->stack
, stack_height
* sizeof (td
->stack
[0]));
3611 WRITE32_INS (td
->last_ins
, 2 + i
* 2, &target
);
3617 CHECK_STACK (td
, 1);
3618 SIMPLE_OP (td
, MINT_LDIND_I1_CHECK
);
3619 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3620 BARRIER_IF_VOLATILE (td
);
3623 CHECK_STACK (td
, 1);
3624 SIMPLE_OP (td
, MINT_LDIND_U1_CHECK
);
3625 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3626 BARRIER_IF_VOLATILE (td
);
3629 CHECK_STACK (td
, 1);
3630 SIMPLE_OP (td
, MINT_LDIND_I2_CHECK
);
3631 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3632 BARRIER_IF_VOLATILE (td
);
3635 CHECK_STACK (td
, 1);
3636 SIMPLE_OP (td
, MINT_LDIND_U2_CHECK
);
3637 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3638 BARRIER_IF_VOLATILE (td
);
3641 CHECK_STACK (td
, 1);
3642 SIMPLE_OP (td
, MINT_LDIND_I4_CHECK
);
3643 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3644 BARRIER_IF_VOLATILE (td
);
3647 CHECK_STACK (td
, 1);
3648 SIMPLE_OP (td
, MINT_LDIND_U4_CHECK
);
3649 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3650 BARRIER_IF_VOLATILE (td
);
3653 CHECK_STACK (td
, 1);
3654 SIMPLE_OP (td
, MINT_LDIND_I8_CHECK
);
3655 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
3656 BARRIER_IF_VOLATILE (td
);
3659 CHECK_STACK (td
, 1);
3660 SIMPLE_OP (td
, MINT_LDIND_REF_CHECK
);
3661 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I
);
3662 BARRIER_IF_VOLATILE (td
);
3665 CHECK_STACK (td
, 1);
3666 SIMPLE_OP (td
, MINT_LDIND_R4_CHECK
);
3667 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R4
);
3668 BARRIER_IF_VOLATILE (td
);
3671 CHECK_STACK (td
, 1);
3672 SIMPLE_OP (td
, MINT_LDIND_R8_CHECK
);
3673 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
3674 BARRIER_IF_VOLATILE (td
);
3677 CHECK_STACK (td
, 1);
3678 SIMPLE_OP (td
, MINT_LDIND_REF_CHECK
);
3679 BARRIER_IF_VOLATILE (td
);
3680 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_O
);
3683 CHECK_STACK (td
, 2);
3684 BARRIER_IF_VOLATILE (td
);
3685 SIMPLE_OP (td
, MINT_STIND_REF
);
3689 CHECK_STACK (td
, 2);
3690 BARRIER_IF_VOLATILE (td
);
3691 SIMPLE_OP (td
, MINT_STIND_I1
);
3695 CHECK_STACK (td
, 2);
3696 BARRIER_IF_VOLATILE (td
);
3697 SIMPLE_OP (td
, MINT_STIND_I2
);
3701 CHECK_STACK (td
, 2);
3702 BARRIER_IF_VOLATILE (td
);
3703 SIMPLE_OP (td
, MINT_STIND_I4
);
3707 CHECK_STACK (td
, 2);
3708 BARRIER_IF_VOLATILE (td
);
3709 SIMPLE_OP (td
, MINT_STIND_I
);
3713 CHECK_STACK (td
, 2);
3714 BARRIER_IF_VOLATILE (td
);
3715 SIMPLE_OP (td
, MINT_STIND_I8
);
3719 CHECK_STACK (td
, 2);
3720 BARRIER_IF_VOLATILE (td
);
3721 SIMPLE_OP (td
, MINT_STIND_R4
);
3725 CHECK_STACK (td
, 2);
3726 BARRIER_IF_VOLATILE (td
);
3727 SIMPLE_OP (td
, MINT_STIND_R8
);
3731 binary_arith_op(td
, MINT_ADD_I4
);
3735 binary_arith_op(td
, MINT_SUB_I4
);
3739 binary_arith_op(td
, MINT_MUL_I4
);
3743 binary_arith_op(td
, MINT_DIV_I4
);
3747 binary_arith_op(td
, MINT_DIV_UN_I4
);
3751 binary_arith_op (td
, MINT_REM_I4
);
3755 binary_arith_op (td
, MINT_REM_UN_I4
);
3759 binary_arith_op (td
, MINT_AND_I4
);
3763 binary_arith_op (td
, MINT_OR_I4
);
3767 binary_arith_op (td
, MINT_XOR_I4
);
3771 shift_op (td
, MINT_SHL_I4
);
3775 shift_op (td
, MINT_SHR_I4
);
3779 shift_op (td
, MINT_SHR_UN_I4
);
3783 unary_arith_op (td
, MINT_NEG_I4
);
3787 unary_arith_op (td
, MINT_NOT_I4
);
3791 CHECK_STACK (td
, 1);
3792 switch (td
->sp
[-1].type
) {
3794 interp_add_ins (td
, MINT_CONV_U1_R4
);
3797 interp_add_ins (td
, MINT_CONV_U1_R8
);
3800 interp_add_ins (td
, MINT_CONV_U1_I4
);
3803 interp_add_ins (td
, MINT_CONV_U1_I8
);
3806 g_assert_not_reached ();
3809 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3812 CHECK_STACK (td
, 1);
3813 switch (td
->sp
[-1].type
) {
3815 interp_add_ins (td
, MINT_CONV_I1_R4
);
3818 interp_add_ins (td
, MINT_CONV_I1_R8
);
3821 interp_add_ins (td
, MINT_CONV_I1_I4
);
3824 interp_add_ins (td
, MINT_CONV_I1_I8
);
3827 g_assert_not_reached ();
3830 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3833 CHECK_STACK (td
, 1);
3834 switch (td
->sp
[-1].type
) {
3836 interp_add_ins (td
, MINT_CONV_U2_R4
);
3839 interp_add_ins (td
, MINT_CONV_U2_R8
);
3842 interp_add_ins (td
, MINT_CONV_U2_I4
);
3845 interp_add_ins (td
, MINT_CONV_U2_I8
);
3848 g_assert_not_reached ();
3851 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3854 CHECK_STACK (td
, 1);
3855 switch (td
->sp
[-1].type
) {
3857 interp_add_ins (td
, MINT_CONV_I2_R4
);
3860 interp_add_ins (td
, MINT_CONV_I2_R8
);
3863 interp_add_ins (td
, MINT_CONV_I2_I4
);
3866 interp_add_ins (td
, MINT_CONV_I2_I8
);
3869 g_assert_not_reached ();
3872 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3875 CHECK_STACK (td
, 1);
3876 switch (td
->sp
[-1].type
) {
3878 #if SIZEOF_VOID_P == 4
3879 interp_add_ins (td
, MINT_CONV_U4_R8
);
3881 interp_add_ins (td
, MINT_CONV_U8_R8
);
3885 #if SIZEOF_VOID_P == 8
3886 interp_add_ins (td
, MINT_CONV_U8_I4
);
3890 #if SIZEOF_VOID_P == 4
3891 interp_add_ins (td
, MINT_CONV_U4_I8
);
3898 g_assert_not_reached ();
3901 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I
);
3904 CHECK_STACK (td
, 1);
3905 switch (td
->sp
[-1].type
) {
3907 #if SIZEOF_VOID_P == 8
3908 interp_add_ins (td
, MINT_CONV_I8_R8
);
3910 interp_add_ins (td
, MINT_CONV_I4_R8
);
3914 #if SIZEOF_VOID_P == 8
3915 interp_add_ins (td
, MINT_CONV_I8_I4
);
3923 #if SIZEOF_VOID_P == 4
3924 interp_add_ins (td
, MINT_CONV_I4_I8
);
3928 g_assert_not_reached ();
3931 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I
);
3934 CHECK_STACK (td
, 1);
3935 switch (td
->sp
[-1].type
) {
3937 interp_add_ins (td
, MINT_CONV_U4_R4
);
3940 interp_add_ins (td
, MINT_CONV_U4_R8
);
3945 interp_add_ins (td
, MINT_CONV_U4_I8
);
3948 #if SIZEOF_VOID_P == 8
3949 interp_add_ins (td
, MINT_CONV_U4_I8
);
3953 g_assert_not_reached ();
3956 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3959 CHECK_STACK (td
, 1);
3960 switch (td
->sp
[-1].type
) {
3962 interp_add_ins (td
, MINT_CONV_I4_R4
);
3965 interp_add_ins (td
, MINT_CONV_I4_R8
);
3970 interp_add_ins (td
, MINT_CONV_I4_I8
);
3973 #if SIZEOF_VOID_P == 8
3974 interp_add_ins (td
, MINT_CONV_I4_I8
);
3978 g_assert_not_reached ();
3981 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
3984 CHECK_STACK (td
, 1);
3985 switch (td
->sp
[-1].type
) {
3987 interp_add_ins (td
, MINT_CONV_I8_R4
);
3990 interp_add_ins (td
, MINT_CONV_I8_R8
);
3992 case STACK_TYPE_I4
: {
3993 if (interp_ins_is_ldc (td
->last_ins
) && (inlining
|| !td
->is_bb_start
[in_offset
])) {
3994 gint64 ct
= interp_ldc_i4_get_const (td
->last_ins
);
3995 interp_clear_ins (td
, td
->last_ins
);
3997 interp_add_ins (td
, MINT_LDC_I8
);
3998 WRITE64_INS (td
->last_ins
, 0, &ct
);
4000 interp_add_ins (td
, MINT_CONV_I8_I4
);
4007 #if SIZEOF_VOID_P == 4
4008 interp_add_ins (td
, MINT_CONV_I8_I4
);
4012 g_assert_not_reached ();
4015 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
4018 CHECK_STACK (td
, 1);
4019 switch (td
->sp
[-1].type
) {
4021 interp_add_ins (td
, MINT_CONV_R4_R8
);
4024 interp_add_ins (td
, MINT_CONV_R4_I8
);
4027 interp_add_ins (td
, MINT_CONV_R4_I4
);
4033 g_assert_not_reached ();
4036 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R4
);
4039 CHECK_STACK (td
, 1);
4040 switch (td
->sp
[-1].type
) {
4042 interp_add_ins (td
, MINT_CONV_R8_I4
);
4045 interp_add_ins (td
, MINT_CONV_R8_I8
);
4048 interp_add_ins (td
, MINT_CONV_R8_R4
);
4053 g_assert_not_reached ();
4056 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
4059 CHECK_STACK (td
, 1);
4060 switch (td
->sp
[-1].type
) {
4062 if (interp_ins_is_ldc (td
->last_ins
) && (inlining
|| !td
->is_bb_start
[in_offset
])) {
4063 gint64 ct
= (guint32
)interp_ldc_i4_get_const (td
->last_ins
);
4064 interp_clear_ins (td
, td
->last_ins
);
4066 interp_add_ins (td
, MINT_LDC_I8
);
4067 WRITE64_INS (td
->last_ins
, 0, &ct
);
4069 interp_add_ins (td
, MINT_CONV_U8_I4
);
4075 interp_add_ins (td
, MINT_CONV_U8_R4
);
4078 interp_add_ins (td
, MINT_CONV_U8_R8
);
4081 #if SIZEOF_VOID_P == 4
4082 interp_add_ins (td
, MINT_CONV_U8_I4
);
4086 g_assert_not_reached ();
4089 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
4092 CHECK_STACK (td
, 2);
4094 token
= read32 (td
->ip
+ 1);
4095 klass
= mono_class_get_and_inflate_typespec_checked (image
, token
, generic_context
, error
);
4096 goto_if_nok (error
, exit
);
4098 if (m_class_is_valuetype (klass
)) {
4099 int mt
= mint_type (m_class_get_byval_arg (klass
));
4100 interp_add_ins (td
, (mt
== MINT_TYPE_VT
) ? MINT_CPOBJ_VT
: MINT_CPOBJ
);
4101 td
->last_ins
->data
[0] = get_data_item_index(td
, klass
);
4103 interp_add_ins (td
, MINT_LDIND_REF
);
4104 interp_add_ins (td
, MINT_STIND_REF
);
4111 CHECK_STACK (td
, 1);
4113 token
= read32 (td
->ip
+ 1);
4115 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4116 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
4118 klass
= mono_class_get_and_inflate_typespec_checked (image
, token
, generic_context
, error
);
4119 goto_if_nok (error
, exit
);
4122 interp_emit_ldobj (td
, klass
);
4125 BARRIER_IF_VOLATILE (td
);
4129 token
= mono_metadata_token_index (read32 (td
->ip
+ 1));
4131 if (method
->wrapper_type
== MONO_WRAPPER_NONE
) {
4132 MonoString
*s
= mono_ldstr_checked (domain
, image
, token
, error
);
4133 goto_if_nok (error
, exit
);
4134 /* GC won't scan code stream, but reference is held by metadata
4135 * machinery so we are good here */
4136 interp_add_ins (td
, MINT_LDSTR
);
4137 td
->last_ins
->data
[0] = get_data_item_index (td
, s
);
4139 /* defer allocation to execution-time */
4140 interp_add_ins (td
, MINT_LDSTR_TOKEN
);
4141 td
->last_ins
->data
[0] = get_data_item_index (td
, GUINT_TO_POINTER (token
));
4143 PUSH_TYPE(td
, STACK_TYPE_O
, mono_defaults
.string_class
);
4148 MonoMethodSignature
*csignature
;
4149 guint32 vt_stack_used
= 0;
4150 guint32 vt_res_size
= 0;
4153 token
= read32 (td
->ip
);
4156 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4157 m
= (MonoMethod
*)mono_method_get_wrapper_data (method
, token
);
4159 m
= mono_get_method_checked (image
, token
, NULL
, generic_context
, error
);
4160 goto_if_nok (error
, exit
);
4163 csignature
= mono_method_signature_internal (m
);
4166 if (!mono_class_init_internal (klass
)) {
4167 mono_error_set_for_class_failure (error
, klass
);
4168 goto_if_nok (error
, exit
);
4171 if (mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_ABSTRACT
) {
4172 char* full_name
= mono_type_get_full_name (klass
);
4173 mono_error_set_member_access (error
, "Cannot create an abstract class: %s", full_name
);
4175 goto_if_nok (error
, exit
);
4178 if (mono_class_is_magic_int (klass
) || mono_class_is_magic_float (klass
)) {
4179 td
->sp
-= csignature
->param_count
;
4180 #if SIZEOF_VOID_P == 8
4181 if (mono_class_is_magic_int (klass
) && td
->sp
[0].type
== STACK_TYPE_I4
)
4182 interp_add_ins (td
, MINT_CONV_I8_I4
);
4183 else if (mono_class_is_magic_float (klass
) && td
->sp
[0].type
== STACK_TYPE_R4
)
4184 interp_add_ins (td
, MINT_CONV_R8_R4
);
4186 interp_add_ins (td
, MINT_NEWOBJ_MAGIC
);
4187 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
4188 goto_if_nok (error
, exit
);
4190 PUSH_TYPE (td
, stack_type
[mint_type (m_class_get_byval_arg (klass
))], klass
);
4192 if (m_class_get_parent (klass
) == mono_defaults
.array_class
) {
4193 interp_add_ins (td
, MINT_NEWOBJ_ARRAY
);
4194 td
->last_ins
->data
[0] = get_data_item_index (td
, m
->klass
);
4195 td
->last_ins
->data
[1] = csignature
->param_count
;
4196 } else if (m_class_get_image (klass
) == mono_defaults
.corlib
&&
4197 !strcmp (m_class_get_name (m
->klass
), "ByReference`1") &&
4198 !strcmp (m
->name
, ".ctor")) {
4199 /* public ByReference(ref T value) */
4200 g_assert (csignature
->hasthis
&& csignature
->param_count
== 1);
4201 interp_add_ins (td
, MINT_INTRINS_BYREFERENCE_CTOR
);
4202 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
4203 } else if (klass
!= mono_defaults
.string_class
&&
4204 !mono_class_is_marshalbyref (klass
) &&
4205 !mono_class_has_finalizer (klass
) &&
4206 !m_class_has_weak_fields (klass
)) {
4207 if (!m_class_is_valuetype (klass
)) {
4208 InterpInst
*newobj_fast
= interp_add_ins (td
, MINT_NEWOBJ_FAST
);
4210 newobj_fast
->data
[1] = csignature
->param_count
;
4212 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, klass
, error
);
4213 goto_if_nok (error
, exit
);
4214 newobj_fast
->data
[2] = get_data_item_index (td
, vtable
);
4216 move_stack (td
, (td
->sp
- td
->stack
) - csignature
->param_count
, 2);
4218 StackInfo
*tmp_sp
= td
->sp
- csignature
->param_count
- 2;
4219 SET_TYPE (tmp_sp
, STACK_TYPE_O
, klass
);
4220 SET_TYPE (tmp_sp
+ 1, STACK_TYPE_O
, klass
);
4222 if ((mono_interp_opt
& INTERP_OPT_INLINE
) && interp_method_check_inlining (td
, m
)) {
4223 MonoMethodHeader
*mheader
= interp_method_get_header (m
, error
);
4224 goto_if_nok (error
, exit
);
4226 if (interp_inline_method (td
, m
, mheader
, error
)) {
4227 newobj_fast
->data
[0] = 0xffff;
4231 // If inlining failed we need to restore the stack
4232 move_stack (td
, (td
->sp
- td
->stack
) - csignature
->param_count
, -2);
4233 // Set the method to be executed as part of newobj instruction
4234 newobj_fast
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
4236 if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
)
4237 interp_add_ins (td
, MINT_NEWOBJ_VTST_FAST
);
4239 interp_add_ins (td
, MINT_NEWOBJ_VT_FAST
);
4241 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
4242 td
->last_ins
->data
[1] = csignature
->param_count
;
4244 if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
) {
4245 td
->last_ins
->data
[2] = mono_class_value_size (klass
, NULL
);
4249 interp_add_ins (td
, MINT_NEWOBJ
);
4250 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
4252 goto_if_nok (error
, exit
);
4253 /* The constructor was not inlined, abort inlining of current method */
4256 td
->sp
-= csignature
->param_count
;
4257 if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
) {
4258 vt_res_size
= mono_class_value_size (klass
, NULL
);
4259 PUSH_VT (td
, vt_res_size
);
4261 for (i
= 0; i
< csignature
->param_count
; ++i
) {
4262 int mt
= mint_type(csignature
->params
[i
]);
4263 if (mt
== MINT_TYPE_VT
) {
4264 MonoClass
*k
= mono_class_from_mono_type_internal (csignature
->params
[i
]);
4265 gint32 size
= mono_class_value_size (k
, NULL
);
4266 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4267 vt_stack_used
+= size
;
4270 if (vt_stack_used
!= 0 || vt_res_size
!= 0) {
4271 interp_add_ins (td
, MINT_VTRESULT
);
4272 td
->last_ins
->data
[0] = vt_res_size
;
4273 WRITE32_INS (td
->last_ins
, 1, &vt_stack_used
);
4274 td
->vt_sp
-= vt_stack_used
;
4276 PUSH_TYPE (td
, stack_type
[mint_type (m_class_get_byval_arg (klass
))], klass
);
4282 gboolean isinst_instr
= *td
->ip
== CEE_ISINST
;
4283 CHECK_STACK (td
, 1);
4284 token
= read32 (td
->ip
+ 1);
4285 klass
= mini_get_class (method
, token
, generic_context
);
4286 CHECK_TYPELOAD (klass
);
4287 interp_handle_isinst (td
, klass
, isinst_instr
);
4289 td
->sp
[-1].klass
= klass
;
4293 switch (td
->sp
[-1].type
) {
4297 interp_add_ins (td
, MINT_CONV_R_UN_I8
);
4300 interp_add_ins (td
, MINT_CONV_R_UN_I4
);
4303 g_assert_not_reached ();
4305 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
4309 CHECK_STACK (td
, 1);
4310 token
= read32 (td
->ip
+ 1);
4312 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4313 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
4315 klass
= mono_class_get_and_inflate_typespec_checked (image
, token
, generic_context
, error
);
4316 goto_if_nok (error
, exit
);
4319 if (mono_class_is_nullable (klass
)) {
4320 MonoMethod
*target_method
;
4321 if (m_class_is_enumtype (mono_class_get_nullable_param_internal (klass
)))
4322 target_method
= mono_class_get_method_from_name_checked (klass
, "UnboxExact", 1, 0, error
);
4324 target_method
= mono_class_get_method_from_name_checked (klass
, "Unbox", 1, 0, error
);
4325 goto_if_nok (error
, exit
);
4326 /* td->ip is incremented by interp_transform_call */
4327 if (!interp_transform_call (td
, method
, target_method
, domain
, generic_context
, td
->is_bb_start
, NULL
, FALSE
, error
, FALSE
, FALSE
))
4330 * CEE_UNBOX needs to push address of vtype while Nullable.Unbox returns the value type
4331 * We create a local variable in the frame so that we can fetch its address.
4333 int local_offset
= create_interp_local (td
, m_class_get_byval_arg (klass
));
4334 store_local_general (td
, local_offset
, m_class_get_byval_arg (klass
));
4335 interp_add_ins (td
, MINT_LDLOCA_S
);
4336 td
->last_ins
->data
[0] = local_offset
;
4337 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_MP
);
4339 interp_add_ins (td
, MINT_UNBOX
);
4340 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
4341 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_MP
);
4346 CHECK_STACK (td
, 1);
4347 token
= read32 (td
->ip
+ 1);
4349 klass
= mini_get_class (method
, token
, generic_context
);
4350 CHECK_TYPELOAD (klass
);
4352 if (mini_type_is_reference (m_class_get_byval_arg (klass
))) {
4353 int mt
= mint_type (m_class_get_byval_arg (klass
));
4354 interp_handle_isinst (td
, klass
, FALSE
);
4355 SET_TYPE (td
->sp
- 1, stack_type
[mt
], klass
);
4356 } else if (mono_class_is_nullable (klass
)) {
4357 MonoMethod
*target_method
;
4358 if (m_class_is_enumtype (mono_class_get_nullable_param_internal (klass
)))
4359 target_method
= mono_class_get_method_from_name_checked (klass
, "UnboxExact", 1, 0, error
);
4361 target_method
= mono_class_get_method_from_name_checked (klass
, "Unbox", 1, 0, error
);
4362 goto_if_nok (error
, exit
);
4363 /* td->ip is incremented by interp_transform_call */
4364 if (!interp_transform_call (td
, method
, target_method
, domain
, generic_context
, td
->is_bb_start
, NULL
, FALSE
, error
, FALSE
, FALSE
))
4367 interp_add_ins (td
, MINT_UNBOX
);
4368 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
4370 interp_emit_ldobj (td
, klass
);
4378 CHECK_STACK (td
, 1);
4379 SIMPLE_OP (td
, MINT_THROW
);
4383 CHECK_STACK (td
, 1);
4384 token
= read32 (td
->ip
+ 1);
4385 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
4386 goto_if_nok (error
, exit
);
4387 MonoType
*ftype
= mono_field_get_type_internal (field
);
4388 gboolean is_static
= !!(ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
);
4389 mono_class_init_internal (klass
);
4390 #ifndef DISABLE_REMOTING
4391 if (m_class_get_marshalbyref (klass
) || mono_class_is_contextbound (klass
) || klass
== mono_defaults
.marshalbyrefobject_class
) {
4392 g_assert (!is_static
);
4393 int offset
= m_class_is_valuetype (klass
) ? field
->offset
- MONO_ABI_SIZEOF (MonoObject
) : field
->offset
;
4395 interp_add_ins (td
, MINT_MONO_LDPTR
);
4396 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
4397 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
4398 interp_add_ins (td
, MINT_MONO_LDPTR
);
4399 td
->last_ins
->data
[0] = get_data_item_index (td
, field
);
4400 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
4401 interp_add_ins (td
, MINT_LDC_I4
);
4402 WRITE32_INS (td
->last_ins
, 0, &offset
);
4403 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I4
);
4404 #if SIZEOF_VOID_P == 8
4405 interp_add_ins (td
, MINT_CONV_I8_I4
);
4408 MonoMethod
*wrapper
= mono_marshal_get_ldflda_wrapper (field
->type
);
4409 /* td->ip is incremented by interp_transform_call */
4410 if (!interp_transform_call (td
, method
, wrapper
, domain
, generic_context
, td
->is_bb_start
, NULL
, FALSE
, error
, FALSE
, FALSE
))
4416 interp_add_ins (td
, MINT_POP
);
4417 td
->last_ins
->data
[0] = 0;
4418 interp_emit_ldsflda (td
, field
, error
);
4419 goto_if_nok (error
, exit
);
4421 if ((td
->sp
- 1)->type
== STACK_TYPE_O
) {
4422 interp_add_ins (td
, MINT_LDFLDA
);
4424 g_assert ((td
->sp
-1)->type
== STACK_TYPE_MP
);
4425 interp_add_ins (td
, MINT_LDFLDA_UNSAFE
);
4427 td
->last_ins
->data
[0] = m_class_is_valuetype (klass
) ? field
->offset
- MONO_ABI_SIZEOF (MonoObject
) : field
->offset
;
4431 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
4435 CHECK_STACK (td
, 1);
4436 token
= read32 (td
->ip
+ 1);
4437 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
4438 goto_if_nok (error
, exit
);
4439 MonoType
*ftype
= mono_field_get_type_internal (field
);
4440 gboolean is_static
= !!(ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
);
4441 mono_class_init_internal (klass
);
4443 MonoClass
*field_klass
= mono_class_from_mono_type_internal (ftype
);
4444 mt
= mint_type (m_class_get_byval_arg (field_klass
));
4445 #ifndef DISABLE_REMOTING
4446 if (m_class_get_marshalbyref (klass
)) {
4447 g_assert (!is_static
);
4448 interp_add_ins (td
, mt
== MINT_TYPE_VT
? MINT_LDRMFLD_VT
: MINT_LDRMFLD
);
4449 td
->last_ins
->data
[0] = get_data_item_index (td
, field
);
4454 interp_add_ins (td
, MINT_POP
);
4455 td
->last_ins
->data
[0] = 0;
4456 interp_emit_sfld_access (td
, field
, field_klass
, mt
, TRUE
, error
);
4457 goto_if_nok (error
, exit
);
4459 int opcode
= MINT_LDFLD_I1
+ mt
- MINT_TYPE_I1
;
4460 #ifdef NO_UNALIGNED_ACCESS
4461 if ((mt
== MINT_TYPE_I8
|| mt
== MINT_TYPE_R8
) && field
->offset
% SIZEOF_VOID_P
!= 0)
4462 opcode
= get_unaligned_opcode (opcode
);
4464 interp_add_ins (td
, opcode
);
4465 td
->last_ins
->data
[0] = m_class_is_valuetype (klass
) ? field
->offset
- MONO_ABI_SIZEOF (MonoObject
) : field
->offset
;
4466 if (mt
== MINT_TYPE_VT
) {
4467 int size
= mono_class_value_size (field_klass
, NULL
);
4468 WRITE32_INS (td
->last_ins
, 1, &size
);
4472 if (mt
== MINT_TYPE_VT
) {
4473 int size
= mono_class_value_size (field_klass
, NULL
);
4476 if (td
->sp
[-1].type
== STACK_TYPE_VT
) {
4477 int size
= mono_class_value_size (klass
, NULL
);
4478 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4479 int field_vt_size
= 0;
4480 if (mt
== MINT_TYPE_VT
) {
4482 * Pop the loaded field from the vtstack (it will still be present
4483 * at the same vtstack address) and we will load it in place of the
4484 * containing valuetype with the second MINT_VTRESULT.
4486 field_vt_size
= mono_class_value_size (field_klass
, NULL
);
4487 field_vt_size
= ALIGN_TO (field_vt_size
, MINT_VT_ALIGNMENT
);
4488 interp_add_ins (td
, MINT_VTRESULT
);
4489 td
->last_ins
->data
[0] = 0;
4490 WRITE32_INS (td
->last_ins
, 1, &field_vt_size
);
4493 interp_add_ins (td
, MINT_VTRESULT
);
4494 td
->last_ins
->data
[0] = field_vt_size
;
4495 WRITE32_INS (td
->last_ins
, 1, &size
);
4498 SET_TYPE (td
->sp
- 1, stack_type
[mt
], field_klass
);
4499 BARRIER_IF_VOLATILE (td
);
4503 CHECK_STACK (td
, 2);
4504 token
= read32 (td
->ip
+ 1);
4505 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
4506 goto_if_nok (error
, exit
);
4507 MonoType
*ftype
= mono_field_get_type_internal (field
);
4508 gboolean is_static
= !!(ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
);
4509 MonoClass
*field_klass
= mono_class_from_mono_type_internal (ftype
);
4510 mono_class_init_internal (klass
);
4511 mt
= mint_type (ftype
);
4513 BARRIER_IF_VOLATILE (td
);
4515 #ifndef DISABLE_REMOTING
4516 if (m_class_get_marshalbyref (klass
)) {
4517 g_assert (!is_static
);
4518 interp_add_ins (td
, mt
== MINT_TYPE_VT
? MINT_STRMFLD_VT
: MINT_STRMFLD
);
4519 td
->last_ins
->data
[0] = get_data_item_index (td
, field
);
4524 interp_add_ins (td
, MINT_POP
);
4525 td
->last_ins
->data
[0] = 1;
4526 interp_emit_sfld_access (td
, field
, field_klass
, mt
, FALSE
, error
);
4527 goto_if_nok (error
, exit
);
4529 /* the vtable of the field might not be initialized at this point */
4530 mono_class_vtable_checked (domain
, field_klass
, error
);
4531 goto_if_nok (error
, exit
);
4533 int opcode
= MINT_STFLD_I1
+ mt
- MINT_TYPE_I1
;
4534 #ifdef NO_UNALIGNED_ACCESS
4535 if ((mt
== MINT_TYPE_I8
|| mt
== MINT_TYPE_R8
) && field
->offset
% SIZEOF_VOID_P
!= 0)
4536 opcode
= get_unaligned_opcode (opcode
);
4538 interp_add_ins (td
, opcode
);
4539 td
->last_ins
->data
[0] = m_class_is_valuetype (klass
) ? field
->offset
- MONO_ABI_SIZEOF (MonoObject
) : field
->offset
;
4540 if (mt
== MINT_TYPE_VT
) {
4541 /* the vtable of the field might not be initialized at this point */
4542 mono_class_vtable_checked (domain
, field_klass
, error
);
4543 goto_if_nok (error
, exit
);
4545 td
->last_ins
->data
[1] = get_data_item_index (td
, field_klass
);
4549 if (mt
== MINT_TYPE_VT
) {
4550 int size
= mono_class_value_size (field_klass
, NULL
);
4558 token
= read32 (td
->ip
+ 1);
4559 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
4560 goto_if_nok (error
, exit
);
4561 interp_emit_ldsflda (td
, field
, error
);
4562 goto_if_nok (error
, exit
);
4564 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
4568 token
= read32 (td
->ip
+ 1);
4569 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
4570 goto_if_nok (error
, exit
);
4571 MonoType
*ftype
= mono_field_get_type_internal (field
);
4572 mt
= mint_type (ftype
);
4573 klass
= mono_class_from_mono_type_internal (ftype
);
4575 interp_emit_sfld_access (td
, field
, klass
, mt
, TRUE
, error
);
4576 goto_if_nok (error
, exit
);
4578 if (mt
== MINT_TYPE_VT
) {
4579 int size
= mono_class_value_size (klass
, NULL
);
4583 PUSH_TYPE(td
, stack_type
[mt
], klass
);
4587 CHECK_STACK (td
, 1);
4588 token
= read32 (td
->ip
+ 1);
4589 field
= interp_field_from_token (method
, token
, &klass
, generic_context
, error
);
4590 goto_if_nok (error
, exit
);
4591 MonoType
*ftype
= mono_field_get_type_internal (field
);
4592 mt
= mint_type (ftype
);
4594 /* the vtable of the field might not be initialized at this point */
4595 MonoClass
*fld_klass
= mono_class_from_mono_type_internal (ftype
);
4596 mono_class_vtable_checked (domain
, fld_klass
, error
);
4597 goto_if_nok (error
, exit
);
4599 interp_emit_sfld_access (td
, field
, fld_klass
, mt
, FALSE
, error
);
4600 goto_if_nok (error
, exit
);
4602 if (mt
== MINT_TYPE_VT
) {
4603 int size
= mono_class_value_size (fld_klass
, NULL
);
4611 token
= read32 (td
->ip
+ 1);
4613 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4614 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
4616 klass
= mini_get_class (method
, token
, generic_context
);
4617 CHECK_TYPELOAD (klass
);
4619 BARRIER_IF_VOLATILE (td
);
4621 interp_emit_stobj (td
, klass
);
4626 case CEE_CONV_OVF_I_UN
:
4627 case CEE_CONV_OVF_U_UN
:
4628 CHECK_STACK (td
, 1);
4629 switch (td
->sp
[-1].type
) {
4631 #if SIZEOF_VOID_P == 8
4632 interp_add_ins (td
, MINT_CONV_OVF_I8_UN_R8
);
4634 interp_add_ins (td
, MINT_CONV_OVF_I4_UN_R8
);
4638 #if SIZEOF_VOID_P == 4
4639 interp_add_ins (td
, MINT_CONV_OVF_I4_UN_I8
);
4643 #if SIZEOF_VOID_P == 8
4644 interp_add_ins (td
, MINT_CONV_I8_U4
);
4645 #elif SIZEOF_VOID_P == 4
4646 if (*td
->ip
== CEE_CONV_OVF_I_UN
)
4647 interp_add_ins (td
, MINT_CONV_OVF_I4_U4
);
4651 g_assert_not_reached ();
4654 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
4657 case CEE_CONV_OVF_I8_UN
:
4658 case CEE_CONV_OVF_U8_UN
:
4659 CHECK_STACK (td
, 1);
4660 switch (td
->sp
[-1].type
) {
4662 interp_add_ins (td
, MINT_CONV_OVF_I8_UN_R8
);
4665 if (*td
->ip
== CEE_CONV_OVF_I8_UN
)
4666 interp_add_ins (td
, MINT_CONV_OVF_I8_U8
);
4669 interp_add_ins (td
, MINT_CONV_I8_U4
);
4672 interp_add_ins (td
, MINT_CONV_OVF_I8_UN_R4
);
4675 g_assert_not_reached ();
4678 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
4683 CHECK_STACK (td
, 1);
4684 token
= read32 (td
->ip
+ 1);
4685 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4686 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
4688 klass
= mini_get_class (method
, token
, generic_context
);
4689 CHECK_TYPELOAD (klass
);
4691 if (mono_class_is_nullable (klass
)) {
4692 MonoMethod
*target_method
= mono_class_get_method_from_name_checked (klass
, "Box", 1, 0, error
);
4693 goto_if_nok (error
, exit
);
4694 /* td->ip is incremented by interp_transform_call */
4695 if (!interp_transform_call (td
, method
, target_method
, domain
, generic_context
, td
->is_bb_start
, NULL
, FALSE
, error
, FALSE
, FALSE
))
4697 } else if (!m_class_is_valuetype (klass
)) {
4698 /* already boxed, do nothing. */
4701 if (G_UNLIKELY (m_class_is_byreflike (klass
))) {
4702 mono_error_set_bad_image (error
, image
, "Cannot box IsByRefLike type '%s.%s'", m_class_get_name_space (klass
), m_class_get_name (klass
));
4705 if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
) {
4706 size
= mono_class_value_size (klass
, NULL
);
4707 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
4709 } else if (td
->sp
[-1].type
== STACK_TYPE_R8
&& m_class_get_byval_arg (klass
)->type
== MONO_TYPE_R4
) {
4710 interp_add_ins (td
, MINT_CONV_R4_R8
);
4712 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, klass
, error
);
4713 goto_if_nok (error
, exit
);
4715 if (mint_type (m_class_get_byval_arg (klass
)) == MINT_TYPE_VT
)
4716 interp_add_ins (td
, MINT_BOX_VT
);
4718 interp_add_ins (td
, MINT_BOX
);
4719 td
->last_ins
->data
[0] = get_data_item_index (td
, vtable
);
4720 td
->last_ins
->data
[1] = 0;
4721 SET_TYPE(td
->sp
- 1, STACK_TYPE_O
, klass
);
4728 CHECK_STACK (td
, 1);
4729 token
= read32 (td
->ip
+ 1);
4731 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4732 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
4734 klass
= mini_get_class (method
, token
, generic_context
);
4735 CHECK_TYPELOAD (klass
);
4737 MonoClass
*array_class
= mono_class_create_array (klass
, 1);
4738 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, array_class
, error
);
4739 goto_if_nok (error
, exit
);
4741 unsigned char lentype
= (td
->sp
- 1)->type
;
4742 if (lentype
== STACK_TYPE_I8
) {
4743 /* mimic mini behaviour */
4744 interp_add_ins (td
, MINT_CONV_OVF_U4_I8
);
4746 g_assert (lentype
== STACK_TYPE_I4
);
4747 interp_add_ins (td
, MINT_CONV_OVF_U4_I4
);
4749 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I4
);
4750 interp_add_ins (td
, MINT_NEWARR
);
4751 td
->last_ins
->data
[0] = get_data_item_index (td
, vtable
);
4752 SET_TYPE (td
->sp
- 1, STACK_TYPE_O
, klass
);
4757 CHECK_STACK (td
, 1);
4758 SIMPLE_OP (td
, MINT_LDLEN
);
4759 #ifdef MONO_BIG_ARRAYS
4760 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I8
);
4762 SET_SIMPLE_TYPE (td
->sp
- 1, STACK_TYPE_I4
);
4767 CHECK_STACK (td
, 2);
4769 token
= read32 (td
->ip
+ 1);
4771 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4772 klass
= (MonoClass
*) mono_method_get_wrapper_data (method
, token
);
4774 klass
= mini_get_class (method
, token
, generic_context
);
4776 CHECK_TYPELOAD (klass
);
4778 if (!m_class_is_valuetype (klass
) && method
->wrapper_type
== MONO_WRAPPER_NONE
&& !readonly
) {
4780 * Check the class for failures before the type check, which can
4781 * throw other exceptions.
4783 mono_class_setup_vtable (klass
);
4784 CHECK_TYPELOAD (klass
);
4785 interp_add_ins (td
, MINT_LDELEMA_TC
);
4786 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
4787 td
->last_ins
->data
[1] = 2;
4789 interp_add_ins (td
, MINT_LDELEMA_FAST
);
4790 mono_class_init_internal (klass
);
4791 size
= mono_class_array_element_size (klass
);
4792 WRITE32_INS (td
->last_ins
, 0, &size
);
4799 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
4803 CHECK_STACK (td
, 2);
4805 SIMPLE_OP (td
, MINT_LDELEM_I1
);
4807 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4810 CHECK_STACK (td
, 2);
4812 SIMPLE_OP (td
, MINT_LDELEM_U1
);
4814 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4817 CHECK_STACK (td
, 2);
4819 SIMPLE_OP (td
, MINT_LDELEM_I2
);
4821 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4824 CHECK_STACK (td
, 2);
4826 SIMPLE_OP (td
, MINT_LDELEM_U2
);
4828 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4831 CHECK_STACK (td
, 2);
4833 SIMPLE_OP (td
, MINT_LDELEM_I4
);
4835 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4838 CHECK_STACK (td
, 2);
4840 SIMPLE_OP (td
, MINT_LDELEM_U4
);
4842 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4845 CHECK_STACK (td
, 2);
4847 SIMPLE_OP (td
, MINT_LDELEM_I8
);
4849 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
4852 CHECK_STACK (td
, 2);
4854 SIMPLE_OP (td
, MINT_LDELEM_I
);
4856 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I
);
4859 CHECK_STACK (td
, 2);
4861 SIMPLE_OP (td
, MINT_LDELEM_R4
);
4863 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R4
);
4866 CHECK_STACK (td
, 2);
4868 SIMPLE_OP (td
, MINT_LDELEM_R8
);
4870 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
4872 case CEE_LDELEM_REF
:
4873 CHECK_STACK (td
, 2);
4875 SIMPLE_OP (td
, MINT_LDELEM_REF
);
4877 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_O
);
4880 CHECK_STACK (td
, 2);
4881 token
= read32 (td
->ip
+ 1);
4882 klass
= mini_get_class (method
, token
, generic_context
);
4883 CHECK_TYPELOAD (klass
);
4884 switch (mint_type (m_class_get_byval_arg (klass
))) {
4887 SIMPLE_OP (td
, MINT_LDELEM_I1
);
4889 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4893 SIMPLE_OP (td
, MINT_LDELEM_U1
);
4895 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4899 SIMPLE_OP (td
, MINT_LDELEM_U2
);
4901 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4905 SIMPLE_OP (td
, MINT_LDELEM_I2
);
4907 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4911 SIMPLE_OP (td
, MINT_LDELEM_I4
);
4913 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
4917 SIMPLE_OP (td
, MINT_LDELEM_I8
);
4919 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
4923 SIMPLE_OP (td
, MINT_LDELEM_R4
);
4925 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R4
);
4929 SIMPLE_OP (td
, MINT_LDELEM_R8
);
4931 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_R8
);
4935 SIMPLE_OP (td
, MINT_LDELEM_REF
);
4937 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_O
);
4939 case MINT_TYPE_VT
: {
4940 int size
= mono_class_value_size (klass
, NULL
);
4942 SIMPLE_OP (td
, MINT_LDELEM_VT
);
4943 WRITE32_INS (td
->last_ins
, 0, &size
);
4945 SET_TYPE (td
->sp
- 1, STACK_TYPE_VT
, klass
);
4950 GString
*res
= g_string_new ("");
4951 mono_type_get_desc (res
, m_class_get_byval_arg (klass
), TRUE
);
4952 g_print ("LDELEM: %s -> %d (%s)\n", m_class_get_name (klass
), mint_type (m_class_get_byval_arg (klass
)), res
->str
);
4953 g_string_free (res
, TRUE
);
4961 CHECK_STACK (td
, 3);
4963 SIMPLE_OP (td
, MINT_STELEM_I
);
4967 CHECK_STACK (td
, 3);
4969 SIMPLE_OP (td
, MINT_STELEM_I1
);
4973 CHECK_STACK (td
, 3);
4975 SIMPLE_OP (td
, MINT_STELEM_I2
);
4979 CHECK_STACK (td
, 3);
4981 SIMPLE_OP (td
, MINT_STELEM_I4
);
4985 CHECK_STACK (td
, 3);
4987 SIMPLE_OP (td
, MINT_STELEM_I8
);
4991 CHECK_STACK (td
, 3);
4993 SIMPLE_OP (td
, MINT_STELEM_R4
);
4997 CHECK_STACK (td
, 3);
4999 SIMPLE_OP (td
, MINT_STELEM_R8
);
5002 case CEE_STELEM_REF
:
5003 CHECK_STACK (td
, 3);
5005 SIMPLE_OP (td
, MINT_STELEM_REF
);
5009 CHECK_STACK (td
, 3);
5011 token
= read32 (td
->ip
+ 1);
5012 klass
= mini_get_class (method
, token
, generic_context
);
5013 CHECK_TYPELOAD (klass
);
5014 switch (mint_type (m_class_get_byval_arg (klass
))) {
5016 SIMPLE_OP (td
, MINT_STELEM_I1
);
5019 SIMPLE_OP (td
, MINT_STELEM_U1
);
5022 SIMPLE_OP (td
, MINT_STELEM_I2
);
5025 SIMPLE_OP (td
, MINT_STELEM_U2
);
5028 SIMPLE_OP (td
, MINT_STELEM_I4
);
5031 SIMPLE_OP (td
, MINT_STELEM_I8
);
5034 SIMPLE_OP (td
, MINT_STELEM_R4
);
5037 SIMPLE_OP (td
, MINT_STELEM_R8
);
5040 SIMPLE_OP (td
, MINT_STELEM_REF
);
5042 case MINT_TYPE_VT
: {
5043 int size
= mono_class_value_size (klass
, NULL
);
5044 SIMPLE_OP (td
, MINT_STELEM_VT
);
5045 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
5046 WRITE32_INS (td
->last_ins
, 1, &size
);
5051 GString
*res
= g_string_new ("");
5052 mono_type_get_desc (res
, m_class_get_byval_arg (klass
), TRUE
);
5053 g_print ("STELEM: %s -> %d (%s)\n", m_class_get_name (klass
), mint_type (m_class_get_byval_arg (klass
)), res
->str
);
5054 g_string_free (res
, TRUE
);
5063 case CEE_CONV_OVF_U1
:
5065 case CEE_CONV_OVF_I8
:
5067 #if SIZEOF_VOID_P == 8
5068 case CEE_CONV_OVF_U
:
5072 CHECK_STACK (td
, 1);
5073 SIMPLE_OP (td
, MINT_CKFINITE
);
5076 CHECK_STACK (td
, 1);
5078 token
= read32 (td
->ip
+ 1);
5079 klass
= mini_get_class (method
, token
, generic_context
);
5080 CHECK_TYPELOAD (klass
);
5082 interp_add_ins (td
, MINT_MKREFANY
);
5083 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
5086 PUSH_VT (td
, sizeof (MonoTypedRef
));
5087 SET_TYPE(td
->sp
- 1, STACK_TYPE_VT
, mono_defaults
.typed_reference_class
);
5089 case CEE_REFANYVAL
: {
5090 CHECK_STACK (td
, 1);
5092 token
= read32 (td
->ip
+ 1);
5093 klass
= mini_get_class (method
, token
, generic_context
);
5094 CHECK_TYPELOAD (klass
);
5096 interp_add_ins (td
, MINT_REFANYVAL
);
5097 td
->last_ins
->data
[0] = get_data_item_index (td
, klass
);
5099 POP_VT (td
, sizeof (MonoTypedRef
));
5100 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
5105 case CEE_CONV_OVF_I1
:
5106 case CEE_CONV_OVF_I1_UN
: {
5107 gboolean is_un
= *td
->ip
== CEE_CONV_OVF_I1_UN
;
5108 CHECK_STACK (td
, 1);
5109 switch (td
->sp
[-1].type
) {
5111 interp_add_ins (td
, is_un
? MINT_CONV_OVF_I1_UN_R8
: MINT_CONV_OVF_I1_R8
);
5114 interp_add_ins (td
, is_un
? MINT_CONV_OVF_I1_U4
: MINT_CONV_OVF_I1_I4
);
5117 interp_add_ins (td
, is_un
? MINT_CONV_OVF_I1_U8
: MINT_CONV_OVF_I1_I8
);
5120 g_assert_not_reached ();
5123 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5126 case CEE_CONV_OVF_U1
:
5127 case CEE_CONV_OVF_U1_UN
:
5128 CHECK_STACK (td
, 1);
5129 switch (td
->sp
[-1].type
) {
5131 interp_add_ins (td
, MINT_CONV_OVF_U1_R8
);
5134 interp_add_ins (td
, MINT_CONV_OVF_U1_I4
);
5137 interp_add_ins (td
, MINT_CONV_OVF_U1_I8
);
5140 g_assert_not_reached ();
5143 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5145 case CEE_CONV_OVF_I2
:
5146 case CEE_CONV_OVF_I2_UN
: {
5147 gboolean is_un
= *td
->ip
== CEE_CONV_OVF_I2_UN
;
5148 CHECK_STACK (td
, 1);
5149 switch (td
->sp
[-1].type
) {
5151 interp_add_ins (td
, is_un
? MINT_CONV_OVF_I2_UN_R8
: MINT_CONV_OVF_I2_R8
);
5154 interp_add_ins (td
, is_un
? MINT_CONV_OVF_I2_U4
: MINT_CONV_OVF_I2_I4
);
5157 interp_add_ins (td
, is_un
? MINT_CONV_OVF_I2_U8
: MINT_CONV_OVF_I2_I8
);
5160 g_assert_not_reached ();
5163 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5166 case CEE_CONV_OVF_U2_UN
:
5167 case CEE_CONV_OVF_U2
:
5168 CHECK_STACK (td
, 1);
5169 switch (td
->sp
[-1].type
) {
5171 interp_add_ins (td
, MINT_CONV_OVF_U2_R8
);
5174 interp_add_ins (td
, MINT_CONV_OVF_U2_I4
);
5177 interp_add_ins (td
, MINT_CONV_OVF_U2_I8
);
5180 g_assert_not_reached ();
5183 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5185 #if SIZEOF_VOID_P == 4
5186 case CEE_CONV_OVF_I
:
5188 case CEE_CONV_OVF_I4
:
5189 case CEE_CONV_OVF_I4_UN
:
5190 CHECK_STACK (td
, 1);
5191 switch (td
->sp
[-1].type
) {
5193 interp_add_ins (td
, MINT_CONV_OVF_I4_R4
);
5196 interp_add_ins (td
, MINT_CONV_OVF_I4_R8
);
5199 if (*td
->ip
== CEE_CONV_OVF_I4_UN
)
5200 interp_add_ins (td
, MINT_CONV_OVF_I4_U4
);
5203 if (*td
->ip
== CEE_CONV_OVF_I4_UN
)
5204 interp_add_ins (td
, MINT_CONV_OVF_I4_U8
);
5206 interp_add_ins (td
, MINT_CONV_OVF_I4_I8
);
5209 g_assert_not_reached ();
5212 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5214 #if SIZEOF_VOID_P == 4
5215 case CEE_CONV_OVF_U
:
5217 case CEE_CONV_OVF_U4
:
5218 case CEE_CONV_OVF_U4_UN
:
5219 CHECK_STACK (td
, 1);
5220 switch (td
->sp
[-1].type
) {
5222 interp_add_ins (td
, MINT_CONV_OVF_U4_R4
);
5225 interp_add_ins (td
, MINT_CONV_OVF_U4_R8
);
5228 if (*td
->ip
!= CEE_CONV_OVF_U4_UN
)
5229 interp_add_ins (td
, MINT_CONV_OVF_U4_I4
);
5232 interp_add_ins (td
, MINT_CONV_OVF_U4_I8
);
5235 interp_add_ins (td
, MINT_CONV_OVF_U4_P
);
5238 g_assert_not_reached ();
5241 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5243 #if SIZEOF_VOID_P == 8
5244 case CEE_CONV_OVF_I
:
5246 case CEE_CONV_OVF_I8
:
5247 CHECK_STACK (td
, 1);
5248 switch (td
->sp
[-1].type
) {
5250 interp_add_ins (td
, MINT_CONV_OVF_I8_R4
);
5253 interp_add_ins (td
, MINT_CONV_OVF_I8_R8
);
5256 interp_add_ins (td
, MINT_CONV_I8_I4
);
5261 g_assert_not_reached ();
5264 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
5266 #if SIZEOF_VOID_P == 8
5267 case CEE_CONV_OVF_U
:
5269 case CEE_CONV_OVF_U8
:
5270 CHECK_STACK (td
, 1);
5271 switch (td
->sp
[-1].type
) {
5273 interp_add_ins (td
, MINT_CONV_OVF_U8_R4
);
5276 interp_add_ins (td
, MINT_CONV_OVF_U8_R8
);
5279 interp_add_ins (td
, MINT_CONV_OVF_U8_I4
);
5282 interp_add_ins (td
, MINT_CONV_OVF_U8_I8
);
5285 g_assert_not_reached ();
5288 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I8
);
5293 token
= read32 (td
->ip
+ 1);
5294 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
|| method
->wrapper_type
== MONO_WRAPPER_SYNCHRONIZED
) {
5295 handle
= mono_method_get_wrapper_data (method
, token
);
5296 klass
= (MonoClass
*) mono_method_get_wrapper_data (method
, token
+ 1);
5297 if (klass
== mono_defaults
.typehandle_class
)
5298 handle
= m_class_get_byval_arg ((MonoClass
*) handle
);
5300 if (generic_context
) {
5301 handle
= mono_class_inflate_generic_type_checked ((MonoType
*)handle
, generic_context
, error
);
5302 goto_if_nok (error
, exit
);
5305 handle
= mono_ldtoken_checked (image
, token
, &klass
, generic_context
, error
);
5306 goto_if_nok (error
, exit
);
5308 mono_class_init_internal (klass
);
5309 mt
= mint_type (m_class_get_byval_arg (klass
));
5310 g_assert (mt
== MINT_TYPE_VT
);
5311 size
= mono_class_value_size (klass
, NULL
);
5312 g_assert (size
== sizeof(gpointer
));
5314 const unsigned char *next_ip
= td
->ip
+ 5;
5315 MonoMethod
*cmethod
;
5316 if (next_ip
< end
&&
5317 !td
->is_bb_start
[next_ip
- td
->il_code
] &&
5318 (*next_ip
== CEE_CALL
|| *next_ip
== CEE_CALLVIRT
) &&
5319 (cmethod
= mono_get_method_checked (image
, read32 (next_ip
+ 1), NULL
, generic_context
, error
)) &&
5320 (cmethod
->klass
== mono_defaults
.systemtype_class
) &&
5321 (strcmp (cmethod
->name
, "GetTypeFromHandle") == 0)) {
5322 interp_add_ins (td
, MINT_MONO_LDPTR
);
5323 gpointer systype
= mono_type_get_object_checked (domain
, (MonoType
*)handle
, error
);
5324 goto_if_nok (error
, exit
);
5325 td
->last_ins
->data
[0] = get_data_item_index (td
, systype
);
5326 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_MP
);
5327 td
->ip
= next_ip
+ 5;
5329 PUSH_VT (td
, sizeof(gpointer
));
5330 interp_add_ins (td
, MINT_LDTOKEN
);
5331 td
->last_ins
->data
[0] = get_data_item_index (td
, handle
);
5332 PUSH_TYPE (td
, stack_type
[mt
], klass
);
5339 binary_arith_op(td
, MINT_ADD_OVF_I4
);
5342 case CEE_ADD_OVF_UN
:
5343 binary_arith_op(td
, MINT_ADD_OVF_UN_I4
);
5347 binary_arith_op(td
, MINT_MUL_OVF_I4
);
5350 case CEE_MUL_OVF_UN
:
5351 binary_arith_op(td
, MINT_MUL_OVF_UN_I4
);
5355 binary_arith_op(td
, MINT_SUB_OVF_I4
);
5358 case CEE_SUB_OVF_UN
:
5359 binary_arith_op(td
, MINT_SUB_OVF_UN_I4
);
5362 case CEE_ENDFINALLY
: {
5363 g_assert (td
->clause_indexes
[in_offset
] != -1);
5365 SIMPLE_OP (td
, MINT_ENDFINALLY
);
5366 td
->last_ins
->data
[0] = td
->clause_indexes
[in_offset
];
5367 // next instructions are always part of new bb
5368 td
->is_bb_start
[td
->ip
- header
->code
] = 1;
5375 if (*td
->ip
== CEE_LEAVE
)
5376 offset
= 5 + read32 (td
->ip
+ 1);
5378 offset
= 2 + (gint8
)td
->ip
[1];
5381 if (td
->clause_indexes
[in_offset
] != -1) {
5382 /* LEAVE instructions in catch clauses need to check for abort exceptions */
5383 handle_branch (td
, MINT_LEAVE_S_CHECK
, MINT_LEAVE_CHECK
, offset
);
5385 handle_branch (td
, MINT_LEAVE_S
, MINT_LEAVE
, offset
);
5388 if (*td
->ip
== CEE_LEAVE
)
5394 case MONO_CUSTOM_PREFIX
:
5397 case CEE_MONO_RETHROW
:
5398 CHECK_STACK (td
, 1);
5399 SIMPLE_OP (td
, MINT_MONO_RETHROW
);
5403 case CEE_MONO_LD_DELEGATE_METHOD_PTR
:
5406 interp_add_ins (td
, MINT_LD_DELEGATE_METHOD_PTR
);
5407 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
5409 case CEE_MONO_CALLI_EXTRA_ARG
:
5410 /* Same as CEE_CALLI, except that we drop the extra arg required for llvm specific behaviour */
5411 interp_add_ins (td
, MINT_POP
);
5412 td
->last_ins
->data
[0] = 1;
5414 if (!interp_transform_call (td
, method
, NULL
, domain
, generic_context
, td
->is_bb_start
, NULL
, FALSE
, error
, FALSE
, FALSE
))
5417 case CEE_MONO_JIT_ICALL_ADDR
: {
5418 const guint32 token
= read32 (td
->ip
+ 1);
5420 const gconstpointer func
= mono_find_jit_icall_info ((MonoJitICallId
)token
)->func
;
5422 interp_add_ins (td
, MINT_LDFTN
);
5423 td
->last_ins
->data
[0] = get_data_item_index (td
, (gpointer
)func
);
5424 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
5427 case CEE_MONO_ICALL
: {
5428 MonoJitICallId
const jit_icall_id
= (MonoJitICallId
)read32 (td
->ip
+ 1);
5429 MonoJitICallInfo
const * const info
= mono_find_jit_icall_info (jit_icall_id
);
5432 CHECK_STACK (td
, info
->sig
->param_count
);
5433 if (jit_icall_id
== MONO_JIT_ICALL_mono_threads_attach_coop
) {
5434 rtm
->needs_thread_attach
= 1;
5436 /* attach needs two arguments, and has one return value: leave one element on the stack */
5437 interp_add_ins (td
, MINT_POP
);
5438 td
->last_ins
->data
[0] = 0;
5439 } else if (jit_icall_id
== MONO_JIT_ICALL_mono_threads_detach_coop
) {
5440 g_assert (rtm
->needs_thread_attach
);
5442 /* detach consumes two arguments, and no return value: drop both of them */
5443 interp_add_ins (td
, MINT_POP
);
5444 td
->last_ins
->data
[0] = 0;
5445 interp_add_ins (td
, MINT_POP
);
5446 td
->last_ins
->data
[0] = 0;
5448 int const icall_op
= interp_icall_op_for_sig (info
->sig
);
5449 g_assert (icall_op
!= -1);
5451 interp_add_ins (td
, icall_op
);
5452 // hash here is overkill
5453 td
->last_ins
->data
[0] = get_data_item_index (td
, (gpointer
)info
->func
);
5455 td
->sp
-= info
->sig
->param_count
;
5457 if (!MONO_TYPE_IS_VOID (info
->sig
->ret
)) {
5458 int mt
= mint_type (info
->sig
->ret
);
5459 PUSH_SIMPLE_TYPE(td
, stack_type
[mt
]);
5463 case CEE_MONO_VTADDR
: {
5465 CHECK_STACK (td
, 1);
5466 if (method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
5467 size
= mono_class_native_size(td
->sp
[-1].klass
, NULL
);
5469 size
= mono_class_value_size(td
->sp
[-1].klass
, NULL
);
5470 size
= ALIGN_TO (size
, MINT_VT_ALIGNMENT
);
5471 interp_add_ins (td
, MINT_VTRESULT
);
5472 td
->last_ins
->data
[0] = 0;
5473 WRITE32_INS (td
->last_ins
, 1, &size
);
5476 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
5479 case CEE_MONO_LDPTR
:
5480 case CEE_MONO_CLASSCONST
:
5481 token
= read32 (td
->ip
+ 1);
5483 interp_add_ins (td
, MINT_MONO_LDPTR
);
5484 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_method_get_wrapper_data (method
, token
));
5485 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
5487 case CEE_MONO_OBJADDR
:
5488 CHECK_STACK (td
, 1);
5490 td
->sp
[-1].type
= STACK_TYPE_MP
;
5493 case CEE_MONO_NEWOBJ
:
5494 token
= read32 (td
->ip
+ 1);
5496 interp_add_ins (td
, MINT_MONO_NEWOBJ
);
5497 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_method_get_wrapper_data (method
, token
));
5498 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_O
);
5500 case CEE_MONO_RETOBJ
:
5501 CHECK_STACK (td
, 1);
5502 token
= read32 (td
->ip
+ 1);
5504 interp_add_ins (td
, MINT_MONO_RETOBJ
);
5507 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
5509 /*stackval_from_data (signature->ret, frame->retval, sp->data.vt, signature->pinvoke);*/
5511 if (td
->sp
> td
->stack
)
5512 g_warning ("CEE_MONO_RETOBJ: more values on stack: %d", td
->sp
-td
->stack
);
5514 case CEE_MONO_LDNATIVEOBJ
:
5515 token
= read32 (td
->ip
+ 1);
5517 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
5518 g_assert(m_class_is_valuetype (klass
));
5519 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
5521 case CEE_MONO_TLS
: {
5522 gint32 key
= read32 (td
->ip
+ 1);
5524 g_assertf (key
== TLS_KEY_SGEN_THREAD_INFO
, "%d", key
);
5525 interp_add_ins (td
, MINT_MONO_SGEN_THREAD_INFO
);
5526 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_MP
);
5529 case CEE_MONO_ATOMIC_STORE_I4
:
5530 CHECK_STACK (td
, 2);
5531 SIMPLE_OP (td
, MINT_MONO_ATOMIC_STORE_I4
);
5535 case CEE_MONO_SAVE_LMF
:
5536 case CEE_MONO_RESTORE_LMF
:
5537 case CEE_MONO_NOT_TAKEN
:
5540 case CEE_MONO_LDPTR_INT_REQ_FLAG
:
5541 interp_add_ins (td
, MINT_MONO_LDPTR
);
5542 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_thread_interruption_request_flag ());
5543 PUSH_TYPE (td
, STACK_TYPE_MP
, NULL
);
5546 case CEE_MONO_MEMORY_BARRIER
:
5547 interp_add_ins (td
, MINT_MONO_MEMORY_BARRIER
);
5550 case CEE_MONO_LDDOMAIN
:
5551 interp_add_ins (td
, MINT_MONO_LDDOMAIN
);
5552 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_I
);
5555 case CEE_MONO_SAVE_LAST_ERROR
:
5556 save_last_error
= TRUE
;
5560 g_error ("transform.c: Unimplemented opcode: 0xF0 %02x at 0x%x\n", *td
->ip
, td
->ip
-header
->code
);
5570 case CEE_PREFIXREF
: ves_abort(); break;
5573 * Note: Exceptions thrown when executing a prefixed opcode need
5574 * to take into account the number of prefix bytes (usually the
5575 * throw point is just (ip - n_prefix_bytes).
5581 interp_add_ins (td
, MINT_ARGLIST
);
5582 PUSH_VT (td
, SIZEOF_VOID_P
);
5583 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_VT
);
5588 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
) {
5589 interp_add_ins (td
, MINT_CEQ_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
5591 if (td
->sp
[-1].type
== STACK_TYPE_R4
&& td
->sp
[-2].type
== STACK_TYPE_R8
)
5592 interp_add_ins (td
, MINT_CONV_R8_R4
);
5593 if (td
->sp
[-1].type
== STACK_TYPE_R8
&& td
->sp
[-2].type
== STACK_TYPE_R4
)
5594 interp_add_ins (td
, MINT_CONV_R8_R4_SP
);
5595 interp_add_ins (td
, MINT_CEQ_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
5598 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5603 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
)
5604 interp_add_ins (td
, MINT_CGT_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
5606 interp_add_ins (td
, MINT_CGT_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
5608 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5613 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
)
5614 interp_add_ins (td
, MINT_CGT_UN_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
5616 interp_add_ins (td
, MINT_CGT_UN_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
5618 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5623 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
)
5624 interp_add_ins (td
, MINT_CLT_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
5626 interp_add_ins (td
, MINT_CLT_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
5628 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5633 if (td
->sp
[-1].type
== STACK_TYPE_O
|| td
->sp
[-1].type
== STACK_TYPE_MP
)
5634 interp_add_ins (td
, MINT_CLT_UN_I4
+ STACK_TYPE_I
- STACK_TYPE_I4
);
5636 interp_add_ins (td
, MINT_CLT_UN_I4
+ td
->sp
[-1].type
- STACK_TYPE_I4
);
5638 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_I4
);
5641 case CEE_LDVIRTFTN
: /* fallthrough */
5644 if (*td
->ip
== CEE_LDVIRTFTN
) {
5645 CHECK_STACK (td
, 1);
5648 token
= read32 (td
->ip
+ 1);
5649 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
5650 m
= (MonoMethod
*)mono_method_get_wrapper_data (method
, token
);
5652 m
= mono_get_method_checked (image
, token
, NULL
, generic_context
, error
);
5653 goto_if_nok (error
, exit
);
5656 if (!mono_method_can_access_method (method
, m
))
5657 interp_generate_mae_throw (td
, method
, m
);
5659 if (method
->wrapper_type
== MONO_WRAPPER_NONE
&& m
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)
5660 m
= mono_marshal_get_synchronized_wrapper (m
);
5662 interp_add_ins (td
, *td
->ip
== CEE_LDFTN
? MINT_LDFTN
: MINT_LDVIRTFTN
);
5663 td
->last_ins
->data
[0] = get_data_item_index (td
, mono_interp_get_imethod (domain
, m
, error
));
5664 goto_if_nok (error
, exit
);
5666 PUSH_SIMPLE_TYPE (td
, STACK_TYPE_F
);
5670 int arg_n
= read16 (td
->ip
+ 1);
5672 load_arg (td
, arg_n
);
5674 load_local_general (td
, arg_offsets
[arg_n
], get_arg_type (signature
, arg_n
));
5679 int n
= read16 (td
->ip
+ 1);
5682 get_arg_type_exact (td
, n
, &mt
);
5683 interp_add_ins (td
, mt
== MINT_TYPE_VT
? MINT_LDARGA_VT
: MINT_LDARGA
);
5684 td
->last_ins
->data
[0] = n
;
5686 interp_add_ins (td
, MINT_LDLOCA_S
);
5687 td
->last_ins
->data
[0] = arg_offsets
[n
];
5689 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
5694 int arg_n
= read16 (td
->ip
+ 1);
5696 store_arg (td
, arg_n
);
5698 store_local_general (td
, arg_offsets
[arg_n
], get_arg_type (signature
, arg_n
));
5703 int loc_n
= read16 (td
->ip
+ 1);
5705 load_local (td
, loc_n
);
5707 load_local_general (td
, local_offsets
[loc_n
], header
->locals
[loc_n
]);
5712 int loc_n
= read16 (td
->ip
+ 1);
5713 interp_add_ins (td
, MINT_LDLOCA_S
);
5715 td
->last_ins
->data
[0] = td
->rtm
->local_offsets
[loc_n
];
5717 td
->last_ins
->data
[0] = local_offsets
[loc_n
];
5718 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_MP
);
5723 int loc_n
= read16 (td
->ip
+ 1);
5725 store_local (td
, loc_n
);
5727 store_local_general (td
, local_offsets
[loc_n
], header
->locals
[loc_n
]);
5733 CHECK_STACK (td
, 1);
5734 #if SIZEOF_VOID_P == 8
5735 if (td
->sp
[-1].type
== STACK_TYPE_I8
)
5736 interp_add_ins (td
, MINT_CONV_I4_I8
);
5738 interp_add_ins (td
, MINT_LOCALLOC
);
5739 if (td
->sp
!= td
->stack
+ 1)
5740 g_warning("CEE_LOCALLOC: stack not empty");
5742 SET_SIMPLE_TYPE(td
->sp
- 1, STACK_TYPE_MP
);
5745 case CEE_UNUSED57
: ves_abort(); break;
5748 interp_add_ins (td
, MINT_ENDFILTER
);
5751 case CEE_UNALIGNED_
:
5760 /* FIX: should do something? */;
5761 // TODO: This should raise a method_tail_call profiler event.
5765 token
= read32 (td
->ip
+ 1);
5766 klass
= mini_get_class (method
, token
, generic_context
);
5767 CHECK_TYPELOAD (klass
);
5768 if (m_class_is_valuetype (klass
)) {
5769 interp_add_ins (td
, MINT_INITOBJ
);
5770 i32
= mono_class_value_size (klass
, NULL
);
5771 WRITE32_INS (td
->last_ins
, 0, &i32
);
5774 interp_add_ins (td
, MINT_LDNULL
);
5775 PUSH_TYPE(td
, STACK_TYPE_O
, NULL
);
5776 interp_add_ins (td
, MINT_STIND_REF
);
5783 /* FIX? convert length to I8? */
5785 interp_add_ins (td
, MINT_MONO_MEMORY_BARRIER
);
5786 interp_add_ins (td
, MINT_CPBLK
);
5787 BARRIER_IF_VOLATILE (td
);
5795 case CEE_CONSTRAINED_
:
5796 token
= read32 (td
->ip
+ 1);
5797 constrained_class
= mini_get_class (method
, token
, generic_context
);
5798 CHECK_TYPELOAD (constrained_class
);
5803 BARRIER_IF_VOLATILE (td
);
5804 interp_add_ins (td
, MINT_INITBLK
);
5809 /* FIXME: implement */
5813 int clause_index
= td
->clause_indexes
[in_offset
];
5814 g_assert (clause_index
!= -1);
5815 SIMPLE_OP (td
, MINT_RETHROW
);
5816 td
->last_ins
->data
[0] = rtm
->exvar_offsets
[clause_index
];
5822 token
= read32 (td
->ip
+ 1);
5824 if (mono_metadata_token_table (token
) == MONO_TABLE_TYPESPEC
&& !image_is_dynamic (m_class_get_image (method
->klass
)) && !generic_context
) {
5826 MonoType
*type
= mono_type_create_from_typespec_checked (image
, token
, error
);
5827 goto_if_nok (error
, exit
);
5828 size
= mono_type_size (type
, &align
);
5831 MonoClass
*szclass
= mini_get_class (method
, token
, generic_context
);
5832 CHECK_TYPELOAD (szclass
);
5834 if (!szclass
->valuetype
)
5835 THROW_EX (mono_exception_from_name (mono_defaults
.corlib
, "System", "InvalidProgramException"), ip
- 5);
5837 size
= mono_type_size (m_class_get_byval_arg (szclass
), &align
);
5839 interp_add_ins (td
, MINT_LDC_I4
);
5840 WRITE32_INS (td
->last_ins
, 0, &size
);
5841 PUSH_SIMPLE_TYPE(td
, STACK_TYPE_I4
);
5844 case CEE_REFANYTYPE
:
5845 interp_add_ins (td
, MINT_REFANYTYPE
);
5847 POP_VT (td
, sizeof (MonoTypedRef
));
5848 PUSH_VT (td
, sizeof (gpointer
));
5849 SET_TYPE(td
->sp
- 1, STACK_TYPE_VT
, NULL
);
5852 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
);
5856 g_error ("transform.c: Unimplemented opcode: %02x at 0x%x\n", *td
->ip
, td
->ip
-header
->code
);
5859 // No IR instructions were added as part of a bb_start IL instruction. Add a MINT_NOP
5860 // so we always have an instruction associated with a bb_start. This is simple and avoids
5861 // any complications associated with il_offset tracking.
5862 if (prev_last_ins
== td
->last_ins
&& (!inlining
&& td
->is_bb_start
[in_offset
]) && td
->ip
< end
)
5863 interp_add_ins (td
, MINT_NOP
);
5866 g_assert (td
->ip
== end
);
5869 g_free (arg_offsets
);
5870 g_free (local_offsets
);
5871 mono_basic_block_free (original_bb
);
5879 // Find the offset of the first interp instruction generated starting il_offset
5880 // This is needed to find the end of clauses.
5882 find_in_offset (TransformData
*td
, int il_offset
)
5885 while (!td
->in_offsets
[i
])
5887 return td
->in_offsets
[i
] - 1;
5890 // We store in the in_offset array the native_offset + 1, so 0 can mean only that the il
5891 // offset is uninitialized. Otherwise 0 is valid value for first interp instruction.
5893 get_in_offset (TransformData
*td
, int il_offset
)
5895 int target_offset
= td
->in_offsets
[il_offset
];
5896 g_assert (target_offset
);
5897 return target_offset
- 1;
5901 handle_relocations (TransformData
*td
)
5903 // Handle relocations
5904 for (int i
= 0; i
< td
->relocs
->len
; ++i
) {
5905 Reloc
*reloc
= (Reloc
*)g_ptr_array_index (td
->relocs
, i
);
5906 int offset
= get_in_offset (td
, reloc
->target
) - reloc
->offset
;
5908 switch (reloc
->type
) {
5909 case RELOC_SHORT_BRANCH
:
5910 g_assert (td
->new_code
[reloc
->offset
+ 1] == 0xdead);
5911 td
->new_code
[reloc
->offset
+ 1] = offset
;
5913 case RELOC_LONG_BRANCH
: {
5914 guint16
*v
= (guint16
*) &offset
;
5915 g_assert (td
->new_code
[reloc
->offset
+ 1] == 0xdead);
5916 g_assert (td
->new_code
[reloc
->offset
+ 2] == 0xbeef);
5917 td
->new_code
[reloc
->offset
+ 1] = *(guint16
*) v
;
5918 td
->new_code
[reloc
->offset
+ 2] = *(guint16
*) (v
+ 1);
5921 case RELOC_SWITCH
: {
5922 guint16
*v
= (guint16
*)&offset
;
5923 g_assert (td
->new_code
[reloc
->offset
] == 0xdead);
5924 g_assert (td
->new_code
[reloc
->offset
+ 1] == 0xbeef);
5925 td
->new_code
[reloc
->offset
] = *(guint16
*)v
;
5926 td
->new_code
[reloc
->offset
+ 1] = *(guint16
*)(v
+ 1);
5930 g_assert_not_reached ();
5938 get_inst_length (InterpInst
*ins
)
5940 if (ins
->opcode
== MINT_SWITCH
)
5941 return MINT_SWITCH_LEN (READ32 (&ins
->data
[0]));
5943 return mono_interp_oplen
[ins
->opcode
];
5947 emit_compacted_instruction (TransformData
*td
, guint16
* start_ip
, InterpInst
*ins
)
5949 guint16 opcode
= ins
->opcode
;
5950 guint16
*ip
= start_ip
;
5952 // We know what IL offset this instruction was created for. We can now map the IL offset
5953 // to the IR offset. We use this array to resolve the relocations, which reference the IL.
5954 if (ins
->il_offset
!= -1 && !td
->in_offsets
[ins
->il_offset
]) {
5955 g_assert (ins
->il_offset
>= 0 && ins
->il_offset
< td
->header
->code_size
);
5956 td
->in_offsets
[ins
->il_offset
] = start_ip
- td
->new_code
+ 1;
5958 MonoDebugLineNumberEntry lne
;
5959 lne
.native_offset
= (guint8
*)start_ip
- (guint8
*)td
->new_code
;
5960 lne
.il_offset
= ins
->il_offset
;
5961 g_array_append_val (td
->line_numbers
, lne
);
5964 if (opcode
== MINT_NOP
)
5968 if (opcode
== MINT_SWITCH
) {
5969 int labels
= READ32 (&ins
->data
[0]);
5970 // Write number of switch labels
5971 *ip
++ = ins
->data
[0];
5972 *ip
++ = ins
->data
[1];
5973 // Add relocation for each label
5974 for (int i
= 0; i
< labels
; i
++) {
5975 Reloc
*reloc
= (Reloc
*)mono_mempool_alloc0 (td
->mempool
, sizeof (Reloc
));
5976 reloc
->type
= RELOC_SWITCH
;
5977 reloc
->offset
= ip
- td
->new_code
;
5978 reloc
->target
= READ32 (&ins
->data
[2 + i
* 2]);
5979 g_ptr_array_add (td
->relocs
, reloc
);
5983 } else if ((opcode
>= MINT_BRFALSE_I4_S
&& opcode
<= MINT_BRTRUE_R8_S
) ||
5984 (opcode
>= MINT_BEQ_I4_S
&& opcode
<= MINT_BLT_UN_R8_S
) ||
5985 opcode
== MINT_BR_S
|| opcode
== MINT_LEAVE_S
|| opcode
== MINT_LEAVE_S_CHECK
) {
5986 const int br_offset
= start_ip
- td
->new_code
;
5987 if (ins
->data
[0] < ins
->il_offset
) {
5988 // Backwards branch. We can already patch it.
5989 *ip
++ = get_in_offset (td
, ins
->data
[0]) - br_offset
;
5991 // We don't know the in_offset of the target, add a reloc
5992 Reloc
*reloc
= (Reloc
*)mono_mempool_alloc0 (td
->mempool
, sizeof (Reloc
));
5993 reloc
->type
= RELOC_SHORT_BRANCH
;
5994 reloc
->offset
= br_offset
;
5995 reloc
->target
= ins
->data
[0];
5996 g_ptr_array_add (td
->relocs
, reloc
);
5999 } else if ((opcode
>= MINT_BRFALSE_I4
&& opcode
<= MINT_BRTRUE_R8
) ||
6000 (opcode
>= MINT_BEQ_I4
&& opcode
<= MINT_BLT_UN_R8
) ||
6001 opcode
== MINT_BR
|| opcode
== MINT_LEAVE
|| opcode
== MINT_LEAVE_CHECK
) {
6002 const int br_offset
= start_ip
- td
->new_code
;
6003 int target_il
= READ32 (&ins
->data
[0]);
6004 if (target_il
< ins
->il_offset
) {
6005 // Backwards branch. We can already patch it
6006 const int br_offset
= start_ip
- td
->new_code
;
6007 int target_offset
= get_in_offset (td
, target_il
) - br_offset
;
6008 WRITE32 (ip
, &target_offset
);
6010 Reloc
*reloc
= (Reloc
*)mono_mempool_alloc0 (td
->mempool
, sizeof (Reloc
));
6011 reloc
->type
= RELOC_LONG_BRANCH
;
6012 reloc
->offset
= br_offset
;
6013 reloc
->target
= target_il
;
6014 g_ptr_array_add (td
->relocs
, reloc
);
6018 } else if (opcode
== MINT_SDB_SEQ_POINT
) {
6019 SeqPoint
*seqp
= (SeqPoint
*)mono_mempool_alloc0 (td
->mempool
, sizeof (SeqPoint
));
6020 InterpBasicBlock
*cbb
;
6022 if (ins
->flags
& INTERP_INST_FLAG_SEQ_POINT_METHOD_ENTRY
) {
6023 seqp
->il_offset
= METHOD_ENTRY_IL_OFFSET
;
6024 cbb
= td
->offset_to_bb
[0];
6026 if (ins
->flags
& INTERP_INST_FLAG_SEQ_POINT_METHOD_EXIT
)
6027 seqp
->il_offset
= METHOD_EXIT_IL_OFFSET
;
6029 seqp
->il_offset
= ins
->il_offset
;
6030 cbb
= td
->offset_to_bb
[ins
->il_offset
];
6032 seqp
->native_offset
= (guint8
*)start_ip
- (guint8
*)td
->new_code
;
6033 if (ins
->flags
& INTERP_INST_FLAG_SEQ_POINT_NONEMPTY_STACK
)
6034 seqp
->flags
|= MONO_SEQ_POINT_FLAG_NONEMPTY_STACK
;
6035 if (ins
->flags
& INTERP_INST_FLAG_SEQ_POINT_NESTED_CALL
)
6036 seqp
->flags
|= MONO_SEQ_POINT_FLAG_NESTED_CALL
;
6037 g_ptr_array_add (td
->seq_points
, seqp
);
6039 cbb
->seq_points
= g_slist_prepend_mempool (td
->mempool
, cbb
->seq_points
, seqp
);
6040 cbb
->last_seq_point
= seqp
;
6042 int size
= get_inst_length (ins
) - 1;
6043 // Emit the rest of the data
6044 for (int i
= 0; i
< size
; i
++)
6045 *ip
++ = ins
->data
[i
];
6050 // Generates the final code, after we are done with all the passes
6052 generate_compacted_code (TransformData
*td
)
6056 td
->relocs
= g_ptr_array_new ();
6058 // Iterate once to compute the exact size of the compacted code
6059 InterpInst
*ins
= td
->first_ins
;
6061 size
+= get_inst_length (ins
);
6065 // Generate the compacted stream of instructions
6066 td
->new_code
= ip
= (guint16
*)mono_domain_alloc0 (td
->rtm
->domain
, size
* sizeof (guint16
));
6067 ins
= td
->first_ins
;
6069 ip
= emit_compacted_instruction (td
, ip
, ins
);
6072 td
->new_code_end
= ip
;
6073 td
->in_offsets
[td
->header
->code_size
] = td
->new_code_end
- td
->new_code
;
6075 // Patch all branches
6076 handle_relocations (td
);
6078 g_ptr_array_free (td
->relocs
, TRUE
);
6082 generate (MonoMethod
*method
, MonoMethodHeader
*header
, InterpMethod
*rtm
, MonoGenericContext
*generic_context
, MonoError
*error
)
6084 MonoDomain
*domain
= rtm
->domain
;
6086 TransformData transform_data
;
6088 static gboolean verbose_method_inited
;
6089 static char* verbose_method_name
;
6091 if (!verbose_method_inited
) {
6092 verbose_method_name
= g_getenv ("MONO_VERBOSE_METHOD");
6093 verbose_method_inited
= TRUE
;
6096 memset (&transform_data
, 0, sizeof(transform_data
));
6097 td
= &transform_data
;
6099 td
->method
= method
;
6101 td
->code_size
= header
->code_size
;
6102 td
->header
= header
;
6103 td
->max_code_size
= td
->code_size
;
6104 td
->in_offsets
= (int*)g_malloc0((header
->code_size
+ 1) * sizeof(int));
6105 td
->stack_height
= (int*)g_malloc(header
->code_size
* sizeof(int));
6106 td
->stack_state
= (StackInfo
**)g_malloc0(header
->code_size
* sizeof(StackInfo
*));
6107 td
->vt_stack_size
= (int*)g_malloc(header
->code_size
* sizeof(int));
6108 td
->clause_indexes
= (int*)g_malloc (header
->code_size
* sizeof (int));
6109 td
->is_bb_start
= (guint8
*)g_malloc0(header
->code_size
);
6110 td
->mempool
= mono_mempool_new ();
6111 td
->n_data_items
= 0;
6112 td
->max_data_items
= 0;
6113 td
->data_items
= NULL
;
6114 td
->data_hash
= g_hash_table_new (NULL
, NULL
);
6115 td
->gen_sdb_seq_points
= mini_debug_options
.gen_sdb_seq_points
;
6116 td
->seq_points
= g_ptr_array_new ();
6117 td
->verbose_level
= mono_interp_traceopt
;
6118 td
->total_locals_size
= rtm
->locals_size
;
6119 rtm
->data_items
= td
->data_items
;
6121 if (verbose_method_name
) {
6122 const char *name
= verbose_method_name
;
6124 if ((strchr (name
, '.') > name
) || strchr (name
, ':')) {
6125 MonoMethodDesc
*desc
;
6127 desc
= mono_method_desc_new (name
, TRUE
);
6128 if (mono_method_desc_full_match (desc
, method
)) {
6129 td
->verbose_level
= 4;
6131 mono_method_desc_free (desc
);
6133 if (strcmp (method
->name
, name
) == 0)
6134 td
->verbose_level
= 4;
6138 td
->stack
= (StackInfo
*)g_malloc0 ((header
->max_stack
+ 1) * sizeof (td
->stack
[0]));
6139 td
->stack_capacity
= header
->max_stack
+ 1;
6141 td
->max_stack_height
= 0;
6142 td
->line_numbers
= g_array_new (FALSE
, TRUE
, sizeof (MonoDebugLineNumberEntry
));
6143 td
->current_il_offset
= -1;
6145 generate_code (td
, method
, header
, generic_context
, error
);
6146 goto_if_nok (error
, exit
);
6148 generate_compacted_code (td
);
6150 if (td
->verbose_level
) {
6151 g_print ("Runtime method: %s %p, VT stack size: %d\n", mono_method_full_name (method
, TRUE
), rtm
, td
->max_vt_sp
);
6152 g_print ("Calculated stack size: %d, stated size: %d\n", td
->max_stack_height
, header
->max_stack
);
6153 dump_mint_code (td
->new_code
, td
->new_code_end
);
6156 /* Check if we use excessive stack space */
6157 if (td
->max_stack_height
> header
->max_stack
* 3 && header
->max_stack
> 16)
6158 g_warning ("Excessive stack space usage for method %s, %d/%d", method
->name
, td
->max_stack_height
, header
->max_stack
);
6161 code_len
= td
->new_code_end
- td
->new_code
;
6163 rtm
->clauses
= (MonoExceptionClause
*)mono_domain_alloc0 (domain
, header
->num_clauses
* sizeof (MonoExceptionClause
));
6164 memcpy (rtm
->clauses
, header
->clauses
, header
->num_clauses
* sizeof(MonoExceptionClause
));
6165 rtm
->code
= (gushort
*)td
->new_code
;
6166 rtm
->init_locals
= header
->init_locals
;
6167 rtm
->num_clauses
= header
->num_clauses
;
6168 for (i
= 0; i
< header
->num_clauses
; i
++) {
6169 MonoExceptionClause
*c
= rtm
->clauses
+ i
;
6170 int end_off
= c
->try_offset
+ c
->try_len
;
6171 c
->try_offset
= get_in_offset (td
, c
->try_offset
);
6172 c
->try_len
= find_in_offset (td
, end_off
) - c
->try_offset
;
6173 g_assert ((c
->try_offset
+ c
->try_len
) < code_len
);
6174 end_off
= c
->handler_offset
+ c
->handler_len
;
6175 c
->handler_offset
= get_in_offset (td
, c
->handler_offset
);
6176 c
->handler_len
= find_in_offset (td
, end_off
) - c
->handler_offset
;
6177 g_assert (c
->handler_len
>= 0 && (c
->handler_offset
+ c
->handler_len
) <= code_len
);
6178 if (c
->flags
& MONO_EXCEPTION_CLAUSE_FILTER
)
6179 c
->data
.filter_offset
= get_in_offset (td
, c
->data
.filter_offset
);
6181 rtm
->stack_size
= (sizeof (stackval
)) * (td
->max_stack_height
+ 2); /* + 1 for returns of called functions + 1 for 0-ing in trace*/
6182 rtm
->stack_size
= ALIGN_TO (rtm
->stack_size
, MINT_VT_ALIGNMENT
);
6183 rtm
->vt_stack_size
= td
->max_vt_sp
;
6184 rtm
->total_locals_size
= td
->total_locals_size
;
6185 rtm
->alloca_size
= rtm
->total_locals_size
+ rtm
->vt_stack_size
+ rtm
->stack_size
;
6186 rtm
->data_items
= (gpointer
*)mono_domain_alloc0 (domain
, td
->n_data_items
* sizeof (td
->data_items
[0]));
6187 memcpy (rtm
->data_items
, td
->data_items
, td
->n_data_items
* sizeof (td
->data_items
[0]));
6189 /* Save debug info */
6190 interp_save_debug_info (rtm
, header
, td
, td
->line_numbers
);
6192 /* Create a MonoJitInfo for the interpreted method by creating the interpreter IR as the native code. */
6194 jinfo_len
= mono_jit_info_size ((MonoJitInfoFlags
)0, header
->num_clauses
, 0);
6196 jinfo
= (MonoJitInfo
*)mono_domain_alloc0 (domain
, jinfo_len
);
6197 jinfo
->is_interp
= 1;
6199 mono_jit_info_init (jinfo
, method
, (guint8
*)rtm
->code
, code_len
, (MonoJitInfoFlags
)0, header
->num_clauses
, 0);
6200 for (i
= 0; i
< jinfo
->num_clauses
; ++i
) {
6201 MonoJitExceptionInfo
*ei
= &jinfo
->clauses
[i
];
6202 MonoExceptionClause
*c
= rtm
->clauses
+ i
;
6204 ei
->flags
= c
->flags
;
6205 ei
->try_start
= (guint8
*)(rtm
->code
+ c
->try_offset
);
6206 ei
->try_end
= (guint8
*)(rtm
->code
+ c
->try_offset
+ c
->try_len
);
6207 ei
->handler_start
= (guint8
*)(rtm
->code
+ c
->handler_offset
);
6208 ei
->exvar_offset
= rtm
->exvar_offsets
[i
];
6209 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
6210 ei
->data
.filter
= (guint8
*)(rtm
->code
+ c
->data
.filter_offset
);
6211 } else if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
6212 ei
->data
.handler_end
= (guint8
*)(rtm
->code
+ c
->handler_offset
+ c
->handler_len
);
6214 ei
->data
.catch_class
= c
->data
.catch_class
;
6218 save_seq_points (td
, jinfo
);
6221 g_free (td
->in_offsets
);
6222 g_free (td
->stack_height
);
6223 for (i
= 0; i
< header
->code_size
; ++i
)
6224 g_free (td
->stack_state
[i
]);
6225 g_free (td
->stack_state
);
6226 g_free (td
->vt_stack_size
);
6227 g_free (td
->clause_indexes
);
6228 g_free (td
->data_items
);
6230 g_free (td
->is_bb_start
);
6231 g_hash_table_destroy (td
->data_hash
);
6232 g_ptr_array_free (td
->seq_points
, TRUE
);
6233 g_array_free (td
->line_numbers
, TRUE
);
6234 mono_mempool_destroy (td
->mempool
);
6237 static mono_mutex_t calc_section
;
6240 mono_interp_transform_init (void)
6242 mono_os_mutex_init_recursive(&calc_section
);
6246 mono_interp_transform_method (InterpMethod
*imethod
, ThreadContext
*context
, MonoError
*error
)
6248 MonoMethod
*method
= imethod
->method
;
6249 MonoMethodHeader
*header
= NULL
;
6250 MonoMethodSignature
*signature
= mono_method_signature_internal (method
);
6251 MonoVTable
*method_class_vt
;
6252 MonoGenericContext
*generic_context
= NULL
;
6253 MonoDomain
*domain
= imethod
->domain
;
6254 InterpMethod tmp_imethod
;
6255 InterpMethod
*real_imethod
;
6259 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (method
->klass
))) {
6260 mono_error_set_invalid_operation (error
, "%s", "Could not execute the method because the containing type is not fully instantiated.");
6264 // g_printerr ("TRANSFORM(0x%016lx): begin %s::%s\n", mono_thread_current (), method->klass->name, method->name);
6265 method_class_vt
= mono_class_vtable_checked (domain
, imethod
->method
->klass
, error
);
6266 return_if_nok (error
);
6268 if (!method_class_vt
->initialized
) {
6269 mono_runtime_class_init_full (method_class_vt
, error
);
6270 return_if_nok (error
);
6273 MONO_PROFILER_RAISE (jit_begin
, (method
));
6275 if (mono_method_signature_internal (method
)->is_inflated
)
6276 generic_context
= mono_method_get_context (method
);
6278 MonoGenericContainer
*generic_container
= mono_method_get_generic_container (method
);
6279 if (generic_container
)
6280 generic_context
= &generic_container
->context
;
6283 if (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)) {
6284 MonoMethod
*nm
= NULL
;
6285 if (imethod
->transformed
) {
6286 MONO_PROFILER_RAISE (jit_done
, (method
, imethod
->jinfo
));
6290 /* assumes all internal calls with an array this are built in... */
6291 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
&& (! mono_method_signature_internal (method
)->hasthis
|| m_class_get_rank (method
->klass
) == 0)) {
6292 nm
= mono_marshal_get_native_wrapper (method
, FALSE
, FALSE
);
6293 signature
= mono_method_signature_internal (nm
);
6295 const char *name
= method
->name
;
6296 if (m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) {
6297 if (*name
== '.' && (strcmp (name
, ".ctor") == 0)) {
6298 MonoJitICallInfo
*mi
= &mono_get_jit_icall_info ()->ves_icall_mono_delegate_ctor_interp
;
6299 nm
= mono_marshal_get_icall_wrapper (mi
, TRUE
);
6300 } else if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
6302 * Usually handled during transformation of the caller, but
6303 * when the caller is handled by another execution engine
6304 * (for example fullAOT) we need to handle it here. That's
6305 * known to be wrong in cases where the reference to
6306 * `MonoDelegate` would be needed (FIXME).
6308 nm
= mono_marshal_get_delegate_invoke (method
, NULL
);
6309 } else if (*name
== 'B' && (strcmp (name
, "BeginInvoke") == 0)) {
6310 nm
= mono_marshal_get_delegate_begin_invoke (method
);
6311 } else if (*name
== 'E' && (strcmp (name
, "EndInvoke") == 0)) {
6312 nm
= mono_marshal_get_delegate_end_invoke (method
);
6316 g_assert_not_reached ();
6319 mono_os_mutex_lock (&calc_section
);
6320 imethod
->stack_size
= sizeof (stackval
); /* for tracing */
6321 imethod
->alloca_size
= imethod
->stack_size
;
6322 mono_memory_barrier ();
6323 imethod
->transformed
= TRUE
;
6324 mono_os_mutex_unlock (&calc_section
);
6325 MONO_PROFILER_RAISE (jit_done
, (method
, NULL
));
6329 header
= interp_method_get_header (nm
, error
);
6330 return_if_nok (error
);
6334 header
= mono_method_get_header_checked (method
, error
);
6335 return_if_nok (error
);
6338 g_assert ((signature
->param_count
+ signature
->hasthis
) < 1000);
6339 // g_printerr ("TRANSFORM(0x%016lx): end %s::%s\n", mono_thread_current (), method->klass->name, method->name);
6341 /* Make modifications to a copy of imethod, copy them back inside the lock */
6342 real_imethod
= imethod
;
6343 memcpy (&tmp_imethod
, imethod
, sizeof (InterpMethod
));
6344 imethod
= &tmp_imethod
;
6346 interp_method_compute_offsets (imethod
, signature
, header
);
6348 MONO_TIME_TRACK (mono_interp_stats
.transform_time
, generate (method
, header
, imethod
, generic_context
, error
));
6350 mono_metadata_free_mh (header
);
6352 return_if_nok (error
);
6354 /* Copy changes back */
6355 imethod
= real_imethod
;
6356 mono_os_mutex_lock (&calc_section
);
6357 if (!imethod
->transformed
) {
6358 // Ignore the first two fields which are unchanged. next_jit_code_hash shouldn't
6359 // be modified because it is racy with internal hash table insert.
6360 const int start_offset
= 2 * sizeof (gpointer
);
6361 memcpy ((char*)imethod
+ start_offset
, (char*)&tmp_imethod
+ start_offset
, sizeof (InterpMethod
) - start_offset
);
6362 mono_memory_barrier ();
6363 imethod
->transformed
= TRUE
;
6364 mono_atomic_fetch_add_i32 (&mono_jit_stats
.methods_with_interp
, 1);
6367 mono_os_mutex_unlock (&calc_section
);
6369 mono_domain_lock (domain
);
6370 if (!g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, imethod
->method
))
6371 g_hash_table_insert (domain_jit_info (domain
)->seq_points
, imethod
->method
, imethod
->jinfo
->seq_points
);
6372 mono_domain_unlock (domain
);
6374 // FIXME: Add a different callback ?
6375 MONO_PROFILER_RAISE (jit_done
, (method
, imethod
->jinfo
));