2008-08-22 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / driver.c
index e78cf22b267a51a864507647fd6d1327eef4dbc5..a3445c7f33a19e98b4f88a9b5933113c398aa6c5 100644 (file)
 
 #include <config.h>
 #include <signal.h>
+#if HAVE_SCHED_SETAFFINITY
+#include <sched.h>
+#endif
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
 
 #include <mono/metadata/assembly.h>
 #include <mono/metadata/loader.h>
-#include <mono/metadata/cil-coff.h>
 #include <mono/metadata/tabledefs.h>
 #include <mono/metadata/class.h>
 #include <mono/metadata/object.h>
 #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/os/gc_wrapper.h>
+#include <mono/metadata/security-core-clr.h>
+#include <mono/metadata/gc-internal.h>
+#include <mono/metadata/coree.h>
 #include "mono/utils/mono-counters.h"
+#include <mono/os/gc_wrapper.h>
 
 #include "mini.h"
 #include "jit.h"
 #include <ctype.h>
 #include "inssel.h"
 #include <locale.h>
+#include "version.h"
 
 static FILE *mini_stats_fd = NULL;
 
 static void mini_usage (void);
 
-extern int mini_wapi_hps (int argc, char **argv);
-extern int mini_wapi_semdel (int argc, char **argv);
-extern int mini_wapi_seminfo (int argc, char **argv);
-
-/* This turns off command line globbing under win32 */
 #ifdef PLATFORM_WIN32
+/* Need this to determine whether to detach console */
+#include <mono/metadata/cil-coff.h>
+/* This turns off command line globbing under win32 */
 int _CRT_glob = 0;
 #endif
 
@@ -120,6 +127,8 @@ opt_funcs [sizeof (int) * 8] = {
        MONO_OPT_INTRINS |  \
        MONO_OPT_LOOP |  \
        MONO_OPT_EXCEPTION |  \
+    MONO_OPT_CMOV |  \
+       MONO_OPT_GSHARED |      \
        MONO_OPT_AOT)
 
 #define EXCLUDED_FROM_ALL (MONO_OPT_SHARED | MONO_OPT_PRECOMP)
