Welcome to mirror list, hosted at ThFree Co, Russian Federation.

DynamicInvokeMethodThunk.cs « Stubs « IL « TypeSystem « Common « tools « coreclr « src - github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: ee50cc4f0565ff223de99d851746e5d12a889d3f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Internal.TypeSystem;

using Debug = System.Diagnostics.Debug;

namespace Internal.IL.Stubs
{
    /// <summary>
    /// Thunk to dynamically invoke a method using reflection. The method accepts an parameters as byrefs
    /// lays them out on the stack, and calls the target method. This thunk has heavy dependencies
    /// on the general dynamic invocation infrastructure in System.InvokeUtils and gets called from there
    /// at runtime. See comments in System.InvokeUtils for a more thorough explanation.
    /// </summary>
    public sealed partial class DynamicInvokeMethodThunk : ILStubMethod
    {
        private TypeDesc _owningType;
        private MethodSignature _targetSignature;
        private MethodSignature _signature;

        public DynamicInvokeMethodThunk(TypeDesc owningType, MethodSignature targetSignature)
        {
            _owningType = owningType;
            _targetSignature = targetSignature;
        }

        // MethodSignature does not track information about the type of the this pointer. We will steal
        // one of the unused upper bits to track whether the this pointer is a byref or an object. This makes
        // the information passed around seamlesly, including name mangling.
        private static MethodSignatureFlags MethodSignatureFlags_ValueTypeInstanceMethod => (MethodSignatureFlags)0x8000;

        public static MethodSignature NormalizeSignature(MethodSignature sig, bool valueTypeInstanceMethod)
        {
            MethodSignatureFlags flags = 0;
            if (sig.IsStatic)
            {
                flags |= MethodSignatureFlags.Static;
            }
            // TODO: Reflection invoke assumes unboxing stubs. It means that the "this" pointer is always a regular boxed object reference and
            // that the dynamic invoke thunks cannot be used to invoke instance methods on unboxed value types currently. This will need
            // to be addressed for the eventual allocation-free reflection invoke.
            // else if (valueTypeInstanceMethod)
            // {
            //     flags |= MethodSignatureFlags_ValueTypeInstanceMethod;
            // }

            TypeDesc[] parameters = new TypeDesc[sig.Length];
            for (int i = 0; i < sig.Length; i++)
                parameters[i] = NormalizeType(sig[i]);
            return new MethodSignature(flags, 0, NormalizeType(sig.ReturnType), parameters);

            static TypeDesc NormalizeType(TypeDesc type)
            {
                Debug.Assert(!type.ContainsSignatureVariables(treatGenericParameterLikeSignatureVariable: true));

                if (type.IsByRef)
                    return type.Context.GetWellKnownType(WellKnownType.Byte).MakeByRefType();

                if (type.IsPointer || type.IsFunctionPointer)
                    return type.Context.GetWellKnownType(WellKnownType.Void).MakePointerType();

                if (type.IsEnum)
                    return type.UnderlyingType;

                if (type.IsValueType)
                    return type;

                return type.Context.GetWellKnownType(WellKnownType.Object);
            }
        }

        public override TypeSystemContext Context
        {
            get
            {
                return _owningType.Context;
            }
        }

        public override TypeDesc OwningType
        {
            get
            {
                return _owningType;
            }
        }

        public override MethodSignature Signature
        {
            get
            {
                if (_signature == null)
                {
                    var ptr = Context.GetWellKnownType(WellKnownType.Void).MakePointerType();
                    var byref = Context.GetWellKnownType(WellKnownType.Byte).MakeByRefType();

                    _signature = new MethodSignature(
                        MethodSignatureFlags.Static,
                        0,
                        byref,
                        new TypeDesc[]
                        {
                            ptr,    // fptr
                            byref,  // thisptr
                            byref,  // refbuf
                            ptr     // arguments
                        });
                }

                return _signature;
            }
        }

        public override string Name => "DynamicInvoke";

        public override string DiagnosticName => "DynamicInvoke";

        public MethodSignature TargetSignature => _targetSignature;

        public override MethodIL EmitIL()
        {
            ILEmitter emitter = new ILEmitter();
            ILCodeStream codeStream = emitter.NewCodeStream();

            // Handle instance methods.
            if (!_targetSignature.IsStatic)
            {
                codeStream.EmitLdArg(1);
                if ((_targetSignature.Flags & MethodSignatureFlags_ValueTypeInstanceMethod) == 0)
                    codeStream.Emit(ILOpcode.ldind_ref);
            }

            // Push the arguments.
            if (_targetSignature.Length != 0)
            {
                var fieldByReferenceValueToken = emitter.NewToken(
                    Context.SystemModule.GetKnownType("System", "ByReference").GetKnownField("Value"));
                for (int i = 0; i < _targetSignature.Length; i++)
                {
                    codeStream.EmitLdArg(3);
                    if (i != 0)
                    {
                        codeStream.EmitLdc(i * Context.Target.PointerSize);
                        codeStream.Emit(ILOpcode.add);
                    }

                    codeStream.Emit(ILOpcode.ldfld, fieldByReferenceValueToken);

                    var parameterType = _targetSignature[i];
                    if (!parameterType.IsByRef)
                    {
                        codeStream.EmitLdInd(parameterType);
                    }
                }
            }

            codeStream.EmitLdArg(0);
            codeStream.Emit(ILOpcode.calli, emitter.NewToken(_targetSignature));

            // Store the return value unless it is a byref
            var returnType = _targetSignature.ReturnType;
            if (!returnType.IsByRef)
            {
                if (!returnType.IsVoid)
                {
                    var retVal = emitter.NewLocal(returnType);
                    codeStream.EmitStLoc(retVal);

                    codeStream.EmitLdArg(2);
                    codeStream.EmitLdLoc(retVal);
                    codeStream.EmitStInd(returnType);
                }
                codeStream.EmitLdArg(2);
            }

            codeStream.Emit(ILOpcode.ret);

            return emitter.Link(this);
        }
    }
}