Exemplo n.º 1
0
 public static void WriteTo(this Instruction instruction, ITextOutput writer, Func <OpCode, string> getOpCodeDocumentation)
 {
     writer.WriteDefinition(DnlibExtensions.OffsetToString(instruction.GetOffset()), instruction, TextTokenType.Label, false);
     writer.Write(':', TextTokenType.Operator);
     writer.WriteSpace();
     writer.WriteReference(instruction.OpCode.Name, instruction.OpCode, TextTokenType.OpCode);
     if (instruction.Operand != null)
     {
         writer.WriteSpace();
         if (instruction.OpCode == OpCodes.Ldtoken)
         {
             var member = instruction.Operand as IMemberRef;
             if (member != null && member.IsMethod)
             {
                 writer.Write("method", TextTokenType.Keyword);
                 writer.WriteSpace();
             }
             else if (member != null && member.IsField)
             {
                 writer.Write("field", TextTokenType.Keyword);
                 writer.WriteSpace();
             }
         }
         WriteOperand(writer, instruction.Operand);
     }
     if (getOpCodeDocumentation != null)
     {
         var doc = getOpCodeDocumentation(instruction.OpCode);
         if (doc != null)
         {
             writer.Write("\t", TextTokenType.Text);
             writer.Write("// " + doc, TextTokenType.Comment);
         }
     }
 }
Exemplo n.º 2
0
        void ConvertParameters(List <ByteCode> body)
        {
            ILVariable thisParameter = null;

            if (methodDef.HasThis)
            {
                TypeDef type = methodDef.DeclaringType;
                thisParameter      = new ILVariable();
                thisParameter.Type = DnlibExtensions.IsValueType(type) ? new ByRefSig(type.ToTypeSig()) : type.ToTypeSig();
                thisParameter.Name = "this";
                thisParameter.OriginalParameter = methodDef.Parameters[0];
            }
            foreach (Parameter p in methodDef.Parameters.SkipNonNormal())
            {
                this.Parameters.Add(new ILVariable {
                    Type = p.Type, Name = p.Name, OriginalParameter = p
                });
            }
            if (this.Parameters.Count > 0 && (methodDef.IsSetter || methodDef.IsAddOn || methodDef.IsRemoveOn))
            {
                // last parameter must be 'value', so rename it
                this.Parameters.Last().Name = "value";
            }
            foreach (ByteCode byteCode in body)
            {
                Parameter p;
                switch (byteCode.Code)
                {
                case ILCode.Ldarg:
                    p                = byteCode.Operand as Parameter;
                    byteCode.Code    = ILCode.Ldloc;
                    byteCode.Operand = p == null ? null : p.IsHiddenThisParameter ? thisParameter : this.Parameters[p.MethodSigIndex];
                    break;

                case ILCode.Starg:
                    p                = byteCode.Operand as Parameter;
                    byteCode.Code    = ILCode.Stloc;
                    byteCode.Operand = p == null ? null : p.IsHiddenThisParameter ? thisParameter : this.Parameters[p.MethodSigIndex];
                    break;

                case ILCode.Ldarga:
                    p                = byteCode.Operand as Parameter;
                    byteCode.Code    = ILCode.Ldloca;
                    byteCode.Operand = p == null ? null : p.IsHiddenThisParameter ? thisParameter : this.Parameters[p.MethodSigIndex];
                    break;
                }
            }
            if (thisParameter != null)
            {
                this.Parameters.Add(thisParameter);
            }
        }
 public static void WriteTo(this Instruction instruction, MethodDef method, ITextOutput writer)
 {
     writer.WriteDefinition(DnlibExtensions.OffsetToString(instruction.Offset), instruction);
     writer.Write(": ");
     writer.WriteReference(instruction.OpCode.Name, instruction.OpCode);
     if (instruction.Operand != null)
     {
         writer.Write(' ');
         if (instruction.OpCode == OpCodes.Ldtoken)
         {
             MemberRef member = instruction.Operand as MemberRef;
             if ((member != null && member.IsMethodRef) || instruction.Operand is MethodDef || instruction.Operand is MethodSpec)
             {
                 writer.Write("method ");
             }
             else if ((member != null && member.IsFieldRef) || instruction.Operand is FieldDef)
             {
                 writer.Write("field ");
             }
         }
         WriteOperand(writer, instruction.Operand.ResolveGenericParams(method));
     }
 }
