|
@@ -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 = tb.DefineNestedType("ClrProperties_" + Guid.NewGuid().ToString("N"));
|
|
|
|
|
|
+ var clrPropertyBuilder = _sreBuilder.DefineType("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,
|
|
|
|
- new XamlIlClrPropertyInfoEmitter(_sreTypeSystem.CreateTypeBuilder(clrPropertyBuilder)),
|
|
|
|
- new XamlIlPropertyInfoAccessorFactoryEmitter(_sreTypeSystem.CreateTypeBuilder(indexerClosureType)),
|
|
|
|
- new XamlIlTrampolineBuilder(_sreTypeSystem.CreateTypeBuilder(trampolineBuilder))),
|
|
|
|
|
|
+ _sreMappings, _sreXmlns, AvaloniaXamlIlLanguage.CustomValueConverter,
|
|
|
|
+ new XamlIlClrPropertyInfoEmitter(_sreTypeSystem.CreateTypeBuilder(clrPropertyBuilder)),
|
|
|
|
+ new XamlIlPropertyInfoAccessorFactoryEmitter(_sreTypeSystem.CreateTypeBuilder(indexerClosureType)),
|
|
|
|
+ new XamlIlTrampolineBuilder(_sreTypeSystem.CreateTypeBuilder(trampolineBuilder))),
|
|
_sreEmitMappings,
|
|
_sreEmitMappings,
|
|
- _sreContextType) { EnableIlVerification = true, DefaultCompileBindings = useCompiledBindingsByDefault };
|
|
|
|
|
|
+ _sreContextType)
|
|
|
|
+ {
|
|
|
|
+ EnableIlVerification = true,
|
|
|
|
+ DefaultCompileBindings = configuration.UseCompiledBindingsByDefault,
|
|
|
|
+ IsDesignMode = configuration.DesignMode
|
|
|
|
+ };
|
|
|
|
|
|
- IXamlType overrideType = null;
|
|
|
|
- if (rootInstance != null)
|
|
|
|
|
|
+ var parsedDocuments = new List<XamlDocumentResource>();
|
|
|
|
+ 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.ParseAndCompile(xaml, uri?.ToString(), null, _sreTypeSystem.CreateTypeBuilder(tb), overrideType);
|
|
|
|
- var created = tb.CreateTypeInfo();
|
|
|
|
|
|
+ compiler.TransformGroup(parsedDocuments);
|
|
|
|
+
|
|
|
|
+ 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,
|
|
|
|
- bool isDesignMode, bool useCompiledBindingsByDefault)
|
|
|
|
|
|
+ public static object Load(RuntimeXamlLoaderDocument document, RuntimeXamlLoaderConfiguration configuration)
|
|
{
|
|
{
|
|
|
|
+#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()
|
|
|
|
- .Replace(":", "_")
|
|
|
|
- .Replace("/", "_")
|
|
|
|
- .Replace("?", "_")
|
|
|
|
- .Replace("=", "_")
|
|
|
|
- .Replace(".", "_");
|
|
|
|
|
|
+ var safeUri = GetSafeUriIdentifier(uri);
|
|
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);
|