Skip to content

Commit 58c2ed4

Browse files
committed
KAFKA-12357: Do not inline methods from the scala package by default (#10174)
As mentioned in #9548, users currently use the kafka jar (`core` module) for integration testing and the current inlining behavior causes problems when the user's classpath contains a different Scala version than the one that was used for compilation (e.g. 2.13.4 versus 2.13.3). An example error: `java.lang.NoClassDefFoundError: scala/math/Ordering$$anon$7` We now disable inlining of the `scala` package by default, but make it easy to enable it for those who so desire (a good option if you can ensure the scala library version matches the one used for compilation). While at it, we make it possible to disable scala compiler optimizations (`none`) or to use only method local optimizations (`method`). This can be useful if optimizing for compilation time during development. Verified behavior by running gradlew with `--debug` and checking the output after `[zinc] The Scala compiler is invoked with:` Reviewers: Chia-Ping Tsai <chia7712@gmail.com>
1 parent 148420f commit 58c2ed4

File tree

2 files changed

+25
-14
lines changed

2 files changed

+25
-14
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,13 @@ The following options should be set with a `-P` switch, for example `./gradlew -
221221
* `enableTestCoverage`: enables test coverage plugins and tasks, including bytecode enhancement of classes required to track said
222222
coverage. Note that this introduces some overhead when running tests and hence why it's disabled by default (the overhead
223223
varies, but 15-20% is a reasonable estimate).
224+
* `scalaOptimizerMode`: configures the optimizing behavior of the scala compiler, the value should be one of `none`, `method`, `inline-kafka` or
225+
`inline-scala` (the default is `inline-kafka`). `none` is the scala compiler default, which only eliminates unreachable code. `method` also
226+
includes method-local optimizations. `inline-kafka` adds inlining of methods within the kafka packages. Finally, `inline-scala` also
227+
includes inlining of methods within the scala library (which avoids lambda allocations for methods like `Option.exists`). `inline-scala` is
228+
only safe if the Scala library version is the same at compile time and runtime. Since we cannot guarantee this for all cases (for example, users
229+
may depend on the kafka jar for integration tests where they may include a scala library with a different version), we don't enable it by
230+
default. See https://www.lightbend.com/blog/scala-inliner-optimizer for more details.
224231

225232
### Dependency Analysis ###
226233

build.gradle

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,12 @@ ext {
134134

135135
userEnableTestCoverage = project.hasProperty("enableTestCoverage") ? enableTestCoverage : false
136136

137+
// See README.md for details on this option and the reasoning for the default
138+
userScalaOptimizerMode = project.hasProperty("scalaOptimizerMode") ? scalaOptimizerMode : "inline-kafka"
139+
def scalaOptimizerValues = ["none", "method", "inline-kafka", "inline-scala"]
140+
if (!scalaOptimizerValues.contains(userScalaOptimizerMode))
141+
throw new GradleException("Unexpected value for scalaOptimizerMode property. Expected one of $scalaOptimizerValues), but received: $userScalaOptimizerMode")
142+
137143
generatedDocsDir = new File("${project.rootDir}/docs/generated")
138144

139145
commitId = project.hasProperty('commitId') ? commitId : null
@@ -515,21 +521,19 @@ subprojects {
515521
"-Xlint:unused"
516522
]
517523

518-
// Inline more aggressively when compiling the `core` jar since it's not meant to be used as a library.
519-
// More specifically, inline classes from the Scala library so that we can inline methods like `Option.exists`
520-
// and avoid lambda allocations. This is only safe if the Scala library version is the same at compile time
521-
// and runtime. We cannot guarantee this for libraries like kafka streams, so only inline classes from the
522-
// Kafka project in that case.
523-
List<String> inlineFrom
524-
if (project.name.equals('core'))
525-
inlineFrom = ["-opt-inline-from:scala.**", "-opt-inline-from:kafka.**", "-opt-inline-from:org.apache.kafka.**"]
526-
else
527-
inlineFrom = ["-opt-inline-from:org.apache.kafka.**"]
524+
// See README.md for details on this option and the meaning of each value
525+
if (userScalaOptimizerMode.equals("method"))
526+
scalaCompileOptions.additionalParameters += ["-opt:l:method"]
527+
else if (userScalaOptimizerMode.startsWith("inline-")) {
528+
List<String> inlineFrom = ["-opt-inline-from:org.apache.kafka.**"]
529+
if (project.name.equals('core'))
530+
inlineFrom.add("-opt-inline-from:kafka.**")
531+
if (userScalaOptimizerMode.equals("inline-scala"))
532+
inlineFrom.add("-opt-inline-from:scala.**")
528533

529-
// Somewhat confusingly, `-opt:l:inline` enables all optimizations. `inlineFrom` configures what can be inlined.
530-
// See https://www.lightbend.com/blog/scala-inliner-optimizer for more information about the optimizer.
531-
scalaCompileOptions.additionalParameters += ["-opt:l:inline"]
532-
scalaCompileOptions.additionalParameters += inlineFrom
534+
scalaCompileOptions.additionalParameters += ["-opt:l:inline"]
535+
scalaCompileOptions.additionalParameters += inlineFrom
536+
}
533537

534538
if (versions.baseScala != '2.12') {
535539
scalaCompileOptions.additionalParameters += ["-opt-warnings", "-Xlint:strict-unsealed-patmat"]

0 commit comments

Comments
 (0)