Skip to content

Commit 7fc06fb

Browse files
committed
Box by-ref-like arguments as System.Reflection.Pointer
1 parent 93e20a0 commit 7fc06fb

3 files changed

Lines changed: 64 additions & 11 deletions

File tree

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright 2004-2025 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+
#if FEATURE_BYREFLIKE
16+
17+
namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST
18+
{
19+
using System;
20+
using System.Diagnostics;
21+
using System.Reflection.Emit;
22+
23+
internal class DereferencePointerExpression : IExpression
24+
{
25+
private readonly IExpression pointerExpression;
26+
private readonly Type pointerType;
27+
28+
public DereferencePointerExpression(IExpression pointerExpression, Type pointerType)
29+
{
30+
Debug.Assert(pointerType.IsPointer);
31+
32+
this.pointerExpression = pointerExpression;
33+
this.pointerType = pointerType;
34+
}
35+
36+
public void Emit(ILGenerator gen)
37+
{
38+
pointerExpression.Emit(gen);
39+
gen.Emit(OpCodes.Ldobj, pointerType.GetElementType());
40+
}
41+
}
42+
}
43+
44+
#endif

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST
1919
using System.Reflection.Emit;
2020

2121
using Castle.DynamicProxy.Internal;
22+
using Castle.DynamicProxy.Tokens;
2223

2324
internal class ReferencesToObjectArrayExpression : IExpression
2425
{
@@ -47,11 +48,16 @@ public void Emit(ILGenerator gen)
4748
#if FEATURE_BYREFLIKE
4849
if (reference.Type.IsByRefLikeSafe())
4950
{
50-
// The by-ref-like argument value cannot be put into the `object[]` array,
51-
// because it cannot be boxed. We need to replace it with some other value.
52-
53-
// For now, we just erase it by substituting `null`:
54-
gen.Emit(OpCodes.Ldnull);
51+
// By-ref-like arguments cannot be put directly into the `object[]` array,
52+
// because they cannot live on the heap. So instead we are taking their address,
53+
// putting that in a `System.Reflection.Pointer`, and then store *that*:
54+
var localCopy = gen.DeclareLocal(reference.Type);
55+
ArgumentsUtil.EmitLoadOwnerAndReference(reference, gen);
56+
gen.Emit(OpCodes.Stloc, localCopy);
57+
gen.Emit(OpCodes.Ldloca, localCopy);
58+
gen.Emit(OpCodes.Ldtoken, reference.Type.MakePointerType());
59+
gen.Emit(OpCodes.Call, TypeMethods.GetTypeFromHandle);
60+
gen.Emit(OpCodes.Call, PointerMethods.BoxMethod);
5561
gen.Emit(OpCodes.Stelem_Ref);
5662

5763
continue;

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ namespace Castle.DynamicProxy.Generators
1616
{
1717
using System;
1818
using System.Collections.Generic;
19+
using System.Linq.Expressions;
1920
using System.Reflection;
2021

2122
using Castle.DynamicProxy.Contributors;
@@ -158,12 +159,14 @@ protected virtual void ImplementInvokeMethodOnTarget(AbstractTypeEmitter invocat
158159
#if FEATURE_BYREFLIKE
159160
if (paramType.IsByRefLikeSafe())
160161
{
161-
// The argument value in the invocation `Arguments` array is an `object`
162-
// and cannot be converted back to its original by-ref-like type.
163-
// We need to replace it with some other value.
164-
165-
// For now, we just substitute the by-ref-like type's default value:
166-
args[i] = new DefaultValueExpression(paramType);
162+
// By-ref-like arguments are stored in the `Arguments` array
163+
// as `System.Reflection.Pointer`s. Here we need to convert those back:
164+
args[i] = new DereferencePointerExpression(
165+
new MethodInvocationExpression(
166+
null,
167+
PointerMethods.UnboxMethod,
168+
new MethodInvocationExpression(SelfReference.Self, InvocationMethods.GetArgumentValue, new LiteralIntExpression(i))),
169+
paramType.MakePointerType());
167170
}
168171
else
169172
#endif

0 commit comments

Comments
 (0)