Skip to content
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

-opt:l:inline breaks incremental compilation #537

Open
eed3si9n opened this issue May 2, 2018 · 19 comments
Open

-opt:l:inline breaks incremental compilation #537

eed3si9n opened this issue May 2, 2018 · 19 comments

Comments

@eed3si9n
Copy link
Member

eed3si9n commented May 2, 2018

This was originally reported by @eparejatobes as sbt/sbt#4125 (comment)

Copying here the relevant portion of the link above; see ohnosequences/sbt4125 for more

steps

scalacOptions ++= Seq(
  "-unchecked",
  "-opt-warnings:_",
  "-opt:l:inline",
  "-opt-inline-from:**"
)

Open a shell and

git checkout "x=1"

Now run sbt on a different shell and do ~test. Once it runs for the first time,

git checkout "x=2"

Take a look at the test passing, and the definitions of x and y.

problem

Incremental compilation when used together with the optimizer generates incorrect bytecode: modifications in methods/vals are not propagated to wherever they are being inlined.

expectation

The incremental compiler should not generate incorrect bytecode.

I'd say we revise the expectation to be that change to x=2 is reflected in compilation and run.

notes

I am not sure how prevalent these optimization flags are, but we should probably print warning or invalidate all sources, similar to 50% threshold mechanism.

@smarter
Copy link
Contributor

smarter commented May 2, 2018

Basically, if a method is inlineable, its body is part of its API signature. We deal with that in dotty by storing the pretty-printed body of the method in a signature in ExtractAPI, though it'd be better to store a hash: https://github.com/lampepfl/dotty/blob/a3c4ec793545fd2b922eb469f7fc4d4a7d26b05f/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala#L593-L602

@eed3si9n
Copy link
Member Author

eed3si9n commented May 2, 2018

Interesting. That would give better usability compared to invalidating all sources :)

@eparejatobes
Copy link

Basically, if a method is inlineable, its body is part of its API signature (...)

What about def f = { g(0): @inline }?

@smarter
Copy link
Contributor

smarter commented May 2, 2018

Does that actually do anything in Scala 2.12 ?

@eparejatobes
Copy link

eparejatobes commented May 2, 2018

Does that actually do anything in Scala 2.12 ?

per the docs it should, and I just checked it in the repo linked above; javap yields

with call-site @inline

public int z();
    Code:
       0: iconst_1
       1: getstatic     #19                 // Field issues/sbt4125/inlineFunTimes$.MODULE$:Lissues/sbt4125/inlineFunTimes$;
       4: ifnonnull     9
       7: aconst_null
       8: athrow
       9: iconst_1
      10: iadd
      11: ireturn

no @inline

  public int z();
    Code:
       0: iconst_1
       1: getstatic     #19                 // Field issues/sbt4125/inlineFunTimes$.MODULE$:Lissues/sbt4125/inlineFunTimes$;
       4: invokevirtual #22                 // Method issues/sbt4125/inlineFunTimes$.x:()I
       7: iadd
       8: ireturn

@smarter
Copy link
Contributor

smarter commented May 2, 2018

Huh. I would vote to deprecate that feature then :P

@eed3si9n
Copy link
Member Author

eed3si9n commented May 2, 2018

Could we deprecate all inlining?

@smarter
Copy link
Contributor

smarter commented May 2, 2018

It can be pretty important for performance

@eed3si9n
Copy link
Member Author

eed3si9n commented May 2, 2018

http://slides.com/cb372/inline-specialized-berlin-2016#/27 says it's slightly slower when used with HotSpot, in that particular benchmark.

@eed3si9n
Copy link
Member Author

For now, we should at least print warnings if it's anything less than 100% compilation.

To potential contributor. Related source might be https://github.com/sbt/zinc/blob/v1.1.7/internal/zinc-core/src/main/scala/sbt/internal/inc/IncrementalCommon.scala#L125-L132

@jvican
Copy link
Member

jvican commented Sep 15, 2018

Uf, I haven't looked at the details but fixing this it's quite complicated. We would need to teach Zinc:

  1. To predict inlining that happens in genbcode (Zinc happens after pickler, bytecode optimizations happen at the end of the pipeling)
  2. To understand the semantics of inlining (they can be complicated, not an easy task given how many heuristics they are involved)

I vote to:

  1. Disable incremental compilation when inlining is involved.
  2. Notify the user of this behaviour and advise him to not enable inlining by default in their build.

I'm optimistically labelling this wontfix.

@jvican jvican added the wontfix label Sep 15, 2018
@smarter
Copy link
Contributor

smarter commented Sep 15, 2018

I still think it makes sense for the scalac bridge to implement what I said in #537 (comment)

@jvican
Copy link
Member

jvican commented Sep 15, 2018

I still think it makes sense for the scalac bridge to implement what I said in #537 (comment)

Missed that. Can the scalac genbcode ever inline something that is not marked as @inline? If it can't, then I like your solution. This isn't a high priority for me, so help on this is welcome.

@jvican jvican removed the wontfix label Sep 15, 2018
@smarter
Copy link
Contributor

smarter commented Sep 15, 2018

Can the scalac genbcode ever inline something that is not marked as @inline?

Yes with call-site @inline, as mentioned in #537 (comment) and I also still stand by #537 (comment), this is a terrible feature that should be removed :).

@eed3si9n
Copy link
Member Author

Let's start the petition for the call-site inline removal. Where do we start?

@smarter
Copy link
Contributor

smarter commented Sep 16, 2018

I suggest making a PR to scala/scala that drops the feature and put a warning in its place.

@eparejatobes
Copy link

this is a terrible feature that should be removed :).

Would love to see both reasons and tests for this. I see #537 (comment) as a much more reasonable compromise.

@som-snytt
Copy link
Contributor

Currently (2.13.12),

$ scalac '-opt:inline:<sources>' -d /tmp/sandbox src/main/scala/separateFile.scala src/main/scala/4125.scala
$ javap -c '/tmp/sandbox/issues/sbt4125/useInlinedStuff$.class'
Compiled from "separateFile.scala"
public final class issues.sbt4125.useInlinedStuff$ {
  public static final issues.sbt4125.useInlinedStuff$ MODULE$;

  public static {};
    Code:
       0: new           #2                  // class issues/sbt4125/useInlinedStuff$
       3: dup
       4: invokespecial #12                 // Method "<init>":()V
       7: putstatic     #14                 // Field MODULE$:Lissues/sbt4125/useInlinedStuff$;
      10: return

  public int z();
    Code:
       0: iconst_1
       1: getstatic     #21                 // Field issues/sbt4125/inlineFunTimes$.MODULE$:Lissues/sbt4125/inlineFunTimes$;
       4: pop
       5: iconst_1
       6: iadd
       7: ireturn
}

The inline annotation is not required.

Also, everyone is 5 years older since the previous comments.

@Friendseeker
Copy link
Member

Friendseeker commented Dec 19, 2023

The inline annotation is not required.

Yeah... I honestly thought that #1310 would cut it, until I tested the PR fix against 2.13.12...

Also, everyone is 5 years older since the previous comments.

Maybe I can advertise myself as a historian as I now have experience with digging up 5 year old archaic zinc ticket.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants