JDK-8205549: unsafe and LW1: needed for MethodHandles, VarHandles and Reflection
Remi Forax
forax at univ-mlv.fr
Wed Jun 27 22:28:47 UTC 2018
Hi Karen,
at least MethodHandles.zero also doesn't work with a value type.
and there are method handles to access arrays, see below.
Rémi
----- Mail original -----
> De: "Karen Kinnear" <karen.kinnear at oracle.com>
> À: "valhalla-dev" <valhalla-dev at openjdk.java.net>
> Envoyé: Mercredi 27 Juin 2018 23:36:44
> Objet: JDK-8205549: unsafe and LW1: needed for MethodHandles, VarHandles and Reflection
> I’ve appended a summary of Unsafe object accessors used in MethodHandles,
> VarHandles and Reflection.
>
> Thanks to Remi’s hashCode that Mandy was trying, we identified a hole in our
> current implementation.
> Turns out our tests for MethodHandles, VarHandles and Reflection did not include
> testing for field accessors
> to flattened value type fields, which all use unsafe.
>
> Model of usage (see e.g. test/hotspot/jtreg/runtime/Unsafe/GetPutObject.java)
> 1. use reflection to return a j.l.reflect.Field:
> Test.class.getField("fieldname")
> 2. unsafe.objectFieldOffset(j.l.reflect.Field)
> 3. unsafe.getObject(jobject t, offset)
>
> sample array usage:
> Object arrayObject[]
> 1. int scale = unsafe.arrayIndexScale(arrayObject.getClass())
> 2. long offset = unsafe.arrayBaseOffset(arrayObject.getClass())
> 3. iterate, starting with offset, += scale and pass to
> unsafe.getObject(arrayObject, offset)
>
> Issues:
> 1. getObject on a flattened value field today will return the first 64 bits of
> the flattened contents
> 2. putObject on a flattened value field today will overwrite the first 64 bits
> with an object address
> 3. put$Type$ to a field in a value class will NOT prevent writing
> note: I recognize this is unsafe. I highly recommend we prevent writing when
> given a clazz and offset so
> we can identify a value type field.
> 4. getObject/putObject not only accept a clazz + offset, they also accept a null
> base pointer + arbitrary address
> - there is no way to determine the start of the object
> 5. performance
> - basic unsafe calls are going to be very slow when applied to flattened fields
> 6. C2 intrinsics
> - today we count on intrinsics to make these fast. If C2 scalarizes fields from
> a value type, there may not be any value type to return
>
> Status:
> 1. Frederic has been working rapidly on an initial prototype for changing
> unsafe, and sent a webrev
> for unsafe changes.
> http://cr.openjdk.java.net/~fparain/Unsafe/webrev.02/index.html
> <http://cr.openjdk.java.net/~fparain/Unsafe/webrev.02/index.html>
> Note - this will not handle passing a null base pointer to a value type
>
> 2. Paul has started prototyping one possible form of optimization -
> - add some internal APIs to determine if you have a flattened field or array
> - call a different unsafe API to access a flattened field or array element
> - use this for VarHandles
>
> 3. Mandy is prototyping optimizations for MethodHandles and Reflection to use
> these new APIs
>
> Next Steps:
>
> Roland:
> Please do look at C2 intrinsics for the unsafe Object accessors and see what it
> would take to make these intrinsics work
> for value types
> If you think there is significant benefit in adding new APIs, please help us
> understand what APIs might be most helpful.
>
> Mandy, Paul - could you possibly send your webrevs when you are ready?
>
> Then we can have a better conversation of alternatives with our C2 folks.
>
> We will need a more complete set of tests specifically for MethodHandles,
> VarHandles and Reflection as well as for
> unsafe.
>
>
> thanks,
> Karen
>
> p.s. Here is the usage of unsafe for MethodHandles, VarHandles, Reflection and
> java.util.Concurrent.
> I did not include explicit internal uses on JDK existing classes or on
> ByteBuffers.
> I did not do a complete search of the JDK.
>
> MethodHandles:
>
> DirectMethodHandles create LambdaForms with NamedFunctions in unsafe to access
> fields. Underneath they use unsafe:
> getObject, getObjectVolatile, putObject, putObjectVolatile as well as
> equivalents for primitive types.
>
> sources in DirectMethodHandles.java: see makePreparedFieldLambdaForm,
> getFieldKind: Kind is an enum in LambdaForm.java
> note: uses MethodHandleNatives.objectFieldOffset, staticFieldBase,
> staticFieldOffset to set up base & offset, base is always
> either the mirror for statics or the class for instances. offset is obtained
> from fieldDescriptor returned by LinkResolver::resolve_field,
> i.e. instanceKlass.find_field(). MemberName stores offset in vmindex, is_static,
> is_setter are stored in flags.
>
> I do not see any array element accessors via MethodHandles
MethodHandles.arrayElementGetter() and MethodHandles.arrayElementSetter.
>
> VarHandles:
> Creates Forms which use unsafe.get$Type$ use:
> getObject, putObject and decorations such as Volatile, Opaque,Acquire, … as well
> as equivalents for primitive types
>
> VarHandles ALSO access array elements using unsafe.
> arrayBaseOffset, arrayIndexScale (returns ascale)
> shift = 31 - Integer.numberOfLeadingZeros(ascale) and then e.g.
> UNSAFE.get$Type$Volatile, etc.
>
> (sources in VarHandle.s.java, X-VarHandle.java.template). Acquire base and
> offset from MethodHandleNatives calls.
> For the non-volatile case, appears to directly get/set from the array[index]
>
> Reflection:
> Reflection creates UnsafeFieldAccessorImpl (or Qualified for Volatile, same 2
> for static) and they use unsafe:
> getObject, putObject, getObjectVolatile, putObjectVolatile
>
> sources in jdk/internal/reflect/UnsafeFieldAccessorImpl.java uses
> unsafe.staticFieldOffset or unsafe.objectFieldOffset
>
> I do not see any array element accessors in Reflection.
>
> java.util.Concurrent: Atomics - uses various decorated versions of
> Get/putObjectVolatile/Release/compareAndSet etc.
> I think clarifying that LW1 does not support java.util.Concurrent atomics is the
> way to handle this one.
More information about the valhalla-dev
mailing list