Merge pull request #2403 from BrzVlad/feature-emulation-delay
[mono.git] / mono / mini / driver.c
index 884d4a82ae9b88e5ab0a4f5fafe79e0f5d58f28b..ab0fab80d49bfbb5d9276f9e7c8559a7b94ca46d 100644 (file)
@@ -45,7 +45,7 @@
 #include <mono/metadata/mono-debug.h>
 #include <mono/metadata/security-manager.h>
 #include <mono/metadata/security-core-clr.h>
-#include <mono/metadata/gc-internal.h>
+#include <mono/metadata/gc-internals.h>
 #include <mono/metadata/coree.h>
 #include <mono/metadata/attach.h>
 #include "mono/utils/mono-counters.h"
 
 #include "mini.h"
 #include "jit.h"
+#include "aot-compiler.h"
+
 #include <string.h>
 #include <ctype.h>
 #include <locale.h>
 #include "version.h"
 #include "debugger-agent.h"
+#if TARGET_OSX
+#   include <sys/resource.h>
+#endif
 
 static FILE *mini_stats_fd;
 
@@ -145,7 +150,7 @@ extern char *nacl_mono_path;
 #define EXCLUDED_FROM_ALL (MONO_OPT_SHARED | MONO_OPT_PRECOMP | MONO_OPT_UNSAFE | MONO_OPT_GSHAREDVT | MONO_OPT_FLOAT32)
 
 static guint32
