[io-layer] Extract error (#4279)
[mono.git] / mono / mini / mini.c
index fff5ece8d5512e319ffe7c3a70bbaf25e5ba2b24..dd83dab383128373a8e23668f07e810803c4dc79 100644 (file)
@@ -47,6 +47,7 @@
 #include <mono/metadata/mempool-internals.h>
 #include <mono/metadata/attach.h>
 #include <mono/metadata/runtime.h>
+#include <mono/metadata/attrdefs.h>
 #include <mono/utils/mono-math.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-counters.h>
@@ -59,7 +60,6 @@
 #include <mono/utils/dtrace.h>
 #include <mono/utils/mono-threads.h>
 #include <mono/utils/mono-threads-coop.h>
-#include <mono/io-layer/io-layer.h>
 
 #include "mini.h"
 #include "seq-points.h"
@@ -76,6 +76,7 @@
 #include "debugger-agent.h"
 #include "llvm-runtime.h"
 #include "mini-llvm.h"
+#include "lldb.h"
 
 MonoTraceSpec *mono_jit_trace_calls;
 MonoMethodDesc *mono_inject_async_exc_method;
@@ -85,6 +86,10 @@ int mono_break_at_bb_bb_num;
 gboolean mono_do_x86_stack_align = TRUE;
 gboolean mono_using_xdebug;
 
+/* Counters */
+static guint32 discarded_code;
+static double discarded_jit_time;
+
 #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
 #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
 static mono_mutex_t jit_mutex;
@@ -365,6 +370,8 @@ handle_enum:
        case MONO_TYPE_TYPEDBYREF:
                return OP_STOREV_MEMBASE;
        case MONO_TYPE_GENERICINST:
+               if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
+                       return OP_STOREX_MEMBASE;
                type = &type->data.generic_class->container_class->byval_arg;
                goto handle_enum;
        case MONO_TYPE_VAR:
@@ -419,6 +426,8 @@ mono_type_to_load_membase (MonoCompile *cfg, MonoType *type)
        case MONO_TYPE_TYPEDBYREF:
                return OP_LOADV_MEMBASE;
        case MONO_TYPE_GENERICINST:
+               if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
+                       return OP_LOADX_MEMBASE;
                if (mono_type_generic_inst_is_valuetype (type))
                        return OP_LOADV_MEMBASE;
                else
@@ -1052,7 +1061,7 @@ mini_method_verify (MonoCompile *cfg, MonoMethod *method, gboolean fail_compile)
                                        else if (info->exception_type == MONO_EXCEPTION_FIELD_ACCESS)
                                                mono_error_set_generic_error (&cfg->error, "System", "FieldAccessException", "%s", msg);
                                        else if (info->exception_type == MONO_EXCEPTION_UNVERIFIABLE_IL)
-                                               mono_error_set_generic_error (&cfg->error, "System.Security", "VerificationException", msg);
+                                               mono_error_set_generic_error (&cfg->error, "System.Security", "VerificationException", "%s", msg);
                                        if (!mono_error_ok (&cfg->error)) {
                                                mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
                                                g_free (msg);
@@ -1948,92 +1957,6 @@ mono_destroy_compile (MonoCompile *cfg)
        g_free (cfg);
 }
 
-static MonoInst*
-mono_create_tls_get_offset (MonoCompile *cfg, int offset)
-{
-       MonoInst* ins;
-
-       if (!cfg->backend->have_tls_get)
-               return NULL;
-
-       if (offset == -1)
-               return NULL;
-
-       MONO_INST_NEW (cfg, ins, OP_TLS_GET);
-       ins->dreg = mono_alloc_preg (cfg);
-       ins->inst_offset = offset;
-       return ins;
-}
-
-gboolean
-mini_tls_get_supported (MonoCompile *cfg, MonoTlsKey key)
-{
-       if (!cfg->backend->have_tls_get)
-               return FALSE;
-
-       if (cfg->compile_aot)
-               return cfg->backend->have_tls_get_reg;
-       else
-               return mini_get_tls_offset (key) != -1;
-}
-
-MonoInst*
-mono_create_tls_get (MonoCompile *cfg, MonoTlsKey key)
-{
-       if (!cfg->backend->have_tls_get)
-               return NULL;
-
-       /*
-        * TLS offsets might be different at AOT time, so load them from a GOT slot and
-        * use a different opcode.
-        */
-       if (cfg->compile_aot) {
-               if (cfg->backend->have_tls_get_reg) {
-                       MonoInst *ins, *c;
-
-                       EMIT_NEW_TLS_OFFSETCONST (cfg, c, key);
-                       MONO_INST_NEW (cfg, ins, OP_TLS_GET_REG);
-                       ins->dreg = mono_alloc_preg (cfg);
-                       ins->sreg1 = c->dreg;
-                       return ins;
-               } else {
-                       return NULL;
-               }
-       }
-
-       return mono_create_tls_get_offset (cfg, mini_get_tls_offset (key));
-}
-
-MonoInst*
-mono_get_jit_tls_intrinsic (MonoCompile *cfg)
-{
-       return mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
-}
-
-MonoInst*
-mono_get_domain_intrinsic (MonoCompile* cfg)
-{
-       return mono_create_tls_get (cfg, TLS_KEY_DOMAIN);
-}
-
-MonoInst*
-mono_get_thread_intrinsic (MonoCompile* cfg)
-{
-       return mono_create_tls_get (cfg, TLS_KEY_THREAD);
-}
-
-MonoInst*
-mono_get_lmf_intrinsic (MonoCompile* cfg)
-{
-       return mono_create_tls_get (cfg, TLS_KEY_LMF);
-}
-
-MonoInst*
-mono_get_lmf_addr_intrinsic (MonoCompile* cfg)
-{
-       return mono_create_tls_get (cfg, TLS_KEY_LMF_ADDR);
-}
-
 void
 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
 {
@@ -2126,8 +2049,10 @@ mono_compile_create_vars (MonoCompile *cfg)
 
        cfg->args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, (sig->param_count + sig->hasthis) * sizeof (MonoInst*));
 
-       if (sig->hasthis)
+       if (sig->hasthis) {
                cfg->args [0] = mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
+               cfg->this_arg = cfg->args [0];
+       }
 
        for (i = 0; i < sig->param_count; ++i) {
                cfg->args [i + sig->hasthis] = mono_compile_create_var (cfg, sig->params [i], OP_ARG);
@@ -2397,20 +2322,17 @@ mono_codegen (MonoCompile *cfg)
  
        if (cfg->verbose_level > 0) {
                char* nm = mono_method_get_full_name (cfg->method);
-               char *opt_descr = mono_opt_descr (cfg->opt);
-               g_print ("Method %s emitted at %p to %p (code length %d) [%s] with opts %s\n", 
+               g_print ("Method %s emitted at %p to %p (code length %d) [%s]\n",
                                 nm, 
-                                cfg->native_code, cfg->native_code + cfg->code_len, cfg->code_len, cfg->domain->friendly_name,
-                                opt_descr);
+                                cfg->native_code, cfg->native_code + cfg->code_len, cfg->code_len, cfg->domain->friendly_name);
                g_free (nm);
-               g_free (opt_descr);
        }
 
        {
                gboolean is_generic = FALSE;
 
                if (cfg->method->is_inflated || mono_method_get_generic_container (cfg->method) ||
-                               cfg->method->klass->generic_container || cfg->method->klass->generic_class) {
+                               mono_class_is_gtd (cfg->method->klass) || mono_class_is_ginst (cfg->method->klass)) {
                        is_generic = TRUE;
                }
 
@@ -2927,7 +2849,8 @@ is_open_method (MonoMethod *method)
        return FALSE;
 }
 
-static void mono_insert_nop_in_empty_bb (MonoCompile *cfg)
+static void
+mono_insert_nop_in_empty_bb (MonoCompile *cfg)
 {
        MonoBasicBlock *bb;
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
@@ -3124,16 +3047,11 @@ init_backend (MonoBackend *backend)
 #ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
        backend->have_objc_get_selector = 1;
 #endif
-#ifdef MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK
-       backend->have_generalized_imt_thunk = 1;
+#ifdef MONO_ARCH_HAVE_GENERALIZED_IMT_TRAMPOLINE
+       backend->have_generalized_imt_trampoline = 1;
 #endif
 #ifdef MONO_ARCH_GSHARED_SUPPORTED
        backend->gshared_supported = 1;
-#endif
-       if (MONO_ARCH_HAVE_TLS_GET)
-               backend->have_tls_get = 1;
-#ifdef MONO_ARCH_HAVE_TLS_GET_REG
-               backend->have_tls_get_reg = 1;
 #endif
        if (MONO_ARCH_USE_FPSTACK)
                backend->use_fpstack = 1;
@@ -3163,6 +3081,9 @@ init_backend (MonoBackend *backend)
 #ifdef MONO_ARCH_DYN_CALL_PARAM_AREA
        backend->dyn_call_param_area = MONO_ARCH_DYN_CALL_PARAM_AREA;
 #endif
+#ifdef MONO_ARCH_NO_DIV_WITH_MUL
+       backend->disable_div_with_mul = 1;
+#endif
 }
 
 /*
@@ -3300,6 +3221,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
        cfg->soft_breakpoints = debug_options.soft_breakpoints;
        cfg->check_pinvoke_callconv = debug_options.check_pinvoke_callconv;
        cfg->disable_direct_icalls = disable_direct_icalls;
+       cfg->direct_pinvoke = (flags & JIT_FLAG_DIRECT_PINVOKE) != 0;
        if (try_generic_shared)
                cfg->gshared = TRUE;
        cfg->compile_llvm = try_llvm;
@@ -3320,7 +3242,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
                cfg->seq_points = g_ptr_array_new ();
        mono_error_init (&cfg->error);
 
-       if (cfg->compile_aot && !try_generic_shared && (method->is_generic || method->klass->generic_container || method_is_gshared)) {
+       if (cfg->compile_aot && !try_generic_shared && (method->is_generic || mono_class_is_gtd (method->klass) || method_is_gshared)) {
                cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED;
                return cfg;
        }
@@ -3958,20 +3880,21 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
        }
 #endif
 
-       if (!cfg->compile_aot)
-               mono_save_xdebug_info (cfg);
-
        MONO_TIME_TRACK (mono_jit_stats.jit_gc_create_gc_map, mini_gc_create_gc_map (cfg));
        MONO_TIME_TRACK (mono_jit_stats.jit_save_seq_point_info, mono_save_seq_point_info (cfg));
 
+       if (!cfg->compile_aot) {
+               mono_save_xdebug_info (cfg);
+               mono_lldb_save_method_info (cfg);
+       }
+
        if (cfg->verbose_level >= 2) {
                char *id =  mono_method_full_name (cfg->method, FALSE);
                mono_disassemble_code (cfg, cfg->native_code, cfg->code_len, id + 3);
                g_free (id);
        }
 
-       if (!cfg->compile_aot) {
+       if (!cfg->compile_aot && !(flags & JIT_FLAG_DISCARD_RESULTS)) {
                mono_domain_lock (cfg->domain);
                mono_jit_info_table_add (cfg->domain, cfg->jit_info);
 
@@ -4013,6 +3936,34 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
        return cfg;
 }
 
+gboolean
+mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
+{
+       int i;
+       MonoGenericContainer *container;
+       MonoGenericInst *ginst;
+
+       if (mono_class_is_ginst (klass)) {
+               container = mono_class_get_generic_container (mono_class_get_generic_class (klass)->container_class);
+               ginst = mono_class_get_generic_class (klass)->context.class_inst;
+       } else if (mono_class_is_gtd (klass) && context_used) {
+               container = mono_class_get_generic_container (klass);
+               ginst = container->context.class_inst;
+       } else {
+               return FALSE;
+       }
+
+       for (i = 0; i < container->type_argc; ++i) {
+               MonoType *type;
+               if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
+                       continue;
+               type = ginst->type_argv [i];
+               if (mini_type_is_reference (type))
+                       return TRUE;
+       }
+       return FALSE;
+}
+
 void*
 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
 {
@@ -4041,7 +3992,7 @@ void
 mono_cfg_set_exception_invalid_program (MonoCompile *cfg, char *msg)
 {
        mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
-       mono_error_set_generic_error (&cfg->error, "System", "InvalidProgramException", msg);
+       mono_error_set_generic_error (&cfg->error, "System", "InvalidProgramException", "%s", msg);
 }
 
 #endif /* DISABLE_JIT */
@@ -4229,7 +4180,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
 
        if (mono_aot_only) {
                char *fullname = mono_method_full_name (method, TRUE);
-               mono_error_set_execution_engine (error, "Attempting to JIT compile method '%s' while running with --aot-only. See http://docs.xamarin.com/ios/about/limitations for more information.\n", fullname);
+               mono_error_set_execution_engine (error, "Attempting to JIT compile method '%s' while running in aot-only mode. See https://developer.xamarin.com/guides/ios/advanced_topics/limitations/ for more information.\n", fullname);
                g_free (fullname);
 
                return NULL;
@@ -4237,7 +4188,9 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
 
        jit_timer = mono_time_track_start ();
        cfg = mini_method_compile (method, opt, target_domain, JIT_FLAG_RUN_CCTORS, 0, -1);
-       mono_time_track_end (&mono_jit_stats.jit_time, jit_timer);
+       double jit_time = 0.0;
+       mono_time_track_end (&jit_time, jit_timer);
+       mono_jit_stats.jit_time += jit_time;
 
        prof_method = cfg->method;
 
@@ -4305,7 +4258,8 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                /* We can't use a domain specific method in another domain */
                if ((target_domain == mono_domain_get ()) || info->domain_neutral) {
                        code = info->code_start;
-//                     printf("Discarding code for method %s\n", method->name);
+                       discarded_code ++;
+                       discarded_jit_time += jit_time;
                }
        }
        if (code == NULL) {
@@ -4385,9 +4339,8 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
 
        vtable = mono_class_vtable (target_domain, method->klass);
        if (!vtable) {
-               ex = mono_class_get_exception_for_failure (method->klass);
-               g_assert (ex);
-               mono_error_set_exception_instance (error, ex);
+               g_assert (mono_class_has_failure (method->klass));
+               mono_error_set_for_class_failure (error, method->klass);
                return NULL;
        }
 
@@ -4426,6 +4379,9 @@ mini_get_underlying_type (MonoType *type)
 void
 mini_jit_init (void)
 {
+       mono_counters_register ("Discarded method code", MONO_COUNTER_JIT | MONO_COUNTER_INT, &discarded_code);
+       mono_counters_register ("Time spent JITting discarded code", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &discarded_jit_time);
+
        mono_os_mutex_init_recursive (&jit_mutex);
 #ifndef DISABLE_JIT
        current_backend = g_new0 (MonoBackend, 1);