/// <summary>
        /// Follows the instructions until the specified stack entry is accessed.
        /// </summary>
        /// <param name="startInstruction">The first instruction.</param>
        /// <param name="stackEntryDistance">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  = ins.GetPopCount(this.Method);
                int push = ins.GetPushCount();

                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;
            }
        }
        /// <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 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 List <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 (ins != null)
                {
                    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.
                    IList <ExceptionHandler> ehc = null;
                    if (Body.HasExceptionHandlers)
                    {
                        ehc = Body.ExceptionHandlers;
                        foreach (ExceptionHandler handler in ehc)
                        {
                            if (handler.HandlerType != 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;
                        if (ehc != null)
                        {
                            foreach (ExceptionHandler handler in ehc)
                            {
                                if (handler.HandlerType != 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);
        }