Skip to content

ArrayTypeCache recursion exception (fix) #2119

Open
@eortega-pjr

Description

@eortega-pjr

20baf2f 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);
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions