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