private void RewriteType(TypeDefinition type, ObserverReferences observer) { foreach (MethodDefinition method in type.Methods) { this.RewriteMethod(method, observer); } }
/// <summary> /// Makes the <see cref="Observer"/> available to the given method as a variable and then /// applies all of the individual rewriters to the method. /// </summary> private void RewriteMethod(MethodDefinition methodDefinition, ObserverReferences observer) { if (methodDefinition.DeclaringType == observer.InstanceField.DeclaringType) { return; // don't inject on our injected type. } if (!methodDefinition.HasBody || methodDefinition.Body.Instructions.Count == 0) { return; // don't inject on method without a Body } // Inject observer instance to method. ILProcessor il = methodDefinition.Body.GetILProcessor(); var observerVariable = new VariableDefinition(observer.InstanceField.FieldType); il.Body.Variables.Add(observerVariable); Instruction start = methodDefinition.Body.Instructions[0]; il.InsertBefore(start, il.Create(OpCodes.Ldsfld, observer.InstanceField)); il.InsertBefore(start, il.CreateStlocBest(observerVariable)); var context = new ObserverRewriterContext(observer, observerVariable); foreach (IObserverMethodRewriter rewriter in methodRewriters) { rewriter.Rewrite(methodDefinition, il, context); } }
/// <summary> /// Adds a call to SpendGas from the RuntimeObserver before the given instruction. /// </summary> private static void AddSpendGasMethodBeforeInstruction(ILProcessor il, ObserverReferences observer, VariableDefinition variable, CodeSegment codeSegment) { Instruction first = codeSegment.Instructions.First(); Instruction newFirst = il.CreateLdlocBest(variable); long segmentCost = (long)codeSegment.CalculateGasCost().Value; il.Body.SimplifyMacros(); il.InsertBefore(first, newFirst); // load observer il.InsertBefore(first, il.Create(OpCodes.Ldc_I8, (long)segmentCost)); // load gas amount il.InsertBefore(first, il.Create(OpCodes.Call, observer.SpendGasMethod)); // trigger method il.Body.OptimizeMacros(); }
/// <summary> /// Completely rewrites a module with all of the code required to meter memory and gas. /// </summary> public ModuleDefinition Rewrite(ModuleDefinition module) { (FieldDefinition observerInstanceField, TypeDefinition observerType) = this.GetRuntimeInstance(module); var observer = new ObserverReferences(observerInstanceField, module); foreach (TypeDefinition type in module.GetTypes()) { this.RewriteType(type, observer); } module.Types.Add(observerType); return(module); }
public ModuleDefinition Rewrite(ModuleDefinition module) { Guid id = Guid.NewGuid(); FieldDefinition observerInstanceField = GetObserverInstance(module, id); var observer = new ObserverReferences(observerInstanceField, module); foreach (TypeDefinition type in module.Types) { RewriteType(type, observer); } ObserverInstances.Set(id, this.observerToInject); return(module); }
public ObserverRewriterContext(ObserverReferences observer, VariableDefinition observerVariable) { this.Observer = observer; this.ObserverVariable = observerVariable; }