/// <summary> /// Emit the code needed to marshal back the local variables to by-ref parameters. /// </summary> protected void EmitManagedToNativeMarshallingForByRefParameters (ILGenerator generator, Type[] nativeParameterTypes, ByRefParameter[] byRefLocalVariables) { for (int i = 0; i < byRefLocalVariables.Length; i++) { LocalBuilder local = byRefLocalVariables [i].LocalBuilder; if (local == null) { continue; } this.EmitManagedToNativeMarshallingCast (generator, local, local.LocalType, i); } }
private Expression BuildMethodCall(MethodBase method, Type type, ParameterExpression targetParameterExpression, ParameterExpression argsParameterExpression) { Expression expression6; ParameterInfo[] parameters = method.GetParameters(); Expression[] arguments = new Expression[parameters.Length]; IList <ByRefParameter> list = new List <ByRefParameter>(); for (int i = 0; i < parameters.Length; i++) { Expression expression4; ParameterInfo info = parameters[i]; Type parameterType = info.ParameterType; bool flag = false; if (parameterType.IsByRef) { parameterType = parameterType.GetElementType(); flag = true; } Expression index = Expression.Constant(i); Expression left = Expression.ArrayIndex(argsParameterExpression, index); if (parameterType.IsValueType()) { BinaryExpression expression = Expression.Coalesce(left, Expression.New(parameterType)); expression4 = this.EnsureCastExpression(expression, parameterType); } else { expression4 = this.EnsureCastExpression(left, parameterType); } if (flag) { ParameterExpression expression5 = Expression.Variable(parameterType); ByRefParameter item = new ByRefParameter { Value = expression4, Variable = expression5, IsOut = info.IsOut }; list.Add(item); expression4 = expression5; } arguments[i] = expression4; } if (method.IsConstructor) { expression6 = Expression.New((ConstructorInfo)method, arguments); } else if (method.IsStatic) { expression6 = Expression.Call((MethodInfo)method, arguments); } else { expression6 = Expression.Call(this.EnsureCastExpression(targetParameterExpression, method.DeclaringType), (MethodInfo)method, arguments); } if (method is MethodInfo) { if (((MethodInfo)method).ReturnType != typeof(void)) { expression6 = this.EnsureCastExpression(expression6, type); } else { expression6 = Expression.Block(expression6, Expression.Constant(null)); } } else { expression6 = this.EnsureCastExpression(expression6, type); } if (list.Count <= 0) { return(expression6); } IList <ParameterExpression> list2 = new List <ParameterExpression>(); IList <Expression> list3 = new List <Expression>(); foreach (ByRefParameter parameter in list) { if (!parameter.IsOut) { list3.Add(Expression.Assign(parameter.Variable, parameter.Value)); } list2.Add(parameter.Variable); } list3.Add(expression6); return(Expression.Block((IEnumerable <ParameterExpression>)list2, (IEnumerable <Expression>)list3)); }
/// <summary> /// Genenerate optimized IL for stacking parameters : /// - For the third or fourth parameter, use the short OpCode /// - For all the parameters left, use the long OpCode /// </summary> protected static void EmitParametersLoadingOnStack (ILGenerator generator, Type[] parameterTypes, Type[] nativeParameterTypes, ByRefParameter[] byRefLocalVariables, int parameterOffset) { for (int i = 0; i < parameterTypes.Length; i++) { // For by-ref type, loads the local variable // Otherwise, loads the argument (wrapped or not) Type parameterType = parameterTypes [i]; if (parameterType.IsByRef) { generator.Emit (OpCodes.Ldloca, byRefLocalVariables [i].LocalBuilder); } else { EmitLoadArgument (generator, i + parameterOffset); // For wrapped type (interface or Id subclass) if (TypeHelper.NeedWrapping (parameterType)) { MethodInfo wrapInstance = EmitInfos.OBJECTIVECRUNTIME_GETINSTANCE.MakeGenericMethod (new[] {parameterType}); generator.Emit (OpCodes.Call, wrapInstance); } else { EmitHelper.CastValueType (generator, nativeParameterTypes [i], parameterTypes [i]); } } } }
/// <summary> /// For by-ref parameters passed as reference (without [out] attribute), we first set the value of local variables /// </summary> protected void EmitNativeToManagedMarshallingForByRefParameters (ILGenerator generator, Type[] nativeParameterTypes, ByRefParameter[] byRefLocalVariables) { for (int i = 0; i < byRefLocalVariables.Length; i++) { ByRefParameter parameter = byRefLocalVariables [i]; if (parameter.LocalBuilder == null || parameter.IsOut) { continue; } Type localType = parameter.LocalBuilder.LocalType; EmitLoadArgument (generator, i + 2); this.EmitNativeToManagedMarshallingCast (generator, localType); generator.Emit (OpCodes.Stloc, parameter.LocalBuilder); } }
/// <summary> /// Emit local variable for each by-ref parameters. These variables will hold the result until the marshalling occurs. /// </summary> protected static ByRefParameter[] CreateLocalVariableForByRefParameters (ILGenerator generator, ParameterInfo[] parameterInfos) { ByRefParameter[] byrefLocals = new ByRefParameter[parameterInfos.Length]; for (int i = 0; i < parameterInfos.Length; i++) { Type parameterType = parameterInfos [i].ParameterType; // For by-ref type, create a local variable and store it if (!parameterType.IsByRef) { continue; } // Create the local variable of the de-referenced type byrefLocals [i].LocalBuilder = generator.DeclareLocal (parameterType.GetElementType ()); byrefLocals [i].IsOut = parameterInfos [i].IsOut; } return byrefLocals; }
private void AddBasicMethodTargets(MethodTracker method) { List<Parameter> parameters = new List<Parameter>(); int argIndex = 0; ArgBuilder instanceBuilder; if (!method.IsStatic) { parameters.Add(new Parameter(method.DeclaringType)); instanceBuilder = new SimpleArgBuilder(argIndex++, parameters[0]); } else { instanceBuilder = new NullArgBuilder(); } List<ArgBuilder> argBuilders = new List<ArgBuilder>(); List<ArgBuilder> defaultBuilders = new List<ArgBuilder>(); bool hasByRef = false; foreach (ParameterInfo pi in method.GetParameters()) { if (pi.ParameterType == typeof(ICallerContext)) { argBuilders.Add(new ContextArgBuilder()); continue; } if (pi.DefaultValue != DBNull.Value) { defaultBuilders.Add(new DefaultArgBuilder(pi.ParameterType, pi.DefaultValue)); } else if (defaultBuilders.Count > 0) { // If we get a bad method with non-contiguous default values, then just use the contiguous list defaultBuilders.Clear(); } if (pi.ParameterType.IsByRef) { hasByRef = true; Parameter param = new ByRefParameter(pi.ParameterType.GetElementType(), pi.IsOut && !pi.IsIn); parameters.Add(param); argBuilders.Add(new ReferenceArgBuilder(argIndex++, param)); } else { Parameter param = new Parameter(pi.ParameterType); parameters.Add(param); argBuilders.Add(new SimpleArgBuilder(argIndex++, param)); } } ReturnBuilder returnBuilder = new ReturnBuilder(CompilerHelpers.GetReturnType(method.Method)); for (int i = 1; i < defaultBuilders.Count + 1; i++) { List<ArgBuilder> defaultArgBuilders = argBuilders.GetRange(0, argBuilders.Count - i); defaultArgBuilders.AddRange(defaultBuilders.GetRange(defaultBuilders.Count - i, i)); AddTarget(new MethodTarget(method, parameters.GetRange(0, parameters.Count - i), instanceBuilder, defaultArgBuilders, returnBuilder)); } if (hasByRef) AddSimpleTarget(MakeByRefReducedMethodTarget(method, parameters, instanceBuilder, argBuilders)); AddSimpleTarget(new MethodTarget(method, parameters, instanceBuilder, argBuilders, returnBuilder)); }
private Expression BuildMethodCall(MethodBase method, Type type, ParameterExpression?targetParameterExpression, ParameterExpression argsParameterExpression) { ParameterInfo[] parametersInfo = method.GetParameters(); Expression[] argsExpression; IList <ByRefParameter> refParameterMap; if (parametersInfo.Length == 0) { argsExpression = new Expression[0]; refParameterMap = new ByRefParameter[0]; } else { argsExpression = new Expression[parametersInfo.Length]; refParameterMap = new List <ByRefParameter>(); for (int i = 0; i < parametersInfo.Length; i++) { ParameterInfo parameter = parametersInfo[i]; Type parameterType = parameter.ParameterType; bool isByRef = false; if (parameterType.IsByRef) { parameterType = parameterType.GetElementType(); isByRef = true; } Expression indexExpression = Expression.Constant(i); Expression paramAccessorExpression = Expression.ArrayIndex(argsParameterExpression, indexExpression); Expression argExpression = EnsureCastExpression(paramAccessorExpression, parameterType, !isByRef); if (isByRef) { ParameterExpression variable = Expression.Variable(parameterType); refParameterMap.Add(new ByRefParameter(argExpression, variable, parameter.IsOut)); argExpression = variable; } argsExpression[i] = argExpression; } } Expression callExpression; if (method.IsConstructor) { callExpression = Expression.New((ConstructorInfo)method, argsExpression); } else if (method.IsStatic) { callExpression = Expression.Call((MethodInfo)method, argsExpression); } else { Expression readParameter = EnsureCastExpression(targetParameterExpression !, method.DeclaringType); callExpression = Expression.Call(readParameter, (MethodInfo)method, argsExpression); } if (method is MethodInfo m) { if (m.ReturnType != typeof(void)) { callExpression = EnsureCastExpression(callExpression, type); } else { callExpression = Expression.Block(callExpression, Expression.Constant(null)); } } else { callExpression = EnsureCastExpression(callExpression, type); } if (refParameterMap.Count > 0) { IList <ParameterExpression> variableExpressions = new List <ParameterExpression>(); IList <Expression> bodyExpressions = new List <Expression>(); foreach (ByRefParameter p in refParameterMap) { if (!p.IsOut) { bodyExpressions.Add(Expression.Assign(p.Variable, p.Value)); } variableExpressions.Add(p.Variable); } bodyExpressions.Add(callExpression); callExpression = Expression.Block(variableExpressions, bodyExpressions); } return(callExpression); }