1#
2# Copyright (C) 2016 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#      http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16
17
18class ArcSummary(object):
19    """Summarizes an arc from a .gcno file.
20
21    Attributes:
22        src_block_index: integer index of the source basic block.
23        dstBlockIndex: integer index of the destination basic block.
24        on_tree: True iff arc has flag GCOV_ARC_ON_TREE.
25        fake: True iff arc has flag GCOV_ARC_FAKE.
26        fallthrough: True iff arc has flag GCOV_ARC_FALLTHROUGH.
27        resolved: True iff the arc's count has been resolved.
28        count: Integer number of times the arc was covered.
29    """
30
31    GCOV_ARC_ON_TREE = 1
32    GCOV_ARC_FAKE = 1 << 1
33    GCOV_ARC_FALLTHROUGH = 1 << 2
34
35    def __init__(self, src_block, dst_block, flag):
36        """Inits the arc summary with provided values.
37
38        Stores the source and destination block indices and parses
39        the arc flag.
40
41        Args:
42            src_block: BlockSummary of source block.
43            dst_block: BlockSummary of destination block.
44            flag: integer flag for the given arc.
45        """
46
47        self.src_block = src_block
48        self.dst_block = dst_block
49        self.on_tree = bool(flag & self.GCOV_ARC_ON_TREE)
50        self.fake = bool(flag & self.GCOV_ARC_FAKE)
51        self.fallthrough = bool(flag & self.GCOV_ARC_FALLTHROUGH)
52        self.resolved = False
53        self.count = 0
54
55    def Resolve(self):
56        """Resolves the arc count and returns True if successful.
57
58        Uses the property that the sum of counts of arcs entering a
59        node is equal to the sum of counts of arcs leaving a node. The
60        exception to this rule is fake non-fallthrough nodes, which have
61        no exit edges. In this case, remove the arc as an exit arc from
62        the source so that the source can be resolved.
63
64        Returns:
65            True if the arc could be resolved and False otherwise.
66        """
67        if self.fake and not self.fallthrough:
68            try:
69                self.src_block.exit_arcs.remove(self)
70            except ValueError:
71                pass
72        elif (len(self.src_block.entry_arcs) > 0 and
73              all(a.resolved for a in self.src_block.entry_arcs) and
74              all(a.resolved for a in self.src_block.exit_arcs if a != self)):
75            in_flow = sum(a.count for a in self.src_block.entry_arcs)
76            out_flow = sum(a.count for a in self.src_block.exit_arcs
77                           if a != self)
78            self.count = in_flow - out_flow
79            self.resolved = True
80        elif (len(self.dst_block.exit_arcs) > 0 and
81              all(a.resolved for a in self.dst_block.exit_arcs) and
82              all(a.resolved for a in self.dst_block.entry_arcs if a != self)):
83            out_flow = sum(a.count for a in self.dst_block.exit_arcs)
84            in_flow = sum(a.count for a in self.dst_block.entry_arcs
85                          if a != self)
86            self.count = out_flow - in_flow
87            self.resolved = True
88        else:
89            return False
90        return True
91