#include <mono/metadata/gc-internals.h>
#include <mono/metadata/verify-internals.h>
#include <mono/metadata/reflection-internals.h>
+#include <mono/metadata/w32event.h>
#include <mono/utils/strenc.h>
#include <mono/utils/mono-counters.h>
#include <mono/utils/mono-error-internals.h>
MonoNativeThreadId tid;
int do_initialization = 0;
MonoDomain *last_domain = NULL;
+ MonoException * pending_tae = NULL;
mono_error_init (error);
if (do_initialization) {
MonoException *exc = NULL;
+
+ mono_threads_begin_abort_protected_block ();
mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
- if (exc != NULL && mono_error_ok (error)) {
- mono_error_set_exception_instance (error, exc);
- }
+ mono_threads_end_abort_protected_block ();
+
+ //exception extracted, error will be set to the right value later
+ if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
+ exc = mono_error_convert_to_exception (error);
+ else
+ mono_error_cleanup (error);
+
+ mono_error_init (error);
/* If the initialization failed, mark the class as unusable. */
/* Avoid infinite loops */
- if (!(mono_error_ok(error) ||
+ if (!(!exc ||
(klass->image == mono_defaults.corlib &&
!strcmp (klass->name_space, "System") &&
!strcmp (klass->name, "TypeInitializationException")))) {
MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
g_free (full_name);
- return_val_if_nok (error, FALSE);
- mono_error_set_exception_instance (error, exc_to_throw);
+ mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
- MonoException *exc_to_store = mono_error_convert_to_exception (error);
- /* What we really want to do here is clone the error object and store one copy in the
- * domain's exception hash and use the other one to error out here. */
- mono_error_init (error);
- mono_error_set_exception_instance (error, exc_to_store);
/*
* Store the exception object so it could be thrown on subsequent
* accesses.
mono_domain_lock (domain);
if (!domain->type_init_exception_hash)
domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "type initialization exceptions table");
- mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_store);
+ mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
mono_domain_unlock (domain);
}
mono_domain_set (last_domain, TRUE);
lock->done = TRUE;
mono_type_init_unlock (lock);
+ if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class)
+ pending_tae = exc;
+ //TAEs are blocked around .cctors, they must escape as soon as no cctor is left to run.
+ if (!pending_tae)
+ pending_tae = mono_thread_try_resume_interruption ();
} else {
/* this just blocks until the initializing thread is done */
mono_type_init_lock (lock);
vtable->initialized = 1;
mono_type_initialization_unlock ();
- if (vtable->init_failed) {
+ //TAE wins over TIE
+ if (pending_tae)
+ mono_error_set_exception_instance (error, pending_tae);
+ else if (vtable->init_failed) {
/* Either we were the initializing thread or we waited for the initialization */
mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
return FALSE;
}
static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
-static MonoImtThunkBuilder imt_thunk_builder;
-static gboolean always_build_imt_thunks;
+static MonoImtTrampolineBuilder imt_trampoline_builder;
+static gboolean always_build_imt_trampolines;
#if (MONO_IMT_SIZE > 32)
#error "MONO_IMT_SIZE cannot be larger than 32"
}
void
-mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
- imt_thunk_builder = func;
+mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
+{
+ imt_trampoline_builder = func;
}
void
-mono_set_always_build_imt_thunks (gboolean value)
+mono_set_always_build_imt_trampolines (gboolean value)
{
- always_build_imt_thunks = value;
+ always_build_imt_trampolines = value;
}
/**
break;
}
- free (hashes_start);
+ g_free (hashes_start);
/* Report the result */
return c % MONO_IMT_SIZE;
}
imt_emit_ir (sorted_array, 0, number_of_entries, result);
- free (sorted_array);
+ g_free (sorted_array);
return result;
}
MONO_REQ_GC_NEUTRAL_MODE;
if (imt_builder_entry != NULL) {
- if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
+ if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
/* No collision, return the vtable slot contents */
return vtable->vtable [imt_builder_entry->value.vtable_slot];
} else {
- /* Collision, build the thunk */
+ /* Collision, build the trampoline */
GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
gpointer result;
int i;
- result = imt_thunk_builder (vtable, domain,
+ result = imt_trampoline_builder (vtable, domain,
(MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
for (i = 0; i < imt_ir->len; ++i)
g_free (g_ptr_array_index (imt_ir, i));
if (has_generic_virtual || has_variant_iface) {
/*
- * There might be collisions later when the the thunk is expanded.
+ * There might be collisions later when the the trampoline is expanded.
*/
imt_collisions_bitmap |= (1 << i);
/*
- * The IMT thunk might be called with an instance of one of the
+ * The IMT trampoline might be called with an instance of one of the
* generic virtual methods, so has to fallback to the IMT trampoline.
*/
imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
entry = next;
}
}
- free (imt_builder);
+ g_free (imt_builder);
/* we OR the bitmap since we may build just a single imt slot at a time */
vt->imt_collisions_bitmap |= imt_collisions_bitmap;
}
* @imt_slot: slot in the IMT table
*
* Fill the given @imt_slot in the IMT table of @vtable with
- * a trampoline or a thunk for the case of collisions.
+ * a trampoline or a trampoline for the case of collisions.
* This is part of the internal mono API.
*
* LOCKING: Take the domain lock.
mono_loader_unlock ();
}
-
-/*
- * The first two free list entries both belong to the wait list: The
- * first entry is the pointer to the head of the list and the second
- * entry points to the last element. That way appending and removing
- * the first element are both O(1) operations.
- */
-#ifdef MONO_SMALL_CONFIG
-#define NUM_FREE_LISTS 6
-#else
-#define NUM_FREE_LISTS 12
-#endif
-#define FIRST_FREE_LIST_SIZE 64
-#define MAX_WAIT_LENGTH 50
#define THUNK_THRESHOLD 10
-/*
- * LOCKING: The domain lock must be held.
- */
-static void
-init_thunk_free_lists (MonoDomain *domain)
-{
- MONO_REQ_GC_NEUTRAL_MODE;
-
- if (domain->thunk_free_lists)
- return;
- domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
-}
-
-static int
-list_index_for_size (int item_size)
-{
- int i = 2;
- int size = FIRST_FREE_LIST_SIZE;
-
- while (item_size > size && i < NUM_FREE_LISTS - 1) {
- i++;
- size <<= 1;
- }
-
- return i;
-}
-
/**
- * mono_method_alloc_generic_virtual_thunk:
+ * mono_method_alloc_generic_virtual_trampoline:
* @domain: a domain
* @size: size in bytes
*
* Allocs size bytes to be used for the code of a generic virtual
- * thunk. It's either allocated from the domain's code manager or
+ * trampoline. It's either allocated from the domain's code manager or
* reused from a previously invalidated piece.
*
* LOCKING: The domain lock must be held.
*/
gpointer
-mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
+mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
{
MONO_REQ_GC_NEUTRAL_MODE;
static gboolean inited = FALSE;
- static int generic_virtual_thunks_size = 0;
-
- guint32 *p;
- int i;
- MonoThunkFreeList **l;
-
- init_thunk_free_lists (domain);
-
- size += sizeof (guint32);
- if (size < sizeof (MonoThunkFreeList))
- size = sizeof (MonoThunkFreeList);
-
- i = list_index_for_size (size);
- for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
- if ((*l)->size >= size) {
- MonoThunkFreeList *item = *l;
- *l = item->next;
- return ((guint32*)item) + 1;
- }
- }
+ static int generic_virtual_trampolines_size = 0;
- /* no suitable item found - search lists of larger sizes */
- while (++i < NUM_FREE_LISTS) {
- MonoThunkFreeList *item = domain->thunk_free_lists [i];
- if (!item)
- continue;
- g_assert (item->size > size);
- domain->thunk_free_lists [i] = item->next;
- return ((guint32*)item) + 1;
- }
-
- /* still nothing found - allocate it */
if (!inited) {
- mono_counters_register ("Generic virtual thunk bytes",
- MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
+ mono_counters_register ("Generic virtual trampoline bytes",
+ MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
inited = TRUE;
}
- generic_virtual_thunks_size += size;
-
- p = (guint32 *)mono_domain_code_reserve (domain, size);
- *p = size;
-
- mono_domain_lock (domain);
- if (!domain->generic_virtual_thunks)
- domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
- g_hash_table_insert (domain->generic_virtual_thunks, p, p);
- mono_domain_unlock (domain);
+ generic_virtual_trampolines_size += size;
- return p + 1;
-}
-
-/*
- * LOCKING: The domain lock must be held.
- */
-static void
-invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
-{
- MONO_REQ_GC_NEUTRAL_MODE;
-
- guint32 *p = (guint32 *)code;
- MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
- gboolean found = FALSE;
-
- mono_domain_lock (domain);
- if (!domain->generic_virtual_thunks)
- domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
- if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
- found = TRUE;
- mono_domain_unlock (domain);
-
- if (!found)
- /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
- return;
- init_thunk_free_lists (domain);
-
- while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
- MonoThunkFreeList *item = domain->thunk_free_lists [0];
- int length = item->length;
- int i;
-
- /* unlink the first item from the wait list */
- domain->thunk_free_lists [0] = item->next;
- domain->thunk_free_lists [0]->length = length - 1;
-
- i = list_index_for_size (item->size);
-
- /* put it in the free list */
- item->next = domain->thunk_free_lists [i];
- domain->thunk_free_lists [i] = item;
- }
-
- l->next = NULL;
- if (domain->thunk_free_lists [1]) {
- domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
- domain->thunk_free_lists [0]->length++;
- } else {
- g_assert (!domain->thunk_free_lists [0]);
-
- domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
- domain->thunk_free_lists [0]->length = 1;
- }
+ return mono_domain_code_reserve (domain, size);
}
typedef struct _GenericVirtualCase {
* Registers a call via unmanaged code to a generic virtual method
* instantiation or variant interface method. If the number of calls reaches a threshold
* (THUNK_THRESHOLD), the method is added to the vtable slot's generic
- * virtual method thunk.
+ * virtual method trampoline.
*/
void
mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
static gboolean inited = FALSE;
static int num_added = 0;
+ static int num_freed = 0;
GenericVirtualCase *gvc, *list;
MonoImtBuilderEntry *entries;
if (!domain->generic_virtual_cases)
domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
+ if (!inited) {
+ mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
+ mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
+ inited = TRUE;
+ }
+
/* Check whether the case was already added */
list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
gvc = list;
g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
- if (!inited) {
- mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
- inited = TRUE;
- }
num_added++;
}
int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
int imt_slot = MONO_IMT_SIZE + displacement;
- /* Force the rebuild of the thunk at the next call */
+ /* Force the rebuild of the trampoline at the next call */
imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
*vtable_slot = imt_trampoline;
} else {
sorted = imt_sort_slot_entries (entries);
- *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
- vtable_trampoline);
+ *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
+ vtable_trampoline);
while (entries) {
MonoImtBuilderEntry *next = entries->next;
for (i = 0; i < sorted->len; ++i)
g_free (g_ptr_array_index (sorted, i));
g_ptr_array_free (sorted, TRUE);
- }
-#ifndef __native_client__
- /* We don't re-use any thunks as there is a lot of overhead */
- /* to deleting and re-using code in Native Client. */
- if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
- invalidate_generic_virtual_thunk (domain, old_thunk);
-#endif
+ if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
+ num_freed ++;
+ }
}
mono_domain_unlock (domain);
g_assert (klass);
if (mono_class_has_failure (klass)) {
- mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
+ mono_error_set_for_class_failure (error, klass);
return NULL;
}
if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
mono_domain_unlock (domain);
mono_loader_unlock ();
- mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
+ mono_error_set_for_class_failure (error, klass);
return NULL;
}
}
mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
mono_domain_unlock (domain);
mono_loader_unlock ();
- mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
+ mono_error_set_for_class_failure (error, klass);
return NULL;
}
}
if (mono_class_has_failure (klass)) {
mono_domain_unlock (domain);
mono_loader_unlock ();
- mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
+ mono_error_set_for_class_failure (error, klass);
return NULL;
}
return 0;
}
-/**
- * mono_runtime_run_main:
- * @method: the method to start the application with (usually Main)
- * @argc: number of arguments from the command line
- * @argv: array of strings from the command line
- * @exc: excetption results
- *
- * Execute a standard Main() method (argc/argv contains the
- * executable name). This method also sets the command line argument value
- * needed by System.Environment.
- *
+/*
+ * Prepare an array of arguments in order to execute a standard Main()
+ * method (argc/argv contains the executable name). This method also
+ * sets the command line argument value needed by System.Environment.
*
*/
-int
-mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
- MonoObject **exc)
+static MonoArray*
+prepare_run_main (MonoMethod *method, int argc, char *argv[])
{
MONO_REQ_GC_UNSAFE_MODE;
mono_assembly_set_main (method->klass->image->assembly);
- return mono_runtime_exec_main (method, args, exc);
+ return args;
+}
+
+/**
+ * mono_runtime_run_main:
+ * @method: the method to start the application with (usually Main)
+ * @argc: number of arguments from the command line
+ * @argv: array of strings from the command line
+ * @exc: excetption results
+ *
+ * Execute a standard Main() method (argc/argv contains the
+ * executable name). This method also sets the command line argument value
+ * needed by System.Environment.
+ *
+ *
+ */
+int
+mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
+ MonoObject **exc)
+{
+ MONO_REQ_GC_UNSAFE_MODE;
+
+ MonoError error;
+ MonoArray *args = prepare_run_main (method, argc, argv);
+ int res;
+ if (exc) {
+ res = mono_runtime_try_exec_main (method, args, exc);
+ } else {
+ res = mono_runtime_exec_main_checked (method, args, &error);
+ mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
+ }
+ return res;
+}
+
+/**
+ * mono_runtime_run_main_checked:
+ * @method: the method to start the application with (usually Main)
+ * @argc: number of arguments from the command line
+ * @argv: array of strings from the command line
+ * @error: set on error
+ *
+ * Execute a standard Main() method (argc/argv contains the
+ * executable name). This method also sets the command line argument value
+ * needed by System.Environment. On failure sets @error.
+ *
+ *
+ */
+int
+mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
+ MonoError *error)
+{
+ mono_error_init (error);
+ MonoArray *args = prepare_run_main (method, argc, argv);
+ return mono_runtime_exec_main_checked (method, args, error);
+}
+
+/**
+ * mono_runtime_try_run_main:
+ * @method: the method to start the application with (usually Main)
+ * @argc: number of arguments from the command line
+ * @argv: array of strings from the command line
+ * @exc: set if Main throws an exception
+ * @error: set if Main can't be executed
+ *
+ * Execute a standard Main() method (argc/argv contains the executable
+ * name). This method also sets the command line argument value needed
+ * by System.Environment. On failure sets @error if Main can't be
+ * executed or @exc if it threw and exception.
+ *
+ *
+ */
+int
+mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
+ MonoObject **exc)
+{
+ g_assert (exc);
+ MonoArray *args = prepare_run_main (method, argc, argv);
+ return mono_runtime_try_exec_main (method, args, exc);
}
+
static MonoObject*
serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
{
if (!current_appdomain_delegate && !root_appdomain_delegate) {
mono_print_unhandled_exception (exc);
} else {
+ /* unhandled exception callbacks must not be aborted */
+ mono_threads_begin_abort_protected_block ();
if (root_appdomain_delegate)
call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
if (current_appdomain_delegate)
call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
+ mono_threads_end_abort_protected_block ();
}
/* set exitcode only if we will abort the process */
mono_thread_manage ();
}
-/*
- * Execute a standard Main() method (args doesn't contain the
- * executable name).
- */
-int
-mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
+static void
+prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
{
- MONO_REQ_GC_UNSAFE_MODE;
-
- MonoError error;
- MonoDomain *domain;
- gpointer pa [1];
- int rval;
+ MonoInternalThread* thread = mono_thread_internal_current ();
MonoCustomAttrInfo* cinfo;
gboolean has_stathread_attribute;
- MonoInternalThread* thread = mono_thread_internal_current ();
-
- g_assert (args);
-
- pa [0] = args;
- domain = mono_object_domain (args);
if (!domain->entry_assembly) {
gchar *str;
MonoAssembly *assembly;
}
}
- cinfo = mono_custom_attrs_from_method_checked (method, &error);
- mono_error_cleanup (&error); /* FIXME warn here? */
+ MonoError cattr_error;
+ cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
+ mono_error_cleanup (&cattr_error); /* FIXME warn here? */
if (cinfo) {
has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
if (!cinfo->cached)
}
mono_thread_init_apartment_state ();
+}
+
+static int
+do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
+{
+ MONO_REQ_GC_UNSAFE_MODE;
+
+ gpointer pa [1];
+ int rval;
+
+ mono_error_init (error);
+ g_assert (args);
+
+ pa [0] = args;
+
/* FIXME: check signature of method */
if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
MonoObject *res;
- if (exc) {
- res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
- if (*exc == NULL && !mono_error_ok (&error))
- *exc = (MonoObject*) mono_error_convert_to_exception (&error);
- else
- mono_error_cleanup (&error);
- } else {
- res = mono_runtime_invoke_checked (method, NULL, pa, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ res = mono_runtime_invoke_checked (method, NULL, pa, error);
+ if (is_ok (error))
+ rval = *(guint32 *)((char *)res + sizeof (MonoObject));
+ else
+ rval = -1;
+ mono_environment_exitcode_set (rval);
+ } else {
+ mono_runtime_invoke_checked (method, NULL, pa, error);
+
+ if (is_ok (error))
+ rval = 0;
+ else {
+ rval = -1;
}
+ }
+ return rval;
+}
+
+static int
+do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
+{
+ MONO_REQ_GC_UNSAFE_MODE;
+
+ gpointer pa [1];
+ int rval;
+
+ g_assert (args);
+ g_assert (exc);
+
+ pa [0] = args;
- if (!exc || !*exc)
+ /* FIXME: check signature of method */
+ if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
+ MonoError inner_error;
+ MonoObject *res;
+ res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
+ if (*exc == NULL && !mono_error_ok (&inner_error))
+ *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
+ else
+ mono_error_cleanup (&inner_error);
+
+ if (*exc == NULL)
rval = *(guint32 *)((char *)res + sizeof (MonoObject));
else
rval = -1;
mono_environment_exitcode_set (rval);
} else {
- if (exc) {
- mono_runtime_try_invoke (method, NULL, pa, exc, &error);
- if (*exc == NULL && !mono_error_ok (&error))
- *exc = (MonoObject*) mono_error_convert_to_exception (&error);
- else
- mono_error_cleanup (&error);
- } else {
- mono_runtime_invoke_checked (method, NULL, pa, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
- }
+ MonoError inner_error;
+ mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
+ if (*exc == NULL && !mono_error_ok (&inner_error))
+ *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
+ else
+ mono_error_cleanup (&inner_error);
- if (!exc || !*exc)
+ if (*exc == NULL)
rval = 0;
else {
/* If the return type of Main is void, only
return rval;
}
+/*
+ * Execute a standard Main() method (args doesn't contain the
+ * executable name).
+ */
+int
+mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
+{
+ MonoError error;
+ prepare_thread_to_exec_main (mono_object_domain (args), method);
+ if (exc) {
+ int rval = do_try_exec_main (method, args, exc);
+ return rval;
+ } else {
+ int rval = do_exec_main_checked (method, args, &error);
+ mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
+ return rval;
+ }
+}
+
+/*
+ * Execute a standard Main() method (args doesn't contain the
+ * executable name).
+ *
+ * On failure sets @error
+ */
+int
+mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
+{
+ mono_error_init (error);
+ prepare_thread_to_exec_main (mono_object_domain (args), method);
+ return do_exec_main_checked (method, args, error);
+}
+
+/*
+ * Execute a standard Main() method (args doesn't contain the
+ * executable name).
+ *
+ * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
+ */
+int
+mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
+{
+ prepare_thread_to_exec_main (mono_object_domain (args), method);
+ return do_try_exec_main (method, args, exc);
+}
+
+
+
/** invoke_array_extract_argument:
* @params: array of arguments to the method.
* @i: the index of the argument to extract.
}
} else {
MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
return result;
}
}
gpointer wait_event = NULL;
ac->msg->exc = NULL;
+
res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
- if (mono_error_set_pending_exception (&error))
- return NULL;
+
+ /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
+ mono_threads_begin_abort_protected_block ();
+
+ if (!ac->msg->exc) {
+ MonoException *ex = mono_error_convert_to_exception (&error);
+ ac->msg->exc = (MonoObject *)ex;
+ } else {
+ mono_error_cleanup (&error);
+ }
+
MONO_OBJECT_SETREF (ac, res, res);
mono_monitor_enter ((MonoObject*) ares);
mono_monitor_exit ((MonoObject*) ares);
if (wait_event != NULL)
- SetEvent (wait_event);
+ mono_w32event_set (wait_event);
- if (ac->cb_method) {
+ mono_error_init (&error); //the else branch would leave it in an undefined state
+ if (ac->cb_method)
mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
- if (mono_error_set_pending_exception (&error))
- return NULL;
- }
+
+ mono_threads_end_abort_protected_block ();
+
+ if (mono_error_set_pending_exception (&error))
+ return NULL;
}
return res;
{
MONO_REQ_GC_UNSAFE_MODE;
- static MonoClass *object_array_klass;
- static MonoClass *byte_array_klass;
- static MonoClass *string_array_klass;
- mono_error_init (error);
- MonoMethodSignature *sig = mono_method_signature (method->method);
- MonoString *name;
- MonoArray *arr;
- int i, j;
- char **names;
- guint8 arg_type;
-
- if (!object_array_klass) {
- MonoClass *klass;
+ static MonoMethod *init_message_method = NULL;
- klass = mono_array_class_get (mono_defaults.byte_class, 1);
- g_assert (klass);
- byte_array_klass = klass;
-
- klass = mono_array_class_get (mono_defaults.string_class, 1);
- g_assert (klass);
- string_array_klass = klass;
-
- klass = mono_array_class_get (mono_defaults.object_class, 1);
- g_assert (klass);
-
- mono_atomic_store_release (&object_array_klass, klass);
+ if (!init_message_method) {
+ init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
+ g_assert (init_message_method != NULL);
}
- MONO_OBJECT_SETREF (this_obj, method, method);
-
- arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, error);
- return_val_if_nok (error, FALSE);
-
- MONO_OBJECT_SETREF (this_obj, args, arr);
-
- arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, error);
- return_val_if_nok (error, FALSE);
-
- MONO_OBJECT_SETREF (this_obj, arg_types, arr);
-
- this_obj->async_result = NULL;
- this_obj->call_type = CallType_Sync;
-
- names = g_new (char *, sig->param_count);
- mono_method_get_param_names (method->method, (const char **) names);
-
- arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, error);
- if (!is_ok (error))
- goto fail;
-
- MONO_OBJECT_SETREF (this_obj, names, arr);
+ mono_error_init (error);
+ /* FIXME set domain instead? */
+ g_assert (domain == mono_domain_get ());
- for (i = 0; i < sig->param_count; i++) {
- name = mono_string_new_checked (domain, names [i], error);
- if (!is_ok (error))
- goto fail;
- mono_array_setref (this_obj->names, i, name);
- }
+ gpointer args[2];
- g_free (names);
- for (i = 0, j = 0; i < sig->param_count; i++) {
- if (sig->params [i]->byref) {
- if (out_args) {
- MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
- mono_array_setref (this_obj->args, i, arg);
- j++;
- }
- arg_type = 2;
- if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
- arg_type |= 1;
- } else {
- arg_type = 1;
- if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
- arg_type |= 4;
- }
- mono_array_set (this_obj->arg_types, guint8, i, arg_type);
- }
+ args[0] = method;
+ args[1] = out_args;
- return TRUE;
-fail:
- g_free (names);
- return FALSE;
+ mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
+ return is_ok (error);
}
#ifndef DISABLE_REMOTING
return result;
}
-/**
- * mono_load_remote_field_new_icall:
- * @this: pointer to an object
- * @klass: klass of the object containing @field
- * @field: the field to load
- *
- * This method is called by the runtime on attempts to load fields of
- * transparent proxy objects. @this points to such TP, @klass is the class of
- * the object containing @field.
- *
- * Returns: a freshly allocated object containing the value of the
- * field. On failure returns NULL and throws an exception.
- */
-MonoObject *
-mono_load_remote_field_new_icall (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
-{
- MonoError error;
- MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
- mono_error_set_pending_exception (&error);
- return result;
-}
-
/**
* mono_load_remote_field_new_checked:
* @this: pointer to an object
mono_error_init (error);
- static MonoMethod *getter = NULL;
- MonoDomain *domain = mono_domain_get ();
- MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
- MonoClass *field_class;
- MonoMethodMessage *msg;
- MonoArray *out_args;
- MonoObject *exc, *res;
- char* full_name;
+ static MonoMethod *tp_load = NULL;
g_assert (mono_object_is_transparent_proxy (this_obj));
- field_class = mono_class_from_mono_type (field->type);
-
- if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
- gpointer val;
- if (field_class->valuetype) {
- res = mono_object_new_checked (domain, field_class, error);
- return_val_if_nok (error, NULL);
- val = ((gchar *) res) + sizeof (MonoObject);
- } else {
- val = &res;
- }
- mono_field_get_value (tp->rp->unwrapped_server, field, val);
- return res;
- }
-
- if (!getter) {
- getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
- if (!getter) {
+ if (!tp_load) {
+ tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
+ if (!tp_load) {
mono_error_set_not_supported (error, "Linked away.");
return NULL;
}
}
- msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
- return_val_if_nok (error, NULL);
- out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
- return_val_if_nok (error, NULL);
-
- MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
- return_val_if_nok (error, NULL);
- mono_message_init (domain, msg, rm, out_args, error);
- return_val_if_nok (error, NULL);
-
- full_name = mono_type_get_full_name (klass);
- mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
- mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
- g_free (full_name);
-
- mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
- return_val_if_nok (error, NULL);
-
- if (exc) {
- mono_error_set_exception_instance (error, (MonoException *)exc);
- return NULL;
- }
+ /* MonoType *type = mono_class_get_type (klass); */
- if (mono_array_length (out_args) == 0)
- res = NULL;
- else
- res = mono_array_get (out_args, MonoObject *, 0);
+ gpointer args[2];
+ args [0] = &klass;
+ args [1] = &field;
- return res;
+ return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
}
/**
MONO_REQ_GC_UNSAFE_MODE;
- static MonoMethod *setter = NULL;
+ mono_error_init (error);
MonoDomain *domain = mono_domain_get ();
- MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
MonoClass *field_class;
- MonoMethodMessage *msg;
- MonoArray *out_args;
- MonoObject *exc;
MonoObject *arg;
- char* full_name;
-
- mono_error_init (error);
g_assert (mono_object_is_transparent_proxy (this_obj));
field_class = mono_class_from_mono_type (field->type);
- if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
- if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
- else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
- return TRUE;
- }
-
- if (!setter) {
- setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
- if (!setter) {
- mono_error_set_not_supported (error, "Linked away.");
- return FALSE;
- }
- }
-
if (field_class->valuetype) {
arg = mono_value_box_checked (domain, field_class, val, error);
return_val_if_nok (error, FALSE);
- } else
- arg = *((MonoObject **)val);
-
-
- msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
- return_val_if_nok (error, FALSE);
- MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, error);
- return_val_if_nok (error, FALSE);
- mono_message_init (domain, msg, rm, NULL, error);
- return_val_if_nok (error, FALSE);
-
- full_name = mono_type_get_full_name (klass);
- mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
- mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
- mono_array_setref (msg->args, 2, arg);
- g_free (full_name);
-
- mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
- return_val_if_nok (error, FALSE);
-
- if (exc) {
- mono_error_set_exception_instance (error, (MonoException *)exc);
- return FALSE;
+ } else {
+ arg = *((MonoObject**)val);
}
- return TRUE;
+
+ return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
}
/**
mono_error_cleanup (&error);
}
-/**
- * mono_store_remote_field_new_icall:
- * @this_obj:
- * @klass:
- * @field:
- * @arg:
- *
- * Missing documentation
- */
-void
-mono_store_remote_field_new_icall (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
-{
- MonoError error;
- (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
- mono_error_set_pending_exception (&error);
-}
-
/**
* mono_store_remote_field_new_checked:
* @this_obj:
{
MONO_REQ_GC_UNSAFE_MODE;
- static MonoMethod *setter = NULL;
- MonoDomain *domain = mono_domain_get ();
- MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
- MonoClass *field_class;
- MonoMethodMessage *msg;
- MonoArray *out_args;
- MonoObject *exc;
- char* full_name;
+ static MonoMethod *tp_store = NULL;
mono_error_init (error);
g_assert (mono_object_is_transparent_proxy (this_obj));
- field_class = mono_class_from_mono_type (field->type);
-
- if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
- if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
- else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
- return TRUE;
- }
-
- if (!setter) {
- setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
- if (!setter) {
+ if (!tp_store) {
+ tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
+ if (!tp_store) {
mono_error_set_not_supported (error, "Linked away.");
return FALSE;
}
}
- msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
- return_val_if_nok (error, FALSE);
- MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, error);
- return_val_if_nok (error, FALSE);
- mono_message_init (domain, msg, rm, NULL, error);
- return_val_if_nok (error, FALSE);
+ gpointer args[3];
+ args [0] = &klass;
+ args [1] = &field;
+ args [2] = arg;
- full_name = mono_type_get_full_name (klass);
- mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
- mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
- mono_array_setref (msg->args, 2, arg);
- g_free (full_name);
-
- mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
- return_val_if_nok (error, FALSE);
-
- if (exc) {
- mono_error_set_exception_instance (error, (MonoException *)exc);
- return FALSE;
- }
- return TRUE;
+ mono_runtime_invoke_checked (tp_store, this_obj, args, error);
+ return is_ok (error);
}
#endif