mirror of
https://github.com/Ryujinx/Opentk.git
synced 2025-01-11 05:55:49 +00:00
[Rewrite] Refactored string prologue/epilogues
We currently have three categories of string parameters: `string`, `string[]` and `StringBuilder`. (OpenTK 1.2 adds one more: `ref string`.) Each category needs to be marshaled separately into a native character array. This commit implements the following changes: - string[] epilogues are now correctly emitted, instead of being ignored. - string[] prologues and epilogues now use the same local variable name. - all epilogues are now generated with a single pass over the function parameters, instead of requiring a separate pass for each category. - string prologues and epilogues now allocate local variables based on the relevant parameter *name* rather than the parameter *type*. Fixes issue #144.
This commit is contained in:
parent
c8a5bf5e32
commit
c32bf4ec5d
|
@ -286,18 +286,8 @@ namespace OpenTK.Rewrite
|
||||||
{
|
{
|
||||||
EmitReturnTypeWrapper(wrapper, native, body, il);
|
EmitReturnTypeWrapper(wrapper, native, body, il);
|
||||||
}
|
}
|
||||||
if (wrapper.Parameters.Any(p => p.ParameterType.Name == "StringBuilder"))
|
|
||||||
{
|
EmitParameterEpilogues(wrapper, native, body, il);
|
||||||
EmitStringBuilderEpilogue(wrapper, native, body, il);
|
|
||||||
}
|
|
||||||
if (wrapper.Parameters.Any(p => p.ParameterType.Name == "String" && p.ParameterType.IsArray))
|
|
||||||
{
|
|
||||||
EmitStringArrayEpilogue(wrapper, body, il);
|
|
||||||
}
|
|
||||||
if (wrapper.Parameters.Any(p => p.ParameterType.Name == "String" && !p.ParameterType.IsArray))
|
|
||||||
{
|
|
||||||
EmitStringEpilogue(wrapper, body, il);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.Contains("-debug"))
|
if (options.Contains("-debug"))
|
||||||
{
|
{
|
||||||
|
@ -517,11 +507,63 @@ namespace OpenTK.Rewrite
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void EmitStringBuilderEpilogue(MethodDefinition wrapper, MethodDefinition native, MethodBody body, ILProcessor il)
|
static void EmitParameterEpilogues(MethodDefinition wrapper, MethodDefinition native, MethodBody body, ILProcessor il)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < wrapper.Parameters.Count; i++)
|
foreach (var p in wrapper.Parameters)
|
||||||
{
|
{
|
||||||
var p = wrapper.Parameters[i].ParameterType;
|
if (p.ParameterType.Name == "StringBuilder")
|
||||||
|
{
|
||||||
|
EmitStringBuilderEpilogue(wrapper, native, p, body, il);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!p.ParameterType.IsArray && p.ParameterType.Name == "String")
|
||||||
|
{
|
||||||
|
EmitStringEpilogue(wrapper, p, body, il);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p.ParameterType.IsArray && p.ParameterType.GetElementType().Name == "String")
|
||||||
|
{
|
||||||
|
EmitStringArrayEpilogue(wrapper, p, body, il);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void EmitStringBuilderParameter(MethodDefinition method, ParameterDefinition parameter, MethodBody body, ILProcessor il)
|
||||||
|
{
|
||||||
|
var p = parameter.ParameterType;
|
||||||
|
|
||||||
|
// void GetShaderInfoLog(..., StringBuilder foo)
|
||||||
|
// IntPtr foo_sb_ptr;
|
||||||
|
// try {
|
||||||
|
// foo_sb_ptr = Marshal.AllocHGlobal(sb.Capacity + 1);
|
||||||
|
// glGetShaderInfoLog(..., foo_sb_ptr);
|
||||||
|
// MarshalPtrToStringBuilder(foo_sb_ptr, sb);
|
||||||
|
// }
|
||||||
|
// finally {
|
||||||
|
// Marshal.FreeHGlobal(sb_ptr);
|
||||||
|
// }
|
||||||
|
// Make sure we have imported StringBuilder::Capacity and Marshal::AllocHGlobal
|
||||||
|
var sb_get_capacity = method.Module.Import(TypeStringBuilder.Methods.First(m => m.Name == "get_Capacity"));
|
||||||
|
var alloc_hglobal = method.Module.Import(TypeMarshal.Methods.First(m => m.Name == "AllocHGlobal"));
|
||||||
|
|
||||||
|
// IntPtr ptr;
|
||||||
|
var variable_name = parameter.Name + " _sb_ptr";
|
||||||
|
body.Variables.Add(new VariableDefinition(variable_name, TypeIntPtr));
|
||||||
|
int index = body.Variables.Count - 1;
|
||||||
|
|
||||||
|
// ptr = Marshal.AllocHGlobal(sb.Capacity + 1);
|
||||||
|
il.Emit(OpCodes.Callvirt, sb_get_capacity);
|
||||||
|
il.Emit(OpCodes.Call, alloc_hglobal);
|
||||||
|
il.Emit(OpCodes.Stloc, index);
|
||||||
|
il.Emit(OpCodes.Ldloc, index);
|
||||||
|
|
||||||
|
// We'll emit the try-finally block in the epilogue implementation,
|
||||||
|
// because we haven't yet emitted all necessary instructions here.
|
||||||
|
}
|
||||||
|
|
||||||
|
static void EmitStringBuilderEpilogue(MethodDefinition wrapper, MethodDefinition native, ParameterDefinition parameter, MethodBody body, ILProcessor il)
|
||||||
|
{
|
||||||
|
var p = parameter.ParameterType;
|
||||||
if (p.Name == "StringBuilder")
|
if (p.Name == "StringBuilder")
|
||||||
{
|
{
|
||||||
// void GetShaderInfoLog(..., StringBuilder foo)
|
// void GetShaderInfoLog(..., StringBuilder foo)
|
||||||
|
@ -541,10 +583,10 @@ namespace OpenTK.Rewrite
|
||||||
var block = new ExceptionHandler(ExceptionHandlerType.Finally);
|
var block = new ExceptionHandler(ExceptionHandlerType.Finally);
|
||||||
block.TryStart = body.Instructions[0];
|
block.TryStart = body.Instructions[0];
|
||||||
|
|
||||||
var variable_name = p.Name + " _sb_ptr";
|
var variable_name = parameter.Name + " _sb_ptr";
|
||||||
var v = body.Variables.First(m => m.Name == variable_name);
|
var v = body.Variables.First(m => m.Name == variable_name);
|
||||||
il.Emit(OpCodes.Ldloc, v.Index);
|
il.Emit(OpCodes.Ldloc, v.Index);
|
||||||
il.Emit(OpCodes.Ldarg, i);
|
il.Emit(OpCodes.Ldarg, parameter.Index);
|
||||||
il.Emit(OpCodes.Call, ptr_to_sb);
|
il.Emit(OpCodes.Call, ptr_to_sb);
|
||||||
|
|
||||||
block.TryEnd = body.Instructions.Last();
|
block.TryEnd = body.Instructions.Last();
|
||||||
|
@ -556,10 +598,11 @@ namespace OpenTK.Rewrite
|
||||||
block.HandlerEnd = body.Instructions.Last();
|
block.HandlerEnd = body.Instructions.Last();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void EmitStringParameter(MethodDefinition wrapper, TypeReference p, MethodBody body, ILProcessor il)
|
static void EmitStringParameter(MethodDefinition wrapper, ParameterDefinition parameter, MethodBody body, ILProcessor il)
|
||||||
{
|
{
|
||||||
|
var p = parameter.ParameterType;
|
||||||
|
|
||||||
// string marshaling:
|
// string marshaling:
|
||||||
// IntPtr ptr = MarshalStringToPtr(str);
|
// IntPtr ptr = MarshalStringToPtr(str);
|
||||||
// try { calli }
|
// try { calli }
|
||||||
|
@ -567,7 +610,7 @@ namespace OpenTK.Rewrite
|
||||||
var marshal_str_to_ptr = wrapper.Module.Import(TypeBindingsBase.Methods.First(m => m.Name == "MarshalStringToPtr"));
|
var marshal_str_to_ptr = wrapper.Module.Import(TypeBindingsBase.Methods.First(m => m.Name == "MarshalStringToPtr"));
|
||||||
|
|
||||||
// IntPtr ptr;
|
// IntPtr ptr;
|
||||||
var variable_name = p.Name + "_string_ptr";
|
var variable_name = parameter.Name + "_string_ptr";
|
||||||
body.Variables.Add(new VariableDefinition(variable_name, TypeIntPtr));
|
body.Variables.Add(new VariableDefinition(variable_name, TypeIntPtr));
|
||||||
int index = body.Variables.Count - 1;
|
int index = body.Variables.Count - 1;
|
||||||
|
|
||||||
|
@ -579,34 +622,30 @@ namespace OpenTK.Rewrite
|
||||||
// The finally block will be emitted in the function epilogue
|
// The finally block will be emitted in the function epilogue
|
||||||
}
|
}
|
||||||
|
|
||||||
static void EmitStringEpilogue(MethodDefinition wrapper, MethodBody body, ILProcessor il)
|
static void EmitStringEpilogue(MethodDefinition wrapper, ParameterDefinition parameter, 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 p = parameter.ParameterType;
|
||||||
var free = wrapper.Module.Import(TypeBindingsBase.Methods.First(m => m.Name == "FreeStringPtr"));
|
var free = wrapper.Module.Import(TypeBindingsBase.Methods.First(m => m.Name == "FreeStringPtr"));
|
||||||
|
|
||||||
// FreeStringPtr(ptr)
|
// FreeStringPtr(ptr)
|
||||||
var variable_name = p.Name + "_string_ptr";
|
var variable_name = parameter.Name + "_string_ptr";
|
||||||
var v = body.Variables.First(m => m.Name == variable_name);
|
var v = body.Variables.First(m => m.Name == variable_name);
|
||||||
il.Emit(OpCodes.Ldloc, v.Index);
|
il.Emit(OpCodes.Ldloc, v.Index);
|
||||||
il.Emit(OpCodes.Call, free);
|
il.Emit(OpCodes.Call, free);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void EmitStringArrayParameter(MethodDefinition wrapper, TypeReference p, MethodBody body, ILProcessor il)
|
static void EmitStringArrayParameter(MethodDefinition wrapper, ParameterDefinition parameter, MethodBody body, ILProcessor il)
|
||||||
{
|
{
|
||||||
|
var p = parameter.ParameterType;
|
||||||
|
|
||||||
// string[] masrhaling:
|
// string[] masrhaling:
|
||||||
// IntPtr ptr = MarshalStringArrayToPtr(strings);
|
// IntPtr ptr = MarshalStringArrayToPtr(strings);
|
||||||
// try { calli }
|
// try { calli }
|
||||||
// finally { UnmarshalStringArray(ptr); }
|
// finally { FreeStringArrayPtr(ptr); }
|
||||||
var marshal_str_array_to_ptr = wrapper.Module.Import(TypeBindingsBase.Methods.First(m => m.Name == "MarshalStringArrayToPtr"));
|
var marshal_str_array_to_ptr = wrapper.Module.Import(TypeBindingsBase.Methods.First(m => m.Name == "MarshalStringArrayToPtr"));
|
||||||
|
|
||||||
// IntPtr ptr;
|
// IntPtr ptr;
|
||||||
var variable_name = p.Name + " _string_array_ptr";
|
var variable_name = parameter.Name + "_string_array_ptr";
|
||||||
body.Variables.Add(new VariableDefinition(variable_name, TypeIntPtr));
|
body.Variables.Add(new VariableDefinition(variable_name, TypeIntPtr));
|
||||||
int index = body.Variables.Count - 1;
|
int index = body.Variables.Count - 1;
|
||||||
|
|
||||||
|
@ -618,28 +657,30 @@ namespace OpenTK.Rewrite
|
||||||
// The finally block will be emitted in the function epilogue
|
// The finally block will be emitted in the function epilogue
|
||||||
}
|
}
|
||||||
|
|
||||||
static void EmitStringArrayEpilogue(MethodDefinition wrapper, MethodBody body, ILProcessor il)
|
static void EmitStringArrayEpilogue(MethodDefinition wrapper, ParameterDefinition parameter, 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)
|
|
||||||
{
|
{
|
||||||
|
// Note: only works for string vectors (1d arrays).
|
||||||
|
// We do not (and will probably never) support 2d or higher string arrays
|
||||||
|
var p = parameter.ParameterType;
|
||||||
var free = wrapper.Module.Import(TypeBindingsBase.Methods.First(m => m.Name == "FreeStringArrayPtr"));
|
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)
|
// FreeStringArrayPtr(string_array_ptr, string_array.Length)
|
||||||
var variable_name = p.Name + "_string_array_ptr";
|
var variable_name = parameter.Name + "_string_array_ptr";
|
||||||
var v = body.Variables.First(m => m.Name == variable_name);
|
var v = body.Variables.First(m => m.Name == variable_name);
|
||||||
|
|
||||||
|
// load string_array_ptr
|
||||||
il.Emit(OpCodes.Ldloc, v.Index);
|
il.Emit(OpCodes.Ldloc, v.Index);
|
||||||
il.Emit(OpCodes.Ldarg, i);
|
|
||||||
il.Emit(OpCodes.Callvirt, get_length);
|
// load string_array.Length
|
||||||
|
il.Emit(OpCodes.Ldarg, parameter.Index);
|
||||||
|
il.Emit(OpCodes.Ldlen);
|
||||||
|
il.Emit(OpCodes.Conv_I4);
|
||||||
|
|
||||||
|
// call FreeStringArrayPtr
|
||||||
il.Emit(OpCodes.Call, free);
|
il.Emit(OpCodes.Call, free);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void EmitConvenienceWrapper(MethodDefinition wrapper,
|
static void EmitConvenienceWrapper(MethodDefinition wrapper,
|
||||||
MethodDefinition native, int difference, MethodBody body, ILProcessor il)
|
MethodDefinition native, int difference, MethodBody body, ILProcessor il)
|
||||||
{
|
{
|
||||||
if (wrapper.Parameters.Count > 2)
|
if (wrapper.Parameters.Count > 2)
|
||||||
|
@ -707,43 +748,17 @@ namespace OpenTK.Rewrite
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < method.Parameters.Count; i++)
|
for (i = 0; i < method.Parameters.Count; i++)
|
||||||
{
|
{
|
||||||
|
var parameter = method.Parameters[i];
|
||||||
var p = method.Module.Import(method.Parameters[i].ParameterType);
|
var p = method.Module.Import(method.Parameters[i].ParameterType);
|
||||||
il.Emit(OpCodes.Ldarg, i);
|
il.Emit(OpCodes.Ldarg, i);
|
||||||
|
|
||||||
if (p.Name == "StringBuilder")
|
if (p.Name == "StringBuilder")
|
||||||
{
|
{
|
||||||
// void GetShaderInfoLog(..., StringBuilder foo)
|
EmitStringBuilderParameter(method, parameter, body, il);
|
||||||
// IntPtr foo_sb_ptr;
|
|
||||||
// try {
|
|
||||||
// foo_sb_ptr = Marshal.AllocHGlobal(sb.Capacity + 1);
|
|
||||||
// glGetShaderInfoLog(..., foo_sb_ptr);
|
|
||||||
// MarshalPtrToStringBuilder(foo_sb_ptr, sb);
|
|
||||||
// }
|
|
||||||
// finally {
|
|
||||||
// Marshal.FreeHGlobal(sb_ptr);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Make sure we have imported StringBuilder::Capacity and Marshal::AllocHGlobal
|
|
||||||
var sb_get_capacity = method.Module.Import(TypeStringBuilder.Methods.First(m => m.Name == "get_Capacity"));
|
|
||||||
var alloc_hglobal = method.Module.Import(TypeMarshal.Methods.First(m => m.Name == "AllocHGlobal"));
|
|
||||||
|
|
||||||
// IntPtr ptr;
|
|
||||||
var variable_name = p.Name + " _sb_ptr";
|
|
||||||
body.Variables.Add(new VariableDefinition(variable_name, TypeIntPtr));
|
|
||||||
int index = body.Variables.Count - 1;
|
|
||||||
|
|
||||||
// ptr = Marshal.AllocHGlobal(sb.Capacity + 1);
|
|
||||||
il.Emit(OpCodes.Callvirt, sb_get_capacity);
|
|
||||||
il.Emit(OpCodes.Call, alloc_hglobal);
|
|
||||||
il.Emit(OpCodes.Stloc, index);
|
|
||||||
il.Emit(OpCodes.Ldloc, index);
|
|
||||||
|
|
||||||
// We'll emit the try-finally block in the epilogue implementation,
|
|
||||||
// because we haven't yet emitted all necessary instructions here.
|
|
||||||
}
|
}
|
||||||
else if (p.Name == "String" && !p.IsArray)
|
else if (p.Name == "String" && !p.IsArray)
|
||||||
{
|
{
|
||||||
EmitStringParameter(method, p, body, il);
|
EmitStringParameter(method, parameter, body, il);
|
||||||
}
|
}
|
||||||
else if (p.IsByReference)
|
else if (p.IsByReference)
|
||||||
{
|
{
|
||||||
|
@ -845,7 +860,7 @@ namespace OpenTK.Rewrite
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
EmitStringArrayParameter(method, p, body, il);
|
EmitStringArrayParameter(method, parameter, body, il);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue