Skip to content

Commit

Permalink
Remove some indirections in Global and Typer
Browse files Browse the repository at this point in the history
This reduces the number of Java stack frames between the bottom
of the stack and the start of typer, and, more importantly,
at each level of recursion in the AST or in symbol completion.

The intent is to make the stacks easier to visually scan in
profilers and other tools that display them. I'm not expecting
that performance will improve, the JVM probably does a decent
jobs and inlining these chunks of the stack.
  • Loading branch information
retronym committed Aug 20, 2018
1 parent caeddb7 commit 3d69134
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 41 deletions.
26 changes: 23 additions & 3 deletions src/compiler/scala/tools/nsc/Global.scala
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,9 @@ class Global(var currentSettings: Settings, reporter0: LegacyReporter)

def run(): Unit = {
echoPhaseSummary(this)
currentRun.units foreach applyPhase
val units = currentRun.units
while (units.hasNext)
applyPhase(units.next())
}

def apply(unit: CompilationUnit): Unit
Expand All @@ -396,19 +398,25 @@ class Global(var currentSettings: Settings, reporter0: LegacyReporter)
reporter.cancelled || unit.isJava && this.id > maxJavaPhase
}

final def withCurrentUnit(unit: CompilationUnit)(task: => Unit): Unit = {
private def beforeUnit(unit: CompilationUnit): Unit = {
if ((unit ne null) && unit.exists)
lastSeenSourceFile = unit.source

if (settings.debug && (settings.verbose || currentRun.size < 5))
inform("[running phase " + name + " on " + unit + "]")
}

@deprecated
final def withCurrentUnit(unit: CompilationUnit)(task: => Unit) {
beforeUnit(unit)
if (!cancelled(unit)) {
currentRun.informUnitStarting(this, unit)
try withCurrentUnitNoLog(unit)(task)
finally currentRun.advanceUnit()
}
}

@inline
final def withCurrentUnitNoLog(unit: CompilationUnit)(task: => Unit): Unit = {
val unit0 = currentUnit
try {
Expand All @@ -420,7 +428,19 @@ class Global(var currentSettings: Settings, reporter0: LegacyReporter)
}
}

final def applyPhase(unit: CompilationUnit) = withCurrentUnit(unit)(apply(unit))
final def applyPhase(unit: CompilationUnit) = {
beforeUnit(unit)
if (!cancelled(unit)) {
currentRun.informUnitStarting(this, unit)
val unit0 = currentUnit
currentRun.currentUnit = unit
try apply(unit)
finally {
currentRun.currentUnit = unit0
currentRun.advanceUnit()
}
}
}
}

