public sealed override DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args) { ContractUtils.RequiresNotNull(target, "target"); ContractUtils.RequiresNotNull(target, "args"); // there must be only one argument and it is always object[]. // see SplatCallSite.Invoke Debug.Assert(args.Length == 1); Debug.Assert(args[0] != null); Debug.Assert(args[0].Expression.Type == typeof(object[])); // We know it is an array. DynamicMetaObject arg = args[0]; Expression argAsArrayExpr = arg.Expression; object[] argValues = (object[])arg.Value; int argLen = argValues.Length; DynamicMetaObject[] splattedArgs = new DynamicMetaObject[argLen]; ArgumentInfo[] arginfos = new ArgumentInfo[argLen]; for (int i = 0; i < argLen; i++) { Expression argExpr = Expression.ArrayIndex( argAsArrayExpr, Expression.Constant(i) ); splattedArgs[i] = new DynamicMetaObject( argExpr, BindingRestrictions.Empty, argValues[i] ); arginfos[i] = Expression.ByRefArgument(i); } BindingRestrictions arrayLenRestriction = BindingRestrictions.GetExpressionRestriction( Expression.Equal( Expression.ArrayLength( argAsArrayExpr ), Expression.Constant(argLen) ) ); ComInvokeAction invokeBinder = new ComInvokeAction(arginfos); DynamicMetaObject innerAction = target.BindInvoke(invokeBinder, splattedArgs); BindingRestrictions restrictions = target.Restrictions. Merge(arg.Restrictions). Merge(arrayLenRestriction). Merge(innerAction.Restrictions); return new DynamicMetaObject( innerAction.Expression, restrictions ); }
internal static bool IsStrongBoxArg(DynamicMetaObject o, ArgumentInfo argInfo) { if (argInfo.IsByRef) { return false; } Type t = o.LimitType; return t.IsGenericType && t.GetGenericTypeDefinition() == typeof(StrongBox<>); }
internal DelegateSignatureInfo(LanguageContext context, Type returnType, ParameterInfo[] parameters) { Assert.NotNull(context, returnType); Assert.NotNullItems(parameters); _context = context; _parameters = parameters; _returnType = returnType; if (_returnType != typeof(void)) { _convert = _context.CreateConvertBinder(_returnType, true); } ArgumentInfo[] args = new ArgumentInfo[_parameters.Length]; for (int i = 0; i < args.Length; i++) { args[i] = Expression.PositionalArg(i); } _invoke = _context.CreateInvokeBinder(args); }
private static void AppendArgument(StringBuilder builder, ArgumentInfo argument) { builder.Append("["); builder.Append(argument.ArgumentType.Name); builder.Append("]"); builder.Append(" "); builder.Append(argument.Name); }
public RubyInvokeMemberBinder(RubyContext/*!*/ context, string/*!*/ name, ArgumentInfo[]/*!*/ arguments) : base(name, false, arguments) { _context = context; }
/// <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; }
public RubyCreateInstanceBinder(RubyContext/*!*/ context, ArgumentInfo[]/*!*/ arguments) : base(arguments) { _context = context; }
// this helper prepares arguments for COM binding by transforming ByVal StongBox arguments // into ByRef expressions that represent the argument's Value fields. internal static void ProcessArgumentsForCom(ref DynamicMetaObject[] args, ref IList<ArgumentInfo> argInfos) { Debug.Assert(args != null); DynamicMetaObject[] newArgs = new DynamicMetaObject[args.Length]; ArgumentInfo[] newArgInfos = new ArgumentInfo[args.Length]; bool hasArgInfos = HasArgInfos(args, argInfos); for (int i = 0; i < args.Length; i++) { DynamicMetaObject curArgument = args[i]; // set new arg infos to their original values or set default ones // we will do this fixup early so that we can assume we always have // arginfos in COM binder. if (hasArgInfos) { newArgInfos[i] = argInfos[i]; } else { // TODO: this fixup should not be needed once refness is expressed only by argInfos if (IsByRef(curArgument)) { newArgInfos[i] = Expression.ByRefPositionalArgument(i); } else { newArgInfos[i] = Expression.PositionalArg(i); } } if (IsStrongBoxArg(curArgument, newArgInfos[i])) { var restrictions = curArgument.Restrictions.Merge( GetTypeRestrictionForDynamicMetaObject(curArgument) ); // we have restricted this argument to LimitType so we can convert and conversion will be trivial cast. Expression boxedValueAccessor = Expression.Field( Helpers.Convert( curArgument.Expression, curArgument.LimitType ), curArgument.LimitType.GetField("Value") ); IStrongBox value = curArgument.Value as IStrongBox; object boxedValue = value != null ? value.Value : null; newArgs[i] = new DynamicMetaObject( boxedValueAccessor, restrictions, boxedValue ); NamedArgumentInfo nai = newArgInfos[i] as NamedArgumentInfo; if (nai != null) { newArgInfos[i] = Expression.ByRefNamedArgument(nai.Name); } else { newArgInfos[i] = Expression.ByRefPositionalArgument(i); } } else { newArgs[i] = curArgument; } } args = newArgs; argInfos = newArgInfos; }
private static Type MarshalType(DynamicMetaObject mo, ArgumentInfo ainf) { Type marshalType = (mo.Value == null && mo.HasValue) ? null : mo.LimitType; // we are not checking that mo.Expression is writeable or whether evaluating it has no sideeffects // the assumption is that whoever matched it with ByRef arginfo took care of this. if (ainf.IsByRef){ // Null just means that null was supplied. if (marshalType == null) { marshalType = mo.Expression.Type; } marshalType = marshalType.MakeByRefType(); } return marshalType; }
private static void WriteArgument(StringBuilderOutputWriter builder, ArgumentInfo argument) { builder.Write("["); builder.Write(argument.ArgumentType.Name); builder.Write("]"); builder.Write(" "); builder.Write(argument.Name); }