Author: spouliot
Date: 2008-02-15 14:27:50 -0500 (Fri, 15 Feb 2008)
New Revision: 95797
Removed:
trunk/mono-tools/gendarme/framework/Gendarme.Framework/MethodSignature.cs
trunk/mono-tools/gendarme/framework/Gendarme.Framework/MethodSignatures.cs
trunk/mono-tools/gendarme/framework/Gendarme.Framework/StackEntryAnalysis.cs
Modified:
trunk/mono-tools/gendarme/framework/Gendarme.Framework/ChangeLog
Log:
* MethodSignature.cs
* MethodSignatures.cs
* StackEntryAnalysis.cs:
Moved into Gendarme.Framework.Helpers
2008-02-15 Sebastien Pouliot <[EMAIL PROTECTED]>
Modified: trunk/mono-tools/gendarme/framework/Gendarme.Framework/ChangeLog
===================================================================
--- trunk/mono-tools/gendarme/framework/Gendarme.Framework/ChangeLog
2008-02-15 19:27:00 UTC (rev 95796)
+++ trunk/mono-tools/gendarme/framework/Gendarme.Framework/ChangeLog
2008-02-15 19:27:50 UTC (rev 95797)
@@ -1,5 +1,12 @@
2008-02-15 Sebastien Pouliot <[EMAIL PROTECTED]>
+ * MethodSignature.cs
+ * MethodSignatures.cs
+ * StackEntryAnalysis.cs:
+ Moved into Gendarme.Framework.Helpers
+
+2008-02-15 Sebastien Pouliot <[EMAIL PROTECTED]>
+
* Runner.cs: Use Rocks to iterate all methods in a type.
2008-02-14 Sebastien Pouliot <[EMAIL PROTECTED]>
Deleted:
trunk/mono-tools/gendarme/framework/Gendarme.Framework/MethodSignature.cs
===================================================================
--- trunk/mono-tools/gendarme/framework/Gendarme.Framework/MethodSignature.cs
2008-02-15 19:27:00 UTC (rev 95796)
+++ trunk/mono-tools/gendarme/framework/Gendarme.Framework/MethodSignature.cs
2008-02-15 19:27:50 UTC (rev 95797)
@@ -1,171 +0,0 @@
-//
-// Gendarme.Framework.MethodSignature
-//
-// Authors:
-// Andreas Noever <[EMAIL PROTECTED]>
-// Sebastien Pouliot <[EMAIL PROTECTED]>
-//
-// (C) 2008 Andreas Noever
-// Copyright (C) 2008 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.Collections.ObjectModel;
-using System.Collections.Generic;
-using System.Text;
-
-using Mono.Cecil;
-
-namespace Gendarme.Framework {
-
- /// <summary>
- /// Used to match methods. Properties that are set to null are ignored
- /// </summary>
- /// <example>
- /// <code>
- /// MethodDefinition method = ...
- /// MethodSignature sig = new MethodSignature ("Dispose");
- /// if (sig.Match (method)) {
- /// //matches any method named "Dispose" with any (or no) return
value and any number of parameters
- /// }
- /// </code>
- /// </example>
- /// <seealso cref="Gendarme.Framework.MethodSignatures"/>
- public class MethodSignature {
-
- /// <summary>
- /// The name of the method to match. Ignored if null.
- /// </summary>
- public string Name { get; private set; }
-
- /// <summary>
- /// The FullName (Namespace.Type) of the return type. Ignored
if null.
- /// </summary>
- public string ReturnType { get; private set; }
-
- /// <summary>
- /// An array of FullNames (Namespace.Type) of parameter types.
Ignored if null. Null entries act as wildcards.
- /// </summary>
- public ReadOnlyCollection<string> Parameters { get; private
set; }
-
- /// <summary>
- /// An attribute mask matched against the attributes of the
method.
- /// </summary>
- public MethodAttributes Attributes { get; private set; }
-
-
- public MethodSignature ()
- {
- }
-
- public MethodSignature (string name)
- : this (name, null, null)
- {
- }
-
- public MethodSignature (string name, string returnType)
- : this (name, returnType, null)
- {
- }
-
- public MethodSignature (string name, string returnType,
string[] parameters)
- {
- Name = name;
- ReturnType = returnType;
- if (parameters != null)
- Parameters = new ReadOnlyCollection<string>
(new List<string> (parameters));
- }
-
- public MethodSignature (string name, string returnType, string
[] parameters, MethodAttributes attributes)
- : this (name, returnType, parameters)
- {
- Attributes = attributes;
- }
-
- /// <summary>
- /// Checks if a MethodReference match the signature.
- /// </summary>
- /// <param name="method">The method to check.</param>
- /// <returns>True if the MethodReference matches all aspects of
the MethodSignature.</returns>
- public bool Matches (MethodReference method)
- {
- if (method == null)
- throw new ArgumentNullException ("method");
-
- if (Name != null && method.Name != Name)
- return false;
-
- if (ReturnType != null &&
method.ReturnType.ReturnType.FullName != ReturnType)
- return false;
-
- if (Parameters != null) {
- if (Parameters.Count != method.Parameters.Count)
- return false;
- for (int i = 0; i < Parameters.Count; i++) {
- if (Parameters [i] == null)
- continue;//ignore parameter
- if (Parameters [i] != method.Parameters
[i].ParameterType.FullName) {
- return false;
- }
- }
- }
-
- // skip last check if no attributes are part of the
signature
- if (((int) Attributes) == 0)
- return true;
-
- // put this at last step so we avoid the cast as much
as possible
- MethodDefinition md = (method as MethodDefinition);
- return ((md == null) || ((md.Attributes & Attributes)
== Attributes));
- }
-
- /// <summary>
- ///
- /// </summary>
- /// <returns></returns>
- public override string ToString ()
- {
- // if we do not have enough useful information return
an empty string
- if (Name == null)
- return String.Empty;
-
- StringBuilder sb = new StringBuilder ();
- if (ReturnType != null) {
- sb.Append (ReturnType);
- sb.Append (' ');
- }
-
- sb.Append (Name);
- sb.Append ('(');
- if (Parameters != null) {
- for (int i = 0; i < Parameters.Count; i++) {
- sb.Append (Parameters [i]);
- if (i < Parameters.Count - 1)
- sb.Append (',');
- }
- }
- sb.Append (')');
-
- return sb.ToString ();
- }
- }
-}
Deleted:
trunk/mono-tools/gendarme/framework/Gendarme.Framework/MethodSignatures.cs
===================================================================
--- trunk/mono-tools/gendarme/framework/Gendarme.Framework/MethodSignatures.cs
2008-02-15 19:27:00 UTC (rev 95796)
+++ trunk/mono-tools/gendarme/framework/Gendarme.Framework/MethodSignatures.cs
2008-02-15 19:27:50 UTC (rev 95797)
@@ -1,92 +0,0 @@
-//
-// Gendarme.Framework.MethodSignatures
-//
-// Authors:
-// Andreas Noever <[EMAIL PROTECTED]>
-// Sebastien Pouliot <[EMAIL PROTECTED]>
-//
-// (C) 2008 Andreas Noever
-// Copyright (C) 2008 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-
-using Mono.Cecil;
-
-namespace Gendarme.Framework {
-
- /// <summary>
- /// Defines commonly used MethodSignatures
- /// </summary>
- /// <see cref="Gendarme.Framework.MethodSignature"/>
- public static class MethodSignatures {
- private static readonly string [] NoParameter = new string [0];
- private static readonly string [] OneParameter = new string [1];
- private static readonly string [] TwoParameters = new string
[2];
-
- // System.Object
- public static readonly new MethodSignature Equals = new
MethodSignature ("Equals", "System.Boolean", new string [] { "System.Object" },
MethodAttributes.Public);
- public static readonly MethodSignature Finalize = new
MethodSignature ("Finalize", "System.Void", NoParameter,
MethodAttributes.Family);
- public static readonly new MethodSignature GetHashCode = new
MethodSignature ("GetHashCode", "System.Int32", NoParameter,
MethodAttributes.Public | MethodAttributes.Virtual);
- public static readonly new MethodSignature ToString = new
MethodSignature ("ToString", "System.String", NoParameter,
MethodAttributes.Public | MethodAttributes.Virtual);
-
- // IDisposable
- public static readonly MethodSignature Dispose = new
MethodSignature ("Dispose", "System.Void", NoParameter);
- public static readonly MethodSignature DisposeExplicit = new
MethodSignature ("System.IDisposable.Dispose", "System.Void", NoParameter);
-
- // operators
- private static readonly MethodAttributes OperatorAttributes =
MethodAttributes.Static | MethodAttributes.SpecialName;
-
- // unary
- public static readonly MethodSignature op_UnaryPlus = new
MethodSignature ("op_UnaryPlus", null, OneParameter, OperatorAttributes);
// +5
- public static readonly MethodSignature op_UnaryNegation = new
MethodSignature ("op_UnaryNegation", null, OneParameter, OperatorAttributes);
// -5
- public static readonly MethodSignature op_LogicalNot = new
MethodSignature ("op_LogicalNot", null, OneParameter, OperatorAttributes);
// !true
- public static readonly MethodSignature op_OnesComplement = new
MethodSignature ("op_OnesComplement", null, OneParameter, OperatorAttributes);
// ~5
-
- public static readonly MethodSignature op_Increment = new
MethodSignature ("op_Increment", null, OneParameter, OperatorAttributes);
// 5++
- public static readonly MethodSignature op_Decrement = new
MethodSignature ("op_Decrement", null, OneParameter, OperatorAttributes);
// 5--
- public static readonly MethodSignature op_True = new
MethodSignature ("op_True", "System.Boolean", OneParameter,
OperatorAttributes); // if (object)
- public static readonly MethodSignature op_False = new
MethodSignature ("op_False", "System.Boolean", OneParameter,
OperatorAttributes); // if (object)
-
- // binary
- public static readonly MethodSignature op_Addition = new
MethodSignature ("op_Addition", null, TwoParameters, OperatorAttributes);
// 5 + 5
- public static readonly MethodSignature op_Subtraction = new
MethodSignature ("op_Subtraction", null, TwoParameters, OperatorAttributes);
// 5 - 5
- public static readonly MethodSignature op_Multiply = new
MethodSignature ("op_Multiply", null, TwoParameters, OperatorAttributes);
// 5 * 5
- public static readonly MethodSignature op_Division = new
MethodSignature ("op_Division", null, TwoParameters, OperatorAttributes);
// 5 / 5
- public static readonly MethodSignature op_Modulus = new
MethodSignature ("op_Modulus", null, TwoParameters, OperatorAttributes);
// 5 % 5
-
- public static readonly MethodSignature op_BitwiseAnd = new
MethodSignature ("op_BitwiseAnd", null, TwoParameters, OperatorAttributes);
// 5 & 5
- public static readonly MethodSignature op_BitwiseOr = new
MethodSignature ("op_BitwiseOr", null, TwoParameters, OperatorAttributes);
// 5 | 5
- public static readonly MethodSignature op_ExclusiveOr = new
MethodSignature ("op_ExclusiveOr", null, TwoParameters, OperatorAttributes);
// 5 ^ 5
-
- public static readonly MethodSignature op_LeftShift = new
MethodSignature ("op_LeftShift", null, TwoParameters, OperatorAttributes);
// 5 << 5
- public static readonly MethodSignature op_RightShift = new
MethodSignature ("op_RightShift", null, TwoParameters, OperatorAttributes);
// 5 >> 5
-
- // comparison
- public static readonly MethodSignature op_Equality = new
MethodSignature ("op_Equality", null, TwoParameters, OperatorAttributes);
// 5 == 5
- public static readonly MethodSignature op_Inequality = new
MethodSignature ("op_Inequality", null, TwoParameters, OperatorAttributes);
// 5 != 5
- public static readonly MethodSignature op_GreaterThan = new
MethodSignature ("op_GreaterThan", null, TwoParameters, OperatorAttributes);
// 5 > 5
- public static readonly MethodSignature op_LessThan = new
MethodSignature ("op_LessThan", null, TwoParameters, OperatorAttributes);
// 5 < 5
- public static readonly MethodSignature op_GreaterThanOrEqual =
new MethodSignature ("op_GreaterThanOrEqual", null, TwoParameters,
OperatorAttributes); // 5 >= 5
- public static readonly MethodSignature op_LessThanOrEqual = new
MethodSignature ("op_LessThanOrEqual", null, TwoParameters,
OperatorAttributes); // 5 <= 5
- }
-}
Deleted:
trunk/mono-tools/gendarme/framework/Gendarme.Framework/StackEntryAnalysis.cs
===================================================================
---
trunk/mono-tools/gendarme/framework/Gendarme.Framework/StackEntryAnalysis.cs
2008-02-15 19:27:00 UTC (rev 95796)
+++
trunk/mono-tools/gendarme/framework/Gendarme.Framework/StackEntryAnalysis.cs
2008-02-15 19:27:50 UTC (rev 95797)
@@ -1,656 +0,0 @@
-//
-// Gendarme.Framework.StackEntryAnalysis
-//
-// Authors:
-// Andreas Noever <[EMAIL PROTECTED]>
-//
-// (C) 2008 Andreas Noever
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.Collections.Generic;
-
-using Mono.Cecil;
-using Mono.Cecil.Cil;
-
-using Gendarme.Framework.Rocks;
-
-namespace Gendarme.Framework {
-
- /// <summary>
- /// This class can be used to find all usages of a reference on the
stack.
- /// Currently used for:
- /// Gendarme.Rules.BadPractice.CheckNewExceptionWithoutThrowRule
- /// Gendarme.Rules.BadPractice.CheckNewThreadWithoutStartRule
- ///
Gendarme.Rules.Interoperability.GetLastErrorMustBeCalledRightAfterPInvokeRule
- /// </summary>
- public class StackEntryAnalysis {
-
- /// <summary>
- /// Represents a usage of a StackEntry
- /// </summary>
- public struct UsageResult {
- /// <summary>
- /// The instruction that uses the StackEntry
- /// </summary>
- public readonly Instruction Instruction;
- /// <summary>
- /// The positive offset of the StackEntry before the
instruction executes. 0 means right on top.
- /// </summary>
- public readonly int StackOffset;
- public UsageResult (Instruction ins, int offset)
- {
- this.Instruction = ins;
- this.StackOffset = offset;
- }
- }
-
- enum StoreType {
- None,
- Local,
- Argument,
- Field,
- StaticField,
- Out,
- }
-
- /// <summary>
- /// Saves information about a local variable slot (argument or
local variable).
- /// Used to keep track of assignments.
- /// </summary>
- struct StoreSlot {
- public readonly StoreType Type;
- public readonly int Slot;
- public StoreSlot (StoreType type, int slot)
- {
- this.Type = type;
- this.Slot = slot;
- }
-
- /// <summary>
- /// Use this to check if an instruction accesses a
StoreSlot. True if this is not a StoreSlot.
- /// </summary>
- public bool IsNone
- {
- get
- {
- return this.Type == StoreType.None;
- }
- }
-
- public static bool operator == (StoreSlot a, StoreSlot
b)
- {
- return a.Slot == b.Slot && a.Type == b.Type;
- }
-
- public static bool operator != (StoreSlot a, StoreSlot
b)
- {
- return a.Slot != b.Slot || a.Type != b.Type;
- }
-
- public override bool Equals (object obj)
- {
- if (obj == null)
- return false;
- if (!(obj is StoreSlot))
- return false;
- StoreSlot other = (StoreSlot) obj;
- return this == other;
- }
-
- public override int GetHashCode ()
- {
- return Slot.GetHashCode () ^ Type.GetHashCode
();
- }
- }
-
- /// <summary>
- /// Wraps an instruction and a stack of leave statements used
to get to this instruction.
- /// Needed to do correct analysis in finally blocks.
- /// </summary>
- struct InstructionWithLeave {
- public static readonly InstructionWithLeave Empty = new
InstructionWithLeave ();
-
- public readonly Instruction Instruction;
- public readonly Instruction [] LeaveStack;
-
- public InstructionWithLeave (Instruction instruction)
- {
- this.Instruction = instruction;
- this.LeaveStack = null;
- }
-
- private InstructionWithLeave (Instruction instruction,
Instruction [] leaveStack)
- {
- this.Instruction = instruction;
- this.LeaveStack = leaveStack;
- }
-
- /// <summary>
- /// Returns a new InstructionWithLeave with leave
pushed onto the stack.
- /// </summary>
- /// <param name="instruction">The new
instruction.</param>
- /// <param name="leave">The leave instruction to push
onto the stack.</param>
- /// <returns>A new InstructionWithLeave</returns>
- public InstructionWithLeave Push (Instruction
instruction, Instruction leave)
- {
- Instruction [] newStack;
- if (this.LeaveStack != null) {
- newStack = new Instruction
[LeaveStack.Length + 1];
- Array.Copy (LeaveStack, newStack,
LeaveStack.Length);
- newStack [LeaveStack.Length] = leave;
- } else {
- newStack = new Instruction [] { leave };
- }
- return new InstructionWithLeave (instruction,
newStack);
- }
-
- /// <summary>
- /// Returns a new InstructionWithLeave with the same
LeaveStack and another instruction.
- /// </summary>
- /// <param name="instruction">The new
instruction.</param>
- /// <returns>a new InstructionWithLeave</returns>
- public InstructionWithLeave Copy (Instruction
instruction)
- {
- return new InstructionWithLeave (instruction,
this.LeaveStack);
- }
-
- /// <summary>
- /// Returns a new InstructionWithLeave with the one
leave statement popped and instruction set to the operand of the popped leave
statement.
- /// </summary>
- /// <returns>a new InstructionWithLeave</returns>
- public InstructionWithLeave Pop ()
- {
- Instruction [] newStack = null;
- if (LeaveStack.Length != 1) {
- newStack = new Instruction
[LeaveStack.Length - 1];
- Array.Copy (LeaveStack, newStack,
newStack.Length);
- }
- return new InstructionWithLeave ((Instruction)
this.LeaveStack [this.LeaveStack.Length - 1].Operand, newStack);
- }
-
- }
-
- public MethodDefinition Method {
- get; private set;
- }
-
- private MethodBody Body {
- get { return Method.Body; }
- }
-
- public StackEntryAnalysis (MethodDefinition method)
- {
- this.Method = method;
- }
-
- //static lists to save allocations.
- private static List<KeyValuePair<InstructionWithLeave, int>>
UsedBy = new List<KeyValuePair<InstructionWithLeave, int>> ();
- private static List<KeyValuePair<InstructionWithLeave, int>>
AlternativePaths = new List<KeyValuePair<InstructionWithLeave, int>> ();
-
- /// <summary>
- /// Searches a method for usage of the value pushed onto the
stack by the specified instruction.
- /// </summary>
- /// <param name="ins">The instruction.</param>
- /// <returns>An array of UsageResults containing the
instructions that use the value and the stack offset of the entry at that
instruction. A StackOffset of 0 means right on top of the stack.</returns>
- public UsageResult [] GetStackEntryUsage (Instruction ins)
- {
- /* In the main loop we search for all usages of a
StackEntry.
- * Then we check each usage for a store (to a local
variable or an argument), search for corrosponding loads and search for usages
of the new Stackentry.
- * This continues until no stores are found. */
-
- UsedBy.Clear ();
- AlternativePaths.Clear ();
-
- AlternativePaths.Add (new
KeyValuePair<InstructionWithLeave, int> (new InstructionWithLeave (ins.Next),
0));
-
- int lastAlternativesCount = 0;
- int lastUsedByCount = 0;
-
- while (lastAlternativesCount != AlternativePaths.Count)
{ //continue until no more alternatives have been found (by CheckUsedBy)
-
- for (int i = lastAlternativesCount; i <
AlternativePaths.Count; i++) { //find the instruction that pops the value and
follow all branches
- var result = FollowStackEntry
(AlternativePaths [i].Key, AlternativePaths [i].Value);
- if (result.Key.Instruction != null)
- UsedBy.AddIfNew (result); //add
to usedby list
- }
- lastAlternativesCount = AlternativePaths.Count;
//check each path only once.
-
- CheckUsedBy (lastUsedByCount);
- lastUsedByCount = UsedBy.Count;
- }
-
- //build return value
- UsageResult [] results = new UsageResult [UsedBy.Count];
- for (int i = 0; i < results.Length; i++)
- results [i] = new UsageResult (UsedBy
[i].Key.Instruction, UsedBy [i].Value);
- return results;
- }
-
- /// <summary>
- /// Iterates over all Instructions inside UsedBy and spawns a
new alternative if necessary.
- /// </summary>
- /// <param name="start">The first index to progress.</param>
- private void CheckUsedBy (int start)
- {
- for (int ii = start; ii < UsedBy.Count; ii++) {
- InstructionWithLeave use = UsedBy [ii].Key;
-
- StoreSlot slot = GetStoreSlot
(use.Instruction); //check if this is a store instruction
-
- bool removeFromUseBy = false; //ignore the use
-
- if (use.Instruction.OpCode.Code ==
Code.Castclass) {
- removeFromUseBy = true;
- AlternativePaths.AddIfNew (new
KeyValuePair<InstructionWithLeave, int> (use.Copy (use.Instruction.Next), 0));
- } else if (use.Instruction.OpCode.Code ==
Code.Pop) {//pop is not a valid usage
- removeFromUseBy = true;
- } else if (!slot.IsNone) {
- if (slot.Type == StoreType.Argument ||
slot.Type == StoreType.Local)
- removeFromUseBy = true;
//temporary save
- foreach (var ld in this.FindLoad
(use.Copy (use.Instruction.Next), slot)) { //start searching at the next
instruction
- AlternativePaths.AddIfNew (new
KeyValuePair<InstructionWithLeave, int> (ld.Copy (ld.Instruction.Next), 0));
- }
- }
- if (removeFromUseBy) {
- UsedBy.RemoveAt (ii);
- ii--;
- }
- }
- }
-
- /// <summary>
- /// Follows the instructions until the specified stack entry is
accessed.
- /// </summary>
- /// <param name="ins">The first instruction.</param>
- /// <param name="stackEntry">The distance of the stack entry
from the top of the stack. 0 means right on top.</param>
- /// <returns>The instruction that pops the stackEntry and the
distance of the entry to the top of the stack. If no valid instruction if found
the method returns InstructionWithLeave.Empty.</returns>
- private KeyValuePair<InstructionWithLeave, int>
FollowStackEntry (InstructionWithLeave startInstruction, int stackEntryDistance)
- {
- Instruction ins = startInstruction.Instruction;
-
- while (true) {
- int pop = this.GetPopCount (ins);
- int push = this.GetPushCount (ins);
-
- if (pop > stackEntryDistance) //does this
instruction pop the stack entry
- return new
KeyValuePair<InstructionWithLeave, int> (startInstruction.Copy (ins),
stackEntryDistance);
-
- stackEntryDistance -= pop;
- stackEntryDistance += push;
-
- //fetch ne next instruction
- object alternativeNext;
- Instruction nextInstruction =
GetNextInstruction (ins, out alternativeNext);
-
- if (nextInstruction == null)
- return new
KeyValuePair<InstructionWithLeave, int> (); //return / throw / endfinally
-
- if (nextInstruction.OpCode.Code == Code.Leave
|| nextInstruction.OpCode.Code == Code.Leave_S)
- return new
KeyValuePair<InstructionWithLeave, int> (); //leave clears the stack, the entry
is gone.
-
- if (alternativeNext != null) { //branch /
switch
- Instruction oneTarget = alternativeNext
as Instruction;
- if (oneTarget != null) { //branch
- AlternativePaths.AddIfNew (new
KeyValuePair<InstructionWithLeave, int> (startInstruction.Copy (oneTarget),
stackEntryDistance));
- } else { //switch
- foreach (Instruction
switchTarget in (Instruction []) alternativeNext)
-
AlternativePaths.AddIfNew (new KeyValuePair<InstructionWithLeave, int>
(startInstruction.Copy (switchTarget), stackEntryDistance));
- }
- }
-
- if (nextInstruction.OpCode.FlowControl ==
FlowControl.Branch || nextInstruction.OpCode.FlowControl ==
FlowControl.Cond_Branch) {
- AlternativePaths.AddIfNew (new
KeyValuePair<InstructionWithLeave, int> (startInstruction.Copy
(nextInstruction), stackEntryDistance));
- return new
KeyValuePair<InstructionWithLeave, int> (); //end of block
- }
- ins = nextInstruction;
- }
- }
-
-
- //static lists to save allocations.
- private static List<InstructionWithLeave> LoadAlternatives =
new List<InstructionWithLeave> ();
- private static List<InstructionWithLeave> LoadResults = new
List<InstructionWithLeave> ();
-
- /// <summary>
- /// Follows the codeflow starting at a given instruction and
finds all loads for a given slot.
- /// Continues and follows all branches until the slot is
overwritten or the method returns / throws.
- /// </summary>
- /// <param name="insWithLeave">The first instruction to start
the search at.</param>
- /// <param name="slot">The slot to search.</param>
- /// <returns>An array of instructions that load from the
slot.</returns>
- private InstructionWithLeave [] FindLoad (InstructionWithLeave
insWithLeave, StoreSlot slot)
- {
- LoadAlternatives.Clear ();
- LoadResults.Clear ();
-
- LoadAlternatives.Add (insWithLeave);
-
-
- for (int i = 0; i < LoadAlternatives.Count; i++) {
//loop over all branches, more will get added inside the loop
- insWithLeave = LoadAlternatives [i]; //the
first instruction of the block (contains the leave stack)
-
- Instruction ins = insWithLeave.Instruction;
//the current instruction
- while (true) {
-
- if (GetStoreSlot (ins) == slot) //check
if the slot gets overwritten
- break;
-
- if (slot == GetLoadSlot (ins))
- LoadResults.AddIfNew
(insWithLeave.Copy (ins)); //continue, might be loaded again
-
- //we simply branch to every possible
catch block.
- foreach (ExceptionHandler handler in
Body.ExceptionHandlers) {
- if (handler.Type !=
ExceptionHandlerType.Catch)
- continue;
- if (ins.Offset <
handler.TryStart.Offset || ins.Offset >= handler.TryEnd.Offset)
- continue;
- LoadAlternatives.AddIfNew
(insWithLeave.Copy (handler.HandlerStart));
- }
-
- //Code.Leave leaves a try/catch block.
Search for the finally block.
- if (ins.OpCode.Code == Code.Leave ||
ins.OpCode.Code == Code.Leave_S) {
- bool handlerFound = false;
- foreach (ExceptionHandler
handler in Body.ExceptionHandlers) {
- if (handler.Type !=
ExceptionHandlerType.Finally)
- continue;
- if
(handler.TryStart.Offset > ins.Offset || handler.TryEnd.Offset <= ins.Offset)
- continue;
-
LoadAlternatives.AddIfNew (insWithLeave.Push (handler.HandlerStart, ins));
//push the leave instruction onto the leave stack
- handlerFound = true;
- break;
- }
- if (!handlerFound) //no finally
found (try/catch without finally)
-
LoadAlternatives.AddIfNew (insWithLeave.Copy ((Instruction) ins.Operand));
- break;
-
- }
-
- if (ins.OpCode.Code == Code.Endfinally)
{ //pop the last leave instruction and branch to it
- LoadAlternatives.AddIfNew
(insWithLeave.Pop ());
- break;
- }
-
- //fetch the next instruction (s)
- object alternativeNext;
- ins = GetNextInstruction (ins, out
alternativeNext);
- if (ins == null)
- break;
-
- if (alternativeNext != null) {
- Instruction oneTarget =
alternativeNext as Instruction;
- if (oneTarget != null) {
//normal branch
-
LoadAlternatives.AddIfNew (insWithLeave.Copy (oneTarget));
- } else { //switch statement
- foreach (Instruction
switchTarget in (Instruction []) alternativeNext)
-
LoadAlternatives.AddIfNew (insWithLeave.Copy (switchTarget));
- }
- }
-
- if (ins.OpCode.FlowControl ==
FlowControl.Branch || ins.OpCode.FlowControl == FlowControl.Cond_Branch) {
- if (ins.OpCode.Code !=
Code.Leave && ins.OpCode.Code != Code.Leave_S) {
-
LoadAlternatives.AddIfNew (insWithLeave.Copy (ins)); //add if new, avoid
infinity loop
- break;
- }
- }
- }
- }
- return LoadResults.ToArray ();
- }
-
- /// <summary>
- /// Helper method that returns the next Instruction.
- /// </summary>
- /// <param name="ins">The instruction</param>
- /// <param name="alternative">If the instruction is a branch,
the branch target is returned. For a switch statemant an array of targets is
returned.</param>
- /// <returns>The next instruction that would be executed by the
runtime.</returns>
- public static Instruction GetNextInstruction (Instruction ins,
out object alternative)
- {
- alternative = null;
- switch (ins.OpCode.FlowControl) {
- case FlowControl.Branch:
- return (Instruction) ins.Operand;
- case FlowControl.Cond_Branch:
- alternative = ins.Operand;
- return ins.Next;
- case FlowControl.Call:
- case FlowControl.Next:
- case FlowControl.Meta:
- case FlowControl.Break: //debugging breakpoint
- return ins.Next;
- case FlowControl.Return:
- case FlowControl.Throw:
- return null;
- default:
- throw new NotImplementedException
("FlowControl: " + ins.OpCode.FlowControl + " is not supported.");
-
- }
- }
-
- /// <summary>
- /// Checks if an instruction is a load and returns the slot it
loads from.
- /// </summary>
- /// <param name="ins">The instruction</param>
- /// <returns>If the instruction is a load returns the slot to
load. Check slot.IsNone() to see if this instruction is a load.</returns>
- private StoreSlot GetLoadSlot (Instruction ins)
- {
- switch (ins.OpCode.Code) {
- case Code.Ldloc_0:
- return new StoreSlot (StoreType.Local, 0);
- case Code.Ldloc_1:
- return new StoreSlot (StoreType.Local, 1);
- case Code.Ldloc_2:
- return new StoreSlot (StoreType.Local, 2);
- case Code.Ldloc_3:
- return new StoreSlot (StoreType.Local, 3);
- case Code.Ldloc_S:
- case Code.Ldloc:
- return new StoreSlot (StoreType.Local,
((VariableDefinition) ins.Operand).Index);
-
- case Code.Ldfld:
- //TODO: we do not check what instance is on the
stack
- return new StoreSlot (StoreType.Field, (int)
((FieldReference) ins.Operand).MetadataToken.ToUInt ());
- case Code.Ldsfld:
- return new StoreSlot (StoreType.StaticField,
(int) ((FieldReference) ins.Operand).MetadataToken.ToUInt ());
-
- case Code.Ldarg_0:
- return new StoreSlot (StoreType.Argument, 0);
- case Code.Ldarg_1:
- return new StoreSlot (StoreType.Argument, 1);
- case Code.Ldarg_2:
- return new StoreSlot (StoreType.Argument, 2);
- case Code.Ldarg_3:
- return new StoreSlot (StoreType.Argument, 3);
- case Code.Ldarg_S:
- case Code.Ldarg: {
- int sequence = ((ParameterDefinition)
ins.Operand).Sequence;
- if (!this.Method.HasThis)
- sequence--;
- return new StoreSlot
(StoreType.Argument, sequence);
- }
-
- case Code.Ldind_I:
- case Code.Ldind_I1:
- case Code.Ldind_I2:
- case Code.Ldind_I4:
- case Code.Ldind_I8:
- case Code.Ldind_R4:
- case Code.Ldind_R8:
- case Code.Ldind_Ref:
- case Code.Ldind_U1:
- case Code.Ldind_U2:
- case Code.Ldind_U4:
- //TODO: improve stack check
- while (ins.Previous != null) { //quick fix for
out parameters.
- ins = ins.Previous;
- StoreSlot last = GetLoadSlot (ins);
- if (last.Type == StoreType.Argument)
- return new StoreSlot
(StoreType.Out, last.Slot);
- }
- goto default;
- default:
- return new StoreSlot (StoreType.None, -1);
- }
- }
- /// <summary>
- /// Checks if an instruction is a store and returns the slot.
- /// </summary>
- /// <param name="ins">The instruction</param>
- /// <returns>If the instruction is a store returns the slot to
store. Check slot.IsNone() to see if this instruction is a store.</returns>
- private StoreSlot GetStoreSlot (Instruction ins)
- {
- switch (ins.OpCode.Code) {
- case Code.Stloc_0:
- return new StoreSlot (StoreType.Local, 0);
- case Code.Stloc_1:
- return new StoreSlot (StoreType.Local, 1);
- case Code.Stloc_2:
- return new StoreSlot (StoreType.Local, 2);
- case Code.Stloc_3:
- return new StoreSlot (StoreType.Local, 3);
- case Code.Stloc_S:
- case Code.Stloc:
- return new StoreSlot (StoreType.Local,
((VariableDefinition) ins.Operand).Index);
-
- case Code.Stfld:
- //TODO: we do not check what instance is on the
stack
- return new StoreSlot (StoreType.Field, (int)
((FieldReference) ins.Operand).MetadataToken.ToUInt ());
- case Code.Stsfld:
- return new StoreSlot (StoreType.StaticField,
(int) ((FieldReference) ins.Operand).MetadataToken.ToUInt ());
-
- case Code.Starg_S: //store arg (not ref / out etc)
- case Code.Starg: {
- int sequence = ((ParameterDefinition)
ins.Operand).Sequence;
- if (!this.Method.HasThis)
- sequence--;
- return new StoreSlot
(StoreType.Argument, sequence);
- }
-
- case Code.Stind_I:
- case Code.Stind_I1:
- case Code.Stind_I2:
- case Code.Stind_I4:
- case Code.Stind_I8:
- case Code.Stind_R4:
- case Code.Stind_R8:
- case Code.Stind_Ref:
- //TODO: improve stack check
- while (ins.Previous != null) { //quick fix for
out parameters.
- ins = ins.Previous;
- StoreSlot last = GetLoadSlot (ins);
- if (last.Type == StoreType.Argument)
- return new StoreSlot
(StoreType.Out, last.Slot);
- }
- goto default;
-
-
-
- default:
- return new StoreSlot (StoreType.None, -1);
- }
- }
-
- private int GetPopCount (Instruction ins)
- {
- switch (ins.OpCode.StackBehaviourPop) {
- case StackBehaviour.Pop0:
- return 0;
-
- case StackBehaviour.Pop1:
- case StackBehaviour.Popi:
- case StackBehaviour.Popref:
- return 1;
-
- case StackBehaviour.Pop1_pop1:
- case StackBehaviour.Popi_pop1:
- case StackBehaviour.Popi_popi8:
- case StackBehaviour.Popi_popr4:
- case StackBehaviour.Popi_popr8:
- case StackBehaviour.Popref_pop1:
- case StackBehaviour.Popref_popi:
- case StackBehaviour.Popi_popi:
- return 2;
-
- case StackBehaviour.Popi_popi_popi:
- case StackBehaviour.Popref_popi_popi:
- case StackBehaviour.Popref_popi_popi8:
- case StackBehaviour.Popref_popi_popr4:
- case StackBehaviour.Popref_popi_popr8:
- case StackBehaviour.Popref_popi_popref:
- return 3;
-
- case StackBehaviour.PopAll:
- goto default;
-
- case StackBehaviour.Varpop:
- switch (ins.OpCode.FlowControl) {
- case FlowControl.Return:
- return
this.Method.ReturnType.ReturnType.FullName == "System.Void" ? 0 : 1;
-
- case FlowControl.Call:
- IMethodSignature calledMethod =
(IMethodSignature) ins.Operand;
- if (ins.OpCode.Code != Code.Newobj)
- if (calledMethod.HasThis)
- return 1 +
calledMethod.Parameters.Count;
- return calledMethod.Parameters.Count;
-
- default:
- throw new NotImplementedException
("Varpop not supported for this Instruction.");
- }
-
- default:
- throw new NotImplementedException
(ins.OpCode.StackBehaviourPop + " not supported.");
- }
- }
-
- private int GetPushCount (Instruction ins)
- {
- switch (ins.OpCode.StackBehaviourPush) {
- case StackBehaviour.Push0:
- return 0;
-
- case StackBehaviour.Push1:
- case StackBehaviour.Pushi:
- case StackBehaviour.Pushi8:
- case StackBehaviour.Pushr4:
- case StackBehaviour.Pushr8:
- case StackBehaviour.Pushref:
- return 1;
-
- case StackBehaviour.Push1_push1:
- return 2;
-
- case StackBehaviour.Varpush:
- if (ins.OpCode.Code == Code.Call ||
ins.OpCode.Code == Code.Calli || ins.OpCode.Code == Code.Callvirt) {
- IMethodSignature calledMethod =
(IMethodSignature) ins.Operand;
- if
(calledMethod.ReturnType.ReturnType.FullName == "System.Void")
- return 0;
- return 1;
- } else {
- throw new NotImplementedException
("Varpush not supported for this Instruction.");
- }
- default:
- throw new NotImplementedException
(ins.OpCode.StackBehaviourPush + " not supported.");
- }
- }
- }
-}
_______________________________________________
Mono-patches maillist - [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches