forked from soot-oss/soot
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathanalysis.tex
More file actions
488 lines (368 loc) · 14.9 KB
/
analysis.tex
File metadata and controls
488 lines (368 loc) · 14.9 KB
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
\documentclass{article}
\usepackage{fullpage}
\usepackage{html}
\usepackage{epsfig}
\title{Using the Soot flow analysis framework}
\author{Patrick Lam (\htmladdnormallink{plam@sable.mcgill.ca)}{mailto:plam@sable.mcgill.ca}}
\date{March 17, 2000}
\begin{document}
\maketitle
Slides from a talk on the Soot flow analysis framework
are at \htmladdnormallink{http://www.sable.mcgill.ca/soot/notes}{http://www.sable.mcgill.ca/soot/notes}.
\section{Goals}
By the end of this lesson, the student should be able to:
\begin{itemize}
\item understand the Soot Flow Analysis class hierarchy
\item use an auxiliary class to package flow analysis results for use
\item use the hooks in Soot to output the results of custom
analyses
\end{itemize}
\section{Flow Sets}
In dataflow analysis, we seek to associate some data with each node
in the control-flow graph. In Soot, we represent this data as flow
sets.
Typically, a flow set represents a set of facts. For reaching
definitions, the flow sets are the sets of pairs (variable, program
point). Soot defines the {\tt FlowSet} interface to be the canonical
flow object.
Soot also provides an implementation of {\tt FlowSet},
{\tt ArraySparseSet}. This represents the {\tt FlowSet} using an
array.
Often, we want a {\tt FlowSet} with complementation; this is a {\tt
BoundedFlowSet}, and implemented by {\tt ArrayPackedSet}. To speak of
complementation, there must be some universe with respect to which we
complement. When the universe is not implicit in the definition of
the flow set itself, then Soot provides the {\tt FlowUniverse} set;
this is used by {\tt ArrayPackedSet}.
The {\tt FlowSet} interface requires the following methods:
\begin{itemize}
\item {\tt clone()}
\item {\tt clear()}
\item {\tt isEmpty()}
\item {\tt copy (FlowSet dest)}
\item {\tt union (FlowSet other, FlowSet dest)}
\item {\tt intersection (FlowSet other, FlowSet dest)}
\item {\tt difference (FlowSet other, FlowSet dest)}
\end{itemize}
The first 3 methods are clear. The {\tt copy()} method
will put the contents of `this' {\tt FlowSet} into the
destination {\tt FlowSet}.
For the last 3 methods, the following rule is used:
\begin{verbatim}
dest <- this op other
\end{verbatim}
Note that these operations give {\tt FlowSet} the necessary
structure to be a lattice element.
Usually, we just need to represent sets for flow analysis. In that
case, the following optional methods are used:
\begin{itemize}
\item {\tt size()}
\item {\tt add (Object obj, FlowSet dest)}
\item {\tt remove (Object obj, FlowSet dest)}
\item {\tt contains (Object obj)}
\item {\tt toList()}
\end{itemize}
The {\tt add()} and {\tt remove} objects use the following rule:
\begin{verbatim}
dest <- this op obj
\end{verbatim}
The reference implementation, {\tt ArraySparseSet}, implements all
of the methods for {\tt FlowSet}.
\section{Graph creation}
In order to do dataflow analysis, a control-flow graph is required.
We will now describe how to create such a graph.
The {\tt SootMethod} and {\tt Body} classes have been described in the
example showing \htmladdnormallink{how to create a class from scratch}
{..//createclass}.
These concepts should now be understood.
Soot provides the {\tt UnitGraph} class to describe the notion of
a control-flow graph. There are two types of {\tt UnitGraphs}:
{\tt ExceptionalUnitGraph} and {\tt BriefUnitGraph}. The exceptional graph
contains all of the edges in the brief graph, plus edges corresponding
to potential exceptions being thrown. It should be used for analysis.
The {\tt UnitGraph} class implements the {\tt DirectedGraph} interface,
which captures the essential features of directed graphs (on {\tt Directed}
objects).
Given a {\tt Body}, say {\tt b}, we can create a {\tt
ExceptionalUnitGraph} by invoking {\tt new ExceptionalUnitGraph(b)}.
\section{Flow Analysis}
Now that we are armed with graphs and flow sets, we can proceed to
carry out the actual analysis.
Soot provides {\tt FlowAnalysis} classes. All we need to plug in are
a flow function, merge, copy, and initial flow sets, and we're all set!
The following abstract methods must be implemented by a {\tt FlowAnalysis}:
\begin{description}
\item{{\tt newInitialFlow()}:} return the initial value for {\tt FlowSet}s in
the graph.
e.g. ``{\tt return emptySet.clone();}''
\item{{\tt customizeInitialFlowGraph()}:} overriding {\tt
customizeInitialFlowGraph()} will permit the user to give different
flow sets to different graph nodes. This method can adjust anything it
needs to; it is called at the end of the constructor for {\tt
Analysis}. For instance, an all-paths analysis will often make the
initial objects the full set, except at the start.
\item{{\tt merge(inSet1, inSet2, outSet)}:} combine two {\tt FlowSet}s to produce
an out-{\tt FlowSet}.
e.g. ``{\tt inSet1.union(inSet2, outSet);}''
\item{{\tt copy(sourceSet, destSet)}:} put the source into the destination.
e.g. ``{\tt sourceSet.copy(destSet);}''
\item{{\tt flowThrough(inSet, s, outSet)}:} given {\tt inSet} and {\tt s}, put
the correct OUT value into the {\tt outSet}.
If we have pre-computed the gen and preserve sets, this code could implement
{\tt flowThrough()}:
\begin{verbatim}
inSet.intersection(unitToPreserveSet.get(s), outSet);
outSet.union(unitToGenerateSet.get(s), outSet);
\end{verbatim}
\end{description}
In appendix \ref{simpleAnalysis} we show a complete example of a simple
analysis, for detecting live locals.
\subsection{Pre-computing gen and preserve Sets}
We made a passing reference to pre-computing sets in the above.
Often, in a flow analysis, the flow-through function is actually quite
simple:
\[\mbox{OUT}(s) = \mbox{IN}(s) \cup \mbox{gen}(s) \cap \mbox{prsv}(s) \]
In such a case, we can pre-compute the gen and preserve sets in the
constructor. Hopefully, this speeds up the analysis.
We illustrate the pre-computation of a preserve set for live locals:
\begin{verbatim}
Unit s = (Unit) unitIt.next();
BoundedFlowSet killSet = emptySet.clone();
Iterator boxIt = s.getDefBoxes().iterator();
while(boxIt.hasNext())
{
ValueBox box = (ValueBox) boxIt.next();
if(box.getValue() instanceof Local)
killSet.add(box.getValue(), killSet);
}
// Store complement
killSet.complement(killSet);
unitToPreserveSet.put(s, killSet);
\end{verbatim}
Note that all {\tt Unit} objects provide a {\tt getDefBoxes}
method. This returns a list of values defined in the {\tt Unit}.
In order to compute the {\tt gen} sets, we use {\tt getUseBoxes} instead;
it is a fairly simple change.
\section{Packaging Flow Analyses}
Typically, we don't want to provide access to the underlying Analysis
classes. For instance, we would much rather pass around {\tt List}s of
live locals, rather than {\tt FlowSet}s; we can make the {\tt List}s
unmodifiable, while we're at it!
In order to do that, we wrap the {\tt Analysis} object. After running the
Analysis, we run through the units and map the {\tt Unit}s in question
to {\tt List}s of results. Then, we can provide accessor methods:
\begin{verbatim}
List lla = liveLocals.getLiveLocalsAfter(s);
\end{verbatim}
An example wrapper is in appendix \ref{simpleAnalysisWrapper}.
We now have clean access to the analysis results.
\section{Transforming Jimple}
Often, we want to transform all of the {\tt JimpleBody} objects for a
program. This can be done, first, by creating a {\tt BodyTransformer}
object.
\begin{verbatim}
public class NaiveCommonSubexpressionEliminator extends BodyTransformer
{
private static NaiveCommonSubexpressionEliminator instance =
new NaiveCommonSubexpressionEliminator();
private NaiveCommonSubexpressionEliminator() {}
public static NaiveCommonSubexpressionEliminator v() { return instance; }
/** Common subexpression eliminator. */
protected void internalTransform(Body b, String phaseName, Map options)
{
\end{verbatim}
The most important part of this class is the {\tt internalTransform}
method. It carries out the work of the transformer. There are also
{\em declared} options -- those that the transformer claims to understand;
and {\em default} options.
The code fragment above also has code to provide a singleton object,
so that we may refer to the common subexpression eliminator as
{\tt NaiveCommonSubexpressionEliminator.v()}, which is a Java object.
Once we have done this, we want to ensure that the transformation
is triggered at the appropriate times. Soot runs a number of {\tt Pack}s
at different stages of its execution; they are built in the {\tt PackManager}'s
constructor. One notable {\tt Pack} is the Jimple transformation pack
({\tt jtp}); the user may wish to add transformations to this pack:
\begin{verbatim}
PackManager.v().getPack("jtp").add(
new Transform("jtp.gotoinstrumenter", GotoInstrumenter.v()));
\end{verbatim}
The {\tt Transform} object just keeps track of the pair (phase name,
transformation object). Phases are described in more detail in the
\htmladdnormallink{document about phase
options}{http://www.sable.mcgill.ca/soot/tutorial/phase}.
\section{Extending Soot}
The approved way of extending Soot is to provide a {\tt Main} class file
in a custom package, say {\tt plam.Main}. This class can make adjustments
to the {\tt Pack}s contained in the PackManager, for instance adding a
goto instrumentor:
\begin{verbatim}
public static void main(String[] args)
{
if(args.length == 0)
{
System.out.println("Syntax: java "+
"soot.examples.instrumentclass.Main --app mainClass "+
"[soot options]");
System.exit(0);
}
PackManager.v().getPack("jtp").add(
new Transform("jtp.gotoinstrumenter", GotoInstrumenter.v()));
soot.Main.main(args);
}
\end{verbatim}
\section{Conclusions}
In this lesson, we have described the Soot flow analysis framework,
described how to write a Body transformer, and how to integrate all of
this into the Soot framework.
\section{History}
\begin{itemize}
\item March 17, 2000: Initial version.
\item May 31, 2003: Initial version.
\end{itemize}
\appendix
\section*{Simple Live Locals Analysis}
\label{simpleAnalysis}
% this should be a real appendix. Unfortunately I don't know how to
% do it!
\begin{verbatim}
/* Soot - a J*va Optimization Framework
* Copyright (C) 1997-1999 Raja Vallee-Rai
*
* Licensed under LGPL. */
package soot.toolkits.scalar;
import soot.*;
import soot.util.*;
import java.util.*;
import soot.jimple.*;
import soot.toolkits.graph.*;
class SimpleLiveLocalsAnalysis extends BackwardFlowAnalysis
{
FlowSet emptySet;
Map unitToGenerateSet;
Map unitToPreserveSet;
protected Object newInitialFlow()
{
return emptySet.clone();
}
protected void flowThrough(Object inValue, Directed unit, Object outValue)
{
FlowSet in = (FlowSet) inValue, out = (FlowSet) outValue;
// Perform kill
in.intersection((FlowSet) unitToPreserveSet.get(unit), out);
// Perform generation
out.union((FlowSet) unitToGenerateSet.get(unit), out);
}
protected void merge(Object in1, Object in2, Object out)
{
FlowSet inSet1 = (FlowSet) in1,
inSet2 = (FlowSet) in2;
FlowSet outSet = (FlowSet) out;
inSet1.union(inSet2, outSet);
}
protected void copy(Object source, Object dest)
{
FlowSet sourceSet = (FlowSet) source,
destSet = (FlowSet) dest;
sourceSet.copy(destSet);
}
SimpleLiveLocalsAnalysis(UnitGraph g)
{
super(g);
// Generate list of locals and empty set
{
Chain locals = g.getBody().getLocals();
FlowUniverse localUniverse = new FlowUniverse(locals.toArray());
emptySet = new ArrayPackedSet(localUniverse);
}
// Create preserve sets.
{
unitToPreserveSet = new HashMap(g.size() * 2 + 1, 0.7f);
Iterator unitIt = g.iterator();
while(unitIt.hasNext())
{
Unit s = (Unit) unitIt.next();
BoundedFlowSet killSet = (BoundedFlowSet) emptySet.clone();
Iterator boxIt = s.getDefBoxes().iterator();
while(boxIt.hasNext())
{
ValueBox box = (ValueBox) boxIt.next();
if(box.getValue() instanceof Local)
killSet.add(box.getValue(), killSet);
}
// Store complement
killSet.complement(killSet);
unitToPreserveSet.put(s, killSet);
}
}
// Create generate sets
{
unitToGenerateSet = new HashMap(g.size() * 2 + 1, 0.7f);
Iterator unitIt = g.iterator();
while(unitIt.hasNext())
{
Unit s = (Unit) unitIt.next();
FlowSet genSet = (FlowSet) emptySet.clone();
Iterator boxIt = s.getUseBoxes().iterator();
while(boxIt.hasNext())
{
ValueBox box = (ValueBox) boxIt.next();
if(box.getValue() instanceof Local)
genSet.add(box.getValue(), genSet);
}
unitToGenerateSet.put(s, genSet);
}
}
doAnalysis();
}
}
\end{verbatim}
\section{Simple Live Locals Analysis Wrapper}
\label{simpleAnalysisWrapper}
\begin{verbatim}
/* Soot - a J*va Optimization Framework
* Copyright (C) 1997-1999 Raja Vallee-Rai
*
* Licensed under LGPL. */
package soot.toolkits.scalar;
import soot.*;
import soot.util.*;
import java.util.*;
import soot.jimple.*;
import soot.toolkits.graph.*;
/** Wrapper for Analysis class. */
public class SimpleLiveLocals implements LiveLocals
{
Map unitToLocalsAfter;
Map unitToLocalsBefore;
public SimpleLiveLocals(ExceptionalUnitGraph graph)
{
SimpleLiveLocalsAnalysis analysis = new SimpleLiveLocalsAnalysis(graph);
// Build unitToLocals map
{
unitToLocalsAfter = new HashMap(graph.size() * 2 + 1, 0.7f);
unitToLocalsBefore = new HashMap(graph.size() * 2 + 1, 0.7f);
Iterator unitIt = graph.iterator();
while(unitIt.hasNext())
{
Unit s = (Unit) unitIt.next();
FlowSet set = (FlowSet) analysis.getFlowBefore(s);
unitToLocalsBefore.put(s,
Collections.unmodifiableList(set.toList()));
set = (FlowSet) analysis.getFlowAfter(s);
unitToLocalsAfter.put(s,
Collections.unmodifiableList(set.toList()));
}
}
}
public List getLiveLocalsAfter(Unit s)
{
return (List) unitToLocalsAfter.get(s);
}
public List getLiveLocalsBefore(Unit s)
{
return (List) unitToLocalsBefore.get(s);
}
}
\end{verbatim}
\end{document}