@@ -187,6 +196,40 @@ 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 {
+                       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];
@@ -260,6 +303,7 @@ 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,
@@ -338,8 +382,8 @@ mini_regression (MonoImage *image, int verbose, int *total_run) {
                /* 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);
-               g_hash_table_destroy (mono_domain_get ()->jit_code_hash);
-               mono_domain_get ()->jit_code_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_timer_start (timer);
                if (mini_stats_fd)
@@ -385,8 +429,13 @@ mini_regression (MonoImage *image, int verbose, int *total_run) {
                        fprintf (mini_stats_fd, "],\n");
                g_timer_stop (timer);
                elapsed = g_timer_elapsed (timer, NULL);
-               g_print ("Results: total tests: %d, failed: %d, cfailed: %d (pass: %.2f%%)\n", 
-                       run, failed, cfailed, 100.0*(run-failed-cfailed)/run);
+               if (failed > 0 || cfailed > 0){
+                       g_print ("Results: total tests: %d, failed: %d, cfailed: %d (pass: %.2f%%)\n", 
+                                run, failed, cfailed, 100.0*(run-failed-cfailed)/run);
+               } else {
+                       g_print ("Results: total tests: %d, all pass \n",  run);
+               }
+               
                g_print ("Elapsed time: %f secs (%f, %f), Code size: %d\n\n", elapsed, 
                         elapsed - comp_time, comp_time, code_size);
                total += failed + cfailed;
@@ -418,11 +467,335 @@ mini_regression_list (int verbose, int count, char *images [])
                total += mini_regression (mono_assembly_get_image (ass), verbose, &run);
                total_run += run;
        }
-       g_print ("Overall results: tests: %d, failed: %d, opt combinations: %d (pass: %.2f%%)\n", 
-               total_run, total, (int)G_N_ELEMENTS (opt_sets), 100.0*(total_run-total)/total_run);
+       if (total > 0){
+               g_print ("Overall results: tests: %d, failed: %d, opt combinations: %d (pass: %.2f%%)\n", 
+                        total_run, total, (int)G_N_ELEMENTS (opt_sets), 100.0*(total_run-total)/total_run);
+       } else {
+               g_print ("Overall results: tests: %d, 100%% pass, opt combinations: %d\n", 
+                        total_run, (int)G_N_ELEMENTS (opt_sets));
+       }
+       
        return total;
 }
 
+#ifdef MONO_JIT_INFO_TABLE_TEST
+typedef struct _JitInfoData
+{
+       guint start;
+       guint length;
+       MonoJitInfo *ji;
+       struct _JitInfoData *next;
+} JitInfoData;
+
+typedef struct
+{
+       guint start;
+       guint length;
+       int num_datas;
+       JitInfoData *data;
+} Region;
+
+typedef struct
+{
+       int num_datas;
+       int num_regions;
+       Region *regions;
+       int num_frees;
+       JitInfoData *frees;
+} ThreadData;
+
+static int num_threads;
+static ThreadData *thread_datas;
+static MonoDomain *test_domain;
+
+static JitInfoData*
+alloc_random_data (Region *region)
+{
+       JitInfoData **data;
+       JitInfoData *prev;
+       guint prev_end;
+       guint next_start;
+       guint max_len;
+       JitInfoData *d;
+       int num_retries = 0;
+       int pos, i;
+
+ restart:
+       prev = NULL;
+       data = &region->data;
+       pos = random () % (region->num_datas + 1);
+       i = 0;
+       while (*data != NULL) {
+               if (i++ == pos)
+                       break;
+               prev = *data;
+               data = &(*data)->next;
+       }
+
+       if (prev == NULL)
+               g_assert (*data == region->data);
+       else
+               g_assert (prev->next == *data);
+
+       if (prev == NULL)
+               prev_end = region->start;
+       else
+               prev_end = prev->start + prev->length;
+
+       if (*data == NULL)
+               next_start = region->start + region->length;
+       else
+               next_start = (*data)->start;
+
+       g_assert (prev_end <= next_start);
+
+       max_len = next_start - prev_end;
+       if (max_len < 128) {
+               if (++num_retries >= 10)
+                       return NULL;
+               goto restart;
+       }
+       if (max_len > 1024)
+               max_len = 1024;
+
+       d = g_new0 (JitInfoData, 1);
+       d->start = prev_end + random () % (max_len / 2);
+       d->length = random () % MIN (max_len, next_start - d->start) + 1;
+
+       g_assert (d->start >= prev_end && d->start + d->length <= next_start);
+
+       d->ji = g_new0 (MonoJitInfo, 1);
+       d->ji->method = (MonoMethod*) 0xABadBabe;
+       d->ji->code_start = (gpointer)(gulong) d->start;
+       d->ji->code_size = d->length;
+       d->ji->cas_inited = 1;  /* marks an allocated jit info */
+
+       d->next = *data;
+       *data = d;
+
+       ++region->num_datas;
+
+       return d;
+}
+
+static JitInfoData**
+choose_random_data (Region *region)
+{
+       int n;
+       int i;
+       JitInfoData **d;
+
+       g_assert (region->num_datas > 0);
+
+       n = random () % region->num_datas;
+
+       for (d = &region->data, i = 0;
+            i < n;
+            d = &(*d)->next, ++i)
+               ;
+
+       return d;
+}
+
+static Region*
+choose_random_region (ThreadData *td)
+{
+       return &td->regions [random () % td->num_regions];
+}
+
+static ThreadData*
+choose_random_thread (void)
+{
+       return &thread_datas [random () % num_threads];
+}
+
+static void
+free_jit_info_data (ThreadData *td, JitInfoData *free)
+{
+       free->next = td->frees;
+       td->frees = free;
+
+       if (++td->num_frees >= 1000) {
+               int i;
+
+               for (i = 0; i < 500; ++i)
+                       free = free->next;
+
+               while (free->next != NULL) {
+                       JitInfoData *next = free->next->next;
+
+                       //g_free (free->next->ji);
+                       g_free (free->next);
+                       free->next = next;
+
+                       --td->num_frees;
+               }
+       }
+}
+
+#define NUM_THREADS            8
+#define REGIONS_PER_THREAD     10
+#define REGION_SIZE            0x10000
+
+#define MAX_ADDR               (REGION_SIZE * REGIONS_PER_THREAD * NUM_THREADS)
+
+#define MODE_ALLOC     1
+#define MODE_FREE      2
+
+static void
+test_thread_func (ThreadData *td)
+{
+       int mode = MODE_ALLOC;
+       int i = 0;
+       gulong lookup_successes = 0, lookup_failures = 0;
+       MonoDomain *domain = test_domain;
+       int thread_num = (int)(td - thread_datas);
+       gboolean modify_thread = thread_num < NUM_THREADS / 2; /* only half of the threads modify the table */
+
+       for (;;) {
+               int alloc;
+               int lookup = 1;
+
+               if (td->num_datas == 0) {
+                       lookup = 0;
+                       alloc = 1;
+               } else if (modify_thread && random () % 1000 < 5) {
+                       lookup = 0;
+                       if (mode == MODE_ALLOC)
+                               alloc = (random () % 100) < 70;
+                       else if (mode == MODE_FREE)
+                               alloc = (random () % 100) < 30;
+               }
+
+               if (lookup) {
+                       /* modify threads sometimes look up their own jit infos */
+                       if (modify_thread && random () % 10 < 5) {
+                               Region *region = choose_random_region (td);
+
+                               if (region->num_datas > 0) {
+                                       JitInfoData **data = choose_random_data (region);
+                                       guint pos = (*data)->start + random () % (*data)->length;
+                                       MonoJitInfo *ji;
+
+                                       ji = mono_jit_info_table_find (domain, (char*)(gulong) pos);
+
+                                       g_assert (ji->cas_inited);
+                                       g_assert ((*data)->ji == ji);
+                               }
+                       } else {
+                               int pos = random () % MAX_ADDR;
+                               char *addr = (char*)(gulong) pos;
+                               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;
+                               } else
+                                       ++lookup_failures;
+                       }
+               } else if (alloc) {
+                       JitInfoData *data = alloc_random_data (choose_random_region (td));
+
+                       if (data != NULL) {
+                               mono_jit_info_table_add (domain, data->ji);
+
+                               ++td->num_datas;
+                       }
+               } else {
+                       Region *region = choose_random_region (td);
+
+                       if (region->num_datas > 0) {
+                               JitInfoData **data = choose_random_data (region);
+                               JitInfoData *free;
+
+                               mono_jit_info_table_remove (domain, (*data)->ji);
+
+                               //(*data)->ji->cas_inited = 0; /* marks a free jit info */
+
+                               free = *data;
+                               *data = (*data)->next;
+
+                               free_jit_info_data (td, free);
+
+                               --region->num_datas;
+                               --td->num_datas;
+                       }
+               }
+
+               if (++i % 100000 == 0) {
+                       int j;
+                       g_print ("num datas %d (%ld - %ld): %d", (int)(td - thread_datas),
+                                lookup_successes, lookup_failures, td->num_datas);
+                       for (j = 0; j < td->num_regions; ++j)
+                               g_print ("  %d", td->regions [j].num_datas);
+                       g_print ("\n");
+               }
+
+               if (td->num_datas < 100)
+                       mode = MODE_ALLOC;
+               else if (td->num_datas > 2000)
+                       mode = MODE_FREE;
+       }
+}
+
+/*
+static void
+small_id_thread_func (gpointer arg)
+{
+       MonoThread *thread = mono_thread_current ();
+       MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
+
+       g_print ("my small id is %d\n", (int)thread->small_id);
+       mono_hazard_pointer_clear (hp, 1);
+       sleep (3);
+       g_print ("done %d\n", (int)thread->small_id);
+}
+*/
+
+static void
+jit_info_table_test (MonoDomain *domain)
+{
+       int i;
+
+       g_print ("testing jit_info_table\n");
+
+       num_threads = NUM_THREADS;
+       thread_datas = g_new0 (ThreadData, num_threads);
+
+       for (i = 0; i < num_threads; ++i) {
+               int j;
+
+               thread_datas [i].num_regions = REGIONS_PER_THREAD;
+               thread_datas [i].regions = g_new0 (Region, REGIONS_PER_THREAD);
+
+               for (j = 0; j < REGIONS_PER_THREAD; ++j) {
+                       thread_datas [i].regions [j].start = (num_threads * j + i) * REGION_SIZE;
+                       thread_datas [i].regions [j].length = REGION_SIZE;
+               }
+       }
+
+       test_domain = domain;
+
+       /*
+       for (i = 0; i < 72; ++i)
+               mono_thread_create (domain, small_id_thread_func, NULL);
+
+       sleep (2);
+       */
+
+       for (i = 0; i < num_threads; ++i)
+               mono_thread_create (domain, test_thread_func, &thread_datas [i]);
+}
+#endif
+
 enum {
        DO_BENCH,
        DO_REGRESSION,
@@ -446,7 +819,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);
@@ -475,9 +848,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
@@ -545,16 +924,29 @@ 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);
+                       }
+                       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.
@@ -575,6 +967,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"
@@ -582,7 +975,10 @@ 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"
                 "\n"
                 "Other options:\n" 
                 "    --graph[=TYPE] METHOD  Draws a graph of the specified method:\n");
@@ -609,7 +1005,7 @@ 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"
                "    --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"
@@ -619,9 +1015,11 @@ mini_usage (void)
                "    --verbose, -v          Increases the verbosity level\n"
                "    --help, -h             Show usage information\n"
                "    --version, -V          Show version information\n"
+               "    --runtime=VERSION      Use the VERSION runtime, instead of autodetecting\n"
                "    --optimize=OPT         Turns on or off a specific optimization\n"
                "                           Use --list-opt to get a list of optimizations\n"
-               "    --security             Turns on the security manager (unsupported, default is off)\n");
+               "    --security[=mode]      Turns on the unsupported security manager (off by default)\n"
+               "                           mode is one of cas, core-clr, verifiable or validil\n");
 }
 
 static void
@@ -644,6 +1042,32 @@ mini_trace_usage (void)
                 "    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(__arm__) && defined(__ARM_EABI__)
+/* Redefine ARCHITECTURE to include more information */
+#undef ARCHITECTURE
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define ARCHITECTURE "armel"
+#else
+#define ARCHITECTURE "armeb"
+#endif
+#endif
+
 static const char info[] =
 #ifdef HAVE_KW_THREAD
        "\tTLS:           __thread\n"
@@ -656,9 +1080,41 @@ static const char info[] =
 #else
     "\tSIGSEGV:       normal\n"
 #endif
