Skip to content

Commit

Permalink
(#354) CodeGen: match compatibility ptr types with the actual pointer…
Browse files Browse the repository at this point in the history
…s in method lookup
  • Loading branch information
ForNeVeR committed Nov 2, 2023
1 parent 2d4c688 commit ee7d6fb
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Module: Primary
Type: <Module>
Methods:
System.Int32 <Module>::main()
Locals:
System.Int32 V_0
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldloca.s V_0
// TODO: There should be type cast or ctor call here
IL_0004: call System.Int32 Test::Func(Cesium.Runtime.CPtr`1<System.Int32>)
IL_0009: 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
10 changes: 3 additions & 7 deletions Cesium.CodeGen/Contexts/TranslationUnitContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@ namespace Cesium.CodeGen.Contexts;

public class TranslationUnitContext
{
private const string _cPtrFullTypeName = "Cesium.Runtime.CPtr`1";
private const string _voidPtrFullTypeName = "Cesium.Runtime.VoidPtr";
private const string _funcPtrFullTypeName = "Cesium.Runtime.FuncPtr`1";

public AssemblyContext AssemblyContext { get; }
public string Name { get; }

Expand Down Expand Up @@ -47,9 +43,9 @@ TypeReference GetRuntimeType(string typeName) =>
assemblyContext.CesiumRuntimeAssembly.GetType(typeName) ??
throw new AssertException($"Could not find type {typeName} in the runtime assembly.");

_runtimeCPtr = Module.ImportReference(GetRuntimeType(_cPtrFullTypeName));
RuntimeVoidPtr = Module.ImportReference(GetRuntimeType(_voidPtrFullTypeName));
_runtimeFuncPtr = Module.ImportReference(GetRuntimeType(_funcPtrFullTypeName));
_runtimeCPtr = Module.ImportReference(GetRuntimeType(TypeSystemEx.CPtrFullTypeName));
RuntimeVoidPtr = Module.ImportReference(GetRuntimeType(TypeSystemEx.VoidPtrFullTypeName));
_runtimeFuncPtr = Module.ImportReference(GetRuntimeType(TypeSystemEx.FuncPtrFullTypeName));

_importedActionDelegates = new("System", "Action", Module, TypeSystem);
_importedFuncDelegates = new("System", "Func", Module, TypeSystem);
Expand Down
44 changes: 42 additions & 2 deletions Cesium.CodeGen/Extensions/TypeSystemEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@
using Cesium.CodeGen.Ir.Types;
using Cesium.Core;
using Mono.Cecil;
using Mono.Cecil.Rocks;

namespace Cesium.CodeGen.Extensions;

internal static class TypeSystemEx
{
public const string CPtrFullTypeName = "Cesium.Runtime.CPtr`1";
public const string VoidPtrFullTypeName = "Cesium.Runtime.VoidPtr";
public const string FuncPtrFullTypeName = "Cesium.Runtime.FuncPtr`1";

public static MethodReference MethodLookup(
this TranslationUnitContext context,
string memberName,
Expand Down Expand Up @@ -85,7 +90,7 @@ private static bool Match(
}

var declReturnReified = returnType.Resolve(context);
if (declReturnReified.FullName != method.ReturnType.FullName)
if (!TypesCorrespond(declReturnReified, method.ReturnType))
{
similarMethods.Add((method, $"Returns types do not match: {declReturnReified.Name} in declaration, {method.ReturnType.Name} in source."));
return false;
Expand All @@ -99,7 +104,7 @@ private static bool Match(
var srcParam = methodParameters[i];
var srcParamType = srcParam.ParameterType;

if (declParamType.FullName != srcParamType.FullName)
if (!TypesCorrespond(declParamType, srcParamType))
{
similarMethods.Add((method, $"Type of argument #{i} does not match: {declParamType} in declaration, {srcParamType} in source."));
return false;
Expand Down Expand Up @@ -132,6 +137,41 @@ private static bool Match(
return true;
}

/// <summary>Determines whether the types correspond to each other.</summary>
/// <remarks>
/// This tries to handle the pointer interop between the arch-independent pointer types introduced by the Cesium
/// compatibility model and the actual runtime pointer types.
/// </remarks>
private static bool TypesCorrespond(TypeReference type1, TypeReference type2)
{
// let type 1 to be pointer out of these two
if (type2.IsPointer || type2.IsFunctionPointer) (type1, type2) = (type2, type1);
var isType1AnyPointer = type1.IsPointer || type1.IsFunctionPointer;
var isType2AnyPointer = type2.IsPointer || type2.IsFunctionPointer;
if (!isType1AnyPointer || isType2AnyPointer)
{
// If type1 is not a pointer, then we don't need to use the compatibility model for this type pair.
// If type2 is a pointer, then type1 is also a pointer, and so no compatibility is required as well.
return type1.FullName == type2.FullName;
}

if (!type2.IsGenericInstance) return false;
type2 = type2.GetElementType();
if (type1.IsPointer)
{
// TODO: Analyze the generic argument.
return type2.FullName == CPtrFullTypeName || type2.FullName == VoidPtrFullTypeName;
}

if (type1.IsFunctionPointer)
{
// TODO: Analyze the generic argument.
return type2.FullName == FuncPtrFullTypeName;
}

throw new AssertException("Impossible: type1 should be either a pointer or a function pointer.");
}

private static string SimilarMethodsMessage(string name, List<(MethodDefinition, string)> similarMethods)
{
return $"Cannot find an appropriate overload for CLI-imported function {name}. Candidates:\n"
Expand Down

0 comments on commit ee7d6fb

Please sign in to comment.