Skip to content

Commit

Permalink
Do not cache overall class
Browse files Browse the repository at this point in the history
This reduces some memory overhead for negligible performance cost.

Residual (post link memory) benchmarks for the test suite:
Baseline: 1.13 GB, new 1.01 GB
  • Loading branch information
gzm0 committed Dec 30, 2023
1 parent 0f1d6ce commit 268775c
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -616,9 +616,9 @@ final class Emitter[E >: Null <: js.Transformed.Value](
}

val fullClass = extractChanged {
val fullClassCache = classCache.getFullClassCache()
val fullClassChangeTracker = classCache.getFullClassChangeTracker()

fullClassCache.getOrElseUpdate(linkedClass.version, ctorWithGlobals,
fullClassChangeTracker.trackChanged(linkedClass.version, ctorWithGlobals,
memberMethodsWithGlobals, exportedMembersWithGlobals, {
for {
ctor <- ctorWithGlobals
Expand All @@ -635,7 +635,7 @@ final class Emitter[E >: Null <: js.Transformed.Value](
storeJSSuperClass.map(js.Transformed(_)), // invalidated by class version
useESClass, // invalidated by class version (depends on kind, config and ancestry only)
membersAsTrees, // invalidated directly
)(moduleContext, fullClassCache, linkedClass.pos) // pos invalidated by class version
)(moduleContext, fullClassChangeTracker, linkedClass.pos) // pos invalidated by class version
} yield {
// Avoid a nested post transform if we just got the original members back.
if (clazz eq membersAsTrees) {
Expand Down Expand Up @@ -849,7 +849,7 @@ final class Emitter[E >: Null <: js.Transformed.Value](
private[this] val _exportedMembersCache =
mutable.Map.empty[Int, MethodCache[E]]

private[this] var _fullClassCache: Option[FullClassCache] = None
private[this] var _fullClassChangeTracker: Option[FullClassChangeTracker] = None

override def invalidate(): Unit = {
/* Do not invalidate contained methods, as they have their own
Expand All @@ -865,7 +865,7 @@ final class Emitter[E >: Null <: js.Transformed.Value](
_methodCaches.foreach(_.valuesIterator.foreach(_.startRun()))
_memberMethodCache.valuesIterator.foreach(_.startRun())
_constructorCache.foreach(_.startRun())
_fullClassCache.foreach(_.startRun())
_fullClassChangeTracker.foreach(_.startRun())
}

def getCache(version: Version): (DesugaredClassCache[E], Boolean) = {
Expand Down Expand Up @@ -904,10 +904,10 @@ final class Emitter[E >: Null <: js.Transformed.Value](
def getExportedMemberCache(idx: Int): MethodCache[E] =
_exportedMembersCache.getOrElseUpdate(idx, new MethodCache)

def getFullClassCache(): FullClassCache = {
_fullClassCache.getOrElse {
val cache = new FullClassCache
_fullClassCache = Some(cache)
def getFullClassChangeTracker(): FullClassChangeTracker = {
_fullClassChangeTracker.getOrElse {
val cache = new FullClassChangeTracker
_fullClassChangeTracker = Some(cache)
cache
}
}
Expand All @@ -921,8 +921,8 @@ final class Emitter[E >: Null <: js.Transformed.Value](

_exportedMembersCache.filterInPlace((_, c) => c.cleanAfterRun())

if (_fullClassCache.exists(!_.cleanAfterRun()))
_fullClassCache = None
if (_fullClassChangeTracker.exists(!_.cleanAfterRun()))
_fullClassChangeTracker = None

if (!_cacheUsed)
invalidate()
Expand Down Expand Up @@ -967,26 +967,24 @@ final class Emitter[E >: Null <: js.Transformed.Value](
}
}

private class FullClassCache extends knowledgeGuardian.KnowledgeAccessor {
private[this] var _tree: WithGlobals[List[E]] = null
private class FullClassChangeTracker extends knowledgeGuardian.KnowledgeAccessor {
private[this] var _lastVersion: Version = Version.Unversioned
private[this] var _lastCtor: WithGlobals[E] = null
private[this] var _lastMemberMethods: List[WithGlobals[E]] = null
private[this] var _lastExportedMembers: List[WithGlobals[E]] = null
private[this] var _cacheUsed = false
private[this] var _trackerUsed = false

override def invalidate(): Unit = {
super.invalidate()
_tree = null
_lastVersion = Version.Unversioned
_lastCtor = null
_lastMemberMethods = null
_lastExportedMembers = null
}

def startRun(): Unit = _cacheUsed = false
def startRun(): Unit = _trackerUsed = false

def getOrElseUpdate(version: Version, ctor: WithGlobals[E],
def trackChanged(version: Version, ctor: WithGlobals[E],
memberMethods: List[WithGlobals[E]], exportedMembers: List[WithGlobals[E]],
compute: => WithGlobals[List[E]]): (WithGlobals[List[E]], Boolean) = {

Expand All @@ -998,28 +996,32 @@ final class Emitter[E >: Null <: js.Transformed.Value](
}
}

_cacheUsed = true
_trackerUsed = true

if (_tree == null || !version.sameVersion(_lastVersion) || (_lastCtor ne ctor) ||
if (!version.sameVersion(_lastVersion) || (_lastCtor ne ctor) ||
!allSame(_lastMemberMethods, memberMethods) ||
!allSame(_lastExportedMembers, exportedMembers)) {
// Input has changed or we were invalidated.
// Clean knowledge tracking and re-track dependencies.
invalidate()
_tree = compute
_lastVersion = version
_lastCtor = ctor
_lastMemberMethods = memberMethods
_lastExportedMembers = exportedMembers
(_tree, true)

(compute, true)
} else {
(_tree, false)
// Input has not changed and we were not invalidated.
// --> nothing has changed (we recompute to save memory).
(compute, false)
}
}

def cleanAfterRun(): Boolean = {
if (!_cacheUsed)
if (!_trackerUsed)
invalidate()

_cacheUsed
_trackerUsed
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,18 +208,21 @@ class EmitterTest {

// Post transforms

val Seq(postTransforms1, _, _) =
val Seq(postTransforms1, nestedPostTransforms1, _) =
lines1.assertContainsMatch(EmitterPostTransformStatsMessage).map(_.toInt)

val Seq(postTransforms2, _, _) =
val Seq(postTransforms2, nestedPostTransforms2, _) =
lines2.assertContainsMatch(EmitterPostTransformStatsMessage).map(_.toInt)

// At the time of writing this test, postTransformsTotal1 reports 216
// At the time of writing this test, postTransforms1 reports 216
assertTrue(
s"Not enough post transforms (got $postTransforms1); extraction must have gone wrong",
postTransforms1 > 200)

assertEquals("Second run must not have any post transforms", 0, postTransforms2)
assertEquals("Second run must only have nested post transforms",
nestedPostTransforms2, postTransforms2)
assertEquals("Both runs must have the same number of nested post transforms",
nestedPostTransforms1, nestedPostTransforms2)
}
}
}
Expand Down

0 comments on commit 268775c

Please sign in to comment.