static unsafe MonoObject *CreateArray(MonoObject *typeobj, ulong elements) { var type = (Type)GetMonoObjectTarget(typeobj); var obj = Array.CreateInstance(type, (int)elements); return((MonoObject *)GetMonoObject(obj)); }
static unsafe MonoObject *GetNullableElementType(MonoObject *typeobj) { var type = (Type)GetMonoObjectTarget(typeobj); var elementType = type.GetGenericArguments() [0]; return((MonoObject *)GetMonoObject(elementType)); }
static unsafe void SetPendingException(MonoObject *exception_obj) { var exc = (Exception)GetMonoObjectTarget(exception_obj); log_coreclr($"Runtime.SetPendingException ({exc})"); ObjectiveCMarshal.SetMessageSendPendingException(exc); }
static unsafe void SetArrayObjectValue(MonoObject *arrayobj, ulong index, MonoObject *mobj) { var array = (Array)GetMonoObjectTarget(arrayobj); var obj = GetMonoObjectTarget(mobj); array.SetValue(obj, (long)index); }
static unsafe MonoObject *GetArrayObjectValue(MonoObject *arrayobj, ulong index) { var array = (Array)GetMonoObjectTarget(arrayobj); var obj = array.GetValue((long)index); return((MonoObject *)GetMonoObject(obj)); }
static unsafe MonoObject *Box(MonoObject *typeobj, IntPtr value) { var type = (Type)GetMonoObjectTarget(typeobj); var rv = Box(type, value); return((MonoObject *)GetMonoObject(rv)); }
static unsafe void MonoHashTableInsert(MonoObject *tableobj, IntPtr key, MonoObject *valueobj) { var table = (MonoHashTable)GetMonoObjectTarget(tableobj); var value = GetMonoObjectTarget(valueobj); table.Insert(key, value); }
unsafe static IntPtr ClassGetName(MonoObject *typeobj) { var type = (Type)GetMonoObjectTarget(typeobj); var rv = type.Name; return(Marshal.StringToHGlobalAuto(rv)); }
unsafe static bool IsDelegate(MonoObject *typeobj) { var type = (Type)GetMonoObjectTarget(typeobj); var rv = typeof(MulticastDelegate).IsAssignableFrom(type); log_coreclr($"IsDelegate ({type.FullName}) => {rv}"); return(rv); }
static unsafe MonoObject *InvokeMethod(MonoObject *methodobj, MonoObject *instanceobj, IntPtr native_parameters) { var method = (MethodBase)GetMonoObjectTarget(methodobj); var instance = GetMonoObjectTarget(instanceobj); var rv = InvokeMethod(method, instance, native_parameters); return((MonoObject *)GetMonoObject(rv)); }
static unsafe void SetArrayStructValue(MonoObject *arrayobj, ulong index, MonoObject *typeobj, IntPtr valueptr) { var array = (Array)GetMonoObjectTarget(arrayobj); var elementType = (Type)GetMonoObjectTarget(typeobj); var obj = Box(elementType, valueptr); array.SetValue(obj, (long)index); }
// This should work like mono_class_from_mono_type. static unsafe MonoObject *TypeToClass(MonoObject *typeobj) { var type = (Type)GetMonoObjectTarget(typeobj); if (type.IsByRef) { type = type.GetElementType(); } return((MonoObject *)GetMonoObject(type)); }
static object GetMonoObjectTarget(MonoObjectPtr mobj) { if (mobj == IntPtr.Zero) { return(null); } unsafe { MonoObject *monoobj = (MonoObject *)mobj; return(GetGCHandleTarget(monoobj->GCHandle)); } }
unsafe static void GCReferenceQueueAdd(MonoObject *mqueue, MonoObject *mobj, IntPtr user_data) { var queue = (ReferenceQueue)GetMonoObjectTarget(mqueue); var obj = GetMonoObjectTarget(mobj); var entry = new ReferenceQueueEntry() { Queue = queue, UserData = user_data, }; queue.Table.Add(obj, entry); }
static unsafe IntPtr GetMethodSignature(MonoObject *methodobj) { var method = (MethodBase)GetMonoObjectTarget(methodobj); var parameters = method.GetParameters(); var parameterCount = parameters.Length; var rv = Marshal.AllocHGlobal(sizeof(MonoMethodSignature) + sizeof(MonoObjectPtr) * parameterCount); MonoMethodSignature *signature = (MonoMethodSignature *)rv; signature->Method = methodobj; xamarin_mono_object_retain(methodobj); signature->ParameterCount = parameterCount; signature->ReturnType = (MonoObject *)GetMonoObject(GetMethodReturnType(method)); MonoObject **mparams = &signature->Parameters; for (var i = 0; i < parameterCount; i++) { var p = parameters [i]; mparams [i] = (MonoObject *)GetMonoObject(p.ParameterType); } return(rv); }
static unsafe MonoObject *GetEnumBaseType(MonoObject *typeobj) { var type = (Type)GetMonoObjectTarget(typeobj); return((MonoObject *)GetMonoObject(GetEnumBaseType(type))); }
unsafe static bool IsEnum(MonoObject *typeobj) { var type = (Type)GetMonoObjectTarget(typeobj); return(type.IsEnum); }
static unsafe bool IsNullable(MonoObject *type) { return(IsNullable((Type)GetMonoObjectTarget(type))); }
static unsafe MonoObject *MonoHashTableLookup(MonoObject *tableobj, IntPtr key) { var dict = (MonoHashTable)GetMonoObjectTarget(tableobj); return((MonoObject *)GetMonoObject(dict.Lookup(key))); }
static unsafe IntPtr GetMethodFullName(MonoObject *mobj) { return(Marshal.StringToHGlobalAuto(GetMethodFullName((MethodBase)GetMonoObjectTarget(mobj)))); }
unsafe static extern void xamarin_mono_object_retain(MonoObject *mono_object);
unsafe static bool IsClassOfType(MonoObject *typeobj, TypeLookup match) { return(IsClassOfType((Type)GetMonoObjectTarget(typeobj), match)); }
static unsafe ulong GetArrayLength(MonoObject *obj) { var array = (Array)GetMonoObjectTarget(obj); return((ulong)array.Length); }
static unsafe MonoObject *GetElementClass(MonoObject *classobj) { var type = (Type)GetMonoObjectTarget(classobj); return((MonoObject *)GetMonoObject(type.GetElementType())); }
static unsafe IntPtr StringToUtf8(MonoObject *obj) { var str = (string)GetMonoObjectTarget(obj); return(Marshal.StringToHGlobalAuto(str)); }
// Return value: NULL or a MonoObject* that must be released with xamarin_mono_object_safe_release. // Any MonoObject* ref parameters must also be retained and must be released with xamarin_mono_object_release. static object InvokeMethod(MethodBase method, object instance, IntPtr native_parameters) { var methodParameters = method.GetParameters(); var parameters = new object [methodParameters.Length]; var inputParameters = new object [methodParameters.Length]; var nativeParameters = new IntPtr [methodParameters.Length]; // Copy native array of void* to managed array of IntPtr to make the subsequent code simpler. unsafe { IntPtr *nativeParams = (IntPtr *)native_parameters; for (var i = 0; i < methodParameters.Length; i++) { nativeParameters [i] = nativeParams [i]; } } // Log our input log_coreclr($"InvokeMethod ({method.DeclaringType.FullName}::{method}, {instance}, 0x{native_parameters.ToString ("x")})"); for (var i = 0; i < methodParameters.Length; i++) { var nativeParam = nativeParameters [i]; var p = methodParameters [i]; var paramType = p.ParameterType; if (paramType.IsByRef) { paramType = paramType.GetElementType(); } log_coreclr($" Argument #{i + 1}: Type = {p.ParameterType.FullName} IsByRef: {p.ParameterType.IsByRef} IsOut: {p.IsOut} IsClass: {paramType.IsClass} IsInterface: {paramType.IsInterface} NativeParameter: 0x{nativeParam.ToString ("x")}"); } // Process the arguments, and convert to what MethodBase.Invoke expects for (var i = 0; i < methodParameters.Length; i++) { var nativeParam = nativeParameters [i]; var p = methodParameters [i]; var paramType = p.ParameterType; var isByRef = paramType.IsByRef; if (isByRef) { paramType = paramType.GetElementType(); } log_coreclr($" Marshalling #{i + 1}: IntPtr => 0x{nativeParam.ToString ("x")} => {p.ParameterType.FullName} [...]"); if (paramType == typeof(IntPtr)) { log_coreclr($" IntPtr"); if (isByRef) { if (p.IsOut) { parameters [i] = Marshal.AllocHGlobal(IntPtr.Size); } else { parameters [i] = nativeParam == IntPtr.Zero ? IntPtr.Zero : Marshal.ReadIntPtr(nativeParam); } } else { parameters [i] = nativeParam == IntPtr.Zero ? IntPtr.Zero : Marshal.ReadIntPtr(nativeParam); } log_coreclr($" => 0x{((IntPtr) parameters [i]).ToString ("x")}"); } else if (paramType.IsClass || paramType.IsInterface || (paramType.IsValueType && IsNullable(paramType))) { log_coreclr($" IsClass/IsInterface/IsNullable IsByRef: {isByRef} IsOut: {p.IsOut} ParameterType: {paramType}"); if (nativeParam != IntPtr.Zero) { unsafe { MonoObject *mono_obj = (MonoObject *)nativeParam; // dereference if it's a byref type if (isByRef) { mono_obj = *(MonoObject **)mono_obj; } // get the object parameters [i] = GetMonoObjectTarget(mono_obj); } } log_coreclr($" => {(parameters [i] == null ? "<null>" : parameters [i].GetType ().FullName)}"); } else if (paramType.IsValueType) { log_coreclr($" IsValueType IsByRef: {isByRef} IsOut: {p.IsOut} nativeParam: 0x{nativeParam.ToString ("x")} ParameterType: {paramType}"); if (nativeParam != IntPtr.Zero) { // We need to unwrap nullable types and enum types to their underlying struct type. var structType = paramType; Type enumType = null; if (IsNullable(structType)) { structType = Nullable.GetUnderlyingType(structType); } if (structType.IsEnum) { enumType = structType; structType = Enum.GetUnderlyingType(structType); } // convert the pointer to the corresponding structure var vt = PtrToStructure(nativeParam, structType); // convert the structure to the enum type if that's what we need if (enumType != null) { vt = Enum.ToObject(enumType, vt); } parameters [i] = vt; } log_coreclr($" => {(parameters [i] == null ? "<null>" : parameters [i].ToString ())}"); } else { throw ErrorHelper.CreateError(8037, Errors.MX8037 /* Don't know how to marshal the parameter of type {p.ParameterType.FullName} for parameter {p.Name} in call to {method} */, p.ParameterType.FullName, p.Name, method); } } // Make a copy of the array of parameters, so that we can figure out if there were any ref parameters that the method modified. parameters.CopyTo(inputParameters, 0); // Call the actual method log_coreclr($" Invoking..."); object rv = null; try { rv = method.Invoke(instance, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance, null, parameters, null); } catch (TargetInvocationException tie) { var ex = tie.InnerException ?? tie; // This will re-throw the original exception and preserve the stacktrace. ExceptionDispatchInfo.Capture(ex).Throw(); } // Copy any byref parameters back out again var byrefParameterCount = 0; for (var i = 0; i < methodParameters.Length; i++) { var p = methodParameters [i]; if (!p.IsOut && !p.ParameterType.IsByRef) { continue; } byrefParameterCount++; log_coreclr($" Marshalling #{i + 1} back (Type: {p.ParameterType.FullName}) value: {(parameters [i] == null ? "<null>" : parameters [i].GetType ().FullName)}"); var parameterType = p.ParameterType.GetElementType(); var isMonoObject = parameterType.IsClass || parameterType.IsInterface || (parameterType.IsValueType && IsNullable(parameterType)); var nativeParam = nativeParameters [i]; if (nativeParam == IntPtr.Zero) { log_coreclr($" No output pointer was provided."); continue; } if (parameters [i] == inputParameters [i]) { log_coreclr($" The argument didn't change, no marshalling required"); if (parameters [i] != null && parameterType != typeof(IntPtr) && isMonoObject) { // byref parameters must be retained xamarin_mono_object_retain(Marshal.ReadIntPtr(nativeParam)); } continue; } if (parameterType == typeof(IntPtr)) { Marshal.WriteIntPtr(nativeParam, (IntPtr)parameters [i]); log_coreclr($" IntPtr: 0x{((IntPtr) parameters [i]).ToString ("x")} => Type: {parameters [i]?.GetType ()} nativeParam: 0x{nativeParam.ToString ("x")}"); } else if (isMonoObject) { var ptr = GetMonoObject(parameters [i]); Marshal.WriteIntPtr(nativeParam, ptr); log_coreclr($" IsClass/IsInterface/IsNullable: {(parameters [i] == null ? "<null>" : parameters [i].GetType ().FullName)} nativeParam: 0x{nativeParam.ToString ("x")} -> MonoObject: 0x{ptr.ToString ("x")}"); } else if (parameterType.IsValueType) { StructureToPtr(parameters [i], nativeParam); log_coreclr($" IsValueType: {(parameters [i] == null ? "<null>" : parameters [i].ToString ())} nativeParam: 0x{nativeParam.ToString ("x")}"); } else { throw ErrorHelper.CreateError(8038, Errors.MX8038 /* Don't know how to marshal back the parameter of type {p.ParameterType.FullName} for parameter {p.Name} in call to {method} */, p.ParameterType.FullName, p.Name, method); } } // we're done! log_coreclr($" Invoke complete with {byrefParameterCount} ref parameters and return value of type {rv?.GetType ()}"); return(rv); }
static unsafe object GetMonoObjectTarget(MonoObject *mobj) { return(GetMonoObjectTarget((IntPtr)mobj)); }
static unsafe int SizeOf(MonoObject *typeobj) { var type = (Type)GetMonoObjectTarget(typeobj); return(SizeOf(type)); }
static unsafe MonoObject *GetMethodDeclaringType(MonoObject *mobj) { var method = (MethodBase)GetMonoObjectTarget(mobj); return((MonoObject *)GetMonoObject(method.DeclaringType)); }