From 49adbf71eb9c510cb8b153c43c8f47b95ef6dd93 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Wed, 6 Nov 2024 14:06:58 +0000 Subject: [PATCH] Better memory efficiency for Analysis --- .../src/main/java/xsbti/api/SafeLazy.java | 15 +++--- .../src/main/scala/xsbt/api/APIUtil.scala | 46 +++++++++++++------ .../main/scala/xsbt/api/SafeLazyProxy.scala | 5 +- 3 files changed, 43 insertions(+), 23 deletions(-) diff --git a/internal/compiler-interface/src/main/java/xsbti/api/SafeLazy.java b/internal/compiler-interface/src/main/java/xsbti/api/SafeLazy.java index 65ae4a55c..318f75d06 100644 --- a/internal/compiler-interface/src/main/java/xsbti/api/SafeLazy.java +++ b/internal/compiler-interface/src/main/java/xsbti/api/SafeLazy.java @@ -15,7 +15,7 @@ /** * Implement a Scala `lazy val` in Java for the facing sbt interface. - * + *

* It holds a reference to a thunk that is lazily evaluated and then * its reference is clear to avoid memory leaks in memory-intensive code. * It needs to be defined in [[xsbti]] or a subpackage, see [[xsbti.api.Lazy]] @@ -34,12 +34,7 @@ public static xsbti.api.Lazy apply(Supplier sbtThunk) { /** Return a sbt [[xsbti.api.Lazy]] from a strict value. */ public static xsbti.api.Lazy strict(T value) { // Convert strict parameter to sbt function returning it - return apply(new Supplier() { - @Override - public T get() { - return value; - } - }); + return new StrictImpl(value); } private static final class Thunky { @@ -68,4 +63,10 @@ public T get() { return t.result; } } + + private static final class StrictImpl extends xsbti.api.AbstractLazy { + private final T value; + StrictImpl(T value) { this.value = value; } + public T get() { return value; } + } } diff --git a/internal/zinc-apiinfo/src/main/scala/xsbt/api/APIUtil.scala b/internal/zinc-apiinfo/src/main/scala/xsbt/api/APIUtil.scala index 567e0f44f..578bd6aab 100644 --- a/internal/zinc-apiinfo/src/main/scala/xsbt/api/APIUtil.scala +++ b/internal/zinc-apiinfo/src/main/scala/xsbt/api/APIUtil.scala @@ -62,7 +62,7 @@ object APIUtil { def minimizeDefinition(d: Definition): Array[Definition] = d match { case c: ClassLike => Array(minimizeClass(c)) - case _ => Array() + case _ => emptyDefs } def minimizeClass(c: ClassLike): ClassLike = { val savedAnnotations = Discovery.defAnnotations(c.structure, (_: Any) => true).toArray[String] @@ -73,7 +73,7 @@ object APIUtil { c.modifiers, c.annotations, c.definitionType, - lzy(emptyType), + emptyTypeLzy, lzy(struct), savedAnnotations, c.childrenOfSealedClass, @@ -91,8 +91,10 @@ object APIUtil { def filterDefinitions( ds: Array[ClassDefinition], isModule: Boolean - ): Lazy[Array[ClassDefinition]] = - lzy(if (isModule) ds filter Discovery.isMainMethod else Array()) + ): Lazy[Array[ClassDefinition]] = { + val mains = if (isModule) ds.filter(Discovery.isMainMethod) else emptyClassDefs + if (mains.isEmpty) emptyClassDefsLzy else lzy(mains) + } def isNonPrivate(d: Definition): Boolean = isNonPrivate(d.access) @@ -104,23 +106,41 @@ object APIUtil { } private val emptyModifiers = new Modifiers(false, false, false, false, false, false, false, false) - private val emptyStructure = Structure.of(lzy(Array.empty), lzy(Array.empty), lzy(Array.empty)) - def emptyClassLike(name: String, definitionType: DefinitionType): ClassLike = - xsbti.api.ClassLike.of( - name, + private[this] val emptyType = EmptyType.of() + private val emptyTypeLzy = lzy(emptyType: Type) + private val emptyDefs = Array.empty[Definition] + private val emptyClassDefs = Array.empty[ClassDefinition] + private val emptyClassDefsLzy = lzy(emptyClassDefs) + private val emptyStructure = Structure.of(lzy(Array.empty), emptyClassDefsLzy, emptyClassDefsLzy) + private val emptyStructureLzy = lzy(emptyStructure) + private val emptyClassLikeTemplate = + ClassLike.of( + null, Public.of(), emptyModifiers, Array.empty, - definitionType, - lzy(emptyType), - lzy(emptyStructure), + null, + emptyTypeLzy, + emptyStructureLzy, Array.empty, Array.empty, true, Array.empty ) + def emptyClassLike(name: String, definitionType: DefinitionType): ClassLike = + ClassLike.of( + name, + emptyClassLikeTemplate.access, + emptyClassLikeTemplate.modifiers, + emptyClassLikeTemplate.annotations, + definitionType, + emptyTypeLzy, + emptyStructureLzy, + emptyClassLikeTemplate.savedAnnotations, + emptyClassLikeTemplate.childrenOfSealedClass, + emptyClassLikeTemplate.topLevel, + emptyClassLikeTemplate.typeParameters, + ) private[this] def lzy[T <: AnyRef](t: T): Lazy[T] = SafeLazyProxy.strict(t) - - private[this] val emptyType = EmptyType.of() } diff --git a/internal/zinc-apiinfo/src/main/scala/xsbt/api/SafeLazyProxy.scala b/internal/zinc-apiinfo/src/main/scala/xsbt/api/SafeLazyProxy.scala index 996255e10..efc22150a 100644 --- a/internal/zinc-apiinfo/src/main/scala/xsbt/api/SafeLazyProxy.scala +++ b/internal/zinc-apiinfo/src/main/scala/xsbt/api/SafeLazyProxy.scala @@ -15,7 +15,7 @@ import java.util.function.Supplier /** * Proxy `SafeLazy` functionality from the Java implementation - * implementation in xsbt.api.SafeLazy to Scala helpers. + * in xsbt.api.SafeLazy to Scala helpers. * * The implementation of these helpers are not reused between each * other because they create intermediate anonymous functions and @@ -35,7 +35,6 @@ object SafeLazyProxy { * Return a lazy implementation of a strict value. */ def strict[T](s: T): Lazy[T] = { - val sbtThunk = new Supplier[T] { override def get() = s } - SafeLazy.apply(sbtThunk) + SafeLazy.strict(s) } }