Skip to content

Commit

Permalink
Merge pull request #177 from CesiumGS/safehandles
Browse files Browse the repository at this point in the history
Use SafeHandles instead of raw IntPtrs to hold native implementation instances
  • Loading branch information
kring authored Jan 29, 2023
2 parents c14a122 + e13ee3e commit cb21853
Show file tree
Hide file tree
Showing 35 changed files with 97 additions and 143 deletions.
44 changes: 30 additions & 14 deletions Reinterop~/CSharpType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,22 @@ internal class CSharpType
public readonly CppGenerationContext Context;
public readonly InteropTypeKind Kind;
public readonly IReadOnlyCollection<string> Namespaces;
public readonly ITypeSymbol Symbol;
public readonly string Name;
public readonly SpecialType SpecialType;
public readonly ITypeSymbol? Symbol;

public Compilation Compilation
{
get { return Context.Compilation; }
}

public CSharpType(CppGenerationContext context, InteropTypeKind kind, IReadOnlyCollection<string> namespaces, ITypeSymbol symbol)
public CSharpType(CppGenerationContext context, InteropTypeKind kind, IReadOnlyCollection<string> namespaces, string name, SpecialType specialType, ITypeSymbol? symbol = null)
{
this.Context = context;
this.Kind = kind;
this.Namespaces = new List<string>(namespaces);
this.Name = name;
this.SpecialType = specialType;
this.Symbol = symbol;
}

Expand All @@ -38,31 +42,41 @@ public static CSharpType FromSymbol(CppGenerationContext context, ITypeSymbol sy

namespaces.Reverse();

return new CSharpType(context, kind, namespaces, symbol);
return new CSharpType(context, kind, namespaces, symbol.Name, symbol.SpecialType, symbol);
}

public string GetFullyQualifiedNamespace()
{
IArrayTypeSymbol? arraySymbol = this.Symbol as IArrayTypeSymbol;
if (arraySymbol != null)
return CSharpType.FromSymbol(this.Context, arraySymbol.ElementType).GetFullyQualifiedNamespace();
if (this.Symbol != null)
{
IArrayTypeSymbol? arraySymbol = this.Symbol as IArrayTypeSymbol;
if (arraySymbol != null)
return CSharpType.FromSymbol(this.Context, arraySymbol.ElementType).GetFullyQualifiedNamespace();
else
return Symbol.ContainingNamespace.ToDisplayString();
}
else
return Symbol.ContainingNamespace.ToDisplayString();
{
return string.Join(".", this.Namespaces);
}
}

public string GetFullyQualifiedName()
{
return Symbol.ToDisplayString();
if (this.Symbol != null)
return this.Symbol.ToDisplayString();
else
return this.GetFullyQualifiedNamespace() + "." + this.Name;
}