Exemplo n.º 4
0
        /// <summary>
        /// Handles both object and collection initializers.
        /// </summary>
        bool TransformObjectInitializers(ILBlockBase block, List <ILNode> body, ILExpression expr, int pos)
        {
            if (!context.Settings.ObjectOrCollectionInitializers)
            {
                return(false);
            }

            Debug.Assert(body[pos] == expr);             // should be called for top-level expressions only
            ILVariable          v;
            ILExpression        newObjExpr;
            ITypeDefOrRef       newObjType;
            bool                isValueType;
            IMethod             ctor;
            List <ILExpression> ctorArgs;

            if (expr.Match(ILCode.Stloc, out v, out newObjExpr))
            {
                if (newObjExpr.Match(ILCode.Newobj, out ctor, out ctorArgs))
                {
                    // v = newObj(ctor, ctorArgs)
                    newObjType  = ctor.DeclaringType;
                    isValueType = false;
                }
                else if (newObjExpr.Match(ILCode.DefaultValue, out newObjType))
                {
                    // v = defaultvalue(type)
                    isValueType = true;
                }
                else
                {
                    return(false);
                }
            }
            else if (expr.Match(ILCode.Call, out ctor, out ctorArgs))
            {
                // call(SomeStruct::.ctor, ldloca(v), remainingArgs)
                if (ctorArgs.Count > 0 && ctorArgs[0].Match(ILCode.Ldloca, out v))
                {
                    isValueType = true;
                    newObjType  = ctor.DeclaringType;
                    ctorArgs    = new List <ILExpression>(ctorArgs);
                    var old = ctorArgs[0];
                    ctorArgs.RemoveAt(0);
                    newObjExpr = new ILExpression(ILCode.Newobj, ctor, ctorArgs);
                    old.AddSelfAndChildrenRecursiveILRanges(newObjExpr.ILRanges);
                }
                else
                {
                    return(false);
                }
            }
            else
            {
                return(false);
            }
            if (DnlibExtensions.IsValueType(newObjType) != isValueType)
            {
                return(false);
            }

            int originalPos = pos;

            // don't use object initializer syntax for closures
            if (Ast.Transforms.DelegateConstruction.IsPotentialClosure(context, newObjType.ResolveWithinSameModule()))
            {
                return(false);
            }

            ILExpression initializer = ParseObjectInitializer(body, ref pos, v, newObjExpr, IsCollectionType(newObjType.ToTypeSig()), isValueType);

            if (initializer.Arguments.Count == 1)             // only newobj argument, no initializer elements
            {
                return(false);
            }
            int totalElementCount = pos - originalPos - 1;             // totalElementCount: includes elements from nested collections

            Debug.Assert(totalElementCount >= initializer.Arguments.Count - 1);

            // Verify that we can inline 'v' into the next instruction:

            if (pos >= body.Count)
            {
                return(false);                // reached end of block, but there should be another instruction which consumes the initialized object
            }
            var inlining = GetILInlining(method);

            if (isValueType)
            {
                // one ldloc for the use of the initialized object
                if (inlining.numLdloc.GetOrDefault(v) != 1)
                {
                    return(false);
                }
                // one ldloca for each initializer argument, and also for the ctor call (if it exists)
                if (inlining.numLdloca.GetOrDefault(v) != totalElementCount + (expr.Code == ILCode.Call ? 1 : 0))
                {
                    return(false);
                }
                // one stloc for the initial store (if no ctor call was used)
                if (inlining.numStloc.GetOrDefault(v) != (expr.Code == ILCode.Call ? 0 : 1))
                {
                    return(false);
                }
            }
            else
            {
                // one ldloc for each initializer argument, and another ldloc for the use of the initialized object
                if (inlining.numLdloc.GetOrDefault(v) != totalElementCount + 1)
                {
                    return(false);
                }
                if (!(inlining.numStloc.GetOrDefault(v) == 1 && inlining.numLdloca.GetOrDefault(v) == 0))
                {
                    return(false);
                }
            }
            ILExpression nextExpr = body[pos] as ILExpression;

            if (!inlining.CanInlineInto(nextExpr, v, initializer))
            {
                return(false);
            }

            if (expr.Code == ILCode.Stloc)
            {
                expr.Arguments[0].AddSelfAndChildrenRecursiveILRanges(initializer.ILRanges);
                expr.Arguments[0] = initializer;
            }
            else
            {
                Debug.Assert(expr.Code == ILCode.Call);
                expr.Code    = ILCode.Stloc;
                expr.Operand = v;
                foreach (var arg in expr.Arguments)
                {
                    arg.AddSelfAndChildrenRecursiveILRanges(initializer.ILRanges);
                }
                expr.Arguments.Clear();
                expr.Arguments.Add(initializer);
            }
            // remove all the instructions that were pulled into the initializer
            for (int i = originalPos + 1; i < pos; i++)
            {
                body[i].AddSelfAndChildrenRecursiveILRanges(initializer.ILRanges);
            }
            body.RemoveRange(originalPos + 1, pos - originalPos - 1);

            // now that we know that it's an object initializer, change all the first arguments to 'InitializedObject'
            ChangeFirstArgumentToInitializedObject(initializer);

            inlining = GetILInlining(method);
            inlining.InlineIfPossible(block, body, ref originalPos);

            return(true);
        }
        void HandleInstanceFieldInitializers(IEnumerable <AstNode> members)
        {
            var instanceCtors = members.OfType <ConstructorDeclaration>().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray();
            var instanceCtorsNotChainingWithThis = instanceCtors.Where(ctor => !thisCallPattern.IsMatch(ctor.Body.Statements.FirstOrDefault())).ToArray();

            if (instanceCtorsNotChainingWithThis.Length > 0)
            {
                MethodDef ctorMethodDef = instanceCtorsNotChainingWithThis[0].Annotation <MethodDef>();
                if (ctorMethodDef != null && DnlibExtensions.IsValueType(ctorMethodDef.DeclaringType))
                {
                    return;
                }

                // Recognize field initializers:
                // Convert first statement in all ctors (if all ctors have the same statement) into a field initializer.
                bool allSame;
                do
                {
                    Match m = fieldInitializerPattern.Match(instanceCtorsNotChainingWithThis[0].Body.FirstOrDefault());
                    if (!m.Success)
                    {
                        break;
                    }

                    FieldDef fieldDef = m.Get <AstNode>("fieldAccess").Single().Annotation <IField>().ResolveFieldWithinSameModule();
                    if (fieldDef == null)
                    {
                        break;
                    }
                    AstNode fieldOrEventDecl = members.FirstOrDefault(f => f.Annotation <FieldDef>() == fieldDef);
                    if (fieldOrEventDecl == null)
                    {
                        break;
                    }
                    Expression initializer = m.Get <Expression>("initializer").Single();
                    // 'this'/'base' cannot be used in field initializers
                    if (initializer.DescendantsAndSelf.Any(n => n is ThisReferenceExpression || n is BaseReferenceExpression))
                    {
                        break;
                    }

                    allSame = true;
                    for (int i = 1; i < instanceCtorsNotChainingWithThis.Length; i++)
                    {
                        if (!instanceCtors[0].Body.First().IsMatch(instanceCtorsNotChainingWithThis[i].Body.FirstOrDefault()))
                        {
                            allSame = false;
                            break;
                        }
                    }
                    if (allSame)
                    {
                        var ctorIlRanges = new List <Tuple <MemberMapping, List <ILRange> > >(instanceCtorsNotChainingWithThis.Length);
                        for (int i = 0; i < instanceCtorsNotChainingWithThis.Length; i++)
                        {
                            var ctor = instanceCtorsNotChainingWithThis[i];
                            var stmt = ctor.Body.First();
                            stmt.Remove();
                            var mm = ctor.Annotation <MemberMapping>() ?? ctor.Body.Annotation <MemberMapping>();
                            Debug.Assert(mm != null);
                            if (mm != null)
                            {
                                ctorIlRanges.Add(Tuple.Create(mm, stmt.GetAllRecursiveILRanges()));
                            }
                        }
                        var varInit = fieldOrEventDecl.GetChildrenByRole(Roles.Variable).Single();
                        initializer.Remove();
                        initializer.RemoveAllILRangesRecursive();
                        varInit.Initializer = initializer;
                        fieldOrEventDecl.AddAnnotation(ctorIlRanges);
                    }
                } while (allSame);
            }
        }
 public static void WriteOffsetReference(ITextOutput writer, Instruction instruction)
 {
     writer.WriteReference(DnlibExtensions.OffsetToString(instruction.Offset), instruction);
 }
Exemplo n.º 7
0
        public static void WriteTo(this Instruction instruction, ITextOutput writer, DisassemblerOptions options, uint baseRva, long baseOffs, IInstructionBytesReader byteReader, MethodDef method)
        {
            if (options != null && (options.ShowTokenAndRvaComments || options.ShowILBytes))
            {
                writer.Write("/* ", TextTokenType.Comment);

                bool needSpace = false;

                if (options.ShowTokenAndRvaComments)
                {
                    ulong fileOffset = (ulong)baseOffs + instruction.Offset;
                    writer.WriteReference(string.Format("0x{0:X8}", fileOffset), new AddressReference(options.OwnerModule == null ? null : options.OwnerModule.Location, false, fileOffset, (ulong)instruction.GetSize()), TextTokenType.Comment, false);
                    needSpace = true;
                }

                if (options.ShowILBytes)
                {
                    if (needSpace)
                    {
                        writer.Write(' ', TextTokenType.Comment);
                    }
                    if (byteReader == null)
                    {
                        writer.Write("??", TextTokenType.Comment);
                    }
                    else
                    {
                        int size = instruction.GetSize();
                        for (int i = 0; i < size; i++)
                        {
                            var b = byteReader.ReadByte();
                            if (b < 0)
                            {
                                writer.Write("??", TextTokenType.Comment);
                            }
                            else
                            {
                                writer.Write(string.Format("{0:X2}", b), TextTokenType.Comment);
                            }
                        }
                        // Most instructions should be at most 5 bytes in length, but use 6 since
                        // ldftn/ldvirtftn are 6 bytes long. The longest instructions are those with
                        // 8 byte operands, ldc.i8 and ldc.r8: 9 bytes.
                        const int MIN_BYTES = 6;
                        for (int i = size; i < MIN_BYTES; i++)
                        {
                            writer.Write("  ", TextTokenType.Comment);
                        }
                    }
                }

                writer.Write(" */", TextTokenType.Comment);
                writer.WriteSpace();
            }
            writer.WriteDefinition(DnlibExtensions.OffsetToString(instruction.GetOffset()), new InstructionReference(method, instruction), TextTokenType.Label, false);
            writer.Write(':', TextTokenType.Operator);
            writer.WriteSpace();
            writer.WriteReference(instruction.OpCode.Name, instruction.OpCode, TextTokenType.OpCode);
            if (instruction.Operand != null)
            {
                int count = OPERAND_ALIGNMENT - instruction.OpCode.Name.Length;
                if (count <= 0)
                {
                    count = 1;
                }
                writer.Write(spaces[count], TextTokenType.Text);
                if (instruction.OpCode == OpCodes.Ldtoken)
                {
                    var member = instruction.Operand as IMemberRef;
                    if (member != null && member.IsMethod)
                    {
                        writer.Write("method", TextTokenType.Keyword);
                        writer.WriteSpace();
                    }
                    else if (member != null && member.IsField)
                    {
                        writer.Write("field", TextTokenType.Keyword);
                        writer.WriteSpace();
                    }
                }
                WriteOperand(writer, instruction.Operand, method);
            }
            if (options != null && options.GetOpCodeDocumentation != null)
            {
                var doc = options.GetOpCodeDocumentation(instruction.OpCode);
                if (doc != null)
                {
                    writer.Write("\t", TextTokenType.Text);
                    writer.Write("// " + doc, TextTokenType.Comment);
                }
            }
        }
