Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 65 additions & 17 deletions Cecilifier.ApiDriver.MonoCecil/MonoCecilDefinitionsFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -147,20 +147,19 @@ public IEnumerable<string> Method(IVisitorContext context,
if (typeParameters.Count > 0)
exps.Add($"{definitionContext.Member.DefinitionVariable}.ReturnType = {returnTypeResolver(context)};");

if (definitionContext.Options.HasFlag(MemberOptions.IsRuntime))
{
exps.Add($"{definitionContext.Member.DefinitionVariable}.IsRuntime = true;");
}

exps.Add($"{definitionContext.Member.DefinitionVariable}.HasThis = {(!definitionContext.Options.HasFlag(MemberOptions.Static)).ToKeyword()};");
exps.Add($"{definitionContext.Member.DefinitionVariable}.IsStatic = {definitionContext.Options.HasFlag(MemberOptions.Static).ToKeyword()};");

foreach (var parameter in parameters)
{
var paramVar = context.Naming.SyntheticVariable(parameter.Name, ElementKind.Parameter);
var parameterExp = CecilDefinitionsFactory.Parameter(
context,
parameter.Name,
parameter.RefKind,
parameter.ParamsAttributeName, // for now,the only callers for this method don't have any `params` parameters.
definitionContext.Member.DefinitionVariable,
paramVar,
parameter.ElementTypeResolver != null ? parameter.ElementTypeResolver(context, parameter) : parameter.ElementType,
parameter.Attributes,
(parameter.DefaultValue, parameter.DefaultValue != null));

var parameterExp = Parameter(context, parameter, definitionContext.Member.DefinitionVariable, paramVar);

context.DefinitionVariables.RegisterNonMethod(definitionContext.Member.Identifier, parameter.Name, VariableMemberKind.Parameter, paramVar);
exps.AddRange(parameterExp);
}
Expand All @@ -180,6 +179,25 @@ public IEnumerable<string> Method(IVisitorContext context,
return exps;
}

public IEnumerable<string> Parameter(IVisitorContext context, ParameterSpec parameterSpec, string memberVar, string paramVar)
{
var exps = new List<string>();

var parameterType = parameterSpec.ElementTypeResolver != null ? parameterSpec.ElementTypeResolver(context, parameterSpec) : parameterSpec.ElementType;
exps.Add($"var {paramVar} = {ParameterDoesNotHandleParamsKeywordOrDefaultValue(context.TypeResolver, parameterSpec.Name, parameterSpec.RefKind, parameterType, parameterSpec.Attributes)};");
if (!string.IsNullOrWhiteSpace(parameterSpec.ParamsAttributeName))
{
exps.Add($"{paramVar}.CustomAttributes.Add(new CustomAttribute(assembly.MainModule.Import(typeof({parameterSpec.ParamsAttributeName}).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, new Type[0], null))));");
}

if (parameterSpec.DefaultValue.Present)
exps.Add($"{paramVar}.Constant = {parameterSpec.DefaultValue.Value ?? "null" };");

exps.Add($"{memberVar}.Parameters.Add({paramVar});");

return exps;
}

public IEnumerable<string> FieldReference(IVisitorContext context, string fieldReferenceVariable, string fieldName, ResolvedType fieldType, in ResolvedType declaringType)
{
return
Expand Down Expand Up @@ -247,18 +265,28 @@ string OperandFor(InstructionRepresentation inst)
}
}

public IEnumerable<string> Constructor(IVisitorContext context, BodiedMemberDefinitionContext definitionContext, string typeName, bool isStatic, string methodAccessibility, string[] paramTypes, string? methodDefinitionPropertyValues = null)
public IEnumerable<string> Constructor(IVisitorContext context, BodiedMemberDefinitionContext definitionContext, string typeName, bool isStatic, string methodAccessibility, ParameterSpec[] parameters)
{
var ctorName = Utils.ConstructorMethodName(isStatic);
context.DefinitionVariables.RegisterMethod(typeName, ctorName, paramTypes, [], definitionContext.Member.DefinitionVariable);
context.DefinitionVariables.RegisterMethod(typeName, ctorName, parameters.Select(p => p.RegistrationTypeName).ToArray()!, [], definitionContext.Member.DefinitionVariable);

var exp = $@"var {definitionContext.Member.DefinitionVariable} = new MethodDefinition(""{ctorName}"", {methodAccessibility} | MethodAttributes.HideBySig | {Constants.Cecil.CtorAttributes}, assembly.MainModule.TypeSystem.Void)";
if (methodDefinitionPropertyValues != null)
var exps = new List<string>();
exps.Add($@"var {definitionContext.Member.DefinitionVariable} = new MethodDefinition(""{ctorName}"", {methodAccessibility} | MethodAttributes.HideBySig | {Constants.Cecil.CtorAttributes}, assembly.MainModule.TypeSystem.Void);");
if (definitionContext.Options.HasFlag(MemberOptions.IsRuntime))
{
exp = exp + $"{{ {methodDefinitionPropertyValues} }}";
exps[^1] = exps[^1].Substring(0, exps[^1].Length - 1); // removes the last `;`
exps.Add("{ IsRuntime = true };");
}

return [exp + ";", $"{definitionContext.Member.ParentDefinitionVariable}.Methods.Add({definitionContext.Member.DefinitionVariable});"];
foreach (var parameter in parameters)
{
var paramVar = context.Naming.Parameter("ctor");
exps.AddRange(Parameter(context, parameter, definitionContext.Member.DefinitionVariable, paramVar));
context.DefinitionVariables.RegisterNonMethod(definitionContext.Member.Identifier, parameter.Name, VariableMemberKind.Parameter, paramVar);
}
exps.Add($"{definitionContext.Member.ParentDefinitionVariable}.Methods.Add({definitionContext.Member.DefinitionVariable});");

return exps;
}

