Browse Source

CECIL

xamlil-debug-info
Nikita Tsukanov 7 years ago
parent
commit
4c7551b9fa
  1. 5
      build/SampleApp.props
  2. 2
      src/Avalonia.Themes.Default/Accents/BaseDark.xaml
  3. 2
      src/Avalonia.Themes.Default/Accents/BaseLight.xaml
  4. 2
      src/Avalonia.Themes.Default/DatePicker.xaml
  5. 2
      src/Avalonia.Themes.Default/MenuItem.xaml
  6. 2
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
  7. 157
      src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs
  8. 2
      src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github
  9. 2
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs
  10. 2
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/DataTemplateTests.cs

5
build/SampleApp.props

@ -5,4 +5,9 @@
<ItemGroup>
<ProjectReference Include="$(MSBuildThisFileDirectory)..\src\Avalonia.Desktop\Avalonia.Desktop.csproj" />
</ItemGroup>
<Target Name="GatherReferences" AfterTargets="CoreCompile">
<WriteLinesToFile File="$(TargetPath).refs"
Lines="@(ReferencePathWithRefAssemblies)"
Overwrite="true" />
</Target>
</Project>

2
src/Avalonia.Themes.Default/Accents/BaseDark.xaml

@ -1,6 +1,6 @@
<Style xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
xmlns:sys="clr-namespace:System;assembly=netstandard">
<Style.Resources>
<Color x:Key="ThemeAccentColor">#CC119EDA</Color>

2
src/Avalonia.Themes.Default/Accents/BaseLight.xaml

@ -1,6 +1,6 @@
<Style xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
xmlns:sys="clr-namespace:System;assembly=netstandard">
<Style.Resources>
<Color x:Key="ThemeAccentColor">#CC119EDA</Color>

2
src/Avalonia.Themes.Default/DatePicker.xaml

@ -7,7 +7,7 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
xmlns:sys="clr-namespace:System;assembly=netstandard">
<Style Selector="DatePicker">
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}"/>

2
src/Avalonia.Themes.Default/MenuItem.xaml

@ -1,5 +1,5 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
xmlns:sys="clr-namespace:System;assembly=netstandard">
<Style Selector="MenuItem">
<Setter Property="Background" Value="Transparent"/>

2
src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

@ -65,6 +65,7 @@
<Compile Include="XamlLoadException.cs" />
<Compile Include="PortableXaml\portable.xaml.github\src\Portable.Xaml\**\*.cs" Exclude="PortableXaml\portable.xaml.github\src\Portable.Xaml\Assembly\**\*.cs" />
<Compile Include="XamlIl\xamlil.github\src\XamlIl\**\*.cs" />
<Compile Include="XamlIl\xamlil.github\src\XamlIl.Cecil\**\*.cs" />
<Compile Remove="XamlIl\xamlil.github\**\obj\**\*.cs" />
</ItemGroup>
<ItemGroup>
@ -78,6 +79,7 @@
<ProjectReference Include="..\..\Avalonia.Styling\Avalonia.Styling.csproj" />
<ProjectReference Include="..\Avalonia.Markup\Avalonia.Markup.csproj" />
<PackageReference Include="System.Reflection.Emit" Version="4.3.0" />
<PackageReference Include="Mono.Cecil" Version="0.10.3" />
</ItemGroup>
<ItemGroup>
<Content Include="XamlIl\CompilerExtensions\README.md" />

