Permalink
Switch branches/tags
Find file
Fetching contributors…
Cannot retrieve contributors at this time
8747 lines (7427 sloc) 253 KB
/**
* \file
*
* Authors:
* Dietmar Maurer (dietmar@ximian.com)
* Paolo Molaro (lupus@ximian.com)
* Patrik Torstensson (patrik.torstensson@labs2.com)
* Marek Safar (marek.safar@gmail.com)
* Aleksey Kliger (aleksey@xamarin.com)
*
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* 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 <glib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#if defined (HAVE_WCHAR_H)
#include <wchar.h>
#endif
#include "mono/metadata/icall-internals.h"
#include "mono/utils/mono-membar.h"
#include <mono/metadata/object.h>
#include <mono/metadata/threads.h>
#include <mono/metadata/threads-types.h>
#include <mono/metadata/threadpool.h>
#include <mono/metadata/threadpool-io.h>
#include <mono/metadata/monitor.h>
#include <mono/metadata/reflection.h>
#include <mono/metadata/image-internals.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/assembly-internals.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/exception.h>
#include <mono/metadata/exception-internals.h>
#include <mono/metadata/w32file.h>
#include <mono/metadata/console-io.h>
#include <mono/metadata/mono-route.h>
#include <mono/metadata/w32socket.h>
#include <mono/metadata/mono-endian.h>
#include <mono/metadata/tokentype.h>
#include <mono/metadata/metadata-internals.h>
#include <mono/metadata/class-internals.h>
#include <mono/metadata/reflection-internals.h>
#include <mono/metadata/marshal.h>
#include <mono/metadata/gc-internals.h>
#include <mono/metadata/mono-gc.h>
#include <mono/metadata/rand.h>
#include <mono/metadata/sysmath.h>
#include <mono/metadata/appdomain-icalls.h>
#include <mono/metadata/string-icalls.h>
#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/w32process.h>
#include <mono/metadata/environment.h>
#include <mono/metadata/profiler-private.h>
#include <mono/metadata/locales.h>
#include <mono/metadata/filewatcher.h>
#include <mono/metadata/security.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/cil-coff.h>
#include <mono/metadata/number-formatter.h>
#include <mono/metadata/security-manager.h>
#include <mono/metadata/security-core-clr.h>
#include <mono/metadata/mono-perfcounters.h>
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/mono-ptr-array.h>
#include <mono/metadata/verify-internals.h>
#include <mono/metadata/runtime.h>
#include <mono/metadata/file-mmap.h>
#include <mono/metadata/seq-points-data.h>
#include <mono/metadata/handle.h>
#include <mono/metadata/w32mutex.h>
#include <mono/metadata/w32semaphore.h>
#include <mono/metadata/w32event.h>
#include <mono/utils/monobitset.h>
#include <mono/utils/mono-time.h>
#include <mono/utils/mono-proclib.h>
#include <mono/utils/mono-string.h>
#include <mono/utils/mono-error-internals.h>
#include <mono/utils/mono-mmap.h>
#include <mono/utils/mono-io-portability.h>
#include <mono/utils/mono-digest.h>
#include <mono/utils/bsearch.h>
#include <mono/utils/mono-os-mutex.h>
#include <mono/utils/mono-threads.h>
#include <mono/metadata/w32error.h>
#include <mono/utils/w32api.h>
#include "decimal-ms.h"
#include "number-ms.h"
#if !defined(HOST_WIN32) && defined(HAVE_SYS_UTSNAME_H)
#include <sys/utsname.h>
#endif
extern MonoStringHandle ves_icall_System_Environment_GetOSVersionString (MonoError *error);
ICALL_EXPORT MonoReflectionAssemblyHandle ves_icall_System_Reflection_Assembly_GetCallingAssembly (MonoError *error);
/* Lazy class loading functions */
static GENERATE_GET_CLASS_WITH_CACHE (system_version, "System", "Version")
static GENERATE_GET_CLASS_WITH_CACHE (assembly_name, "System.Reflection", "AssemblyName")
static GENERATE_GET_CLASS_WITH_CACHE (constructor_info, "System.Reflection", "ConstructorInfo")
static GENERATE_GET_CLASS_WITH_CACHE (property_info, "System.Reflection", "PropertyInfo")
static GENERATE_GET_CLASS_WITH_CACHE (event_info, "System.Reflection", "EventInfo")
static GENERATE_GET_CLASS_WITH_CACHE (module, "System.Reflection", "Module")
static void
array_set_value_impl (MonoArrayHandle arr, MonoObjectHandle value, guint32 pos, MonoError *error);
static MonoArrayHandle
type_array_from_modifiers (MonoImage *image, MonoType *type, int optional, MonoError *error);
static inline MonoBoolean
is_generic_parameter (MonoType *type)
{
return !type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR);
}
static void
mono_class_init_checked (MonoClass *klass, MonoError *error)
{
error_init (error);
if (!mono_class_init (klass))
mono_error_set_for_class_failure (error, klass);
}
#ifndef HOST_WIN32
static inline void
mono_icall_make_platform_path (gchar *path)
{
return;
}
static inline const gchar *
mono_icall_get_file_path_prefix (const gchar *path)
{
return "file://";
}
#endif /* HOST_WIN32 */
ICALL_EXPORT MonoObject *
ves_icall_System_Array_GetValueImpl (MonoArray *arr, guint32 pos)
{
MonoError error;
MonoClass *ac;
gint32 esize;
gpointer *ea;
MonoObject *result = NULL;
ac = (MonoClass *)arr->obj.vtable->klass;
esize = mono_array_element_size (ac);
ea = (gpointer*)((char*)arr->vector + (pos * esize));
if (ac->element_class->valuetype) {
result = mono_value_box_checked (arr->obj.vtable->domain, ac->element_class, ea, &error);
mono_error_set_pending_exception (&error);
} else
result = (MonoObject *)*ea;
return result;
}
ICALL_EXPORT MonoObject *
ves_icall_System_Array_GetValue (MonoArray *arr, MonoArray *idxs)
{
MonoClass *ac, *ic;
MonoArray *io;
gint32 i, pos, *ind;
MONO_CHECK_ARG_NULL (idxs, NULL);
io = idxs;
ic = (MonoClass *)io->obj.vtable->klass;
ac = (MonoClass *)arr->obj.vtable->klass;
g_assert (ic->rank == 1);
if (io->bounds != NULL || io->max_length != ac->rank) {
mono_set_pending_exception (mono_get_exception_argument (NULL, NULL));
return NULL;
}
ind = (gint32 *)io->vector;
if (arr->bounds == NULL) {
if (*ind < 0 || *ind >= arr->max_length) {
mono_set_pending_exception (mono_get_exception_index_out_of_range ());
return NULL;
}
return ves_icall_System_Array_GetValueImpl (arr, *ind);
}
for (i = 0; i < ac->rank; i++) {
if ((ind [i] < arr->bounds [i].lower_bound) ||
(ind [i] >= (mono_array_lower_bound_t)arr->bounds [i].length + arr->bounds [i].lower_bound)) {
mono_set_pending_exception (mono_get_exception_index_out_of_range ());
return NULL;
}
}
pos = ind [0] - arr->bounds [0].lower_bound;
for (i = 1; i < ac->rank; i++)
pos = pos * arr->bounds [i].length + ind [i] -
arr->bounds [i].lower_bound;
return ves_icall_System_Array_GetValueImpl (arr, pos);
}
ICALL_EXPORT void
ves_icall_System_Array_SetValueImpl (MonoArrayHandle arr, MonoObjectHandle value, guint32 pos, MonoError *error)
{
error_init (error);
array_set_value_impl (arr, value, pos, error);
}
static void
array_set_value_impl (MonoArrayHandle arr, MonoObjectHandle value, guint32 pos, MonoError *error)
{
MonoClass *ac, *vc, *ec;
gint32 esize, vsize;
gpointer *ea, *va;
int et, vt;
guint64 u64 = 0;
gint64 i64 = 0;
gdouble r64 = 0;
uint32_t arr_gchandle = 0;
uint32_t value_gchandle = 0;
error_init (error);
if (!MONO_HANDLE_IS_NULL (value))
vc = mono_handle_class (value);
else
vc = NULL;
ac = mono_handle_class (arr);
ec = ac->element_class;
esize = mono_array_element_size (ac);
ea = mono_array_handle_pin_with_size (arr, esize, pos, &arr_gchandle);
if (mono_class_is_nullable (ec)) {
mono_nullable_init_from_handle ((guint8*)ea, value, ec);
goto leave;
}
if (MONO_HANDLE_IS_NULL (value)) {
mono_gc_bzero_atomic (ea, esize);
goto leave;
}
#define NO_WIDENING_CONVERSION G_STMT_START{ \
mono_error_set_argument (error, "value", "not a widening conversion"); \
goto leave; \
}G_STMT_END
#define CHECK_WIDENING_CONVERSION(extra) G_STMT_START{ \
if (esize < vsize + (extra)) { \
mono_error_set_argument (error, "value", "not a widening conversion"); \
goto leave; \
} \
}G_STMT_END
#define INVALID_CAST G_STMT_START{ \
mono_get_runtime_callbacks ()->set_cast_details (vc, ec); \
mono_error_set_invalid_cast (error); \
goto leave; \
}G_STMT_END
/* Check element (destination) type. */
switch (ec->byval_arg.type) {
case MONO_TYPE_STRING:
switch (vc->byval_arg.type) {
case MONO_TYPE_STRING:
break;
default:
INVALID_CAST;
}
break;
case MONO_TYPE_BOOLEAN:
switch (vc->byval_arg.type) {
case MONO_TYPE_BOOLEAN:
break;
case MONO_TYPE_CHAR:
case MONO_TYPE_U1:
case MONO_TYPE_U2:
case MONO_TYPE_U4:
case MONO_TYPE_U8:
case MONO_TYPE_I1:
case MONO_TYPE_I2:
case MONO_TYPE_I4:
case MONO_TYPE_I8:
case MONO_TYPE_R4:
case MONO_TYPE_R8:
NO_WIDENING_CONVERSION;
default:
INVALID_CAST;
}
break;
default:
break;
}
MonoObjectHandle inst = mono_object_handle_isinst (value, ec, error);
if (!is_ok (error))
goto leave;
gboolean castOk = !MONO_HANDLE_IS_NULL (inst);
if (!ec->valuetype) {
if (!castOk)
INVALID_CAST;
MONO_HANDLE_ARRAY_SETREF (arr, pos, value);
goto leave;
}
if (castOk) {
va = mono_object_handle_pin_unbox (value, &value_gchandle);
if (ec->has_references)
mono_value_copy (ea, va, ec);
else
mono_gc_memmove_atomic (ea, va, esize);
mono_gchandle_free (value_gchandle);
value_gchandle = 0;
goto leave;
}
if (!vc->valuetype)
INVALID_CAST;
va = mono_object_handle_pin_unbox (value, &value_gchandle);
vsize = mono_class_instance_size (vc) - sizeof (MonoObject);
et = ec->byval_arg.type;
if (et == MONO_TYPE_VALUETYPE && ec->byval_arg.data.klass->enumtype)
et = mono_class_enum_basetype (ec->byval_arg.data.klass)->type;
vt = vc->byval_arg.type;
if (vt == MONO_TYPE_VALUETYPE && vc->byval_arg.data.klass->enumtype)
vt = mono_class_enum_basetype (vc->byval_arg.data.klass)->type;
#define ASSIGN_UNSIGNED(etype) G_STMT_START{\
switch (vt) { \
case MONO_TYPE_U1: \
case MONO_TYPE_U2: \
case MONO_TYPE_U4: \
case MONO_TYPE_U8: \
case MONO_TYPE_CHAR: \
CHECK_WIDENING_CONVERSION(0); \
*(etype *) ea = (etype) u64; \
goto leave; \
/* You can't assign a signed value to an unsigned array. */ \
case MONO_TYPE_I1: \
case MONO_TYPE_I2: \
case MONO_TYPE_I4: \
case MONO_TYPE_I8: \
/* You can't assign a floating point number to an integer array. */ \
case MONO_TYPE_R4: \
case MONO_TYPE_R8: \
NO_WIDENING_CONVERSION; \
} \
}G_STMT_END
#define ASSIGN_SIGNED(etype) G_STMT_START{\
switch (vt) { \
case MONO_TYPE_I1: \
case MONO_TYPE_I2: \
case MONO_TYPE_I4: \
case MONO_TYPE_I8: \
CHECK_WIDENING_CONVERSION(0); \
*(etype *) ea = (etype) i64; \
goto leave; \
/* You can assign an unsigned value to a signed array if the array's */ \
/* element size is larger than the value size. */ \
case MONO_TYPE_U1: \
case MONO_TYPE_U2: \
case MONO_TYPE_U4: \
case MONO_TYPE_U8: \
case MONO_TYPE_CHAR: \
CHECK_WIDENING_CONVERSION(1); \
*(etype *) ea = (etype) u64; \
goto leave; \
/* You can't assign a floating point number to an integer array. */ \
case MONO_TYPE_R4: \
case MONO_TYPE_R8: \
NO_WIDENING_CONVERSION; \
} \
}G_STMT_END
#define ASSIGN_REAL(etype) G_STMT_START{\
switch (vt) { \
case MONO_TYPE_R4: \
case MONO_TYPE_R8: \
CHECK_WIDENING_CONVERSION(0); \
*(etype *) ea = (etype) r64; \
goto leave; \
/* All integer values fit into a floating point array, so we don't */ \
/* need to CHECK_WIDENING_CONVERSION here. */ \
case MONO_TYPE_I1: \
case MONO_TYPE_I2: \
case MONO_TYPE_I4: \
case MONO_TYPE_I8: \
*(etype *) ea = (etype) i64; \
goto leave; \
case MONO_TYPE_U1: \
case MONO_TYPE_U2: \
case MONO_TYPE_U4: \
case MONO_TYPE_U8: \
case MONO_TYPE_CHAR: \
*(etype *) ea = (etype) u64; \
goto leave; \
} \
}G_STMT_END
switch (vt) {
case MONO_TYPE_U1:
u64 = *(guint8 *) va;
break;
case MONO_TYPE_U2:
u64 = *(guint16 *) va;
break;
case MONO_TYPE_U4:
u64 = *(guint32 *) va;
break;
case MONO_TYPE_U8:
u64 = *(guint64 *) va;
break;
case MONO_TYPE_I1:
i64 = *(gint8 *) va;
break;
case MONO_TYPE_I2:
i64 = *(gint16 *) va;
break;
case MONO_TYPE_I4:
i64 = *(gint32 *) va;
break;
case MONO_TYPE_I8:
i64 = *(gint64 *) va;
break;
case MONO_TYPE_R4:
r64 = *(gfloat *) va;
break;
case MONO_TYPE_R8:
r64 = *(gdouble *) va;
break;
case MONO_TYPE_CHAR:
u64 = *(guint16 *) va;
break;
case MONO_TYPE_BOOLEAN:
/* Boolean is only compatible with itself. */
switch (et) {
case MONO_TYPE_CHAR:
case MONO_TYPE_U1:
case MONO_TYPE_U2:
case MONO_TYPE_U4:
case MONO_TYPE_U8:
case MONO_TYPE_I1:
case MONO_TYPE_I2:
case MONO_TYPE_I4:
case MONO_TYPE_I8:
case MONO_TYPE_R4:
case MONO_TYPE_R8:
NO_WIDENING_CONVERSION;
default:
INVALID_CAST;
}
break;
}
/* If we can't do a direct copy, let's try a widening conversion. */
switch (et) {
case MONO_TYPE_CHAR:
ASSIGN_UNSIGNED (guint16);
case MONO_TYPE_U1:
ASSIGN_UNSIGNED (guint8);
case MONO_TYPE_U2:
ASSIGN_UNSIGNED (guint16);
case MONO_TYPE_U4:
ASSIGN_UNSIGNED (guint32);
case MONO_TYPE_U8:
ASSIGN_UNSIGNED (guint64);
case MONO_TYPE_I1:
ASSIGN_SIGNED (gint8);
case MONO_TYPE_I2:
ASSIGN_SIGNED (gint16);
case MONO_TYPE_I4:
ASSIGN_SIGNED (gint32);
case MONO_TYPE_I8:
ASSIGN_SIGNED (gint64);
case MONO_TYPE_R4:
ASSIGN_REAL (gfloat);
case MONO_TYPE_R8:
ASSIGN_REAL (gdouble);
}
INVALID_CAST;
/* Not reached, INVALID_CAST does fall thru. */
g_assert_not_reached ();
#undef INVALID_CAST
#undef NO_WIDENING_CONVERSION
#undef CHECK_WIDENING_CONVERSION
#undef ASSIGN_UNSIGNED
#undef ASSIGN_SIGNED
#undef ASSIGN_REAL
leave:
if (arr_gchandle)
mono_gchandle_free (arr_gchandle);
if (value_gchandle)
mono_gchandle_free (value_gchandle);
return;
}
ICALL_EXPORT void
ves_icall_System_Array_SetValue (MonoArrayHandle arr, MonoObjectHandle value,
MonoArrayHandle idxs, MonoError *error)
{
MonoArrayBounds dim;
MonoClass *ac, *ic;
gint32 idx;
gint32 i, pos;
error_init (error);
if (MONO_HANDLE_IS_NULL (idxs)) {
mono_error_set_argument_null (error, "idxs", "");
return;
}
ic = mono_handle_class (idxs);
ac = mono_handle_class (arr);
g_assert (ic->rank == 1);
if (mono_handle_array_has_bounds (idxs) || MONO_HANDLE_GETVAL (idxs, max_length) != ac->rank) {
mono_error_set_argument (error, "idxs", "");
return;
}
if (!mono_handle_array_has_bounds (arr)) {
MONO_HANDLE_ARRAY_GETVAL (idx, idxs, gint32, 0);
if (idx < 0 || idx >= MONO_HANDLE_GETVAL (arr, max_length)) {
mono_error_set_exception_instance (error, mono_get_exception_index_out_of_range ());
return;
}
array_set_value_impl (arr, value, idx, error);
return;
}
for (i = 0; i < ac->rank; i++) {
mono_handle_array_get_bounds_dim (arr, i, &dim);
MONO_HANDLE_ARRAY_GETVAL (idx, idxs, gint32, i);
if ((idx < dim.lower_bound) ||
(idx >= (mono_array_lower_bound_t)dim.length + dim.lower_bound)) {
mono_error_set_exception_instance (error, mono_get_exception_index_out_of_range ());
return;
}
}
MONO_HANDLE_ARRAY_GETVAL (idx, idxs, gint32, 0);
mono_handle_array_get_bounds_dim (arr, 0, &dim);
pos = idx - dim.lower_bound;
for (i = 1; i < ac->rank; i++) {
mono_handle_array_get_bounds_dim (arr, i, &dim);
MONO_HANDLE_ARRAY_GETVAL (idx, idxs, gint32, i);
pos = pos * dim.length + idx - dim.lower_bound;
}
array_set_value_impl (arr, value, pos, error);
}
ICALL_EXPORT MonoArray *
ves_icall_System_Array_CreateInstanceImpl (MonoReflectionType *type, MonoArray *lengths, MonoArray *bounds)
{
MonoError error;
MonoClass *aklass, *klass;
MonoArray *array;
uintptr_t *sizes, i;
gboolean bounded = FALSE;
MONO_CHECK_ARG_NULL (type, NULL);
MONO_CHECK_ARG_NULL (lengths, NULL);
MONO_CHECK_ARG (lengths, mono_array_length (lengths) > 0, NULL);
if (bounds)
MONO_CHECK_ARG (bounds, mono_array_length (lengths) == mono_array_length (bounds), NULL);
for (i = 0; i < mono_array_length (lengths); i++) {
if (mono_array_get (lengths, gint32, i) < 0) {
mono_set_pending_exception (mono_get_exception_argument_out_of_range (NULL));
return NULL;
}
}
klass = mono_class_from_mono_type (type->type);
mono_class_init_checked (klass, &error);
if (mono_error_set_pending_exception (&error))
return NULL;
if (klass->element_class->byval_arg.type == MONO_TYPE_VOID) {
mono_set_pending_exception (mono_get_exception_not_supported ("Arrays of System.Void are not supported."));
return NULL;
}
if (bounds && (mono_array_length (bounds) == 1) && (mono_array_get (bounds, gint32, 0) != 0))
/* vectors are not the same as one dimensional arrays with no-zero bounds */
bounded = TRUE;
else
bounded = FALSE;
aklass = mono_bounded_array_class_get (klass, mono_array_length (lengths), bounded);
sizes = (uintptr_t *)alloca (aklass->rank * sizeof(intptr_t) * 2);
for (i = 0; i < aklass->rank; ++i) {
sizes [i] = mono_array_get (lengths, guint32, i);
if (bounds)
sizes [i + aklass->rank] = mono_array_get (bounds, gint32, i);
else
sizes [i + aklass->rank] = 0;
}
array = mono_array_new_full_checked (mono_object_domain (type), aklass, sizes, (intptr_t*)sizes + aklass->rank, &error);
mono_error_set_pending_exception (&error);
return array;
}
ICALL_EXPORT MonoArray *
ves_icall_System_Array_CreateInstanceImpl64 (MonoReflectionType *type, MonoArray *lengths, MonoArray *bounds)
{
MonoError error;
MonoClass *aklass, *klass;
MonoArray *array;
uintptr_t *sizes, i;
gboolean bounded = FALSE;
MONO_CHECK_ARG_NULL (type, NULL);
MONO_CHECK_ARG_NULL (lengths, NULL);
MONO_CHECK_ARG (lengths, mono_array_length (lengths) > 0, NULL);
if (bounds)
MONO_CHECK_ARG (bounds, mono_array_length (lengths) == mono_array_length (bounds), NULL);
for (i = 0; i < mono_array_length (lengths); i++) {
if ((mono_array_get (lengths, gint64, i) < 0) ||
(mono_array_get (lengths, gint64, i) > MONO_ARRAY_MAX_INDEX)) {
mono_set_pending_exception (mono_get_exception_argument_out_of_range (NULL));
return NULL;
}
}
klass = mono_class_from_mono_type (type->type);
mono_class_init_checked (klass, &error);
if (mono_error_set_pending_exception (&error))
return NULL;
if (bounds && (mono_array_length (bounds) == 1) && (mono_array_get (bounds, gint64, 0) != 0))
/* vectors are not the same as one dimensional arrays with no-zero bounds */
bounded = TRUE;
else
bounded = FALSE;
aklass = mono_bounded_array_class_get (klass, mono_array_length (lengths), bounded);
sizes = (uintptr_t *)alloca (aklass->rank * sizeof(intptr_t) * 2);
for (i = 0; i < aklass->rank; ++i) {
sizes [i] = mono_array_get (lengths, guint64, i);
if (bounds)
sizes [i + aklass->rank] = (mono_array_size_t) mono_array_get (bounds, guint64, i);
else
sizes [i + aklass->rank] = 0;
}
array = mono_array_new_full_checked (mono_object_domain (type), aklass, sizes, (intptr_t*)sizes + aklass->rank, &error);
mono_error_set_pending_exception (&error);
return array;
}
ICALL_EXPORT gint32
ves_icall_System_Array_GetRank (MonoObject *arr)
{
return arr->vtable->klass->rank;
}
ICALL_EXPORT gint32
ves_icall_System_Array_GetLength (MonoArray *arr, gint32 dimension)
{
gint32 rank = arr->obj.vtable->klass->rank;
uintptr_t length;
if ((dimension < 0) || (dimension >= rank)) {
mono_set_pending_exception (mono_get_exception_index_out_of_range ());
return 0;
}
if (arr->bounds == NULL)
length = arr->max_length;
else
length = arr->bounds [dimension].length;
#ifdef MONO_BIG_ARRAYS
if (length > G_MAXINT32) {
mono_set_pending_exception (mono_get_exception_overflow ());
return 0;
}
#endif
return length;
}
ICALL_EXPORT gint64
ves_icall_System_Array_GetLongLength (MonoArray *arr, gint32 dimension)
{
gint32 rank = arr->obj.vtable->klass->rank;
if ((dimension < 0) || (dimension >= rank)) {
mono_set_pending_exception (mono_get_exception_index_out_of_range ());
return 0;
}
if (arr->bounds == NULL)
return arr->max_length;
return arr->bounds [dimension].length;
}
ICALL_EXPORT gint32
ves_icall_System_Array_GetLowerBound (MonoArray *arr, gint32 dimension)
{
gint32 rank = arr->obj.vtable->klass->rank;
if ((dimension < 0) || (dimension >= rank)) {
mono_set_pending_exception (mono_get_exception_index_out_of_range ());
return 0;
}
if (arr->bounds == NULL)
return 0;
return arr->bounds [dimension].lower_bound;
}
ICALL_EXPORT void
ves_icall_System_Array_ClearInternal (MonoArray *arr, int idx, int length)
{
int sz = mono_array_element_size (mono_object_class (arr));
mono_gc_bzero_atomic (mono_array_addr_with_size_fast (arr, sz, idx), length * sz);
}
ICALL_EXPORT gboolean
ves_icall_System_Array_FastCopy (MonoArray *source, int source_idx, MonoArray* dest, int dest_idx, int length)
{
int element_size;
void * dest_addr;
void * source_addr;
MonoVTable *src_vtable;
MonoVTable *dest_vtable;
MonoClass *src_class;
MonoClass *dest_class;
src_vtable = source->obj.vtable;
dest_vtable = dest->obj.vtable;
if (src_vtable->rank != dest_vtable->rank)
return FALSE;
if (source->bounds || dest->bounds)
return FALSE;
/* there's no integer overflow since mono_array_length returns an unsigned integer */
if ((dest_idx + length > mono_array_length_fast (dest)) ||
(source_idx + length > mono_array_length_fast (source)))
return FALSE;
src_class = src_vtable->klass->element_class;
dest_class = dest_vtable->klass->element_class;
/*
* Handle common cases.
*/
/* Case1: object[] -> valuetype[] (ArrayList::ToArray)
We fallback to managed here since we need to typecheck each boxed valuetype before storing them in the dest array.
*/
if (src_class == mono_defaults.object_class && dest_class->valuetype)
return FALSE;
/* Check if we're copying a char[] <==> (u)short[] */
if (src_class != dest_class) {
if (dest_class->valuetype || dest_class->enumtype || src_class->valuetype || src_class->enumtype)
return FALSE;
/* It's only safe to copy between arrays if we can ensure the source will always have a subtype of the destination. We bail otherwise. */
if (!mono_class_is_subclass_of (src_class, dest_class, FALSE))
return FALSE;
}
if (dest_class->valuetype) {
element_size = mono_array_element_size (source->obj.vtable->klass);
source_addr = mono_array_addr_with_size_fast (source, element_size, source_idx);
if (dest_class->has_references) {
mono_value_copy_array (dest, dest_idx, source_addr, length);
} else {
dest_addr = mono_array_addr_with_size_fast (dest, element_size, dest_idx);
mono_gc_memmove_atomic (dest_addr, source_addr, element_size * length);
}
} else {
mono_array_memcpy_refs_fast (dest, dest_idx, source, source_idx, length);
}
return TRUE;
}
ICALL_EXPORT void
ves_icall_System_Array_GetGenericValueImpl (MonoArray *arr, guint32 pos, gpointer value)
{
MonoClass *ac;
gint32 esize;
gpointer *ea;
ac = (MonoClass *)arr->obj.vtable->klass;
esize = mono_array_element_size (ac);
ea = (gpointer*)((char*)arr->vector + (pos * esize));
mono_gc_memmove_atomic (value, ea, esize);
}
ICALL_EXPORT void
ves_icall_System_Array_SetGenericValueImpl (MonoArray *arr, guint32 pos, gpointer value)
{
MonoClass *ac, *ec;
gint32 esize;
gpointer *ea;
ac = (MonoClass *)arr->obj.vtable->klass;
ec = ac->element_class;
esize = mono_array_element_size (ac);
ea = (gpointer*)((char*)arr->vector + (pos * esize));
if (MONO_TYPE_IS_REFERENCE (&ec->byval_arg)) {
g_assert (esize == sizeof (gpointer));
mono_gc_wbarrier_generic_store (ea, *(MonoObject **)value);
} else {
g_assert (ec->inited);
g_assert (esize == mono_class_value_size (ec, NULL));
if (ec->has_references)
mono_gc_wbarrier_value_copy (ea, value, 1, ec);
else
mono_gc_memmove_atomic (ea, value, esize);
}
}
ICALL_EXPORT void
ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_InitializeArray (MonoArrayHandle array, MonoClassField *field_handle, MonoError *error)
{
error_init (error);
MonoClass *klass = mono_handle_class (array);
guint32 size = mono_array_element_size (klass);
MonoType *type = mono_type_get_underlying_type (&klass->element_class->byval_arg);
int align;
const char *field_data;
if (MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VALUETYPE) {
mono_error_set_argument (error, "array", "Cannot initialize array of non-primitive type");
return;
}
if (!(field_handle->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
mono_error_set_argument (error, "field_handle", "Field '%s' doesn't have an RVA", mono_field_get_name (field_handle));
return;
}
size *= MONO_HANDLE_GETVAL(array, max_length);
field_data = mono_field_get_data (field_handle);
if (size > mono_type_size (field_handle->type, &align)) {
mono_error_set_argument (error, "field_handle", "Field not large enough to fill array");
return;
}
#if G_BYTE_ORDER != G_LITTLE_ENDIAN
#define SWAP(n) { \
guint ## n *data = (guint ## n *) mono_array_addr (MONO_HANDLE_RAW(array), char, 0); \
guint ## n *src = (guint ## n *) field_data; \
int i, \
nEnt = (size / sizeof(guint ## n)); \
\
for (i = 0; i < nEnt; i++) { \
data[i] = read ## n (&src[i]); \
} \
}
/* printf ("Initialize array with elements of %s type\n", klass->element_class->name); */
switch (type->type) {
case MONO_TYPE_CHAR:
case MONO_TYPE_I2:
case MONO_TYPE_U2:
SWAP (16);
break;
case MONO_TYPE_I4:
case MONO_TYPE_U4:
case MONO_TYPE_R4:
SWAP (32);
break;
case MONO_TYPE_I8:
case MONO_TYPE_U8:
case MONO_TYPE_R8:
SWAP (64);
break;
default:
memcpy (mono_array_addr (MONO_HANDLE_RAW(array), char, 0), field_data, size);
break;
}
#else
memcpy (mono_array_addr (MONO_HANDLE_RAW(array), char, 0), field_data, size);
#endif
}
ICALL_EXPORT gint
ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_GetOffsetToStringData (void)
{
return offsetof (MonoString, chars);
}
ICALL_EXPORT MonoObject *
ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_GetObjectValue (MonoObject *obj)
{
if ((obj == NULL) || (! (obj->vtable->klass->valuetype)))
return obj;
else {
MonoError error;
MonoObject *ret = mono_object_clone_checked (obj, &error);
mono_error_set_pending_exception (&error);
return ret;
}
}
ICALL_EXPORT void
ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_RunClassConstructor (MonoType *handle)
{
MonoError error;
MonoClass *klass;
MonoVTable *vtable;
MONO_CHECK_ARG_NULL (handle,);
klass = mono_class_from_mono_type (handle);
MONO_CHECK_ARG (handle, klass,);
if (mono_class_is_gtd (klass))
return;
vtable = mono_class_vtable_full (mono_domain_get (), klass, &error);
if (!is_ok (&error)) {
mono_error_set_pending_exception (&error);
return;
}
/* This will call the type constructor */
if (!mono_runtime_class_init_full (vtable, &error))
mono_error_set_pending_exception (&error);
}
ICALL_EXPORT void
ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_RunModuleConstructor (MonoImage *image)
{
MonoError error;
mono_image_check_for_module_cctor (image);
if (image->has_module_cctor) {
MonoClass *module_klass = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | 1, &error);
if (!mono_error_ok (&error)) {
mono_error_set_pending_exception (&error);
return;
}
/*It's fine to raise the exception here*/
MonoVTable * vtable = mono_class_vtable_full (mono_domain_get (), module_klass, &error);
if (!is_ok (&error)) {
mono_error_set_pending_exception (&error);
return;
}
if (!mono_runtime_class_init_full (vtable, &error))
mono_error_set_pending_exception (&error);
}
}
ICALL_EXPORT MonoBoolean
ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_SufficientExecutionStack (void)
{
#if defined(TARGET_WIN32) || defined(HOST_WIN32)
// It does not work on win32
#elif defined(TARGET_ANDROID)
// No need for now
#else
guint8 *stack_addr;
guint8 *current;
size_t stack_size;
int min_size;
MonoInternalThread *thread;
mono_thread_info_get_stack_bounds (&stack_addr, &stack_size);
/* if we have no info we are optimistic and assume there is enough room */
if (!stack_addr)
return TRUE;
thread = mono_thread_internal_current ();
// .net seems to check that at least 50% of stack is available
min_size = thread->stack_size / 2;
// TODO: It's not always set
if (!min_size)
return TRUE;
current = (guint8 *)&stack_addr;
if (current > stack_addr) {
if ((current - stack_addr) < min_size)
return FALSE;
} else {
if (current - (stack_addr - stack_size) < min_size)
return FALSE;
}
#endif
return TRUE;
}
ICALL_EXPORT MonoObject *
ves_icall_System_Object_MemberwiseClone (MonoObject *this_obj)
{
MonoError error;
MonoObject *ret = mono_object_clone_checked (this_obj, &error);
mono_error_set_pending_exception (&error);
return ret;
}
ICALL_EXPORT gint32
ves_icall_System_ValueType_InternalGetHashCode (MonoObject *this_obj, MonoArray **fields)
{
MonoError error;
MonoClass *klass;
MonoObject **values = NULL;
MonoObject *o;
int count = 0;
gint32 result = (int)(gsize)mono_defaults.int32_class;
MonoClassField* field;
gpointer iter;
klass = mono_object_class (this_obj);
if (mono_class_num_fields (klass) == 0)
return result;
/*
* Compute the starting value of the hashcode for fields of primitive
* types, and return the remaining fields in an array to the managed side.
* This way, we can avoid costly reflection operations in managed code.
*/
iter = NULL;
while ((field = mono_class_get_fields (klass, &iter))) {
if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
continue;
if (mono_field_is_deleted (field))
continue;
/* FIXME: Add more types */
switch (field->type->type) {
case MONO_TYPE_I4:
result ^= *(gint32*)((guint8*)this_obj + field->offset);
break;
case MONO_TYPE_STRING: {
MonoString *s;
s = *(MonoString**)((guint8*)this_obj + field->offset);
if (s != NULL)
result ^= mono_string_hash (s);
break;
}
default:
if (!values)
values = g_newa (MonoObject*, mono_class_num_fields (klass));
o = mono_field_get_value_object_checked (mono_object_domain (this_obj), field, this_obj, &error);
if (!is_ok (&error)) {
mono_error_set_pending_exception (&error);
return 0;
}
values [count++] = o;
}
}
if (values) {
int i;
MonoArray *fields_arr = mono_array_new_checked (mono_domain_get (), mono_defaults.object_class, count, &error);
if (mono_error_set_pending_exception (&error))
return 0;
mono_gc_wbarrier_generic_store (fields, (MonoObject*) fields_arr);
for (i = 0; i < count; ++i)
mono_array_setref (*fields, i, values [i]);
} else {
*fields = NULL;
}
return result;
}
ICALL_EXPORT MonoBoolean
ves_icall_System_ValueType_Equals (MonoObject *this_obj, MonoObject *that, MonoArray **fields)
{
MonoError error;
MonoClass *klass;
MonoObject **values = NULL;
MonoObject *o;
MonoClassField* field;
gpointer iter;
int count = 0;
MONO_CHECK_ARG_NULL (that, FALSE);
if (this_obj->vtable != that->vtable)
return FALSE;
klass = mono_object_class (this_obj);
if (klass->enumtype && mono_class_enum_basetype (klass) && mono_class_enum_basetype (klass)->type == MONO_TYPE_I4)
return (*(gint32*)((guint8*)this_obj + sizeof (MonoObject)) == *(gint32*)((guint8*)that + sizeof (MonoObject)));
/*
* Do the comparison for fields of primitive type and return a result if
* possible. Otherwise, return the remaining fields in an array to the
* managed side. This way, we can avoid costly reflection operations in
* managed code.
*/
*fields = NULL;
iter = NULL;
while ((field = mono_class_get_fields (klass, &iter))) {
if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
continue;
if (mono_field_is_deleted (field))
continue;
/* FIXME: Add more types */
switch (field->type->type) {
case MONO_TYPE_U1:
case MONO_TYPE_I1:
case MONO_TYPE_BOOLEAN:
if (*((guint8*)this_obj + field->offset) != *((guint8*)that + field->offset))
return FALSE;
break;
case MONO_TYPE_U2:
case MONO_TYPE_I2:
case MONO_TYPE_CHAR:
if (*(gint16*)((guint8*)this_obj + field->offset) != *(gint16*)((guint8*)that + field->offset))
return FALSE;
break;
case MONO_TYPE_U4:
case MONO_TYPE_I4:
if (*(gint32*)((guint8*)this_obj + field->offset) != *(gint32*)((guint8*)that + field->offset))
return FALSE;
break;
case MONO_TYPE_U8:
case MONO_TYPE_I8:
if (*(gint64*)((guint8*)this_obj + field->offset) != *(gint64*)((guint8*)that + field->offset))
return FALSE;
break;
case MONO_TYPE_R4:
if (*(float*)((guint8*)this_obj + field->offset) != *(float*)((guint8*)that + field->offset))
return FALSE;
break;
case MONO_TYPE_R8:
if (*(double*)((guint8*)this_obj + field->offset) != *(double*)((guint8*)that + field->offset))
return FALSE;
break;
case MONO_TYPE_STRING: {
MonoString *s1, *s2;
guint32 s1len, s2len;
s1 = *(MonoString**)((guint8*)this_obj + field->offset);
s2 = *(MonoString**)((guint8*)that + field->offset);
if (s1 == s2)
break;
if ((s1 == NULL) || (s2 == NULL))
return FALSE;
s1len = mono_string_length (s1);
s2len = mono_string_length (s2);
if (s1len != s2len)
return FALSE;
if (memcmp (mono_string_chars (s1), mono_string_chars (s2), s1len * sizeof (gunichar2)) != 0)
return FALSE;
break;
}
default:
if (!values)
values = g_newa (MonoObject*, mono_class_num_fields (klass) * 2);
o = mono_field_get_value_object_checked (mono_object_domain (this_obj), field, this_obj, &error);
if (!is_ok (&error)) {
mono_error_set_pending_exception (&error);
return FALSE;
}
values [count++] = o;
o = mono_field_get_value_object_checked (mono_object_domain (this_obj), field, that, &error);
if (!is_ok (&error)) {
mono_error_set_pending_exception (&error);
return FALSE;
}
values [count++] = o;
}
if (klass->enumtype)
/* enums only have one non-static field */
break;
}
if (values) {
int i;
MonoArray *fields_arr = mono_array_new_checked (mono_domain_get (), mono_defaults.object_class, count, &error);
if (mono_error_set_pending_exception (&error))
return FALSE;
mono_gc_wbarrier_generic_store (fields, (MonoObject*) fields_arr);
for (i = 0; i < count; ++i)
mono_array_setref_fast (*fields, i, values [i]);
return FALSE;
} else {
return TRUE;
}
}
ICALL_EXPORT MonoReflectionTypeHandle
ves_icall_System_Object_GetType (MonoObjectHandle obj, MonoError *error)
{
error_init (error);
MonoDomain *domain = MONO_HANDLE_DOMAIN (obj);
MonoClass *klass = mono_handle_class (obj);
#ifndef DISABLE_REMOTING
if (mono_class_is_transparent_proxy (klass)) {
MonoTransparentProxyHandle proxy_obj = MONO_HANDLE_CAST (MonoTransparentProxy, obj);
MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (proxy_obj, remote_class);
MonoType *proxy_type = &remote_class->proxy_class->byval_arg;
return mono_type_get_object_handle (domain, proxy_type, error);
} else
#endif
return mono_type_get_object_handle (domain, &klass->byval_arg, error);
}
static gboolean
get_executing (MonoMethod *m, gint32 no, gint32 ilo, gboolean managed, gpointer data)
{
MonoMethod **dest = (MonoMethod **)data;
/* skip unmanaged frames */
if (!managed)
return FALSE;
if (!(*dest)) {
if (!strcmp (m->klass->name_space, "System.Reflection"))
return FALSE;
*dest = m;
return TRUE;
}
return FALSE;
}
static gboolean
get_caller_no_reflection (MonoMethod *m, gint32 no, gint32 ilo, gboolean managed, gpointer data)
{
MonoMethod **dest = (MonoMethod **)data;
/* skip unmanaged frames */
if (!managed)
return FALSE;
if (m->wrapper_type != MONO_WRAPPER_NONE)
return FALSE;
if (m == *dest) {
*dest = NULL;
return FALSE;
}
if (m->klass->image == mono_defaults.corlib && !strcmp (m->klass->name_space, "System.Reflection"))
return FALSE;
if (!(*dest)) {
*dest = m;
return TRUE;
}
return FALSE;
}
static gboolean
get_caller_no_system_or_reflection (MonoMethod *m, gint32 no, gint32 ilo, gboolean managed, gpointer data)
{
MonoMethod **dest = (MonoMethod **)data;
/* skip unmanaged frames */
if (!managed)
return FALSE;
if (m->wrapper_type != MONO_WRAPPER_NONE)
return FALSE;
if (m == *dest) {
*dest = NULL;
return FALSE;
}
if (m->klass->image == mono_defaults.corlib && ((!strcmp (m->klass->name_space, "System.Reflection"))
|| (!strcmp (m->klass->name_space, "System"))))
return FALSE;
if (!(*dest)) {
*dest = m;
return TRUE;
}
return FALSE;
}
static MonoReflectionTypeHandle
type_from_parsed_name (MonoTypeNameParse *info, MonoBoolean ignoreCase, MonoAssembly **caller_assembly, MonoError *error)
{
MonoMethod *m, *dest;
MonoType *type = NULL;
MonoAssembly *assembly = NULL;
gboolean type_resolve = FALSE;
MonoImage *rootimage = NULL;
error_init (error);
/*
* We must compute the calling assembly as type loading must happen under a metadata context.
* For example. The main assembly is a.exe and Type.GetType is called from dir/b.dll. Without
* the metadata context (basedir currently) set to dir/b.dll we won't be able to load a dir/c.dll.
*/
m = mono_method_get_last_managed ();
dest = m;
if (m && m->klass->image != mono_defaults.corlib) {
/* Happens with inlining */
} else {
/* Ugly hack: type_from_parsed_name is called from
* System.Type.internal_from_name, which is called most
* directly from System.Type.GetType(string,bool,bool) but
* also indirectly from places such as
* System.Type.GetType(string,func,func) (via
* System.TypeNameParser.GetType and System.TypeSpec.Resolve)
* so we need to skip over all of those to find the true caller.
*
* It would be nice if we had stack marks.
*/
mono_stack_walk_no_il (get_caller_no_system_or_reflection, &dest);
if (!dest)
dest = m;
}
/*
* FIXME: mono_method_get_last_managed() sometimes returns NULL, thus
* causing ves_icall_System_Reflection_Assembly_GetCallingAssembly()
* to crash. This only seems to happen in some strange remoting
* scenarios and I was unable to figure out what's happening there.
* Dec 10, 2005 - Martin.
*/
if (dest) {
assembly = dest->klass->image->assembly;
type_resolve = TRUE;
rootimage = assembly->image;
} else {
g_warning (G_STRLOC);
}
*caller_assembly = assembly;
if (info->assembly.name)
assembly = mono_assembly_load (&info->assembly, assembly ? assembly->basedir : NULL, NULL);
if (assembly) {
/* When loading from the current assembly, AppDomain.TypeResolve will not be called yet */
type = mono_reflection_get_type_checked (rootimage, assembly->image, info, ignoreCase, &type_resolve, error);
if (!is_ok (error))
goto fail;
}
// XXXX - aleksey -
// Say we're looking for System.Generic.Dict<int, Local>
// we FAIL the get type above, because S.G.Dict isn't in assembly->image. So we drop down here.
// but then we FAIL AGAIN because now we pass null as the image and the rootimage and everything
// is messed up when we go to construct the Local as the type arg...
//
// By contrast, if we started with Mine<System.Generic.Dict<int, Local>> we'd go in with assembly->image
// as the root and then even the detour into generics would still not screw us when we went to load Local.
if (!info->assembly.name && !type) {
/* try mscorlib */
type = mono_reflection_get_type_checked (rootimage, NULL, info, ignoreCase, &type_resolve, error);
if (!is_ok (error))
goto fail;
}
if (assembly && !type && type_resolve) {
type_resolve = FALSE; /* This will invoke TypeResolve if not done in the first 'if' */
type = mono_reflection_get_type_checked (rootimage, assembly->image, info, ignoreCase, &type_resolve, error);
if (!is_ok (error))
goto fail;
}
if (!type)
goto fail;
return mono_type_get_object_handle (mono_domain_get (), type, error);
fail:
return MONO_HANDLE_NEW (MonoReflectionType, NULL);
}
ICALL_EXPORT MonoReflectionTypeHandle
ves_icall_System_Type_internal_from_name (MonoStringHandle name,
MonoBoolean throwOnError,
MonoBoolean ignoreCase,
MonoError *error)
{
error_init (error);
MonoTypeNameParse info;
gboolean parsedOk;
MonoAssembly *caller_assembly;
MonoReflectionTypeHandle type = MONO_HANDLE_NEW (MonoReflectionType, NULL);
char *str = mono_string_handle_to_utf8 (name, error);
if (!is_ok (error))
goto leave;
parsedOk = mono_reflection_parse_type (str, &info);
/* mono_reflection_parse_type() mangles the string */
if (!parsedOk) {
mono_reflection_free_type_info (&info);
if (throwOnError)
mono_error_set_argument (error, "typeName", "failed parse: %s", str);
goto leave;
}
MONO_HANDLE_ASSIGN (type, type_from_parsed_name (&info, ignoreCase, &caller_assembly, error));
if (!is_ok (error)) {
mono_reflection_free_type_info (&info);
goto leave;
}
if (MONO_HANDLE_IS_NULL (type)) {
if (throwOnError) {
char *tname = info.name_space ? g_strdup_printf ("%s.%s", info.name_space, info.name) : g_strdup (info.name);
char *aname;
if (info.assembly.name)
aname = mono_stringify_assembly_name (&info.assembly);
else if (caller_assembly)
aname = mono_stringify_assembly_name (mono_assembly_get_name (caller_assembly));
else
aname = g_strdup ("");
mono_error_set_type_load_name (error, tname, aname, "");
}
mono_reflection_free_type_info (&info);
goto leave;
}
leave:
g_free (str);
if (!is_ok (error)) {
if (!throwOnError)
mono_error_cleanup (error);
return MONO_HANDLE_CAST (MonoReflectionType, NULL_HANDLE);
}
return type;
}
ICALL_EXPORT MonoReflectionTypeHandle
ves_icall_System_Type_internal_from_handle (MonoType *handle, MonoError *error)
{
error_init (error);
MonoDomain *domain = mono_domain_get ();
return mono_type_get_object_handle (domain, handle, error);
}
ICALL_EXPORT MonoType*
ves_icall_Mono_RuntimeClassHandle_GetTypeFromClass (MonoClass *klass)
{
return mono_class_get_type (klass);
}
ICALL_EXPORT void
ves_icall_Mono_RuntimeGPtrArrayHandle_GPtrArrayFree (GPtrArray *ptr_array)
{
g_ptr_array_free (ptr_array, TRUE);
}
ICALL_EXPORT void
ves_icall_Mono_SafeStringMarshal_GFree (void *c_str)
{
g_free (c_str);
}
ICALL_EXPORT char*
ves_icall_Mono_SafeStringMarshal_StringToUtf8 (MonoString *s)
{
MonoError error;
char *res = mono_string_to_utf8_checked (s, &error);
mono_error_set_pending_exception (&error);
return res;
}
/* System.TypeCode */
typedef enum {
TYPECODE_EMPTY,
TYPECODE_OBJECT,
TYPECODE_DBNULL,
TYPECODE_BOOLEAN,
TYPECODE_CHAR,
TYPECODE_SBYTE,
TYPECODE_BYTE,
TYPECODE_INT16,
TYPECODE_UINT16,
TYPECODE_INT32,
TYPECODE_UINT32,
TYPECODE_INT64,
TYPECODE_UINT64,
TYPECODE_SINGLE,
TYPECODE_DOUBLE,
TYPECODE_DECIMAL,
TYPECODE_DATETIME,
TYPECODE_STRING = 18
} TypeCode;
ICALL_EXPORT guint32
ves_icall_type_GetTypeCodeInternal (MonoReflectionTypeHandle ref_type, MonoError *error)
{
error_init (error);
MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
int t = type->type;
if (type->byref)
return TYPECODE_OBJECT;
handle_enum:
switch (t) {
case MONO_TYPE_VOID:
return TYPECODE_OBJECT;
case MONO_TYPE_BOOLEAN:
return TYPECODE_BOOLEAN;
case MONO_TYPE_U1:
return TYPECODE_BYTE;
case MONO_TYPE_I1:
return TYPECODE_SBYTE;
case MONO_TYPE_U2:
return TYPECODE_UINT16;
case MONO_TYPE_I2:
return TYPECODE_INT16;
case MONO_TYPE_CHAR:
return TYPECODE_CHAR;
case MONO_TYPE_PTR:
case MONO_TYPE_U:
case MONO_TYPE_I:
return TYPECODE_OBJECT;
case MONO_TYPE_U4:
return TYPECODE_UINT32;
case MONO_TYPE_I4:
return TYPECODE_INT32;
case MONO_TYPE_U8:
return TYPECODE_UINT64;
case MONO_TYPE_I8:
return TYPECODE_INT64;
case MONO_TYPE_R4:
return TYPECODE_SINGLE;
case MONO_TYPE_R8:
return TYPECODE_DOUBLE;
case MONO_TYPE_VALUETYPE: {
MonoClass *klass = type->data.klass;
if (klass->enumtype) {
t = mono_class_enum_basetype (klass)->type;
goto handle_enum;
} else if (mono_is_corlib_image (klass->image)) {
if (strcmp (klass->name_space, "System") == 0) {
if (strcmp (klass->name, "Decimal") == 0)
return TYPECODE_DECIMAL;
else if (strcmp (klass->name, "DateTime") == 0)
return TYPECODE_DATETIME;
}
}
return TYPECODE_OBJECT;
}
case MONO_TYPE_STRING:
return TYPECODE_STRING;
case MONO_TYPE_SZARRAY:
case MONO_TYPE_ARRAY:
case MONO_TYPE_OBJECT:
case MONO_TYPE_VAR:
case MONO_TYPE_MVAR:
case MONO_TYPE_TYPEDBYREF:
return TYPECODE_OBJECT;
case MONO_TYPE_CLASS:
{
MonoClass *klass = type->data.klass;
if (klass->image == mono_defaults.corlib && strcmp (klass->name_space, "System") == 0) {
if (strcmp (klass->name, "DBNull") == 0)
return TYPECODE_DBNULL;
}
}
return TYPECODE_OBJECT;
case MONO_TYPE_GENERICINST:
return TYPECODE_OBJECT;
default:
g_error ("type 0x%02x not handled in GetTypeCode()", t);
}
return 0;
}
static MonoType*
mono_type_get_underlying_type_ignore_byref (MonoType *type)
{
if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype)
return mono_class_enum_basetype (type->data.klass);
if (type->type == MONO_TYPE_GENERICINST && type->data.generic_class->container_class->enumtype)
return mono_class_enum_basetype (type->data.generic_class->container_class);
return type;
}
ICALL_EXPORT guint32
ves_icall_RuntimeTypeHandle_type_is_assignable_from (MonoReflectionTypeHandle ref_type, MonoReflectionTypeHandle ref_c, MonoError *error)
{
error_init (error);
g_assert (!MONO_HANDLE_IS_NULL (ref_type));
MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
MonoClass *klass = mono_class_from_mono_type (type);
MonoType *ctype = MONO_HANDLE_GETVAL (ref_c, type);
MonoClass *klassc = mono_class_from_mono_type (ctype);
if (type->byref ^ ctype->byref)
return FALSE;
if (type->byref) {
MonoType *t = mono_type_get_underlying_type_ignore_byref (type);
MonoType *ot = mono_type_get_underlying_type_ignore_byref (ctype);
klass = mono_class_from_mono_type (t);
klassc = mono_class_from_mono_type (ot);
if (mono_type_is_primitive (t)) {
return mono_type_is_primitive (ot) && klass->instance_size == klassc->instance_size;
} else if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) {
return t->type == ot->type && t->data.generic_param->num == ot->data.generic_param->num;
} else if (t->type == MONO_TYPE_PTR || t->type == MONO_TYPE_FNPTR) {
return t->type == ot->type;
} else {
if (ot->type == MONO_TYPE_VAR || ot->type == MONO_TYPE_MVAR)
return FALSE;
if (klass->valuetype)
return klass == klassc;
return klass->valuetype == klassc->valuetype;
}
}
return mono_class_is_assignable_from (klass, klassc);
}
ICALL_EXPORT guint32
ves_icall_RuntimeTypeHandle_IsInstanceOfType (MonoReflectionTypeHandle ref_type, MonoObjectHandle obj, MonoError *error)
{
error_init (error);
MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
MonoClass *klass = mono_class_from_mono_type (type);
mono_class_init_checked (klass, error);
return_val_if_nok (error, FALSE);
MonoObjectHandle inst = mono_object_handle_isinst (obj, klass, error);
return_val_if_nok (error, FALSE);
return !MONO_HANDLE_IS_NULL (inst);
}
ICALL_EXPORT guint32
ves_icall_RuntimeTypeHandle_GetAttributes (MonoReflectionTypeHandle ref_type, MonoError *error)
{
error_init (error);
MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
MonoClass *klass = mono_class_from_mono_type (type);
return mono_class_get_flags (klass);
}
ICALL_EXPORT MonoReflectionMarshalAsAttributeHandle
ves_icall_System_Reflection_FieldInfo_get_marshal_info (MonoReflectionFieldHandle field_h, MonoError *error)
{
error_init (error);
MonoDomain *domain = MONO_HANDLE_DOMAIN (field_h);
MonoClassField *field = MONO_HANDLE_GETVAL (field_h, field);
MonoClass *klass = field->parent;
MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
if (mono_class_is_gtd (klass) ||
(gklass && gklass->context.class_inst->is_open))
return MONO_HANDLE_CAST (MonoReflectionMarshalAsAttribute, NULL_HANDLE);
MonoType *ftype = mono_field_get_type (field);
if (ftype && !(ftype->attrs & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL))
return MONO_HANDLE_CAST (MonoReflectionMarshalAsAttribute, NULL_HANDLE);
MonoMarshalType *info = mono_marshal_load_type_info (klass);
for (int i = 0; i < info->num_fields; ++i) {
if (info->fields [i].field == field) {
if (!info->fields [i].mspec)
return MONO_HANDLE_CAST (MonoReflectionMarshalAsAttribute, NULL_HANDLE);
else {
return mono_reflection_marshal_as_attribute_from_marshal_spec (domain, klass, info->fields [i].mspec, error);
}
}
}
return MONO_HANDLE_CAST (MonoReflectionMarshalAsAttribute, NULL_HANDLE);
}
ICALL_EXPORT MonoReflectionFieldHandle
ves_icall_System_Reflection_FieldInfo_internal_from_handle_type (MonoClassField *handle, MonoType *type, MonoError *error)
{
MonoClass *klass;
g_assert (handle);
error_init (error);
if (!type) {
klass = handle->parent;
} else {
klass = mono_class_from_mono_type (type);
gboolean found = klass == handle->parent || mono_class_has_parent (klass, handle->parent);
if (!found)
/* The managed code will throw the exception */
return MONO_HANDLE_CAST (MonoReflectionField, NULL_HANDLE);
}
return mono_field_get_object_handle (mono_domain_get (), klass, handle, error);
}
ICALL_EXPORT MonoReflectionEventHandle
ves_icall_System_Reflection_EventInfo_internal_from_handle_type (MonoEvent *handle, MonoType *type, MonoError *error)
{
MonoClass *klass;
g_assert (handle);
error_init (error);
if (!type) {
klass = handle->parent;
} else {
klass = mono_class_from_mono_type (type);
gboolean found = klass == handle->parent || mono_class_has_parent (klass, handle->parent);
if (!found)
/* Managed code will throw an exception */
return MONO_HANDLE_CAST (MonoReflectionEvent, NULL_HANDLE);
}
return mono_event_get_object_handle (mono_domain_get (), klass, handle, error);
}
ICALL_EXPORT MonoReflectionPropertyHandle
ves_icall_System_Reflection_PropertyInfo_internal_from_handle_type (MonoProperty *handle, MonoType *type, MonoError *error)
{
error_init (error);
MonoClass *klass;
g_assert (handle);
if (!type) {
klass = handle->parent;
} else {
klass = mono_class_from_mono_type (type);
gboolean found = klass == handle->parent || mono_class_has_parent (klass, handle->parent);
if (!found)
/* Managed code will throw an exception */
return MONO_HANDLE_CAST (MonoReflectionProperty, NULL_HANDLE);
}
return mono_property_get_object_handle (mono_domain_get (), klass, handle, error);
}
ICALL_EXPORT MonoArrayHandle
ves_icall_System_Reflection_FieldInfo_GetTypeModifiers (MonoReflectionFieldHandle field_h, MonoBoolean optional, MonoError *error)
{
error_init (error);
MonoClassField *field = MONO_HANDLE_GETVAL (field_h, field);
MonoType *type = mono_field_get_type_checked (field, error);
if (!is_ok (error))
return MONO_HANDLE_CAST (MonoArray, NULL_HANDLE);
return type_array_from_modifiers (field->parent->image, type, optional, error);
}
ICALL_EXPORT int
vell_icall_get_method_attributes (MonoMethod *method)
{
return method->flags;
}
ICALL_EXPORT void
ves_icall_get_method_info (MonoMethod *method, MonoMethodInfo *info, MonoError *error)
{
MonoDomain *domain = mono_domain_get ();
MonoMethodSignature* sig = mono_method_signature_checked (method, error);
return_if_nok (error);
MonoReflectionTypeHandle rt = mono_type_get_object_handle (domain, &method->klass->byval_arg, error);
return_if_nok (error);
MONO_STRUCT_SETREF (info, parent, MONO_HANDLE_RAW (rt));
MONO_HANDLE_ASSIGN (rt, mono_type_get_object_handle (domain, sig->ret, error));
return_if_nok (error);
MONO_STRUCT_SETREF (info, ret, MONO_HANDLE_RAW (rt));
info->attrs = method->flags;
info->implattrs = method->iflags;
guint32 callconv;
if (sig->call_convention == MONO_CALL_DEFAULT)
callconv = sig->sentinelpos >= 0 ? 2 : 1;
else {
if (sig->call_convention == MONO_CALL_VARARG || sig->sentinelpos >= 0)
callconv = 2;
else
callconv = 1;
}
callconv |= (sig->hasthis << 5) | (sig->explicit_this << 6);
info->callconv = callconv;
}
ICALL_EXPORT MonoArrayHandle
ves_icall_System_Reflection_MonoMethodInfo_get_parameter_info (MonoMethod *method, MonoReflectionMethodHandle member, MonoError *error)
{
error_init (error);
MonoDomain *domain = mono_domain_get ();
MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
MONO_HANDLE_GET (reftype, member, reftype);
MonoClass *klass = NULL;
if (!MONO_HANDLE_IS_NULL (reftype))
klass = mono_class_from_mono_type (MONO_HANDLE_GETVAL (reftype, type));
return mono_param_get_objects_internal (domain, method, klass, error);
}
ICALL_EXPORT MonoReflectionMarshalAsAttributeHandle
ves_icall_System_MonoMethodInfo_get_retval_marshal (MonoMethod *method, MonoError *error)
{
error_init (error);
MonoDomain *domain = mono_domain_get ();
MonoReflectionMarshalAsAttributeHandle res = MONO_HANDLE_NEW (MonoReflectionMarshalAsAttribute, NULL);
MonoMarshalSpec **mspecs = g_new (MonoMarshalSpec*, mono_method_signature (method)->param_count + 1);
mono_method_get_marshal_info (method, mspecs);
if (mspecs [0]) {
MONO_HANDLE_ASSIGN (res, mono_reflection_marshal_as_attribute_from_marshal_spec (domain, method->klass, mspecs [0], error));
if (!is_ok (error))
goto leave;
}
leave:
for (int i = mono_method_signature (method)->param_count; i >= 0; i--)
if (mspecs [i])
mono_metadata_free_marshal_spec (mspecs [i]);
g_free (mspecs);
return res;
}
ICALL_EXPORT gint32
ves_icall_MonoField_GetFieldOffset (MonoReflectionField *field)
{
MonoClass *parent = field->field->parent;
mono_class_setup_fields (parent);
return field->field->offset - sizeof (MonoObject);
}
ICALL_EXPORT MonoReflectionTypeHandle
ves_icall_MonoField_GetParentType (MonoReflectionFieldHandle field, MonoBoolean declaring, MonoError *error)
{
error_init (error);
MonoDomain *domain = MONO_HANDLE_DOMAIN (field);
MonoClass *parent;
if (declaring) {
MonoClassField *f = MONO_HANDLE_GETVAL (field, field);
parent = f->parent;
} else {
parent = MONO_HANDLE_GETVAL (field, klass);
}
return mono_type_get_object_handle (domain, &parent->byval_arg, error);
}
ICALL_EXPORT MonoObject *
ves_icall_MonoField_GetValueInternal (MonoReflectionField *field, MonoObject *obj)
{
MonoError error;
MonoClass *fklass = field->klass;
MonoClassField *cf = field->field;
MonoDomain *domain = mono_object_domain (field);
if (fklass->image->assembly->ref_only) {
mono_set_pending_exception (mono_get_exception_invalid_operation (
"It is illegal to get the value on a field on a type loaded using the ReflectionOnly methods."));
return NULL;
}
if (mono_security_core_clr_enabled () &&
!mono_security_core_clr_ensure_reflection_access_field (cf, &error)) {
mono_error_set_pending_exception (&error);
return NULL;
}
MonoObject * result = mono_field_get_value_object_checked (domain, cf, obj, &error);
mono_error_set_pending_exception (&error);
return result;
}
ICALL_EXPORT void
ves_icall_MonoField_SetValueInternal (MonoReflectionFieldHandle field, MonoObjectHandle obj, MonoObjectHandle value, MonoError *error)
{
MonoClassField *cf = MONO_HANDLE_GETVAL (field, field);
MonoClass *field_klass = MONO_HANDLE_GETVAL (field, klass);
if (field_klass->image->assembly->ref_only) {
mono_error_set_invalid_operation (error, "It is illegal to set the value on a field on a type loaded using the ReflectionOnly methods.");
return;
}
if (mono_security_core_clr_enabled () &&
!mono_security_core_clr_ensure_reflection_access_field (cf, error)) {
return;
}
MonoType *type = mono_field_get_type_checked (cf, error);
return_if_nok (error);
gboolean isref = FALSE;
uint32_t value_gchandle = 0;
gchar *v = NULL;
if (!type->byref) {
switch (type->type) {
case MONO_TYPE_U1:
case MONO_TYPE_I1:
case MONO_TYPE_BOOLEAN:
case MONO_TYPE_U2:
case MONO_TYPE_I2:
case MONO_TYPE_CHAR:
case MONO_TYPE_U:
case MONO_TYPE_I:
case MONO_TYPE_U4:
case MONO_TYPE_I4:
case MONO_TYPE_R4:
case MONO_TYPE_U8:
case MONO_TYPE_I8:
case MONO_TYPE_R8:
case MONO_TYPE_VALUETYPE:
case MONO_TYPE_PTR:
isref = FALSE;
if (!MONO_HANDLE_IS_NULL (value))
v = mono_object_handle_pin_unbox (value, &value_gchandle);
break;
case MONO_TYPE_STRING:
case MONO_TYPE_OBJECT:
case MONO_TYPE_CLASS:
case MONO_TYPE_ARRAY:
case MONO_TYPE_SZARRAY:
/* Do nothing */
isref = TRUE;
break;
case MONO_TYPE_GENERICINST: {
MonoGenericClass *gclass = type->data.generic_class;
g_assert (!gclass->context.class_inst->is_open);
if (mono_class_is_nullable (mono_class_from_mono_type (type))) {
MonoClass *nklass = mono_class_from_mono_type (type);
/*
* Convert the boxed vtype into a Nullable structure.
* This is complicated by the fact that Nullables have
* a variable structure.
*/
MonoObjectHandle nullable = MONO_HANDLE_NEW (MonoObject, mono_object_new_checked (mono_domain_get (), nklass, error));
return_if_nok (error);
uint32_t nullable_gchandle = 0;
guint8 *nval = mono_object_handle_pin_unbox (nullable, &nullable_gchandle);
mono_nullable_init_from_handle (nval, value, nklass);
isref = FALSE;
value_gchandle = nullable_gchandle;
v = (gchar*)nval;
}
else {
isref = !gclass->container_class->valuetype;
if (!isref && !MONO_HANDLE_IS_NULL (value)) {
v = mono_object_handle_pin_unbox (value, &value_gchandle);
};
}
break;
}
default:
g_error ("type 0x%x not handled in "
"ves_icall_FieldInfo_SetValueInternal", type->type);
return;
}
}
/* either value is a reference type, or it's a value type and we pinned
* it and v points to the payload. */
g_assert ((isref && v == NULL && value_gchandle == 0) ||
(!isref && v != NULL && value_gchandle != 0) ||
(!isref && v == NULL && value_gchandle == 0));
if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
MonoVTable *vtable = mono_class_vtable_full (MONO_HANDLE_DOMAIN (field), cf->parent, error);
if (!is_ok (error))
goto leave;
if (!vtable->initialized) {
if (!mono_runtime_class_init_full (vtable, error))
goto leave;
}
if (isref)
mono_field_static_set_value (vtable, cf, MONO_HANDLE_RAW (value)); /* FIXME make mono_field_static_set_value work with handles for value */
else
mono_field_static_set_value (vtable, cf, v);
} else {
if (isref)
MONO_HANDLE_SET_FIELD_REF (obj, cf, value);
else
mono_field_set_value (MONO_HANDLE_RAW (obj), cf, v); /* FIXME: make mono_field_set_value take a handle for obj */
}
leave:
if (value_gchandle)
mono_gchandle_free (value_gchandle);
}
ICALL_EXPORT void
ves_icall_System_RuntimeFieldHandle_SetValueDirect (MonoReflectionField *field, MonoReflectionType *field_type, MonoTypedRef *obj, MonoObject *value, MonoReflectionType *context_type)
{
MonoClassField *f;
g_assert (field);
g_assert (obj);
g_assert (value);
f = field->field;
if (!MONO_TYPE_ISSTRUCT (&f->parent->byval_arg)) {
mono_set_pending_exception (mono_get_exception_not_implemented (NULL));
return;
}
if (MONO_TYPE_IS_REFERENCE (f->type))
mono_copy_value (f->type, (guint8*)obj->value + f->offset - sizeof (MonoObject), value, FALSE);
else
mono_copy_value (f->type, (guint8*)obj->value + f->offset - sizeof (MonoObject), mono_object_unbox (value), FALSE);
}
ICALL_EXPORT MonoObject *
ves_icall_MonoField_GetRawConstantValue (MonoReflectionField *rfield)
{
MonoObject *o = NULL;
MonoClassField *field = rfield->field;
MonoClass *klass;
MonoDomain *domain = mono_object_domain (rfield);
gchar *v;
MonoTypeEnum def_type;
const char *def_value;
MonoType *t;
MonoError error;
mono_class_init (field->parent);
t = mono_field_get_type_checked (field, &error);
if (!mono_error_ok (&error)) {
mono_error_set_pending_exception (&error);
return NULL;
}
if (!(t->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT)) {
mono_set_pending_exception (mono_get_exception_invalid_operation (NULL));
return NULL;
}
if (image_is_dynamic (field->parent->image)) {
MonoClass *klass = field->parent;
int fidx = field - klass->fields;
MonoFieldDefaultValue *def_values = mono_class_get_field_def_values (klass);
g_assert (def_values);
def_type = def_values [fidx].def_type;
def_value = def_values [fidx].data;
if (def_type == MONO_TYPE_END) {
mono_set_pending_exception (mono_get_exception_invalid_operation (NULL));
return NULL;
}
} else {
def_value = mono_class_get_field_default_value (field, &def_type);
/* FIXME, maybe we should try to raise TLE if field->parent is broken */
if (!def_value) {
mono_set_pending_exception (mono_get_exception_invalid_operation (NULL));
return NULL;
}
}
/*FIXME unify this with reflection.c:mono_get_object_from_blob*/
switch (def_type) {
case MONO_TYPE_U1:
case MONO_TYPE_I1:
case MONO_TYPE_BOOLEAN:
case MONO_TYPE_U2:
case MONO_TYPE_I2:
case MONO_TYPE_CHAR:
case MONO_TYPE_U:
case MONO_TYPE_I:
case MONO_TYPE_U4:
case MONO_TYPE_I4:
case MONO_TYPE_R4:
case MONO_TYPE_U8:
case MONO_TYPE_I8:
case MONO_TYPE_R8: {
MonoType *t;
/* boxed value type */
t = g_new0 (MonoType, 1);
t->type = def_type;
klass = mono_class_from_mono_type (t);
g_free (t);
o = mono_object_new_checked (domain, klass, &error);
if (!mono_error_ok (&error)) {
mono_error_set_pending_exception (&error);
return NULL;
}
v = ((gchar *) o) + sizeof (MonoObject);
mono_get_constant_value_from_blob (domain, def_type, def_value, v, &error);
if (mono_error_set_pending_exception (&error))
return NULL;
break;
}
case MONO_TYPE_STRING:
case MONO_TYPE_CLASS:
mono_get_constant_value_from_blob (domain, def_type, def_value, &o, &error);
if (mono_error_set_pending_exception (&error))
return NULL;
break;
default:
g_assert_not_reached ();
}
return o;
}
ICALL_EXPORT MonoReflectionTypeHandle
ves_icall_MonoField_ResolveType (MonoReflectionFieldHandle ref_field, MonoError *error)
{
error_init (error);
MonoDomain *domain = MONO_HANDLE_DOMAIN (ref_field);
MonoClassField *field = MONO_HANDLE_GETVAL (ref_field, field);
MonoType *type = mono_field_get_type_checked (field, error);
if (!is_ok (error)) {
return MONO_HANDLE_CAST (MonoReflectionType, NULL_HANDLE);
}
return mono_type_get_object_handle (domain, type, error);
}
/* From MonoProperty.cs */
typedef enum {
PInfo_Attributes = 1,
PInfo_GetMethod = 1 << 1,
PInfo_SetMethod = 1 << 2,
PInfo_ReflectedType = 1 << 3,
PInfo_DeclaringType = 1 << 4,
PInfo_Name = 1 << 5
} PInfo;
ICALL_EXPORT void
ves_icall_MonoPropertyInfo_get_property_info (MonoReflectionPropertyHandle property, MonoPropertyInfo *info, PInfo req_info, MonoError *error)
{
error_init (error);
MonoDomain *domain = MONO_HANDLE_DOMAIN (property);
const MonoProperty *pproperty = MONO_HANDLE_GETVAL (property, property);
if ((req_info & PInfo_ReflectedType) != 0) {
MonoClass *klass = MONO_HANDLE_GETVAL (property, klass);
MonoReflectionTypeHandle rt = mono_type_get_object_handle (domain, &klass->byval_arg, error);
return_if_nok (error);
MONO_STRUCT_SETREF (info, parent, MONO_HANDLE_RAW (rt));
}
if ((req_info & PInfo_DeclaringType) != 0) {
MonoReflectionTypeHandle rt = mono_type_get_object_handle (domain, &pproperty->parent->byval_arg, error);
return_if_nok (error);
MONO_STRUCT_SETREF (info, declaring_type, MONO_HANDLE_RAW (rt));
}
if ((req_info & PInfo_Name) != 0) {
MonoStringHandle name = mono_string_new_handle (domain, pproperty->name, error);
return_if_nok (error);
MONO_STRUCT_SETREF (info, name, MONO_HANDLE_RAW (name));
}
if ((req_info & PInfo_Attributes) != 0)
info->attrs = pproperty->attrs;
if ((req_info & PInfo_GetMethod) != 0) {
MonoClass *property_klass = MONO_HANDLE_GETVAL (property, klass);
MonoReflectionMethodHandle rm;
if (pproperty->get &&
(((pproperty->get->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) != METHOD_ATTRIBUTE_PRIVATE) ||
pproperty->get->klass == property_klass)) {
rm = mono_method_get_object_handle (domain, pproperty->get, property_klass, error);
return_if_nok (error);
} else {
rm = MONO_HANDLE_NEW (MonoReflectionMethod, NULL);
}
MONO_STRUCT_SETREF (info, get, MONO_HANDLE_RAW (rm));
}
if ((req_info & PInfo_SetMethod) != 0) {
MonoClass *property_klass = MONO_HANDLE_GETVAL (property, klass);
MonoReflectionMethodHandle rm;
if (pproperty->set &&
(((pproperty->set->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) != METHOD_ATTRIBUTE_PRIVATE) ||
pproperty->set->klass == property_klass)) {
rm = mono_method_get_object_handle (domain, pproperty->set, property_klass, error);
return_if_nok (error);
} else {
rm = MONO_HANDLE_NEW (MonoReflectionMethod, NULL);
}
MONO_STRUCT_SETREF (info, set, MONO_HANDLE_RAW (rm));
}
/*
* There may be other methods defined for properties, though, it seems they are not exposed
* in the reflection API
*/
}
static gboolean
add_event_other_methods_to_array (MonoDomain *domain, MonoMethod *m, MonoArrayHandle dest, int i, MonoError *error)
{
HANDLE_FUNCTION_ENTER ();
error_init (error);
MonoReflectionMethodHandle rm = mono_method_get_object_handle (domain, m, NULL, error);
if (!is_ok (error))
goto leave;
MONO_HANDLE_ARRAY_SETREF (dest, i, rm);
leave:
HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
}
ICALL_EXPORT void
ves_icall_MonoEventInfo_get_event_info (MonoReflectionMonoEventHandle ref_event, MonoEventInfo *info, MonoError *error)
{
error_init (error);
MonoDomain *domain = MONO_HANDLE_DOMAIN (ref_event);
MonoClass *klass = MONO_HANDLE_GETVAL (ref_event, klass);
MonoEvent *event = MONO_HANDLE_GETVAL (ref_event, event);
MonoReflectionTypeHandle rt = mono_type_get_object_handle (domain, &klass->byval_arg, error);
return_if_nok (error);
MONO_STRUCT_SETREF (info, reflected_type, MONO_HANDLE_RAW (rt));
rt = mono_type_get_object_handle (domain, &event->parent->byval_arg, error);
return_if_nok (error);
MONO_STRUCT_SETREF (info, declaring_type, MONO_HANDLE_RAW (rt));
MonoStringHandle ev_name = mono_string_new_handle (domain, event->name, error);
return_if_nok (error);
MONO_STRUCT_SETREF (info, name, MONO_HANDLE_RAW (ev_name));
info->attrs = event->attrs;
MonoReflectionMethodHandle rm;
if (event->add) {
rm = mono_method_get_object_handle (domain, event->add, NULL, error);
return_if_nok (error);
} else {
rm = MONO_HANDLE_NEW (MonoReflectionMethod, NULL);
}
MONO_STRUCT_SETREF (info, add_method, MONO_HANDLE_RAW (rm));
if (event->remove) {
rm = mono_method_get_object_handle (domain, event->remove, NULL, error);
return_if_nok (error);
} else {
rm = MONO_HANDLE_NEW (MonoReflectionMethod, NULL);
}
MONO_STRUCT_SETREF (info, remove_method, MONO_HANDLE_RAW (rm));
if (event->raise) {
rm = mono_method_get_object_handle (domain, event->raise, NULL, error);
return_if_nok (error);
} else {
rm = MONO_HANDLE_NEW (MonoReflectionMethod, NULL);
}
MONO_STRUCT_SETREF (info, raise_method, MONO_HANDLE_RAW (rm));
#ifndef MONO_SMALL_CONFIG
if (event->other) {
int i, n = 0;
while (event->other [n])
n++;
MonoArrayHandle info_arr = mono_array_new_handle (domain, mono_defaults.method_info_class, n, error);
return_if_nok (error);
MONO_STRUCT_SETREF (info, other_methods, MONO_HANDLE_RAW (info_arr));
for (i = 0; i < n; i++)
if (!add_event_other_methods_to_array (domain, event->other [i], info_arr, i, error))
return;
}
#endif
}
static void
collect_interfaces (MonoClass *klass, GHashTable *ifaces, MonoError *error)
{
int i;
MonoClass *ic;
mono_class_setup_interfaces (klass, error);
if (!mono_error_ok (error))
return;
for (i = 0; i < klass->interface_count; i++) {
ic = klass->interfaces [i];
g_hash_table_insert (ifaces, ic, ic);
collect_interfaces (ic, ifaces, error);
if (!mono_error_ok (error))
return;
}
}
typedef struct {
MonoArrayHandle iface_array;
MonoGenericContext *context;
MonoError *error;
MonoDomain *domain;
int next_idx;
} FillIfaceArrayData;
static void
fill_iface_array (gpointer key, gpointer value, gpointer user_data)
{
HANDLE_FUNCTION_ENTER ();
FillIfaceArrayData *data = (FillIfaceArrayData *)user_data;
MonoClass *ic = (MonoClass *)key;
MonoType *ret = &ic->byval_arg, *inflated = NULL;
MonoError *error = data->error;
if (!is_ok (error))
goto leave;
if (data->context && mono_class_is_ginst (ic) && mono_class_get_generic_class (ic)->context.class_inst->is_open) {
inflated = ret = mono_class_inflate_generic_type_checked (ret, data->context, error);
if (!is_ok (error))
goto leave;
}
MonoReflectionTypeHandle rt = mono_type_get_object_handle (data->domain, ret, error);
if (!is_ok (error))
goto leave;
MONO_HANDLE_ARRAY_SETREF (data->iface_array, data->next_idx, rt);
data->next_idx++;
if (inflated)
mono_metadata_free_type (inflated);
leave:
HANDLE_FUNCTION_RETURN ();
}
static guint
get_interfaces_hash (gconstpointer v1)
{
MonoClass *k = (MonoClass*)v1;
return k->type_token;
}
ICALL_EXPORT MonoArrayHandle
ves_icall_RuntimeType_GetInterfaces (MonoReflectionTypeHandle ref_type, MonoError *error)
{
error_init (error);
MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
MonoClass *klass = mono_class_from_mono_type (type);
GHashTable *iface_hash = g_hash_table_new (get_interfaces_hash, NULL);
MonoGenericContext *context = NULL;
if (mono_class_is_ginst (klass) && mono_class_get_generic_class (klass)->context.class_inst->is_open) {
context = mono_class_get_context (klass);
klass = mono_class_get_generic_class (klass)->container_class;
}
for (MonoClass *parent = klass; parent; parent = parent->parent) {
mono_class_setup_interfaces (parent, error);
if (!is_ok (error))
goto fail;
collect_interfaces (parent, iface_hash, error);
if (!is_ok (error))
goto fail;
}
MonoDomain *domain = MONO_HANDLE_DOMAIN (ref_type);
int len = g_hash_table_size (iface_hash);
if (len == 0) {
g_hash_table_destroy (iface_hash);
if (!domain->empty_types) {
domain->empty_types = mono_array_new_cached (domain, mono_defaults.runtimetype_class, 0, error);
if (!is_ok (error))
goto fail;
}
return MONO_HANDLE_NEW (MonoArray, domain->empty_types);
}
FillIfaceArrayData data;
data.iface_array = MONO_HANDLE_NEW (MonoArray, mono_array_new_cached (domain, mono_defaults.runtimetype_class, len, error));
if (!is_ok (error))
goto fail;
data.context = context;
data.error = error;
data.domain = domain;
data.next_idx = 0;
g_hash_table_foreach (iface_hash, fill_iface_array, &data);
if (!is_ok (error))
goto fail;
g_hash_table_destroy (iface_hash);
return data.iface_array;
fail:
g_hash_table_destroy (iface_hash);
return MONO_HANDLE_CAST (MonoArray, NULL_HANDLE);
}
static gboolean
set_interface_map_data_method_object (MonoDomain *domain, MonoMethod *method, MonoClass *iclass, int ioffset, MonoClass *klass, MonoArrayHandle targets, MonoArrayHandle methods, int i, MonoError *error)
{
HANDLE_FUNCTION_ENTER ();
error_init (error);
MonoReflectionMethodHandle member = mono_method_get_object_handle (domain, method, iclass, error);
if (!is_ok (error))
goto leave;
MONO_HANDLE_ARRAY_SETREF (methods, i, member);
MONO_HANDLE_ASSIGN (member, mono_method_get_object_handle (domain, klass->vtable [i + ioffset], klass, error));
if (!is_ok (error))
goto leave;
MONO_HANDLE_ARRAY_SETREF (targets, i, member);
leave:
HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
}
ICALL_EXPORT void
ves_icall_RuntimeType_GetInterfaceMapData (MonoReflectionTypeHandle ref_type, MonoReflectionTypeHandle ref_iface, MonoArrayHandleOut targets, MonoArrayHandleOut methods, MonoError *error)
{
error_init (error);
MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
MonoClass *klass = mono_class_from_mono_type (type);
MonoType *iface = MONO_HANDLE_GETVAL (ref_iface, type);
MonoClass *iclass = mono_class_from_mono_type (iface);
mono_class_init_checked (klass, error);
return_if_nok (error);
mono_class_init_checked (iclass, error);
return_if_nok (error);
mono_class_setup_vtable (klass);
gboolean variance_used;
int ioffset = mono_class_interface_offset_with_variance (klass, iclass, &variance_used);
if (ioffset == -1)
return;
int len = mono_class_num_methods (iclass);
MonoDomain *domain = MONO_HANDLE_DOMAIN (ref_type);
MonoArrayHandle targets_arr = mono_array_new_handle (domain, mono_defaults.method_info_class, len, error);
return_if_nok (error);
MONO_HANDLE_ASSIGN (targets, targets_arr);
MonoArrayHandle methods_arr = mono_array_new_handle (domain, mono_defaults.method_info_class, len, error);
return_if_nok (error);
MONO_HANDLE_ASSIGN (methods, methods_arr);
MonoMethod* method;
int i = 0;
gpointer iter = NULL;
while ((method = mono_class_get_methods (iclass, &iter))) {
if (!set_interface_map_data_method_object (domain, method, iclass, ioffset, klass, targets, methods, i, error))
return;
i ++;
}
}
ICALL_EXPORT void
ves_icall_RuntimeType_GetPacking (MonoReflectionTypeHandle ref_type, guint32 *packing, guint32 *size, MonoError *error)
{
error_init (error);
MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
MonoClass *klass = mono_class_from_mono_type (type);
mono_class_init_checked (klass, error);
if (!is_ok (error))
return;
if (image_is_dynamic (klass->image)) {
MonoReflectionTypeBuilderHandle tb = MONO_HANDLE_CAST (MonoReflectionTypeBuilder, ref_type);
*packing = MONO_HANDLE_GETVAL (tb, packing_size);
*size = MONO_HANDLE_GETVAL (tb, class_size);
} else {
mono_metadata_packing_from_typedef (klass->image, klass->type_token, packing, size);
}
}
ICALL_EXPORT MonoReflectionTypeHandle
ves_icall_RuntimeTypeHandle_GetElementType (MonoReflectionTypeHandle ref_type, MonoError *error)
{
error_init (error);
MonoDomain *domain = MONO_HANDLE_DOMAIN (ref_type);
MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
if (!type->byref && type->type == MONO_TYPE_SZARRAY) {
return mono_type_get_object_handle (domain, &type->data.klass->byval_arg, error);
}
MonoClass *klass = mono_class_from_mono_type (type);
mono_class_init_checked (klass, error);
if (!is_ok (error))
return MONO_HANDLE_CAST (MonoReflectionType, NULL_HANDLE);
// GetElementType should only return a type for:
// Array Pointer PassedByRef
if (type->byref)
return mono_type_get_object_handle (domain, &klass->byval_arg, error);
else if (klass->element_class && MONO_CLASS_IS_ARRAY (klass))
return mono_type_get_object_handle (domain, &klass->element_class->byval_arg, error);
else if (klass->element_class && type->type == MONO_TYPE_PTR)
return mono_type_get_object_handle (domain, &klass->element_class->byval_arg, error);
else
return MONO_HANDLE_CAST (MonoReflectionType, NULL_HANDLE);
}
ICALL_EXPORT MonoReflectionTypeHandle
ves_icall_RuntimeTypeHandle_GetBaseType (MonoReflectionTypeHandle ref_type, MonoError *error)
{
error_init (error);
MonoDomain *domain = MONO_HANDLE_DOMAIN (ref_type);
MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
if (type->byref)
return MONO_HANDLE_CAST (MonoReflectionType, NULL_HANDLE);
MonoClass *klass = mono_class_from_mono_type (type);
if (!klass->parent)
return MONO_HANDLE_CAST (MonoReflectionType, NULL_HANDLE);
return mono_type_get_object_handle (domain, &klass->parent->byval_arg, error);
}
ICALL_EXPORT MonoBoolean
ves_icall_RuntimeTypeHandle_IsPointer (MonoReflectionTypeHandle ref_type, MonoError *error)
{
error_init (error);
MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
return type->type == MONO_TYPE_PTR;
}
ICALL_EXPORT MonoBoolean
ves_icall_RuntimeTypeHandle_IsPrimitive (MonoReflectionTypeHandle ref_type, MonoError *error)
{
error_init (error);
MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
return (!type->byref && (((type->type >= MONO_TYPE_BOOLEAN) && (type->type <= MONO_TYPE_R8)) || (type->type == MONO_TYPE_I) || (type->type == MONO_TYPE_U)));
}
ICALL_EXPORT MonoBoolean
ves_icall_RuntimeTypeHandle_HasReferences (MonoReflectionTypeHandle ref_type, MonoError *error)
{
error_init (error);
MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
MonoClass *klass;
klass = mono_class_from_mono_type (type);
mono_class_init (klass);
return klass->has_references;
}
ICALL_EXPORT MonoBoolean
ves_icall_RuntimeTypeHandle_IsByRef (MonoReflectionTypeHandle ref_type, MonoError *error)
{
error_init (error);
MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
return type->byref;
}
ICALL_EXPORT MonoBoolean
ves_icall_RuntimeTypeHandle_IsComObject (MonoReflectionTypeHandle ref_type, MonoError *error)
{
error_init (error);
MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
MonoClass *klass = mono_class_from_mono_type (type);
mono_class_init_checked (klass, error);
if (!is_ok (error))
return FALSE;
return mono_class_is_com_object (klass);
}
ICALL_EXPORT guint32
ves_icall_reflection_get_token (MonoObjectHandle obj, MonoError *error)
{
error_init (error);
return mono_reflection_get_token_checked (obj, error);
}
ICALL_EXPORT MonoReflectionModuleHandle
ves_icall_RuntimeTypeHandle_GetModule (MonoReflectionTypeHandle type, MonoError *error)
{
error_init (error);
MonoDomain *domain = MONO_HANDLE_DOMAIN (type);
MonoType *t = MONO_HANDLE_GETVAL (type, type);
MonoClass *klass = mono_class_from_mono_type (t);
return mono_module_get_object_handle (domain, klass->image, error);
}
ICALL_EXPORT MonoReflectionAssemblyHandle
ves_icall_RuntimeTypeHandle_GetAssembly (MonoReflectionTypeHandle type, MonoError *error)
{
error_init (error);
MonoDomain *domain = mono_domain_get ();
MonoType *t = MONO_HANDLE_GETVAL (type, type);
MonoClass *klass = mono_class_from_mono_type (t);
return mono_assembly_get_object_handle (domain, klass->image->assembly, error);
}
ICALL_EXPORT MonoReflectionTypeHandle
ves_icall_RuntimeType_get_DeclaringType (MonoReflectionTypeHandle ref_type, MonoError *error)
{
error_init (error);
MonoDomain *domain = mono_domain_get ();
MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
MonoClass *klass;
if (type->byref)
return MONO_HANDLE_CAST (MonoReflectionType, NULL_HANDLE);
if (type->type == MONO_TYPE_VAR) {
MonoGenericContainer *param = mono_type_get_generic_param_owner (type);
klass = param ? param->owner.klass : NULL;
} else if (type->type == MONO_TYPE_MVAR) {
MonoGenericContainer *param = mono_type_get_generic_param_owner (type);
klass = param ? param->owner.method->klass : NULL;
} else {
klass = mono_class_from_mono_type (type)->nested_in;
}
if (!klass)
return MONO_HANDLE_CAST (MonoReflectionType, NULL_HANDLE);
return mono_type_get_object_handle (domain, &klass->byval_arg, error);
}
ICALL_EXPORT MonoStringHandle
ves_icall_RuntimeType_get_Name (MonoReflectionTypeHandle reftype, MonoError *error)
{
MonoDomain *domain = mono_domain_get ();
MonoType *type = MONO_HANDLE_RAW(reftype)->type;
MonoClass *klass = mono_class_from_mono_type (type);
if (type->byref) {
char *n = g_strdup_printf ("%s&", klass->name);
MonoStringHandle res = mono_string_new_handle (domain, n, error);
g_free (n);
return res;
} else {
return mono_string_new_handle (domain, klass->name, error);
}
}
ICALL_EXPORT MonoStringHandle
ves_icall_RuntimeType_get_Namespace (MonoReflectionTypeHandle type, MonoError *error)
{
MonoDomain *domain = mono_domain_get ();
MonoClass *klass = mono_class_from_mono_type_handle (type);
while (klass->nested_in)
klass = klass->nested_in;
if (klass->name_space [0] == '\0')
return NULL_HANDLE_STRING;
else
return mono_string_new_handle (domain, klass->name_space, error);
}
ICALL_EXPORT gint32
ves_icall_RuntimeTypeHandle_GetArrayRank (MonoReflectionTypeHandle ref_type, MonoError *error)
{
error_init (error);
MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
if (type->type != MONO_TYPE_ARRAY && type->type != MONO_TYPE_SZARRAY) {
mono_error_set_argument (error, "type", "Type must be an array type");
return 0;
}
MonoClass *klass = mono_class_from_mono_type (type);
return klass->rank;
}
static MonoArrayHandle
create_type_array (MonoDomain *domain, MonoBoolean runtimeTypeArray, int count, MonoError *error)
{
return mono_array_new_handle (domain, runtimeTypeArray ? mono_defaults.runtimetype_class : mono_defaults.systemtype_class, count, error);
}
static gboolean
set_type_object_in_array (MonoDomain *domain, MonoType *type, MonoArrayHandle dest, int i, MonoError *error)
{
HANDLE_FUNCTION_ENTER();
error_init (error);
MonoReflectionTypeHandle rt = mono_type_get_object_handle (domain, type, error);
if (!is_ok (error))
goto leave;
MONO_HANDLE_ARRAY_SETREF (dest, i, rt);
leave:
HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
}
ICALL_EXPORT MonoArrayHandle
ves_icall_RuntimeType_GetGenericArguments (MonoReflectionTypeHandle ref_type, MonoBoolean runtimeTypeArray, MonoError *error)
{
error_init (error);
MonoDomain *domain = MONO_HANDLE_DOMAIN (ref_type);
MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
MonoClass *klass = mono_class_from_mono_type (type);
MonoArrayHandle res = MONO_HANDLE_NEW (MonoArray, NULL);
if (mono_class_is_gtd (klass)) {
MonoGenericContainer *container = mono_class_get_generic_container (klass);
MONO_HANDLE_ASSIGN (res, create_type_array (domain, runtimeTypeArray, container->type_argc, error));
if (!is_ok (error))
goto leave;
for (int i = 0; i < container->type_argc; ++i) {
MonoClass *pklass = mono_class_from_generic_parameter_internal (mono_generic_container_get_param (container, i));
if (!set_type_object_in_array (domain, &pklass->byval_arg, res, i, error))
goto leave;
}
} else if (mono_class_is_ginst (klass)) {
MonoGenericInst *inst = mono_class_get_generic_class (klass)->context.class_inst;
MONO_HANDLE_ASSIGN (res, create_type_array (domain, runtimeTypeArray, inst->type_argc, error));
if (!is_ok (error))
goto leave;
for (int i = 0; i < inst->type_argc; ++i) {
if (!set_type_object_in_array (domain, inst->type_argv [i], res, i, error))
goto leave;
}
}
leave:
return res;
}
ICALL_EXPORT gboolean
ves_icall_RuntimeTypeHandle_IsGenericTypeDefinition (MonoReflectionTypeHandle ref_type, MonoError *error)
{
error_init (error);
if (!IS_MONOTYPE (MONO_HANDLE_RAW(ref_type)))
return FALSE;
MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
if (type->byref)
return FALSE;
MonoClass *klass = mono_class_from_mono_type (type);
return mono_class_is_gtd (klass);
}
ICALL_EXPORT MonoReflectionTypeHandle
ves_icall_RuntimeTypeHandle_GetGenericTypeDefinition_impl (MonoReflectionTypeHandle ref_type, MonoError *error)
{
error_init (error);
MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
MonoReflectionTypeHandle ret = MONO_HANDLE_NEW (MonoReflectionType, NULL);
if (type->byref)
goto leave;
MonoClass *klass = mono_class_from_mono_type (type);
if (mono_class_is_gtd (klass)) {
/* check this one */
MONO_HANDLE_ASSIGN (ret, ref_type);
goto leave;
}
if (mono_class_is_ginst (klass)) {
MonoClass *generic_class = mono_class_get_generic_class (klass)->container_class;
guint32 ref_info_handle = mono_class_get_ref_info_handle (generic_class);
if (generic_class->wastypebuilder && ref_info_handle) {
MonoObjectHandle tb = mono_gchandle_get_target_handle (ref_info_handle);
g_assert (!MONO_HANDLE_IS_NULL (tb));
MONO_HANDLE_ASSIGN (ret, tb);
} else {
MonoDomain *domain = MONO_HANDLE_DOMAIN (ref_type);
MONO_HANDLE_ASSIGN (ret, mono_type_get_object_handle (domain, &generic_class->byval_arg, error));
}
}
leave:
return ret;
}
ICALL_EXPORT MonoReflectionTypeHandle
ves_icall_RuntimeType_MakeGenericType (MonoReflectionTypeHandle reftype, MonoArrayHandle type_array, MonoError *error)
{
error_init (error);
MonoDomain *domain = MONO_HANDLE_DOMAIN (reftype);
g_assert (IS_MONOTYPE_HANDLE (reftype));
MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
mono_class_init_checked (mono_class_from_mono_type (type), error);
if (!is_ok (error))
return MONO_HANDLE_CAST (MonoReflectionType, NULL_HANDLE);
int count = mono_array_handle_length (type_array);
MonoType **types = g_new0 (MonoType *, count);
MonoReflectionTypeHandle t = MONO_HANDLE_NEW (MonoReflectionType, NULL);
for (int i = 0; i < count; i++) {
MONO_HANDLE_ARRAY_GETREF (t, type_array, i);
types [i] = MONO_HANDLE_GETVAL (t, type);
}
MonoType *geninst = mono_reflection_bind_generic_parameters (reftype, count, types, error);
g_free (types);
if (!geninst) {
return MONO_HANDLE_CAST (MonoReflectionType, NULL_HANDLE);
}
MonoClass *klass = mono_class_from_mono_type (geninst);
/*we might inflate to the GTD*/
if (mono_class_is_ginst (klass) && !mono_verifier_class_is_valid_generic_instantiation (klass)) {
mono_error_set_argument (error, "typeArguments", "Invalid generic arguments");
return MONO_HANDLE_CAST (MonoReflectionType, NULL_HANDLE);
}
return mono_type_get_object_handle (domain, geninst, error);
}
ICALL_EXPORT gboolean
ves_icall_RuntimeTypeHandle_HasInstantiation (MonoReflectionTypeHandle ref_type, MonoError *error)
{
error_init (error);
MonoClass *klass;
if (!IS_MONOTYPE (MONO_HANDLE_RAW (ref_type)))
return FALSE;
MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
if (type->byref)
return FALSE;
klass = mono_class_from_mono_type (type);
return mono_class_is_ginst (klass) || mono_class_is_gtd (klass);
}
ICALL_EXPORT gint32
ves_icall_RuntimeType_GetGenericParameterPosition (MonoReflectionTypeHandle ref_type, MonoError *error)
{
error_init (error);
if (!IS_MONOTYPE_HANDLE (ref_type))
return -1;
MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
if (is_generic_parameter (type))
return mono_type_get_generic_param_num (type);
return -1;
}
ICALL_EXPORT MonoGenericParamInfo *
ves_icall_RuntimeTypeHandle_GetGenericParameterInfo (MonoReflectionTypeHandle ref_type, MonoError *error)
{
error_init (error);
MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
return mono_generic_param_info (type->data.generic_param);
}
ICALL_EXPORT MonoBoolean
ves_icall_RuntimeTypeHandle_IsGenericVariable (MonoReflectionTypeHandle ref_type, MonoError *error)
{
MonoType *type = MONO_HANDLE_GETVAL(ref_type, type);
return is_generic_parameter (type);
}
ICALL_EXPORT MonoReflectionMethodHandle
ves_icall_RuntimeType_GetCorrespondingInflatedMethod (MonoReflectionTypeHandle ref_type,
MonoReflectionMethodHandle generic,
MonoError *error)
{
error_init (error);
MonoDomain *domain = MONO_HANDLE_DOMAIN (ref_type);
MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
MonoClass *klass = mono_class_from_mono_type (type);
mono_class_init_checked (klass, error);
if (!is_ok (error))
return MONO_HANDLE_CAST (MonoReflectionMethod, NULL_HANDLE);
MonoMethod *generic_method = MONO_HANDLE_GETVAL (generic, method);
MonoReflectionMethodHandle ret = MONO_HANDLE_CAST (MonoReflectionMethod, NULL_HANDLE);
MonoMethod *method;
gpointer iter = NULL;
while ((method = mono_class_get_methods (klass, &iter))) {
if (method->token == generic_method->token) {
ret = mono_method_get_object_handle (domain, method, klass, error);
if (!is_ok (error))
return MONO_HANDLE_CAST (MonoReflectionMethod, NULL_HANDLE);
}
}
return ret;
}
ICALL_EXPORT MonoReflectionMethodHandle
ves_icall_RuntimeType_get_DeclaringMethod (MonoReflectionTypeHandle ref_type, MonoError *error)
{
error_init (error);
MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
MonoReflectionMethodHandle ret = MONO_HANDLE_NEW (MonoReflectionMethod, NULL);
if (type->byref || (type->type != MONO_TYPE_MVAR && type->type != MONO_TYPE_VAR)) {
mono_error_set_invalid_operation (error, "DeclaringMethod can only be used on generic arguments");
goto leave;
}
if (type->type == MONO_TYPE_VAR)
goto leave;
MonoMethod *method = mono_type_get_generic_param_owner (type)->owner.method;
g_assert (method);
MonoDomain *domain = MONO_HANDLE_DOMAIN (ref_type);
MONO_HANDLE_ASSIGN (ret, mono_method_get_object_handle (domain, method, method->klass, error));
leave:
return ret;
}
ICALL_EXPORT MonoBoolean
ves_icall_System_RuntimeType_IsTypeExportedToWindowsRuntime (MonoError *error)
{
error_init (error);
mono_error_set_not_implemented (error, "%s", "");
return FALSE;
}
ICALL_EXPORT MonoBoolean
ves_icall_System_RuntimeType_IsWindowsRuntimeObjectType (MonoError *error)
{
error_init (error);
mono_error_set_not_implemented (error, "%s", "");
return FALSE;
}
ICALL_EXPORT void
ves_icall_MonoMethod_GetPInvoke (MonoReflectionMethodHandle ref_method, int* flags, MonoStringHandleOut entry_point, MonoStringHandleOut dll_name, MonoError *error)
{
MonoDomain *domain = mono_domain_get ();
MonoMethod *method = MONO_HANDLE_GETVAL (ref_method, method);
MonoImage *image = method->klass->image;
MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method;
MonoTableInfo *tables = image->tables;
MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
MonoTableInfo *mr = &tables [MONO_TABLE_MODULEREF];
guint32 im_cols [MONO_IMPLMAP_SIZE];
guint32 scope_token;
const char *import = NULL;
const char *scope = NULL;
error_init (error);
if (image_is_dynamic (image)) {
MonoReflectionMethodAux *method_aux =
(MonoReflectionMethodAux *)g_hash_table_lookup (((MonoDynamicImage*)image)->method_aux_hash, method);
if (method_aux) {
import = method_aux->dllentry;
scope = method_aux->dll;
}
if (!import || !scope) {
mono_error_set_argument (error, "method", "System.Refleciton.Emit method with invalid pinvoke information");
return;
}
}
else {
if (piinfo->implmap_idx) {
mono_metadata_decode_row (im, piinfo->implmap_idx - 1, im_cols, MONO_IMPLMAP_SIZE);
piinfo->piflags = im_cols [MONO_IMPLMAP_FLAGS];
import = mono_metadata_string_heap (image, im_cols [MONO_IMPLMAP_NAME]);
scope_token = mono_metadata_decode_row_col (mr, im_cols [MONO_IMPLMAP_SCOPE] - 1, MONO_MODULEREF_NAME);
scope = mono_metadata_string_heap (image, scope_token);
}
}
*flags = piinfo->piflags;
MONO_HANDLE_ASSIGN (entry_point, mono_string_new_handle (domain, import, error));
return_if_nok (error);
MONO_HANDLE_ASSIGN (dll_name, mono_string_new_handle (domain, scope, error));
}
ICALL_EXPORT MonoReflectionMethodHandle
ves_icall_MonoMethod_GetGenericMethodDefinition (MonoReflectionMethodHandle ref_method, MonoError *error)
{
error_init (error);
MonoMethod *method = MONO_HANDLE_GETVAL (ref_method, method);
if (method->is_generic)
return ref_method;
if (!method->is_inflated)
return MONO_HANDLE_CAST (MonoReflectionMethod, NULL_HANDLE);
MonoMethodInflated *imethod = (MonoMethodInflated *) method;
MonoMethod *result = imethod->declaring;
/* Not a generic method. */
if (!result->is_generic)
return MONO_HANDLE_CAST (MonoReflectionMethod, NULL_HANDLE);
if (image_is_dynamic (method->klass->image)) {
MonoDynamicImage *image = (MonoDynamicImage*)method->klass->image;
/*
* FIXME: Why is this stuff needed at all ? Why can't the code below work for
* the dynamic case as well ?
*/
mono_image_lock ((MonoImage*)image);
MonoReflectionMethodHandle res = MONO_HANDLE_NEW (MonoReflectionMethod, mono_g_hash_table_lookup (image->generic_def_objects, imethod));
mono_image_unlock ((MonoImage*)image);
if (!MONO_HANDLE_IS_NULL (res))
return res;
}
if (imethod->context.class_inst) {
MonoClass *klass = ((MonoMethod *) imethod)->klass;
/*Generic methods gets the context of the GTD.*/
if (mono_class_get_context (klass)) {
result = mono_class_inflate_generic_method_full_checked (result, klass, mono_class_get_context (klass), error);
return_val_if_nok (error, MONO_HANDLE_CAST (MonoReflectionMethod, NULL_HANDLE));
}
}
return mono_method_get_object_handle (MONO_HANDLE_DOMAIN (ref_method), result, NULL, error);
}
ICALL_EXPORT gboolean
ves_icall_MonoMethod_get_IsGenericMethod (MonoReflectionMethodHandle ref_method, MonoError *erro)
{
MonoMethod *method = MONO_HANDLE_GETVAL (ref_method, method);
return mono_method_signature (method)->generic_param_count != 0;
}
ICALL_EXPORT gboolean
ves_icall_MonoMethod_get_IsGenericMethodDefinition (MonoReflectionMethodHandle ref_method, MonoError *Error)
{
MonoMethod *method = MONO_HANDLE_GETVAL (ref_method, method);
return method->is_generic;
}
static gboolean
set_array_generic_argument_handle_inflated (MonoDomain *domain, MonoGenericInst *inst, int i, MonoArrayHandle arr, MonoError *error)
{
HANDLE_FUNCTION_ENTER ();
error_init (error);
MonoReflectionTypeHandle rt = mono_type_get_object_handle (domain, inst->type_argv [i], error);
if (!is_ok (error))
goto leave;
MONO_HANDLE_ARRAY_SETREF (arr, i, rt);
leave:
HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
}
static gboolean
set_array_generic_argument_handle_gparam (MonoDomain *domain, MonoGenericContainer *container, int i, MonoArrayHandle arr, MonoError *error)
{
HANDLE_FUNCTION_ENTER ();
error_init (error);
MonoGenericParam *param = mono_generic_container_get_param (container, i);
MonoClass *pklass = mono_class_from_generic_parameter_internal (param);
MonoReflectionTypeHandle rt = mono_type_get_object_handle (domain, &pklass->byval_arg, error);
if (!is_ok (error))
goto leave;
MONO_HANDLE_ARRAY_SETREF (arr, i, rt);
leave:
HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
}
ICALL_EXPORT MonoArrayHandle
ves_icall_MonoMethod_GetGenericArguments (MonoReflectionMethodHandle ref_method, MonoError *error)
{
error_init (error);
MonoDomain *domain = MONO_HANDLE_DOMAIN (ref_method);
MonoMethod *method = MONO_HANDLE_GETVAL (ref_method, method);
if (method->is_inflated) {