From 16b2b3eea8a37a97ae147072c9fbfac7388cd1c1 Mon Sep 17 00:00:00 2001 From: Dominique Schuppli Date: Wed, 17 Dec 2025 00:19:12 +0100 Subject: [PATCH 1/4] `getTargetExpression` and `getTargetReference` delegates can be merged --- .../DynamicProxy/Contributors/Delegates.cs | 2 -- ...erfaceProxyWithOptionalTargetContributor.cs | 10 +++------- .../InterfaceProxyWithoutTargetContributor.cs | 6 +++--- .../Generators/ForwardingMethodGenerator.cs | 12 ++++++------ ...terfaceProxyWithTargetInterfaceGenerator.cs | 9 ++------- .../OptionallyForwardingMethodGenerator.cs | 18 +++++++++--------- 6 files changed, 23 insertions(+), 34 deletions(-) diff --git a/src/Castle.Core/DynamicProxy/Contributors/Delegates.cs b/src/Castle.Core/DynamicProxy/Contributors/Delegates.cs index 60a64d6173..ffab3c2e37 100644 --- a/src/Castle.Core/DynamicProxy/Contributors/Delegates.cs +++ b/src/Castle.Core/DynamicProxy/Contributors/Delegates.cs @@ -23,6 +23,4 @@ internal delegate MethodEmitter OverrideMethodDelegate( string name, MethodAttributes attributes, MethodInfo methodToOverride); internal delegate IExpression GetTargetExpressionDelegate(ClassEmitter @class, MethodInfo method); - - internal delegate Reference GetTargetReferenceDelegate(ClassEmitter @class, MethodInfo method); } \ No newline at end of file diff --git a/src/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithOptionalTargetContributor.cs b/src/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithOptionalTargetContributor.cs index 858a6fb205..26feb983d3 100644 --- a/src/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithOptionalTargetContributor.cs +++ b/src/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithOptionalTargetContributor.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,13 +19,9 @@ namespace Castle.DynamicProxy.Contributors internal class InterfaceProxyWithOptionalTargetContributor : InterfaceProxyWithoutTargetContributor { - private readonly GetTargetReferenceDelegate getTargetReference; - - public InterfaceProxyWithOptionalTargetContributor(INamingScope namingScope, GetTargetExpressionDelegate getTarget, - GetTargetReferenceDelegate getTargetReference) + public InterfaceProxyWithOptionalTargetContributor(INamingScope namingScope, GetTargetExpressionDelegate getTarget) : base(namingScope, getTarget) { - this.getTargetReference = getTargetReference; canChangeTarget = true; } @@ -34,7 +30,7 @@ protected override MethodGenerator GetMethodGenerator(MetaMethod method, ClassEm { if (!method.Proxyable) { - return new OptionallyForwardingMethodGenerator(method, overrideMethod, getTargetReference); + return new OptionallyForwardingMethodGenerator(method, overrideMethod, getTarget); } return base.GetMethodGenerator(method, @class, overrideMethod); diff --git a/src/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithoutTargetContributor.cs b/src/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithoutTargetContributor.cs index aa465956da..d3eca51ad7 100644 --- a/src/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithoutTargetContributor.cs +++ b/src/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithoutTargetContributor.cs @@ -26,13 +26,13 @@ namespace Castle.DynamicProxy.Contributors internal class InterfaceProxyWithoutTargetContributor : CompositeTypeContributor { - private readonly GetTargetExpressionDelegate getTargetExpression; + protected readonly GetTargetExpressionDelegate getTarget; protected bool canChangeTarget = false; public InterfaceProxyWithoutTargetContributor(INamingScope namingScope, GetTargetExpressionDelegate getTarget) : base(namingScope) { - getTargetExpression = getTarget; + this.getTarget = getTarget; } protected override IEnumerable GetCollectors() @@ -56,7 +56,7 @@ protected override MethodGenerator GetMethodGenerator(MetaMethod method, ClassEm return new MethodWithInvocationGenerator(method, @class.GetField("__interceptors"), invocation, - getTargetExpression, + getTarget, overrideMethod, null); } diff --git a/src/Castle.Core/DynamicProxy/Generators/ForwardingMethodGenerator.cs b/src/Castle.Core/DynamicProxy/Generators/ForwardingMethodGenerator.cs index 6b7364f6e5..769b0cffe3 100644 --- a/src/Castle.Core/DynamicProxy/Generators/ForwardingMethodGenerator.cs +++ b/src/Castle.Core/DynamicProxy/Generators/ForwardingMethodGenerator.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. @@ -20,24 +20,24 @@ namespace Castle.DynamicProxy.Generators internal class ForwardingMethodGenerator : MethodGenerator { - private readonly GetTargetReferenceDelegate getTargetReference; + private readonly GetTargetExpressionDelegate getTarget; public ForwardingMethodGenerator(MetaMethod method, OverrideMethodDelegate overrideMethod, - GetTargetReferenceDelegate getTargetReference) + GetTargetExpressionDelegate getTarget) : base(method, overrideMethod) { - this.getTargetReference = getTargetReference; + this.getTarget = getTarget; } protected override MethodEmitter BuildProxiedMethodBody(MethodEmitter emitter, ClassEmitter @class, INamingScope namingScope) { - var targetReference = getTargetReference(@class, MethodToOverride); + var target = getTarget(@class, MethodToOverride); var arguments = ArgumentsUtil.ConvertToArgumentReferenceExpression(MethodToOverride.GetParameters()); emitter.CodeBuilder.AddStatement(new ReturnStatement( new MethodInvocationExpression( - targetReference, + target, MethodToOverride, arguments) { VirtualCall = true })); return emitter; diff --git a/src/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithTargetInterfaceGenerator.cs b/src/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithTargetInterfaceGenerator.cs index f0f6d2a2bc..e588df95f0 100644 --- a/src/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithTargetInterfaceGenerator.cs +++ b/src/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithTargetInterfaceGenerator.cs @@ -57,18 +57,13 @@ protected override void AddMappingForAdditionalInterfaces(CompositeTypeContribut protected override InterfaceProxyWithoutTargetContributor GetContributorForAdditionalInterfaces( INamingScope namingScope) { - return new InterfaceProxyWithOptionalTargetContributor(namingScope, GetTargetExpression, GetTarget) + return new InterfaceProxyWithOptionalTargetContributor(namingScope, GetTarget) { Logger = Logger }; } - private Reference GetTarget(ClassEmitter @class, MethodInfo method) + private IExpression GetTarget(ClassEmitter @class, MethodInfo method) { return new AsTypeReference(@class.GetField("__target"), method.DeclaringType); } - - private IExpression GetTargetExpression(ClassEmitter @class, MethodInfo method) - { - return GetTarget(@class, method); - } } } \ No newline at end of file diff --git a/src/Castle.Core/DynamicProxy/Generators/OptionallyForwardingMethodGenerator.cs b/src/Castle.Core/DynamicProxy/Generators/OptionallyForwardingMethodGenerator.cs index 51a36f2f73..9ae81f7d2e 100644 --- a/src/Castle.Core/DynamicProxy/Generators/OptionallyForwardingMethodGenerator.cs +++ b/src/Castle.Core/DynamicProxy/Generators/OptionallyForwardingMethodGenerator.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. @@ -24,37 +24,37 @@ namespace Castle.DynamicProxy.Generators internal class OptionallyForwardingMethodGenerator : MethodGenerator { // TODO: This class largely duplicates code from Forwarding and Minimalistic generators. Should be refactored to change that - private readonly GetTargetReferenceDelegate getTargetReference; + private readonly GetTargetExpressionDelegate getTarget; public OptionallyForwardingMethodGenerator(MetaMethod method, OverrideMethodDelegate overrideMethod, - GetTargetReferenceDelegate getTargetReference) + GetTargetExpressionDelegate getTarget) : base(method, overrideMethod) { - this.getTargetReference = getTargetReference; + this.getTarget = getTarget; } protected override MethodEmitter BuildProxiedMethodBody(MethodEmitter emitter, ClassEmitter @class, INamingScope namingScope) { - var targetReference = getTargetReference(@class, MethodToOverride); + var target = getTarget(@class, MethodToOverride); emitter.CodeBuilder.AddStatement( new IfNullExpression( - targetReference, + target, IfNull(emitter.ReturnType), - IfNotNull(targetReference))); + IfNotNull(target))); return emitter; } - private IStatement IfNotNull(Reference targetReference) + private IStatement IfNotNull(IExpression target) { var statements = new BlockStatement(); var arguments = ArgumentsUtil.ConvertToArgumentReferenceExpression(MethodToOverride.GetParameters()); statements.AddStatement(new ReturnStatement( new MethodInvocationExpression( - targetReference, + target, MethodToOverride, arguments) { VirtualCall = true })); return statements; From 1f7f2399a771f6ff66177cf0f343e60b7d42111e Mon Sep 17 00:00:00 2001 From: Dominique Schuppli Date: Wed, 17 Dec 2025 00:21:40 +0100 Subject: [PATCH 2/4] Now can downgrade `AsTypeReference` to an expression & rename it --- .../Contributors/MixinContributor.cs | 4 ++-- ...AsTypeReference.cs => AsTypeExpression.cs} | 21 +++---------------- ...erfaceProxyWithTargetInterfaceGenerator.cs | 2 +- .../Generators/InvocationTypeGenerator.cs | 2 +- 4 files changed, 7 insertions(+), 22 deletions(-) rename src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/{AsTypeReference.cs => AsTypeExpression.cs} (59%) diff --git a/src/Castle.Core/DynamicProxy/Contributors/MixinContributor.cs b/src/Castle.Core/DynamicProxy/Contributors/MixinContributor.cs index e6070994ef..9f63b269bd 100644 --- a/src/Castle.Core/DynamicProxy/Contributors/MixinContributor.cs +++ b/src/Castle.Core/DynamicProxy/Contributors/MixinContributor.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. @@ -114,7 +114,7 @@ private GetTargetExpressionDelegate BuildGetTargetExpression() } return (c, m) => new NullCoalescingOperatorExpression( - new AsTypeReference(c.GetField("__target"), m.DeclaringType), + new AsTypeExpression(c.GetField("__target"), m.DeclaringType), fields[m.DeclaringType]); } diff --git a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AsTypeReference.cs b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AsTypeExpression.cs similarity index 59% rename from src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AsTypeReference.cs rename to src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AsTypeExpression.cs index 58d7866f7f..003e83d655 100644 --- a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AsTypeReference.cs +++ b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AsTypeExpression.cs @@ -21,36 +21,21 @@ namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST using System.Reflection.Emit; [DebuggerDisplay("{reference} as {type}")] - internal class AsTypeReference : Reference + internal class AsTypeExpression : IExpression { private readonly Reference reference; private readonly Type type; - public AsTypeReference(Reference reference, Type type) - : base(type) + public AsTypeExpression(Reference reference, Type type) { this.reference = reference; this.type = type; } - public override void EmitAddress(ILGenerator gen) - { - // It does not make sense to take the address of a cast expression. - // The C# language would also forbid address-taking of the form `&(x as T)`. - throw new NotSupportedException(); - } - - public override void Emit(ILGenerator gen) + public void Emit(ILGenerator gen) { reference.Emit(gen); gen.Emit(OpCodes.Isinst, type); } - - public override void EmitStore(IExpression value, ILGenerator gen) - { - // It does not make sense to assign a value to the result of a cast expression. - // The C# language would also forbid assignments of the form `(x as T) = y`. - throw new NotSupportedException(); - } } } \ No newline at end of file diff --git a/src/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithTargetInterfaceGenerator.cs b/src/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithTargetInterfaceGenerator.cs index e588df95f0..47106c7bf6 100644 --- a/src/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithTargetInterfaceGenerator.cs +++ b/src/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithTargetInterfaceGenerator.cs @@ -63,7 +63,7 @@ protected override InterfaceProxyWithoutTargetContributor GetContributorForAddit private IExpression GetTarget(ClassEmitter @class, MethodInfo method) { - return new AsTypeReference(@class.GetField("__target"), method.DeclaringType); + return new AsTypeExpression(@class.GetField("__target"), method.DeclaringType); } } } \ No newline at end of file diff --git a/src/Castle.Core/DynamicProxy/Generators/InvocationTypeGenerator.cs b/src/Castle.Core/DynamicProxy/Generators/InvocationTypeGenerator.cs index b0c2a13b04..83ad99082f 100644 --- a/src/Castle.Core/DynamicProxy/Generators/InvocationTypeGenerator.cs +++ b/src/Castle.Core/DynamicProxy/Generators/InvocationTypeGenerator.cs @@ -96,7 +96,7 @@ protected virtual MethodInvocationExpression GetCallbackMethodInvocation(Abstrac return contributor.GetCallbackMethodInvocation(invocation, args, targetField, invokeMethodOnTarget); } var methodOnTargetInvocationExpression = new MethodInvocationExpression( - new AsTypeReference(targetField, callbackMethod.DeclaringType), + new AsTypeExpression(targetField, callbackMethod.DeclaringType), callbackMethod, args) { VirtualCall = true }; return methodOnTargetInvocationExpression; From 81f1b9bd159d373276f9d2c7f56e1ec41606a9b2 Mon Sep 17 00:00:00 2001 From: Dominique Schuppli Date: Wed, 17 Dec 2025 00:27:59 +0100 Subject: [PATCH 3/4] Downgrade `ByRefReference` to an expression & rename it --- ...RefReference.cs => AddressOfExpression.cs} | 27 +++++-------------- .../Generators/InvocationTypeGenerator.cs | 4 +-- 2 files changed, 9 insertions(+), 22 deletions(-) rename src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/{ByRefReference.cs => AddressOfExpression.cs} (58%) diff --git a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ByRefReference.cs b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AddressOfExpression.cs similarity index 58% rename from src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ByRefReference.cs rename to src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AddressOfExpression.cs index 769e97db5c..60345f1734 100644 --- a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ByRefReference.cs +++ b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AddressOfExpression.cs @@ -16,35 +16,22 @@ namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST { - using System; using System.Diagnostics; using System.Reflection.Emit; - - [DebuggerDisplay("&{localReference}")] - internal class ByRefReference : Reference + [DebuggerDisplay("&{reference}")] + internal class AddressOfExpression : IExpression { - private readonly LocalReference localReference; - - public ByRefReference(LocalReference localReference) - : base(localReference.Type) - { - this.localReference = localReference; - } - - public override void EmitAddress(ILGenerator gen) - { - localReference.EmitAddress(gen); - } + private readonly Reference reference; - public override void Emit(ILGenerator gen) + public AddressOfExpression(Reference reference) { - localReference.EmitAddress(gen); + this.reference = reference; } - public override void EmitStore(IExpression value, ILGenerator gen) + public void Emit(ILGenerator gen) { - throw new NotImplementedException(); + reference.EmitAddress(gen); } } } \ No newline at end of file diff --git a/src/Castle.Core/DynamicProxy/Generators/InvocationTypeGenerator.cs b/src/Castle.Core/DynamicProxy/Generators/InvocationTypeGenerator.cs index 83ad99082f..749b65e775 100644 --- a/src/Castle.Core/DynamicProxy/Generators/InvocationTypeGenerator.cs +++ b/src/Castle.Core/DynamicProxy/Generators/InvocationTypeGenerator.cs @@ -149,8 +149,8 @@ protected virtual void ImplementInvokeMethodOnTarget(AbstractTypeEmitter invocat } invokeMethodOnTarget.CodeBuilder.AddStatement(new AssignStatement(localReference, localValue)); - var byRefReference = new ByRefReference(localReference); - args[i] = byRefReference; + var localByRef = new AddressOfExpression(localReference); + args[i] = localByRef; byRefArguments[i] = localReference; } else From f2bc4a296fd08709f99f466d034d56e6e63c5357 Mon Sep 17 00:00:00 2001 From: Dominique Schuppli Date: Wed, 17 Dec 2025 00:39:17 +0100 Subject: [PATCH 4/4] Add missing `ArrayElementReference` --- .../Contributors/SerializableContributor.cs | 7 +- .../Generators/BaseProxyGenerator.cs | 6 +- .../SimpleAST/ArrayElementReference.cs | 64 +++++++++++++++++++ .../SimpleAST/AssignArrayStatement.cs | 45 ------------- .../LoadRefArrayElementExpression.cs | 39 ----------- .../DynamicProxy/Generators/GeneratorUtil.cs | 2 +- .../MethodWithInvocationGenerator.cs | 4 +- 7 files changed, 75 insertions(+), 92 deletions(-) create mode 100644 src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ArrayElementReference.cs delete mode 100644 src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignArrayStatement.cs delete mode 100644 src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LoadRefArrayElementExpression.cs diff --git a/src/Castle.Core/DynamicProxy/Contributors/SerializableContributor.cs b/src/Castle.Core/DynamicProxy/Contributors/SerializableContributor.cs index c4ff33945c..d1b54f5999 100644 --- a/src/Castle.Core/DynamicProxy/Contributors/SerializableContributor.cs +++ b/src/Castle.Core/DynamicProxy/Contributors/SerializableContributor.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. @@ -90,9 +90,8 @@ protected void ImplementGetObjectData(ClassEmitter emitter) for (var i = 0; i < interfaces.Length; i++) { getObjectData.CodeBuilder.AddStatement( - new AssignArrayStatement( - interfacesLocal, - i, + new AssignStatement( + new ArrayElementReference(interfacesLocal, i), new LiteralStringExpression(interfaces[i].AssemblyQualifiedName))); } diff --git a/src/Castle.Core/DynamicProxy/Generators/BaseProxyGenerator.cs b/src/Castle.Core/DynamicProxy/Generators/BaseProxyGenerator.cs index 2d790409d6..ec1a150ac6 100644 --- a/src/Castle.Core/DynamicProxy/Generators/BaseProxyGenerator.cs +++ b/src/Castle.Core/DynamicProxy/Generators/BaseProxyGenerator.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. @@ -331,7 +331,9 @@ protected void GenerateParameterlessConstructor(ClassEmitter emitter, Type baseC constructor.CodeBuilder.AddStatement(new AssignStatement(interceptorField, new NewArrayExpression(1, typeof(IInterceptor)))); constructor.CodeBuilder.AddStatement( - new AssignArrayStatement(interceptorField, 0, new NewInstanceExpression(typeof(StandardInterceptor)))); + new AssignStatement( + new ArrayElementReference(interceptorField, 0), + new NewInstanceExpression(typeof(StandardInterceptor)))); // Invoke base constructor diff --git a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ArrayElementReference.cs b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ArrayElementReference.cs new file mode 100644 index 0000000000..bb9241a302 --- /dev/null +++ b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ArrayElementReference.cs @@ -0,0 +1,64 @@ +// 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.Diagnostics; + using System.Reflection.Emit; + + internal sealed class ArrayElementReference : Reference + { + private readonly Reference array; + private readonly int index; + + public ArrayElementReference(Reference array, int index) + : base(array.Type.GetElementType()!) + { + Debug.Assert(array.Type.IsArray); + + // The below methods have the `ldelem.ref` and `stelem.ref` opcodes hardcoded, + // which is only correct for reference types. Once we start using this class + // for arrays of primitive types, enums, value types, or generic parameters, + // we will need to revisit this. + Debug.Assert(array.Type.GetElementType()!.IsClass || array.Type.GetElementType()!.IsInterface); + + this.array = array; + this.index = index; + } + + public override void Emit(ILGenerator gen) + { + array.Emit(gen); + gen.Emit(OpCodes.Ldc_I4, index); + gen.Emit(OpCodes.Ldelem_Ref); + } + + public override void EmitAddress(ILGenerator gen) + { + array.Emit(gen); + gen.Emit(OpCodes.Ldc_I4, index); + gen.Emit(OpCodes.Ldelema); + } + + public override void EmitStore(IExpression value, ILGenerator gen) + { + array.Emit(gen); + gen.Emit(OpCodes.Ldc_I4, index); + value.Emit(gen); + gen.Emit(OpCodes.Stelem_Ref); + } + } +} diff --git a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignArrayStatement.cs b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignArrayStatement.cs deleted file mode 100644 index d02432c480..0000000000 --- a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignArrayStatement.cs +++ /dev/null @@ -1,45 +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 AssignArrayStatement : IStatement - { - private readonly Reference targetArray; - private readonly int targetPosition; - private readonly IExpression value; - - public AssignArrayStatement(Reference targetArray, int targetPosition, IExpression value) - { - this.targetArray = targetArray; - this.targetPosition = targetPosition; - this.value = value; - } - - public void Emit(ILGenerator il) - { - targetArray.Emit(il); - - il.Emit(OpCodes.Ldc_I4, targetPosition); - - value.Emit(il); - - il.Emit(OpCodes.Stelem_Ref); - } - } -} \ No newline at end of file diff --git a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LoadRefArrayElementExpression.cs b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LoadRefArrayElementExpression.cs deleted file mode 100644 index d6db83640d..0000000000 --- a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LoadRefArrayElementExpression.cs +++ /dev/null @@ -1,39 +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 LoadRefArrayElementExpression : IExpression - { - private readonly Reference arrayReference; - private readonly LiteralIntExpression index; - - public LoadRefArrayElementExpression(int index, Reference arrayReference) - { - this.index = new LiteralIntExpression(index); - this.arrayReference = arrayReference; - } - - public void Emit(ILGenerator gen) - { - arrayReference.Emit(gen); - index.Emit(gen); - gen.Emit(OpCodes.Ldelem_Ref); - } - } -} \ No newline at end of file diff --git a/src/Castle.Core/DynamicProxy/Generators/GeneratorUtil.cs b/src/Castle.Core/DynamicProxy/Generators/GeneratorUtil.cs index de82458779..9ece9992ba 100644 --- a/src/Castle.Core/DynamicProxy/Generators/GeneratorUtil.cs +++ b/src/Castle.Core/DynamicProxy/Generators/GeneratorUtil.cs @@ -133,7 +133,7 @@ bool IsReadOnly(ParameterInfo parameter) private static ConvertExpression Argument(int i, LocalReference invocationArgs, Reference[] arguments) { - return new ConvertExpression(arguments[i].Type, new LoadRefArrayElementExpression(i, invocationArgs)); + return new ConvertExpression(arguments[i].Type, new ArrayElementReference(invocationArgs, i)); } private static AssignStatement AssignArgument(Reference[] dereferencedArguments, int i, diff --git a/src/Castle.Core/DynamicProxy/Generators/MethodWithInvocationGenerator.cs b/src/Castle.Core/DynamicProxy/Generators/MethodWithInvocationGenerator.cs index 765355b52d..8f1e1ead6c 100644 --- a/src/Castle.Core/DynamicProxy/Generators/MethodWithInvocationGenerator.cs +++ b/src/Castle.Core/DynamicProxy/Generators/MethodWithInvocationGenerator.cs @@ -222,7 +222,9 @@ private void EmitLoadGenericMethodArguments(MethodEmitter methodEmitter, MethodI for (var i = 0; i < genericParameters.Length; ++i) { methodEmitter.CodeBuilder.AddStatement( - new AssignArrayStatement(genericParamsArrayLocal, i, new TypeTokenExpression(genericParameters[i]))); + new AssignStatement( + new ArrayElementReference(genericParamsArrayLocal, i), + new TypeTokenExpression(genericParameters[i]))); } methodEmitter.CodeBuilder.AddStatement( new MethodInvocationExpression(invocationLocal,