Added array bounds check (ABC) removal optimization.
[mono.git] / mono / mini / driver.c
index 16a06612d01e6c8372669e79cdfb5e6a2b15da80..bb159ba29c2853413bd80b57df970014379a8cc3 100644 (file)
@@ -5,7 +5,8 @@
  *   Paolo Molaro (lupus@ximian.com)
  *   Dietmar Maurer (dietmar@ximian.com)
  *
- * (C) 2002 Ximian, Inc.
+ * (C) 2002-2003 Ximian, Inc.
+ * (C) 2003-2004 Novell, Inc.
  */
 
 #include <config.h>
 #include <mono/metadata/profiler-private.h>
 #include <mono/metadata/mono-config.h>
 #include <mono/metadata/environment.h>
+#include <mono/metadata/verify.h>
 #include <mono/metadata/mono-debug.h>
 #include <mono/metadata/mono-debug-debugger.h>
 
 #include "mini.h"
+#include "jit.h"
 #include <string.h>
 #include <ctype.h>
 #include "inssel.h"
+#include <locale.h>
 
 static FILE *mini_stats_fd = NULL;
 
@@ -67,22 +71,37 @@ opt_names [] = {
        {"cmov",     "Conditional moves"},
        {"shared",   "Emit per-domain code"},
        {"sched",    "Instruction scheduling"},
-       {"instrins", "Intrinsic method implementations"},
+       {"intrins",  "Intrinsic method implementations"},
        {"tailc",    "Tail recursion and tail calls"},
        {"loop",     "Loop related optimizations"},
-       {"fcmov",    "Fast x86 FP compares"}
+       {"fcmov",    "Fast x86 FP compares"},
+       {"leaf",     "Leaf procedures optimizations"},
+       {"aot",      "Usage of Ahead Of Time compiled code"},
+       {"precomp",  "Precompile all methods before executing Main"},
+       {"abcrem",   "Array bound checks removal"}
 };
 
+#define DEFAULT_OPTIMIZATIONS (        \
+       MONO_OPT_PEEPHOLE |     \
+       MONO_OPT_CFOLD |        \
+       MONO_OPT_BRANCH |       \
+       MONO_OPT_LINEARS |      \
+       MONO_OPT_INTRINS |  \
+    MONO_OPT_AOT)
+
+
 static guint32
 parse_optimizations (const char* p)
 {
        /* the default value */
-       guint32 opt = MONO_OPT_PEEPHOLE | MONO_OPT_CFOLD /* | MONO_OPT_CONSPROP | MONO_OPT_INLINE*/ | MONO_OPT_BRANCH | /* | MONO_OPT_SAHRED |*/ MONO_OPT_LINEARS;
+       guint32 opt = DEFAULT_OPTIMIZATIONS;
+       guint32 exclude = 0;
        const char *n;
        int i, invert, len;
 
        /* call out to cpu detection code here that sets the defaults ... */
-       opt |= mono_arch_cpu_optimizazions ();
+       opt |= mono_arch_cpu_optimizazions (&exclude);
+       opt &= ~exclude;
        if (!p)
                return opt;
 
@@ -121,7 +140,7 @@ parse_optimizations (const char* p)
                                if (invert)
                                        opt = 0;
                                else
-                                       opt = ~(MONO_OPT_SAHRED);
+                                       opt = ~(MONO_OPT_SHARED | MONO_OPT_PRECOMP | exclude);
                                p += 3;
                                if (*p == ',')
                                        p++;
@@ -167,7 +186,7 @@ mono_parse_graph_options (const char* p)
 }
 
 int
