Open smarter opened 4 years ago
Here's some prototype target code @smarter paired with me to write:
This occurs for me in another context: using jlink
to minimize the JVM foot print for a command line tool. My tool only uses the java.base module, so I want to eliminate 600MB of JDK 21 down to a 95MB JDK to deliver with my application. Since my use of threading exceeds the threading capabilities of Scala Native, I can't use that. The same problem occurs with GraalVM (see #13985). So, I'm blocked from minimizing my tool's footprint. :(
This occurs with Scala 3.3.3.
Also: in response to this from the issue description:
actually I don't think this is good enough: using VarHandle would require adding static fields in any class that has a lazy val, so we need to know at compile-time the version of Java we support (via -release/-Xtarget)
I'd be happy if Scala declared a minimum JVM version to the version that supports adding static fields in any class. Didn't the JVM just add its own bytecode manipulation API? I'm okay with JDK 21 as the minimum for Scala, and I'm sure others are not.
Noting that also comes up when using the new given
keyword. implicit val
and implicit def
do not invoke LazyVals and Unsafe. given
does invoke LazyVals and Unsafe.
OOC, why is this not a problem with lazy vals in 2.12 and 2.13? Is there something fundamentally different about lazy vals in 3.x?
@alexklibisz yes, see https://github.com/scala/scala3/pull/15296 (and linked history stretching at least as far back as https://github.com/scala/scala3/pull/6979)
Note: JEP-471 deprecates memory access methods in sun.misc.Unsafe
for removal.
https://openjdk.org/jeps/471
(thanks to @smarter for raising this)
so I guess you can use some static methodhandles that resolve to the right thing at runtime?
BTW, Kotlin uses AtomicReferenceFieldUpdater. Oracle did some work to improve its performance.
And for me personally most important that this ABI depends on the idea that object is located somewhere in flat memory with fields available by some offsets. For some JVM implementations this not necessarily true. So it would be a good step forward if at least at ABI level there was something more high-level, at least similar to interface provided by AtomicReferenceFieldUpdater
. I think OpenJDK is smart enough to optimize any overhead here.
Currently, any usage of a lazy val requires getitng an instance of sun.misc.Unsafe at runtime: https://github.com/lampepfl/dotty/blob/43e4bfa5598e9cdbebb1dc56ed25a319d5aa8fbe/library/src/dotty/runtime/LazyVals.scala#L7 which is problematic for various reasons (e.g. usage of a security manager, using Graal Native (https://github.com/lampepfl/dotty/issues/13985)).
On Java 8, there's no good alternative, but on Java 9+ we should be able to replace that using VarHandle.
We should be able to use the same trick used in scala.runtime.Statics to check once at runtime if VarHandle is available to stay compatible with Java 8: https://github.com/scala/scala/blob/a8a726118d06c90b5506f907b1524457c0d401a7/src/library/scala/runtime/Statics.java#L158-L173(EDIT: actually I don't think this is good enough: using VarHandle would require adding static fields in any class that has a lazy val, so we need to know at compile-time the version of Java we support (via -release/-Xtarget)