From dl at cs.oswego.edu Fri Oct 3 11:51:12 2014 From: dl at cs.oswego.edu (Doug Lea) Date: Fri, 03 Oct 2014 07:51:12 -0400 Subject: [jmm-dev] News from the TAR pit Message-ID: <542E8DB0.4040902@cs.oswego.edu> Thanks to Alan Jeffrey for the cute term (TAR: Thin Air Read)! Last week, some people working on these issues in C++/C11 and Java got together informally to discuss problems and ideas; with somewhat more focus on C/C++ than Java. Some slides and notes can be found at: http://www.cl.cam.ac.uk/~pes20/MMmeet-2014-09-slides.html Several new ideas to explore arose from this, but no magic bullet emerged that would enable immediate progress on the foundational issues of JMM revision necessary to unblock progress on other fronts. -Doug From ajeffrey at bell-labs.com Fri Oct 3 13:15:48 2014 From: ajeffrey at bell-labs.com (Alan Jeffrey) Date: Fri, 3 Oct 2014 08:15:48 -0500 Subject: [jmm-dev] Acyclicity of rf and dependent program order Message-ID: <542EA184.2060708@bell-labs.com> Hi all, Here are some half-baked ideas, this time about acyclicity of rf and dependent program order. The idea is that requiring (rf \cup po) to be acyclic is too strong. Really what is wanted is a notion of "dependent program order" (dpo) such that we require (rf \cup dpo) to be acyclic. What follows is an attempt to define dpo. I'm ignoring synchronization actions for now. Reminder: - A labelled event structure with alphabet Sigma is a tuple (E,<=,#,l) where E is a set of events, <= is a partial order on E, # is a binary relation on E, and l is a function from E to Sigma such that [...] - Define d~e in a labelled event structure to be the "minimal conflict" relation: d#e and for any (d => b # c <= e) we have (d = b # c = e). In examples, d~e when they are events from "the same" read, with different values being read. - A memory model alphabet is (Sigma,RWC,RWJ) is a set Sigma with binary relations RWJ \subseteq RWC on Sigma such that [...] - A pre-configuration C is a <=-downclosed subset of E. Write (d \simeq e) whenever (d ~ e) or (d = e). In examples, d \simeq e when they are events from "the same" read. Let a pre-configuration C be read-enabled whenever, for any d,e in C, if (d,e) in RWC then there exists c \simeq e where (d,c) in RWJ. In examples, this is saying that if (R x=0) and (W x=1) are in C, then there must be (R x=1) in C from "the same" read. In a pre-configuration C, e in C is guaranteed to perform a whenever, for any e<=d in C there exists c in C such that l(c)=a and either e<=c<=d or e<=d<=c. In a pre-configuration C, d <= e is independent whenever for any c in C if (c \simeq d) then c is guaranteed to perform l(e). Let ipo be the independent program order, and dpo be the dependent program order. So now, the proposed requirement is to find a read-enabled pre-configuration in which (rf \cup dpo) is acyclic. Note this handles the canonical cases, for example the TAR pit has a cycle in (rf cup dpo) given by: (R x=42) --dpo--> (W y=42) --rf--> (R y=42) --dpo--> (W x=42) --rf--> whereas the version where the second thread is (r=y; x=42) has no cycle since: (R x=42) --dpo--> (W y=42) --rf--> (R y=42) --ipo--> (W x=42) --rf--> This even deals with range analysis, for example if we make the second thread (r=y; if (r < 43) { x=42; } else { x=100; }) then we get the same pre-configuration, with no cycle: (R x=42) --dpo--> (W y=42) --rf--> (R y=42) --ipo--> (W x=42) --rf--> This definition seems to be in line with the thinking at the Cambridge workshop about trying to define semantic dependency. I'm sure there is some horror (e.g. in proving the DRF theorem, or scaling up to handle synchronization actions). Thoughts? Alan. From bdemsky at uci.edu Fri Oct 3 20:57:51 2014 From: bdemsky at uci.edu (Brian Demsky) Date: Fri, 3 Oct 2014 13:57:51 -0700 Subject: [jmm-dev] Acyclicity of rf and dependent program order In-Reply-To: <542EA184.2060708@bell-labs.com> References: <542EA184.2060708@bell-labs.com> Message-ID: <7A692C1A-E2F7-4DBC-9E6C-BF958D5C88E6@uci.edu> Hi Alan, How does this work with the JMM causality test case 3? ( http://www.cs.umd.edu/~pugh/java/memoryModel/CausalityTestCases.html ) My naive reading of the definitions would seem to imply that y=1 would depend the loads r1=x and r2=x and thus forbid the execution. Brian BrianOn Oct 3, 2014, at 6:15 AM, Alan Jeffrey wrote: > Hi all, > > Here are some half-baked ideas, this time about acyclicity of rf and dependent program order. > > The idea is that requiring (rf \cup po) to be acyclic is too strong. Really what is wanted is a notion of "dependent program order" (dpo) such that we require (rf \cup dpo) to be acyclic. > > What follows is an attempt to define dpo. I'm ignoring synchronization actions for now. > > Reminder: > > - A labelled event structure with alphabet Sigma is a tuple (E,<=,#,l) where E is a set of events, <= is a partial order on E, # is a binary relation on E, and l is a function from E to Sigma such that [...] > > - Define d~e in a labelled event structure to be the "minimal conflict" relation: d#e and for any (d => b # c <= e) we have (d = b # c = e). In examples, d~e when they are events from "the same" read, with different values being read. > > - A memory model alphabet is (Sigma,RWC,RWJ) is a set Sigma with binary relations RWJ \subseteq RWC on Sigma such that [...] > > - A pre-configuration C is a <=-downclosed subset of E. > > Write (d \simeq e) whenever (d ~ e) or (d = e). In examples, d \simeq e when they are events from "the same" read. > > Let a pre-configuration C be read-enabled whenever, for any d,e in C, if (d,e) in RWC then there exists c \simeq e where (d,c) in RWJ. In examples, this is saying that if (R x=0) and (W x=1) are in C, then there must be (R x=1) in C from "the same" read. > > In a pre-configuration C, e in C is guaranteed to perform a whenever, for any e<=d in C there exists c in C such that l(c)=a and either e<=c<=d or e<=d<=c. > > In a pre-configuration C, d <= e is independent whenever for any c in C if (c \simeq d) then c is guaranteed to perform l(e). Let ipo be the independent program order, and dpo be the dependent program order. > > So now, the proposed requirement is to find a read-enabled pre-configuration in which (rf \cup dpo) is acyclic. > > Note this handles the canonical cases, for example the TAR pit has a cycle in (rf cup dpo) given by: > > (R x=42) --dpo--> (W y=42) --rf--> (R y=42) --dpo--> (W x=42) --rf--> > > whereas the version where the second thread is (r=y; x=42) has no cycle since: > > (R x=42) --dpo--> (W y=42) --rf--> (R y=42) --ipo--> (W x=42) --rf--> > > This even deals with range analysis, for example if we make the second thread (r=y; if (r < 43) { x=42; } else { x=100; }) then we get the same pre-configuration, with no cycle: > > (R x=42) --dpo--> (W y=42) --rf--> (R y=42) --ipo--> (W x=42) --rf--> > > This definition seems to be in line with the thinking at the Cambridge workshop about trying to define semantic dependency. I'm sure there is some horror (e.g. in proving the DRF theorem, or scaling up to handle synchronization actions). > > Thoughts? > > Alan. > From boehm at acm.org Fri Oct 3 22:18:44 2014 From: boehm at acm.org (Hans Boehm) Date: Fri, 3 Oct 2014 15:18:44 -0700 Subject: [jmm-dev] Acyclicity of rf and dependent program order In-Reply-To: <7A692C1A-E2F7-4DBC-9E6C-BF958D5C88E6@uci.edu> References: <542EA184.2060708@bell-labs.com> <7A692C1A-E2F7-4DBC-9E6C-BF958D5C88E6@uci.edu> Message-ID: I'd like to have more of an intuition for how this differs (aside from the difference in formalism) from the current Java memory model. I'd really like to understand if and how we're solving the original problems. What happens in Alan's model with Sevcik and Aspinall's examples, for example (everything initially zero) Thread 1: y = x; Thread 2: r2 = y; x=(r2==1)?y:1; In practice, as Jaroslav points out ( http://www.dagstuhl.de/mat/Files/11/11011/11011.SevcikJaroslav.Slides.pdf) this can currently result in r2 = x = y = 1, by eliminating the second read of y in thread 2, and noting that the right side is always 1. Hans On Fri, Oct 3, 2014 at 1:57 PM, Brian Demsky wrote: > Hi Alan, > > How does this work with the JMM causality test case 3? ( > http://www.cs.umd.edu/~pugh/java/memoryModel/CausalityTestCases.html ) > > My naive reading of the definitions would seem to imply that y=1 would > depend the loads r1=x and r2=x and thus forbid the execution. > > Brian > > BrianOn Oct 3, 2014, at 6:15 AM, Alan Jeffrey > wrote: > > > Hi all, > > > > Here are some half-baked ideas, this time about acyclicity of rf and > dependent program order. > > > > The idea is that requiring (rf \cup po) to be acyclic is too strong. > Really what is wanted is a notion of "dependent program order" (dpo) such > that we require (rf \cup dpo) to be acyclic. > > > > What follows is an attempt to define dpo. I'm ignoring synchronization > actions for now. > > > > Reminder: > > > > - A labelled event structure with alphabet Sigma is a tuple (E,<=,#,l) > where E is a set of events, <= is a partial order on E, # is a binary > relation on E, and l is a function from E to Sigma such that [...] > > > > - Define d~e in a labelled event structure to be the "minimal conflict" > relation: d#e and for any (d => b # c <= e) we have (d = b # c = e). In > examples, d~e when they are events from "the same" read, with different > values being read. > > > > - A memory model alphabet is (Sigma,RWC,RWJ) is a set Sigma with binary > relations RWJ \subseteq RWC on Sigma such that [...] > > > > - A pre-configuration C is a <=-downclosed subset of E. > > > > Write (d \simeq e) whenever (d ~ e) or (d = e). In examples, d \simeq e > when they are events from "the same" read. > > > > Let a pre-configuration C be read-enabled whenever, for any d,e in C, if > (d,e) in RWC then there exists c \simeq e where (d,c) in RWJ. In examples, > this is saying that if (R x=0) and (W x=1) are in C, then there must be (R > x=1) in C from "the same" read. > > > > In a pre-configuration C, e in C is guaranteed to perform a whenever, > for any e<=d in C there exists c in C such that l(c)=a and either e<=c<=d > or e<=d<=c. > > > > In a pre-configuration C, d <= e is independent whenever for any c in C > if (c \simeq d) then c is guaranteed to perform l(e). Let ipo be the > independent program order, and dpo be the dependent program order. > > > > So now, the proposed requirement is to find a read-enabled > pre-configuration in which (rf \cup dpo) is acyclic. > > > > Note this handles the canonical cases, for example the TAR pit has a > cycle in (rf cup dpo) given by: > > > > (R x=42) --dpo--> (W y=42) --rf--> (R y=42) --dpo--> (W x=42) --rf--> > > > > whereas the version where the second thread is (r=y; x=42) has no cycle > since: > > > > (R x=42) --dpo--> (W y=42) --rf--> (R y=42) --ipo--> (W x=42) --rf--> > > > > This even deals with range analysis, for example if we make the second > thread (r=y; if (r < 43) { x=42; } else { x=100; }) then we get the same > pre-configuration, with no cycle: > > > > (R x=42) --dpo--> (W y=42) --rf--> (R y=42) --ipo--> (W x=42) --rf--> > > > > This definition seems to be in line with the thinking at the Cambridge > workshop about trying to define semantic dependency. I'm sure there is some > horror (e.g. in proving the DRF theorem, or scaling up to handle > synchronization actions). > > > > Thoughts? > > > > Alan. > > > > From ajeffrey at bell-labs.com Fri Oct 3 23:25:19 2014 From: ajeffrey at bell-labs.com (Alan Jeffrey) Date: Fri, 3 Oct 2014 18:25:19 -0500 Subject: [jmm-dev] Acyclicity of rf and dependent program order In-Reply-To: <7A692C1A-E2F7-4DBC-9E6C-BF958D5C88E6@uci.edu> References: <542EA184.2060708@bell-labs.com> <7A692C1A-E2F7-4DBC-9E6C-BF958D5C88E6@uci.edu> Message-ID: <542F305F.2090503@bell-labs.com> Good point. I think this is fixable by changing rf so that a read can rf another read with the same label, and then only require read-enablement on reads which rf a write. But this is getting a bit hairy... This is quite a weird test case, but it's difficult to argue with the optimization that causes it: r1 = x; r2 = x; P --> r1 = x; r2 = r1; P A. On 10/03/2014 03:57 PM, Brian Demsky wrote: > Hi Alan, > > How does this work with the JMM causality test case 3? ( > http://www.cs.umd.edu/~pugh/java/memoryModel/CausalityTestCases.html ) > > My naive reading of the definitions would seem to imply that y=1 would > depend the loads r1=x and r2=x and thus forbid the execution. > > Brian > > BrianOn Oct 3, 2014, at 6:15 AM, Alan Jeffrey > wrote: > >> Hi all, >> >> Here are some half-baked ideas, this time about acyclicity of rf and >> dependent program order. >> >> The idea is that requiring (rf \cup po) to be acyclic is too strong. >> Really what is wanted is a notion of "dependent program order" (dpo) >> such that we require (rf \cup dpo) to be acyclic. >> >> What follows is an attempt to define dpo. I'm ignoring synchronization >> actions for now. >> >> Reminder: >> >> - A labelled event structure with alphabet Sigma is a tuple (E,<=,#,l) >> where E is a set of events, <= is a partial order on E, # is a binary >> relation on E, and l is a function from E to Sigma such that [...] >> >> - Define d~e in a labelled event structure to be the "minimal >> conflict" relation: d#e and for any (d => b # c <= e) we have (d = b # >> c = e). In examples, d~e when they are events from "the same" read, >> with different values being read. >> >> - A memory model alphabet is (Sigma,RWC,RWJ) is a set Sigma with >> binary relations RWJ \subseteq RWC on Sigma such that [...] >> >> - A pre-configuration C is a <=-downclosed subset of E. >> >> Write (d \simeq e) whenever (d ~ e) or (d = e). In examples, d \simeq >> e when they are events from "the same" read. >> >> Let a pre-configuration C be read-enabled whenever, for any d,e in C, >> if (d,e) in RWC then there exists c \simeq e where (d,c) in RWJ. In >> examples, this is saying that if (R x=0) and (W x=1) are in C, then >> there must be (R x=1) in C from "the same" read. >> >> In a pre-configuration C, e in C is guaranteed to perform a whenever, >> for any e<=d in C there exists c in C such that l(c)=a and either >> e<=c<=d or e<=d<=c. >> >> In a pre-configuration C, d <= e is independent whenever for any c in >> C if (c \simeq d) then c is guaranteed to perform l(e). Let ipo be the >> independent program order, and dpo be the dependent program order. >> >> So now, the proposed requirement is to find a read-enabled >> pre-configuration in which (rf \cup dpo) is acyclic. >> >> Note this handles the canonical cases, for example the TAR pit has a >> cycle in (rf cup dpo) given by: >> >> (R x=42) --dpo--> (W y=42) --rf--> (R y=42) --dpo--> (W x=42) --rf--> >> >> whereas the version where the second thread is (r=y; x=42) has no >> cycle since: >> >> (R x=42) --dpo--> (W y=42) --rf--> (R y=42) --ipo--> (W x=42) --rf--> >> >> This even deals with range analysis, for example if we make the second >> thread (r=y; if (r < 43) { x=42; } else { x=100; }) then we get the >> same pre-configuration, with no cycle: >> >> (R x=42) --dpo--> (W y=42) --rf--> (R y=42) --ipo--> (W x=42) --rf--> >> >> This definition seems to be in line with the thinking at the Cambridge >> workshop about trying to define semantic dependency. I'm sure there is >> some horror (e.g. in proving the DRF theorem, or scaling up to handle >> synchronization actions). >> >> Thoughts? >> >> Alan. >> > From ajeffrey at bell-labs.com Fri Oct 3 23:35:29 2014 From: ajeffrey at bell-labs.com (Alan Jeffrey) Date: Fri, 3 Oct 2014 18:35:29 -0500 Subject: [jmm-dev] Acyclicity of rf and dependent program order In-Reply-To: References: <542EA184.2060708@bell-labs.com> <7A692C1A-E2F7-4DBC-9E6C-BF958D5C88E6@uci.edu> Message-ID: <542F32C1.60100@bell-labs.com> I think this is essentially the same example. With the definition below the write (W x=1) is dependent on the second read (R y=1), but if you allow reads to justify reads then they're independent. A. On 10/03/2014 05:18 PM, Hans Boehm wrote: > I'd like to have more of an intuition for how this differs (aside from > the difference in formalism) from the current Java memory model. I'd > really like to understand if and how we're solving the original problems. > > What happens in Alan's model with Sevcik and Aspinall's examples, for > example > > (everything initially zero) > > Thread 1: > y = x; > > Thread 2: > r2 = y; x=(r2==1)?y:1; > > In practice, as Jaroslav points out > (http://www.dagstuhl.de/mat/Files/11/11011/11011.SevcikJaroslav.Slides.pdf) > this can currently result in r2 = x = y = 1, by eliminating the second > read of y in thread 2, and noting that the right side is always 1. > > Hans > > On Fri, Oct 3, 2014 at 1:57 PM, Brian Demsky > wrote: > > Hi Alan, > > How does this work with the JMM causality test case 3? ( > http://www.cs.umd.edu/~pugh/java/memoryModel/CausalityTestCases.html ) > > My naive reading of the definitions would seem to imply that y=1 > would depend the loads r1=x and r2=x and thus forbid the execution. > > Brian > > BrianOn Oct 3, 2014, at 6:15 AM, Alan Jeffrey > > wrote: > > > Hi all, > > > > Here are some half-baked ideas, this time about acyclicity of rf > and dependent program order. > > > > The idea is that requiring (rf \cup po) to be acyclic is too > strong. Really what is wanted is a notion of "dependent program > order" (dpo) such that we require (rf \cup dpo) to be acyclic. > > > > What follows is an attempt to define dpo. I'm ignoring > synchronization actions for now. > > > > Reminder: > > > > - A labelled event structure with alphabet Sigma is a tuple > (E,<=,#,l) where E is a set of events, <= is a partial order on E, # > is a binary relation on E, and l is a function from E to Sigma such > that [...] > > > > - Define d~e in a labelled event structure to be the "minimal > conflict" relation: d#e and for any (d => b # c <= e) we have (d = b > # c = e). In examples, d~e when they are events from "the same" > read, with different values being read. > > > > - A memory model alphabet is (Sigma,RWC,RWJ) is a set Sigma with > binary relations RWJ \subseteq RWC on Sigma such that [...] > > > > - A pre-configuration C is a <=-downclosed subset of E. > > > > Write (d \simeq e) whenever (d ~ e) or (d = e). In examples, d > \simeq e when they are events from "the same" read. > > > > Let a pre-configuration C be read-enabled whenever, for any d,e > in C, if (d,e) in RWC then there exists c \simeq e where (d,c) in > RWJ. In examples, this is saying that if (R x=0) and (W x=1) are in > C, then there must be (R x=1) in C from "the same" read. > > > > In a pre-configuration C, e in C is guaranteed to perform a > whenever, for any e<=d in C there exists c in C such that l(c)=a and > either e<=c<=d or e<=d<=c. > > > > In a pre-configuration C, d <= e is independent whenever for any > c in C if (c \simeq d) then c is guaranteed to perform l(e). Let ipo > be the independent program order, and dpo be the dependent program > order. > > > > So now, the proposed requirement is to find a read-enabled > pre-configuration in which (rf \cup dpo) is acyclic. > > > > Note this handles the canonical cases, for example the TAR pit > has a cycle in (rf cup dpo) given by: > > > > (R x=42) --dpo--> (W y=42) --rf--> (R y=42) --dpo--> (W x=42) > --rf--> > > > > whereas the version where the second thread is (r=y; x=42) has no > cycle since: > > > > (R x=42) --dpo--> (W y=42) --rf--> (R y=42) --ipo--> (W x=42) > --rf--> > > > > This even deals with range analysis, for example if we make the > second thread (r=y; if (r < 43) { x=42; } else { x=100; }) then we > get the same pre-configuration, with no cycle: > > > > (R x=42) --dpo--> (W y=42) --rf--> (R y=42) --ipo--> (W x=42) > --rf--> > > > > This definition seems to be in line with the thinking at the > Cambridge workshop about trying to define semantic dependency. I'm > sure there is some horror (e.g. in proving the DRF theorem, or > scaling up to handle synchronization actions). > > > > Thoughts? > > > > Alan. > > > > From boehm at acm.org Sat Oct 4 00:20:40 2014 From: boehm at acm.org (Hans Boehm) Date: Fri, 3 Oct 2014 17:20:40 -0700 Subject: [jmm-dev] Non-core-model issues status In-Reply-To: References: <54032B87.4040703@cs.oswego.edu> <540AF866.1000709@cs.oswego.edu> <540EE3CF.5000008@cs.oswego.edu> Message-ID: Let me try restating the proposed finalization rules and moving the annotation from a filed to the containing class. As far as I can tell, the annotation we've been discussing really only impacts the treatment of the containing class, so that seems to be a more logical place for it. 1. A class is reachability-sensitive if it has a non-default finalizer or is suitably annotated (e.g. because its instances are cleaned up by a finalizer guardian or through a reference queue). 2. A reference variable is reachability-sensitive if its static type is a reachability-sensitive class (Q1: or array of such?). 3. The end of the scope of a reachability-sensitive variable synchronizes with the invocation of the finalize() method on the object to which it last referred. For this purpose, the "this" reference is treated as an implicit parameter to member functions. (Q2: The treatment of expression temporary reachability-sensitive references is unclear. Do we treat them as though they had a scope that lasts through the end of the full expression, as for C++ destructors?) I think this is implementable at modest performance cost, though non-trivial compiler engineering cost. To enforce (3) the compiler mist either treat the end of such a scope as a release operation (though without the actual fence) or refrain from moving operations across the next GC safe-point. The GC should then guarantee sufficient synchronization. Hard real-time GCs may have other issues, but I would be surprised if this became expensive to enforce. We don't enforce a corresponding property for references whose static type is not reachability-sensitive while their dynamic type is. I think that's generally OK, since the fields being cleaned up by a finalizer can't be accessed in such a context without entering another one in which the static reachability-sensitive type is visible. There's usually a similar argument for indirect references to reachability-sensitive objects. It seems to me that this would implicitly make most code that either naively used finalizers (instead of finalizer guardians or java.lang.ref) or correctly annotated finalizable classes correct. Q3: Where does this leave the current conditions in http://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.6.2 ? Can we just drop it? Hans On Wed, Sep 17, 2014 at 2:45 PM, Hans Boehm wrote: > On Tue, Sep 9, 2014 at 4:26 AM, Doug Lea
wrote: > > > > On 09/07/2014 01:55 AM, Hans Boehm wrote: > >> > >> we seem to have lots of evidence that essentially everyone currently > gets > >> this code wrong, introducing premature deallocations. > > > > > > Continuing in vacillation mode.... What do you think of > > the following concrete version of Jeremy's original > > suggestion: > > > > 1. Introduce reachabilityFence (or whatever name; > > How about "keepReachable"?) > > > > 2. Spec at syntax level that every declaration and > > use of a local (or param) ref to an object of a class F > > defining finalize() is translated from: > > F f; > > ... > > > > to: > > F f; > > try { > > ... > > > > } finally > > if (f != null) reachabilityFence(f); > > } > > > > It might be a little challenging to spec this to cover multiple > > refs while keeping blocked scopes, but it seems feasible. > > I think that's similar to the earlier proposal with annotations, except > that we're back to "defining finalize()" as the criterion for when to apply > it. I think that's the wrong criterion. Counterexamples: > > - Any class that uses a finalizer guardian (recommended practice in > places, I think) to perform finalization on its behalf. > > - Any object that's "finalized" by enqueuing it on a reference queue > instead of using a "finalize()" method. (Recommended practice to deal with > the lack of finalize() ordering.) > > I think we need a field annotation A that basically says: "This field > becomes unusable once the enclosing object becomes unreachable". That's > only loosely correlated with defining a finalize() method. We then > essentially guarantee that every method that uses a field x.f, where f is > annotated with A keeps x reachable as long as that would be expected by the > naive semantics, by performing the transformation you suggest. > > I'm not sure, but I think we might be able to avoid dealing with > transitive reachability issues. If field f is annotated with a, and I have > > T' x = ...; > { > T y = x.a; > { > foo(y.f); > } > } > > where x is finalizable with a finalizer that invalidates f, I should > annotate both a and f, and the right things should happen. And that > actually makes sense, I think. > > For things like new T'().a.foo(), where foo uses f, to work correctly, we > probably need something like the C++ rule in the "naive semantics", that > references stay around until the end of the enclosing full expression. > > This requires more thought, but this annotation seems to be significantly > easier and cleaner to use than reachabilityFence. > > Hans > > > > > This seems to completely address premature finalization, > > at the expense of lack of control in the other direction. > > > > The only middle ground I see is the one you like least, > > of telling people to write their own try-finally blocks. > > > > -Doug > > > > > > > From dl at cs.oswego.edu Sun Oct 5 14:24:59 2014 From: dl at cs.oswego.edu (Doug Lea) Date: Sun, 05 Oct 2014 10:24:59 -0400 Subject: [jmm-dev] Non-core-model issues status In-Reply-To: References: <54032B87.4040703@cs.oswego.edu> <540AF866.1000709@cs.oswego.edu> <540EE3CF.5000008@cs.oswego.edu> Message-ID: <543154BB.2050207@cs.oswego.edu> On 10/03/2014 08:20 PM, Hans Boehm wrote: > Let me try restating the proposed finalization rules and moving the annotation > from a field to the containing class. As far as I can tell, the annotation > we've been discussing really only impacts the treatment of the containing class, > so that seems to be a more logical place for it. Thanks. Seeing this fleshed out leads me again to prefer a simpler (for us) option: Defining reachabilityFence() and introducing but not requiring support for your annotation @ReachabilitySensitive (modulo names for these). Backing up to explain why... Finalization reveals a mismatch between JVM-level lifetimes and source-code-level block scopes. Most programmers implicity expect that reachability continues to the end of enclosing block. But the only Java syntactic constructs guaranteed to preserve this entail locking. Probably the best default advice is to always use synchronized blocks/methods (or other j.u.c locks in try-finally constructions) when accessing finalizable resources (as well as in the finalize methods themselves). But when people can't or don't want to use locking (not even the hacky and possibly slow but effective trailing "synchronized(x){}") they should be able to use try {...} finally {reachabilityFence(x);} (which acts as an RCU-ish read-lock with respect to GC). Or, in some cases (e.g., ThreadPoolExecutor), do nothing, because nothing bad can happen anyway. Automated placement of any of these forms of lifetime control must be done at source level, because scope information is not guaranteed to be preserved in bytecode. (Although live-range debugging information in class files might suffice in many cases.) Different languages running on JVMs might have different scoping constructs and rules. To nail them down, languages would need to add C++-destructor-like rules as Hans sketched out. But even if they do, in Java and probably all JVM-hosted languages, a front-end compiler's ability to automate placement of reachability fences is limited by static type information. For example, a reference of nominal type Object might be a FileHandle, and even a call to an Object method like hashCode() might require reachabililty protection. Insisting on the elimination of all possible lifetime mismatches requires compilers to always insert reachability fences unless provably not necessary, either because the object is known to be of a type without a finalizer, or one of the above manual techniques already occurs in the source code. Even though it is rarely necessary to insert reachability fences, most proofs require analyses that front-end compilers do not perform. So, guaranteeing lack of scope-lifetime surprise doesn't look like a promising option. Instead we can require something like Hans sketched out that is good but imperfect, or fall back to introducing annotation @ReachabilitySensitive (implicitly applied to classes with non-default finalize()), but not requiring any compile-time or run-time properties. And then encouraging tool/IDE developers to support it to help programmers avoid bugs. These might include points-to analyses to minimize impact, warnings about upcasts from @ReachabilitySensitive, suggested alternatives to using finalize(), and so on. If people using finalization came to rely on such tools, I'd expect the tools would become better at this than we could ever mandate as part of language/VM spec. As always, I realize that finding a middle ground between deprecating and "fixing" finalize() can be a tough sell to both sides. Other ideas welcome. -Doug > > 1. A class is reachability-sensitive if it has a non-default finalizer or is > suitably annotated (e.g. because its instances are cleaned up by a finalizer > guardian or through a reference queue). > > 2. A reference variable is reachability-sensitive if its static type is a > reachability-sensitive class (Q1: or array of such?). > > 3. The end of the scope of a reachability-sensitive variable synchronizes with > the invocation of the finalize() method on the object to which it last > referred. For this purpose, the "this" reference is treated as an implicit > parameter to member functions. (Q2: The treatment of expression temporary > reachability-sensitive references is unclear. Do we treat them as though they > had a scope that lasts through the end of the full expression, as for C++ > destructors?) > > I think this is implementable at modest performance cost, though non-trivial > compiler engineering cost. To enforce (3) the compiler mist either treat the > end of such a scope as a release operation (though without the actual fence) or > refrain from moving operations across the next GC safe-point. The GC should > then guarantee sufficient synchronization. Hard real-time GCs may have other > issues, but I would be surprised if this became expensive to enforce. > > We don't enforce a corresponding property for references whose static type is > not reachability-sensitive while their dynamic type is. I think that's > generally OK, since the fields being cleaned up by a finalizer can't be accessed > in such a context without entering another one in which the static > reachability-sensitive type is visible. There's usually a similar argument for > indirect references to reachability-sensitive objects. > > It seems to me that this would implicitly make most code that either naively > used finalizers (instead of finalizer guardians or java.lang.ref) or correctly > annotated finalizable classes correct. > > Q3: Where does this leave the current conditions in > http://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.6.2 ? Can > we just drop it? > > Hans > > On Wed, Sep 17, 2014 at 2:45 PM, Hans Boehm > wrote: > > On Tue, Sep 9, 2014 at 4:26 AM, Doug Lea
> wrote: > > > > On 09/07/2014 01:55 AM, Hans Boehm wrote: > >> > >> we seem to have lots of evidence that essentially everyone currently gets > >> this code wrong, introducing premature deallocations. > > > > > > Continuing in vacillation mode.... What do you think of > > the following concrete version of Jeremy's original > > suggestion: > > > > 1. Introduce reachabilityFence (or whatever name; > > How about "keepReachable"?) > > > > 2. Spec at syntax level that every declaration and > > use of a local (or param) ref to an object of a class F > > defining finalize() is translated from: > > F f; > > ... > > > > to: > > F f; > > try { > > ... > > > > } finally > > if (f != null) reachabilityFence(f); > > } > > > > It might be a little challenging to spec this to cover multiple > > refs while keeping blocked scopes, but it seems feasible. > > I think that's similar to the earlier proposal with annotations, except that > we're back to "defining finalize()" as the criterion for when to apply it. > I think that's the wrong criterion. Counterexamples: > > - Any class that uses a finalizer guardian (recommended practice in places, > I think) to perform finalization on its behalf. > > - Any object that's "finalized" by enqueuing it on a reference queue instead > of using a "finalize()" method. (Recommended practice to deal with the lack > of finalize() ordering.) > > I think we need a field annotation A that basically says: "This field > becomes unusable once the enclosing object becomes unreachable". That's > only loosely correlated with defining a finalize() method. We then > essentially guarantee that every method that uses a field x.f, where f is > annotated with A keeps x reachable as long as that would be expected by the > naive semantics, by performing the transformation you suggest. > > I'm not sure, but I think we might be able to avoid dealing with transitive > reachability issues. If field f is annotated with a, and I have > > T' x = ...; > { > T y = x.a; > { > foo(y.f); > } > } > > where x is finalizable with a finalizer that invalidates f, I should > annotate both a and f, and the right things should happen. And that > actually makes sense, I think. > > For things like new T'().a.foo(), where foo uses f, to work correctly, we > probably need something like the C++ rule in the "naive semantics", that > references stay around until the end of the enclosing full expression. > > This requires more thought, but this annotation seems to be significantly > easier and cleaner to use than reachabilityFence. > > Hans > > > > > This seems to completely address premature finalization, > > at the expense of lack of control in the other direction. > > > > The only middle ground I see is the one you like least, > > of telling people to write their own try-finally blocks. > > > > -Doug > > > > > > > > From boehm at acm.org Tue Oct 7 22:23:58 2014 From: boehm at acm.org (Hans Boehm) Date: Tue, 7 Oct 2014 15:23:58 -0700 Subject: [jmm-dev] Non-core-model issues status In-Reply-To: <543154BB.2050207@cs.oswego.edu> References: <54032B87.4040703@cs.oswego.edu> <540AF866.1000709@cs.oswego.edu> <540EE3CF.5000008@cs.oswego.edu> <543154BB.2050207@cs.oswego.edu> Message-ID: On Sun, Oct 5, 2014 at 7:24 AM, Doug Lea
wrote: > > On 10/03/2014 08:20 PM, Hans Boehm wrote: >> >> Let me try restating the proposed finalization rules and moving the annotation >> from a field to the containing class. As far as I can tell, the annotation >> we've been discussing really only impacts the treatment of the containing class, >> so that seems to be a more logical place for it. > > > Thanks. Seeing this fleshed out leads me again to prefer a simpler > (for us) option: Defining reachabilityFence() and introducing but not > requiring support for your annotation @ReachabilitySensitive (modulo > names for these). Backing up to explain why... > > Finalization reveals a mismatch between JVM-level lifetimes and > source-code-level block scopes. Most programmers implicity expect that > reachability continues to the end of enclosing block. But the only > Java syntactic constructs guaranteed to preserve this entail locking. > Probably the best default advice is to always use synchronized > blocks/methods (or other j.u.c locks in try-finally constructions) > when accessing finalizable resources (as well as in the finalize > methods themselves). But when people can't or don't want to use > locking (not even the hacky and possibly slow but effective trailing > "synchronized(x){}") they should be able to use try {...} finally > {reachabilityFence(x);} (which acts as an RCU-ish read-lock with > respect to GC). Or, in some cases (e.g., ThreadPoolExecutor), do > nothing, because nothing bad can happen anyway. Note that the locking that's naturally required in finalizers protects the underlying resource pool to which the resources being cleaned up will be returned. I don't know of many cases in which that naturally suffices to handle the premature finalization issues. The locking we're talking about is almost always just there to prevent premature finalization. I'm not convinced that the version of ThreadPoolExecutor.java I found is officially correct as written, though I can believe that it doesn't fail in practice. Since it doesn't lock the ThreadPoolExecutor itself, and instead uses a mainLock field, it seems to me that the semantics allows a ThreadPoolExecutor to be shut down by the finalizer while e.g. an execute() call is in progress but the call hasn't done anything yet except cache the fields of the ThreadPoolExecutor object, so that it doesn't need the object itself anymore. I really do think that nearly all non-debug uses of finalizers are affected. > > Automated placement of any of these forms of lifetime control must be > done at source level, because scope information is not guaranteed to > be preserved in bytecode. (Although live-range debugging information > in class files might suffice in many cases.) Different languages > running on JVMs might have different scoping constructs and rules. To > nail them down, languages would need to add C++-destructor-like rules > as Hans sketched out. But even if they do, in Java and probably all > JVM-hosted languages, a front-end compiler's ability to automate > placement of reachability fences is limited by static type > information. For example, a reference of nominal type Object might be > a FileHandle, and even a call to an Object method like hashCode() > might require reachabililty protection. Insisting on the elimination > of all possible lifetime mismatches requires compilers to always > insert reachability fences unless provably not necessary, either > because the object is known to be of a type without a finalizer, or > one of the above manual techniques already occurs in the source code. > Even though it is rarely necessary to insert reachability fences, most > proofs require analyses that front-end compilers do not perform. I think you're actually making things look a bit worse than they are. (Which is nontrivial in this area!) If an object p has a field f that's cleaned up by a finalizer, then any function that cares about premature finalization must at some point have a reference to p with static type S (e.g. FileHandle) that includes the field f. Otherwise it couldn't access f, and wouldn't care if it were cleaned up. If it accesses f via a call to another method m2, then m2 must have the reference to p with the right static type. Depending on how we deal with expression temporaries, this argument may or may not be 100% solid, but I think it covers all common use cases. I do think that looking at static types can buy as something here. The problem is that just looking at the presence of a finalize() method doesn't suffice; with Java's variety of finalization-like mechanisms, we need an annotation. This is very similar to proposed solution 2 in http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2261.html . > > So, guaranteeing lack of scope-lifetime surprise doesn't look like a > promising option. Instead we can require something like Hans sketched > out that is good but imperfect, or fall back to introducing annotation > @ReachabilitySensitive (implicitly applied to classes with non-default > finalize()), but not requiring any compile-time or run-time > properties. And then encouraging tool/IDE developers to support it to > help programmers avoid bugs. These might include points-to analyses > to minimize impact, warnings about upcasts from > @ReachabilitySensitive, suggested alternatives to using finalize(), > and so on. If people using finalization came to rely on such tools, > I'd expect the tools would become better at this than we could ever > mandate as part of language/VM spec. A down side of not requiring it in the language is that the code produced by the tools would look rather ugly. For example, the Android Biginteger.multiply() method current looks unsurprisingly like public BigInteger multiply(BigInteger value) { return new BigInteger(BigInt.product(getBigInt(), value.getBigInt())); } I think it becomes (using "reachabilityFence" as the name, although Ihttp:// www.tutorialspoint.com/java/util/ personally don't like it): public BigInteger multiply(BigInteger value) { try { BigInteger result = new BigInteger(BigInt.product(getBigInt(), value.getBigInt())); finally { reachabilityFence(this); reachabilityFence(value); } return result; } and similarly for many of the other functions in the file. And I'm not sure this is actually a complete answer. Do we allow executions in which the result is finalized before the product() call completes, if the result isn't used? I thought we didn't, but I don't see the words to that effect. Do I also need a reachabilityFence(result)? > > As always, I realize that finding a middle ground between deprecating > and "fixing" finalize() can be a tough sell to both sides. Other > ideas welcome. Deprecating it seems like a non-starter to me. I'm OK with deprecating finalize(), but that only makes this problem worse. And I haven't heard arguments for deprecating java.lang.ref, which would really make things easier for us (though probably harder for users). Hans > > -Doug > >> >> 1. A class is reachability-sensitive if it has a non-default finalizer or is >> suitably annotated (e.g. because its instances are cleaned up by a finalizer >> guardian or through a reference queue). >> >> 2. A reference variable is reachability-sensitive if its static type is a >> reachability-sensitive class (Q1: or array of such?). >> >> 3. The end of the scope of a reachability-sensitive variable synchronizes with >> the invocation of the finalize() method on the object to which it last >> referred. For this purpose, the "this" reference is treated as an implicit >> parameter to member functions. (Q2: The treatment of expression temporary >> reachability-sensitive references is unclear. Do we treat them as though they >> had a scope that lasts through the end of the full expression, as for C++ >> destructors?) >> >> I think this is implementable at modest performance cost, though non-trivial >> compiler engineering cost. To enforce (3) the compiler mist either treat the >> end of such a scope as a release operation (though without the actual fence) or >> refrain from moving operations across the next GC safe-point. The GC should >> then guarantee sufficient synchronization. Hard real-time GCs may have other >> issues, but I would be surprised if this became expensive to enforce. >> >> We don't enforce a corresponding property for references whose static type is >> not reachability-sensitive while their dynamic type is. I think that's >> generally OK, since the fields being cleaned up by a finalizer can't be accessed >> in such a context without entering another one in which the static >> reachability-sensitive type is visible. There's usually a similar argument for >> indirect references to reachability-sensitive objects. >> >> It seems to me that this would implicitly make most code that either naively >> used finalizers (instead of finalizer guardians or java.lang.ref) or correctly >> annotated finalizable classes correct. >> >> Q3: Where does this leave the current conditions in >> http://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.6.2 ? Can >> we just drop it? >> >> Hans From pbenedict at apache.org Thu Oct 9 15:02:44 2014 From: pbenedict at apache.org (Paul Benedict) Date: Thu, 9 Oct 2014 10:02:44 -0500 Subject: [jmm-dev] Non-core-model issues status In-Reply-To: References: <54032B87.4040703@cs.oswego.edu> <540AF866.1000709@cs.oswego.edu> <540EE3CF.5000008@cs.oswego.edu> <543154BB.2050207@cs.oswego.edu> Message-ID: I think the annotation belongs on a method and it forces the JVM (or compiler) to do the reachability fence boilerplate code automatically -- or whatever strategy becomes agreed upon. I don't think it's a "good" solution to throw the weight of the responsibility to the developer to write more boilerplate code. Cheers, Paul On Tue, Oct 7, 2014 at 5:23 PM, Hans Boehm wrote: > On Sun, Oct 5, 2014 at 7:24 AM, Doug Lea
wrote: > > > > On 10/03/2014 08:20 PM, Hans Boehm wrote: > >> > >> Let me try restating the proposed finalization rules and moving the > annotation > >> from a field to the containing class. As far as I can tell, the > annotation > >> we've been discussing really only impacts the treatment of the > containing class, > >> so that seems to be a more logical place for it. > > > > > > Thanks. Seeing this fleshed out leads me again to prefer a simpler > > (for us) option: Defining reachabilityFence() and introducing but not > > requiring support for your annotation @ReachabilitySensitive (modulo > > names for these). Backing up to explain why... > > > > Finalization reveals a mismatch between JVM-level lifetimes and > > source-code-level block scopes. Most programmers implicity expect that > > reachability continues to the end of enclosing block. But the only > > Java syntactic constructs guaranteed to preserve this entail locking. > > Probably the best default advice is to always use synchronized > > blocks/methods (or other j.u.c locks in try-finally constructions) > > when accessing finalizable resources (as well as in the finalize > > methods themselves). But when people can't or don't want to use > > locking (not even the hacky and possibly slow but effective trailing > > "synchronized(x){}") they should be able to use try {...} finally > > {reachabilityFence(x);} (which acts as an RCU-ish read-lock with > > respect to GC). Or, in some cases (e.g., ThreadPoolExecutor), do > > nothing, because nothing bad can happen anyway. > Note that the locking that's naturally required in finalizers protects the > underlying resource pool to which the resources being cleaned up will be > returned. I don't know of many cases in which that naturally suffices to > handle the premature finalization issues. The locking we're talking about > is almost always just there to prevent premature finalization. > > I'm not convinced that the version of ThreadPoolExecutor.java I found is > officially correct as written, though I can believe that it doesn't fail in > practice. Since it doesn't lock the ThreadPoolExecutor itself, and instead > uses a mainLock field, it seems to me that the semantics allows a > ThreadPoolExecutor to be shut down by the finalizer while e.g. an execute() > call is in progress but the call hasn't done anything yet except cache the > fields of the ThreadPoolExecutor object, so that it doesn't need the object > itself anymore. I really do think that nearly all non-debug uses of > finalizers are affected. > > > > > Automated placement of any of these forms of lifetime control must be > > done at source level, because scope information is not guaranteed to > > be preserved in bytecode. (Although live-range debugging information > > in class files might suffice in many cases.) Different languages > > running on JVMs might have different scoping constructs and rules. To > > nail them down, languages would need to add C++-destructor-like rules > > as Hans sketched out. But even if they do, in Java and probably all > > JVM-hosted languages, a front-end compiler's ability to automate > > placement of reachability fences is limited by static type > > information. For example, a reference of nominal type Object might be > > a FileHandle, and even a call to an Object method like hashCode() > > might require reachabililty protection. Insisting on the elimination > > of all possible lifetime mismatches requires compilers to always > > insert reachability fences unless provably not necessary, either > > because the object is known to be of a type without a finalizer, or > > one of the above manual techniques already occurs in the source code. > > Even though it is rarely necessary to insert reachability fences, most > > proofs require analyses that front-end compilers do not perform. > > I think you're actually making things look a bit worse than they are. > (Which is nontrivial in this area!) If an object p has a field f that's > cleaned up by a finalizer, then any function that cares about premature > finalization must at some point have a reference to p with static type S > (e.g. FileHandle) that includes the field f. Otherwise it couldn't access > f, and wouldn't care if it were cleaned up. If it accesses f via a call to > another method m2, then m2 must have the reference to p with the right > static type. Depending on how we deal with expression temporaries, this > argument may or may not be 100% solid, but I think it covers all common use > cases. I do think that looking at static types can buy as something here. > The problem is that just looking at the presence of a finalize() method > doesn't suffice; with Java's variety of finalization-like mechanisms, we > need an annotation. > > This is very similar to proposed solution 2 in > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2261.html . > > > > > So, guaranteeing lack of scope-lifetime surprise doesn't look like a > > promising option. Instead we can require something like Hans sketched > > out that is good but imperfect, or fall back to introducing annotation > > @ReachabilitySensitive (implicitly applied to classes with non-default > > finalize()), but not requiring any compile-time or run-time > > properties. And then encouraging tool/IDE developers to support it to > > help programmers avoid bugs. These might include points-to analyses > > to minimize impact, warnings about upcasts from > > @ReachabilitySensitive, suggested alternatives to using finalize(), > > and so on. If people using finalization came to rely on such tools, > > I'd expect the tools would become better at this than we could ever > > mandate as part of language/VM spec. > > A down side of not requiring it in the language is that the code produced > by the tools would look rather ugly. For example, the Android > Biginteger.multiply() method current looks unsurprisingly like > > public BigInteger multiply(BigInteger value) { > return new BigInteger(BigInt.product(getBigInt(), > value.getBigInt())); > } > > I think it becomes (using "reachabilityFence" as the name, although > Ihttp:// > www.tutorialspoint.com/java/util/ personally don't like it): > > public BigInteger multiply(BigInteger value) { > try { > BigInteger result = new BigInteger(BigInt.product(getBigInt(), > value.getBigInt())); > finally { > reachabilityFence(this); > reachabilityFence(value); > } > return result; > } > > and similarly for many of the other functions in the file. > > And I'm not sure this is actually a complete answer. Do we allow > executions in which the result is finalized before the product() call > completes, if the result isn't used? I thought we didn't, but I don't see > the words to that effect. Do I also need a reachabilityFence(result)? > > > > > As always, I realize that finding a middle ground between deprecating > > and "fixing" finalize() can be a tough sell to both sides. Other > > ideas welcome. > > Deprecating it seems like a non-starter to me. I'm OK with deprecating > finalize(), but that only makes this problem worse. And I haven't heard > arguments for deprecating java.lang.ref, which would really make things > easier for us (though probably harder for users). > > Hans > > > > > -Doug > > > >> > >> 1. A class is reachability-sensitive if it has a non-default finalizer > or is > >> suitably annotated (e.g. because its instances are cleaned up by a > finalizer > >> guardian or through a reference queue). > >> > >> 2. A reference variable is reachability-sensitive if its static type is > a > >> reachability-sensitive class (Q1: or array of such?). > >> > >> 3. The end of the scope of a reachability-sensitive variable > synchronizes with > >> the invocation of the finalize() method on the object to which it last > >> referred. For this purpose, the "this" reference is treated as an > implicit > >> parameter to member functions. (Q2: The treatment of expression > temporary > >> reachability-sensitive references is unclear. Do we treat them as > though they > >> had a scope that lasts through the end of the full expression, as for > C++ > >> destructors?) > >> > >> I think this is implementable at modest performance cost, though > non-trivial > >> compiler engineering cost. To enforce (3) the compiler mist either > treat the > >> end of such a scope as a release operation (though without the actual > fence) or > >> refrain from moving operations across the next GC safe-point. The GC > should > >> then guarantee sufficient synchronization. Hard real-time GCs may have > other > >> issues, but I would be surprised if this became expensive to enforce. > >> > >> We don't enforce a corresponding property for references whose static > type is > >> not reachability-sensitive while their dynamic type is. I think that's > >> generally OK, since the fields being cleaned up by a finalizer can't be > accessed > >> in such a context without entering another one in which the static > >> reachability-sensitive type is visible. There's usually a similar > argument for > >> indirect references to reachability-sensitive objects. > >> > >> It seems to me that this would implicitly make most code that either > naively > >> used finalizers (instead of finalizer guardians or java.lang.ref) or > correctly > >> annotated finalizable classes correct. > >> > >> Q3: Where does this leave the current conditions in > >> http://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.6.2 > ? Can > >> we just drop it? > >> > >> Hans > From boehm at acm.org Mon Oct 20 21:01:54 2014 From: boehm at acm.org (Hans Boehm) Date: Mon, 20 Oct 2014 14:01:54 -0700 Subject: [jmm-dev] Non-core-model issues status In-Reply-To: References: <54032B87.4040703@cs.oswego.edu> <540AF866.1000709@cs.oswego.edu> <540EE3CF.5000008@cs.oswego.edu> <543154BB.2050207@cs.oswego.edu> Message-ID: I can see arguments for putting the annotation on 1) A field that is logically invalidated by finalization, implying that reachability of the enclosing object needs to be preserved as long as it is logically reachable. 2) The class that contains such a field. I think (1) has the advantage that we can restrict the more careful treatment to methods accessing that field rather than all methods. (2) may be slightly simpler to use. As Paul suggests, we could also (3) annotate the methods accessing such a field. That seems less convenient and more error-prone to me. In particular, for something like Android BigInteger, we'd end up annotating most of the methods, rather than either a single field or a single class. It does seem better to me than explicit reachabilityFence(), which would require dozens of much more subtle (and largely untestable) annotations. Hans On Thu, Oct 9, 2014 at 8:02 AM, Paul Benedict wrote: > I think the annotation belongs on a method and it forces the JVM (or > compiler) to do the reachability fence boilerplate code automatically -- or > whatever strategy becomes agreed upon. I don't think it's a "good" solution > to throw the weight of the responsibility to the developer to write more > boilerplate code. > > > Cheers, > Paul > > On Tue, Oct 7, 2014 at 5:23 PM, Hans Boehm wrote: > >> On Sun, Oct 5, 2014 at 7:24 AM, Doug Lea
wrote: >> > >> > On 10/03/2014 08:20 PM, Hans Boehm wrote: >> >> >> >> Let me try restating the proposed finalization rules and moving the >> annotation >> >> from a field to the containing class. As far as I can tell, the >> annotation >> >> we've been discussing really only impacts the treatment of the >> containing class, >> >> so that seems to be a more logical place for it. >> > >> > >> > Thanks. Seeing this fleshed out leads me again to prefer a simpler >> > (for us) option: Defining reachabilityFence() and introducing but not >> > requiring support for your annotation @ReachabilitySensitive (modulo >> > names for these). Backing up to explain why... >> > >> > Finalization reveals a mismatch between JVM-level lifetimes and >> > source-code-level block scopes. Most programmers implicity expect that >> > reachability continues to the end of enclosing block. But the only >> > Java syntactic constructs guaranteed to preserve this entail locking. >> > Probably the best default advice is to always use synchronized >> > blocks/methods (or other j.u.c locks in try-finally constructions) >> > when accessing finalizable resources (as well as in the finalize >> > methods themselves). But when people can't or don't want to use >> > locking (not even the hacky and possibly slow but effective trailing >> > "synchronized(x){}") they should be able to use try {...} finally >> > {reachabilityFence(x);} (which acts as an RCU-ish read-lock with >> > respect to GC). Or, in some cases (e.g., ThreadPoolExecutor), do >> > nothing, because nothing bad can happen anyway. >> Note that the locking that's naturally required in finalizers protects the >> underlying resource pool to which the resources being cleaned up will be >> returned. I don't know of many cases in which that naturally suffices to >> handle the premature finalization issues. The locking we're talking about >> is almost always just there to prevent premature finalization. >> >> I'm not convinced that the version of ThreadPoolExecutor.java I found is >> officially correct as written, though I can believe that it doesn't fail >> in >> practice. Since it doesn't lock the ThreadPoolExecutor itself, and >> instead >> uses a mainLock field, it seems to me that the semantics allows a >> ThreadPoolExecutor to be shut down by the finalizer while e.g. an >> execute() >> call is in progress but the call hasn't done anything yet except cache the >> fields of the ThreadPoolExecutor object, so that it doesn't need the >> object >> itself anymore. I really do think that nearly all non-debug uses of >> finalizers are affected. >> >> > >> > Automated placement of any of these forms of lifetime control must be >> > done at source level, because scope information is not guaranteed to >> > be preserved in bytecode. (Although live-range debugging information >> > in class files might suffice in many cases.) Different languages >> > running on JVMs might have different scoping constructs and rules. To >> > nail them down, languages would need to add C++-destructor-like rules >> > as Hans sketched out. But even if they do, in Java and probably all >> > JVM-hosted languages, a front-end compiler's ability to automate >> > placement of reachability fences is limited by static type >> > information. For example, a reference of nominal type Object might be >> > a FileHandle, and even a call to an Object method like hashCode() >> > might require reachabililty protection. Insisting on the elimination >> > of all possible lifetime mismatches requires compilers to always >> > insert reachability fences unless provably not necessary, either >> > because the object is known to be of a type without a finalizer, or >> > one of the above manual techniques already occurs in the source code. >> > Even though it is rarely necessary to insert reachability fences, most >> > proofs require analyses that front-end compilers do not perform. >> >> I think you're actually making things look a bit worse than they are. >> (Which is nontrivial in this area!) If an object p has a field f that's >> cleaned up by a finalizer, then any function that cares about premature >> finalization must at some point have a reference to p with static type S >> (e.g. FileHandle) that includes the field f. Otherwise it couldn't access >> f, and wouldn't care if it were cleaned up. If it accesses f via a call >> to >> another method m2, then m2 must have the reference to p with the right >> static type. Depending on how we deal with expression temporaries, this >> argument may or may not be 100% solid, but I think it covers all common >> use >> cases. I do think that looking at static types can buy as something here. >> The problem is that just looking at the presence of a finalize() method >> doesn't suffice; with Java's variety of finalization-like mechanisms, we >> need an annotation. >> >> This is very similar to proposed solution 2 in >> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2261.html . >> >> > >> > So, guaranteeing lack of scope-lifetime surprise doesn't look like a >> > promising option. Instead we can require something like Hans sketched >> > out that is good but imperfect, or fall back to introducing annotation >> > @ReachabilitySensitive (implicitly applied to classes with non-default >> > finalize()), but not requiring any compile-time or run-time >> > properties. And then encouraging tool/IDE developers to support it to >> > help programmers avoid bugs. These might include points-to analyses >> > to minimize impact, warnings about upcasts from >> > @ReachabilitySensitive, suggested alternatives to using finalize(), >> > and so on. If people using finalization came to rely on such tools, >> > I'd expect the tools would become better at this than we could ever >> > mandate as part of language/VM spec. >> >> A down side of not requiring it in the language is that the code produced >> by the tools would look rather ugly. For example, the Android >> Biginteger.multiply() method current looks unsurprisingly like >> >> public BigInteger multiply(BigInteger value) { >> return new BigInteger(BigInt.product(getBigInt(), >> value.getBigInt())); >> } >> >> I think it becomes (using "reachabilityFence" as the name, although >> Ihttp:// >> www.tutorialspoint.com/java/util/ personally don't like it): >> >> public BigInteger multiply(BigInteger value) { >> try { >> BigInteger result = new BigInteger(BigInt.product(getBigInt(), >> value.getBigInt())); >> finally { >> reachabilityFence(this); >> reachabilityFence(value); >> } >> return result; >> } >> >> and similarly for many of the other functions in the file. >> >> And I'm not sure this is actually a complete answer. Do we allow >> executions in which the result is finalized before the product() call >> completes, if the result isn't used? I thought we didn't, but I don't see >> the words to that effect. Do I also need a reachabilityFence(result)? >> >> > >> > As always, I realize that finding a middle ground between deprecating >> > and "fixing" finalize() can be a tough sell to both sides. Other >> > ideas welcome. >> >> Deprecating it seems like a non-starter to me. I'm OK with deprecating >> finalize(), but that only makes this problem worse. And I haven't heard >> arguments for deprecating java.lang.ref, which would really make things >> easier for us (though probably harder for users). >> >> Hans >> >> > >> > -Doug >> > >> >> >> >> 1. A class is reachability-sensitive if it has a non-default finalizer >> or is >> >> suitably annotated (e.g. because its instances are cleaned up by a >> finalizer >> >> guardian or through a reference queue). >> >> >> >> 2. A reference variable is reachability-sensitive if its static type >> is a >> >> reachability-sensitive class (Q1: or array of such?). >> >> >> >> 3. The end of the scope of a reachability-sensitive variable >> synchronizes with >> >> the invocation of the finalize() method on the object to which it last >> >> referred. For this purpose, the "this" reference is treated as an >> implicit >> >> parameter to member functions. (Q2: The treatment of expression >> temporary >> >> reachability-sensitive references is unclear. Do we treat them as >> though they >> >> had a scope that lasts through the end of the full expression, as for >> C++ >> >> destructors?) >> >> >> >> I think this is implementable at modest performance cost, though >> non-trivial >> >> compiler engineering cost. To enforce (3) the compiler mist either >> treat the >> >> end of such a scope as a release operation (though without the actual >> fence) or >> >> refrain from moving operations across the next GC safe-point. The GC >> should >> >> then guarantee sufficient synchronization. Hard real-time GCs may have >> other >> >> issues, but I would be surprised if this became expensive to enforce. >> >> >> >> We don't enforce a corresponding property for references whose static >> type is >> >> not reachability-sensitive while their dynamic type is. I think that's >> >> generally OK, since the fields being cleaned up by a finalizer can't be >> accessed >> >> in such a context without entering another one in which the static >> >> reachability-sensitive type is visible. There's usually a similar >> argument for >> >> indirect references to reachability-sensitive objects. >> >> >> >> It seems to me that this would implicitly make most code that either >> naively >> >> used finalizers (instead of finalizer guardians or java.lang.ref) or >> correctly >> >> annotated finalizable classes correct. >> >> >> >> Q3: Where does this leave the current conditions in >> >> >> http://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.6.2 >> ? Can >> >> we just drop it? >> >> >> >> Hans >> > > From aph at redhat.com Wed Oct 22 20:42:52 2014 From: aph at redhat.com (Andrew Haley) Date: Wed, 22 Oct 2014 21:42:52 +0100 Subject: [jmm-dev] Non-core-model issues status In-Reply-To: References: <54032B87.4040703@cs.oswego.edu> <540AF866.1000709@cs.oswego.edu> <540EE3CF.5000008@cs.oswego.edu> <543154BB.2050207@cs.oswego.edu> Message-ID: <544816CC.3060207@redhat.com> On 20/10/14 22:01, Hans Boehm wrote: > I can see arguments for putting the annotation on > > 1) A field that is logically invalidated by finalization, implying that > reachability of the enclosing object needs to be preserved as long as it is > logically reachable. > > 2) The class that contains such a field. > > I think (1) has the advantage that we can restrict the more careful > treatment to methods accessing that field rather than all methods. (2) may > be slightly simpler to use. > > As Paul suggests, we could also (3) annotate the methods accessing such a > field. That seems less convenient and more error-prone to me. In > particular, for something like Android BigInteger, we'd end up annotating > most of the methods, rather than either a single field or a single class. > It does seem better to me than explicit reachabilityFence(), which would > require dozens of much more subtle (and largely untestable) annotations. It seems better to me too, but as I understand it any annotation would be expanded by javac to a try { ... } finally { reachabilityFence(); } or something similar. In that case it makes sense to make reachabilityFence() part of a public API, even if only for the non- Java languages running on the JVM who are equally plagued by early finalization. Andrew. From boehm at acm.org Thu Oct 23 05:58:28 2014 From: boehm at acm.org (Hans Boehm) Date: Wed, 22 Oct 2014 22:58:28 -0700 Subject: [jmm-dev] Non-core-model issues status In-Reply-To: <544816CC.3060207@redhat.com> References: <54032B87.4040703@cs.oswego.edu> <540AF866.1000709@cs.oswego.edu> <540EE3CF.5000008@cs.oswego.edu> <543154BB.2050207@cs.oswego.edu> <544816CC.3060207@redhat.com> Message-ID: Sounds reasonable to me. So long as there is a reasonably clean and straightforward way to write the Java source code in 99% of use cases, I'm happy. I think reachabilityFence() by itself, without the annotation, doesn't get us far enough. On Wed, Oct 22, 2014 at 1:42 PM, Andrew Haley wrote: > On 20/10/14 22:01, Hans Boehm wrote: > > I can see arguments for putting the annotation on > > > > 1) A field that is logically invalidated by finalization, implying that > > reachability of the enclosing object needs to be preserved as long as it > is > > logically reachable. > > > > 2) The class that contains such a field. > > > > I think (1) has the advantage that we can restrict the more careful > > treatment to methods accessing that field rather than all methods. (2) > may > > be slightly simpler to use. > > > > As Paul suggests, we could also (3) annotate the methods accessing such a > > field. That seems less convenient and more error-prone to me. In > > particular, for something like Android BigInteger, we'd end up annotating > > most of the methods, rather than either a single field or a single class. > > It does seem better to me than explicit reachabilityFence(), which would > > require dozens of much more subtle (and largely untestable) annotations. > > It seems better to me too, but as I understand it any annotation would > be expanded by javac to a try { ... } finally { reachabilityFence(); } > or something similar. In that case it makes sense to make > reachabilityFence() part of a public API, even if only for the non- > Java languages running on the JVM who are equally plagued by early > finalization. > > Andrew. > From boehm at acm.org Wed Oct 29 01:39:44 2014 From: boehm at acm.org (Hans Boehm) Date: Tue, 28 Oct 2014 18:39:44 -0700 Subject: [jmm-dev] Another way to punt OOTA Message-ID: Here's another conceivable approach. This sounds somewhat crazy based on our prior assumptions, but it may only be mildly crazy, so here goes. (I ran this past Jeremy who thought it was at least mildly crazy.) Assumptions/observations: - Very few people actually care about Java security as originally conceived. We usually either don't allow untrusted Java code into our process, or we sandbox the resulting process. (Android does the latter.) - The argument for providing well-defined behavior for data races in Java was based either on the original model of Java, or on the desire to unconditionally maintain secondary properties, like memory safety, even in the presence of data races. - [Dubious, but plausible assumption] We should be able to explicitly require those secondary properties, even if we allow otherwise allow less than well-defined behavior for data races. - We're essentially already making the preceding dubious assumption. We have all sorts of library APIs that don't specify how they behave in the presence of races, but only say that you shouldn't do that. We're somehow supposed to conclude that the heap can't be corrupted even in the presence of racy library calls, because of the (unstated?) assumption that libraries should behave as though they were implemented in Java, and Java programs preserve e.g. memory safety. The only place we actually claim (incorrectly as we now know) to have well-defined semantics for data races is at the basic type and reference level, which is arguably not even the most interesting place in a large code base. - Most of us don't care that much about slowing down potentially racing accesses a bit. The reason the load->store ordering solution seems so dubious for Java is that the compiler doesn't know which accesses might race, and thus we need to treat many accesses conservatively. ARM is much more concerned about Java than C++ memory_order_relaxed. Possible long-term approach: - Switch to a much more C++-like (or Java library-like) model in which data races have something like "undefined behavior". Exactly how to model that is an open question. Ordinary loads can only see stores that happen-before them, but racing loads trigger "undefined behavior". "Undefined behavior" should be defined to allow reporting an error and produce any type correct answer for the racing load. Unlike C++, we probably want to be explicit that it disallows a VM crash - [Probably challenging, others understand the Java constraints better than I] Introduce a mechanism for (nearly) unordered memory-order-relaxed like racing loads. Require current racing accesses to use that mechanism instead. (Open question: coherence) - Strengthen this memory_order_relaxed analog to guarantee load->store ordering. - Implementations may specify that they treat all ordinary accesses as these "memory_order_relaxed" accesses. Browser-based implementations, or others that require the current security model, would do so. Whether and how to specify this is open.. Transition strategy: - Implementations are not required to break existing code in any way, though the spec would allow them to. In the near term, we would expect implementations to continue to support (possibly with a suitable flag) the current ill-defined model, along with the new model. (Which should be easy; the only really new support id for memory_order_relaxed and load->store ordering.) - The fact that data race detection is much easier in the new model may help to inspire people to move to it. Long term potential advantages: - No OOTA issues! - Easier race detection. A standard conforming JVM should be able to throw a data race exception if it finds one. - Uniform model for basic types and libraries. - We can delete the special cases for tearing longs and doubles without unacceptably slowing down some implementations. Long term disadvantages: - As for C++, we promise less about behavior of buggy programs. AFAICT, much has been written about this, but it isn't a major practical issue along the lines of memory safety. And again, we already have that problem for library clients. - Security sensitive code will run slower and need a separate JVM flag. Again, my impression is there is little of it, so this isn't a big deal. (There are probably some mild security advantages in exchange; untrusted racy code can induce slightly fewer perverse behaviors.) Short term issues: - This would declare significant amounts of currently correct code to be deprecated and in the future incorrect. But if we can figure out how to cleanly introduce something like memory_order_relaxed, I think the required changes would clearly also improve readability. From boehm at acm.org Wed Oct 29 19:54:59 2014 From: boehm at acm.org (Hans Boehm) Date: Wed, 29 Oct 2014 12:54:59 -0700 Subject: [jmm-dev] Another way to punt OOTA In-Reply-To: <20141029182338.GB5718@linux.vnet.ibm.com> References: <20141029182338.GB5718@linux.vnet.ibm.com> Message-ID: On Wed, Oct 29, 2014 at 11:23 AM, Paul E. McKenney < paulmck at linux.vnet.ibm.com> wrote: > ... > > - Most of us don't care that much about slowing down potentially racing > > accesses a bit. The reason the load->store ordering solution seems so > > dubious for Java is that the compiler doesn't know which accesses might > > race, and thus we need to treat many accesses conservatively. ARM is much > > more concerned about Java than C++ memory_order_relaxed. > > Speaking as one of the people who is most definitely not in the "most > of us" set... ;-) > > Yes, if you are taking a cache miss on each access, you won't notice a > compare and conditional branch. But an important subset of well-tuned > parallel software takes care to promote cache locality, which means > that you -won't- see very many cache misses. The extra unnecessary > conditional branches can place pressure on branch-prediction resources, > which can result in noticeable performance degradation. > > Degrading memory_order_relaxed in this manner will push people back to > the old workarounds involving volatile and inline assembler, which > seems quite counterproductive. Probably less of an issue in Java. But I agree that if we can find an acceptable solution that doesn't require this, we should go with it. I'm not suggesting we stop work on that. > > > Possible long-term approach: > > > > - Switch to a much more C++-like (or Java library-like) model in which data > > races have something like "undefined behavior". Exactly how to model that > > is an open question. Ordinary loads can only see stores that happen-before > > them, but racing loads trigger "undefined behavior". "Undefined behavior" > > should be defined to allow reporting an error and produce any type correct > > answer for the racing load. Unlike C++, we probably want to be explicit > > that it disallows a VM crash > > > > - [Probably challenging, others understand the Java constraints better than > > I] Introduce a mechanism for (nearly) unordered memory-order-relaxed like > > racing loads. Require current racing accesses to use that mechanism > > instead. (Open question: coherence) > > > > - Strengthen this memory_order_relaxed analog to guarantee load->store > > ordering. > > Again, I am not a Java expert. But demanding the unneeded load-to-store > ordering while dispensing with coherence seems completely backwards. Agreed. But that seemed like a somewhat separable issue, so I left it as an open question. I think we should add coherence. That means > > > - Implementations may specify that they treat all ordinary accesses as > > these "memory_order_relaxed" accesses. Browser-based implementations, or > > others that require the current security model, would do so. Whether and > > how to specify this is open.. > > > > > > Transition strategy: > > > > - Implementations are not required to break existing code in any way, > > though the spec would allow them to. In the near term, we would expect > > implementations to continue to support (possibly with a suitable flag) the > > current ill-defined model, along with the new model. (Which should be > > easy; the only really new support id for memory_order_relaxed and > > load->store ordering.) > > > > - The fact that data race detection is much easier in the new model may > > help to inspire people to move to it. > > > > > > Long term potential advantages: > > > > - No OOTA issues! > > I still believe that we can avoid OOTA without requiring implementations > to emit unnecessary instructions. I'm all in favor, so long as the solution doesn't amount to introducing an even more complicated model that we understand even less well, thus effectively just kicking the can down the road. View this as a fallback. > > > - Easier race detection. A standard conforming JVM should be able to throw > > a data race exception if it finds one. > > You lost me here -- how do needless branches and foregone coherence help > in detecting data races? The problem is that Java, unlike C/C++, currently allows unannotated data races. Thus detected races are not necessarily bugs, meaning that data race detectors will unavoidably generate false positives. This benefit essentially just derives from introducing a standard way to identify intentional races that should not be reported. > > > - Uniform model for basic types and libraries. > > Uniform in what way? Data races are errors in both cases. Currently Java has (supposedly) defined semantics for racing accesses to base types like int, and there are semi-common idioms that rely on those data races. In contrast we effectively treat racing accessed to ArrayList as errors, with no restriction on their behavior. I don't think we ever believed this made much sense. I think the original intention, at least in the back of my mind, was that we would eventually fix the ArrayList etc. specifications. It hasn't happened, and it probably isn't realistically possible. I'm proposing that we bite the bullet and say both are errors. > > > - We can delete the special cases for tearing longs and doubles without > > unacceptably slowing down some implementations. > > The idea here is that tearing becomes legal, correct? If so, I guess > I can agree with one out of four! ;-) Right. Since the issue is only raised by erroneous programs. Hans From aph at redhat.com Thu Oct 30 07:55:57 2014 From: aph at redhat.com (Andrew Haley) Date: Thu, 30 Oct 2014 07:55:57 +0000 Subject: [jmm-dev] Another way to punt OOTA In-Reply-To: References: Message-ID: <5451EF0D.6060105@redhat.com> On 29/10/14 01:39, Hans Boehm wrote: > Here's another conceivable approach. This sounds somewhat crazy based on > our prior assumptions, but it may only be mildly crazy, so here goes. (I > ran this past Jeremy who thought it was at least mildly crazy.) I think it's mildly crazy. As discussed, real hardware doesn't manifest true OOTA values: the OOTA problem is a problem with our models, not with our systems. Changing (and slowing down) our systems in order to accommodate the inadequacies of our models is rather to put the cart before the horse, is it not? Andrew. From paul.sandoz at oracle.com Thu Oct 30 14:02:06 2014 From: paul.sandoz at oracle.com (Paul Sandoz) Date: Thu, 30 Oct 2014 15:02:06 +0100 Subject: [jmm-dev] Update to description of JEP 193: Enhanced Volatiles Message-ID: <8DE0C1E6-6B6A-4C0F-8C42-A37947B44AF6@oracle.com> Hi, I have, with the help of Brian, Doug and John, updated the description of JEP 193: Enhanced Volatiles to reflect our current thinking based on: - the prototype implementation in valhalla; - performance measurements of that implementation; and - investigations related to signature polymorphic methods and invokedynamic. Thanks, Paul. From ajeffrey at bell-labs.com Thu Oct 30 14:35:03 2014 From: ajeffrey at bell-labs.com (Alan Jeffrey) Date: Thu, 30 Oct 2014 09:35:03 -0500 Subject: [jmm-dev] Another way to punt OOTA In-Reply-To: References: Message-ID: <54524C97.6070708@bell-labs.com> If racing access has undefined semantics, are we not going to have the same problems in Java as in C/C++11, where undefined behavior generates the write that justifies the read that causes the undefined behavior? For example (initially x and y are different objects, both with field a=0): thread 1: if (x.a == 1) { undefined(); } thread 2: y.a = 1; One possible undefined behaviour is y=x, which can then be used to justify the read x.a == 1. Of course, this is an OOTA behavior, but ruling out such OOTA occurrences of undefined seems just as difficult as ruling out OOTA regular behaviours (and possibly harder). A. On 10/28/2014 08:39 PM, Hans Boehm wrote: > Here's another conceivable approach. This sounds somewhat crazy based on > our prior assumptions, but it may only be mildly crazy, so here goes. (I > ran this past Jeremy who thought it was at least mildly crazy.) > > Assumptions/observations: > > - Very few people actually care about Java security as originally > conceived. We usually either don't allow untrusted Java code into our > process, or we sandbox the resulting process. (Android does the latter.) > > - The argument for providing well-defined behavior for data races in Java > was based either on the original model of Java, or on the desire to > unconditionally maintain secondary properties, like memory safety, even in > the presence of data races. > > - [Dubious, but plausible assumption] We should be able to explicitly > require those secondary properties, even if we allow otherwise allow less > than well-defined behavior for data races. > > - We're essentially already making the preceding dubious assumption. We > have all sorts of library APIs that don't specify how they behave in the > presence of races, but only say that you shouldn't do that. We're somehow > supposed to conclude that the heap can't be corrupted even in the presence > of racy library calls, because of the (unstated?) assumption that libraries > should behave as though they were implemented in Java, and Java programs > preserve e.g. memory safety. The only place we actually claim (incorrectly > as we now know) to have well-defined semantics for data races is at the > basic type and reference level, which is arguably not even the most > interesting place in a large code base. > > - Most of us don't care that much about slowing down potentially racing > accesses a bit. The reason the load->store ordering solution seems so > dubious for Java is that the compiler doesn't know which accesses might > race, and thus we need to treat many accesses conservatively. ARM is much > more concerned about Java than C++ memory_order_relaxed. > > > Possible long-term approach: > > - Switch to a much more C++-like (or Java library-like) model in which data > races have something like "undefined behavior". Exactly how to model that > is an open question. Ordinary loads can only see stores that happen-before > them, but racing loads trigger "undefined behavior". "Undefined behavior" > should be defined to allow reporting an error and produce any type correct > answer for the racing load. Unlike C++, we probably want to be explicit > that it disallows a VM crash > > - [Probably challenging, others understand the Java constraints better than > I] Introduce a mechanism for (nearly) unordered memory-order-relaxed like > racing loads. Require current racing accesses to use that mechanism > instead. (Open question: coherence) > > - Strengthen this memory_order_relaxed analog to guarantee load->store > ordering. > > - Implementations may specify that they treat all ordinary accesses as > these "memory_order_relaxed" accesses. Browser-based implementations, or > others that require the current security model, would do so. Whether and > how to specify this is open.. > > > Transition strategy: > > - Implementations are not required to break existing code in any way, > though the spec would allow them to. In the near term, we would expect > implementations to continue to support (possibly with a suitable flag) the > current ill-defined model, along with the new model. (Which should be > easy; the only really new support id for memory_order_relaxed and > load->store ordering.) > > - The fact that data race detection is much easier in the new model may > help to inspire people to move to it. > > > Long term potential advantages: > > - No OOTA issues! > > - Easier race detection. A standard conforming JVM should be able to throw > a data race exception if it finds one. > > - Uniform model for basic types and libraries. > > - We can delete the special cases for tearing longs and doubles without > unacceptably slowing down some implementations. > > > Long term disadvantages: > > - As for C++, we promise less about behavior of buggy programs. AFAICT, > much has been written about this, but it isn't a major practical issue > along the lines of memory safety. And again, we already have that problem > for library clients. > > - Security sensitive code will run slower and need a separate JVM flag. > Again, my impression is there is little of it, so this isn't a big deal. > (There are probably some mild security advantages in exchange; untrusted > racy code can induce slightly fewer perverse behaviors.) > > > Short term issues: > > - This would declare significant amounts of currently correct code to be > deprecated and in the future incorrect. But if we can figure out how to > cleanly introduce something like memory_order_relaxed, I think the required > changes would clearly also improve readability. > From david.lloyd at redhat.com Thu Oct 30 15:17:31 2014 From: david.lloyd at redhat.com (David M. Lloyd) Date: Thu, 30 Oct 2014 10:17:31 -0500 Subject: [jmm-dev] Update to description of JEP 193: Enhanced Volatiles In-Reply-To: <8DE0C1E6-6B6A-4C0F-8C42-A37947B44AF6@oracle.com> References: <8DE0C1E6-6B6A-4C0F-8C42-A37947B44AF6@oracle.com> Message-ID: <5452568B.2020203@redhat.com> On 10/30/2014 09:02 AM, Paul Sandoz wrote: > Hi, > > I have, with the help of Brian, Doug and John, updated the description of JEP 193: Enhanced Volatiles to reflect our current thinking based on: > > - the prototype implementation in valhalla; > - performance measurements of that implementation; and > - investigations related to signature polymorphic methods and invokedynamic. It's awesome to see this move forward. It's too bad that the taboo against adding (two) bytecodes defeated that (much simpler seeming) approach though. -- - DML From paul.sandoz at oracle.com Thu Oct 30 15:53:23 2014 From: paul.sandoz at oracle.com (Paul Sandoz) Date: Thu, 30 Oct 2014 16:53:23 +0100 Subject: [jmm-dev] Update to description of JEP 193: Enhanced Volatiles In-Reply-To: <54525D8D.2080801@univ-mlv.fr> References: <8DE0C1E6-6B6A-4C0F-8C42-A37947B44AF6@oracle.com> <54525D8D.2080801@univ-mlv.fr> Message-ID: On Oct 30, 2014, at 4:47 PM, Remi Forax wrote: > > On 10/30/2014 03:02 PM, Paul Sandoz wrote: >> Hi, >> >> I have, with the help of Brian, Doug and John, updated the description of JEP 193: Enhanced Volatiles to reflect our current thinking based on: >> >> - the prototype implementation in valhalla; >> - performance measurements of that implementation; and >> - investigations related to signature polymorphic methods and invokedynamic. >> >> Thanks, >> Paul. > > I seems that the changes are not propagated to the JEP yet, > but there are available throught the corresponding bug: > https://bugs.openjdk.java.net/browse/JDK-8046183 > Doh! thanks, i forgot to send the link out, Paul, From brian.goetz at oracle.com Thu Oct 30 15:55:20 2014 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 30 Oct 2014 11:55:20 -0400 Subject: [jmm-dev] Another way to punt OOTA In-Reply-To: References: Message-ID: <54525F68.9080109@oracle.com> Yeah, makes me nervous too. I understand Google has made its peace with this security approach, and I don't disagree that it has considerable merit, but I also don't think Oracle is ready to take that plunge yet. So, while I think its good to toss out the crazy ideas because sometimes something really good comes out of that, I'm skeptical that an approach that rests on these assumptions could make it all the way across the finish line. But, while on the topic of security, we do have an interest in strengthening various integrity constraints. Specifically, the non-finality of final fields is a persistent irritant, and we would like to get to an initialization model that meets the extended use cases (e.g., dependency injection, deserialization of objects with final fields) while strengthening the promises of "final means final." (See John Rose's blog entry on larval objects for a hint about the direction we've got in mind.) On 10/28/2014 9:39 PM, Hans Boehm wrote: > Here's another conceivable approach. This sounds somewhat crazy based on > our prior assumptions, but it may only be mildly crazy, so here goes. (I > ran this past Jeremy who thought it was at least mildly crazy.) > > Assumptions/observations: > > - Very few people actually care about Java security as originally > conceived. We usually either don't allow untrusted Java code into our > process, or we sandbox the resulting process. (Android does the latter.) > > - The argument for providing well-defined behavior for data races in Java > was based either on the original model of Java, or on the desire to > unconditionally maintain secondary properties, like memory safety, even in > the presence of data races. > > - [Dubious, but plausible assumption] We should be able to explicitly > require those secondary properties, even if we allow otherwise allow less > than well-defined behavior for data races. > > - We're essentially already making the preceding dubious assumption. We > have all sorts of library APIs that don't specify how they behave in the > presence of races, but only say that you shouldn't do that. We're somehow > supposed to conclude that the heap can't be corrupted even in the presence > of racy library calls, because of the (unstated?) assumption that libraries > should behave as though they were implemented in Java, and Java programs > preserve e.g. memory safety. The only place we actually claim (incorrectly > as we now know) to have well-defined semantics for data races is at the > basic type and reference level, which is arguably not even the most > interesting place in a large code base. > > - Most of us don't care that much about slowing down potentially racing > accesses a bit. The reason the load->store ordering solution seems so > dubious for Java is that the compiler doesn't know which accesses might > race, and thus we need to treat many accesses conservatively. ARM is much > more concerned about Java than C++ memory_order_relaxed. > > > Possible long-term approach: > > - Switch to a much more C++-like (or Java library-like) model in which data > races have something like "undefined behavior". Exactly how to model that > is an open question. Ordinary loads can only see stores that happen-before > them, but racing loads trigger "undefined behavior". "Undefined behavior" > should be defined to allow reporting an error and produce any type correct > answer for the racing load. Unlike C++, we probably want to be explicit > that it disallows a VM crash > > - [Probably challenging, others understand the Java constraints better than > I] Introduce a mechanism for (nearly) unordered memory-order-relaxed like > racing loads. Require current racing accesses to use that mechanism > instead. (Open question: coherence) > > - Strengthen this memory_order_relaxed analog to guarantee load->store > ordering. > > - Implementations may specify that they treat all ordinary accesses as > these "memory_order_relaxed" accesses. Browser-based implementations, or > others that require the current security model, would do so. Whether and > how to specify this is open.. > > > Transition strategy: > > - Implementations are not required to break existing code in any way, > though the spec would allow them to. In the near term, we would expect > implementations to continue to support (possibly with a suitable flag) the > current ill-defined model, along with the new model. (Which should be > easy; the only really new support id for memory_order_relaxed and > load->store ordering.) > > - The fact that data race detection is much easier in the new model may > help to inspire people to move to it. > > > Long term potential advantages: > > - No OOTA issues! > > - Easier race detection. A standard conforming JVM should be able to throw > a data race exception if it finds one. > > - Uniform model for basic types and libraries. > > - We can delete the special cases for tearing longs and doubles without > unacceptably slowing down some implementations. > > > Long term disadvantages: > > - As for C++, we promise less about behavior of buggy programs. AFAICT, > much has been written about this, but it isn't a major practical issue > along the lines of memory safety. And again, we already have that problem > for library clients. > > - Security sensitive code will run slower and need a separate JVM flag. > Again, my impression is there is little of it, so this isn't a big deal. > (There are probably some mild security advantages in exchange; untrusted > racy code can induce slightly fewer perverse behaviors.) > > > Short term issues: > > - This would declare significant amounts of currently correct code to be > deprecated and in the future incorrect. But if we can figure out how to > cleanly introduce something like memory_order_relaxed, I think the required > changes would clearly also improve readability. > From david.lloyd at redhat.com Thu Oct 30 16:23:44 2014 From: david.lloyd at redhat.com (David M. Lloyd) Date: Thu, 30 Oct 2014 11:23:44 -0500 Subject: [jmm-dev] Update to description of JEP 193: Enhanced Volatiles In-Reply-To: References: <8DE0C1E6-6B6A-4C0F-8C42-A37947B44AF6@oracle.com> <54525D8D.2080801@univ-mlv.fr> Message-ID: <54526610.1030805@redhat.com> On 10/30/2014 10:53 AM, Paul Sandoz wrote: > > On Oct 30, 2014, at 4:47 PM, Remi Forax wrote: > >> >> On 10/30/2014 03:02 PM, Paul Sandoz wrote: >>> Hi, >>> >>> I have, with the help of Brian, Doug and John, updated the description of JEP 193: Enhanced Volatiles to reflect our current thinking based on: >>> >>> - the prototype implementation in valhalla; >>> - performance measurements of that implementation; and >>> - investigations related to signature polymorphic methods and invokedynamic. >>> >>> Thanks, >>> Paul. >> >> I seems that the changes are not propagated to the JEP yet, >> but there are available throught the corresponding bug: >> https://bugs.openjdk.java.net/browse/JDK-8046183 >> > > Doh! thanks, i forgot to send the link out, Wow, that's even *more* convoluted. Are we *certain* that we are actually improving on the original proposal here? It seems to me like everyone can't jump on the *handle bandwagon fast enough, even though it seems to be objectively more complex from concept (that human engineers want to understand) to API (the previously proposed API was very much cleaner and didn't rely on cross-your-fingers magic to make inefficient things become efficient) to implementation (to this day, relatively few people outside of Oracle even have a glimmer of understanding as to the rules and behaviors of these things). Are we *certain* this is an improvement? -- - DML From brian.goetz at oracle.com Thu Oct 30 17:18:44 2014 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 30 Oct 2014 13:18:44 -0400 Subject: [jmm-dev] Update to description of JEP 193: Enhanced Volatiles In-Reply-To: <54526610.1030805@redhat.com> References: <8DE0C1E6-6B6A-4C0F-8C42-A37947B44AF6@oracle.com> <54525D8D.2080801@univ-mlv.fr> <54526610.1030805@redhat.com> Message-ID: <545272F4.2090701@oracle.com> I think you are misunderstanding the underlying goal here, David, which may explain your reaction. The goal here was never "let's add more syntax". It was to have an alternative to Unsafe for exposing esoteric, low-level memory-access features in a regular, safe, reliably efficient, and specifiable way. Just as only .00001% of Java developers ever use Unsafe (or should, anyway), we don't expect the audience for this feature to be very large. MethodHandles are an excellent analogy; they are a tool intended for writers of compilers, language runtimes, and other low-level components. VarHandles are similar; this is a tool for people writing nonblocking algorithms and other fancy library code, without having to resort to Unsafe (which is currently the only option.) The proposed language syntax in the original JEP was the least-bad way at the time we could think of to expose this functionality (and, the semantics were a mess), but no one was very happy about it, and I for one am thrilled that we came up with a no-syntax way to expose the required functionality. So yes, I am absolutely certain that this is an improvement *for the goals we had in mind for this feature*. On 10/30/2014 12:23 PM, David M. Lloyd wrote: > On 10/30/2014 10:53 AM, Paul Sandoz wrote: >> >> On Oct 30, 2014, at 4:47 PM, Remi Forax wrote: >> >>> >>> On 10/30/2014 03:02 PM, Paul Sandoz wrote: >>>> Hi, >>>> >>>> I have, with the help of Brian, Doug and John, updated the >>>> description of JEP 193: Enhanced Volatiles to reflect our current >>>> thinking based on: >>>> >>>> - the prototype implementation in valhalla; >>>> - performance measurements of that implementation; and >>>> - investigations related to signature polymorphic methods and >>>> invokedynamic. >>>> >>>> Thanks, >>>> Paul. >>> >>> I seems that the changes are not propagated to the JEP yet, >>> but there are available throught the corresponding bug: >>> https://bugs.openjdk.java.net/browse/JDK-8046183 >>> >> >> Doh! thanks, i forgot to send the link out, > > Wow, that's even *more* convoluted. Are we *certain* that we are > actually improving on the original proposal here? It seems to me like > everyone can't jump on the *handle bandwagon fast enough, even though it > seems to be objectively more complex from concept (that human engineers > want to understand) to API (the previously proposed API was very much > cleaner and didn't rely on cross-your-fingers magic to make inefficient > things become efficient) to implementation (to this day, relatively few > people outside of Oracle even have a glimmer of understanding as to the > rules and behaviors of these things). > > Are we *certain* this is an improvement? > From dl at cs.oswego.edu Fri Oct 31 14:19:42 2014 From: dl at cs.oswego.edu (Doug Lea) Date: Fri, 31 Oct 2014 10:19:42 -0400 Subject: [jmm-dev] Another way to punt OOTA In-Reply-To: References: Message-ID: <54539A7E.8030606@cs.oswego.edu> On 10/28/2014 09:39 PM, Hans Boehm wrote: > Here's another conceivable approach. This sounds somewhat crazy based on > our prior assumptions, but it may only be mildly crazy, so here goes. I think some of the details are crazy, but I agree with most of the broad points: First, odds are that we will "solve" OOTA and related speculation constraints, but in a somewhat disappointing way: most likely by defining a form of "dep" such that (rf U dep) is acyclic, but where dep may sometimes be undecidable. Or any of several variations with similar impact. Paul et al's N4216 (http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2014/n4216.html) presents a meta-litmus test along these lines. With Alan, Peter, Viktor, and others looking at this from various angles, I'm still optimistic about discovering a solution straddled by C11 (allowing OOTA) and JSR133 (disallowing valid transformations). So it still seems best to imagine that we arrive (out-of-thin-air!) at a core model that suffices, even if in some cases it includes caveats along the lines of "read r could be 42 only if P==NP". > - The argument for providing well-defined behavior for data races in Java > was based either on the original model of Java, or on the desire to > unconditionally maintain secondary properties, like memory safety, even in > the presence of data races. Yes. No-OOTA is only one part of the minimal guarantees of even arbitrarily racy Java programs. This set of predicates forms the Java analog of C/C++ undefinedness. Informally, we (in conjunction with other part of the JLS) need to ensure that nothing anyone can write in Java proper causes a JVM to crash (with disclaimers about JNI etc that from a security point of view arbitrarily widen the trusted computing base. BTW, this is the main reason we need to stop making people use Unsafe to get the effects of enhanced-volatiles.) As I sketched out last January (mostly on the pre-jmm9 list), we ought to solidify meanings of memory safety and security -- these are at least as important as guaranteeing SC for DRF programs. And from there, we need simple characterizations of at least release->acquire and create->use (constructors). But I don't think we can simply characterize all the intermediate points. It seems impossible to routinely distinguish subtly correct vs subtly incorrect code. For example you need to know that the String hash function is idempotent, and that if hash is zero, it intentionally recomputes, to see that racy lazy initialization of String.hashCode is OK. > - We're essentially already making the preceding dubious assumption. We > have all sorts of library APIs that don't specify how they behave in the > presence of races, but only say that you shouldn't do that. We're somehow > supposed to conclude that the heap can't be corrupted even in the presence > of racy library calls, because of the (unstated?) assumption that libraries > should behave as though they were implemented in Java, and Java programs > preserve e.g. memory safety. To emphasize: I agree. > > - Switch to a much more C++-like (or Java library-like) model in which data > races have something like "undefined behavior". Exactly how to model that > is an open question. Ordinary loads can only see stores that happen-before > them, but racing loads trigger "undefined behavior". "Undefined behavior" > should be defined to allow reporting an error and produce any type correct > answer for the racing load. And to emphasize: I disagree in the general case because I don't know how to do it. However, I don't think there is anything stopping JVM+core-libraries conspiring to throw exceptions in particular kinds of races that are never correct. Or for add-on tools to dynamically or statically detect them. > > - [Probably challenging, others understand the Java constraints better than > I] Introduce a mechanism for (nearly) unordered memory-order-relaxed like > racing loads. Require current racing accesses to use that mechanism > instead. (Open question: coherence) I have yet to see a compelling example/case for guaranteeing coherence for relaxed accesses to volatiles (i.e., in Java 9+, the enhanced-volatile mechanism for a relaxed read.) -Doug From dl at cs.oswego.edu Fri Oct 31 15:05:03 2014 From: dl at cs.oswego.edu (Doug Lea) Date: Fri, 31 Oct 2014 11:05:03 -0400 Subject: [jmm-dev] Another way to punt OOTA In-Reply-To: <54525F68.9080109@oracle.com> References: <54525F68.9080109@oracle.com> Message-ID: <5453A51F.9070602@cs.oswego.edu> On 10/30/2014 11:55 AM, Brian Goetz wrote: > But, while on the topic of security, we do have an interest in strengthening > various integrity constraints. Specifically, the non-finality of final fields > is a persistent irritant, and we would like to get to an initialization model > that meets the extended use cases (e.g., dependency injection, deserialization > of objects with final fields) while strengthening the promises of "final means > final." (See John Rose's blog entry on larval objects for a hint about the > direction we've got in mind.) I still think the only path here is for the JMM per se to get out of the final fields business, and just promise the equivalent of a store fence on constructor exit. Then various annotations, trusted class-loading mechanisms, etc can help establish restrictions on writes and/or visibility. -Doug