Skip to content

Commit

Permalink
Merge pull request #828 from soot-oss/enhance/concurrencyJavaView827
Browse files Browse the repository at this point in the history
improve concurrency in the JavaView; create less JavaLanguage objects / IdentifierFactories
  • Loading branch information
swissiety authored Jan 25, 2024
2 parents 17ae880 + 16134a5 commit ee53892
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 97 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import sootup.core.SourceTypeSpecifier;
import sootup.core.cache.FullCache;
import sootup.core.cache.provider.ClassCacheProvider;
import sootup.core.cache.provider.FullCacheProvider;
import sootup.core.inputlocation.AnalysisInputLocation;
Expand All @@ -38,7 +37,6 @@
import sootup.core.signatures.PackageName;
import sootup.core.types.ClassType;
import sootup.java.core.*;
import sootup.java.core.language.JavaLanguage;
import sootup.java.core.signatures.ModulePackageName;
import sootup.java.core.signatures.ModuleSignature;
import sootup.java.core.types.JavaClassType;
Expand Down Expand Up @@ -96,9 +94,12 @@ public JavaModuleView(
@Nonnull ClassCacheProvider cacheProvider,
@Nonnull Function<AnalysisInputLocation, ClassLoadingOptions> classLoadingOptionsSpecifier,
@Nonnull SourceTypeSpecifier sourceTypeSpecifier) {
super(inputLocations, cacheProvider, sourceTypeSpecifier);
super(
inputLocations,
cacheProvider,
sourceTypeSpecifier,
JavaModuleIdentifierFactory.getInstance());
this.moduleInfoAnalysisInputLocations = moduleInputLocations;

JavaModuleInfo unnamedModuleInfo = JavaModuleInfo.getUnnamedModuleInfo();
moduleInfoMap.put(unnamedModuleInfo.getModuleSignature(), unnamedModuleInfo);
}
Expand Down Expand Up @@ -163,7 +164,7 @@ private boolean isPackageVisibleToModule(

@Override
@Nonnull
protected Optional<JavaSootClassSource> getAbstractClass(@Nonnull ClassType type) {
protected Optional<JavaSootClassSource> getClassSource(@Nonnull ClassType type) {

Optional<JavaSootClassSource> cs =
moduleInfoAnalysisInputLocations.stream()
Expand All @@ -177,7 +178,7 @@ protected Optional<JavaSootClassSource> getAbstractClass(@Nonnull ClassType type
return cs;
}

return super.getAbstractClass(type);
return super.getClassSource(type);
}

@Nonnull
Expand Down Expand Up @@ -433,7 +434,7 @@ public synchronized Collection<JavaSootClass> getTransitiveClasses(@Nonnull Modu
@Nonnull
@Override
public JavaModuleIdentifierFactory getIdentifierFactory() {
return (JavaModuleIdentifierFactory) new JavaLanguage(9).getIdentifierFactory();
return (JavaModuleIdentifierFactory) identifierFactory;
}

@Nonnull
Expand Down Expand Up @@ -479,40 +480,4 @@ public Set<ModuleSignature> getNamedModules() {
}
return modules;
}

@Override
@Nonnull
protected synchronized Collection<JavaSootClass> resolveAll() {
if (isFullyResolved && cache instanceof FullCache) {
return cache.getClasses().stream()
.map(clazz -> (JavaSootClass) clazz)
.collect(Collectors.toList());
}

Collection<Optional<JavaSootClass>> resolvedClassesOpts =
inputLocations.stream()
.flatMap(location -> location.getClassSources(this).stream())
.map(this::buildClassFrom)
.collect(Collectors.toList());

Collection<Optional<JavaSootClass>> resolvedModuleClassesOpts =
moduleInfoAnalysisInputLocations.stream()
.flatMap(location -> location.getClassSources(this).stream())
.map(this::buildClassFrom)
.collect(Collectors.toList());

Collection<Optional<JavaSootClass>> combinedResolvedClassesOpts =
Stream.concat(resolvedClassesOpts.stream(), resolvedModuleClassesOpts.stream())
.collect(Collectors.toList());

Collection<JavaSootClass> resolvedClasses =
combinedResolvedClassesOpts.stream()
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());

isFullyResolved = true;

return resolvedClasses;
}
}
88 changes: 43 additions & 45 deletions sootup.java.core/src/main/java/sootup/java/core/views/JavaView.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,7 @@
* #L%
*/

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.*;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import sootup.core.SourceTypeSpecifier;
Expand All @@ -41,7 +38,6 @@
import sootup.core.types.ClassType;
import sootup.core.views.AbstractView;
import sootup.java.core.*;
import sootup.java.core.language.JavaLanguage;
import sootup.java.core.types.AnnotationType;

