diff --git a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/xta/InstantiatedTypesAnalysis.scala b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/xta/InstantiatedTypesAnalysis.scala index 7dfd55ddb2..a30b26d84f 100644 --- a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/xta/InstantiatedTypesAnalysis.scala +++ b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/xta/InstantiatedTypesAnalysis.scala @@ -22,6 +22,7 @@ import org.opalj.br.fpcf.properties.cg.NoCallers import org.opalj.br.instructions.INVOKESPECIAL import org.opalj.br.instructions.NEW import org.opalj.collection.immutable.UIDSet +import org.opalj.collection.mutable.RefArrayBuffer import org.opalj.fpcf.EOptionP import org.opalj.fpcf.EPK import org.opalj.fpcf.EPS @@ -37,8 +38,6 @@ import org.opalj.fpcf.PropertyStore import org.opalj.fpcf.Results import org.opalj.fpcf.SomeEPS import org.opalj.fpcf.UBP -import scala.collection.mutable -import scala.collection.mutable.ListBuffer /** * Marks types as instantiated if their constructor is invoked. Constructors invoked by subclass @@ -106,7 +105,7 @@ class InstantiatedTypesAnalysis private[analyses] ( seenCallers: Set[DeclaredMethod] ): PropertyComputationResult = { var newSeenCallers = seenCallers - val partialResults = new ListBuffer[PartialResult[TypeSetEntity, InstantiatedTypes]]() + val partialResults = RefArrayBuffer.empty[PartialResult[TypeSetEntity, InstantiatedTypes]] for { (caller, _, _) ← callersUB.callers // if we already analyzed the caller, we do not need to do it twice @@ -128,7 +127,7 @@ class InstantiatedTypesAnalysis private[analyses] ( continuation(declaredMethod, declaredType, newSeenCallers) ) - Results(reRegistration, partialResults) + Results(reRegistration, partialResults.iterator()) } } @@ -136,7 +135,7 @@ class InstantiatedTypesAnalysis private[analyses] ( declaredMethod: DeclaredMethod, declaredType: ObjectType, caller: DeclaredMethod, - partialResults: ListBuffer[PartialResult[TypeSetEntity, InstantiatedTypes]] + partialResults: RefArrayBuffer[PartialResult[TypeSetEntity, InstantiatedTypes]] ): Unit = { // a constructor is called by a non-constructor method, there will be an initialization. if (caller.name != "") { @@ -275,20 +274,21 @@ class InstantiatedTypesAnalysisScheduler( val packageIsClosed = p.get(ClosedPackagesKey) val declaredMethods = p.get(DeclaredMethodsKey) val entryPoints = p.get(InitialEntryPointsKey) - val initialInstantiatedTypes = p.get(InitialInstantiatedTypesKey).toSet + val initialInstantiatedTypes = + UIDSet[ReferenceType](p.get(InitialInstantiatedTypesKey).toSeq: _*) // While processing entry points and fields, we keep track of all array types we see, as // well as subtypes and lower-dimensional types. These types also need to be // pre-initialized. Note: This set only contains ArrayTypes whose element type is an // ObjectType. Arrays of primitive types can be ignored. - val seenArrayTypes = mutable.Set[ArrayType]() + val seenArrayTypes = UIDSet.newBuilder[ArrayType] - def initialize(setEntity: TypeSetEntity, types: Traversable[ReferenceType]): Unit = { + def initialize(setEntity: TypeSetEntity, types: UIDSet[ReferenceType]): Unit = { ps.preInitialize(setEntity, InstantiatedTypes.key) { case UBP(typeSet) ⇒ InterimEUBP(setEntity, typeSet.updated(types)) case _: EPK[_, _] ⇒ - InterimEUBP(setEntity, InstantiatedTypes(UIDSet(types.toSeq: _*))) + InterimEUBP(setEntity, InstantiatedTypes(types)) case eps ⇒ sys.error(s"unexpected property: $eps") } @@ -296,7 +296,7 @@ class InstantiatedTypesAnalysisScheduler( // Some cooperative analyses originally meant for RTA may require the global type set // to be pre-initialized. For that purpose, an empty type set is sufficient. - initialize(p, Traversable.empty) + initialize(p, UIDSet.empty) def isRelevantArrayType(rt: Type): Boolean = rt.isArrayType && rt.asArrayType.elementType.isObjectType @@ -307,8 +307,8 @@ class InstantiatedTypesAnalysisScheduler( ep ← entryPoints; dm = declaredMethods(ep) ) { - val typeFilters = mutable.Set[ReferenceType]() - val arrayTypeAssignments = mutable.Set[ArrayType]() + val typeFilters = UIDSet.newBuilder[ReferenceType] + val arrayTypeAssignments = UIDSet.newBuilder[ArrayType] if (!dm.definedMethod.isStatic) { typeFilters += dm.declaringClassType @@ -331,11 +331,13 @@ class InstantiatedTypesAnalysisScheduler( } } + val typeFilterSet = typeFilters.result() + // Initial assignments of ObjectTypes - val objectTypeAssignments = initialInstantiatedTypes.filter(iit ⇒ typeFilters.exists(tf ⇒ - p.classHierarchy.isSubtypeOf(iit, tf))) + val objectTypeAssignments = initialInstantiatedTypes.filter(iit ⇒ + typeFilterSet.exists(tf ⇒ p.classHierarchy.isSubtypeOf(iit, tf))) - val initialAssignment = arrayTypeAssignments ++ objectTypeAssignments + val initialAssignment = objectTypeAssignments ++ arrayTypeAssignments.result() val dmSetEntity = selectSetEntity(dm) @@ -343,7 +345,7 @@ class InstantiatedTypesAnalysisScheduler( } // Returns true if the field's type indicates that the field should be pre-initialized. - def fieldIsRelevant(f: Field): Boolean = { + @inline def fieldIsRelevant(f: Field): Boolean = { // Only fields which are ArrayType or ObjectType are relevant. f.fieldType.isReferenceType && // If the field is an ArrayType, then the array's element type must be an ObjectType. @@ -374,25 +376,32 @@ class InstantiatedTypesAnalysisScheduler( // Assign initial types to all accessable fields. p.classFile(ot) match { case Some(cf) ⇒ - for (f ← cf.fields if fieldIsRelevant(f) && f.isNotFinal && fieldIsAccessible(f)) { + for (f ← cf.fields if f.isNotFinal && fieldIsRelevant(f) && fieldIsAccessible(f)) { val fieldType = f.fieldType.asReferenceType - - val initialAssignments = fieldType match { - case ot: ObjectType ⇒ - initialInstantiatedTypes.filter( - p.classHierarchy.isSubtypeOf(_, ot) - ) - - case at: ArrayType ⇒ - seenArrayTypes += at - - val dim = at.dimensions - val et = at.elementType.asObjectType - p.classHierarchy.allSubtypes(et, reflexive = true) - .intersect(initialInstantiatedTypes).map( - ArrayType(dim, _) - ) - + import p.classHierarchy + + val initialAssignments = if (fieldType.isObjectType) { + val ot = fieldType.asObjectType + initialInstantiatedTypes.foldLeft(UIDSet.newBuilder[ReferenceType]) { + (assignments, iit) ⇒ + if (classHierarchy.isSubtypeOf(iit, ot)) { + assignments += iit + } + assignments + }.result() + } else { + val at = fieldType.asArrayType + seenArrayTypes += at + val dim = at.dimensions + val et = at.elementType.asObjectType + val allSubtypes = p.classHierarchy.allSubtypes(et, true) + initialInstantiatedTypes.foldLeft(UIDSet.newBuilder[ReferenceType]) { + (assignments, iit) ⇒ + if (allSubtypes.contains(iit.asObjectType)) { + assignments += ArrayType(dim, iit) + } + assignments + }.result() } val fieldSetEntity = selectSetEntity(f) @@ -409,7 +418,7 @@ class InstantiatedTypesAnalysisScheduler( // and initialize their type sets. // Remember which ArrayTypes were processed, so we don't do it twice. - val initializedArrayTypes = mutable.Set[ArrayType]() + val initializedArrayTypes = new java.util.HashSet[ArrayType]() def initializeArrayType(at: ArrayType): Unit = { // If this type has already been initialized, we skip it. @@ -417,17 +426,24 @@ class InstantiatedTypesAnalysisScheduler( return ; } - initializedArrayTypes += at + initializedArrayTypes.add(at) val et = at.elementType.asObjectType - val subtypes = p.classHierarchy.allSubtypes(et, reflexive = true).intersect(initialInstantiatedTypes) + val allSubtypes = p.classHierarchy.allSubtypes(et, true) + val subtypes = + initialInstantiatedTypes.foldLeft(UIDSet.newBuilder[ReferenceType]) { (builder, iit) ⇒ + if (allSubtypes.contains(iit.asObjectType)) { + builder += iit + } + builder + }.result() val dim = at.dimensions if (dim > 1) { // Initialize multidimensional ArrayType. E.g., if at == A[][] and A is a supertype of A1, // we need to assign A[] and A1[] to the type set of A[][]. - val assignedArrayTypes = subtypes.map(ArrayType(dim - 1, _)) - initialize(at, assignedArrayTypes) + val assignedArrayTypes: UIDSet[ArrayType] = subtypes.map(ArrayType(dim - 1, _)) + initialize(at, assignedArrayTypes.asInstanceOf[UIDSet[ReferenceType]]) // After that, we also need to initialize the ArrayTypes which were just assigned. It is possible // that these were types which were not initially seen when processing entry points and fields. @@ -438,6 +454,6 @@ class InstantiatedTypesAnalysisScheduler( } } - seenArrayTypes foreach initializeArrayType + seenArrayTypes.result() foreach initializeArrayType } } diff --git a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/xta/PropagationBasedCGState.scala b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/xta/PropagationBasedCGState.scala index fc75f0f26e..79afce9f8c 100644 --- a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/xta/PropagationBasedCGState.scala +++ b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/xta/PropagationBasedCGState.scala @@ -6,8 +6,6 @@ package analyses package cg package xta -import scala.collection.mutable - import org.opalj.collection.immutable.UIDSet import org.opalj.fpcf.EOptionP import org.opalj.fpcf.SomeEOptionP @@ -18,6 +16,10 @@ import org.opalj.br.ReferenceType import org.opalj.br.fpcf.properties.cg.InstantiatedTypes import org.opalj.tac.fpcf.properties.TACAI +import scala.collection.mutable + +import scala.collection.JavaConverters._ + /** * Manages the state of each method analyzed by [[PropagationBasedCallGraphAnalysis]]. * @@ -29,10 +31,10 @@ class PropagationBasedCGState( _instantiatedTypesDependees: Iterable[EOptionP[TypeSetEntity, InstantiatedTypes]] ) extends CGState { - private[this] val _instantiatedTypesDependeeMap: mutable.Map[TypeSetEntity, EOptionP[TypeSetEntity, InstantiatedTypes]] = mutable.Map.empty + private[this] val _instantiatedTypesDependeeMap = new java.util.HashMap[TypeSetEntity, EOptionP[TypeSetEntity, InstantiatedTypes]]() for (dependee ← _instantiatedTypesDependees) { - _instantiatedTypesDependeeMap.update(dependee.e, dependee) + _instantiatedTypesDependeeMap.put(dependee.e, dependee) } private[this] val _virtualCallSites: mutable.LongMap[mutable.Set[CallSiteT]] = mutable.LongMap.empty @@ -46,11 +48,11 @@ class PropagationBasedCGState( def updateInstantiatedTypesDependee( instantiatedTypesDependee: EOptionP[TypeSetEntity, InstantiatedTypes] ): Unit = { - _instantiatedTypesDependeeMap.update(instantiatedTypesDependee.e, instantiatedTypesDependee) + _instantiatedTypesDependeeMap.put(instantiatedTypesDependee.e, instantiatedTypesDependee) } def instantiatedTypes(typeSetEntity: TypeSetEntity): UIDSet[ReferenceType] = { - val typeDependee = _instantiatedTypesDependeeMap(typeSetEntity) + val typeDependee = _instantiatedTypesDependeeMap.get(typeSetEntity) if (typeDependee.hasUBP) typeDependee.ub.types else @@ -58,11 +60,13 @@ class PropagationBasedCGState( } def instantiatedTypesContains(tpe: ReferenceType): Boolean = { - _instantiatedTypesDependeeMap.keys.exists(instantiatedTypes(_).contains(tpe)) + _instantiatedTypesDependeeMap.values().iterator().asScala.exists { eOptP ⇒ + instantiatedTypes(eOptP.e).contains(tpe) + } } def newInstantiatedTypes(typeSetEntity: TypeSetEntity, seenTypes: Int): TraversableOnce[ReferenceType] = { - val typeDependee = _instantiatedTypesDependeeMap(typeSetEntity) + val typeDependee = _instantiatedTypesDependeeMap.get(typeSetEntity) if (typeDependee.hasUBP) { typeDependee.ub.dropOldest(seenTypes) } else { @@ -92,7 +96,7 @@ class PropagationBasedCGState( } def removeCallSite(instantiatedType: ObjectType): Unit = { - _virtualCallSites -= instantiatedType.id.toLong + _virtualCallSites.remove(instantiatedType.id.toLong) } ///////////////////////////////////////////// @@ -102,10 +106,11 @@ class PropagationBasedCGState( ///////////////////////////////////////////// override def hasOpenDependencies: Boolean = { - _instantiatedTypesDependeeMap.exists(_._2.isRefinable) || super.hasOpenDependencies + super.hasOpenDependencies || + _instantiatedTypesDependeeMap.values().iterator().asScala.exists(_.isRefinable) } override def dependees: Set[SomeEOptionP] = { - super.dependees ++ _instantiatedTypesDependeeMap.valuesIterator + super.dependees ++ _instantiatedTypesDependeeMap.values().asScala } } \ No newline at end of file diff --git a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/xta/TypePropagationAnalysis.scala b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/xta/TypePropagationAnalysis.scala index abbbb474c0..72f6aa042c 100644 --- a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/xta/TypePropagationAnalysis.scala +++ b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/xta/TypePropagationAnalysis.scala @@ -6,7 +6,8 @@ package analyses package cg package xta -import org.opalj.br.ArrayType +import scala.collection.JavaConverters.asScalaIteratorConverter + import org.opalj.br.Code import org.opalj.br.DeclaredMethod import org.opalj.br.DefinedMethod @@ -24,6 +25,7 @@ import org.opalj.br.fpcf.properties.cg.InstantiatedTypes import org.opalj.br.instructions.CHECKCAST import org.opalj.br.instructions.INVOKESTATIC import org.opalj.collection.immutable.UIDSet +import org.opalj.collection.mutable.RefArrayBuffer import org.opalj.fpcf.EPS import org.opalj.fpcf.EUBP import org.opalj.fpcf.Entity @@ -37,7 +39,6 @@ import org.opalj.fpcf.Results import org.opalj.fpcf.SomeEPS import org.opalj.fpcf.SomePartialResult import org.opalj.tac.fpcf.properties.TACAI -import scala.collection.mutable.ListBuffer /** * This analysis handles the type propagation of XTA, MTA, FTA and CTA call graph @@ -52,6 +53,7 @@ final class TypePropagationAnalysis private[analyses] ( selectTypeSetEntity: TypeSetEntitySelector ) extends ReachableMethodAnalysis { + private[this] val debug = false private[this] val _trace: TypePropagationTrace = new TypePropagationTrace() private type State = TypePropagationState @@ -65,24 +67,24 @@ final class TypePropagationAnalysis private[analyses] ( val instantiatedTypesEOptP = propertyStore(typeSetEntity, InstantiatedTypes.key) val calleesEOptP = propertyStore(definedMethod, Callees.key) - _trace.traceInit(definedMethod) + if (debug) _trace.traceInit(definedMethod) implicit val state: TypePropagationState = new TypePropagationState(definedMethod, typeSetEntity, tacEP, instantiatedTypesEOptP, calleesEOptP) - implicit val partialResults: ListBuffer[SomePartialResult] = new ListBuffer[SomePartialResult]() + implicit val partialResults: RefArrayBuffer[SomePartialResult] = RefArrayBuffer.empty[SomePartialResult] if (calleesEOptP.hasUBP) processCallees(calleesEOptP.ub) processTACStatements processArrayTypes(state.ownInstantiatedTypes) - returnResults(partialResults) + returnResults(partialResults.iterator()) } /** * Processes the method upon initialization. Finds field/array accesses and wires up dependencies accordingly. */ - private def processTACStatements(implicit state: State, partialResults: ListBuffer[SomePartialResult]): Unit = { + private def processTACStatements(implicit state: State, partialResults: RefArrayBuffer[SomePartialResult]): Unit = { val bytecode = state.method.definedMethod.body.get val tac = state.tac tac.stmts.foreach { @@ -132,16 +134,18 @@ final class TypePropagationAnalysis private[analyses] ( private def c(state: State)(eps: SomeEPS): ProperPropertyComputationResult = eps match { case EUBP(e: DefinedMethod, _: Callees) ⇒ - assert(e == state.method) - _trace.traceCalleesUpdate(e) + if (debug) { + assert(e == state.method) + _trace.traceCalleesUpdate(e) + } handleUpdateOfCallees(eps.asInstanceOf[EPS[DefinedMethod, Callees]])(state) case EUBP(e: TypeSetEntity, t: InstantiatedTypes) if e == state.typeSetEntity ⇒ - _trace.traceTypeUpdate(state.method, e, t.types) + if (debug) _trace.traceTypeUpdate(state.method, e, t.types) handleUpdateOfOwnTypeSet(eps.asInstanceOf[EPS[TypeSetEntity, InstantiatedTypes]])(state) case EUBP(e: TypeSetEntity, t: InstantiatedTypes) ⇒ - _trace.traceTypeUpdate(state.method, e, t.types) + if (debug) _trace.traceTypeUpdate(state.method, e, t.types) handleUpdateOfBackwardPropagationTypeSet(eps.asInstanceOf[EPS[TypeSetEntity, InstantiatedTypes]])(state) case _ ⇒ @@ -155,9 +159,9 @@ final class TypePropagationAnalysis private[analyses] ( state: State ): ProperPropertyComputationResult = { state.updateCalleeDependee(eps) - implicit val partialResults: ListBuffer[SomePartialResult] = new ListBuffer[SomePartialResult]() + implicit val partialResults: RefArrayBuffer[SomePartialResult] = RefArrayBuffer.empty[SomePartialResult] processCallees(eps.ub) - returnResults(partialResults) + returnResults(partialResults.iterator()) } private def handleUpdateOfOwnTypeSet( @@ -170,8 +174,8 @@ final class TypePropagationAnalysis private[analyses] ( state.updateOwnInstantiatedTypesDependee(eps) val unseenTypes = UIDSet(eps.ub.dropOldest(previouslySeenTypes).toSeq: _*) - implicit val partialResults: ListBuffer[SomePartialResult] = new ListBuffer[SomePartialResult]() - for (fpe ← state.forwardPropagationEntities) { + implicit val partialResults: RefArrayBuffer[SomePartialResult] = RefArrayBuffer.empty[SomePartialResult] + for (fpe ← state.forwardPropagationEntities.iterator().asScala) { val filters = state.forwardPropagationFilters(fpe) val propagation = propagateTypes(fpe, unseenTypes, filters) if (propagation.isDefined) @@ -180,7 +184,7 @@ final class TypePropagationAnalysis private[analyses] ( processArrayTypes(unseenTypes) - returnResults(partialResults) + returnResults(partialResults.iterator()) } private def handleUpdateOfBackwardPropagationTypeSet( @@ -195,7 +199,7 @@ final class TypePropagationAnalysis private[analyses] ( val unseenTypes = UIDSet(eps.ub.dropOldest(previouslySeenTypes).toSeq: _*) val filters = state.backwardPropagationFilters(typeSetEntity) - val propagationResult = propagateTypes(state.typeSetEntity, unseenTypes, filters.toSet) + val propagationResult = propagateTypes(state.typeSetEntity, unseenTypes, filters) returnResults(propagationResult) } @@ -205,7 +209,7 @@ final class TypePropagationAnalysis private[analyses] ( )( implicit state: State, - partialResults: ListBuffer[SomePartialResult] + partialResults: RefArrayBuffer[SomePartialResult] ): Unit = { for (t ← unseenTypes if t.isArrayType; at = t.asArrayType if at.elementType.isReferenceType) { if (state.methodWritesArrays) { @@ -231,7 +235,7 @@ final class TypePropagationAnalysis private[analyses] ( )( implicit state: State, - partialResults: ListBuffer[SomePartialResult] + partialResults: RefArrayBuffer[SomePartialResult] ): Unit = { val bytecode = state.method.definedMethod.body.get for { @@ -263,7 +267,7 @@ final class TypePropagationAnalysis private[analyses] ( )( implicit state: State, - partialResults: ListBuffer[SomePartialResult] + partialResults: RefArrayBuffer[SomePartialResult] ): Unit = { val params = UIDSet.newBuilder[ReferenceType] @@ -299,7 +303,7 @@ final class TypePropagationAnalysis private[analyses] ( )( implicit state: State, - partialResults: ListBuffer[SomePartialResult] + partialResults: RefArrayBuffer[SomePartialResult] ): Unit = { val returnValueIsUsed = { val tacIndex = state.tac.properStmtIndexForPC(pc) @@ -334,7 +338,7 @@ final class TypePropagationAnalysis private[analyses] ( )( implicit state: State, - partialResults: ListBuffer[SomePartialResult] + partialResults: RefArrayBuffer[SomePartialResult] ): Unit = { // Propagation from and to the same entity can be ignored. val typeSetEntity = selectTypeSetEntity(e) @@ -356,7 +360,7 @@ final class TypePropagationAnalysis private[analyses] ( )( implicit state: State, - partialResults: ListBuffer[SomePartialResult] + partialResults: RefArrayBuffer[SomePartialResult] ): Unit = { val typeSetEntity = selectTypeSetEntity(e) if (typeSetEntity == state.typeSetEntity) { @@ -419,9 +423,12 @@ final class TypePropagationAnalysis private[analyses] ( // The other option is that the candidate is also a project type, in which case we should have gotten a // definitive Yes/No answer before. Since we didn't get one, the candidate type probably has a supertype // which is not a project type. In that case, the above argument applies similarly. - val filterTypeIsProjectType = filterType match { - case ot: ObjectType ⇒ project.isProjectType(ot) - case at: ArrayType ⇒ project.isProjectType(at.elementType.asObjectType) + + val filterTypeIsProjectType = if (filterType.isObjectType) { + project.isProjectType(filterType.asObjectType) + } else { + val at = filterType.asArrayType + project.isProjectType(at.elementType.asObjectType) } !filterTypeIsProjectType @@ -438,10 +445,21 @@ final class TypePropagationAnalysis private[analyses] ( return None; } - val filteredTypes = newTypes.filter(nt ⇒ filters.exists(f ⇒ candidateMatchesTypeFilter(nt, f))) + val filteredTypes = newTypes.foldLeft(UIDSet.newBuilder[ReferenceType]) { (builder, nt) ⇒ + val fitr = filters.iterator + var canditateMatches = false + while (!canditateMatches && fitr.hasNext) { + val tf = fitr.next + if (candidateMatchesTypeFilter(nt, tf)) { + canditateMatches = true + builder += nt + } + } + builder + }.result() if (filteredTypes.nonEmpty) { - _trace.traceTypePropagation(targetSetEntity, filteredTypes) + if (debug) _trace.traceTypePropagation(targetSetEntity, filteredTypes) val partialResult = PartialResult[E, InstantiatedTypes]( targetSetEntity, InstantiatedTypes.key, diff --git a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/xta/TypePropagationState.scala b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/xta/TypePropagationState.scala index e4cf3be12c..506ac90b6a 100644 --- a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/xta/TypePropagationState.scala +++ b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/xta/TypePropagationState.scala @@ -18,8 +18,11 @@ import org.opalj.collection.immutable.UIDSet import org.opalj.fpcf.EOptionP import org.opalj.fpcf.SomeEOptionP import org.opalj.tac.fpcf.properties.TACAI +import java.util.{HashSet ⇒ JHashSet} +import java.util.{HashMap ⇒ JHashMap} +import java.util.{Set ⇒ JSet} -import scala.collection.mutable +import scala.collection.JavaConverters.asScalaIteratorConverter /** * Manages the state of each method analyzed by [[TypePropagationAnalysis]]. @@ -73,7 +76,7 @@ final class TypePropagationState( // // ///////////////////////////////////////////// - private[this] var _seenCallees: mutable.Set[(PC, DeclaredMethod)] = mutable.Set.empty + private[this] val _seenCallees: JSet[(PC, DeclaredMethod)] = new JHashSet() def isSeenCallee(pc: PC, callee: DeclaredMethod): Boolean = _seenCallees.contains((pc, callee)) @@ -100,12 +103,14 @@ final class TypePropagationState( // // ///////////////////////////////////////////// - private[this] var _forwardPropagationEntities: mutable.Set[TypeSetEntity] = mutable.Set.empty - private[this] var _forwardPropagationFilters: mutable.Map[TypeSetEntity, UIDSet[ReferenceType]] = mutable.Map.empty + private[this] val _forwardPropagationEntities: JSet[TypeSetEntity] = new JHashSet() + private[this] val _forwardPropagationFilters: JHashMap[TypeSetEntity, UIDSet[ReferenceType]] = + new JHashMap() - def forwardPropagationEntities: Traversable[TypeSetEntity] = _forwardPropagationEntities + def forwardPropagationEntities: JSet[TypeSetEntity] = _forwardPropagationEntities - def forwardPropagationFilters(typeSetEntity: TypeSetEntity): UIDSet[ReferenceType] = _forwardPropagationFilters(typeSetEntity) + def forwardPropagationFilters(typeSetEntity: TypeSetEntity): UIDSet[ReferenceType] = + _forwardPropagationFilters.get(typeSetEntity) /** * Registers a new set entity to consider for forward propagation alongside a set of filters. If the @@ -127,13 +132,13 @@ final class TypePropagationState( val alreadyExists = _forwardPropagationEntities.contains(typeSetEntity) if (!alreadyExists) { val compactedFilters = rootTypes(typeFilters) - _forwardPropagationEntities += typeSetEntity - _forwardPropagationFilters += typeSetEntity → compactedFilters + _forwardPropagationEntities.add(typeSetEntity) + _forwardPropagationFilters.put(typeSetEntity, compactedFilters) true } else { - val existingTypeFilters = _forwardPropagationFilters(typeSetEntity) + val existingTypeFilters = _forwardPropagationFilters.get(typeSetEntity) val newFilters = rootTypes(existingTypeFilters union typeFilters) - _forwardPropagationFilters.update(typeSetEntity, newFilters) + _forwardPropagationFilters.put(typeSetEntity, newFilters) newFilters != existingTypeFilters } } @@ -144,12 +149,13 @@ final class TypePropagationState( // // ///////////////////////////////////////////// - private[this] var _backwardPropagationDependees: mutable.Map[TypeSetEntity, EOptionP[TypeSetEntity, InstantiatedTypes]] = - mutable.Map.empty - private[this] var _backwardPropagationFilters: mutable.Map[TypeSetEntity, UIDSet[ReferenceType]] = mutable.Map.empty + private[this] val _backwardPropagationDependees: JHashMap[TypeSetEntity, EOptionP[TypeSetEntity, InstantiatedTypes]] = + new JHashMap() + private[this] val _backwardPropagationFilters: JHashMap[TypeSetEntity, UIDSet[ReferenceType]] = + new JHashMap() def backwardPropagationDependeeInstantiatedTypes(typeSetEntity: TypeSetEntity): UIDSet[ReferenceType] = { - val dependee = _backwardPropagationDependees(typeSetEntity) + val dependee = _backwardPropagationDependees.get(typeSetEntity) if (dependee.hasUBP) dependee.ub.types else @@ -157,10 +163,10 @@ final class TypePropagationState( } def backwardPropagationDependeeIsRegistered(typeSetEntity: TypeSetEntity): Boolean = - _backwardPropagationDependees.contains(typeSetEntity) + _backwardPropagationDependees.containsKey(typeSetEntity) def backwardPropagationFilters(typeSetEntity: TypeSetEntity): UIDSet[ReferenceType] = - _backwardPropagationFilters(typeSetEntity) + _backwardPropagationFilters.get(typeSetEntity) def updateBackwardPropagationFilters( typeSetEntity: TypeSetEntity, @@ -170,25 +176,25 @@ final class TypePropagationState( classHierarchy: ClassHierarchy ): Boolean = { assert(typeFilters.nonEmpty) - val alreadyExists = _backwardPropagationFilters.contains(typeSetEntity) + val alreadyExists = _backwardPropagationFilters.containsKey(typeSetEntity) if (!alreadyExists) { val compactedFilters = rootTypes(typeFilters) - _backwardPropagationFilters += typeSetEntity → compactedFilters + _backwardPropagationFilters.put(typeSetEntity, compactedFilters) true } else { - val existingTypeFilters = _backwardPropagationFilters(typeSetEntity) + val existingTypeFilters = _backwardPropagationFilters.get(typeSetEntity) val newFilters = rootTypes(existingTypeFilters union typeFilters) - _backwardPropagationFilters.update(typeSetEntity, newFilters) + _backwardPropagationFilters.put(typeSetEntity, newFilters) newFilters != existingTypeFilters } } def updateBackwardPropagationDependee(eps: EOptionP[TypeSetEntity, InstantiatedTypes]): Unit = { - _backwardPropagationDependees.update(eps.e, eps) + _backwardPropagationDependees.put(eps.e, eps) } def seenTypes(typeSetEntity: TypeSetEntity): Int = { - val dependee = _backwardPropagationDependees(typeSetEntity) + val dependee = _backwardPropagationDependees.get(typeSetEntity) if (dependee.hasUBP) dependee.ub.numElements else @@ -205,7 +211,7 @@ final class TypePropagationState( super.hasOpenDependencies || _ownInstantiatedTypesDependee.isRefinable || _calleeDependee.isRefinable || - _backwardPropagationDependees.nonEmpty + !_backwardPropagationDependees.isEmpty } override def dependees: Set[SomeEOptionP] = { @@ -218,7 +224,7 @@ final class TypePropagationState( // Note: The values are copied here. The "++" operator on List // forces immediate evaluation of the map values iterator. - dependees ++= _backwardPropagationDependees.valuesIterator + dependees ++= _backwardPropagationDependees.values().iterator().asScala dependees }