[interp] Remove unconditional branches to next instruction (#15939)
[mono-project.git] / mono / mini / interp / transform.c
blob00927473a9c35f60af870749b2b39a6284800921
1 /**
2 * \file
3 * transform CIL into different opcodes for more
4 * efficient interpretation
6 * Written by Bernie Solomon (bernard@ugsolutions.com)
7 * Copyright (c) 2004.
8 */
10 #include "config.h"
11 #include <string.h>
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>
30 #include "mintops.h"
31 #include "interp-internals.h"
32 #include "interp.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;
41 #define DEBUG 0
43 typedef struct InterpInst InterpInst;
45 typedef struct
47 MonoClass *klass;
48 unsigned char type;
49 unsigned char flags;
50 } StackInfo;
52 struct InterpInst {
53 guint16 opcode;
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.
57 int il_offset;
58 guint32 flags;
59 guint16 data [MONO_ZERO_LEN_ARRAY];
62 typedef struct {
63 guint8 *ip;
64 GSList *preds;
65 GSList *seq_points;
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;
71 } InterpBasicBlock;
73 typedef enum {
74 RELOC_SHORT_BRANCH,
75 RELOC_LONG_BRANCH,
76 RELOC_SWITCH
77 } RelocType;
79 typedef struct {
80 RelocType type;
81 /* In the interpreter IR */
82 int offset;
83 /* In the IL code */
84 int target;
85 } Reloc;
87 typedef struct
89 MonoMethod *method;
90 MonoMethod *inlined_method;
91 MonoMethodHeader *header;
92 InterpMethod *rtm;
93 const unsigned char *il_code;
94 const unsigned char *ip;
95 const unsigned char *in_start;
96 InterpInst *last_ins, *first_ins;
97 int code_size;
98 int *in_offsets;
99 StackInfo **stack_state;
100 int *stack_height;
101 int *vt_stack_size;
102 unsigned char *is_bb_start;
103 unsigned short *new_code;
104 unsigned short *new_code_end;
105 unsigned int max_code_size;
106 StackInfo *stack;
107 StackInfo *sp;
108 unsigned int max_stack_height;
109 unsigned int stack_capacity;
110 unsigned int vt_sp;
111 unsigned int max_vt_sp;
112 unsigned int total_locals_size;
113 int n_data_items;
114 int max_data_items;
115 void **data_items;
116 GHashTable *data_hash;
117 int *clause_indexes;
118 gboolean gen_sdb_seq_points;
119 GPtrArray *seq_points;
120 InterpBasicBlock **offset_to_bb;
121 InterpBasicBlock *entry_bb;
122 MonoMemPool *mempool;
123 GList *basic_blocks;
124 GPtrArray *relocs;
125 gboolean verbose_level;
126 GArray *line_numbers;
127 } TransformData;
129 #define STACK_TYPE_I4 0
130 #define STACK_TYPE_I8 1
131 #define STACK_TYPE_R4 2
132 #define STACK_TYPE_R8 3
133 #define STACK_TYPE_O 4
134 #define STACK_TYPE_VT 5
135 #define STACK_TYPE_MP 6
136 #define STACK_TYPE_F 7
138 static const char *stack_type_string [] = { "I4", "I8", "R4", "R8", "O ", "VT", "MP", "F " };
140 #if SIZEOF_VOID_P == 8
141 #define STACK_TYPE_I STACK_TYPE_I8
142 #else
143 #define STACK_TYPE_I STACK_TYPE_I4
144 #endif
146 static int stack_type [] = {
147 STACK_TYPE_I4, /*I1*/
148 STACK_TYPE_I4, /*U1*/
149 STACK_TYPE_I4, /*I2*/
150 STACK_TYPE_I4, /*U2*/
151 STACK_TYPE_I4, /*I4*/
152 STACK_TYPE_I8, /*I8*/
153 STACK_TYPE_R4, /*R4*/
154 STACK_TYPE_R8, /*R8*/
155 STACK_TYPE_O, /*O*/
156 STACK_TYPE_MP, /*P*/
157 STACK_TYPE_VT
160 #if SIZEOF_VOID_P == 8
161 #define MINT_NEG_P MINT_NEG_I8
162 #define MINT_NOT_P MINT_NOT_I8
164 #define MINT_NEG_FP MINT_NEG_R8
166 #define MINT_ADD_P MINT_ADD_I8
167 #define MINT_SUB_P MINT_SUB_I8
168 #define MINT_MUL_P MINT_MUL_I8
169 #define MINT_DIV_P MINT_DIV_I8
170 #define MINT_DIV_UN_P MINT_DIV_UN_I8
171 #define MINT_REM_P MINT_REM_I8
172 #define MINT_REM_UN_P MINT_REM_UN_I8
173 #define MINT_AND_P MINT_AND_I8
174 #define MINT_OR_P MINT_OR_I8
175 #define MINT_XOR_P MINT_XOR_I8
176 #define MINT_SHL_P MINT_SHL_I8
177 #define MINT_SHR_P MINT_SHR_I8
178 #define MINT_SHR_UN_P MINT_SHR_UN_I8
180 #define MINT_CEQ_P MINT_CEQ_I8
181 #define MINT_CNE_P MINT_CNE_I8
182 #define MINT_CLT_P MINT_CLT_I8
183 #define MINT_CLT_UN_P MINT_CLT_UN_I8
184 #define MINT_CGT_P MINT_CGT_I8
185 #define MINT_CGT_UN_P MINT_CGT_UN_I8
186 #define MINT_CLE_P MINT_CLE_I8
187 #define MINT_CLE_UN_P MINT_CLE_UN_I8
188 #define MINT_CGE_P MINT_CGE_I8
189 #define MINT_CGE_UN_P MINT_CGE_UN_I8
191 #define MINT_ADD_FP MINT_ADD_R8
192 #define MINT_SUB_FP MINT_SUB_R8
193 #define MINT_MUL_FP MINT_MUL_R8
194 #define MINT_DIV_FP MINT_DIV_R8
195 #define MINT_REM_FP MINT_REM_R8
197 #define MINT_CNE_FP MINT_CNE_R8
198 #define MINT_CEQ_FP MINT_CEQ_R8
199 #define MINT_CGT_FP MINT_CGT_R8
200 #define MINT_CGE_FP MINT_CGE_R8
201 #define MINT_CLT_FP MINT_CLT_R8
202 #define MINT_CLE_FP MINT_CLE_R8
204 #define MINT_CONV_OVF_U4_P MINT_CONV_OVF_U4_I8
205 #else
207 #define MINT_NEG_P MINT_NEG_I4
208 #define MINT_NOT_P MINT_NOT_I4
210 #define MINT_NEG_FP MINT_NEG_R4
212 #define MINT_ADD_P MINT_ADD_I4
213 #define MINT_SUB_P MINT_SUB_I4
214 #define MINT_MUL_P MINT_MUL_I4
215 #define MINT_DIV_P MINT_DIV_I4
216 #define MINT_DIV_UN_P MINT_DIV_UN_I4
217 #define MINT_REM_P MINT_REM_I4
218 #define MINT_REM_UN_P MINT_REM_UN_I4
219 #define MINT_AND_P MINT_AND_I4
220 #define MINT_OR_P MINT_OR_I4
221 #define MINT_XOR_P MINT_XOR_I4
222 #define MINT_SHL_P MINT_SHL_I4
223 #define MINT_SHR_P MINT_SHR_I4
224 #define MINT_SHR_UN_P MINT_SHR_UN_I4
226 #define MINT_CEQ_P MINT_CEQ_I4
227 #define MINT_CNE_P MINT_CNE_I4
228 #define MINT_CLT_P MINT_CLT_I4
229 #define MINT_CLT_UN_P MINT_CLT_UN_I4
230 #define MINT_CGT_P MINT_CGT_I4
231 #define MINT_CGT_UN_P MINT_CGT_UN_I4
232 #define MINT_CLE_P MINT_CLE_I4
233 #define MINT_CLE_UN_P MINT_CLE_UN_I4
234 #define MINT_CGE_P MINT_CGE_I4
235 #define MINT_CGE_UN_P MINT_CGE_UN_I4
237 #define MINT_ADD_FP MINT_ADD_R4
238 #define MINT_SUB_FP MINT_SUB_R4
239 #define MINT_MUL_FP MINT_MUL_R4
240 #define MINT_DIV_FP MINT_DIV_R4
241 #define MINT_REM_FP MINT_REM_R4
243 #define MINT_CNE_FP MINT_CNE_R4
244 #define MINT_CEQ_FP MINT_CEQ_R4
245 #define MINT_CGT_FP MINT_CGT_R4
246 #define MINT_CGE_FP MINT_CGE_R4
247 #define MINT_CLT_FP MINT_CLT_R4
248 #define MINT_CLE_FP MINT_CLE_R4
250 #define MINT_CONV_OVF_U4_P MINT_CONV_OVF_U4_I4
251 #endif
253 typedef struct {
254 const gchar *op_name;
255 guint16 insn [3];
256 } MagicIntrinsic;
258 // static const MagicIntrinsic int_binop[] = {
260 static const MagicIntrinsic int_unnop[] = {
261 { "op_UnaryPlus", {MINT_NOP, MINT_NOP, MINT_NOP}},
262 { "op_UnaryNegation", {MINT_NEG_P, MINT_NEG_P, MINT_NEG_FP}},
263 { "op_OnesComplement", {MINT_NOT_P, MINT_NOT_P, MINT_NIY}}
266 static const MagicIntrinsic int_binop[] = {
267 { "op_Addition", {MINT_ADD_P, MINT_ADD_P, MINT_ADD_FP}},
268 { "op_Subtraction", {MINT_SUB_P, MINT_SUB_P, MINT_SUB_FP}},
269 { "op_Multiply", {MINT_MUL_P, MINT_MUL_P, MINT_MUL_FP}},
270 { "op_Division", {MINT_DIV_P, MINT_DIV_UN_P, MINT_DIV_FP}},
271 { "op_Modulus", {MINT_REM_P, MINT_REM_UN_P, MINT_REM_FP}},
272 { "op_BitwiseAnd", {MINT_AND_P, MINT_AND_P, MINT_NIY}},
273 { "op_BitwiseOr", {MINT_OR_P, MINT_OR_P, MINT_NIY}},
274 { "op_ExclusiveOr", {MINT_XOR_P, MINT_XOR_P, MINT_NIY}},
275 { "op_LeftShift", {MINT_SHL_P, MINT_SHL_P, MINT_NIY}},
276 { "op_RightShift", {MINT_SHR_P, MINT_SHR_UN_P, MINT_NIY}},
279 static const MagicIntrinsic int_cmpop[] = {
280 { "op_Inequality", {MINT_CNE_P, MINT_CNE_P, MINT_CNE_FP}},
281 { "op_Equality", {MINT_CEQ_P, MINT_CEQ_P, MINT_CEQ_FP}},
282 { "op_GreaterThan", {MINT_CGT_P, MINT_CGT_UN_P, MINT_CGT_FP}},
283 { "op_GreaterThanOrEqual", {MINT_CGE_P, MINT_CGE_UN_P, MINT_CGE_FP}},
284 { "op_LessThan", {MINT_CLT_P, MINT_CLT_UN_P, MINT_CLT_FP}},
285 { "op_LessThanOrEqual", {MINT_CLE_P, MINT_CLE_UN_P, MINT_CLE_FP}}
288 static gboolean generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, MonoGenericContext *generic_context, MonoError *error);
290 static InterpInst*
291 interp_new_ins (TransformData *td, guint16 opcode, int len)
293 InterpInst *new_inst;
294 g_assert (len);
295 // Size of data region of instruction is length of instruction minus 1 (the opcode slot)
296 new_inst = mono_mempool_alloc0 (td->mempool, sizeof (InterpInst) + sizeof (guint16) * (len - 1));
297 new_inst->opcode = opcode;
298 // opcodes from inlined methods don't have il offset associated with them since the offset
299 // stored here is relevant only for the original method
300 if (!td->inlined_method)
301 new_inst->il_offset = td->in_start - td->il_code;
302 else
303 new_inst->il_offset = -1;
304 return new_inst;
307 // This version need to be used with switch opcode, which doesn't have constant length
308 static InterpInst*
309 interp_add_ins_explicit (TransformData *td, guint16 opcode, int len)
311 InterpInst *new_inst = interp_new_ins (td, opcode, len);
312 new_inst->prev = td->last_ins;
313 if (td->last_ins)
314 td->last_ins->next = new_inst;
315 else
316 td->first_ins = new_inst;
317 td->last_ins = new_inst;
318 return new_inst;
321 static InterpInst*
322 interp_add_ins (TransformData *td, guint16 opcode)
324 return interp_add_ins_explicit (td, opcode, mono_interp_oplen [opcode]);
327 // Inserts a new instruction inside the instruction stream
328 static InterpInst*
329 interp_insert_ins (TransformData *td, InterpInst *prev_ins, guint16 opcode)
331 InterpInst *new_inst = interp_new_ins (td, opcode, mono_interp_oplen [opcode]);
332 g_assert (prev_ins && prev_ins->next);
334 new_inst->prev = prev_ins;
335 new_inst->next = prev_ins->next;
336 prev_ins->next = new_inst;
337 new_inst->next->prev = new_inst;
339 return new_inst;
342 static void
343 interp_remove_ins (TransformData *td, InterpInst *ins)
345 if (ins->prev) {
346 ins->prev->next = ins->next;
347 } else {
348 td->first_ins = ins->next;
350 if (ins->next) {
351 ins->next->prev = ins->prev;
352 } else {
353 td->last_ins = ins->prev;
357 #define CHECK_STACK(td, n) \
358 do { \
359 int stack_size = (td)->sp - (td)->stack; \
360 if (stack_size < (n)) \
361 g_warning ("%s.%s: not enough values (%d < %d) on stack at %04x", \
362 m_class_get_name ((td)->method->klass), (td)->method->name, \
363 stack_size, n, (td)->ip - (td)->il_code); \
364 } while (0)
366 #define ENSURE_I4(td, sp_off) \
367 do { \
368 if ((td)->sp [-sp_off].type == STACK_TYPE_I8) \
369 interp_add_ins (td, sp_off == 1 ? MINT_CONV_I4_I8 : MINT_CONV_I4_I8_SP); \
370 } while (0)
372 #define CHECK_TYPELOAD(klass) \
373 do { \
374 if (!(klass) || mono_class_has_failure (klass)) { \
375 mono_error_set_for_class_failure (error, klass); \
376 goto exit; \
378 } while (0)
380 #if NO_UNALIGNED_ACCESS
381 #define WRITE32(ip, v) \
382 do { \
383 * (ip) = * (guint16 *)(v); \
384 * ((ip) + 1) = * ((guint16 *)(v) + 1); \
385 (ip) += 2; \
386 } while (0)
388 #define WRITE32_INS(ins, index, v) \
389 do { \
390 (ins)->data [index] = * (guint16 *)(v); \
391 (ins)->data [index + 1] = * ((guint16 *)(v) + 1); \
392 } while (0)
394 #define WRITE64_INS(ins, index, v) \
395 do { \
396 (ins)->data [index] = * (guint16 *)(v); \
397 (ins)->data [index + 1] = * ((guint16 *)(v) + 1); \
398 (ins)->data [index + 2] = * ((guint16 *)(v) + 2); \
399 (ins)->data [index + 3] = * ((guint16 *)(v) + 3); \
400 } while (0)
401 #else
402 #define WRITE32(ip, v) \
403 do { \
404 * (guint32*)(ip) = * (guint32 *)(v); \
405 (ip) += 2; \
406 } while (0)
407 #define WRITE32_INS(ins, index, v) \
408 do { \
409 * (guint32 *)(&(ins)->data [index]) = * (guint32 *)(v); \
410 } while (0)
412 #define WRITE64_INS(ins, index, v) \
413 do { \
414 * (guint64 *)(&(ins)->data [index]) = * (guint64 *)(v); \
415 } while (0)
417 #endif
420 static void
421 handle_branch (TransformData *td, int short_op, int long_op, int offset)
423 int shorten_branch = 0;
424 int target = td->ip + offset - td->il_code;
425 if (target < 0 || target >= td->code_size)
426 g_assert_not_reached ();
427 /* Add exception checkpoint or safepoint for backward branches */
428 if (offset < 0) {
429 if (mono_threads_are_safepoints_enabled ())
430 interp_add_ins (td, MINT_SAFEPOINT);
431 else
432 interp_add_ins (td, MINT_CHECKPOINT);
434 if (offset > 0 && td->stack_height [target] < 0) {
435 td->stack_height [target] = td->sp - td->stack;
436 if (td->stack_height [target] > 0)
437 td->stack_state [target] = (StackInfo*)g_memdup (td->stack, td->stack_height [target] * sizeof (td->stack [0]));
438 td->vt_stack_size [target] = td->vt_sp;
441 if (td->header->code_size <= 25000) /* FIX to be precise somehow? */
442 shorten_branch = 1;
444 if (shorten_branch) {
445 interp_add_ins (td, short_op);
446 td->last_ins->data [0] = (guint16) target;
447 } else {
448 interp_add_ins (td, long_op);
449 WRITE32_INS (td->last_ins, 0, &target);
453 static void
454 one_arg_branch(TransformData *td, int mint_op, int offset)
456 int type = td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP ? STACK_TYPE_I : td->sp [-1].type;
457 int long_op = mint_op + type - STACK_TYPE_I4;
458 int short_op = long_op + MINT_BRFALSE_I4_S - MINT_BRFALSE_I4;
459 CHECK_STACK(td, 1);
460 --td->sp;
461 handle_branch (td, short_op, long_op, offset);
464 static void
465 two_arg_branch(TransformData *td, int mint_op, int offset)
467 int type1 = td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP ? STACK_TYPE_I : td->sp [-1].type;
468 int type2 = td->sp [-2].type == STACK_TYPE_O || td->sp [-2].type == STACK_TYPE_MP ? STACK_TYPE_I : td->sp [-2].type;
469 int long_op = mint_op + type1 - STACK_TYPE_I4;
470 int short_op = long_op + MINT_BEQ_I4_S - MINT_BEQ_I4;
471 CHECK_STACK(td, 2);
472 if (type1 == STACK_TYPE_I4 && type2 == STACK_TYPE_I8) {
473 interp_add_ins (td, MINT_CONV_I8_I4);
474 // The il instruction starts with the actual branch, and not with the conversion opcodes
475 td->last_ins->il_offset = -1;
476 } else if (type1 == STACK_TYPE_I8 && type2 == STACK_TYPE_I4) {
477 interp_add_ins (td, MINT_CONV_I8_I4_SP);
478 td->last_ins->il_offset = -1;
479 } else if (type1 == STACK_TYPE_R4 && type2 == STACK_TYPE_R8) {
480 interp_add_ins (td, MINT_CONV_R8_R4);
481 td->last_ins->il_offset = -1;
482 } else if (type1 == STACK_TYPE_R8 && type2 == STACK_TYPE_R4) {
483 interp_add_ins (td, MINT_CONV_R8_R4_SP);
484 td->last_ins->il_offset = -1;
485 } else if (type1 != type2) {
486 g_warning("%s.%s: branch type mismatch %d %d",
487 m_class_get_name (td->method->klass), td->method->name,
488 td->sp [-1].type, td->sp [-2].type);
490 td->sp -= 2;
491 handle_branch (td, short_op, long_op, offset);
494 static void
495 unary_arith_op(TransformData *td, int mint_op)
497 int op = mint_op + td->sp [-1].type - STACK_TYPE_I4;
498 CHECK_STACK(td, 1);
499 interp_add_ins (td, op);
502 static void
503 binary_arith_op(TransformData *td, int mint_op)
505 int type1 = td->sp [-2].type;
506 int type2 = td->sp [-1].type;
507 int op;
508 #if SIZEOF_VOID_P == 8
509 if ((type1 == STACK_TYPE_MP || type1 == STACK_TYPE_I8) && type2 == STACK_TYPE_I4) {
510 interp_add_ins (td, MINT_CONV_I8_I4);
511 type2 = STACK_TYPE_I8;
513 if (type1 == STACK_TYPE_I4 && (type2 == STACK_TYPE_MP || type2 == STACK_TYPE_I8)) {
514 interp_add_ins (td, MINT_CONV_I8_I4_SP);
515 type1 = STACK_TYPE_I8;
516 td->sp [-2].type = STACK_TYPE_I8;
518 #endif
519 if (type1 == STACK_TYPE_R8 && type2 == STACK_TYPE_R4) {
520 interp_add_ins (td, MINT_CONV_R8_R4);
521 type2 = STACK_TYPE_R8;
523 if (type1 == STACK_TYPE_R4 && type2 == STACK_TYPE_R8) {
524 interp_add_ins (td, MINT_CONV_R8_R4_SP);
525 type1 = STACK_TYPE_R8;
526 td->sp [-2].type = STACK_TYPE_R8;
528 if (type1 == STACK_TYPE_MP)
529 type1 = STACK_TYPE_I;
530 if (type2 == STACK_TYPE_MP)
531 type2 = STACK_TYPE_I;
532 if (type1 != type2) {
533 g_warning("%s.%s: %04x arith type mismatch %s %d %d",
534 m_class_get_name (td->method->klass), td->method->name,
535 td->ip - td->il_code, mono_interp_opname[mint_op], type1, type2);
537 op = mint_op + type1 - STACK_TYPE_I4;
538 CHECK_STACK(td, 2);
539 interp_add_ins (td, op);
540 --td->sp;
543 static void
544 shift_op(TransformData *td, int mint_op)
546 int op = mint_op + td->sp [-2].type - STACK_TYPE_I4;
547 CHECK_STACK(td, 2);
548 if (td->sp [-1].type != STACK_TYPE_I4) {
549 g_warning("%s.%s: shift type mismatch %d",
550 m_class_get_name (td->method->klass), td->method->name,
551 td->sp [-2].type);
553 interp_add_ins (td, op);
554 --td->sp;
557 static int
558 can_store (int st_value, int vt_value)
560 if (st_value == STACK_TYPE_O || st_value == STACK_TYPE_MP)
561 st_value = STACK_TYPE_I;
562 if (vt_value == STACK_TYPE_O || vt_value == STACK_TYPE_MP)
563 vt_value = STACK_TYPE_I;
564 return st_value == vt_value;
567 #define SET_SIMPLE_TYPE(s, ty) \
568 do { \
569 (s)->type = (ty); \
570 (s)->flags = 0; \
571 (s)->klass = NULL; \
572 } while (0)
574 #define SET_TYPE(s, ty, k) \
575 do { \
576 (s)->type = (ty); \
577 (s)->flags = 0; \
578 (s)->klass = k; \
579 } while (0)
581 #define REALLOC_STACK(td, sppos) \
582 do { \
583 (td)->stack_capacity *= 2; \
584 (td)->stack = (StackInfo*)realloc ((td)->stack, (td)->stack_capacity * sizeof (td->stack [0])); \
585 (td)->sp = (td)->stack + (sppos); \
586 } while (0);
588 #define PUSH_SIMPLE_TYPE(td, ty) \
589 do { \
590 int sp_height; \
591 (td)->sp++; \
592 sp_height = (td)->sp - (td)->stack; \
593 if (sp_height > (td)->max_stack_height) \
594 (td)->max_stack_height = sp_height; \
595 if (sp_height > (td)->stack_capacity) \
596 REALLOC_STACK(td, sp_height); \
597 SET_SIMPLE_TYPE((td)->sp - 1, ty); \
598 } while (0)
600 #define PUSH_TYPE(td, ty, k) \
601 do { \
602 int sp_height; \
603 (td)->sp++; \
604 sp_height = (td)->sp - (td)->stack; \
605 if (sp_height > (td)->max_stack_height) \
606 (td)->max_stack_height = sp_height; \
607 if (sp_height > (td)->stack_capacity) \
608 REALLOC_STACK(td, sp_height); \
609 SET_TYPE((td)->sp - 1, ty, k); \
610 } while (0)
612 static void
613 move_stack (TransformData *td, int start, int amount)
615 int sp_height = td->sp - td->stack;
616 int to_move = sp_height - start;
618 td->sp += amount;
619 sp_height += amount;
620 if (amount > 0) {
621 if (sp_height > td->max_stack_height)
622 td->max_stack_height = sp_height;
623 if (sp_height > td->stack_capacity)
624 REALLOC_STACK (td, sp_height);
625 } else {
626 g_assert (td->sp >= td->stack);
629 if (to_move > 0)
630 memmove (td->stack + start + amount, td->stack + start, to_move * sizeof (StackInfo));
633 #define PUSH_VT(td, size) \
634 do { \
635 (td)->vt_sp += ALIGN_TO ((size), MINT_VT_ALIGNMENT); \
636 if ((td)->vt_sp > (td)->max_vt_sp) \
637 (td)->max_vt_sp = (td)->vt_sp; \
638 } while (0)
640 #define POP_VT(td, size) \
641 do { \
642 (td)->vt_sp -= ALIGN_TO ((size), MINT_VT_ALIGNMENT); \
643 } while (0)
645 static MonoType*
646 get_arg_type_exact (TransformData *td, int n, int *mt)
648 MonoType *type;
649 gboolean hasthis = mono_method_signature_internal (td->method)->hasthis;
651 if (hasthis && n == 0)
652 type = m_class_get_byval_arg (td->method->klass);
653 else
654 type = mono_method_signature_internal (td->method)->params [n - !!hasthis];
656 if (mt)
657 *mt = mint_type (type);
659 return type;
662 static void
663 load_arg(TransformData *td, int n)
665 int mt;
666 MonoClass *klass = NULL;
667 MonoType *type;
668 gboolean hasthis = mono_method_signature_internal (td->method)->hasthis;
670 type = get_arg_type_exact (td, n, &mt);
672 if (mt == MINT_TYPE_VT) {
673 gint32 size;
674 klass = mono_class_from_mono_type_internal (type);
675 if (mono_method_signature_internal (td->method)->pinvoke)
676 size = mono_class_native_size (klass, NULL);
677 else
678 size = mono_class_value_size (klass, NULL);
680 if (hasthis && n == 0) {
681 mt = MINT_TYPE_P;
682 interp_add_ins (td, MINT_LDARG_P);
683 td->last_ins->data [0] = 0;
684 klass = NULL;
685 } else {
686 PUSH_VT (td, size);
687 interp_add_ins (td, MINT_LDARG_VT);
688 td->last_ins->data [0] = n;
689 WRITE32_INS (td->last_ins, 1, &size);
691 } else {
692 if (hasthis && n == 0) {
693 mt = MINT_TYPE_P;
694 interp_add_ins (td, MINT_LDARG_P);
695 td->last_ins->data [0] = n;
696 klass = NULL;
697 } else {
698 interp_add_ins (td, MINT_LDARG_I1 + (mt - MINT_TYPE_I1));
699 td->last_ins->data [0] = n;
700 if (mt == MINT_TYPE_O)
701 klass = mono_class_from_mono_type_internal (type);
704 PUSH_TYPE(td, stack_type[mt], klass);
707 static void
708 store_arg(TransformData *td, int n)
710 int mt;
711 CHECK_STACK (td, 1);
712 MonoType *type;
714 type = get_arg_type_exact (td, n, &mt);
716 if (mt == MINT_TYPE_VT) {
717 gint32 size;
718 MonoClass *klass = mono_class_from_mono_type_internal (type);
719 if (mono_method_signature_internal (td->method)->pinvoke)
720 size = mono_class_native_size (klass, NULL);
721 else
722 size = mono_class_value_size (klass, NULL);
723 interp_add_ins (td, MINT_STARG_VT);
724 td->last_ins->data [0] = n;
725 WRITE32_INS (td->last_ins, 1, &size);
726 if (td->sp [-1].type == STACK_TYPE_VT)
727 POP_VT(td, size);
728 } else {
729 interp_add_ins (td, MINT_STARG_I1 + (mt - MINT_TYPE_I1));
730 td->last_ins->data [0] = n;
732 --td->sp;
735 static void
736 load_local_general (TransformData *td, int offset, MonoType *type)
738 int mt = mint_type (type);
739 MonoClass *klass = NULL;
740 if (mt == MINT_TYPE_VT) {
741 klass = mono_class_from_mono_type_internal (type);
742 gint32 size = mono_class_value_size (klass, NULL);
743 PUSH_VT(td, size);
744 interp_add_ins (td, MINT_LDLOC_VT);
745 td->last_ins->data [0] = offset;
746 WRITE32_INS (td->last_ins, 1, &size);
747 } else {
748 g_assert (mt < MINT_TYPE_VT);
749 if (!td->gen_sdb_seq_points &&
750 mt == MINT_TYPE_I4 && !td->is_bb_start [td->in_start - td->il_code] && td->last_ins != NULL &&
751 td->last_ins->opcode == MINT_STLOC_I4 && td->last_ins->data [0] == offset) {
752 td->last_ins->opcode = MINT_STLOC_NP_I4;
753 } else if (!td->gen_sdb_seq_points &&
754 mt == MINT_TYPE_O && !td->is_bb_start [td->in_start - td->il_code] && td->last_ins != NULL &&
755 td->last_ins->opcode == MINT_STLOC_O && td->last_ins->data [0] == offset) {
756 td->last_ins->opcode = MINT_STLOC_NP_O;
757 } else {
758 interp_add_ins (td, MINT_LDLOC_I1 + (mt - MINT_TYPE_I1));
759 td->last_ins->data [0] = offset; /*FIX for large offset */
761 if (mt == MINT_TYPE_O)
762 klass = mono_class_from_mono_type_internal (type);
764 PUSH_TYPE(td, stack_type[mt], klass);
767 static void
768 load_local (TransformData *td, int n)
770 MonoType *type = td->header->locals [n];
771 int offset = td->rtm->local_offsets [n];
772 load_local_general (td, offset, type);
775 static void
776 store_local_general (TransformData *td, int offset, MonoType *type)
778 int mt = mint_type (type);
779 CHECK_STACK (td, 1);
780 #if SIZEOF_VOID_P == 8
781 if (td->sp [-1].type == STACK_TYPE_I4 && stack_type [mt] == STACK_TYPE_I8) {
782 interp_add_ins (td, MINT_CONV_I8_I4);
783 td->sp [-1].type = STACK_TYPE_I8;
785 #endif
786 if (!can_store(td->sp [-1].type, stack_type [mt])) {
787 g_warning("%s.%s: Store local stack type mismatch %d %d",
788 m_class_get_name (td->method->klass), td->method->name,
789 stack_type [mt], td->sp [-1].type);
791 if (mt == MINT_TYPE_VT) {
792 MonoClass *klass = mono_class_from_mono_type_internal (type);
793 gint32 size = mono_class_value_size (klass, NULL);
794 interp_add_ins (td, MINT_STLOC_VT);
795 td->last_ins->data [0] = offset; /*FIX for large offset */
796 WRITE32_INS (td->last_ins, 1, &size);
797 if (td->sp [-1].type == STACK_TYPE_VT)
798 POP_VT(td, size);
799 } else {
800 g_assert (mt < MINT_TYPE_VT);
801 interp_add_ins (td, MINT_STLOC_I1 + (mt - MINT_TYPE_I1));
802 td->last_ins->data [0] = offset; /*FIX for large offset */
804 --td->sp;
807 static void
808 store_local (TransformData *td, int n)
810 MonoType *type = td->header->locals [n];
811 int offset = td->rtm->local_offsets [n];
812 store_local_general (td, offset, type);
815 #define SIMPLE_OP(td, op) \
816 do { \
817 interp_add_ins (td, op); \
818 ++td->ip; \
819 } while (0)
821 static guint16
822 get_data_item_index (TransformData *td, void *ptr)
824 gpointer p = g_hash_table_lookup (td->data_hash, ptr);
825 guint index;
826 if (p != NULL)
827 return GPOINTER_TO_UINT (p) - 1;
828 if (td->max_data_items == td->n_data_items) {
829 td->max_data_items = td->n_data_items == 0 ? 16 : 2 * td->max_data_items;
830 td->data_items = (gpointer*)g_realloc (td->data_items, td->max_data_items * sizeof(td->data_items [0]));
832 index = td->n_data_items;
833 td->data_items [index] = ptr;
834 ++td->n_data_items;
835 g_hash_table_insert (td->data_hash, ptr, GUINT_TO_POINTER (index + 1));
836 return index;
839 static gboolean
840 jit_call_supported (MonoMethod *method, MonoMethodSignature *sig)
842 GSList *l;
844 if (sig->param_count > 6)
845 return FALSE;
846 if (sig->pinvoke)
847 return FALSE;
848 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
849 return FALSE;
850 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
851 return FALSE;
852 if (method->is_inflated)
853 return FALSE;
854 if (method->string_ctor)
855 return FALSE;
857 if (mono_aot_only && m_class_get_image (method->klass)->aot_module && !(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)) {
858 ERROR_DECL (error);
859 gpointer addr = mono_jit_compile_method_jit_only (method, error);
860 if (addr && mono_error_ok (error))
861 return TRUE;
864 for (l = mono_interp_jit_classes; l; l = l->next) {
865 const char *class_name = (const char*)l->data;
866 // FIXME: Namespaces
867 if (!strcmp (m_class_get_name (method->klass), class_name))
868 return TRUE;
871 //return TRUE;
872 return FALSE;
875 static int mono_class_get_magic_index (MonoClass *k)
877 if (mono_class_is_magic_int (k))
878 return !strcmp ("nint", m_class_get_name (k)) ? 0 : 1;
880 if (mono_class_is_magic_float (k))
881 return 2;
883 return -1;
886 static void
887 interp_generate_mae_throw (TransformData *td, MonoMethod *method, MonoMethod *target_method)
889 MonoJitICallInfo *info = &mono_get_jit_icall_info ()->mono_throw_method_access;
891 /* Inject code throwing MethodAccessException */
892 interp_add_ins (td, MINT_MONO_LDPTR);
893 td->last_ins->data [0] = get_data_item_index (td, method);
894 PUSH_SIMPLE_TYPE (td, STACK_TYPE_I);
896 interp_add_ins (td, MINT_MONO_LDPTR);
897 td->last_ins->data [0] = get_data_item_index (td, target_method);
898 PUSH_SIMPLE_TYPE (td, STACK_TYPE_I);
900 interp_add_ins (td, MINT_ICALL_PP_V);
901 td->last_ins->data [0] = get_data_item_index (td, (gpointer)info->func);
903 td->sp -= 2;
906 static void
907 interp_generate_bie_throw (TransformData *td)
909 MonoJitICallInfo *info = &mono_get_jit_icall_info ()->mono_throw_bad_image;
911 interp_add_ins (td, MINT_ICALL_PP_V);
912 td->last_ins->data [0] = get_data_item_index (td, (gpointer)info->func);
916 * These are additional locals that can be allocated as we transform the code.
917 * They are allocated past the method locals so they are accessed in the same
918 * way, with an offset relative to the frame->locals.
920 static int
921 create_interp_local (TransformData *td, MonoType *type)
923 int align, size;
924 int offset = td->total_locals_size;
926 size = mono_type_size (type, &align);
927 offset = ALIGN_TO (offset, align);
929 td->total_locals_size = offset + size;
931 return offset;
934 static void
935 dump_mint_code (const guint16 *start, const guint16* end)
937 const guint16 *p = start;
938 while (p < end) {
939 char *ins = mono_interp_dis_mintop (start, p);
940 g_print ("%s\n", ins);
941 g_free (ins);
942 p = mono_interp_dis_mintop_len (p);
946 /* For debug use */
947 void
948 mono_interp_print_code (InterpMethod *imethod)
950 MonoJitInfo *jinfo = imethod->jinfo;
951 const guint16 *start;
953 if (!jinfo)
954 return;
956 char *name = mono_method_full_name (imethod->method, 1);
957 g_print ("Method : %s\n", name);
958 g_free (name);
960 start = (guint16*) jinfo->code_start;
961 dump_mint_code (start, start + jinfo->code_size);
965 static MonoMethodHeader*
966 interp_method_get_header (MonoMethod* method, MonoError *error)
968 /* An explanation: mono_method_get_header_internal returns an error if
969 * called on a method with no body (e.g. an abstract method, or an
970 * icall). We don't want that.
972 if (mono_method_has_no_body (method))
973 return NULL;
974 else
975 return mono_method_get_header_internal (method, error);
978 /* stores top of stack as local and pushes address of it on stack */
979 static void
980 emit_store_value_as_local (TransformData *td, MonoType *src)
982 int size = mini_magic_type_size (NULL, src);
983 int local_offset = create_interp_local (td, mini_native_type_replace_type (src));
985 store_local_general (td, local_offset, src);
987 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
988 interp_add_ins (td, MINT_LDLOC_VT);
989 td->last_ins->data [0] = local_offset;
990 WRITE32_INS (td->last_ins, 1, &size);
992 PUSH_VT (td, size);
993 PUSH_TYPE (td, STACK_TYPE_VT, NULL);
996 // Returns whether we can optimize away the instructions starting at start.
997 // If any instructions are part of a new basic block, we can't remove them.
998 static gboolean
999 interp_is_bb_start (TransformData *td, InterpInst *start, InterpInst *end)
1001 InterpInst *ins = start;
1002 while (ins != end) {
1003 if (ins->il_offset != -1) {
1004 if (td->is_bb_start [ins->il_offset])
1005 return TRUE;
1007 ins = ins->next;
1009 return FALSE;
1012 static gboolean
1013 interp_ins_is_ldc (InterpInst *ins)
1015 return ins->opcode >= MINT_LDC_I4_M1 && ins->opcode <= MINT_LDC_I8;
1018 static gint32
1019 interp_ldc_i4_get_const (InterpInst *ins)
1021 switch (ins->opcode) {
1022 case MINT_LDC_I4_M1: return -1;
1023 case MINT_LDC_I4_0: return 0;
1024 case MINT_LDC_I4_1: return 1;
1025 case MINT_LDC_I4_2: return 2;
1026 case MINT_LDC_I4_3: return 3;
1027 case MINT_LDC_I4_4: return 4;
1028 case MINT_LDC_I4_5: return 5;
1029 case MINT_LDC_I4_6: return 6;
1030 case MINT_LDC_I4_7: return 7;
1031 case MINT_LDC_I4_8: return 8;
1032 case MINT_LDC_I4_S: return (gint32)(gint8)ins->data [0];
1033 case MINT_LDC_I4: return READ32 (&ins->data [0]);
1034 default:
1035 g_assert_not_reached ();
1039 static int
1040 interp_get_ldind_for_mt (int mt)
1042 switch (mt) {
1043 case MINT_TYPE_I1: return MINT_LDIND_I1_CHECK;
1044 case MINT_TYPE_U1: return MINT_LDIND_U1_CHECK;
1045 case MINT_TYPE_I2: return MINT_LDIND_I2_CHECK;
1046 case MINT_TYPE_U2: return MINT_LDIND_U2_CHECK;
1047 case MINT_TYPE_I4: return MINT_LDIND_I4_CHECK;
1048 case MINT_TYPE_I8: return MINT_LDIND_I8_CHECK;
1049 case MINT_TYPE_R4: return MINT_LDIND_R4_CHECK;
1050 case MINT_TYPE_R8: return MINT_LDIND_R8_CHECK;
1051 case MINT_TYPE_O: return MINT_LDIND_REF;
1052 default:
1053 g_assert_not_reached ();
1055 return -1;
1058 /* Return TRUE if call transformation is finished */
1059 static gboolean
1060 interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClass *constrained_class, MonoMethodSignature *csignature, gboolean readonly, int *op)
1062 const char *tm = target_method->name;
1063 int i;
1064 int type_index = mono_class_get_magic_index (target_method->klass);
1065 gboolean in_corlib = m_class_get_image (target_method->klass) == mono_defaults.corlib;
1066 const char *klass_name_space = m_class_get_name_space (target_method->klass);
1067 const char *klass_name = m_class_get_name (target_method->klass);
1069 if (target_method->klass == mono_defaults.string_class) {
1070 if (tm [0] == 'g') {
1071 if (strcmp (tm, "get_Chars") == 0)
1072 *op = MINT_GETCHR;
1073 else if (strcmp (tm, "get_Length") == 0)
1074 *op = MINT_STRLEN;
1076 } else if (type_index >= 0) {
1077 MonoClass *magic_class = target_method->klass;
1079 const int mt = mint_type (m_class_get_byval_arg (magic_class));
1080 if (!strcmp (".ctor", tm)) {
1081 MonoType *arg = csignature->params [0];
1082 /* depending on SIZEOF_VOID_P and the type of the value passed to the .ctor we either have to CONV it, or do nothing */
1083 int arg_size = mini_magic_type_size (NULL, arg);
1085 if (arg_size > SIZEOF_VOID_P) { // 8 -> 4
1086 switch (type_index) {
1087 case 0: case 1:
1088 interp_add_ins (td, MINT_CONV_I4_I8);
1089 break;
1090 case 2:
1091 interp_add_ins (td, MINT_CONV_R4_R8);
1092 break;
1096 if (arg_size < SIZEOF_VOID_P) { // 4 -> 8
1097 switch (type_index) {
1098 case 0:
1099 interp_add_ins (td, MINT_CONV_I8_I4);
1100 break;
1101 case 1:
1102 interp_add_ins (td, MINT_CONV_I8_U4);
1103 break;
1104 case 2:
1105 interp_add_ins (td, MINT_CONV_R8_R4);
1106 break;
1110 switch (type_index) {
1111 case 0: case 1:
1112 #if SIZEOF_VOID_P == 4
1113 interp_add_ins (td, MINT_STIND_I4);
1114 #else
1115 interp_add_ins (td, MINT_STIND_I8);
1116 #endif
1117 break;
1118 case 2:
1119 #if SIZEOF_VOID_P == 4
1120 interp_add_ins (td, MINT_STIND_R4);
1121 #else
1122 interp_add_ins (td, MINT_STIND_R8);
1123 #endif
1124 break;
1127 td->sp -= 2;
1128 td->ip += 5;
1129 return TRUE;
1130 } else if (!strcmp ("op_Implicit", tm ) || !strcmp ("op_Explicit", tm)) {
1131 MonoType *src = csignature->params [0];
1132 MonoType *dst = csignature->ret;
1133 MonoClass *src_klass = mono_class_from_mono_type_internal (src);
1134 int src_size = mini_magic_type_size (NULL, src);
1135 int dst_size = mini_magic_type_size (NULL, dst);
1137 gboolean store_value_as_local = FALSE;
1139 switch (type_index) {
1140 case 0: case 1:
1141 if (!mini_magic_is_int_type (src) || !mini_magic_is_int_type (dst)) {
1142 if (mini_magic_is_int_type (src))
1143 store_value_as_local = TRUE;
1144 else if (mono_class_is_magic_float (src_klass))
1145 store_value_as_local = TRUE;
1146 else
1147 return FALSE;
1149 break;
1150 case 2:
1151 if (!mini_magic_is_float_type (src) || !mini_magic_is_float_type (dst)) {
1152 if (mini_magic_is_float_type (src))
1153 store_value_as_local = TRUE;
1154 else if (mono_class_is_magic_int (src_klass))
1155 store_value_as_local = TRUE;
1156 else
1157 return FALSE;
1159 break;
1162 if (store_value_as_local) {
1163 emit_store_value_as_local (td, src);
1165 /* emit call to managed conversion method */
1166 return FALSE;
1169 if (src_size > dst_size) { // 8 -> 4
1170 switch (type_index) {
1171 case 0: case 1:
1172 interp_add_ins (td, MINT_CONV_I4_I8);
1173 break;
1174 case 2:
1175 interp_add_ins (td, MINT_CONV_R4_R8);
1176 break;
1180 if (src_size < dst_size) { // 4 -> 8
1181 switch (type_index) {
1182 case 0:
1183 interp_add_ins (td, MINT_CONV_I8_I4);
1184 break;
1185 case 1:
1186 interp_add_ins (td, MINT_CONV_I8_U4);
1187 break;
1188 case 2:
1189 interp_add_ins (td, MINT_CONV_R8_R4);
1190 break;
1194 SET_TYPE (td->sp - 1, stack_type [mint_type (dst)], mono_class_from_mono_type_internal (dst));
1195 td->ip += 5;
1196 return TRUE;
1197 } else if (!strcmp ("op_Increment", tm)) {
1198 g_assert (type_index != 2); // no nfloat
1199 #if SIZEOF_VOID_P == 8
1200 interp_add_ins (td, MINT_ADD1_I8);
1201 #else
1202 interp_add_ins (td, MINT_ADD1_I4);
1203 #endif
1204 SET_TYPE (td->sp - 1, stack_type [mt], magic_class);
1205 td->ip += 5;
1206 return TRUE;
1207 } else if (!strcmp ("op_Decrement", tm)) {
1208 g_assert (type_index != 2); // no nfloat
1209 #if SIZEOF_VOID_P == 8
1210 interp_add_ins (td, MINT_SUB1_I8);
1211 #else
1212 interp_add_ins (td, MINT_SUB1_I4);
1213 #endif
1214 SET_TYPE (td->sp - 1, stack_type [mt], magic_class);
1215 td->ip += 5;
1216 return TRUE;
1217 } else if (!strcmp ("CompareTo", tm) || !strcmp ("Equals", tm)) {
1218 MonoType *arg = csignature->params [0];
1220 /* on 'System.n*::{CompareTo,Equals} (System.n*)' variant we need to push managed
1221 * pointer instead of value */
1222 if (arg->type == MONO_TYPE_VALUETYPE)
1223 emit_store_value_as_local (td, arg);
1225 /* emit call to managed conversion method */
1226 return FALSE;
1227 } else if (!strcmp (".cctor", tm)) {
1228 /* white list */
1229 return FALSE;
1230 } else if (!strcmp ("Parse", tm)) {
1231 /* white list */
1232 return FALSE;
1233 } else if (!strcmp ("ToString", tm)) {
1234 /* white list */
1235 return FALSE;
1236 } else if (!strcmp ("GetHashCode", tm)) {
1237 /* white list */
1238 return FALSE;
1239 } else if (!strcmp ("IsNaN", tm) || !strcmp ("IsInfinity", tm) || !strcmp ("IsNegativeInfinity", tm) || !strcmp ("IsPositiveInfinity", tm)) {
1240 g_assert (type_index == 2); // nfloat only
1241 /* white list */
1242 return FALSE;
1245 for (i = 0; i < sizeof (int_unnop) / sizeof (MagicIntrinsic); ++i) {
1246 if (!strcmp (int_unnop [i].op_name, tm)) {
1247 interp_add_ins (td, int_unnop [i].insn [type_index]);
1248 SET_TYPE (td->sp - 1, stack_type [mt], magic_class);
1249 td->ip += 5;
1250 return TRUE;
1254 for (i = 0; i < sizeof (int_binop) / sizeof (MagicIntrinsic); ++i) {
1255 if (!strcmp (int_binop [i].op_name, tm)) {
1256 interp_add_ins (td, int_binop [i].insn [type_index]);
1257 td->sp -= 1;
1258 SET_TYPE (td->sp - 1, stack_type [mt], magic_class);
1259 td->ip += 5;
1260 return TRUE;
1264 for (i = 0; i < sizeof (int_cmpop) / sizeof (MagicIntrinsic); ++i) {
1265 if (!strcmp (int_cmpop [i].op_name, tm)) {
1266 MonoClass *k = mono_defaults.boolean_class;
1267 interp_add_ins (td, int_cmpop [i].insn [type_index]);
1268 td->sp -= 1;
1269 SET_TYPE (td->sp - 1, stack_type [mint_type (m_class_get_byval_arg (k))], k);
1270 td->ip += 5;
1271 return TRUE;
1275 g_error ("TODO: interp_transform_call %s:%s", m_class_get_name (target_method->klass), tm);
1276 } else if (mono_class_is_subclass_of_internal (target_method->klass, mono_defaults.array_class, FALSE)) {
1277 if (!strcmp (tm, "get_Rank")) {
1278 *op = MINT_ARRAY_RANK;
1279 } else if (!strcmp (tm, "get_Length")) {
1280 *op = MINT_LDLEN;
1281 } else if (!strcmp (tm, "Address")) {
1282 *op = readonly ? MINT_LDELEMA : MINT_LDELEMA_TC;
1283 } else if (!strcmp (tm, "UnsafeMov") || !strcmp (tm, "UnsafeLoad") || !strcmp (tm, "Set") || !strcmp (tm, "Get")) {
1284 *op = MINT_CALLRUN;
1285 } else if (!strcmp (tm, "UnsafeStore")) {
1286 g_error ("TODO ArrayClass::UnsafeStore");
1288 } else if (in_corlib &&
1289 !strcmp (klass_name_space, "System.Diagnostics") &&
1290 !strcmp (klass_name, "Debugger")) {
1291 if (!strcmp (tm, "Break") && csignature->param_count == 0) {
1292 if (mini_should_insert_breakpoint (td->method))
1293 *op = MINT_BREAK;
1295 } else if (in_corlib && !strcmp (klass_name_space, "System") && !strcmp (klass_name, "ByReference`1")) {
1296 g_assert (!strcmp (tm, "get_Value"));
1297 *op = MINT_INTRINS_BYREFERENCE_GET_VALUE;
1298 } else if (in_corlib && !strcmp (klass_name_space, "System") && !strcmp (klass_name, "Math") && csignature->param_count == 1 && csignature->params [0]->type == MONO_TYPE_R8) {
1299 if (tm [0] == 'A') {
1300 if (strcmp (tm, "Abs") == 0 && csignature->params [0]->type == MONO_TYPE_R8) {
1301 *op = MINT_ABS;
1302 } else if (strcmp (tm, "Asin") == 0){
1303 *op = MINT_ASIN;
1304 } else if (strcmp (tm, "Asinh") == 0){
1305 *op = MINT_ASINH;
1306 } else if (strcmp (tm, "Acos") == 0){
1307 *op = MINT_ACOS;
1308 } else if (strcmp (tm, "Acosh") == 0){
1309 *op = MINT_ACOSH;
1310 } else if (strcmp (tm, "Atan") == 0){
1311 *op = MINT_ATAN;
1312 } else if (strcmp (tm, "Atanh") == 0){
1313 *op = MINT_ATANH;
1315 } else if (tm [0] == 'C') {
1316 if (strcmp (tm, "Cos") == 0) {
1317 *op = MINT_COS;
1318 } else if (strcmp (tm, "Cbrt") == 0){
1319 *op = MINT_CBRT;
1320 } else if (strcmp (tm, "Cosh") == 0){
1321 *op = MINT_COSH;
1323 } else if (tm [0] == 'S') {
1324 if (strcmp (tm, "Sin") == 0) {
1325 *op = MINT_SIN;
1326 } else if (strcmp (tm, "Sqrt") == 0) {
1327 *op = MINT_SQRT;
1328 } else if (strcmp (tm, "Sinh") == 0){
1329 *op = MINT_SINH;
1331 } else if (tm [0] == 'T') {
1332 if (strcmp (tm, "Tan") == 0) {
1333 *op = MINT_TAN;
1334 } else if (strcmp (tm, "Tanh") == 0){
1335 *op = MINT_TANH;
1338 } else if (in_corlib && !strcmp (klass_name_space, "System") && (!strcmp (klass_name, "Span`1") || !strcmp (klass_name, "ReadOnlySpan`1"))) {
1339 if (!strcmp (tm, "get_Item")) {
1340 MonoGenericClass *gclass = mono_class_get_generic_class (target_method->klass);
1341 MonoClass *param_class = mono_class_from_mono_type_internal (gclass->context.class_inst->type_argv [0]);
1343 if (!mini_is_gsharedvt_variable_klass (param_class)) {
1344 MonoClassField *length_field = mono_class_get_field_from_name_full (target_method->klass, "_length", NULL);
1345 g_assert (length_field);
1346 int offset_length = length_field->offset - sizeof (MonoObject);
1348 MonoClassField *ptr_field = mono_class_get_field_from_name_full (target_method->klass, "_pointer", NULL);
1349 g_assert (ptr_field);
1350 int offset_pointer = ptr_field->offset - sizeof (MonoObject);
1352 int size = mono_class_array_element_size (param_class);
1353 interp_add_ins (td, MINT_GETITEM_SPAN);
1354 td->last_ins->data [0] = size;
1355 td->last_ins->data [1] = offset_length;
1356 td->last_ins->data [2] = offset_pointer;
1358 SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_MP);
1359 td->sp -= 1;
1360 td->ip += 5;
1361 return TRUE;
1363 } else if (!strcmp (tm, "get_Length")) {
1364 MonoClassField *length_field = mono_class_get_field_from_name_full (target_method->klass, "_length", NULL);
1365 g_assert (length_field);
1366 int offset_length = length_field->offset - sizeof (MonoObject);
1367 interp_add_ins (td, MINT_LDLEN_SPAN);
1368 td->last_ins->data [0] = offset_length;
1369 SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I4);
1370 td->ip += 5;
1371 return TRUE;
1373 } else if (in_corlib && !strcmp (klass_name_space, "Internal.Runtime.CompilerServices") && !strcmp (klass_name, "Unsafe")) {
1374 #ifdef ENABLE_NETCORE
1375 if (!strcmp (tm, "AddByteOffset"))
1376 *op = MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET;
1377 else if (!strcmp (tm, "ByteOffset"))
1378 *op = MINT_INTRINS_UNSAFE_BYTE_OFFSET;
1379 else if (!strcmp (tm, "As") || !strcmp (tm, "AsRef"))
1380 *op = MINT_NOP;
1381 else if (!strcmp (tm, "AsPointer")) {
1382 /* NOP */
1383 SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_MP);
1384 td->ip += 5;
1385 return TRUE;
1386 } else if (!strcmp (tm, "IsAddressLessThan")) {
1387 MonoGenericContext *ctx = mono_method_get_context (target_method);
1388 g_assert (ctx);
1389 g_assert (ctx->method_inst);
1390 g_assert (ctx->method_inst->type_argc == 1);
1392 MonoClass *k = mono_defaults.boolean_class;
1393 interp_add_ins (td, MINT_CLT_UN_P);
1394 td->sp -= 1;
1395 SET_TYPE (td->sp - 1, stack_type [mint_type (m_class_get_byval_arg (k))], k);
1396 td->ip += 5;
1397 return TRUE;
1398 } else if (!strcmp (tm, "SizeOf")) {
1399 MonoGenericContext *ctx = mono_method_get_context (target_method);
1400 g_assert (ctx);
1401 g_assert (ctx->method_inst);
1402 g_assert (ctx->method_inst->type_argc == 1);
1403 MonoType *t = ctx->method_inst->type_argv [0];
1404 int align;
1405 int esize = mono_type_size (t, &align);
1406 interp_add_ins (td, MINT_LDC_I4);
1407 WRITE32_INS (td->last_ins, 0, &esize);
1408 PUSH_SIMPLE_TYPE (td, STACK_TYPE_I4);
1409 td->ip += 5;
1410 return TRUE;
1411 } else if (!strcmp (tm, "AreSame")) {
1412 *op = MINT_CEQ_P;
1414 #endif
1415 } else if (in_corlib && !strcmp (klass_name_space, "System.Runtime.CompilerServices") && !strcmp (klass_name, "RuntimeHelpers")) {
1416 #ifdef ENABLE_NETCORE
1417 if (!strcmp (tm, "IsBitwiseEquatable")) {
1418 g_assert (csignature->param_count == 0);
1419 MonoGenericContext *ctx = mono_method_get_context (target_method);
1420 g_assert (ctx);
1421 g_assert (ctx->method_inst);
1422 g_assert (ctx->method_inst->type_argc == 1);
1423 MonoType *t = mini_get_underlying_type (ctx->method_inst->type_argv [0]);
1425 if (MONO_TYPE_IS_PRIMITIVE (t) && t->type != MONO_TYPE_R4 && t->type != MONO_TYPE_R8)
1426 *op = MINT_LDC_I4_1;
1427 else
1428 *op = MINT_LDC_I4_0;
1429 } else if (!strcmp (tm, "ObjectHasComponentSize")) {
1430 *op = MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE;
1432 #endif
1433 } else if (in_corlib && !strcmp (klass_name_space, "System") && !strcmp (klass_name, "RuntimeMethodHandle") && !strcmp (tm, "GetFunctionPointer") && csignature->param_count == 1) {
1434 // We must intrinsify this method on interp so we don't return a pointer to native code entering interpreter
1435 *op = MINT_LDFTN_DYNAMIC;
1436 } else if (in_corlib && target_method->klass == mono_defaults.object_class) {
1437 if (!strcmp (tm, "InternalGetHashCode"))
1438 *op = MINT_INTRINS_GET_HASHCODE;
1439 #ifdef DISABLE_REMOTING
1440 else if (!strcmp (tm, "GetType"))
1441 *op = MINT_INTRINS_GET_TYPE;
1442 #endif
1443 #ifdef ENABLE_NETCORE
1444 else if (!strcmp (tm, "GetRawData")) {
1445 #if SIZEOF_VOID_P == 8
1446 interp_add_ins (td, MINT_LDC_I8_S);
1447 #else
1448 interp_add_ins (td, MINT_LDC_I4_S);
1449 #endif
1450 td->last_ins->data [0] = (gint16) MONO_ABI_SIZEOF (MonoObject);
1452 interp_add_ins (td, MINT_ADD_P);
1453 SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_MP);
1455 td->ip += 5;
1456 return TRUE;
1458 #endif
1459 } else if (in_corlib && target_method->klass == mono_defaults.enum_class && !strcmp (tm, "HasFlag")) {
1460 gboolean intrinsify = FALSE;
1461 MonoClass *base_klass = NULL;
1462 if (td->last_ins && td->last_ins->opcode == MINT_BOX &&
1463 td->last_ins->prev && interp_ins_is_ldc (td->last_ins->prev) &&
1464 td->last_ins->prev->prev && td->last_ins->prev->prev->opcode == MINT_BOX &&
1465 td->sp [-2].klass == td->sp [-1].klass &&
1466 !interp_is_bb_start (td, td->last_ins->prev->prev, NULL) &&
1467 !td->is_bb_start [td->in_start - td->il_code]) {
1468 // csc pattern : box, ldc, box, call HasFlag
1469 g_assert (m_class_is_enumtype (td->sp [-2].klass));
1470 MonoType *base_type = mono_type_get_underlying_type (m_class_get_byval_arg (td->sp [-2].klass));
1471 base_klass = mono_class_from_mono_type_internal (base_type);
1473 // Remove the boxing of valuetypes
1474 interp_remove_ins (td, td->last_ins->prev->prev);
1475 interp_remove_ins (td, td->last_ins);
1477 intrinsify = TRUE;
1478 } else if (td->last_ins && td->last_ins->opcode == MINT_BOX &&
1479 td->last_ins->prev && interp_ins_is_ldc (td->last_ins->prev) &&
1480 constrained_class && td->sp [-1].klass == constrained_class &&
1481 !interp_is_bb_start (td, td->last_ins->prev, NULL) &&
1482 !td->is_bb_start [td->in_start - td->il_code]) {
1483 // mcs pattern : ldc, box, constrained Enum, call HasFlag
1484 g_assert (m_class_is_enumtype (constrained_class));
1485 MonoType *base_type = mono_type_get_underlying_type (m_class_get_byval_arg (constrained_class));
1486 base_klass = mono_class_from_mono_type_internal (base_type);
1487 int mt = mint_type (m_class_get_byval_arg (base_klass));
1489 // Remove boxing and load the value of this
1490 interp_remove_ins (td, td->last_ins);
1491 interp_insert_ins (td, td->last_ins->prev, interp_get_ldind_for_mt (mt));
1493 intrinsify = TRUE;
1495 if (intrinsify) {
1496 interp_add_ins (td, MINT_INTRINS_ENUM_HASFLAG);
1497 td->last_ins->data [0] = get_data_item_index (td, base_klass);
1498 td->sp -= 2;
1499 PUSH_SIMPLE_TYPE (td, STACK_TYPE_I4);
1500 td->ip += 5;
1501 return TRUE;
1503 } else if (in_corlib && !strcmp (klass_name_space, "System.Threading") && !strcmp (klass_name, "Interlocked")) {
1504 #if ENABLE_NETCORE
1505 if (!strcmp (tm, "MemoryBarrier") && csignature->param_count == 0)
1506 *op = MINT_MONO_MEMORY_BARRIER;
1507 #endif
1508 } else if (in_corlib &&
1509 !strcmp (klass_name_space, "System.Runtime.CompilerServices") &&
1510 !strcmp (klass_name, "JitHelpers") &&
1511 (!strcmp (tm, "EnumEquals") || !strcmp (tm, "EnumCompareTo"))) {
1512 MonoGenericContext *ctx = mono_method_get_context (target_method);
1513 g_assert (ctx);
1514 g_assert (ctx->method_inst);
1515 g_assert (ctx->method_inst->type_argc == 1);
1516 g_assert (csignature->param_count == 2);
1518 MonoType *t = ctx->method_inst->type_argv [0];
1519 t = mini_get_underlying_type (t);
1521 gboolean is_i8 = (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_U8);
1522 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);
1524 gboolean is_compareto = strcmp (tm, "EnumCompareTo") == 0;
1525 if (is_compareto) {
1526 int offseta, offsetb;
1527 offseta = create_interp_local (td, t);
1528 offsetb = create_interp_local (td, t);
1530 // Save arguments
1531 store_local_general (td, offsetb, t);
1532 store_local_general (td, offseta, t);
1533 // (a > b)
1534 load_local_general (td, offseta, t);
1535 load_local_general (td, offsetb, t);
1536 if (is_unsigned)
1537 interp_add_ins (td, is_i8 ? MINT_CGT_UN_I8 : MINT_CGT_UN_I4);
1538 else
1539 interp_add_ins (td, is_i8 ? MINT_CGT_I8 : MINT_CGT_I4);
1540 td->sp --;
1541 SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I4);
1542 // (a < b)
1543 load_local_general (td, offseta, t);
1544 load_local_general (td, offsetb, t);
1545 if (is_unsigned)
1546 interp_add_ins (td, is_i8 ? MINT_CLT_UN_I8 : MINT_CLT_UN_I4);
1547 else
1548 interp_add_ins (td, is_i8 ? MINT_CLT_I8 : MINT_CLT_I4);
1549 td->sp --;
1550 SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I4);
1551 // (a > b) - (a < b)
1552 interp_add_ins (td, MINT_SUB_I4);
1553 td->sp --;
1554 td->ip += 5;
1555 return TRUE;
1556 } else {
1557 if (is_i8) {
1558 *op = MINT_CEQ_I8;
1559 } else {
1560 *op = MINT_CEQ_I4;
1565 return FALSE;
1568 static MonoMethod*
1569 interp_transform_internal_calls (MonoMethod *method, MonoMethod *target_method, MonoMethodSignature *csignature, gboolean is_virtual)
1571 if (method->wrapper_type == MONO_WRAPPER_NONE && target_method != NULL) {
1572 if (target_method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1573 target_method = mono_marshal_get_native_wrapper (target_method, FALSE, FALSE);
1574 if (!is_virtual && target_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1575 target_method = mono_marshal_get_synchronized_wrapper (target_method);
1577 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)
1578 target_method = mono_marshal_get_native_wrapper (target_method, FALSE, FALSE);
1580 return target_method;
1583 static gboolean
1584 interp_type_as_ptr (MonoType *tp)
1586 if (MONO_TYPE_IS_POINTER (tp))
1587 return TRUE;
1588 if (MONO_TYPE_IS_REFERENCE (tp))
1589 return TRUE;
1590 if ((tp)->type == MONO_TYPE_I4)
1591 return TRUE;
1592 #if SIZEOF_VOID_P == 8
1593 if ((tp)->type == MONO_TYPE_I8)
1594 return TRUE;
1595 #endif
1596 if ((tp)->type == MONO_TYPE_BOOLEAN)
1597 return TRUE;
1598 if ((tp)->type == MONO_TYPE_CHAR)
1599 return TRUE;
1600 if ((tp)->type == MONO_TYPE_VALUETYPE && m_class_is_enumtype (tp->data.klass))
1601 return TRUE;
1602 return FALSE;
1605 #define INTERP_TYPE_AS_PTR(tp) interp_type_as_ptr (tp)
1607 static int
1608 interp_icall_op_for_sig (MonoMethodSignature *sig)
1610 int op = -1;
1611 switch (sig->param_count) {
1612 case 0:
1613 if (MONO_TYPE_IS_VOID (sig->ret))
1614 op = MINT_ICALL_V_V;
1615 else if (INTERP_TYPE_AS_PTR (sig->ret))
1616 op = MINT_ICALL_V_P;
1617 break;
1618 case 1:
1619 if (MONO_TYPE_IS_VOID (sig->ret)) {
1620 if (INTERP_TYPE_AS_PTR (sig->params [0]))
1621 op = MINT_ICALL_P_V;
1622 } else if (INTERP_TYPE_AS_PTR (sig->ret)) {
1623 if (INTERP_TYPE_AS_PTR (sig->params [0]))
1624 op = MINT_ICALL_P_P;
1626 break;
1627 case 2:
1628 if (MONO_TYPE_IS_VOID (sig->ret)) {
1629 if (INTERP_TYPE_AS_PTR (sig->params [0]) &&
1630 INTERP_TYPE_AS_PTR (sig->params [1]))
1631 op = MINT_ICALL_PP_V;
1632 } else if (INTERP_TYPE_AS_PTR (sig->ret)) {
1633 if (INTERP_TYPE_AS_PTR (sig->params [0]) &&
1634 INTERP_TYPE_AS_PTR (sig->params [1]))
1635 op = MINT_ICALL_PP_P;
1637 break;
1638 case 3:
1639 if (MONO_TYPE_IS_VOID (sig->ret)) {
1640 if (INTERP_TYPE_AS_PTR (sig->params [0]) &&
1641 INTERP_TYPE_AS_PTR (sig->params [1]) &&
1642 INTERP_TYPE_AS_PTR (sig->params [2]))
1643 op = MINT_ICALL_PPP_V;
1644 } else if (INTERP_TYPE_AS_PTR (sig->ret)) {
1645 if (INTERP_TYPE_AS_PTR (sig->params [0]) &&
1646 INTERP_TYPE_AS_PTR (sig->params [1]) &&
1647 INTERP_TYPE_AS_PTR (sig->params [2]))
1648 op = MINT_ICALL_PPP_P;
1650 break;
1651 case 4:
1652 if (MONO_TYPE_IS_VOID (sig->ret)) {
1653 if (INTERP_TYPE_AS_PTR (sig->params [0]) &&
1654 INTERP_TYPE_AS_PTR (sig->params [1]) &&
1655 INTERP_TYPE_AS_PTR (sig->params [2]) &&
1656 INTERP_TYPE_AS_PTR (sig->params [3]))
1657 op = MINT_ICALL_PPPP_V;
1658 } else if (INTERP_TYPE_AS_PTR (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 op = MINT_ICALL_PPPP_P;
1665 break;
1666 case 5:
1667 if (MONO_TYPE_IS_VOID (sig->ret)) {
1668 if (INTERP_TYPE_AS_PTR (sig->params [0]) &&
1669 INTERP_TYPE_AS_PTR (sig->params [1]) &&
1670 INTERP_TYPE_AS_PTR (sig->params [2]) &&
1671 INTERP_TYPE_AS_PTR (sig->params [3]) &&
1672 INTERP_TYPE_AS_PTR (sig->params [4]))
1673 op = MINT_ICALL_PPPPP_V;
1674 } else if (INTERP_TYPE_AS_PTR (sig->ret)) {
1675 if (INTERP_TYPE_AS_PTR (sig->params [0]) &&
1676 INTERP_TYPE_AS_PTR (sig->params [1]) &&
1677 INTERP_TYPE_AS_PTR (sig->params [2]) &&
1678 INTERP_TYPE_AS_PTR (sig->params [3]) &&
1679 INTERP_TYPE_AS_PTR (sig->params [4]))
1680 op = MINT_ICALL_PPPPP_P;
1682 break;
1683 case 6:
1684 if (MONO_TYPE_IS_VOID (sig->ret)) {
1685 if (INTERP_TYPE_AS_PTR (sig->params [0]) &&
1686 INTERP_TYPE_AS_PTR (sig->params [1]) &&
1687 INTERP_TYPE_AS_PTR (sig->params [2]) &&
1688 INTERP_TYPE_AS_PTR (sig->params [3]) &&
1689 INTERP_TYPE_AS_PTR (sig->params [4]) &&
1690 INTERP_TYPE_AS_PTR (sig->params [5]))
1691 op = MINT_ICALL_PPPPPP_V;
1692 } else if (INTERP_TYPE_AS_PTR (sig->ret)) {
1693 if (INTERP_TYPE_AS_PTR (sig->params [0]) &&
1694 INTERP_TYPE_AS_PTR (sig->params [1]) &&
1695 INTERP_TYPE_AS_PTR (sig->params [2]) &&
1696 INTERP_TYPE_AS_PTR (sig->params [3]) &&
1697 INTERP_TYPE_AS_PTR (sig->params [4]) &&
1698 INTERP_TYPE_AS_PTR (sig->params [5]))
1699 op = MINT_ICALL_PPPPPP_P;
1701 break;
1703 return op;
1706 #define INLINE_LENGTH_LIMIT 20
1708 static gboolean
1709 interp_method_check_inlining (TransformData *td, MonoMethod *method)
1711 MonoMethodHeaderSummary header;
1713 if (td->method == method)
1714 return FALSE;
1716 if (!mono_method_get_header_summary (method, &header))
1717 return FALSE;
1719 /*runtime, icall and pinvoke are checked by summary call*/
1720 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
1721 (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
1722 (mono_class_is_marshalbyref (method->klass)) ||
1723 header.has_clauses)
1724 return FALSE;
1726 if (header.code_size >= INLINE_LENGTH_LIMIT)
1727 return FALSE;
1729 if (mono_class_needs_cctor_run (method->klass, NULL)) {
1730 MonoVTable *vtable;
1731 ERROR_DECL (error);
1732 if (!m_class_get_runtime_info (method->klass))
1733 /* No vtable created yet */
1734 return FALSE;
1735 vtable = mono_class_vtable_checked (td->rtm->domain, method->klass, error);
1736 if (!is_ok (error)) {
1737 mono_error_cleanup (error);
1738 return FALSE;
1740 if (!vtable->initialized)
1741 return FALSE;
1744 /* We currently access at runtime the wrapper data */
1745 if (method->wrapper_type != MONO_WRAPPER_NONE)
1746 return FALSE;
1748 /* Our usage of `emit_store_value_as_local ()` for nint, nuint and nfloat
1749 * is kinda hacky, and doesn't work with the inliner */
1750 if (mono_class_get_magic_index (method->klass) >= 0)
1751 return FALSE;
1753 return TRUE;
1756 static gboolean
1757 interp_inline_method (TransformData *td, MonoMethod *target_method, MonoMethodHeader *header, MonoError *error)
1759 const unsigned char *prev_ip, *prev_il_code, *prev_in_start;
1760 StackInfo **prev_stack_state;
1761 int *prev_stack_height, *prev_vt_stack_size, *prev_clause_indexes, *prev_in_offsets;
1762 guint8 *prev_is_bb_start;
1763 gboolean ret;
1764 unsigned int prev_max_stack_height, prev_max_vt_sp, prev_total_locals_size;
1765 int prev_n_data_items;
1766 int i, prev_vt_sp;
1767 int prev_sp_offset;
1768 MonoGenericContext *generic_context = NULL;
1769 StackInfo *prev_param_area;
1770 MonoMethod *prev_inlined_method;
1771 MonoMethodSignature *csignature = mono_method_signature_internal (target_method);
1772 int nargs = csignature->param_count + !!csignature->hasthis;
1773 InterpInst *prev_last_ins;
1775 if (csignature->is_inflated)
1776 generic_context = mono_method_get_context (target_method);
1777 else {
1778 MonoGenericContainer *generic_container = mono_method_get_generic_container (target_method);
1779 if (generic_container)
1780 generic_context = &generic_container->context;
1783 prev_ip = td->ip;
1784 prev_il_code = td->il_code;
1785 prev_in_start = td->in_start;
1786 prev_sp_offset = td->sp - td->stack;
1787 prev_vt_sp = td->vt_sp;
1788 prev_stack_state = td->stack_state;
1789 prev_stack_height = td->stack_height;
1790 prev_vt_stack_size = td->vt_stack_size;
1791 prev_clause_indexes = td->clause_indexes;
1792 prev_inlined_method = td->inlined_method;
1793 prev_last_ins = td->last_ins;
1794 td->inlined_method = target_method;
1796 prev_max_stack_height = td->max_stack_height;
1797 prev_max_vt_sp = td->max_vt_sp;
1798 prev_total_locals_size = td->total_locals_size;
1800 prev_n_data_items = td->n_data_items;
1801 prev_in_offsets = td->in_offsets;
1802 td->in_offsets = (int*)g_malloc0((header->code_size + 1) * sizeof(int));
1804 prev_is_bb_start = td->is_bb_start;
1806 /* Inlining pops the arguments, restore the stack */
1807 prev_param_area = (StackInfo*)g_malloc (nargs * sizeof (StackInfo));
1808 memcpy (prev_param_area, &td->sp [-nargs], nargs * sizeof (StackInfo));
1810 if (td->verbose_level)
1811 g_print ("Inline start method %s.%s\n", m_class_get_name (target_method->klass), target_method->name);
1812 ret = generate_code (td, target_method, header, generic_context, error);
1814 if (!ret) {
1815 if (td->verbose_level)
1816 g_print ("Inline aborted method %s.%s\n", m_class_get_name (target_method->klass), target_method->name);
1817 td->max_stack_height = prev_max_stack_height;
1818 td->max_vt_sp = prev_max_vt_sp;
1819 td->total_locals_size = prev_total_locals_size;
1822 /* Remove any newly added items */
1823 for (i = prev_n_data_items; i < td->n_data_items; i++) {
1824 g_hash_table_remove (td->data_hash, td->data_items [i]);
1826 td->n_data_items = prev_n_data_items;
1827 td->sp = td->stack + prev_sp_offset;
1828 memcpy (&td->sp [-nargs], prev_param_area, nargs * sizeof (StackInfo));
1829 td->vt_sp = prev_vt_sp;
1830 td->last_ins = prev_last_ins;
1831 if (td->last_ins)
1832 td->last_ins->next = NULL;
1833 UnlockedIncrement (&mono_interp_stats.inline_failures);
1834 } else {
1835 if (td->verbose_level)
1836 g_print ("Inline end method %s.%s\n", m_class_get_name (target_method->klass), target_method->name);
1837 UnlockedIncrement (&mono_interp_stats.inlined_methods);
1838 // Make sure we have an IR instruction associated with the now removed IL CALL
1839 // FIXME This could be prettier. We might be able to make inlining saner now that
1840 // that we can easily tweak the instruction list.
1841 if (!prev_inlined_method) {
1842 if (prev_last_ins) {
1843 if (prev_last_ins->next)
1844 prev_last_ins->next->il_offset = prev_in_start - prev_il_code;
1845 } else if (td->first_ins) {
1846 td->first_ins->il_offset = prev_in_start - prev_il_code;
1851 td->ip = prev_ip;
1852 td->in_start = prev_in_start;
1853 td->il_code = prev_il_code;
1854 td->stack_state = prev_stack_state;
1855 td->stack_height = prev_stack_height;
1856 td->vt_stack_size = prev_vt_stack_size;
1857 td->clause_indexes = prev_clause_indexes;
1858 td->is_bb_start = prev_is_bb_start;
1859 td->inlined_method = prev_inlined_method;
1861 g_free (td->in_offsets);
1862 td->in_offsets = prev_in_offsets;
1864 g_free (prev_param_area);
1865 return ret;
1868 static void
1869 interp_constrained_box (TransformData *td, MonoDomain *domain, MonoClass *constrained_class, MonoMethodSignature *csignature, MonoError *error)
1871 int mt = mint_type (m_class_get_byval_arg (constrained_class));
1872 if (mono_class_is_nullable (constrained_class)) {
1873 g_assert (mt == MINT_TYPE_VT);
1874 interp_add_ins (td, MINT_BOX_NULLABLE);
1875 td->last_ins->data [0] = get_data_item_index (td, constrained_class);
1876 td->last_ins->data [1] = csignature->param_count | ((td->sp - 1 - csignature->param_count)->type != STACK_TYPE_MP ? 0 : BOX_NOT_CLEAR_VT_SP);
1877 } else {
1878 MonoVTable *vtable = mono_class_vtable_checked (domain, constrained_class, error);
1879 return_if_nok (error);
1881 if (mt == MINT_TYPE_VT) {
1882 interp_add_ins (td, MINT_BOX_VT);
1883 td->last_ins->data [0] = get_data_item_index (td, vtable);
1884 td->last_ins->data [1] = csignature->param_count | ((td->sp - 1 - csignature->param_count)->type != STACK_TYPE_MP ? 0 : BOX_NOT_CLEAR_VT_SP);
1885 } else {
1886 interp_add_ins (td, MINT_BOX);
1887 td->last_ins->data [0] = get_data_item_index (td, vtable);
1888 td->last_ins->data [1] = csignature->param_count;
1893 /* Return FALSE if error, including inline failure */
1894 static gboolean
1895 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)
1897 MonoImage *image = m_class_get_image (method->klass);
1898 MonoMethodSignature *csignature;
1899 int is_virtual = *td->ip == CEE_CALLVIRT;
1900 int calli = *td->ip == CEE_CALLI || *td->ip == CEE_MONO_CALLI_EXTRA_ARG;
1901 int i;
1902 guint32 vt_stack_used = 0;
1903 guint32 vt_res_size = 0;
1904 int op = -1;
1905 int native = 0;
1906 int is_void = 0;
1907 int need_null_check = is_virtual;
1909 guint32 token = read32 (td->ip + 1);
1911 if (target_method == NULL) {
1912 if (calli) {
1913 CHECK_STACK(td, 1);
1914 if (method->wrapper_type != MONO_WRAPPER_NONE)
1915 csignature = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
1916 else {
1917 csignature = mono_metadata_parse_signature_checked (image, token, error);
1918 return_val_if_nok (error, FALSE);
1921 if (generic_context) {
1922 csignature = mono_inflate_generic_signature (csignature, generic_context, error);
1923 return_val_if_nok (error, FALSE);
1927 * The compiled interp entry wrapper is passed to runtime_invoke instead of
1928 * the InterpMethod pointer. FIXME
1930 native = csignature->pinvoke || method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE;
1931 --td->sp;
1933 target_method = NULL;
1934 } else {
1935 if (method->wrapper_type == MONO_WRAPPER_NONE) {
1936 target_method = mono_get_method_checked (image, token, NULL, generic_context, error);
1937 return_val_if_nok (error, FALSE);
1938 } else
1939 target_method = (MonoMethod *)mono_method_get_wrapper_data (method, token);
1940 csignature = mono_method_signature_internal (target_method);
1942 if (generic_context) {
1943 csignature = mono_inflate_generic_signature (csignature, generic_context, error);
1944 return_val_if_nok (error, FALSE);
1945 target_method = mono_class_inflate_generic_method_checked (target_method, generic_context, error);
1946 return_val_if_nok (error, FALSE);
1949 } else {
1950 csignature = mono_method_signature_internal (target_method);
1953 if (check_visibility && target_method && !mono_method_can_access_method (method, target_method))
1954 interp_generate_mae_throw (td, method, target_method);
1956 if (target_method && target_method->string_ctor) {
1957 /* Create the real signature */
1958 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (td->mempool, csignature);
1959 ctor_sig->ret = m_class_get_byval_arg (mono_defaults.string_class);
1961 csignature = ctor_sig;
1964 /* Intrinsics */
1965 if (target_method && interp_handle_intrinsics (td, target_method, constrained_class, csignature, readonly, &op))
1966 return TRUE;
1968 if (constrained_class) {
1969 if (m_class_is_enumtype (constrained_class) && !strcmp (target_method->name, "GetHashCode")) {
1970 /* Use the corresponding method from the base type to avoid boxing */
1971 MonoType *base_type = mono_class_enum_basetype_internal (constrained_class);
1972 g_assert (base_type);
1973 constrained_class = mono_class_from_mono_type_internal (base_type);
1974 target_method = mono_class_get_method_from_name_checked (constrained_class, target_method->name, 0, 0, error);
1975 mono_error_assert_ok (error);
1976 g_assert (target_method);
1980 if (constrained_class) {
1981 mono_class_setup_vtable (constrained_class);
1982 if (mono_class_has_failure (constrained_class)) {
1983 mono_error_set_for_class_failure (error, constrained_class);
1984 return FALSE;
1986 #if DEBUG_INTERP
1987 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);
1988 #endif
1989 target_method = mono_get_method_constrained_with_method (image, target_method, constrained_class, generic_context, error);
1990 #if DEBUG_INTERP
1991 g_print (" : %s::%s. %s (%p)\n", target_method->klass->name, target_method->name, mono_signature_full_name (target_method->signature), target_method);
1992 #endif
1993 /* Intrinsics: Try again, it could be that `mono_get_method_constrained_with_method` resolves to a method that we can substitute */
1994 if (target_method && interp_handle_intrinsics (td, target_method, constrained_class, csignature, readonly, &op))
1995 return TRUE;
1997 return_val_if_nok (error, FALSE);
1998 mono_class_setup_vtable (target_method->klass);
2000 if (!m_class_is_valuetype (constrained_class)) {
2001 /* managed pointer on the stack, we need to deref that puppy */
2002 interp_add_ins (td, MINT_LDIND_I);
2003 td->last_ins->data [0] = csignature->param_count;
2004 } 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) {
2005 if (target_method->klass == mono_defaults.enum_class && (td->sp - csignature->param_count - 1)->type == STACK_TYPE_MP) {
2006 /* managed pointer on the stack, we need to deref that puppy */
2007 /* Always load the entire stackval, to handle also the case where the enum has long storage */
2008 interp_add_ins (td, MINT_LDIND_I8);
2009 td->last_ins->data [0] = csignature->param_count;
2012 interp_constrained_box (td, domain, constrained_class, csignature, error);
2013 return_val_if_nok (error, FALSE);
2014 } else {
2015 if (target_method->klass != constrained_class) {
2017 * The type parameter is instantiated as a valuetype,
2018 * but that type doesn't override the method we're
2019 * calling, so we need to box `this'.
2021 if (target_method->klass == mono_defaults.enum_class && (td->sp - csignature->param_count - 1)->type == STACK_TYPE_MP) {
2022 /* managed pointer on the stack, we need to deref that puppy */
2023 /* Always load the entire stackval, to handle also the case where the enum has long storage */
2024 interp_add_ins (td, MINT_LDIND_I8);
2025 td->last_ins->data [0] = csignature->param_count;
2028 interp_constrained_box (td, domain, constrained_class, csignature, error);
2029 return_val_if_nok (error, FALSE);
2031 is_virtual = FALSE;
2035 if (target_method)
2036 mono_class_init_internal (target_method->klass);
2038 if (!is_virtual && target_method && (target_method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
2039 if (!mono_class_is_interface (method->klass))
2040 interp_generate_bie_throw (td);
2041 else
2042 is_virtual = TRUE;
2045 if (is_virtual && target_method && (!(target_method->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
2046 (MONO_METHOD_IS_FINAL (target_method) &&
2047 target_method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2048 !(mono_class_is_marshalbyref (target_method->klass))) {
2049 /* Not really virtual, just needs a null check */
2050 is_virtual = FALSE;
2051 need_null_check = TRUE;
2054 CHECK_STACK (td, csignature->param_count + csignature->hasthis);
2055 if (!td->gen_sdb_seq_points && !calli && op == -1 && (!is_virtual || (target_method->flags & METHOD_ATTRIBUTE_VIRTUAL) == 0) &&
2056 (target_method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 &&
2057 (target_method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) == 0 &&
2058 !(target_method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING)) {
2059 (void)mono_class_vtable_checked (domain, target_method->klass, error);
2060 return_val_if_nok (error, FALSE);
2062 if (method == target_method && *(td->ip + 5) == CEE_RET && !(csignature->hasthis && m_class_is_valuetype (target_method->klass))) {
2063 if (td->inlined_method)
2064 return FALSE;
2066 if (td->verbose_level)
2067 g_print ("Optimize tail call of %s.%s\n", m_class_get_name (target_method->klass), target_method->name);
2069 for (i = csignature->param_count - 1 + !!csignature->hasthis; i >= 0; --i)
2070 store_arg (td, i);
2072 interp_add_ins (td, MINT_BR_S);
2073 // We are branching to the beginning of the method
2074 td->last_ins->data [0] = 0;
2075 if (!is_bb_start [td->ip + 5 - td->il_code])
2076 ++td->ip; /* gobble the CEE_RET if it isn't branched to */
2077 td->ip += 5;
2078 return TRUE;
2082 target_method = interp_transform_internal_calls (method, target_method, csignature, is_virtual);
2084 if (csignature->call_convention == MONO_CALL_VARARG) {
2085 csignature = mono_method_get_signature_checked (target_method, image, token, generic_context, error);
2086 int vararg_stack = 0;
2088 * For vararg calls, ArgIterator expects the signature and the varargs to be
2089 * stored in a linear memory. We allocate the necessary vt_stack space for
2090 * this. All varargs will be pushed to the vt_stack at call site.
2092 vararg_stack += sizeof (gpointer);
2093 for (i = csignature->sentinelpos; i < csignature->param_count; ++i) {
2094 int align, arg_size;
2095 arg_size = mono_type_stack_size (csignature->params [i], &align);
2096 vararg_stack += arg_size;
2098 vt_stack_used += ALIGN_TO (vararg_stack, MINT_VT_ALIGNMENT);
2099 PUSH_VT (td, vararg_stack);
2102 if (need_null_check) {
2103 interp_add_ins (td, MINT_CKNULL_N);
2104 td->last_ins->data [0] = csignature->param_count + 1;
2107 g_assert (csignature->call_convention != MONO_CALL_FASTCALL);
2108 if ((mono_interp_opt & INTERP_OPT_INLINE) && op == -1 && !is_virtual && target_method && interp_method_check_inlining (td, target_method)) {
2109 MonoMethodHeader *mheader = interp_method_get_header (target_method, error);
2110 return_val_if_nok (error, FALSE);
2112 if (interp_inline_method (td, target_method, mheader, error)) {
2113 td->ip += 5;
2114 return TRUE;
2118 /* Don't inline methods that do calls */
2119 if (op == -1 && td->inlined_method)
2120 return FALSE;
2122 td->sp -= csignature->param_count + !!csignature->hasthis;
2123 for (i = 0; i < csignature->param_count; ++i) {
2124 if (td->sp [i + !!csignature->hasthis].type == STACK_TYPE_VT) {
2125 gint32 size;
2126 MonoClass *klass = mono_class_from_mono_type_internal (csignature->params [i]);
2127 if (csignature->pinvoke && method->wrapper_type != MONO_WRAPPER_NONE)
2128 size = mono_class_native_size (klass, NULL);
2129 else
2130 size = mono_class_value_size (klass, NULL);
2131 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
2132 vt_stack_used += size;
2136 /* need to handle typedbyref ... */
2137 if (csignature->ret->type != MONO_TYPE_VOID) {
2138 int mt = mint_type(csignature->ret);
2139 MonoClass *klass = mono_class_from_mono_type_internal (csignature->ret);
2140 if (mt == MINT_TYPE_VT) {
2141 if (csignature->pinvoke && method->wrapper_type != MONO_WRAPPER_NONE)
2142 vt_res_size = mono_class_native_size (klass, NULL);
2143 else
2144 vt_res_size = mono_class_value_size (klass, NULL);
2145 if (mono_class_has_failure (klass)) {
2146 mono_error_set_for_class_failure (error, klass);
2147 return FALSE;
2149 PUSH_VT(td, vt_res_size);
2151 PUSH_TYPE(td, stack_type[mt], klass);
2152 } else
2153 is_void = TRUE;
2155 /* We need to convert delegate invoke to a indirect call on the interp_invoke_impl field */
2156 if (target_method && m_class_get_parent (target_method->klass) == mono_defaults.multicastdelegate_class) {
2157 const char *name = target_method->name;
2158 if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
2159 calli = TRUE;
2160 interp_add_ins (td, MINT_LD_DELEGATE_INVOKE_IMPL);
2161 td->last_ins->data [0] = csignature->param_count + 1;
2165 if (op >= 0) {
2166 interp_add_ins (td, op);
2168 if (op == MINT_LDLEN) {
2169 #ifdef MONO_BIG_ARRAYS
2170 SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I8);
2171 #else
2172 SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I4);
2173 #endif
2175 if (op == MINT_LDELEMA || op == MINT_LDELEMA_TC) {
2176 td->last_ins->data [0] = get_data_item_index (td, m_class_get_element_class (target_method->klass));
2177 td->last_ins->data [1] = 1 + m_class_get_rank (target_method->klass);
2180 if (op == MINT_CALLRUN) {
2181 td->last_ins->data [0] = get_data_item_index (td, target_method);
2182 td->last_ins->data [1] = get_data_item_index (td, mono_method_signature_internal (target_method));
2184 } else if (!calli && !is_virtual && jit_call_supported (target_method, csignature)) {
2185 interp_add_ins (td, MINT_JIT_CALL);
2186 td->last_ins->data [0] = get_data_item_index (td, (void *)mono_interp_get_imethod (domain, target_method, error));
2187 mono_error_assert_ok (error);
2188 } else {
2189 #ifndef MONO_ARCH_HAS_NO_PROPER_MONOCTX
2190 /* Try using fast icall path for simple signatures */
2191 if (native && !method->dynamic)
2192 op = interp_icall_op_for_sig (csignature);
2193 #endif
2194 if (csignature->call_convention == MONO_CALL_VARARG)
2195 interp_add_ins (td, MINT_CALL_VARARG);
2196 else if (calli)
2197 interp_add_ins (td, native ? ((op != -1) ? MINT_CALLI_NAT_FAST : MINT_CALLI_NAT) : MINT_CALLI);
2198 else if (is_virtual && !mono_class_is_marshalbyref (target_method->klass))
2199 interp_add_ins (td, is_void ? MINT_VCALLVIRT_FAST : MINT_CALLVIRT_FAST);
2200 else if (is_virtual)
2201 interp_add_ins (td, is_void ? MINT_VCALLVIRT : MINT_CALLVIRT);
2202 else
2203 interp_add_ins (td, is_void ? MINT_VCALL : MINT_CALL);
2205 if (calli) {
2206 td->last_ins->data [0] = get_data_item_index (td, (void *)csignature);
2207 if (op != -1) {
2208 td->last_ins->data[1] = op;
2209 if (td->last_ins->opcode == MINT_CALLI_NAT_FAST)
2210 td->last_ins->data[2] = save_last_error;
2211 } else if (op == -1 && td->last_ins->opcode == MINT_CALLI_NAT) {
2212 td->last_ins->data[1] = save_last_error;
2214 } else {
2215 td->last_ins->data [0] = get_data_item_index (td, (void *)mono_interp_get_imethod (domain, target_method, error));
2216 return_val_if_nok (error, FALSE);
2217 if (csignature->call_convention == MONO_CALL_VARARG)
2218 td->last_ins->data [1] = get_data_item_index (td, (void *)csignature);
2219 else if (is_virtual && !mono_class_is_marshalbyref (target_method->klass)) {
2220 /* FIXME Use fastpath also for MBRO. Asserts in mono_method_get_vtable_slot */
2221 if (mono_class_is_interface (target_method->klass))
2222 td->last_ins->data [1] = -2 * MONO_IMT_SIZE + mono_method_get_imt_slot (target_method);
2223 else
2224 td->last_ins->data [1] = mono_method_get_vtable_slot (target_method);
2228 td->ip += 5;
2229 if (vt_stack_used != 0 || vt_res_size != 0) {
2230 interp_add_ins (td, MINT_VTRESULT);
2231 td->last_ins->data [0] = vt_res_size;
2232 WRITE32_INS (td->last_ins, 1, &vt_stack_used);
2233 td->vt_sp -= vt_stack_used;
2236 return TRUE;
2239 static MonoClassField *
2240 interp_field_from_token (MonoMethod *method, guint32 token, MonoClass **klass, MonoGenericContext *generic_context, MonoError *error)
2242 MonoClassField *field = NULL;
2243 if (method->wrapper_type != MONO_WRAPPER_NONE) {
2244 field = (MonoClassField *) mono_method_get_wrapper_data (method, token);
2245 *klass = field->parent;
2247 mono_class_setup_fields (field->parent);
2248 } else {
2249 field = mono_field_from_token_checked (m_class_get_image (method->klass), token, klass, generic_context, error);
2250 return_val_if_nok (error, NULL);
2253 if (!method->skip_visibility && !mono_method_can_access_field (method, field)) {
2254 char *method_fname = mono_method_full_name (method, TRUE);
2255 char *field_fname = mono_field_full_name (field);
2256 mono_error_set_generic_error (error, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
2257 g_free (method_fname);
2258 g_free (field_fname);
2259 return NULL;
2262 return field;
2265 static InterpBasicBlock*
2266 get_bb (TransformData *td, InterpBasicBlock *cbb, unsigned char *ip)
2268 int offset = ip - td->il_code;
2269 InterpBasicBlock *bb = td->offset_to_bb [offset];
2271 if (!bb) {
2272 bb = (InterpBasicBlock*)mono_mempool_alloc0 (td->mempool, sizeof (InterpBasicBlock));
2273 bb->ip = ip;
2274 td->offset_to_bb [offset] = bb;
2276 td->basic_blocks = g_list_append_mempool (td->mempool, td->basic_blocks, bb);
2279 if (cbb)
2280 bb->preds = g_slist_prepend_mempool (td->mempool, bb->preds, cbb);
2281 return bb;
2285 * get_basic_blocks:
2287 * Compute the set of IL level basic blocks.
2289 static void
2290 get_basic_blocks (TransformData *td)
2292 guint8 *start = (guint8*)td->il_code;
2293 guint8 *end = (guint8*)td->il_code + td->code_size;
2294 guint8 *ip = start;
2295 unsigned char *target;
2296 int i;
2297 guint cli_addr;
2298 const MonoOpcode *opcode;
2299 InterpBasicBlock *cbb;
2301 td->offset_to_bb = (InterpBasicBlock**)mono_mempool_alloc0 (td->mempool, sizeof (InterpBasicBlock*) * (end - start + 1));
2302 td->entry_bb = cbb = get_bb (td, NULL, start);
2304 while (ip < end) {
2305 cli_addr = ip - start;
2306 td->offset_to_bb [cli_addr] = cbb;
2307 i = mono_opcode_value ((const guint8 **)&ip, end);
2308 opcode = &mono_opcodes [i];
2309 switch (opcode->argument) {
2310 case MonoInlineNone:
2311 ip++;
2312 break;
2313 case MonoInlineString:
2314 case MonoInlineType:
2315 case MonoInlineField:
2316 case MonoInlineMethod:
2317 case MonoInlineTok:
2318 case MonoInlineSig:
2319 case MonoShortInlineR:
2320 case MonoInlineI:
2321 ip += 5;
2322 break;
2323 case MonoInlineVar:
2324 ip += 3;
2325 break;
2326 case MonoShortInlineVar:
2327 case MonoShortInlineI:
2328 ip += 2;
2329 break;
2330 case MonoShortInlineBrTarget:
2331 target = start + cli_addr + 2 + (signed char)ip [1];
2332 get_bb (td, cbb, target);
2333 ip += 2;
2334 cbb = get_bb (td, cbb, ip);
2335 break;
2336 case MonoInlineBrTarget:
2337 target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
2338 get_bb (td, cbb, target);
2339 ip += 5;
2340 cbb = get_bb (td, cbb, ip);
2341 break;
2342 case MonoInlineSwitch: {
2343 guint32 n = read32 (ip + 1);
2344 guint32 j;
2345 ip += 5;
2346 cli_addr += 5 + 4 * n;
2347 target = start + cli_addr;
2348 get_bb (td, cbb, target);
2350 for (j = 0; j < n; ++j) {
2351 target = start + cli_addr + (gint32)read32 (ip);
2352 get_bb (td, cbb, target);
2353 ip += 4;
2355 cbb = get_bb (td, cbb, ip);
2356 break;
2358 case MonoInlineR:
2359 case MonoInlineI8:
2360 ip += 9;
2361 break;
2362 default:
2363 g_assert_not_reached ();
2366 if (i == CEE_THROW)
2367 cbb = get_bb (td, NULL, ip);
2371 static void
2372 interp_save_debug_info (InterpMethod *rtm, MonoMethodHeader *header, TransformData *td, GArray *line_numbers)
2374 MonoDebugMethodJitInfo *dinfo;
2375 int i;
2377 if (!mono_debug_enabled ())
2378 return;
2381 * We save the debug info in the same way the JIT does it, treating the interpreter IR as the native code.
2384 dinfo = g_new0 (MonoDebugMethodJitInfo, 1);
2385 dinfo->num_params = rtm->param_count;
2386 dinfo->params = g_new0 (MonoDebugVarInfo, dinfo->num_params);
2387 dinfo->num_locals = header->num_locals;
2388 dinfo->locals = g_new0 (MonoDebugVarInfo, header->num_locals);
2389 dinfo->code_start = (guint8*)rtm->code;
2390 dinfo->code_size = td->new_code_end - td->new_code;
2391 dinfo->epilogue_begin = 0;
2392 dinfo->has_var_info = TRUE;
2393 dinfo->num_line_numbers = line_numbers->len;
2394 dinfo->line_numbers = g_new0 (MonoDebugLineNumberEntry, dinfo->num_line_numbers);
2396 for (i = 0; i < dinfo->num_params; i++) {
2397 MonoDebugVarInfo *var = &dinfo->params [i];
2398 var->type = rtm->param_types [i];
2400 for (i = 0; i < dinfo->num_locals; i++) {
2401 MonoDebugVarInfo *var = &dinfo->locals [i];
2402 var->type = mono_metadata_type_dup (NULL, header->locals [i]);
2405 for (i = 0; i < dinfo->num_line_numbers; i++)
2406 dinfo->line_numbers [i] = g_array_index (line_numbers, MonoDebugLineNumberEntry, i);
2407 mono_debug_add_method (rtm->method, dinfo, rtm->domain);
2409 mono_debug_free_method_jit_info (dinfo);
2412 /* Same as the code in seq-points.c */
2413 static void
2414 insert_pred_seq_point (SeqPoint *last_sp, SeqPoint *sp, GSList **next)
2416 GSList *l;
2417 int src_index = last_sp->next_offset;
2418 int dst_index = sp->next_offset;
2420 /* bb->in_bb might contain duplicates */
2421 for (l = next [src_index]; l; l = l->next)
2422 if (GPOINTER_TO_UINT (l->data) == dst_index)
2423 break;
2424 if (!l)
2425 next [src_index] = g_slist_append (next [src_index], GUINT_TO_POINTER (dst_index));
2428 static void
2429 recursively_make_pred_seq_points (TransformData *td, InterpBasicBlock *bb)
2431 SeqPoint ** const MONO_SEQ_SEEN_LOOP = (SeqPoint**)GINT_TO_POINTER(-1);
2432 GSList *l;
2434 GArray *predecessors = g_array_new (FALSE, TRUE, sizeof (gpointer));
2435 GHashTable *seen = g_hash_table_new_full (g_direct_hash, NULL, NULL, NULL);
2437 // Insert/remove sentinel into the memoize table to detect loops containing bb
2438 bb->pred_seq_points = MONO_SEQ_SEEN_LOOP;
2440 for (l = bb->preds; l; l = l->next) {
2441 InterpBasicBlock *in_bb = (InterpBasicBlock*)l->data;
2443 // This bb has the last seq point, append it and continue
2444 if (in_bb->last_seq_point != NULL) {
2445 predecessors = g_array_append_val (predecessors, in_bb->last_seq_point);
2446 continue;
2449 // We've looped or handled this before, exit early.
2450 // No last sequence points to find.
2451 if (in_bb->pred_seq_points == MONO_SEQ_SEEN_LOOP)
2452 continue;
2454 // Take sequence points from incoming basic blocks
2456 if (in_bb == td->entry_bb)
2457 continue;
2459 if (in_bb->pred_seq_points == NULL)
2460 recursively_make_pred_seq_points (td, in_bb);
2462 // Union sequence points with incoming bb's
2463 for (int i=0; i < in_bb->num_pred_seq_points; i++) {
2464 if (!g_hash_table_lookup (seen, in_bb->pred_seq_points [i])) {
2465 g_array_append_val (predecessors, in_bb->pred_seq_points [i]);
2466 g_hash_table_insert (seen, in_bb->pred_seq_points [i], (gpointer)&MONO_SEQ_SEEN_LOOP);
2469 // predecessors = g_array_append_vals (predecessors, in_bb->pred_seq_points, in_bb->num_pred_seq_points);
2472 g_hash_table_destroy (seen);
2474 if (predecessors->len != 0) {
2475 bb->pred_seq_points = (SeqPoint**)mono_mempool_alloc0 (td->mempool, sizeof (SeqPoint *) * predecessors->len);
2476 bb->num_pred_seq_points = predecessors->len;
2478 for (int newer = 0; newer < bb->num_pred_seq_points; newer++) {
2479 bb->pred_seq_points [newer] = (SeqPoint*)g_array_index (predecessors, gpointer, newer);
2483 g_array_free (predecessors, TRUE);
2486 static void
2487 collect_pred_seq_points (TransformData *td, InterpBasicBlock *bb, SeqPoint *seqp, GSList **next)
2489 // Doesn't have a last sequence point, must find from incoming basic blocks
2490 if (bb->pred_seq_points == NULL && bb != td->entry_bb)
2491 recursively_make_pred_seq_points (td, bb);
2493 for (int i = 0; i < bb->num_pred_seq_points; i++)
2494 insert_pred_seq_point (bb->pred_seq_points [i], seqp, next);
2496 return;
2499 static void
2500 save_seq_points (TransformData *td, MonoJitInfo *jinfo)
2502 GByteArray *array;
2503 int i, seq_info_size;
2504 MonoSeqPointInfo *info;
2505 GSList **next = NULL;
2506 GList *bblist;
2508 if (!td->gen_sdb_seq_points)
2509 return;
2512 * For each sequence point, compute the list of sequence points immediately
2513 * following it, this is needed to implement 'step over' in the debugger agent.
2514 * Similar to the code in mono_save_seq_point_info ().
2516 for (i = 0; i < td->seq_points->len; ++i) {
2517 SeqPoint *sp = (SeqPoint*)g_ptr_array_index (td->seq_points, i);
2519 /* Store the seq point index here temporarily */
2520 sp->next_offset = i;
2522 next = (GSList**)mono_mempool_alloc0 (td->mempool, sizeof (GList*) * td->seq_points->len);
2523 for (bblist = td->basic_blocks; bblist; bblist = bblist->next) {
2524 InterpBasicBlock *bb = (InterpBasicBlock*)bblist->data;
2526 GSList *bb_seq_points = g_slist_reverse (bb->seq_points);
2527 SeqPoint *last = NULL;
2528 for (GSList *l = bb_seq_points; l; l = l->next) {
2529 SeqPoint *sp = (SeqPoint*)l->data;
2531 if (sp->il_offset == METHOD_ENTRY_IL_OFFSET || sp->il_offset == METHOD_EXIT_IL_OFFSET)
2532 /* Used to implement method entry/exit events */
2533 continue;
2535 if (last != NULL) {
2536 /* Link with the previous seq point in the same bb */
2537 next [last->next_offset] = g_slist_append_mempool (td->mempool, next [last->next_offset], GINT_TO_POINTER (sp->next_offset));
2538 } else {
2539 /* Link with the last bb in the previous bblocks */
2540 collect_pred_seq_points (td, bb, sp, next);
2542 last = sp;
2546 /* Serialize the seq points into a byte array */
2547 array = g_byte_array_new ();
2548 SeqPoint zero_seq_point = {0};
2549 SeqPoint* last_seq_point = &zero_seq_point;
2550 for (i = 0; i < td->seq_points->len; ++i) {
2551 SeqPoint *sp = (SeqPoint*)g_ptr_array_index (td->seq_points, i);
2553 sp->next_offset = 0;
2554 if (mono_seq_point_info_add_seq_point (array, sp, last_seq_point, next [i], TRUE))
2555 last_seq_point = sp;
2558 if (td->verbose_level) {
2559 g_print ("\nSEQ POINT MAP FOR %s: \n", td->method->name);
2561 for (i = 0; i < td->seq_points->len; ++i) {
2562 SeqPoint *sp = (SeqPoint*)g_ptr_array_index (td->seq_points, i);
2563 GSList *l;
2565 if (!next [i])
2566 continue;
2568 g_print ("\tIL0x%x[0x%0x] ->", sp->il_offset, sp->native_offset);
2569 for (l = next [i]; l; l = l->next) {
2570 int next_index = GPOINTER_TO_UINT (l->data);
2571 g_print (" IL0x%x", ((SeqPoint*)g_ptr_array_index (td->seq_points, next_index))->il_offset);
2573 g_print ("\n");
2577 info = mono_seq_point_info_new (array->len, TRUE, array->data, TRUE, &seq_info_size);
2578 mono_atomic_fetch_add_i32 (&mono_jit_stats.allocated_seq_points_size, seq_info_size);
2580 g_byte_array_free (array, TRUE);
2582 jinfo->seq_points = info;
2585 #define BARRIER_IF_VOLATILE(td) \
2586 do { \
2587 if (volatile_) { \
2588 interp_add_ins (td, MINT_MONO_MEMORY_BARRIER); \
2589 volatile_ = FALSE; \
2591 } while (0)
2593 #define INLINE_FAILURE \
2594 do { \
2595 if (td->method != method) \
2596 goto exit; \
2597 } while (0)
2599 static void
2600 interp_method_compute_offsets (InterpMethod *imethod, MonoMethodSignature *signature, MonoMethodHeader *header)
2602 int i, offset, size, align;
2604 imethod->local_offsets = (guint32*)g_malloc (header->num_locals * sizeof(guint32));
2605 offset = 0;
2606 for (i = 0; i < header->num_locals; ++i) {
2607 size = mono_type_size (header->locals [i], &align);
2608 offset += align - 1;
2609 offset &= ~(align - 1);
2610 imethod->local_offsets [i] = offset;
2611 offset += size;
2613 offset = (offset + 7) & ~7;
2615 imethod->exvar_offsets = (guint32*)g_malloc (header->num_clauses * sizeof (guint32));
2616 for (i = 0; i < header->num_clauses; i++) {
2617 imethod->exvar_offsets [i] = offset;
2618 offset += sizeof (MonoObject*);
2620 offset = (offset + 7) & ~7;
2622 imethod->locals_size = offset;
2623 g_assert (imethod->locals_size < 65536);
2626 static MonoType*
2627 get_arg_type (MonoMethodSignature *signature, int arg_n)
2629 if (signature->hasthis && arg_n == 0)
2630 return mono_get_object_type ();
2631 return signature->params [arg_n - !!signature->hasthis];
2634 static void
2635 init_bb_start (TransformData *td, MonoMethodHeader *header)
2637 const unsigned char *ip, *end;
2638 const MonoOpcode *opcode;
2639 int offset, i, in, backwards;
2641 /* intern the strings in the method. */
2642 ip = header->code;
2643 end = ip + header->code_size;
2645 td->is_bb_start [0] = 1;
2646 while (ip < end) {
2647 in = *ip;
2648 if (in == 0xfe) {
2649 ip++;
2650 in = *ip + 256;
2652 else if (in == 0xf0) {
2653 ip++;
2654 in = *ip + MONO_CEE_MONO_ICALL;
2656 opcode = &mono_opcodes [in];
2657 switch (opcode->argument) {
2658 case MonoInlineNone:
2659 ++ip;
2660 break;
2661 case MonoInlineString:
2662 ip += 5;
2663 break;
2664 case MonoInlineType:
2665 ip += 5;
2666 break;
2667 case MonoInlineMethod:
2668 ip += 5;
2669 break;
2670 case MonoInlineField:
2671 case MonoInlineSig:
2672 case MonoInlineI:
2673 case MonoInlineTok:
2674 case MonoShortInlineR:
2675 ip += 5;
2676 break;
2677 case MonoInlineBrTarget:
2678 offset = read32 (ip + 1);
2679 ip += 5;
2680 backwards = offset < 0;
2681 offset += ip - header->code;
2682 g_assert (offset >= 0 && offset < header->code_size);
2683 td->is_bb_start [offset] |= backwards ? 2 : 1;
2684 break;
2685 case MonoShortInlineBrTarget:
2686 offset = ((gint8 *)ip) [1];
2687 ip += 2;
2688 backwards = offset < 0;
2689 offset += ip - header->code;
2690 g_assert (offset >= 0 && offset < header->code_size);
2691 td->is_bb_start [offset] |= backwards ? 2 : 1;
2692 break;
2693 case MonoInlineVar:
2694 ip += 3;
2695 break;
2696 case MonoShortInlineVar:
2697 case MonoShortInlineI:
2698 ip += 2;
2699 break;
2700 case MonoInlineSwitch: {
2701 guint32 n;
2702 const unsigned char *next_ip;
2703 ++ip;
2704 n = read32 (ip);
2705 ip += 4;
2706 next_ip = ip + 4 * n;
2707 for (i = 0; i < n; i++) {
2708 offset = read32 (ip);
2709 backwards = offset < 0;
2710 offset += next_ip - header->code;
2711 g_assert (offset >= 0 && offset < header->code_size);
2712 td->is_bb_start [offset] |= backwards ? 2 : 1;
2713 ip += 4;
2715 break;
2717 case MonoInlineR:
2718 case MonoInlineI8:
2719 ip += 9;
2720 break;
2721 default:
2722 g_assert_not_reached ();
2727 #ifdef NO_UNALIGNED_ACCESS
2728 static int
2729 get_unaligned_opcode (int opcode)
2731 switch (opcode) {
2732 case MINT_LDFLD_I8:
2733 return MINT_LDFLD_I8_UNALIGNED;
2734 case MINT_LDFLD_R8:
2735 return MINT_LDFLD_R8_UNALIGNED;
2736 case MINT_STFLD_I8:
2737 return MINT_STFLD_I8_UNALIGNED;
2738 case MINT_STFLD_R8:
2739 return MINT_STFLD_R8_UNALIGNED;
2740 default:
2741 g_assert_not_reached ();
2743 return -1;
2745 #endif
2747 static void
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);
2756 else
2757 interp_add_ins (td, isinst_instr ? MINT_ISINST : MINT_CASTCLASS);
2758 } else {
2759 interp_add_ins (td, isinst_instr ? MINT_ISINST : MINT_CASTCLASS);
2761 td->last_ins->data [0] = get_data_item_index (td, klass);
2762 td->ip += 5;
2765 static void
2766 interp_emit_ldobj (TransformData *td, MonoClass *klass)
2768 int mt = mint_type (m_class_get_byval_arg (klass));
2769 int size;
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);
2775 PUSH_VT (td, size);
2776 } else {
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);
2784 static void
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) {
2790 int size;
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);
2794 POP_VT (td, size);
2795 } else {
2796 int opcode;
2797 switch (mt) {
2798 case MINT_TYPE_I1:
2799 case MINT_TYPE_U1:
2800 opcode = MINT_STIND_I1;
2801 break;
2802 case MINT_TYPE_I2:
2803 case MINT_TYPE_U2:
2804 opcode = MINT_STIND_I2;
2805 break;
2806 case MINT_TYPE_I4:
2807 opcode = MINT_STIND_I4;
2808 break;
2809 case MINT_TYPE_I8:
2810 opcode = MINT_STIND_I8;
2811 break;
2812 case MINT_TYPE_R4:
2813 opcode = MINT_STIND_R4;
2814 break;
2815 case MINT_TYPE_R8:
2816 opcode = MINT_STIND_R8;
2817 break;
2818 case MINT_TYPE_O:
2819 opcode = MINT_STIND_REF;
2820 break;
2821 default: g_assert_not_reached (); break;
2823 interp_add_ins (td, opcode);
2825 td->sp -= 2;
2828 static void
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)) {
2837 guint32 offset;
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);
2843 g_assert (offset);
2845 interp_add_ins (td, MINT_LDSSFLDA);
2846 WRITE32_INS(td->last_ins, 0, &offset);
2847 } else {
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);
2854 static void
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)) {
2863 guint32 offset;
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);
2869 g_assert (offset);
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);
2876 } else {
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);
2883 } else {
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);
2889 } else {
2890 if (is_load)
2891 interp_add_ins (td, (mt == MINT_TYPE_VT) ? MINT_LDSFLD_VT : (MINT_LDSFLD_I1 + mt - MINT_TYPE_I1));
2892 else
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);
2905 static gboolean
2906 generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, MonoGenericContext *generic_context, MonoError *error)
2908 int target;
2909 int offset, mt, i, i32;
2910 guint32 token;
2911 int in_offset;
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;
2919 MonoClass *klass;
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;
2932 original_bb = bb = mono_basic_block_split (method, error, header);
2933 goto_if_nok (error, exit);
2934 g_assert (bb);
2936 td->il_code = header->code;
2937 td->in_start = td->ip = header->code;
2938 end = td->ip + header->code_size;
2939 td->stack_state = (StackInfo**)g_malloc0(header->code_size * sizeof(StackInfo *));
2940 td->stack_height = (int*)g_malloc(header->code_size * sizeof(int));
2941 td->vt_stack_size = (int*)g_malloc(header->code_size * sizeof(int));
2942 td->clause_indexes = (int*)g_malloc (header->code_size * sizeof (int));
2943 td->is_bb_start = (guint8*)g_malloc0(header->code_size);
2945 init_bb_start (td, header);
2947 for (i = 0; i < header->code_size; i++) {
2948 td->stack_height [i] = -1;
2949 td->clause_indexes [i] = -1;
2952 for (i = 0; i < header->num_clauses; i++) {
2953 MonoExceptionClause *c = header->clauses + i;
2954 td->stack_height [c->handler_offset] = 0;
2955 td->vt_stack_size [c->handler_offset] = 0;
2956 td->is_bb_start [c->handler_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 && td->method == method) {
2981 MonoDebugMethodInfo *minfo;
2982 get_basic_blocks (td);
2984 minfo = mono_debug_lookup_method (method);
2986 if (minfo) {
2987 MonoSymSeqPoint *sps;
2988 int i, n_il_offsets;
2990 mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
2991 // FIXME: Free
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);
2999 g_free (sps);
3001 MonoDebugMethodAsyncInfo* asyncMethod = mono_debug_lookup_method_async_debug_info (method);
3002 if (asyncMethod) {
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);
3024 if (method == td->method) {
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);
3030 g_free (tmp);
3031 g_free (name);
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);
3045 } else {
3046 int offset;
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;
3076 td->in_start = td->ip;
3077 InterpInst *prev_last_ins = td->last_ins;
3079 if (td->stack_height [in_offset] >= 0) {
3080 g_assert (td->is_bb_start [in_offset]);
3081 if (td->stack_height [in_offset] > 0)
3082 memcpy (td->stack, td->stack_state [in_offset], td->stack_height [in_offset] * sizeof(td->stack [0]));
3083 td->sp = td->stack + td->stack_height [in_offset];
3084 td->vt_sp = td->vt_stack_size [in_offset];
3087 if (in_offset == bb->end)
3088 bb = bb->next;
3090 if (bb->dead) {
3091 int op_size = mono_opcode_size (td->ip, end);
3092 g_assert (op_size > 0); /* The BB formation pass must catch all bad ops */
3094 if (td->verbose_level > 1)
3095 g_print ("SKIPPING DEAD OP at %x\n", in_offset);
3097 td->ip += op_size;
3098 continue;
3101 if (td->verbose_level > 1) {
3102 g_print ("IL_%04lx %s %-10s, sp %ld, %s %-12s vt_sp %u (max %u)\n",
3103 td->ip - td->il_code,
3104 td->is_bb_start [td->ip - td->il_code] == 3 ? "<>" :
3105 td->is_bb_start [td->ip - td->il_code] == 2 ? "< " :
3106 td->is_bb_start [td->ip - td->il_code] == 1 ? " >" : " ",
3107 mono_opcode_name (*td->ip), td->sp - td->stack,
3108 td->sp > td->stack ? stack_type_string [td->sp [-1].type] : " ",
3109 (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)) : "",
3110 td->vt_sp, td->max_vt_sp);
3113 if (sym_seq_points && mono_bitset_test_fast (seq_point_locs, td->ip - header->code)) {
3114 InterpBasicBlock *cbb = td->offset_to_bb [td->ip - header->code];
3115 g_assert (cbb);
3118 * Make methods interruptable at the beginning, and at the targets of
3119 * backward branches.
3121 if (in_offset == 0 || g_slist_length (cbb->preds) > 1)
3122 interp_add_ins (td, MINT_SDB_INTR_LOC);
3124 last_seq_point = interp_add_ins (td, MINT_SDB_SEQ_POINT);
3127 if (td->is_bb_start [in_offset]) {
3128 int index = td->clause_indexes [in_offset];
3129 if (index != -1) {
3130 MonoExceptionClause *clause = &header->clauses [index];
3131 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
3132 clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) &&
3133 in_offset == clause->handler_offset)
3134 interp_add_ins (td, MINT_START_ABORT_PROT);
3138 switch (*td->ip) {
3139 case CEE_NOP:
3140 /* lose it */
3141 emitted_funccall_seq_point = FALSE;
3142 ++td->ip;
3143 break;
3144 case CEE_BREAK:
3145 SIMPLE_OP(td, MINT_BREAK);
3146 break;
3147 case CEE_LDARG_0:
3148 case CEE_LDARG_1:
3149 case CEE_LDARG_2:
3150 case CEE_LDARG_3: {
3151 int arg_n = *td->ip - CEE_LDARG_0;
3152 if (td->method == method)
3153 load_arg (td, arg_n);
3154 else
3155 load_local_general (td, arg_offsets [arg_n], get_arg_type (signature, arg_n));
3156 ++td->ip;
3157 break;
3159 case CEE_LDLOC_0:
3160 case CEE_LDLOC_1:
3161 case CEE_LDLOC_2:
3162 case CEE_LDLOC_3: {
3163 int loc_n = *td->ip - CEE_LDLOC_0;
3164 if (td->method == method)
3165 load_local (td, loc_n);
3166 else
3167 load_local_general (td, local_offsets [loc_n], header->locals [loc_n]);
3168 ++td->ip;
3169 break;
3171 case CEE_STLOC_0:
3172 case CEE_STLOC_1:
3173 case CEE_STLOC_2:
3174 case CEE_STLOC_3: {
3175 int loc_n = *td->ip - CEE_STLOC_0;
3176 if (td->method == method)
3177 store_local (td, loc_n);
3178 else
3179 store_local_general (td, local_offsets [loc_n], header->locals [loc_n]);
3180 ++td->ip;
3181 break;
3183 case CEE_LDARG_S: {
3184 int arg_n = ((guint8 *)td->ip)[1];
3185 if (td->method == method)
3186 load_arg (td, arg_n);
3187 else
3188 load_local_general (td, arg_offsets [arg_n], get_arg_type (signature, arg_n));
3189 td->ip += 2;
3190 break;
3192 case CEE_LDARGA_S: {
3193 /* NOTE: n includes this */
3194 int n = ((guint8 *) td->ip) [1];
3196 if (td->method == method) {
3197 get_arg_type_exact (td, n, &mt);
3198 interp_add_ins (td, mt == MINT_TYPE_VT ? MINT_LDARGA_VT : MINT_LDARGA);
3199 td->last_ins->data [0] = n;
3200 } else {
3201 interp_add_ins (td, MINT_LDLOCA_S);
3202 td->last_ins->data [0] = arg_offsets [n];
3204 PUSH_SIMPLE_TYPE(td, STACK_TYPE_MP);
3205 td->ip += 2;
3206 break;
3208 case CEE_STARG_S: {
3209 int arg_n = ((guint8 *)td->ip)[1];
3210 if (td->method == method)
3211 store_arg (td, arg_n);
3212 else
3213 store_local_general (td, arg_offsets [arg_n], get_arg_type (signature, arg_n));
3214 td->ip += 2;
3215 break;
3217 case CEE_LDLOC_S: {
3218 int loc_n = ((guint8 *)td->ip)[1];
3219 if (td->method == method)
3220 load_local (td, loc_n);
3221 else
3222 load_local_general (td, local_offsets [loc_n], header->locals [loc_n]);
3223 td->ip += 2;
3224 break;
3226 case CEE_LDLOCA_S: {
3227 int loc_n = ((guint8 *)td->ip)[1];
3228 interp_add_ins (td, MINT_LDLOCA_S);
3229 if (td->method == method)
3230 td->last_ins->data [0] = td->rtm->local_offsets [loc_n];
3231 else
3232 td->last_ins->data [0] = local_offsets [loc_n];
3233 PUSH_SIMPLE_TYPE(td, STACK_TYPE_MP);
3234 td->ip += 2;
3235 break;
3237 case CEE_STLOC_S: {
3238 int loc_n = ((guint8 *)td->ip)[1];
3239 if (td->method == method)
3240 store_local (td, loc_n);
3241 else
3242 store_local_general (td, local_offsets [loc_n], header->locals [loc_n]);
3243 td->ip += 2;
3244 break;
3246 case CEE_LDNULL:
3247 SIMPLE_OP(td, MINT_LDNULL);
3248 PUSH_TYPE(td, STACK_TYPE_O, NULL);
3249 break;
3250 case CEE_LDC_I4_M1:
3251 SIMPLE_OP(td, MINT_LDC_I4_M1);
3252 PUSH_SIMPLE_TYPE(td, STACK_TYPE_I4);
3253 break;
3254 case CEE_LDC_I4_0:
3255 if (!td->is_bb_start[td->ip + 1 - td->il_code] && td->ip [1] == 0xfe && td->ip [2] == CEE_CEQ &&
3256 td->sp > td->stack && td->sp [-1].type == STACK_TYPE_I4) {
3257 SIMPLE_OP(td, MINT_CEQ0_I4);
3258 td->ip += 2;
3259 } else {
3260 SIMPLE_OP(td, MINT_LDC_I4_0);
3261 PUSH_SIMPLE_TYPE(td, STACK_TYPE_I4);
3263 break;
3264 case CEE_LDC_I4_1:
3265 if (!td->is_bb_start[td->ip + 1 - td->il_code] &&
3266 (td->ip [1] == CEE_ADD || td->ip [1] == CEE_SUB) && td->sp [-1].type == STACK_TYPE_I4) {
3267 interp_add_ins (td, td->ip [1] == CEE_ADD ? MINT_ADD1_I4 : MINT_SUB1_I4);
3268 td->ip += 2;
3269 } else {
3270 SIMPLE_OP(td, MINT_LDC_I4_1);
3271 PUSH_SIMPLE_TYPE(td, STACK_TYPE_I4);
3273 break;
3274 case CEE_LDC_I4_2:
3275 case CEE_LDC_I4_3:
3276 case CEE_LDC_I4_4:
3277 case CEE_LDC_I4_5:
3278 case CEE_LDC_I4_6:
3279 case CEE_LDC_I4_7:
3280 case CEE_LDC_I4_8:
3281 SIMPLE_OP(td, (*td->ip - CEE_LDC_I4_0) + MINT_LDC_I4_0);
3282 PUSH_SIMPLE_TYPE(td, STACK_TYPE_I4);
3283 break;
3284 case CEE_LDC_I4_S:
3285 interp_add_ins (td, MINT_LDC_I4_S);
3286 td->last_ins->data [0] = ((gint8 *) td->ip) [1];
3287 td->ip += 2;
3288 PUSH_SIMPLE_TYPE(td, STACK_TYPE_I4);
3289 break;
3290 case CEE_LDC_I4:
3291 i32 = read32 (td->ip + 1);
3292 interp_add_ins (td, MINT_LDC_I4);
3293 WRITE32_INS (td->last_ins, 0, &i32);
3294 td->ip += 5;
3295 PUSH_SIMPLE_TYPE(td, STACK_TYPE_I4);
3296 break;
3297 case CEE_LDC_I8: {
3298 gint64 val = read64 (td->ip + 1);
3299 interp_add_ins (td, MINT_LDC_I8);
3300 WRITE64_INS (td->last_ins, 0, &val);
3301 td->ip += 9;
3302 PUSH_SIMPLE_TYPE(td, STACK_TYPE_I8);
3303 break;
3305 case CEE_LDC_R4: {
3306 float val;
3307 readr4 (td->ip + 1, &val);
3308 interp_add_ins (td, MINT_LDC_R4);
3309 WRITE32_INS (td->last_ins, 0, &val);
3310 td->ip += 5;
3311 PUSH_SIMPLE_TYPE(td, STACK_TYPE_R4);
3312 break;
3314 case CEE_LDC_R8: {
3315 double val;
3316 readr8 (td->ip + 1, &val);
3317 interp_add_ins (td, MINT_LDC_R8);
3318 WRITE64_INS (td->last_ins, 0, &val);
3319 td->ip += 9;
3320 PUSH_SIMPLE_TYPE(td, STACK_TYPE_R8);
3321 break;
3323 case CEE_DUP: {
3324 int type = td->sp [-1].type;
3325 MonoClass *klass = td->sp [-1].klass;
3326 if (td->sp [-1].type == STACK_TYPE_VT) {
3327 gint32 size = mono_class_value_size (klass, NULL);
3328 PUSH_VT(td, size);
3329 interp_add_ins (td, MINT_DUP_VT);
3330 WRITE32_INS (td->last_ins, 0, &size);
3331 td->ip ++;
3332 } else
3333 SIMPLE_OP(td, MINT_DUP);
3334 PUSH_TYPE(td, type, klass);
3335 break;
3337 case CEE_POP:
3338 CHECK_STACK(td, 1);
3339 SIMPLE_OP(td, MINT_POP);
3340 td->last_ins->data [0] = 0;
3341 if (td->sp [-1].type == STACK_TYPE_VT) {
3342 int size = mono_class_value_size (td->sp [-1].klass, NULL);
3343 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
3344 interp_add_ins (td, MINT_VTRESULT);
3345 td->last_ins->data [0] = 0;
3346 WRITE32_INS (td->last_ins, 1, &size);
3347 td->vt_sp -= size;
3349 --td->sp;
3350 break;
3351 case CEE_JMP: {
3352 MonoMethod *m;
3353 INLINE_FAILURE;
3354 if (td->sp > td->stack)
3355 g_warning ("CEE_JMP: stack must be empty");
3356 token = read32 (td->ip + 1);
3357 m = mono_get_method_checked (image, token, NULL, generic_context, error);
3358 goto_if_nok (error, exit);
3359 interp_add_ins (td, MINT_JMP);
3360 td->last_ins->data [0] = get_data_item_index (td, mono_interp_get_imethod (domain, m, error));
3361 goto_if_nok (error, exit);
3362 td->ip += 5;
3363 break;
3365 case CEE_CALLVIRT: /* Fall through */
3366 case CEE_CALLI: /* Fall through */
3367 case CEE_CALL: {
3368 gboolean need_seq_point = FALSE;
3370 if (sym_seq_points && !mono_bitset_test_fast (seq_point_locs, td->ip + 5 - header->code))
3371 need_seq_point = TRUE;
3373 if (!interp_transform_call (td, method, NULL, domain, generic_context, td->is_bb_start, constrained_class, readonly, error, TRUE, save_last_error))
3374 goto exit;
3376 if (need_seq_point) {
3377 //check is is a nested call and remove the MONO_INST_NONEMPTY_STACK of the last breakpoint, only for non native methods
3378 if (!(method->flags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
3379 if (emitted_funccall_seq_point) {
3380 if (last_seq_point)
3381 last_seq_point->flags |= INTERP_INST_FLAG_SEQ_POINT_NESTED_CALL;
3383 else
3384 emitted_funccall_seq_point = TRUE;
3386 last_seq_point = interp_add_ins (td, MINT_SDB_SEQ_POINT);
3387 // This seq point is actually associated with the instruction following the call
3388 last_seq_point->il_offset = td->ip - header->code;
3389 last_seq_point->flags = INTERP_INST_FLAG_SEQ_POINT_NONEMPTY_STACK;
3392 constrained_class = NULL;
3393 readonly = FALSE;
3394 save_last_error = FALSE;
3395 break;
3397 case CEE_RET: {
3398 /* Return from inlined method, return value is on top of stack */
3399 if (td->method != method) {
3400 td->ip++;
3401 break;
3404 int vt_size = 0;
3405 MonoType *ult = mini_type_get_underlying_type (signature->ret);
3406 if (ult->type != MONO_TYPE_VOID) {
3407 CHECK_STACK (td, 1);
3408 --td->sp;
3409 if (mint_type (ult) == MINT_TYPE_VT) {
3410 MonoClass *klass = mono_class_from_mono_type_internal (ult);
3411 vt_size = mono_class_value_size (klass, NULL);
3414 if (td->sp > td->stack) {
3415 mono_error_set_generic_error (error, "System", "InvalidProgramException", "");
3416 goto exit;
3418 if (td->vt_sp != ALIGN_TO (vt_size, MINT_VT_ALIGNMENT))
3419 g_error ("%s: CEE_RET: value type stack: %d vs. %d", mono_method_full_name (td->method, TRUE), td->vt_sp, vt_size);
3421 if (sym_seq_points) {
3422 last_seq_point = interp_add_ins (td, MINT_SDB_SEQ_POINT);
3423 td->last_ins->flags = INTERP_INST_FLAG_SEQ_POINT_METHOD_EXIT;
3426 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
3427 /* This does the return as well */
3428 interp_add_ins (td, MINT_TRACE_EXIT);
3429 if (ult->type == MONO_TYPE_VOID)
3430 vt_size = -1;
3431 WRITE32_INS (td->last_ins, 0, &vt_size);
3432 ++td->ip;
3433 } else {
3434 if (vt_size == 0)
3435 SIMPLE_OP(td, ult->type == MONO_TYPE_VOID ? MINT_RET_VOID : MINT_RET);
3436 else {
3437 interp_add_ins (td, MINT_RET_VT);
3438 WRITE32_INS (td->last_ins, 0, &vt_size);
3439 ++td->ip;
3442 break;
3444 case CEE_BR: {
3445 int offset = read32 (td->ip + 1);
3446 if (offset) {
3447 INLINE_FAILURE;
3448 handle_branch (td, MINT_BR_S, MINT_BR, 5 + offset);
3450 td->ip += 5;
3451 break;
3453 case CEE_BR_S: {
3454 int offset = (gint8)td->ip [1];
3455 if (offset) {
3456 INLINE_FAILURE;
3457 handle_branch (td, MINT_BR_S, MINT_BR, 2 + (gint8)td->ip [1]);
3459 td->ip += 2;
3460 break;
3462 case CEE_BRFALSE:
3463 INLINE_FAILURE;
3464 one_arg_branch (td, MINT_BRFALSE_I4, 5 + read32 (td->ip + 1));
3465 td->ip += 5;
3466 break;
3467 case CEE_BRFALSE_S:
3468 INLINE_FAILURE;
3469 one_arg_branch (td, MINT_BRFALSE_I4, 2 + (gint8)td->ip [1]);
3470 td->ip += 2;
3471 break;
3472 case CEE_BRTRUE:
3473 INLINE_FAILURE;
3474 one_arg_branch (td, MINT_BRTRUE_I4, 5 + read32 (td->ip + 1));
3475 td->ip += 5;
3476 break;
3477 case CEE_BRTRUE_S:
3478 INLINE_FAILURE;
3479 one_arg_branch (td, MINT_BRTRUE_I4, 2 + (gint8)td->ip [1]);
3480 td->ip += 2;
3481 break;
3482 case CEE_BEQ:
3483 INLINE_FAILURE;
3484 two_arg_branch (td, MINT_BEQ_I4, 5 + read32 (td->ip + 1));
3485 td->ip += 5;
3486 break;
3487 case CEE_BEQ_S:
3488 INLINE_FAILURE;
3489 two_arg_branch (td, MINT_BEQ_I4, 2 + (gint8) td->ip [1]);
3490 td->ip += 2;
3491 break;
3492 case CEE_BGE:
3493 INLINE_FAILURE;
3494 two_arg_branch (td, MINT_BGE_I4, 5 + read32 (td->ip + 1));
3495 td->ip += 5;
3496 break;
3497 case CEE_BGE_S:
3498 INLINE_FAILURE;
3499 two_arg_branch (td, MINT_BGE_I4, 2 + (gint8) td->ip [1]);
3500 td->ip += 2;
3501 break;
3502 case CEE_BGT:
3503 INLINE_FAILURE;
3504 two_arg_branch (td, MINT_BGT_I4, 5 + read32 (td->ip + 1));
3505 td->ip += 5;
3506 break;
3507 case CEE_BGT_S:
3508 INLINE_FAILURE;
3509 two_arg_branch (td, MINT_BGT_I4, 2 + (gint8) td->ip [1]);
3510 td->ip += 2;
3511 break;
3512 case CEE_BLT:
3513 INLINE_FAILURE;
3514 two_arg_branch (td, MINT_BLT_I4, 5 + read32 (td->ip + 1));
3515 td->ip += 5;
3516 break;
3517 case CEE_BLT_S:
3518 INLINE_FAILURE;
3519 two_arg_branch (td, MINT_BLT_I4, 2 + (gint8) td->ip [1]);
3520 td->ip += 2;
3521 break;
3522 case CEE_BLE:
3523 INLINE_FAILURE;
3524 two_arg_branch (td, MINT_BLE_I4, 5 + read32 (td->ip + 1));
3525 td->ip += 5;
3526 break;
3527 case CEE_BLE_S:
3528 INLINE_FAILURE;
3529 two_arg_branch (td, MINT_BLE_I4, 2 + (gint8) td->ip [1]);
3530 td->ip += 2;
3531 break;
3532 case CEE_BNE_UN:
3533 INLINE_FAILURE;
3534 two_arg_branch (td, MINT_BNE_UN_I4, 5 + read32 (td->ip + 1));
3535 td->ip += 5;
3536 break;
3537 case CEE_BNE_UN_S:
3538 INLINE_FAILURE;
3539 two_arg_branch (td, MINT_BNE_UN_I4, 2 + (gint8) td->ip [1]);
3540 td->ip += 2;
3541 break;
3542 case CEE_BGE_UN:
3543 INLINE_FAILURE;
3544 two_arg_branch (td, MINT_BGE_UN_I4, 5 + read32 (td->ip + 1));
3545 td->ip += 5;
3546 break;
3547 case CEE_BGE_UN_S:
3548 INLINE_FAILURE;
3549 two_arg_branch (td, MINT_BGE_UN_I4, 2 + (gint8) td->ip [1]);
3550 td->ip += 2;
3551 break;
3552 case CEE_BGT_UN:
3553 INLINE_FAILURE;
3554 two_arg_branch (td, MINT_BGT_UN_I4, 5 + read32 (td->ip + 1));
3555 td->ip += 5;
3556 break;
3557 case CEE_BGT_UN_S:
3558 INLINE_FAILURE;
3559 two_arg_branch (td, MINT_BGT_UN_I4, 2 + (gint8) td->ip [1]);
3560 td->ip += 2;
3561 break;
3562 case CEE_BLE_UN:
3563 INLINE_FAILURE;
3564 two_arg_branch (td, MINT_BLE_UN_I4, 5 + read32 (td->ip + 1));
3565 td->ip += 5;
3566 break;
3567 case CEE_BLE_UN_S:
3568 INLINE_FAILURE;
3569 two_arg_branch (td, MINT_BLE_UN_I4, 2 + (gint8) td->ip [1]);
3570 td->ip += 2;
3571 break;
3572 case CEE_BLT_UN:
3573 INLINE_FAILURE;
3574 two_arg_branch (td, MINT_BLT_UN_I4, 5 + read32 (td->ip + 1));
3575 td->ip += 5;
3576 break;
3577 case CEE_BLT_UN_S:
3578 INLINE_FAILURE;
3579 two_arg_branch (td, MINT_BLT_UN_I4, 2 + (gint8) td->ip [1]);
3580 td->ip += 2;
3581 break;
3582 case CEE_SWITCH: {
3583 INLINE_FAILURE;
3584 guint32 n;
3585 const unsigned char *next_ip;
3586 ++td->ip;
3587 n = read32 (td->ip);
3588 interp_add_ins_explicit (td, MINT_SWITCH, MINT_SWITCH_LEN (n));
3589 WRITE32_INS (td->last_ins, 0, &n);
3590 td->ip += 4;
3591 next_ip = td->ip + n * 4;
3592 --td->sp;
3593 int stack_height = td->sp - td->stack;
3594 for (i = 0; i < n; i++) {
3595 offset = read32 (td->ip);
3596 target = next_ip - td->il_code + offset;
3597 if (offset < 0) {
3598 #if DEBUG_INTERP
3599 if (stack_height > 0 && stack_height != td->stack_height [target])
3600 g_warning ("SWITCH with back branch and non-empty stack");
3601 #endif
3602 } else {
3603 td->stack_height [target] = stack_height;
3604 td->vt_stack_size [target] = td->vt_sp;
3605 if (stack_height > 0)
3606 td->stack_state [target] = (StackInfo*)g_memdup (td->stack, stack_height * sizeof (td->stack [0]));
3608 WRITE32_INS (td->last_ins, 2 + i * 2, &target);
3609 td->ip += 4;
3611 break;
3613 case CEE_LDIND_I1:
3614 CHECK_STACK (td, 1);
3615 SIMPLE_OP (td, MINT_LDIND_I1_CHECK);
3616 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
3617 BARRIER_IF_VOLATILE (td);
3618 break;
3619 case CEE_LDIND_U1:
3620 CHECK_STACK (td, 1);
3621 SIMPLE_OP (td, MINT_LDIND_U1_CHECK);
3622 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
3623 BARRIER_IF_VOLATILE (td);
3624 break;
3625 case CEE_LDIND_I2:
3626 CHECK_STACK (td, 1);
3627 SIMPLE_OP (td, MINT_LDIND_I2_CHECK);
3628 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
3629 BARRIER_IF_VOLATILE (td);
3630 break;
3631 case CEE_LDIND_U2:
3632 CHECK_STACK (td, 1);
3633 SIMPLE_OP (td, MINT_LDIND_U2_CHECK);
3634 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
3635 BARRIER_IF_VOLATILE (td);
3636 break;
3637 case CEE_LDIND_I4:
3638 CHECK_STACK (td, 1);
3639 SIMPLE_OP (td, MINT_LDIND_I4_CHECK);
3640 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
3641 BARRIER_IF_VOLATILE (td);
3642 break;
3643 case CEE_LDIND_U4:
3644 CHECK_STACK (td, 1);
3645 SIMPLE_OP (td, MINT_LDIND_U4_CHECK);
3646 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
3647 BARRIER_IF_VOLATILE (td);
3648 break;
3649 case CEE_LDIND_I8:
3650 CHECK_STACK (td, 1);
3651 SIMPLE_OP (td, MINT_LDIND_I8_CHECK);
3652 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8);
3653 BARRIER_IF_VOLATILE (td);
3654 break;
3655 case CEE_LDIND_I:
3656 CHECK_STACK (td, 1);
3657 SIMPLE_OP (td, MINT_LDIND_REF_CHECK);
3658 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I);
3659 BARRIER_IF_VOLATILE (td);
3660 break;
3661 case CEE_LDIND_R4:
3662 CHECK_STACK (td, 1);
3663 SIMPLE_OP (td, MINT_LDIND_R4_CHECK);
3664 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R4);
3665 BARRIER_IF_VOLATILE (td);
3666 break;
3667 case CEE_LDIND_R8:
3668 CHECK_STACK (td, 1);
3669 SIMPLE_OP (td, MINT_LDIND_R8_CHECK);
3670 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R8);
3671 BARRIER_IF_VOLATILE (td);
3672 break;
3673 case CEE_LDIND_REF:
3674 CHECK_STACK (td, 1);
3675 SIMPLE_OP (td, MINT_LDIND_REF_CHECK);
3676 BARRIER_IF_VOLATILE (td);
3677 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_O);
3678 break;
3679 case CEE_STIND_REF:
3680 CHECK_STACK (td, 2);
3681 BARRIER_IF_VOLATILE (td);
3682 SIMPLE_OP (td, MINT_STIND_REF);
3683 td->sp -= 2;
3684 break;
3685 case CEE_STIND_I1:
3686 CHECK_STACK (td, 2);
3687 BARRIER_IF_VOLATILE (td);
3688 SIMPLE_OP (td, MINT_STIND_I1);
3689 td->sp -= 2;
3690 break;
3691 case CEE_STIND_I2:
3692 CHECK_STACK (td, 2);
3693 BARRIER_IF_VOLATILE (td);
3694 SIMPLE_OP (td, MINT_STIND_I2);
3695 td->sp -= 2;
3696 break;
3697 case CEE_STIND_I4:
3698 CHECK_STACK (td, 2);
3699 BARRIER_IF_VOLATILE (td);
3700 SIMPLE_OP (td, MINT_STIND_I4);
3701 td->sp -= 2;
3702 break;
3703 case CEE_STIND_I:
3704 CHECK_STACK (td, 2);
3705 BARRIER_IF_VOLATILE (td);
3706 SIMPLE_OP (td, MINT_STIND_I);
3707 td->sp -= 2;
3708 break;
3709 case CEE_STIND_I8:
3710 CHECK_STACK (td, 2);
3711 BARRIER_IF_VOLATILE (td);
3712 SIMPLE_OP (td, MINT_STIND_I8);
3713 td->sp -= 2;
3714 break;
3715 case CEE_STIND_R4:
3716 CHECK_STACK (td, 2);
3717 BARRIER_IF_VOLATILE (td);
3718 SIMPLE_OP (td, MINT_STIND_R4);
3719 td->sp -= 2;
3720 break;
3721 case CEE_STIND_R8:
3722 CHECK_STACK (td, 2);
3723 BARRIER_IF_VOLATILE (td);
3724 SIMPLE_OP (td, MINT_STIND_R8);
3725 td->sp -= 2;
3726 break;
3727 case CEE_ADD:
3728 binary_arith_op(td, MINT_ADD_I4);
3729 ++td->ip;
3730 break;
3731 case CEE_SUB:
3732 binary_arith_op(td, MINT_SUB_I4);
3733 ++td->ip;
3734 break;
3735 case CEE_MUL:
3736 binary_arith_op(td, MINT_MUL_I4);
3737 ++td->ip;
3738 break;
3739 case CEE_DIV:
3740 binary_arith_op(td, MINT_DIV_I4);
3741 ++td->ip;
3742 break;
3743 case CEE_DIV_UN:
3744 binary_arith_op(td, MINT_DIV_UN_I4);
3745 ++td->ip;
3746 break;
3747 case CEE_REM:
3748 binary_arith_op (td, MINT_REM_I4);
3749 ++td->ip;
3750 break;
3751 case CEE_REM_UN:
3752 binary_arith_op (td, MINT_REM_UN_I4);
3753 ++td->ip;
3754 break;
3755 case CEE_AND:
3756 binary_arith_op (td, MINT_AND_I4);
3757 ++td->ip;
3758 break;
3759 case CEE_OR:
3760 binary_arith_op (td, MINT_OR_I4);
3761 ++td->ip;
3762 break;
3763 case CEE_XOR:
3764 binary_arith_op (td, MINT_XOR_I4);
3765 ++td->ip;
3766 break;
3767 case CEE_SHL:
3768 shift_op (td, MINT_SHL_I4);
3769 ++td->ip;
3770 break;
3771 case CEE_SHR:
3772 shift_op (td, MINT_SHR_I4);
3773 ++td->ip;
3774 break;
3775 case CEE_SHR_UN:
3776 shift_op (td, MINT_SHR_UN_I4);
3777 ++td->ip;
3778 break;
3779 case CEE_NEG:
3780 unary_arith_op (td, MINT_NEG_I4);
3781 ++td->ip;
3782 break;
3783 case CEE_NOT:
3784 unary_arith_op (td, MINT_NOT_I4);
3785 ++td->ip;
3786 break;
3787 case CEE_CONV_U1:
3788 CHECK_STACK (td, 1);
3789 switch (td->sp [-1].type) {
3790 case STACK_TYPE_R4:
3791 interp_add_ins (td, MINT_CONV_U1_R4);
3792 break;
3793 case STACK_TYPE_R8:
3794 interp_add_ins (td, MINT_CONV_U1_R8);
3795 break;
3796 case STACK_TYPE_I4:
3797 interp_add_ins (td, MINT_CONV_U1_I4);
3798 break;
3799 case STACK_TYPE_I8:
3800 interp_add_ins (td, MINT_CONV_U1_I8);
3801 break;
3802 default:
3803 g_assert_not_reached ();
3805 ++td->ip;
3806 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
3807 break;
3808 case CEE_CONV_I1:
3809 CHECK_STACK (td, 1);
3810 switch (td->sp [-1].type) {
3811 case STACK_TYPE_R4:
3812 interp_add_ins (td, MINT_CONV_I1_R4);
3813 break;
3814 case STACK_TYPE_R8:
3815 interp_add_ins (td, MINT_CONV_I1_R8);
3816 break;
3817 case STACK_TYPE_I4:
3818 interp_add_ins (td, MINT_CONV_I1_I4);
3819 break;
3820 case STACK_TYPE_I8:
3821 interp_add_ins (td, MINT_CONV_I1_I8);
3822 break;
3823 default:
3824 g_assert_not_reached ();
3826 ++td->ip;
3827 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
3828 break;
3829 case CEE_CONV_U2:
3830 CHECK_STACK (td, 1);
3831 switch (td->sp [-1].type) {
3832 case STACK_TYPE_R4:
3833 interp_add_ins (td, MINT_CONV_U2_R4);
3834 break;
3835 case STACK_TYPE_R8:
3836 interp_add_ins (td, MINT_CONV_U2_R8);
3837 break;
3838 case STACK_TYPE_I4:
3839 interp_add_ins (td, MINT_CONV_U2_I4);
3840 break;
3841 case STACK_TYPE_I8:
3842 interp_add_ins (td, MINT_CONV_U2_I8);
3843 break;
3844 default:
3845 g_assert_not_reached ();
3847 ++td->ip;
3848 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
3849 break;
3850 case CEE_CONV_I2:
3851 CHECK_STACK (td, 1);
3852 switch (td->sp [-1].type) {
3853 case STACK_TYPE_R4:
3854 interp_add_ins (td, MINT_CONV_I2_R4);
3855 break;
3856 case STACK_TYPE_R8:
3857 interp_add_ins (td, MINT_CONV_I2_R8);
3858 break;
3859 case STACK_TYPE_I4:
3860 interp_add_ins (td, MINT_CONV_I2_I4);
3861 break;
3862 case STACK_TYPE_I8:
3863 interp_add_ins (td, MINT_CONV_I2_I8);
3864 break;
3865 default:
3866 g_assert_not_reached ();
3868 ++td->ip;
3869 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
3870 break;
3871 case CEE_CONV_U:
3872 CHECK_STACK (td, 1);
3873 switch (td->sp [-1].type) {
3874 case STACK_TYPE_R8:
3875 #if SIZEOF_VOID_P == 4
3876 interp_add_ins (td, MINT_CONV_U4_R8);
3877 #else
3878 interp_add_ins (td, MINT_CONV_U8_R8);
3879 #endif
3880 break;
3881 case STACK_TYPE_I4:
3882 #if SIZEOF_VOID_P == 8
3883 interp_add_ins (td, MINT_CONV_U8_I4);
3884 #endif
3885 break;
3886 case STACK_TYPE_I8:
3887 #if SIZEOF_VOID_P == 4
3888 interp_add_ins (td, MINT_CONV_U4_I8);
3889 #endif
3890 break;
3891 case STACK_TYPE_MP:
3892 case STACK_TYPE_O:
3893 break;
3894 default:
3895 g_assert_not_reached ();
3897 ++td->ip;
3898 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I);
3899 break;
3900 case CEE_CONV_I:
3901 CHECK_STACK (td, 1);
3902 switch (td->sp [-1].type) {
3903 case STACK_TYPE_R8:
3904 #if SIZEOF_VOID_P == 8
3905 interp_add_ins (td, MINT_CONV_I8_R8);
3906 #else
3907 interp_add_ins (td, MINT_CONV_I4_R8);
3908 #endif
3909 break;
3910 case STACK_TYPE_I4:
3911 #if SIZEOF_VOID_P == 8
3912 interp_add_ins (td, MINT_CONV_I8_I4);
3913 #endif
3914 break;
3915 case STACK_TYPE_O:
3916 break;
3917 case STACK_TYPE_MP:
3918 break;
3919 case STACK_TYPE_I8:
3920 #if SIZEOF_VOID_P == 4
3921 interp_add_ins (td, MINT_CONV_I4_I8);
3922 #endif
3923 break;
3924 default:
3925 g_assert_not_reached ();
3927 ++td->ip;
3928 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I);
3929 break;
3930 case CEE_CONV_U4:
3931 CHECK_STACK (td, 1);
3932 switch (td->sp [-1].type) {
3933 case STACK_TYPE_R4:
3934 interp_add_ins (td, MINT_CONV_U4_R4);
3935 break;
3936 case STACK_TYPE_R8:
3937 interp_add_ins (td, MINT_CONV_U4_R8);
3938 break;
3939 case STACK_TYPE_I4:
3940 break;
3941 case STACK_TYPE_I8:
3942 interp_add_ins (td, MINT_CONV_U4_I8);
3943 break;
3944 case STACK_TYPE_MP:
3945 #if SIZEOF_VOID_P == 8
3946 interp_add_ins (td, MINT_CONV_U4_I8);
3947 #endif
3948 break;
3949 default:
3950 g_assert_not_reached ();
3952 ++td->ip;
3953 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
3954 break;
3955 case CEE_CONV_I4:
3956 CHECK_STACK (td, 1);
3957 switch (td->sp [-1].type) {
3958 case STACK_TYPE_R4:
3959 interp_add_ins (td, MINT_CONV_I4_R4);
3960 break;
3961 case STACK_TYPE_R8:
3962 interp_add_ins (td, MINT_CONV_I4_R8);
3963 break;
3964 case STACK_TYPE_I4:
3965 break;
3966 case STACK_TYPE_I8:
3967 interp_add_ins (td, MINT_CONV_I4_I8);
3968 break;
3969 case STACK_TYPE_MP:
3970 #if SIZEOF_VOID_P == 8
3971 interp_add_ins (td, MINT_CONV_I4_I8);
3972 #endif
3973 break;
3974 default:
3975 g_assert_not_reached ();
3977 ++td->ip;
3978 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
3979 break;
3980 case CEE_CONV_I8:
3981 CHECK_STACK (td, 1);
3982 switch (td->sp [-1].type) {
3983 case STACK_TYPE_R4:
3984 interp_add_ins (td, MINT_CONV_I8_R4);
3985 break;
3986 case STACK_TYPE_R8:
3987 interp_add_ins (td, MINT_CONV_I8_R8);
3988 break;
3989 case STACK_TYPE_I4: {
3990 if (interp_ins_is_ldc (td->last_ins) && !td->is_bb_start [in_offset]) {
3991 gint64 ct = interp_ldc_i4_get_const (td->last_ins);
3992 interp_remove_ins (td, td->last_ins);
3994 interp_add_ins (td, MINT_LDC_I8);
3995 WRITE64_INS (td->last_ins, 0, &ct);
3996 } else {
3997 interp_add_ins (td, MINT_CONV_I8_I4);
3999 break;
4001 case STACK_TYPE_I8:
4002 break;
4003 case STACK_TYPE_MP:
4004 #if SIZEOF_VOID_P == 4
4005 interp_add_ins (td, MINT_CONV_I8_I4);
4006 #endif
4007 break;
4008 default:
4009 g_assert_not_reached ();
4011 ++td->ip;
4012 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8);
4013 break;
4014 case CEE_CONV_R4:
4015 CHECK_STACK (td, 1);
4016 switch (td->sp [-1].type) {
4017 case STACK_TYPE_R8:
4018 interp_add_ins (td, MINT_CONV_R4_R8);
4019 break;
4020 case STACK_TYPE_I8:
4021 interp_add_ins (td, MINT_CONV_R4_I8);
4022 break;
4023 case STACK_TYPE_I4:
4024 interp_add_ins (td, MINT_CONV_R4_I4);
4025 break;
4026 case STACK_TYPE_R4:
4027 /* no-op */
4028 break;
4029 default:
4030 g_assert_not_reached ();
4032 ++td->ip;
4033 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R4);
4034 break;
4035 case CEE_CONV_R8:
4036 CHECK_STACK (td, 1);
4037 switch (td->sp [-1].type) {
4038 case STACK_TYPE_I4:
4039 interp_add_ins (td, MINT_CONV_R8_I4);
4040 break;
4041 case STACK_TYPE_I8:
4042 interp_add_ins (td, MINT_CONV_R8_I8);
4043 break;
4044 case STACK_TYPE_R4:
4045 interp_add_ins (td, MINT_CONV_R8_R4);
4046 break;
4047 case STACK_TYPE_R8:
4048 break;
4049 default:
4050 g_assert_not_reached ();
4052 ++td->ip;
4053 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R8);
4054 break;
4055 case CEE_CONV_U8:
4056 CHECK_STACK (td, 1);
4057 switch (td->sp [-1].type) {
4058 case STACK_TYPE_I4:
4059 if (interp_ins_is_ldc (td->last_ins) && !td->is_bb_start [in_offset]) {
4060 gint64 ct = (guint32)interp_ldc_i4_get_const (td->last_ins);
4061 interp_remove_ins (td, td->last_ins);
4063 interp_add_ins (td, MINT_LDC_I8);
4064 WRITE64_INS (td->last_ins, 0, &ct);
4065 } else {
4066 interp_add_ins (td, MINT_CONV_U8_I4);
4068 break;
4069 case STACK_TYPE_I8:
4070 break;
4071 case STACK_TYPE_R4:
4072 interp_add_ins (td, MINT_CONV_U8_R4);
4073 break;
4074 case STACK_TYPE_R8:
4075 interp_add_ins (td, MINT_CONV_U8_R8);
4076 break;
4077 case STACK_TYPE_MP:
4078 #if SIZEOF_VOID_P == 4
4079 interp_add_ins (td, MINT_CONV_U8_I4);
4080 #endif
4081 break;
4082 default:
4083 g_assert_not_reached ();
4085 ++td->ip;
4086 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8);
4087 break;
4088 case CEE_CPOBJ: {
4089 CHECK_STACK (td, 2);
4091 token = read32 (td->ip + 1);
4092 klass = mono_class_get_and_inflate_typespec_checked (image, token, generic_context, error);
4093 goto_if_nok (error, exit);
4095 if (m_class_is_valuetype (klass)) {
4096 int mt = mint_type (m_class_get_byval_arg (klass));
4097 interp_add_ins (td, (mt == MINT_TYPE_VT) ? MINT_CPOBJ_VT : MINT_CPOBJ);
4098 td->last_ins->data [0] = get_data_item_index(td, klass);
4099 } else {
4100 interp_add_ins (td, MINT_LDIND_REF);
4101 interp_add_ins (td, MINT_STIND_REF);
4103 td->ip += 5;
4104 td->sp -= 2;
4105 break;
4107 case CEE_LDOBJ: {
4108 CHECK_STACK (td, 1);
4110 token = read32 (td->ip + 1);
4112 if (method->wrapper_type != MONO_WRAPPER_NONE)
4113 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
4114 else {
4115 klass = mono_class_get_and_inflate_typespec_checked (image, token, generic_context, error);
4116 goto_if_nok (error, exit);
4119 interp_emit_ldobj (td, klass);
4121 td->ip += 5;
4122 BARRIER_IF_VOLATILE (td);
4123 break;
4125 case CEE_LDSTR: {
4126 token = mono_metadata_token_index (read32 (td->ip + 1));
4127 td->ip += 5;
4128 if (method->wrapper_type == MONO_WRAPPER_NONE) {
4129 MonoString *s = mono_ldstr_checked (domain, image, token, error);
4130 goto_if_nok (error, exit);
4131 /* GC won't scan code stream, but reference is held by metadata
4132 * machinery so we are good here */
4133 interp_add_ins (td, MINT_LDSTR);
4134 td->last_ins->data [0] = get_data_item_index (td, s);
4135 } else {
4136 /* defer allocation to execution-time */
4137 interp_add_ins (td, MINT_LDSTR_TOKEN);
4138 td->last_ins->data [0] = get_data_item_index (td, GUINT_TO_POINTER (token));
4140 PUSH_TYPE(td, STACK_TYPE_O, mono_defaults.string_class);
4141 break;
4143 case CEE_NEWOBJ: {
4144 MonoMethod *m;
4145 MonoMethodSignature *csignature;
4146 guint32 vt_stack_used = 0;
4147 guint32 vt_res_size = 0;
4149 td->ip++;
4150 token = read32 (td->ip);
4151 td->ip += 4;
4153 if (method->wrapper_type != MONO_WRAPPER_NONE)
4154 m = (MonoMethod *)mono_method_get_wrapper_data (method, token);
4155 else {
4156 m = mono_get_method_checked (image, token, NULL, generic_context, error);
4157 goto_if_nok (error, exit);
4160 csignature = mono_method_signature_internal (m);
4161 klass = m->klass;
4163 if (!mono_class_init_internal (klass)) {
4164 mono_error_set_for_class_failure (error, klass);
4165 goto_if_nok (error, exit);
4168 if (mono_class_get_flags (klass) & TYPE_ATTRIBUTE_ABSTRACT) {
4169 char* full_name = mono_type_get_full_name (klass);
4170 mono_error_set_member_access (error, "Cannot create an abstract class: %s", full_name);
4171 g_free (full_name);
4172 goto_if_nok (error, exit);
4175 if (mono_class_is_magic_int (klass) || mono_class_is_magic_float (klass)) {
4176 td->sp -= csignature->param_count;
4177 #if SIZEOF_VOID_P == 8
4178 if (mono_class_is_magic_int (klass) && td->sp [0].type == STACK_TYPE_I4)
4179 interp_add_ins (td, MINT_CONV_I8_I4);
4180 else if (mono_class_is_magic_float (klass) && td->sp [0].type == STACK_TYPE_R4)
4181 interp_add_ins (td, MINT_CONV_R8_R4);
4182 #endif
4183 interp_add_ins (td, MINT_NEWOBJ_MAGIC);
4184 td->last_ins->data [0] = get_data_item_index (td, mono_interp_get_imethod (domain, m, error));
4185 goto_if_nok (error, exit);
4187 PUSH_TYPE (td, stack_type [mint_type (m_class_get_byval_arg (klass))], klass);
4188 } else {
4189 if (m_class_get_parent (klass) == mono_defaults.array_class) {
4190 interp_add_ins (td, MINT_NEWOBJ_ARRAY);
4191 td->last_ins->data [0] = get_data_item_index (td, m->klass);
4192 td->last_ins->data [1] = csignature->param_count;
4193 } else if (m_class_get_image (klass) == mono_defaults.corlib &&
4194 !strcmp (m_class_get_name (m->klass), "ByReference`1") &&
4195 !strcmp (m->name, ".ctor")) {
4196 /* public ByReference(ref T value) */
4197 g_assert (csignature->hasthis && csignature->param_count == 1);
4198 interp_add_ins (td, MINT_INTRINS_BYREFERENCE_CTOR);
4199 td->last_ins->data [0] = get_data_item_index (td, mono_interp_get_imethod (domain, m, error));
4200 } else if (klass != mono_defaults.string_class &&
4201 !mono_class_is_marshalbyref (klass) &&
4202 !mono_class_has_finalizer (klass) &&
4203 !m_class_has_weak_fields (klass)) {
4204 if (!m_class_is_valuetype (klass)) {
4205 InterpInst *newobj_fast = interp_add_ins (td, MINT_NEWOBJ_FAST);
4207 newobj_fast->data [1] = csignature->param_count;
4209 MonoVTable *vtable = mono_class_vtable_checked (domain, klass, error);
4210 goto_if_nok (error, exit);
4211 newobj_fast->data [2] = get_data_item_index (td, vtable);
4213 move_stack (td, (td->sp - td->stack) - csignature->param_count, 2);
4215 StackInfo *tmp_sp = td->sp - csignature->param_count - 2;
4216 SET_TYPE (tmp_sp, STACK_TYPE_O, klass);
4217 SET_TYPE (tmp_sp + 1, STACK_TYPE_O, klass);
4219 if ((mono_interp_opt & INTERP_OPT_INLINE) && interp_method_check_inlining (td, m)) {
4220 MonoMethodHeader *mheader = interp_method_get_header (m, error);
4221 goto_if_nok (error, exit);
4223 if (interp_inline_method (td, m, mheader, error)) {
4224 newobj_fast->data [0] = 0xffff;
4225 break;
4228 // If inlining failed we need to restore the stack
4229 move_stack (td, (td->sp - td->stack) - csignature->param_count, -2);
4230 // Set the method to be executed as part of newobj instruction
4231 newobj_fast->data [0] = get_data_item_index (td, mono_interp_get_imethod (domain, m, error));
4232 } else {
4233 if (mint_type (m_class_get_byval_arg (klass)) == MINT_TYPE_VT)
4234 interp_add_ins (td, MINT_NEWOBJ_VTST_FAST);
4235 else
4236 interp_add_ins (td, MINT_NEWOBJ_VT_FAST);
4238 td->last_ins->data [0] = get_data_item_index (td, mono_interp_get_imethod (domain, m, error));
4239 td->last_ins->data [1] = csignature->param_count;
4241 if (mint_type (m_class_get_byval_arg (klass)) == MINT_TYPE_VT) {
4242 td->last_ins->data [2] = mono_class_value_size (klass, NULL);
4245 } else {
4246 interp_add_ins (td, MINT_NEWOBJ);
4247 td->last_ins->data [0] = get_data_item_index (td, mono_interp_get_imethod (domain, m, error));
4249 goto_if_nok (error, exit);
4250 /* The constructor was not inlined, abort inlining of current method */
4251 INLINE_FAILURE;
4253 td->sp -= csignature->param_count;
4254 if (mint_type (m_class_get_byval_arg (klass)) == MINT_TYPE_VT) {
4255 vt_res_size = mono_class_value_size (klass, NULL);
4256 PUSH_VT (td, vt_res_size);
4258 for (i = 0; i < csignature->param_count; ++i) {
4259 int mt = mint_type(csignature->params [i]);
4260 if (mt == MINT_TYPE_VT) {
4261 MonoClass *k = mono_class_from_mono_type_internal (csignature->params [i]);
4262 gint32 size = mono_class_value_size (k, NULL);
4263 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
4264 vt_stack_used += size;
4267 if (vt_stack_used != 0 || vt_res_size != 0) {
4268 interp_add_ins (td, MINT_VTRESULT);
4269 td->last_ins->data [0] = vt_res_size;
4270 WRITE32_INS (td->last_ins, 1, &vt_stack_used);
4271 td->vt_sp -= vt_stack_used;
4273 PUSH_TYPE (td, stack_type [mint_type (m_class_get_byval_arg (klass))], klass);
4275 break;
4277 case CEE_CASTCLASS:
4278 case CEE_ISINST: {
4279 gboolean isinst_instr = *td->ip == CEE_ISINST;
4280 CHECK_STACK (td, 1);
4281 token = read32 (td->ip + 1);
4282 klass = mini_get_class (method, token, generic_context);
4283 CHECK_TYPELOAD (klass);
4284 interp_handle_isinst (td, klass, isinst_instr);
4285 if (!isinst_instr)
4286 td->sp [-1].klass = klass;
4287 break;
4289 case CEE_CONV_R_UN:
4290 switch (td->sp [-1].type) {
4291 case STACK_TYPE_R8:
4292 break;
4293 case STACK_TYPE_I8:
4294 interp_add_ins (td, MINT_CONV_R_UN_I8);
4295 break;
4296 case STACK_TYPE_I4:
4297 interp_add_ins (td, MINT_CONV_R_UN_I4);
4298 break;
4299 default:
4300 g_assert_not_reached ();
4302 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R8);
4303 ++td->ip;
4304 break;
4305 case CEE_UNBOX:
4306 CHECK_STACK (td, 1);
4307 token = read32 (td->ip + 1);
4309 if (method->wrapper_type != MONO_WRAPPER_NONE)
4310 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
4311 else {
4312 klass = mono_class_get_and_inflate_typespec_checked (image, token, generic_context, error);
4313 goto_if_nok (error, exit);
4316 if (mono_class_is_nullable (klass)) {
4317 MonoMethod *target_method;
4318 if (m_class_is_enumtype (mono_class_get_nullable_param_internal (klass)))
4319 target_method = mono_class_get_method_from_name_checked (klass, "UnboxExact", 1, 0, error);
4320 else
4321 target_method = mono_class_get_method_from_name_checked (klass, "Unbox", 1, 0, error);
4322 goto_if_nok (error, exit);
4323 /* td->ip is incremented by interp_transform_call */
4324 if (!interp_transform_call (td, method, target_method, domain, generic_context, td->is_bb_start, NULL, FALSE, error, FALSE, FALSE))
4325 goto exit;
4327 * CEE_UNBOX needs to push address of vtype while Nullable.Unbox returns the value type
4328 * We create a local variable in the frame so that we can fetch its address.
4330 int local_offset = create_interp_local (td, m_class_get_byval_arg (klass));
4331 store_local_general (td, local_offset, m_class_get_byval_arg (klass));
4332 interp_add_ins (td, MINT_LDLOCA_S);
4333 td->last_ins->data [0] = local_offset;
4334 PUSH_SIMPLE_TYPE (td, STACK_TYPE_MP);
4335 } else {
4336 interp_add_ins (td, MINT_UNBOX);
4337 td->last_ins->data [0] = get_data_item_index (td, klass);
4338 SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_MP);
4339 td->ip += 5;
4341 break;
4342 case CEE_UNBOX_ANY:
4343 CHECK_STACK (td, 1);
4344 token = read32 (td->ip + 1);
4346 klass = mini_get_class (method, token, generic_context);
4347 CHECK_TYPELOAD (klass);
4349 if (mini_type_is_reference (m_class_get_byval_arg (klass))) {
4350 int mt = mint_type (m_class_get_byval_arg (klass));
4351 interp_handle_isinst (td, klass, FALSE);
4352 SET_TYPE (td->sp - 1, stack_type [mt], klass);
4353 } else if (mono_class_is_nullable (klass)) {
4354 MonoMethod *target_method;
4355 if (m_class_is_enumtype (mono_class_get_nullable_param_internal (klass)))
4356 target_method = mono_class_get_method_from_name_checked (klass, "UnboxExact", 1, 0, error);
4357 else
4358 target_method = mono_class_get_method_from_name_checked (klass, "Unbox", 1, 0, error);
4359 goto_if_nok (error, exit);
4360 /* td->ip is incremented by interp_transform_call */
4361 if (!interp_transform_call (td, method, target_method, domain, generic_context, td->is_bb_start, NULL, FALSE, error, FALSE, FALSE))
4362 goto exit;
4363 } else {
4364 interp_add_ins (td, MINT_UNBOX);
4365 td->last_ins->data [0] = get_data_item_index (td, klass);
4367 interp_emit_ldobj (td, klass);
4369 td->ip += 5;
4372 break;
4373 case CEE_THROW:
4374 INLINE_FAILURE;
4375 CHECK_STACK (td, 1);
4376 SIMPLE_OP (td, MINT_THROW);
4377 td->sp = td->stack;
4378 break;
4379 case CEE_LDFLDA: {
4380 CHECK_STACK (td, 1);
4381 token = read32 (td->ip + 1);
4382 field = interp_field_from_token (method, token, &klass, generic_context, error);
4383 goto_if_nok (error, exit);
4384 MonoType *ftype = mono_field_get_type_internal (field);
4385 gboolean is_static = !!(ftype->attrs & FIELD_ATTRIBUTE_STATIC);
4386 mono_class_init_internal (klass);
4387 #ifndef DISABLE_REMOTING
4388 if (m_class_get_marshalbyref (klass) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
4389 g_assert (!is_static);
4390 int offset = m_class_is_valuetype (klass) ? field->offset - MONO_ABI_SIZEOF (MonoObject) : field->offset;
4392 interp_add_ins (td, MINT_MONO_LDPTR);
4393 td->last_ins->data [0] = get_data_item_index (td, klass);
4394 PUSH_SIMPLE_TYPE (td, STACK_TYPE_I);
4395 interp_add_ins (td, MINT_MONO_LDPTR);
4396 td->last_ins->data [0] = get_data_item_index (td, field);
4397 PUSH_SIMPLE_TYPE (td, STACK_TYPE_I);
4398 interp_add_ins (td, MINT_LDC_I4);
4399 WRITE32_INS (td->last_ins, 0, &offset);
4400 PUSH_SIMPLE_TYPE (td, STACK_TYPE_I4);
4401 #if SIZEOF_VOID_P == 8
4402 interp_add_ins (td, MINT_CONV_I8_I4);
4403 #endif
4405 MonoMethod *wrapper = mono_marshal_get_ldflda_wrapper (field->type);
4406 /* td->ip is incremented by interp_transform_call */
4407 if (!interp_transform_call (td, method, wrapper, domain, generic_context, td->is_bb_start, NULL, FALSE, error, FALSE, FALSE))
4408 goto exit;
4409 } else
4410 #endif
4412 if (is_static) {
4413 interp_add_ins (td, MINT_POP);
4414 td->last_ins->data [0] = 0;
4415 interp_emit_ldsflda (td, field, error);
4416 goto_if_nok (error, exit);
4417 } else {
4418 if ((td->sp - 1)->type == STACK_TYPE_O) {
4419 interp_add_ins (td, MINT_LDFLDA);
4420 } else {
4421 g_assert ((td->sp -1)->type == STACK_TYPE_MP);
4422 interp_add_ins (td, MINT_LDFLDA_UNSAFE);
4424 td->last_ins->data [0] = m_class_is_valuetype (klass) ? field->offset - MONO_ABI_SIZEOF (MonoObject) : field->offset;
4426 td->ip += 5;
4428 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_MP);
4429 break;
4431 case CEE_LDFLD: {
4432 CHECK_STACK (td, 1);
4433 token = read32 (td->ip + 1);
4434 field = interp_field_from_token (method, token, &klass, generic_context, error);
4435 goto_if_nok (error, exit);
4436 MonoType *ftype = mono_field_get_type_internal (field);
4437 gboolean is_static = !!(ftype->attrs & FIELD_ATTRIBUTE_STATIC);
4438 mono_class_init_internal (klass);
4440 MonoClass *field_klass = mono_class_from_mono_type_internal (ftype);
4441 mt = mint_type (m_class_get_byval_arg (field_klass));
4442 #ifndef DISABLE_REMOTING
4443 if (m_class_get_marshalbyref (klass)) {
4444 g_assert (!is_static);
4445 interp_add_ins (td, mt == MINT_TYPE_VT ? MINT_LDRMFLD_VT : MINT_LDRMFLD);
4446 td->last_ins->data [0] = get_data_item_index (td, field);
4447 } else
4448 #endif
4450 if (is_static) {
4451 interp_add_ins (td, MINT_POP);
4452 td->last_ins->data [0] = 0;
4453 interp_emit_sfld_access (td, field, field_klass, mt, TRUE, error);
4454 goto_if_nok (error, exit);
4455 } else {
4456 int opcode = MINT_LDFLD_I1 + mt - MINT_TYPE_I1;
4457 #ifdef NO_UNALIGNED_ACCESS
4458 if ((mt == MINT_TYPE_I8 || mt == MINT_TYPE_R8) && field->offset % SIZEOF_VOID_P != 0)
4459 opcode = get_unaligned_opcode (opcode);
4460 #endif
4461 interp_add_ins (td, opcode);
4462 td->last_ins->data [0] = m_class_is_valuetype (klass) ? field->offset - MONO_ABI_SIZEOF (MonoObject) : field->offset;
4463 if (mt == MINT_TYPE_VT) {
4464 int size = mono_class_value_size (field_klass, NULL);
4465 WRITE32_INS (td->last_ins, 1, &size);
4469 if (mt == MINT_TYPE_VT) {
4470 int size = mono_class_value_size (field_klass, NULL);
4471 PUSH_VT (td, size);
4473 if (td->sp [-1].type == STACK_TYPE_VT) {
4474 int size = mono_class_value_size (klass, NULL);
4475 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
4476 int field_vt_size = 0;
4477 if (mt == MINT_TYPE_VT) {
4479 * Pop the loaded field from the vtstack (it will still be present
4480 * at the same vtstack address) and we will load it in place of the
4481 * containing valuetype with the second MINT_VTRESULT.
4483 field_vt_size = mono_class_value_size (field_klass, NULL);
4484 field_vt_size = ALIGN_TO (field_vt_size, MINT_VT_ALIGNMENT);
4485 interp_add_ins (td, MINT_VTRESULT);
4486 td->last_ins->data [0] = 0;
4487 WRITE32_INS (td->last_ins, 1, &field_vt_size);
4489 td->vt_sp -= size;
4490 interp_add_ins (td, MINT_VTRESULT);
4491 td->last_ins->data [0] = field_vt_size;
4492 WRITE32_INS (td->last_ins, 1, &size);
4494 td->ip += 5;
4495 SET_TYPE (td->sp - 1, stack_type [mt], field_klass);
4496 BARRIER_IF_VOLATILE (td);
4497 break;
4499 case CEE_STFLD: {
4500 CHECK_STACK (td, 2);
4501 token = read32 (td->ip + 1);
4502 field = interp_field_from_token (method, token, &klass, generic_context, error);
4503 goto_if_nok (error, exit);
4504 MonoType *ftype = mono_field_get_type_internal (field);
4505 gboolean is_static = !!(ftype->attrs & FIELD_ATTRIBUTE_STATIC);
4506 MonoClass *field_klass = mono_class_from_mono_type_internal (ftype);
4507 mono_class_init_internal (klass);
4508 mt = mint_type (ftype);
4510 BARRIER_IF_VOLATILE (td);
4512 #ifndef DISABLE_REMOTING
4513 if (m_class_get_marshalbyref (klass)) {
4514 g_assert (!is_static);
4515 interp_add_ins (td, mt == MINT_TYPE_VT ? MINT_STRMFLD_VT : MINT_STRMFLD);
4516 td->last_ins->data [0] = get_data_item_index (td, field);
4517 } else
4518 #endif
4520 if (is_static) {
4521 interp_add_ins (td, MINT_POP);
4522 td->last_ins->data [0] = 1;
4523 interp_emit_sfld_access (td, field, field_klass, mt, FALSE, error);
4524 goto_if_nok (error, exit);
4526 /* the vtable of the field might not be initialized at this point */
4527 mono_class_vtable_checked (domain, field_klass, error);
4528 goto_if_nok (error, exit);
4529 } else {
4530 int opcode = MINT_STFLD_I1 + mt - MINT_TYPE_I1;
4531 #ifdef NO_UNALIGNED_ACCESS
4532 if ((mt == MINT_TYPE_I8 || mt == MINT_TYPE_R8) && field->offset % SIZEOF_VOID_P != 0)
4533 opcode = get_unaligned_opcode (opcode);
4534 #endif
4535 interp_add_ins (td, opcode);
4536 td->last_ins->data [0] = m_class_is_valuetype (klass) ? field->offset - MONO_ABI_SIZEOF (MonoObject) : field->offset;
4537 if (mt == MINT_TYPE_VT) {
4538 /* the vtable of the field might not be initialized at this point */
4539 mono_class_vtable_checked (domain, field_klass, error);
4540 goto_if_nok (error, exit);
4542 td->last_ins->data [1] = get_data_item_index (td, field_klass);
4546 if (mt == MINT_TYPE_VT) {
4547 int size = mono_class_value_size (field_klass, NULL);
4548 POP_VT (td, size);
4550 td->ip += 5;
4551 td->sp -= 2;
4552 break;
4554 case CEE_LDSFLDA: {
4555 token = read32 (td->ip + 1);
4556 field = interp_field_from_token (method, token, &klass, generic_context, error);
4557 goto_if_nok (error, exit);
4558 interp_emit_ldsflda (td, field, error);
4559 goto_if_nok (error, exit);
4560 td->ip += 5;
4561 PUSH_SIMPLE_TYPE(td, STACK_TYPE_MP);
4562 break;
4564 case CEE_LDSFLD: {
4565 token = read32 (td->ip + 1);
4566 field = interp_field_from_token (method, token, &klass, generic_context, error);
4567 goto_if_nok (error, exit);
4568 MonoType *ftype = mono_field_get_type_internal (field);
4569 mt = mint_type (ftype);
4570 klass = mono_class_from_mono_type_internal (ftype);
4572 interp_emit_sfld_access (td, field, klass, mt, TRUE, error);
4573 goto_if_nok (error, exit);
4575 if (mt == MINT_TYPE_VT) {
4576 int size = mono_class_value_size (klass, NULL);
4577 PUSH_VT(td, size);
4579 td->ip += 5;
4580 PUSH_TYPE(td, stack_type [mt], klass);
4581 break;
4583 case CEE_STSFLD: {
4584 CHECK_STACK (td, 1);
4585 token = read32 (td->ip + 1);
4586 field = interp_field_from_token (method, token, &klass, generic_context, error);
4587 goto_if_nok (error, exit);
4588 MonoType *ftype = mono_field_get_type_internal (field);
4589 mt = mint_type (ftype);
4591 /* the vtable of the field might not be initialized at this point */
4592 MonoClass *fld_klass = mono_class_from_mono_type_internal (ftype);
4593 mono_class_vtable_checked (domain, fld_klass, error);
4594 goto_if_nok (error, exit);
4596 interp_emit_sfld_access (td, field, fld_klass, mt, FALSE, error);
4597 goto_if_nok (error, exit);
4599 if (mt == MINT_TYPE_VT) {
4600 int size = mono_class_value_size (fld_klass, NULL);
4601 POP_VT(td, size);
4603 td->ip += 5;
4604 --td->sp;
4605 break;
4607 case CEE_STOBJ: {
4608 token = read32 (td->ip + 1);
4610 if (method->wrapper_type != MONO_WRAPPER_NONE)
4611 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
4612 else
4613 klass = mini_get_class (method, token, generic_context);
4614 CHECK_TYPELOAD (klass);
4616 BARRIER_IF_VOLATILE (td);
4618 interp_emit_stobj (td, klass);
4620 td->ip += 5;
4621 break;
4623 case CEE_CONV_OVF_I_UN:
4624 case CEE_CONV_OVF_U_UN:
4625 CHECK_STACK (td, 1);
4626 switch (td->sp [-1].type) {
4627 case STACK_TYPE_R8:
4628 #if SIZEOF_VOID_P == 8
4629 interp_add_ins (td, MINT_CONV_OVF_I8_UN_R8);
4630 #else
4631 interp_add_ins (td, MINT_CONV_OVF_I4_UN_R8);
4632 #endif
4633 break;
4634 case STACK_TYPE_I8:
4635 #if SIZEOF_VOID_P == 4
4636 interp_add_ins (td, MINT_CONV_OVF_I4_UN_I8);
4637 #endif
4638 break;
4639 case STACK_TYPE_I4:
4640 #if SIZEOF_VOID_P == 8
4641 interp_add_ins (td, MINT_CONV_I8_U4);
4642 #elif SIZEOF_VOID_P == 4
4643 if (*td->ip == CEE_CONV_OVF_I_UN)
4644 interp_add_ins (td, MINT_CONV_OVF_I4_U4);
4645 #endif
4646 break;
4647 default:
4648 g_assert_not_reached ();
4649 break;
4651 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8);
4652 ++td->ip;
4653 break;
4654 case CEE_CONV_OVF_I8_UN:
4655 case CEE_CONV_OVF_U8_UN:
4656 CHECK_STACK (td, 1);
4657 switch (td->sp [-1].type) {
4658 case STACK_TYPE_R8:
4659 interp_add_ins (td, MINT_CONV_OVF_I8_UN_R8);
4660 break;
4661 case STACK_TYPE_I8:
4662 if (*td->ip == CEE_CONV_OVF_I8_UN)
4663 interp_add_ins (td, MINT_CONV_OVF_I8_U8);
4664 break;
4665 case STACK_TYPE_I4:
4666 interp_add_ins (td, MINT_CONV_I8_U4);
4667 break;
4668 case STACK_TYPE_R4:
4669 interp_add_ins (td, MINT_CONV_OVF_I8_UN_R4);
4670 break;
4671 default:
4672 g_assert_not_reached ();
4673 break;
4675 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8);
4676 ++td->ip;
4677 break;
4678 case CEE_BOX: {
4679 int size;
4680 CHECK_STACK (td, 1);
4681 token = read32 (td->ip + 1);
4682 if (method->wrapper_type != MONO_WRAPPER_NONE)
4683 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
4684 else
4685 klass = mini_get_class (method, token, generic_context);
4686 CHECK_TYPELOAD (klass);
4688 if (mono_class_is_nullable (klass)) {
4689 MonoMethod *target_method = mono_class_get_method_from_name_checked (klass, "Box", 1, 0, error);
4690 goto_if_nok (error, exit);
4691 /* td->ip is incremented by interp_transform_call */
4692 if (!interp_transform_call (td, method, target_method, domain, generic_context, td->is_bb_start, NULL, FALSE, error, FALSE, FALSE))
4693 goto exit;
4694 } else if (!m_class_is_valuetype (klass)) {
4695 /* already boxed, do nothing. */
4696 td->ip += 5;
4697 } else {
4698 if (G_UNLIKELY (m_class_is_byreflike (klass))) {
4699 mono_error_set_bad_image (error, image, "Cannot box IsByRefLike type '%s.%s'", m_class_get_name_space (klass), m_class_get_name (klass));
4700 goto exit;
4702 if (mint_type (m_class_get_byval_arg (klass)) == MINT_TYPE_VT) {
4703 size = mono_class_value_size (klass, NULL);
4704 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
4705 td->vt_sp -= size;
4706 } else if (td->sp [-1].type == STACK_TYPE_R8 && m_class_get_byval_arg (klass)->type == MONO_TYPE_R4) {
4707 interp_add_ins (td, MINT_CONV_R4_R8);
4709 MonoVTable *vtable = mono_class_vtable_checked (domain, klass, error);
4710 goto_if_nok (error, exit);
4712 if (mint_type (m_class_get_byval_arg (klass)) == MINT_TYPE_VT)
4713 interp_add_ins (td, MINT_BOX_VT);
4714 else
4715 interp_add_ins (td, MINT_BOX);
4716 td->last_ins->data [0] = get_data_item_index (td, vtable);
4717 td->last_ins->data [1] = 0;
4718 SET_TYPE(td->sp - 1, STACK_TYPE_O, klass);
4719 td->ip += 5;
4722 break;
4724 case CEE_NEWARR: {
4725 CHECK_STACK (td, 1);
4726 token = read32 (td->ip + 1);
4728 if (method->wrapper_type != MONO_WRAPPER_NONE)
4729 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
4730 else
4731 klass = mini_get_class (method, token, generic_context);
4732 CHECK_TYPELOAD (klass);
4734 MonoClass *array_class = mono_class_create_array (klass, 1);
4735 MonoVTable *vtable = mono_class_vtable_checked (domain, array_class, error);
4736 goto_if_nok (error, exit);
4738 unsigned char lentype = (td->sp - 1)->type;
4739 if (lentype == STACK_TYPE_I8) {
4740 /* mimic mini behaviour */
4741 interp_add_ins (td, MINT_CONV_OVF_U4_I8);
4742 } else {
4743 g_assert (lentype == STACK_TYPE_I4);
4744 interp_add_ins (td, MINT_CONV_OVF_U4_I4);
4746 SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I4);
4747 interp_add_ins (td, MINT_NEWARR);
4748 td->last_ins->data [0] = get_data_item_index (td, vtable);
4749 SET_TYPE (td->sp - 1, STACK_TYPE_O, klass);
4750 td->ip += 5;
4751 break;
4753 case CEE_LDLEN:
4754 CHECK_STACK (td, 1);
4755 SIMPLE_OP (td, MINT_LDLEN);
4756 #ifdef MONO_BIG_ARRAYS
4757 SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I8);
4758 #else
4759 SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I4);
4760 #endif
4761 break;
4762 case CEE_LDELEMA: {
4763 gint32 size;
4764 CHECK_STACK (td, 2);
4765 ENSURE_I4 (td, 1);
4766 token = read32 (td->ip + 1);
4768 if (method->wrapper_type != MONO_WRAPPER_NONE)
4769 klass = (MonoClass *) mono_method_get_wrapper_data (method, token);
4770 else
4771 klass = mini_get_class (method, token, generic_context);
4773 CHECK_TYPELOAD (klass);
4775 if (!m_class_is_valuetype (klass) && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
4777 * Check the class for failures before the type check, which can
4778 * throw other exceptions.
4780 mono_class_setup_vtable (klass);
4781 CHECK_TYPELOAD (klass);
4782 interp_add_ins (td, MINT_LDELEMA_TC);
4783 td->last_ins->data [0] = get_data_item_index (td, klass);
4784 td->last_ins->data [1] = 2;
4785 } else {
4786 interp_add_ins (td, MINT_LDELEMA_FAST);
4787 mono_class_init_internal (klass);
4788 size = mono_class_array_element_size (klass);
4789 WRITE32_INS (td->last_ins, 0, &size);
4792 readonly = FALSE;
4794 td->ip += 5;
4795 --td->sp;
4796 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_MP);
4797 break;
4799 case CEE_LDELEM_I1:
4800 CHECK_STACK (td, 2);
4801 ENSURE_I4 (td, 1);
4802 SIMPLE_OP (td, MINT_LDELEM_I1);
4803 --td->sp;
4804 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
4805 break;
4806 case CEE_LDELEM_U1:
4807 CHECK_STACK (td, 2);
4808 ENSURE_I4 (td, 1);
4809 SIMPLE_OP (td, MINT_LDELEM_U1);
4810 --td->sp;
4811 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
4812 break;
4813 case CEE_LDELEM_I2:
4814 CHECK_STACK (td, 2);
4815 ENSURE_I4 (td, 1);
4816 SIMPLE_OP (td, MINT_LDELEM_I2);
4817 --td->sp;
4818 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
4819 break;
4820 case CEE_LDELEM_U2:
4821 CHECK_STACK (td, 2);
4822 ENSURE_I4 (td, 1);
4823 SIMPLE_OP (td, MINT_LDELEM_U2);
4824 --td->sp;
4825 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
4826 break;
4827 case CEE_LDELEM_I4:
4828 CHECK_STACK (td, 2);
4829 ENSURE_I4 (td, 1);
4830 SIMPLE_OP (td, MINT_LDELEM_I4);
4831 --td->sp;
4832 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
4833 break;
4834 case CEE_LDELEM_U4:
4835 CHECK_STACK (td, 2);
4836 ENSURE_I4 (td, 1);
4837 SIMPLE_OP (td, MINT_LDELEM_U4);
4838 --td->sp;
4839 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
4840 break;
4841 case CEE_LDELEM_I8:
4842 CHECK_STACK (td, 2);
4843 ENSURE_I4 (td, 1);
4844 SIMPLE_OP (td, MINT_LDELEM_I8);
4845 --td->sp;
4846 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8);
4847 break;
4848 case CEE_LDELEM_I:
4849 CHECK_STACK (td, 2);
4850 ENSURE_I4 (td, 1);
4851 SIMPLE_OP (td, MINT_LDELEM_I);
4852 --td->sp;
4853 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I);
4854 break;
4855 case CEE_LDELEM_R4:
4856 CHECK_STACK (td, 2);
4857 ENSURE_I4 (td, 1);
4858 SIMPLE_OP (td, MINT_LDELEM_R4);
4859 --td->sp;
4860 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R4);
4861 break;
4862 case CEE_LDELEM_R8:
4863 CHECK_STACK (td, 2);
4864 ENSURE_I4 (td, 1);
4865 SIMPLE_OP (td, MINT_LDELEM_R8);
4866 --td->sp;
4867 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R8);
4868 break;
4869 case CEE_LDELEM_REF:
4870 CHECK_STACK (td, 2);
4871 ENSURE_I4 (td, 1);
4872 SIMPLE_OP (td, MINT_LDELEM_REF);
4873 --td->sp;
4874 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_O);
4875 break;
4876 case CEE_LDELEM:
4877 CHECK_STACK (td, 2);
4878 token = read32 (td->ip + 1);
4879 klass = mini_get_class (method, token, generic_context);
4880 CHECK_TYPELOAD (klass);
4881 switch (mint_type (m_class_get_byval_arg (klass))) {
4882 case MINT_TYPE_I1:
4883 ENSURE_I4 (td, 1);
4884 SIMPLE_OP (td, MINT_LDELEM_I1);
4885 --td->sp;
4886 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
4887 break;
4888 case MINT_TYPE_U1:
4889 ENSURE_I4 (td, 1);
4890 SIMPLE_OP (td, MINT_LDELEM_U1);
4891 --td->sp;
4892 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
4893 break;
4894 case MINT_TYPE_U2:
4895 ENSURE_I4 (td, 1);
4896 SIMPLE_OP (td, MINT_LDELEM_U2);
4897 --td->sp;
4898 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
4899 break;
4900 case MINT_TYPE_I2:
4901 ENSURE_I4 (td, 1);
4902 SIMPLE_OP (td, MINT_LDELEM_I2);
4903 --td->sp;
4904 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
4905 break;
4906 case MINT_TYPE_I4:
4907 ENSURE_I4 (td, 1);
4908 SIMPLE_OP (td, MINT_LDELEM_I4);
4909 --td->sp;
4910 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
4911 break;
4912 case MINT_TYPE_I8:
4913 ENSURE_I4 (td, 1);
4914 SIMPLE_OP (td, MINT_LDELEM_I8);
4915 --td->sp;
4916 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8);
4917 break;
4918 case MINT_TYPE_R4:
4919 ENSURE_I4 (td, 1);
4920 SIMPLE_OP (td, MINT_LDELEM_R4);
4921 --td->sp;
4922 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R4);
4923 break;
4924 case MINT_TYPE_R8:
4925 ENSURE_I4 (td, 1);
4926 SIMPLE_OP (td, MINT_LDELEM_R8);
4927 --td->sp;
4928 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R8);
4929 break;
4930 case MINT_TYPE_O:
4931 ENSURE_I4 (td, 1);
4932 SIMPLE_OP (td, MINT_LDELEM_REF);
4933 --td->sp;
4934 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_O);
4935 break;
4936 case MINT_TYPE_VT: {
4937 int size = mono_class_value_size (klass, NULL);
4938 ENSURE_I4 (td, 1);
4939 SIMPLE_OP (td, MINT_LDELEM_VT);
4940 WRITE32_INS (td->last_ins, 0, &size);
4941 --td->sp;
4942 SET_TYPE (td->sp - 1, STACK_TYPE_VT, klass);
4943 PUSH_VT (td, size);
4944 break;
4946 default: {
4947 GString *res = g_string_new ("");
4948 mono_type_get_desc (res, m_class_get_byval_arg (klass), TRUE);
4949 g_print ("LDELEM: %s -> %d (%s)\n", m_class_get_name (klass), mint_type (m_class_get_byval_arg (klass)), res->str);
4950 g_string_free (res, TRUE);
4951 g_assert (0);
4952 break;
4955 td->ip += 4;
4956 break;
4957 case CEE_STELEM_I:
4958 CHECK_STACK (td, 3);
4959 ENSURE_I4 (td, 2);
4960 SIMPLE_OP (td, MINT_STELEM_I);
4961 td->sp -= 3;
4962 break;
4963 case CEE_STELEM_I1:
4964 CHECK_STACK (td, 3);
4965 ENSURE_I4 (td, 2);
4966 SIMPLE_OP (td, MINT_STELEM_I1);
4967 td->sp -= 3;
4968 break;
4969 case CEE_STELEM_I2:
4970 CHECK_STACK (td, 3);
4971 ENSURE_I4 (td, 2);
4972 SIMPLE_OP (td, MINT_STELEM_I2);
4973 td->sp -= 3;
4974 break;
4975 case CEE_STELEM_I4:
4976 CHECK_STACK (td, 3);
4977 ENSURE_I4 (td, 2);
4978 SIMPLE_OP (td, MINT_STELEM_I4);
4979 td->sp -= 3;
4980 break;
4981 case CEE_STELEM_I8:
4982 CHECK_STACK (td, 3);
4983 ENSURE_I4 (td, 2);
4984 SIMPLE_OP (td, MINT_STELEM_I8);
4985 td->sp -= 3;
4986 break;
4987 case CEE_STELEM_R4:
4988 CHECK_STACK (td, 3);
4989 ENSURE_I4 (td, 2);
4990 SIMPLE_OP (td, MINT_STELEM_R4);
4991 td->sp -= 3;
4992 break;
4993 case CEE_STELEM_R8:
4994 CHECK_STACK (td, 3);
4995 ENSURE_I4 (td, 2);
4996 SIMPLE_OP (td, MINT_STELEM_R8);
4997 td->sp -= 3;
4998 break;
4999 case CEE_STELEM_REF:
5000 CHECK_STACK (td, 3);
5001 ENSURE_I4 (td, 2);
5002 SIMPLE_OP (td, MINT_STELEM_REF);
5003 td->sp -= 3;
5004 break;
5005 case CEE_STELEM:
5006 CHECK_STACK (td, 3);
5007 ENSURE_I4 (td, 2);
5008 token = read32 (td->ip + 1);
5009 klass = mini_get_class (method, token, generic_context);
5010 CHECK_TYPELOAD (klass);
5011 switch (mint_type (m_class_get_byval_arg (klass))) {
5012 case MINT_TYPE_I1:
5013 SIMPLE_OP (td, MINT_STELEM_I1);
5014 break;
5015 case MINT_TYPE_U1:
5016 SIMPLE_OP (td, MINT_STELEM_U1);
5017 break;
5018 case MINT_TYPE_I2:
5019 SIMPLE_OP (td, MINT_STELEM_I2);
5020 break;
5021 case MINT_TYPE_U2:
5022 SIMPLE_OP (td, MINT_STELEM_U2);
5023 break;
5024 case MINT_TYPE_I4:
5025 SIMPLE_OP (td, MINT_STELEM_I4);
5026 break;
5027 case MINT_TYPE_I8:
5028 SIMPLE_OP (td, MINT_STELEM_I8);
5029 break;
5030 case MINT_TYPE_R4:
5031 SIMPLE_OP (td, MINT_STELEM_R4);
5032 break;
5033 case MINT_TYPE_R8:
5034 SIMPLE_OP (td, MINT_STELEM_R8);
5035 break;
5036 case MINT_TYPE_O:
5037 SIMPLE_OP (td, MINT_STELEM_REF);
5038 break;
5039 case MINT_TYPE_VT: {
5040 int size = mono_class_value_size (klass, NULL);
5041 SIMPLE_OP (td, MINT_STELEM_VT);
5042 td->last_ins->data [0] = get_data_item_index (td, klass);
5043 WRITE32_INS (td->last_ins, 1, &size);
5044 POP_VT (td, size);
5045 break;
5047 default: {
5048 GString *res = g_string_new ("");
5049 mono_type_get_desc (res, m_class_get_byval_arg (klass), TRUE);
5050 g_print ("STELEM: %s -> %d (%s)\n", m_class_get_name (klass), mint_type (m_class_get_byval_arg (klass)), res->str);
5051 g_string_free (res, TRUE);
5052 g_assert (0);
5053 break;
5056 td->ip += 4;
5057 td->sp -= 3;
5058 break;
5059 #if 0
5060 case CEE_CONV_OVF_U1:
5062 case CEE_CONV_OVF_I8:
5064 #if SIZEOF_VOID_P == 8
5065 case CEE_CONV_OVF_U:
5066 #endif
5067 #endif
5068 case CEE_CKFINITE:
5069 CHECK_STACK (td, 1);
5070 SIMPLE_OP (td, MINT_CKFINITE);
5071 break;
5072 case CEE_MKREFANY:
5073 CHECK_STACK (td, 1);
5075 token = read32 (td->ip + 1);
5076 klass = mini_get_class (method, token, generic_context);
5077 CHECK_TYPELOAD (klass);
5079 interp_add_ins (td, MINT_MKREFANY);
5080 td->last_ins->data [0] = get_data_item_index (td, klass);
5082 td->ip += 5;
5083 PUSH_VT (td, sizeof (MonoTypedRef));
5084 SET_TYPE(td->sp - 1, STACK_TYPE_VT, mono_defaults.typed_reference_class);
5085 break;
5086 case CEE_REFANYVAL: {
5087 CHECK_STACK (td, 1);
5089 token = read32 (td->ip + 1);
5090 klass = mini_get_class (method, token, generic_context);
5091 CHECK_TYPELOAD (klass);
5093 interp_add_ins (td, MINT_REFANYVAL);
5094 td->last_ins->data [0] = get_data_item_index (td, klass);
5096 POP_VT (td, sizeof (MonoTypedRef));
5097 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_MP);
5099 td->ip += 5;
5100 break;
5102 case CEE_CONV_OVF_I1:
5103 case CEE_CONV_OVF_I1_UN: {
5104 gboolean is_un = *td->ip == CEE_CONV_OVF_I1_UN;
5105 CHECK_STACK (td, 1);
5106 switch (td->sp [-1].type) {
5107 case STACK_TYPE_R8:
5108 interp_add_ins (td, is_un ? MINT_CONV_OVF_I1_UN_R8 : MINT_CONV_OVF_I1_R8);
5109 break;
5110 case STACK_TYPE_I4:
5111 interp_add_ins (td, is_un ? MINT_CONV_OVF_I1_U4 : MINT_CONV_OVF_I1_I4);
5112 break;
5113 case STACK_TYPE_I8:
5114 interp_add_ins (td, is_un ? MINT_CONV_OVF_I1_U8 : MINT_CONV_OVF_I1_I8);
5115 break;
5116 default:
5117 g_assert_not_reached ();
5119 ++td->ip;
5120 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
5121 break;
5123 case CEE_CONV_OVF_U1:
5124 case CEE_CONV_OVF_U1_UN:
5125 CHECK_STACK (td, 1);
5126 switch (td->sp [-1].type) {
5127 case STACK_TYPE_R8:
5128 interp_add_ins (td, MINT_CONV_OVF_U1_R8);
5129 break;
5130 case STACK_TYPE_I4:
5131 interp_add_ins (td, MINT_CONV_OVF_U1_I4);
5132 break;
5133 case STACK_TYPE_I8:
5134 interp_add_ins (td, MINT_CONV_OVF_U1_I8);
5135 break;
5136 default:
5137 g_assert_not_reached ();
5139 ++td->ip;
5140 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
5141 break;
5142 case CEE_CONV_OVF_I2:
5143 case CEE_CONV_OVF_I2_UN: {
5144 gboolean is_un = *td->ip == CEE_CONV_OVF_I2_UN;
5145 CHECK_STACK (td, 1);
5146 switch (td->sp [-1].type) {
5147 case STACK_TYPE_R8:
5148 interp_add_ins (td, is_un ? MINT_CONV_OVF_I2_UN_R8 : MINT_CONV_OVF_I2_R8);
5149 break;
5150 case STACK_TYPE_I4:
5151 interp_add_ins (td, is_un ? MINT_CONV_OVF_I2_U4 : MINT_CONV_OVF_I2_I4);
5152 break;
5153 case STACK_TYPE_I8:
5154 interp_add_ins (td, is_un ? MINT_CONV_OVF_I2_U8 : MINT_CONV_OVF_I2_I8);
5155 break;
5156 default:
5157 g_assert_not_reached ();
5159 ++td->ip;
5160 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
5161 break;
5163 case CEE_CONV_OVF_U2_UN:
5164 case CEE_CONV_OVF_U2:
5165 CHECK_STACK (td, 1);
5166 switch (td->sp [-1].type) {
5167 case STACK_TYPE_R8:
5168 interp_add_ins (td, MINT_CONV_OVF_U2_R8);
5169 break;
5170 case STACK_TYPE_I4:
5171 interp_add_ins (td, MINT_CONV_OVF_U2_I4);
5172 break;
5173 case STACK_TYPE_I8:
5174 interp_add_ins (td, MINT_CONV_OVF_U2_I8);
5175 break;
5176 default:
5177 g_assert_not_reached ();
5179 ++td->ip;
5180 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
5181 break;
5182 #if SIZEOF_VOID_P == 4
5183 case CEE_CONV_OVF_I:
5184 #endif
5185 case CEE_CONV_OVF_I4:
5186 case CEE_CONV_OVF_I4_UN:
5187 CHECK_STACK (td, 1);
5188 switch (td->sp [-1].type) {
5189 case STACK_TYPE_R4:
5190 interp_add_ins (td, MINT_CONV_OVF_I4_R4);
5191 break;
5192 case STACK_TYPE_R8:
5193 interp_add_ins (td, MINT_CONV_OVF_I4_R8);
5194 break;
5195 case STACK_TYPE_I4:
5196 if (*td->ip == CEE_CONV_OVF_I4_UN)
5197 interp_add_ins (td, MINT_CONV_OVF_I4_U4);
5198 break;
5199 case STACK_TYPE_I8:
5200 if (*td->ip == CEE_CONV_OVF_I4_UN)
5201 interp_add_ins (td, MINT_CONV_OVF_I4_U8);
5202 else
5203 interp_add_ins (td, MINT_CONV_OVF_I4_I8);
5204 break;
5205 default:
5206 g_assert_not_reached ();
5208 ++td->ip;
5209 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
5210 break;
5211 #if SIZEOF_VOID_P == 4
5212 case CEE_CONV_OVF_U:
5213 #endif
5214 case CEE_CONV_OVF_U4:
5215 case CEE_CONV_OVF_U4_UN:
5216 CHECK_STACK (td, 1);
5217 switch (td->sp [-1].type) {
5218 case STACK_TYPE_R4:
5219 interp_add_ins (td, MINT_CONV_OVF_U4_R4);
5220 break;
5221 case STACK_TYPE_R8:
5222 interp_add_ins (td, MINT_CONV_OVF_U4_R8);
5223 break;
5224 case STACK_TYPE_I4:
5225 if (*td->ip != CEE_CONV_OVF_U4_UN)
5226 interp_add_ins (td, MINT_CONV_OVF_U4_I4);
5227 break;
5228 case STACK_TYPE_I8:
5229 interp_add_ins (td, MINT_CONV_OVF_U4_I8);
5230 break;
5231 case STACK_TYPE_MP:
5232 interp_add_ins (td, MINT_CONV_OVF_U4_P);
5233 break;
5234 default:
5235 g_assert_not_reached ();
5237 ++td->ip;
5238 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
5239 break;
5240 #if SIZEOF_VOID_P == 8
5241 case CEE_CONV_OVF_I:
5242 #endif
5243 case CEE_CONV_OVF_I8:
5244 CHECK_STACK (td, 1);
5245 switch (td->sp [-1].type) {
5246 case STACK_TYPE_R4:
5247 interp_add_ins (td, MINT_CONV_OVF_I8_R4);
5248 break;
5249 case STACK_TYPE_R8:
5250 interp_add_ins (td, MINT_CONV_OVF_I8_R8);
5251 break;
5252 case STACK_TYPE_I4:
5253 interp_add_ins (td, MINT_CONV_I8_I4);
5254 break;
5255 case STACK_TYPE_I8:
5256 break;
5257 default:
5258 g_assert_not_reached ();
5260 ++td->ip;
5261 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8);
5262 break;
5263 #if SIZEOF_VOID_P == 8
5264 case CEE_CONV_OVF_U:
5265 #endif
5266 case CEE_CONV_OVF_U8:
5267 CHECK_STACK (td, 1);
5268 switch (td->sp [-1].type) {
5269 case STACK_TYPE_R4:
5270 interp_add_ins (td, MINT_CONV_OVF_U8_R4);
5271 break;
5272 case STACK_TYPE_R8:
5273 interp_add_ins (td, MINT_CONV_OVF_U8_R8);
5274 break;
5275 case STACK_TYPE_I4:
5276 interp_add_ins (td, MINT_CONV_OVF_U8_I4);
5277 break;
5278 case STACK_TYPE_I8:
5279 interp_add_ins (td, MINT_CONV_OVF_U8_I8);
5280 break;
5281 default:
5282 g_assert_not_reached ();
5284 ++td->ip;
5285 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8);
5286 break;
5287 case CEE_LDTOKEN: {
5288 int size;
5289 gpointer handle;
5290 token = read32 (td->ip + 1);
5291 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
5292 handle = mono_method_get_wrapper_data (method, token);
5293 klass = (MonoClass *) mono_method_get_wrapper_data (method, token + 1);
5294 if (klass == mono_defaults.typehandle_class)
5295 handle = m_class_get_byval_arg ((MonoClass *) handle);
5297 if (generic_context) {
5298 handle = mono_class_inflate_generic_type_checked ((MonoType*)handle, generic_context, error);
5299 goto_if_nok (error, exit);
5301 } else {
5302 handle = mono_ldtoken_checked (image, token, &klass, generic_context, error);
5303 goto_if_nok (error, exit);
5305 mono_class_init_internal (klass);
5306 mt = mint_type (m_class_get_byval_arg (klass));
5307 g_assert (mt == MINT_TYPE_VT);
5308 size = mono_class_value_size (klass, NULL);
5309 g_assert (size == sizeof(gpointer));
5311 const unsigned char *next_ip = td->ip + 5;
5312 MonoMethod *cmethod;
5313 if (next_ip < end &&
5314 !td->is_bb_start [next_ip - td->il_code] &&
5315 (*next_ip == CEE_CALL || *next_ip == CEE_CALLVIRT) &&
5316 (cmethod = mono_get_method_checked (image, read32 (next_ip + 1), NULL, generic_context, error)) &&
5317 (cmethod->klass == mono_defaults.systemtype_class) &&
5318 (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
5319 interp_add_ins (td, MINT_MONO_LDPTR);
5320 gpointer systype = mono_type_get_object_checked (domain, (MonoType*)handle, error);
5321 goto_if_nok (error, exit);
5322 td->last_ins->data [0] = get_data_item_index (td, systype);
5323 PUSH_SIMPLE_TYPE (td, STACK_TYPE_MP);
5324 td->ip = next_ip + 5;
5325 } else {
5326 PUSH_VT (td, sizeof(gpointer));
5327 interp_add_ins (td, MINT_LDTOKEN);
5328 td->last_ins->data [0] = get_data_item_index (td, handle);
5329 PUSH_TYPE (td, stack_type [mt], klass);
5330 td->ip += 5;
5333 break;
5335 case CEE_ADD_OVF:
5336 binary_arith_op(td, MINT_ADD_OVF_I4);
5337 ++td->ip;
5338 break;
5339 case CEE_ADD_OVF_UN:
5340 binary_arith_op(td, MINT_ADD_OVF_UN_I4);
5341 ++td->ip;
5342 break;
5343 case CEE_MUL_OVF:
5344 binary_arith_op(td, MINT_MUL_OVF_I4);
5345 ++td->ip;
5346 break;
5347 case CEE_MUL_OVF_UN:
5348 binary_arith_op(td, MINT_MUL_OVF_UN_I4);
5349 ++td->ip;
5350 break;
5351 case CEE_SUB_OVF:
5352 binary_arith_op(td, MINT_SUB_OVF_I4);
5353 ++td->ip;
5354 break;
5355 case CEE_SUB_OVF_UN:
5356 binary_arith_op(td, MINT_SUB_OVF_UN_I4);
5357 ++td->ip;
5358 break;
5359 case CEE_ENDFINALLY: {
5360 g_assert (td->clause_indexes [in_offset] != -1);
5361 td->sp = td->stack;
5362 SIMPLE_OP (td, MINT_ENDFINALLY);
5363 td->last_ins->data [0] = td->clause_indexes [in_offset];
5364 break;
5366 case CEE_LEAVE:
5367 case CEE_LEAVE_S: {
5368 int offset;
5370 if (*td->ip == CEE_LEAVE)
5371 offset = 5 + read32 (td->ip + 1);
5372 else
5373 offset = 2 + (gint8)td->ip [1];
5375 td->sp = td->stack;
5376 if (td->clause_indexes [in_offset] != -1) {
5377 /* LEAVE instructions in catch clauses need to check for abort exceptions */
5378 handle_branch (td, MINT_LEAVE_S_CHECK, MINT_LEAVE_CHECK, offset);
5379 } else {
5380 handle_branch (td, MINT_LEAVE_S, MINT_LEAVE, offset);
5383 if (*td->ip == CEE_LEAVE)
5384 td->ip += 5;
5385 else
5386 td->ip += 2;
5387 break;
5389 case MONO_CUSTOM_PREFIX:
5390 ++td->ip;
5391 switch (*td->ip) {
5392 case CEE_MONO_RETHROW:
5393 CHECK_STACK (td, 1);
5394 SIMPLE_OP (td, MINT_MONO_RETHROW);
5395 td->sp = td->stack;
5396 break;
5398 case CEE_MONO_LD_DELEGATE_METHOD_PTR:
5399 --td->sp;
5400 td->ip += 1;
5401 interp_add_ins (td, MINT_LD_DELEGATE_METHOD_PTR);
5402 PUSH_SIMPLE_TYPE (td, STACK_TYPE_I);
5403 break;
5404 case CEE_MONO_CALLI_EXTRA_ARG:
5405 /* Same as CEE_CALLI, except that we drop the extra arg required for llvm specific behaviour */
5406 interp_add_ins (td, MINT_POP);
5407 td->last_ins->data [0] = 1;
5408 --td->sp;
5409 if (!interp_transform_call (td, method, NULL, domain, generic_context, td->is_bb_start, NULL, FALSE, error, FALSE, FALSE))
5410 goto exit;
5411 break;
5412 case CEE_MONO_JIT_ICALL_ADDR: {
5413 const guint32 token = read32 (td->ip + 1);
5414 td->ip += 5;
5415 const gconstpointer func = mono_find_jit_icall_info ((MonoJitICallId)token)->func;
5417 interp_add_ins (td, MINT_LDFTN);
5418 td->last_ins->data [0] = get_data_item_index (td, (gpointer)func);
5419 PUSH_SIMPLE_TYPE (td, STACK_TYPE_I);
5420 break;
5422 case CEE_MONO_ICALL: {
5423 MonoJitICallId const jit_icall_id = (MonoJitICallId)read32 (td->ip + 1);
5424 MonoJitICallInfo const * const info = mono_find_jit_icall_info (jit_icall_id);
5425 td->ip += 5;
5427 CHECK_STACK (td, info->sig->param_count);
5428 if (jit_icall_id == MONO_JIT_ICALL_mono_threads_attach_coop) {
5429 rtm->needs_thread_attach = 1;
5431 /* attach needs two arguments, and has one return value: leave one element on the stack */
5432 interp_add_ins (td, MINT_POP);
5433 td->last_ins->data [0] = 0;
5434 } else if (jit_icall_id == MONO_JIT_ICALL_mono_threads_detach_coop) {
5435 g_assert (rtm->needs_thread_attach);
5437 /* detach consumes two arguments, and no return value: drop both of them */
5438 interp_add_ins (td, MINT_POP);
5439 td->last_ins->data [0] = 0;
5440 interp_add_ins (td, MINT_POP);
5441 td->last_ins->data [0] = 0;
5442 } else {
5443 int const icall_op = interp_icall_op_for_sig (info->sig);
5444 g_assert (icall_op != -1);
5446 interp_add_ins (td, icall_op);
5447 // hash here is overkill
5448 td->last_ins->data [0] = get_data_item_index (td, (gpointer)info->func);
5450 td->sp -= info->sig->param_count;
5452 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
5453 int mt = mint_type (info->sig->ret);
5454 PUSH_SIMPLE_TYPE(td, stack_type [mt]);
5456 break;
5458 case CEE_MONO_VTADDR: {
5459 int size;
5460 CHECK_STACK (td, 1);
5461 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
5462 size = mono_class_native_size(td->sp [-1].klass, NULL);
5463 else
5464 size = mono_class_value_size(td->sp [-1].klass, NULL);
5465 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
5466 interp_add_ins (td, MINT_VTRESULT);
5467 td->last_ins->data [0] = 0;
5468 WRITE32_INS (td->last_ins, 1, &size);
5469 td->vt_sp -= size;
5470 ++td->ip;
5471 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_MP);
5472 break;
5474 case CEE_MONO_LDPTR:
5475 case CEE_MONO_CLASSCONST:
5476 token = read32 (td->ip + 1);
5477 td->ip += 5;
5478 interp_add_ins (td, MINT_MONO_LDPTR);
5479 td->last_ins->data [0] = get_data_item_index (td, mono_method_get_wrapper_data (method, token));
5480 td->sp [0].type = STACK_TYPE_I;
5481 ++td->sp;
5482 break;
5483 case CEE_MONO_OBJADDR:
5484 CHECK_STACK (td, 1);
5485 ++td->ip;
5486 td->sp[-1].type = STACK_TYPE_MP;
5487 /* do nothing? */
5488 break;
5489 case CEE_MONO_NEWOBJ:
5490 token = read32 (td->ip + 1);
5491 td->ip += 5;
5492 interp_add_ins (td, MINT_MONO_NEWOBJ);
5493 td->last_ins->data [0] = get_data_item_index (td, mono_method_get_wrapper_data (method, token));
5494 td->sp [0].type = STACK_TYPE_O;
5495 ++td->sp;
5496 break;
5497 case CEE_MONO_RETOBJ:
5498 CHECK_STACK (td, 1);
5499 token = read32 (td->ip + 1);
5500 td->ip += 5;
5501 interp_add_ins (td, MINT_MONO_RETOBJ);
5502 td->sp--;
5504 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
5506 /*stackval_from_data (signature->ret, frame->retval, sp->data.vt, signature->pinvoke);*/
5508 if (td->sp > td->stack)
5509 g_warning ("CEE_MONO_RETOBJ: more values on stack: %d", td->sp-td->stack);
5510 break;
5511 case CEE_MONO_LDNATIVEOBJ:
5512 token = read32 (td->ip + 1);
5513 td->ip += 5;
5514 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
5515 g_assert(m_class_is_valuetype (klass));
5516 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_MP);
5517 break;
5518 case CEE_MONO_TLS: {
5519 gint32 key = read32 (td->ip + 1);
5520 td->ip += 5;
5521 g_assertf (key == TLS_KEY_SGEN_THREAD_INFO, "%d", key);
5522 interp_add_ins (td, MINT_MONO_SGEN_THREAD_INFO);
5523 PUSH_SIMPLE_TYPE (td, STACK_TYPE_MP);
5524 break;
5526 case CEE_MONO_ATOMIC_STORE_I4:
5527 CHECK_STACK (td, 2);
5528 SIMPLE_OP (td, MINT_MONO_ATOMIC_STORE_I4);
5529 td->sp -= 2;
5530 td->ip++;
5531 break;
5532 case CEE_MONO_SAVE_LMF:
5533 case CEE_MONO_RESTORE_LMF:
5534 case CEE_MONO_NOT_TAKEN:
5535 ++td->ip;
5536 break;
5537 case CEE_MONO_LDPTR_INT_REQ_FLAG:
5538 interp_add_ins (td, MINT_MONO_LDPTR);
5539 td->last_ins->data [0] = get_data_item_index (td, mono_thread_interruption_request_flag ());
5540 PUSH_TYPE (td, STACK_TYPE_MP, NULL);
5541 ++td->ip;
5542 break;
5543 case CEE_MONO_MEMORY_BARRIER:
5544 interp_add_ins (td, MINT_MONO_MEMORY_BARRIER);
5545 ++td->ip;
5546 break;
5547 case CEE_MONO_LDDOMAIN:
5548 interp_add_ins (td, MINT_MONO_LDDOMAIN);
5549 td->sp [0].type = STACK_TYPE_I;
5550 ++td->sp;
5551 ++td->ip;
5552 break;
5553 case CEE_MONO_SAVE_LAST_ERROR:
5554 save_last_error = TRUE;
5555 ++td->ip;
5556 break;
5557 default:
5558 g_error ("transform.c: Unimplemented opcode: 0xF0 %02x at 0x%x\n", *td->ip, td->ip-header->code);
5560 break;
5561 #if 0
5562 case CEE_PREFIX7:
5563 case CEE_PREFIX6:
5564 case CEE_PREFIX5:
5565 case CEE_PREFIX4:
5566 case CEE_PREFIX3:
5567 case CEE_PREFIX2:
5568 case CEE_PREFIXREF: ves_abort(); break;
5569 #endif
5571 * Note: Exceptions thrown when executing a prefixed opcode need
5572 * to take into account the number of prefix bytes (usually the
5573 * throw point is just (ip - n_prefix_bytes).
5575 case CEE_PREFIX1:
5576 ++td->ip;
5577 switch (*td->ip) {
5578 case CEE_ARGLIST:
5579 interp_add_ins (td, MINT_ARGLIST);
5580 PUSH_VT (td, SIZEOF_VOID_P);
5581 PUSH_SIMPLE_TYPE (td, STACK_TYPE_VT);
5582 ++td->ip;
5583 break;
5584 case CEE_CEQ:
5585 CHECK_STACK(td, 2);
5586 if (td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP) {
5587 interp_add_ins (td, MINT_CEQ_I4 + STACK_TYPE_I - STACK_TYPE_I4);
5588 } else {
5589 if (td->sp [-1].type == STACK_TYPE_R4 && td->sp [-2].type == STACK_TYPE_R8)
5590 interp_add_ins (td, MINT_CONV_R8_R4);
5591 if (td->sp [-1].type == STACK_TYPE_R8 && td->sp [-2].type == STACK_TYPE_R4)
5592 interp_add_ins (td, MINT_CONV_R8_R4_SP);
5593 interp_add_ins (td, MINT_CEQ_I4 + td->sp [-1].type - STACK_TYPE_I4);
5595 --td->sp;
5596 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
5597 ++td->ip;
5598 break;
5599 case CEE_CGT:
5600 CHECK_STACK(td, 2);
5601 if (td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP)
5602 interp_add_ins (td, MINT_CGT_I4 + STACK_TYPE_I - STACK_TYPE_I4);
5603 else
5604 interp_add_ins (td, MINT_CGT_I4 + td->sp [-1].type - STACK_TYPE_I4);
5605 --td->sp;
5606 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
5607 ++td->ip;
5608 break;
5609 case CEE_CGT_UN:
5610 CHECK_STACK(td, 2);
5611 if (td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP)
5612 interp_add_ins (td, MINT_CGT_UN_I4 + STACK_TYPE_I - STACK_TYPE_I4);
5613 else
5614 interp_add_ins (td, MINT_CGT_UN_I4 + td->sp [-1].type - STACK_TYPE_I4);
5615 --td->sp;
5616 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
5617 ++td->ip;
5618 break;
5619 case CEE_CLT:
5620 CHECK_STACK(td, 2);
5621 if (td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP)
5622 interp_add_ins (td, MINT_CLT_I4 + STACK_TYPE_I - STACK_TYPE_I4);
5623 else
5624 interp_add_ins (td, MINT_CLT_I4 + td->sp [-1].type - STACK_TYPE_I4);
5625 --td->sp;
5626 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
5627 ++td->ip;
5628 break;
5629 case CEE_CLT_UN:
5630 CHECK_STACK(td, 2);
5631 if (td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP)
5632 interp_add_ins (td, MINT_CLT_UN_I4 + STACK_TYPE_I - STACK_TYPE_I4);
5633 else
5634 interp_add_ins (td, MINT_CLT_UN_I4 + td->sp [-1].type - STACK_TYPE_I4);
5635 --td->sp;
5636 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
5637 ++td->ip;
5638 break;
5639 case CEE_LDVIRTFTN: /* fallthrough */
5640 case CEE_LDFTN: {
5641 MonoMethod *m;
5642 if (*td->ip == CEE_LDVIRTFTN) {
5643 CHECK_STACK (td, 1);
5644 --td->sp;
5646 token = read32 (td->ip + 1);
5647 if (method->wrapper_type != MONO_WRAPPER_NONE)
5648 m = (MonoMethod *)mono_method_get_wrapper_data (method, token);
5649 else {
5650 m = mono_get_method_checked (image, token, NULL, generic_context, error);
5651 goto_if_nok (error, exit);
5654 if (!mono_method_can_access_method (method, m))
5655 interp_generate_mae_throw (td, method, m);
5657 if (method->wrapper_type == MONO_WRAPPER_NONE && m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
5658 m = mono_marshal_get_synchronized_wrapper (m);
5660 interp_add_ins (td, *td->ip == CEE_LDFTN ? MINT_LDFTN : MINT_LDVIRTFTN);
5661 td->last_ins->data [0] = get_data_item_index (td, mono_interp_get_imethod (domain, m, error));
5662 goto_if_nok (error, exit);
5663 td->ip += 5;
5664 PUSH_SIMPLE_TYPE (td, STACK_TYPE_F);
5665 break;
5667 case CEE_LDARG: {
5668 int arg_n = read16 (td->ip + 1);
5669 if (td->method == method)
5670 load_arg (td, arg_n);
5671 else
5672 load_local_general (td, arg_offsets [arg_n], get_arg_type (signature, arg_n));
5673 td->ip += 3;
5674 break;
5676 case CEE_LDARGA: {
5677 int n = read16 (td->ip + 1);
5679 if (td->method == method) {
5680 get_arg_type_exact (td, n, &mt);
5681 interp_add_ins (td, mt == MINT_TYPE_VT ? MINT_LDARGA_VT : MINT_LDARGA);
5682 td->last_ins->data [0] = n;
5683 } else {
5684 interp_add_ins (td, MINT_LDLOCA_S);
5685 td->last_ins->data [0] = arg_offsets [n];
5687 PUSH_SIMPLE_TYPE(td, STACK_TYPE_MP);
5688 td->ip += 3;
5689 break;
5691 case CEE_STARG: {
5692 int arg_n = read16 (td->ip + 1);
5693 if (td->method == method)
5694 store_arg (td, arg_n);
5695 else
5696 store_local_general (td, arg_offsets [arg_n], get_arg_type (signature, arg_n));
5697 td->ip += 3;
5698 break;
5700 case CEE_LDLOC: {
5701 int loc_n = read16 (td->ip + 1);
5702 if (td->method == method)
5703 load_local (td, loc_n);
5704 else
5705 load_local_general (td, local_offsets [loc_n], header->locals [loc_n]);
5706 td->ip += 3;
5707 break;
5709 case CEE_LDLOCA: {
5710 int loc_n = read16 (td->ip + 1);
5711 interp_add_ins (td, MINT_LDLOCA_S);
5712 if (td->method == method)
5713 td->last_ins->data [0] = td->rtm->local_offsets [loc_n];
5714 else
5715 td->last_ins->data [0] = local_offsets [loc_n];
5716 PUSH_SIMPLE_TYPE(td, STACK_TYPE_MP);
5717 td->ip += 3;
5718 break;
5720 case CEE_STLOC: {
5721 int loc_n = read16 (td->ip + 1);
5722 if (td->method == method)
5723 store_local (td, loc_n);
5724 else
5725 store_local_general (td, local_offsets [loc_n], header->locals [loc_n]);
5726 td->ip += 3;
5727 break;
5729 case CEE_LOCALLOC:
5730 INLINE_FAILURE;
5731 CHECK_STACK (td, 1);
5732 #if SIZEOF_VOID_P == 8
5733 if (td->sp [-1].type == STACK_TYPE_I8)
5734 interp_add_ins (td, MINT_CONV_I4_I8);
5735 #endif
5736 interp_add_ins (td, MINT_LOCALLOC);
5737 if (td->sp != td->stack + 1)
5738 g_warning("CEE_LOCALLOC: stack not empty");
5739 ++td->ip;
5740 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_MP);
5741 break;
5742 #if 0
5743 case CEE_UNUSED57: ves_abort(); break;
5744 #endif
5745 case CEE_ENDFILTER:
5746 interp_add_ins (td, MINT_ENDFILTER);
5747 ++td->ip;
5748 break;
5749 case CEE_UNALIGNED_:
5750 td->ip += 2;
5751 break;
5752 case CEE_VOLATILE_:
5753 ++td->ip;
5754 volatile_ = TRUE;
5755 break;
5756 case CEE_TAIL_:
5757 ++td->ip;
5758 /* FIX: should do something? */;
5759 // TODO: This should raise a method_tail_call profiler event.
5760 break;
5761 case CEE_INITOBJ:
5762 CHECK_STACK(td, 1);
5763 token = read32 (td->ip + 1);
5764 klass = mini_get_class (method, token, generic_context);
5765 CHECK_TYPELOAD (klass);
5766 if (m_class_is_valuetype (klass)) {
5767 interp_add_ins (td, MINT_INITOBJ);
5768 i32 = mono_class_value_size (klass, NULL);
5769 WRITE32_INS (td->last_ins, 0, &i32);
5770 } else {
5771 interp_add_ins (td, MINT_LDNULL);
5772 interp_add_ins (td, MINT_STIND_REF);
5774 td->ip += 5;
5775 --td->sp;
5776 break;
5777 case CEE_CPBLK:
5778 CHECK_STACK(td, 3);
5779 /* FIX? convert length to I8? */
5780 if (volatile_)
5781 interp_add_ins (td, MINT_MONO_MEMORY_BARRIER);
5782 interp_add_ins (td, MINT_CPBLK);
5783 BARRIER_IF_VOLATILE (td);
5784 td->sp -= 3;
5785 ++td->ip;
5786 break;
5787 case CEE_READONLY_:
5788 readonly = TRUE;
5789 td->ip += 1;
5790 break;
5791 case CEE_CONSTRAINED_:
5792 token = read32 (td->ip + 1);
5793 constrained_class = mini_get_class (method, token, generic_context);
5794 CHECK_TYPELOAD (constrained_class);
5795 td->ip += 5;
5796 break;
5797 case CEE_INITBLK:
5798 CHECK_STACK(td, 3);
5799 BARRIER_IF_VOLATILE (td);
5800 interp_add_ins (td, MINT_INITBLK);
5801 td->sp -= 3;
5802 td->ip += 1;
5803 break;
5804 case CEE_NO_:
5805 /* FIXME: implement */
5806 td->ip += 2;
5807 break;
5808 case CEE_RETHROW: {
5809 int clause_index = td->clause_indexes [in_offset];
5810 g_assert (clause_index != -1);
5811 SIMPLE_OP (td, MINT_RETHROW);
5812 td->last_ins->data [0] = rtm->exvar_offsets [clause_index];
5813 td->sp = td->stack;
5814 break;
5816 case CEE_SIZEOF: {
5817 gint32 size;
5818 token = read32 (td->ip + 1);
5819 td->ip += 5;
5820 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (m_class_get_image (method->klass)) && !generic_context) {
5821 int align;
5822 MonoType *type = mono_type_create_from_typespec_checked (image, token, error);
5823 goto_if_nok (error, exit);
5824 size = mono_type_size (type, &align);
5825 } else {
5826 int align;
5827 MonoClass *szclass = mini_get_class (method, token, generic_context);
5828 CHECK_TYPELOAD (szclass);
5829 #if 0
5830 if (!szclass->valuetype)
5831 THROW_EX (mono_exception_from_name (mono_defaults.corlib, "System", "InvalidProgramException"), ip - 5);
5832 #endif
5833 size = mono_type_size (m_class_get_byval_arg (szclass), &align);
5835 interp_add_ins (td, MINT_LDC_I4);
5836 WRITE32_INS (td->last_ins, 0, &size);
5837 PUSH_SIMPLE_TYPE(td, STACK_TYPE_I4);
5838 break;
5840 case CEE_REFANYTYPE:
5841 interp_add_ins (td, MINT_REFANYTYPE);
5842 td->ip += 1;
5843 POP_VT (td, sizeof (MonoTypedRef));
5844 PUSH_VT (td, sizeof (gpointer));
5845 SET_TYPE(td->sp - 1, STACK_TYPE_VT, NULL);
5846 break;
5847 default:
5848 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);
5850 break;
5851 default:
5852 g_error ("transform.c: Unimplemented opcode: %02x at 0x%x\n", *td->ip, td->ip-header->code);
5855 // No IR instructions were added as part of the IL instruction. Extend bb_start
5856 if (prev_last_ins == td->last_ins && td->is_bb_start [in_offset] && td->ip < end)
5857 td->is_bb_start [td->ip - td->il_code] = 1;
5860 g_assert (td->ip == end);
5862 exit_ret:
5863 g_free (arg_offsets);
5864 g_free (local_offsets);
5865 mono_basic_block_free (original_bb);
5866 for (i = 0; i < header->code_size; ++i)
5867 g_free (td->stack_state [i]);
5868 g_free (td->stack_state);
5869 g_free (td->stack_height);
5870 g_free (td->vt_stack_size);
5871 g_free (td->clause_indexes);
5872 g_free (td->is_bb_start);
5874 return ret;
5875 exit:
5876 ret = FALSE;
5877 goto exit_ret;
5880 // We are trying to branch to an il offset that has no associated ir instruction with it.
5881 // We will branch instead to the next instruction that we find
5882 static int
5883 resolve_in_offset (TransformData *td, int il_offset)
5885 int i = il_offset;
5886 g_assert (!td->in_offsets [il_offset]);
5887 while (!td->in_offsets [i])
5888 i++;
5889 td->in_offsets [il_offset] = td->in_offsets [i];
5890 return td->in_offsets [il_offset];
5893 // We store in the in_offset array the native_offset + 1, so 0 can mean only that the il
5894 // offset is uninitialized. Otherwise 0 is valid value for first interp instruction.
5895 static int
5896 get_in_offset (TransformData *td, int il_offset)
5898 int target_offset = td->in_offsets [il_offset];
5899 if (target_offset)
5900 return target_offset - 1;
5901 return resolve_in_offset (td, il_offset) - 1;
5904 static void
5905 handle_relocations (TransformData *td)
5907 // Handle relocations
5908 for (int i = 0; i < td->relocs->len; ++i) {
5909 Reloc *reloc = (Reloc*)g_ptr_array_index (td->relocs, i);
5910 int offset = get_in_offset (td, reloc->target) - reloc->offset;
5912 switch (reloc->type) {
5913 case RELOC_SHORT_BRANCH:
5914 g_assert (td->new_code [reloc->offset + 1] == 0xdead);
5915 td->new_code [reloc->offset + 1] = offset;
5916 break;
5917 case RELOC_LONG_BRANCH: {
5918 guint16 *v = (guint16 *) &offset;
5919 g_assert (td->new_code [reloc->offset + 1] == 0xdead);
5920 g_assert (td->new_code [reloc->offset + 2] == 0xbeef);
5921 td->new_code [reloc->offset + 1] = *(guint16 *) v;
5922 td->new_code [reloc->offset + 2] = *(guint16 *) (v + 1);
5923 break;
5925 case RELOC_SWITCH: {
5926 guint16 *v = (guint16*)&offset;
5927 g_assert (td->new_code [reloc->offset] == 0xdead);
5928 g_assert (td->new_code [reloc->offset + 1] == 0xbeef);
5929 td->new_code [reloc->offset] = *(guint16*)v;
5930 td->new_code [reloc->offset + 1] = *(guint16*)(v + 1);
5931 break;
5933 default:
5934 g_assert_not_reached ();
5935 break;
5941 static int
5942 get_inst_length (InterpInst *ins)
5944 if (ins->opcode == MINT_SWITCH)
5945 return MINT_SWITCH_LEN (READ32 (&ins->data [0]));
5946 else
5947 return mono_interp_oplen [ins->opcode];
5950 static guint16*
5951 emit_compacted_instruction (TransformData *td, guint16* start_ip, InterpInst *ins)
5953 guint16 opcode = ins->opcode;
5954 guint16 *ip = start_ip;
5956 // We know what IL offset this instruction was created for. We can now map the IL offset
5957 // to the IR offset. We use this array to resolve the relocations, which reference the IL.
5958 if (ins->il_offset != -1 && !td->in_offsets [ins->il_offset]) {
5959 g_assert (ins->il_offset >= 0 && ins->il_offset < td->header->code_size);
5960 td->in_offsets [ins->il_offset] = start_ip - td->new_code + 1;
5962 MonoDebugLineNumberEntry lne;
5963 lne.native_offset = (guint8*)start_ip - (guint8*)td->new_code;
5964 lne.il_offset = ins->il_offset;
5965 g_array_append_val (td->line_numbers, lne);
5968 *ip++ = opcode;
5969 if (opcode == MINT_SWITCH) {
5970 int labels = READ32 (&ins->data [0]);
5971 // Write number of switch labels
5972 *ip++ = ins->data [0];
5973 *ip++ = ins->data [1];
5974 // Add relocation for each label
5975 for (int i = 0; i < labels; i++) {
5976 Reloc *reloc = (Reloc*)mono_mempool_alloc0 (td->mempool, sizeof (Reloc));
5977 reloc->type = RELOC_SWITCH;
5978 reloc->offset = ip - td->new_code;
5979 reloc->target = READ32 (&ins->data [2 + i * 2]);
5980 g_ptr_array_add (td->relocs, reloc);
5981 *ip++ = 0xdead;
5982 *ip++ = 0xbeef;
5984 } else if ((opcode >= MINT_BRFALSE_I4_S && opcode <= MINT_BRTRUE_R8_S) ||
5985 (opcode >= MINT_BEQ_I4_S && opcode <= MINT_BLT_UN_R8_S) ||
5986 opcode == MINT_BR_S || opcode == MINT_LEAVE_S || opcode == MINT_LEAVE_S_CHECK) {
5987 const int br_offset = start_ip - td->new_code;
5988 if (ins->data [0] < ins->il_offset) {
5989 // Backwards branch. We can already patch it.
5990 *ip++ = get_in_offset (td, ins->data [0]) - br_offset;
5991 } else {
5992 // We don't know the in_offset of the target, add a reloc
5993 Reloc *reloc = (Reloc*)mono_mempool_alloc0 (td->mempool, sizeof (Reloc));
5994 reloc->type = RELOC_SHORT_BRANCH;
5995 reloc->offset = br_offset;
5996 reloc->target = ins->data [0];
5997 g_ptr_array_add (td->relocs, reloc);
5998 *ip++ = 0xdead;
6000 } else if ((opcode >= MINT_BRFALSE_I4 && opcode <= MINT_BRTRUE_R8) ||
6001 (opcode >= MINT_BEQ_I4 && opcode <= MINT_BLT_UN_R8) ||
6002 opcode == MINT_BR || opcode == MINT_LEAVE || opcode == MINT_LEAVE_CHECK) {
6003 const int br_offset = start_ip - td->new_code;
6004 int target_il = READ32 (&ins->data [0]);
6005 if (target_il < ins->il_offset) {
6006 // Backwards branch. We can already patch it
6007 const int br_offset = start_ip - td->new_code;
6008 int target_offset = get_in_offset (td, target_il) - br_offset;
6009 WRITE32 (ip, &target_offset);
6010 } else {
6011 Reloc *reloc = (Reloc*)mono_mempool_alloc0 (td->mempool, sizeof (Reloc));
6012 reloc->type = RELOC_LONG_BRANCH;
6013 reloc->offset = br_offset;
6014 reloc->target = target_il;
6015 g_ptr_array_add (td->relocs, reloc);
6016 *ip++ = 0xdead;
6017 *ip++ = 0xbeef;
6019 } else if (opcode == MINT_SDB_SEQ_POINT) {
6020 SeqPoint *seqp = (SeqPoint*)mono_mempool_alloc0 (td->mempool, sizeof (SeqPoint));
6021 InterpBasicBlock *cbb;
6023 if (ins->flags & INTERP_INST_FLAG_SEQ_POINT_METHOD_ENTRY) {
6024 seqp->il_offset = METHOD_ENTRY_IL_OFFSET;
6025 cbb = td->offset_to_bb [0];
6026 } else {
6027 if (ins->flags & INTERP_INST_FLAG_SEQ_POINT_METHOD_EXIT)
6028 seqp->il_offset = METHOD_EXIT_IL_OFFSET;
6029 else
6030 seqp->il_offset = ins->il_offset;
6031 cbb = td->offset_to_bb [ins->il_offset];
6033 seqp->native_offset = (guint8*)start_ip - (guint8*)td->new_code;
6034 if (ins->flags & INTERP_INST_FLAG_SEQ_POINT_NONEMPTY_STACK)
6035 seqp->flags |= MONO_SEQ_POINT_FLAG_NONEMPTY_STACK;
6036 if (ins->flags & INTERP_INST_FLAG_SEQ_POINT_NESTED_CALL)
6037 seqp->flags |= MONO_SEQ_POINT_FLAG_NESTED_CALL;
6038 g_ptr_array_add (td->seq_points, seqp);
6040 cbb->seq_points = g_slist_prepend_mempool (td->mempool, cbb->seq_points, seqp);
6041 cbb->last_seq_point = seqp;
6042 } else {
6043 int size = get_inst_length (ins) - 1;
6044 // Emit the rest of the data
6045 for (int i = 0; i < size; i++)
6046 *ip++ = ins->data [i];
6048 return ip;
6051 // Generates the final code, after we are done with all the passes
6052 static void
6053 generate_compacted_code (TransformData *td)
6055 guint16 *ip;
6056 int size = 0;
6057 td->relocs = g_ptr_array_new ();
6059 // Iterate once to compute the exact size of the compacted code
6060 InterpInst *ins = td->first_ins;
6061 while (ins) {
6062 size += get_inst_length (ins);
6063 ins = ins->next;
6066 // Generate the compacted stream of instructions
6067 td->new_code = ip = (guint16*)mono_domain_alloc0 (td->rtm->domain, size * sizeof (guint16));
6068 ins = td->first_ins;
6069 while (ins) {
6070 ip = emit_compacted_instruction (td, ip, ins);
6071 ins = ins->next;
6073 td->new_code_end = ip;
6074 td->in_offsets [td->header->code_size] = td->new_code_end - td->new_code;
6076 // Patch all branches
6077 handle_relocations (td);
6079 g_ptr_array_free (td->relocs, TRUE);
6082 static void
6083 generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, MonoGenericContext *generic_context, MonoError *error)
6085 MonoDomain *domain = rtm->domain;
6086 int i;
6087 TransformData transform_data;
6088 TransformData *td;
6089 static gboolean verbose_method_inited;
6090 static char* verbose_method_name;
6092 if (!verbose_method_inited) {
6093 verbose_method_name = g_getenv ("MONO_VERBOSE_METHOD");
6094 verbose_method_inited = TRUE;
6097 memset (&transform_data, 0, sizeof(transform_data));
6098 td = &transform_data;
6100 td->method = method;
6101 td->rtm = rtm;
6102 td->code_size = header->code_size;
6103 td->header = header;
6104 td->max_code_size = td->code_size;
6105 td->in_offsets = (int*)g_malloc0((header->code_size + 1) * sizeof(int));
6106 td->mempool = mono_mempool_new ();
6107 td->n_data_items = 0;
6108 td->max_data_items = 0;
6109 td->data_items = NULL;
6110 td->data_hash = g_hash_table_new (NULL, NULL);
6111 td->gen_sdb_seq_points = mini_debug_options.gen_sdb_seq_points;
6112 td->seq_points = g_ptr_array_new ();
6113 td->verbose_level = mono_interp_traceopt;
6114 td->total_locals_size = rtm->locals_size;
6115 rtm->data_items = td->data_items;
6117 if (verbose_method_name) {
6118 const char *name = verbose_method_name;
6120 if ((strchr (name, '.') > name) || strchr (name, ':')) {
6121 MonoMethodDesc *desc;
6123 desc = mono_method_desc_new (name, TRUE);
6124 if (mono_method_desc_full_match (desc, method)) {
6125 td->verbose_level = 4;
6127 mono_method_desc_free (desc);
6128 } else {
6129 if (strcmp (method->name, name) == 0)
6130 td->verbose_level = 4;
6134 td->stack = (StackInfo*)g_malloc0 ((header->max_stack + 1) * sizeof (td->stack [0]));
6135 td->stack_capacity = header->max_stack + 1;
6136 td->sp = td->stack;
6137 td->max_stack_height = 0;
6138 td->line_numbers = g_array_new (FALSE, TRUE, sizeof (MonoDebugLineNumberEntry));
6140 generate_code (td, method, header, generic_context, error);
6141 goto_if_nok (error, exit);
6143 generate_compacted_code (td);
6145 if (td->verbose_level) {
6146 g_print ("Runtime method: %s %p, VT stack size: %d\n", mono_method_full_name (method, TRUE), rtm, td->max_vt_sp);
6147 g_print ("Calculated stack size: %d, stated size: %d\n", td->max_stack_height, header->max_stack);
6148 dump_mint_code (td->new_code, td->new_code_end);
6151 /* Check if we use excessive stack space */
6152 if (td->max_stack_height > header->max_stack * 3 && header->max_stack > 16)
6153 g_warning ("Excessive stack space usage for method %s, %d/%d", method->name, td->max_stack_height, header->max_stack);
6155 int code_len;
6156 code_len = td->new_code_end - td->new_code;
6158 rtm->clauses = (MonoExceptionClause*)mono_domain_alloc0 (domain, header->num_clauses * sizeof (MonoExceptionClause));
6159 memcpy (rtm->clauses, header->clauses, header->num_clauses * sizeof(MonoExceptionClause));
6160 rtm->code = (gushort*)td->new_code;
6161 rtm->init_locals = header->init_locals;
6162 rtm->num_clauses = header->num_clauses;
6163 for (i = 0; i < header->num_clauses; i++) {
6164 MonoExceptionClause *c = rtm->clauses + i;
6165 int end_off = c->try_offset + c->try_len;
6166 c->try_offset = get_in_offset (td, c->try_offset);
6167 c->try_len = get_in_offset (td, end_off) - c->try_offset;
6168 g_assert ((c->try_offset + c->try_len) < code_len);
6169 end_off = c->handler_offset + c->handler_len;
6170 c->handler_offset = get_in_offset (td, c->handler_offset);
6171 c->handler_len = get_in_offset (td, end_off) - c->handler_offset;
6172 g_assert (c->handler_len >= 0 && (c->handler_offset + c->handler_len) <= code_len);
6173 if (c->flags & MONO_EXCEPTION_CLAUSE_FILTER)
6174 c->data.filter_offset = get_in_offset (td, c->data.filter_offset);
6176 rtm->stack_size = (sizeof (stackval)) * (td->max_stack_height + 2); /* + 1 for returns of called functions + 1 for 0-ing in trace*/
6177 rtm->stack_size = ALIGN_TO (rtm->stack_size, MINT_VT_ALIGNMENT);
6178 rtm->vt_stack_size = td->max_vt_sp;
6179 rtm->total_locals_size = td->total_locals_size;
6180 rtm->alloca_size = rtm->total_locals_size + rtm->vt_stack_size + rtm->stack_size;
6181 rtm->data_items = (gpointer*)mono_domain_alloc0 (domain, td->n_data_items * sizeof (td->data_items [0]));
6182 memcpy (rtm->data_items, td->data_items, td->n_data_items * sizeof (td->data_items [0]));
6184 /* Save debug info */
6185 interp_save_debug_info (rtm, header, td, td->line_numbers);
6187 /* Create a MonoJitInfo for the interpreted method by creating the interpreter IR as the native code. */
6188 int jinfo_len;
6189 jinfo_len = mono_jit_info_size ((MonoJitInfoFlags)0, header->num_clauses, 0);
6190 MonoJitInfo *jinfo;
6191 jinfo = (MonoJitInfo *)mono_domain_alloc0 (domain, jinfo_len);
6192 jinfo->is_interp = 1;
6193 rtm->jinfo = jinfo;
6194 mono_jit_info_init (jinfo, method, (guint8*)rtm->code, code_len, (MonoJitInfoFlags)0, header->num_clauses, 0);
6195 for (i = 0; i < jinfo->num_clauses; ++i) {
6196 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
6197 MonoExceptionClause *c = rtm->clauses + i;
6199 ei->flags = c->flags;
6200 ei->try_start = (guint8*)(rtm->code + c->try_offset);
6201 ei->try_end = (guint8*)(rtm->code + c->try_offset + c->try_len);
6202 ei->handler_start = (guint8*)(rtm->code + c->handler_offset);
6203 ei->exvar_offset = rtm->exvar_offsets [i];
6204 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
6205 ei->data.filter = (guint8*)(rtm->code + c->data.filter_offset);
6206 } else if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
6207 ei->data.handler_end = (guint8*)(rtm->code + c->handler_offset + c->handler_len);
6208 } else {
6209 ei->data.catch_class = c->data.catch_class;
6213 save_seq_points (td, jinfo);
6215 exit:
6216 g_free (td->in_offsets);
6217 g_free (td->data_items);
6218 g_free (td->stack);
6219 g_hash_table_destroy (td->data_hash);
6220 g_ptr_array_free (td->seq_points, TRUE);
6221 g_array_free (td->line_numbers, TRUE);
6222 mono_mempool_destroy (td->mempool);
6225 static mono_mutex_t calc_section;
6227 void
6228 mono_interp_transform_init (void)
6230 mono_os_mutex_init_recursive(&calc_section);
6233 void
6234 mono_interp_transform_method (InterpMethod *imethod, ThreadContext *context, MonoError *error)
6236 MonoMethod *method = imethod->method;
6237 MonoMethodHeader *header = NULL;
6238 MonoMethodSignature *signature = mono_method_signature_internal (method);
6239 MonoVTable *method_class_vt;
6240 MonoGenericContext *generic_context = NULL;
6241 MonoDomain *domain = imethod->domain;
6242 InterpMethod tmp_imethod;
6243 InterpMethod *real_imethod;
6245 error_init (error);
6247 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (method->klass))) {
6248 mono_error_set_invalid_operation (error, "%s", "Could not execute the method because the containing type is not fully instantiated.");
6249 return;
6252 // g_printerr ("TRANSFORM(0x%016lx): begin %s::%s\n", mono_thread_current (), method->klass->name, method->name);
6253 method_class_vt = mono_class_vtable_checked (domain, imethod->method->klass, error);
6254 return_if_nok (error);
6256 if (!method_class_vt->initialized) {
6257 mono_runtime_class_init_full (method_class_vt, error);
6258 return_if_nok (error);
6261 MONO_PROFILER_RAISE (jit_begin, (method));
6263 if (mono_method_signature_internal (method)->is_inflated)
6264 generic_context = mono_method_get_context (method);
6265 else {
6266 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
6267 if (generic_container)
6268 generic_context = &generic_container->context;
6271 if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
6272 MonoMethod *nm = NULL;
6273 if (imethod->transformed) {
6274 MONO_PROFILER_RAISE (jit_done, (method, imethod->jinfo));
6275 return;
6278 /* assumes all internal calls with an array this are built in... */
6279 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL && (! mono_method_signature_internal (method)->hasthis || m_class_get_rank (method->klass) == 0)) {
6280 nm = mono_marshal_get_native_wrapper (method, FALSE, FALSE);
6281 signature = mono_method_signature_internal (nm);
6282 } else {
6283 const char *name = method->name;
6284 if (m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
6285 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
6286 MonoJitICallInfo *mi = &mono_get_jit_icall_info ()->ves_icall_mono_delegate_ctor_interp;
6287 nm = mono_marshal_get_icall_wrapper (mi, TRUE);
6288 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
6290 * Usually handled during transformation of the caller, but
6291 * when the caller is handled by another execution engine
6292 * (for example fullAOT) we need to handle it here. That's
6293 * known to be wrong in cases where the reference to
6294 * `MonoDelegate` would be needed (FIXME).
6296 nm = mono_marshal_get_delegate_invoke (method, NULL);
6297 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
6298 nm = mono_marshal_get_delegate_begin_invoke (method);
6299 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
6300 nm = mono_marshal_get_delegate_end_invoke (method);
6303 if (nm == NULL)
6304 g_assert_not_reached ();
6306 if (nm == NULL) {
6307 mono_os_mutex_lock (&calc_section);
6308 imethod->stack_size = sizeof (stackval); /* for tracing */
6309 imethod->alloca_size = imethod->stack_size;
6310 mono_memory_barrier ();
6311 imethod->transformed = TRUE;
6312 mono_os_mutex_unlock (&calc_section);
6313 MONO_PROFILER_RAISE (jit_done, (method, NULL));
6314 return;
6316 method = nm;
6317 header = interp_method_get_header (nm, error);
6318 return_if_nok (error);
6321 if (!header) {
6322 header = mono_method_get_header_checked (method, error);
6323 return_if_nok (error);
6326 g_assert ((signature->param_count + signature->hasthis) < 1000);
6327 // g_printerr ("TRANSFORM(0x%016lx): end %s::%s\n", mono_thread_current (), method->klass->name, method->name);
6329 /* Make modifications to a copy of imethod, copy them back inside the lock */
6330 real_imethod = imethod;
6331 memcpy (&tmp_imethod, imethod, sizeof (InterpMethod));
6332 imethod = &tmp_imethod;
6334 interp_method_compute_offsets (imethod, signature, header);
6336 MONO_TIME_TRACK (mono_interp_stats.transform_time, generate (method, header, imethod, generic_context, error));
6338 mono_metadata_free_mh (header);
6340 return_if_nok (error);
6342 /* Copy changes back */
6343 imethod = real_imethod;
6344 mono_os_mutex_lock (&calc_section);
6345 if (!imethod->transformed) {
6346 // Ignore the first two fields which are unchanged. next_jit_code_hash shouldn't
6347 // be modified because it is racy with internal hash table insert.
6348 const int start_offset = 2 * sizeof (gpointer);
6349 memcpy ((char*)imethod + start_offset, (char*)&tmp_imethod + start_offset, sizeof (InterpMethod) - start_offset);
6350 mono_memory_barrier ();
6351 imethod->transformed = TRUE;
6352 mono_atomic_fetch_add_i32 (&mono_jit_stats.methods_with_interp, 1);
6355 mono_os_mutex_unlock (&calc_section);
6357 mono_domain_lock (domain);
6358 if (!g_hash_table_lookup (domain_jit_info (domain)->seq_points, imethod->method))
6359 g_hash_table_insert (domain_jit_info (domain)->seq_points, imethod->method, imethod->jinfo->seq_points);
6360 mono_domain_unlock (domain);
6362 // FIXME: Add a different callback ?
6363 MONO_PROFILER_RAISE (jit_done, (method, imethod->jinfo));