'Computes the diff of the functions and saves the result.'

def _compute_diff(self):

    l.debug('Computing    diff    of    functions:    %s,    %s', (('%#x' % self._function_a.startpoint.addr) if (self._function_a.startpoint is not None) else 'None'), (('%#x' % self._function_b.startpoint.addr) if (self._function_b.startpoint is not None) else 'None'))
    self.attributes_a = self._compute_block_attributes(self._function_a)
    self.attributes_b = self._compute_block_attributes(self._function_b)
    initial_matches = self._get_block_matches(self.attributes_a, self.attributes_b, tiebreak_with_block_similarity=False)
    to_process = deque(initial_matches)
    processed_matches = set(((x, y) for (x, y) in initial_matches))
    matched_a = dict()
    matched_b = dict()
    for (x, y) in processed_matches:
        matched_a[x] = y
        matched_b[y] = x
    while to_process:
        (block_a, block_b) = to_process.pop()
        l.debug('FunctionDiff:    Processing    (%#x,    %#x)', block_a.addr, block_b.addr)
        block_a_succ = self._function_a.graph.successors(block_a)
        block_b_succ = self._function_b.graph.successors(block_b)
        block_a_pred = self._function_a.graph.predecessors(block_a)
        block_b_pred = self._function_b.graph.predecessors(block_b)
        delta = tuple(((i - j) for (i, j) in zip(self.attributes_b[block_b], self.attributes_a[block_a])))
        new_matches = []
        if (self.blocks_probably_identical(block_a, block_b) and (len(block_a_succ) == len(block_b_succ))):
            ordered_succ_a = self._get_ordered_successors(self._project_a, block_a, block_a_succ)
            ordered_succ_b = self._get_ordered_successors(self._project_b, block_b, block_b_succ)
            new_matches += zip(ordered_succ_a, ordered_succ_b)
        new_matches += self._get_block_matches(self.attributes_a, self.attributes_b, block_a_succ, block_b_succ, delta, tiebreak_with_block_similarity=True)
        new_matches += self._get_block_matches(self.attributes_a, self.attributes_b, block_a_pred, block_b_pred, delta, tiebreak_with_block_similarity=True)
        for (x, y) in new_matches:
            if ((x, y) not in processed_matches):
                processed_matches.add((x, y))
                l.debug('FunctionDiff:    checking    if    (%#x,    %#x)    is    better', x.addr, y.addr)
                if _is_better_match(x, y, matched_a, matched_b, self.attributes_a, self.attributes_b):
                    l.debug('FunctionDiff:    adding    possible    match    (%#x,    %#x)', x.addr, y.addr)
                    if (x in matched_a):
                        old_match = matched_a[x]
                        del matched_b[old_match]
                    if (y in matched_b):
                        old_match = matched_b[y]
                        del matched_a[old_match]
                    matched_a[x] = y
                    matched_b[y] = x
                    to_process.appendleft((x, y))
    self._block_matches = set(((x, y) for (x, y) in matched_a.items()))
    self._unmatched_blocks_from_a = set((x for x in self._function_a.graph.nodes() if (x not in matched_a)))
    self._unmatched_blocks_from_b = set((x for x in self._function_b.graph.nodes() if (x not in matched_b)))