/**
Expand All @@ -52,6 +48,7 @@
* @author Jan Martin Persch
*/
public class JavaView extends AbstractView {
@Nonnull protected final JavaIdentifierFactory identifierFactory;

@Nonnull protected final List<AnalysisInputLocation> inputLocations;
@Nonnull protected final ClassCache cache;
Expand Down Expand Up @@ -83,16 +80,41 @@ public JavaView(
@Nonnull List<AnalysisInputLocation> inputLocations,
@Nonnull ClassCacheProvider cacheProvider,
@Nonnull SourceTypeSpecifier sourceTypeSpecifier) {
this(inputLocations, cacheProvider, sourceTypeSpecifier, JavaIdentifierFactory.getInstance());
}

protected JavaView(
@Nonnull List<AnalysisInputLocation> inputLocations,
@Nonnull ClassCacheProvider cacheProvider,
@Nonnull SourceTypeSpecifier sourceTypeSpecifier,
@Nonnull JavaIdentifierFactory idf) {
this.inputLocations = inputLocations;
this.cache = cacheProvider.createCache();
this.sourceTypeSpecifier = sourceTypeSpecifier;
this.identifierFactory = idf;
}

/** Resolves all classes that are part of the view and stores them in the cache. */
@Override
@Nonnull
public synchronized Collection<JavaSootClass> getClasses() {
return resolveAll();
if (isFullyResolved && cache instanceof FullCache) {
return cache.getClasses().stream()
.map(clazz -> (JavaSootClass) clazz)
.collect(Collectors.toList());
}

Collection<JavaSootClass> resolvedClasses =
inputLocations.stream()
.flatMap(location -> location.getClassSources(this).stream())
.map(this::buildClassFrom)
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());

isFullyResolved = true;

return resolvedClasses;
}

/** Resolves the class matching the provided {@link ClassType ClassType}. */
Expand All @@ -104,44 +126,45 @@ public synchronized Optional<JavaSootClass> getClass(@Nonnull ClassType type) {
return Optional.of(cachedClass);
}

Optional<JavaSootClassSource> abstractClass = getAbstractClass(type);
Optional<JavaSootClassSource> abstractClass = getClassSource(type);
return abstractClass.flatMap(this::buildClassFrom);
}

