2 * mini.c: The new Mono code generator.
5 * Paolo Molaro (lupus@ximian.com)
6 * Dietmar Maurer (dietmar@ximian.com)
8 * (C) 2002 Ximian, Inc.
17 #ifdef HAVE_SYS_TIME_H
21 #ifdef PLATFORM_MACOSX
22 #include <mach/mach.h>
23 #include <mach/mach_error.h>
24 #include <mach/exception.h>
25 #include <mach/task.h>
29 #ifdef HAVE_VALGRIND_MEMCHECK_H
30 #include <valgrind/memcheck.h>
33 #include <mono/metadata/assembly.h>
34 #include <mono/metadata/loader.h>
35 #include <mono/metadata/tabledefs.h>
36 #include <mono/metadata/class.h>
37 #include <mono/metadata/object.h>
38 #include <mono/metadata/exception.h>
39 #include <mono/metadata/opcodes.h>
40 #include <mono/metadata/mono-endian.h>
41 #include <mono/metadata/tokentype.h>
42 #include <mono/metadata/tabledefs.h>
43 #include <mono/metadata/threads.h>
44 #include <mono/metadata/marshal.h>
45 #include <mono/metadata/socket-io.h>
46 #include <mono/metadata/appdomain.h>
47 #include <mono/metadata/debug-helpers.h>
48 #include <mono/io-layer/io-layer.h>
49 #include "mono/metadata/profiler.h"
50 #include <mono/metadata/profiler-private.h>
51 #include <mono/metadata/mono-config.h>
52 #include <mono/metadata/environment.h>
53 #include <mono/metadata/mono-debug.h>
54 #include <mono/metadata/monitor.h>
55 #include <mono/metadata/gc-internal.h>
56 #include <mono/metadata/security-manager.h>
57 #include <mono/metadata/threads-types.h>
58 #include <mono/metadata/rawbuffer.h>
59 #include <mono/metadata/security-core-clr.h>
60 #include <mono/metadata/verify.h>
61 #include <mono/metadata/verify-internals.h>
62 #include <mono/metadata/mempool-internals.h>
63 #include <mono/metadata/attach.h>
64 #include <mono/utils/mono-math.h>
65 #include <mono/utils/mono-compiler.h>
66 #include <mono/utils/mono-counters.h>
67 #include <mono/utils/mono-logger.h>
68 #include <mono/utils/mono-mmap.h>
69 #include <mono/utils/dtrace.h>
77 #include "jit-icalls.h"
81 #include "debug-mini.h"
83 #define BRANCH_COST 100
84 #define INLINE_LENGTH_LIMIT 20
85 #define INLINE_FAILURE do {\
86 if ((cfg->method != method) && (method->wrapper_type == MONO_WRAPPER_NONE))\
89 #define CHECK_CFG_EXCEPTION do {\
90 if (cfg->exception_type != MONO_EXCEPTION_NONE)\
93 #define METHOD_ACCESS_FAILURE do { \
94 char *method_fname = mono_method_full_name (method, TRUE); \
95 char *cil_method_fname = mono_method_full_name (cil_method, TRUE); \
96 cfg->exception_type = MONO_EXCEPTION_METHOD_ACCESS; \
97 cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname); \
98 g_free (method_fname); \
99 g_free (cil_method_fname); \
100 goto exception_exit; \
102 #define FIELD_ACCESS_FAILURE do { \
103 char *method_fname = mono_method_full_name (method, TRUE); \
104 char *field_fname = mono_field_full_name (field); \
105 cfg->exception_type = MONO_EXCEPTION_FIELD_ACCESS; \
106 cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname); \
107 g_free (method_fname); \
108 g_free (field_fname); \
109 goto exception_exit; \
111 #define GENERIC_SHARING_FAILURE(opcode) do { \
112 if (cfg->generic_sharing_context) { \
113 if (cfg->verbose_level > 1) \
114 printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", method->klass->name_space, method->klass->name, method->name, method->signature->param_count, mono_opcode_name ((opcode)), __LINE__); \
115 cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED; \
116 goto exception_exit; \
119 #define GET_RGCTX(rgctx, context_used) do { \
120 MonoInst *this = NULL; \
121 g_assert (context_used); \
122 if (!(method->flags & METHOD_ATTRIBUTE_STATIC) && \
123 !((context_used) & MONO_GENERIC_CONTEXT_USED_METHOD) && \
124 !method->klass->valuetype) \
125 NEW_ARGLOAD (cfg, this, 0); \
126 (rgctx) = get_runtime_generic_context (cfg, method, (context_used), this, ip); \
130 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
132 static void setup_stat_profiler (void);
133 gboolean mono_arch_print_tree(MonoInst *tree, int arity);
134 static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt);
135 static gpointer mono_jit_compile_method (MonoMethod *method);
136 inline static int mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip);
138 static void handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src,
139 const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native, gboolean write_barrier);
141 static void dec_foreach (MonoInst *tree, MonoCompile *cfg);
143 int mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock,
144 MonoInst *return_var, GList *dont_inline, MonoInst **inline_args,
145 guint inline_offset, gboolean is_virtual_call);
147 static int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock,
148 int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args,
149 guint inline_offset, gboolean is_virtual_call);
151 #ifdef MONO_ARCH_SOFT_FLOAT
153 handle_store_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, MonoInst *val, const unsigned char *ip);
156 /* helper methods signature */
157 /* FIXME: Make these static again */
158 MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
159 MonoMethodSignature *helper_sig_domain_get = NULL;
160 MonoMethodSignature *helper_sig_generic_class_init_trampoline = NULL;
161 MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline = NULL;
163 static guint32 default_opt = 0;
164 static gboolean default_opt_set = FALSE;
166 guint32 mono_jit_tls_id = -1;
168 #ifdef HAVE_KW_THREAD
169 static __thread gpointer mono_jit_tls MONO_TLS_FAST;
172 MonoTraceSpec *mono_jit_trace_calls = NULL;
173 gboolean mono_break_on_exc = FALSE;
174 gboolean mono_compile_aot = FALSE;
175 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
176 gboolean mono_aot_only = FALSE;
177 /* Whenever to use IMT */
178 #ifdef MONO_ARCH_HAVE_IMT
179 gboolean mono_use_imt = TRUE;
181 gboolean mono_use_imt = FALSE;
183 MonoMethodDesc *mono_inject_async_exc_method = NULL;
184 int mono_inject_async_exc_pos;
185 MonoMethodDesc *mono_break_at_bb_method = NULL;
186 int mono_break_at_bb_bb_num;
188 static int mini_verbose = 0;
190 #define mono_jit_lock() EnterCriticalSection (&jit_mutex)
191 #define mono_jit_unlock() LeaveCriticalSection (&jit_mutex)
192 static CRITICAL_SECTION jit_mutex;
194 static MonoCodeManager *global_codeman = NULL;
196 /* FIXME: Make this static again */
197 GHashTable *jit_icall_name_hash = NULL;
199 static MonoDebugOptions debug_options;
201 #ifdef VALGRIND_JIT_REGISTER_MAP
202 static int valgrind_register = 0;
206 * Table written to by the debugger with a 1-based index into the
207 * mono_breakpoint_info table, which contains changes made to
208 * the JIT instructions by the debugger.
211 mono_breakpoint_info_index [MONO_BREAKPOINT_ARRAY_SIZE];
213 /* Whenever to check for pending exceptions in managed-to-native wrappers */
214 gboolean check_for_pending_exc = TRUE;
216 /* Whenever to disable passing/returning small valuetypes in registers for managed methods */
217 gboolean disable_vtypes_in_regs = FALSE;
219 gboolean mono_dont_free_global_codeman;
222 /* Define this here, since many files reference it */
223 const guint8 mono_burg_arity [MBMAX_OPCODES] = {
228 mono_running_on_valgrind (void)
230 #ifdef HAVE_VALGRIND_MEMCHECK_H
231 if (RUNNING_ON_VALGRIND){
232 #ifdef VALGRIND_JIT_REGISTER_MAP
233 valgrind_register = TRUE;
249 find_tramp (gpointer key, gpointer value, gpointer user_data)
251 FindTrampUserData *ud = (FindTrampUserData*)user_data;
254 ud->method = (MonoMethod*)key;
258 G_GNUC_UNUSED static char*
259 get_method_from_ip (void *ip)
264 MonoDomain *domain = mono_domain_get ();
265 MonoDebugSourceLocation *location;
266 FindTrampUserData user_data;
268 ji = mono_jit_info_table_find (domain, ip);
271 user_data.method = NULL;
272 mono_domain_lock (domain);
273 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
274 mono_domain_unlock (domain);
275 if (user_data.method) {
276 char *mname = mono_method_full_name (user_data.method, TRUE);
277 res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
284 method = mono_method_full_name (ji->method, TRUE);
285 /* FIXME: unused ? */
286 location = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
288 res = g_strdup_printf (" %s + 0x%x (%p %p) [%p - %s]", method, (int)((char*)ip - (char*)ji->code_start), ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
290 mono_debug_free_source_location (location);
298 * @ip: an instruction pointer address
300 * This method is used from a debugger to get the name of the
301 * method at address @ip. This routine is typically invoked from
302 * a debugger like this:
304 * (gdb) print mono_pmip ($pc)
306 * Returns: the name of the method at address @ip.
311 return get_method_from_ip (ip);
315 * mono_print_method_from_ip
316 * @ip: an instruction pointer address
318 * This method is used from a debugger to get the name of the
319 * method at address @ip.
321 * This prints the name of the method at address @ip in the standard
322 * output. Unlike mono_pmip which returns a string, this routine
323 * prints the value on the standard output.
326 mono_print_method_from_ip (void *ip)
330 MonoDebugSourceLocation *source;
331 MonoDomain *domain = mono_domain_get ();
332 FindTrampUserData user_data;
334 ji = mono_jit_info_table_find (domain, ip);
337 user_data.method = NULL;
338 mono_domain_lock (domain);
339 g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
340 mono_domain_unlock (domain);
341 if (user_data.method) {
342 char *mname = mono_method_full_name (user_data.method, TRUE);
343 printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
347 g_print ("No method at %p\n", ip);
350 method = mono_method_full_name (ji->method, TRUE);
351 source = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
353 g_print ("IP %p at offset 0x%x of method %s (%p %p)[domain %p - %s]\n", ip, (int)((char*)ip - (char*)ji->code_start), method, ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
356 g_print ("%s:%d\n", source->source_file, source->row);
358 mono_debug_free_source_location (source);
363 * mono_method_same_domain:
365 * Determine whenever two compiled methods are in the same domain, thus
366 * the address of the callee can be embedded in the caller.
368 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
370 if (!caller || !callee)
374 * If the call was made from domain-neutral to domain-specific
375 * code, we can't patch the call site.
377 if (caller->domain_neutral && !callee->domain_neutral)
380 if ((caller->method->klass == mono_defaults.appdomain_class) &&
381 (strstr (caller->method->name, "InvokeInDomain"))) {
382 /* The InvokeInDomain methods change the current appdomain */
390 * mono_global_codeman_reserve:
392 * Allocate code memory from the global code manager.
394 void *mono_global_codeman_reserve (int size)
399 g_error ("Attempting to allocate from the global code manager while running with --aot-only.\n");
401 if (!global_codeman) {
402 /* This can happen during startup */
403 global_codeman = mono_code_manager_new ();
404 return mono_code_manager_reserve (global_codeman, size);
408 ptr = mono_code_manager_reserve (global_codeman, size);
415 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
417 MonoJumpInfoToken *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
424 #define MONO_INIT_VARINFO(vi,id) do { \
425 (vi)->range.first_use.pos.bid = 0xffff; \
430 //#define UNVERIFIED do { G_BREAKPOINT (); goto unverified; } while (0)
431 #define UNVERIFIED do { if (debug_options.break_on_unverified) G_BREAKPOINT (); else goto unverified; } while (0)
434 * Basic blocks have two numeric identifiers:
435 * dfn: Depth First Number
436 * block_num: unique ID assigned at bblock creation
438 #define NEW_BBLOCK(cfg) (mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)))
439 #define ADD_BBLOCK(cfg,b) do { \
440 cfg->cil_offset_to_bb [(b)->cil_code - cfg->cil_start] = (b); \
441 (b)->block_num = cfg->num_bblocks++; \
442 (b)->real_offset = real_offset; \
445 #define GET_BBLOCK(cfg,tblock,ip) do { \
446 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
448 if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
449 (tblock) = NEW_BBLOCK (cfg); \
450 (tblock)->cil_code = (ip); \
451 ADD_BBLOCK (cfg, (tblock)); \
455 #define CHECK_BBLOCK(target,ip,tblock) do { \
456 if ((target) < (ip) && !(tblock)->code) { \
457 bb_recheck = g_list_prepend (bb_recheck, (tblock)); \
458 if (cfg->verbose_level > 2) g_print ("queued block %d for check at IL%04x from IL%04x\n", (tblock)->block_num, (int)((target) - header->code), (int)((ip) - header->code)); \
462 #define NEW_ICONST(cfg,dest,val) do { \
463 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
464 (dest)->opcode = OP_ICONST; \
465 (dest)->inst_c0 = (val); \
466 (dest)->type = STACK_I4; \
469 #define NEW_PCONST(cfg,dest,val) do { \
470 MONO_INST_NEW ((cfg), (dest), OP_PCONST); \
471 (dest)->inst_p0 = (val); \
472 (dest)->type = STACK_PTR; \
476 #ifdef MONO_ARCH_NEED_GOT_VAR
478 #define NEW_PATCH_INFO(cfg,dest,el1,el2) do { \
479 MONO_INST_NEW ((cfg), (dest), OP_PATCH_INFO); \
480 (dest)->inst_left = (gpointer)(el1); \
481 (dest)->inst_right = (gpointer)(el2); \
484 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do { \
485 MONO_INST_NEW ((cfg), (dest), OP_NOP); \
486 (dest)->opcode = cfg->compile_aot ? OP_GOT_ENTRY : OP_PCONST; \
487 if (cfg->compile_aot) { \
488 MonoInst *group, *got_var, *got_loc; \
489 got_loc = mono_get_got_var (cfg); \
490 NEW_TEMPLOAD ((cfg), got_var, got_loc->inst_c0); \
491 NEW_PATCH_INFO ((cfg), group, cons, patch_type); \
492 (dest)->inst_p0 = got_var; \
493 (dest)->inst_p1 = group; \
495 (dest)->inst_p0 = (cons); \
496 (dest)->inst_i1 = (gpointer)(patch_type); \
498 (dest)->type = STACK_PTR; \
501 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
502 MonoInst *group, *got_var, *got_loc; \
503 MONO_INST_NEW ((cfg), (dest), OP_GOT_ENTRY); \
504 got_loc = mono_get_got_var (cfg); \
505 NEW_TEMPLOAD ((cfg), got_var, got_loc->inst_c0); \
506 NEW_PATCH_INFO ((cfg), group, NULL, patch_type); \
507 group->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
508 (dest)->inst_p0 = got_var; \
509 (dest)->inst_p1 = group; \
510 (dest)->type = (stack_type); \
511 (dest)->klass = (stack_class); \
516 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do { \
517 MONO_INST_NEW ((cfg), (dest), OP_NOP); \
518 (dest)->opcode = cfg->compile_aot ? OP_AOTCONST : OP_PCONST; \
519 (dest)->inst_p0 = (cons); \
520 (dest)->inst_i1 = (gpointer)(patch_type); \
521 (dest)->type = STACK_PTR; \
524 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
525 MONO_INST_NEW ((cfg), (dest), OP_AOTCONST); \
526 (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
527 (dest)->inst_p1 = (gpointer)(patch_type); \
528 (dest)->type = (stack_type); \
529 (dest)->klass = (stack_class); \
534 #define NEW_CLASSCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_CLASS, (val))
536 #define NEW_IMAGECONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_IMAGE, (val))
538 #define NEW_FIELDCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_FIELD, (val))
540 #define NEW_METHODCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_METHODCONST, (val))
542 #define NEW_VTABLECONST(cfg,dest,vtable) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_VTABLE, cfg->compile_aot ? (gpointer)((vtable)->klass) : (vtable))
544 #define NEW_SFLDACONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_SFLDA, (val))
546 #define NEW_LDSTRCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDSTR, (image), (token), STACK_OBJ, mono_defaults.string_class)
548 #define NEW_TYPE_FROM_HANDLE_CONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_TYPE_FROM_HANDLE, (image), (token), STACK_OBJ, mono_defaults.monotype_class)
550 #define NEW_LDTOKENCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDTOKEN, (image), (token), STACK_PTR, NULL)
552 #define NEW_DECLSECCONST(cfg,dest,image,entry) do { \
553 if (cfg->compile_aot) { \
554 NEW_AOTCONST_TOKEN (cfg, dest, MONO_PATCH_INFO_DECLSEC, image, (entry).index, STACK_OBJ, NULL); \
556 NEW_PCONST (cfg, args [0], (entry).blob); \
560 #define NEW_DOMAINCONST(cfg,dest) do { \
561 if (cfg->opt & MONO_OPT_SHARED) { \
562 /* avoid depending on undefined C behavior in sequence points */ \
563 MonoInst* __domain_var = mono_get_domainvar (cfg); \
564 NEW_TEMPLOAD (cfg, dest, __domain_var->inst_c0); \
566 NEW_PCONST (cfg, dest, (cfg)->domain); \
570 #define GET_VARINFO_INST(cfg,num) ((cfg)->varinfo [(num)]->inst)
572 #define NEW_ARGLOAD(cfg,dest,num) do { \
573 if (arg_array [(num)]->opcode == OP_ICONST) (dest) = arg_array [(num)]; else { \
574 MONO_INST_NEW ((cfg), (dest), OP_NOP); \
575 (dest)->ssa_op = MONO_SSA_LOAD; \
576 (dest)->inst_i0 = arg_array [(num)]; \
577 (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
578 type_to_eval_stack_type ((cfg), param_types [(num)], (dest)); \
579 (dest)->klass = (dest)->inst_i0->klass; \
582 #define NEW_LOCLOAD(cfg,dest,num) do { \
583 MONO_INST_NEW ((cfg), (dest), OP_NOP); \
584 (dest)->ssa_op = MONO_SSA_LOAD; \
585 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
586 (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
587 type_to_eval_stack_type ((cfg), header->locals [(num)], (dest)); \
588 (dest)->klass = (dest)->inst_i0->klass; \
591 #define NEW_LOCLOADA(cfg,dest,num) do { \
592 MONO_INST_NEW ((cfg), (dest), OP_LDADDR); \
593 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN; \
594 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
595 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
596 (dest)->type = STACK_MP; \
597 (dest)->klass = (dest)->inst_i0->klass; \
598 if (!MONO_TYPE_ISSTRUCT (header->locals [(num)])) \
599 (cfg)->disable_ssa = TRUE; \
602 #define NEW_RETLOADA(cfg,dest) do { \
603 if (cfg->vret_addr) { \
604 MONO_INST_NEW ((cfg), (dest), OP_NOP); \
605 (dest)->ssa_op = MONO_SSA_LOAD; \
606 (dest)->inst_i0 = cfg->vret_addr; \
607 (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
608 (dest)->type = STACK_MP; \
609 (dest)->klass = (dest)->inst_i0->klass; \
611 MONO_INST_NEW ((cfg), (dest), OP_NOP); \
612 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN; \
613 (dest)->inst_i0 = (cfg)->ret; \
614 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
615 (dest)->opcode = cfg->ret_var_is_local ? OP_LDADDR : CEE_LDIND_I; \
616 (dest)->type = STACK_MP; \
617 (dest)->klass = (dest)->inst_i0->klass; \
618 (cfg)->disable_ssa = TRUE; \
622 #define NEW_ARGLOADA(cfg,dest,num) do { \
623 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
624 MONO_INST_NEW ((cfg), (dest), OP_LDADDR); \
625 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN; \
626 (dest)->inst_i0 = arg_array [(num)]; \
627 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
628 (dest)->type = STACK_MP; \
629 (dest)->klass = (dest)->inst_i0->klass; \
630 (cfg)->disable_ssa = TRUE; \
633 #define NEW_TEMPLOAD(cfg,dest,num) do { \
634 MONO_INST_NEW ((cfg), (dest), OP_NOP); \
635 (dest)->ssa_op = MONO_SSA_LOAD; \
636 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
637 (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
638 type_to_eval_stack_type ((cfg), (dest)->inst_i0->inst_vtype, (dest)); \
639 (dest)->klass = (dest)->inst_i0->klass; \
642 #define NEW_TEMPLOADA(cfg,dest,num) do { \
643 MONO_INST_NEW ((cfg), (dest), OP_LDADDR); \
644 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN; \
645 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
646 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
647 (dest)->type = STACK_MP; \
648 (dest)->klass = (dest)->inst_i0->klass; \
649 if (!MONO_TYPE_ISSTRUCT (cfg->varinfo [(num)]->inst_vtype)) \
650 (cfg)->disable_ssa = TRUE; \
653 #define NEW_INDLOAD(cfg,dest,addr,vtype) do { \
654 MONO_INST_NEW ((cfg), (dest), OP_NOP); \
655 (dest)->inst_left = addr; \
656 (dest)->opcode = mini_type_to_ldind ((cfg), vtype); \
657 type_to_eval_stack_type ((cfg), vtype, (dest)); \
658 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/ \
661 #define NEW_INDSTORE(cfg,dest,addr,value,vtype) do { \
662 MONO_INST_NEW ((cfg), (dest), OP_NOP); \
663 (dest)->inst_i0 = addr; \
664 (dest)->opcode = mini_type_to_stind ((cfg), vtype); \
665 (dest)->inst_i1 = (value); \
666 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/ \
669 #define NEW_TEMPSTORE(cfg,dest,num,inst) do { \
670 MONO_INST_NEW ((cfg), (dest), OP_NOP); \
671 (dest)->ssa_op = MONO_SSA_STORE; \
672 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
673 (dest)->opcode = mini_type_to_stind ((cfg), (dest)->inst_i0->inst_vtype); \
674 (dest)->inst_i1 = (inst); \
675 (dest)->klass = (dest)->inst_i0->klass; \
678 #define NEW_LOCSTORE(cfg,dest,num,inst) do { \
679 MONO_INST_NEW ((cfg), (dest), OP_NOP); \
680 (dest)->opcode = mini_type_to_stind ((cfg), header->locals [(num)]); \
681 (dest)->ssa_op = MONO_SSA_STORE; \
682 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
683 (dest)->inst_i1 = (inst); \
684 (dest)->klass = (dest)->inst_i0->klass; \
687 #define NEW_ARGSTORE(cfg,dest,num,inst) do { \
688 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
689 MONO_INST_NEW ((cfg), (dest), OP_NOP); \
690 (dest)->opcode = mini_type_to_stind ((cfg), param_types [(num)]); \
691 (dest)->ssa_op = MONO_SSA_STORE; \
692 (dest)->inst_i0 = arg_array [(num)]; \
693 (dest)->inst_i1 = (inst); \
694 (dest)->klass = (dest)->inst_i0->klass; \
697 #define NEW_MEMCPY(cfg,dest,dst,src,memcpy_size,memcpy_align) do { \
698 MONO_INST_NEW (cfg, dest, OP_MEMCPY); \
699 (dest)->inst_left = (dst); \
700 (dest)->inst_right = (src); \
701 (dest)->backend.memcpy_args = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoMemcpyArgs)); \
702 (dest)->backend.memcpy_args->size = (memcpy_size); \
703 (dest)->backend.memcpy_args->align = (memcpy_align); \
706 #define NEW_MEMSET(cfg,dest,dst,imm,memcpy_size,memcpy_align) do { \
707 MONO_INST_NEW (cfg, dest, OP_MEMSET); \
708 (dest)->inst_left = (dst); \
709 (dest)->inst_imm = (imm); \
710 (dest)->backend.memcpy_args = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoMemcpyArgs)); \
711 (dest)->backend.memcpy_args->size = (memcpy_size); \
712 (dest)->backend.memcpy_args->align = (memcpy_align); \
715 #define NEW_DUMMY_USE(cfg,dest,load) do { \
716 MONO_INST_NEW ((cfg), (dest), OP_DUMMY_USE); \
717 (dest)->inst_left = (load); \
720 #define NEW_DUMMY_STORE(cfg,dest,num) do { \
721 MONO_INST_NEW ((cfg), (dest), OP_DUMMY_STORE); \
722 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
723 (dest)->klass = (dest)->inst_i0->klass; \
726 #define ADD_BINOP(op) do { \
727 MONO_INST_NEW (cfg, ins, (op)); \
729 ins->inst_i0 = sp [0]; \
730 ins->inst_i1 = sp [1]; \
732 type_from_op (ins); \
734 /* Have to insert a widening op */ \
735 /* FIXME: Need to add many more cases */ \
736 if (ins->inst_i0->type == STACK_PTR && ins->inst_i1->type == STACK_I4) { \
738 MONO_INST_NEW (cfg, widen, CEE_CONV_I); \
739 widen->inst_i0 = ins->inst_i1; \
740 ins->inst_i1 = widen; \
744 #define ADD_UNOP(op) do { \
745 MONO_INST_NEW (cfg, ins, (op)); \
747 ins->inst_i0 = sp [0]; \
749 type_from_op (ins); \
753 #define ADD_BINCOND(next_block) do { \
756 MONO_INST_NEW(cfg, cmp, OP_COMPARE); \
757 cmp->inst_i0 = sp [0]; \
758 cmp->inst_i1 = sp [1]; \
759 cmp->cil_code = ins->cil_code; \
760 type_from_op (cmp); \
762 ins->inst_i0 = cmp; \
763 MONO_ADD_INS (bblock, ins); \
764 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2); \
765 GET_BBLOCK (cfg, tblock, target); \
766 link_bblock (cfg, bblock, tblock); \
767 ins->inst_true_bb = tblock; \
768 CHECK_BBLOCK (target, ip, tblock); \
769 if ((next_block)) { \
770 link_bblock (cfg, bblock, (next_block)); \
771 ins->inst_false_bb = (next_block); \
772 start_new_bblock = 1; \
774 GET_BBLOCK (cfg, tblock, ip); \
775 link_bblock (cfg, bblock, tblock); \
776 ins->inst_false_bb = tblock; \
777 start_new_bblock = 2; \
781 /* FIXME: handle float, long ... */
782 #define ADD_UNCOND(istrue) do { \
785 MONO_INST_NEW(cfg, cmp, OP_COMPARE); \
786 cmp->inst_i0 = sp [0]; \
787 switch (cmp->inst_i0->type) { \
789 cmp->inst_i1 = zero_int64; break; \
791 cmp->inst_i1 = zero_r8; break; \
794 cmp->inst_i1 = zero_ptr; break; \
796 cmp->inst_i1 = zero_obj; break; \
798 cmp->inst_i1 = zero_int32; \
800 cmp->cil_code = ins->cil_code; \
801 type_from_op (cmp); \
803 ins->inst_i0 = cmp; \
804 ins->opcode = (istrue)? CEE_BNE_UN: CEE_BEQ; \
805 MONO_ADD_INS (bblock, ins); \
806 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2); \
807 GET_BBLOCK (cfg, tblock, target); \
808 link_bblock (cfg, bblock, tblock); \
809 ins->inst_true_bb = tblock; \
810 CHECK_BBLOCK (target, ip, tblock); \
811 GET_BBLOCK (cfg, tblock, ip); \
812 link_bblock (cfg, bblock, tblock); \
813 ins->inst_false_bb = tblock; \
814 start_new_bblock = 2; \
817 #define NEW_LDELEMA(cfg,dest,sp,k) do { \
818 MONO_INST_NEW ((cfg), (dest), CEE_LDELEMA); \
819 (dest)->inst_left = (sp) [0]; \
820 (dest)->inst_right = (sp) [1]; \
821 (dest)->type = STACK_MP; \
822 (dest)->klass = (k); \
823 (cfg)->flags |= MONO_CFG_HAS_LDELEMA; \
826 #define NEW_GROUP(cfg,dest,el1,el2) do { \
827 MONO_INST_NEW ((cfg), (dest), OP_GROUP); \
828 (dest)->inst_left = (el1); \
829 (dest)->inst_right = (el2); \
834 compare_bblock (gconstpointer a, gconstpointer b)
836 const MonoBasicBlock *b1 = a;
837 const MonoBasicBlock *b2 = b;
839 return b2->cil_code - b1->cil_code;
844 * link_bblock: Links two basic blocks
846 * links two basic blocks in the control flow graph, the 'from'
847 * argument is the starting block and the 'to' argument is the block
848 * the control flow ends to after 'from'.
851 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
853 MonoBasicBlock **newa;
857 if (from->cil_code) {
859 g_print ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
861 g_print ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
864 g_print ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
866 g_print ("edge from entry to exit\n");
870 for (i = 0; i < from->out_count; ++i) {
871 if (to == from->out_bb [i]) {
877 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
878 for (i = 0; i < from->out_count; ++i) {
879 newa [i] = from->out_bb [i];
887 for (i = 0; i < to->in_count; ++i) {
888 if (from == to->in_bb [i]) {
894 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
895 for (i = 0; i < to->in_count; ++i) {
896 newa [i] = to->in_bb [i];
905 * mono_unlink_bblock:
907 * Unlink two basic blocks.
910 mono_unlink_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
916 for (i = 0; i < from->out_count; ++i) {
917 if (to == from->out_bb [i]) {
924 for (i = 0; i < from->out_count; ++i) {
925 if (from->out_bb [i] != to)
926 from->out_bb [pos ++] = from->out_bb [i];
928 g_assert (pos == from->out_count - 1);
933 for (i = 0; i < to->in_count; ++i) {
934 if (from == to->in_bb [i]) {
941 for (i = 0; i < to->in_count; ++i) {
942 if (to->in_bb [i] != from)
943 to->in_bb [pos ++] = to->in_bb [i];
945 g_assert (pos == to->in_count - 1);
951 * mono_bblocks_linked:
953 * Return whenever BB1 and BB2 are linked in the CFG.
956 mono_bblocks_linked (MonoBasicBlock *bb1, MonoBasicBlock *bb2)
960 for (i = 0; i < bb1->out_count; ++i) {
961 if (bb1->out_bb [i] == bb2)
969 * mono_find_block_region:
971 * We mark each basic block with a region ID. We use that to avoid BB
972 * optimizations when blocks are in different regions.
975 * A region token that encodes where this region is, and information
976 * about the clause owner for this block.
978 * The region encodes the try/catch/filter clause that owns this block
979 * as well as the type. -1 is a special value that represents a block
980 * that is in none of try/catch/filter.
983 mono_find_block_region (MonoCompile *cfg, int offset)
985 MonoMethod *method = cfg->method;
986 MonoMethodHeader *header = mono_method_get_header (method);
987 MonoExceptionClause *clause;
990 /* first search for handlers and filters */
991 for (i = 0; i < header->num_clauses; ++i) {
992 clause = &header->clauses [i];
993 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
994 (offset < (clause->handler_offset)))
995 return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
997 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
998 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
999 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
1000 else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
1001 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
1002 else if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE)
1003 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
1007 /* search the try blocks */
1008 for (i = 0; i < header->num_clauses; ++i) {
1009 clause = &header->clauses [i];
1010 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
1011 return ((i + 1) << 8) | clause->flags;
1018 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
1020 MonoMethod *method = cfg->method;
1021 MonoMethodHeader *header = mono_method_get_header (method);
1022 MonoExceptionClause *clause;
1023 MonoBasicBlock *handler;
1027 for (i = 0; i < header->num_clauses; ++i) {
1028 clause = &header->clauses [i];
1029 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) &&
1030 (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
1031 if (clause->flags == type) {
1032 handler = cfg->cil_offset_to_bb [clause->handler_offset];
1034 res = g_list_append (res, handler);
1042 mono_find_spvar_for_region (MonoCompile *cfg, int region)
1044 return g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
1048 mono_create_spvar_for_region (MonoCompile *cfg, int region)
1052 var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
1056 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1057 /* prevent it from being register allocated */
1058 var->flags |= MONO_INST_INDIRECT;
1060 g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
1064 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
1066 return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
1070 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
1074 var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
1078 var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
1079 /* prevent it from being register allocated */
1080 var->flags |= MONO_INST_INDIRECT;
1082 g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
1088 df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
1092 array [*dfn] = start;
1093 /* g_print ("visit %d at %p (BB%ld)\n", *dfn, start->cil_code, start->block_num); */
1094 for (i = 0; i < start->out_count; ++i) {
1095 if (start->out_bb [i]->dfn)
1098 start->out_bb [i]->dfn = *dfn;
1099 start->out_bb [i]->df_parent = start;
1100 array [*dfn] = start->out_bb [i];
1101 df_visit (start->out_bb [i], dfn, array);
1105 static MonoBasicBlock*
1106 find_previous (MonoBasicBlock **bblocks, guint32 n_bblocks, MonoBasicBlock *start, const guchar *code)
1108 MonoBasicBlock *best = start;
1111 for (i = 0; i < n_bblocks; ++i) {
1113 MonoBasicBlock *bb = bblocks [i];
1115 if (bb->cil_code && bb->cil_code < code && bb->cil_code > best->cil_code)
1124 split_bblock (MonoCompile *cfg, MonoBasicBlock *first, MonoBasicBlock *second) {
1133 * FIXME: take into account all the details:
1134 * second may have been the target of more than one bblock
1136 second->out_count = first->out_count;
1137 second->out_bb = first->out_bb;
1139 for (i = 0; i < first->out_count; ++i) {
1140 bb = first->out_bb [i];
1141 for (j = 0; j < bb->in_count; ++j) {
1142 if (bb->in_bb [j] == first)
1143 bb->in_bb [j] = second;
1147 first->out_count = 0;
1148 first->out_bb = NULL;
1149 link_bblock (cfg, first, second);
1151 second->last_ins = first->last_ins;
1153 /*g_print ("start search at %p for %p\n", first->cil_code, second->cil_code);*/
1154 MONO_BB_FOR_EACH_INS (first, inst) {
1155 /*char *code = mono_disasm_code_one (NULL, cfg->method, inst->next->cil_code, NULL);
1156 g_print ("found %p: %s", inst->next->cil_code, code);
1158 if (inst->cil_code < second->cil_code && inst->next->cil_code >= second->cil_code) {
1159 second->code = inst->next;
1161 first->last_ins = inst;
1162 second->next_bb = first->next_bb;
1163 first->next_bb = second;
1167 if (!second->code) {
1168 g_warning ("bblock split failed in %s::%s\n", cfg->method->klass->name, cfg->method->name);
1174 mono_reverse_branch_op (guint32 opcode)
1176 static const int reverse_map [] = {
1177 CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
1178 CEE_BEQ, CEE_BLT_UN, CEE_BLE_UN, CEE_BGT_UN, CEE_BGE_UN
1180 static const int reverse_fmap [] = {
1181 OP_FBNE_UN, OP_FBLT, OP_FBLE, OP_FBGT, OP_FBGE,
1182 OP_FBEQ, OP_FBLT_UN, OP_FBLE_UN, OP_FBGT_UN, OP_FBGE_UN
1184 static const int reverse_lmap [] = {
1185 OP_LBNE_UN, OP_LBLT, OP_LBLE, OP_LBGT, OP_LBGE,
1186 OP_LBEQ, OP_LBLT_UN, OP_LBLE_UN, OP_LBGT_UN, OP_LBGE_UN
1188 static const int reverse_imap [] = {
1189 OP_IBNE_UN, OP_IBLT, OP_IBLE, OP_IBGT, OP_IBGE,
1190 OP_IBEQ, OP_IBLT_UN, OP_IBLE_UN, OP_IBGT_UN, OP_IBGE_UN
1193 if (opcode >= CEE_BEQ && opcode <= CEE_BLT_UN) {
1194 opcode = reverse_map [opcode - CEE_BEQ];
1195 } else if (opcode >= OP_FBEQ && opcode <= OP_FBLT_UN) {
1196 opcode = reverse_fmap [opcode - OP_FBEQ];
1197 } else if (opcode >= OP_LBEQ && opcode <= OP_LBLT_UN) {
1198 opcode = reverse_lmap [opcode - OP_LBEQ];
1199 } else if (opcode >= OP_IBEQ && opcode <= OP_IBLT_UN) {
1200 opcode = reverse_imap [opcode - OP_IBEQ];
1202 g_assert_not_reached ();
1208 mono_type_to_store_membase (MonoCompile *cfg, MonoType *type)
1211 return OP_STORE_MEMBASE_REG;
1214 switch (type->type) {
1217 case MONO_TYPE_BOOLEAN:
1218 return OP_STOREI1_MEMBASE_REG;
1221 case MONO_TYPE_CHAR:
1222 return OP_STOREI2_MEMBASE_REG;
1225 return OP_STOREI4_MEMBASE_REG;
1229 case MONO_TYPE_FNPTR:
1230 return OP_STORE_MEMBASE_REG;
1231 case MONO_TYPE_CLASS:
1232 case MONO_TYPE_STRING:
1233 case MONO_TYPE_OBJECT:
1234 case MONO_TYPE_SZARRAY:
1235 case MONO_TYPE_ARRAY:
1236 return OP_STORE_MEMBASE_REG;
1239 return OP_STOREI8_MEMBASE_REG;
1241 return OP_STORER4_MEMBASE_REG;
1243 return OP_STORER8_MEMBASE_REG;
1244 case MONO_TYPE_VALUETYPE:
1245 if (type->data.klass->enumtype) {
1246 type = type->data.klass->enum_basetype;
1249 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
1250 return OP_STOREX_MEMBASE;
1251 return OP_STOREV_MEMBASE;
1252 case MONO_TYPE_TYPEDBYREF:
1253 return OP_STOREV_MEMBASE;
1254 case MONO_TYPE_GENERICINST:
1255 type = &type->data.generic_class->container_class->byval_arg;
1258 case MONO_TYPE_MVAR:
1259 /* FIXME: all the arguments must be references for now,
1260 * later look inside cfg and see if the arg num is
1261 * really a reference
1263 g_assert (cfg->generic_sharing_context);
1264 return OP_STORE_MEMBASE_REG;
1266 g_error ("unknown type 0x%02x in type_to_store_membase", type->type);
1272 mono_type_to_load_membase (MonoCompile *cfg, MonoType *type)
1275 return OP_LOAD_MEMBASE;
1277 switch (mono_type_get_underlying_type (type)->type) {
1279 return OP_LOADI1_MEMBASE;
1281 case MONO_TYPE_BOOLEAN:
1282 return OP_LOADU1_MEMBASE;
1284 return OP_LOADI2_MEMBASE;
1286 case MONO_TYPE_CHAR:
1287 return OP_LOADU2_MEMBASE;
1289 return OP_LOADI4_MEMBASE;
1291 return OP_LOADU4_MEMBASE;
1295 case MONO_TYPE_FNPTR:
1296 return OP_LOAD_MEMBASE;
1297 case MONO_TYPE_CLASS:
1298 case MONO_TYPE_STRING:
1299 case MONO_TYPE_OBJECT:
1300 case MONO_TYPE_SZARRAY:
1301 case MONO_TYPE_ARRAY:
1302 return OP_LOAD_MEMBASE;
1305 return OP_LOADI8_MEMBASE;
1307 return OP_LOADR4_MEMBASE;
1309 return OP_LOADR8_MEMBASE;
1310 case MONO_TYPE_VALUETYPE:
1311 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
1312 return OP_LOADX_MEMBASE;
1313 case MONO_TYPE_TYPEDBYREF:
1314 return OP_LOADV_MEMBASE;
1315 case MONO_TYPE_GENERICINST:
1316 if (mono_type_generic_inst_is_valuetype (type))
1317 return OP_LOADV_MEMBASE;
1319 return OP_LOAD_MEMBASE;
1322 case MONO_TYPE_MVAR:
1323 /* FIXME: all the arguments must be references for now,
1324 * later look inside cfg and see if the arg num is
1325 * really a reference
1327 g_assert (cfg->generic_sharing_context);
1328 return OP_LOAD_MEMBASE;
1330 g_error ("unknown type 0x%02x in type_to_load_membase", type->type);
1335 #ifdef MONO_ARCH_SOFT_FLOAT
1337 condbr_to_fp_br (int opcode)
1340 case CEE_BEQ: return OP_FBEQ;
1341 case CEE_BGE: return OP_FBGE;
1342 case CEE_BGT: return OP_FBGT;
1343 case CEE_BLE: return OP_FBLE;
1344 case CEE_BLT: return OP_FBLT;
1345 case CEE_BNE_UN: return OP_FBNE_UN;
1346 case CEE_BGE_UN: return OP_FBGE_UN;
1347 case CEE_BGT_UN: return OP_FBGT_UN;
1348 case CEE_BLE_UN: return OP_FBLE_UN;
1349 case CEE_BLT_UN: return OP_FBLT_UN;
1351 g_assert_not_reached ();
1357 * The following tables are used to quickly validate the IL code in type_from_op ().
1360 bin_num_table [STACK_MAX] [STACK_MAX] = {
1361 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1362 {STACK_INV, STACK_I4, STACK_INV, STACK_PTR, STACK_INV, STACK_MP, STACK_INV, STACK_INV},
1363 {STACK_INV, STACK_INV, STACK_I8, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1364 {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP, STACK_INV, STACK_INV},
1365 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV},
1366 {STACK_INV, STACK_MP, STACK_INV, STACK_MP, STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
1367 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1368 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1373 STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
1376 /* reduce the size of this table */
1378 bin_int_table [STACK_MAX] [STACK_MAX] = {
1379 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1380 {STACK_INV, STACK_I4, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1381 {STACK_INV, STACK_INV, STACK_I8, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1382 {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1383 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1384 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1385 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1386 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1390 bin_comp_table [STACK_MAX] [STACK_MAX] = {
1391 /* Inv i L p F & O vt */
1393 {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
1394 {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
1395 {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
1396 {0, 0, 0, 0, 1, 0, 0, 0}, /* F, R8 */
1397 {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
1398 {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
1399 {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
1402 /* reduce the size of this table */
1404 shift_table [STACK_MAX] [STACK_MAX] = {
1405 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1406 {STACK_INV, STACK_I4, STACK_INV, STACK_I4, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1407 {STACK_INV, STACK_I8, STACK_INV, STACK_I8, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1408 {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1409 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1410 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1411 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1412 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1416 * Tables to map from the non-specific opcode to the matching
1417 * type-specific opcode.
1419 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
1420 static const guint16
1421 binops_op_map [STACK_MAX] = {
1422 0, 0, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
1425 /* handles from CEE_NEG to CEE_CONV_U8 */
1426 static const guint16
1427 unops_op_map [STACK_MAX] = {
1428 0, 0, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
1431 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
1432 static const guint16
1433 ovfops_op_map [STACK_MAX] = {
1434 0, 0, OP_LCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_FCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2
1437 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
1438 static const guint16
1439 ovf2ops_op_map [STACK_MAX] = {
1440 0, 0, OP_LCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_FCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN
1443 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
1444 static const guint16
1445 ovf3ops_op_map [STACK_MAX] = {
1446 0, 0, OP_LCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_FCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1
1449 /* handles from CEE_CEQ to CEE_CLT_UN */
1450 static const guint16
1451 ceqops_op_map [STACK_MAX] = {
1452 0, 0, OP_LCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_FCEQ-OP_CEQ, OP_LCEQ-OP_CEQ
1456 * Sets ins->type (the type on the eval stack) according to the
1457 * type of the opcode and the arguments to it.
1458 * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
1460 * FIXME: this function sets ins->type unconditionally in some cases, but
1461 * it should set it to invalid for some types (a conv.x on an object)
1464 type_from_op (MonoInst *ins) {
1465 switch (ins->opcode) {
1472 /* FIXME: check unverifiable args for STACK_MP */
1473 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1474 ins->opcode += binops_op_map [ins->type];
1481 ins->type = bin_int_table [ins->inst_i0->type] [ins->inst_i1->type];
1482 ins->opcode += binops_op_map [ins->type];
1487 ins->type = shift_table [ins->inst_i0->type] [ins->inst_i1->type];
1488 ins->opcode += binops_op_map [ins->type];
1492 /* FIXME: handle some specifics with ins->next->type */
1493 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1494 if ((ins->inst_i0->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((ins->inst_i0->type == STACK_PTR) || (ins->inst_i0->type == STACK_OBJ) || (ins->inst_i0->type == STACK_MP))))
1495 ins->opcode = OP_LCOMPARE;
1498 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1499 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1506 ins->type = (bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] & 1) ? STACK_I4: STACK_INV;
1507 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1511 ins->type = neg_table [ins->inst_i0->type];
1512 ins->opcode += unops_op_map [ins->type];
1515 if (ins->inst_i0->type >= STACK_I4 && ins->inst_i0->type <= STACK_PTR)
1516 ins->type = ins->inst_i0->type;
1518 ins->type = STACK_INV;
1519 ins->opcode += unops_op_map [ins->type];
1525 ins->type = STACK_I4;
1526 ins->opcode += unops_op_map [ins->inst_i0->type];
1529 ins->type = STACK_R8;
1530 switch (ins->inst_i0->type) {
1535 ins->opcode = OP_LCONV_TO_R_UN;
1539 case CEE_CONV_OVF_I1:
1540 case CEE_CONV_OVF_U1:
1541 case CEE_CONV_OVF_I2:
1542 case CEE_CONV_OVF_U2:
1543 case CEE_CONV_OVF_I4:
1544 case CEE_CONV_OVF_U4:
1545 ins->type = STACK_I4;
1546 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1548 case CEE_CONV_OVF_I_UN:
1549 case CEE_CONV_OVF_U_UN:
1550 ins->type = STACK_PTR;
1551 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1553 case CEE_CONV_OVF_I1_UN:
1554 case CEE_CONV_OVF_I2_UN:
1555 case CEE_CONV_OVF_I4_UN:
1556 case CEE_CONV_OVF_U1_UN:
1557 case CEE_CONV_OVF_U2_UN:
1558 case CEE_CONV_OVF_U4_UN:
1559 ins->type = STACK_I4;
1560 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1563 ins->type = STACK_PTR;
1564 switch (ins->inst_i0->type) {
1569 #if SIZEOF_VOID_P == 8
1570 ins->opcode = OP_LCONV_TO_U;
1574 ins->opcode = OP_LCONV_TO_U;
1577 ins->opcode = OP_FCONV_TO_U;
1583 ins->type = STACK_I8;
1584 ins->opcode += unops_op_map [ins->inst_i0->type];
1586 case CEE_CONV_OVF_I8:
1587 case CEE_CONV_OVF_U8:
1588 ins->type = STACK_I8;
1589 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1591 case CEE_CONV_OVF_U8_UN:
1592 case CEE_CONV_OVF_I8_UN:
1593 ins->type = STACK_I8;
1594 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1598 ins->type = STACK_R8;
1599 ins->opcode += unops_op_map [ins->inst_i0->type];
1602 ins->type = STACK_R8;
1606 ins->type = STACK_I4;
1607 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1610 case CEE_CONV_OVF_I:
1611 case CEE_CONV_OVF_U:
1612 ins->type = STACK_PTR;
1613 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1616 case CEE_ADD_OVF_UN:
1618 case CEE_MUL_OVF_UN:
1620 case CEE_SUB_OVF_UN:
1621 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1622 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1623 if (ins->type == STACK_R8)
1624 ins->type = STACK_INV;
1627 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1634 STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1637 /* map ldelem.x to the matching ldind.x opcode */
1639 ldelem_to_ldind [] = {
1653 /* map stelem.x to the matching stind.x opcode */
1655 stelem_to_stind [] = {
1667 #ifdef MONO_ARCH_SOFT_FLOAT
1669 handle_store_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, MonoInst *val, const unsigned char *ip)
1671 MonoInst *iargs [2];
1675 mono_emit_jit_icall (cfg, bblock, mono_fstore_r4, iargs, ip);
1679 handle_load_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, const unsigned char *ip)
1681 MonoInst *iargs [1];
1684 return mono_emit_jit_icall (cfg, bblock, mono_fload_r4, iargs, ip);
1687 #define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
1688 if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) { \
1690 NEW_LOCLOADA (cfg, (ins), (idx)); \
1691 temp = handle_load_float (cfg, bblock, (ins), (ip)); \
1692 NEW_TEMPLOAD (cfg, (ins), temp); \
1695 #define STLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
1696 if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) { \
1697 NEW_LOCLOADA (cfg, (ins), (idx)); \
1698 handle_store_float (cfg, bblock, (ins), *sp, (ip)); \
1699 MONO_INST_NEW (cfg, (ins), OP_NOP); \
1702 #define LDARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
1703 if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
1705 NEW_ARGLOADA (cfg, (ins), (idx)); \
1706 temp = handle_load_float (cfg, bblock, (ins), (ip)); \
1707 NEW_TEMPLOAD (cfg, (ins), temp); \
1710 #define STARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
1711 if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
1712 NEW_ARGLOADA (cfg, (ins), (idx)); \
1713 handle_store_float (cfg, bblock, (ins), *sp, (ip)); \
1714 MONO_INST_NEW (cfg, (ins), OP_NOP); \
1718 #define NEW_TEMPLOAD_SOFT_FLOAT(cfg,bblock,ins,num,ip) do { \
1719 if ((ins)->opcode == CEE_LDIND_R4) { \
1722 NEW_TEMPLOADA (cfg, (ins), (idx)); \
1723 temp = handle_load_float (cfg, (bblock), (ins), ip); \
1724 NEW_TEMPLOAD (cfg, (ins), (temp)); \
1728 #define NEW_TEMPSTORE_SOFT_FLOAT(cfg,bblock,ins,num,val,ip) do { \
1729 if ((ins)->opcode == CEE_STIND_R4) { \
1731 NEW_TEMPLOADA (cfg, (ins), (idx)); \
1732 handle_store_float ((cfg), (bblock), (ins), (val), (ip)); \
1738 #define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip)
1739 #define STLOC_SOFT_FLOAT(cfg,ins,idx,ip)
1740 #define LDARG_SOFT_FLOAT(cfg,ins,idx,ip)
1741 #define STARG_SOFT_FLOAT(cfg,ins,idx,ip)
1742 #define NEW_TEMPLOAD_SOFT_FLOAT(cfg,bblock,ins,num,ip)
1743 #define NEW_TEMPSTORE_SOFT_FLOAT(cfg,bblock,ins,num,val,ip)
1749 param_table [STACK_MAX] [STACK_MAX] = {
1754 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig)
1759 switch (args->type) {
1769 for (i = 0; i < sig->param_count; ++i) {
1770 switch (args [i].type) {
1774 if (!sig->params [i]->byref)
1778 if (sig->params [i]->byref)
1780 switch (sig->params [i]->type) {
1781 case MONO_TYPE_CLASS:
1782 case MONO_TYPE_STRING:
1783 case MONO_TYPE_OBJECT:
1784 case MONO_TYPE_SZARRAY:
1785 case MONO_TYPE_ARRAY:
1792 if (sig->params [i]->byref)
1794 if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1803 /*if (!param_table [args [i].type] [sig->params [i]->type])
1811 mini_type_to_ldind (MonoCompile* cfg, MonoType *type)
1813 if (cfg->generic_sharing_context && !type->byref) {
1814 /* FIXME: all the arguments must be references for now,
1815 * later look inside cfg and see if the arg num is
1816 * really a reference
1818 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)
1819 return CEE_LDIND_REF;
1821 return mono_type_to_ldind (type);
1825 mini_type_to_stind (MonoCompile* cfg, MonoType *type)
1827 if (cfg->generic_sharing_context && !type->byref) {
1828 /* FIXME: all the arguments must be references for now,
1829 * later look inside cfg and see if the arg num is
1830 * really a reference
1832 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)
1833 return CEE_STIND_REF;
1835 return mono_type_to_stind (type);
1839 mono_op_imm_to_op (int opcode)
1843 #if SIZEOF_VOID_P == 4
1859 #if SIZEOF_VOID_P == 4
1884 case OP_ISHR_UN_IMM:
1886 case OP_LSHR_UN_IMM:
1890 case OP_IDIV_UN_IMM:
1892 case OP_IREM_UN_IMM:
1897 #if SIZEOF_VOID_P == 4
1903 #if SIZEOF_VOID_P == 4
1920 case OP_COMPARE_IMM:
1922 case OP_ICOMPARE_IMM:
1924 case OP_LOCALLOC_IMM:
1927 printf ("%s\n", mono_inst_name (opcode));
1928 g_assert_not_reached ();
1934 * mono_decompose_op_imm:
1936 * Replace the OP_.._IMM INS with its non IMM variant.
1939 mono_decompose_op_imm (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
1943 MONO_INST_NEW (cfg, temp, OP_ICONST);
1944 temp->inst_c0 = ins->inst_imm;
1945 temp->dreg = mono_regstate_next_int (cfg->rs);
1946 mono_bblock_insert_before_ins (bb, ins, temp);
1947 ins->opcode = mono_op_imm_to_op (ins->opcode);
1948 if (ins->opcode == OP_LOCALLOC)
1949 ins->sreg1 = temp->dreg;
1951 ins->sreg2 = temp->dreg;
1953 bb->max_vreg = MAX (bb->max_vreg, cfg->rs->next_vreg);
1957 * When we need a pointer to the current domain many times in a method, we
1958 * call mono_domain_get() once and we store the result in a local variable.
1959 * This function returns the variable that represents the MonoDomain*.
1961 inline static MonoInst *
1962 mono_get_domainvar (MonoCompile *cfg)
1964 if (!cfg->domainvar)
1965 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1966 return cfg->domainvar;
1970 * The got_var contains the address of the Global Offset Table when AOT
1973 inline static MonoInst *
1974 mono_get_got_var (MonoCompile *cfg)
1976 #ifdef MONO_ARCH_NEED_GOT_VAR
1977 if (!cfg->compile_aot)
1979 if (!cfg->got_var) {
1980 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1982 return cfg->got_var;
1989 mono_get_vtable_var (MonoCompile *cfg)
1991 g_assert (cfg->generic_sharing_context);
1993 if (!cfg->rgctx_var) {
1994 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1995 /* force the var to be stack allocated */
1996 cfg->rgctx_var->flags |= MONO_INST_INDIRECT;
1999 return cfg->rgctx_var;
2003 set_vreg_to_inst (MonoCompile *cfg, int vreg, MonoInst *inst)
2005 if (vreg >= cfg->vreg_to_inst_len) {
2006 MonoInst **tmp = cfg->vreg_to_inst;
2007 int size = cfg->vreg_to_inst_len;
2009 while (vreg >= cfg->vreg_to_inst_len)
2010 cfg->vreg_to_inst_len = cfg->vreg_to_inst_len ? cfg->vreg_to_inst_len * 2 : 32;
2011 cfg->vreg_to_inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * cfg->vreg_to_inst_len);
2013 memcpy (cfg->vreg_to_inst, tmp, size * sizeof (MonoInst*));
2015 cfg->vreg_to_inst [vreg] = inst;
2018 #define mono_type_is_long(type) (!(type)->byref && ((mono_type_get_underlying_type (type)->type == MONO_TYPE_I8) || (mono_type_get_underlying_type (type)->type == MONO_TYPE_U8)))
2019 #define mono_type_is_float(type) (!(type)->byref && (((type)->type == MONO_TYPE_R8) || ((type)->type == MONO_TYPE_R4)))
2022 mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode, int vreg)
2025 int num = cfg->num_varinfo;
2028 if ((num + 1) >= cfg->varinfo_count) {
2029 int orig_count = cfg->varinfo_count;
2030 cfg->varinfo_count = cfg->varinfo_count ? (cfg->varinfo_count * 2) : 64;
2031 cfg->varinfo = (MonoInst **)g_realloc (cfg->varinfo, sizeof (MonoInst*) * cfg->varinfo_count);
2032 cfg->vars = (MonoMethodVar *)g_realloc (cfg->vars, sizeof (MonoMethodVar) * cfg->varinfo_count);
2033 memset (&cfg->vars [orig_count], 0, (cfg->varinfo_count - orig_count) * sizeof (MonoMethodVar));
2036 mono_jit_stats.allocate_var++;
2038 MONO_INST_NEW (cfg, inst, opcode);
2039 inst->inst_c0 = num;
2040 inst->inst_vtype = type;
2041 inst->klass = mono_class_from_mono_type (type);
2042 type_to_eval_stack_type (cfg, type, inst);
2043 /* if set to 1 the variable is native */
2044 inst->backend.is_pinvoke = 0;
2047 cfg->varinfo [num] = inst;
2049 MONO_INIT_VARINFO (&cfg->vars [num], num);
2052 set_vreg_to_inst (cfg, vreg, inst);
2054 #if SIZEOF_VOID_P == 4
2055 #ifdef MONO_ARCH_SOFT_FLOAT
2056 regpair = mono_type_is_long (type) || mono_type_is_float (type);
2058 regpair = mono_type_is_long (type);
2068 * These two cannot be allocated using create_var_for_vreg since that would
2069 * put it into the cfg->varinfo array, confusing many parts of the JIT.
2073 * Set flags to VOLATILE so SSA skips it.
2076 if (cfg->verbose_level >= 4) {
2077 printf (" Create LVAR R%d (R%d, R%d)\n", inst->dreg, inst->dreg + 1, inst->dreg + 2);
2080 #ifdef MONO_ARCH_SOFT_FLOAT
2081 if (cfg->opt & MONO_OPT_SSA) {
2082 if (mono_type_is_float (type))
2083 inst->flags = MONO_INST_VOLATILE;
2087 /* Allocate a dummy MonoInst for the first vreg */
2088 MONO_INST_NEW (cfg, tree, OP_LOCAL);
2089 tree->dreg = inst->dreg + 1;
2090 if (cfg->opt & MONO_OPT_SSA)
2091 tree->flags = MONO_INST_VOLATILE;
2092 tree->inst_c0 = num;
2093 tree->type = STACK_I4;
2094 tree->inst_vtype = &mono_defaults.int32_class->byval_arg;
2095 tree->klass = mono_class_from_mono_type (tree->inst_vtype);
2097 set_vreg_to_inst (cfg, inst->dreg + 1, tree);
2099 /* Allocate a dummy MonoInst for the second vreg */
2100 MONO_INST_NEW (cfg, tree, OP_LOCAL);
2101 tree->dreg = inst->dreg + 2;
2102 if (cfg->opt & MONO_OPT_SSA)
2103 tree->flags = MONO_INST_VOLATILE;
2104 tree->inst_c0 = num;
2105 tree->type = STACK_I4;
2106 tree->inst_vtype = &mono_defaults.int32_class->byval_arg;
2107 tree->klass = mono_class_from_mono_type (tree->inst_vtype);
2109 set_vreg_to_inst (cfg, inst->dreg + 2, tree);
2113 if (cfg->verbose_level > 2)
2114 g_print ("created temp %d (R%d) of type %s\n", num, vreg, mono_type_get_name (type));
2119 mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
2123 if (mono_type_is_long (type))
2124 dreg = mono_alloc_dreg (cfg, STACK_I8);
2125 #ifdef MONO_ARCH_SOFT_FLOAT
2126 else if (mono_type_is_float (type))
2127 dreg = mono_alloc_dreg (cfg, STACK_R8);
2130 /* All the others are unified */
2131 dreg = mono_alloc_preg (cfg);
2133 return mono_compile_create_var_for_vreg (cfg, type, opcode, dreg);
2137 * Transform a MonoInst into a load from the variable of index var_index.
2140 mono_compile_make_var_load (MonoCompile *cfg, MonoInst *dest, gssize var_index) {
2141 memset (dest, 0, sizeof (MonoInst));
2142 dest->ssa_op = MONO_SSA_LOAD;
2143 dest->inst_i0 = cfg->varinfo [var_index];
2144 dest->opcode = mini_type_to_ldind (cfg, dest->inst_i0->inst_vtype);
2145 type_to_eval_stack_type (cfg, dest->inst_i0->inst_vtype, dest);
2146 dest->klass = dest->inst_i0->klass;
2150 * Create a MonoInst that is a load from the variable of index var_index.
2153 mono_compile_create_var_load (MonoCompile *cfg, gssize var_index) {
2155 NEW_TEMPLOAD (cfg,dest,var_index);
2160 * Create a MonoInst that is a store of the given value into the variable of index var_index.
2163 mono_compile_create_var_store (MonoCompile *cfg, gssize var_index, MonoInst *value) {
2165 NEW_TEMPSTORE (cfg, dest, var_index, value);
2170 type_from_stack_type (MonoInst *ins) {
2171 switch (ins->type) {
2172 case STACK_I4: return &mono_defaults.int32_class->byval_arg;
2173 case STACK_I8: return &mono_defaults.int64_class->byval_arg;
2174 case STACK_PTR: return &mono_defaults.int_class->byval_arg;
2175 case STACK_R8: return &mono_defaults.double_class->byval_arg;
2178 * this if used to be commented without any specific reason, but
2179 * it breaks #80235 when commented
2182 return &ins->klass->this_arg;
2184 return &mono_defaults.object_class->this_arg;
2186 /* ins->klass may not be set for ldnull.
2187 * Also, if we have a boxed valuetype, we want an object lass,
2188 * not the valuetype class
2190 if (ins->klass && !ins->klass->valuetype)
2191 return &ins->klass->byval_arg;
2192 return &mono_defaults.object_class->byval_arg;
2193 case STACK_VTYPE: return &ins->klass->byval_arg;
2195 g_error ("stack type %d to montype not handled\n", ins->type);
2201 mono_type_from_stack_type (MonoInst *ins) {
2202 return type_from_stack_type (ins);
2206 array_access_to_klass (int opcode, MonoInst *array_obj)
2210 return mono_defaults.byte_class;
2212 return mono_defaults.uint16_class;
2215 return mono_defaults.int_class;
2218 return mono_defaults.sbyte_class;
2221 return mono_defaults.int16_class;
2224 return mono_defaults.int32_class;
2226 return mono_defaults.uint32_class;
2229 return mono_defaults.int64_class;
2232 return mono_defaults.single_class;
2235 return mono_defaults.double_class;
2236 case CEE_LDELEM_REF:
2237 case CEE_STELEM_REF: {
2238 MonoClass *klass = array_obj->klass;
2239 /* FIXME: add assert */
2240 if (klass && klass->rank)
2241 return klass->element_class;
2242 return mono_defaults.object_class;
2245 g_assert_not_reached ();
2251 * mono_add_ins_to_end:
2253 * Same as MONO_ADD_INS, but add INST before any branches at the end of BB.
2256 mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
2261 MONO_ADD_INS (bb, inst);
2265 switch (bb->last_ins->opcode) {
2279 mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
2282 if (MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
2283 /* Need to insert the ins before the compare */
2284 if (bb->code == bb->last_ins) {
2285 mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
2289 if (bb->code->next == bb->last_ins) {
2290 /* Only two instructions */
2291 opcode = bb->code->opcode;
2293 if ((opcode == OP_COMPARE) || (opcode == OP_COMPARE_IMM) || (opcode == OP_ICOMPARE) || (opcode == OP_ICOMPARE_IMM) || (opcode == OP_FCOMPARE) || (opcode == OP_LCOMPARE) || (opcode == OP_LCOMPARE_IMM)) {
2295 mono_bblock_insert_before_ins (bb, bb->code, inst);
2297 mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
2300 opcode = bb->last_ins->prev->opcode;
2302 if ((opcode == OP_COMPARE) || (opcode == OP_COMPARE_IMM) || (opcode == OP_ICOMPARE) || (opcode == OP_ICOMPARE_IMM) || (opcode == OP_FCOMPARE) || (opcode == OP_LCOMPARE) || (opcode == OP_LCOMPARE_IMM)) {
2304 mono_bblock_insert_before_ins (bb, bb->last_ins->prev, inst);
2306 mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
2311 MONO_ADD_INS (bb, inst);
2319 * Replace INS with its decomposition which is stored in a series of bblocks starting
2320 * at FIRST_BB and ending at LAST_BB. On enter, PREV points to the predecessor of INS.
2321 * On return, it will be set to the last ins of the decomposition.
2324 mono_replace_ins (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, MonoInst **prev, MonoBasicBlock *first_bb, MonoBasicBlock *last_bb)
2326 MonoInst *next = ins->next;
2328 if (next && next->opcode == OP_NOP) {
2329 /* Avoid NOPs following branches */
2330 ins->next = next->next;
2334 if (first_bb == last_bb) {
2336 * Only one replacement bb, merge the code into
2340 /* Delete links between the first_bb and its successors */
2341 while (first_bb->out_count)
2342 mono_unlink_bblock (cfg, first_bb, first_bb->out_bb [0]);
2346 (*prev)->next = first_bb->code;
2347 first_bb->code->prev = (*prev);
2349 bb->code = first_bb->code;
2353 last_bb->last_ins->next = next;
2355 next->prev = last_bb->last_ins;
2357 bb->last_ins = last_bb->last_ins;
2358 *prev = last_bb->last_ins;
2361 MonoBasicBlock **tmp_bblocks, *tmp;
2367 for (tmp = first_bb; tmp; tmp = tmp->next_bb)
2368 tmp->region = bb->region;
2370 /* Split the original bb */
2372 ins->next->prev = NULL;
2376 /* Merge the second part of the original bb into the last bb */
2377 if (last_bb->last_ins) {
2378 last_bb->last_ins->next = next;
2380 next->prev = last_bb->last_ins;
2382 last_bb->code = next;
2386 for (last = next; last->next != NULL; last = last->next)
2388 last_bb->last_ins = last;
2391 for (i = 0; i < bb->out_count; ++i)
2392 link_bblock (cfg, last_bb, bb->out_bb [i]);
2394 /* Merge the first (dummy) bb to the original bb */
2396 (*prev)->next = first_bb->code;
2397 first_bb->code->prev = (*prev);
2399 bb->code = first_bb->code;
2401 bb->last_ins = first_bb->last_ins;
2403 /* Delete the links between the original bb and its successors */
2404 tmp_bblocks = bb->out_bb;
2405 count = bb->out_count;
2406 for (i = 0; i < count; ++i)
2407 mono_unlink_bblock (cfg, bb, tmp_bblocks [i]);
2409 /* Add links between the original bb and the first_bb's successors */
2410 for (i = 0; i < first_bb->out_count; ++i) {
2411 MonoBasicBlock *out_bb = first_bb->out_bb [i];
2413 link_bblock (cfg, bb, out_bb);
2415 /* Delete links between the first_bb and its successors */
2416 for (i = 0; i < bb->out_count; ++i) {
2417 MonoBasicBlock *out_bb = bb->out_bb [i];
2419 mono_unlink_bblock (cfg, first_bb, out_bb);
2421 last_bb->next_bb = bb->next_bb;
2422 bb->next_bb = first_bb->next_bb;
2429 mono_add_varcopy_to_end (MonoCompile *cfg, MonoBasicBlock *bb, int src, int dest)
2431 MonoInst *inst, *load;
2433 NEW_TEMPLOAD (cfg, load, src);
2435 NEW_TEMPSTORE (cfg, inst, dest, load);
2436 /* FIXME: handle CEE_STIND_R4 */
2437 if (inst->opcode == CEE_STOBJ) {
2438 NEW_TEMPLOADA (cfg, inst, dest);
2439 handle_stobj (cfg, bb, inst, load, NULL, inst->klass, TRUE, FALSE, FALSE);
2441 inst->cil_code = NULL;
2442 mono_add_ins_to_end (bb, inst);
2447 * This function is called to handle items that are left on the evaluation stack
2448 * at basic block boundaries. What happens is that we save the values to local variables
2449 * and we reload them later when first entering the target basic block (with the
2450 * handle_loaded_temps () function).
2451 * It is also used to handle items on the stack in store opcodes, since it is
2452 * possible that the variable to be stored into is already on the stack, in
2453 * which case its old value should be used.
2454 * A single joint point will use the same variables (stored in the array bb->out_stack or
2455 * bb->in_stack, if the basic block is before or after the joint point).
2456 * If the stack merge fails at a join point, cfg->unverifiable is set.
2459 handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count)
2462 MonoBasicBlock *outb;
2463 MonoInst *inst, **locals;
2468 if (cfg->verbose_level > 3)
2469 g_print ("%d item(s) on exit from B%d\n", count, bb->block_num);
2471 if (!bb->out_scount) {
2472 bb->out_scount = count;
2473 //g_print ("bblock %d has out:", bb->block_num);
2475 for (i = 0; i < bb->out_count; ++i) {
2476 outb = bb->out_bb [i];
2477 /* exception handlers are linked, but they should not be considered for stack args */
2478 if (outb->flags & BB_EXCEPTION_HANDLER)
2480 //g_print (" %d", outb->block_num);
2481 if (outb->in_stack) {
2483 bb->out_stack = outb->in_stack;
2489 bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
2490 for (i = 0; i < count; ++i) {
2492 * try to reuse temps already allocated for this purpouse, if they occupy the same
2493 * stack slot and if they are of the same type.
2494 * This won't cause conflicts since if 'local' is used to
2495 * store one of the values in the in_stack of a bblock, then
2496 * the same variable will be used for the same outgoing stack
2498 * This doesn't work when inlining methods, since the bblocks
2499 * in the inlined methods do not inherit their in_stack from
2500 * the bblock they are inlined to. See bug #58863 for an
2502 * This hack is disabled since it also prevents proper tracking of types.
2505 bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
2507 if (cfg->inlined_method)
2508 bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
2510 bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
2516 for (i = 0; i < bb->out_count; ++i) {
2517 outb = bb->out_bb [i];
2518 /* exception handlers are linked, but they should not be considered for stack args */
2519 if (outb->flags & BB_EXCEPTION_HANDLER)
2521 if (outb->in_scount) {
2522 if (outb->in_scount != bb->out_scount) {
2523 cfg->unverifiable = TRUE;
2526 continue; /* check they are the same locals */
2528 outb->in_scount = count;
2529 outb->in_stack = bb->out_stack;
2532 locals = bb->out_stack;
2533 for (i = 0; i < count; ++i) {
2534 /* add store ops at the end of the bb, before the branch */
2535 NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
2536 if (inst->opcode == CEE_STOBJ) {
2537 NEW_TEMPLOADA (cfg, inst, locals [i]->inst_c0);
2538 handle_stobj (cfg, bb, inst, sp [i], sp [i]->cil_code, inst->klass, TRUE, FALSE, FALSE);
2540 inst->cil_code = sp [i]->cil_code;
2541 mono_add_ins_to_end (bb, inst);
2543 if (cfg->verbose_level > 3)
2544 g_print ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
2548 * It is possible that the out bblocks already have in_stack assigned, and
2549 * the in_stacks differ. In this case, we will store to all the different
2556 /* Find a bblock which has a different in_stack */
2558 while (bindex < bb->out_count) {
2559 outb = bb->out_bb [bindex];
2560 /* exception handlers are linked, but they should not be considered for stack args */
2561 if (outb->flags & BB_EXCEPTION_HANDLER) {
2565 if (outb->in_stack != locals) {
2567 * Instead of storing sp [i] to locals [i], we need to store
2568 * locals [i] to <new locals>[i], since the sp [i] tree can't
2569 * be shared between trees.
2571 for (i = 0; i < count; ++i)
2572 mono_add_varcopy_to_end (cfg, bb, locals [i]->inst_c0, outb->in_stack [i]->inst_c0);
2573 locals = outb->in_stack;
2583 ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
2586 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2589 type = mini_get_basic_type_from_generic (gsctx, type);
2590 switch (type->type) {
2591 case MONO_TYPE_VOID:
2592 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALLVIRT: OP_VOIDCALL;
2595 case MONO_TYPE_BOOLEAN:
2598 case MONO_TYPE_CHAR:
2601 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2605 case MONO_TYPE_FNPTR:
2606 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2607 case MONO_TYPE_CLASS:
2608 case MONO_TYPE_STRING:
2609 case MONO_TYPE_OBJECT:
2610 case MONO_TYPE_SZARRAY:
2611 case MONO_TYPE_ARRAY:
2612 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2615 return calli? OP_LCALL_REG: virt? OP_LCALLVIRT: OP_LCALL;
2618 return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
2619 case MONO_TYPE_VALUETYPE:
2620 if (type->data.klass->enumtype) {
2621 type = type->data.klass->enum_basetype;
2624 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
2625 case MONO_TYPE_TYPEDBYREF:
2626 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
2627 case MONO_TYPE_GENERICINST:
2628 type = &type->data.generic_class->container_class->byval_arg;
2631 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2637 mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs, int num_blocks)
2639 MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
2640 MonoJumpInfoBBTable *table;
2642 table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
2644 table->table_size = num_blocks;
2646 ji->ip.label = label;
2647 ji->type = MONO_PATCH_INFO_SWITCH;
2648 ji->data.table = table;
2649 ji->next = cfg->patch_info;
2650 cfg->patch_info = ji;
2654 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
2656 if (cfg->compile_aot) {
2657 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
2658 jump_info_token->image = image;
2659 jump_info_token->token = token;
2660 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
2665 * When we add a tree of instructions, we need to ensure the instructions currently
2666 * on the stack are executed before (like, if we load a value from a local).
2667 * We ensure this by saving the currently loaded values to temps and rewriting the
2668 * instructions to load the values.
2669 * This is not done for opcodes that terminate a basic block (because it's handled already
2670 * by handle_stack_args ()) and for opcodes that can't change values, like POP.
2673 handle_loaded_temps (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst **stack, MonoInst **sp)
2675 MonoInst *load, *store, *temp, *ins;
2677 while (stack < sp) {
2679 /* handle also other constants */
2680 if ((ins->opcode != OP_ICONST) &&
2681 /* temps never get written to again, so we can safely avoid duplicating them */
2682 !(ins->ssa_op == MONO_SSA_LOAD && ins->inst_i0->opcode == OP_LOCAL && ins->inst_i0->flags & MONO_INST_IS_TEMP)) {
2683 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
2684 temp->flags |= MONO_INST_IS_TEMP;
2685 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2686 store->cil_code = ins->cil_code;
2687 if (store->opcode == CEE_STOBJ) {
2688 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
2689 handle_stobj (cfg, bblock, store, ins, ins->cil_code, temp->klass, FALSE, FALSE, FALSE);
2691 MONO_ADD_INS (bblock, store);
2692 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
2693 load->cil_code = ins->cil_code;
2701 * target_type_is_incompatible:
2702 * @cfg: MonoCompile context
2704 * Check that the item @arg on the evaluation stack can be stored
2705 * in the target type (can be a local, or field, etc).
2706 * The cfg arg can be used to check if we need verification or just
2709 * Returns: non-0 value if arg can't be stored on a target.
2712 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2714 MonoType *simple_type;
2717 if (target->byref) {
2718 /* FIXME: check that the pointed to types match */
2719 if (arg->type == STACK_MP)
2720 return arg->klass != mono_class_from_mono_type (target);
2721 if (arg->type == STACK_PTR)
2725 simple_type = mono_type_get_underlying_type (target);
2726 switch (simple_type->type) {
2727 case MONO_TYPE_VOID:
2731 case MONO_TYPE_BOOLEAN:
2734 case MONO_TYPE_CHAR:
2737 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2741 /* STACK_MP is needed when setting pinned locals */
2742 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2747 case MONO_TYPE_FNPTR:
2748 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2751 case MONO_TYPE_OBJECT:
2752 if (arg->type != STACK_OBJ)
2755 case MONO_TYPE_STRING:
2756 if (arg->type != STACK_OBJ)
2758 /* ldnull has arg->klass unset */
2759 /*if (arg->klass && arg->klass != mono_defaults.string_class) {
2764 case MONO_TYPE_CLASS:
2765 case MONO_TYPE_SZARRAY:
2766 case MONO_TYPE_ARRAY:
2767 if (arg->type != STACK_OBJ)
2769 /* FIXME: check type compatibility */
2773 if (arg->type != STACK_I8)
2778 if (arg->type != STACK_R8)
2781 case MONO_TYPE_VALUETYPE:
2782 if (arg->type != STACK_VTYPE)
2784 klass = mono_class_from_mono_type (simple_type);
2785 if (klass != arg->klass)
2788 case MONO_TYPE_TYPEDBYREF:
2789 if (arg->type != STACK_VTYPE)
2791 klass = mono_class_from_mono_type (simple_type);
2792 if (klass != arg->klass)
2795 case MONO_TYPE_GENERICINST:
2796 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2797 klass = mono_class_from_mono_type (simple_type);
2798 if (klass->enumtype)
2799 return target_type_is_incompatible (cfg, klass->enum_basetype, arg);
2800 if (arg->type != STACK_VTYPE)
2802 if (klass != arg->klass)
2806 if (arg->type != STACK_OBJ)
2808 /* FIXME: check type compatibility */
2812 case MONO_TYPE_MVAR:
2813 /* FIXME: all the arguments must be references for now,
2814 * later look inside cfg and see if the arg num is
2815 * really a reference
2817 g_assert (cfg->generic_sharing_context);
2818 if (arg->type != STACK_OBJ)
2822 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2828 * Prepare arguments for passing to a function call.
2829 * Return a non-zero value if the arguments can't be passed to the given
2831 * The type checks are not yet complete and some conversions may need
2832 * casts on 32 or 64 bit architectures.
2834 * FIXME: implement this using target_type_is_incompatible ()
2837 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2839 MonoType *simple_type;
2843 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2847 for (i = 0; i < sig->param_count; ++i) {
2848 if (sig->params [i]->byref) {
2849 if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2853 simple_type = sig->params [i];
2854 simple_type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, simple_type);
2856 switch (simple_type->type) {
2857 case MONO_TYPE_VOID:
2862 case MONO_TYPE_BOOLEAN:
2865 case MONO_TYPE_CHAR:
2868 if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2874 case MONO_TYPE_FNPTR:
2875 if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2878 case MONO_TYPE_CLASS:
2879 case MONO_TYPE_STRING:
2880 case MONO_TYPE_OBJECT:
2881 case MONO_TYPE_SZARRAY:
2882 case MONO_TYPE_ARRAY:
2883 if (args [i]->type != STACK_OBJ)
2888 if (args [i]->type != STACK_I8)
2893 if (args [i]->type != STACK_R8)
2896 case MONO_TYPE_VALUETYPE:
2897 if (simple_type->data.klass->enumtype) {
2898 simple_type = simple_type->data.klass->enum_basetype;
2901 if (args [i]->type != STACK_VTYPE)
2904 case MONO_TYPE_TYPEDBYREF:
2905 if (args [i]->type != STACK_VTYPE)
2908 case MONO_TYPE_GENERICINST:
2909 simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2913 g_error ("unknown type 0x%02x in check_call_signature",
2921 mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, MonoMethodSignature *sig, gboolean ret_object,
2922 const guint8 *ip, gboolean to_end)
2924 MonoInst *temp, *store, *ins = (MonoInst*)call;
2925 MonoType *ret = sig->ret;
2927 if (!MONO_TYPE_IS_VOID (ret) || ret_object) {
2929 call->inst.type = STACK_OBJ;
2930 call->inst.opcode = OP_CALL;
2931 temp = mono_compile_create_var (cfg, &mono_defaults.string_class->byval_arg, OP_LOCAL);
2933 type_to_eval_stack_type (cfg, ret, ins);
2934 temp = mono_compile_create_var (cfg, ret, OP_LOCAL);
2937 temp->flags |= MONO_INST_IS_TEMP;
2939 if (MONO_TYPE_ISSTRUCT (ret)) {
2940 MonoInst *loada, *dummy_store;
2943 * Emit a dummy store to the local holding the result so the
2944 * liveness info remains correct.
2946 NEW_DUMMY_STORE (cfg, dummy_store, temp->inst_c0);
2948 mono_add_ins_to_end (bblock, dummy_store);
2950 MONO_ADD_INS (bblock, dummy_store);
2952 /* we use this to allocate native sized structs */
2953 temp->backend.is_pinvoke = sig->pinvoke;
2955 NEW_TEMPLOADA (cfg, loada, temp->inst_c0);
2956 if (call->inst.opcode == OP_VCALL || call->inst.opcode == OP_VCALL_RGCTX)
2957 ins->inst_left = loada;
2959 ins->inst_right = loada; /* a virtual or indirect call */
2962 mono_add_ins_to_end (bblock, ins);
2964 MONO_ADD_INS (bblock, ins);
2966 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2967 store->cil_code = ip;
2969 #ifdef MONO_ARCH_SOFT_FLOAT
2970 if (store->opcode == CEE_STIND_R4) {
2971 /*FIXME implement proper support for to_end*/
2973 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
2974 handle_store_float (cfg, bblock, store, ins, ip);
2978 mono_add_ins_to_end (bblock, store);
2980 MONO_ADD_INS (bblock, store);
2982 return temp->inst_c0;
2985 mono_add_ins_to_end (bblock, ins);
2987 MONO_ADD_INS (bblock, ins);
2992 inline static MonoCallInst *
2993 mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
2994 MonoInst **args, int calli, int virtual, const guint8 *ip, gboolean to_end)
2999 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
3001 #ifdef MONO_ARCH_SOFT_FLOAT
3002 /* we need to convert the r4 value to an int value */
3005 for (i = 0; i < sig->param_count; ++i) {
3006 if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4) {
3007 MonoInst *iargs [1];
3009 iargs [0] = args [i + sig->hasthis];
3011 temp = mono_emit_jit_icall (cfg, bblock, mono_fload_r4_arg, iargs, ip);
3012 NEW_TEMPLOAD (cfg, arg, temp);
3013 args [i + sig->hasthis] = arg;
3019 call->inst.cil_code = ip;
3021 call->signature = sig;
3022 call = mono_arch_call_opcode (cfg, bblock, call, virtual);
3023 type_to_eval_stack_type (cfg, sig->ret, &call->inst);
3025 for (arg = call->out_args; arg;) {
3026 MonoInst *narg = arg->next;
3031 mono_add_ins_to_end (bblock, arg);
3033 MONO_ADD_INS (bblock, arg);
3039 inline static MonoCallInst*
3040 mono_emit_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
3041 MonoInst **args, MonoInst *addr, const guint8 *ip)
3043 MonoCallInst *call = mono_emit_call_args (cfg, bblock, sig, args, TRUE, FALSE, ip, FALSE);
3045 call->inst.inst_i0 = addr;
3050 inline static MonoCallInst*
3051 mono_emit_rgctx_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
3052 MonoInst **args, MonoInst *addr, MonoInst *rgctx_arg, const guint8 *ip)
3054 MonoCallInst *call = mono_emit_calli (cfg, bblock, sig, args, addr, ip);
3057 switch (call->inst.opcode) {
3058 case OP_CALL_REG: call->inst.opcode = OP_CALL_REG_RGCTX; break;
3059 case OP_VOIDCALL_REG: call->inst.opcode = OP_VOIDCALL_REG_RGCTX; break;
3060 case OP_FCALL_REG: call->inst.opcode = OP_FCALL_REG_RGCTX; break;
3061 case OP_LCALL_REG: call->inst.opcode = OP_LCALL_REG_RGCTX; break;
3062 case OP_VCALL_REG: {
3065 NEW_GROUP (cfg, group, call->inst.inst_left, NULL);
3066 call->inst.inst_left = group;
3067 call->inst.opcode = OP_VCALL_REG_RGCTX;
3070 default: g_assert_not_reached ();
3073 if (call->inst.opcode != OP_VCALL_REG_RGCTX) {
3074 g_assert (!call->inst.inst_right);
3075 call->inst.inst_right = rgctx_arg;
3077 g_assert (!call->inst.inst_left->inst_right);
3078 call->inst.inst_left->inst_right = rgctx_arg;
3086 mono_emit_calli_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
3087 MonoInst **args, MonoInst *addr, const guint8 *ip)
3089 MonoCallInst *call = mono_emit_calli (cfg, bblock, sig, args, addr, ip);
3091 return mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
3095 mono_emit_rgctx_calli_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
3096 MonoInst **args, MonoInst *addr, MonoInst *rgctx_arg, const guint8 *ip)
3098 MonoCallInst *call = mono_emit_rgctx_calli (cfg, bblock, sig, args, addr, rgctx_arg, ip);
3100 return mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
3103 static MonoCallInst*
3104 mono_emit_method_call_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
3105 MonoInst **args, const guint8 *ip, MonoInst *this, gboolean to_end)
3107 gboolean virtual = this != NULL;
3110 call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, virtual, ip, to_end);
3112 if (this && sig->hasthis &&
3113 (method->klass->marshalbyref || method->klass == mono_defaults.object_class) &&
3114 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this)) {
3115 call->method = mono_marshal_get_remoting_invoke_with_check (method);
3117 call->method = method;
3119 call->inst.flags |= MONO_INST_HAS_METHOD;
3120 call->inst.inst_left = this;
3122 if (call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
3123 /* Needed by the code generated in inssel.brg */
3124 mono_get_got_var (cfg);
3129 static MonoCallInst*
3130 mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
3131 MonoInst **args, const guint8 *ip, MonoInst *this)
3133 return mono_emit_method_call_full (cfg, bblock, method, sig, args, ip, this, FALSE);
3137 mono_emit_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,
3138 MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
3140 MonoCallInst *call = mono_emit_method_call (cfg, bblock, method, signature, args, ip, this);
3142 return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
3146 mono_emit_method_call_spilled_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,
3147 MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this,
3148 gboolean ret_object, gboolean to_end)
3150 MonoCallInst *call = mono_emit_method_call_full (cfg, bblock, method, signature, args, ip, this, to_end);
3152 return mono_spill_call (cfg, bblock, call, signature, ret_object, ip, to_end);
3156 mono_emit_native_call (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoMethodSignature *sig,
3157 MonoInst **args, const guint8 *ip, gboolean ret_object, gboolean to_end)
3163 call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, FALSE, ip, to_end);
3166 return mono_spill_call (cfg, bblock, call, sig, ret_object, ip, to_end);
3170 mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip)
3172 MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
3175 g_warning ("unregistered JIT ICall");
3176 g_assert_not_reached ();
3179 return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, args, ip, FALSE, FALSE);
3182 static MonoCallInst*
3183 mono_emit_rgctx_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
3184 MonoInst **args, MonoInst *rgctx_arg, MonoInst *imt_arg, const guint8 *ip, MonoInst *this)
3186 MonoCallInst *call = mono_emit_method_call_full (cfg, bblock, method, sig, args, ip, this, FALSE);
3188 g_assert (!(rgctx_arg && imt_arg));
3191 switch (call->inst.opcode) {
3192 case OP_CALL: call->inst.opcode = OP_CALL_RGCTX; break;
3193 case OP_VOIDCALL: call->inst.opcode = OP_VOIDCALL_RGCTX; break;
3194 case OP_FCALL: call->inst.opcode = OP_FCALL_RGCTX; break;
3195 case OP_LCALL: call->inst.opcode = OP_LCALL_RGCTX; break;
3196 case OP_VCALL: call->inst.opcode = OP_VCALL_RGCTX; break;
3197 default: g_assert_not_reached ();
3200 if (call->inst.opcode != OP_VCALL_RGCTX) {
3201 g_assert (!call->inst.inst_left);
3202 call->inst.inst_left = rgctx_arg;
3204 g_assert (!call->inst.inst_right);
3205 call->inst.inst_right = rgctx_arg;
3207 } else if (imt_arg) {
3208 switch (call->inst.opcode) {
3209 case OP_CALLVIRT: call->inst.opcode = OP_CALLVIRT_IMT; break;
3210 case OP_VOIDCALLVIRT: call->inst.opcode = OP_VOIDCALLVIRT_IMT; break;
3211 case OP_FCALLVIRT: call->inst.opcode = OP_FCALLVIRT_IMT; break;
3212 case OP_LCALLVIRT: call->inst.opcode = OP_LCALLVIRT_IMT; break;
3213 case OP_VCALLVIRT: {
3216 NEW_GROUP (cfg, group, call->inst.inst_left, NULL);
3217 call->inst.inst_left = group;
3218 call->inst.opcode = OP_VCALLVIRT_IMT;
3221 default: g_assert_not_reached ();
3224 if (call->inst.opcode != OP_VCALLVIRT_IMT) {
3225 g_assert (!call->inst.inst_right);
3226 call->inst.inst_right = imt_arg;
3228 g_assert (!call->inst.inst_left->inst_right);
3229 call->inst.inst_left->inst_right = imt_arg;
3237 mono_emit_rgctx_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,
3238 MonoMethodSignature *signature, MonoInst **args, MonoInst *rgctx_arg, MonoInst *imt_arg,
3239 const guint8 *ip, MonoInst *this)
3241 MonoCallInst *call = mono_emit_rgctx_method_call (cfg, bblock, method, signature, args, rgctx_arg, imt_arg, ip, this);
3243 return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
3247 mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJitICallInfo *info)
3249 MonoInst *ins, *temp = NULL, *store, *load, *begin;
3250 MonoInst *last_arg = NULL;
3254 //g_print ("emulating: ");
3255 //mono_print_tree_nl (tree);
3256 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (info->sig->ret, FALSE, FALSE, cfg->generic_sharing_context));
3257 ins = (MonoInst*)call;
3259 call->inst.cil_code = tree->cil_code;
3261 call->signature = info->sig;
3263 call = mono_arch_call_opcode (cfg, cfg->cbb, call, FALSE);
3265 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
3266 temp = mono_compile_create_var (cfg, info->sig->ret, OP_LOCAL);
3267 temp->flags |= MONO_INST_IS_TEMP;
3268 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
3269 /* FIXME: handle CEE_STIND_R4 */
3270 store->cil_code = tree->cil_code;
3275 nargs = info->sig->param_count + info->sig->hasthis;
3277 for (last_arg = call->out_args; last_arg && last_arg->next; last_arg = last_arg->next) ;
3280 last_arg->next = store;
3283 begin = call->out_args;
3287 if (cfg->prev_ins) {
3289 * This assumes that that in a tree, emulate_opcode is called for a
3290 * node before it is called for its children. dec_foreach needs to
3291 * take this into account.
3293 store->next = cfg->prev_ins->next;
3294 cfg->prev_ins->next = begin;
3296 store->next = cfg->cbb->code;
3297 cfg->cbb->code = begin;
3300 call->fptr = mono_icall_get_wrapper (info);
3302 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
3303 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
3309 * This entry point could be used later for arbitrary method
3313 mini_redirect_call (int *temp, MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,
3314 MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
3317 if (method->klass == mono_defaults.string_class) {
3318 /* managed string allocation support */
3319 if (strcmp (method->name, "InternalAllocateStr") == 0) {
3320 MonoInst *iargs [2];
3321 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3322 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, FALSE);
3325 NEW_VTABLECONST (cfg, iargs [0], vtable);
3326 iargs [1] = args [0];
3327 *temp = mono_emit_method_call_spilled (cfg, bblock, managed_alloc, mono_method_signature (managed_alloc), iargs, ip, this);
3334 static MonoMethodSignature *
3335 mono_get_array_new_va_signature (int arity)
3337 static GHashTable *sighash = NULL;
3338 MonoMethodSignature *res;
3343 sighash = g_hash_table_new (NULL, NULL);
3345 else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
3350 res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
3353 #ifdef MONO_ARCH_VARARG_ICALLS
3354 /* Only set this only some archs since not all backends can handle varargs+pinvoke */
3355 res->call_convention = MONO_CALL_VARARG;
3358 #ifdef PLATFORM_WIN32
3359 res->call_convention = MONO_CALL_C;
3362 res->params [0] = &mono_defaults.int_class->byval_arg;
3363 for (i = 0; i < arity; i++)
3364 res->params [i + 1] = &mono_defaults.int_class->byval_arg;
3366 res->ret = &mono_defaults.object_class->byval_arg;
3368 g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
3375 mono_get_array_new_va_icall (int rank)
3377 MonoMethodSignature *esig;
3378 char icall_name [256];
3380 MonoJitICallInfo *info;
3382 /* Need to register the icall so it gets an icall wrapper */
3383 sprintf (icall_name, "ves_array_new_va_%d", rank);
3386 info = mono_find_jit_icall_by_name (icall_name);
3388 esig = mono_get_array_new_va_signature (rank);
3389 name = g_strdup (icall_name);
3390 info = mono_register_jit_icall (mono_array_new_va, name, esig, FALSE);
3392 g_hash_table_insert (jit_icall_name_hash, name, name);
3400 get_memcpy_method (void)
3402 static MonoMethod *memcpy_method = NULL;
3403 if (!memcpy_method) {
3404 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3406 g_error ("Old corlib found. Install a new one");
3408 return memcpy_method;
3412 handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native, gboolean write_barrier) {
3413 MonoInst *iargs [3];
3416 MonoMethod *memcpy_method;
3420 * This check breaks with spilled vars... need to handle it during verification anyway.
3421 * g_assert (klass && klass == src->klass && klass == dest->klass);
3425 n = mono_class_native_size (klass, &align);
3427 n = mono_class_value_size (klass, &align);
3429 #if HAVE_WRITE_BARRIERS
3430 /* if native is true there should be no references in the struct */
3431 if (write_barrier && klass->has_references && !native) {
3434 NEW_PCONST (cfg, iargs [2], klass);
3436 mono_emit_jit_icall (cfg, bblock, mono_value_copy, iargs, ip);
3441 /* FIXME: add write barrier handling */
3442 if ((cfg->opt & MONO_OPT_INTRINS) && !to_end && n <= sizeof (gpointer) * 5) {
3444 if (dest->opcode == OP_LDADDR) {
3445 /* Keep liveness info correct */
3446 NEW_DUMMY_STORE (cfg, inst, dest->inst_i0->inst_c0);
3447 MONO_ADD_INS (bblock, inst);
3449 NEW_MEMCPY (cfg, inst, dest, src, n, align);
3450 MONO_ADD_INS (bblock, inst);
3455 NEW_ICONST (cfg, iargs [2], n);
3457 memcpy_method = get_memcpy_method ();
3458 mono_emit_method_call_spilled_full (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL, FALSE, to_end);
3462 get_memset_method (void)
3464 static MonoMethod *memset_method = NULL;
3465 if (!memset_method) {
3466 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3468 g_error ("Old corlib found. Install a new one");
3470 return memset_method;
3474 handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const guchar *ip, MonoClass *klass, MonoInst **stack_start, MonoInst **sp)
3476 MonoInst *iargs [3];
3477 MonoInst *ins, *zero_int32;
3480 MonoMethod *memset_method;
3482 NEW_ICONST (cfg, zero_int32, 0);
3484 mono_class_init (klass);
3485 n = mono_class_value_size (klass, &align);
3486 MONO_INST_NEW (cfg, ins, 0);
3488 ins->inst_left = dest;
3489 ins->inst_right = zero_int32;
3491 ins->opcode = CEE_STIND_I1;
3492 MONO_ADD_INS (bblock, ins);
3493 } else if ((n == 2) && (align >= 2)) {
3494 ins->opcode = CEE_STIND_I2;
3495 MONO_ADD_INS (bblock, ins);
3496 } else if ((n == 2) && (align >= 4)) {
3497 ins->opcode = CEE_STIND_I4;
3498 MONO_ADD_INS (bblock, ins);
3499 } else if (n <= sizeof (gpointer) * 5) {
3500 NEW_MEMSET (cfg, ins, dest, 0, n, align);
3501 MONO_ADD_INS (bblock, ins);
3503 memset_method = get_memset_method ();
3504 handle_loaded_temps (cfg, bblock, stack_start, sp);
3506 NEW_ICONST (cfg, iargs [1], 0);
3507 NEW_ICONST (cfg, iargs [2], n);
3508 mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
3513 handle_alloc (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, gboolean for_box, const guchar *ip)
3515 MonoInst *iargs [2];
3518 if (cfg->opt & MONO_OPT_SHARED) {
3519 NEW_DOMAINCONST (cfg, iargs [0]);
3520 NEW_CLASSCONST (cfg, iargs [1], klass);
3522 alloc_ftn = mono_object_new;
3523 } else if (cfg->compile_aot && bblock->out_of_line && klass->type_token && klass->image == mono_defaults.corlib) {
3524 /* This happens often in argument checking code, eg. throw new FooException... */
3525 /* Avoid relocations by calling a helper function specialized to mscorlib */
3526 NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
3527 return mono_emit_jit_icall (cfg, bblock, mono_helper_newobj_mscorlib, iargs, ip);
3529 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3530 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
3533 if (managed_alloc) {
3534 NEW_VTABLECONST (cfg, iargs [0], vtable);
3535 return mono_emit_method_call_spilled (cfg, bblock, managed_alloc, mono_method_signature (managed_alloc), iargs, ip, NULL);
3537 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
3539 guint32 lw = vtable->klass->instance_size;
3540 lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
3541 NEW_ICONST (cfg, iargs [0], lw);
3542 NEW_VTABLECONST (cfg, iargs [1], vtable);
3545 NEW_VTABLECONST (cfg, iargs [0], vtable);
3548 return mono_emit_jit_icall (cfg, bblock, alloc_ftn, iargs, ip);
3552 handle_alloc_from_inst (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, MonoInst *data_inst,
3553 gboolean for_box, const guchar *ip)
3555 MonoInst *iargs [2];
3556 MonoMethod *managed_alloc = NULL;
3559 FIXME: we cannot get managed_alloc here because we can't get
3560 the class's vtable (because it's not a closed class)
3562 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3563 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
3566 if (cfg->opt & MONO_OPT_SHARED) {
3567 NEW_DOMAINCONST (cfg, iargs [0]);
3568 iargs [1] = data_inst;
3569 alloc_ftn = mono_object_new;
3571 g_assert (!cfg->compile_aot);
3573 if (managed_alloc) {
3574 iargs [0] = data_inst;
3575 return mono_emit_method_call_spilled (cfg, bblock, managed_alloc,
3576 mono_method_signature (managed_alloc), iargs, ip, NULL);
3579 iargs [0] = data_inst;
3580 alloc_ftn = mono_object_new_specific;
3583 return mono_emit_jit_icall (cfg, bblock, alloc_ftn, iargs, ip);
3587 handle_box_copy (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass, int temp)
3589 MonoInst *dest, *vtoffset, *add, *vstore;
3591 NEW_TEMPLOAD (cfg, dest, temp);
3592 NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
3593 MONO_INST_NEW (cfg, add, OP_PADD);
3594 add->inst_left = dest;
3595 add->inst_right = vtoffset;
3598 MONO_INST_NEW (cfg, vstore, CEE_STIND_I);
3599 vstore->opcode = mini_type_to_stind (cfg, &klass->byval_arg);
3600 vstore->cil_code = ip;
3601 vstore->inst_left = add;
3602 vstore->inst_right = val;
3604 #ifdef MONO_ARCH_SOFT_FLOAT
3605 if (vstore->opcode == CEE_STIND_R4) {
3606 handle_store_float (cfg, bblock, add, val, ip);
3609 if (vstore->opcode == CEE_STOBJ) {
3610 handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE, TRUE);
3612 MONO_ADD_INS (bblock, vstore);
3614 NEW_TEMPLOAD (cfg, dest, temp);
3619 handle_box (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass)
3624 if (mono_class_is_nullable (klass)) {
3625 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
3626 temp = mono_emit_method_call_spilled (cfg, bblock, method, mono_method_signature (method), &val, ip, NULL);
3627 NEW_TEMPLOAD (cfg, dest, temp);
3631 temp = handle_alloc (cfg, bblock, klass, TRUE, ip);
3633 return handle_box_copy (cfg, bblock, val, ip, klass, temp);
3637 handle_box_from_inst (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip,
3638 MonoClass *klass, MonoInst *data_inst)
3642 g_assert (!mono_class_is_nullable (klass));
3644 temp = handle_alloc_from_inst (cfg, bblock, klass, data_inst, TRUE, ip);
3646 return handle_box_copy (cfg, bblock, val, ip, klass, temp);
3650 handle_delegate_ctor (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, MonoInst *target, MonoMethod *method, unsigned char *ip)
3652 gpointer *trampoline;
3653 MonoInst *obj, *ins, *store, *offset_ins, *method_ins, *tramp_ins;
3656 temp = handle_alloc (cfg, bblock, klass, FALSE, ip);
3658 /* Inline the contents of mono_delegate_ctor */
3660 /* Set target field */
3661 /* Optimize away setting of NULL target */
3662 if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
3663 NEW_TEMPLOAD (cfg, obj, temp);
3664 NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, target));
3665 MONO_INST_NEW (cfg, ins, OP_PADD);
3666 ins->inst_left = obj;
3667 ins->inst_right = offset_ins;
3669 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
3670 store->inst_left = ins;
3671 store->inst_right = target;
3672 mono_bblock_add_inst (bblock, store);
3675 /* Set method field */
3676 NEW_TEMPLOAD (cfg, obj, temp);
3677 NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, method));
3678 MONO_INST_NEW (cfg, ins, OP_PADD);
3679 ins->inst_left = obj;
3680 ins->inst_right = offset_ins;
3682 NEW_METHODCONST (cfg, method_ins, method);
3684 MONO_INST_NEW (cfg, store, CEE_STIND_I);
3685 store->inst_left = ins;
3686 store->inst_right = method_ins;
3687 mono_bblock_add_inst (bblock, store);
3689 /* Set invoke_impl field */
3690 NEW_TEMPLOAD (cfg, obj, temp);
3691 NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, invoke_impl));
3692 MONO_INST_NEW (cfg, ins, OP_PADD);
3693 ins->inst_left = obj;
3694 ins->inst_right = offset_ins;
3696 trampoline = mono_create_delegate_trampoline (klass);
3697 NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_ABS, trampoline);
3699 MONO_INST_NEW (cfg, store, CEE_STIND_I);
3700 store->inst_left = ins;
3701 store->inst_right = tramp_ins;
3702 mono_bblock_add_inst (bblock, store);
3704 /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
3706 NEW_TEMPLOAD (cfg, obj, temp);
3712 handle_array_new (MonoCompile *cfg, MonoBasicBlock *bblock, int rank, MonoInst **sp, unsigned char *ip)
3714 MonoJitICallInfo *info;
3716 info = mono_get_array_new_va_icall (rank);
3718 cfg->flags |= MONO_CFG_HAS_VARARGS;
3720 /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
3721 return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, TRUE, FALSE);
3725 mono_emit_load_got_addr (MonoCompile *cfg)
3727 MonoInst *load, *store, *dummy_use;
3730 if (!cfg->got_var || cfg->got_var_allocated)
3733 MONO_INST_NEW (cfg, get_got, OP_LOAD_GOTADDR);
3734 NEW_TEMPSTORE (cfg, store, cfg->got_var->inst_c0, get_got);
3736 /* Add it to the start of the first bblock */
3737 if (cfg->bb_entry->code) {
3738 store->next = cfg->bb_entry->code;
3739 cfg->bb_entry->code = store;
3742 MONO_ADD_INS (cfg->bb_entry, store);
3744 cfg->got_var_allocated = TRUE;
3747 * Add a dummy use to keep the got_var alive, since real uses might
3748 * only be generated in the decompose or instruction selection phases.
3749 * Add it to end_bblock, so the variable's lifetime covers the whole
3752 NEW_TEMPLOAD (cfg, load, cfg->got_var->inst_c0);
3753 NEW_DUMMY_USE (cfg, dummy_use, load);
3754 MONO_ADD_INS (cfg->bb_exit, dummy_use);
3757 #define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
3760 mini_class_is_system_array (MonoClass *klass)
3762 if (klass->parent == mono_defaults.array_class)
3769 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
3771 MonoMethodHeader *header = mono_method_get_header (method);
3772 MonoMethodSignature *signature = mono_method_signature (method);
3776 if (cfg->generic_sharing_context)
3779 if (method->inline_failure)
3782 #ifdef MONO_ARCH_HAVE_LMF_OPS
3783 if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3784 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
3785 !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
3789 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
3790 (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3791 (method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
3792 (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
3793 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
3794 (method->klass->marshalbyref) ||
3795 !header || header->num_clauses ||
3796 /* fixme: why cant we inline valuetype returns? */
3797 MONO_TYPE_ISSTRUCT (signature->ret))
3800 #ifdef MONO_ARCH_SOFT_FLOAT
3801 /* this complicates things, fix later */
3802 if (signature->ret->type == MONO_TYPE_R4)
3805 /* its not worth to inline methods with valuetype arguments?? */
3806 for (i = 0; i < signature->param_count; i++) {
3807 if (MONO_TYPE_ISSTRUCT (signature->params [i])) {
3810 #ifdef MONO_ARCH_SOFT_FLOAT
3811 /* this complicates things, fix later */
3812 if (!signature->params [i]->byref && signature->params [i]->type == MONO_TYPE_R4)
3817 /* also consider num_locals? */
3818 /* Do the size check early to avoid creating vtables */
3819 if (getenv ("MONO_INLINELIMIT")) {
3820 if (header->code_size >= atoi (getenv ("MONO_INLINELIMIT"))) {
3823 } else if (header->code_size >= INLINE_LENGTH_LIMIT)
3827 * if we can initialize the class of the method right away, we do,
3828 * otherwise we don't allow inlining if the class needs initialization,
3829 * since it would mean inserting a call to mono_runtime_class_init()
3830 * inside the inlined code
3832 if (!(cfg->opt & MONO_OPT_SHARED)) {
3833 if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
3834 if (cfg->run_cctors && method->klass->has_cctor) {
3835 if (!method->klass->runtime_info)
3836 /* No vtable created yet */
3838 vtable = mono_class_vtable (cfg->domain, method->klass);
3841 /* This makes so that inline cannot trigger */
3842 /* .cctors: too many apps depend on them */
3843 /* running with a specific order... */
3844 if (! vtable->initialized)
3846 mono_runtime_class_init (vtable);
3848 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
3849 if (!method->klass->runtime_info)
3850 /* No vtable created yet */
3852 vtable = mono_class_vtable (cfg->domain, method->klass);
3855 if (!vtable->initialized)
3860 * If we're compiling for shared code
3861 * the cctor will need to be run at aot method load time, for example,
3862 * or at the end of the compilation of the inlining method.
3864 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
3867 //if (!MONO_TYPE_IS_VOID (signature->ret)) return FALSE;
3870 * CAS - do not inline methods with declarative security
3871 * Note: this has to be before any possible return TRUE;
3873 if (mono_method_has_declsec (method))
3880 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoVTable *vtable)
3882 if (vtable->initialized && !cfg->compile_aot)
3885 if (vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
3888 if (!mono_class_needs_cctor_run (vtable->klass, method))
3891 if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (vtable->klass == method->klass))
3892 /* The initialization is already done before the method is called */
3899 mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
3903 MonoMethod *addr_method;
3906 rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
3909 MONO_INST_NEW (cfg, addr, CEE_LDELEMA);
3910 addr->inst_left = sp [0];
3911 addr->inst_right = sp [1];
3912 addr->type = STACK_MP;
3913 addr->klass = cmethod->klass->element_class;
3917 if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
3918 #if defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(MONO_ARCH_NO_EMULATE_MUL)
3919 /* OP_LDELEMA2D depends on OP_LMUL */
3922 NEW_GROUP (cfg, indexes, sp [1], sp [2]);
3923 MONO_INST_NEW (cfg, addr, OP_LDELEMA2D);
3924 addr->inst_left = sp [0];
3925 addr->inst_right = indexes;
3926 addr->type = STACK_MP;
3927 addr->klass = cmethod->klass->element_class;
3932 element_size = mono_class_array_element_size (cmethod->klass->element_class);
3933 addr_method = mono_marshal_get_array_address (rank, element_size);
3934 temp = mono_emit_method_call_spilled (cfg, bblock, addr_method, addr_method->signature, sp, ip, NULL);
3935 NEW_TEMPLOAD (cfg, addr, temp);
3940 static MonoJitICallInfo **emul_opcode_map = NULL;
3943 mono_find_jit_opcode_emulation (int opcode)
3945 g_assert (opcode >= 0 && opcode <= OP_LAST);
3946 if (emul_opcode_map)
3947 return emul_opcode_map [opcode];
3953 mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3955 MonoInst *ins = NULL;
3957 static MonoClass *runtime_helpers_class = NULL;
3958 if (! runtime_helpers_class)
3959 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
3960 "System.Runtime.CompilerServices", "RuntimeHelpers");
3962 if (cmethod->klass == mono_defaults.string_class) {
3963 if (strcmp (cmethod->name, "get_Chars") == 0) {
3964 MONO_INST_NEW (cfg, ins, OP_GETCHR);
3965 ins->inst_i0 = args [0];
3966 ins->inst_i1 = args [1];
3968 } else if (strcmp (cmethod->name, "get_Length") == 0) {
3969 MONO_INST_NEW (cfg, ins, OP_STRLEN);
3970 ins->inst_i0 = args [0];
3972 } else if (strcmp (cmethod->name, "InternalSetChar") == 0) {
3974 MONO_INST_NEW (cfg, get_addr, OP_STR_CHAR_ADDR);
3975 get_addr->inst_i0 = args [0];
3976 get_addr->inst_i1 = args [1];
3977 MONO_INST_NEW (cfg, ins, CEE_STIND_I2);
3978 ins->inst_i0 = get_addr;
3979 ins->inst_i1 = args [2];
3983 } else if (cmethod->klass == mono_defaults.object_class) {
3984 if (strcmp (cmethod->name, "GetType") == 0) {
3985 MONO_INST_NEW (cfg, ins, OP_GETTYPE);
3986 ins->inst_i0 = args [0];
3988 /* The OP_GETHASHCODE rule depends on OP_MUL */
3989 #if !defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(HAVE_MOVING_COLLECTOR)
3990 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0) {
3991 MONO_INST_NEW (cfg, ins, OP_GETHASHCODE);
3992 ins->inst_i0 = args [0];
3995 } else if (strcmp (cmethod->name, ".ctor") == 0) {
3996 MONO_INST_NEW (cfg, ins, OP_NOP);
4000 } else if (cmethod->klass == mono_defaults.array_class) {
4001 if (cmethod->name [0] != 'g')
4004 if (strcmp (cmethod->name, "get_Rank") == 0) {
4005 MONO_INST_NEW (cfg, ins, OP_ARRAY_RANK);
4006 ins->inst_i0 = args [0];
4008 } else if (strcmp (cmethod->name, "get_Length") == 0) {
4009 MONO_INST_NEW (cfg, ins, CEE_LDLEN);
4010 ins->inst_i0 = args [0];
4014 } else if (cmethod->klass == runtime_helpers_class) {
4015 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
4016 NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
4020 } else if (cmethod->klass == mono_defaults.thread_class) {
4021 if (strcmp (cmethod->name, "get_CurrentThread") == 0 && (ins = mono_arch_get_thread_intrinsic (cfg)))
4023 if (strcmp (cmethod->name, "MemoryBarrier") == 0) {
4024 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
4027 if (strcmp (cmethod->name, "SpinWait_nop") == 0) {
4028 MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
4031 } else if (mini_class_is_system_array (cmethod->klass) &&
4032 strcmp (cmethod->name, "GetGenericValueImpl") == 0) {
4034 MonoInst *ldelem, *store, *load;
4035 MonoClass *eklass = mono_class_from_mono_type (fsig->params [1]);
4037 n = mini_type_to_stind (cfg, &eklass->byval_arg);
4042 NEW_LDELEMA (cfg, ldelem, sp, eklass);
4043 ldelem->flags |= MONO_INST_NORANGECHECK;
4044 MONO_INST_NEW (cfg, store, n);
4045 MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, &eklass->byval_arg));
4046 type_to_eval_stack_type (cfg, &eklass->byval_arg, load);
4047 load->inst_left = ldelem;
4048 store->inst_left = args [2];
4049 store->inst_right = load;
4051 } else if (cmethod->klass == mono_defaults.math_class) {
4053 * There is general branches code for Min/Max, but it does not work for
4055 * http://everything2.com/?node_id=1051618
4057 } else if (cmethod->klass->image == mono_defaults.corlib &&
4058 (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
4059 (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
4062 #if SIZEOF_VOID_P == 8
4063 if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
4064 /* 64 bit reads are already atomic */
4065 MONO_INST_NEW (cfg, ins, CEE_LDIND_I8);
4066 ins->inst_i0 = args [0];
4070 #ifdef MONO_ARCH_HAVE_ATOMIC_ADD
4071 if (strcmp (cmethod->name, "Increment") == 0) {
4072 MonoInst *ins_iconst;
4075 if (fsig->params [0]->type == MONO_TYPE_I4)
4076 opcode = OP_ATOMIC_ADD_NEW_I4;
4077 else if (fsig->params [0]->type == MONO_TYPE_I8)
4078 opcode = OP_ATOMIC_ADD_NEW_I8;
4080 g_assert_not_reached ();
4082 #if SIZEOF_VOID_P == 4
4083 if (opcode == OP_ATOMIC_ADD_NEW_I8)
4087 MONO_INST_NEW (cfg, ins, opcode);
4088 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
4089 ins_iconst->inst_c0 = 1;
4091 ins->inst_i0 = args [0];
4092 ins->inst_i1 = ins_iconst;
4093 } else if (strcmp (cmethod->name, "Decrement") == 0) {
4094 MonoInst *ins_iconst;
4097 if (fsig->params [0]->type == MONO_TYPE_I4)
4098 opcode = OP_ATOMIC_ADD_NEW_I4;
4099 else if (fsig->params [0]->type == MONO_TYPE_I8)
4100 opcode = OP_ATOMIC_ADD_NEW_I8;
4102 g_assert_not_reached ();
4104 #if SIZEOF_VOID_P == 4
4105 if (opcode == OP_ATOMIC_ADD_NEW_I8)
4109 MONO_INST_NEW (cfg, ins, opcode);
4110 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
4111 ins_iconst->inst_c0 = -1;
4113 ins->inst_i0 = args [0];
4114 ins->inst_i1 = ins_iconst;
4115 } else if (strcmp (cmethod->name, "Add") == 0) {
4118 if (fsig->params [0]->type == MONO_TYPE_I4)
4119 opcode = OP_ATOMIC_ADD_NEW_I4;
4120 else if (fsig->params [0]->type == MONO_TYPE_I8)
4121 opcode = OP_ATOMIC_ADD_NEW_I8;
4123 g_assert_not_reached ();
4125 #if SIZEOF_VOID_P == 4
4126 if (opcode == OP_ATOMIC_ADD_NEW_I8)
4130 MONO_INST_NEW (cfg, ins, opcode);
4132 ins->inst_i0 = args [0];
4133 ins->inst_i1 = args [1];
4135 #endif /* MONO_ARCH_HAVE_ATOMIC_ADD */
4137 #ifdef MONO_ARCH_HAVE_ATOMIC_EXCHANGE
4138 if (strcmp (cmethod->name, "Exchange") == 0) {
4141 if (fsig->params [0]->type == MONO_TYPE_I4)
4142 opcode = OP_ATOMIC_EXCHANGE_I4;
4143 #if SIZEOF_VOID_P == 8
4144 else if ((fsig->params [0]->type == MONO_TYPE_I8) ||
4145 (fsig->params [0]->type == MONO_TYPE_I) ||
4146 (fsig->params [0]->type == MONO_TYPE_OBJECT))
4147 opcode = OP_ATOMIC_EXCHANGE_I8;
4149 else if ((fsig->params [0]->type == MONO_TYPE_I) ||
4150 (fsig->params [0]->type == MONO_TYPE_OBJECT))
4151 opcode = OP_ATOMIC_EXCHANGE_I4;
4156 #if SIZEOF_VOID_P == 4
4157 if (opcode == OP_ATOMIC_EXCHANGE_I8)
4161 MONO_INST_NEW (cfg, ins, opcode);
4163 ins->inst_i0 = args [0];
4164 ins->inst_i1 = args [1];
4166 #endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
4168 #ifdef MONO_ARCH_HAVE_ATOMIC_CAS_IMM
4170 * Can't implement CompareExchange methods this way since they have
4171 * three arguments. We can implement one of the common cases, where the new
4172 * value is a constant.
4174 if ((strcmp (cmethod->name, "CompareExchange") == 0)) {
4175 if (fsig->params [1]->type == MONO_TYPE_I4 && args [2]->opcode == OP_ICONST) {
4176 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_IMM_I4);
4177 ins->inst_i0 = args [0];
4178 ins->inst_i1 = args [1];
4179 ins->backend.data = GINT_TO_POINTER (args [2]->inst_c0);
4181 /* The I8 case is hard to detect, since the arg might be a conv.i8 (iconst) tree */
4183 #endif /* MONO_ARCH_HAVE_ATOMIC_CAS_IMM */
4187 } else if (cmethod->klass->image == mono_defaults.corlib) {
4188 if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
4189 && strcmp (cmethod->klass->name, "Debugger") == 0) {
4190 MONO_INST_NEW (cfg, ins, OP_BREAK);
4193 if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
4194 && strcmp (cmethod->klass->name, "Environment") == 0) {
4195 #ifdef PLATFORM_WIN32
4196 NEW_ICONST (cfg, ins, 1);
4198 NEW_ICONST (cfg, ins, 0);
4204 return mono_arch_get_inst_for_method (cfg, cmethod, fsig, args);
4208 mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, MonoInst **sp, MonoInst **args)
4210 MonoInst *store, *temp;
4213 g_assert (!MONO_TYPE_ISSTRUCT (sig->ret));
4215 if (!sig->hasthis && sig->param_count == 0)
4219 if (sp [0]->opcode == OP_ICONST) {
4222 temp = mono_compile_create_var (cfg, type_from_stack_type (*sp), OP_LOCAL);
4224 NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
4225 /* FIXME: handle CEE_STIND_R4 */
4226 store->cil_code = sp [0]->cil_code;
4227 MONO_ADD_INS (bblock, store);
4232 for (i = 0; i < sig->param_count; ++i) {
4233 if (sp [0]->opcode == OP_ICONST) {
4236 temp = mono_compile_create_var (cfg, sig->params [i], OP_LOCAL);
4238 NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
4239 store->cil_code = sp [0]->cil_code;
4240 /* FIXME: handle CEE_STIND_R4 */
4241 if (store->opcode == CEE_STOBJ) {
4242 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
4243 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, temp->klass, FALSE, FALSE, FALSE);
4244 #ifdef MONO_ARCH_SOFT_FLOAT
4245 } else if (store->opcode == CEE_STIND_R4) {
4246 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
4247 handle_store_float (cfg, bblock, store, *sp, sp [0]->cil_code);
4250 MONO_ADD_INS (bblock, store);
4256 #define MONO_INLINE_CALLED_LIMITED_METHODS 0
4257 #define MONO_INLINE_CALLER_LIMITED_METHODS 0
4259 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
4261 mono_inline_called_method_name_limit = NULL;
4262 static gboolean check_inline_called_method_name_limit (MonoMethod *called_method) {
4263 char *called_method_name = mono_method_full_name (called_method, TRUE);
4266 if (mono_inline_called_method_name_limit == NULL) {
4267 char *limit_string = getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
4268 if (limit_string != NULL) {
4269 mono_inline_called_method_name_limit = limit_string;
4271 mono_inline_called_method_name_limit = (char *) "";
4275 strncmp_result = strncmp (called_method_name, mono_inline_called_method_name_limit, strlen (mono_inline_called_method_name_limit));
4276 g_free (called_method_name);
4278 //return (strncmp_result <= 0);
4279 return (strncmp_result == 0);
4283 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
4285 mono_inline_caller_method_name_limit = NULL;
4286 static gboolean check_inline_caller_method_name_limit (MonoMethod *caller_method) {
4287 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
4290 if (mono_inline_caller_method_name_limit == NULL) {
4291 char *limit_string = getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
4292 if (limit_string != NULL) {
4293 mono_inline_caller_method_name_limit = limit_string;
4295 mono_inline_caller_method_name_limit = (char *) "";
4299 strncmp_result = strncmp (caller_method_name, mono_inline_caller_method_name_limit, strlen (mono_inline_caller_method_name_limit));
4300 g_free (caller_method_name);
4302 //return (strncmp_result <= 0);
4303 return (strncmp_result == 0);
4308 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoBasicBlock *bblock, MonoInst **sp,
4309 guchar *ip, guint real_offset, GList *dont_inline, MonoBasicBlock **last_b, gboolean inline_allways)
4311 MonoInst *ins, *rvar = NULL;
4312 MonoMethodHeader *cheader;
4313 MonoBasicBlock *ebblock, *sbblock;
4314 int i, costs, new_locals_offset;
4315 MonoMethod *prev_inlined_method;
4316 MonoBasicBlock **prev_cil_offset_to_bb;
4317 unsigned char* prev_cil_start;
4318 guint32 prev_cil_offset_to_bb_len;
4320 g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
4322 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
4323 if ((! inline_allways) && ! check_inline_called_method_name_limit (cmethod))
4326 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
4327 if ((! inline_allways) && ! check_inline_caller_method_name_limit (cfg->method))
4331 if (bblock->out_of_line && !inline_allways)
4334 if (cfg->verbose_level > 2)
4335 g_print ("INLINE START %p %s -> %s\n", cmethod, mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
4337 if (!cmethod->inline_info) {
4338 mono_jit_stats.inlineable_methods++;
4339 cmethod->inline_info = 1;
4341 /* allocate space to store the return value */
4342 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
4343 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
4346 /* allocate local variables */
4347 cheader = mono_method_get_header (cmethod);
4348 new_locals_offset = cfg->num_varinfo;
4349 for (i = 0; i < cheader->num_locals; ++i)
4350 mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
4352 /* allocate starte and end blocks */
4353 sbblock = NEW_BBLOCK (cfg);
4354 sbblock->block_num = cfg->num_bblocks++;
4355 sbblock->real_offset = real_offset;
4357 ebblock = NEW_BBLOCK (cfg);
4358 ebblock->block_num = cfg->num_bblocks++;
4359 ebblock->real_offset = real_offset;
4361 prev_inlined_method = cfg->inlined_method;
4362 cfg->inlined_method = cmethod;
4363 prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
4364 prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
4365 prev_cil_start = cfg->cil_start;
4367 costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
4369 cfg->inlined_method = prev_inlined_method;
4370 cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
4371 cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
4372 cfg->cil_start = prev_cil_start;
4374 if ((costs >= 0 && costs < 60) || inline_allways) {
4375 if (cfg->verbose_level > 2)
4376 g_print ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
4378 mono_jit_stats.inlined_methods++;
4380 /* always add some code to avoid block split failures */
4381 MONO_INST_NEW (cfg, ins, OP_NOP);
4382 MONO_ADD_INS (bblock, ins);
4385 bblock->next_bb = sbblock;
4386 link_bblock (cfg, bblock, sbblock);
4389 NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
4390 NEW_TEMPLOAD_SOFT_FLOAT (cfg, ebblock, ins, rvar->inst_c0, ip);
4396 if (cfg->verbose_level > 2)
4397 g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
4398 cfg->exception_type = MONO_EXCEPTION_NONE;
4399 mono_loader_clear_error ();
4400 cmethod->inline_failure = TRUE;
4406 * Some of these comments may well be out-of-date.
4407 * Design decisions: we do a single pass over the IL code (and we do bblock
4408 * splitting/merging in the few cases when it's required: a back jump to an IL
4409 * address that was not already seen as bblock starting point).
4410 * Code is validated as we go (full verification is still better left to metadata/verify.c).
4411 * Complex operations are decomposed in simpler ones right away. We need to let the
4412 * arch-specific code peek and poke inside this process somehow (except when the
4413 * optimizations can take advantage of the full semantic info of coarse opcodes).
4414 * All the opcodes of the form opcode.s are 'normalized' to opcode.
4415 * MonoInst->opcode initially is the IL opcode or some simplification of that
4416 * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific
4417 * opcode with value bigger than OP_LAST.
4418 * At this point the IR can be handed over to an interpreter, a dumb code generator
4419 * or to the optimizing code generator that will translate it to SSA form.
4421 * Profiling directed optimizations.
4422 * We may compile by default with few or no optimizations and instrument the code
4423 * or the user may indicate what methods to optimize the most either in a config file
4424 * or through repeated runs where the compiler applies offline the optimizations to
4425 * each method and then decides if it was worth it.
4429 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
4430 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
4431 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
4432 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
4433 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
4434 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
4435 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
4436 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; goto load_error;}
4438 /* offset from br.s -> br like opcodes */
4439 #define BIG_BRANCH_OFFSET 13
4441 static inline gboolean
4442 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
4444 MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
4446 return b == NULL || b == bb;
4450 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
4452 unsigned char *ip = start;
4453 unsigned char *target;
4456 MonoBasicBlock *bblock;
4457 const MonoOpcode *opcode;
4460 cli_addr = ip - start;
4461 i = mono_opcode_value ((const guint8 **)&ip, end);
4464 opcode = &mono_opcodes [i];
4465 switch (opcode->argument) {
4466 case MonoInlineNone:
4469 case MonoInlineString:
4470 case MonoInlineType:
4471 case MonoInlineField:
4472 case MonoInlineMethod:
4475 case MonoShortInlineR:
4482 case MonoShortInlineVar:
4483 case MonoShortInlineI:
4486 case MonoShortInlineBrTarget:
4487 target = start + cli_addr + 2 + (signed char)ip [1];
4488 GET_BBLOCK (cfg, bblock, target);
4491 GET_BBLOCK (cfg, bblock, ip);
4493 case MonoInlineBrTarget:
4494 target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
4495 GET_BBLOCK (cfg, bblock, target);
4498 GET_BBLOCK (cfg, bblock, ip);
4500 case MonoInlineSwitch: {
4501 guint32 n = read32 (ip + 1);
4504 cli_addr += 5 + 4 * n;
4505 target = start + cli_addr;
4506 GET_BBLOCK (cfg, bblock, target);
4508 for (j = 0; j < n; ++j) {
4509 target = start + cli_addr + (gint32)read32 (ip);
4510 GET_BBLOCK (cfg, bblock, target);
4520 g_assert_not_reached ();
4523 if (i == CEE_THROW) {
4524 unsigned char *bb_start = ip - 1;
4526 /* Find the start of the bblock containing the throw */
4528 while ((bb_start >= start) && !bblock) {
4529 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
4533 bblock->out_of_line = 1;
4543 emit_tree (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ins, const guint8* ip_next)
4545 MonoInst *store, *temp, *load;
4547 if (ip_in_bb (cfg, bblock, ip_next) &&
4548 (CODE_IS_STLOC (ip_next) || *ip_next == CEE_RET))
4551 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
4552 temp->flags |= MONO_INST_IS_TEMP;
4553 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
4554 /* FIXME: handle CEE_STIND_R4 */
4555 store->cil_code = ins->cil_code;
4556 MONO_ADD_INS (bblock, store);
4557 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
4558 load->cil_code = ins->cil_code;
4562 static inline MonoMethod *
4563 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
4567 if (m->wrapper_type != MONO_WRAPPER_NONE)
4568 return mono_method_get_wrapper_data (m, token);
4570 method = mono_get_method_full (m->klass->image, token, klass, context);
4575 static inline MonoMethod *
4576 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
4578 MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
4580 if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
4586 static inline MonoClass*
4587 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
4591 if (method->wrapper_type != MONO_WRAPPER_NONE)
4592 klass = mono_method_get_wrapper_data (method, token);
4594 klass = mono_class_get_full (method->klass->image, token, context);
4596 mono_class_init (klass);
4601 * Returns TRUE if the JIT should abort inlining because "callee"
4602 * is influenced by security attributes.
4605 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee, MonoBasicBlock *bblock, unsigned char *ip)
4609 if ((cfg->method != caller) && mono_method_has_declsec (callee)) {
4613 result = mono_declsec_linkdemand (cfg->domain, caller, callee);
4614 if (result == MONO_JIT_SECURITY_OK)
4617 if (result == MONO_JIT_LINKDEMAND_ECMA) {
4618 /* Generate code to throw a SecurityException before the actual call/link */
4619 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4622 NEW_ICONST (cfg, args [0], 4);
4623 NEW_METHODCONST (cfg, args [1], caller);
4624 mono_emit_method_call_spilled (cfg, bblock, secman->linkdemandsecurityexception, mono_method_signature (secman->linkdemandsecurityexception), args, ip, NULL);
4625 } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
4626 /* don't hide previous results */
4627 cfg->exception_type = MONO_EXCEPTION_SECURITY_LINKDEMAND;
4628 cfg->exception_data = result;
4636 method_access_exception (void)
4638 static MonoMethod *method = NULL;
4641 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4642 method = mono_class_get_method_from_name (secman->securitymanager,
4643 "MethodAccessException", 2);
4650 emit_throw_method_access_exception (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
4651 MonoBasicBlock *bblock, unsigned char *ip)
4653 MonoMethod *thrower = method_access_exception ();
4656 NEW_METHODCONST (cfg, args [0], caller);
4657 NEW_METHODCONST (cfg, args [1], callee);
4658 mono_emit_method_call_spilled (cfg, bblock, thrower,
4659 mono_method_signature (thrower), args, ip, NULL);
4663 verification_exception (void)
4665 static MonoMethod *method = NULL;
4668 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4669 method = mono_class_get_method_from_name (secman->securitymanager,
4670 "VerificationException", 0);
4677 emit_throw_verification_exception (MonoCompile *cfg, MonoBasicBlock *bblock, unsigned char *ip)
4679 MonoMethod *thrower = verification_exception ();
4681 mono_emit_method_call_spilled (cfg, bblock, thrower,
4682 mono_method_signature (thrower),
4687 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
4688 MonoBasicBlock *bblock, unsigned char *ip)
4690 MonoSecurityCoreCLRLevel caller_level = mono_security_core_clr_method_level (caller, TRUE);
4691 MonoSecurityCoreCLRLevel callee_level = mono_security_core_clr_method_level (callee, TRUE);
4692 gboolean is_safe = TRUE;
4694 if (!(caller_level >= callee_level ||
4695 caller_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL ||
4696 callee_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL)) {
4701 emit_throw_method_access_exception (cfg, caller, callee, bblock, ip);
4705 method_is_safe (MonoMethod *method)
4708 if (strcmp (method->name, "unsafeMethod") == 0)
4715 * Check that the IL instructions at ip are the array initialization
4716 * sequence and return the pointer to the data and the size.
4719 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoInst *newarr, int *out_size)
4722 * newarr[System.Int32]
4724 * ldtoken field valuetype ...
4725 * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
4727 if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
4728 MonoClass *klass = newarr->inst_newa_class;
4729 guint32 field_token = read32 (ip + 2);
4730 guint32 field_index = field_token & 0xffffff;
4731 guint32 token = read32 (ip + 7);
4733 const char *data_ptr;
4735 MonoMethod *cmethod;
4736 MonoClass *dummy_class;
4737 MonoClassField *field = mono_field_from_token (method->klass->image, field_token, &dummy_class, NULL);
4743 if (newarr->inst_newa_len->opcode != OP_ICONST)
4745 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
4748 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
4750 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
4751 case MONO_TYPE_BOOLEAN:
4755 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
4756 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
4757 case MONO_TYPE_CHAR:
4767 return NULL; /* stupid ARM FP swapped format */
4776 size *= newarr->inst_newa_len->inst_c0;
4777 if (size > mono_type_size (field->type, &dummy_align))
4780 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
4781 field_index = read32 (ip + 2) & 0xffffff;
4782 mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
4783 data_ptr = mono_image_rva_map (method->klass->image, rva);
4784 /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
4785 /* for aot code we do the lookup on load */
4786 if (aot && data_ptr)
4787 return GUINT_TO_POINTER (rva);
4794 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
4796 char *method_fname = mono_method_full_name (method, TRUE);
4799 if (mono_method_get_header (method)->code_size == 0)
4800 method_code = g_strdup ("method body is empty.");
4802 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
4803 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
4804 cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
4805 g_free (method_fname);
4806 g_free (method_code);
4810 set_exception_object (MonoCompile *cfg, MonoException *exception)
4812 cfg->exception_type = MONO_EXCEPTION_OBJECT_SUPPLIED;
4813 MONO_GC_REGISTER_ROOT (cfg->exception_ptr);
4814 cfg->exception_ptr = exception;
4818 get_runtime_generic_context (MonoCompile *cfg, MonoMethod *method, int context_used, MonoInst *this, unsigned char *ip)
4820 g_assert (cfg->generic_sharing_context);
4822 if (method->klass->valuetype)
4825 if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
4826 MonoInst *mrgctx_loc, *mrgctx_var;
4829 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
4831 mrgctx_loc = mono_get_vtable_var (cfg);
4832 NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
4835 } else if ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype) {
4836 MonoInst *vtable_loc, *vtable_var;
4840 vtable_loc = mono_get_vtable_var (cfg);
4841 NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
4843 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
4844 MonoInst *mrgctx_var = vtable_var;
4846 g_assert (G_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable) == 0);
4848 MONO_INST_NEW (cfg, vtable_var, CEE_LDIND_I);
4849 vtable_var->cil_code = ip;
4850 vtable_var->inst_left = mrgctx_var;
4851 vtable_var->type = STACK_PTR;
4860 MONO_INST_NEW (cfg, vtable, CEE_LDIND_I);
4861 vtable->inst_left = this;
4862 vtable->type = STACK_PTR;
4869 get_runtime_generic_context_other_table_ptr (MonoCompile *cfg, MonoBasicBlock *bblock,
4870 MonoInst *rgc_ptr, guint32 slot, const unsigned char *ip)
4872 MonoMethodSignature *sig = helper_sig_rgctx_lazy_fetch_trampoline;
4873 guint8 *tramp = mono_create_rgctx_lazy_fetch_trampoline (slot);
4877 temp = mono_emit_native_call (cfg, bblock, tramp, sig, &rgc_ptr, ip, FALSE, FALSE);
4879 NEW_TEMPLOAD (cfg, field, temp);
4885 get_runtime_generic_context_ptr (MonoCompile *cfg, MonoMethod *method, int context_used, MonoBasicBlock *bblock,
4886 MonoClass *klass, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type, unsigned char *ip)
4888 guint32 slot = mono_method_lookup_or_register_other_info (method,
4889 context_used & MONO_GENERIC_CONTEXT_USED_METHOD, &klass->byval_arg, rgctx_type, generic_context);
4891 return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
4895 get_runtime_generic_context_method (MonoCompile *cfg, MonoMethod *method, int context_used, MonoBasicBlock *bblock,
4896 MonoMethod *cmethod, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type, const unsigned char *ip)
4898 guint32 slot = mono_method_lookup_or_register_other_info (method,
4899 context_used & MONO_GENERIC_CONTEXT_USED_METHOD, cmethod, rgctx_type, generic_context);
4901 return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
4905 get_runtime_generic_context_field (MonoCompile *cfg, MonoMethod *method, int context_used, MonoBasicBlock *bblock,
4906 MonoClassField *field, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type,
4907 const unsigned char *ip)
4909 guint32 slot = mono_method_lookup_or_register_other_info (method,
4910 context_used & MONO_GENERIC_CONTEXT_USED_METHOD, field, rgctx_type, generic_context);
4912 return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
4916 get_runtime_generic_context_method_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used, MonoBasicBlock *bblock,
4917 MonoMethod *rgctx_method, MonoGenericContext *generic_context, MonoInst *rgctx, const unsigned char *ip)
4919 guint32 slot = mono_method_lookup_or_register_other_info (method,
4920 context_used & MONO_GENERIC_CONTEXT_USED_METHOD, rgctx_method,
4921 MONO_RGCTX_INFO_METHOD_RGCTX, generic_context);
4923 return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
4927 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
4931 if (cfg->generic_sharing_context)
4932 type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, &klass->byval_arg);
4934 type = &klass->byval_arg;
4935 return MONO_TYPE_IS_REFERENCE (type);
4939 * Handles unbox of a Nullable<T>, returning a temp variable where the
4940 * result is stored. If a rgctx is passed, then shared generic code
4944 handle_unbox_nullable (MonoCompile* cfg, MonoMethod *caller_method, int context_used, MonoBasicBlock* bblock,
4945 MonoInst* val, const guchar *ip, MonoClass* klass, MonoGenericContext *generic_context, MonoInst *rgctx)
4947 MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
4948 MonoMethodSignature *signature = mono_method_signature (method);
4951 /* FIXME: What if the class is shared? We might not
4952 have to get the address of the method from the
4954 MonoInst *addr = get_runtime_generic_context_method (cfg, caller_method, context_used, bblock, method,
4955 generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
4957 return mono_emit_rgctx_calli_spilled (cfg, bblock, signature, &val, addr, NULL, ip);
4959 return mono_emit_method_call_spilled (cfg, bblock, method, signature, &val, ip, NULL);
4964 handle_box_nullable_from_inst (MonoCompile *cfg, MonoMethod *caller_method, int context_used, MonoBasicBlock *bblock,
4965 MonoInst *val, const guchar *ip, MonoClass *klass, MonoGenericContext *generic_context, MonoInst *rgctx)
4967 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4968 MonoInst *dest, *method_addr;
4971 g_assert (mono_class_is_nullable (klass));
4973 /* FIXME: What if the class is shared? We might not have to
4974 get the method address from the RGCTX. */
4975 method_addr = get_runtime_generic_context_method (cfg, caller_method, context_used, bblock, method,
4976 generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
4977 temp = mono_emit_rgctx_calli_spilled (cfg, bblock, mono_method_signature (method), &val,
4978 method_addr, NULL, ip);
4979 NEW_TEMPLOAD (cfg, dest, temp);
4984 emit_castclass (MonoClass *klass, guint32 token, int context_used, gboolean inst_is_castclass, MonoCompile *cfg,
4985 MonoMethod *method, MonoInst **arg_array, MonoType **param_types, GList *dont_inline,
4986 unsigned char *end, MonoMethodHeader *header, MonoGenericContext *generic_context,
4987 MonoBasicBlock **_bblock, unsigned char **_ip, MonoInst ***_sp, int *_inline_costs, guint *_real_offset)
4989 MonoBasicBlock *bblock = *_bblock;
4990 unsigned char *ip = *_ip;
4991 MonoInst **sp = *_sp;
4992 int inline_costs = *_inline_costs;
4993 guint real_offset = *_real_offset;
4994 int return_value = 0;
4997 MonoInst *rgctx, *args [2];
5000 g_assert (!method->klass->valuetype);
5006 GET_RGCTX (rgctx, context_used);
5007 args [1] = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
5008 generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
5010 temp = mono_emit_jit_icall (cfg, bblock, mono_object_castclass, args, ip);
5011 NEW_TEMPLOAD (cfg, *sp, temp);
5016 } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5018 MonoMethod *mono_castclass;
5019 MonoInst *iargs [1];
5020 MonoBasicBlock *ebblock;
5024 mono_castclass = mono_marshal_get_castclass (klass);
5027 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock,
5028 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
5030 g_assert (costs > 0);
5035 GET_BBLOCK (cfg, bblock, ip);
5036 ebblock->next_bb = bblock;
5037 link_bblock (cfg, ebblock, bblock);
5039 temp = iargs [0]->inst_i0->inst_c0;
5040 NEW_TEMPLOAD (cfg, *sp, temp);
5044 inline_costs += costs;
5048 /* Needed by the code generated in inssel.brg */
5049 mono_get_got_var (cfg);
5051 MONO_INST_NEW (cfg, ins, CEE_CASTCLASS);
5052 ins->type = STACK_OBJ;
5053 ins->inst_left = *sp;
5055 ins->inst_newa_class = klass;
5056 if (inst_is_castclass)
5057 ins->backend.record_cast_details = debug_options.better_cast_details;
5058 if (inst_is_castclass)
5059 *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
5069 *_inline_costs = inline_costs;
5070 *_real_offset = real_offset;
5071 return return_value;
5078 emit_unbox (MonoClass *klass, guint32 token, int context_used,
5079 MonoCompile *cfg, MonoMethod *method, MonoInst **arg_array, MonoType **param_types, GList *dont_inline,
5080 unsigned char *end, MonoMethodHeader *header, MonoGenericContext *generic_context,
5081 MonoBasicBlock **_bblock, unsigned char **_ip, MonoInst ***_sp, int *_inline_costs, guint *_real_offset)
5083 MonoBasicBlock *bblock = *_bblock;
5084 unsigned char *ip = *_ip;
5085 MonoInst **sp = *_sp;
5086 int inline_costs = *_inline_costs;
5087 guint real_offset = *_real_offset;
5088 int return_value = 0;
5090 MonoInst *add, *vtoffset, *ins;
5092 /* Needed by the code generated in inssel.brg */
5093 mono_get_got_var (cfg);
5096 MonoInst *rgctx, *element_class;
5098 /* This assertion is from the unboxcast insn */
5099 g_assert (klass->rank == 0);
5101 GET_RGCTX (rgctx, context_used);
5102 element_class = get_runtime_generic_context_ptr (cfg, method, context_used, bblock,
5103 klass->element_class, generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
5105 MONO_INST_NEW (cfg, ins, OP_UNBOXCAST_REG);
5106 ins->type = STACK_OBJ;
5107 ins->inst_left = *sp;
5108 ins->inst_right = element_class;
5112 MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
5113 ins->type = STACK_OBJ;
5114 ins->inst_left = *sp;
5116 ins->inst_newa_class = klass;
5120 MONO_INST_NEW (cfg, add, OP_PADD);
5121 NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
5122 add->inst_left = ins;
5123 add->inst_right = vtoffset;
5124 add->type = STACK_MP;
5131 *_inline_costs = inline_costs;
5132 *_real_offset = real_offset;
5133 return return_value;
5137 mini_assembly_can_skip_verification (MonoDomain *domain, MonoMethod *method)
5139 MonoAssembly *assembly = method->klass->image->assembly;
5140 if (method->wrapper_type != MONO_WRAPPER_NONE)
5142 if (assembly->in_gac || assembly->image == mono_defaults.corlib)
5144 if (mono_security_get_mode () != MONO_SECURITY_MODE_NONE)
5146 return mono_assembly_has_skip_verification (assembly);
5150 * mini_method_verify:
5152 * Verify the method using the new verfier.
5154 * Returns true if the method is invalid.
5157 mini_method_verify (MonoCompile *cfg, MonoMethod *method)
5160 gboolean is_fulltrust;
5161 MonoLoaderError *error;
5163 if (method->verification_success)
5166 is_fulltrust = mono_verifier_is_method_full_trust (method);
5168 if (!mono_verifier_is_enabled_for_method (method))
5171 res = mono_method_verify_with_current_settings (method, cfg->skip_visibility);
5173 if ((error = mono_loader_get_last_error ())) {
5174 cfg->exception_type = error->exception_type;
5176 mono_free_verify_list (res);
5181 for (tmp = res; tmp; tmp = tmp->next) {
5182 MonoVerifyInfoExtended *info = (MonoVerifyInfoExtended *)tmp->data;
5183 if (info->info.status == MONO_VERIFY_ERROR) {
5184 cfg->exception_type = info->exception_type;
5185 cfg->exception_message = g_strdup (info->info.message);
5186 mono_free_verify_list (res);
5189 if (info->info.status == MONO_VERIFY_NOT_VERIFIABLE && !is_fulltrust) {
5190 cfg->exception_type = info->exception_type;
5191 cfg->exception_message = g_strdup (info->info.message);
5192 mono_free_verify_list (res);
5196 mono_free_verify_list (res);
5198 method->verification_success = 1;
5203 * mono_method_to_ir: translates IL into basic blocks containing trees
5206 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock,
5207 int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args,
5208 guint inline_offset, gboolean is_virtual_call)
5210 MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
5211 MonoInst *ins, **sp, **stack_start;
5212 MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
5213 MonoMethod *cmethod, *method_definition;
5214 MonoInst **arg_array;
5215 MonoMethodHeader *header;
5217 guint32 token, ins_flag;
5219 MonoClass *constrained_call = NULL;
5220 unsigned char *ip, *end, *target, *err_pos;
5221 static double r8_0 = 0.0;
5222 MonoMethodSignature *sig;
5223 MonoGenericContext *generic_context = NULL;
5224 MonoGenericContainer *generic_container = NULL;
5225 MonoType **param_types;
5226 GList *bb_recheck = NULL, *tmp;
5227 int i, n, start_new_bblock, ialign;
5228 int num_calls = 0, inline_costs = 0;
5229 int breakpoint_id = 0;
5231 guint real_offset, num_args;
5232 MonoBoolean security, pinvoke;
5233 MonoSecurityManager* secman = NULL;
5234 MonoDeclSecurityActions actions;
5235 GSList *class_inits = NULL;
5236 gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
5239 /* serialization and xdomain stuff may need access to private fields and methods */
5240 dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
5241 dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
5242 dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
5243 dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
5244 dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
5245 dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
5247 /* turn off visibility checks for smcs */
5248 dont_verify |= mono_security_get_mode () == MONO_SECURITY_MODE_SMCS_HACK;
5250 /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
5251 dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
5252 dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
5253 dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
5255 image = method->klass->image;
5256 header = mono_method_get_header (method);
5257 generic_container = mono_method_get_generic_container (method);
5258 sig = mono_method_signature (method);
5259 num_args = sig->hasthis + sig->param_count;
5260 ip = (unsigned char*)header->code;
5261 cfg->cil_start = ip;
5262 end = ip + header->code_size;
5263 mono_jit_stats.cil_code_size += header->code_size;
5265 method_definition = method;
5266 while (method_definition->is_inflated) {
5267 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
5268 method_definition = imethod->declaring;
5271 /* SkipVerification is not allowed if core-clr is enabled */
5272 if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
5274 dont_verify_stloc = TRUE;
5277 if (!dont_verify && mini_method_verify (cfg, method_definition))
5278 goto exception_exit;
5280 if (sig->is_inflated)
5281 generic_context = mono_method_get_context (method);
5282 else if (generic_container)
5283 generic_context = &generic_container->context;
5285 if (!cfg->generic_sharing_context)
5286 g_assert (!sig->has_type_parameters);
5288 if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
5289 g_assert (method->is_inflated);
5290 g_assert (mono_method_get_context (method)->method_inst);
5292 if (method->is_inflated && mono_method_get_context (method)->method_inst)
5293 g_assert (sig->generic_param_count);
5295 if (cfg->method == method)
5298 real_offset = inline_offset;
5300 cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
5301 cfg->cil_offset_to_bb_len = header->code_size;
5303 if (cfg->verbose_level > 2)
5304 g_print ("method to IR %s\n", mono_method_full_name (method, TRUE));
5306 dont_inline = g_list_prepend (dont_inline, method);
5307 if (cfg->method == method) {
5309 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
5310 cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
5313 cfg->bb_entry = start_bblock = NEW_BBLOCK (cfg);
5314 start_bblock->cil_code = NULL;
5315 start_bblock->cil_length = 0;
5316 start_bblock->block_num = cfg->num_bblocks++;
5319 cfg->bb_exit = end_bblock = NEW_BBLOCK (cfg);
5320 end_bblock->cil_code = NULL;
5321 end_bblock->cil_length = 0;
5322 end_bblock->block_num = cfg->num_bblocks++;
5323 g_assert (cfg->num_bblocks == 2);
5325 arg_array = alloca (sizeof (MonoInst *) * num_args);
5326 for (i = num_args - 1; i >= 0; i--)
5327 arg_array [i] = cfg->varinfo [i];
5329 if (header->num_clauses) {
5330 cfg->spvars = g_hash_table_new (NULL, NULL);
5331 cfg->exvars = g_hash_table_new (NULL, NULL);
5333 /* handle exception clauses */
5334 for (i = 0; i < header->num_clauses; ++i) {
5335 MonoBasicBlock *try_bb;
5336 MonoExceptionClause *clause = &header->clauses [i];
5338 GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
5339 try_bb->real_offset = clause->try_offset;
5340 GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
5341 tblock->real_offset = clause->handler_offset;
5342 tblock->flags |= BB_EXCEPTION_HANDLER;
5344 link_bblock (cfg, try_bb, tblock);
5346 if (*(ip + clause->handler_offset) == CEE_POP)
5347 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
5349 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
5350 clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
5351 clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
5352 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
5353 MONO_ADD_INS (tblock, ins);
5355 /* todo: is a fault block unsafe to optimize? */
5356 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
5357 tblock->flags |= BB_EXCEPTION_UNSAFE;
5361 /*g_print ("clause try IL_%04x to IL_%04x handler %d at IL_%04x to IL_%04x\n", clause->try_offset, clause->try_offset + clause->try_len, clause->flags, clause->handler_offset, clause->handler_offset + clause->handler_len);
5363 g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
5365 /* catch and filter blocks get the exception object on the stack */
5366 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
5367 clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5368 MonoInst *load, *dummy_use;
5370 /* mostly like handle_stack_args (), but just sets the input args */
5371 /* g_print ("handling clause at IL_%04x\n", clause->handler_offset); */
5372 tblock->in_scount = 1;
5373 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
5374 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
5377 * Add a dummy use for the exvar so its liveness info will be
5380 NEW_TEMPLOAD (cfg, load, tblock->in_stack [0]->inst_c0);
5381 NEW_DUMMY_USE (cfg, dummy_use, load);
5382 MONO_ADD_INS (tblock, dummy_use);
5384 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5385 GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
5386 tblock->real_offset = clause->data.filter_offset;
5387 tblock->in_scount = 1;
5388 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
5389 /* The filter block shares the exvar with the handler block */
5390 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
5391 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
5392 MONO_ADD_INS (tblock, ins);
5396 if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
5397 clause->data.catch_class &&
5398 cfg->generic_sharing_context &&
5399 mono_class_check_context_used (clause->data.catch_class)) {
5400 if (mono_method_get_context (method)->method_inst)
5401 GENERIC_SHARING_FAILURE (CEE_NOP);
5404 * In shared generic code with catch
5405 * clauses containing type variables
5406 * the exception handling code has to
5407 * be able to get to the rgctx.
5408 * Therefore we have to make sure that
5409 * the vtable/mrgctx argument (for
5410 * static or generic methods) or the
5411 * "this" argument (for non-static
5412 * methods) are live.
5414 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
5415 mini_method_get_context (method)->method_inst ||
5416 method->klass->valuetype) {
5417 mono_get_vtable_var (cfg);
5419 MonoInst *this, *dummy_use;
5420 MonoType *this_type;
5422 if (method->klass->valuetype)
5423 this_type = &method->klass->this_arg;
5425 this_type = &method->klass->byval_arg;
5427 if (arg_array [0]->opcode == OP_ICONST) {
5428 this = arg_array [0];
5430 this = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));
5431 this->ssa_op = MONO_SSA_LOAD;
5432 this->inst_i0 = arg_array [0];
5433 this->opcode = mini_type_to_ldind ((cfg), this->inst_i0->inst_vtype);
5434 type_to_eval_stack_type ((cfg), this_type, this);
5435 this->klass = this->inst_i0->klass;
5438 NEW_DUMMY_USE (cfg, dummy_use, this);
5439 MONO_ADD_INS (tblock, dummy_use);
5444 arg_array = alloca (sizeof (MonoInst *) * num_args);
5445 mono_save_args (cfg, start_bblock, sig, inline_args, arg_array);
5448 /* FIRST CODE BLOCK */
5449 bblock = NEW_BBLOCK (cfg);
5450 bblock->cil_code = ip;
5452 ADD_BBLOCK (cfg, bblock);
5454 if (cfg->method == method) {
5455 breakpoint_id = mono_debugger_method_has_breakpoint (method);
5456 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
5457 MONO_INST_NEW (cfg, ins, OP_BREAK);
5458 MONO_ADD_INS (bblock, ins);
5462 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS)
5463 secman = mono_security_manager_get_methods ();
5465 security = (secman && mono_method_has_declsec (method));
5466 /* at this point having security doesn't mean we have any code to generate */
5467 if (security && (cfg->method == method)) {
5468 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
5469 * And we do not want to enter the next section (with allocation) if we
5470 * have nothing to generate */
5471 security = mono_declsec_get_demands (method, &actions);
5474 /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
5475 pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
5477 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
5478 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
5479 MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
5481 /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
5482 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
5486 mono_custom_attrs_free (custom);
5489 custom = mono_custom_attrs_from_class (wrapped->klass);
5490 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
5494 mono_custom_attrs_free (custom);
5497 /* not a P/Invoke after all */
5502 if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot || security || pinvoke) {
5503 /* we use a separate basic block for the initialization code */
5504 cfg->bb_init = init_localsbb = NEW_BBLOCK (cfg);
5505 init_localsbb->real_offset = real_offset;
5506 start_bblock->next_bb = init_localsbb;
5507 init_localsbb->next_bb = bblock;
5508 link_bblock (cfg, start_bblock, init_localsbb);
5509 link_bblock (cfg, init_localsbb, bblock);
5510 init_localsbb->block_num = cfg->num_bblocks++;
5512 start_bblock->next_bb = bblock;
5513 link_bblock (cfg, start_bblock, bblock);
5516 /* at this point we know, if security is TRUE, that some code needs to be generated */
5517 if (security && (cfg->method == method)) {
5520 mono_jit_stats.cas_demand_generation++;
5522 if (actions.demand.blob) {
5523 /* Add code for SecurityAction.Demand */
5524 NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
5525 NEW_ICONST (cfg, args [1], actions.demand.size);
5526 /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
5527 mono_emit_method_call_spilled (cfg, init_localsbb, secman->demand, mono_method_signature (secman->demand), args, ip, NULL);
5529 if (actions.noncasdemand.blob) {
5530 /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
5531 /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
5532 NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
5533 NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
5534 /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
5535 mono_emit_method_call_spilled (cfg, init_localsbb, secman->demand, mono_method_signature (secman->demand), args, ip, NULL);
5537 if (actions.demandchoice.blob) {
5538 /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
5539 NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
5540 NEW_ICONST (cfg, args [1], actions.demandchoice.size);
5541 /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
5542 mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandchoice, mono_method_signature (secman->demandchoice), args, ip, NULL);
5546 /* we must Demand SecurityPermission.Unmanaged before p/invoking */
5548 mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandunmanaged, mono_method_signature (secman->demandunmanaged), NULL, ip, NULL);
5551 if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
5552 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
5553 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
5554 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
5555 if (!(method->klass && method->klass->image &&
5556 mono_security_core_clr_is_platform_image (method->klass->image))) {
5557 emit_throw_method_access_exception (cfg, method, wrapped, bblock, ip);
5561 if (!method_is_safe (method))
5562 emit_throw_verification_exception (cfg, bblock, ip);
5565 if (header->code_size == 0)
5568 if (get_basic_blocks (cfg, header, real_offset, ip, end, &err_pos)) {
5573 if (cfg->method == method)
5574 mono_debug_init_method (cfg, bblock, breakpoint_id);
5576 param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
5578 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
5579 for (n = 0; n < sig->param_count; ++n)
5580 param_types [n + sig->hasthis] = sig->params [n];
5581 for (n = 0; n < header->num_locals; ++n) {
5582 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
5587 /* do this somewhere outside - not here */
5588 NEW_ICONST (cfg, zero_int32, 0);
5589 NEW_ICONST (cfg, zero_int64, 0);
5590 zero_int64->type = STACK_I8;
5591 NEW_PCONST (cfg, zero_ptr, 0);
5592 NEW_PCONST (cfg, zero_obj, 0);
5593 zero_obj->type = STACK_OBJ;
5595 MONO_INST_NEW (cfg, zero_r8, OP_R8CONST);
5596 zero_r8->type = STACK_R8;
5597 zero_r8->inst_p0 = &r8_0;
5599 /* add a check for this != NULL to inlined methods */
5600 if (is_virtual_call) {
5601 MONO_INST_NEW (cfg, ins, OP_CHECK_THIS);
5602 NEW_ARGLOAD (cfg, ins->inst_left, 0);
5604 MONO_ADD_INS (bblock, ins);
5607 /* we use a spare stack slot in SWITCH and NEWOBJ and others */
5608 stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
5611 start_new_bblock = 0;
5614 if (cfg->method == method)
5615 real_offset = ip - header->code;
5617 real_offset = inline_offset;
5622 if (start_new_bblock) {
5623 bblock->cil_length = ip - bblock->cil_code;
5624 if (start_new_bblock == 2) {
5625 g_assert (ip == tblock->cil_code);
5627 GET_BBLOCK (cfg, tblock, ip);
5629 bblock->next_bb = tblock;
5631 start_new_bblock = 0;
5632 for (i = 0; i < bblock->in_scount; ++i) {
5633 if (cfg->verbose_level > 3)
5634 g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);
5635 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
5638 g_slist_free (class_inits);
5641 if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
5642 link_bblock (cfg, bblock, tblock);
5643 if (sp != stack_start) {
5644 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5646 CHECK_UNVERIFIABLE (cfg);
5648 bblock->next_bb = tblock;
5650 for (i = 0; i < bblock->in_scount; ++i) {
5651 if (cfg->verbose_level > 3)
5652 g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);
5653 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
5656 g_slist_free (class_inits);
5661 bblock->real_offset = real_offset;
5663 if ((cfg->method == method) && cfg->coverage_info) {
5664 MonoInst *store, *one;
5665 guint32 cil_offset = ip - header->code;
5666 cfg->coverage_info->data [cil_offset].cil_code = ip;
5668 /* TODO: Use an increment here */
5669 NEW_ICONST (cfg, one, 1);
5672 NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
5675 MONO_INST_NEW (cfg, store, CEE_STIND_I);
5676 store->inst_left = ins;
5677 store->inst_right = one;
5679 MONO_ADD_INS (bblock, store);
5682 if (cfg->verbose_level > 3)
5683 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
5687 MONO_INST_NEW (cfg, ins, OP_NOP);
5689 MONO_ADD_INS (bblock, ins);
5692 MONO_INST_NEW (cfg, ins, OP_BREAK);
5694 MONO_ADD_INS (bblock, ins);
5700 CHECK_STACK_OVF (1);
5701 n = (*ip)-CEE_LDARG_0;
5703 NEW_ARGLOAD (cfg, ins, n);
5704 LDARG_SOFT_FLOAT (cfg, ins, n, ip);
5712 CHECK_STACK_OVF (1);
5713 n = (*ip)-CEE_LDLOC_0;
5715 NEW_LOCLOAD (cfg, ins, n);
5716 LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
5725 n = (*ip)-CEE_STLOC_0;
5728 handle_loaded_temps (cfg, bblock, stack_start, sp);
5729 NEW_LOCSTORE (cfg, ins, n, *sp);
5730 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
5732 STLOC_SOFT_FLOAT (cfg, ins, n, ip);
5733 if (ins->opcode == CEE_STOBJ) {
5734 NEW_LOCLOADA (cfg, ins, n);
5735 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
5737 MONO_ADD_INS (bblock, ins);
5743 CHECK_STACK_OVF (1);
5745 NEW_ARGLOAD (cfg, ins, ip [1]);
5746 LDARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
5752 CHECK_STACK_OVF (1);
5754 NEW_ARGLOADA (cfg, ins, ip [1]);
5763 NEW_ARGSTORE (cfg, ins, ip [1], *sp);
5764 handle_loaded_temps (cfg, bblock, stack_start, sp);
5765 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
5767 STARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
5768 if (ins->opcode == CEE_STOBJ) {
5769 NEW_ARGLOADA (cfg, ins, ip [1]);
5770 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
5772 MONO_ADD_INS (bblock, ins);
5777 CHECK_STACK_OVF (1);
5778 CHECK_LOCAL (ip [1]);
5779 NEW_LOCLOAD (cfg, ins, ip [1]);
5780 LDLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
5786 CHECK_STACK_OVF (1);
5787 CHECK_LOCAL (ip [1]);
5788 NEW_LOCLOADA (cfg, ins, ip [1]);
5796 handle_loaded_temps (cfg, bblock, stack_start, sp);
5797 CHECK_LOCAL (ip [1]);
5798 NEW_LOCSTORE (cfg, ins, ip [1], *sp);
5799 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
5801 STLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
5802 if (ins->opcode == CEE_STOBJ) {
5803 NEW_LOCLOADA (cfg, ins, ip [1]);
5804 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
5806 MONO_ADD_INS (bblock, ins);
5811 CHECK_STACK_OVF (1);
5812 NEW_PCONST (cfg, ins, NULL);
5813 ins->type = STACK_OBJ;
5818 CHECK_STACK_OVF (1);
5819 NEW_ICONST (cfg, ins, -1);
5832 CHECK_STACK_OVF (1);
5833 NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
5839 CHECK_STACK_OVF (1);
5841 NEW_ICONST (cfg, ins, *((signed char*)ip));
5847 CHECK_STACK_OVF (1);
5848 NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
5854 CHECK_STACK_OVF (1);
5855 MONO_INST_NEW (cfg, ins, OP_I8CONST);
5856 ins->type = STACK_I8;
5858 ins->inst_l = (gint64)read64 (ip);
5864 /* we should really allocate this only late in the compilation process */
5865 mono_domain_lock (cfg->domain);
5866 f = mono_domain_alloc (cfg->domain, sizeof (float));
5867 mono_domain_unlock (cfg->domain);
5869 CHECK_STACK_OVF (1);
5870 MONO_INST_NEW (cfg, ins, OP_R4CONST);
5871 ins->type = STACK_R8;
5882 mono_domain_lock (cfg->domain);
5883 d = mono_domain_alloc (cfg->domain, sizeof (double));
5884 mono_domain_unlock (cfg->domain);
5886 CHECK_STACK_OVF (1);
5887 MONO_INST_NEW (cfg, ins, OP_R8CONST);
5888 ins->type = STACK_R8;
5898 MonoInst *temp, *store;
5900 CHECK_STACK_OVF (1);
5905 * small optimization: if the loaded value was from a local already,
5906 * just load it twice.
5908 if (ins->ssa_op == MONO_SSA_LOAD &&
5909 (ins->inst_i0->opcode == OP_LOCAL || ins->inst_i0->opcode == OP_ARG)) {
5911 MONO_INST_NEW (cfg, temp, 0);
5915 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
5916 temp->flags |= MONO_INST_IS_TEMP;
5917 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
5918 /* FIXME: handle CEE_STIND_R4 */
5919 if (store->opcode == CEE_STOBJ) {
5920 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
5921 handle_stobj (cfg, bblock, store, sp [0], sp [0]->cil_code, store->klass, TRUE, FALSE, FALSE);
5923 MONO_ADD_INS (bblock, store);
5925 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
5927 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
5936 MONO_INST_NEW (cfg, ins, CEE_POP);
5937 MONO_ADD_INS (bblock, ins);
5944 if (stack_start != sp)
5946 MONO_INST_NEW (cfg, ins, OP_JMP);
5947 token = read32 (ip + 1);
5948 /* FIXME: check the signature matches */
5949 cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
5954 if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
5955 GENERIC_SHARING_FAILURE (CEE_JMP);
5957 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
5958 if (check_linkdemand (cfg, method, cmethod, bblock, ip))
5960 CHECK_CFG_EXCEPTION;
5963 ins->inst_p0 = cmethod;
5964 MONO_ADD_INS (bblock, ins);
5966 start_new_bblock = 1;
5970 case CEE_CALLVIRT: {
5971 MonoInst *addr = NULL;
5972 MonoMethodSignature *fsig = NULL;
5973 int temp, array_rank = 0;
5974 int virtual = *ip == CEE_CALLVIRT;
5976 gboolean pass_imt_from_rgctx = FALSE;
5977 MonoInst *imt_arg = NULL;
5978 gboolean pass_vtable = FALSE;
5979 gboolean pass_mrgctx = FALSE;
5980 MonoInst *vtable_arg = NULL;
5981 gboolean check_this = FALSE;
5984 token = read32 (ip + 1);
5986 if (*ip == CEE_CALLI) {
5991 if (method->wrapper_type != MONO_WRAPPER_NONE)
5992 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
5994 fsig = mono_metadata_parse_signature (image, token);
5996 n = fsig->param_count + fsig->hasthis;
5998 MonoMethod *cil_method;
6000 if (method->wrapper_type != MONO_WRAPPER_NONE) {
6001 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
6002 cil_method = cmethod;
6003 } else if (constrained_call) {
6004 cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
6005 cil_method = cmethod;
6007 cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
6008 cil_method = cmethod;
6013 if (!dont_verify && !cfg->skip_visibility) {
6014 MonoMethod *target_method = cil_method;
6015 if (method->is_inflated) {
6016 target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
6018 if (!mono_method_can_access_method (method_definition, target_method) &&
6019 !mono_method_can_access_method (method, cil_method))
6020 METHOD_ACCESS_FAILURE;
6023 if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
6024 ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
6026 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
6027 /* MS.NET seems to silently convert this to a callvirt */
6030 if (!cmethod->klass->inited){
6031 if (!mono_class_init (cmethod->klass))
6035 if (mono_method_signature (cmethod)->pinvoke) {
6036 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
6037 fsig = mono_method_signature (wrapper);
6038 } else if (constrained_call) {
6039 fsig = mono_method_signature (cmethod);
6041 fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
6044 mono_save_token_info (cfg, image, token, cmethod);
6046 n = fsig->param_count + fsig->hasthis;
6048 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
6049 if (check_linkdemand (cfg, method, cmethod, bblock, ip))
6051 CHECK_CFG_EXCEPTION;
6054 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
6055 mini_class_is_system_array (cmethod->klass)) {
6056 array_rank = cmethod->klass->rank;
6059 if (cmethod->string_ctor)
6060 g_assert_not_reached ();
6064 if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
6067 if (!cfg->generic_sharing_context && cmethod)
6068 g_assert (!mono_method_check_context_used (cmethod));
6072 //g_assert (!virtual || fsig->hasthis);
6076 if (constrained_call) {
6078 * We have the `constrained.' prefix opcode.
6080 if (constrained_call->valuetype && !cmethod->klass->valuetype) {
6083 * The type parameter is instantiated as a valuetype,
6084 * but that type doesn't override the method we're
6085 * calling, so we need to box `this'.
6086 * sp [0] is a pointer to the data: we need the value
6087 * in handle_box (), so load it here.
6089 MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, &constrained_call->byval_arg));
6090 type_to_eval_stack_type (cfg, &constrained_call->byval_arg, load);
6091 load->inst_left = sp [0];
6092 sp [0] = handle_box (cfg, bblock, load, ip, constrained_call);
6093 } else if (!constrained_call->valuetype) {
6097 * The type parameter is instantiated as a reference
6098 * type. We have a managed pointer on the stack, so
6099 * we need to dereference it here.
6102 MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
6103 ins->inst_i0 = sp [0];
6104 ins->type = STACK_OBJ;
6105 ins->klass = mono_class_from_mono_type (&constrained_call->byval_arg);
6107 } else if (cmethod->klass->valuetype)
6109 constrained_call = NULL;
6112 if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
6115 if (cmethod && ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
6116 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
6117 gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
6118 MonoGenericContext *context = mini_class_get_context (cmethod->klass);
6119 gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
6122 * Pass vtable iff target method might
6123 * be shared, which means that sharing
6124 * is enabled for its class and its
6125 * context is sharable (and it's not a
6128 if (sharing_enabled && context_sharable &&
6129 !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
6133 if (cmethod && mini_method_get_context (cmethod) &&
6134 mini_method_get_context (cmethod)->method_inst) {
6135 gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
6136 MonoGenericContext *context = mini_method_get_context (cmethod);
6137 gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
6139 g_assert (!pass_vtable);
6141 if (sharing_enabled && context_sharable)
6145 if (cfg->generic_sharing_context && cmethod) {
6146 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
6148 context_used = mono_method_check_context_used (cmethod);
6150 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
6151 /* Generic method interface
6152 calls are resolved via a
6153 helper function and don't
6155 if (!cmethod_context || !cmethod_context->method_inst)
6156 pass_imt_from_rgctx = TRUE;
6160 * If a shared method calls another
6161 * shared method then the caller must
6162 * have a generic sharing context
6163 * because the magic trampoline
6164 * requires it. FIXME: We shouldn't
6165 * have to force the vtable/mrgctx
6166 * variable here. Instead there
6167 * should be a flag in the cfg to
6168 * request a generic sharing context.
6170 if (context_used && ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
6171 mono_get_vtable_var (cfg);
6178 GET_RGCTX (rgctx, context_used);
6179 vtable_arg = get_runtime_generic_context_ptr (cfg, method, context_used,
6180 bblock, cmethod->klass, generic_context, rgctx, MONO_RGCTX_INFO_VTABLE, ip);
6182 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
6184 CHECK_TYPELOAD (cmethod->klass);
6185 NEW_VTABLECONST (cfg, vtable_arg, vtable);
6190 g_assert (!vtable_arg);
6195 GET_RGCTX (rgctx, context_used);
6196 vtable_arg = get_runtime_generic_context_method_rgctx (cfg, method,
6197 context_used, bblock, cmethod, generic_context, rgctx, ip);
6199 MonoMethodRuntimeGenericContext *mrgctx;
6201 mrgctx = mono_method_lookup_rgctx (mono_class_vtable (cfg->domain, cmethod->klass),
6202 mini_method_get_context (cmethod)->method_inst);
6204 cfg->disable_aot = TRUE;
6205 NEW_PCONST (cfg, vtable_arg, mrgctx);
6208 if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
6209 (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) {
6216 if (pass_imt_from_rgctx) {
6219 g_assert (!pass_vtable);
6222 GET_RGCTX (rgctx, context_used);
6223 imt_arg = get_runtime_generic_context_method (cfg, method, context_used, bblock, cmethod,
6224 generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
6230 MONO_INST_NEW (cfg, check, OP_CHECK_THIS_PASSTHROUGH);
6231 check->cil_code = ip;
6232 check->inst_left = sp [0];
6233 check->type = sp [0]->type;
6237 if (cmethod && virtual &&
6238 (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
6239 !((cmethod->flags & METHOD_ATTRIBUTE_FINAL) &&
6240 cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
6241 mono_method_signature (cmethod)->generic_param_count) {
6242 MonoInst *this_temp, *this_arg_temp, *store;
6243 MonoInst *iargs [4];
6245 g_assert (mono_method_signature (cmethod)->is_inflated);
6246 /* Prevent inlining of methods that contain indirect calls */
6249 this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
6250 NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
6251 MONO_ADD_INS (bblock, store);
6253 /* FIXME: This should be a managed pointer */
6254 this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
6256 /* Because of the PCONST below */
6257 cfg->disable_aot = TRUE;
6258 NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
6262 GET_RGCTX (rgctx, context_used);
6263 iargs [1] = get_runtime_generic_context_method (cfg, method, context_used,
6265 generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
6266 NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
6267 temp = mono_emit_jit_icall (cfg, bblock,
6268 mono_helper_compile_generic_method, iargs, ip);
6270 NEW_METHODCONST (cfg, iargs [1], cmethod);
6271 NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
6272 temp = mono_emit_jit_icall (cfg, bblock, mono_helper_compile_generic_method,
6276 NEW_TEMPLOAD (cfg, addr, temp);
6277 NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
6279 if ((temp = mono_emit_calli_spilled (cfg, bblock, fsig, sp, addr, ip)) != -1) {
6280 NEW_TEMPLOAD (cfg, *sp, temp);
6289 /* FIXME: runtime generic context pointer for jumps? */
6290 /* FIXME: handle this for generic sharing eventually */
6291 if ((ins_flag & MONO_INST_TAILCALL) && !cfg->generic_sharing_context && !vtable_arg && cmethod && (*ip == CEE_CALL) &&
6292 (mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)))) {
6295 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
6297 /* FIXME: This assumes the two methods has the same number and type of arguments */
6299 * We implement tail calls by storing the actual arguments into the
6300 * argument variables, then emitting a OP_JMP. Since the actual arguments
6301 * can refer to the arg variables, we have to spill them.
6303 handle_loaded_temps (cfg, bblock, sp, sp + n);
6304 for (i = 0; i < n; ++i) {
6305 /* Prevent argument from being register allocated */
6306 arg_array [i]->flags |= MONO_INST_VOLATILE;
6308 /* Check if argument is the same */
6310 * FIXME: This loses liveness info, so it can only be done if the
6311 * argument is not register allocated.
6313 NEW_ARGLOAD (cfg, ins, i);
6314 if ((ins->opcode == sp [i]->opcode) && (ins->inst_i0 == sp [i]->inst_i0))
6317 NEW_ARGSTORE (cfg, ins, i, sp [i]);
6318 /* FIXME: handle CEE_STIND_R4 */
6319 if (ins->opcode == CEE_STOBJ) {
6320 NEW_ARGLOADA (cfg, ins, i);
6321 handle_stobj (cfg, bblock, ins, sp [i], sp [i]->cil_code, ins->klass, FALSE, FALSE, FALSE);
6324 MONO_ADD_INS (bblock, ins);
6326 MONO_INST_NEW (cfg, ins, OP_JMP);
6327 ins->inst_p0 = cmethod;
6328 ins->inst_p1 = arg_array [0];
6329 MONO_ADD_INS (bblock, ins);
6330 link_bblock (cfg, bblock, end_bblock);
6331 start_new_bblock = 1;
6332 /* skip CEE_RET as well */
6337 if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_inst_for_method (cfg, cmethod, fsig, sp))) {
6338 if (MONO_TYPE_IS_VOID (fsig->ret)) {
6339 MONO_ADD_INS (bblock, ins);
6341 type_to_eval_stack_type (cfg, fsig->ret, ins);
6351 handle_loaded_temps (cfg, bblock, stack_start, sp);
6353 if ((cfg->opt & MONO_OPT_INLINE) && cmethod && //!check_this &&
6354 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) &&
6355 mono_method_check_inlining (cfg, cmethod) &&
6356 !g_list_find (dont_inline, cmethod)) {
6358 MonoBasicBlock *ebblock;
6359 gboolean allways = FALSE;
6361 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
6362 (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
6363 /* Prevent inlining of methods that call wrappers */
6365 cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
6369 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, allways))) {
6373 GET_BBLOCK (cfg, bblock, ip);
6374 ebblock->next_bb = bblock;
6375 link_bblock (cfg, ebblock, bblock);
6377 if (!MONO_TYPE_IS_VOID (fsig->ret))
6380 /* indicates start of a new block, and triggers a load of all
6381 stack arguments at bb boundarie */
6384 inline_costs += costs;
6390 inline_costs += 10 * num_calls++;
6392 /* tail recursion elimination */
6393 if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET &&
6395 gboolean has_vtargs = FALSE;
6398 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
6400 /* keep it simple */
6401 for (i = fsig->param_count - 1; i >= 0; i--) {
6402 if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i]))
6407 for (i = 0; i < n; ++i) {
6408 /* FIXME: handle CEE_STIND_R4 */
6409 NEW_ARGSTORE (cfg, ins, i, sp [i]);
6410 MONO_ADD_INS (bblock, ins);
6412 MONO_INST_NEW (cfg, ins, OP_BR);
6413 MONO_ADD_INS (bblock, ins);
6414 tblock = start_bblock->out_bb [0];
6415 link_bblock (cfg, bblock, tblock);
6416 ins->inst_target_bb = tblock;
6417 start_new_bblock = 1;
6419 /* skip the CEE_RET, too */
6420 if (ip_in_bb (cfg, bblock, ip + 5))
6429 if (ip_in_bb (cfg, bblock, ip + 5)
6430 && (!MONO_TYPE_ISSTRUCT (fsig->ret))
6431 && (!MONO_TYPE_IS_VOID (fsig->ret) || (cmethod && cmethod->string_ctor))
6432 && (CODE_IS_STLOC (ip + 5) || ip [5] == CEE_POP || ip [5] == CEE_RET))
6433 /* No need to spill */
6438 if (context_used && !imt_arg &&
6439 (!mono_method_is_generic_sharable_impl (cmethod, TRUE) ||
6440 !mono_class_generic_sharing_enabled (cmethod->klass)) &&
6441 (!virtual || cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
6442 !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
6447 g_assert (cfg->generic_sharing_context && cmethod);
6451 * We are compiling a call to
6452 * non-shared generic code from shared
6453 * code, which means that we have to
6454 * look up the method in the rgctx and
6455 * do an indirect call.
6457 GET_RGCTX (rgctx, context_used);
6458 addr = get_runtime_generic_context_method (cfg, method, context_used, bblock, cmethod,
6459 generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
6464 g_assert (!imt_arg);
6466 if (*ip == CEE_CALL) {
6467 g_assert (context_used);
6468 } else if (*ip == CEE_CALLI) {
6469 g_assert (!vtable_arg);
6471 g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
6472 !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
6475 /* Prevent inlining of methods with indirect calls */
6478 ins = (MonoInst*)mono_emit_rgctx_calli (cfg, bblock, fsig, sp, addr, vtable_arg, ip);
6481 temp = mono_emit_rgctx_calli_spilled (cfg, bblock, fsig, sp, addr, vtable_arg, ip);
6483 NEW_TEMPLOAD (cfg, *sp, temp);
6484 NEW_TEMPLOAD_SOFT_FLOAT (cfg, bblock, *sp, temp, ip);
6488 } else if (array_rank) {
6491 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */
6492 if (sp [fsig->param_count]->type == STACK_OBJ) {
6493 MonoInst *iargs [2];
6494 MonoInst *array, *to_store, *store;
6496 handle_loaded_temps (cfg, bblock, stack_start, sp);
6498 array = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
6499 NEW_TEMPSTORE (cfg, store, array->inst_c0, sp [0]);
6500 MONO_ADD_INS (bblock, store);
6501 NEW_TEMPLOAD (cfg, iargs [0], array->inst_c0);
6503 to_store = mono_compile_create_var (cfg, type_from_stack_type (sp [fsig->param_count]), OP_LOCAL);
6504 NEW_TEMPSTORE (cfg, store, to_store->inst_c0, sp [fsig->param_count]);
6505 /* FIXME: handle CEE_STIND_R4 */
6506 MONO_ADD_INS (bblock, store);
6507 NEW_TEMPLOAD (cfg, iargs [1], to_store->inst_c0);
6510 * We first save the args for the call so that the args are copied to the stack
6511 * and a new instruction tree for them is created. If we don't do this,
6512 * the same MonoInst is added to two different trees and this is not
6515 mono_emit_jit_icall (cfg, bblock, mono_helper_stelem_ref_check, iargs, ip);
6517 NEW_TEMPLOAD (cfg, sp [0], array->inst_c0);
6518 NEW_TEMPLOAD (cfg, sp [fsig->param_count], to_store->inst_c0);
6521 addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, TRUE);
6522 NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
6523 /* FIXME: handle CEE_STIND_R4 */
6524 if (ins->opcode == CEE_STOBJ) {
6525 handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE, TRUE);
6527 MONO_ADD_INS (bblock, ins);
6530 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
6531 addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
6532 NEW_INDLOAD (cfg, ins, addr, fsig->ret);
6535 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
6536 if (!cmethod->klass->element_class->valuetype && !readonly) {
6538 //* Needed by the code generated in inssel.brg * /
6539 mono_get_got_var (cfg);
6541 MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
6542 check->klass = cmethod->klass;
6543 check->inst_left = sp [0];
6544 check->type = STACK_OBJ;
6549 addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
6552 g_assert_not_reached ();
6556 /* Prevent inlining of methods which call other methods */
6558 if (mini_redirect_call (&temp, cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL)) {
6560 NEW_TEMPLOAD (cfg, *sp, temp);
6563 } else if (no_spill) {
6564 ins = (MonoInst*)mono_emit_rgctx_method_call (cfg, bblock, cmethod, fsig, sp,
6565 vtable_arg, imt_arg, ip, virtual ? sp [0] : NULL);
6568 if ((temp = mono_emit_rgctx_method_call_spilled (cfg, bblock, cmethod, fsig, sp,
6569 vtable_arg, imt_arg, ip, virtual ? sp [0] : NULL)) != -1) {
6571 NEW_TEMPLOAD (cfg, load, temp);
6573 #ifdef MONO_ARCH_SOFT_FLOAT
6574 if (load->opcode == CEE_LDIND_R4) {
6575 NEW_TEMPLOADA (cfg, load, temp);
6576 temp = handle_load_float (cfg, bblock, load, ip);
6577 NEW_TEMPLOAD (cfg, load, temp);
6590 if (cfg->method != method) {
6591 /* return from inlined method */
6596 //g_assert (returnvar != -1);
6597 NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
6598 store->cil_code = sp [0]->cil_code;
6599 if (store->opcode == CEE_STOBJ) {
6600 g_assert_not_reached ();
6601 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
6602 /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
6603 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, return_var->klass, FALSE, FALSE, FALSE);
6604 #ifdef MONO_ARCH_SOFT_FLOAT
6605 } else if (store->opcode == CEE_STIND_R4) {
6606 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
6607 handle_store_float (cfg, bblock, store, *sp, sp [0]->cil_code);
6610 MONO_ADD_INS (bblock, store);
6614 g_assert (!return_var);
6617 MONO_INST_NEW (cfg, ins, OP_NOP);
6618 ins->opcode = mini_type_to_stind (cfg, mono_method_signature (method)->ret);
6619 if (ins->opcode == CEE_STOBJ) {
6620 NEW_RETLOADA (cfg, ins);
6621 /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
6622 handle_stobj (cfg, bblock, ins, *sp, ip, cfg->ret->klass, FALSE, FALSE, FALSE);
6624 ins->opcode = OP_SETRET;
6625 ins->inst_i0 = *sp;;
6626 ins->inst_i1 = NULL;
6627 MONO_ADD_INS (bblock, ins);
6631 if (sp != stack_start)
6633 MONO_INST_NEW (cfg, ins, OP_BR);
6635 ins->inst_target_bb = end_bblock;
6636 MONO_ADD_INS (bblock, ins);
6637 link_bblock (cfg, bblock, end_bblock);
6638 start_new_bblock = 1;
6642 MONO_INST_NEW (cfg, ins, OP_BR);
6644 MONO_ADD_INS (bblock, ins);
6645 target = ip + 1 + (signed char)(*ip);
6647 GET_BBLOCK (cfg, tblock, target);
6648 link_bblock (cfg, bblock, tblock);
6649 CHECK_BBLOCK (target, ip, tblock);
6650 ins->inst_target_bb = tblock;
6651 if (sp != stack_start) {
6652 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6654 CHECK_UNVERIFIABLE (cfg);
6656 start_new_bblock = 1;
6657 inline_costs += BRANCH_COST;
6663 if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
6665 MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
6667 target = ip + 1 + *(signed char*)ip;
6669 ADD_UNCOND (ins->opcode == CEE_BRTRUE);
6670 if (sp != stack_start) {
6671 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6673 CHECK_UNVERIFIABLE (cfg);
6675 inline_costs += BRANCH_COST;
6689 MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
6691 target = ip + 1 + *(signed char*)ip;
6693 #ifdef MONO_ARCH_SOFT_FLOAT
6694 if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
6695 ins->opcode = condbr_to_fp_br (ins->opcode);
6697 ins->inst_left = sp [0];
6698 ins->inst_right = sp [1];
6699 ins->type = STACK_I4;
6700 *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
6701 MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
6709 if (sp != stack_start) {
6710 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6712 CHECK_UNVERIFIABLE (cfg);
6714 inline_costs += BRANCH_COST;
6718 MONO_INST_NEW (cfg, ins, OP_BR);
6720 MONO_ADD_INS (bblock, ins);
6721 target = ip + 4 + (gint32)read32(ip);
6723 GET_BBLOCK (cfg, tblock, target);
6724 link_bblock (cfg, bblock, tblock);
6725 CHECK_BBLOCK (target, ip, tblock);
6726 ins->inst_target_bb = tblock;
6727 if (sp != stack_start) {
6728 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6730 CHECK_UNVERIFIABLE (cfg);
6732 start_new_bblock = 1;
6733 inline_costs += BRANCH_COST;
6739 if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
6741 MONO_INST_NEW (cfg, ins, *ip);
6743 target = ip + 4 + (gint32)read32(ip);
6745 ADD_UNCOND(ins->opcode == CEE_BRTRUE);
6746 if (sp != stack_start) {
6747 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6749 CHECK_UNVERIFIABLE (cfg);
6751 inline_costs += BRANCH_COST;
6765 MONO_INST_NEW (cfg, ins, *ip);
6767 target = ip + 4 + (gint32)read32(ip);
6769 #ifdef MONO_ARCH_SOFT_FLOAT
6770 if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
6771 ins->opcode = condbr_to_fp_br (ins->opcode);
6773 ins->inst_left = sp [0];
6774 ins->inst_right = sp [1];
6775 ins->type = STACK_I4;
6776 *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
6777 MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
6785 if (sp != stack_start) {
6786 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6788 CHECK_UNVERIFIABLE (cfg);
6790 inline_costs += BRANCH_COST;
6795 n = read32 (ip + 1);
6796 MONO_INST_NEW (cfg, ins, OP_SWITCH);
6798 ins->inst_left = *sp;
6799 if ((ins->inst_left->type != STACK_I4) && (ins->inst_left->type != STACK_PTR))
6802 CHECK_OPSIZE (n * sizeof (guint32));
6803 target = ip + n * sizeof (guint32);
6804 MONO_ADD_INS (bblock, ins);
6805 GET_BBLOCK (cfg, tblock, target);
6806 link_bblock (cfg, bblock, tblock);
6807 ins->klass = GUINT_TO_POINTER (n);
6808 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (n + 1));
6809 ins->inst_many_bb [n] = tblock;
6811 for (i = 0; i < n; ++i) {
6812 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
6813 link_bblock (cfg, bblock, tblock);
6814 ins->inst_many_bb [i] = tblock;
6817 if (sp != stack_start) {
6818 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6820 CHECK_UNVERIFIABLE (cfg);
6822 /* Needed by the code generated in inssel.brg */
6823 mono_get_got_var (cfg);
6824 inline_costs += (BRANCH_COST * 2);
6838 MONO_INST_NEW (cfg, ins, *ip);
6842 ins->type = ldind_type [*ip - CEE_LDIND_I1];
6843 ins->flags |= ins_flag;
6845 if (ins->type == STACK_OBJ)
6846 ins->klass = mono_defaults.object_class;
6847 #ifdef MONO_ARCH_SOFT_FLOAT
6848 if (*ip == CEE_LDIND_R4) {
6851 temp = handle_load_float (cfg, bblock, ins->inst_i0, ip);
6852 NEW_TEMPLOAD (cfg, *sp, temp);
6866 #ifdef MONO_ARCH_SOFT_FLOAT
6867 if (*ip == CEE_STIND_R4) {
6869 handle_store_float (cfg, bblock, sp [0], sp [1], ip);
6874 #if HAVE_WRITE_BARRIERS
6875 if (*ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [-1]->opcode == OP_PCONST) && (sp [-1]->inst_p0 == 0))) {
6876 /* insert call to write barrier */
6877 MonoMethod *write_barrier = mono_marshal_get_write_barrier ();
6879 mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), sp, ip, NULL);
6884 MONO_INST_NEW (cfg, ins, *ip);
6887 handle_loaded_temps (cfg, bblock, stack_start, sp);
6888 MONO_ADD_INS (bblock, ins);
6889 ins->inst_i0 = sp [0];
6890 ins->inst_i1 = sp [1];
6891 ins->flags |= ins_flag;
6899 #ifdef MONO_ARCH_NO_EMULATE_MUL_IMM
6900 /* FIXME: This breaks with ssapre (mono -O=ssapre loader.exe) */
6901 if ((ins->inst_right->opcode == OP_ICONST) && !(cfg->opt & MONO_OPT_SSAPRE)) {
6902 switch (ins->opcode) {
6904 ins->opcode = OP_IMUL_IMM;
6905 ins->inst_imm = ins->inst_right->inst_c0;
6908 ins->opcode = OP_LMUL_IMM;
6909 ins->inst_imm = ins->inst_right->inst_c0;
6912 g_assert_not_reached ();
6917 if (mono_find_jit_opcode_emulation (ins->opcode)) {
6919 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
6937 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
6938 * later apply the speedup to the left shift as well
6941 if ((ins->opcode == OP_LSHR_UN) && (ins->type == STACK_I8)
6942 && (ins->inst_right->opcode == OP_ICONST) && (ins->inst_right->inst_c0 == 32)) {
6943 ins->opcode = OP_LSHR_UN_32;
6944 /*g_print ("applied long shr speedup to %s\n", cfg->method->name);*/
6948 if (mono_find_jit_opcode_emulation (ins->opcode)) {
6950 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
6964 case CEE_CONV_OVF_I8:
6965 case CEE_CONV_OVF_U8:
6970 #ifdef MONO_ARCH_SOFT_FLOAT
6972 * Its rather hard to emit the soft float code during the decompose
6973 * pass, so avoid it in some specific cases.
6975 if (ins->opcode == OP_LCONV_TO_R4) {
6978 ins->opcode = OP_LCONV_TO_R8;
6979 ins->type = STACK_R8;
6982 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
6984 MONO_INST_NEW (cfg, conv, CEE_CONV_R4);
6985 conv->inst_left = sp [-1];
6986 conv->type = STACK_R8;
6994 if (mono_find_jit_opcode_emulation (ins->opcode)) {
6996 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
7000 case CEE_CONV_OVF_I4:
7001 case CEE_CONV_OVF_I1:
7002 case CEE_CONV_OVF_I2:
7003 case CEE_CONV_OVF_I:
7004 case CEE_CONV_OVF_U:
7007 if (sp [-1]->type == STACK_R8) {
7008 ADD_UNOP (CEE_CONV_OVF_I8);
7016 case CEE_CONV_OVF_U1:
7017 case CEE_CONV_OVF_U2:
7018 case CEE_CONV_OVF_U4:
7021 if (sp [-1]->type == STACK_R8) {
7022 ADD_UNOP (CEE_CONV_OVF_U8);
7030 case CEE_CONV_OVF_I1_UN:
7031 case CEE_CONV_OVF_I2_UN:
7032 case CEE_CONV_OVF_I4_UN:
7033 case CEE_CONV_OVF_I8_UN:
7034 case CEE_CONV_OVF_U1_UN:
7035 case CEE_CONV_OVF_U2_UN:
7036 case CEE_CONV_OVF_U4_UN:
7037 case CEE_CONV_OVF_U8_UN:
7038 case CEE_CONV_OVF_I_UN:
7039 case CEE_CONV_OVF_U_UN:
7047 token = read32 (ip + 1);
7048 klass = mini_get_class (method, token, generic_context);
7049 CHECK_TYPELOAD (klass);
7051 if (generic_class_is_reference_type (cfg, klass)) {
7052 MonoInst *store, *load;
7053 MONO_INST_NEW (cfg, load, CEE_LDIND_REF);
7054 load->inst_i0 = sp [1];
7055 load->type = STACK_OBJ;
7056 load->klass = klass;
7057 load->flags |= ins_flag;
7058 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
7059 handle_loaded_temps (cfg, bblock, stack_start, sp);
7060 MONO_ADD_INS (bblock, store);
7061 store->inst_i0 = sp [0];
7062 store->inst_i1 = load;
7063 store->flags |= ins_flag;
7067 n = mono_class_value_size (klass, &align);
7068 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
7070 NEW_MEMCPY (cfg, copy, sp [0], sp [1], n, align);
7071 MONO_ADD_INS (bblock, copy);
7073 MonoMethod *memcpy_method = get_memcpy_method ();
7074 MonoInst *iargs [3];
7077 NEW_ICONST (cfg, iargs [2], n);
7079 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
7086 MonoInst *iargs [3];
7094 token = read32 (ip + 1);
7095 klass = mini_get_class (method, token, generic_context);
7096 CHECK_TYPELOAD (klass);
7097 if (generic_class_is_reference_type (cfg, klass)) {
7098 MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
7099 ins->inst_i0 = sp [0];
7100 ins->type = STACK_OBJ;
7102 ins->flags |= ins_flag;
7109 /* Optimize the common ldobj+stloc combination */
7119 loc_index = ip [5] - CEE_STLOC_0;
7126 if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
7127 CHECK_LOCAL (loc_index);
7128 NEW_LOCSTORE (cfg, ins, loc_index, *sp);
7130 /* FIXME: handle CEE_STIND_R4 */
7131 if (ins->opcode == CEE_STOBJ) {
7132 handle_loaded_temps (cfg, bblock, stack_start, sp);
7133 g_assert (ins->opcode == CEE_STOBJ);
7134 NEW_LOCLOADA (cfg, ins, loc_index);
7135 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
7142 n = mono_class_value_size (klass, &align);
7143 ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
7144 NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
7145 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
7147 NEW_MEMCPY (cfg, copy, iargs [0], *sp, n, align);
7148 MONO_ADD_INS (bblock, copy);
7150 MonoMethod *memcpy_method = get_memcpy_method ();
7152 NEW_ICONST (cfg, iargs [2], n);
7154 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
7156 NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
7164 CHECK_STACK_OVF (1);
7166 n = read32 (ip + 1);
7168 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
7169 /* FIXME: moving GC */
7170 NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
7171 ins->type = STACK_OBJ;
7172 ins->klass = mono_defaults.string_class;
7175 else if (method->wrapper_type != MONO_WRAPPER_NONE) {
7177 MonoInst *iargs [1];
7179 NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));
7180 temp = mono_emit_jit_icall (cfg, bblock, mono_string_new_wrapper, iargs, ip);
7181 NEW_TEMPLOAD (cfg, *sp, temp);
7185 if (cfg->opt & MONO_OPT_SHARED) {
7187 MonoInst *iargs [3];
7188 MonoInst* domain_var;
7190 if (cfg->compile_aot) {
7191 /* FIXME: bug when inlining methods from different assemblies (n is a token valid just in one). */
7192 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
7194 /* avoid depending on undefined C behavior in sequence points */
7195 domain_var = mono_get_domainvar (cfg);
7196 NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
7197 NEW_IMAGECONST (cfg, iargs [1], image);
7198 NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
7199 temp = mono_emit_jit_icall (cfg, bblock, mono_ldstr, iargs, ip);
7200 NEW_TEMPLOAD (cfg, *sp, temp);
7201 mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
7203 if (bblock->out_of_line) {
7204 MonoInst *iargs [2];
7207 if (cfg->method->klass->image == mono_defaults.corlib) {
7209 * Avoid relocations and save some code size by using a
7210 * version of helper_ldstr specialized to mscorlib.
7212 NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
7213 temp = mono_emit_jit_icall (cfg, bblock, mono_helper_ldstr_mscorlib, iargs, ip);
7215 /* Avoid creating the string object */
7216 NEW_IMAGECONST (cfg, iargs [0], image);
7217 NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
7218 temp = mono_emit_jit_icall (cfg, bblock, mono_helper_ldstr, iargs, ip);
7220 NEW_TEMPLOAD (cfg, *sp, temp);
7223 if (cfg->compile_aot) {
7224 NEW_LDSTRCONST (cfg, ins, image, n);
7228 NEW_PCONST (cfg, ins, NULL);
7229 ins->type = STACK_OBJ;
7230 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
7231 ins->klass = mono_defaults.string_class;
7241 MonoInst *iargs [2];
7242 MonoMethodSignature *fsig;
7245 MonoInst *vtable_arg = NULL;
7248 token = read32 (ip + 1);
7249 cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7252 fsig = mono_method_get_signature (cmethod, image, token);
7254 mono_save_token_info (cfg, image, token, cmethod);
7256 if (!mono_class_init (cmethod->klass))
7259 if (cfg->generic_sharing_context)
7260 context_used = mono_method_check_context_used (cmethod);
7262 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
7263 if (check_linkdemand (cfg, method, cmethod, bblock, ip))
7265 CHECK_CFG_EXCEPTION;
7266 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
7267 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
7270 if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7271 mono_method_is_generic_sharable_impl (cmethod, TRUE)) {
7272 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7276 GET_RGCTX (rgctx, context_used);
7277 vtable_arg = get_runtime_generic_context_method_rgctx (cfg, method,
7278 context_used, bblock, cmethod, generic_context, rgctx, ip);
7280 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7281 MonoMethodRuntimeGenericContext *mrgctx;
7283 mrgctx = mono_method_lookup_rgctx (vtable,
7284 mini_method_get_context (cmethod)->method_inst);
7286 NEW_PCONST (cfg, vtable_arg, mrgctx);
7292 GET_RGCTX (rgctx, context_used);
7293 vtable_arg = get_runtime_generic_context_ptr (cfg, method, context_used,
7294 bblock, cmethod->klass, generic_context,
7295 rgctx, MONO_RGCTX_INFO_VTABLE, ip);
7297 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7299 CHECK_TYPELOAD (cmethod->klass);
7300 NEW_VTABLECONST (cfg, vtable_arg, vtable);
7305 n = fsig->param_count;
7309 * Generate smaller code for the common newobj <exception> instruction in
7310 * argument checking code.
7312 if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib && n <= 2 &&
7313 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) &&
7314 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
7315 MonoInst *iargs [3];
7318 g_assert (!vtable_arg);
7322 NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
7325 temp = mono_emit_jit_icall (cfg, bblock, mono_create_corlib_exception_0, iargs, ip);
7329 temp = mono_emit_jit_icall (cfg, bblock, mono_create_corlib_exception_1, iargs, ip);
7334 temp = mono_emit_jit_icall (cfg, bblock, mono_create_corlib_exception_2, iargs, ip);
7337 g_assert_not_reached ();
7339 NEW_TEMPLOAD (cfg, ins, temp);
7347 /* move the args to allow room for 'this' in the first position */
7353 /* check_call_signature () requires sp[0] to be set */
7354 this_ins.type = STACK_OBJ;
7356 if (check_call_signature (cfg, fsig, sp))
7359 handle_loaded_temps (cfg, bblock, stack_start, sp);
7361 if (mini_class_is_system_array (cmethod->klass)) {
7362 g_assert (!context_used);
7363 g_assert (!vtable_arg);
7365 NEW_METHODCONST (cfg, *sp, cmethod);
7367 if (fsig->param_count == 2)
7368 /* Avoid varargs in the common case */
7369 temp = mono_emit_jit_icall (cfg, bblock, mono_array_new_2, sp, ip);
7371 temp = handle_array_new (cfg, bblock, fsig->param_count, sp, ip);
7372 } else if (cmethod->string_ctor) {
7373 g_assert (!context_used);
7374 g_assert (!vtable_arg);
7376 /* we simply pass a null pointer */
7377 NEW_PCONST (cfg, *sp, NULL);
7378 /* now call the string ctor */
7379 temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, NULL);
7381 MonoInst* callvirt_this_arg = NULL;
7383 if (cmethod->klass->valuetype) {
7384 iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
7385 temp = iargs [0]->inst_c0;
7387 NEW_TEMPLOADA (cfg, *sp, temp);
7389 handle_initobj (cfg, bblock, *sp, NULL, cmethod->klass, stack_start, sp);
7391 NEW_TEMPLOADA (cfg, *sp, temp);
7394 * The code generated by mini_emit_virtual_call () expects
7395 * iargs [0] to be a boxed instance, but luckily the vcall
7396 * will be transformed into a normal call there.
7398 } else if (context_used) {
7399 MonoInst *rgctx, *data;
7402 GET_RGCTX (rgctx, context_used);
7403 if (cfg->opt & MONO_OPT_SHARED)
7404 rgctx_info = MONO_RGCTX_INFO_KLASS;
7406 rgctx_info = MONO_RGCTX_INFO_VTABLE;
7407 data = get_runtime_generic_context_ptr (cfg, method, context_used, bblock,
7408 cmethod->klass, generic_context, rgctx, rgctx_info, ip);
7410 temp = handle_alloc_from_inst (cfg, bblock, cmethod->klass, data, FALSE, ip);
7411 NEW_TEMPLOAD (cfg, *sp, temp);
7413 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7415 CHECK_TYPELOAD (cmethod->klass);
7416 if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
7417 guint8 *tramp = mono_create_class_init_trampoline (vtable);
7418 mono_emit_native_call (cfg, bblock, tramp,
7419 helper_sig_class_init_trampoline,
7420 NULL, ip, FALSE, FALSE);
7421 if (cfg->verbose_level > 2)
7422 g_print ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
7423 class_inits = g_slist_prepend (class_inits, vtable);
7425 temp = handle_alloc (cfg, bblock, cmethod->klass, FALSE, ip);
7426 NEW_TEMPLOAD (cfg, *sp, temp);
7429 /* Avoid virtual calls to ctors if possible */
7430 if (cmethod->klass->marshalbyref)
7431 callvirt_this_arg = sp [0];
7433 if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7434 mono_method_check_inlining (cfg, cmethod) &&
7435 !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
7436 !g_list_find (dont_inline, cmethod)) {
7438 MonoBasicBlock *ebblock;
7439 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, FALSE))) {
7444 GET_BBLOCK (cfg, bblock, ip);
7445 ebblock->next_bb = bblock;
7446 link_bblock (cfg, ebblock, bblock);
7448 NEW_TEMPLOAD (cfg, *sp, temp);
7451 /* indicates start of a new block, and triggers a load
7452 of all stack arguments at bb boundarie */
7455 inline_costs += costs;
7459 /* Prevent inlining of methods which call other methods */
7461 mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
7463 } else if (context_used &&
7464 (!mono_method_is_generic_sharable_impl (cmethod, TRUE) ||
7465 !mono_class_generic_sharing_enabled (cmethod->klass))) {
7466 MonoInst *rgctx, *cmethod_addr;
7468 g_assert (!callvirt_this_arg);
7470 GET_RGCTX (rgctx, context_used);
7471 cmethod_addr = get_runtime_generic_context_method (cfg, method, context_used,
7473 generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
7475 mono_emit_rgctx_calli_spilled (cfg, bblock, fsig, sp, cmethod_addr, vtable_arg, ip);
7477 /* Prevent inlining of methods which call other methods */
7479 /* now call the actual ctor */
7480 mono_emit_rgctx_method_call_spilled (cfg, bblock, cmethod, fsig, sp,
7481 vtable_arg, NULL, ip, callvirt_this_arg);
7485 NEW_TEMPLOAD (cfg, *sp, temp);
7496 token = read32 (ip + 1);
7497 klass = mini_get_class (method, token, generic_context);
7498 CHECK_TYPELOAD (klass);
7499 if (sp [0]->type != STACK_OBJ)
7502 if (cfg->generic_sharing_context)
7503 context_used = mono_class_check_context_used (klass);
7505 /* Needed by the code generated in inssel.brg */
7507 mono_get_got_var (cfg);
7510 MonoInst *rgctx, *args [2];
7517 GET_RGCTX (rgctx, context_used);
7518 args [1] = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
7519 generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
7521 temp = mono_emit_jit_icall (cfg, bblock, mono_object_isinst, args, ip);
7522 NEW_TEMPLOAD (cfg, *sp, temp);
7527 } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
7529 MonoMethod *mono_isinst;
7530 MonoInst *iargs [1];
7531 MonoBasicBlock *ebblock;
7535 mono_isinst = mono_marshal_get_isinst (klass);
7538 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), bblock,
7539 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
7541 g_assert (costs > 0);
7546 GET_BBLOCK (cfg, bblock, ip);
7547 ebblock->next_bb = bblock;
7548 link_bblock (cfg, ebblock, bblock);
7550 temp = iargs [0]->inst_i0->inst_c0;
7551 NEW_TEMPLOAD (cfg, *sp, temp);
7555 inline_costs += costs;
7557 MONO_INST_NEW (cfg, ins, *ip);
7558 ins->type = STACK_OBJ;
7559 ins->inst_left = *sp;
7560 ins->inst_newa_class = klass;
7562 *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
7566 case CEE_UNBOX_ANY: {
7567 MonoInst *iargs [3];
7573 token = read32 (ip + 1);
7574 klass = mini_get_class (method, token, generic_context);
7575 CHECK_TYPELOAD (klass);
7577 if (cfg->generic_sharing_context)
7578 context_used = mono_class_check_context_used (klass);
7580 if (generic_class_is_reference_type (cfg, klass)) {
7581 switch (emit_castclass (klass, token, context_used, FALSE,
7582 cfg, method, arg_array, param_types, dont_inline, end, header,
7583 generic_context, &bblock, &ip, &sp, &inline_costs, &real_offset)) {
7585 case -1: goto unverified;
7586 case -2: goto exception_exit;
7587 default: g_assert_not_reached ();
7592 if (mono_class_is_nullable (klass)) {
7594 MonoInst *rgctx = NULL;
7597 GET_RGCTX (rgctx, context_used);
7599 v = handle_unbox_nullable (cfg, method, context_used, bblock, *sp, ip, klass,
7600 generic_context, rgctx);
7601 NEW_TEMPLOAD (cfg, *sp, v);
7607 switch (emit_unbox (klass, token, context_used,
7608 cfg, method, arg_array, param_types, dont_inline, end, header,
7609 generic_context, &bblock, &ip, &sp, &inline_costs, &real_offset)) {
7611 case -1: goto unverified;
7612 case -2: goto exception_exit;
7613 default: g_assert_not_reached ();
7617 n = mono_class_value_size (klass, &align);
7618 ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
7619 NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
7620 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
7622 NEW_MEMCPY (cfg, copy, iargs [0], *sp, n, align);
7623 MONO_ADD_INS (bblock, copy);
7625 MonoMethod *memcpy_method = get_memcpy_method ();
7627 NEW_ICONST (cfg, iargs [2], n);
7629 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
7631 NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
7640 token = read32 (ip + 1);
7641 klass = mini_get_class (method, token, generic_context);
7642 CHECK_TYPELOAD (klass);
7644 if (cfg->generic_sharing_context)
7645 context_used = mono_class_check_context_used (klass);
7647 if (mono_class_is_nullable (klass)) {
7649 MonoInst *rgctx = NULL;
7652 GET_RGCTX (rgctx, context_used);
7653 v = handle_unbox_nullable (cfg, method, context_used, bblock, *sp, ip, klass,
7654 generic_context, rgctx);
7655 NEW_TEMPLOAD (cfg, *sp, v);
7661 switch (emit_unbox (klass, token, context_used,
7662 cfg, method, arg_array, param_types, dont_inline, end, header,
7663 generic_context, &bblock, &ip, &sp, &inline_costs, &real_offset)) {
7665 case -1: goto unverified;
7666 case -2: goto exception_exit;
7667 default: g_assert_not_reached ();
7678 token = read32 (ip + 1);
7679 klass = mini_get_class (method, token, generic_context);
7680 CHECK_TYPELOAD (klass);
7681 if (sp [0]->type != STACK_OBJ)
7684 if (cfg->generic_sharing_context)
7685 context_used = mono_class_check_context_used (klass);
7687 switch (emit_castclass (klass, token, context_used, TRUE,
7688 cfg, method, arg_array, param_types, dont_inline, end, header,
7689 generic_context, &bblock, &ip, &sp, &inline_costs, &real_offset)) {
7691 case -1: goto unverified;
7692 case -2: goto exception_exit;
7693 default: g_assert_not_reached ();
7698 MONO_INST_NEW (cfg, ins, OP_THROW);
7700 ins->inst_left = *sp;
7702 bblock->out_of_line = TRUE;
7703 MONO_ADD_INS (bblock, ins);
7704 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
7705 ins->cil_code = ip - 1;
7706 MONO_ADD_INS (bblock, ins);
7709 link_bblock (cfg, bblock, end_bblock);
7710 start_new_bblock = 1;
7715 MonoInst *offset_ins;
7716 MonoClassField *field;
7717 MonoBasicBlock *ebblock;
7721 if (*ip == CEE_STFLD) {
7728 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
7730 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
7733 token = read32 (ip + 1);
7734 if (method->wrapper_type != MONO_WRAPPER_NONE) {
7735 field = mono_method_get_wrapper_data (method, token);
7736 klass = field->parent;
7738 field = mono_field_from_token (image, token, &klass, generic_context);
7742 mono_class_init (klass);
7743 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
7744 FIELD_ACCESS_FAILURE;
7746 foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
7747 /* FIXME: mark instructions for use in SSA */
7748 if (*ip == CEE_STFLD) {
7749 if (target_type_is_incompatible (cfg, field->type, sp [1]))
7751 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
7752 MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type);
7753 MonoInst *iargs [5];
7756 NEW_CLASSCONST (cfg, iargs [1], klass);
7757 NEW_FIELDCONST (cfg, iargs [2], field);
7758 NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) :
7762 if (cfg->opt & MONO_OPT_INLINE) {
7763 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), bblock,
7764 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
7765 g_assert (costs > 0);
7770 GET_BBLOCK (cfg, bblock, ip);
7771 ebblock->next_bb = bblock;
7772 link_bblock (cfg, ebblock, bblock);
7774 /* indicates start of a new block, and triggers a load
7775 of all stack arguments at bb boundarie */
7778 inline_costs += costs;
7781 mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, mono_method_signature (stfld_wrapper), iargs, ip, NULL);
7783 #if HAVE_WRITE_BARRIERS
7784 } else if (mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !(sp [1]->opcode == OP_PCONST && sp [1]->inst_c0 == 0)) {
7785 /* insert call to write barrier */
7786 MonoMethod *write_barrier = mono_marshal_get_write_barrier ();
7787 MonoInst *iargs [2];
7788 NEW_ICONST (cfg, offset_ins, foffset);
7789 MONO_INST_NEW (cfg, ins, OP_PADD);
7790 ins->inst_left = *sp;
7791 ins->inst_right = offset_ins;
7792 ins->type = STACK_MP;
7793 ins->klass = mono_defaults.object_class;
7796 mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), iargs, ip, NULL);
7798 #ifdef MONO_ARCH_SOFT_FLOAT
7799 } else if (mini_type_to_stind (cfg, field->type) == CEE_STIND_R4) {
7800 NEW_ICONST (cfg, offset_ins, foffset);
7801 MONO_INST_NEW (cfg, ins, OP_PADD);
7802 ins->inst_left = *sp;
7803 ins->inst_right = offset_ins;
7804 ins->type = STACK_MP;
7805 ins->klass = mono_defaults.object_class;
7806 handle_store_float (cfg, bblock, ins, sp [1], ip);
7810 NEW_ICONST (cfg, offset_ins, foffset);
7811 MONO_INST_NEW (cfg, ins, OP_PADD);
7812 ins->inst_left = *sp;
7813 ins->inst_right = offset_ins;
7814 ins->type = STACK_MP;
7816 MONO_INST_NEW (cfg, store, mini_type_to_stind (cfg, field->type));
7817 store->inst_left = ins;
7818 store->inst_right = sp [1];
7819 handle_loaded_temps (cfg, bblock, stack_start, sp);
7820 store->flags |= ins_flag;
7822 if (store->opcode == CEE_STOBJ) {
7823 handle_stobj (cfg, bblock, ins, sp [1], ip,
7824 mono_class_from_mono_type (field->type), FALSE, FALSE, TRUE);
7826 MONO_ADD_INS (bblock, store);
7829 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
7830 MonoMethod *wrapper = (*ip == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type);
7831 MonoInst *iargs [4];
7835 NEW_CLASSCONST (cfg, iargs [1], klass);
7836 NEW_FIELDCONST (cfg, iargs [2], field);
7837 NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
7838 if ((cfg->opt & MONO_OPT_INLINE) && !MONO_TYPE_ISSTRUCT (mono_method_signature (wrapper)->ret)) {
7839 costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), bblock,
7840 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
7841 g_assert (costs > 0);
7846 GET_BBLOCK (cfg, bblock, ip);
7847 ebblock->next_bb = bblock;
7848 link_bblock (cfg, ebblock, bblock);
7850 temp = iargs [0]->inst_i0->inst_c0;
7852 NEW_TEMPLOAD (cfg, *sp, temp);
7855 /* indicates start of a new block, and triggers a load of
7856 all stack arguments at bb boundarie */
7859 inline_costs += costs;
7862 temp = mono_emit_method_call_spilled (cfg, bblock, wrapper, mono_method_signature (wrapper), iargs, ip, NULL);
7863 NEW_TEMPLOAD (cfg, *sp, temp);
7864 NEW_TEMPLOAD_SOFT_FLOAT (cfg, bblock, *sp, temp, ip);
7868 NEW_ICONST (cfg, offset_ins, foffset);
7869 MONO_INST_NEW (cfg, ins, OP_PADD);
7870 ins->inst_left = *sp;
7871 ins->inst_right = offset_ins;
7872 ins->type = STACK_MP;
7874 if (*ip == CEE_LDFLDA) {
7875 ins->klass = mono_class_from_mono_type (field->type);
7879 MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, field->type));
7880 type_to_eval_stack_type (cfg, field->type, load);
7881 load->inst_left = ins;
7882 load->flags |= ins_flag;
7884 #ifdef MONO_ARCH_SOFT_FLOAT
7885 if (mini_type_to_ldind (cfg, field->type) == CEE_LDIND_R4) {
7887 temp = handle_load_float (cfg, bblock, ins, ip);
7888 NEW_TEMPLOAD (cfg, *sp, temp);
7902 MonoClassField *field;
7903 gboolean is_special_static;
7904 gpointer addr = NULL;
7907 token = read32 (ip + 1);
7908 if (method->wrapper_type != MONO_WRAPPER_NONE) {
7909 field = mono_method_get_wrapper_data (method, token);
7910 klass = field->parent;
7913 field = mono_field_from_token (image, token, &klass, generic_context);
7916 mono_class_init (klass);
7917 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
7918 FIELD_ACCESS_FAILURE;
7921 * We can only support shared generic static
7922 * field access on architectures where the
7923 * trampoline code has been extended to handle
7924 * the generic class init.
7926 #ifndef MONO_ARCH_VTABLE_REG
7927 GENERIC_SHARING_FAILURE (*ip);
7930 if (cfg->generic_sharing_context)
7931 context_used = mono_class_check_context_used (klass);
7933 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
7935 if ((*ip) == CEE_STSFLD)
7936 handle_loaded_temps (cfg, bblock, stack_start, sp);
7938 is_special_static = mono_class_field_is_special_static (field);
7940 if ((cfg->opt & MONO_OPT_SHARED) ||
7941 (cfg->compile_aot && is_special_static) ||
7942 (context_used && is_special_static)) {
7944 MonoInst *iargs [2];
7946 g_assert (field->parent);
7947 if ((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) {
7948 MonoInst *domain_var;
7949 /* avoid depending on undefined C behavior in sequence points */
7950 domain_var = mono_get_domainvar (cfg);
7951 NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
7953 NEW_DOMAINCONST (cfg, iargs [0]);
7958 GET_RGCTX (rgctx, context_used);
7959 iargs [1] = get_runtime_generic_context_field (cfg, method, context_used,
7961 generic_context, rgctx, MONO_RGCTX_INFO_CLASS_FIELD, ip);
7963 NEW_FIELDCONST (cfg, iargs [1], field);
7965 temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
7966 NEW_TEMPLOAD (cfg, ins, temp);
7967 } else if (context_used) {
7968 MonoInst *rgctx, *static_data;
7971 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
7972 method->klass->name_space, method->klass->name, method->name,
7973 depth, field->offset);
7976 if (mono_class_needs_cctor_run (klass, method)) {
7977 MonoMethodSignature *sig = helper_sig_generic_class_init_trampoline;
7979 MonoInst *vtable, *rgctx;
7981 GET_RGCTX (rgctx, context_used);
7982 vtable = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
7983 generic_context, rgctx, MONO_RGCTX_INFO_VTABLE, ip);
7985 call = mono_emit_call_args (cfg, bblock, sig, NULL, FALSE, FALSE, ip, FALSE);
7986 call->inst.opcode = OP_TRAMPCALL_VTABLE;
7987 call->fptr = mono_create_generic_class_init_trampoline ();
7989 call->inst.inst_left = vtable;
7991 mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
7995 * The pointer we're computing here is
7997 * super_info.static_data + field->offset
7999 GET_RGCTX (rgctx, context_used);
8000 static_data = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
8001 generic_context, rgctx, MONO_RGCTX_INFO_STATIC_DATA, ip);
8003 if (field->offset == 0) {
8006 MonoInst *field_offset;
8008 NEW_ICONST (cfg, field_offset, field->offset);
8010 MONO_INST_NEW (cfg, ins, OP_PADD);
8011 ins->inst_left = static_data;
8012 ins->inst_right = field_offset;
8013 ins->type = STACK_PTR;
8019 vtable = mono_class_vtable (cfg->domain, klass);
8020 CHECK_TYPELOAD (klass);
8021 if (!is_special_static) {
8022 if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
8023 guint8 *tramp = mono_create_class_init_trampoline (vtable);
8024 mono_emit_native_call (cfg, bblock, tramp,
8025 helper_sig_class_init_trampoline,
8026 NULL, ip, FALSE, FALSE);
8027 if (cfg->verbose_level > 2)
8028 g_print ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, field->name);
8029 class_inits = g_slist_prepend (class_inits, vtable);
8031 if (cfg->run_cctors) {
8033 /* This makes so that inline cannot trigger */
8034 /* .cctors: too many apps depend on them */
8035 /* running with a specific order... */
8036 if (! vtable->initialized)
8038 ex = mono_runtime_class_init_full (vtable, FALSE);
8040 set_exception_object (cfg, ex);
8041 goto exception_exit;
8045 addr = (char*)vtable->data + field->offset;
8047 if (cfg->compile_aot)
8048 NEW_SFLDACONST (cfg, ins, field);
8050 NEW_PCONST (cfg, ins, addr);
8053 MonoInst *iargs [1];
8055 /* The special_static_fields
8056 * field is init'd in
8057 * mono_class_vtable, so it
8058 * needs to be called here.
8060 if (!(cfg->opt & MONO_OPT_SHARED)) {
8061 mono_class_vtable (cfg->domain, klass);
8062 CHECK_TYPELOAD (klass);
8064 mono_domain_lock (cfg->domain);
8065 if (cfg->domain->special_static_fields)
8066 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
8067 mono_domain_unlock (cfg->domain);
8070 * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr))
8071 * This could be later optimized to do just a couple of
8072 * memory dereferences with constant offsets.
8074 NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
8075 temp = mono_emit_jit_icall (cfg, bblock, mono_get_special_static_data, iargs, ip);
8076 NEW_TEMPLOAD (cfg, ins, temp);
8080 /* FIXME: mark instructions for use in SSA */
8081 if (*ip == CEE_LDSFLDA) {
8082 ins->klass = mono_class_from_mono_type (field->type);
8084 } else if (*ip == CEE_STSFLD) {
8088 MONO_INST_NEW (cfg, store, mini_type_to_stind (cfg, field->type));
8089 store->inst_left = ins;
8090 store->inst_right = sp [0];
8091 store->flags |= ins_flag;
8094 #ifdef MONO_ARCH_SOFT_FLOAT
8095 if (store->opcode == CEE_STIND_R4)
8096 handle_store_float (cfg, bblock, ins, sp [0], ip);
8099 if (store->opcode == CEE_STOBJ) {
8100 handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE, FALSE);
8102 MONO_ADD_INS (bblock, store);
8104 gboolean is_const = FALSE;
8105 MonoVTable *vtable = NULL;
8108 vtable = mono_class_vtable (cfg->domain, klass);
8110 CHECK_TYPELOAD (klass);
8111 if (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) &&
8112 vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
8113 gpointer addr = (char*)vtable->data + field->offset;
8114 int ro_type = field->type->type;
8115 if (ro_type == MONO_TYPE_VALUETYPE && field->type->data.klass->enumtype) {
8116 ro_type = field->type->data.klass->enum_basetype->type;
8118 /* g_print ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, field->name);*/
8121 case MONO_TYPE_BOOLEAN:
8123 NEW_ICONST (cfg, *sp, *((guint8 *)addr));
8127 NEW_ICONST (cfg, *sp, *((gint8 *)addr));
8130 case MONO_TYPE_CHAR:
8132 NEW_ICONST (cfg, *sp, *((guint16 *)addr));
8136 NEW_ICONST (cfg, *sp, *((gint16 *)addr));
8141 NEW_ICONST (cfg, *sp, *((gint32 *)addr));
8145 NEW_ICONST (cfg, *sp, *((guint32 *)addr));
8148 #ifndef HAVE_MOVING_COLLECTOR
8151 case MONO_TYPE_STRING:
8152 case MONO_TYPE_OBJECT:
8153 case MONO_TYPE_CLASS:
8154 case MONO_TYPE_SZARRAY:
8156 case MONO_TYPE_FNPTR:
8157 case MONO_TYPE_ARRAY:
8158 NEW_PCONST (cfg, *sp, *((gpointer *)addr));
8159 type_to_eval_stack_type (cfg, field->type, *sp);
8165 MONO_INST_NEW (cfg, *sp, OP_I8CONST);
8166 sp [0]->type = STACK_I8;
8167 sp [0]->inst_l = *((gint64 *)addr);
8172 case MONO_TYPE_VALUETYPE:
8181 CHECK_STACK_OVF (1);
8182 MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, field->type));
8183 type_to_eval_stack_type (cfg, field->type, load);
8184 load->inst_left = ins;
8185 load->flags |= ins_flag;
8186 #ifdef MONO_ARCH_SOFT_FLOAT
8187 if (load->opcode == CEE_LDIND_R4) {
8189 temp = handle_load_float (cfg, bblock, ins, ip);
8190 NEW_TEMPLOAD (cfg, load, temp);
8204 token = read32 (ip + 1);
8205 klass = mini_get_class (method, token, generic_context);
8206 CHECK_TYPELOAD (klass);
8207 n = mini_type_to_stind (cfg, &klass->byval_arg);
8208 /* FIXME: handle CEE_STIND_R4 */
8209 if (n == CEE_STOBJ) {
8210 handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE, TRUE);
8212 /* FIXME: should check item at sp [1] is compatible with the type of the store. */
8214 MONO_INST_NEW (cfg, store, n);
8215 store->inst_left = sp [0];
8216 store->inst_right = sp [1];
8217 store->flags |= ins_flag;
8218 MONO_ADD_INS (bblock, store);
8231 token = read32 (ip + 1);
8232 klass = mini_get_class (method, token, generic_context);
8233 CHECK_TYPELOAD (klass);
8235 if (cfg->generic_sharing_context)
8236 context_used = mono_class_check_context_used (klass);
8238 if (generic_class_is_reference_type (cfg, klass)) {
8243 if (klass == mono_defaults.void_class)
8245 if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
8247 /* frequent check in generic code: box (struct), brtrue */
8248 if (!mono_class_is_nullable (klass) &&
8249 ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) && (ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S)) {
8250 /*g_print ("box-brtrue opt at 0x%04x in %s\n", real_offset, method->name);*/
8251 MONO_INST_NEW (cfg, ins, CEE_POP);
8252 MONO_ADD_INS (bblock, ins);
8256 MONO_INST_NEW (cfg, ins, OP_BR);
8257 MONO_ADD_INS (bblock, ins);
8258 if (*ip == CEE_BRTRUE_S) {
8261 target = ip + 1 + (signed char)(*ip);
8266 target = ip + 4 + (gint)(read32 (ip));
8269 GET_BBLOCK (cfg, tblock, target);
8270 link_bblock (cfg, bblock, tblock);
8271 CHECK_BBLOCK (target, ip, tblock);
8272 ins->inst_target_bb = tblock;
8273 GET_BBLOCK (cfg, tblock, ip);
8274 link_bblock (cfg, bblock, tblock);
8275 if (sp != stack_start) {
8276 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
8278 CHECK_UNVERIFIABLE (cfg);
8280 start_new_bblock = 1;
8286 if (mono_class_is_nullable (klass)) {
8287 GET_RGCTX (rgctx, context_used);
8288 *sp++ = handle_box_nullable_from_inst (cfg, method, context_used, bblock, val,
8289 ip, klass, generic_context, rgctx);
8294 GET_RGCTX (rgctx, context_used);
8295 if (cfg->opt & MONO_OPT_SHARED)
8296 rgctx_info = MONO_RGCTX_INFO_KLASS;
8298 rgctx_info = MONO_RGCTX_INFO_VTABLE;
8299 data = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
8300 generic_context, rgctx, rgctx_info, ip);
8302 *sp++ = handle_box_from_inst (cfg, bblock, val, ip, klass, data);
8305 *sp++ = handle_box (cfg, bblock, val, ip, klass);
8316 token = read32 (ip + 1);
8318 /* allocate the domainvar - becaus this is used in decompose_foreach */
8319 if (cfg->opt & MONO_OPT_SHARED) {
8320 mono_get_domainvar (cfg);
8321 /* LAME-IR: Mark it as used since otherwise it will be optimized away */
8322 cfg->domainvar->flags |= MONO_INST_VOLATILE;
8326 mono_get_got_var (cfg);
8328 klass = mini_get_class (method, token, generic_context);
8329 CHECK_TYPELOAD (klass);
8331 if (cfg->generic_sharing_context)
8332 context_used = mono_class_check_context_used (klass);
8335 MonoInst *rgctx, *args [3];
8339 /* FIXME: what about domain-neutral code? */
8340 NEW_DOMAINCONST (cfg, args [0]);
8343 GET_RGCTX (rgctx, context_used);
8344 args [1] = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
8345 generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
8350 temp = mono_emit_jit_icall (cfg, bblock, mono_array_new, args, ip);
8351 NEW_TEMPLOAD (cfg, ins, temp);
8353 MONO_INST_NEW (cfg, ins, *ip);
8354 ins->inst_newa_class = klass;
8355 ins->inst_newa_len = *sp;
8356 ins->type = STACK_OBJ;
8357 ins->klass = mono_array_class_get (klass, 1);
8363 * we store the object so calls to create the array are not interleaved
8364 * with the arguments of other calls.
8367 MonoInst *store, *temp, *load;
8368 const char *data_ptr;
8371 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8372 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8373 store->cil_code = ins->cil_code;
8374 MONO_ADD_INS (bblock, store);
8376 * we inline/optimize the initialization sequence if possible.
8377 * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
8378 * for small sizes open code the memcpy
8379 * ensure the rva field is big enough
8381 if ((cfg->opt & MONO_OPT_INTRINS) && ip + 6 < end && ip_in_bb (cfg, bblock, ip + 6) && (data_ptr = initialize_array_data (method, cfg->compile_aot, ip, ins, &data_size))) {
8382 MonoMethod *memcpy_method = get_memcpy_method ();
8383 MonoInst *data_offset, *add;
8384 MonoInst *iargs [3];
8385 NEW_ICONST (cfg, iargs [2], data_size);
8386 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
8387 load->cil_code = ins->cil_code;
8388 NEW_ICONST (cfg, data_offset, G_STRUCT_OFFSET (MonoArray, vector));
8389 MONO_INST_NEW (cfg, add, OP_PADD);
8390 add->inst_left = load;
8391 add->inst_right = data_offset;
8393 if (cfg->compile_aot) {
8394 NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(data_ptr), STACK_PTR, NULL);
8396 NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
8398 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
8401 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
8402 load->cil_code = ins->cil_code;
8410 if (sp [0]->type != STACK_OBJ)
8412 MONO_INST_NEW (cfg, ins, *ip);
8414 ins->inst_left = *sp;
8415 ins->type = STACK_PTR;
8422 if (sp [0]->type != STACK_OBJ)
8425 klass = mini_get_class (method, read32 (ip + 1), generic_context);
8426 CHECK_TYPELOAD (klass);
8427 /* we need to make sure that this array is exactly the type it needs
8428 * to be for correctness. the wrappers are lax with their usage
8429 * so we need to ignore them here
8431 if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
8434 /* Needed by the code generated in inssel.brg */
8435 mono_get_got_var (cfg);
8437 MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
8438 check->klass = mono_array_class_get (klass, 1);
8439 check->inst_left = sp [0];
8440 check->type = STACK_OBJ;
8445 mono_class_init (klass);
8446 NEW_LDELEMA (cfg, ins, sp, klass);
8450 case CEE_LDELEM_ANY: {
8454 if (sp [0]->type != STACK_OBJ)
8457 token = read32 (ip + 1);
8458 klass = mini_get_class (method, token, generic_context);
8459 CHECK_TYPELOAD (klass);
8460 mono_class_init (klass);
8461 NEW_LDELEMA (cfg, load, sp, klass);
8462 MONO_INST_NEW (cfg, ins, mini_type_to_ldind (cfg, &klass->byval_arg));
8463 ins->inst_left = load;
8465 type_to_eval_stack_type (cfg, &klass->byval_arg, ins);
8479 case CEE_LDELEM_REF: {
8483 * ldind.x (ldelema (array, index))
8484 * ldelema does the bounds check
8488 if (sp [0]->type != STACK_OBJ)
8490 klass = array_access_to_klass (*ip, sp [0]);
8491 NEW_LDELEMA (cfg, load, sp, klass);
8492 #ifdef MONO_ARCH_SOFT_FLOAT
8493 if (*ip == CEE_LDELEM_R4) {
8495 temp = handle_load_float (cfg, bblock, load, ip);
8496 NEW_TEMPLOAD (cfg, *sp, temp);
8502 MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
8503 ins->inst_left = load;
8505 ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
8516 case CEE_STELEM_R8: {
8520 * stind.x (ldelema (array, index), val)
8521 * ldelema does the bounds check
8525 if (sp [0]->type != STACK_OBJ)
8527 klass = array_access_to_klass (*ip, sp [0]);
8528 NEW_LDELEMA (cfg, load, sp, klass);
8529 #ifdef MONO_ARCH_SOFT_FLOAT
8530 if (*ip == CEE_STELEM_R4) {
8531 handle_store_float (cfg, bblock, load, sp [2], ip);
8536 MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
8537 ins->inst_left = load;
8538 ins->inst_right = sp [2];
8540 handle_loaded_temps (cfg, bblock, stack_start, sp);
8541 MONO_ADD_INS (bblock, ins);
8545 case CEE_STELEM_ANY: {
8549 * stind.x (ldelema (array, index), val)
8550 * ldelema does the bounds check
8554 if (sp [0]->type != STACK_OBJ)
8557 token = read32 (ip + 1);
8558 klass = mini_get_class (method, token, generic_context);
8559 CHECK_TYPELOAD (klass);
8560 mono_class_init (klass);
8561 if (generic_class_is_reference_type (cfg, klass)) {
8562 /* storing a NULL doesn't need any of the complex checks in stelemref */
8563 if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
8565 NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
8566 MONO_INST_NEW (cfg, ins, CEE_STIND_REF);
8567 ins->inst_left = load;
8568 ins->inst_right = sp [2];
8569 MONO_ADD_INS (bblock, ins);
8571 MonoMethod* helper = mono_marshal_get_stelemref ();
8572 MonoInst *iargs [3];
8573 handle_loaded_temps (cfg, bblock, stack_start, sp);
8579 mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
8582 NEW_LDELEMA (cfg, load, sp, klass);
8584 n = mini_type_to_stind (cfg, &klass->byval_arg);
8585 /* FIXME: CEE_STIND_R4 */
8587 handle_stobj (cfg, bblock, load, sp [2], ip, klass, FALSE, FALSE, TRUE);
8589 MONO_INST_NEW (cfg, ins, n);
8590 ins->inst_left = load;
8591 ins->inst_right = sp [2];
8592 handle_loaded_temps (cfg, bblock, stack_start, sp);
8593 MONO_ADD_INS (bblock, ins);
8600 case CEE_STELEM_REF: {
8601 MonoInst *iargs [3];
8602 MonoMethod* helper = mono_marshal_get_stelemref ();
8606 if (sp [0]->type != STACK_OBJ)
8608 if (sp [2]->type != STACK_OBJ)
8611 handle_loaded_temps (cfg, bblock, stack_start, sp);
8613 /* storing a NULL doesn't need any of the complex checks in stelemref */
8614 if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
8616 NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
8617 MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
8618 ins->inst_left = load;
8619 ins->inst_right = sp [2];
8620 MONO_ADD_INS (bblock, ins);
8626 mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
8633 case CEE_CKFINITE: {
8634 MonoInst *store, *temp;
8637 /* this instr. can throw exceptions as side effect,
8638 * so we cant eliminate dead code which contains CKFINITE opdodes.
8639 * Spilling to memory makes sure that we always perform
8643 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
8644 ins->inst_left = sp [-1];
8645 temp = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
8647 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8648 MONO_ADD_INS (bblock, store);
8650 NEW_TEMPLOAD (cfg, sp [-1], temp->inst_c0);
8659 token = read32 (ip + 1);
8660 klass = mono_class_get_full (image, token, generic_context);
8661 CHECK_TYPELOAD (klass);
8662 mono_class_init (klass);
8664 /* Needed by the code generated in inssel.brg */
8665 mono_get_got_var (cfg);
8667 if (cfg->generic_sharing_context) {
8668 context_used = mono_class_check_context_used (klass);
8669 if (context_used && cfg->compile_aot)
8670 GENERIC_SHARING_FAILURE (*ip);
8676 MONO_INST_NEW (cfg, ins, OP_REFANYVAL_REG);
8677 ins->type = STACK_MP;
8678 ins->inst_left = *sp;
8681 GET_RGCTX (rgctx, context_used);
8682 ins->inst_right = get_runtime_generic_context_ptr (cfg, method, context_used,
8683 bblock, klass, generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
8685 MONO_INST_NEW (cfg, ins, *ip);
8686 ins->type = STACK_MP;
8687 ins->inst_left = *sp;
8689 ins->inst_newa_class = klass;
8694 case CEE_MKREFANY: {
8700 token = read32 (ip + 1);
8701 klass = mono_class_get_full (image, token, generic_context);
8702 CHECK_TYPELOAD (klass);
8703 mono_class_init (klass);
8705 if (cfg->generic_sharing_context) {
8706 context_used = mono_class_check_context_used (klass);
8707 if (context_used && cfg->compile_aot)
8708 GENERIC_SHARING_FAILURE (CEE_MKREFANY);
8711 loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
8713 MonoInst *rgctx, *klass_type, *klass_klass, *loc_load;
8715 GET_RGCTX (rgctx, context_used);
8716 klass_klass = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
8717 generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
8718 GET_RGCTX (rgctx, context_used);
8719 klass_type = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
8720 generic_context, rgctx, MONO_RGCTX_INFO_TYPE, ip);
8722 NEW_TEMPLOADA (cfg, loc_load, loc->inst_c0);
8724 MONO_INST_NEW (cfg, ins, OP_MKREFANY_REGS);
8725 NEW_GROUP (cfg, ins->inst_left, klass_type, klass_klass);
8726 NEW_GROUP (cfg, ins->inst_right, *sp, loc_load);
8728 MonoInst *klassconst;
8730 NEW_PCONST (cfg, klassconst, klass);
8732 MONO_INST_NEW (cfg, ins, *ip);
8733 NEW_TEMPLOADA (cfg, ins->inst_right, loc->inst_c0);
8734 NEW_GROUP (cfg, ins->inst_left, *sp, klassconst);
8737 MONO_ADD_INS (bblock, ins);
8739 NEW_TEMPLOAD (cfg, *sp, loc->inst_c0);
8746 MonoClass *handle_class;
8748 CHECK_STACK_OVF (1);
8751 n = read32 (ip + 1);
8753 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
8754 handle = mono_method_get_wrapper_data (method, n);
8755 handle_class = mono_method_get_wrapper_data (method, n + 1);
8756 if (handle_class == mono_defaults.typehandle_class)
8757 handle = &((MonoClass*)handle)->byval_arg;
8760 handle = mono_ldtoken (image, n, &handle_class, generic_context);
8764 mono_class_init (handle_class);
8766 if (cfg->generic_sharing_context) {
8767 if (handle_class == mono_defaults.typehandle_class) {
8768 /* If we get a MONO_TYPE_CLASS
8769 then we need to provide the
8771 instantiation of it. */
8772 if (mono_type_get_type (handle) == MONO_TYPE_CLASS)
8775 context_used = mono_class_check_context_used (mono_class_from_mono_type (handle));
8776 } else if (handle_class == mono_defaults.fieldhandle_class)
8777 context_used = mono_class_check_context_used (((MonoClassField*)handle)->parent);
8778 else if (handle_class == mono_defaults.methodhandle_class)
8779 context_used = mono_method_check_context_used (handle);
8781 g_assert_not_reached ();
8784 if (cfg->opt & MONO_OPT_SHARED) {
8786 MonoInst *res, *store, *addr, *vtvar, *iargs [3];
8787 int method_context_used;
8789 if (cfg->generic_sharing_context)
8790 method_context_used = mono_method_check_context_used (method);
8792 method_context_used = 0;
8794 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
8796 NEW_IMAGECONST (cfg, iargs [0], image);
8797 NEW_ICONST (cfg, iargs [1], n);
8798 if (method_context_used) {
8801 GET_RGCTX (rgctx, method_context_used);
8802 iargs [2] = get_runtime_generic_context_method (cfg, method, method_context_used,
8804 generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
8805 temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper_generic_shared,
8808 NEW_PCONST (cfg, iargs [2], generic_context);
8809 temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
8811 NEW_TEMPLOAD (cfg, res, temp);
8812 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
8813 NEW_INDSTORE (cfg, store, addr, res, &mono_defaults.int_class->byval_arg);
8814 MONO_ADD_INS (bblock, store);
8815 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
8817 if ((ip + 10 < end) && ip_in_bb (cfg, bblock, ip + 5) &&
8818 handle_class == mono_defaults.typehandle_class &&
8819 ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) &&
8820 (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
8821 (cmethod->klass == mono_defaults.monotype_class->parent) &&
8822 (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
8823 MonoClass *tclass = mono_class_from_mono_type (handle);
8824 mono_class_init (tclass);
8828 g_assert (!cfg->compile_aot);
8830 GET_RGCTX (rgctx, context_used);
8831 ins = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, tclass,
8832 generic_context, rgctx, MONO_RGCTX_INFO_REFLECTION_TYPE, ip);
8833 } else if (cfg->compile_aot) {
8835 * FIXME: We would have to include the context into the
8836 * aot constant too (tests/generic-array-type.2.exe).
8838 if (generic_context)
8839 cfg->disable_aot = TRUE;
8840 NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n);
8842 NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
8844 ins->type = STACK_OBJ;
8845 ins->klass = cmethod->klass;
8848 MonoInst *store, *addr, *vtvar;
8853 g_assert (!cfg->compile_aot);
8855 GET_RGCTX (rgctx, context_used);
8856 if (handle_class == mono_defaults.typehandle_class) {
8857 ins = get_runtime_generic_context_ptr (cfg, method,
8858 context_used, bblock,
8859 mono_class_from_mono_type (handle), generic_context,
8860 rgctx, MONO_RGCTX_INFO_TYPE, ip);
8861 } else if (handle_class == mono_defaults.methodhandle_class) {
8862 ins = get_runtime_generic_context_method (cfg, method,
8863 context_used, bblock, handle, generic_context,
8864 rgctx, MONO_RGCTX_INFO_METHOD, ip);
8865 } else if (handle_class == mono_defaults.fieldhandle_class) {
8866 ins = get_runtime_generic_context_field (cfg, method,
8867 context_used, bblock, handle, generic_context,
8868 rgctx, MONO_RGCTX_INFO_CLASS_FIELD, ip);
8870 g_assert_not_reached ();
8873 else if (cfg->compile_aot) {
8874 NEW_LDTOKENCONST (cfg, ins, image, n);
8876 NEW_PCONST (cfg, ins, handle);
8878 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
8879 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
8880 NEW_INDSTORE (cfg, store, addr, ins, &mono_defaults.int_class->byval_arg);
8881 MONO_ADD_INS (bblock, store);
8882 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
8898 case CEE_ADD_OVF_UN:
8900 case CEE_MUL_OVF_UN:
8902 case CEE_SUB_OVF_UN:
8905 if (mono_find_jit_opcode_emulation (ins->opcode)) {
8907 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
8911 case CEE_ENDFINALLY:
8912 MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
8913 MONO_ADD_INS (bblock, ins);
8915 start_new_bblock = 1;
8918 * Control will leave the method so empty the stack, otherwise
8919 * the next basic block will start with a nonempty stack.
8921 while (sp != stack_start) {
8922 MONO_INST_NEW (cfg, ins, CEE_POP);
8925 MONO_ADD_INS (bblock, ins);
8932 if (*ip == CEE_LEAVE) {
8934 target = ip + 5 + (gint32)read32(ip + 1);
8937 target = ip + 2 + (signed char)(ip [1]);
8940 /* empty the stack */
8941 while (sp != stack_start) {
8942 MONO_INST_NEW (cfg, ins, CEE_POP);
8945 MONO_ADD_INS (bblock, ins);
8949 * If this leave statement is in a catch block, check for a
8950 * pending exception, and rethrow it if necessary.
8952 for (i = 0; i < header->num_clauses; ++i) {
8953 MonoExceptionClause *clause = &header->clauses [i];
8956 * Use <= in the final comparison to handle clauses with multiple
8957 * leave statements, like in bug #78024.
8958 * The ordering of the exception clauses guarantees that we find the
8961 if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) && (ip - header->code + ((*ip == CEE_LEAVE) ? 5 : 2)) <= (clause->handler_offset + clause->handler_len)) {
8965 NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
8967 temp = mono_emit_jit_icall (cfg, bblock, mono_thread_get_undeniable_exception, NULL, ip);
8968 NEW_TEMPLOAD (cfg, *sp, temp);
8970 MONO_INST_NEW (cfg, ins, OP_THROW_OR_NULL);
8971 ins->inst_left = *sp;
8972 ins->inst_right = load;
8973 MONO_ADD_INS (bblock, ins);
8977 if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
8979 for (tmp = handlers; tmp; tmp = tmp->next) {
8981 link_bblock (cfg, bblock, tblock);
8982 MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
8983 ins->inst_target_bb = tblock;
8984 MONO_ADD_INS (bblock, ins);
8986 g_list_free (handlers);
8989 MONO_INST_NEW (cfg, ins, OP_BR);
8990 MONO_ADD_INS (bblock, ins);
8991 GET_BBLOCK (cfg, tblock, target);
8992 link_bblock (cfg, bblock, tblock);
8993 CHECK_BBLOCK (target, ip, tblock);
8994 ins->inst_target_bb = tblock;
8995 start_new_bblock = 1;
8997 if (*ip == CEE_LEAVE)
9006 MONO_INST_NEW (cfg, ins, *ip);
9008 handle_loaded_temps (cfg, bblock, stack_start, sp);
9009 MONO_ADD_INS (bblock, ins);
9011 ins->inst_i0 = sp [0];
9012 ins->inst_i1 = sp [1];
9020 /* trampoline mono specific opcodes */
9021 case MONO_CUSTOM_PREFIX: {
9023 g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
9028 case CEE_MONO_ICALL: {
9031 MonoJitICallInfo *info;
9033 token = read32 (ip + 2);
9034 func = mono_method_get_wrapper_data (method, token);
9035 info = mono_find_jit_icall_by_addr (func);
9037 g_error ("An attempt has been made to perform an icall to address %p, "
9038 "but the address has not been registered as an icall\n", info);
9039 g_assert_not_reached ();
9042 CHECK_STACK (info->sig->param_count);
9043 sp -= info->sig->param_count;
9045 temp = mono_emit_jit_icall (cfg, bblock, info->func, sp, ip);
9046 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
9047 NEW_TEMPLOAD (cfg, *sp, temp);
9052 inline_costs += 10 * num_calls++;
9056 case CEE_MONO_LDPTR: {
9059 CHECK_STACK_OVF (1);
9061 token = read32 (ip + 2);
9063 ptr = mono_method_get_wrapper_data (method, token);
9064 if (cfg->compile_aot && (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE || cfg->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)) {
9065 MonoMethod *wrapped = mono_marshal_method_from_wrapper (cfg->method);
9067 if (wrapped && ptr != NULL && mono_lookup_internal_call (wrapped) == ptr) {
9068 NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, wrapped);
9074 if ((method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
9075 MonoJitICallInfo *callinfo;
9076 const char *icall_name;
9078 icall_name = method->name + strlen ("__icall_wrapper_");
9079 g_assert (icall_name);
9080 callinfo = mono_find_jit_icall_by_name (icall_name);
9081 g_assert (callinfo);
9083 if (ptr == callinfo->func) {
9084 /* Will be transformed into an AOTCONST later */
9085 NEW_PCONST (cfg, ins, ptr);
9092 /* FIXME: Generalize this */
9093 if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
9094 NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
9099 NEW_PCONST (cfg, ins, ptr);
9102 inline_costs += 10 * num_calls++;
9103 /* Can't embed random pointers into AOT code */
9104 cfg->disable_aot = 1;
9107 case CEE_MONO_ICALL_ADDR: {
9108 MonoMethod *cmethod;
9110 CHECK_STACK_OVF (1);
9112 token = read32 (ip + 2);
9114 cmethod = mono_method_get_wrapper_data (method, token);
9116 g_assert (cfg->compile_aot);
9118 NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
9123 case CEE_MONO_VTADDR:
9126 MONO_INST_NEW (cfg, ins, OP_VTADDR);
9127 ins->type = STACK_MP;
9128 ins->inst_left = *sp;
9132 case CEE_MONO_NEWOBJ: {
9133 MonoInst *iargs [2];
9135 CHECK_STACK_OVF (1);
9137 token = read32 (ip + 2);
9138 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
9139 mono_class_init (klass);
9140 NEW_DOMAINCONST (cfg, iargs [0]);
9141 NEW_CLASSCONST (cfg, iargs [1], klass);
9142 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
9143 NEW_TEMPLOAD (cfg, *sp, temp);
9146 inline_costs += 10 * num_calls++;
9149 case CEE_MONO_OBJADDR:
9152 MONO_INST_NEW (cfg, ins, OP_OBJADDR);
9153 ins->type = STACK_MP;
9154 ins->inst_left = *sp;
9158 case CEE_MONO_LDNATIVEOBJ:
9161 token = read32 (ip + 2);
9162 klass = mono_method_get_wrapper_data (method, token);
9163 g_assert (klass->valuetype);
9164 mono_class_init (klass);
9165 NEW_INDLOAD (cfg, ins, sp [-1], &klass->byval_arg);
9169 case CEE_MONO_RETOBJ:
9170 g_assert (cfg->ret);
9171 g_assert (mono_method_signature (method)->pinvoke);
9176 token = read32 (ip + 2);
9177 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
9179 NEW_RETLOADA (cfg, ins);
9180 handle_stobj (cfg, bblock, ins, *sp, ip, klass, FALSE, TRUE, FALSE);
9182 if (sp != stack_start)
9185 MONO_INST_NEW (cfg, ins, OP_BR);
9186 ins->inst_target_bb = end_bblock;
9187 MONO_ADD_INS (bblock, ins);
9188 link_bblock (cfg, bblock, end_bblock);
9189 start_new_bblock = 1;
9192 case CEE_MONO_CISINST:
9193 case CEE_MONO_CCASTCLASS: {
9198 token = read32 (ip + 2);
9199 /* Needed by the code generated in inssel.brg */
9200 mono_get_got_var (cfg);
9204 * The code generated for CCASTCLASS has too much register pressure
9205 * (obj+vtable+ibitmap_byte_reg+iid_reg), leading to the usual
9206 * branches-inside-bblocks problem.
9208 cfg->disable_aot = TRUE;
9211 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
9212 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_CISINST) ? OP_CISINST : OP_CCASTCLASS);
9213 ins->type = STACK_I4;
9214 ins->inst_left = *sp;
9215 ins->inst_newa_class = klass;
9216 *sp++ = emit_tree (cfg, bblock, ins, ip + 6);
9220 case CEE_MONO_SAVE_LMF:
9221 case CEE_MONO_RESTORE_LMF:
9222 #ifdef MONO_ARCH_HAVE_LMF_OPS
9223 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
9224 MONO_ADD_INS (bblock, ins);
9225 cfg->need_lmf_area = TRUE;
9229 case CEE_MONO_CLASSCONST:
9230 CHECK_STACK_OVF (1);
9232 token = read32 (ip + 2);
9233 NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
9236 inline_costs += 10 * num_calls++;
9238 case CEE_MONO_NOT_TAKEN:
9239 bblock->out_of_line = TRUE;
9243 CHECK_STACK_OVF (1);
9245 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
9246 ins->inst_offset = (gint32)read32 (ip + 2);
9247 ins->type = STACK_PTR;
9252 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
9261 /* somewhat similar to LDTOKEN */
9262 MonoInst *addr, *vtvar;
9263 CHECK_STACK_OVF (1);
9264 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL);
9266 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
9267 MONO_INST_NEW (cfg, ins, OP_ARGLIST);
9268 ins->inst_left = addr;
9269 MONO_ADD_INS (bblock, ins);
9270 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
9283 * The following transforms:
9284 * CEE_CEQ into OP_CEQ
9285 * CEE_CGT into OP_CGT
9286 * CEE_CGT_UN into OP_CGT_UN
9287 * CEE_CLT into OP_CLT
9288 * CEE_CLT_UN into OP_CLT_UN
9290 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
9292 MONO_INST_NEW (cfg, ins, cmp->opcode);
9294 cmp->inst_i0 = sp [0];
9295 cmp->inst_i1 = sp [1];
9298 ins->type = STACK_I4;
9300 #if MONO_ARCH_SOFT_FLOAT
9301 if (sp [0]->type == STACK_R8) {
9302 cmp->type = STACK_I4;
9303 *sp++ = emit_tree (cfg, bblock, cmp, ip + 2);
9308 if ((sp [0]->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
9309 cmp->opcode = OP_LCOMPARE;
9311 cmp->opcode = OP_COMPARE;
9313 /* spill it to reduce the expression complexity
9314 * and workaround bug 54209
9316 if (cmp->inst_left->type == STACK_I8) {
9318 *sp++ = emit_tree (cfg, bblock, ins, ip + 2);
9325 MonoMethod *cil_method, *ctor_method;
9327 gboolean needs_static_rgctx_invoke;
9329 CHECK_STACK_OVF (1);
9331 n = read32 (ip + 2);
9332 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
9335 mono_class_init (cmethod->klass);
9337 if (cfg->generic_sharing_context)
9338 context_used = mono_method_check_context_used (cmethod);
9340 needs_static_rgctx_invoke = mono_method_needs_static_rgctx_invoke (cmethod, TRUE);
9342 cil_method = cmethod;
9343 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
9344 METHOD_ACCESS_FAILURE;
9345 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
9346 if (check_linkdemand (cfg, method, cmethod, bblock, ip))
9348 CHECK_CFG_EXCEPTION;
9349 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
9350 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9354 * Optimize the common case of ldftn+delegate creation
9356 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE) && !defined(HAVE_WRITE_BARRIERS)
9357 /* FIXME: SGEN support */
9358 /* FIXME: handle shared static generic methods */
9359 /* FIXME: handle this in shared code */
9360 if (!needs_static_rgctx_invoke && !context_used && (sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ) && (ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context)) && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
9361 MonoInst *target_ins;
9364 if (cfg->verbose_level > 3)
9365 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
9366 target_ins = sp [-1];
9368 *sp = handle_delegate_ctor (cfg, bblock, ctor_method->klass, target_ins, cmethod, ip);
9375 handle_loaded_temps (cfg, bblock, stack_start, sp);
9380 if (needs_static_rgctx_invoke)
9381 cmethod = mono_marshal_get_static_rgctx_invoke (cmethod);
9383 GET_RGCTX (rgctx, context_used);
9384 argconst = get_runtime_generic_context_method (cfg, method, context_used,
9386 generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
9387 } else if (needs_static_rgctx_invoke) {
9388 NEW_METHODCONST (cfg, argconst, mono_marshal_get_static_rgctx_invoke (cmethod));
9390 NEW_METHODCONST (cfg, argconst, cmethod);
9392 temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
9393 NEW_TEMPLOAD (cfg, *sp, temp);
9397 inline_costs += 10 * num_calls++;
9400 case CEE_LDVIRTFTN: {
9406 n = read32 (ip + 2);
9407 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
9410 mono_class_init (cmethod->klass);
9412 if (cfg->generic_sharing_context)
9413 context_used = mono_method_check_context_used (cmethod);
9415 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
9416 if (check_linkdemand (cfg, method, cmethod, bblock, ip))
9418 CHECK_CFG_EXCEPTION;
9419 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
9420 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9423 handle_loaded_temps (cfg, bblock, stack_start, sp);
9430 GET_RGCTX (rgctx, context_used);
9431 args [1] = get_runtime_generic_context_method (cfg, method, context_used,
9433 generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
9434 temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn_gshared, args, ip);
9436 NEW_METHODCONST (cfg, args [1], cmethod);
9437 temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn, args, ip);
9439 NEW_TEMPLOAD (cfg, *sp, temp);
9443 inline_costs += 10 * num_calls++;
9447 CHECK_STACK_OVF (1);
9449 n = read16 (ip + 2);
9451 NEW_ARGLOAD (cfg, ins, n);
9452 LDARG_SOFT_FLOAT (cfg, ins, n, ip);
9457 CHECK_STACK_OVF (1);
9459 n = read16 (ip + 2);
9461 NEW_ARGLOADA (cfg, ins, n);
9468 handle_loaded_temps (cfg, bblock, stack_start, sp);
9470 n = read16 (ip + 2);
9472 NEW_ARGSTORE (cfg, ins, n, *sp);
9473 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
9475 STARG_SOFT_FLOAT (cfg, ins, n, ip);
9476 if (ins->opcode == CEE_STOBJ) {
9477 NEW_ARGLOADA (cfg, ins, n);
9478 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
9480 MONO_ADD_INS (bblock, ins);
9484 CHECK_STACK_OVF (1);
9486 n = read16 (ip + 2);
9488 NEW_LOCLOAD (cfg, ins, n);
9489 LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
9494 CHECK_STACK_OVF (1);
9496 n = read16 (ip + 2);
9498 NEW_LOCLOADA (cfg, ins, n);
9506 n = read16 (ip + 2);
9508 handle_loaded_temps (cfg, bblock, stack_start, sp);
9509 NEW_LOCSTORE (cfg, ins, n, *sp);
9510 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
9512 STLOC_SOFT_FLOAT (cfg, ins, n, ip);
9513 if (ins->opcode == CEE_STOBJ) {
9514 NEW_LOCLOADA (cfg, ins, n);
9515 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
9517 MONO_ADD_INS (bblock, ins);
9524 if (sp != stack_start)
9526 if (cfg->method != method)
9528 * Inlining this into a loop in a parent could lead to
9529 * stack overflows which is different behavior than the
9530 * non-inlined case, thus disable inlining in this case.
9532 goto inline_failure;
9533 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
9534 ins->inst_left = *sp;
9535 ins->type = STACK_PTR;
9537 cfg->flags |= MONO_CFG_HAS_ALLOCA;
9538 if (header->init_locals)
9539 ins->flags |= MONO_INST_INIT;
9543 /* FIXME: set init flag if locals init is set in this method */
9545 case CEE_ENDFILTER: {
9546 MonoExceptionClause *clause, *nearest;
9547 int cc, nearest_num;
9551 if ((sp != stack_start) || (sp [0]->type != STACK_I4))
9553 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
9554 ins->inst_left = *sp;
9555 MONO_ADD_INS (bblock, ins);
9556 start_new_bblock = 1;
9561 for (cc = 0; cc < header->num_clauses; ++cc) {
9562 clause = &header->clauses [cc];
9563 if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
9564 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
9565 (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
9571 if ((ip - header->code) != nearest->handler_offset)
9576 case CEE_UNALIGNED_:
9577 ins_flag |= MONO_INST_UNALIGNED;
9578 /* FIXME: record alignment? we can assume 1 for now */
9583 ins_flag |= MONO_INST_VOLATILE;
9587 ins_flag |= MONO_INST_TAILCALL;
9588 cfg->flags |= MONO_CFG_HAS_TAIL;
9589 /* Can't inline tail calls at this time */
9590 inline_costs += 100000;
9597 token = read32 (ip + 2);
9598 klass = mini_get_class (method, token, generic_context);
9599 CHECK_TYPELOAD (klass);
9601 if (generic_class_is_reference_type (cfg, klass)) {
9602 MonoInst *store, *load;
9603 NEW_PCONST (cfg, load, NULL);
9604 load->type = STACK_OBJ;
9605 load->klass = klass;
9606 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
9607 handle_loaded_temps (cfg, bblock, stack_start, sp);
9608 MONO_ADD_INS (bblock, store);
9609 store->inst_i0 = sp [0];
9610 store->inst_i1 = load;
9612 handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
9617 case CEE_CONSTRAINED_:
9618 /* FIXME: implement */
9620 token = read32 (ip + 2);
9621 constrained_call = mono_class_get_full (image, token, generic_context);
9622 CHECK_TYPELOAD (constrained_call);
9627 MonoInst *iargs [3];
9630 if ((cfg->opt & MONO_OPT_INTRINS) && (ip [1] == CEE_CPBLK) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
9632 NEW_MEMCPY (cfg, copy, sp [0], sp [1], n, 0);
9633 MONO_ADD_INS (bblock, copy);
9640 handle_loaded_temps (cfg, bblock, stack_start, sp);
9641 if (ip [1] == CEE_CPBLK) {
9642 MonoMethod *memcpy_method = get_memcpy_method ();
9643 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
9645 MonoMethod *memset_method = get_memset_method ();
9646 mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
9655 ins_flag |= MONO_INST_NOTYPECHECK;
9657 ins_flag |= MONO_INST_NORANGECHECK;
9658 /* we ignore the no-nullcheck for now since we
9659 * really do it explicitly only when doing callvirt->call
9665 int handler_offset = -1;
9667 for (i = 0; i < header->num_clauses; ++i) {
9668 MonoExceptionClause *clause = &header->clauses [i];
9669 if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
9670 handler_offset = clause->handler_offset;
9675 bblock->flags |= BB_EXCEPTION_UNSAFE;
9677 g_assert (handler_offset != -1);
9679 NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
9680 MONO_INST_NEW (cfg, ins, OP_RETHROW);
9681 ins->inst_left = load;
9682 MONO_ADD_INS (bblock, ins);
9684 link_bblock (cfg, bblock, end_bblock);
9685 start_new_bblock = 1;
9690 CHECK_STACK_OVF (1);
9692 token = read32 (ip + 2);
9693 /* FIXXME: handle generics. */
9694 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
9695 MonoType *type = mono_type_create_from_typespec (image, token);
9696 token = mono_type_size (type, &ialign);
9698 MonoClass *klass = mono_class_get_full (image, token, generic_context);
9699 CHECK_TYPELOAD (klass);
9700 mono_class_init (klass);
9701 token = mono_class_value_size (klass, &align);
9703 NEW_ICONST (cfg, ins, token);
9707 case CEE_REFANYTYPE:
9709 MONO_INST_NEW (cfg, ins, OP_REFANYTYPE);
9711 ins->type = STACK_MP;
9712 ins->inst_left = *sp;
9713 ins->type = STACK_VTYPE;
9714 ins->klass = mono_defaults.typehandle_class;
9723 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
9728 g_error ("opcode 0x%02x not handled", *ip);
9731 if (start_new_bblock != 1)
9734 bblock->cil_length = ip - bblock->cil_code;
9735 bblock->next_bb = end_bblock;
9737 if (cfg->method == method && cfg->domainvar) {
9739 MonoInst *get_domain;
9741 if (! (get_domain = mono_arch_get_domain_intrinsic (cfg))) {
9744 MONO_INST_NEW_CALL (cfg, call, OP_CALL);
9745 call->signature = helper_sig_domain_get;
9746 call->inst.type = STACK_PTR;
9747 call->fptr = mono_domain_get;
9748 get_domain = (MonoInst*)call;
9751 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
9752 MONO_ADD_INS (init_localsbb, store);
9755 if (cfg->method == method && cfg->got_var)
9756 mono_emit_load_got_addr (cfg);
9758 if (header->init_locals) {
9760 cfg->ip = header->code;
9761 for (i = 0; i < header->num_locals; ++i) {
9762 MonoType *ptype = header->locals [i];
9763 int t = ptype->type;
9764 if (t == MONO_TYPE_VALUETYPE && ptype->data.klass->enumtype)
9765 t = ptype->data.klass->enum_basetype->type;
9767 NEW_PCONST (cfg, ins, NULL);
9768 NEW_LOCSTORE (cfg, store, i, ins);
9769 MONO_ADD_INS (init_localsbb, store);
9770 } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
9771 NEW_ICONST (cfg, ins, 0);
9772 NEW_LOCSTORE (cfg, store, i, ins);
9773 MONO_ADD_INS (init_localsbb, store);
9774 } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
9775 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9776 ins->type = STACK_I8;
9778 NEW_LOCSTORE (cfg, store, i, ins);
9779 MONO_ADD_INS (init_localsbb, store);
9780 } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
9781 #ifdef MONO_ARCH_SOFT_FLOAT
9782 /* FIXME: handle init of R4 */
9784 MONO_INST_NEW (cfg, ins, OP_R8CONST);
9785 ins->type = STACK_R8;
9786 ins->inst_p0 = (void*)&r8_0;
9787 NEW_LOCSTORE (cfg, store, i, ins);
9788 MONO_ADD_INS (init_localsbb, store);
9790 } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
9791 ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
9792 NEW_LOCLOADA (cfg, ins, i);
9793 handle_initobj (cfg, init_localsbb, ins, NULL, mono_class_from_mono_type (ptype), NULL, NULL);
9795 NEW_PCONST (cfg, ins, NULL);
9796 NEW_LOCSTORE (cfg, store, i, ins);
9797 MONO_ADD_INS (init_localsbb, store);
9804 /* resolve backward branches in the middle of an existing basic block */
9805 for (tmp = bb_recheck; tmp; tmp = tmp->next) {
9807 /*g_print ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
9808 tblock = find_previous (cfg->cil_offset_to_bb, header->code_size, start_bblock, bblock->cil_code);
9809 if (tblock != start_bblock) {
9811 split_bblock (cfg, tblock, bblock);
9812 l = bblock->cil_code - header->code;
9813 bblock->cil_length = tblock->cil_length - l;
9814 tblock->cil_length = l;
9816 g_print ("recheck failed.\n");
9820 if (cfg->method == method) {
9822 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
9823 bb->region = mono_find_block_region (cfg, bb->real_offset);
9825 mono_create_spvar_for_region (cfg, bb->region);
9826 if (cfg->verbose_level > 2)
9827 g_print ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
9831 g_slist_free (class_inits);
9832 dont_inline = g_list_remove (dont_inline, method);
9834 if (inline_costs < 0) {
9837 /* Method is too large */
9838 mname = mono_method_full_name (method, TRUE);
9839 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
9840 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
9845 return inline_costs;
9848 g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
9849 g_slist_free (class_inits);
9850 dont_inline = g_list_remove (dont_inline, method);
9854 g_slist_free (class_inits);
9855 dont_inline = g_list_remove (dont_inline, method);
9859 g_slist_free (class_inits);
9860 dont_inline = g_list_remove (dont_inline, method);
9861 cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
9865 g_slist_free (class_inits);
9866 dont_inline = g_list_remove (dont_inline, method);
9867 set_exception_type_from_invalid_il (cfg, method, ip);
9872 mono_print_tree (MonoInst *tree) {
9878 arity = mono_burg_arity [tree->opcode];
9880 printf (" %s%s", arity?"(":"", mono_inst_name (tree->opcode));
9882 switch (tree->opcode) {
9884 printf ("[%d]", (int)tree->inst_c0);
9887 printf ("[%lld]", (long long)tree->inst_l);
9890 printf ("[%f]", *(double*)tree->inst_p0);
9893 printf ("[%f]", *(float*)tree->inst_p0);
9897 printf ("[%d]", (int)tree->inst_c0);
9900 if (tree->inst_offset < 0)
9901 printf ("[-0x%x(%s)]", (int)(-tree->inst_offset), mono_arch_regname (tree->inst_basereg));
9903 printf ("[0x%x(%s)]", (int)(tree->inst_offset), mono_arch_regname (tree->inst_basereg));
9906 printf ("[%s]", mono_arch_regname (tree->dreg));
9909 printf ("[%s]", tree->inst_newa_class->name);
9910 mono_print_tree (tree->inst_newa_len);
9921 case OP_VOIDCALLVIRT:
9922 case OP_TRAMPCALL_VTABLE: {
9923 MonoCallInst *call = (MonoCallInst*)tree;
9925 printf ("[%s]", call->method->name);
9926 else if (call->fptr) {
9927 MonoJitICallInfo *info = mono_find_jit_icall_by_addr (call->fptr);
9929 printf ("[%s]", info->name);
9935 printf ("[%d (", (int)tree->inst_c0);
9936 for (i = 0; i < tree->inst_phi_args [0]; i++) {
9939 printf ("%d", tree->inst_phi_args [i + 1]);
9950 case OP_LOAD_MEMBASE:
9951 case OP_LOADI4_MEMBASE:
9952 case OP_LOADU4_MEMBASE:
9953 case OP_LOADU1_MEMBASE:
9954 case OP_LOADI1_MEMBASE:
9955 case OP_LOADU2_MEMBASE:
9956 case OP_LOADI2_MEMBASE:
9957 printf ("[%s] <- [%s + 0x%x]", mono_arch_regname (tree->dreg), mono_arch_regname (tree->inst_basereg), (int)tree->inst_offset);
9960 case OP_CALL_HANDLER:
9961 printf ("[B%d]", tree->inst_target_bb->block_num);
9971 case OP_VOIDCALL_REG:
9972 mono_print_tree (tree->inst_left);
9984 printf ("[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
9985 mono_print_tree (tree->inst_left);
9988 if (!mono_arch_print_tree(tree, arity)) {
9990 mono_print_tree (tree->inst_left);
9992 mono_print_tree (tree->inst_right);
10003 mono_print_tree_nl (MonoInst *tree)
10005 mono_print_tree (tree);
10010 create_helper_signature (void)
10012 helper_sig_domain_get = mono_create_icall_signature ("ptr");
10013 helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
10014 helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
10015 helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
10018 static gconstpointer
10019 mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
10022 MonoMethod *wrapper;
10023 gconstpointer trampoline;
10024 MonoDomain *domain = mono_get_root_domain ();
10026 if (callinfo->wrapper) {
10027 return callinfo->wrapper;
10030 if (callinfo->trampoline)
10031 return callinfo->trampoline;
10034 * We use the lock on the root domain instead of the JIT lock to protect
10035 * callinfo->trampoline, since we do a lot of stuff inside the critical section.
10037 mono_domain_lock (domain);
10039 if (callinfo->trampoline) {
10040 mono_domain_unlock (domain);
10041 return callinfo->trampoline;
10044 name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
10045 wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_for_pending_exc);
10049 trampoline = mono_compile_method (wrapper);
10051 trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper));
10052 mono_register_jit_icall_wrapper (callinfo, trampoline);
10054 callinfo->trampoline = trampoline;
10056 mono_domain_unlock (domain);
10058 return callinfo->trampoline;
10062 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
10064 return mono_icall_get_wrapper_full (callinfo, FALSE);
10068 mono_dynamic_code_hash_insert (MonoDomain *domain, MonoMethod *method, MonoJitDynamicMethodInfo *ji)
10070 if (!domain_jit_info (domain)->dynamic_code_hash)
10071 domain_jit_info (domain)->dynamic_code_hash = g_hash_table_new (NULL, NULL);
10072 g_hash_table_insert (domain_jit_info (domain)->dynamic_code_hash, method, ji);
10075 static MonoJitDynamicMethodInfo*
10076 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
10078 MonoJitDynamicMethodInfo *res;
10080 if (domain_jit_info (domain)->dynamic_code_hash)
10081 res = g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
10089 GList *active, *inactive;
10094 compare_by_interval_start_pos_func (gconstpointer a, gconstpointer b)
10096 MonoMethodVar *v1 = (MonoMethodVar*)a;
10097 MonoMethodVar *v2 = (MonoMethodVar*)b;
10101 else if (v1->interval->range && v2->interval->range)
10102 return v1->interval->range->from - v2->interval->range->from;
10103 else if (v1->interval->range)
10109 #ifndef DISABLE_JIT
10112 #define LSCAN_DEBUG(a) do { a; } while (0)
10114 #define LSCAN_DEBUG(a)
10118 mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align)
10120 int i, slot, offset, size;
10122 MonoMethodVar *vmv;
10125 GList *vars = NULL, *l, *unhandled;
10126 StackSlotInfo *scalar_stack_slots, *vtype_stack_slots, *slot_info;
10130 LSCAN_DEBUG (printf ("Allocate Stack Slots 2 for %s:\n", mono_method_full_name (cfg->method, TRUE)));
10132 scalar_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * MONO_TYPE_PINNED);
10133 vtype_stack_slots = NULL;
10136 offsets = mono_mempool_alloc (cfg->mempool, sizeof (gint32) * cfg->num_varinfo);
10137 for (i = 0; i < cfg->num_varinfo; ++i)
10140 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
10141 inst = cfg->varinfo [i];
10142 vmv = MONO_VARINFO (cfg, i);
10144 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR || inst->opcode == OP_REGOFFSET)
10147 vars = g_list_prepend (vars, vmv);
10150 vars = g_list_sort (g_list_copy (vars), compare_by_interval_start_pos_func);
10155 for (unhandled = vars; unhandled; unhandled = unhandled->next) {
10156 MonoMethodVar *current = unhandled->data;
10158 if (current->interval->range) {
10159 g_assert (current->interval->range->from >= i);
10160 i = current->interval->range->from;
10167 for (unhandled = vars; unhandled; unhandled = unhandled->next) {
10168 MonoMethodVar *current = unhandled->data;
10171 inst = cfg->varinfo [vmv->idx];
10173 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
10174 * pinvoke wrappers when they call functions returning structures */
10175 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
10176 size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
10180 size = mono_type_size (inst->inst_vtype, &ialign);
10184 t = mono_type_get_underlying_type (inst->inst_vtype);
10186 case MONO_TYPE_GENERICINST:
10187 if (!mono_type_generic_inst_is_valuetype (t)) {
10188 slot_info = &scalar_stack_slots [t->type];
10192 case MONO_TYPE_VALUETYPE:
10193 if (!vtype_stack_slots)
10194 vtype_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * 256);
10195 for (i = 0; i < nvtypes; ++i)
10196 if (t->data.klass == vtype_stack_slots [i].vtype)
10199 slot_info = &vtype_stack_slots [i];
10201 g_assert (nvtypes < 256);
10202 vtype_stack_slots [nvtypes].vtype = t->data.klass;
10203 slot_info = &vtype_stack_slots [nvtypes];
10207 case MONO_TYPE_CLASS:
10208 case MONO_TYPE_OBJECT:
10209 case MONO_TYPE_ARRAY:
10210 case MONO_TYPE_SZARRAY:
10211 case MONO_TYPE_STRING:
10212 case MONO_TYPE_PTR:
10215 #if SIZEOF_VOID_P == 4
10219 /* Share non-float stack slots of the same size */
10220 slot_info = &scalar_stack_slots [MONO_TYPE_CLASS];
10224 slot_info = &scalar_stack_slots [t->type];
10228 if (cfg->comp_done & MONO_COMP_LIVENESS) {
10232 //printf ("START %2d %08x %08x\n", vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos);
10234 if (!current->interval->range) {
10235 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
10239 inst->flags |= MONO_INST_IS_DEAD;
10244 pos = current->interval->range->from;
10246 LSCAN_DEBUG (printf ("process R%d ", inst->dreg));
10247 if (current->interval->range)
10248 LSCAN_DEBUG (mono_linterval_print (current->interval));
10249 LSCAN_DEBUG (printf ("\n"));
10251 /* Check for intervals in active which expired or inactive */
10253 /* FIXME: Optimize this */
10256 for (l = slot_info->active; l != NULL; l = l->next) {
10257 MonoMethodVar *v = (MonoMethodVar*)l->data;
10259 if (v->interval->last_range->to < pos) {
10260 slot_info->active = g_list_delete_link (slot_info->active, l);
10261 slot_info->slots = g_slist_prepend_mempool (cfg->mempool, slot_info->slots, GINT_TO_POINTER (offsets [v->idx]));
10262 LSCAN_DEBUG (printf ("Interval R%d has expired, adding 0x%x to slots\n", cfg->varinfo [v->idx]->dreg, offsets [v->idx]));
10266 else if (!mono_linterval_covers (v->interval, pos)) {
10267 slot_info->inactive = g_list_append (slot_info->inactive, v);
10268 slot_info->active = g_list_delete_link (slot_info->active, l);
10269 LSCAN_DEBUG (printf ("Interval R%d became inactive\n", cfg->varinfo [v->idx]->dreg));
10276 /* Check for intervals in inactive which expired or active */
10278 /* FIXME: Optimize this */
10281 for (l = slot_info->inactive; l != NULL; l = l->next) {
10282 MonoMethodVar *v = (MonoMethodVar*)l->data;
10284 if (v->interval->last_range->to < pos) {
10285 slot_info->inactive = g_list_delete_link (slot_info->inactive, l);
10286 // FIXME: Enabling this seems to cause impossible to debug crashes
10287 //slot_info->slots = g_slist_prepend_mempool (cfg->mempool, slot_info->slots, GINT_TO_POINTER (offsets [v->idx]));
10288 LSCAN_DEBUG (printf ("Interval R%d has expired, adding 0x%x to slots\n", cfg->varinfo [v->idx]->dreg, offsets [v->idx]));
10292 else if (mono_linterval_covers (v->interval, pos)) {
10293 slot_info->active = g_list_append (slot_info->active, v);
10294 slot_info->inactive = g_list_delete_link (slot_info->inactive, l);
10295 LSCAN_DEBUG (printf ("\tInterval R%d became active\n", cfg->varinfo [v->idx]->dreg));
10303 * This also handles the case when the variable is used in an
10304 * exception region, as liveness info is not computed there.
10307 * FIXME: All valuetypes are marked as INDIRECT because of LDADDR
10310 if (! (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) {
10311 if (slot_info->slots) {
10312 slot = GPOINTER_TO_INT (slot_info->slots->data);
10314 slot_info->slots = slot_info->slots->next;
10317 /* FIXME: We might want to consider the inactive intervals as well if slot_info->slots is empty */
10319 slot_info->active = mono_varlist_insert_sorted (cfg, slot_info->active, vmv, TRUE);
10325 static int count = 0;
10328 if (count == atoi (getenv ("COUNT3")))
10329 printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
10330 if (count > atoi (getenv ("COUNT3")))
10333 mono_print_tree_nl (inst);
10338 LSCAN_DEBUG (printf ("R%d %s -> 0x%x\n", inst->dreg, mono_type_full_name (t), slot));
10340 if (slot == 0xffffff) {
10342 * Allways allocate valuetypes to sizeof (gpointer) to allow more
10343 * efficient copying (and to work around the fact that OP_MEMCPY
10344 * and OP_MEMSET ignores alignment).
10346 if (MONO_TYPE_ISSTRUCT (t))
10347 align = sizeof (gpointer);
10351 offset += align - 1;
10352 offset &= ~(align - 1);
10356 offset += align - 1;
10357 offset &= ~(align - 1);
10362 if (*stack_align == 0)
10363 *stack_align = align;
10366 offsets [vmv->idx] = slot;
10368 g_list_free (vars);
10369 for (i = 0; i < MONO_TYPE_PINNED; ++i) {
10370 if (scalar_stack_slots [i].active)
10371 g_list_free (scalar_stack_slots [i].active);
10373 for (i = 0; i < nvtypes; ++i) {
10374 if (vtype_stack_slots [i].active)
10375 g_list_free (vtype_stack_slots [i].active);
10378 mono_jit_stats.locals_stack_size += offset;
10380 *stack_size = offset;
10385 * mono_allocate_stack_slots_full:
10387 * Allocate stack slots for all non register allocated variables using a
10388 * linear scan algorithm.
10389 * Returns: an array of stack offsets.
10390 * STACK_SIZE is set to the amount of stack space needed.
10391 * STACK_ALIGN is set to the alignment needed by the locals area.
10394 mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align)
10396 int i, slot, offset, size;
10398 MonoMethodVar *vmv;
10401 GList *vars = NULL, *l;
10402 StackSlotInfo *scalar_stack_slots, *vtype_stack_slots, *slot_info;
10406 if ((cfg->num_varinfo > 0) && MONO_VARINFO (cfg, 0)->interval)
10407 return mono_allocate_stack_slots_full2 (cfg, backward, stack_size, stack_align);
10409 scalar_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * MONO_TYPE_PINNED);
10410 vtype_stack_slots = NULL;
10413 offsets = mono_mempool_alloc (cfg->mempool, sizeof (gint32) * cfg->num_varinfo);
10414 for (i = 0; i < cfg->num_varinfo; ++i)
10417 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
10418 inst = cfg->varinfo [i];
10419 vmv = MONO_VARINFO (cfg, i);
10421 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR || inst->opcode == OP_REGOFFSET)
10424 vars = g_list_prepend (vars, vmv);
10427 vars = mono_varlist_sort (cfg, vars, 0);
10430 for (l = vars; l; l = l->next) {
10432 inst = cfg->varinfo [vmv->idx];
10434 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
10435 * pinvoke wrappers when they call functions returning structures */
10436 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
10437 size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
10441 size = mono_type_size (inst->inst_vtype, &ialign);
10445 t = mono_type_get_underlying_type (inst->inst_vtype);
10447 slot_info = &scalar_stack_slots [MONO_TYPE_I];
10450 case MONO_TYPE_GENERICINST:
10451 if (!mono_type_generic_inst_is_valuetype (t)) {
10452 slot_info = &scalar_stack_slots [t->type];
10456 case MONO_TYPE_VALUETYPE:
10457 if (!vtype_stack_slots)
10458 vtype_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * 256);
10459 for (i = 0; i < nvtypes; ++i)
10460 if (t->data.klass == vtype_stack_slots [i].vtype)
10463 slot_info = &vtype_stack_slots [i];
10465 g_assert (nvtypes < 256);
10466 vtype_stack_slots [nvtypes].vtype = t->data.klass;
10467 slot_info = &vtype_stack_slots [nvtypes];
10471 case MONO_TYPE_CLASS:
10472 case MONO_TYPE_OBJECT:
10473 case MONO_TYPE_ARRAY:
10474 case MONO_TYPE_SZARRAY:
10475 case MONO_TYPE_STRING:
10476 case MONO_TYPE_PTR:
10479 #if SIZEOF_VOID_P == 4
10484 /* Share non-float stack slots of the same size */
10485 slot_info = &scalar_stack_slots [MONO_TYPE_CLASS];
10488 slot_info = &scalar_stack_slots [t->type];
10493 if (cfg->comp_done & MONO_COMP_LIVENESS) {
10494 //printf ("START %2d %08x %08x\n", vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos);
10496 /* expire old intervals in active */
10497 while (slot_info->active) {
10498 MonoMethodVar *amv = (MonoMethodVar *)slot_info->active->data;
10500 if (amv->range.last_use.abs_pos > vmv->range.first_use.abs_pos)
10503 //printf ("EXPIR %2d %08x %08x C%d R%d\n", amv->idx, amv->range.first_use.abs_pos, amv->range.last_use.abs_pos, amv->spill_costs, amv->reg);
10505 slot_info->active = g_list_delete_link (slot_info->active, slot_info->active);
10506 slot_info->slots = g_slist_prepend_mempool (cfg->mempool, slot_info->slots, GINT_TO_POINTER (offsets [amv->idx]));
10510 * This also handles the case when the variable is used in an
10511 * exception region, as liveness info is not computed there.
10514 * FIXME: All valuetypes are marked as INDIRECT because of LDADDR
10517 if (! (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) {
10518 if (slot_info->slots) {
10519 slot = GPOINTER_TO_INT (slot_info->slots->data);
10521 slot_info->slots = slot_info->slots->next;
10524 slot_info->active = mono_varlist_insert_sorted (cfg, slot_info->active, vmv, TRUE);
10529 static int count = 0;
10533 if (count == atoi (getenv ("COUNT")))
10534 printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
10535 if (count > atoi (getenv ("COUNT")))
10538 mono_print_tree_nl (inst);
10543 if (cfg->disable_reuse_stack_slots)
10546 if (slot == 0xffffff) {
10548 * Allways allocate valuetypes to sizeof (gpointer) to allow more
10549 * efficient copying (and to work around the fact that OP_MEMCPY
10550 * and OP_MEMSET ignores alignment).
10552 if (MONO_TYPE_ISSTRUCT (t))
10553 align = sizeof (gpointer);
10557 offset += align - 1;
10558 offset &= ~(align - 1);
10562 offset += align - 1;
10563 offset &= ~(align - 1);
10568 if (*stack_align == 0)
10569 *stack_align = align;
10572 offsets [vmv->idx] = slot;
10574 g_list_free (vars);
10575 for (i = 0; i < MONO_TYPE_PINNED; ++i) {
10576 if (scalar_stack_slots [i].active)
10577 g_list_free (scalar_stack_slots [i].active);
10579 for (i = 0; i < nvtypes; ++i) {
10580 if (vtype_stack_slots [i].active)
10581 g_list_free (vtype_stack_slots [i].active);
10584 mono_jit_stats.locals_stack_size += offset;
10586 *stack_size = offset;
10591 mono_allocate_stack_slots (MonoCompile *m, guint32 *stack_size, guint32 *stack_align)
10593 return mono_allocate_stack_slots_full (m, TRUE, stack_size, stack_align);
10599 mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align)
10601 g_assert_not_reached ();
10605 #endif /* DISABLE_JIT */
10608 mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, gboolean no_throw)
10610 MonoJitICallInfo *info;
10611 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
10613 if (!emul_opcode_map)
10614 emul_opcode_map = g_new0 (MonoJitICallInfo*, OP_LAST + 1);
10616 g_assert (!sig->hasthis);
10617 g_assert (sig->param_count < 3);
10619 info = mono_register_jit_icall (func, name, sig, no_throw);
10621 emul_opcode_map [opcode] = info;
10625 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
10627 MonoMethodSignature *sig;
10630 sig = mono_create_icall_signature (sigstr);
10634 mono_register_jit_icall (func, name, sig, save);
10638 decompose_foreach (MonoInst *tree, gpointer data)
10640 static MonoJitICallInfo *newarr_info = NULL;
10641 static MonoJitICallInfo *newarr_specific_info = NULL;
10642 MonoJitICallInfo *info;
10645 switch (tree->opcode) {
10647 MonoCompile *cfg = data;
10648 MonoInst *iargs [3];
10650 if (!newarr_info) {
10651 newarr_info = mono_find_jit_icall_by_addr (mono_array_new);
10652 g_assert (newarr_info);
10653 newarr_specific_info = mono_find_jit_icall_by_addr (mono_array_new_specific);
10654 g_assert (newarr_specific_info);
10657 if (cfg->opt & MONO_OPT_SHARED) {
10658 NEW_DOMAINCONST (cfg, iargs [0]);
10659 NEW_CLASSCONST (cfg, iargs [1], tree->inst_newa_class);
10660 iargs [2] = tree->inst_newa_len;
10662 info = newarr_info;
10665 MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (tree->inst_newa_class, 1));
10668 NEW_VTABLECONST (cfg, iargs [0], vtable);
10669 iargs [1] = tree->inst_newa_len;
10671 info = newarr_specific_info;
10674 mono_emulate_opcode (cfg, tree, iargs, info);
10676 /* Need to decompose arguments after the the opcode is decomposed */
10677 for (i = 0; i < info->sig->param_count; ++i)
10678 dec_foreach (iargs [i], cfg);
10681 #ifdef MONO_ARCH_SOFT_FLOAT
10692 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
10693 MonoCompile *cfg = data;
10694 MonoInst *iargs [2];
10696 iargs [0] = tree->inst_i0;
10697 iargs [1] = tree->inst_i1;
10699 mono_emulate_opcode (cfg, tree, iargs, info);
10701 dec_foreach (iargs [0], cfg);
10702 dec_foreach (iargs [1], cfg);
10705 g_assert_not_reached ();
10714 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
10715 MonoCompile *cfg = data;
10716 MonoInst *iargs [2];
10718 /* the args are in the compare opcode ... */
10719 iargs [0] = tree->inst_i0;
10720 iargs [1] = tree->inst_i1;
10722 mono_emulate_opcode (cfg, tree, iargs, info);
10724 dec_foreach (iargs [0], cfg);
10725 dec_foreach (iargs [1], cfg);
10728 g_assert_not_reached ();
10740 mono_inst_foreach (MonoInst *tree, MonoInstFunc func, gpointer data) {
10742 switch (mono_burg_arity [tree->opcode]) {
10745 mono_inst_foreach (tree->inst_left, func, data);
10748 mono_inst_foreach (tree->inst_left, func, data);
10749 mono_inst_foreach (tree->inst_right, func, data);
10752 g_assert_not_reached ();
10759 mono_print_bb_code (MonoBasicBlock *bb)
10763 MONO_BB_FOR_EACH_INS (bb, c) {
10764 mono_print_tree (c);
10770 print_dfn (MonoCompile *cfg) {
10773 MonoBasicBlock *bb;
10776 g_print ("IR code for method %s\n", mono_method_full_name (cfg->method, TRUE));
10778 for (i = 0; i < cfg->num_bblocks; ++i) {
10779 bb = cfg->bblocks [i];
10780 /*if (bb->cil_code) {
10781 char* code1, *code2;
10782 code1 = mono_disasm_code_one (NULL, cfg->method, bb->cil_code, NULL);
10783 if (bb->last_ins->cil_code)
10784 code2 = mono_disasm_code_one (NULL, cfg->method, bb->last_ins->cil_code, NULL);
10786 code2 = g_strdup ("");
10788 code1 [strlen (code1) - 1] = 0;
10789 code = g_strdup_printf ("%s -> %s", code1, code2);
10793 code = g_strdup ("\n");
10794 g_print ("\nBB%d (%d) (len: %d): %s", bb->block_num, i, bb->cil_length, code);
10795 MONO_BB_FOR_EACH_INS (bb, c) {
10797 mono_print_ins_index (-1, c);
10799 mono_print_tree (c);
10804 g_print ("\tprev:");
10805 for (j = 0; j < bb->in_count; ++j) {
10806 g_print (" BB%d", bb->in_bb [j]->block_num);
10808 g_print ("\t\tsucc:");
10809 for (j = 0; j < bb->out_count; ++j) {
10810 g_print (" BB%d", bb->out_bb [j]->block_num);
10812 g_print ("\n\tidom: BB%d\n", bb->idom? bb->idom->block_num: -1);
10815 g_assert (mono_bitset_test_fast (bb->dominators, bb->idom->dfn));
10817 if (bb->dominators)
10818 mono_blockset_print (cfg, bb->dominators, "\tdominators", bb->idom? bb->idom->dfn: -1);
10820 mono_blockset_print (cfg, bb->dfrontier, "\tdfrontier", -1);
10828 mono_bblock_add_inst (MonoBasicBlock *bb, MonoInst *inst)
10830 MONO_ADD_INS (bb, inst);
10834 mono_bblock_insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *ins_to_insert)
10838 bb->code = ins_to_insert;
10840 /* Link with next */
10841 ins_to_insert->next = ins;
10843 ins->prev = ins_to_insert;
10845 if (bb->last_ins == NULL)
10846 bb->last_ins = ins_to_insert;
10848 /* Link with next */
10849 ins_to_insert->next = ins->next;
10851 ins->next->prev = ins_to_insert;
10853 /* Link with previous */
10854 ins->next = ins_to_insert;
10855 ins_to_insert->prev = ins;
10857 if (bb->last_ins == ins)
10858 bb->last_ins = ins_to_insert;
10863 mono_bblock_insert_before_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *ins_to_insert)
10868 bb->code = ins_to_insert;
10869 ins_to_insert->next = ins;
10870 if (bb->last_ins == NULL)
10871 bb->last_ins = ins_to_insert;
10873 /* Link with previous */
10875 ins->prev->next = ins_to_insert;
10876 ins_to_insert->prev = ins->prev;
10878 /* Link with next */
10879 ins->prev = ins_to_insert;
10880 ins_to_insert->next = ins;
10882 if (bb->code == ins)
10883 bb->code = ins_to_insert;
10888 * mono_verify_bblock:
10890 * Verify that the next and prev pointers are consistent inside the instructions in BB.
10893 mono_verify_bblock (MonoBasicBlock *bb)
10895 MonoInst *ins, *prev;
10898 for (ins = bb->code; ins; ins = ins->next) {
10899 g_assert (ins->prev == prev);
10903 g_assert (!bb->last_ins->next);
10909 * Perform consistency checks on the JIT data structures and the IR
10912 mono_verify_cfg (MonoCompile *cfg)
10914 MonoBasicBlock *bb;
10916 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
10917 mono_verify_bblock (bb);
10921 mono_destroy_compile (MonoCompile *cfg)
10923 //mono_mempool_stats (cfg->mempool);
10924 mono_free_loop_info (cfg);
10926 mono_regstate_free (cfg->rs);
10928 g_hash_table_destroy (cfg->spvars);
10930 g_hash_table_destroy (cfg->exvars);
10931 mono_mempool_destroy (cfg->mempool);
10932 g_list_free (cfg->ldstr_list);
10933 g_hash_table_destroy (cfg->token_info_hash);
10934 if (cfg->abs_patches)
10935 g_hash_table_destroy (cfg->abs_patches);
10937 g_free (cfg->varinfo);
10938 g_free (cfg->vars);
10939 g_free (cfg->exception_message);
10943 #ifdef HAVE_KW_THREAD
10944 static __thread gpointer mono_lmf_addr MONO_TLS_FAST;
10945 #ifdef MONO_ARCH_ENABLE_MONO_LMF_VAR
10947 * When this is defined, the current lmf is stored in this tls variable instead of in
10950 static __thread gpointer mono_lmf MONO_TLS_FAST;
10955 mono_get_jit_tls_key (void)
10957 return mono_jit_tls_id;
10961 mono_get_jit_tls_offset (void)
10963 #ifdef HAVE_KW_THREAD
10965 MONO_THREAD_VAR_OFFSET (mono_jit_tls, offset);
10973 mono_get_lmf_tls_offset (void)
10975 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
10977 MONO_THREAD_VAR_OFFSET(mono_lmf,offset);
10985 mono_get_lmf_addr_tls_offset (void)
10988 MONO_THREAD_VAR_OFFSET(mono_lmf_addr,offset);
10993 mono_get_lmf (void)
10995 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
10998 MonoJitTlsData *jit_tls;
11000 if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
11001 return jit_tls->lmf;
11003 g_assert_not_reached ();
11009 mono_get_lmf_addr (void)
11011 #ifdef HAVE_KW_THREAD
11012 return mono_lmf_addr;
11014 MonoJitTlsData *jit_tls;
11016 if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
11017 return &jit_tls->lmf;
11019 g_assert_not_reached ();
11024 /* Called by native->managed wrappers */
11026 mono_jit_thread_attach (MonoDomain *domain)
11028 #ifdef HAVE_KW_THREAD
11029 if (!mono_lmf_addr) {
11030 mono_thread_attach (domain);
11033 if (!TlsGetValue (mono_jit_tls_id))
11034 mono_thread_attach (domain);
11036 if (mono_domain_get () != domain)
11037 mono_domain_set (domain, TRUE);
11041 * mono_thread_abort:
11042 * @obj: exception object
11044 * abort the thread, print exception information and stack trace
11047 mono_thread_abort (MonoObject *obj)
11049 /* MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); */
11051 /* handle_remove should be eventually called for this thread, too
11052 g_free (jit_tls);*/
11054 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANLED_POLICY_LEGACY) ||
11055 (obj->vtable->klass == mono_defaults.threadabortexception_class)) {
11056 mono_thread_exit ();
11058 exit (mono_environment_exitcode_get ());
11063 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
11065 MonoJitTlsData *jit_tls;
11068 jit_tls = TlsGetValue (mono_jit_tls_id);
11072 jit_tls = g_new0 (MonoJitTlsData, 1);
11074 TlsSetValue (mono_jit_tls_id, jit_tls);
11076 #ifdef HAVE_KW_THREAD
11077 mono_jit_tls = jit_tls;
11080 jit_tls->abort_func = abort_func;
11081 jit_tls->end_of_stack = stack_start;
11083 lmf = g_new0 (MonoLMF, 1);
11084 #ifdef MONO_ARCH_INIT_TOP_LMF_ENTRY
11085 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
11090 jit_tls->first_lmf = lmf;
11092 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
11093 /* jit_tls->lmf is unused */
11095 mono_lmf_addr = &mono_lmf;
11097 #if defined(HAVE_KW_THREAD)
11098 mono_lmf_addr = &jit_tls->lmf;
11101 jit_tls->lmf = lmf;
11104 mono_arch_setup_jit_tls_data (jit_tls);
11105 mono_setup_altstack (jit_tls);
11111 mono_thread_start_cb (gsize tid, gpointer stack_start, gpointer func)
11113 MonoThread *thread;
11114 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
11115 thread = mono_thread_current ();
11116 mono_debugger_thread_created (tid, thread, jit_tls);
11118 thread->jit_data = jit_tls;
11121 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
11124 mono_thread_abort_dummy (MonoObject *obj)
11126 if (mono_thread_attach_aborted_cb)
11127 mono_thread_attach_aborted_cb (obj);
11129 mono_thread_abort (obj);
11133 mono_thread_attach_cb (gsize tid, gpointer stack_start)
11135 MonoThread *thread;
11136 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
11137 thread = mono_thread_current ();
11138 mono_debugger_thread_created (tid, thread, (MonoJitTlsData *) jit_tls);
11140 thread->jit_data = jit_tls;
11141 if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
11142 setup_stat_profiler ();
11146 mini_thread_cleanup (MonoThread *thread)
11148 MonoJitTlsData *jit_tls = thread->jit_data;
11151 mono_debugger_thread_cleanup (jit_tls);
11152 mono_arch_free_jit_tls_data (jit_tls);
11154 mono_free_altstack (jit_tls);
11155 g_free (jit_tls->first_lmf);
11157 thread->jit_data = NULL;
11158 TlsSetValue (mono_jit_tls_id, NULL);
11163 mono_create_tls_get (MonoCompile *cfg, int offset)
11165 #ifdef MONO_ARCH_HAVE_TLS_GET
11171 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
11172 ins->dreg = cfg->new_ir ? mono_alloc_preg (cfg) : mono_regstate_next_int (cfg->rs);
11173 ins->inst_offset = offset;
11181 mono_get_jit_tls_intrinsic (MonoCompile *cfg)
11183 return mono_create_tls_get (cfg, mono_get_jit_tls_offset ());
11187 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
11189 MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
11193 ji->data.target = target;
11194 ji->next = cfg->patch_info;
11196 cfg->patch_info = ji;
11200 mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
11202 MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
11206 ji->data.target = target;
11213 mono_remove_patch_info (MonoCompile *cfg, int ip)
11215 MonoJumpInfo **ji = &cfg->patch_info;
11218 if ((*ji)->ip.i == ip)
11221 ji = &((*ji)->next);
11226 * mono_patch_info_dup_mp:
11228 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
11231 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
11233 MonoJumpInfo *res = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
11234 memcpy (res, patch_info, sizeof (MonoJumpInfo));
11236 switch (patch_info->type) {
11237 case MONO_PATCH_INFO_RVA:
11238 case MONO_PATCH_INFO_LDSTR:
11239 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
11240 case MONO_PATCH_INFO_LDTOKEN:
11241 case MONO_PATCH_INFO_DECLSEC:
11242 res->data.token = mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
11243 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
11245 case MONO_PATCH_INFO_SWITCH:
11246 res->data.table = mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
11247 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
11249 case MONO_PATCH_INFO_RGCTX_FETCH:
11250 res->data.rgctx_entry = mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
11251 memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
11252 res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
11262 mono_patch_info_hash (gconstpointer data)
11264 const MonoJumpInfo *ji = (MonoJumpInfo*)data;
11266 switch (ji->type) {
11267 case MONO_PATCH_INFO_RVA:
11268 case MONO_PATCH_INFO_LDSTR:
11269 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
11270 case MONO_PATCH_INFO_LDTOKEN:
11271 case MONO_PATCH_INFO_DECLSEC:
11272 return (ji->type << 8) | ji->data.token->token;
11273 case MONO_PATCH_INFO_VTABLE:
11274 case MONO_PATCH_INFO_CLASS:
11275 case MONO_PATCH_INFO_IID:
11276 case MONO_PATCH_INFO_ADJUSTED_IID:
11277 case MONO_PATCH_INFO_CLASS_INIT:
11278 case MONO_PATCH_INFO_METHODCONST:
11279 case MONO_PATCH_INFO_METHOD:
11280 case MONO_PATCH_INFO_METHOD_JUMP:
11281 case MONO_PATCH_INFO_IMAGE:
11282 case MONO_PATCH_INFO_INTERNAL_METHOD:
11283 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
11284 case MONO_PATCH_INFO_FIELD:
11285 case MONO_PATCH_INFO_SFLDA:
11286 return (ji->type << 8) | (gssize)ji->data.target;
11288 return (ji->type << 8);
11293 * mono_patch_info_equal:
11295 * This might fail to recognize equivalent patches, i.e. floats, so its only
11296 * usable in those cases where this is not a problem, i.e. sharing GOT slots
11300 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
11302 const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
11303 const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
11305 if (ji1->type != ji2->type)
11308 switch (ji1->type) {
11309 case MONO_PATCH_INFO_RVA:
11310 case MONO_PATCH_INFO_LDSTR:
11311 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
11312 case MONO_PATCH_INFO_LDTOKEN:
11313 case MONO_PATCH_INFO_DECLSEC:
11314 if ((ji1->data.token->image != ji2->data.token->image) ||
11315 (ji1->data.token->token != ji2->data.token->token))
11319 if (ji1->data.target != ji2->data.target)
11328 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors)
11330 unsigned char *ip = patch_info->ip.i + code;
11331 gconstpointer target = NULL;
11333 switch (patch_info->type) {
11334 case MONO_PATCH_INFO_BB:
11335 g_assert (patch_info->data.bb->native_offset);
11336 target = patch_info->data.bb->native_offset + code;
11338 case MONO_PATCH_INFO_ABS:
11339 target = patch_info->data.target;
11341 case MONO_PATCH_INFO_LABEL:
11342 target = patch_info->data.inst->inst_c0 + code;
11344 case MONO_PATCH_INFO_IP:
11347 case MONO_PATCH_INFO_METHOD_REL:
11348 target = code + patch_info->data.offset;
11350 case MONO_PATCH_INFO_INTERNAL_METHOD: {
11351 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
11353 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
11354 g_assert_not_reached ();
11356 target = mono_icall_get_wrapper (mi);
11359 case MONO_PATCH_INFO_METHOD_JUMP:
11360 target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE);
11362 case MONO_PATCH_INFO_METHOD:
11363 if (patch_info->data.method == method) {
11366 /* get the trampoline to the method from the domain */
11367 if (method && method->wrapper_type == MONO_WRAPPER_STATIC_RGCTX_INVOKE) {
11368 target = mono_create_jit_trampoline_in_domain (mono_domain_get (),
11369 patch_info->data.method);
11371 target = mono_create_jit_trampoline (patch_info->data.method);
11375 case MONO_PATCH_INFO_SWITCH: {
11376 gpointer *jump_table;
11379 if (method && method->dynamic) {
11380 jump_table = mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
11382 mono_domain_lock (domain);
11384 jump_table = mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
11386 jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
11387 mono_domain_unlock (domain);
11390 for (i = 0; i < patch_info->data.table->table_size; i++)
11391 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
11392 target = jump_table;
11395 case MONO_PATCH_INFO_METHODCONST:
11396 case MONO_PATCH_INFO_CLASS:
11397 case MONO_PATCH_INFO_IMAGE:
11398 case MONO_PATCH_INFO_FIELD:
11399 target = patch_info->data.target;
11401 case MONO_PATCH_INFO_IID:
11402 mono_class_init (patch_info->data.klass);
11403 target = GINT_TO_POINTER ((int)patch_info->data.klass->interface_id);
11405 case MONO_PATCH_INFO_ADJUSTED_IID:
11406 mono_class_init (patch_info->data.klass);
11407 target = GINT_TO_POINTER ((int)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
11409 case MONO_PATCH_INFO_VTABLE:
11410 target = mono_class_vtable (domain, patch_info->data.klass);
11413 case MONO_PATCH_INFO_CLASS_INIT: {
11414 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.klass);
11417 target = mono_create_class_init_trampoline (vtable);
11420 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
11421 target = mono_create_delegate_trampoline (patch_info->data.klass);
11423 case MONO_PATCH_INFO_SFLDA: {
11424 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
11427 if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
11428 /* Done by the generated code */
11432 mono_runtime_class_init (vtable);
11434 target = (char*)vtable->data + patch_info->data.field->offset;
11437 case MONO_PATCH_INFO_RVA:
11438 target = mono_image_rva_map (patch_info->data.token->image, patch_info->data.token->token);
11440 case MONO_PATCH_INFO_R4:
11441 case MONO_PATCH_INFO_R8:
11442 target = patch_info->data.target;
11444 case MONO_PATCH_INFO_EXC_NAME:
11445 target = patch_info->data.name;
11447 case MONO_PATCH_INFO_LDSTR:
11449 mono_ldstr (domain, patch_info->data.token->image,
11450 mono_metadata_token_index (patch_info->data.token->token));
11452 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
11454 MonoClass *handle_class;
11456 handle = mono_ldtoken (patch_info->data.token->image,
11457 patch_info->data.token->token, &handle_class, NULL);
11458 mono_class_init (handle_class);
11459 mono_class_init (mono_class_from_mono_type (handle));
11462 mono_type_get_object (domain, handle);
11465 case MONO_PATCH_INFO_LDTOKEN: {
11467 MonoClass *handle_class;
11469 handle = mono_ldtoken (patch_info->data.token->image,
11470 patch_info->data.token->token, &handle_class, NULL);
11471 mono_class_init (handle_class);
11476 case MONO_PATCH_INFO_DECLSEC:
11477 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
11479 case MONO_PATCH_INFO_ICALL_ADDR:
11480 target = mono_lookup_internal_call (patch_info->data.method);
11481 /* run_cctors == 0 -> AOT */
11482 if (!target && run_cctors)
11483 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
11485 case MONO_PATCH_INFO_JIT_ICALL_ADDR: {
11486 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
11488 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
11489 g_assert_not_reached ();
11494 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
11495 target = mono_thread_interruption_request_flag ();
11497 case MONO_PATCH_INFO_METHOD_RGCTX:
11498 target = mono_method_lookup_rgctx (mono_class_vtable (domain, patch_info->data.method->klass), mini_method_get_context (patch_info->data.method)->method_inst);
11500 case MONO_PATCH_INFO_BB_OVF:
11501 case MONO_PATCH_INFO_EXC_OVF:
11502 case MONO_PATCH_INFO_GOT_OFFSET:
11503 case MONO_PATCH_INFO_NONE:
11505 case MONO_PATCH_INFO_RGCTX_FETCH: {
11506 MonoJumpInfoRgctxEntry *entry = patch_info->data.rgctx_entry;
11509 switch (entry->data->type) {
11510 case MONO_PATCH_INFO_CLASS:
11511 slot = mono_method_lookup_or_register_other_info (entry->method, entry->in_mrgctx, &entry->data->data.klass->byval_arg, entry->info_type, mono_method_get_context (entry->method));
11513 case MONO_PATCH_INFO_METHOD:
11514 case MONO_PATCH_INFO_METHODCONST:
11515 slot = mono_method_lookup_or_register_other_info (entry->method, entry->in_mrgctx, entry->data->data.method, entry->info_type, mono_method_get_context (entry->method));
11517 case MONO_PATCH_INFO_FIELD:
11518 slot = mono_method_lookup_or_register_other_info (entry->method, entry->in_mrgctx, entry->data->data.field, entry->info_type, mono_method_get_context (entry->method));
11521 g_assert_not_reached ();
11525 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
11528 case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
11529 target = mono_create_generic_class_init_trampoline ();
11532 g_assert_not_reached ();
11535 return (gpointer)target;
11539 dec_foreach (MonoInst *tree, MonoCompile *cfg) {
11540 MonoJitICallInfo *info;
11542 decompose_foreach (tree, cfg);
11544 switch (mono_burg_arity [tree->opcode]) {
11547 dec_foreach (tree->inst_left, cfg);
11549 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
11550 MonoInst *iargs [2];
11552 iargs [0] = tree->inst_left;
11554 mono_emulate_opcode (cfg, tree, iargs, info);
11560 #ifdef MONO_ARCH_BIGMUL_INTRINS
11561 if (tree->opcode == OP_LMUL
11562 && (cfg->opt & MONO_OPT_INTRINS)
11563 && (tree->inst_left->opcode == CEE_CONV_I8
11564 || tree->inst_left->opcode == CEE_CONV_U8)
11565 && tree->inst_left->inst_left->type == STACK_I4
11566 && (tree->inst_right->opcode == CEE_CONV_I8
11567 || tree->inst_right->opcode == CEE_CONV_U8)
11568 && tree->inst_right->inst_left->type == STACK_I4
11569 && tree->inst_left->opcode == tree->inst_right->opcode) {
11570 tree->opcode = (tree->inst_left->opcode == CEE_CONV_I8 ? OP_BIGMUL: OP_BIGMUL_UN);
11571 tree->inst_left = tree->inst_left->inst_left;
11572 tree->inst_right = tree->inst_right->inst_left;
11573 dec_foreach (tree, cfg);
11576 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
11577 MonoInst *iargs [2];
11579 iargs [0] = tree->inst_i0;
11580 iargs [1] = tree->inst_i1;
11582 mono_emulate_opcode (cfg, tree, iargs, info);
11584 dec_foreach (iargs [0], cfg);
11585 dec_foreach (iargs [1], cfg);
11588 dec_foreach (tree->inst_left, cfg);
11589 dec_foreach (tree->inst_right, cfg);
11593 g_assert_not_reached ();
11598 decompose_pass (MonoCompile *cfg) {
11599 MonoBasicBlock *bb;
11601 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11604 cfg->prev_ins = NULL;
11605 MONO_BB_FOR_EACH_INS (cfg->cbb, tree) {
11606 dec_foreach (tree, cfg);
11607 cfg->prev_ins = tree;
11613 mono_compile_create_vars (MonoCompile *cfg)
11615 MonoMethodSignature *sig;
11616 MonoMethodHeader *header;
11619 header = mono_method_get_header (cfg->method);
11621 sig = mono_method_signature (cfg->method);
11623 if (!MONO_TYPE_IS_VOID (sig->ret)) {
11625 cfg->ret = mono_compile_create_var (cfg, sig->ret, OP_ARG);
11626 /* Inhibit optimizations */
11627 cfg->ret->flags |= MONO_INST_VOLATILE;
11629 cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
11630 cfg->ret->opcode = OP_RETARG;
11631 cfg->ret->inst_vtype = sig->ret;
11632 cfg->ret->klass = mono_class_from_mono_type (sig->ret);
11635 if (cfg->verbose_level > 2)
11636 g_print ("creating vars\n");
11638 cfg->args = mono_mempool_alloc0 (cfg->mempool, (sig->param_count + sig->hasthis) * sizeof (MonoInst*));
11641 cfg->args [0] = mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
11643 for (i = 0; i < sig->param_count; ++i) {
11644 cfg->args [i + sig->hasthis] = mono_compile_create_var (cfg, sig->params [i], OP_ARG);
11645 if (sig->params [i]->byref) {
11646 if (!cfg->new_ir) cfg->disable_ssa = TRUE;
11650 if (cfg->new_ir && cfg->verbose_level > 2) {
11652 printf ("\treturn : ");
11653 mono_print_ins (cfg->ret);
11656 if (sig->hasthis) {
11657 printf ("\tthis: ");
11658 mono_print_ins (cfg->args [0]);
11661 for (i = 0; i < sig->param_count; ++i) {
11662 printf ("\targ [%d]: ", i);
11663 mono_print_ins (cfg->args [i + sig->hasthis]);
11667 cfg->locals_start = cfg->num_varinfo;
11668 cfg->locals = mono_mempool_alloc0 (cfg->mempool, header->num_locals * sizeof (MonoInst*));
11670 if (cfg->verbose_level > 2)
11671 g_print ("creating locals\n");
11673 for (i = 0; i < header->num_locals; ++i)
11674 cfg->locals [i] = mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
11676 if (cfg->verbose_level > 2)
11677 g_print ("locals done\n");
11679 mono_arch_create_vars (cfg);
11683 mono_print_code (MonoCompile *cfg, const char* msg)
11685 MonoBasicBlock *bb;
11687 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11688 MonoInst *tree = bb->code;
11691 mono_print_bb (bb, msg);
11696 g_print ("%s CODE BLOCK %d (nesting %d):\n", msg, bb->block_num, bb->nesting);
11698 MONO_BB_FOR_EACH_INS (bb, tree) {
11699 mono_print_tree (tree);
11706 #ifndef DISABLE_JIT
11708 extern const char * const mono_burg_rule_string [];
11711 emit_state (MonoCompile *cfg, MBState *state, int goal)
11713 MBState *kids [10];
11714 int ern = mono_burg_rule (state, goal);
11715 const guint16 *nts = mono_burg_nts_data + mono_burg_nts [ern];
11717 //g_print ("rule: %s\n", mono_burg_rule_string [ern]);
11721 // state->reg1 = state->reg2; /* chain rule */
11723 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
11726 state->reg1 = mono_regstate_next_int (cfg->rs);
11727 //g_print ("alloc symbolic R%d (reg2: R%d) in block %d\n", state->reg1, state->reg2, cfg->cbb->block_num);
11729 case MB_NTERM_lreg:
11730 state->reg1 = mono_regstate_next_int (cfg->rs);
11731 state->reg2 = mono_regstate_next_int (cfg->rs);
11733 case MB_NTERM_freg:
11734 #ifdef MONO_ARCH_SOFT_FLOAT
11735 state->reg1 = mono_regstate_next_int (cfg->rs);
11736 state->reg2 = mono_regstate_next_int (cfg->rs);
11738 state->reg1 = mono_regstate_next_float (cfg->rs);
11742 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
11744 * Enabling this might cause bugs to surface in the local register
11745 * allocators on some architectures like x86.
11747 if ((state->tree->ssa_op == MONO_SSA_STORE) && (state->left->tree->opcode == OP_REGVAR)) {
11748 /* Do not optimize away reg-reg moves */
11749 if (! ((state->right->tree->ssa_op == MONO_SSA_LOAD) && (state->right->left->tree->opcode == OP_REGVAR))) {
11750 state->right->reg1 = state->left->tree->dreg;
11759 mono_burg_kids (state, ern, kids);
11761 emit_state (cfg, kids [0], nts [0]);
11763 emit_state (cfg, kids [1], nts [1]);
11765 emit_state (cfg, kids [2], nts [2]);
11767 g_assert (!nts [4]);
11768 emit_state (cfg, kids [3], nts [3]);
11774 // g_print ("emit: %s (%p)\n", mono_burg_rule_string [ern], state);
11775 mono_burg_emit (ern, state, state->tree, cfg);
11778 #define DEBUG_SELECTION
11781 mini_select_instructions (MonoCompile *cfg)
11783 MonoBasicBlock *bb;
11785 cfg->state_pool = mono_mempool_new ();
11786 cfg->rs = mono_regstate_new ();
11788 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11789 if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins) &&
11790 bb->last_ins->inst_false_bb && bb->next_bb != bb->last_ins->inst_false_bb) {
11792 /* we are careful when inverting, since bugs like #59580
11793 * could show up when dealing with NaNs.
11795 if (MONO_IS_COND_BRANCH_NOFP(bb->last_ins) && bb->next_bb == bb->last_ins->inst_true_bb) {
11796 MonoBasicBlock *tmp = bb->last_ins->inst_true_bb;
11797 bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
11798 bb->last_ins->inst_false_bb = tmp;
11800 bb->last_ins->opcode = mono_reverse_branch_op (bb->last_ins->opcode);
11804 MONO_INST_NEW (cfg, ins, OP_BR);
11805 ins->inst_target_bb = bb->last_ins->inst_false_bb;
11806 MONO_ADD_INS (bb, ins);
11811 #ifdef DEBUG_SELECTION
11812 if (cfg->verbose_level >= 4) {
11813 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11815 g_print ("DUMP BLOCK %d:\n", bb->block_num);
11816 MONO_BB_FOR_EACH_INS (bb, tree) {
11817 mono_print_tree (tree);
11824 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11825 MonoInst *tree = bb->code, *next;
11831 bb->last_ins = NULL;
11834 mono_regstate_reset (cfg->rs);
11836 #ifdef DEBUG_SELECTION
11837 if (cfg->verbose_level >= 3)
11838 g_print ("LABEL BLOCK %d:\n", bb->block_num);
11840 for (; tree; tree = next) {
11842 #ifdef DEBUG_SELECTION
11843 if (cfg->verbose_level >= 3) {
11844 mono_print_tree (tree);
11849 cfg->ip = tree->cil_code;
11850 if (!(mbstate = mono_burg_label (tree, cfg))) {
11851 g_warning ("unable to label tree %p", tree);
11852 mono_print_tree (tree);
11854 g_assert_not_reached ();
11856 emit_state (cfg, mbstate, MB_NTERM_stmt);
11858 bb->max_vreg = cfg->rs->next_vreg;
11861 bb->last_ins->next = NULL;
11863 mono_mempool_empty (cfg->state_pool);
11865 mono_mempool_destroy (cfg->state_pool);
11871 * mono_normalize_opcodes:
11873 * Replace CEE_ and OP_ opcodes with the corresponding OP_I or OP_L opcodes.
11876 static gint16 *remap_table;
11878 #if SIZEOF_VOID_P == 8
11879 #define REMAP_OPCODE(opcode) OP_L ## opcode
11881 #define REMAP_OPCODE(opcode) OP_I ## opcode
11884 static G_GNUC_UNUSED void
11885 mono_normalize_opcodes (MonoCompile *cfg, MonoBasicBlock *bb)
11889 if (!remap_table) {
11890 remap_table = g_new0 (gint16, OP_LAST);
11892 #if SIZEOF_VOID_P == 8
11893 remap_table [CEE_CONV_U8] = OP_ZEXT_I4;
11894 remap_table [CEE_CONV_U] = OP_ZEXT_I4;
11895 remap_table [CEE_CONV_I8] = OP_SEXT_I4;
11896 remap_table [CEE_CONV_I] = OP_SEXT_I4;
11897 remap_table [CEE_CONV_OVF_U4] = OP_LCONV_TO_OVF_U4;
11898 remap_table [CEE_CONV_OVF_I4_UN] = OP_LCONV_TO_OVF_I4_UN;
11901 remap_table [CEE_CONV_R4] = OP_ICONV_TO_R4;
11902 remap_table [CEE_CONV_R8] = OP_ICONV_TO_R8;
11903 remap_table [CEE_CONV_I4] = OP_MOVE;
11904 remap_table [CEE_CONV_U4] = OP_MOVE;
11905 remap_table [CEE_CONV_I1] = REMAP_OPCODE (CONV_TO_I1);
11906 remap_table [CEE_CONV_I2] = REMAP_OPCODE (CONV_TO_I2);
11907 remap_table [CEE_CONV_U1] = REMAP_OPCODE (CONV_TO_U1);
11908 remap_table [CEE_CONV_U2] = REMAP_OPCODE (CONV_TO_U2);
11909 remap_table [CEE_CONV_R_UN] = REMAP_OPCODE (CONV_TO_R_UN);
11910 remap_table [CEE_ADD] = REMAP_OPCODE (ADD);
11911 remap_table [CEE_SUB] = REMAP_OPCODE (SUB);
11912 remap_table [CEE_MUL] = REMAP_OPCODE (MUL);
11913 remap_table [CEE_DIV] = REMAP_OPCODE (DIV);
11914 remap_table [CEE_REM] = REMAP_OPCODE (REM);
11915 remap_table [CEE_DIV_UN] = REMAP_OPCODE (DIV_UN);
11916 remap_table [CEE_REM_UN] = REMAP_OPCODE (REM_UN);
11917 remap_table [CEE_AND] = REMAP_OPCODE (AND);
11918 remap_table [CEE_OR] = REMAP_OPCODE (OR);
11919 remap_table [CEE_XOR] = REMAP_OPCODE (XOR);
11920 remap_table [CEE_SHL] = REMAP_OPCODE (SHL);
11921 remap_table [CEE_SHR] = REMAP_OPCODE (SHR);
11922 remap_table [CEE_SHR_UN] = REMAP_OPCODE (SHR_UN);
11923 remap_table [CEE_NOT] = REMAP_OPCODE (NOT);
11924 remap_table [CEE_NEG] = REMAP_OPCODE (NEG);
11925 remap_table [CEE_CALL] = OP_CALL;
11926 remap_table [CEE_BEQ] = REMAP_OPCODE (BEQ);
11927 remap_table [CEE_BNE_UN] = REMAP_OPCODE (BNE_UN);
11928 remap_table [CEE_BLT] = REMAP_OPCODE (BLT);
11929 remap_table [CEE_BLT_UN] = REMAP_OPCODE (BLT_UN);
11930 remap_table [CEE_BGT] = REMAP_OPCODE (BGT);
11931 remap_table [CEE_BGT_UN] = REMAP_OPCODE (BGT_UN);
11932 remap_table [CEE_BGE] = REMAP_OPCODE (BGE);
11933 remap_table [CEE_BGE_UN] = REMAP_OPCODE (BGE_UN);
11934 remap_table [CEE_BLE] = REMAP_OPCODE (BLE);
11935 remap_table [CEE_BLE_UN] = REMAP_OPCODE (BLE_UN);
11936 remap_table [CEE_ADD_OVF] = REMAP_OPCODE (ADD_OVF);
11937 remap_table [CEE_ADD_OVF_UN] = REMAP_OPCODE (ADD_OVF_UN);
11938 remap_table [CEE_SUB_OVF] = REMAP_OPCODE (SUB_OVF);
11939 remap_table [CEE_SUB_OVF_UN] = REMAP_OPCODE (SUB_OVF_UN);
11940 remap_table [CEE_MUL_OVF] = REMAP_OPCODE (MUL_OVF);
11941 remap_table [CEE_MUL_OVF_UN] = REMAP_OPCODE (MUL_OVF_UN);
11944 MONO_BB_FOR_EACH_INS (bb, ins) {
11945 int remapped = remap_table [ins->opcode];
11947 ins->opcode = remapped;
11952 mono_codegen (MonoCompile *cfg)
11954 MonoJumpInfo *patch_info;
11955 MonoBasicBlock *bb;
11956 int i, max_epilog_size;
11959 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11960 cfg->spill_count = 0;
11961 /* we reuse dfn here */
11962 /* bb->dfn = bb_count++; */
11963 #ifdef MONO_ARCH_ENABLE_NORMALIZE_OPCODES
11965 mono_normalize_opcodes (cfg, bb);
11968 mono_arch_lowering_pass (cfg, bb);
11970 if (cfg->opt & MONO_OPT_PEEPHOLE)
11971 mono_arch_peephole_pass_1 (cfg, bb);
11973 if (!cfg->globalra)
11974 mono_local_regalloc (cfg, bb);
11976 if (cfg->opt & MONO_OPT_PEEPHOLE)
11977 mono_arch_peephole_pass_2 (cfg, bb);
11980 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
11981 cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, cfg->num_bblocks);
11983 code = mono_arch_emit_prolog (cfg);
11985 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
11986 code = mono_arch_instrument_prolog (cfg, mono_profiler_method_enter, code, FALSE);
11988 cfg->code_len = code - cfg->native_code;
11989 cfg->prolog_end = cfg->code_len;
11991 mono_debug_open_method (cfg);
11993 /* emit code all basic blocks */
11994 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11995 bb->native_offset = cfg->code_len;
11996 //if ((bb == cfg->bb_entry) || !(bb->region == -1 && !bb->dfn))
11997 mono_arch_output_basic_block (cfg, bb);
11999 if (bb == cfg->bb_exit) {
12000 cfg->epilog_begin = cfg->code_len;
12002 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
12003 code = cfg->native_code + cfg->code_len;
12004 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
12005 cfg->code_len = code - cfg->native_code;
12006 g_assert (cfg->code_len < cfg->code_size);
12009 mono_arch_emit_epilog (cfg);
12013 mono_arch_emit_exceptions (cfg);
12015 max_epilog_size = 0;
12017 code = cfg->native_code + cfg->code_len;
12019 /* we always allocate code in cfg->domain->code_mp to increase locality */
12020 cfg->code_size = cfg->code_len + max_epilog_size;
12021 /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
12023 if (cfg->method->dynamic) {
12024 guint unwindlen = 0;
12025 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
12026 unwindlen = mono_arch_unwindinfo_get_size (cfg->arch.unwindinfo);
12028 /* Allocate the code into a separate memory pool so it can be freed */
12029 cfg->dynamic_info = g_new0 (MonoJitDynamicMethodInfo, 1);
12030 cfg->dynamic_info->code_mp = mono_code_manager_new_dynamic ();
12031 mono_domain_lock (cfg->domain);
12032 mono_dynamic_code_hash_insert (cfg->domain, cfg->method, cfg->dynamic_info);
12033 mono_domain_unlock (cfg->domain);
12035 code = mono_code_manager_reserve (cfg->dynamic_info->code_mp, cfg->code_size + unwindlen);
12037 guint unwindlen = 0;
12038 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
12039 unwindlen = mono_arch_unwindinfo_get_size (cfg->arch.unwindinfo);
12041 mono_domain_lock (cfg->domain);
12042 code = mono_code_manager_reserve (cfg->domain->code_mp, cfg->code_size + unwindlen);
12043 mono_domain_unlock (cfg->domain);
12046 memcpy (code, cfg->native_code, cfg->code_len);
12047 g_free (cfg->native_code);
12048 cfg->native_code = code;
12049 code = cfg->native_code + cfg->code_len;
12051 /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
12052 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
12053 switch (patch_info->type) {
12054 case MONO_PATCH_INFO_ABS: {
12055 MonoJitICallInfo *info = mono_find_jit_icall_by_addr (patch_info->data.target);
12058 * Change patches of type MONO_PATCH_INFO_ABS into patches describing the
12059 * absolute address.
12062 //printf ("TEST %s %p\n", info->name, patch_info->data.target);
12063 // FIXME: CLEAN UP THIS MESS.
12064 if ((cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) &&
12065 strstr (cfg->method->name, info->name)) {
12067 * This is an icall wrapper, and this is a call to the
12068 * wrapped function.
12070 if (cfg->compile_aot) {
12071 patch_info->type = MONO_PATCH_INFO_JIT_ICALL_ADDR;
12072 patch_info->data.name = info->name;
12075 /* for these array methods we currently register the same function pointer
12076 * since it's a vararg function. But this means that mono_find_jit_icall_by_addr ()
12077 * will return the incorrect one depending on the order they are registered.
12078 * See tests/test-arr.cs
12080 if (strstr (info->name, "ves_array_new_va_") == NULL && strstr (info->name, "ves_array_element_address_") == NULL) {
12081 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
12082 patch_info->data.name = info->name;
12087 if (patch_info->type == MONO_PATCH_INFO_ABS && !cfg->new_ir) {
12088 MonoVTable *vtable = mono_find_class_init_trampoline_by_addr (patch_info->data.target);
12090 patch_info->type = MONO_PATCH_INFO_CLASS_INIT;
12091 patch_info->data.klass = vtable->klass;
12095 if (patch_info->type == MONO_PATCH_INFO_ABS) {
12096 MonoClass *klass = mono_find_delegate_trampoline_by_addr (patch_info->data.target);
12098 patch_info->type = MONO_PATCH_INFO_DELEGATE_TRAMPOLINE;
12099 patch_info->data.klass = klass;
12103 if (patch_info->type == MONO_PATCH_INFO_ABS) {
12104 if (cfg->abs_patches) {
12105 MonoJumpInfo *abs_ji = g_hash_table_lookup (cfg->abs_patches, patch_info->data.target);
12107 patch_info->type = abs_ji->type;
12108 patch_info->data.target = abs_ji->data.target;
12115 case MONO_PATCH_INFO_SWITCH: {
12117 if (cfg->method->dynamic) {
12118 table = mono_code_manager_reserve (cfg->dynamic_info->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
12120 mono_domain_lock (cfg->domain);
12121 table = mono_code_manager_reserve (cfg->domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
12122 mono_domain_unlock (cfg->domain);
12125 if (!cfg->compile_aot && !cfg->new_ir)
12126 /* In the aot case, the patch already points to the correct location */
12127 patch_info->ip.i = patch_info->ip.label->inst_c0;
12128 for (i = 0; i < patch_info->data.table->table_size; i++) {
12129 /* Might be NULL if the switch is eliminated */
12130 if (patch_info->data.table->table [i]) {
12131 g_assert (patch_info->data.table->table [i]->native_offset);
12132 table [i] = GINT_TO_POINTER (patch_info->data.table->table [i]->native_offset);
12137 patch_info->data.table->table = (MonoBasicBlock**)table;
12140 case MONO_PATCH_INFO_METHOD_JUMP: {
12142 MonoDomain *domain = cfg->domain;
12143 unsigned char *ip = cfg->native_code + patch_info->ip.i;
12145 mono_domain_lock (domain);
12146 if (!domain_jit_info (domain)->jump_target_hash)
12147 domain_jit_info (domain)->jump_target_hash = g_hash_table_new (NULL, NULL);
12148 list = g_hash_table_lookup (domain_jit_info (domain)->jump_target_hash, patch_info->data.method);
12149 list = g_slist_prepend (list, ip);
12150 g_hash_table_insert (domain_jit_info (domain)->jump_target_hash, patch_info->data.method, list);
12151 mono_domain_unlock (domain);
12160 #ifdef VALGRIND_JIT_REGISTER_MAP
12161 if (valgrind_register){
12162 char* nm = mono_method_full_name (cfg->method, TRUE);
12163 VALGRIND_JIT_REGISTER_MAP (nm, cfg->native_code, cfg->native_code + cfg->code_len);
12168 if (cfg->verbose_level > 0) {
12169 char* nm = mono_method_full_name (cfg->method, TRUE);
12170 g_print ("Method %s emitted at %p to %p (code length %d) [%s]\n",
12172 cfg->native_code, cfg->native_code + cfg->code_len, cfg->code_len, cfg->domain->friendly_name);
12177 gboolean is_generic = FALSE;
12179 if (cfg->method->is_inflated || mono_method_get_generic_container (cfg->method) ||
12180 cfg->method->klass->generic_container || cfg->method->klass->generic_class) {
12184 if (cfg->generic_sharing_context)
12185 g_assert (is_generic);
12188 #ifdef MONO_ARCH_HAVE_SAVE_UNWIND_INFO
12189 mono_arch_save_unwind_info (cfg);
12192 mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors);
12194 if (cfg->method->dynamic) {
12195 mono_code_manager_commit (cfg->dynamic_info->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
12197 mono_domain_lock (cfg->domain);
12198 mono_code_manager_commit (cfg->domain->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
12199 mono_domain_unlock (cfg->domain);
12202 mono_arch_flush_icache (cfg->native_code, cfg->code_len);
12204 mono_debug_close_method (cfg);
12205 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
12206 mono_arch_unwindinfo_install_unwind_info (&cfg->arch.unwindinfo, cfg->native_code, cfg->code_len);
12210 static MonoGenericInst*
12211 get_object_generic_inst (int type_argc)
12213 MonoType **type_argv;
12216 type_argv = alloca (sizeof (MonoType*) * type_argc);
12218 for (i = 0; i < type_argc; ++i)
12219 type_argv [i] = &mono_defaults.object_class->byval_arg;
12221 return mono_metadata_get_generic_inst (type_argc, type_argv);
12225 * mini_method_compile:
12226 * @method: the method to compile
12227 * @opts: the optimization flags to use
12228 * @domain: the domain where the method will be compiled in
12229 * @run_cctors: whether we should run type ctors if possible
12230 * @compile_aot: whether this is an AOT compilation
12231 * @parts: debug flag
12233 * Returns: a MonoCompile* pointer. Caller must check the exception_type
12234 * field in the returned struct to see if compilation succeded.
12237 mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
12239 MonoMethodHeader *header;
12242 MonoJitInfo *jinfo;
12243 int dfn, i, code_size_ratio;
12244 gboolean deadce_has_run = FALSE;
12245 gboolean try_generic_shared;
12246 MonoMethod *method_to_compile, *method_to_register;
12247 int generic_info_size;
12249 mono_jit_stats.methods_compiled++;
12250 if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
12251 mono_profiler_method_jit (method);
12252 if (MONO_PROBE_METHOD_COMPILE_BEGIN_ENABLED ())
12253 MONO_PROBE_METHOD_COMPILE_BEGIN (method);
12256 /* We are passed the original generic method definition */
12257 try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
12258 (opts & MONO_OPT_GSHARED) && (method->is_generic || method->klass->generic_container);
12260 try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
12261 (opts & MONO_OPT_GSHARED) && mono_method_is_generic_sharable_impl (method, FALSE);
12263 if (opts & MONO_OPT_GSHARED) {
12264 if (try_generic_shared)
12265 mono_stats.generics_sharable_methods++;
12266 else if (mono_method_is_generic_impl (method))
12267 mono_stats.generics_unsharable_methods++;
12271 if (try_generic_shared) {
12272 MonoMethod *declaring_method;
12273 MonoGenericContext *shared_context;
12276 declaring_method = method;
12278 declaring_method = mono_method_get_declaring_generic_method (method);
12279 if (method->klass->generic_class)
12280 g_assert (method->klass->generic_class->container_class == declaring_method->klass);
12282 g_assert (method->klass == declaring_method->klass);
12285 if (declaring_method->is_generic)
12286 shared_context = &(mono_method_get_generic_container (declaring_method)->context);
12288 shared_context = &declaring_method->klass->generic_container->context;
12290 method_to_compile = mono_class_inflate_generic_method (declaring_method, shared_context);
12291 g_assert (method_to_compile);
12293 method_to_compile = method;
12296 cfg = g_new0 (MonoCompile, 1);
12297 cfg->method = method_to_compile;
12298 cfg->mempool = mono_mempool_new ();
12300 cfg->prof_options = mono_profiler_get_events ();
12301 cfg->run_cctors = run_cctors;
12302 cfg->domain = domain;
12303 cfg->verbose_level = mini_verbose;
12304 cfg->compile_aot = compile_aot;
12305 cfg->skip_visibility = method->skip_visibility;
12306 cfg->orig_method = method;
12307 if (try_generic_shared)
12308 cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->generic_sharing_context;
12309 cfg->token_info_hash = g_hash_table_new (NULL, NULL);
12311 if (cfg->compile_aot && !try_generic_shared && (method->is_generic || method->klass->generic_container)) {
12312 cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED;
12316 /* The debugger has no liveness information, so avoid sharing registers/stack slots */
12317 if (mono_debug_using_mono_debugger () || debug_options.mdb_optimizations) {
12318 cfg->disable_reuse_registers = TRUE;
12319 cfg->disable_reuse_stack_slots = TRUE;
12321 * This decreases the change the debugger will read registers/stack slots which are
12322 * not yet initialized.
12324 cfg->disable_initlocals_opt = TRUE;
12326 /* Temporarily disable this when running in the debugger until we have support
12327 * for this in the debugger. */
12328 cfg->disable_omit_fp = TRUE;
12330 /* The debugger needs all locals to be on the stack or in a global register */
12331 cfg->disable_vreg_to_lvreg = TRUE;
12333 // cfg->opt |= MONO_OPT_SHARED;
12334 cfg->opt &= ~MONO_OPT_INLINE;
12335 cfg->opt &= ~MONO_OPT_COPYPROP;
12336 cfg->opt &= ~MONO_OPT_CONSPROP;
12337 cfg->opt &= ~MONO_OPT_GSHARED;
12340 header = mono_method_get_header (method_to_compile);
12342 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
12343 cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
12344 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
12345 MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
12346 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
12347 mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
12351 if (getenv ("MONO_VERBOSE_METHOD")) {
12352 if (strcmp (cfg->method->name, getenv ("MONO_VERBOSE_METHOD")) == 0)
12353 cfg->verbose_level = 4;
12356 ip = (guint8 *)header->code;
12358 cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX * header->max_stack);
12360 if (cfg->verbose_level > 2) {
12361 if (cfg->generic_sharing_context)
12362 g_print ("converting shared method %s\n", mono_method_full_name (method, TRUE));
12364 g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
12367 if (cfg->opt & (MONO_OPT_ABCREM | MONO_OPT_SSAPRE))
12368 cfg->opt |= MONO_OPT_SSA;
12371 static int count = 0;
12375 if (getenv ("MONO_COUNT")) {
12376 if (count == atoi (getenv ("MONO_COUNT"))) {
12377 printf ("LAST: %s\n", mono_method_full_name (method, TRUE));
12378 //cfg->verbose_level = 5;
12380 if (count <= atoi (getenv ("MONO_COUNT")))
12381 cfg->new_ir = TRUE;
12384 * Passing/returning vtypes in registers in managed methods is an ABI change
12385 * from the old JIT.
12387 disable_vtypes_in_regs = TRUE;
12390 cfg->new_ir = TRUE;
12394 if ((cfg->method->klass->image != mono_defaults.corlib) || (strstr (cfg->method->klass->name, "StackOverflowException") && strstr (cfg->method->name, ".ctor")) || (strstr (cfg->method->klass->name, "OutOfMemoryException") && strstr (cfg->method->name, ".ctor")))
12395 cfg->globalra = TRUE;
12398 //cfg->globalra = TRUE;
12400 //if (!strcmp (cfg->method->klass->name, "Tests") && !cfg->method->wrapper_type)
12401 // cfg->globalra = TRUE;
12404 static int count = 0;
12407 if (getenv ("COUNT2")) {
12408 if (count == atoi (getenv ("COUNT2")))
12409 printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
12410 if (count > atoi (getenv ("COUNT2")))
12411 cfg->globalra = FALSE;
12415 if (header->clauses)
12416 cfg->globalra = FALSE;
12418 if (cfg->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
12419 /* The code in the prolog clobbers caller saved registers */
12420 cfg->globalra = FALSE;
12422 // FIXME: Disable globalra in case of tracing/profiling
12424 if (cfg->method->save_lmf)
12425 /* The LMF saving code might clobber caller saved registers */
12426 cfg->globalra = FALSE;
12429 if (!strcmp (cfg->method->name, "CompareInternal"))
12430 cfg->globalra = FALSE;
12433 if (strstr (cfg->method->name, "LoadData"))
12434 cfg->new_ir = FALSE;
12438 cfg->rs = mono_regstate_new ();
12439 cfg->next_vreg = cfg->rs->next_vreg;
12442 /* FIXME: Fix SSA to handle branches inside bblocks */
12443 if (cfg->opt & MONO_OPT_SSA)
12444 cfg->enable_extended_bblocks = FALSE;
12447 * FIXME: This confuses liveness analysis because variables which are assigned after
12448 * a branch inside a bblock become part of the kill set, even though the assignment
12449 * might not get executed. This causes the optimize_initlocals pass to delete some
12450 * assignments which are needed.
12451 * Also, the mono_if_conversion pass needs to be modified to recognize the code
12454 //cfg->enable_extended_bblocks = TRUE;
12457 * create MonoInst* which represents arguments and local variables
12459 mono_compile_create_vars (cfg);
12462 /* SSAPRE is not supported on linear IR */
12463 cfg->opt &= ~MONO_OPT_SSAPRE;
12465 i = mono_method_to_ir2 (cfg, method_to_compile, NULL, NULL, NULL, NULL, NULL, 0, FALSE);
12468 i = mono_method_to_ir (cfg, method_to_compile, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE);
12472 if (try_generic_shared && cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
12474 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
12475 MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
12478 mono_destroy_compile (cfg);
12479 try_generic_shared = FALSE;
12480 goto restart_compile;
12482 g_assert (cfg->exception_type != MONO_EXCEPTION_GENERIC_SHARING_FAILED);
12484 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
12485 MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
12486 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
12487 mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
12488 /* cfg contains the details of the failure, so let the caller cleanup */
12492 mono_jit_stats.basic_blocks += cfg->num_bblocks;
12493 mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
12495 /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
12498 mono_decompose_long_opts (cfg);
12500 /* Should be done before branch opts */
12501 if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
12502 mono_local_cprop2 (cfg);
12505 if (cfg->opt & MONO_OPT_BRANCH)
12506 mono_optimize_branches (cfg);
12509 /* This must be done _before_ global reg alloc and _after_ decompose */
12510 mono_handle_global_vregs (cfg);
12511 mono_local_deadce (cfg);
12512 mono_if_conversion (cfg);
12515 if ((cfg->opt & MONO_OPT_SSAPRE) || cfg->globalra)
12516 mono_remove_critical_edges (cfg);
12518 /* Depth-first ordering on basic blocks */
12519 cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
12522 df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
12523 if (cfg->num_bblocks != dfn + 1) {
12524 MonoBasicBlock *bb;
12526 cfg->num_bblocks = dfn + 1;
12528 /* remove unreachable code, because the code in them may be
12529 * inconsistent (access to dead variables for example) */
12530 for (bb = cfg->bb_entry; bb;) {
12531 MonoBasicBlock *bbn = bb->next_bb;
12534 * FIXME: Can't use the second case in methods with clauses, since the
12535 * bblocks inside the clauses are not processed during dfn computation.
12537 if (((header->clauses && (bbn && bbn->region == -1 && bbn->in_count == 0)) ||
12538 (!header->clauses && (bbn && bbn->region == -1 && !bbn->dfn))) &&
12539 bbn != cfg->bb_exit) {
12540 if (cfg->verbose_level > 1)
12541 g_print ("found unreachable code in BB%d\n", bbn->block_num);
12542 /* There may exist unreachable branches to this bb */
12543 bb->next_bb = bbn->next_bb;
12544 mono_nullify_basic_block (bbn);
12551 if (((cfg->num_varinfo > 2000) || (cfg->num_bblocks > 1000)) && !cfg->compile_aot) {
12553 * we disable some optimizations if there are too many variables
12554 * because JIT time may become too expensive. The actual number needs
12555 * to be tweaked and eventually the non-linear algorithms should be fixed.
12557 cfg->opt &= ~ (MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP);
12558 cfg->disable_ssa = TRUE;
12561 if (cfg->opt & MONO_OPT_LOOP) {
12562 mono_compile_dominator_info (cfg, MONO_COMP_DOM | MONO_COMP_IDOM);
12563 mono_compute_natural_loops (cfg);
12566 /* after method_to_ir */
12568 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
12569 MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
12573 //#define DEBUGSSA "logic_run"
12574 #define DEBUGSSA_CLASS "Tests"
12577 if (!header->num_clauses && !cfg->disable_ssa) {
12578 mono_local_cprop (cfg);
12580 #ifndef DISABLE_SSA
12582 mono_ssa_compute2 (cfg);
12584 mono_ssa_compute (cfg);
12588 if (cfg->opt & MONO_OPT_SSA) {
12589 if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
12590 #ifndef DISABLE_SSA
12592 mono_local_cprop (cfg);
12594 mono_ssa_compute2 (cfg);
12596 mono_ssa_compute (cfg);
12599 if (cfg->verbose_level >= 2) {
12606 /* after SSA translation */
12608 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
12609 MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
12613 if ((cfg->opt & MONO_OPT_CONSPROP) || (cfg->opt & MONO_OPT_COPYPROP)) {
12614 if (cfg->comp_done & MONO_COMP_SSA) {
12615 #ifndef DISABLE_SSA
12617 mono_ssa_cprop2 (cfg);
12619 mono_ssa_cprop (cfg);
12623 mono_local_cprop (cfg);
12627 #ifndef DISABLE_SSA
12628 if (cfg->comp_done & MONO_COMP_SSA) {
12629 //mono_ssa_strength_reduction (cfg);
12631 if (cfg->opt & MONO_OPT_SSAPRE) {
12632 mono_perform_ssapre (cfg);
12633 //mono_local_cprop (cfg);
12636 if (cfg->opt & MONO_OPT_DEADCE) {
12638 mono_ssa_deadce2 (cfg);
12640 mono_ssa_deadce (cfg);
12641 deadce_has_run = TRUE;
12645 if ((cfg->flags & (MONO_CFG_HAS_LDELEMA|MONO_CFG_HAS_CHECK_THIS)) && (cfg->opt & MONO_OPT_ABCREM))
12646 mono_perform_abc_removal2 (cfg);
12648 if ((cfg->flags & MONO_CFG_HAS_LDELEMA) && (cfg->opt & MONO_OPT_ABCREM))
12649 mono_perform_abc_removal (cfg);
12653 mono_ssa_remove2 (cfg);
12654 mono_local_cprop2 (cfg);
12655 mono_handle_global_vregs (cfg);
12656 mono_local_deadce (cfg);
12659 mono_ssa_remove (cfg);
12661 if (cfg->opt & MONO_OPT_BRANCH) {
12662 MonoBasicBlock *bb;
12664 mono_optimize_branches (cfg);
12666 /* Have to recompute cfg->bblocks and bb->dfn */
12667 if (cfg->globalra) {
12668 mono_remove_critical_edges (cfg);
12670 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12673 /* Depth-first ordering on basic blocks */
12674 cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
12677 df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
12678 cfg->num_bblocks = dfn + 1;
12684 /* after SSA removal */
12686 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
12687 MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
12692 #ifdef MONO_ARCH_SOFT_FLOAT
12693 mono_decompose_soft_float (cfg);
12695 mono_decompose_vtype_opts (cfg);
12696 if (cfg->flags & MONO_CFG_HAS_ARRAY_ACCESS)
12697 mono_decompose_array_access_opts (cfg);
12700 if (!cfg->new_ir) {
12701 if (cfg->verbose_level > 4)
12702 mono_print_code (cfg, "BEFORE DECOMPOSE");
12704 decompose_pass (cfg);
12707 if (cfg->got_var) {
12710 g_assert (cfg->got_var_allocated);
12713 * Allways allocate the GOT var to a register, because keeping it
12714 * in memory will increase the number of live temporaries in some
12715 * code created by inssel.brg, leading to the well known spills+
12716 * branches problem. Testcase: mcs crash in
12717 * System.MonoCustomAttrs:GetCustomAttributes.
12719 regs = mono_arch_get_global_int_regs (cfg);
12721 cfg->got_var->opcode = OP_REGVAR;
12722 cfg->got_var->dreg = GPOINTER_TO_INT (regs->data);
12723 cfg->used_int_regs |= 1LL << cfg->got_var->dreg;
12725 g_list_free (regs);
12728 /* todo: remove code when we have verified that the liveness for try/catch blocks
12732 * Currently, this can't be commented out since exception blocks are not
12733 * processed during liveness analysis.
12735 mono_liveness_handle_exception_clauses (cfg);
12737 if (cfg->globalra) {
12738 MonoBasicBlock *bb;
12740 /* Have to do this before regalloc since it can create vregs */
12741 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12742 mono_arch_lowering_pass (cfg, bb);
12744 mono_global_regalloc (cfg);
12747 if ((cfg->opt & MONO_OPT_LINEARS) && !cfg->globalra) {
12748 GList *vars, *regs;
12750 /* For now, compute aliasing info only if needed for deadce... */
12751 if (!cfg->new_ir && (cfg->opt & MONO_OPT_DEADCE) && (! deadce_has_run) && (header->num_clauses == 0)) {
12752 cfg->aliasing_info = mono_build_aliasing_information (cfg);
12755 /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
12756 cfg->comp_done &= ~MONO_COMP_LIVENESS;
12757 if (!(cfg->comp_done & MONO_COMP_LIVENESS))
12758 mono_analyze_liveness (cfg);
12760 if (cfg->aliasing_info != NULL) {
12761 mono_aliasing_deadce (cfg->aliasing_info);
12762 deadce_has_run = TRUE;
12765 if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
12766 regs = mono_arch_get_global_int_regs (cfg);
12768 regs = g_list_delete_link (regs, regs);
12769 mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
12772 if (cfg->aliasing_info != NULL) {
12773 mono_destroy_aliasing_information (cfg->aliasing_info);
12774 cfg->aliasing_info = NULL;
12778 //mono_print_code (cfg);
12782 /* variables are allocated after decompose, since decompose could create temps */
12783 if (!cfg->globalra)
12784 mono_arch_allocate_vars (cfg);
12786 if (!cfg->new_ir && cfg->opt & MONO_OPT_CFOLD)
12787 mono_constant_fold (cfg);
12790 MonoBasicBlock *bb;
12791 gboolean need_local_opts;
12793 if (!cfg->globalra) {
12794 mono_spill_global_vars (cfg, &need_local_opts);
12796 if (need_local_opts || cfg->compile_aot) {
12797 /* To optimize code created by spill_global_vars */
12798 mono_local_cprop2 (cfg);
12799 mono_local_deadce (cfg);
12803 /* Add branches between non-consecutive bblocks */
12804 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12805 if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins) &&
12806 bb->last_ins->inst_false_bb && bb->next_bb != bb->last_ins->inst_false_bb) {
12807 /* we are careful when inverting, since bugs like #59580
12808 * could show up when dealing with NaNs.
12810 if (MONO_IS_COND_BRANCH_NOFP(bb->last_ins) && bb->next_bb == bb->last_ins->inst_true_bb) {
12811 MonoBasicBlock *tmp = bb->last_ins->inst_true_bb;
12812 bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
12813 bb->last_ins->inst_false_bb = tmp;
12815 bb->last_ins->opcode = mono_reverse_branch_op (bb->last_ins->opcode);
12817 MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
12818 inst->opcode = OP_BR;
12819 inst->inst_target_bb = bb->last_ins->inst_false_bb;
12820 mono_bblock_add_inst (bb, inst);
12825 if (cfg->verbose_level >= 4 && !cfg->globalra) {
12826 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12827 MonoInst *tree = bb->code;
12828 g_print ("DUMP BLOCK %d:\n", bb->block_num);
12831 for (; tree; tree = tree->next) {
12832 mono_print_ins_index (-1, tree);
12838 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12839 bb->max_vreg = cfg->next_vreg;
12843 mini_select_instructions (cfg);
12845 mono_codegen (cfg);
12846 if (cfg->verbose_level >= 2) {
12847 char *id = mono_method_full_name (cfg->method, FALSE);
12848 mono_disassemble_code (cfg, cfg->native_code, cfg->code_len, id + 3);
12852 if (cfg->generic_sharing_context)
12853 generic_info_size = sizeof (MonoGenericJitInfo);
12855 generic_info_size = 0;
12857 if (cfg->method->dynamic) {
12858 jinfo = g_malloc0 (sizeof (MonoJitInfo) + (header->num_clauses * sizeof (MonoJitExceptionInfo)) +
12859 generic_info_size);
12861 /* we access cfg->domain->mp */
12862 mono_domain_lock (cfg->domain);
12863 jinfo = mono_domain_alloc0 (cfg->domain, sizeof (MonoJitInfo) +
12864 (header->num_clauses * sizeof (MonoJitExceptionInfo)) +
12865 generic_info_size);
12866 mono_domain_unlock (cfg->domain);
12869 if (cfg->generic_sharing_context) {
12870 MonoGenericContext object_context;
12872 g_assert (!method_to_compile->klass->generic_class);
12873 if (method_to_compile->klass->generic_container) {
12874 int type_argc = method_to_compile->klass->generic_container->type_argc;
12876 object_context.class_inst = get_object_generic_inst (type_argc);
12878 object_context.class_inst = NULL;
12881 if (mini_method_get_context (method_to_compile)->method_inst) {
12882 int type_argc = mini_method_get_context (method_to_compile)->method_inst->type_argc;
12884 object_context.method_inst = get_object_generic_inst (type_argc);
12886 object_context.method_inst = NULL;
12889 g_assert (object_context.class_inst || object_context.method_inst);
12891 method_to_register = mono_class_inflate_generic_method (method_to_compile, &object_context);
12893 g_assert (method == method_to_compile);
12894 method_to_register = method;
12897 jinfo->method = method_to_register;
12898 jinfo->code_start = cfg->native_code;
12899 jinfo->code_size = cfg->code_len;
12900 jinfo->used_regs = cfg->used_int_regs;
12901 jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
12902 jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */
12903 jinfo->num_clauses = header->num_clauses;
12905 if (cfg->generic_sharing_context) {
12907 MonoGenericJitInfo *gi;
12909 jinfo->has_generic_jit_info = 1;
12911 gi = mono_jit_info_get_generic_jit_info (jinfo);
12914 gi->generic_sharing_context = cfg->generic_sharing_context;
12917 * Non-generic static methods only get a "this" info
12918 * if they use the rgctx variable (which they are
12919 * forced to if they have any open catch clauses).
12921 if (cfg->rgctx_var ||
12922 (!(method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) &&
12923 !mini_method_get_context (method_to_compile)->method_inst &&
12924 !method_to_compile->klass->valuetype)) {
12927 if ((method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) ||
12928 mini_method_get_context (method_to_compile)->method_inst ||
12929 method_to_compile->klass->valuetype) {
12930 inst = cfg->rgctx_var;
12931 g_assert (inst->opcode == OP_REGOFFSET);
12933 inst = cfg->args [0];
12936 if (inst->opcode == OP_REGVAR) {
12937 gi->this_in_reg = 1;
12938 gi->this_reg = inst->dreg;
12940 //g_print ("this in reg %d\n", inst->dreg);
12942 g_assert (inst->opcode == OP_REGOFFSET);
12944 g_assert (inst->inst_basereg == X86_EBP);
12945 #elif defined(__x86_64__)
12946 g_assert (inst->inst_basereg == X86_EBP || inst->inst_basereg == X86_ESP);
12948 g_assert (inst->inst_offset >= G_MININT32 && inst->inst_offset <= G_MAXINT32);
12950 gi->this_in_reg = 0;
12951 gi->this_reg = inst->inst_basereg;
12952 gi->this_offset = inst->inst_offset;
12954 //g_print ("this at offset %d from reg %d\n", gi->this_offset, gi->this_reg);
12961 if (header->num_clauses) {
12964 for (i = 0; i < header->num_clauses; i++) {
12965 MonoExceptionClause *ec = &header->clauses [i];
12966 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
12967 MonoBasicBlock *tblock;
12970 ei->flags = ec->flags;
12972 exvar = mono_find_exvar_for_offset (cfg, ec->handler_offset);
12973 ei->exvar_offset = exvar ? exvar->inst_offset : 0;
12975 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
12976 tblock = cfg->cil_offset_to_bb [ec->data.filter_offset];
12978 ei->data.filter = cfg->native_code + tblock->native_offset;
12980 ei->data.catch_class = ec->data.catch_class;
12983 tblock = cfg->cil_offset_to_bb [ec->try_offset];
12985 ei->try_start = cfg->native_code + tblock->native_offset;
12986 g_assert (tblock->native_offset);
12987 tblock = cfg->cil_offset_to_bb [ec->try_offset + ec->try_len];
12989 ei->try_end = cfg->native_code + tblock->native_offset;
12990 g_assert (tblock->native_offset);
12991 tblock = cfg->cil_offset_to_bb [ec->handler_offset];
12993 ei->handler_start = cfg->native_code + tblock->native_offset;
12997 cfg->jit_info = jinfo;
12998 #if defined(__arm__)
12999 mono_arch_fixup_jinfo (cfg);
13002 if (!cfg->compile_aot) {
13003 mono_domain_lock (cfg->domain);
13004 mono_jit_info_table_add (cfg->domain, jinfo);
13006 if (cfg->method->dynamic)
13007 mono_dynamic_code_hash_lookup (cfg->domain, cfg->method)->ji = jinfo;
13008 mono_domain_unlock (cfg->domain);
13011 /* collect statistics */
13012 mono_perfcounters->jit_methods++;
13013 mono_perfcounters->jit_bytes += header->code_size;
13014 mono_jit_stats.allocated_code_size += cfg->code_len;
13015 code_size_ratio = cfg->code_len;
13016 if (code_size_ratio > mono_jit_stats.biggest_method_size && mono_jit_stats.enabled) {
13017 mono_jit_stats.biggest_method_size = code_size_ratio;
13018 g_free (mono_jit_stats.biggest_method);
13019 mono_jit_stats.biggest_method = g_strdup_printf ("%s::%s)", method->klass->name, method->name);
13021 code_size_ratio = (code_size_ratio * 100) / mono_method_get_header (method)->code_size;
13022 if (code_size_ratio > mono_jit_stats.max_code_size_ratio && mono_jit_stats.enabled) {
13023 mono_jit_stats.max_code_size_ratio = code_size_ratio;
13024 g_free (mono_jit_stats.max_ratio_method);
13025 mono_jit_stats.max_ratio_method = g_strdup_printf ("%s::%s)", method->klass->name, method->name);
13027 mono_jit_stats.native_code_size += cfg->code_len;
13029 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
13030 MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
13031 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
13032 mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
13040 mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
13042 g_assert_not_reached ();
13046 #endif /* DISABLE_JIT */
13048 static MonoJitInfo*
13049 lookup_generic_method (MonoDomain *domain, MonoMethod *method)
13051 MonoMethod *open_method;
13053 if (!mono_method_is_generic_sharable_impl (method, FALSE))
13056 open_method = mono_method_get_declaring_generic_method (method);
13058 return mono_domain_lookup_shared_generic (domain, open_method);
13062 * LOCKING: Assumes domain->jit_code_hash_lock is held.
13064 static MonoJitInfo*
13065 lookup_method_inner (MonoDomain *domain, MonoMethod *method)
13067 MonoJitInfo *ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
13072 return lookup_generic_method (domain, method);
13075 static MonoJitInfo*
13076 lookup_method (MonoDomain *domain, MonoMethod *method)
13080 mono_domain_jit_code_hash_lock (domain);
13081 info = lookup_method_inner (domain, method);
13082 mono_domain_jit_code_hash_unlock (domain);
13088 mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt)
13091 gpointer code = NULL;
13093 MonoVTable *vtable;
13095 #ifdef MONO_USE_AOT_COMPILER
13096 if ((opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
13097 MonoDomain *domain = mono_domain_get ();
13099 mono_class_init (method->klass);
13101 mono_domain_lock (domain);
13102 if ((code = mono_aot_get_method (domain, method))) {
13103 mono_domain_unlock (domain);
13104 vtable = mono_class_vtable (domain, method->klass);
13106 mono_runtime_class_init (vtable);
13110 mono_domain_unlock (domain);
13114 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
13115 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
13117 MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
13119 if (!piinfo->addr) {
13120 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
13121 piinfo->addr = mono_lookup_internal_call (method);
13122 else if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
13123 #ifdef PLATFORM_WIN32
13124 g_warning ("Method '%s' in assembly '%s' contains native code that cannot be executed by Mono in modules loaded from byte arrays. The assembly was probably created using C++/CLI.\n", mono_method_full_name (method, TRUE), method->klass->image->name);
13126 g_warning ("Method '%s' in assembly '%s' contains native code that cannot be executed by Mono on this platform. The assembly was probably created using C++/CLI.\n", mono_method_full_name (method, TRUE), method->klass->image->name);
13129 mono_lookup_pinvoke_call (method, NULL, NULL);
13131 nm = mono_marshal_get_native_wrapper (method, check_for_pending_exc, FALSE);
13132 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
13134 //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
13135 //mono_debug_add_wrapper (method, nm);
13136 } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
13137 const char *name = method->name;
13140 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
13141 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
13142 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_delegate_ctor");
13145 * We need to make sure this wrapper
13146 * is compiled because it might end up
13147 * in an (M)RGCTX if generic sharing
13148 * is enabled, and would be called
13149 * indirectly. If it were a
13150 * trampoline we'd try to patch that
13151 * indirect call, which is not
13154 return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper_full (mi, TRUE));
13155 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
13156 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
13157 return mono_create_delegate_trampoline (method->klass);
13159 nm = mono_marshal_get_delegate_invoke (method, NULL);
13160 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
13162 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
13163 nm = mono_marshal_get_delegate_begin_invoke (method);
13164 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
13165 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
13166 nm = mono_marshal_get_delegate_end_invoke (method);
13167 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
13174 g_error ("Attempting to JIT compile method '%s' while running with --aot-only.\n", mono_method_full_name (method, TRUE));
13176 cfg = mini_method_compile (method, opt, target_domain, TRUE, FALSE, 0);
13178 switch (cfg->exception_type) {
13179 case MONO_EXCEPTION_NONE:
13181 case MONO_EXCEPTION_TYPE_LOAD:
13182 case MONO_EXCEPTION_MISSING_FIELD:
13183 case MONO_EXCEPTION_MISSING_METHOD:
13184 case MONO_EXCEPTION_FILE_NOT_FOUND:
13185 case MONO_EXCEPTION_BAD_IMAGE: {
13186 /* Throw a type load exception if needed */
13187 MonoLoaderError *error = mono_loader_get_last_error ();
13191 ex = mono_loader_error_prepare_exception (error);
13193 if (cfg->exception_ptr) {
13194 ex = mono_class_get_exception_for_failure (cfg->exception_ptr);
13196 if (cfg->exception_type == MONO_EXCEPTION_MISSING_FIELD)
13197 ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingFieldException", cfg->exception_message);
13198 else if (cfg->exception_type == MONO_EXCEPTION_MISSING_METHOD)
13199 ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingMethodException", cfg->exception_message);
13200 else if (cfg->exception_type == MONO_EXCEPTION_TYPE_LOAD)
13201 ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "TypeLoadException", cfg->exception_message);
13202 else if (cfg->exception_type == MONO_EXCEPTION_FILE_NOT_FOUND)
13203 ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FileNotFoundException", cfg->exception_message);
13204 else if (cfg->exception_type == MONO_EXCEPTION_BAD_IMAGE)
13205 ex = mono_get_exception_bad_image_format (cfg->exception_message);
13207 g_assert_not_reached ();
13210 mono_destroy_compile (cfg);
13211 mono_raise_exception (ex);
13214 case MONO_EXCEPTION_INVALID_PROGRAM: {
13215 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", cfg->exception_message);
13216 mono_destroy_compile (cfg);
13217 mono_raise_exception (ex);
13220 case MONO_EXCEPTION_UNVERIFIABLE_IL: {
13221 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System.Security", "VerificationException", cfg->exception_message);
13222 mono_destroy_compile (cfg);
13223 mono_raise_exception (ex);
13226 case MONO_EXCEPTION_METHOD_ACCESS: {
13227 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MethodAccessException", cfg->exception_message);
13228 mono_destroy_compile (cfg);
13229 mono_raise_exception (ex);
13232 case MONO_EXCEPTION_FIELD_ACCESS: {
13233 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FieldAccessException", cfg->exception_message);
13234 mono_destroy_compile (cfg);
13235 mono_raise_exception (ex);
13238 /* this can only be set if the security manager is active */
13239 case MONO_EXCEPTION_SECURITY_LINKDEMAND: {
13240 MonoSecurityManager* secman = mono_security_manager_get_methods ();
13241 MonoObject *exc = NULL;
13244 args [0] = &cfg->exception_data;
13245 args [1] = &method;
13246 mono_runtime_invoke (secman->linkdemandsecurityexception, NULL, args, &exc);
13248 mono_destroy_compile (cfg);
13251 mono_raise_exception ((MonoException*)exc);
13253 case MONO_EXCEPTION_OBJECT_SUPPLIED: {
13254 MonoException *exp = cfg->exception_ptr;
13255 MONO_GC_UNREGISTER_ROOT (cfg->exception_ptr);
13256 mono_destroy_compile (cfg);
13257 mono_raise_exception (exp);
13261 g_assert_not_reached ();
13264 mono_domain_lock (target_domain);
13266 /* Check if some other thread already did the job. In this case, we can
13267 discard the code this thread generated. */
13269 mono_domain_jit_code_hash_lock (target_domain);
13271 info = lookup_method_inner (target_domain, method);
13273 /* We can't use a domain specific method in another domain */
13274 if ((target_domain == mono_domain_get ()) || info->domain_neutral) {
13275 code = info->code_start;
13276 // printf("Discarding code for method %s\n", method->name);
13280 if (code == NULL) {
13281 mono_internal_hash_table_insert (&target_domain->jit_code_hash, cfg->jit_info->method, cfg->jit_info);
13282 mono_domain_jit_code_hash_unlock (target_domain);
13283 code = cfg->native_code;
13285 if (cfg->generic_sharing_context && mono_method_is_generic_sharable_impl (method, FALSE)) {
13286 /* g_print ("inserting method %s.%s.%s\n", method->klass->name_space, method->klass->name, method->name); */
13287 mono_domain_register_shared_generic (target_domain,
13288 mono_method_get_declaring_generic_method (method), cfg->jit_info);
13289 mono_stats.generics_shared_methods++;
13292 mono_domain_jit_code_hash_unlock (target_domain);
13295 mono_destroy_compile (cfg);
13297 if (domain_jit_info (target_domain)->jump_target_hash) {
13298 MonoJumpInfo patch_info;
13299 GSList *list, *tmp;
13300 list = g_hash_table_lookup (domain_jit_info (target_domain)->jump_target_hash, method);
13302 patch_info.next = NULL;
13303 patch_info.ip.i = 0;
13304 patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
13305 patch_info.data.method = method;
13306 g_hash_table_remove (domain_jit_info (target_domain)->jump_target_hash, method);
13308 for (tmp = list; tmp; tmp = tmp->next)
13309 mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info, TRUE);
13310 g_slist_free (list);
13313 mono_domain_unlock (target_domain);
13315 vtable = mono_class_vtable (target_domain, method->klass);
13317 MonoException *exc;
13318 exc = mono_class_get_exception_for_failure (method->klass);
13320 mono_raise_exception (exc);
13322 mono_runtime_class_init (vtable);
13327 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
13329 MonoDomain *target_domain, *domain = mono_domain_get ();
13332 MonoJitICallInfo *callinfo = NULL;
13335 * ICALL wrappers are handled specially, since there is only one copy of them
13336 * shared by all appdomains.
13338 if ((method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
13339 const char *icall_name;
13341 icall_name = method->name + strlen ("__icall_wrapper_");
13342 g_assert (icall_name);
13343 callinfo = mono_find_jit_icall_by_name (icall_name);
13344 g_assert (callinfo);
13346 /* Must be domain neutral since there is only one copy */
13347 opt |= MONO_OPT_SHARED;
13350 if (opt & MONO_OPT_SHARED)
13351 target_domain = mono_get_root_domain ();
13353 target_domain = domain;
13355 info = lookup_method (target_domain, method);
13357 /* We can't use a domain specific method in another domain */
13358 if (! ((domain != target_domain) && !info->domain_neutral)) {
13359 MonoVTable *vtable;
13361 mono_jit_stats.methods_lookups++;
13362 vtable = mono_class_vtable (domain, method->klass);
13363 mono_runtime_class_init (vtable);
13364 return mono_create_ftnptr (target_domain, info->code_start);
13368 p = mono_create_ftnptr (target_domain, mono_jit_compile_method_inner (method, target_domain, opt));
13372 if (!callinfo->wrapper) {
13373 callinfo->wrapper = p;
13374 mono_register_jit_icall_wrapper (callinfo, p);
13375 mono_debug_add_icall_wrapper (method, callinfo);
13377 mono_jit_unlock ();
13384 mono_jit_compile_method (MonoMethod *method)
13386 return mono_jit_compile_method_with_opt (method, default_opt);
13389 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
13391 invalidated_delegate_trampoline (char *desc)
13393 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
13394 "See http://www.go-mono.com/delegate.html for an explanation and ways to fix this.",
13400 * mono_jit_free_method:
13402 * Free all memory allocated by the JIT for METHOD.
13405 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
13407 MonoJitDynamicMethodInfo *ji;
13408 gboolean destroy = TRUE;
13410 g_assert (method->dynamic);
13412 mono_domain_lock (domain);
13413 ji = mono_dynamic_code_hash_lookup (domain, method);
13414 mono_domain_unlock (domain);
13418 mono_domain_lock (domain);
13419 g_hash_table_remove (domain_jit_info (domain)->dynamic_code_hash, method);
13420 mono_internal_hash_table_remove (&domain->jit_code_hash, method);
13421 g_hash_table_remove (domain_jit_info (domain)->jump_trampoline_hash, method);
13422 mono_domain_unlock (domain);
13424 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
13425 if (debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
13427 * Instead of freeing the code, change it to call an error routine
13428 * so people can fix their code.
13430 char *type = mono_type_full_name (&method->klass->byval_arg);
13431 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
13434 mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
13440 * This needs to be done before freeing code_mp, since the code address is the
13441 * key in the table, so if we free the code_mp first, another thread can grab the
13442 * same code address and replace our entry in the table.
13444 mono_jit_info_table_remove (domain, ji->ji);
13447 mono_code_manager_destroy (ji->code_mp);
13452 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
13454 MonoDomain *target_domain;
13457 if (default_opt & MONO_OPT_SHARED)
13458 target_domain = mono_get_root_domain ();
13460 target_domain = domain;
13462 info = lookup_method (target_domain, method);
13464 /* We can't use a domain specific method in another domain */
13465 if (! ((domain != target_domain) && !info->domain_neutral)) {
13466 mono_jit_stats.methods_lookups++;
13467 return info->code_start;
13475 * mono_jit_runtime_invoke:
13476 * @method: the method to invoke
13477 * @obj: this pointer
13478 * @params: array of parameter values.
13479 * @exc: used to catch exceptions objects
13482 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
13484 MonoMethod *to_compile;
13485 MonoMethod *invoke;
13486 MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc, void* compiled_method);
13487 void* compiled_method;
13488 MonoVTable *vtable;
13490 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
13491 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
13495 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
13496 to_compile = mono_marshal_get_static_rgctx_invoke (method);
13498 to_compile = method;
13500 invoke = mono_marshal_get_runtime_invoke (method);
13501 runtime_invoke = mono_jit_compile_method (invoke);
13503 /* We need this here becuase mono_marshal_get_runtime_invoke can be place
13504 * the helper method in System.Object and not the target class
13506 vtable = mono_class_vtable (mono_domain_get (), method->klass);
13508 mono_runtime_class_init (vtable);
13510 if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
13511 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
13513 * Array Get/Set/Address methods. The JIT implements them using inline code
13514 * inside the runtime invoke wrappers, so no need to compile them.
13516 compiled_method = NULL;
13518 compiled_method = mono_jit_compile_method (to_compile);
13520 return runtime_invoke (obj, params, exc, compiled_method);
13523 #ifdef MONO_GET_CONTEXT
13524 #define GET_CONTEXT MONO_GET_CONTEXT
13527 #ifndef GET_CONTEXT
13528 #ifdef PLATFORM_WIN32
13529 #define GET_CONTEXT \
13530 struct sigcontext *ctx = (struct sigcontext*)_dummy;
13532 #ifdef MONO_ARCH_USE_SIGACTION
13533 #define GET_CONTEXT \
13534 void *ctx = context;
13535 #elif defined(__sparc__)
13536 #define GET_CONTEXT \
13537 void *ctx = sigctx;
13539 #define GET_CONTEXT \
13540 void **_p = (void **)&_dummy; \
13541 struct sigcontext *ctx = (struct sigcontext *)++_p;
13546 #ifdef MONO_ARCH_USE_SIGACTION
13547 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, siginfo_t *info, void *context)
13548 #elif defined(__sparc__)
13549 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, void *sigctx)
13551 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy)
13555 SIG_HANDLER_SIGNATURE (sigfpe_signal_handler)
13557 MonoException *exc = NULL;
13558 #ifndef MONO_ARCH_USE_SIGACTION
13563 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
13564 if (mono_arch_is_int_overflow (ctx, info))
13565 exc = mono_get_exception_arithmetic ();
13567 exc = mono_get_exception_divide_by_zero ();
13569 exc = mono_get_exception_divide_by_zero ();
13572 mono_arch_handle_exception (ctx, exc, FALSE);
13576 SIG_HANDLER_SIGNATURE (sigill_signal_handler)
13578 MonoException *exc;
13581 exc = mono_get_exception_execution_engine ("SIGILL");
13583 mono_arch_handle_exception (ctx, exc, FALSE);
13587 SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
13589 #ifndef MONO_ARCH_SIGSEGV_ON_ALTSTACK
13590 MonoException *exc = NULL;
13593 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
13597 #ifdef MONO_ARCH_USE_SIGACTION
13598 if (debug_options.collect_pagefault_stats) {
13599 if (mono_raw_buffer_is_pagefault (info->si_addr)) {
13600 mono_raw_buffer_handle_pagefault (info->si_addr);
13603 if (mono_aot_is_pagefault (info->si_addr)) {
13604 mono_aot_handle_pagefault (info->si_addr);
13610 /* The thread might no be registered with the runtime */
13611 if (!mono_domain_get () || !jit_tls)
13612 mono_handle_native_sigsegv (SIGSEGV, ctx);
13614 ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context (ctx));
13616 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
13617 if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr))
13620 /* The hard-guard page has been hit: there is not much we can do anymore
13621 * Print a hopefully clear message and abort.
13623 if (jit_tls->stack_size &&
13624 ABS ((guint8*)info->si_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 32768) {
13625 const char *method;
13626 /* we don't do much now, but we can warn the user with a useful message */
13627 fprintf (stderr, "Stack overflow: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), (gpointer)info->si_addr);
13628 if (ji && ji->method)
13629 method = mono_method_full_name (ji->method, TRUE);
13631 method = "Unmanaged";
13632 fprintf (stderr, "At %s\n", method);
13635 mono_arch_handle_altstack_exception (ctx, info->si_addr, FALSE);
13640 mono_handle_native_sigsegv (SIGSEGV, ctx);
13643 mono_arch_handle_exception (ctx, exc, FALSE);
13647 #ifndef PLATFORM_WIN32
13650 SIG_HANDLER_SIGNATURE (sigabrt_signal_handler)
13655 ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
13657 mono_handle_native_sigsegv (SIGABRT, ctx);
13662 SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
13664 gboolean running_managed;
13665 MonoException *exc;
13666 MonoThread *thread = mono_thread_current ();
13671 if (thread->thread_dump_requested) {
13672 thread->thread_dump_requested = FALSE;
13674 mono_print_thread_dump (ctx);
13679 * This is an async signal, so the code below must not call anything which
13680 * is not async safe. That includes the pthread locking functions. If we
13681 * know that we interrupted managed code, then locking is safe.
13683 ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
13684 running_managed = ji != NULL;
13686 exc = mono_thread_request_interruption (running_managed);
13689 mono_arch_handle_exception (ctx, exc, FALSE);
13692 #if defined(__i386__) || defined(__x86_64__)
13693 #define FULL_STAT_PROFILER_BACKTRACE 1
13694 #define CURRENT_FRAME_GET_BASE_POINTER(f) (* (gpointer*)(f))
13695 #define CURRENT_FRAME_GET_RETURN_ADDRESS(f) (* (((gpointer*)(f)) + 1))
13696 #if MONO_ARCH_STACK_GROWS_UP
13697 #define IS_BEFORE_ON_STACK <
13698 #define IS_AFTER_ON_STACK >
13700 #define IS_BEFORE_ON_STACK >
13701 #define IS_AFTER_ON_STACK <
13704 #define FULL_STAT_PROFILER_BACKTRACE 0
13707 #if defined(__ia64__) || defined(__sparc__) || defined(sparc) || defined(__s390__) || defined(s390)
13710 SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
13718 SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
13720 int call_chain_depth = mono_profiler_stat_get_call_chain_depth ();
13723 if (call_chain_depth == 0) {
13724 mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx);
13726 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
13727 int current_frame_index = 1;
13728 MonoContext mono_context;
13729 #if FULL_STAT_PROFILER_BACKTRACE
13730 guchar *current_frame;
13731 guchar *stack_bottom;
13734 MonoDomain *domain;
13736 guchar *ips [call_chain_depth + 1];
13738 mono_arch_sigctx_to_monoctx (ctx, &mono_context);
13739 ips [0] = MONO_CONTEXT_GET_IP (&mono_context);
13741 if (jit_tls != NULL) {
13742 #if FULL_STAT_PROFILER_BACKTRACE
13743 stack_bottom = jit_tls->end_of_stack;
13744 stack_top = MONO_CONTEXT_GET_SP (&mono_context);
13745 current_frame = MONO_CONTEXT_GET_BP (&mono_context);
13747 while ((current_frame_index <= call_chain_depth) &&
13748 (stack_bottom IS_BEFORE_ON_STACK (guchar*) current_frame) &&
13749 ((guchar*) current_frame IS_BEFORE_ON_STACK stack_top)) {
13750 ips [current_frame_index] = CURRENT_FRAME_GET_RETURN_ADDRESS (current_frame);
13751 current_frame_index ++;
13752 stack_top = current_frame;
13753 current_frame = CURRENT_FRAME_GET_BASE_POINTER (current_frame);
13756 domain = mono_domain_get ();
13757 if (domain != NULL) {
13758 MonoLMF *lmf = NULL;
13761 MonoContext new_mono_context;
13763 ji = mono_find_jit_info (domain, jit_tls, &res, NULL, &mono_context,
13764 &new_mono_context, NULL, &lmf, &native_offset, NULL);
13765 while ((ji != NULL) && (current_frame_index <= call_chain_depth)) {
13766 ips [current_frame_index] = MONO_CONTEXT_GET_IP (&new_mono_context);
13767 current_frame_index ++;
13768 mono_context = new_mono_context;
13769 ji = mono_find_jit_info (domain, jit_tls, &res, NULL, &mono_context,
13770 &new_mono_context, NULL, &lmf, &native_offset, NULL);
13777 mono_profiler_stat_call_chain (current_frame_index, & ips [0], ctx);
13784 SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
13790 /* We use this signal to start the attach agent too */
13791 res = mono_attach_start ();
13795 printf ("Full thread dump:\n");
13797 mono_threads_request_thread_dump ();
13800 * print_thread_dump () skips the current thread, since sending a signal
13801 * to it would invoke the signal handler below the sigquit signal handler,
13802 * and signal handlers don't create an lmf, so the stack walk could not
13805 mono_print_thread_dump (ctx);
13809 SIG_HANDLER_SIGNATURE (sigusr2_signal_handler)
13811 gboolean enabled = mono_trace_is_enabled ();
13813 mono_trace_enable (!enabled);
13819 SIG_HANDLER_SIGNATURE (sigint_signal_handler)
13821 MonoException *exc;
13824 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
13826 mono_arch_handle_exception (ctx, exc, FALSE);
13829 #ifdef PLATFORM_MACOSX
13832 * This code disables the CrashReporter of MacOS X by installing
13833 * a dummy Mach exception handler.
13837 * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/exc_server.html
13841 exc_server (mach_msg_header_t *request_msg,
13842 mach_msg_header_t *reply_msg);
13845 * The exception message
13848 mach_msg_base_t msg; /* common mach message header */
13849 char payload [1024]; /* opaque */
13850 } mach_exception_msg_t;
13852 /* The exception port */
13853 static mach_port_t mach_exception_port = VM_MAP_NULL;
13856 * Implicitly called by exc_server. Must be public.
13858 * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/catch_exception_raise.html
13861 catch_exception_raise (
13862 mach_port_t exception_port,
13863 mach_port_t thread,
13865 exception_type_t exception,
13866 exception_data_t code,
13867 mach_msg_type_number_t code_count)
13869 /* consume the exception */
13870 return KERN_FAILURE;
13874 * Exception thread handler.
13878 mach_exception_thread (void *arg)
13881 mach_exception_msg_t request;
13882 mach_exception_msg_t reply;
13883 mach_msg_return_t result;
13885 /* receive from "mach_exception_port" */
13886 result = mach_msg (&request.msg.header,
13887 MACH_RCV_MSG | MACH_RCV_LARGE,
13890 mach_exception_port,
13891 MACH_MSG_TIMEOUT_NONE,
13894 g_assert (result == MACH_MSG_SUCCESS);
13896 /* dispatch to catch_exception_raise () */
13897 exc_server (&request.msg.header, &reply.msg.header);
13899 /* send back to sender */
13900 result = mach_msg (&reply.msg.header,
13902 reply.msg.header.msgh_size,
13905 MACH_MSG_TIMEOUT_NONE,
13908 g_assert (result == MACH_MSG_SUCCESS);
13914 macosx_register_exception_handler ()
13917 pthread_attr_t attr;
13920 if (mach_exception_port != VM_MAP_NULL)
13923 task = mach_task_self ();
13925 /* create the "mach_exception_port" with send & receive rights */
13926 g_assert (mach_port_allocate (task, MACH_PORT_RIGHT_RECEIVE,
13927 &mach_exception_port) == KERN_SUCCESS);
13928 g_assert (mach_port_insert_right (task, mach_exception_port, mach_exception_port,
13929 MACH_MSG_TYPE_MAKE_SEND) == KERN_SUCCESS);
13931 /* create the exception handler thread */
13932 g_assert (!pthread_attr_init (&attr));
13933 g_assert (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED));
13934 g_assert (!pthread_create (&thread, &attr, mach_exception_thread, NULL));
13935 pthread_attr_destroy (&attr);
13938 * register "mach_exception_port" as a receiver for the
13939 * EXC_BAD_ACCESS exception
13941 * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/task_set_exception_ports.html
13943 g_assert (task_set_exception_ports (task, EXC_MASK_BAD_ACCESS,
13944 mach_exception_port,
13946 MACHINE_THREAD_STATE) == KERN_SUCCESS);
13950 #ifndef PLATFORM_WIN32
13952 add_signal_handler (int signo, gpointer handler)
13954 struct sigaction sa;
13956 #ifdef MONO_ARCH_USE_SIGACTION
13957 sa.sa_sigaction = handler;
13958 sigemptyset (&sa.sa_mask);
13959 sa.sa_flags = SA_SIGINFO;
13960 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
13961 if (signo == SIGSEGV)
13962 sa.sa_flags |= SA_ONSTACK;
13965 sa.sa_handler = handler;
13966 sigemptyset (&sa.sa_mask);
13969 g_assert (sigaction (signo, &sa, NULL) != -1);
13973 remove_signal_handler (int signo)
13975 struct sigaction sa;
13977 sa.sa_handler = SIG_DFL;
13978 sigemptyset (&sa.sa_mask);
13981 g_assert (sigaction (signo, &sa, NULL) != -1);
13986 mono_runtime_install_handlers (void)
13988 #ifdef PLATFORM_WIN32
13990 win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
13991 win32_seh_set_handler(SIGILL, sigill_signal_handler);
13992 win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
13993 if (debug_options.handle_sigint)
13994 win32_seh_set_handler(SIGINT, sigint_signal_handler);
13996 #else /* !PLATFORM_WIN32 */
13999 #if defined(PLATFORM_MACOSX) && !defined(__arm__)
14000 macosx_register_exception_handler ();
14003 if (debug_options.handle_sigint)
14004 add_signal_handler (SIGINT, sigint_signal_handler);
14006 add_signal_handler (SIGFPE, sigfpe_signal_handler);
14007 add_signal_handler (SIGQUIT, sigquit_signal_handler);
14008 add_signal_handler (SIGILL, sigill_signal_handler);
14009 add_signal_handler (SIGBUS, sigsegv_signal_handler);
14010 if (mono_jit_trace_calls != NULL)
14011 add_signal_handler (SIGUSR2, sigusr2_signal_handler);
14013 add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler);
14014 signal (SIGPIPE, SIG_IGN);
14016 add_signal_handler (SIGABRT, sigabrt_signal_handler);
14018 /* catch SIGSEGV */
14019 add_signal_handler (SIGSEGV, sigsegv_signal_handler);
14020 #endif /* PLATFORM_WIN32 */
14024 mono_runtime_cleanup_handlers (void)
14026 #ifdef PLATFORM_WIN32
14027 win32_seh_cleanup();
14029 if (debug_options.handle_sigint)
14030 remove_signal_handler (SIGINT);
14032 remove_signal_handler (SIGFPE);
14033 remove_signal_handler (SIGQUIT);
14034 remove_signal_handler (SIGILL);
14035 remove_signal_handler (SIGBUS);
14036 if (mono_jit_trace_calls != NULL)
14037 remove_signal_handler (SIGUSR2);
14039 remove_signal_handler (mono_thread_get_abort_signal ());
14041 remove_signal_handler (SIGABRT);
14043 remove_signal_handler (SIGSEGV);
14044 #endif /* PLATFORM_WIN32 */
14048 #ifdef HAVE_LINUX_RTC_H
14049 #include <linux/rtc.h>
14050 #include <sys/ioctl.h>
14052 static int rtc_fd = -1;
14055 enable_rtc_timer (gboolean enable)
14058 flags = fcntl (rtc_fd, F_GETFL);
14060 perror ("getflags");
14067 if (fcntl (rtc_fd, F_SETFL, flags) == -1) {
14068 perror ("setflags");
14075 #ifdef PLATFORM_WIN32
14076 static HANDLE win32_main_thread;
14077 static MMRESULT win32_timer;
14079 static void CALLBACK
14080 win32_time_proc (UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
14084 context.ContextFlags = CONTEXT_CONTROL;
14085 if (GetThreadContext (win32_main_thread, &context)) {
14087 mono_profiler_stat_hit ((guchar *) context.Rip, &context);
14089 mono_profiler_stat_hit ((guchar *) context.Eip, &context);
14096 setup_stat_profiler (void)
14099 struct itimerval itval;
14100 static int inited = 0;
14101 #ifdef HAVE_LINUX_RTC_H
14102 const char *rtc_freq;
14103 if (!inited && (rtc_freq = g_getenv ("MONO_RTC"))) {
14107 freq = atoi (rtc_freq);
14110 rtc_fd = open ("/dev/rtc", O_RDONLY);
14111 if (rtc_fd == -1) {
14112 perror ("open /dev/rtc");
14115 add_signal_handler (SIGPROF, sigprof_signal_handler);
14116 if (ioctl (rtc_fd, RTC_IRQP_SET, freq) == -1) {
14117 perror ("set rtc freq");
14120 if (ioctl (rtc_fd, RTC_PIE_ON, 0) == -1) {
14121 perror ("start rtc");
14124 if (fcntl (rtc_fd, F_SETSIG, SIGPROF) == -1) {
14128 if (fcntl (rtc_fd, F_SETOWN, getpid ()) == -1) {
14132 enable_rtc_timer (TRUE);
14139 itval.it_interval.tv_usec = 999;
14140 itval.it_interval.tv_sec = 0;
14141 itval.it_value = itval.it_interval;
14142 setitimer (ITIMER_PROF, &itval, NULL);
14146 add_signal_handler (SIGPROF, sigprof_signal_handler);
14147 #elif defined (PLATFORM_WIN32)
14148 static int inited = 0;
14155 if (timeGetDevCaps (&timecaps, sizeof (timecaps)) != TIMERR_NOERROR)
14158 if ((win32_main_thread = OpenThread (READ_CONTROL | THREAD_GET_CONTEXT, FALSE, GetCurrentThreadId ())) == NULL)
14161 if (timeBeginPeriod (1) != TIMERR_NOERROR)
14164 if ((win32_timer = timeSetEvent (1, 0, win32_time_proc, 0, TIME_PERIODIC)) == 0) {
14171 /* mono_jit_create_remoting_trampoline:
14172 * @method: pointer to the method info
14174 * Creates a trampoline which calls the remoting functions. This
14175 * is used in the vtable of transparent proxies.
14177 * Returns: a pointer to the newly created code
14180 mono_jit_create_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
14183 guint8 *addr = NULL;
14185 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
14186 (mono_method_signature (method)->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class))) {
14187 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
14188 addr = mono_compile_method (nm);
14190 addr = mono_compile_method (method);
14192 return mono_get_addr_from_ftnptr (addr);
14195 #ifdef MONO_ARCH_HAVE_IMT
14197 mini_get_imt_trampoline (void)
14199 static gpointer tramp = NULL;
14201 tramp = mono_create_specific_trampoline (MONO_FAKE_IMT_METHOD, MONO_TRAMPOLINE_JIT, mono_get_root_domain (), NULL);
14206 #ifdef MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
14208 mini_get_vtable_trampoline (void)
14210 static gpointer tramp = NULL;
14212 tramp = mono_create_specific_trampoline (MONO_FAKE_VTABLE_METHOD, MONO_TRAMPOLINE_JIT, mono_get_root_domain (), NULL);
14218 mini_parse_debug_options (void)
14220 char *options = getenv ("MONO_DEBUG");
14221 gchar **args, **ptr;
14226 args = g_strsplit (options, ",", -1);
14228 for (ptr = args; ptr && *ptr; ptr++) {
14229 const char *arg = *ptr;
14231 if (!strcmp (arg, "handle-sigint"))
14232 debug_options.handle_sigint = TRUE;
14233 else if (!strcmp (arg, "keep-delegates"))
14234 debug_options.keep_delegates = TRUE;
14235 else if (!strcmp (arg, "collect-pagefault-stats"))
14236 debug_options.collect_pagefault_stats = TRUE;
14237 else if (!strcmp (arg, "break-on-unverified"))
14238 debug_options.break_on_unverified = TRUE;
14239 else if (!strcmp (arg, "no-gdb-backtrace"))
14240 debug_options.no_gdb_backtrace = TRUE;
14241 else if (!strcmp (arg, "dont-free-domains"))
14242 mono_dont_free_domains = TRUE;
14244 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
14245 fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'dont-free-domains'\n");
14254 mini_get_debug_options (void)
14256 return &debug_options;
14260 mini_create_jit_domain_info (MonoDomain *domain)
14262 MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
14264 info->class_init_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
14265 info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
14266 info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
14267 info->delegate_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
14269 domain->runtime_info = info;
14273 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
14275 g_slist_free (value);
14279 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
14281 MonoJitDynamicMethodInfo *di = value;
14282 mono_code_manager_destroy (di->code_mp);
14287 mini_free_jit_domain_info (MonoDomain *domain)
14289 MonoJitDomainInfo *info = domain_jit_info (domain);
14291 if (info->jump_target_hash) {
14292 g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
14293 g_hash_table_destroy (info->jump_target_hash);
14295 if (info->jump_target_got_slot_hash) {
14296 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_jump_list, NULL);
14297 g_hash_table_destroy (info->jump_target_got_slot_hash);
14299 if (info->dynamic_code_hash) {
14300 g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
14301 g_hash_table_destroy (info->dynamic_code_hash);
14303 if (info->method_code_hash)
14304 g_hash_table_destroy (info->method_code_hash);
14305 g_hash_table_destroy (info->class_init_trampoline_hash);
14306 g_hash_table_destroy (info->jump_trampoline_hash);
14307 g_hash_table_destroy (info->jit_trampoline_hash);
14308 g_hash_table_destroy (info->delegate_trampoline_hash);
14310 g_free (domain->runtime_info);
14311 domain->runtime_info = NULL;
14315 mini_init (const char *filename, const char *runtime_version)
14317 MonoDomain *domain;
14319 MONO_PROBE_VES_INIT_BEGIN ();
14322 if (access ("/proc/self/maps", F_OK) != 0) {
14323 g_print ("Mono requires /proc to be mounted.\n");
14328 /* Happens when using the embedding interface */
14329 if (!default_opt_set)
14330 default_opt = mono_parse_default_optimizations (NULL);
14332 InitializeCriticalSection (&jit_mutex);
14334 if (!global_codeman)
14335 global_codeman = mono_code_manager_new ();
14336 jit_icall_name_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
14338 mono_arch_cpu_init ();
14342 mono_trampolines_init ();
14344 if (!g_thread_supported ())
14345 g_thread_init (NULL);
14347 if (getenv ("MONO_DEBUG") != NULL)
14348 mini_parse_debug_options ();
14350 mono_gc_base_init ();
14352 mono_jit_tls_id = TlsAlloc ();
14353 setup_jit_tls_data ((gpointer)-1, mono_thread_abort);
14355 #ifndef DISABLE_JIT
14359 if (default_opt & MONO_OPT_AOT)
14362 mono_runtime_install_handlers ();
14363 mono_threads_install_cleanup (mini_thread_cleanup);
14365 #ifdef MONO_ARCH_HAVE_NOTIFY_PENDING_EXC
14366 // This is experimental code so provide an env var to switch it off
14367 if (getenv ("MONO_DISABLE_PENDING_EXCEPTIONS")) {
14368 printf ("MONO_DISABLE_PENDING_EXCEPTIONS env var set.\n");
14370 check_for_pending_exc = FALSE;
14371 mono_threads_install_notify_pending_exc (mono_arch_notify_pending_exc);
14375 #define JIT_TRAMPOLINES_WORK
14376 #ifdef JIT_TRAMPOLINES_WORK
14377 mono_install_compile_method (mono_jit_compile_method);
14378 mono_install_free_method (mono_jit_free_method);
14379 mono_install_trampoline (mono_create_jit_trampoline);
14380 mono_install_jump_trampoline (mono_create_jump_trampoline);
14381 mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
14382 mono_install_delegate_trampoline (mono_create_delegate_trampoline);
14383 mono_install_create_domain_hook (mini_create_jit_domain_info);
14384 mono_install_free_domain_hook (mini_free_jit_domain_info);
14386 #define JIT_INVOKE_WORKS
14387 #ifdef JIT_INVOKE_WORKS
14388 mono_install_runtime_invoke (mono_jit_runtime_invoke);
14390 mono_install_stack_walk (mono_jit_walk_stack);
14391 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
14392 mono_install_get_class_from_name (mono_aot_get_class_from_name);
14393 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
14395 if (debug_options.collect_pagefault_stats) {
14396 mono_raw_buffer_set_make_unreadable (TRUE);
14397 mono_aot_set_make_unreadable (TRUE);
14400 if (runtime_version)
14401 domain = mono_init_version (filename, runtime_version);
14403 domain = mono_init_from_assembly (filename, filename);
14405 if (mono_aot_only) {
14406 /* The IMT tables are very dynamic thus they are hard to AOT */
14407 mono_use_imt = FALSE;
14408 /* This helps catch code allocation requests */
14409 mono_code_manager_set_read_only (domain->code_mp);
14412 #ifdef MONO_ARCH_HAVE_IMT
14413 if (mono_use_imt) {
14414 mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
14415 mono_install_imt_trampoline (mini_get_imt_trampoline ());
14416 #if MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
14417 mono_install_vtable_trampoline (mini_get_vtable_trampoline ());
14422 /* This must come after mono_init () in the aot-only case */
14423 mono_exceptions_init ();
14424 mono_install_handler (mono_get_throw_exception ());
14426 mono_icall_init ();
14428 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
14429 ves_icall_get_frame_info);
14430 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
14431 ves_icall_get_trace);
14432 mono_add_internal_call ("System.Exception::get_trace",
14433 ves_icall_System_Exception_get_trace);
14434 mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityFrame",
14435 ves_icall_System_Security_SecurityFrame_GetSecurityFrame);
14436 mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityStack",
14437 ves_icall_System_Security_SecurityFrame_GetSecurityStack);
14438 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
14439 mono_runtime_install_handlers);
14442 create_helper_signature ();
14444 #define JIT_CALLS_WORK
14445 #ifdef JIT_CALLS_WORK
14446 /* Needs to be called here since register_jit_icall depends on it */
14447 mono_marshal_init ();
14449 mono_arch_register_lowlevel_calls ();
14450 register_icall (mono_profiler_method_enter, "mono_profiler_method_enter", NULL, TRUE);
14451 register_icall (mono_profiler_method_leave, "mono_profiler_method_leave", NULL, TRUE);
14452 register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
14453 register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
14454 register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
14455 register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "void", TRUE);
14456 register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
14458 register_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
14459 register_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
14460 register_icall (mono_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", "void ptr", TRUE);
14461 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
14462 register_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception",
14465 register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
14466 register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "void", FALSE);
14467 register_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", "void", FALSE);
14468 register_icall (mono_load_remote_field_new, "mono_load_remote_field_new", "object object ptr ptr", FALSE);
14469 register_icall (mono_store_remote_field_new, "mono_store_remote_field_new", "void object ptr ptr object", FALSE);
14472 * NOTE, NOTE, NOTE, NOTE:
14473 * when adding emulation for some opcodes, remember to also add a dummy
14474 * rule to the burg files, because we need the arity information to be correct.
14476 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
14477 mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, TRUE);
14478 mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, FALSE);
14479 mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, FALSE);
14480 mono_register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, FALSE);
14481 mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, FALSE);
14482 mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, FALSE);
14483 mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, FALSE);
14486 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
14487 mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, TRUE);
14488 mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, TRUE);
14489 mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, TRUE);
14492 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
14493 mono_register_opcode_emulation (CEE_DIV, "__emul_idiv", "int32 int32 int32", mono_idiv, FALSE);
14494 mono_register_opcode_emulation (CEE_DIV_UN, "__emul_idiv_un", "int32 int32 int32", mono_idiv_un, FALSE);
14495 mono_register_opcode_emulation (CEE_REM, "__emul_irem", "int32 int32 int32", mono_irem, FALSE);
14496 mono_register_opcode_emulation (CEE_REM_UN, "__emul_irem_un", "int32 int32 int32", mono_irem_un, FALSE);
14497 mono_register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, FALSE);
14498 mono_register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, FALSE);
14499 mono_register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, FALSE);
14500 mono_register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, FALSE);
14503 #ifdef MONO_ARCH_EMULATE_MUL_DIV
14504 mono_register_opcode_emulation (CEE_MUL_OVF, "__emul_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE);
14505 mono_register_opcode_emulation (CEE_MUL_OVF_UN, "__emul_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE);
14506 mono_register_opcode_emulation (CEE_MUL, "__emul_imul", "int32 int32 int32", mono_imul, TRUE);
14507 mono_register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, TRUE);
14508 mono_register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE);
14509 mono_register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE);
14511 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
14512 mono_register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, FALSE);
14515 mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, FALSE);
14516 mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, FALSE);
14517 mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, FALSE);
14518 mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, FALSE);
14520 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
14521 mono_register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, FALSE);
14523 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
14524 mono_register_opcode_emulation (CEE_CONV_R_UN, "__emul_conv_r_un", "double int32", mono_conv_to_r8_un, FALSE);
14525 mono_register_opcode_emulation (OP_ICONV_TO_R_UN, "__emul_iconv_to_r_un", "double int32", mono_conv_to_r8_un, FALSE);
14527 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
14528 mono_register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, FALSE);
14530 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
14531 mono_register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, FALSE);
14533 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
14534 mono_register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, FALSE);
14536 #ifdef MONO_ARCH_EMULATE_FREM
14537 mono_register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, FALSE);
14540 #ifdef MONO_ARCH_SOFT_FLOAT
14541 mono_register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, FALSE);
14542 mono_register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, FALSE);
14543 mono_register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, FALSE);
14544 mono_register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, FALSE);
14545 mono_register_opcode_emulation (CEE_CONV_R8, "__emul_conv_r8", "double int32", mono_conv_to_r8, FALSE);
14546 mono_register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, FALSE);
14547 mono_register_opcode_emulation (CEE_CONV_R4, "__emul_conv_r4", "double int32", mono_conv_to_r4, FALSE);
14548 mono_register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, FALSE);
14549 mono_register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, FALSE);
14550 mono_register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, FALSE);
14551 mono_register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, FALSE);
14552 mono_register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, FALSE);
14553 mono_register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, FALSE);
14554 mono_register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, FALSE);
14556 mono_register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, FALSE);
14557 mono_register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, FALSE);
14558 mono_register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, FALSE);
14559 mono_register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, FALSE);
14560 mono_register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, FALSE);
14561 mono_register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, FALSE);
14562 mono_register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, FALSE);
14563 mono_register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, FALSE);
14564 mono_register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, FALSE);
14565 mono_register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, FALSE);
14567 mono_register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, FALSE);
14568 mono_register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, FALSE);
14569 mono_register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, FALSE);
14570 mono_register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, FALSE);
14571 mono_register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, FALSE);
14573 register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
14574 register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
14575 register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
14578 #if SIZEOF_VOID_P == 4
14579 mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, TRUE);
14582 /* other jit icalls */
14583 register_icall (mono_delegate_ctor, "mono_delegate_ctor", "void object object ptr", FALSE);
14584 register_icall (mono_class_static_field_address , "mono_class_static_field_address",
14585 "ptr ptr ptr", FALSE);
14586 register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
14587 register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
14588 "ptr ptr ptr ptr", FALSE);
14589 register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
14590 register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
14591 register_icall (mono_helper_stelem_ref_check, "helper_stelem_ref_check", "void object object", FALSE);
14592 register_icall (mono_object_new, "mono_object_new", "object ptr ptr", FALSE);
14593 register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE);
14594 register_icall (mono_array_new, "mono_array_new", "object ptr ptr int32", FALSE);
14595 register_icall (mono_array_new_specific, "mono_array_new_specific", "object ptr int32", FALSE);
14596 register_icall (mono_runtime_class_init, "mono_runtime_class_init", "void ptr", FALSE);
14597 register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
14598 register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
14599 register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
14600 register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr", FALSE);
14601 register_icall (mono_helper_ldstr, "helper_ldstr", "object ptr int", FALSE);
14602 register_icall (mono_helper_ldstr_mscorlib, "helper_ldstr_mscorlib", "object int", FALSE);
14603 register_icall (mono_helper_newobj_mscorlib, "helper_newobj_mscorlib", "object int", FALSE);
14604 register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
14605 register_icall (mono_object_castclass, "mono_object_castclass", "object object ptr", FALSE);
14606 register_icall (mono_break, "mono_break", NULL, TRUE);
14607 register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
14608 register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
14609 register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
14610 register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
14611 register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
14614 mono_generic_sharing_init ();
14616 if (mono_compile_aot)
14618 * Avoid running managed code when AOT compiling, since the platform
14619 * might only support aot-only execution.
14621 mono_runtime_set_no_exec (TRUE);
14623 #define JIT_RUNTIME_WORKS
14624 #ifdef JIT_RUNTIME_WORKS
14625 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
14626 mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
14627 mono_thread_attach (domain);
14630 mono_profiler_runtime_initialized ();
14632 MONO_PROBE_VES_INIT_END ();
14637 MonoJitStats mono_jit_stats = {0};
14640 print_jit_stats (void)
14642 if (mono_jit_stats.enabled) {
14643 g_print ("Mono Jit statistics\n");
14644 g_print ("Compiled methods: %ld\n", mono_jit_stats.methods_compiled);
14645 g_print ("Methods from AOT: %ld\n", mono_jit_stats.methods_aot);
14646 g_print ("Methods cache lookup: %ld\n", mono_jit_stats.methods_lookups);
14647 g_print ("Method trampolines: %ld\n", mono_jit_stats.method_trampolines);
14648 g_print ("Basic blocks: %ld\n", mono_jit_stats.basic_blocks);
14649 g_print ("Max basic blocks: %ld\n", mono_jit_stats.max_basic_blocks);
14650 g_print ("Allocated vars: %ld\n", mono_jit_stats.allocate_var);
14651 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
14652 g_print ("Native code size: %ld\n", mono_jit_stats.native_code_size);
14653 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
14654 mono_jit_stats.max_ratio_method);
14655 g_print ("Biggest method: %ld (%s)\n", mono_jit_stats.biggest_method_size,
14656 mono_jit_stats.biggest_method);
14657 g_print ("Code reallocs: %ld\n", mono_jit_stats.code_reallocs);
14658 g_print ("Allocated code size: %ld\n", mono_jit_stats.allocated_code_size);
14659 g_print ("Inlineable methods: %ld\n", mono_jit_stats.inlineable_methods);
14660 g_print ("Inlined methods: %ld\n", mono_jit_stats.inlined_methods);
14661 g_print ("Regvars: %ld\n", mono_jit_stats.regvars);
14662 g_print ("Locals stack size: %ld\n", mono_jit_stats.locals_stack_size);
14664 g_print ("\nCreated object count: %ld\n", mono_stats.new_object_count);
14665 g_print ("Delegates created: %ld\n", mono_stats.delegate_creations);
14666 g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
14667 g_print ("Used classes: %ld\n", mono_stats.used_class_count);
14668 g_print ("Generic vtables: %ld\n", mono_stats.generic_vtable_count);
14669 g_print ("Methods: %ld\n", mono_stats.method_count);
14670 g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
14671 g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
14672 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
14674 g_print ("\nGeneric instances: %ld\n", mono_stats.generic_instance_count);
14675 g_print ("Initialized classes: %ld\n", mono_stats.generic_class_count);
14676 g_print ("Inflated methods: %ld / %ld\n", mono_stats.inflated_method_count_2,
14677 mono_stats.inflated_method_count);
14678 g_print ("Inflated types: %ld\n", mono_stats.inflated_type_count);
14679 g_print ("Generics metadata size: %ld\n", mono_stats.generics_metadata_size);
14680 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
14682 g_print ("Sharable generic methods: %ld\n", mono_stats.generics_sharable_methods);
14683 g_print ("Unsharable generic methods: %ld\n", mono_stats.generics_unsharable_methods);
14684 g_print ("Shared generic methods: %ld\n", mono_stats.generics_shared_methods);
14686 g_print ("Dynamic code allocs: %ld\n", mono_stats.dynamic_code_alloc_count);
14687 g_print ("Dynamic code bytes: %ld\n", mono_stats.dynamic_code_bytes_count);
14688 g_print ("Dynamic code frees: %ld\n", mono_stats.dynamic_code_frees_count);
14690 g_print ("IMT tables size: %ld\n", mono_stats.imt_tables_size);
14691 g_print ("IMT number of tables: %ld\n", mono_stats.imt_number_of_tables);
14692 g_print ("IMT number of methods: %ld\n", mono_stats.imt_number_of_methods);
14693 g_print ("IMT used slots: %ld\n", mono_stats.imt_used_slots);
14694 g_print ("IMT colliding slots: %ld\n", mono_stats.imt_slots_with_collisions);
14695 g_print ("IMT max collisions: %ld\n", mono_stats.imt_max_collisions_in_slot);
14696 g_print ("IMT methods at max col: %ld\n", mono_stats.imt_method_count_when_max_collisions);
14697 g_print ("IMT thunks size: %ld\n", mono_stats.imt_thunks_size);
14699 g_print ("JIT info table inserts: %ld\n", mono_stats.jit_info_table_insert_count);
14700 g_print ("JIT info table removes: %ld\n", mono_stats.jit_info_table_remove_count);
14701 g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count);
14703 g_print ("Hazardous pointers: %ld\n", mono_stats.hazardous_pointer_count);
14704 #ifdef HAVE_SGEN_GC
14705 g_print ("Minor GC collections: %ld\n", mono_stats.minor_gc_count);
14706 g_print ("Major GC collections: %ld\n", mono_stats.major_gc_count);
14707 g_print ("Minor GC time in msecs: %lf\n", (double)mono_stats.minor_gc_time_usecs / 1000.0);
14708 g_print ("Major GC time in msecs: %lf\n", (double)mono_stats.major_gc_time_usecs / 1000.0);
14710 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
14711 g_print ("\nDecl security check : %ld\n", mono_jit_stats.cas_declsec_check);
14712 g_print ("LinkDemand (user) : %ld\n", mono_jit_stats.cas_linkdemand);
14713 g_print ("LinkDemand (icall) : %ld\n", mono_jit_stats.cas_linkdemand_icall);
14714 g_print ("LinkDemand (pinvoke) : %ld\n", mono_jit_stats.cas_linkdemand_pinvoke);
14715 g_print ("LinkDemand (aptc) : %ld\n", mono_jit_stats.cas_linkdemand_aptc);
14716 g_print ("Demand (code gen) : %ld\n", mono_jit_stats.cas_demand_generation);
14718 if (debug_options.collect_pagefault_stats) {
14719 g_print ("Metadata pagefaults : %d\n", mono_raw_buffer_get_n_pagefaults ());
14720 g_print ("AOT pagefaults : %d\n", mono_aot_get_n_pagefaults ());
14723 g_free (mono_jit_stats.max_ratio_method);
14724 mono_jit_stats.max_ratio_method = NULL;
14725 g_free (mono_jit_stats.biggest_method);
14726 mono_jit_stats.biggest_method = NULL;
14731 mini_cleanup (MonoDomain *domain)
14733 #ifdef HAVE_LINUX_RTC_H
14735 enable_rtc_timer (FALSE);
14739 * mono_runtime_cleanup() and mono_domain_finalize () need to
14740 * be called early since they need the execution engine still
14741 * fully working (mono_domain_finalize may invoke managed finalizers
14742 * and mono_runtime_cleanup will wait for other threads to finish).
14744 mono_domain_finalize (domain, 2000);
14746 /* This accesses metadata so needs to be called before runtime shutdown */
14747 print_jit_stats ();
14749 mono_runtime_cleanup (domain);
14751 mono_profiler_shutdown ();
14753 mono_icall_cleanup ();
14755 mono_runtime_cleanup_handlers ();
14757 mono_domain_free (domain, TRUE);
14759 mono_debugger_cleanup ();
14761 mono_trampolines_cleanup ();
14763 if (!mono_dont_free_global_codeman)
14764 mono_code_manager_destroy (global_codeman);
14765 g_hash_table_destroy (jit_icall_name_hash);
14766 g_free (emul_opcode_map);
14768 mono_arch_cleanup ();
14772 mono_trace_cleanup ();
14774 mono_counters_dump (-1, stdout);
14776 if (mono_inject_async_exc_method)
14777 mono_method_desc_free (mono_inject_async_exc_method);
14779 TlsFree(mono_jit_tls_id);
14781 DeleteCriticalSection (&jit_mutex);
14783 DeleteCriticalSection (&mono_delegate_section);
14787 mono_set_defaults (int verbose_level, guint32 opts)
14789 mini_verbose = verbose_level;
14790 default_opt = opts;
14791 default_opt_set = TRUE;
14795 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
14797 GHashTable *assemblies = (GHashTable*)user_data;
14798 MonoImage *image = mono_assembly_get_image (ass);
14799 MonoMethod *method, *invoke;
14802 if (g_hash_table_lookup (assemblies, ass))
14805 g_hash_table_insert (assemblies, ass, ass);
14807 if (mini_verbose > 0)
14808 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
14810 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
14811 method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
14812 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
14816 if (mini_verbose > 1) {
14817 char * desc = mono_method_full_name (method, TRUE);
14818 g_print ("Compiling %d %s\n", count, desc);
14821 mono_compile_method (method);
14822 if (strcmp (method->name, "Finalize") == 0) {
14823 invoke = mono_marshal_get_runtime_invoke (method);
14824 mono_compile_method (invoke);
14826 if (method->klass->marshalbyref && mono_method_signature (method)->hasthis) {
14827 invoke = mono_marshal_get_remoting_invoke_with_check (method);
14828 mono_compile_method (invoke);
14832 /* Load and precompile referenced assemblies as well */
14833 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
14834 mono_assembly_load_reference (image, i);
14835 if (image->references [i])
14836 mono_precompile_assembly (image->references [i], assemblies);
14840 void mono_precompile_assemblies ()
14842 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
14844 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
14846 g_hash_table_destroy (assemblies);