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