+#ifdef HAVE_EPOLL
+    "\tNotifications: epoll\n"
+#else
+    "\tNotification:  Thread + polling\n"
+#endif
+        "\tArchitecture:  " ARCHITECTURE "\n"
        "\tDisabled:      " DISABLED_FEATURES "\n"
        "";
 
+#ifndef MONO_ARCH_AOT_SUPPORTED
+#define error_if_aot_unsupported() do {fprintf (stderr, "AOT compilation is not supported on this platform.\n"); exit (1);} while (0)
+#else
+#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[])
 {
@@ -668,6 +1124,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;
@@ -679,9 +1136,22 @@ mono_main (int argc, char* argv[])
        char *trace_options = NULL;
        char *profile_options = NULL;
        char *aot_options = NULL;
+       char *forced_version = NULL;
+#ifdef MONO_JIT_INFO_TABLE_TEST
+       int test_jit_info_table = FALSE;
+#endif
 
        setlocale (LC_ALL, "");
 
+#if HAVE_SCHED_SETAFFINITY
+       if (getenv ("MONO_NO_SMP")) {
+               unsigned long proc_mask = 1;
+               sched_setaffinity (getpid(), sizeof (unsigned long), (gpointer)&proc_mask);
+       }
+#endif
+       if (!g_thread_supported ())
+               g_thread_init (NULL);
+
        if (mono_running_on_valgrind () && getenv ("MONO_VALGRIND_LEAK_CHECK")) {
                GMemVTable mem_vtable;
 
@@ -711,7 +1181,7 @@ 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, (C) 2002-2006 Novell, Inc and Contributors. www.mono-project.com\n", VERSION);
+                       g_print ("Mono JIT compiler version %s (%s)\nCopyright (C) 2002-2008 Novell, Inc and Contributors. www.mono-project.com\n", VERSION, FULL_VERSION);
                        g_print (info);
                        if (mini_verbose) {
                                const char *cerror;
@@ -736,6 +1206,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;
@@ -776,6 +1249,32 @@ 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");
+                               return 1;
+                       }
+                       mono_inject_async_exc_method = mono_method_desc_new (argv [++i], TRUE);
+                       if (mono_inject_async_exc_method == NULL) {
+                               fprintf (stderr, "Method name is in a bad format in --inject-async-exc command line option\n");
+                               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) {
@@ -784,13 +1283,17 @@ mono_main (int argc, char* argv[])
                        mono_jit_stats.enabled = TRUE;
 #ifndef DISABLE_AOT
                } else if (strcmp (argv [i], "--aot") == 0) {
+                       error_if_aot_unsupported ();
                        mono_compile_aot = TRUE;
                } else if (strncmp (argv [i], "--aot=", 6) == 0) {
+                       error_if_aot_unsupported ();
                        mono_compile_aot = TRUE;
                        aot_options = &argv [i][6];
 #endif
                } else if (strcmp (argv [i], "--compile-all") == 0) {
                        action = DO_COMPILE;
+               } else if (strncmp (argv [i], "--runtime=", 10) == 0) {
+                       forced_version = &argv [i][10];
                } else if (strcmp (argv [i], "--profile") == 0) {
                        enable_profile = TRUE;
                        profile_options = NULL;
@@ -825,9 +1328,42 @@ 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 (strcmp (argv [i], "--security") == 0) {
-                       mono_use_security_manager = TRUE;
+                       /* fixme enable verifiable code when the verifier works with 2.0
+                       * mini_verifier_set_mode (MINI_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) {
+                               /* fixme enable verifiable code when the verifier works with 2.0
+                                * mini_verifier_set_mode (MINI_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){
+                               /* fixme enable verifiable code when the verifier works with 2.0
+                                * mini_verifier_set_mode (MINI_VERIFIER_MODE_VERIFIABLE);
+                                */
+                               mono_security_set_mode (MONO_SECURITY_MODE_CAS);
+                               mono_activate_security_manager ();
+                       } 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) {
 #if defined (HAVE_BOEHM_GC)
                        GC_dont_expand = 1;
@@ -848,6 +1384,10 @@ mono_main (int argc, char* argv[])
                                fprintf (stderr, "Invalid --wapi suboption: '%s'\n", argv [i]);
                                return 1;
                        }
+#ifdef MONO_JIT_INFO_TABLE_TEST
+               } else if (strcmp (argv [i], "--test-jit-info-table") == 0) {
+                       test_jit_info_table = TRUE;
+#endif
                } else {
                        fprintf (stderr, "Unknown command line option: '%s'\n", argv [i]);
                        return 1;
@@ -859,7 +1399,7 @@ mono_main (int argc, char* argv[])
                return 1;
        }
 
-       if ((action == DO_EXEC) && g_getenv ("MONO_INSIDE_MDB"))
+       if ((action == DO_EXEC) && mono_debug_using_mono_debugger ())
                action = DO_DEBUGGER;
 
        if (mono_compile_aot || action == DO_EXEC || action == DO_DEBUGGER) {
@@ -868,7 +1408,7 @@ mono_main (int argc, char* argv[])
 
        if (enable_profile) {
                /* Needed because of TLS accesses in mono_profiler_load () */
-               MONO_GC_PRE_INIT ();
+               mono_gc_base_init ();
                mono_profiler_load (profile_options);
        }
 
@@ -883,10 +1423,6 @@ mono_main (int argc, char* argv[])
        }
 
        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
@@ -896,10 +1432,12 @@ mono_main (int argc, char* argv[])
                g_print ("The Mono Debugger is not supported on this platform.\n");
                return 1;
 #endif
-       }
+       } else if (enable_debugging)
+               mono_debug_init (MONO_DEBUG_FORMAT_MONO);
 
        mono_set_defaults (mini_verbose, opt);
