Browse Source
This also provides a location for us to add any other trampolines that we need to emit.pull/7246/head
9 changed files with 237 additions and 186 deletions
@ -0,0 +1,117 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Diagnostics; |
|||
using System.Text; |
|||
using XamlX.Emit; |
|||
using XamlX.IL; |
|||
using XamlX.TypeSystem; |
|||
using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers; |
|||
using System.Reflection.Emit; |
|||
|
|||
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions |
|||
{ |
|||
internal class XamlIlTrampolineBuilder |
|||
{ |
|||
private IXamlTypeBuilder<IXamlILEmitter> _builder; |
|||
private Dictionary<string, IXamlMethod> _trampolines = new(); |
|||
|
|||
public XamlIlTrampolineBuilder(IXamlTypeBuilder<IXamlILEmitter> builder) |
|||
{ |
|||
_builder = builder; |
|||
} |
|||
|
|||
public IXamlMethod EmitCommandExecuteTrampoline(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlMethod executeMethod) |
|||
{ |
|||
Debug.Assert(!executeMethod.IsStatic); |
|||
string methodName = $"{executeMethod.DeclaringType.GetFqn()}+{executeMethod.Name}_{executeMethod.Parameters.Count}!CommandExecuteTrampoline"; |
|||
if (_trampolines.TryGetValue(methodName, out var method)) |
|||
{ |
|||
return method; |
|||
} |
|||
var trampoline = _builder.DefineMethod( |
|||
context.Configuration.WellKnownTypes.Void, |
|||
new[] { context.Configuration.WellKnownTypes.Object, context.Configuration.WellKnownTypes.Object }, |
|||
methodName, |
|||
true, |
|||
true, |
|||
false); |
|||
var gen = trampoline.Generator; |
|||
if (executeMethod.DeclaringType.IsValueType) |
|||
{ |
|||
gen.Ldarg_0() |
|||
.Unbox(executeMethod.DeclaringType); |
|||
} |
|||
else |
|||
{ |
|||
gen.Ldarg_0() |
|||
.Castclass(executeMethod.DeclaringType); |
|||
} |
|||
if (executeMethod.Parameters.Count != 0) |
|||
{ |
|||
Debug.Assert(executeMethod.Parameters.Count == 1); |
|||
if (executeMethod.Parameters[0] != context.Configuration.WellKnownTypes.Object) |
|||
{ |
|||
var convertedValue = gen.DefineLocal(context.Configuration.WellKnownTypes.Object); |
|||
gen.Ldtype(executeMethod.Parameters[0]) |
|||
.Ldarg(1) |
|||
.EmitCall(context.Configuration.WellKnownTypes.CultureInfo.FindMethod(m => m.Name == "get_CurrentCulture")) |
|||
.Ldloca(convertedValue) |
|||
.EmitCall( |
|||
context.GetAvaloniaTypes().TypeUtilities.FindMethod(m => m.Name == "TryConvert"), |
|||
swallowResult: true) |
|||
.Ldloc(convertedValue) |
|||
.Unbox_Any(executeMethod.Parameters[0]); |
|||
} |
|||
else |
|||
{ |
|||
gen.Ldarg(1); |
|||
} |
|||
} |
|||
gen.Emit(OpCodes.Tailcall); |
|||
gen.EmitCall(executeMethod, swallowResult: true); |
|||
gen.Ret(); |
|||
|
|||
_trampolines.Add(methodName, trampoline); |
|||
return trampoline; |
|||
} |
|||
|
|||
public IXamlMethod EmitCommandCanExecuteTrampoline(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlMethod canExecuteMethod) |
|||
{ |
|||
Debug.Assert(!canExecuteMethod.IsStatic); |
|||
Debug.Assert(canExecuteMethod.Parameters.Count == 1); |
|||
Debug.Assert(canExecuteMethod.ReturnType == context.Configuration.WellKnownTypes.Boolean); |
|||
string methodName = $"{canExecuteMethod.DeclaringType.GetFqn()}+{canExecuteMethod.Name}!CommandCanExecuteTrampoline"; |
|||
if (_trampolines.TryGetValue(methodName, out var method)) |
|||
{ |
|||
return method; |
|||
} |
|||
var trampoline = _builder.DefineMethod( |
|||
context.Configuration.WellKnownTypes.Boolean, |
|||
new[] { context.Configuration.WellKnownTypes.Object, context.Configuration.WellKnownTypes.Object }, |
|||
methodName, |
|||
true, |
|||
true, |
|||
false); |
|||
if (canExecuteMethod.DeclaringType.IsValueType) |
|||
{ |
|||
trampoline.Generator |
|||
.Ldarg_0() |
|||
.Unbox(canExecuteMethod.DeclaringType); |
|||
} |
|||
else |
|||
{ |
|||
trampoline.Generator |
|||
.Ldarg_0() |
|||
.Castclass(canExecuteMethod.DeclaringType); |
|||
} |
|||
trampoline.Generator |
|||
.Ldarg(1) |
|||
.Emit(OpCodes.Tailcall) |
|||
.EmitCall(canExecuteMethod) |
|||
.Ret(); |
|||
|
|||
_trampolines.Add(methodName, trampoline); |
|||
return trampoline; |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue