|
|
@ -10,6 +10,7 @@ using System.Runtime.InteropServices; |
|
|
using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions; |
|
|
using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions; |
|
|
using Avalonia.Markup.Xaml.XamlIl.Runtime; |
|
|
using Avalonia.Markup.Xaml.XamlIl.Runtime; |
|
|
using Avalonia.Platform; |
|
|
using Avalonia.Platform; |
|
|
|
|
|
using XamlX.Ast; |
|
|
using XamlX.Transform; |
|
|
using XamlX.Transform; |
|
|
using XamlX.TypeSystem; |
|
|
using XamlX.TypeSystem; |
|
|
using XamlX.IL; |
|
|
using XamlX.IL; |
|
|
@ -150,12 +151,12 @@ namespace Avalonia.Markup.Xaml.XamlIl |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static object LoadSre(string xaml, Assembly localAssembly, object rootInstance, Uri uri, bool isDesignMode, bool useCompiledBindingsByDefault) |
|
|
static object LoadSre(RuntimeXamlLoaderDocument document, RuntimeXamlLoaderConfiguration configuration) |
|
|
{ |
|
|
{ |
|
|
var success = false; |
|
|
var success = false; |
|
|
try |
|
|
try |
|
|
{ |
|
|
{ |
|
|
var rv = LoadSreCore(xaml, localAssembly, rootInstance, uri, isDesignMode, useCompiledBindingsByDefault); |
|
|
var rv = LoadSreCore(document, configuration); |
|
|
success = true; |
|
|
success = true; |
|
|
return rv; |
|
|
return rv; |
|
|
} |
|
|
} |
|
|
@ -166,45 +167,100 @@ namespace Avalonia.Markup.Xaml.XamlIl |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static IReadOnlyList<object> LoadGroupSre(IReadOnlyCollection<RuntimeXamlLoaderDocument> documents, |
|
|
|
|
|
RuntimeXamlLoaderConfiguration configuration) |
|
|
|
|
|
{ |
|
|
|
|
|
var success = false; |
|
|
|
|
|
try |
|
|
|
|
|
{ |
|
|
|
|
|
var rv = LoadGroupSreCore(documents, configuration); |
|
|
|
|
|
success = true; |
|
|
|
|
|
return rv; |
|
|
|
|
|
} |
|
|
|
|
|
finally |
|
|
|
|
|
{ |
|
|
|
|
|
if( _sreCanSave) |
|
|
|
|
|
DumpRuntimeCompilationResults(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
static object LoadSreCore(string xaml, Assembly localAssembly, object rootInstance, Uri uri, bool isDesignMode, bool useCompiledBindingsByDefault) |
|
|
static IReadOnlyList<object> LoadGroupSreCore(IReadOnlyCollection<RuntimeXamlLoaderDocument> documents, RuntimeXamlLoaderConfiguration configuration) |
|
|
{ |
|
|
{ |
|
|
|
|
|
|
|
|
InitializeSre(); |
|
|
InitializeSre(); |
|
|
|
|
|
var localAssembly = configuration.LocalAssembly; |
|
|
if (localAssembly?.GetName() != null) |
|
|
if (localAssembly?.GetName() != null) |
|
|
EmitIgnoresAccessCheckToAttribute(localAssembly.GetName()); |
|
|
EmitIgnoresAccessCheckToAttribute(localAssembly.GetName()); |
|
|
var asm = localAssembly == null ? null : _sreTypeSystem.GetAssembly(localAssembly); |
|
|
var asm = localAssembly == null ? null : _sreTypeSystem.GetAssembly(localAssembly); |
|
|
var tb = _sreBuilder.DefineType("Builder_" + Guid.NewGuid().ToString("N") + "_" + uri); |
|
|
var clrPropertyBuilder = _sreBuilder.DefineType("ClrProperties_" + Guid.NewGuid().ToString("N")); |
|
|
var clrPropertyBuilder = tb.DefineNestedType("ClrProperties_" + Guid.NewGuid().ToString("N")); |
|
|
|
|
|
var indexerClosureType = _sreBuilder.DefineType("IndexerClosure_" + Guid.NewGuid().ToString("N")); |
|
|
var indexerClosureType = _sreBuilder.DefineType("IndexerClosure_" + Guid.NewGuid().ToString("N")); |
|
|
var trampolineBuilder = _sreBuilder.DefineType("Trampolines_" + Guid.NewGuid().ToString("N")); |
|
|
var trampolineBuilder = _sreBuilder.DefineType("Trampolines_" + Guid.NewGuid().ToString("N")); |
|
|
|
|
|
|
|
|
var compiler = new AvaloniaXamlIlCompiler(new AvaloniaXamlIlCompilerConfiguration(_sreTypeSystem, asm, |
|
|
var compiler = new AvaloniaXamlIlCompiler(new AvaloniaXamlIlCompilerConfiguration(_sreTypeSystem, asm, |
|
|
_sreMappings, _sreXmlns, AvaloniaXamlIlLanguage.CustomValueConverter, |
|
|
_sreMappings, _sreXmlns, AvaloniaXamlIlLanguage.CustomValueConverter, |
|
|
new XamlIlClrPropertyInfoEmitter(_sreTypeSystem.CreateTypeBuilder(clrPropertyBuilder)), |
|
|
new XamlIlClrPropertyInfoEmitter(_sreTypeSystem.CreateTypeBuilder(clrPropertyBuilder)), |
|
|
new XamlIlPropertyInfoAccessorFactoryEmitter(_sreTypeSystem.CreateTypeBuilder(indexerClosureType)), |
|
|
new XamlIlPropertyInfoAccessorFactoryEmitter(_sreTypeSystem.CreateTypeBuilder(indexerClosureType)), |
|
|
new XamlIlTrampolineBuilder(_sreTypeSystem.CreateTypeBuilder(trampolineBuilder))), |
|
|
new XamlIlTrampolineBuilder(_sreTypeSystem.CreateTypeBuilder(trampolineBuilder))), |
|
|
_sreEmitMappings, |
|
|
_sreEmitMappings, |
|
|
_sreContextType) { EnableIlVerification = true, DefaultCompileBindings = useCompiledBindingsByDefault }; |
|
|
_sreContextType) |
|
|
|
|
|
{ |
|
|
|
|
|
EnableIlVerification = true, |
|
|
|
|
|
DefaultCompileBindings = configuration.UseCompiledBindingsByDefault, |
|
|
|
|
|
IsDesignMode = configuration.DesignMode |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
IXamlType overrideType = null; |
|
|
var parsedDocuments = new List<XamlDocumentResource>(); |
|
|
if (rootInstance != null) |
|
|
var rootInstances = new List<object>(); |
|
|
|
|
|
|
|
|
|
|
|
foreach (var document in documents) |
|
|
{ |
|
|
{ |
|
|
overrideType = _sreTypeSystem.GetType(rootInstance.GetType()); |
|
|
string xaml; |
|
|
|
|
|
using (var sr = new StreamReader(document.XamlStream)) |
|
|
|
|
|
xaml = sr.ReadToEnd(); |
|
|
|
|
|
|
|
|
|
|
|
IXamlType overrideType = null; |
|
|
|
|
|
if (document.RootInstance != null) |
|
|
|
|
|
{ |
|
|
|
|
|
overrideType = _sreTypeSystem.GetType(document.RootInstance.GetType()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var parsed = compiler.Parse(xaml, overrideType); |
|
|
|
|
|
compiler.Transform(parsed); |
|
|
|
|
|
|
|
|
|
|
|
var xamlName = GetSafeUriIdentifier(document.BaseUri) |
|
|
|
|
|
?? document.RootInstance?.GetType().Name |
|
|
|
|
|
?? ((IXamlAstValueNode)parsed.Root).Type.GetClrType().Name; |
|
|
|
|
|
var tb = _sreBuilder.DefineType("Builder_" + Guid.NewGuid().ToString("N") + "_" + xamlName); |
|
|
|
|
|
var builder = _sreTypeSystem.CreateTypeBuilder(tb); |
|
|
|
|
|
parsedDocuments.Add(new XamlDocumentResource(parsed, document.BaseUri?.ToString(), null, null, |
|
|
|
|
|
builder, |
|
|
|
|
|
compiler.DefinePopulateMethod(builder, parsed, AvaloniaXamlIlCompiler.PopulateName, true), |
|
|
|
|
|
compiler.DefineBuildMethod(builder, parsed, AvaloniaXamlIlCompiler.BuildName, true))); |
|
|
|
|
|
rootInstances.Add(document.RootInstance); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
compiler.IsDesignMode = isDesignMode; |
|
|
compiler.TransformGroup(parsedDocuments); |
|
|
compiler.ParseAndCompile(xaml, uri?.ToString(), null, _sreTypeSystem.CreateTypeBuilder(tb), overrideType); |
|
|
|
|
|
var created = tb.CreateTypeInfo(); |
|
|
var createdTypes = parsedDocuments.Select(document => |
|
|
|
|
|
{ |
|
|
|
|
|
compiler.Compile(document.XamlDocument, document.TypeBuilder, document.PopulateMethod, |
|
|
|
|
|
document.BuildMethod, document.Uri, document.FileSource); |
|
|
|
|
|
return _sreTypeSystem.GetType(document.TypeBuilder.CreateType()); |
|
|
|
|
|
}).ToArray(); |
|
|
|
|
|
|
|
|
clrPropertyBuilder.CreateTypeInfo(); |
|
|
clrPropertyBuilder.CreateTypeInfo(); |
|
|
indexerClosureType.CreateTypeInfo(); |
|
|
indexerClosureType.CreateTypeInfo(); |
|
|
trampolineBuilder.CreateTypeInfo(); |
|
|
trampolineBuilder.CreateTypeInfo(); |
|
|
|
|
|
|
|
|
return LoadOrPopulate(created, rootInstance); |
|
|
return createdTypes.Zip(rootInstances, (l, r) => (l, r)).Select(t => LoadOrPopulate(t.Item1, t.Item2)).ToArray(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static object LoadSreCore(RuntimeXamlLoaderDocument document, RuntimeXamlLoaderConfiguration configuration) |
|
|
|
|
|
{ |
|
|
|
|
|
return LoadGroupSreCore(new[] { document }, configuration).Single(); |
|
|
} |
|
|
} |
|
|
#endif
|
|
|
#endif
|
|
|
|
|
|
|
|
|
static object LoadOrPopulate(Type created, object rootInstance) |
|
|
static object LoadOrPopulate(Type created, object rootInstance) |
|
|
{ |
|
|
{ |
|
|
var isp = Expression.Parameter(typeof(IServiceProvider)); |
|
|
var isp = Expression.Parameter(typeof(IServiceProvider)); |
|
|
|
|
|
|
|
|
@ -249,19 +305,37 @@ namespace Avalonia.Markup.Xaml.XamlIl |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public static object Load(Stream stream, Assembly localAssembly, object rootInstance, Uri uri, |
|
|
public static object Load(RuntimeXamlLoaderDocument document, RuntimeXamlLoaderConfiguration configuration) |
|
|
bool isDesignMode, bool useCompiledBindingsByDefault) |
|
|
|
|
|
{ |
|
|
{ |
|
|
|
|
|
#if RUNTIME_XAML_CECIL
|
|
|
string xaml; |
|
|
string xaml; |
|
|
using (var sr = new StreamReader(stream)) |
|
|
using (var sr = new StreamReader(document.XamlStream)) |
|
|
xaml = sr.ReadToEnd(); |
|
|
xaml = sr.ReadToEnd(); |
|
|
|
|
|
return LoadCecil(xaml, configuration.LocalAssembly, document.RootInstance,document.BaseUri, configuration.UseCompiledBindingsByDefault); |
|
|
|
|
|
#else
|
|
|
|
|
|
return LoadSre(document, configuration); |
|
|
|
|
|
#endif
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public static IReadOnlyList<object> LoadGroup(IReadOnlyCollection<RuntimeXamlLoaderDocument> documents, RuntimeXamlLoaderConfiguration configuration) |
|
|
|
|
|
{ |
|
|
#if RUNTIME_XAML_CECIL
|
|
|
#if RUNTIME_XAML_CECIL
|
|
|
return LoadCecil(xaml, localAssembly, rootInstance, uri, useCompiledBindingsByDefault); |
|
|
throw new NotImplementedException("Load group was not implemented for the Cecil backend"); |
|
|
#else
|
|
|
#else
|
|
|
return LoadSre(xaml, localAssembly, rootInstance, uri, isDesignMode, useCompiledBindingsByDefault); |
|
|
return LoadGroupSre(documents, configuration); |
|
|
#endif
|
|
|
#endif
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static string GetSafeUriIdentifier(Uri uri) |
|
|
|
|
|
{ |
|
|
|
|
|
return uri?.ToString() |
|
|
|
|
|
.Replace(":", "_") |
|
|
|
|
|
.Replace("/", "_") |
|
|
|
|
|
.Replace("?", "_") |
|
|
|
|
|
.Replace("=", "_") |
|
|
|
|
|
.Replace(".", "_"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
#if RUNTIME_XAML_CECIL
|
|
|
#if RUNTIME_XAML_CECIL
|
|
|
private static Dictionary<string, (Action<IServiceProvider, object> populate, Func<IServiceProvider, object> |
|
|
private static Dictionary<string, (Action<IServiceProvider, object> populate, Func<IServiceProvider, object> |
|
|
build)> |
|
|
build)> |
|
|
@ -303,12 +377,7 @@ namespace Avalonia.Markup.Xaml.XamlIl |
|
|
overrideType = _cecilTypeSystem.GetType(rootInstance.GetType().FullName); |
|
|
overrideType = _cecilTypeSystem.GetType(rootInstance.GetType().FullName); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
var safeUri = uri.ToString() |
|
|
var safeUri = GetSafeUriIdentifier(uri); |
|
|
.Replace(":", "_") |
|
|
|
|
|
.Replace("/", "_") |
|
|
|
|
|
.Replace("?", "_") |
|
|
|
|
|
.Replace("=", "_") |
|
|
|
|
|
.Replace(".", "_"); |
|
|
|
|
|
if (_cecilGeneratedCache.TryGetValue(safeUri, out var cached)) |
|
|
if (_cecilGeneratedCache.TryGetValue(safeUri, out var cached)) |
|
|
return LoadOrPopulate(cached, rootInstance); |
|
|
return LoadOrPopulate(cached, rootInstance); |
|
|
|
|
|
|
|
|
@ -335,7 +404,7 @@ namespace Avalonia.Markup.Xaml.XamlIl |
|
|
{ |
|
|
{ |
|
|
DefaultCompileBindings = useCompiledBindingsByDefault |
|
|
DefaultCompileBindings = useCompiledBindingsByDefault |
|
|
}; |
|
|
}; |
|
|
compiler.ParseAndCompile(xaml, uri.ToString(), tb, overrideType); |
|
|
compiler.ParseAndCompile(xaml, uri.ToString(), null, tb, overrideType); |
|
|
var asmPath = Path.Combine(_cecilEmitDir, safeUri + ".dll"); |
|
|
var asmPath = Path.Combine(_cecilEmitDir, safeUri + ".dll"); |
|
|
using(var f = File.Create(asmPath)) |
|
|
using(var f = File.Create(asmPath)) |
|
|
asm.Write(f); |
|
|
asm.Write(f); |
|
|
|