Removed uses of out variables and introduced a generated variable identifier class.

This commit is contained in:
Jarl Gullberg 2017-05-29 18:57:13 +02:00
parent 092ffb480c
commit 760e68ed4e
No known key found for this signature in database
GPG key ID: 750FF6F6BDA72D23
3 changed files with 106 additions and 56 deletions

View file

@ -1,7 +1,43 @@
using System;
namespace OpenTK.Rewrite namespace OpenTK.Rewrite
{ {
/// <summary>
/// Acts as a unique identifier for a generated named variable that can be passed between methods. Replaces uses of
/// variable names from Mono.Cecil.
/// </summary>
public class GeneratedVariableIdentifier public class GeneratedVariableIdentifier
{ {
/// <summary>
/// The name of the generated variable.
/// </summary>
public string Name { get; }
/// <summary>
/// The index of the generated variable in its method.
/// </summary>
public int Index { get; }
/// <summary>
/// Initializes a new instance of the <see cref="GeneratedVariableIdentifier"/> class.
/// </summary>
/// <param name="name">The name of the generated variable.</param>
/// <param name="index">The index of the generated variable in its method.</param>
/// <exception cref="ArgumentException"></exception>
public GeneratedVariableIdentifier(string name, int index)
{
if (string.IsNullOrEmpty(name))
{
throw new ArgumentException("The name argument cannot be null or empty", nameof(name));
}
if (index < 0)
{
throw new ArgumentException("The index must be greater than zero.", nameof(index));
}
this.Name = name;
this.Index = index;
}
} }
} }

View file

@ -52,6 +52,7 @@
<Reference Include="System.Core" /> <Reference Include="System.Core" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="GeneratedVariableIdentifier.cs" />
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>

View file

