2009-07-01 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / driver.c
index 2232e06b9e427d0c24da12a967395543934b8bfe..7f2a70415d90235ad481ad21ba4fd28d97af1c29 100644 (file)
 #include <mono/metadata/mono-config.h>
 #include <mono/metadata/environment.h>
 #include <mono/metadata/verify.h>
+#include <mono/metadata/verify-internals.h>
 #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/coree.h>
+#include <mono/metadata/attach.h>
 #include "mono/utils/mono-counters.h"
+#include <mono/utils/gc_wrapper.h>
 
 #include "mini.h"
 #include "jit.h"
 #include <string.h>
 #include <ctype.h>
-#include "inssel.h"
 #include <locale.h>
 #include "version.h"
+#include "debugger-agent.h"
 
 static FILE *mini_stats_fd = NULL;
 
@@ -111,19 +115,22 @@ opt_funcs [sizeof (int) * 8] = {
        NULL
 };
 
+
 #define DEFAULT_OPTIMIZATIONS (        \
        MONO_OPT_PEEPHOLE |     \
        MONO_OPT_CFOLD |        \
        MONO_OPT_INLINE |       \
        MONO_OPT_CONSPROP |     \
        MONO_OPT_COPYPROP |     \
-       MONO_OPT_TREEPROP |     \
        MONO_OPT_DEADCE |       \
        MONO_OPT_BRANCH |       \
        MONO_OPT_LINEARS |      \
        MONO_OPT_INTRINS |  \
        MONO_OPT_LOOP |  \
        MONO_OPT_EXCEPTION |  \
+    MONO_OPT_CMOV |  \
+       MONO_OPT_GSHARED |      \
+       MONO_OPT_SIMD | \
        MONO_OPT_AOT)
 
 #define EXCLUDED_FROM_ALL (MONO_OPT_SHARED | MONO_OPT_PRECOMP)
@@ -191,6 +198,43 @@ parse_optimizations (const char* p)
        return opt;
 }
 
+static gboolean
+parse_debug_options (const char* p)
+{
+       MonoDebugOptions *opt = mini_get_debug_options ();
+
+       do {
+               if (!*p) {
+                       fprintf (stderr, "Syntax error; expected debug option name\n");
+                       return FALSE;
+               }
+
+               if (!strncmp (p, "casts", 5)) {
+                       opt->better_cast_details = TRUE;
+                       p += 5;
+               } else if (!strncmp (p, "mdb-optimizations", 17)) {
+                       opt->mdb_optimizations = TRUE;
+                       p += 17;
+               } else if (!strncmp (p, "gdb", 3)) {
+                       opt->gdb = TRUE;
+                       p += 3;
+               } else {
+                       fprintf (stderr, "Invalid debug option `%s', use --help-debug for details\n", p);
+                       return FALSE;
+               }
+
+               if (*p == ',') {
+                       p++;
+                       if (!*p) {
+                               fprintf (stderr, "Syntax error; expected debug option name\n");
+                               return FALSE;
+                       }
+               }
+       } while (*p);
+
+       return TRUE;
+}
+
 typedef struct {
        const char name [6];
        const char desc [18];
@@ -256,6 +300,11 @@ opt_sets [] = {
        MONO_OPT_BRANCH,
        MONO_OPT_CFOLD,
        MONO_OPT_FCMOV,
+#ifdef MONO_ARCH_SIMD_INTRINSICS
+       MONO_OPT_SIMD,
+       MONO_OPT_SSE2,
+       MONO_OPT_SIMD | MONO_OPT_SSE2,
+#endif
        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,
@@ -264,12 +313,13 @@ opt_sets [] = {
        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_SSA,
        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_EXCEPTION,
+       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_EXCEPTION | MONO_OPT_CMOV,
        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_EXCEPTION | MONO_OPT_ABCREM,
        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_EXCEPTION | MONO_OPT_ABCREM | MONO_OPT_SSAPRE,
        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,
-       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_TREEPROP,
        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_SSAPRE,
-       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 | MONO_OPT_SHARED
+       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 | MONO_OPT_SHARED,
+       DEFAULT_OPTIMIZATIONS, 
 };
 
 typedef int (*TestMethod) (void);
@@ -283,7 +333,8 @@ domain_dump_native_code (MonoDomain *domain) {
 #endif
 
 static int
-mini_regression (MonoImage *image, int verbose, int *total_run) {
+mini_regression (MonoImage *image, int verbose, int *total_run)
+{
        guint32 i, opt, opt_flags;
        MonoMethod *method;
        MonoCompile *cfg;
@@ -291,6 +342,10 @@ mini_regression (MonoImage *image, int verbose, int *total_run) {
        int result, expected, failed, cfailed, run, code_size, total;
        TestMethod func;
        GTimer *timer = g_timer_new ();
+       MonoDomain *domain = mono_domain_get ();
+       guint32 exclude = 0;
+
+       mono_arch_cpu_optimizazions (&exclude);
 
        if (mini_stats_fd) {
                fprintf (mini_stats_fd, "$stattitle = \'Mono Benchmark Results (various optimizations)\';\n");
@@ -315,7 +370,9 @@ mini_regression (MonoImage *image, int verbose, int *total_run) {
 
        /* load the metadata */
        for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
-                       method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
+               method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
+               if (!method)
+                       continue;
                mono_class_init (method->klass);
 
                if (!strncmp (method->name, "test_", 5) && mini_stats_fd) {
@@ -331,7 +388,7 @@ mini_regression (MonoImage *image, int verbose, int *total_run) {
        for (opt = 0; opt < G_N_ELEMENTS (opt_sets); ++opt) {
                double elapsed, comp_time, start_time;
 
-               opt_flags = opt_sets [opt];
+               opt_flags = opt_sets [opt] & ~exclude;
                mono_set_defaults (verbose, opt_flags);
                n = opt_descr (opt_flags);
                g_print ("Test run: image=%s, opts=%s\n", mono_image_get_filename (image), n);
@@ -340,16 +397,18 @@ mini_regression (MonoImage *image, int verbose, int *total_run) {
                comp_time = elapsed = 0.0;
 
                /* fixme: ugly hack - delete all previously compiled methods */
-               g_hash_table_destroy (mono_domain_get ()->jit_trampoline_hash);
-               mono_domain_get ()->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
-               mono_internal_hash_table_destroy (&(mono_domain_get ()->jit_code_hash));
-               mono_jit_code_hash_init (&(mono_domain_get ()->jit_code_hash));
+               g_hash_table_destroy (domain_jit_info (domain)->jit_trampoline_hash);
+               domain_jit_info (domain)->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
+               mono_internal_hash_table_destroy (&(domain->jit_code_hash));
+               mono_jit_code_hash_init (&(domain->jit_code_hash));
 
                g_timer_start (timer);
                if (mini_stats_fd)
                        fprintf (mini_stats_fd, "[");
                for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
-                       method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
+                       method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
+                       if (!method)
+                               continue;
                        if (strncmp (method->name, "test_", 5) == 0) {
                                expected = atoi (method->name + 5);
                                run++;
@@ -584,7 +643,7 @@ free_jit_info_data (ThreadData *td, JitInfoData *free)
                while (free->next != NULL) {
                        JitInfoData *next = free->next->next;
 
-                       g_free (free->next->ji);
+                       //g_free (free->next->ji);
                        g_free (free->next);
                        free->next = next;
 
@@ -635,16 +694,26 @@ test_thread_func (ThreadData *td)
                                if (region->num_datas > 0) {
                                        JitInfoData **data = choose_random_data (region);
                                        guint pos = (*data)->start + random () % (*data)->length;
-                                       MonoJitInfo *ji = mono_jit_info_table_find (domain, (char*)(gulong) pos);
+                                       MonoJitInfo *ji;
+
+                                       ji = mono_jit_info_table_find (domain, (char*)(gulong) pos);
 
-                                       g_assert ((*data)->ji == ji);
                                        g_assert (ji->cas_inited);
+                                       g_assert ((*data)->ji == ji);
                                }
                        } else {
                                int pos = random () % MAX_ADDR;
                                char *addr = (char*)(gulong) pos;
-                               MonoJitInfo *ji = mono_jit_info_table_find (domain, addr);
+                               MonoJitInfo *ji;
+
+                               ji = mono_jit_info_table_find (domain, addr);
 
+                               /*
+                                * FIXME: We are actually not allowed
+                                * to do this.  By the time we examine
+                                * the ji another thread might already
+                                * have removed it.
+                                */
                                if (ji != NULL) {
                                        g_assert (addr >= (char*)ji->code_start && addr < (char*)ji->code_start + ji->code_size);
                                        ++lookup_successes;
@@ -668,7 +737,7 @@ test_thread_func (ThreadData *td)
 
                                mono_jit_info_table_remove (domain, (*data)->ji);
 
-                               (*data)->ji->cas_inited = 0; /* marks a free jit info */
+                               //(*data)->ji->cas_inited = 0; /* marks a free jit info */
 
                                free = *data;
                                *data = (*data)->next;
@@ -769,7 +838,7 @@ compile_all_methods_thread_main (CompileAllThreadArgs *args)
        MonoImage *image = mono_assembly_get_image (ass);
        MonoMethod *method;
        MonoCompile *cfg;
-       int i, count = 0;
+       int i, count = 0, fail_count = 0;
 
        for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
                guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
@@ -779,6 +848,8 @@ compile_all_methods_thread_main (CompileAllThreadArgs *args)
                        continue;
 
                method = mono_get_method (image, token, NULL);
+               if (!method)
+                       continue;
                if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
                    (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
                    (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
@@ -798,9 +869,15 @@ compile_all_methods_thread_main (CompileAllThreadArgs *args)
                        g_free (desc);
                }
                cfg = mini_method_compile (method, args->opts, mono_get_root_domain (), FALSE, FALSE, 0);
+               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 ++;
+               }
                mono_destroy_compile (cfg);
        }
 
+       if (fail_count)
+               exit (1);
 }
 
 static void
@@ -868,16 +945,40 @@ 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);
-               exit (1);
-       }
-
        if (mono_compile_aot) {
-               int res = mono_compile_assembly (assembly, main_args->opts, main_args->aot_options);
-               printf ("AOT RESULT %d\n", res);
+               int i, res;
+
+               /* Treat the other arguments as assemblies to compile too */
+               for (i = 0; i < main_args->argc; ++i) {
+                       assembly = mono_domain_assembly_open (main_args->domain, main_args->argv [i]);
+                       if (!assembly) {
+                               fprintf (stderr, "Can not open image %s\n", main_args->argv [i]);
+                               exit (1);
+                       }
+                       /* Check that the assembly loaded matches the filename */
+                       {
+                               MonoImageOpenStatus status;
+                               MonoImage *img;
+
+                               img = mono_image_open (main_args->argv [i], &status);
+                               if (img && strcmp (img->name, assembly->image->name)) {
+                                       fprintf (stderr, "Error: Loaded assembly '%s' doesn't match original file name '%s'. Set MONO_PATH to the assembly's location.\n", assembly->image->name, img->name);
+                                       exit (1);
+                               }
+                       }
+                       res = mono_compile_assembly (assembly, main_args->opts, main_args->aot_options);
+                       if (res != 0) {
+                               fprintf (stderr, "AOT of image %s failed.\n", main_args->argv [i]);
+                               exit (1);
+                       }
+               }
        } else {
+               assembly = mono_domain_assembly_open (main_args->domain, main_args->file);
+               if (!assembly){
+                       fprintf (stderr, "Can not open image %s\n", main_args->file);
+                       exit (1);
+               }
+
                /* 
                 * This must be done in a thread managed by mono since it can invoke
                 * managed code.
@@ -889,6 +990,72 @@ static void main_thread_handler (gpointer user_data)
        }
 }
 
+static int
+load_agent (MonoDomain *domain, char *desc)
+{
+       char* col = strchr (desc, ':'); 
+       char *agent, *args;
+       MonoAssembly *agent_assembly;
+       MonoImage *image;
+       MonoMethod *method;
+       guint32 entry;
+       MonoArray *main_args;
+       gpointer pa [1];
+       MonoImageOpenStatus open_status;
+
+       if (col) {
+               agent = g_memdup (desc, col - desc + 1);
+               agent [col - desc] = '\0';
+               args = col + 1;
+       } else {
+               agent = g_strdup (desc);
+               args = NULL;
+       }
+
+       agent_assembly = mono_assembly_open (agent, &open_status);
+       if (!agent_assembly) {
+               fprintf (stderr, "Cannot open agent assembly '%s': %s.\n", agent, mono_image_strerror (open_status));
+               g_free (agent);
+               return 2;
+       }
+
+       /* 
+        * Can't use mono_jit_exec (), as it sets things which might confuse the
+        * real Main method.
+        */
+       image = mono_assembly_get_image (agent_assembly);
+       entry = mono_image_get_entry_point (image);
+       if (!entry) {
+               g_print ("Assembly '%s' doesn't have an entry point.\n", mono_image_get_filename (image));
+               g_free (agent);
+               return 1;
+       }
+
+       method = mono_get_method (image, entry, NULL);
+       if (method == NULL){
+               g_print ("The entry point method of assembly '%s' could not be loaded\n", agent);
+               g_free (agent);
+               return 1;
+       }
+       
+       mono_thread_set_main (mono_thread_current ());
+
+       if (args) {
+               main_args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 1);
+               mono_array_set (main_args, MonoString*, 0, mono_string_new (domain, args));
+       } else {
+               main_args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
+       }
+
+       g_free (agent);
+
+       pa [0] = main_args;
+       /* Pass NULL as 'exc' so unhandled exceptions abort the runtime */
+       mono_runtime_invoke (method, NULL, pa, NULL);
+
+       return 0;
+}
+
 static void
 mini_usage_jitdeveloper (void)
 {
@@ -898,6 +1065,7 @@ mini_usage_jitdeveloper (void)
                 "Runtime and JIT debugging options:\n"
                 "    --breakonex            Inserts a breakpoint on exceptions\n"
                 "    --break METHOD         Inserts a breakpoint at METHOD entry\n"
+                "    --break-at-bb METHOD N Inserts a breakpoint in METHOD at BB N\n"
                 "    --compile METHOD       Just compile METHOD in assembly\n"
                 "    --compile-all          Compiles all the methods in the assembly\n"
                 "    --ncompile N           Number of times to compile METHOD (default: 1)\n"
@@ -905,8 +1073,12 @@ mini_usage_jitdeveloper (void)
                 "    --regression           Runs the regression test contained in the assembly\n"
                 "    --statfile FILE        Sets the stat file to FILE\n"
                 "    --stats                Print statistics about the JIT operations\n"
-                "    --wapi=hps|semdel      IO-layer maintenance\n"
+                "    --wapi=hps|semdel|seminfo IO-layer maintenance\n"
                 "    --inject-async-exc METHOD OFFSET Inject an asynchronous exception at METHOD\n"
+                "    --verify-all           Run the verifier on all methods\n"
+                "    --full-aot             Avoid JITting any code\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"
                 "Other options:\n" 
                 "    --graph[=TYPE] METHOD  Draws a graph of the specified method:\n");
@@ -933,7 +1105,8 @@ mini_usage (void)
                "\n"
                "Development:\n"
                "    --aot                  Compiles the assembly to native code\n"
-               "    --debug                Enable debugging support\n"
+               "    --debug[=<options>]    Enable debugging support, use --help-debug for details\n"
+               "    --debugger-agent=options Enable the debugger agent\n"
                "    --profile[=profiler]   Runs in profiling mode with the specified profiler module\n"
                "    --trace[=EXPR]         Enable tracing, use --help-trace for details\n"
                "    --help-devel           Shows more options available to developers\n"
@@ -947,7 +1120,10 @@ mini_usage (void)
                "    --optimize=OPT         Turns on or off a specific optimization\n"
                "                           Use --list-opt to get a list of optimizations\n"
                "    --security[=mode]      Turns on the unsupported security manager (off by default)\n"
-               "                           mode is one of cas or core-clr\n");
+               "                           mode is one of cas, core-clr, verifiable or validil\n"
+               "    --attach=OPTIONS       Pass OPTIONS to the attach agent in the runtime.\n"
+               "                           Currently the only supported option is 'disable'.\n"
+         );
 }
 
 static void
@@ -965,11 +1141,34 @@ mini_trace_usage (void)
                 "    M:Type:Method        Specifies a method\n"
                 "    N:Namespace          Specifies a namespace\n"
                 "    T:Type               Specifies a type\n"
-                "    +EXPR                Includes expression\n"
+                "    EXPR                 Includes expression\n"
                 "    -EXPR                Excludes expression\n"
+                "    EXPR,EXPR            Multiple expressions\n"
                 "    disabled             Don't print any output until toggled via SIGUSR2\n");
 }
 
+static void
+mini_debug_usage (void)
+{
+       fprintf (stdout,
+                "Debugging options:\n"
+                "   --debug[=OPTIONS]     Enable debugging support, optional OPTIONS is a comma\n"
+                "                         separated list of options\n"
+                "\n"
+                "OPTIONS is composed of:\n"
+                "    casts                Enable more detailed InvalidCastException messages.\n"
+                "    mdb-optimizations    Disable some JIT optimizations which are normally\n"
+                "                         disabled when running inside the debugger.\n"
+                "                         This is useful if you plan to attach to the running\n"
+                "                         process with the debugger.\n");
+}
+
+#if defined(MONO_ARCH_ARCHITECTURE)
+/* Redefine ARCHITECTURE to include more information */
+#undef ARCHITECTURE
+#define ARCHITECTURE MONO_ARCH_ARCHITECTURE
+#endif
+
 static const char info[] =
 #ifdef HAVE_KW_THREAD
        "\tTLS:           __thread\n"
@@ -997,6 +1196,26 @@ static const char info[] =
 #define error_if_aot_unsupported()
 #endif
 
+#ifdef PLATFORM_WIN32
+BOOL APIENTRY DllMain (HMODULE module_handle, DWORD reason, LPVOID reserved)
+{
+       if (!GC_DllMain (module_handle, reason, reserved))
+               return FALSE;
+
+       switch (reason)
+       {
+       case DLL_PROCESS_ATTACH:
+               mono_install_runtime_load (mini_init);
+               break;
+       case DLL_PROCESS_DETACH:
+               if (coree_module_handle)
+                       FreeLibrary (coree_module_handle);
+               break;
+       }
+       return TRUE;
+}
+#endif
+
 int
 mono_main (int argc, char* argv[])
 {
@@ -1006,6 +1225,7 @@ mono_main (int argc, char* argv[])
        MonoMethod *method;
        MonoCompile *cfg;
        MonoDomain *domain;
+       MonoImageOpenStatus open_status;
        const char* aname, *mname = NULL;
        char *config_file = NULL;
        int i, count = 1;
@@ -1018,6 +1238,8 @@ mono_main (int argc, char* argv[])
        char *profile_options = NULL;
        char *aot_options = NULL;
        char *forced_version = NULL;
+       GPtrArray *agents = NULL;
+       char *attach_options = NULL;
 #ifdef MONO_JIT_INFO_TABLE_TEST
        int test_jit_info_table = FALSE;
 #endif
@@ -1062,7 +1284,9 @@ mono_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 (%s)\nCopyright (C) 2002-2007 Novell, Inc and Contributors. www.mono-project.com\n", VERSION, FULL_VERSION);
+                       char *build = mono_get_runtime_build_info ();
+                       g_print ("Mono JIT compiler version %s (%s)\nCopyright (C) 2002-2009 Novell, Inc and Contributors. www.mono-project.com\n", VERSION, build);
+                       g_free (build);
                        g_print (info);
                        if (mini_verbose) {
                                const char *cerror;
@@ -1087,6 +1311,9 @@ mono_main (int argc, char* argv[])
                } else if (strcmp (argv [i], "--help-devel") == 0){
                        mini_usage_jitdeveloper ();
                        return 0;
+               } else if (strcmp (argv [i], "--help-debug") == 0){
+                       mini_debug_usage ();
+                       return 0;
                } else if (strcmp (argv [i], "--list-opt") == 0){
                        mini_usage_list_opt ();
                        return 0;
@@ -1127,6 +1354,17 @@ mono_main (int argc, char* argv[])
                        
                        if (!mono_debugger_insert_breakpoint (argv [++i], FALSE))
                                fprintf (stderr, "Error: invalid method name '%s'\n", argv [i]);
+               } else if (strcmp (argv [i], "--break-at-bb") == 0) {
+                       if (i + 2 >= argc) {
+                               fprintf (stderr, "Missing method name or bb num in --break-at-bb command line option.");
+                               return 1;
+                       }
+                       mono_break_at_bb_method = mono_method_desc_new (argv [++i], TRUE);
+                       if (mono_break_at_bb_method == NULL) {
+                               fprintf (stderr, "Method name is in a bad format in --break-at-bb command line option.");
+                               return 1;
+                       }
+                       mono_break_at_bb_bb_num = atoi (argv [++i]);
                } else if (strcmp (argv [i], "--inject-async-exc") == 0) {
                        if (i + 2 >= argc) {
                                fprintf (stderr, "Missing method name or position in --inject-async-exc command line option\n");
@@ -1138,6 +1376,10 @@ mono_main (int argc, char* argv[])
                                return 1;
                        }
                        mono_inject_async_exc_pos = atoi (argv [++i]);
+               } else if (strcmp (argv [i], "--verify-all") == 0) {
+                       mono_verifier_enable_verify_all ();
+               } else if (strcmp (argv [i], "--full-aot") == 0) {
+                       mono_aot_only = TRUE;
                } else if (strcmp (argv [i], "--print-vtable") == 0) {
                        mono_print_vtable = TRUE;
                } else if (strcmp (argv [i], "--stats") == 0) {
@@ -1163,6 +1405,12 @@ mono_main (int argc, char* argv[])
                } else if (strncmp (argv [i], "--profile=", 10) == 0) {
                        enable_profile = TRUE;
                        profile_options = argv [i] + 10;
+               } else if (strncmp (argv [i], "--agent=", 8) == 0) {
+                       if (agents == NULL)
+                               agents = g_ptr_array_new ();
+                       g_ptr_array_add (agents, argv [i] + 8);
+               } else if (strncmp (argv [i], "--attach=", 9) == 0) {
+                       attach_options = argv [i] + 9;
                } else if (strcmp (argv [i], "--compile") == 0) {
                        if (i + 1 >= argc){
                                fprintf (stderr, "error: --compile option requires a method name argument\n");
@@ -1191,22 +1439,40 @@ mono_main (int argc, char* argv[])
                        action = DO_DRAW;
                } else if (strcmp (argv [i], "--debug") == 0) {
                        enable_debugging = TRUE;
+               } else if (strncmp (argv [i], "--debug=", 8) == 0) {
+                       enable_debugging = TRUE;
+                       if (!parse_debug_options (argv [i] + 8))
+                               return 1;
+               } else if (strncmp (argv [i], "--debugger-agent=", 17) == 0) {
+                       MonoDebugOptions *opt = mini_get_debug_options ();
+
+                       mono_debugger_agent_parse_options (argv [i] + 17);
+                       opt->mdb_optimizations = TRUE;
+                       enable_debugging = TRUE;
                } else if (strcmp (argv [i], "--security") == 0) {
+                       mono_verifier_set_mode (MONO_VERIFIER_MODE_VERIFIABLE);
                        mono_security_set_mode (MONO_SECURITY_MODE_CAS);
                        mono_activate_security_manager ();
                } else if (strncmp (argv [i], "--security=", 11) == 0) {
                        if (strcmp (argv [i] + 11, "temporary-smcs-hack") == 0) {
                                mono_security_set_mode (MONO_SECURITY_MODE_SMCS_HACK);
                        } else if (strcmp (argv [i] + 11, "core-clr") == 0) {
+                               mono_verifier_set_mode (MONO_VERIFIER_MODE_VERIFIABLE);
                                mono_security_set_mode (MONO_SECURITY_MODE_CORE_CLR);
                        } else if (strcmp (argv [i] + 11, "core-clr-test") == 0) {
+                               /* fixme should we enable verifiable code here?*/
                                mono_security_set_mode (MONO_SECURITY_MODE_CORE_CLR);
                                mono_security_core_clr_test = TRUE;
                        } else if (strcmp (argv [i] + 11, "cas") == 0){
+                               mono_verifier_set_mode (MONO_VERIFIER_MODE_VERIFIABLE);
                                mono_security_set_mode (MONO_SECURITY_MODE_CAS);
                                mono_activate_security_manager ();
-                       } else {
-                               fprintf (stderr, "error: --security= option has invalid argument (cas or core-clr)\n");
+                       } else  if (strcmp (argv [i] + 11, "validil") == 0) {
+                               mono_verifier_set_mode (MONO_VERIFIER_MODE_VALID);
+                       } else  if (strcmp (argv [i] + 11, "verifiable") == 0) {
+                               mono_verifier_set_mode (MONO_VERIFIER_MODE_VERIFIABLE);
+                       } else  {
+                               fprintf (stderr, "error: --security= option has invalid argument (cas, core-clr, verifiable or validil)\n");
                                return 1;
                        }
                } else if (strcmp (argv [i], "--desktop") == 0) {
@@ -1229,6 +1495,8 @@ mono_main (int argc, char* argv[])
                                fprintf (stderr, "Invalid --wapi suboption: '%s'\n", argv [i]);
                                return 1;
                        }
+               } else if (strcmp (argv [i], "--no-x86-stack-align") == 0) {
+                       mono_do_x86_stack_align = FALSE;
 #ifdef MONO_JIT_INFO_TABLE_TEST
                } else if (strcmp (argv [i], "--test-jit-info-table") == 0) {
                        test_jit_info_table = TRUE;
@@ -1244,18 +1512,31 @@ mono_main (int argc, char* argv[])
                return 1;
        }
 
-       if ((action == DO_EXEC) && g_getenv ("MONO_INSIDE_MDB"))
+       if (getenv ("MONO_XDEBUG"))
+               enable_debugging = TRUE;
+
+#ifdef MONO_CROSS_COMPILE
+       if (!mono_compile_aot) {
+                  fprintf (stderr, "This mono runtime is compiled for cross-compiling. Only the --aot option is supported.");
+                  exit (1);
+       }
+#if SIZEOF_VOID_P == 8 && defined(TARGET_ARM)
+       fprintf (stderr, "Can't cross-compile on 64 bit platforms to arm.\n");
+       exit (1);
+#endif
+#endif
+
+       if ((action == DO_EXEC) && mono_debug_using_mono_debugger ())
                action = DO_DEBUGGER;
 
        if (mono_compile_aot || action == DO_EXEC || action == DO_DEBUGGER) {
                g_set_prgname (argv[i]);
        }
 
-       if (enable_profile) {
-               /* Needed because of TLS accesses in mono_profiler_load () */
-               mono_gc_base_init ();
+       if (enable_profile)
                mono_profiler_load (profile_options);
-       }
+
+       mono_attach_parse_options (attach_options);
 
        if (trace_options != NULL){
                /* 
@@ -1267,16 +1548,18 @@ mono_main (int argc, char* argv[])
                        exit (1);
        }
 
+#ifdef DISABLE_JIT
+       if (!mono_aot_only) {
+               fprintf (stderr, "This runtime has been configured with --enable-minimal=jit, so the --full-aot command line option is required.\n");
+               exit (1);
+       }
+#endif
+
        if (action == DO_DEBUGGER) {
-               // opt |= MONO_OPT_SHARED;
-               opt &= ~MONO_OPT_INLINE;
-               opt &= ~MONO_OPT_COPYPROP;
-               opt &= ~MONO_OPT_CONSPROP;
                enable_debugging = TRUE;
 
 #ifdef MONO_DEBUGGER_SUPPORTED
                mono_debug_init (MONO_DEBUG_FORMAT_DEBUGGER);
-               mono_debugger_init ();
 #else
                g_print ("The Mono Debugger is not supported on this platform.\n");
                return 1;
@@ -1284,8 +1567,31 @@ mono_main (int argc, char* argv[])
        } else if (enable_debugging)
                mono_debug_init (MONO_DEBUG_FORMAT_MONO);
 
+#ifdef MONO_DEBUGGER_SUPPORTED
+       if (enable_debugging) {
+               if ((opt & MONO_OPT_GSHARED) == 0)
+                       mini_debugger_set_attach_ok ();
+       }
+#endif
+
        mono_set_defaults (mini_verbose, opt);
+       mono_setup_vtable_in_class_init = FALSE;
        domain = mini_init (argv [i], forced_version);
+
+       if (agents) {
+               int i;
+
+               for (i = 0; i < agents->len; ++i) {
+                       int res = load_agent (domain, (char*)g_ptr_array_index (agents, i));
+                       if (res) {
+                               g_ptr_array_free (agents, TRUE);
+                               mini_cleanup (domain);
+                               return 1;
+                       }
+               }
+
+               g_ptr_array_free (agents, TRUE);
+       }
        
        switch (action) {
        case DO_REGRESSION:
@@ -1340,9 +1646,9 @@ mono_main (int argc, char* argv[])
                jit_info_table_test (domain);
 #endif
 
-       assembly = mono_assembly_open (aname, NULL);
+       assembly = mono_assembly_open (aname, &open_status);
        if (!assembly) {
-               fprintf (stderr, "Cannot open assembly %s.\n", aname);
+               fprintf (stderr, "Cannot open assembly '%s': %s.\n", aname, mono_image_strerror (open_status));
                mini_cleanup (domain);
                return 2;
        }
@@ -1382,6 +1688,28 @@ mono_main (int argc, char* argv[])
                main_thread_handler (&main_args);
                mono_thread_manage ();
 #endif
+
+       /* 
+        * On unix, WaitForMultipleObjects for threads is implemented by waiting on
+        * a cond variable, which is set by the thread when it exits _mono code_, 
+        * but it could still be running libc code. On amd64, the libc thread exit 
+        * code does a stack unwind, and if it encounters a frame pointing to native
+        * code which is in memory which is no longer mapped (because the runtime has
+        * shut down), it will crash:
+        * http://mail-archives.apache.org/mod_mbox/harmony-dev/200801.mbox/%3C200801130327.41572.gshimansky@apache.org%3E
+        * Testcase: tests/main-exit-background-change.exe.
+        * To make this race less frequent, we avoid freeing the global code manager.
+        * Since mono_main () is hopefully only used by the runtime executable, this 
+        * will only cause a shutdown leak. This workaround also has the advantage
+        * that it can be back-ported to 2.0 safely.
+        * FIXME: Fix this properly by waiting for threads to really exit using 
+        * pthread_join (). This cannot be done currently as the io-layer calls
+        * pthread_detach ().
+        */
+#ifdef __x86_64__
+               mono_dont_free_global_codeman = TRUE;
+#endif
+
                mini_cleanup (domain);
 
                /* Look up return value from System.Environment.ExitCode */
@@ -1402,7 +1730,7 @@ mono_main (int argc, char* argv[])
                        exit (1);
                }
 
-               mono_debugger_main (domain, assembly, argc - i, argv + i);
+               mini_debugger_main (domain, assembly, argc - i, argv + i);
                mini_cleanup (domain);
                return 0;
 #else
@@ -1446,7 +1774,7 @@ mono_main (int argc, char* argv[])
                if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
                        (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
                        MonoMethod *nm;
-                       nm = mono_marshal_get_native_wrapper (method);
+                       nm = mono_marshal_get_native_wrapper (method, TRUE, FALSE);
                        cfg = mini_method_compile (nm, opt, mono_get_root_domain (), FALSE, FALSE, part);
                }
                else
@@ -1503,7 +1831,7 @@ mono_main (int argc, char* argv[])
                        for (i = 0; i < count; ++i) {
                                if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
                                        (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
-                                       method = mono_marshal_get_native_wrapper (method);
+                                       method = mono_marshal_get_native_wrapper (method, TRUE, FALSE);
 
                                cfg = mini_method_compile (method, opt, mono_get_root_domain (), FALSE, FALSE, 0);
                                mono_destroy_compile (cfg);
@@ -1526,7 +1854,7 @@ mono_jit_init (const char *file)
 
 /**
  * mono_jit_init_version:
- * @file: the initial assembly to load
+ * @domain_name: the name of the root domain
  * @runtime_version: the version of the runtime to load
  *
  * Use this version when you want to force a particular runtime
@@ -1544,9 +1872,9 @@ mono_jit_init (const char *file)
  * was loaded.
  */
 MonoDomain * 
-mono_jit_init_version (const char *file, const char *runtime_version)
+mono_jit_init_version (const char *domain_name, const char *runtime_version)
 {
-       return mini_init (file, runtime_version);
+       return mini_init (domain_name, runtime_version);
 }
 
 void        
@@ -1554,3 +1882,47 @@ mono_jit_cleanup (MonoDomain *domain)
 {
        mini_cleanup (domain);
 }
+
+void
+mono_jit_set_aot_only (gboolean val)
+{
+       mono_aot_only = val;
+}
+
+/**
+ * mono_jit_set_trace_options:
+ * @options: string representing the trace options
+ *
+ * Set the options of the tracing engine. This function can be called before initializing
+ * the mono runtime. See the --trace mono(1) manpage for the options format.
+ *
+ * Returns: #TRUE if the options where parsed and set correctly, #FALSE otherwise.
+ */
+gboolean
+mono_jit_set_trace_options (const char* options)
+{
+       MonoTraceSpec *trace_opt = mono_trace_parse_options (options);
+       if (trace_opt == NULL)
+               return FALSE;
+       mono_jit_trace_calls = trace_opt;
+       return TRUE;
+}
+
+/**
+ * mono_set_signal_chaining:
+ *
+ *   Enable/disable signal chaining. This should be called before mono_jit_init ().
+ * If signal chaining is enabled, the runtime saves the original signal handlers before
+ * installing its own handlers, and calls the original ones in the following cases:
+ * - a SIGSEGV/SIGABRT signal received while executing native (i.e. not JITted) code.
+ * - SIGPROF
+ * - SIGFPE
+ * - SIGQUIT
+ * - SIGUSR2
+ * Signal chaining only works on POSIX platforms.
+ */
+void
+mono_set_signal_chaining (gboolean chain_signals)
+{
+       mono_do_signal_chaining = chain_signals;
+}