internal void AnalyzeMembers(FormalParam /*!*/ node, Analyzer /*!*/ analyzer, PhpRoutine /*!*/ routine, int index) { this.routine = routine; this.index = index; PhpType referring_type; Scope referring_scope; if (routine.IsMethod) { referring_type = routine.DeclaringPhpType; referring_scope = referring_type.Declaration.Scope; } else if (routine.IsLambdaFunction) { referring_type = analyzer.CurrentType; referring_scope = analyzer.CurrentScope; } else { referring_type = null; referring_scope = ((PhpFunction)routine).Declaration.Scope; } var attributes = node.Attributes; if (attributes != null) { attributes.AnalyzeMembers(analyzer, referring_scope); } resolvedTypeHint = analyzer.ResolveType(node.TypeHint, referring_type, routine, node.Span, false); }
internal void AnalyzeMembers(Analyzer /*!*/ analyzer, PhpRoutine /*!*/ routine, int index) { this.routine = routine; this.index = index; PhpType referring_type; Scope referring_scope; if (routine.IsMethod) { referring_type = routine.DeclaringPhpType; referring_scope = referring_type.Declaration.Scope; } else if (routine.IsLambdaFunction) { referring_type = analyzer.CurrentType; referring_scope = analyzer.CurrentScope; } else { referring_type = null; referring_scope = ((PhpFunction)routine).Declaration.Scope; } attributes.AnalyzeMembers(analyzer, referring_scope); resolvedTypeHint = analyzer.ResolveType(typeHint, referring_type, routine, position, false); }
internal void EmitLoadTypeArgsOnEvalStack(CodeGenerator /*!*/ codeGenerator, PhpRoutine /*!*/ routine) { ILEmitter il = codeGenerator.IL; int mandatory_count = (routine.Signature != null) ? routine.Signature.MandatoryGenericParamCount : 0; int formal_count = (routine.Signature != null) ? routine.Signature.GenericParamCount : 0; int actual_count = genericParams.Count; // loads all actual parameters which are not superfluous: for (int i = 0; i < Math.Min(actual_count, formal_count); i++) { genericParams[i].EmitLoadTypeDesc(codeGenerator, ResolveTypeFlags.UseAutoload | ResolveTypeFlags.ThrowErrors); } // loads missing mandatory arguments: for (int i = actual_count; i < mandatory_count; i++) { // CALL PhpException.MissingTypeArgument(<i+1>,<name>); il.LdcI4(i + 1); il.Emit(OpCodes.Ldstr, routine.FullName); codeGenerator.EmitPhpException(Methods.PhpException.MissingTypeArgument); // LOAD DTypeDesc.ObjectTypeDesc; il.Emit(OpCodes.Ldsfld, Fields.DTypeDesc.ObjectTypeDesc); } // loads missing optional arguments: for (int i = Math.Max(mandatory_count, actual_count); i < formal_count; i++) { // LOAD Arg.DefaultType; il.Emit(OpCodes.Ldsfld, Fields.Arg_DefaultType); } }
/// <summary> /// Generates expression for a given argument to fit formal argument of the give routine. /// </summary> /// <param name="routine">Routine for which argument will be supplied.</param> /// <param name="scriptContext">ScriptContext DynamicMetaObject</param> /// <param name="arg">Actual argument to be supplied to be supplied to routine.</param> /// <param name="argIndex">Index of the argument in a routine(not counting ScriptContext argument).</param> /// <returns>The expression of an argument that is prepared to be supplied as an argument to the routine.</returns> private static Expression /*!*/ GeneratePeekArgument(PhpRoutine routine, DynamicMetaObject scriptContext, DynamicMetaObject arg, int argIndex) { bool optional = argIndex >= routine.Signature.MandatoryParamCount; int argIndexTransformed = argIndex + 1; // in PHP indexes of arguments starts from index 1 if (routine.Signature.IsAlias(argIndex)) { if (optional) { return(PeekReferenceOptional(routine, scriptContext, arg, argIndexTransformed)); } else { return(PeekReference(routine, scriptContext, arg, argIndexTransformed)); } } else { if (optional) { return(PeekValueOptional(routine, scriptContext, arg, argIndexTransformed)); } else { return(PeekValue(routine, scriptContext, arg, argIndexTransformed)); } } }
private static Expression /*!*/ PeekReferenceUnchecked(PhpRoutine routine, DynamicMetaObject scriptContext, DynamicMetaObject arg, int argIndex) { // the caller may not pushed a reference although the formal argument is a reference: // it doesn't matter if called by callback: if (!Types.PhpReference[0].IsAssignableFrom(arg.LimitType)) { // caller may have pushed a runtime chain => evaluate it: if (arg.LimitType == Types.PhpRuntimeChain[0]) { //result = php_chain.GetReference(Context); return(Expression.Call( Expression.Convert(arg.Expression, Types.PhpRuntimeChain[0]), Methods.PhpRuntimeChain.GetReference, scriptContext.Expression)); } else { // the reason of copy is not exactly known (it may be returning by copy as well as passing by copy): // result = new PhpReference(PhpVariable.Copy(arg_i, CopyReason.Unknown)); ParameterExpression resultVariable = Expression.Parameter(Types.PhpReference[0], "result"); ParameterExpression[] vars = new ParameterExpression[] { resultVariable }; return(Expression.Block(vars, Expression.Assign( resultVariable, Expression.New(Constructors.PhpReference_Object, Expression.Call(Methods.PhpVariable.Copy, arg.Expression, Expression.Constant(CopyReason.Unknown)))), BinderHelper.ThrowArgumentNotPassedByRef(argIndex, routine.FullName), resultVariable)); //(MB) I'm not sure if it's necessary to execute these two in this order //Original code // //(MB) I don't have to solve this now, PhpCallback is called in a old manner. So I can just throw exception always now. // // Reports an error in the case that we are not called by callback. // Although, this error is fatal one can switch throwing exceptions off. // If this is the case the afterwards behavior will be the same as if callback was called. //if (!Callback) //{ // // warning (can invoke user code => we have to save and restore callstate): // CallState call_state = SaveCallState(); // PhpException.ArgumentNotPassedByRef(i, CalleeName); // RestoreCallState(call_state); //} } } else { return(Expression.Convert(arg.Expression, arg.LimitType)); } }
private static Expression /*!*/ PeekTypeOptional(PhpRoutine routine, DynamicMetaObject scriptContext, DynamicMetaObject arg, int argIndex) { if (arg != null) { // peeks the value: return(Expression.Convert(arg.Expression, arg.LimitType)); } else { // default value: return(Expression.Constant(Arg.DefaultType, Types.DTypeDesc[0])); } }
private static Expression /*!*/ PeekReferenceOptional(PhpRoutine routine, DynamicMetaObject scriptContext, DynamicMetaObject arg, int argIndex) { if (arg != null) { // peeks the value: return(PeekReferenceUnchecked(routine, scriptContext, arg, argIndex)); } else { // default value: return(Expression.Constant(Arg.Default, Types.PhpReference[0])); } }
private static Expression /*!*/ PeekType(PhpRoutine routine, DynamicMetaObject scriptContext, DynamicMetaObject arg, int argIndex) { if (arg != null) { // peeks the value: return(Expression.Convert(arg.Expression, arg.LimitType)); } else { return(Expression.Block( BinderHelper.ThrowMissingTypeArgument(argIndex, routine.FullName), Expression.Constant(DTypeDesc.ObjectTypeDesc, Types.DTypeDesc[0]))); } }
private static Expression /*!*/ PeekReference(PhpRoutine routine, DynamicMetaObject scriptContext, DynamicMetaObject arg, int argIndex) { if (arg != null) { // peeks the reference: return(PeekReferenceUnchecked(routine, scriptContext, arg, argIndex)); } else { return(Expression.Block( BinderHelper.ThrowMissingArgument(argIndex, routine.FullName), Expression.New(Constructors.PhpReference_Void))); } }
private static Expression /*!*/ PeekValue(PhpRoutine routine, DynamicMetaObject scriptContext, DynamicMetaObject arg, int argIndex) { if (arg != null) { // peeks the value: return(PeekValueUnchecked(routine, scriptContext, arg, argIndex)); } else { return(Expression.Block( BinderHelper.ThrowMissingArgument(argIndex, routine.FullName), Expression.Constant(null))); } }
private static Expression /*!*/ GeneratePeekPseudoGenericArgument(PhpRoutine routine, DynamicMetaObject scriptContext, DynamicMetaObject arg, int index) { bool optional = index >= routine.Signature.MandatoryGenericParamCount; int indexTransformed = index + 1; // in PHP indexes of arguments starts from index 1 if (optional) { return(PeekTypeOptional(routine, scriptContext, arg, indexTransformed)); } else { return(PeekType(routine, scriptContext, arg, indexTransformed)); } }
internal void EmitLoadArgsOnEvalStack(CodeGenerator /*!*/ codeGenerator, PhpRoutine /*!*/ routine) { ILEmitter il = codeGenerator.IL; int mandatory_count = (routine.Signature != null) ? routine.Signature.MandatoryParamCount : 0; int formal_count = (routine.Signature != null) ? routine.Signature.ParamCount : 0; int actual_count = parameters.Count; PhpTypeCode param_type; // loads all actual parameters which are not superfluous: for (int i = 0; i < Math.Min(actual_count, formal_count); i++) { codeGenerator.EmitBoxing(param_type = parameters[i].Emit(codeGenerator)); // Actual param emitter should emit "boxing" to a reference if its access type is ReadRef. // That's why no operation is needed here and references should match. Debug.Assert((routine.Signature == null || routine.Signature.IsAlias(i)) == (param_type == PhpTypeCode.PhpReference)); } // loads missing mandatory arguments: for (int i = actual_count; i < mandatory_count; i++) { // CALL PhpException.MissingArgument(<i+1>,<name>); il.LdcI4(i + 1); il.Emit(OpCodes.Ldstr, routine.FullName); codeGenerator.EmitPhpException(Methods.PhpException.MissingArgument); // LOAD null; if (routine.Signature.IsAlias(i)) { il.Emit(OpCodes.Newobj, Constructors.PhpReference_Void); } else { il.Emit(OpCodes.Ldnull); } } // loads missing optional arguments: for (int i = Math.Max(mandatory_count, actual_count); i < formal_count; i++) { // LOAD Arg.Default; il.Emit(OpCodes.Ldsfld, Fields.Arg_Default); } }
private static Expression /*!*/ PeekValueUnchecked(PhpRoutine routine, DynamicMetaObject scriptContext, DynamicMetaObject arg, int argIndex) { // caller may have pushed a reference even if a formal argument is not reference => dereference it: if (Types.PhpReference[0].IsAssignableFrom(arg.LimitType)) // what about SmartReference { //object result = ((PhpReference)arg_i).Value; return(Expression.Field(Expression.Convert(arg.Expression, Types.PhpReference[0]), Fields.PhpReference_Value)); } else // caller may have pushed a runtime chain => evaluate it: if (arg.LimitType == Types.PhpRuntimeChain[0]) { //result = php_chain.GetValue(Context); return(Expression.Call( Expression.Convert(arg.Expression, Types.PhpRuntimeChain[0]), Methods.PhpRuntimeChain.GetValue, scriptContext.Expression)); } else { return(arg.Expression); } }
internal void AnalyzeMembers(Analyzer /*!*/ analyzer, PhpRoutine /*!*/ routine) { int last_mandatory_param_index = -1; bool last_param_was_optional = false; BitArray alias_mask = new BitArray(formalParams.Count); DType[] type_hints = new DType[formalParams.Count]; for (int i = 0; i < formalParams.Count; i++) { FormalParam param = formalParams[i]; param.AnalyzeMembers(analyzer, routine, i); alias_mask[i] = param.PassedByRef; type_hints[i] = param.ResolvedTypeHint; if (param.InitValue == null) { if (last_param_was_optional) { analyzer.ErrorSink.Add(Warnings.MandatoryBehindOptionalParam, analyzer.SourceUnit, param.Position, param.Name); } last_mandatory_param_index = i; last_param_was_optional = false; } else { last_param_was_optional = true; } } routine.Signature.WriteUp(aliasReturn, alias_mask, type_hints, last_mandatory_param_index + 1); }
/// <summary> /// Prepares arguments for argfull overload. /// </summary> /// <param name="routine">Routine for which arguments should be prepared</param> /// <param name="arguments">Arguments to be prepared for the routine</param> /// <param name="genericArguments">Amount of generic arguments provided by call site.</param> /// <param name="regularArguments">Amount of value arguments provided by call site.</param> /// <param name="restrictions">Type restrictions for the arguments</param> /// <returns>Array of prepared arguments to be called with routine</returns> /// <remarks> /// This is basically substitute for everything important that was done in argless overload (except it doesn't use PhpStack but evaluation stack). /// It adopts the arguments according to routine. e.g. dereference reference if value is needed, supplies default argument, etc. /// </remarks> public static Expression[] PrepareArguments(this PhpRoutine routine, DynamicMetaObject[] arguments, int genericArguments, int regularArguments, out BindingRestrictions restrictions) { const int scriptContextIndex = 0; DynamicMetaObject arg; int result_offset = 0; int argument_offset = 0; Expression[] result = new Expression[1 + routine.Signature.GenericParamCount + routine.Signature.ParamCount];//ScriptContext + all arguments = actual arguments to be passed to argfull overload restrictions = BindingRestrictions.Empty; result[scriptContextIndex] = arguments[scriptContextIndex].Expression; ++result_offset; ++argument_offset; // peek pseudo-generic arguments: for (int i = 0; i < routine.Signature.GenericParamCount; ++i) { if (i < genericArguments) { arg = arguments[argument_offset + i]; } else { arg = null; } result[result_offset + i] = GeneratePeekPseudoGenericArgument(routine, arguments[scriptContextIndex], arg, i); // it isn't necessary to add restriction for type argument, it is always DTypeDesc } result_offset += routine.Signature.GenericParamCount; argument_offset += genericArguments; // peek regular arguments: // skip first one ScriptContext and generic parameters for (int i = 0; i < routine.Signature.ParamCount; ++i) { if (i < regularArguments) { arg = arguments[argument_offset + i]; if (arg.RuntimeType != null) { restrictions = restrictions.Merge(BindingRestrictions.GetTypeRestriction(arguments[argument_offset + i].Expression, arguments[argument_offset + i].LimitType)); } else { restrictions = restrictions.Merge(BindingRestrictions.GetInstanceRestriction(arguments[argument_offset + i].Expression, null));//(MB) is it necessary? } } else { arg = null; } result[result_offset + i] = GeneratePeekArgument(routine, arguments[scriptContextIndex], arg, i); } return(result); }
/// <summary> /// Emits IL instructions that load actual parameters on the evaluation stack. /// </summary> /// <param name="codeGenerator">Code generator.</param> /// <param name="routine">PHP method being called.</param> /// <remarks> /// <para> /// The function has mandatory and optional formal arguments. /// Mandatory arguments are those formal arguments which are not preceded by /// any formal argument with default value. The others are optional. /// If a formal argument without default value is declared beyond the last mandatory argument /// it is treated as optional one by the caller. The callee checks this and throws warning. /// </para> /// Missing arguments handling: /// <list type="bullet"> /// <item>missing mandatory argument - WARNING; LOAD(null);</item> /// <item>missing optional argument - LOAD(Arg.Default);</item> /// <item>superfluous arguments are ignored</item> /// </list> /// </remarks> internal void EmitLoadOnEvalStack(CodeGenerator /*!*/ codeGenerator, PhpRoutine /*!*/ routine) { EmitLoadTypeArgsOnEvalStack(codeGenerator, routine); EmitLoadArgsOnEvalStack(codeGenerator, routine); }
internal static void AnalyzeMembers(Signature node, Analyzer /*!*/ analyzer, PhpRoutine /*!*/ routine) { int last_mandatory_param_index = -1; bool last_param_was_optional = false; var formalParams = node.FormalParams; BitArray alias_mask = new BitArray(formalParams.Length); DType[] type_hints = new DType[formalParams.Length]; for (int i = 0; i < formalParams.Length; i++) { var param = formalParams[i]; var paramcompiler = param.NodeCompiler <FormalParamCompiler>(); paramcompiler.AnalyzeMembers(param, analyzer, routine, i); alias_mask[i] = param.PassedByRef; type_hints[i] = paramcompiler.ResolvedTypeHint; if (param.InitValue == null && !param.IsVariadic) // optional parameters { if (last_param_was_optional) { analyzer.ErrorSink.Add(Warnings.MandatoryBehindOptionalParam, analyzer.SourceUnit, param.Span, param.Name); } last_mandatory_param_index = i; last_param_was_optional = false; } else { last_param_was_optional = true; } } routine.Signature.WriteUp(node.AliasReturn, alias_mask, type_hints, last_mandatory_param_index + 1); }
/// <summary> /// Emits IL instructions that load actual parameters on the evaluation stack. /// </summary> /// <param name="node">Instance.</param> /// <param name="codeGenerator">Code generator.</param> /// <param name="routine">PHP method being called.</param> /// <remarks> /// <para> /// The function has mandatory and optional formal arguments. /// Mandatory arguments are those formal arguments which are not preceded by /// any formal argument with default value. The others are optional. /// If a formal argument without default value is declared beyond the last mandatory argument /// it is treated as optional one by the caller. The callee checks this and throws warning. /// </para> /// Missing arguments handling: /// <list type="bullet"> /// <item>missing mandatory argument - WARNING; LOAD(null);</item> /// <item>missing optional argument - LOAD(Arg.Default);</item> /// <item>superfluous arguments are ignored</item> /// </list> /// </remarks> public void EmitLoadOnEvalStack(CallSignature /*!*/ node, CodeGenerator /*!*/ codeGenerator, PhpRoutine /*!*/ routine) { EmitLoadTypeArgsOnEvalStack(node, codeGenerator, routine); EmitLoadArgsOnEvalStack(node, codeGenerator, routine); }
/// <summary> /// Enumerates all export overloads for the given target PHP method. /// </summary> public static IEnumerable <StubInfo> DefineMethodExportStubs( PhpRoutine /*!*/ target, MethodAttributes attributes, bool defineConstructors, StubSignatureFilter /*!*/ signatureFilter) { Debug.Assert(target.Builder != null); Type return_type = Types.Object[0]; PhpRoutineSignature signature = target.Signature; List <AST.FormalParam> formal_params = target.Builder.Signature.FormalParams; List <AST.FormalTypeParam> formal_type_params = target.Builder.TypeSignature.TypeParams; int gen_sig_count = signature.GenericParamCount - signature.MandatoryGenericParamCount + 1; int arg_sig_count = signature.ParamCount - signature.MandatoryParamCount + 1; // TODO: return type hints // HACK: change return type to void for methods that are apparently event handlers if (signature.GenericParamCount == 0 && arg_sig_count == 1 && signature.ParamCount == 2 && (signature.TypeHints[0] == null || signature.TypeHints[0].RealType == Types.Object[0]) && (signature.TypeHints[1] != null && typeof(EventArgs).IsAssignableFrom(signature.TypeHints[1].RealType))) { return_type = Types.Void; } for (int gen_sig = 0; gen_sig < gen_sig_count; gen_sig++) { for (int arg_sig = 0; arg_sig < arg_sig_count; arg_sig++) { // determine parameter types (except for method mandatory generic parameters) object[] parameter_types = GetStubParameterTypes( arg_sig + signature.MandatoryParamCount, gen_sig + signature.MandatoryGenericParamCount, signature, formal_type_params); // determine generic parameter names string[] generic_param_names = new string[target.Signature.MandatoryGenericParamCount + gen_sig]; for (int i = 0; i < generic_param_names.Length; i++) { generic_param_names[i] = formal_type_params[i].Name.ToString(); } // are we allowed to generate this signature? if (!signatureFilter(generic_param_names, parameter_types, return_type)) { continue; } GenericTypeParameterBuilder[] generic_params = StubInfo.EmptyGenericParameters; MethodBase method_base = null; MethodBuilder method = null; if (!defineConstructors) { method = target.DeclaringType.RealTypeBuilder.DefineMethod(target.FullName, attributes); // determine generic parameters if (generic_param_names.Length > 0) { generic_params = method.DefineGenericParameters(generic_param_names); } method_base = method; } ParameterInfo[] parameters = new ParameterInfo[parameter_types.Length]; // fill in parameter infos Type[] real_parameter_types = new Type[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { Type type = parameter_types[i] as Type; // generic method parameter fixup if (type == null) { int index = (int)parameter_types[i]; if (index < 0) { type = generic_params[-(index + 1)].MakeByRefType(); } else { type = generic_params[index]; } } string param_name; ParameterAttributes param_attrs; if (i < formal_params.Count) { param_name = formal_params[i].Name.ToString(); param_attrs = (formal_params[i].IsOut ? ParameterAttributes.Out : ParameterAttributes.None); } else { param_name = "args" + (i + 1); param_attrs = ParameterAttributes.None; } parameters[i] = new StubParameterInfo(i, type, param_attrs, param_name); real_parameter_types[i] = type; } if (method != null) { method.SetParameters(real_parameter_types); method.SetReturnType(return_type); method.SetCustomAttribute(AttributeBuilders.DebuggerHidden); } else { // constructor is never a generic method attributes |= MethodAttributes.SpecialName | MethodAttributes.RTSpecialName; attributes &= ~MethodAttributes.Virtual; ConstructorBuilder constructor = target.DeclaringType.RealTypeBuilder.DefineConstructor( attributes, CallingConventions.Standard, real_parameter_types); constructor.SetCustomAttribute(AttributeBuilders.DebuggerHidden); method_base = constructor; } yield return(new StubInfo(method_base, parameters, generic_params, return_type)); } } }
public static void EmitLoadOnEvalStack(this CallSignature /*!*/ node, CodeGenerator /*!*/ codeGenerator, PhpRoutine /*!*/ routine) { node.NodeCompiler <ICallSignatureCompiler>().EmitLoadOnEvalStack(node, codeGenerator, routine); }
/// <summary> /// This method binds rules for PhpMethod /// </summary> private void InvokePhpMethod(DynamicMetaObject /*!*/ target, DynamicMetaObject[] /*!!*/ args, /*object targetObj,*/ PhpRoutine /*!*/ routine, out BindingRestrictions restrictions, out Expression invokeMethodExpr) { Debug.Assert(target != null && target.Value != null); Debug.Assert(!(target.Value is IClrValue), "PhpRoutine should not be declared on CLR value type!"); /*if (target.Value is PhpObject) * { * // Restriction: typeof(target) == |target.TypeDesc.RealType| * var targetPhpObj = (PhpObject)target.Value; * Debug.Assert(targetPhpObj.TypeDesc.RealType == target.LimitType); * Debug.Assert(target.Value.GetType() == target.LimitType); * restrictions = BindingRestrictions.GetTypeRestriction(target.Expression, targetPhpObj.TypeDesc.RealType); * } * else*/ Debug.Assert(typeof(ClrObject).IsSealed); // just to ensure following condition is correct if (target.Value.GetType() == typeof(ClrObject)) { target = new ClrDynamicMetaObject(target); // unwrap the real object, get restrictions restrictions = target.Restrictions; } else { Debug.Assert(target.Value.GetType() == target.LimitType); // just for sure Debug.Assert(!(target.Value is PhpObject) || ((PhpObject)target.Value).TypeDesc.RealType == target.LimitType); restrictions = BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType); } BindingRestrictions argumentsRestrictions; Expression[] arguments; if (routine.Name != PHP.Core.Reflection.DObject.SpecialMethodNames.Call) { args = GetArgumentsRange(args, 0, RealMethodArgumentCount);// This can't be done when _call method is invoked //Check if method has ArgAware attribute if ((routine.Properties & RoutineProperties.IsArgsAware) != 0 || routine.IsStatic)// this is because of hack in PHP.Library.XML library static methods that can be also called like instance methods { DynamicMetaObject scriptContext = args[0]; //Select arguments without scriptContext DynamicMetaObject[] realArgs = GetArgumentsRange(args, 1, RealMethodArgumentCount - 1); InvokeArgLess(target, scriptContext, routine.RoutineDesc, realArgs, out argumentsRestrictions, out invokeMethodExpr); restrictions = restrictions.Merge(argumentsRestrictions); return; } arguments = routine.PrepareArguments(args, _genericParamsCount, _paramsCount, out argumentsRestrictions); restrictions = restrictions.Merge(argumentsRestrictions); } else { arguments = BinderHelper.PackToExpressions(args); } //((PhpObject)target)) var realObjEx = Expression.Convert(target.Expression, routine.ArgFullInfo.DeclaringType);//targetObj.TypeDesc.RealType); //ArgFull( ((PhpObject)target), ScriptContext, args, ... ) invokeMethodExpr = Expression.Call(BinderHelper.WrapInstanceMethodCall(routine.ArgFullInfo), BinderHelper.CombineArguments(realObjEx, arguments)); invokeMethodExpr = ReturnArgumentHelpers.ReturnValueConversion(routine.ArgFullInfo, invokeMethodExpr); invokeMethodExpr = HandleResult(invokeMethodExpr, routine.ArgFullInfo.ReturnType, false); }