public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) { var exts = context.Configuration.TypeSystem.GetType("Avalonia.Controls.NameScopeExtensions"); var findNameScope = exts.FindMethod(m => m.Name == "FindNameScope"); var registerMethod = findNameScope.ReturnType.FindMethod(m => m.Name == "Register"); using (var targetLoc = context.GetLocal(context.Configuration.WellKnownTypes.Object)) using (var nameScopeLoc = context.GetLocal(findNameScope.ReturnType)) { var exit = codeGen.DefineLabel(); codeGen // var target = {pop} .Stloc(targetLoc.Local) // var scope = target.FindNameScope() .Ldloc(targetLoc.Local) .Castclass(findNameScope.Parameters[0]) .EmitCall(findNameScope) .Stloc(nameScopeLoc.Local) // if({scope} != null) goto call; .Ldloc(nameScopeLoc.Local) .Brfalse(exit) .Ldloc(nameScopeLoc.Local); context.Emit(Value, codeGen, Value.Type.GetClrType()); codeGen .Ldloc(targetLoc.Local) .EmitCall(registerMethod) .MarkLabel(exit); } return(XamlIlNodeEmitResult.Void(1)); }
public void Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen, bool swallowResult) { int firstCast = -1; for (var c = ParametersWithThis.Count - 1; c >= 0; c--) { if (!_method.ParametersWithThis[c].Equals(ParametersWithThis[c])) { firstCast = c; } } if (firstCast != -1) { var locals = new Stack <XamlIlEmitContext.PooledLocal>(); for (var c = ParametersWithThis.Count - 1; c >= firstCast; c--) { codeGen.Castclass(ParametersWithThis[c]); if (c > firstCast) { var l = context.GetLocal(ParametersWithThis[c]); codeGen.Stloc(l.Local); locals.Push(l); } } while (locals.Count != 0) { using (var l = locals.Pop()) codeGen.Ldloc(l.Local); } } _method.Emit(context, codeGen, swallowResult); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlEmitter codeGen) { if (!(node is XamlIlObjectInitializationNode init)) { return(null); } var supportInitType = context.Configuration.TypeMappings.SupportInitialize; var supportsInitialize = supportInitType != null && context.Configuration.TypeMappings.SupportInitialize .IsAssignableFrom(init.Type); if (supportsInitialize) { codeGen // We need a copy for/EndInit .Emit(OpCodes.Dup); if (!init.SkipBeginInit) { codeGen .Emit(OpCodes.Dup) .EmitCall(supportInitType.FindMethod(m => m.Name == "BeginInit")); } } var addToParentStack = context.RuntimeContext.ParentListField != null && !init.Type.IsValueType && context.GetOrCreateItem <XamlIlNeedsParentStackCache>().NeedsParentStack(node); if (addToParentStack) { using (var local = context.GetLocal(init.Type)) codeGen .Stloc(local.Local) .Ldloc(context.ContextLocal) .Ldloc(local.Local) .EmitCall(context.RuntimeContext.PushParentMethod) .Ldloc(local.Local); } context.Emit(init.Manipulation, codeGen, null); if (addToParentStack) { codeGen .Ldloc(context.ContextLocal) .EmitCall(context.RuntimeContext.PopParentMethod, true); } if (supportsInitialize) { codeGen .EmitCall(supportInitType.FindMethod(m => m.Name == "EndInit")); } return(XamlIlNodeEmitResult.Void(1)); }
void CompileBuilder(XamlIlEmitContext context) { var il = context.Emitter; // Initialize the context il .Ldarg_0(); context.RuntimeContext.Factory(il); il.Stloc(context.ContextLocal); // It might be better to save this in a closure if (context.Configuration.TypeMappings.RootObjectProvider != null) { // Attempt to get the root object from parent service provider var noRoot = il.DefineLabel(); using (var loc = context.GetLocal(context.Configuration.WellKnownTypes.Object)) il // if(arg == null) goto noRoot; .Ldarg_0() .Brfalse(noRoot) // var loc = arg.GetService(typeof(IRootObjectProvider)) .Ldarg_0() .Ldtype(context.Configuration.TypeMappings.RootObjectProvider) .EmitCall(context.Configuration.TypeMappings.ServiceProvider .FindMethod(m => m.Name == "GetService")) .Stloc(loc.Local) // if(loc == null) goto noRoot; .Ldloc(loc.Local) .Brfalse(noRoot) // loc = ((IRootObjectProvider)loc).RootObject .Ldloc(loc.Local) .Castclass(context.Configuration.TypeMappings.RootObjectProvider) .EmitCall(context.Configuration.TypeMappings.RootObjectProvider .FindMethod(m => m.Name == "get_RootObject")) .Stloc(loc.Local) // contextLocal.RootObject = loc; .Ldloc(context.ContextLocal) .Ldloc(loc.Local) .Castclass(context.RuntimeContext.ContextType.GenericArguments[0]) .Stfld(context.RuntimeContext.RootObjectField) .MarkLabel(noRoot); } context.Emit(Value, context.Emitter, context.Configuration.WellKnownTypes.Object); il.Ret(); }
public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) { var scopeField = context.RuntimeContext.ContextType.Fields.First(f => f.Name == AvaloniaXamlIlLanguage.ContextNameScopeFieldName); using (var targetLoc = context.GetLocal(context.Configuration.WellKnownTypes.Object)) { codeGen // var target = {pop} .Stloc(targetLoc.Local) // _context.NameScope.Register(Name, target) .Ldloc(context.ContextLocal) .Ldfld(scopeField); context.Emit(Name, codeGen, Name.Type.GetClrType()); codeGen .Ldloc(targetLoc.Local) .EmitCall(_types.INameScopeRegister, true); } return(XamlIlNodeEmitResult.Void(1)); }
public static void EmitConvert(XamlIlEmitContext context, IXamlIlLineInfo node, IXamlIlType what, IXamlIlType to, Func <bool, IXamlIlEmitter> ld) { if (what.Equals(to)) { ld(false); } else if (what == XamlIlPseudoType.Null) { if (to.IsValueType) { if (to.GenericTypeDefinition?.Equals(context.Configuration.WellKnownTypes.NullableT) == true) { using (var loc = context.GetLocal(to)) ld(false) .Pop() .Ldloca(loc.Local) .Emit(OpCodes.Initobj, to) .Ldloc(loc.Local); } else { throw new XamlIlLoadException("Unable to convert {x:Null} to " + to.GetFqn(), node); } } else { ld(false); } } else if (what.IsValueType && to.IsValueType) { if (to.IsNullableOf(what)) { ld(false).Emit(OpCodes.Newobj, to.Constructors.First(c => c.Parameters.Count == 1 && c.Parameters[0].Equals(what))); } else if (what.IsNullableOf(what)) { ld(true) .EmitCall(what.FindMethod(m => m.Name == "get_Value")); } else { throw new XamlIlLoadException( $"Don't know how to convert value type {what.GetFullName()} to value type {to.GetFullName()}", node); } } else if (!to.IsValueType && what.IsValueType) { if (!to.IsAssignableFrom(what)) { throw new XamlIlLoadException( $"Don't know how to convert value type {what.GetFullName()} to reference type {to.GetFullName()}", node); } ld(false).Box(what); } else if (to.IsValueType && !what.IsValueType) { if (!(what.Namespace == "System" && what.Name == "Object")) { throw new XamlIlLoadException( $"Don't know how to convert reference type {what.GetFullName()} to value type {to.GetFullName()}", node); } ld(false).Unbox_Any(to); } else { if (to.IsAssignableFrom(what)) { // Downcast, always safe ld(false); } else if (what.IsInterface || what.IsAssignableFrom(to)) { // Upcast or cast from interface, might throw InvalidCastException ld(false).Emit(OpCodes.Castclass, to); } else { // Types are completely unrelated, e. g. string to List<int> conversion attempt throw new XamlIlLoadException( $"Don't know how to convert reference type {what.GetFullName()} to reference type {to.GetFullName()}", node); } } }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlEmitter codeGen) { if (!(node is XamlIlObjectInitializationNode init)) { return(null); } var supportInitType = context.Configuration.TypeMappings.SupportInitialize; var supportsInitialize = supportInitType != null && context.Configuration.TypeMappings.SupportInitialize .IsAssignableFrom(init.Type); if (supportsInitialize) { codeGen // We need a copy for/EndInit .Emit(OpCodes.Dup); if (!init.SkipBeginInit) { codeGen .Emit(OpCodes.Dup) .EmitCall(supportInitType.FindMethod(m => m.Name == "BeginInit")); } } IXamlIlType objectListType = null; var addToParentStack = context.RuntimeContext.ParentListField != null && !init.Type.IsValueType && context.GetOrCreateItem <XamlIlNeedsParentStackCache>().NeedsParentStack(node); if (addToParentStack) { objectListType = context.Configuration.TypeSystem.GetType("System.Collections.Generic.List`1") .MakeGenericType(new[] { context.Configuration.WellKnownTypes.Object }); using (var local = context.GetLocal(init.Type)) codeGen .Stloc(local.Local) .Ldloc(context.ContextLocal).Ldfld(context.RuntimeContext.ParentListField) .Ldloc(local.Local) .EmitCall(objectListType.FindMethod("Add", context.Configuration.WellKnownTypes.Void, false, context.Configuration.WellKnownTypes.Object)) .Ldloc(local.Local); } context.Emit(init.Manipulation, codeGen, null); if (addToParentStack) { codeGen .Ldloc(context.ContextLocal).Ldfld(context.RuntimeContext.ParentListField) .Ldloc(context.ContextLocal).Ldfld(context.RuntimeContext.ParentListField) .EmitCall(objectListType.FindMethod(m => m.Name == "get_Count")) .Ldc_I4(1).Emit(OpCodes.Sub) .EmitCall(objectListType.FindMethod(m => m.Name == "RemoveAt")); } if (supportsInitialize) { codeGen .EmitCall(supportInitType.FindMethod(m => m.Name == "EndInit")); } return(XamlIlNodeEmitResult.Void(1)); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlEmitter codeGen) { if (!(node is XamlIlMarkupExtensionNode me)) { return(null); } XamlIlNeedsParentStackCache.Verify(context, node); var ilgen = codeGen; var so = context.Configuration.WellKnownTypes.Object; var ptype = me.Manipulation?.ParametersWithThis[1] ?? me.Property.PropertyType; var rtype = me.ProvideValue?.ReturnType ?? me.Value.Type.GetClrType(); var needProvideValueTarget = me.ProvideValue != null && me.ProvideValue.Parameters.Count != 0 && context.RuntimeContext.PropertyTargetObject != null && me.Property != null; void EmitPropertyDescriptor() { if (me.Property == null) { ilgen.Ldnull(); } else if (context.Configuration.TypeMappings.ProvideValueTargetPropertyEmitter ?.Invoke(context, codeGen, me.Property) == true) { return; } else if (me.Property is XamlIlAstAttachedProperty) { ilgen.Ldtoken(me.Property.Getter ?? me.Property.Setter) .Emit(OpCodes.Box, context.Configuration.TypeSystem.GetType("System.RuntimeMethodHandle")); } else { ilgen.Ldstr(me.Property?.Name); } } using (var resultLocalContainer = context.GetLocal(rtype)) { var resultLocal = resultLocalContainer.Local; using (var targetObjectLocal = needProvideValueTarget ? context.GetLocal(so) : null) { if (needProvideValueTarget) { ilgen .Dup().Stloc(targetObjectLocal.Local); } context.Emit(me.Value, codeGen, me.Value.Type.GetClrType()); if (me.ProvideValue?.Parameters.Count > 0) { ilgen .Emit(OpCodes.Ldloc, context.ContextLocal); } if (needProvideValueTarget) { ilgen .Ldloc(context.ContextLocal) .Ldloc(targetObjectLocal.Local) .Stfld(context.RuntimeContext.PropertyTargetObject) .Ldloc(context.ContextLocal); EmitPropertyDescriptor(); ilgen .Stfld(context.RuntimeContext.PropertyTargetProperty); } if (me.ProvideValue != null) { ilgen .Emit(OpCodes.Call, me.ProvideValue); } ilgen .Emit(OpCodes.Stloc, resultLocal); if (needProvideValueTarget) { ilgen .Ldloc(context.ContextLocal) .Ldnull() .Stfld(context.RuntimeContext.PropertyTargetObject) .Ldloc(context.ContextLocal) .Ldnull() .Stfld(context.RuntimeContext.PropertyTargetProperty); } } // At this point we have the target object at the top of the stack and markup extension result in resultLocal var exit = ilgen.DefineLabel(); // This is needed for custom conversions of Binding to object var customTypes = context.Configuration.TypeMappings.MarkupExtensionCustomResultTypes; // This is needed for properties that accept Binding if ( me.Property != null && context.Configuration.TypeMappings.ShouldIgnoreMarkupExtensionCustomResultForProperty != null) { customTypes = customTypes.Where(ct => !context.Configuration.TypeMappings .ShouldIgnoreMarkupExtensionCustomResultForProperty(me.Property, ct)) .ToList(); } if (customTypes.Any() && !rtype.IsValueType) { void EmitCustomActionCall() { EmitPropertyDescriptor(); codeGen .Emit(OpCodes.Ldloc, context.ContextLocal) .Emit(OpCodes.Ldloc, resultLocal); if (rtype.IsValueType) { codeGen.Emit(OpCodes.Box, rtype); } codeGen .Emit(OpCodes.Call, context.Configuration.TypeMappings.MarkupExtensionCustomResultHandler) .Emit(OpCodes.Br, exit); } // Skip conversion attempts and call custom conversion directly if (customTypes.Any(ct => ct.IsAssignableFrom(rtype))) { EmitCustomActionCall(); ilgen.MarkLabel(exit); return(XamlIlNodeEmitResult.Void(1)); } var callCustomLabel = ilgen.DefineLabel(); var afterCustomLabel = ilgen.DefineLabel(); foreach (var ct in customTypes) { codeGen .Ldloc(resultLocal) .Isinst(ct) .Brtrue(callCustomLabel); } ilgen .Br(afterCustomLabel) .MarkLabel(callCustomLabel); EmitCustomActionCall(); ilgen.MarkLabel(afterCustomLabel); } TypeSystemHelpers.EmitConvert(context, node, rtype, ptype, lda => ilgen.Emit(lda ? OpCodes.Ldloca : OpCodes.Ldloc, resultLocal)); // Call some method either on the target or on target's property if (me.Manipulation != null) { // {target}.{Property}.{Method)(res) if (me.Property != null) { using (var res = context.GetLocal(ptype)) ilgen .Emit(OpCodes.Stloc, res.Local) .EmitCall(me.Property.Getter) .Emit(OpCodes.Ldloc, res.Local); } me.Manipulation.Emit(context, ilgen, true); } // Call property setter on the target else { ilgen.EmitCall(me.Property.Setter); } ilgen.MarkLabel(exit); } return(XamlIlNodeEmitResult.Void(1)); }