Discussion:
RFR:8157251:BeanLinker relinks array length operations for array types
Priya Lakshmi Muthuswamy
2018-01-09 07:00:31 UTC
Permalink
Hi,

Please review JDK-8157251 : BeanLinker relinks array length operations
for array types

JBS : https://bugs.openjdk.java.net/browse/JDK-8157251
webrev : http://cr.openjdk.java.net/~pmuthuswamy/8157251/webrev.00/

Thanks,
Priya
Jim Laskey (Oracle)
2018-01-09 13:23:28 UTC
Permalink
+1
Hi,
Please review JDK-8157251 : BeanLinker relinks array length operations for array types
JBS : https://bugs.openjdk.java.net/browse/JDK-8157251
webrev : http://cr.openjdk.java.net/~pmuthuswamy/8157251/webrev.00/
Thanks,
Priya
Hannes Wallnöfer
2018-01-09 13:58:27 UTC
Permalink
+1

Hannes
+1
Hi,
Please review JDK-8157251 : BeanLinker relinks array length operations for array types
JBS : https://bugs.openjdk.java.net/browse/JDK-8157251
webrev : http://cr.openjdk.java.net/~pmuthuswamy/8157251/webrev.00/
Thanks,
Priya
Attila Szegedi
2018-01-09 14:21:08 UTC
Permalink
This effectively reverts the combined <https://bugs.openjdk.java.net/browse/JDK-8157225> and <https://bugs.openjdk.java.net/browse/JDK-8157250>.

That was not the intent of 8157251, though.

The intent of 8157251 was to use MethodHandles.arrayLength(Object[].class) for all arrays with components of reference type (and use ValidationType.INSTANCE_OF for it, as all such arrays will be instance-of Object[] through instance-of semantics for array types) and leave the linking of arrays with primitive component types as they are today.

So, basically, something like:

if(clazz.isArray()) {
// Some languages won't have a notion of manipulating collections. Exposing "length" on arrays as an
// explicit property is beneficial for them.
if (clazz.getComponentType().isPrimitive()) {
setPropertyGetter("length", MethodHandles.arrayLength(clazz), ValidationType.EXACT_CLASS);
} else {
setPropertyGetter("length", MethodHandles.arrayLength(Object[].class), ValidationType.INSTANCE_OF);
}

Obviously, this is again a tradeoff between linkage stability and performance, except that with this solution we don’t sacrifice any performance and we still increase linkage stability. Going back to Array.getLength does further increase linkage stability, but *speculatively* it doesn’t intrinsify to as lean code as MethodHandles.arrayLength does (it certainly erases the type information of the argument); someone with time on their hands should probably run some PrintAssembly tests with -XX:-TieredCompilation to see whether this is true (if not, then 8157225 and 8157250 were done for nothing and this patch undoes them anyway).

In any case, I don’t have a too strong opinion about this; I don’t mind even if this ends up being a reversal of 8157225; it’s just weird that we have arrayLength method handle intrinsics and not use them.

Attila.
Hi,
Please review JDK-8157251 : BeanLinker relinks array length operations for array types
JBS : https://bugs.openjdk.java.net/browse/JDK-8157251
webrev : http://cr.openjdk.java.net/~pmuthuswamy/8157251/webrev.00/
Thanks,
Priya
Priya Lakshmi Muthuswamy
2018-01-10 05:42:44 UTC
Permalink
Hi Attila,

Thanks for the review. I just felt in the case of primitive types there
will be relinking.
I tried with the below fix.
In the case object types, I see relinking when we use
Validation.INSTANCE_OF. But works fine without relinking when we use
Validation.IS_ARRAY

if(clazz.isArray()) {
// Some languages won't have a notion of manipulating collections.
Exposing "length" on arrays as an // explicit property is beneficial for
them. if (clazz.getComponentType().isPrimitive()) {
setPropertyGetter("length", MethodHandles.arrayLength(clazz), ValidationType.EXACT_CLASS);
}else {
setPropertyGetter("length", MethodHandles.arrayLength(Object[].class), ValidationType.IS_ARRAY);
}

Thanks,
Priya
Post by Attila Szegedi
This effectively reverts the combined <https://bugs.openjdk.java.net/browse/JDK-8157225> and <https://bugs.openjdk.java.net/browse/JDK-8157250>.
That was not the intent of 8157251, though.
The intent of 8157251 was to use MethodHandles.arrayLength(Object[].class) for all arrays with components of reference type (and use ValidationType.INSTANCE_OF for it, as all such arrays will be instance-of Object[] through instance-of semantics for array types) and leave the linking of arrays with primitive component types as they are today.
if(clazz.isArray()) {
// Some languages won't have a notion of manipulating collections. Exposing "length" on arrays as an
// explicit property is beneficial for them.
if (clazz.getComponentType().isPrimitive()) {
setPropertyGetter("length", MethodHandles.arrayLength(clazz), ValidationType.EXACT_CLASS);
} else {
setPropertyGetter("length", MethodHandles.arrayLength(Object[].class), ValidationType.INSTANCE_OF);
}
Obviously, this is again a tradeoff between linkage stability and performance, except that with this solution we don’t sacrifice any performance and we still increase linkage stability. Going back to Array.getLength does further increase linkage stability, but *speculatively* it doesn’t intrinsify to as lean code as MethodHandles.arrayLength does (it certainly erases the type information of the argument); someone with time on their hands should probably run some PrintAssembly tests with -XX:-TieredCompilation to see whether this is true (if not, then 8157225 and 8157250 were done for nothing and this patch undoes them anyway).
In any case, I don’t have a too strong opinion about this; I don’t mind even if this ends up being a reversal of 8157225; it’s just weird that we have arrayLength method handle intrinsics and not use them.
Attila.
Hi,
Please review JDK-8157251 : BeanLinker relinks array length operations for array types
JBS : https://bugs.openjdk.java.net/browse/JDK-8157251
webrev : http://cr.openjdk.java.net/~pmuthuswamy/8157251/webrev.00/
Thanks,
Priya
Hannes Wallnöfer
2018-01-10 13:32:28 UTC
Permalink
Priya,

The problem with your solution that using an object array invocation with a primitive array will throw a ClassCastException as it passes the isArray guard.

On the other hand, the problem with instanceof validation in Attila’s snippet is that it uses the concrete callsite type (e.g. String[]) instead of Object[]. What we’d need is a guard with an instanceof Object[] check.

However, I don’t think a callsite for array length will usually see so many different array classes to go megamorphic, so I think both your solutions (Priya’s webrev and Attila’s code snippet) are acceptable.

Hannes
Post by Priya Lakshmi Muthuswamy
Hi Attila,
Thanks for the review. I just felt in the case of primitive types there will be relinking.
I tried with the below fix.
In the case object types, I see relinking when we use Validation.INSTANCE_OF. But works fine without relinking when we use Validation.IS_ARRAY
if(clazz.isArray()) {
// Some languages won't have a notion of manipulating collections. Exposing "length" on arrays as an // explicit property is beneficial for them. if (clazz.getComponentType().isPrimitive()) {
setPropertyGetter("length", MethodHandles.arrayLength(clazz), ValidationType.EXACT_CLASS);
}else {
setPropertyGetter("length", MethodHandles.arrayLength(Object[].class), ValidationType.IS_ARRAY);
}
Thanks,
Priya
Post by Attila Szegedi
This effectively reverts the combined <https://bugs.openjdk.java.net/browse/JDK-8157225> and <https://bugs.openjdk.java.net/browse/JDK-8157250>.
That was not the intent of 8157251, though.
The intent of 8157251 was to use MethodHandles.arrayLength(Object[].class) for all arrays with components of reference type (and use ValidationType.INSTANCE_OF for it, as all such arrays will be instance-of Object[] through instance-of semantics for array types) and leave the linking of arrays with primitive component types as they are today.
if(clazz.isArray()) {
// Some languages won't have a notion of manipulating collections. Exposing "length" on arrays as an
// explicit property is beneficial for them.
if (clazz.getComponentType().isPrimitive()) {
setPropertyGetter("length", MethodHandles.arrayLength(clazz), ValidationType.EXACT_CLASS);
} else {
setPropertyGetter("length", MethodHandles.arrayLength(Object[].class), ValidationType.INSTANCE_OF);
}
Obviously, this is again a tradeoff between linkage stability and performance, except that with this solution we don’t sacrifice any performance and we still increase linkage stability. Going back to Array.getLength does further increase linkage stability, but *speculatively* it doesn’t intrinsify to as lean code as MethodHandles.arrayLength does (it certainly erases the type information of the argument); someone with time on their hands should probably run some PrintAssembly tests with -XX:-TieredCompilation to see whether this is true (if not, then 8157225 and 8157250 were done for nothing and this patch undoes them anyway).
In any case, I don’t have a too strong opinion about this; I don’t mind even if this ends up being a reversal of 8157225; it’s just weird that we have arrayLength method handle intrinsics and not use them.
Attila.
Hi,
Please review JDK-8157251 : BeanLinker relinks array length operations for array types
JBS : https://bugs.openjdk.java.net/browse/JDK-8157251
webrev : http://cr.openjdk.java.net/~pmuthuswamy/8157251/webrev.00/
Thanks,
Priya
Attila Szegedi
2018-01-10 17:39:13 UTC
Permalink
Post by Hannes Wallnöfer
Priya,
The problem with your solution that using an object array invocation with a primitive array will throw a ClassCastException as it passes the isArray guard.
On the other hand, the problem with instanceof validation in Attila’s snippet is that it uses the concrete callsite type (e.g. String[]) instead of Object[]. What we’d need is a guard with an instanceof Object[] check.
Yeah, my solution wasn’t complete by any means, it just wanted to be a pointer in the right direction. Priya’s change to use IS_ARRAY *almost* worked, except for, as you noticed, primitive arrays.

FWIW, since IS_ARRAY isn’t actually used for anything else (the JIRA ticket allures to it getting retired), we could replace it with a new IS_REFERENCE_ARRAY ValidationType (that basically describes an instanceof Object[] check) and then Priya and mine combined solution below would work with it. The only other place where a new ValidationType needs to be handled is in AbstractJavaLinker.getGuard and GuardedInvocationComponent.Validator.compose. Those would need some more adjustments (basically, replacing every "validatorClass.isArray()” expression with “Object[].class.isAssignableFrom(validatorClass)”.)

Of course, then on another look it seems to me that length properties for collections and maps will *also* have stricter linkage than necessary, since INSTANCE_OF validation type will always link an instanceof check for the linked class, and these properties could also have more lenient linkage, like how element getters and setters are stably linked for lists and maps in general. So I guess we might need to add an IS_COLLECTION and IS_MAP ValidationType too to use for these length getters :-)

It’s not a big deal adding validation types, they’re just encapsulations of guard logic that also know how to compose (they need to compose in unnamed getter linking logic… welcome to the nontrivial world of bean linking :-) ). It might be tempting to just override getPropertyGetter() instead and add special code for linking “length”, and that’d _mostly_ work; one advantage of using setPropertyGetter() is that those properties defined with setPropertyGetter() will be automatically found by call sites with unnamed access, e.g. Nashorn pseudocode:

var propName = (function() { return “length” })()
arr[propName]
Post by Hannes Wallnöfer
However, I don’t think a callsite for array length will usually see so many different array classes to go megamorphic, so I think both your solutions (Priya’s webrev and Attila’s code snippet) are acceptable.
Yeah, I’m also fine with whichever solution. Committing the reversal to Array.getLength is fine too with me.

It might be a nice exercise though to add IS_REFERENCE_ARRAY, IS_COLLECTION, and IS_MAP ValidationTypes, and define the length getters for arrays, collections, and maps using them, with requisite adjustments to both AbstractJavaLinker.getGuard and GuardedInvocationComponent.Validator.compose.

Attila.
Post by Hannes Wallnöfer
Hannes
Post by Priya Lakshmi Muthuswamy
Hi Attila,
Thanks for the review. I just felt in the case of primitive types there will be relinking.
I tried with the below fix.
In the case object types, I see relinking when we use Validation.INSTANCE_OF. But works fine without relinking when we use Validation.IS_ARRAY
if(clazz.isArray()) {
// Some languages won't have a notion of manipulating collections. Exposing "length" on arrays as an // explicit property is beneficial for them. if (clazz.getComponentType().isPrimitive()) {
setPropertyGetter("length", MethodHandles.arrayLength(clazz), ValidationType.EXACT_CLASS);
}else {
setPropertyGetter("length", MethodHandles.arrayLength(Object[].class), ValidationType.IS_ARRAY);
}
Thanks,
Priya
Post by Attila Szegedi
This effectively reverts the combined <https://bugs.openjdk.java.net/browse/JDK-8157225> and <https://bugs.openjdk.java.net/browse/JDK-8157250>.
That was not the intent of 8157251, though.
The intent of 8157251 was to use MethodHandles.arrayLength(Object[].class) for all arrays with components of reference type (and use ValidationType.INSTANCE_OF for it, as all such arrays will be instance-of Object[] through instance-of semantics for array types) and leave the linking of arrays with primitive component types as they are today.
if(clazz.isArray()) {
// Some languages won't have a notion of manipulating collections. Exposing "length" on arrays as an
// explicit property is beneficial for them.
if (clazz.getComponentType().isPrimitive()) {
setPropertyGetter("length", MethodHandles.arrayLength(clazz), ValidationType.EXACT_CLASS);
} else {
setPropertyGetter("length", MethodHandles.arrayLength(Object[].class), ValidationType.INSTANCE_OF);
}
Obviously, this is again a tradeoff between linkage stability and performance, except that with this solution we don’t sacrifice any performance and we still increase linkage stability. Going back to Array.getLength does further increase linkage stability, but *speculatively* it doesn’t intrinsify to as lean code as MethodHandles.arrayLength does (it certainly erases the type information of the argument); someone with time on their hands should probably run some PrintAssembly tests with -XX:-TieredCompilation to see whether this is true (if not, then 8157225 and 8157250 were done for nothing and this patch undoes them anyway).
In any case, I don’t have a too strong opinion about this; I don’t mind even if this ends up being a reversal of 8157225; it’s just weird that we have arrayLength method handle intrinsics and not use them.
Attila.
Hi,
Please review JDK-8157251 : BeanLinker relinks array length operations for array types
JBS : https://bugs.openjdk.java.net/browse/JDK-8157251
webrev : http://cr.openjdk.java.net/~pmuthuswamy/8157251/webrev.00/
Thanks,
Priya
Loading...