Exemplo n.º 8
0
        public static void WriteOffsetReference(ITextOutput writer, Instruction instruction, MethodDef method, TextTokenType tokenType = TextTokenType.Label)
        {
            var r = instruction == null ? null : method == null ? (object)instruction : new InstructionReference(method, instruction);

            writer.WriteReference(DnlibExtensions.OffsetToString(instruction.GetOffset()), r, tokenType);
        }
Exemplo n.º 9
0
        public static void WriteTo(this ITypeDefOrRef type, ITextOutput writer, ILNameSyntax syntax, int depth)
        {
            if (depth++ > MAX_CONVERTTYPE_DEPTH || type == null)
            {
                return;
            }
            var ts = type as TypeSpec;

            if (ts != null && !(ts.TypeSig is FnPtrSig))
            {
                WriteTo(((TypeSpec)type).TypeSig, writer, syntax, depth);
                return;
            }
            string typeFullName = type.FullName;
            string typeName     = type.Name.String;

            if (ts != null)
            {
                var fnPtrSig = ts.TypeSig as FnPtrSig;
                typeFullName = DnlibExtensions.GetFnPtrFullName(fnPtrSig);
                typeName     = DnlibExtensions.GetFnPtrName(fnPtrSig);
            }
            TypeSig typeSig = null;
            string  name    = type.DefinitionAssembly.IsCorLib() ? PrimitiveTypeName(typeFullName, type.Module, out typeSig) : null;

            if (syntax == ILNameSyntax.ShortTypeName)
            {
                if (name != null)
                {
                    WriteKeyword(writer, name, typeSig.ToTypeDefOrRef());
                }
                else
                {
                    writer.WriteReference(Escape(typeName), type, TextTokenHelper.GetTextTokenType(type));
                }
            }
            else if ((syntax == ILNameSyntax.Signature || syntax == ILNameSyntax.SignatureNoNamedTypeParameters) && name != null)
            {
                WriteKeyword(writer, name, typeSig.ToTypeDefOrRef());
            }
            else
            {
                if (syntax == ILNameSyntax.Signature || syntax == ILNameSyntax.SignatureNoNamedTypeParameters)
                {
                    writer.Write(DnlibExtensions.IsValueType(type) ? "valuetype" : "class", TextTokenType.Keyword);
                    writer.WriteSpace();
                }

                if (type.DeclaringType != null)
                {
                    type.DeclaringType.WriteTo(writer, ILNameSyntax.TypeName, depth);
                    writer.Write('/', TextTokenType.Operator);
                    writer.WriteReference(Escape(typeName), type, TextTokenHelper.GetTextTokenType(type));
                }
                else
                {
                    if (!(type is TypeDef) && type.Scope != null && !(type is TypeSpec))
                    {
                        writer.Write('[', TextTokenType.Operator);
                        writer.Write(Escape(type.Scope.GetScopeName()), TextTokenType.ILModule);
                        writer.Write(']', TextTokenType.Operator);
                    }
                    if (ts != null || MustEscape(typeFullName))
                    {
                        writer.WriteReference(Escape(typeFullName), type, TextTokenHelper.GetTextTokenType(type));
                    }
                    else
                    {
                        WriteNamespace(writer, type.Namespace);
                        if (!string.IsNullOrEmpty(type.Namespace))
                        {
                            writer.Write('.', TextTokenType.Operator);
                        }
                        writer.WriteReference(IdentifierEscaper.Escape(type.Name), type, TextTokenHelper.GetTextTokenType(type));
                    }
                }
            }
        }
