Skip to content

Commit

Permalink
Merge pull request #65 from MrJul/size-optimization
Browse files Browse the repository at this point in the history
Reduce generated IL code size
  • Loading branch information
kekekeks authored Aug 12, 2022
2 parents ad11913 + 31564c2 commit 79ab88b
Show file tree
Hide file tree
Showing 27 changed files with 1,053 additions and 233 deletions.
3 changes: 1 addition & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,4 @@
<ItemGroup>
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>

</Project>
</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

0 comments on commit 79ab88b

Please sign in to comment.