private CSharpType AsInteropTypeCommon()
{
// C++ doesn't specify the size of a bool, and C# uses different sizes in different contexts.
// So we explicitly marshal bools as uint8_t / System.Byte.
if (this.Symbol.SpecialType == SpecialType.System_Boolean)
if (this.SpecialType == SpecialType.System_Boolean)
return CSharpType.FromSymbol(Context, Compilation.GetSpecialType(SpecialType.System_Byte));
else if (this.Kind == InteropTypeKind.ClassWrapper || this.Kind == InteropTypeKind.NonBlittableStructWrapper || this.Kind == InteropTypeKind.Delegate)
return new CSharpType(Context, InteropTypeKind.Primitive, new string[] { "System" }, Compilation.GetSpecialType(SpecialType.System_IntPtr));
return CSharpType.FromSymbol(Context, Compilation.GetSpecialType(SpecialType.System_IntPtr));
else
return this;
}
Expand Down Expand Up @@ -100,7 +114,7 @@ public CSharpType AsInteropTypeReturn()
/// </summary>
public string GetConversionToInteropType(string variableName)
{
if (this.Symbol.SpecialType == SpecialType.System_Boolean)
if (this.SpecialType == SpecialType.System_Boolean)
return $"{variableName} ? (byte)1 : (byte)0";
else if (this.Kind == InteropTypeKind.ClassWrapper || this.Kind == InteropTypeKind.NonBlittableStructWrapper || this.Kind == InteropTypeKind.Delegate)
return $"Reinterop.ObjectHandleUtility.CreateHandle({variableName})";
Expand All @@ -114,7 +128,7 @@ public string GetConversionToInteropType(string variableName)

public string GetParameterConversionFromInteropType(string variableName)
{
if (this.Symbol.SpecialType == SpecialType.System_Boolean)
if (this.SpecialType == SpecialType.System_Boolean)
return $"{variableName} != 0";
else if (this.Kind == InteropTypeKind.ClassWrapper || this.Kind == InteropTypeKind.NonBlittableStructWrapper || this.Kind == InteropTypeKind.Delegate)
return $"({this.GetFullyQualifiedName()})Reinterop.ObjectHandleUtility.GetObjectFromHandle({variableName})!";
Expand All @@ -128,7 +142,7 @@ public string GetParameterConversionFromInteropType(string variableName)

public string GetReturnValueConversionFromInteropType(string variableName)
{
if (this.Symbol.SpecialType == SpecialType.System_Boolean)
if (this.SpecialType == SpecialType.System_Boolean)
return $"{variableName} != 0";
else if (this.Kind == InteropTypeKind.ClassWrapper || this.Kind == InteropTypeKind.NonBlittableStructWrapper || this.Kind == InteropTypeKind.Delegate)
return $"({this.GetFullyQualifiedName()})Reinterop.ObjectHandleUtility.GetObjectAndFreeHandle({variableName})!";
Expand Down Expand Up @@ -157,7 +171,9 @@ public static bool IsFirstDerivedFromSecond(ITypeSymbol first, ITypeSymbol secon

public CSharpType AsPointer()
{
return new CSharpType(this.Context, InteropTypeKind.Primitive, this.Namespaces, this.Compilation.CreatePointerTypeSymbol(this.Symbol));
if (this.Symbol == null)
return this;
return new CSharpType(this.Context, InteropTypeKind.Primitive, this.Namespaces, this.Symbol.Name, this.Symbol.SpecialType, this.Compilation.CreatePointerTypeSymbol(this.Symbol));
}
}
}
2 changes: 1 addition & 1 deletion Reinterop~/CodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public static void WriteCSharpCode(GeneratorExecutionContext context, CppGenerat
if (partialMethods == null || partialMethods.Methods.Count == 0)
continue;

context.AddSource(partialMethods.Type.Symbol.Name + "-generated", partialMethods.ToSourceFileString());
context.AddSource(partialMethods.Type.Name + "-generated", partialMethods.ToSourceFileString());
}
}

Expand Down
12 changes: 6 additions & 6 deletions Reinterop~/CustomDelegateGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ private void GenerateDelegate(CppGenerationContext context, GeneratedResult resu
genericTypeHash = Interop.HashParameters(null, named.TypeArguments);
}

string csBaseName = $"{csType.GetFullyQualifiedNamespace().Replace(".", "_")}_{csType.Symbol.Name}{genericTypeHash}_CreateDelegate";
string csBaseName = $"{csType.GetFullyQualifiedNamespace().Replace(".", "_")}_{csType.Name}{genericTypeHash}_CreateDelegate";
string invokeCallbackName = $"{csType.GetFullyQualifiedNamespace().Replace(".", "_")}_{item.Type.Name}{genericTypeHash}_InvokeCallback";
string disposeCallbackName = $"{csType.GetFullyQualifiedNamespace().Replace(".", "_")}_{item.Type.Name}{genericTypeHash}_DisposeCallback";

Expand All @@ -107,16 +107,16 @@ private void GenerateDelegate(CppGenerationContext context, GeneratedResult resu
CSharpName: csBaseName + "Delegate",
CSharpContent:
$$"""
private class {{csType.Symbol.Name}}{{genericTypeHash}}NativeFunction : System.IDisposable
private class {{csType.Name}}{{genericTypeHash}}NativeFunction : System.IDisposable
{
private IntPtr _callbackFunction;
public {{csType.Symbol.Name}}{{genericTypeHash}}NativeFunction(IntPtr callbackFunction)
public {{csType.Name}}{{genericTypeHash}}NativeFunction(IntPtr callbackFunction)
{
_callbackFunction = callbackFunction;
}
~{{csType.Symbol.Name}}{{genericTypeHash}}NativeFunction()
~{{csType.Name}}{{genericTypeHash}}NativeFunction()
{
Dispose(false);
}
Expand All @@ -139,7 +139,7 @@ private void Dispose(bool disposing)
public {{csReturnType.GetFullyQualifiedName()}} Invoke({{string.Join(", ", invokeParameters)}})
{
if (_callbackFunction == null)
throw new System.ObjectDisposedException("{{csType.Symbol.Name}}");
throw new System.ObjectDisposedException("{{csType.Name}}");
{{csResultImplementation}}{{invokeCallbackName}}({{string.Join(", ", callInvokeInteropParameters)}});
{{csReturnImplementation}};
Expand All @@ -156,7 +156,7 @@ private void Dispose(bool disposing)
[AOT.MonoPInvokeCallback(typeof({{csBaseName}}Type))]
private static unsafe IntPtr {{csBaseName}}(IntPtr callbackFunction)
{
var receiver = new {{csType.Symbol.Name}}{{genericTypeHash}}NativeFunction(callbackFunction);
var receiver = new {{csType.Name}}{{genericTypeHash}}NativeFunction(callbackFunction);
return Reinterop.ObjectHandleUtility.CreateHandle(new {{csType.GetFullyQualifiedName()}}(receiver.Invoke));
}
"""
Expand Down
28 changes: 26 additions & 2 deletions Reinterop~/GeneratedCSharpPartialMethodDefinitions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,24 +40,48 @@ public GeneratedCSharpPartialMethodDefinitions(CSharpType type)

public string ToSourceFileString()
{
if (Type.Symbol == null)
throw new Exception("Type with partial method definitions must have a Symbol.");

// TODO: support structs
string kind = "class";

string interopPrefix = Type.GetFullyQualifiedName().Replace(".", "_");
if (!string.IsNullOrEmpty(this.Type.Context.BaseNamespace))
interopPrefix = this.Type.Context.BaseNamespace + "_" + interopPrefix;

if (needsInstance)
{
return
$$"""
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
namespace {{Type.GetFullyQualifiedNamespace()}}
{
{{CSharpTypeUtility.GetAccessString(Type.Symbol.DeclaredAccessibility)}} partial {{kind}} {{Type.Symbol.Name}} : System.IDisposable
{
internal class ImplementationHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public ImplementationHandle({{Type.Symbol.Name}} managed) : base(true)
{
SetHandle({{interopPrefix}}_CreateImplementation(Reinterop.ObjectHandleUtility.CreateHandle(managed)));
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
protected override bool ReleaseHandle()
{
{{interopPrefix}}_DestroyImplementation(this.handle);
return true;
}
}
[System.NonSerialized]
private System.IntPtr _implementation = System.IntPtr.Zero;
private ImplementationHandle _implementation = null;
public IntPtr NativeImplementation
internal ImplementationHandle NativeImplementation
{
get { return _implementation; }
}
Expand Down
2 changes: 1 addition & 1 deletion Reinterop~/Interop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ public static (string Name, string Content) CreateCSharpDelegateInit(

public static string GetUniqueNameForType(CSharpType type)
{
string name = type.Symbol.Name;
string name = type.Name;
string genericTypeHash = "";
INamedTypeSymbol? named = type.Symbol as INamedTypeSymbol;
if (named != null && named.IsGenericType)
Expand Down
Loading

0 comments on commit cb21853

Please sign in to comment.