mscorlib(4.0.0.0) API with additions
CallSite.cs
3 using System.Dynamic;
4 using System.Dynamic.Utils;
7 using System.Reflection;
8 
10 {
12  [global::__DynamicallyInvokable]
13  public class CallSite
14  {
15  private static volatile CacheDict<Type, Func<CallSiteBinder, CallSite>> _SiteCtors;
16 
17  internal readonly CallSiteBinder _binder;
18 
19  internal bool _match;
20 
23  [global::__DynamicallyInvokable]
24  public CallSiteBinder Binder
25  {
26  [global::__DynamicallyInvokable]
27  get
28  {
29  return _binder;
30  }
31  }
32 
33  internal CallSite(CallSiteBinder binder)
34  {
35  _binder = binder;
36  }
37 
42  [global::__DynamicallyInvokable]
43  public static CallSite Create(Type delegateType, CallSiteBinder binder)
44  {
45  ContractUtils.RequiresNotNull(delegateType, "delegateType");
46  ContractUtils.RequiresNotNull(binder, "binder");
47  if (!delegateType.IsSubclassOf(typeof(MulticastDelegate)))
48  {
49  throw Error.TypeMustBeDerivedFromSystemDelegate();
50  }
51  CacheDict<Type, Func<CallSiteBinder, CallSite>> cacheDict = _SiteCtors;
52  if (cacheDict == null)
53  {
54  cacheDict = (_SiteCtors = new CacheDict<Type, Func<CallSiteBinder, CallSite>>(100));
55  }
56  MethodInfo methodInfo = null;
57  if (!cacheDict.TryGetValue(delegateType, out Func<CallSiteBinder, CallSite> value))
58  {
59  methodInfo = typeof(CallSite<>).MakeGenericType(delegateType).GetMethod("Create");
60  if (delegateType.CanCache())
61  {
62  value = (Func<CallSiteBinder, CallSite>)Delegate.CreateDelegate(typeof(Func<CallSiteBinder, CallSite>), methodInfo);
63  cacheDict.Add(delegateType, value);
64  }
65  }
66  if (value != null)
67  {
68  return value(binder);
69  }
70  return (CallSite)methodInfo.Invoke(null, new object[1]
71  {
72  binder
73  });
74  }
75  }
78  [global::__DynamicallyInvokable]
79  public class CallSite<T> : CallSite where T : class
80  {
82  [global::__DynamicallyInvokable]
83  public T Target;
84 
85  internal T[] Rules;
86 
87  private static T _CachedUpdate;
88 
89  private static volatile T _CachedNoMatch;
90 
91  private const int MaxRules = 10;
92 
95  [global::__DynamicallyInvokable]
96  public T Update
97  {
98  [global::__DynamicallyInvokable]
99  get
100  {
101  if (_match)
102  {
103  return _CachedNoMatch;
104  }
105  return _CachedUpdate;
106  }
107  }
108 
109  private CallSite(CallSiteBinder binder)
110  : base(binder)
111  {
112  Target = GetUpdateDelegate();
113  }
114 
115  private CallSite()
116  : base(null)
117  {
118  }
119 
120  internal CallSite<T> CreateMatchMaker()
121  {
122  return new CallSite<T>();
123  }
124 
128  [global::__DynamicallyInvokable]
129  public static CallSite<T> Create(CallSiteBinder binder)
130  {
131  if (!typeof(T).IsSubclassOf(typeof(MulticastDelegate)))
132  {
133  throw Error.TypeMustBeDerivedFromSystemDelegate();
134  }
135  return new CallSite<T>(binder);
136  }
137 
138  private T GetUpdateDelegate()
139  {
140  return GetUpdateDelegate(ref _CachedUpdate);
141  }
142 
143  private T GetUpdateDelegate(ref T addr)
144  {
145  if (addr == null)
146  {
147  addr = MakeUpdateDelegate();
148  }
149  return addr;
150  }
151 
152  private void ClearRuleCache()
153  {
154  base.Binder.GetRuleCache<T>();
155  Dictionary<Type, object> cache = base.Binder.Cache;
156  if (cache != null)
157  {
158  lock (cache)
159  {
160  cache.Clear();
161  }
162  }
163  }
164 
165  internal void AddRule(T newRule)
166  {
167  T[] rules = Rules;
168  if (rules == null)
169  {
170  Rules = new T[1]
171  {
172  newRule
173  };
174  return;
175  }
176  T[] array;
177  if (rules.Length < 9)
178  {
179  array = new T[rules.Length + 1];
180  Array.Copy(rules, 0, array, 1, rules.Length);
181  }
182  else
183  {
184  array = new T[10];
185  Array.Copy(rules, 0, array, 1, 9);
186  }
187  array[0] = newRule;
188  Rules = array;
189  }
190 
191  internal void MoveRule(int i)
192  {
193  T[] rules = Rules;
194  T val = rules[i];
195  rules[i] = rules[i - 1];
196  rules[i - 1] = rules[i - 2];
197  rules[i - 2] = val;
198  }
199 
200  internal T MakeUpdateDelegate()
201  {
202  Type typeFromHandle = typeof(T);
203  MethodInfo method = typeFromHandle.GetMethod("Invoke");
204  if (typeFromHandle.IsGenericType && IsSimpleSignature(method, out Type[] sig))
205  {
206  MethodInfo methodInfo = null;
207  MethodInfo methodInfo2 = null;
208  if (method.ReturnType == typeof(void))
209  {
210  if (typeFromHandle == DelegateHelpers.GetActionType(sig.AddFirst(typeof(CallSite))))
211  {
212  methodInfo = typeof(UpdateDelegates).GetMethod("UpdateAndExecuteVoid" + sig.Length, BindingFlags.Static | BindingFlags.NonPublic);
213  methodInfo2 = typeof(UpdateDelegates).GetMethod("NoMatchVoid" + sig.Length, BindingFlags.Static | BindingFlags.NonPublic);
214  }
215  }
216  else if (typeFromHandle == DelegateHelpers.GetFuncType(sig.AddFirst(typeof(CallSite))))
217  {
218  methodInfo = typeof(UpdateDelegates).GetMethod("UpdateAndExecute" + (sig.Length - 1), BindingFlags.Static | BindingFlags.NonPublic);
219  methodInfo2 = typeof(UpdateDelegates).GetMethod("NoMatch" + (sig.Length - 1), BindingFlags.Static | BindingFlags.NonPublic);
220  }
221  if (methodInfo != null)
222  {
223  _CachedNoMatch = (T)(object)CreateDelegateHelper(typeFromHandle, methodInfo2.MakeGenericMethod(sig));
224  return (T)(object)CreateDelegateHelper(typeFromHandle, methodInfo.MakeGenericMethod(sig));
225  }
226  }
227  _CachedNoMatch = CreateCustomNoMatchDelegate(method);
228  return CreateCustomUpdateDelegate(method);
229  }
230 
231  private static Delegate CreateDelegateHelper(Type delegateType, MethodInfo method)
232  {
233  return Delegate.CreateDelegate(delegateType, method);
234  }
235 
236  private static bool IsSimpleSignature(MethodInfo invoke, out Type[] sig)
237  {
238  ParameterInfo[] parametersCached = invoke.GetParametersCached();
239  ContractUtils.Requires(parametersCached.Length != 0 && parametersCached[0].ParameterType == typeof(CallSite), "T");
240  Type[] array = new Type[(invoke.ReturnType != typeof(void)) ? parametersCached.Length : (parametersCached.Length - 1)];
241  bool result = true;
242  for (int i = 1; i < parametersCached.Length; i++)
243  {
244  ParameterInfo parameterInfo = parametersCached[i];
245  if (parameterInfo.IsByRefParameter())
246  {
247  result = false;
248  }
249  array[i - 1] = parameterInfo.ParameterType;
250  }
251  if (invoke.ReturnType != typeof(void))
252  {
253  array[array.Length - 1] = invoke.ReturnType;
254  }
255  sig = array;
256  return result;
257  }
258 
259  private T CreateCustomNoMatchDelegate(MethodInfo invoke)
260  {
261  ParameterExpression[] array = invoke.GetParametersCached().Map((ParameterInfo p) => Expression.Parameter(p.ParameterType, p.Name));
262  return Expression.Lambda<T>(Expression.Block(Expression.Call(typeof(CallSiteOps).GetMethod("SetNotMatched"), array.First()), Expression.Default(invoke.GetReturnType())), array).Compile();
263  }
264 
265  private T CreateCustomUpdateDelegate(MethodInfo invoke)
266  {
267  List<Expression> list = new List<Expression>();
269  ParameterExpression[] array = invoke.GetParametersCached().Map((ParameterInfo p) => Expression.Parameter(p.ParameterType, p.Name));
270  LabelTarget labelTarget = Expression.Label(invoke.GetReturnType());
271  Type[] typeArguments = new Type[1]
272  {
273  typeof(T)
274  };
275  ParameterExpression parameterExpression = array[0];
276  ParameterExpression[] collection = array.RemoveFirst();
277  ParameterExpression parameterExpression2 = Expression.Variable(typeof(CallSite<T>), "this");
278  list2.Add(parameterExpression2);
279  list.Add(Expression.Assign(parameterExpression2, Expression.Convert(parameterExpression, parameterExpression2.Type)));
280  ParameterExpression parameterExpression3 = Expression.Variable(typeof(T[]), "applicable");
281  list2.Add(parameterExpression3);
282  ParameterExpression parameterExpression4 = Expression.Variable(typeof(T), "rule");
283  list2.Add(parameterExpression4);
284  ParameterExpression parameterExpression5 = Expression.Variable(typeof(T), "originalRule");
285  list2.Add(parameterExpression5);
286  list.Add(Expression.Assign(parameterExpression5, Expression.Field(parameterExpression2, "Target")));
287  ParameterExpression parameterExpression6 = null;
288  if (labelTarget.Type != typeof(void))
289  {
290  list2.Add(parameterExpression6 = Expression.Variable(labelTarget.Type, "result"));
291  }
292  ParameterExpression parameterExpression7 = Expression.Variable(typeof(int), "count");
293  list2.Add(parameterExpression7);
294  ParameterExpression parameterExpression8 = Expression.Variable(typeof(int), "index");
295  list2.Add(parameterExpression8);
296  list.Add(Expression.Assign(parameterExpression, Expression.Call(typeof(CallSiteOps), "CreateMatchmaker", typeArguments, parameterExpression2)));
297  Expression test = Expression.Call(typeof(CallSiteOps).GetMethod("GetMatch"), parameterExpression);
298  Expression expression = Expression.Call(typeof(CallSiteOps).GetMethod("ClearMatch"), parameterExpression);
299  MethodCallExpression arg = Expression.Call(typeof(CallSiteOps), "UpdateRules", typeArguments, parameterExpression2, parameterExpression8);
300  Expression arg2 = (!(labelTarget.Type == typeof(void))) ? Expression.Block(Expression.Assign(parameterExpression6, Expression.Invoke(parameterExpression4, new TrueReadOnlyCollection<Expression>(array))), Expression.IfThen(test, Expression.Block(arg, Expression.Return(labelTarget, parameterExpression6)))) : Expression.Block(Expression.Invoke(parameterExpression4, new TrueReadOnlyCollection<Expression>(array)), Expression.IfThen(test, Expression.Block(arg, Expression.Return(labelTarget))));
301  Expression arg3 = Expression.Assign(parameterExpression4, Expression.ArrayAccess(parameterExpression3, parameterExpression8));
302  LabelTarget labelTarget2 = Expression.Label();
303  ConditionalExpression arg4 = Expression.IfThen(Expression.Equal(parameterExpression8, parameterExpression7), Expression.Break(labelTarget2));
304  UnaryExpression unaryExpression = Expression.PreIncrementAssign(parameterExpression8);
305  list.Add(Expression.IfThen(Expression.NotEqual(Expression.Assign(parameterExpression3, Expression.Call(typeof(CallSiteOps), "GetRules", typeArguments, parameterExpression2)), Expression.Constant(null, parameterExpression3.Type)), Expression.Block(Expression.Assign(parameterExpression7, Expression.ArrayLength(parameterExpression3)), Expression.Assign(parameterExpression8, Expression.Constant(0)), Expression.Loop(Expression.Block(arg4, arg3, Expression.IfThen(Expression.NotEqual(Expression.Convert(parameterExpression4, typeof(object)), Expression.Convert(parameterExpression5, typeof(object))), Expression.Block(Expression.Assign(Expression.Field(parameterExpression2, "Target"), parameterExpression4), arg2, expression)), unaryExpression), labelTarget2, null))));
306  ParameterExpression parameterExpression9 = Expression.Variable(typeof(RuleCache<T>), "cache");
307  list2.Add(parameterExpression9);
308  list.Add(Expression.Assign(parameterExpression9, Expression.Call(typeof(CallSiteOps), "GetRuleCache", typeArguments, parameterExpression2)));
309  list.Add(Expression.Assign(parameterExpression3, Expression.Call(typeof(CallSiteOps), "GetCachedRules", typeArguments, parameterExpression9)));
310  arg2 = ((!(labelTarget.Type == typeof(void))) ? Expression.Block(Expression.Assign(parameterExpression6, Expression.Invoke(parameterExpression4, new TrueReadOnlyCollection<Expression>(array))), Expression.IfThen(test, Expression.Return(labelTarget, parameterExpression6))) : Expression.Block(Expression.Invoke(parameterExpression4, new TrueReadOnlyCollection<Expression>(array)), Expression.IfThen(test, Expression.Return(labelTarget))));
311  TryExpression arg5 = Expression.TryFinally(arg2, Expression.IfThen(test, Expression.Block(Expression.Call(typeof(CallSiteOps), "AddRule", typeArguments, parameterExpression2, parameterExpression4), Expression.Call(typeof(CallSiteOps), "MoveRule", typeArguments, parameterExpression9, parameterExpression4, parameterExpression8))));
312  arg3 = Expression.Assign(Expression.Field(parameterExpression2, "Target"), Expression.Assign(parameterExpression4, Expression.ArrayAccess(parameterExpression3, parameterExpression8)));
313  list.Add(Expression.Assign(parameterExpression8, Expression.Constant(0)));
314  list.Add(Expression.Assign(parameterExpression7, Expression.ArrayLength(parameterExpression3)));
315  list.Add(Expression.Loop(Expression.Block(arg4, arg3, arg5, expression, unaryExpression), labelTarget2, null));
316  list.Add(Expression.Assign(parameterExpression4, Expression.Constant(null, parameterExpression4.Type)));
317  ParameterExpression parameterExpression10 = Expression.Variable(typeof(object[]), "args");
318  list2.Add(parameterExpression10);
319  list.Add(Expression.Assign(parameterExpression10, Expression.NewArrayInit(typeof(object), collection.Map((ParameterExpression p) => Convert(p, typeof(object))))));
320  Expression arg6 = Expression.Assign(Expression.Field(parameterExpression2, "Target"), parameterExpression5);
321  arg3 = Expression.Assign(Expression.Field(parameterExpression2, "Target"), Expression.Assign(parameterExpression4, Expression.Call(typeof(CallSiteOps), "Bind", typeArguments, Expression.Property(parameterExpression2, "Binder"), parameterExpression2, parameterExpression10)));
322  arg5 = Expression.TryFinally(arg2, Expression.IfThen(test, Expression.Call(typeof(CallSiteOps), "AddRule", typeArguments, parameterExpression2, parameterExpression4)));
323  list.Add(Expression.Loop(Expression.Block(arg6, arg3, arg5, expression), null, null));
324  list.Add(Expression.Default(labelTarget.Type));
325  Expression<T> expression2 = Expression.Lambda<T>(Expression.Label(labelTarget, Expression.Block(new ReadOnlyCollection<ParameterExpression>(list2), new ReadOnlyCollection<Expression>(list))), "CallSite.Target", tailCall: true, new ReadOnlyCollection<ParameterExpression>(array));
326  return expression2.Compile();
327  }
328 
329  private static Expression Convert(Expression arg, Type type)
330  {
331  if (TypeUtils.AreReferenceAssignable(type, arg.Type))
332  {
333  return arg;
334  }
335  return Expression.Convert(arg, type);
336  }
337  }
338 }
Discovers the attributes of a parameter and provides access to parameter metadata.
override Type Type
Gets the static type of the expression that this T:System.Linq.Expressions.Expression represents.
Discovers the attributes of a method and provides access to method metadata.
Definition: MethodInfo.cs:13
Type Type
The type of value that is passed when jumping to the label (or T:System.Void if no value should be pa...
Definition: LabelTarget.cs:27
Represents a multicast delegate; that is, a delegate that can have more than one element in its invoc...
BindingFlags
Specifies flags that control binding and the way in which the search for members and types is conduct...
Definition: BindingFlags.cs:10
Definition: __Canon.cs:3
virtual Type ReturnType
Gets the return type of this method.
Definition: MethodInfo.cs:23
virtual MethodInfo MakeGenericMethod(params Type[] typeArguments)
Substitutes the elements of an array of types for the type parameters of the current generic method d...
Definition: MethodInfo.cs:134
A dynamic call site base class. This type is used as a parameter type to the dynamic site targets.
Definition: CallSite.cs:13
Used to represent the target of a T:System.Linq.Expressions.GotoExpression.
Definition: LabelTarget.cs:5
static CallSite< T > Create(CallSiteBinder binder)
Creates an instance of the dynamic call site, initialized with the binder responsible for the runtime...
Definition: CallSite.cs:129
virtual bool IsSubclassOf(Type c)
Determines whether the current T:System.Type derives from the specified T:System.Type.
Definition: Type.cs:2664
void Add(T item)
Adds an object to the end of the T:System.Collections.Generic.List`1.
Definition: List.cs:510
Provides the base class from which the classes that represent expression tree nodes are derived....
Definition: Expression.cs:17
T Update
The update delegate. Called when the dynamic site experiences cache miss.
Definition: CallSite.cs:97
Represents a delegate, which is a data structure that refers to a static method or to a class instanc...
Definition: Delegate.cs:15
Represents type declarations: class types, interface types, array types, value types,...
Definition: Type.cs:18
Represents a named parameter expression.
Selects a member from a list of candidates, and performs type conversion from actual argument type to...
Definition: Binder.cs:10
static CallSite Create(Type delegateType, CallSiteBinder binder)
Creates a call site with the given delegate type and binder.
Definition: CallSite.cs:43
Represents a collection of keys and values.To browse the .NET Framework source code for this type,...
Definition: Dictionary.cs:17
Represents a try/catch/finally/fault block.
Represents a strongly typed list of objects that can be accessed by index. Provides methods to search...
Definition: List.cs:14
Class responsible for runtime binding of the dynamic operations on the dynamic call site.
Represents an expression that has a unary operator.
virtual Type ParameterType
Gets the Type of this parameter.
Represents a call to either static or an instance method.
Represents an expression that has a conditional operator.
void Clear()
Removes all keys and values from the T:System.Collections.Generic.Dictionary`2.
Definition: Dictionary.cs:1280
T Target
The Level 0 cache - a delegate specialized based on the site history.
Definition: CallSite.cs:83
virtual string Name
Gets the name of the parameter.
static Delegate CreateDelegate(Type type, object target, string method)
Creates a delegate of the specified type that represents the specified instance method to invoke on t...
Definition: Delegate.cs:368
Attribute can be applied to a delegate.