Scala Compiler2.13.3 < Back


# Packages

-  package root

  The Scala compiler and reflection APIs.

  The Scala compiler and reflection APIs.

  Definition Classes
    root
-  package scala
  Definition Classes
    root
-  package tools
  Definition Classes
    scala
-  package nsc
  Definition Classes
    tools
-  package backend
  Definition Classes
    nsc
-  package jvm
  Definition Classes
    backend
-  package opt
  Definition Classes
    jvm
- BoxUnbox
- ByteCodeRepository
- BytecodeUtils
- CallGraph
- ClosureOptimizer
- CopyProp
- InlineInfoAttribute
- InlineInfoAttributePrototype
- Inliner
- InlinerHeuristics
- LabelNotLive
- LocalOpt
- LocalOptImpls
- LruMap
- RemovePair
- RemovePairDependency

c

scala.tools.nsc.backend.jvm.opt

# BoxUnbox

###

#### abstract class BoxUnbox extends AnyRef

Source
  BoxUnbox.scala

Linear Supertypes
AnyRef, Any
Type Hierarchy

Ordering

1. Alphabetic
2. By Inheritance

Inherited

1. BoxUnbox
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. Protected

### Instance Constructors

1.  new BoxUnbox()

### Type Members

1.  sealed trait BoxConsumer extends AnyRef
2.  sealed trait BoxCreation extends AnyRef
3.  trait BoxKind extends AnyRef
4.  case class BoxedPrimitiveTypeCheck(consumer: AbstractInsnNode, success: Boolean) extends BoxConsumer with Product with Serializable

   `.$isInstanceOf[T]` (can be statically proven true or false)

5.  class CopyOpsIterator extends Iterator[AbstractInsnNode]

   For a set of box creation operations and a corresponding set of box consumer operations, this iterator returns all copy operations (load, store, dup) that are in between.

6.  case class EscapingConsumer(consumer: AbstractInsnNode) extends BoxConsumer with Product with Serializable

   An unknown box consumer

7.  case class InstanceCreation(newOp: TypeInsnNode, dupOp: InsnNode, initCall: MethodInsnNode) extends BoxCreation with Product with Serializable
8.  case class ModuleFactory(moduleLoad: AbstractInsnNode, producer: MethodInsnNode) extends BoxCreation with Product with Serializable
9.  case class ModuleGetter(moduleLoad: AbstractInsnNode, consumer: MethodInsnNode) extends BoxConsumer with Product with Serializable

   An extractor method in a Scala module, e.g., `Predef.Integer2int`

10.  case class PrimitiveBox(boxedType: Type, boxClass: InternalName) extends BoxKind with Product with Serializable
11.  case class PrimitiveBoxingGetter(consumer: MethodInsnNode) extends BoxConsumer with Product with Serializable

    A getter that boxes the returned value, e.g., `Tuple2$mcII$sp._1`

12.  case class PrimitiveUnboxingGetter(consumer: MethodInsnNode, unboxedPrimitive: Type) extends BoxConsumer with Product with Serializable

    A getter that unboxes the returned value, e.g., `Tuple2._1$mcI$sp`

13.  case class Ref(boxedType: Type, refClass: InternalName) extends BoxKind with Product with Serializable
14.  case class StaticFactory(producer: MethodInsnNode, loadInitialValues: Option[List[AbstractInsnNode]]) extends BoxCreation with Product with Serializable
15.  case class StaticGetterOrInstanceRead(consumer: AbstractInsnNode) extends BoxConsumer with Product with Serializable

    Static extractor (BoxesRunTime.unboxToInt) or GETFIELD or getter invocation

16.  case class StaticSetterOrInstanceWrite(consumer: AbstractInsnNode) extends BoxConsumer with Product with Serializable

    PUTFIELD or setter invocation

17.  case class Tuple(boxedTypes: List[Type], tupleClass: InternalName) extends BoxKind with Product with Serializable

### Abstract Value Members

1.  abstract val postProcessor: PostProcessor

### Concrete 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 BoxUnbox toany2stringadd[BoxUnbox] performed by method any2stringadd in scala.Predef.
   Definition Classes
     any2stringadd
