hg: valhalla/valhalla: 8205549: [lworld] Unsafe support for flattened field of value type

John Rose john.r.rose at oracle.com
Wed Jul 11 23:17:17 UTC 2018

On Jul 11, 2018, at 3:08 PM, Karen Kinnear <karen.kinnear at oracle.com> wrote:
> Mandy,
> Many thanks for jumping in and figuring this out so quickly.
> I had some questions about follow-on steps you were planning for lw1 please - could you possibly
> file lw1 bugs for the steps you are planning to do so we can sync up?
> 1. Flattened arrays
> — AFAICT you have implemented unsafe support for value types in fields for MethodHandles, VarHandles and Reflection.
> What were your plans for array support?

I think the array support uses bytecodes instead of Unsafe.
As such, it should pretty much Just Work wth value types.
See code for MethodHandleImpl.makeArrayElementAccessor;
it has no use of Unsafe, just xaload/xastore instructions on
particular array types.

> If you add new APIs here, can we disallow a base of zero and require a base that is an array?

Please, let's not disallow this.  I think we can get away with it, and
it's very useful.  As long as a value type does not contain oops, it
seems reasonable (failing some argument I'm not aware of) to
store the value type in native memory.  In fact, some value types
(as in the Vector API) will be bridges to native data types which
don't correspond to Java primitives.  Those value types should
be loadable and storable directly to and from memory via the
usual conventions in Unsafe, which involve zero bases.

> 2. There were several proposals for explicit new API points for getReference/putReference (your call on naming) and friends that would
> know they were dealing with objects. Are you planning to add those for lw1?
> And the C2 folks would move the intrinsics today used for getObject/putObject to be used for the new getReference/putReference.
> They need to know your timing here please.
> 3. getObject/putObject and variations
> See attached proposal - John bought into steps 1-3. So
> Step 2: Were you planning to move conditional logic to jdk.internal.misc.unsafe to split into calls to getValue/getReference for lw1?
> Step 3: Are there other JDK uses of getObject/putObject variations that you would change to explicitly use getValue/putValue or getReference/putReference?
> What I had proposed was that internal to the JDK we switch over to using the explicit new APIs.
> This could allow Remi’s proposal of moving the getObject/putObject split logic into sun.misc.unsafe

(Sounds reasonable to me!)

> 4. Immutability
> For the record I share Frederic’s concern - if you write to a value type that has its default value you overwrite the default value for that type.
> Looks like for lw1 folks want to allow this. 

It seems paradoxical to allow putByte to an immutable storage,
but that's the game with Unsafe:  It performs machine-level operations
that would be unsafe and potentially illegal and damaging if performed
via a normal public-use JVM API.  The interpreter, runtime, and JIT all
perform such paradoxical stores, and Unsafe is a member of that select

The complete story for this, in Unsafe, requires confining the paradoxical
use of putByte, etc., to a limited explicit scope, using barrier operations
before and after the paradoxical write.  Between the barrier operations,
the supposedly immutable value instance is held in a private buffer where
mutations are localized (unobservable elsewhere, e.g., via global variables)
until it is patched up to its new value, before it is released into the wild.
So the sequence of operations is like this:

   Point patchPointValue(Point x1) {  // x1 is immutable and shareable
     Point buf;  // buf is mutable but private
     buf = Unsafe.makeWritableBufferedCopy(x1);  // START
     Unsafe.putByte(buf, MY_OFFSET, 42);  // MODIFY
     Point x2 = Unsafe.finishWritableBufferedCopy(buf);  // END
     return x2; // x2 is immutable and shareable

The funny status of "buf" in this example is that of a "larval" object:
It is hidden and under development, to be metamorphosed to an
adult state when the changes are finished.

Note that Unsafe.putByte (or any other putX) doesn't know whether
it is doing something safe or not:  It is the user's responsibility to
avoid just scribbling a byte to any old value instance; the user must
make sure that it is a private/buffered/writable/larval value instance.
In doing so the user takes on exactly the same kind of responsibility
that is taken on by the engineer of the interpreter, runtime, or JIT
not to scribble results on the wrong output memory.

In the current state of things there is no way to absolutely ensure
that a given value instance is unshared; that's why the Unsafe API
needs those fencing operations, one to force a value instance to be
unshared (hence safely writable), and one to pat it on the back and
send it on its way as a shareable immutable.

> 5. Writing null. Sounds like John wants this to be the user’s problem, with unpredictable results. Agree with not automatically replacing
> null with a default value.

Yep.  If we make it the user's problem, the user will write code to
solve the problem.

> 6. For lw1, the vm does not support atomics/volatiles for value types. So glad you added a java workaround.

Yes, that will help.

— John

More information about the valhalla-dev mailing list