* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2011 Novell, Inc (http://www.novell.com)
* Copyright 2001 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#ifdef HAVE_ALLOCA_H
#include <mono/metadata/object.h>
#include <mono/metadata/gc-internals.h>
#include <mono/metadata/exception.h>
+#include <mono/metadata/exception-internals.h>
#include <mono/metadata/domain-internals.h>
#include "mono/metadata/metadata-internals.h"
#include "mono/metadata/class-internals.h"
#include "mono/metadata/mono-debug-debugger.h"
#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>
#include <mono/utils/mono-memory-model.h>
#include <mono/utils/checked-build.h>
#include <mono/utils/mono-threads.h>
+#include <mono/utils/mono-threads-coop.h>
#include "cominterop.h"
static void
-get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
+get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
static MonoString*
-mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
+mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
static void
free_main_args (void);
static char *
mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
+/* Class lazy loading functions */
+static GENERATE_GET_CLASS_WITH_CACHE (pointer, System.Reflection, Pointer)
+static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, System.Runtime.Remoting, RemotingServices)
+static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, System, UnhandledExceptionEventArgs)
+static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, System, STAThreadAttribute)
+static GENERATE_GET_CLASS_WITH_CACHE (activation_services, System.Runtime.Remoting.Activation, ActivationServices)
+
#define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
#define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
static mono_mutex_t ldstr_section;
+/**
+ * mono_runtime_object_init:
+ * @this_obj: the object to initialize
+ *
+ * This function calls the zero-argument constructor (which must
+ * exist) for the given object.
+ */
void
mono_runtime_object_init (MonoObject *this_obj)
+{
+ MonoError error;
+ mono_runtime_object_init_checked (this_obj, &error);
+ mono_error_assert_ok (&error);
+}
+
+/**
+ * mono_runtime_object_init_checked:
+ * @this_obj: the object to initialize
+ * @error: set on error.
+ *
+ * This function calls the zero-argument constructor (which must
+ * exist) for the given object and returns TRUE on success, or FALSE
+ * on error and sets @error.
+ */
+gboolean
+mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
MonoMethod *method = NULL;
MonoClass *klass = this_obj->vtable->klass;
+ mono_error_init (error);
method = mono_class_get_method_from_name (klass, ".ctor", 0);
if (!method)
g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
if (method->klass->valuetype)
this_obj = (MonoObject *)mono_object_unbox (this_obj);
- mono_runtime_invoke (method, this_obj, NULL, NULL);
+
+ mono_runtime_invoke_checked (method, this_obj, NULL, error);
+ return is_ok (error);
}
/* The pseudo algorithm for type initialization from the spec
{
MONO_REQ_GC_UNSAFE_MODE;
+ MonoError error;
MonoDomain *domain = vtable->domain;
MonoClass *klass = vtable->klass;
MonoException *ex;
full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
else
full_name = g_strdup (klass->name);
- ex = mono_get_exception_type_initialization (full_name, NULL);
+ ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
g_free (full_name);
+ return_val_if_nok (&error, NULL);
}
return ex;
}
+
/*
* mono_runtime_class_init:
* @vtable: vtable that needs to be initialized
mono_runtime_class_init (MonoVTable *vtable)
{
MONO_REQ_GC_UNSAFE_MODE;
+ MonoError error;
- mono_runtime_class_init_full (vtable, TRUE);
+ mono_runtime_class_init_full (vtable, &error);
+ mono_error_assert_ok (&error);
}
-/*
+/**
* mono_runtime_class_init_full:
* @vtable that neeeds to be initialized
- * @raise_exception is TRUE, exceptions are raised intead of returned
+ * @error set on error
+ *
+ * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
*
*/
-MonoException *
-mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
+gboolean
+mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
- MonoException *exc;
- MonoException *exc_to_throw;
MonoMethod *method = NULL;
MonoClass *klass;
gchar *full_name;
MonoNativeThreadId tid;
int do_initialization = 0;
MonoDomain *last_domain = NULL;
+ MonoException * pending_tae = NULL;
+
+ mono_error_init (error);
if (vtable->initialized)
- return NULL;
+ return TRUE;
- exc = NULL;
klass = vtable->klass;
if (!klass->image->checked_module_cctor) {
mono_image_check_for_module_cctor (klass->image);
if (klass->image->has_module_cctor) {
- MonoError error;
MonoClass *module_klass;
MonoVTable *module_vtable;
- module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, &error);
+ module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
if (!module_klass) {
- exc = mono_error_convert_to_exception (&error);
- if (raise_exception)
- mono_raise_exception (exc);
- return exc;
+ return FALSE;
}
- module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
+ module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
if (!module_vtable)
- return NULL;
- exc = mono_runtime_class_init_full (module_vtable, raise_exception);
- if (exc)
- return exc;
+ return FALSE;
+ if (!mono_runtime_class_init_full (module_vtable, error))
+ return FALSE;
}
}
method = mono_class_get_cctor (klass);
if (!method) {
vtable->initialized = 1;
- return NULL;
+ return TRUE;
}
tid = mono_native_thread_id_get ();
/* double check... */
if (vtable->initialized) {
mono_type_initialization_unlock ();
- return NULL;
+ return TRUE;
}
if (vtable->init_failed) {
mono_type_initialization_unlock ();
/* The type initialization already failed once, rethrow the same exception */
- if (raise_exception)
- mono_raise_exception (get_type_init_exception_for_vtable (vtable));
- return get_type_init_exception_for_vtable (vtable);
+ mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
+ return FALSE;
}
lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
if (lock == NULL) {
if (!mono_domain_set (domain, FALSE)) {
vtable->initialized = 1;
mono_type_initialization_unlock ();
- if (raise_exception)
- mono_raise_exception (mono_get_exception_appdomain_unloaded ());
- return mono_get_exception_appdomain_unloaded ();
+ mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
+ return FALSE;
}
}
lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
mono_type_initialization_unlock ();
- return NULL;
+ return TRUE;
}
/* see if the thread doing the initialization is already blocked on this thread */
blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
if (!pending_lock->done) {
mono_type_initialization_unlock ();
- return NULL;
+ return TRUE;
} else {
/* the thread doing the initialization is blocked on this thread,
but on a lock that has already been freed. It just hasn't got
mono_type_initialization_unlock ();
if (do_initialization) {
- mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
+ MonoException *exc = NULL;
+
+ mono_threads_begin_abort_protected_block ();
+ mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
+ 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 (!(exc == NULL ||
+ if (!(!exc ||
(klass->image == mono_defaults.corlib &&
!strcmp (klass->name_space, "System") &&
!strcmp (klass->name, "TypeInitializationException")))) {
full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
else
full_name = g_strdup (klass->name);
- exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
+
+ MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
g_free (full_name);
+ mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
+
/*
* Store the exception object so it could be thrown on subsequent
* accesses.
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 */
- if (raise_exception)
- mono_raise_exception (get_type_init_exception_for_vtable (vtable));
- return get_type_init_exception_for_vtable (vtable);
+ mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
+ return FALSE;
}
- return NULL;
+ return TRUE;
}
static
mono_type_initialization_unlock ();
}
-static gpointer
-default_trampoline (MonoMethod *method)
-{
- return method;
-}
-
-static gpointer
-default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
-{
- g_assert_not_reached ();
-
- return NULL;
-}
-
#ifndef DISABLE_REMOTING
static gpointer
-default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
+default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
{
g_error ("remoting not installed");
return NULL;
return NULL;
}
-static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
-static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
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"
return &callbacks;
}
-void
-mono_install_trampoline (MonoTrampoline func)
-{
- arch_create_jit_trampoline = func? func: default_trampoline;
-}
-
-void
-mono_install_jump_trampoline (MonoJumpTrampoline func)
-{
- arch_create_jump_trampoline = func? func: default_jump_trampoline;
-}
-
#ifndef DISABLE_REMOTING
void
mono_install_remoting_trampoline (MonoRemotingTrampoline func)
}
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;
}
-static MonoCompileFunc default_mono_compile_method = NULL;
-
/**
- * mono_install_compile_method:
- * @func: function to install
+ * mono_compile_method:
+ * @method: The method to compile.
*
- * This is a VM internal routine
+ * This JIT-compiles the method, and returns the pointer to the native code
+ * produced.
*/
-void
-mono_install_compile_method (MonoCompileFunc func)
+gpointer
+mono_compile_method (MonoMethod *method)
{
- default_mono_compile_method = func;
+ MonoError error;
+ gpointer result = mono_compile_method_checked (method, &error);
+ mono_error_cleanup (&error);
+ return result;
}
/**
* mono_compile_method:
* @method: The method to compile.
+ * @error: set on error.
*
* This JIT-compiles the method, and returns the pointer to the native code
- * produced.
+ * produced. On failure returns NULL and sets @error.
*/
-gpointer
-mono_compile_method (MonoMethod *method)
+gpointer
+mono_compile_method_checked (MonoMethod *method, MonoError *error)
{
+ gpointer res;
+
MONO_REQ_GC_NEUTRAL_MODE
- if (!default_mono_compile_method) {
+ mono_error_init (error);
+
+ if (!callbacks.compile_method) {
g_error ("compile method called on uninitialized runtime");
return NULL;
}
- return default_mono_compile_method (method);
+ res = callbacks.compile_method (method, error);
+ return res;
}
gpointer
-mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
+mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
{
- MONO_REQ_GC_NEUTRAL_MODE
+ gpointer res;
+
+ MONO_REQ_GC_NEUTRAL_MODE;
- return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
+ mono_error_init (error);
+ res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
+ return res;
}
gpointer
#endif
MonoString*
-mono_string_alloc (int length)
+ves_icall_string_alloc (int length)
{
- MONO_REQ_GC_UNSAFE_MODE;
- return mono_string_new_size (mono_domain_get (), length);
+ MonoError error;
+ MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
+ mono_error_set_pending_exception (&error);
+
+ return str;
}
void
if (!gcj_inited) {
mono_loader_lock ();
- mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
- mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
+ mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
+ mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
gcj_inited = TRUE;
mono_loader_unlock ();
{
MONO_REQ_GC_NEUTRAL_MODE;
+ MonoError error;
MonoCustomAttrInfo *ainfo;
int i;
- ainfo = mono_custom_attrs_from_field (fklass, field);
+ ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
+ mono_error_cleanup (&error); /* FIXME don't swallow the error? */
if (!ainfo)
return FALSE;
for (i = 0; i < ainfo->num_attrs; ++i) {
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));
for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
MonoMethod *method;
- if (slot_num >= 0 && iface->is_inflated) {
+ if (slot_num >= 0 && mono_class_is_ginst (iface)) {
/*
* The imt slot of the method is the same as for its declaring method,
* see the comment in mono_method_get_imt_slot (), so we can
* avoid inflating methods which will be discarded by
* add_imt_builder_entry anyway.
*/
- method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
+ method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
if (mono_method_get_imt_slot (method) != slot_num) {
vt_slot ++;
continue;
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;
- }
- }
-
- /* 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;
- }
+ static int generic_virtual_trampolines_size = 0;
- /* 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);
-
- 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]);
+ generic_virtual_trampolines_size += size;
- 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);
}
-static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error);
+static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
/**
* mono_class_vtable:
MonoVTable *
mono_class_vtable (MonoDomain *domain, MonoClass *klass)
{
- return mono_class_vtable_full (domain, klass, FALSE);
+ MonoError error;
+ MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
+ mono_error_cleanup (&error);
+ return vtable;
}
/**
* mono_class_vtable_full:
* @domain: the application domain
* @class: the class to initialize
- * @raise_on_error if an exception should be raised on failure or not
+ * @error set on failure.
*
* VTables are domain specific because we create domain specific code, and
* they contain the domain specific static class data.
*/
MonoVTable *
-mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
+mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
MonoClassRuntimeInfo *runtime_info;
+ mono_error_init (error);
+
g_assert (klass);
- if (klass->exception_type) {
- if (raise_on_error)
- mono_raise_exception (mono_class_get_exception_for_failure (klass));
+ if (mono_class_has_failure (klass)) {
+ mono_error_set_for_class_failure (error, klass);
return NULL;
}
runtime_info = klass->runtime_info;
if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
return runtime_info->domain_vtables [domain->domain_id];
- return mono_class_create_runtime_vtable (domain, klass, raise_on_error);
+ return mono_class_create_runtime_vtable (domain, klass, error);
}
/**
}
static MonoVTable *
-mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
+mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
gpointer iter;
gpointer *interface_offsets;
+ mono_error_init (error);
+
mono_loader_lock (); /*FIXME mono_class_init acquires it*/
mono_domain_lock (domain);
runtime_info = klass->runtime_info;
mono_loader_unlock ();
return runtime_info->domain_vtables [domain->domain_id];
}
- if (!klass->inited || klass->exception_type) {
- if (!mono_class_init (klass) || klass->exception_type) {
+ if (!klass->inited || mono_class_has_failure (klass)) {
+ if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
mono_domain_unlock (domain);
mono_loader_unlock ();
- if (raise_on_error)
- mono_raise_exception (mono_class_get_exception_for_failure (klass));
+ mono_error_set_for_class_failure (error, klass);
return NULL;
}
}
mono_class_init (element_class);
/*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
- if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
+ if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
mono_class_setup_vtable (element_class);
- if (element_class->exception_type != MONO_EXCEPTION_NONE) {
+ if (mono_class_has_failure (element_class)) {
/*Can happen if element_class only got bad after mono_class_setup_vtable*/
- if (klass->exception_type == MONO_EXCEPTION_NONE)
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ if (!mono_class_has_failure (klass))
+ mono_class_set_type_load_failure (klass, "");
mono_domain_unlock (domain);
mono_loader_unlock ();
- if (raise_on_error)
- mono_raise_exception (mono_class_get_exception_for_failure (klass));
+ mono_error_set_for_class_failure (error, klass);
return NULL;
}
}
if (!klass->vtable_size)
mono_class_setup_vtable (klass);
- if (klass->generic_class && !klass->vtable)
+ if (mono_class_is_ginst (klass) && !klass->vtable)
mono_class_check_vtable_constraints (klass, NULL);
/* Initialize klass->has_finalize */
mono_class_has_finalizer (klass);
- if (klass->exception_type) {
+ if (mono_class_has_failure (klass)) {
mono_domain_unlock (domain);
mono_loader_unlock ();
- if (raise_on_error)
- mono_raise_exception (mono_class_get_exception_for_failure (klass));
+ mono_error_set_for_class_failure (error, klass);
return NULL;
}
for (i = 0; i < klass->vtable_size; ++i) {
MonoMethod *cm;
- if ((cm = klass->vtable [i]))
- vt->vtable [i] = arch_create_jit_trampoline (cm);
+ cm = klass->vtable [i];
+ if (cm) {
+ vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
+ if (!is_ok (error)) {
+ mono_domain_unlock (domain);
+ mono_loader_unlock ();
+ return NULL;
+ }
+ }
}
}
* re-acquire them and check if another thread has created the vtable in the meantime.
*/
/* Special case System.MonoType to avoid infinite recursion */
- if (klass != mono_defaults.monotype_class) {
- /*FIXME check for OOM*/
- vt->type = mono_type_get_object (domain, &klass->byval_arg);
- if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
+ if (klass != mono_defaults.runtimetype_class) {
+ vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
+ if (!is_ok (error)) {
+ mono_domain_unlock (domain);
+ mono_loader_unlock ();
+ return NULL;
+ }
+
+ if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
/* This is unregistered in
unregister_vtable_reflection_type() in
domain.c. */
klass->runtime_info = runtime_info;
}
- if (klass == mono_defaults.monotype_class) {
- /*FIXME check for OOM*/
- vt->type = mono_type_get_object (domain, &klass->byval_arg);
- if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
+ if (klass == mono_defaults.runtimetype_class) {
+ vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
+ if (!is_ok (error)) {
+ mono_domain_unlock (domain);
+ mono_loader_unlock ();
+ return NULL;
+ }
+
+ if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
/* This is unregistered in
unregister_vtable_reflection_type() in
domain.c. */
/* make sure the parent is initialized */
/*FIXME shouldn't this fail the current type?*/
if (klass->parent)
- mono_class_vtable_full (domain, klass->parent, raise_on_error);
+ mono_class_vtable_full (domain, klass->parent, error);
return vt;
}
* mono_class_proxy_vtable:
* @domain: the application domain
* @remove_class: the remote class
+ * @error: set on error
*
* Creates a vtable for transparent proxies. It is basically
* a copy of the real vtable of the class wrapped in @remote_class,
* but all function pointers invoke the remoting functions, and
* vtable->klass points to the transparent proxy class, and not to @class.
+ *
+ * On failure returns NULL and sets @error
*/
static MonoVTable *
-mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
+mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
- MonoError error;
MonoVTable *vt, *pvt;
int i, j, vtsize, extra_interface_vtsize = 0;
guint32 max_interface_id;
GSList *extra_interfaces = NULL;
MonoClass *klass = remote_class->proxy_class;
gpointer *interface_offsets;
- uint8_t *bitmap;
+ uint8_t *bitmap = NULL;
int bsize;
size_t imt_table_bytes;
int bcsize;
#endif
+ mono_error_init (error);
+
vt = mono_class_vtable (domain, klass);
g_assert (vt); /*FIXME property handle failure*/
max_interface_id = vt->max_interface_id;
method_count = mono_class_num_methods (iclass);
- ifaces = mono_class_get_implemented_interfaces (iclass, &error);
- g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
+ ifaces = mono_class_get_implemented_interfaces (iclass, error);
+ if (!is_ok (error))
+ goto failure;
if (ifaces) {
for (i = 0; i < ifaces->len; ++i) {
MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
method_count += mono_class_num_methods (ic);
}
g_ptr_array_free (ifaces, TRUE);
+ ifaces = NULL;
}
extra_interface_vtsize += method_count * sizeof (gpointer);
for (i = 0; i < klass->vtable_size; ++i) {
MonoMethod *cm;
- if ((cm = klass->vtable [i]))
- pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
- else
+ if ((cm = klass->vtable [i])) {
+ pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type, error);
+ if (!is_ok (error))
+ goto failure;
+ } else
pvt->vtable [i] = NULL;
}
- if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
+ if (mono_class_is_abstract (klass)) {
/* create trampolines for abstract methods */
for (k = klass; k; k = k->parent) {
MonoMethod* m;
gpointer iter = NULL;
while ((m = mono_class_get_methods (k, &iter)))
- if (!pvt->vtable [m->slot])
- pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
+ if (!pvt->vtable [m->slot]) {
+ pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type, error);
+ if (!is_ok (error))
+ goto failure;
+ }
}
}
iter = NULL;
j = 0;
- while ((cm = mono_class_get_methods (interf, &iter)))
- pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
+ while ((cm = mono_class_get_methods (interf, &iter))) {
+ pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type, error);
+ if (!is_ok (error))
+ goto failure;
+ }
slot += mono_class_num_methods (interf);
}
pvt->interface_bitmap = bitmap;
#endif
return pvt;
+failure:
+ if (extra_interfaces)
+ g_slist_free (extra_interfaces);
+#ifdef COMPRESSED_INTERFACE_BITMAP
+ g_free (bitmap);
+#endif
+ return NULL;
}
#endif /* DISABLE_REMOTING */
int i, j;
if (remote_class == NULL) {
- if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
+ if (mono_class_is_interface (extra_class)) {
key = (void **)g_malloc (sizeof(gpointer) * 3);
key [0] = GINT_TO_POINTER (2);
key [1] = mono_defaults.marshalbyrefobject_class;
key [1] = extra_class;
}
} else {
- if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
+ if (extra_class != NULL && mono_class_is_interface (extra_class)) {
key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
key [1] = remote_class->proxy_class;
* mono_remote_class:
* @domain: the application domain
* @class_name: name of the remote class
+ * @error: set on error
*
* Creates and initializes a MonoRemoteClass object for a remote type.
*
- * Can raise an exception on failure.
+ * On failure returns NULL and sets @error
*/
MonoRemoteClass*
-mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
+mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
- MonoError error;
MonoRemoteClass *rc;
gpointer* key, *mp_key;
char *name;
+ mono_error_init (error);
+
key = create_remote_class_key (NULL, proxy_class);
mono_domain_lock (domain);
return rc;
}
- name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
- if (!mono_error_ok (&error)) {
+ name = mono_string_to_utf8_mp (domain->mp, class_name, error);
+ if (!is_ok (error)) {
g_free (key);
mono_domain_unlock (domain);
- mono_error_raise_exception (&error);
+ return NULL;
}
mp_key = copy_remote_class_key (domain, key);
g_free (key);
key = mp_key;
- if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
+ if (mono_class_is_interface (proxy_class)) {
rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
rc->interface_count = 1;
rc->interfaces [0] = proxy_class;
g_free (key);
key = mp_key;
- if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
+ if (mono_class_is_interface (extra_class)) {
int i,j;
rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
rc->proxy_class = remote_class->proxy_class;
}
gpointer
-mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
+mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
+ mono_error_init (error);
+
mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
mono_domain_lock (domain);
if (rp->target_domain_id != -1) {
if (remote_class->xdomain_vtable == NULL)
- remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
+ remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
mono_domain_unlock (domain);
mono_loader_unlock ();
+ return_val_if_nok (error, NULL);
return remote_class->xdomain_vtable;
}
if (remote_class->default_vtable == NULL) {
klass = mono_class_from_mono_type (type);
#ifndef DISABLE_COM
if ((mono_class_is_com_object (klass) || (mono_class_get_com_object_class () && klass == mono_class_get_com_object_class ())) && !mono_vtable_is_remote (mono_class_vtable (mono_domain_get (), klass)))
- remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
+ remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
else
#endif
- remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
+ remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
+ /* N.B. both branches of the if modify error */
+ if (!is_ok (error)) {
+ mono_domain_unlock (domain);
+ mono_loader_unlock ();
+ return NULL;
+ }
}
mono_domain_unlock (domain);
* @domain: the application domain
* @tproxy: the proxy whose remote class has to be upgraded.
* @klass: class to which the remote class can be casted.
+ * @error: set on error
*
* Updates the vtable of the remote class by adding the necessary method slots
* and interface offsets so it can be safely casted to klass. klass can be a
- * class or an interface.
+ * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
*/
-void
-mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
+gboolean
+mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
MonoRemoteClass *remote_class;
gboolean redo_vtable;
+ mono_error_init (error);
mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
mono_domain_lock (domain);
tproxy = (MonoTransparentProxy*) proxy_object;
remote_class = tproxy->remote_class;
- if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+ if (mono_class_is_interface (klass)) {
int i;
redo_vtable = TRUE;
for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
if (redo_vtable) {
tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
- proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
+ proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp, error);
+ if (!is_ok (error))
+ goto leave;
}
+leave:
mono_domain_unlock (domain);
mono_loader_unlock ();
+ return is_ok (error);
}
#endif /* DISABLE_REMOTING */
/* check method->slot is a valid index: perform isinstance? */
if (method->slot != -1) {
- if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+ if (mono_class_is_interface (method->klass)) {
if (!is_proxy) {
gboolean variance_used = FALSE;
int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
}
static MonoObject*
-dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
+do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
{
- g_error ("runtime invoke called on uninitialized runtime");
- return NULL;
-}
+ MONO_REQ_GC_UNSAFE_MODE;
+
+ MonoObject *result = NULL;
+
+ g_assert (callbacks.runtime_invoke);
-static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
+ mono_error_init (error);
+
+ if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
+ mono_profiler_method_start_invoke (method);
+
+ result = callbacks.runtime_invoke (method, obj, params, exc, error);
+
+ if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
+ mono_profiler_method_end_invoke (method);
+
+ if (!mono_error_ok (error))
+ return NULL;
+
+ return result;
+}
/**
* mono_runtime_invoke:
MonoObject*
mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
{
- MONO_REQ_GC_UNSAFE_MODE;
-
- MonoObject *result;
-
- if (mono_runtime_get_no_exec ())
- g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
-
- if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
- mono_profiler_method_start_invoke (method);
-
- result = default_mono_runtime_invoke (method, obj, params, exc);
-
- if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
- mono_profiler_method_end_invoke (method);
-
- return result;
+ MonoError error;
+ MonoObject *res;
+ if (exc) {
+ res = mono_runtime_try_invoke (method, obj, params, 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, obj, params, &error);
+ mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
+ }
+ return res;
}
/**
- * mono_method_get_unmanaged_thunk:
- * @method: method to generate a thunk for.
+ * mono_runtime_try_invoke:
+ * @method: method to invoke
+ * @obJ: object instance
+ * @params: arguments to the method
+ * @exc: exception information.
+ * @error: set on error
*
- * Returns an unmanaged->managed thunk that can be used to call
- * a managed method directly from C.
+ * Invokes the method represented by @method on the object @obj.
*
- * The thunk's C signature closely matches the managed signature:
+ * obj is the 'this' pointer, it should be NULL for static
+ * methods, a MonoObject* for object instances and a pointer to
+ * the value type for value types.
*
- * C#: public bool Equals (object obj);
+ * The params array contains the arguments to the method with the
+ * same convention: MonoObject* pointers for object instances and
+ * pointers to the value type otherwise.
+ *
+ * From unmanaged code you'll usually use the
+ * mono_runtime_invoke() variant.
+ *
+ * Note that this function doesn't handle virtual methods for
+ * you, it will exec the exact method you pass: we still need to
+ * expose a function to lookup the derived class implementation
+ * of a virtual method (there are examples of this in the code,
+ * though).
+ *
+ * For this function, you must not pass NULL as the exc argument if
+ * you don't want to catch exceptions, use
+ * mono_runtime_invoke_checked(). If an exception is thrown, you
+ * can't use the MonoObject* result from the function.
+ *
+ * If this method cannot be invoked, @error will be set and @exc and
+ * the return value must not be used.
+ *
+ * If the method returns a value type, it is boxed in an object
+ * reference.
+ */
+MonoObject*
+mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
+{
+ MONO_REQ_GC_UNSAFE_MODE;
+
+ g_assert (exc != NULL);
+
+ if (mono_runtime_get_no_exec ())
+ g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
+
+ return do_runtime_invoke (method, obj, params, exc, error);
+}
+
+/**
+ * mono_runtime_invoke_checked:
+ * @method: method to invoke
+ * @obJ: object instance
+ * @params: arguments to the method
+ * @error: set on error
+ *
+ * Invokes the method represented by @method on the object @obj.
+ *
+ * obj is the 'this' pointer, it should be NULL for static
+ * methods, a MonoObject* for object instances and a pointer to
+ * the value type for value types.
+ *
+ * The params array contains the arguments to the method with the
+ * same convention: MonoObject* pointers for object instances and
+ * pointers to the value type otherwise.
+ *
+ * From unmanaged code you'll usually use the
+ * mono_runtime_invoke() variant.
+ *
+ * Note that this function doesn't handle virtual methods for
+ * you, it will exec the exact method you pass: we still need to
+ * expose a function to lookup the derived class implementation
+ * of a virtual method (there are examples of this in the code,
+ * though).
+ *
+ * If an exception is thrown, you can't use the MonoObject* result
+ * from the function.
+ *
+ * If this method cannot be invoked, @error will be set. If the
+ * method throws an exception (and we're in coop mode) the exception
+ * will be set in @error.
+ *
+ * If the method returns a value type, it is boxed in an object
+ * reference.
+ */
+MonoObject*
+mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
+{
+ MONO_REQ_GC_UNSAFE_MODE;
+
+ if (mono_runtime_get_no_exec ())
+ g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
+
+ return do_runtime_invoke (method, obj, params, NULL, error);
+}
+
+/**
+ * mono_method_get_unmanaged_thunk:
+ * @method: method to generate a thunk for.
+ *
+ * Returns an unmanaged->managed thunk that can be used to call
+ * a managed method directly from C.
+ *
+ * The thunk's C signature closely matches the managed signature:
+ *
+ * C#: public bool Equals (object obj);
* C: typedef MonoBoolean (*Equals)(MonoObject*,
* MonoObject*, MonoException**);
*
MONO_REQ_GC_NEUTRAL_MODE;
MONO_REQ_API_ENTRYPOINT;
+ MonoError error;
gpointer res;
- MONO_PREPARE_RESET_BLOCKING;
+ g_assert (!mono_threads_is_coop_enabled ());
+
+ MONO_ENTER_GC_UNSAFE;
method = mono_marshal_get_thunk_invoke_wrapper (method);
- res = mono_compile_method (method);
- MONO_FINISH_RESET_BLOCKING;
+ res = mono_compile_method_checked (method, &error);
+ mono_error_cleanup (&error);
+ MONO_EXIT_GC_UNSAFE;
return res;
}
MonoObject *
mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
{
+ MonoError error;
+ MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
+ mono_error_assert_ok (&error);
+ return result;
+}
+
+/**
+ * mono_field_get_value_object_checked:
+ * @domain: domain where the object will be created (if boxing)
+ * @field: MonoClassField describing the field to fetch information from
+ * @obj: The object instance for the field.
+ * @error: Set on error.
+ *
+ * Returns: a new MonoObject with the value from the given field. If the
+ * field represents a value type, the value is boxed. On error returns NULL and sets @error.
+ *
+ */
+MonoObject *
+mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
+{
MONO_REQ_GC_UNSAFE_MODE;
+ mono_error_init (error);
+
MonoObject *o;
MonoClass *klass;
MonoVTable *vtable = NULL;
gboolean is_ref = FALSE;
gboolean is_literal = FALSE;
gboolean is_ptr = FALSE;
- MonoError error;
- MonoType *type = mono_field_get_type_checked (field, &error);
+ MonoType *type = mono_field_get_type_checked (field, error);
- if (!mono_error_ok (&error))
- mono_error_raise_exception (&error);
+ return_val_if_nok (error, NULL);
switch (type->type) {
case MONO_TYPE_STRING:
is_static = TRUE;
if (!is_literal) {
- vtable = mono_class_vtable_full (domain, field->parent, TRUE);
- if (!vtable->initialized)
- mono_runtime_class_init (vtable);
+ vtable = mono_class_vtable_full (domain, field->parent, error);
+ return_val_if_nok (error, NULL);
+
+ if (!vtable->initialized) {
+ mono_runtime_class_init_full (vtable, error);
+ return_val_if_nok (error, NULL);
+ }
}
} else {
g_assert (obj);
if (is_ref) {
if (is_literal) {
- get_default_field_value (domain, field, &o);
+ get_default_field_value (domain, field, &o, error);
+ return_val_if_nok (error, NULL);
} else if (is_static) {
- mono_field_static_get_value (vtable, field, &o);
+ mono_field_static_get_value_checked (vtable, field, &o, error);
+ return_val_if_nok (error, NULL);
} else {
mono_field_get_value (obj, field, &o);
}
gpointer v;
if (!m) {
- MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
+ MonoClass *ptr_klass = mono_class_get_pointer_class ();
m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
g_assert (m);
}
v = &ptr;
if (is_literal) {
- get_default_field_value (domain, field, v);
+ get_default_field_value (domain, field, v, error);
+ return_val_if_nok (error, NULL);
} else if (is_static) {
- mono_field_static_get_value (vtable, field, v);
+ mono_field_static_get_value_checked (vtable, field, v, error);
+ return_val_if_nok (error, NULL);
} else {
mono_field_get_value (obj, field, v);
}
/* MONO_TYPE_PTR is passed by value to runtime_invoke () */
args [0] = ptr ? *ptr : NULL;
- args [1] = mono_type_get_object (mono_domain_get (), type);
+ args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
+ return_val_if_nok (error, NULL);
+
+ o = mono_runtime_invoke_checked (m, NULL, args, error);
+ return_val_if_nok (error, NULL);
- return mono_runtime_invoke (m, NULL, args, NULL);
+ return o;
}
/* boxed value type */
klass = mono_class_from_mono_type (type);
if (mono_class_is_nullable (klass))
- return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
+ return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
- o = mono_object_new (domain, klass);
+ o = mono_object_new_checked (domain, klass, error);
+ return_val_if_nok (error, NULL);
v = ((gchar *) o) + sizeof (MonoObject);
if (is_literal) {
- get_default_field_value (domain, field, v);
+ get_default_field_value (domain, field, v, error);
+ return_val_if_nok (error, NULL);
} else if (is_static) {
- mono_field_static_get_value (vtable, field, v);
+ mono_field_static_get_value_checked (vtable, field, v, error);
+ return_val_if_nok (error, NULL);
} else {
mono_field_get_value (obj, field, v);
}
}
int
-mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
+mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
+ mono_error_init (error);
int retval = 0;
const char *p = blob;
mono_metadata_decode_blob_size (p, &p);
readr8 (p, (double*) value);
break;
case MONO_TYPE_STRING:
- *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
+ *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
break;
case MONO_TYPE_CLASS:
*(gpointer*) value = NULL;
}
static void
-get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
+get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
{
MONO_REQ_GC_NEUTRAL_MODE;
MonoTypeEnum def_type;
const char* data;
+
+ mono_error_init (error);
data = mono_class_get_field_default_value (field, &def_type);
- mono_get_constant_value_from_blob (domain, def_type, data, value);
+ mono_get_constant_value_from_blob (domain, def_type, data, value, error);
}
void
-mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
+mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
void *src;
+ mono_error_init (error);
+
g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
- get_default_field_value (vt->domain, field, value);
+ get_default_field_value (vt->domain, field, value, error);
return;
}
{
MONO_REQ_GC_NEUTRAL_MODE;
- mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
+ MonoError error;
+ mono_field_static_get_value_checked (vt, field, value, &error);
+ mono_error_cleanup (&error);
+}
+
+/**
+ * mono_field_static_get_value_checked:
+ * @vt: vtable to the object
+ * @field: MonoClassField describing the field to fetch information from
+ * @value: where the value is returned
+ * @error: set on error
+ *
+ * Use this routine to get the value of the static field @field value.
+ *
+ * The pointer provided by value must be of the field type, for reference
+ * types this is a MonoObject*, for value types its the actual pointer to
+ * the value type.
+ *
+ * For example:
+ * int i;
+ * mono_field_static_get_value_checked (vt, int_field, &i, error);
+ * if (!is_ok (error)) { ... }
+ *
+ * On failure sets @error.
+ */
+void
+mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
+{
+ MONO_REQ_GC_NEUTRAL_MODE;
+
+ mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
}
/**
{
MONO_REQ_GC_UNSAFE_MODE;
- default_mono_runtime_invoke (prop->set, obj, params, exc);
+ MonoError error;
+ do_runtime_invoke (prop->set, obj, params, exc, &error);
+ if (exc && *exc == NULL && !mono_error_ok (&error)) {
+ *exc = (MonoObject*) mono_error_convert_to_exception (&error);
+ } else {
+ mono_error_cleanup (&error);
+ }
+}
+
+/**
+ * mono_property_set_value_checked:
+ * @prop: MonoProperty to set
+ * @obj: instance object on which to act
+ * @params: parameters to pass to the propery
+ * @error: set on error
+ *
+ * Invokes the property's set method with the given arguments on the
+ * object instance obj (or NULL for static properties).
+ *
+ * Returns: TRUE on success. On failure returns FALSE and sets @error.
+ * If an exception is thrown, it will be caught and returned via @error.
+ */
+gboolean
+mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
+{
+ MONO_REQ_GC_UNSAFE_MODE;
+
+ MonoObject *exc;
+
+ mono_error_init (error);
+ do_runtime_invoke (prop->set, obj, params, &exc, error);
+ if (exc != NULL && is_ok (error))
+ mono_error_set_exception_instance (error, (MonoException*)exc);
+ return is_ok (error);
}
/**
{
MONO_REQ_GC_UNSAFE_MODE;
- return default_mono_runtime_invoke (prop->get, obj, params, exc);
+ MonoError error;
+ MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
+ if (exc && *exc == NULL && !mono_error_ok (&error)) {
+ *exc = (MonoObject*) mono_error_convert_to_exception (&error);
+ } else {
+ mono_error_cleanup (&error); /* FIXME don't raise here */
+ }
+
+ return val;
+}
+
+/**
+ * mono_property_get_value_checked:
+ * @prop: MonoProperty to fetch
+ * @obj: instance object on which to act
+ * @params: parameters to pass to the propery
+ * @error: set on error
+ *
+ * Invokes the property's get method with the given arguments on the
+ * object instance obj (or NULL for static properties).
+ *
+ * If an exception is thrown, you can't use the
+ * MonoObject* result from the function. The exception will be propagated via @error.
+ *
+ * Returns: the value from invoking the get method on the property. On
+ * failure returns NULL and sets @error.
+ */
+MonoObject*
+mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
+{
+ MONO_REQ_GC_UNSAFE_MODE;
+
+ MonoObject *exc;
+ MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
+ if (exc != NULL && !is_ok (error))
+ mono_error_set_exception_instance (error, (MonoException*) exc);
+ if (!is_ok (error))
+ val = NULL;
+ return val;
}
+
/*
* mono_nullable_init:
* @buf: The nullable structure to initialize.
MonoClass *param_class = klass->cast_class;
- mono_class_setup_fields_locking (klass);
+ mono_class_setup_fields (klass);
g_assert (klass->fields_inited);
g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
* mono_nullable_box:
* @buf: The buffer representing the data to be boxed
* @klass: the type to box it as.
+ * @error: set on oerr
*
* Creates a boxed vtype or NULL from the Nullable structure pointed to by
- * @buf.
+ * @buf. On failure returns NULL and sets @error
*/
MonoObject*
-mono_nullable_box (guint8 *buf, MonoClass *klass)
+mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
+ mono_error_init (error);
MonoClass *param_class = klass->cast_class;
- mono_class_setup_fields_locking (klass);
+ mono_class_setup_fields (klass);
g_assert (klass->fields_inited);
g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
- MonoObject *o = mono_object_new (mono_domain_get (), param_class);
+ MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
+ return_val_if_nok (error, NULL);
if (param_class->has_references)
mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
else
/* This is called at runtime, so avoid the slower search in metadata */
mono_class_setup_methods (klass);
- if (klass->exception_type)
+ if (mono_class_has_failure (klass))
return NULL;
im = mono_class_get_method_from_name (klass, "Invoke", -1);
return im;
/* This is called at runtime, so avoid the slower search in metadata */
mono_class_setup_methods (klass);
- if (klass->exception_type)
+ if (mono_class_has_failure (klass))
return NULL;
im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
return im;
/* This is called at runtime, so avoid the slower search in metadata */
mono_class_setup_methods (klass);
- if (klass->exception_type)
+ if (mono_class_has_failure (klass))
return NULL;
im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
return im;
{
MONO_REQ_GC_UNSAFE_MODE;
+ MonoError error;
+ if (exc) {
+ MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
+ if (*exc) {
+ mono_error_cleanup (&error);
+ return NULL;
+ } else {
+ if (!is_ok (&error))
+ *exc = (MonoObject*)mono_error_convert_to_exception (&error);
+ return result;
+ }
+ } else {
+ MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
+ mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
+ return result;
+ }
+}
+
+/**
+ * mono_runtime_delegate_try_invoke:
+ * @delegate: pointer to a delegate object.
+ * @params: parameters for the delegate.
+ * @exc: Pointer to the exception result.
+ * @error: set on error
+ *
+ * Invokes the delegate method @delegate with the parameters provided.
+ *
+ * You can pass NULL as the exc argument if you don't want to
+ * catch exceptions, otherwise, *exc will be set to the exception
+ * thrown, if any. On failure to execute, @error will be set.
+ * if an exception is thrown, you can't use the
+ * MonoObject* result from the function.
+ */
+MonoObject*
+mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
+{
+ MONO_REQ_GC_UNSAFE_MODE;
+
+ mono_error_init (error);
MonoMethod *im;
MonoClass *klass = delegate->vtable->klass;
+ MonoObject *o;
im = mono_get_delegate_invoke (klass);
if (!im)
g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
- return mono_runtime_invoke (im, delegate, params, exc);
+ if (exc) {
+ o = mono_runtime_try_invoke (im, delegate, params, exc, error);
+ } else {
+ o = mono_runtime_invoke_checked (im, delegate, params, error);
+ }
+
+ return o;
+}
+
+/**
+ * mono_runtime_delegate_invoke_checked:
+ * @delegate: pointer to a delegate object.
+ * @params: parameters for the delegate.
+ * @error: set on error
+ *
+ * Invokes the delegate method @delegate with the parameters provided.
+ *
+ * On failure @error will be set and you can't use the MonoObject*
+ * result from the function.
+ */
+MonoObject*
+mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
+{
+ mono_error_init (error);
+ return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
}
static char **main_args = NULL;
mono_runtime_get_main_args (void)
{
MONO_REQ_GC_UNSAFE_MODE;
+ MonoError error;
+ MonoArray *result = mono_runtime_get_main_args_checked (&error);
+ mono_error_assert_ok (&error);
+ return result;
+}
+/**
+ * mono_runtime_get_main_args:
+ * @error: set on error
+ *
+ * Returns: a MonoArray with the arguments passed to the main
+ * program. On failure returns NULL and sets @error.
+ */
+MonoArray*
+mono_runtime_get_main_args_checked (MonoError *error)
+{
MonoArray *res;
int i;
MonoDomain *domain = mono_domain_get ();
- res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
+ mono_error_init (error);
+
+ res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
+ return_val_if_nok (error, NULL);
for (i = 0; i < num_main_args; ++i)
mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
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;
+ MonoError error;
int i;
MonoArray *args = NULL;
MonoDomain *domain = mono_domain_get ();
}
if (sig->param_count) {
- args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
+ args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
+ mono_error_assert_ok (&error);
for (i = 0; i < argc; ++i) {
/* The encodings should all work, given that
* we've checked all these args for the
g_free (str);
}
} else {
- args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
+ args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
+ mono_error_assert_ok (&error);
}
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)
-{
- static MonoMethod *serialize_method;
-
- void *params [1];
- MonoObject *array;
-
- if (!serialize_method) {
- MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
- serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
- }
-
- if (!serialize_method) {
- *failure = TRUE;
- return NULL;
- }
+
+static MonoObject*
+serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
+{
+ static MonoMethod *serialize_method;
+
+ MonoError error;
+ void *params [1];
+ MonoObject *array;
+
+ if (!serialize_method) {
+ MonoClass *klass = mono_class_get_remoting_services_class ();
+ serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
+ }
+
+ if (!serialize_method) {
+ *failure = TRUE;
+ return NULL;
+ }
g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
params [0] = obj;
*exc = NULL;
- array = mono_runtime_invoke (serialize_method, NULL, params, exc);
+
+ array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
+ if (*exc == NULL && !mono_error_ok (&error))
+ *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
+ else
+ mono_error_cleanup (&error);
+
if (*exc)
*failure = TRUE;
static MonoMethod *deserialize_method;
+ MonoError error;
void *params [1];
MonoObject *result;
if (!deserialize_method) {
- MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
+ MonoClass *klass = mono_class_get_remoting_services_class ();
deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
}
if (!deserialize_method) {
params [0] = obj;
*exc = NULL;
- result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
+
+ result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
+ if (*exc == NULL && !mono_error_ok (&error))
+ *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
+ else
+ mono_error_cleanup (&error);
+
if (*exc)
*failure = TRUE;
#ifndef DISABLE_REMOTING
static MonoObject*
-make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
+make_transparent_proxy (MonoObject *obj, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
MonoReflectionType *reflection_type;
MonoTransparentProxy *transparent_proxy;
+ mono_error_init (error);
+
if (!get_proxy_method)
get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
- real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
- reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
+ real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
+ return_val_if_nok (error, NULL);
+ reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
+ return_val_if_nok (error, NULL);
MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
- *exc = NULL;
- transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
- if (*exc)
- *failure = TRUE;
+ MonoObject *exc = NULL;
+
+ transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
+ if (exc != NULL && is_ok (error))
+ mono_error_set_exception_instance (error, (MonoException*)exc);
return (MonoObject*) transparent_proxy;
}
* mono_object_xdomain_representation
* @obj: an object
* @target_domain: a domain
- * @exc: pointer to a MonoObject*
+ * @error: set on error.
*
* Creates a representation of obj in the domain target_domain. This
* is either a copy of obj arrived through via serialization and
* serializable or marshal by ref. obj must not be in target_domain.
*
* If the object cannot be represented in target_domain, NULL is
- * returned and *exc is set to an appropriate exception.
+ * returned and @error is set appropriately.
*/
MonoObject*
-mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
+mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
+ mono_error_init (error);
MonoObject *deserialized = NULL;
- gboolean failure = FALSE;
-
- *exc = NULL;
#ifndef DISABLE_REMOTING
if (mono_class_is_marshalbyref (mono_object_class (obj))) {
- deserialized = make_transparent_proxy (obj, &failure, exc);
+ deserialized = make_transparent_proxy (obj, error);
}
else
#endif
{
+ gboolean failure = FALSE;
MonoDomain *domain = mono_domain_get ();
MonoObject *serialized;
+ MonoObject *exc = NULL;
mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
- serialized = serialize_object (obj, &failure, exc);
+ serialized = serialize_object (obj, &failure, &exc);
mono_domain_set_internal_with_options (target_domain, FALSE);
if (!failure)
- deserialized = deserialize_object (serialized, &failure, exc);
+ deserialized = deserialize_object (serialized, &failure, &exc);
if (domain != target_domain)
mono_domain_set_internal_with_options (domain, FALSE);
+ if (failure)
+ mono_error_set_exception_instance (error, (MonoException*)exc);
}
return deserialized;
/* Used in call_unhandled_exception_delegate */
static MonoObject *
-create_unhandled_exception_eventargs (MonoObject *exc)
+create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
+ mono_error_init (error);
MonoClass *klass;
gpointer args [2];
MonoMethod *method = NULL;
MonoBoolean is_terminating = TRUE;
MonoObject *obj;
- klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
- g_assert (klass);
-
+ klass = mono_class_get_unhandled_exception_event_args_class ();
mono_class_init (klass);
/* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
args [0] = exc;
args [1] = &is_terminating;
- obj = mono_object_new (mono_domain_get (), klass);
- mono_runtime_invoke (method, obj, args, NULL);
+ obj = mono_object_new_checked (mono_domain_get (), klass, error);
+ return_val_if_nok (error, NULL);
+
+ mono_runtime_invoke_checked (method, obj, args, error);
+ return_val_if_nok (error, NULL);
return obj;
}
call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
MONO_REQ_GC_UNSAFE_MODE;
+ MonoError error;
MonoObject *e = NULL;
gpointer pa [2];
MonoDomain *current_domain = mono_domain_get ();
g_assert (domain == mono_object_domain (domain->domain));
if (mono_object_domain (exc) != domain) {
- MonoObject *serialization_exc;
- exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
+ exc = mono_object_xdomain_representation (exc, domain, &error);
if (!exc) {
- if (serialization_exc) {
- MonoObject *dummy;
- exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
- g_assert (exc);
+ if (!is_ok (&error)) {
+ MonoError inner_error;
+ MonoException *serialization_exc = mono_error_convert_to_exception (&error);
+ exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
+ mono_error_assert_ok (&inner_error);
} else {
exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
"System.Runtime.Serialization", "SerializationException",
g_assert (mono_object_domain (exc) == domain);
pa [0] = domain->domain;
- pa [1] = create_unhandled_exception_eventargs (exc);
- mono_runtime_delegate_invoke (delegate, pa, &e);
+ pa [1] = create_unhandled_exception_eventargs (exc, &error);
+ mono_error_assert_ok (&error);
+ mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
+ if (!is_ok (&error)) {
+ if (e == NULL)
+ e = (MonoObject*)mono_error_convert_to_exception (&error);
+ else
+ mono_error_cleanup (&error);
+ }
if (domain != current_domain)
mono_domain_set_internal_with_options (current_domain, FALSE);
if (e) {
- MonoError error;
gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
if (!mono_error_ok (&error)) {
g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
{
MONO_REQ_GC_UNSAFE_MODE;
+ MonoError error;
MonoClassField *field;
MonoDomain *current_domain, *root_domain;
MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
current_domain = mono_domain_get ();
root_domain = mono_get_root_domain ();
- root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
- if (current_domain != root_domain)
- current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
+ root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
+ mono_error_assert_ok (&error);
+ if (current_domain != root_domain) {
+ current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
+ mono_error_assert_ok (&error);
+ }
- /* set exitcode only if we will abort the process */
if (!current_appdomain_delegate && !root_appdomain_delegate) {
- if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
- || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
- {
- mono_environment_exitcode_set (1);
- }
-
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 */
+ if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
+ || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
+ {
+ mono_environment_exitcode_set (1);
}
}
MonoMainThreadFunc main_func,
gpointer main_args)
{
- mono_thread_create (domain, main_func, main_args);
+ MonoError error;
+ mono_thread_create_checked (domain, main_func, main_args, &error);
+ mono_error_assert_ok (&error);
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;
-
- 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;
str = g_strconcat (assembly->image->name, ".config", NULL);
MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
g_free (str);
- mono_set_private_bin_path_from_config (domain);
+ mono_domain_set_options_from_config (domain);
}
}
- cinfo = mono_custom_attrs_from_method (method);
+ MonoError cattr_error;
+ cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
+ mono_error_cleanup (&cattr_error); /* FIXME warn here? */
if (cinfo) {
- static MonoClass *stathread_attribute = NULL;
- if (!stathread_attribute)
- stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
- has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
+ has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
if (!cinfo->cached)
mono_custom_attrs_free (cinfo);
} else {
}
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;
+ 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;
+
/* FIXME: check signature of method */
if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
+ MonoError inner_error;
MonoObject *res;
- res = mono_runtime_invoke (method, NULL, pa, exc);
- if (!exc || !*exc)
+ 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 {
- mono_runtime_invoke (method, NULL, pa, exc);
- if (!exc || !*exc)
+ 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 == NULL)
rval = 0;
else {
/* If the return type of Main is void, only
return rval;
}
-/**
- * mono_install_runtime_invoke:
- * @func: Function to install
- *
- * This is a VM internal routine
+/*
+ * Execute a standard Main() method (args doesn't contain the
+ * executable name).
*/
-void
-mono_install_runtime_invoke (MonoInvokeFunc func)
+int
+mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
{
- default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
+ 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;
+ }
}
-
-/**
- * mono_runtime_invoke_array:
- * @method: method to invoke
- * @obJ: object instance
- * @params: arguments to the method
- * @exc: exception information.
- *
- * Invokes the method represented by @method on the object @obj.
- *
- * obj is the 'this' pointer, it should be NULL for static
- * methods, a MonoObject* for object instances and a pointer to
- * the value type for value types.
+/*
+ * Execute a standard Main() method (args doesn't contain the
+ * executable name).
*
- * The params array contains the arguments to the method with the
- * same convention: MonoObject* pointers for object instances and
- * pointers to the value type otherwise. The _invoke_array
- * variant takes a C# object[] as the params argument (MonoArray
- * *params): in this case the value types are boxed inside the
- * respective reference representation.
- *
- * From unmanaged code you'll usually use the
- * mono_runtime_invoke() variant.
+ * 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).
*
- * Note that this function doesn't handle virtual methods for
- * you, it will exec the exact method you pass: we still need to
- * expose a function to lookup the derived class implementation
- * of a virtual method (there are examples of this in the code,
- * though).
- *
- * You can pass NULL as the exc argument if you don't want to
- * catch exceptions, otherwise, *exc will be set to the exception
- * thrown, if any. if an exception is thrown, you can't use the
- * MonoObject* result from the function.
- *
- * If the method returns a value type, it is boxed in an object
- * reference.
+ * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
*/
-MonoObject*
-mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
- MonoObject **exc)
+int
+mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
{
- MONO_REQ_GC_UNSAFE_MODE;
+ prepare_thread_to_exec_main (mono_object_domain (args), method);
+ return do_try_exec_main (method, args, exc);
+}
- MonoMethodSignature *sig = mono_method_signature (method);
- gpointer *pa = NULL;
- MonoObject *res;
- int i;
- gboolean has_byref_nullables = FALSE;
- if (NULL != params) {
- pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
- for (i = 0; i < mono_array_length (params); i++) {
- MonoType *t = sig->params [i];
+/** invoke_array_extract_argument:
+ * @params: array of arguments to the method.
+ * @i: the index of the argument to extract.
+ * @t: ith type from the method signature.
+ * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
+ * @error: set on error.
+ *
+ * Given an array of method arguments, return the ith one using the corresponding type
+ * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
+ *
+ * On failure sets @error and returns NULL.
+ */
+static gpointer
+invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
+{
+ MonoType *t_orig = t;
+ gpointer result = NULL;
+ mono_error_init (error);
again:
switch (t->type) {
case MONO_TYPE_U1:
case MONO_TYPE_R4:
case MONO_TYPE_R8:
case MONO_TYPE_VALUETYPE:
- if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
+ if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
/* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
- pa [i] = mono_array_get (params, MonoObject*, i);
+ result = mono_array_get (params, MonoObject*, i);
if (t->byref)
- has_byref_nullables = TRUE;
+ *has_byref_nullables = TRUE;
} else {
/* MS seems to create the objects if a null is passed in */
- if (!mono_array_get (params, MonoObject*, i))
- mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
+ if (!mono_array_get (params, MonoObject*, i)) {
+ MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
+ return_val_if_nok (error, NULL);
+ mono_array_setref (params, i, o);
+ }
if (t->byref) {
/*
* boxed object in the arg array with the copy.
*/
MonoObject *orig = mono_array_get (params, MonoObject*, i);
- MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
+ MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
+ return_val_if_nok (error, NULL);
mono_array_setref (params, i, copy);
}
- pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
+ result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
}
break;
case MONO_TYPE_STRING:
case MONO_TYPE_ARRAY:
case MONO_TYPE_SZARRAY:
if (t->byref)
- pa [i] = mono_array_addr (params, MonoObject*, i);
+ result = mono_array_addr (params, MonoObject*, i);
// FIXME: I need to check this code path
else
- pa [i] = mono_array_get (params, MonoObject*, i);
+ result = mono_array_get (params, MonoObject*, i);
break;
case MONO_TYPE_GENERICINST:
if (t->byref)
/* The argument should be an IntPtr */
arg = mono_array_get (params, MonoObject*, i);
if (arg == NULL) {
- pa [i] = NULL;
+ result = NULL;
} else {
g_assert (arg->vtable->klass == mono_defaults.int_class);
- pa [i] = ((MonoIntPtr*)arg)->m_value;
+ result = ((MonoIntPtr*)arg)->m_value;
}
break;
}
default:
- g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
+ g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
}
+ return result;
+}
+/**
+ * mono_runtime_invoke_array:
+ * @method: method to invoke
+ * @obJ: object instance
+ * @params: arguments to the method
+ * @exc: exception information.
+ *
+ * Invokes the method represented by @method on the object @obj.
+ *
+ * obj is the 'this' pointer, it should be NULL for static
+ * methods, a MonoObject* for object instances and a pointer to
+ * the value type for value types.
+ *
+ * The params array contains the arguments to the method with the
+ * same convention: MonoObject* pointers for object instances and
+ * pointers to the value type otherwise. The _invoke_array
+ * variant takes a C# object[] as the params argument (MonoArray
+ * *params): in this case the value types are boxed inside the
+ * respective reference representation.
+ *
+ * From unmanaged code you'll usually use the
+ * mono_runtime_invoke_checked() variant.
+ *
+ * Note that this function doesn't handle virtual methods for
+ * you, it will exec the exact method you pass: we still need to
+ * expose a function to lookup the derived class implementation
+ * of a virtual method (there are examples of this in the code,
+ * though).
+ *
+ * You can pass NULL as the exc argument if you don't want to
+ * catch exceptions, otherwise, *exc will be set to the exception
+ * thrown, if any. if an exception is thrown, you can't use the
+ * MonoObject* result from the function.
+ *
+ * If the method returns a value type, it is boxed in an object
+ * reference.
+ */
+MonoObject*
+mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
+ MonoObject **exc)
+{
+ MonoError error;
+ if (exc) {
+ MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
+ if (*exc) {
+ mono_error_cleanup (&error);
+ return NULL;
+ } else {
+ if (!is_ok (&error))
+ *exc = (MonoObject*)mono_error_convert_to_exception (&error);
+ return result;
+ }
+ } else {
+ MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
+ mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
+ return result;
+ }
+}
+
+/**
+ * mono_runtime_invoke_array_checked:
+ * @method: method to invoke
+ * @obJ: object instance
+ * @params: arguments to the method
+ * @error: set on failure.
+ *
+ * Invokes the method represented by @method on the object @obj.
+ *
+ * obj is the 'this' pointer, it should be NULL for static
+ * methods, a MonoObject* for object instances and a pointer to
+ * the value type for value types.
+ *
+ * The params array contains the arguments to the method with the
+ * same convention: MonoObject* pointers for object instances and
+ * pointers to the value type otherwise. The _invoke_array
+ * variant takes a C# object[] as the params argument (MonoArray
+ * *params): in this case the value types are boxed inside the
+ * respective reference representation.
+ *
+ * From unmanaged code you'll usually use the
+ * mono_runtime_invoke_checked() variant.
+ *
+ * Note that this function doesn't handle virtual methods for
+ * you, it will exec the exact method you pass: we still need to
+ * expose a function to lookup the derived class implementation
+ * of a virtual method (there are examples of this in the code,
+ * though).
+ *
+ * On failure or exception, @error will be set. In that case, you
+ * can't use the MonoObject* result from the function.
+ *
+ * If the method returns a value type, it is boxed in an object
+ * reference.
+ */
+MonoObject*
+mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
+ MonoError *error)
+{
+ mono_error_init (error);
+ return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
+}
+
+/**
+ * mono_runtime_try_invoke_array:
+ * @method: method to invoke
+ * @obJ: object instance
+ * @params: arguments to the method
+ * @exc: exception information.
+ * @error: set on failure.
+ *
+ * Invokes the method represented by @method on the object @obj.
+ *
+ * obj is the 'this' pointer, it should be NULL for static
+ * methods, a MonoObject* for object instances and a pointer to
+ * the value type for value types.
+ *
+ * The params array contains the arguments to the method with the
+ * same convention: MonoObject* pointers for object instances and
+ * pointers to the value type otherwise. The _invoke_array
+ * variant takes a C# object[] as the params argument (MonoArray
+ * *params): in this case the value types are boxed inside the
+ * respective reference representation.
+ *
+ * From unmanaged code you'll usually use the
+ * mono_runtime_invoke_checked() variant.
+ *
+ * Note that this function doesn't handle virtual methods for
+ * you, it will exec the exact method you pass: we still need to
+ * expose a function to lookup the derived class implementation
+ * of a virtual method (there are examples of this in the code,
+ * though).
+ *
+ * You can pass NULL as the exc argument if you don't want to catch
+ * exceptions, otherwise, *exc will be set to the exception thrown, if
+ * any. On other failures, @error will be set. If an exception is
+ * thrown or there's an error, you can't use the MonoObject* result
+ * from the function.
+ *
+ * If the method returns a value type, it is boxed in an object
+ * reference.
+ */
+MonoObject*
+mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
+ MonoObject **exc, MonoError *error)
+{
+ MONO_REQ_GC_UNSAFE_MODE;
+
+ mono_error_init (error);
+
+ MonoMethodSignature *sig = mono_method_signature (method);
+ gpointer *pa = NULL;
+ MonoObject *res;
+ int i;
+ gboolean has_byref_nullables = FALSE;
+
+ if (NULL != params) {
+ pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
+ for (i = 0; i < mono_array_length (params); i++) {
+ MonoType *t = sig->params [i];
+ pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
+ return_val_if_nok (error, NULL);
}
}
if (!params)
return NULL;
- else
- return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
+ else {
+ return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
+ }
}
if (!obj) {
- obj = mono_object_new (mono_domain_get (), method->klass);
+ obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
+ mono_error_assert_ok (error);
g_assert (obj); /*maybe we should raise a TLE instead?*/
#ifndef DISABLE_REMOTING
if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
else
o = obj;
} else if (method->klass->valuetype) {
- obj = mono_value_box (mono_domain_get (), method->klass, obj);
+ obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
+ return_val_if_nok (error, NULL);
+ }
+
+ if (exc) {
+ mono_runtime_try_invoke (method, o, pa, exc, error);
+ } else {
+ mono_runtime_invoke_checked (method, o, pa, error);
}
- mono_runtime_invoke (method, o, pa, exc);
return (MonoObject *)obj;
} else {
if (mono_class_is_nullable (method->klass)) {
MonoObject *nullable;
/* Convert the unboxed vtype into a Nullable structure */
- nullable = mono_object_new (mono_domain_get (), method->klass);
+ nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
+ return_val_if_nok (error, NULL);
- mono_nullable_init ((guint8 *)mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
+ MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
+ return_val_if_nok (error, NULL);
+ mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
obj = mono_object_unbox (nullable);
}
/* obj must be already unboxed if needed */
- res = mono_runtime_invoke (method, obj, pa, exc);
+ if (exc) {
+ res = mono_runtime_try_invoke (method, obj, pa, exc, error);
+ } else {
+ res = mono_runtime_invoke_checked (method, obj, pa, error);
+ }
+ return_val_if_nok (error, NULL);
if (sig->ret->type == MONO_TYPE_PTR) {
MonoClass *pointer_class;
* The runtime-invoke wrapper returns a boxed IntPtr, need to
* convert it to a Pointer object.
*/
- pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
+ pointer_class = mono_class_get_pointer_class ();
if (!box_method)
box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
g_assert (res->vtable->klass == mono_defaults.int_class);
box_args [0] = ((MonoIntPtr*)res)->m_value;
- box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
- res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
- g_assert (!box_exc);
+ box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
+ return_val_if_nok (error, NULL);
+
+ res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
+ g_assert (box_exc == NULL);
+ mono_error_assert_ok (error);
}
if (has_byref_nullables) {
}
}
-static void
-arith_overflow (void)
+/**
+ * mono_object_new:
+ * @klass: the class of the object that we want to create
+ *
+ * Returns: a newly created object whose definition is
+ * looked up using @klass. This will not invoke any constructors,
+ * so the consumer of this routine has to invoke any constructors on
+ * its own to initialize the object.
+ *
+ * It returns NULL on failure.
+ */
+MonoObject *
+mono_object_new (MonoDomain *domain, MonoClass *klass)
{
MONO_REQ_GC_UNSAFE_MODE;
- mono_raise_exception (mono_get_exception_overflow ());
+ MonoError error;
+
+ MonoObject * result = mono_object_new_checked (domain, klass, &error);
+
+ mono_error_cleanup (&error);
+ return result;
+}
+
+MonoObject *
+ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
+{
+ MONO_REQ_GC_UNSAFE_MODE;
+
+ MonoError error;
+
+ MonoObject * result = mono_object_new_checked (domain, klass, &error);
+
+ mono_error_set_pending_exception (&error);
+ return result;
}
/**
- * mono_object_new:
+ * mono_object_new_checked:
* @klass: the class of the object that we want to create
+ * @error: set on error
*
* Returns: a newly created object whose definition is
- * looked up using @klass. This will not invoke any constructors,
+ * looked up using @klass. This will not invoke any constructors,
* so the consumer of this routine has to invoke any constructors on
* its own to initialize the object.
- *
- * It returns NULL on failure.
+ *
+ * It returns NULL on failure and sets @error.
*/
MonoObject *
-mono_object_new (MonoDomain *domain, MonoClass *klass)
+mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
MonoVTable *vtable;
vtable = mono_class_vtable (domain, klass);
- if (!vtable)
- return NULL;
- return mono_object_new_specific (vtable);
+ g_assert (vtable); /* FIXME don't swallow the error */
+
+ MonoObject *o = mono_object_new_specific_checked (vtable, error);
+ return o;
}
/**
* For SGEN, these objects will only be freed at appdomain unload.
*/
MonoObject *
-mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
+mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
MonoVTable *vtable;
+ mono_error_init (error);
+
vtable = mono_class_vtable (domain, klass);
- if (!vtable)
- return NULL;
+ g_assert (vtable); /* FIXME don't swallow the error */
-#ifdef HAVE_SGEN_GC
- return (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
-#else
- return mono_object_new_specific (vtable);
-#endif
+ MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
+
+ if (G_UNLIKELY (!o))
+ mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
+ else if (G_UNLIKELY (vtable->klass->has_finalize))
+ mono_object_register_finalizer (o);
+
+ return o;
}
/**
*/
MonoObject *
mono_object_new_specific (MonoVTable *vtable)
+{
+ MonoError error;
+ MonoObject *o = mono_object_new_specific_checked (vtable, &error);
+ mono_error_cleanup (&error);
+
+ return o;
+}
+
+MonoObject *
+mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
MonoObject *o;
+ mono_error_init (error);
+
/* check for is_com_object for COM Interop */
if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
{
MonoMethod *im = vtable->domain->create_proxy_for_type_method;
if (im == NULL) {
- MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
+ MonoClass *klass = mono_class_get_activation_services_class ();
if (!klass->inited)
mono_class_init (klass);
im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
- if (!im)
- mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
+ if (!im) {
+ mono_error_set_not_supported (error, "Linked away.");
+ return NULL;
+ }
vtable->domain->create_proxy_for_type_method = im;
}
- pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
+ pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
+ if (!mono_error_ok (error))
+ return NULL;
- o = mono_runtime_invoke (im, NULL, pa, NULL);
- if (o != NULL) return o;
+ o = mono_runtime_invoke_checked (im, NULL, pa, error);
+ if (!mono_error_ok (error))
+ return NULL;
+
+ if (o != NULL)
+ return o;
}
- return mono_object_new_alloc_specific (vtable);
+ return mono_object_new_alloc_specific_checked (vtable, error);
+}
+
+MonoObject *
+ves_icall_object_new_specific (MonoVTable *vtable)
+{
+ MonoError error;
+ MonoObject *o = mono_object_new_specific_checked (vtable, &error);
+ mono_error_set_pending_exception (&error);
+
+ return o;
}
+/**
+ * mono_object_new_alloc_specific:
+ * @vtable: virtual table for the object.
+ *
+ * This function allocates a new `MonoObject` with the type derived
+ * from the @vtable information. If the class of this object has a
+ * finalizer, then the object will be tracked for finalization.
+ *
+ * This method might raise an exception on errors. Use the
+ * `mono_object_new_fast_checked` method if you want to manually raise
+ * the exception.
+ *
+ * Returns: the allocated object.
+ */
MonoObject *
mono_object_new_alloc_specific (MonoVTable *vtable)
+{
+ MonoError error;
+ MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
+ mono_error_cleanup (&error);
+
+ return o;
+}
+
+/**
+ * mono_object_new_alloc_specific_checked:
+ * @vtable: virtual table for the object.
+ * @error: holds the error return value.
+ *
+ * This function allocates a new `MonoObject` with the type derived
+ * from the @vtable information. If the class of this object has a
+ * finalizer, then the object will be tracked for finalization.
+ *
+ * If there is not enough memory, the @error parameter will be set
+ * and will contain a user-visible message with the amount of bytes
+ * that were requested.
+ *
+ * Returns: the allocated object, or NULL if there is not enough memory
+ *
+ */
+MonoObject *
+mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
- MonoObject *o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
+ MonoObject *o;
+
+ mono_error_init (error);
+
+ o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
- if (G_UNLIKELY (vtable->klass->has_finalize))
+ if (G_UNLIKELY (!o))
+ mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
+ else if (G_UNLIKELY (vtable->klass->has_finalize))
mono_object_register_finalizer (o);
return o;
}
+/**
+ * mono_object_new_fast:
+ * @vtable: virtual table for the object.
+ *
+ * This function allocates a new `MonoObject` with the type derived
+ * from the @vtable information. The returned object is not tracked
+ * for finalization. If your object implements a finalizer, you should
+ * use `mono_object_new_alloc_specific` instead.
+ *
+ * This method might raise an exception on errors. Use the
+ * `mono_object_new_fast_checked` method if you want to manually raise
+ * the exception.
+ *
+ * Returns: the allocated object.
+ */
MonoObject*
mono_object_new_fast (MonoVTable *vtable)
+{
+ MonoError error;
+ MonoObject *o = mono_object_new_fast_checked (vtable, &error);
+ mono_error_cleanup (&error);
+
+ return o;
+}
+
+/**
+ * mono_object_new_fast_checked:
+ * @vtable: virtual table for the object.
+ * @error: holds the error return value.
+ *
+ * This function allocates a new `MonoObject` with the type derived
+ * from the @vtable information. The returned object is not tracked
+ * for finalization. If your object implements a finalizer, you should
+ * use `mono_object_new_alloc_specific_checked` instead.
+ *
+ * If there is not enough memory, the @error parameter will be set
+ * and will contain a user-visible message with the amount of bytes
+ * that were requested.
+ *
+ * Returns: the allocated object, or NULL if there is not enough memory
+ *
+ */
+MonoObject*
+mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
+{
+ MONO_REQ_GC_UNSAFE_MODE;
+
+ MonoObject *o;
+
+ mono_error_init (error);
+
+ o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
+
+ if (G_UNLIKELY (!o))
+ mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
+
+ return o;
+}
+
+MonoObject *
+ves_icall_object_new_fast (MonoVTable *vtable)
+{
+ MonoError error;
+ MonoObject *o = mono_object_new_fast_checked (vtable, &error);
+ mono_error_set_pending_exception (&error);
+
+ return o;
+}
+
+MonoObject*
+mono_object_new_mature (MonoVTable *vtable, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
- return (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
+ MonoObject *o;
+
+ mono_error_init (error);
+
+ o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
+
+ if (G_UNLIKELY (!o))
+ mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
+ else if (G_UNLIKELY (vtable->klass->has_finalize))
+ mono_object_register_finalizer (o);
+
+ return o;
}
/**
*pass_size_in_words = FALSE;
- if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
- return mono_object_new_specific;
+ if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
+ return ves_icall_object_new_specific;
if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
- return mono_object_new_fast;
+ return ves_icall_object_new_fast;
/*
- * FIXME: This is actually slower than mono_object_new_fast, because
+ * FIXME: This is actually slower than ves_icall_object_new_fast, because
* of the overhead of parameter passing.
*/
/*
*/
}
- return mono_object_new_specific;
+ return ves_icall_object_new_specific;
}
/**
MONO_REQ_GC_UNSAFE_MODE;
MonoError error;
+ MonoObject *result;
MonoClass *klass;
klass = mono_class_get_checked (image, token, &error);
- g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+ mono_error_assert_ok (&error);
+
+ result = mono_object_new_checked (domain, klass, &error);
- return mono_object_new (domain, klass);
+ mono_error_cleanup (&error);
+ return result;
+
}
*/
MonoObject *
mono_object_clone (MonoObject *obj)
+{
+ MonoError error;
+ MonoObject *o = mono_object_clone_checked (obj, &error);
+ mono_error_cleanup (&error);
+
+ return o;
+}
+
+MonoObject *
+mono_object_clone_checked (MonoObject *obj, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
MonoObject *o;
- int size = obj->vtable->klass->instance_size;
+ int size;
+
+ mono_error_init (error);
+
+ size = obj->vtable->klass->instance_size;
if (obj->vtable->klass->rank)
- return (MonoObject*)mono_array_clone ((MonoArray*)obj);
+ return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
+ if (G_UNLIKELY (!o)) {
+ mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
+ return NULL;
+ }
+
/* If the object doesn't contain references this will do a simple memmove. */
mono_gc_wbarrier_object_copy (o, obj);
* mono_array_clone_in_domain:
* @domain: the domain in which the array will be cloned into
* @array: the array to clone
+ * @error: set on error
*
* This routine returns a copy of the array that is hosted on the
- * specified MonoDomain.
+ * specified MonoDomain. On failure returns NULL and sets @error.
*/
MonoArray*
-mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
+mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
uintptr_t *sizes;
MonoClass *klass = array->obj.vtable->klass;
+ mono_error_init (error);
+
if (array->bounds == NULL) {
size = mono_array_length (array);
- o = mono_array_new_full (domain, klass, &size, NULL);
+ o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
+ return_val_if_nok (error, NULL);
size *= mono_array_element_size (klass);
#ifdef HAVE_SGEN_GC
size *= array->bounds [i].length;
sizes [i + klass->rank] = array->bounds [i].lower_bound;
}
- o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
+ o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
+ return_val_if_nok (error, NULL);
#ifdef HAVE_SGEN_GC
if (klass->element_class->valuetype) {
if (klass->element_class->has_references)
{
MONO_REQ_GC_UNSAFE_MODE;
- return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
+ MonoError error;
+ MonoArray *result = mono_array_clone_checked (array, &error);
+ mono_error_cleanup (&error);
+ return result;
+}
+
+/**
+ * mono_array_clone_checked:
+ * @array: the array to clone
+ * @error: set on error
+ *
+ * Returns: A newly created array who is a shallow copy of @array. On
+ * failure returns NULL and sets @error.
+ */
+MonoArray*
+mono_array_clone_checked (MonoArray *array, MonoError *error)
+{
+
+ MONO_REQ_GC_UNSAFE_MODE;
+ return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
}
/* helper macros to check for overflow when calculating the size of arrays */
*/
MonoArray*
mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
+{
+ MonoError error;
+ MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
+ mono_error_cleanup (&error);
+
+ return array;
+}
+
+MonoArray*
+mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
MonoVTable *vtable;
int i;
+ mono_error_init (error);
+
if (!array_class->inited)
mono_class_init (array_class);
/* A single dimensional array with a 0 lower bound is the same as an szarray */
if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
len = lengths [0];
- if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
- arith_overflow ();
+ if (len > MONO_ARRAY_MAX_INDEX) {
+ mono_error_set_generic_error (error, "System", "OverflowException", "");
+ return NULL;
+ }
bounds_size = 0;
} else {
bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
for (i = 0; i < array_class->rank; ++i) {
- if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
- arith_overflow ();
- if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
- mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
+ if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
+ mono_error_set_generic_error (error, "System", "OverflowException", "");
+ return NULL;
+ }
+ if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
+ mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
+ return NULL;
+ }
len *= lengths [i];
}
}
- if (!mono_array_calc_byte_len (array_class, len, &byte_len))
- mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
+ if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
+ mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
+ return NULL;
+ }
if (bounds_size) {
/* align */
- if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
- mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
+ if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
+ mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
+ return NULL;
+ }
byte_len = (byte_len + 3) & ~3;
- if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
- mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
+ if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
+ mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
+ return NULL;
+ }
byte_len += bounds_size;
}
/*
* Following three lines almost taken from mono_object_new ():
* they need to be kept in sync.
*/
- vtable = mono_class_vtable_full (domain, array_class, TRUE);
+ vtable = mono_class_vtable_full (domain, array_class, error);
+ return_val_if_nok (error, NULL);
+
if (bounds_size)
o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
else
o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
+
+ if (G_UNLIKELY (!o)) {
+ mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
+ return NULL;
+ }
+
array = (MonoArray*)o;
bounds = array->bounds;
{
MONO_REQ_GC_UNSAFE_MODE;
+ MonoError error;
+ MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
+ mono_error_cleanup (&error);
+ return result;
+}
+
+/**
+ * mono_array_new_checked:
+ * @domain: domain where the object is created
+ * @eclass: element class
+ * @n: number of array elements
+ * @error: set on error
+ *
+ * This routine creates a new szarray with @n elements of type @eclass.
+ * On failure returns NULL and sets @error.
+ */
+MonoArray *
+mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
+{
MonoClass *ac;
+ mono_error_init (error);
+
ac = mono_array_class_get (eclass, 1);
g_assert (ac);
- return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
+ MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
+ return_val_if_nok (error, NULL);
+
+ return mono_array_new_specific_checked (vtable, n, error);
+}
+
+MonoArray*
+ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
+{
+ MonoError error;
+ MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
+ mono_error_set_pending_exception (&error);
+
+ return arr;
}
/**
*/
MonoArray *
mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
+{
+ MonoError error;
+ MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
+ mono_error_cleanup (&error);
+
+ return arr;
+}
+
+MonoArray*
+mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
MonoObject *o;
- MonoArray *ao;
uintptr_t byte_len;
+ mono_error_init (error);
+
if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
- arith_overflow ();
+ mono_error_set_generic_error (error, "System", "OverflowException", "");
return NULL;
}
if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
- mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
+ mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
return NULL;
}
o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
- ao = (MonoArray*)o;
- return ao;
+ if (G_UNLIKELY (!o)) {
+ mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
+ return NULL;
+ }
+
+ return (MonoArray*)o;
+}
+
+MonoArray*
+ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
+{
+ MonoError error;
+ MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
+ mono_error_set_pending_exception (&error);
+
+ return arr;
}
/**
{
MONO_REQ_GC_UNSAFE_MODE;
+ MonoError error;
+ MonoString *res = NULL;
+ res = mono_string_new_utf16_checked (domain, text, len, &error);
+ mono_error_cleanup (&error);
+
+ return res;
+}
+
+/**
+ * mono_string_new_utf16_checked:
+ * @text: a pointer to an utf16 string
+ * @len: the length of the string
+ * @error: written on error.
+ *
+ * Returns: A newly created string object which contains @text.
+ * On error, returns NULL and sets @error.
+ */
+MonoString *
+mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
+{
+ MONO_REQ_GC_UNSAFE_MODE;
+
MonoString *s;
- s = mono_string_new_size (domain, len);
- g_assert (s != NULL);
-
- memcpy (mono_string_chars (s), text, len * 2);
+ mono_error_init (error);
+
+ s = mono_string_new_size_checked (domain, len, error);
+ if (s != NULL)
+ memcpy (mono_string_chars (s), text, len * 2);
return s;
}
* mono_string_new_utf32:
* @text: a pointer to an utf32 string
* @len: the length of the string
+ * @error: set on failure.
*
- * Returns: A newly created string object which contains @text.
+ * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
*/
-MonoString *
-mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
+static MonoString *
+mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
MonoString *s;
mono_unichar2 *utf16_output = NULL;
gint32 utf16_len = 0;
- GError *error = NULL;
+ GError *gerror = NULL;
glong items_written;
- utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &error);
+ mono_error_init (error);
+ utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
- if (error)
- g_error_free (error);
+ if (gerror)
+ g_error_free (gerror);
while (utf16_output [utf16_len]) utf16_len++;
- s = mono_string_new_size (domain, utf16_len);
- g_assert (s != NULL);
+ s = mono_string_new_size_checked (domain, utf16_len, error);
+ return_val_if_nok (error, NULL);
memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
return s;
}
+/**
+ * mono_string_new_utf32:
+ * @text: a pointer to an utf32 string
+ * @len: the length of the string
+ *
+ * Returns: A newly created string object which contains @text.
+ */
+MonoString *
+mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
+{
+ MonoError error;
+ MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
+ mono_error_cleanup (&error);
+ return result;
+}
+
/**
* mono_string_new_size:
* @text: a pointer to an utf16 string
* Returns: A newly created string object of @len
*/
MonoString *
-mono_string_new_size (MonoDomain *domain, gint32 len)
+mono_string_new_size (MonoDomain *domain, gint32 len)
+{
+ MonoError error;
+ MonoString *str = mono_string_new_size_checked (domain, len, &error);
+ mono_error_cleanup (&error);
+
+ return str;
+}
+
+MonoString *
+mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
MonoVTable *vtable;
size_t size;
+ mono_error_init (error);
+
/* check for overflow */
- if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2))
- mono_gc_out_of_memory (-1);
+ if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
+ mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
+ return NULL;
+ }
size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
g_assert (size > 0);
s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
+ if (G_UNLIKELY (!s)) {
+ mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
+ return NULL;
+ }
+
return s;
}
{
MONO_REQ_GC_UNSAFE_MODE;
- GError *error = NULL;
+ MonoError error;
+ MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
+ mono_error_cleanup (&error);
+ return result;
+}
+
+/**
+ * mono_string_new_len_checked:
+ * @text: a pointer to an utf8 string
+ * @length: number of bytes in @text to consider
+ * @error: set on error
+ *
+ * Returns: A newly created string object which contains @text. On
+ * failure returns NULL and sets @error.
+ */
+MonoString*
+mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
+{
+ MONO_REQ_GC_UNSAFE_MODE;
+
+ mono_error_init (error);
+
+ GError *eg_error = NULL;
MonoString *o = NULL;
- guint16 *ut;
+ guint16 *ut = NULL;
glong items_written;
- ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
+ ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
- if (!error)
- o = mono_string_new_utf16 (domain, ut, items_written);
+ if (!eg_error)
+ o = mono_string_new_utf16_checked (domain, ut, items_written, error);
else
- g_error_free (error);
+ g_error_free (eg_error);
g_free (ut);
* @text: a pointer to an utf8 string
*
* Returns: A newly created string object which contains @text.
+ *
+ * This function asserts if it cannot allocate a new string.
+ *
+ * @deprecated Use mono_string_new_checked in new code.
*/
MonoString*
mono_string_new (MonoDomain *domain, const char *text)
+{
+ MonoError error;
+ MonoString *res = NULL;
+ res = mono_string_new_checked (domain, text, &error);
+ mono_error_assert_ok (&error);
+ return res;
+}
+
+/**
+ * mono_string_new_checked:
+ * @text: a pointer to an utf8 string
+ * @merror: set on error
+ *
+ * Returns: A newly created string object which contains @text.
+ * On error returns NULL and sets @merror.
+ */
+MonoString*
+mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
- GError *error = NULL;
+ GError *eg_error = NULL;
MonoString *o = NULL;
guint16 *ut;
glong items_written;
int l;
+ mono_error_init (error);
+
l = strlen (text);
- ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
+ ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
- if (!error)
- o = mono_string_new_utf16 (domain, ut, items_written);
+ if (!eg_error)
+ o = mono_string_new_utf16_checked (domain, ut, items_written, error);
else
- g_error_free (error);
+ g_error_free (eg_error);
g_free (ut);
+
/*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
#if 0
gunichar2 *str;
int len;
MonoString *o = NULL;
- if (!g_utf8_validate (text, -1, &end))
- return NULL;
+ if (!g_utf8_validate (text, -1, &end)) {
+ mono_error_set_argument (error, "text", "Not a valid utf8 string");
+ goto leave;
+ }
len = g_utf8_strlen (text, -1);
- o = mono_string_new_size (domain, len);
+ o = mono_string_new_size_checked (domain, len, error);
+ if (!o)
+ goto leave;
str = mono_string_chars (o);
while (text < end) {
*str++ = g_utf8_get_char (text);
text = g_utf8_next_char (text);
}
+
+leave:
#endif
return o;
}
MonoObject *
mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
{
- MONO_REQ_GC_UNSAFE_MODE;
+ MonoError error;
+ MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
+ mono_error_cleanup (&error);
+ return result;
+}
+/**
+ * mono_value_box_checked:
+ * @domain: the domain of the new object
+ * @class: the class of the value
+ * @value: a pointer to the unboxed data
+ * @error: set on error
+ *
+ * Returns: A newly created object which contains @value. On failure
+ * returns NULL and sets @error.
+ */
+MonoObject *
+mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
+{
+ MONO_REQ_GC_UNSAFE_MODE;
MonoObject *res;
int size;
MonoVTable *vtable;
+ mono_error_init (error);
+
g_assert (klass->valuetype);
if (mono_class_is_nullable (klass))
- return mono_nullable_box ((guint8 *)value, klass);
+ return mono_nullable_box ((guint8 *)value, klass, error);
vtable = mono_class_vtable (domain, klass);
if (!vtable)
return NULL;
size = mono_class_instance_size (klass);
- res = mono_object_new_alloc_specific (vtable);
+ res = mono_object_new_alloc_specific_checked (vtable, error);
+ return_val_if_nok (error, NULL);
size = size - sizeof (MonoObject);
}
#endif
#endif
- if (klass->has_finalize)
+ if (klass->has_finalize) {
mono_object_register_finalizer (res);
+ return_val_if_nok (error, NULL);
+ }
return res;
}
-/*
+/**
* mono_value_copy:
* @dest: destination pointer
* @src: source pointer
mono_gc_wbarrier_value_copy (dest, src, 1, klass);
}
-/*
+/**
* mono_value_copy_array:
* @dest: destination array
* @dest_idx: index in the @dest array
/**
* mono_object_get_class:
* @obj: object to query
- *
- * Returns: the MonOClass of the object.
+ *
+ * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
+ *
+ * Returns: the MonoClass of the object.
*/
MonoClass*
mono_object_get_class (MonoObject *obj)
* @obj: an object
* @klass: a pointer to a class
*
- * Returns: @obj if @obj is derived from @klass
+ * Returns: @obj if @obj is derived from @klass or NULL otherwise.
*/
MonoObject *
mono_object_isinst (MonoObject *obj, MonoClass *klass)
{
MONO_REQ_GC_UNSAFE_MODE;
+ MonoError error;
+ MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
+ mono_error_cleanup (&error);
+ return result;
+}
+
+
+/**
+ * mono_object_isinst_checked:
+ * @obj: an object
+ * @klass: a pointer to a class
+ * @error: set on error
+ *
+ * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
+ * On failure returns NULL and sets @error.
+ */
+MonoObject *
+mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
+{
+ MONO_REQ_GC_UNSAFE_MODE;
+
+ mono_error_init (error);
+
+ MonoObject *result = NULL;
+
if (!klass->inited)
mono_class_init (klass);
- if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
- return mono_object_isinst_mbyref (obj, klass);
+ if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
+ result = mono_object_isinst_mbyref_checked (obj, klass, error);
+ return result;
+ }
if (!obj)
return NULL;
{
MONO_REQ_GC_UNSAFE_MODE;
+ MonoError error;
+ MonoObject *result = mono_object_isinst_mbyref_checked (obj, klass, &error);
+ mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
+ return result;
+}
+
+MonoObject *
+mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
+{
+ MONO_REQ_GC_UNSAFE_MODE;
+
MonoVTable *vt;
+ mono_error_init (error);
+
if (!obj)
return NULL;
vt = obj->vtable;
- if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+ if (mono_class_is_interface (klass)) {
if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
return obj;
}
gpointer pa [2];
im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
- if (!im)
- mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
+ if (!im) {
+ mono_error_set_not_supported (error, "Linked away.");
+ return NULL;
+ }
im = mono_object_get_virtual_method (rp, im);
g_assert (im);
- pa [0] = mono_type_get_object (domain, &klass->byval_arg);
+ pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, error);
+ return_val_if_nok (error, NULL);
pa [1] = obj;
- res = mono_runtime_invoke (im, rp, pa, NULL);
-
+ res = mono_runtime_invoke_checked (im, rp, pa, error);
+ return_val_if_nok (error, NULL);
+
if (*(MonoBoolean *) mono_object_unbox(res)) {
/* Update the vtable of the remote type, so it can safely cast to this new type */
- mono_upgrade_remote_class (domain, obj, klass);
+ mono_upgrade_remote_class (domain, obj, klass, error);
+ return_val_if_nok (error, NULL);
return obj;
}
}
* @obj: an object
* @klass: a pointer to a class
*
- * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
+ * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
*/
MonoObject *
mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
{
MONO_REQ_GC_UNSAFE_MODE;
+ MonoError error;
if (!obj) return NULL;
- if (mono_object_isinst_mbyref (obj, klass)) return obj;
-
- mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
- "System",
- "InvalidCastException"));
+ if (mono_object_isinst_mbyref_checked (obj, klass, &error)) return obj;
+ mono_error_cleanup (&error);
return NULL;
}
info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
}
-#ifdef HAVE_SGEN_GC
-
static MonoString*
-mono_string_get_pinned (MonoString *str)
+mono_string_get_pinned (MonoString *str, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
+ mono_error_init (error);
+
+ /* We only need to make a pinned version of a string if this is a moving GC */
+ if (!mono_gc_is_moving ())
+ return str;
int size;
MonoString *news;
size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
if (news) {
memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
news->length = mono_string_length (str);
+ } else {
+ mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
}
return news;
}
-#else
-#define mono_string_get_pinned(str) (str)
-#endif
-
static MonoString*
-mono_string_is_interned_lookup (MonoString *str, int insert)
+mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
MonoString *s, *res;
MonoDomain *domain;
+ mono_error_init (error);
+
domain = ((MonoObject *)str)->vtable->domain;
ldstr_table = domain->ldstr_table;
ldstr_lock ();
if (insert) {
/* Allocate outside the lock */
ldstr_unlock ();
- s = mono_string_get_pinned (str);
+ s = mono_string_get_pinned (str, error);
+ return_val_if_nok (error, NULL);
if (s) {
ldstr_lock ();
res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
MonoString*
mono_string_is_interned (MonoString *o)
{
- MONO_REQ_GC_UNSAFE_MODE;
-
- return mono_string_is_interned_lookup (o, FALSE);
+ MonoError error;
+ MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
+ /* This function does not fail. */
+ mono_error_assert_ok (&error);
+ return result;
}
/**
*/
MonoString*
mono_string_intern (MonoString *str)
+{
+ MonoError error;
+ MonoString *result = mono_string_intern_checked (str, &error);
+ mono_error_assert_ok (&error);
+ return result;
+}
+
+/**
+ * mono_string_intern_checked:
+ * @o: String to intern
+ * @error: set on error.
+ *
+ * Interns the string passed.
+ * Returns: The interned string. On failure returns NULL and sets @error
+ */
+MonoString*
+mono_string_intern_checked (MonoString *str, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
- return mono_string_is_interned_lookup (str, TRUE);
+ mono_error_init (error);
+
+ return mono_string_is_interned_lookup (str, TRUE, error);
}
/**
*/
MonoString*
mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
+{
+ MonoError error;
+ MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
+ mono_error_cleanup (&error);
+ return result;
+}
+
+/**
+ * mono_ldstr_checked:
+ * @domain: the domain where the string will be used.
+ * @image: a metadata context
+ * @idx: index into the user string table.
+ * @error: set on error.
+ *
+ * Implementation for the ldstr opcode.
+ * Returns: a loaded string from the @image/@idx combination.
+ * On failure returns NULL and sets @error.
+ */
+MonoString*
+mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
+ mono_error_init (error);
if (image->dynamic) {
- MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
+ MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
return str;
} else {
if (!mono_verifier_verify_string_signature (image, idx, NULL))
return NULL; /*FIXME we should probably be raising an exception here*/
- return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
+ MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
+ return str;
}
}
* mono_ldstr_metadata_sig
* @domain: the domain for the string
* @sig: the signature of a metadata string
+ * @error: set on error
*
- * Returns: a MonoString for a string stored in the metadata
+ * Returns: a MonoString for a string stored in the metadata. On
+ * failure returns NULL and sets @error.
*/
static MonoString*
-mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
+mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
+ mono_error_init (error);
const char *str = sig;
MonoString *o, *interned;
size_t len2;
len2 = mono_metadata_decode_blob_size (str, &str);
len2 >>= 1;
- o = mono_string_new_utf16 (domain, (guint16*)str, len2);
+ o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
+ return_val_if_nok (error, NULL);
#if G_BYTE_ORDER != G_LITTLE_ENDIAN
{
int i;
if (interned)
return interned; /* o will get garbage collected */
- o = mono_string_get_pinned (o);
+ o = mono_string_get_pinned (o, error);
if (o) {
ldstr_lock ();
interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
return interned;
}
+/*
+ * mono_ldstr_utf8:
+ *
+ * Same as mono_ldstr, but return a NULL terminated utf8 string instead
+ * of an object.
+ */
+char*
+mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
+{
+ const char *str;
+ size_t len2;
+ long written = 0;
+ char *as;
+ GError *gerror = NULL;
+
+ mono_error_init (error);
+
+ if (!mono_verifier_verify_string_signature (image, idx, NULL))
+ return NULL; /*FIXME we should probably be raising an exception here*/
+ str = mono_metadata_user_string (image, idx);
+
+ len2 = mono_metadata_decode_blob_size (str, &str);
+ len2 >>= 1;
+
+ as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
+ if (gerror) {
+ mono_error_set_argument (error, "string", "%s", gerror->message);
+ g_error_free (gerror);
+ return NULL;
+ }
+ /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
+ if (len2 > written) {
+ /* allocate the total length and copy the part of the string that has been converted */
+ char *as2 = (char *)g_malloc0 (len2);
+ memcpy (as2, as, written);
+ g_free (as);
+ as = as2;
+ }
+
+ return as;
+}
+
/**
* mono_string_to_utf8:
* @s: a System.String
MonoError error;
char *result = mono_string_to_utf8_checked (s, &error);
- if (!mono_error_ok (&error))
- mono_error_raise_exception (&error);
+ if (!is_ok (&error)) {
+ mono_error_cleanup (&error);
+ return NULL;
+ }
return result;
}
MonoString *
mono_string_from_utf16 (gunichar2 *data)
{
+ MonoError error;
+ MonoString *result = mono_string_from_utf16_checked (data, &error);
+ mono_error_cleanup (&error);
+ return result;
+}
+
+/**
+ * mono_string_from_utf16_checked:
+ * @data: the UTF16 string (LPWSTR) to convert
+ * @error: set on error
+ *
+ * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
+ *
+ * Returns: a MonoString. On failure sets @error and returns NULL.
+ */
+MonoString *
+mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
+{
+
MONO_REQ_GC_UNSAFE_MODE;
+ mono_error_init (error);
MonoDomain *domain = mono_domain_get ();
int len = 0;
while (data [len]) len++;
- return mono_string_new_utf16 (domain, data, len);
+ return mono_string_new_utf16_checked (domain, data, len, error);
}
/**
*/
MonoString *
mono_string_from_utf32 (mono_unichar4 *data)
+{
+ MonoError error;
+ MonoString *result = mono_string_from_utf32_checked (data, &error);
+ mono_error_cleanup (&error);
+ return result;
+}
+
+/**
+ * mono_string_from_utf32_checked:
+ * @data: the UTF32 string (LPWSTR) to convert
+ * @error: set on error
+ *
+ * Converts a UTF32 (UCS-4)to a MonoString.
+ *
+ * Returns: a MonoString. On failure returns NULL and sets @error.
+ */
+MonoString *
+mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
+ mono_error_init (error);
MonoString* result = NULL;
mono_unichar2 *utf16_output = NULL;
- GError *error = NULL;
+ GError *gerror = NULL;
glong items_written;
int len = 0;
while (data [len]) len++;
- utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
+ utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
- if (error)
- g_error_free (error);
+ if (gerror)
+ g_error_free (gerror);
- result = mono_string_from_utf16 (utf16_output);
+ result = mono_string_from_utf16_checked (utf16_output, error);
g_free (utf16_output);
return result;
}
* mono_wait_handle_new:
* @domain: Domain where the object will be created
* @handle: Handle for the wait handle
+ * @error: set on error.
*
- * Returns: A new MonoWaitHandle created in the given domain for the given handle
+ * Returns: A new MonoWaitHandle created in the given domain for the
+ * given handle. On failure returns NULL and sets @rror.
*/
MonoWaitHandle *
-mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
+mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
gpointer params [1];
static MonoMethod *handle_set;
- res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
+ mono_error_init (error);
+ res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
+ return_val_if_nok (error, NULL);
/* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
if (!handle_set)
handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
params [0] = &handle;
- mono_runtime_invoke (handle_set, res, params, NULL);
+ mono_runtime_invoke_checked (handle_set, res, params, error);
return res;
}
{
MONO_REQ_GC_UNSAFE_MODE;
- static MonoClassField *f_os_handle;
- static MonoClassField *f_safe_handle;
+ static MonoClassField *f_safe_handle = NULL;
+ MonoSafeHandle *sh;
- if (!f_os_handle && !f_safe_handle) {
- f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
- f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
+ if (!f_safe_handle) {
+ f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
+ g_assert (f_safe_handle);
}
- if (f_os_handle) {
- HANDLE retval;
- mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
- return retval;
- } else {
- MonoSafeHandle *sh;
- mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
- return sh->handle;
- }
+ mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
+ return sh->handle;
}
static MonoObject*
-mono_runtime_capture_context (MonoDomain *domain)
+mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
RuntimeInvokeFunction runtime_invoke;
+ mono_error_init (error);
+
if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
MonoMethod *method = mono_get_context_capture_method ();
MonoMethod *wrapper;
if (!method)
return NULL;
- wrapper = mono_marshal_get_runtime_invoke (method, FALSE, FALSE);
- domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
- domain->capture_context_method = mono_compile_method (method);
+ wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
+ domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
+ return_val_if_nok (error, NULL);
+ domain->capture_context_method = mono_compile_method_checked (method, error);
+ return_val_if_nok (error, NULL);
}
runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
* @handle: wait handle.
* @state: state to pass to AsyncResult
* @data: C closure data.
+ * @error: set on error.
*
* Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
* If the handle is not null, the handle is initialized to a MonOWaitHandle.
+ * On failure returns NULL and sets @error.
*
*/
MonoAsyncResult *
-mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
+mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
- MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
- MonoObject *context = mono_runtime_capture_context (domain);
+ mono_error_init (error);
+ MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
+ return_val_if_nok (error, NULL);
+ MonoObject *context = mono_runtime_capture_context (domain, error);
+ return_val_if_nok (error, NULL);
/* we must capture the execution context from the original thread */
if (context) {
MONO_OBJECT_SETREF (res, execution_context, context);
res->data = (void **)data;
MONO_OBJECT_SETREF (res, object_data, object_data);
MONO_OBJECT_SETREF (res, async_state, state);
+ MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
+ return_val_if_nok (error, NULL);
if (handle != NULL)
- MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
+ MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
res->sync_completed = FALSE;
res->completed = FALSE;
{
MONO_REQ_GC_UNSAFE_MODE;
+ MonoError error;
MonoAsyncCall *ac;
MonoObject *res;
ac = (MonoAsyncCall*) ares->object_data;
if (!ac) {
- res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
+ res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
+ if (mono_error_set_pending_exception (&error))
+ return NULL;
} else {
gpointer wait_event = NULL;
ac->msg->exc = NULL;
- res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
+
+ res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
+
+ /* 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);
-
- if (ac->cb_method) {
- /* we swallow the excepton as it is the behavior on .NET */
- MonoObject *exc = NULL;
- mono_runtime_invoke (ac->cb_method, ac->cb_target, (gpointer*) &ares, &exc);
- if (exc)
- mono_unhandled_exception (exc);
- }
+ mono_w32event_set (wait_event);
+
+ 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);
+
+ mono_threads_end_abort_protected_block ();
+
+ if (mono_error_set_pending_exception (&error))
+ return NULL;
}
return res;
}
-void
+gboolean
mono_message_init (MonoDomain *domain,
MonoMethodMessage *this_obj,
MonoReflectionMethod *method,
- MonoArray *out_args)
+ MonoArray *out_args,
+ MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
- static MonoClass *object_array_klass;
- static MonoClass *byte_array_klass;
- static MonoClass *string_array_klass;
- MonoMethodSignature *sig = mono_method_signature (method->method);
- MonoString *name;
- int i, j;
- char **names;
- guint8 arg_type;
-
- if (!object_array_klass) {
- MonoClass *klass;
-
- 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);
- }
-
- MONO_OBJECT_SETREF (this_obj, method, method);
-
- MONO_OBJECT_SETREF (this_obj, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
- MONO_OBJECT_SETREF (this_obj, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
- this_obj->async_result = NULL;
- this_obj->call_type = CallType_Sync;
+ static MonoMethod *init_message_method = NULL;
- names = g_new (char *, sig->param_count);
- mono_method_get_param_names (method->method, (const char **) names);
- MONO_OBJECT_SETREF (this_obj, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
-
- for (i = 0; i < sig->param_count; i++) {
- name = mono_string_new (domain, names [i]);
- mono_array_setref (this_obj->names, i, name);
+ 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);
}
- 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);
- }
+ mono_error_init (error);
+ /* FIXME set domain instead? */
+ g_assert (domain == mono_domain_get ());
+
+ gpointer args[2];
+
+ args[0] = method;
+ args[1] = out_args;
+
+ mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
+ return is_ok (error);
}
#ifndef DISABLE_REMOTING
* Returns: the result object.
*/
MonoObject *
-mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
- MonoObject **exc, MonoArray **out_args)
+mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
+ MonoObject *o;
MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
gpointer pa [4];
+ g_assert (exc);
+
+ mono_error_init (error);
+
/*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
if (!im) {
im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
- if (!im)
- mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
+ if (!im) {
+ mono_error_set_not_supported (error, "Linked away.");
+ return NULL;
+ }
real_proxy->vtable->domain->private_invoke_method = im;
}
pa [2] = exc;
pa [3] = out_args;
- return mono_runtime_invoke (im, NULL, pa, exc);
+ o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
+ return_val_if_nok (error, NULL);
+
+ return o;
}
#endif
MonoObject *
mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
- MonoObject **exc, MonoArray **out_args)
+ MonoObject **exc, MonoArray **out_args, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
static MonoClass *object_array_klass;
+ mono_error_init (error);
+
MonoDomain *domain;
MonoMethod *method;
MonoMethodSignature *sig;
- MonoObject *ret;
+ MonoArray *arr;
int i, j, outarg_count = 0;
#ifndef DISABLE_REMOTING
if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
target = tp->rp->unwrapped_server;
} else {
- return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
+ return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
}
}
#endif
object_array_klass = klass;
}
- mono_gc_wbarrier_generic_store (out_args, (MonoObject*) mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count));
+ arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
+ return_val_if_nok (error, NULL);
+
+ mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
*exc = NULL;
- ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
+ MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
+ return_val_if_nok (error, NULL);
for (i = 0, j = 0; i < sig->param_count; i++) {
if (sig->params [i]->byref) {
}
/**
- * mono_object_to_string:
+ * prepare_to_string_method:
* @obj: The object
- * @exc: Any exception thrown by ToString (). May be NULL.
+ * @target: Set to @obj or unboxed value if a valuetype
*
- * Returns: the result of calling ToString () on an object.
+ * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
*/
-MonoString *
-mono_object_to_string (MonoObject *obj, MonoObject **exc)
+static MonoMethod *
+prepare_to_string_method (MonoObject *obj, void **target)
{
MONO_REQ_GC_UNSAFE_MODE;
static MonoMethod *to_string = NULL;
MonoMethod *method;
- void *target = obj;
-
+ g_assert (target);
g_assert (obj);
+ *target = obj;
+
if (!to_string)
to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
// Unbox value type if needed
if (mono_class_is_valuetype (mono_method_get_class (method))) {
- target = mono_object_unbox (obj);
+ *target = mono_object_unbox (obj);
+ }
+ return method;
+}
+
+/**
+ * mono_object_to_string:
+ * @obj: The object
+ * @exc: Any exception thrown by ToString (). May be NULL.
+ *
+ * Returns: the result of calling ToString () on an object.
+ */
+MonoString *
+mono_object_to_string (MonoObject *obj, MonoObject **exc)
+{
+ MonoError error;
+ MonoString *s = NULL;
+ void *target;
+ MonoMethod *method = prepare_to_string_method (obj, &target);
+ if (exc) {
+ s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
+ if (*exc == NULL && !mono_error_ok (&error))
+ *exc = (MonoObject*) mono_error_convert_to_exception (&error);
+ else
+ mono_error_cleanup (&error);
+ } else {
+ s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
+ mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
}
- return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
+ return s;
+}
+
+/**
+ * mono_object_to_string_checked:
+ * @obj: The object
+ * @error: Set on error.
+ *
+ * Returns: the result of calling ToString () on an object. If the
+ * method cannot be invoked or if it raises an exception, sets @error
+ * and returns NULL.
+ */
+MonoString *
+mono_object_to_string_checked (MonoObject *obj, MonoError *error)
+{
+ mono_error_init (error);
+ void *target;
+ MonoMethod *method = prepare_to_string_method (obj, &target);
+ return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
+}
+
+/**
+ * mono_object_try_to_string:
+ * @obj: The object
+ * @exc: Any exception thrown by ToString (). Must not be NULL.
+ * @error: Set if method cannot be invoked.
+ *
+ * Returns: the result of calling ToString () on an object. If the
+ * method cannot be invoked sets @error, if it raises an exception sets @exc,
+ * and returns NULL.
+ */
+MonoString *
+mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
+{
+ g_assert (exc);
+ mono_error_init (error);
+ void *target;
+ MonoMethod *method = prepare_to_string_method (obj, &target);
+ return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
}
+
+
/**
* mono_print_unhandled_exception:
* @exc: The exception
free_message = TRUE;
} else {
MonoObject *other_exc = NULL;
- str = mono_object_to_string (exc, &other_exc);
+ str = mono_object_try_to_string (exc, &other_exc, &error);
+ if (other_exc == NULL && !is_ok (&error))
+ other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
+ else
+ mono_error_cleanup (&error);
if (other_exc) {
char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
}
/**
- * mono_delegate_ctor:
+ * mono_delegate_ctor_with_method:
* @this: pointer to an uninitialized delegate object
* @target: target object
* @addr: pointer to native code
* @method: method
+ * @error: set on error.
*
* Initialize a delegate and sets a specific method, not the one
* associated with addr. This is useful when sharing generic code.
* In that case addr will most probably not be associated with the
* correct instantiation of the method.
+ * On failure returns FALSE and sets @error.
*/
-void
-mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
+gboolean
+mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
+ mono_error_init (error);
MonoDelegate *delegate = (MonoDelegate *)this_obj;
g_assert (this_obj);
if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
g_assert (method);
method = mono_marshal_get_remoting_invoke (method);
- delegate->method_ptr = mono_compile_method (method);
+ delegate->method_ptr = mono_compile_method_checked (method, error);
+ return_val_if_nok (error, FALSE);
MONO_OBJECT_SETREF (delegate, target, target);
} else
#endif
}
delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
+ if (callbacks.init_delegate)
+ callbacks.init_delegate (delegate);
+ return TRUE;
}
/**
* @this: pointer to an uninitialized delegate object
* @target: target object
* @addr: pointer to native code
+ * @error: set on error.
*
* This is used to initialize a delegate.
+ * On failure returns FALSE and sets @error.
*/
-void
-mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
+gboolean
+mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
+ mono_error_init (error);
MonoDomain *domain = mono_domain_get ();
MonoJitInfo *ji;
MonoMethod *method = NULL;
ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
if (ji) {
method = mono_jit_info_get_method (ji);
- g_assert (!method->klass->generic_container);
+ g_assert (!mono_class_is_gtd (method->klass));
}
- mono_delegate_ctor_with_method (this_obj, target, addr, method);
+ return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
}
/**
* @invoke: optional, delegate invoke.
* @cb: async callback delegate.
* @state: state passed to the async callback.
+ * @error: set on error.
*
* Translates arguments pointers into a MonoMethodMessage.
+ * On failure returns NULL and sets @error.
*/
MonoMethodMessage *
mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
- MonoDelegate **cb, MonoObject **state)
+ MonoDelegate **cb, MonoObject **state, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
+ mono_error_init (error);
+
MonoDomain *domain = mono_domain_get ();
MonoMethodSignature *sig = mono_method_signature (method);
MonoMethodMessage *msg;
int i, count;
- msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
-
+ msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
+ return_val_if_nok (error, NULL);
+
if (invoke) {
- mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
+ MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
+ return_val_if_nok (error, NULL);
+ mono_message_init (domain, msg, rm, NULL, error);
+ return_val_if_nok (error, NULL);
count = sig->param_count - 2;
} else {
- mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
+ MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
+ return_val_if_nok (error, NULL);
+ mono_message_init (domain, msg, rm, NULL, error);
+ return_val_if_nok (error, NULL);
count = sig->param_count;
}
klass = mono_class_from_mono_type (sig->params [i]);
- if (klass->valuetype)
- arg = mono_value_box (domain, klass, vpos);
- else
+ if (klass->valuetype) {
+ arg = mono_value_box_checked (domain, klass, vpos, error);
+ return_val_if_nok (error, NULL);
+ } else
arg = *((MonoObject **)vpos);
mono_array_setref (msg->args, i, arg);
* Restore results from message based processing back to arguments pointers
*/
void
-mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
+mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
+ mono_error_init (error);
+
MonoMethodSignature *sig = mono_method_signature (method);
int i, j, type, size, out_len;
if (pt->byref) {
char *arg;
- if (j >= out_len)
- mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
+ if (j >= out_len) {
+ mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
+ return;
+ }
arg = (char *)mono_array_get (out_args, gpointer, j);
type = pt->type;
*/
gpointer
mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
+{
+ MonoError error;
+ gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
+ mono_error_cleanup (&error);
+ return result;
+}
+
+/**
+ * mono_load_remote_field_checked:
+ * @this: pointer to an object
+ * @klass: klass of the object containing @field
+ * @field: the field to load
+ * @res: a storage to store the result
+ * @error: set on error
+ *
+ * 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. @res is a storage location which can be
+ * used to store the result.
+ *
+ * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
+ */
+gpointer
+mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
static MonoMethod *getter = NULL;
+
+ mono_error_init (error);
+
MonoDomain *domain = mono_domain_get ();
MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
MonoClass *field_class;
if (!getter) {
getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
- if (!getter)
- mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
+ if (!getter) {
+ mono_error_set_not_supported (error, "Linked away.");
+ return NULL;
+ }
}
field_class = mono_class_from_mono_type (field->type);
- msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
- out_args = mono_array_new (domain, mono_defaults.object_class, 1);
- mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
+ 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);
+ mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
+ return_val_if_nok (error, NULL);
- if (exc) mono_raise_exception ((MonoException *)exc);
+ if (exc) {
+ mono_error_set_exception_instance (error, (MonoException *)exc);
+ return NULL;
+ }
if (mono_array_length (out_args) == 0)
return NULL;
- *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
+ mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
if (field_class->valuetype) {
return ((char *)*res) + sizeof (MonoObject);
*/
MonoObject *
mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
+{
+ MonoError error;
+
+ MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
+ mono_error_cleanup (&error);
+ return result;
+}
+
+/**
+ * mono_load_remote_field_new_checked:
+ * @this: pointer to an object
+ * @klass: klass of the object containing @field
+ * @field: the field to load
+ * @error: set on error.
+ *
+ * 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 sets @error.
+ */
+MonoObject *
+mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
- 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;
+ mono_error_init (error);
- g_assert (mono_object_is_transparent_proxy (this_obj));
+ static MonoMethod *tp_load = NULL;
- field_class = mono_class_from_mono_type (field->type);
+ g_assert (mono_object_is_transparent_proxy (this_obj));
- 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 (domain, field_class);
- val = ((gchar *) res) + sizeof (MonoObject);
- } else {
- val = &res;
+ 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;
}
- 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)
- mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
}
- msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
- out_args = mono_array_new (domain, mono_defaults.object_class, 1);
-
- mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
-
- 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);
+ /* MonoType *type = mono_class_get_type (klass); */
- mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
+ gpointer args[2];
+ args [0] = &klass;
+ args [1] = &field;
- if (exc) mono_raise_exception ((MonoException *)exc);
-
- if (mono_array_length (out_args) == 0)
- res = NULL;
- else
- res = mono_array_get (out_args, MonoObject *, 0);
-
- return res;
+ return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
}
/**
void
mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
{
+ MonoError error;
+ (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
+ mono_error_cleanup (&error);
+}
+
+/**
+ * mono_store_remote_field_checked:
+ * @this_obj: pointer to an object
+ * @klass: klass of the object containing @field
+ * @field: the field to load
+ * @val: the value/object to store
+ * @error: set on error
+ *
+ * This method is called by the runtime on attempts to store fields of
+ * transparent proxy objects. @this_obj points to such TP, @klass is the class of
+ * the object containing @field. @val is the new value to store in @field.
+ *
+ * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
+ */
+gboolean
+mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *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;
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;
- }
-
- if (!setter) {
- setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
- if (!setter)
- mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
+ if (field_class->valuetype) {
+ arg = mono_value_box_checked (domain, field_class, val, error);
+ return_val_if_nok (error, FALSE);
+ } else {
+ arg = *((MonoObject**)val);
}
- if (field_class->valuetype)
- arg = mono_value_box (domain, field_class, val);
- else
- arg = *((MonoObject **)val);
-
-
- msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
- mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), 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)));
- mono_array_setref (msg->args, 2, arg);
- g_free (full_name);
-
- mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
-
- if (exc) mono_raise_exception ((MonoException *)exc);
+ return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
}
/**
void
mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
{
- MONO_REQ_GC_UNSAFE_MODE;
+ MonoError error;
+ (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
+ mono_error_cleanup (&error);
+}
- 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;
+/**
+ * mono_store_remote_field_new_checked:
+ * @this_obj:
+ * @klass:
+ * @field:
+ * @arg:
+ * @error:
+ *
+ * Missing documentation
+ */
+gboolean
+mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
+{
+ MONO_REQ_GC_UNSAFE_MODE;
- g_assert (mono_object_is_transparent_proxy (this_obj));
+ static MonoMethod *tp_store = NULL;
- field_class = mono_class_from_mono_type (field->type);
+ mono_error_init (error);
- 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;
- }
+ g_assert (mono_object_is_transparent_proxy (this_obj));
- if (!setter) {
- setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
- if (!setter)
- mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
+ 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 (domain, mono_defaults.mono_method_message_class);
- mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), 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)));
- mono_array_setref (msg->args, 2, arg);
- g_free (full_name);
-
- mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
+ gpointer args[3];
+ args [0] = &klass;
+ args [1] = &field;
+ args [2] = arg;
- if (exc) mono_raise_exception ((MonoException *)exc);
+ mono_runtime_invoke_checked (tp_store, this_obj, args, error);
+ return is_ok (error);
}
#endif
* @size: size of the array elements
* @idx: index into the array
*
+ * Use this function to obtain the address for the @idx item on the
+ * @array containing elements of size @size.
+ *
+ * This method performs no bounds checking or type checking.
+ *
* Returns the address of the @idx element in the array.
*/
char*
MonoArray *
-mono_glist_to_array (GList *list, MonoClass *eclass)
+mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
{
MonoDomain *domain = mono_domain_get ();
MonoArray *res;
int len, i;
+ mono_error_init (error);
if (!list)
return NULL;
len = g_list_length (list);
- res = mono_array_new (domain, eclass, len);
+ res = mono_array_new_checked (domain, eclass, len, error);
+ return_val_if_nok (error, NULL);
for (i = 0; list; list = list->next, i++)
mono_array_set (res, gpointer, i, list->data);
return res;
}
+#if NEVER_DEFINED
+/*
+ * The following section is purely to declare prototypes and
+ * document the API, as these C files are processed by our
+ * tool
+ */
+
+/**
+ * mono_array_set:
+ * @array: array to alter
+ * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
+ * @index: index into the array
+ * @value: value to set
+ *
+ * Value Type version: This sets the @index's element of the @array
+ * with elements of size sizeof(type) to the provided @value.
+ *
+ * This macro does not attempt to perform type checking or bounds checking.
+ *
+ * Use this to set value types in a `MonoArray`.
+ */
+void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
+{
+}
+
+/**
+ * mono_array_setref:
+ * @array: array to alter
+ * @index: index into the array
+ * @value: value to set
+ *
+ * Reference Type version: This sets the @index's element of the
+ * @array with elements of size sizeof(type) to the provided @value.
+ *
+ * This macro does not attempt to perform type checking or bounds checking.
+ *
+ * Use this to reference types in a `MonoArray`.
+ */
+void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
+{
+}
+
+/**
+ * mono_array_get:
+ * @array: array on which to operate on
+ * @element_type: C element type (example: MonoString *, int, MonoObject *)
+ * @index: index into the array
+ *
+ * Use this macro to retrieve the @index element of an @array and
+ * extract the value assuming that the elements of the array match
+ * the provided type value.
+ *
+ * This method can be used with both arrays holding value types and
+ * reference types. For reference types, the @type parameter should
+ * be a `MonoObject*` or any subclass of it, like `MonoString*`.
+ *
+ * This macro does not attempt to perform type checking or bounds checking.
+ *
+ * Returns: The element at the @index position in the @array.
+ */
+Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)
+{
+}
+#endif
+