diff --git a/compile/interface/API.scala b/compile/interface/API.scala index 9985f4c67..35e441fbe 100644 --- a/compile/interface/API.scala +++ b/compile/interface/API.scala @@ -44,14 +44,29 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend val packages = traverser.packages.toArray[String].map(p => new xsbti.api.Package(p)) val source = new xsbti.api.Source(packages, traverser.definitions.toArray[xsbti.api.Definition]) forceStructures() + clearCaches() callback.api(sourceFile, source) } } + // this cache reduces duplicate work both here and when persisting + // caches on other structures had minimal effect on time and cache size + // (tried: Definition, Modifier, Path, Id, String) + private[this] val typeCache = new HashMap[Type, xsbti.api.Type] + // these caches are necessary for correctness private[this] val structureCache = new HashMap[Symbol, xsbti.api.Structure] private[this] val classLikeCache = new HashMap[Symbol, xsbti.api.ClassLike] private[this] val pending = new HashSet[xsbti.api.Lazy[_]] + // to mitigate "temporary leaks" like that caused by NoPhase in 2.8.0, + // this ensures this class is not retaining objects + private def clearCaches() + { + typeCache.clear() + structureCache.clear() + classLikeCache.clear() + } + // call back to the xsbti.SafeLazy class in main sbt code to construct a SafeLazy instance // we pass a thunk, whose class is loaded by the interface class loader (this class's loader) // SafeLazy ensures that once the value is forced, the thunk is nulled out and so @@ -256,6 +271,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend new xsbti.api.Modifiers(s.hasFlag(ABSTRACT) || s.hasFlag(DEFERRED), s.hasFlag(OVERRIDE), s.isFinal, s.hasFlag(SEALED), isImplicit(s), s.hasFlag(LAZY)) } + private def isImplicit(s: Symbol) = s.hasFlag(Flags.IMPLICIT) private def getAccess(c: Symbol): xsbti.api.Access = { @@ -270,7 +286,8 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend else new xsbti.api.Private(qualifier) } } - private def processType(t: Type): xsbti.api.Type = + private def processType(t: Type): xsbti.api.Type = typeCache.getOrElseUpdate(t, makeType(t)) + private def makeType(t: Type): xsbti.api.Type = { def dealias(t: Type) = t match { case TypeRef(_, sym, _) if sym.isAliasType => t.normalize; case _ => t } @@ -394,5 +411,5 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend if(annots.isEmpty) processType(at.underlying) else annotated(annots, at.underlying) } private def fullName(s: Symbol): String = nameString(s) - private def simpleName(s: Symbol): String = s.simpleName.toString.trim + private def simpleName(s: Symbol): String = s.simpleName.toString.trim } diff --git a/interface/other b/interface/other index bba27dc7f..2ee086bcb 100644 --- a/interface/other +++ b/interface/other @@ -18,14 +18,6 @@ Qualifier IdQualifier value: String -Modifiers - isAbstract: Boolean - isOverride: Boolean - isFinal: Boolean - isSealed: Boolean - isImplicit: Boolean - isLazy: Boolean - ParameterList parameters: MethodParameter* isImplicit: Boolean diff --git a/interface/src/main/java/xsbti/api/Modifiers.java b/interface/src/main/java/xsbti/api/Modifiers.java new file mode 100644 index 000000000..14737be57 --- /dev/null +++ b/interface/src/main/java/xsbti/api/Modifiers.java @@ -0,0 +1,69 @@ +package xsbti.api; + +public final class Modifiers implements java.io.Serializable +{ + private static final int AbstractBit = 0; + private static final int OverrideBit = 1; + private static final int FinalBit = 2; + private static final int SealedBit = 3; + private static final int ImplicitBit = 4; + private static final int LazyBit = 5; + + private static final int flag(boolean set, int bit) + { + return set ? (1 << bit) : 0; + } + + public Modifiers(boolean isAbstract, boolean isOverride, boolean isFinal, boolean isSealed, boolean isImplicit, boolean isLazy) + { + this.flags = (byte)( + flag(isAbstract, AbstractBit) | + flag(isOverride, OverrideBit) | + flag(isFinal, FinalBit) | + flag(isSealed, SealedBit) | + flag(isImplicit, ImplicitBit) | + flag(isLazy, LazyBit) + ); + } + + private final byte flags; + + private final boolean flag(int bit) + { + return (flags & (1 << bit)) != 0; + } + + public final byte raw() + { + return flags; + } + + public final boolean isAbstract() + { + return flag(AbstractBit); + } + public final boolean isOverride() + { + return flag(OverrideBit); + } + public final boolean isFinal() + { + return flag(FinalBit); + } + public final boolean isSealed() + { + return flag(SealedBit); + } + public final boolean isImplicit() + { + return flag(ImplicitBit); + } + public final boolean isLazy() + { + return flag(LazyBit); + } + public String toString() + { + return "Modifiers(" + "isAbstract: " + isAbstract() + ", " + "isOverride: " + isOverride() + ", " + "isFinal: " + isFinal() + ", " + "isSealed: " + isSealed() + ", " + "isImplicit: " + isImplicit() + ", " + "isLazy: " + isLazy()+ ")"; + } +}