protected override Expression VisitDynamic(DynamicExpression node) { Type siteType = typeof(CallSite <>).MakeGenericType(node.DelegateType); // Rewite call site as constant var siteExpr = VisitConstant(Expression.Constant(DynamicSiteHelpers.MakeSite(node.Binder, siteType))); // Rewrite all of the arguments var args = Visit(node.Arguments); var siteVar = Expression.Variable(siteExpr.Type, "$site"); // ($site = siteExpr).Target.Invoke($site, *args) return(Expression.Block( new [] { siteVar }, Expression.Call( Expression.Field( Expression.Assign(siteVar, siteExpr), siteType.GetField("Target") ), node.DelegateType.GetMethod("Invoke"), ArrayUtils.Insert(siteVar, args) ) )); }
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)); }
private static IEnumerable <DynamicStackFrame> GetStackFrames(StackTrace trace, List <DynamicStackFrame> dynamicFrames, bool reverseOrder) { StackFrame[] frames = trace.GetFrames(); if (frames == null) { yield break; } foreach (StackFrame frame in WalkList(frames, reverseOrder)) { MethodBase method = frame.GetMethod(); Type parentType = method.DeclaringType; if (dynamicFrames.Count > 0 && frame.GetMethod() == dynamicFrames[dynamicFrames.Count - 1].GetMethod()) { yield return(dynamicFrames[dynamicFrames.Count - 1]); dynamicFrames.RemoveAt(dynamicFrames.Count - 1); continue; } if (parentType != null) { if (parentType == typeof(LambdaExpression) && method.Name == "DoExecute") { // Evaluated frame -- Replace with dynamic frame Debug.Assert(dynamicFrames.Count > 0); //if (dynamicFrames.Count == 0) continue; yield return(dynamicFrames[dynamicFrames.Count - 1]); dynamicFrames.RemoveAt(dynamicFrames.Count - 1); continue; } } if (DynamicSiteHelpers.IsInvisibleDlrStackFrame(method)) { continue; } if (method.DeclaringType != null && Snippets.Shared.IsSnippetsAssembly(method.DeclaringType.Assembly)) { yield return(GetStackFrame(frame)); } } }
private static MSA.LambdaExpression /*!*/ CreateLambda(string /*!*/ name, MSA.ParameterExpression /*!*/[] /*!*/ parameters, MSA.Expression /*!*/ body) { Type lambdaType = DynamicSiteHelpers.GetStandardDelegateType(AstFactory.GetSignature(parameters, typeof(object))); if (lambdaType == null) { // to many parameters for Func<> delegate -> use object[]: MSA.ParameterExpression array = Ast.Parameter(typeof(object[]), "#params"); var actualParameters = new MSA.ParameterExpression[] { parameters[0], parameters[1], array }; parameters = ArrayUtils.ShiftLeft(parameters, 2); var bodyWithParamInit = new MSA.Expression[parameters.Length + 1]; for (int i = 0; i < parameters.Length; i++) { bodyWithParamInit[i] = Ast.Assign(parameters[i], Ast.ArrayIndex(array, Ast.Constant(i))); } bodyWithParamInit[parameters.Length] = body; return(Ast.Lambda( RubyMethodInfo.ParamsArrayDelegateType, Ast.Block( new ReadOnlyCollection <MSA.ParameterExpression>(parameters), new ReadOnlyCollection <MSA.Expression>(bodyWithParamInit) ), name, new ReadOnlyCollection <MSA.ParameterExpression>(actualParameters) )); } else { return(Ast.Lambda( lambdaType, body, name, new ReadOnlyCollection <MSA.ParameterExpression>(parameters) )); } }
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); }
/// <summary> /// Generates stub to receive the CLR call and then call the dynamic language code. /// </summary> public static void EmitClrCallStub(CodeGen cg, Slot callTarget, int firstArg, CallType functionAttributes) { List <ReturnFixer> fixers = new List <ReturnFixer>(0); IList <Slot> args = cg.ArgumentSlots; int nargs = args.Count - firstArg; CallAction action; if ((functionAttributes & CallType.ArgumentList) != 0) { ArgumentInfo[] infos = CompilerHelpers.MakeRepeatedArray(ArgumentInfo.Simple, nargs); infos[nargs - 1] = new ArgumentInfo(ArgumentKind.List); action = CallAction.Make(new CallSignature(infos)); } else { action = CallAction.Make(nargs); } bool fast; Slot site = cg.CreateDynamicSite(action, CompilerHelpers.MakeRepeatedArray(typeof(object), nargs + 2), out fast); site.EmitGet(cg); if (!fast) { cg.EmitCodeContext(); } if (DynamicSiteHelpers.IsBigTarget(site.Type)) { cg.EmitTuple(site.Type.GetGenericArguments()[0], args.Count + 1, delegate(int index) { if (index == 0) { callTarget.EmitGet(cg); } else { ReturnFixer rf = ReturnFixer.EmitArgument(cg, args[index - 1]); if (rf != null) { fixers.Add(rf); } } }); } else { callTarget.EmitGet(cg); for (int i = firstArg; i < args.Count; i++) { ReturnFixer rf = ReturnFixer.EmitArgument(cg, args[i]); if (rf != null) { fixers.Add(rf); } } } cg.EmitCall(site.Type, "Invoke"); foreach (ReturnFixer rf in fixers) { rf.FixReturn(cg); } cg.EmitReturnFromObject(); }
/// <summary> /// Generates stub to receive the CLR call and then call the dynamic language code. /// </summary> private object[] EmitClrCallStub(ILGen cg) { List <ReturnFixer> fixers = new List <ReturnFixer>(0); ArgumentInfo[] args = new ArgumentInfo[_parameters.Length]; for (int i = 0; i < args.Length; i++) { args[i] = Expression.PositionalArg(i); } ConvertBinder convert = _context.CreateConvertBinder(_returnType, true); InvokeBinder action = _context.CreateInvokeBinder(args); // Create strongly typed return type from the site. // This will, among other things, generate tighter code. Type[] siteTypes = MakeSiteSignature(); Type siteType = DynamicSiteHelpers.MakeCallSiteType(siteTypes); CallSite callSite = DynamicSiteHelpers.MakeSite(action, siteType); Type convertSiteType = null; CallSite convertSite = null; if (_returnType != typeof(void)) { convertSiteType = DynamicSiteHelpers.MakeCallSiteType(typeof(object), _returnType); convertSite = DynamicSiteHelpers.MakeSite(convert, convertSiteType); } // build up constants array object[] constants = new object[] { TargetPlaceHolder, callSite, convertSite }; const int TargetIndex = 0, CallSiteIndex = 1, ConvertSiteIndex = 2; LocalBuilder convertSiteLocal = null; FieldInfo convertTarget = null; if (_returnType != typeof(void)) { // load up the conversesion logic on the stack convertSiteLocal = cg.DeclareLocal(convertSiteType); EmitConstantGet(cg, ConvertSiteIndex, convertSiteType); cg.Emit(OpCodes.Dup); cg.Emit(OpCodes.Stloc, convertSiteLocal); convertTarget = convertSiteType.GetField("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.GetField("Target"); cg.EmitFieldGet(target); cg.Emit(OpCodes.Ldloc, site); EmitConstantGet(cg, TargetIndex, typeof(object)); for (int i = 0; i < _parameters.Length; i++) { if (_parameters[i].ParameterType.IsByRef) { ReturnFixer rf = ReturnFixer.EmitArgument(cg, i + 1, _parameters[i].ParameterType); 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); return(constants); }