Browse Source

CECIL

xamlil-debug-info
Nikita Tsukanov 8 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> <ItemGroup>
<ProjectReference Include="$(MSBuildThisFileDirectory)..\src\Avalonia.Desktop\Avalonia.Desktop.csproj" /> <ProjectReference Include="$(MSBuildThisFileDirectory)..\src\Avalonia.Desktop\Avalonia.Desktop.csproj" />
</ItemGroup> </ItemGroup>
<Target Name="GatherReferences" AfterTargets="CoreCompile">
<WriteLinesToFile File="$(TargetPath).refs"
Lines="@(ReferencePathWithRefAssemblies)"
Overwrite="true" />
</Target>
</Project> </Project>

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

@ -1,6 +1,6 @@
<Style xmlns="https://github.com/avaloniaui" <Style xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 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> <Style.Resources>
<Color x:Key="ThemeAccentColor">#CC119EDA</Color> <Color x:Key="ThemeAccentColor">#CC119EDA</Color>

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

@ -1,6 +1,6 @@
<Style xmlns="https://github.com/avaloniaui" <Style xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 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> <Style.Resources>
<Color x:Key="ThemeAccentColor">#CC119EDA</Color> <Color x:Key="ThemeAccentColor">#CC119EDA</Color>

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

@ -7,7 +7,7 @@
<Styles xmlns="https://github.com/avaloniaui" <Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 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"> <Style Selector="DatePicker">
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}"/> <Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}"/>

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