Exemplo n.º 10
0
 public static void WriteOffsetReference(ITextOutput writer, Instruction instruction, TextTokenType tokenType = TextTokenType.Label)
 {
     writer.WriteReference(DnlibExtensions.OffsetToString(instruction.GetOffset()), instruction, tokenType);
 }
Exemplo n.º 11
0
 public void WriteTo(TextWriter writer)
 {
     foreach (Instruction prefix in this.Prefixes)
     {
         Disassembler.DisassemblerHelpers.WriteTo(prefix, new PlainTextOutput(writer));
         writer.WriteLine();
     }
     if (Instruction != null && Instruction.Offset >= 0)
     {
         writer.Write(DnlibExtensions.OffsetToString(Instruction.Offset));
         writer.Write(": ");
     }
     if (Target != null)
     {
         writer.Write(Target.ToString());
         writer.Write(" = ");
     }
     if (IsMoveInstruction)
     {
         writer.Write(Operands[0].ToString());
         if (Instruction != null)
         {
             writer.Write(" (" + Instruction.OpCode.Name + ")");
         }
     }
     else
     {
         if (Instruction == null)
         {
             writer.Write(SpecialOpCode.ToString());
         }
         else
         {
             writer.Write(Instruction.OpCode.Name);
             if (null != Instruction.Operand)
             {
                 writer.Write(' ');
                 Disassembler.DisassemblerHelpers.WriteOperand(new PlainTextOutput(writer), Instruction.Operand);
                 writer.Write(' ');
             }
         }
         if (TypeOperand != null)
         {
             writer.Write(' ');
             writer.Write(TypeOperand.ToString());
             writer.Write(' ');
         }
         if (Operands.Length > 0)
         {
             writer.Write('(');
             for (int i = 0; i < Operands.Length; i++)
             {
                 if (i > 0)
                 {
                     writer.Write(", ");
                 }
                 writer.Write(Operands[i].ToString());
             }
             writer.Write(')');
         }
     }
 }
