Skip to content

Commit 638244f

Browse files
committed
Invoke converter for incoming argument values
1 parent 3bd5910 commit 638244f

File tree

5 files changed

+81
-0
lines changed

5 files changed

+81
-0
lines changed

src/Castle.Core/DynamicProxy/Generators/BaseProxyGenerator.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,11 @@ protected virtual ClassEmitter BuildClassEmitter(string typeName, Type parentTyp
131131
CheckNotGenericTypeDefinition(parentType, nameof(parentType));
132132
CheckNotGenericTypeDefinitions(interfaces, nameof(interfaces));
133133

134+
#if FEATURE_BYREFLIKE
135+
return new ClassEmitter(Scope, typeName, parentType, interfaces) { ByRefLikeConverterSelector = ProxyGenerationOptions.ByRefLikeConverterSelector };
136+
#else
134137
return new ClassEmitter(Scope, typeName, parentType, interfaces);
138+
#endif
135139
}
136140

137141
protected void CheckNotGenericTypeDefinition(Type type, string argumentName)

src/Castle.Core/DynamicProxy/Generators/Emitters/ClassEmitter.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ public ClassEmitter(TypeBuilder typeBuilder)
6565
{
6666
}
6767

68+
#if FEATURE_BYREFLIKE
69+
public IByRefLikeConverterSelector ByRefLikeConverterSelector { get; set; }
70+
#endif
71+
6872
public ModuleScope ModuleScope
6973
{
7074
get { return moduleScope; }

src/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReferencesToObjectArrayExpression.cs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,28 @@ namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST
1818
using System.Reflection;
1919
using System.Reflection.Emit;
2020

21+
using Castle.DynamicProxy.Tokens;
22+
2123
internal class ReferencesToObjectArrayExpression : IExpression
2224
{
2325
private readonly TypeReference[] args;
2426

27+
#if FEATURE_BYREFLIKE
28+
private readonly MethodInfo proxiedMethod;
29+
private readonly IByRefLikeConverterSelector byRefLikeConverterSelector;
30+
31+
public ReferencesToObjectArrayExpression(MethodInfo proxiedMethod, IByRefLikeConverterSelector byRefLikeConverterSelector, params TypeReference[] args)
32+
{
33+
this.proxiedMethod = proxiedMethod;
34+
this.byRefLikeConverterSelector = byRefLikeConverterSelector;
35+
this.args = args;
36+
}
37+
#else
2538
public ReferencesToObjectArrayExpression(params TypeReference[] args)
2639
{
2740
this.args = args;
2841
}
42+
#endif
2943

3044
public void Emit(ILGenerator gen)
3145
{
@@ -42,6 +56,37 @@ public void Emit(ILGenerator gen)
4256

4357
var reference = args[i];
4458

59+
#if FEATURE_BYREFLIKE
60+
if (reference.Type.IsByRefLike)
61+
{
62+
var converterType = byRefLikeConverterSelector?.SelectConverterType(proxiedMethod, i, reference.Type);
63+
if (converterType != null)
64+
{
65+
// instantiate the by-ref-like value converter:
66+
gen.Emit(OpCodes.Ldtoken, converterType);
67+
gen.Emit(OpCodes.Call, TypeMethods.GetTypeFromHandle);
68+
gen.EmitCall(OpCodes.Call, ActivatorMethods.CreateInstance, null);
69+
70+
// invoke it:
71+
var boxMethodOnConverter = converterType.GetMethod("Box");
72+
// (TODO: isn't there a nicer way to figure out whether or not the argument was passed by-ref,
73+
// and then ensure that we end up with the argument's address on the evaluation stack?)
74+
var argumentReference = (ArgumentReference)(reference is IndirectReference ? reference.OwnerReference : reference);
75+
gen.Emit(argumentReference.Type.IsByRef ? OpCodes.Ldarg_S : OpCodes.Ldarga_S, argumentReference.Position);
76+
gen.EmitCall(OpCodes.Callvirt, boxMethodOnConverter, null);
77+
}
78+
else
79+
{
80+
// no by-ref-like value converter is available, fall back to substituting the argument value with `null`
81+
// because the logic further down would attempt to box it (which isn't allowed for by-ref-like values):
82+
gen.Emit(OpCodes.Ldnull);
83+
}
84+
85+
gen.Emit(OpCodes.Stelem_Ref);
86+
continue;
87+
}
88+
#endif
89+
4590
ArgumentsUtil.EmitLoadOwnerAndReference(reference, gen);
4691

4792
if (reference.Type.IsByRef)

src/Castle.Core/DynamicProxy/Generators/MethodWithInvocationGenerator.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,11 @@ private IExpression[] GetCtorArguments(ClassEmitter @class, IExpression proxiedM
221221
SelfReference.Self,
222222
methodInterceptors ?? interceptors,
223223
proxiedMethodTokenExpression,
224+
#if FEATURE_BYREFLIKE
225+
new ReferencesToObjectArrayExpression(MethodToOverride, @class.ByRefLikeConverterSelector, dereferencedArguments)
226+
#else
224227
new ReferencesToObjectArrayExpression(dereferencedArguments)
228+
#endif
225229
};
226230
}
227231

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2004-2023 Castle Project - http://www.castleproject.org/
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
namespace Castle.DynamicProxy.Tokens
16+
{
17+
using System;
18+
using System.Reflection;
19+
20+
internal class ActivatorMethods
21+
{
22+
public static readonly MethodInfo CreateInstance = typeof(Activator).GetMethod("CreateInstance", new[] { typeof(Type) });
23+
}
24+
}

0 commit comments

Comments
 (0)