157
src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
@ -8,31 +9,35 @@ using System.Reflection.Emit;
using System.Runtime.InteropServices;
using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions;
using Avalonia.Platform;
using Mono.Cecil;
using XamlIl.Ast;
using XamlIl.Transform;
using XamlIl.TypeSystem;
using TypeAttributes = Mono.Cecil.TypeAttributes;
namespace Avalonia.Markup.Xaml.XamlIl
{
public static class AvaloniaXamlIlRuntimeCompiler
{
private static SreTypeSystem _typeSystem;
private static ModuleBuilder _builder;
private static XamlIlLanguageTypeMappings _mappings;
private static XamlIlXmlnsMappings _xmlns;
private static AssemblyBuilder _asm;
private static bool _canSave;
private static SreTypeSystem _sreTypeSystem;
private static ModuleBuilder _sreBuilder;
private static XamlIlLanguageTypeMappings _sreMappings;
private static XamlIlXmlnsMappings _sreXmlns;
private static AssemblyBuilder _sreAsm;
private static bool _sreCanSave;
public static void DumpRuntimeCompilationResults()
{
var saveMethod = _asm.GetType().GetMethods()
if (_sreBuilder == null)
return;
var saveMethod = _sreAsm.GetType().GetMethods()
.FirstOrDefault(m => m.Name == "Save" && m.GetParameters().Length == 1);
if (saveMethod == null)
return;
try
{
_builder.CreateGlobalFunctions();
saveMethod.Invoke(_asm, new Object[] {"XamlIlLoader.ildump"});
_sreBuilder.CreateGlobalFunctions();
saveMethod.Invoke(_sreAsm, new Object[] {"XamlIlLoader.ildump"});
}
catch
{
@ -40,81 +45,92 @@ namespace Avalonia.Markup.Xaml.XamlIl
}
}
static void Initialize()
static void InitializeSre()
{
if (_typeSystem == null)
_typeSystem = new SreTypeSystem();
if (_builder == null)
if (_sreTypeSystem == null)
_sreTypeSystem = new SreTypeSystem();
if (_sreBuilder == null)
{
_canSave = !AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetRuntimeInfo().IsCoreClr;
_sreCanSave = !AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetRuntimeInfo().IsCoreClr;
var name = new AssemblyName(Guid.NewGuid().ToString("N"));
if (_canSave)
if (_sreCanSave)
{
var define = AppDomain.CurrentDomain.GetType().GetMethods()
.FirstOrDefault(m => m.Name == "DefineDynamicAssembly"
&& m.GetParameters().Length == 3 &&
m.GetParameters()[2].ParameterType == typeof(string));
if (define != null)
_asm = (AssemblyBuilder)define.Invoke(AppDomain.CurrentDomain, new object[]
_sreAsm = (AssemblyBuilder)define.Invoke(AppDomain.CurrentDomain, new object[]
{
name, (AssemblyBuilderAccess)3,
Path.GetDirectoryName(typeof(AvaloniaXamlIlRuntimeCompiler).Assembly.GetModules()[0]
.FullyQualifiedName)
});
else
_canSave = false;
_sreCanSave = false;
}
if(_asm == null)
_asm = AssemblyBuilder.DefineDynamicAssembly(name,
if(_sreAsm == null)
_sreAsm = AssemblyBuilder.DefineDynamicAssembly(name,
AssemblyBuilderAccess.RunAndCollect);
_builder = _asm.DefineDynamicModule("XamlIlLoader.ildump");
_sreBuilder = _sreAsm.DefineDynamicModule("XamlIlLoader.ildump");
}
if (_mappings == null)
_mappings = AvaloniaXamlIlLanguage.Configure(_typeSystem);
if (_xmlns == null)
_xmlns = XamlIlXmlnsMappings.Resolve(_typeSystem, _mappings);
if (_sreMappings == null)
_sreMappings = AvaloniaXamlIlLanguage.Configure(_sreTypeSystem);
if (_sreXmlns == null)
_sreXmlns = XamlIlXmlnsMappings.Resolve(_sreTypeSystem, _sreMappings);
}
public static object Load(Stream stream, Assembly localAssembly, object rootInstance, Uri uri)
{
string xaml;
using (var sr = new StreamReader(stream))
xaml = sr.ReadToEnd();
return LoadCecil(xaml, localAssembly, rootInstance, uri);
}
static object LoadSre(string xaml, Assembly localAssembly, object rootInstance, Uri uri)
{
var success = false;
try
{
var rv = LoadCore(stream, localAssembly, rootInstance, uri);
var rv = LoadSreCore(xaml, localAssembly, rootInstance, uri);
success = true;
return rv;
}
finally
{
if(!success && _canSave)
if(!success && _sreCanSave)
DumpRuntimeCompilationResults();
}
}
static object LoadCore(Stream stream, Assembly localAssembly, object rootInstance, Uri uri)
static object LoadSreCore(string xaml, Assembly localAssembly, object rootInstance, Uri uri)
{
string xaml;
using (var sr = new StreamReader(stream))
xaml = sr.ReadToEnd();
Initialize();
var asm = localAssembly == null ? null : _typeSystem.GetAssembly(localAssembly);
var compiler = new AvaloniaXamlIlCompiler(new XamlIlTransformerConfiguration(_typeSystem, asm,
_mappings, _xmlns, CustomValueConverter));
var tb = _builder.DefineType("Builder_" + Guid.NewGuid().ToString("N") + "_" + uri);
InitializeSre();
var asm = localAssembly == null ? null : _sreTypeSystem.GetAssembly(localAssembly);
var compiler = new AvaloniaXamlIlCompiler(new XamlIlTransformerConfiguration(_sreTypeSystem, asm,
_sreMappings, _sreXmlns, CustomValueConverter));
var tb = _sreBuilder.DefineType("Builder_" + Guid.NewGuid().ToString("N") + "_" + uri);
IXamlIlType overrideType = null;
if (rootInstance != null)
{
overrideType = _typeSystem.GetType(rootInstance.GetType());
overrideType = _sreTypeSystem.GetType(rootInstance.GetType());
}
compiler.ParseAndCompile(xaml, uri?.ToString(), _typeSystem.CreateTypeBuilder(tb), overrideType);
compiler.ParseAndCompile(xaml, uri?.ToString(), _sreTypeSystem.CreateTypeBuilder(tb), overrideType);
var created = tb.CreateTypeInfo();
return LoadOrPopulate(created, rootInstance);
}
static object LoadOrPopulate(Type created, object rootInstance)
{
var isp = Expression.Parameter(typeof(IServiceProvider));
if (rootInstance == null)
{
@ -136,6 +152,73 @@ namespace Avalonia.Markup.Xaml.XamlIl
}
}
private static Dictionary<string, (Action<IServiceProvider, object> populate, Func<IServiceProvider, object>
build)>
s_CecilCache =
new Dictionary<string, (Action<IServiceProvider, object> populate, Func<IServiceProvider, object> build)
>();
private static string _cecilEmitDir;
private static CecilTypeSystem _cecilTypeSystem;
private static XamlIlLanguageTypeMappings _cecilMappings;
private static XamlIlXmlnsMappings _cecilXmlns;
private static bool _cecilInitialized;
static void InitializeCecil()
{
if(_cecilInitialized)
return;
var path = Assembly.GetEntryAssembly().GetModules()[0].FullyQualifiedName;
_cecilEmitDir = Path.Combine(Path.GetDirectoryName(path), "emit");
Directory.CreateDirectory(_cecilEmitDir);
var refs = new[] {path}.Concat(File.ReadAllLines(path + ".refs"));
_cecilTypeSystem = new CecilTypeSystem(refs);
_cecilMappings = AvaloniaXamlIlLanguage.Configure(_cecilTypeSystem);
_cecilXmlns = XamlIlXmlnsMappings.Resolve(_cecilTypeSystem, _cecilMappings);
_cecilInitialized = true;
}
static object LoadCecil(string xaml, Assembly localAssembly, object rootInstance, Uri uri)
{
if (uri == null)
throw new InvalidOperationException("Please, go away");
InitializeCecil();
IXamlIlType overrideType = null;
if (rootInstance != null)
{
overrideType = _cecilTypeSystem.GetType(rootInstance.GetType().FullName);
}
var safeUri = uri.ToString()
.Replace(":", "_")
.Replace("/", "_")
.Replace("?", "_")
.Replace("=", "_");
var asm = _cecilTypeSystem.CreateAndRegisterAssembly(safeUri, new Version(1, 0),
ModuleKind.Dll);
var def = new TypeDefinition("XamlIlLoader", safeUri,
TypeAttributes.Class | TypeAttributes.Public, asm.MainModule.TypeSystem.Object);
asm.MainModule.Types.Add(def);
var tb = _cecilTypeSystem.CreateTypeBuilder(def);
var compiler = new AvaloniaXamlIlCompiler(new XamlIlTransformerConfiguration(_cecilTypeSystem,
localAssembly == null ? null : _cecilTypeSystem.FindAssembly(localAssembly.GetName().Name),
_cecilMappings, XamlIlXmlnsMappings.Resolve(_cecilTypeSystem, _cecilMappings), CustomValueConverter));
compiler.ParseAndCompile(xaml, uri.ToString(), tb, overrideType);
var asmPath = Path.Combine(_cecilEmitDir, safeUri + ".dll");
using(var f = File.Create(asmPath))
asm.Write(f);
var loaded = Assembly.LoadFile(asmPath)
.GetTypes().First(x => x.Name == safeUri);
return LoadOrPopulate(loaded, rootInstance);
}
private static bool CustomValueConverter(XamlIlAstTransformationContext context,
IXamlIlAstValueNode node, IXamlIlType type, out IXamlIlAstValueNode result)
{

2
src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github

@ -1 +1 @@
Subproject commit 4e7544ea2d152d22668b93c993d4965d5e9d515a
Subproject commit 0c66a9a0a5226378ac0b2c756a85129b94cf1de9

2
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs

@ -518,7 +518,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
var xaml = @"
<Style xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:sys='clr-namespace:System;assembly=mscorlib'>
xmlns:sys='clr-namespace:System;assembly=netstandard'>
<Style.Resources>
<SolidColorBrush x:Key='Brush'>White</SolidColorBrush>
<sys:Double x:Key='Double'>10</sys:Double>

2
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/DataTemplateTests.cs

@ -17,7 +17,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
{
var xaml = @"
<Window xmlns='https://github.com/avaloniaui'
xmlns:sys='clr-namespace:System;assembly=mscorlib'
xmlns:sys='clr-namespace:System;assembly=netstandard'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<Window.DataTemplates>
<DataTemplate DataType='{x:Type sys:String}'>

Loading…
Cancel
Save