Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduce generated IL code size #65

Merged
merged 10 commits into from
Aug 12, 2022
6 changes: 6 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
<Project>

<PropertyGroup>
<LangVersion>latest</LangVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>

</Project>
10 changes: 9 additions & 1 deletion src/XamlX.IL.Cecil/CecilEmitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ public IXamlILEmitter Emit(SreOpCode code, int arg)

public IXamlILEmitter Emit(SreOpCode code, long arg)
=> Emit(Instruction.Create(Dic[code], arg));

public IXamlILEmitter Emit(SreOpCode code, sbyte arg)
=> Emit(Instruction.Create(Dic[code], arg));

public IXamlILEmitter Emit(SreOpCode code, byte arg)
=> Emit(Instruction.Create(Dic[code], arg));

public IXamlILEmitter Emit(SreOpCode code, IXamlType type)
=> Emit(Instruction.Create(Dic[code], Import(((ITypeReference) type).Reference)));
Expand All @@ -143,9 +149,11 @@ public IXamlILEmitter Emit(SreOpCode code, double arg)
=> Emit(Instruction.Create(Dic[code], arg));


class CecilLocal : IXamlLocal
class CecilLocal : IXamlILLocal
{
public VariableDefinition Variable { get; set; }

public int Index => Variable.Index;
}

class CecilLabel : IXamlLabel
Expand Down
6 changes: 4 additions & 2 deletions src/XamlX.IL.Cecil/CecilField.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ public CecilField(CecilTypeSystem typeSystem, FieldDefinition def, TypeReference
Field = new FieldReference(def.Name, def.FieldType, declaringType);
}

public bool Equals(IXamlField other) => other is CecilField cf && cf.Field == Field;
public bool Equals(IXamlField other) => other is CecilField cf && cf.Field.FullName == Field.FullName;

public override int GetHashCode() => Field.FullName.GetHashCode();

public string Name => Field.Name;
private IXamlType _type;
Expand All @@ -41,4 +43,4 @@ public object GetLiteralValue()
}
}
}
}
}
3 changes: 3 additions & 0 deletions src/XamlX.IL.Cecil/CecilMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ other is CecilMethod cm
&& DeclaringType.Equals(cm.DeclaringType)
&& Reference.FullName == cm.Reference.FullName;

public override int GetHashCode()
=> (DeclaringType.GetHashCode() * 397) ^ Reference.FullName.GetHashCode();

public IXamlMethod MakeGenericMethod(IReadOnlyList<IXamlType> typeArguments)
{
GenericInstanceMethod instantiation = new GenericInstanceMethod(Reference);
Expand Down
7 changes: 3 additions & 4 deletions src/XamlX.IL.Cecil/CecilType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,9 @@ public bool IsAssignableFrom(IXamlType type)
}
bool IsAssignableFromCore(IXamlType type)
{
if (!type.IsValueType
&& type == XamlPseudoType.Null)
return true;

if (type == XamlPseudoType.Null)
return !IsValueType || GenericTypeDefinition?.FullName == "System.Nullable`1";

if (type.IsValueType
&& GenericTypeDefinition?.FullName == "System.Nullable`1"
&& GenericArguments[0].Equals(type))
Expand Down
84 changes: 77 additions & 7 deletions src/XamlX/Ast/Clr.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,33 +87,101 @@ public XamlAstClrProperty(IXamlLineInfo lineInfo, string name, IXamlType declari
public override string ToString() => DeclaringType.GetFqn() + "." + Name;
}

class XamlDirectCallPropertySetter : IXamlPropertySetter, IXamlEmitablePropertySetter<IXamlILEmitter>
#if !XAMLX_INTERNAL
public
#endif
interface IXamlILOptimizedEmitablePropertySetter : IXamlEmitablePropertySetter<IXamlILEmitter>
{
void EmitWithArguments(
XamlEmitContextWithLocals<IXamlILEmitter, XamlILNodeEmitResult> context,
IXamlILEmitter emitter,
IReadOnlyList<IXamlAstValueNode> arguments);
}

class XamlDirectCallPropertySetter : IXamlILOptimizedEmitablePropertySetter, IEquatable<XamlDirectCallPropertySetter>
{
private readonly IXamlMethod _method;
public IXamlType TargetType { get; }
public PropertySetterBinderParameters BinderParameters { get; } = new PropertySetterBinderParameters();
public IReadOnlyList<IXamlType> Parameters { get; }
public void Emit(IXamlILEmitter codegen)

public void Emit(IXamlILEmitter emitter)
=> emitter.EmitCall(_method, true);

public void EmitWithArguments(
XamlEmitContextWithLocals<IXamlILEmitter, XamlILNodeEmitResult> context,
IXamlILEmitter emitter,
IReadOnlyList<IXamlAstValueNode> arguments)
{
codegen.EmitCall(_method, true);
for (var i = 0; i < arguments.Count; ++i)
context.Emit(arguments[i], emitter, Parameters[i]);

emitter.EmitCall(_method, true);
}

public XamlDirectCallPropertySetter(IXamlMethod method)
{
_method = method;
Parameters = method.ParametersWithThis().Skip(1).ToList();
TargetType = method.ThisOrFirstParameter();

bool allowNull = Parameters.Last().AcceptsNull();
BinderParameters = new PropertySetterBinderParameters
{
AllowMultiple = false,
AllowXNull = allowNull,
AllowRuntimeNull = allowNull
};
}

public bool Equals(XamlDirectCallPropertySetter other)
{
if (ReferenceEquals(null, other))
return false;
if (ReferenceEquals(this, other))
return true;

return _method.Equals(other._method) && BinderParameters.Equals(other.BinderParameters);
}

public override bool Equals(object obj)
=> Equals(obj as XamlDirectCallPropertySetter);

public override int GetHashCode()
=> (_method.GetHashCode() * 397) ^ BinderParameters.GetHashCode();
}

#if !XAMLX_INTERNAL
public
#endif
class PropertySetterBinderParameters
class PropertySetterBinderParameters : IEquatable<PropertySetterBinderParameters>
{
public bool AllowMultiple { get; set; }
public bool AllowXNull { get; set; } = true;
public bool AllowRuntimeNull { get; set; } = true;

public bool Equals(PropertySetterBinderParameters other)
{
if (ReferenceEquals(null, other))
return false;
if (ReferenceEquals(this, other))
return true;

return AllowMultiple == other.AllowMultiple
&& AllowXNull == other.AllowXNull
&& AllowRuntimeNull == other.AllowRuntimeNull;
}

public override bool Equals(object obj)
=> Equals(obj as PropertySetterBinderParameters);

public override int GetHashCode()
{
int hashCode = AllowMultiple.GetHashCode();
hashCode = (hashCode * 397) ^ AllowXNull.GetHashCode();
hashCode = (hashCode * 397) ^ AllowRuntimeNull.GetHashCode();
return hashCode;
}
}

#if !XAMLX_INTERNAL
Expand Down Expand Up @@ -637,6 +705,8 @@ void CompileBuilder(ILEmitContext context)

context.Emit(Value, context.Emitter, context.Configuration.WellKnownTypes.Object);
il.Ret();

context.ExecuteAfterEmitCallbacks();
}

