Packages

class LocalOpt[BT <: BTypes] extends AnyRef

Optimizations within a single method. Certain optimizations enable others, for example removing unreachable code can render a try block empty and enable removeEmptyExceptionHandlers. The latter in turn enables more unreachable code to be eliminated (the catch block), so there is a cyclic dependency. Optimizations that depend on each other are therefore executed in a loop until reaching a fixpoint.

The optimizations marked UPSTREAM enable optimizations that were already executed, so they cause another iteration in the fixpoint loop.

nullness optimizations: rewrite null-checking branches to GOTO if nullness is known + enables downstream

  • unreachable code (null / non-null branch becomes unreachable)
  • box-unbox elimination (may render an escaping consumer of a box unreachable)
  • stale stores (aload x is replaced by aconst_null if it's known null)
  • simplify jumps (replaces conditional jumps by goto, so may enable goto chains)

unreachable code / DCE (removes instructions of basic blocks to which there is no branch) + enables downstream:

  • stale stores (loads may be eliminated, removing consumers of a store)
  • empty handlers (try blocks may become empty)
  • simplify jumps (goto l; [dead code]; l: ..) => remove goto
  • stale local variable descriptors
  • (not box-unbox, which is implemented using prod-cons, so it doesn't consider dead code)

note that eliminating empty handlers and stale local variable descriptors is required for correctness, see the comment in the body of methodOptimizations.

box-unbox elimination (eliminates box-unbox pairs within the same method) + enables UPSTREAM:

  • nullness optimizations (a box extraction operation (unknown nullness) may be rewritten to a read of a non-null local. example in doc comment of box-unbox implementation)
  • further box-unbox elimination (e.g. an Integer stored in a Tuple; eliminating the tuple may enable eliminating the Integer) + enables downstream:
  • copy propagation (new locals are introduced, may be aliases of existing)
  • stale stores (multi-value boxes where not all values are used)
  • redundant casts (("a", "b")._1: the generic _1 method returns Object, a cast to String is added. The cast is redundant after eliminating the tuple.)
  • empty local variable descriptors (local variables that were holding the box may become unused)

copy propagation (replaces LOAD n to the LOAD m for the smallest m that is an alias of n) + enables downstrem:

  • stale stores (a stored value may not be loaded anymore)
  • store-load pairs (a load n may now be right after a store n) + NOTE: copy propagation is only executed once, in the first fixpoint loop iteration. none of the other optimizations enables further copy prop. we still run it as part of the loop because it requires unreachable code to be eliminated.

stale stores (replace STORE by POP) + enables downstream:

  • push-pop (the new pop may be the single consumer for an instruction)

redundant casts: eliminates casts that are statically known to succeed (uses type propagation) + enables UPSTREAM:

  • box-unbox elimination (a removed checkcast may be a box consumer) + enables downstream:
  • push-pop for closure allocation elimination (every indyLambda is followed by a checkcast, see SI-9540)

push-pop (when a POP is the only consumer of a value, remove the POP and its producer) + enables UPSTREAM:

  • stale stores (if a LOAD is removed, a corresponding STORE may become stale)
  • box-unbox elimination (push-pop may eliminate a closure allocation, rendering a captured box non-escaping) + enables downstream:
  • store-load pairs (a variable may become non-live)
  • stale handlers (push-pop removes code)
  • simplify jumps (push-pop removes code)

store-load pairs (remove STORE x; LOAD x if x is otherwise not used in the method) + enables downstream:

  • empty handlers (code is removes, a try block may become empty
  • simplify jumps (code is removed, a goto may become redundant for example)
  • stale local variable descriptors

empty handlers (removes exception handlers whose try block is empty) + enables UPSTREAM:

  • unreachable code (catch block becomes unreachable)
  • box-unbox (a box may be escape in an operation in a dead handler) + enables downstream:
  • simplify jumps

simplify jumps (various, like GOTO l; l: ..., see doc comments of individual optimizations) + enables UPSTREAM

  • unreachable code (GOTO a; a: GOTO b; b: ..., the first jump is changed to GOTO b, the second becomes unreachable)
  • store-load pairs (a GOTO l; l: ... is removed between store and load)
  • push-pop (IFNULL l; l: ... is replaced by POP)

The following cleanup optimizations don't enable any upstream optimizations, so they can be executed once at the end, when the above optimizations reach a fixpoint.

empty local variable descriptors (removes unused variables from the local variable table) + enables downstream:

  • stale labels (labels that the entry points to, if not otherwise referenced)

empty line numbers (eliminates line number nodes that describe no executable instructions) + enables downstream:

  • stale labels (label of the line number node, if not otherwise referenced)

stale labels (eliminate labels that are not referenced, merge sequences of label definitions)

Note on a method's maxLocals / maxStack: the backend only uses those values for running Analyzers. The values can be conservative approximations: if an optimization removes code and the maximal stack size is now smaller, the larger maxStack value will still work fine for running an Analyzer (just that frames allocate more space than required). The correct max values written to the bytecode are re-computed during classfile serialization. To keep things simpler, we don't update the max values in every optimization:

  • we do it in removeUnreachableCodeImpl, because it's quite straightforward
  • maxLocals is updated in compactLocalVariables, which runs at the end of method optimizations

Note on updating the call graph: whenever an optimization eliminates a callsite or a closure instantiation, we eliminate the corresponding entry from the call graph.

Source
LocalOpt.scala
Linear Supertypes
AnyRef, Any
Type Hierarchy
Ordering
  1. Alphabetic
  2. By Inheritance
Inherited
  1. LocalOpt
  2. AnyRef
  3. Any
Implicitly
  1. by any2stringadd
  2. by StringFormat
  3. by Ensuring
  4. by ArrowAssoc
  1. Hide All
  2. Show All
Visibility
  1. Public
  2. All

Instance Constructors

  1. new LocalOpt(btypes: BT)

Value Members

  1. final def !=(arg0: Any): Boolean
    Definition Classes
    AnyRef → Any
  2. final def ##(): Int
    Definition Classes
    AnyRef → Any
  3. def +(other: String): String
    Implicit
    This member is added by an implicit conversion from LocalOpt[BT] to any2stringadd[LocalOpt[BT]] performed by method any2stringadd in scala.Predef.
    Definition Classes
    any2stringadd
  4. def ->[B](y: B): (LocalOpt[BT], B)
    Implicit
    This member is added by an implicit conversion from LocalOpt[BT] to ArrowAssoc[LocalOpt[BT]] performed by method ArrowAssoc in scala.Predef.
    Definition Classes
    ArrowAssoc
    Annotations
    @inline()
  5. final def ==(arg0: Any): Boolean
    Definition Classes
    AnyRef → Any
  6. final def asInstanceOf[T0]: T0
    Definition Classes
    Any
  7. val boxUnbox: BoxUnbox[BT]
  8. val btypes: BT
  9. def clone(): AnyRef
    Attributes
    protected[java.lang]
    Definition Classes
    AnyRef
    Annotations
    @throws( ... )
  10. val copyProp: CopyProp[BT]
  11. def eliminateRedundantCasts(method: MethodNode, owner: InternalName): Boolean

    Eliminate CHECKCAST instructions that are statically known to succeed.

    Eliminate CHECKCAST instructions that are statically known to succeed. This is safe if the tested object is null: null.asInstanceOf always succeeds.

    The type of the tested object is determined using a NonLubbingTypeFlowAnalyzer. Note that this analysis collapses LUBs of non-equal references types to Object for simplicity. Example: given B <: A <: Object, the cast in (if (..) new B else new A).asInstanceOf[A] would not be eliminated.

    Note: we cannot replace INSTANCEOF tests by only looking at the types, null.isInstanceOf always returns false, so we'd also need nullness information.

  12. def ensuring(cond: (LocalOpt[BT]) ⇒ Boolean, msg: ⇒ Any): LocalOpt[BT]
    Implicit
    This member is added by an implicit conversion from LocalOpt[BT] to Ensuring[LocalOpt[BT]] performed by method Ensuring in scala.Predef.
    Definition Classes
    Ensuring
  13. def ensuring(cond: (LocalOpt[BT]) ⇒ Boolean): LocalOpt[BT]
    Implicit
    This member is added by an implicit conversion from LocalOpt[BT] to Ensuring[LocalOpt[BT]] performed by method Ensuring in scala.Predef.
    Definition Classes
    Ensuring
  14. def ensuring(cond: Boolean, msg: ⇒ Any): LocalOpt[BT]
    Implicit
    This member is added by an implicit conversion from LocalOpt[BT] to Ensuring[LocalOpt[BT]] performed by method Ensuring in scala.Predef.
    Definition Classes
    Ensuring
  15. def ensuring(cond: Boolean): LocalOpt[BT]
    Implicit
    This member is added by an implicit conversion from LocalOpt[BT] to Ensuring[LocalOpt[BT]] performed by method Ensuring in scala.Predef.
    Definition Classes
    Ensuring
  16. final def eq(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef
  17. def equals(arg0: Any): Boolean
    Definition Classes
    AnyRef → Any
  18. def finalize(): Unit
    Attributes
    protected[java.lang]
    Definition Classes
    AnyRef
    Annotations
    @throws( classOf[java.lang.Throwable] )
  19. def formatted(fmtstr: String): String
    Implicit
    This member is added by an implicit conversion from LocalOpt[BT] to StringFormat[LocalOpt[BT]] performed by method StringFormat in scala.Predef.
    Definition Classes
    StringFormat
    Annotations
    @inline()
  20. final def getClass(): Class[_]
    Definition Classes
    AnyRef → Any
  21. def hashCode(): Int
    Definition Classes
    AnyRef → Any
  22. final def isInstanceOf[T0]: Boolean
    Definition Classes
    Any
  23. def methodOptimizations(method: MethodNode, ownerClassName: InternalName): Boolean

    Run method-level optimizations, see comment on class LocalOpt.

    Run method-level optimizations, see comment on class LocalOpt.

    Returns true if the bytecode of method was changed.

  24. def methodOptimizations(clazz: ClassNode): Boolean

    Remove unreachable instructions from all (non-abstract) methods and apply various other cleanups to the bytecode.

    Remove unreachable instructions from all (non-abstract) methods and apply various other cleanups to the bytecode.

    clazz

    The class whose methods are optimized

    returns

    true if unreachable code was eliminated in some method, false otherwise.

  25. def minimalRemoveUnreachableCode(method: MethodNode, ownerClassName: InternalName): Boolean

    Remove unreachable code from a method.

    Remove unreachable code from a method.

    This implementation only removes instructions that are unreachable for an ASM analyzer / interpreter. This ensures that future analyses will not produce null frames. The inliner depends on this property.

    returns

    A set containing the eliminated instructions

  26. final def ne(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef
  27. final def notify(): Unit
    Definition Classes
    AnyRef
  28. final def notifyAll(): Unit
    Definition Classes
    AnyRef
  29. def nullnessOptimizations(method: MethodNode, ownerClassName: InternalName): Boolean

    Apply various optimizations based on nullness analysis information.

    Apply various optimizations based on nullness analysis information.

    • IFNULL / IFNONNULL are rewritten to GOTO if nullness is known
    • IF_ACMPEQ / IF_ACMPNE are rewritten to GOTO if the both references are known null, or if one is known null and the other known not-null
    • ALOAD is replaced by ACONST_NULL if the local is known to hold null
    • ASTORE of null is removed if the local is known to hold null
    • INSTANCEOF of null is replaced by ICONST_0
    • scala.runtime.BoxesRunTime.unboxToX(null) is rewritten to a zero-value load
  30. def removeUnreachableCodeImpl(method: MethodNode, ownerClassName: InternalName): (Boolean, Set[LabelNode])

    Removes unreachable basic blocks.

    Removes unreachable basic blocks.

    returns

    A set containing eliminated instructions, and a set containing all live label nodes.

  31. final def synchronized[T0](arg0: ⇒ T0): T0
    Definition Classes
    AnyRef
  32. def toString(): String
    Definition Classes
    AnyRef → Any
  33. final def wait(): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws( ... )
  34. final def wait(arg0: Long, arg1: Int): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws( ... )
  35. final def wait(arg0: Long): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws( ... )
  36. def [B](y: B): (LocalOpt[BT], B)
    Implicit
    This member is added by an implicit conversion from LocalOpt[BT] to ArrowAssoc[LocalOpt[BT]] performed by method ArrowAssoc in scala.Predef.
    Definition Classes
    ArrowAssoc

Inherited from AnyRef

Inherited from Any

Inherited by implicit conversion any2stringadd from LocalOpt[BT] to any2stringadd[LocalOpt[BT]]

Inherited by implicit conversion StringFormat from LocalOpt[BT] to StringFormat[LocalOpt[BT]]

Inherited by implicit conversion Ensuring from LocalOpt[BT] to Ensuring[LocalOpt[BT]]

Inherited by implicit conversion ArrowAssoc from LocalOpt[BT] to ArrowAssoc[LocalOpt[BT]]

Ungrouped