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

TypeGetTypeMethodThunk.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: 7e7a9133b13c0458a8f866d63f5f41de3d51e81c (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
183
184
185
// 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>
    /// Helps model the behavior of calls to various Type.GetType overloads. Type.GetType is required to search
    /// the calling assembly for a matching type if the type name supplied by the user code was not assembly qualified.
    /// This thunk calls a helper method, passing it a string for what should be considered the "calling assembly".
    /// </summary>
    internal partial class TypeGetTypeMethodThunk : ILStubMethod
    {
        private readonly MethodDesc _helperMethod;

        public TypeGetTypeMethodThunk(TypeDesc owningType, MethodSignature signature, MethodDesc helperMethod, string defaultAssemblyName)
        {
            OwningType = owningType;
            Signature = signature;
            DefaultAssemblyName = defaultAssemblyName;

            _helperMethod = helperMethod;
        }

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

        public override string Name
        {
            get
            {
                return $"{_helperMethod.Name}_{Signature.Length}_{DefaultAssemblyName}";
            }
        }

        public override string DiagnosticName
        {
            get
            {
                return $"{_helperMethod.DiagnosticName}_{Signature.Length}_{DefaultAssemblyName}";
            }
        }

        public override TypeDesc OwningType
        {
            get;
        }

        public override MethodSignature Signature
        {
            get;
        }

        public string DefaultAssemblyName
        {
            get;
        }

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

            Debug.Assert(Signature[0] == _helperMethod.Signature[0]);
            codeStream.EmitLdArg(0);

            Debug.Assert(_helperMethod.Signature[1].IsString);
            codeStream.Emit(ILOpcode.ldstr, emit.NewToken(DefaultAssemblyName));

            for (int i = 2; i < _helperMethod.Signature.Length; i++)
            {
                // The helper method could be expecting more arguments than what we have - check for that
                // The thunk represents one of the 6 possible overloads:
                // (String), (String, bool), (String, bool, bool)
                // (String, Func<...>, Func<...>), (String, Func<...>, Func<...>, bool), (String, Func<...>, Func<...>, bool, bool)
                // We only need 2 helpers to support all 6 overloads. The default value for the bools is false.

                if (i - 1 < Signature.Length)
                {
                    // Pass user's parameter
                    Debug.Assert(_helperMethod.Signature[i] == Signature[i - 1]);
                    codeStream.EmitLdArg(i - 1);
                }
                else
                {
                    // Pass a default value
                    Debug.Assert(_helperMethod.Signature[i].IsWellKnownType(WellKnownType.Boolean));
                    codeStream.EmitLdc(0);
                }
            }

            codeStream.Emit(ILOpcode.call, emit.NewToken(_helperMethod));
            codeStream.Emit(ILOpcode.ret);

            return emit.Link(this);
        }
    }

    internal class TypeGetTypeMethodThunkCache
    {
        private TypeDesc _owningTypeForThunks;
        private Unifier _cache;

        public TypeGetTypeMethodThunkCache(TypeDesc owningTypeForThunks)
        {
            _owningTypeForThunks = owningTypeForThunks;
            _cache = new Unifier(this);
        }

        public MethodDesc GetHelper(MethodDesc getTypeOverload, string defaultAssemblyName)
        {
            return _cache.GetOrCreateValue(new Key(defaultAssemblyName, getTypeOverload));
        }

        private struct Key
        {
            public readonly string DefaultAssemblyName;
            public readonly MethodDesc GetTypeOverload;

            public Key(string defaultAssemblyName, MethodDesc getTypeOverload)
            {
                DefaultAssemblyName = defaultAssemblyName;
                GetTypeOverload = getTypeOverload;
            }
        }

        private class Unifier : LockFreeReaderHashtable<Key, TypeGetTypeMethodThunk>
        {
            private TypeGetTypeMethodThunkCache _parent;

            public Unifier(TypeGetTypeMethodThunkCache parent)
            {
                _parent = parent;
            }

            protected override int GetKeyHashCode(Key key)
            {
                return key.DefaultAssemblyName.GetHashCode() ^ key.GetTypeOverload.Signature.GetHashCode();
            }
            protected override int GetValueHashCode(TypeGetTypeMethodThunk value)
            {
                return value.DefaultAssemblyName.GetHashCode() ^ value.Signature.GetHashCode();
            }
            protected override bool CompareKeyToValue(Key key, TypeGetTypeMethodThunk value)
            {
                return key.DefaultAssemblyName == value.DefaultAssemblyName &&
                    key.GetTypeOverload.Signature.Equals(value.Signature);
            }
            protected override bool CompareValueToValue(TypeGetTypeMethodThunk value1, TypeGetTypeMethodThunk value2)
            {
                return value1.DefaultAssemblyName == value2.DefaultAssemblyName &&
                    value1.Signature.Equals(value2.Signature);
            }
            protected override TypeGetTypeMethodThunk CreateValueFromKey(Key key)
            {
                TypeSystemContext context = key.GetTypeOverload.Context;

                // This will be one of the 6 possible overloads:
                // (String), (String, bool), (String, bool, bool)
                // (String, Func<...>, Func<...>), (String, Func<...>, Func<...>, bool), (String, Func<...>, Func<...>, bool, bool)

                // We only need 2 helpers to support this. Use the second parameter to pick the right one.

                string helperName;
                MethodSignature signature = key.GetTypeOverload.Signature;
                if (signature.Length > 1 && signature[1].HasInstantiation)
                    helperName = "ExtensibleGetType";
                else
                    helperName = "GetType";

                MethodDesc helper = context.GetHelperEntryPoint("ReflectionHelpers", helperName);

                return new TypeGetTypeMethodThunk(_parent._owningTypeForThunks, signature, helper, key.DefaultAssemblyName);
            }
        }
    }
}