RFR: JDK-8205549 JDK-8205698 Support of flattened values in Unsafe
John Rose
john.r.rose at oracle.com
Fri Jun 29 00:54:16 UTC 2018
On Jun 28, 2018, at 2:03 PM, mandy chung <mandy.chung at oracle.com> wrote:
>
> On 6/27/18 4:54 PM, Paul Sandoz wrote:
>> Hi John,
>> Those new API points you propose match closely with what i had in
>> mind, and i also agree that a set of query methods are important (I
>> was just scratching the surface of that).
>> IMHO i think we can make a tentative split now and that would also
>> increase prototyping velocity without potentially destabilizing
>> existing unsafe usages. Mandy’s patch indicates the amount of Java
>> platform code changes are manageable for such a split and it can
>> allow for quicker experimentation with VarHandles.
>
> I am making further progress on the patch [1] to split the access to flattened fields with the new Unsafe API. It's still work in progress and I should be able to post something next week (if not this week).
>
> Mandy
> [1] http://cr.openjdk.java.net/~mchung/valhalla/webrevs/unsafe-flat-fields-webrev/
I read this patch and I like what you are doing; thanks for pushing on this problem.
I guess the underlying theory is that any object field whose type is a value type
can be flattened, but the decision to flatten must be queried for the metadata
*for that field*. The query returns a boolean: If false, the field is formatted as
a regular oop pointer (though there might be a restriction against nulls on it).
If true, then the field is formatted in a layout which is permanently assigned
to the value type. Two flattened fields of the same value type *always* have
the same layout; thus, flattened fields have no variance or polymorphism.
This allows you to statically query whether a given field is flattened, and
thereafter just use the value type (Class mirror) to control how the field
is correctly accessed. This all makes sense to me, and we want to be
clear that this is how we are going to do things. For example, we won't
pack two value type fields in one container by mixing their fields together
according to alignment restrictions, even though that would pack the
containing object tighter in memory. I have ideas how to do this in the
long run, but it would complicate the logic for U.getValue.
Once a field (with its base offset) has been determined to be a flat value,
then loading or storing it is a fixed procedure to copy into TLVB or out of
TLVB/HB, which the JIT can easily "see through" and optimize down to
individual memory operations. There will be one such procedure for
each U.get/put operation. Maybe {get,put} x {normal,volatile,acquire,
release,opaque}. In addition to teaching the JIT how to optimize those,
I wonder if we will want to make them into quasi-virtual methods on
java.lang.Class or ValueKlass, and call them out-of-line from codes
which cannot determine the value type Class as a JIT-time constant.
Probably not, but it's interesting to imagine this protocol, a sort of
type-dependent access API for flattened fields.
In your code, the extra check in unsafe.cpp (check_putfield_access) seems
to promise that the unsafe access is taking responsibility for preventing certain
mismatched accesses. The more "unsafe-y" way to handle this is to require the
caller of the access to perform the check. In this way the primitive can do the
simplest possible thing, even if that would crash the VM if the access is mismatched.
This reasoning applies to almost every path you might find in unsafe.cpp which throws
an exception. It doesn't apply to "large scale" ops like loadClass or allocateMemory,
but it does apply to every op we hope the JIT will optimize as an intrinsic.
As a service to the user we can sometimes make simple checks in unsafe.cpp,
but if we put complicated ones in, then we are putting the optimizations at risk,
since the JIT will then have the burden to reproduce the complicated checks.
Making the unsafe.cpp code using the 'guarantee' macro is less friendly to the
user, but more honest than throwing an exception that the JIT won't be able
to produce.
Dealing with the layers of required checking will be easier, I think, if we put most
or all of the checks (for flattening, for value type mismatches, etc.) in Java code.
So if we *do* decide that getObject should have a special value-type check
(as a service to the user, even though the user should drive more carefully)
then that check would be better reified as a subroutine method call inside
a Java-coded version of U.getObject, rather than hardwired C++ code in
unsafe.cpp. In that case, the logic of the Java-coded check can itself be
made into an intrinsic, so the JIT can separately optimize it.
— John
More information about the valhalla-dev
mailing list