Lokad / ILPack

Serialize .NET Core assemblies

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Manage cyclic type dependencies

osman-turan opened this issue · comments

During working #9, I realized a major problem in the code architecture. All serialization logic works in-order. With latest fixes serializing a type works like that:

  1. Serialize all fields of the type
  2. Serialize all properties of the type
  3. Serialize all methods of the type
  4. Serialize all constructors of the type
  5. Serialize the type

Meaning that, a simple code which uses singleton pattern cannot be serialized:

public class MyClass {
  private static MyClass _instance;

  public static MyClass GetInstance() {
    if (_instance == null) {
      _instance = new MyClass();
    }
    return _instance;
  }
}

Because, during serializing the GetInstance method (see 3rd step), MyClass type is not added into _typeHandles dictionary which is used for type resolution.

The following code is the root of the problem:

var fields = CreateFields(type.GetFields(AllFields));
var propsHandle = CreatePropertiesForType(type.GetProperties(AllProperties));
var methods = CreateMethods(type.GetMethods(AllMethods));
CreateConstructors(type.GetConstructors());
var def = _metadataBuilder.AddTypeDefinition(
type.Attributes,
GetString(type.Namespace),
GetString(type.Name),
baseType,
fields.IsNil ? MetadataTokens.FieldDefinitionHandle(1) : fields,
methods.IsNil ? MetadataTokens.MethodDefinitionHandle(1) : methods);
// Handle generics type
if (type.IsGenericType)
{
if (type.IsGenericTypeDefinition)
{
var genericType = type.GetGenericTypeDefinition();
var typeInfo = genericType.GetTypeInfo();
for (var i = 0; i < typeInfo.GenericTypeParameters.Length; ++i)
{
var parm = typeInfo.GenericTypeParameters[i];
var attr = parm.GenericParameterAttributes;
var genericParameterHandle =
_metadataBuilder.AddGenericParameter(def, attr, GetString(parm.Name), i);
foreach (var constraint in parm.GetGenericParameterConstraints())
{
_metadataBuilder.AddGenericParameterConstraint(genericParameterHandle,
GetOrCreateType(constraint));
}
}
}
}
_typeHandles[type.GUID] = def;

Relevant unit test can be found in self-reference-unit-test branch. I didn't merge the changes into develop branch incase you set up CI pipeline which relies on all tests passed.

A major refactoring is required to support cyclic-references with placeholder classes to "reserve" metadata tokens. This refactoring will increase the coverage of generic support as well such as:

public class Vector: IEquatable<Vector> {
  // ...
}

Relevant unit test was added to master branch.