JDK-8205549: unsafe and LW1: needed for MethodHandles, VarHandles and Reflection

Karen Kinnear karen.kinnear at oracle.com
Wed Jul 11 20:09:50 UTC 2018


Remi,

Thank you for catching that - thought I had already thanked you.

Karen

> On Jun 27, 2018, at 6:28 PM, Remi Forax <forax at univ-mlv.fr> wrote:
> 
> 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