protected virtual void ImplementInvokeMethodOnTarget(AbstractTypeEmitter invocation, ParameterInfo[] parameters, MethodEmitter invokeMethodOnTarget, Reference targetField) { var callbackMethod = GetCallbackMethod(invocation); if (callbackMethod == null) { EmitCallThrowOnNoTarget(invokeMethodOnTarget); return; } var args = new IExpression[parameters.Length]; // Idea: instead of grab parameters one by one // we should grab an array var byRefArguments = new Dictionary <int, LocalReference>(); for (var i = 0; i < parameters.Length; i++) { var param = parameters[i]; var paramType = invocation.GetClosedParameterType(param.ParameterType); if (paramType.IsByRef) { var localReference = invokeMethodOnTarget.CodeBuilder.DeclareLocal(paramType.GetElementType()); invokeMethodOnTarget.CodeBuilder .AddStatement( new AssignStatement(localReference, new ConvertExpression(paramType.GetElementType(), new MethodInvocationExpression(SelfReference.Self, InvocationMethods.GetArgumentValue, new LiteralIntExpression(i))))); var byRefReference = new ByRefReference(localReference); args[i] = byRefReference; byRefArguments[i] = localReference; } else { args[i] = new ConvertExpression(paramType, new MethodInvocationExpression(SelfReference.Self, InvocationMethods.GetArgumentValue, new LiteralIntExpression(i))); } } if (byRefArguments.Count > 0) { invokeMethodOnTarget.CodeBuilder.AddStatement(new TryStatement()); } var methodOnTargetInvocationExpression = GetCallbackMethodInvocation(invocation, args, callbackMethod, targetField, invokeMethodOnTarget); LocalReference returnValue = null; if (callbackMethod.ReturnType != typeof(void)) { var returnType = invocation.GetClosedParameterType(callbackMethod.ReturnType); returnValue = invokeMethodOnTarget.CodeBuilder.DeclareLocal(returnType); invokeMethodOnTarget.CodeBuilder.AddStatement(new AssignStatement(returnValue, methodOnTargetInvocationExpression)); } else { invokeMethodOnTarget.CodeBuilder.AddStatement(methodOnTargetInvocationExpression); } AssignBackByRefArguments(invokeMethodOnTarget, byRefArguments); if (callbackMethod.ReturnType != typeof(void)) { var setRetVal = new MethodInvocationExpression(SelfReference.Self, InvocationMethods.SetReturnValue, new ConvertExpression(typeof(object), returnValue.Type, returnValue)); invokeMethodOnTarget.CodeBuilder.AddStatement(setRetVal); } invokeMethodOnTarget.CodeBuilder.AddStatement(new ReturnStatement()); }
protected virtual void ImplementInvokeMethodOnTarget(AbstractTypeEmitter invocation, ParameterInfo[] parameters, MethodEmitter invokeMethodOnTarget, Reference targetField) { var callbackMethod = GetCallbackMethod(invocation); if (callbackMethod == null) { EmitCallThrowOnNoTarget(invokeMethodOnTarget); return; } if (canChangeTarget) { EmitCallEnsureValidTarget(invokeMethodOnTarget); } Expression[] args = new Expression[parameters.Length]; // Idea: instead of grab parameters one by one // we should grab an array Dictionary <int, LocalReference> byRefArguments = new Dictionary <int, LocalReference>(); for (int i = 0; i < parameters.Length; i++) { ParameterInfo param = parameters[i]; Type paramType = invocation.GetClosedParameterType(param.ParameterType); if (paramType.IsByRef) { LocalReference localReference = invokeMethodOnTarget.CodeBuilder.DeclareLocal(paramType.GetElementType()); invokeMethodOnTarget.CodeBuilder .AddStatement( new AssignStatement(localReference, new ConvertExpression(paramType.GetElementType(), new MethodInvocationExpression(SelfReference.Self, InvocationMethods.GetArgumentValue, new LiteralIntExpression(i))))); ByRefReference byRefReference = new ByRefReference(localReference); args[i] = new ReferenceExpression(byRefReference); byRefArguments[i] = localReference; } else { args[i] = new ConvertExpression(paramType, new MethodInvocationExpression(SelfReference.Self, InvocationMethods.GetArgumentValue, new LiteralIntExpression(i))); } } var methodOnTargetInvocationExpression = GetCallbackMethodInvocation(invocation, args, callbackMethod, targetField, invokeMethodOnTarget); LocalReference returnValue = null; if (callbackMethod.ReturnType != typeof(void)) { Type returnType = invocation.GetClosedParameterType(callbackMethod.ReturnType); returnValue = invokeMethodOnTarget.CodeBuilder.DeclareLocal(returnType); invokeMethodOnTarget.CodeBuilder.AddStatement(new AssignStatement(returnValue, methodOnTargetInvocationExpression)); } else { invokeMethodOnTarget.CodeBuilder.AddStatement(new ExpressionStatement(methodOnTargetInvocationExpression)); } foreach (KeyValuePair <int, LocalReference> byRefArgument in byRefArguments) { int index = byRefArgument.Key; LocalReference localReference = byRefArgument.Value; invokeMethodOnTarget.CodeBuilder.AddStatement( new ExpressionStatement( new MethodInvocationExpression(SelfReference.Self, InvocationMethods.SetArgumentValue, new LiteralIntExpression(index), new ConvertExpression(typeof(object), localReference. Type, new ReferenceExpression (localReference))) )); } if (callbackMethod.ReturnType != typeof(void)) { var setRetVal = new MethodInvocationExpression(SelfReference.Self, InvocationMethods.SetReturnValue, new ConvertExpression(typeof(object), returnValue.Type, returnValue.ToExpression())); invokeMethodOnTarget.CodeBuilder.AddStatement(new ExpressionStatement(setRetVal)); } invokeMethodOnTarget.CodeBuilder.AddStatement(new ReturnStatement()); }