Skip to content

Commit

Permalink
minimize changed to consider not only compare(a,b) == 1 but also -1
Browse files Browse the repository at this point in the history
results, this allows us to only check half of the matrix (tgs x tgs)
  • Loading branch information
jpstotz committed Mar 22, 2024
1 parent 8eb6edb commit f6f5cd1
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 44 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package soot.jimple.toolkits.typing.fast;

import java.util.ArrayList;

/*-
* #%L
* Soot - a J*va Optimization Framework
Expand Down Expand Up @@ -29,6 +31,11 @@
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import soot.Local;
import soot.RefType;
Expand All @@ -42,9 +49,13 @@
* The default typing strategy
*/
public class DefaultTypingStrategy implements ITypingStrategy {
private static final Logger logger = LoggerFactory.getLogger(DefaultTypingStrategy.class);

public static final ITypingStrategy INSTANCE = new DefaultTypingStrategy();

public static boolean MINIMIZING_ENABLED = true;
public static int USE_PARALLEL_MINIMIZE_IF_ENTRIES_MORE_THAN = 1000;

@Override
public Typing createTyping(Chain<Local> locals) {
return new Typing(locals);
Expand Down Expand Up @@ -81,18 +92,54 @@ public static Set<Local> getObjectLikeTypings(List<Typing> tgs) {

@Override
public void minimize(List<Typing> tgs, IHierarchy h) {
if (!MINIMIZING_ENABLED) {
return;
}

if (tgs.size() > USE_PARALLEL_MINIMIZE_IF_ENTRIES_MORE_THAN) {
minimizeParallel(tgs, h);
return;
}

minimizeSequential(tgs, h);
}

public void minimizeSequential(List<Typing> tgs, IHierarchy h) {
// int count = 0;
// int tgsSize = tgs.size();
Set<Local> objectVars = getObjectLikeTypings(tgs);
OUTER: for (ListIterator<Typing> i = tgs.listIterator(); i.hasNext();) {
Typing tgi = i.next();
// count++;
// if (count % 500 == 0) {
// logger.info("{} of {} = {}%", count, tgsSize, 100f * count / tgsSize);
// }
if (tgi == null) {
// element is marked to be deleted, here we can finally remove it
i.remove();
continue;
}

// Throw out duplicate typings
for (Typing tgj : tgs) {
// if compare = 1, then tgi is the more general typing
// We shouldn't pick that one as we would then end up
// with lots of locals typed to Serializable etc.
if (tgi != tgj && compare(tgi, tgj, h, objectVars) == 1) {
ListIterator<Typing> j = tgs.listIterator(i.nextIndex());
while (j.hasNext()) {
Typing tgj = j.next();
if (tgj == null) {
continue; // element is marked to be deleted
}
int comp = compare(tgi, tgj, h, objectVars);
if (comp == 1) {
// if compare = 1, then tgi is the more general typing
// We shouldn't pick that one as we would then end up
// with lots of locals typed to Serializable etc.
i.remove();
continue OUTER;
} else if (comp == -1) {
// if compare == -1, then tgj is the more general typing
// Set it to null as workaround for marking it as deleted.
// We can not remove the element here as this would cause a
// ConcurrentModificationException in the outer list iterator.
j.set(null);
}
}
}
Expand All @@ -109,15 +156,17 @@ public int compare(Typing a, Typing b, IHierarchy h, Collection<Local> localsToI
cmp = 0;
} else if (h.ancestor(ta, tb)) {
cmp = 1;
if (r == -1) {
return 2;
}
} else if (h.ancestor(tb, ta)) {
cmp = -1;
if (r == 1) {
return 2;
}
} else {
return -2;
}

if ((cmp == 1 && r == -1) || (cmp == -1 && r == 1)) {
return 2;
}
if (r == 0) {
r = cmp;
}
Expand All @@ -126,6 +175,63 @@ public int compare(Typing a, Typing b, IHierarchy h, Collection<Local> localsToI
return r;
}

public void minimizeParallel(List<Typing> tgs, IHierarchy h) {
logger.debug("Performing parallel minimization");
Set<Local> objectVars = getObjectLikeTypings(tgs);

// We don't know what type of list we get, we need a list that is thread safe for get/set
// values. (get could return stale values, but this would not cause harm)
ArrayList<Typing> workList = new ArrayList<>(tgs);
final AtomicInteger processed = new AtomicInteger();
final int tgsSize = tgs.size();

// We iterate over the list using the list item index.
// This way we have something like a parallel list iterator.
// The only disadvantage is that we can not delete items from the list.
// As workaround we replace those entries with a null value (mark them for deletion).
IntStream.range(0, tgsSize).parallel().forEach(i -> {
int count = processed.incrementAndGet();
if (count % 1000 == 0) {
logger.debug("minimizing {} = {}%", count, (100f * count) / tgsSize);
}
Typing tgi = workList.get(i);
if (tgi == null) {
return;
}
ListIterator<Typing> j = workList.listIterator(i + 1);
while (j.hasNext()) {
Typing tgj = j.next();
if (tgj == null) {
continue;
}
int comp = compare(tgi, tgj, h, objectVars);
if (comp == 1) {
// if compare = 1, then tgi is the more general typing
// We shouldn't pick that one as we would then end up
// with lots of locals typed to Serializable etc.
// Set it to null as workaround for marking it as deleted.
workList.set(i, null);
return;
} else if (comp == -1) {
// if compare == -1, then tgj is the more general typing
// Set it to null as workaround for marking it as deleted.
j.set(null);
}
}
});
// remove all null entries (entries marked for deletion)
for (int i = tgsSize - 1; i >= 0; i--) {
if (workList.get(i) == null) {
tgs.remove(i);
}
}

int diff = tgsSize - tgs.size();
if (diff > 0) {
logger.debug("Minimizing has removed {} of {} typing", diff, tgsSize);
}
}

@Override
public void finalizeTypes(Typing tp) {
for (Local l : tp.getAllLocals()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package soot.jimple.toolkits.typing;

/*-
* #%L
* Soot - a J*va Optimization Framework
* %%
* Copyright (C) 1997 - 2018 Raja Vallée-Rai and others
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 2.1 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-2.1.html>.
* #L%
*/

import java.util.List;

import soot.jimple.toolkits.typing.fast.BytecodeHierarchy;
import soot.jimple.toolkits.typing.fast.DefaultTypingStrategy;
import soot.jimple.toolkits.typing.fast.Typing;

/**
* JUnit-Tests for the {@link DefaultTypingStrategy#minimizeParallel(List, soot.jimple.toolkits.typing.fast.IHierarchy)}
* method.
*
* For each test we generate a simple synthetic class hierarchy and some {@link Typing}s we minimize afterwards and check the
* result. The test are the same as in {@link DefaultTypingStrategyMinimizeSequentialTest}.
*
* @author Jan Peter Stotz
*/
public class DefaultTypingStrategyMinimizeParallelTest extends DefaultTypingStrategyMinimizeSequentialTest {

@Override
protected void executeMinimize(List<Typing> typingList) {
new DefaultTypingStrategy().minimizeParallel(typingList, new BytecodeHierarchy());
}

}
Loading

0 comments on commit f6f5cd1

Please sign in to comment.