[interp] Small fixes (#11667)
[mono-project.git] / mono / mini / interp / transform.c
blob133d4863253331f0ac172273fcd05308c9c17a7a
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/debug-helpers.h>
14 #include <mono/metadata/exception.h>
15 #include <mono/metadata/exception-internals.h>
16 #include <mono/metadata/mono-endian.h>
17 #include <mono/metadata/marshal.h>
18 #include <mono/metadata/profiler-private.h>
19 #include <mono/metadata/tabledefs.h>
20 #include <mono/metadata/seq-points-data.h>
21 #include <mono/metadata/mono-basic-block.h>
22 #include <mono/metadata/abi-details.h>
23 #include <mono/metadata/reflection-internals.h>
25 #include <mono/mini/mini.h>
26 #include <mono/mini/mini-runtime.h>
28 #include "mintops.h"
29 #include "interp-internals.h"
30 #include "interp.h"
32 #define DEBUG 0
34 typedef struct
36 MonoClass *klass;
37 unsigned char type;
38 unsigned char flags;
39 } StackInfo;
41 typedef struct {
42 guint8 *ip;
43 GSList *preds;
44 GSList *seq_points;
45 SeqPoint *last_seq_point;
47 // This will hold a list of last sequence points of incoming basic blocks
48 SeqPoint **pred_seq_points;
49 guint num_pred_seq_points;
50 } InterpBasicBlock;
52 typedef enum {
53 RELOC_SHORT_BRANCH,
54 RELOC_LONG_BRANCH,
55 RELOC_SWITCH
56 } RelocType;
58 typedef struct {
59 RelocType type;
60 /* In the interpreter IR */
61 int offset;
62 /* In the IL code */
63 int target;
64 } Reloc;
66 typedef struct
68 MonoMethod *method;
69 MonoMethodHeader *header;
70 InterpMethod *rtm;
71 const unsigned char *il_code;
72 const unsigned char *ip;
73 const unsigned char *last_ip;
74 const unsigned char *in_start;
75 int code_size;
76 int *in_offsets;
77 StackInfo **stack_state;
78 int *stack_height;
79 int *vt_stack_size;
80 unsigned char *is_bb_start;
81 unsigned short *new_code;
82 unsigned short *new_code_end;
83 unsigned short *new_ip;
84 unsigned short *last_new_ip;
85 unsigned int max_code_size;
86 StackInfo *stack;
87 StackInfo *sp;
88 unsigned int max_stack_height;
89 unsigned int stack_capacity;
90 unsigned int vt_sp;
91 unsigned int max_vt_sp;
92 unsigned int total_locals_size;
93 int n_data_items;
94 int max_data_items;
95 void **data_items;
96 GHashTable *data_hash;
97 int *clause_indexes;
98 gboolean gen_sdb_seq_points;
99 GPtrArray *seq_points;
100 InterpBasicBlock **offset_to_bb;
101 InterpBasicBlock *entry_bb;
102 MonoMemPool *mempool;
103 GList *basic_blocks;
104 GPtrArray *relocs;
105 gboolean verbose_level;
106 } TransformData;
108 #define STACK_TYPE_I4 0
109 #define STACK_TYPE_I8 1
110 #define STACK_TYPE_R4 2
111 #define STACK_TYPE_R8 3
112 #define STACK_TYPE_O 4
113 #define STACK_TYPE_VT 5
114 #define STACK_TYPE_MP 6
115 #define STACK_TYPE_F 7
117 static const char *stack_type_string [] = { "I4", "I8", "R4", "R8", "O ", "VT", "MP", "F " };
119 #if SIZEOF_VOID_P == 8
120 #define STACK_TYPE_I STACK_TYPE_I8
121 #else
122 #define STACK_TYPE_I STACK_TYPE_I4
123 #endif
125 static int stack_type [] = {
126 STACK_TYPE_I4, /*I1*/
127 STACK_TYPE_I4, /*U1*/
128 STACK_TYPE_I4, /*I2*/
129 STACK_TYPE_I4, /*U2*/
130 STACK_TYPE_I4, /*I4*/
131 STACK_TYPE_I8, /*I8*/
132 STACK_TYPE_R4, /*R4*/
133 STACK_TYPE_R8, /*R8*/
134 STACK_TYPE_O, /*O*/
135 STACK_TYPE_MP, /*P*/
136 STACK_TYPE_VT
139 #if SIZEOF_VOID_P == 8
140 #define MINT_NEG_P MINT_NEG_I8
141 #define MINT_NOT_P MINT_NOT_I8
143 #define MINT_NEG_FP MINT_NEG_R8
145 #define MINT_ADD_P MINT_ADD_I8
146 #define MINT_SUB_P MINT_SUB_I8
147 #define MINT_MUL_P MINT_MUL_I8
148 #define MINT_DIV_P MINT_DIV_I8
149 #define MINT_DIV_UN_P MINT_DIV_UN_I8
150 #define MINT_REM_P MINT_REM_I8
151 #define MINT_REM_UN_P MINT_REM_UN_I8
152 #define MINT_AND_P MINT_AND_I8
153 #define MINT_OR_P MINT_OR_I8
154 #define MINT_XOR_P MINT_XOR_I8
155 #define MINT_SHL_P MINT_SHL_I8
156 #define MINT_SHR_P MINT_SHR_I8
157 #define MINT_SHR_UN_P MINT_SHR_UN_I8
159 #define MINT_CEQ_P MINT_CEQ_I8
160 #define MINT_CNE_P MINT_CNE_I8
161 #define MINT_CLT_P MINT_CLT_I8
162 #define MINT_CLT_UN_P MINT_CLT_UN_I8
163 #define MINT_CGT_P MINT_CGT_I8
164 #define MINT_CGT_UN_P MINT_CGT_UN_I8
165 #define MINT_CLE_P MINT_CLE_I8
166 #define MINT_CLE_UN_P MINT_CLE_UN_I8
167 #define MINT_CGE_P MINT_CGE_I8
168 #define MINT_CGE_UN_P MINT_CGE_UN_I8
170 #define MINT_ADD_FP MINT_ADD_R8
171 #define MINT_SUB_FP MINT_SUB_R8
172 #define MINT_MUL_FP MINT_MUL_R8
173 #define MINT_DIV_FP MINT_DIV_R8
174 #define MINT_REM_FP MINT_REM_R8
176 #define MINT_CNE_FP MINT_CNE_R8
177 #define MINT_CEQ_FP MINT_CEQ_R8
178 #define MINT_CGT_FP MINT_CGT_R8
179 #define MINT_CGE_FP MINT_CGE_R8
180 #define MINT_CLT_FP MINT_CLT_R8
181 #define MINT_CLE_FP MINT_CLE_R8
183 #else
185 #define MINT_NEG_P MINT_NEG_I4
186 #define MINT_NOT_P MINT_NOT_I4
188 #define MINT_NEG_FP MINT_NEG_R4
190 #define MINT_ADD_P MINT_ADD_I4
191 #define MINT_SUB_P MINT_SUB_I4
192 #define MINT_MUL_P MINT_MUL_I4
193 #define MINT_DIV_P MINT_DIV_I4
194 #define MINT_DIV_UN_P MINT_DIV_UN_I4
195 #define MINT_REM_P MINT_REM_I4
196 #define MINT_REM_UN_P MINT_REM_UN_I4
197 #define MINT_AND_P MINT_AND_I4
198 #define MINT_OR_P MINT_OR_I4
199 #define MINT_XOR_P MINT_XOR_I4
200 #define MINT_SHL_P MINT_SHL_I4
201 #define MINT_SHR_P MINT_SHR_I4
202 #define MINT_SHR_UN_P MINT_SHR_UN_I4
204 #define MINT_CEQ_P MINT_CEQ_I4
205 #define MINT_CNE_P MINT_CNE_I4
206 #define MINT_CLT_P MINT_CLT_I4
207 #define MINT_CLT_UN_P MINT_CLT_UN_I4
208 #define MINT_CGT_P MINT_CGT_I4
209 #define MINT_CGT_UN_P MINT_CGT_UN_I4
210 #define MINT_CLE_P MINT_CLE_I4
211 #define MINT_CLE_UN_P MINT_CLE_UN_I4
212 #define MINT_CGE_P MINT_CGE_I4
213 #define MINT_CGE_UN_P MINT_CGE_UN_I4
215 #define MINT_ADD_FP MINT_ADD_R4
216 #define MINT_SUB_FP MINT_SUB_R4
217 #define MINT_MUL_FP MINT_MUL_R4
218 #define MINT_DIV_FP MINT_DIV_R4
219 #define MINT_REM_FP MINT_REM_R4
221 #define MINT_CNE_FP MINT_CNE_R4
222 #define MINT_CEQ_FP MINT_CEQ_R4
223 #define MINT_CGT_FP MINT_CGT_R4
224 #define MINT_CGE_FP MINT_CGE_R4
225 #define MINT_CLT_FP MINT_CLT_R4
226 #define MINT_CLE_FP MINT_CLE_R4
228 #endif
230 typedef struct {
231 const gchar *op_name;
232 guint16 insn [3];
233 } MagicIntrinsic;
235 // static const MagicIntrinsic int_binop[] = {
237 static const MagicIntrinsic int_unnop[] = {
238 { "op_UnaryPlus", {MINT_NOP, MINT_NOP, MINT_NOP}},
239 { "op_UnaryNegation", {MINT_NEG_P, MINT_NEG_P, MINT_NEG_FP}},
240 { "op_OnesComplement", {MINT_NOT_P, MINT_NOT_P, MINT_NIY}}
243 static const MagicIntrinsic int_binop[] = {
244 { "op_Addition", {MINT_ADD_P, MINT_ADD_P, MINT_ADD_FP}},
245 { "op_Subtraction", {MINT_SUB_P, MINT_SUB_P, MINT_SUB_FP}},
246 { "op_Multiply", {MINT_MUL_P, MINT_MUL_P, MINT_MUL_FP}},
247 { "op_Division", {MINT_DIV_P, MINT_DIV_UN_P, MINT_DIV_FP}},
248 { "op_Modulus", {MINT_REM_P, MINT_REM_UN_P, MINT_REM_FP}},
249 { "op_BitwiseAnd", {MINT_AND_P, MINT_AND_P, MINT_NIY}},
250 { "op_BitwiseOr", {MINT_OR_P, MINT_OR_P, MINT_NIY}},
251 { "op_ExclusiveOr", {MINT_XOR_P, MINT_XOR_P, MINT_NIY}},
252 { "op_LeftShift", {MINT_SHL_P, MINT_SHL_P, MINT_NIY}},
253 { "op_RightShift", {MINT_SHR_P, MINT_SHR_UN_P, MINT_NIY}},
256 static const MagicIntrinsic int_cmpop[] = {
257 { "op_Inequality", {MINT_CNE_P, MINT_CNE_P, MINT_CNE_FP}},
258 { "op_Equality", {MINT_CEQ_P, MINT_CEQ_P, MINT_CEQ_FP}},
259 { "op_GreaterThan", {MINT_CGT_P, MINT_CGT_UN_P, MINT_CGT_FP}},
260 { "op_GreaterThanOrEqual", {MINT_CGE_P, MINT_CGE_UN_P, MINT_CGE_FP}},
261 { "op_LessThan", {MINT_CLT_P, MINT_CLT_UN_P, MINT_CLT_FP}},
262 { "op_LessThanOrEqual", {MINT_CLE_P, MINT_CLE_UN_P, MINT_CLE_FP}}
265 static void
266 grow_code (TransformData *td)
268 unsigned int old_ip_offset = td->new_ip - td->new_code;
269 unsigned int old_last_ip_offset = td->last_new_ip - td->new_code;
270 g_assert (old_ip_offset <= td->max_code_size);
271 td->new_code = (guint16*)g_realloc (td->new_code, (td->max_code_size *= 2) * sizeof (td->new_code [0]));
272 td->new_code_end = td->new_code + td->max_code_size;
273 td->new_ip = td->new_code + old_ip_offset;
274 td->last_new_ip = td->new_code + old_last_ip_offset;
277 #define ENSURE_CODE(td, n) \
278 do { \
279 if ((td)->new_ip + (n) > (td)->new_code_end) \
280 grow_code (td); \
281 } while (0)
283 #define ADD_CODE(td, n) \
284 do { \
285 if ((td)->new_ip == (td)->new_code_end) \
286 grow_code (td); \
287 *(td)->new_ip++ = (n); \
288 } while (0)
290 #define CHECK_STACK(td, n) \
291 do { \
292 int stack_size = (td)->sp - (td)->stack; \
293 if (stack_size < (n)) \
294 g_warning ("%s.%s: not enough values (%d < %d) on stack at %04x", \
295 m_class_get_name ((td)->method->klass), (td)->method->name, \
296 stack_size, n, (td)->ip - (td)->il_code); \
297 } while (0)
299 #define ENSURE_I4(td, sp_off) \
300 do { \
301 if ((td)->sp [-sp_off].type == STACK_TYPE_I8) \
302 ADD_CODE(td, sp_off == 1 ? MINT_CONV_I4_I8 : MINT_CONV_I4_I8_SP); \
303 } while (0)
305 #define CHECK_TYPELOAD(klass) \
306 do { \
307 if (!(klass) || mono_class_has_failure (klass)) { \
308 mono_error_set_for_class_failure (error, klass); \
309 goto exit; \
311 } while (0)
314 static void
315 handle_branch (TransformData *td, int short_op, int long_op, int offset)
317 int shorten_branch = 0;
318 int target = td->ip + offset - td->il_code;
319 if (target < 0 || target >= td->code_size)
320 g_assert_not_reached ();
321 /* Add exception checkpoint or safepoint for backward branches */
322 if (offset < 0) {
323 if (mono_threads_are_safepoints_enabled ())
324 ADD_CODE (td, MINT_SAFEPOINT);
325 else
326 ADD_CODE (td, MINT_CHECKPOINT);
328 if (offset > 0 && td->stack_height [target] < 0) {
329 td->stack_height [target] = td->sp - td->stack;
330 if (td->stack_height [target] > 0)
331 td->stack_state [target] = (StackInfo*)g_memdup (td->stack, td->stack_height [target] * sizeof (td->stack [0]));
332 td->vt_stack_size [target] = td->vt_sp;
334 if (offset < 0) {
335 offset = td->in_offsets [target] - (td->new_ip - td->new_code);
336 if (offset >= -32768) {
337 shorten_branch = 1;
339 } else {
340 if (td->header->code_size <= 25000) /* FIX to be precise somehow? */
341 shorten_branch = 1;
343 Reloc *reloc = (Reloc*)mono_mempool_alloc0 (td->mempool, sizeof (Reloc));
344 if (shorten_branch) {
345 offset = 0xffff;
346 reloc->type = RELOC_SHORT_BRANCH;
347 } else {
348 offset = 0xdeadbeef;
349 reloc->type = RELOC_LONG_BRANCH;
351 reloc->offset = td->new_ip - td->new_code;
352 reloc->target = target;
353 g_ptr_array_add (td->relocs, reloc);
355 if (shorten_branch) {
356 ADD_CODE(td, short_op);
357 ADD_CODE(td, offset);
358 } else {
359 ADD_CODE(td, long_op);
360 ADD_CODE(td, * (unsigned short *)(&offset));
361 ADD_CODE(td, * ((unsigned short *)&offset + 1));
365 static void
366 one_arg_branch(TransformData *td, int mint_op, int offset)
368 int type = td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP ? STACK_TYPE_I : td->sp [-1].type;
369 int long_op = mint_op + type - STACK_TYPE_I4;
370 int short_op = long_op + MINT_BRFALSE_I4_S - MINT_BRFALSE_I4;
371 CHECK_STACK(td, 1);
372 --td->sp;
373 handle_branch (td, short_op, long_op, offset);
376 static void
377 two_arg_branch(TransformData *td, int mint_op, int offset)
379 int type1 = td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP ? STACK_TYPE_I : td->sp [-1].type;
380 int type2 = td->sp [-2].type == STACK_TYPE_O || td->sp [-2].type == STACK_TYPE_MP ? STACK_TYPE_I : td->sp [-2].type;
381 int long_op = mint_op + type1 - STACK_TYPE_I4;
382 int short_op = long_op + MINT_BEQ_I4_S - MINT_BEQ_I4;
383 CHECK_STACK(td, 2);
384 if (type1 == STACK_TYPE_I4 && type2 == STACK_TYPE_I8) {
385 ADD_CODE(td, MINT_CONV_I8_I4);
386 td->in_offsets [td->ip - td->il_code]++;
387 } else if (type1 == STACK_TYPE_I8 && type2 == STACK_TYPE_I4) {
388 ADD_CODE(td, MINT_CONV_I8_I4_SP);
389 td->in_offsets [td->ip - td->il_code]++;
390 } else if (type1 == STACK_TYPE_R4 && type2 == STACK_TYPE_R8) {
391 ADD_CODE (td, MINT_CONV_R8_R4);
392 td->in_offsets [td->ip - td->il_code]++;
393 } else if (type1 == STACK_TYPE_R8 && type2 == STACK_TYPE_R4) {
394 ADD_CODE (td, MINT_CONV_R8_R4_SP);
395 td->in_offsets [td->ip - td->il_code]++;
396 } else if (type1 != type2) {
397 g_warning("%s.%s: branch type mismatch %d %d",
398 m_class_get_name (td->method->klass), td->method->name,
399 td->sp [-1].type, td->sp [-2].type);
401 td->sp -= 2;
402 handle_branch (td, short_op, long_op, offset);
405 static void
406 unary_arith_op(TransformData *td, int mint_op)
408 int op = mint_op + td->sp [-1].type - STACK_TYPE_I4;
409 CHECK_STACK(td, 1);
410 ADD_CODE(td, op);
413 static void
414 binary_arith_op(TransformData *td, int mint_op)
416 int type1 = td->sp [-2].type;
417 int type2 = td->sp [-1].type;
418 int op;
419 #if SIZEOF_VOID_P == 8
420 if ((type1 == STACK_TYPE_MP || type1 == STACK_TYPE_I8) && type2 == STACK_TYPE_I4) {
421 ADD_CODE(td, MINT_CONV_I8_I4);
422 type2 = STACK_TYPE_I8;
424 if (type1 == STACK_TYPE_I4 && (type2 == STACK_TYPE_MP || type2 == STACK_TYPE_I8)) {
425 ADD_CODE(td, MINT_CONV_I8_I4_SP);
426 type1 = STACK_TYPE_I8;
427 td->sp [-2].type = STACK_TYPE_I8;
429 #endif
430 if (type1 == STACK_TYPE_R8 && type2 == STACK_TYPE_R4) {
431 ADD_CODE (td, MINT_CONV_R8_R4);
432 type2 = STACK_TYPE_R8;
434 if (type1 == STACK_TYPE_R4 && type2 == STACK_TYPE_R8) {
435 ADD_CODE (td, MINT_CONV_R8_R4_SP);
436 type1 = STACK_TYPE_R8;
437 td->sp [-2].type = STACK_TYPE_R8;
439 if (type1 == STACK_TYPE_MP)
440 type1 = STACK_TYPE_I;
441 if (type2 == STACK_TYPE_MP)
442 type2 = STACK_TYPE_I;
443 if (type1 != type2) {
444 g_warning("%s.%s: %04x arith type mismatch %s %d %d",
445 m_class_get_name (td->method->klass), td->method->name,
446 td->ip - td->il_code, mono_interp_opname[mint_op], type1, type2);
448 op = mint_op + type1 - STACK_TYPE_I4;
449 CHECK_STACK(td, 2);
450 ADD_CODE(td, op);
451 --td->sp;
454 static void
455 shift_op(TransformData *td, int mint_op)
457 int op = mint_op + td->sp [-2].type - STACK_TYPE_I4;
458 CHECK_STACK(td, 2);
459 if (td->sp [-1].type != STACK_TYPE_I4) {
460 g_warning("%s.%s: shift type mismatch %d",
461 m_class_get_name (td->method->klass), td->method->name,
462 td->sp [-2].type);
464 ADD_CODE(td, op);
465 --td->sp;
468 static int
469 can_store (int stack_type, int var_type)
471 if (stack_type == STACK_TYPE_O || stack_type == STACK_TYPE_MP)
472 stack_type = STACK_TYPE_I;
473 if (var_type == STACK_TYPE_O || var_type == STACK_TYPE_MP)
474 var_type = STACK_TYPE_I;
475 return stack_type == var_type;
478 #define SET_SIMPLE_TYPE(s, ty) \
479 do { \
480 (s)->type = (ty); \
481 (s)->flags = 0; \
482 (s)->klass = NULL; \
483 } while (0)
485 #define SET_TYPE(s, ty, k) \
486 do { \
487 (s)->type = (ty); \
488 (s)->flags = 0; \
489 (s)->klass = k; \
490 } while (0)
492 #define REALLOC_STACK(td, sppos) \
493 do { \
494 (td)->stack_capacity *= 2; \
495 (td)->stack = (StackInfo*)realloc ((td)->stack, (td)->stack_capacity * sizeof (td->stack [0])); \
496 (td)->sp = (td)->stack + sppos; \
497 } while (0);
499 #define PUSH_SIMPLE_TYPE(td, ty) \
500 do { \
501 int sp_height; \
502 (td)->sp++; \
503 sp_height = (td)->sp - (td)->stack; \
504 if (sp_height > (td)->max_stack_height) \
505 (td)->max_stack_height = sp_height; \
506 if (sp_height > (td)->stack_capacity) \
507 REALLOC_STACK(td, sp_height); \
508 SET_SIMPLE_TYPE((td)->sp - 1, ty); \
509 } while (0)
511 #define PUSH_TYPE(td, ty, k) \
512 do { \
513 int sp_height; \
514 (td)->sp++; \
515 sp_height = (td)->sp - (td)->stack; \
516 if (sp_height > (td)->max_stack_height) \
517 (td)->max_stack_height = sp_height; \
518 if (sp_height > (td)->stack_capacity) \
519 REALLOC_STACK(td, sp_height); \
520 SET_TYPE((td)->sp - 1, ty, k); \
521 } while (0)
523 #define PUSH_VT(td, size) \
524 do { \
525 (td)->vt_sp += ALIGN_TO ((size), MINT_VT_ALIGNMENT); \
526 if ((td)->vt_sp > (td)->max_vt_sp) \
527 (td)->max_vt_sp = (td)->vt_sp; \
528 } while (0)
530 #define POP_VT(td, size) \
531 do { \
532 (td)->vt_sp -= ALIGN_TO ((size), MINT_VT_ALIGNMENT); \
533 } while (0)
535 #if NO_UNALIGNED_ACCESS
536 #define WRITE32(td, v) \
537 do { \
538 ENSURE_CODE(td, 2); \
539 * (guint16 *)((td)->new_ip) = * (guint16 *)(v); \
540 * ((guint16 *)((td)->new_ip) + 1) = * ((guint16 *)(v) + 1); \
541 (td)->new_ip += 2; \
542 } while (0)
544 #define WRITE64(td, v) \
545 do { \
546 ENSURE_CODE(td, 4); \
547 * (guint16 *)((td)->new_ip) = * (guint16 *)(v); \
548 * ((guint16 *)((td)->new_ip) + 1) = * ((guint16 *)(v) + 1); \
549 * ((guint16 *)((td)->new_ip) + 2) = * ((guint16 *)(v) + 2); \
550 * ((guint16 *)((td)->new_ip) + 3) = * ((guint16 *)(v) + 3); \
551 (td)->new_ip += 4; \
552 } while (0)
553 #else
554 #define WRITE32(td, v) \
555 do { \
556 ENSURE_CODE(td, 2); \
557 * (guint32 *)((td)->new_ip) = * (guint32 *)(v); \
558 (td)->new_ip += 2; \
559 } while (0)
561 #define WRITE64(td, v) \
562 do { \
563 ENSURE_CODE(td, 4); \
564 * (guint64 *)((td)->new_ip) = * (guint64 *)(v); \
565 (td)->new_ip += 4; \
566 } while (0)
568 #endif
570 static void
571 load_arg(TransformData *td, int n)
573 int mt;
574 MonoClass *klass = NULL;
575 MonoType *type;
577 gboolean hasthis = mono_method_signature_internal (td->method)->hasthis;
578 if (hasthis && n == 0)
579 type = m_class_get_byval_arg (td->method->klass);
580 else
581 type = mono_method_signature_internal (td->method)->params [hasthis ? n - 1 : n];
583 mt = mint_type (type);
584 if (mt == MINT_TYPE_VT) {
585 gint32 size;
586 klass = mono_class_from_mono_type_internal (type);
587 if (mono_method_signature_internal (td->method)->pinvoke)
588 size = mono_class_native_size (klass, NULL);
589 else
590 size = mono_class_value_size (klass, NULL);
592 if (hasthis && n == 0) {
593 mt = MINT_TYPE_P;
594 ADD_CODE (td, MINT_LDARG_P);
595 ADD_CODE (td, td->rtm->arg_offsets [n]); /* FIX for large offset */
596 klass = NULL;
597 } else {
598 PUSH_VT (td, size);
599 ADD_CODE (td, MINT_LDARG_VT);
600 ADD_CODE (td, td->rtm->arg_offsets [n]); /* FIX for large offset */
601 WRITE32 (td, &size);
603 } else {
604 if (hasthis && n == 0) {
605 mt = MINT_TYPE_P;
606 ADD_CODE (td, MINT_LDARG_P);
607 ADD_CODE (td, td->rtm->arg_offsets [n]); /* FIX for large offset */
608 klass = NULL;
609 } else {
610 ADD_CODE(td, MINT_LDARG_I1 + (mt - MINT_TYPE_I1));
611 ADD_CODE(td, td->rtm->arg_offsets [n]); /* FIX for large offset */
612 if (mt == MINT_TYPE_O)
613 klass = mono_class_from_mono_type_internal (type);
616 PUSH_TYPE(td, stack_type[mt], klass);
619 static void
620 store_arg(TransformData *td, int n)
622 int mt;
623 CHECK_STACK (td, 1);
624 MonoType *type;
626 gboolean hasthis = mono_method_signature_internal (td->method)->hasthis;
627 if (hasthis && n == 0)
628 type = m_class_get_byval_arg (td->method->klass);
629 else
630 type = mono_method_signature_internal (td->method)->params [n - !!hasthis];
632 mt = mint_type (type);
633 if (mt == MINT_TYPE_VT) {
634 gint32 size;
635 MonoClass *klass = mono_class_from_mono_type_internal (type);
636 if (mono_method_signature_internal (td->method)->pinvoke)
637 size = mono_class_native_size (klass, NULL);
638 else
639 size = mono_class_value_size (klass, NULL);
640 ADD_CODE(td, MINT_STARG_VT);
641 ADD_CODE(td, td->rtm->arg_offsets [n]);
642 WRITE32(td, &size);
643 if (td->sp [-1].type == STACK_TYPE_VT)
644 POP_VT(td, size);
645 } else {
646 ADD_CODE(td, MINT_STARG_I1 + (mt - MINT_TYPE_I1));
647 ADD_CODE(td, td->rtm->arg_offsets [n]);
649 --td->sp;
652 static void
653 store_inarg(TransformData *td, int n)
655 MonoType *type;
656 gboolean hasthis = mono_method_signature_internal (td->method)->hasthis;
657 if (hasthis && n == 0)
658 type = m_class_get_byval_arg (td->method->klass);
659 else
660 type = mono_method_signature_internal (td->method)->params [n - !!hasthis];
662 int mt = mint_type (type);
663 if (hasthis && n == 0) {
664 ADD_CODE (td, MINT_STINARG_P);
665 ADD_CODE (td, n);
666 return;
668 if (mt == MINT_TYPE_VT) {
669 MonoClass *klass = mono_class_from_mono_type_internal (type);
670 gint32 size;
671 if (mono_method_signature_internal (td->method)->pinvoke)
672 size = mono_class_native_size (klass, NULL);
673 else
674 size = mono_class_value_size (klass, NULL);
675 ADD_CODE(td, MINT_STINARG_VT);
676 ADD_CODE(td, n);
677 WRITE32(td, &size);
678 } else {
679 ADD_CODE(td, MINT_STINARG_I1 + (mt - MINT_TYPE_I1));
680 ADD_CODE(td, n);
684 static void
685 load_local(TransformData *td, int n)
687 MonoType *type = td->header->locals [n];
688 int mt = mint_type (type);
689 int offset = td->rtm->local_offsets [n];
690 MonoClass *klass = NULL;
691 if (mt == MINT_TYPE_VT) {
692 klass = mono_class_from_mono_type_internal (type);
693 gint32 size = mono_class_value_size (klass, NULL);
694 PUSH_VT(td, size);
695 ADD_CODE(td, MINT_LDLOC_VT);
696 ADD_CODE(td, offset); /*FIX for large offset */
697 WRITE32(td, &size);
698 } else {
699 g_assert (mt < MINT_TYPE_VT);
700 if (!td->gen_sdb_seq_points &&
701 mt == MINT_TYPE_I4 && !td->is_bb_start [td->in_start - td->il_code] && td->last_new_ip != NULL &&
702 td->last_new_ip [0] == MINT_STLOC_I4 && td->last_new_ip [1] == offset) {
703 td->last_new_ip [0] = MINT_STLOC_NP_I4;
704 } else if (!td->gen_sdb_seq_points &&
705 mt == MINT_TYPE_O && !td->is_bb_start [td->in_start - td->il_code] && td->last_new_ip != NULL &&
706 td->last_new_ip [0] == MINT_STLOC_O && td->last_new_ip [1] == offset) {
707 td->last_new_ip [0] = MINT_STLOC_NP_O;
708 } else {
709 ADD_CODE(td, MINT_LDLOC_I1 + (mt - MINT_TYPE_I1));
710 ADD_CODE(td, offset); /*FIX for large offset */
712 if (mt == MINT_TYPE_O)
713 klass = mono_class_from_mono_type_internal (type);
715 PUSH_TYPE(td, stack_type[mt], klass);
718 static void
719 store_local_general (TransformData *td, int offset, MonoType *type)
721 int mt = mint_type (type);
722 CHECK_STACK (td, 1);
723 #if SIZEOF_VOID_P == 8
724 if (td->sp [-1].type == STACK_TYPE_I4 && stack_type [mt] == STACK_TYPE_I8) {
725 ADD_CODE(td, MINT_CONV_I8_I4);
726 td->sp [-1].type = STACK_TYPE_I8;
728 #endif
729 if (!can_store(td->sp [-1].type, stack_type [mt])) {
730 g_warning("%s.%s: Store local stack type mismatch %d %d",
731 m_class_get_name (td->method->klass), td->method->name,
732 stack_type [mt], td->sp [-1].type);
734 if (mt == MINT_TYPE_VT) {
735 MonoClass *klass = mono_class_from_mono_type_internal (type);
736 gint32 size = mono_class_value_size (klass, NULL);
737 ADD_CODE(td, MINT_STLOC_VT);
738 ADD_CODE(td, offset); /*FIX for large offset */
739 WRITE32(td, &size);
740 if (td->sp [-1].type == STACK_TYPE_VT)
741 POP_VT(td, size);
742 } else {
743 g_assert (mt < MINT_TYPE_VT);
744 ADD_CODE(td, MINT_STLOC_I1 + (mt - MINT_TYPE_I1));
745 ADD_CODE(td, offset); /*FIX for large offset */
747 --td->sp;
750 static void
751 store_local (TransformData *td, int n)
753 MonoType *type = td->header->locals [n];
754 int offset = td->rtm->local_offsets [n];
755 store_local_general (td, offset, type);
758 #define SIMPLE_OP(td, op) \
759 do { \
760 ADD_CODE(td, op); \
761 ++td->ip; \
762 } while (0)
764 static guint16
765 get_data_item_index (TransformData *td, void *ptr)
767 gpointer p = g_hash_table_lookup (td->data_hash, ptr);
768 guint index;
769 if (p != NULL)
770 return GPOINTER_TO_UINT (p) - 1;
771 if (td->max_data_items == td->n_data_items) {
772 td->max_data_items = td->n_data_items == 0 ? 16 : 2 * td->max_data_items;
773 td->data_items = (gpointer*)g_realloc (td->data_items, td->max_data_items * sizeof(td->data_items [0]));
775 index = td->n_data_items;
776 td->data_items [index] = ptr;
777 ++td->n_data_items;
778 g_hash_table_insert (td->data_hash, ptr, GUINT_TO_POINTER (index + 1));
779 return index;
782 static gboolean
783 jit_call_supported (MonoMethod *method, MonoMethodSignature *sig)
785 GSList *l;
787 if (sig->param_count > 6)
788 return FALSE;
789 if (sig->pinvoke)
790 return FALSE;
791 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
792 return FALSE;
793 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
794 return FALSE;
795 if (method->is_inflated)
796 return FALSE;
797 if (method->string_ctor)
798 return FALSE;
800 if (mono_aot_only && m_class_get_image (method->klass)->aot_module) {
801 ERROR_DECL (error);
802 gpointer addr = mono_jit_compile_method_jit_only (method, error);
803 if (addr && mono_error_ok (error))
804 return TRUE;
807 for (l = mono_interp_jit_classes; l; l = l->next) {
808 const char *class_name = (const char*)l->data;
809 // FIXME: Namespaces
810 if (!strcmp (m_class_get_name (method->klass), class_name))
811 return TRUE;
814 //return TRUE;
815 return FALSE;
818 static int mono_class_get_magic_index (MonoClass *k)
820 if (mono_class_is_magic_int (k))
821 return !strcmp ("nint", m_class_get_name (k)) ? 0 : 1;
823 if (mono_class_is_magic_float (k))
824 return 2;
826 return -1;
829 static void
830 interp_generate_mae_throw (TransformData *td, MonoMethod *method, MonoMethod *target_method)
832 MonoJitICallInfo *info = mono_find_jit_icall_by_name ("mono_throw_method_access");
834 /* Inject code throwing MethodAccessException */
835 ADD_CODE (td, MINT_MONO_LDPTR);
836 ADD_CODE (td, get_data_item_index (td, method));
837 PUSH_SIMPLE_TYPE (td, STACK_TYPE_I);
839 ADD_CODE (td, MINT_MONO_LDPTR);
840 ADD_CODE (td, get_data_item_index (td, target_method));
841 PUSH_SIMPLE_TYPE (td, STACK_TYPE_I);
843 ADD_CODE (td, MINT_ICALL_PP_V);
844 ADD_CODE (td, get_data_item_index (td, (gpointer)info->func));
846 td->sp -= 2;
850 * These are additional locals that can be allocated as we transform the code.
851 * They are allocated past the method locals so they are accessed in the same
852 * way, with an offset relative to the frame->locals.
854 static int
855 create_interp_local (TransformData *td, MonoType *type)
857 int align, size;
858 int offset = td->total_locals_size;
860 size = mono_type_size (type, &align);
861 offset = ALIGN_TO (offset, align);
863 td->total_locals_size = offset + size;
865 return offset;
868 static void
869 dump_mint_code (TransformData *td)
871 const guint16 *p = td->new_code;
872 while (p < td->new_ip) {
873 char *ins = mono_interp_dis_mintop (td->new_code, p);
874 g_print ("%s\n", ins);
875 g_free (ins);
876 p = mono_interp_dis_mintop_len (p);
880 static MonoMethodHeader*
881 interp_method_get_header (MonoMethod* method, MonoError *error)
883 /* An explanation: mono_method_get_header_internal returns an error if
884 * called on a method with no body (e.g. an abstract method, or an
885 * icall). We don't want that.
887 if (mono_method_has_no_body (method))
888 return NULL;
889 else
890 return mono_method_get_header_internal (method, error);
893 /* stores top of stack as local and pushes address of it on stack */
894 static void
895 emit_store_value_as_local (TransformData *td, MonoType *src)
897 int size = mini_magic_type_size (NULL, src);
898 int local_offset = create_interp_local (td, mini_native_type_replace_type (src));
900 store_local_general (td, local_offset, src);
902 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
903 ADD_CODE (td, MINT_LDLOC_VT);
904 ADD_CODE (td, local_offset);
905 WRITE32 (td, &size);
907 PUSH_VT (td, size);
908 PUSH_TYPE (td, STACK_TYPE_VT, NULL);
911 /* Return TRUE if call transformation is finished */
912 static gboolean
913 interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoMethodSignature *csignature, gboolean readonly, int *op)
915 const char *tm = target_method->name;
916 int i;
917 int type_index = mono_class_get_magic_index (target_method->klass);
918 gboolean in_corlib = m_class_get_image (target_method->klass) == mono_defaults.corlib;
919 const char *klass_name_space = m_class_get_name_space (target_method->klass);
920 const char *klass_name = m_class_get_name (target_method->klass);
922 if (target_method->klass == mono_defaults.string_class) {
923 if (tm [0] == 'g') {
924 if (strcmp (tm, "get_Chars") == 0)
925 *op = MINT_GETCHR;
926 else if (strcmp (tm, "get_Length") == 0)
927 *op = MINT_STRLEN;
929 } else if (type_index >= 0) {
930 MonoClass *magic_class = target_method->klass;
932 const int mt = mint_type (m_class_get_byval_arg (magic_class));
933 if (!strcmp (".ctor", tm)) {
934 MonoType *arg = csignature->params [0];
935 /* depending on SIZEOF_VOID_P and the type of the value passed to the .ctor we either have to CONV it, or do nothing */
936 int arg_size = mini_magic_type_size (NULL, arg);
938 if (arg_size > SIZEOF_VOID_P) { // 8 -> 4
939 switch (type_index) {
940 case 0: case 1:
941 ADD_CODE (td, MINT_CONV_I4_I8);
942 break;
943 case 2:
944 ADD_CODE (td, MINT_CONV_R4_R8);
945 break;
949 if (arg_size < SIZEOF_VOID_P) { // 4 -> 8
950 switch (type_index) {
951 case 0:
952 ADD_CODE (td, MINT_CONV_I8_I4);
953 break;
954 case 1:
955 ADD_CODE (td, MINT_CONV_I8_U4);
956 break;
957 case 2:
958 ADD_CODE (td, MINT_CONV_R8_R4);
959 break;
963 switch (type_index) {
964 case 0: case 1:
965 #if SIZEOF_VOID_P == 4
966 ADD_CODE (td, MINT_STIND_I4);
967 #else
968 ADD_CODE (td, MINT_STIND_I8);
969 #endif
970 break;
971 case 2:
972 #if SIZEOF_VOID_P == 4
973 ADD_CODE (td, MINT_STIND_R4);
974 #else
975 ADD_CODE (td, MINT_STIND_R8);
976 #endif
977 break;
980 td->sp -= 2;
981 td->ip += 5;
982 return TRUE;
983 } else if (!strcmp ("op_Implicit", tm ) || !strcmp ("op_Explicit", tm)) {
984 MonoType *src = csignature->params [0];
985 MonoType *dst = csignature->ret;
986 int src_size = mini_magic_type_size (NULL, src);
987 int dst_size = mini_magic_type_size (NULL, dst);
989 gboolean store_value_as_local = FALSE;
991 switch (type_index) {
992 case 0: case 1:
993 if (!mini_magic_is_int_type (src) || !mini_magic_is_int_type (dst)) {
994 if (mini_magic_is_int_type (src))
995 store_value_as_local = TRUE;
996 else
997 return FALSE;
999 break;
1000 case 2:
1001 if (!mini_magic_is_float_type (src) || !mini_magic_is_float_type (dst)) {
1002 if (mini_magic_is_float_type (src))
1003 store_value_as_local = TRUE;
1004 else
1005 return FALSE;
1007 break;
1010 if (store_value_as_local) {
1011 emit_store_value_as_local (td, src);
1013 /* emit call to managed conversion method */
1014 return FALSE;
1017 #if SIZEOF_VOID_P == 4
1018 if (src_size > dst_size) { // 8 -> 4
1019 switch (type_index) {
1020 case 0: case 1:
1021 ADD_CODE (td, MINT_CONV_I4_I8);
1022 break;
1023 case 2:
1024 ADD_CODE (td, MINT_CONV_R4_R8);
1025 break;
1028 #endif
1030 #if SIZEOF_VOID_P == 8
1031 if (src_size < dst_size) { // 4 -> 8
1032 switch (type_index) {
1033 case 0:
1034 ADD_CODE (td, MINT_CONV_I8_I4);
1035 break;
1036 case 1:
1037 ADD_CODE (td, MINT_CONV_I8_U4);
1038 break;
1039 case 2:
1040 ADD_CODE (td, MINT_CONV_R8_R4);
1041 break;
1044 #endif
1046 SET_TYPE (td->sp - 1, stack_type [mt], magic_class);
1047 td->ip += 5;
1048 return TRUE;
1049 } else if (!strcmp ("op_Increment", tm)) {
1050 g_assert (type_index != 2); // no nfloat
1051 #if SIZEOF_VOID_P == 8
1052 ADD_CODE (td, MINT_ADD1_I8);
1053 #else
1054 ADD_CODE (td, MINT_ADD1_I4);
1055 #endif
1056 SET_TYPE (td->sp - 1, stack_type [mt], magic_class);
1057 td->ip += 5;
1058 return TRUE;
1059 } else if (!strcmp ("op_Decrement", tm)) {
1060 g_assert (type_index != 2); // no nfloat
1061 #if SIZEOF_VOID_P == 8
1062 ADD_CODE (td, MINT_SUB1_I8);
1063 #else
1064 ADD_CODE (td, MINT_SUB1_I4);
1065 #endif
1066 SET_TYPE (td->sp - 1, stack_type [mt], magic_class);
1067 td->ip += 5;
1068 return TRUE;
1069 } else if (!strcmp ("CompareTo", tm) || !strcmp ("Equals", tm)) {
1070 MonoType *arg = csignature->params [0];
1072 /* on 'System.n*::{CompareTo,Equals} (System.n*)' variant we need to push managed
1073 * pointer instead of value */
1074 if (arg->type == MONO_TYPE_VALUETYPE)
1075 emit_store_value_as_local (td, arg);
1077 /* emit call to managed conversion method */
1078 return FALSE;
1079 } else if (!strcmp (".cctor", tm)) {
1080 /* white list */
1081 return FALSE;
1082 } else if (!strcmp ("Parse", tm)) {
1083 /* white list */
1084 return FALSE;
1085 } else if (!strcmp ("ToString", tm)) {
1086 /* white list */
1087 return FALSE;
1088 } else if (!strcmp ("IsNaN", tm) || !strcmp ("IsInfinity", tm) || !strcmp ("IsNegativeInfinity", tm) || !strcmp ("IsPositiveInfinity", tm)) {
1089 g_assert (type_index == 2); // nfloat only
1090 /* white list */
1091 return FALSE;
1094 for (i = 0; i < sizeof (int_unnop) / sizeof (MagicIntrinsic); ++i) {
1095 if (!strcmp (int_unnop [i].op_name, tm)) {
1096 ADD_CODE (td, int_unnop [i].insn [type_index]);
1097 SET_TYPE (td->sp - 1, stack_type [mt], magic_class);
1098 td->ip += 5;
1099 return TRUE;
1103 for (i = 0; i < sizeof (int_binop) / sizeof (MagicIntrinsic); ++i) {
1104 if (!strcmp (int_binop [i].op_name, tm)) {
1105 ADD_CODE (td, int_binop [i].insn [type_index]);
1106 td->sp -= 1;
1107 SET_TYPE (td->sp - 1, stack_type [mt], magic_class);
1108 td->ip += 5;
1109 return TRUE;
1113 for (i = 0; i < sizeof (int_cmpop) / sizeof (MagicIntrinsic); ++i) {
1114 if (!strcmp (int_cmpop [i].op_name, tm)) {
1115 MonoClass *k = mono_defaults.boolean_class;
1116 ADD_CODE (td, int_cmpop [i].insn [type_index]);
1117 td->sp -= 1;
1118 SET_TYPE (td->sp - 1, stack_type [mint_type (m_class_get_byval_arg (k))], k);
1119 td->ip += 5;
1120 return TRUE;
1124 g_error ("TODO: interp_transform_call %s:%s", m_class_get_name (target_method->klass), tm);
1125 } else if (mono_class_is_subclass_of (target_method->klass, mono_defaults.array_class, FALSE)) {
1126 if (!strcmp (tm, "get_Rank")) {
1127 *op = MINT_ARRAY_RANK;
1128 } else if (!strcmp (tm, "get_Length")) {
1129 *op = MINT_LDLEN;
1130 } else if (!strcmp (tm, "Address")) {
1131 *op = readonly ? MINT_LDELEMA : MINT_LDELEMA_TC;
1132 } else if (!strcmp (tm, "UnsafeMov") || !strcmp (tm, "UnsafeLoad") || !strcmp (tm, "Set") || !strcmp (tm, "Get")) {
1133 *op = MINT_CALLRUN;
1134 } else if (!strcmp (tm, "UnsafeStore")) {
1135 g_error ("TODO ArrayClass::UnsafeStore");
1137 } else if (in_corlib &&
1138 !strcmp (klass_name_space, "System.Diagnostics") &&
1139 !strcmp (klass_name, "Debugger")) {
1140 if (!strcmp (tm, "Break") && csignature->param_count == 0) {
1141 if (mini_should_insert_breakpoint (td->method))
1142 *op = MINT_BREAK;
1144 } else if (in_corlib && !strcmp (klass_name_space, "System") && !strcmp (klass_name, "ByReference`1")) {
1145 *op = MINT_INTRINS_BYREFERENCE_GET_VALUE;
1146 } else if (in_corlib && !strcmp (klass_name_space, "System") && (!strcmp (klass_name, "Span`1") || !strcmp (klass_name, "ReadOnlySpan`1"))) {
1147 if (!strcmp (tm, "get_Item")) {
1148 MonoGenericClass *gclass = mono_class_get_generic_class (target_method->klass);
1149 MonoClass *param_class = mono_class_from_mono_type_internal (gclass->context.class_inst->type_argv [0]);
1151 if (!mini_is_gsharedvt_variable_klass (param_class)) {
1152 MonoClassField *length_field = mono_class_get_field_from_name_full (target_method->klass, "_length", NULL);
1153 g_assert (length_field);
1154 int offset_length = length_field->offset - sizeof (MonoObject);
1156 MonoClassField *ptr_field = mono_class_get_field_from_name_full (target_method->klass, "_pointer", NULL);
1157 g_assert (ptr_field);
1158 int offset_pointer = ptr_field->offset - sizeof (MonoObject);
1160 int size = mono_class_array_element_size (param_class);
1161 ADD_CODE (td, MINT_GETITEM_SPAN);
1162 ADD_CODE (td, size);
1163 ADD_CODE (td, offset_length);
1164 ADD_CODE (td, offset_pointer);
1166 SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_MP);
1167 td->sp -= 1;
1168 td->ip += 5;
1169 return TRUE;
1171 } else if (!strcmp (tm, "get_Length")) {
1172 MonoClassField *length_field = mono_class_get_field_from_name_full (target_method->klass, "_length", NULL);
1173 g_assert (length_field);
1174 int offset_length = length_field->offset - sizeof (MonoObject);
1175 ADD_CODE (td, MINT_LDLEN_SPAN);
1176 ADD_CODE (td, offset_length);
1177 SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I4);
1178 td->ip += 5;
1179 return TRUE;
1182 return FALSE;
1185 static MonoMethod*
1186 interp_transform_internal_calls (MonoMethod *method, MonoMethod *target_method, MonoMethodSignature *csignature, gboolean is_virtual)
1188 if (method->wrapper_type == MONO_WRAPPER_NONE && target_method != NULL) {
1189 if (target_method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1190 target_method = mono_marshal_get_native_wrapper (target_method, FALSE, FALSE);
1191 if (!is_virtual && target_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1192 target_method = mono_marshal_get_synchronized_wrapper (target_method);
1194 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)
1195 target_method = mono_marshal_get_native_wrapper (target_method, TRUE, FALSE);
1197 return target_method;
1200 static gboolean
1201 interp_type_as_ptr (MonoType *tp)
1203 if (MONO_TYPE_IS_POINTER (tp))
1204 return TRUE;
1205 if (MONO_TYPE_IS_REFERENCE (tp))
1206 return TRUE;
1207 if ((tp)->type == MONO_TYPE_I4)
1208 return TRUE;
1209 #if SIZEOF_VOID_P == 8
1210 if ((tp)->type == MONO_TYPE_I8)
1211 return TRUE;
1212 #endif
1213 if ((tp)->type == MONO_TYPE_BOOLEAN)
1214 return TRUE;
1215 if ((tp)->type == MONO_TYPE_CHAR)
1216 return TRUE;
1217 if ((tp)->type == MONO_TYPE_VALUETYPE && m_class_is_enumtype (tp->data.klass))
1218 return TRUE;
1219 return FALSE;
1222 #define INTERP_TYPE_AS_PTR(tp) interp_type_as_ptr (tp)
1224 static int
1225 interp_icall_op_for_sig (MonoMethodSignature *sig)
1227 int op = -1;
1228 switch (sig->param_count) {
1229 case 0:
1230 if (MONO_TYPE_IS_VOID (sig->ret))
1231 op = MINT_ICALL_V_V;
1232 else if (INTERP_TYPE_AS_PTR (sig->ret))
1233 op = MINT_ICALL_V_P;
1234 break;
1235 case 1:
1236 if (MONO_TYPE_IS_VOID (sig->ret)) {
1237 if (INTERP_TYPE_AS_PTR (sig->params [0]))
1238 op = MINT_ICALL_P_V;
1239 } else if (INTERP_TYPE_AS_PTR (sig->ret)) {
1240 if (INTERP_TYPE_AS_PTR (sig->params [0]))
1241 op = MINT_ICALL_P_P;
1243 break;
1244 case 2:
1245 if (MONO_TYPE_IS_VOID (sig->ret)) {
1246 if (INTERP_TYPE_AS_PTR (sig->params [0]) &&
1247 INTERP_TYPE_AS_PTR (sig->params [1]))
1248 op = MINT_ICALL_PP_V;
1249 } else if (INTERP_TYPE_AS_PTR (sig->ret)) {
1250 if (INTERP_TYPE_AS_PTR (sig->params [0]) &&
1251 INTERP_TYPE_AS_PTR (sig->params [1]))
1252 op = MINT_ICALL_PP_P;
1254 break;
1255 case 3:
1256 if (MONO_TYPE_IS_VOID (sig->ret)) {
1257 if (INTERP_TYPE_AS_PTR (sig->params [0]) &&
1258 INTERP_TYPE_AS_PTR (sig->params [1]) &&
1259 INTERP_TYPE_AS_PTR (sig->params [2]))
1260 op = MINT_ICALL_PPP_V;
1261 } else if (INTERP_TYPE_AS_PTR (sig->ret)) {
1262 if (INTERP_TYPE_AS_PTR (sig->params [0]) &&
1263 INTERP_TYPE_AS_PTR (sig->params [1]) &&
1264 INTERP_TYPE_AS_PTR (sig->params [2]))
1265 op = MINT_ICALL_PPP_P;
1267 break;
1268 case 4:
1269 if (MONO_TYPE_IS_VOID (sig->ret)) {
1270 if (INTERP_TYPE_AS_PTR (sig->params [0]) &&
1271 INTERP_TYPE_AS_PTR (sig->params [1]) &&
1272 INTERP_TYPE_AS_PTR (sig->params [2]) &&
1273 INTERP_TYPE_AS_PTR (sig->params [3]))
1274 op = MINT_ICALL_PPPP_V;
1275 } else if (INTERP_TYPE_AS_PTR (sig->ret)) {
1276 if (INTERP_TYPE_AS_PTR (sig->params [0]) &&
1277 INTERP_TYPE_AS_PTR (sig->params [1]) &&
1278 INTERP_TYPE_AS_PTR (sig->params [2]) &&
1279 INTERP_TYPE_AS_PTR (sig->params [3]))
1280 op = MINT_ICALL_PPPP_P;
1282 break;
1283 case 5:
1284 if (MONO_TYPE_IS_VOID (sig->ret)) {
1285 if (INTERP_TYPE_AS_PTR (sig->params [0]) &&
1286 INTERP_TYPE_AS_PTR (sig->params [1]) &&
1287 INTERP_TYPE_AS_PTR (sig->params [2]) &&
1288 INTERP_TYPE_AS_PTR (sig->params [3]) &&
1289 INTERP_TYPE_AS_PTR (sig->params [4]))
1290 op = MINT_ICALL_PPPPP_V;
1291 } else if (INTERP_TYPE_AS_PTR (sig->ret)) {
1292 if (INTERP_TYPE_AS_PTR (sig->params [0]) &&
1293 INTERP_TYPE_AS_PTR (sig->params [1]) &&
1294 INTERP_TYPE_AS_PTR (sig->params [2]) &&
1295 INTERP_TYPE_AS_PTR (sig->params [3]) &&
1296 INTERP_TYPE_AS_PTR (sig->params [4]))
1297 op = MINT_ICALL_PPPPP_P;
1299 break;
1300 case 6:
1301 if (MONO_TYPE_IS_VOID (sig->ret)) {
1302 if (INTERP_TYPE_AS_PTR (sig->params [0]) &&
1303 INTERP_TYPE_AS_PTR (sig->params [1]) &&
1304 INTERP_TYPE_AS_PTR (sig->params [2]) &&
1305 INTERP_TYPE_AS_PTR (sig->params [3]) &&
1306 INTERP_TYPE_AS_PTR (sig->params [4]) &&
1307 INTERP_TYPE_AS_PTR (sig->params [5]))
1308 op = MINT_ICALL_PPPPPP_V;
1309 } else if (INTERP_TYPE_AS_PTR (sig->ret)) {
1310 if (INTERP_TYPE_AS_PTR (sig->params [0]) &&
1311 INTERP_TYPE_AS_PTR (sig->params [1]) &&
1312 INTERP_TYPE_AS_PTR (sig->params [2]) &&
1313 INTERP_TYPE_AS_PTR (sig->params [3]) &&
1314 INTERP_TYPE_AS_PTR (sig->params [4]) &&
1315 INTERP_TYPE_AS_PTR (sig->params [5]))
1316 op = MINT_ICALL_PPPPPP_P;
1318 break;
1320 return op;
1323 static void
1324 interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target_method, MonoDomain *domain, MonoGenericContext *generic_context, unsigned char *is_bb_start, int body_start_offset, MonoClass *constrained_class, gboolean readonly, MonoError *error, gboolean check_visibility)
1326 MonoImage *image = m_class_get_image (method->klass);
1327 MonoMethodSignature *csignature;
1328 int is_virtual = *td->ip == CEE_CALLVIRT;
1329 int calli = *td->ip == CEE_CALLI || *td->ip == CEE_MONO_CALLI_EXTRA_ARG;
1330 int i;
1331 guint32 vt_stack_used = 0;
1332 guint32 vt_res_size = 0;
1333 int op = -1;
1334 int native = 0;
1335 int is_void = 0;
1336 int need_null_check = is_virtual;
1338 guint32 token = read32 (td->ip + 1);
1340 if (target_method == NULL) {
1341 if (calli) {
1342 CHECK_STACK(td, 1);
1343 if (method->wrapper_type != MONO_WRAPPER_NONE)
1344 csignature = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
1345 else {
1346 csignature = mono_metadata_parse_signature_checked (image, token, error);
1347 return_if_nok (error);
1350 if (generic_context) {
1351 csignature = mono_inflate_generic_signature (csignature, generic_context, error);
1352 return_if_nok (error);
1356 * The compiled interp entry wrapper is passed to runtime_invoke instead of
1357 * the InterpMethod pointer. FIXME
1359 native = csignature->pinvoke || method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE;
1360 --td->sp;
1362 target_method = NULL;
1363 } else {
1364 if (method->wrapper_type == MONO_WRAPPER_NONE) {
1365 target_method = mono_get_method_checked (image, token, NULL, generic_context, error);
1366 return_if_nok (error);
1367 } else
1368 target_method = (MonoMethod *)mono_method_get_wrapper_data (method, token);
1369 csignature = mono_method_signature_internal (target_method);
1371 if (generic_context) {
1372 csignature = mono_inflate_generic_signature (csignature, generic_context, error);
1373 return_if_nok (error);
1374 target_method = mono_class_inflate_generic_method_checked (target_method, generic_context, error);
1375 return_if_nok (error);
1378 } else {
1379 csignature = mono_method_signature_internal (target_method);
1382 if (check_visibility && target_method && !mono_method_can_access_method (method, target_method))
1383 interp_generate_mae_throw (td, method, target_method);
1385 if (target_method && target_method->string_ctor) {
1386 /* Create the real signature */
1387 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (td->mempool, csignature);
1388 ctor_sig->ret = m_class_get_byval_arg (mono_defaults.string_class);
1390 csignature = ctor_sig;
1393 /* Intrinsics */
1394 if (target_method && interp_handle_intrinsics (td, target_method, csignature, readonly, &op))
1395 return;
1397 if (constrained_class) {
1398 if (m_class_is_enumtype (constrained_class) && !strcmp (target_method->name, "GetHashCode")) {
1399 /* Use the corresponding method from the base type to avoid boxing */
1400 MonoType *base_type = mono_class_enum_basetype_internal (constrained_class);
1401 g_assert (base_type);
1402 constrained_class = mono_class_from_mono_type_internal (base_type);
1403 target_method = mono_class_get_method_from_name_checked (constrained_class, target_method->name, 0, 0, error);
1404 mono_error_assert_ok (error);
1405 g_assert (target_method);
1409 if (constrained_class) {
1410 mono_class_setup_vtable (constrained_class);
1411 if (mono_class_has_failure (constrained_class)) {
1412 mono_error_set_for_class_failure (error, constrained_class);
1413 return;
1415 #if DEBUG_INTERP
1416 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);
1417 #endif
1418 target_method = mono_get_method_constrained_with_method (image, target_method, constrained_class, generic_context, error);
1419 #if DEBUG_INTERP
1420 g_print (" : %s::%s. %s (%p)\n", target_method->klass->name, target_method->name, mono_signature_full_name (target_method->signature), target_method);
1421 #endif
1422 return_if_nok (error);
1423 mono_class_setup_vtable (target_method->klass);
1425 if (m_class_is_valuetype (constrained_class) && (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)) {
1426 if (target_method->klass == mono_defaults.enum_class && (td->sp - csignature->param_count - 1)->type == STACK_TYPE_MP) {
1427 /* managed pointer on the stack, we need to deref that puppy */
1428 ADD_CODE (td, MINT_LDIND_I);
1429 ADD_CODE (td, csignature->param_count);
1431 if (mint_type (m_class_get_byval_arg (constrained_class)) == MINT_TYPE_VT) {
1432 ADD_CODE (td, MINT_BOX_VT);
1433 ADD_CODE (td, get_data_item_index (td, constrained_class));
1434 ADD_CODE (td, csignature->param_count | ((td->sp - 1 - csignature->param_count)->type != STACK_TYPE_MP ? 0 : BOX_NOT_CLEAR_VT_SP));
1435 } else {
1436 ADD_CODE (td, MINT_BOX);
1437 ADD_CODE (td, get_data_item_index (td, constrained_class));
1438 ADD_CODE (td, csignature->param_count);
1440 } else if (!m_class_is_valuetype (constrained_class)) {
1441 /* managed pointer on the stack, we need to deref that puppy */
1442 ADD_CODE (td, MINT_LDIND_I);
1443 ADD_CODE (td, csignature->param_count);
1444 } else {
1445 if (m_class_is_valuetype (target_method->klass)) {
1446 /* Own method */
1447 } else {
1448 /* Interface method */
1449 int ioffset, slot;
1451 mono_class_setup_vtable (constrained_class);
1452 ioffset = mono_class_interface_offset (constrained_class, target_method->klass);
1453 if (ioffset == -1)
1454 g_error ("type load error: constrained_class");
1455 slot = mono_method_get_vtable_slot (target_method);
1456 if (slot == -1)
1457 g_error ("type load error: target_method->klass");
1458 target_method = m_class_get_vtable (constrained_class) [ioffset + slot];
1460 if (target_method->klass == mono_defaults.enum_class) {
1461 if ((td->sp - csignature->param_count - 1)->type == STACK_TYPE_MP) {
1462 /* managed pointer on the stack, we need to deref that puppy */
1463 ADD_CODE (td, MINT_LDIND_I);
1464 ADD_CODE (td, csignature->param_count);
1466 if (mint_type (m_class_get_byval_arg (constrained_class)) == MINT_TYPE_VT) {
1467 ADD_CODE (td, MINT_BOX_VT);
1468 ADD_CODE (td, get_data_item_index (td, constrained_class));
1469 ADD_CODE (td, csignature->param_count | ((td->sp - 1 - csignature->param_count)->type != STACK_TYPE_MP ? 0 : BOX_NOT_CLEAR_VT_SP));
1470 } else {
1471 ADD_CODE (td, MINT_BOX);
1472 ADD_CODE (td, get_data_item_index (td, constrained_class));
1473 ADD_CODE (td, csignature->param_count);
1477 is_virtual = FALSE;
1481 if (target_method)
1482 mono_class_init (target_method->klass);
1484 if (!is_virtual && target_method && (target_method->flags & METHOD_ATTRIBUTE_ABSTRACT))
1485 /* MS.NET seems to silently convert this to a callvirt */
1486 is_virtual = TRUE;
1488 if (is_virtual && target_method && (!(target_method->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
1489 (MONO_METHOD_IS_FINAL (target_method) &&
1490 target_method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
1491 !(mono_class_is_marshalbyref (target_method->klass))) {
1492 /* Not really virtual, just needs a null check */
1493 is_virtual = FALSE;
1494 need_null_check = TRUE;
1497 CHECK_STACK (td, csignature->param_count + csignature->hasthis);
1498 if (!calli && op == -1 && (!is_virtual || (target_method->flags & METHOD_ATTRIBUTE_VIRTUAL) == 0) &&
1499 (target_method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 &&
1500 (target_method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) == 0 &&
1501 !(target_method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING)) {
1502 MonoVTable *vt = mono_class_vtable_checked (domain, target_method->klass, error);
1503 return_if_nok (error);
1504 int called_inited = vt->initialized;
1506 if (method == target_method && *(td->ip + 5) == CEE_RET && !(csignature->hasthis && m_class_is_valuetype (target_method->klass))) {
1507 int offset;
1508 if (td->verbose_level)
1509 g_print ("Optimize tail call of %s.%s\n", m_class_get_name (target_method->klass), target_method->name);
1511 for (i = csignature->param_count - 1 + !!csignature->hasthis; i >= 0; --i)
1512 store_arg (td, i);
1514 ADD_CODE(td, MINT_BR_S);
1515 offset = body_start_offset - ((td->new_ip - 1) - td->new_code);
1516 ADD_CODE(td, offset);
1517 if (!is_bb_start [td->ip + 5 - td->il_code])
1518 ++td->ip; /* gobble the CEE_RET if it isn't branched to */
1519 td->ip += 5;
1520 return;
1521 } else {
1522 MonoMethodHeader *mheader = interp_method_get_header (target_method, error);
1523 return_if_nok (error);
1524 /* mheader might not exist if this is a delegate invoc, etc */
1525 gboolean has_vt_arg = FALSE;
1526 for (i = 0; i < csignature->param_count; i++)
1527 has_vt_arg |= !mini_type_is_reference (csignature->params [i]);
1529 gboolean empty_callee = mheader && *mheader->code == CEE_RET;
1530 mono_metadata_free_mh (mheader);
1532 if (empty_callee && called_inited && !has_vt_arg) {
1533 if (td->verbose_level)
1534 g_print ("Inline (empty) call of %s.%s\n", m_class_get_name (target_method->klass), target_method->name);
1535 for (i = 0; i < csignature->param_count; i++) {
1536 ADD_CODE (td, MINT_POP); /*FIX: vt */
1537 ADD_CODE (td, 0);
1539 if (csignature->hasthis) {
1540 if (is_virtual || need_null_check)
1541 ADD_CODE (td, MINT_CKNULL);
1542 ADD_CODE (td, MINT_POP);
1543 ADD_CODE (td, 0);
1545 td->sp -= csignature->param_count + csignature->hasthis;
1546 td->ip += 5;
1547 return;
1552 target_method = interp_transform_internal_calls (method, target_method, csignature, is_virtual);
1554 if (csignature->call_convention == MONO_CALL_VARARG) {
1555 csignature = mono_method_get_signature_checked (target_method, image, token, generic_context, error);
1556 int vararg_stack = 0;
1558 * For vararg calls, ArgIterator expects the signature and the varargs to be
1559 * stored in a linear memory. We allocate the necessary vt_stack space for
1560 * this. All varargs will be pushed to the vt_stack at call site.
1562 vararg_stack += sizeof (gpointer);
1563 for (i = csignature->sentinelpos; i < csignature->param_count; ++i) {
1564 int align, arg_size;
1565 arg_size = mono_type_stack_size (csignature->params [i], &align);
1566 vararg_stack += arg_size;
1568 vt_stack_used += ALIGN_TO (vararg_stack, MINT_VT_ALIGNMENT);
1569 PUSH_VT (td, vararg_stack);
1572 g_assert (csignature->call_convention != MONO_CALL_FASTCALL);
1573 td->sp -= csignature->param_count + !!csignature->hasthis;
1574 for (i = 0; i < csignature->param_count; ++i) {
1575 if (td->sp [i + !!csignature->hasthis].type == STACK_TYPE_VT) {
1576 gint32 size;
1577 MonoClass *klass = mono_class_from_mono_type_internal (csignature->params [i]);
1578 if (csignature->pinvoke && method->wrapper_type != MONO_WRAPPER_NONE)
1579 size = mono_class_native_size (klass, NULL);
1580 else
1581 size = mono_class_value_size (klass, NULL);
1582 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
1583 vt_stack_used += size;
1587 if (need_null_check) {
1588 ADD_CODE (td, MINT_CKNULL_N);
1589 ADD_CODE (td, csignature->param_count + 1);
1592 /* need to handle typedbyref ... */
1593 if (csignature->ret->type != MONO_TYPE_VOID) {
1594 int mt = mint_type(csignature->ret);
1595 MonoClass *klass = mono_class_from_mono_type_internal (csignature->ret);
1596 if (mt == MINT_TYPE_VT) {
1597 if (csignature->pinvoke && method->wrapper_type != MONO_WRAPPER_NONE)
1598 vt_res_size = mono_class_native_size (klass, NULL);
1599 else
1600 vt_res_size = mono_class_value_size (klass, NULL);
1601 if (mono_class_has_failure (klass)) {
1602 mono_error_set_for_class_failure (error, klass);
1603 return;
1605 PUSH_VT(td, vt_res_size);
1607 PUSH_TYPE(td, stack_type[mt], klass);
1608 } else
1609 is_void = TRUE;
1611 /* We need to convert delegate invoke to a indirect call on the interp_invoke_impl field */
1612 if (target_method && m_class_get_parent (target_method->klass) == mono_defaults.multicastdelegate_class) {
1613 const char *name = target_method->name;
1614 if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
1615 calli = TRUE;
1616 ADD_CODE (td, MINT_LD_DELEGATE_INVOKE_IMPL);
1617 ADD_CODE (td, csignature->param_count + 1);
1621 if (op >= 0) {
1622 ADD_CODE (td, op);
1624 if (op == MINT_LDLEN) {
1625 #ifdef MONO_BIG_ARRAYS
1626 SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I8);
1627 #else
1628 SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I4);
1629 #endif
1631 if (op == MINT_LDELEMA || op == MINT_LDELEMA_TC) {
1632 ADD_CODE (td, get_data_item_index (td, target_method->klass));
1633 ADD_CODE (td, 1 + m_class_get_rank (target_method->klass));
1636 if (op == MINT_CALLRUN) {
1637 ADD_CODE (td, get_data_item_index (td, target_method));
1638 ADD_CODE (td, get_data_item_index (td, mono_method_signature_internal (target_method)));
1640 } else if (!calli && !is_virtual && jit_call_supported (target_method, csignature)) {
1641 ADD_CODE(td, MINT_JIT_CALL);
1642 ADD_CODE(td, get_data_item_index (td, (void *)mono_interp_get_imethod (domain, target_method, error)));
1643 mono_error_assert_ok (error);
1644 } else {
1645 /* Try using fast icall path for simple signatures */
1646 if (native && !method->dynamic)
1647 op = interp_icall_op_for_sig (csignature);
1648 if (calli)
1649 ADD_CODE(td, native ? ((op != -1) ? MINT_CALLI_NAT_FAST : MINT_CALLI_NAT) : MINT_CALLI);
1650 else if (is_virtual)
1651 ADD_CODE(td, is_void ? MINT_VCALLVIRT : MINT_CALLVIRT);
1652 else
1653 ADD_CODE(td, is_void ? MINT_VCALL : MINT_CALL);
1655 if (calli) {
1656 ADD_CODE(td, get_data_item_index (td, (void *)csignature));
1657 if (op != -1)
1658 ADD_CODE (td, op);
1659 } else {
1660 ADD_CODE(td, get_data_item_index (td, (void *)mono_interp_get_imethod (domain, target_method, error)));
1661 return_if_nok (error);
1662 if (csignature->call_convention == MONO_CALL_VARARG)
1663 ADD_CODE(td, get_data_item_index (td, (void *)csignature));
1666 td->ip += 5;
1667 if (vt_stack_used != 0 || vt_res_size != 0) {
1668 ADD_CODE(td, MINT_VTRESULT);
1669 ADD_CODE(td, vt_res_size);
1670 WRITE32(td, &vt_stack_used);
1671 td->vt_sp -= vt_stack_used;
1675 static MonoClassField *
1676 interp_field_from_token (MonoMethod *method, guint32 token, MonoClass **klass, MonoGenericContext *generic_context, MonoError *error)
1678 MonoClassField *field = NULL;
1679 if (method->wrapper_type != MONO_WRAPPER_NONE) {
1680 field = (MonoClassField *) mono_method_get_wrapper_data (method, token);
1681 *klass = field->parent;
1682 } else {
1683 field = mono_field_from_token_checked (m_class_get_image (method->klass), token, klass, generic_context, error);
1684 return_val_if_nok (error, NULL);
1687 if (!method->skip_visibility && !mono_method_can_access_field (method, field)) {
1688 char *method_fname = mono_method_full_name (method, TRUE);
1689 char *field_fname = mono_field_full_name (field);
1690 mono_error_set_generic_error (error, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
1691 g_free (method_fname);
1692 g_free (field_fname);
1693 return NULL;
1696 return field;
1699 static InterpBasicBlock*
1700 get_bb (TransformData *td, InterpBasicBlock *cbb, unsigned char *ip)
1702 int offset = ip - td->il_code;
1703 InterpBasicBlock *bb = td->offset_to_bb [offset];
1705 if (!bb) {
1706 bb = (InterpBasicBlock*)mono_mempool_alloc0 (td->mempool, sizeof (InterpBasicBlock));
1707 bb->ip = ip;
1708 td->offset_to_bb [offset] = bb;
1710 td->basic_blocks = g_list_append_mempool (td->mempool, td->basic_blocks, bb);
1713 if (cbb)
1714 bb->preds = g_slist_prepend_mempool (td->mempool, bb->preds, cbb);
1715 return bb;
1719 * get_basic_blocks:
1721 * Compute the set of IL level basic blocks.
1723 static void
1724 get_basic_blocks (TransformData *td)
1726 guint8 *start = (guint8*)td->il_code;
1727 guint8 *end = (guint8*)td->il_code + td->code_size;
1728 guint8 *ip = start;
1729 unsigned char *target;
1730 int i;
1731 guint cli_addr;
1732 const MonoOpcode *opcode;
1733 InterpBasicBlock *cbb;
1735 td->offset_to_bb = (InterpBasicBlock**)mono_mempool_alloc0 (td->mempool, sizeof (InterpBasicBlock*) * (end - start + 1));
1736 td->entry_bb = cbb = get_bb (td, NULL, start);
1738 while (ip < end) {
1739 cli_addr = ip - start;
1740 td->offset_to_bb [cli_addr] = cbb;
1741 i = mono_opcode_value ((const guint8 **)&ip, end);
1742 opcode = &mono_opcodes [i];
1743 switch (opcode->argument) {
1744 case MonoInlineNone:
1745 ip++;
1746 break;
1747 case MonoInlineString:
1748 case MonoInlineType:
1749 case MonoInlineField:
1750 case MonoInlineMethod:
1751 case MonoInlineTok:
1752 case MonoInlineSig:
1753 case MonoShortInlineR:
1754 case MonoInlineI:
1755 ip += 5;
1756 break;
1757 case MonoInlineVar:
1758 ip += 3;
1759 break;
1760 case MonoShortInlineVar:
1761 case MonoShortInlineI:
1762 ip += 2;
1763 break;
1764 case MonoShortInlineBrTarget:
1765 target = start + cli_addr + 2 + (signed char)ip [1];
1766 get_bb (td, cbb, target);
1767 ip += 2;
1768 cbb = get_bb (td, cbb, ip);
1769 break;
1770 case MonoInlineBrTarget:
1771 target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
1772 get_bb (td, cbb, target);
1773 ip += 5;
1774 cbb = get_bb (td, cbb, ip);
1775 break;
1776 case MonoInlineSwitch: {
1777 guint32 n = read32 (ip + 1);
1778 guint32 j;
1779 ip += 5;
1780 cli_addr += 5 + 4 * n;
1781 target = start + cli_addr;
1782 get_bb (td, cbb, target);
1784 for (j = 0; j < n; ++j) {
1785 target = start + cli_addr + (gint32)read32 (ip);
1786 get_bb (td, cbb, target);
1787 ip += 4;
1789 cbb = get_bb (td, cbb, ip);
1790 break;
1792 case MonoInlineR:
1793 case MonoInlineI8:
1794 ip += 9;
1795 break;
1796 default:
1797 g_assert_not_reached ();
1800 if (i == CEE_THROW)
1801 cbb = get_bb (td, NULL, ip);
1805 static void
1806 interp_save_debug_info (InterpMethod *rtm, MonoMethodHeader *header, TransformData *td, GArray *line_numbers)
1808 MonoDebugMethodJitInfo *dinfo;
1809 int i;
1811 if (!mono_debug_enabled ())
1812 return;
1815 * We save the debug info in the same way the JIT does it, treating the interpreter IR as the native code.
1818 dinfo = g_new0 (MonoDebugMethodJitInfo, 1);
1819 dinfo->num_params = rtm->param_count;
1820 dinfo->params = g_new0 (MonoDebugVarInfo, dinfo->num_params);
1821 dinfo->num_locals = header->num_locals;
1822 dinfo->locals = g_new0 (MonoDebugVarInfo, header->num_locals);
1823 dinfo->code_start = (guint8*)rtm->code;
1824 dinfo->code_size = td->new_ip - td->new_code;
1825 dinfo->epilogue_begin = 0;
1826 dinfo->has_var_info = TRUE;
1827 dinfo->num_line_numbers = line_numbers->len;
1828 dinfo->line_numbers = g_new0 (MonoDebugLineNumberEntry, dinfo->num_line_numbers);
1830 for (i = 0; i < dinfo->num_params; i++) {
1831 MonoDebugVarInfo *var = &dinfo->params [i];
1832 var->type = rtm->param_types [i];
1834 for (i = 0; i < dinfo->num_locals; i++) {
1835 MonoDebugVarInfo *var = &dinfo->locals [i];
1836 var->type = mono_metadata_type_dup (NULL, header->locals [i]);
1839 for (i = 0; i < dinfo->num_line_numbers; i++)
1840 dinfo->line_numbers [i] = g_array_index (line_numbers, MonoDebugLineNumberEntry, i);
1841 mono_debug_add_method (rtm->method, dinfo, rtm->domain);
1843 mono_debug_free_method_jit_info (dinfo);
1846 /* Same as the code in seq-points.c */
1847 static void
1848 insert_pred_seq_point (SeqPoint *last_sp, SeqPoint *sp, GSList **next)
1850 GSList *l;
1851 int src_index = last_sp->next_offset;
1852 int dst_index = sp->next_offset;
1854 /* bb->in_bb might contain duplicates */
1855 for (l = next [src_index]; l; l = l->next)
1856 if (GPOINTER_TO_UINT (l->data) == dst_index)
1857 break;
1858 if (!l)
1859 next [src_index] = g_slist_append (next [src_index], GUINT_TO_POINTER (dst_index));
1862 static void
1863 recursively_make_pred_seq_points (TransformData *td, InterpBasicBlock *bb)
1865 SeqPoint ** const MONO_SEQ_SEEN_LOOP = (SeqPoint**)GINT_TO_POINTER(-1);
1866 GSList *l;
1868 GArray *predecessors = g_array_new (FALSE, TRUE, sizeof (gpointer));
1869 GHashTable *seen = g_hash_table_new_full (g_direct_hash, NULL, NULL, NULL);
1871 // Insert/remove sentinel into the memoize table to detect loops containing bb
1872 bb->pred_seq_points = MONO_SEQ_SEEN_LOOP;
1874 for (l = bb->preds; l; l = l->next) {
1875 InterpBasicBlock *in_bb = (InterpBasicBlock*)l->data;
1877 // This bb has the last seq point, append it and continue
1878 if (in_bb->last_seq_point != NULL) {
1879 predecessors = g_array_append_val (predecessors, in_bb->last_seq_point);
1880 continue;
1883 // We've looped or handled this before, exit early.
1884 // No last sequence points to find.
1885 if (in_bb->pred_seq_points == MONO_SEQ_SEEN_LOOP)
1886 continue;
1888 // Take sequence points from incoming basic blocks
1890 if (in_bb == td->entry_bb)
1891 continue;
1893 if (in_bb->pred_seq_points == NULL)
1894 recursively_make_pred_seq_points (td, in_bb);
1896 // Union sequence points with incoming bb's
1897 for (int i=0; i < in_bb->num_pred_seq_points; i++) {
1898 if (!g_hash_table_lookup (seen, in_bb->pred_seq_points [i])) {
1899 g_array_append_val (predecessors, in_bb->pred_seq_points [i]);
1900 g_hash_table_insert (seen, in_bb->pred_seq_points [i], (gpointer)&MONO_SEQ_SEEN_LOOP);
1903 // predecessors = g_array_append_vals (predecessors, in_bb->pred_seq_points, in_bb->num_pred_seq_points);
1906 g_hash_table_destroy (seen);
1908 if (predecessors->len != 0) {
1909 bb->pred_seq_points = (SeqPoint**)mono_mempool_alloc0 (td->mempool, sizeof (SeqPoint *) * predecessors->len);
1910 bb->num_pred_seq_points = predecessors->len;
1912 for (int newer = 0; newer < bb->num_pred_seq_points; newer++) {
1913 bb->pred_seq_points [newer] = (SeqPoint*)g_array_index (predecessors, gpointer, newer);
1917 g_array_free (predecessors, TRUE);
1920 static void
1921 collect_pred_seq_points (TransformData *td, InterpBasicBlock *bb, SeqPoint *seqp, GSList **next)
1923 // Doesn't have a last sequence point, must find from incoming basic blocks
1924 if (bb->pred_seq_points == NULL && bb != td->entry_bb)
1925 recursively_make_pred_seq_points (td, bb);
1927 for (int i = 0; i < bb->num_pred_seq_points; i++)
1928 insert_pred_seq_point (bb->pred_seq_points [i], seqp, next);
1930 return;
1933 static void
1934 save_seq_points (TransformData *td, MonoJitInfo *jinfo)
1936 InterpMethod *rtm = td->rtm;
1937 GByteArray *array;
1938 int i, seq_info_size;
1939 MonoSeqPointInfo *info;
1940 MonoDomain *domain = mono_domain_get ();
1941 GSList **next = NULL;
1942 GList *bblist;
1944 if (!td->gen_sdb_seq_points)
1945 return;
1948 * For each sequence point, compute the list of sequence points immediately
1949 * following it, this is needed to implement 'step over' in the debugger agent.
1950 * Similar to the code in mono_save_seq_point_info ().
1952 for (i = 0; i < td->seq_points->len; ++i) {
1953 SeqPoint *sp = (SeqPoint*)g_ptr_array_index (td->seq_points, i);
1955 /* Store the seq point index here temporarily */
1956 sp->next_offset = i;
1958 next = (GSList**)mono_mempool_alloc0 (td->mempool, sizeof (GList*) * td->seq_points->len);
1959 for (bblist = td->basic_blocks; bblist; bblist = bblist->next) {
1960 InterpBasicBlock *bb = (InterpBasicBlock*)bblist->data;
1962 GSList *bb_seq_points = g_slist_reverse (bb->seq_points);
1963 SeqPoint *last = NULL;
1964 for (GSList *l = bb_seq_points; l; l = l->next) {
1965 SeqPoint *sp = (SeqPoint*)l->data;
1967 if (sp->il_offset == METHOD_ENTRY_IL_OFFSET || sp->il_offset == METHOD_EXIT_IL_OFFSET)
1968 /* Used to implement method entry/exit events */
1969 continue;
1971 if (last != NULL) {
1972 /* Link with the previous seq point in the same bb */
1973 next [last->next_offset] = g_slist_append_mempool (td->mempool, next [last->next_offset], GINT_TO_POINTER (sp->next_offset));
1974 } else {
1975 /* Link with the last bb in the previous bblocks */
1976 collect_pred_seq_points (td, bb, sp, next);
1978 last = sp;
1982 /* Serialize the seq points into a byte array */
1983 array = g_byte_array_new ();
1984 SeqPoint zero_seq_point = {0};
1985 SeqPoint* last_seq_point = &zero_seq_point;
1986 for (i = 0; i < td->seq_points->len; ++i) {
1987 SeqPoint *sp = (SeqPoint*)g_ptr_array_index (td->seq_points, i);
1989 sp->next_offset = 0;
1990 if (mono_seq_point_info_add_seq_point (array, sp, last_seq_point, next [i], TRUE))
1991 last_seq_point = sp;
1994 if (td->verbose_level) {
1995 g_print ("\nSEQ POINT MAP FOR %s: \n", td->method->name);
1997 for (i = 0; i < td->seq_points->len; ++i) {
1998 SeqPoint *sp = (SeqPoint*)g_ptr_array_index (td->seq_points, i);
1999 GSList *l;
2001 if (!next [i])
2002 continue;
2004 g_print ("\tIL0x%x[0x%0x] ->", sp->il_offset, sp->native_offset);
2005 for (l = next [i]; l; l = l->next) {
2006 int next_index = GPOINTER_TO_UINT (l->data);
2007 g_print (" IL0x%x", ((SeqPoint*)g_ptr_array_index (td->seq_points, next_index))->il_offset);
2009 g_print ("\n");
2013 info = mono_seq_point_info_new (array->len, TRUE, array->data, TRUE, &seq_info_size);
2014 mono_atomic_fetch_add_i32 (&mono_jit_stats.allocated_seq_points_size, seq_info_size);
2016 g_byte_array_free (array, TRUE);
2018 mono_domain_lock (domain);
2019 g_hash_table_insert (domain_jit_info (domain)->seq_points, rtm->method, info);
2020 mono_domain_unlock (domain);
2022 jinfo->seq_points = info;
2025 static void
2026 emit_seq_point (TransformData *td, int il_offset, InterpBasicBlock *cbb, gboolean nonempty_stack)
2028 SeqPoint *seqp;
2030 seqp = (SeqPoint*)mono_mempool_alloc0 (td->mempool, sizeof (SeqPoint));
2031 seqp->il_offset = il_offset;
2032 seqp->native_offset = (guint8*)td->new_ip - (guint8*)td->new_code;
2033 if (nonempty_stack)
2034 seqp->flags |= MONO_SEQ_POINT_FLAG_NONEMPTY_STACK;
2036 ADD_CODE (td, MINT_SDB_SEQ_POINT);
2037 g_ptr_array_add (td->seq_points, seqp);
2039 cbb->seq_points = g_slist_prepend_mempool (td->mempool, cbb->seq_points, seqp);
2040 cbb->last_seq_point = seqp;
2043 #define BARRIER_IF_VOLATILE(td) \
2044 do { \
2045 if (volatile_) { \
2046 ADD_CODE (td, MINT_MONO_MEMORY_BARRIER); \
2047 volatile_ = FALSE; \
2049 } while (0)
2051 static void
2052 generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsigned char *is_bb_start, MonoGenericContext *generic_context, MonoError *error)
2054 MonoMethodSignature *signature = mono_method_signature_internal (method);
2055 MonoImage *image = m_class_get_image (method->klass);
2056 MonoDomain *domain = rtm->domain;
2057 MonoClass *constrained_class = NULL;
2058 MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
2059 int offset, mt, i, i32;
2060 gboolean readonly = FALSE;
2061 gboolean volatile_ = FALSE;
2062 MonoClass *klass;
2063 MonoClassField *field;
2064 const unsigned char *end;
2065 int new_in_start_offset;
2066 int body_start_offset;
2067 int target;
2068 guint32 token;
2069 TransformData transform_data;
2070 TransformData *td;
2071 GArray *line_numbers;
2072 MonoDebugMethodInfo *minfo;
2073 MonoBitSet *seq_point_locs = NULL;
2074 MonoBitSet *seq_point_set_locs = NULL;
2075 gboolean sym_seq_points = FALSE;
2076 InterpBasicBlock *bb_exit = NULL;
2077 static gboolean verbose_method_inited;
2078 static char* verbose_method_name;
2080 if (!verbose_method_inited) {
2081 verbose_method_name = g_getenv ("MONO_VERBOSE_METHOD");
2082 verbose_method_inited = TRUE;
2085 memset (&transform_data, 0, sizeof(transform_data));
2086 td = &transform_data;
2088 td->method = method;
2089 td->rtm = rtm;
2090 td->is_bb_start = is_bb_start;
2091 td->il_code = header->code;
2092 td->code_size = header->code_size;
2093 td->header = header;
2094 td->max_code_size = td->code_size;
2095 td->new_code = (unsigned short *)g_malloc(td->max_code_size * sizeof(gushort));
2096 td->new_code_end = td->new_code + td->max_code_size;
2097 td->mempool = mono_mempool_new ();
2098 td->in_offsets = (int*)g_malloc0((header->code_size + 1) * sizeof(int));
2099 td->stack_state = (StackInfo**)g_malloc0(header->code_size * sizeof(StackInfo *));
2100 td->stack_height = (int*)g_malloc(header->code_size * sizeof(int));
2101 td->vt_stack_size = (int*)g_malloc(header->code_size * sizeof(int));
2102 td->n_data_items = 0;
2103 td->max_data_items = 0;
2104 td->data_items = NULL;
2105 td->data_hash = g_hash_table_new (NULL, NULL);
2106 td->clause_indexes = (int*)g_malloc (header->code_size * sizeof (int));
2107 td->gen_sdb_seq_points = mini_debug_options.gen_sdb_seq_points;
2108 td->seq_points = g_ptr_array_new ();
2109 td->relocs = g_ptr_array_new ();
2110 td->verbose_level = mono_interp_traceopt;
2111 td->total_locals_size = rtm->locals_size;
2112 rtm->data_items = td->data_items;
2113 for (i = 0; i < header->code_size; i++) {
2114 td->stack_height [i] = -1;
2115 td->clause_indexes [i] = -1;
2118 if (verbose_method_name) {
2119 const char *name = verbose_method_name;
2121 if ((strchr (name, '.') > name) || strchr (name, ':')) {
2122 MonoMethodDesc *desc;
2124 desc = mono_method_desc_new (name, TRUE);
2125 if (mono_method_desc_full_match (desc, method)) {
2126 td->verbose_level = 4;
2128 mono_method_desc_free (desc);
2129 } else {
2130 if (strcmp (method->name, name) == 0)
2131 td->verbose_level = 4;
2135 if (td->gen_sdb_seq_points) {
2136 get_basic_blocks (td);
2138 minfo = mono_debug_lookup_method (method);
2140 if (minfo) {
2141 MonoSymSeqPoint *sps;
2142 int i, n_il_offsets;
2144 mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
2145 // FIXME: Free
2146 seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (td->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
2147 seq_point_set_locs = mono_bitset_mem_new (mono_mempool_alloc0 (td->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
2148 sym_seq_points = TRUE;
2150 for (i = 0; i < n_il_offsets; ++i) {
2151 if (sps [i].il_offset < header->code_size)
2152 mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
2154 g_free (sps);
2156 MonoDebugMethodAsyncInfo* asyncMethod = mono_debug_lookup_method_async_debug_info (method);
2157 if (asyncMethod) {
2158 for (i = 0; asyncMethod != NULL && i < asyncMethod->num_awaits; i++) {
2159 mono_bitset_set_fast (seq_point_locs, asyncMethod->resume_offsets [i]);
2160 mono_bitset_set_fast (seq_point_locs, asyncMethod->yield_offsets [i]);
2162 mono_debug_free_method_async_debug_info (asyncMethod);
2164 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (m_class_get_image (method->klass))) {
2165 /* Methods without line number info like auto-generated property accessors */
2166 seq_point_locs = mono_bitset_new (header->code_size, 0);
2167 seq_point_set_locs = mono_bitset_new (header->code_size, 0);
2168 sym_seq_points = TRUE;
2172 td->new_ip = td->new_code;
2173 td->last_new_ip = NULL;
2175 td->stack = (StackInfo*)g_malloc0 ((header->max_stack + 1) * sizeof (td->stack [0]));
2176 td->stack_capacity = header->max_stack + 1;
2177 td->sp = td->stack;
2178 td->max_stack_height = 0;
2180 line_numbers = g_array_new (FALSE, TRUE, sizeof (MonoDebugLineNumberEntry));
2182 for (i = 0; i < header->num_clauses; i++) {
2183 MonoExceptionClause *c = header->clauses + i;
2184 td->stack_height [c->handler_offset] = 0;
2185 td->vt_stack_size [c->handler_offset] = 0;
2186 td->is_bb_start [c->handler_offset] = 1;
2188 td->stack_height [c->handler_offset] = 1;
2189 td->stack_state [c->handler_offset] = (StackInfo*)g_malloc0(sizeof(StackInfo));
2190 td->stack_state [c->handler_offset][0].type = STACK_TYPE_O;
2191 td->stack_state [c->handler_offset][0].klass = NULL; /*FIX*/
2193 if (c->flags & MONO_EXCEPTION_CLAUSE_FILTER) {
2194 td->stack_height [c->data.filter_offset] = 0;
2195 td->vt_stack_size [c->data.filter_offset] = 0;
2196 td->is_bb_start [c->data.filter_offset] = 1;
2198 td->stack_height [c->data.filter_offset] = 1;
2199 td->stack_state [c->data.filter_offset] = (StackInfo*)g_malloc0(sizeof(StackInfo));
2200 td->stack_state [c->data.filter_offset][0].type = STACK_TYPE_O;
2201 td->stack_state [c->data.filter_offset][0].klass = NULL; /*FIX*/
2204 for (int j = c->handler_offset; j < c->handler_offset + c->handler_len; ++j) {
2205 if (td->clause_indexes [j] == -1)
2206 td->clause_indexes [j] = i;
2210 td->ip = header->code;
2211 end = td->ip + header->code_size;
2213 if (td->verbose_level) {
2214 char *tmp = mono_disasm_code (NULL, method, td->ip, end);
2215 char *name = mono_method_full_name (method, TRUE);
2216 g_print ("Method %s, original code:\n", name);
2217 g_print ("%s\n", tmp);
2218 g_free (tmp);
2219 g_free (name);
2222 if (signature->hasthis)
2223 store_inarg (td, 0);
2224 for (i = 0; i < signature->param_count; i++)
2225 store_inarg (td, i + !!signature->hasthis);
2227 body_start_offset = td->new_ip - td->new_code;
2229 for (i = 0; i < header->num_locals; i++) {
2230 int mt = mint_type(header->locals [i]);
2231 if (mt == MINT_TYPE_VT || mt == MINT_TYPE_O || mt == MINT_TYPE_P) {
2232 ADD_CODE(td, MINT_INITLOCALS);
2233 break;
2237 if (rtm->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ENTER)
2238 ADD_CODE (td, MINT_PROF_ENTER);
2240 /* safepoint is required on method entry */
2241 if (mono_threads_are_safepoints_enabled ())
2242 ADD_CODE (td, MINT_SAFEPOINT);
2244 if (sym_seq_points) {
2245 InterpBasicBlock *cbb = td->offset_to_bb [0];
2246 g_assert (cbb);
2247 emit_seq_point (td, METHOD_ENTRY_IL_OFFSET, cbb, FALSE);
2250 original_bb = bb = mono_basic_block_split (method, error, header);
2251 goto_if_nok (error, exit);
2252 g_assert (bb);
2254 int in_offset;
2255 while (td->ip < end) {
2256 g_assert (td->sp >= td->stack);
2257 g_assert (td->vt_sp < 0x10000000);
2258 in_offset = td->ip - header->code;
2259 td->in_offsets [in_offset] = td->new_ip - td->new_code;
2260 new_in_start_offset = td->new_ip - td->new_code;
2261 td->in_start = td->ip;
2263 MonoDebugLineNumberEntry lne;
2264 lne.native_offset = (guint8*)td->new_ip - (guint8*)td->new_code;
2265 lne.il_offset = in_offset;
2266 g_array_append_val (line_numbers, lne);
2268 if (td->stack_height [in_offset] >= 0) {
2269 g_assert (is_bb_start [in_offset]);
2270 if (td->stack_height [in_offset] > 0)
2271 memcpy (td->stack, td->stack_state [in_offset], td->stack_height [in_offset] * sizeof(td->stack [0]));
2272 td->sp = td->stack + td->stack_height [in_offset];
2273 td->vt_sp = td->vt_stack_size [in_offset];
2276 if (in_offset == bb->end)
2277 bb = bb->next;
2279 if (bb->dead) {
2280 int op_size = mono_opcode_size (td->ip, end);
2281 g_assert (op_size > 0); /* The BB formation pass must catch all bad ops */
2283 if (td->verbose_level > 1)
2284 g_print ("SKIPPING DEAD OP at %x\n", in_offset);
2286 td->ip += op_size;
2287 continue;
2290 if (td->verbose_level > 1) {
2291 g_print ("IL_%04lx %s %-10s -> IL_%04lx, sp %ld, %s %-12s vt_sp %u (max %u)\n",
2292 td->ip - td->il_code,
2293 td->is_bb_start [td->ip - td->il_code] == 3 ? "<>" :
2294 td->is_bb_start [td->ip - td->il_code] == 2 ? "< " :
2295 td->is_bb_start [td->ip - td->il_code] == 1 ? " >" : " ",
2296 mono_opcode_name (*td->ip), td->new_ip - td->new_code, td->sp - td->stack,
2297 td->sp > td->stack ? stack_type_string [td->sp [-1].type] : " ",
2298 (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)) : "",
2299 td->vt_sp, td->max_vt_sp);
2302 if (sym_seq_points && mono_bitset_test_fast (seq_point_locs, td->ip - header->code)) {
2303 InterpBasicBlock *cbb = td->offset_to_bb [td->ip - header->code];
2304 g_assert (cbb);
2307 * Make methods interruptable at the beginning, and at the targets of
2308 * backward branches.
2310 if (in_offset == 0 || g_slist_length (cbb->preds) > 1)
2311 ADD_CODE (td, MINT_SDB_INTR_LOC);
2313 emit_seq_point (td, in_offset, cbb, FALSE);
2315 mono_bitset_set_fast (seq_point_set_locs, td->ip - header->code);
2318 if (sym_seq_points)
2319 bb_exit = td->offset_to_bb [td->ip - header->code];
2321 if (is_bb_start [in_offset]) {
2322 int index = td->clause_indexes [in_offset];
2323 if (index != -1) {
2324 MonoExceptionClause *clause = &header->clauses [index];
2325 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
2326 clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) &&
2327 in_offset == clause->handler_offset)
2328 ADD_CODE (td, MINT_START_ABORT_PROT);
2332 switch (*td->ip) {
2333 case CEE_NOP:
2334 /* lose it */
2335 ++td->ip;
2336 break;
2337 case CEE_BREAK:
2338 SIMPLE_OP(td, MINT_BREAK);
2339 break;
2340 case CEE_LDARG_0:
2341 case CEE_LDARG_1:
2342 case CEE_LDARG_2:
2343 case CEE_LDARG_3:
2344 load_arg (td, *td->ip - CEE_LDARG_0);
2345 ++td->ip;
2346 break;
2347 case CEE_LDLOC_0:
2348 case CEE_LDLOC_1:
2349 case CEE_LDLOC_2:
2350 case CEE_LDLOC_3:
2351 load_local (td, *td->ip - CEE_LDLOC_0);
2352 ++td->ip;
2353 break;
2354 case CEE_STLOC_0:
2355 case CEE_STLOC_1:
2356 case CEE_STLOC_2:
2357 case CEE_STLOC_3:
2358 store_local (td, *td->ip - CEE_STLOC_0);
2359 ++td->ip;
2360 break;
2361 case CEE_LDARG_S:
2362 load_arg (td, ((guint8 *)td->ip)[1]);
2363 td->ip += 2;
2364 break;
2365 case CEE_LDARGA_S: {
2366 /* NOTE: n includes this */
2367 int n = ((guint8 *) td->ip) [1];
2368 ADD_CODE (td, MINT_LDARGA);
2369 ADD_CODE (td, td->rtm->arg_offsets [n]);
2370 PUSH_SIMPLE_TYPE(td, STACK_TYPE_MP);
2371 td->ip += 2;
2372 break;
2374 case CEE_STARG_S:
2375 store_arg (td, ((guint8 *)td->ip)[1]);
2376 td->ip += 2;
2377 break;
2378 case CEE_LDLOC_S:
2379 load_local (td, ((guint8 *)td->ip)[1]);
2380 td->ip += 2;
2381 break;
2382 case CEE_LDLOCA_S:
2383 ADD_CODE(td, MINT_LDLOCA_S);
2384 ADD_CODE(td, td->rtm->local_offsets [((guint8 *)td->ip)[1]]);
2385 PUSH_SIMPLE_TYPE(td, STACK_TYPE_MP);
2386 td->ip += 2;
2387 break;
2388 case CEE_STLOC_S:
2389 store_local (td, ((guint8 *)td->ip)[1]);
2390 td->ip += 2;
2391 break;
2392 case CEE_LDNULL:
2393 SIMPLE_OP(td, MINT_LDNULL);
2394 PUSH_TYPE(td, STACK_TYPE_O, NULL);
2395 break;
2396 case CEE_LDC_I4_M1:
2397 SIMPLE_OP(td, MINT_LDC_I4_M1);
2398 PUSH_SIMPLE_TYPE(td, STACK_TYPE_I4);
2399 break;
2400 case CEE_LDC_I4_0:
2401 if (!td->is_bb_start[td->ip + 1 - td->il_code] && td->ip [1] == 0xfe && td->ip [2] == CEE_CEQ &&
2402 td->sp > td->stack && td->sp [-1].type == STACK_TYPE_I4) {
2403 SIMPLE_OP(td, MINT_CEQ0_I4);
2404 td->ip += 2;
2405 } else {
2406 SIMPLE_OP(td, MINT_LDC_I4_0);
2407 PUSH_SIMPLE_TYPE(td, STACK_TYPE_I4);
2409 break;
2410 case CEE_LDC_I4_1:
2411 if (!td->is_bb_start[td->ip + 1 - td->il_code] &&
2412 (td->ip [1] == CEE_ADD || td->ip [1] == CEE_SUB) && td->sp [-1].type == STACK_TYPE_I4) {
2413 ADD_CODE(td, td->ip [1] == CEE_ADD ? MINT_ADD1_I4 : MINT_SUB1_I4);
2414 td->ip += 2;
2415 } else {
2416 SIMPLE_OP(td, MINT_LDC_I4_1);
2417 PUSH_SIMPLE_TYPE(td, STACK_TYPE_I4);
2419 break;
2420 case CEE_LDC_I4_2:
2421 case CEE_LDC_I4_3:
2422 case CEE_LDC_I4_4:
2423 case CEE_LDC_I4_5:
2424 case CEE_LDC_I4_6:
2425 case CEE_LDC_I4_7:
2426 case CEE_LDC_I4_8:
2427 SIMPLE_OP(td, (*td->ip - CEE_LDC_I4_0) + MINT_LDC_I4_0);
2428 PUSH_SIMPLE_TYPE(td, STACK_TYPE_I4);
2429 break;
2430 case CEE_LDC_I4_S:
2431 ADD_CODE(td, MINT_LDC_I4_S);
2432 ADD_CODE(td, ((gint8 *) td->ip) [1]);
2433 td->ip += 2;
2434 PUSH_SIMPLE_TYPE(td, STACK_TYPE_I4);
2435 break;
2436 case CEE_LDC_I4:
2437 i32 = read32 (td->ip + 1);
2438 ADD_CODE(td, MINT_LDC_I4);
2439 WRITE32(td, &i32);
2440 td->ip += 5;
2441 PUSH_SIMPLE_TYPE(td, STACK_TYPE_I4);
2442 break;
2443 case CEE_LDC_I8: {
2444 gint64 val = read64 (td->ip + 1);
2445 ADD_CODE(td, MINT_LDC_I8);
2446 WRITE64(td, &val);
2447 td->ip += 9;
2448 PUSH_SIMPLE_TYPE(td, STACK_TYPE_I8);
2449 break;
2451 case CEE_LDC_R4: {
2452 float val;
2453 readr4 (td->ip + 1, &val);
2454 ADD_CODE(td, MINT_LDC_R4);
2455 WRITE32(td, &val);
2456 td->ip += 5;
2457 PUSH_SIMPLE_TYPE(td, STACK_TYPE_R4);
2458 break;
2460 case CEE_LDC_R8: {
2461 double val;
2462 readr8 (td->ip + 1, &val);
2463 ADD_CODE(td, MINT_LDC_R8);
2464 WRITE64(td, &val);
2465 td->ip += 9;
2466 PUSH_SIMPLE_TYPE(td, STACK_TYPE_R8);
2467 break;
2469 case CEE_DUP: {
2470 int type = td->sp [-1].type;
2471 MonoClass *klass = td->sp [-1].klass;
2472 if (td->sp [-1].type == STACK_TYPE_VT) {
2473 gint32 size = mono_class_value_size (klass, NULL);
2474 PUSH_VT(td, size);
2475 ADD_CODE(td, MINT_DUP_VT);
2476 WRITE32(td, &size);
2477 td->ip ++;
2478 } else
2479 SIMPLE_OP(td, MINT_DUP);
2480 PUSH_TYPE(td, type, klass);
2481 break;
2483 case CEE_POP:
2484 CHECK_STACK(td, 1);
2485 SIMPLE_OP(td, MINT_POP);
2486 ADD_CODE (td, 0);
2487 if (td->sp [-1].type == STACK_TYPE_VT) {
2488 int size = mono_class_value_size (td->sp [-1].klass, NULL);
2489 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
2490 ADD_CODE(td, MINT_VTRESULT);
2491 ADD_CODE(td, 0);
2492 WRITE32(td, &size);
2493 td->vt_sp -= size;
2495 --td->sp;
2496 break;
2497 case CEE_JMP: {
2498 MonoMethod *m;
2499 if (td->sp > td->stack)
2500 g_warning ("CEE_JMP: stack must be empty");
2501 token = read32 (td->ip + 1);
2502 m = mono_get_method_checked (image, token, NULL, generic_context, error);
2503 goto_if_nok (error, exit);
2504 ADD_CODE (td, MINT_JMP);
2505 ADD_CODE (td, get_data_item_index (td, mono_interp_get_imethod (domain, m, error)));
2506 goto_if_nok (error, exit);
2507 td->ip += 5;
2508 break;
2510 case CEE_CALLVIRT: /* Fall through */
2511 case CEE_CALLI: /* Fall through */
2512 case CEE_CALL: {
2513 gboolean need_seq_point = FALSE;
2515 if (sym_seq_points && !mono_bitset_test_fast (seq_point_locs, td->ip + 5 - header->code))
2516 need_seq_point = TRUE;
2518 interp_transform_call (td, method, NULL, domain, generic_context, is_bb_start, body_start_offset, constrained_class, readonly, error, TRUE);
2519 goto_if_nok (error, exit);
2521 if (need_seq_point) {
2522 InterpBasicBlock *cbb = td->offset_to_bb [td->ip - header->code];
2523 g_assert (cbb);
2525 emit_seq_point (td, td->ip - header->code, cbb, TRUE);
2528 constrained_class = NULL;
2529 readonly = FALSE;
2530 break;
2532 case CEE_RET: {
2533 int vt_size = 0;
2534 MonoType *ult = mini_type_get_underlying_type (signature->ret);
2535 if (ult->type != MONO_TYPE_VOID) {
2536 CHECK_STACK (td, 1);
2537 --td->sp;
2538 if (mint_type (ult) == MINT_TYPE_VT) {
2539 MonoClass *klass = mono_class_from_mono_type_internal (ult);
2540 vt_size = mono_class_value_size (klass, NULL);
2543 if (td->sp > td->stack) {
2544 mono_error_set_generic_error (error, "System", "InvalidProgramException", "");
2545 goto exit;
2547 if (td->vt_sp != ALIGN_TO (vt_size, MINT_VT_ALIGNMENT))
2548 g_error ("%s: CEE_RET: value type stack: %d vs. %d", mono_method_full_name (td->method, TRUE), td->vt_sp, vt_size);
2550 if (sym_seq_points) {
2551 InterpBasicBlock *cbb = td->offset_to_bb [td->ip - header->code];
2552 g_assert (cbb);
2553 emit_seq_point (td, METHOD_EXIT_IL_OFFSET, bb_exit, FALSE);
2556 if (vt_size == 0)
2557 SIMPLE_OP(td, ult->type == MONO_TYPE_VOID ? MINT_RET_VOID : MINT_RET);
2558 else {
2559 ADD_CODE(td, MINT_RET_VT);
2560 WRITE32(td, &vt_size);
2561 ++td->ip;
2563 break;
2565 case CEE_BR:
2566 handle_branch (td, MINT_BR_S, MINT_BR, 5 + read32 (td->ip + 1));
2567 td->ip += 5;
2568 break;
2569 case CEE_BR_S:
2570 handle_branch (td, MINT_BR_S, MINT_BR, 2 + (gint8)td->ip [1]);
2571 td->ip += 2;
2572 break;
2573 case CEE_BRFALSE:
2574 one_arg_branch (td, MINT_BRFALSE_I4, 5 + read32 (td->ip + 1));
2575 td->ip += 5;
2576 break;
2577 case CEE_BRFALSE_S:
2578 one_arg_branch (td, MINT_BRFALSE_I4, 2 + (gint8)td->ip [1]);
2579 td->ip += 2;
2580 break;
2581 case CEE_BRTRUE:
2582 one_arg_branch (td, MINT_BRTRUE_I4, 5 + read32 (td->ip + 1));
2583 td->ip += 5;
2584 break;
2585 case CEE_BRTRUE_S:
2586 one_arg_branch (td, MINT_BRTRUE_I4, 2 + (gint8)td->ip [1]);
2587 td->ip += 2;
2588 break;
2589 case CEE_BEQ:
2590 two_arg_branch (td, MINT_BEQ_I4, 5 + read32 (td->ip + 1));
2591 td->ip += 5;
2592 break;
2593 case CEE_BEQ_S:
2594 two_arg_branch (td, MINT_BEQ_I4, 2 + (gint8) td->ip [1]);
2595 td->ip += 2;
2596 break;
2597 case CEE_BGE:
2598 two_arg_branch (td, MINT_BGE_I4, 5 + read32 (td->ip + 1));
2599 td->ip += 5;
2600 break;
2601 case CEE_BGE_S:
2602 two_arg_branch (td, MINT_BGE_I4, 2 + (gint8) td->ip [1]);
2603 td->ip += 2;
2604 break;
2605 case CEE_BGT:
2606 two_arg_branch (td, MINT_BGT_I4, 5 + read32 (td->ip + 1));
2607 td->ip += 5;
2608 break;
2609 case CEE_BGT_S:
2610 two_arg_branch (td, MINT_BGT_I4, 2 + (gint8) td->ip [1]);
2611 td->ip += 2;
2612 break;
2613 case CEE_BLT:
2614 two_arg_branch (td, MINT_BLT_I4, 5 + read32 (td->ip + 1));
2615 td->ip += 5;
2616 break;
2617 case CEE_BLT_S:
2618 two_arg_branch (td, MINT_BLT_I4, 2 + (gint8) td->ip [1]);
2619 td->ip += 2;
2620 break;
2621 case CEE_BLE:
2622 two_arg_branch (td, MINT_BLE_I4, 5 + read32 (td->ip + 1));
2623 td->ip += 5;
2624 break;
2625 case CEE_BLE_S:
2626 two_arg_branch (td, MINT_BLE_I4, 2 + (gint8) td->ip [1]);
2627 td->ip += 2;
2628 break;
2629 case CEE_BNE_UN:
2630 two_arg_branch (td, MINT_BNE_UN_I4, 5 + read32 (td->ip + 1));
2631 td->ip += 5;
2632 break;
2633 case CEE_BNE_UN_S:
2634 two_arg_branch (td, MINT_BNE_UN_I4, 2 + (gint8) td->ip [1]);
2635 td->ip += 2;
2636 break;
2637 case CEE_BGE_UN:
2638 two_arg_branch (td, MINT_BGE_UN_I4, 5 + read32 (td->ip + 1));
2639 td->ip += 5;
2640 break;
2641 case CEE_BGE_UN_S:
2642 two_arg_branch (td, MINT_BGE_UN_I4, 2 + (gint8) td->ip [1]);
2643 td->ip += 2;
2644 break;
2645 case CEE_BGT_UN:
2646 two_arg_branch (td, MINT_BGT_UN_I4, 5 + read32 (td->ip + 1));
2647 td->ip += 5;
2648 break;
2649 case CEE_BGT_UN_S:
2650 two_arg_branch (td, MINT_BGT_UN_I4, 2 + (gint8) td->ip [1]);
2651 td->ip += 2;
2652 break;
2653 case CEE_BLE_UN:
2654 two_arg_branch (td, MINT_BLE_UN_I4, 5 + read32 (td->ip + 1));
2655 td->ip += 5;
2656 break;
2657 case CEE_BLE_UN_S:
2658 two_arg_branch (td, MINT_BLE_UN_I4, 2 + (gint8) td->ip [1]);
2659 td->ip += 2;
2660 break;
2661 case CEE_BLT_UN:
2662 two_arg_branch (td, MINT_BLT_UN_I4, 5 + read32 (td->ip + 1));
2663 td->ip += 5;
2664 break;
2665 case CEE_BLT_UN_S:
2666 two_arg_branch (td, MINT_BLT_UN_I4, 2 + (gint8) td->ip [1]);
2667 td->ip += 2;
2668 break;
2669 case CEE_SWITCH: {
2670 guint32 n;
2671 const unsigned char *next_ip;
2672 ++td->ip;
2673 n = read32 (td->ip);
2674 ADD_CODE (td, MINT_SWITCH);
2675 WRITE32 (td, &n);
2676 td->ip += 4;
2677 next_ip = td->ip + n * 4;
2678 --td->sp;
2679 int stack_height = td->sp - td->stack;
2680 for (i = 0; i < n; i++) {
2681 offset = read32 (td->ip);
2682 target = next_ip - td->il_code + offset;
2683 if (offset < 0) {
2684 #if DEBUG_INTERP
2685 if (stack_height > 0 && stack_height != td->stack_height [target])
2686 g_warning ("SWITCH with back branch and non-empty stack");
2687 #endif
2688 target = td->in_offsets [target] - (td->new_ip - td->new_code);
2689 } else {
2690 td->stack_height [target] = stack_height;
2691 td->vt_stack_size [target] = td->vt_sp;
2692 if (stack_height > 0)
2693 td->stack_state [target] = (StackInfo*)g_memdup (td->stack, stack_height * sizeof (td->stack [0]));
2695 Reloc *reloc = (Reloc*)mono_mempool_alloc0 (td->mempool, sizeof (Reloc));
2696 reloc->type = RELOC_SWITCH;
2697 reloc->offset = td->new_ip - td->new_code;
2698 reloc->target = target;
2699 g_ptr_array_add (td->relocs, reloc);
2700 target = 0xffff;
2702 WRITE32 (td, &target);
2703 td->ip += 4;
2705 break;
2707 case CEE_LDIND_I1:
2708 CHECK_STACK (td, 1);
2709 SIMPLE_OP (td, MINT_LDIND_I1_CHECK);
2710 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
2711 BARRIER_IF_VOLATILE (td);
2712 break;
2713 case CEE_LDIND_U1:
2714 CHECK_STACK (td, 1);
2715 SIMPLE_OP (td, MINT_LDIND_U1_CHECK);
2716 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
2717 BARRIER_IF_VOLATILE (td);
2718 break;
2719 case CEE_LDIND_I2:
2720 CHECK_STACK (td, 1);
2721 SIMPLE_OP (td, MINT_LDIND_I2_CHECK);
2722 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
2723 BARRIER_IF_VOLATILE (td);
2724 break;
2725 case CEE_LDIND_U2:
2726 CHECK_STACK (td, 1);
2727 SIMPLE_OP (td, MINT_LDIND_U2_CHECK);
2728 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
2729 BARRIER_IF_VOLATILE (td);
2730 break;
2731 case CEE_LDIND_I4:
2732 CHECK_STACK (td, 1);
2733 SIMPLE_OP (td, MINT_LDIND_I4_CHECK);
2734 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
2735 BARRIER_IF_VOLATILE (td);
2736 break;
2737 case CEE_LDIND_U4:
2738 CHECK_STACK (td, 1);
2739 SIMPLE_OP (td, MINT_LDIND_U4_CHECK);
2740 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
2741 BARRIER_IF_VOLATILE (td);
2742 break;
2743 case CEE_LDIND_I8:
2744 CHECK_STACK (td, 1);
2745 SIMPLE_OP (td, MINT_LDIND_I8_CHECK);
2746 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8);
2747 BARRIER_IF_VOLATILE (td);
2748 break;
2749 case CEE_LDIND_I:
2750 CHECK_STACK (td, 1);
2751 ADD_CODE (td, MINT_CKNULL);
2752 SIMPLE_OP (td, MINT_LDIND_I);
2753 ADD_CODE (td, 0);
2754 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I);
2755 BARRIER_IF_VOLATILE (td);
2756 break;
2757 case CEE_LDIND_R4:
2758 CHECK_STACK (td, 1);
2759 SIMPLE_OP (td, MINT_LDIND_R4_CHECK);
2760 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R4);
2761 BARRIER_IF_VOLATILE (td);
2762 break;
2763 case CEE_LDIND_R8:
2764 CHECK_STACK (td, 1);
2765 SIMPLE_OP (td, MINT_LDIND_R8_CHECK);
2766 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R8);
2767 BARRIER_IF_VOLATILE (td);
2768 break;
2769 case CEE_LDIND_REF:
2770 CHECK_STACK (td, 1);
2771 ADD_CODE (td, MINT_CKNULL);
2772 SIMPLE_OP (td, MINT_LDIND_REF);
2773 BARRIER_IF_VOLATILE (td);
2774 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_O);
2775 break;
2776 case CEE_STIND_REF:
2777 CHECK_STACK (td, 2);
2778 BARRIER_IF_VOLATILE (td);
2779 SIMPLE_OP (td, MINT_STIND_REF);
2780 td->sp -= 2;
2781 break;
2782 case CEE_STIND_I1:
2783 CHECK_STACK (td, 2);
2784 BARRIER_IF_VOLATILE (td);
2785 SIMPLE_OP (td, MINT_STIND_I1);
2786 td->sp -= 2;
2787 break;
2788 case CEE_STIND_I2:
2789 CHECK_STACK (td, 2);
2790 BARRIER_IF_VOLATILE (td);
2791 SIMPLE_OP (td, MINT_STIND_I2);
2792 td->sp -= 2;
2793 break;
2794 case CEE_STIND_I4:
2795 CHECK_STACK (td, 2);
2796 BARRIER_IF_VOLATILE (td);
2797 SIMPLE_OP (td, MINT_STIND_I4);
2798 td->sp -= 2;
2799 break;
2800 case CEE_STIND_I:
2801 CHECK_STACK (td, 2);
2802 BARRIER_IF_VOLATILE (td);
2803 SIMPLE_OP (td, MINT_STIND_I);
2804 td->sp -= 2;
2805 break;
2806 case CEE_STIND_I8:
2807 CHECK_STACK (td, 2);
2808 BARRIER_IF_VOLATILE (td);
2809 SIMPLE_OP (td, MINT_STIND_I8);
2810 td->sp -= 2;
2811 break;
2812 case CEE_STIND_R4:
2813 CHECK_STACK (td, 2);
2814 BARRIER_IF_VOLATILE (td);
2815 SIMPLE_OP (td, MINT_STIND_R4);
2816 td->sp -= 2;
2817 break;
2818 case CEE_STIND_R8:
2819 CHECK_STACK (td, 2);
2820 BARRIER_IF_VOLATILE (td);
2821 SIMPLE_OP (td, MINT_STIND_R8);
2822 td->sp -= 2;
2823 break;
2824 case CEE_ADD:
2825 binary_arith_op(td, MINT_ADD_I4);
2826 ++td->ip;
2827 break;
2828 case CEE_SUB:
2829 binary_arith_op(td, MINT_SUB_I4);
2830 ++td->ip;
2831 break;
2832 case CEE_MUL:
2833 binary_arith_op(td, MINT_MUL_I4);
2834 ++td->ip;
2835 break;
2836 case CEE_DIV:
2837 binary_arith_op(td, MINT_DIV_I4);
2838 ++td->ip;
2839 break;
2840 case CEE_DIV_UN:
2841 binary_arith_op(td, MINT_DIV_UN_I4);
2842 ++td->ip;
2843 break;
2844 case CEE_REM:
2845 binary_arith_op (td, MINT_REM_I4);
2846 ++td->ip;
2847 break;
2848 case CEE_REM_UN:
2849 binary_arith_op (td, MINT_REM_UN_I4);
2850 ++td->ip;
2851 break;
2852 case CEE_AND:
2853 binary_arith_op (td, MINT_AND_I4);
2854 ++td->ip;
2855 break;
2856 case CEE_OR:
2857 binary_arith_op (td, MINT_OR_I4);
2858 ++td->ip;
2859 break;
2860 case CEE_XOR:
2861 binary_arith_op (td, MINT_XOR_I4);
2862 ++td->ip;
2863 break;
2864 case CEE_SHL:
2865 shift_op (td, MINT_SHL_I4);
2866 ++td->ip;
2867 break;
2868 case CEE_SHR:
2869 shift_op (td, MINT_SHR_I4);
2870 ++td->ip;
2871 break;
2872 case CEE_SHR_UN:
2873 shift_op (td, MINT_SHR_UN_I4);
2874 ++td->ip;
2875 break;
2876 case CEE_NEG:
2877 unary_arith_op (td, MINT_NEG_I4);
2878 ++td->ip;
2879 break;
2880 case CEE_NOT:
2881 unary_arith_op (td, MINT_NOT_I4);
2882 ++td->ip;
2883 break;
2884 case CEE_CONV_U1:
2885 CHECK_STACK (td, 1);
2886 switch (td->sp [-1].type) {
2887 case STACK_TYPE_R4:
2888 ADD_CODE (td, MINT_CONV_U1_R4);
2889 break;
2890 case STACK_TYPE_R8:
2891 ADD_CODE(td, MINT_CONV_U1_R8);
2892 break;
2893 case STACK_TYPE_I4:
2894 ADD_CODE(td, MINT_CONV_U1_I4);
2895 break;
2896 case STACK_TYPE_I8:
2897 ADD_CODE(td, MINT_CONV_U1_I8);
2898 break;
2899 default:
2900 g_assert_not_reached ();
2902 ++td->ip;
2903 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
2904 break;
2905 case CEE_CONV_I1:
2906 CHECK_STACK (td, 1);
2907 switch (td->sp [-1].type) {
2908 case STACK_TYPE_R4:
2909 ADD_CODE(td, MINT_CONV_I1_R4);
2910 break;
2911 case STACK_TYPE_R8:
2912 ADD_CODE(td, MINT_CONV_I1_R8);
2913 break;
2914 case STACK_TYPE_I4:
2915 ADD_CODE(td, MINT_CONV_I1_I4);
2916 break;
2917 case STACK_TYPE_I8:
2918 ADD_CODE(td, MINT_CONV_I1_I8);
2919 break;
2920 default:
2921 g_assert_not_reached ();
2923 ++td->ip;
2924 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
2925 break;
2926 case CEE_CONV_U2:
2927 CHECK_STACK (td, 1);
2928 switch (td->sp [-1].type) {
2929 case STACK_TYPE_R4:
2930 ADD_CODE(td, MINT_CONV_U2_R4);
2931 break;
2932 case STACK_TYPE_R8:
2933 ADD_CODE(td, MINT_CONV_U2_R8);
2934 break;
2935 case STACK_TYPE_I4:
2936 ADD_CODE(td, MINT_CONV_U2_I4);
2937 break;
2938 case STACK_TYPE_I8:
2939 ADD_CODE(td, MINT_CONV_U2_I8);
2940 break;
2941 default:
2942 g_assert_not_reached ();
2944 ++td->ip;
2945 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
2946 break;
2947 case CEE_CONV_I2:
2948 CHECK_STACK (td, 1);
2949 switch (td->sp [-1].type) {
2950 case STACK_TYPE_R4:
2951 ADD_CODE(td, MINT_CONV_I2_R4);
2952 break;
2953 case STACK_TYPE_R8:
2954 ADD_CODE(td, MINT_CONV_I2_R8);
2955 break;
2956 case STACK_TYPE_I4:
2957 ADD_CODE(td, MINT_CONV_I2_I4);
2958 break;
2959 case STACK_TYPE_I8:
2960 ADD_CODE(td, MINT_CONV_I2_I8);
2961 break;
2962 default:
2963 g_assert_not_reached ();
2965 ++td->ip;
2966 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
2967 break;
2968 case CEE_CONV_U:
2969 CHECK_STACK (td, 1);
2970 switch (td->sp [-1].type) {
2971 case STACK_TYPE_R8:
2972 #if SIZEOF_VOID_P == 4
2973 ADD_CODE(td, MINT_CONV_U4_R8);
2974 #else
2975 ADD_CODE(td, MINT_CONV_U8_R8);
2976 #endif
2977 break;
2978 case STACK_TYPE_I4:
2979 #if SIZEOF_VOID_P == 8
2980 ADD_CODE(td, MINT_CONV_U8_I4);
2981 #endif
2982 break;
2983 case STACK_TYPE_I8:
2984 #if SIZEOF_VOID_P == 4
2985 ADD_CODE(td, MINT_CONV_U4_I8);
2986 #endif
2987 break;
2988 case STACK_TYPE_MP:
2989 case STACK_TYPE_O:
2990 break;
2991 default:
2992 g_assert_not_reached ();
2994 ++td->ip;
2995 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I);
2996 break;
2997 case CEE_CONV_I:
2998 CHECK_STACK (td, 1);
2999 switch (td->sp [-1].type) {
3000 case STACK_TYPE_R8:
3001 #if SIZEOF_VOID_P == 8
3002 ADD_CODE(td, MINT_CONV_I8_R8);
3003 #else
3004 ADD_CODE(td, MINT_CONV_I4_R8);
3005 #endif
3006 break;
3007 case STACK_TYPE_I4:
3008 #if SIZEOF_VOID_P == 8
3009 ADD_CODE(td, MINT_CONV_I8_I4);
3010 #endif
3011 break;
3012 case STACK_TYPE_O:
3013 break;
3014 case STACK_TYPE_MP:
3015 break;
3016 case STACK_TYPE_I8:
3017 #if SIZEOF_VOID_P == 4
3018 ADD_CODE(td, MINT_CONV_I4_I8);
3019 #endif
3020 break;
3021 default:
3022 g_assert_not_reached ();
3024 ++td->ip;
3025 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I);
3026 break;
3027 case CEE_CONV_U4:
3028 CHECK_STACK (td, 1);
3029 switch (td->sp [-1].type) {
3030 case STACK_TYPE_R4:
3031 ADD_CODE(td, MINT_CONV_U4_R4);
3032 break;
3033 case STACK_TYPE_R8:
3034 ADD_CODE(td, MINT_CONV_U4_R8);
3035 break;
3036 case STACK_TYPE_I4:
3037 break;
3038 case STACK_TYPE_I8:
3039 ADD_CODE(td, MINT_CONV_U4_I8);
3040 break;
3041 case STACK_TYPE_MP:
3042 #if SIZEOF_VOID_P == 8
3043 ADD_CODE(td, MINT_CONV_U4_I8);
3044 #endif
3045 break;
3046 default:
3047 g_assert_not_reached ();
3049 ++td->ip;
3050 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
3051 break;
3052 case CEE_CONV_I4:
3053 CHECK_STACK (td, 1);
3054 switch (td->sp [-1].type) {
3055 case STACK_TYPE_R4:
3056 ADD_CODE (td, MINT_CONV_I4_R4);
3057 break;
3058 case STACK_TYPE_R8:
3059 ADD_CODE(td, MINT_CONV_I4_R8);
3060 break;
3061 case STACK_TYPE_I4:
3062 break;
3063 case STACK_TYPE_I8:
3064 ADD_CODE(td, MINT_CONV_I4_I8);
3065 break;
3066 case STACK_TYPE_MP:
3067 #if SIZEOF_VOID_P == 8
3068 ADD_CODE(td, MINT_CONV_I4_I8);
3069 #endif
3070 break;
3071 default:
3072 g_assert_not_reached ();
3074 ++td->ip;
3075 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
3076 break;
3077 case CEE_CONV_I8:
3078 CHECK_STACK (td, 1);
3079 switch (td->sp [-1].type) {
3080 case STACK_TYPE_R4:
3081 ADD_CODE(td, MINT_CONV_I8_R4);
3082 break;
3083 case STACK_TYPE_R8:
3084 ADD_CODE(td, MINT_CONV_I8_R8);
3085 break;
3086 case STACK_TYPE_I4:
3087 ADD_CODE(td, MINT_CONV_I8_I4);
3088 break;
3089 case STACK_TYPE_I8:
3090 break;
3091 case STACK_TYPE_MP:
3092 #if SIZEOF_VOID_P == 4
3093 ADD_CODE(td, MINT_CONV_I8_I4);
3094 #endif
3095 break;
3096 default:
3097 g_assert_not_reached ();
3099 ++td->ip;
3100 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8);
3101 break;
3102 case CEE_CONV_R4:
3103 CHECK_STACK (td, 1);
3104 switch (td->sp [-1].type) {
3105 case STACK_TYPE_R8:
3106 ADD_CODE(td, MINT_CONV_R4_R8);
3107 break;
3108 case STACK_TYPE_I8:
3109 ADD_CODE(td, MINT_CONV_R4_I8);
3110 break;
3111 case STACK_TYPE_I4:
3112 ADD_CODE(td, MINT_CONV_R4_I4);
3113 break;
3114 case STACK_TYPE_R4:
3115 /* no-op */
3116 break;
3117 default:
3118 g_assert_not_reached ();
3120 ++td->ip;
3121 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R4);
3122 break;
3123 case CEE_CONV_R8:
3124 CHECK_STACK (td, 1);
3125 switch (td->sp [-1].type) {
3126 case STACK_TYPE_I4:
3127 ADD_CODE(td, MINT_CONV_R8_I4);
3128 break;
3129 case STACK_TYPE_I8:
3130 ADD_CODE(td, MINT_CONV_R8_I8);
3131 break;
3132 case STACK_TYPE_R4:
3133 ADD_CODE (td, MINT_CONV_R8_R4);
3134 break;
3135 case STACK_TYPE_R8:
3136 break;
3137 default:
3138 g_assert_not_reached ();
3140 ++td->ip;
3141 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R8);
3142 break;
3143 case CEE_CONV_U8:
3144 CHECK_STACK (td, 1);
3145 switch (td->sp [-1].type) {
3146 case STACK_TYPE_I4:
3147 ADD_CODE(td, MINT_CONV_U8_I4);
3148 break;
3149 case STACK_TYPE_I8:
3150 break;
3151 case STACK_TYPE_R4:
3152 ADD_CODE (td, MINT_CONV_U8_R4);
3153 break;
3154 case STACK_TYPE_R8:
3155 ADD_CODE(td, MINT_CONV_U8_R8);
3156 break;
3157 case STACK_TYPE_MP:
3158 #if SIZEOF_VOID_P == 4
3159 ADD_CODE(td, MINT_CONV_U8_I4);
3160 #endif
3161 break;
3162 default:
3163 g_assert_not_reached ();
3165 ++td->ip;
3166 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8);
3167 break;
3168 case CEE_CPOBJ: {
3169 CHECK_STACK (td, 2);
3171 token = read32 (td->ip + 1);
3172 klass = mono_class_get_and_inflate_typespec_checked (image, token, generic_context, error);
3173 goto_if_nok (error, exit);
3175 if (m_class_is_valuetype (klass)) {
3176 int mt = mint_type (m_class_get_byval_arg (klass));
3177 ADD_CODE (td, (mt == MINT_TYPE_VT) ? MINT_CPOBJ_VT : MINT_CPOBJ);
3178 ADD_CODE (td, get_data_item_index(td, klass));
3179 } else {
3180 ADD_CODE (td, MINT_LDIND_REF);
3181 ADD_CODE (td, MINT_STIND_REF);
3183 td->ip += 5;
3184 td->sp -= 2;
3185 break;
3187 case CEE_LDOBJ: {
3188 int size;
3189 CHECK_STACK (td, 1);
3191 token = read32 (td->ip + 1);
3193 if (method->wrapper_type != MONO_WRAPPER_NONE)
3194 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3195 else {
3196 klass = mono_class_get_and_inflate_typespec_checked (image, token, generic_context, error);
3197 goto_if_nok (error, exit);
3200 MonoClass *tos_klass = td->sp [-1].klass;
3201 if (tos_klass && td->sp [-1].type == STACK_TYPE_VT) {
3202 int tos_size = mono_class_value_size (tos_klass, NULL);
3203 POP_VT (td, tos_size);
3206 int mt = mint_type (m_class_get_byval_arg (klass));
3208 ADD_CODE(td, (mt == MINT_TYPE_VT) ? MINT_LDOBJ_VT: MINT_LDOBJ);
3209 ADD_CODE(td, get_data_item_index(td, klass));
3211 if (mt == MINT_TYPE_VT) {
3212 size = mono_class_value_size (klass, NULL);
3213 PUSH_VT (td, size);
3215 td->ip += 5;
3216 SET_TYPE (td->sp - 1, stack_type [mt], klass);
3217 BARRIER_IF_VOLATILE (td);
3218 break;
3220 case CEE_LDSTR: {
3221 token = mono_metadata_token_index (read32 (td->ip + 1));
3222 td->ip += 5;
3223 if (method->wrapper_type == MONO_WRAPPER_NONE) {
3224 MonoString *s = mono_ldstr_checked (domain, image, token, error);
3225 goto_if_nok (error, exit);
3226 /* GC won't scan code stream, but reference is held by metadata
3227 * machinery so we are good here */
3228 ADD_CODE (td, MINT_LDSTR);
3229 ADD_CODE (td, get_data_item_index (td, s));
3230 } else {
3231 /* defer allocation to execution-time */
3232 ADD_CODE (td, MINT_LDSTR_TOKEN);
3233 ADD_CODE (td, get_data_item_index (td, GUINT_TO_POINTER (token)));
3235 PUSH_TYPE(td, STACK_TYPE_O, mono_defaults.string_class);
3236 break;
3238 case CEE_NEWOBJ: {
3239 MonoMethod *m;
3240 MonoMethodSignature *csignature;
3241 guint32 vt_stack_used = 0;
3242 guint32 vt_res_size = 0;
3244 td->ip++;
3245 token = read32 (td->ip);
3246 td->ip += 4;
3248 if (method->wrapper_type != MONO_WRAPPER_NONE)
3249 m = (MonoMethod *)mono_method_get_wrapper_data (method, token);
3250 else {
3251 m = mono_get_method_checked (image, token, NULL, generic_context, error);
3252 goto_if_nok (error, exit);
3255 csignature = mono_method_signature_internal (m);
3256 klass = m->klass;
3258 if (!mono_class_init (klass)) {
3259 mono_error_set_for_class_failure (error, klass);
3260 goto_if_nok (error, exit);
3263 if (mono_class_get_flags (klass) & TYPE_ATTRIBUTE_ABSTRACT) {
3264 char* full_name = mono_type_get_full_name (klass);
3265 mono_error_set_member_access (error, "Cannot create an abstract class: %s", full_name);
3266 g_free (full_name);
3267 goto_if_nok (error, exit);
3270 td->sp -= csignature->param_count;
3271 if (mono_class_is_magic_int (klass) || mono_class_is_magic_float (klass)) {
3272 #if SIZEOF_VOID_P == 8
3273 if (mono_class_is_magic_int (klass) && td->sp [0].type == STACK_TYPE_I4)
3274 ADD_CODE (td, MINT_CONV_I8_I4);
3275 else if (mono_class_is_magic_float (klass) && td->sp [0].type == STACK_TYPE_R4)
3276 ADD_CODE (td, MINT_CONV_R8_R4);
3277 #endif
3278 ADD_CODE (td, MINT_NEWOBJ_MAGIC);
3279 ADD_CODE (td, get_data_item_index (td, mono_interp_get_imethod (domain, m, error)));
3280 goto_if_nok (error, exit);
3282 PUSH_TYPE (td, stack_type [mint_type (m_class_get_byval_arg (klass))], klass);
3283 } else {
3284 if (m_class_get_parent (klass) == mono_defaults.array_class) {
3285 ADD_CODE(td, MINT_NEWOBJ_ARRAY);
3286 ADD_CODE(td, get_data_item_index (td, mono_interp_get_imethod (domain, m, error)));
3287 ADD_CODE(td, csignature->param_count);
3288 } else if (m_class_get_image (klass) == mono_defaults.corlib &&
3289 !strcmp (m_class_get_name (m->klass), "ByReference`1") &&
3290 !strcmp (m->name, ".ctor")) {
3291 /* public ByReference(ref T value) */
3292 g_assert (csignature->hasthis && csignature->param_count == 1);
3293 ADD_CODE(td, MINT_INTRINS_BYREFERENCE_CTOR);
3294 ADD_CODE(td, get_data_item_index (td, mono_interp_get_imethod (domain, m, error)));
3295 } else if (klass != mono_defaults.string_class &&
3296 !mono_class_is_marshalbyref (klass) &&
3297 !mono_class_has_finalizer (klass) &&
3298 !m_class_has_weak_fields (klass)) {
3299 if (!m_class_is_valuetype (klass))
3300 ADD_CODE(td, MINT_NEWOBJ_FAST);
3301 else if (mint_type (m_class_get_byval_arg (klass)) == MINT_TYPE_VT)
3302 ADD_CODE(td, MINT_NEWOBJ_VTST_FAST);
3303 else
3304 ADD_CODE(td, MINT_NEWOBJ_VT_FAST);
3306 ADD_CODE(td, get_data_item_index (td, mono_interp_get_imethod (domain, m, error)));
3307 ADD_CODE(td, csignature->param_count);
3309 if (!m_class_is_valuetype (klass)) {
3310 MonoVTable *vtable = mono_class_vtable_checked (domain, klass, error);
3311 goto_if_nok (error, exit);
3312 ADD_CODE(td, get_data_item_index (td, vtable));
3313 } else if (mint_type (m_class_get_byval_arg (klass)) == MINT_TYPE_VT) {
3314 ADD_CODE(td, mono_class_value_size (klass, NULL));
3316 } else {
3317 ADD_CODE(td, MINT_NEWOBJ);
3318 ADD_CODE(td, get_data_item_index (td, mono_interp_get_imethod (domain, m, error)));
3320 goto_if_nok (error, exit);
3322 if (mint_type (m_class_get_byval_arg (klass)) == MINT_TYPE_VT) {
3323 vt_res_size = mono_class_value_size (klass, NULL);
3324 PUSH_VT (td, vt_res_size);
3326 for (i = 0; i < csignature->param_count; ++i) {
3327 int mt = mint_type(csignature->params [i]);
3328 if (mt == MINT_TYPE_VT) {
3329 MonoClass *k = mono_class_from_mono_type_internal (csignature->params [i]);
3330 gint32 size = mono_class_value_size (k, NULL);
3331 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
3332 vt_stack_used += size;
3335 if (vt_stack_used != 0 || vt_res_size != 0) {
3336 ADD_CODE(td, MINT_VTRESULT);
3337 ADD_CODE(td, vt_res_size);
3338 WRITE32(td, &vt_stack_used);
3339 td->vt_sp -= vt_stack_used;
3341 PUSH_TYPE (td, stack_type [mint_type (m_class_get_byval_arg (klass))], klass);
3343 break;
3345 case CEE_CASTCLASS:
3346 CHECK_STACK (td, 1);
3347 token = read32 (td->ip + 1);
3348 klass = mini_get_class (method, token, generic_context);
3349 CHECK_TYPELOAD (klass);
3350 ADD_CODE(td, MINT_CASTCLASS);
3351 ADD_CODE(td, get_data_item_index (td, klass));
3352 td->sp [-1].klass = klass;
3353 td->ip += 5;
3354 break;
3355 case CEE_ISINST:
3356 CHECK_STACK (td, 1);
3357 token = read32 (td->ip + 1);
3358 klass = mini_get_class (method, token, generic_context);
3359 CHECK_TYPELOAD (klass);
3360 ADD_CODE(td, MINT_ISINST);
3361 ADD_CODE(td, get_data_item_index (td, klass));
3362 td->ip += 5;
3363 break;
3364 case CEE_CONV_R_UN:
3365 switch (td->sp [-1].type) {
3366 case STACK_TYPE_R8:
3367 break;
3368 case STACK_TYPE_I8:
3369 ADD_CODE(td, MINT_CONV_R_UN_I8);
3370 break;
3371 case STACK_TYPE_I4:
3372 ADD_CODE(td, MINT_CONV_R_UN_I4);
3373 break;
3374 default:
3375 g_assert_not_reached ();
3377 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R8);
3378 ++td->ip;
3379 break;
3380 case CEE_UNBOX:
3381 CHECK_STACK (td, 1);
3382 token = read32 (td->ip + 1);
3384 if (method->wrapper_type != MONO_WRAPPER_NONE)
3385 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3386 else {
3387 klass = mono_class_get_and_inflate_typespec_checked (image, token, generic_context, error);
3388 goto_if_nok (error, exit);
3391 if (mono_class_is_nullable (klass)) {
3392 MonoMethod *target_method;
3393 if (m_class_is_enumtype (mono_class_get_nullable_param (klass)))
3394 target_method = mono_class_get_method_from_name_checked (klass, "UnboxExact", 1, 0, error);
3395 else
3396 target_method = mono_class_get_method_from_name_checked (klass, "Unbox", 1, 0, error);
3397 goto_if_nok (error, exit);
3398 /* td->ip is incremented by interp_transform_call */
3399 interp_transform_call (td, method, target_method, domain, generic_context, is_bb_start, body_start_offset, NULL, FALSE, error, FALSE);
3400 goto_if_nok (error, exit);
3402 * CEE_UNBOX needs to push address of vtype while Nullable.Unbox returns the value type
3403 * We create a local variable in the frame so that we can fetch its address.
3405 int local_offset = create_interp_local (td, m_class_get_byval_arg (klass));
3406 store_local_general (td, local_offset, m_class_get_byval_arg (klass));
3407 ADD_CODE (td, MINT_LDLOCA_S);
3408 ADD_CODE (td, local_offset);
3409 PUSH_SIMPLE_TYPE (td, STACK_TYPE_MP);
3410 } else {
3411 ADD_CODE (td, MINT_UNBOX);
3412 ADD_CODE (td, get_data_item_index (td, klass));
3413 SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_MP);
3414 td->ip += 5;
3416 break;
3417 case CEE_UNBOX_ANY:
3418 CHECK_STACK (td, 1);
3419 token = read32 (td->ip + 1);
3421 klass = mini_get_class (method, token, generic_context);
3422 CHECK_TYPELOAD (klass);
3424 if (mini_type_is_reference (m_class_get_byval_arg (klass))) {
3425 int mt = mint_type (m_class_get_byval_arg (klass));
3426 ADD_CODE (td, MINT_CASTCLASS);
3427 ADD_CODE (td, get_data_item_index (td, klass));
3428 SET_TYPE (td->sp - 1, stack_type [mt], klass);
3429 td->ip += 5;
3430 } else if (mono_class_is_nullable (klass)) {
3431 MonoMethod *target_method;
3432 if (m_class_is_enumtype (mono_class_get_nullable_param (klass)))
3433 target_method = mono_class_get_method_from_name_checked (klass, "UnboxExact", 1, 0, error);
3434 else
3435 target_method = mono_class_get_method_from_name_checked (klass, "Unbox", 1, 0, error);
3436 goto_if_nok (error, exit);
3437 /* td->ip is incremented by interp_transform_call */
3438 interp_transform_call (td, method, target_method, domain, generic_context, is_bb_start, body_start_offset, NULL, FALSE, error, FALSE);
3440 goto_if_nok (error, exit);
3441 } else {
3442 int mt = mint_type (m_class_get_byval_arg (klass));
3443 ADD_CODE (td, MINT_UNBOX);
3444 ADD_CODE (td, get_data_item_index (td, klass));
3446 ADD_CODE (td, (mt == MINT_TYPE_VT) ? MINT_LDOBJ_VT: MINT_LDOBJ);
3447 ADD_CODE (td, get_data_item_index(td, klass));
3448 SET_TYPE (td->sp - 1, stack_type [mt], klass);
3450 if (mt == MINT_TYPE_VT) {
3451 int size = mono_class_value_size (klass, NULL);
3452 PUSH_VT (td, size);
3454 td->ip += 5;
3457 break;
3458 case CEE_THROW:
3459 CHECK_STACK (td, 1);
3460 SIMPLE_OP (td, MINT_THROW);
3461 td->sp = td->stack;
3462 break;
3463 case CEE_LDFLDA: {
3464 CHECK_STACK (td, 1);
3465 token = read32 (td->ip + 1);
3466 field = interp_field_from_token (method, token, &klass, generic_context, error);
3467 goto_if_nok (error, exit);
3468 MonoType *ftype = mono_field_get_type_internal (field);
3469 gboolean is_static = !!(ftype->attrs & FIELD_ATTRIBUTE_STATIC);
3470 mono_class_init (klass);
3471 #ifndef DISABLE_REMOTING
3472 if (m_class_get_marshalbyref (klass) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
3473 g_assert (!is_static);
3474 int offset = m_class_is_valuetype (klass) ? field->offset - MONO_ABI_SIZEOF (MonoObject) : field->offset;
3476 ADD_CODE (td, MINT_MONO_LDPTR);
3477 ADD_CODE (td, get_data_item_index (td, klass));
3478 PUSH_SIMPLE_TYPE (td, STACK_TYPE_I);
3479 ADD_CODE (td, MINT_MONO_LDPTR);
3480 ADD_CODE (td, get_data_item_index (td, field));
3481 PUSH_SIMPLE_TYPE (td, STACK_TYPE_I);
3482 ADD_CODE (td, MINT_LDC_I4);
3483 WRITE32 (td, &offset);
3484 PUSH_SIMPLE_TYPE (td, STACK_TYPE_I4);
3485 #if SIZEOF_VOID_P == 8
3486 ADD_CODE(td, MINT_CONV_I8_I4);
3487 #endif
3489 MonoMethod *wrapper = mono_marshal_get_ldflda_wrapper (field->type);
3490 /* td->ip is incremented by interp_transform_call */
3491 interp_transform_call (td, method, wrapper, domain, generic_context, is_bb_start, body_start_offset, NULL, FALSE, error, FALSE);
3492 goto_if_nok (error, exit);
3493 } else
3494 #endif
3496 if (is_static) {
3497 ADD_CODE (td, MINT_POP);
3498 ADD_CODE (td, 0);
3499 ADD_CODE (td, MINT_LDSFLDA);
3500 ADD_CODE (td, get_data_item_index (td, field));
3501 } else {
3502 if ((td->sp - 1)->type == STACK_TYPE_O) {
3503 ADD_CODE (td, MINT_LDFLDA);
3504 } else {
3505 g_assert ((td->sp -1)->type == STACK_TYPE_MP);
3506 ADD_CODE (td, MINT_LDFLDA_UNSAFE);
3508 ADD_CODE (td, m_class_is_valuetype (klass) ? field->offset - MONO_ABI_SIZEOF (MonoObject) : field->offset);
3510 td->ip += 5;
3512 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_MP);
3513 break;
3515 case CEE_LDFLD: {
3516 CHECK_STACK (td, 1);
3517 token = read32 (td->ip + 1);
3518 field = interp_field_from_token (method, token, &klass, generic_context, error);
3519 goto_if_nok (error, exit);
3520 MonoType *ftype = mono_field_get_type_internal (field);
3521 gboolean is_static = !!(ftype->attrs & FIELD_ATTRIBUTE_STATIC);
3522 mono_class_init (klass);
3524 MonoClass *field_klass = mono_class_from_mono_type_internal (ftype);
3525 mt = mint_type (m_class_get_byval_arg (field_klass));
3526 #ifndef DISABLE_REMOTING
3527 if (m_class_get_marshalbyref (klass)) {
3528 g_assert (!is_static);
3529 ADD_CODE(td, mt == MINT_TYPE_VT ? MINT_LDRMFLD_VT : MINT_LDRMFLD);
3530 ADD_CODE(td, get_data_item_index (td, field));
3531 } else
3532 #endif
3534 if (is_static) {
3535 ADD_CODE (td, MINT_POP);
3536 ADD_CODE (td, 0);
3537 ADD_CODE (td, mt == MINT_TYPE_VT ? MINT_LDSFLD_VT : MINT_LDSFLD);
3538 ADD_CODE (td, get_data_item_index (td, field));
3539 } else {
3540 ADD_CODE (td, MINT_LDFLD_I1 + mt - MINT_TYPE_I1);
3541 ADD_CODE (td, m_class_is_valuetype (klass) ? field->offset - MONO_ABI_SIZEOF (MonoObject) : field->offset);
3542 if (mt == MINT_TYPE_VT)
3543 ADD_CODE (td, get_data_item_index (td, field));
3546 if (mt == MINT_TYPE_VT) {
3547 int size = mono_class_value_size (field_klass, NULL);
3548 PUSH_VT (td, size);
3550 if (td->sp [-1].type == STACK_TYPE_VT) {
3551 int size = mono_class_value_size (klass, NULL);
3552 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
3553 int field_vt_size = 0;
3554 if (mt == MINT_TYPE_VT) {
3556 * Pop the loaded field from the vtstack (it will still be present
3557 * at the same vtstack address) and we will load it in place of the
3558 * containing valuetype with the second MINT_VTRESULT.
3560 field_vt_size = mono_class_value_size (field_klass, NULL);
3561 field_vt_size = ALIGN_TO (field_vt_size, MINT_VT_ALIGNMENT);
3562 ADD_CODE (td, MINT_VTRESULT);
3563 ADD_CODE (td, 0);
3564 WRITE32 (td, &field_vt_size);
3566 td->vt_sp -= size;
3567 ADD_CODE (td, MINT_VTRESULT);
3568 ADD_CODE (td, field_vt_size);
3569 WRITE32 (td, &size);
3571 td->ip += 5;
3572 SET_TYPE (td->sp - 1, stack_type [mt], field_klass);
3573 BARRIER_IF_VOLATILE (td);
3574 break;
3576 case CEE_STFLD: {
3577 CHECK_STACK (td, 2);
3578 token = read32 (td->ip + 1);
3579 field = interp_field_from_token (method, token, &klass, generic_context, error);
3580 goto_if_nok (error, exit);
3581 MonoType *ftype = mono_field_get_type_internal (field);
3582 gboolean is_static = !!(ftype->attrs & FIELD_ATTRIBUTE_STATIC);
3583 mono_class_init (klass);
3584 mt = mint_type (ftype);
3586 BARRIER_IF_VOLATILE (td);
3588 #ifndef DISABLE_REMOTING
3589 if (m_class_get_marshalbyref (klass)) {
3590 g_assert (!is_static);
3591 ADD_CODE(td, mt == MINT_TYPE_VT ? MINT_STRMFLD_VT : MINT_STRMFLD);
3592 ADD_CODE(td, get_data_item_index (td, field));
3593 } else
3594 #endif
3596 if (is_static) {
3597 ADD_CODE (td, MINT_POP);
3598 ADD_CODE (td, 1);
3599 ADD_CODE (td, mt == MINT_TYPE_VT ? MINT_STSFLD_VT : MINT_STSFLD);
3600 ADD_CODE (td, get_data_item_index (td, field));
3602 /* the vtable of the field might not be initialized at this point */
3603 MonoClass *fld_klass = mono_class_from_mono_type_internal (field->type);
3604 mono_class_vtable_checked (domain, fld_klass, error);
3605 goto_if_nok (error, exit);
3606 } else {
3607 ADD_CODE (td, MINT_STFLD_I1 + mt - MINT_TYPE_I1);
3608 ADD_CODE (td, m_class_is_valuetype (klass) ? field->offset - MONO_ABI_SIZEOF (MonoObject) : field->offset);
3609 if (mt == MINT_TYPE_VT) {
3610 ADD_CODE (td, get_data_item_index (td, field));
3612 /* the vtable of the field might not be initialized at this point */
3613 MonoClass *fld_klass = mono_class_from_mono_type_internal (field->type);
3614 mono_class_vtable_checked (domain, fld_klass, error);
3615 goto_if_nok (error, exit);
3619 if (mt == MINT_TYPE_VT) {
3620 MonoClass *klass = mono_class_from_mono_type_internal (ftype);
3621 int size = mono_class_value_size (klass, NULL);
3622 POP_VT (td, size);
3624 td->ip += 5;
3625 td->sp -= 2;
3626 break;
3628 case CEE_LDSFLDA: {
3629 token = read32 (td->ip + 1);
3630 field = interp_field_from_token (method, token, &klass, generic_context, error);
3631 goto_if_nok (error, exit);
3632 mono_field_get_type_internal (field);
3633 ADD_CODE(td, MINT_LDSFLDA);
3634 ADD_CODE(td, get_data_item_index (td, field));
3635 td->ip += 5;
3636 PUSH_SIMPLE_TYPE(td, STACK_TYPE_MP);
3637 break;
3639 case CEE_LDSFLD: {
3640 token = read32 (td->ip + 1);
3641 field = interp_field_from_token (method, token, &klass, generic_context, error);
3642 goto_if_nok (error, exit);
3643 MonoType *ftype = mono_field_get_type_internal (field);
3644 mt = mint_type (ftype);
3645 klass = NULL;
3646 if (mt == MINT_TYPE_VT) {
3647 ADD_CODE(td, MINT_LDSFLD_VT);
3648 ADD_CODE(td, get_data_item_index (td, field));
3649 klass = mono_class_from_mono_type_internal (ftype);
3650 int size = mono_class_value_size (klass, NULL);
3651 PUSH_VT(td, size);
3652 WRITE32(td, &size);
3653 } else {
3654 if (mono_class_field_is_special_static (field)) {
3655 ADD_CODE(td, MINT_LDSFLD);
3656 ADD_CODE(td, get_data_item_index (td, field));
3657 } else {
3658 MonoVTable *vtable = mono_class_vtable_checked (domain, field->parent, error);
3659 goto_if_nok (error, exit);
3661 ADD_CODE(td, MINT_LDSFLD_I1 + mt - MINT_TYPE_I1);
3662 ADD_CODE(td, get_data_item_index (td, vtable));
3663 ADD_CODE(td, get_data_item_index (td, (char*)mono_vtable_get_static_field_data (vtable) + field->offset));
3665 if (mt == MINT_TYPE_O)
3666 klass = mono_class_from_mono_type_internal (ftype);
3668 td->ip += 5;
3669 PUSH_TYPE(td, stack_type [mt], klass);
3670 break;
3672 case CEE_STSFLD: {
3673 CHECK_STACK (td, 1);
3674 token = read32 (td->ip + 1);
3675 field = interp_field_from_token (method, token, &klass, generic_context, error);
3676 goto_if_nok (error, exit);
3677 MonoType *ftype = mono_field_get_type_internal (field);
3678 mt = mint_type (ftype);
3680 /* the vtable of the field might not be initialized at this point */
3681 MonoClass *fld_klass = mono_class_from_mono_type_internal (field->type);
3682 mono_class_vtable_checked (domain, fld_klass, error);
3683 goto_if_nok (error, exit);
3685 if (mt == MINT_TYPE_VT) {
3686 MonoClass *klass = mono_class_from_mono_type_internal (ftype);
3687 int size = mono_class_value_size (klass, NULL);
3688 ADD_CODE(td, MINT_STSFLD_VT);
3689 ADD_CODE(td, get_data_item_index (td, field));
3690 POP_VT (td, size);
3691 } else {
3692 if (mono_class_field_is_special_static (field)) {
3693 ADD_CODE(td, MINT_STSFLD);
3694 ADD_CODE(td, get_data_item_index (td, field));
3695 } else {
3696 MonoVTable *vtable = mono_class_vtable_checked (domain, field->parent, error);
3697 goto_if_nok (error, exit);
3699 ADD_CODE(td, MINT_STSFLD_I1 + mt - MINT_TYPE_I1);
3700 ADD_CODE(td, get_data_item_index (td, vtable));
3701 ADD_CODE(td, get_data_item_index (td, (char*)mono_vtable_get_static_field_data (vtable) + field->offset));
3705 td->ip += 5;
3706 --td->sp;
3707 break;
3709 case CEE_STOBJ: {
3710 int size;
3711 token = read32 (td->ip + 1);
3713 if (method->wrapper_type != MONO_WRAPPER_NONE)
3714 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3715 else
3716 klass = mini_get_class (method, token, generic_context);
3717 CHECK_TYPELOAD (klass);
3719 BARRIER_IF_VOLATILE (td);
3720 ADD_CODE(td, td->sp [-1].type == STACK_TYPE_VT ? MINT_STOBJ_VT : MINT_STOBJ);
3721 ADD_CODE(td, get_data_item_index (td, klass));
3722 if (td->sp [-1].type == STACK_TYPE_VT) {
3723 size = mono_class_value_size (klass, NULL);
3724 POP_VT (td, size);
3726 td->ip += 5;
3727 td->sp -= 2;
3728 break;
3730 case CEE_CONV_OVF_I_UN:
3731 case CEE_CONV_OVF_U_UN:
3732 CHECK_STACK (td, 1);
3733 switch (td->sp [-1].type) {
3734 case STACK_TYPE_R8:
3735 #if SIZEOF_VOID_P == 8
3736 ADD_CODE(td, MINT_CONV_OVF_I8_UN_R8);
3737 #else
3738 ADD_CODE(td, MINT_CONV_OVF_I4_UN_R8);
3739 #endif
3740 break;
3741 case STACK_TYPE_I8:
3742 #if SIZEOF_VOID_P == 4
3743 ADD_CODE (td, MINT_CONV_OVF_I4_UN_I8);
3744 #endif
3745 break;
3746 case STACK_TYPE_I4:
3747 #if SIZEOF_VOID_P == 8
3748 ADD_CODE(td, MINT_CONV_I8_U4);
3749 #elif SIZEOF_VOID_P == 4
3750 if (*td->ip == CEE_CONV_OVF_I_UN)
3751 ADD_CODE(td, MINT_CONV_OVF_I4_U4);
3752 #endif
3753 break;
3754 default:
3755 g_assert_not_reached ();
3756 break;
3758 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8);
3759 ++td->ip;
3760 break;
3761 case CEE_CONV_OVF_I8_UN:
3762 case CEE_CONV_OVF_U8_UN:
3763 CHECK_STACK (td, 1);
3764 switch (td->sp [-1].type) {
3765 case STACK_TYPE_R8:
3766 ADD_CODE(td, MINT_CONV_OVF_I8_UN_R8);
3767 break;
3768 case STACK_TYPE_I8:
3769 if (*td->ip == CEE_CONV_OVF_I8_UN)
3770 ADD_CODE (td, MINT_CONV_OVF_I8_U8);
3771 break;
3772 case STACK_TYPE_I4:
3773 ADD_CODE(td, MINT_CONV_I8_U4);
3774 break;
3775 default:
3776 g_assert_not_reached ();
3777 break;
3779 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8);
3780 ++td->ip;
3781 break;
3782 case CEE_BOX: {
3783 int size;
3784 CHECK_STACK (td, 1);
3785 token = read32 (td->ip + 1);
3786 if (method->wrapper_type != MONO_WRAPPER_NONE)
3787 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3788 else
3789 klass = mini_get_class (method, token, generic_context);
3790 CHECK_TYPELOAD (klass);
3792 if (mono_class_is_nullable (klass)) {
3793 MonoMethod *target_method = mono_class_get_method_from_name_checked (klass, "Box", 1, 0, error);
3794 goto_if_nok (error, exit);
3795 /* td->ip is incremented by interp_transform_call */
3796 interp_transform_call (td, method, target_method, domain, generic_context, is_bb_start, body_start_offset, NULL, FALSE, error, FALSE);
3797 goto_if_nok (error, exit);
3798 } else if (!m_class_is_valuetype (klass)) {
3799 /* already boxed, do nothing. */
3800 td->ip += 5;
3801 } else {
3802 if (G_UNLIKELY (m_class_is_byreflike (klass))) {
3803 mono_error_set_bad_image (error, image, "Cannot box IsByRefLike type '%s.%s'", m_class_get_name_space (klass), m_class_get_name (klass));
3804 goto exit;
3806 if (mint_type (m_class_get_byval_arg (klass)) == MINT_TYPE_VT && !m_class_is_enumtype (klass)) {
3807 size = mono_class_value_size (klass, NULL);
3808 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
3809 td->vt_sp -= size;
3810 } else if (td->sp [-1].type == STACK_TYPE_R8 && m_class_get_byval_arg (klass)->type == MONO_TYPE_R4) {
3811 ADD_CODE (td, MINT_CONV_R4_R8);
3813 if (mint_type (m_class_get_byval_arg (klass)) == MINT_TYPE_VT)
3814 ADD_CODE (td, MINT_BOX_VT);
3815 else
3816 ADD_CODE (td, MINT_BOX);
3817 ADD_CODE(td, get_data_item_index (td, klass));
3818 ADD_CODE (td, 0);
3819 SET_TYPE(td->sp - 1, STACK_TYPE_O, klass);
3820 td->ip += 5;
3823 break;
3825 case CEE_NEWARR: {
3826 CHECK_STACK (td, 1);
3827 token = read32 (td->ip + 1);
3829 if (method->wrapper_type != MONO_WRAPPER_NONE)
3830 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3831 else
3832 klass = mini_get_class (method, token, generic_context);
3833 CHECK_TYPELOAD (klass);
3835 unsigned char lentype = (td->sp - 1)->type;
3836 if (lentype == STACK_TYPE_I8) {
3837 /* mimic mini behaviour */
3838 ADD_CODE (td, MINT_CONV_OVF_U4_I8);
3839 } else {
3840 g_assert (lentype == STACK_TYPE_I4);
3841 ADD_CODE (td, MINT_CONV_OVF_U4_I4);
3843 SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I4);
3844 ADD_CODE (td, MINT_NEWARR);
3845 ADD_CODE (td, get_data_item_index (td, klass));
3846 SET_TYPE (td->sp - 1, STACK_TYPE_O, klass);
3847 td->ip += 5;
3848 break;
3850 case CEE_LDLEN:
3851 CHECK_STACK (td, 1);
3852 SIMPLE_OP (td, MINT_LDLEN);
3853 #ifdef MONO_BIG_ARRAYS
3854 SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I8);
3855 #else
3856 SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I4);
3857 #endif
3858 break;
3859 case CEE_LDELEMA:
3860 CHECK_STACK (td, 2);
3861 ENSURE_I4 (td, 1);
3862 token = read32 (td->ip + 1);
3864 if (method->wrapper_type != MONO_WRAPPER_NONE)
3865 klass = (MonoClass *) mono_method_get_wrapper_data (method, token);
3866 else
3867 klass = mini_get_class (method, token, generic_context);
3869 CHECK_TYPELOAD (klass);
3871 if (!m_class_is_valuetype (klass) && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
3873 * Check the class for failures before the type check, which can
3874 * throw other exceptions.
3876 mono_class_setup_vtable (klass);
3877 CHECK_TYPELOAD (klass);
3878 ADD_CODE (td, MINT_LDELEMA_TC);
3879 } else {
3880 ADD_CODE (td, MINT_LDELEMA);
3882 ADD_CODE (td, get_data_item_index (td, klass));
3883 /* according to spec, ldelema bytecode is only used for 1-dim arrays */
3884 ADD_CODE (td, 2);
3885 readonly = FALSE;
3887 td->ip += 5;
3888 --td->sp;
3889 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_MP);
3890 break;
3891 case CEE_LDELEM_I1:
3892 CHECK_STACK (td, 2);
3893 ENSURE_I4 (td, 1);
3894 SIMPLE_OP (td, MINT_LDELEM_I1);
3895 --td->sp;
3896 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
3897 break;
3898 case CEE_LDELEM_U1:
3899 CHECK_STACK (td, 2);
3900 ENSURE_I4 (td, 1);
3901 SIMPLE_OP (td, MINT_LDELEM_U1);
3902 --td->sp;
3903 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
3904 break;
3905 case CEE_LDELEM_I2:
3906 CHECK_STACK (td, 2);
3907 ENSURE_I4 (td, 1);
3908 SIMPLE_OP (td, MINT_LDELEM_I2);
3909 --td->sp;
3910 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
3911 break;
3912 case CEE_LDELEM_U2:
3913 CHECK_STACK (td, 2);
3914 ENSURE_I4 (td, 1);
3915 SIMPLE_OP (td, MINT_LDELEM_U2);
3916 --td->sp;
3917 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
3918 break;
3919 case CEE_LDELEM_I4:
3920 CHECK_STACK (td, 2);
3921 ENSURE_I4 (td, 1);
3922 SIMPLE_OP (td, MINT_LDELEM_I4);
3923 --td->sp;
3924 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
3925 break;
3926 case CEE_LDELEM_U4:
3927 CHECK_STACK (td, 2);
3928 ENSURE_I4 (td, 1);
3929 SIMPLE_OP (td, MINT_LDELEM_U4);
3930 --td->sp;
3931 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
3932 break;
3933 case CEE_LDELEM_I8:
3934 CHECK_STACK (td, 2);
3935 ENSURE_I4 (td, 1);
3936 SIMPLE_OP (td, MINT_LDELEM_I8);
3937 --td->sp;
3938 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8);
3939 break;
3940 case CEE_LDELEM_I:
3941 CHECK_STACK (td, 2);
3942 ENSURE_I4 (td, 1);
3943 SIMPLE_OP (td, MINT_LDELEM_I);
3944 --td->sp;
3945 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I);
3946 break;
3947 case CEE_LDELEM_R4:
3948 CHECK_STACK (td, 2);
3949 ENSURE_I4 (td, 1);
3950 SIMPLE_OP (td, MINT_LDELEM_R4);
3951 --td->sp;
3952 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R4);
3953 break;
3954 case CEE_LDELEM_R8:
3955 CHECK_STACK (td, 2);
3956 ENSURE_I4 (td, 1);
3957 SIMPLE_OP (td, MINT_LDELEM_R8);
3958 --td->sp;
3959 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R8);
3960 break;
3961 case CEE_LDELEM_REF:
3962 CHECK_STACK (td, 2);
3963 ENSURE_I4 (td, 1);
3964 SIMPLE_OP (td, MINT_LDELEM_REF);
3965 --td->sp;
3966 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_O);
3967 break;
3968 case CEE_LDELEM:
3969 CHECK_STACK (td, 2);
3970 token = read32 (td->ip + 1);
3971 klass = mini_get_class (method, token, generic_context);
3972 CHECK_TYPELOAD (klass);
3973 switch (mint_type (m_class_get_byval_arg (klass))) {
3974 case MINT_TYPE_I1:
3975 ENSURE_I4 (td, 1);
3976 SIMPLE_OP (td, MINT_LDELEM_I1);
3977 --td->sp;
3978 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
3979 break;
3980 case MINT_TYPE_U1:
3981 ENSURE_I4 (td, 1);
3982 SIMPLE_OP (td, MINT_LDELEM_U1);
3983 --td->sp;
3984 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
3985 break;
3986 case MINT_TYPE_U2:
3987 ENSURE_I4 (td, 1);
3988 SIMPLE_OP (td, MINT_LDELEM_U2);
3989 --td->sp;
3990 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
3991 break;
3992 case MINT_TYPE_I2:
3993 ENSURE_I4 (td, 1);
3994 SIMPLE_OP (td, MINT_LDELEM_I2);
3995 --td->sp;
3996 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
3997 break;
3998 case MINT_TYPE_I4:
3999 ENSURE_I4 (td, 1);
4000 SIMPLE_OP (td, MINT_LDELEM_I4);
4001 --td->sp;
4002 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
4003 break;
4004 case MINT_TYPE_I8:
4005 ENSURE_I4 (td, 1);
4006 SIMPLE_OP (td, MINT_LDELEM_I8);
4007 --td->sp;
4008 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8);
4009 break;
4010 case MINT_TYPE_R4:
4011 ENSURE_I4 (td, 1);
4012 SIMPLE_OP (td, MINT_LDELEM_R4);
4013 --td->sp;
4014 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R4);
4015 break;
4016 case MINT_TYPE_R8:
4017 ENSURE_I4 (td, 1);
4018 SIMPLE_OP (td, MINT_LDELEM_R8);
4019 --td->sp;
4020 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R8);
4021 break;
4022 case MINT_TYPE_O:
4023 ENSURE_I4 (td, 1);
4024 SIMPLE_OP (td, MINT_LDELEM_REF);
4025 --td->sp;
4026 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_O);
4027 break;
4028 case MINT_TYPE_VT: {
4029 int size = mono_class_value_size (klass, NULL);
4030 ENSURE_I4 (td, 1);
4031 SIMPLE_OP (td, MINT_LDELEM_VT);
4032 ADD_CODE (td, get_data_item_index (td, klass));
4033 WRITE32 (td, &size);
4034 --td->sp;
4035 SET_TYPE (td->sp - 1, STACK_TYPE_VT, klass);
4036 PUSH_VT (td, size);
4037 break;
4039 default: {
4040 GString *res = g_string_new ("");
4041 mono_type_get_desc (res, m_class_get_byval_arg (klass), TRUE);
4042 g_print ("LDELEM: %s -> %d (%s)\n", m_class_get_name (klass), mint_type (m_class_get_byval_arg (klass)), res->str);
4043 g_string_free (res, TRUE);
4044 g_assert (0);
4045 break;
4048 td->ip += 4;
4049 break;
4050 case CEE_STELEM_I:
4051 CHECK_STACK (td, 3);
4052 ENSURE_I4 (td, 2);
4053 SIMPLE_OP (td, MINT_STELEM_I);
4054 td->sp -= 3;
4055 break;
4056 case CEE_STELEM_I1:
4057 CHECK_STACK (td, 3);
4058 ENSURE_I4 (td, 2);
4059 SIMPLE_OP (td, MINT_STELEM_I1);
4060 td->sp -= 3;
4061 break;
4062 case CEE_STELEM_I2:
4063 CHECK_STACK (td, 3);
4064 ENSURE_I4 (td, 2);
4065 SIMPLE_OP (td, MINT_STELEM_I2);
4066 td->sp -= 3;
4067 break;
4068 case CEE_STELEM_I4:
4069 CHECK_STACK (td, 3);
4070 ENSURE_I4 (td, 2);
4071 SIMPLE_OP (td, MINT_STELEM_I4);
4072 td->sp -= 3;
4073 break;
4074 case CEE_STELEM_I8:
4075 CHECK_STACK (td, 3);
4076 ENSURE_I4 (td, 2);
4077 SIMPLE_OP (td, MINT_STELEM_I8);
4078 td->sp -= 3;
4079 break;
4080 case CEE_STELEM_R4:
4081 CHECK_STACK (td, 3);
4082 ENSURE_I4 (td, 2);
4083 SIMPLE_OP (td, MINT_STELEM_R4);
4084 td->sp -= 3;
4085 break;
4086 case CEE_STELEM_R8:
4087 CHECK_STACK (td, 3);
4088 ENSURE_I4 (td, 2);
4089 SIMPLE_OP (td, MINT_STELEM_R8);
4090 td->sp -= 3;
4091 break;
4092 case CEE_STELEM_REF:
4093 CHECK_STACK (td, 3);
4094 ENSURE_I4 (td, 2);
4095 SIMPLE_OP (td, MINT_STELEM_REF);
4096 td->sp -= 3;
4097 break;
4098 case CEE_STELEM:
4099 CHECK_STACK (td, 3);
4100 ENSURE_I4 (td, 2);
4101 token = read32 (td->ip + 1);
4102 klass = mini_get_class (method, token, generic_context);
4103 CHECK_TYPELOAD (klass);
4104 switch (mint_type (m_class_get_byval_arg (klass))) {
4105 case MINT_TYPE_I1:
4106 SIMPLE_OP (td, MINT_STELEM_I1);
4107 break;
4108 case MINT_TYPE_U1:
4109 SIMPLE_OP (td, MINT_STELEM_U1);
4110 break;
4111 case MINT_TYPE_I2:
4112 SIMPLE_OP (td, MINT_STELEM_I2);
4113 break;
4114 case MINT_TYPE_U2:
4115 SIMPLE_OP (td, MINT_STELEM_U2);
4116 break;
4117 case MINT_TYPE_I4:
4118 SIMPLE_OP (td, MINT_STELEM_I4);
4119 break;
4120 case MINT_TYPE_I8:
4121 SIMPLE_OP (td, MINT_STELEM_I8);
4122 break;
4123 case MINT_TYPE_R4:
4124 SIMPLE_OP (td, MINT_STELEM_R4);
4125 break;
4126 case MINT_TYPE_R8:
4127 SIMPLE_OP (td, MINT_STELEM_R8);
4128 break;
4129 case MINT_TYPE_O:
4130 SIMPLE_OP (td, MINT_STELEM_REF);
4131 break;
4132 case MINT_TYPE_VT: {
4133 int size = mono_class_value_size (klass, NULL);
4134 SIMPLE_OP (td, MINT_STELEM_VT);
4135 ADD_CODE (td, get_data_item_index (td, klass));
4136 WRITE32 (td, &size);
4137 POP_VT (td, size);
4138 break;
4140 default: {
4141 GString *res = g_string_new ("");
4142 mono_type_get_desc (res, m_class_get_byval_arg (klass), TRUE);
4143 g_print ("STELEM: %s -> %d (%s)\n", m_class_get_name (klass), mint_type (m_class_get_byval_arg (klass)), res->str);
4144 g_string_free (res, TRUE);
4145 g_assert (0);
4146 break;
4149 td->ip += 4;
4150 td->sp -= 3;
4151 break;
4152 #if 0
4153 case CEE_CONV_OVF_U1:
4155 case CEE_CONV_OVF_I8:
4157 #if SIZEOF_VOID_P == 8
4158 case CEE_CONV_OVF_U:
4159 #endif
4160 #endif
4161 case CEE_CKFINITE:
4162 CHECK_STACK (td, 1);
4163 SIMPLE_OP (td, MINT_CKFINITE);
4164 break;
4165 case CEE_MKREFANY:
4166 CHECK_STACK (td, 1);
4168 token = read32 (td->ip + 1);
4169 klass = mini_get_class (method, token, generic_context);
4170 CHECK_TYPELOAD (klass);
4172 ADD_CODE (td, MINT_MKREFANY);
4173 ADD_CODE (td, get_data_item_index (td, klass));
4175 td->ip += 5;
4176 PUSH_VT (td, sizeof (MonoTypedRef));
4177 SET_TYPE(td->sp - 1, STACK_TYPE_VT, mono_defaults.typed_reference_class);
4178 break;
4179 case CEE_REFANYVAL: {
4180 CHECK_STACK (td, 1);
4182 token = read32 (td->ip + 1);
4183 klass = mini_get_class (method, token, generic_context);
4184 CHECK_TYPELOAD (klass);
4186 ADD_CODE (td, MINT_REFANYVAL);
4187 ADD_CODE (td, get_data_item_index (td, klass));
4189 POP_VT (td, sizeof (MonoTypedRef));
4190 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_MP);
4192 td->ip += 5;
4193 break;
4195 case CEE_CONV_OVF_I1:
4196 case CEE_CONV_OVF_I1_UN: {
4197 gboolean is_un = *td->ip == CEE_CONV_OVF_I1_UN;
4198 CHECK_STACK (td, 1);
4199 switch (td->sp [-1].type) {
4200 case STACK_TYPE_R8:
4201 ADD_CODE(td, is_un ? MINT_CONV_OVF_I1_UN_R8 : MINT_CONV_OVF_I1_R8);
4202 break;
4203 case STACK_TYPE_I4:
4204 ADD_CODE(td, is_un ? MINT_CONV_OVF_I1_U4 : MINT_CONV_OVF_I1_I4);
4205 break;
4206 case STACK_TYPE_I8:
4207 ADD_CODE(td, is_un ? MINT_CONV_OVF_I1_U8 : MINT_CONV_OVF_I1_I8);
4208 break;
4209 default:
4210 g_assert_not_reached ();
4212 ++td->ip;
4213 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
4214 break;
4216 case CEE_CONV_OVF_U1:
4217 case CEE_CONV_OVF_U1_UN:
4218 CHECK_STACK (td, 1);
4219 switch (td->sp [-1].type) {
4220 case STACK_TYPE_R8:
4221 ADD_CODE(td, MINT_CONV_OVF_U1_R8);
4222 break;
4223 case STACK_TYPE_I4:
4224 ADD_CODE(td, MINT_CONV_OVF_U1_I4);
4225 break;
4226 case STACK_TYPE_I8:
4227 ADD_CODE(td, MINT_CONV_OVF_U1_I8);
4228 break;
4229 default:
4230 g_assert_not_reached ();
4232 ++td->ip;
4233 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
4234 break;
4235 case CEE_CONV_OVF_I2:
4236 case CEE_CONV_OVF_I2_UN: {
4237 gboolean is_un = *td->ip == CEE_CONV_OVF_I2_UN;
4238 CHECK_STACK (td, 1);
4239 switch (td->sp [-1].type) {
4240 case STACK_TYPE_R8:
4241 ADD_CODE(td, is_un ? MINT_CONV_OVF_I2_UN_R8 : MINT_CONV_OVF_I2_R8);
4242 break;
4243 case STACK_TYPE_I4:
4244 ADD_CODE(td, is_un ? MINT_CONV_OVF_I2_U4 : MINT_CONV_OVF_I2_I4);
4245 break;
4246 case STACK_TYPE_I8:
4247 ADD_CODE(td, is_un ? MINT_CONV_OVF_I2_U8 : MINT_CONV_OVF_I2_I8);
4248 break;
4249 default:
4250 g_assert_not_reached ();
4252 ++td->ip;
4253 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
4254 break;
4256 case CEE_CONV_OVF_U2_UN:
4257 case CEE_CONV_OVF_U2:
4258 CHECK_STACK (td, 1);
4259 switch (td->sp [-1].type) {
4260 case STACK_TYPE_R8:
4261 ADD_CODE(td, MINT_CONV_OVF_U2_R8);
4262 break;
4263 case STACK_TYPE_I4:
4264 ADD_CODE(td, MINT_CONV_OVF_U2_I4);
4265 break;
4266 case STACK_TYPE_I8:
4267 ADD_CODE(td, MINT_CONV_OVF_U2_I8);
4268 break;
4269 default:
4270 g_assert_not_reached ();
4272 ++td->ip;
4273 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
4274 break;
4275 #if SIZEOF_VOID_P == 4
4276 case CEE_CONV_OVF_I:
4277 #endif
4278 case CEE_CONV_OVF_I4:
4279 case CEE_CONV_OVF_I4_UN:
4280 CHECK_STACK (td, 1);
4281 switch (td->sp [-1].type) {
4282 case STACK_TYPE_R4:
4283 ADD_CODE(td, MINT_CONV_OVF_I4_R4);
4284 break;
4285 case STACK_TYPE_R8:
4286 ADD_CODE(td, MINT_CONV_OVF_I4_R8);
4287 break;
4288 case STACK_TYPE_I4:
4289 if (*td->ip == CEE_CONV_OVF_I4_UN)
4290 ADD_CODE(td, MINT_CONV_OVF_I4_U4);
4291 break;
4292 case STACK_TYPE_I8:
4293 if (*td->ip == CEE_CONV_OVF_I4_UN)
4294 ADD_CODE (td, MINT_CONV_OVF_I4_U8);
4295 else
4296 ADD_CODE (td, MINT_CONV_OVF_I4_I8);
4297 break;
4298 default:
4299 g_assert_not_reached ();
4301 ++td->ip;
4302 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
4303 break;
4304 #if SIZEOF_VOID_P == 4
4305 case CEE_CONV_OVF_U:
4306 #endif
4307 case CEE_CONV_OVF_U4:
4308 case CEE_CONV_OVF_U4_UN:
4309 CHECK_STACK (td, 1);
4310 switch (td->sp [-1].type) {
4311 case STACK_TYPE_R4:
4312 ADD_CODE(td, MINT_CONV_OVF_U4_R4);
4313 break;
4314 case STACK_TYPE_R8:
4315 ADD_CODE(td, MINT_CONV_OVF_U4_R8);
4316 break;
4317 case STACK_TYPE_I4:
4318 if (*td->ip != CEE_CONV_OVF_U4_UN)
4319 ADD_CODE(td, MINT_CONV_OVF_U4_I4);
4320 break;
4321 case STACK_TYPE_I8:
4322 ADD_CODE(td, MINT_CONV_OVF_U4_I8);
4323 break;
4324 default:
4325 g_assert_not_reached ();
4327 ++td->ip;
4328 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
4329 break;
4330 #if SIZEOF_VOID_P == 8
4331 case CEE_CONV_OVF_I:
4332 #endif
4333 case CEE_CONV_OVF_I8:
4334 CHECK_STACK (td, 1);
4335 switch (td->sp [-1].type) {
4336 case STACK_TYPE_R4:
4337 ADD_CODE(td, MINT_CONV_OVF_I8_R4);
4338 break;
4339 case STACK_TYPE_R8:
4340 ADD_CODE(td, MINT_CONV_OVF_I8_R8);
4341 break;
4342 case STACK_TYPE_I4:
4343 ADD_CODE(td, MINT_CONV_I8_I4);
4344 break;
4345 case STACK_TYPE_I8:
4346 break;
4347 default:
4348 g_assert_not_reached ();
4350 ++td->ip;
4351 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8);
4352 break;
4353 #if SIZEOF_VOID_P == 8
4354 case CEE_CONV_OVF_U:
4355 #endif
4356 case CEE_CONV_OVF_U8:
4357 CHECK_STACK (td, 1);
4358 switch (td->sp [-1].type) {
4359 case STACK_TYPE_R4:
4360 ADD_CODE(td, MINT_CONV_OVF_U8_R4);
4361 break;
4362 case STACK_TYPE_R8:
4363 ADD_CODE(td, MINT_CONV_OVF_U8_R8);
4364 break;
4365 case STACK_TYPE_I4:
4366 ADD_CODE(td, MINT_CONV_OVF_U8_I4);
4367 break;
4368 case STACK_TYPE_I8:
4369 ADD_CODE (td, MINT_CONV_OVF_U8_I8);
4370 break;
4371 default:
4372 g_assert_not_reached ();
4374 ++td->ip;
4375 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8);
4376 break;
4377 case CEE_LDTOKEN: {
4378 int size;
4379 gpointer handle;
4380 token = read32 (td->ip + 1);
4381 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
4382 handle = mono_method_get_wrapper_data (method, token);
4383 klass = (MonoClass *) mono_method_get_wrapper_data (method, token + 1);
4384 if (klass == mono_defaults.typehandle_class)
4385 handle = m_class_get_byval_arg ((MonoClass *) handle);
4387 if (generic_context) {
4388 handle = mono_class_inflate_generic_type_checked ((MonoType*)handle, generic_context, error);
4389 goto_if_nok (error, exit);
4391 } else {
4392 handle = mono_ldtoken_checked (image, token, &klass, generic_context, error);
4393 goto_if_nok (error, exit);
4395 mono_class_init (klass);
4396 mt = mint_type (m_class_get_byval_arg (klass));
4397 g_assert (mt == MINT_TYPE_VT);
4398 size = mono_class_value_size (klass, NULL);
4399 g_assert (size == sizeof(gpointer));
4401 const unsigned char *next_ip = td->ip + 5;
4402 MonoMethod *cmethod;
4403 if (next_ip < end &&
4404 !is_bb_start [next_ip - td->il_code] &&
4405 (*next_ip == CEE_CALL || *next_ip == CEE_CALLVIRT) &&
4406 (cmethod = mono_get_method_checked (image, read32 (next_ip + 1), NULL, generic_context, error)) &&
4407 (cmethod->klass == mono_defaults.systemtype_class) &&
4408 (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
4409 ADD_CODE (td, MINT_MONO_LDPTR);
4410 gpointer systype = mono_type_get_object_checked (domain, (MonoType*)handle, error);
4411 goto_if_nok (error, exit);
4412 ADD_CODE (td, get_data_item_index (td, systype));
4413 PUSH_SIMPLE_TYPE (td, STACK_TYPE_MP);
4414 td->ip = next_ip + 5;
4415 } else {
4416 PUSH_VT (td, sizeof(gpointer));
4417 ADD_CODE (td, MINT_LDTOKEN);
4418 ADD_CODE (td, get_data_item_index (td, handle));
4419 SET_TYPE (td->sp, stack_type [mt], klass);
4420 td->sp++;
4421 td->ip += 5;
4424 break;
4426 case CEE_ADD_OVF:
4427 binary_arith_op(td, MINT_ADD_OVF_I4);
4428 ++td->ip;
4429 break;
4430 case CEE_ADD_OVF_UN:
4431 binary_arith_op(td, MINT_ADD_OVF_UN_I4);
4432 ++td->ip;
4433 break;
4434 case CEE_MUL_OVF:
4435 binary_arith_op(td, MINT_MUL_OVF_I4);
4436 ++td->ip;
4437 break;
4438 case CEE_MUL_OVF_UN:
4439 binary_arith_op(td, MINT_MUL_OVF_UN_I4);
4440 ++td->ip;
4441 break;
4442 case CEE_SUB_OVF:
4443 binary_arith_op(td, MINT_SUB_OVF_I4);
4444 ++td->ip;
4445 break;
4446 case CEE_SUB_OVF_UN:
4447 binary_arith_op(td, MINT_SUB_OVF_UN_I4);
4448 ++td->ip;
4449 break;
4450 case CEE_ENDFINALLY: {
4451 g_assert (td->clause_indexes [in_offset] != -1);
4452 td->sp = td->stack;
4453 SIMPLE_OP (td, MINT_ENDFINALLY);
4454 ADD_CODE (td, td->clause_indexes [in_offset]);
4455 break;
4457 case CEE_LEAVE:
4458 case CEE_LEAVE_S: {
4459 int offset;
4461 if (*td->ip == CEE_LEAVE)
4462 offset = 5 + read32 (td->ip + 1);
4463 else
4464 offset = 2 + (gint8)td->ip [1];
4466 td->sp = td->stack;
4467 if (td->clause_indexes [in_offset] != -1) {
4468 /* LEAVE instructions in catch clauses need to check for abort exceptions */
4469 handle_branch (td, MINT_LEAVE_S_CHECK, MINT_LEAVE_CHECK, offset);
4470 } else {
4471 handle_branch (td, MINT_LEAVE_S, MINT_LEAVE, offset);
4474 if (*td->ip == CEE_LEAVE)
4475 td->ip += 5;
4476 else
4477 td->ip += 2;
4478 break;
4480 case MONO_CUSTOM_PREFIX:
4481 ++td->ip;
4482 switch (*td->ip) {
4483 case CEE_MONO_RETHROW:
4484 CHECK_STACK (td, 1);
4485 SIMPLE_OP (td, MINT_MONO_RETHROW);
4486 td->sp = td->stack;
4487 break;
4489 case CEE_MONO_LD_DELEGATE_METHOD_PTR:
4490 --td->sp;
4491 td->ip += 1;
4492 ADD_CODE (td, MINT_LD_DELEGATE_METHOD_PTR);
4493 PUSH_SIMPLE_TYPE (td, STACK_TYPE_I);
4494 break;
4495 case CEE_MONO_CALLI_EXTRA_ARG:
4496 /* Same as CEE_CALLI, except that we drop the extra arg required for llvm specific behaviour */
4497 ADD_CODE (td, MINT_POP);
4498 ADD_CODE (td, 1);
4499 --td->sp;
4500 interp_transform_call (td, method, NULL, domain, generic_context, is_bb_start, body_start_offset, NULL, FALSE, error, FALSE);
4501 goto_if_nok (error, exit);
4502 break;
4503 case CEE_MONO_JIT_ICALL_ADDR: {
4504 guint32 token;
4505 gpointer func;
4506 MonoJitICallInfo *info;
4508 token = read32 (td->ip + 1);
4509 td->ip += 5;
4510 func = mono_method_get_wrapper_data (method, token);
4511 info = mono_find_jit_icall_by_addr (func);
4513 ADD_CODE (td, MINT_LDFTN);
4514 ADD_CODE (td, get_data_item_index (td, func));
4515 PUSH_SIMPLE_TYPE (td, STACK_TYPE_I);
4516 break;
4518 case CEE_MONO_ICALL: {
4519 guint32 token;
4520 gpointer func;
4521 MonoJitICallInfo *info;
4522 int icall_op;
4524 token = read32 (td->ip + 1);
4525 td->ip += 5;
4526 func = mono_method_get_wrapper_data (method, token);
4527 info = mono_find_jit_icall_by_addr (func);
4528 g_assert (info);
4530 CHECK_STACK (td, info->sig->param_count);
4531 if (!strcmp (info->name, "mono_threads_attach_coop")) {
4532 rtm->needs_thread_attach = 1;
4534 /* attach needs two arguments, and has one return value: leave one element on the stack */
4535 ADD_CODE (td, MINT_POP);
4536 ADD_CODE (td, 0);
4537 } else if (!strcmp (info->name, "mono_threads_detach_coop")) {
4538 g_assert (rtm->needs_thread_attach);
4540 /* detach consumes two arguments, and no return value: drop both of them */
4541 ADD_CODE (td, MINT_POP);
4542 ADD_CODE (td, 0);
4543 ADD_CODE (td, MINT_POP);
4544 ADD_CODE (td, 0);
4545 } else {
4546 icall_op = interp_icall_op_for_sig (info->sig);
4547 g_assert (icall_op != -1);
4549 ADD_CODE(td, icall_op);
4550 ADD_CODE(td, get_data_item_index (td, func));
4552 td->sp -= info->sig->param_count;
4554 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
4555 int mt = mint_type (info->sig->ret);
4556 td->sp ++;
4557 SET_SIMPLE_TYPE(td->sp - 1, stack_type [mt]);
4559 break;
4561 case CEE_MONO_VTADDR: {
4562 int size;
4563 CHECK_STACK (td, 1);
4564 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
4565 size = mono_class_native_size(td->sp [-1].klass, NULL);
4566 else
4567 size = mono_class_value_size(td->sp [-1].klass, NULL);
4568 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
4569 ADD_CODE(td, MINT_VTRESULT);
4570 ADD_CODE(td, 0);
4571 WRITE32(td, &size);
4572 td->vt_sp -= size;
4573 ++td->ip;
4574 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_MP);
4575 break;
4577 case CEE_MONO_LDPTR:
4578 case CEE_MONO_CLASSCONST:
4579 token = read32 (td->ip + 1);
4580 td->ip += 5;
4581 ADD_CODE(td, MINT_MONO_LDPTR);
4582 ADD_CODE(td, get_data_item_index (td, mono_method_get_wrapper_data (method, token)));
4583 td->sp [0].type = STACK_TYPE_I;
4584 ++td->sp;
4585 break;
4586 case CEE_MONO_OBJADDR:
4587 CHECK_STACK (td, 1);
4588 ++td->ip;
4589 td->sp[-1].type = STACK_TYPE_MP;
4590 /* do nothing? */
4591 break;
4592 case CEE_MONO_NEWOBJ:
4593 token = read32 (td->ip + 1);
4594 td->ip += 5;
4595 ADD_CODE(td, MINT_MONO_NEWOBJ);
4596 ADD_CODE(td, get_data_item_index (td, mono_method_get_wrapper_data (method, token)));
4597 td->sp [0].type = STACK_TYPE_O;
4598 ++td->sp;
4599 break;
4600 case CEE_MONO_RETOBJ:
4601 CHECK_STACK (td, 1);
4602 token = read32 (td->ip + 1);
4603 td->ip += 5;
4604 ADD_CODE(td, MINT_MONO_RETOBJ);
4605 td->sp--;
4607 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
4609 /*stackval_from_data (signature->ret, frame->retval, sp->data.vt, signature->pinvoke);*/
4611 if (td->sp > td->stack)
4612 g_warning ("CEE_MONO_RETOBJ: more values on stack: %d", td->sp-td->stack);
4613 break;
4614 case CEE_MONO_LDNATIVEOBJ:
4615 token = read32 (td->ip + 1);
4616 td->ip += 5;
4617 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
4618 g_assert(m_class_is_valuetype (klass));
4619 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_MP);
4620 break;
4621 case CEE_MONO_TLS: {
4622 gint32 key = read32 (td->ip + 1);
4623 td->ip += 5;
4624 g_assert (key < TLS_KEY_NUM);
4625 ADD_CODE (td, MINT_MONO_TLS);
4626 WRITE32 (td, &key);
4627 PUSH_SIMPLE_TYPE (td, STACK_TYPE_MP);
4628 break;
4630 case CEE_MONO_ATOMIC_STORE_I4:
4631 CHECK_STACK (td, 2);
4632 SIMPLE_OP (td, MINT_MONO_ATOMIC_STORE_I4);
4633 td->sp -= 2;
4634 td->ip++;
4635 break;
4636 case CEE_MONO_SAVE_LMF:
4637 case CEE_MONO_RESTORE_LMF:
4638 case CEE_MONO_NOT_TAKEN:
4639 ++td->ip;
4640 break;
4641 case CEE_MONO_LDPTR_INT_REQ_FLAG:
4642 ADD_CODE (td, MINT_MONO_LDPTR);
4643 ADD_CODE (td, get_data_item_index (td, mono_thread_interruption_request_flag ()));
4644 PUSH_TYPE (td, STACK_TYPE_MP, NULL);
4645 ++td->ip;
4646 break;
4647 case CEE_MONO_MEMORY_BARRIER:
4648 ADD_CODE (td, MINT_MONO_MEMORY_BARRIER);
4649 ++td->ip;
4650 break;
4651 case CEE_MONO_LDDOMAIN:
4652 ADD_CODE (td, MINT_MONO_LDDOMAIN);
4653 td->sp [0].type = STACK_TYPE_I;
4654 ++td->sp;
4655 ++td->ip;
4656 break;
4657 default:
4658 g_error ("transform.c: Unimplemented opcode: 0xF0 %02x at 0x%x\n", *td->ip, td->ip-header->code);
4660 break;
4661 #if 0
4662 case CEE_PREFIX7:
4663 case CEE_PREFIX6:
4664 case CEE_PREFIX5:
4665 case CEE_PREFIX4:
4666 case CEE_PREFIX3:
4667 case CEE_PREFIX2:
4668 case CEE_PREFIXREF: ves_abort(); break;
4669 #endif
4671 * Note: Exceptions thrown when executing a prefixed opcode need
4672 * to take into account the number of prefix bytes (usually the
4673 * throw point is just (ip - n_prefix_bytes).
4675 case CEE_PREFIX1:
4676 ++td->ip;
4677 switch (*td->ip) {
4678 case CEE_ARGLIST:
4679 ADD_CODE (td, MINT_ARGLIST);
4680 PUSH_VT (td, SIZEOF_VOID_P);
4681 PUSH_SIMPLE_TYPE (td, STACK_TYPE_VT);
4682 ++td->ip;
4683 break;
4684 case CEE_CEQ:
4685 CHECK_STACK(td, 2);
4686 if (td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP) {
4687 ADD_CODE(td, MINT_CEQ_I4 + STACK_TYPE_I - STACK_TYPE_I4);
4688 } else {
4689 if (td->sp [-1].type == STACK_TYPE_R4 && td->sp [-2].type == STACK_TYPE_R8)
4690 ADD_CODE (td, MINT_CONV_R8_R4);
4691 if (td->sp [-1].type == STACK_TYPE_R8 && td->sp [-2].type == STACK_TYPE_R4)
4692 ADD_CODE (td, MINT_CONV_R8_R4_SP);
4693 ADD_CODE(td, MINT_CEQ_I4 + td->sp [-1].type - STACK_TYPE_I4);
4695 --td->sp;
4696 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
4697 ++td->ip;
4698 break;
4699 case CEE_CGT:
4700 CHECK_STACK(td, 2);
4701 if (td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP)
4702 ADD_CODE(td, MINT_CGT_I4 + STACK_TYPE_I - STACK_TYPE_I4);
4703 else
4704 ADD_CODE(td, MINT_CGT_I4 + td->sp [-1].type - STACK_TYPE_I4);
4705 --td->sp;
4706 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
4707 ++td->ip;
4708 break;
4709 case CEE_CGT_UN:
4710 CHECK_STACK(td, 2);
4711 if (td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP)
4712 ADD_CODE(td, MINT_CGT_UN_I4 + STACK_TYPE_I - STACK_TYPE_I4);
4713 else
4714 ADD_CODE(td, MINT_CGT_UN_I4 + td->sp [-1].type - STACK_TYPE_I4);
4715 --td->sp;
4716 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
4717 ++td->ip;
4718 break;
4719 case CEE_CLT:
4720 CHECK_STACK(td, 2);
4721 if (td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP)
4722 ADD_CODE(td, MINT_CLT_I4 + STACK_TYPE_I - STACK_TYPE_I4);
4723 else
4724 ADD_CODE(td, MINT_CLT_I4 + td->sp [-1].type - STACK_TYPE_I4);
4725 --td->sp;
4726 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
4727 ++td->ip;
4728 break;
4729 case CEE_CLT_UN:
4730 CHECK_STACK(td, 2);
4731 if (td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP)
4732 ADD_CODE(td, MINT_CLT_UN_I4 + STACK_TYPE_I - STACK_TYPE_I4);
4733 else
4734 ADD_CODE(td, MINT_CLT_UN_I4 + td->sp [-1].type - STACK_TYPE_I4);
4735 --td->sp;
4736 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
4737 ++td->ip;
4738 break;
4739 case CEE_LDVIRTFTN: /* fallthrough */
4740 case CEE_LDFTN: {
4741 MonoMethod *m;
4742 if (*td->ip == CEE_LDVIRTFTN) {
4743 CHECK_STACK (td, 1);
4744 --td->sp;
4746 token = read32 (td->ip + 1);
4747 if (method->wrapper_type != MONO_WRAPPER_NONE)
4748 m = (MonoMethod *)mono_method_get_wrapper_data (method, token);
4749 else {
4750 m = mono_get_method_checked (image, token, NULL, generic_context, error);
4751 goto_if_nok (error, exit);
4754 if (!mono_method_can_access_method (method, m))
4755 interp_generate_mae_throw (td, method, m);
4757 if (method->wrapper_type == MONO_WRAPPER_NONE && m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
4758 m = mono_marshal_get_synchronized_wrapper (m);
4760 ADD_CODE(td, *td->ip == CEE_LDFTN ? MINT_LDFTN : MINT_LDVIRTFTN);
4761 ADD_CODE(td, get_data_item_index (td, mono_interp_get_imethod (domain, m, error)));
4762 goto_if_nok (error, exit);
4763 td->ip += 5;
4764 PUSH_SIMPLE_TYPE (td, STACK_TYPE_F);
4765 break;
4767 case CEE_LDARG:
4768 load_arg (td, read16 (td->ip + 1));
4769 td->ip += 3;
4770 break;
4771 case CEE_LDARGA: {
4772 int n = read16 (td->ip + 1);
4773 ADD_CODE (td, MINT_LDARGA);
4774 ADD_CODE (td, td->rtm->arg_offsets [n]); /* FIX for large offsets */
4775 PUSH_SIMPLE_TYPE(td, STACK_TYPE_MP);
4776 td->ip += 3;
4777 break;
4779 case CEE_STARG:
4780 store_arg (td, read16 (td->ip + 1));
4781 td->ip += 3;
4782 break;
4783 case CEE_LDLOC:
4784 load_local (td, read16 (td->ip + 1));
4785 td->ip += 3;
4786 break;
4787 case CEE_LDLOCA:
4788 ADD_CODE(td, MINT_LDLOCA_S);
4789 ADD_CODE(td, td->rtm->local_offsets [read16 (td->ip + 1)]);
4790 PUSH_SIMPLE_TYPE(td, STACK_TYPE_MP);
4791 td->ip += 3;
4792 break;
4793 case CEE_STLOC:
4794 store_local (td, read16 (td->ip + 1));
4795 td->ip += 3;
4796 break;
4797 case CEE_LOCALLOC:
4798 CHECK_STACK (td, 1);
4799 #if SIZEOF_VOID_P == 8
4800 if (td->sp [-1].type == STACK_TYPE_I8)
4801 ADD_CODE(td, MINT_CONV_I4_I8);
4802 #endif
4803 ADD_CODE(td, MINT_LOCALLOC);
4804 if (td->sp != td->stack + 1)
4805 g_warning("CEE_LOCALLOC: stack not empty");
4806 ++td->ip;
4807 SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_MP);
4808 break;
4809 #if 0
4810 case CEE_UNUSED57: ves_abort(); break;
4811 #endif
4812 case CEE_ENDFILTER:
4813 ADD_CODE (td, MINT_ENDFILTER);
4814 ++td->ip;
4815 break;
4816 case CEE_UNALIGNED_:
4817 td->ip += 2;
4818 break;
4819 case CEE_VOLATILE_:
4820 ++td->ip;
4821 volatile_ = TRUE;
4822 break;
4823 case CEE_TAIL_:
4824 ++td->ip;
4825 /* FIX: should do something? */;
4826 // TODO: This should raise a method_tail_call profiler event.
4827 break;
4828 case CEE_INITOBJ:
4829 CHECK_STACK(td, 1);
4830 token = read32 (td->ip + 1);
4831 klass = mini_get_class (method, token, generic_context);
4832 CHECK_TYPELOAD (klass);
4833 if (m_class_is_valuetype (klass)) {
4834 ADD_CODE (td, MINT_INITOBJ);
4835 i32 = mono_class_value_size (klass, NULL);
4836 WRITE32 (td, &i32);
4837 } else {
4838 ADD_CODE (td, MINT_LDNULL);
4839 ADD_CODE (td, MINT_STIND_REF);
4841 td->ip += 5;
4842 --td->sp;
4843 break;
4844 case CEE_CPBLK:
4845 CHECK_STACK(td, 3);
4846 /* FIX? convert length to I8? */
4847 if (volatile_)
4848 ADD_CODE (td, MINT_MONO_MEMORY_BARRIER);
4849 ADD_CODE(td, MINT_CPBLK);
4850 BARRIER_IF_VOLATILE (td);
4851 td->sp -= 3;
4852 ++td->ip;
4853 break;
4854 case CEE_READONLY_:
4855 readonly = TRUE;
4856 td->ip += 1;
4857 break;
4858 case CEE_CONSTRAINED_:
4859 token = read32 (td->ip + 1);
4860 constrained_class = mini_get_class (method, token, generic_context);
4861 CHECK_TYPELOAD (constrained_class);
4862 td->ip += 5;
4863 break;
4864 case CEE_INITBLK:
4865 CHECK_STACK(td, 3);
4866 BARRIER_IF_VOLATILE (td);
4867 ADD_CODE(td, MINT_INITBLK);
4868 td->sp -= 3;
4869 td->ip += 1;
4870 break;
4871 case CEE_NO_:
4872 /* FIXME: implement */
4873 td->ip += 2;
4874 break;
4875 case CEE_RETHROW: {
4876 int clause_index = td->clause_indexes [in_offset];
4877 g_assert (clause_index != -1);
4878 SIMPLE_OP (td, MINT_RETHROW);
4879 ADD_CODE (td, rtm->exvar_offsets [clause_index]);
4880 td->sp = td->stack;
4881 break;
4883 case CEE_SIZEOF: {
4884 gint32 size;
4885 token = read32 (td->ip + 1);
4886 td->ip += 5;
4887 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (m_class_get_image (method->klass)) && !generic_context) {
4888 int align;
4889 MonoType *type = mono_type_create_from_typespec_checked (image, token, error);
4890 goto_if_nok (error, exit);
4891 size = mono_type_size (type, &align);
4892 } else {
4893 int align;
4894 MonoClass *szclass = mini_get_class (method, token, generic_context);
4895 CHECK_TYPELOAD (szclass);
4896 #if 0
4897 if (!szclass->valuetype)
4898 THROW_EX (mono_exception_from_name (mono_defaults.corlib, "System", "InvalidProgramException"), ip - 5);
4899 #endif
4900 size = mono_type_size (m_class_get_byval_arg (szclass), &align);
4902 ADD_CODE(td, MINT_LDC_I4);
4903 WRITE32(td, &size);
4904 PUSH_SIMPLE_TYPE(td, STACK_TYPE_I4);
4905 break;
4907 case CEE_REFANYTYPE:
4908 ADD_CODE (td, MINT_REFANYTYPE);
4909 td->ip += 1;
4910 POP_VT (td, sizeof (MonoTypedRef));
4911 PUSH_VT (td, sizeof (gpointer));
4912 SET_TYPE(td->sp - 1, STACK_TYPE_VT, NULL);
4913 break;
4914 default:
4915 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);
4917 break;
4918 default:
4919 g_error ("transform.c: Unimplemented opcode: %02x at 0x%x\n", *td->ip, td->ip-header->code);
4922 if (td->new_ip - td->new_code != new_in_start_offset)
4923 td->last_new_ip = td->new_code + new_in_start_offset;
4924 else if (td->is_bb_start [td->in_start - td->il_code])
4925 td->is_bb_start [td->ip - td->il_code] = 1;
4927 td->last_ip = td->in_start;
4929 in_offset = td->ip - header->code;
4930 g_assert (td->ip == end);
4931 td->in_offsets [in_offset] = td->new_ip - td->new_code;
4933 /* Handle relocations */
4934 for (int i = 0; i < td->relocs->len; ++i) {
4935 Reloc *reloc = (Reloc*)g_ptr_array_index (td->relocs, i);
4937 int offset = td->in_offsets [reloc->target] - reloc->offset;
4939 switch (reloc->type) {
4940 case RELOC_SHORT_BRANCH:
4941 g_assert (td->new_code [reloc->offset + 1] == 0xffff);
4942 td->new_code [reloc->offset + 1] = offset;
4943 break;
4944 case RELOC_LONG_BRANCH: {
4945 guint16 *v = (guint16 *) &offset;
4946 g_assert (td->new_code [reloc->offset + 1] == 0xbeef);
4947 g_assert (td->new_code [reloc->offset + 2] == 0xdead);
4948 td->new_code [reloc->offset + 1] = *(guint16 *) v;
4949 td->new_code [reloc->offset + 2] = *(guint16 *) (v + 1);
4950 break;
4952 case RELOC_SWITCH: {
4953 guint16 *v = (guint16*)&offset;
4954 td->new_code [reloc->offset] = *(guint16*)v;
4955 td->new_code [reloc->offset + 1] = *(guint16*)(v + 1);
4956 break;
4958 default:
4959 g_assert_not_reached ();
4960 break;
4964 if (td->verbose_level) {
4965 g_print ("Runtime method: %s %p, VT stack size: %d\n", mono_method_full_name (method, TRUE), rtm, td->max_vt_sp);
4966 g_print ("Calculated stack size: %d, stated size: %d\n", td->max_stack_height, header->max_stack);
4967 dump_mint_code (td);
4970 /* Check if we use excessive stack space */
4971 if (td->max_stack_height > header->max_stack * 3 && header->max_stack > 16)
4972 g_warning ("Excessive stack space usage for method %s, %d/%d", method->name, td->max_stack_height, header->max_stack);
4974 int code_len;
4975 code_len = td->new_ip - td->new_code;
4977 rtm->clauses = (MonoExceptionClause*)mono_domain_alloc0 (domain, header->num_clauses * sizeof (MonoExceptionClause));
4978 memcpy (rtm->clauses, header->clauses, header->num_clauses * sizeof(MonoExceptionClause));
4979 rtm->code = (gushort*)mono_domain_alloc0 (domain, (td->new_ip - td->new_code) * sizeof (gushort));
4980 memcpy (rtm->code, td->new_code, (td->new_ip - td->new_code) * sizeof(gushort));
4981 g_free (td->new_code);
4982 rtm->new_body_start = rtm->code + body_start_offset;
4983 rtm->init_locals = header->init_locals;
4984 rtm->num_clauses = header->num_clauses;
4985 for (i = 0; i < header->num_clauses; i++) {
4986 MonoExceptionClause *c = rtm->clauses + i;
4987 int end_off = c->try_offset + c->try_len;
4988 c->try_offset = td->in_offsets [c->try_offset];
4989 c->try_len = td->in_offsets [end_off] - c->try_offset;
4990 end_off = c->handler_offset + c->handler_len;
4991 c->handler_offset = td->in_offsets [c->handler_offset];
4992 c->handler_len = td->in_offsets [end_off] - c->handler_offset;
4993 if (c->flags & MONO_EXCEPTION_CLAUSE_FILTER)
4994 c->data.filter_offset = td->in_offsets [c->data.filter_offset];
4996 rtm->stack_size = (sizeof (stackval)) * (td->max_stack_height + 2); /* + 1 for returns of called functions + 1 for 0-ing in trace*/
4997 rtm->stack_size = ALIGN_TO (rtm->stack_size, MINT_VT_ALIGNMENT);
4998 rtm->vt_stack_size = td->max_vt_sp;
4999 rtm->total_locals_size = td->total_locals_size;
5000 rtm->alloca_size = rtm->total_locals_size + rtm->args_size + rtm->vt_stack_size + rtm->stack_size;
5001 rtm->data_items = (gpointer*)mono_domain_alloc0 (domain, td->n_data_items * sizeof (td->data_items [0]));
5002 memcpy (rtm->data_items, td->data_items, td->n_data_items * sizeof (td->data_items [0]));
5004 /* Save debug info */
5005 interp_save_debug_info (rtm, header, td, line_numbers);
5007 /* Create a MonoJitInfo for the interpreted method by creating the interpreter IR as the native code. */
5008 int jinfo_len;
5009 jinfo_len = mono_jit_info_size ((MonoJitInfoFlags)0, header->num_clauses, 0);
5010 MonoJitInfo *jinfo;
5011 jinfo = (MonoJitInfo *)mono_domain_alloc0 (domain, jinfo_len);
5012 jinfo->is_interp = 1;
5013 rtm->jinfo = jinfo;
5014 mono_jit_info_init (jinfo, method, (guint8*)rtm->code, code_len, (MonoJitInfoFlags)0, header->num_clauses, 0);
5015 for (i = 0; i < jinfo->num_clauses; ++i) {
5016 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
5017 MonoExceptionClause *c = rtm->clauses + i;
5019 ei->flags = c->flags;
5020 ei->try_start = (guint8*)(rtm->code + c->try_offset);
5021 ei->try_end = (guint8*)(rtm->code + c->try_offset + c->try_len);
5022 ei->handler_start = (guint8*)(rtm->code + c->handler_offset);
5023 ei->exvar_offset = rtm->exvar_offsets [i];
5024 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5025 ei->data.filter = (guint8*)(rtm->code + c->data.filter_offset);
5026 } else if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
5027 ei->data.handler_end = (guint8*)(rtm->code + c->handler_offset + c->handler_len);
5028 } else {
5029 ei->data.catch_class = c->data.catch_class;
5033 save_seq_points (td, jinfo);
5035 exit:
5036 mono_basic_block_free (original_bb);
5037 g_free (td->in_offsets);
5038 for (i = 0; i < header->code_size; ++i)
5039 g_free (td->stack_state [i]);
5040 g_free (td->stack_state);
5041 g_free (td->stack_height);
5042 g_free (td->vt_stack_size);
5043 g_free (td->data_items);
5044 g_free (td->stack);
5045 g_hash_table_destroy (td->data_hash);
5046 g_free (td->clause_indexes);
5047 g_ptr_array_free (td->seq_points, TRUE);
5048 g_array_free (line_numbers, TRUE);
5049 g_ptr_array_free (td->relocs, TRUE);
5050 mono_mempool_destroy (td->mempool);
5053 static mono_mutex_t calc_section;
5055 void
5056 mono_interp_transform_init (void)
5058 mono_os_mutex_init_recursive(&calc_section);
5061 void
5062 mono_interp_transform_method (InterpMethod *imethod, ThreadContext *context, MonoError *error)
5064 int i, align, size, offset;
5065 MonoMethod *method = imethod->method;
5066 MonoImage *image = m_class_get_image (method->klass);
5067 MonoMethodHeader *header = NULL;
5068 MonoMethodSignature *signature = mono_method_signature_internal (method);
5069 const unsigned char *ip, *end;
5070 const MonoOpcode *opcode;
5071 MonoMethod *m;
5072 MonoClass *klass;
5073 unsigned char *is_bb_start;
5074 int in;
5075 MonoVTable *method_class_vt;
5076 int backwards;
5077 MonoGenericContext *generic_context = NULL;
5078 MonoDomain *domain = imethod->domain;
5079 InterpMethod tmp_imethod;
5080 InterpMethod *real_imethod;
5082 error_init (error);
5084 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (method->klass))) {
5085 mono_error_set_invalid_operation (error, "%s", "Could not execute the method because the containing type is not fully instantiated.");
5086 return;
5089 // g_printerr ("TRANSFORM(0x%016lx): begin %s::%s\n", mono_thread_current (), method->klass->name, method->name);
5090 method_class_vt = mono_class_vtable_checked (domain, imethod->method->klass, error);
5091 return_if_nok (error);
5093 if (!method_class_vt->initialized) {
5094 mono_runtime_class_init_full (method_class_vt, error);
5095 return_if_nok (error);
5098 MONO_PROFILER_RAISE (jit_begin, (method));
5100 if (mono_method_signature_internal (method)->is_inflated)
5101 generic_context = mono_method_get_context (method);
5102 else {
5103 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
5104 if (generic_container)
5105 generic_context = &generic_container->context;
5108 if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
5109 MonoMethod *nm = NULL;
5110 mono_os_mutex_lock (&calc_section);
5111 if (imethod->transformed) {
5112 mono_os_mutex_unlock (&calc_section);
5113 MONO_PROFILER_RAISE (jit_done, (method, imethod->jinfo));
5114 return;
5117 /* assumes all internal calls with an array this are built in... */
5118 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL && (! mono_method_signature_internal (method)->hasthis || m_class_get_rank (method->klass) == 0)) {
5119 nm = mono_marshal_get_native_wrapper (method, TRUE, FALSE);
5120 signature = mono_method_signature_internal (nm);
5121 } else {
5122 const char *name = method->name;
5123 if (m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
5124 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
5125 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("ves_icall_mono_delegate_ctor_interp");
5126 g_assert (mi);
5127 char *wrapper_name = g_strdup_printf ("__icall_wrapper_%s", mi->name);
5128 nm = mono_marshal_get_icall_wrapper (mi->sig, wrapper_name, mi->func, TRUE);
5129 g_free (wrapper_name);
5130 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
5132 * Usually handled during transformation of the caller, but
5133 * when the caller is handled by another execution engine
5134 * (for example fullAOT) we need to handle it here. That's
5135 * known to be wrong in cases where the reference to
5136 * `MonoDelegate` would be needed (FIXME).
5138 nm = mono_marshal_get_delegate_invoke (method, NULL);
5139 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
5140 nm = mono_marshal_get_delegate_begin_invoke (method);
5141 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
5142 nm = mono_marshal_get_delegate_end_invoke (method);
5145 if (nm == NULL)
5146 g_assert_not_reached ();
5148 if (nm == NULL) {
5149 imethod->stack_size = sizeof (stackval); /* for tracing */
5150 imethod->alloca_size = imethod->stack_size;
5151 imethod->transformed = TRUE;
5152 mono_os_mutex_unlock(&calc_section);
5153 MONO_PROFILER_RAISE (jit_done, (method, NULL));
5154 return;
5156 method = nm;
5157 header = interp_method_get_header (nm, error);
5158 mono_os_mutex_unlock (&calc_section);
5159 return_if_nok (error);
5162 if (!header) {
5163 header = mono_method_get_header_checked (method, error);
5164 return_if_nok (error);
5167 g_assert ((signature->param_count + signature->hasthis) < 1000);
5168 /* intern the strings in the method. */
5169 ip = header->code;
5170 end = ip + header->code_size;
5172 is_bb_start = (guint8*)g_malloc0(header->code_size);
5173 is_bb_start [0] = 1;
5174 while (ip < end) {
5175 in = *ip;
5176 if (in == 0xfe) {
5177 ip++;
5178 in = *ip + 256;
5180 else if (in == 0xf0) {
5181 ip++;
5182 in = *ip + MONO_CEE_MONO_ICALL;
5184 opcode = &mono_opcodes [in];
5185 switch (opcode->argument) {
5186 case MonoInlineNone:
5187 ++ip;
5188 break;
5189 case MonoInlineString:
5190 if (method->wrapper_type == MONO_WRAPPER_NONE) {
5191 mono_ldstr_checked (domain, image, mono_metadata_token_index (read32 (ip + 1)), error);
5192 if (!is_ok (error)) {
5193 g_free (is_bb_start);
5194 mono_metadata_free_mh (header);
5195 return;
5198 ip += 5;
5199 break;
5200 case MonoInlineType:
5201 if (method->wrapper_type == MONO_WRAPPER_NONE) {
5202 klass = mini_get_class (method, read32 (ip + 1), generic_context);
5203 mono_class_init (klass);
5204 /* quick fix to not do this for the fake ptr classes - probably should not be getting the vtable at all here */
5205 #if 0
5206 g_error ("FIXME: interface method lookup: %s (in method %s)", klass->name, method->name);
5207 if (!(klass->flags & TYPE_ATTRIBUTE_INTERFACE) && klass->interface_offsets != NULL)
5208 mono_class_vtable (domain, klass);
5209 #endif
5211 ip += 5;
5212 break;
5213 case MonoInlineMethod:
5214 if (method->wrapper_type == MONO_WRAPPER_NONE && *ip != CEE_CALLI) {
5215 m = mono_get_method_checked (image, read32 (ip + 1), NULL, generic_context, error);
5216 if (!is_ok (error)) {
5217 g_free (is_bb_start);
5218 mono_metadata_free_mh (header);
5219 return;
5221 mono_class_init (m->klass);
5222 if (!mono_class_is_interface (m->klass)) {
5223 mono_class_vtable_checked (domain, m->klass, error);
5224 if (!is_ok (error)) {
5225 g_free (is_bb_start);
5226 mono_metadata_free_mh (header);
5227 return;
5231 ip += 5;
5232 break;
5233 case MonoInlineField:
5234 case MonoInlineSig:
5235 case MonoInlineI:
5236 case MonoInlineTok:
5237 case MonoShortInlineR:
5238 ip += 5;
5239 break;
5240 case MonoInlineBrTarget:
5241 offset = read32 (ip + 1);
5242 ip += 5;
5243 backwards = offset < 0;
5244 offset += ip - header->code;
5245 g_assert (offset >= 0 && offset < header->code_size);
5246 is_bb_start [offset] |= backwards ? 2 : 1;
5247 break;
5248 case MonoShortInlineBrTarget:
5249 offset = ((gint8 *)ip) [1];
5250 ip += 2;
5251 backwards = offset < 0;
5252 offset += ip - header->code;
5253 g_assert (offset >= 0 && offset < header->code_size);
5254 is_bb_start [offset] |= backwards ? 2 : 1;
5255 break;
5256 case MonoInlineVar:
5257 ip += 3;
5258 break;
5259 case MonoShortInlineVar:
5260 case MonoShortInlineI:
5261 ip += 2;
5262 break;
5263 case MonoInlineSwitch: {
5264 guint32 n;
5265 const unsigned char *next_ip;
5266 ++ip;
5267 n = read32 (ip);
5268 ip += 4;
5269 next_ip = ip + 4 * n;
5270 for (i = 0; i < n; i++) {
5271 offset = read32 (ip);
5272 backwards = offset < 0;
5273 offset += next_ip - header->code;
5274 g_assert (offset >= 0 && offset < header->code_size);
5275 is_bb_start [offset] |= backwards ? 2 : 1;
5276 ip += 4;
5278 break;
5280 case MonoInlineR:
5281 case MonoInlineI8:
5282 ip += 9;
5283 break;
5284 default:
5285 g_assert_not_reached ();
5288 // g_printerr ("TRANSFORM(0x%016lx): end %s::%s\n", mono_thread_current (), method->klass->name, method->name);
5290 /* Make modifications to a copy of imethod, copy them back inside the lock */
5291 real_imethod = imethod;
5292 memcpy (&tmp_imethod, imethod, sizeof (InterpMethod));
5293 imethod = &tmp_imethod;
5295 imethod->local_offsets = (guint32*)g_malloc (header->num_locals * sizeof(guint32));
5296 offset = 0;
5297 for (i = 0; i < header->num_locals; ++i) {
5298 size = mono_type_size (header->locals [i], &align);
5299 offset += align - 1;
5300 offset &= ~(align - 1);
5301 imethod->local_offsets [i] = offset;
5302 offset += size;
5304 offset = (offset + 7) & ~7;
5306 imethod->exvar_offsets = (guint32*)g_malloc (header->num_clauses * sizeof (guint32));
5307 for (i = 0; i < header->num_clauses; i++) {
5308 imethod->exvar_offsets [i] = offset;
5309 offset += sizeof (MonoObject*);
5311 offset = (offset + 7) & ~7;
5313 imethod->locals_size = offset;
5314 g_assert (imethod->locals_size < 65536);
5315 offset = 0;
5316 imethod->arg_offsets = (guint32*)g_malloc ((!!signature->hasthis + signature->param_count) * sizeof(guint32));
5318 if (signature->hasthis) {
5319 g_assert (!signature->pinvoke);
5320 size = align = SIZEOF_VOID_P;
5321 offset += align - 1;
5322 offset &= ~(align - 1);
5323 imethod->arg_offsets [0] = offset;
5324 offset += size;
5327 for (i = 0; i < signature->param_count; ++i) {
5328 if (signature->pinvoke) {
5329 guint32 dummy;
5330 size = mono_type_native_stack_size (signature->params [i], &dummy);
5331 align = 8;
5333 else
5334 size = mono_type_stack_size (signature->params [i], &align);
5335 offset += align - 1;
5336 offset &= ~(align - 1);
5337 imethod->arg_offsets [i + !!signature->hasthis] = offset;
5338 offset += size;
5340 offset = (offset + 7) & ~7;
5341 imethod->args_size = offset;
5342 g_assert (imethod->args_size < 10000);
5344 generate (method, header, imethod, is_bb_start, generic_context, error);
5346 mono_metadata_free_mh (header);
5347 g_free (is_bb_start);
5349 return_if_nok (error);
5351 // FIXME: Add a different callback ?
5352 MONO_PROFILER_RAISE (jit_done, (method, imethod->jinfo));
5354 /* Copy changes back */
5355 imethod = real_imethod;
5356 mono_os_mutex_lock (&calc_section);
5357 if (!imethod->transformed) {
5358 InterpMethod *hash = imethod->next_jit_code_hash;
5359 memcpy (imethod, &tmp_imethod, sizeof (InterpMethod));
5360 imethod->next_jit_code_hash = hash;
5361 mono_memory_barrier ();
5362 imethod->transformed = TRUE;
5363 mono_atomic_fetch_add_i32 (&mono_jit_stats.methods_with_interp, 1);
5365 mono_os_mutex_unlock (&calc_section);