'Merges together the appropriate execution points and unstashes them from the intermidiate merge_x_y stashes to
pruned (dropped), deadend or active stashes
param SimulationManager manager:        current simulation context being stepped through
param [(int, int)] merge_points: list of address and loop counters of execution points to merge
returns SimulationManager:              new manager with edited stashes'

def _join_merge_points(self, manager, merge_points):

    merged_anything = False
    for (merge_point_addr, merge_point_looping_times) in merge_points:
        if merged_anything:
            break
        stash_name = ('_merge_%x_%d' % (merge_point_addr, merge_point_looping_times))
        if (stash_name not in manager.stashes):
            continue
        stash_size = len(manager.stashes[stash_name])
        if (stash_size == 0):
            continue
        if (stash_size == 1):
            l.info('Skipping    merge    of    1    state    in    stash    %s.', stash_size)
            manager.move(stash_name, 'active')
            continue
        l.info('Merging    %d    states    in    stash    %s', stash_size, stash_name)
        manager.prune(from_stash=stash_name, to_stash='pruned')
        if (('pruned' in manager.stashes) and len(manager.pruned)):
            l.debug('...    pruned    %d    paths    from    stash    %s', len(manager.pruned), stash_name)
        manager.drop(stash='pruned')
        while len(manager.stashes[stash_name]):
            r = manager.stashes[stash_name][0]
            manager.move(stash_name, 'merge_tmp', (lambda p: (p.callstack == r.callstack)))
            old_count = len(manager.merge_tmp)
            l.debug('...    trying    to    merge    %d    states.', old_count)
            new_loop_ctrs = defaultdict(int)
            for m in manager.merge_tmp:
                for (head_addr, looping_times) in m.globals['loop_ctrs'].iteritems():
                    new_loop_ctrs[head_addr] = max(looping_times, m.globals['loop_ctrs'][head_addr])
            manager.merge(stash='merge_tmp')
            for m in manager.merge_tmp:
                m.globals['loop_ctrs'] = new_loop_ctrs
            new_count = len(manager.stashes['merge_tmp'])
            l.debug('...    after    merge:    %d    states.', new_count)
            merged_anything |= (new_count != old_count)
            if (len(manager.merge_tmp) > 1):
                l.warning('More    than    1    state    after    Veritesting    merge.')
                manager.move('merge_tmp', 'active')
            elif any(((loop_ctr >= (self._loop_unrolling_limit + 1)) for loop_ctr in manager.one_merge_tmp.globals['loop_ctrs'].itervalues())):
                l.debug('...    merged    state    is    overlooping')
                manager.move('merge_tmp', 'deadended')
            else:
                l.debug('...    merged    state    going    to    active    stash')
                manager.move('merge_tmp', 'active')
    return manager
