Skip to content

Commit

Permalink
(#354) FuncPtr conversion via constructor
Browse files Browse the repository at this point in the history
  • Loading branch information
ForNeVeR committed Nov 17, 2023
1 parent e4c9183 commit 1a9bf18
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 20 deletions.
2 changes: 1 addition & 1 deletion Cesium.CodeGen.Tests/CodeGenNetInteropTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public Task FuncPtrInterop(TargetArchitectureSet architecture) => DoTest(
@"using Cesium.Runtime;
public static class Test
{
public static int Func(FPtr<Func<int>> ptr) => 1;
public static int Func(FuncPtr<Func<int>> ptr) => 1;
}
", """
__cli_import("Test::Func")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Module: Primary
Type: <Module>
Methods:
System.Int32 <Module>::myFunc()
IL_0000: ldc.i4.0
IL_0001: ret

System.Int32 <Module>::main()
IL_0000: ldftn System.Int32 <Module>::myFunc()
IL_0006: conv.i
IL_0007: newobj Cesium.Runtime.FuncPtr`1<TDelegate> Cesium.Runtime.FuncPtr`1<System.Func`1<System.Int32>>::.ctor(System.Void*)
IL_000c: call System.Int32 Test::Func(Cesium.Runtime.FuncPtr`1<System.Func`1<System.Int32>>)
IL_0011: ret

System.Int32 <Module>::<SyntheticEntrypoint>()
Locals:
System.Int32 V_0
IL_0000: call System.Int32 <Module>::main()
IL_0005: stloc.s V_0
IL_0007: ldloc.s V_0
IL_0009: call System.Void Cesium.Runtime.RuntimeHelpers::Exit(System.Int32)
IL_000e: ldloc.s V_0
IL_0010: ret
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Module: Primary
Type: <Module>
Methods:
System.Int32 <Module>::myFunc()
IL_0000: ldc.i4.0
IL_0001: ret

System.Int32 <Module>::main()
IL_0000: ldftn System.Int32 <Module>::myFunc()
IL_0006: conv.i
IL_0007: newobj Cesium.Runtime.FuncPtr`1<TDelegate> Cesium.Runtime.FuncPtr`1<System.Func`1<System.Int32>>::.ctor(System.Void*)
IL_000c: call System.Int32 Test::Func(Cesium.Runtime.FuncPtr`1<System.Func`1<System.Int32>>)
IL_0011: ret

System.Int32 <Module>::<SyntheticEntrypoint>()
Locals:
System.Int32 V_0
IL_0000: call System.Int32 <Module>::main()
IL_0005: stloc.s V_0
IL_0007: ldloc.s V_0
IL_0009: call System.Void Cesium.Runtime.RuntimeHelpers::Exit(System.Int32)
IL_000e: ldloc.s V_0
IL_0010: ret
13 changes: 9 additions & 4 deletions Cesium.CodeGen/Contexts/AssemblyContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,14 @@ public MethodReference CPtrConverter(TypeReference argument) =>
_cPtrConverterCache.GetOrImportMethod(argument);

public TypeReference RuntimeVoidPtr { get; }
private readonly TypeReference _runtimeFuncPtr;

private readonly Lazy<MethodReference> _voidPtrConverter;
public MethodReference VoidPtrConverter => _voidPtrConverter.Value;

private readonly TypeReference _runtimeFuncPtr;
private readonly ConversionMethodCache _funcPtrConstructorCache;
public MethodReference FuncPtrConstructor(TypeReference argument) =>
_funcPtrConstructorCache.GetOrImportMethod(argument);

private AssemblyContext(
AssemblyDefinition assembly,
ModuleDefinition module,
Expand Down Expand Up @@ -135,14 +138,16 @@ TypeDefinition GetRuntimeType(string typeName) =>

_runtimeCPtr = Module.ImportReference(GetRuntimeType(TypeSystemEx.CPtrFullTypeName));
_cPtrConverterCache = new ConversionMethodCache(_runtimeCPtr, "op_Implicit", Module);

RuntimeVoidPtr = Module.ImportReference(GetRuntimeType(TypeSystemEx.VoidPtrFullTypeName));
_voidPtrConverter = new(() => GetImplicitCastOperator(TypeSystemEx.VoidPtrFullTypeName));

_runtimeFuncPtr = Module.ImportReference(GetRuntimeType(TypeSystemEx.FuncPtrFullTypeName));
_funcPtrConstructorCache = new ConversionMethodCache(_runtimeFuncPtr, ".ctor", Module);

_importedActionDelegates = new("System", "Action", Module);
_importedFuncDelegates = new("System", "Func", Module);

_voidPtrConverter = new(() => GetImplicitCastOperator(TypeSystemEx.VoidPtrFullTypeName));

MethodReference GetImplicitCastOperator(string typeName)
{
var type = GetRuntimeType(typeName);
Expand Down
11 changes: 2 additions & 9 deletions Cesium.CodeGen/Ir/Expressions/TypeCastExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,8 @@ public void EmitTo(IEmitScope scope)
Add(OpCodes.Conv_I);
else if (TargetType is InteropType iType)
{
var type = iType.UnderlyingType;
if (type.FullName == TypeSystemEx.VoidPtrFullTypeName
|| type.IsGenericInstance && type.GetElementType().FullName == TypeSystemEx.CPtrFullTypeName)
{
Add(OpCodes.Conv_I); // TODO: Should only emit if required.
scope.Method.Body.Instructions.Add(
Instruction.Create(OpCodes.Call, iType.GetConvertCall(scope.AssemblyContext)));
}
else throw new WipException(WipException.ToDo, $"Cast to {iType.UnderlyingType} is not implemented, yet.");
Add(OpCodes.Conv_I); // TODO: Should only emit if required.
scope.Method.Body.Instructions.Add(iType.GetConvertInstruction(scope.AssemblyContext));
}
else
throw new AssertException($"Type {TargetType} is not supported.");
Expand Down
19 changes: 13 additions & 6 deletions Cesium.CodeGen/Ir/Types/InteropType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Cesium.CodeGen.Extensions;
using Cesium.Core;
using Mono.Cecil;
using Mono.Cecil.Cil;

namespace Cesium.CodeGen.Ir.Types;

Expand Down Expand Up @@ -32,18 +33,24 @@ internal record InteropType(TypeReference UnderlyingType) : IType
$"{nameof(InteropType)} doesn't know how to get size of an underlying {UnderlyingType}.");
}

public MethodReference GetConvertCall(AssemblyContext context)
public Instruction GetConvertInstruction(AssemblyContext context)
{
if (UnderlyingType.FullName == TypeSystemEx.VoidPtrFullTypeName)
return context.VoidPtrConverter;
return Instruction.Create(OpCodes.Call, context.VoidPtrConverter);

if (UnderlyingType is GenericInstanceType typeInstance)
{
var parent = typeInstance.GetElementType();
if (parent.FullName == TypeSystemEx.CPtrFullTypeName)
return context.CPtrConverter(typeInstance.GenericArguments.Single());

throw new WipException(WipException.ToDo, "Cannot import the converter method for FuncPtr, yet.");
return parent.FullName switch
{
TypeSystemEx.CPtrFullTypeName =>
Instruction.Create(OpCodes.Call, context.CPtrConverter(typeInstance.GenericArguments.Single())),
TypeSystemEx.FuncPtrFullTypeName =>
Instruction.Create(
OpCodes.Newobj,
context.FuncPtrConstructor(typeInstance.GenericArguments.Single())),
_ => throw new AssertException($"No conversion available for interop type {parent}.")
};
}

throw new AssertException(
Expand Down

0 comments on commit 1a9bf18

Please sign in to comment.