Skip to content

Commit 23e3d36

Browse files
authored
Add client to count may-alias variable pairs (#149)
1 parent e3eadc9 commit 23e3d36

File tree

3 files changed

+234
-0
lines changed

3 files changed

+234
-0
lines changed
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*
2+
* Tai-e: A Static Analysis Framework for Java
3+
*
4+
* Copyright (C) 2022 Tian Tan <[email protected]>
5+
* Copyright (C) 2022 Yue Li <[email protected]>
6+
*
7+
* This file is part of Tai-e.
8+
*
9+
* Tai-e is free software: you can redistribute it and/or modify
10+
* it under the terms of the GNU Lesser General Public License
11+
* as published by the Free Software Foundation, either version 3
12+
* of the License, or (at your option) any later version.
13+
*
14+
* Tai-e is distributed in the hope that it will be useful,but WITHOUT
15+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16+
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
17+
* Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Lesser General Public
20+
* License along with Tai-e. If not, see <https://www.gnu.org/licenses/>.
21+
*/
22+
23+
package pascal.taie.analysis.pta.client;
24+
25+
import org.apache.logging.log4j.LogManager;
26+
import org.apache.logging.log4j.Logger;
27+
import pascal.taie.World;
28+
import pascal.taie.analysis.ProgramAnalysis;
29+
import pascal.taie.analysis.pta.PointerAnalysis;
30+
import pascal.taie.analysis.pta.PointerAnalysisResult;
31+
import pascal.taie.analysis.pta.core.heap.Obj;
32+
import pascal.taie.config.AnalysisConfig;
33+
import pascal.taie.ir.exp.Var;
34+
import pascal.taie.util.Indexer;
35+
import pascal.taie.util.collection.IndexerBitSet;
36+
import pascal.taie.util.collection.Maps;
37+
import pascal.taie.util.collection.Sets;
38+
39+
import java.util.Collection;
40+
import java.util.Collections;
41+
import java.util.Map;
42+
import java.util.Set;
43+
import java.util.stream.Collectors;
44+
45+
public class MayAliasPair extends ProgramAnalysis<MayAliasPair.MayAliasPairResult> {
46+
47+
private static final Logger logger = LogManager.getLogger(MayAliasPair.class);
48+
49+
public static final String ID = "may-alias-pair";
50+
51+
private PointerAnalysisResult ptaResult;
52+
53+
public MayAliasPair(AnalysisConfig config) {
54+
super(config);
55+
}
56+
57+
@Override
58+
public MayAliasPairResult analyze() {
59+
ptaResult = World.get().getResult(PointerAnalysis.ID);
60+
Set<Var> vars = Sets.newSet(ptaResult.getVars());
61+
Set<Var> appVars = vars.stream()
62+
.filter(MayAliasPair::isApp)
63+
.collect(Collectors.toUnmodifiableSet());
64+
65+
long nAliasPairs = computeMayAliasPairs(vars);
66+
long nVars = vars.size();
67+
68+
long nAppAliasPairs = computeMayAliasPairs(appVars);
69+
long nAppVars = appVars.size();
70+
71+
// Log statistics
72+
logger.info("#{}: found {} in {} variable pairs",
73+
ID, nAliasPairs, (nVars - 1) * nVars / 2);
74+
logger.info("#{}: found {} in {} variable pairs (app)",
75+
ID, nAppAliasPairs, (nAppVars - 1) * nAppVars / 2);
76+
77+
return new MayAliasPairResult(nAliasPairs, nAppAliasPairs);
78+
}
79+
80+
private long computeMayAliasPairs(Set<Var> vars) {
81+
VarIndexer indexer = new VarIndexer(vars);
82+
Map<Obj, Set<Var>> obj2Vars = Maps.newMap();
83+
vars.forEach(v -> {
84+
for (Obj obj : ptaResult.getPointsToSet(v)) {
85+
obj2Vars.computeIfAbsent(obj, k -> indexer.makeIndexerBitSet())
86+
.add(v);
87+
}
88+
});
89+
90+
// mayAlias(u, v) if
91+
// exists o, s.t. in(o, pts(u)) and in(o, pts(v))
92+
long nAliasPairs = vars.parallelStream()
93+
.mapToLong(v -> {
94+
Set<Var> aliasVars = indexer.makeIndexerBitSet();
95+
for (Obj o : ptaResult.getPointsToSet(v)) {
96+
aliasVars.addAll(obj2Vars.getOrDefault(o, Collections.emptySet()));
97+
}
98+
// v may alias to itself, but we do not count in this case
99+
aliasVars.remove(v);
100+
return aliasVars.size();
101+
}).sum();
102+
// mayAlias(u, v) iff mayAlias(v, u), so a pair is counted twice
103+
return nAliasPairs / 2;
104+
}
105+
106+
private static boolean isApp(Var v) {
107+
return v.getMethod().isApplication();
108+
}
109+
110+
public record MayAliasPairResult(long aliasPairs, long appAliasPairs) {
111+
}
112+
113+
// A global indexer for Vars
114+
private static class VarIndexer implements Indexer<Var> {
115+
116+
private static final boolean IS_SPARSE = true;
117+
118+
private final Var[] vars;
119+
120+
private final Map<Var, Integer> varIndexMap = Maps.newMap();
121+
122+
VarIndexer(Collection<Var> vars) {
123+
this.vars = vars.stream()
124+
.distinct()
125+
.toArray(Var[]::new);
126+
for (int index = 0; index < this.vars.length; index++) {
127+
varIndexMap.put(this.vars[index], index);
128+
}
129+
}
130+
131+
public IndexerBitSet<Var> makeIndexerBitSet() {
132+
return new IndexerBitSet<>(this, IS_SPARSE);
133+
}
134+
135+
@Override
136+
public int getIndex(Var o) {
137+
return varIndexMap.get(o);
138+
}
139+
140+
@Override
141+
public Var getObject(int index) {
142+
return vars[index];
143+
}
144+
}
145+
}

src/main/resources/tai-e-analyses.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@
5454
id: poly-call
5555
requires: [ pta ]
5656

57+
- description: identify variable pairs that may alias
58+
analysisClass: pascal.taie.analysis.pta.client.MayAliasPair
59+
id: may-alias-pair
60+
requires: [ pta ]
61+
5762
- description: find modified objects of methods and statements
5863
analysisClass: pascal.taie.analysis.sideeffect.SideEffectAnalysis
5964
id: side-effect
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Tai-e: A Static Analysis Framework for Java
3+
*
4+
* Copyright (C) 2022 Tian Tan <[email protected]>
5+
* Copyright (C) 2022 Yue Li <[email protected]>
6+
*
7+
* This file is part of Tai-e.
8+
*
9+
* Tai-e is free software: you can redistribute it and/or modify
10+
* it under the terms of the GNU Lesser General Public License
11+
* as published by the Free Software Foundation, either version 3
12+
* of the License, or (at your option) any later version.
13+
*
14+
* Tai-e is distributed in the hope that it will be useful,but WITHOUT
15+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16+
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
17+
* Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Lesser General Public
20+
* License along with Tai-e. If not, see <https://www.gnu.org/licenses/>.
21+
*/
22+
23+
24+
package pascal.taie.analysis.pta.client;
25+
26+
import org.junit.jupiter.params.ParameterizedTest;
27+
import org.junit.jupiter.params.provider.ValueSource;
28+
import pascal.taie.Main;
29+
import pascal.taie.World;
30+
import pascal.taie.analysis.pta.PointerAnalysis;
31+
import pascal.taie.analysis.pta.PointerAnalysisResult;
32+
import pascal.taie.ir.exp.Var;
33+
34+
import java.util.List;
35+
36+
import static org.junit.jupiter.api.Assertions.assertEquals;
37+
38+
public class MayAliasPairTest {
39+
static final String DIR = "basic";
40+
41+
@ParameterizedTest
42+
@ValueSource(strings = {
43+
"New",
44+
"Assign",
45+
"StoreLoad",
46+
"Call",
47+
"InstanceField",
48+
"CallParamRet",
49+
"StaticCall",
50+
"MergeParam",
51+
})
52+
void test(String mainClass) {
53+
String ptaTestRoot = "src/test/resources/pta";
54+
String classPath = ptaTestRoot + "/" + DIR;
55+
List<String> args = List.of(
56+
// for loading class PTAAssert
57+
"-cp", ptaTestRoot,
58+
// for loading main class
59+
"-cp", classPath, "-m", mainClass,
60+
"-a", MayAliasPair.ID
61+
);
62+
Main.main(args.toArray(new String[0]));
63+
MayAliasPair.MayAliasPairResult resultByAnalysis = World.get().getResult(MayAliasPair.ID);
64+
long appResultByDefinition = computeByDefinition();
65+
assertEquals(appResultByDefinition, resultByAnalysis.appAliasPairs());
66+
}
67+
68+
private static long computeByDefinition() {
69+
PointerAnalysisResult ptaResult = World.get().getResult(PointerAnalysis.ID);
70+
Var[] appVars = ptaResult.getVars().stream()
71+
.filter(v -> v.getMethod().isApplication())
72+
.toArray(Var[]::new);
73+
long aliasPairs = 0;
74+
for (int i = 0; i < appVars.length; i++) {
75+
for (int j = i + 1; j < appVars.length; j++) {
76+
Var v1 = appVars[i], v2 = appVars[j];
77+
if (ptaResult.mayAlias(v1, v2)) {
78+
aliasPairs++;
79+
}
80+
}
81+
}
82+
return aliasPairs;
83+
}
84+
}

0 commit comments

Comments
 (0)