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;
			}
		}
예제 #2
0
 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;
        }