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