public IEnumerable<string> Field(IVisitorContext context, in MemberDefinitionContext definitionContext, ISymbol fieldOrEvent, ITypeSymbol fieldType, string fieldAttributes, bool isVolatile, bool isByRef, in FieldInitializationData initializer = default)
Expand Down Expand Up @@ -496,6 +524,15 @@ static string CallingConventionToCecil(CallingConvention callingConvention)
}
}

public IEnumerable<string> SetStructLayoutAttribute(IVisitorContext context, string structDefinitionVariable, TypeLayoutProperty[] properties)
{
return
[
$"{structDefinitionVariable}.ClassSize = { properties.SingleOrDefault(p => p.Kind == TypeLayoutPropertyKind.ClassSize).Value };",
$"{structDefinitionVariable}.PackingSize = { properties.SingleOrDefault(p => p.Kind == TypeLayoutPropertyKind.PackingSize).Value };",
];
}

private static string CustomAttributeArgumentValueFor(IVisitorContext context, object argument)
{
if (argument is Array array)
Expand Down Expand Up @@ -636,4 +673,15 @@ private ResolvedType ProcessRequiredModifiers(IVisitorContext context, ResolvedT

return id;
}

private static string ParameterDoesNotHandleParamsKeywordOrDefaultValue(ITypeResolver resolver, string name, RefKind byRef, ResolvedType resolvedType, string? paramAttributes = null)
{
paramAttributes ??= Constants.ParameterAttributes.None;
if (RefKind.None != byRef)
{
resolvedType = resolver.MakeByRefType(resolvedType);
}

return $"new ParameterDefinition(\"{name}\", {paramAttributes}, {resolvedType})";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public string ResolveMethod(IMethodSymbol method)
foreach (var parameter in method.Parameters)
{
var tempParamVar = context.Naming.SyntheticVariable(parameter.Name, ElementKind.Parameter);
var exps = CecilDefinitionsFactory.Parameter(context, parameter.OriginalDefinition, tempMethodVar, tempParamVar);
var exps = context.ApiDefinitionsFactory.Parameter(context, parameter.OriginalDefinition.ToParameterSpec(context, tempMethodVar), tempMethodVar, tempParamVar);
context.Generate(exps);
}

Expand Down Expand Up @@ -143,7 +143,7 @@ public string ResolveMethod(string declaringTypeName, string declaringTypeVariab
HasThis = {{methodWithIncorrectDeclaringType}}.HasThis,
CallingConvention = {{methodWithIncorrectDeclaringType}}.CallingConvention,
ExplicitThis = {{methodWithIncorrectDeclaringType}}.ExplicitThis,
DeclaringType = {{methodWithIncorrectDeclaringType}}.DeclaringType.MakeGenericInstanceType({{correctDeclaringType}}.GenericArguments.ToArray()),
DeclaringType = {{correctDeclaringType}},
};
""");
context.WriteNewLine();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,18 @@ void DefineDelayed(SystemReflectionMetadataContext ctx, ref TypeDefinitionRecord
}
}

public void SetStructLayoutAttribute(IVisitorContext context, string structDefinitionVariable, TypeLayoutProperty[] properties)
{
if (properties.Length == 0)
return;

var packingSize = properties.SingleOrDefault(p => p.Kind == TypeLayoutPropertyKind.PackingSize).Value;
var clasSize = properties.SingleOrDefault(p => p.Kind == TypeLayoutPropertyKind.ClassSize).Value;

context.Generate($"metadata.AddTypeLayout({structDefinitionVariable}, {packingSize}, {clasSize});");
context.WriteNewLine();
}

public void UpdateBaseTypeIfNeeded(IVisitorContext context, ITypeSymbol typeSymbol, string typeDefinitionVariable)
{
// No op on SRM.
Expand All @@ -146,15 +158,14 @@ public IEnumerable<string> Method(IVisitorContext context, IMethodSymbol methodS

// Resolve the method to make sure there's a method ref available (this will be used to fulfill any references to this method)
context.MemberResolver.ResolveMethod(methodSymbol);

var paramIndexOffset = methodSymbol.IsStatic ? 0 : 1;

// register all parameters so we can reference them when emitting the method body
foreach (var parameter in methodSymbol.Parameters)
{
// This is a hack. SRM accesses parameters by index, and Cecilifier does not have a way to pass that index around; it only has variable names,
// so we record the `index` of the parameter as the variable name.
// Code that emits Ldarg/Starg/etc will use this `name` (actually the parameter index) as its operand (this is similar to the way we handle local variables)
context.DefinitionVariables.RegisterNonMethod(methodSymbol.ToDisplayString(), parameter.Name, VariableMemberKind.Parameter, (parameter.Ordinal + paramIndexOffset).ToString());
context.DefinitionVariables.RegisterNonMethod(methodSymbol.ToDisplayString(), parameter.Name, VariableMemberKind.Parameter, parameter.AdjustedParameterIndex().ToString());
}

var memberParentDefinitionVariable = bodiedMemberDefinitionContext.Member.ParentDefinitionVariable ?? throw new ArgumentNullException(nameof(bodiedMemberDefinitionContext.Member.ParentDefinitionVariable));
Expand Down Expand Up @@ -273,7 +284,7 @@ public IEnumerable<string> Method(IVisitorContext context,
ctx.Generate($"""
var {methodDefVar} = metadata.AddMethodDefinition(
{methodModifiers},
MethodImplAttributes.IL | MethodImplAttributes.Managed,
{ "MethodImplAttributes.IL | MethodImplAttributes.Managed".AppendEnumFlagConditional("MethodImplAttributes.Runtime", definitionContext.Options.HasFlag(MemberOptions.IsRuntime)) },
metadata.GetOrAddString("{definitionContext.Member.Name}"),
{methodSignatureVar.VariableName},
{methodBodyOffset},
Expand Down Expand Up @@ -302,41 +313,55 @@ public IEnumerable<string> Method(IVisitorContext context,
return [];
}

public IEnumerable<string> Constructor(IVisitorContext context, BodiedMemberDefinitionContext definitionContext, string typeName, bool isStatic, string methodAccessibility, string[] paramTypes, string? methodDefinitionPropertyValues = null)
public IEnumerable<string> Constructor(IVisitorContext context, BodiedMemberDefinitionContext definitionContext, string typeName, bool isStatic, string methodAccessibility, ParameterSpec[] parameters)
{
var nameAsIdentifier = typeName.ToValidIdentifier();
var parameterlessCtorSignatureVar = context.Naming.SyntheticVariable($"{nameAsIdentifier}_ctorSignature", ElementKind.MemberReference);
var parameterCtorSignatureVar = context.Naming.SyntheticVariable($"{nameAsIdentifier}_ctorSignature", ElementKind.MemberReference);
yield return Format(
$$"""
var {{parameterlessCtorSignatureVar}} = new BlobBuilder();
new BlobEncoder({{parameterlessCtorSignatureVar}})
var {{parameterCtorSignatureVar}} = new BlobBuilder();
new BlobEncoder({{parameterCtorSignatureVar}})
.MethodSignature(isInstanceMethod: {{ (!isStatic).ToKeyword()}})
.Parameters(0, returnType => returnType.Void(), parameters => { });
.Parameters({{parameters.Length}}, returnType => returnType.Void(), parameters =>
{
{{
string.Join('\n', parameters.Select(p => $"""parameters.AddParameter().{p.ElementType};"""))
}}
});
""");

var parentDefinitionVariable = definitionContext.Member.ParentDefinitionVariable ?? throw new ArgumentNullException(nameof(definitionContext.Member.ParentDefinitionVariable));
TypedContext(context).DelayedDefinitionsManager.RegisterMethodDefinition(parentDefinitionVariable, definitionContext.Member.DefinitionVariable, (ctx, methodRecord) =>
{
EmitLocalVariables(ctx, "ctor", in methodRecord);

Debug.Assert(definitionContext.IlContext != null);
var ctorBodyOffset = definitionContext.IlContext != null
? $"methodBodyStream.AddMethodBody({definitionContext.IlContext.VariableName}, localVariablesSignature: {methodRecord.LocalSignatureHandleVariable})"
: "-1"; // ilcontext is null meaning the method don't have a body whence we need to set offset to -1

var ctorDefVar = ctx.Naming.SyntheticVariable($"{nameAsIdentifier}_Ctor", ElementKind.MemberReference);
var ctorAttributes = "MethodImplAttributes.IL | MethodImplAttributes.Managed".AppendEnumFlagConditional("MethodImplAttributes.Runtime", definitionContext.Options.HasFlag(MemberOptions.IsRuntime));
ctx.Generate($"""
var {ctorDefVar} = metadata.AddMethodDefinition(
{(isStatic ? "MethodAttributes.Private | MethodAttributes.Static" : methodAccessibility)} | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
MethodImplAttributes.IL | MethodImplAttributes.Managed,
metadata.GetOrAddString("{(isStatic ? ".cctor" : ".ctor")}"),
metadata.GetOrAddBlob({parameterlessCtorSignatureVar}),
methodBodyStream.AddMethodBody({definitionContext.IlContext.VariableName}, localVariablesSignature: {methodRecord.LocalSignatureHandleVariable}),
parameterList: {methodRecord.FirstParameterHandle});
""");
var {ctorDefVar} = metadata.AddMethodDefinition(
{(isStatic ? "MethodAttributes.Private | MethodAttributes.Static" : methodAccessibility)} | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
{ctorAttributes},
metadata.GetOrAddString("{(isStatic ? ".cctor" : ".ctor")}"),
metadata.GetOrAddBlob({parameterCtorSignatureVar}),
{ctorBodyOffset},
parameterList: {methodRecord.FirstParameterHandle});
""");

ctx.WriteNewLine();
ctx.WriteNewLine();
return ctorDefVar;
});
}

public IEnumerable<string> Parameter(IVisitorContext context, ParameterSpec parameterSpec, string memberVar, string paramVar)
{
throw new NotImplementedException();
}

public IEnumerable<string> Field(IVisitorContext context, in MemberDefinitionContext definitionContext, ISymbol fieldOrEvent, ITypeSymbol fieldType, string fieldAttributes, bool isVolatile, bool isByRef, in FieldInitializationData initializer = default)
{
var resolvedType = context.TypeResolver.Resolve(fieldType, new TypeResolutionContext(ResolveTargetKind.Field, fieldType.ElementTypeSymbolOf().IsValueType ? TypeResolutionOptions.IsValueType : TypeResolutionOptions.None));
Expand Down Expand Up @@ -626,6 +651,11 @@ static DefinitionVariable GetOrRegisterModuleReference(IVisitorContext context,
}
}

IEnumerable<string> IApiDriverDefinitionsFactory.SetStructLayoutAttribute(IVisitorContext context, string structDefinitionVariable, TypeLayoutProperty[] properties)
{
return [];
}

private SystemReflectionMetadataContext TypedContext(IVisitorContext context) => ((SystemReflectionMetadataContext) context);

static void EmitLocalVariables(SystemReflectionMetadataContext context, string methodName, ref readonly MethodDefinitionRecord methodRecord)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Runtime.CompilerServices;
using Cecilifier.Core.ApiDriver;
using Cecilifier.Core.Extensions;
using Cecilifier.Core.Misc;
using Cecilifier.Core.Naming;
using Cecilifier.Core.TypeSystem;
using Cecilifier.Core.Variables;
Expand Down Expand Up @@ -178,9 +179,15 @@ public string ResolveField(IFieldSymbol field)
return fieldRefVarName;
}

public string ResolveEventField(IEventSymbol aEvent)
public string ResolveEventField(IEventSymbol eventSymbol)
{
throw new NotImplementedException();
if (!eventSymbol.IsDefinedInCurrentAssembly(context))
throw new InvalidOperationException($"Event field {eventSymbol.Name} must be defined in the current assembly.");

var found = context.DefinitionVariables.GetVariable(eventSymbol.Name, VariableMemberKind.Field, eventSymbol.ContainingType.OriginalDefinition.ToDisplayString());
found.ThrowIfVariableIsNotValid();

return Utils.MakeGenericTypeIfAppropriate(context, eventSymbol, eventSymbol.Name) ?? found.VariableName;
}

public string ImportReference(string expression) => expression; // In SRM this is a noop
Expand Down
2 changes: 1 addition & 1 deletion Cecilifier.Common.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>13</LangVersion>
<AssemblyVersion>2.28.0</AssemblyVersion>
<AssemblyVersion>2.29.0</AssemblyVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>

Expand Down
Loading
Loading