@Override
@Nonnull
public Optional<JavaSootMethod> getMethod(@Nonnull MethodSignature signature) {
final Optional<JavaSootClass> aClass = getClass(signature.getDeclClassType());
if (!aClass.isPresent()) {
return Optional.empty();
if (aClass.isPresent()) {
return aClass.get().getMethod(signature.getSubSignature());
}
return aClass.get().getMethod(signature.getSubSignature());
return Optional.empty();
}

@Override
@Nonnull
public Optional<JavaSootField> getField(@Nonnull FieldSignature signature) {
final Optional<JavaSootClass> aClass = getClass(signature.getDeclClassType());
if (!aClass.isPresent()) {
return Optional.empty();
if (aClass.isPresent()) {
return aClass.get().getField(signature.getSubSignature());
}
return aClass.get().getField(signature.getSubSignature());
return Optional.empty();
}

@Nonnull
@Override
public JavaIdentifierFactory getIdentifierFactory() {
return (JavaIdentifierFactory) new JavaLanguage(8).getIdentifierFactory();
return identifierFactory;
}

/** Returns the number of classes that are currently stored in the cache. */
public int getNumberOfStoredClasses() {
public int getCachedClassesCount() {
return cache.size();
}

@Nonnull
protected Optional<JavaSootClassSource> getAbstractClass(@Nonnull ClassType type) {
return inputLocations.stream()
protected Optional<JavaSootClassSource> getClassSource(@Nonnull ClassType type) {
return inputLocations
.parallelStream()
.map(location -> location.getClassSource(type, this))
.filter(Optional::isPresent)
// like javas behaviour: if multiple matching Classes(ClassTypes) are found on the
Expand All @@ -157,12 +180,12 @@ protected synchronized Optional<JavaSootClass> buildClassFrom(AbstractClassSourc

ClassType classType = classSource.getClassType();
JavaSootClass theClass;
if (!cache.hasClass(classType)) {
if (cache.hasClass(classType)) {
theClass = (JavaSootClass) cache.getClass(classType);
} else {
theClass =
(JavaSootClass) classSource.buildClass(sourceTypeSpecifier.sourceTypeFor(classSource));
cache.putClass(classType, theClass);
} else {
theClass = (JavaSootClass) cache.getClass(classType);
}

if (theClass.getType() instanceof AnnotationType) {
Expand All @@ -172,29 +195,4 @@ protected synchronized Optional<JavaSootClass> buildClassFrom(AbstractClassSourc

return Optional.of(theClass);
}

@Nonnull
protected synchronized Collection<JavaSootClass> resolveAll() {
if (isFullyResolved && cache instanceof FullCache) {
return cache.getClasses().stream()
.map(clazz -> (JavaSootClass) clazz)
.collect(Collectors.toList());
}

Collection<Optional<JavaSootClass>> resolvedClassesOpts =
inputLocations.stream()
.flatMap(location -> location.getClassSources(this).stream())
.map(this::buildClassFrom)
.collect(Collectors.toList());

Collection<JavaSootClass> resolvedClasses =
resolvedClassesOpts.stream()
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());

isFullyResolved = true;

return resolvedClasses;
}
}
18 changes: 9 additions & 9 deletions sootup.tests/src/test/java/sootup/tests/CacheTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,41 +39,41 @@ public static void setupProject() {
@Test
public void fullCacheTest() {
JavaView view = new JavaView(inputLocations, new FullCacheProvider());
assertEquals(0, view.getNumberOfStoredClasses());
assertEquals(0, view.getCachedClassesCount());

ClassType miniAppClassType = view.getIdentifierFactory().getClassType("MiniApp");
view.getClass(miniAppClassType);
assertEquals(1, view.getNumberOfStoredClasses());
assertEquals(1, view.getCachedClassesCount());

ClassType utilsOperationClassType =
view.getIdentifierFactory().getClassType("utils.Operations");
view.getClass(utilsOperationClassType);
assertEquals(2, view.getNumberOfStoredClasses());
assertEquals(2, view.getCachedClassesCount());

view.getClasses();
assertEquals(6, view.getNumberOfStoredClasses());
assertEquals(6, view.getCachedClassesCount());
}

/** Test the {@link sootup.core.cache.LRUCache} class */
@Test
public void lruCacheTest() {
JavaView view = new JavaView(inputLocations, new LRUCacheProvider(1));
assertEquals(0, view.getNumberOfStoredClasses());
assertEquals(0, view.getCachedClassesCount());

ClassType miniAppClassType = view.getIdentifierFactory().getClassType("MiniApp");
view.getClass(miniAppClassType);
assertEquals(1, view.getNumberOfStoredClasses());
assertEquals(1, view.getCachedClassesCount());

ClassType utilsOperationClassType =
view.getIdentifierFactory().getClassType("utils.Operations");
view.getClass(utilsOperationClassType);
assertEquals(1, view.getNumberOfStoredClasses());
assertEquals(1, view.getCachedClassesCount());

view.getClasses();
assertEquals(1, view.getNumberOfStoredClasses());
assertEquals(1, view.getCachedClassesCount());

JavaView newView = new JavaView(inputLocations, new LRUCacheProvider());
newView.getClasses();
assertEquals(6, newView.getNumberOfStoredClasses());
assertEquals(6, newView.getCachedClassesCount());
}
}

0 comments on commit ee53892

Please sign in to comment.