Exemplo n.º 12
0
 object ResolveGenericParams(object operand)
 {
     return(DnlibExtensions.ResolveGenericParams(typeParams, methodParams, operand));
 }
 static MethodDef GetMethodDefinition(IMethod method)
 {
     return(DnlibExtensions.ResolveMethodWithinSameModule(method));
 }
 static FieldDef GetFieldDefinition(IField field)
 {
     return(DnlibExtensions.ResolveFieldWithinSameModule(field));
 }
Exemplo n.º 15
0
		bool MatchTaskCreationPattern(ILBlock method)
		{
			if (method.Body.Count < 5)
				return false;
			// Check the second-to-last instruction (the start call) first, as we can get the most information from that
			IMethod startMethod;
			ILExpression loadStartTarget, loadStartArgument;
			// call(AsyncTaskMethodBuilder::Start, ldloca(builder), ldloca(stateMachine))
			if (!method.Body[method.Body.Count - 2].Match(ILCode.Call, out startMethod, out loadStartTarget, out loadStartArgument))
				return false;
			if (startMethod.Name != "Start" || startMethod.DeclaringType == null || startMethod.DeclaringType.Namespace != "System.Runtime.CompilerServices")
				return false;
			switch (startMethod.DeclaringType.Name) {
				case "AsyncTaskMethodBuilder`1":
					methodType = AsyncMethodType.TaskOfT;
					break;
				case "AsyncTaskMethodBuilder":
					methodType = AsyncMethodType.Task;
					break;
				case "AsyncVoidMethodBuilder":
					methodType = AsyncMethodType.Void;
					break;
				default:
					return false;
			}
			ILVariable stateMachineVar, builderVar;
			if (!loadStartTarget.Match(ILCode.Ldloca, out builderVar))
				return false;
			if (!loadStartArgument.Match(ILCode.Ldloca, out stateMachineVar))
				return false;
			
			stateMachineStruct = stateMachineVar.Type.GetTypeDefOrRef().ResolveWithinSameModule();
			if (stateMachineStruct == null || !DnlibExtensions.IsValueType(stateMachineStruct))
				return false;
			moveNextMethod = stateMachineStruct.Methods.FirstOrDefault(f => f.Name == "MoveNext");
			if (moveNextMethod == null)
				return false;
			
			// Check third-to-last instruction (copy of builder):
			// stloc(builder, ldfld(StateMachine::<>t__builder, ldloca(stateMachine)))
			ILExpression loadBuilderExpr;
			if (!method.Body[method.Body.Count - 3].MatchStloc(builderVar, out loadBuilderExpr))
				return false;
			IField builderFieldRef;
			ILExpression loadStateMachineForBuilderExpr;
			if (!loadBuilderExpr.Match(ILCode.Ldfld, out builderFieldRef, out loadStateMachineForBuilderExpr))
				return false;
			if (!(loadStateMachineForBuilderExpr.MatchLdloca(stateMachineVar) || loadStateMachineForBuilderExpr.MatchLdloc(stateMachineVar)))
				return false;
			builderField = builderFieldRef.ResolveFieldWithinSameModule();
			if (builderField == null)
				return false;
			
			// Check the last instruction (ret)
			if (methodType == AsyncMethodType.Void) {
				if (!method.Body[method.Body.Count - 1].Match(ILCode.Ret))
					return false;
			} else {
				// ret(call(AsyncTaskMethodBuilder::get_Task, ldflda(StateMachine::<>t__builder, ldloca(stateMachine))))
				ILExpression returnValue;
				if (!method.Body[method.Body.Count - 1].Match(ILCode.Ret, out returnValue))
					return false;
				IMethod getTaskMethod;
				ILExpression builderExpr;
				if (!returnValue.Match(ILCode.Call, out getTaskMethod, out builderExpr))
					return false;
				ILExpression loadStateMachineForBuilderExpr2;
				IField builderField2;
				if (!builderExpr.Match(ILCode.Ldflda, out builderField2, out loadStateMachineForBuilderExpr2))
					return false;
				if (builderField2.ResolveFieldWithinSameModule() != builderField || !loadStateMachineForBuilderExpr2.MatchLdloca(stateMachineVar))
					return false;
			}
			
			// Check the last field assignment - this should be the state field
			ILExpression initialStateExpr;
			if (!MatchStFld(method.Body[method.Body.Count - 4], stateMachineVar, out stateField, out initialStateExpr))
				return false;
			if (!initialStateExpr.Match(ILCode.Ldc_I4, out initialState))
				return false;
			if (initialState != -1)
				return false;
			
			// Check the second-to-last field assignment - this should be the builder field
			FieldDef builderField3;
			ILExpression builderInitialization;
			if (!MatchStFld(method.Body[method.Body.Count - 5], stateMachineVar, out builderField3, out builderInitialization))
				return false;
			IMethod createMethodRef;
			if (builderField3 != builderField || !builderInitialization.Match(ILCode.Call, out createMethodRef))
				return false;
			if (createMethodRef.Name != "Create")
				return false;
			
			for (int i = 0; i < method.Body.Count - 5; i++) {
				FieldDef field;
				ILExpression fieldInit;
				if (!MatchStFld(method.Body[i], stateMachineVar, out field, out fieldInit))
					return false;
				ILVariable v;
				if (!fieldInit.Match(ILCode.Ldloc, out v))
					return false;
				if (!v.IsParameter)
					return false;
				fieldToParameterMap[field] = v;
			}
			
			return true;
		}