// phaseName = "parser"
Expand Down
8 changes: 5 additions & 3 deletions src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ trait Analyzer extends AnyRef
val phaseName = "typer"
val runsAfter = List[String]()
val runsRightAfter = Some("packageobjects")
def newPhase(_prev: Phase): StdPhase = new StdPhase(_prev) {
def newPhase(prev: Phase): StdPhase = new TyperPhase(prev)
final class TyperPhase(prev: Phase) extends StdPhase(prev) {
override def keepsTypeParams = false
resetTyper()
// the log accumulates entries over time, even though it should not (Adriaan, Martin said so).
Expand All @@ -91,8 +92,9 @@ trait Analyzer extends AnyRef
override def run(): Unit = {
val start = if (StatisticsStatics.areSomeColdStatsEnabled) statistics.startTimer(statistics.typerNanos) else null
global.echoPhaseSummary(this)
for (unit <- currentRun.units) {
applyPhase(unit)
val units = currentRun.units
while (units.hasNext) {
applyPhase(units.next())
undoLog.clear()
}
finishComputeParamAlias()
Expand Down
64 changes: 29 additions & 35 deletions src/compiler/scala/tools/nsc/typechecker/Typers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5522,7 +5522,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
case _ => abort(s"unexpected tree in pattern mode: ${tree.getClass}\n$tree")
}

def typedTypTree(tree: TypTree): Tree = tree match {
@inline def typedTypTree(tree: TypTree): Tree = tree match {
case tree: TypeTree => typedTypeTree(tree)
case tree: AppliedTypeTree => typedAppliedTypeTree(tree)
case tree: TypeBoundsTree => typedTypeBoundsTree(tree)
Expand All @@ -5534,7 +5534,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
case _ => abort(s"unexpected type-representing tree: ${tree.getClass}\n$tree")
}

def typedMemberDef(tree: MemberDef): Tree = tree match {
@inline def typedMemberDef(tree: MemberDef): Tree = tree match {
case tree: ValDef => typedValDef(tree)
case tree: DefDef => defDefTyper(tree).typedDefDef(tree)
case tree: ClassDef => newTyper(context.makeNewScope(tree, sym)).typedClassDef(tree)
Expand Down Expand Up @@ -5578,7 +5578,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}

// Trees allowed in or out of pattern mode.
def typedInAnyMode(tree: Tree): Tree = tree match {
@inline def typedInAnyMode(tree: Tree): Tree = tree match {
case tree: Ident => typedIdentOrWildcard(tree)
case tree: Bind => typedBind(tree)
case tree: Apply => insertStabilizer(typedApply(tree), tree)
Expand All @@ -5604,27 +5604,19 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper

def typed(tree: Tree, mode: Mode, pt: Type): Tree = {
lastTreeToTyper = tree
def body = (
if (printTypings && !phase.erasedTypes && !noPrintTyping(tree))
typingStack.nextTyped(tree, mode, pt, context)(typedInternal(tree, mode, pt))
else
typedInternal(tree, mode, pt)
)
val statsEnabled = StatisticsStatics.areSomeHotStatsEnabled() && statistics.areHotStatsLocallyEnabled
val startByType = if (statsEnabled) statistics.pushTimer(byTypeStack, byTypeNanos(tree.getClass)) else null
if (statsEnabled) statistics.incCounter(visitsByType, tree.getClass)
try body
finally if (statsEnabled) statistics.popTimer(byTypeStack, startByType)
}
val shouldPrintTyping = printTypings && !phase.erasedTypes && !noPrintTyping(tree)
val shouldPopTypingStack = shouldPrintTyping && typingStack.beforeNextTyped(tree, mode, pt, context)
try {

private def typedInternal(tree: Tree, mode: Mode, pt: Type): Tree = {
val ptPlugins = pluginsPt(pt, this, tree, mode)
def retypingOk = (
context.retyping
&& (tree.tpe ne null)
&& (tree.tpe.isErroneous || !(tree.tpe <:< ptPlugins))
)
def runTyper(): Tree = {
val ptPlugins = pluginsPt(pt, this, tree, mode)
def retypingOk = (
context.retyping
&& (tree.tpe ne null)
&& (tree.tpe.isErroneous || !(tree.tpe <:< ptPlugins))
)
if (retypingOk) {
tree.setType(null)
if (tree.hasSymbolField) tree.symbol = NoSymbol
Expand Down Expand Up @@ -5664,10 +5656,10 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
if (mode.inPatternMode && !mode.inPolyMode && result.isType)
PatternMustBeValue(result, pt)

result
}
if (shouldPopTypingStack) typingStack.showPop(result)

try runTyper() catch {
result
} catch {
case ex: CyclicReference if global.propagateCyclicReferences =>
throw ex
case ex: TypeError =>
Expand All @@ -5678,10 +5670,13 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
setError(tree)
case ex: Exception =>
// @M causes cyclic reference error
devWarning(s"exception when typing $tree, pt=$ptPlugins")
devWarning(s"exception when typing $tree, pt=$pt")
if (context != null && context.unit.exists && tree != null)
logError("AT: " + tree.pos, ex)
throw ex
} finally {
if (shouldPopTypingStack) typingStack.pop(tree)
if (statsEnabled) statistics.popTimer(byTypeStack, startByType)
}
}

Expand All @@ -5693,12 +5688,10 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper

/** Types expression or definition `tree`.
*/
def typed(tree: Tree): Tree = {
val ret = typed(tree, context.defaultModeForTyped, WildcardType)
ret
}
@inline final def typed(tree: Tree): Tree =
typed(tree, context.defaultModeForTyped, WildcardType)

def typedByValueExpr(tree: Tree, pt: Type = WildcardType): Tree = typed(tree, EXPRmode | BYVALmode, pt)
@inline final def typedByValueExpr(tree: Tree, pt: Type = WildcardType): Tree = typed(tree, EXPRmode | BYVALmode, pt)

def typedPos(pos: Position, mode: Mode, pt: Type)(tree: Tree) = typed(atPos(pos)(tree), mode, pt)
def typedPos(pos: Position)(tree: Tree) = typed(atPos(pos)(tree))
Expand All @@ -5708,28 +5701,28 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper

/** Types expression `tree` with given prototype `pt`.
*/
def typed(tree: Tree, pt: Type): Tree =
@inline final def typed(tree: Tree, pt: Type): Tree =
typed(tree, context.defaultModeForTyped, pt)

def typed(tree: Tree, mode: Mode): Tree =
@inline final def typed(tree: Tree, mode: Mode): Tree =
typed(tree, mode, WildcardType)

/** Types qualifier `tree` of a select node.
* E.g. is tree occurs in a context like `tree.m`.
*/
def typedQualifier(tree: Tree, mode: Mode, pt: Type): Tree =
@inline final def typedQualifier(tree: Tree, mode: Mode, pt: Type): Tree =
typed(tree, PolyQualifierModes | mode.onlyTypePat, pt) // TR: don't set BYVALmode, since qualifier might end up as by-name param to an implicit

/** Types qualifier `tree` of a select node.
* E.g. is tree occurs in a context like `tree.m`.
*/
def typedQualifier(tree: Tree, mode: Mode): Tree =
@inline final def typedQualifier(tree: Tree, mode: Mode): Tree =
typedQualifier(tree, mode, WildcardType)

def typedQualifier(tree: Tree): Tree = typedQualifier(tree, NOmode, WildcardType)
@inline final def typedQualifier(tree: Tree): Tree = typedQualifier(tree, NOmode, WildcardType)

/** Types function part of an application */
def typedOperator(tree: Tree): Tree = typed(tree, OperatorModes)
@inline final def typedOperator(tree: Tree): Tree = typed(tree, OperatorModes)

// the qualifier type of a supercall constructor is its first parent class
private def typedSelectOrSuperQualifier(qual: Tree) =
Expand Down Expand Up @@ -5846,6 +5839,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
case _ => op
}

@inline
final def transformedOrTyped(tree: Tree, mode: Mode, pt: Type): Tree = {
lookupTransformed(tree) match {
case Some(tree1) => tree1
Expand Down
10 changes: 10 additions & 0 deletions src/compiler/scala/tools/nsc/typechecker/TypersTracking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,16 @@ trait TypersTracking {
runWith(tree) { pushFn ; showPop(body) }
)

def beforeNextTyped(tree: Tree, mode: Mode, pt: Type, context: Context): Boolean = if (noPrintTyping(tree)) false else {
push(tree)
showPush(tree, mode, pt, context)
true
}
def afterNextTyped(tree: Tree, typedTree: Tree): Unit = {
showPop(typedTree)
pop(tree)
}

@inline final def printTyping(tree: Tree, s: => String) = {
if (printTypings && !noPrintTyping(tree))
show(indented(s))
Expand Down

0 comments on commit 3d69134

Please sign in to comment.