public void Constant(Constant constant) { if (constant.Value == null) { ILUtil.EmitNull(_il); } else if (constant.Value is DateTime) { ILUtil.EmitConstant(_il, ((DateTime)constant.Value).Ticks); ILUtil.EmitNew(_il, typeof(DateTime).GetConstructor(new[] { typeof(long) })); } else if (constant.Value is TimeSpan) { ILUtil.EmitConstant(_il, ((TimeSpan)constant.Value).Ticks); ILUtil.EmitNew(_il, typeof(TimeSpan).GetConstructor(new[] { typeof(long) })); } else { ILUtil.EmitConstant(_il, constant.Value); } }
public void MethodCall(MethodCall methodCall) { bool isStatic = methodCall.Operand is TypeAccess; if (!isStatic) { bool emitBox = false; bool emitStoreLoad = false; if ( (methodCall.Operand is FieldAccess || methodCall.Operand is Constant) && methodCall.Operand.Type.IsValueType && !methodCall.MethodInfo.DeclaringType.IsValueType ) { emitBox = true; } else if ( methodCall.Operand.Type.IsValueType && ( !(methodCall.Operand is FieldAccess) || methodCall.MethodInfo.DeclaringType.IsValueType ) ) { emitStoreLoad = true; } // Signal field access that we're using the field as a // parameter. _fieldAsParameter = methodCall.Operand is FieldAccess && methodCall.MethodInfo.DeclaringType.IsValueType && !emitStoreLoad; try { methodCall.Operand.Accept(this); } finally { _fieldAsParameter = false; } if (emitBox) { _il.Emit(OpCodes.Box, methodCall.Operand.Type); } else if (emitStoreLoad) { Debug.Assert(methodCall.Operand.Type == methodCall.MethodInfo.DeclaringType); var builder = _il.DeclareLocal(methodCall.Operand.Type); _il.Emit(OpCodes.Stloc, builder); _il.Emit(OpCodes.Ldloca, builder); } } var parameters = methodCall.MethodInfo.GetParameters(); var arguments = methodCall.Arguments; bool paramsMethod = parameters.Length > 0 && parameters[parameters.Length - 1].GetCustomAttributes(typeof(ParamArrayAttribute), true).Length == 1; int mandatoryParameterCount = paramsMethod ? parameters.Length - 1 : parameters.Length; for (int i = 0; i < mandatoryParameterCount; i++) { Emit(arguments[i], parameters[i].ParameterType); } if (paramsMethod) { var paramsType = parameters[parameters.Length - 1].ParameterType; var elementType = paramsType.GetElementType(); bool emitted = false; // When the params argument is missing, a new array is issued. if (arguments.Count == mandatoryParameterCount) { ILUtil.EmitEmptyArray(_il, elementType); emitted = true; } else if (arguments.Count == mandatoryParameterCount + 1) { var lastArgument = arguments[arguments.Count - 1]; // Null arguments are passed blindly. if (lastArgument is Constant constant && constant.Value == null) { ILUtil.EmitNull(_il); emitted = true; } else { // So are array arguments that can be casted. if ( lastArgument.Type.IsArray && TypeUtil.CanCastImplicitely(lastArgument.Type, paramsType, false) ) { Emit(lastArgument, paramsType); emitted = true; } } } // If we didn't find a shortcut, emit the array with all // arguments. if (!emitted) { ILUtil.EmitArray( _il, elementType, arguments.Count - mandatoryParameterCount, p => Emit(arguments[mandatoryParameterCount + p], elementType) ); } }