internal static bool AreEquivalent(Instruction source, Instruction target) { if (source.OpCode.Code != target.OpCode.Code) return false; if (source.OpCode.Code == Code.Ldstr) return true; //Check the types in ldarg stuff. Sometimes this scheme //could lead us to false positives. We need an analysis //which depends on the context. if (source.IsLoadArgument ()) { // case where 'ldarg this' is used (p.GetSequence () would be 0) if (!Current.HasParameters && !Target.HasParameters) return true; return AreEquivalent (source.GetParameter (Current), target.GetParameter (Target)); } // The same for ldloc / stloc if (source.IsLoadLocal () || source.IsStoreLocal ()) return AreEquivalent (source.GetVariable (Current), target.GetVariable (Target)); //WARNING: Dirty Evil Hack: this should be in the //Pattern class if (source.OpCode.Code == Code.Ret && source.Previous != null && (source.Previous.OpCode.StackBehaviourPush == StackBehaviour.Pushi || source.Previous.OpCode.Code == Code.Ldnull || source.Previous.OpCode.StackBehaviourPush == StackBehaviour.Push1)) return false; //if (source.Operand != target.Operand) if (source.Operand != null && target.Operand != null) { // we're sure that target.Operand is of the same type as source.Operand (same OpCode is used) Instruction si = (source.Operand as Instruction); if (si != null) return (si.Offset == ((Instruction) target.Operand).Offset); IMetadataTokenProvider sm = (source.Operand as IMetadataTokenProvider); if (sm != null) return sm.Equals (target.Operand as IMetadataTokenProvider); if (source.Operand == target.Operand) return true; // last chance: we do call ToString if (source.Operand.ToString () != target.Operand.ToString ()) return false; } return true; }
static bool OriginsMatch (MethodDefinition method, Instruction lhs, Instruction rhs) { bool match = false; object operand1 = lhs.GetOperand (method); object operand2 = rhs.GetOperand (method); if (lhs.OpCode.Code == rhs.OpCode.Code) { if (lhs.IsLoadArgument ()) match = operand1.Equals (operand2); else if (lhs.IsLoadElement ()) match = LoadElementMatch (method, lhs, rhs); else if (lhs.IsLoadIndirect ()) match = LoadIndirectMatch (method, lhs, rhs); else if (lhs.IsLoadLocal ()) match = LocalsMatch (operand1, operand2); } else if (lhs.IsStoreLocal () && rhs.IsLoadLocal ()) match = LocalsMatch (operand1, operand2); else if (lhs.IsLoadLocal () && rhs.IsStoreLocal ()) match = LocalsMatch (operand1, operand2); return match; }
private static Instruction StoreLoadLocal (MethodDefinition method, Instruction ins) { // check for a STLOC followed by a LDLOC if (!ins.IsLoadLocal () || !ins.Previous.IsStoreLocal ()) return null; // make sure it's about the same local variable if (ins.GetVariable (method) != ins.Previous.GetVariable (method)) return null; return ins.Previous.Previous; }
private static bool CheckParameters (MethodDefinition method, Instruction ins) { Instruction prev; if (ins.IsLoadLocal ()) { prev = ins.Previous; while (null != prev) { // look for a STLOC* instruction and compare the variable indexes if (prev.IsStoreLocal () && AreMirrorInstructions (ins, prev, method)) return IsGetNow (prev.Previous); prev = prev.Previous; } } else if (ins.OpCode.Code == Code.Ldobj) { prev = ins.TraceBack (method); ParameterDefinition p = prev.GetParameter (method); if (p == null) return false; int arg = p.GetSequence (); prev = prev.Previous; while (null != prev) { // look for a STOBJ instruction and compare the objects if (prev.OpCode.Code == Code.Stobj) { prev = prev.TraceBack (method); p = prev.GetParameter (method); return (p == null) ? false : (arg == p.GetSequence ()); } prev = prev.Previous; } } else { return IsGetNow (ins); } return false; }
void CheckForOutParameters (MethodDefinition method, Instruction ins) { Instruction iref = ins.TraceBack (method); if (iref == null) return; ParameterDefinition p = iref.GetParameter (method); if ((p != null) && p.IsOut) { ins = ins.Previous; if (ins.IsLoadLocal ()) Clear (method, ins); } }
void CheckForReturn (MethodDefinition method, Instruction ins) { if (ins.IsLoadLocal ()) Clear (method, ins); }
private void Apply(Instruction instruction, Stack<Value> stack, ICollection<Value> values, IList<Value> locals) { // TODO: this method is a mess and needs to be refactored!! var pushCount = instruction.GetPushCount(); var popCount = instruction.GetPopCount(_method); if (popCount == Int32.MaxValue) popCount = stack.Count; var isCall = instruction.OpCode.FlowControl == FlowControl.Call; var callParams = isCall ? (instruction.Operand as MethodReference).Parameters : NoParams; // List of all popped values var poppedValues = new List<Value>(); var inputArguments = new List<Value>(); for (var i = 0; i < popCount; i++) { // Instruction is a consumer var value = stack.Pop(); poppedValues.Add(value); // If we popped a value for an out parameter, we're not a consumer! // Note that the first pop returns the last argument. if (isCall && i < callParams.Count && callParams[callParams.Count - i - 1].IsOut) { inputArguments.Insert(0, null); // empty slot continue; } value.Consumer = instruction; inputArguments.Insert(0, value); //TODO: not 'this'!?!? } int storeIndex; if (instruction.IsStoreLocal(out storeIndex)) { Debug.Assert(popCount == 1); locals[storeIndex] = poppedValues[0]; } for (var i = 0; i < pushCount; i++) { Value newValue; // Instruction is a producer int loadIndex; if (instruction.IsLoadLocal(out loadIndex)) { Debug.Assert(pushCount == 1); newValue = new Value(instruction); values.Add(newValue); // The local value can be null if we're passing loading a reference // destined for an out parameter. Note that we can get a non-null // value as well, so we have to sort things out when we handle the // call to the method with the out parameter. var localValue = locals[loadIndex]; if (localValue != null) { newValue.AddParents(new[] { localValue }); } } else { newValue = new Value(instruction); values.Add(newValue); newValue.AddParents(inputArguments.Where(a => a != null)); } stack.Push(newValue); } if (isCall) { var argValues = new Value[callParams.Count]; for (var i = 0; i < argValues.Length; i++) { argValues[i] = poppedValues[argValues.Length - i - 1]; } for (var i = 0; i < callParams.Count; i++) { // First of poppedValues is last argument var inputArgument = poppedValues[callParams.Count - i - 1]; if (!callParams[i].IsRef() && !callParams[i].IsOut) continue; var newValue = new Value(instruction); var storeAtIndex = (inputArgument.Producer.Operand as VariableDefinition).Index; // Add all input values (including any refs) as parents! for (var j = 0; j < callParams.Count; j++) { if (callParams[j].IsOut) continue; newValue.AddParents(new[] { argValues[j] }); } // Don't push onto the stack, but save the value and store // it in the locals array. values.Add(newValue); locals[storeAtIndex] = newValue; } } }
static Instruction LocalTraceBack (IMethodSignature method, Instruction ins) { ins = ins.TraceBack (method); while (ins != null) { if (ins.IsLoadLocal () || ins.IsStoreLocal ()) return ins; ins = ins.TraceBack (method); } return null; }