public IEnumerable<ConstructorCallWeave> FindConstructorCallWeaves(IAssembly assembly, FactoryMap factories) { List<ConstructorCallWeave> spots = new List<ConstructorCallWeave>(); foreach (TypeDefinition type in GetTypes(assembly, factories)) { foreach (MethodDefinition method in type.Methods) { if (method.Body == null) { continue; } foreach (Instruction instruction in method.Body.Instructions) { if (instruction.OpCode == OpCodes.Newobj) { MethodDefinition constructor = instruction.Operand as MethodDefinition; if (constructor != null && constructor.Parameters.Count == 0) { if (factories.HasForObjectType(constructor.DeclaringType)) { spots.Add(new ConstructorCallWeave(assembly, method, instruction, constructor)); } } } } } } return spots; }
public void StoreFactoryMap(IAssembly assembly, FactoryMap factoryMap) { MethodInfo getTypeFromHandleReflect = typeof (Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) }); MethodReference getTypeFromHandle = assembly.Import(getTypeFromHandleReflect); TypeReference systemType = assembly.Import(typeof(Type)); TypeReference arrayOfTypes = assembly.Import(typeof(Type[])); TypeReference arrayOfArrayOfTypes = assembly.Import(typeof(Type[][])); // Now we create the actual type and stuff... TypeDefinition mapType = GetFactoryMapType(assembly); MethodDefinition getFactoriesMethod = new MethodDefinition(FactoryMapMethodName, MethodAttributes.Public, arrayOfArrayOfTypes); getFactoriesMethod.IsVirtual = true; mapType.Methods.Add(getFactoriesMethod); getFactoriesMethod.Body.Variables.Add(new VariableDefinition("map", 0, getFactoriesMethod, arrayOfArrayOfTypes)); getFactoriesMethod.Body.Variables.Add(new VariableDefinition("row", 1, getFactoriesMethod, arrayOfTypes)); getFactoriesMethod.Body.InitLocals = true; CilWorker worker = getFactoriesMethod.Body.CilWorker; List<Factory> factories = new List<Factory>(factoryMap.Factories); worker.Append(worker.Create(OpCodes.Nop)); worker.Append(worker.Create(OpCodes.Ldc_I4, factories.Count)); worker.Append(worker.Create(OpCodes.Newarr, arrayOfTypes)); worker.Append(worker.Create(OpCodes.Stloc_0)); worker.Append(worker.Create(OpCodes.Ldloc_0)); int index = 0; foreach (Factory factory in factories) { worker.Append(worker.Create(OpCodes.Ldc_I4, index)); worker.Append(worker.Create(OpCodes.Ldc_I4, 2)); worker.Append(worker.Create(OpCodes.Newarr, systemType)); worker.Append(worker.Create(OpCodes.Stloc_1)); worker.Append(worker.Create(OpCodes.Ldloc_1)); worker.Append(worker.Create(OpCodes.Ldc_I4_0)); worker.Append(worker.Create(OpCodes.Ldtoken, factory.ObjectType)); worker.Append(worker.Create(OpCodes.Call, getTypeFromHandle)); worker.Append(worker.Create(OpCodes.Stelem_Ref)); worker.Append(worker.Create(OpCodes.Ldloc_1)); worker.Append(worker.Create(OpCodes.Ldc_I4_1)); worker.Append(worker.Create(OpCodes.Ldtoken, factory.FactoryType)); worker.Append(worker.Create(OpCodes.Call, getTypeFromHandle)); worker.Append(worker.Create(OpCodes.Stelem_Ref)); worker.Append(worker.Create(OpCodes.Ldloc_1)); worker.Append(worker.Create(OpCodes.Stelem_Ref)); index++; worker.Append(worker.Create(OpCodes.Ldloc_0)); } worker.Append(worker.Create(OpCodes.Ret)); assembly.Inject(mapType); }
private static IEnumerable<TypeDefinition> GetTypes(IAssembly assembly, FactoryMap factories) { foreach (TypeDefinition type in assembly.Types) { if (!factories.HasForFactoryType(type)) { yield return type; } } }
public FactoryMap FindFactories(IAssembly assembly) { FactoryMap map = new FactoryMap(); foreach (TypeDefinition type in assembly.Types) { TypeReference objectIsFactoryFor = IsFactory(type); if (objectIsFactoryFor != null) { _log.Log("Found {0} as factory for {1}", type.FullName, objectIsFactoryFor.FullName); map.AddFactory(objectIsFactoryFor, type); } } return map; }
public void WeaveConstructorCalls(IEnumerable<ConstructorCallWeave> weaves, FactoryMap factories) { MethodInfo getFactoryMethod = typeof(Factories).GetMethod("Create"); foreach (ConstructorCallWeave weave in weaves) { Factory factory = factories.GetForObjectType(weave.Constructor.DeclaringType); _log.Log("Weaving {0} in {1}", factory.ObjectType, weave.ParentMethod); MethodReference getObjectMethodReference = weave.ParentAssembly.Import(getFactoryMethod); GenericInstanceMethod methodCall = new GenericInstanceMethod(getObjectMethodReference); methodCall.GenericArguments.Add(factory.ObjectType); CilWorker worker = weave.ParentMethod.Body.CilWorker; Instruction callGetFactory = worker.Create(OpCodes.Call, methodCall); worker.Replace(weave.NewInstruction, callGetFactory); } }