Merge pull request #2819 from BrzVlad/fix-major-log
[mono.git] / mono / mini / driver.c
index 09da6d2875e48376d83823e8eec0857ad79e4300..e39a941023491c1b34581a32ef7f7e3db9789cd6 100644 (file)
@@ -7,6 +7,7 @@
  *
  * (C) 2002-2003 Ximian, Inc.
  * (C) 2003-2006 Novell, Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
 #include <config.h>
@@ -50,6 +51,7 @@
 #include <mono/metadata/attach.h>
 #include "mono/utils/mono-counters.h"
 #include "mono/utils/mono-hwcap.h"
+#include "mono/utils/mono-logger-internals.h"
 
 #include "mini.h"
 #include "jit.h"
@@ -381,9 +383,12 @@ mini_regression_step (MonoImage *image, int verbose, int *total_run, int *total,
        if (mini_stats_fd)
                fprintf (mini_stats_fd, "[");
        for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
-               MonoMethod *method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
-               if (!method)
+               MonoError error;
+               MonoMethod *method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
+               if (!method) {
+                       mono_error_cleanup (&error); /* FIXME don't swallow the error */
                        continue;
+               }
                if (strncmp (method->name, "test_", 5) == 0) {
                        MonoCompile *cfg;
 
@@ -474,9 +479,12 @@ 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);
-               if (!method)
+               MonoError error;
+               method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
+               if (!method) {
+                       mono_error_cleanup (&error);
                        continue;
+               }
                mono_class_init (method->klass);
 
                if (!strncmp (method->name, "test_", 5) && mini_stats_fd) {
@@ -904,15 +912,18 @@ compile_all_methods_thread_main_inner (CompileAllThreadArgs *args)
        int i, count = 0, fail_count = 0;
 
        for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
+               MonoError error;
                guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
                MonoMethodSignature *sig;
 
                if (mono_metadata_has_generic_params (image, token))
                        continue;
 
-               method = mono_get_method (image, token, NULL);
-               if (!method)
+               method = mono_get_method_checked (image, token, NULL, NULL, &error);
+               if (!method) {
+                       mono_error_cleanup (&error); /* FIXME don't swallow the error */
                        continue;
+               }
                if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
                    (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
                    (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
@@ -989,6 +1000,7 @@ compile_all_methods (MonoAssembly *ass, int verbose, guint32 opts, guint32 recom
 int 
 mono_jit_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
 {
+       MonoError error;
        MonoImage *image = mono_assembly_get_image (assembly);
        MonoMethod *method;
        guint32 entry = mono_image_get_entry_point (image);
@@ -1000,14 +1012,28 @@ mono_jit_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[
                return 1;
        }
 
-       method = mono_get_method (image, entry, NULL);
+       method = mono_get_method_checked (image, entry, NULL, NULL, &error);
        if (method == NULL){
-               g_print ("The entry point method could not be loaded\n");
+               g_print ("The entry point method could not be loaded due to %s\n", mono_error_get_message (&error));
+               mono_error_cleanup (&error);
                mono_environment_exitcode_set (1);
                return 1;
        }
        
-       return mono_runtime_run_main (method, argc, argv, NULL);
+       if (mono_llvm_only) {
+               MonoObject *exc;
+               int res;
+
+               res = mono_runtime_run_main (method, argc, argv, &exc);
+               if (exc) {
+                       mono_unhandled_exception (exc);
+                       mono_invoke_unhandled_exception_hook (exc);
+                       return 1;
+               }
+               return res;
+       } else {
+               return mono_runtime_run_main (method, argc, argv, NULL);
+       }
 }
 
 typedef struct 
@@ -1073,6 +1099,7 @@ static void main_thread_handler (gpointer user_data)
 static int
 load_agent (MonoDomain *domain, char *desc)
 {
+       MonoError error;
        char* col = strchr (desc, ':'); 
        char *agent, *args;
        MonoAssembly *agent_assembly;
@@ -1111,9 +1138,10 @@ load_agent (MonoDomain *domain, char *desc)
                return 1;
        }
 
-       method = mono_get_method (image, entry, NULL);
+       method = mono_get_method_checked (image, entry, NULL, NULL, &error);
        if (method == NULL){
-               g_print ("The entry point method of assembly '%s' could not be loaded\n", agent);
+               g_print ("The entry point method of assembly '%s' could not be loaded due to %s\n", agent, &error);
+               mono_error_cleanup (&error);
                g_free (agent);
                return 1;
        }
@@ -1131,7 +1159,8 @@ load_agent (MonoDomain *domain, char *desc)
 
        pa [0] = main_args;
        /* Pass NULL as 'exc' so unhandled exceptions abort the runtime */
-       mono_runtime_invoke (method, NULL, pa, NULL);
+       mono_runtime_invoke_checked (method, NULL, pa, &error);
+       mono_error_raise_exception (&error); /* FIXME don't raise here */
 
        return 0;
 }
@@ -1162,6 +1191,8 @@ mini_usage_jitdeveloper (void)
                 "    --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"
+                "The options supported by MONO_DEBUG can also be passed on the command line.\n"
+                "\n"
                 "Other options:\n" 
                 "    --graph[=TYPE] METHOD  Draws a graph of the specified method:\n");
        
@@ -1411,6 +1442,7 @@ mono_jit_parse_options (int argc, char * argv[])
 #else
                        mono_use_llvm = TRUE;
 #endif
+               } else if (argv [i][0] == '-' && argv [i][1] == '-' && mini_parse_debug_option (argv [i] + 2)) {
                } else {
                        fprintf (stderr, "Unsupported command line option: '%s'\n", argv [i]);
                        exit (1);
@@ -1574,7 +1606,7 @@ mono_main (int argc, char* argv[])
 #if TARGET_OSX
        darwin_change_default_file_handles ();
 #endif
-       
+
        if (g_getenv ("MONO_NO_SMP"))
                mono_set_use_smp (FALSE);
        
@@ -1883,6 +1915,7 @@ mono_main (int argc, char* argv[])
                } else if (strcmp (argv [i], "--nacl-null-checks-off") == 0){
                        nacl_null_checks_off = TRUE;
 #endif
+               } else if (argv [i][0] == '-' && argv [i][1] == '-' && mini_parse_debug_option (argv [i] + 2)) {
                } else {
                        fprintf (stderr, "Unknown command line option: '%s'\n", argv [i]);
                        return 1;
@@ -1900,6 +1933,14 @@ mono_main (int argc, char* argv[])
        }
 #endif
 
+#ifdef DISABLE_HW_TRAPS
+       // Signal handlers not available
+       {
+               MonoDebugOptions *opt = mini_get_debug_options ();
+               opt->explicit_null_checks = TRUE;
+       }
+#endif
+
        if (!argv [i]) {
                mini_usage ();
                return 1;
@@ -1946,8 +1987,16 @@ mono_main (int argc, char* argv[])
        /* Set rootdir before loading config */
        mono_set_rootdir ();
 
-       if (enable_profile)
+       /*
+        * We only set the native name of the thread since MS.NET leaves the
+        * managed thread name for the main thread as null.
+        */
+       mono_thread_info_set_name (mono_native_thread_id_get (), "Main");
+
+       if (enable_profile) {
                mono_profiler_load (profile_options);
+               mono_profiler_thread_name (mono_native_thread_id_get (), "Main");
+       }
 
        mono_attach_parse_options (attach_options);
 
@@ -2240,8 +2289,9 @@ mono_jit_init (const char *file)
  * (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. 
+ * The @runtime_version can be one of these strings: "v4.0.30319" for
+ * desktop, "mobile" for mobile or "moonlight" for Silverlight compat.
+ * If an unrecognized string is input, the vm will default to desktop.
  *
  * Returns: the MonoDomain representing the domain where the assembly
  * was loaded.
@@ -2270,8 +2320,10 @@ void
 mono_jit_set_aot_mode (MonoAotMode mode)
 {
        mono_aot_mode = mode;
-       if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY)
+       if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY) {
+               mono_aot_only = TRUE;
                mono_llvm_only = TRUE;
+       }
 }
 
 /**
@@ -2325,83 +2377,154 @@ mono_set_crash_chaining (gboolean chain_crashes)
        mono_do_crash_chaining = chain_crashes;
 }
 
-void
-mono_parse_env_options (int *ref_argc, char **ref_argv [])
+/**
+ * mono_parse_options_from:
+ * @options: string containing strings 
+ * @ref_argc: pointer to the argc variable that might be updated 
+ * @ref_argv: pointer to the argv string vector variable that might be updated
+ *
+ * This function parses the contents of the `MONO_ENV_OPTIONS`
+ * environment variable as if they were parsed by a command shell
+ * splitting the contents by spaces into different elements of the
+ * @argv vector.  This method supports quoting with both the " and '
+ * characters.  Inside quoting, spaces and tabs are significant,
+ * otherwise, they are considered argument separators.
+ *
+ * The \ character can be used to escape the next character which will
+ * be added to the current element verbatim.  Typically this is used
+ * inside quotes.   If the quotes are not balanced, this method 
+ *
+ * If the environment variable is empty, no changes are made
+ * to the values pointed by @ref_argc and @ref_argv.
+ *
+ * Otherwise the @ref_argv is modified to point to a new array that contains
+ * all the previous elements contained in the vector, plus the values parsed.
+ * The @argc is updated to match the new number of parameters.
+ *
+ * Returns: The value NULL is returned on success, otherwise a g_strdup allocated
+ * string is returned (this is an alias to malloc under normal circumstances) that
+ * contains the error message that happened during parsing.
+ */
+char *
+mono_parse_options_from (const char *options, int *ref_argc, char **ref_argv [])
 {
        int argc = *ref_argc;
        char **argv = *ref_argv;
-
-       const char *env_options = g_getenv ("MONO_ENV_OPTIONS");
-       if (env_options != NULL){
-               GPtrArray *array = g_ptr_array_new ();
-               GString *buffer = g_string_new ("");
-               const char *p;
-               unsigned i;
-               gboolean in_quotes = FALSE;
-               char quote_char = '\0';
-
-               for (p = env_options; *p; p++){
-                       switch (*p){
-                       case ' ': case '\t':
-                               if (!in_quotes) {
-                                       if (buffer->len != 0){
-                                               g_ptr_array_add (array, g_strdup (buffer->str));
-                                               g_string_truncate (buffer, 0);
-                                       }
-                               } else {
-                                       g_string_append_c (buffer, *p);
-                               }
-                               break;
-                       case '\\':
-                               if (p [1]){
-                                       g_string_append_c (buffer, p [1]);
-                                       p++;
-                               }
-                               break;
-                       case '\'':
-                       case '"':
-                               if (in_quotes) {
-                                       if (quote_char == *p)
-                                               in_quotes = FALSE;
-                                       else
-                                               g_string_append_c (buffer, *p);
-                               } else {
-                                       in_quotes = TRUE;
-                                       quote_char = *p;
+       GPtrArray *array = g_ptr_array_new ();
+       GString *buffer = g_string_new ("");
+       const char *p;
+       unsigned i;
+       gboolean in_quotes = FALSE;
+       char quote_char = '\0';
+
+       if (options == NULL)
+               return NULL;
+       
+       for (p = options; *p; p++){
+               switch (*p){
+               case ' ': case '\t':
+                       if (!in_quotes) {
+                               if (buffer->len != 0){
+                                       g_ptr_array_add (array, g_strdup (buffer->str));
+                                       g_string_truncate (buffer, 0);
                                }
-                               break;
-                       default:
+                       } else {
                                g_string_append_c (buffer, *p);
-                               break;
                        }
+                       break;
+               case '\\':
+                       if (p [1]){
+                               g_string_append_c (buffer, p [1]);
+                               p++;
+                       }
+                       break;
+               case '\'':
+               case '"':
+                       if (in_quotes) {
+                               if (quote_char == *p)
+                                       in_quotes = FALSE;
+                               else
+                                       g_string_append_c (buffer, *p);
+                       } else {
+                               in_quotes = TRUE;
+                               quote_char = *p;
+                       }
+                       break;
+               default:
+                       g_string_append_c (buffer, *p);
+                       break;
                }
-               if (in_quotes) {
-                       fprintf (stderr, "Unmatched quotes in value of MONO_ENV_OPTIONS: [%s]\n", env_options);
-                       exit (1);
-               }
-                       
-               if (buffer->len != 0)
-                       g_ptr_array_add (array, g_strdup (buffer->str));
-               g_string_free (buffer, TRUE);
+       }
+       if (in_quotes) 
+               return g_strdup_printf ("Unmatched quotes in value: [%s]\n", options);
+               
+       if (buffer->len != 0)
+               g_ptr_array_add (array, g_strdup (buffer->str));
+       g_string_free (buffer, TRUE);
 
-               if (array->len > 0){
-                       int new_argc = array->len + argc;
-                       char **new_argv = g_new (char *, new_argc + 1);
-                       int j;
+       if (array->len > 0){
+               int new_argc = array->len + argc;
+               char **new_argv = g_new (char *, new_argc + 1);
+               int j;
 
-                       new_argv [0] = argv [0];
-                       
-                       /* First the environment variable settings, to allow the command line options to override */
-                       for (i = 0; i < array->len; i++)
-                               new_argv [i+1] = (char *)g_ptr_array_index (array, i);
-                       i++;
-                       for (j = 1; j < argc; j++)
-                               new_argv [i++] = argv [j];
-                       new_argv [i] = NULL;
-
-                       *ref_argc = new_argc;
-                       *ref_argv = new_argv;
-               }
-               g_ptr_array_free (array, TRUE);
+               new_argv [0] = argv [0];
+               
+               /* First the environment variable settings, to allow the command line options to override */
+               for (i = 0; i < array->len; i++)
+                       new_argv [i+1] = (char *)g_ptr_array_index (array, i);
+               i++;
+               for (j = 1; j < argc; j++)
+                       new_argv [i++] = argv [j];
+               new_argv [i] = NULL;
+
+               *ref_argc = new_argc;
+               *ref_argv = new_argv;
        }
+       g_ptr_array_free (array, TRUE);
+       return NULL;
+}
+
+/**
+ * mono_parse_env_options:
+ * @ref_argc: pointer to the argc variable that might be updated 
+ * @ref_argv: pointer to the argv string vector variable that might be updated
+ *
+ * This function parses the contents of the `MONO_ENV_OPTIONS`
+ * environment variable as if they were parsed by a command shell
+ * splitting the contents by spaces into different elements of the
+ * @argv vector.  This method supports quoting with both the " and '
+ * characters.  Inside quoting, spaces and tabs are significant,
+ * otherwise, they are considered argument separators.
+ *
+ * The \ character can be used to escape the next character which will
+ * be added to the current element verbatim.  Typically this is used
+ * inside quotes.   If the quotes are not balanced, this method 
+ *
+ * If the environment variable is empty, no changes are made
+ * to the values pointed by @ref_argc and @ref_argv.
+ *
+ * Otherwise the @ref_argv is modified to point to a new array that contains
+ * all the previous elements contained in the vector, plus the values parsed.
+ * The @argc is updated to match the new number of parameters.
+ *
+ * If there is an error parsing, this method will terminate the process by
+ * calling exit(1).
+ *
+ * An alternative to this method that allows an arbitrary string to be parsed
+ * and does not exit on error is the `api:mono_parse_options_from`.
+ */
+void
+mono_parse_env_options (int *ref_argc, char **ref_argv [])
+{
+       char *ret;
+       
+       const char *env_options = g_getenv ("MONO_ENV_OPTIONS");
+       if (env_options == NULL)
+               return;
+       ret = mono_parse_options_from (env_options, ref_argc, ref_argv);
+       if (ret == NULL)
+               return;
+       fprintf (stderr, "%s", ret);
+       exit (1);
 }
+