@ -1,5 +1,5 @@
<Styles xmlns="https://github.com/avaloniaui" <Styles xmlns="https://github.com/avaloniaui"
xmlns:sys="clr-namespace:System;assembly=mscorlib"> xmlns:sys="clr-namespace:System;assembly=netstandard">
<Style Selector="MenuItem"> <Style Selector="MenuItem">
<Setter Property="Background" Value="Transparent"/> <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="XamlLoadException.cs" />
<Compile Include="PortableXaml\portable.xaml.github\src\Portable.Xaml\**\*.cs" Exclude="PortableXaml\portable.xaml.github\src\Portable.Xaml\Assembly\**\*.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\**\*.cs" />
<Compile Include="XamlIl\xamlil.github\src\XamlIl.Cecil\**\*.cs" />
<Compile Remove="XamlIl\xamlil.github\**\obj\**\*.cs" /> <Compile Remove="XamlIl\xamlil.github\**\obj\**\*.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -78,6 +79,7 @@
<ProjectReference Include="..\..\Avalonia.Styling\Avalonia.Styling.csproj" /> <ProjectReference Include="..\..\Avalonia.Styling\Avalonia.Styling.csproj" />
<ProjectReference Include="..\Avalonia.Markup\Avalonia.Markup.csproj" /> <ProjectReference Include="..\Avalonia.Markup\Avalonia.Markup.csproj" />
<PackageReference Include="System.Reflection.Emit" Version="4.3.0" /> <PackageReference Include="System.Reflection.Emit" Version="4.3.0" />
<PackageReference Include="Mono.Cecil" Version="0.10.3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="XamlIl\CompilerExtensions\README.md" /> <Content Include="XamlIl\CompilerExtensions\README.md" />

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

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -8,31 +9,35 @@ using System.Reflection.Emit;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions; using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions;
using Avalonia.Platform; using Avalonia.Platform;
using Mono.Cecil;
using XamlIl.Ast; using XamlIl.Ast;
using XamlIl.Transform; using XamlIl.Transform;
using XamlIl.TypeSystem; using XamlIl.TypeSystem;
using TypeAttributes = Mono.Cecil.TypeAttributes;
namespace Avalonia.Markup.Xaml.XamlIl namespace Avalonia.Markup.Xaml.XamlIl
{ {
public static class AvaloniaXamlIlRuntimeCompiler public static class AvaloniaXamlIlRuntimeCompiler
{ {
private static SreTypeSystem _typeSystem; private static SreTypeSystem _sreTypeSystem;
private static ModuleBuilder _builder; private static ModuleBuilder _sreBuilder;
private static XamlIlLanguageTypeMappings _mappings; private static XamlIlLanguageTypeMappings _sreMappings;
private static XamlIlXmlnsMappings _xmlns; private static XamlIlXmlnsMappings _sreXmlns;
private static AssemblyBuilder _asm; private static AssemblyBuilder _sreAsm;
private static bool _canSave; private static bool _sreCanSave;
public static void DumpRuntimeCompilationResults() 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); .FirstOrDefault(m => m.Name == "Save" && m.GetParameters().Length == 1);
if (saveMethod == null) if (saveMethod == null)
return; return;
try try
{ {
_builder.CreateGlobalFunctions(); _sreBuilder.CreateGlobalFunctions();
saveMethod.Invoke(_asm, new Object[] {"XamlIlLoader.ildump"}); saveMethod.Invoke(_sreAsm, new Object[] {"XamlIlLoader.ildump"});
} }
catch catch
{ {
@ -40,81 +45,92 @@ namespace Avalonia.Markup.Xaml.XamlIl
} }
} }
static void Initialize() static void InitializeSre()
{ {
if (_typeSystem == null) if (_sreTypeSystem == null)
_typeSystem = new SreTypeSystem(); _sreTypeSystem = new SreTypeSystem();
if (_builder == null) 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")); var name = new AssemblyName(Guid.NewGuid().ToString("N"));
if (_canSave) if (_sreCanSave)
{ {
var define = AppDomain.CurrentDomain.GetType().GetMethods() var define = AppDomain.CurrentDomain.GetType().GetMethods()
.FirstOrDefault(m => m.Name == "DefineDynamicAssembly" .FirstOrDefault(m => m.Name == "DefineDynamicAssembly"
&& m.GetParameters().Length == 3 && && m.GetParameters().Length == 3 &&
m.GetParameters()[2].ParameterType == typeof(string)); m.GetParameters()[2].ParameterType == typeof(string));
if (define != null) if (define != null)
_asm = (AssemblyBuilder)define.Invoke(AppDomain.CurrentDomain, new object[] _sreAsm = (AssemblyBuilder)define.Invoke(AppDomain.CurrentDomain, new object[]
{ {
name, (AssemblyBuilderAccess)3, name, (AssemblyBuilderAccess)3,
Path.GetDirectoryName(typeof(AvaloniaXamlIlRuntimeCompiler).Assembly.GetModules()[0] Path.GetDirectoryName(typeof(AvaloniaXamlIlRuntimeCompiler).Assembly.GetModules()[0]
.FullyQualifiedName) .FullyQualifiedName)
}); });
else else
_canSave = false; _sreCanSave = false;
} }
if(_asm == null) if(_sreAsm == null)
_asm = AssemblyBuilder.DefineDynamicAssembly(name, _sreAsm = AssemblyBuilder.DefineDynamicAssembly(name,
AssemblyBuilderAccess.RunAndCollect); AssemblyBuilderAccess.RunAndCollect);
_builder = _asm.DefineDynamicModule("XamlIlLoader.ildump"); _sreBuilder = _sreAsm.DefineDynamicModule("XamlIlLoader.ildump");
} }
if (_mappings == null) if (_sreMappings == null)
_mappings = AvaloniaXamlIlLanguage.Configure(_typeSystem); _sreMappings = AvaloniaXamlIlLanguage.Configure(_sreTypeSystem);
if (_xmlns == null) if (_sreXmlns == null)
_xmlns = XamlIlXmlnsMappings.Resolve(_typeSystem, _mappings); _sreXmlns = XamlIlXmlnsMappings.Resolve(_sreTypeSystem, _sreMappings);
} }
public static object Load(Stream stream, Assembly localAssembly, object rootInstance, Uri uri) 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; var success = false;
try try
{ {
var rv = LoadCore(stream, localAssembly, rootInstance, uri); var rv = LoadSreCore(xaml, localAssembly, rootInstance, uri);
success = true; success = true;
return rv; return rv;
} }
finally finally
{ {
if(!success && _canSave) if(!success && _sreCanSave)
DumpRuntimeCompilationResults(); 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)) InitializeSre();
xaml = sr.ReadToEnd(); var asm = localAssembly == null ? null : _sreTypeSystem.GetAssembly(localAssembly);
Initialize(); var compiler = new AvaloniaXamlIlCompiler(new XamlIlTransformerConfiguration(_sreTypeSystem, asm,
var asm = localAssembly == null ? null : _typeSystem.GetAssembly(localAssembly); _sreMappings, _sreXmlns, CustomValueConverter));
var compiler = new AvaloniaXamlIlCompiler(new XamlIlTransformerConfiguration(_typeSystem, asm, var tb = _sreBuilder.DefineType("Builder_" + Guid.NewGuid().ToString("N") + "_" + uri);
_mappings, _xmlns, CustomValueConverter));
var tb = _builder.DefineType("Builder_" + Guid.NewGuid().ToString("N") + "_" + uri);
IXamlIlType overrideType = null; IXamlIlType overrideType = null;
if (rootInstance != 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(); var created = tb.CreateTypeInfo();
return LoadOrPopulate(created, rootInstance);
}
static object LoadOrPopulate(Type created, object rootInstance)
{
var isp = Expression.Parameter(typeof(IServiceProvider)); var isp = Expression.Parameter(typeof(IServiceProvider));
if (rootInstance == null) 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, private static bool CustomValueConverter(XamlIlAstTransformationContext context,
IXamlIlAstValueNode node, IXamlIlType type, out IXamlIlAstValueNode result) 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 = @" var xaml = @"
<Style xmlns='https://github.com/avaloniaui' <Style xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' 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> <Style.Resources>
<SolidColorBrush x:Key='Brush'>White</SolidColorBrush> <SolidColorBrush x:Key='Brush'>White</SolidColorBrush>
<sys:Double x:Key='Double'>10</sys:Double> <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 = @" var xaml = @"
<Window xmlns='https://github.com/avaloniaui' <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'> xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<Window.DataTemplates> <Window.DataTemplates>
<DataTemplate DataType='{x:Type sys:String}'> <DataTemplate DataType='{x:Type sys:String}'>

Loading…
Cancel
Save