Skip to content

Inline code leads to a lot of Unit load + discard bytecode #6800

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
jsuereth opened this issue Jul 3, 2019 · 6 comments · Fixed by #9263
Closed

Inline code leads to a lot of Unit load + discard bytecode #6800

jsuereth opened this issue Jul 3, 2019 · 6 comments · Fixed by #9263

Comments

@jsuereth
Copy link

jsuereth commented Jul 3, 2019

I've been using a lot of inline lately and I'm seeing the following bytecode in a lot of places:

N: getstatic     #54  // Field scala/runtime/BoxedUnit.UNIT:Lscala/runtime/BoxedUnit;
N+1: pop

This stems from doing Tuple-pair-wise-peel-off(tm), basically:

inline def doNextThing[Elems](idx: Int, p: Product): Unit =
   inline erasedValue match {
       case _: (a *: b) =>  doThing[a](p.productElement(idx).asInstanceOf)
       case _: Unit => () // Base case
   }

I had thought the empty () would get removed from the AST/generated code, but it seems to show up in bytecode. Additionally, when doing nested Product types with the same technique, I see BoxedUnit accessed and discarded at every nested-product boundary.

@nicolasstucki
Copy link
Contributor

Those where supposed to be handled by the local optimizer which was removed in #4799

@nicolasstucki
Copy link
Contributor

@jsuereth could you give a self contained snippet of code that reproduces the issue?

@jsuereth
Copy link
Author

jsuereth commented Jul 3, 2019

@nicolasstucki I'll be a bit, but I can.

@nicolasstucki
Copy link
Contributor

It is possible that the new backend already optimizes those. Maybe we should wait until we upgrade the backend and see if it is still a problem.

@TheElectronWill
Copy link
Contributor

Hello, has the backend been upgraded? It seems that some BoxedUnits are still there.
Here is a minimal example:

class SpuriousUnits {
  inline def inlined(f: => Unit): Unit = f
  def use: Unit = inlined { println("") }
}

The use method gets compiled to:

getstatic scala/Predef$.MODULE$:scala.Predef$
ldc "" (java.lang.String)
invokevirtual scala/Predef$.println(Ljava/lang/Object;)V
getstatic scala/runtime/BoxedUnit.UNIT:scala.runtime.BoxedUnit
pop

Inline conditionals and matches are also affected:

  inline def printIfZero(x: Int): Unit = inline x match {
    case 0 => println("zero")
    case _ => ()
  }
  
  def useMatch: Unit = printIfZero(0) // contains getstatic BoxedUnit.UNIT at the end

Interestingly, if we do

def noop: Unit = inlined { () }
def useMatch2: Unit = printIfZero(2) // case _ => ()

then BoxedUnit doesn't show up like it seemed to do with jsuereth's code.

@nicolasstucki
Copy link
Contributor

No, the backend has not been upgraded. This is something that will need some time.

nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Jun 30, 2020
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Jun 30, 2020
@nicolasstucki nicolasstucki linked a pull request Jun 30, 2020 that will close this issue
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Jun 30, 2020
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Jul 1, 2020
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Jul 1, 2020
nicolasstucki added a commit that referenced this issue Jul 1, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants