public Delegate CreateDelegate(Type delegateType, object dynamicObject) { Assert.NotNull(delegateType, dynamicObject); object[] closure; lock (_closureMap) { if (!_closureMap.TryGetValue(dynamicObject, out WeakReference weakClosure) || (closure = (object[])weakClosure.Target) == null) { closure = new[] { TargetPlaceHolder, CallSitePlaceHolder, ConvertSitePlaceHolder }; _closureMap[dynamicObject] = new WeakReference(closure); Type[] siteTypes = MakeSiteSignature(_parameterTypes); CallSite callSite = CallSite.Create(DynamicSiteHelpers.MakeCallSiteDelegate(siteTypes), _invokeBinder); CallSite convertSite = null; if (_returnType != typeof(void)) { convertSite = CallSite.Create(DynamicSiteHelpers.MakeCallSiteDelegate(typeof(object), _returnType), _convertBinder); } closure[TargetIndex] = dynamicObject; closure[CallSiteIndex] = callSite; closure[ConvertSiteIndex] = convertSite; } } return(_method.CreateDelegate(delegateType, closure)); }
internal Delegate CreateDelegate(Type delegateType, object target) { Assert.NotNull(delegateType, target); // to enable: // function x() { } // someClass.someEvent += delegateType(x) // someClass.someEvent -= delegateType(x) // // we need to avoid re-creating the object array because they won't // be compare equal when removing the delegate if they're difference // instances. Therefore we use a weak hashtable to get back the // original object array. The values also need to be weak to avoid // creating a circular reference from the constants target back to the // target. This is fine because as long as the delegate is referenced // the object array will stay alive. Once the delegate is gone it's not // wired up anywhere and -= will never be used again. object[] clone; lock (_constantMap) { WeakReference cloneRef; if (!_constantMap.TryGetValue(target, out cloneRef) || (clone = (object[])cloneRef.Target) == null) { _constantMap[target] = new WeakReference(clone = (object[])_constants.Clone()); Type[] siteTypes = MakeSiteSignature(); CallSite callSite = CallSite.Create(DynamicSiteHelpers.MakeCallSiteDelegate(siteTypes), _invokeBinder); Type siteType = callSite.GetType(); Type convertSiteType = null; CallSite convertSite = null; if (_returnType != typeof(void)) { convertSite = CallSite.Create(DynamicSiteHelpers.MakeCallSiteDelegate(typeof(object), _returnType), _convertBinder); convertSiteType = convertSite.GetType(); } Debug.Assert(clone[0] == TargetPlaceHolder); Debug.Assert(clone[1] == CallSitePlaceHolder); Debug.Assert(clone[2] == ConvertSitePlaceHolder); clone[0] = target; clone[1] = callSite; clone[2] = convertSite; } } return(ReflectionUtils.CreateDelegate(_method, delegateType, clone)); }
internal static Delegate CreateDelegateForDynamicObject(LanguageContext context, object dynamicObject, Type delegateType, MethodInfo invoke) { PerfTrack.NoteEvent(PerfTrack.Categories.DelegateCreate, delegateType.ToString()); Type returnType = invoke.ReturnType; ParameterInfo[] parameterInfos = invoke.GetParameters(); var parameters = new List <ParameterExpression>(); for (int i = 0; i < parameterInfos.Length; i++) { parameters.Add(Expression.Parameter(parameterInfos[i].ParameterType, "p" + i)); } InvokeBinder invokeBinder = context.CreateInvokeBinder(new CallInfo(parameterInfos.Length)); ConvertBinder convertBinder = (returnType != typeof(void)) ? context.CreateConvertBinder(returnType, explicitCast: true) : null; CallSite invokeSite = CallSite.Create(DynamicSiteHelpers.MakeCallSiteDelegate(MakeSiteSignature(parameterInfos)), invokeBinder); Type invokeSiteType = invokeSite.GetType(); Type convertSiteType; CallSite convertSite; if (convertBinder != null) { convertSite = CallSite.Create(DynamicSiteHelpers.MakeCallSiteDelegate(typeof(object), returnType), convertBinder); convertSiteType = convertSite.GetType(); } else { convertSiteType = null; convertSite = null; } var locals = new List <ParameterExpression>(); ParameterExpression invokeSiteVar = Expression.Parameter(invokeSiteType, "site"); ParameterExpression convertSiteVar = null; var args = new List <Expression>(); args.Add(invokeSiteVar); args.Add(Expression.Constant(dynamicObject)); int strongBoxVarsStart = locals.Count; for (int i = 0; i < parameterInfos.Length; i++) { if (parameterInfos[i].ParameterType.IsByRef) { var argType = parameterInfos[i].ParameterType; Type elementType = argType.GetElementType(); Type concreteType = typeof(StrongBox <>).MakeGenericType(elementType); var strongBox = Expression.Parameter(concreteType, "box" + i); locals.Add(strongBox); args.Add( Expression.Assign( strongBox, Expression.New( concreteType.GetConstructor(new Type[] { elementType }), parameters[i] ) ) ); } else { args.Add(parameters[i]); } } int strongBoxVarsEnd = locals.Count; Expression invocation = Expression.Invoke( Expression.Field( Expression.Assign( invokeSiteVar, Expression.Convert(Expression.Constant(invokeSite), invokeSiteType) ), invokeSiteType.GetDeclaredField("Target") ), args ); if (convertBinder != null) { convertSiteVar = Expression.Parameter(convertSiteType, "convertSite"); invocation = Expression.Invoke( Expression.Field( Expression.Assign( convertSiteVar, Expression.Convert(Expression.Constant(convertSite), convertSiteType) ), convertSiteType.GetDeclaredField("Target") ), convertSiteVar, invocation ); } locals.Add(invokeSiteVar); if (convertSiteVar != null) { locals.Add(convertSiteVar); } Expression body; // copy back from StrongBox.Value if (strongBoxVarsEnd > strongBoxVarsStart) { var block = new Expression[1 + strongBoxVarsEnd - strongBoxVarsStart + 1]; var resultVar = Expression.Parameter(invocation.Type, "result"); locals.Add(resultVar); int b = 0; int l = strongBoxVarsStart; // values of strong boxes are initialized in invocation expression: block[b++] = Expression.Assign(resultVar, invocation); for (int i = 0; i < parameterInfos.Length; i++) { if (parameterInfos[i].ParameterType.IsByRef) { var local = locals[l++]; block[b++] = Expression.Assign( parameters[i], Expression.Field(local, local.Type.GetDeclaredField("Value")) ); } } block[b++] = resultVar; Debug.Assert(l == strongBoxVarsEnd); Debug.Assert(b == block.Length); body = Expression.Block(locals, block); } else { body = Expression.Block(locals, invocation); } var lambda = Expression.Lambda(delegateType, body, "_Scripting_", parameters); return(lambda.Compile()); }
/// <summary> /// Generates stub to receive the CLR call and then call the dynamic language code. /// </summary> private void EmitClrCallStub(ILGen cg) { List <ReturnFixer> fixers = new List <ReturnFixer>(0); // Create strongly typed return type from the site. // This will, among other things, generate tighter code. Type[] siteTypes = MakeSiteSignature(_parameterTypes); CallSite callSite = CallSite.Create(DynamicSiteHelpers.MakeCallSiteDelegate(siteTypes), _invokeBinder); Type siteType = callSite.GetType(); Type convertSiteType = null; CallSite convertSite = null; if (_returnType != typeof(void)) { convertSite = CallSite.Create(DynamicSiteHelpers.MakeCallSiteDelegate(typeof(object), _returnType), _convertBinder); convertSiteType = convertSite.GetType(); } LocalBuilder convertSiteLocal = null; FieldInfo convertTarget = null; if (_returnType != typeof(void)) { // load up the conversion logic on the stack convertSiteLocal = cg.DeclareLocal(convertSiteType); EmitConstantGet(cg, ConvertSiteIndex, convertSiteType); cg.Emit(OpCodes.Dup); cg.Emit(OpCodes.Stloc, convertSiteLocal); convertTarget = convertSiteType.GetDeclaredField("Target"); cg.EmitFieldGet(convertTarget); cg.Emit(OpCodes.Ldloc, convertSiteLocal); } // load up the invoke logic on the stack LocalBuilder site = cg.DeclareLocal(siteType); EmitConstantGet(cg, CallSiteIndex, siteType); cg.Emit(OpCodes.Dup); cg.Emit(OpCodes.Stloc, site); FieldInfo target = siteType.GetDeclaredField("Target"); cg.EmitFieldGet(target); cg.Emit(OpCodes.Ldloc, site); EmitConstantGet(cg, TargetIndex, typeof(object)); for (int i = 0; i < _parameterTypes.Length; i++) { if (_parameterTypes[i].IsByRef) { ReturnFixer rf = ReturnFixer.EmitArgument(cg, i + 1, _parameterTypes[i]); if (rf != null) { fixers.Add(rf); } } else { cg.EmitLoadArg(i + 1); } } // emit the invoke for the call cg.EmitCall(target.FieldType, "Invoke"); // emit the invoke for the convert if (_returnType == typeof(void)) { cg.Emit(OpCodes.Pop); } else { cg.EmitCall(convertTarget.FieldType, "Invoke"); } // fixup any references foreach (ReturnFixer rf in fixers) { rf.FixReturn(cg); } cg.Emit(OpCodes.Ret); }