Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add ErrorHelper to bindings.

Wrap new generated binding calls with using ErrorHelper. Sets up a try
to call the method in and a finally block to call Dispose on the
ErrorHelper. Currently hardcoded to only work for the graphics modules.
  • Loading branch information...
commit 10ca14ac6d31cc50f94d0a121b7218cf989941f6 1 parent efc59fa
@Frassle Frassle authored thefiddler committed
Showing with 158 additions and 13 deletions.
  1. +156 −11 Source/Generator.Rewrite/Program.cs
  2. +2 −2 Source/OpenTK/OpenTK.csproj
View
167 Source/Generator.Rewrite/Program.cs
@@ -34,14 +34,17 @@ static void Main(string[] args)
{
if (args.Length == 0)
{
- Console.WriteLine("Usage: rewrite [file.dll] [file.snk]");
+ Console.WriteLine("Usage: rewrite [file.dll] [file.snk] [options]");
+ Console.WriteLine("[options] is:");
+ Console.WriteLine(" -debug (enable calls to GL.GetError())");
return;
}
var program = new Program();
var file = args[0];
- var key = args.Length >= 2 ? args[1] : null;
- program.Rewrite(file, key);
+ var key = args[1];
+ var options = args.Where(a => a.StartsWith("-") || a.StartsWith("/"));
+ program.Rewrite(file, key, options);
}
// mscorlib types
@@ -55,7 +58,7 @@ static void Main(string[] args)
// OpenTK.BindingsBase
static TypeDefinition TypeBindingsBase;
- void Rewrite(string file, string keyfile)
+ void Rewrite(string file, string keyfile, IEnumerable<string> options)
{
// Specify assembly read and write parameters
// We want to keep a valid symbols file (pdb or mdb)
@@ -123,7 +126,7 @@ void Rewrite(string file, string keyfile)
{
foreach (var type in module.Types)
{
- Rewrite(type);
+ Rewrite(type, options);
}
}
}
@@ -136,7 +139,7 @@ void Rewrite(string file, string keyfile)
assembly.Write(file, write_params);
}
- void Rewrite(TypeDefinition type)
+ void Rewrite(TypeDefinition type, IEnumerable<string> options)
{
var entry_points = type.Fields.FirstOrDefault(f => f.Name == "EntryPoints");
if (entry_points != null)
@@ -146,7 +149,7 @@ void Rewrite(TypeDefinition type)
entry_signatures.AddRange(type.Methods
.Where(t => t.CustomAttributes.Any(a => a.AttributeType.Name == "SlotAttribute")));
- Rewrite(type, entry_points, entry_signatures);
+ Rewrite(type, entry_points, entry_signatures, options);
RemoveNativeSignatures(type, entry_signatures);
}
@@ -162,7 +165,7 @@ void Rewrite(TypeDefinition type)
}
void Rewrite(TypeDefinition type, FieldDefinition entry_points,
- List<MethodDefinition> entry_signatures)
+ List<MethodDefinition> entry_signatures, IEnumerable<string> options)
{
// Rewrite all wrapper methods
var wrapper_signatures = new List<MethodDefinition>();
@@ -182,7 +185,7 @@ void Rewrite(TypeDefinition type)
.First(a => a.AttributeType.Name == "SlotAttribute")
.ConstructorArguments[0].Value;
- ProcessMethod(wrapper, signature, slot, entry_points);
+ ProcessMethod(wrapper, signature, slot, entry_points, options);
}
}
@@ -192,7 +195,7 @@ void Rewrite(TypeDefinition type)
{
foreach (var nested_type in type.NestedTypes)
{
- Rewrite(nested_type, entry_points, entry_signatures);
+ Rewrite(nested_type, entry_points, entry_signatures, options);
}
}
}
@@ -223,7 +226,8 @@ void RemoveSupportingAttributes(TypeDefinition type)
}
// Create body for method
- static void ProcessMethod(MethodDefinition wrapper, MethodDefinition native, int slot, FieldDefinition entry_points)
+ static void ProcessMethod(MethodDefinition wrapper, MethodDefinition native, int slot,
+ FieldDefinition entry_points, IEnumerable<string> options)
{
var body = wrapper.Body;
var il = body.GetILProcessor();
@@ -243,6 +247,12 @@ static void ProcessMethod(MethodDefinition wrapper, MethodDefinition native, int
int difference = native.Parameters.Count - wrapper.Parameters.Count;
EmitConvenienceWrapper(wrapper, native, difference, body, il);
}
+
+ DebugVariables vars = null;
+ if (options.Contains("-debug"))
+ {
+ vars = EmitDebugPrologue(wrapper, il);
+ }
// push the entry point address on the stack
EmitEntryPoint(entry_points, il, slot);
@@ -266,6 +276,11 @@ static void ProcessMethod(MethodDefinition wrapper, MethodDefinition native, int
{
EmitStringEpilogue(wrapper, body, il);
}
+
+ if (options.Contains("-debug"))
+ {
+ EmitDebugEpilogue(wrapper, il, vars);
+ }
// return
il.Emit(OpCodes.Ret);
@@ -279,6 +294,136 @@ static void ProcessMethod(MethodDefinition wrapper, MethodDefinition native, int
body.OptimizeMacros();
}
+ class DebugVariables
+ {
+ public TypeDefinition ErrorHelperType;
+ public VariableDefinition ErrorHelperLocal;
+ public MethodReference Get_CurrentContext;
+ public MethodReference Set_ErrorChecking;
+ public Instruction BeginTry;
+ }
+
+ static DebugVariables EmitDebugPrologue(MethodDefinition wrapper, ILProcessor il)
+ {
+
+ DebugVariables vars = null;
+ if (il.Body.Method.Name != "GetError")
+ {
+ // Pull out the namespace name, method fullname will look
+ // something like "type namespace.class::method(type arg)"
+ var module = il.Body.Method.FullName;
+ module = module.Substring(module.IndexOf(' ') + 1);
+ module = module.Substring(0, module.IndexOf("::"));
+ module = module.Substring(0, module.LastIndexOf('.'));
+
+ // Only works for Graphics modules due to hardcoded use of
+ // OpenTK.Graphics.GraphicsContext
+ if (module == "OpenTK.Graphics.OpenGL4" ||
+ module == "OpenTK.Graphics.OpenGL" ||
+ module == "OpenTK.Graphics.ES10" ||
+ module == "OpenTK.Graphics.ES11" ||
+ module == "OpenTK.Graphics.ES20" ||
+ module == "OpenTK.Graphics.ES30")
+ {
+ var errorHelperType = wrapper.Module.Types.FirstOrDefault(
+ type => type.FullName == string.Concat(module, "ErrorHelper"));
+
+ if (errorHelperType != null)
+ {
+ vars = new DebugVariables();
+ vars.ErrorHelperType = errorHelperType;
+
+ // Get the constructor that has no parameters
+ var ctor = vars.ErrorHelperType.GetConstructors().First(
+ c => !c.HasParameters);
+
+ var graphicsContext = wrapper.Module.Types.First(
+ type => type.FullName == "OpenTK.Graphics.GraphicsContext");
+
+ var iGraphicsContext = wrapper.Module.Types.First(
+ type => type.FullName == "OpenTK.Graphics.GraphicsContext");
+
+ vars.Get_CurrentContext = graphicsContext.Methods.First(
+ method => method.Name == "get_CurrentContext");
+
+ vars.Set_ErrorChecking = graphicsContext.Methods.First(
+ method => method.Name == "set_ErrorChecking");
+
+ vars.ErrorHelperLocal = new VariableDefinition(vars.ErrorHelperType);
+
+ il.Body.Variables.Add(vars.ErrorHelperLocal);
+ il.Emit(OpCodes.Call, vars.Get_CurrentContext);
+ il.Emit(OpCodes.Newobj, ctor);
+ il.Emit(OpCodes.Stloc, vars.ErrorHelperLocal);
+
+ vars.BeginTry = Instruction.Create(OpCodes.Nop);
+ il.Append(vars.BeginTry);
+
+ // Special case Begin to turn off error checking.
+ if (il.Body.Method.Name == "Begin")
+ {
+ il.Emit(OpCodes.Call, vars.Get_CurrentContext);
+ il.Emit(OpCodes.Ldc_I4_0);
+ il.Emit(OpCodes.Conv_I1);
+ il.Emit(OpCodes.Call, vars.Set_ErrorChecking);
+ }
+ }
+ }
+ }
+
+ return vars;
+ }
+
+ static void EmitDebugEpilogue(MethodDefinition wrapper, ILProcessor il, DebugVariables vars)
+ {
+ if (vars != null)
+ {
+ var disposeMethod = vars.ErrorHelperType.Methods.First(
+ method => method.Name == "Dispose");
+
+ // Store then reload the result from the call
+ var resultLocal = new VariableDefinition(wrapper.ReturnType);
+ if (resultLocal.VariableType != Program.TypeVoid)
+ {
+ il.Body.Variables.Add(resultLocal);
+ il.Emit(OpCodes.Stloc, resultLocal);
+ }
+
+ // Special case End to turn on error checking.
+ if (il.Body.Method.Name == "End")
+ {
+ il.Emit(OpCodes.Call, vars.Get_CurrentContext);
+ il.Emit(OpCodes.Ldc_I4_1);
+ il.Emit(OpCodes.Conv_I1);
+ il.Emit(OpCodes.Call, vars.Set_ErrorChecking);
+ }
+
+ // We need a NOP to set up the finally handler range correctly.
+ var nopInstruction = Instruction.Create(OpCodes.Nop);
+ var loadInstruction = Instruction.Create(OpCodes.Ldloca, vars.ErrorHelperLocal);
+ var disposeInstruction = Instruction.Create(OpCodes.Call, disposeMethod);
+ var leaveInstruction = Instruction.Create(OpCodes.Leave, nopInstruction);
+
+ il.Append(loadInstruction);
+ il.Append(disposeInstruction);
+ il.Append(leaveInstruction);
+ il.Append(nopInstruction);
+
+ var finallyHandler = new ExceptionHandler(ExceptionHandlerType.Finally);
+ finallyHandler.TryStart = vars.BeginTry;
+ finallyHandler.TryEnd = loadInstruction;
+ finallyHandler.HandlerStart = loadInstruction;
+ finallyHandler.HandlerEnd = nopInstruction;
+
+ il.Body.ExceptionHandlers.Add(finallyHandler);
+
+ if (resultLocal.VariableType != Program.TypeVoid)
+ {
+ il.Emit(OpCodes.Ldloc, resultLocal);
+ }
+ }
+ }
+
private static void EmitReturnTypeWrapper(MethodDefinition wrapper, MethodDefinition native, MethodBody body, ILProcessor il)
{
if (wrapper.Parameters.Count < native.Parameters.Count)
View
4 Source/OpenTK/OpenTK.csproj
@@ -811,9 +811,9 @@
</PropertyGroup>
<ItemGroup />
<Target Name="AfterBuild">
- <Exec Command="$(OutputPath)..\..\Tools\Debug\Rewrite.exe $(OutputPath)OpenTK.dll ..\..\OpenTK.snk" Condition="$(OS) == 'Windows_NT' and $(Configuration) == 'Debug'" />
+ <Exec Command="$(OutputPath)..\..\Tools\Debug\Rewrite.exe $(OutputPath)OpenTK.dll ..\..\OpenTK.snk -debug" Condition="$(OS) == 'Windows_NT' and $(Configuration) == 'Debug'" />
<Exec Command="$(OutputPath)..\..\Tools\Release\Rewrite.exe $(OutputPath)OpenTK.dll ..\..\OpenTK.snk" Condition="$(OS) == 'Windows_NT' and $(Configuration) != 'Debug'" />
- <Exec Command="mono $(OutputPath)..\..\Tools\Debug\Rewrite.exe $(OutputPath)OpenTK.dll ..\..\OpenTK.snk" Condition="$(OS) != 'Windows_NT' and $(Configuration) == 'Debug'" />
+ <Exec Command="mono $(OutputPath)..\..\Tools\Debug\Rewrite.exe $(OutputPath)OpenTK.dll ..\..\OpenTK.snk -debug" Condition="$(OS) != 'Windows_NT' and $(Configuration) == 'Debug'" />
<Exec Command="mono $(OutputPath)..\..\Tools\Release\Rewrite.exe $(OutputPath)OpenTK.dll ..\..\OpenTK.snk" Condition="$(OS) != 'Windows_NT' and $(Configuration) != 'Debug'" />
</Target>
<ProjectExtensions>
Please sign in to comment.
Something went wrong with that request. Please try again.