-parse_optimizations (guint32 opt, const char* p)
+parse_optimizations (guint32 opt, const char* p, gboolean cpu_opts)
 {
        guint32 exclude = 0;
        const char *n;
@@ -155,8 +160,10 @@ parse_optimizations (guint32 opt, const char* p)
        mono_hwcap_init ();
 
        /* call out to cpu detection code here that sets the defaults ... */
-       opt |= mono_arch_cpu_optimizations (&exclude);
-       opt &= ~exclude;
+       if (cpu_opts) {
+               opt |= mono_arch_cpu_optimizations (&exclude);
+               opt &= ~exclude;
+       }
        if (!p)
                return opt;
 
@@ -282,12 +289,12 @@ mono_parse_default_optimizations (const char* p)
 {
        guint32 opt;
 
-       opt = parse_optimizations (DEFAULT_OPTIMIZATIONS, p);
+       opt = parse_optimizations (DEFAULT_OPTIMIZATIONS, p, TRUE);
        return opt;
 }
 
-static char*
-opt_descr (guint32 flags) {
+char*
+mono_opt_descr (guint32 flags) {
        GString *str = g_string_new ("");
        int i, need_comma;
 
@@ -356,7 +363,7 @@ mini_regression_step (MonoImage *image, int verbose, int *total_run, int *total,
        int i;
 
        mono_set_defaults (verbose, opt_flags);
-       n = opt_descr (opt_flags);
+       n = mono_opt_descr (opt_flags);
        g_print ("Test run: image=%s, opts=%s\n", mono_image_get_filename (image), n);
        g_free (n);
        cfailed = failed = run = code_size = 0;
@@ -390,7 +397,7 @@ mini_regression_step (MonoImage *image, int verbose, int *total_run, int *total,
                                if (verbose >= 2)
                                        g_print ("Running '%s' ...\n", method->name);
 #ifdef MONO_USE_AOT_COMPILER
-                               if ((func = mono_aot_get_method (mono_get_root_domain (), method)))
+                               if ((func = (TestMethod)mono_aot_get_method (mono_get_root_domain (), method)))
                                        ;
                                else
 #endif
@@ -450,7 +457,7 @@ mini_regression (MonoImage *image, int verbose, int *total_run)
                fprintf (mini_stats_fd, "$graph->set_legend(qw(");
                for (opt = 0; opt < G_N_ELEMENTS (opt_sets); opt++) {
                        guint32 opt_flags = opt_sets [opt];
-                       n = opt_descr (opt_flags);
+                       n = mono_opt_descr (opt_flags);
                        if (!n [0])
                                n = (char *)"none";
                        if (opt)
@@ -495,7 +502,7 @@ mini_regression (MonoImage *image, int verbose, int *total_run)
                for (iter = mono_single_method_list; iter; iter = g_slist_next (iter)) {
                        char *method_name;
 
-                       mono_current_single_method = iter->data;
+                       mono_current_single_method = (MonoMethod *)iter->data;
 
                        method_name = mono_method_full_name (mono_current_single_method, TRUE);
                        g_print ("Current single method: %s\n", method_name);
@@ -932,7 +939,7 @@ compile_all_methods_thread_main_inner (CompileAllThreadArgs *args)
                        g_print ("Compiling %d %s\n", count, desc);
                        g_free (desc);
                }
-               cfg = mini_method_compile (method, mono_get_optimizations_for_method (method, args->opts), mono_get_root_domain (), 0, 0, -1);
+               cfg = mini_method_compile (method, mono_get_optimizations_for_method (method, args->opts), mono_get_root_domain (), (JitFlags)0, 0, -1);
                if (cfg->exception_type != MONO_EXCEPTION_NONE) {
                        printf ("Compilation of %s failed with exception '%s':\n", mono_method_full_name (cfg->method, TRUE), cfg->exception_message);
                        fail_count ++;
@@ -1015,7 +1022,7 @@ typedef struct
 
 static void main_thread_handler (gpointer user_data)
 {
-       MainThreadArgs *main_args = user_data;
+       MainThreadArgs *main_args = (MainThreadArgs *)user_data;
        MonoAssembly *assembly;
 
        if (mono_compile_aot) {
@@ -1077,7 +1084,7 @@ load_agent (MonoDomain *domain, char *desc)
        MonoImageOpenStatus open_status;
 
        if (col) {
-               agent = g_memdup (desc, col - desc + 1);
+               agent = (char *)g_memdup (desc, col - desc + 1);
                agent [col - desc] = '\0';
                args = col + 1;
        } else {
@@ -1151,6 +1158,7 @@ mini_usage_jitdeveloper (void)
                 "    --inject-async-exc METHOD OFFSET Inject an asynchronous exception at METHOD\n"
                 "    --verify-all           Run the verifier on all assemblies and methods\n"
                 "    --full-aot             Avoid JITting any code\n"
+                "    --llvmonly             Use LLVM compiled code only\n"
                 "    --agent=ASSEMBLY[:ARG] Loads the specific agent assembly and executes its Main method with the given argument before loading the main assembly.\n"
                 "    --no-x86-stack-align   Don't align stack on x86\n"
                 "\n"
@@ -1205,6 +1213,9 @@ mini_usage (void)
                "                           Currently the only supported option is 'disable'.\n"
                "    --llvm, --nollvm       Controls whenever the runtime uses LLVM to compile code.\n"
                "    --gc=[sgen,boehm]      Select SGen or Boehm GC (runs mono or mono-sgen)\n"
+#ifdef TARGET_OSX
+               "    --arch=[32,64]         Select architecture (runs mono32 or mono64)\n"
+#endif
 #ifdef HOST_WIN32
                "    --mixed-mode           Enable mixed-mode image support.\n"
 #endif
@@ -1251,9 +1262,9 @@ mini_debug_usage (void)
 }
 
 #if defined(MONO_ARCH_ARCHITECTURE)
-/* Redefine ARCHITECTURE to include more information */
-#undef ARCHITECTURE
-#define ARCHITECTURE MONO_ARCH_ARCHITECTURE
+/* Redefine MONO_ARCHITECTURE to include more information */
+#undef MONO_ARCHITECTURE
+#define MONO_ARCHITECTURE MONO_ARCH_ARCHITECTURE
 #endif
 
 static const char info[] =
@@ -1274,7 +1285,7 @@ static const char info[] =
 #else
     "\tNotification:  Thread + polling\n"
 #endif
-        "\tArchitecture:  " ARCHITECTURE "\n"
+        "\tArchitecture:  " MONO_ARCHITECTURE "\n"
        "\tDisabled:      " DISABLED_FEATURES "\n"
        "\tMisc:          "
 #ifdef MONO_SMALL_CONFIG
@@ -1365,10 +1376,10 @@ mono_jit_parse_options (int argc, char * argv[])
                        opt->soft_breakpoints = TRUE;
                        opt->explicit_null_checks = TRUE;
                } else if (strncmp (argv [i], "--optimize=", 11) == 0) {
-                       opt = parse_optimizations (opt, argv [i] + 11);
+                       opt = parse_optimizations (opt, argv [i] + 11, TRUE);
                        mono_set_optimizations (opt);
                } else if (strncmp (argv [i], "-O=", 3) == 0) {
-                       opt = parse_optimizations (opt, argv [i] + 3);
+                       opt = parse_optimizations (opt, argv [i] + 3, TRUE);
                        mono_set_optimizations (opt);
                } else if (strcmp (argv [i], "--trace") == 0) {
                        trace_options = (char*)"";
@@ -1429,7 +1440,7 @@ mono_set_use_smp (int use_smp)
 #ifdef GLIBC_BEFORE_2_3_4_SCHED_SETAFFINITY
                sched_setaffinity (getpid(), (gpointer)&proc_mask);
 #else
-               sched_setaffinity (getpid(), sizeof (unsigned long), (gpointer)&proc_mask);
+               sched_setaffinity (getpid(), sizeof (unsigned long), (const cpu_set_t *)&proc_mask);
 #endif
        }
 #endif
@@ -1462,6 +1473,52 @@ switch_gc (char* argv[], const char* target_gc)
 #endif
 }
 
+#ifdef TARGET_OSX
+
+/*
+ * tries to increase the minimum number of files, if the number is below 1024
+ */
+static void
+darwin_change_default_file_handles ()
+{
+       struct rlimit limit;
+       
+       if (getrlimit (RLIMIT_NOFILE, &limit) == 0){
+               if (limit.rlim_cur < 1024){
+                       limit.rlim_cur = MAX(1024,limit.rlim_cur);
+                       setrlimit (RLIMIT_NOFILE, &limit);
+               }
+       }
+}
+
+static void
+switch_arch (char* argv[], const char* target_arch)
+{
+       GString *path;
+       gsize arch_offset;
+
+       if ((strcmp (target_arch, "32") == 0 && strcmp (MONO_ARCHITECTURE, "x86") == 0) ||
+               (strcmp (target_arch, "64") == 0 && strcmp (MONO_ARCHITECTURE, "amd64") == 0)) {
+               return; /* matching arch loaded */
+       }
+
+       path = g_string_new (argv [0]);
+       arch_offset = path->len -2; /* last two characters */
+
+       /* Remove arch suffix if present */
+       if (strstr (&path->str[arch_offset], "32") || strstr (&path->str[arch_offset], "64")) {
+               g_string_truncate (path, arch_offset);
+       }
+
+       g_string_append (path, target_arch);
+
+       if (execvp (path->str, argv) < 0) {
+               fprintf (stderr, "Error: --arch=%s Failed to switch to '%s'.\n", target_arch, path->str);
+               exit (1);
+       }
+}
+
+#endif
 /**
  * mono_main:
  * @argc: number of arguments in the argv array
@@ -1484,7 +1541,7 @@ mono_main (int argc, char* argv[])
        char *config_file = NULL;
        int i, count = 1;
        guint32 opt, action = DO_EXEC, recompilation_times = 1;
-       MonoGraphOptions mono_graph_options = 0;
+       MonoGraphOptions mono_graph_options = (MonoGraphOptions)0;
        int mini_verbose = 0;
        gboolean enable_profile = FALSE;
        char *trace_options = NULL;
@@ -1514,6 +1571,10 @@ mono_main (int argc, char* argv[])
 
        setlocale (LC_ALL, "");
 
+#if TARGET_OSX
+       darwin_change_default_file_handles ();
+#endif
+       
        if (g_getenv ("MONO_NO_SMP"))
                mono_set_use_smp (FALSE);
        
@@ -1530,7 +1591,7 @@ mono_main (int argc, char* argv[])
                } else if (strncmp (argv [i], "--single-method=", 16) == 0) {
                        char *full_opts = g_strdup_printf ("-all,%s", argv [i] + 16);
                        action = DO_SINGLE_METHOD_REGRESSION;
-                       mono_single_method_regression_opt = parse_optimizations (opt, full_opts);
+                       mono_single_method_regression_opt = parse_optimizations (opt, full_opts, TRUE);
                        g_free (full_opts);
                } else if (strcmp (argv [i], "--verbose") == 0 || strcmp (argv [i], "-v") == 0) {
                        mini_verbose++;
@@ -1580,14 +1641,33 @@ mono_main (int argc, char* argv[])
                        }
                        mini_stats_fd = fopen (argv [++i], "w+");
                } else if (strncmp (argv [i], "--optimize=", 11) == 0) {
-                       opt = parse_optimizations (opt, argv [i] + 11);
+                       opt = parse_optimizations (opt, argv [i] + 11, TRUE);
                } else if (strncmp (argv [i], "-O=", 3) == 0) {
-                       opt = parse_optimizations (opt, argv [i] + 3);
+                       opt = parse_optimizations (opt, argv [i] + 3, TRUE);
+               } else if (strncmp (argv [i], "--bisect=", 9) == 0) {
+                       char *param = argv [i] + 9;
+                       char *sep = strchr (param, ':');
+                       if (!sep) {
+                               fprintf (stderr, "Error: --bisect requires OPT:FILENAME\n");
+                               return 1;
+                       }
+                       char *opt_string = g_strndup (param, sep - param);
+                       guint32 opt = parse_optimizations (0, opt_string, FALSE);
+                       g_free (opt_string);
+                       mono_set_bisect_methods (opt, sep + 1);
                } else if (strcmp (argv [i], "--gc=sgen") == 0) {
                        switch_gc (argv, "sgen");
                } else if (strcmp (argv [i], "--gc=boehm") == 0) {
                        switch_gc (argv, "boehm");
-               } else if (strcmp (argv [i], "--config") == 0) {
+               }
+#ifdef TARGET_OSX
+               else if (strcmp (argv [i], "--arch=32") == 0) {
+                       switch_arch (argv, "32");
+               } else if (strcmp (argv [i], "--arch=64") == 0) {
+                       switch_arch (argv, "64");
+               }
+#endif
+               else if (strcmp (argv [i], "--config") == 0) {
                        if (i +1 >= argc){
                                fprintf (stderr, "error: --config requires a filename argument\n");
                                return 1;
@@ -1646,6 +1726,9 @@ mono_main (int argc, char* argv[])
                        mono_verifier_enable_verify_all ();
                } else if (strcmp (argv [i], "--full-aot") == 0) {
                        mono_aot_only = TRUE;
+               } else if (strcmp (argv [i], "--llvmonly") == 0) {
+                       mono_aot_only = TRUE;
+                       mono_llvm_only = TRUE;
                } else if (strcmp (argv [i], "--print-vtable") == 0) {
                        mono_print_vtable = TRUE;
                } else if (strcmp (argv [i], "--stats") == 0) {
@@ -2066,10 +2149,10 @@ mono_main (int argc, char* argv[])
                        (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
                        MonoMethod *nm;
                        nm = mono_marshal_get_native_wrapper (method, TRUE, FALSE);
-                       cfg = mini_method_compile (nm, opt, mono_get_root_domain (), 0, part, -1);
+                       cfg = mini_method_compile (nm, opt, mono_get_root_domain (), (JitFlags)0, part, -1);
                }
                else
-                       cfg = mini_method_compile (method, opt, mono_get_root_domain (), 0, part, -1);
+                       cfg = mini_method_compile (method, opt, mono_get_root_domain (), (JitFlags)0, part, -1);
                if ((mono_graph_options & MONO_GRAPH_CFG_SSA) && !(cfg->comp_done & MONO_COMP_SSA)) {
                        g_warning ("no SSA info available (use -O=deadce)");
                        return 1;
@@ -2088,7 +2171,7 @@ mono_main (int argc, char* argv[])
                        fprintf (mini_stats_fd, "[");
                        for (i = 0; i < G_N_ELEMENTS (opt_sets); i++) {
                                opt = opt_sets [i];
-                               n = opt_descr (opt);
+                               n = mono_opt_descr (opt);
                                if (!n [0])
                                        n = "none";
                                fprintf (mini_stats_fd, "\"%s\",", n);
@@ -2101,7 +2184,7 @@ mono_main (int argc, char* argv[])
                                opt = opt_sets [i];
                                g_timer_start (timer);
                                for (j = 0; j < count; ++j) {
-                                       cfg = mini_method_compile (method, opt, mono_get_root_domain (), 0, 0, -1);
+                                       cfg = mini_method_compile (method, opt, mono_get_root_domain (), (JitFlags)0, 0, -1);
                                        mono_destroy_compile (cfg);
                                }
                                g_timer_stop (timer);
@@ -2124,12 +2207,12 @@ mono_main (int argc, char* argv[])
                                        (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
                                        method = mono_marshal_get_native_wrapper (method, TRUE, FALSE);
 
-                               cfg = mini_method_compile (method, opt, mono_get_root_domain (), 0, 0, -1);
+                               cfg = mini_method_compile (method, opt, mono_get_root_domain (), (JitFlags)0, 0, -1);
                                mono_destroy_compile (cfg);
                        }
                }
        } else {
-               cfg = mini_method_compile (method, opt, mono_get_root_domain (), 0, 0, -1);
+               cfg = mini_method_compile (method, opt, mono_get_root_domain (), (JitFlags)0, 0, -1);
                mono_destroy_compile (cfg);
        }
 #endif
@@ -2187,6 +2270,10 @@ void
 mono_jit_set_aot_mode (MonoAotMode mode)
 {
        mono_aot_mode = mode;
+       if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY) {
+               mono_aot_only = TRUE;
+               mono_llvm_only = TRUE;
+       }
 }
 
 /**
@@ -2239,3 +2326,84 @@ mono_set_crash_chaining (gboolean chain_crashes)
 {
        mono_do_crash_chaining = chain_crashes;
 }
+
+void
+mono_parse_env_options (int *ref_argc, char **ref_argv [])
+{
+       int argc = *ref_argc;
+       char **argv = *ref_argv;
+
+       const char *env_options = g_getenv ("MONO_ENV_OPTIONS");
+       if (env_options != NULL){
+               GPtrArray *array = g_ptr_array_new ();
+               GString *buffer = g_string_new ("");
+               const char *p;
+               unsigned i;
+               gboolean in_quotes = FALSE;
+               char quote_char = '\0';
+
+               for (p = env_options; *p; p++){
+                       switch (*p){
+                       case ' ': case '\t':
+                               if (!in_quotes) {
+                                       if (buffer->len != 0){
+                                               g_ptr_array_add (array, g_strdup (buffer->str));
+                                               g_string_truncate (buffer, 0);
+                                       }
+                               } else {
+                                       g_string_append_c (buffer, *p);
+                               }
+                               break;
+                       case '\\':
+                               if (p [1]){
+                                       g_string_append_c (buffer, p [1]);
+                                       p++;
+                               }
+                               break;
+                       case '\'':
+                       case '"':
+                               if (in_quotes) {
+                                       if (quote_char == *p)
+                                               in_quotes = FALSE;
+                                       else
+                                               g_string_append_c (buffer, *p);
+                               } else {
+                                       in_quotes = TRUE;
+                                       quote_char = *p;
+                               }
+                               break;
+                       default:
+                               g_string_append_c (buffer, *p);
+                               break;
+                       }
+               }
+               if (in_quotes) {
+                       fprintf (stderr, "Unmatched quotes in value of MONO_ENV_OPTIONS: [%s]\n", env_options);
+                       exit (1);
+               }
+                       
+               if (buffer->len != 0)
+                       g_ptr_array_add (array, g_strdup (buffer->str));
+               g_string_free (buffer, TRUE);
+
+               if (array->len > 0){
+                       int new_argc = array->len + argc;
+                       char **new_argv = g_new (char *, new_argc + 1);
+                       int j;
+
+                       new_argv [0] = argv [0];
+                       
+                       /* First the environment variable settings, to allow the command line options to override */
+                       for (i = 0; i < array->len; i++)
+                               new_argv [i+1] = (char *)g_ptr_array_index (array, i);
+                       i++;
+                       for (j = 1; j < argc; j++)
+                               new_argv [i++] = argv [j];
+                       new_argv [i] = NULL;
+
+                       *ref_argc = new_argc;
+                       *ref_argv = new_argv;
+               }
+               g_ptr_array_free (array, TRUE);
+       }
+}