Skip to content

Commit

Permalink
Work on adding support for generics (#124)
Browse files Browse the repository at this point in the history
  • Loading branch information
josesimoes authored Dec 9, 2020
1 parent 6f5a569 commit ffc10a0
Show file tree
Hide file tree
Showing 13 changed files with 237 additions and 10 deletions.
4 changes: 4 additions & 0 deletions MetadataProcessor.Core/DumpGenerator/DumpTemplates.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ internal partial class DumpTemplates
{{#each TypeDefinitions}}
TypeDefProps [{{ReferenceId}}]: Flags: {{Flags}} Extends: {{ExtendsType}} Enclosed: {{EnclosedType}} '{{Name}}'{{#newline}}
{{#each GenericParameters}}
GenericParam [{{GenericParamToken}}]: Position: ({{Position}}) '{{Name}}' Owner: {{Owner}} [{{Signature}}]{{#newline}}
{{/each}}
{{#each FieldDefinitions}}
FieldDefProps [{{ReferenceId}}]: Attr: {{Attributes}} Flags: {{Flags}} '{{Name}}' [{{Signature}}]{{#newline}}
{{/each}}
Expand Down
20 changes: 20 additions & 0 deletions MetadataProcessor.Core/DumpGenerator/GenericParam.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//

namespace nanoFramework.Tools.MetadataProcessor.Core
{
public class GenericParam
{
public string Position;

public string GenericParamToken;

public string Name;

public string Owner;

public string Signature;
}
}
1 change: 1 addition & 0 deletions MetadataProcessor.Core/DumpGenerator/TypeDef.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class TypeDef

public string Name;

public List<GenericParam> GenericParameters = new List<GenericParam>();
public List<FieldDef> FieldDefinitions = new List<FieldDef>();
public List<MethodDef> MethodDefinitions = new List<MethodDef>();
public List<InterfaceDef> InterfaceDefinitions = new List<InterfaceDef>();
Expand Down
3 changes: 2 additions & 1 deletion MetadataProcessor.Core/Extensions/TypeReferenceExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ public static string TypeSignatureAsString(this TypeReference type)
return byrefSig.ToString();
}

if (type.IsGenericParameter)
if (type.IsGenericParameter ||
type.IsGenericInstance)
{
return $"!!{type.Name}";
}
Expand Down
2 changes: 2 additions & 0 deletions MetadataProcessor.Core/MetadataProcessor.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
<Compile Include="DumpGenerator\ExceptionHandler.cs" />
<Compile Include="DumpGenerator\AttributeCustom.cs" />
<Compile Include="DumpGenerator\AttFixedArgs.cs" />
<Compile Include="DumpGenerator\GenericParam.cs" />
<Compile Include="DumpGenerator\UserString.cs" />
<Compile Include="DumpGenerator\ILCode.cs" />
<Compile Include="DumpGenerator\LocalDef.cs" />
Expand Down Expand Up @@ -92,6 +93,7 @@
<Compile Include="Tables\nanoFieldDefinitionTable.cs" />
<Compile Include="Tables\nanoFieldReferenceTable.cs" />
<Compile Include="Tables\nanoMethodDefinitionTable.cs" />
<Compile Include="Tables\nanoGenericParamTable.cs" />
<Compile Include="Tables\nanoMethodReferenceTable.cs" />
<Compile Include="Tables\nanoReferenceTableBase.cs" />
<Compile Include="Tables\nanoResourceDataTable.cs" />
Expand Down
88 changes: 88 additions & 0 deletions MetadataProcessor.Core/Tables/nanoGenericParamTable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//

using Mono.Cecil;
using System;
using System.Collections.Generic;

namespace nanoFramework.Tools.MetadataProcessor
{
/// <summary>
/// Encapsulates logic for storing generic parameters list and writing
/// this collected list into target assembly in .NET nanoFramework format.
/// </summary>
public sealed class nanoGenericParamTable :
nanoReferenceTableBase<GenericParameter>
{
/// <summary>
/// Helper class for comparing two instances of <see cref="GenericParameter"/> objects
/// using <see cref="MetadataToken"/> property as unique key for comparison.
/// </summary>
private sealed class MemberReferenceComparer : IEqualityComparer<GenericParameter>
{
/// <inheritdoc/>
public bool Equals(GenericParameter x, GenericParameter y)
{
if (x is null)
{
throw new ArgumentNullException(nameof(x));
}

if (y is null)
{
throw new ArgumentNullException(nameof(y));
}

return x.MetadataToken.ToInt32() == y.MetadataToken.ToInt32();
}

/// <inheritdoc/>
public int GetHashCode(GenericParameter obj)
{
return obj.MetadataToken.ToInt32().GetHashCode();
}
}

/// <summary>
/// Creates new instance of <see cref="nanoGenericParamTable"/> object.
/// </summary>
/// <param name="items">List of member references in Mono.Cecil format.</param>
/// <param name="context">
/// Assembly tables context - contains all tables used for building target assembly.
/// </param>
public nanoGenericParamTable(
IEnumerable<GenericParameter> items,
nanoTablesContext context)
: base(items, new MemberReferenceComparer(), context)
{
}

/// <summary>
/// Gets method reference ID if possible (if method is external and stored in this table).
/// </summary>
/// <param name="genericParameter">Method reference metadata in Mono.Cecil format.</param>
/// <param name="referenceId">Method reference ID in .NET nanoFramework format.</param>
/// <returns>Returns <c>true</c> if reference found, otherwise returns <c>false</c>.</returns>
public bool TryGetParameterId(
GenericParameter genericParameter,
out ushort referenceId)
{
return TryGetIdByValue(genericParameter, out referenceId);
}

/// <inheritdoc/>
protected override void WriteSingleItem(
nanoBinaryWriter writer,
GenericParameter item)
{
if (!_context.MinimizeComplete)
{
return;
}

// TODO
}
}
}
11 changes: 10 additions & 1 deletion MetadataProcessor.Core/Tables/nanoSignaturesTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -665,10 +665,19 @@ private void WriteSubTypeInfo(TypeReference typeDefinition, nanoBinaryWriter wri
writer.WriteMetadataToken(((uint)referenceId << 2) | 0x01);
}
else if (_context.TypeDefinitionTable.TryGetTypeReferenceId(
typeDefinition.Resolve(), out referenceId))
typeDefinition.Resolve(),
out referenceId))
{
writer.WriteMetadataToken((uint)referenceId << 2);
}
else if (typeDefinition.Resolve().HasGenericParameters &&
_context.GenericParamsTable.TryGetParameterId(
typeDefinition.Resolve().GenericParameters.FirstOrDefault(),
out referenceId))
{
// TODO
writer.WriteMetadataToken((uint)referenceId << 2);
}
else
{
throw new ArgumentException($"Can't find entry in type reference table for {typeDefinition.FullName}.");
Expand Down
28 changes: 25 additions & 3 deletions MetadataProcessor.Core/Tables/nanoTablesContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,17 @@ public nanoTablesContext(
var memberReferences = mainModule.GetMemberReferences()
.Where(item =>
(typeReferencesNames.Contains(item.DeclaringType.FullName) ||
item.DeclaringType.GetElementType().IsPrimitive))
item.DeclaringType.GetElementType().IsPrimitive ||
item.ContainsGenericParameter ||
item.DeclaringType.IsGenericInstance))

.ToList();

FieldReferencesTable = new nanoFieldReferenceTable(
memberReferences.OfType<FieldReference>(), this);
MethodReferencesTable = new nanoMethodReferenceTable(
memberReferences.OfType<MethodReference>(), this);

// Internal types definitions

var types = GetOrderedTypes(mainModule, explicitTypesOrder);
Expand All @@ -133,7 +136,6 @@ public nanoTablesContext(
.SelectMany(item => GetOrderedFields(item.Fields.Where(field => !field.HasConstant)))
.ToList();
FieldsTable = new nanoFieldDefinitionTable(fields, this);

var methods = types.SelectMany(item => GetOrderedMethods(item.Methods)).ToList();

MethodDefinitionTable = new nanoMethodDefinitionTable(methods, this);
Expand Down Expand Up @@ -172,6 +174,24 @@ public nanoTablesContext(

ResourceFileTable = new nanoResourceFileTable(this);

// build list of generic parameters belonging to method defs
List<GenericParameter> methodDefsGenericParameters = new List<GenericParameter>();

foreach (var m in methods)
{
if (m.HasGenericParameters)
{
methodDefsGenericParameters.AddRange(m.GenericParameters);
}
}

var generics = types
.SelectMany(t => t.GenericParameters)
.Concat(methodDefsGenericParameters)
.ToList();

GenericParamsTable = new nanoGenericParamTable(generics, this);

// Pre-allocate strings from some tables
AssemblyReferenceTable.AllocateStrings();
TypeReferencesTable.AllocateStrings();
Expand Down Expand Up @@ -223,6 +243,8 @@ public ushort GetMethodReferenceId(

public nanoFieldReferenceTable FieldReferencesTable { get; private set; }

public nanoGenericParamTable GenericParamsTable { get; private set; }

public nanoMethodReferenceTable MethodReferencesTable { get; private set; }

public nanoFieldDefinitionTable FieldsTable { get; private set; }
Expand Down
68 changes: 67 additions & 1 deletion MetadataProcessor.Core/nanoAssemblyBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
//

using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
using nanoFramework.Tools.MetadataProcessor.Core.Extensions;
using System;
Expand Down Expand Up @@ -514,6 +515,15 @@ private HashSet<MetadataToken> BuildDependencyList(MetadataToken token)
}
}

// generic parameters
foreach (var g in td.GenericParameters)
{
if (!nanoTablesContext.ClassNamesToExclude.Contains(g.DeclaringType.FullName))
{
set.Add(g.MetadataToken);
}
}

// methods
foreach (var m in td.Methods)
{
Expand Down Expand Up @@ -620,6 +630,15 @@ private HashSet<MetadataToken> BuildDependencyList(MetadataToken token)
set.Add(md.ReturnType.MetadataToken);
}

// generic parameters
if(md.HasGenericParameters)
{
foreach (var gp in md.GenericParameters)
{
set.Add(gp.MetadataToken);
}
}

// parameters
foreach (var p in md.Parameters)
{
Expand Down Expand Up @@ -707,7 +726,9 @@ private HashSet<MetadataToken> BuildDependencyList(MetadataToken token)
i.Operand is FieldReference ||
i.Operand is TypeDefinition ||
i.Operand is TypeSpecification ||
i.Operand is TypeReference)
i.Operand is TypeReference ||
i.Operand is GenericInstanceType ||
i.Operand is GenericParameter)
{
set.Add(((IMetadataTokenProvider)i.Operand).MetadataToken);
}
Expand Down Expand Up @@ -763,6 +784,16 @@ i.Operand is TypeSpecification ||
}

break;

case TokenType.GenericParam:
case TokenType.AssemblyRef:
case TokenType.String:
// we are good with these, nothing to do here
break;

default:
Debug.Fail($"Unable to process token {token}.");
break;
}

return set;
Expand Down Expand Up @@ -823,6 +854,26 @@ private string TokenToString(MetadataToken token)
output.Append(fd.Name);
break;

case TokenType.GenericParam:
var gp = _tablesContext.GenericParamsTable.Items.FirstOrDefault(g => g.MetadataToken == token);

output.Append($"[GenericParam 0x{token.ToUInt32().ToString("X8")}]");

if (gp.DeclaringType != null)
{
output.Append(TokenToString(gp.DeclaringType.MetadataToken));
output.Append("::");
}
else if(gp.DeclaringMethod != null)
{
output.Append(TokenToString(gp.DeclaringMethod.MetadataToken));
output.Append("::");
}

output.Append(gp.Name);

break;

case TokenType.Method:
var md = _tablesContext.MethodDefinitionTable.Items.FirstOrDefault(i => i.MetadataToken == token);

Expand Down Expand Up @@ -879,6 +930,17 @@ private string TokenToString(MetadataToken token)
typeRef = fr.DeclaringType;
typeName = fr.Name;
}
else
{
// try now with generic parameters
var gr = _tablesContext.GenericParamsTable.Items.FirstOrDefault(g => g.MetadataToken == token);

if (gr != null)
{
typeRef = gr.DeclaringType;
typeName = gr.Name;
}
}
}

Debug.Assert(typeRef != null);
Expand Down Expand Up @@ -916,6 +978,10 @@ private string TokenToString(MetadataToken token)
output.Append($"'{sr}'");
}
break;

default:
Debug.Fail($"Unable to process token {token}.");
break;
}

// output token ID if empty
Expand Down
15 changes: 15 additions & 0 deletions MetadataProcessor.Core/nanoDumperGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,21 @@ private void DumpTypeDefinitions(DumpAllTable dumpTable)
typeDef.EnclosedType = token.ToInt32().ToString("x8");
}

// list generic parameters
foreach (var gp in t.GenericParameters)
{
var genericParam = new GenericParam()
{
Position = gp.Position.ToString(),
GenericParamToken = gp.MetadataToken.ToInt32().ToString("x8"),
Name = gp.FullName,
Owner = gp.Owner.MetadataToken.ToInt32().ToString("x8"),
Signature = gp.DeclaringType.Name
};

typeDef.GenericParameters.Add(genericParam);
}

// list type fields
foreach (var f in t.Fields)
{
Expand Down
1 change: 0 additions & 1 deletion MetadataProcessor.Core/nanoSkeletonGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
//

using Mono.Cecil;
using Mono.Cecil.Rocks;
using Mustache;
using nanoFramework.Tools.MetadataProcessor.Core.Extensions;
using System;
Expand Down
Loading

0 comments on commit ffc10a0

Please sign in to comment.