def build_instrumentation_point_graphs(program : Program): instrumentation_point_graphs = {} depth_first_search_tree = DepthFirstSearch(program.call_graph, program.call_graph.root_function, False) # Traverse call graph in reverse topological order for call_vertex in depth_first_search_tree.post_order: verbose_message("Analysing function '{}'".format(call_vertex.name), __name__) caller_ipg = InstrumentationPointGraph.instrument_as_per_user_instruction\ (program[call_vertex.name]) instrumentation_point_graphs[call_vertex.name] = caller_ipg # Process every call made by this function for call_edge in call_vertex.successor_edge_iterator(): callee_vertex = program.call_graph.get_vertex(call_edge.vertex_id) verbose_message("@ callee {}".format(callee_vertex.name), __name__) callee_ipg = instrumentation_point_graphs[callee_vertex.name] # Grab each instrumentation point from the callee that may be executed # first when the function begins entry_sign_posts = [] if not callee_ipg.entry_vertex.abstract: entry_sign_posts.append(callee_ipg.entry_vertex) else: for succ_edge in callee_ipg.entry_vertex.successor_edge_iterator(): entry_sign_posts.append(callee_ipg.get_vertex(succ_edge.vertex_id)) # Grab each instrumentation point from the callee that may be executed # last before the function returns exit_sign_posts = [] if not callee_ipg.exit_vertex.abstract: exit_sign_posts.append(callee_ipg.exit_vertex) else: for pred_edge in callee_ipg.exit_vertex.predecessor_edge_iterator(): exit_sign_posts.append(callee_ipg.get_vertex(pred_edge.vertex_id)) for call_site in call_edge.call_sites: verbose_message("@ call site {}".format(call_site), __name__) # Inline the sign posts to callee entry inlined_entry_program_points = set() for vertex in entry_sign_posts: vertex_copy = ProgramPointVertex(caller_ipg.get_new_vertex_id(), vertex.program_point, abstract=True) inlined_entry_program_points.add(vertex_copy) caller_ipg.add_vertex(vertex_copy) # Inline the sign posts to callee exit inlined_exit_program_points = set() for vertex in exit_sign_posts: vertex_copy = ProgramPointVertex(caller_ipg.get_new_vertex_id(), vertex.program_point, abstract=True) inlined_exit_program_points.add(vertex_copy) caller_ipg.add_vertex(vertex_copy) # Link the inlined instrumentation points for pred_vertex in inlined_entry_program_points: for succ_vertex in inlined_exit_program_points: caller_ipg.add_edge(pred_vertex, succ_vertex, None) # Relink the call site vertex edges_to_purge = set() call_site_vertex = caller_ipg.get_vertex_for_program_point(call_site) for pred_vertex in inlined_exit_program_points: for redundant_succ_edge in call_site_vertex.successor_edge_iterator(): succ_vertex = caller_ipg.get_vertex(redundant_succ_edge.vertex_id) caller_ipg.add_edge(pred_vertex, succ_vertex, None) edges_to_purge.add((call_site_vertex, succ_vertex)) if redundant_succ_edge.backedge: pred_edge = succ_vertex.get_predecessor_edge(pred_vertex.vertex_id) succ_edge = pred_vertex.get_successor_edge(succ_vertex.vertex_id) pred_edge.backedge = True succ_edge.backedge = True for edge in edges_to_purge: caller_ipg.remove_edge(*edge) for succ_vertex in inlined_entry_program_points: caller_ipg.add_edge(call_site_vertex, succ_vertex, None) dot.make_file(caller_ipg) return instrumentation_point_graphs