Enhance maximum number of supported interfaces from 2^16.
/*
* Copyright 2012 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_METADATA_CLASS_INTERNALS_H__
#define __MONO_METADATA_CLASS_INTERNALS_H__
#define MONO_CLASS_IS_ARRAY(c) ((c)->rank)
-#define MONO_CLASS_HAS_STATIC_METADATA(klass) ((klass)->type_token && !(klass)->image->dynamic && !(klass)->generic_class)
+#define MONO_CLASS_HAS_STATIC_METADATA(klass) ((klass)->type_token && !(klass)->image->dynamic && !mono_class_is_ginst (klass))
#define MONO_DEFAULT_SUPERTABLE_SIZE 6
};
/* type of exception being "on hold" for later processing (see exception_type) */
-enum {
+typedef enum {
MONO_EXCEPTION_NONE = 0,
MONO_EXCEPTION_INVALID_PROGRAM = 3,
MONO_EXCEPTION_UNVERIFIABLE_IL = 4,
MONO_EXCEPTION_INLINE_FAILED = 15,
MONO_EXCEPTION_MONO_ERROR = 16,
/* add other exception type */
-};
+} MonoExceptionType;
/* This struct collects the info needed for the runtime use of a class,
* like the vtables for a domain, the GC descriptor, etc.
GList *nested_classes;
} MonoClassExt;
+typedef enum {
+ MONO_CLASS_DEF = 1, /* non-generic type */
+ MONO_CLASS_GTD, /* generic type definition */
+ MONO_CLASS_GINST, /* generic instantiation */
+ MONO_CLASS_GPARAM, /* generic parameter */
+ MONO_CLASS_ARRAY, /* vector or array, bounded or not */
+ MONO_CLASS_POINTER, /* pointer of function pointer*/
+} MonoTypeKind;
+
struct _MonoClass {
/* element class for arrays and enum basetype for enums */
MonoClass *element_class;
int instance_size; /* object instance size */
guint inited : 1;
- /* We use init_pending to detect cyclic calls to mono_class_init */
- guint init_pending : 1;
/* A class contains static and non static data. Static data can be
* of the same type as the class itselfs, but it does not influence
guint nested_classes_inited : 1; /* Whenever nested_class is initialized */
/* next byte*/
+ guint class_kind : 3; /* One of the values from MonoTypeKind */
guint interfaces_inited : 1; /* interfaces is initialized */
guint simd_type : 1; /* class is a simd intrinsic type */
- guint is_generic : 1; /* class is a generic type definition */
- guint is_inflated : 1; /* class is a generic instance */
guint has_finalize_inited : 1; /* has_finalize is initialized */
- guint fields_inited : 1; /* fields is initialized */
- guint setup_fields_called : 1; /* to prevent infinite loops in setup_fields */
-
- guint8 exception_type; /* MONO_EXCEPTION_* */
-
- /* Additional information about the exception */
- /* Stored as property MONO_CLASS_PROP_EXCEPTION_DATA */
- //void *exception_data;
+ guint fields_inited : 1; /* setup_fields () has finished */
+ guint has_failure : 1; /* See MONO_CLASS_PROP_EXCEPTION_DATA for a MonoErrorBoxed with the details */
MonoClass *parent;
MonoClass *nested_in;
int vtable_size; /* number of slots */
guint16 interface_count;
- guint16 interface_id; /* unique inderface id (for interfaces) */
- guint16 max_interface_id;
+ guint32 interface_id; /* unique inderface id (for interfaces) */
+ guint32 max_interface_id;
guint16 interface_offsets_count;
MonoClass **interfaces_packed;
/*
* From the TypeDef table
*/
- guint32 flags;
struct {
#if MONO_SMALL_CONFIG
- guint16 first, count;
+ guint16 count;
#else
- guint32 first, count;
+ guint32 count;
#endif
- } field, method;
+ } field;
+ struct {
+#if MONO_SMALL_CONFIG
+ guint16 count;
+#else
+ guint32 count;
+#endif
+ } method;
/* A GC handle pointing to the corresponding type builder/generic param builder */
guint32 ref_info_handle;
MonoType this_arg;
MonoType byval_arg;
- MonoGenericClass *generic_class;
- MonoGenericContainer *generic_container;
-
MonoGCDescriptor gc_descr;
MonoClassRuntimeInfo *runtime_info;
- /* next element in the class_cache hash list (in MonoImage) */
- MonoClass *next_class_cache;
-
/* Generic vtable. Initialized by a call to mono_class_setup_vtable () */
MonoMethod **vtable;
MonoClassExt *ext;
};
+typedef struct {
+ MonoClass class;
+ guint32 flags;
+ /*
+ * From the TypeDef table
+ */
+ guint32 first_method_idx;
+ guint32 first_field_idx;
+ /* next element in the class_cache hash list (in MonoImage) */
+ MonoClass *next_class_cache;
+} MonoClassDef;
+
+typedef struct {
+ MonoClassDef class;
+ MonoGenericContainer *generic_container;
+} MonoClassGtd;
+
+typedef struct {
+ MonoClass class;
+ MonoGenericClass *generic_class;
+} MonoClassGenericInst;
+
+typedef struct {
+ MonoClass class;
+} MonoClassGenericParam;
+
+typedef struct {
+ MonoClass class;
+} MonoClassArray;
+
+typedef struct {
+ MonoClass class;
+} MonoClassPointer;
+
#ifdef COMPRESSED_INTERFACE_BITMAP
int mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size);
int mono_class_interface_match (const uint8_t *bitmap, int id);
MonoDomain *domain; /* each object/vtable belongs to exactly one domain */
gpointer type; /* System.Type type for klass */
guint8 *interface_bitmap;
- guint16 max_interface_id;
+ guint32 max_interface_id;
guint8 rank;
guint remote : 1; /* class is remotely activated */
guint initialized : 1; /* cctor has been run */
MonoMethod method;
MonoMethodPInvoke pinvoke;
} method;
- MonoMethodHeader *header;
MonoMethod *declaring; /* the generic method definition. */
MonoGenericContext context; /* The current instantiation */
MonoImageSet *owner; /* The image set that the inflated method belongs to. */
struct _MonoGenericClass {
MonoClass *container_class; /* the generic type definition */
MonoGenericContext context; /* a context that contains the type instantiation doesn't contain any method instantiation */ /* FIXME: Only the class_inst member of "context" is ever used, so this field could be replaced with just a monogenericinst */
- guint is_dynamic : 1; /* We're a MonoDynamicGenericClass */
+ guint is_dynamic : 1; /* Contains dynamic types */
guint is_tb_open : 1; /* This is the fully open instantiation for a type_builder. Quite ugly, but it's temporary.*/
+ guint need_sync : 1; /* Only if dynamic. Need to be synchronized with its container class after its finished. */
MonoClass *cached_class; /* if present, the MonoClass corresponding to the instantiation. */
/*
MonoImageSet *owner;
};
-/*
- * This is used when instantiating a generic type definition which is
- * a TypeBuilder.
- */
-struct _MonoDynamicGenericClass {
- MonoGenericClass generic_class;
- int count_fields;
- MonoClassField *fields;
- guint initialized;
- /* The non-inflated types of the fields */
- MonoType **field_generic_types;
- /* The managed objects representing the fields */
- MonoObject **field_objects;
-};
-
/*
* A type parameter.
*/
};
/* Additional details about a MonoGenericParam */
+/* Keep in sync with managed Mono.RuntimeStructs.GenericParamInfo */
typedef struct {
MonoClass *pklass; /* The corresponding `MonoClass'. */
const char *name;
gboolean no_raise;
} MonoJitICallInfo;
-typedef struct {
- guint8 exception_type;
- char *class_name; /* If kind == TYPE */
- char *assembly_name; /* If kind == TYPE or ASSEMBLY */
- MonoClass *klass; /* If kind != TYPE */
- const char *member_name; /* If kind != TYPE */
- gboolean ref_only; /* If kind == ASSEMBLY */
- char *msg; /* If kind == BAD_IMAGE */
-} MonoLoaderError;
-
void
mono_class_setup_supertypes (MonoClass *klass);
void
-mono_class_setup_fields_locking (MonoClass *klass);
+mono_class_setup_fields (MonoClass *klass);
/* WARNING
* Only call this function if you can ensure both @klass and @parent
size_t imt_slots_with_collisions;
size_t imt_max_collisions_in_slot;
size_t imt_method_count_when_max_collisions;
- size_t imt_thunks_size;
+ size_t imt_trampolines_size;
size_t jit_info_table_insert_count;
size_t jit_info_table_remove_count;
size_t jit_info_table_lookup_count;
extern MonoStats mono_stats;
-typedef gpointer (*MonoTrampoline) (MonoMethod *method);
-typedef gpointer (*MonoJumpTrampoline) (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper);
-typedef gpointer (*MonoRemotingTrampoline) (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target);
+typedef gpointer (*MonoRemotingTrampoline) (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error);
typedef gpointer (*MonoDelegateTrampoline) (MonoDomain *domain, MonoClass *klass);
-typedef gpointer (*MonoLookupDynamicToken) (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context);
-
typedef gboolean (*MonoGetCachedClassInfo) (MonoClass *klass, MonoCachedClassInfo *res);
typedef gboolean (*MonoGetClassFromName) (MonoImage *image, const char *name_space, const char *name, MonoClass **res);
mono_classes_cleanup (void);
void
-mono_class_layout_fields (MonoClass *klass);
+mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_size, gboolean sre);
void
mono_class_setup_interface_offsets (MonoClass *klass);
const char*
mono_class_get_property_default_value (MonoProperty *property, MonoTypeEnum *def_type);
-void
-mono_install_trampoline (MonoTrampoline func);
-
-void
-mono_install_jump_trampoline (MonoJumpTrampoline func);
-
void
mono_install_delegate_trampoline (MonoDelegateTrampoline func);
gpointer
-mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context);
+mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context, MonoError *error);
gpointer
-mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean check_token, MonoClass **handle_class, MonoGenericContext *context);
-
-void
-mono_install_lookup_dynamic_token (MonoLookupDynamicToken func);
+mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean check_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error);
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);
gpointer
mono_runtime_create_delegate_trampoline (MonoClass *klass);
MonoType*
mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error);
-MonoClass*
-mono_class_inflate_generic_class (MonoClass *gklass, MonoGenericContext *context);
-
MonoType*
mono_class_inflate_generic_type_checked (MonoType *type, MonoGenericContext *context, MonoError *error);
MonoClass *fieldhandle_class;
MonoClass *methodhandle_class;
MonoClass *systemtype_class;
- MonoClass *monotype_class;
MonoClass *runtimetype_class;
MonoClass *exception_class;
MonoClass *threadabortexception_class;
MonoClass *typed_reference_class;
MonoClass *argumenthandle_class;
MonoClass *monitor_class;
- MonoClass *runtimesecurityframe_class;
- MonoClass *executioncontext_class;
- MonoClass *internals_visible_class;
MonoClass *generic_ilist_class;
MonoClass *generic_nullable_class;
- MonoClass *safehandle_class;
MonoClass *handleref_class;
MonoClass *attribute_class;
MonoClass *customattribute_data_class;
- MonoClass *critical_finalizer_object;
+ MonoClass *critical_finalizer_object; /* MAYBE NULL */
MonoClass *generic_ireadonlylist_class;
MonoClass *threadpool_wait_callback_class;
MonoMethod *threadpool_perform_wait_callback_method;
#define mono_object_is_transparent_proxy(object) (FALSE)
#else
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);
void
mono_install_remoting_trampoline (MonoRemotingTrampoline func);
#define GENERATE_GET_CLASS_WITH_CACHE_DECL(shortname) \
MonoClass* mono_class_get_##shortname##_class (void);
+#define GENERATE_TRY_GET_CLASS_WITH_CACHE_DECL(shortname) \
+MonoClass* mono_class_try_get_##shortname##_class (void);
+
#define GENERATE_GET_CLASS_WITH_CACHE(shortname,namespace,name) \
MonoClass* \
mono_class_get_##shortname##_class (void) \
static MonoClass *tmp_class; \
MonoClass *klass = tmp_class; \
if (!klass) { \
- klass = mono_class_from_name (mono_defaults.corlib, #namespace, #name); \
- g_assert (klass); \
+ klass = mono_class_load_from_name (mono_defaults.corlib, #namespace, #name); \
mono_memory_barrier (); \
tmp_class = klass; \
} \
return klass; \
}
-#define GENERATE_STATIC_GET_CLASS_WITH_CACHE(shortname,namespace,name) \
-static GENERATE_GET_CLASS_WITH_CACHE (shortname,namespace,name)
+#define GENERATE_TRY_GET_CLASS_WITH_CACHE(shortname,namespace,name) \
+MonoClass* \
+mono_class_try_get_##shortname##_class (void) \
+{ \
+ static volatile MonoClass *tmp_class; \
+ static volatile gboolean inited; \
+ MonoClass *klass = (MonoClass *)tmp_class; \
+ mono_memory_barrier (); \
+ if (!inited) { \
+ klass = mono_class_try_load_from_name (mono_defaults.corlib, #namespace, #name); \
+ tmp_class = klass; \
+ mono_memory_barrier (); \
+ inited = TRUE; \
+ } \
+ return klass; \
+}
+GENERATE_TRY_GET_CLASS_WITH_CACHE_DECL (safehandle)
#ifndef DISABLE_COM
void
mono_loader_unlock_if_inited (void);
-void
-mono_loader_set_error_assembly_load (const char *assembly_name, gboolean ref_only);
-
-void
-mono_loader_set_error_type_load (const char *class_name, const char *assembly_name);
-
-void
-mono_loader_set_error_method_load (const char *class_name, const char *member_name);
-
-void
-mono_loader_set_error_field_load (MonoClass *klass, const char *member_name);
-void
-mono_loader_set_error_bad_image (char *msg);
-
-MonoException *
-mono_loader_error_prepare_exception (MonoLoaderError *error);
-
-MonoLoaderError *
-mono_loader_get_last_error (void);
-
-void
-mono_loader_clear_error (void);
-
-void
-mono_loader_assert_no_error (void);
-
void
mono_reflection_init (void);
mono_lookup_jit_icall_symbol (const char *name);
gboolean
-mono_class_set_failure (MonoClass *klass, guint32 ex_type, void *ex_data);
-
-gpointer
-mono_class_get_exception_data (MonoClass *klass);
+mono_class_set_type_load_failure (MonoClass *klass, const char * fmt, ...) MONO_ATTR_FORMAT_PRINTF(2,3);
MonoException*
mono_class_get_exception_for_failure (MonoClass *klass);
mono_type_get_full_name (MonoClass *klass);
char *
-mono_method_get_name_full (MonoMethod *method, gboolean signature, MonoTypeNameFormat format);
+mono_method_get_name_full (MonoMethod *method, gboolean signature, gboolean ret, MonoTypeNameFormat format);
+
+char *
+mono_method_get_full_name (MonoMethod *method);
MonoArrayType *mono_dup_array_type (MonoImage *image, MonoArrayType *a);
MonoMethodSignature *mono_metadata_signature_deep_dup (MonoImage *image, MonoMethodSignature *sig);
MonoGenericContainer*
mono_class_get_generic_container (MonoClass *klass);
-MonoGenericClass*
-mono_class_get_generic_class (MonoClass *klass);
+gpointer
+mono_class_alloc (MonoClass *klass, int size);
+
+gpointer
+mono_class_alloc0 (MonoClass *klass, int size);
void
mono_class_alloc_ext (MonoClass *klass);
mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoType *type);
MonoVTable*
-mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error);
+mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error);
gboolean
mono_class_is_assignable_from_slow (MonoClass *target, MonoClass *candidate);
mono_unload_interface_id (MonoClass *klass);
GPtrArray*
-mono_class_get_methods_by_name (MonoClass *klass, const char *name, guint32 bflags, gboolean ignore_case, gboolean allow_ctors, MonoException **ex);
+mono_class_get_methods_by_name (MonoClass *klass, const char *name, guint32 bflags, gboolean ignore_case, gboolean allow_ctors, MonoError *error);
char*
mono_class_full_name (MonoClass *klass);
char *
make_generic_name_string (MonoImage *image, int num);
+MonoClass *
+mono_class_load_from_name (MonoImage *image, const char* name_space, const char *name) MONO_LLVM_INTERNAL;
+
+MonoClass*
+mono_class_try_load_from_name (MonoImage *image, const char* name_space, const char *name);
+
+void
+mono_error_set_for_class_failure (MonoError *orerror, const MonoClass *klass);
+
+gboolean
+mono_class_has_failure (const MonoClass *klass);
+
+/* Kind specific accessors */
+MonoGenericClass*
+mono_class_get_generic_class (MonoClass *klass);
+
+MonoGenericClass*
+mono_class_try_get_generic_class (MonoClass *klass);
+
+void
+mono_class_set_flags (MonoClass *klass, guint32 flags);
+
+MonoGenericContainer*
+mono_class_try_get_generic_container (MonoClass *klass);
+
+void
+mono_class_set_generic_container (MonoClass *klass, MonoGenericContainer *container);
+
+guint32
+mono_class_get_first_method_idx (MonoClass *klass);
+
+void
+mono_class_set_first_method_idx (MonoClass *klass, guint32 idx);
+
+guint32
+mono_class_get_first_field_idx (MonoClass *klass);
+
+void
+mono_class_set_first_field_idx (MonoClass *klass, guint32 idx);
+
+/*Now that everything has been defined, let's include the inline functions */
+#include <mono/metadata/class-inlines.h>
+
#endif /* __MONO_METADATA_CLASS_INTERNALS_H__ */
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* Copyright 2012 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 <string.h>
#include <stdlib.h>
#include <mono/metadata/image.h>
+#include <mono/metadata/image-internals.h>
#include <mono/metadata/assembly.h>
+#include <mono/metadata/assembly-internals.h>
#include <mono/metadata/metadata.h>
#include <mono/metadata/metadata-internals.h>
#include <mono/metadata/profiler-private.h>
gboolean mono_align_small_structs = FALSE;
/* Statistics */
-guint32 inflated_classes, inflated_classes_size, inflated_methods_size;
-guint32 classes_size, class_ext_size;
+guint32 inflated_classes_size, inflated_methods_size;
+guint32 classes_size, class_ext_size, class_ext_count;
+guint32 class_def_count, class_gtd_count, class_ginst_count, class_gparam_count, class_array_count, class_pointer_count;
/* Low level lock which protects data structures in this module */
static mono_mutex_t classes_mutex;
static void mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup);
static void mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gklass);
+static gboolean mono_class_set_failure (MonoClass *klass, MonoErrorBoxed *boxed_error);
+static gpointer mono_class_get_exception_data (const MonoClass *klass);
+
+
/*
We use gclass recording to allow recursive system f types to be referenced by a parent.
static GSList *gclass_recorded_list;
typedef gboolean (*gclass_record_func) (MonoClass*, void*);
+/* This TLS variable points to a GSList of classes which have setup_fields () executing */
+static MonoNativeTlsKey setup_fields_tls_id;
+
+static MonoNativeTlsKey init_pending_tls_id;
+
static inline void
classes_lock (void)
{
}
}
-/*
+/**
* mono_class_from_typeref:
* @image: a MonoImage
* @type_token: a TypeRef token
*
* Creates the MonoClass* structure representing the type defined by
* the typeref token valid inside @image.
- * Returns: the MonoClass* representing the typeref token, NULL ifcould
+ * Returns: The MonoClass* representing the typeref token, NULL ifcould
* not be loaded.
*/
MonoClass *
return klass;
}
+/**
+ * mono_class_from_typeref_checked:
+ * @image: a MonoImage
+ * @type_token: a TypeRef token
+ * @error: error return code, if any.
+ *
+ * Creates the MonoClass* structure representing the type defined by
+ * the typeref token valid inside @image.
+ *
+ * Returns: The MonoClass* representing the typeref token, NULL if it could
+ * not be loaded with the @error value filled with the information about the
+ * error.
+ */
MonoClass *
mono_class_from_typeref_checked (MonoImage *image, guint32 type_token, MonoError *error)
{
goto done;
case MONO_RESOLUTION_SCOPE_MODULEREF:
- module = mono_image_load_module (image, idx);
+ module = mono_image_load_module_checked (image, idx, error);
if (module)
res = mono_class_from_name_checked (module, nspace, name, error);
goto done;
}
enclosing = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | idx, error);
- if (!mono_error_ok (error))
- return NULL;
+ return_val_if_nok (error, NULL);
if (enclosing->nested_classes_inited && enclosing->ext) {
/* Micro-optimization: don't scan the metadata tables if enclosing is already inited */
done:
/* Generic case, should be avoided for when a better error is possible. */
if (!res && mono_error_ok (error)) {
- if (mono_loader_get_last_error ()) { /*FIXME plug the above to not leak errors*/
- mono_error_set_from_loader_error (error);
- } else {
- char *name = mono_class_name_from_token (image, type_token);
- char *assembly = mono_assembly_name_from_token (image, type_token);
- mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x", type_token);
- }
+ char *name = mono_class_name_from_token (image, type_token);
+ char *assembly = mono_assembly_name_from_token (image, type_token);
+ mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x", type_token);
}
- mono_loader_assert_no_error ();
return res;
}
}
if (is_recursed)
break;
- if (klass->generic_class) {
- MonoGenericClass *gclass = klass->generic_class;
+ if (mono_class_is_ginst (klass)) {
+ MonoGenericClass *gclass = mono_class_get_generic_class (klass);
MonoGenericInst *inst = gclass->context.class_inst;
MonoTypeNameFormat nested_format;
int i;
g_string_append_c (str, '>');
else
g_string_append_c (str, ']');
- } else if (klass->generic_container &&
+ } else if (mono_class_is_gtd (klass) &&
(format != MONO_TYPE_NAME_FORMAT_FULL_NAME) &&
(format != MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)) {
int i;
g_string_append_c (str, '<');
else
g_string_append_c (str, '[');
- for (i = 0; i < klass->generic_container->type_argc; i++) {
+ for (i = 0; i < mono_class_get_generic_container (klass)->type_argc; i++) {
if (i)
g_string_append_c (str, ',');
- g_string_append (str, mono_generic_container_get_param_info (klass->generic_container, i)->name);
+ g_string_append (str, mono_generic_container_get_param_info (mono_class_get_generic_container (klass), i)->name);
}
if (format == MONO_TYPE_NAME_FORMAT_IL)
g_string_append_c (str, '>');
* @format: the format for the return string.
*
*
- * Returns: the string representation in a number of formats:
+ * Returns: The string representation in a number of formats:
*
* if format is MONO_TYPE_NAME_FORMAT_REFLECTION, the return string is
* returned in the formatrequired by System.Reflection, this is the
* mono_type_get_full_name:
* @class: a class
*
- * Returns: the string representation for type as required by System.Reflection.
+ * Returns: The string representation for type as required by System.Reflection.
* The inverse of mono_reflection_parse_type ().
*/
char *
* mono_type_get_name:
* @type: a type
*
- * Returns: the string representation for type as it would be represented in IL code.
+ * Returns: The string representation for type as it would be represented in IL code.
*/
char*
mono_type_get_name (MonoType *type)
* mono_type_get_underlying_type:
* @type: a type
*
- * Returns: the MonoType for the underlying integer type if @type
+ * Returns: The MonoType for the underlying integer type if @type
* is an enum and byref is false, otherwise the type itself.
*/
MonoType*
return type;
}
-/*
+/**
* mono_class_is_open_constructed_type:
* @type: a type
*
- * Returns TRUE if type represents a generics open constructed type.
+ * Returns: TRUE if type represents a generics open constructed type.
* IOW, not all type parameters required for the instantiation have
* been provided or it's a generic type definition.
*
return t->data.generic_class->context.class_inst->is_open;
case MONO_TYPE_CLASS:
case MONO_TYPE_VALUETYPE:
- return t->data.klass->generic_container != NULL;
+ return mono_class_is_gtd (t->data.klass);
default:
return FALSE;
}
return NULL;
inst = mono_metadata_inflate_generic_inst (gclass->context.class_inst, context, error);
- if (!mono_error_ok (error))
- return NULL;
+ return_val_if_nok (error, NULL);
+
if (inst != gclass->context.class_inst)
gclass = mono_metadata_lookup_generic_class (gclass->container_class, inst, gclass->is_dynamic);
case MONO_TYPE_CLASS:
case MONO_TYPE_VALUETYPE: {
MonoClass *klass = type->data.klass;
- MonoGenericContainer *container = klass->generic_container;
+ MonoGenericContainer *container = mono_class_try_get_generic_container (klass);
MonoGenericInst *inst;
MonoGenericClass *gclass = NULL;
MonoType *nt;
/* We can't use context->class_inst directly, since it can have more elements */
inst = mono_metadata_inflate_generic_inst (container->context.class_inst, context, error);
- if (!mono_error_ok (error))
- return NULL;
+ return_val_if_nok (error, NULL);
+
if (inst == container->context.class_inst)
return NULL;
MonoGenericContext *
mono_class_get_context (MonoClass *klass)
{
- return klass->generic_class ? mono_generic_class_get_context (klass->generic_class) : NULL;
-}
-
-/*
- * mono_class_get_generic_container:
- *
- * Return the generic container of KLASS which should be a generic type definition.
- */
-MonoGenericContainer*
-mono_class_get_generic_container (MonoClass *klass)
-{
- g_assert (klass->is_generic);
-
- return klass->generic_container;
-}
-
-/*
- * mono_class_get_generic_class:
- *
- * Return the MonoGenericClass of KLASS, which should be a generic instance.
- */
-MonoGenericClass*
-mono_class_get_generic_class (MonoClass *klass)
-{
- g_assert (klass->is_inflated);
-
- return klass->generic_class;
+ MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
+ return gklass ? mono_generic_class_get_context (gklass) : NULL;
}
/*
if (context)
inflated = inflate_generic_type (image, type, context, error);
- if (!mono_error_ok (error))
- return NULL;
+ return_val_if_nok (error, NULL);
if (!inflated) {
MonoType *shared = mono_metadata_get_shared_type (type);
* If @type is a generic type and @context is not NULL, instantiate it using the
* generics context @context.
*
- * Returns: the instantiated type or a copy of @type. The returned MonoType is allocated
+ * Returns: The instantiated type or a copy of @type. The returned MonoType is allocated
* on the heap and is owned by the caller. Returns NULL on error.
*
* @deprecated Please use mono_class_inflate_generic_type_checked instead
MonoError error;
MonoType *result;
result = mono_class_inflate_generic_type_checked (type, context, &error);
-
- if (!mono_error_ok (&error)) {
- mono_error_cleanup (&error);
- return NULL;
- }
+ mono_error_cleanup (&error);
return result;
}
* If @type is a generic type and @context is not NULL, instantiate it using the
* generics context @context.
*
- * Returns: the instantiated type or a copy of @type. The returned MonoType is allocated
+ * Returns: The instantiated type or a copy of @type. The returned MonoType is allocated
* on the heap and is owned by the caller.
*/
MonoType*
mono_error_init (error);
if (context) {
inflated = inflate_generic_type (image, type, context, error);
- if (!mono_error_ok (error))
- return NULL;
+ return_val_if_nok (error, NULL);
}
if (!inflated)
return inflated;
}
+/*
+ * mono_class_inflate_generic_class:
+ *
+ * Inflate the class @gklass with @context. Set @error on failure.
+ */
MonoClass*
mono_class_inflate_generic_class_checked (MonoClass *gklass, MonoGenericContext *context, MonoError *error)
{
MonoType *inflated;
inflated = mono_class_inflate_generic_type_checked (&gklass->byval_arg, context, error);
- if (!mono_error_ok (error))
- return NULL;
+ return_val_if_nok (error, NULL);
res = mono_class_from_mono_type (inflated);
mono_metadata_free_type (inflated);
return res;
}
-/*
- * mono_class_inflate_generic_class:
- *
- * Inflate the class GKLASS with CONTEXT.
- */
-MonoClass*
-mono_class_inflate_generic_class (MonoClass *gklass, MonoGenericContext *context)
-{
- MonoError error;
- MonoClass *res;
-
- res = mono_class_inflate_generic_class_checked (gklass, context, &error);
- g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
-
- return res;
-}
-
-
static MonoGenericContext
inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflate_with, MonoError *error)
*
* Instantiate the generic method @method using the generics context @context.
*
- * Returns: the new instantiated method
+ * Returns: The new instantiated method
*/
MonoMethod *
mono_class_inflate_generic_method (MonoMethod *method, MonoGenericContext *context)
MonoMethodInflated *imethod = (MonoMethodInflated *) method;
tmp_context = inflate_generic_context (method_context, context, error);
- if (!mono_error_ok (error))
- return NULL;
+ return_val_if_nok (error, NULL);
+
context = &tmp_context;
if (mono_metadata_generic_context_equal (method_context, context))
*
*/
if (!((method->is_generic && context->method_inst) ||
- (method->klass->generic_container && context->class_inst)))
+ (mono_class_is_gtd (method->klass) && context->class_inst)))
return method;
iresult = g_new0 (MonoMethodInflated, 1);
iresult->context.method_inst = mono_method_get_generic_container (method)->context.method_inst;
if (!context->class_inst) {
- g_assert (!iresult->declaring->klass->generic_class);
- if (iresult->declaring->klass->generic_container)
- iresult->context.class_inst = iresult->declaring->klass->generic_container->context.class_inst;
- else if (iresult->declaring->klass->generic_class)
- iresult->context.class_inst = iresult->declaring->klass->generic_class->context.class_inst;
+ g_assert (!mono_class_is_ginst (iresult->declaring->klass));
+ if (mono_class_is_gtd (iresult->declaring->klass))
+ iresult->context.class_inst = mono_class_get_generic_container (iresult->declaring->klass)->context.class_inst;
}
/* This can happen with some callers like mono_object_get_virtual_method () */
- if (!iresult->declaring->klass->generic_container && !iresult->declaring->klass->generic_class)
+ if (!mono_class_is_gtd (iresult->declaring->klass) && !mono_class_is_ginst (iresult->declaring->klass))
iresult->context.class_inst = NULL;
MonoImageSet *set = mono_metadata_get_image_set_for_method (iresult);
result->sre_method = FALSE;
result->signature = NULL;
- if (!context->method_inst) {
+ if (method->wrapper_type) {
+ MonoMethodWrapper *mw = (MonoMethodWrapper*)method;
+ MonoMethodWrapper *resw = (MonoMethodWrapper*)result;
+ int len = GPOINTER_TO_INT (((void**)mw->method_data) [0]);
+
+ resw->method_data = (void **)g_malloc (sizeof (gpointer) * (len + 1));
+ memcpy (resw->method_data, mw->method_data, sizeof (gpointer) * (len + 1));
+ }
+
+ if (iresult->context.method_inst) {
/* Set the generic_container of the result to the generic_container of method */
MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
- if (generic_container) {
+ if (generic_container && iresult->context.method_inst == generic_container->context.method_inst) {
result->is_generic = 1;
mono_method_set_generic_container (result, generic_container);
}
}
- if (!klass_hint || !klass_hint->generic_class ||
- klass_hint->generic_class->container_class != method->klass ||
- klass_hint->generic_class->context.class_inst != context->class_inst)
- klass_hint = NULL;
+ if (klass_hint) {
+ MonoGenericClass *gklass_hint = mono_class_try_get_generic_class (klass_hint);
+ if (gklass_hint && (gklass_hint->container_class != method->klass || gklass_hint->context.class_inst != context->class_inst))
+ klass_hint = NULL;
+ }
- if (method->klass->generic_container)
+ if (mono_class_is_gtd (method->klass))
result->klass = klass_hint;
if (!result->klass) {
return NULL;
if (method->is_generic)
return &(mono_method_get_generic_container (method)->context);
- if (method->klass->generic_container)
- return &method->klass->generic_container->context;
+ if (mono_class_is_gtd (method->klass))
+ return &mono_class_get_generic_container (method->klass)->context;
return NULL;
}
MonoGenericContainer *container = NULL;
MonoImage *m = klass->image;
const int top = klass->field.count;
- int i;
+ int i, first_field_idx;
g_assert (klass->enumtype);
mono_error_init (error);
- if (klass->generic_container)
- container = klass->generic_container;
- else if (klass->generic_class) {
- MonoClass *gklass = klass->generic_class->container_class;
+ container = mono_class_try_get_generic_container (klass);
+ if (mono_class_is_ginst (klass)) {
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
- container = gklass->generic_container;
+ container = mono_class_get_generic_container (gklass);
g_assert (container);
}
/*
* Fetch all the field information.
*/
+ first_field_idx = mono_class_get_first_field_idx (klass);
for (i = 0; i < top; i++){
const char *sig;
guint32 cols [MONO_FIELD_SIZE];
- int idx = klass->field.first + i;
+ int idx = first_field_idx + i;
MonoType *ftype;
- /* klass->field.first and idx points into the fieldptr table */
+ /* first_field_idx and idx points into the fieldptr table */
mono_metadata_decode_table_row (m, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC) //no need to decode static fields
goto fail;
}
- ftype = mono_metadata_parse_type_full (m, container, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
- if (!ftype) {
- if (mono_loader_get_last_error ()) /*FIXME plug the above to not leak errors*/
- mono_error_set_from_loader_error (error);
- else
- mono_error_set_bad_image (error, klass->image, "Could not parse type for field signature %x", cols [MONO_FIELD_SIGNATURE]);
+ ftype = mono_metadata_parse_type_checked (m, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error);
+ if (!ftype)
goto fail;
- }
- if (klass->generic_class) {
+
+ if (mono_class_is_ginst (klass)) {
//FIXME do we leak here?
ftype = mono_class_inflate_generic_type_checked (ftype, mono_class_get_context (klass), error);
if (!mono_error_ok (error))
mono_error_set_type_load_class (error, klass, "Could not find base type");
fail:
- mono_loader_assert_no_error ();
return NULL;
}
/*
- * Checks for MonoClass::exception_type without resolving all MonoType's into MonoClass'es
+ * Checks for MonoClass::has_failure without resolving all MonoType's into MonoClass'es
*/
static gboolean
mono_type_has_exceptions (MonoType *type)
case MONO_TYPE_CLASS:
case MONO_TYPE_VALUETYPE:
case MONO_TYPE_SZARRAY:
- return type->data.klass->exception_type;
+ return mono_class_has_failure (type->data.klass);
case MONO_TYPE_ARRAY:
- return type->data.array->eklass->exception_type;
+ return mono_class_has_failure (type->data.array->eklass);
case MONO_TYPE_GENERICINST:
- return mono_generic_class_get_class (type->data.generic_class)->exception_type;
+ return mono_class_has_failure (mono_generic_class_get_class (type->data.generic_class));
default:
return FALSE;
}
}
+void
+mono_error_set_for_class_failure (MonoError *oerror, const MonoClass *klass)
+{
+ g_assert (mono_class_has_failure (klass));
+ MonoErrorBoxed *box = (MonoErrorBoxed*)mono_class_get_exception_data (klass);
+ mono_error_set_from_boxed (oerror, box);
+}
+
+
/*
* mono_class_alloc:
*
* Allocate memory for some data belonging to CLASS, either from its image's mempool,
* or from the heap.
*/
-static gpointer
+gpointer
mono_class_alloc (MonoClass *klass, int size)
{
- if (klass->generic_class)
- return mono_image_set_alloc (klass->generic_class->owner, size);
+ MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
+ if (gklass)
+ return mono_image_set_alloc (gklass->owner, size);
else
return mono_image_alloc (klass->image, size);
}
-static gpointer
+gpointer
mono_class_alloc0 (MonoClass *klass, int size)
{
gpointer res;
* mono_class_setup_basic_field_info:
* @class: The class to initialize
*
- * Initializes the klass->fields.
- * LOCKING: Assumes the loader lock is held.
+ * Initializes the following fields in MonoClass:
+ * * klass->fields (only field->parent and field->name)
+ * * klass->field.count
+ * * klass->first_field_idx
+ * LOCKING: Acquires the loader lock
*/
static void
mono_class_setup_basic_field_info (MonoClass *klass)
{
+ MonoGenericClass *gklass;
MonoClassField *field;
+ MonoClassField *fields;
MonoClass *gtd;
MonoImage *image;
int i, top;
if (klass->fields)
return;
- gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL;
+ gklass = mono_class_try_get_generic_class (klass);
+ gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL;
image = klass->image;
- top = klass->field.count;
- if (klass->generic_class && image_is_dynamic (klass->generic_class->container_class->image) && !klass->generic_class->container_class->wastypebuilder) {
+
+ if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) {
/*
* This happens when a generic instance of an unfinished generic typebuilder
* is used as an element type for creating an array type. We can't initialize
if (gtd) {
mono_class_setup_basic_field_info (gtd);
- top = gtd->field.count;
- klass->field.first = gtd->field.first;
+ mono_loader_lock ();
klass->field.count = gtd->field.count;
+ mono_loader_unlock ();
}
- klass->fields = (MonoClassField *)mono_class_alloc0 (klass, sizeof (MonoClassField) * top);
+ top = klass->field.count;
+
+ fields = (MonoClassField *)mono_class_alloc0 (klass, sizeof (MonoClassField) * top);
/*
* Fetch all the field information.
*/
- for (i = 0; i < top; i++){
- field = &klass->fields [i];
+ int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
+ for (i = 0; i < top; i++) {
+ field = &fields [i];
field->parent = klass;
if (gtd) {
field->name = mono_field_get_name (>d->fields [i]);
} else {
- int idx = klass->field.first + i;
- /* klass->field.first and idx points into the fieldptr table */
+ int idx = first_field_idx + i;
+ /* first_field_idx and idx points into the fieldptr table */
guint32 name_idx = mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_NAME);
/* The name is needed for fieldrefs */
field->name = mono_metadata_string_heap (image, name_idx);
}
}
+
+ mono_memory_barrier ();
+
+ mono_loader_lock ();
+ if (!klass->fields)
+ klass->fields = fields;
+ mono_loader_unlock ();
}
+/**
+ * mono_class_set_failure_causedby_class:
+ * @klass: the class that is failing
+ * @caused_by: the class that caused the failure
+ * @msg: Why @klass is failing.
+ *
+ * If @caused_by has a failure, sets a TypeLoadException failure on
+ * @klass with message "@msg, due to: {@caused_by message}".
+ *
+ * Returns: TRUE if a failiure was set, or FALSE if @caused_by doesn't have a failure.
+ */
+static gboolean
+mono_class_set_type_load_failure_causedby_class (MonoClass *klass, const MonoClass *caused_by, const gchar* msg)
+{
+ if (mono_class_has_failure (caused_by)) {
+ MonoError cause_error;
+ mono_error_init (&cause_error);
+ mono_error_set_for_class_failure (&cause_error, caused_by);
+ mono_class_set_type_load_failure (klass, "%s, due to: %s", msg, mono_error_get_message (&cause_error));
+ mono_error_cleanup (&cause_error);
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+
/**
* mono_class_setup_fields:
- * @class: The class to initialize
+ * @klass: The class to initialize
+ *
+ * Initializes klass->fields, computes class layout and sizes.
+ * typebuilder_setup_fields () is the corresponding function for dynamic classes.
+ * Sets the following fields in @klass:
+ * - all the fields initialized by mono_class_init_sizes ()
+ * - element_class/cast_class (for enums)
+ * - field->type/offset for all fields
+ * - fields_inited
*
- * Initializes the klass->fields.
- * LOCKING: Assumes the loader lock is held.
+ * LOCKING: Acquires the loader lock.
*/
-static void
+void
mono_class_setup_fields (MonoClass *klass)
{
MonoError error;
MonoImage *m = klass->image;
int top;
- guint32 layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
- int i, blittable = TRUE;
+ guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
+ int i;
guint32 real_size = 0;
guint32 packing_size = 0;
+ int instance_size;
gboolean explicit_size;
MonoClassField *field;
- MonoGenericContainer *container = NULL;
- MonoClass *gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL;
+ MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
+ MonoClass *gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL;
- /*
- * FIXME: We have a race condition here. It's possible that this function returns
- * to its caller with `instance_size` set to `0` instead of the actual size. This
- * is not a problem when the function is called recursively on the same class,
- * because the size will be initialized by the outer invocation. What follows is a
- * description of how it can occur in other cases, too. There it is a problem,
- * because it can lead to the GC being asked to allocate an object of size `0`,
- * which SGen chokes on. The race condition is triggered infrequently by
- * `tests/sgen-suspend.cs`.
- *
- * This function is called for a class whenever one of its subclasses is inited.
- * For example, it's called for every subclass of Object. What it does is this:
- *
- * if (klass->setup_fields_called)
- * return;
- * ...
- * klass->instance_size = 0;
- * ...
- * klass->setup_fields_called = 1;
- * ... critical point
- * klass->instance_size = actual_instance_size;
- *
- * The last two steps are sometimes reversed, but that only changes the way in which
- * the race condition works.
- *
- * Assume thread A goes through this function and makes it to the critical point.
- * Now thread B runs the function and, since `setup_fields_called` is set, returns
- * immediately, but `instance_size` is incorrect.
- *
- * The other case looks like this:
- *
- * if (klass->setup_fields_called)
- * return;
- * ... critical point X
- * klass->instance_size = 0;
- * ... critical point Y
- * klass->instance_size = actual_instance_size;
- * ...
- * klass->setup_fields_called = 1;
- *
- * Assume thread A goes through the function and makes it to critical point X. Now
- * thread B runs through the whole of the function, returning, assuming
- * `instance_size` is set. At that point thread A gets to run and makes it to
- * critical point Y, at which time `instance_size` is `0` again, invalidating thread
- * B's assumption.
- */
- if (klass->setup_fields_called)
+ if (klass->fields_inited)
return;
- if (klass->generic_class && image_is_dynamic (klass->generic_class->container_class->image) && !klass->generic_class->container_class->wastypebuilder) {
+ if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) {
/*
* This happens when a generic instance of an unfinished generic typebuilder
* is used as an element type for creating an array type. We can't initialize
if (gtd) {
mono_class_setup_fields (gtd);
- if (gtd->exception_type) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ if (mono_class_set_type_load_failure_causedby_class (klass, gtd, "Generic type definition failed"))
return;
- }
}
- klass->instance_size = 0;
- if (!klass->rank)
- klass->sizes.class_size = 0;
-
+ instance_size = 0;
if (klass->parent) {
/* For generic instances, klass->parent might not have been initialized */
mono_class_init (klass->parent);
- if (!klass->parent->size_inited) {
- mono_class_setup_fields (klass->parent);
- if (klass->parent->exception_type) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
- return;
- }
- }
- klass->instance_size += klass->parent->instance_size;
- klass->min_align = klass->parent->min_align;
- /* we use |= since it may have been set already */
- klass->has_references |= klass->parent->has_references;
- blittable = klass->parent->blittable;
+ mono_class_setup_fields (klass->parent);
+ if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Could not set up parent class"))
+ return;
+ instance_size = klass->parent->instance_size;
} else {
- klass->instance_size = sizeof (MonoObject);
- klass->min_align = 1;
+ instance_size = sizeof (MonoObject);
}
- /* We can't really enable 16 bytes alignment until the GC supports it.
- The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the
- boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type.
- Bug #506144 is an example of this issue.
-
- if (klass->simd_type)
- klass->min_align = 16;
- */
/* Get the real size */
explicit_size = mono_metadata_packing_from_typedef (klass->image, klass->type_token, &packing_size, &real_size);
+ if (explicit_size)
+ instance_size += real_size;
- if (explicit_size) {
- if ((packing_size & 0xffffff00) != 0) {
- char *err_msg = g_strdup_printf ("Could not load struct '%s' with packing size %d >= 256", klass->name, packing_size);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, err_msg);
- return;
- }
- klass->packing_size = packing_size;
- real_size += klass->instance_size;
- }
-
- if (!top) {
- if (explicit_size && real_size) {
- klass->instance_size = MAX (real_size, klass->instance_size);
- }
- klass->blittable = blittable;
- mono_memory_barrier ();
- klass->size_inited = 1;
- klass->fields_inited = 1;
- klass->setup_fields_called = 1;
+ /*
+ * This function can recursively call itself.
+ * Prevent infinite recursion by using a list in TLS.
+ */
+ GSList *init_list = (GSList *)mono_native_tls_get_value (setup_fields_tls_id);
+ if (g_slist_find (init_list, klass))
return;
- }
-
- if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT && !(mono_is_corlib_image (klass->image) && !strcmp (klass->name_space, "System") && !strcmp (klass->name, "ValueType")))
- blittable = FALSE;
-
- /* Prevent infinite loops if the class references itself */
- klass->setup_fields_called = 1;
-
- if (klass->generic_container) {
- container = klass->generic_container;
- } else if (gtd) {
- container = gtd->generic_container;
- g_assert (container);
- }
+ init_list = g_slist_prepend (init_list, klass);
+ mono_native_tls_set_value (setup_fields_tls_id, init_list);
/*
* Fetch all the field information.
*/
- for (i = 0; i < top; i++){
- int idx = klass->field.first + i;
+ int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
+ for (i = 0; i < top; i++) {
+ int idx = first_field_idx + i;
field = &klass->fields [i];
- field->parent = klass;
-
if (!field->type) {
mono_field_resolve_type (field, &error);
if (!mono_error_ok (&error)) {
/*mono_field_resolve_type already failed class*/
mono_error_cleanup (&error);
- return;
+ break;
}
if (!field->type)
g_error ("could not resolve %s:%s\n", mono_type_get_full_name(klass), field->name);
if (mono_field_is_deleted (field))
continue;
- if (gtd) {
- MonoClassField *gfield = >d->fields [i];
- field->offset = gfield->offset;
- } else {
- if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
- guint32 offset;
- mono_metadata_field_info (m, idx, &offset, NULL, NULL);
- field->offset = offset;
+ if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
+ guint32 uoffset;
+ mono_metadata_field_info (m, idx, &uoffset, NULL, NULL);
+ int offset = uoffset;
- if (field->offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Missing field layout info for %s", field->name));
- break;
- }
- if (field->offset < -1) { /*-1 is used to encode special static fields */
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Invalid negative field offset %d for %s", field->offset, field->name));
- break;
- }
- if (klass->generic_container) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Generic class cannot have explicit layout."));
- break;
- }
+ if (offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
+ mono_class_set_type_load_failure (klass, "Missing field layout info for %s", field->name);
+ break;
}
- }
-
- /* Only do these checks if we still think this type is blittable */
- if (blittable && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
- if (field->type->byref || MONO_TYPE_IS_REFERENCE (field->type)) {
- blittable = FALSE;
- } else {
- MonoClass *field_class = mono_class_from_mono_type (field->type);
- if (field_class) {
- mono_class_setup_fields (field_class);
- if (field_class->exception_type) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
- break;
- }
- }
- if (!field_class || !field_class->blittable)
- blittable = FALSE;
+ if (offset < -1) { /*-1 is used to encode special static fields */
+ mono_class_set_type_load_failure (klass, "Field '%s' has a negative offset %d", field->name, offset);
+ break;
+ }
+ if (mono_class_is_gtd (klass)) {
+ mono_class_set_type_load_failure (klass, "Generic class cannot have explicit layout.");
+ break;
}
}
-
- if (klass->enumtype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
- klass->cast_class = klass->element_class = mono_class_from_mono_type (field->type);
- blittable = klass->element_class->blittable;
- }
-
if (mono_type_has_exceptions (field->type)) {
char *class_name = mono_type_get_full_name (klass);
char *type_name = mono_type_full_name (field->type);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ mono_class_set_type_load_failure (klass, "");
g_warning ("Invalid type %s for instance field %s:%s", type_name, class_name, field->name);
g_free (class_name);
g_free (type_name);
/* The def_value of fields is compute lazily during vtable creation */
}
- if (klass == mono_defaults.string_class)
- blittable = FALSE;
+ if (!mono_class_has_failure (klass))
+ mono_class_layout_fields (klass, instance_size, packing_size, FALSE);
- klass->blittable = blittable;
+ init_list = g_slist_remove (init_list, klass);
+ mono_native_tls_set_value (setup_fields_tls_id, init_list);
+}
- if (klass->enumtype && !mono_class_enum_basetype (klass)) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
- return;
+static void
+init_sizes_with_info (MonoClass *klass, MonoCachedClassInfo *cached_info)
+{
+ if (cached_info) {
+ klass->instance_size = cached_info->instance_size;
+ klass->sizes.class_size = cached_info->class_size;
+ klass->packing_size = cached_info->packing_size;
+ klass->min_align = cached_info->min_align;
+ klass->blittable = cached_info->blittable;
+ klass->has_references = cached_info->has_references;
+ klass->has_static_refs = cached_info->has_static_refs;
+ klass->no_special_static_fields = cached_info->no_special_static_fields;
}
- if (explicit_size && real_size) {
- klass->instance_size = MAX (real_size, klass->instance_size);
+ else {
+ if (!klass->size_inited)
+ mono_class_setup_fields (klass);
}
-
- if (klass->exception_type)
- return;
- mono_class_layout_fields (klass);
-
- /*valuetypes can't be neither bigger than 1Mb or empty. */
- if (klass->valuetype && (klass->instance_size <= 0 || klass->instance_size > (0x100000 + sizeof (MonoObject))))
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
-
- mono_memory_barrier ();
- klass->fields_inited = 1;
}
+/*
-/**
- * mono_class_setup_fields_locking:
- * @class: The class to initialize
+ * mono_class_init_sizes:
*
- * Initializes the klass->fields array of fields.
- * Aquires the loader lock.
- */
-void
-mono_class_setup_fields_locking (MonoClass *klass)
-{
- /* This can be checked without locks */
- if (klass->fields_inited)
- return;
- mono_loader_lock ();
- mono_class_setup_fields (klass);
- mono_loader_unlock ();
-}
-
-/*
- * mono_class_has_references:
+ * Initializes the size related fields of @klass without loading all field data if possible.
+ * Sets the following fields in @klass:
+ * - instance_size
+ * - sizes.class_size
+ * - packing_size
+ * - min_align
+ * - blittable
+ * - has_references
+ * - has_static_refs
+ * - size_inited
+ * Can fail the class.
*
- * Returns whenever @klass->has_references is set, initializing it if needed.
- * Aquires the loader lock.
+ * LOCKING: Acquires the loader lock.
*/
-static gboolean
-mono_class_has_references (MonoClass *klass)
+static void
+mono_class_init_sizes (MonoClass *klass)
{
- if (klass->init_pending) {
- /* Be conservative */
- return TRUE;
- } else {
- mono_class_init (klass);
+ MonoCachedClassInfo cached_info;
+ gboolean has_cached_info;
- return klass->has_references;
- }
+ has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
+
+ init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
}
/*
return type;
}
+static gboolean
+class_has_references (MonoClass *klass)
+{
+ mono_class_init_sizes (klass);
+
+ /*
+ * has_references is not set if this is called recursively, but this is not a problem since this is only used
+ * during field layout, and instance fields are initialized before static fields, and instance fields can't
+ * embed themselves.
+ */
+ return klass->has_references;
+}
+
static gboolean
type_has_references (MonoClass *klass, MonoType *ftype)
{
- if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (klass, ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
+ if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (klass, ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && class_has_references (mono_class_from_mono_type (ftype)))))
return TRUE;
if (!ftype->byref && (ftype->type == MONO_TYPE_VAR || ftype->type == MONO_TYPE_MVAR)) {
MonoGenericParam *gparam = ftype->data.generic_param;
if (gparam->gshared_constraint)
- return mono_class_has_references (mono_class_from_mono_type (gparam->gshared_constraint));
+ return class_has_references (mono_class_from_mono_type (gparam->gshared_constraint));
}
return FALSE;
}
/*
* mono_class_layout_fields:
* @class: a class
+ * @base_instance_size: base instance size
+ * @packing_size:
*
- * Compute the placement of fields inside an object or struct, according to
- * the layout rules and set the following fields in @class:
- * - has_references (if the class contains instance references firled or structs that contain references)
- * - has_static_refs (same, but for static fields)
- * - instance_size (size of the object in memory)
- * - class_size (size needed for the static fields)
- * - size_inited (flag set when the instance_size is set)
+ * This contains the common code for computing the layout of classes and sizes.
+ * This should only be called from mono_class_setup_fields () and
+ * typebuilder_setup_fields ().
*
- * LOCKING: this is supposed to be called with the loader lock held.
+ * LOCKING: Acquires the loader lock
*/
void
-mono_class_layout_fields (MonoClass *klass)
+mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_size, gboolean sre)
{
int i;
const int top = klass->field.count;
- guint32 layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
+ guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
guint32 pass, passes, real_size;
gboolean gc_aware_layout = FALSE;
gboolean has_static_fields = FALSE;
+ gboolean has_references = FALSE;
+ gboolean has_static_refs = FALSE;
MonoClassField *field;
+ gboolean blittable;
+ int instance_size = base_instance_size;
+ int class_size, min_align;
+ int *field_offsets;
+
+ /*
+ * We want to avoid doing complicated work inside locks, so we compute all the required
+ * information and write it to @klass inside a lock.
+ */
+ if (klass->fields_inited)
+ return;
+
+ if ((packing_size & 0xffffff00) != 0) {
+ mono_class_set_type_load_failure (klass, "Could not load struct '%s' with packing size %d >= 256", klass->name, packing_size);
+ return;
+ }
+
+ if (klass->parent) {
+ min_align = klass->parent->min_align;
+ /* we use | since it may have been set already */
+ has_references = klass->has_references | klass->parent->has_references;
+ } else {
+ min_align = 1;
+ }
+ /* We can't really enable 16 bytes alignment until the GC supports it.
+ The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the
+ boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type.
+ Bug #506144 is an example of this issue.
+
+ if (klass->simd_type)
+ min_align = 16;
+ */
/*
* When we do generic sharing we need to have layout
* container), so we don't return in that case anymore.
*/
+ if (klass->enumtype) {
+ for (i = 0; i < top; i++) {
+ field = &klass->fields [i];
+ if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
+ klass->cast_class = klass->element_class = mono_class_from_mono_type (field->type);
+ break;
+ }
+ }
+
+ if (!mono_class_enum_basetype (klass)) {
+ mono_class_set_type_load_failure (klass, "The enumeration's base type is invalid.");
+ return;
+ }
+ }
+
/*
* Enable GC aware auto layout: in this mode, reference
* fields are grouped together inside objects, increasing collector
gc_aware_layout = TRUE;
}
- /* Compute klass->has_references */
- /*
- * Process non-static fields first, since static fields might recursively
- * refer to the class itself.
- */
+ /* Compute klass->blittable */
+ blittable = TRUE;
+ if (klass->parent)
+ blittable = klass->parent->blittable;
+ if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT && !(mono_is_corlib_image (klass->image) && !strcmp (klass->name_space, "System") && !strcmp (klass->name, "ValueType")) && top)
+ blittable = FALSE;
for (i = 0; i < top; i++) {
- MonoType *ftype;
-
field = &klass->fields [i];
- if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
- ftype = mono_type_get_underlying_type (field->type);
- ftype = mono_type_get_basic_type_from_generic (ftype);
- if (type_has_references (klass, ftype))
- klass->has_references = TRUE;
+ if (mono_field_is_deleted (field))
+ continue;
+ if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
+ continue;
+ if (blittable) {
+ if (field->type->byref || MONO_TYPE_IS_REFERENCE (field->type)) {
+ blittable = FALSE;
+ } else {
+ MonoClass *field_class = mono_class_from_mono_type (field->type);
+ if (field_class) {
+ mono_class_setup_fields (field_class);
+ if (mono_class_has_failure (field_class)) {
+ MonoError field_error;
+ mono_error_init (&field_error);
+ mono_error_set_for_class_failure (&field_error, field_class);
+ mono_class_set_type_load_failure (klass, "Could not set up field '%s' due to: %s", field->name, mono_error_get_message (&field_error));
+ mono_error_cleanup (&field_error);
+ break;
+ }
+ }
+ if (!field_class || !field_class->blittable)
+ blittable = FALSE;
+ }
}
+ if (klass->enumtype)
+ blittable = klass->element_class->blittable;
}
+ if (mono_class_has_failure (klass))
+ return;
+ if (klass == mono_defaults.string_class)
+ blittable = FALSE;
+ /* Compute klass->has_references */
+ /*
+ * Process non-static fields first, since static fields might recursively
+ * refer to the class itself.
+ */
for (i = 0; i < top; i++) {
MonoType *ftype;
field = &klass->fields [i];
- if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
+ if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
ftype = mono_type_get_underlying_type (field->type);
ftype = mono_type_get_basic_type_from_generic (ftype);
if (type_has_references (klass, ftype))
- klass->has_static_refs = TRUE;
- }
- }
-
- for (i = 0; i < top; i++) {
- MonoType *ftype;
-
- field = &klass->fields [i];
-
- ftype = mono_type_get_underlying_type (field->type);
- ftype = mono_type_get_basic_type_from_generic (ftype);
- if (type_has_references (klass, ftype)) {
- if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
- klass->has_static_refs = TRUE;
- else
- klass->has_references = TRUE;
+ has_references = TRUE;
}
}
/*
* Compute field layout and total size (not considering static fields)
*/
-
+ field_offsets = g_new0 (int, top);
+ int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
switch (layout) {
case TYPE_ATTRIBUTE_AUTO_LAYOUT:
case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
-
if (gc_aware_layout)
passes = 2;
else
if (klass->parent) {
mono_class_setup_fields (klass->parent);
- if (klass->parent->exception_type) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Cannot initialize parent class"))
return;
- }
real_size = klass->parent->instance_size;
} else {
real_size = sizeof (MonoObject);
}
}
- if ((top == 1) && (klass->instance_size == sizeof (MonoObject)) &&
+ if ((top == 1) && (instance_size == sizeof (MonoObject)) &&
(strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) {
/* This field is a hack inserted by MCS to empty structures */
continue;
size = mono_type_size (field->type, &align);
/* FIXME (LAMESPEC): should we also change the min alignment according to pack? */
- align = klass->packing_size ? MIN (klass->packing_size, align): align;
+ align = packing_size ? MIN (packing_size, align): align;
/* if the field has managed references, we need to force-align it
* see bug #77788
*/
if (type_has_references (klass, ftype))
align = MAX (align, sizeof (gpointer));
- klass->min_align = MAX (align, klass->min_align);
- field->offset = real_size;
+ min_align = MAX (align, min_align);
+ field_offsets [i] = real_size;
if (align) {
- field->offset += align - 1;
- field->offset &= ~(align - 1);
+ field_offsets [i] += align - 1;
+ field_offsets [i] &= ~(align - 1);
}
/*TypeBuilders produce all sort of weird things*/
- g_assert (image_is_dynamic (klass->image) || field->offset > 0);
- real_size = field->offset + size;
+ g_assert (image_is_dynamic (klass->image) || field_offsets [i] > 0);
+ real_size = field_offsets [i] + size;
}
- klass->instance_size = MAX (real_size, klass->instance_size);
+ instance_size = MAX (real_size, instance_size);
- if (klass->instance_size & (klass->min_align - 1)) {
- klass->instance_size += klass->min_align - 1;
- klass->instance_size &= ~(klass->min_align - 1);
+ if (instance_size & (min_align - 1)) {
+ instance_size += min_align - 1;
+ instance_size &= ~(min_align - 1);
}
}
break;
continue;
size = mono_type_size (field->type, &align);
- align = klass->packing_size ? MIN (klass->packing_size, align): align;
- klass->min_align = MAX (align, klass->min_align);
+ align = packing_size ? MIN (packing_size, align): align;
+ min_align = MAX (align, min_align);
- /*
- * When we get here, field->offset is already set by the
- * loader (for either runtime fields or fields loaded from metadata).
- * The offset is from the start of the object: this works for both
- * classes and valuetypes.
- */
- field->offset += sizeof (MonoObject);
+ if (sre) {
+ /* Already set by typebuilder_setup_fields () */
+ field_offsets [i] = field->offset + sizeof (MonoObject);
+ } else {
+ int idx = first_field_idx + i;
+ guint32 offset;
+ mono_metadata_field_info (klass->image, idx, &offset, NULL, NULL);
+ field_offsets [i] = offset + sizeof (MonoObject);
+ }
ftype = mono_type_get_underlying_type (field->type);
ftype = mono_type_get_basic_type_from_generic (ftype);
if (type_has_references (klass, ftype)) {
- if (field->offset % sizeof (gpointer)) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ if (field_offsets [i] % sizeof (gpointer)) {
+ mono_class_set_type_load_failure (klass, "Reference typed field '%s' has explicit offset that is not pointer-size aligned.", field->name);
}
}
/*
* Calc max size.
*/
- real_size = MAX (real_size, size + field->offset);
+ real_size = MAX (real_size, size + field_offsets [i]);
}
if (klass->has_references) {
continue;
ftype = mono_type_get_underlying_type (field->type);
if (MONO_TYPE_IS_REFERENCE (ftype))
- ref_bitmap [field->offset / sizeof (gpointer)] = 1;
+ ref_bitmap [field_offsets [i] / sizeof (gpointer)] = 1;
}
for (i = 0; i < top; i++) {
field = &klass->fields [i];
// FIXME: Too much code does this
#if 0
- if (!MONO_TYPE_IS_REFERENCE (field->type) && ref_bitmap [field->offset / sizeof (gpointer)]) {
- char *err_msg = g_strdup_printf ("Could not load type '%s' because it contains an object field at offset %d that is incorrectly aligned or overlapped by a non-object field.", klass->name, field->offset);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, err_msg);
+ if (!MONO_TYPE_IS_REFERENCE (field->type) && ref_bitmap [field_offsets [i] / sizeof (gpointer)]) {
+ mono_class_set_type_load_failure (klass, "Could not load type '%s' because it contains an object field at offset %d that is incorrectly aligned or overlapped by a non-object field.", klass->name, field_offsets [i]);
}
#endif
}
g_free (ref_bitmap);
}
- klass->instance_size = MAX (real_size, klass->instance_size);
- if (klass->instance_size & (klass->min_align - 1)) {
- klass->instance_size += klass->min_align - 1;
- klass->instance_size &= ~(klass->min_align - 1);
+ instance_size = MAX (real_size, instance_size);
+ if (instance_size & (min_align - 1)) {
+ instance_size += min_align - 1;
+ instance_size &= ~(min_align - 1);
}
break;
}
* performance, and since the JIT memset/memcpy code assumes this and generates
* unaligned accesses otherwise. See #78990 for a testcase.
*/
- if (mono_align_small_structs) {
- if (klass->instance_size <= sizeof (MonoObject) + sizeof (gpointer))
- klass->min_align = MAX (klass->min_align, klass->instance_size - sizeof (MonoObject));
+ if (mono_align_small_structs && top) {
+ if (instance_size <= sizeof (MonoObject) + sizeof (gpointer))
+ min_align = MAX (min_align, instance_size - sizeof (MonoObject));
}
}
+ if (klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
+ instance_size = sizeof (MonoObject) + mono_type_stack_size_internal (&klass->byval_arg, NULL, TRUE);
+ else if (klass->byval_arg.type == MONO_TYPE_PTR)
+ instance_size = sizeof (MonoObject) + sizeof (gpointer);
+
+ /* Publish the data */
+ mono_loader_lock ();
+ if (klass->instance_size && !klass->image->dynamic) {
+ /* Might be already set using cached info */
+ g_assert (klass->instance_size == instance_size);
+ } else {
+ klass->instance_size = instance_size;
+ }
+ klass->blittable = blittable;
+ klass->has_references = has_references;
+ klass->packing_size = packing_size;
+ klass->min_align = min_align;
+ for (i = 0; i < top; ++i) {
+ field = &klass->fields [i];
+ if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
+ klass->fields [i].offset = field_offsets [i];
+ }
+
mono_memory_barrier ();
klass->size_inited = 1;
+ mono_loader_unlock ();
/*
* Compute static field layout and size
+ * Static fields can reference the class itself, so this has to be
+ * done after instance_size etc. are initialized.
*/
- for (i = 0; i < top; i++){
+ class_size = 0;
+ for (i = 0; i < top; i++) {
gint32 align;
guint32 size;
continue;
if (mono_type_has_exceptions (field->type)) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ mono_class_set_type_load_failure (klass, "Field '%s' has an invalid type.", field->name);
break;
}
has_static_fields = TRUE;
size = mono_type_size (field->type, &align);
- field->offset = klass->sizes.class_size;
+ field_offsets [i] = class_size;
/*align is always non-zero here*/
- field->offset += align - 1;
- field->offset &= ~(align - 1);
- klass->sizes.class_size = field->offset + size;
+ field_offsets [i] += align - 1;
+ field_offsets [i] &= ~(align - 1);
+ class_size = field_offsets [i] + size;
}
- if (has_static_fields && klass->sizes.class_size == 0)
+ if (has_static_fields && class_size == 0)
/* Simplify code which depends on class_size != 0 if the class has static fields */
- klass->sizes.class_size = 8;
+ class_size = 8;
+
+ /* Compute klass->has_static_refs */
+ has_static_refs = FALSE;
+ for (i = 0; i < top; i++) {
+ MonoType *ftype;
+
+ field = &klass->fields [i];
+
+ if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
+ ftype = mono_type_get_underlying_type (field->type);
+ ftype = mono_type_get_basic_type_from_generic (ftype);
+ if (type_has_references (klass, ftype))
+ has_static_refs = TRUE;
+ }
+ }
+
+ /*valuetypes can't be neither bigger than 1Mb or empty. */
+ if (klass->valuetype && (klass->instance_size <= 0 || klass->instance_size > (0x100000 + sizeof (MonoObject))))
+ mono_class_set_type_load_failure (klass, "Value type instance size (%d) cannot be zero, negative, or bigger than 1Mb", klass->instance_size);
+
+ /* Publish the data */
+ mono_loader_lock ();
+ if (!klass->rank)
+ klass->sizes.class_size = class_size;
+ klass->has_static_refs = has_static_refs;
+ for (i = 0; i < top; ++i) {
+ field = &klass->fields [i];
+
+ if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
+ field->offset = field_offsets [i];
+ }
+
+ mono_memory_barrier ();
+ klass->fields_inited = 1;
+ mono_loader_unlock ();
+
+ g_free (field_offsets);
}
static MonoMethod*
* Methods belonging to an interface are assigned a sequential slot starting
* from 0.
*
- * On failure this function sets klass->exception_type
+ * On failure this function sets klass->has_failure and stores a MonoErrorBoxed with details
*/
void
mono_class_setup_methods (MonoClass *klass)
if (klass->methods)
return;
- if (klass->generic_class) {
+ if (mono_class_is_ginst (klass)) {
MonoError error;
- MonoClass *gklass = klass->generic_class->container_class;
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
mono_class_init (gklass);
- if (!gklass->exception_type)
+ if (!mono_class_has_failure (gklass))
mono_class_setup_methods (gklass);
- if (gklass->exception_type) {
- /* FIXME make exception_data less opaque so it's possible to dup it here */
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
+ if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
return;
- }
/* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */
count = gklass->method.count;
gklass->methods [i], klass, mono_class_get_context (klass), &error);
if (!mono_error_ok (&error)) {
char *method = mono_method_full_name (gklass->methods [i], TRUE);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Could not inflate method %s due to %s", method, mono_error_get_message (&error)));
+ mono_class_set_type_load_failure (klass, "Could not inflate method %s due to %s", method, mono_error_get_message (&error));
g_free (method);
mono_error_cleanup (&error);
for (i = 0; i < klass->interface_count; i++)
setup_generic_array_ifaces (klass, klass->interfaces [i], methods, first_generic + i * count_generic);
- } else {
+ } else if (mono_class_has_static_metadata (klass)) {
MonoError error;
+ int first_idx = mono_class_get_first_method_idx (klass);
count = klass->method.count;
methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * count);
for (i = 0; i < count; ++i) {
- int idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, klass->method.first + i + 1);
+ int idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, first_idx + i + 1);
methods [i] = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | idx, klass, NULL, &error);
if (!methods [i]) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Could not load method %d due to %s", i, mono_error_get_message (&error)));
+ mono_class_set_type_load_failure (klass, "Could not load method %d due to %s", i, mono_error_get_message (&error));
mono_error_cleanup (&error);
}
}
+ } else {
+ methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * 1);
+ count = 0;
}
if (MONO_CLASS_IS_INTERFACE (klass)) {
mono_class_get_method_by_index (MonoClass *klass, int index)
{
MonoError error;
+
+ MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
/* Avoid calling setup_methods () if possible */
- if (klass->generic_class && !klass->methods) {
- MonoClass *gklass = klass->generic_class->container_class;
+ if (gklass && !klass->methods) {
MonoMethod *m;
m = mono_class_inflate_generic_method_full_checked (
- gklass->methods [index], klass, mono_class_get_context (klass), &error);
+ gklass->container_class->methods [index], klass, mono_class_get_context (klass), &error);
g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
/*
* If setup_methods () is called later for this class, no duplicates are created,
return m;
} else {
mono_class_setup_methods (klass);
- if (klass->exception_type) /*FIXME do proper error handling*/
+ if (mono_class_has_failure (klass)) /*FIXME do proper error handling*/
return NULL;
g_assert (index >= 0 && index < klass->method.count);
return klass->methods [index];
MonoMethod*
mono_class_get_inflated_method (MonoClass *klass, MonoMethod *method)
{
- MonoClass *gklass = klass->generic_class->container_class;
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
int i;
g_assert (method->klass == gklass);
mono_class_setup_methods (gklass);
- g_assert (!gklass->exception_type); /*FIXME do proper error handling*/
+ g_assert (!mono_class_has_failure (gklass)); /*FIXME do proper error handling*/
for (i = 0; i < gklass->method.count; ++i) {
if (gklass->methods [i] == method) {
return klass->parent->vtable [offset];
}
- if (klass->generic_class) {
+ if (mono_class_is_ginst (klass)) {
MonoError error;
- MonoClass *gklass = klass->generic_class->container_class;
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
mono_class_setup_vtable (gklass);
m = gklass->vtable [offset];
g_assert (mono_error_ok (&error)); /* FIXME don't swallow this error */
} else {
mono_class_setup_vtable (klass);
- if (klass->exception_type)
+ if (mono_class_has_failure (klass))
return NULL;
m = klass->vtable [offset];
}
if (klass->ext && klass->ext->properties)
return;
- if (klass->generic_class) {
- MonoClass *gklass = klass->generic_class->container_class;
+ if (mono_class_is_ginst (klass)) {
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
mono_class_init (gklass);
mono_class_setup_properties (gklass);
- if (gklass->exception_type) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
+ if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
return;
- }
properties = mono_class_new0 (klass, MonoProperty, gklass->ext->property.count + 1);
if (count) {
mono_class_setup_methods (klass);
- if (klass->exception_type)
+ if (mono_class_has_failure (klass))
return;
}
properties [i - first].name = mono_metadata_string_heap (klass->image, cols [MONO_PROPERTY_NAME]);
startm = mono_metadata_methods_from_property (klass->image, i, &endm);
+ int first_idx = mono_class_get_first_method_idx (klass);
for (j = startm; j < endm; ++j) {
MonoMethod *method;
method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, &error);
mono_error_cleanup (&error); /* FIXME don't swallow this error */
} else {
- method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - klass->method.first];
+ method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
}
switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
if (klass->ext && klass->ext->events)
return;
- if (klass->generic_class) {
- MonoClass *gklass = klass->generic_class->container_class;
+ if (mono_class_is_ginst (klass)) {
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
MonoGenericContext *context = NULL;
mono_class_setup_events (gklass);
- if (gklass->exception_type) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
+ if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
return;
- }
first = gklass->ext->event.first;
count = gklass->ext->event.count;
if (count) {
mono_class_setup_methods (klass);
- if (klass->exception_type) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
+ if (mono_class_has_failure (klass)) {
return;
}
}
event->name = mono_metadata_string_heap (klass->image, cols [MONO_EVENT_NAME]);
startm = mono_metadata_methods_from_event (klass->image, i, &endm);
+ int first_idx = mono_class_get_first_method_idx (klass);
for (j = startm; j < endm; ++j) {
MonoMethod *method;
method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, &error);
mono_error_cleanup (&error); /* FIXME don't swallow this error */
} else {
- method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - klass->method.first];
+ method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
}
switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
}
}
-/*
+/**
* mono_get_unique_iid:
* @class: interface
*
* Assign a unique integer ID to the interface represented by @class.
* The ID will positive and as small as possible.
* LOCKING: Acquires the classes lock.
- * Returns: the new ID.
+ * Returns: The new ID.
*/
- static guint
+ static guint32
mono_get_unique_iid (MonoClass *klass)
{
int iid;
}
mono_bitset_set (global_interface_bitset, iid);
/* set the bit also in the per-image set */
- if (!klass->generic_class) {
+ if (!mono_class_is_ginst (klass)) {
if (klass->image->interface_bitset) {
if (iid >= mono_bitset_size (klass->image->interface_bitset)) {
MonoBitSet *new_set = mono_bitset_clone (klass->image->interface_bitset, iid + 1);
if (mono_print_vtable) {
int generic_id;
char *type_name = mono_type_full_name (&klass->byval_arg);
- if (klass->generic_class && !klass->generic_class->context.class_inst->is_open) {
- generic_id = klass->generic_class->context.class_inst->id;
+ MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
+ if (gklass && !gklass->context.class_inst->is_open) {
+ generic_id = gklass->context.class_inst->id;
g_assert (generic_id != 0);
} else {
generic_id = 0;
}
#endif
- g_assert (iid <= 65535);
+ /* I've confirmed iids safe past 16 bits, however bitset code uses a signed int while testing.
+ * Once this changes, it should be safe for us to allow 2^32-1 interfaces, until then 2^31-2 is the max. */
+ g_assert (iid < INT_MAX);
return iid;
}
MonoClass *ic;
mono_class_setup_interfaces (klass, error);
- if (!mono_error_ok (error))
- return;
+ return_if_nok (error);
for (i = 0; i < klass->interface_count; i++) {
ic = klass->interfaces [i];
*res = g_ptr_array_new ();
g_ptr_array_add (*res, ic);
mono_class_init (ic);
- if (ic->exception_type) {
+ if (mono_class_has_failure (ic)) {
mono_error_set_type_load_class (error, ic, "Error Loading class");
return;
}
collect_implemented_interfaces_aux (ic, res, error);
- if (!mono_error_ok (error))
- return;
+ return_if_nok (error);
}
}
}
}
-/*
+/**
* mono_class_interface_offset_with_variance:
*
* Return the interface offset of @itf in @klass. Sets @non_exact_match to TRUE if the match required variance check
valuetype_types [1] = mono_class_from_mono_type (mono_class_enum_basetype (eclass));
}
+static GENERATE_GET_CLASS_WITH_CACHE (generic_icollection, System.Collections.Generic, ICollection`1)
+static GENERATE_GET_CLASS_WITH_CACHE (generic_ienumerable, System.Collections.Generic, IEnumerable`1)
+static GENERATE_GET_CLASS_WITH_CACHE (generic_ienumerator, System.Collections.Generic, IEnumerator`1)
+static GENERATE_GET_CLASS_WITH_CACHE (generic_ireadonlylist, System.Collections.Generic, IReadOnlyList`1)
+static GENERATE_GET_CLASS_WITH_CACHE (generic_ireadonlycollection, System.Collections.Generic, IReadOnlyCollection`1)
+
/* this won't be needed once bug #325495 is completely fixed
* though we'll need something similar to know which interfaces to allow
* in arrays when they'll be lazyly created
get_implicit_generic_array_interfaces (MonoClass *klass, int *num, int *is_enumerator)
{
MonoClass *eclass = klass->element_class;
- static MonoClass* generic_icollection_class = NULL;
- static MonoClass* generic_ienumerable_class = NULL;
- static MonoClass* generic_ienumerator_class = NULL;
- static MonoClass* generic_ireadonlylist_class = NULL;
- static MonoClass* generic_ireadonlycollection_class = NULL;
+ MonoClass* generic_icollection_class;
+ MonoClass* generic_ienumerable_class;
+ MonoClass* generic_ienumerator_class;
+ MonoClass* generic_ireadonlylist_class;
+ MonoClass* generic_ireadonlycollection_class;
MonoClass *valuetype_types[2] = { NULL, NULL };
MonoClass **interfaces = NULL;
int i, nifaces, interface_count, real_count, original_rank;
eclass_is_valuetype = FALSE;
original_rank = eclass->rank;
if (klass->byval_arg.type != MONO_TYPE_SZARRAY) {
- if (klass->generic_class && klass->nested_in == mono_defaults.array_class && strcmp (klass->name, "InternalEnumerator`1") == 0) {
+ MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
+ if (gklass && klass->nested_in == mono_defaults.array_class && strcmp (klass->name, "InternalEnumerator`1") == 0) {
/*
* For a Enumerator<T[]> we need to get the list of interfaces for T.
*/
- eclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
+ eclass = mono_class_from_mono_type (gklass->context.class_inst->type_argv [0]);
original_rank = eclass->rank;
if (!eclass->rank)
eclass = eclass->element_class;
*/
all_interfaces = eclass->rank && eclass->element_class->rank? FALSE: TRUE;
- if (!generic_icollection_class) {
- generic_icollection_class = mono_class_from_name (mono_defaults.corlib,
- "System.Collections.Generic", "ICollection`1");
- generic_ienumerable_class = mono_class_from_name (mono_defaults.corlib,
- "System.Collections.Generic", "IEnumerable`1");
- generic_ienumerator_class = mono_class_from_name (mono_defaults.corlib,
- "System.Collections.Generic", "IEnumerator`1");
- generic_ireadonlylist_class = mono_class_from_name (mono_defaults.corlib,
- "System.Collections.Generic", "IReadOnlyList`1");
- generic_ireadonlycollection_class = mono_class_from_name (mono_defaults.corlib,
- "System.Collections.Generic", "IReadOnlyCollection`1");
- }
+ generic_icollection_class = mono_class_get_generic_icollection_class ();
+ generic_ienumerable_class = mono_class_get_generic_ienumerable_class ();
+ generic_ienumerator_class = mono_class_get_generic_ienumerator_class ();
+ generic_ireadonlylist_class = mono_class_get_generic_ireadonlylist_class ();
+ generic_ireadonlycollection_class = mono_class_get_generic_ireadonlycollection_class ();
mono_class_init (eclass);
if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
mono_class_setup_methods (klass);
- if (klass->exception_type)
+ if (mono_class_has_failure (klass))
return -1;
for (i = 0; i < klass->method.count; ++i) {
++count;
}
} else {
+ int first_idx = mono_class_get_first_method_idx (klass);
for (i = 0; i < klass->method.count; ++i) {
- flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, klass->method.first + i, MONO_METHOD_FLAGS);
+ flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
if (flags & METHOD_ATTRIBUTE_VIRTUAL)
++count;
* the size of the buffer.
* This compression algorithm assumes the bits set in the bitmap are
* few and far between, like in interface bitmaps.
- * Returns: the size of the compressed bitmap in bytes.
+ * Returns: The size of the compressed bitmap in bytes.
*/
int
mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size)
* be already checked for being smaller than the maximum id encoded in the
* bitmap.
*
- * Returns: a non-zero value if bit @id is set in the bitmap @bitmap,
+ * Returns: A non-zero value if bit @id is set in the bitmap @bitmap,
* #FALSE otherwise.
*/
int
#endif
/*
- * LOCKING: this is supposed to be called with the loader lock held.
- * Return -1 on failure and set exception_type
+ * Return -1 on failure and set klass->has_failure and store a MonoErrorBoxed with the details.
+ * LOCKING: Acquires the loader lock.
*/
static int
setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
{
MonoError error;
MonoClass *k, *ic;
- int i, j, max_iid, num_ifaces;
+ int i, j, num_ifaces;
+ guint32 max_iid;
MonoClass **interfaces_full = NULL;
int *interface_offsets_full = NULL;
GPtrArray *ifaces;
for (i = 0; i < k->interface_count; i++) {
ic = k->interfaces [i];
- if (!ic->inited)
- mono_class_init (ic);
+ mono_class_init (ic);
if (max_iid < ic->interface_id)
max_iid = ic->interface_id;
ifaces = mono_class_get_implemented_interfaces (k, &error);
if (!mono_error_ok (&error)) {
char *name = mono_type_get_full_name (k);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Error getting the interfaces of %s due to %s", name, mono_error_get_message (&error)));
+ mono_class_set_type_load_failure (klass, "Error getting the interfaces of %s due to %s", name, mono_error_get_message (&error));
g_free (name);
mono_error_cleanup (&error);
cur_slot = -1;
if (max_iid < klass->interface_id)
max_iid = klass->interface_id;
}
- klass->max_interface_id = max_iid;
+
/* compute vtable offset for interfaces */
interfaces_full = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * num_ifaces);
interface_offsets_full = (int *)g_malloc (sizeof (int) * num_ifaces);
- for (i = 0; i < num_ifaces; i++) {
+ for (i = 0; i < num_ifaces; i++)
interface_offsets_full [i] = -1;
- }
/* skip the current class */
for (j = 0; j < klass->idepth - 1; j++) {
count = count_virtual_methods (ic);
if (count == -1) {
char *name = mono_type_get_full_name (ic);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Error calculating interface offset of %s", name));
+ mono_class_set_type_load_failure (klass, "Error calculating interface offset of %s", name);
g_free (name);
cur_slot = -1;
goto end;
for (i = 0; i < num_array_interfaces; ++i) {
int offset;
ic = array_interfaces [i];
- if (ic->generic_class->container_class == mono_defaults.generic_ilist_class)
+ if (mono_class_get_generic_class (ic)->container_class == mono_defaults.generic_ilist_class)
offset = ilist_offset;
else if (strcmp (ic->name, "ICollection`1") == 0)
offset = icollection_offset;
}
for (interface_offsets_count = 0, i = 0; i < num_ifaces; i++) {
- if (interface_offsets_full [i] != -1) {
+ if (interface_offsets_full [i] != -1)
interface_offsets_count ++;
- }
}
+ /* Publish the data */
+ mono_loader_lock ();
+
+ klass->max_interface_id = max_iid;
/*
* We might get called multiple times:
* - mono_class_init ()
bitmap = (uint8_t *)mono_class_alloc0 (klass, bsize);
#endif
for (i = 0; i < interface_offsets_count; i++) {
- int id = interfaces_full [i]->interface_id;
+ guint32 id = interfaces_full [i]->interface_id;
bitmap [id >> 3] |= (1 << (id & 7));
klass->interfaces_packed [i] = interfaces_full [i];
klass->interface_offsets_packed [i] = interface_offsets_full [i];
klass->interface_bitmap = bitmap;
#endif
}
+ mono_loader_unlock ();
end:
g_free (interfaces_full);
//printf ("JUST DONE: ");
//print_implemented_interfaces (klass);
-
+
return cur_slot;
}
void
mono_class_setup_interface_offsets (MonoClass *klass)
{
- mono_loader_lock ();
-
setup_interface_offsets (klass, 0, FALSE);
-
- mono_loader_unlock ();
}
/*Checks if @klass has @parent as one of it's parents type gtd
{
MonoGenericInst *ginst;
int i;
- if (!klass->generic_class) {
+
+ if (!mono_class_is_ginst (klass)) {
mono_class_setup_vtable_full (klass, in_setup);
- return klass->exception_type == 0;
+ return !mono_class_has_failure (klass);
}
mono_class_setup_vtable_full (mono_class_get_generic_type_definition (klass), in_setup);
- if (klass->generic_class->container_class->exception_type) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Failed to load generic definition vtable"));
+ if (mono_class_set_type_load_failure_causedby_class (klass, mono_class_get_generic_class (klass)->container_class, "Failed to load generic definition vtable"))
return FALSE;
- }
- ginst = klass->generic_class->context.class_inst;
+ ginst = mono_class_get_generic_class (klass)->context.class_inst;
for (i = 0; i < ginst->type_argc; ++i) {
MonoClass *arg;
if (ginst->type_argv [i]->type != MONO_TYPE_GENERICINST)
if (mono_class_has_gtd_parent (klass, arg) || mono_class_has_gtd_parent (arg, klass))
continue;
if (!mono_class_check_vtable_constraints (arg, in_setup)) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Failed to load generic parameter %d", i));
+ mono_class_set_type_load_failure (klass, "Failed to load generic parameter %d", i);
return FALSE;
}
}
* - vtable
* - vtable_size
* Plus all the fields initialized by setup_interface_offsets ().
- * If there is an error during vtable construction, klass->exception_type is set.
+ * If there is an error during vtable construction, klass->has_failure
+ * is set and details are stored in a MonoErrorBoxed.
*
* LOCKING: Acquires the loader lock.
*/
static void
mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup)
{
+ MonoError error;
MonoMethod **overrides;
MonoGenericContext *context;
guint32 type_token;
return;
}
- if (klass->exception_type)
+ if (mono_class_has_failure (klass))
return;
if (g_list_find (in_setup, klass))
mono_stats.generic_vtable_count ++;
in_setup = g_list_prepend (in_setup, klass);
- if (klass->generic_class) {
+ if (mono_class_is_ginst (klass)) {
if (!mono_class_check_vtable_constraints (klass, in_setup)) {
mono_loader_unlock ();
g_list_remove (in_setup, klass);
}
context = mono_class_get_context (klass);
- type_token = klass->generic_class->container_class->type_token;
+ type_token = mono_class_get_generic_class (klass)->container_class->type_token;
} else {
- context = (MonoGenericContext *) klass->generic_container;
+ context = (MonoGenericContext *) mono_class_try_get_generic_container (klass); //FIXME is this a case of a try?
type_token = klass->type_token;
}
* This is true since we don't do layout all over again for them, we simply inflate
* the layout of the parent.
*/
- mono_reflection_get_dynamic_overrides (klass, &overrides, &onum);
+ mono_reflection_get_dynamic_overrides (klass, &overrides, &onum, &error);
+ if (!is_ok (&error)) {
+ mono_loader_unlock ();
+ g_list_remove (in_setup, klass);
+ mono_class_set_type_load_failure (klass, "Could not load list of method overrides due to %s", mono_error_get_message (&error));
+ mono_error_cleanup (&error);
+ return;
+ }
} else {
/* The following call fails if there are missing methods in the type */
/* FIXME it's probably a good idea to avoid this for generic instances. */
if (ok)
mono_class_setup_vtable_general (klass, overrides, onum, in_setup);
else
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not load list of method overrides"));
+ mono_class_set_type_load_failure (klass, "Could not load list of method overrides");
g_free (overrides);
cmsig = mono_method_signature (cm);
imsig = mono_method_signature (im);
if (!cmsig || !imsig) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not resolve the signature of a virtual method"));
+ mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
return FALSE;
}
if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
char *body_name = mono_method_full_name (cm, TRUE);
char *decl_name = mono_method_full_name (im, TRUE);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
+ mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
g_free (body_name);
g_free (decl_name);
return FALSE;
cmsig = mono_method_signature (cm);
imsig = mono_method_signature (im);
if (!cmsig || !imsig) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not resolve the signature of a virtual method"));
+ mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
return FALSE;
}
if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
char *body_name = mono_method_full_name (cm, TRUE);
char *decl_name = mono_method_full_name (im, TRUE);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
+ mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
g_free (body_name);
g_free (decl_name);
return FALSE;
g_free (method_signature);
g_free (type_name);
mono_class_setup_methods (klass);
- if (klass->exception_type) {
+ if (mono_class_has_failure (klass)) {
char *name = mono_type_get_full_name (klass);
mono_trace_warning (MONO_TRACE_TYPE, "CLASS %s failed to resolve methods\n", name);
g_free (name);
MonoMethod *body = overrides [i * 2 + 1];
if (mono_class_get_generic_type_definition (body->klass) != mono_class_get_generic_type_definition (klass)) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method belongs to a different class than the declared one"));
+ mono_class_set_type_load_failure (klass, "Method belongs to a different class than the declared one");
return FALSE;
}
if (!(body->flags & METHOD_ATTRIBUTE_VIRTUAL) || (body->flags & METHOD_ATTRIBUTE_STATIC)) {
if (body->flags & METHOD_ATTRIBUTE_STATIC)
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method must not be static to override a base type"));
+ mono_class_set_type_load_failure (klass, "Method must not be static to override a base type");
else
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method must be virtual to override a base type"));
+ mono_class_set_type_load_failure (klass, "Method must be virtual to override a base type");
return FALSE;
}
if (!(decl->flags & METHOD_ATTRIBUTE_VIRTUAL) || (decl->flags & METHOD_ATTRIBUTE_STATIC)) {
if (body->flags & METHOD_ATTRIBUTE_STATIC)
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a static method in a base type"));
+ mono_class_set_type_load_failure (klass, "Cannot override a static method in a base type");
else
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a non virtual method in a base type"));
+ mono_class_set_type_load_failure (klass, "Cannot override a non virtual method in a base type");
return FALSE;
}
if (!mono_class_is_assignable_from_slow (decl->klass, klass)) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method overrides a class or interface that is not extended or implemented by this type"));
+ mono_class_set_type_load_failure (klass, "Method overrides a class or interface that is not extended or implemented by this type");
return FALSE;
}
if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (body, decl, NULL)) {
char *body_name = mono_method_full_name (body, TRUE);
char *decl_name = mono_method_full_name (decl, TRUE);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
+ mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
g_free (body_name);
g_free (decl_name);
return FALSE;
MonoError error;
MonoClass *k, *ic;
MonoMethod **vtable;
- int i, max_vtsize = 0, max_iid, cur_slot = 0;
+ int i, max_vtsize = 0, cur_slot = 0;
+ guint32 max_iid;
GPtrArray *ifaces = NULL;
GHashTable *override_map = NULL;
MonoMethod *cm;
ifaces = mono_class_get_implemented_interfaces (klass, &error);
if (!mono_error_ok (&error)) {
char *name = mono_type_get_full_name (klass);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Could not resolve %s interfaces due to %s", name, mono_error_get_message (&error)));
+ mono_class_set_type_load_failure (klass, "Could not resolve %s interfaces due to %s", name, mono_error_get_message (&error));
g_free (name);
mono_error_cleanup (&error);
return;
mono_class_init (klass->parent);
mono_class_setup_vtable_full (klass->parent, in_setup);
- if (klass->parent->exception_type) {
- char *name = mono_type_get_full_name (klass->parent);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Parent %s failed to load", name));
- g_free (name);
+ if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class failed to load"))
return;
- }
max_vtsize += klass->parent->vtable_size;
cur_slot = klass->parent->vtable_size;
DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot);
/* Optimized version for generic instances */
- if (klass->generic_class) {
+ if (mono_class_is_ginst (klass)) {
MonoError error;
- MonoClass *gklass = klass->generic_class->container_class;
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
MonoMethod **tmp;
mono_class_setup_vtable_full (gklass, in_setup);
- if (gklass->exception_type != MONO_EXCEPTION_NONE) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Could not load generic definition"))
return;
- }
tmp = (MonoMethod **)mono_class_alloc0 (klass, sizeof (gpointer) * gklass->vtable_size);
klass->vtable_size = gklass->vtable_size;
if (gklass->vtable [i]) {
MonoMethod *inflated = mono_class_inflate_generic_method_full_checked (gklass->vtable [i], klass, mono_class_get_context (klass), &error);
if (!mono_error_ok (&error)) {
- char *err_msg = g_strdup_printf ("Could not inflate method due to %s", mono_error_get_message (&error));
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, err_msg);
- g_free (err_msg);
+ mono_class_set_type_load_failure (klass, "Could not inflate method due to %s", mono_error_get_message (&error));
mono_error_cleanup (&error);
return;
}
mono_class_setup_methods (parent_interface); /*FIXME Just kill this whole chunk of dead code*/
TRACE_INTERFACE_VTABLE (printf (" +++ Inheriting interface %s.%s\n", parent_interface->name_space, parent_interface->name));
- for (j = 0; j < parent_interface->method.count && !klass->exception_type; j++) {
+ for (j = 0; j < parent_interface->method.count && !mono_class_has_failure (klass); j++) {
vtable [interface_offset + j] = parent->vtable [parent_interface_offset + j];
TRACE_INTERFACE_VTABLE (printf (" --- Inheriting: [%03d][(%03d)+(%03d)] => [%03d][(%03d)+(%03d)]\n",
parent_interface_offset + j, parent_interface_offset, j,
int dslot;
dslot = mono_method_get_vtable_slot (decl);
if (dslot == -1) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ mono_class_set_type_load_failure (klass, "");
return;
}
while ((cm = mono_class_get_virtual_methods (klass, &iter))) {
virt_methods = g_slist_prepend (virt_methods, cm);
}
- if (klass->exception_type)
+ if (mono_class_has_failure (klass))
goto fail;
}
ic_offset = mono_class_interface_offset (klass, ic);
mono_class_setup_methods (ic);
- if (ic->exception_type)
+ if (mono_class_has_failure (ic))
goto fail;
// Check if this interface is explicitly implemented (instead of just inherited)
}
}
TRACE_INTERFACE_VTABLE (printf ("\n"));
- if (klass->exception_type) /*Might be set by check_interface_method_override*/
+ if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
goto fail;
}
}
break;
}
- if (klass->exception_type) /*Might be set by check_interface_method_override*/
+ if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
goto fail;
TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n"));
}
// it can happen (for injected generic array interfaces) that the same slot is
// processed multiple times (those interfaces have overlapping slots), and it
// will not always be the first pass the one that fills the slot.
- if (! (klass->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
+ if (!mono_class_is_abstract (klass)) {
for (i = 0; i < klass->interface_offsets_count; i++) {
int ic_offset;
int im_index;
m1sig = mono_method_signature (m1);
if (!cmsig || !m1sig) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ /* FIXME proper error message */
+ mono_class_set_type_load_failure (klass, "");
return;
}
if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, m1, NULL)) {
char *body_name = mono_method_full_name (cm, TRUE);
char *decl_name = mono_method_full_name (m1, TRUE);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
+ mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
g_free (body_name);
g_free (decl_name);
goto fail;
break;
}
}
- if (k->exception_type)
+ if (mono_class_has_failure (k))
goto fail;
if (slot >= 0)
virt_methods = NULL;
/* Ensure that all vtable slots are filled with concrete instance methods */
- if (!(klass->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
+ if (!mono_class_is_abstract (klass)) {
for (i = 0; i < cur_slot; ++i) {
if (vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) {
char *type_name = mono_type_get_full_name (klass);
char *method_name = vtable [i] ? mono_method_full_name (vtable [i], TRUE) : g_strdup ("none");
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Type %s has invalid vtable method slot %d with method %s", type_name, i, method_name));
+ mono_class_set_type_load_failure (klass, "Type %s has invalid vtable method slot %d with method %s", type_name, i, method_name);
g_free (type_name);
g_free (method_name);
return;
}
}
- if (klass->generic_class) {
- MonoClass *gklass = klass->generic_class->container_class;
+ if (mono_class_is_ginst (klass)) {
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
mono_class_init (gklass);
fail:
{
char *name = mono_type_get_full_name (klass);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("VTable setup of type %s failed", name));
+ mono_class_set_type_load_failure (klass, "VTable setup of type %s failed", name);
g_free (name);
if (override_map)
g_hash_table_destroy (override_map);
{
if (method->slot == -1) {
mono_class_setup_vtable (method->klass);
- if (method->klass->exception_type)
+ if (mono_class_has_failure (method->klass))
return -1;
if (method->slot == -1) {
MonoClass *gklass;
int i;
- if (!method->klass->generic_class) {
+ if (!mono_class_is_ginst (method->klass)) {
g_assert (method->is_inflated);
return mono_method_get_vtable_slot (((MonoMethodInflated*)method)->declaring);
}
/* This can happen for abstract methods of generic instances due to the shortcut code in mono_class_setup_vtable_general (). */
- g_assert (method->klass->generic_class);
- gklass = method->klass->generic_class->container_class;
+ g_assert (mono_class_is_ginst (method->klass));
+ gklass = mono_class_get_generic_class (method->klass)->container_class;
mono_class_setup_methods (method->klass);
g_assert (method->klass->methods);
for (i = 0; i < method->klass->method.count; ++i) {
if (generic_array_method_num)
return generic_array_method_num;
mono_class_setup_methods (klass->parent); /*This is setting up System.Array*/
- g_assert (!klass->parent->exception_type); /*So hitting this assert is a huge problem*/
+ g_assert (!mono_class_has_failure (klass->parent)); /*So hitting this assert is a huge problem*/
for (i = 0; i < klass->parent->method.count; i++) {
MonoMethod *m = klass->parent->methods [i];
if (!strncmp (m->name, "InternalArray__", 15)) {
int i;
tmp_context.class_inst = NULL;
- tmp_context.method_inst = iface->generic_class->context.class_inst;
+ tmp_context.method_inst = mono_class_get_generic_class (iface)->context.class_inst;
//g_print ("setting up array interface: %s\n", mono_type_get_name_full (&iface->byval_arg, 0));
for (i = 0; i < generic_array_method_num; i++) {
return s;
}
-static void
-set_failure_from_loader_error (MonoClass *klass, MonoLoaderError *error)
-{
- gpointer exception_data = NULL;
-
- switch (error->exception_type) {
- case MONO_EXCEPTION_TYPE_LOAD:
- exception_data = concat_two_strings_with_zero (klass->image, error->class_name, error->assembly_name);
- break;
-
- case MONO_EXCEPTION_MISSING_METHOD:
- exception_data = concat_two_strings_with_zero (klass->image, error->class_name, error->member_name);
- break;
-
- case MONO_EXCEPTION_MISSING_FIELD: {
- const char *name_space = error->klass->name_space ? error->klass->name_space : NULL;
- const char *class_name;
-
- if (name_space)
- class_name = g_strdup_printf ("%s.%s", name_space, error->klass->name);
- else
- class_name = error->klass->name;
-
- exception_data = concat_two_strings_with_zero (klass->image, class_name, error->member_name);
-
- if (name_space)
- g_free ((void*)class_name);
- break;
- }
-
- case MONO_EXCEPTION_FILE_NOT_FOUND: {
- const char *msg;
-
- if (error->ref_only)
- msg = "Cannot resolve dependency to assembly '%s' because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event.";
- else
- msg = "Could not load file or assembly '%s' or one of its dependencies.";
-
- exception_data = concat_two_strings_with_zero (klass->image, msg, error->assembly_name);
- break;
- }
-
- case MONO_EXCEPTION_BAD_IMAGE:
- exception_data = error->msg;
- break;
-
- default :
- g_assert_not_reached ();
- }
-
- mono_class_set_failure (klass, error->exception_type, exception_data);
-}
-
/**
* mono_class_init:
- * @class: the class to initialize
+ * @klass: the class to initialize
*
* Compute the instance_size, class_size and other infos that cannot be
* computed at mono_class_get() time. Also compute vtable_size if possible.
* Returns TRUE on success or FALSE if there was a problem in loading
- * the type (incorrect assemblies, missing assemblies, methods, etc).
+ * the type (incorrect assemblies, missing assemblies, methods, etc).
+ * Initializes the following fields in @klass:
+ * - all the fields initialized by mono_class_init_sizes ()
+ * - has_cctor
+ * - ghcimpl
+ * - inited
*
* LOCKING: Acquires the loader lock.
*/
gboolean
mono_class_init (MonoClass *klass)
{
- int i;
+ int i, vtable_size = 0, array_method_count = 0;
MonoCachedClassInfo cached_info;
gboolean has_cached_info;
+ gboolean locked = FALSE;
+ gboolean ghcimpl = FALSE;
+ gboolean has_cctor = FALSE;
+ int first_iface_slot = 0;
g_assert (klass);
/* Double-checking locking pattern */
- if (klass->inited || klass->exception_type)
- return klass->exception_type == MONO_EXCEPTION_NONE;
+ if (klass->inited || mono_class_has_failure (klass))
+ return !mono_class_has_failure (klass);
/*g_print ("Init class %s\n", mono_type_get_full_name (klass));*/
- /* We do everything inside the lock to prevent races */
- mono_loader_lock ();
-
- if (klass->inited || klass->exception_type) {
- mono_loader_unlock ();
- /* Somebody might have gotten in before us */
- return klass->exception_type == MONO_EXCEPTION_NONE;
- }
-
- if (klass->init_pending) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Recursive type definition detected"));
+ /*
+ * This function can recursively call itself.
+ */
+ GSList *init_list = (GSList *)mono_native_tls_get_value (init_pending_tls_id);
+ if (g_slist_find (init_list, klass)) {
+ mono_class_set_type_load_failure (klass, "Recursive type definition detected");
goto leave;
}
+ init_list = g_slist_prepend (init_list, klass);
+ mono_native_tls_set_value (init_pending_tls_id, init_list);
- klass->init_pending = 1;
+ /*
+ * We want to avoid doing complicated work inside locks, so we compute all the required
+ * information and write it to @klass inside a lock.
+ */
if (mono_verifier_is_enabled_for_class (klass) && !mono_verifier_verify_class (klass)) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, concat_two_strings_with_zero (klass->image, klass->name, klass->image->assembly_name));
+ mono_class_set_type_load_failure (klass, "%s", concat_two_strings_with_zero (klass->image, klass->name, klass->image->assembly_name));
goto leave;
}
-
if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
MonoClass *element_class = klass->element_class;
if (!element_class->inited)
mono_class_init (element_class);
- if (element_class->exception_type != MONO_EXCEPTION_NONE) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ if (mono_class_set_type_load_failure_causedby_class (klass, element_class, "Could not load array element class"))
goto leave;
- }
}
mono_stats.initialized_class_count++;
- if (klass->generic_class && !klass->generic_class->is_dynamic) {
- MonoClass *gklass = klass->generic_class->container_class;
-
- mono_stats.generic_class_count++;
-
- klass->method = gklass->method;
- klass->field = gklass->field;
+ if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic) {
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
mono_class_init (gklass);
- // FIXME: Why is this needed ?
- if (!gklass->exception_type)
- mono_class_setup_methods (gklass);
- if (gklass->exception_type) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Generic Type Defintion failed to init"));
+ if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic Type Definition failed to init"))
goto leave;
- }
- if (MONO_CLASS_IS_INTERFACE (klass))
- klass->interface_id = mono_get_unique_iid (klass);
+ mono_class_setup_interface_id (klass);
}
if (klass->parent && !klass->parent->inited)
has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
- if (klass->generic_class || image_is_dynamic (klass->image) || !klass->type_token || (has_cached_info && !cached_info.has_nested_classes))
- klass->nested_classes_inited = TRUE;
-
- /*
- * Computes the size used by the fields, and their locations
- */
- if (has_cached_info) {
- klass->instance_size = cached_info.instance_size;
- klass->sizes.class_size = cached_info.class_size;
- klass->packing_size = cached_info.packing_size;
- klass->min_align = cached_info.min_align;
- klass->blittable = cached_info.blittable;
- klass->has_references = cached_info.has_references;
- klass->has_static_refs = cached_info.has_static_refs;
- klass->no_special_static_fields = cached_info.no_special_static_fields;
- }
- else
- if (!klass->size_inited){
- mono_class_setup_fields (klass);
- if (klass->exception_type || mono_loader_get_last_error ())
- goto leave;
- }
-
- /* Initialize arrays */
- if (klass->rank) {
- klass->method.count = 3 + (klass->rank > 1? 2: 1);
-
- if (klass->interface_count) {
- int count_generic = generic_array_methods (klass);
- klass->method.count += klass->interface_count * count_generic;
- }
- }
+ /* Compute instance size etc. */
+ init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
+ if (mono_class_has_failure (klass))
+ goto leave;
mono_class_setup_supertypes (klass);
*/
if (has_cached_info) {
/* AOT case */
- klass->vtable_size = cached_info.vtable_size;
- klass->has_finalize = cached_info.has_finalize;
- klass->has_finalize_inited = TRUE;
- klass->ghcimpl = cached_info.ghcimpl;
- klass->has_cctor = cached_info.has_cctor;
+ vtable_size = cached_info.vtable_size;
+ ghcimpl = cached_info.ghcimpl;
+ has_cctor = cached_info.has_cctor;
} else if (klass->rank == 1 && klass->byval_arg.type == MONO_TYPE_SZARRAY) {
/* SZARRAY can have 2 vtable layouts, with and without the stelemref method.
* The first slot if for array with.
if (!szarray_vtable_size [slot]) {
mono_class_setup_vtable (klass);
szarray_vtable_size [slot] = klass->vtable_size;
+ vtable_size = klass->vtable_size;
} else {
- klass->vtable_size = szarray_vtable_size[slot];
+ vtable_size = szarray_vtable_size[slot];
}
- } else if (klass->generic_class && !MONO_CLASS_IS_INTERFACE (klass)) {
- MonoClass *gklass = klass->generic_class->container_class;
+ } else if (mono_class_is_ginst (klass) && !MONO_CLASS_IS_INTERFACE (klass)) {
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
/* Generic instance case */
- klass->ghcimpl = gklass->ghcimpl;
- klass->has_cctor = gklass->has_cctor;
+ ghcimpl = gklass->ghcimpl;
+ has_cctor = gklass->has_cctor;
mono_class_setup_vtable (gklass);
- if (gklass->exception_type) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to init"))
goto leave;
- }
- klass->vtable_size = gklass->vtable_size;
+ vtable_size = gklass->vtable_size;
} else {
/* General case */
if (!MONO_CLASS_IS_INTERFACE (klass) || klass->image != mono_defaults.corlib) {
MonoMethod *cmethod = NULL;
- if (klass->type_token && !image_is_dynamic(klass->image)) {
+ if (mono_class_is_ginst (klass)) {
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
+
+ /* Generic instance case */
+ ghcimpl = gklass->ghcimpl;
+ has_cctor = gklass->has_cctor;
+ } else if (klass->type_token && !image_is_dynamic(klass->image)) {
cmethod = find_method_in_metadata (klass, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME);
/* The find_method function ignores the 'flags' argument */
if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
- klass->has_cctor = 1;
+ has_cctor = 1;
} else {
mono_class_setup_methods (klass);
- if (klass->exception_type)
+ if (mono_class_has_failure (klass))
goto leave;
for (i = 0; i < klass->method.count; ++i) {
MonoMethod *method = klass->methods [i];
if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
(strcmp (".cctor", method->name) == 0)) {
- klass->has_cctor = 1;
+ has_cctor = 1;
break;
}
}
}
}
- if (klass->parent) {
- int first_iface_slot;
- /* This will compute klass->parent->vtable_size for some classes */
- mono_class_init (klass->parent);
- if (klass->parent->exception_type) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
- goto leave;
+ if (klass->rank) {
+ array_method_count = 3 + (klass->rank > 1? 2: 1);
+
+ if (klass->interface_count) {
+ int count_generic = generic_array_methods (klass);
+ array_method_count += klass->interface_count * count_generic;
}
- if (mono_loader_get_last_error ())
- goto leave;
- if (!klass->parent->vtable_size) {
- /* FIXME: Get rid of this somehow */
+ }
+
+ if (klass->parent) {
+ if (!klass->parent->vtable_size)
mono_class_setup_vtable (klass->parent);
- if (klass->parent->exception_type) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
- goto leave;
- }
- if (mono_loader_get_last_error ())
- goto leave;
- }
+ if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class vtable failed to initialize"))
+ goto leave;
+ g_assert (klass->parent->vtable_size);
first_iface_slot = klass->parent->vtable_size;
if (mono_class_need_stelemref_method (klass))
++first_iface_slot;
- setup_interface_offsets (klass, first_iface_slot, TRUE);
- } else {
- setup_interface_offsets (klass, 0, TRUE);
}
+ /*
+ * Do the actual changes to @klass inside the loader lock
+ */
+ mono_loader_lock ();
+ locked = TRUE;
+
+ if (klass->inited || mono_class_has_failure (klass)) {
+ mono_loader_unlock ();
+ /* Somebody might have gotten in before us */
+ return !mono_class_has_failure (klass);
+ }
+
+ mono_stats.initialized_class_count++;
+
+ if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic) {
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
+
+ mono_stats.generic_class_count++;
+
+ klass->method = gklass->method;
+ klass->field = gklass->field;
+ }
+
+ if (mono_class_is_ginst (klass) || image_is_dynamic (klass->image) || !klass->type_token || (has_cached_info && !cached_info.has_nested_classes))
+ klass->nested_classes_inited = TRUE;
+ klass->ghcimpl = ghcimpl;
+ klass->has_cctor = has_cctor;
+ if (vtable_size)
+ klass->vtable_size = vtable_size;
+ if (has_cached_info) {
+ klass->has_finalize = cached_info.has_finalize;
+ klass->has_finalize_inited = TRUE;
+ }
+ if (klass->rank)
+ klass->method.count = array_method_count;
+
+ mono_loader_unlock ();
+ locked = FALSE;
+
+ setup_interface_offsets (klass, first_iface_slot, TRUE);
+
if (mono_security_core_clr_enabled ())
mono_security_core_clr_check_inheritance (klass);
- if (mono_loader_get_last_error ()) {
- if (klass->exception_type == MONO_EXCEPTION_NONE) {
- set_failure_from_loader_error (klass, mono_loader_get_last_error ());
- }
- mono_loader_clear_error ();
- }
-
- if (klass->generic_class && !mono_verifier_class_is_valid_generic_instantiation (klass))
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Invalid generic instantiation"));
+ if (mono_class_is_ginst (klass) && !mono_verifier_class_is_valid_generic_instantiation (klass))
+ mono_class_set_type_load_failure (klass, "Invalid generic instantiation");
goto leave;
leave:
+ init_list = g_slist_remove (init_list, klass);
+ mono_native_tls_set_value (init_pending_tls_id, init_list);
+
/* Because of the double-checking locking pattern */
mono_memory_barrier ();
klass->inited = 1;
- klass->init_pending = 0;
- mono_loader_unlock ();
+ if (locked)
+ mono_loader_unlock ();
- return klass->exception_type == MONO_EXCEPTION_NONE;
+ return !mono_class_has_failure (klass);
}
/*
MonoMethod *cmethod = NULL;
if (klass->rank == 1 && klass->byval_arg.type == MONO_TYPE_SZARRAY) {
- } else if (klass->generic_class) {
- MonoClass *gklass = klass->generic_class->container_class;
+ } else if (mono_class_is_ginst (klass)) {
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
has_finalize = mono_class_has_finalizer (gklass);
} else if (klass->parent && klass->parent->has_finalize) {
* ignores overrides.
*/
mono_class_setup_vtable (klass);
- if (klass->exception_type || mono_loader_get_last_error ())
+ if (mono_class_has_failure (klass))
cmethod = NULL;
else
cmethod = klass->vtable [finalize_slot];
gboolean
mono_is_corlib_image (MonoImage *image)
{
- /* FIXME: allow the dynamic case for our compilers and with full trust */
- if (image_is_dynamic (image))
- return image->assembly && !strcmp (image->assembly->aname.name, "mscorlib");
- else
- return image == mono_defaults.corlib;
+ return image == mono_defaults.corlib;
}
/*
if (MONO_CLASS_IS_INTERFACE (klass))
klass->interface_id = mono_get_unique_iid (klass);
-
}
#ifndef DISABLE_COM
/* but it can not be made available for application (i.e. user code) since all COM calls
* are considered native calls. In this case we fail with a TypeLoadException (just like
* Silverlight 2 does */
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ mono_class_set_type_load_failure (klass, "");
return;
}
}
if (!parent) {
/* set the parent to something useful and safe, but mark the type as broken */
parent = mono_defaults.object_class;
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ mono_class_set_type_load_failure (klass, "");
+ g_assert (parent);
}
klass->parent = parent;
- if (parent->generic_class && !parent->name) {
+ if (mono_class_is_ginst (parent) && !parent->name) {
/*
* If the parent is a generic instance, we may get
* called before it is fully initialized, especially
{
MonoClass *gtd = (MonoClass*)user_data;
/* Only try to fix generic instances of @gtd */
- if (gclass->generic_class->container_class != gtd)
+ if (mono_class_get_generic_class (gclass)->container_class != gtd)
return FALSE;
/* Check if the generic instance has no parent. */
static void
mono_class_set_failure_and_error (MonoClass *klass, MonoError *error, const char *msg)
{
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup (msg));
- mono_error_set_type_load_class (error, klass, msg);
-}
-
-static void
-mono_class_set_failure_from_loader_error (MonoClass *klass, MonoError *error, char *msg)
-{
- MonoLoaderError *lerror = mono_loader_get_last_error ();
-
- if (lerror) {
- set_failure_from_loader_error (klass, lerror);
- mono_error_set_from_loader_error (error);
- if (msg)
- g_free (msg);
- } else {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, msg);
- mono_error_set_type_load_class (error, klass, msg);
- }
+ mono_class_set_type_load_failure (klass, "%s", msg);
+ mono_error_set_type_load_class (error, klass, "%s", msg);
}
/**
if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
mono_error_set_bad_image (error, image, "Invalid typedef token %x", type_token);
- mono_loader_assert_no_error ();
return NULL;
}
if ((klass = (MonoClass *)mono_internal_hash_table_lookup (&image->class_cache, GUINT_TO_POINTER (type_token)))) {
mono_loader_unlock ();
- mono_loader_assert_no_error ();
return klass;
}
name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
- klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass));
+ if (mono_metadata_has_generic_params (image, type_token)) {
+ klass = mono_image_alloc0 (image, sizeof (MonoClassGtd));
+ klass->class_kind = MONO_CLASS_GTD;
+ classes_size += sizeof (MonoClassGtd);
+ ++class_gtd_count;
+ } else {
+ klass = mono_image_alloc0 (image, sizeof (MonoClassDef));
+ klass->class_kind = MONO_CLASS_DEF;
+ classes_size += sizeof (MonoClassDef);
+ ++class_def_count;
+ }
klass->name = name;
klass->name_space = nspace;
klass->image = image;
klass->type_token = type_token;
- klass->flags = cols [MONO_TYPEDEF_FLAGS];
+ mono_class_set_flags (klass, cols [MONO_TYPEDEF_FLAGS]);
mono_internal_hash_table_insert (&image->class_cache, GUINT_TO_POINTER (type_token), klass);
- classes_size += sizeof (MonoClass);
-
/*
* Check whether we're a generic type definition.
*/
- klass->generic_container = mono_metadata_load_generic_params (image, klass->type_token, NULL);
- if (klass->generic_container) {
- klass->is_generic = 1;
- klass->generic_container->owner.klass = klass;
- klass->generic_container->is_anonymous = FALSE; // Owner class is now known, container is no longer anonymous
- context = &klass->generic_container->context;
- }
-
- if (klass->generic_container)
+ if (mono_class_is_gtd (klass)) {
+ MonoGenericContainer *generic_container = mono_metadata_load_generic_params (image, klass->type_token, NULL);
+ generic_container->owner.klass = klass;
+ generic_container->is_anonymous = FALSE; // Owner class is now known, container is no longer anonymous
+ context = &generic_container->context;
+ mono_class_set_generic_container (klass, generic_container);
enable_gclass_recording ();
+ }
if (cols [MONO_TYPEDEF_EXTENDS]) {
MonoClass *tmp;
parent = mono_class_inflate_generic_class_checked (parent, context, error);
if (parent == NULL) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
+ mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
goto parent_failure;
}
mono_class_set_failure_and_error (klass, error, "Cycle found while resolving parent");
goto parent_failure;
}
- if (klass->generic_container && tmp->generic_class && tmp->generic_class->container_class == klass) {
+ if (mono_class_is_gtd (klass) && mono_class_is_ginst (tmp) && mono_class_get_generic_class (tmp)->container_class == klass) {
mono_class_set_failure_and_error (klass, error, "Parent extends generic instance of this type");
goto parent_failure;
}
/* uses ->valuetype, which is initialized by mono_class_setup_parent above */
mono_class_setup_mono_type (klass);
- if (klass->generic_container)
+ if (mono_class_is_gtd (klass))
disable_gclass_recording (fix_gclass_incomplete_instantiation, klass);
/*
klass->nested_in = mono_class_create_from_typedef (image, nesting_tokeen, error);
if (!mono_error_ok (error)) {
/*FIXME implement a mono_class_set_failure_from_mono_error */
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
+ mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
mono_loader_unlock ();
mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
- mono_loader_assert_no_error ();
return NULL;
}
}
- if ((klass->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
+ if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
klass->unicode = 1;
#ifdef HOST_WIN32
- if ((klass->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
+ if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
klass->unicode = 1;
#endif
if (!mono_metadata_interfaces_from_typedef_full (
image, type_token, &interfaces, &icount, FALSE, context, error)){
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
+ mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
mono_loader_unlock ();
mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
return NULL;
}
+ /* This is required now that it is possible for more than 2^16 interfaces to exist. */
+ g_assert(icount <= 65535);
+
klass->interfaces = interfaces;
klass->interface_count = icount;
klass->interfaces_inited = 1;
/*
* Compute the field and method lists
*/
- klass->field.first = cols [MONO_TYPEDEF_FIELD_LIST] - 1;
- klass->method.first = cols [MONO_TYPEDEF_METHOD_LIST] - 1;
+ int first_field_idx = cols [MONO_TYPEDEF_FIELD_LIST] - 1;
+ mono_class_set_first_field_idx (klass, first_field_idx);
+ int first_method_idx = cols [MONO_TYPEDEF_METHOD_LIST] - 1;
+ mono_class_set_first_method_idx (klass, first_method_idx);
if (tt->rows > tidx){
mono_metadata_decode_row (tt, tidx, cols_next, MONO_TYPEDEF_SIZE);
if (cols [MONO_TYPEDEF_FIELD_LIST] &&
cols [MONO_TYPEDEF_FIELD_LIST] <= image->tables [MONO_TABLE_FIELD].rows)
- klass->field.count = field_last - klass->field.first;
+ klass->field.count = field_last - first_field_idx;
else
klass->field.count = 0;
if (cols [MONO_TYPEDEF_METHOD_LIST] <= image->tables [MONO_TABLE_METHOD].rows)
- klass->method.count = method_last - klass->method.first;
+ klass->method.count = method_last - first_method_idx;
else
klass->method.count = 0;
if (!enum_basetype) {
/*set it to a default value as the whole runtime can't handle this to be null*/
klass->cast_class = klass->element_class = mono_defaults.int32_class;
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
+ mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
mono_loader_unlock ();
mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
- mono_loader_assert_no_error ();
return NULL;
}
klass->cast_class = klass->element_class = mono_class_from_mono_type (enum_basetype);
* We must do this after the class has been constructed to make certain recursive scenarios
* work.
*/
- if (klass->generic_container && !mono_metadata_load_generic_param_constraints_checked (image, type_token, klass->generic_container, error)) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Could not load generic parameter constrains due to %s", mono_error_get_message (error)));
+ if (mono_class_is_gtd (klass) && !mono_metadata_load_generic_param_constraints_checked (image, type_token, mono_class_get_generic_container (klass), error)) {
+ mono_class_set_type_load_failure (klass, "Could not load generic parameter constrains due to %s", mono_error_get_message (error));
mono_loader_unlock ();
mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
- mono_loader_assert_no_error ();
return NULL;
}
mono_loader_unlock ();
mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
- mono_loader_assert_no_error ();
return klass;
mono_class_setup_mono_type (klass);
mono_loader_unlock ();
mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
- mono_loader_assert_no_error ();
return NULL;
}
gboolean
mono_class_is_nullable (MonoClass *klass)
{
- return klass->generic_class != NULL &&
- klass->generic_class->container_class == mono_defaults.generic_nullable_class;
+ MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
+ return gklass && gklass->container_class == mono_defaults.generic_nullable_class;
}
mono_class_get_nullable_param (MonoClass *klass)
{
g_assert (mono_class_is_nullable (klass));
- return mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
+ return mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
}
static void
{
if (gtd->parent) {
MonoError error;
- MonoGenericClass *gclass = klass->generic_class;
+ MonoGenericClass *gclass = mono_class_get_generic_class (klass);
klass->parent = mono_class_inflate_generic_class_checked (gtd->parent, mono_generic_class_get_context (gclass), &error);
if (!mono_error_ok (&error)) {
/*Set parent to something safe as the runtime doesn't handle well this kind of failure.*/
klass->parent = mono_defaults.object_class;
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ mono_class_set_type_load_failure (klass, "Parent is a generic type instantiation that failed due to: %s", mono_error_get_message (&error));
mono_error_cleanup (&error);
}
}
return gclass->cached_class;
}
- klass = (MonoClass *)mono_image_set_alloc0 (gclass->owner, sizeof (MonoClass));
+ klass = (MonoClass *)mono_image_set_alloc0 (gclass->owner, sizeof (MonoClassGenericInst));
gklass = gclass->container_class;
mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
klass->image = gklass->image;
- klass->flags = gklass->flags;
klass->type_token = gklass->type_token;
klass->field.count = gklass->field.count;
- klass->is_inflated = 1;
- klass->generic_class = gclass;
+ klass->class_kind = MONO_CLASS_GINST;
+ //FIXME add setter
+ ((MonoClassGenericInst*)klass)->generic_class = gclass;
klass->byval_arg.type = MONO_TYPE_GENERICINST;
klass->this_arg.type = klass->byval_arg.type;
mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
- inflated_classes ++;
- inflated_classes_size += sizeof (MonoClass);
+ ++class_ginst_count;
+ inflated_classes_size += sizeof (MonoClassGenericInst);
mono_loader_unlock ();
gboolean is_mvar = container->is_method;
gboolean is_anonymous = container->is_anonymous;
- klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass));
- classes_size += sizeof (MonoClass);
+ klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassGenericParam));
+ klass->class_kind = MONO_CLASS_GPARAM;
+ classes_size += sizeof (MonoClassGenericParam);
+ ++class_gparam_count;
if (pinfo) {
CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name , pinfo->name );
CHECKED_METADATA_WRITE_PTR ( klass->parent , pinfo->constraints [0] );
pos++;
} else if (pinfo && pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) {
- CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_class_from_name (mono_defaults.corlib, "System", "ValueType") );
+ CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_class_load_from_name (mono_defaults.corlib, "System", "ValueType") );
} else {
CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_defaults.object_class );
}
klass->inited = TRUE;
CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->cast_class , klass );
CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->element_class , klass );
- klass->flags = TYPE_ATTRIBUTE_PUBLIC;
klass->byval_arg.type = is_mvar ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
klass->this_arg.type = klass->byval_arg.type;
klass->instance_size = sizeof (MonoObject) + mono_type_stack_size_internal (&klass->byval_arg, NULL, TRUE);
mono_memory_barrier ();
klass->size_inited = 1;
- klass->setup_fields_called = 1;
mono_class_setup_supertypes (klass);
if (count - pos > 0) {
mono_class_setup_vtable (klass->parent);
- if (klass->parent->exception_type)
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Failed to setup parent interfaces"));
+ if (mono_class_has_failure (klass->parent))
+ mono_class_set_type_load_failure (klass, "Failed to setup parent interfaces");
else
setup_interface_offsets (klass, klass->parent->vtable_size, TRUE);
}
}
mono_image_unlock (image);
- result = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass));
+ result = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassPointer));
- classes_size += sizeof (MonoClass);
+ classes_size += sizeof (MonoClassPointer);
+ ++class_pointer_count;
result->parent = NULL; /* no parent for PTR types */
result->name_space = el_class->name_space;
name = g_strdup_printf ("%s*", el_class->name);
result->name = mono_image_strdup (image, name);
+ result->class_kind = MONO_CLASS_POINTER;
g_free (name);
mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
result->image = el_class->image;
result->inited = TRUE;
- result->flags = TYPE_ATTRIBUTE_CLASS | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK);
- /* Can pointers get boxed? */
- result->instance_size = sizeof (gpointer);
+ result->instance_size = sizeof (MonoObject) + sizeof (gpointer);
result->cast_class = result->element_class = el_class;
result->blittable = TRUE;
}
result = g_new0 (MonoClass, 1);
+ classes_size += sizeof (MonoClassPointer);
+ ++class_pointer_count;
+
result->parent = NULL; /* no parent for PTR types */
result->name_space = "System";
result->name = "MonoFNPtrFakeClass";
+ result->class_kind = MONO_CLASS_POINTER;
mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
result->image = mono_defaults.corlib; /* need to fix... */
result->inited = TRUE;
- result->flags = TYPE_ATTRIBUTE_CLASS; /* | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK); */
- /* Can pointers get boxed? */
- result->instance_size = sizeof (gpointer);
+ result->instance_size = sizeof (MonoObject) + sizeof (gpointer);
result->cast_class = result->element_class = result;
result->blittable = TRUE;
return result;
}
+/**
+ * mono_class_from_mono_type:
+ * @type: describes the type to return
+ *
+ * This returns a MonoClass for the specified MonoType, the value is never NULL.
+ */
MonoClass *
mono_class_from_mono_type (MonoType *type)
{
g_warning ("mono_class_from_mono_type: implement me 0x%02x\n", type->type);
g_assert_not_reached ();
}
-
+
+ // Yes, this returns NULL, even if it is documented as not doing so, but there
+ // is no way for the code to make it this far, due to the assert above.
return NULL;
}
MonoType *inflated = inflate_generic_type (NULL, t, context, error);
if (!mono_error_ok (error)) {
- mono_loader_assert_no_error ();
return NULL;
}
MonoClass *ret;
gboolean inflated = FALSE;
MonoType *t = mono_type_retrieve_from_typespec (image, type_spec, context, &inflated, error);
- if (!mono_error_ok (error))
- return NULL;
+ return_val_if_nok (error, NULL);
ret = mono_class_from_mono_type (t);
if (inflated)
mono_metadata_free_type (t);
* @rank: the dimension of the array class
* @bounded: whenever the array has non-zero bounds
*
- * Returns: a class object describing the array with element type @element_type and
+ * Returns: A class object describing the array with element type @element_type and
* dimension @rank.
*/
MonoClass *
GSList *list, *rootlist = NULL;
int nsize;
char *name;
- gboolean corlib_type = FALSE;
g_assert (rank <= 255);
}
}
- /* for the building corlib use System.Array from it */
- if (image->assembly && assembly_is_dynamic (image->assembly) && image->assembly_name && strcmp (image->assembly_name, "mscorlib") == 0) {
- parent = mono_class_from_name (image, "System", "Array");
- corlib_type = TRUE;
- } else {
- parent = mono_defaults.array_class;
- if (!parent->inited)
- mono_class_init (parent);
- }
+ parent = mono_defaults.array_class;
+ if (!parent->inited)
+ mono_class_init (parent);
- klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass));
+ klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassArray));
klass->image = image;
klass->name_space = eclass->name_space;
+ klass->class_kind = MONO_CLASS_ARRAY;
+
nsize = strlen (eclass->name);
name = (char *)g_malloc (nsize + 2 + rank + 1);
memcpy (name, eclass->name, nsize);
mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
- classes_size += sizeof (MonoClass);
+ classes_size += sizeof (MonoClassArray);
+ ++class_array_count;
klass->type_token = 0;
- /* all arrays are marked serializable and sealed, bug #42779 */
- klass->flags = TYPE_ATTRIBUTE_CLASS | TYPE_ATTRIBUTE_SERIALIZABLE | TYPE_ATTRIBUTE_SEALED | TYPE_ATTRIBUTE_PUBLIC;
klass->parent = parent;
klass->instance_size = mono_class_instance_size (klass->parent);
if (eclass->byval_arg.type == MONO_TYPE_TYPEDBYREF || eclass->byval_arg.type == MONO_TYPE_VOID) {
/*Arrays of those two types are invalid.*/
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ MonoError prepared_error;
+ mono_error_init (&prepared_error);
+ mono_error_set_invalid_program (&prepared_error, "Arrays of void or System.TypedReference types are invalid.");
+ mono_class_set_failure (klass, mono_error_box (&prepared_error, klass->image));
+ mono_error_cleanup (&prepared_error);
} else if (eclass->enumtype && !mono_class_enum_basetype (eclass)) {
if (!eclass->ref_info_handle || eclass->wastypebuilder) {
g_warning ("Only incomplete TypeBuilder objects are allowed to be an enum without base_type");
mono_class_setup_supertypes (klass);
- if (eclass->generic_class)
+ if (mono_class_is_ginst (eclass))
mono_class_init (eclass);
if (!eclass->size_inited)
mono_class_setup_fields (eclass);
- if (eclass->exception_type) /*FIXME we fail the array type, but we have to let other fields be set.*/
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ mono_class_set_type_load_failure_causedby_class (klass, eclass, "Could not load array element type");
+ /*FIXME we fail the array type, but we have to let other fields be set.*/
klass->has_references = MONO_TYPE_IS_REFERENCE (&eclass->byval_arg) || eclass->has_references? TRUE: FALSE;
}
klass->this_arg = klass->byval_arg;
klass->this_arg.byref = 1;
- if (corlib_type) {
- klass->inited = 1;
- }
- klass->generic_container = eclass->generic_container;
+ //WTF was this? it's wrong
+ // klass->generic_container = eclass->generic_container;
if (rank == 1 && !bounded) {
MonoClass *prev_class;
* @element_class: element class
* @rank: the dimension of the array class
*
- * Returns: a class object describing the array with element type @element_type and
+ * Returns: A class object describing the array with element type @element_type and
* dimension @rank.
*/
MonoClass *
/**
* mono_class_instance_size:
* @klass: a class
- *
- * Returns: the size of an object instance
+ *
+ * Use to get the size of a class in bytes.
+ *
+ * Returns: The size of an object instance
*/
gint32
mono_class_instance_size (MonoClass *klass)
/**
* mono_class_min_align:
* @klass: a class
- *
- * Returns: minimm alignment requirements
+ *
+ * Use to get the computed minimum alignment requirements for the specified class.
+ *
+ * Returns: minimum alignment requirements
*/
gint32
mono_class_min_align (MonoClass *klass)
* Returns: the size of a value of kind @klass
*/
gint32
-mono_class_value_size (MonoClass *klass, guint32 *align)
+mono_class_value_size (MonoClass *klass, guint32 *align)
{
gint32 size;
* mono_class_data_size:
* @klass: a class
*
- * Returns: the size of the static class data
+ * Returns: The size of the static class data
*/
gint32
mono_class_data_size (MonoClass *klass)
mono_class_init (klass);
/* This can happen with dynamically created types */
if (!klass->fields_inited)
- mono_class_setup_fields_locking (klass);
+ mono_class_setup_fields (klass);
/* in arrays, sizes.class_size is unioned with element_size
* and arrays have no static fields
static MonoClassField *
mono_class_get_field_idx (MonoClass *klass, int idx)
{
- mono_class_setup_fields_locking (klass);
- if (klass->exception_type)
+ mono_class_setup_fields (klass);
+ if (mono_class_has_failure (klass))
return NULL;
while (klass) {
+ int first_field_idx = mono_class_get_first_field_idx (klass);
if (klass->image->uncompressed_metadata) {
/*
- * klass->field.first points to the FieldPtr table, while idx points into the
+ * first_field_idx points to the FieldPtr table, while idx points into the
* Field table, so we have to do a search.
*/
/*FIXME this is broken for types with multiple fields with the same name.*/
g_assert_not_reached ();
} else {
if (klass->field.count) {
- if ((idx >= klass->field.first) && (idx < klass->field.first + klass->field.count)){
- return &klass->fields [idx - klass->field.first];
+ if ((idx >= first_field_idx) && (idx < first_field_idx + klass->field.count)){
+ return &klass->fields [idx - first_field_idx];
}
}
}
*
* Search the class @klass and it's parents for a field with the name @name.
*
- * Returns: the MonoClassField pointer of the named field or NULL
+ * Returns: The MonoClassField pointer of the named field or NULL
*/
MonoClassField *
mono_class_get_field_from_name (MonoClass *klass, const char *name)
* If @klass is an inflated generic type, the type comparison is done with the equivalent field
* of its generic type definition.
*
- * Returns: the MonoClassField pointer of the named field or NULL
+ * Returns: The MonoClassField pointer of the named field or NULL
*/
MonoClassField *
mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoType *type)
{
int i;
- mono_class_setup_fields_locking (klass);
- if (klass->exception_type)
+ mono_class_setup_fields (klass);
+ if (mono_class_has_failure (klass))
return NULL;
while (klass) {
* Get the token of a field. Note that the tokesn is only valid for the image
* the field was loaded from. Don't use this function for fields in dynamic types.
*
- * Returns: the token representing the field in the image it was loaded from.
+ * Returns: The token representing the field in the image it was loaded from.
*/
guint32
mono_class_get_field_token (MonoClassField *field)
MonoClass *klass = field->parent;
int i;
- mono_class_setup_fields_locking (klass);
+ mono_class_setup_fields (klass);
while (klass) {
if (!klass->fields)
return 0;
+ int first_field_idx = mono_class_get_first_field_idx (klass);
for (i = 0; i < klass->field.count; ++i) {
if (&klass->fields [i] == field) {
- int idx = klass->field.first + i + 1;
+ int idx = first_field_idx + i + 1;
if (klass->image->uncompressed_metadata)
idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_FIELD, idx);
return 0;
}
+/**
+ * mono_class_get_property_from_name:
+ * @klass: a class
+ * @name: name of the property to lookup in the specified class
+ *
+ * Use this method to lookup a property in a class
+ * Returns: the MonoProperty with the given name, or NULL if the property
+ * does not exist on the @klass.
+ */
MonoProperty*
mono_class_get_property_from_name (MonoClass *klass, const char *name)
{
return NULL;
}
+/**
+ * mono_class_get_property_token:
+ * @prop: MonoProperty to query
+ *
+ * Returns: The ECMA token for the specified property.
+ */
guint32
mono_class_get_property_token (MonoProperty *prop)
{
* @context: the generic context used to evaluate generic instantiations in
* @deprecated: Functions that expose MonoGenericContext are going away in mono 4.0
*
- * Returns: the MonoClass that represents @type_token in @image
+ * Returns: The MonoClass that represents @type_token in @image
*/
MonoClass *
mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
* @type_token: the token for the class
* @error: error object to return any error
*
- * Returns: the MonoClass that represents @type_token in @image
+ * Returns: The MonoClass that represents @type_token in @image, or NULL on error.
*/
MonoClass *
mono_class_get_checked (MonoImage *image, guint32 type_token, MonoError *error)
mono_error_set_bad_image (error, image,"Bad token table for dynamic image: %x", table);
return NULL;
}
- klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, NULL); /*FIXME proper error handling*/
+ klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, NULL, error);
goto done;
}
*
* This functions exists to fullfill the fact that sometimes it's desirable to have access to the
*
- * Returns: the MonoType that represents @type_token in @image
+ * Returns: The MonoType that represents @type_token in @image
*/
MonoType *
mono_type_get_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
mono_error_init (error);
//FIXME: this will not fix the very issue for which mono_type_get_full exists -but how to do it then?
- if (image_is_dynamic (image))
- return mono_class_get_type ((MonoClass *)mono_lookup_dynamic_token (image, type_token, context));
+ if (image_is_dynamic (image)) {
+ MonoClass *klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, context, error);
+ return_val_if_nok (error, NULL);
+ return mono_class_get_type (klass);
+ }
if ((type_token & 0xff000000) != MONO_TOKEN_TYPE_SPEC) {
MonoClass *klass = mono_class_get_checked (image, type_token, error);
if (!klass) {
- mono_loader_assert_no_error ();
return NULL;
}
type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated, error);
if (!type) {
- mono_loader_assert_no_error ();
return NULL;
}
return type;
}
-
+/**
+ * mono_class_get:
+ * @image: image where the class token will be looked up.
+ * @type_token: a type token from the image
+ *
+ * Returns the MonoClass with the given @type_token on the @image
+ */
MonoClass *
mono_class_get (MonoImage *image, guint32 type_token)
{
* @image: The MonoImage where the type is looked up in
* @name_space: the type namespace
* @name: the type short name.
- * @deprecated: use the _checked variant
+ * @deprecated: use the mono_class_from_name_case_checked variant instead.
*
* Obtains a MonoClass with a given namespace and a given name which
* is located in the given MonoImage. The namespace and name
{
MonoError error;
MonoClass *res = mono_class_from_name_case_checked (image, name_space, name, &error);
- g_assert (!mono_error_ok (&error));
+ mono_error_cleanup (&error);
+
return res;
}
+/**
+ * mono_class_from_name_case:
+ * @image: The MonoImage where the type is looked up in
+ * @name_space: the type namespace
+ * @name: the type short name.
+ * @error: if
+ *
+ * Obtains a MonoClass with a given namespace and a given name which
+ * is located in the given MonoImage. The namespace and name
+ * lookups are case insensitive.
+ *
+ * Returns: The MonoClass if the given namespace and name were found, or NULL if it
+ * was not found. The @error object will contain information about the problem
+ * in that case.
+ */
MonoClass *
-mono_class_from_name_case_checked (MonoImage *image, const char* name_space, const char *name, MonoError *error)
+mono_class_from_name_case_checked (MonoImage *image, const char *name_space, const char *name, MonoError *error)
{
MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
guint32 cols [MONO_TYPEDEF_SIZE];
}
static MonoClass*
-search_modules (MonoImage *image, const char *name_space, const char *name)
+search_modules (MonoImage *image, const char *name_space, const char *name, MonoError *error)
{
MonoTableInfo *file_table = &image->tables [MONO_TABLE_FILE];
MonoImage *file_image;
MonoClass *klass;
int i;
+ mono_error_init (error);
+
/*
* The EXPORTEDTYPES table only contains public types, so have to search the
* modules as well.
if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
continue;
- file_image = mono_image_load_file_for_image (image, i + 1);
+ file_image = mono_image_load_file_for_image_checked (image, i + 1, error);
if (file_image) {
- klass = mono_class_from_name (file_image, name_space, name);
- if (klass)
+ klass = mono_class_from_name_checked (file_image, name_space, name, error);
+ if (klass || !is_ok (error))
return klass;
}
}
}
static MonoClass *
-mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, const char *name, MonoError *error, GHashTable* visited_images)
+mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, const char *name, GHashTable* visited_images, MonoError *error)
{
GHashTable *nspace_table;
MonoImage *loaded_image;
if (get_class_from_name && image->tables [MONO_TABLE_EXPORTEDTYPE].rows == 0) {
gboolean res = get_class_from_name (image, name_space, name, &klass);
if (res) {
- if (!klass)
- klass = search_modules (image, name_space, name);
+ if (!klass) {
+ klass = search_modules (image, name_space, name, error);
+ if (!is_ok (error))
+ return NULL;
+ }
if (nested)
return klass ? return_nested_in (klass, nested) : NULL;
else
for (i = 0; i < image->module_count; ++i) {
MonoImage *module = image->modules [i];
- klass = mono_class_from_name (module, name_space, name);
- if (klass)
+ klass = mono_class_from_name_checked (module, name_space, name, error);
+ if (klass || !is_ok (error))
return klass;
}
}
if (!token) {
- klass = search_modules (image, name_space, name);
- if (klass)
+ klass = search_modules (image, name_space, name, error);
+ if (klass || !is_ok (error))
return klass;
- }
-
- if (!token)
return NULL;
+ }
if (mono_metadata_token_table (token) == MONO_TABLE_EXPORTEDTYPE) {
MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_FILE) {
- loaded_image = mono_assembly_load_module (image->assembly, impl >> MONO_IMPLEMENTATION_BITS);
+ loaded_image = mono_assembly_load_module_checked (image->assembly, impl >> MONO_IMPLEMENTATION_BITS, error);
if (!loaded_image)
return NULL;
- klass = mono_class_from_name_checked_aux (loaded_image, name_space, name, error, visited_images);
+ klass = mono_class_from_name_checked_aux (loaded_image, name_space, name, visited_images, error);
if (nested)
return klass ? return_nested_in (klass, nested) : NULL;
return klass;
g_assert (image->references [assembly_idx - 1]);
if (image->references [assembly_idx - 1] == (gpointer)-1)
return NULL;
- klass = mono_class_from_name_checked_aux (image->references [assembly_idx - 1]->image, name_space, name, error, visited_images);
+ klass = mono_class_from_name_checked_aux (image->references [assembly_idx - 1]->image, name_space, name, visited_images, error);
if (nested)
- return return_nested_in (klass, nested);
+ return klass ? return_nested_in (klass, nested) : NULL;
return klass;
} else {
g_assert_not_reached ();
return klass;
}
+/**
+ * mono_class_from_name_checked:
+ * @image: The MonoImage where the type is looked up in
+ * @name_space: the type namespace
+ * @name: the type short name.
+ *
+ * Obtains a MonoClass with a given namespace and a given name which
+ * is located in the given MonoImage.
+ *
+ * Works like mono_class_from_name, but error handling is tricky. It can return NULL and have no error
+ * set if the class was not found or it will return NULL and set the error if there was a loading error.
+ */
MonoClass *
mono_class_from_name_checked (MonoImage *image, const char* name_space, const char *name, MonoError *error)
{
visited_images = g_hash_table_new (g_direct_hash, g_direct_equal);
- klass = mono_class_from_name_checked_aux (image, name_space, name, error, visited_images);
+ klass = mono_class_from_name_checked_aux (image, name_space, name, visited_images, error);
g_hash_table_destroy (visited_images);
MonoClass *klass;
klass = mono_class_from_name_checked (image, name_space, name, &error);
- if (!mono_error_ok (&error)) {
- mono_loader_set_error_from_mono_error (&error);
- mono_error_cleanup (&error); /* FIXME Don't swallow the error */
- }
+ mono_error_cleanup (&error); /* FIXME Don't swallow the error */
+
+ return klass;
+}
+
+/**
+ * mono_class_load_from_name:
+ * @image: The MonoImage where the type is looked up in
+ * @name_space: the type namespace
+ * @name: the type short name.
+ *
+ * This function works exactly like mono_class_from_name but it will abort if the class is not found.
+ * This function should be used by the runtime for critical types to which there's no way to recover but crash
+ * If they are missing. Thing of System.Object or System.String.
+ */
+MonoClass *
+mono_class_load_from_name (MonoImage *image, const char* name_space, const char *name)
+{
+ MonoError error;
+ MonoClass *klass;
+
+ klass = mono_class_from_name_checked (image, name_space, name, &error);
+ if (!klass)
+ g_error ("Runtime critical type %s.%s not found", name_space, name);
+ if (!mono_error_ok (&error))
+ g_error ("Could not load runtime critical type %s.%s due to %s", name_space, name, mono_error_get_message (&error));
+ return klass;
+}
+
+/**
+ * mono_class_try_load_from_name:
+ * @image: The MonoImage where the type is looked up in
+ * @name_space: the type namespace
+ * @name: the type short name.
+ *
+ * This function tries to load a type, returning the class was found or NULL otherwise.
+ * This function should be used by the runtime when probing for optional types, those that could have being linked out.
+ *
+ * Big design consideration. This function aborts if there was an error loading the type. This prevents us from missing
+ * a type that we would otherwise assume to be available but was not due some error.
+ *
+ */
+MonoClass*
+mono_class_try_load_from_name (MonoImage *image, const char* name_space, const char *name)
+{
+ MonoError error;
+ MonoClass *klass;
+
+ klass = mono_class_from_name_checked (image, name_space, name, &error);
+ if (!mono_error_ok (&error))
+ g_error ("Could not load runtime critical type %s.%s due to %s", name_space, name, mono_error_get_message (&error));
return klass;
}
+
/**
* mono_class_is_subclass_of:
* @klass: class to probe if it is a subclass of another one
* This method determines whether @klass is a subclass of @klassc.
*
* If the @check_interfaces flag is set, then if @klassc is an interface
- * this method return true if the @klass implements the interface or
+ * this method return TRUE if the @klass implements the interface or
* if @klass is an interface, if one of its base classes is @klass.
*
* If @check_interfaces is false then, then if @klass is not an interface
- * then it returns true if the @klass is a subclass of @klassc.
+ * then it returns TRUE if the @klass is a subclass of @klassc.
*
* if @klass is an interface and @klassc is System.Object, then this function
* return true.
mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc,
gboolean check_interfaces)
{
-/*FIXME test for interfaces with variant generic arguments*/
+ /* FIXME test for interfaces with variant generic arguments */
+ mono_class_init (klass);
+ mono_class_init (klassc);
if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && !MONO_CLASS_IS_INTERFACE (klass)) {
if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, klassc->interface_id))
int i;
MonoGenericContainer *container;
- if (!klass->generic_class)
+ if (!mono_class_is_ginst (klass))
return FALSE;
- container = klass->generic_class->container_class->generic_container;
+ container = mono_class_get_generic_container (mono_class_get_generic_class (klass)->container_class);
for (i = 0; i < container->type_argc; ++i)
if (mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))
* @klass: the class to be assigned to
* @oklass: the source class
*
- * Both klass and oklass must be instances of the same generic interface.
- * Return true if @klass can be assigned to a @klass variable
+ * Both @klass and @oklass must be instances of the same generic interface.
+ *
+ * Returns: TRUE if @klass can be assigned to a @klass variable
*/
gboolean
mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass, gboolean check_for_reference_conv)
int j;
MonoType **klass_argv, **oklass_argv;
MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
- MonoGenericContainer *container = klass_gtd->generic_container;
+ MonoGenericContainer *container = mono_class_get_generic_container (klass_gtd);
if (klass == oklass)
return TRUE;
if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
return FALSE;
- klass_argv = &klass->generic_class->context.class_inst->type_argv [0];
- oklass_argv = &oklass->generic_class->context.class_inst->type_argv [0];
+ klass_argv = &mono_class_get_generic_class (klass)->context.class_inst->type_argv [0];
+ oklass_argv = &mono_class_get_generic_class (oklass)->context.class_inst->type_argv [0];
for (j = 0; j < container->type_argc; ++j) {
MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]);
* @klass: the class to be assigned to
* @oklass: the source class
*
- * Return: true if an instance of object oklass can be assigned to an
+ * Returns: TRUE if an instance of object oklass can be assigned to an
* instance of object @klass
*/
gboolean
mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
{
+ MonoError error;
/*FIXME this will cause a lot of irrelevant stuff to be loaded.*/
if (!klass->inited)
mono_class_init (klass);
if (!oklass->inited)
mono_class_init (oklass);
- if (klass->exception_type || oklass->exception_type)
+ if (mono_class_has_failure (klass) || mono_class_has_failure (oklass))
return FALSE;
if (mono_type_is_generic_argument (&klass->byval_arg)) {
}
/* interface_offsets might not be set for dynamic classes */
- if (oklass->ref_info_handle && !oklass->interface_bitmap)
+ if (oklass->ref_info_handle && !oklass->interface_bitmap) {
/*
* oklass might be a generic type parameter but they have
* interface_offsets set.
*/
- return mono_reflection_call_is_assignable_to (oklass, klass);
+ gboolean result = mono_reflection_call_is_assignable_to (oklass, klass, &error);
+ if (!is_ok (&error)) {
+ mono_error_cleanup (&error);
+ return FALSE;
+ }
+ return result;
+ }
if (!oklass->interface_bitmap)
/* Happens with generic instances of not-yet created dynamic types */
return FALSE;
return TRUE;
if (mono_class_has_variant_generic_params (klass)) {
- MonoError error;
int i;
mono_class_setup_interfaces (oklass, &error);
if (!mono_error_ok (&error)) {
int j;
MonoType **klass_argv, **oklass_argv;
MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
- MonoGenericContainer *container = klass_gtd->generic_container;
+ MonoGenericContainer *container = mono_class_get_generic_container (klass_gtd);
/*Viable candidates are instances of the same generic interface*/
if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
return FALSE;
- klass_argv = &klass->generic_class->context.class_inst->type_argv [0];
- oklass_argv = &oklass->generic_class->context.class_inst->type_argv [0];
+ klass_argv = &mono_class_get_generic_class (klass)->context.class_inst->type_argv [0];
+ oklass_argv = &mono_class_get_generic_class (oklass)->context.class_inst->type_argv [0];
for (j = 0; j < container->type_argc; ++j) {
MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]);
* mono_class_get_cctor:
* @klass: A MonoClass pointer
*
- * Returns: the static constructor of @klass if it exists, NULL otherwise.
+ * Returns: The static constructor of @klass if it exists, NULL otherwise.
*/
MonoMethod*
mono_class_get_cctor (MonoClass *klass)
return result;
}
- if (klass->generic_class && !klass->methods)
- return mono_class_get_inflated_method (klass, mono_class_get_cctor (klass->generic_class->container_class));
+ if (mono_class_is_ginst (klass) && !klass->methods)
+ return mono_class_get_inflated_method (klass, mono_class_get_cctor (mono_class_get_generic_class (klass)->container_class));
return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME);
}
* mono_class_get_finalizer:
* @klass: The MonoClass pointer
*
- * Returns: the finalizer method of @klass if it exists, NULL otherwise.
+ * Returns: The finalizer method of @klass if it exists, NULL otherwise.
*/
MonoMethod*
mono_class_get_finalizer (MonoClass *klass)
* mono_class_array_element_size:
* @klass:
*
- * Returns: the number of bytes an element of type @klass
+ * Returns: The number of bytes an element of type @klass
* uses when stored into an array.
*/
gint32
* mono_array_element_size:
* @ac: pointer to a #MonoArrayClass
*
- * Returns: the size of single array element.
+ * Returns: The size of single array element.
*/
gint32
mono_array_element_size (MonoClass *ac)
if (image_is_dynamic (image)) {
MonoClass *tmp_handle_class;
- gpointer obj = mono_lookup_dynamic_token_class (image, token, TRUE, &tmp_handle_class, context);
+ gpointer obj = mono_lookup_dynamic_token_class (image, token, TRUE, &tmp_handle_class, context, error);
+ mono_error_assert_ok (error);
g_assert (tmp_handle_class);
if (handle_class)
*handle_class = tmp_handle_class;
return NULL;
}
-/**
- * This function might need to call runtime functions so it can't be part
- * of the metadata library.
- */
-static MonoLookupDynamicToken lookup_dynamic = NULL;
-
-void
-mono_install_lookup_dynamic_token (MonoLookupDynamicToken func)
-{
- lookup_dynamic = func;
-}
-
gpointer
-mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context)
+mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context, MonoError *error)
{
MonoClass *handle_class;
-
- return lookup_dynamic (image, token, TRUE, &handle_class, context);
+ mono_error_init (error);
+ return mono_reflection_lookup_dynamic_token (image, token, TRUE, &handle_class, context, error);
}
gpointer
-mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context)
+mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error)
{
- return lookup_dynamic (image, token, valid_token, handle_class, context);
+ return mono_reflection_lookup_dynamic_token (image, token, valid_token, handle_class, context, error);
}
static MonoGetCachedClassInfo get_cached_class_info = NULL;
get_class_from_name = func;
}
+/**
+ * mono_class_get_image:
+ *
+ * Use this method to get the `MonoImage*` where this class came from.
+ *
+ * Returns: The image where this class is defined.
+ */
MonoImage*
mono_class_get_image (MonoClass *klass)
{
* mono_class_get_element_class:
* @klass: the MonoClass to act on
*
- * Returns: the element class of an array or an enumeration.
+ * Use this function to get the element class of an array.
+ *
+ * Returns: The element class of an array.
*/
MonoClass*
mono_class_get_element_class (MonoClass *klass)
* mono_class_is_valuetype:
* @klass: the MonoClass to act on
*
- * Returns: true if the MonoClass represents a ValueType.
+ * Use this method to determine if the provided `MonoClass*` represents a value type,
+ * or a reference type.
+ *
+ * Returns: TRUE if the MonoClass represents a ValueType, FALSE if it represents a reference type.
*/
gboolean
mono_class_is_valuetype (MonoClass *klass)
* mono_class_is_enum:
* @klass: the MonoClass to act on
*
- * Returns: true if the MonoClass represents an enumeration.
+ * Use this function to determine if the provided `MonoClass*` represents an enumeration.
+ *
+ * Returns: TRUE if the MonoClass represents an enumeration.
*/
gboolean
mono_class_is_enum (MonoClass *klass)
* mono_class_enum_basetype:
* @klass: the MonoClass to act on
*
- * Returns: the underlying type representation for an enumeration.
+ * Use this function to get the underlying type for an enumeration value.
+ *
+ * Returns: The underlying type representation for an enumeration.
*/
MonoType*
mono_class_enum_basetype (MonoClass *klass)
* mono_class_get_parent
* @klass: the MonoClass to act on
*
- * Returns: the parent class for this class.
+ * Returns: The parent class for this class.
*/
MonoClass*
mono_class_get_parent (MonoClass *klass)
}
/**
- * mono_class_get_nesting_type;
+ * mono_class_get_nesting_type:
* @klass: the MonoClass to act on
*
- * Returns: the container type where this type is nested or NULL if this type is not a nested type.
+ * Use this function to obtain the class that the provided `MonoClass*` is nested on.
+ *
+ * If the return is NULL, this indicates that this class is not nested.
+ *
+ * Returns: The container type where this type is nested or NULL if this type is not a nested type.
*/
MonoClass*
mono_class_get_nesting_type (MonoClass *klass)
* mono_class_get_rank:
* @klass: the MonoClass to act on
*
- * Returns: the rank for the array (the number of dimensions).
+ * Returns: The rank for the array (the number of dimensions).
*/
int
mono_class_get_rank (MonoClass *klass)
return klass->rank;
}
-/**
- * mono_class_get_flags:
- * @klass: the MonoClass to act on
- *
- * The type flags from the TypeDef table from the metadata.
- * see the TYPE_ATTRIBUTE_* definitions on tabledefs.h for the
- * different values.
- *
- * Returns: the flags from the TypeDef table.
- */
-guint32
-mono_class_get_flags (MonoClass *klass)
-{
- return klass->flags;
-}
-
/**
* mono_class_get_name
* @klass: the MonoClass to act on
*
- * Returns: the name of the class.
+ * Returns: The name of the class.
*/
const char*
mono_class_get_name (MonoClass *klass)
* mono_class_get_namespace:
* @klass: the MonoClass to act on
*
- * Returns: the namespace of the class.
+ * Returns: The namespace of the class.
*/
const char*
mono_class_get_namespace (MonoClass *klass)
*
* This method returns the internal Type representation for the class.
*
- * Returns: the MonoType from the class.
+ * Returns: The MonoType from the class.
*/
MonoType*
mono_class_get_type (MonoClass *klass)
}
/**
- * mono_class_get_type_token
+ * mono_class_get_type_token:
* @klass: the MonoClass to act on
*
* This method returns type token for the class.
*
- * Returns: the type token for the class.
+ * Returns: The type token for the class.
*/
guint32
mono_class_get_type_token (MonoClass *klass)
* mono_class_num_fields:
* @klass: the MonoClass to act on
*
- * Returns: the number of static and instance fields in the class.
+ * Returns: The number of static and instance fields in the class.
*/
int
mono_class_num_fields (MonoClass *klass)
* mono_class_num_methods:
* @klass: the MonoClass to act on
*
- * Returns: the number of methods in the class.
+ * Returns: The number of methods in the class.
*/
int
mono_class_num_methods (MonoClass *klass)
* mono_class_num_properties
* @klass: the MonoClass to act on
*
- * Returns: the number of properties in the class.
+ * Returns: The number of properties in the class.
*/
int
mono_class_num_properties (MonoClass *klass)
* mono_class_num_events:
* @klass: the MonoClass to act on
*
- * Returns: the number of events in the class.
+ * Returns: The number of events in the class.
*/
int
mono_class_num_events (MonoClass *klass)
if (!iter)
return NULL;
if (!*iter) {
- mono_class_setup_fields_locking (klass);
- if (klass->exception_type)
+ mono_class_setup_fields (klass);
+ if (mono_class_has_failure (klass))
return NULL;
/* start from the first */
if (klass->field.count) {
start_index = GPOINTER_TO_UINT (*iter);
}
+ int first_idx = mono_class_get_first_method_idx (klass);
for (i = start_index; i < klass->method.count; ++i) {
guint32 flags;
- /* klass->method.first points into the methodptr table */
- flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, klass->method.first + i, MONO_METHOD_FLAGS);
+ /* first_idx points into the methodptr table */
+ flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
if (flags & METHOD_ATTRIBUTE_VIRTUAL)
break;
if (i < klass->method.count) {
MonoError error;
- res = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass, NULL, &error);
+ res = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, &error);
mono_error_cleanup (&error); /* FIXME don't swallow the error */
/* Add 1 here so the if (*iter) check fails */
* mono_class_is_delegate
* @klass: the MonoClass to act on
*
- * Returns: true if the MonoClass represents a System.Delegate.
+ * Returns: TRUE if the MonoClass represents a System.Delegate.
*/
mono_bool
mono_class_is_delegate (MonoClass *klass)
* @klass: The MonoClass to act on
* @interface: The interface to check if @klass implements.
*
- * Returns: true if @klass implements @interface.
+ * Returns: TRUE if @klass implements @interface.
*/
mono_bool
mono_class_implements_interface (MonoClass* klass, MonoClass* iface)
* mono_field_get_name:
* @field: the MonoClassField to act on
*
- * Returns: the name of the field.
+ * Returns: The name of the field.
*/
const char*
mono_field_get_name (MonoClassField *field)
* The metadata flags for a field are encoded using the
* FIELD_ATTRIBUTE_* constants. See the tabledefs.h file for details.
*
- * Returns: the flags for the field.
+ * Returns: The flags for the field.
*/
guint32
mono_field_get_flags (MonoClassField *field)
}
/**
- * mono_field_get_offset;
+ * mono_field_get_offset:
* @field: the MonoClassField to act on
*
- * Returns: the field offset.
+ * Returns: The field offset.
*/
guint32
mono_field_get_offset (MonoClassField *field)
field_index = mono_field_get_index (field);
if (!klass->ext->field_def_values [field_index].data && !image_is_dynamic (klass->image)) {
- mono_metadata_field_info (field->parent->image, klass->field.first + field_index, NULL, &rva, NULL);
+ int first_field_idx = mono_class_get_first_field_idx (klass);
+ mono_metadata_field_info (field->parent->image, first_field_idx + field_index, NULL, &rva, NULL);
if (!rva)
g_warning ("field %s in %s should have RVA data, but hasn't", mono_field_get_name (field), field->parent->name);
klass->ext->field_def_values [field_index].data = mono_image_rva_map (field->parent->image, rva);
}
/**
- * mono_field_get_data;
+ * mono_field_get_data:
* @field: the MonoClassField to act on
*
- * Returns: pointer to the metadata constant value or to the field
+ * Returns: A pointer to the metadata constant value or to the field
* data if it has an RVA flag.
*/
const char *
* mono_property_get_name:
* @prop: the MonoProperty to act on
*
- * Returns: the name of the property
+ * Returns: The name of the property
*/
const char*
mono_property_get_name (MonoProperty *prop)
* mono_property_get_set_method
* @prop: the MonoProperty to act on.
*
- * Returns: the setter method of the property (A MonoMethod)
+ * Returns: The setter method of the property (A MonoMethod)
*/
MonoMethod*
mono_property_get_set_method (MonoProperty *prop)
* mono_property_get_get_method
* @prop: the MonoProperty to act on.
*
- * Returns: the setter method of the property (A MonoMethod)
+ * Returns: The setter method of the property (A MonoMethod)
*/
MonoMethod*
mono_property_get_get_method (MonoProperty *prop)
* mono_property_get_parent:
* @prop: the MonoProperty to act on.
*
- * Returns: the MonoClass where the property was defined.
+ * Returns: The MonoClass where the property was defined.
*/
MonoClass*
mono_property_get_parent (MonoProperty *prop)
* The metadata flags for a property are encoded using the
* PROPERTY_ATTRIBUTE_* constants. See the tabledefs.h file for details.
*
- * Returns: the flags for the property.
+ * Returns: The flags for the property.
*/
guint32
mono_property_get_flags (MonoProperty *prop)
* mono_event_get_name:
* @event: the MonoEvent to act on
*
- * Returns: the name of the event.
+ * Returns: The name of the event.
*/
const char*
mono_event_get_name (MonoEvent *event)
* mono_event_get_add_method:
* @event: The MonoEvent to act on.
*
- * Returns: the @add' method for the event (a MonoMethod).
+ * Returns: The @add' method for the event (a MonoMethod).
*/
MonoMethod*
mono_event_get_add_method (MonoEvent *event)
* mono_event_get_remove_method:
* @event: The MonoEvent to act on.
*
- * Returns: the @remove method for the event (a MonoMethod).
+ * Returns: The @remove method for the event (a MonoMethod).
*/
MonoMethod*
mono_event_get_remove_method (MonoEvent *event)
* mono_event_get_raise_method:
* @event: The MonoEvent to act on.
*
- * Returns: the @raise method for the event (a MonoMethod).
+ * Returns: The @raise method for the event (a MonoMethod).
*/
MonoMethod*
mono_event_get_raise_method (MonoEvent *event)
* mono_event_get_parent:
* @event: the MonoEvent to act on.
*
- * Returns: the MonoClass where the event is defined.
+ * Returns: The MonoClass where the event is defined.
*/
MonoClass*
mono_event_get_parent (MonoEvent *event)
* The metadata flags for an event are encoded using the
* EVENT_* constants. See the tabledefs.h file for details.
*
- * Returns: the flags for the event.
+ * Returns: The flags for the event.
*/
guint32
mono_event_get_flags (MonoEvent *event)
int i;
/* Search directly in the metadata to avoid calling setup_methods () */
+ int first_idx = mono_class_get_first_method_idx (klass);
for (i = 0; i < klass->method.count; ++i) {
MonoError error;
guint32 cols [MONO_METHOD_SIZE];
MonoMethod *method;
MonoMethodSignature *sig;
- /* klass->method.first points into the methodptr table */
- mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, klass->method.first + i, cols, MONO_METHOD_SIZE);
+ /* first_idx points into the methodptr table */
+ mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, first_idx + i, cols, MONO_METHOD_SIZE);
if (!strcmp (mono_metadata_string_heap (klass->image, cols [MONO_METHOD_NAME]), name)) {
- method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass, NULL, &error);
+ method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, &error);
if (!method) {
mono_error_cleanup (&error); /* FIXME don't swallow the error */
continue;
mono_class_init (klass);
- if (klass->generic_class && !klass->methods) {
- res = mono_class_get_method_from_name_flags (klass->generic_class->container_class, name, param_count, flags);
+ if (mono_class_is_ginst (klass) && !klass->methods) {
+ res = mono_class_get_method_from_name_flags (mono_class_get_generic_class (klass)->container_class, name, param_count, flags);
if (res) {
MonoError error;
res = mono_class_inflate_generic_method_full_checked (res, klass, mono_class_get_context (klass), &error);
*
* LOCKING: Acquires the loader lock.
*/
-gboolean
-mono_class_set_failure (MonoClass *klass, guint32 ex_type, void *ex_data)
+static gboolean
+mono_class_set_failure (MonoClass *klass, MonoErrorBoxed *boxed_error)
{
- if (klass->exception_type)
+ g_assert (boxed_error != NULL);
+
+ if (mono_class_has_failure (klass))
return FALSE;
mono_loader_lock ();
- klass->exception_type = ex_type;
- if (ex_data)
- mono_image_property_insert (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA, ex_data);
+ klass->has_failure = 1;
+ mono_image_property_insert (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA, boxed_error);
mono_loader_unlock ();
return TRUE;
}
+gboolean
+mono_class_has_failure (const MonoClass *klass)
+{
+ g_assert (klass != NULL);
+ return klass->has_failure != 0;
+}
+
+
+/**
+ * mono_class_set_type_load_failure:
+ * @klass: class in which the failure was detected
+ * @fmt: Printf-style error message string.
+ *
+ * Collect detected failure informaion in the class for later processing.
+ * The error is stored as a MonoErrorBoxed as with mono_error_set_type_load_class ()
+ * Note that only the first failure is kept.
+ *
+ * Returns FALSE if a failure was already set on the class, or TRUE otherwise.
+ *
+ * LOCKING: Acquires the loader lock.
+ */
+gboolean
+mono_class_set_type_load_failure (MonoClass *klass, const char * fmt, ...)
+{
+ MonoError prepare_error;
+ va_list args;
+
+ if (mono_class_has_failure (klass))
+ return FALSE;
+
+ mono_error_init (&prepare_error);
+
+ va_start (args, fmt);
+ mono_error_vset_type_load_class (&prepare_error, klass, fmt, args);
+ va_end (args);
+
+ MonoErrorBoxed *box = mono_error_box (&prepare_error, klass->image);
+ mono_error_cleanup (&prepare_error);
+ return mono_class_set_failure (klass, box);
+}
+
/*
* mono_class_get_exception_data:
*
*
* LOCKING: Acquires the loader lock.
*/
-gpointer
-mono_class_get_exception_data (MonoClass *klass)
+static gpointer
+mono_class_get_exception_data (const MonoClass *klass)
{
- return mono_image_property_lookup (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA);
+ return mono_image_property_lookup (klass->image, (MonoClass*)klass, MONO_CLASS_PROP_EXCEPTION_DATA);
}
/**
{
mono_os_mutex_init (&classes_mutex);
+ mono_native_tls_alloc (&setup_fields_tls_id, NULL);
+ mono_native_tls_alloc (&init_pending_tls_id, NULL);
+
+ mono_counters_register ("MonoClassDef count",
+ MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_def_count);
+ mono_counters_register ("MonoClassGtd count",
+ MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gtd_count);
+ mono_counters_register ("MonoClassGenericInst count",
+ MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ginst_count);
+ mono_counters_register ("MonoClassGenericParam count",
+ MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gparam_count);
+ mono_counters_register ("MonoClassArray count",
+ MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_array_count);
+ mono_counters_register ("MonoClassPointer count",
+ MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_pointer_count);
mono_counters_register ("Inflated methods size",
MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_methods_size);
- mono_counters_register ("Inflated classes",
- MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes);
mono_counters_register ("Inflated classes size",
MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes_size);
mono_counters_register ("MonoClass size",
MONO_COUNTER_METADATA | MONO_COUNTER_INT, &classes_size);
mono_counters_register ("MonoClassExt size",
MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ext_size);
+
+ mono_counters_register ("MonoClassExt count",
+ MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ext_count);
}
/**
void
mono_classes_cleanup (void)
{
+ mono_native_tls_free (setup_fields_tls_id);
+ mono_native_tls_free (init_pending_tls_id);
+
if (global_interface_bitset)
mono_bitset_free (global_interface_bitset);
global_interface_bitset = NULL;
MonoException*
mono_class_get_exception_for_failure (MonoClass *klass)
{
- gpointer exception_data = mono_class_get_exception_data (klass);
-
- switch (klass->exception_type) {
- case MONO_EXCEPTION_TYPE_LOAD: {
- MonoString *name;
- MonoException *ex;
- char *str = mono_type_get_full_name (klass);
- char *astr = klass->image->assembly? mono_stringify_assembly_name (&klass->image->assembly->aname): NULL;
- name = mono_string_new (mono_domain_get (), str);
- g_free (str);
- ex = mono_get_exception_type_load (name, astr);
- g_free (astr);
- return ex;
- }
- case MONO_EXCEPTION_MISSING_METHOD: {
- char *class_name = (char *)exception_data;
- char *assembly_name = class_name + strlen (class_name) + 1;
-
- return mono_get_exception_missing_method (class_name, assembly_name);
- }
- case MONO_EXCEPTION_MISSING_FIELD: {
- char *class_name = (char *)exception_data;
- char *member_name = class_name + strlen (class_name) + 1;
-
- return mono_get_exception_missing_field (class_name, member_name);
- }
- case MONO_EXCEPTION_FILE_NOT_FOUND: {
- char *msg_format = (char *)exception_data;
- char *assembly_name = msg_format + strlen (msg_format) + 1;
- char *msg = g_strdup_printf (msg_format, assembly_name);
- MonoException *ex;
-
- ex = mono_get_exception_file_not_found2 (msg, mono_string_new (mono_domain_get (), assembly_name));
-
- g_free (msg);
-
- return ex;
- }
- case MONO_EXCEPTION_BAD_IMAGE: {
- return mono_get_exception_bad_image_format ((const char *)exception_data);
- }
- default: {
- MonoLoaderError *error;
- MonoException *ex;
-
- error = mono_loader_get_last_error ();
- if (error != NULL){
- ex = mono_loader_error_prepare_exception (error);
- return ex;
- }
-
- /* TODO - handle other class related failures */
+ if (!mono_class_has_failure (klass))
return NULL;
- }
- }
+ MonoError unboxed_error;
+ mono_error_init (&unboxed_error);
+ mono_error_set_for_class_failure (&unboxed_error, klass);
+ return mono_error_convert_to_exception (&unboxed_error);
}
static gboolean
MonoClass *
mono_class_get_generic_type_definition (MonoClass *klass)
{
- return klass->generic_class ? klass->generic_class->container_class : klass;
+ MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
+ return gklass ? gklass->container_class : klass;
}
/*
get_generic_definition_class (MonoClass *klass)
{
while (klass) {
- if (klass->generic_class && klass->generic_class->container_class)
- return klass->generic_class->container_class;
+ MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
+ if (gklass && gklass->container_class)
+ return gklass->container_class;
klass = klass->parent;
}
return NULL;
{
int access_level;
+ if (access_klass == member_klass)
+ return TRUE;
+
if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
return TRUE;
if (member_klass->element_class && !member_klass->enumtype)
member_klass = member_klass->element_class;
- access_level = member_klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
+ access_level = mono_class_get_flags (member_klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK;
if (member_klass->byval_arg.type == MONO_TYPE_VAR || member_klass->byval_arg.type == MONO_TYPE_MVAR)
return TRUE;
- if (member_klass->generic_class && !can_access_instantiation (access_klass, member_klass->generic_class->context.class_inst))
+ if (mono_class_is_ginst (member_klass) && !can_access_instantiation (access_klass, mono_class_get_generic_class (member_klass)->context.class_inst))
return FALSE;
if (is_nesting_type (access_klass, member_klass) || (access_klass->nested_in && is_nesting_type (access_klass->nested_in, member_klass)))
if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
return TRUE;
- if (((access_klass->generic_class && access_klass->generic_class->container_class) ||
- access_klass->generic_container) &&
+ MonoGenericClass *access_gklass = mono_class_try_get_generic_class (access_klass);
+ if (((access_gklass && access_gklass->container_class) ||
+ mono_class_is_gtd (access_klass)) &&
(member_generic_def = get_generic_definition_class (member_klass))) {
MonoClass *access_container;
- if (access_klass->generic_container)
+ if (mono_class_is_gtd (access_klass))
access_container = access_klass;
else
- access_container = access_klass->generic_class->container_class;
+ access_container = access_gklass->container_class;
if (can_access_member (access_container, member_generic_def, context_klass, access_level))
return TRUE;
return FALSE;
}
+/**
+ * mono_method_can_access_field:
+ * @method: Method that will attempt to access the field
+ * @field: the field to access
+ *
+ * Used to determine if a method is allowed to access the specified field.
+ *
+ * Returns: TRUE if the given @method is allowed to access the @field while following
+ * the accessibility rules of the CLI.
+ */
gboolean
mono_method_can_access_field (MonoMethod *method, MonoClassField *field)
{
return can;
}
+/**
+ * mono_method_can_access_method:
+ * @method: Method that will attempt to access the other method
+ * @called: the method that we want to probe for accessibility.
+ *
+ * Used to determine if the @method is allowed to access the specified @called method.
+ *
+ * Returns: TRUE if the given @method is allowed to invoke the @called while following
+ * the accessibility rules of the CLI.
+ */
gboolean
mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
{
- int can = can_access_member (method->klass, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
- if (!can) {
- MonoClass *nested = method->klass->nested_in;
- while (nested) {
- can = can_access_member (nested, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
- if (can)
- return TRUE;
- nested = nested->nested_in;
- }
- }
- /*
- * FIXME:
- * with generics calls to explicit interface implementations can be expressed
- * directly: the method is private, but we must allow it. This may be opening
- * a hole or the generics code should handle this differently.
- * Maybe just ensure the interface type is public.
- */
- if ((called->flags & METHOD_ATTRIBUTE_VIRTUAL) && (called->flags & METHOD_ATTRIBUTE_FINAL))
- return TRUE;
- return can;
+ method = mono_method_get_method_definition (method);
+ called = mono_method_get_method_definition (called);
+ return mono_method_can_access_method_full (method, called, NULL);
}
/*
gboolean
mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, MonoClass *context_klass)
{
+ /* Wrappers are except from access checks */
+ if (method->wrapper_type != MONO_WRAPPER_NONE || called->wrapper_type != MONO_WRAPPER_NONE)
+ return TRUE;
+
MonoClass *access_class = method->klass;
MonoClass *member_class = called->klass;
int can = can_access_member (access_class, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
* FIXME: enum types are not allowed to have a cctor, but mono_reflection_create_runtime_class sets has_cctor to 1 for all types
* FIXME: TypeBuilder enums can have any kind of static fields, but the spec is very explicit about that (P II 14.3)
*/
-gboolean mono_class_is_valid_enum (MonoClass *klass) {
+gboolean
+mono_class_is_valid_enum (MonoClass *klass)
+{
MonoClassField * field;
gpointer iter = NULL;
gboolean found_base_field = FALSE;
return FALSE;
}
- if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT)
+ if (!mono_class_is_auto_layout (klass))
return FALSE;
while ((field = mono_class_get_fields (klass, &iter))) {
gboolean
mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass)
{
- return gklass->context.class_inst == gklass->container_class->generic_container->context.class_inst;
+ return gklass->context.class_inst == mono_class_get_generic_container (gklass->container_class)->context.class_inst;
}
/*
if (!klass->ext)
klass->ext = ext;
class_ext_size += sizeof (MonoClassExt);
+ ++class_ext_count;
mono_image_unlock (klass->image);
}
if (interface_count > 1)
interfaces [1] = mono_class_bind_generic_parameters (
mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
- } else if (klass->generic_class) {
- MonoClass *gklass = klass->generic_class->container_class;
+ } else if (mono_class_is_ginst (klass)) {
+ MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
mono_class_setup_interfaces (gklass, error);
if (!mono_error_ok (error)) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not setup the interfaces"));
+ mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
return;
}
interface_count = gklass->interface_count;
interfaces = mono_class_new0 (klass, MonoClass *, interface_count);
for (i = 0; i < interface_count; i++) {
- interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (klass->generic_class), error);
+ interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (mono_class_get_generic_class (klass)), error);
if (!mono_error_ok (error)) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not setup the interfaces"));
+ mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
return;
}
}
{
MonoClass *klass = field->parent;
MonoImage *image = klass->image;
- MonoClass *gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL;
+ MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL;
int field_idx = field - klass->fields;
mono_error_init (error);
MonoClassField *gfield = >d->fields [field_idx];
MonoType *gtype = mono_field_get_type_checked (gfield, error);
if (!mono_error_ok (error)) {
- char *err_msg = g_strdup_printf ("Could not load field %d type due to: %s", field_idx, mono_error_get_message (error));
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, err_msg);
- g_free (err_msg);
+ char *full_name = mono_type_get_full_name (gtd);
+ mono_class_set_type_load_failure (klass, "Could not load generic type of field '%s:%s' (%d) due to: %s", full_name, gfield->name, field_idx, mono_error_get_message (error));
+ g_free (full_name);
}
field->type = mono_class_inflate_generic_type_no_copy (image, gtype, mono_class_get_context (klass), error);
if (!mono_error_ok (error)) {
- char *err_msg = g_strdup_printf ("Could not load field %d type due to: %s", field_idx, mono_error_get_message (error));
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, err_msg);
- g_free (err_msg);
+ char *full_name = mono_type_get_full_name (klass);
+ mono_class_set_type_load_failure (klass, "Could not load instantiated type of field '%s:%s' (%d) due to: %s", full_name, field->name, field_idx, mono_error_get_message (error));
+ g_free (full_name);
}
} else {
const char *sig;
guint32 cols [MONO_FIELD_SIZE];
MonoGenericContainer *container = NULL;
- int idx = klass->field.first + field_idx;
+ int idx = mono_class_get_first_field_idx (klass) + field_idx;
/*FIXME, in theory we do not lazy load SRE fields*/
g_assert (!image_is_dynamic (image));
- if (klass->generic_container) {
- container = klass->generic_container;
+ if (mono_class_is_gtd (klass)) {
+ container = mono_class_get_generic_container (klass);
} else if (gtd) {
- container = gtd->generic_container;
+ container = mono_class_get_generic_container (gtd);
g_assert (container);
}
- /* klass->field.first and idx points into the fieldptr table */
+ /* first_field_idx and idx points into the fieldptr table */
mono_metadata_decode_table_row (image, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
if (!mono_verifier_verify_field_signature (image, cols [MONO_FIELD_SIGNATURE], NULL)) {
- mono_error_set_type_load_class (error, klass, "Could not verify field %s signature", field->name);
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ char *full_name = mono_type_get_full_name (klass);
+ mono_error_set_type_load_class (error, klass, "Could not verify field '%s:%s' signature", full_name, field->name);;
+ mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
+ g_free (full_name);
return;
}
mono_metadata_decode_value (sig, &sig);
/* FIELD signature == 0x06 */
g_assert (*sig == 0x06);
- field->type = mono_metadata_parse_type_full (image, container, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
- if (!field->type)
- mono_class_set_failure_from_loader_error (klass, error, g_strdup_printf ("Could not load field %s type", field->name));
+
+ field->type = mono_metadata_parse_type_checked (image, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error);
+ if (!field->type) {
+ char *full_name = mono_type_get_full_name (klass);
+ mono_class_set_type_load_failure (klass, "Could not load type of field '%s:%s' (%d) due to: %s", full_name, field->name, field_idx, mono_error_get_message (error));
+ g_free (full_name);
+ }
}
}
{
MonoClass *klass = field->parent;
MonoImage *image = klass->image;
- MonoClass *gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL;
+ MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL;
int field_idx = field - klass->fields;
MonoClassField *gfield = >d->fields [field_idx];
return mono_field_get_flags (gfield);
} else {
- int idx = klass->field.first + field_idx;
+ int idx = mono_class_get_first_field_idx (klass) + field_idx;
/*FIXME, in theory we do not lazy load SRE fields*/
g_assert (!image_is_dynamic (image));
}
}
-/**
- * mono_class_setup_basic_field_info:
- * @class: The class to initialize
- *
- * Initializes the klass->fields array of fields.
- * Aquires the loader lock.
- */
-static void
-mono_class_setup_basic_field_info_locking (MonoClass *klass)
-{
- mono_loader_lock ();
- mono_class_setup_basic_field_info (klass);
- mono_loader_unlock ();
-}
-
/**
* mono_class_get_fields_lazy:
* @klass: the MonoClass to act on
if (!iter)
return NULL;
if (!*iter) {
- mono_class_setup_basic_field_info_locking (klass);
+ mono_class_setup_basic_field_info (klass);
if (!klass->fields)
return NULL;
/* start from the first */
return mono_type_full_name (&klass->byval_arg);
}
+/* Declare all shared lazy type lookup functions */
+GENERATE_TRY_GET_CLASS_WITH_CACHE (safehandle, System.Runtime.InteropServices, SafeHandle)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* Copyright 2011 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"
#include "loader.h"
#include "cil-coff.h"
#include "metadata/marshal.h"
+#include "metadata/marshal-internals.h"
#include "metadata/method-builder.h"
#include "metadata/tabledefs.h"
#include "metadata/exception.h"
#include "mono/metadata/remoting.h"
#include "mono/metadata/reflection-internals.h"
#include "mono/metadata/threadpool-ms.h"
+#include "mono/metadata/handle.h"
#include "mono/utils/mono-counters.h"
#include "mono/utils/mono-tls.h"
#include "mono/utils/mono-memory-model.h"
#include "mono/utils/atomic.h"
#include <mono/utils/mono-threads.h>
+#include <mono/utils/mono-threads-coop.h>
+#include <mono/utils/mono-error-internals.h>
#include <string.h>
#include <errno.h>
static gboolean use_aot_wrappers;
+static int class_marshal_info_count;
+
+static void ftnptr_eh_callback_default (guint32 gchandle);
+
+static MonoFtnPtrEHCallback ftnptr_eh_callback = ftnptr_eh_callback_default;
+
static void
delegate_hash_table_add (MonoDelegate *d);
+static void
+delegate_hash_table_remove (MonoDelegate *d);
+
static void
emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object);
static void
-emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object, MonoMarshalNative string_encoding);
+emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object, int offset_of_first_child_field, MonoMarshalNative string_encoding);
static void
mono_struct_delete_old (MonoClass *klass, char *ptr);
mono_marshal_string_to_utf16_copy (MonoString *s);
static gpointer
-mono_string_to_lpstr (MonoString *string_obj);
+mono_string_to_utf8str (MonoString *string_obj);
static MonoStringBuilder *
mono_string_utf8_to_builder2 (char *text);
static void init_safe_handle (void);
+static void*
+ves_icall_marshal_alloc (gulong size);
+
+void
+mono_string_utf8_to_builder (MonoStringBuilder *sb, char *text);
+
+void
+mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text);
+
+gchar*
+mono_string_builder_to_utf8 (MonoStringBuilder *sb);
+
+gunichar2*
+mono_string_builder_to_utf16 (MonoStringBuilder *sb);
+
+void
+mono_string_to_byvalstr (gpointer dst, MonoString *src, int size);
+
+void
+mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size);
+
+gpointer
+mono_delegate_to_ftnptr (MonoDelegate *delegate);
+
+MonoDelegate*
+mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn);
+
+gpointer
+mono_array_to_savearray (MonoArray *array);
+
+gpointer
+mono_array_to_lparray (MonoArray *array);
+
+void
+mono_free_lparray (MonoArray *array, gpointer* nativeArray);
+
+gpointer
+mono_marshal_asany (MonoObject *obj, MonoMarshalNative string_encoding, int param_attrs);
+
+void
+mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_encoding, int param_attrs);
+
+gpointer
+mono_array_to_savearray (MonoArray *array);
+
+gpointer
+mono_array_to_lparray (MonoArray *array);
+
+void
+mono_free_lparray (MonoArray *array, gpointer* nativeArray);
+
+static void
+mono_marshal_ftnptr_eh_callback (guint32 gchandle);
+
+static MonoThreadInfo*
+mono_icall_start (HandleStackMark *stackmark, MonoError *error);
+
+static void
+mono_icall_end (MonoThreadInfo *info, HandleStackMark *stackmark, MonoError *error);
+
+/* Lazy class loading functions */
+static GENERATE_GET_CLASS_WITH_CACHE (string_builder, System.Text, StringBuilder)
+static GENERATE_GET_CLASS_WITH_CACHE (date_time, System, DateTime)
+static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_function_pointer_attribute, System.Runtime.InteropServices, UnmanagedFunctionPointerAttribute)
+static GENERATE_TRY_GET_CLASS_WITH_CACHE (icustom_marshaler, System.Runtime.InteropServices, ICustomMarshaler)
+
/* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */
static MonoMethod *sh_dangerous_add_ref;
static MonoMethod *sh_dangerous_release;
-
static void
init_safe_handle ()
{
sh_dangerous_add_ref = mono_class_get_method_from_name (
- mono_defaults.safehandle_class, "DangerousAddRef", 1);
+ mono_class_try_get_safehandle_class (), "DangerousAddRef", 1);
sh_dangerous_release = mono_class_get_method_from_name (
- mono_defaults.safehandle_class, "DangerousRelease", 0);
+ mono_class_try_get_safehandle_class (), "DangerousRelease", 0);
}
static void
-register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
+register_icall (gpointer func, const char *name, const char *sigstr, gboolean no_wrapper)
{
MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
- mono_register_jit_icall (func, name, sig, save);
+ mono_register_jit_icall (func, name, sig, no_wrapper);
}
MonoMethodSignature*
mono_native_tls_alloc (&load_type_info_tls_id, NULL);
}
+static MonoObject*
+mono_object_isinst_icall (MonoObject *obj, MonoClass *klass)
+{
+ MonoError error;
+ MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
+ mono_error_set_pending_exception (&error);
+ return result;
+}
+
+static MonoString*
+ves_icall_mono_string_from_utf16 (gunichar2 *data)
+{
+ MonoError error;
+ MonoString *result = mono_string_from_utf16_checked (data, &error);
+ mono_error_set_pending_exception (&error);
+ return result;
+}
+
+static char*
+ves_icall_mono_string_to_utf8 (MonoString *str)
+{
+ MonoError error;
+ char *result = mono_string_to_utf8_checked (str, &error);
+ mono_error_set_pending_exception (&error);
+ return result;
+}
+
void
mono_marshal_init (void)
{
register_icall (mono_marshal_string_to_utf16, "mono_marshal_string_to_utf16", "ptr obj", FALSE);
register_icall (mono_marshal_string_to_utf16_copy, "mono_marshal_string_to_utf16_copy", "ptr obj", FALSE);
register_icall (mono_string_to_utf16, "mono_string_to_utf16", "ptr obj", FALSE);
- register_icall (mono_string_from_utf16, "mono_string_from_utf16", "obj ptr", FALSE);
+ register_icall (ves_icall_mono_string_from_utf16, "ves_icall_mono_string_from_utf16", "obj ptr", FALSE);
register_icall (mono_string_from_byvalstr, "mono_string_from_byvalstr", "obj ptr int", FALSE);
register_icall (mono_string_from_byvalwstr, "mono_string_from_byvalwstr", "obj ptr int", FALSE);
register_icall (mono_string_new_wrapper, "mono_string_new_wrapper", "obj ptr", FALSE);
register_icall (mono_string_new_len_wrapper, "mono_string_new_len_wrapper", "obj ptr int", FALSE);
- register_icall (mono_string_to_utf8, "mono_string_to_utf8", "ptr obj", FALSE);
- register_icall (mono_string_to_lpstr, "mono_string_to_lpstr", "ptr obj", FALSE);
+ register_icall (ves_icall_mono_string_to_utf8, "ves_icall_mono_string_to_utf8", "ptr obj", FALSE);
+ register_icall (mono_string_to_utf8str, "mono_string_to_utf8str", "ptr obj", FALSE);
register_icall (mono_string_to_ansibstr, "mono_string_to_ansibstr", "ptr object", FALSE);
register_icall (mono_string_builder_to_utf8, "mono_string_builder_to_utf8", "ptr object", FALSE);
register_icall (mono_string_builder_to_utf16, "mono_string_builder_to_utf16", "ptr object", FALSE);
register_icall (mono_ftnptr_to_delegate, "mono_ftnptr_to_delegate", "object ptr ptr", FALSE);
register_icall (mono_marshal_asany, "mono_marshal_asany", "ptr object int32 int32", FALSE);
register_icall (mono_marshal_free_asany, "mono_marshal_free_asany", "void object ptr int32 int32", FALSE);
- register_icall (mono_marshal_alloc, "mono_marshal_alloc", "ptr int32", FALSE);
+ register_icall (ves_icall_marshal_alloc, "ves_icall_marshal_alloc", "ptr int32", FALSE);
register_icall (mono_marshal_free, "mono_marshal_free", "void ptr", FALSE);
register_icall (mono_marshal_set_last_error, "mono_marshal_set_last_error", "void", FALSE);
register_icall (mono_marshal_set_last_error_windows, "mono_marshal_set_last_error_windows", "void int32", FALSE);
register_icall (mono_string_to_byvalstr, "mono_string_to_byvalstr", "void ptr ptr int32", FALSE);
register_icall (mono_string_to_byvalwstr, "mono_string_to_byvalwstr", "void ptr ptr int32", FALSE);
register_icall (g_free, "g_free", "void ptr", FALSE);
- register_icall (mono_object_isinst, "mono_object_isinst", "object object ptr", FALSE);
+ register_icall (mono_object_isinst_icall, "mono_object_isinst_icall", "object object ptr", FALSE);
register_icall (mono_struct_delete_old, "mono_struct_delete_old", "void ptr ptr", FALSE);
register_icall (mono_delegate_begin_invoke, "mono_delegate_begin_invoke", "object object ptr", FALSE);
register_icall (mono_delegate_end_invoke, "mono_delegate_end_invoke", "object object ptr", FALSE);
- register_icall (mono_compile_method, "mono_compile_method", "ptr ptr", FALSE);
register_icall (mono_context_get, "mono_context_get", "object", FALSE);
register_icall (mono_context_set, "mono_context_set", "void object", FALSE);
register_icall (mono_gc_wbarrier_generic_nostore, "wb_generic", "void ptr", FALSE);
register_icall (mono_gchandle_get_target, "mono_gchandle_get_target", "object int32", TRUE);
+ register_icall (mono_gchandle_new, "mono_gchandle_new", "uint32 object bool", TRUE);
register_icall (mono_marshal_isinst_with_cache, "mono_marshal_isinst_with_cache", "object object ptr ptr", FALSE);
+ register_icall (mono_marshal_ftnptr_eh_callback, "mono_marshal_ftnptr_eh_callback", "void uint32", TRUE);
+ register_icall (mono_threads_enter_gc_safe_region_unbalanced, "mono_threads_enter_gc_safe_region_unbalanced", "ptr ptr", TRUE);
+ register_icall (mono_threads_exit_gc_safe_region_unbalanced, "mono_threads_exit_gc_safe_region_unbalanced", "void ptr ptr", TRUE);
+ register_icall (mono_threads_attach_coop, "mono_threads_attach_coop", "ptr ptr ptr", TRUE);
+ register_icall (mono_threads_detach_coop, "mono_threads_detach_coop", "void ptr ptr", TRUE);
+ register_icall (mono_icall_start, "mono_icall_start", "ptr ptr ptr", TRUE);
+ register_icall (mono_icall_end, "mono_icall_end", "void ptr ptr ptr", TRUE);
+ register_icall (mono_handle_new, "mono_handle_new", "ptr ptr", TRUE);
mono_cominterop_init ();
mono_remoting_init ();
- if (mono_threads_is_coop_enabled ()) {
- register_icall (mono_threads_prepare_blocking, "mono_threads_prepare_blocking", "ptr ptr", FALSE);
- register_icall (mono_threads_finish_blocking, "mono_threads_finish_blocking", "void ptr ptr", FALSE);
- register_icall (mono_threads_reset_blocking_start, "mono_threads_reset_blocking_start","ptr ptr", TRUE);
- register_icall (mono_threads_reset_blocking_end, "mono_threads_reset_blocking_end","void ptr ptr", TRUE);
- }
+ mono_counters_register ("MonoClass::class_marshal_info_count count",
+ MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_marshal_info_count);
+
}
}
mono_marshal_unlock ();
}
+/* This is a JIT icall, it sets the pending exception and return NULL on error */
gpointer
mono_delegate_to_ftnptr (MonoDelegate *delegate)
{
+ MonoError error;
MonoMethod *method, *wrapper;
MonoClass *klass;
uint32_t target_handle = 0;
g_assert (klass->delegate);
method = delegate->method;
+ if (delegate->method_is_virtual)
+ method = mono_object_get_virtual_method (delegate->target, method);
- if (mono_method_signature (method)->pinvoke) {
+ if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
const char *exc_class, *exc_arg;
gpointer ftnptr;
ftnptr = mono_lookup_pinvoke_call (method, &exc_class, &exc_arg);
if (!ftnptr) {
g_assert (exc_class);
- mono_raise_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
+ mono_set_pending_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
+ return NULL;
}
return ftnptr;
}
wrapper = mono_marshal_get_managed_wrapper (method, klass, target_handle);
- delegate->delegate_trampoline = mono_compile_method (wrapper);
+ delegate->delegate_trampoline = mono_compile_method_checked (wrapper, &error);
+ if (!is_ok (&error))
+ goto fail;
// Add the delegate to the delegate hash table
delegate_hash_table_add (delegate);
mono_object_register_finalizer ((MonoObject*)delegate);
return delegate->delegate_trampoline;
+
+fail:
+ if (target_handle != 0)
+ mono_gchandle_free (target_handle);
+ mono_error_set_pending_exception (&error);
+ return NULL;
}
/*
static void
parse_unmanaged_function_pointer_attr (MonoClass *klass, MonoMethodPInvoke *piinfo)
{
- static MonoClass *UnmanagedFunctionPointerAttribute;
+ MonoError error;
MonoCustomAttrInfo *cinfo;
MonoReflectionUnmanagedFunctionPointerAttribute *attr;
- if (!UnmanagedFunctionPointerAttribute)
- UnmanagedFunctionPointerAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
-
/* The attribute is only available in Net 2.0 */
- if (UnmanagedFunctionPointerAttribute) {
+ if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
/*
* The pinvoke attributes are stored in a real custom attribute so we have to
* construct it.
*/
- cinfo = mono_custom_attrs_from_class (klass);
+ cinfo = mono_custom_attrs_from_class_checked (klass, &error);
+ if (!mono_error_ok (&error)) {
+ g_warning ("Could not load UnmanagedFunctionPointerAttribute due to %s", mono_error_get_message (&error));
+ mono_error_cleanup (&error);
+ }
if (cinfo && !mono_runtime_get_no_exec ()) {
- MonoError error;
- attr = (MonoReflectionUnmanagedFunctionPointerAttribute*)mono_custom_attrs_get_attr_checked (cinfo, UnmanagedFunctionPointerAttribute, &error);
+ attr = (MonoReflectionUnmanagedFunctionPointerAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_try_get_unmanaged_function_pointer_attribute_class (), &error);
if (attr) {
piinfo->piflags = (attr->call_conv << 8) | (attr->charset ? (attr->charset - 1) * 2 : 1) | attr->set_last_error;
} else {
}
}
+/* This is a JIT icall, it sets the pending exception and returns NULL on error */
MonoDelegate*
mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn)
{
+ MonoError error;
guint32 gchandle;
MonoDelegate *d;
if (use_aot_wrappers) {
wrapper = mono_marshal_get_native_func_wrapper_aot (klass);
- this_obj = mono_value_box (mono_domain_get (), mono_defaults.int_class, &ftn);
+ this_obj = mono_value_box_checked (mono_domain_get (), mono_defaults.int_class, &ftn, &error);
+ if (!is_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ }
} else {
memset (&piinfo, 0, sizeof (piinfo));
parse_unmanaged_function_pointer_attr (klass, &piinfo);
g_free (sig);
}
- d = (MonoDelegate*)mono_object_new (mono_domain_get (), klass);
- mono_delegate_ctor_with_method ((MonoObject*)d, this_obj, mono_compile_method (wrapper), wrapper);
+ d = (MonoDelegate*)mono_object_new_checked (mono_domain_get (), klass, &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ }
+ gpointer compiled_ptr = mono_compile_method_checked (wrapper, &error);
+ if (mono_error_set_pending_exception (&error))
+ return NULL;
+ mono_delegate_ctor_with_method ((MonoObject*)d, this_obj, compiled_ptr, wrapper, &error);
+ if (mono_error_set_pending_exception (&error))
+ return NULL;
}
- if (d->object.vtable->domain != mono_domain_get ())
- mono_raise_exception (mono_get_exception_not_supported ("Delegates cannot be marshalled from native code into a domain other than their home domain"));
+ if (d->object.vtable->domain != mono_domain_get ()) {
+ mono_set_pending_exception (mono_get_exception_not_supported ("Delegates cannot be marshalled from native code into a domain other than their home domain"));
+ return NULL;
+ }
return d;
}
}
}
+/* This is a JIT icall, it sets the pending exception and returns NULL on error */
static MonoString *
mono_string_from_byvalstr (const char *data, int max_len)
{
+ MonoError error;
MonoDomain *domain = mono_domain_get ();
int len = 0;
while (len < max_len - 1 && data [len])
len++;
- return mono_string_new_len (domain, data, len);
+ MonoString *result = mono_string_new_len_checked (domain, data, len, &error);
+ mono_error_set_pending_exception (&error);
+ return result;
}
+/* This is a JIT icall, it sets the pending exception and return NULL on error */
static MonoString *
mono_string_from_byvalwstr (gunichar2 *data, int max_len)
{
+ MonoError error;
+ MonoString *res = NULL;
MonoDomain *domain = mono_domain_get ();
int len = 0;
while (data [len]) len++;
- return mono_string_new_utf16 (domain, data, MIN (len, max_len));
+ res = mono_string_new_utf16_checked (domain, data, MIN (len, max_len), &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ }
+ return res;
}
gpointer
if (klass->element_class->byval_arg.type == MONO_TYPE_CLASS) {
for(i = 0; i < array->max_length; ++i)
mono_marshal_free_ccw (mono_array_get (array, MonoObject*, i));
- free(nativeArray);
+ g_free (nativeArray);
}
#endif
}
mono_byvalarray_to_array (arr, native_arr, mono_defaults.byte_class, elnum);
}
+/* This is a JIT icall, it sets the pending exception and returns on error */
static void
mono_array_to_byvalarray (gpointer native_arr, MonoArray *arr, MonoClass *elclass, guint32 elnum)
{
as = g_utf16_to_utf8 (mono_array_addr (arr, gunichar2, 0), mono_array_length (arr), NULL, NULL, &error);
if (error) {
- MonoException *exc = mono_get_exception_argument ("string", error->message);
+ mono_set_pending_exception (mono_get_exception_argument ("string", error->message));
g_error_free (error);
- mono_raise_exception (exc);
+ return;
}
memcpy (native_arr, as, MIN (strlen (as), elnum));
static MonoClass *string_builder_class;
static MonoMethod *sb_ctor;
static void *args [1];
+
+ MonoError error;
int initial_len = starting_string_length;
if (initial_len < 0)
MonoMethodDesc *desc;
MonoMethod *m;
- string_builder_class = mono_class_from_name (mono_defaults.corlib, "System.Text", "StringBuilder");
+ string_builder_class = mono_class_get_string_builder_class ();
g_assert (string_builder_class);
desc = mono_method_desc_new (":.ctor(int)", FALSE);
m = mono_method_desc_search_in_class (desc, string_builder_class);
// array will always be garbage collected.
args [0] = &initial_len;
- MonoStringBuilder *sb = (MonoStringBuilder*)mono_object_new (mono_domain_get (), string_builder_class);
- MonoObject *exc;
- g_assert (sb);
+ MonoStringBuilder *sb = (MonoStringBuilder*)mono_object_new_checked (mono_domain_get (), string_builder_class, &error);
+ mono_error_assert_ok (&error);
- mono_runtime_invoke (sb_ctor, sb, args, &exc);
- g_assert (!exc);
+ MonoObject *exc;
+ mono_runtime_try_invoke (sb_ctor, sb, args, &exc, &error);
+ g_assert (exc == NULL);
+ mono_error_assert_ok (&error);
g_assert (sb->chunkChars->max_length >= initial_len);
if (!sb || !text)
return;
- int len = strlen (text);
- if (len > mono_string_builder_capacity (sb))
- len = mono_string_builder_capacity (sb);
-
GError *error = NULL;
glong copied;
- gunichar2* ut = g_utf8_to_utf16 (text, len, NULL, &copied, &error);
+ gunichar2* ut = g_utf8_to_utf16 (text, strlen (text), NULL, &copied, &error);
+ int capacity = mono_string_builder_capacity (sb);
+
+ if (copied > capacity)
+ copied = capacity;
if (!error) {
MONO_OBJECT_SETREF (sb, chunkPrevious, NULL);
return sb;
}
-
void
mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text)
{
*
* Returns: a utf8 string with the contents of the StringBuilder.
*
- * The return value must be released with g_free.
+ * The return value must be released with mono_marshal_free.
+ *
+ * This is a JIT icall, it sets the pending exception and returns NULL on error.
*/
gchar*
mono_string_builder_to_utf8 (MonoStringBuilder *sb)
{
- GError *error = NULL;
-
+ MonoError error;
+ GError *gerror = NULL;
+ glong byte_count;
if (!sb)
return NULL;
-
gunichar2 *str_utf16 = mono_string_builder_to_utf16 (sb);
guint str_len = mono_string_builder_string_length (sb);
- gchar *tmp = g_utf16_to_utf8 (str_utf16, str_len, NULL, NULL, &error);
+ gchar *tmp = g_utf16_to_utf8 (str_utf16, str_len, NULL, &byte_count, &gerror);
- if (error) {
- g_error_free (error);
- g_free (str_utf16);
- mono_raise_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8"));
+ if (gerror) {
+ g_error_free (gerror);
+ mono_marshal_free (str_utf16);
+ mono_set_pending_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8"));
return NULL;
} else {
guint len = mono_string_builder_capacity (sb) + 1;
- gchar *res = (gchar *)mono_marshal_alloc (len * sizeof (gchar));
- g_assert (str_len < len);
- memcpy (res, tmp, str_len * sizeof (gchar));
- res[str_len] = '\0';
+ gchar *res = (gchar *)mono_marshal_alloc (MAX (byte_count+1, len * sizeof (gchar)), &error);
+ if (!mono_error_ok (&error)) {
+ mono_marshal_free (str_utf16);
+ g_free (tmp);
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ }
+ memcpy (res, tmp, byte_count);
+ res[byte_count] = '\0';
- g_free (str_utf16);
+ mono_marshal_free (str_utf16);
g_free (tmp);
return res;
}
*
* Returns: a utf16 string with the contents of the StringBuilder.
*
- * The return value must not be freed.
+ * The return value must be released with mono_marshal_free.
+ *
+ * This is a JIT icall, it sets the pending exception and returns NULL on error.
*/
gunichar2*
mono_string_builder_to_utf16 (MonoStringBuilder *sb)
{
+ MonoError error;
+
if (!sb)
return NULL;
if (len == 0)
len = 1;
- gunichar2 *str = (gunichar2 *)mono_marshal_alloc ((len + 1) * sizeof (gunichar2));
+ gunichar2 *str = (gunichar2 *)mono_marshal_alloc ((len + 1) * sizeof (gunichar2), &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ }
+
str[len] = '\0';
if (len == 0)
return str;
}
+/* This is a JIT icall, it sets the pending exception and returns NULL on error. */
static gpointer
-mono_string_to_lpstr (MonoString *s)
+mono_string_to_utf8str (MonoString *s)
{
-#ifdef TARGET_WIN32
- char *as, *tmp;
- glong len;
- GError *error = NULL;
-
- if (s == NULL)
- return NULL;
-
- if (!s->length) {
- as = CoTaskMemAlloc (1);
- as [0] = '\0';
- return as;
- }
-
- tmp = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &len, &error);
- if (error) {
- MonoException *exc = mono_get_exception_argument ("string", error->message);
- g_error_free (error);
- mono_raise_exception(exc);
- return NULL;
- } else {
- as = CoTaskMemAlloc (len + 1);
- memcpy (as, tmp, len + 1);
- g_free (tmp);
- return as;
- }
-#else
- return mono_string_to_utf8 (s);
-#endif
-}
+ MonoError error;
+ char *result = mono_string_to_utf8_checked (s, &error);
+ mono_error_set_pending_exception (&error);
+ return result;
+}
gpointer
mono_string_to_ansibstr (MonoString *string_obj)
void
mono_string_to_byvalstr (gpointer dst, MonoString *src, int size)
{
+ MonoError error;
char *s;
int len;
if (!src)
return;
- s = mono_string_to_utf8 (src);
+ s = mono_string_to_utf8_checked (src, &error);
+ if (mono_error_set_pending_exception (&error))
+ return;
len = MIN (size, strlen (s));
if (len >= size)
len--;
*((gunichar2 *) dst + len) = 0;
}
+/* this is an icall, it sets the pending exception and returns NULL on error */
static MonoString*
mono_string_new_len_wrapper (const char *text, guint length)
{
- return mono_string_new_len (mono_domain_get (), text, length);
+ MonoError error;
+ MonoString *result = mono_string_new_len_checked (mono_domain_get (), text, length, &error);
+ mono_error_set_pending_exception (&error);
+ return result;
}
#ifndef DISABLE_JIT
mono_type_to_stind (MonoType *type)
{
if (type->byref)
- return CEE_STIND_I;
+ return MONO_TYPE_IS_REFERENCE (type) ? CEE_STIND_REF : CEE_STIND_I;
+
handle_enum:
switch (type->type) {
mono_mb_emit_ldloc (mb, 1);
mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
mono_mb_emit_op (mb, CEE_NEWARR, eklass);
- mono_mb_emit_byte (mb, CEE_STIND_I);
+ mono_mb_emit_byte (mb, CEE_STIND_REF);
if (eklass->blittable) {
/* copy the elements */
} else {
mono_mb_emit_ldloc (mb, 1);
mono_mb_emit_ldloc (mb, 0);
- mono_mb_emit_icall (mb, mono_string_from_utf16);
+ mono_mb_emit_icall (mb, ves_icall_mono_string_from_utf16);
}
mono_mb_emit_byte (mb, CEE_STIND_REF);
break;
mono_mb_emit_ldloc (mb, 0);
mono_mb_emit_byte (mb, CEE_LDIND_I);
#ifdef TARGET_WIN32
- mono_mb_emit_icall (mb, mono_string_from_utf16);
+ mono_mb_emit_icall (mb, ves_icall_mono_string_from_utf16);
#else
mono_mb_emit_icall (mb, mono_string_new_wrapper);
#endif
mono_mb_emit_byte (mb, CEE_STIND_REF);
break;
+
+ // In Mono historically LPSTR was treated as a UTF8STR
case MONO_MARSHAL_CONV_STR_LPSTR:
+ case MONO_MARSHAL_CONV_STR_UTF8STR:
mono_mb_emit_ldloc (mb, 1);
mono_mb_emit_ldloc (mb, 0);
mono_mb_emit_byte (mb, CEE_LDIND_I);
mono_mb_emit_ldloc (mb, 1);
mono_mb_emit_ldloc (mb, 0);
mono_mb_emit_byte (mb, CEE_LDIND_I);
- mono_mb_emit_icall (mb, mono_string_from_utf16);
+ mono_mb_emit_icall (mb, ves_icall_mono_string_from_utf16);
mono_mb_emit_byte (mb, CEE_STIND_REF);
break;
case MONO_MARSHAL_CONV_OBJECT_STRUCT: {
}
static gpointer
-conv_to_icall (MonoMarshalConv conv)
+conv_to_icall (MonoMarshalConv conv, int *ind_store_type)
{
+ int dummy;
+ if (!ind_store_type)
+ ind_store_type = &dummy;
+ *ind_store_type = CEE_STIND_I;
switch (conv) {
case MONO_MARSHAL_CONV_STR_LPWSTR:
return mono_marshal_string_to_utf16;
case MONO_MARSHAL_CONV_LPWSTR_STR:
- return mono_string_from_utf16;
+ *ind_store_type = CEE_STIND_REF;
+ return ves_icall_mono_string_from_utf16;
case MONO_MARSHAL_CONV_LPTSTR_STR:
+ *ind_store_type = CEE_STIND_REF;
return mono_string_new_wrapper;
+ case MONO_MARSHAL_CONV_UTF8STR_STR:
case MONO_MARSHAL_CONV_LPSTR_STR:
+ *ind_store_type = CEE_STIND_REF;
return mono_string_new_wrapper;
case MONO_MARSHAL_CONV_STR_LPTSTR:
#ifdef TARGET_WIN32
return mono_marshal_string_to_utf16;
#else
- return mono_string_to_lpstr;
+ return mono_string_to_utf8str;
#endif
+ // In Mono historically LPSTR was treated as a UTF8STR
+ case MONO_MARSHAL_CONV_STR_UTF8STR:
case MONO_MARSHAL_CONV_STR_LPSTR:
- return mono_string_to_lpstr;
+ return mono_string_to_utf8str;
case MONO_MARSHAL_CONV_STR_BSTR:
return mono_string_to_bstr;
case MONO_MARSHAL_CONV_BSTR_STR:
- return mono_string_from_bstr;
+ *ind_store_type = CEE_STIND_REF;
+ return mono_string_from_bstr_icall;
case MONO_MARSHAL_CONV_STR_TBSTR:
case MONO_MARSHAL_CONV_STR_ANSIBSTR:
return mono_string_to_ansibstr;
+ case MONO_MARSHAL_CONV_SB_UTF8STR:
case MONO_MARSHAL_CONV_SB_LPSTR:
return mono_string_builder_to_utf8;
case MONO_MARSHAL_CONV_SB_LPTSTR:
case MONO_MARSHAL_CONV_DEL_FTN:
return mono_delegate_to_ftnptr;
case MONO_MARSHAL_CONV_FTN_DEL:
+ *ind_store_type = CEE_STIND_REF;
return mono_ftnptr_to_delegate;
+ case MONO_MARSHAL_CONV_UTF8STR_SB:
case MONO_MARSHAL_CONV_LPSTR_SB:
+ *ind_store_type = CEE_STIND_REF;
return mono_string_utf8_to_builder;
case MONO_MARSHAL_CONV_LPTSTR_SB:
+ *ind_store_type = CEE_STIND_REF;
#ifdef TARGET_WIN32
return mono_string_utf16_to_builder;
#else
return mono_string_utf8_to_builder;
#endif
case MONO_MARSHAL_CONV_LPWSTR_SB:
+ *ind_store_type = CEE_STIND_REF;
return mono_string_utf16_to_builder;
case MONO_MARSHAL_FREE_ARRAY:
return mono_marshal_free_array;
emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
{
int pos;
+ int stind_op;
switch (conv) {
case MONO_MARSHAL_CONV_BOOL_I4:
mono_mb_emit_byte (mb, CEE_NEG);
mono_mb_emit_byte (mb, CEE_STIND_I2);
break;
+ // In Mono historically LPSTR was treated as a UTF8STR
+ case MONO_MARSHAL_CONV_STR_UTF8STR:
case MONO_MARSHAL_CONV_STR_LPWSTR:
case MONO_MARSHAL_CONV_STR_LPSTR:
case MONO_MARSHAL_CONV_STR_LPTSTR:
mono_mb_emit_ldloc (mb, 1);
mono_mb_emit_ldloc (mb, 0);
mono_mb_emit_byte (mb, CEE_LDIND_REF);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
- mono_mb_emit_byte (mb, CEE_STIND_I);
+ mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+ mono_mb_emit_byte (mb, stind_op);
break;
}
case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
mono_mb_emit_ldloc (mb, 1);
mono_mb_emit_ldloc (mb, 0);
mono_mb_emit_byte (mb, CEE_LDIND_REF);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
- mono_mb_emit_byte (mb, CEE_STIND_I);
+ mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+ mono_mb_emit_byte (mb, stind_op);
break;
case MONO_MARSHAL_CONV_STR_BYVALSTR:
case MONO_MARSHAL_CONV_STR_BYVALWSTR: {
mono_mb_emit_ldloc (mb, 0);
mono_mb_emit_byte (mb, CEE_LDIND_REF); /* src String */
mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
+ mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
break;
}
case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
}
default: {
- char *msg = g_strdup_printf ("marshalling conversion %d not implemented", conv);
- MonoException *exc = mono_get_exception_not_implemented (msg);
- g_warning ("%s", msg);
- g_free (msg);
- mono_raise_exception (exc);
+ g_error ("marshalling conversion %d not implemented", conv);
+ }
}
+}
+
+static int offset_of_first_nonstatic_field(MonoClass *klass)
+{
+ int i;
+ for (i = 0; i < klass->field.count; i++) {
+ if (!(klass->fields[i].type->attrs & FIELD_ATTRIBUTE_STATIC) && !mono_field_is_deleted (&klass->fields[i]))
+ return klass->fields[i].offset - sizeof (MonoObject);
}
+
+ return 0;
}
static void
emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object,
- MonoMarshalNative string_encoding)
+ int offset_of_first_child_field, MonoMarshalNative string_encoding)
{
MonoMarshalType *info;
int i;
if (klass->parent)
- emit_struct_conv(mb, klass->parent, to_object);
+ emit_struct_conv_full (mb, klass->parent, to_object, offset_of_first_nonstatic_field (klass), string_encoding);
info = mono_marshal_load_type_info (klass);
return;
if (klass->blittable) {
- int msize = mono_class_value_size (klass, NULL);
- g_assert (msize == info->native_size);
+ int usize = mono_class_value_size (klass, NULL);
+ g_assert (usize == info->native_size);
mono_mb_emit_ldloc (mb, 1);
mono_mb_emit_ldloc (mb, 0);
- mono_mb_emit_icon (mb, msize);
+ mono_mb_emit_icon (mb, usize);
mono_mb_emit_byte (mb, CEE_PREFIX1);
mono_mb_emit_byte (mb, CEE_CPBLK);
- mono_mb_emit_add_to_local (mb, 0, msize);
- mono_mb_emit_add_to_local (mb, 1, msize);
+ if (to_object) {
+ mono_mb_emit_add_to_local (mb, 0, usize);
+ mono_mb_emit_add_to_local (mb, 1, offset_of_first_child_field);
+ } else {
+ mono_mb_emit_add_to_local (mb, 0, offset_of_first_child_field);
+ mono_mb_emit_add_to_local (mb, 1, usize);
+ }
return;
}
- if (klass != mono_defaults.safehandle_class) {
- if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
+ if (klass != mono_class_try_get_safehandle_class ()) {
+ if (mono_class_is_auto_layout (klass)) {
char *msg = g_strdup_printf ("Type %s which is passed to unmanaged code must have a StructLayout attribute.",
mono_type_full_name (&klass->byval_arg));
mono_mb_emit_exception_marshal_directive (mb, msg);
usize = info->fields [i + 1].offset - info->fields [i].offset;
}
- if (klass != mono_defaults.safehandle_class){
+ if (klass != mono_class_try_get_safehandle_class ()){
/*
* FIXME: Should really check for usize==0 and msize>0, but we apply
* the layout to the managed structure as well.
*/
- if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) && (usize == 0)) {
+ if (mono_class_is_explicit_layout (klass) && (usize == 0)) {
if (MONO_TYPE_IS_REFERENCE (info->fields [i].field->type) ||
((!last_field && MONO_TYPE_IS_REFERENCE (info->fields [i + 1].field->type))))
g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a "
case MONO_MARSHAL_CONV_NONE: {
int t;
- if (ftype->byref || ftype->type == MONO_TYPE_I ||
- ftype->type == MONO_TYPE_U) {
+ //XXX a byref field!?!? that's not allowed! and worse, it might miss a WB
+ g_assert (!ftype->byref);
+ if (ftype->type == MONO_TYPE_I || ftype->type == MONO_TYPE_U) {
mono_mb_emit_ldloc (mb, 1);
mono_mb_emit_ldloc (mb, 0);
mono_mb_emit_byte (mb, CEE_LDIND_I);
static void
emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
{
- emit_struct_conv_full (mb, klass, to_object, (MonoMarshalNative)-1);
+ emit_struct_conv_full (mb, klass, to_object, 0, (MonoMarshalNative)-1);
}
static void
#endif /* DISABLE_JIT */
+/* This is a JIT icall, it sets the pending exception and returns NULL on error. */
static MonoAsyncResult *
mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params)
{
+ MonoError error;
MonoMulticastDelegate *mcast_delegate;
MonoClass *klass;
MonoMethod *method;
g_assert (delegate);
mcast_delegate = (MonoMulticastDelegate *) delegate;
- if (mcast_delegate->delegates != NULL)
- mono_raise_exception (mono_get_exception_argument (NULL, "The delegate must have only one target"));
+ if (mcast_delegate->delegates != NULL) {
+ mono_set_pending_exception (mono_get_exception_argument (NULL, "The delegate must have only one target"));
+ return NULL;
+ }
#ifndef DISABLE_REMOTING
if (delegate->target && mono_object_class (delegate->target) == mono_defaults.transparent_proxy_class) {
-
MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target;
if (!mono_class_is_contextbound (tp->remote_class->proxy_class) || tp->rp->context != (MonoObject *) mono_context_get ()) {
-
/* If the target is a proxy, make a direct call. Is proxy's work
// to make the call asynchronous.
*/
MonoArray *out_args;
method = delegate->method;
- msg = mono_method_call_message_new (mono_marshal_method_from_wrapper (method), params, NULL, &async_callback, &state);
- ares = mono_async_result_new (mono_domain_get (), NULL, state, NULL, NULL);
+ msg = mono_method_call_message_new (mono_marshal_method_from_wrapper (method), params, NULL, &async_callback, &state, &error);
+ if (mono_error_set_pending_exception (&error))
+ return NULL;
+ ares = mono_async_result_new (mono_domain_get (), NULL, state, NULL, NULL, &error);
+ if (mono_error_set_pending_exception (&error))
+ return NULL;
MONO_OBJECT_SETREF (ares, async_delegate, (MonoObject *)delegate);
MONO_OBJECT_SETREF (ares, async_callback, (MonoObject *)async_callback);
MONO_OBJECT_SETREF (msg, async_result, ares);
msg->call_type = CallType_BeginInvoke;
exc = NULL;
- mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args);
+ mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args, &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ }
if (exc)
- mono_raise_exception ((MonoException *) exc);
+ mono_set_pending_exception ((MonoException *) exc);
return ares;
}
}
method = mono_get_delegate_invoke (klass);
g_assert (method);
- return mono_threadpool_ms_begin_invoke (mono_domain_get (), (MonoObject*) delegate, method, params);
+ MonoAsyncResult *result = mono_threadpool_ms_begin_invoke (mono_domain_get (), (MonoObject*) delegate, method, params, &error);
+ mono_error_set_pending_exception (&error);
+ return result;
}
#ifndef DISABLE_JIT
return MONO_MARSHAL_CONV_STR_LPTSTR;
case MONO_NATIVE_BSTR:
return MONO_MARSHAL_CONV_STR_BSTR;
+ case MONO_NATIVE_UTF8STR:
+ return MONO_MARSHAL_CONV_STR_UTF8STR;
default:
- return (MonoMarshalConv)-1;
+ return MONO_MARSHAL_CONV_INVALID;
}
}
switch (encoding) {
case MONO_NATIVE_LPWSTR:
return MONO_MARSHAL_CONV_SB_LPWSTR;
- break;
case MONO_NATIVE_LPSTR:
return MONO_MARSHAL_CONV_SB_LPSTR;
- break;
+ case MONO_NATIVE_UTF8STR:
+ return MONO_MARSHAL_CONV_SB_UTF8STR;
case MONO_NATIVE_LPTSTR:
return MONO_MARSHAL_CONV_SB_LPTSTR;
- break;
default:
- return (MonoMarshalConv)-1;
+ return MONO_MARSHAL_CONV_INVALID;
}
}
case MONO_NATIVE_LPWSTR:
*need_free = FALSE;
return MONO_MARSHAL_CONV_LPWSTR_STR;
+ case MONO_NATIVE_UTF8STR:
+ return MONO_MARSHAL_CONV_UTF8STR_STR;
case MONO_NATIVE_LPSTR:
case MONO_NATIVE_VBBYREFSTR:
return MONO_MARSHAL_CONV_LPSTR_STR;
case MONO_NATIVE_BSTR:
return MONO_MARSHAL_CONV_BSTR_STR;
default:
- return (MonoMarshalConv)-1;
+ return MONO_MARSHAL_CONV_INVALID;
}
}
*/
*need_free = FALSE;
return MONO_MARSHAL_CONV_LPWSTR_SB;
+ case MONO_NATIVE_UTF8STR:
+ return MONO_MARSHAL_CONV_UTF8STR_SB;
case MONO_NATIVE_LPSTR:
return MONO_MARSHAL_CONV_LPSTR_SB;
break;
return MONO_MARSHAL_CONV_LPTSTR_SB;
break;
default:
- return (MonoMarshalConv)-1;
+ return MONO_MARSHAL_CONV_INVALID;
}
}
return info->d.runtime_invoke.method;
else
return NULL;
+ case MONO_WRAPPER_DELEGATE_INVOKE:
+ if (info)
+ return info->d.delegate_invoke.method;
+ else
+ return NULL;
default:
return NULL;
}
{
MonoError error;
MonoMethod *inst, *res;
+ WrapperInfo *ginfo, *info;
/*
* We use the same cache for the generic definition and the instances.
inst = mono_class_inflate_generic_method_checked (def, ctx, &error);
g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+ ginfo = mono_marshal_get_wrapper_info (def);
+ if (ginfo) {
+ info = (WrapperInfo *)mono_image_alloc0 (def->klass->image, sizeof (WrapperInfo));
+ info->subtype = ginfo->subtype;
+ if (info->subtype == WRAPPER_SUBTYPE_NONE) {
+ info->d.delegate_invoke.method = mono_class_inflate_generic_method_checked (ginfo->d.delegate_invoke.method, ctx, &error);
+ mono_error_assert_ok (&error);
+ }
+ }
+
mono_memory_barrier ();
mono_marshal_lock ();
res = (MonoMethod *)g_hash_table_lookup (cache, orig_method->klass);
return res;
}
+/* This is a JIT icall, it sets the pending exception and returns NULL on error. */
static MonoObject *
mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
{
+ MonoError error;
MonoDomain *domain = mono_domain_get ();
MonoAsyncResult *ares;
MonoMethod *method = NULL;
if (!delegate->method_info) {
g_assert (delegate->method);
- MONO_OBJECT_SETREF (delegate, method_info, mono_method_get_object (domain, delegate->method, NULL));
+ MonoReflectionMethod *rm = mono_method_get_object_checked (domain, delegate->method, NULL, &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ }
+ MONO_OBJECT_SETREF (delegate, method_info, rm);
}
if (!delegate->method_info || !delegate->method_info->method)
sig = mono_signature_no_pinvoke (method);
- msg = mono_method_call_message_new (method, params, NULL, NULL, NULL);
+ msg = mono_method_call_message_new (method, params, NULL, NULL, NULL, &error);
+ if (mono_error_set_pending_exception (&error))
+ return NULL;
ares = (MonoAsyncResult *)mono_array_get (msg->args, gpointer, sig->param_count - 1);
if (ares == NULL) {
- mono_raise_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingException", "The async result object is null or of an unexpected type."));
+ mono_set_pending_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingException", "The async result object is null or of an unexpected type."));
return NULL;
}
if (ares->async_delegate != (MonoObject*)delegate) {
- mono_raise_exception (mono_get_exception_invalid_operation (
+ mono_set_pending_exception (mono_get_exception_invalid_operation (
"The IAsyncResult object provided does not match this delegate."));
return NULL;
}
#ifndef DISABLE_REMOTING
if (delegate->target && mono_object_is_transparent_proxy (delegate->target)) {
MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target;
- msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
- mono_message_init (domain, msg, delegate->method_info, NULL);
+ msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ }
+ mono_message_init (domain, msg, delegate->method_info, NULL, &error);
+ if (mono_error_set_pending_exception (&error))
+ return NULL;
msg->call_type = CallType_EndInvoke;
MONO_OBJECT_SETREF (msg, async_result, ares);
- res = mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args);
+ res = mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args, &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ }
} else
#endif
{
- res = mono_threadpool_ms_end_invoke (ares, &out_args, &exc);
+ res = mono_threadpool_ms_end_invoke (ares, &out_args, &exc, &error);
+ if (mono_error_set_pending_exception (&error))
+ return NULL;
}
if (exc) {
if (((MonoException*)exc)->stack_trace) {
- char *strace = mono_string_to_utf8 (((MonoException*)exc)->stack_trace);
- char *tmp;
- tmp = g_strdup_printf ("%s\nException Rethrown at:\n", strace);
- g_free (strace);
- MONO_OBJECT_SETREF (((MonoException*)exc), stack_trace, mono_string_new (domain, tmp));
- g_free (tmp);
+ MonoError inner_error;
+ char *strace = mono_string_to_utf8_checked (((MonoException*)exc)->stack_trace, &inner_error);
+ if (is_ok (&inner_error)) {
+ char *tmp;
+ tmp = g_strdup_printf ("%s\nException Rethrown at:\n", strace);
+ g_free (strace);
+ MONO_OBJECT_SETREF (((MonoException*)exc), stack_trace, mono_string_new (domain, tmp));
+ g_free (tmp);
+ } else
+ mono_error_cleanup (&inner_error); /* no stack trace, but at least throw the original exception */
}
- mono_raise_exception ((MonoException*)exc);
+ mono_set_pending_exception ((MonoException*)exc);
}
- mono_method_return_message_restore (method, params, out_args);
+ mono_method_return_message_restore (method, params, out_args, &error);
+ mono_error_set_pending_exception (&error);
return res;
}
g_free (pair);
}
-static MonoMethodSignature*
-sig_to_rgctx_sig (MonoMethodSignature *sig)
-{
- // FIXME: memory allocation
- MonoMethodSignature *res;
- int i;
-
- res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
- memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
- res->param_count = sig->param_count + 1;
- for (i = 0; i < sig->param_count; ++i)
- res->params [i] = sig->params [i];
- res->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
- return res;
-}
-
MonoMethod *
mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt, gboolean static_method_with_first_arg_bound, MonoMethod *target_method)
{
MonoMethod *res;
GHashTable *cache;
gpointer cache_key = NULL;
- SignaturePointerPair key;
+ SignaturePointerPair key = { NULL, NULL };
SignaturePointerPair *new_key;
int local_i, local_len, local_delegates, local_d, local_target, local_res;
- int pos0, pos1, pos2, pos3, pos4;
+ int pos0, pos1, pos2;
char *name;
MonoClass *target_class = NULL;
gboolean closed_over_null = FALSE;
MonoGenericContext *ctx = NULL;
MonoGenericContainer *container = NULL;
- MonoMethod *orig_method = NULL;
+ MonoMethod *orig_method = method;
WrapperInfo *info;
WrapperSubtype subtype = WRAPPER_SUBTYPE_NONE;
gboolean found;
if (callvirt) {
subtype = WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL;
if (target_method->is_inflated) {
+ MonoError error;
MonoType *target_type;
g_assert (method->signature->hasthis);
- target_type = mono_class_inflate_generic_type (method->signature->params [0],
- mono_method_get_context (method));
+ target_type = mono_class_inflate_generic_type_checked (method->signature->params [0],
+ mono_method_get_context (method), &error);
+ mono_error_assert_ok (&error); /* FIXME don't swallow the error */
target_class = mono_class_from_mono_type (target_type);
} else {
target_class = target_method->klass;
* For generic delegates, create a generic wrapper, and return an instance to help AOT.
*/
if (method->is_inflated && subtype == WRAPPER_SUBTYPE_NONE) {
- orig_method = method;
ctx = &((MonoMethodInflated*)method)->context;
method = ((MonoMethodInflated*)method)->declaring;
container = mono_method_get_generic_container (method);
if (!container)
- container = method->klass->generic_container;
+ container = mono_class_try_get_generic_container (method->klass); //FIXME is this a case of a try?
g_assert (container);
invoke_sig = sig = mono_signature_no_pinvoke (method);
mono_mb_emit_byte (mb, CEE_LDIND_REF);
mono_mb_emit_stloc (mb, local_delegates);
-
/* if (delegates == null) */
mono_mb_emit_ldloc (mb, local_delegates);
pos2 = mono_mb_emit_branch (mb, CEE_BRTRUE);
// FIXME:
mono_mb_emit_exception_full (mb, "System", "NotImplementedException", "");
} else {
- MonoMethodSignature *rgctx_sig;
-
- // FIXME: Support this for the other cases as well
- mono_mb_emit_ldarg (mb, 0);
- mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, rgctx));
- mono_mb_emit_byte (mb, CEE_LDIND_I);
- pos3 = mono_mb_emit_branch (mb, CEE_BRFALSE);
-
- /* Rgctx case */
- rgctx_sig = sig_to_rgctx_sig (sig);
-
mono_mb_emit_ldloc (mb, local_target);
for (i = 0; i < sig->param_count; ++i)
mono_mb_emit_ldarg (mb, i + 1);
mono_mb_emit_ldarg (mb, 0);
- mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, rgctx));
+ mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, extra_arg));
mono_mb_emit_byte (mb, CEE_LDIND_I);
mono_mb_emit_ldarg (mb, 0);
mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
mono_mb_emit_byte (mb, CEE_LDIND_I);
- mono_mb_emit_op (mb, CEE_CALLI, rgctx_sig);
- pos4 = mono_mb_emit_branch (mb, CEE_BR);
-
- /* Non-rgctx case */
- mono_mb_patch_branch (mb, pos3);
- mono_mb_emit_ldloc (mb, local_target);
- for (i = 0; i < sig->param_count; ++i)
- mono_mb_emit_ldarg (mb, i + 1);
- mono_mb_emit_ldarg (mb, 0);
- mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
- mono_mb_emit_byte (mb, CEE_LDIND_I );
- mono_mb_emit_op (mb, CEE_CALLI, sig);
-
- mono_mb_patch_branch (mb, pos4);
-
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_op (mb, CEE_MONO_CALLI_EXTRA_ARG, sig);
mono_mb_emit_byte (mb, CEE_RET);
}
mono_mb_emit_op (mb, CEE_CALL, target_method);
}
} else {
- MonoMethodSignature *rgctx_sig;
-
- mono_mb_emit_ldarg (mb, 0);
- mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, rgctx));
- mono_mb_emit_byte (mb, CEE_LDIND_I);
- pos3 = mono_mb_emit_branch (mb, CEE_BRFALSE);
-
- /* Rgctx case */
- rgctx_sig = sig_to_rgctx_sig (invoke_sig);
-
if (static_method_with_first_arg_bound) {
mono_mb_emit_ldloc (mb, local_target);
if (!MONO_TYPE_IS_REFERENCE (invoke_sig->params[0]))
for (i = 0; i < sig->param_count; ++i)
mono_mb_emit_ldarg (mb, i + 1);
mono_mb_emit_ldarg (mb, 0);
- mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, rgctx));
- mono_mb_emit_byte (mb, CEE_LDIND_I);
- mono_mb_emit_ldarg (mb, 0);
- mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
+ mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, extra_arg));
mono_mb_emit_byte (mb, CEE_LDIND_I);
- mono_mb_emit_op (mb, CEE_CALLI, rgctx_sig);
- pos4 = mono_mb_emit_branch (mb, CEE_BR);
-
- /* Non-rgctx case */
- mono_mb_patch_branch (mb, pos3);
- if (static_method_with_first_arg_bound) {
- mono_mb_emit_ldloc (mb, local_target);
- if (!MONO_TYPE_IS_REFERENCE (invoke_sig->params[0]))
- mono_mb_emit_op (mb, CEE_UNBOX_ANY, mono_class_from_mono_type (invoke_sig->params[0]));
- }
- for (i = 0; i < sig->param_count; ++i)
- mono_mb_emit_ldarg (mb, i + 1);
mono_mb_emit_ldarg (mb, 0);
mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
mono_mb_emit_byte (mb, CEE_LDIND_I);
- mono_mb_emit_op (mb, CEE_CALLI, invoke_sig);
-
- mono_mb_patch_branch (mb, pos4);
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_op (mb, CEE_MONO_CALLI_EXTRA_ARG, invoke_sig);
}
mono_mb_emit_byte (mb, CEE_RET);
mb->skip_visibility = 1;
#endif /* DISABLE_JIT */
+ info = mono_wrapper_info_create (mb, subtype);
+ info->d.delegate_invoke.method = method;
+
if (ctx) {
MonoMethod *def;
- def = mono_mb_create_and_cache (cache, cache_key, mb, sig, sig->param_count + 16);
+ def = mono_mb_create_and_cache_full (cache, cache_key, mb, sig, sig->param_count + 16, info, NULL);
res = cache_generic_delegate_wrapper (cache, orig_method, def, ctx);
} else if (callvirt) {
new_key = g_new0 (SignaturePointerPair, 1);
*new_key = key;
- info = mono_wrapper_info_create (mb, subtype);
-
res = mono_mb_create_and_cache_full (cache, new_key, mb, sig, sig->param_count + 16, info, &found);
if (found)
g_free (new_key);
} else {
- info = mono_wrapper_info_create (mb, subtype);
-
res = mono_mb_create_and_cache_full (cache, cache_key, mb, sig, sig->param_count + 16, info, NULL);
}
mono_mb_free (mb);
case MONO_TYPE_CHAR:
return &mono_defaults.uint16_class->byval_arg;
case MONO_TYPE_U:
- case MONO_TYPE_PTR:
return &mono_defaults.int_class->byval_arg;
case MONO_TYPE_VALUETYPE:
if (t->data.klass->enumtype) {
* it means that the compiled code for METHOD does not have to be looked up
* before calling the runtime invoke wrapper. In this case, the wrapper ignores
* its METHOD argument.
- * If PASS_RGCTX is TRUE, the signature of the called method is changed to include a 'gpointer rgctx' as the
- * last argument (after 'this').
*/
MonoMethod *
-mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual_, gboolean pass_rgctx)
+mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual_)
{
MonoMethodSignature *sig, *csig, *callsig;
MonoMethodBuilder *mb;
sig = mono_method_signature (method);
- if (pass_rgctx) {
- sig = sig_to_rgctx_sig (sig);
- callsig = sig_to_rgctx_sig (callsig);
- }
-
target_klass = get_wrapper_target_class (method->klass->image);
/* Try to share wrappers for non-corlib methods with simple signatures */
csig->call_convention = MONO_CALL_C;
#endif
- name = mono_signature_to_name (callsig, pass_rgctx ? (virtual_ ? "runtime_invoke_virtual_rgctx" : "runtime_invoke_rgctx") : (virtual_ ? "runtime_invoke_virtual" : "runtime_invoke"));
+ name = mono_signature_to_name (callsig, virtual_ ? "runtime_invoke_virtual" : "runtime_invoke");
mb = mono_mb_new (target_klass, name, MONO_WRAPPER_RUNTIME_INVOKE);
g_free (name);
info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL);
info->d.runtime_invoke.sig = callsig;
- info->d.runtime_invoke.pass_rgctx = pass_rgctx;
/* Somebody may have created it before us */
if (!res) {
* ARGS should contain the this argument too.
* This wrapper serves the same purpose as the runtime-invoke wrappers, but there
* is only one copy of it, which is useful in full-aot.
- * The wrapper info for the wrapper is a WrapperInfo structure.
*/
MonoMethod*
mono_marshal_get_runtime_invoke_dynamic (void)
/*
* generates IL code for the icall wrapper (the generated method
* calls the unmanaged code in func)
- * The wrapper info for the wrapper is a WrapperInfo structure.
*/
MonoMethod *
mono_marshal_get_icall_wrapper (MonoMethodSignature *sig, const char *name, gconstpointer func, gboolean check_exceptions)
int i;
WrapperInfo *info;
+ GHashTable *cache = get_cache (&mono_defaults.object_class->image->icall_wrapper_cache, mono_aligned_addr_hash, NULL);
+ if ((res = mono_marshal_find_in_cache (cache, (gpointer) func)))
+ return res;
+
g_assert (sig->pinvoke);
mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_ICALL_WRAPPER);
info->d.icall.func = (gpointer)func;
- res = mono_mb_create (mb, csig, csig->param_count + 16, info);
+ res = mono_mb_create_and_cache_full (cache, (gpointer) func, mb, csig, csig->param_count + 16, info, NULL);
mono_mb_free (mb);
return res;
*conv_arg_type = &mono_defaults.int_class->byval_arg;
return conv_arg;
#else
+ MonoError error;
MonoType *mtype;
MonoClass *mklass;
static MonoClass *ICustomMarshaler = NULL;
int pos2;
if (!ICustomMarshaler) {
- MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ICustomMarshaler");
+ MonoClass *klass = mono_class_try_get_icustom_marshaler_class ();
if (!klass) {
exception_msg = g_strdup ("Current profile doesn't support ICustomMarshaler");
goto handle_exception;
}
if (spec->data.custom_data.image)
- mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, spec->data.custom_data.image);
+ mtype = mono_reflection_type_from_name_checked (spec->data.custom_data.custom_name, spec->data.custom_data.image, &error);
else
- mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, m->image);
+ mtype = mono_reflection_type_from_name_checked (spec->data.custom_data.custom_name, m->image, &error);
g_assert (mtype != NULL);
+ mono_error_assert_ok (&error);
mklass = mono_class_from_mono_type (mtype);
g_assert (mklass != NULL);
klass = mono_class_from_mono_type (t);
- date_time_class = mono_class_from_name_cached (mono_defaults.corlib, "System", "DateTime");
+ date_time_class = mono_class_get_date_time_class ();
switch (action) {
case MARSHAL_ACTION_CONV_IN:
break;
}
- if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
- klass->blittable || klass->enumtype)
+ if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype)
break;
conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
/* Have to change the signature since the vtype is passed byref */
m->csig->params [argnum - m->csig->hasthis] = &mono_defaults.int_class->byval_arg;
- if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
- klass->blittable || klass->enumtype)
+ if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype)
mono_mb_emit_ldarg_addr (mb, argnum);
else
mono_mb_emit_ldloc (mb, conv_arg);
break;
}
- if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
- klass->blittable || klass->enumtype) {
+ if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype) {
mono_mb_emit_ldarg (mb, argnum);
break;
}
break;
}
- if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
- klass->blittable || klass->enumtype)
+ if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype)
break;
if (t->byref) {
break;
case MARSHAL_ACTION_CONV_RESULT:
- if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
- klass->blittable) {
+ if (mono_class_is_explicit_layout (klass) || klass->blittable) {
mono_mb_emit_stloc (mb, 3);
break;
}
/* load pointer to returned value type */
- mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
- mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
+ g_assert (m->vtaddr_var);
+ mono_mb_emit_ldloc (mb, m->vtaddr_var);
/* store the address of the source into local variable 0 */
mono_mb_emit_stloc (mb, 0);
/* set dst_ptr */
break;
case MARSHAL_ACTION_MANAGED_CONV_IN:
- if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
- klass->blittable || klass->enumtype) {
+ if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype) {
conv_arg = 0;
break;
}
break;
case MARSHAL_ACTION_MANAGED_CONV_OUT:
- if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
- klass->blittable || klass->enumtype) {
+ if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype)
break;
- }
-
if (t->byref && (t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT))
break;
break;
case MARSHAL_ACTION_MANAGED_CONV_RESULT:
- if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
- klass->blittable || klass->enumtype) {
+ if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype) {
mono_mb_emit_stloc (mb, 3);
m->retobj_var = 0;
break;
}
/* load pointer to returned value type */
- mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
- mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
+ g_assert (m->vtaddr_var);
+ mono_mb_emit_ldloc (mb, m->vtaddr_var);
/* store the address of the source into local variable 0 */
mono_mb_emit_stloc (mb, 0);
g_assert (m->retobj_var);
mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
mono_mb_emit_byte (mb, CEE_CONV_I);
- mono_mb_emit_icall (mb, mono_marshal_alloc);
+ mono_mb_emit_icall (mb, ves_icall_marshal_alloc);
mono_mb_emit_stloc (mb, 1);
mono_mb_emit_ldloc (mb, 1);
mono_mb_emit_stloc (mb, m->retobj_var);
mono_mb_emit_ldarg (mb, argnum);
}
- if (conv == -1) {
+ if (conv == MONO_MARSHAL_CONV_INVALID) {
char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
mono_mb_emit_exception_marshal_directive (mb, msg);
} else {
- mono_mb_emit_icall (mb, conv_to_icall (conv));
+ mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
mono_mb_emit_stloc (mb, conv_arg);
}
case MARSHAL_ACTION_CONV_OUT:
conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
- if (conv == -1) {
+ if (conv == MONO_MARSHAL_CONV_INVALID) {
char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
mono_mb_emit_exception_marshal_directive (mb, msg);
break;
mono_mb_emit_icall (mb, mono_string_new_len_wrapper);
mono_mb_emit_byte (mb, CEE_STIND_REF);
} else if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) {
+ int stind_op;
mono_mb_emit_ldarg (mb, argnum);
mono_mb_emit_ldloc (mb, conv_arg);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
- mono_mb_emit_byte (mb, CEE_STIND_REF);
+ mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+ mono_mb_emit_byte (mb, stind_op);
need_free = TRUE;
}
mono_mb_emit_stloc (mb, 0);
conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
- if (conv == -1) {
+ if (conv == MONO_MARSHAL_CONV_INVALID) {
char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
mono_mb_emit_exception_marshal_directive (mb, msg);
break;
}
mono_mb_emit_ldloc (mb, 0);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
+ mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
mono_mb_emit_stloc (mb, 3);
/* free the string */
}
conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
- if (conv == -1) {
+ if (conv == MONO_MARSHAL_CONV_INVALID) {
char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
mono_mb_emit_exception_marshal_directive (mb, msg);
break;
mono_mb_emit_ldarg (mb, argnum);
if (t->byref)
mono_mb_emit_byte (mb, CEE_LDIND_I);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
+ mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
mono_mb_emit_stloc (mb, conv_arg);
break;
case MARSHAL_ACTION_MANAGED_CONV_OUT:
if (t->byref) {
if (conv_arg) {
+ int stind_op;
mono_mb_emit_ldarg (mb, argnum);
mono_mb_emit_ldloc (mb, conv_arg);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
- mono_mb_emit_byte (mb, CEE_STIND_I);
+ mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+ mono_mb_emit_byte (mb, stind_op);
}
}
break;
case MARSHAL_ACTION_MANAGED_CONV_RESULT:
- if (conv_to_icall (conv) == mono_marshal_string_to_utf16)
+ if (conv_to_icall (conv, NULL) == mono_marshal_string_to_utf16)
/* We need to make a copy so the caller is able to free it */
mono_mb_emit_icall (mb, mono_marshal_string_to_utf16_copy);
else
- mono_mb_emit_icall (mb, conv_to_icall (conv));
+ mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
mono_mb_emit_stloc (mb, 3);
break;
MonoMethod *ctor = NULL;
int intptr_handle_slot;
- if (t->data.klass->flags & TYPE_ATTRIBUTE_ABSTRACT){
+ if (mono_class_is_abstract (t->data.klass)) {
mono_mb_emit_byte (mb, CEE_POP);
mono_mb_emit_exception_marshal_directive (mb, g_strdup ("Returned SafeHandles should not be abstract"));
break;
mono_mb_emit_stloc (mb, conv_arg);
} else {
mono_mb_emit_ldarg (mb, argnum);
- mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
+ mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, NULL));
mono_mb_emit_stloc (mb, conv_arg);
}
} else if (klass == mono_defaults.stringbuilder_class) {
if (t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))
break;
- if (conv == -1) {
+ if (conv == MONO_MARSHAL_CONV_INVALID) {
char *msg = g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding);
mono_mb_emit_exception_marshal_directive (mb, msg);
break;
if (t->byref)
mono_mb_emit_byte (mb, CEE_LDIND_I);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
+ mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
mono_mb_emit_stloc (mb, conv_arg);
} else if (klass->blittable) {
mono_mb_emit_byte (mb, CEE_LDNULL);
case MONO_NATIVE_LPSTR:
mono_mb_emit_icall (mb, mono_string_utf8_to_builder2);
break;
+ case MONO_NATIVE_UTF8STR:
+ mono_mb_emit_icall (mb, mono_string_utf8_to_builder2);
+ break;
default:
g_assert_not_reached ();
}
mono_mb_emit_ldarg (mb, argnum);
mono_mb_emit_ldloc (mb, conv_arg);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
+ mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
}
if (need_free) {
mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
mono_mb_emit_ldloc (mb, conv_arg);
- mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
+ mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL));
mono_mb_emit_byte (mb, CEE_STIND_REF);
}
break;
mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
mono_mb_emit_ldloc (mb, 0);
- mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
+ mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL));
mono_mb_emit_stloc (mb, 3);
+ } else if (klass == mono_defaults.stringbuilder_class){
+ // FIXME: implement
} else {
/* set src */
mono_mb_emit_stloc (mb, 0);
mono_mb_emit_ldarg (mb, argnum);
if (t->byref)
mono_mb_emit_byte (mb, CEE_LDIND_I);
- mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
+ mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL));
mono_mb_emit_stloc (mb, conv_arg);
break;
}
encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
// FIXME:
- g_assert (encoding == MONO_NATIVE_LPSTR);
+ g_assert (encoding == MONO_NATIVE_LPSTR || encoding == MONO_NATIVE_UTF8STR);
g_assert (!t->byref);
g_assert (encoding != -1);
}
/* The class can not have an automatic layout */
- if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
+ if (mono_class_is_auto_layout (klass)) {
mono_mb_emit_auto_layout_exception (mb, klass);
break;
}
case MARSHAL_ACTION_MANAGED_CONV_OUT:
if (klass->delegate) {
if (t->byref) {
+ int stind_op;
mono_mb_emit_ldarg (mb, argnum);
mono_mb_emit_ldloc (mb, conv_arg);
- mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
- mono_mb_emit_byte (mb, CEE_STIND_I);
+ mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, &stind_op));
+ mono_mb_emit_byte (mb, stind_op);
break;
}
}
/* Allocate and set dest */
mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
mono_mb_emit_byte (mb, CEE_CONV_I);
- mono_mb_emit_icall (mb, mono_marshal_alloc);
+ mono_mb_emit_icall (mb, ves_icall_marshal_alloc);
mono_mb_emit_stloc (mb, 1);
/* Update argument pointer */
case MARSHAL_ACTION_MANAGED_CONV_RESULT:
if (klass->delegate) {
- mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
+ mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, NULL));
mono_mb_emit_stloc (mb, 3);
break;
}
/* The class can not have an automatic layout */
- if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
+ if (mono_class_is_auto_layout (klass)) {
mono_mb_emit_auto_layout_exception (mb, klass);
break;
}
/* Allocate and set dest */
mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
mono_mb_emit_byte (mb, CEE_CONV_I);
- mono_mb_emit_icall (mb, mono_marshal_alloc);
+ mono_mb_emit_icall (mb, ves_icall_marshal_alloc);
mono_mb_emit_byte (mb, CEE_DUP);
mono_mb_emit_stloc (mb, 1);
mono_mb_emit_stloc (mb, 3);
mono_mb_emit_ldarg (mb, argnum);
if (t->byref)
mono_mb_emit_byte (mb, CEE_LDIND_I);
- mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY));
+ mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY, NULL));
mono_mb_emit_stloc (mb, conv_arg);
} else {
MonoClass *eklass;
conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
}
else
- conv = (MonoMarshalConv)-1;
+ conv = MONO_MARSHAL_CONV_INVALID;
- if (is_string && conv == -1) {
+ if (is_string && conv == MONO_MARSHAL_CONV_INVALID) {
char *msg = g_strdup_printf ("string/stringbuilder marshalling conversion %d not implemented", encoding);
mono_mb_emit_exception_marshal_directive (mb, msg);
break;
/* Emit marshalling code */
if (is_string) {
+ int stind_op;
mono_mb_emit_ldloc (mb, dest_ptr);
mono_mb_emit_ldloc (mb, src_var);
mono_mb_emit_ldloc (mb, index_var);
mono_mb_emit_byte (mb, CEE_LDELEM_REF);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
- mono_mb_emit_byte (mb, CEE_STIND_I);
+ mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+ mono_mb_emit_byte (mb, stind_op);
} else {
/* set the src_ptr */
mono_mb_emit_ldloc (mb, src_var);
mono_mb_emit_stloc (mb, 1);
/* emit valuetype conversion code */
- emit_struct_conv_full (mb, eklass, FALSE, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1);
+ emit_struct_conv_full (mb, eklass, FALSE, 0, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1);
}
mono_mb_emit_add_to_local (mb, index_var, 1);
mono_mb_emit_byte (mb, CEE_CONV_OVF_I);
mono_mb_emit_op (mb, CEE_NEWARR, klass->element_class);
/* Store into argument */
- mono_mb_emit_byte (mb, CEE_STIND_I);
+ mono_mb_emit_byte (mb, CEE_STIND_REF);
}
}
gboolean need_free2;
MonoMarshalConv conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free2);
- g_assert (conv != -1);
+ g_assert (conv != MONO_MARSHAL_CONV_INVALID);
/* dest */
mono_mb_emit_ldarg (mb, argnum);
mono_mb_emit_ldloc (mb, src_ptr);
mono_mb_emit_byte (mb, CEE_LDIND_I);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
+ mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
if (need_free) {
/* src */
mono_mb_emit_stloc (mb, 1);
/* emit valuetype conversion code */
- emit_struct_conv_full (mb, eklass, TRUE, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1);
+ emit_struct_conv_full (mb, eklass, TRUE, 0, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1);
}
if (need_free) {
if (t->byref)
mono_mb_emit_byte (mb, CEE_LDIND_REF);
mono_mb_emit_ldloc (mb, conv_arg);
- mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_FREE_LPARRAY));
+ mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_FREE_LPARRAY, NULL));
}
break;
conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free);
}
else
- conv = (MonoMarshalConv)-1;
+ conv = MONO_MARSHAL_CONV_INVALID;
mono_marshal_load_type_info (eklass);
mono_mb_emit_icon (mb, esize);
mono_mb_emit_byte (mb, CEE_MUL);
mono_mb_emit_byte (mb, CEE_PREFIX1);
- mono_mb_emit_byte (mb, CEE_CPBLK);
+ mono_mb_emit_byte (mb, CEE_CPBLK);
+ mono_mb_patch_branch (mb, label1);
break;
}
/* Emit marshalling code */
if (is_string) {
- g_assert (conv != -1);
+ g_assert (conv != MONO_MARSHAL_CONV_INVALID);
mono_mb_emit_ldloc (mb, conv_arg);
mono_mb_emit_ldloc (mb, index_var);
mono_mb_emit_ldloc (mb, src_ptr);
mono_mb_emit_byte (mb, CEE_LDIND_I);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
+ mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
mono_mb_emit_byte (mb, CEE_STELEM_REF);
}
else {
conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
}
else
- conv = (MonoMarshalConv)-1;
+ conv = MONO_MARSHAL_CONV_INVALID;
mono_marshal_load_type_info (eklass);
/* Emit marshalling code */
if (is_string) {
- g_assert (conv != -1);
+ int stind_op;
+ g_assert (conv != MONO_MARSHAL_CONV_INVALID);
/* dest */
mono_mb_emit_ldloc (mb, dest_ptr);
mono_mb_emit_byte (mb, CEE_LDELEM_REF);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
- mono_mb_emit_byte (mb, CEE_STIND_I);
+ mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+ mono_mb_emit_byte (mb, stind_op);
}
else {
char *msg = g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
MonoClass *eklass;
guint32 label1, label2, label3;
int index_var, src, dest, esize;
- MonoMarshalConv conv = (MonoMarshalConv)-1;
+ MonoMarshalConv conv = MONO_MARSHAL_CONV_INVALID;
gboolean is_string = FALSE;
g_assert (!t->byref);
mono_mb_emit_byte (mb, CEE_ADD);
}
mono_mb_emit_byte (mb, CEE_MUL);
- mono_mb_emit_icall (mb, mono_marshal_alloc);
+ mono_mb_emit_icall (mb, ves_icall_marshal_alloc);
mono_mb_emit_stloc (mb, dest);
mono_mb_emit_ldloc (mb, dest);
mono_mb_emit_stloc (mb, 3);
/* Emit marshalling code */
if (is_string) {
- g_assert (conv != -1);
+ int stind_op;
+ g_assert (conv != MONO_MARSHAL_CONV_INVALID);
/* dest */
mono_mb_emit_ldloc (mb, dest);
mono_mb_emit_byte (mb, CEE_LDELEM_REF);
- mono_mb_emit_icall (mb, conv_to_icall (conv));
- mono_mb_emit_byte (mb, CEE_STIND_I);
+ mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+ mono_mb_emit_byte (mb, stind_op);
}
else {
char *msg = g_strdup ("Marshalling of non-string arrays to managed code is not implemented.");
return emit_marshal_string (m, argnum, t, spec, conv_arg, conv_arg_type, action);
case MONO_TYPE_CLASS:
case MONO_TYPE_OBJECT:
-#ifndef DISABLE_COM
+#if !defined(DISABLE_COM) && !defined(DISABLE_JIT)
if (spec && spec->native == MONO_NATIVE_STRUCT)
return emit_marshal_variant (m, argnum, t, spec, conv_arg, conv_arg_type, action);
+#endif
+#if !defined(DISABLE_COM)
if (spec && (spec->native == MONO_NATIVE_IUNKNOWN ||
spec->native == MONO_NATIVE_IDISPATCH ||
spec->native == MONO_NATIVE_INTERFACE))
return mono_cominterop_emit_marshal_safearray (m, argnum, t, spec, conv_arg, conv_arg_type, action);
#endif
- if (mono_defaults.safehandle_class != NULL && t->data.klass &&
- mono_class_is_subclass_of (t->data.klass, mono_defaults.safehandle_class, FALSE))
+ if (mono_class_try_get_safehandle_class () != NULL && t->data.klass &&
+ mono_class_is_subclass_of (t->data.klass, mono_class_try_get_safehandle_class (), FALSE))
return emit_marshal_safehandle (m, argnum, t, spec, conv_arg, conv_arg_type, action);
return emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action);
MonoClass *klass;
int i, argnum, *tmp_locals;
int type, param_shift = 0;
- static MonoMethodSignature *get_last_error_sig = NULL;
int coop_gc_stack_dummy, coop_gc_var;
memset (&m, 0, sizeof (m));
mono_mb_emit_icon (mb, 0);
mono_mb_emit_stloc (mb, 2);
- if (!MONO_TYPE_IS_VOID(sig->ret)) {
+ if (!MONO_TYPE_IS_VOID (sig->ret)) {
/* allocate local 3 to store the return value */
mono_mb_add_local (mb, sig->ret);
}
coop_gc_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
}
- if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
- /* Return type custom marshaling */
- /*
- * Since we can't determine the return type of the unmanaged function,
+ /*
+ * cookie = mono_threads_enter_gc_safe_region_unbalanced (ref dummy);
+ *
+ * ret = method (...);
+ *
+ * mono_threads_exit_gc_safe_region_unbalanced (cookie, ref dummy);
+ *
+ * <interrupt check>
+ *
+ * return ret;
+ */
+
+ if (MONO_TYPE_ISSTRUCT (sig->ret))
+ m.vtaddr_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+ if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
+ /* Return type custom marshaling */
+ /*
+ * Since we can't determine the return type of the unmanaged function,
* we assume it returns a pointer, and pass that pointer to
* MarshalNativeToManaged.
*/
tmp_locals [i] = emit_marshal (&m, i + param_shift, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_CONV_IN);
}
+ // In coop mode need to register blocking state during native call
+ if (mono_threads_is_coop_enabled ()) {
+ // Perform an extra, early lookup of the function address, so any exceptions
+ // potentially resulting from the lookup occur before entering blocking mode.
+ if (!func_param && !MONO_CLASS_IS_IMPORT (mb->method->klass) && aot) {
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_op (mb, CEE_MONO_ICALL_ADDR, &piinfo->method);
+ mono_mb_emit_byte (mb, CEE_POP); // Result not needed yet
+ }
+
+ mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
+ mono_mb_emit_icall (mb, mono_threads_enter_gc_safe_region_unbalanced);
+ mono_mb_emit_stloc (mb, coop_gc_var);
+ }
+
/* push all arguments */
if (sig->hasthis)
emit_marshal (&m, i + param_shift, sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_PUSH);
}
- if (mono_threads_is_coop_enabled ()) {
- mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
- mono_mb_emit_icall (mb, mono_threads_prepare_blocking);
- mono_mb_emit_stloc (mb, coop_gc_var);
- }
-
/* call the native method */
if (func_param) {
mono_mb_emit_byte (mb, CEE_LDARG_0);
#else
g_assert_not_reached ();
#endif
- }
- else {
+ } else {
if (aot) {
/* Reuse the ICALL_ADDR opcode for pinvokes too */
mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
/* Set LastError if needed */
if (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) {
- if (!get_last_error_sig) {
- get_last_error_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
- get_last_error_sig->ret = &mono_defaults.int_class->byval_arg;
- get_last_error_sig->pinvoke = 1;
- }
-
#ifdef TARGET_WIN32
- /*
- * Have to call GetLastError () early and without a wrapper, since various runtime components could
- * clobber its value.
- */
- mono_mb_emit_native_call (mb, get_last_error_sig, GetLastError);
- mono_mb_emit_icall (mb, mono_marshal_set_last_error_windows);
+ if (!aot) {
+ static MonoMethodSignature *get_last_error_sig = NULL;
+ if (!get_last_error_sig) {
+ get_last_error_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
+ get_last_error_sig->ret = &mono_defaults.int_class->byval_arg;
+ get_last_error_sig->pinvoke = 1;
+ }
+
+ /*
+ * Have to call GetLastError () early and without a wrapper, since various runtime components could
+ * clobber its value.
+ */
+ mono_mb_emit_native_call (mb, get_last_error_sig, GetLastError);
+ mono_mb_emit_icall (mb, mono_marshal_set_last_error_windows);
+ } else {
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_GET_LAST_ERROR);
+ mono_mb_emit_icall (mb, mono_marshal_set_last_error_windows);
+ }
#else
mono_mb_emit_icall (mb, mono_marshal_set_last_error);
#endif
- }
+ }
+
+ if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+ MonoClass *klass = mono_class_from_mono_type (sig->ret);
+ mono_class_init (klass);
+ if (!(mono_class_is_explicit_layout (klass) || klass->blittable)) {
+ /* This is used by emit_marshal_vtype (), but it needs to go right before the call */
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
+ mono_mb_emit_stloc (mb, m.vtaddr_var);
+ }
+ }
+ /* Unblock before converting the result, since that can involve calls into the runtime */
if (mono_threads_is_coop_enabled ()) {
mono_mb_emit_ldloc (mb, coop_gc_var);
mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
- mono_mb_emit_icall (mb, mono_threads_finish_blocking);
+ mono_mb_emit_icall (mb, mono_threads_exit_gc_safe_region_unbalanced);
}
/* convert the result */
if (spec && spec->native == MONO_NATIVE_CUSTOM) {
emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
} else {
-
handle_enum:
switch (type) {
case MONO_TYPE_VOID:
*
* generates IL code for the pinvoke wrapper (the generated method
* calls the unmanaged code in piinfo->addr)
- * The wrapper info for the wrapper is a WrapperInfo structure.
*/
MonoMethod *
mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, gboolean aot)
else
csig = mono_metadata_signature_dup_full (method->klass->image, sig);
+ //printf ("%s\n", mono_method_full_name (method, 1));
+
/* hack - string constructors returns a value */
if (method->string_ctor)
csig->ret = &mono_defaults.string_class->byval_arg;
#ifndef DISABLE_JIT
+ // FIXME:
+ MonoClass *handle_stack_mark_class;
+ MonoClass *error_class;
+ int thread_info_var = -1, stack_mark_var = -1, error_var = -1;
+ MonoMethodSignature *call_sig = csig;
+ gboolean uses_handles = FALSE;
+ (void) mono_lookup_internal_call_full (method, &uses_handles);
+
+
+ /* If it uses handles and MonoError, it had better check exceptions */
+ g_assert (!uses_handles || check_exceptions);
+
+ if (uses_handles) {
+ MonoMethodSignature *ret;
+
+ /* Add a MonoError argument */
+ // FIXME: The stuff from mono_metadata_signature_dup_internal_with_padding ()
+ ret = mono_metadata_signature_alloc (method->klass->image, csig->param_count + 1);
+
+ ret->param_count = csig->param_count + 1;
+ ret->ret = csig->ret;
+ for (int i = 0; i < csig->param_count; ++i) {
+ // FIXME: TODO implement handle wrapping for out and inout params.
+ g_assert (!mono_signature_param_is_out (csig, i));
+ ret->params [i] = csig->params [i];
+ }
+ ret->params [csig->param_count] = &mono_get_intptr_class ()->byval_arg;
+ call_sig = ret;
+ }
+
+ if (uses_handles) {
+ handle_stack_mark_class = mono_class_load_from_name (mono_get_corlib (), "Mono", "RuntimeStructs/HandleStackMark");
+ error_class = mono_class_load_from_name (mono_get_corlib (), "Mono", "RuntimeStructs/MonoError");
+
+ thread_info_var = mono_mb_add_local (mb, &mono_get_intptr_class ()->byval_arg);
+ stack_mark_var = mono_mb_add_local (mb, &handle_stack_mark_class->byval_arg);
+ error_var = mono_mb_add_local (mb, &error_class->byval_arg);
+
+ // FIXME: Change csig so it passes a handle not an objref
+ }
+
if (sig->hasthis) {
int pos;
pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
mono_mb_emit_exception (mb, "NullReferenceException", NULL);
mono_mb_patch_branch (mb, pos);
-
- mono_mb_emit_byte (mb, CEE_LDARG_0);
}
- for (i = 0; i < sig->param_count; i++)
- mono_mb_emit_ldarg (mb, i + sig->hasthis);
+ if (uses_handles) {
+ mono_mb_emit_ldloc_addr (mb, stack_mark_var);
+ mono_mb_emit_ldloc_addr (mb, error_var);
+ mono_mb_emit_icall (mb, mono_icall_start);
+ mono_mb_emit_stloc (mb, thread_info_var);
+
+ if (sig->hasthis) {
+ mono_mb_emit_byte (mb, CEE_LDARG_0);
+ mono_mb_emit_icall (mb, mono_handle_new);
+ }
+ for (i = 0; i < sig->param_count; i++) {
+ mono_mb_emit_ldarg (mb, i + sig->hasthis);
+ if (MONO_TYPE_IS_REFERENCE (sig->params [i])) {
+ mono_mb_emit_icall (mb, mono_handle_new);
+ }
+ }
+ mono_mb_emit_ldloc_addr (mb, error_var);
+ } else {
+ if (sig->hasthis)
+ mono_mb_emit_byte (mb, CEE_LDARG_0);
+ for (i = 0; i < sig->param_count; i++)
+ mono_mb_emit_ldarg (mb, i + sig->hasthis);
+ }
if (aot) {
mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
mono_mb_emit_op (mb, CEE_MONO_ICALL_ADDR, &piinfo->method);
- mono_mb_emit_calli (mb, csig);
+ mono_mb_emit_calli (mb, call_sig);
} else {
g_assert (piinfo->addr);
- mono_mb_emit_native_call (mb, csig, piinfo->addr);
+ mono_mb_emit_native_call (mb, call_sig, piinfo->addr);
}
+
+ if (uses_handles) {
+ if (MONO_TYPE_IS_REFERENCE (sig->ret)) {
+ // if (ret != NULL_HANDLE) {
+ // ret = MONO_HANDLE_RAW(ret)
+ // }
+ mono_mb_emit_byte (mb, CEE_DUP);
+ int pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
+ mono_mb_emit_ldflda (mb, MONO_HANDLE_PAYLOAD_OFFSET (MonoObject));
+ mono_mb_emit_byte (mb, CEE_LDIND_REF);
+ mono_mb_patch_branch (mb, pos);
+ }
+ mono_mb_emit_ldloc (mb, thread_info_var);
+ mono_mb_emit_ldloc_addr (mb, stack_mark_var);
+ mono_mb_emit_ldloc_addr (mb, error_var);
+ mono_mb_emit_icall (mb, mono_icall_end);
+ }
+
if (check_exceptions)
emit_thread_interrupt_checkpoint (mb);
mono_mb_emit_byte (mb, CEE_RET);
}
#else
MonoMethodSignature *sig, *csig;
- int i, *tmp_locals;
+ MonoExceptionClause *clauses, *clause_finally, *clause_catch;
+ int i, *tmp_locals, ex_local, e_local, attach_cookie_local, attach_dummy_local;
+ int leave_try_pos, leave_catch_pos, ex_m1_pos;
gboolean closed = FALSE;
- int coop_gc_var, coop_gc_dummy_local;
sig = m->sig;
csig = m->csig;
mono_mb_add_local (mb, sig->ret);
}
- if (mono_threads_is_coop_enabled ()) {
- /* local 4, the local to be used when calling the reset_blocking funcs */
- /* tons of code hardcode 3 to be the return var */
- coop_gc_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
- /* local 5, the local used to get a stack address for suspend funcs */
- coop_gc_dummy_local = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
- }
+ if (MONO_TYPE_ISSTRUCT (sig->ret))
+ m->vtaddr_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
- mono_mb_emit_icon (mb, 0);
- mono_mb_emit_stloc (mb, 2);
+ ex_local = mono_mb_add_local (mb, &mono_defaults.uint32_class->byval_arg);
+ e_local = mono_mb_add_local (mb, &mono_defaults.exception_class->byval_arg);
+
+ attach_cookie_local = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+ attach_dummy_local = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
/*
- * Might need to attach the thread to the JIT or change the
- * domain for the callback.
+ * guint32 ex = -1;
+ * try {
+ * // does (STARTING|RUNNING|BLOCKING) -> RUNNING + set/switch domain
+ * mono_threads_attach_coop ();
+ *
+ * <interrupt check>
+ *
+ * ret = method (...);
+ * } catch (Exception e) {
+ * ex = mono_gchandle_new (e, false);
+ * } finally {
+ * // does RUNNING -> (RUNNING|BLOCKING) + unset/switch domain
+ * mono_threads_detach_coop ();
+ *
+ * if (ex != -1)
+ * mono_marshal_ftnptr_eh_callback (ex);
+ * }
+ *
+ * return ret;
*/
- mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
- mono_mb_emit_byte (mb, CEE_MONO_JIT_ATTACH);
- if (mono_threads_is_coop_enabled ()) {
- /* XXX can we merge reset_blocking_start with JIT_ATTACH above and save one call? */
- mono_mb_emit_ldloc_addr (mb, coop_gc_dummy_local);
- mono_mb_emit_icall (mb, mono_threads_reset_blocking_start);
- mono_mb_emit_stloc (mb, coop_gc_var);
+ clauses = g_new0 (MonoExceptionClause, 2);
+
+ clause_catch = &clauses [0];
+ clause_catch->flags = MONO_EXCEPTION_CLAUSE_NONE;
+ clause_catch->data.catch_class = mono_defaults.exception_class;
+
+ clause_finally = &clauses [1];
+ clause_finally->flags = MONO_EXCEPTION_CLAUSE_FINALLY;
+
+ mono_mb_emit_icon (mb, 0);
+ mono_mb_emit_stloc (mb, 2);
+
+ mono_mb_emit_icon (mb, -1);
+ mono_mb_emit_byte (mb, CEE_CONV_U4);
+ mono_mb_emit_stloc (mb, ex_local);
+
+ /* try { */
+ clause_catch->try_offset = clause_finally->try_offset = mono_mb_get_label (mb);
+
+ if (!mono_threads_is_coop_enabled ()) {
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_JIT_ATTACH);
+ } else {
+ /* mono_threads_attach_coop (); */
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_LDDOMAIN);
+ mono_mb_emit_ldloc_addr (mb, attach_dummy_local);
+ mono_mb_emit_icall (mb, mono_threads_attach_coop);
+ mono_mb_emit_stloc (mb, attach_cookie_local);
}
+ /* <interrupt check> */
+ emit_thread_interrupt_checkpoint (mb);
+
/* we first do all conversions */
tmp_locals = (int *)alloca (sizeof (int) * sig->param_count);
for (i = 0; i < sig->param_count; i ++) {
}
}
- emit_thread_interrupt_checkpoint (mb);
-
if (sig->hasthis) {
if (target_handle) {
mono_mb_emit_icon (mb, (gint32)target_handle);
mono_mb_emit_ldarg (mb, i);
}
+ /* ret = method (...) */
mono_mb_emit_managed_call (mb, method, NULL);
+ if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+ MonoClass *klass = mono_class_from_mono_type (sig->ret);
+ mono_class_init (klass);
+ if (!(mono_class_is_explicit_layout (klass) || klass->blittable)) {
+ /* This is used by emit_marshal_vtype (), but it needs to go right before the call */
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
+ mono_mb_emit_stloc (mb, m->vtaddr_var);
+ }
+ }
+
if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
} else if (!sig->ret->byref) {
}
}
- if (mono_threads_is_coop_enabled ()) {
- /* XXX merge reset_blocking_end with detach */
- mono_mb_emit_ldloc (mb, coop_gc_var);
- mono_mb_emit_ldloc_addr (mb, coop_gc_dummy_local);
- mono_mb_emit_icall (mb, mono_threads_reset_blocking_end);
+ leave_try_pos = mono_mb_emit_branch (mb, CEE_LEAVE);
+
+ /* } [endtry] */
+
+ /* catch (Exception e) { */
+ clause_catch->try_len = mono_mb_get_label (mb) - clause_catch->try_offset;
+ clause_catch->handler_offset = mono_mb_get_label (mb);
+
+ mono_mb_emit_stloc (mb, e_local);
+
+ /* ex = mono_gchandle_new (e, false); */
+ mono_mb_emit_ldloc (mb, e_local);
+ mono_mb_emit_icon (mb, 0);
+ mono_mb_emit_icall (mb, mono_gchandle_new);
+ mono_mb_emit_stloc (mb, ex_local);
+
+ leave_catch_pos = mono_mb_emit_branch (mb, CEE_LEAVE);
+
+ /* } [endcatch] */
+ clause_catch->handler_len = mono_mb_get_pos (mb) - clause_catch->handler_offset;
+
+ /* finally { */
+ clause_finally->try_len = mono_mb_get_label (mb) - clause_finally->try_offset;
+ clause_finally->handler_offset = mono_mb_get_label (mb);
+
+ if (!mono_threads_is_coop_enabled ()) {
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_JIT_DETACH);
+ } else {
+ /* mono_threads_detach_coop (); */
+ mono_mb_emit_ldloc (mb, attach_cookie_local);
+ mono_mb_emit_ldloc_addr (mb, attach_dummy_local);
+ mono_mb_emit_icall (mb, mono_threads_detach_coop);
}
- mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
- mono_mb_emit_byte (mb, CEE_MONO_JIT_DETACH);
+ /* if (ex != -1) */
+ mono_mb_emit_ldloc (mb, ex_local);
+ mono_mb_emit_icon (mb, -1);
+ mono_mb_emit_byte (mb, CEE_CONV_U4);
+ ex_m1_pos = mono_mb_emit_branch (mb, CEE_BEQ);
+
+ /* mono_marshal_ftnptr_eh_callback (ex) */
+ mono_mb_emit_ldloc (mb, ex_local);
+ mono_mb_emit_icall (mb, mono_marshal_ftnptr_eh_callback);
+ /* [ex == -1] */
+ mono_mb_patch_branch (mb, ex_m1_pos);
+
+ mono_mb_emit_byte (mb, CEE_ENDFINALLY);
+
+ /* } [endfinally] */
+ clause_finally->handler_len = mono_mb_get_pos (mb) - clause_finally->handler_offset;
+
+ mono_mb_patch_branch (mb, leave_try_pos);
+ mono_mb_patch_branch (mb, leave_catch_pos);
+
+ /* return ret; */
if (m->retobj_var) {
mono_mb_emit_ldloc (mb, m->retobj_var);
mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
mono_mb_emit_byte (mb, CEE_RET);
}
+ mono_mb_set_clauses (mb, 2, clauses);
+
if (closed)
g_free (sig);
#endif
MonoMethod *
mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, uint32_t target_handle)
{
- static MonoClass *UnmanagedFunctionPointerAttribute;
+ MonoError error;
MonoMethodSignature *sig, *csig, *invoke_sig;
MonoMethodBuilder *mb;
MonoMethod *res, *invoke;
EmitMarshalContext m;
g_assert (method != NULL);
- g_assert (!mono_method_signature (method)->pinvoke);
+ g_assert (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL));
/*
* FIXME: Should cache the method+delegate type pair, since the same method
mono_marshal_set_callconv_from_modopt (invoke, csig);
- /* Handle the UnmanagedFunctionPointerAttribute */
- if (!UnmanagedFunctionPointerAttribute)
- UnmanagedFunctionPointerAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
-
/* The attribute is only available in Net 2.0 */
- if (UnmanagedFunctionPointerAttribute) {
+ if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
MonoCustomAttrInfo *cinfo;
MonoCustomAttrEntry *attr;
* contents of the attribute without constructing it, as that might not be
* possible when running in cross-compiling mode.
*/
- cinfo = mono_custom_attrs_from_class (delegate_klass);
+ cinfo = mono_custom_attrs_from_class_checked (delegate_klass, &error);
+ mono_error_assert_ok (&error);
attr = NULL;
if (cinfo) {
for (i = 0; i < cinfo->num_attrs; ++i) {
MonoClass *ctor_class = cinfo->attrs [i].ctor->klass;
- if (mono_class_has_parent (ctor_class, UnmanagedFunctionPointerAttribute)) {
+ if (mono_class_has_parent (ctor_class, mono_class_try_get_unmanaged_function_pointer_attribute_class ())) {
attr = &cinfo->attrs [i];
break;
}
gpointer
mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type)
{
+ MonoError error;
MonoMethod *method;
MonoMethodSignature *sig;
MonoMethodBuilder *mb;
g_assert (token);
- method = mono_get_method (image, token, NULL);
+ method = mono_get_method_checked (image, token, NULL, NULL, &error);
+ if (!method)
+ g_error ("Could not load vtfixup token 0x%x due to %s", token, mono_error_get_message (&error));
g_assert (method);
if (type & (VTFIXUP_TYPE_FROM_UNMANAGED | VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN)) {
mono_metadata_free_marshal_spec (mspecs [i]);
g_free (mspecs);
- return mono_compile_method (method);
+ gpointer compiled_ptr = mono_compile_method_checked (method, &error);
+ mono_error_assert_ok (&error);
+ return compiled_ptr;
}
sig = mono_method_signature (method);
method = mono_mb_create (mb, sig, param_count, NULL);
mono_mb_free (mb);
- return mono_compile_method (method);
+ gpointer compiled_ptr = mono_compile_method_checked (method, &error);
+ mono_error_assert_ok (&error);
+ return compiled_ptr;
}
#ifndef DISABLE_JIT
/*
* This does the equivalent of mono_object_castclass_with_cache.
- * The wrapper info for the wrapper is a WrapperInfo structure.
*/
MonoMethod *
mono_marshal_get_castclass_with_cache (void)
return cached;
}
+/* this is an icall */
static MonoObject *
mono_marshal_isinst_with_cache (MonoObject *obj, MonoClass *klass, uintptr_t *cache)
{
- MonoObject *isinst = mono_object_isinst (obj, klass);
+ MonoError error;
+ MonoObject *isinst = mono_object_isinst_checked (obj, klass, &error);
+ if (mono_error_set_pending_exception (&error))
+ return NULL;
#ifndef DISABLE_REMOTING
if (obj->vtable->klass == mono_defaults.transparent_proxy_class)
/*
* This does the equivalent of mono_object_isinst_with_cache.
- * The wrapper info for the wrapper is a WrapperInfo structure.
*/
MonoMethod *
mono_marshal_get_isinst_with_cache (void)
// return obj
mono_mb_patch_branch (mb, positive_cache_hit_pos);
- mono_mb_emit_ldarg (mb, 0);
+ mono_mb_emit_ldarg (mb, obj_arg_position);
mono_mb_emit_byte (mb, CEE_RET);
#endif
* an instance of the given type, icluding the case where the object is a proxy.
* The generated function has the following signature:
* MonoObject* __castclass_wrapper_ (MonoObject *obj)
- * The wrapper info for the wrapper is a WrapperInfo structure.
*/
MonoMethod *
mono_marshal_get_castclass (MonoClass *klass)
* @klass:
*
* generates IL code for StructureToPtr (object structure, IntPtr ptr, bool fDeleteOld)
- * The wrapper info for the wrapper is a WrapperInfo structure.
*/
MonoMethod *
mono_marshal_get_struct_to_ptr (MonoClass *klass)
res = mono_mb_create (mb, mono_signature_no_pinvoke (stoptr), 0, info);
mono_mb_free (mb);
- klass->marshal_info->str_to_ptr = res;
+ mono_marshal_lock ();
+ if (!klass->marshal_info->str_to_ptr)
+ klass->marshal_info->str_to_ptr = res;
+ else
+ res = klass->marshal_info->str_to_ptr;
+ mono_marshal_unlock ();
return res;
}
* @klass:
*
* generates IL code for PtrToStructure (IntPtr src, object structure)
- * The wrapper info for the wrapper is a WrapperInfo structure.
*/
MonoMethod *
mono_marshal_get_ptr_to_struct (MonoClass *klass)
res = mono_mb_create (mb, ptostr, 0, info);
mono_mb_free (mb);
- klass->marshal_info->ptr_to_str = res;
+ mono_marshal_lock ();
+ if (!klass->marshal_info->ptr_to_str)
+ klass->marshal_info->ptr_to_str = res;
+ else
+ res = klass->marshal_info->ptr_to_str;
+ mono_marshal_unlock ();
return res;
}
* This is used to avoid infinite recursion since it is hard to determine where to
* replace a method with its synchronized wrapper, and where not.
* The runtime should execute METHOD instead of the wrapper.
- * The wrapper info for the wrapper is a WrapperInfo structure.
*/
MonoMethod *
mono_marshal_get_synchronized_inner_wrapper (MonoMethod *method)
method = ((MonoMethodInflated*)method)->declaring;
container = mono_method_get_generic_container (method);
if (!container)
- container = method->klass->generic_container;
+ container = mono_class_try_get_generic_container (method->klass); //FIXME is this a case of a try?
g_assert (container);
}
method = ((MonoMethodInflated*)method)->declaring;
container = mono_method_get_generic_container (method);
if (!container)
- container = method->klass->generic_container;
+ container = mono_class_try_get_generic_container (method->klass); //FIXME is this a case of a try?
g_assert (container);
}
#endif
if (method->klass->valuetype && !(method->flags & MONO_METHOD_ATTR_STATIC)) {
- mono_class_set_failure (method->klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ /* FIXME Is this really the best way to signal an error here? Isn't this called much later after class setup? -AK */
+ mono_class_set_type_load_failure (method->klass, "");
#ifndef DISABLE_JIT
/* This will throw the type load exception when the wrapper is compiled */
mono_mb_emit_byte (mb, CEE_LDNULL);
if (!enter_method) {
MonoMethodDesc *desc;
- desc = mono_method_desc_new ("Monitor:enter_with_atomic_var(object,bool&)", FALSE);
+ desc = mono_method_desc_new ("Monitor:Enter(object,bool&)", FALSE);
enter_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
g_assert (enter_method);
mono_method_desc_free (desc);
return FALSE;
element_class = klass->element_class;
- return (element_class->flags & TYPE_ATTRIBUTE_SEALED) || element_class->valuetype;
+ return mono_class_is_sealed (element_class) || element_class->valuetype;
}
static int
/*Arrays are sealed but are covariant on their element type, We can't use any of the fast paths.*/
if (mono_class_is_marshalbyref (element_class) || element_class->rank || mono_class_has_variant_generic_params (element_class))
return STELEMREF_COMPLEX;
- if (element_class->flags & TYPE_ATTRIBUTE_SEALED)
+ if (mono_class_is_sealed (element_class))
return STELEMREF_SEALED_CLASS;
return STELEMREF_CLASS;
}
#endif
/*
- * The wrapper info for the wrapper is a WrapperInfo structure.
- *
* TODO:
* - Separate simple interfaces from variant interfaces or mbr types. This way we can avoid the icall for them.
* - Emit a (new) mono bytecode that produces OP_COND_EXC_NE_UN to raise ArrayTypeMismatch
MonoMethod *res;
char *name;
const char *param_names [16];
- guint32 b1, b2, b3;
+ guint32 b1, b2, b3, b4;
int aklass, vklass, vtable, uiid;
int array_slot_addr;
WrapperInfo *info;
/*if (mono_object_isinst (value, aklass)) */
mono_mb_emit_ldarg (mb, 2);
mono_mb_emit_ldloc (mb, aklass);
- mono_mb_emit_icall (mb, mono_object_isinst);
+ mono_mb_emit_icall (mb, mono_object_isinst_icall);
b2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
/* do_store: */
/*if (mono_object_isinst (value, aklass)) */
mono_mb_emit_ldarg (mb, 2);
mono_mb_emit_ldloc (mb, aklass);
- mono_mb_emit_icall (mb, mono_object_isinst);
+ mono_mb_emit_icall (mb, mono_object_isinst_icall);
b2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
/* if (vklass->idepth < aklass->idepth) goto failue */
mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoClass, idepth));
mono_mb_emit_byte (mb, CEE_LDIND_U2);
- b2 = mono_mb_emit_branch (mb, CEE_BLT_UN);
+ b3 = mono_mb_emit_branch (mb, CEE_BLT_UN);
/* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
mono_mb_emit_ldloc (mb, vklass);
mono_mb_emit_byte (mb, CEE_LDIND_I);
mono_mb_emit_ldloc (mb, aklass);
- b3 = mono_mb_emit_branch (mb, CEE_BNE_UN);
+ b4 = mono_mb_emit_branch (mb, CEE_BNE_UN);
/* do_store: */
mono_mb_patch_branch (mb, b1);
/* do_exception: */
mono_mb_patch_branch (mb, b2);
mono_mb_patch_branch (mb, b3);
+ mono_mb_patch_branch (mb, b4);
mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
break;
/* uiid = klass->interface_id; */
mono_mb_emit_ldloc (mb, aklass);
mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoClass, interface_id));
- mono_mb_emit_byte (mb, CEE_LDIND_U2);
+ mono_mb_emit_byte (mb, CEE_LDIND_U4);
mono_mb_emit_stloc (mb, uiid);
/*if (uiid > vt->max_interface_id)*/
mono_mb_emit_ldloc (mb, uiid);
mono_mb_emit_ldloc (mb, vtable);
mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
- mono_mb_emit_byte (mb, CEE_LDIND_U2);
+ mono_mb_emit_byte (mb, CEE_LDIND_U4);
b2 = mono_mb_emit_branch (mb, CEE_BGT_UN);
/* if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7)))) */
return res;
}
-/*
- * The wrapper info for the wrapper is a WrapperInfo structure.
- */
MonoMethod*
mono_marshal_get_stelemref (void)
{
mono_mb_emit_ldarg (mb, 2);
mono_mb_emit_ldloc (mb, aklass);
- mono_mb_emit_icall (mb, mono_object_isinst);
+ mono_mb_emit_icall (mb, mono_object_isinst_icall);
b4 = mono_mb_emit_branch (mb, CEE_BRTRUE);
mono_mb_patch_addr (mb, b4, copy_pos - (b4 + 4));
* mono_marshal_get_gsharedvt_in_wrapper:
*
* This wrapper handles calls from normal code to gsharedvt code.
- *
- * The wrapper info for the wrapper is a WrapperInfo structure.
*/
MonoMethod*
mono_marshal_get_gsharedvt_in_wrapper (void)
* mono_marshal_get_gsharedvt_out_wrapper:
*
* This wrapper handles calls from gsharedvt code to normal code.
- *
- * The wrapper info for the wrapper is a WrapperInfo structure.
*/
MonoMethod*
mono_marshal_get_gsharedvt_out_wrapper (void)
return res;
}
+#ifndef HOST_WIN32
+static inline void*
+mono_marshal_alloc_co_task_mem (size_t size)
+{
+ if ((gulong)size == 0)
+ /* This returns a valid pointer for size 0 on MS.NET */
+ size = 4;
+
+ return g_try_malloc ((gulong)size);
+}
+#endif
+
void*
-mono_marshal_alloc (gulong size)
+mono_marshal_alloc (gulong size, MonoError *error)
{
gpointer res;
-#ifdef HOST_WIN32
- res = CoTaskMemAlloc (size);
-#else
- res = g_try_malloc ((gulong)size);
+ mono_error_init (error);
+
+ res = mono_marshal_alloc_co_task_mem (size);
if (!res)
- mono_gc_out_of_memory ((gulong)size);
-#endif
+ mono_error_set_out_of_memory (error, "Could not allocate %lu bytes", size);
+
return res;
}
-void
-mono_marshal_free (gpointer ptr)
+/* This is a JIT icall, it sets the pending exception and returns NULL on error. */
+static void*
+ves_icall_marshal_alloc (gulong size)
+{
+ MonoError error;
+ void *ret = mono_marshal_alloc (size, &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ }
+
+ return ret;
+}
+
+#ifndef HOST_WIN32
+static inline void
+mono_marshal_free_co_task_mem (void *ptr)
{
-#ifdef HOST_WIN32
- CoTaskMemFree (ptr);
-#else
g_free (ptr);
+ return;
+}
#endif
+
+void
+mono_marshal_free (gpointer ptr)
+{
+ mono_marshal_free_co_task_mem (ptr);
}
void
return s ? mono_string_chars (s) : NULL;
}
+/* This is a JIT icall, it sets the pending exception and returns NULL on error. */
static void *
mono_marshal_string_to_utf16_copy (MonoString *s)
{
if (s == NULL) {
return NULL;
} else {
- gunichar2 *res = (gunichar2 *)mono_marshal_alloc ((mono_string_length (s) * 2) + 2);
+ MonoError error;
+ gunichar2 *res = (gunichar2 *)mono_marshal_alloc ((mono_string_length (s) * 2) + 2, &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ }
memcpy (res, mono_string_chars (s), mono_string_length (s) * 2);
res [mono_string_length (s)] = 0;
return res;
MonoString *
ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (char *ptr, gint32 len)
{
- if (ptr == NULL) {
- mono_set_pending_exception (mono_get_exception_argument_null ("ptr"));
- return NULL;
- } else {
- return mono_string_new_len (mono_domain_get (), ptr, len);
- }
+ MonoError error;
+ MonoString *result = NULL;
+ mono_error_init (&error);
+ if (ptr == NULL)
+ mono_error_set_argument_null (&error, "ptr", "");
+ else
+ result = mono_string_new_len_checked (mono_domain_get (), ptr, len, &error);
+ mono_error_set_pending_exception (&error);
+ return result;
}
MonoString *
ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (guint16 *ptr)
{
+ MonoError error;
+ MonoString *res = NULL;
MonoDomain *domain = mono_domain_get ();
int len = 0;
guint16 *t = ptr;
while (*t++)
len++;
- return mono_string_new_utf16 (domain, ptr, len);
+ res = mono_string_new_utf16_checked (domain, ptr, len, &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ }
+ return res;
}
MonoString *
ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (guint16 *ptr, gint32 len)
{
+ MonoError error;
+ MonoString *res = NULL;
MonoDomain *domain = mono_domain_get ();
+ mono_error_init (&error);
+
if (ptr == NULL) {
- mono_set_pending_exception (mono_get_exception_argument_null ("ptr"));
- return NULL;
+ res = NULL;
+ mono_error_set_argument_null (&error, "ptr", "");
} else {
- return mono_string_new_utf16 (domain, ptr, len);
+ res = mono_string_new_utf16_checked (domain, ptr, len, &error);
}
+
+ if (!mono_error_ok (&error))
+ mono_error_set_pending_exception (&error);
+ return res;
}
guint32
return 0;
}
- layout = (klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK);
+ layout = (mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK);
if (type->type == MONO_TYPE_PTR || type->type == MONO_TYPE_FNPTR) {
return sizeof (gpointer);
void
ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject *obj, gpointer dst, MonoBoolean delete_old)
{
+ MonoError error;
MonoMethod *method;
gpointer pa [3];
pa [1] = &dst;
pa [2] = &delete_old;
- mono_runtime_invoke (method, NULL, pa, NULL);
+ mono_runtime_invoke_checked (method, NULL, pa, &error);
+ if (!mono_error_ok (&error))
+ mono_error_set_pending_exception (&error);
}
static void
-ptr_to_structure (gpointer src, MonoObject *dst)
+ptr_to_structure (gpointer src, MonoObject *dst, MonoError *error)
{
MonoMethod *method;
gpointer pa [2];
+ mono_error_init (error);
+
method = mono_marshal_get_ptr_to_struct (dst->vtable->klass);
pa [0] = &src;
pa [1] = dst;
- mono_runtime_invoke (method, NULL, pa, NULL);
+ mono_runtime_invoke_checked (method, NULL, pa, error);
}
void
ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src, MonoObject *dst)
{
MonoType *t;
+ MonoError error;
MONO_CHECK_ARG_NULL (src,);
MONO_CHECK_ARG_NULL (dst,);
return;
}
- ptr_to_structure (src, dst);
+ ptr_to_structure (src, dst, &error);
+ if (!mono_error_ok (&error))
+ mono_error_set_pending_exception (&error);
}
MonoObject *
ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer src, MonoReflectionType *type)
{
+ MonoError error;
MonoClass *klass;
MonoDomain *domain = mono_domain_get ();
MonoObject *res;
return NULL;
}
- res = mono_object_new (domain, klass);
+ res = mono_object_new_checked (domain, klass, &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ }
- ptr_to_structure (src, res);
+ ptr_to_structure (src, res, &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ }
return res;
}
int
ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType *type, MonoString *field_name)
{
+ MonoError error;
MonoMarshalType *info;
MonoClass *klass;
char *fname;
MONO_CHECK_ARG_NULL (type, 0);
MONO_CHECK_ARG_NULL (field_name, 0);
- fname = mono_string_to_utf8 (field_name);
+ fname = mono_string_to_utf8_checked (field_name, &error);
+ if (mono_error_set_pending_exception (&error))
+ return 0;
klass = mono_class_from_mono_type (type->type);
if (!mono_class_init (klass)) {
mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
return info->fields [match_index].offset;
}
+#ifndef HOST_WIN32
gpointer
ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (MonoString *string)
{
-#ifdef HOST_WIN32
- char* tres, *ret;
- size_t len;
- tres = mono_string_to_utf8 (string);
- if (!tres)
- return tres;
-
- len = strlen (tres) + 1;
- ret = ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (len);
- memcpy (ret, tres, len);
- g_free (tres);
+ MonoError error;
+ char *ret = mono_string_to_utf8_checked (string, &error);
+ mono_error_set_pending_exception (&error);
return ret;
-
-#else
- return mono_string_to_utf8 (string);
-#endif
}
gpointer
if (string == NULL)
return NULL;
else {
-#ifdef TARGET_WIN32
- gunichar2 *res = ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal
- ((mono_string_length (string) + 1) * 2);
-#else
gunichar2 *res = (gunichar2 *)g_malloc ((mono_string_length (string) + 1) * 2);
-#endif
+
memcpy (res, mono_string_chars (string), mono_string_length (string) * 2);
res [mono_string_length (string)] = 0;
return res;
}
}
+#endif /* !HOST_WIN32 */
static void
mono_struct_delete_old (MonoClass *klass, char *ptr)
case MONO_MARSHAL_CONV_STR_BSTR:
case MONO_MARSHAL_CONV_STR_ANSIBSTR:
case MONO_MARSHAL_CONV_STR_TBSTR:
+ case MONO_MARSHAL_CONV_STR_UTF8STR:
mono_marshal_free (*(gpointer *)cpos);
break;
mono_struct_delete_old (klass, (char *)src);
}
+#ifndef HOST_WIN32
+static inline void *
+mono_marshal_alloc_hglobal (size_t size)
+{
+ return g_try_malloc (size);
+}
+#endif
+
void*
ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (gpointer size)
{
/* This returns a valid pointer for size 0 on MS.NET */
s = 4;
-#ifdef HOST_WIN32
- res = GlobalAlloc (GMEM_FIXED, s);
-#else
- res = g_try_malloc (s);
-#endif
- if (!res)
- mono_gc_out_of_memory (s);
+ res = mono_marshal_alloc_hglobal (s);
+
+ if (!res) {
+ mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
+ return NULL;
+ }
return res;
}
+#ifndef HOST_WIN32
+static inline gpointer
+mono_marshal_realloc_hglobal (gpointer ptr, size_t size)
+{
+ return g_try_realloc (ptr, size);
+}
+#endif
+
gpointer
ves_icall_System_Runtime_InteropServices_Marshal_ReAllocHGlobal (gpointer ptr, gpointer size)
{
size_t s = (size_t)size;
if (ptr == NULL) {
- mono_gc_out_of_memory (s);
+ mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
return NULL;
}
-#ifdef HOST_WIN32
- res = GlobalReAlloc (ptr, s, GMEM_MOVEABLE);
-#else
- res = g_try_realloc (ptr, s);
-#endif
- if (!res)
- mono_gc_out_of_memory (s);
+ res = mono_marshal_realloc_hglobal (ptr, s);
+
+ if (!res) {
+ mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
+ return NULL;
+ }
return res;
}
-void
-ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr)
+#ifndef HOST_WIN32
+static inline void
+mono_marshal_free_hglobal (gpointer ptr)
{
-#ifdef HOST_WIN32
- GlobalFree (ptr);
-#else
g_free (ptr);
+ return;
+}
#endif
+
+void
+ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr)
+{
+ mono_marshal_free_hglobal (ptr);
}
void*
ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem (int size)
{
- void *res;
+ void *res = mono_marshal_alloc_co_task_mem (size);
-#ifdef HOST_WIN32
- res = CoTaskMemAlloc (size);
-#else
- if ((gulong)size == 0)
- /* This returns a valid pointer for size 0 on MS.NET */
- size = 4;
+ if (!res) {
+ mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
+ return NULL;
+ }
+ return res;
+}
- res = g_try_malloc ((gulong)size);
-#endif
- if (!res)
- mono_gc_out_of_memory ((gulong)size);
+void*
+ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMemSize (gulong size)
+{
+ void *res = mono_marshal_alloc_co_task_mem (size);
+
+ if (!res) {
+ mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
+ return NULL;
+ }
return res;
}
void
ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem (void *ptr)
{
-#ifdef HOST_WIN32
- CoTaskMemFree (ptr);
-#else
- g_free (ptr);
-#endif
+ mono_marshal_free_co_task_mem (ptr);
+ return;
+}
+
+#ifndef HOST_WIN32
+static inline gpointer
+mono_marshal_realloc_co_task_mem (gpointer ptr, size_t size)
+{
+ return g_try_realloc (ptr, (gulong)size);
}
+#endif
gpointer
ves_icall_System_Runtime_InteropServices_Marshal_ReAllocCoTaskMem (gpointer ptr, int size)
{
- void *res;
+ void *res = mono_marshal_realloc_co_task_mem (ptr, size);
-#ifdef HOST_WIN32
- res = CoTaskMemRealloc (ptr, size);
-#else
- res = g_try_realloc (ptr, (gulong)size);
-#endif
- if (!res)
- mono_gc_out_of_memory ((gulong)size);
+ if (!res) {
+ mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
+ return NULL;
+ }
return res;
}
return mono_ftnptr_to_delegate (klass, ftn);
}
+gpointer
+ves_icall_System_Runtime_InteropServices_Marshal_GetFunctionPointerForDelegateInternal (MonoDelegate *delegate)
+{
+ return mono_delegate_to_ftnptr (delegate);
+}
+
/**
* mono_marshal_is_loading_type_info:
*
count++;
}
- layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
+ layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
/* The mempool is protected by the loader lock */
info = (MonoMarshalType *)mono_image_alloc0 (klass->image, MONO_SIZEOF_MARSHAL_TYPE + sizeof (MonoMarshalField) * count);
j++;
}
+ if (klass->byval_arg.type == MONO_TYPE_PTR)
+ info->native_size = sizeof (gpointer);
+
if (layout != TYPE_ATTRIBUTE_AUTO_LAYOUT) {
info->native_size = MAX (native_size, info->native_size);
/*
/*We do double-checking locking on marshal_info */
mono_memory_barrier ();
klass->marshal_info = info;
+ ++class_marshal_info_count;
}
mono_marshal_unlock ();
case MONO_NATIVE_BSTR:
case MONO_NATIVE_ANSIBSTR:
case MONO_NATIVE_TBSTR:
+ case MONO_NATIVE_UTF8STR:
case MONO_NATIVE_LPARRAY:
case MONO_NATIVE_SAFEARRAY:
case MONO_NATIVE_IUNKNOWN:
return 0;
}
+/* This is a JIT icall, it sets the pending exception and return NULL on error */
gpointer
mono_marshal_asany (MonoObject *o, MonoMarshalNative string_encoding, int param_attrs)
{
+ MonoError error;
MonoType *t;
MonoClass *klass;
switch (string_encoding) {
case MONO_NATIVE_LPWSTR:
return mono_marshal_string_to_utf16_copy ((MonoString*)o);
- break;
case MONO_NATIVE_LPSTR:
- return mono_string_to_lpstr ((MonoString*)o);
- break;
+ case MONO_NATIVE_UTF8STR:
+ // Same code path, because in Mono, we treated strings as Utf8
+ return mono_string_to_utf8str ((MonoString*)o);
default:
g_warning ("marshaling conversion %d not implemented", string_encoding);
g_assert_not_reached ();
klass = t->data.klass;
- if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
+ if (mono_class_is_auto_layout (klass))
break;
- if (klass->valuetype && (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
- klass->blittable || klass->enumtype))
+ if (klass->valuetype && (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype))
return mono_object_unbox (o);
- res = mono_marshal_alloc (mono_class_native_size (klass, NULL));
+ res = mono_marshal_alloc (mono_class_native_size (klass, NULL), &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ }
if (!((param_attrs & PARAM_ATTRIBUTE_OUT) && !(param_attrs & PARAM_ATTRIBUTE_IN))) {
method = mono_marshal_get_struct_to_ptr (o->vtable->klass);
pa [1] = &res;
pa [2] = &delete_old;
- mono_runtime_invoke (method, NULL, pa, NULL);
+ mono_runtime_invoke_checked (method, NULL, pa, &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ }
}
return res;
default:
break;
}
- mono_raise_exception (mono_get_exception_argument ("", "No PInvoke conversion exists for value passed to Object-typed parameter."));
+ mono_set_pending_exception (mono_get_exception_argument ("", "No PInvoke conversion exists for value passed to Object-typed parameter."));
return NULL;
}
+/* This is a JIT icall, it sets the pending exception */
void
mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_encoding, int param_attrs)
{
+ MonoError error;
MonoType *t;
MonoClass *klass;
switch (string_encoding) {
case MONO_NATIVE_LPWSTR:
case MONO_NATIVE_LPSTR:
+ case MONO_NATIVE_UTF8STR:
mono_marshal_free (ptr);
break;
default:
case MONO_TYPE_VALUETYPE: {
klass = t->data.klass;
- if (klass->valuetype && (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
- klass->blittable || klass->enumtype))
+ if (klass->valuetype && (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype))
break;
if (param_attrs & PARAM_ATTRIBUTE_OUT) {
pa [0] = &ptr;
pa [1] = o;
- mono_runtime_invoke (method, NULL, pa, NULL);
+ mono_runtime_invoke_checked (method, NULL, pa, &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return;
+ }
}
if (!((param_attrs & PARAM_ATTRIBUTE_OUT) && !(param_attrs & PARAM_ATTRIBUTE_IN))) {
GHashTable *cache;
MonoMethod *res;
int i, param_count, sig_size, pos_leave;
- int coop_gc_var, coop_gc_dummy_local;
g_assert (method);
+ // FIXME: we need to store the exception into a MonoHandle
+ g_assert (!mono_threads_is_coop_enabled ());
+
klass = method->klass;
image = method->klass->image;
if (!MONO_TYPE_IS_VOID (sig->ret))
mono_mb_add_local (mb, sig->ret);
- if (mono_threads_is_coop_enabled ()) {
- /* local 4, the local to be used when calling the reset_blocking funcs */
- /* tons of code hardcode 3 to be the return var */
- coop_gc_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
- /* local 5, the local used to get a stack address for suspend funcs */
- coop_gc_dummy_local = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
- }
-
/* clear exception arg */
mono_mb_emit_ldarg (mb, param_count - 1);
mono_mb_emit_byte (mb, CEE_LDNULL);
mono_mb_emit_byte (mb, CEE_STIND_REF);
- if (mono_threads_is_coop_enabled ()) {
- /* FIXME this is technically wrong as the callback itself must be executed in gc unsafe context. */
- mono_mb_emit_ldloc_addr (mb, coop_gc_dummy_local);
- mono_mb_emit_icall (mb, mono_threads_reset_blocking_start);
- mono_mb_emit_stloc (mb, coop_gc_var);
- }
-
/* try */
clause = (MonoExceptionClause *)mono_image_alloc0 (image, sizeof (MonoExceptionClause));
clause->try_offset = mono_mb_get_label (mb);
mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type (sig->ret));
}
- if (mono_threads_is_coop_enabled ()) {
- /* XXX merge reset_blocking_end with detach */
- mono_mb_emit_ldloc (mb, coop_gc_var);
- mono_mb_emit_ldloc_addr (mb, coop_gc_dummy_local);
- mono_mb_emit_icall (mb, mono_threads_reset_blocking_end);
- }
-
mono_mb_emit_byte (mb, CEE_RET);
#endif
if (marshal_mutex_initialized)
mono_marshal_unlock ();
}
+
+static void
+mono_marshal_ftnptr_eh_callback (guint32 gchandle)
+{
+ g_assert (ftnptr_eh_callback);
+ ftnptr_eh_callback (gchandle);
+}
+
+static void
+ftnptr_eh_callback_default (guint32 gchandle)
+{
+ MonoException *exc;
+ gpointer stackdata;
+
+ mono_threads_enter_gc_unsafe_region_unbalanced (&stackdata);
+
+ exc = (MonoException*) mono_gchandle_get_target (gchandle);
+
+ mono_gchandle_free (gchandle);
+
+ mono_raise_exception (exc);
+}
+
+/*
+ * mono_install_ftnptr_eh_callback:
+ *
+ * Install a callback that should be called when there is a managed exception
+ * in a native-to-managed wrapper. This is mainly used by iOS to convert a
+ * managed exception to a native exception, to properly unwind the native
+ * stack; this native exception will then be converted back to a managed
+ * exception in their managed-to-native wrapper.
+ */
+void
+mono_install_ftnptr_eh_callback (MonoFtnPtrEHCallback callback)
+{
+ ftnptr_eh_callback = callback;
+}
+
+static MonoThreadInfo*
+mono_icall_start (HandleStackMark *stackmark, MonoError *error)
+{
+ MonoThreadInfo *info = mono_thread_info_current ();
+
+ mono_stack_mark_init (info, stackmark);
+ mono_error_init (error);
+ return info;
+}
+
+static void
+mono_icall_end (MonoThreadInfo *info, HandleStackMark *stackmark, MonoError *error)
+{
+ mono_stack_mark_pop (info, stackmark);
+ mono_error_set_pending_exception (error);
+}
* 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, max_interface_id, extra_interface_vtsize = 0;
+ int i, j, vtsize, extra_interface_vtsize = 0;
+ guint32 max_interface_id;
MonoClass *k;
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
+
* (C) 2002 Ximian, Inc.
* Copyright 2003-2010 Novell, Inc (http://www.novell.com)
* Copyright 2011 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>
#include <mono/metadata/security-core-clr.h>
#include <mono/metadata/profiler-private.h>
#include <mono/metadata/profiler.h>
+#include <mono/metadata/monitor.h>
#include <mono/metadata/debug-mono-symfile.h>
#include <mono/utils/mono-compiler.h>
#include <mono/utils/mono-memory-model.h>
+#include <mono/utils/mono-error-internals.h>
#include <mono/metadata/mono-basic-block.h>
+#include <mono/metadata/reflection-internals.h>
+#include <mono/utils/mono-threads-coop.h>
#include "trace.h"
if (cfg->exception_type != MONO_EXCEPTION_NONE) \
goto exception_exit; \
} while (0)
-#define METHOD_ACCESS_FAILURE(method, cmethod) do { \
- method_access_failure ((cfg), (method), (cmethod)); \
- goto exception_exit; \
- } while (0)
#define FIELD_ACCESS_FAILURE(method, field) do { \
field_access_failure ((cfg), (method), (field)); \
goto exception_exit; \
} \
} while (0)
#define OUT_OF_MEMORY_FAILURE do { \
- mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY); \
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR); \
+ mono_error_set_out_of_memory (&cfg->error, ""); \
goto exception_exit; \
} while (0)
#define DISABLE_AOT(cfg) do { \
/* helper methods signatures */
static MonoMethodSignature *helper_sig_domain_get;
static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
-static MonoMethodSignature *helper_sig_llvmonly_imt_thunk;
+static MonoMethodSignature *helper_sig_llvmonly_imt_trampoline;
+
+/* type loading helpers */
+static GENERATE_GET_CLASS_WITH_CACHE (runtime_helpers, System.Runtime.CompilerServices, RuntimeHelpers)
+static GENERATE_TRY_GET_CLASS_WITH_CACHE (debuggable_attribute, System.Diagnostics, DebuggableAttribute)
/*
* Instruction metadata
{
helper_sig_domain_get = mono_create_icall_signature ("ptr");
helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
- helper_sig_llvmonly_imt_thunk = mono_create_icall_signature ("ptr ptr ptr");
+ helper_sig_llvmonly_imt_trampoline = mono_create_icall_signature ("ptr ptr ptr");
}
static MONO_NEVER_INLINE void
G_BREAKPOINT ();
}
-static MONO_NEVER_INLINE void
-method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
-{
- char *method_fname = mono_method_full_name (method, TRUE);
- char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
- mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS);
- cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
- g_free (method_fname);
- g_free (cil_method_fname);
-}
-
static MONO_NEVER_INLINE void
field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
{
char *method_fname = mono_method_full_name (method, TRUE);
char *field_fname = mono_field_full_name (field);
- mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS);
- cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
+ mono_error_set_generic_error (&cfg->error, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
g_free (method_fname);
g_free (field_fname);
}
return -1;
}
+static gboolean
+ip_in_finally_clause (MonoCompile *cfg, int offset)
+{
+ MonoMethodHeader *header = cfg->header;
+ MonoExceptionClause *clause;
+ int i;
+
+ for (i = 0; i < header->num_clauses; ++i) {
+ clause = &header->clauses [i];
+ if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FAULT)
+ continue;
+
+ if (MONO_OFFSET_IN_HANDLER (clause, offset))
+ return TRUE;
+ }
+ return FALSE;
+}
+
static GList*
mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
{
} else {
MonoJumpInfo ji;
gpointer target;
+ MonoError error;
ji.type = patch_type;
ji.data.target = data;
- target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE);
+ target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE, &error);
+ mono_error_assert_ok (&error);
EMIT_NEW_PCONST (cfg, ins, target);
}
{
int max_iid_reg = alloc_preg (cfg);
- MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
}
{
int max_iid_reg = alloc_preg (cfg);
- MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
}
mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
} else if (klass->cast_class == mono_defaults.enum_class) {
mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
- } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
+ } else if (mono_class_is_interface (klass->cast_class)) {
mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
} else {
// Pass -1 as obj_reg to skip the check below for arrays of arrays
return -1;
}
+//XXX this ignores if t is byref
+#define MONO_TYPE_IS_PRIMITIVE_SCALAR(t) ((((((t)->type >= MONO_TYPE_BOOLEAN && (t)->type <= MONO_TYPE_U8) || ((t)->type >= MONO_TYPE_I && (t)->type <= MONO_TYPE_U)))))
+
/*
* target_type_is_incompatible:
* @cfg: MonoCompile context
if (target->byref) {
/* FIXME: check that the pointed to types match */
if (arg->type == STACK_MP) {
- MonoClass *base_class = mono_class_from_mono_type (target);
- /* This is needed to handle gshared types + ldaddr */
- simple_type = mini_get_underlying_type (&base_class->byval_arg);
- return target->type != MONO_TYPE_I && arg->klass != base_class && arg->klass != mono_class_from_mono_type (simple_type);
+ /* This is needed to handle gshared types + ldaddr. We lower the types so we can handle enums and other typedef-like types. */
+ MonoClass *target_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&mono_class_from_mono_type (target)->byval_arg));
+ MonoClass *source_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg));
+
+ /* if the target is native int& or same type */
+ if (target->type == MONO_TYPE_I || target_class_lowered == source_class_lowered)
+ return 0;
+
+ /* Both are primitive type byrefs and the source points to a larger type that the destination */
+ if (MONO_TYPE_IS_PRIMITIVE_SCALAR (&target_class_lowered->byval_arg) && MONO_TYPE_IS_PRIMITIVE_SCALAR (&source_class_lowered->byval_arg) &&
+ mono_class_instance_size (target_class_lowered) <= mono_class_instance_size (source_class_lowered))
+ return 0;
+ return 1;
}
if (arg->type == STACK_PTR)
return 0;
gboolean pass_mrgctx = FALSE;
if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
- (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
+ (mono_class_is_ginst (cmethod->klass) || mono_class_is_gtd (cmethod->klass))) {
gboolean sharable = FALSE;
if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
if (!sig)
sig = mono_method_signature (method);
- if (cfg->llvm_only && (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
+ if (cfg->llvm_only && (mono_class_is_interface (method->klass)))
g_assert_not_reached ();
if (rgctx_arg) {
if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL))
return emit_llvmonly_virtual_call (cfg, method, sig, 0, args);
- need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
+ need_unbox_trampoline = method->klass == mono_defaults.object_class || mono_class_is_interface (method->klass);
call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
} else {
vtable_reg = alloc_preg (cfg);
MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
- if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+ if (mono_class_is_interface (method->klass)) {
guint32 imt_slot = mono_method_get_imt_slot (method);
emit_imt_argument (cfg, call, call->method, imt_arg);
slot_reg = vtable_reg;
{
/* LLVM on amd64 can't handle calls to non-32 bit addresses */
#ifdef TARGET_AMD64
- if (cfg->compile_llvm)
+ if (cfg->compile_llvm && !cfg->llvm_only)
return FALSE;
#endif
if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
}
MonoInst*
-mono_emit_jit_icall_by_info (MonoCompile *cfg, MonoJitICallInfo *info, MonoInst **args)
+mono_emit_jit_icall_by_info (MonoCompile *cfg, int il_offset, MonoJitICallInfo *info, MonoInst **args)
{
/*
* Call the jit icall without a wrapper if possible.
* an exception check.
*/
costs = inline_method (cfg, info->wrapper_method, NULL,
- args, NULL, cfg->real_offset, TRUE);
+ args, NULL, il_offset, TRUE);
g_assert (costs > 0);
g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
return ins;
}
+
+static void
+emit_method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
+{
+ MonoInst *args [16];
+
+ args [0] = emit_get_rgctx_method (cfg, mono_method_check_context_used (method), method, MONO_RGCTX_INFO_METHOD);
+ args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cil_method), cil_method, MONO_RGCTX_INFO_METHOD);
+
+ mono_emit_jit_icall (cfg, mono_throw_method_access, args);
+}
+
static MonoMethod*
get_memcpy_method (void)
{
RGCTX. */
addr = emit_get_rgctx_method (cfg, context_used, method,
MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
- if (cfg->llvm_only && cfg->gsharedvt) {
+ if (cfg->llvm_only) {
+ cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, mono_method_signature (method));
return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
} else {
rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
if (cfg->opt & MONO_OPT_SHARED) {
EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
iargs [1] = data;
- alloc_ftn = mono_object_new;
+ alloc_ftn = ves_icall_object_new;
} else {
iargs [0] = data;
- alloc_ftn = mono_object_new_specific;
+ alloc_ftn = ves_icall_object_new_specific;
}
if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
if (size < sizeof (MonoObject))
g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
- EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
+ EMIT_NEW_ICONST (cfg, iargs [1], size);
}
return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
}
EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
- alloc_ftn = mono_object_new;
- } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
+ alloc_ftn = ves_icall_object_new;
+ } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !mono_class_is_ginst (klass)) {
/* This happens often in argument checking code, eg. throw new FooException... */
/* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
- EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
+ EMIT_NEW_ICONST (cfg, iargs [1], size);
return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
}
alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
MonoGenericContainer *container;
MonoGenericInst *ginst;
- if (klass->generic_class) {
- container = klass->generic_class->container_class->generic_container;
- ginst = klass->generic_class->context.class_inst;
- } else if (klass->generic_container && context_used) {
- container = klass->generic_container;
+ if (mono_class_is_ginst (klass)) {
+ container = mono_class_get_generic_container (mono_class_get_generic_class (klass)->container_class);
+ ginst = mono_class_get_generic_class (klass)->context.class_inst;
+ } else if (mono_class_is_gtd (klass) && context_used) {
+ container = mono_class_get_generic_container (klass);
ginst = container->context.class_inst;
} else {
return FALSE;
return FALSE;
}
-#define is_complex_isinst(klass) ((klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
+static gboolean
+method_needs_stack_walk (MonoCompile *cfg, MonoMethod *cmethod)
+{
+ if (cmethod->klass == mono_defaults.systemtype_class) {
+ if (!strcmp (cmethod->name, "GetType"))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#define is_complex_isinst(klass) (mono_class_is_interface (klass) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || mono_class_is_sealed (klass) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
+
+static MonoInst*
+emit_isinst_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
+{
+ MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
+ return mono_emit_method_call (cfg, mono_isinst, args, NULL);
+}
static MonoInst*
emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
{
- MonoMethod *mono_castclass;
+ MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
MonoInst *res;
- mono_castclass = mono_marshal_get_castclass_with_cache ();
-
save_cast_details (cfg, klass, args [0]->dreg, TRUE);
res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
reset_cast_details (cfg);
return (cfg->method_index << 16) | cfg->castclass_cache_index;
}
+
+static MonoInst*
+emit_isinst_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
+{
+ MonoInst *args [3];
+ int idx;
+
+ args [0] = obj; /* obj */
+ EMIT_NEW_CLASSCONST (cfg, args [1], klass); /* klass */
+
+ idx = get_castclass_cache_idx (cfg); /* inline cache*/
+ args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
+
+ return emit_isinst_with_cache (cfg, klass, args);
+}
+
static MonoInst*
emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
{
* Returns NULL and set the cfg exception on error.
*/
static MonoInst*
-handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, int *inline_costs)
+handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
{
MonoBasicBlock *is_null_bb;
int obj_reg = src->dreg;
int vtable_reg = alloc_preg (cfg);
- int context_used;
- MonoInst *klass_inst = NULL, *res;
-
- context_used = mini_class_check_context_used (cfg, klass);
-
- if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
- res = emit_castclass_with_cache_nonshared (cfg, src, klass);
- (*inline_costs) += 2;
- return res;
- } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
- MonoMethod *mono_castclass;
- MonoInst *iargs [1];
- int costs;
-
- mono_castclass = mono_marshal_get_castclass (klass);
- iargs [0] = src;
-
- save_cast_details (cfg, klass, src->dreg, TRUE);
- costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass),
- iargs, ip, cfg->real_offset, TRUE);
- reset_cast_details (cfg);
- CHECK_CFG_EXCEPTION;
- g_assert (costs > 0);
-
- cfg->real_offset += 5;
-
- (*inline_costs) += costs;
+ MonoInst *klass_inst = NULL;
+ if (MONO_INS_IS_PCONST_NULL (src))
return src;
- }
if (context_used) {
MonoInst *args [3];
- if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
+ if (mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
MonoInst *cache_ins;
cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
save_cast_details (cfg, klass, obj_reg, FALSE);
- if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+ if (mono_class_is_interface (klass)) {
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
} else {
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
- if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
+ if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) {
/* the remoting code is broken, access the class for now */
if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
reset_cast_details (cfg);
return src;
-
-exception_exit:
- return NULL;
}
/*
MonoInst *args [3];
if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
- MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
- MonoInst *cache_ins;
+ MonoInst *cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
- cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
-
- /* obj */
- args [0] = src;
+ args [0] = src; /* obj */
/* klass - it's the second element of the cache entry*/
EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
- /* cache */
- args [2] = cache_ins;
-
- return mono_emit_method_call (cfg, mono_isinst, args, NULL);
+ args [2] = cache_ins; /* cache */
+ return emit_isinst_with_cache (cfg, klass, args);
}
klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
- if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+ if (mono_class_is_interface (klass)) {
g_assert (!context_used);
/* the is_null_bb target simply copies the input register to the output */
mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
} else if (klass->cast_class == mono_defaults.enum_class) {
mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
- } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
+ } else if (mono_class_is_interface (klass->cast_class)) {
mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
} else {
if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
/* the is_null_bb target simply copies the input register to the output */
mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
} else {
- if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
+ if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) {
g_assert (!context_used);
/* the remoting code is broken, access the class for now */
if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
- if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+ if (mono_class_is_interface (klass)) {
#ifndef DISABLE_REMOTING
NEW_BBLOCK (cfg, interface_fail_bb);
#endif
save_cast_details (cfg, klass, obj_reg, FALSE);
- if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+ if (mono_class_is_interface (klass)) {
#ifndef DISABLE_REMOTING
NEW_BBLOCK (cfg, interface_fail_bb);
if (!obj)
return NULL;
- if (cfg->llvm_only) {
- MonoInst *args [16];
-
- /*
- * If the method to be called needs an rgctx, we can't fall back to mono_delegate_ctor (), since it might receive
- * the address of a gshared method. So use a JIT icall.
- * FIXME: Optimize this.
- */
- args [0] = obj;
- args [1] = target;
- args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
- mono_emit_jit_icall (cfg, virtual_ ? mono_init_delegate_virtual : mono_init_delegate, args);
-
- return obj;
- }
-
/* Inline the contents of mono_delegate_ctor */
/* Set target field */
/* Optimize away setting of NULL target */
- if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
+ if (!MONO_INS_IS_PCONST_NULL (target)) {
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
if (cfg->gen_write_barriers) {
dreg = alloc_preg (cfg);
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);
}
+ if (cfg->llvm_only) {
+ MonoInst *args [16];
+
+ if (virtual_) {
+ args [0] = obj;
+ args [1] = target;
+ args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
+ mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate_virtual, args);
+ } else {
+ args [0] = obj;
+ mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate, args);
+ }
+
+ return obj;
+ }
+
if (cfg->compile_aot) {
MonoDelegateClassMethodPair *del_tramp;
cfg->flags |= MONO_CFG_HAS_VARARGS;
/* mono_array_new_va () needs a vararg calling convention */
+ cfg->exception_message = g_strdup ("array-new");
cfg->disable_llvm = TRUE;
/* FIXME: This uses info->sig, but it should use the signature of the wrapper */
* This is hard to do with the current call code, since we would have to emit a branch and two different calls. So instead, we
* pack the arguments into an array, and do the rest of the work in in an icall.
*/
- if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
+ if (((cmethod->klass == mono_defaults.object_class) || mono_class_is_interface (cmethod->klass) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
(MONO_TYPE_IS_VOID (fsig->ret) || MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_IS_REFERENCE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret) || mini_is_gsharedvt_type (fsig->ret)) &&
(fsig->param_count == 0 || (!fsig->hasthis && fsig->param_count == 1) || (fsig->param_count == 1 && (MONO_TYPE_IS_REFERENCE (fsig->params [0]) || fsig->params [0]->byref || mini_is_gsharedvt_type (fsig->params [0]))))) {
MonoInst *args [16];
vtable = mono_class_vtable (cfg->domain, method->klass);
if (!vtable)
return FALSE;
- if (!cfg->compile_aot)
- mono_runtime_class_init (vtable);
- } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
+ if (!cfg->compile_aot) {
+ MonoError error;
+ if (!mono_runtime_class_init_full (vtable, &error)) {
+ mono_error_cleanup (&error);
+ return FALSE;
+ }
+ }
+ } else if (mono_class_is_before_field_init (method->klass)) {
if (cfg->run_cctors && method->klass->has_cctor) {
/*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
if (!method->klass->runtime_info)
/* running with a specific order... */
if (! vtable->initialized)
return FALSE;
- mono_runtime_class_init (vtable);
+ MonoError error;
+ if (!mono_runtime_class_init_full (vtable, &error)) {
+ mono_error_cleanup (&error);
+ return FALSE;
+ }
}
} else if (mono_class_needs_cctor_run (method->klass, NULL)) {
if (!method->klass->runtime_info)
* the cctor will need to be run at aot method load time, for example,
* or at the end of the compilation of the inlining method.
*/
- if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
+ if (mono_class_needs_cctor_run (method->klass, NULL) && !mono_class_is_before_field_init (method->klass))
return FALSE;
}
return FALSE;
}
- if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
+ if (mono_class_is_before_field_init (klass)) {
if (cfg->method == method)
return FALSE;
}
if (is_set) {
EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
- if (mini_type_is_reference (fsig->params [2]))
+ if (mini_type_is_reference (&eklass->byval_arg))
emit_write_barrier (cfg, addr, load);
} else {
EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
{
if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
- !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
+ !(MONO_INS_IS_PCONST_NULL (sp [2]))) {
MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
MonoInst *iargs [3];
if (opcode && fsig->param_count == 1) {
MONO_INST_NEW (cfg, ins, opcode);
ins->type = STACK_R8;
- ins->dreg = mono_alloc_freg (cfg);
+ ins->dreg = mono_alloc_dreg (cfg, ins->type);
ins->sreg1 = args [0]->dreg;
MONO_ADD_INS (cfg->cbb, ins);
}
if (opcode && fsig->param_count == 2) {
MONO_INST_NEW (cfg, ins, opcode);
ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
- ins->dreg = mono_alloc_ireg (cfg);
+ ins->dreg = mono_alloc_dreg (cfg, ins->type);
ins->sreg1 = args [0]->dreg;
ins->sreg2 = args [1]->dreg;
MONO_ADD_INS (cfg->cbb, ins);
{
MonoInst *ins = NULL;
- static MonoClass *runtime_helpers_class = NULL;
- if (! runtime_helpers_class)
- runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
- "System.Runtime.CompilerServices", "RuntimeHelpers");
+ MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
if (cmethod->klass == mono_defaults.string_class) {
if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
} else
return NULL;
} else if (cmethod->klass == mono_defaults.object_class) {
-
if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
int dreg = alloc_ireg_ref (cfg);
int vt_reg = alloc_preg (cfg);
} else
return NULL;
} else if (cmethod->klass == runtime_helpers_class) {
-
if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
return ins;
} else
return NULL;
+ } else if (cmethod->klass == mono_defaults.monitor_class) {
+ gboolean is_enter = FALSE;
+ gboolean is_v4 = FALSE;
+
+ if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 2 && fsig->params [1]->byref) {
+ is_enter = TRUE;
+ is_v4 = TRUE;
+ }
+ if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 1)
+ is_enter = TRUE;
+
+ if (is_enter) {
+ /*
+ * To make async stack traces work, icalls which can block should have a wrapper.
+ * For Monitor.Enter, emit two calls: a fastpath which doesn't have a wrapper, and a slowpath, which does.
+ */
+ MonoBasicBlock *end_bb;
+
+ NEW_BBLOCK (cfg, end_bb);
+
+ ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_fast : (gpointer)mono_monitor_enter_fast, args);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, ins->dreg, 0);
+ MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, end_bb);
+ ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4 : (gpointer)mono_monitor_enter, args);
+ MONO_START_BB (cfg, end_bb);
+ return ins;
+ }
} else if (cmethod->klass == mono_defaults.thread_class) {
if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
if (opcode == OP_LOADI8_MEMBASE)
ins = mono_decompose_opcode (cfg, ins);
- emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
+ emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
return ins;
}
opcode = OP_STORE_MEMBASE_REG;
if (opcode) {
- emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
+ emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
MONO_INST_NEW (cfg, ins, opcode);
ins->sreg1 = args [1]->dreg;
if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
guint32 opcode = 0;
- gboolean is_ref = mini_type_is_reference (fsig->params [0]);
- gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
-
- if (fsig->params [0]->type == MONO_TYPE_I1)
+ MonoType *t = fsig->params [0];
+ gboolean is_ref;
+ gboolean is_float = t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8;
+
+ g_assert (t->byref);
+ /* t is a byref type, so the reference check is more complicated */
+ is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
+ if (t->type == MONO_TYPE_I1)
opcode = OP_ATOMIC_LOAD_I1;
- else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
+ else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
opcode = OP_ATOMIC_LOAD_U1;
- else if (fsig->params [0]->type == MONO_TYPE_I2)
+ else if (t->type == MONO_TYPE_I2)
opcode = OP_ATOMIC_LOAD_I2;
- else if (fsig->params [0]->type == MONO_TYPE_U2)
+ else if (t->type == MONO_TYPE_U2)
opcode = OP_ATOMIC_LOAD_U2;
- else if (fsig->params [0]->type == MONO_TYPE_I4)
+ else if (t->type == MONO_TYPE_I4)
opcode = OP_ATOMIC_LOAD_I4;
- else if (fsig->params [0]->type == MONO_TYPE_U4)
+ else if (t->type == MONO_TYPE_U4)
opcode = OP_ATOMIC_LOAD_U4;
- else if (fsig->params [0]->type == MONO_TYPE_R4)
+ else if (t->type == MONO_TYPE_R4)
opcode = OP_ATOMIC_LOAD_R4;
- else if (fsig->params [0]->type == MONO_TYPE_R8)
+ else if (t->type == MONO_TYPE_R8)
opcode = OP_ATOMIC_LOAD_R8;
#if SIZEOF_REGISTER == 8
- else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
+ else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
opcode = OP_ATOMIC_LOAD_I8;
- else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
+ else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
opcode = OP_ATOMIC_LOAD_U8;
#else
- else if (fsig->params [0]->type == MONO_TYPE_I)
+ else if (t->type == MONO_TYPE_I)
opcode = OP_ATOMIC_LOAD_I4;
- else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
+ else if (is_ref || t->type == MONO_TYPE_U)
opcode = OP_ATOMIC_LOAD_U4;
#endif
ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
MONO_ADD_INS (cfg->cbb, ins);
- switch (fsig->params [0]->type) {
+ switch (t->type) {
case MONO_TYPE_BOOLEAN:
case MONO_TYPE_I1:
case MONO_TYPE_U1:
ins->type = STACK_R8;
break;
default:
- g_assert (mini_type_is_reference (fsig->params [0]));
+ g_assert (is_ref);
ins->type = STACK_OBJ;
break;
}
if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
guint32 opcode = 0;
- gboolean is_ref = mini_type_is_reference (fsig->params [0]);
+ MonoType *t = fsig->params [0];
+ gboolean is_ref;
- if (fsig->params [0]->type == MONO_TYPE_I1)
+ g_assert (t->byref);
+ is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
+ if (t->type == MONO_TYPE_I1)
opcode = OP_ATOMIC_STORE_I1;
- else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
+ else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
opcode = OP_ATOMIC_STORE_U1;
- else if (fsig->params [0]->type == MONO_TYPE_I2)
+ else if (t->type == MONO_TYPE_I2)
opcode = OP_ATOMIC_STORE_I2;
- else if (fsig->params [0]->type == MONO_TYPE_U2)
+ else if (t->type == MONO_TYPE_U2)
opcode = OP_ATOMIC_STORE_U2;
- else if (fsig->params [0]->type == MONO_TYPE_I4)
+ else if (t->type == MONO_TYPE_I4)
opcode = OP_ATOMIC_STORE_I4;
- else if (fsig->params [0]->type == MONO_TYPE_U4)
+ else if (t->type == MONO_TYPE_U4)
opcode = OP_ATOMIC_STORE_U4;
- else if (fsig->params [0]->type == MONO_TYPE_R4)
+ else if (t->type == MONO_TYPE_R4)
opcode = OP_ATOMIC_STORE_R4;
- else if (fsig->params [0]->type == MONO_TYPE_R8)
+ else if (t->type == MONO_TYPE_R8)
opcode = OP_ATOMIC_STORE_R8;
#if SIZEOF_REGISTER == 8
- else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
+ else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
opcode = OP_ATOMIC_STORE_I8;
- else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
+ else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
opcode = OP_ATOMIC_STORE_U8;
#else
- else if (fsig->params [0]->type == MONO_TYPE_I)
+ else if (t->type == MONO_TYPE_I)
opcode = OP_ATOMIC_STORE_I4;
- else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
+ else if (is_ref || t->type == MONO_TYPE_U)
opcode = OP_ATOMIC_STORE_U4;
#endif
(strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
(strcmp (cmethod->klass->name, "Assembly") == 0)) {
if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
- /* No stack walks are current available, so implement this as an intrinsic */
+ /* No stack walks are currently available, so implement this as an intrinsic */
MonoInst *assembly_ins;
EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
return ins;
}
+ } else if (cmethod->klass->image == mono_defaults.corlib &&
+ (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
+ (strcmp (cmethod->klass->name, "MethodBase") == 0)) {
+ if (cfg->llvm_only && !strcmp (cmethod->name, "GetCurrentMethod")) {
+ /* No stack walks are currently available, so implement this as an intrinsic */
+ MonoInst *method_ins;
+ MonoMethod *declaring = cfg->method;
+
+ /* This returns the declaring generic method */
+ if (declaring->is_inflated)
+ declaring = ((MonoMethodInflated*)cfg->method)->declaring;
+ EMIT_NEW_AOTCONST (cfg, method_ins, MONO_PATCH_INFO_METHODCONST, declaring);
+ ins = mono_emit_jit_icall (cfg, mono_get_method_object, &method_ins);
+ cfg->no_inline = TRUE;
+ if (cfg->method != cfg->current_method)
+ inline_failure (cfg, "MethodBase:GetCurrentMethod ()");
+ return ins;
+ }
} else if (cmethod->klass == mono_defaults.math_class) {
/*
* There is general branchless code for Min/Max, but it does not work for
!strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
!strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
!strcmp (cmethod->klass->name, "Selector")) ||
- (!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") &&
+ ((!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") ||
+ !strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.Mac")) &&
!strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
!strcmp (cmethod->klass->name, "Selector"))
) {
- if (cfg->backend->have_objc_get_selector &&
+ if ((cfg->backend->have_objc_get_selector || cfg->compile_llvm) &&
!strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
(args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
cfg->compile_aot) {
MonoInst *pi;
MonoJumpInfoToken *ji;
- MonoString *s;
-
- cfg->disable_llvm = TRUE;
+ char *s;
if (args [0]->opcode == OP_GOT_ENTRY) {
pi = (MonoInst *)args [0]->inst_p1;
NULLIFY_INS (args [0]);
- // FIXME: Ugly
- s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
+ s = mono_ldstr_utf8 (ji->image, mono_metadata_token_index (ji->token), &cfg->error);
+ return_val_if_nok (&cfg->error, NULL);
+
MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
ins->dreg = mono_alloc_ireg (cfg);
// FIXME: Leaks
- ins->inst_p0 = mono_string_to_utf8 (s);
+ ins->inst_p0 = s;
MONO_ADD_INS (cfg->cbb, ins);
return ins;
}
/*
* inline_method:
*
- * Return the cost of inlining CMETHOD.
+ * Return the cost of inlining CMETHOD, or zero if it should not be inlined.
*/
static int
inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
- guchar *ip, guint real_offset, gboolean inline_always)
+ guchar *ip, guint real_offset, gboolean inline_always)
{
+ MonoError error;
MonoInst *ins, *rvar = NULL;
MonoMethodHeader *cheader;
MonoBasicBlock *ebblock, *sbblock;
GHashTable *prev_cbb_hash;
MonoBasicBlock **prev_cil_offset_to_bb;
MonoBasicBlock *prev_cbb;
- unsigned char* prev_cil_start;
+ const unsigned char *prev_ip;
+ unsigned char *prev_cil_start;
guint32 prev_cil_offset_to_bb_len;
MonoMethod *prev_current_method;
MonoGenericContext *prev_generic_context;
}
/* allocate local variables */
- cheader = mono_method_get_header (cmethod);
-
- if (cheader == NULL || mono_loader_get_last_error ()) {
- MonoLoaderError *error = mono_loader_get_last_error ();
-
- if (cheader)
- mono_metadata_free_mh (cheader);
- if (inline_always && error)
- mono_cfg_set_exception (cfg, error->exception_type);
-
- mono_loader_clear_error ();
+ cheader = mono_method_get_header_checked (cmethod, &error);
+ if (!cheader) {
+ if (inline_always) {
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
+ mono_error_move (&cfg->error, &error);
+ } else {
+ mono_error_cleanup (&error);
+ }
return 0;
}
prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
prev_cil_start = cfg->cil_start;
+ prev_ip = cfg->ip;
prev_cbb = cfg->cbb;
prev_current_method = cfg->current_method;
prev_generic_context = cfg->generic_context;
cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
cfg->cil_start = prev_cil_start;
+ cfg->ip = prev_ip;
cfg->locals = prev_locals;
cfg->args = prev_args;
cfg->arg_types = prev_arg_types;
if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
MonoBasicBlock *prev = ebblock->in_bb [0];
- mono_merge_basic_blocks (cfg, prev, ebblock);
- cfg->cbb = prev;
- if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
- mono_merge_basic_blocks (cfg, prev_cbb, prev);
- cfg->cbb = prev_cbb;
+
+ if (prev->next_bb == ebblock) {
+ mono_merge_basic_blocks (cfg, prev, ebblock);
+ cfg->cbb = prev;
+ if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
+ mono_merge_basic_blocks (cfg, prev_cbb, prev);
+ cfg->cbb = prev_cbb;
+ }
+ } else {
+ /* There could be a bblock after 'prev', and making 'prev' the current bb could cause problems */
+ cfg->cbb = ebblock;
}
} else {
/*
if (cfg->verbose_level > 2)
printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
cfg->exception_type = MONO_EXCEPTION_NONE;
- mono_loader_clear_error ();
/* This gets rid of the newly added bblocks */
cfg->cbb = prev_cbb;
#define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
#define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
#define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
-#define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
+#define CHECK_TYPELOAD(klass) if (!(klass) || mono_class_has_failure (klass)) TYPE_LOAD_ERROR ((klass))
/* offset from br.s -> br like opcodes */
#define BIG_BRANCH_OFFSET 13
}
static inline MonoMethod *
-mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
+mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
{
MonoMethod *method;
+ mono_error_init (error);
+
if (m->wrapper_type != MONO_WRAPPER_NONE) {
method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
if (context) {
- MonoError error;
- method = mono_class_inflate_generic_method_checked (method, context, &error);
- g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+ method = mono_class_inflate_generic_method_checked (method, context, error);
}
} else {
- method = mono_get_method_full (m->klass->image, token, klass, context);
+ method = mono_get_method_checked (m->klass->image, token, klass, context, error);
}
return method;
static inline MonoMethod *
mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
{
- MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
+ MonoError error;
+ MonoMethod *method = mini_get_method_allow_open (m, token, klass, context, cfg ? &cfg->error : &error);
- if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg))
- return NULL;
+ if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
+ mono_error_set_bad_image (&cfg->error, cfg->method->klass->image, "Method with open type while not compiling gshared");
+ method = NULL;
+ }
+
+ if (!method && !cfg)
+ mono_error_cleanup (&error); /* FIXME don't swallow the error */
return method;
}
if (method->wrapper_type != MONO_WRAPPER_NONE) {
klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
- if (context)
- klass = mono_class_inflate_generic_class (klass, context);
+ if (context) {
+ klass = mono_class_inflate_generic_class_checked (klass, context, &error);
+ mono_error_cleanup (&error); /* FIXME don't swallow the error */
+ }
} else {
klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
mono_error_cleanup (&error); /* FIXME don't swallow the error */
}
static inline MonoMethodSignature*
-mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
+mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context, MonoError *error)
{
MonoMethodSignature *fsig;
+ mono_error_init (error);
if (method->wrapper_type != MONO_WRAPPER_NONE) {
fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
} else {
- fsig = mono_metadata_parse_signature (method->klass->image, token);
+ fsig = mono_metadata_parse_signature_checked (method->klass->image, token, error);
+ return_val_if_nok (error, NULL);
}
if (context) {
- MonoError error;
- fsig = mono_inflate_generic_signature(fsig, context, &error);
- // FIXME:
- g_assert(mono_error_ok(&error));
+ fsig = mono_inflate_generic_signature(fsig, context, error);
}
return fsig;
}
static void
set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
{
+ MonoError error;
char *method_fname = mono_method_full_name (method, TRUE);
char *method_code;
- MonoMethodHeader *header = mono_method_get_header (method);
+ MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
- if (header->code_size == 0)
+ if (!header) {
+ method_code = g_strdup_printf ("could not parse method body due to %s", mono_error_get_message (&error));
+ mono_error_cleanup (&error);
+ } else if (header->code_size == 0)
method_code = g_strdup ("method body is empty.");
else
method_code = mono_disasm_code_one (NULL, method, ip, NULL);
- mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
- cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
+ mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code));
g_free (method_fname);
g_free (method_code);
cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
}
-static void
-set_exception_object (MonoCompile *cfg, MonoException *exception)
-{
- mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
- MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr, MONO_ROOT_SOURCE_JIT, "jit exception");
- cfg->exception_ptr = exception;
-}
-
static void
emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
{
MonoInst *icall_args [16];
MonoInst *call_target, *ins, *vtable_ins;
int arg_reg, this_reg, vtable_reg;
- gboolean is_iface = cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE;
+ gboolean is_iface = mono_class_is_interface (cmethod->klass);
gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
+ gboolean variant_iface = FALSE;
guint32 slot;
int offset;
this_reg = sp [0]->dreg;
+ if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
+ variant_iface = TRUE;
+
if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
/*
* The simplest case, a normal virtual call.
return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
}
- if (!fsig->generic_param_count && is_iface && !is_gsharedvt) {
+ if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt) {
/*
* A simple interface call
*
icall_args [0] = thunk_arg_ins;
icall_args [1] = emit_get_rgctx_method (cfg, context_used,
cmethod, MONO_RGCTX_INFO_METHOD);
- ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL);
+ ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
}
- if (fsig->generic_param_count && !is_gsharedvt) {
+ if ((fsig->generic_param_count || variant_iface) && !is_gsharedvt) {
/*
* This is similar to the interface case, the vtable slot points to an imt thunk which is
* dynamically extended as more instantiations are discovered.
icall_args [0] = thunk_arg_ins;
icall_args [1] = emit_get_rgctx_method (cfg, context_used,
cmethod, MONO_RGCTX_INFO_METHOD);
- ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL);
+ ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
ftndesc_ins->dreg = ftndesc_reg;
/*
* Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
static gboolean
is_jit_optimizer_disabled (MonoMethod *m)
{
+ MonoError error;
MonoAssembly *ass = m->klass->image->assembly;
MonoCustomAttrInfo* attrs;
- static MonoClass *klass;
+ MonoClass *klass;
int i;
gboolean val = FALSE;
if (ass->jit_optimizer_disabled_inited)
return ass->jit_optimizer_disabled;
- if (!klass)
- klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
+ klass = mono_class_try_get_debuggable_attribute_class ();
+
if (!klass) {
/* Linked away */
ass->jit_optimizer_disabled = FALSE;
return FALSE;
}
- attrs = mono_custom_attrs_from_assembly (ass);
+ attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
+ mono_error_cleanup (&error); /* FIXME don't swallow the error */
if (attrs) {
for (i = 0; i < attrs->num_attrs; ++i) {
MonoCustomAttrEntry *attr = &attrs->attrs [i];
/*
* mono_method_to_ir:
*
- * Translate the .net IL into linear IR.
+ * Translate the .net IL into linear IR.
+ *
+ * @start_bblock: if not NULL, the starting basic block, used during inlining.
+ * @end_bblock: if not NULL, the ending basic block, used during inlining.
+ * @return_var: if not NULL, the place where the return value is stored, used during inlining.
+ * @inline_args: if not NULL, contains the arguments to the inline call
+ * @inline_offset: if not zero, the real offset from the inline call, or zero otherwise.
+ * @is_virtual_call: whether this method is being called as a result of a call to callvirt
+ *
+ * This method is used to turn ECMA IL into Mono's internal Linear IR
+ * reprensetation. It is used both for entire methods, as well as
+ * inlining existing methods. In the former case, the @start_bblock,
+ * @end_bblock, @return_var, @inline_args are all set to NULL, and the
+ * inline_offset is set to zero.
+ *
+ * Returns: the inline cost, or -1 if there was an error processing this method.
*/
int
mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock,
dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
image = method->klass->image;
- header = mono_method_get_header (method);
+ header = mono_method_get_header_checked (method, &cfg->error);
if (!header) {
- MonoLoaderError *error;
-
- if ((error = mono_loader_get_last_error ())) {
- mono_cfg_set_exception (cfg, error->exception_type);
- } else {
- mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
- cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
- }
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
goto exception_exit;
+ } else {
+ cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
}
+
generic_container = mono_method_get_generic_container (method);
sig = mono_method_signature (method);
num_args = sig->hasthis + sig->param_count;
/* we use a separate basic block for the initialization code */
NEW_BBLOCK (cfg, init_localsbb);
- cfg->bb_init = init_localsbb;
+ if (cfg->method == method)
+ cfg->bb_init = init_localsbb;
init_localsbb->real_offset = cfg->real_offset;
start_bblock->next_bb = init_localsbb;
init_localsbb->next_bb = cfg->cbb;
skip_dead_blocks = !dont_verify;
if (skip_dead_blocks) {
- original_bb = bb = mono_basic_block_split (method, &cfg->error);
+ original_bb = bb = mono_basic_block_split (method, &cfg->error, header);
CHECK_CFG_ERROR;
g_assert (bb);
}
token = read32 (ip + 1);
/* FIXME: check the signature matches */
cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
-
- if (!cmethod || mono_loader_get_last_error ())
- LOAD_ERROR;
+ CHECK_CFG_ERROR;
if (cfg->gshared && mono_method_check_context_used (cmethod))
GENERIC_SHARING_FAILURE (CEE_JMP);
for (i = 0; i < n; ++i)
EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
+ if (mini_type_is_vtype (mini_get_underlying_type (call->signature->ret)))
+ call->vret_var = cfg->vret_addr;
+
mono_arch_emit_call (cfg, call);
cfg->param_area = MAX(cfg->param_area, call->stack_usage);
MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
CHECK_STACK (1);
--sp;
addr = *sp;
- fsig = mini_get_signature (method, token, generic_context);
+ fsig = mini_get_signature (method, token, generic_context, &cfg->error);
+ CHECK_CFG_ERROR;
if (method->dynamic && fsig->pinvoke) {
MonoInst *args [3];
info_data = addr->inst_right->inst_left;
}
- if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
+ if (info_type == MONO_PATCH_INFO_ICALL_ADDR) {
+ ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR_CALL, info_data, fsig, sp);
+ NULLIFY_INS (addr);
+ goto calli_end;
+ } else if (info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
NULLIFY_INS (addr);
goto calli_end;
ins = NULL;
cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
+ CHECK_CFG_ERROR;
+
cil_method = cmethod;
if (constrained_class) {
}
}
- if (!cmethod || mono_loader_get_last_error ())
- LOAD_ERROR;
if (!dont_verify && !cfg->skip_visibility) {
MonoMethod *target_method = cil_method;
if (method->is_inflated) {
- target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
+ target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
+ CHECK_CFG_ERROR;
}
if (!mono_method_can_access_method (method_definition, target_method) &&
!mono_method_can_access_method (method, cil_method))
- METHOD_ACCESS_FAILURE (method, cil_method);
+ emit_method_access_failure (cfg, method, cil_method);
}
if (mono_security_core_clr_enabled ())
CHECK_CFG_ERROR;
}
- if (cfg->llvm_only && !cfg->method->wrapper_type)
+ if (cfg->llvm_only && !cfg->method->wrapper_type && (!cmethod || cmethod->is_inflated))
cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
/* See code below */
n = fsig->param_count + fsig->hasthis;
- if (!cfg->gshared && cmethod->klass->generic_container)
+ if (!cfg->gshared && mono_class_is_gtd (cmethod->klass))
UNVERIFIED;
if (!cfg->gshared)
if (mini_is_gsharedvt_klass (constrained_class)) {
if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
/* The 'Own method' case below */
- } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
+ } else if (cmethod->klass->image != mono_defaults.corlib && !mono_class_is_interface (cmethod->klass) && !cmethod->klass->valuetype) {
/* 'The type parameter is instantiated as a reference type' case below. */
} else {
ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
* A simple solution would be to box always and make a normal virtual call, but that would
* be bad performance wise.
*/
- if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
+ if (mono_class_is_interface (cmethod->klass) && mono_class_is_ginst (cmethod->klass)) {
/*
* The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
*/
nonbox_call->dreg = ins->dreg;
goto call_end;
} else {
- g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
+ g_assert (mono_class_is_interface (cmethod->klass));
addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
goto call_end;
* If the callee is a shared method, then its static cctor
* might not get called after the call was patched.
*/
- if (cfg->gshared && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
+ if (cfg->gshared && cmethod->klass != method->klass && mono_class_is_ginst (cmethod->klass) && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
emit_class_init (cfg, cmethod->klass);
CHECK_TYPELOAD (cmethod->klass);
}
context_used = mini_method_check_context_used (cfg, cmethod);
- if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
+ if (context_used && mono_class_is_interface (cmethod->klass)) {
/* Generic method interface
calls are resolved via a
helper function and don't
if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
GSHAREDVT_FAILURE (*ip);
- if (cfg->backend->have_generalized_imt_thunk && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
+ if (cfg->backend->have_generalized_imt_trampoline && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
g_assert (!imt_arg);
if (!context_used)
g_assert (cmethod->is_inflated);
}
goto call_end;
}
-
+ CHECK_CFG_ERROR;
+
/* Inlining */
if ((cfg->opt & MONO_OPT_INLINE) &&
(!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
}
if (!has_vtargs) {
+ if (need_seq_point) {
+ emit_seq_point (cfg, method, ip, FALSE, TRUE);
+ need_seq_point = FALSE;
+ }
for (i = 0; i < n; ++i)
EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
MONO_INST_NEW (cfg, ins, OP_BR);
inline_costs += 10 * num_calls++;
+ /*
+ * Synchronized wrappers.
+ * Its hard to determine where to replace a method with its synchronized
+ * wrapper without causing an infinite recursion. The current solution is
+ * to add the synchronized wrapper in the trampolines, and to
+ * change the called method to a dummy wrapper, and resolve that wrapper
+ * to the real method in mono_jit_compile_method ().
+ */
+ if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
+ MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
+ if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
+ cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
+ }
+
/*
* Making generic calls out of gsharedvt methods.
* This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
* patching gshared method addresses into a gsharedvt method.
*/
- if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
+ if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || mono_class_is_ginst (cmethod->klass)) &&
!(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
- (!(cfg->llvm_only && virtual_))) {
+ (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
MonoRgctxInfoType info_type;
if (virtual_) {
- //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
+ //if (mono_class_is_interface (cmethod->klass))
//GSHAREDVT_FAILURE (*ip);
// disable for possible remoting calls
if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
cmethod, MONO_RGCTX_INFO_METHOD);
/* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
vtable_arg = NULL;
- } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
+ } else if (mono_class_is_interface (cmethod->klass) && !imt_arg) {
/* This can happen when we call a fully instantiated iface method */
imt_arg = emit_get_rgctx_method (cfg, context_used,
cmethod, MONO_RGCTX_INFO_METHOD);
if (fsig->hasthis)
MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
- addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
if (cfg->llvm_only) {
+ if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
+ addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
+ else
+ addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
// FIXME: Avoid initializing imt_arg/vtable_arg
ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
} else {
+ addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
}
goto call_end;
addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
- if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
+ if (cfg->gen_write_barriers && val->type == STACK_OBJ && !MONO_INS_IS_PCONST_NULL (val))
emit_write_barrier (cfg, addr, val);
if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
GSHAREDVT_FAILURE (*ip);
}
}
- /*
- * Synchronized wrappers.
- * Its hard to determine where to replace a method with its synchronized
- * wrapper without causing an infinite recursion. The current solution is
- * to add the synchronized wrapper in the trampolines, and to
- * change the called method to a dummy wrapper, and resolve that wrapper
- * to the real method in mono_jit_compile_method ().
- */
- if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
- MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
- if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
- cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
- }
-
/*
* Virtual calls in llvm-only mode.
*/
EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
}
+ if (cfg->llvm_only && cmethod && method_needs_stack_walk (cfg, cmethod)) {
+ /*
+ * Clang can convert these calls to tail calls which screw up the stack
+ * walk. This happens even when the -fno-optimize-sibling-calls
+ * option is passed to clang.
+ * Work around this by emitting a dummy call.
+ */
+ mono_emit_jit_icall (cfg, mono_dummy_jit_icall, NULL);
+ }
+
CHECK_CFG_EXCEPTION;
ip += 5;
MONO_ADD_INS (cfg->cbb, ins);
- if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [1]->opcode == OP_PCONST) && (sp [1]->inst_p0 == 0)))
+ if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !MONO_INS_IS_PCONST_NULL (sp [1]))
emit_write_barrier (cfg, sp [0], sp [1]);
inline_costs += 1;
/* Use the immediate opcodes if possible */
if (((sp [1]->opcode == OP_ICONST) || (sp [1]->opcode == OP_I8CONST)) && mono_arch_is_inst_imm (sp [1]->opcode == OP_ICONST ? sp [1]->inst_c0 : sp [1]->inst_l)) {
- int imm_opcode;
-
- imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
-#if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
- /* Keep emulated opcodes which are optimized away later */
- if ((ins->opcode == OP_IREM_UN || ins->opcode == OP_IDIV_UN_IMM) && (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP)) && sp [1]->opcode == OP_ICONST && mono_is_power_of_two (sp [1]->inst_c0) >= 0) {
- imm_opcode = mono_op_to_op_imm (ins->opcode);
- }
-#endif
+ int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
if (imm_opcode != -1) {
ins->opcode = imm_opcode;
if (sp [1]->opcode == OP_I8CONST) {
EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
- *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
- mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
+ *sp = mono_emit_jit_icall (cfg, ves_icall_mono_ldstr, iargs);
+ mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
+ CHECK_CFG_ERROR;
} else {
if (cfg->cbb->out_of_line) {
MonoInst *iargs [2];
else {
NEW_PCONST (cfg, ins, NULL);
ins->type = STACK_OBJ;
- ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
+ ins->inst_p0 = mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
+ CHECK_CFG_ERROR;
+
if (!ins->inst_p0)
OUT_OF_MEMORY_FAILURE;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
- if (!cmethod || mono_loader_get_last_error ())
- LOAD_ERROR;
+ CHECK_CFG_ERROR;
+
fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
CHECK_CFG_ERROR;
if (mono_security_core_clr_enabled ())
ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
- if (cfg->gshared && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
+ if (cfg->gshared && cmethod && cmethod->klass != method->klass && mono_class_is_ginst (cmethod->klass) && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
emit_class_init (cfg, cmethod->klass);
CHECK_TYPELOAD (cmethod->klass);
}
break;
}
case CEE_CASTCLASS:
- CHECK_STACK (1);
- --sp;
- CHECK_OPSIZE (5);
- token = read32 (ip + 1);
- klass = mini_get_class (method, token, generic_context);
- CHECK_TYPELOAD (klass);
- if (sp [0]->type != STACK_OBJ)
- UNVERIFIED;
-
- ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
- CHECK_CFG_EXCEPTION;
-
- *sp ++ = ins;
- ip += 5;
- break;
case CEE_ISINST: {
CHECK_STACK (1);
--sp;
CHECK_TYPELOAD (klass);
if (sp [0]->type != STACK_OBJ)
UNVERIFIED;
-
- context_used = mini_class_check_context_used (cfg, klass);
-
- if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
- MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
- MonoInst *args [3];
- int idx;
-
- /* obj */
- args [0] = *sp;
- /* klass */
- EMIT_NEW_CLASSCONST (cfg, args [1], klass);
-
- /* inline cache*/
- idx = get_castclass_cache_idx (cfg);
- args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
-
- *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
- ip += 5;
- inline_costs += 2;
- } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
- MonoMethod *mono_isinst;
- MonoInst *iargs [1];
- int costs;
-
- mono_isinst = mono_marshal_get_isinst (klass);
- iargs [0] = sp [0];
-
- costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst),
- iargs, ip, cfg->real_offset, TRUE);
- CHECK_CFG_EXCEPTION;
- g_assert (costs > 0);
-
- ip += 5;
- cfg->real_offset += 5;
+ MONO_INST_NEW (cfg, ins, *ip == CEE_ISINST ? OP_ISINST : OP_CASTCLASS);
+ ins->dreg = alloc_preg (cfg);
+ ins->sreg1 = (*sp)->dreg;
+ ins->klass = klass;
+ ins->type = STACK_OBJ;
+ MONO_ADD_INS (cfg->cbb, ins);
- *sp++= iargs [0];
+ CHECK_CFG_EXCEPTION;
+ *sp++ = ins;
+ ip += 5;
- inline_costs += costs;
- }
- else {
- ins = handle_isinst (cfg, klass, *sp, context_used);
- CHECK_CFG_EXCEPTION;
- *sp ++ = ins;
- ip += 5;
- }
+ cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
break;
}
case CEE_UNBOX_ANY: {
res = handle_unbox_gsharedvt (cfg, klass, *sp);
inline_costs += 2;
} else if (generic_class_is_reference_type (cfg, klass)) {
- res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
- CHECK_CFG_EXCEPTION;
+ if (MONO_INS_IS_PCONST_NULL (*sp)) {
+ EMIT_NEW_PCONST (cfg, res, NULL);
+ res->type = STACK_OBJ;
+ } else {
+ MONO_INST_NEW (cfg, res, OP_CASTCLASS);
+ res->dreg = alloc_preg (cfg);
+ res->sreg1 = (*sp)->dreg;
+ res->klass = klass;
+ res->type = STACK_OBJ;
+ MONO_ADD_INS (cfg->cbb, res);
+ cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
+ }
} else if (mono_class_is_nullable (klass)) {
res = handle_unbox_nullable (cfg, *sp, klass, context_used);
} else {
} else
#endif
{
- MonoInst *store;
+ MonoInst *store, *wbarrier_ptr_ins = NULL;
MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
+ if (ins_flag & MONO_INST_VOLATILE) {
+ /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
+ emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
+ }
+
if (mini_is_gsharedvt_klass (klass)) {
MonoInst *offset_ins;
EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
dreg = alloc_ireg_mp (cfg);
EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
+ wbarrier_ptr_ins = ins;
/* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
} else {
if (sp [0]->opcode != OP_LDADDR)
store->flags |= MONO_INST_FAULT;
- if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !(sp [1]->opcode == OP_PCONST && sp [1]->inst_c0 == 0)) {
- /* insert call to write barrier */
- MonoInst *ptr;
- int dreg;
+ if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !MONO_INS_IS_PCONST_NULL (sp [1])) {
+ if (mini_is_gsharedvt_klass (klass)) {
+ g_assert (wbarrier_ptr_ins);
+ emit_write_barrier (cfg, wbarrier_ptr_ins, sp [1]);
+ } else {
+ /* insert call to write barrier */
+ MonoInst *ptr;
+ int dreg;
- dreg = alloc_ireg_mp (cfg);
- EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
- emit_write_barrier (cfg, ptr, sp [1]);
- }
+ dreg = alloc_ireg_mp (cfg);
+ EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
+ emit_write_barrier (cfg, ptr, sp [1]);
+ }
+ }
store->flags |= ins_flag;
}
/* STATIC CASE */
context_used = mini_class_check_context_used (cfg, klass);
- if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
- UNVERIFIED;
+ if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL) {
+ mono_error_set_field_load (&cfg->error, field->parent, field->name, "Using static instructions with literal field");
+ CHECK_CFG_ERROR;
+ }
/* The special_static_fields field is init'd in mono_class_vtable, so it needs
* to be called here.
}
} else {
if (cfg->run_cctors) {
- MonoException *ex;
/* This makes so that inline cannot trigger */
/* .cctors: too many apps depend on them */
/* running with a specific order... */
g_assert (vtable);
if (! vtable->initialized)
INLINE_FAILURE ("class init");
- ex = mono_runtime_class_init_full (vtable, FALSE);
- if (ex) {
- set_exception_object (cfg, ex);
+ if (!mono_runtime_class_init_full (vtable, &cfg->error)) {
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
goto exception_exit;
}
}
EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
ins->flags |= ins_flag;
if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
- generic_class_is_reference_type (cfg, klass)) {
+ generic_class_is_reference_type (cfg, klass) && !MONO_INS_IS_PCONST_NULL (sp [1])) {
/* insert call to write barrier */
emit_write_barrier (cfg, sp [0], sp [1]);
}
if (managed_alloc)
ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
else
- ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
+ ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
} else {
if (cfg->opt & MONO_OPT_SHARED) {
/* Decompose now to avoid problems with references to the domainvar */
EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
iargs [2] = sp [0];
- ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
+ ins = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
} else {
/* Decompose later since it is needed by abcrem */
MonoClass *array_type = mono_array_class_get (klass, 1);
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
- } else if (cfg->compile_aot) {
+ } else {
int const_reg = alloc_preg (cfg);
int type_reg = alloc_preg (cfg);
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
- } else {
- MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
- MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
}
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
}
} else {
- EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, (MonoType *)handle));
+ MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &cfg->error);
+ CHECK_CFG_ERROR;
+ EMIT_NEW_PCONST (cfg, ins, rt);
}
ins->type = STACK_OBJ;
ins->klass = cmethod->klass;
}
case CEE_THROW:
CHECK_STACK (1);
+ if (sp [-1]->type != STACK_OBJ)
+ UNVERIFIED;
+
MONO_INST_NEW (cfg, ins, OP_THROW);
--sp;
ins->sreg1 = sp [0]->dreg;
INLINE_FAILURE ("throw");
break;
case CEE_ENDFINALLY:
+ if (!ip_in_finally_clause (cfg, ip - header->code))
+ UNVERIFIED;
/* mono_save_seq_point_info () depends on this */
if (sp != stack_start)
emit_seq_point (cfg, method, ip, FALSE, FALSE);
MONO_ADD_INS (cfg->cbb, iargs [0]);
NEW_CLASSCONST (cfg, iargs [1], klass);
MONO_ADD_INS (cfg->cbb, iargs [1]);
- *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
+ *sp++ = mono_emit_jit_icall (cfg, ves_icall_object_new, iargs);
ip += 6;
inline_costs += 10 * num_calls++;
break;
ip += 6;
break;
}
+ case CEE_MONO_ATOMIC_STORE_I4: {
+ g_assert (mono_arch_opcode_supported (OP_ATOMIC_STORE_I4));
+
+ CHECK_OPSIZE (6);
+ CHECK_STACK (2);
+ sp -= 2;
+
+ MONO_INST_NEW (cfg, ins, OP_ATOMIC_STORE_I4);
+ ins->dreg = sp [0]->dreg;
+ ins->sreg1 = sp [1]->dreg;
+ ins->backend.memory_barrier_kind = (int) read32 (ip + 2);
+ MONO_ADD_INS (cfg->cbb, ins);
+
+ ip += 6;
+ break;
+ }
case CEE_MONO_JIT_ATTACH: {
MonoInst *args [16], *domain_ins;
MonoInst *ad_ins, *jit_tls_ins;
MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
+ g_assert (!mono_threads_is_coop_enabled ());
+
cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
EMIT_NEW_PCONST (cfg, ins, NULL);
MONO_START_BB (cfg, call_bb);
}
- if (cfg->compile_aot) {
- /* AOT code is only used in the root domain */
- EMIT_NEW_PCONST (cfg, args [0], NULL);
- } else {
- EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
- }
+ /* AOT code is only used in the root domain */
+ EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
if (next_bb)
MONO_START_BB (cfg, next_bb);
+
+
ip += 2;
break;
}
ip += 2;
break;
}
+ case CEE_MONO_CALLI_EXTRA_ARG: {
+ MonoInst *addr;
+ MonoMethodSignature *fsig;
+ MonoInst *arg;
+
+ /*
+ * This is the same as CEE_CALLI, but passes an additional argument
+ * to the called method in llvmonly mode.
+ * This is only used by delegate invoke wrappers to call the
+ * actual delegate method.
+ */
+ g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
+
+ CHECK_OPSIZE (6);
+ token = read32 (ip + 2);
+
+ ins = NULL;
+
+ cmethod = NULL;
+ CHECK_STACK (1);
+ --sp;
+ addr = *sp;
+ fsig = mini_get_signature (method, token, generic_context, &cfg->error);
+ CHECK_CFG_ERROR;
+
+ if (cfg->llvm_only)
+ cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
+
+ n = fsig->param_count + fsig->hasthis + 1;
+
+ CHECK_STACK (n);
+
+ sp -= n;
+ arg = sp [n - 1];
+
+ if (cfg->llvm_only) {
+ /*
+ * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
+ * cconv. This is set by mono_init_delegate ().
+ */
+ if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
+ MonoInst *callee = addr;
+ MonoInst *call, *localloc_ins;
+ MonoBasicBlock *is_gsharedvt_bb, *end_bb;
+ int low_bit_reg = alloc_preg (cfg);
+
+ NEW_BBLOCK (cfg, is_gsharedvt_bb);
+ NEW_BBLOCK (cfg, end_bb);
+
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
+ MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
+
+ /* Normal case: callee uses a normal cconv, have to add an out wrapper */
+ addr = emit_get_rgctx_sig (cfg, context_used,
+ fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
+ /*
+ * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
+ */
+ MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
+ ins->dreg = alloc_preg (cfg);
+ ins->inst_imm = 2 * SIZEOF_VOID_P;
+ MONO_ADD_INS (cfg->cbb, ins);
+ localloc_ins = ins;
+ cfg->flags |= MONO_CFG_HAS_ALLOCA;
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
+
+ call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
+ MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
+
+ /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
+ MONO_START_BB (cfg, is_gsharedvt_bb);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
+ ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
+ ins->dreg = call->dreg;
+
+ MONO_START_BB (cfg, end_bb);
+ } else {
+ /* Caller uses a normal calling conv */
+
+ MonoInst *callee = addr;
+ MonoInst *call, *localloc_ins;
+ MonoBasicBlock *is_gsharedvt_bb, *end_bb;
+ int low_bit_reg = alloc_preg (cfg);
+
+ NEW_BBLOCK (cfg, is_gsharedvt_bb);
+ NEW_BBLOCK (cfg, end_bb);
+
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
+ MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
+
+ /* Normal case: callee uses a normal cconv, no conversion is needed */
+ call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
+ MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
+ /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
+ MONO_START_BB (cfg, is_gsharedvt_bb);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
+ NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
+ MONO_ADD_INS (cfg->cbb, addr);
+ /*
+ * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
+ */
+ MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
+ ins->dreg = alloc_preg (cfg);
+ ins->inst_imm = 2 * SIZEOF_VOID_P;
+ MONO_ADD_INS (cfg->cbb, ins);
+ localloc_ins = ins;
+ cfg->flags |= MONO_CFG_HAS_ALLOCA;
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
+
+ ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
+ ins->dreg = call->dreg;
+ MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
+
+ MONO_START_BB (cfg, end_bb);
+ }
+ } else {
+ /* Same as CEE_CALLI */
+ if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
+ /*
+ * We pass the address to the gsharedvt trampoline in the rgctx reg
+ */
+ MonoInst *callee = addr;
+
+ addr = emit_get_rgctx_sig (cfg, context_used,
+ fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
+ ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
+ } else {
+ ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
+ }
+ }
+
+ if (!MONO_TYPE_IS_VOID (fsig->ret))
+ *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
+
+ CHECK_CFG_EXCEPTION;
+
+ ip += 6;
+ ins_flag = 0;
+ constrained_class = NULL;
+ break;
+ }
+ case CEE_MONO_LDDOMAIN:
+ CHECK_STACK_OVF (1);
+ EMIT_NEW_PCONST (cfg, ins, cfg->compile_aot ? NULL : cfg->domain);
+ ip += 2;
+ *sp++ = ins;
+ break;
+ case CEE_MONO_GET_LAST_ERROR:
+ CHECK_OPSIZE (2);
+ CHECK_STACK_OVF (1);
+
+ MONO_INST_NEW (cfg, ins, OP_GET_LAST_ERROR);
+ ins->dreg = alloc_dreg (cfg, STACK_I4);
+ ins->type = STACK_I4;
+ MONO_ADD_INS (cfg->cbb, ins);
+
+ ip += 2;
+ *sp++ = ins;
+ break;
default:
g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
break;
CHECK_OPSIZE (6);
n = read32 (ip + 2);
cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
- if (!cmethod || mono_loader_get_last_error ())
- LOAD_ERROR;
+ CHECK_CFG_ERROR;
+
mono_class_init (cmethod->klass);
mono_save_token_info (cfg, image, n, cmethod);
cil_method = cmethod;
if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
- METHOD_ACCESS_FAILURE (method, cil_method);
+ emit_method_access_failure (cfg, method, cil_method);
if (mono_security_core_clr_enabled ())
ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
CHECK_OPSIZE (6);
n = read32 (ip + 2);
cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
- if (!cmethod || mono_loader_get_last_error ())
- LOAD_ERROR;
+ CHECK_CFG_ERROR;
+
mono_class_init (cmethod->klass);
context_used = mini_method_check_context_used (cfg, cmethod);
ip += 4;
inline_costs += 1;
break;
- case CEE_LOCALLOC:
+ case CEE_LOCALLOC: {
CHECK_STACK (1);
+ MonoBasicBlock *non_zero_bb, *end_bb;
+ int alloc_ptr = alloc_preg (cfg);
--sp;
if (sp != stack_start)
UNVERIFIED;
*/
INLINE_FAILURE("localloc");
+ NEW_BBLOCK (cfg, non_zero_bb);
+ NEW_BBLOCK (cfg, end_bb);
+
+ /* if size != zero */
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
+ MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_zero_bb);
+
+ //size is zero, so result is NULL
+ MONO_EMIT_NEW_PCONST (cfg, alloc_ptr, NULL);
+ MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
+
+ MONO_START_BB (cfg, non_zero_bb);
MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
- ins->dreg = alloc_preg (cfg);
+ ins->dreg = alloc_ptr;
ins->sreg1 = sp [0]->dreg;
ins->type = STACK_PTR;
MONO_ADD_INS (cfg->cbb, ins);
if (init_locals)
ins->flags |= MONO_INST_INIT;
+ MONO_START_BB (cfg, end_bb);
+ EMIT_NEW_UNALU (cfg, ins, OP_MOVE, alloc_preg (cfg), alloc_ptr);
+ ins->type = STACK_PTR;
+
*sp++ = ins;
ip += 2;
break;
+ }
case CEE_ENDFILTER: {
MonoExceptionClause *clause, *nearest;
int cc;
if (cfg->method == method) {
MonoBasicBlock *bb;
for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
- bb->region = mono_find_block_region (cfg, bb->real_offset);
+ if (bb == cfg->bb_init)
+ bb->region = -1;
+ else
+ bb->region = mono_find_block_region (cfg, bb->real_offset);
if (cfg->spvars)
mono_create_spvar_for_region (cfg, bb->region);
if (cfg->verbose_level > 2)
printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
}
+ } else {
+ MonoBasicBlock *bb;
+ /* get_most_deep_clause () in mini-llvm.c depends on this for inlined bblocks */
+ for (bb = start_bblock; bb != end_bblock; bb = bb->next_bb) {
+ bb->real_offset = inline_offset;
+ }
}
if (inline_costs < 0) {
/* Method is too large */
mname = mono_method_full_name (method, TRUE);
- mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
- cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
+ mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
g_free (mname);
}
g_slist_free (class_inits);
mono_basic_block_free (original_bb);
cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
- cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
if (cfg->exception_type)
return -1;
else
* Make the component vregs volatile since the optimizations can
* get confused otherwise.
*/
- get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
- get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
+ get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
+ get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
}
#endif
/* Modify the two component vars too */
MonoInst *var1;
- var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
+ var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
var1->inst_c0 = pos;
- var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
+ var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
var1->inst_c0 = pos;
}
#endif
g_assert (ins->opcode == OP_REGOFFSET);
- tree = get_vreg_to_inst (cfg, ins->dreg + 1);
+ tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
g_assert (tree);
tree->opcode = OP_REGOFFSET;
tree->inst_basereg = ins->inst_basereg;
tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
- tree = get_vreg_to_inst (cfg, ins->dreg + 2);
+ tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
g_assert (tree);
tree->opcode = OP_REGOFFSET;
tree->inst_basereg = ins->inst_basereg;
#if SIZEOF_REGISTER != 8
if (regtype == 'l') {
- NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
+ NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, MONO_LVREG_LS (ins->dreg));
mono_bblock_insert_after_ins (bb, ins, store_ins);
- NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
+ NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, MONO_LVREG_MS (ins->dreg));
mono_bblock_insert_after_ins (bb, ins, store_ins);
def_ins = store_ins;
}
#if SIZEOF_REGISTER != 8
if (regtype == 'l') {
- NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
+ NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
mono_bblock_insert_before_ins (bb, ins, load_ins);
- NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
+ NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
mono_bblock_insert_before_ins (bb, ins, load_ins);
use_ins = load_ins;
}
g_free (live_range_end_bb);
}
+static void
+mono_decompose_typecheck (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
+{
+ MonoInst *ret, *move, *source;
+ MonoClass *klass = ins->klass;
+ int context_used = mini_class_check_context_used (cfg, klass);
+ int is_isinst = ins->opcode == OP_ISINST;
+ g_assert (is_isinst || ins->opcode == OP_CASTCLASS);
+ source = get_vreg_to_inst (cfg, ins->sreg1);
+ if (!source || source == (MonoInst *) -1)
+ source = mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, ins->sreg1);
+ g_assert (source && source != (MonoInst *) -1);
+
+ MonoBasicBlock *first_bb;
+ NEW_BBLOCK (cfg, first_bb);
+ cfg->cbb = first_bb;
+
+ if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
+ if (is_isinst)
+ ret = emit_isinst_with_cache_nonshared (cfg, source, klass);
+ else
+ ret = emit_castclass_with_cache_nonshared (cfg, source, klass);
+ } else if (!context_used && (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass))) {
+ MonoInst *iargs [1];
+ int costs;
+
+ iargs [0] = source;
+ if (is_isinst) {
+ MonoMethod *wrapper = mono_marshal_get_isinst (klass);
+ costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
+ } else {
+ MonoMethod *wrapper = mono_marshal_get_castclass (klass);
+ save_cast_details (cfg, klass, source->dreg, TRUE);
+ costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
+ reset_cast_details (cfg);
+ }
+ g_assert (costs > 0);
+ ret = iargs [0];
+ } else {
+ if (is_isinst)
+ ret = handle_isinst (cfg, klass, source, context_used);
+ else
+ ret = handle_castclass (cfg, klass, source, context_used);
+ }
+ EMIT_NEW_UNALU (cfg, move, OP_MOVE, ins->dreg, ret->dreg);
+
+ g_assert (cfg->cbb->code || first_bb->code);
+ MonoInst *prev = ins->prev;
+ mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
+}
+
+void
+mono_decompose_typechecks (MonoCompile *cfg)
+{
+ for (MonoBasicBlock *bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+ MonoInst *ins;
+ MONO_BB_FOR_EACH_INS (bb, ins) {
+ switch (ins->opcode) {
+ case OP_ISINST:
+ case OP_CASTCLASS:
+ mono_decompose_typecheck (cfg, bb, ins);
+ break;
+ }
+ }
+ }
+}
+
+
/**
* FIXME:
* - use 'iadd' instead of 'int_add'
+
/*
* mini-runtime.c: Runtime code for the JIT
*
* Copyright 2002-2003 Ximian, Inc.
* Copyright 2003-2010 Novell, Inc.
* Copyright 2011-2015 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>
#include <mono/metadata/mempool-internals.h>
#include <mono/metadata/attach.h>
#include <mono/metadata/runtime.h>
+#include <mono/metadata/reflection-internals.h>
+#include <mono/metadata/monitor.h>
#include <mono/utils/mono-math.h>
#include <mono/utils/mono-compiler.h>
#include <mono/utils/mono-counters.h>
#include <mono/utils/dtrace.h>
#include <mono/utils/mono-signal-handler.h>
#include <mono/utils/mono-threads.h>
+#include <mono/utils/mono-threads-coop.h>
#include <mono/utils/checked-build.h>
+#include <mono/metadata/w32handle.h>
#include <mono/io-layer/io-layer.h>
#include "mini.h"
#ifdef MONO_ARCH_LLVM_SUPPORTED
#ifdef ENABLE_LLVM
#include "mini-llvm-cpp.h"
+#include "llvm-jit.h"
#endif
#endif
get_method_from_ip (void *ip)
{
MonoJitInfo *ji;
- char *method;
+ MonoMethod *method;
+ char *method_name;
char *res;
MonoDomain *domain = mono_domain_get ();
MonoDebugSourceLocation *location;
return res;
}
- method = mono_method_full_name (jinfo_get_method (ji), TRUE);
+ method = jinfo_get_method (ji);
+ method_name = mono_method_full_name (method, TRUE);
/* FIXME: unused ? */
- location = mono_debug_lookup_source_location (jinfo_get_method (ji), (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
+ location = mono_debug_lookup_source_location (method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
- res = g_strdup_printf (" %s + 0x%x (%p %p) [%p - %s]", method, (int)((char*)ip - (char*)ji->code_start), ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
+ res = g_strdup_printf (" %s {%p} + 0x%x (%p %p) [%p - %s]", method_name, method, (int)((char*)ip - (char*)ji->code_start), ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
mono_debug_free_source_location (location);
- g_free (method);
+ g_free (method_name);
return res;
}
void *ptr;
if (mono_aot_only)
- g_error ("Attempting to allocate from the global code manager while running with --aot-only.\n");
+ g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
if (!global_codeman) {
/* This can happen during startup */
__nacl_suspend_thread_if_needed();
#endif
}
-
-/* Given the temporary buffer (allocated by mono_global_codeman_reserve) into
- * which we are generating code, return a pointer to the destination in the
- * dynamic code segment into which the code will be copied when
- * mono_global_codeman_commit is called.
- * LOCKING: Acquires the jit lock.
- */
-void*
-nacl_global_codeman_get_dest (void *data)
-{
- void *dest;
- mono_jit_lock ();
- dest = nacl_code_manager_get_code_dest (global_codeman, data);
- mono_jit_unlock ();
- return dest;
-}
-
-void
-mono_global_codeman_commit (void *data, int size, int newsize)
-{
- mono_jit_lock ();
- mono_code_manager_commit (global_codeman, data, size, newsize);
- mono_jit_unlock ();
-}
-
-/*
- * Convenience function which calls mono_global_codeman_commit to validate and
- * copy the code. The caller sets *buf_base and *buf_size to the start and size
- * of the buffer (allocated by mono_global_codeman_reserve), and *code_end to
- * the byte after the last instruction byte. On return, *buf_base will point to
- * the start of the copied in the code segment, and *code_end will point after
- * the end of the copied code.
- */
-void
-nacl_global_codeman_validate (guint8 **buf_base, int buf_size, guint8 **code_end)
-{
- guint8 *tmp = nacl_global_codeman_get_dest (*buf_base);
- mono_global_codeman_commit (*buf_base, buf_size, *code_end - *buf_base);
- *code_end = tmp + (*code_end - *buf_base);
- *buf_base = tmp;
-}
-#else
-/* no-op versions of Native Client functions */
-void*
-nacl_global_codeman_get_dest (void *data)
-{
- return data;
-}
-
-void
-mono_global_codeman_commit (void *data, int size, int newsize)
-{
-}
-
-void
-nacl_global_codeman_validate (guint8 **buf_base, int buf_size, guint8 **code_end)
-{
-}
-
#endif /* __native_client__ */
/**
gconstpointer
mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
{
+ MonoError error;
char *name;
MonoMethod *wrapper;
gconstpointer trampoline;
wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_exc);
g_free (name);
- if (do_compile)
- trampoline = mono_compile_method (wrapper);
- else
- trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper));
+ if (do_compile) {
+ trampoline = mono_compile_method_checked (wrapper, &error);
+ mono_error_assert_ok (&error);
+ } else {
+
+ trampoline = mono_create_jit_trampoline (domain, wrapper, &error);
+ mono_error_assert_ok (&error);
+ trampoline = mono_create_ftnptr (domain, (gpointer)trampoline);
+ }
mono_loader_lock ();
if (!callinfo->trampoline) {
mono_register_jit_icall_full (func, name, sig, TRUE, FALSE, name);
}
+static void
+register_icall_with_wrapper (gpointer func, const char *name, const char *sigstr)
+{
+ MonoMethodSignature *sig;
+
+ if (sigstr)
+ sig = mono_create_icall_signature (sigstr);
+ else
+ sig = NULL;
+
+ mono_register_jit_icall_full (func, name, sig, FALSE, FALSE, NULL);
+}
+
static void
register_dyn_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
{
* mono_get_lmf_addr, and mono_get_lmf_addr requires the thread to be attached.
*/
- mono_jit_thread_attach (NULL);
+ mono_thread_attach (mono_get_root_domain ());
+ mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
if ((jit_tls = mono_native_tls_get_value (mono_jit_tls_id)))
return &jit_tls->lmf;
/*
* mono_jit_thread_attach:
*
- * Called by native->managed wrappers. Returns the original domain which needs to be
- * restored, or NULL.
+ * Called by Xamarin.Mac and other products. Attach thread to runtime if
+ * needed and switch to @domain.
+ *
+ * @return the original domain which needs to be restored, or NULL.
*/
MonoDomain*
mono_jit_thread_attach (MonoDomain *domain)
{
MonoDomain *orig;
+ gboolean attached;
- if (!domain)
- /*
- * Happens when called from AOTed code which is only used in the root
- * domain.
- */
+ g_assert (!mono_threads_is_coop_enabled ());
+
+ if (!domain) {
+ /* Happens when called from AOTed code which is only used in the root domain. */
domain = mono_get_root_domain ();
+ }
+
+ g_assert (domain);
#ifdef MONO_HAVE_FAST_TLS
- if (!MONO_FAST_TLS_GET (mono_lmf_addr)) {
- mono_thread_attach (domain);
- // #678164
- mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
- }
+ attached = MONO_FAST_TLS_GET (mono_lmf_addr) != NULL;
#else
- if (!mono_native_tls_get_value (mono_jit_tls_id)) {
+ attached = mono_native_tls_get_value (mono_jit_tls_id) != NULL;
+#endif
+
+ if (!attached) {
mono_thread_attach (domain);
+
+ // #678164
mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
}
-#endif
+
orig = mono_domain_get ();
if (orig != domain)
mono_domain_set (domain, TRUE);
return orig != domain ? orig : NULL;
}
-/* Called by native->managed wrappers */
+/*
+ * mono_jit_set_domain:
+ *
+ * Set domain to @domain if @domain is not null
+ */
void
mono_jit_set_domain (MonoDomain *domain)
{
+ g_assert (!mono_threads_is_coop_enabled ());
+
if (domain)
mono_domain_set (domain, TRUE);
}
thread = mono_thread_info_current_unchecked ();
if (thread)
thread->jit_data = jit_tls;
- if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
- mono_runtime_setup_stat_profiler ();
mono_arch_cpu_init ();
}
return ji;
}
+#if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
+
+static const char* const patch_info_str[] = {
+#define PATCH_INFO(a,b) "" #a,
+#include "patch-info.h"
+#undef PATCH_INFO
+};
+
+const char*
+mono_ji_type_to_string (MonoJumpInfoType type)
+{
+ return patch_info_str [type];
+}
+
+void
+mono_print_ji (const MonoJumpInfo *ji)
+{
+ switch (ji->type) {
+ case MONO_PATCH_INFO_RGCTX_FETCH: {
+ MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry;
+
+ printf ("[RGCTX_FETCH ");
+ mono_print_ji (entry->data);
+ printf (" - %s]", mono_rgctx_info_type_to_str (entry->info_type));
+ break;
+ }
+ case MONO_PATCH_INFO_METHODCONST: {
+ char *s = mono_method_full_name (ji->data.method, TRUE);
+ printf ("[METHODCONST - %s]", s);
+ g_free (s);
+ break;
+ }
+ case MONO_PATCH_INFO_INTERNAL_METHOD: {
+ printf ("[INTERNAL_METHOD - %s]", ji->data.name);
+ break;
+ }
+ default:
+ printf ("[%s]", patch_info_str [ji->type]);
+ break;
+ }
+}
+
+#else
+
+const char*
+mono_ji_type_to_string (MonoJumpInfoType type)
+{
+ return "";
+}
+
+void
+mono_print_ji (const MonoJumpInfo *ji)
+{
+}
+
+#endif
+
/**
* mono_patch_info_dup_mp:
*
case MONO_PATCH_INFO_METHOD_JUMP:
case MONO_PATCH_INFO_IMAGE:
case MONO_PATCH_INFO_ICALL_ADDR:
+ case MONO_PATCH_INFO_ICALL_ADDR_CALL:
case MONO_PATCH_INFO_FIELD:
case MONO_PATCH_INFO_SFLDA:
case MONO_PATCH_INFO_SEQ_POINT_INFO:
case MONO_PATCH_INFO_GOT_OFFSET:
case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
case MONO_PATCH_INFO_AOT_MODULE:
+ case MONO_PATCH_INFO_GET_TLS_TRAMP:
return (ji->type << 8);
case MONO_PATCH_INFO_CASTCLASS_CACHE:
return (ji->type << 8) | (ji->data.index);
}
case MONO_PATCH_INFO_JIT_ICALL_ADDR:
return (ji->type << 8) | g_str_hash (ji->data.target);
+ case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
+ return (ji->type << 8) | mono_signature_hash (ji->data.sig);
default:
printf ("info type: %d\n", ji->type);
mono_print_ji (ji); printf ("\n");
if (ji1->data.target == ji2->data.target)
return 1;
return strcmp (ji1->data.target, ji2->data.target) == 0 ? 1 : 0;
+ case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
+ return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig) ? 1 : 0;
default:
if (ji1->data.target != ji2->data.target)
return 0;
}
gpointer
-mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors)
+mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
{
unsigned char *ip = patch_info->ip.i + code;
gconstpointer target = NULL;
+ mono_error_init (error);
+
switch (patch_info->type) {
case MONO_PATCH_INFO_BB:
/*
target = patch_info->data.inst->inst_c0 + code;
break;
case MONO_PATCH_INFO_IP:
-#if defined(__native_client__) && defined(__native_client_codegen__)
- /* Need to transform to the destination address, it's */
- /* emitted as an immediate in the code. */
- target = nacl_inverse_modify_patch_target(ip);
-#else
target = ip;
-#endif
break;
case MONO_PATCH_INFO_METHOD_REL:
target = code + patch_info->data.offset;
break;
}
case MONO_PATCH_INFO_METHOD_JUMP:
- target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE);
-#if defined(__native_client__) && defined(__native_client_codegen__)
-# if defined(TARGET_AMD64)
- /* This target is an absolute address, not relative to the */
- /* current code being emitted on AMD64. */
- target = nacl_inverse_modify_patch_target(target);
-# endif
-#endif
+ target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
+ if (!mono_error_ok (error))
+ return NULL;
break;
case MONO_PATCH_INFO_METHOD:
-#if defined(__native_client_codegen__) && defined(USE_JUMP_TABLES)
- /*
- * If we use jumptables, for recursive calls we cannot
- * avoid trampoline, as we not yet know where we will
- * be installed.
- */
- target = mono_create_jit_trampoline_in_domain (domain, patch_info->data.method);
-#else
if (patch_info->data.method == method) {
target = code;
} else {
/* get the trampoline to the method from the domain */
- target = mono_create_jit_trampoline_in_domain (domain, patch_info->data.method);
+ target = mono_create_jit_trampoline (domain, patch_info->data.method, error);
+ if (!mono_error_ok (error))
+ return NULL;
}
-#endif
break;
case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
gpointer code_slot;
#endif
for (i = 0; i < patch_info->data.table->table_size; i++) {
-#if defined(__native_client__) && defined(__native_client_codegen__)
- /* 'code' is relative to the current code blob, we */
- /* need to do this transform on it to make the */
- /* pointers in this table absolute */
- jump_table [i] = nacl_inverse_modify_patch_target (code) + GPOINTER_TO_INT (patch_info->data.table->table [i]);
-#else
jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
-#endif
}
-#if defined(__native_client__) && defined(__native_client_codegen__)
- /* jump_table is in the data section, we need to transform */
- /* it here so when it gets modified in amd64_patch it will */
- /* then point back to the absolute data address */
- target = nacl_inverse_modify_patch_target (jump_table);
-#else
target = jump_table;
-#endif
break;
}
case MONO_PATCH_INFO_METHODCONST:
break;
case MONO_PATCH_INFO_IID:
mono_class_init (patch_info->data.klass);
- target = GINT_TO_POINTER ((int)patch_info->data.klass->interface_id);
+ target = GUINT_TO_POINTER (patch_info->data.klass->interface_id);
break;
case MONO_PATCH_INFO_ADJUSTED_IID:
mono_class_init (patch_info->data.klass);
- target = GINT_TO_POINTER ((int)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
+ target = GUINT_TO_POINTER ((guint32)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
break;
case MONO_PATCH_INFO_VTABLE:
target = mono_class_vtable (domain, patch_info->data.klass);
}
g_assert (vtable);
- if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
+ if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
/* Done by the generated code */
;
else {
- if (run_cctors)
- mono_runtime_class_init (vtable);
+ if (run_cctors) {
+ if (!mono_runtime_class_init_full (vtable, error)) {
+ return NULL;
+ }
+ }
}
target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
break;
break;
case MONO_PATCH_INFO_LDSTR:
target =
- mono_ldstr (domain, patch_info->data.token->image,
- mono_metadata_token_index (patch_info->data.token->token));
+ mono_ldstr_checked (domain, patch_info->data.token->image,
+ mono_metadata_token_index (patch_info->data.token->token), error);
break;
case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
gpointer handle;
MonoClass *handle_class;
- MonoError error;
handle = mono_ldtoken_checked (patch_info->data.token->image,
- patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, &error);
- if (!mono_error_ok (&error))
- g_error ("Could not patch ldtoken due to %s", mono_error_get_message (&error));
+ patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
+ if (!mono_error_ok (error))
+ return NULL;
mono_class_init (handle_class);
mono_class_init (mono_class_from_mono_type ((MonoType *)handle));
- target =
- mono_type_get_object (domain, (MonoType *)handle);
+ target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
+ if (!mono_error_ok (error))
+ return NULL;
break;
}
case MONO_PATCH_INFO_LDTOKEN: {
gpointer handle;
MonoClass *handle_class;
- MonoError error;
handle = mono_ldtoken_checked (patch_info->data.token->image,
- patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, &error);
- if (!mono_error_ok (&error))
- g_error ("Could not patch ldtoken due to %s", mono_error_get_message (&error));
+ patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
+ if (!mono_error_ok (error))
+ g_error ("Could not patch ldtoken due to %s", mono_error_get_message (error));
mono_class_init (handle_class);
target = handle;
target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
break;
case MONO_PATCH_INFO_ICALL_ADDR:
+ case MONO_PATCH_INFO_ICALL_ADDR_CALL:
/* run_cctors == 0 -> AOT */
if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
const char *exc_class;
if (run_cctors) {
target = mono_lookup_pinvoke_call (patch_info->data.method, &exc_class, &exc_arg);
if (!target) {
- if (mono_aot_only)
- mono_raise_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
+ if (mono_aot_only) {
+ mono_error_set_exception_instance (error, mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
+ return NULL;
+ }
g_error ("Unable to resolve pinvoke method '%s' Re-run with MONO_LOG_LEVEL=debug for more information.\n", mono_method_full_name (patch_info->data.method, TRUE));
}
} else {
break;
}
+ case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
+ target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
+ break;
+ case MONO_PATCH_INFO_GET_TLS_TRAMP:
+#ifdef MONO_ARCH_HAVE_GET_TLS_TRAMP
+ target = mono_arch_get_get_tls_tramp ();
+#else
+ target = NULL;
+#endif
+ break;
default:
g_assert_not_reached ();
}
}
static gpointer
-mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException **ex)
+mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoError *error)
{
MonoDomain *target_domain, *domain = mono_domain_get ();
MonoJitInfo *info;
MonoJitICallInfo *callinfo = NULL;
WrapperInfo *winfo = NULL;
+ mono_error_init (error);
+
+ if (mono_llvm_only)
+ /* Should be handled by the caller */
+ g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
+
/*
* ICALL wrappers are handled specially, since there is only one copy of them
* shared by all appdomains.
ctx = mono_method_get_context (method);
method = info->d.synchronized_inner.method;
if (ctx) {
- MonoError error;
- method = mono_class_inflate_generic_method_checked (method, ctx, &error);
- g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+ method = mono_class_inflate_generic_method_checked (method, ctx, error);
+ g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
}
}
}
/* We can't use a domain specific method in another domain */
if (! ((domain != target_domain) && !info->domain_neutral)) {
MonoVTable *vtable;
- MonoException *tmpEx;
mono_jit_stats.methods_lookups++;
- vtable = mono_class_vtable (domain, method->klass);
+ vtable = mono_class_vtable_full (domain, method->klass, error);
+ if (!is_ok (error))
+ return NULL;
g_assert (vtable);
- tmpEx = mono_runtime_class_init_full (vtable, ex == NULL);
- if (tmpEx) {
- *ex = tmpEx;
+ if (!mono_runtime_class_init_full (vtable, error))
return NULL;
- }
return mono_create_ftnptr (target_domain, info->code_start);
}
}
mono_class_init (method->klass);
- if ((code = mono_aot_get_method (domain, method))) {
+ if ((code = mono_aot_get_method_checked (domain, method, error))) {
MonoVTable *vtable;
+ if (mono_runtime_is_critical_method (method) || mono_gc_is_critical_method (method)) {
+ /*
+ * The suspend code needs to be able to lookup these methods by ip in async context,
+ * so preload their jit info.
+ */
+ MonoJitInfo *ji = mono_jit_info_table_find (domain, code);
+ g_assert (ji);
+ }
+
/*
* In llvm-only mode, method might be a shared method, so we can't initialize its class.
* This is not a problem, since it will be initialized when the method is first
if (!mono_llvm_only) {
vtable = mono_class_vtable (domain, method->klass);
g_assert (vtable);
- mono_runtime_class_init (vtable);
+ if (!mono_runtime_class_init_full (vtable, error))
+ return NULL;
}
}
+ if (!is_ok (error))
+ return NULL;
}
#endif
- if (!code)
- code = mono_jit_compile_method_inner (method, target_domain, opt, ex);
-
if (!code && mono_llvm_only) {
if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
WrapperInfo *info = mono_marshal_get_wrapper_info (method);
return no_gsharedvt_in_wrapper;
}
}
+ }
+ if (!code)
+ code = mono_jit_compile_method_inner (method, target_domain, opt, error);
+ if (!mono_error_ok (error))
+ return NULL;
+
+ if (!code && mono_llvm_only) {
printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
g_assert_not_reached ();
}
}
gpointer
-mono_jit_compile_method (MonoMethod *method)
+mono_jit_compile_method (MonoMethod *method, MonoError *error)
{
- MonoException *ex = NULL;
gpointer code;
- code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), &ex);
- if (!code) {
- g_assert (ex);
- mono_raise_exception (ex);
- }
-
+ code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), error);
return code;
}
}
g_slist_free (remove);
}
-
mono_domain_unlock (domain);
#ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
return NULL;
}
+static guint32 bisect_opt = 0;
+static GHashTable *bisect_methods_hash = NULL;
+
+void
+mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
+{
+ FILE *file;
+ char method_name [2048];
+
+ bisect_opt = opt;
+ bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
+ g_assert (bisect_methods_hash);
+
+ file = fopen (method_list_filename, "r");
+ g_assert (file);
+
+ while (fgets (method_name, sizeof (method_name), file)) {
+ size_t len = strlen (method_name);
+ g_assert (len > 0);
+ g_assert (method_name [len - 1] == '\n');
+ method_name [len - 1] = 0;
+ g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
+ }
+ g_assert (feof (file));
+}
+
gboolean mono_do_single_method_regression = FALSE;
guint32 mono_single_method_regression_opt = 0;
MonoMethod *mono_current_single_method;
{
g_assert (method);
+ if (bisect_methods_hash) {
+ char *name = mono_method_full_name (method, TRUE);
+ void *res = g_hash_table_lookup (bisect_methods_hash, name);
+ g_free (name);
+ if (res)
+ return default_opt | bisect_opt;
+ }
if (!mono_do_single_method_regression)
return default_opt;
if (!mono_current_single_method) {
MonoVTable *vtable;
MonoDynCallInfo *dyn_call_info;
MonoClass *ret_box_class;
- gboolean needs_rgctx;
MonoMethodSignature *sig;
+ gboolean gsharedvt_invoke;
gpointer *wrapper_arg;
} RuntimeInvokeInfo;
-gboolean
-mini_gsharedvt_runtime_invoke_supported (MonoMethodSignature *sig)
-{
- gboolean supported = TRUE;
- int i;
-
- for (i = 0; i < sig->param_count; ++i) {
- MonoType *t = sig->params [i];
-
- if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
- supported = FALSE;
- }
-
- return supported;
-}
-
static RuntimeInvokeInfo*
-create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method)
+create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, MonoError *error)
{
MonoMethod *invoke;
RuntimeInvokeInfo *info;
info = g_new0 (RuntimeInvokeInfo, 1);
- info->needs_rgctx = mono_llvm_only && mono_method_needs_static_rgctx_invoke (method, TRUE);
info->compiled_method = compiled_method;
+ if (mono_llvm_only && method->string_ctor)
+ info->sig = mono_marshal_get_string_ctor_signature (method);
+ else
+ info->sig = mono_method_signature (method);
- invoke = mono_marshal_get_runtime_invoke (method, FALSE, info->needs_rgctx);
- info->vtable = mono_class_vtable_full (domain, method->klass, TRUE);
+ invoke = mono_marshal_get_runtime_invoke (method, FALSE);
+ info->vtable = mono_class_vtable_full (domain, method->klass, error);
+ if (!mono_error_ok (error))
+ return NULL;
g_assert (info->vtable);
- MonoMethodSignature *sig = mono_method_signature (method);
+ MonoMethodSignature *sig = info->sig;
MonoType *ret_type;
/*
if (method->string_ctor)
sig = mono_marshal_get_string_ctor_signature (method);
- g_assert (!info->needs_rgctx);
for (i = 0; i < sig->param_count; ++i) {
MonoType *t = sig->params [i];
if (!info->dyn_call_info) {
if (mono_llvm_only) {
- gboolean supported;
-
- supported = mini_gsharedvt_runtime_invoke_supported (sig);
-
- if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
- supported = FALSE;
-
-#ifndef ENABLE_GSHAREDVT
- supported = FALSE;
+#ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
+ g_assert_not_reached ();
#endif
-
- if (supported) {
+ info->gsharedvt_invoke = TRUE;
+ if (!callee_gsharedvt) {
/* Invoke a gsharedvt out wrapper instead */
MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
- info->wrapper_arg [0] = info->compiled_method;
- info->wrapper_arg [1] = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
+ info->wrapper_arg [0] = mini_add_method_wrappers_llvmonly (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
/* Pass has_rgctx == TRUE since the wrapper has an extra arg */
invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
g_free (wrapper_sig);
- info->compiled_method = mono_jit_compile_method (wrapper);
+ info->compiled_method = mono_jit_compile_method (wrapper, error);
+ if (!mono_error_ok (error)) {
+ g_free (info);
+ return NULL;
+ }
+ } else {
+ /* Gsharedvt methods can be invoked the same way */
+ /* The out wrapper has the same signature as the compiled gsharedvt method */
+ MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
+
+ info->wrapper_arg = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
+
+ invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
+ g_free (wrapper_sig);
}
}
- info->runtime_invoke = mono_jit_compile_method (invoke);
+ info->runtime_invoke = mono_jit_compile_method (invoke, error);
+ if (!mono_error_ok (error)) {
+ g_free (info);
+ return NULL;
+ }
}
return info;
}
+static MonoObject*
+mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
+{
+ MonoMethodSignature *sig = info->sig;
+ MonoDomain *domain = mono_domain_get ();
+ MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
+ gpointer *args;
+ gpointer retval_ptr;
+ guint8 retval [256];
+ gpointer *param_refs;
+ int i, pindex;
+
+ mono_error_init (error);
+
+ g_assert (info->gsharedvt_invoke);
+
+ /*
+ * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
+ * The advantage of this is the gsharedvt out wrappers have a reduced set of
+ * signatures, so we only have to generate runtime invoke wrappers for these
+ * signatures.
+ * This code also handles invocation of gsharedvt methods directly, no
+ * out wrappers are used in that case.
+ */
+ args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
+ param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
+ pindex = 0;
+ /*
+ * The runtime invoke wrappers expects pointers to primitive types, so have to
+ * use indirections.
+ */
+ if (sig->hasthis)
+ args [pindex ++] = &obj;
+ if (sig->ret->type != MONO_TYPE_VOID) {
+ retval_ptr = (gpointer)&retval;
+ args [pindex ++] = &retval_ptr;
+ }
+ for (i = 0; i < sig->param_count; ++i) {
+ MonoType *t = sig->params [i];
+
+ if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
+ MonoClass *klass = mono_class_from_mono_type (t);
+ guint8 *nullable_buf;
+ int size;
+
+ size = mono_class_value_size (klass, NULL);
+ nullable_buf = g_alloca (size);
+ g_assert (nullable_buf);
+
+ /* The argument pointed to by params [i] is either a boxed vtype or null */
+ mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
+ params [i] = nullable_buf;
+ }
+
+ if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
+ param_refs [i] = params [i];
+ params [i] = &(param_refs [i]);
+ }
+ args [pindex ++] = ¶ms [i];
+ }
+ /* The gsharedvt out wrapper has an extra argument which contains the method to call */
+ args [pindex ++] = &info->wrapper_arg;
+
+ runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
+
+ runtime_invoke (NULL, args, exc, info->compiled_method);
+ if (exc && *exc)
+ return NULL;
+
+ if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
+ return mono_value_box_checked (domain, info->ret_box_class, retval, error);
+ else
+ return *(MonoObject**)retval;
+}
+
/**
* mono_jit_runtime_invoke:
* @method: the method to invoke
* @obj: this pointer
* @params: array of parameter values.
- * @exc: used to catch exceptions objects
+ * @exc: Set to the exception raised in the managed method. If NULL, error is thrown instead.
+ * If coop is enabled, this argument is ignored - all exceptoins are caught and propagated
+ * through @error
+ * @error: error or caught exception object
*/
static MonoObject*
-mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
+mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
{
MonoMethod *invoke, *callee;
MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
MonoDomain *domain = mono_domain_get ();
MonoJitDomainInfo *domain_info;
RuntimeInvokeInfo *info, *info2;
+ MonoJitInfo *ji = NULL;
+ gboolean callee_gsharedvt = FALSE;
+
+ mono_error_init (error);
if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
* but keep it just in case for moonlight.
*/
mono_class_setup_vtable (method->klass);
- if (method->klass->exception_type != MONO_EXCEPTION_NONE) {
+ if (mono_class_has_failure (method->klass)) {
+ mono_error_set_for_class_failure (error, method->klass);
if (exc)
*exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
- else
- mono_raise_exception (mono_class_get_exception_for_failure (method->klass));
return NULL;
}
}
MonoMethod *wrapper;
wrapper = mono_marshal_get_array_accessor_wrapper (method);
- invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE, FALSE);
+ invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
callee = wrapper;
} else {
callee = NULL;
}
if (callee) {
- MonoException *jit_ex = NULL;
-
- compiled_method = mono_jit_compile_method_with_opt (callee, mono_get_optimizations_for_method (callee, default_opt), &jit_ex);
+ compiled_method = mono_jit_compile_method_with_opt (callee, mono_get_optimizations_for_method (callee, default_opt), error);
if (!compiled_method) {
- g_assert (jit_ex);
- if (exc) {
- *exc = (MonoObject*)jit_ex;
- return NULL;
- } else {
- mono_raise_exception (jit_ex);
- /* coverity[unreachable] */
- }
+ g_assert (!mono_error_ok (error));
+ return NULL;
}
- compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
+ if (mono_llvm_only) {
+ ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
+ callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
+ if (callee_gsharedvt)
+ callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
+ }
+
+ if (!callee_gsharedvt)
+ compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
} else {
compiled_method = NULL;
}
- info = create_runtime_invoke_info (domain, method, compiled_method);
+ info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, error);
+ if (!mono_error_ok (error))
+ return NULL;
mono_domain_lock (domain);
info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
* We need this here because mono_marshal_get_runtime_invoke can place
* the helper method in System.Object and not the target class.
*/
- if (exc) {
- *exc = (MonoObject*)mono_runtime_class_init_full (info->vtable, FALSE);
- if (*exc)
- return NULL;
- } else {
- mono_runtime_class_init (info->vtable);
+ if (!mono_runtime_class_init_full (info->vtable, error)) {
+ if (exc)
+ *exc = (MonoObject*) mono_error_convert_to_exception (error);
+ return NULL;
}
+ /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
+ we always catch the exception and propagate it through the MonoError */
+ gboolean catchExcInMonoError =
+ (exc == NULL) && mono_threads_is_coop_enabled ();
+ MonoObject *invoke_exc = NULL;
+ if (catchExcInMonoError)
+ exc = &invoke_exc;
+
/* The wrappers expect this to be initialized to NULL */
if (exc)
*exc = NULL;
int i, pindex;
guint8 buf [512];
guint8 retval [256];
- gpointer rgctx;
if (!dyn_runtime_invoke) {
invoke = mono_marshal_get_runtime_invoke_dynamic ();
- dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke);
+ dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke, error);
+ if (!mono_error_ok (error))
+ return NULL;
}
/* Convert the arguments to the format expected by start_dyn_call () */
- args = (void **)g_alloca ((sig->param_count + sig->hasthis + info->needs_rgctx) * sizeof (gpointer));
+ args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
pindex = 0;
if (sig->hasthis)
args [pindex ++] = &obj;
args [pindex ++] = params [i];
}
}
- if (info->needs_rgctx) {
- rgctx = mini_method_get_rgctx (method);
- args [pindex ++] = &rgctx;
- }
//printf ("M: %s\n", mono_method_full_name (method, TRUE));
mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf, sizeof (buf));
dyn_runtime_invoke (buf, exc, info->compiled_method);
-
mono_arch_finish_dyn_call (info->dyn_call_info, buf);
- if (info->ret_box_class)
- return mono_value_box (domain, info->ret_box_class, retval);
- else
- return *(MonoObject**)retval;
- }
-#endif
-
- runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
-
- if (info->wrapper_arg) {
- MonoMethodSignature *sig = mono_method_signature (method);
- gpointer *args;
- gpointer retval_ptr;
- guint8 retval [256];
- gpointer *param_refs;
- int i, pindex;
-
- /*
- * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
- * The advantage of this is the gsharedvt out wrappers have a reduced set of
- * signatures, so we only have to generate runtime invoke wrappers for these
- * signatures.
- */
- args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
- param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
- pindex = 0;
- /*
- * The runtime invoke wrappers expects pointers to primitive types, so have to
- * use indirections.
- */
- if (sig->hasthis)
- args [pindex ++] = &obj;
- if (sig->ret->type != MONO_TYPE_VOID) {
- retval_ptr = (gpointer)&retval;
- args [pindex ++] = &retval_ptr;
- }
- for (i = 0; i < sig->param_count; ++i) {
- MonoType *t = sig->params [i];
-
- if (MONO_TYPE_IS_REFERENCE (t)) {
- param_refs [i] = params [i];
- params [i] = &(param_refs [i]);
- }
- args [pindex ++] = ¶ms [i];
+ if (catchExcInMonoError && *exc != NULL) {
+ mono_error_set_exception_instance (error, (MonoException*) *exc);
+ return NULL;
}
- /* The gsharedvt out wrapper has an extra argument which contains the method to call */
- args [pindex ++] = &info->wrapper_arg;
- runtime_invoke (NULL, args, exc, info->compiled_method);
- if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
- return mono_value_box (domain, info->ret_box_class, retval);
+ if (info->ret_box_class)
+ return mono_value_box_checked (domain, info->ret_box_class, retval, error);
else
return *(MonoObject**)retval;
}
+#endif
- // FIXME: Cache this
- if (info->needs_rgctx) {
- MonoMethodSignature *sig = mono_method_signature (method);
- gpointer rgctx;
- gpointer *args;
- int i, pindex;
+ MonoObject *result;
- args = (void **)g_alloca ((sig->param_count + sig->hasthis + info->needs_rgctx) * sizeof (gpointer));
- pindex = 0;
- rgctx = mini_method_get_rgctx (method);
- for (i = 0; i < sig->param_count; ++i)
- args [pindex ++] = params [i];
- args [pindex ++] = &rgctx;
- return runtime_invoke ((MonoObject *)obj, args, exc, info->compiled_method);
+ if (mono_llvm_only) {
+ result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
+ if (!is_ok (error))
+ return NULL;
} else {
- return runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
+ runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
+
+ result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
}
+ if (catchExcInMonoError && *exc != NULL)
+ mono_error_set_exception_instance (error, (MonoException*) *exc);
+ return result;
}
typedef struct {
MonoVTable *vtable;
int slot;
-} IMTThunkInfo;
+} IMTTrampInfo;
-typedef gpointer (*IMTThunkFunc) (gpointer *arg, MonoMethod *imt_method);
+typedef gpointer (*IMTTrampFunc) (gpointer *arg, MonoMethod *imt_method);
/*
- * mini_llvmonly_initial_imt_thunk:
+ * mini_llvmonly_initial_imt_tramp:
*
- * This function is called the first time a call is made through an IMT thunk.
- * It should have the same signature as the mono_llvmonly_imt_thunk_... functions.
+ * This function is called the first time a call is made through an IMT trampoline.
+ * It should have the same signature as the mono_llvmonly_imt_tramp_... functions.
*/
static gpointer
-mini_llvmonly_initial_imt_thunk (gpointer *arg, MonoMethod *imt_method)
+mini_llvmonly_initial_imt_tramp (gpointer *arg, MonoMethod *imt_method)
{
- IMTThunkInfo *info = (IMTThunkInfo*)arg;
+ IMTTrampInfo *info = (IMTTrampInfo*)arg;
gpointer *imt;
gpointer *ftndesc;
- IMTThunkFunc func;
+ IMTTrampFunc func;
mono_vtable_build_imt_slot (info->vtable, info->slot);
imt = (gpointer*)info->vtable;
imt -= MONO_IMT_SIZE;
- /* Return what the real IMT thunk returns */
+ /* Return what the real IMT trampoline returns */
ftndesc = imt [info->slot];
func = ftndesc [0];
- if (func == (IMTThunkFunc)mini_llvmonly_initial_imt_thunk)
+ if (func == (IMTTrampFunc)mini_llvmonly_initial_imt_tramp)
/* Happens when the imt slot contains only a generic virtual method */
return NULL;
return func ((gpointer *)ftndesc [1], imt_method);
/* This is called indirectly through an imt slot. */
static gpointer
-mono_llvmonly_imt_thunk (gpointer *arg, MonoMethod *imt_method)
+mono_llvmonly_imt_tramp (gpointer *arg, MonoMethod *imt_method)
{
int i = 0;
- /* arg points to an array created in mono_llvmonly_get_imt_thunk () */
+ /* arg points to an array created in mono_llvmonly_get_imt_trampoline () */
while (arg [i] && arg [i] != imt_method)
i += 2;
g_assert (arg [i]);
return arg [i + 1];
}
-/* Optimized versions of mono_llvmonly_imt_thunk () for different table sizes */
+/* Optimized versions of mono_llvmonly_imt_trampoline () for different table sizes */
static gpointer
-mono_llvmonly_imt_thunk_1 (gpointer *arg, MonoMethod *imt_method)
+mono_llvmonly_imt_tramp_1 (gpointer *arg, MonoMethod *imt_method)
{
//g_assert (arg [0] == imt_method);
return arg [1];
}
static gpointer
-mono_llvmonly_imt_thunk_2 (gpointer *arg, MonoMethod *imt_method)
+mono_llvmonly_imt_tramp_2 (gpointer *arg, MonoMethod *imt_method)
{
//g_assert (arg [0] == imt_method || arg [2] == imt_method);
if (arg [0] == imt_method)
}
static gpointer
-mono_llvmonly_imt_thunk_3 (gpointer *arg, MonoMethod *imt_method)
+mono_llvmonly_imt_tramp_3 (gpointer *arg, MonoMethod *imt_method)
{
//g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
if (arg [0] == imt_method)
}
/*
- * A version of the imt thunk used for generic virtual methods.
- * Unlikely a normal imt thunk, its possible that IMT_METHOD is not found
+ * A version of the imt trampoline used for generic virtual/variant iface methods.
+ * Unlikely a normal imt trampoline, its possible that IMT_METHOD is not found
* in the search table. The original JIT code had a 'fallback' trampoline it could
* call, but we can't do that, so we just return NULL, and the compiled code
* will handle it.
*/
static gpointer
-mono_llvmonly_generic_virtual_imt_thunk (gpointer *arg, MonoMethod *imt_method)
+mono_llvmonly_fallback_imt_tramp (gpointer *arg, MonoMethod *imt_method)
{
int i = 0;
}
static gpointer
-mono_llvmonly_get_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
+mono_llvmonly_get_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
{
gpointer *buf;
gpointer *res;
gboolean virtual_generic = FALSE;
/*
- * Create an array which is passed to the imt thunk functions.
+ * Create an array which is passed to the imt trampoline functions.
* The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
*/
res = (void **)mono_domain_alloc (domain, 2 * sizeof (gpointer));
switch (real_count) {
case 1:
- res [0] = mono_llvmonly_imt_thunk_1;
+ res [0] = mono_llvmonly_imt_tramp_1;
break;
case 2:
- res [0] = mono_llvmonly_imt_thunk_2;
+ res [0] = mono_llvmonly_imt_tramp_2;
break;
case 3:
- res [0] = mono_llvmonly_imt_thunk_3;
+ res [0] = mono_llvmonly_imt_tramp_3;
break;
default:
- res [0] = mono_llvmonly_imt_thunk;
+ res [0] = mono_llvmonly_imt_tramp;
break;
}
- if (virtual_generic)
- res [0] = mono_llvmonly_generic_virtual_imt_thunk;
+ if (virtual_generic || fail_tramp)
+ res [0] = mono_llvmonly_fallback_imt_tramp;
res [1] = buf;
return res;
MonoException *exc;
MONO_SIG_HANDLER_GET_CONTEXT;
+ if (mono_runtime_get_no_exec ())
+ exit (1);
+
+ MONO_ENTER_GC_UNSAFE_UNBALANCED;
+
exc = mono_get_exception_execution_engine ("SIGILL");
mono_arch_handle_exception (ctx, exc);
+
+ MONO_EXIT_GC_UNSAFE_UNBALANCED;
}
#if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
* Returns: a pointer to the newly created code
*/
static gpointer
-mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
+mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
{
MonoMethod *nm;
guint8 *addr = NULL;
+ mono_error_init (error);
+
if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature (method)->generic_param_count) {
return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
domain, NULL);
}
if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
- (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))) {
+ (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
nm = mono_marshal_get_remoting_invoke_for_target (method, target);
- addr = (guint8 *)mono_compile_method (nm);
- } else
- {
- addr = (guint8 *)mono_compile_method (method);
- }
+ else
+ nm = method;
+ addr = (guint8 *)mono_compile_method_checked (nm, error);
+ return_val_if_nok (error, NULL);
return mono_get_addr_from_ftnptr (addr);
}
#endif
-static void
+static G_GNUC_UNUSED void
no_imt_trampoline (void)
{
g_assert_not_reached ();
}
-static void
+static G_GNUC_UNUSED void
no_vcall_trampoline (void)
{
g_assert_not_reached ();
if (mono_llvm_only) {
if (slot_index < 0) {
- /* Initialize the IMT thunks to a 'trampoline' so the generated code doesn't have to initialize it */
+ /* Initialize the IMT trampoline to a 'trampoline' so the generated code doesn't have to initialize it */
// FIXME: Memory management
gpointer *ftndesc = g_malloc (2 * sizeof (gpointer));
- IMTThunkInfo *info = g_new0 (IMTThunkInfo, 1);
+ IMTTrampInfo *info = g_new0 (IMTTrampInfo, 1);
info->vtable = vt;
info->slot = index;
- ftndesc [0] = mini_llvmonly_initial_imt_thunk;
+ ftndesc [0] = mini_llvmonly_initial_imt_tramp;
ftndesc [1] = info;
mono_memory_barrier ();
return ftndesc;
return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
}
+static gboolean
+is_callee_gsharedvt_variable (gpointer addr)
+{
+ MonoJitInfo *ji;
+ gboolean callee_gsharedvt;
+
+ ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
+ g_assert (ji);
+ callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
+ if (callee_gsharedvt)
+ callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
+ return callee_gsharedvt;
+}
+
+gpointer
+mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr)
+{
+ gpointer arg = NULL;
+
+ if (mono_method_needs_static_rgctx_invoke (method, FALSE))
+ arg = mini_method_get_rgctx (method);
+
+ /*
+ * Avoid adding gsharedvt in wrappers since they might not exist if
+ * this delegate is called through a gsharedvt delegate invoke wrapper.
+ * Instead, encode that the method is gsharedvt in del->extra_arg,
+ * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
+ */
+ if (method->is_inflated && is_callee_gsharedvt_variable (method_ptr)) {
+ g_assert ((((mgreg_t)arg) & 1) == 0);
+ arg = (gpointer)(((mgreg_t)arg) | 1);
+ }
+ return arg;
+}
+
+void
+mini_init_delegate (MonoDelegate *del)
+{
+ if (mono_llvm_only)
+ del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
+}
+
+char*
+mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
+{
+ int abs_offset;
+
+ abs_offset = offset;
+ if (abs_offset < 0)
+ abs_offset = - abs_offset;
+ return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / SIZEOF_VOID_P);
+}
+
gpointer
mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
{
return NULL;
is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
- is_interface = method->klass->flags & TYPE_ATTRIBUTE_INTERFACE ? TRUE : FALSE;
+ is_interface = mono_class_is_interface (method->klass);
load_imt_reg = is_virtual_generic || is_interface;
- if (is_interface && !is_virtual_generic)
+ if (is_interface)
offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * SIZEOF_VOID_P;
else
offset = G_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
/* FIXME Support more cases */
if (mono_aot_only) {
- char tramp_name [256];
- const char *imt = load_imt_reg ? "_imt" : "";
- int ind = (load_imt_reg ? (-offset) : offset) / SIZEOF_VOID_P;
-
- sprintf (tramp_name, "delegate_virtual_invoke%s_%d", imt, ind);
- cache [idx] = (guint8 *)mono_aot_get_trampoline (tramp_name);
+ cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
g_assert (cache [idx]);
} else {
cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
return cache [idx];
}
+/**
+ * mini_parse_debug_option:
+ * @option: The option to parse.
+ *
+ * Parses debug options for the mono runtime. The options are the same as for
+ * the MONO_DEBUG environment variable.
+ *
+ */
+gboolean
+mini_parse_debug_option (const char *option)
+{
+ if (!strcmp (option, "handle-sigint"))
+ debug_options.handle_sigint = TRUE;
+ else if (!strcmp (option, "keep-delegates"))
+ debug_options.keep_delegates = TRUE;
+ else if (!strcmp (option, "reverse-pinvoke-exceptions"))
+ debug_options.reverse_pinvoke_exceptions = TRUE;
+ else if (!strcmp (option, "collect-pagefault-stats"))
+ debug_options.collect_pagefault_stats = TRUE;
+ else if (!strcmp (option, "break-on-unverified"))
+ debug_options.break_on_unverified = TRUE;
+ else if (!strcmp (option, "no-gdb-backtrace"))
+ debug_options.no_gdb_backtrace = TRUE;
+ else if (!strcmp (option, "suspend-on-sigsegv"))
+ debug_options.suspend_on_sigsegv = TRUE;
+ else if (!strcmp (option, "suspend-on-exception"))
+ debug_options.suspend_on_exception = TRUE;
+ else if (!strcmp (option, "suspend-on-unhandled"))
+ debug_options.suspend_on_unhandled = TRUE;
+ else if (!strcmp (option, "dont-free-domains"))
+ mono_dont_free_domains = TRUE;
+ else if (!strcmp (option, "dyn-runtime-invoke"))
+ debug_options.dyn_runtime_invoke = TRUE;
+ else if (!strcmp (option, "gdb"))
+ debug_options.gdb = TRUE;
+ else if (!strcmp (option, "explicit-null-checks"))
+ debug_options.explicit_null_checks = TRUE;
+ else if (!strcmp (option, "gen-seq-points"))
+ debug_options.gen_sdb_seq_points = TRUE;
+ else if (!strcmp (option, "gen-compact-seq-points"))
+ fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
+ else if (!strcmp (option, "no-compact-seq-points"))
+ debug_options.no_seq_points_compact_data = TRUE;
+ else if (!strcmp (option, "single-imm-size"))
+ debug_options.single_imm_size = TRUE;
+ else if (!strcmp (option, "init-stacks"))
+ debug_options.init_stacks = TRUE;
+ else if (!strcmp (option, "casts"))
+ debug_options.better_cast_details = TRUE;
+ else if (!strcmp (option, "soft-breakpoints"))
+ debug_options.soft_breakpoints = TRUE;
+ else if (!strcmp (option, "check-pinvoke-callconv"))
+ debug_options.check_pinvoke_callconv = TRUE;
+ else if (!strcmp (option, "arm-use-fallback-tls"))
+ debug_options.arm_use_fallback_tls = TRUE;
+ else if (!strcmp (option, "debug-domain-unload"))
+ mono_enable_debug_domain_unload (TRUE);
+ else if (!strcmp (option, "partial-sharing"))
+ mono_set_partial_sharing_supported (TRUE);
+ else if (!strcmp (option, "align-small-structs"))
+ mono_align_small_structs = TRUE;
+ else if (!strcmp (option, "native-debugger-break"))
+ debug_options.native_debugger_break = TRUE;
+ else if (!strcmp (option, "disable_omit_fp"))
+ debug_options.disable_omit_fp = TRUE;
+ else
+ return FALSE;
+
+ return TRUE;
+}
+
static void
mini_parse_debug_options (void)
{
for (ptr = args; ptr && *ptr; ptr++) {
const char *arg = *ptr;
- if (!strcmp (arg, "handle-sigint"))
- debug_options.handle_sigint = TRUE;
- else if (!strcmp (arg, "keep-delegates"))
- debug_options.keep_delegates = TRUE;
- else if (!strcmp (arg, "reverse-pinvoke-exceptions"))
- debug_options.reverse_pinvoke_exceptions = TRUE;
- else if (!strcmp (arg, "collect-pagefault-stats"))
- debug_options.collect_pagefault_stats = TRUE;
- else if (!strcmp (arg, "break-on-unverified"))
- debug_options.break_on_unverified = TRUE;
- else if (!strcmp (arg, "no-gdb-backtrace"))
- debug_options.no_gdb_backtrace = TRUE;
- else if (!strcmp (arg, "suspend-on-sigsegv"))
- debug_options.suspend_on_sigsegv = TRUE;
- else if (!strcmp (arg, "suspend-on-exception"))
- debug_options.suspend_on_exception = TRUE;
- else if (!strcmp (arg, "suspend-on-unhandled"))
- debug_options.suspend_on_unhandled = TRUE;
- else if (!strcmp (arg, "dont-free-domains"))
- mono_dont_free_domains = TRUE;
- else if (!strcmp (arg, "dyn-runtime-invoke"))
- debug_options.dyn_runtime_invoke = TRUE;
- else if (!strcmp (arg, "gdb"))
- debug_options.gdb = TRUE;
- else if (!strcmp (arg, "explicit-null-checks"))
- debug_options.explicit_null_checks = TRUE;
- else if (!strcmp (arg, "gen-seq-points"))
- debug_options.gen_sdb_seq_points = TRUE;
- else if (!strcmp (arg, "gen-compact-seq-points"))
- debug_options.gen_seq_points_compact_data = TRUE;
- else if (!strcmp (arg, "single-imm-size"))
- debug_options.single_imm_size = TRUE;
- else if (!strcmp (arg, "init-stacks"))
- debug_options.init_stacks = TRUE;
- else if (!strcmp (arg, "casts"))
- debug_options.better_cast_details = TRUE;
- else if (!strcmp (arg, "soft-breakpoints"))
- debug_options.soft_breakpoints = TRUE;
- else if (!strcmp (arg, "check-pinvoke-callconv"))
- debug_options.check_pinvoke_callconv = TRUE;
- else if (!strcmp (arg, "arm-use-fallback-tls"))
- debug_options.arm_use_fallback_tls = TRUE;
- else if (!strcmp (arg, "debug-domain-unload"))
- mono_enable_debug_domain_unload (TRUE);
- else if (!strcmp (arg, "partial-sharing"))
- mono_set_partial_sharing_supported (TRUE);
- else if (!strcmp (arg, "align-small-structs"))
- mono_align_small_structs = TRUE;
- else if (!strcmp (arg, "native-debugger-break"))
- debug_options.native_debugger_break = TRUE;
- else {
+ if (!mini_parse_debug_option (arg)) {
fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
- fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'suspend-on-sigsegv', 'suspend-on-exception', 'suspend-on-unhandled', 'dont-free-domains', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'gen-seq-points', 'gen-compact-seq-points', 'single-imm-size', 'init-stacks', 'casts', 'soft-breakpoints', 'check-pinvoke-callconv', 'arm-use-fallback-tls', 'debug-domain-unload', 'partial-sharing', 'align-small-structs', 'native-debugger-break'\n");
+ fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'suspend-on-sigsegv', 'suspend-on-exception', 'suspend-on-unhandled', 'dont-free-domains', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'gen-seq-points', 'no-compact-seq-points', 'single-imm-size', 'init-stacks', 'casts', 'soft-breakpoints', 'check-pinvoke-callconv', 'arm-use-fallback-tls', 'debug-domain-unload', 'partial-sharing', 'align-small-structs', 'native-debugger-break'\n");
exit (1);
}
}
mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
+ mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_method_to_ir);
+ mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses);
+ mono_counters_register ("JIT/handle_out_of_line_bblock (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_out_of_line_bblock);
+ mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_long_opts);
+ mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_typechecks);
+ mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop);
+ mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_emulate_ops);
+ mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches);
+ mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs);
+ mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce);
+ mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_alias_analysis);
+ mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_if_conversion);
+ mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_bb_ordering);
+ mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compile_dominator_info);
+ mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compute_natural_loops);
+ mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_insert_safepoints);
+ mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_compute);
+ mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_cprop);
+ mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_deadce);
+ mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_perform_abc_removal);
+ mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_remove);
+ mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop2);
+ mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs2);
+ mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce2);
+ mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches2);
+ mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_vtype_opts);
+ mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_array_access_opts);
+ mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses2);
+ mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_analyze_liveness);
+ mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_linear_scan);
+ mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_arch_allocate_vars);
+ mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_spill_global_vars);
+ mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop3);
+ mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce3);
+ mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_codegen);
+ mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_create_jit_info);
+ mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_gc_create_gc_map);
+ mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_save_seq_point_info);
mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_time);
mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
+ mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
}
static void runtime_invoke_info_free (gpointer value);
g_free (info);
}
+static void
+free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
+{
+ g_slist_free (value);
+}
+
static void
mini_free_jit_domain_info (MonoDomain *domain)
{
mono_debugger_agent_free_domain_info (domain);
if (info->gsharedvt_arg_tramp_hash)
g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
+ if (info->llvm_jit_callees) {
+ g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
+ g_hash_table_destroy (info->llvm_jit_callees);
+ }
#ifdef ENABLE_LLVM
mono_llvm_free_domain_info (domain);
#endif
MonoDomain *
mini_init (const char *filename, const char *runtime_version)
{
+ MonoError error;
MonoDomain *domain;
MonoRuntimeCallbacks callbacks;
MonoThreadInfoRuntimeCallbacks ticallbacks;
callbacks.debug_log = mono_debugger_agent_debug_log;
callbacks.debug_log_is_enabled = mono_debugger_agent_debug_log_is_enabled;
callbacks.tls_key_supported = mini_tls_key_supported;
-
callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
callbacks.get_imt_trampoline = mini_get_imt_trampoline;
callbacks.imt_entry_inited = mini_imt_entry_inited;
+ callbacks.init_delegate = mini_init_delegate;
+#define JIT_INVOKE_WORKS
+#ifdef JIT_INVOKE_WORKS
+ callbacks.runtime_invoke = mono_jit_runtime_invoke;
+#endif
+#define JIT_TRAMPOLINES_WORK
+#ifdef JIT_TRAMPOLINES_WORK
+ callbacks.compile_method = mono_jit_compile_method;
+ callbacks.create_jump_trampoline = mono_create_jump_trampoline;
+ callbacks.create_jit_trampoline = mono_create_jit_trampoline;
+#endif
mono_install_callbacks (&callbacks);
mono_counters_init ();
+#ifndef HOST_WIN32
+ mono_w32handle_init ();
+#endif
+
mono_threads_runtime_init (&ticallbacks);
if (g_getenv ("MONO_DEBUG") != NULL)
#endif
mono_threads_install_cleanup (mini_thread_cleanup);
-#define JIT_TRAMPOLINES_WORK
#ifdef JIT_TRAMPOLINES_WORK
- mono_install_compile_method (mono_jit_compile_method);
mono_install_free_method (mono_jit_free_method);
- mono_install_trampoline (mono_create_jit_trampoline);
- mono_install_jump_trampoline (mono_create_jump_trampoline);
#ifndef DISABLE_REMOTING
mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
#endif
mono_install_delegate_trampoline (mono_create_delegate_trampoline);
mono_install_create_domain_hook (mini_create_jit_domain_info);
mono_install_free_domain_hook (mini_free_jit_domain_info);
-#endif
-#define JIT_INVOKE_WORKS
-#ifdef JIT_INVOKE_WORKS
- mono_install_runtime_invoke (mono_jit_runtime_invoke);
#endif
mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
mono_install_get_class_from_name (mono_aot_get_class_from_name);
}
if (mono_llvm_only) {
- mono_install_imt_thunk_builder (mono_llvmonly_get_imt_thunk);
- mono_set_always_build_imt_thunks (TRUE);
+ mono_install_imt_trampoline_builder (mono_llvmonly_get_imt_trampoline);
+ mono_set_always_build_imt_trampolines (TRUE);
} else if (mono_aot_only) {
- mono_install_imt_thunk_builder (mono_aot_get_imt_thunk);
+ mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
} else {
- mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
+ mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
}
/*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
mono_simd_intrinsics_init ();
#endif
-#if MONO_SUPPORT_TASKLETS
mono_tasklets_init ();
-#endif
register_trampolines (domain);
*/
mono_runtime_set_no_exec (TRUE);
+ mono_mem_account_register_counters ();
+
#define JIT_RUNTIME_WORKS
#ifdef JIT_RUNTIME_WORKS
mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
- mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
+ mono_runtime_init_checked (domain, mono_thread_start_cb, mono_thread_attach_cb, &error);
+ mono_error_assert_ok (&error);
mono_thread_attach (domain);
#endif
+ if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
+ mono_runtime_setup_stat_profiler ();
+
mono_profiler_runtime_initialized ();
MONO_VES_INIT_END ();
ves_icall_get_trace);
mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
mono_runtime_install_handlers);
+ mono_add_internal_call ("Mono.Runtime::mono_runtime_cleanup_handlers",
+ mono_runtime_cleanup_handlers);
#if defined(PLATFORM_ANDROID) || defined(TARGET_ANDROID)
mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
register_icall (mono_llvm_match_exception, "mono_llvm_match_exception", "int ptr int int", TRUE);
register_icall (mono_llvm_clear_exception, "mono_llvm_clear_exception", NULL, TRUE);
register_icall (mono_llvm_load_exception, "mono_llvm_load_exception", "object", TRUE);
- register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", FALSE);
+ register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", TRUE);
#if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED)
register_icall (mono_llvm_set_unhandled_exception_handler, "mono_llvm_set_unhandled_exception_handler", NULL, TRUE);
register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE);
register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE);
- register_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", "void", FALSE);
-#ifndef DISABLE_REMOTING
- register_icall (mono_load_remote_field_new, "mono_load_remote_field_new", "object object ptr ptr", FALSE);
- register_icall (mono_store_remote_field_new, "mono_store_remote_field_new", "void object ptr ptr object", FALSE);
-#endif
#if defined(__native_client__) || defined(__native_client_codegen__)
register_icall (mono_nacl_gc, "mono_nacl_gc", "void", FALSE);
register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, "mono_lconv_to_r8_un", FALSE);
#endif
#ifdef MONO_ARCH_EMULATE_FREM
-#if defined(__default_codegen__)
+#if !defined(__native_client__)
register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, "fmod", FALSE);
register_opcode_emulation (OP_RREM, "__emul_rrem", "float float float", fmodf, "fmodf", FALSE);
-#elif defined(__native_client_codegen__)
+#else
register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", mono_fmod, "mono_fmod", FALSE);
#endif
#endif
#endif
/* other jit icalls */
- register_icall (mono_delegate_ctor, "mono_delegate_ctor", "void object object ptr", FALSE);
+ register_icall (ves_icall_mono_delegate_ctor, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE);
register_icall (mono_class_static_field_address , "mono_class_static_field_address",
"ptr ptr ptr", FALSE);
register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
"ptr ptr ptr ptr", FALSE);
register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
- register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
+ register_icall (ves_icall_mono_ldstr, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE);
register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
- register_icall (mono_object_new, "mono_object_new", "object ptr ptr", FALSE);
- register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE);
- register_icall (mono_array_new, "mono_array_new", "object ptr ptr int32", FALSE);
- register_icall (mono_array_new_specific, "mono_array_new_specific", "object ptr int32", FALSE);
- register_icall (mono_runtime_class_init, "mono_runtime_class_init", "void ptr", FALSE);
+ register_icall (ves_icall_object_new, "ves_icall_object_new", "object ptr ptr", FALSE);
+ register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE);
+ register_icall (ves_icall_array_new, "ves_icall_array_new", "object ptr ptr int32", FALSE);
+ register_icall (ves_icall_array_new_specific, "ves_icall_array_new_specific", "object ptr int32", FALSE);
+ register_icall (ves_icall_runtime_class_init, "ves_icall_runtime_class_init", "void ptr", FALSE);
register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
register_icall (mono_generic_class_init, "mono_generic_class_init", "void ptr", FALSE);
- register_icall (mono_fill_class_rgctx, "mono_class_fill_rgctx", "ptr ptr int", FALSE);
- register_icall (mono_fill_method_rgctx, "mono_method_fill_rgctx", "ptr ptr int", FALSE);
+ register_icall (mono_fill_class_rgctx, "mono_fill_class_rgctx", "ptr ptr int", FALSE);
+ register_icall (mono_fill_method_rgctx, "mono_fill_method_rgctx", "ptr ptr int", FALSE);
register_icall (mono_debugger_agent_user_break, "mono_debugger_agent_user_break", "void", FALSE);
register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
- register_icall (mono_aot_init_gshared_method_rgctx, "mono_aot_init_gshared_method_rgctx", "void ptr int ptr", TRUE);
+ register_icall (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE);
+ register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE);
register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
/* This needs a wrapper so it can have a preserveall cconv */
register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr ptr int", FALSE);
- register_icall (mono_init_delegate, "mono_init_delegate", "void object object ptr", TRUE);
- register_icall (mono_init_delegate_virtual, "mono_init_delegate_virtual", "void object object ptr", TRUE);
+ register_icall (mono_llvmonly_init_delegate, "mono_llvmonly_init_delegate", "void object", TRUE);
+ register_icall (mono_llvmonly_init_delegate_virtual, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE);
register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
+ register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE);
+ register_icall (mono_throw_method_access, "mono_throw_method_access", "void ptr ptr", FALSE);
+ register_icall_no_wrapper (mono_dummy_jit_icall, "mono_dummy_jit_icall", "void");
+
+ register_icall_with_wrapper (mono_monitor_enter, "mono_monitor_enter", "void obj");
+ register_icall_with_wrapper (mono_monitor_enter_v4, "mono_monitor_enter_v4", "void obj ptr");
+ register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", "int obj");
+ register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", "int obj ptr");
#ifdef TARGET_IOS
register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
g_print ("IMT colliding slots: %ld\n", mono_stats.imt_slots_with_collisions);
g_print ("IMT max collisions: %ld\n", mono_stats.imt_max_collisions_in_slot);
g_print ("IMT methods at max col: %ld\n", mono_stats.imt_method_count_when_max_collisions);
- g_print ("IMT thunks size: %ld\n", mono_stats.imt_thunks_size);
+ g_print ("IMT trampolines size: %ld\n", mono_stats.imt_trampolines_size);
g_print ("JIT info table inserts: %ld\n", mono_stats.jit_info_table_insert_count);
g_print ("JIT info table removes: %ld\n", mono_stats.jit_info_table_remove_count);
void
mini_cleanup (MonoDomain *domain)
{
- mono_runtime_shutdown_stat_profiler ();
+ if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
+ mono_runtime_shutdown_stat_profiler ();
#ifndef DISABLE_COM
cominterop_release_all_rcws ();
/* This accesses metadata so needs to be called before runtime shutdown */
print_jit_stats ();
- mono_profiler_shutdown ();
-
#ifndef MONO_CROSS_COMPILE
mono_runtime_cleanup (domain);
#endif
+ mono_profiler_shutdown ();
+
free_jit_tls_data ((MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id));
mono_icall_cleanup ();
mono_code_manager_cleanup ();
-#ifdef USE_JUMP_TABLES
- mono_jumptable_cleanup ();
+#ifndef HOST_WIN32
+ mono_w32handle_cleanup ();
#endif
}
printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
- method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
+ MonoError error;
+
+ method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
+ if (!method) {
+ mono_error_cleanup (&error); /* FIXME don't swallow the error */
+ continue;
+ }
if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
continue;
- if (method->is_generic || method->klass->generic_container)
+ if (method->is_generic || mono_class_is_gtd (method->klass))
continue;
count++;
g_print ("Compiling %d %s\n", count, desc);
g_free (desc);
}
- mono_compile_method (method);
+ mono_compile_method_checked (method, &error);
+ if (!is_ok (&error)) {
+ mono_error_cleanup (&error); /* FIXME don't swallow the error */
+ continue;
+ }
if (strcmp (method->name, "Finalize") == 0) {
- invoke = mono_marshal_get_runtime_invoke (method, FALSE, FALSE);
- mono_compile_method (invoke);
+ invoke = mono_marshal_get_runtime_invoke (method, FALSE);
+ mono_compile_method_checked (invoke, &error);
+ mono_error_assert_ok (&error);
}
#ifndef DISABLE_REMOTING
if (mono_class_is_marshalbyref (method->klass) && mono_method_signature (method)->hasthis) {
invoke = mono_marshal_get_remoting_invoke_with_check (method);
- mono_compile_method (invoke);
+ mono_compile_method_checked (invoke, &error);
+ mono_error_assert_ok (&error);
}
#endif
}
g_assert_not_reached ();
}
-#ifdef USE_JUMP_TABLES
-#define DEFAULT_JUMPTABLE_CHUNK_ELEMENTS 128
-
-typedef struct MonoJumpTableChunk {
- guint32 total;
- guint32 active;
- struct MonoJumpTableChunk *previous;
- /* gpointer entries[total]; */
-} MonoJumpTableChunk;
-
-static MonoJumpTableChunk* g_jumptable;
-#define mono_jumptable_lock() mono_os_mutex_lock (&jumptable_mutex)
-#define mono_jumptable_unlock() mono_os_mutex_unlock (&jumptable_mutex)
-static mono_mutex_t jumptable_mutex;
-
-static MonoJumpTableChunk*
-mono_create_jumptable_chunk (guint32 max_entries)
-{
- guint32 size = sizeof (MonoJumpTableChunk) + max_entries * sizeof(gpointer);
- MonoJumpTableChunk *chunk = (MonoJumpTableChunk*) g_new0 (guchar, size);
- chunk->total = max_entries;
- return chunk;
-}
-
-void
-mono_jumptable_init (void)
-{
- if (g_jumptable == NULL) {
- mono_os_mutex_init_recursive (&jumptable_mutex);
- g_jumptable = mono_create_jumptable_chunk (DEFAULT_JUMPTABLE_CHUNK_ELEMENTS);
- }
-}
-
-gpointer*
-mono_jumptable_add_entry (void)
-{
- return mono_jumptable_add_entries (1);
-}
-
-gpointer*
-mono_jumptable_add_entries (guint32 entries)
+// Custom handlers currently only implemented by Windows.
+#ifndef HOST_WIN32
+gboolean
+mono_runtime_install_custom_handlers (const char *handlers)
{
- guint32 index;
- gpointer *result;
-
- mono_jumptable_init ();
- mono_jumptable_lock ();
- index = g_jumptable->active;
- if (index + entries >= g_jumptable->total) {
- /*
- * Grow jumptable, by adding one more chunk.
- * We cannot realloc jumptable, as there could be pointers
- * to existing jump table entries in the code, so instead
- * we just add one more chunk.
- */
- guint32 max_entries = entries;
- MonoJumpTableChunk *new_chunk;
-
- if (max_entries < DEFAULT_JUMPTABLE_CHUNK_ELEMENTS)
- max_entries = DEFAULT_JUMPTABLE_CHUNK_ELEMENTS;
- new_chunk = mono_create_jumptable_chunk (max_entries);
- /* Link old jumptable, so that we could free it up later. */
- new_chunk->previous = g_jumptable;
- g_jumptable = new_chunk;
- index = 0;
- }
- g_jumptable->active = index + entries;
- result = (gpointer*)((guchar*)g_jumptable + sizeof(MonoJumpTableChunk)) + index;
- mono_jumptable_unlock();
-
- return result;
+ return FALSE;
}
void
-mono_jumptable_cleanup (void)
-{
- if (g_jumptable) {
- MonoJumpTableChunk *current = g_jumptable, *prev;
- while (current != NULL) {
- prev = current->previous;
- g_free (current);
- current = prev;
- }
- g_jumptable = NULL;
- mono_os_mutex_destroy (&jumptable_mutex);
- }
-}
-
-gpointer*
-mono_jumptable_get_entry (guint8 *code_ptr)
+mono_runtime_install_custom_handlers_usage (void)
{
- return mono_arch_jumptable_entry_from_code (code_ptr);
+ fprintf (stdout,
+ "Custom Handlers:\n"
+ " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
+ " separated list of available handlers to install.\n"
+ "\n"
+ "No handlers supported on current platform.\n");
}
-#endif
+#endif /* HOST_WIN32 */