8000 By default, only run DCE on methods with an ATHROW. by retronym · Pull Request #6044 · scala/scala · GitHub
[go: up one dir, main page]

Skip to content

By default, only run DCE on methods with an ATHROW. #6044

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
Prev Previous commit
Next Next commit
move backend state from BTypes to components where it belongs
  • Loading branch information
lrytz committed Aug 11, 2017
commit 58cfe9e76c058e4e1f56065256a318f564a171ef
22 changes: 10 additions & 12 deletions src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,17 @@
* @author Martin Odersky
*/


package scala
package tools.nsc
package backend
package jvm
package scala.tools.nsc
package backend.jvm

import scala.annotation.switch
import scala.reflect.internal.Flags
import scala.tools.asm
import GenBCode._
import BackendReporting._
import scala.collection.mutable
import scala.tools.asm.Opcodes
import scala.tools.asm.tree.{MethodInsnNode, MethodNode}
import scala.tools.nsc.backend.jvm.BCodeHelpers.{InvokeStyle, TestOp}
import scala.tools.nsc.backend.jvm.BackendReporting._
import scala.tools.nsc.backend.jvm.GenBCode._

/*
*
Expand All @@ -27,9 +23,11 @@ import scala.tools.nsc.backend.jvm.BCodeHelpers.{InvokeStyle, TestOp}
*/
abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
import global._
import definitions._
import bTypes._
import coreBTypes._
import definitions._
import genBCode.postProcessor.backendUtils.addIndyLambdaImplMethod
import genBCode.postProcessor.callGraph.{inlineAnnotatedCallsites, noInlineAnnotatedCallsites}

/*
* Functionality to build the body of ASM MethodNode, except for `synchronized` and `try` expressions.
Expand Down Expand Up @@ -213,7 +211,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
val Apply(fun @ Select(receiver, _), _) = tree
val code = scalaPrimitives.getPrimitive(sym, receiver.tpe)

import scalaPrimitives.{isArithmeticOp, isArrayOp, isLogicalOp, isComparisonOp}
import scalaPrimitives.{isArithmeticOp, isArrayOp, isComparisonOp, isLogicalOp}

if (isArithmeticOp(code)) genArithmeticOp(tree, code)
else if (code == scalaPrimitives.CONCAT) genStringConcat(tree)
Expand Down Expand Up @@ -1213,7 +1211,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
tree match {

case Apply(fun, args) if isPrimitive(fun.symbol) =>
import scalaPrimitives.{ ZNOT, ZAND, ZOR, EQ, getPrimitive }
import scalaPrimitives._

// lhs and rhs of test
lazy val Select(lhs, _) = fun
Expand Down Expand Up @@ -1360,7 +1358,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
private def visitInvokeDynamicInsnLMF(jmethod: MethodNode, samName: String, invokedType: String, samMethodType: asm.Type,
implMethodHandle: asm.Handle, instantiatedMethodType: asm.Type,
serializable: Boolean, markerInterfaces: Seq[asm.Type]) = {
import java.lang.invoke.LambdaMetafactory.{FLAG_MARKERS, FLAG_SERIALIZABLE, FLAG_BRIDGES}
import java.lang.invoke.LambdaMetafactory.{FLAG_BRIDGES, FLAG_MARKERS, FLAG_SERIALIZABLE}
// scala/bug#10334: make sure that a lambda object for `T => U` has a method `apply(T)U`, not only the `(Object)Object`
// version. Using the lambda a structural type `{def apply(t: T): U}` causes a reflective lookup for this method.
val needsBridge = samMethodType != instantiatedMethodType
Expand Down
18 changes: 9 additions & 9 deletions src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@
* @author Martin Odersky
*/

package scala
package tools.nsc
package scala.tools.nsc
package backend.jvm

import scala.tools.asm
import scala.annotation.switch
import scala.collection.mutable
import GenBCode._
import scala.tools.asm
import scala.tools.asm.tree.MethodInsnNode
import scala.tools.nsc.backend.jvm.BCodeHelpers.TestOp
import scala.tools.nsc.backend.jvm.GenBCode._

/*
* A high-level facade to the ASM API for bytecode generation.
Expand All @@ -28,6 +27,7 @@ abstract class BCodeIdiomatic {
import global._
import bTypes._
import coreBTypes._
import genBCode.postProcessor.callGraph.callsitePositions

lazy val JavaStringBuilderClassName = jlStringBuilderRef.internalName

Expand Down Expand Up @@ -116,7 +116,7 @@ abstract class BCodeIdiomatic {
*/
final def genPrimitiveLogical(op: /* LogicalOp */ Int, kind: BType) {

import scalaPrimitives.{ AND, OR, XOR }
import scalaPrimitives.{AND, OR, XOR}

((op, kind): @unchecked) match {
case (AND, LONG) => emit(Opcodes.LAND)
Expand Down Expand Up @@ -145,7 +145,7 @@ abstract class BCodeIdiomatic {
*/
final def genPrimitiveShift(op: /* ShiftOp */ Int, kind: BType) {

import scalaPrimitives.{ LSL, ASR, LSR }
import scalaPrimitives.{ASR, LSL, LSR}

((op, kind): @unchecked) match {
case (LSL, LONG) => emit(Opcodes.LSHL)
Expand Down Expand Up @@ -253,23 +253,23 @@ abstract class BCodeIdiomatic {
case INT => pickOne(JCodeMethodN.fromIntT2T)

case FLOAT =>
import asm.Opcodes.{ F2L, F2D, F2I }
import asm.Opcodes.{F2D, F2I, F2L}
to match {
case LONG => emit(F2L)
case DOUBLE => emit(F2D)
case _ => emit(F2I); emitT2T(INT, to)
}

case LONG =>
import asm.Opcodes.{ L2F, L2D, L2I }
import asm.Opcodes.{L2D, L2F, L2I}
to match {
case FLOAT => emit(L2F)
case DOUBLE => emit(L2D)
case _ => emit(L2I); emitT2T(INT, to)
}

case DOUBLE =>
import asm.Opcodes.{ D2L, D2F, D2I }
import asm.Opcodes.{D2F, D2I, D2L}
to match {
case FLOAT => emit(D2F)
case LONG => emit(D2L)
Expand Down
82 changes: 0 additions & 82 deletions src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ package backend.jvm

import scala.collection.concurrent.TrieMap
import scala.collection.{concurrent, mutable}
import scala.reflect.internal.util.Position
import scala.tools.asm
import scala.tools.asm.Opcodes
import scala.tools.asm.tree._
import scala.tools.nsc.backend.jvm.BTypes.{InlineInfo, InternalName}
import scala.tools.nsc.backend.jvm.BackendReporting._
import scala.tools.nsc.backend.jvm.opt._
Expand Down Expand Up @@ -46,86 +44,6 @@ abstract class BTypes {
val classBTypeCacheFromSymbol: concurrent.Map[InternalName, ClassBType] = recordPerRunCache(TrieMap.empty)
val classBTypeCacheFromClassfile: concurrent.Map[InternalName, ClassBType] = recordPerRunCache(TrieMap.empty)

/**
* Store the position of every MethodInsnNode during code generation. This allows each callsite
* in the call graph to remember its source position, which is required for inliner warnings.
*/
val callsitePositions: concurrent.Map[MethodInsnNode, Position] = recordPerRunCache(TrieMap.empty)

/**
* Stores callsite instructions of invocations annotated `f(): @inline/noinline`.
* Instructions are added during code generation (BCodeBodyBuilder). The maps are then queried
* when building the CallGraph, every Callsite object has an annotated(No)Inline field.
*/
val inlineAnnotatedCallsites: mutable.Set[MethodInsnNode] = recordPerRunCache(mutable.Set.empty)
val noInlineAnnotatedCallsites: mutable.Set[MethodInsnNode] = recordPerRunCache(mutable.Set.empty)

/**
* Contains the internal names of all classes that are defined in Java source files of the current
* compilation run (mixed compilation). Used for more detailed error reporting.
*/
val javaDefinedClasses: mutable.Set[InternalName] = recordPerRunCache(mutable.Set.empty)

/**
* Cache, contains methods whose unreachable instructions are eliminated.
*
* The ASM Analyzer class does not compute any frame information for unreachable instructions.
* Transformations that use an analyzer (including inlining) therefore require unreachable code
* to be eliminated.
*
* This cache allows running dead code elimination whenever an analyzer is used. If the method
* is already optimized, DCE can return early.
*/
val unreachableCodeEliminated: mutable.Set[MethodNode] = recordPerRunCache(mutable.Set.empty)

/**
* Cache of methods which have correct `maxLocals` / `maxStack` values assigned. This allows
* invoking `computeMaxLocalsMaxStack` whenever running an analyzer but performing the actual
* computation only when necessary.
*/
val maxLocalsMaxStackComputed: mutable.Set[MethodNode] = recordPerRunCache(mutable.Set.empty)

/**
* Classes with indyLambda closure instantiations where the SAM type is serializable (e.g. Scala's
* FunctionN) need a `$deserializeLambda$` method. This map contains classes for which such a
* method has been generated. It is used during ordinary code generation, as well as during
* inlining: when inlining an indyLambda instruction into a class, we need to make sure the class
* has the method.
*/
val indyLambdaImplMethods: mutable.AnyRefMap[InternalName, mutable.LinkedHashSet[asm.Handle]] = recordPerRunCache(mutable.AnyRefMap())

/**
* add methods
* @return the added methods. Note the order is undefined
*/
def addIndyLambdaImplMethod(hostClass: InternalName, handle: Seq[asm.Handle]): Seq[asm.Handle] = {
if (handle.isEmpty) Nil else {
val set = indyLambdaImplMethods.getOrElseUpdate(hostClass, mutable.LinkedHashSet())
if (set.isEmpty) {
set ++= handle
handle
} else {
var added = List.empty[asm.Handle]
handle foreach { h => if (set.add(h)) added ::= h}
added
}
}
}
def addIndyLambdaImplMethod(hostClass: InternalName, handle: asm.Handle): Boolean = {
indyLambdaImplMethods.getOrElseUpdate(hostClass, mutable.LinkedHashSet()).add(handle)
}
def removeIndyLambdaImplMethod(hostClass: InternalName, handle: Seq[asm.Handle]): Unit = {
if (handle.nonEmpty)
indyLambdaImplMethods.get(hostClass).foreach(_ --= handle)
}

def getIndyLambdaImplMethods(hostClass: InternalName): Iterable[asm.Handle] = {
indyLambdaImplMethods.getOrNull(hostClass) match {
case null => Nil
case xs => xs
}
}

/**
* A BType is either a primitive type, a ClassBType, an ArrayBType of one of these, or a MethodType
* referring to BTypes.
Expand Down
10 changes: 0 additions & 10 deletions src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,6 @@ import scala.tools.nsc.backend.jvm.BackendReporting._
* This class mainly contains the method classBTypeFromSymbol, which extracts the necessary
* information from a symbol and its type to create the corresponding ClassBType. It requires
* access to the compiler (global parameter).
*
* The mixin CoreBTypes defines core BTypes that are used in the backend. Building these BTypes
* uses classBTypeFromSymbol, hence requires access to the compiler (global).
*
* BTypesFromSymbols extends BTypes because the implementation of BTypes requires access to some
* of the core btypes. They are declared in BTypes as abstract members. Note that BTypes does
* not have access to the compiler instance.
*/
abstract class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
val frontendAccess: PostProcessorFrontendAccess
Expand All @@ -39,9 +32,6 @@ abstract class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {

final def initialize(): Unit = {
coreBTypes.initialize()
javaDefinedClasses ++= currentRun.symSource collect {
case (sym, _) if sym.isJavaDefined => sym.javaBinaryNameString
}
}

// helpers that need access to global.
Expand Down
7 changes: 6 additions & 1 deletion src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,14 @@ abstract class CoreBTypesFromSymbols[G <: Global] extends CoreBTypes {

import bTypes._
import global._
import rootMirror.{requiredClass, getRequiredClass, getClassIfDefined}
import definitions._
import rootMirror.{getClassIfDefined, getRequiredClass, requiredClass}

/**
* This method is used to lazily initialize the core BTypes. The computation is synchronized on
* the frontendLock, as it reads Symbols. The BTypes are re-initialized in each compiler run as
* the information in symbols may change.
*/
private def runLazy[T](init: => T): LazyVar[T] = perRunLazy(this)(init)

/**
Expand Down
6 changes: 4 additions & 2 deletions src/compiler/scala/tools/nsc/backend/jvm/PostProcessor.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
package scala.tools.nsc.backend.jvm
package scala.tools.nsc
package backend.jvm

import scala.collection.mutable.ListBuffer
import scala.reflect.internal.util.NoPosition
Expand Down Expand Up @@ -35,6 +36,7 @@ abstract class PostProcessor extends PerRunInit {
override def initialize(): Unit = {
super.initialize()
backendUtils.initialize()
byteCodeRepository.initialize()
inlinerHeuristics.initialize()
}

Expand All @@ -45,7 +47,7 @@ abstract class PostProcessor extends PerRunInit {
val bytes = try {
if (!isArtifact) {
localOptimizations(classNode)
val lambdaImplMethods = getIndyLambdaImplMethods(classNode.name)
val lambdaImplMethods = backendUtils.getIndyLambdaImplMethods(classNode.name)
if (lambdaImplMethods.nonEmpty)
backendUtils.addLambdaDeserialize(classNode, lambdaImplMethods)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package scala.tools.nsc.backend.jvm
package scala.tools.nsc
package backend.jvm

import scala.collection.generic.Clearable
import scala.reflect.internal.util.Position
import scala.reflect.io.AbstractFile
import scala.tools.nsc.Global
import scala.tools.nsc.backend.jvm.BTypes.InternalName

/**
* Functionality needed in the post-processor whose implementation depends on the compiler
Expand All @@ -25,6 +26,8 @@ sealed abstract class PostProcessorFrontendAccess {

def getEntryPoints: List[String]

def javaDefinedClasses: Set[InternalName]

def recordPerRunCache[T <: Clearable](cache: T): T
}

Expand Down Expand Up @@ -152,6 +155,13 @@ object PostProcessorFrontendAccess {

def getEntryPoints: List[String] = frontendSynch(cleanup.getEntryPoints)

def javaDefinedClasses: Set[InternalName] = frontendSynch {
currentRun.symSource.collect({
case (sym, _) if sym.isJavaDefined => sym.javaBinaryNameString
}).toSet
}


def recordPerRunCache[T <: Clearable](cache: T): T = frontendSynch(perRunCaches.recordCache(cache))
}
}
Loading
0