Finalization and dead references: another proposal (original) (raw)
Hans Boehm hboehm at google.com
Fri Dec 8 00:57:51 UTC 2017
- Previous message: Finalization and dead references: another proposal
- Next message: Java SE Maths questions.
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
On Thu, Dec 7, 2017 at 7:49 AM, Peter Levart <peter.levart at gmail.com> wrote:
... 1st case that comes to mind and is a real case in the JDK is the existence of sun.nio.ch.DirectBuffer internal (not exported) interface implemented by NIO direct buffer(s) with method:
long address(); Utility method like the following: static void erase(ByteBuffer bb) { unsafe.setMemory(((DirectBuffer)bb).address(), bb.capacity(), (byte)0); } ...won't get reachabilityFence(bb) before return, will it? Calling a method on a bb doesn't count as a dereference of a reachablity-sensitive field of bb. Unless methods could also be annotated with the same annotation. This would only work for instance methods that return a native resource kept in the same instance or some instance that is reachable from this instance. Native resources are typically encapsulated, but there are various levels of encapsulation. DirectBuffer is an example of module level encapsulation by non-exported public interface implemented by package-private classes.
I think there are two issues here. The first one is the use of a getter to retrieve the value of the address field. This yields a value whose logical lifetime is limited by the lifetime of a separate garbage-collected Java object. That feels very un-Java-like and dangerous. My immediate inclination is to strongly discourage this idiom.
A second issue is a possible access to an @ReachabilitySensitive field from outside the declaring class. I've gone back and forth as to whether they should be covered, i.e. result in a logical reachabilityFence(bb). It's easy enough to specify either way. The major difference is whether an implementation that simply avoids doing dead reference elimination on any class containing an @ReachabilitySensitive annotation is conforming. If you want this to work, the criterion becomes "accesses an @ReachabilitySensitive field". Which may be OK?
2nd case is artificial. But, since we have streams, lambdas, optionals... It's easy to fool above rules even if the annotation is put on the DirectBuffer#address() method ...
static void doSomethingWith1stNonNull(DirectBuffer... dbs) { Stream.of(dbs) .filter(Objects::nonNull) .mapToLong(DirectBuffer::address) .findFirst() .ifPresent(addr -> { ... do something with addr ... }); } Even with imperative programming, one can play with scopes: static void doSomethingWith1stNonNull(DirectBuffer... dbs) { long addr = 0; for (DirectBuffer db : dbs) { if (db != null) { addr = db.address(); break; } } if (addr != 0) { ... do something with addr ... } }
Aside from the above issues, the intent was for these to work. A rechabilityFence(dbs) should be generated at the end of either method (possibly among others).
Or, hope that this would work (but the above rules don't cover it): static void doSomethingWithEither(DirectBuffer db1, DirectBuffer db2) { long addr = ((some condition) ? db1 : db2).address(); ... do something with addr ... } Again, this should be covered, aside from the issues discussed above. If this were an access to an @ReachabilitySensitive field, a reachaibilityFence for the appropriate dbX is required at the end. A real compiler would just generate one each for both.
But I can imagine that teaching users to not do such foolish things would be easy. The rules are simple: - always dereference reachablity-sensitive resources directly through local reference variables. - make sure that the local reference variable that you extracted reachablity-sensitive resource from, is in scope while you perform operations on the resource.
Regards, Peter
- Previous message: Finalization and dead references: another proposal
- Next message: Java SE Maths questions.
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]