From 4cb2e891252b06a689b33b8c84287cfb93de6bd8 Mon Sep 17 00:00:00 2001 From: Dominique Schuppli Date: Wed, 17 Dec 2025 21:42:49 +0100 Subject: [PATCH 1/8] Remove redundant `AssignArgumentStatement` ... which only works correctly for by-refs and with `DefaultValue- Expression` --- .../SimpleAST/AssignArgumentStatement.cs | 38 ------------------- .../SimpleAST/DefaultValueExpression.cs | 24 +----------- .../Generators/MinimalisticMethodGenerator.cs | 8 ++-- .../OptionallyForwardingMethodGenerator.cs | 6 ++- 4 files changed, 10 insertions(+), 66 deletions(-) delete mode 100644 src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignArgumentStatement.cs diff --git a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignArgumentStatement.cs b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignArgumentStatement.cs deleted file mode 100644 index 2967821031..0000000000 --- a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignArgumentStatement.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2004-2025 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#nullable enable - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System.Reflection.Emit; - - internal class AssignArgumentStatement : IStatement - { - private readonly ArgumentReference argument; - private readonly IExpression expression; - - public AssignArgumentStatement(ArgumentReference argument, IExpression expression) - { - this.argument = argument; - this.expression = expression; - } - - public void Emit(ILGenerator gen) - { - argument.Emit(gen); - expression.Emit(gen); - } - } -} \ No newline at end of file diff --git a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/DefaultValueExpression.cs b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/DefaultValueExpression.cs index c4668cf208..177c731485 100644 --- a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/DefaultValueExpression.cs +++ b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/DefaultValueExpression.cs @@ -1,4 +1,4 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// Copyright 2004-2025 Castle Project - http://www.castleproject.org/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -42,34 +42,12 @@ public void Emit(ILGenerator gen) gen.Emit(OpCodes.Initobj, type); gen.Emit(OpCodes.Ldloc, local); } - else if (type.IsByRef) - { - EmitByRef(gen); - } else { throw new NotImplementedException("Can't emit default value for type " + type); } } - private void EmitByRef(ILGenerator gen) - { - var elementType = type.GetElementType(); - if (IsPrimitiveOrClass(elementType)) - { - OpCodeUtil.EmitLoadOpCodeForDefaultValueOfType(gen, elementType); - OpCodeUtil.EmitStoreIndirectOpCodeForType(gen, elementType); - } - else if (elementType.IsGenericParameter || elementType.IsValueType) - { - gen.Emit(OpCodes.Initobj, elementType); - } - else - { - throw new NotImplementedException("Can't emit default value for reference of type " + elementType); - } - } - private bool IsPrimitiveOrClass(Type type) { if (type.IsPrimitive && type != typeof(IntPtr) && type != typeof(UIntPtr)) diff --git a/src/Castle.Core/DynamicProxy/Generators/MinimalisticMethodGenerator.cs b/src/Castle.Core/DynamicProxy/Generators/MinimalisticMethodGenerator.cs index 965ea8e78e..3b70fb86cd 100644 --- a/src/Castle.Core/DynamicProxy/Generators/MinimalisticMethodGenerator.cs +++ b/src/Castle.Core/DynamicProxy/Generators/MinimalisticMethodGenerator.cs @@ -1,4 +1,4 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// Copyright 2004-2025 Castle Project - http://www.castleproject.org/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -52,8 +52,10 @@ private void InitOutParameters(MethodEmitter emitter, ParameterInfo[] parameters if (parameter.IsOut) { emitter.CodeBuilder.AddStatement( - new AssignArgumentStatement(new ArgumentReference(parameter.ParameterType, index + 1), - new DefaultValueExpression(parameter.ParameterType))); + new AssignStatement( + new IndirectReference( + new ArgumentReference(parameter.ParameterType, index + 1)), + new DefaultValueExpression(parameter.ParameterType.GetElementType()))); } } } diff --git a/src/Castle.Core/DynamicProxy/Generators/OptionallyForwardingMethodGenerator.cs b/src/Castle.Core/DynamicProxy/Generators/OptionallyForwardingMethodGenerator.cs index 9ae81f7d2e..86359be053 100644 --- a/src/Castle.Core/DynamicProxy/Generators/OptionallyForwardingMethodGenerator.cs +++ b/src/Castle.Core/DynamicProxy/Generators/OptionallyForwardingMethodGenerator.cs @@ -84,8 +84,10 @@ private void InitOutParameters(BlockStatement statements, ParameterInfo[] parame if (parameter.IsOut) { statements.AddStatement( - new AssignArgumentStatement(new ArgumentReference(parameter.ParameterType, index + 1), - new DefaultValueExpression(parameter.ParameterType))); + new AssignStatement( + new IndirectReference( + new ArgumentReference(parameter.ParameterType, index + 1)), + new DefaultValueExpression(parameter.ParameterType.GetElementType()))); } } } From 7a9f5fccb5f34dfe781913d9709d22d471d610df Mon Sep 17 00:00:00 2001 From: Dominique Schuppli Date: Wed, 17 Dec 2025 22:26:41 +0100 Subject: [PATCH 2/8] Remove sequential coupling in `LocalReference` --- .../Generators/Emitters/CodeBuilder.cs | 13 ++----------- .../Emitters/SimpleAST/LocalReference.cs | 18 +++++++++--------- .../Generators/Emitters/SimpleAST/Reference.cs | 4 ---- 3 files changed, 11 insertions(+), 24 deletions(-) diff --git a/src/Castle.Core/DynamicProxy/Generators/Emitters/CodeBuilder.cs b/src/Castle.Core/DynamicProxy/Generators/Emitters/CodeBuilder.cs index 606e975431..4fdfd646ca 100644 --- a/src/Castle.Core/DynamicProxy/Generators/Emitters/CodeBuilder.cs +++ b/src/Castle.Core/DynamicProxy/Generators/Emitters/CodeBuilder.cs @@ -1,4 +1,4 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// Copyright 2004-2025 Castle Project - http://www.castleproject.org/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -22,14 +22,12 @@ namespace Castle.DynamicProxy.Generators.Emitters internal sealed class CodeBuilder { - private readonly List locals; private readonly List statements; private bool isEmpty; public CodeBuilder() { statements = new List(); - locals = new List(); isEmpty = true; } @@ -47,18 +45,11 @@ public CodeBuilder AddStatement(IStatement statement) public LocalReference DeclareLocal(Type type) { - var local = new LocalReference(type); - locals.Add(local); - return local; + return new LocalReference(type); } internal void Generate(ILGenerator il) { - foreach (var local in locals) - { - local.Generate(il); - } - foreach (var statement in statements) { statement.Emit(il); diff --git a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LocalReference.cs b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LocalReference.cs index 450a69c57e..1c848d0153 100644 --- a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LocalReference.cs +++ b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LocalReference.cs @@ -23,32 +23,32 @@ namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST [DebuggerDisplay("local {Type}")] internal class LocalReference : Reference { - private LocalBuilder? localBuilder; + private LocalBuilder? local; public LocalReference(Type type) : base(type) { } - public override void Generate(ILGenerator gen) - { - localBuilder = gen.DeclareLocal(base.Type); - } - public override void EmitAddress(ILGenerator gen) { - gen.Emit(OpCodes.Ldloca, localBuilder!); + gen.Emit(OpCodes.Ldloca, GetInitializedLocal(gen)); } public override void Emit(ILGenerator gen) { - gen.Emit(OpCodes.Ldloc, localBuilder!); + gen.Emit(OpCodes.Ldloc, GetInitializedLocal(gen)); } public override void EmitStore(IExpression value, ILGenerator gen) { value.Emit(gen); - gen.Emit(OpCodes.Stloc, localBuilder!); + gen.Emit(OpCodes.Stloc, GetInitializedLocal(gen)); + } + + private LocalBuilder GetInitializedLocal(ILGenerator gen) + { + return local ??= gen.DeclareLocal(Type); } } } \ No newline at end of file diff --git a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/Reference.cs b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/Reference.cs index 168f603570..ead6764529 100644 --- a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/Reference.cs +++ b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/Reference.cs @@ -38,9 +38,5 @@ public Type Type public abstract void Emit(ILGenerator gen); public abstract void EmitStore(IExpression value, ILGenerator gen); - - public virtual void Generate(ILGenerator gen) - { - } } } \ No newline at end of file From e677ee08456cc4a82791339172ed1c3bb3851b41 Mon Sep 17 00:00:00 2001 From: Dominique Schuppli Date: Wed, 17 Dec 2025 22:32:46 +0100 Subject: [PATCH 3/8] Simplify `ReturnStatement` --- .../Emitters/SimpleAST/ReturnStatement.cs | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReturnStatement.cs b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReturnStatement.cs index c913945d1f..cd2bb40b17 100644 --- a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReturnStatement.cs +++ b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReturnStatement.cs @@ -21,17 +21,11 @@ namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST internal class ReturnStatement : IStatement { private readonly IExpression? expression; - private readonly Reference? reference; public ReturnStatement() { } - public ReturnStatement(Reference reference) - { - this.reference = reference; - } - public ReturnStatement(IExpression expression) { this.expression = expression; @@ -39,15 +33,7 @@ public ReturnStatement(IExpression expression) public void Emit(ILGenerator gen) { - if (reference != null) - { - reference.Emit(gen); - } - else if (expression != null) - { - expression.Emit(gen); - } - + expression?.Emit(gen); gen.Emit(OpCodes.Ret); } } From c3b95f32fb3d7a439e842df623fab97c9cbc64bc Mon Sep 17 00:00:00 2001 From: Dominique Schuppli Date: Wed, 17 Dec 2025 22:36:56 +0100 Subject: [PATCH 4/8] `AsTypeExpression` can operate on expressions --- .../Generators/Emitters/SimpleAST/AsTypeExpression.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AsTypeExpression.cs b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AsTypeExpression.cs index 003e83d655..f4984690ea 100644 --- a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AsTypeExpression.cs +++ b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AsTypeExpression.cs @@ -20,21 +20,21 @@ namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST using System.Diagnostics; using System.Reflection.Emit; - [DebuggerDisplay("{reference} as {type}")] + [DebuggerDisplay("{expression} as {type}")] internal class AsTypeExpression : IExpression { - private readonly Reference reference; + private readonly IExpression expression; private readonly Type type; - public AsTypeExpression(Reference reference, Type type) + public AsTypeExpression(IExpression expression, Type type) { - this.reference = reference; + this.expression = expression; this.type = type; } public void Emit(ILGenerator gen) { - reference.Emit(gen); + expression.Emit(gen); gen.Emit(OpCodes.Isinst, type); } } From dcb941602f8a4d0499af34932e1ac5e973dfe7db Mon Sep 17 00:00:00 2001 From: Dominique Schuppli Date: Wed, 17 Dec 2025 22:50:23 +0100 Subject: [PATCH 5/8] More correct param name for `NewArrayExpression` --- .../Emitters/SimpleAST/NewArrayExpression.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NewArrayExpression.cs b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NewArrayExpression.cs index e6a2524c9f..e4f35a2821 100644 --- a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NewArrayExpression.cs +++ b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NewArrayExpression.cs @@ -1,4 +1,4 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// Copyright 2004-2025 Castle Project - http://www.castleproject.org/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -19,19 +19,19 @@ namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST internal class NewArrayExpression : IExpression { - private readonly Type arrayType; + private readonly Type elementType; private readonly int size; - public NewArrayExpression(int size, Type arrayType) + public NewArrayExpression(int size, Type elementType) { this.size = size; - this.arrayType = arrayType; + this.elementType = elementType; } public void Emit(ILGenerator gen) { gen.Emit(OpCodes.Ldc_I4, size); - gen.Emit(OpCodes.Newarr, arrayType); + gen.Emit(OpCodes.Newarr, elementType); } } } \ No newline at end of file From c22408a8ffc9ee4cff5ec35149ef145f3d37bea8 Mon Sep 17 00:00:00 2001 From: Dominique Schuppli Date: Wed, 17 Dec 2025 22:51:34 +0100 Subject: [PATCH 6/8] Remove unnecessary `IfNullExpression` ctor overload --- .../Emitters/SimpleAST/IfNullExpression.cs | 20 ++----------------- 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IfNullExpression.cs b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IfNullExpression.cs index 470ea9af7f..cb2ad00de7 100644 --- a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IfNullExpression.cs +++ b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IfNullExpression.cs @@ -23,15 +23,7 @@ internal class IfNullExpression : IExpression, IStatement { private readonly IExpressionOrStatement ifNotNull; private readonly IExpressionOrStatement ifNull; - private readonly Reference? reference; - private readonly IExpression? expression; - - public IfNullExpression(Reference reference, IExpressionOrStatement ifNull, IExpressionOrStatement ifNotNull = null) - { - this.reference = reference ?? throw new ArgumentNullException(nameof(reference)); - this.ifNull = ifNull; - this.ifNotNull = ifNotNull; - } + private readonly IExpression expression; public IfNullExpression(IExpression expression, IExpressionOrStatement ifNull, IExpressionOrStatement ifNotNull = null) { @@ -42,15 +34,7 @@ public IfNullExpression(IExpression expression, IExpressionOrStatement ifNull, I public void Emit(ILGenerator gen) { - if (reference != null) - { - reference.Emit(gen); - } - else if (expression != null) - { - expression.Emit(gen); - } - + expression.Emit(gen); var notNull = gen.DefineLabel(); gen.Emit(OpCodes.Brtrue_S, notNull); ifNull.Emit(gen); From 64e394df6059bc65aff8b9e1859d41aa2a47ed51 Mon Sep 17 00:00:00 2001 From: Dominique Schuppli Date: Thu, 18 Dec 2025 00:46:40 +0100 Subject: [PATCH 7/8] Update `[DebuggerDisplay]` & XML doc comment of `IndirectReference` --- .../Generators/Emitters/SimpleAST/IndirectReference.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IndirectReference.cs b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IndirectReference.cs index 8865d99705..3cc727401f 100644 --- a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IndirectReference.cs +++ b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IndirectReference.cs @@ -22,10 +22,11 @@ namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST using System.Reflection.Emit; /// - /// Wraps a reference that is passed - /// ByRef and provides indirect load/store support. + /// Represents the storage location X referenced by a + /// holding a managed pointer ("by-ref") &X to it. + /// It essentially has the same function as the pointer indirection / dereferencing operator *. /// - [DebuggerDisplay("&{OwnerReference}")] + [DebuggerDisplay("*{byRefReference}")] internal class IndirectReference : Reference { private readonly Reference byRefReference; From 0ab422123658ef72d5de623f5adc38ae8bd2dcba Mon Sep 17 00:00:00 2001 From: Dominique Schuppli Date: Thu, 18 Dec 2025 00:48:35 +0100 Subject: [PATCH 8/8] Fix `FieldRefernce`'s `[DebuggerDisplay]` --- .../Generators/Emitters/SimpleAST/FieldReference.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/FieldReference.cs b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/FieldReference.cs index 3ba3d8a902..476ac9c395 100644 --- a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/FieldReference.cs +++ b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/FieldReference.cs @@ -20,7 +20,7 @@ namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST using System.Reflection; using System.Reflection.Emit; - [DebuggerDisplay("{fieldBuilder.Name} ({fieldBuilder.FieldType})")] + [DebuggerDisplay("{field.Name} ({field.FieldType})")] internal class FieldReference : Reference { private readonly FieldInfo field;