@@ -109,13 +109,12 @@ object Infos {
109
109
/** Things from a given class that are reached by one method. */
110
110
final class ReachabilityInfoInClass private [Infos ] (
111
111
val className : ClassName ,
112
- val fieldsRead : List [FieldName ],
113
- val fieldsWritten : List [FieldName ],
114
- val staticFieldsRead : List [FieldName ],
115
- val staticFieldsWritten : List [FieldName ],
116
- val methodsCalled : List [MethodName ],
117
- val methodsCalledStatically : List [NamespacedMethodName ],
118
- val jsNativeMembersUsed : List [MethodName ],
112
+ /* We use a single field for all members to reduce memory consumption:
113
+ * Typically, there are very few members reached in a single
114
+ * ReachabilityInfoInClass, so the overhead of having a field per type
115
+ * becomes significant in terms of memory usage.
116
+ */
117
+ val memberInfos : Array [MemberReachabilityInfo ], // nullable!
119
118
val flags : ReachabilityInfoInClass .Flags
120
119
)
121
120
@@ -134,6 +133,38 @@ object Infos {
134
133
final val FlagDynamicallyReferenced = 1 << 5
135
134
}
136
135
136
+ sealed trait MemberReachabilityInfo
137
+
138
+ final case class FieldReachable private [Infos ] (
139
+ val fieldName : FieldName ,
140
+ val read : Boolean = false ,
141
+ val written : Boolean = false
142
+ ) extends MemberReachabilityInfo
143
+
144
+ final case class StaticFieldReachable private [Infos ] (
145
+ val fieldName : FieldName ,
146
+ val read : Boolean = false ,
147
+ val written : Boolean = false
148
+ ) extends MemberReachabilityInfo
149
+
150
+ final case class MethodReachable private [Infos ] (
151
+ val methodName : MethodName
152
+ ) extends MemberReachabilityInfo
153
+
154
+ final case class MethodStaticallyReachable private [Infos ] (
155
+ val namespace : MemberNamespace ,
156
+ val methodName : MethodName
157
+ ) extends MemberReachabilityInfo
158
+
159
+ object MethodStaticallyReachable {
160
+ private [Infos ] def apply (m : NamespacedMethodName ): MethodStaticallyReachable =
161
+ MethodStaticallyReachable (m.namespace, m.methodName)
162
+ }
163
+
164
+ final case class JSNativeMemberReachable private [Infos ] (
165
+ val methodName : MethodName
166
+ ) extends MemberReachabilityInfo
167
+
137
168
final class ClassInfoBuilder (
138
169
private val className : ClassName ,
139
170
private val kind : ClassKind ,
@@ -378,33 +409,39 @@ object Infos {
378
409
}
379
410
380
411
final class ReachabilityInfoInClassBuilder (val className : ClassName ) {
381
- private val fieldsRead = mutable.Set .empty[FieldName ]
382
- private val fieldsWritten = mutable.Set .empty[FieldName ]
383
- private val staticFieldsRead = mutable.Set .empty[FieldName ]
384
- private val staticFieldsWritten = mutable.Set .empty[FieldName ]
412
+ private val fieldsUsed = mutable.Map .empty[FieldName , FieldReachable ]
413
+ private val staticFieldsUsed = mutable.Map .empty[FieldName , StaticFieldReachable ]
385
414
private val methodsCalled = mutable.Set .empty[MethodName ]
386
415
private val methodsCalledStatically = mutable.Set .empty[NamespacedMethodName ]
387
416
private val jsNativeMembersUsed = mutable.Set .empty[MethodName ]
388
417
private var flags : ReachabilityInfoInClass .Flags = 0
389
418
390
419
def addFieldRead (field : FieldName ): this .type = {
391
- fieldsRead += field
420
+ fieldsUsed(field) = fieldsUsed
421
+ .getOrElse(field, FieldReachable (field))
422
+ .copy(read = true )
392
423
this
393
424
}
394
425
395
426
def addFieldWritten (field : FieldName ): this .type = {
396
- fieldsWritten += field
427
+ fieldsUsed(field) = fieldsUsed
428
+ .getOrElse(field, FieldReachable (field))
429
+ .copy(written = true )
397
430
this
398
431
}
399
432
400
433
def addStaticFieldRead (field : FieldName ): this .type = {
401
- staticFieldsRead += field
434
+ staticFieldsUsed(field) = staticFieldsUsed
435
+ .getOrElse(field, StaticFieldReachable (field))
436
+ .copy(read = true )
402
437
setStaticallyReferenced()
403
438
this
404
439
}
405
440
406
441
def addStaticFieldWritten (field : FieldName ): this .type = {
407
- staticFieldsWritten += field
442
+ staticFieldsUsed(field) = staticFieldsUsed
443
+ .getOrElse(field, StaticFieldReachable (field))
444
+ .copy(written = true )
408
445
setStaticallyReferenced()
409
446
this
410
447
}
@@ -454,22 +491,20 @@ object Infos {
454
491
setFlag(ReachabilityInfoInClass .FlagStaticallyReferenced )
455
492
456
493
def result (): ReachabilityInfoInClass = {
457
- new ReachabilityInfoInClass (
458
- className,
459
- fieldsRead = toLikelyEmptyList(fieldsRead),
460
- fieldsWritten = toLikelyEmptyList(fieldsWritten),
461
- staticFieldsRead = toLikelyEmptyList(staticFieldsRead),
462
- staticFieldsWritten = toLikelyEmptyList(staticFieldsWritten),
463
- methodsCalled = toLikelyEmptyList(methodsCalled),
464
- methodsCalledStatically = toLikelyEmptyList(methodsCalledStatically),
465
- jsNativeMembersUsed = toLikelyEmptyList(jsNativeMembersUsed),
466
- flags = flags
467
- )
468
- }
494
+ val memberInfos : Array [MemberReachabilityInfo ] = (
495
+ fieldsUsed.valuesIterator ++
496
+ staticFieldsUsed.valuesIterator ++
497
+ methodsCalled.iterator.map(MethodReachable (_)) ++
498
+ methodsCalledStatically.iterator.map(MethodStaticallyReachable (_)) ++
499
+ jsNativeMembersUsed.iterator.map(JSNativeMemberReachable (_))
500
+ ).toArray
501
+
502
+ val memberInfosOrNull =
503
+ if (memberInfos.isEmpty) null
504
+ else memberInfos
469
505
470
- private def toLikelyEmptyList [A ](set : mutable.Set [A ]): List [A ] =
471
- if (set.isEmpty) Nil
472
- else set.toList
506
+ new ReachabilityInfoInClass (className, memberInfosOrNull, flags)
507
+ }
473
508
}
474
509
475
510
/** Generates the [[MethodInfo ]] of a
0 commit comments