Hi Jeremy,

Sorry for the late reply. Catching after some distractions and being away.


> On 22 Jan 2016, at 19:03, Jeremy Manson <jeremyman...@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.

Reply via email to