-mini_parse_default_optimizations (const char* p)
+mono_parse_default_optimizations (const char* p)
 {
        guint32 opt;
 
@@ -199,12 +218,13 @@ opt_sets [] = {
        MONO_OPT_BRANCH,
        MONO_OPT_CFOLD,
        MONO_OPT_FCMOV,
-       MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE,
+       MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_INTRINS,
        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS,
        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP,
        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_CFOLD,
        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP | MONO_OPT_DEADCE,
-       MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP | MONO_OPT_DEADCE | MONO_OPT_LOOP | MONO_OPT_INLINE
+       MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP | MONO_OPT_DEADCE | MONO_OPT_LOOP | MONO_OPT_INLINE | MONO_OPT_INTRINS,
+       MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP | MONO_OPT_DEADCE | MONO_OPT_LOOP | MONO_OPT_INLINE | MONO_OPT_INTRINS | MONO_OPT_ABCREM
 };
 
 typedef int (*TestMethod) (void);
@@ -265,8 +285,10 @@ mini_regression (MonoImage *image, int verbose, int *total_run) {
        *total_run = 0;
        for (opt = 0; opt < G_N_ELEMENTS (opt_sets); ++opt) {
                double elapsed, comp_time, start_time;
+               MonoJitInfo *jinfo;
+
                opt_flags = opt_sets [opt];
-               mini_set_defaults (verbose, opt_flags);
+               mono_set_defaults (verbose, opt_flags);
                n = opt_descr (opt_flags);
                g_print ("Test run: image=%s, opts=%s\n", image->name, n);
                g_free (n);
@@ -289,13 +311,15 @@ mini_regression (MonoImage *image, int verbose, int *total_run) {
                                run++;
                                start_time = g_timer_elapsed (timer, NULL);
                                comp_time -= start_time; 
-                               cfg = mini_method_compile (method, opt_flags, mono_root_domain, 0);
+                               cfg = mini_method_compile (method, opt_flags, mono_root_domain, TRUE, 0);
                                comp_time += g_timer_elapsed (timer, NULL);
                                if (cfg) {
                                        if (verbose >= 2)
                                                g_print ("Running '%s' ...\n", method->name);
 #ifdef MONO_USE_AOT_COMPILER
-                                       if (!(func = mono_aot_get_method (method)))
+                                       if ((jinfo = mono_aot_get_method (mono_root_domain, method)))
+                                               func = jinfo->code_start;
+                                       else
 #endif
                                                func = (TestMethod)cfg->native_code;
                                        result = func ();
@@ -307,19 +331,6 @@ mini_regression (MonoImage *image, int verbose, int *total_run) {
                                        code_size += cfg->code_len;
                                        mono_destroy_compile (cfg);
 
-                                       if (mono_trace_coverage) {
-                                               MonoCoverageInfo *cov = mono_get_coverage_info (method);
-
-                                               if (cov) {
-                                                       int k;
-                                                       printf ("COVERAGE INFO %s\n", mono_method_full_name (method, TRUE));
-                                               
-                                                       for (k = 0; k < cov->entries; k++) {
-                                                               printf ("  BBLOCK %3d %d\n", cov->data [k].iloffset, cov->data [k].count);
-                                                       }
-                                               }
-                                       }
-
                                } else {
                                        cfailed++;
                                        if (verbose)
@@ -378,12 +389,19 @@ enum {
        DO_REGRESSION,
        DO_COMPILE,
        DO_EXEC,
-       DO_DRAW,
+       DO_DRAW
 };
 
+typedef struct CompileAllThreadArgs {
+       MonoAssembly *ass;
+       int verbose;
+} CompileAllThreadArgs;
+
 static void
-compile_all_methods (MonoAssembly *ass, int verbose)
+compile_all_methods_thread_main (CompileAllThreadArgs *args)
 {
+       MonoAssembly *ass = args->ass;
+       int verbose = args->verbose;
        MonoImage *image = ass->image;
        MonoMethod *method;
        int i, count = 0;
@@ -398,7 +416,7 @@ compile_all_methods (MonoAssembly *ass, int verbose)
                count++;
                if (verbose) {
                        char * desc = mono_method_full_name (method, TRUE);
-                       g_print ("Compiling %d %s\n", count, desc + 3);
+                       g_print ("Compiling %d %s\n", count, desc);
                        g_free (desc);
                }
                mono_compile_method (method);
@@ -406,6 +424,23 @@ compile_all_methods (MonoAssembly *ass, int verbose)
 
 }
 
+static void
+compile_all_methods (MonoAssembly *ass, int verbose)
+{
+       CompileAllThreadArgs args;
+
+       args.ass = ass;
+       args.verbose = verbose;
+
+       /* 
+        * Need to create a mono thread since compilation might trigger
+        * running of managed code.
+        */
+       mono_thread_create (mono_domain_get (), compile_all_methods_thread_main, &args);
+
+       mono_thread_manage ();
+}
+
 /**
  * mono_jit_exec:
  * @assembly: reference to an assembly
@@ -446,7 +481,7 @@ static void main_thread_handler (gpointer user_data)
 {
        MainThreadArgs *main_args = user_data;
        MonoAssembly *assembly;
-       
+
        assembly = mono_domain_assembly_open (main_args->domain, main_args->file);
        if (!assembly){
                fprintf (stderr, "Can not open image %s\n", main_args->file);
@@ -457,6 +492,13 @@ static void main_thread_handler (gpointer user_data)
                int res = mono_compile_assembly (assembly, main_args->opts);
                printf ("AOT RESULT %d\n", res);
        } else {
+               /* 
+                * This must be done in a thread managed by mono since it can invoke
+                * managed code.
+                */
+               if (main_args->opts & MONO_OPT_PRECOMP)
+                       mono_precompile_assemblies ();
+
                mono_jit_exec (main_args->domain, assembly, main_args->argc, main_args->argv);
        }
 }
@@ -466,31 +508,31 @@ mini_usage (void)
 {
        int i;
 
-       fprintf (stderr,
+       fprintf (stdout,
                "Usage is: mono [options] assembly\n\n"
                "Runtime and JIT debugging:\n"
                "    --compile METHOD       Just compile METHOD in assembly\n"
                "    --ncompile N           Number of times to compile METHOD (default: 1)\n"
                "    --regression           Runs the regression test contained in the assembly\n"
                "    --print-vtable         Print the vtable of all used classes\n"
-               "    --trace                Enable tracing\n"
+               "    --trace[=EXPR]         Enable tracing, use --help-trace for details\n"
                "    --compile-all          Compiles all the methods in the assembly\n"
                "    --breakonex            Inserts a breakpoint on exceptions\n"
                "    --break METHOD         Inserts a breakpoint at METHOD entry\n"
                "    --debug                Enable debugging support\n"
+               "    --stats                Print statistics about the JIT operations\n"
                "\n"
                "Development:\n"
                "    --statfile FILE        Sets the stat file to FILE\n"
                "    --aot                  Compiles the assembly to native code\n"
-               "    --coverage             Performs coverage analysis\n"
-               "    --profile              Runs in profiling mode\n"
+               "    --profile[=profiler]   Runs in profiling mode with the specified profiler module\n"
                "    --graph[=TYPE] METHOD  Draws a graph of the specified method:\n");
        
        for (i = 0; i < G_N_ELEMENTS (graph_names); ++i) {
-               fprintf (stderr, "                           %-10s %s\n", graph_names [i].name, graph_names [i].desc);
+               fprintf (stdout, "                           %-10s %s\n", graph_names [i].name, graph_names [i].desc);
        }
 
-       fprintf (stderr,
+       fprintf (stdout,
                "\n"
                "Runtime:\n"
                "    --config FILE          Loads FILE as the Mono config\n"
@@ -500,11 +542,62 @@ mini_usage (void)
                "    --optimize=OPT         Turns on a specific optimization:\n");
 
        for (i = 0; i < G_N_ELEMENTS (opt_names); ++i)
-               fprintf (stderr, "                           %-10s %s\n", opt_names [i].name, opt_names [i].desc);
+               fprintf (stdout, "                           %-10s %s\n", opt_names [i].name, opt_names [i].desc);
 }
 
+static void
+mini_trace_usage (void)
+{
+       fprintf (stdout,
+                "Tracing options:\n"
+                "   --trace[=EXPR]        Trace every call, optional EXPR controls the scope\n"
+                "\n"
+                "EXPR is composed of:\n"
+                "    all                  All assemblies\n"
+                "    none                 No assemblies\n"
+                "    program              Entry point assembly\n"
+                "    assembly             Specifies an assembly\n"
+                "    M:Type:Method        Specifies a method\n"
+                "    N:Namespace          Specifies a namespace\n"
+                "    T:Type               Specifies a type\n"
+                "    +EXPR                Includes expression\n"
+                "    -EXPR                Excludes expression\n");
+}
+
+static const char *info = ""
+#ifdef HAVE_KW_THREAD
+       "\tTLS:           NPTL\n"
+#else
+       "\tTLS:           normal\n"
+#endif /* HAVE_KW_THREAD */
+#ifdef HAVE_BOEHM_GC
+#ifdef USE_INCLUDED_LIBGC
+       "\tGC:            Included Boehm (with typed GC)\n"
+#else
+#if HAVE_GC_GCJ_MALLOC
+       "\tGC:            System Boehm (with typed GC)\n"
+#else
+       "\tGC:            System Boehm (no typed GC available)\n"
+#endif
+#endif
+#else
+       "\tGC:            none\n"
+#endif /* HAVE_BOEHM_GC */
+#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
+    "\tSIGSEGV      : altstack\n"
+#else
+    "\tSIGSEGV      : normal\n"
+#endif
+#ifdef HAVE_ICU
+       "\tGlobalization: ICU\n"
+#else
+       "\tGlobalization: none\n"
+#endif /* HAVE_ICU */
+       "";
+
 int
-mini_main (int argc, char* argv[]) {
+mono_main (int argc, char* argv[])
+{
        MainThreadArgs main_args;
        MonoAssembly *assembly;
        MonoMethodDesc *desc;
@@ -518,7 +611,12 @@ mini_main (int argc, char* argv[]) {
        guint32 opt, action = DO_EXEC;
        MonoGraphOptions mono_graph_options = 0;
        int mini_verbose = 0;
+       char *trace_options = NULL;
 
+       setlocale (LC_ALL, "");
+       g_log_set_always_fatal (G_LOG_LEVEL_ERROR);
+       g_log_set_fatal_mask (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR);
+       
        opt = parse_optimizations (NULL);
 
        for (i = 1; i < argc; ++i) {
@@ -529,11 +627,28 @@ mini_main (int argc, char* argv[]) {
                } else if (strcmp (argv [i], "--verbose") == 0 || strcmp (argv [i], "-v") == 0) {
                        mini_verbose++;
                } else if (strcmp (argv [i], "--version") == 0 || strcmp (argv [i], "-V") == 0) {
-                       g_print ("Mono JIT compiler version %s, (C) 2002, 2003 Ximian, Inc.\n", VERSION);
+                       g_print ("Mono JIT compiler version %s, (C) 2002-2004 Novell, Inc and Contributors. www.go-mono.com\n", VERSION);
+                       g_print (info);
+                       if (mini_verbose) {
+                               const guchar *cerror;
+                               const guchar *clibpath;
+                               mono_init ("mono");
+                               cerror = mono_check_corlib_version ();
+                               clibpath = mono_defaults.corlib? mono_defaults.corlib->name: "unknown";
+                               if (cerror) {
+                                       g_print ("The currently installed mscorlib doesn't match this runtime version.\n");
+                                       g_print ("The error is: %s\n", cerror);
+                                       g_print ("mscorlib.dll loaded at: %s\n", clibpath);
+                                       return 1;
+                               }
+                       }
                        return 0;
                } else if (strcmp (argv [i], "--help") == 0 || strcmp (argv [i], "-h") == 0) {
                        mini_usage ();
                        return 0;
+               } else if (strcmp (argv [i], "--help-trace") == 0){
+                       mini_trace_usage ();
+                       return 0;
                } else if (strncmp (argv [i], "--statfile", 10) == 0) {
                        mini_stats_fd = fopen (argv [++i], "w+");
                } else if (strncmp (argv [i], "--optimize=", 11) == 0) {
@@ -546,7 +661,9 @@ mini_main (int argc, char* argv[]) {
                        count = atoi (argv [++i]);
                        action = DO_BENCH;
                } else if (strcmp (argv [i], "--trace") == 0) {
-                       mono_jit_trace_calls = TRUE;
+                       trace_options = "";
+               } else if (strncmp (argv [i], "--trace=", 8) == 0) {
+                       trace_options = &argv [i][8];
                } else if (strcmp (argv [i], "--breakonex") == 0) {
                        mono_break_on_exc = TRUE;
                } else if (strcmp (argv [i], "--break") == 0) {
@@ -558,13 +675,12 @@ mini_main (int argc, char* argv[]) {
                        mono_jit_stats.enabled = TRUE;
                } else if (strcmp (argv [i], "--aot") == 0) {
                        mono_compile_aot = TRUE;
-               } else if (strcmp (argv [i], "--coverage") == 0) {
-                       mono_trace_coverage = TRUE;
                } else if (strcmp (argv [i], "--compile-all") == 0) {
                        action = DO_COMPILE;
                } else if (strcmp (argv [i], "--profile") == 0) {
-                       mono_jit_profile = TRUE;
-                       mono_profiler_install_simple ();
+                       mono_profiler_load (NULL);
+               } else if (strncmp (argv [i], "--profile=", 10) == 0) {
+                       mono_profiler_load (argv [i] + 10);
                } else if (strcmp (argv [i], "--compile") == 0) {
                        mname = argv [++i];
                        action = DO_BENCH;
@@ -579,14 +695,23 @@ mini_main (int argc, char* argv[]) {
                } else if (strcmp (argv [i], "--debug") == 0) {
                        enable_debugging = TRUE;
                } else {
-                       fprintf (stderr, "Unknown command line option: %s\n", argv [i]);
+                       fprintf (stderr, "Unknown command line option: '%s'\n", argv [i]);
                        return 1;
                }
        }
 
-       mini_set_defaults (mini_verbose, opt);
-       domain = mini_init (argv [i]);
+       if (!argv [i]) {
+               mini_usage ();
+               return 1;
+       }
+
+       if (mono_compile_aot || action == DO_EXEC) {
+               g_set_prgname (argv[i]);
+       }
 
+       mono_set_defaults (mini_verbose, opt);
+       domain = mini_init (argv [i]);
+       
        switch (action) {
        case DO_REGRESSION:
                if (mini_regression_list (mini_verbose, argc -i, argv + i)) {
@@ -631,7 +756,12 @@ mini_main (int argc, char* argv[]) {
        }
 
        if (enable_debugging)
-               mono_debug_init (MONO_DEBUG_FORMAT_MONO);
+               mono_debug_init (domain, MONO_DEBUG_FORMAT_MONO);
+
+       /* Parse gac loading options before loading assemblies. */
+       if (mono_compile_aot || action == DO_EXEC) {
+               mono_config_parse (config_file);
+       }
 
        assembly = mono_assembly_open (aname, NULL);
        if (!assembly) {
@@ -640,14 +770,27 @@ mini_main (int argc, char* argv[]) {
                return 2;
        }
 
+       if (trace_options != NULL){
+               mono_jit_trace_calls = mono_trace_parse_options (assembly, trace_options);
+               if (mono_jit_trace_calls == NULL)
+                       exit (1);
+       }
+
        if (enable_debugging)
                mono_debug_init_2 (assembly);
 
        if (mono_compile_aot || action == DO_EXEC) {
-               g_set_prgname (aname);
-               mono_config_parse (config_file);
+               const guchar *error;
+
                //mono_set_rootdir ();
 
+               error = mono_check_corlib_version ();
+               if (error) {
+                       fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
+                       fprintf (stderr, "Download a newer corlib or a newer runtime at http://www.go-mono.com/daily.\n");
+                       exit (1);
+               }
+
                main_args.domain = domain;
                main_args.file = aname;         
                main_args.argc = argc - i;
@@ -656,6 +799,7 @@ mini_main (int argc, char* argv[]) {
             
                mono_runtime_exec_managed_code (domain, main_thread_handler, &main_args);
                mini_cleanup (domain);
+
                /* Look up return value from System.Environment.ExitCode */
                i = mono_environment_exitcode_get ();
                return i;
@@ -698,7 +842,7 @@ mini_main (int argc, char* argv[]) {
                        break;
                }
 
-               cfg = mini_method_compile (method, opt, mono_root_domain, part);
+               cfg = mini_method_compile (method, opt, mono_root_domain, FALSE, part);
                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;
@@ -730,7 +874,7 @@ mini_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_root_domain, 0);
+                                       cfg = mini_method_compile (method, opt, mono_root_domain, FALSE, 0);
                                        mono_destroy_compile (cfg);
                                }
                                g_timer_stop (timer);
@@ -749,12 +893,16 @@ mini_main (int argc, char* argv[]) {
                        fprintf (mini_stats_fd, ");\n");
                } else {
                        for (i = 0; i < count; ++i) {
-                               cfg = mini_method_compile (method, opt, mono_root_domain, 0);
+                               if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
+                                       (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
+                                       method = mono_marshal_get_native_wrapper (method);
+
+                               cfg = mini_method_compile (method, opt, mono_root_domain, FALSE, 0);
                                mono_destroy_compile (cfg);
                        }
                }
        } else {
-               cfg = mini_method_compile (method, opt, mono_root_domain, 0);
+               cfg = mini_method_compile (method, opt, mono_root_domain, FALSE, 0);
                mono_destroy_compile (cfg);
        }