/// <summary> /// Create a singleton field used to store property information for the provided property. /// </summary> /// <param name="property">The property weaver.</param> /// <returns></returns> public Variable CreatePropertyInfo(PropertyEmitter property) { var parent = property.Parent.Target.IsNotPublic ? property.Parent : CreateTypeContainer(property.Parent.Target); var type = property.Parent.Target; var sta = (property.Target.GetMethod ?? property.Target.SetMethod).IsStatic; var name = $"<{property.Target.Name}>k__PropertyInfo"; var existing = parent.GetField(name, Context.Finder.PropertyInfo, toStatic: true); if (existing != null) { return(existing); } var field = parent.EmitField(name, Context.Finder.PropertyInfo, toStatic: true, toPublic: true); var flags = BindingFlags.NonPublic | BindingFlags.Public | (sta ? BindingFlags.Static : BindingFlags.Instance); var il = parent.GetStaticConstructor().GetIL(); il.Emit(Codes.Nop); il.Emit(Codes.LoadToken(type.GetGeneric())); il.Emit(Codes.InvokeStatic(Context.Finder.TypeGetTypeFromHandle)); il.Emit(Codes.String(property.Target.Name)); il.Emit(Codes.Int((int)flags)); il.Emit(Codes.Invoke(Context.Finder.TypeGetProperty)); il.Emit(Codes.Store(field)); return(field); }
/// <summary> /// Create a singleton field used to store parameter information for the provided method. /// </summary> /// <param name="method">The method weaver.</param> /// <param name="param">The parameter.</param> /// <returns></returns> public Variable CreateParameterInfo(MethodEmitter method, ParameterReference param) { var parent = method.Parent.Target.IsNotPublic ? method.Parent : CreateTypeContainer(method.Parent.Target); var type = method.Parent.Target; var id = method.Target.GetHashString(); var name = $"<{method.Target.Name}${id}${param.Index}>k__ParameterInfo"; var existing = parent.GetField(name, Context.Finder.ParameterInfo, toStatic: true); if (existing != null) { return(existing); } var field = parent.EmitField(name, Context.Finder.ParameterInfo, toStatic: true, toPublic: true); var il = parent.GetStaticConstructor().GetIL(); il.Emit(Codes.Nop); il.Emit(Codes.LoadToken(type.HasGenericParameters ? method.Target : method.Target.GetGeneric())); il.Emit(Codes.LoadToken(type.GetGeneric())); il.Emit(Codes.InvokeStatic(Context.Finder.MethodBaseGetMethodFromHandleAndType)); il.Emit(Codes.Invoke(Context.Finder.MethodBaseGetParameters)); il.Emit(Codes.Int(param.Index)); il.Emit(Codes.LoadArray); il.Emit(Codes.Store(field)); return(field); }
/// <summary> /// Copies the values of an array of parameter values into the corresponding parameters. /// </summary> /// <param name="method">The method.</param> /// <param name="array">The array.</param> public void CopyArgumentArrayToParameters(MethodEmitter method, Variable array) { var parameters = method.Target.Parameters; var count = parameters.Count; var il = method.GetIL(); for (int i = 0; i < count; i++) { var p = parameters[i]; var variable = new Variable(p); var type = p.ParameterType; if (type.IsByReference || p.IsOut) { continue; } il.Emit(Codes.Load(array)); il.Emit(Codes.Int(i)); il.Emit(Codes.LoadArray); il.Emit(Codes.Unbox(type)); il.Emit(Codes.Store(variable)); } CopyArgumentArrayToReferences(method, array); }
/// <summary> /// Creates a reference to a parameter used in a custom attribute. /// </summary> /// <param name="emitter">The emitter.</param> /// <param name="attribute">The attribute.</param> /// <param name="arg">The argument.</param> public void CreateAttributeParameter(MethodEmitter emitter, CustomAttribute attribute, CustomAttributeArgument arg) { var il = emitter.GetIL(); if (arg.Value == null) { il.Emit(Codes.Null); return; } var type = arg.Type; if (type.IsArray) { var elements = (arg.Value as IEnumerable).Cast <CustomAttributeArgument>().ToArray(); il.Emit(Codes.Int(elements.Length)); il.Emit(Codes.CreateArray(type.GetElementType())); if (elements.Length == 0) { return; } il.Emit(Codes.Duplicate); for (int i = 0, count = elements.Length; i < count; i++) { il.Emit(Codes.Int(i)); if (elements[i].Value == null) { il.Emit(Codes.Null); il.Emit(Codes.StoreArray); } else { il.Emit(Codes.Load(elements[i].Value)); il.Emit(Codes.StoreArray); } if (i + 1 < count) { il.Emit(Codes.Duplicate); } } } else { il.Emit(Codes.Load(arg.Value)); } }
/// <summary> /// Copies the values of an array of parameter values into the required references. /// </summary> /// <param name="method">The method.</param> /// <param name="array">The array.</param> public void CopyArgumentArrayToReferences(MethodEmitter method, Variable array) { var parameters = method.Target.Parameters; var count = parameters.Count; var il = method.GetIL(); for (int i = 0; i < count; i++) { var p = parameters[i]; var type = p.ParameterType; if (!type.IsByReference || p.IsOut) { continue; } var spec = (TypeSpecification)type; var unboxing = true; il.Emit(Codes.Arg(p)); il.Emit(Codes.Load(array)); il.Emit(Codes.Int(i)); il.Emit(Codes.LoadArray); var code = OpCodes.Nop; switch (spec.ElementType.MetadataType) { case MetadataType.Boolean: case MetadataType.SByte: case MetadataType.Byte: code = OpCodes.Stind_I1; break; case MetadataType.Int16: case MetadataType.UInt16: code = OpCodes.Stind_I2; break; case MetadataType.Int32: case MetadataType.UInt32: code = OpCodes.Stind_I4; break; case MetadataType.Int64: case MetadataType.UInt64: code = OpCodes.Stind_I8; break; case MetadataType.Single: code = OpCodes.Stind_R4; break; case MetadataType.Double: code = OpCodes.Stind_R8; break; case MetadataType.IntPtr: case MetadataType.UIntPtr: code = OpCodes.Stind_I; break; default: if (spec.ElementType.IsValueType) { il.Emit(Instruction.Create(OpCodes.Stobj, spec.ElementType)); } else { code = OpCodes.Stind_Ref; unboxing = false; } break; } if (unboxing) { il.Emit(Codes.Unbox(spec.ElementType)); } if (code != OpCodes.Nop) { il.Emit(code); } } }
/// <summary> /// Create an array variable containing the arguments of the method invocation. /// </summary> /// <param name="method">The method weaver.</param> /// <returns></returns> public Variable CreateArgumentArray(MethodEmitter method) { var parameters = method.Target.Parameters; var count = parameters.Count; var array = method.EmitLocal(Context.Finder.ObjectArray); var il = method.GetIL(); il.Emit(Codes.Nop); il.Emit(Codes.Int(count)); il.Emit(Codes.CreateArray(TypeSystem.ObjectReference)); il.Emit(Codes.Store(array)); for (int i = 0; i < count; i++) { var p = parameters[i]; var type = p.ParameterType; il.Emit(Codes.Load(array)); il.Emit(Codes.Int(i)); if (p.IsOut) { var spec = (TypeSpecification)type; if (spec.ElementType.IsValueType) { il.Emit(Codes.Init(spec.ElementType)); } else { il.Emit(Codes.Null); il.Emit(Codes.StoreArray); } continue; } il.Emit(Codes.Arg(p)); if (type.IsByReference) { var spec = (TypeSpecification)type; var boxing = true; switch (spec.ElementType.MetadataType) { case MetadataType.SByte: il.Emit(OpCodes.Ldind_I1); break; case MetadataType.Int16: il.Emit(OpCodes.Ldind_I2); break; case MetadataType.Int32: il.Emit(OpCodes.Ldind_I4); break; case MetadataType.Int64: case MetadataType.UInt64: il.Emit(OpCodes.Ldind_I8); break; case MetadataType.Boolean: case MetadataType.Byte: il.Emit(OpCodes.Ldind_U1); break; case MetadataType.UInt16: il.Emit(OpCodes.Ldind_U2); break; case MetadataType.UInt32: il.Emit(OpCodes.Ldind_U4); break; case MetadataType.Single: il.Emit(OpCodes.Ldind_R4); break; case MetadataType.Double: il.Emit(OpCodes.Ldind_R8); break; case MetadataType.IntPtr: case MetadataType.UIntPtr: il.Emit(OpCodes.Ldind_I); break; default: if (spec.ElementType.IsValueType) { il.Emit(Instruction.Create(OpCodes.Ldobj, spec.ElementType)); } else { il.Emit(OpCodes.Ldind_Ref); boxing = false; } break; } if (boxing) { il.Emit(Codes.Box(spec.ElementType)); } } else { il.Emit(Codes.Box(p.ParameterType)); } il.Emit(Codes.StoreArray); } return(array); }