public XamlILNodeEmitResult Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
Expand All @@ -652,7 +722,7 @@ public XamlILNodeEmitResult Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitR
context.EmitMappings, runtimeContext: context.RuntimeContext,
contextLocal: buildMethod.Generator.DefineLocal(context.RuntimeContext.ContextType),
createSubType: (s, type) => subType.DefineSubType(type, s, false),
defineDelegateSubType: (s, returnType, parameters) => subType.DefineDelegateSubType(s, false, returnType, parameters),
defineDelegateSubType: (s, returnType, parameters) => subType.DefineDelegateSubType(s, false, returnType, parameters),
file: context.File,
emitters: context.Emitters));

Expand All @@ -662,11 +732,11 @@ public XamlILNodeEmitResult Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitR
.Ldftn(buildMethod)
.Newobj(funcType.Constructors.FirstOrDefault(ct =>
ct.Parameters.Count == 2 && ct.Parameters[0].Equals(context.Configuration.WellKnownTypes.Object)));

// Allow to save values from the parent context, pass own service provider, etc, etc
if (context.Configuration.TypeMappings.DeferredContentExecutorCustomization != null)
{

var customization = context.Configuration.TypeMappings.DeferredContentExecutorCustomization;
if (_deferredContentCustomizationTypeParameter != null)
customization =
Expand Down
4 changes: 2 additions & 2 deletions src/XamlX/Ast/Intrinsics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public XamlILNodeEmitResult Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitR
codeGen.Emit(OpCodes.Ldnull);
return XamlILNodeEmitResult.Type(0, XamlPseudoType.Null);
}
}
}

#if !XAMLX_INTERNAL
public
Expand Down Expand Up @@ -165,7 +165,7 @@ public XamlILNodeEmitResult Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitR
else if (Constant is bool b)
codeGen.Emit(b ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
else
codeGen.Emit(OpCodes.Ldc_I4, TypeSystem.TypeSystemHelpers.ConvertLiteralToInt(Constant));
codeGen.Ldc_I4(TypeSystem.TypeSystemHelpers.ConvertLiteralToInt(Constant));
return XamlILNodeEmitResult.Type(0, Type.GetClrType());
}
}
Expand Down
13 changes: 12 additions & 1 deletion src/XamlX/Emit/XamlEmitContext.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using XamlX.Ast;
using XamlX.Transform;
Expand All @@ -18,6 +17,7 @@ abstract class XamlEmitContext<TBackendEmitter, TEmitResult> : XamlContextBase
public IFileSource File { get; }
public List<object> Emitters { get; }

private readonly List<Action> _afterEmitCallbacks = new();
private IXamlAstNode _currentNode;

public TransformerConfiguration Configuration { get; }
Expand Down Expand Up @@ -217,6 +217,17 @@ protected virtual TEmitResult EmitNodeCore(IXamlAstNode value, TBackendEmitter c
foundEmitter = false;
return res;
}

public void AddAfterEmitCallbacks(Action callback)
=> _afterEmitCallbacks.Add(callback);

public void ExecuteAfterEmitCallbacks()
{
foreach (var callback in _afterEmitCallbacks)
callback();

_afterEmitCallbacks.Clear();
}
}

#if !XAMLX_INTERNAL
Expand Down
14 changes: 14 additions & 0 deletions src/XamlX/IL/CheckingIlEmitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,20 @@ public IXamlILEmitter Emit(OpCode code, long arg)
return this;
}

public IXamlILEmitter Emit(OpCode code, sbyte arg)
{
Track(code, arg);
_inner.Emit(code, arg);
return this;
}

public IXamlILEmitter Emit(OpCode code, byte arg)
{
Track(code, arg);
_inner.Emit(code, arg);
return this;
}

public IXamlILEmitter Emit(OpCode code, IXamlType type)
{
Track(code, type);
Expand Down
2 changes: 1 addition & 1 deletion src/XamlX/IL/Emitters/MarkupExtensionEmitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ void EmitPropertyDescriptor()

if (me.ProvideValue.Parameters.Count > 0)
ilgen
.Emit(OpCodes.Ldloc, context.ContextLocal);
.Ldloc(context.ContextLocal);

if (needProvideValueTarget)
{
Expand Down
Loading