public MethodDefinition InsertMethod (MethodDefinition method, bool clone) { if (methods.ContainsKey (method.Name)) { Console.Error.WriteLine ("Error: duplicated method {0}", method.Name); return null; } else { if (clone) { method = method.Clone (); } methods [method.Name] = method; if (method.Name == ".start") { //TODO More sanity checks here... Console.WriteLine ("*** Method '.start' found!"); entryPoint = method; } else { Console.WriteLine ("*** Method {0} is not named '.start'", method.Name); } return method; } }
static MethodDefinition ImportMethodDefinition(MethodDefinition meth, ImportContext context) { return(MethodDefinition.Clone(meth, context)); }
internal static TypeDefinition Clone(TypeDefinition type, ImportContext context) { TypeDefinition nt = new TypeDefinition( type.Name, type.Namespace, type.Attributes); context.GenericContext.Type = nt; foreach (GenericParameter p in type.GenericParameters) { nt.GenericParameters.Add(GenericParameter.Clone(p, context)); } if (type.BaseType != null) { nt.BaseType = context.Import(type.BaseType); } if (type.HasLayoutInfo) { nt.ClassSize = type.ClassSize; nt.PackingSize = type.PackingSize; } foreach (FieldDefinition field in type.Fields) { nt.Fields.Add(FieldDefinition.Clone(field, context)); } foreach (MethodDefinition ctor in type.Constructors) { nt.Constructors.Add(MethodDefinition.Clone(ctor, context)); } foreach (MethodDefinition meth in type.Methods) { nt.Methods.Add(MethodDefinition.Clone(meth, context)); } foreach (EventDefinition evt in type.Events) { nt.Events.Add(EventDefinition.Clone(evt, context)); } foreach (PropertyDefinition prop in type.Properties) { nt.Properties.Add(PropertyDefinition.Clone(prop, context)); } foreach (TypeReference intf in type.Interfaces) { nt.Interfaces.Add(context.Import(intf)); } foreach (TypeDefinition nested in type.NestedTypes) { nt.NestedTypes.Add(Clone(nested, context)); } foreach (CustomAttribute ca in type.CustomAttributes) { nt.CustomAttributes.Add(CustomAttribute.Clone(ca, context)); } foreach (SecurityDeclaration dec in type.SecurityDeclarations) { nt.SecurityDeclarations.Add(SecurityDeclaration.Clone(dec)); } return(nt); }
private void Rewrite(TypeDefinition typeDefinition, MethodDefinition methodDefinition, List<MethodDefinition> addedMethods) { if (!methodDefinition.HasBody) return; ImportReferences(); // Create an interceptor stub for the method. string stubFieldName = StaticInterceptorStub.GetStubFieldName(methodDefinition.Name); FieldDefinition stubFieldDefinition = new FieldDefinition(stubFieldName, staticInterceptorStubReference, FieldAttributes.Private | FieldAttributes.Static | FieldAttributes.NotSerialized); typeDefinition.Fields.Add(stubFieldDefinition); // Clone the original method and give it a new name. MethodDefinition targetMethodDefinition = methodDefinition.Clone(); targetMethodDefinition.Overrides.Clear(); targetMethodDefinition.Attributes = (methodDefinition.Attributes & MethodAttributes.Static) | MethodAttributes.Private | MethodAttributes.HideBySig; targetMethodDefinition.CallingConvention = MethodCallingConvention.Default; targetMethodDefinition.Name = StaticInterceptorStub.GetTargetMethodName(methodDefinition.Name); addedMethods.Add(targetMethodDefinition); // Replace the original method with a stub that calls the callback. MethodBody body = new MethodBody(methodDefinition); body.InitLocals = true; methodDefinition.Body = body; CilWorker worker = body.CilWorker; /*** Obtain the invocation, if needed ***/ // Load the stub if it has been initialized. VariableDefinition stubVariableDefinition = new VariableDefinition(staticInterceptorStubReference); body.Variables.Add(stubVariableDefinition); worker.Emit(OpCodes.Ldsfld, stubFieldDefinition); worker.Emit(OpCodes.Dup); worker.Emit(OpCodes.Stloc, stubVariableDefinition); Instruction fastPathEntryBranch = worker.Emit(OpCodes.Brfalse, body.Instructions.Outside); /*** Slow path ***/ // Copy arguments to an array. VariableDefinition argumentsVariableDefinition = null; if (methodDefinition.Parameters.Count != 0) { argumentsVariableDefinition = new VariableDefinition(objectArrayReference); body.Variables.Add(argumentsVariableDefinition); worker.Emit(OpCodes.Ldc_I4, methodDefinition.Parameters.Count); worker.Emit(OpCodes.Newarr, objectReference); worker.Emit(OpCodes.Stloc, argumentsVariableDefinition); foreach (ParameterDefinition param in methodDefinition.Parameters) { if ((param.Attributes & ParameterAttributes.In) != 0) { worker.Emit(OpCodes.Ldloc, argumentsVariableDefinition); worker.Emit(OpCodes.Ldc_I4, param.Sequence); worker.Emit(OpCodes.Ldarg, param); worker.Emit(OpCodes.Box, objectReference); worker.Emit(OpCodes.Stelem_Ref); } } } // Create the invocation. worker.Emit(OpCodes.Ldloc, stubVariableDefinition); if (methodDefinition.HasThis) worker.Emit(OpCodes.Ldarg_0); else worker.Emit(OpCodes.Ldnull); if (argumentsVariableDefinition == null) worker.Emit(OpCodes.Ldsfld, noArgumentsReference); else worker.Emit(OpCodes.Ldloc, argumentsVariableDefinition); worker.Emit(OpCodes.Newobj, staticInvocationConstructorReference); // Execute it (leaves the result on the stack). worker.Emit(OpCodes.Call, executeReference); // Copy any ref and out arguments back out of the invocation's array. if (argumentsVariableDefinition != null) { foreach (ParameterDefinition param in methodDefinition.Parameters) { if ((param.Attributes & ParameterAttributes.Out) != 0) { worker.Emit(OpCodes.Ldloc, argumentsVariableDefinition); worker.Emit(OpCodes.Ldc_I4, param.Sequence); worker.Emit(OpCodes.Ldelem_Ref); worker.Emit(OpCodes.Unbox_Any, param.ParameterType); worker.Emit(OpCodes.Starg, param); } } } // Unbox the result if needed and return. if (CecilUtils.IsVoid(methodDefinition.ReturnType.ReturnType)) worker.Emit(OpCodes.Pop); else worker.Emit(OpCodes.Unbox_Any, methodDefinition.ReturnType.ReturnType); Instruction slowPathReturnBranch = worker.Emit(OpCodes.Br, body.Instructions.Outside); /*** Fast path ***/ // Load up all arguments. Instruction fastPathEntryInstr = null; if (methodDefinition.HasThis) fastPathEntryInstr = worker.Emit(OpCodes.Ldarg, methodDefinition.This); foreach (ParameterDefinition param in methodDefinition.Parameters) { Instruction instr = worker.Emit(OpCodes.Ldarg, param); if (fastPathEntryInstr == null) fastPathEntryInstr = instr; } // Emit a tail call back to the original method for the fast-path without an invocation. worker.Emit(OpCodes.Tail); worker.Emit(OpCodes.Call, targetMethodDefinition); /*** Common return ***/ Instruction returnInstr = worker.Emit(OpCodes.Ret); // Patch branches. fastPathEntryBranch.Operand = fastPathEntryInstr; slowPathReturnBranch.Operand = returnInstr; }