-       domain = mini_init (argv [i]);
+       mono_setup_vtable_in_class_init = FALSE;
+       domain = mini_init (argv [i], forced_version);
        
        switch (action) {
        case DO_REGRESSION:
@@ -944,21 +1482,19 @@ mono_main (int argc, char* argv[])
                break;
        }
 
-       if (action == DO_DEBUGGER)
-               mono_debug_init_1 (domain);
-       else if (enable_debugging) {
-               mono_debug_init (MONO_DEBUG_FORMAT_MONO);
-               mono_debug_init_1 (domain);
-       }
-
        /* Parse gac loading options before loading assemblies. */
        if (mono_compile_aot || action == DO_EXEC || action == DO_DEBUGGER) {
                mono_config_parse (config_file);
        }
 
-       assembly = mono_assembly_open (aname, NULL);
+#ifdef MONO_JIT_INFO_TABLE_TEST
+       if (test_jit_info_table)
+               jit_info_table_test (domain);
+#endif
+
+       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;
        }
@@ -966,9 +1502,6 @@ mono_main (int argc, char* argv[])
        if (trace_options != NULL)
                mono_trace_set_assembly (assembly);
 
-       if (enable_debugging)
-               mono_debug_init_2 (assembly);
-
        if (mono_compile_aot || action == DO_EXEC) {
                const char *error;
 
@@ -977,6 +1510,8 @@ mono_main (int argc, char* argv[])
                error = mono_check_corlib_version ();
                if (error) {
                        fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
+                       fprintf (stderr, "Loaded from: %s\n",
+                               mono_defaults.corlib? mono_image_get_filename (mono_defaults.corlib): "unknown");
                        fprintf (stderr, "Download a newer corlib or a newer runtime at http://www.go-mono.com/daily.\n");
                        exit (1);
                }
@@ -1063,7 +1598,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
@@ -1120,7 +1655,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);
@@ -1138,7 +1673,32 @@ mono_main (int argc, char* argv[])
 MonoDomain * 
 mono_jit_init (const char *file)
 {
-       return mini_init (file);
+       return mini_init (file, NULL);
+}
+
+/**
+ * mono_jit_init_version:
+ * @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
+ * version to be used.  By default Mono will pick the runtime that is
+ * referenced by the initial assembly (specified in @file), this
+ * routine allows programmers to specify the actual runtime to be used
+ * as the initial runtime is inherited by all future assemblies loaded
+ * (since Mono does not support having more than one mscorlib runtime
+ * loaded at once).
+ *
+ * The @runtime_version can be one of these strings: "v1.1.4322" for
+ * the 1.1 runtime or "v2.0.50727"  for the 2.0 runtime. 
+ *
+ * Returns: the MonoDomain representing the domain where the assembly
+ * was loaded.
+ */
+MonoDomain * 
+mono_jit_init_version (const char *domain_name, const char *runtime_version)
+{
+       return mini_init (domain_name, runtime_version);
 }
 
 void        
@@ -1146,3 +1706,23 @@ mono_jit_cleanup (MonoDomain *domain)
 {
        mini_cleanup (domain);
 }
+
+/**
+ * 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;
+}
+