4.  def ->[B](y: B): (BoxUnbox, B)
   Implicit
     This member is added by an implicit conversion from BoxUnbox toArrowAssoc[BoxUnbox] performed by method ArrowAssoc in scala.Predef.
   Definition Classes
     ArrowAssoc
   Annotations
     @inline()
5.  final def ==(arg0: Any): Boolean
   Definition Classes
     AnyRef → Any
6.  def allCreationsConsumers(initialCreation: BoxCreation, boxKind: BoxKind, prodCons: ProdConsAnalyzer): Option[(Set[BoxCreation], Set[BoxConsumer])]

   Given a box creations operation

   Given a box creations operation

   - find all ultimate consumers for the produced value. then:
     - for all consumed values, find all producer operations. check that all are box creations
       - recurse until reaching a fixpoint

   Returns a set of box creations and a set of box consumers. Note that the box consumers may contain EscapingConsumers, even if there are multiple box creation operations. The callee will handle this case (and not attempt to eliminate the box).

7.  final def asInstanceOf[T0]: T0
   Definition Classes
     Any
8.  def boxUnboxElimination(method: MethodNode, owner: InternalName): Boolean

   Eliminate box-unbox pairs within `method`.

   Eliminate box-unbox pairs within `method`. Such appear commonly after closure elimination:

   def t2 = { val f = (b: Byte, i: Int) => i + b // no specialized variant for this function type f(1, 2) // invokes the generic `apply` }

   The closure optimizer re-writes the `apply` call to `anonfun$adapted` method, which takes boxed arguments. After inlining this method, we get

   def t2 = { val a = boxByte(1) val b = boxInteger(2) val r = boxInteger(anonfun$(unboxByte(a), unboxInt(b))) unboxInt(r) }

   All these box/unbox operations are eliminated here.

   Implementation: for every box operation, find all consumers of the boxed value, then all producers of these consumers, repeat until reaching a fixpoint. If this results in a set of boxing and unboxing operations, the box can be eliminated.

   There are two methods for eliminating boxes: M1: If there is a single boxing operation, the boxed value(s) are stored into new local variable(s) at the allocation site. Accesses to the boxed value are re-written to reads / writes of these locals. Advantages:

   - supports mutable boxes (IntRef and friends)
   - supports eliminating unbox operations even if the box object needs to be created because it escapes (see E4)
     - works by keeping the unboxed value(s) in locals AND the box in its original form
     - only for immutable boxes: modifications to the escaped box cannot be applied to the local variable(s) holding the boxed value(s). Restriction:
   - does not work if there are multiple boxing operations (see E1)

   M2: If there are multiple boxing operations, the boxing operations are simply eliminated, leaving the unboxed value(s) on the stack. Store / load operations that previously acted on the box are adapted to handle the boxed type(s). If the box contains multiple values (or a size-2 value, which doesn't fit into locals that were used for the box), new local slots are used for store / load operations. Restrictions:

   - does not support re-writing writes to (mutable) boxes (see E2)
   - does not support re-writing reads of boxes that also escape (see E3)

   E1: M1 only works if there's a single boxing operation. def e1(b: Boolean) = { val i: Integer = box(10) // 10 is stored into a new local, box operation and i removed val j: Integer = box(20) // 20 is stored into a new local, box operation and j removed val r = if (b) i else j // loads and stores of the box are eliminated, r no longer exists unbox(r) // cannot rewrite: we don't know which local to load } Note: the example has no write and the box does not escape, so M2 works here.

   E2: mutable boxes with multiple boxing operations cannot be eliminated. M1: see E1 M2: cannot replace an `IntRef` on the stack by an `Int` value on the stack, an Int on the stack cannot be modified.

   def e2(b: Boolean) = { val r1 = new IntRef(0) val r2 = new IntRef(1) val modRef = if (b) r1 else r2 modRef.elem += 10 // M1: cannot rewrite: which local to write? same as E1. (if (b) r1 else r2).elem += 10 // M2: cannot change an Int on the stack (r1.elem, r2.elem) }

   E3: escaping boxes with multiple boxing operations cannot be rewritten. M1: see E1. M2: at *, instead of an Integer, an Int is on the stack, but the escape method expects an Integer. We cannot just create a box at this point: if there are multiple escapes (or an escape is executed more than once), the difference could be observed (reference equality).

   def e3(b: Boolean) = { val i: Integer = box(1) val j: Integer = box(2) escape(if (b) i else j) // * unbox(if (b) i else j) }

   E4: M1 supports rewriting unbox operations of immutable boxes that escape def e4 = { val i: Integer = box(10) // 10 is stored into a new local, loaded as argument for the box call escape(i) // not changed, still loads the local i holding the box unbox(i) // rewritten to a pop (of the box) and a load of the local variable }

   E4 seems to be a bit of a corner case, but it's necessary to unblock box eliminations with mutual dependencies. Example:

   val ((a, b), c) = ((1, 2), 3) a + b + c

   generates (after a few cleanups) the following (pseudo-bytecode, ignoring primitive boxing, specialization):

   load 1, load 2, new Tuple2 // stack: Tuple2 load 3 // stack: Tuple2; Int val local1 = new Tuple2 val local2 = local1._1.asInstanceOf[Tuple2] val c = local1._2.asInstanceOf[Int] if (local2 == null) throw new MatchError(local1) val a = local2._1 val b = local2._2 a + b + c

   In order to eliminate the tuples, we first need to eliminate the outer tuple (stored in local1)

   - single box operation, so we use M1
   - there are three consumers of the outer tuple: `local1._1`, `local1._2` and `new MatchError(local1)`. in the last one, the tuple escapes.
   - note that the MatchError creation is dead code: local2 is never null. However, our nullness analysis cannot identify this: it does not track nullness through tuple stores and loads.
   - if we re-write the non-escaping consumers of the outer tuple, but keep the tuple allocation and the escaping consumer, we get the following:

   load 1, load 2 val newLocal1 = new Tuple2; load newLocal1 // stack: Tuple2 val newLocal2 = 3; load newLocal2 // stack: Tuple2; Int val local1 = new Tuple2 val local2 = newLocal1 val c = newLocal2 if (local2 == null) throw new MatchError(local1) val a = local2._1 val b = local2._2 a + b + c

   At this point, the nullness analysis sees that `local2 == null` is false, dead code elimination removes the `throw new MatchError(local1)`. After eliminating the allocation of the outer tuple, the inner tuple (stored in newLocal1) can also be eliminated.

   Special case for tuples wrt specialization: a tuple getter may box or unbox the value stored in the tuple: calling `_1` on a `Tuple2$mcII$sp` boxes the primitive Int stored in the tuple. Similarly, calling `_1$mcI$sp` on a non-specialized `Tuple2` unboxes the Integer in the tuple. When eliminating such getters, we have to introduce appropriate box / unbox calls.

   TODO: add new calls (box / unbox) to the call graph (not urgent) TODO: update the call graph because stack heights change (not urgent). this may also affect other optimizations, we ignored the issue so far. check how stack heights stored in the call graph are used. Note: these tasks are not urgent because the call graph is not currently used during / after method-local optimizations, only before to perform inlining and closure rewriting.

9.  def checkCopyOpReplacements(initialProds: Set[BoxCreation], finalCons: Set[BoxConsumer], valueTypes: List[Type], nextLocal: Int, prodCons: ProdConsAnalyzer): Option[(Map[AbstractInsnNode, List[AbstractInsnNode]], Int, Map[Int, Type])]

   Takes two sets `initialProds` and `finalCons` such that all boxes produced by the first set are only consumed by an operation in the second set.

   Takes two sets `initialProds` and `finalCons` such that all boxes produced by the first set are only consumed by an operation in the second set.

   Returns a map that replaces copy operations (ALOAD / ASTORE) between the producers and consumers with corresponding copy operations for the values stored in the box. The returned `Int` value returns the next free local variable slot.

   Examples:

   - for an Integer box, an ASTORE x is simply replaced by ISTORE x
   - for a pair of two references, an ASTORE x is replaced by `ASTORE x1; ASTORE x2` where x1 and x2 are fresh locals

   Not all copy operations can be supported: DUP only works for single-value boxes, the more exotic copy operations (DUP2_X2) are not supported (note that Scalac never emits them). If a copy operation cannot be replaced, this method returns `None`.

10.  def clone(): AnyRef
    Attributes
      protected[lang]
    Definition Classes
      AnyRef
    Annotations
      @throws(classOf[java.lang.CloneNotSupportedException]) @native()
11.  def ensuring(cond: (BoxUnbox) => Boolean, msg: => Any): BoxUnbox
    Implicit
      This member is added by an implicit conversion from BoxUnbox toEnsuring[BoxUnbox] performed by method Ensuring in scala.Predef.
    Definition Classes
      Ensuring
12.  def ensuring(cond: (BoxUnbox) => Boolean): BoxUnbox
    Implicit
      This member is added by an implicit conversion from BoxUnbox toEnsuring[BoxUnbox] performed by method Ensuring in scala.Predef.
    Definition Classes
      Ensuring
13.  def ensuring(cond: Boolean, msg: => Any): BoxUnbox
    Implicit
      This member is added by an implicit conversion from BoxUnbox toEnsuring[BoxUnbox] performed by method Ensuring in scala.Predef.
    Definition Classes
      Ensuring
14.  def ensuring(cond: Boolean): BoxUnbox
    Implicit
      This member is added by an implicit conversion from BoxUnbox toEnsuring[BoxUnbox] performed by method Ensuring in scala.Predef.
    Definition Classes
      Ensuring
15.  final def eq(arg0: AnyRef): Boolean
    Definition Classes
      AnyRef
16.  def equals(arg0: AnyRef): Boolean
    Definition Classes
      AnyRef → Any
17.  def finalize(): Unit
    Attributes
      protected[lang]
    Definition Classes
      AnyRef
    Annotations
      @throws(classOf[java.lang.Throwable])
18.  def formatted(fmtstr: String): String
    Implicit
      This member is added by an implicit conversion from BoxUnbox toStringFormat[BoxUnbox] performed by method StringFormat in scala.Predef.
    Definition Classes
      StringFormat
    Annotations
      @inline()
19.  final def getClass(): Class[_ <: AnyRef]
    Definition Classes
      AnyRef → Any
    Annotations
      @native()
20.  def hashCode(): Int
    Definition Classes
      AnyRef → Any
    Annotations
      @native()
21.  final def isInstanceOf[T0]: Boolean
    Definition Classes
      Any
22.  final def ne(arg0: AnyRef): Boolean
    Definition Classes
      AnyRef
23.  final def notify(): Unit
    Definition Classes
      AnyRef
    Annotations
      @native()
24.  final def notifyAll(): Unit
    Definition Classes
      AnyRef
    Annotations
      @native()
25.  final def synchronized[T0](arg0: => T0): T0
    Definition Classes
      AnyRef
26.  def toString(): String
    Definition Classes
      AnyRef → Any
27.  final def wait(): Unit
    Definition Classes
      AnyRef
    Annotations
      @throws(classOf[java.lang.InterruptedException])
28.  final def wait(arg0: Long, arg1: Int): Unit
    Definition Classes
      AnyRef
    Annotations
      @throws(classOf[java.lang.InterruptedException])
29.  final def wait(arg0: Long): Unit
    Definition Classes
      AnyRef
    Annotations
      @throws(classOf[java.lang.InterruptedException]) @native()
30.  object BoxKind
31.  object PrimitiveBox extends java.io.Serializable
32.  object Ref extends java.io.Serializable
33.  object Tuple extends java.io.Serializable

### Deprecated Value Members

1.  def →[B](y: B): (BoxUnbox, B)
   Implicit
     This member is added by an implicit conversion from BoxUnbox toArrowAssoc[BoxUnbox] performed by method ArrowAssoc in scala.Predef.
   Definition Classes
     ArrowAssoc
   Annotations
     @deprecated
   Deprecated

     (Since version 2.13.0) Use `->` instead. If you still wish to display it as one character, consider using a font with programming ligatures such as Fira Code.

### Inherited from AnyRef

### Inherited from Any

### Inherited by implicit conversion any2stringadd fromBoxUnbox to any2stringadd[BoxUnbox]

### Inherited by implicit conversion StringFormat fromBoxUnbox to StringFormat[BoxUnbox]

### Inherited by implicit conversion Ensuring fromBoxUnbox to Ensuring[BoxUnbox]

### Inherited by implicit conversion ArrowAssoc fromBoxUnbox to ArrowAssoc[BoxUnbox]

### Ungrouped