PageRenderTime 60ms CodeModel.GetById 16ms app.highlight 34ms RepoModel.GetById 1ms app.codeStats 1ms

/Microsoft.Scripting.Core/Actions/CallSite.cs

https://bitbucket.org/stefanrusek/xronos
C# | 737 lines | 449 code | 93 blank | 195 comment | 38 complexity | 447b957aefdd84fbafd9edd70366d652 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 * ***************************************************************************/
 15using System; using Microsoft;
 16
 17
 18using System.Collections.Generic;
 19using System.Collections.ObjectModel;
 20using System.Diagnostics;
 21#if CODEPLEX_40
 22using System.Dynamic;
 23using System.Dynamic.Utils;
 24using System.Linq.Expressions;
 25using System.Linq.Expressions.Compiler;
 26#else
 27using Microsoft.Scripting;
 28using Microsoft.Scripting.Utils;
 29using Microsoft.Linq.Expressions;
 30using Microsoft.Linq.Expressions.Compiler;
 31#endif
 32using System.Reflection;
 33using System.Threading;
 34using System.Collections;
 35
 36#if CODEPLEX_40
 37namespace System.Runtime.CompilerServices {
 38#else
 39namespace Microsoft.Runtime.CompilerServices {
 40#endif
 41
 42    //
 43    // A CallSite provides a fast mechanism for call-site caching of dynamic dispatch
 44    // behvaior. Each site will hold onto a delegate that provides a fast-path dispatch
 45    // based on previous types that have been seen at the call-site. This delegate will
 46    // call UpdateAndExecute if it is called with types that it hasn't seen before.
 47    // Updating the binding will typically create (or lookup) a new delegate
 48    // that supports fast-paths for both the new type and for any types that 
 49    // have been seen previously.
 50    // 
 51    // DynamicSites will generate the fast-paths specialized for sets of runtime argument
 52    // types. However, they will generate exactly the right amount of code for the types
 53    // that are seen in the program so that int addition will remain as fast as it would
 54    // be with custom implementation of the addition, and the user-defined types can be
 55    // as fast as ints because they will all have the same optimal dynamically generated
 56    // fast-paths.
 57    // 
 58    // DynamicSites don't encode any particular caching policy, but use their
 59    // CallSiteBinding to encode a caching policy.
 60    //
 61
 62
 63    /// <summary>
 64    /// A Dynamic Call Site base class. This type is used as a parameter type to the
 65    /// dynamic site targets. The first parameter of the delegate (T) below must be
 66    /// of this type.
 67    /// </summary>
 68    public class CallSite {
 69
 70        // Cache of CallSite constructors for a given delegate type
 71        private static CacheDict<Type, Func<CallSiteBinder, CallSite>> _SiteCtors;
 72
 73        /// <summary>
 74        /// The Binder responsible for binding operations at this call site.
 75        /// This binder is invoked by the UpdateAndExecute below if all Level 0,
 76        /// Level 1 and Level 2 caches experience cache miss.
 77        /// </summary>
 78        internal readonly CallSiteBinder _binder;
 79
 80        // only CallSite<T> derives from this
 81        internal CallSite(CallSiteBinder binder) {
 82            _binder = binder;
 83        }
 84
 85        /// <summary>
 86        /// used by Matchmaker sites to indicate rule match.
 87        /// </summary>
 88        internal bool _match;
 89
 90        /// <summary>
 91        /// Class responsible for binding dynamic operations on the dynamic site.
 92        /// </summary>
 93        public CallSiteBinder Binder {
 94            get { return _binder; }
 95        }
 96
 97        /// <summary>
 98        /// Creates a CallSite with the given delegate type and binder.
 99        /// </summary>
100        /// <param name="delegateType">The CallSite delegate type.</param>
101        /// <param name="binder">The CallSite binder.</param>
102        /// <returns>The new CallSite.</returns>
103        public static CallSite Create(Type delegateType, CallSiteBinder binder) {
104            ContractUtils.RequiresNotNull(delegateType, "delegateType");
105            ContractUtils.RequiresNotNull(binder, "binder");
106            ContractUtils.Requires(delegateType.IsSubclassOf(typeof(Delegate)), "delegateType", Strings.TypeMustBeDerivedFromSystemDelegate);
107
108            if (_SiteCtors == null) {
109                // It's okay to just set this, worst case we're just throwing away some data
110                _SiteCtors = new CacheDict<Type, Func<CallSiteBinder, CallSite>>(100);
111            }
112            Func<CallSiteBinder, CallSite> ctor;
113
114            var ctors = _SiteCtors;
115            lock (ctors) {
116                if (!ctors.TryGetValue(delegateType, out ctor)) {
117                    MethodInfo method = typeof(CallSite<>).MakeGenericType(delegateType).GetMethod("Create");
118                    ctor = (Func<CallSiteBinder, CallSite>)Delegate.CreateDelegate(typeof(Func<CallSiteBinder, CallSite>), method);
119                    ctors.Add(delegateType, ctor);
120                }
121            }
122            return ctor(binder);
123        }
124    }
125
126    /// <summary>
127    /// Dynamic site type.
128    /// </summary>
129    /// <typeparam name="T">The delegate type.</typeparam>
130    public sealed partial class CallSite<T> : CallSite where T : class {
131        /// <summary>
132        /// The update delegate. Called when the dynamic site experiences cache miss.
133        /// </summary>
134        /// <returns>The update delegate.</returns>
135        public T Update {
136            get {
137                // if this site is set up for match making, then use NoMatch as an Update 
138                if (_match) {
139                    Debug.Assert(_CachedNoMatch != null, "all normal sites should have Update cached once there is an instance.");
140                    return _CachedNoMatch;
141                } else {
142                    Debug.Assert(_CachedUpdate != null, "all normal sites should have Update cached once there is an instance.");
143                    return _CachedUpdate;
144                }
145            }
146        }
147
148        /// <summary>
149        /// The Level 0 cache - a delegate specialized based on the site history.
150        /// </summary>
151        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")]
152        public T Target;
153
154
155        /// <summary>
156        /// The Level 1 cache - a history of the dynamic site.
157        /// </summary>
158        internal SmallRuleSet<T> Rules;
159
160
161        // Cached update delegate for all sites with a given T
162        private static T _CachedUpdate;
163
164        // Cached noMatch delegate for all sites with a given T
165        private static T _CachedNoMatch;
166
167        private CallSite(CallSiteBinder binder)
168            : base(binder) {
169            Target = GetUpdateDelegate();
170        }
171
172        private CallSite()
173            : base(null) {
174        }
175
176        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
177        internal CallSite<T> CreateMatchMaker() {
178            return new CallSite<T>();
179        }
180
181        /// <summary>
182        /// Creates an instance of the dynamic call site, initialized with the binder responsible for the
183        /// runtime binding of the dynamic operations at this call site.
184        /// </summary>
185        /// <param name="binder">The binder responsible for the runtime binding of the dynamic operations at this call site.</param>
186        /// <returns>The new instance of dynamic call site.</returns>
187        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")]
188        public static CallSite<T> Create(CallSiteBinder binder) {
189            return new CallSite<T>(binder);
190        }
191
192        private T GetUpdateDelegate() {
193            // This is intentionally non-static to speed up creation - in particular MakeUpdateDelegate
194            // as static generic methods are more expensive than instance methods.  We call a ref helper
195            // so we only access the generic static field once.
196            return GetUpdateDelegate(ref _CachedUpdate);
197        }
198
199        private T GetUpdateDelegate(ref T addr) {
200            if (addr == null) {
201                // reduce creation cost by not using Interlocked.CompareExchange.  Calling I.CE causes
202                // us to spend 25% of our creation time in JIT_GenericHandle.  Instead we'll rarely
203                // create 2 delegates with no other harm caused.
204                addr = MakeUpdateDelegate();
205            }
206            return addr;
207        }
208
209        /// <summary>
210        /// Clears the rule cache ... used by the call site tests.
211        /// </summary>
212        private void ClearRuleCache() {
213            // make sure it initialized/atomized etc...
214            Binder.GetRuleCache<T>();
215
216            var cache = Binder.Cache;
217
218            if (cache != null) {
219                lock (cache) {
220                    cache.Clear();
221                }
222            }
223        }
224
225        internal T MakeUpdateDelegate() {
226            Type target = typeof(T);
227            Type[] args;
228            MethodInfo invoke = target.GetMethod("Invoke");
229
230
231            if (target.IsGenericType && IsSimpleSignature(invoke, out args)) {
232                MethodInfo method = null;
233                MethodInfo noMatchMethod = null;
234
235                if (invoke.ReturnType == typeof(void)) {
236                    if (target == DelegateHelpers.GetActionType(args.AddFirst(typeof(CallSite)))) {
237                        method = typeof(UpdateDelegates).GetMethod("UpdateAndExecuteVoid" + args.Length, BindingFlags.NonPublic | BindingFlags.Static);
238                        noMatchMethod = typeof(UpdateDelegates).GetMethod("NoMatchVoid" + args.Length, BindingFlags.NonPublic | BindingFlags.Static);
239                    }
240                } else {
241                    if (target == DelegateHelpers.GetFuncType(args.AddFirst(typeof(CallSite)))) {
242                        method = typeof(UpdateDelegates).GetMethod("UpdateAndExecute" + (args.Length - 1), BindingFlags.NonPublic | BindingFlags.Static);
243                        noMatchMethod = typeof(UpdateDelegates).GetMethod("NoMatch" + (args.Length - 1), BindingFlags.NonPublic | BindingFlags.Static);
244                    }
245                }
246                if (method != null) {
247                    _CachedNoMatch = (T)(object)noMatchMethod.MakeGenericMethod(args).CreateDelegate(target);
248                    return (T)(object)method.MakeGenericMethod(args).CreateDelegate(target);
249                }
250            }
251
252            _CachedNoMatch = CreateCustomNoMatchDelegate(invoke);
253            return CreateCustomUpdateDelegate(invoke);
254        }
255
256
257        private static bool IsSimpleSignature(MethodInfo invoke, out Type[] sig) {
258            ParameterInfo[] pis = invoke.GetParametersCached();
259            ContractUtils.Requires(pis.Length > 0 && pis[0].ParameterType == typeof(CallSite), "T");
260
261            Type[] args = new Type[invoke.ReturnType != typeof(void) ? pis.Length : pis.Length - 1];
262            bool supported = true;
263
264            for (int i = 1; i < pis.Length; i++) {
265                ParameterInfo pi = pis[i];
266                if (pi.IsByRefParameter()) {
267                    supported = false;
268                }
269                args[i - 1] = pi.ParameterType;
270            }
271            if (invoke.ReturnType != typeof(void)) {
272                args[args.Length - 1] = invoke.ReturnType;
273            }
274            sig = args;
275            return supported;
276        }
277
278
279        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
280        private T CreateCustomNoMatchDelegate(MethodInfo invoke) {
281            var @params = invoke.GetParametersCached().Map(p => Expression.Parameter(p.ParameterType, p.Name));
282            var site = @params[0];
283            return Expression.Lambda<T>(
284                Expression.Block(
285                    Expression.Call(
286                        typeof(CallSiteOps).GetMethod("SetNotMatched"),
287                        @params.First()
288                    ),
289                    Expression.Default(invoke.GetReturnType())
290                ),
291                @params
292            ).Compile();
293        }
294
295        //
296        // WARNING: If you're changing this method, make sure you update the
297        // pregenerated versions as well, which are generated by
298        // generate_dynsites.py
299        // The two implementations *must* be kept functionally equivalent!
300        //
301        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
302        private T CreateCustomUpdateDelegate(MethodInfo invoke) {
303            var body = new List<Expression>();
304            var vars = new List<ParameterExpression>();
305            var @params = invoke.GetParametersCached().Map(p => Expression.Parameter(p.ParameterType, p.Name));
306            var @return = Expression.Label(invoke.GetReturnType());
307            var typeArgs = new[] { typeof(T) };
308
309            var site = @params[0];
310            var arguments = @params.RemoveFirst();
311
312            //var @this = (CallSite<T>)site;
313            var @this = Expression.Variable(typeof(CallSite<T>), "this");
314            vars.Add(@this);
315            body.Add(Expression.Assign(@this, Expression.Convert(site, @this.Type)));
316
317            //T[] applicable;
318            var applicable = Expression.Variable(typeof(T[]), "applicable");
319            vars.Add(applicable);
320
321            //T rule, originalRule = @this.Target;
322            var rule = Expression.Variable(typeof(T), "rule");
323            vars.Add(rule);
324
325            var originalRule = Expression.Variable(typeof(T), "originalRule");
326            vars.Add(originalRule);
327
328            //TRet result;
329            ParameterExpression result = null;
330            if (@return.Type != typeof(void)) {
331                vars.Add(result = Expression.Variable(@return.Type, "result"));
332            }
333
334            //int count, index;
335            var count = Expression.Variable(typeof(int), "count");
336            vars.Add(count);
337            var index = Expression.Variable(typeof(int), "index");
338            vars.Add(index);
339
340            ////
341            //// Create matchmaker site. We'll need it regardless.
342            ////
343            //site = CallSiteOps.CreateMatchmaker();
344            body.Add(
345                Expression.Assign(
346                    site,
347                    Expression.Call(
348                        typeof(CallSiteOps),
349                        "CreateMatchmaker",
350                        typeArgs, 
351                        @this
352                    )
353                )
354            );
355
356            ////
357            //// Level 1 cache lookup
358            ////
359            //if ((applicable = CallSiteOps.GetRules(@this)) != null) {
360            //    for (index = 0, count = applicable.Length; index < count; index++) {
361            //        @this.Target = rule = applicable[i];
362
363            //        //
364            //        // Execute the rule
365            //        //
366            //
367            //        // if we've already tried it skip it...
368            //        if ((object)rule != (object)originalRule) {
369            //            %(setResult)s rule(site, %(args)s);
370            //            if (CallSiteOps.GetMatch(site)) {
371            //                CallSiteOps.UpdateRules(@this, i);
372            //                %(returnResult)s;
373            //            }
374            //
375            //            // Rule didn't match, try the next one
376            //            CallSiteOps.ClearMatch(site);
377            //        }
378            //    }
379            //}
380            Expression invokeRule;
381
382            Expression getMatch = Expression.Call(
383                typeof(CallSiteOps).GetMethod("GetMatch"),
384                site
385            );
386
387            Expression resetMatch = Expression.Call(
388                typeof(CallSiteOps).GetMethod("ClearMatch"),
389                site
390            );
391
392            var onMatch = Expression.Call(
393                typeof(CallSiteOps),
394                "UpdateRules",
395                typeArgs,
396                @this,
397                index
398            );
399
400            if (@return.Type == typeof(void)) {
401                invokeRule = Expression.Block(
402                    Expression.Invoke(rule, new TrueReadOnlyCollection<Expression>(@params)),
403                    Expression.IfThen(
404                        getMatch,
405                        Expression.Block(onMatch, Expression.Return(@return))
406                    )
407                );
408            } else {
409                invokeRule = Expression.Block(
410                    Expression.Assign(result, Expression.Invoke(rule, new TrueReadOnlyCollection<Expression>(@params))),
411                    Expression.IfThen(
412                        getMatch,
413                        Expression.Block(onMatch, Expression.Return(@return, result))
414                    )
415                );
416            }
417
418            Expression getRule = Expression.Assign(
419                rule,
420                Expression.ArrayAccess(applicable, index)
421            );
422
423            var @break = Expression.Label();
424
425            var breakIfDone = Expression.IfThen(
426                Expression.Equal(index, count),
427                Expression.Break(@break)
428            );
429
430            var incrementIndex = Expression.PreIncrementAssign(index);
431
432            body.Add(
433                Expression.IfThen(
434                    Expression.NotEqual(
435                        Expression.Assign(applicable, Expression.Call(typeof(CallSiteOps), "GetRules", typeArgs, @this)),
436                        Expression.Constant(null, applicable.Type)
437                    ),
438                    Expression.Block(
439                        Expression.Assign(count, Expression.ArrayLength(applicable)),
440                        Expression.Assign(index, Expression.Constant(0)),
441                        Expression.Loop(
442                            Expression.Block(
443                                breakIfDone,
444                                getRule,
445                                Expression.IfThen(
446                                    Expression.NotEqual(
447                                        Expression.Convert(rule, typeof(object)),
448                                        Expression.Convert(originalRule, typeof(object))
449                                    ),
450                                    Expression.Block(
451                                        Expression.Assign(
452                                            Expression.Field(
453                                                @this,
454                                                "Target"
455                                            ),
456                                            rule
457                                        ),
458                                        invokeRule,
459                                        resetMatch
460                                    )
461                                ),
462                                incrementIndex
463                            ),
464                            @break,
465                            null
466                        )
467                    )
468                )
469            );
470
471            ////
472            //// Level 2 cache lookup
473            ////
474            // i = 0;
475            // var cache = @this.Binder.GetRuleCache<%(funcType)s>();
476
477            var cache = Expression.Variable(typeof(RuleCache<T>), "cache");
478            vars.Add(cache);
479
480            body.Add(
481                Expression.Assign(
482                    cache,
483                    Expression.Call(typeof(CallSiteOps), "GetRuleCache", typeArgs, @this)
484                )
485            );
486
487            body.Add(
488                Expression.Assign(
489                    index,
490                    Expression.Constant(0)
491                )
492            );
493
494            ////
495            //// Any applicable rules in level 2 cache?
496            ////
497            //    foreach (var cachedRule in CallSiteOps.GetCachedRules<%(funcType)s>(cache)) {
498
499            ParameterExpression enumerator = Expression.Parameter(typeof(IEnumerator<>).MakeGenericType(typeArgs), "enum");
500            vars.Add(enumerator);
501
502            body.Add(
503                Expression.Assign(
504                    enumerator,
505                    Expression.Call(
506                        Expression.Call(
507                            typeof(CallSiteOps),
508                            "GetCachedRules",
509                            typeArgs,
510                            cache
511                        ),
512                        typeof(IEnumerable<>).MakeGenericType(typeArgs).GetMethod("GetEnumerator")
513                    )
514                )
515            );
516
517
518            //        @this.Target = rule;
519            //
520            //        //
521            //        // Execute the rule
522            //        //
523            //
524            //        try {
525            //            result = rule(site, arg0);
526            //            if (match) {
527            //                return result;
528            //            }
529            //        } finally {
530            //            if (CallSiteOps.GetMatch(site)) {
531            //                //
532            //                // Rule worked. Add it to level 1 cache
533            //                //
534            //
535            //                CallSiteOps.AddRule(@this, rule);
536            //                // and then move it to the front of the L2 cache
537            //                CallSiteOps.MoveRule(cache, rule, index);
538            //            }
539            //        }
540            //
541            //        // Rule didn't match, try the next one
542            //        CallSiteOps.ClearMatch(site);
543            //    }
544            //
545
546
547            // L2 invokeRule is different (no onMatch)
548            if (@return.Type == typeof(void)) {
549                invokeRule = Expression.Block(
550                    Expression.Invoke(rule, new TrueReadOnlyCollection<Expression>(@params)),
551                    Expression.IfThen(
552                        getMatch,
553                        Expression.Return(@return)
554                    )
555                );
556            } else {
557                invokeRule = Expression.Block(
558                    Expression.Assign(result, Expression.Invoke(rule, new TrueReadOnlyCollection<Expression>(@params))),
559                    Expression.IfThen(
560                        getMatch,
561                        Expression.Return(@return, result)
562                    )
563                );
564            }
565
566            var tryRule = Expression.TryFinally(
567                invokeRule,
568                Expression.IfThen(
569                    getMatch,
570                    Expression.Block(
571                        Expression.Call(typeof(CallSiteOps), "AddRule", typeArgs, @this, rule),
572                        Expression.Call(typeof(CallSiteOps), "MoveRule", typeArgs, cache, rule, index)
573                    )
574                )
575            );
576
577            body.Add(
578                Expression.Assign(index, Expression.Constant(0))
579            );
580
581            breakIfDone = Expression.IfThen(
582                Expression.Not(
583                    Expression.Call(
584                        enumerator,
585                        typeof(IEnumerator).GetMethod("MoveNext")
586                    )
587                ),
588                Expression.Break(@break)
589            );
590
591            getRule = Expression.Assign(
592                rule,
593                Expression.Assign(
594                    Expression.Field(
595                        @this,
596                        "Target"
597                    ),
598                    Expression.Property(
599                        enumerator,
600                        "Current"
601                    )
602                )
603            );
604
605            body.Add(
606                Expression.Loop(
607                    Expression.Block(
608                        breakIfDone,
609                        getRule,
610                        tryRule,
611                        resetMatch,
612                        incrementIndex
613                    ),
614                    @break,
615                    null
616                )
617            );
618
619            ////
620            //// Miss on Level 0, 1 and 2 caches. Create new rule
621            ////
622
623            //rule = null;
624            body.Add(Expression.Assign(rule, Expression.Constant(null, rule.Type)));
625
626            //var args = new object[] { arg0, arg1, ... };
627            var args = Expression.Variable(typeof(object[]), "args");
628            vars.Add(args);
629            body.Add(
630                Expression.Assign(
631                    args,
632                    Expression.NewArrayInit(typeof(object), arguments.Map(p => Convert(p, typeof(object))))
633                )
634            );
635
636            //for (; ; ) {
637            //    @this.Target = originalRule;
638            //    rule = @this.Target = @this.Binder.BindDelegate(@this, args);
639
640            //    //
641            //    // Execute the rule on the matchmaker site
642            //    //
643
644            //    try {
645            //        %(setResult)s ruleTarget(site, %(args)s);
646            //        if (match) {
647            //            %(returnResult)s;
648            //        }
649            //    } finally {
650            //        if (match) {
651            //            //
652            //            // The rule worked. Add it to level 1 cache.
653            //            //
654            //            CallSiteOps.AddRule(@this, rule);
655            //        }
656            //    }
657
658            //    // Rule we got back didn't work, try another one
659            //    match = true;
660            //}
661
662            Expression setOldTarget = Expression.Assign(
663                Expression.Field(
664                    @this,
665                    "Target"
666                ),
667                originalRule
668            );
669
670            getRule = Expression.Assign(
671                Expression.Field(
672                    @this,
673                    "Target"
674                ),
675                Expression.Assign(
676                    rule,
677                    Expression.Call(
678                        Expression.Property(
679                            @this,
680                            "Binder"
681                        ),
682                        "BindDelegate",
683                        typeArgs,
684                        @this,
685                        args
686                    )
687                )
688            );
689
690            tryRule = Expression.TryFinally(
691                invokeRule,
692                Expression.IfThen(
693                    getMatch,
694                    Expression.Call(typeof(CallSiteOps), "AddRule", typeArgs, @this, rule)
695                )
696            );
697
698            body.Add(
699                Expression.Loop(
700                    Expression.Block(setOldTarget, getRule, tryRule, resetMatch),
701                    null, null
702                )
703            );
704
705            body.Add(Expression.Default(@return.Type));
706
707            var lambda = Expression.Lambda<T>(
708                Expression.Label(
709                    @return,
710                    Expression.Block(
711                        new ReadOnlyCollection<ParameterExpression>(vars),
712                        new ReadOnlyCollection<Expression>(body)
713                    )
714                ),
715                "CallSite.Target",
716                true, // always compile the rules with tail call optimization
717                new ReadOnlyCollection<ParameterExpression>(@params)
718            );
719
720            // Need to compile with forceDynamic because T could be invisible,
721            // or one of the argument types could be invisible
722            return lambda.Compile();
723        }
724
725        private static Expression Convert(Expression arg, Type type) {
726            if (TypeUtils.AreReferenceAssignable(type, arg.Type)) {
727                return arg;
728            }
729            return Expression.Convert(arg, type);
730        }
731
732        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
733        internal CallSiteRule<T> MakeRule(T target) {
734            return new CallSiteRule<T>(null, target);
735        }
736    }
737}