mirror of
https://github.com/Ryujinx/Opentk.git
synced 2024-12-23 16:05:32 +00:00
Implemented marshaling for string arrays
This allows functions such as GL.ShaderSource to run on Mono without crashing.
This commit is contained in:
parent
406de0b846
commit
f15c9ecb95
|
@ -47,6 +47,7 @@ namespace OpenTK.Rewrite
|
||||||
// mscorlib types
|
// mscorlib types
|
||||||
static AssemblyDefinition mscorlib;
|
static AssemblyDefinition mscorlib;
|
||||||
static TypeDefinition TypeMarshal;
|
static TypeDefinition TypeMarshal;
|
||||||
|
static TypeDefinition TypeStringArray;
|
||||||
static TypeDefinition TypeStringBuilder;
|
static TypeDefinition TypeStringBuilder;
|
||||||
static TypeDefinition TypeVoid;
|
static TypeDefinition TypeVoid;
|
||||||
static TypeDefinition TypeIntPtr;
|
static TypeDefinition TypeIntPtr;
|
||||||
|
@ -111,6 +112,7 @@ namespace OpenTK.Rewrite
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
TypeMarshal = mscorlib.MainModule.GetType("System.Runtime.InteropServices.Marshal");
|
TypeMarshal = mscorlib.MainModule.GetType("System.Runtime.InteropServices.Marshal");
|
||||||
|
TypeStringArray = mscorlib.MainModule.GetType("System.String").MakeArrayType().Resolve();
|
||||||
TypeStringBuilder = mscorlib.MainModule.GetType("System.Text.StringBuilder");
|
TypeStringBuilder = mscorlib.MainModule.GetType("System.Text.StringBuilder");
|
||||||
TypeVoid = mscorlib.MainModule.GetType("System.Void");
|
TypeVoid = mscorlib.MainModule.GetType("System.Void");
|
||||||
TypeIntPtr = mscorlib.MainModule.GetType("System.IntPtr");
|
TypeIntPtr = mscorlib.MainModule.GetType("System.IntPtr");
|
||||||
|
@ -328,7 +330,7 @@ namespace OpenTK.Rewrite
|
||||||
// try {
|
// try {
|
||||||
// foo_sb_ptr = Marshal.AllocHGlobal(sb.Capacity + 1); -- already emitted
|
// foo_sb_ptr = Marshal.AllocHGlobal(sb.Capacity + 1); -- already emitted
|
||||||
// glGetShaderInfoLog(..., foo_sb_ptr); -- already emitted
|
// glGetShaderInfoLog(..., foo_sb_ptr); -- already emitted
|
||||||
// MarshalStringBuilder(foo_sb_ptr, foo);
|
// MarshalPtrToStringBuilder(foo_sb_ptr, foo);
|
||||||
// }
|
// }
|
||||||
// finally {
|
// finally {
|
||||||
// Marshal.FreeHGlobal(foo_sb_ptr);
|
// Marshal.FreeHGlobal(foo_sb_ptr);
|
||||||
|
@ -358,6 +360,52 @@ namespace OpenTK.Rewrite
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void EmitStringArrayParameter(MethodDefinition wrapper, TypeReference p, MethodBody body, ILProcessor il)
|
||||||
|
{
|
||||||
|
// string[] masrhaling:
|
||||||
|
// IntPtr ptr = MarshalStringArrayToPtr(strings);
|
||||||
|
// try {
|
||||||
|
// calli
|
||||||
|
// }
|
||||||
|
// finally {
|
||||||
|
// UnmarshalStringArray(ptr);
|
||||||
|
// }
|
||||||
|
var marshal_str_array_to_ptr = wrapper.Module.Import(TypeBindingsBase.Methods.First(m => m.Name == "MarshalStringArrayToPtr"));
|
||||||
|
|
||||||
|
// IntPtr ptr;
|
||||||
|
var variable_name = p.Name + " _string_array_ptr";
|
||||||
|
body.Variables.Add(new VariableDefinition(variable_name, TypeIntPtr));
|
||||||
|
int index = body.Variables.Count - 1;
|
||||||
|
|
||||||
|
// ptr = MarshalStringArrayToPtr(strings);
|
||||||
|
il.Emit(OpCodes.Call, marshal_str_array_to_ptr);
|
||||||
|
il.Emit(OpCodes.Stloc, index);
|
||||||
|
il.Emit(OpCodes.Ldloc, index);
|
||||||
|
|
||||||
|
// The finally block will be emitted in the function epilogue
|
||||||
|
}
|
||||||
|
|
||||||
|
static void EmitStringArrayEpilogue(MethodDefinition wrapper, MethodDefinition native, MethodBody body, ILProcessor il)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < wrapper.Parameters.Count; i++)
|
||||||
|
{
|
||||||
|
var p = wrapper.Parameters[i].ParameterType;
|
||||||
|
if (p.Name == "String" && p.IsArray)
|
||||||
|
{
|
||||||
|
var free = wrapper.Module.Import(TypeBindingsBase.Methods.First(m => m.Name == "FreeStringArrayPtr"));
|
||||||
|
var get_length = wrapper.Module.Import(TypeStringArray.Methods.First(m => m.Name == "get_Length"));
|
||||||
|
|
||||||
|
// FreeStringArrayPtr(string_array_ptr, string_array.Length)
|
||||||
|
var variable_name = p.Name + "_string_array_ptr";
|
||||||
|
var v = body.Variables.First(m => m.Name == variable_name);
|
||||||
|
il.Emit(OpCodes.Ldloc, v.Index);
|
||||||
|
il.Emit(OpCodes.Ldarg, i);
|
||||||
|
il.Emit(OpCodes.Callvirt, get_length);
|
||||||
|
il.Emit(OpCodes.Call, free);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void EmitConvenienceWrapper(MethodDefinition wrapper,
|
private static void EmitConvenienceWrapper(MethodDefinition wrapper,
|
||||||
MethodDefinition native, int difference, MethodBody body, ILProcessor il)
|
MethodDefinition native, int difference, MethodBody body, ILProcessor il)
|
||||||
{
|
{
|
||||||
|
@ -491,8 +539,7 @@ namespace OpenTK.Rewrite
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// String[] requires special marshalling.
|
EmitStringArrayParameter(method, p, body, il);
|
||||||
// Let the runtime handle this for now.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,13 +119,13 @@ namespace OpenTK
|
||||||
/// unique objects, but all instances of ES10.GL should return the same object.</remarks>
|
/// unique objects, but all instances of ES10.GL should return the same object.</remarks>
|
||||||
protected abstract object SyncRoot { get; }
|
protected abstract object SyncRoot { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Marshals a pointer to a null-terminated byte array to the specified <c>StringBuilder</c>.
|
/// Marshals a pointer to a null-terminated byte array to the specified <c>StringBuilder</c>.
|
||||||
/// This method supports OpenTK and is not intended to be called by user code.
|
/// This method supports OpenTK and is not intended to be called by user code.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ptr">A pointer to a null-terminated byte array.</param>
|
/// <param name="ptr">A pointer to a null-terminated byte array.</param>
|
||||||
/// <param name="sb">The StringBuilder to receive the contents of the pointer.</param>
|
/// <param name="sb">The StringBuilder to receive the contents of the pointer.</param>
|
||||||
protected static void MarshalPtrToStringBuilder(IntPtr ptr, StringBuilder sb)
|
protected static void MarshalPtrToStringBuilder(IntPtr ptr, StringBuilder sb)
|
||||||
{
|
{
|
||||||
if (ptr == IntPtr.Zero)
|
if (ptr == IntPtr.Zero)
|
||||||
throw new ArgumentException("ptr");
|
throw new ArgumentException("ptr");
|
||||||
|
@ -144,6 +144,52 @@ namespace OpenTK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Marshals a string array to unmanaged memory by calling
|
||||||
|
/// Marshal.AllocHGlobal for each element.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An unmanaged pointer to an array of null-terminated strings</returns>
|
||||||
|
/// <param name="str_array">The string array to marshal.</param>
|
||||||
|
protected static IntPtr MarshalStringArrayToPtr(string[] str_array)
|
||||||
|
{
|
||||||
|
IntPtr ptr = IntPtr.Zero;
|
||||||
|
if (str_array != null && str_array.Length != 0)
|
||||||
|
{
|
||||||
|
ptr = Marshal.AllocHGlobal(str_array.Length * IntPtr.Size);
|
||||||
|
if (ptr == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
throw new OutOfMemoryException();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < str_array.Length; i++)
|
||||||
|
{
|
||||||
|
IntPtr str = Marshal.StringToHGlobalAnsi(str_array[i]);
|
||||||
|
if (str == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
throw new OutOfMemoryException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Marshal.WriteIntPtr(ptr, i * IntPtr.Size, str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Frees a string array that has previously been
|
||||||
|
/// marshalled by <c>MarshalStringArrayToPtr</c>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ptr">An unmanaged pointer allocated by <c>MarshalStringArrayToPtr</c></param>
|
||||||
|
/// <param name="length">The length of the string array.</param>
|
||||||
|
protected static void FreeStringArrayPtr(IntPtr ptr, int length)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(Marshal.ReadIntPtr(ptr, length * IntPtr.Size));
|
||||||
|
}
|
||||||
|
Marshal.FreeHGlobal(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Internal Members
|
#region Internal Members
|
||||||
|
|
Loading…
Reference in a new issue