michael@0: #!/usr/bin/python michael@0: michael@0: import re michael@0: import argparse michael@0: michael@0: parser = argparse.ArgumentParser(description='Process some integers.') michael@0: parser.add_argument('rootingHazards', nargs='?', default='rootingHazards.txt') michael@0: parser.add_argument('gcFunctions', nargs='?', default='gcFunctions.txt') michael@0: parser.add_argument('hazards', nargs='?', default='hazards.txt') michael@0: parser.add_argument('extra', nargs='?', default='unnecessary.txt') michael@0: parser.add_argument('refs', nargs='?', default='refs.txt') michael@0: args = parser.parse_args() michael@0: michael@0: num_hazards = 0 michael@0: num_refs = 0 michael@0: try: michael@0: with open(args.rootingHazards) as rootingHazards, \ michael@0: open(args.hazards, 'w') as hazards, \ michael@0: open(args.extra, 'w') as extra, \ michael@0: open(args.refs, 'w') as refs: michael@0: current_gcFunction = None michael@0: michael@0: # Map from a GC function name to the list of hazards resulting from michael@0: # that GC function michael@0: hazardousGCFunctions = {} michael@0: michael@0: # List of tuples (gcFunction, index of hazard) used to maintain the michael@0: # ordering of the hazards michael@0: hazardOrder = [] michael@0: michael@0: for line in rootingHazards: michael@0: m = re.match(r'^Time: (.*)', line) michael@0: mm = re.match(r'^Run on:', line) michael@0: if m or mm: michael@0: print >>hazards, line michael@0: print >>extra, line michael@0: print >>refs, line michael@0: continue michael@0: michael@0: m = re.match(r'^Function.*has unnecessary root', line) michael@0: if m: michael@0: print >>extra, line michael@0: continue michael@0: michael@0: m = re.match(r'^Function.*takes unsafe address of unrooted', line) michael@0: if m: michael@0: num_refs += 1 michael@0: print >>refs, line michael@0: continue michael@0: michael@0: m = re.match(r"^Function.*has unrooted.*of type.*live across GC call ('?)(.*?)('?) at \S+:\d+$", line) michael@0: if m: michael@0: # Function names are surrounded by single quotes. Field calls michael@0: # are unquoted. michael@0: current_gcFunction = m.group(2) michael@0: hazardousGCFunctions.setdefault(current_gcFunction, []).append(line) michael@0: hazardOrder.append((current_gcFunction, len(hazardousGCFunctions[current_gcFunction]) - 1)) michael@0: num_hazards += 1 michael@0: continue michael@0: michael@0: if current_gcFunction: michael@0: if not line.strip(): michael@0: # Blank line => end of this hazard michael@0: current_gcFunction = None michael@0: else: michael@0: hazardousGCFunctions[current_gcFunction][-1] += line michael@0: michael@0: with open(args.gcFunctions) as gcFunctions: michael@0: gcExplanations = {} # gcFunction => stack showing why it can GC michael@0: michael@0: current_func = None michael@0: explanation = None michael@0: for line in gcFunctions: michael@0: m = re.match(r'^GC Function: (.*)', line) michael@0: if m: michael@0: if current_func: michael@0: gcExplanations[current_func] = explanation michael@0: current_func = None michael@0: if m.group(1) in hazardousGCFunctions: michael@0: current_func = m.group(1) michael@0: explanation = line michael@0: elif current_func: michael@0: explanation += line michael@0: if current_func: michael@0: gcExplanations[current_func] = explanation michael@0: michael@0: for gcFunction, index in hazardOrder: michael@0: gcHazards = hazardousGCFunctions[gcFunction] michael@0: if gcFunction in gcExplanations: michael@0: print >>hazards, (gcHazards[index] + gcExplanations[gcFunction]) michael@0: else: michael@0: print >>hazards, gcHazards[index] michael@0: michael@0: except IOError as e: michael@0: print 'Failed: %s' % str(e) michael@0: michael@0: print("Wrote %s" % args.hazards) michael@0: print("Wrote %s" % args.extra) michael@0: print("Wrote %s" % args.refs) michael@0: print("Found %d hazards and %d unsafe references" % (num_hazards, num_refs))