Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance tests and improvements: LLVM and Type updates #775

Merged
merged 11 commits into from
Jun 15, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,7 @@
import de.fraunhofer.aisec.cpg.graph.types.TypeParser;
import de.fraunhofer.aisec.cpg.sarif.PhysicalLocation;
import de.fraunhofer.aisec.cpg.sarif.Region;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.*;
import java.util.stream.Collectors;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.slf4j.Logger;
Expand Down Expand Up @@ -612,7 +610,7 @@ private CatchClause handleCatchClause(com.github.javaparser.ast.stmt.CatchClause
CatchClause cClause = NodeBuilder.newCatchClause(catchCls.toString());
lang.getScopeManager().enterScope(cClause);

HashSet<Type> possibleTypes = new HashSet<>();
List<Type> possibleTypes = new ArrayList<>();
Type concreteType;
if (catchCls.getParameter().getType() instanceof UnionType) {
for (ReferenceType t : ((UnionType) catchCls.getParameter().getType()).getElements()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import de.fraunhofer.aisec.cpg.graph.types.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.checkerframework.checker.nullness.qual.NonNull;

Expand All @@ -51,7 +52,7 @@ default void setType(Type type) {
*/
void updateType(Type type);

void updatePossibleSubtypes(Set<Type> types);
void updatePossibleSubtypes(List<Type> types);

/**
* Set the node's type. This may start a chain of type listener notifications
Expand All @@ -62,22 +63,22 @@ default void setType(Type type) {
* can abort. If root is an empty list, the type change is seen as an externally triggered
* event and subsequent type listeners receive the current node as their root.
*/
void setType(Type type, Collection<HasType> root);
void setType(Type type, List<HasType> root);

Set<Type> getPossibleSubTypes();
List<Type> getPossibleSubTypes();

default void setPossibleSubTypes(Set<Type> possibleSubTypes) {
default void setPossibleSubTypes(List<Type> possibleSubTypes) {
setPossibleSubTypes(possibleSubTypes, new ArrayList<>());
}

/**
* Set the node's possible subtypes. Listener circle detection works the same way as with {@link
* #setType(Type, Collection)}
* #setType(Type, List)}
*
* @param possibleSubTypes the set of possible sub types
* @param root A list of already seen nodes which is used for detecting loops.
*/
void setPossibleSubTypes(Set<Type> possibleSubTypes, @NonNull Collection<HasType> root);
void setPossibleSubTypes(List<Type> possibleSubTypes, @NonNull List<HasType> root);

void registerTypeListener(TypeListener listener);

Expand All @@ -97,9 +98,9 @@ default void setPossibleSubTypes(Set<Type> possibleSubTypes) {

interface TypeListener {

void typeChanged(HasType src, Collection<HasType> root, Type oldType);
void typeChanged(HasType src, List<HasType> root, Type oldType);

void possibleSubTypesChanged(HasType src, Collection<HasType> root, Set<Type> oldSubTypes);
void possibleSubTypesChanged(HasType src, List<HasType> root);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public enum Language {
}

@NonNull
private final Map<HasType, Set<Type>> typeCache =
private final Map<HasType, List<Type>> typeCache =
Collections.synchronizedMap(new IdentityHashMap<>());

@NonNull
Expand Down Expand Up @@ -336,13 +336,16 @@ public static void setTypeSystemActive(boolean active) {
}

@NotNull
public Map<HasType, Set<Type>> getTypeCache() {
public Map<HasType, List<Type>> getTypeCache() {
return typeCache;
}

public synchronized void cacheType(HasType node, Type type) {
if (!isUnknown(type)) {
typeCache.computeIfAbsent(node, n -> new HashSet<>()).add(type);
List<Type> types = typeCache.computeIfAbsent(node, n -> new ArrayList<>());
if (!types.contains(type)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this essentially the same as a set does? Not sure this is really faster / better here.

types.add(type);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ public void setModifiers(List<String> modifiers) {
}

@Override
public void typeChanged(HasType src, Collection<HasType> root, Type oldType) {
public void typeChanged(HasType src, List<HasType> root, Type oldType) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to keep Collection in the function signature here?

if (!TypeManager.isTypeSystemActive()) {
return;
}
Expand Down Expand Up @@ -165,12 +165,11 @@ public void typeChanged(HasType src, Collection<HasType> root, Type oldType) {
}

@Override
public void possibleSubTypesChanged(
HasType src, Collection<HasType> root, Set<Type> oldSubTypes) {
public void possibleSubTypesChanged(HasType src, List<HasType> root) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here as well I guess

if (!TypeManager.isTypeSystemActive()) {
return;
}
Set<Type> subTypes = new HashSet<>(getPossibleSubTypes());
List<Type> subTypes = new ArrayList<>(getPossibleSubTypes());
subTypes.addAll(src.getPossibleSubTypes());
setPossibleSubTypes(subTypes, root);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public abstract class ValueDeclaration extends Declaration implements HasType {

protected Type type = UnknownType.getUnknownType();

protected Set<Type> possibleSubTypes = new HashSet<>();
protected List<Type> possibleSubTypes = new ArrayList<>();

@Transient private final Set<TypeListener> typeListeners = new HashSet<>();

Expand All @@ -59,7 +59,7 @@ public Type getType() {
result =
TypeManager.getInstance()
.getTypeCache()
.computeIfAbsent(this, n -> Collections.emptySet())
.computeIfAbsent(this, n -> Collections.emptyList())
.stream()
.findAny()
.orElse(UnknownType.getUnknownType());
Expand All @@ -83,7 +83,7 @@ public Type getPropagationType() {
}

@Override
public void setType(Type type, Collection<HasType> root) {
public void setType(Type type, List<HasType> root) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here. Keep signature and only change the implememation?

if (!TypeManager.isTypeSystemActive()) {
TypeManager.getInstance().cacheType(this, type);
return;
Expand Down Expand Up @@ -118,7 +118,7 @@ public void setType(Type type, Collection<HasType> root) {
TypeManager.getInstance()
.registerType(TypeManager.getInstance().getCommonType(subTypes).orElse(type));

Set<Type> newSubtypes = new HashSet<>();
List<Type> newSubtypes = new ArrayList<>();
for (var s : subTypes) {
if (TypeManager.getInstance().isSupertypeOf(this.type, s)) {
newSubtypes.add(TypeManager.getInstance().registerType(s));
Expand All @@ -142,11 +142,11 @@ public void setType(Type type, Collection<HasType> root) {

@Override
public void resetTypes(Type type) {
Set<Type> oldSubTypes = new HashSet<>(getPossibleSubTypes());
List<Type> oldSubTypes = getPossibleSubTypes();
Type oldType = this.type;

this.type = type;
setPossibleSubTypes(new HashSet<>(List.of(type)));
setPossibleSubTypes(List.of(type));

List<HasType> root = new ArrayList<>(List.of(this));
if (!Objects.equals(oldType, type)) {
Expand All @@ -157,15 +157,15 @@ public void resetTypes(Type type) {
if (oldSubTypes.size() != 1 || !oldSubTypes.contains(type))
this.typeListeners.stream()
.filter(l -> !l.equals(this))
.forEach(l -> l.possibleSubTypesChanged(this, root, oldSubTypes));
.forEach(l -> l.possibleSubTypesChanged(this, root));
}

@Override
public void registerTypeListener(TypeListener listener) {
List<HasType> root = new ArrayList<>(List.of(this));
typeListeners.add(listener);
listener.typeChanged(this, root, this.type);
listener.possibleSubTypesChanged(this, root, this.possibleSubTypes);
listener.possibleSubTypesChanged(this, root);
}

@Override
Expand All @@ -179,19 +179,20 @@ public Set<TypeListener> getTypeListeners() {
}

@Override
public Set<Type> getPossibleSubTypes() {
public List<Type> getPossibleSubTypes() {
if (!TypeManager.isTypeSystemActive()) {
return TypeManager.getInstance().getTypeCache().getOrDefault(this, Collections.emptySet());
return TypeManager.getInstance().getTypeCache().getOrDefault(this, Collections.emptyList());
}
return possibleSubTypes;
}

@Override
public void setPossibleSubTypes(Set<Type> possibleSubTypes, @NotNull Collection<HasType> root) {
public void setPossibleSubTypes(List<Type> possibleSubTypes, @NotNull List<HasType> root) {
possibleSubTypes =
possibleSubTypes.stream()
.filter(Predicate.not(TypeManager.getInstance()::isUnknown))
.collect(Collectors.toSet());
.distinct()
.collect(Collectors.toList());

if (!TypeManager.isTypeSystemActive()) {
possibleSubTypes.forEach(t -> TypeManager.getInstance().cacheType(this, t));
Expand All @@ -201,16 +202,19 @@ public void setPossibleSubTypes(Set<Type> possibleSubTypes, @NotNull Collection<
if (root.contains(this)) {
return;
}
root.add(this);

Set<Type> oldSubTypes = this.possibleSubTypes;
List<Type> oldSubTypes = this.possibleSubTypes;
this.possibleSubTypes = possibleSubTypes;

if (!this.possibleSubTypes.equals(oldSubTypes)) {
for (var listener : this.typeListeners) {
if (!listener.equals(this)) {
listener.possibleSubTypesChanged(this, root, oldSubTypes);
}
if (new HashSet<>(oldSubTypes).containsAll(getPossibleSubTypes())) {
// Nothing changed, so we do not have to notify the listeners.
return;
}
root.add(this); // Add current node to the set of "triggers" to detect potential loops.
// Notify all listeners about the changed type
for (var listener : this.typeListeners) {
if (!listener.equals(this)) {
listener.possibleSubTypesChanged(this, root);
}
}
}
Expand All @@ -220,7 +224,7 @@ public void refreshType() {
List<HasType> root = new ArrayList<>(List.of(this));
for (var l : this.typeListeners) {
l.typeChanged(this, root, type);
l.possibleSubTypesChanged(this, root, possibleSubTypes);
l.possibleSubTypesChanged(this, root);
}
}

Expand Down Expand Up @@ -254,7 +258,7 @@ public void updateType(Type type) {
}

@Override
public void updatePossibleSubtypes(Set<Type> types) {
public void updatePossibleSubtypes(List<Type> types) {
this.possibleSubTypes = types;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public void setInitializer(@Nullable Expression initializer) {
}

@Override
public void typeChanged(HasType src, Collection<HasType> root, Type oldType) {
public void typeChanged(HasType src, List<HasType> root, Type oldType) {
if (!TypeManager.isTypeSystemActive()) {
return;
}
Expand Down Expand Up @@ -162,12 +162,11 @@ public void typeChanged(HasType src, Collection<HasType> root, Type oldType) {
}

@Override
public void possibleSubTypesChanged(
HasType src, Collection<HasType> root, Set<Type> oldSubTypes) {
public void possibleSubTypesChanged(HasType src, List<HasType> root) {
if (!TypeManager.isTypeSystemActive()) {
return;
}
Set<Type> subTypes = new HashSet<>(getPossibleSubTypes());
List<Type> subTypes = new ArrayList<>(getPossibleSubTypes());
subTypes.addAll(src.getPossibleSubTypes());
setPossibleSubTypes(subTypes, root);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public boolean equals(Object o) {
}

@Override
public void typeChanged(HasType src, Collection<HasType> root, Type oldType) {
public void typeChanged(HasType src, List<HasType> root, Type oldType) {
if (!TypeManager.isTypeSystemActive()) {
return;
}
Expand All @@ -123,12 +123,11 @@ public void typeChanged(HasType src, Collection<HasType> root, Type oldType) {
}

@Override
public void possibleSubTypesChanged(
HasType src, Collection<HasType> root, Set<Type> oldSubTypes) {
public void possibleSubTypesChanged(HasType src, List<HasType> root) {
if (!TypeManager.isTypeSystemActive()) {
return;
}
Set<Type> subTypes = new HashSet<>(getPossibleSubTypes());
List<Type> subTypes = new ArrayList<>(getPossibleSubTypes());
subTypes.addAll(src.getPossibleSubTypes());
setPossibleSubTypes(subTypes, root);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,7 @@
import de.fraunhofer.aisec.cpg.graph.SubGraph;
import de.fraunhofer.aisec.cpg.graph.TypeManager;
import de.fraunhofer.aisec.cpg.graph.types.Type;
import java.util.Collection;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull;

Expand Down Expand Up @@ -75,7 +72,7 @@ public void setSubscriptExpression(Expression subscriptExpression) {
}

@Override
public void typeChanged(HasType src, Collection<HasType> root, Type oldType) {
public void typeChanged(HasType src, List<HasType> root, Type oldType) {
if (!TypeManager.isTypeSystemActive()) {
return;
}
Expand All @@ -87,12 +84,11 @@ public void typeChanged(HasType src, Collection<HasType> root, Type oldType) {
}

@Override
public void possibleSubTypesChanged(
HasType src, Collection<HasType> root, Set<Type> oldSubTypes) {
public void possibleSubTypesChanged(HasType src, List<HasType> root) {
if (!TypeManager.isTypeSystemActive()) {
return;
}
Set<Type> subTypes = new HashSet<>(getPossibleSubTypes());
List<Type> subTypes = new ArrayList<>(getPossibleSubTypes());
subTypes.addAll(
src.getPossibleSubTypes().stream()
.map(this::getSubscriptType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ public void setOperatorCode(String operatorCode) {
}

@Override
public void typeChanged(HasType src, Collection<HasType> root, Type oldType) {
public void typeChanged(HasType src, List<HasType> root, Type oldType) {
if (!TypeManager.isTypeSystemActive()) {
return;
}
Expand All @@ -207,12 +207,11 @@ public void typeChanged(HasType src, Collection<HasType> root, Type oldType) {
}

@Override
public void possibleSubTypesChanged(
HasType src, Collection<HasType> root, Set<Type> oldSubTypes) {
public void possibleSubTypesChanged(HasType src, List<HasType> root) {
if (!TypeManager.isTypeSystemActive()) {
return;
}
Set<Type> subTypes = new HashSet<>(getPossibleSubTypes());
List<Type> subTypes = new ArrayList<>(getPossibleSubTypes());
subTypes.addAll(src.getPossibleSubTypes());
setPossibleSubTypes(subTypes, root);
}
Expand Down
Loading