Skip to content

Commit

Permalink
compare -> isTypingSetMoreGeneral; parallel minimize implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
jpstotz committed Mar 20, 2024
1 parent 8eb6edb commit f2e389e
Showing 1 changed file with 84 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

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

import soot.Local;
import soot.RefType;
Expand All @@ -42,6 +47,7 @@
* 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();

Expand Down Expand Up @@ -81,49 +87,98 @@ public static Set<Local> getObjectLikeTypings(List<Typing> tgs) {

@Override
public void minimize(List<Typing> tgs, IHierarchy h) {
if (tgs.size() > 1000) {
minimizeParallel(tgs, h);
return;
}

Set<Local> objectVars = getObjectLikeTypings(tgs);
OUTER: for (ListIterator<Typing> i = tgs.listIterator(); i.hasNext();) {
Typing tgi = i.next();

// Throw out duplicate typings
for (Typing tgj : tgs) {
// if compare = 1, then tgi is the more general typing
// if tgi is the more general typing (isTypingSetMoreGeneral == true)
// 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) {
if (tgi != tgj && isTypingSetMoreGeneral(tgi, tgj, h, objectVars)) {
i.remove();
continue OUTER;
}
}
}
}

public int compare(Typing a, Typing b, IHierarchy h, Collection<Local> localsToIgnore) {
int r = 0;
public void minimizeParallel(List<Typing> tgs, IHierarchy h) {
logger.debug("Performing parallel minimization");
final AtomicInteger processed = new AtomicInteger();
Set<Local> objectVars = getObjectLikeTypings(tgs);

final int size = tgs.size();
List<DeletableTyping> typings = tgs.stream().map(t -> new DeletableTyping(t)).collect(Collectors.toList());

typings.parallelStream().forEach(t -> {
Typing tgi = t.typing;
// Mark duplicate typings
for (Typing tgj : tgs) {
// if tgi is the more general typing (isTypingSetMoreGeneral == true)
// We shouldn't pick that one as we would then end up
// with lots of locals typed to Serializable etc.
if (tgi != tgj && isTypingSetMoreGeneral(tgi, tgj, h, objectVars)) {
t.deleted = true;
break;
}
}
int count = processed.incrementAndGet();
if (count % 1000 == 0) {
logger.debug("minimizing {} = {}%", count, (100f * count) / size);
}
});

// Remove marked Typing list entries from tgs
// this loop works because tgs[i] == typings[i].typing
for (int i = typings.size() - 1; i >= 0; i--) {
DeletableTyping deletableTyping = typings.get(i);
if (deletableTyping.deleted) {
tgs.remove(i);
}
}
}

/**
* Check if typing a is more general than typing b
*
* Replaces the old compare method that was able to detect more cases.
*
* @param a
* @param b
* @param h
* @param localsToIgnore
* @return
*/
public boolean isTypingSetMoreGeneral(Typing a, Typing b, IHierarchy h, Collection<Local> localsToIgnore) {
boolean result = false;
for (Local v : a.map.keySet()) {
if (!localsToIgnore.contains(v)) {
Type ta = a.get(v), tb = b.get(v);

int cmp;
if (TypeResolver.typesEqual(ta, tb)) {
cmp = 0;
if (ta == tb || TypeResolver.typesEqual(ta, tb)) {
// ta == tb can happen often, thus it gains a small performance boost checking it directly
} else if (h.ancestor(ta, tb)) {
cmp = 1;
// local ta is an ancestor of tb, so typing a is potentially more general than typing b.
// We need to check the other locals for a final result.
result = true;
} else if (h.ancestor(tb, ta)) {
cmp = -1;
// local tb is an ancestor of ta, this means tb is more general than ta.
// Therefore the whole set a can not be more general than b
return false;
} else {
return -2;
}

if ((cmp == 1 && r == -1) || (cmp == -1 && r == 1)) {
return 2;
}
if (r == 0) {
r = cmp;
// types not comparable
return false;
}
}
}
return r;
return result;
}

@Override
Expand All @@ -136,4 +191,15 @@ public void finalizeTypes(Typing tp) {
}
}

private static class DeletableTyping {
private boolean deleted = false;

private final Typing typing;

public DeletableTyping(Typing typing) {
super();
this.typing = typing;
}

}
}

0 comments on commit f2e389e

Please sign in to comment.