API review of VarHandles

Jeremy Manson jeremymanson at google.com
Wed Feb 10 00:09:06 UTC 2016


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