Exemplo n.º 16
0
        /// <summary>
        /// Is this a temporary variable generated by the C# compiler for instance method calls on value type values
        /// </summary>
        /// <param name="next">The next top-level expression</param>
        /// <param name="parent">The direct parent of the load within 'next'</param>
        /// <param name="pos">Index of the load within 'parent'</param>
        /// <param name="v">The variable being inlined.</param>
        /// <param name="inlinedExpression">The expression being inlined</param>
        bool IsGeneratedValueTypeTemporary(ILExpression next, ILExpression parent, int pos, ILVariable v, ILExpression inlinedExpression)
        {
            if (pos == 0 && v.Type != null && DnlibExtensions.IsValueType(v.Type))
            {
                // Inlining a value type variable is allowed only if the resulting code will maintain the semantics
                // that the method is operating on a copy.
                // Thus, we have to disallow inlining of other locals, fields, array elements, dereferenced pointers
                switch (inlinedExpression.Code)
                {
                case ILCode.Ldloc:
                case ILCode.Stloc:
                case ILCode.CompoundAssignment:
                case ILCode.Ldelem:
                case ILCode.Ldelem_I:
                case ILCode.Ldelem_I1:
                case ILCode.Ldelem_I2:
                case ILCode.Ldelem_I4:
                case ILCode.Ldelem_I8:
                case ILCode.Ldelem_R4:
                case ILCode.Ldelem_R8:
                case ILCode.Ldelem_Ref:
                case ILCode.Ldelem_U1:
                case ILCode.Ldelem_U2:
                case ILCode.Ldelem_U4:
                case ILCode.Ldobj:
                case ILCode.Ldind_Ref:
                    return(false);

                case ILCode.Ldfld:
                case ILCode.Stfld:
                case ILCode.Ldsfld:
                case ILCode.Stsfld:
                    // allow inlining field access only if it's a readonly field
                    FieldDef f = ((IField)inlinedExpression.Operand).Resolve();
                    if (!(f != null && f.IsInitOnly))
                    {
                        return(false);
                    }
                    break;

                case ILCode.Call:
                case ILCode.CallGetter:
                    // inlining runs both before and after IntroducePropertyAccessInstructions,
                    // so we have to handle both 'call' and 'callgetter'
                    IMethod mr = (IMethod)inlinedExpression.Operand;
                    // ensure that it's not an multi-dimensional array getter
                    TypeSig ts;
                    if (mr.DeclaringType is TypeSpec && (ts = ((TypeSpec)mr.DeclaringType).TypeSig.RemovePinnedAndModifiers()) != null && ts.IsSingleOrMultiDimensionalArray)
                    {
                        return(false);
                    }
                    goto case ILCode.Callvirt;

                case ILCode.Callvirt:
                case ILCode.CallvirtGetter:
                    // don't inline foreach loop variables:
                    mr = (IMethod)inlinedExpression.Operand;
                    if (mr.Name == "get_Current" && mr.MethodSig != null && mr.MethodSig.HasThis)
                    {
                        return(false);
                    }
                    break;

                case ILCode.Castclass:
                case ILCode.Unbox_Any:
                    // These are valid, but might occur as part of a foreach loop variable.
                    ILExpression arg = inlinedExpression.Arguments[0];
                    if (arg.Code == ILCode.CallGetter || arg.Code == ILCode.CallvirtGetter || arg.Code == ILCode.Call || arg.Code == ILCode.Callvirt)
                    {
                        mr = (IMethod)arg.Operand;
                        if (mr.Name == "get_Current" && mr.MethodSig != null && mr.MethodSig.HasThis)
                        {
                            return(false);                                    // looks like a foreach loop variable, so don't inline it
                        }
                    }
                    break;
                }

                // inline the compiler-generated variable that are used when accessing a member on a value type:
                switch (parent.Code)
                {
                case ILCode.Call:
                case ILCode.CallGetter:
                case ILCode.CallSetter:
                case ILCode.Callvirt:
                case ILCode.CallvirtGetter:
                case ILCode.CallvirtSetter:
                    IMethod mr = parent.Operand as IMethod;
                    return(mr == null || mr.MethodSig == null ? false : mr.MethodSig.HasThis);

                case ILCode.Stfld:
                case ILCode.Ldfld:
                case ILCode.Ldflda:
                case ILCode.Await:
                    return(true);
                }
            }
            return(false);
        }