8
8
package sbt .internal .inc .binary .converters
9
9
10
10
import java .io .File
11
+ import scala .collection .mutable
11
12
12
13
import sbt .internal .inc .Relations .ClassDependencies
13
14
import sbt .internal .inc ._
@@ -21,9 +22,18 @@ import sbt.internal.inc.binary.converters.ProtobufDefaults.{ Classes, ReadersCon
21
22
import sbt .internal .util .Relation
22
23
import xsbti .api ._
23
24
25
+ /**
26
+ * Each instance of this class will intern (most) deserialized strings in one (instance-level)
27
+ * pool, so it's recommended to use a new instance per deserialized top-level object (generally
28
+ * `AnalysisFile`).
29
+ */
24
30
final class ProtobufReaders (mapper : ReadMapper ) {
31
+ private [this ] val internMap = mutable.Map [String , String ]()
32
+
33
+ private [this ] def intern (str : String ): String = internMap.getOrElseUpdate(str, str)
34
+
25
35
def fromPathString (path : String ): File = {
26
- java.nio.file.Paths .get(path).toFile
36
+ java.nio.file.Paths .get(intern( path) ).toFile
27
37
}
28
38
29
39
def fromStampType (stampType : schema.Stamps .StampType ): Stamp = {
@@ -117,7 +127,7 @@ final class ProtobufReaders(mapper: ReadMapper) {
117
127
def fromPosition (position : schema.Position ): Position = {
118
128
import ProtobufDefaults .{ MissingString , MissingInt }
119
129
def fromString (value : String ): Option [String ] =
120
- if (value == MissingString ) None else Some (value)
130
+ if (value == MissingString ) None else Some (intern( value) )
121
131
def fromInt (value : Int ): Option [Integer ] =
122
132
if (value == MissingInt ) None else Some (value)
123
133
InterfaceUtil .position(
@@ -151,7 +161,7 @@ final class ProtobufReaders(mapper: ReadMapper) {
151
161
}
152
162
153
163
def fromSourceInfo (sourceInfo : schema.SourceInfo ): SourceInfo = {
154
- val mainClasses = sourceInfo.mainClasses
164
+ val mainClasses = sourceInfo.mainClasses.map(intern)
155
165
val reportedProblems = sourceInfo.reportedProblems.map(fromProblem)
156
166
val unreportedProblems = sourceInfo.unreportedProblems.map(fromProblem)
157
167
SourceInfos .makeInfo(reported = reportedProblems,
@@ -240,7 +250,7 @@ final class ProtobufReaders(mapper: ReadMapper) {
240
250
import SchemaPath .{ Component => SchemaComponent }
241
251
import Classes .{ Component , PathComponent }
242
252
pathComponent.component match {
243
- case SchemaComponent .Id (c) => Id .of(c.id)
253
+ case SchemaComponent .Id (c) => Id .of(intern( c.id) )
244
254
case SchemaComponent .Super (c) =>
245
255
Super .of(c.qualifier.read(fromPath, ExpectedPathInSuper ))
246
256
case SchemaComponent .This (_) => ReadersConstants .This
@@ -253,8 +263,8 @@ final class ProtobufReaders(mapper: ReadMapper) {
253
263
254
264
def fromAnnotation (annotation : schema.Annotation ): Annotation = {
255
265
def fromAnnotationArgument (argument : schema.AnnotationArgument ): AnnotationArgument = {
256
- val name = argument.name
257
- val value = argument.value
266
+ val name = intern( argument.name)
267
+ val value = intern( argument.value)
258
268
AnnotationArgument .of(name, value)
259
269
}
260
270
@@ -274,7 +284,7 @@ final class ProtobufReaders(mapper: ReadMapper) {
274
284
def fromType (`type` : schema.Type ): Type = {
275
285
import ReadersFeedback .expectedBaseIn
276
286
def fromParameterRef (tpe : schema.Type .ParameterRef ): ParameterRef = {
277
- ParameterRef .of(tpe.id)
287
+ ParameterRef .of(intern( tpe.id) )
278
288
}
279
289
280
290
def fromParameterized (tpe : schema.Type .Parameterized ): Parameterized = {
@@ -291,7 +301,7 @@ final class ProtobufReaders(mapper: ReadMapper) {
291
301
292
302
def fromConstant (tpe : schema.Type .Constant ): Constant = {
293
303
val baseType = tpe.baseType.read(fromType, expectedBaseIn(Classes .Constant ))
294
- val value = tpe.value
304
+ val value = intern( tpe.value)
295
305
Constant .of(baseType, value)
296
306
}
297
307
@@ -307,7 +317,7 @@ final class ProtobufReaders(mapper: ReadMapper) {
307
317
}
308
318
309
319
def fromProjection (tpe : schema.Type .Projection ): Projection = {
310
- val id = tpe.id
320
+ val id = intern( tpe.id)
311
321
val prefix = tpe.prefix.read(fromType, ReadersFeedback .ExpectedPrefixInProjection )
312
322
Projection .of(prefix, id)
313
323
}
@@ -340,7 +350,7 @@ final class ProtobufReaders(mapper: ReadMapper) {
340
350
def fromQualifier (qualifier : schema.Qualifier ): Qualifier = {
341
351
import schema .Qualifier .{ Type => QualifierType }
342
352
qualifier.`type` match {
343
- case QualifierType .IdQualifier (q) => IdQualifier .of(q.value)
353
+ case QualifierType .IdQualifier (q) => IdQualifier .of(intern( q.value) )
344
354
case QualifierType .ThisQualifier (_) => ReadersConstants .ThisQualifier
345
355
case QualifierType .Unqualified (_) => ReadersConstants .Unqualified
346
356
case QualifierType .Empty => ReadersFeedback .ExpectedNonEmptyQualifier .!!
@@ -376,7 +386,7 @@ final class ProtobufReaders(mapper: ReadMapper) {
376
386
ExpectedUpperBoundInTypeDeclaration
377
387
}
378
388
379
- val name = classDefinition.name
389
+ val name = intern( classDefinition.name)
380
390
val access = classDefinition.access.read(fromAccess, MissingAccessInDef )
381
391
val modifiers = classDefinition.modifiers.read(fromModifiers, MissingModifiersInDef )
382
392
val annotations = classDefinition.annotations.toZincArray(fromAnnotation)
@@ -392,7 +402,7 @@ final class ProtobufReaders(mapper: ReadMapper) {
392
402
ReadersFeedback .UnrecognizedParamModifier .!!
393
403
}
394
404
}
395
- val name = methodParameter.name
405
+ val name = intern( methodParameter.name)
396
406
val hasDefault = methodParameter.hasDefault
397
407
val `type` = methodParameter.`type`.read(fromType, expectedTypeIn(Classes .MethodParameter ))
398
408
val modifier = fromParameterModifier(methodParameter.modifier)
@@ -463,7 +473,7 @@ final class ProtobufReaders(mapper: ReadMapper) {
463
473
}
464
474
465
475
import ReadersFeedback .{ ExpectedLowerBoundInTypeParameter , ExpectedUpperBoundInTypeParameter }
466
- val id = typeParameter.id
476
+ val id = intern( typeParameter.id)
467
477
val annotations = typeParameter.annotations.toZincArray(fromAnnotation)
468
478
val typeParameters = typeParameter.typeParameters.toZincArray(fromTypeParameter)
469
479
val variance = fromVariance(typeParameter.variance)
@@ -475,7 +485,7 @@ final class ProtobufReaders(mapper: ReadMapper) {
475
485
def fromClassLike (classLike : schema.ClassLike ): ClassLike = {
476
486
def expectedMsg (msg : String ) = ReadersFeedback .expected(msg, Classes .ClassLike )
477
487
def expected (clazz : Class [_]) = expectedMsg(clazz.getName)
478
- val name = classLike.name
488
+ val name = intern( classLike.name)
479
489
val access = classLike.access.read(fromAccess, expected(Classes .Access ))
480
490
val modifiers = classLike.modifiers.read(fromModifiers, expected(Classes .Modifiers ))
481
491
val annotations = classLike.annotations.toZincArray(fromAnnotation)
@@ -484,7 +494,7 @@ final class ProtobufReaders(mapper: ReadMapper) {
484
494
val definitionType = fromDefinitionType(classLike.definitionType)
485
495
val selfType = mkLazy(classLike.selfType.read(fromType, expectedMsg(" self type" )))
486
496
val structure = mkLazy(classLike.structure.read(fromStructure, expected(Classes .Structure )))
487
- val savedAnnotations = classLike.savedAnnotations.toArray
497
+ val savedAnnotations = classLike.savedAnnotations.map(intern). toArray
488
498
val childrenOfSealedClass = classLike.childrenOfSealedClass.toZincArray(fromType)
489
499
val topLevel = classLike.topLevel
490
500
val typeParameters = classLike.typeParameters.toZincArray(fromTypeParameter)
@@ -521,7 +531,7 @@ final class ProtobufReaders(mapper: ReadMapper) {
521
531
}
522
532
523
533
def fromNameHash (nameHash : schema.NameHash ): NameHash = {
524
- val name = nameHash.name
534
+ val name = intern( nameHash.name)
525
535
val hash = nameHash.hash
526
536
val scope = fromUseScope(nameHash.scope)
527
537
NameHash .of(name, scope, hash)
@@ -530,15 +540,15 @@ final class ProtobufReaders(mapper: ReadMapper) {
530
540
import SafeLazyProxy .{ strict => mkLazy }
531
541
import ReadersFeedback .ExpectedCompanionsInAnalyzedClass
532
542
val compilationTimestamp = analyzedClass.compilationTimestamp
533
- val name = analyzedClass.name
543
+ val name = intern( analyzedClass.name)
534
544
val api = mkLazy(analyzedClass.api.read(fromCompanions, ExpectedCompanionsInAnalyzedClass ))
535
545
val apiHash = analyzedClass.apiHash
536
546
val nameHashes = analyzedClass.nameHashes.toZincArray(fromNameHash)
537
547
val hasMacro = analyzedClass.hasMacro
538
548
AnalyzedClass .of(compilationTimestamp, name, api, apiHash, nameHashes, hasMacro)
539
549
}
540
550
541
- private final val stringId = identity[ String ] _
551
+ private final val stringId = intern _
542
552
private final val stringToFile = (path : String ) => fromPathString(path)
543
553
def fromRelations (relations : schema.Relations ): Relations = {
544
554
def fromMap [K , V ](map : Map [String , schema.Values ],
@@ -559,7 +569,7 @@ final class ProtobufReaders(mapper: ReadMapper) {
559
569
}
560
570
561
571
def fromUsedName (usedName : schema.UsedName ): UsedName = {
562
- val name = usedName.name
572
+ val name = intern( usedName.name)
563
573
val scopes = usedName.scopes.iterator.map(fromUseScope).toIterable
564
574
UsedName .apply(name, scopes)
565
575
}
@@ -608,8 +618,8 @@ final class ProtobufReaders(mapper: ReadMapper) {
608
618
}
609
619
610
620
def fromApis (apis : schema.APIs ): APIs = {
611
- val internal = apis.internal.mapValues( fromAnalyzedClass)
612
- val external = apis.external.mapValues( fromAnalyzedClass)
621
+ val internal = apis.internal.map { case (k, v) => intern(k) -> fromAnalyzedClass(v) }
622
+ val external = apis.external.map { case (k, v) => intern(k) -> fromAnalyzedClass(v) }
613
623
APIs (internal = internal, external = external)
614
624
}
615
625
0 commit comments