20baf2f67aecf44f6089a0a42d7e9b2e08f4b449 introduced an ArrayTypeCache which evidences the following issue when processing certain inputs:
DEBUG: Caused by: java.lang.IllegalStateException: Recursive update
DEBUG: at java.base/java.util.concurrent.ConcurrentHashMap.transfer(ConcurrentHashMap.java:2552)
DEBUG: at java.base/java.util.concurrent.ConcurrentHashMap.addCount(ConcurrentHashMap.java:2354)
DEBUG: at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1776)
DEBUG: at soot.ArrayTypeCache$1.apply(ArrayTypeCache.java:54)
DEBUG: at soot.ArrayTypeCache$1.apply(ArrayTypeCache.java:41)
DEBUG: at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1708)
DEBUG: at soot.ArrayTypeCache.getArrayType(ArrayTypeCache.java:82)
DEBUG: at soot.ArrayType.v(ArrayType.java:73)
DEBUG: at soot.asm.AsmUtil.toJimpleType(AsmUtil.java:208)
DEBUG: at soot.asm.SootClassBuilder.visitField(SootClassBuilder.java:166)
DEBUG: at org.objectweb.asm.ClassReader.readField(ClassReader.java:1138)
DEBUG: at org.objectweb.asm.ClassReader.accept(ClassReader.java:740)
DEBUG: at org.objectweb.asm.ClassReader.accept(ClassReader.java:425)
DEBUG: at soot.asm.AsmClassSource.resolve(AsmClassSource.java:67)
DEBUG: at soot.SootResolver.bringToHierarchyUnchecked(SootResolver.java:258)
DEBUG: at soot.SootResolver.bringToHierarchy(SootResolver.java:225)
DEBUG: at soot.SootResolver.bringToSignatures(SootResolver.java:298)
DEBUG: at soot.SootResolver.bringToBodies(SootResolver.java:342)
DEBUG: at soot.SootResolver.processResolveWorklist(SootResolver.java:171)
DEBUG: at soot.SootResolver.resolveClass(SootResolver.java:135)
DEBUG: at soot.Scene.loadClass(Scene.java:492)
DEBUG: at soot.Scene.loadClassAndSupport(Scene.java:479)
DEBUG: at soot.Scene.loadNecessaryClasses(Scene.java:1331)
This is due to computeIfAbsent being called recursively, triggering a reentrant guard in ConcurrentHashMap.
I've rewritten the ArrayTypeCache as such and found it works nicely, speeding up some of our processing by 25%:
public class ArrayTypeCache {
private final Map<Pair<Type, Integer>, ArrayType> cache = new ConcurrentHashMap<>();
public ArrayTypeCache(final Global g) {
}
/**
* Returns a potentially cached array type of the given dimensions
* @param baseType the base type (array element type)
* @param dimensionsCurrent the number of dimensions
* @return the array type
*/
public ArrayType getArrayType(final Type baseType, final int dimensionsCurrent) {
final Pair<Type, Integer> pairSearch = new Pair<>(baseType, dimensionsCurrent);
final ArrayType result = cache.get(pairSearch);
if (result != null) {
return result;
}
Type elementType = baseType;
for (int i = 1; i <= dimensionsCurrent; i++) {
final ArrayType ret =
cache.computeIfAbsent( new Pair<>(baseType, i),
k -> { return new ArrayType(k.getO1(), k.getO2()); });
elementType.setArrayType(ret);
elementType = ret;
}
return cache.get(pairSearch);
}
}
20baf2f67aecf44f6089a0a42d7e9b2e08f4b449 introduced an ArrayTypeCache which evidences the following issue when processing certain inputs:
This is due to
computeIfAbsent
being called recursively, triggering a reentrant guard inConcurrentHashMap
.I've rewritten the ArrayTypeCache as such and found it works nicely, speeding up some of our processing by 25%: