From 10bfe2a1eef247493a0f836839cc01ceb0161a07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Thu, 5 May 2022 11:50:52 +0200 Subject: [PATCH 1/2] Handle `Block` in `BCodeBodyBuilder.genCond`. For `Block`s, we can push `genCond` inside the final `expr`, reducing the number of cases where we need to go through `loadAndTestBoolean`. We explicitly exclude `Block`s whose `expr` is a `LabelDef`, otherwise we short-circuit the match optimization done in `genBlockTo`. This is a backport of dotty's commit https://github.com/lampepfl/dotty/commit/d260adf95b94f397a89543a8cd86122b50ecece9 --- .../nsc/backend/jvm/BCodeBodyBuilder.scala | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index e618d2359e18..794fce7045c1 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -977,11 +977,18 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { default() } - val end = currProgramPoint() - if (emitVars) { // add entries to LocalVariableTable JVM attribute + emitLocalVarScopes() + varsInScope = savedScope + } + + /** Add entries to the `LocalVariableTable` JVM attribute for all the vars in + * `varsInScope`, ending at the current program point. + */ + def emitLocalVarScopes(): Unit = { + if (emitVars) { + val end = currProgramPoint() for ((sym, start) <- varsInScope.reverse) { emitLocalVarScope(sym, start, end) } } - varsInScope = savedScope } def adapt(from: BType, to: BType) { @@ -1429,6 +1436,17 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { loadAndTestBoolean() } + // Explicitly exclude LabelDef's here because we don't want to break the match optimization in genBlockTo. + // Anyway, we wouldn't be able to push `genCond` further inside a `LabelDef`, so we're not losing any opportunity. + case Block(stats, expr) if !expr.isInstanceOf[LabelDef] => + // Push the decision further down the `expr`. + val savedScope = varsInScope + varsInScope = Nil + stats foreach genStat + genCond(expr, success, failure, targetIfNoJump) + emitLocalVarScopes() + varsInScope = savedScope + case _ => loadAndTestBoolean() } From a6e652408e7a5a131fe3f56cc992d3fb1c8a712d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Thu, 5 May 2022 11:53:38 +0200 Subject: [PATCH 2/2] Handle `If` in `BCodeBodyBuilder.genCond()`. This is more for completeness of `genCond()`. It can now push down the jumps inside all the control structures for which it makes sense to do so. It typically applies when the condition of an `if` or `while` is an `if..else` expression. It is however not always a win. If the result of the nested `if`s must be converted to a boolean anyway, doing this will result in duplication of the conversion to boolean. This is a backport of dotty's commit https://github.com/lampepfl/dotty/commit/32c3395233aff768a04685a328d6030b0dc0df07 --- .../scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index 794fce7045c1..9e286358b962 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -1447,6 +1447,15 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { emitLocalVarScopes() varsInScope = savedScope + case If(condp, thenp, elsep) => + val innerSuccess = new asm.Label + val innerFailure = new asm.Label + genCond(condp, innerSuccess, innerFailure, targetIfNoJump = innerSuccess) + markProgramPoint(innerSuccess) + genCond(thenp, success, failure, targetIfNoJump = innerFailure) + markProgramPoint(innerFailure) + genCond(elsep, success, failure, targetIfNoJump) + case _ => loadAndTestBoolean() }