@ -266,17 +266,15 @@ namespace OpenTK.Rewrite
} }
// Patch convenience wrappers // Patch convenience wrappers
int stringBuilderPointerVarIndex = -1; List<GeneratedVariableIdentifier> generatedVariables = new List<GeneratedVariableIdentifier>();
int stringPointerVarIndex = -1; if (wrapper.Parameters.Count == native.Parameters.Count)
int stringArrayPointerVarIndex = -1;
if (wrapper.Parameters.Count == native.Parameters.Count)
{ {
EmitParameters(wrapper, native, body, il, out stringBuilderPointerVarIndex, out stringPointerVarIndex, out stringArrayPointerVarIndex); generatedVariables = EmitParameters(wrapper, native, body, il);
} }
else else
{ {
int difference = native.Parameters.Count - wrapper.Parameters.Count; int difference = native.Parameters.Count - wrapper.Parameters.Count;
EmitConvenienceWrapper(wrapper, native, difference, body, il); generatedVariables = EmitConvenienceWrapper(wrapper, native, difference, body, il);
} }
if (slot != -1) if (slot != -1)
@ -298,7 +296,7 @@ namespace OpenTK.Rewrite
EmitReturnTypeWrapper(wrapper, native, body, il); EmitReturnTypeWrapper(wrapper, native, body, il);
} }
EmitParameterEpilogues(wrapper, native, body, il, stringBuilderPointerVarIndex, stringPointerVarIndex, stringArrayPointerVarIndex); EmitParameterEpilogues(wrapper, native, body, il, generatedVariables);
if (options.Contains("-debug")) if (options.Contains("-debug"))
{ {
@ -519,29 +517,28 @@ namespace OpenTK.Rewrite
} }
static void EmitParameterEpilogues(MethodDefinition wrapper, MethodDefinition native, MethodBody body, ILProcessor il, static void EmitParameterEpilogues(MethodDefinition wrapper, MethodDefinition native, MethodBody body, ILProcessor il,
int stringBuilderPointerVarIndex, int stringPointerVarIndex, int stringArrayPointerVarIndex) List<GeneratedVariableIdentifier> generatedVariables)
{ {
foreach (var p in wrapper.Parameters) // TODO: Should not need to check for >= 0 here, but StringBuilder foreach (var p in wrapper.Parameters)
// TODO: requires it for some reason. Find out why
{ {
if (p.ParameterType.Name == "StringBuilder" && stringBuilderPointerVarIndex >= 0) if (p.ParameterType.Name == "StringBuilder")
{ {
EmitStringBuilderEpilogue(wrapper, native, p, body, il, stringBuilderPointerVarIndex); EmitStringBuilderEpilogue(wrapper, native, p, body, il, generatedVariables.FirstOrDefault(g => g.Name == p.Name + "_sb_ptr"));
} }
if (!p.ParameterType.IsArray && p.ParameterType.Name == "String" && stringPointerVarIndex >= 0) if (!p.ParameterType.IsArray && p.ParameterType.Name == "String")
{ {
EmitStringEpilogue(wrapper, p, body, il, stringPointerVarIndex); EmitStringEpilogue(wrapper, p, body, il, generatedVariables.FirstOrDefault(g => g.Name == p.Name + "_string_ptr"));
} }
if (p.ParameterType.IsArray && p.ParameterType.GetElementType().Name == "String" && stringArrayPointerVarIndex >= 0) if (p.ParameterType.IsArray && p.ParameterType.GetElementType().Name == "String")
{ {
EmitStringArrayEpilogue(wrapper, p, body, il, stringArrayPointerVarIndex); EmitStringArrayEpilogue(wrapper, p, body, il, generatedVariables.FirstOrDefault(g => g.Name == p.Name + "_string_array_ptr"));
} }
} }
} }
static void EmitStringBuilderParameter(MethodDefinition method, ParameterDefinition parameter, MethodBody body, ILProcessor il, out int stringBuilderPointerIndex) static GeneratedVariableIdentifier EmitStringBuilderParameter(MethodDefinition method, ParameterDefinition parameter, MethodBody body, ILProcessor il)
{ {
var p = parameter.ParameterType; var p = parameter.ParameterType;
@ -561,21 +558,30 @@ namespace OpenTK.Rewrite
// IntPtr ptr; // IntPtr ptr;
body.Variables.Add(new VariableDefinition(TypeIntPtr)); body.Variables.Add(new VariableDefinition(TypeIntPtr));
stringBuilderPointerIndex = body.Variables.Count - 1; int stringBuilderPtrIndex = body.Variables.Count - 1;
GeneratedVariableIdentifier stringBuilderPtrVar = new GeneratedVariableIdentifier(parameter.Name + "_sb_ptr", stringBuilderPtrIndex);
// ptr = Marshal.AllocHGlobal(sb.Capacity + 1); // ptr = Marshal.AllocHGlobal(sb.Capacity + 1);
il.Emit(OpCodes.Callvirt, sb_get_capacity); il.Emit(OpCodes.Callvirt, sb_get_capacity);
il.Emit(OpCodes.Call, alloc_hglobal); il.Emit(OpCodes.Call, alloc_hglobal);
il.Emit(OpCodes.Stloc, stringBuilderPointerIndex); il.Emit(OpCodes.Stloc, stringBuilderPtrVar.Index);
il.Emit(OpCodes.Ldloc, stringBuilderPointerIndex); il.Emit(OpCodes.Ldloc, stringBuilderPtrVar.Index);
// We'll emit the try-finally block in the epilogue implementation, // We'll emit the try-finally block in the epilogue implementation,
// because we haven't yet emitted all necessary instructions here. // because we haven't yet emitted all necessary instructions here.
return stringBuilderPtrVar;
} }
static void EmitStringBuilderEpilogue(MethodDefinition wrapper, MethodDefinition native, static void EmitStringBuilderEpilogue(MethodDefinition wrapper, MethodDefinition native,
ParameterDefinition parameter, MethodBody body, ILProcessor il, int generatedPointerVarIndex) ParameterDefinition parameter, MethodBody body, ILProcessor il, GeneratedVariableIdentifier generatedPtrVar)
{ {
if (generatedPtrVar == null)
{
throw new ArgumentNullException(nameof(generatedPtrVar));
}
var p = parameter.ParameterType; var p = parameter.ParameterType;
if (p.Name == "StringBuilder") if (p.Name == "StringBuilder")
{ {
@ -596,22 +602,22 @@ 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];
il.Emit(OpCodes.Ldloc, generatedPointerVarIndex); il.Emit(OpCodes.Ldloc, generatedPtrVar.Index);
il.Emit(OpCodes.Ldarg, parameter.Index); 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();
block.HandlerStart = body.Instructions.Last(); block.HandlerStart = body.Instructions.Last();
il.Emit(OpCodes.Ldloc, generatedPointerVarIndex); il.Emit(OpCodes.Ldloc, generatedPtrVar.Index);
il.Emit(OpCodes.Call, free_hglobal); il.Emit(OpCodes.Call, free_hglobal);
block.HandlerEnd = body.Instructions.Last(); block.HandlerEnd = body.Instructions.Last();
} }
} }
static void EmitStringParameter(MethodDefinition wrapper, ParameterDefinition parameter, MethodBody body, static GeneratedVariableIdentifier EmitStringParameter(MethodDefinition wrapper, ParameterDefinition parameter, MethodBody body,
ILProcessor il, out int generatedPointerVarIndex) ILProcessor il)
{ {
var p = parameter.ParameterType; var p = parameter.ParameterType;
@ -623,29 +629,32 @@ namespace OpenTK.Rewrite
// IntPtr ptr; // IntPtr ptr;
body.Variables.Add(new VariableDefinition(TypeIntPtr)); body.Variables.Add(new VariableDefinition(TypeIntPtr));
generatedPointerVarIndex = body.Variables.Count - 1; int generatedPointerVarIndex = body.Variables.Count - 1;
GeneratedVariableIdentifier stringPtrVar = new GeneratedVariableIdentifier(parameter.Name + "_string_ptr", generatedPointerVarIndex);
// ptr = Marshal.StringToHGlobalAnsi(str); // ptr = Marshal.StringToHGlobalAnsi(str);
il.Emit(OpCodes.Call, marshal_str_to_ptr); il.Emit(OpCodes.Call, marshal_str_to_ptr);
il.Emit(OpCodes.Stloc, generatedPointerVarIndex); il.Emit(OpCodes.Stloc, stringPtrVar.Index);
il.Emit(OpCodes.Ldloc, generatedPointerVarIndex); il.Emit(OpCodes.Ldloc, stringPtrVar.Index);
// The finally block will be emitted in the function epilogue // The finally block will be emitted in the function epilogue
return stringPtrVar;
} }
static void EmitStringEpilogue(MethodDefinition wrapper, ParameterDefinition parameter, MethodBody body, static void EmitStringEpilogue(MethodDefinition wrapper, ParameterDefinition parameter, MethodBody body,
ILProcessor il, int generatedPointerVarIndex) ILProcessor il, GeneratedVariableIdentifier generatedPtrVar)
{ {
var p = parameter.ParameterType; var p = parameter.ParameterType;
var free = wrapper.Module.ImportReference(TypeBindingsBase.Methods.First(m => m.Name == "FreeStringPtr")); var free = wrapper.Module.ImportReference(TypeBindingsBase.Methods.First(m => m.Name == "FreeStringPtr"));
// FreeStringPtr(ptr) // FreeStringPtr(ptr)
il.Emit(OpCodes.Ldloc, generatedPointerVarIndex); il.Emit(OpCodes.Ldloc, generatedPtrVar.Index);
il.Emit(OpCodes.Call, free); il.Emit(OpCodes.Call, free);
} }
static void EmitStringArrayParameter(MethodDefinition wrapper, ParameterDefinition parameter, MethodBody body, static GeneratedVariableIdentifier EmitStringArrayParameter(MethodDefinition wrapper, ParameterDefinition parameter, MethodBody body,
ILProcessor il, out int generatedPointerVarIndex) ILProcessor il)
{ {
var p = parameter.ParameterType; var p = parameter.ParameterType;
@ -657,19 +666,28 @@ namespace OpenTK.Rewrite
// IntPtr ptr; // IntPtr ptr;
body.Variables.Add(new VariableDefinition(TypeIntPtr)); body.Variables.Add(new VariableDefinition(TypeIntPtr));
generatedPointerVarIndex = body.Variables.Count - 1; int generatedPointerVarIndex = body.Variables.Count - 1;
GeneratedVariableIdentifier stringArrayPtrVar = new GeneratedVariableIdentifier(parameter.Name + "_string_array_ptr", generatedPointerVarIndex);
// ptr = MarshalStringArrayToPtr(strings); // ptr = MarshalStringArrayToPtr(strings);
il.Emit(OpCodes.Call, marshal_str_array_to_ptr); il.Emit(OpCodes.Call, marshal_str_array_to_ptr);
il.Emit(OpCodes.Stloc, generatedPointerVarIndex); il.Emit(OpCodes.Stloc, stringArrayPtrVar.Index);
il.Emit(OpCodes.Ldloc, generatedPointerVarIndex); il.Emit(OpCodes.Ldloc, stringArrayPtrVar.Index);
// The finally block will be emitted in the function epilogue // The finally block will be emitted in the function epilogue
return stringArrayPtrVar;
} }
static void EmitStringArrayEpilogue(MethodDefinition wrapper, ParameterDefinition parameter, MethodBody body, static void EmitStringArrayEpilogue(MethodDefinition wrapper, ParameterDefinition parameter, MethodBody body,
ILProcessor il, int generatedPointerVarIndex) ILProcessor il, GeneratedVariableIdentifier generatedPtrVar)
{ {
if (generatedPtrVar == null)
{
throw new ArgumentNullException(nameof(generatedPtrVar));
}
// Note: only works for string vectors (1d arrays). // Note: only works for string vectors (1d arrays).
// We do not (and will probably never) support 2d or higher string arrays // We do not (and will probably never) support 2d or higher string arrays
var p = parameter.ParameterType; var p = parameter.ParameterType;
@ -678,7 +696,7 @@ namespace OpenTK.Rewrite
// FreeStringArrayPtr(string_array_ptr, string_array.Length) // FreeStringArrayPtr(string_array_ptr, string_array.Length)
// load string_array_ptr // load string_array_ptr
il.Emit(OpCodes.Ldloc, generatedPointerVarIndex); il.Emit(OpCodes.Ldloc, generatedPtrVar.Index);
// load string_array.Length // load string_array.Length
il.Emit(OpCodes.Ldarg, parameter.Index); il.Emit(OpCodes.Ldarg, parameter.Index);
@ -689,7 +707,7 @@ namespace OpenTK.Rewrite
il.Emit(OpCodes.Call, free); il.Emit(OpCodes.Call, free);
} }
static void EmitConvenienceWrapper(MethodDefinition wrapper, static List<GeneratedVariableIdentifier> 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)
@ -698,6 +716,8 @@ namespace OpenTK.Rewrite
throw new NotImplementedException(); throw new NotImplementedException();
} }
List<GeneratedVariableIdentifier> generatedVariables = new List<GeneratedVariableIdentifier>();
if (wrapper.ReturnType.Name != "Void") if (wrapper.ReturnType.Name != "Void")
{ {
if (difference == 2) if (difference == 2)
@ -724,12 +744,8 @@ namespace OpenTK.Rewrite
// return result; // return result;
// } // }
body.Variables.Add(new VariableDefinition(wrapper.ReturnType)); body.Variables.Add(new VariableDefinition(wrapper.ReturnType));
int dummy1;
int dummy2;
int dummy3;
EmitParameters(wrapper, native, body, il, out dummy1, out dummy2, out dummy3); generatedVariables = EmitParameters(wrapper, native, body, il);
il.Emit(OpCodes.Ldloca, body.Variables.Count - 1); il.Emit(OpCodes.Ldloca, body.Variables.Count - 1);
} }
else else
@ -755,18 +771,14 @@ namespace OpenTK.Rewrite
Console.Error.WriteLine("Unknown wrapper type for ({0})", native.Name); Console.Error.WriteLine("Unknown wrapper type for ({0})", native.Name);
} }
} }
return generatedVariables;
} }
static int EmitParameters(MethodDefinition method, MethodDefinition native, MethodBody body, ILProcessor il, static List<GeneratedVariableIdentifier> EmitParameters(MethodDefinition method, MethodDefinition native, MethodBody body, ILProcessor il)
out int stringBuilderPointerVarIndex, out int stringPointerVarIndex, out int stringArrayPointerVarIndex)
{ {
// Default outs List<GeneratedVariableIdentifier> generatedVariables = new List<GeneratedVariableIdentifier>();
stringBuilderPointerVarIndex = -1; for (int i = 0; i < method.Parameters.Count; i++)
stringPointerVarIndex = -1;
stringArrayPointerVarIndex = -1;
int i;
for (i = 0; i < method.Parameters.Count; i++)
{ {
var parameter = method.Parameters[i]; var parameter = method.Parameters[i];
var p = method.Module.ImportReference(method.Parameters[i].ParameterType); var p = method.Module.ImportReference(method.Parameters[i].ParameterType);
@ -780,11 +792,11 @@ namespace OpenTK.Rewrite
} }
else if (p.Name == "StringBuilder") else if (p.Name == "StringBuilder")
{ {
EmitStringBuilderParameter(method, parameter, body, il, out stringBuilderPointerVarIndex); generatedVariables.Add(EmitStringBuilderParameter(method, parameter, body, il));
} }
else if (p.Name == "String" && !p.IsArray) else if (p.Name == "String" && !p.IsArray)
{ {
EmitStringParameter(method, parameter, body, il, out stringPointerVarIndex); generatedVariables.Add(EmitStringParameter(method, parameter, body, il));
} }
else if (p.IsByReference) else if (p.IsByReference)
{ {
@ -886,11 +898,12 @@ namespace OpenTK.Rewrite
} }
else else
{ {
EmitStringArrayParameter(method, parameter, body, il, out stringArrayPointerVarIndex); generatedVariables.Add(EmitStringArrayParameter(method, parameter, body, il));
} }
} }
} }
return i;
return generatedVariables;
} }
static void EmitEntryPoint(FieldDefinition entry_points, ILProcessor il, int slot) static void EmitEntryPoint(FieldDefinition entry_points, ILProcessor il, int slot)