@@ -21,6 +21,7 @@ import org.opalj.br.fpcf.properties.cg.NoCallers
2121import org .opalj .br .instructions .INVOKESPECIAL
2222import org .opalj .br .instructions .NEW
2323import org .opalj .collection .immutable .UIDSet
24+ import org .opalj .collection .mutable .RefArrayBuffer
2425import org .opalj .fpcf .EOptionP
2526import org .opalj .fpcf .EPK
2627import org .opalj .fpcf .EPS
@@ -37,9 +38,6 @@ import org.opalj.fpcf.Results
3738import org .opalj .fpcf .SomeEPS
3839import org .opalj .fpcf .UBP
3940
40- import scala .collection .mutable
41- import scala .collection .mutable .ListBuffer
42-
4341/**
4442 * Marks types as instantiated if their constructor is invoked. Constructors invoked by subclass
4543 * constructors do not result in additional instantiated types.
@@ -106,7 +104,7 @@ class InstantiatedTypesAnalysis private[analyses] (
106104 seenCallers : Set [DeclaredMethod ]
107105 ): PropertyComputationResult = {
108106 var newSeenCallers = seenCallers
109- val partialResults = new ListBuffer [PartialResult [TypeSetEntity , InstantiatedTypes ]]()
107+ val partialResults = RefArrayBuffer .empty [PartialResult [TypeSetEntity , InstantiatedTypes ]]
110108 for {
111109 (caller, _, _) ← callersUB.callers
112110 // if we already analyzed the caller, we do not need to do it twice
@@ -128,15 +126,15 @@ class InstantiatedTypesAnalysis private[analyses] (
128126 continuation(declaredMethod, declaredType, newSeenCallers)
129127 )
130128
131- Results (reRegistration, partialResults)
129+ Results (reRegistration, partialResults.iterator() )
132130 }
133131 }
134132
135133 private [this ] def processSingleCaller (
136134 declaredMethod : DeclaredMethod ,
137135 declaredType : ObjectType ,
138136 caller : DeclaredMethod ,
139- partialResults : ListBuffer [PartialResult [TypeSetEntity , InstantiatedTypes ]]
137+ partialResults : RefArrayBuffer [PartialResult [TypeSetEntity , InstantiatedTypes ]]
140138 ): Unit = {
141139 // a constructor is called by a non-constructor method, there will be an initialization.
142140 if (caller.name != " <init>" ) {
@@ -273,28 +271,29 @@ class InstantiatedTypesAnalysisScheduler(
273271 val packageIsClosed = p.get(ClosedPackagesKey )
274272 val declaredMethods = p.get(DeclaredMethodsKey )
275273 val entryPoints = p.get(InitialEntryPointsKey )
276- val initialInstantiatedTypes = p.get(InitialInstantiatedTypesKey ).toSet
274+ val initialInstantiatedTypes =
275+ UIDSet [ReferenceType ](p.get(InitialInstantiatedTypesKey ).toSeq: _* )
277276
278277 // While processing entry points and fields, we keep track of all array types we see, as
279278 // well as subtypes and lower-dimensional types. These types also need to be
280279 // pre-initialized. Note: This set only contains ArrayTypes whose element type is an
281280 // ObjectType. Arrays of primitive types can be ignored.
282- val seenArrayTypes = mutable. Set [ArrayType ]()
281+ val seenArrayTypes = UIDSet .newBuilder [ArrayType ]
283282
284- def initialize (setEntity : TypeSetEntity , types : Traversable [ReferenceType ]): Unit = {
283+ def initialize (setEntity : TypeSetEntity , types : UIDSet [ReferenceType ]): Unit = {
285284 ps.preInitialize(setEntity, InstantiatedTypes .key) {
286285 case UBP (typeSet) ⇒
287286 InterimEUBP (setEntity, typeSet.updated(types))
288287 case _ : EPK [_, _] ⇒
289- InterimEUBP (setEntity, InstantiatedTypes (UIDSet ( types.toSeq : _* ) ))
288+ InterimEUBP (setEntity, InstantiatedTypes (types))
290289 case eps ⇒
291290 sys.error(s " unexpected property: $eps" )
292291 }
293292 }
294293
295294 // Some cooperative analyses originally meant for RTA may require the global type set
296295 // to be pre-initialized. For that purpose, an empty type set is sufficient.
297- initialize(p, Traversable .empty)
296+ initialize(p, UIDSet .empty)
298297
299298 def isRelevantArrayType (rt : Type ): Boolean =
300299 rt.isArrayType && rt.asArrayType.elementType.isObjectType
@@ -305,8 +304,8 @@ class InstantiatedTypesAnalysisScheduler(
305304 ep ← entryPoints;
306305 dm = declaredMethods(ep)
307306 ) {
308- val typeFilters = mutable. Set [ReferenceType ]()
309- val arrayTypeAssignments = mutable. Set [ArrayType ]()
307+ val typeFilters = UIDSet .newBuilder [ReferenceType ]
308+ val arrayTypeAssignments = UIDSet .newBuilder [ArrayType ]
310309
311310 if (! dm.definedMethod.isStatic) {
312311 typeFilters += dm.declaringClassType
@@ -330,18 +329,18 @@ class InstantiatedTypesAnalysisScheduler(
330329 }
331330
332331 // Initial assignments of ObjectTypes
333- val objectTypeAssignments = initialInstantiatedTypes.filter(iit ⇒ typeFilters.exists(tf ⇒
334- p.classHierarchy.isSubtypeOf(iit, tf)))
332+ val objectTypeAssignments = initialInstantiatedTypes.filter(iit ⇒
333+ typeFilters.result().exists(tf ⇒ p.classHierarchy.isSubtypeOf(iit, tf)))
335334
336- val initialAssignment = arrayTypeAssignments ++ objectTypeAssignments
335+ val initialAssignment = objectTypeAssignments ++ arrayTypeAssignments.result()
337336
338337 val dmSetEntity = selectSetEntity(dm)
339338
340339 initialize(dmSetEntity, initialAssignment)
341340 }
342341
343342 // Returns true if the field's type indicates that the field should be pre-initialized.
344- def fieldIsRelevant (f : Field ): Boolean = {
343+ @ inline def fieldIsRelevant (f : Field ): Boolean = {
345344 // Only fields which are ArrayType or ObjectType are relevant.
346345 f.fieldType.isReferenceType &&
347346 // If the field is an ArrayType, then the array's element type must be an ObjectType.
@@ -372,25 +371,32 @@ class InstantiatedTypesAnalysisScheduler(
372371 // Assign initial types to all accessable fields.
373372 p.classFile(ot) match {
374373 case Some (cf) ⇒
375- for (f ← cf.fields if fieldIsRelevant(f) && f.isNotFinal && fieldIsAccessible(f)) {
374+ for (f ← cf.fields if f.isNotFinal && fieldIsRelevant(f) && fieldIsAccessible(f)) {
376375 val fieldType = f.fieldType.asReferenceType
377-
378- val initialAssignments = fieldType match {
379- case ot : ObjectType ⇒
380- initialInstantiatedTypes.filter(
381- p.classHierarchy.isSubtypeOf(_, ot)
382- )
383-
384- case at : ArrayType ⇒
385- seenArrayTypes += at
386-
387- val dim = at.dimensions
388- val et = at.elementType.asObjectType
389- p.classHierarchy.allSubtypes(et, reflexive = true )
390- .intersect(initialInstantiatedTypes).map(
391- ArrayType (dim, _)
392- )
393-
376+ import p .classHierarchy
377+
378+ val initialAssignments = if (fieldType.isObjectType) {
379+ val ot = fieldType.asObjectType
380+ initialInstantiatedTypes.foldLeft(UIDSet .newBuilder[ReferenceType ]) {
381+ (assignments, iit) ⇒
382+ if (classHierarchy.isSubtypeOf(iit, ot)) {
383+ assignments += iit
384+ }
385+ assignments
386+ }.result()
387+ } else {
388+ val at = fieldType.asArrayType
389+ seenArrayTypes += at
390+ val dim = at.dimensions
391+ val et = at.elementType.asObjectType
392+ val allSubtypes = p.classHierarchy.allSubtypes(et, true )
393+ initialInstantiatedTypes.foldLeft(UIDSet .newBuilder[ReferenceType ]) {
394+ (assignments, iit) ⇒
395+ if (allSubtypes.contains(iit.asObjectType)) {
396+ assignments += ArrayType (dim, iit)
397+ }
398+ assignments
399+ }.result()
394400 }
395401
396402 val fieldSetEntity = selectSetEntity(f)
@@ -407,25 +413,32 @@ class InstantiatedTypesAnalysisScheduler(
407413 // and initialize their type sets.
408414
409415 // Remember which ArrayTypes were processed, so we don't do it twice.
410- val initializedArrayTypes = mutable. Set [ArrayType ]()
416+ val initializedArrayTypes = new java.util. HashSet [ArrayType ]()
411417
412418 def initializeArrayType (at : ArrayType ): Unit = {
413419 // If this type has already been initialized, we skip it.
414420 if (initializedArrayTypes.contains(at)) {
415421 return ;
416422 }
417423
418- initializedArrayTypes += at
424+ initializedArrayTypes.add(at)
419425
420426 val et = at.elementType.asObjectType
421- val subtypes = p.classHierarchy.allSubtypes(et, reflexive = true ).intersect(initialInstantiatedTypes)
427+ val allSubtypes = p.classHierarchy.allSubtypes(et, true )
428+ val subtypes =
429+ initialInstantiatedTypes.foldLeft(UIDSet .newBuilder[ReferenceType ]) { (builder, iit) ⇒
430+ if (allSubtypes.contains(iit.asObjectType)) {
431+ builder += iit
432+ }
433+ builder
434+ }.result()
422435
423436 val dim = at.dimensions
424437 if (dim > 1 ) {
425438 // Initialize multidimensional ArrayType. E.g., if at == A[][] and A is a supertype of A1,
426439 // we need to assign A[] and A1[] to the type set of A[][].
427- val assignedArrayTypes = subtypes.map(ArrayType (dim - 1 , _))
428- initialize(at, assignedArrayTypes)
440+ val assignedArrayTypes : UIDSet [ ArrayType ] = subtypes.map(ArrayType (dim - 1 , _))
441+ initialize(at, assignedArrayTypes. asInstanceOf [ UIDSet [ ReferenceType ]] )
429442
430443 // After that, we also need to initialize the ArrayTypes which were just assigned. It is possible
431444 // that these were types which were not initially seen when processing entry points and fields.
@@ -436,6 +449,6 @@ class InstantiatedTypesAnalysisScheduler(
436449 }
437450 }
438451
439- seenArrayTypes foreach initializeArrayType
452+ seenArrayTypes.result() foreach initializeArrayType
440453 }
441454}
0 commit comments