From d91bb5324ca55941a254fd25abf8ff2bb5bba1d4 Mon Sep 17 00:00:00 2001 From: Dominique Schuppli Date: Fri, 23 Jan 2026 14:16:39 +0100 Subject: [PATCH] Make more SimpleAST nodes singletons (fewer allocs) --- .../ClassProxySerializableContributor.cs | 5 +++-- .../ProxyTargetAccessorContributor.cs | 4 ++-- .../Contributors/SerializableContributor.cs | 4 ++-- .../Generators/BaseProxyGenerator.cs | 8 ++++---- .../Generators/Emitters/ConstructorEmitter.cs | 4 ++-- .../Generators/Emitters/MethodEmitter.cs | 2 +- .../SimpleAST/EndExceptionBlockStatement.cs | 10 ++++++++-- .../Emitters/SimpleAST/FinallyStatement.cs | 10 ++++++++-- .../Emitters/SimpleAST/ReturnStatement.cs | 8 +++++--- .../Emitters/SimpleAST/TryStatement.cs | 10 ++++++++-- .../Generators/InvocationTypeGenerator.cs | 20 ++++++++++--------- .../MethodWithInvocationGenerator.cs | 10 +++++----- .../Generators/MinimalisticMethodGenerator.cs | 4 ++-- .../OptionallyForwardingMethodGenerator.cs | 2 +- 14 files changed, 62 insertions(+), 39 deletions(-) diff --git a/src/Castle.Core/DynamicProxy/Contributors/ClassProxySerializableContributor.cs b/src/Castle.Core/DynamicProxy/Contributors/ClassProxySerializableContributor.cs index 70cd816891..bdf8909cb5 100644 --- a/src/Castle.Core/DynamicProxy/Contributors/ClassProxySerializableContributor.cs +++ b/src/Castle.Core/DynamicProxy/Contributors/ClassProxySerializableContributor.cs @@ -1,4 +1,4 @@ -// Copyright 2004-2025 Castle Project - http://www.castleproject.org/ +// Copyright 2004-2026 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. @@ -187,7 +187,8 @@ private void GenerateSerializationConstructor(ClassEmitter emitter) typeof(object), getValue))); } - ctor.CodeBuilder.AddStatement(new ReturnStatement()); + + ctor.CodeBuilder.AddStatement(ReturnStatement.Instance); } private bool VerifyIfBaseImplementsGetObjectData(Type baseType, MetaType model, out MetaMethod getObjectData) diff --git a/src/Castle.Core/DynamicProxy/Contributors/ProxyTargetAccessorContributor.cs b/src/Castle.Core/DynamicProxy/Contributors/ProxyTargetAccessorContributor.cs index 55711a2ab5..2018af822a 100644 --- a/src/Castle.Core/DynamicProxy/Contributors/ProxyTargetAccessorContributor.cs +++ b/src/Castle.Core/DynamicProxy/Contributors/ProxyTargetAccessorContributor.cs @@ -1,4 +1,4 @@ -// Copyright 2004-2025 Castle Project - http://www.castleproject.org/ +// Copyright 2004-2026 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. @@ -63,7 +63,7 @@ public void Generate(ClassEmitter emitter) new ThrowStatement(typeof(InvalidOperationException), "Cannot change the target of the class proxy.")); } - dynProxySetTarget.CodeBuilder.AddStatement(new ReturnStatement()); + dynProxySetTarget.CodeBuilder.AddStatement(ReturnStatement.Instance); var getInterceptors = emitter.CreateMethod(nameof(IProxyTargetAccessor.GetInterceptors), typeof(IInterceptor[])); diff --git a/src/Castle.Core/DynamicProxy/Contributors/SerializableContributor.cs b/src/Castle.Core/DynamicProxy/Contributors/SerializableContributor.cs index d1b54f5999..34b5817946 100644 --- a/src/Castle.Core/DynamicProxy/Contributors/SerializableContributor.cs +++ b/src/Castle.Core/DynamicProxy/Contributors/SerializableContributor.cs @@ -1,4 +1,4 @@ -// Copyright 2004-2025 Castle Project - http://www.castleproject.org/ +// Copyright 2004-2026 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. @@ -125,7 +125,7 @@ protected void ImplementGetObjectData(ClassEmitter emitter) CustomizeGetObjectData(getObjectData.CodeBuilder, info, getObjectData.Arguments[1], emitter); - getObjectData.CodeBuilder.AddStatement(new ReturnStatement()); + getObjectData.CodeBuilder.AddStatement(ReturnStatement.Instance); } protected virtual void AddAddValueInvocation(ArgumentReference serializationInfo, MethodEmitter getObjectData, diff --git a/src/Castle.Core/DynamicProxy/Generators/BaseProxyGenerator.cs b/src/Castle.Core/DynamicProxy/Generators/BaseProxyGenerator.cs index 1ca96a2d22..1dc5806b82 100644 --- a/src/Castle.Core/DynamicProxy/Generators/BaseProxyGenerator.cs +++ b/src/Castle.Core/DynamicProxy/Generators/BaseProxyGenerator.cs @@ -1,4 +1,4 @@ -// Copyright 2004-2025 Castle Project - http://www.castleproject.org/ +// Copyright 2004-2026 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. @@ -156,7 +156,7 @@ protected void CheckNotGenericTypeDefinitions(IEnumerable types, string ar protected void CompleteInitCacheMethod(CodeBuilder constCodeBuilder) { - constCodeBuilder.AddStatement(new ReturnStatement()); + constCodeBuilder.AddStatement(ReturnStatement.Instance); } protected virtual void CreateFields(ClassEmitter emitter) @@ -281,7 +281,7 @@ protected void GenerateConstructor(ClassEmitter emitter, ConstructorInfo baseCon constructor.CodeBuilder.AddStatement(new ConstructorInvocationStatement(emitter.BaseType)); } - constructor.CodeBuilder.AddStatement(new ReturnStatement()); + constructor.CodeBuilder.AddStatement(ReturnStatement.Instance); } protected void GenerateConstructors(ClassEmitter emitter, Type baseType, params FieldReference[] fields) @@ -339,7 +339,7 @@ protected void GenerateParameterlessConstructor(ClassEmitter emitter, Type baseC constructor.CodeBuilder.AddStatement(new ConstructorInvocationStatement(defaultConstructor)); - constructor.CodeBuilder.AddStatement(new ReturnStatement()); + constructor.CodeBuilder.AddStatement(ReturnStatement.Instance); } protected ConstructorEmitter GenerateStaticConstructor(ClassEmitter emitter) diff --git a/src/Castle.Core/DynamicProxy/Generators/Emitters/ConstructorEmitter.cs b/src/Castle.Core/DynamicProxy/Generators/Emitters/ConstructorEmitter.cs index 463da37ace..7aead20046 100644 --- a/src/Castle.Core/DynamicProxy/Generators/Emitters/ConstructorEmitter.cs +++ b/src/Castle.Core/DynamicProxy/Generators/Emitters/ConstructorEmitter.cs @@ -1,4 +1,4 @@ -// Copyright 2004-2025 Castle Project - http://www.castleproject.org/ +// Copyright 2004-2026 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. @@ -76,7 +76,7 @@ public virtual void Generate() CodeBuilder.AddStatement(new ConstructorInvocationStatement(mainType.BaseType)); } - CodeBuilder.AddStatement(new ReturnStatement()); + CodeBuilder.AddStatement(ReturnStatement.Instance); } CodeBuilder.Generate(builder.GetILGenerator()); diff --git a/src/Castle.Core/DynamicProxy/Generators/Emitters/MethodEmitter.cs b/src/Castle.Core/DynamicProxy/Generators/Emitters/MethodEmitter.cs index f48d1e27cb..8587c210f4 100644 --- a/src/Castle.Core/DynamicProxy/Generators/Emitters/MethodEmitter.cs +++ b/src/Castle.Core/DynamicProxy/Generators/Emitters/MethodEmitter.cs @@ -131,7 +131,7 @@ public virtual void Generate() { if (ReturnType == typeof(void)) { - CodeBuilder.AddStatement(new ReturnStatement()); + CodeBuilder.AddStatement(ReturnStatement.Instance); } else { diff --git a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/EndExceptionBlockStatement.cs b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/EndExceptionBlockStatement.cs index f8b9339c83..5a482a53c2 100644 --- a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/EndExceptionBlockStatement.cs +++ b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/EndExceptionBlockStatement.cs @@ -1,4 +1,4 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// Copyright 2004-2026 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. @@ -16,8 +16,14 @@ namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST { using System.Reflection.Emit; - internal class EndExceptionBlockStatement : IStatement + internal sealed class EndExceptionBlockStatement : IStatement { + public static readonly EndExceptionBlockStatement Instance = new EndExceptionBlockStatement(); + + private EndExceptionBlockStatement() + { + } + public void Emit(ILGenerator gen) { gen.EndExceptionBlock(); diff --git a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/FinallyStatement.cs b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/FinallyStatement.cs index ff2ba63aa5..587998d38a 100644 --- a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/FinallyStatement.cs +++ b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/FinallyStatement.cs @@ -1,4 +1,4 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// Copyright 2004-2026 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. @@ -16,8 +16,14 @@ namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST { using System.Reflection.Emit; - internal class FinallyStatement : IStatement + internal sealed class FinallyStatement : IStatement { + public static readonly FinallyStatement Instance = new FinallyStatement(); + + private FinallyStatement() + { + } + public void Emit(ILGenerator gen) { gen.BeginFinallyBlock(); diff --git a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReturnStatement.cs b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReturnStatement.cs index cd2bb40b17..8006c44187 100644 --- a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReturnStatement.cs +++ b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReturnStatement.cs @@ -1,4 +1,4 @@ -// Copyright 2004-2025 Castle Project - http://www.castleproject.org/ +// Copyright 2004-2026 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. @@ -18,11 +18,13 @@ namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST { using System.Reflection.Emit; - internal class ReturnStatement : IStatement + internal sealed class ReturnStatement : IStatement { + public static readonly ReturnStatement Instance = new ReturnStatement(); + private readonly IExpression? expression; - public ReturnStatement() + private ReturnStatement() { } diff --git a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TryStatement.cs b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TryStatement.cs index 69eb9bd48e..7f7a07b555 100644 --- a/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TryStatement.cs +++ b/src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TryStatement.cs @@ -1,4 +1,4 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// Copyright 2004-2026 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. @@ -16,8 +16,14 @@ namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST { using System.Reflection.Emit; - internal class TryStatement : IStatement + internal sealed class TryStatement : IStatement { + public static readonly TryStatement Instance = new TryStatement(); + + private TryStatement() + { + } + public void Emit(ILGenerator gen) { gen.BeginExceptionBlock(); diff --git a/src/Castle.Core/DynamicProxy/Generators/InvocationTypeGenerator.cs b/src/Castle.Core/DynamicProxy/Generators/InvocationTypeGenerator.cs index 4508fc122a..ca7ebe08ee 100644 --- a/src/Castle.Core/DynamicProxy/Generators/InvocationTypeGenerator.cs +++ b/src/Castle.Core/DynamicProxy/Generators/InvocationTypeGenerator.cs @@ -1,4 +1,4 @@ -// Copyright 2004-2025 Castle Project - http://www.castleproject.org/ +// Copyright 2004-2026 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. @@ -179,7 +179,7 @@ protected virtual void ImplementInvokeMethodOnTarget(ClassEmitter invocation, Pa if (byRefArguments.Count > 0) { - invokeMethodOnTarget.CodeBuilder.AddStatement(new TryStatement()); + invokeMethodOnTarget.CodeBuilder.AddStatement(TryStatement.Instance); } var methodOnTargetInvocationExpression = GetCallbackMethodInvocation(invocation, args, callbackMethod, targetField, invokeMethodOnTarget); @@ -225,7 +225,7 @@ protected virtual void ImplementInvokeMethodOnTarget(ClassEmitter invocation, Pa invokeMethodOnTarget.CodeBuilder.AddStatement(setRetVal); } - invokeMethodOnTarget.CodeBuilder.AddStatement(new ReturnStatement()); + invokeMethodOnTarget.CodeBuilder.AddStatement(ReturnStatement.Instance); } private void AssignBackByRefArguments(MethodEmitter invokeMethodOnTarget, Dictionary byRefArguments) @@ -235,7 +235,8 @@ private void AssignBackByRefArguments(MethodEmitter invokeMethodOnTarget, Dictio return; } - invokeMethodOnTarget.CodeBuilder.AddStatement(new FinallyStatement()); + invokeMethodOnTarget.CodeBuilder.AddStatement(FinallyStatement.Instance); + foreach (var byRefArgument in byRefArguments) { var index = byRefArgument.Key; @@ -265,7 +266,8 @@ private void AssignBackByRefArguments(MethodEmitter invokeMethodOnTarget, Dictio new LiteralIntExpression(index), localValue)); } - invokeMethodOnTarget.CodeBuilder.AddStatement(new EndExceptionBlockStatement()); + + invokeMethodOnTarget.CodeBuilder.AddStatement(EndExceptionBlockStatement.Instance); } private void CreateConstructor(ClassEmitter invocation) @@ -275,7 +277,7 @@ private void CreateConstructor(ClassEmitter invocation) var constructor = CreateConstructor(invocation, baseCtorArguments); constructor.CodeBuilder.AddStatement(new ConstructorInvocationStatement(baseConstructor, baseCtorArguments)); - constructor.CodeBuilder.AddStatement(new ReturnStatement()); + constructor.CodeBuilder.AddStatement(ReturnStatement.Instance); } private ConstructorEmitter CreateConstructor(ClassEmitter invocation, ArgumentReference[] baseCtorArguments) @@ -292,7 +294,7 @@ private void EmitCallThrowOnNoTarget(MethodEmitter invokeMethodOnTarget) var throwOnNoTarget = new MethodInvocationExpression(InvocationMethods.ThrowOnNoTarget); invokeMethodOnTarget.CodeBuilder.AddStatement(throwOnNoTarget); - invokeMethodOnTarget.CodeBuilder.AddStatement(new ReturnStatement()); + invokeMethodOnTarget.CodeBuilder.AddStatement(ReturnStatement.Instance); } private MethodInfo GetCallbackMethod(ClassEmitter invocation) @@ -336,7 +338,7 @@ private void ImplementChangeInvocationTarget(ClassEmitter invocation, FieldRefer changeInvocationTarget.CodeBuilder.AddStatement( new AssignStatement(targetField, new ConvertExpression(targetType, changeInvocationTarget.Arguments[0]))); - changeInvocationTarget.CodeBuilder.AddStatement(new ReturnStatement()); + changeInvocationTarget.CodeBuilder.AddStatement(ReturnStatement.Instance); } private void ImplementChangeProxyTarget(ClassEmitter invocation, ClassEmitter @class) @@ -357,7 +359,7 @@ private void ImplementChangeProxyTarget(ClassEmitter invocation, ClassEmitter @c VirtualCall = true }); - changeProxyTarget.CodeBuilder.AddStatement(new ReturnStatement()); + changeProxyTarget.CodeBuilder.AddStatement(ReturnStatement.Instance); } private void ImplementChangeProxyTargetInterface(ClassEmitter @class, ClassEmitter invocation, diff --git a/src/Castle.Core/DynamicProxy/Generators/MethodWithInvocationGenerator.cs b/src/Castle.Core/DynamicProxy/Generators/MethodWithInvocationGenerator.cs index 8f1e1ead6c..1e8592b10d 100644 --- a/src/Castle.Core/DynamicProxy/Generators/MethodWithInvocationGenerator.cs +++ b/src/Castle.Core/DynamicProxy/Generators/MethodWithInvocationGenerator.cs @@ -1,4 +1,4 @@ -// Copyright 2004-2025 Castle Project - http://www.castleproject.org/ +// Copyright 2004-2026 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. @@ -118,7 +118,7 @@ protected override MethodEmitter BuildProxiedMethodBody(MethodEmitter emitter, C if (hasByRefArguments) { - emitter.CodeBuilder.AddStatement(new TryStatement()); + emitter.CodeBuilder.AddStatement(TryStatement.Instance); } var proceed = new MethodInvocationExpression(invocationLocal, InvocationMethods.Proceed); @@ -126,14 +126,14 @@ protected override MethodEmitter BuildProxiedMethodBody(MethodEmitter emitter, C if (hasByRefArguments) { - emitter.CodeBuilder.AddStatement(new FinallyStatement()); + emitter.CodeBuilder.AddStatement(FinallyStatement.Instance); } GeneratorUtil.CopyOutAndRefParameters(dereferencedArguments, invocationLocal, MethodToOverride, emitter); if (hasByRefArguments) { - emitter.CodeBuilder.AddStatement(new EndExceptionBlockStatement()); + emitter.CodeBuilder.AddStatement(EndExceptionBlockStatement.Instance); } if (MethodToOverride.ReturnType != typeof(void)) @@ -172,7 +172,7 @@ protected override MethodEmitter BuildProxiedMethodBody(MethodEmitter emitter, C } else { - emitter.CodeBuilder.AddStatement(new ReturnStatement()); + emitter.CodeBuilder.AddStatement(ReturnStatement.Instance); } return emitter; diff --git a/src/Castle.Core/DynamicProxy/Generators/MinimalisticMethodGenerator.cs b/src/Castle.Core/DynamicProxy/Generators/MinimalisticMethodGenerator.cs index 3b70fb86cd..731ff1c8f5 100644 --- a/src/Castle.Core/DynamicProxy/Generators/MinimalisticMethodGenerator.cs +++ b/src/Castle.Core/DynamicProxy/Generators/MinimalisticMethodGenerator.cs @@ -1,4 +1,4 @@ -// Copyright 2004-2025 Castle Project - http://www.castleproject.org/ +// Copyright 2004-2026 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. @@ -34,7 +34,7 @@ protected override MethodEmitter BuildProxiedMethodBody(MethodEmitter emitter, C if (emitter.ReturnType == typeof(void)) { - emitter.CodeBuilder.AddStatement(new ReturnStatement()); + emitter.CodeBuilder.AddStatement(ReturnStatement.Instance); } else { diff --git a/src/Castle.Core/DynamicProxy/Generators/OptionallyForwardingMethodGenerator.cs b/src/Castle.Core/DynamicProxy/Generators/OptionallyForwardingMethodGenerator.cs index b1dedf36e9..fa5678e14a 100644 --- a/src/Castle.Core/DynamicProxy/Generators/OptionallyForwardingMethodGenerator.cs +++ b/src/Castle.Core/DynamicProxy/Generators/OptionallyForwardingMethodGenerator.cs @@ -67,7 +67,7 @@ private IStatement IfNull(Type returnType) if (returnType == typeof(void)) { - statements.AddStatement(new ReturnStatement()); + statements.AddStatement(ReturnStatement.Instance); } else {