API review of VarHandles

Hans Boehm hboehm at google.com
Wed Feb 10 01:03:22 UTC 2016


I found this a bit scary for naive readers:

* The Java Language Specification permits operations to be executed in
* orders different than are apparent in program source code, subject to
* constraints arising, for example, from the use of locks, {@code volatile}
* fields or VarHandles.

I would change it to

* The Java Language Specification permits other threads to observe
operations
* as if they were executed in orders different than are apparent in program
source code,
* subject to constraints arising, for example, from the use of locks,
{@code volatile}
* fields or VarHandles.

to make it clear that we are not talking about intra-thread semantics here.

That way it will hopefully only be scary to experts, as intended.

On Tue, Feb 9, 2016 at 4:09 PM, Jeremy Manson <jeremymanson at google.com>
wrote:

> Thanks, Paul!  I agree that the wording about reorderings is probably
> okay.  I probably would have added the sentence about
> implementation-dependence, but I can see why you might want to avoid it.
>
> Jeremy
>
> On Tue, Feb 9, 2016 at 3:12 AM, Paul Sandoz <paul.sandoz at oracle.com>
> wrote:
>
> > Hi Jeremy,
> >
> > Sorry for the late reply. Catching after some distractions and being
> away.
> >
> >
> > > On 22 Jan 2016, at 19:03, Jeremy Manson <jeremymanson at google.com>
> wrote:
> > >
> > > Couple of thoughts:
> > > The Java Language Specification permits operations to be executed in
> > orders different than are apparent in program source code, subject to
> > constraints arising, for example, from the use of locks, volatile fields
> or
> > VarHandles. The static methods, fullFence, acquireFence, releaseFence,
> > loadLoadFence andstoreStoreFence, can also be used to impose constraints.
> > Their specifications are phrased in terms of the lack of "reorderings" --
> > observable ordering effects that might otherwise occur if the fence were
> > not present.
> > >
> > >
> > > There is no notion of reordering (per se) in the JLS; the fact that
> > reorderings can occur is just implied by the way programs can be observed
> > to behave. So, these fence operations don't map to anything
> > non-implementation dependent.  I don't think it would be impossible to
> fix
> > the spec to define something that works the way you want (similar to the
> > final field semantics), but it isn't in there already.  You might want to
> > call that out (either by saying this behavior is best effort
> > implementation-dependent or by fixing the spec).
> > >
> >
> > Until we update the JMM spec, pushed out beyond 9, we are in a bit of a
> > bind and have to hand wave a bit for both access mode methods and fences,
> > both of which talk about reorderings (see getAcquire/setRelease for
> > example).
> >
> > There is the following at the end, but it’s easy to loose sight of with
> > all the other sections:
> >
> > * @apiNote
> > * More precise phrasing of the specification of access mode methods and
> > memory
> > * fence methods may accompany future updates of the Java Language
> > * Specification.
> >
> > I moved that up into the fences paragraph.
> >
> > * <p>In addition to supporting access to variables under various access
> > modes,
> > * a set of static methods, referred to as memory fence methods, is also
> > * provided for fine-grained control of memory ordering.
> > *
> > * The Java Language Specification permits operations to be executed in
> > * orders different than are apparent in program source code, subject to
> > * constraints arising, for example, from the use of locks, {@code
> volatile}
> > * fields or VarHandles.  The static methods, {@link #fullFence
> fullFence},
> > * {@link #acquireFence acquireFence}, {@link #releaseFence releaseFence},
> > * {@link #loadLoadFence loadLoadFence} and {@link #storeStoreFence
> > * storeStoreFence}, can also be used to impose constraints.  Their
> > * specifications, as is the case for certain access modes, are phrased in
> > terms
> > * of the lack of "reorderings" -- observable ordering effects that might
> > * otherwise occur if the fence was not present.  More precise phrasing of
> > the
> > * specification of access mode methods and memory fence methods may
> > accompany
> > * future updates of the Java Language Specification.
> >
> >
> > I could append another sentence:
> >
> >   Until then, such reordering behaviour is considered
> > implementation-dependent on a best-effort basis.
> >
> > But perhaps the less we say the better?
> >
> >
> > > If a VarHandle references a read-only variable (for example a final
> > field) then write, atomic update and numeric atomic update access modes
> are
> > not supported and corresponding methods throw
> UnsupportedOperationException.
> > >
> > > Are you sure you want to limit it in this way?  There are an awful lot
> > of calls to setAccessible in the world of reflection.  And writing to
> final
> > fields *does* map to something sensible in the spec.  In fact, it would
> be
> > great to have something that wasn't quite such a blunt instrument as
> > setAccessible.
> >
> > Indeed, very much a blunt instrument.
> >
> > Note that setAccessible would otherwise be required to be called on the
> > Field before being unreflected (either for unreflectVarHandle or, as is
> the
> > case today, unreflectSetter/Getter).
> >
> > I don’t wanna widen the accessibility hole of this blunt instrument right
> > now; it’s easy to widen rather than shrink later on if need be.
> >
> > The motivation behind this is we want to move towards a world "final
> > really means final" and thus lots of nice optimisations may ensue. It may
> > be a long and windy road to get there but we have some plans and are
> > starting to work some routes towards that goal.
> >
> >
> > >
> > > getVolatile
> > > public final Object getVolatile(Object... args)
> > > Returns the value of a variable, with memory semantics of reading a
> > volatile variable.
> > >
> > > Reading *which* volatile variable?  You probably mean that all
> > getVolatiles and setVolatiles provide semantics that behave as if the
> > variable being written / read was declared volatile in the first place,
> but
> > it is worth calling out.
> > >
> >
> > /**
> >  * Returns the value of a variable, with memory semantics of reading as
> if
> >  * the variable was declared {@code volatile}.
> > ...
> > Object getVolatile(Object... args);
> >
> > /**
> >  * Sets the value of a variable to the {@code newValue}, with memory
> >  * semantics of setting as if the variable was declared {@code volatile}.
> > …
> > void setVolatile(Object... args);
> >
> > I also updated the plain accessors using similar “as if” language.
> >
> >
> > > Nits:
> > >
> >
> > The following nits are copied and translated from documentation on
> > MethodHandle.
> >
> >
> > > As is usual with virtual methods, source-level calls to access mode
> > methods compile to an invokevirtual instruction. More unusually, the
> > compiler must record the actual argument types, and may not perform
> method
> > invocation conversions on the arguments. Instead, it must push them on
> the
> > stack according to their own unconverted types. The VarHandle object
> itself
> > is pushed on the stack before the arguments. The compiler then calls the
> > VarHandle with a symbolic type descriptor which describes the argument
> and
> > return types.
> > >
> > > This is somewhat oddly worded.  The compiler doesn't push arguments on
> a
> > stack or call anything - it generates instructions that do that.
> > >
> >
> > I updated to:
> >
> > * As is usual with virtual methods, source-level calls to access mode
> > methods
> > * compile to an {@code invokevirtual} instruction.  More unusually, the
> > * compiler must record the actual argument types, and may not perform
> > method
> > * invocation conversions on the arguments.  Instead, it must generate
> > * instructions to push them on the stack according to their own
> unconverted
> > * types.  The VarHandle object itself will be pushed on the stack before
> > the
> > * arguments.  The compiler then generates an {@code invokevirtual}
> > instruction
> > * that invokes the access mode method with a symbolic type descriptor
> which
> > * describes the argument and return types.
> >
> >
> > > The first time a invokevirtual instruction is executed it is linked, by
> > symbolically resolving the names in the instruction and verifying that
> the
> > method call is statically legal
> > >
> > > I keep trying not to call this out as a nit, but there should be no
> > comma between "linked" and "by”.
> >
> > Updated.
> >
> > In both cases I also updated the relevant areas in MethodHandle.
> >
> > Thanks,
> > Paul.
> >
>


More information about the valhalla-dev mailing list