From daniel.smith at oracle.com Tue May 13 01:31:58 2025 From: daniel.smith at oracle.com (Dan Smith) Date: Tue, 13 May 2025 01:31:58 +0000 Subject: 2025 JVM Language Summit Message-ID: 2025 JVM LANGUAGE SUMMIT -- CALL FOR SPEAKERS We are pleased to announce the 2025 JVM Language Summit to be held at Oracle?s Santa Clara campus on August 4-6, 2025. Registration is now open for speakers, with general attendee registration coming soon. Speaker submissions will be accepted through May 30. The JVM Language Summit is an open technical collaboration among language designers, compiler writers, tool builders, runtime engineers, and VM architects. We will share our experiences as creators of both the JVM and programming languages for the JVM. We also welcome non-JVM developers of similar technologies to attend or speak on their runtime, VM, or language of choice. Presentations will be recorded and made available to the public. This event is being organized by language and JVM engineers -- no marketers involved! So bring your slide rules and be prepared for some seriously geeky discussions. Please review additional details at: https://jvmlangsummit.com To register: https://register.jvmlangsummit.com Questions: info2025 at jvmlangsummit.com From headius at headius.com Wed May 21 17:42:40 2025 From: headius at headius.com (Charles Oliver Nutter) Date: Wed, 21 May 2025 12:42:40 -0500 Subject: Years later, finally integrating ClassValue... but... Message-ID: Due to issues for years trying to understand the lifecycle of class/value pairs stored in ClassValue, I am only now integrating the JDK-provided version of ClassValue into JRuby's logic to store method tables for Java classes. And I have run into a new inconsistency I want to clarify. The docs for ClassValue state this for the "computeValue" method: "This method will be invoked within the first thread that accesses the value with the get method. Normally, this method is invoked at most once per class, but it may be invoked again if there has been a call to remove." To me, that means computeValue will be invoked *exactly once* per class (ignoring removals), regardless of how many threads attempt to compute it at the same time. Otherwise, what's the point of saying it will be invoked by the "first thread"? But then the docs for "get" say something different: "Returns the value for the given class. If no value has yet been computed, it is obtained by an invocation of the computeValue method. The actual installation of the value on the class is performed atomically. At that point, if several racing threads have computed values, one is chosen, and returned to all the racing threads." Ok hold up... so now it's possible for multiple threads to independently computeValue? These two statements don't appear to mesh... I'm looking for the behavior computeValue describes: basically computeIfAbsent. But in practice (and from what I have read of the current implementation), multiple threads might call computeValue for a given class. In JRuby, where the computation of this value also sets up global namespace tables, it results in warnings that the namespace entry has been initialized multiple times. Adding synchronized to my implementation of computeValue does not help; it just means two threads don't compute at the same time. They will block until the first thread finishes its computeValue, and while that first thread is initializing the ClassValue, they'll proceed to computeValue several more times. This was not a problem with my home-grown ClassValue implementation because I double-check the cache before proceeding into synchronized code that makes the computeValue call (computeIfAbsent behavior). I can work around this by also overriding ClassValue.get to be synchronized, but the existing behavior does not seem right to me. It works this way on 1.8, 21, and 24, so nothing has changed. Either the docs are wrong or the implementation is wrong. *Charles Oliver Nutter* *Architect and Technologist* Headius Enterprises https://www.headius.com headius at headius.com -------------- next part -------------- An HTML attachment was scrubbed... URL: From chen.l.liang at oracle.com Wed May 21 18:47:24 2025 From: chen.l.liang at oracle.com (Chen Liang) Date: Wed, 21 May 2025 18:47:24 +0000 Subject: Years later, finally integrating ClassValue... but... In-Reply-To: References: Message-ID: Hi Charles, Indeed, the docs for "computeValue" was wrong. The doc for "get" was right. The upcoming JDK 25 will provide a spec update that simplifies the mental model of a ClassValue and correct these mistakes in the docs. ClassValue always have been utilizing racy computation, that multiple threads can compute a value, so there is minimal locking - the only locking would be at the time when a thread tries to associate a value. This association is essentially a CAS, where only one thread's computeValue result is ever installed. There is no synchronization lock on computeValue, and there is no way for a synchronized computeValue to check whether a value is already associated. The only threading guarantee provided by ClassValue is that the associated value's identity/value is unique and its computation result is published to all threads that saw the value via a get. If you wish for synchronous initialization, I think you can store a container, such as a memoized function (such as StableValue::supplier), in a ClassValue, and then call the function (or a synchronized initializer) on all accessing threads - this ensures the is exactly one memoized function object, and that object is initialized exactly once. Regards, Chen Liang ________________________________ From: mlvm-dev on behalf of Charles Oliver Nutter Sent: Wednesday, May 21, 2025 12:42 PM To: Da Vinci Machine Project Subject: Years later, finally integrating ClassValue... but... Due to issues for years trying to understand the lifecycle of class/value pairs stored in ClassValue, I am only now integrating the JDK-provided version of ClassValue into JRuby's logic to store method tables for Java classes. And I have run into a new inconsistency I want to clarify. The docs for ClassValue state this for the "computeValue" method: "This method will be invoked within the first thread that accesses the value with the get method. Normally, this method is invoked at most once per class, but it may be invoked again if there has been a call to remove." To me, that means computeValue will be invoked *exactly once* per class (ignoring removals), regardless of how many threads attempt to compute it at the same time. Otherwise, what's the point of saying it will be invoked by the "first thread"? But then the docs for "get" say something different: "Returns the value for the given class. If no value has yet been computed, it is obtained by an invocation of the computeValue method. The actual installation of the value on the class is performed atomically. At that point, if several racing threads have computed values, one is chosen, and returned to all the racing threads." Ok hold up... so now it's possible for multiple threads to independently computeValue? These two statements don't appear to mesh... I'm looking for the behavior computeValue describes: basically computeIfAbsent. But in practice (and from what I have read of the current implementation), multiple threads might call computeValue for a given class. In JRuby, where the computation of this value also sets up global namespace tables, it results in warnings that the namespace entry has been initialized multiple times. Adding synchronized to my implementation of computeValue does not help; it just means two threads don't compute at the same time. They will block until the first thread finishes its computeValue, and while that first thread is initializing the ClassValue, they'll proceed to computeValue several more times. This was not a problem with my home-grown ClassValue implementation because I double-check the cache before proceeding into synchronized code that makes the computeValue call (computeIfAbsent behavior). I can work around this by also overriding ClassValue.get to be synchronized, but the existing behavior does not seem right to me. It works this way on 1.8, 21, and 24, so nothing has changed. Either the docs are wrong or the implementation is wrong. Charles Oliver Nutter Architect and Technologist Headius Enterprises https://www.headius.com headius at headius.com -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Wed May 21 18:59:09 2025 From: forax at univ-mlv.fr (Remi Forax) Date: Wed, 21 May 2025 20:59:09 +0200 (CEST) Subject: Years later, finally integrating ClassValue... but... In-Reply-To: References: Message-ID: <230474542.1416562.1747853949994.JavaMail.zimbra@univ-eiffel.fr> > From: "Chen Liang" > To: "Da Vinci Machine Project" , "Charles Oliver Nutter" > > Sent: Wednesday, May 21, 2025 8:47:24 PM > Subject: Re: Years later, finally integrating ClassValue... but... > Hi Charles, > Indeed, the docs for "computeValue" was wrong. The doc for "get" was right. The > upcoming JDK 25 will provide a spec update that simplifies the mental model of > a ClassValue and correct these mistakes in the docs. > ClassValue always have been utilizing racy computation, that multiple threads > can compute a value, so there is minimal locking - the only locking would be at > the time when a thread tries to associate a value. This association is > essentially a CAS, where only one thread's computeValue result is ever > installed. There is no synchronization lock on computeValue, and there is no > way for a synchronized computeValue to check whether a value is already > associated. The only threading guarantee provided by ClassValue is that the > associated value's identity/value is unique and its computation result is > published to all threads that saw the value via a get. > If you wish for synchronous initialization, I think you can store a container, > such as a memoized function (such as StableValue::supplier), in a ClassValue, > and then call the function (or a synchronized initializer) on all accessing > threads - this ensures the is exactly one memoized function object, and that > object is initialized exactly once. yes, a double check locking (or a stable value but it's in preview in 25) solve the issue. > Regards, > Chen Liang R?mi > From: mlvm-dev on behalf of Charles Oliver Nutter > > Sent: Wednesday, May 21, 2025 12:42 PM > To: Da Vinci Machine Project > Subject: Years later, finally integrating ClassValue... but... > Due to issues for years trying to understand the lifecycle of class/value pairs > stored in ClassValue, I am only now integrating the JDK-provided version of > ClassValue into JRuby's logic to store method tables for Java classes. And I > have run into a new inconsistency I want to clarify. > The docs for ClassValue state this for the "computeValue" method: > "This method will be invoked within the first thread that accesses the value > with the get method. > Normally, this method is invoked at most once per class, but it may be invoked > again if there has been a call to remove." > To me, that means computeValue will be invoked *exactly once* per class > (ignoring removals), regardless of how many threads attempt to compute it at > the same time. Otherwise, what's the point of saying it will be invoked by the > "first thread"? > But then the docs for "get" say something different: > "Returns the value for the given class. If no value has yet been computed, it is > obtained by an invocation of the computeValue method. > The actual installation of the value on the class is performed atomically. At > that point, if several racing threads have computed values, one is chosen, and > returned to all the racing threads." > Ok hold up... so now it's possible for multiple threads to independently > computeValue? These two statements don't appear to mesh... I'm looking for the > behavior computeValue describes: basically computeIfAbsent. But in practice > (and from what I have read of the current implementation), multiple threads > might call computeValue for a given class. > In JRuby, where the computation of this value also sets up global namespace > tables, it results in warnings that the namespace entry has been initialized > multiple times. > Adding synchronized to my implementation of computeValue does not help; it just > means two threads don't compute at the same time. They will block until the > first thread finishes its computeValue, and while that first thread is > initializing the ClassValue, they'll proceed to computeValue several more > times. > This was not a problem with my home-grown ClassValue implementation because I > double-check the cache before proceeding into synchronized code that makes the > computeValue call (computeIfAbsent behavior). > I can work around this by also overriding ClassValue.get to be synchronized, but > the existing behavior does not seem right to me. It works this way on 1.8, 21, > and 24, so nothing has changed. Either the docs are wrong or the implementation > is wrong. > Charles Oliver Nutter > Architect and Technologist > Headius Enterprises > [ https://www.headius.com/ | https://www.headius.com ] > [ mailto:headius at headius.com | headius at headius.com ] > _______________________________________________ > mlvm-dev mailing list > mlvm-dev at openjdk.org > https://mail.openjdk.org/mailman/listinfo/mlvm-dev -------------- next part -------------- An HTML attachment was scrubbed... URL: From headius at headius.com Wed May 21 20:53:52 2025 From: headius at headius.com (Charles Oliver Nutter) Date: Wed, 21 May 2025 15:53:52 -0500 Subject: Years later, finally integrating ClassValue... but... In-Reply-To: <230474542.1416562.1747853949994.JavaMail.zimbra@univ-eiffel.fr> References: <230474542.1416562.1747853949994.JavaMail.zimbra@univ-eiffel.fr> Message-ID: Ok thanks for the confirmations! If I'm understanding correctly, in the future the way to guarantee once-only initialization of a ClassValue would be to have it produce a StableValue, of which only one will be installed, and which will then be guaranteed by the JVM to have once-only initialization and a foldable, stable result. Until that is generally available, I should use a factory object with double-checked locking to ensure once-only initialization (which is essentially what my own ClassValue did, but built as a wrapper around java.lang.ClassValue). On Wed, May 21, 2025 at 1:59?PM Remi Forax wrote: > > > ------------------------------ > > *From: *"Chen Liang" > *To: *"Da Vinci Machine Project" , "Charles Oliver > Nutter" > *Sent: *Wednesday, May 21, 2025 8:47:24 PM > *Subject: *Re: Years later, finally integrating ClassValue... but... > > Hi Charles, > Indeed, the docs for "computeValue" was wrong. The doc for "get" was > right. The upcoming JDK 25 will provide a spec update that simplifies the > mental model of a ClassValue and correct these mistakes in the docs. > > ClassValue always have been utilizing racy computation, that multiple > threads can compute a value, so there is minimal locking - the only locking > would be at the time when a thread tries to associate a value. This > association is essentially a CAS, where only one thread's computeValue > result is ever installed. There is no synchronization lock on computeValue, > and there is no way for a synchronized computeValue to check whether a > value is already associated. The only threading guarantee provided by > ClassValue is that the associated value's identity/value is unique and its > computation result is published to all threads that saw the value via a get. > > If you wish for synchronous initialization, I think you can store a > container, such as a memoized function (such as StableValue::supplier), in > a ClassValue, and then call the function (or a synchronized initializer) on > all accessing threads - this ensures the is exactly one memoized function > object, and that object is initialized exactly once. > > > yes, a double check locking (or a stable value but it's in preview in 25) > solve the issue. > > > Regards, > Chen Liang > > > R?mi > > ------------------------------ > *From:* mlvm-dev on behalf of Charles Oliver > Nutter > *Sent:* Wednesday, May 21, 2025 12:42 PM > *To:* Da Vinci Machine Project > *Subject:* Years later, finally integrating ClassValue... but... > > Due to issues for years trying to understand the lifecycle of class/value > pairs stored in ClassValue, I am only now integrating the JDK-provided > version of ClassValue into JRuby's logic to store method tables for Java > classes. And I have run into a new inconsistency I want to clarify. > > The docs for ClassValue state this for the "computeValue" method: > > "This method will be invoked within the first thread that accesses the > value with the get method. > Normally, this method is invoked at most once per class, but it may be > invoked again if there has been a call to remove." > > To me, that means computeValue will be invoked *exactly once* per class > (ignoring removals), regardless of how many threads attempt to compute it > at the same time. Otherwise, what's the point of saying it will be invoked > by the "first thread"? > > But then the docs for "get" say something different: > > "Returns the value for the given class. If no value has yet been computed, > it is obtained by an invocation of the computeValue method. > The actual installation of the value on the class is performed atomically. > At that point, if several racing threads have computed values, one is > chosen, and returned to all the racing threads." > > Ok hold up... so now it's possible for multiple threads to independently > computeValue? These two statements don't appear to mesh... I'm looking for > the behavior computeValue describes: basically computeIfAbsent. But in > practice (and from what I have read of the current implementation), > multiple threads might call computeValue for a given class. > > In JRuby, where the computation of this value also sets up global > namespace tables, it results in warnings that the namespace entry has been > initialized multiple times. > > Adding synchronized to my implementation of computeValue does not help; it > just means two threads don't compute at the same time. They will block > until the first thread finishes its computeValue, and while that first > thread is initializing the ClassValue, they'll proceed to computeValue > several more times. > > This was not a problem with my home-grown ClassValue implementation > because I double-check the cache before proceeding into synchronized code > that makes the computeValue call (computeIfAbsent behavior). > > I can work around this by also overriding ClassValue.get to be > synchronized, but the existing behavior does not seem right to me. It works > this way on 1.8, 21, and 24, so nothing has changed. Either the docs are > wrong or the implementation is wrong. > > *Charles Oliver Nutter* > *Architect and Technologist* > Headius Enterprises > https://www.headius.com > headius at headius.com > > _______________________________________________ > mlvm-dev mailing list > mlvm-dev at openjdk.org > https://mail.openjdk.org/mailman/listinfo/mlvm-dev > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From chen.l.liang at oracle.com Wed May 21 20:55:44 2025 From: chen.l.liang at oracle.com (Chen Liang) Date: Wed, 21 May 2025 20:55:44 +0000 Subject: [External] : Re: Years later, finally integrating ClassValue... but... In-Reply-To: References: <230474542.1416562.1747853949994.JavaMail.zimbra@univ-eiffel.fr> Message-ID: Yes. You are correct. ________________________________ From: Charles Oliver Nutter Sent: Wednesday, May 21, 2025 3:53 PM To: Remi Forax Cc: Da Vinci Machine Project ; Chen Liang Subject: [External] : Re: Years later, finally integrating ClassValue... but... Ok thanks for the confirmations! If I'm understanding correctly, in the future the way to guarantee once-only initialization of a ClassValue would be to have it produce a StableValue, of which only one will be installed, and which will then be guaranteed by the JVM to have once-only initialization and a foldable, stable result. Until that is generally available, I should use a factory object with double-checked locking to ensure once-only initialization (which is essentially what my own ClassValue did, but built as a wrapper around java.lang.ClassValue). -------------- next part -------------- An HTML attachment was scrubbed... URL: