-
Notifications
You must be signed in to change notification settings - Fork 0
/
loadCallgraph.js
120 lines (105 loc) · 3.38 KB
/
loadCallgraph.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/* -*- Mode: Javascript; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
"use strict";
var calleeGraph = {};
var callerGraph = {};
var gcFunctions = {};
var suppressedFunctions = {};
function addGCFunction(caller, reason)
{
if (caller in suppressedFunctions)
return false;
if (ignoreGCFunction(caller))
return false;
if (!(caller in gcFunctions)) {
gcFunctions[caller] = reason;
return true;
}
return false;
}
function addCallEdge(caller, callee, suppressed)
{
if (!(caller in calleeGraph))
calleeGraph[caller] = [];
calleeGraph[caller].push({callee:callee, suppressed:suppressed});
if (!(callee in callerGraph))
callerGraph[callee] = [];
callerGraph[callee].push({caller:caller, suppressed:suppressed});
}
var functionNames = [""];
function loadCallgraph(file)
{
var textLines = snarf(file).split('\n');
for (var line of textLines) {
var match;
if (match = /^\#(\d+) (.*)/.exec(line)) {
assert(functionNames.length == match[1]);
functionNames.push(match[2]);
continue;
}
var suppressed = false;
if (/SUPPRESS_GC/.test(line)) {
match = /^(..)SUPPRESS_GC (.*)/.exec(line);
line = match[1] + match[2];
suppressed = true;
}
if (match = /^I (\d+) VARIABLE ([^\,]*)/.exec(line)) {
var caller = functionNames[match[1]];
var name = match[2];
if (!indirectCallCannotGC(caller, name) && !suppressed)
addGCFunction(caller, "IndirectCall: " + name);
} else if (match = /^F (\d+) CLASS (.*?) FIELD (.*)/.exec(line)) {
var caller = functionNames[match[1]];
var csu = match[2];
var field = match[3];
if (!fieldCallCannotGC(csu, field) && !suppressed)
addGCFunction(caller, "FieldCall: " + csu + "." + field);
} else if (match = /^D (\d+) (\d+)/.exec(line)) {
var caller = functionNames[match[1]];
var callee = functionNames[match[2]];
addCallEdge(caller, callee, suppressed);
}
}
var worklist = [];
for (var name in callerGraph)
suppressedFunctions[name] = true;
for (var name in calleeGraph) {
if (!(name in callerGraph)) {
suppressedFunctions[name] = true;
worklist.push(name);
}
}
while (worklist.length) {
name = worklist.pop();
if (shouldSuppressGC(name))
continue;
if (!(name in suppressedFunctions))
continue;
delete suppressedFunctions[name];
if (!(name in calleeGraph))
continue;
for (var entry of calleeGraph[name]) {
if (!entry.suppressed)
worklist.push(entry.callee);
}
}
for (var name in gcFunctions) {
if (name in suppressedFunctions)
delete gcFunctions[name];
}
var gcName = 'void js::GC(JSRuntime*, uint32, uint32)';
assert(gcName in callerGraph);
addGCFunction(gcName, "GC");
var worklist = [];
for (var name in gcFunctions)
worklist.push(name);
while (worklist.length) {
name = worklist.pop();
assert(name in gcFunctions);
if (!(name in callerGraph))
continue;
for (var entry of callerGraph[name]) {
if (!entry.suppressed && addGCFunction(entry.caller, name))
worklist.push(entry.caller);
}
}
}