static HandlerState?GetNextHandlerState(ref FindHandlerState findState)
        {
            for (int i = 0; i < findState.CompositeState.BlockSigInfos.Count; i++)
            {
                if (findState.VisitedCompositeBlocks.ContainsKey(i))
                {
                    continue;
                }
                return(new HandlerState(findState.CompositeState.BlockSigInfos, i, 0));
            }

            return(null);
        }
        MethodSigInfo FindHandlerMethod(ref FindHandlerState findExecState)
        {
            foreach (var handler in handlers)
            {
                var findExecStateNew = findExecState.Clone();
                if (!Matches(handler.BlockSigInfos, ref findExecStateNew))
                {
                    continue;
                }

                findExecState = findExecStateNew;
                return(handler);
            }
            return(null);
        }
        OpCodeHandler FindHandlerMethod(ref FindHandlerState findExecState)
        {
            foreach (var handler in handlers)
            {
                FindHandlerState findExecStateNew = findExecState.Clone();
                if (!Matches(handler.ExecMethod, ref findExecStateNew))
                {
                    continue;
                }

                findExecState = findExecStateNew;
                return(handler);
            }
            return(null);
        }
        public bool FindHandlers(CompositeOpCodeHandler composite)
        {
            composite.TypeCodes.Clear();
            var compositeExecState = new FindHandlerState(new HandlerState(composite.BlockSigInfos, 0, 0));

            while (!compositeExecState.Done)
            {
                var handler = FindHandlerMethod(ref compositeExecState);
                if (handler == null)
                {
                    return(false);
                }

                composite.TypeCodes.Add(handler.TypeCode);
            }
            return(composite.TypeCodes.Count != 0);
        }
		public bool FindHandlers(CompositeOpCodeHandler composite) {
			composite.TypeCodes.Clear();
			var compositeExecState = new FindHandlerState(new HandlerState(composite.BlockSigInfos, 0, 0));
			while (!compositeExecState.Done) {
				var handler = FindHandlerMethod(ref compositeExecState);
				if (handler == null)
					return false;

				composite.TypeCodes.Add(handler.TypeCode);
			}
			return composite.TypeCodes.Count != 0;
		}
		static HandlerState? GetNextHandlerState(ref FindHandlerState findState) {
			for (int i = 0; i < findState.CompositeState.BlockSigInfos.Count; i++) {
				if (findState.VisitedCompositeBlocks.ContainsKey(i))
					continue;
				return new HandlerState(findState.CompositeState.BlockSigInfos, i, 0);
			}

			return null;
		}
		bool Matches(List<BlockSigInfo> handler, ref FindHandlerState findState) {
			HandlerState? nextState = null;
			stack.Clear();
			stack.Push(new MatchState(new HandlerState(handler, 0, 0), findState.CompositeState));
			while (stack.Count > 0) {
				var matchState = stack.Pop();

				if (matchState.CompositeState.HashIndex == 0) {
					if (findState.VisitedCompositeBlocks.ContainsKey(matchState.CompositeState.BlockIndex))
						continue;
					findState.VisitedCompositeBlocks[matchState.CompositeState.BlockIndex] = true;
				}
				else {
					if (!findState.VisitedCompositeBlocks.ContainsKey(matchState.CompositeState.BlockIndex))
						throw new ApplicationException("Block hasn't been visited");
				}

				if (!Compare(ref matchState.OtherState, ref matchState.CompositeState))
					return false;

				var hblock = matchState.OtherState.BlockSigInfos[matchState.OtherState.BlockIndex];
				var hinstrs = hblock.Hashes;
				int hi = matchState.OtherState.HashIndex;
				var cblock = matchState.CompositeState.BlockSigInfos[matchState.CompositeState.BlockIndex];
				var cinstrs = cblock.Hashes;
				int ci = matchState.CompositeState.HashIndex;
				if (hi < hinstrs.Count)
					return false;

				if (ci < cinstrs.Count) {
					if (hblock.Targets.Count != 0)
						return false;
					if (hblock.EndsInRet) {
						if (nextState != null)
							return false;
						nextState = matchState.CompositeState;
					}
				}
				else {
					if (cblock.Targets.Count != hblock.Targets.Count)
						return false;
					if (cblock.HasFallThrough != hblock.HasFallThrough)
						return false;

					for (int i = 0; i < cblock.Targets.Count; i++) {
						var hs = new HandlerState(handler, hblock.Targets[i], 0);
						var cs = new HandlerState(findState.CompositeState.BlockSigInfos, cblock.Targets[i], 0);
						stack.Push(new MatchState(hs, cs));
					}
				}
			}

			if (nextState == null && findState.VisitedCompositeBlocks.Count != findState.CompositeState.BlockSigInfos.Count)
				nextState = GetNextHandlerState(ref findState);
			if (nextState == null) {
				if (findState.VisitedCompositeBlocks.Count != findState.CompositeState.BlockSigInfos.Count)
					return false;
				findState.Done = true;
				return true;
			}
			else {
				if (findState.CompositeState.BlockIndex == nextState.Value.BlockIndex &&
					findState.CompositeState.HashIndex == nextState.Value.HashIndex)
					return false;
				findState.CompositeState = nextState.Value;
				if (findState.CompositeState.HashIndex == 0)
					findState.VisitedCompositeBlocks.Remove(findState.CompositeState.BlockIndex);
				return true;
			}
		}
		MethodSigInfo FindHandlerMethod(ref FindHandlerState findExecState) {
			foreach (var handler in handlers) {
				FindHandlerState findExecStateNew = findExecState.Clone();
				if (!Matches(handler.BlockSigInfos, ref findExecStateNew))
					continue;

				findExecState = findExecStateNew;
				return handler;
			}
			return null;
		}
        bool Matches(List <BlockSigInfo> handler, ref FindHandlerState findState)
        {
            HandlerState?nextState = null;

            stack.Clear();
            stack.Push(new MatchState(new HandlerState(handler, 0, 0), findState.CompositeState));
            while (stack.Count > 0)
            {
                var matchState = stack.Pop();

                if (matchState.CompositeState.HashIndex == 0)
                {
                    if (findState.VisitedCompositeBlocks.ContainsKey(matchState.CompositeState.BlockIndex))
                    {
                        continue;
                    }
                    findState.VisitedCompositeBlocks[matchState.CompositeState.BlockIndex] = true;
                }
                else
                {
                    if (!findState.VisitedCompositeBlocks.ContainsKey(matchState.CompositeState.BlockIndex))
                    {
                        throw new ApplicationException("Block hasn't been visited");
                    }
                }

                if (!Compare(ref matchState.OtherState, ref matchState.CompositeState))
                {
                    return(false);
                }

                var hblock  = matchState.OtherState.BlockSigInfos[matchState.OtherState.BlockIndex];
                var hinstrs = hblock.Hashes;
                int hi      = matchState.OtherState.HashIndex;
                var cblock  = matchState.CompositeState.BlockSigInfos[matchState.CompositeState.BlockIndex];
                var cinstrs = cblock.Hashes;
                int ci      = matchState.CompositeState.HashIndex;
                if (hi < hinstrs.Count)
                {
                    return(false);
                }

                if (ci < cinstrs.Count)
                {
                    if (hblock.Targets.Count != 0)
                    {
                        return(false);
                    }
                    if (hblock.EndsInRet)
                    {
                        if (nextState != null)
                        {
                            return(false);
                        }
                        nextState = matchState.CompositeState;
                    }
                }
                else
                {
                    if (cblock.Targets.Count != hblock.Targets.Count)
                    {
                        return(false);
                    }
                    if (cblock.HasFallThrough != hblock.HasFallThrough)
                    {
                        return(false);
                    }

                    for (int i = 0; i < cblock.Targets.Count; i++)
                    {
                        var hs = new HandlerState(handler, hblock.Targets[i], 0);
                        var cs = new HandlerState(findState.CompositeState.BlockSigInfos, cblock.Targets[i], 0);
                        stack.Push(new MatchState(hs, cs));
                    }
                }
            }

            if (nextState == null && findState.VisitedCompositeBlocks.Count != findState.CompositeState.BlockSigInfos.Count)
            {
                nextState = GetNextHandlerState(ref findState);
            }
            if (nextState == null)
            {
                if (findState.VisitedCompositeBlocks.Count != findState.CompositeState.BlockSigInfos.Count)
                {
                    return(false);
                }
                findState.Done = true;
                return(true);
            }
            else
            {
                if (findState.CompositeState.BlockIndex == nextState.Value.BlockIndex &&
                    findState.CompositeState.HashIndex == nextState.Value.HashIndex)
                {
                    return(false);
                }
                findState.CompositeState = nextState.Value;
                if (findState.CompositeState.HashIndex == 0)
                {
                    findState.VisitedCompositeBlocks.Remove(findState.CompositeState.BlockIndex);
                }
                return(true);
            }
        }
		bool Matches(HandlerMethod handler, ref FindHandlerState findState) {
			HandlerState? nextState = null;
			stack.Clear();
			stack.Push(new MatchState(new HandlerState(handler, 0, 0), findState.CompositeState));
			while (stack.Count > 0) {
				var matchState = stack.Pop();

				if (matchState.CompositeState.InstructionIndex == 0) {
					if (findState.VisitedCompositeBlocks.ContainsKey(matchState.CompositeState.BlockIndex))
						continue;
					findState.VisitedCompositeBlocks[matchState.CompositeState.BlockIndex] = true;
				}
				else {
					if (!findState.VisitedCompositeBlocks.ContainsKey(matchState.CompositeState.BlockIndex))
						throw new ApplicationException("Block hasn't been visited");
				}

				if (!Compare(ref matchState.OtherState, ref matchState.CompositeState))
					return false;

				var hblock = matchState.OtherState.Blocks[matchState.OtherState.BlockIndex];
				var hinstrs = hblock.Instructions;
				int hi = matchState.OtherState.InstructionIndex;
				var cblock = matchState.CompositeState.Blocks[matchState.CompositeState.BlockIndex];
				var cinstrs = cblock.Instructions;
				int ci = matchState.CompositeState.InstructionIndex;
				if (hi < hinstrs.Count)
					return false;

				if (ci < cinstrs.Count) {
					if (hblock.CountTargets() != 0)
						return false;
					if (hblock.LastInstr.OpCode.Code == Code.Ret) {
						if (nextState != null)
							return false;
						nextState = matchState.CompositeState;
					}
				}
				else {
					if (cblock.CountTargets() != hblock.CountTargets())
						return false;
					if (cblock.FallThrough != null || hblock.FallThrough != null) {
						if (cblock.FallThrough == null || hblock.FallThrough == null)
							return false;

						var hs = CreateHandlerState(handler, matchState.OtherState.Blocks, hblock.FallThrough);
						var cs = CreateHandlerState(findState.CompositeState.HandlerMethod, findState.CompositeState.Blocks, cblock.FallThrough);
						stack.Push(new MatchState(hs, cs));
					}
					if (cblock.Targets != null || hblock.Targets != null) {
						if (cblock.Targets == null || hblock.Targets == null ||
							cblock.Targets.Count != hblock.Targets.Count)
							return false;

						for (int i = 0; i < cblock.Targets.Count; i++) {
							var hs = CreateHandlerState(handler, matchState.OtherState.Blocks, hblock.Targets[i]);
							var cs = CreateHandlerState(findState.CompositeState.HandlerMethod, findState.CompositeState.Blocks, cblock.Targets[i]);
							stack.Push(new MatchState(hs, cs));
						}
					}
				}
			}

			if (nextState == null) {
				findState.Done = true;
				return true;
			}
			else {
				if (findState.CompositeState.BlockIndex == nextState.Value.BlockIndex &&
					findState.CompositeState.InstructionIndex == nextState.Value.InstructionIndex)
					return false;
				findState.CompositeState = nextState.Value;
				return true;
			}
		}
		OpCodeHandler FindHandlerMethod(ref FindHandlerState findExecState) {
			foreach (var handler in handlers) {
				FindHandlerState findExecStateNew = findExecState.Clone();
				if (!Matches(handler.ExecMethod, ref findExecStateNew))
					continue;

				findExecState = findExecStateNew;
				return handler;
			}
			return null;
		}
        bool Matches(HandlerMethod handler, ref FindHandlerState findState)
        {
            HandlerState?nextState = null;

            stack.Clear();
            stack.Push(new MatchState(new HandlerState(handler, 0, 0), findState.CompositeState));
            while (stack.Count > 0)
            {
                var matchState = stack.Pop();

                if (matchState.CompositeState.InstructionIndex == 0)
                {
                    if (findState.VisitedCompositeBlocks.ContainsKey(matchState.CompositeState.BlockIndex))
                    {
                        continue;
                    }
                    findState.VisitedCompositeBlocks[matchState.CompositeState.BlockIndex] = true;
                }
                else
                {
                    if (!findState.VisitedCompositeBlocks.ContainsKey(matchState.CompositeState.BlockIndex))
                    {
                        throw new ApplicationException("Block hasn't been visited");
                    }
                }

                if (!Compare(ref matchState.OtherState, ref matchState.CompositeState))
                {
                    return(false);
                }

                var hblock  = matchState.OtherState.Blocks[matchState.OtherState.BlockIndex];
                var hinstrs = hblock.Instructions;
                int hi      = matchState.OtherState.InstructionIndex;
                var cblock  = matchState.CompositeState.Blocks[matchState.CompositeState.BlockIndex];
                var cinstrs = cblock.Instructions;
                int ci      = matchState.CompositeState.InstructionIndex;
                if (hi < hinstrs.Count)
                {
                    return(false);
                }

                if (ci < cinstrs.Count)
                {
                    if (hblock.CountTargets() != 0)
                    {
                        return(false);
                    }
                    if (hblock.LastInstr.OpCode.Code == Code.Ret)
                    {
                        if (nextState != null)
                        {
                            return(false);
                        }
                        nextState = matchState.CompositeState;
                    }
                }
                else
                {
                    if (cblock.CountTargets() != hblock.CountTargets())
                    {
                        return(false);
                    }
                    if (cblock.FallThrough != null || hblock.FallThrough != null)
                    {
                        if (cblock.FallThrough == null || hblock.FallThrough == null)
                        {
                            return(false);
                        }

                        var hs = CreateHandlerState(handler, matchState.OtherState.Blocks, hblock.FallThrough);
                        var cs = CreateHandlerState(findState.CompositeState.HandlerMethod, findState.CompositeState.Blocks, cblock.FallThrough);
                        stack.Push(new MatchState(hs, cs));
                    }
                    if (cblock.Targets != null || hblock.Targets != null)
                    {
                        if (cblock.Targets == null || hblock.Targets == null ||
                            cblock.Targets.Count != hblock.Targets.Count)
                        {
                            return(false);
                        }

                        for (int i = 0; i < cblock.Targets.Count; i++)
                        {
                            var hs = CreateHandlerState(handler, matchState.OtherState.Blocks, hblock.Targets[i]);
                            var cs = CreateHandlerState(findState.CompositeState.HandlerMethod, findState.CompositeState.Blocks, cblock.Targets[i]);
                            stack.Push(new MatchState(hs, cs));
                        }
                    }
                }
            }

            if (nextState == null)
            {
                findState.Done = true;
                return(true);
            }
            else
            {
                if (findState.CompositeState.BlockIndex == nextState.Value.BlockIndex &&
                    findState.CompositeState.InstructionIndex == nextState.Value.InstructionIndex)
                {
                    return(false);
                }
                findState.CompositeState = nextState.Value;
                return(true);
            }
        }