/// <summary> /// Wraps the field. /// </summary> public void Wrap(WrapContext context) { // Throw an exception if it's not a compiler generated field. if (this.m_Field.CustomAttributes.Count(c => c.AttributeType.Name == "CompilerGeneratedAttribute") == 0 && !this.IsEvent(this.m_Field.FieldType) && !Utility.HasAttribute(this.m_Field.CustomAttributes, "LocalAttribute") && !this.m_Field.IsLiteral) { throw new PostProcessingException(this.m_Type.FullName, this.m_Field.Name, "The field '" + this.m_Field.Name + "' was found. Distributed types may not contain fields as they can not be hooked successfully. Use auto-generated properties instead."); } if (this.IsEvent(this.m_Field.FieldType) && !Utility.HasAttribute(this.m_Field.CustomAttributes, "LocalAttribute")) { throw new PostProcessingException( this.m_Type.FullName, this.m_Field.Name, "Distributed events are no longer supported in version 3."); } // Apply the ProtoMember attribute if this is not a local field, constant or the Node field. if (this.m_Field.Name != "<Node>k__BackingField" && !Utility.HasAttribute(this.m_Field.CustomAttributes, "LocalAttribute") && !this.m_Field.IsLiteral) { Utility.AddProtoMemberAttribute(this.m_Field, ++context.ProtoMemberCount); } }
/// <summary> /// Wraps the method. /// </summary> public void Wrap(WrapContext context) { this.m_TraceSource.TraceEvent(TraceEventType.Information, 0, "Modifying {0} for distributed processing", this.m_Constructor.Name); // Create the Process4.Providers.DpmEntrypoint::Construct method reference. var construct = new MethodReference("Construct", this.m_Type.Module.Import(typeof(void)), this.m_Type.Module.Import(typeof(DpmEntrypoint))); construct.Parameters.Add(new ParameterDefinition(this.m_Type.Module.Import(typeof(object)))); // It's technically not valid to call a method on this before the base constructor // has been called. To ensure the code is valid, we find the call to the base constructor and place // our Construct call right after it. Instruction instr = null; for (var i = 0; i < this.m_Constructor.Body.Instructions.Count; i++) { instr = this.m_Constructor.Body.Instructions[i]; if (instr.OpCode == OpCodes.Call && instr.Operand is MethodReference && ((MethodReference)instr.Operand).Name == ".ctor") { break; } } // Prepend instructions. var il = this.m_Constructor.Body.GetILProcessor(); il.InsertAfter(instr, Instruction.Create(OpCodes.Call, construct)); il.InsertAfter(instr, Instruction.Create(OpCodes.Ldarg_0)); }
/// <summary> /// Wraps the field. /// </summary> public void Wrap(WrapContext context) { // Throw an exception if it's not a compiler generated field. if (this.m_Field.CustomAttributes.Count(c => c.AttributeType.Name == "CompilerGeneratedAttribute") == 0 && !this.IsEvent(this.m_Field.FieldType) && !Utility.HasAttribute(this.m_Field.CustomAttributes, "LocalAttribute") && !this.m_Field.IsLiteral) throw new PostProcessingException(this.m_Type.FullName, this.m_Field.Name, "The field '" + this.m_Field.Name + "' was found. Distributed types may not contain fields as they can not be hooked successfully. Use auto-generated properties instead."); if (this.IsEvent(this.m_Field.FieldType) && !Utility.HasAttribute(this.m_Field.CustomAttributes, "LocalAttribute")) { throw new PostProcessingException( this.m_Type.FullName, this.m_Field.Name, "Distributed events are no longer supported in version 3."); } // Apply the ProtoMember attribute if this is not a local field, constant or the Node field. if (this.m_Field.Name != "<Node>k__BackingField" && !Utility.HasAttribute(this.m_Field.CustomAttributes, "LocalAttribute") && !this.m_Field.IsLiteral) { Utility.AddProtoMemberAttribute(this.m_Field, ++context.ProtoMemberCount); } }
/// <summary> /// Wraps the property. /// </summary> public void Wrap(WrapContext context) { // Check to ensure property type has a distributed attribute or is a value type. if (this.m_Property.PropertyType.Resolve() == null) { // Not sure what to do with this? var warning = "Property {0} has type {1} which does not resolve to a full type. If this is a " + "generic type, ensure that the generic type is restricted to value types or other " + "distributed types. If a non-distributed type is used, runtime exceptions may occur."; this.m_TraceSource.TraceEvent( TraceEventType.Warning, 0, warning, this.m_Property.Name, this.m_Property.PropertyType.Name); } else if (this.m_Property.PropertyType.IsValueType || this.m_Property.PropertyType.IsArray || this.m_Property.PropertyType.Resolve().IsInterface || this.m_Property.PropertyType.FullName == "System.String" || Utility.HasAttribute(this.m_Property.PropertyType.Resolve(), "DistributedAttribute")) { // This is a valid type. this.m_TraceSource.TraceEvent(TraceEventType.Information, 0, "Recognised {0} as valid property", this.m_Property.Name); } else if (Utility.HasAttribute(this.m_Property.CustomAttributes, "LocalAttribute")) { // This is a localized property; add the get and set methods to our // exclusion list. this.m_TraceSource.TraceEvent( TraceEventType.Verbose, 0, "Adding getter / setters of {0} to exclusions list because the property is marked with LocalAttribute", this.m_Property.Name); this.Exclusions.Add(this.m_Property.GetMethod.Name); this.Exclusions.Add(this.m_Property.SetMethod.Name); } else { // This is an invalid type (throw an exception). this.m_TraceSource.TraceEvent(TraceEventType.Error, 0, "Property {0} isn't of a valid type", this.m_Property.Name); throw new PostProcessingException( this.m_Type.FullName, this.m_Property.Name, "The property '" + this.m_Property.Name + "' is of type '" + this.m_Property.PropertyType.Name + "', but it is not a distributed or value type. Distributed types may only contain properties that are value types or types which are also distributed."); } }
public void Wrap(WrapContext context) { var synchronisedFieldsOrProperties = new List <FieldOrPropertyDefinition>(); foreach (var property in this.m_Type.Properties) { if (Utility.HasAttribute(property.CustomAttributes, "SynchronisedAttribute")) { synchronisedFieldsOrProperties.Add(new FieldOrPropertyDefinition { Property = property, IsField = false }); } } foreach (var field in this.m_Type.Fields) { if (Utility.HasAttribute(field.CustomAttributes, "SynchronisedAttribute")) { synchronisedFieldsOrProperties.Add(new FieldOrPropertyDefinition { Field = field, IsField = true }); } } if (synchronisedFieldsOrProperties.Count == 0) { return; } this.m_TraceSource.TraceEvent( TraceEventType.Information, 0, "Detected synchronisation attribute on one or more fields / properties of {0}", this.m_Type.FullName); // Mark as processed. this.m_TraceSource.TraceEvent(TraceEventType.Verbose, 0, "Adding ProcessedAttribute to {0}", this.m_Type.FullName); Utility.AddAttribute(this.m_Type, typeof(ProcessedAttribute), this.m_Type.Module); // Get a reference to the synchronisation store's constructor. var synchronisationStoreCtor = new MethodReference( ".ctor", this.m_Type.Module.Import(typeof(void)), this.m_Type.Module.Import(typeof(SynchronisationStore))); synchronisationStoreCtor.HasThis = true; // Generate nested class that inherits from SynchronisationStore. var nestedClass = this.m_TypeBuilder.CreateNestedClass( this.m_Type, string.Empty, this.m_Type.Name + "_SynchronisationStore", this.m_Type.Module.Import(typeof(SynchronisationStore))); // Add distributed attribute onto the nested class. nestedClass.CustomAttributes.Add(new CustomAttribute( new MethodReference( ".ctor", this.m_Type.Module.Import(typeof(void)), this.m_Type.Module.Import(typeof(DistributedAttribute))) { HasThis = true })); // Create copies of all synchronised properties in the synchronisation store. foreach (var prop in synchronisedFieldsOrProperties) { if (prop.IsField) { Utility.AddAutoProperty( nestedClass, prop.Field.Name, this.m_SynchronisationTypeTranslator.GetDistributedType(prop.Field.FieldType)); } else { Utility.AddAutoProperty( nestedClass, prop.Property.Name, this.m_SynchronisationTypeTranslator.GetDistributedType(prop.Property.PropertyType)); } } // Create default constructor. var ctor = this.m_MethodBuilder.CreateConstructor(nestedClass); var ctorIL = ctor.Body.GetILProcessor(); ctorIL.Append(Instruction.Create(OpCodes.Ldarg_0)); ctorIL.Append(Instruction.Create(OpCodes.Call, synchronisationStoreCtor)); ctorIL.Append(Instruction.Create(OpCodes.Ret)); // Create overrides for GetNames and GetTypes. var getNames = this.m_MethodBuilder.CreateOverride( nestedClass, "GetNames", nestedClass.Module.Import(typeof(string[]))); var getTypes = this.m_MethodBuilder.CreateOverride( nestedClass, "GetTypes", nestedClass.Module.Import(typeof(Type[]))); var getIsFields = this.m_MethodBuilder.CreateOverride( nestedClass, "GetIsFields", nestedClass.Module.Import(typeof(bool[]))); // Mark the methods as local so the distributed processor doesn't // intercept them at all. getNames.CustomAttributes.Add(new CustomAttribute(new MethodReference( ".ctor", this.m_Type.Module.Import(typeof(void)), this.m_Type.Module.Import(typeof(LocalAttribute))) { HasThis = true })); getTypes.CustomAttributes.Add(new CustomAttribute(new MethodReference( ".ctor", this.m_Type.Module.Import(typeof(void)), this.m_Type.Module.Import(typeof(LocalAttribute))) { HasThis = true })); getIsFields.CustomAttributes.Add(new CustomAttribute(new MethodReference( ".ctor", this.m_Type.Module.Import(typeof(void)), this.m_Type.Module.Import(typeof(LocalAttribute))) { HasThis = true })); // Emit opcodes to produce GetNames. getNames.Body.Variables.Add(new VariableDefinition( this.m_Type.Module.Import(typeof(string[])))); var getNamesIL = getNames.Body.GetILProcessor(); getNamesIL.Append(Instruction.Create(OpCodes.Ldc_I4, synchronisedFieldsOrProperties.Count)); getNamesIL.Append(Instruction.Create(OpCodes.Newarr, this.m_Type.Module.Import(typeof(string)))); for (var i = 0; i < synchronisedFieldsOrProperties.Count; i++) { var name = synchronisedFieldsOrProperties[i].IsField ? synchronisedFieldsOrProperties[i].Field.Name : synchronisedFieldsOrProperties[i].Property.Name; getNamesIL.Append(Instruction.Create(OpCodes.Dup)); getNamesIL.Append(Instruction.Create(OpCodes.Ldc_I4, i)); getNamesIL.Append(Instruction.Create(OpCodes.Ldstr, name)); getNamesIL.Append(Instruction.Create(OpCodes.Stelem_Ref)); } getNamesIL.Append(Instruction.Create(OpCodes.Stloc_0)); getNamesIL.Append(Instruction.Create(OpCodes.Ldloc_0)); getNamesIL.Append(Instruction.Create(OpCodes.Ret)); // Get a reference to the GetTypeFromHandle method, which is used for typeof(). var getTypeFromHandle = new MethodReference( "GetTypeFromHandle", this.m_Type.Module.Import(typeof(Type)), this.m_Type.Module.Import(typeof(Type))); getTypeFromHandle.Parameters.Add(new ParameterDefinition( this.m_Type.Module.Import(typeof(RuntimeTypeHandle)))); // Emit opcodes to produce GetTypes. getTypes.Body.Variables.Add(new VariableDefinition( this.m_Type.Module.Import(typeof(Type[])))); var getTypesIL = getTypes.Body.GetILProcessor(); getTypesIL.Append(Instruction.Create(OpCodes.Ldc_I4, synchronisedFieldsOrProperties.Count)); getTypesIL.Append(Instruction.Create(OpCodes.Newarr, this.m_Type.Module.Import(typeof(Type)))); for (var i = 0; i < synchronisedFieldsOrProperties.Count; i++) { var type = synchronisedFieldsOrProperties[i].IsField ? synchronisedFieldsOrProperties[i].Field.FieldType : synchronisedFieldsOrProperties[i].Property.PropertyType; getTypesIL.Append(Instruction.Create(OpCodes.Dup)); getTypesIL.Append(Instruction.Create(OpCodes.Ldc_I4, i)); getTypesIL.Append(Instruction.Create(OpCodes.Ldtoken, this.m_Type.Module.Import(type))); getTypesIL.Append(Instruction.Create(OpCodes.Call, getTypeFromHandle)); getTypesIL.Append(Instruction.Create(OpCodes.Stelem_Ref)); } getTypesIL.Append(Instruction.Create(OpCodes.Stloc_0)); getTypesIL.Append(Instruction.Create(OpCodes.Ldloc_0)); getTypesIL.Append(Instruction.Create(OpCodes.Ret)); // Emit opcodes to produce GetNames. getIsFields.Body.Variables.Add(new VariableDefinition( this.m_Type.Module.Import(typeof(bool[])))); var getIsFieldsIL = getIsFields.Body.GetILProcessor(); getIsFieldsIL.Append(Instruction.Create(OpCodes.Ldc_I4, synchronisedFieldsOrProperties.Count)); getIsFieldsIL.Append(Instruction.Create(OpCodes.Newarr, this.m_Type.Module.Import(typeof(bool)))); for (var i = 0; i < synchronisedFieldsOrProperties.Count; i++) { getIsFieldsIL.Append(Instruction.Create(OpCodes.Dup)); getIsFieldsIL.Append(Instruction.Create(OpCodes.Ldc_I4, i)); getIsFieldsIL.Append(Instruction.Create(OpCodes.Ldc_I4, synchronisedFieldsOrProperties[i].IsField ? 1 : 0)); getIsFieldsIL.Append(Instruction.Create(OpCodes.Stelem_I1)); } getIsFieldsIL.Append(Instruction.Create(OpCodes.Stloc_0)); getIsFieldsIL.Append(Instruction.Create(OpCodes.Ldloc_0)); getIsFieldsIL.Append(Instruction.Create(OpCodes.Ret)); // Create the field on the original type to hold an instance of // the nested class. var syncField = new FieldDefinition( "<>_SynchronisationField", FieldAttributes.Private, nestedClass); syncField.CustomAttributes.Add(new CustomAttribute(new MethodReference( ".ctor", this.m_Type.Module.Import(typeof(void)), this.m_Type.Module.Import(typeof(CompilerGeneratedAttribute))) { HasThis = true })); this.m_Type.Fields.Add(syncField); // Implement the ISynchronised interface on the original class. var syncMethod = new MethodDefinition( "GetSynchronisationStore", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Final | MethodAttributes.Virtual, this.m_Type.Module.Import(typeof(SynchronisationStore))); syncMethod.Parameters.Add(new ParameterDefinition( this.m_Type.Module.Import(typeof(ILocalNode)))); syncMethod.Parameters.Add(new ParameterDefinition( this.m_Type.Module.Import(typeof(string)))); this.m_Type.Methods.Add(syncMethod); // Get a reference to Distributed<NestedClass> and it's constructor. var distributedClass = this.m_Type.Module.Import(typeof(Distributed <>)); var distributedNestedClass = new GenericInstanceType(distributedClass); distributedNestedClass.GenericArguments.Add(nestedClass); var distributedNestedCtor = new MethodReference( ".ctor", this.m_Type.Module.Import(typeof(void)), distributedNestedClass) { HasThis = true }; distributedNestedCtor.Parameters.Add(new ParameterDefinition( this.m_Type.Module.Import(typeof(ILocalNode)))); distributedNestedCtor.Parameters.Add(new ParameterDefinition( this.m_Type.Module.Import(typeof(string)))); // Get a reference to the cast to convert it to back to it's original object. var distributedNestedCast = new MethodReference( "op_Implicit", distributedClass.GenericParameters[0], distributedNestedClass); distributedNestedCast.HasThis = false; var distributedNestedClassParam2 = new GenericInstanceType(this.m_Type.Module.Import(typeof(Distributed <>))); distributedNestedClassParam2.GenericArguments.Add(distributedClass.GenericParameters[0]); distributedNestedCast.Parameters.Add(new ParameterDefinition(distributedNestedClassParam2)); // Implement the GetSynchronisationStore method. syncMethod.Body.Variables.Add(new VariableDefinition(nestedClass)); var il = syncMethod.Body.GetILProcessor(); il.Append(Instruction.Create(OpCodes.Ldarg_0)); var beforeCheck = Instruction.Create(OpCodes.Ldfld, syncField); il.Append(beforeCheck); // Brtrue to be inserted here il.Append(Instruction.Create(OpCodes.Ldarg_0)); il.Append(Instruction.Create(OpCodes.Ldarg_1)); il.Append(Instruction.Create(OpCodes.Ldarg_2)); il.Append(Instruction.Create(OpCodes.Newobj, distributedNestedCtor)); il.Append(Instruction.Create(OpCodes.Call, distributedNestedCast)); il.Append(Instruction.Create(OpCodes.Stfld, syncField)); var skip = Instruction.Create(OpCodes.Ldarg_0); il.Append(skip); il.Append(Instruction.Create(OpCodes.Ldfld, syncField)); il.Append(Instruction.Create(OpCodes.Ret)); // Insert brtrue. il.InsertAfter( beforeCheck, Instruction.Create(OpCodes.Brtrue, skip)); // Add interface. this.m_Type.Interfaces.Add(this.m_Type.Module.Import(typeof(ISynchronised))); // Finally, apply distributed processing to the nested class! this.m_TraceSource.TraceEvent(TraceEventType.Information, 0, "Starting processing of {0}", nestedClass.Name); new TypeWrapper(nestedClass).Wrap(new WrapContext(0)); this.m_TraceSource.TraceEvent(TraceEventType.Information, 0, "Finished processing of {0}", nestedClass.Name); }
/// <summary> /// Wraps the method. /// </summary> public void Wrap(WrapContext context) { if (this.m_Method.CustomAttributes.Any(c => c.AttributeType.Name == "LocalAttribute")) return; this.m_TraceSource.TraceEvent(TraceEventType.Information, 0, "Modifying {0} for distributed processing", this.m_Method.Name); // Generate the direct invocation class. TypeDefinition idc = this.GenerateDirectInvokeClass(); // Get a list of existing instructions. Collection<Instruction> instructions = this.m_Method.Body.Instructions; // Get a reference to the context setting method. var assignNodeContext = new MethodReference("AssignNodeContext", this.m_Type.Module.Import(typeof(void)), this.m_Type.Module.Import(typeof(DpmConstructContext))); assignNodeContext.Parameters.Add(new ParameterDefinition(this.m_Type.Module.Import(typeof(object)))); // Create a new Action delegate using those instructions. TypeReference mdr = this.m_Method.ReturnType; MethodDefinition md = new MethodDefinition(this.m_Method.Name + "__Distributed0", MethodAttributes.Private, mdr); md.Body = new MethodBody(md); md.Body.InitLocals = true; md.Body.Instructions.Clear(); foreach (Instruction ii in instructions) { if (ii.OpCode == OpCodes.Newobj) { md.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); md.Body.Instructions.Add(Instruction.Create(OpCodes.Call, assignNodeContext)); } md.Body.Instructions.Add(ii); } foreach (VariableDefinition l in this.m_Method.Body.Variables) { md.Body.Variables.Add(l); } foreach (ExceptionHandler ex in this.m_Method.Body.ExceptionHandlers) { md.Body.ExceptionHandlers.Add(ex); } foreach (ParameterDefinition p in this.m_Method.Parameters) { md.Parameters.Add(p); } foreach (GenericParameter gp in this.m_Method.GenericParameters) { GenericParameter gpn = new GenericParameter(gp.Name, md); gpn.Attributes = gp.Attributes; foreach (TypeReference tr in gp.Constraints) { gpn.Constraints.Add(tr); } md.GenericParameters.Add(gpn); } this.m_Type.Methods.Add(md); Utility.AddAttribute(md, typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), this.m_Module); // Get the ILProcessor and create variables to store the delegate variable // and delegate constructor. ILProcessor il = this.m_Method.Body.GetILProcessor(); VariableDefinition vd; MethodReference ct; // Clear the existing instructions and local variables. this.m_Method.Body.ExceptionHandlers.Clear(); this.m_Method.Body.Instructions.Clear(); this.m_Method.Body.Variables.Clear(); // Generate the IL for the delegate definition and fill the vd and ct // variables. TypeDefinition dg = Utility.EmitDelegate(il, idc, md, this.m_Type, out vd, out ct); // Implement the Invoke method in the DirectInvoke class. this.ImplementDirectInvokeClass(idc, dg, md.Parameters, md.ReturnType); // Create the Process4.Providers.DpmEntrypoint::GetProperty method reference. MethodReference getproperty = new MethodReference("GetProperty", this.m_Type.Module.Import(typeof(object)), this.m_Type.Module.Import(typeof(DpmEntrypoint))); getproperty.Parameters.Add(new ParameterDefinition(this.m_Type.Module.Import(typeof(Delegate)))); getproperty.Parameters.Add(new ParameterDefinition(this.m_Type.Module.Import(typeof(object[])))); // Create the Process4.Providers.DpmEntrypoint::SetProperty method reference. MethodReference setproperty = new MethodReference("SetProperty", this.m_Type.Module.Import(typeof(object)), this.m_Type.Module.Import(typeof(DpmEntrypoint))); setproperty.Parameters.Add(new ParameterDefinition(this.m_Type.Module.Import(typeof(Delegate)))); setproperty.Parameters.Add(new ParameterDefinition(this.m_Type.Module.Import(typeof(object[])))); // Create the Process4.Providers.DpmEntrypoint::Invoke method reference. MethodReference invoke = new MethodReference("Invoke", this.m_Type.Module.Import(typeof(object)), this.m_Type.Module.Import(typeof(DpmEntrypoint))); invoke.Parameters.Add(new ParameterDefinition(this.m_Type.Module.Import(typeof(Delegate)))); invoke.Parameters.Add(new ParameterDefinition(this.m_Type.Module.Import(typeof(object[])))); // Generate the local variables like: // * 0 - MultitypeDelegate // * 1 - object[] // * 2 - {return type} (if not void) VariableDefinition v_0 = vd; VariableDefinition v_1 = new VariableDefinition(this.m_Type.Module.Import(typeof(object[]))); VariableDefinition v_2 = new VariableDefinition(md.ReturnType); // Add the variables to the local variable list (delegate is already added). this.m_Method.Body.Variables.Add(v_1); if (v_2.VariableType.Name.ToLower() != "void") { this.m_Method.Body.Variables.Add(v_2); } // Force local variables to be initalized. this.m_Method.Body.InitLocals = true; this.m_Method.Body.MaxStackSize = 10; // Create statement processor for method. StatementProcessor processor = new StatementProcessor(il); // Make a generic version of the delegate method. TypeDefinition btd = this.m_Type; MethodDefinition bmd = md; MethodReference bmr = btd.Module.Import(bmd); GenericInstanceType bti = null; if (this.m_Type.HasGenericParameters) { bti = (GenericInstanceType)Utility.MakeGenericType(this.m_Type, this.m_Type.GenericParameters.ToArray()); bmr = Utility.MakeGeneric(bmr, bti.GenericArguments.ToArray()); } if (this.m_Method.HasGenericParameters) { GenericInstanceMethod gim = new GenericInstanceMethod(bmr); foreach (GenericParameter gp in bmr.GenericParameters) { gim.GenericArguments.Add(gp); } bmr = gim; } foreach (var gp in this.m_Type.GenericParameters) { ((GenericInstanceType)ct.DeclaringType).GenericArguments.Add(gp); } foreach (var gp in this.m_Method.GenericParameters) { ((GenericInstanceType)ct.DeclaringType).GenericArguments.Add(gp); } // Initialize the delegate. processor.Add(new InitDelegateStatement(ct, bmr, v_0)); // Initialize the array. if (this.m_Method.IsSetter) { il.Append(Instruction.Create(OpCodes.Ldloc_0)); } processor.Add( new InitArrayStatement( this.m_Module.Import(typeof(object)), (sbyte)md.Parameters.Count, v_1, new Action<ILProcessor, int>((p, i) => { // Get a reference to the parameter being passed to the method. ParameterDefinition pd = this.m_Method.Parameters[i]; if (i > this.m_Method.Parameters.Count - 1) { return; } // Create IL to copy the value from the parameter directly // into the array, boxing the value if needed. p.Append(Instruction.Create(OpCodes.Ldloc, v_1)); p.Append(Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)i)); p.Append(Instruction.Create(OpCodes.Ldarg_S, pd)); if (pd.ParameterType.IsValueType || pd.ParameterType.IsGenericParameter) { p.Append(Instruction.Create(OpCodes.Box, pd.ParameterType)); } p.Append(Instruction.Create(OpCodes.Stelem_Ref)); }))); // Call the delegate. if (this.m_Method.IsSetter) { processor.Add(new CallStatement(setproperty, new VariableDefinition[] { v_1 }, this.m_Method.ReturnType, v_2)); } else if (this.m_Method.IsGetter) { processor.Add(new CallStatement(getproperty, new VariableDefinition[] { v_0, v_1 }, this.m_Method.ReturnType, v_2)); } else { processor.Add(new CallStatement(invoke, new VariableDefinition[] { v_0, v_1 }, this.m_Method.ReturnType, v_2)); } }
/// <summary> /// Wraps the type. /// </summary> /// <param name="context"> /// The context. /// </param> public void Wrap(WrapContext context) { // Add attributes. this.m_TraceSource.TraceEvent( TraceEventType.Verbose, 0, "Adding ProcessedAttribute to {0}", this.m_Type.FullName); Utility.AddAttribute(this.m_Type, typeof(ProcessedAttribute), this.m_Type.Module); // Add ProtoContract attribute. this.m_TraceSource.TraceEvent( TraceEventType.Verbose, 0, "Adding ProtoContractAttribute to {0}", this.m_Type.FullName); var pc = Utility.AddAttribute(this.m_Type, typeof(ProtoContractAttribute), this.m_Type.Module); pc.Properties.Add( new CustomAttributeNamedArgument( "SkipConstructor", new CustomAttributeArgument(this.m_Module.Import(typeof(bool)), true))); // Add appropriate interfaces. this.m_TraceSource.TraceEvent( TraceEventType.Verbose, 0, "Adding interface ITransparent to {0}", this.m_Type.FullName); this.m_Type.Interfaces.Add(this.m_Module.Import(typeof(ITransparent))); // Add required properties. this.m_TraceSource.TraceEvent( TraceEventType.Verbose, 0, "Implementing auto-property NetworkName on {0}", this.m_Type.FullName); Utility.AddAutoProperty(this.m_Type, "NetworkName", typeof(string), ++context.ProtoMemberCount); this.m_TraceSource.TraceEvent( TraceEventType.Verbose, 0, "Implementing auto-property Node on {0}", this.m_Type.FullName); Utility.AddAutoProperty(this.m_Type, "Node", typeof(ILocalNode)); // Define a list of exclusions for wrapping. var exclusions = new List <string> { "NetworkName", "get_NetworkName", "set_NetworkName", "Node", "get_Node", "set_Node" }; // Wrap all of our other properties, methods and fields. foreach (var p in this.m_Type.Properties.Where(value => !exclusions.Contains(value.Name)).ToList()) { (new PropertyWrapper(p) { Exclusions = exclusions }).Wrap(context); } foreach (var p in this.m_Type.Properties.Where(value => exclusions.Contains(value.Name)).ToList()) { this.m_TraceSource.TraceEvent( TraceEventType.Information, 0, "Skipping property wrapping on {0} because it is an excluded property", p.Name); } foreach (var m in this.m_Type.Methods.Where( value => !exclusions.Contains(value.Name) && !value.IsStatic && value.Name != ".ctor").ToList()) { (new MethodWrapper(m)).Wrap(context); } foreach (var m in this.m_Type.Methods.Where( value => (exclusions.Contains(value.Name) || value.IsStatic) && value.Name != ".ctor").ToList()) { this.m_TraceSource.TraceEvent( TraceEventType.Information, 0, "Skipping method wrapping on {0} because it is an excluded method", m.Name); } foreach (var m in this.m_Type.Methods.Where(value => value.Name == ".ctor").ToList()) { (new ConstructorWrapper(m)).Wrap(context); } foreach (var f in this.m_Type.Fields.ToList()) { (new FieldWrapper(f)).Wrap(context); } }
/// <summary> /// Wraps the type. /// </summary> /// <param name="context"> /// The context. /// </param> public void Wrap(WrapContext context) { // Add attributes. this.m_TraceSource.TraceEvent( TraceEventType.Verbose, 0, "Adding ProcessedAttribute to {0}", this.m_Type.FullName); Utility.AddAttribute(this.m_Type, typeof(ProcessedAttribute), this.m_Type.Module); // Add ProtoContract attribute. this.m_TraceSource.TraceEvent( TraceEventType.Verbose, 0, "Adding ProtoContractAttribute to {0}", this.m_Type.FullName); var pc = Utility.AddAttribute(this.m_Type, typeof(ProtoContractAttribute), this.m_Type.Module); pc.Properties.Add( new CustomAttributeNamedArgument( "SkipConstructor", new CustomAttributeArgument(this.m_Module.Import(typeof(bool)), true))); // Add appropriate interfaces. this.m_TraceSource.TraceEvent( TraceEventType.Verbose, 0, "Adding interface ITransparent to {0}", this.m_Type.FullName); this.m_Type.Interfaces.Add(this.m_Module.Import(typeof(ITransparent))); // Add required properties. this.m_TraceSource.TraceEvent( TraceEventType.Verbose, 0, "Implementing auto-property NetworkName on {0}", this.m_Type.FullName); Utility.AddAutoProperty(this.m_Type, "NetworkName", typeof(string), ++context.ProtoMemberCount); this.m_TraceSource.TraceEvent( TraceEventType.Verbose, 0, "Implementing auto-property Node on {0}", this.m_Type.FullName); Utility.AddAutoProperty(this.m_Type, "Node", typeof(ILocalNode)); // Define a list of exclusions for wrapping. var exclusions = new List<string> { "NetworkName", "get_NetworkName", "set_NetworkName", "Node", "get_Node", "set_Node" }; // Wrap all of our other properties, methods and fields. foreach (var p in this.m_Type.Properties.Where(value => !exclusions.Contains(value.Name)).ToList()) { (new PropertyWrapper(p) { Exclusions = exclusions }).Wrap(context); } foreach (var p in this.m_Type.Properties.Where(value => exclusions.Contains(value.Name)).ToList()) { this.m_TraceSource.TraceEvent( TraceEventType.Information, 0, "Skipping property wrapping on {0} because it is an excluded property", p.Name); } foreach (var m in this.m_Type.Methods.Where( value => !exclusions.Contains(value.Name) && !value.IsStatic && value.Name != ".ctor").ToList()) { (new MethodWrapper(m)).Wrap(context); } foreach (var m in this.m_Type.Methods.Where( value => (exclusions.Contains(value.Name) || value.IsStatic) && value.Name != ".ctor").ToList()) { this.m_TraceSource.TraceEvent( TraceEventType.Information, 0, "Skipping method wrapping on {0} because it is an excluded method", m.Name); } foreach (var m in this.m_Type.Methods.Where(value => value.Name == ".ctor").ToList()) { (new ConstructorWrapper(m)).Wrap(context); } foreach (var f in this.m_Type.Fields.ToList()) { (new FieldWrapper(f)).Wrap(context); } }
public void Wrap(WrapContext context) { var synchronisedFieldsOrProperties = new List<FieldOrPropertyDefinition>(); foreach (var property in this.m_Type.Properties) { if (Utility.HasAttribute(property.CustomAttributes, "SynchronisedAttribute")) { synchronisedFieldsOrProperties.Add(new FieldOrPropertyDefinition { Property = property, IsField = false }); } } foreach (var field in this.m_Type.Fields) { if (Utility.HasAttribute(field.CustomAttributes, "SynchronisedAttribute")) { synchronisedFieldsOrProperties.Add(new FieldOrPropertyDefinition { Field = field, IsField = true }); } } if (synchronisedFieldsOrProperties.Count == 0) return; this.m_TraceSource.TraceEvent( TraceEventType.Information, 0, "Detected synchronisation attribute on one or more fields / properties of {0}", this.m_Type.FullName); // Mark as processed. this.m_TraceSource.TraceEvent(TraceEventType.Verbose, 0, "Adding ProcessedAttribute to {0}", this.m_Type.FullName); Utility.AddAttribute(this.m_Type, typeof(ProcessedAttribute), this.m_Type.Module); // Get a reference to the synchronisation store's constructor. var synchronisationStoreCtor = new MethodReference( ".ctor", this.m_Type.Module.Import(typeof(void)), this.m_Type.Module.Import(typeof(SynchronisationStore))); synchronisationStoreCtor.HasThis = true; // Generate nested class that inherits from SynchronisationStore. var nestedClass = this.m_TypeBuilder.CreateNestedClass( this.m_Type, string.Empty, this.m_Type.Name + "_SynchronisationStore", this.m_Type.Module.Import(typeof(SynchronisationStore))); // Add distributed attribute onto the nested class. nestedClass.CustomAttributes.Add(new CustomAttribute( new MethodReference( ".ctor", this.m_Type.Module.Import(typeof(void)), this.m_Type.Module.Import(typeof(DistributedAttribute))) { HasThis = true })); // Create copies of all synchronised properties in the synchronisation store. foreach (var prop in synchronisedFieldsOrProperties) { if (prop.IsField) Utility.AddAutoProperty( nestedClass, prop.Field.Name, this.m_SynchronisationTypeTranslator.GetDistributedType(prop.Field.FieldType)); else Utility.AddAutoProperty( nestedClass, prop.Property.Name, this.m_SynchronisationTypeTranslator.GetDistributedType(prop.Property.PropertyType)); } // Create default constructor. var ctor = this.m_MethodBuilder.CreateConstructor(nestedClass); var ctorIL = ctor.Body.GetILProcessor(); ctorIL.Append(Instruction.Create(OpCodes.Ldarg_0)); ctorIL.Append(Instruction.Create(OpCodes.Call, synchronisationStoreCtor)); ctorIL.Append(Instruction.Create(OpCodes.Ret)); // Create overrides for GetNames and GetTypes. var getNames = this.m_MethodBuilder.CreateOverride( nestedClass, "GetNames", nestedClass.Module.Import(typeof(string[]))); var getTypes = this.m_MethodBuilder.CreateOverride( nestedClass, "GetTypes", nestedClass.Module.Import(typeof(Type[]))); var getIsFields = this.m_MethodBuilder.CreateOverride( nestedClass, "GetIsFields", nestedClass.Module.Import(typeof(bool[]))); // Mark the methods as local so the distributed processor doesn't // intercept them at all. getNames.CustomAttributes.Add(new CustomAttribute(new MethodReference( ".ctor", this.m_Type.Module.Import(typeof(void)), this.m_Type.Module.Import(typeof(LocalAttribute))) { HasThis = true })); getTypes.CustomAttributes.Add(new CustomAttribute(new MethodReference( ".ctor", this.m_Type.Module.Import(typeof(void)), this.m_Type.Module.Import(typeof(LocalAttribute))) { HasThis = true })); getIsFields.CustomAttributes.Add(new CustomAttribute(new MethodReference( ".ctor", this.m_Type.Module.Import(typeof(void)), this.m_Type.Module.Import(typeof(LocalAttribute))) { HasThis = true })); // Emit opcodes to produce GetNames. getNames.Body.Variables.Add(new VariableDefinition( this.m_Type.Module.Import(typeof(string[])))); var getNamesIL = getNames.Body.GetILProcessor(); getNamesIL.Append(Instruction.Create(OpCodes.Ldc_I4, synchronisedFieldsOrProperties.Count)); getNamesIL.Append(Instruction.Create(OpCodes.Newarr, this.m_Type.Module.Import(typeof(string)))); for (var i = 0; i < synchronisedFieldsOrProperties.Count; i++) { var name = synchronisedFieldsOrProperties[i].IsField ? synchronisedFieldsOrProperties[i].Field.Name : synchronisedFieldsOrProperties[i].Property.Name; getNamesIL.Append(Instruction.Create(OpCodes.Dup)); getNamesIL.Append(Instruction.Create(OpCodes.Ldc_I4, i)); getNamesIL.Append(Instruction.Create(OpCodes.Ldstr, name)); getNamesIL.Append(Instruction.Create(OpCodes.Stelem_Ref)); } getNamesIL.Append(Instruction.Create(OpCodes.Stloc_0)); getNamesIL.Append(Instruction.Create(OpCodes.Ldloc_0)); getNamesIL.Append(Instruction.Create(OpCodes.Ret)); // Get a reference to the GetTypeFromHandle method, which is used for typeof(). var getTypeFromHandle = new MethodReference( "GetTypeFromHandle", this.m_Type.Module.Import(typeof(Type)), this.m_Type.Module.Import(typeof(Type))); getTypeFromHandle.Parameters.Add(new ParameterDefinition( this.m_Type.Module.Import(typeof(RuntimeTypeHandle)))); // Emit opcodes to produce GetTypes. getTypes.Body.Variables.Add(new VariableDefinition( this.m_Type.Module.Import(typeof(Type[])))); var getTypesIL = getTypes.Body.GetILProcessor(); getTypesIL.Append(Instruction.Create(OpCodes.Ldc_I4, synchronisedFieldsOrProperties.Count)); getTypesIL.Append(Instruction.Create(OpCodes.Newarr, this.m_Type.Module.Import(typeof(Type)))); for (var i = 0; i < synchronisedFieldsOrProperties.Count; i++) { var type = synchronisedFieldsOrProperties[i].IsField ? synchronisedFieldsOrProperties[i].Field.FieldType : synchronisedFieldsOrProperties[i].Property.PropertyType; getTypesIL.Append(Instruction.Create(OpCodes.Dup)); getTypesIL.Append(Instruction.Create(OpCodes.Ldc_I4, i)); getTypesIL.Append(Instruction.Create(OpCodes.Ldtoken, this.m_Type.Module.Import(type))); getTypesIL.Append(Instruction.Create(OpCodes.Call, getTypeFromHandle)); getTypesIL.Append(Instruction.Create(OpCodes.Stelem_Ref)); } getTypesIL.Append(Instruction.Create(OpCodes.Stloc_0)); getTypesIL.Append(Instruction.Create(OpCodes.Ldloc_0)); getTypesIL.Append(Instruction.Create(OpCodes.Ret)); // Emit opcodes to produce GetNames. getIsFields.Body.Variables.Add(new VariableDefinition( this.m_Type.Module.Import(typeof(bool[])))); var getIsFieldsIL = getIsFields.Body.GetILProcessor(); getIsFieldsIL.Append(Instruction.Create(OpCodes.Ldc_I4, synchronisedFieldsOrProperties.Count)); getIsFieldsIL.Append(Instruction.Create(OpCodes.Newarr, this.m_Type.Module.Import(typeof(bool)))); for (var i = 0; i < synchronisedFieldsOrProperties.Count; i++) { getIsFieldsIL.Append(Instruction.Create(OpCodes.Dup)); getIsFieldsIL.Append(Instruction.Create(OpCodes.Ldc_I4, i)); getIsFieldsIL.Append(Instruction.Create(OpCodes.Ldc_I4, synchronisedFieldsOrProperties[i].IsField ? 1 : 0)); getIsFieldsIL.Append(Instruction.Create(OpCodes.Stelem_I1)); } getIsFieldsIL.Append(Instruction.Create(OpCodes.Stloc_0)); getIsFieldsIL.Append(Instruction.Create(OpCodes.Ldloc_0)); getIsFieldsIL.Append(Instruction.Create(OpCodes.Ret)); // Create the field on the original type to hold an instance of // the nested class. var syncField = new FieldDefinition( "<>_SynchronisationField", FieldAttributes.Private, nestedClass); syncField.CustomAttributes.Add(new CustomAttribute(new MethodReference( ".ctor", this.m_Type.Module.Import(typeof(void)), this.m_Type.Module.Import(typeof(CompilerGeneratedAttribute))) { HasThis = true })); this.m_Type.Fields.Add(syncField); // Implement the ISynchronised interface on the original class. var syncMethod = new MethodDefinition( "GetSynchronisationStore", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Final | MethodAttributes.Virtual, this.m_Type.Module.Import(typeof(SynchronisationStore))); syncMethod.Parameters.Add(new ParameterDefinition( this.m_Type.Module.Import(typeof(ILocalNode)))); syncMethod.Parameters.Add(new ParameterDefinition( this.m_Type.Module.Import(typeof(string)))); this.m_Type.Methods.Add(syncMethod); // Get a reference to Distributed<NestedClass> and it's constructor. var distributedClass = this.m_Type.Module.Import(typeof(Distributed<>)); var distributedNestedClass = new GenericInstanceType(distributedClass); distributedNestedClass.GenericArguments.Add(nestedClass); var distributedNestedCtor = new MethodReference( ".ctor", this.m_Type.Module.Import(typeof(void)), distributedNestedClass) { HasThis = true }; distributedNestedCtor.Parameters.Add(new ParameterDefinition( this.m_Type.Module.Import(typeof(ILocalNode)))); distributedNestedCtor.Parameters.Add(new ParameterDefinition( this.m_Type.Module.Import(typeof(string)))); // Get a reference to the cast to convert it to back to it's original object. var distributedNestedCast = new MethodReference( "op_Implicit", distributedClass.GenericParameters[0], distributedNestedClass); distributedNestedCast.HasThis = false; var distributedNestedClassParam2 = new GenericInstanceType(this.m_Type.Module.Import(typeof(Distributed<>))); distributedNestedClassParam2.GenericArguments.Add(distributedClass.GenericParameters[0]); distributedNestedCast.Parameters.Add(new ParameterDefinition(distributedNestedClassParam2)); // Implement the GetSynchronisationStore method. syncMethod.Body.Variables.Add(new VariableDefinition(nestedClass)); var il = syncMethod.Body.GetILProcessor(); il.Append(Instruction.Create(OpCodes.Ldarg_0)); var beforeCheck = Instruction.Create(OpCodes.Ldfld, syncField); il.Append(beforeCheck); // Brtrue to be inserted here il.Append(Instruction.Create(OpCodes.Ldarg_0)); il.Append(Instruction.Create(OpCodes.Ldarg_1)); il.Append(Instruction.Create(OpCodes.Ldarg_2)); il.Append(Instruction.Create(OpCodes.Newobj, distributedNestedCtor)); il.Append(Instruction.Create(OpCodes.Call, distributedNestedCast)); il.Append(Instruction.Create(OpCodes.Stfld, syncField)); var skip = Instruction.Create(OpCodes.Ldarg_0); il.Append(skip); il.Append(Instruction.Create(OpCodes.Ldfld, syncField)); il.Append(Instruction.Create(OpCodes.Ret)); // Insert brtrue. il.InsertAfter( beforeCheck, Instruction.Create(OpCodes.Brtrue, skip)); // Add interface. this.m_Type.Interfaces.Add(this.m_Type.Module.Import(typeof(ISynchronised))); // Finally, apply distributed processing to the nested class! this.m_TraceSource.TraceEvent(TraceEventType.Information, 0, "Starting processing of {0}", nestedClass.Name); new TypeWrapper(nestedClass).Wrap(new WrapContext(0)); this.m_TraceSource.TraceEvent(TraceEventType.Information, 0, "Finished processing of {0}", nestedClass.Name); }
/// <summary> /// Called when the MSBuild task executes. Also invoked by Program.Main /// when run from the command-line. /// </summary> /// <returns>Whether the build task succeeded.</returns> public bool Execute() { var kernel = new StandardKernel(); kernel.Load<DxProcessNinjectModule>(); var wrapperFactory = kernel.Get<IWrapperFactory>(); Directory.SetCurrentDirectory(Path.GetDirectoryName(this.AssemblyFile)); var source = new TraceSource("Processor", SourceLevels.All); source.TraceEvent(TraceEventType.Information, 0, "Processor started at {0:G}", DateTime.Now); try { // Get the assembly based on the path. AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly( Path.GetFileName(this.AssemblyFile), new ReaderParameters { ReadSymbols = File.Exists(this.AssemblyFile + ".mdb") || File.Exists(this.AssemblyFile.Substring(0, this.AssemblyFile.Length - 4) + ".pdb"), }); // Get all of the types in the assembly. TypeDefinition[] types = assembly.MainModule.Types.ToArray(); foreach (TypeDefinition type in types) { // Skip the module and Program classes. if (type.Name == "<Module>" || type.Name == "Program") { source.TraceEvent(TraceEventType.Information, 0, "Skipped {0} because it is a module", type.Name); continue; } // Check to see whether this type has a ProcessedAttribute // attached to it. if (Utility.HasAttributeSpecific(type, "ProcessedAttribute")) { source.TraceEvent(TraceEventType.Information, 0, "Skipped {0} because it has already been processed", type.Name); continue; } var context = new WrapContext(0); // Apply synchronisation wrapper. wrapperFactory.CreateSynchronisationWrapper(type).Wrap(context); // Check to see whether this type has a DistributedAttribute // attached to it. if (!Utility.HasAttribute(type, "DistributedAttribute")) { source.TraceEvent(TraceEventType.Information, 0, "Skipped {0} because it does not have DistributedAttribute", type.Name); continue; } // This type is marked as distributed, so we need to perform // wrapping on it. source.TraceEvent(TraceEventType.Information, 0, "Starting processing of {0}", type.Name); new TypeWrapper(type).Wrap(context); source.TraceEvent(TraceEventType.Information, 0, "Finished processing of {0}", type.Name); } assembly.Write(Path.GetFileName(this.AssemblyFile), new WriterParameters { WriteSymbols = true }); source.TraceEvent(TraceEventType.Information, 0, "Processor completed successfully at {0:G}", DateTime.Now); return true; } catch (PostProcessingException e) { source.TraceEvent( TraceEventType.Critical, 0, @"Post Processing Exception Occurred! {0} in {1} caused: {2} {3} {4}", e.OffendingMember, e.OffendingType, e.GetType().FullName, e.Message, e.StackTrace); source.TraceEvent(TraceEventType.Stop, 0, "Processor failed at {0:G}", DateTime.Now); if (this.BuildEngine != null) this.BuildEngine.LogErrorEvent(new BuildErrorEventArgs("Post Processing", "E0002", e.OffendingType + "." + e.OffendingMember, 0, 0, 0, 0, e.Message, "", "")); return false; } catch (Exception e) { source.TraceEvent( TraceEventType.Critical, 0, @"Exception Occurred! {0} {1} {2}", e.GetType().FullName, e.Message, e.StackTrace); source.TraceEvent(TraceEventType.Stop, 0, "Processor failed at {0:G}", DateTime.Now); if (this.BuildEngine != null) this.BuildEngine.LogErrorEvent(new BuildErrorEventArgs("General", "E0001", "", 0, 0, 0, 0, e.Message, "", "")); return false; } }
/// <summary> /// Wraps the method. /// </summary> public void Wrap(WrapContext context) { if (this.m_Method.CustomAttributes.Any(c => c.AttributeType.Name == "LocalAttribute")) { return; } this.m_TraceSource.TraceEvent(TraceEventType.Information, 0, "Modifying {0} for distributed processing", this.m_Method.Name); // Generate the direct invocation class. TypeDefinition idc = this.GenerateDirectInvokeClass(); // Get a list of existing instructions. Collection <Instruction> instructions = this.m_Method.Body.Instructions; // Get a reference to the context setting method. var assignNodeContext = new MethodReference("AssignNodeContext", this.m_Type.Module.Import(typeof(void)), this.m_Type.Module.Import(typeof(DpmConstructContext))); assignNodeContext.Parameters.Add(new ParameterDefinition(this.m_Type.Module.Import(typeof(object)))); // Create a new Action delegate using those instructions. TypeReference mdr = this.m_Method.ReturnType; MethodDefinition md = new MethodDefinition(this.m_Method.Name + "__Distributed0", MethodAttributes.Private, mdr); md.Body = new MethodBody(md); md.Body.InitLocals = true; md.Body.Instructions.Clear(); foreach (Instruction ii in instructions) { if (ii.OpCode == OpCodes.Newobj) { md.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); md.Body.Instructions.Add(Instruction.Create(OpCodes.Call, assignNodeContext)); } md.Body.Instructions.Add(ii); } foreach (VariableDefinition l in this.m_Method.Body.Variables) { md.Body.Variables.Add(l); } foreach (ExceptionHandler ex in this.m_Method.Body.ExceptionHandlers) { md.Body.ExceptionHandlers.Add(ex); } foreach (ParameterDefinition p in this.m_Method.Parameters) { md.Parameters.Add(p); } foreach (GenericParameter gp in this.m_Method.GenericParameters) { GenericParameter gpn = new GenericParameter(gp.Name, md); gpn.Attributes = gp.Attributes; foreach (TypeReference tr in gp.Constraints) { gpn.Constraints.Add(tr); } md.GenericParameters.Add(gpn); } this.m_Type.Methods.Add(md); Utility.AddAttribute(md, typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), this.m_Module); // Get the ILProcessor and create variables to store the delegate variable // and delegate constructor. ILProcessor il = this.m_Method.Body.GetILProcessor(); VariableDefinition vd; MethodReference ct; // Clear the existing instructions and local variables. this.m_Method.Body.ExceptionHandlers.Clear(); this.m_Method.Body.Instructions.Clear(); this.m_Method.Body.Variables.Clear(); // Generate the IL for the delegate definition and fill the vd and ct // variables. TypeDefinition dg = Utility.EmitDelegate(il, idc, md, this.m_Type, out vd, out ct); // Implement the Invoke method in the DirectInvoke class. this.ImplementDirectInvokeClass(idc, dg, md.Parameters, md.ReturnType); // Create the Process4.Providers.DpmEntrypoint::GetProperty method reference. MethodReference getproperty = new MethodReference("GetProperty", this.m_Type.Module.Import(typeof(object)), this.m_Type.Module.Import(typeof(DpmEntrypoint))); getproperty.Parameters.Add(new ParameterDefinition(this.m_Type.Module.Import(typeof(Delegate)))); getproperty.Parameters.Add(new ParameterDefinition(this.m_Type.Module.Import(typeof(object[])))); // Create the Process4.Providers.DpmEntrypoint::SetProperty method reference. MethodReference setproperty = new MethodReference("SetProperty", this.m_Type.Module.Import(typeof(object)), this.m_Type.Module.Import(typeof(DpmEntrypoint))); setproperty.Parameters.Add(new ParameterDefinition(this.m_Type.Module.Import(typeof(Delegate)))); setproperty.Parameters.Add(new ParameterDefinition(this.m_Type.Module.Import(typeof(object[])))); // Create the Process4.Providers.DpmEntrypoint::Invoke method reference. MethodReference invoke = new MethodReference("Invoke", this.m_Type.Module.Import(typeof(object)), this.m_Type.Module.Import(typeof(DpmEntrypoint))); invoke.Parameters.Add(new ParameterDefinition(this.m_Type.Module.Import(typeof(Delegate)))); invoke.Parameters.Add(new ParameterDefinition(this.m_Type.Module.Import(typeof(object[])))); // Generate the local variables like: // * 0 - MultitypeDelegate // * 1 - object[] // * 2 - {return type} (if not void) VariableDefinition v_0 = vd; VariableDefinition v_1 = new VariableDefinition(this.m_Type.Module.Import(typeof(object[]))); VariableDefinition v_2 = new VariableDefinition(md.ReturnType); // Add the variables to the local variable list (delegate is already added). this.m_Method.Body.Variables.Add(v_1); if (v_2.VariableType.Name.ToLower() != "void") { this.m_Method.Body.Variables.Add(v_2); } // Force local variables to be initalized. this.m_Method.Body.InitLocals = true; this.m_Method.Body.MaxStackSize = 10; // Create statement processor for method. StatementProcessor processor = new StatementProcessor(il); // Make a generic version of the delegate method. TypeDefinition btd = this.m_Type; MethodDefinition bmd = md; MethodReference bmr = btd.Module.Import(bmd); GenericInstanceType bti = null; if (this.m_Type.HasGenericParameters) { bti = (GenericInstanceType)Utility.MakeGenericType(this.m_Type, this.m_Type.GenericParameters.ToArray()); bmr = Utility.MakeGeneric(bmr, bti.GenericArguments.ToArray()); } if (this.m_Method.HasGenericParameters) { GenericInstanceMethod gim = new GenericInstanceMethod(bmr); foreach (GenericParameter gp in bmr.GenericParameters) { gim.GenericArguments.Add(gp); } bmr = gim; } foreach (var gp in this.m_Type.GenericParameters) { ((GenericInstanceType)ct.DeclaringType).GenericArguments.Add(gp); } foreach (var gp in this.m_Method.GenericParameters) { ((GenericInstanceType)ct.DeclaringType).GenericArguments.Add(gp); } // Initialize the delegate. processor.Add(new InitDelegateStatement(ct, bmr, v_0)); // Initialize the array. if (this.m_Method.IsSetter) { il.Append(Instruction.Create(OpCodes.Ldloc_0)); } processor.Add( new InitArrayStatement( this.m_Module.Import(typeof(object)), (sbyte)md.Parameters.Count, v_1, new Action <ILProcessor, int>((p, i) => { // Get a reference to the parameter being passed to the method. ParameterDefinition pd = this.m_Method.Parameters[i]; if (i > this.m_Method.Parameters.Count - 1) { return; } // Create IL to copy the value from the parameter directly // into the array, boxing the value if needed. p.Append(Instruction.Create(OpCodes.Ldloc, v_1)); p.Append(Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)i)); p.Append(Instruction.Create(OpCodes.Ldarg_S, pd)); if (pd.ParameterType.IsValueType || pd.ParameterType.IsGenericParameter) { p.Append(Instruction.Create(OpCodes.Box, pd.ParameterType)); } p.Append(Instruction.Create(OpCodes.Stelem_Ref)); }))); // Call the delegate. if (this.m_Method.IsSetter) { processor.Add(new CallStatement(setproperty, new VariableDefinition[] { v_1 }, this.m_Method.ReturnType, v_2)); } else if (this.m_Method.IsGetter) { processor.Add(new CallStatement(getproperty, new VariableDefinition[] { v_0, v_1 }, this.m_Method.ReturnType, v_2)); } else { processor.Add(new CallStatement(invoke, new VariableDefinition[] { v_0, v_1 }, this.m_Method.ReturnType, v_2)); } }
/// <summary> /// Called when the MSBuild task executes. Also invoked by Program.Main /// when run from the command-line. /// </summary> /// <returns>Whether the build task succeeded.</returns> public bool Execute() { var kernel = new StandardKernel(); kernel.Load <DxProcessNinjectModule>(); var wrapperFactory = kernel.Get <IWrapperFactory>(); Directory.SetCurrentDirectory(Path.GetDirectoryName(this.AssemblyFile)); var source = new TraceSource("Processor", SourceLevels.All); source.TraceEvent(TraceEventType.Information, 0, "Processor started at {0:G}", DateTime.Now); try { // Get the assembly based on the path. AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly( Path.GetFileName(this.AssemblyFile), new ReaderParameters { ReadSymbols = File.Exists(this.AssemblyFile + ".mdb") || File.Exists(this.AssemblyFile.Substring(0, this.AssemblyFile.Length - 4) + ".pdb"), }); // Get all of the types in the assembly. TypeDefinition[] types = assembly.MainModule.Types.ToArray(); foreach (TypeDefinition type in types) { // Skip the module and Program classes. if (type.Name == "<Module>" || type.Name == "Program") { source.TraceEvent(TraceEventType.Information, 0, "Skipped {0} because it is a module", type.Name); continue; } // Check to see whether this type has a ProcessedAttribute // attached to it. if (Utility.HasAttributeSpecific(type, "ProcessedAttribute")) { source.TraceEvent(TraceEventType.Information, 0, "Skipped {0} because it has already been processed", type.Name); continue; } var context = new WrapContext(0); // Apply synchronisation wrapper. wrapperFactory.CreateSynchronisationWrapper(type).Wrap(context); // Check to see whether this type has a DistributedAttribute // attached to it. if (!Utility.HasAttribute(type, "DistributedAttribute")) { source.TraceEvent(TraceEventType.Information, 0, "Skipped {0} because it does not have DistributedAttribute", type.Name); continue; } // This type is marked as distributed, so we need to perform // wrapping on it. source.TraceEvent(TraceEventType.Information, 0, "Starting processing of {0}", type.Name); new TypeWrapper(type).Wrap(context); source.TraceEvent(TraceEventType.Information, 0, "Finished processing of {0}", type.Name); } assembly.Write(Path.GetFileName(this.AssemblyFile), new WriterParameters { WriteSymbols = true }); source.TraceEvent(TraceEventType.Information, 0, "Processor completed successfully at {0:G}", DateTime.Now); return(true); } catch (PostProcessingException e) { source.TraceEvent( TraceEventType.Critical, 0, @"Post Processing Exception Occurred! {0} in {1} caused: {2} {3} {4}", e.OffendingMember, e.OffendingType, e.GetType().FullName, e.Message, e.StackTrace); source.TraceEvent(TraceEventType.Stop, 0, "Processor failed at {0:G}", DateTime.Now); if (this.BuildEngine != null) { this.BuildEngine.LogErrorEvent(new BuildErrorEventArgs("Post Processing", "E0002", e.OffendingType + "." + e.OffendingMember, 0, 0, 0, 0, e.Message, "", "")); } return(false); } catch (Exception e) { source.TraceEvent( TraceEventType.Critical, 0, @"Exception Occurred! {0} {1} {2}", e.GetType().FullName, e.Message, e.StackTrace); source.TraceEvent(TraceEventType.Stop, 0, "Processor failed at {0:G}", DateTime.Now); if (this.BuildEngine != null) { this.BuildEngine.LogErrorEvent(new BuildErrorEventArgs("General", "E0001", "", 0, 0, 0, 0, e.Message, "", "")); } return(false); } }