private MergePointValue(ValueNode one, ValueNode two) { Kind = ValueNodeKind.MergePoint; m_values = new ValueNodeHashSet(); if (one.Kind == ValueNodeKind.MergePoint) { MergePointValue mpvOne = (MergePointValue)one; foreach (ValueNode value in mpvOne.Values) { m_values.Add(value); } } else { m_values.Add(one); } if (two.Kind == ValueNodeKind.MergePoint) { MergePointValue mpvTwo = (MergePointValue)two; foreach (ValueNode value in mpvTwo.Values) { m_values.Add(value); } } else { m_values.Add(two); } }
public override bool Equals(ValueNode other) { if (other == null) { return(false); } if (this.Kind != other.Kind) { return(false); } MergePointValue otherMpv = (MergePointValue)other; if (this.Values.Count != otherMpv.Values.Count) { return(false); } foreach (ValueNode value in this.Values) { if (!otherMpv.Values.Contains(value)) { return(false); } } return(true); }
private static void StoreMethodLocalValue <KeyType> ( Dictionary <KeyType, ValueBasicBlockPair> valueCollection, ValueNode valueToStore, KeyType collectionKey, int curBasicBlock) { ValueBasicBlockPair newValue = new ValueBasicBlockPair { BasicBlockIndex = curBasicBlock }; ValueBasicBlockPair existingValue; if (valueCollection.TryGetValue(collectionKey, out existingValue) && existingValue.BasicBlockIndex == curBasicBlock) { // If the previous value was stored in the current basic block, then we can safely // overwrite the previous value with the new one. newValue.Value = valueToStore; } else { // If the previous value came from a previous basic block, then some other use of // the local could see the previous value, so we must merge the new value with the // old value. newValue.Value = MergePointValue.MergeValues(existingValue.Value, valueToStore); } valueCollection[collectionKey] = newValue; }
private static StackSlot MergeStackElement(StackSlot a, StackSlot b) { StackSlot mergedSlot; if (b.Value == null) { mergedSlot = a; } else if (a.Value == null) { mergedSlot = b; } else { mergedSlot = new StackSlot(MergePointValue.MergeValues(a.Value, b.Value)); } return(mergedSlot); }
private static void StoreMethodLocalValue <KeyType> ( Dictionary <KeyType, ValueBasicBlockPair> valueCollection, ValueNode?valueToStore, KeyType collectionKey, int curBasicBlock, int?maxTrackedValues = null) where KeyType : notnull { ValueBasicBlockPair newValue = new ValueBasicBlockPair { BasicBlockIndex = curBasicBlock }; ValueBasicBlockPair existingValue; if (valueCollection.TryGetValue(collectionKey, out existingValue)) { if (existingValue.BasicBlockIndex == curBasicBlock) { // If the previous value was stored in the current basic block, then we can safely // overwrite the previous value with the new one. newValue.Value = valueToStore; } else { // If the previous value came from a previous basic block, then some other use of // the local could see the previous value, so we must merge the new value with the // old value. newValue.Value = MergePointValue.MergeValues(existingValue.Value, valueToStore); } valueCollection[collectionKey] = newValue; } else if (maxTrackedValues == null || valueCollection.Count < maxTrackedValues) { // We're not currently tracking a value a this index, so store the value now. newValue.Value = valueToStore; valueCollection[collectionKey] = newValue; } }
public void Scan(MethodBody methodBody) { MethodDefinition thisMethod = methodBody.Method; Dictionary <VariableDefinition, ValueBasicBlockPair> locals = new Dictionary <VariableDefinition, ValueBasicBlockPair> (methodBody.Variables.Count); Dictionary <int, Stack <StackSlot> > knownStacks = new Dictionary <int, Stack <StackSlot> > (); Stack <StackSlot> currentStack = new Stack <StackSlot> (methodBody.MaxStackSize); ScanExceptionInformation(knownStacks, methodBody); BasicBlockIterator blockIterator = new BasicBlockIterator(methodBody); MethodReturnValue = null; foreach (Instruction operation in methodBody.Instructions) { int curBasicBlock = blockIterator.MoveNext(operation); if (knownStacks.ContainsKey(operation.Offset)) { if (currentStack == null) { // The stack copy constructor reverses the stack currentStack = new Stack <StackSlot> (knownStacks[operation.Offset].Reverse()); } else { currentStack = MergeStack(currentStack, knownStacks[operation.Offset]); } } if (currentStack == null) { currentStack = new Stack <StackSlot> (methodBody.MaxStackSize); } switch (operation.OpCode.Code) { case Code.Add: case Code.Add_Ovf: case Code.Add_Ovf_Un: case Code.And: case Code.Div: case Code.Div_Un: case Code.Mul: case Code.Mul_Ovf: case Code.Mul_Ovf_Un: case Code.Or: case Code.Rem: case Code.Rem_Un: case Code.Sub: case Code.Sub_Ovf: case Code.Sub_Ovf_Un: case Code.Xor: case Code.Cgt: case Code.Cgt_Un: case Code.Clt: case Code.Clt_Un: case Code.Shl: case Code.Shr: case Code.Shr_Un: case Code.Ceq: PopUnknown(currentStack, 2, methodBody, operation.Offset); PushUnknown(currentStack); break; case Code.Dup: currentStack.Push(currentStack.Peek()); break; case Code.Ldnull: currentStack.Push(new StackSlot(NullValue.Instance)); break; case Code.Ldc_I4_0: case Code.Ldc_I4_1: case Code.Ldc_I4_2: case Code.Ldc_I4_3: case Code.Ldc_I4_4: case Code.Ldc_I4_5: case Code.Ldc_I4_6: case Code.Ldc_I4_7: case Code.Ldc_I4_8: { int value = operation.OpCode.Code - Code.Ldc_I4_0; ConstIntValue civ = new ConstIntValue(value); StackSlot slot = new StackSlot(civ); currentStack.Push(slot); } break; case Code.Ldc_I4_M1: { ConstIntValue civ = new ConstIntValue(-1); StackSlot slot = new StackSlot(civ); currentStack.Push(slot); } break; case Code.Ldc_I4: { int value = (int)operation.Operand; ConstIntValue civ = new ConstIntValue(value); StackSlot slot = new StackSlot(civ); currentStack.Push(slot); } break; case Code.Ldc_I4_S: { int value = (sbyte)operation.Operand; ConstIntValue civ = new ConstIntValue(value); StackSlot slot = new StackSlot(civ); currentStack.Push(slot); } break; case Code.Arglist: case Code.Ldftn: case Code.Sizeof: case Code.Ldc_I8: case Code.Ldc_R4: case Code.Ldc_R8: PushUnknown(currentStack); break; case Code.Ldarg: case Code.Ldarg_0: case Code.Ldarg_1: case Code.Ldarg_2: case Code.Ldarg_3: case Code.Ldarg_S: case Code.Ldarga: case Code.Ldarga_S: ScanLdarg(operation, currentStack, thisMethod, methodBody); break; case Code.Ldloc: case Code.Ldloc_0: case Code.Ldloc_1: case Code.Ldloc_2: case Code.Ldloc_3: case Code.Ldloc_S: case Code.Ldloca: case Code.Ldloca_S: ScanLdloc(operation, currentStack, methodBody, locals); break; case Code.Ldstr: { StackSlot slot = new StackSlot(new KnownStringValue((string)operation.Operand)); currentStack.Push(slot); } break; case Code.Ldtoken: ScanLdtoken(operation, currentStack); break; 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_U1: case Code.Ldind_U2: case Code.Ldind_U4: case Code.Ldlen: case Code.Ldvirtftn: case Code.Localloc: case Code.Refanytype: case Code.Refanyval: case Code.Conv_I1: case Code.Conv_I2: case Code.Conv_I4: case Code.Conv_Ovf_I1: case Code.Conv_Ovf_I1_Un: case Code.Conv_Ovf_I2: case Code.Conv_Ovf_I2_Un: case Code.Conv_Ovf_I4: case Code.Conv_Ovf_I4_Un: case Code.Conv_Ovf_U: case Code.Conv_Ovf_U_Un: case Code.Conv_Ovf_U1: case Code.Conv_Ovf_U1_Un: case Code.Conv_Ovf_U2: case Code.Conv_Ovf_U2_Un: case Code.Conv_Ovf_U4: case Code.Conv_Ovf_U4_Un: case Code.Conv_U1: case Code.Conv_U2: case Code.Conv_U4: case Code.Conv_I8: case Code.Conv_Ovf_I8: case Code.Conv_Ovf_I8_Un: case Code.Conv_Ovf_U8: case Code.Conv_Ovf_U8_Un: case Code.Conv_U8: case Code.Conv_I: case Code.Conv_Ovf_I: case Code.Conv_Ovf_I_Un: case Code.Conv_U: case Code.Conv_R_Un: case Code.Conv_R4: case Code.Conv_R8: case Code.Ldind_Ref: case Code.Ldobj: case Code.Mkrefany: case Code.Unbox: case Code.Unbox_Any: case Code.Box: case Code.Neg: case Code.Not: PopUnknown(currentStack, 1, methodBody, operation.Offset); PushUnknown(currentStack); break; case Code.Isinst: case Code.Castclass: // We can consider a NOP because the value doesn't change. // It might change to NULL, but for the purposes of dataflow analysis // it doesn't hurt much. break; case Code.Ldfld: case Code.Ldsfld: case Code.Ldflda: case Code.Ldsflda: ScanLdfld(operation, currentStack, thisMethod, methodBody); break; case Code.Newarr: { StackSlot count = PopUnknown(currentStack, 1, methodBody, operation.Offset); currentStack.Push(new StackSlot(new ArrayValue(count.Value, (TypeReference)operation.Operand))); } break; case Code.Stelem_I: case Code.Stelem_I1: case Code.Stelem_I2: case Code.Stelem_I4: case Code.Stelem_I8: case Code.Stelem_R4: case Code.Stelem_R8: case Code.Stelem_Any: case Code.Stelem_Ref: ScanStelem(operation, currentStack, methodBody, curBasicBlock); break; case Code.Ldelem_I: case Code.Ldelem_I1: case Code.Ldelem_I2: case Code.Ldelem_I4: case Code.Ldelem_I8: case Code.Ldelem_R4: case Code.Ldelem_R8: case Code.Ldelem_U1: case Code.Ldelem_U2: case Code.Ldelem_U4: case Code.Ldelem_Any: case Code.Ldelem_Ref: case Code.Ldelema: ScanLdelem(operation, currentStack, methodBody, curBasicBlock); break; case Code.Cpblk: case Code.Initblk: PopUnknown(currentStack, 3, methodBody, operation.Offset); break; case Code.Stfld: case Code.Stsfld: ScanStfld(operation, currentStack, thisMethod, methodBody); break; case Code.Cpobj: PopUnknown(currentStack, 2, methodBody, operation.Offset); break; 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: case Code.Stobj: ScanIndirectStore(operation, currentStack, methodBody); break; case Code.Initobj: case Code.Pop: PopUnknown(currentStack, 1, methodBody, operation.Offset); break; case Code.Starg: case Code.Starg_S: ScanStarg(operation, currentStack, thisMethod, methodBody); break; case Code.Stloc: case Code.Stloc_S: case Code.Stloc_0: case Code.Stloc_1: case Code.Stloc_2: case Code.Stloc_3: ScanStloc(operation, currentStack, methodBody, locals, curBasicBlock); break; case Code.Constrained: case Code.No: case Code.Readonly: case Code.Tail: case Code.Unaligned: case Code.Volatile: break; case Code.Brfalse: case Code.Brfalse_S: case Code.Brtrue: case Code.Brtrue_S: PopUnknown(currentStack, 1, methodBody, operation.Offset); NewKnownStack(knownStacks, ((Instruction)operation.Operand).Offset, currentStack); break; case Code.Calli: { var signature = (CallSite)operation.Operand; if (signature.HasThis && !signature.ExplicitThis) { PopUnknown(currentStack, 1, methodBody, operation.Offset); } // Pop arguments PopUnknown(currentStack, signature.Parameters.Count, methodBody, operation.Offset); // Pop function pointer PopUnknown(currentStack, 1, methodBody, operation.Offset); // Push return value if (signature.ReturnType.MetadataType != MetadataType.Void) { PushUnknown(currentStack); } } break; case Code.Call: case Code.Callvirt: case Code.Newobj: HandleCall(methodBody, operation, currentStack, curBasicBlock); break; case Code.Jmp: // Not generated by mainstream compilers break; case Code.Br: case Code.Br_S: NewKnownStack(knownStacks, ((Instruction)operation.Operand).Offset, currentStack); ClearStack(ref currentStack); break; case Code.Leave: case Code.Leave_S: ClearStack(ref currentStack); NewKnownStack(knownStacks, ((Instruction)operation.Operand).Offset, new Stack <StackSlot> (methodBody.MaxStackSize)); break; case Code.Endfilter: case Code.Endfinally: case Code.Rethrow: case Code.Throw: ClearStack(ref currentStack); break; case Code.Ret: { bool hasReturnValue = methodBody.Method.ReturnType.MetadataType != MetadataType.Void; if (currentStack.Count != (hasReturnValue ? 1 : 0)) { WarnAboutInvalidILInMethod(methodBody, operation.Offset); } if (hasReturnValue) { StackSlot retValue = PopUnknown(currentStack, 1, methodBody, operation.Offset); MethodReturnValue = MergePointValue.MergeValues(MethodReturnValue, retValue.Value); } ClearStack(ref currentStack); break; } case Code.Switch: { PopUnknown(currentStack, 1, methodBody, operation.Offset); Instruction[] targets = (Instruction[])operation.Operand; foreach (Instruction target in targets) { NewKnownStack(knownStacks, target.Offset, currentStack); } break; } case Code.Beq: case Code.Beq_S: case Code.Bne_Un: case Code.Bne_Un_S: case Code.Bge: case Code.Bge_S: case Code.Bge_Un: case Code.Bge_Un_S: case Code.Bgt: case Code.Bgt_S: case Code.Bgt_Un: case Code.Bgt_Un_S: case Code.Ble: case Code.Ble_S: case Code.Ble_Un: case Code.Ble_Un_S: case Code.Blt: case Code.Blt_S: case Code.Blt_Un: case Code.Blt_Un_S: PopUnknown(currentStack, 2, methodBody, operation.Offset); NewKnownStack(knownStacks, ((Instruction)operation.Operand).Offset, currentStack); break; } } }