PageRenderTime 78ms CodeModel.GetById 58ms app.highlight 15ms RepoModel.GetById 1ms app.codeStats 1ms

/Microsoft.Scripting/Runtime/DelegateSignatureInfo.cs

https://bitbucket.org/stefanrusek/xronos
C# | 262 lines | 182 code | 46 blank | 34 comment | 33 complexity | 122c6e086a6d39f216d3d2a0fbb755f9 MD5 | raw file
  1/* ****************************************************************************
  2 *
  3 * Copyright (c) Microsoft Corporation. 
  4 *
  5 * This source code is subject to terms and conditions of the Microsoft Public License. A 
  6 * copy of the license can be found in the License.html file at the root of this distribution. If 
  7 * you cannot locate the  Microsoft Public License, please send an email to 
  8 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
  9 * by the terms of the Microsoft Public License.
 10 *
 11 * You must not remove this notice, or any other, from this software.
 12 *
 13 *
 14 * ***************************************************************************/
 15
 16#if CODEPLEX_40
 17using System;
 18#else
 19using System; using Microsoft;
 20#endif
 21using System.Collections.Generic;
 22#if CODEPLEX_40
 23using System.Dynamic;
 24using System.Linq.Expressions;
 25#else
 26using Microsoft.Scripting;
 27using Microsoft.Linq.Expressions;
 28#endif
 29using System.Reflection;
 30using System.Reflection.Emit;
 31using System.Runtime.CompilerServices;
 32#if !CODEPLEX_40
 33using Microsoft.Runtime.CompilerServices;
 34#endif
 35
 36using System.Text;
 37using Microsoft.Contracts;
 38using Microsoft.Scripting.Actions;
 39using Microsoft.Scripting.Generation;
 40using Microsoft.Scripting.Utils;
 41
 42namespace Microsoft.Scripting.Runtime {
 43    /// <summary>
 44    /// Used as the key for the ScriptingRuntimeHelpers.GetDelegate method caching system
 45    /// </summary>
 46    internal sealed class DelegateSignatureInfo {
 47        private readonly LanguageContext _context;
 48        private readonly Type _returnType;
 49        private readonly ParameterInfo[] _parameters;
 50        private readonly ConvertBinder _convert;
 51        private readonly InvokeBinder _invoke;
 52
 53        internal static readonly object TargetPlaceHolder = new object();
 54        internal static readonly object CallSitePlaceHolder = new object();
 55        internal static readonly object ConvertSitePlaceHolder = new object();
 56
 57        internal DelegateSignatureInfo(LanguageContext context, Type returnType, ParameterInfo[] parameters) {
 58            Assert.NotNull(context, returnType);
 59            Assert.NotNullItems(parameters);
 60
 61            _context = context;
 62            _parameters = parameters;
 63            _returnType = returnType;
 64            
 65            if (_returnType != typeof(void)) {
 66                _convert = _context.CreateConvertBinder(_returnType, true);
 67            }
 68            
 69            _invoke = _context.CreateInvokeBinder(new CallInfo(_parameters.Length));
 70        }
 71
 72        [Confined]
 73        public override bool Equals(object obj) {
 74            DelegateSignatureInfo dsi = obj as DelegateSignatureInfo;
 75
 76            if (dsi == null || 
 77                dsi._context != _context ||
 78                dsi._parameters.Length != _parameters.Length ||
 79                dsi._returnType != _returnType) {
 80                return false;
 81            }
 82
 83            for (int i = 0; i < _parameters.Length; i++) {
 84                if (dsi._parameters[i] != _parameters[i]) {
 85                    return false;
 86                }
 87            }
 88
 89            return true;
 90        }
 91
 92        [Confined]
 93        public override int GetHashCode() {
 94            int hashCode = 5331;
 95
 96            for (int i = 0; i < _parameters.Length; i++) {
 97                hashCode ^= _parameters[i].GetHashCode();
 98            }
 99            hashCode ^= _returnType.GetHashCode() ^ _context.GetHashCode();
100            return hashCode;
101        }
102
103        [Confined]
104        public override string ToString() {
105            StringBuilder text = new StringBuilder();
106            text.Append(_returnType.ToString());
107            text.Append("(");
108            for (int i = 0; i < _parameters.Length; i++) {
109                if (i != 0) text.Append(", ");
110                text.Append(_parameters[i].ParameterType.Name);
111            }
112            text.Append(")");
113            return text.ToString();
114        }
115
116        internal DelegateInfo GenerateDelegateStub() {
117            PerfTrack.NoteEvent(PerfTrack.Categories.DelegateCreate, ToString());
118
119            Type[] delegateParams = new Type[_parameters.Length];
120            for (int i = 0; i < _parameters.Length; i++) {
121                delegateParams[i] = _parameters[i].ParameterType;
122            }
123
124            // Create the method with a special name so the langauge compiler knows that method's stack frame is not visible
125            DynamicILGen cg = Snippets.Shared.CreateDynamicMethod("_Scripting_", _returnType, ArrayUtils.Insert(typeof(object[]), delegateParams), false);
126
127            // Emit the stub
128            object[] constants = EmitClrCallStub(cg);
129
130            // Save the constants in the delegate info class
131            return new DelegateInfo(cg.Finish(), constants, this);
132        }
133
134        /// <summary>
135        /// Generates stub to receive the CLR call and then call the dynamic language code.
136        /// </summary>
137        private object[] EmitClrCallStub(ILGen cg) {
138
139            List<ReturnFixer> fixers = new List<ReturnFixer>(0);
140            // Create strongly typed return type from the site.
141            // This will, among other things, generate tighter code.
142            Type[] siteTypes = MakeSiteSignature();
143
144            CallSite callSite = CallSite.Create(DynamicSiteHelpers.MakeCallSiteDelegate(siteTypes), InvokeBinder);
145            Type siteType = callSite.GetType();
146
147            Type convertSiteType = null;
148            CallSite convertSite = null;
149
150            if (_returnType != typeof(void)) {
151                convertSite = CallSite.Create(DynamicSiteHelpers.MakeCallSiteDelegate(typeof(object), _returnType), ConvertBinder);
152                convertSiteType = convertSite.GetType();
153            }
154
155            // build up constants array
156            object[] constants = new object[] { TargetPlaceHolder, CallSitePlaceHolder, ConvertSitePlaceHolder };
157            const int TargetIndex = 0, CallSiteIndex = 1, ConvertSiteIndex = 2;
158
159            LocalBuilder convertSiteLocal = null;
160            FieldInfo convertTarget = null;
161            if (_returnType != typeof(void)) {
162                // load up the conversesion logic on the stack
163                convertSiteLocal = cg.DeclareLocal(convertSiteType);
164                EmitConstantGet(cg, ConvertSiteIndex, convertSiteType);
165
166                cg.Emit(OpCodes.Dup);
167                cg.Emit(OpCodes.Stloc, convertSiteLocal);
168
169                convertTarget = convertSiteType.GetField("Target");
170                cg.EmitFieldGet(convertTarget);
171                cg.Emit(OpCodes.Ldloc, convertSiteLocal);
172            }
173
174            // load up the invoke logic on the stack
175            LocalBuilder site = cg.DeclareLocal(siteType);
176            EmitConstantGet(cg, CallSiteIndex, siteType);
177            cg.Emit(OpCodes.Dup);
178            cg.Emit(OpCodes.Stloc, site);
179
180            FieldInfo target = siteType.GetField("Target");
181            cg.EmitFieldGet(target);
182            cg.Emit(OpCodes.Ldloc, site);
183
184            EmitConstantGet(cg, TargetIndex, typeof(object));
185
186            for (int i = 0; i < _parameters.Length; i++) {
187                if (_parameters[i].ParameterType.IsByRef) {
188                    ReturnFixer rf = ReturnFixer.EmitArgument(cg, i + 1, _parameters[i].ParameterType);
189                    if (rf != null) fixers.Add(rf);
190                } else {
191                    cg.EmitLoadArg(i + 1);
192                }
193            }
194
195            // emit the invoke for the call
196            cg.EmitCall(target.FieldType, "Invoke");
197
198            // emit the invoke for the convert
199            if (_returnType == typeof(void)) {
200                cg.Emit(OpCodes.Pop);
201            } else {
202                cg.EmitCall(convertTarget.FieldType, "Invoke");
203            }
204
205            // fixup any references
206            foreach (ReturnFixer rf in fixers) {
207                rf.FixReturn(cg);
208            }
209
210            cg.Emit(OpCodes.Ret);
211            return constants;
212        }
213
214        private static void EmitConstantGet(ILGen il, int index, Type type) {
215            il.Emit(OpCodes.Ldarg_0);
216            il.EmitInt(index);
217            il.Emit(OpCodes.Ldelem_Ref);
218            if (type != typeof(object)) {
219                il.Emit(OpCodes.Castclass, type);
220            }
221        }
222
223        internal Type[] MakeSiteSignature() {
224            Type[] sig = new Type[_parameters.Length + 2];
225            
226            // target object
227            sig[0] = typeof(object);     
228
229            // arguments
230            for (int i = 0; i < _parameters.Length; i++) {
231                if (_parameters[i].IsByRefParameter()) {
232                    sig[i + 1] = typeof(object);
233                } else {
234                    sig[i + 1] = _parameters[i].ParameterType;
235                }
236            }
237
238            // return type
239            sig[sig.Length - 1] = typeof(object);
240
241            return sig;
242        }
243
244        internal Type ReturnType {
245            get {
246                return _returnType;
247            }
248        }
249
250        internal ConvertBinder ConvertBinder {
251            get {
252                return _convert;
253            }
254        }
255
256        internal InvokeBinder InvokeBinder {
257            get {
258                return _invoke;
259            }
260        }
261    }
262}