@@ -1409,7 +1409,7 @@ private List<Method> cacheDeclaredPublicMethods(List<Method> methods, CacheKey c
1409
1409
methods .set (i , methodPut );
1410
1410
}
1411
1411
}
1412
- cache .insert (cacheKey , methods );
1412
+ cache .insertRoot (cacheKey , methods );
1413
1413
} finally {
1414
1414
if (cache != null ) {
1415
1415
cache .release ();
@@ -4549,32 +4549,38 @@ private String getParameterTypesSignature(boolean throwException, String name, C
4549
4549
return signature .toString ();
4550
4550
}
4551
4551
4552
+ /*[IF JAVA_SPEC_VERSION <= 11] */
4553
+ private static Method getRootMethod ;
4552
4554
/*[IF JAVA_SPEC_VERSION == 8]*/
4553
4555
/*[PR CMVC 114820, CMVC 115873, CMVC 116166] add reflection cache */
4554
4556
private static Method copyMethod , copyField , copyConstructor ;
4557
+ private static Field rootField ;
4555
4558
private static Field methodParameterTypesField ;
4556
4559
private static Field constructorParameterTypesField ;
4557
- private static final Object [] NoArgs = new Object [0 ];
4558
4560
/*[ENDIF] JAVA_SPEC_VERSION == 8 */
4561
+ private static final Object [] NoArgs = new Object [0 ];
4562
+ /*[ENDIF] JAVA_SPEC_VERSION <= 11 */
4559
4563
4560
4564
/*[PR JAZZ 107786] constructorParameterTypesField should be initialized regardless of reflectCacheEnabled or not */
4561
4565
static void initCacheIds (boolean cacheEnabled , boolean cacheDebug ) {
4562
4566
reflectCacheEnabled = cacheEnabled ;
4563
4567
reflectCacheDebug = cacheDebug ;
4564
- /*[IF JAVA_SPEC_VERSION == 8 ]*/
4568
+ /*[IF JAVA_SPEC_VERSION <= 11 ]*/
4565
4569
AccessController .doPrivileged (new PrivilegedAction <Void >() {
4566
4570
@ Override
4567
4571
public Void run () {
4568
4572
doInitCacheIds ();
4569
4573
return null ;
4570
4574
}
4571
4575
});
4572
- /*[ENDIF] JAVA_SPEC_VERSION == 8 */
4576
+ /*[ENDIF] JAVA_SPEC_VERSION <= 11 */
4573
4577
}
4578
+
4574
4579
static void setReflectCacheAppOnly (boolean cacheAppOnly ) {
4575
4580
reflectCacheAppOnly = cacheAppOnly ;
4576
4581
}
4577
- /*[IF JAVA_SPEC_VERSION == 8]*/
4582
+
4583
+ /*[IF JAVA_SPEC_VERSION <= 11]*/
4578
4584
@ SuppressWarnings ("nls" )
4579
4585
static void doInitCacheIds () {
4580
4586
/*
@@ -4585,6 +4591,7 @@ static void doInitCacheIds() {
4585
4591
* not done (we're in the process of initializing the caching mechanisms).
4586
4592
* We must ensure the classes that own the fields of interest are prepared.
4587
4593
*/
4594
+ /*[IF JAVA_SPEC_VERSION == 8]*/
4588
4595
J9VMInternals .prepare (Constructor .class );
4589
4596
J9VMInternals .prepare (Method .class );
4590
4597
try {
@@ -4596,12 +4603,28 @@ static void doInitCacheIds() {
4596
4603
constructorParameterTypesField .setAccessible (true );
4597
4604
methodParameterTypesField .setAccessible (true );
4598
4605
if (reflectCacheEnabled ) {
4606
+ J9VMInternals .prepare (Executable .class );
4607
+ J9VMInternals .prepare (Field .class );
4599
4608
copyConstructor = getAccessibleMethod (Constructor .class , "copy" );
4600
4609
copyMethod = getAccessibleMethod (Method .class , "copy" );
4601
4610
copyField = getAccessibleMethod (Field .class , "copy" );
4611
+ getRootMethod = getAccessibleMethod (Executable .class , "getRoot" );
4612
+ try {
4613
+ rootField = Field .class .getDeclaredFieldImpl ("root" );
4614
+ } catch (NoSuchFieldException e ) {
4615
+ throw newInternalError (e );
4616
+ }
4617
+ rootField .setAccessible (true );
4602
4618
}
4619
+ /*[ELSE] JAVA_SPEC_VERSION == 8 */
4620
+ J9VMInternals .prepare (AccessibleObject .class );
4621
+ if (reflectCacheEnabled ) {
4622
+ getRootMethod = getAccessibleMethod (AccessibleObject .class , "getRoot" );
4623
+ }
4624
+ /*[ENDIF] JAVA_SPEC_VERSION == 8 */
4603
4625
}
4604
- /*[ENDIF] JAVA_SPEC_VERSION == 8 */
4626
+ /*[ENDIF] JAVA_SPEC_VERSION <= 11 */
4627
+
4605
4628
private static Method getAccessibleMethod (Class <?> cls , String name ) {
4606
4629
try {
4607
4630
Method method = cls .getDeclaredMethod (name , EmptyParameters );
@@ -4974,16 +4997,24 @@ Object find(CacheKey key) {
4974
4997
return ref != null ? ref .get () : null ;
4975
4998
}
4976
4999
4977
- void insert (CacheKey key , Object value ) {
5000
+ void insert (CacheKey key , AccessibleObject value ) {
5001
+ insertRoot (key , retrieveRoot (value ));
5002
+ }
5003
+
5004
+ /*
5005
+ * This method must only be called with known roots or aggregates of roots.
5006
+ */
5007
+ void insertRoot (CacheKey key , Object value ) {
4978
5008
put (key , new ReflectRef (this , key , value ));
4979
5009
}
4980
5010
4981
- <T > T insertIfAbsent (CacheKey key , T value ) {
4982
- ReflectRef newRef = new ReflectRef (this , key , value );
5011
+ <T extends AccessibleObject > T insertIfAbsent (CacheKey key , T value ) {
5012
+ T rootValue = retrieveRoot (value );
5013
+ ReflectRef newRef = new ReflectRef (this , key , rootValue );
4983
5014
for (;;) {
4984
5015
ReflectRef oldRef = putIfAbsent (key , newRef );
4985
5016
if (oldRef == null ) {
4986
- return value ;
5017
+ return rootValue ;
4987
5018
}
4988
5019
T oldValue = (T ) oldRef .get ();
4989
5020
if (oldValue != null ) {
@@ -4992,11 +5023,23 @@ <T> T insertIfAbsent(CacheKey key, T value) {
4992
5023
// The entry addressed by key has been cleared, but not yet removed from this map.
4993
5024
// One thread will successfully replace the entry; the value stored will be shared.
4994
5025
if (replace (key , oldRef , newRef )) {
4995
- return value ;
5026
+ return rootValue ;
4996
5027
}
4997
5028
}
4998
5029
}
4999
5030
5031
+ private static <T extends AccessibleObject > T retrieveRoot (T value ) {
5032
+ T root = getRoot (value );
5033
+ if (root != null ) {
5034
+ if (reflectCacheDebug ) {
5035
+ System .err .println ("extracted root from non-root accessible object before caching: " + value );
5036
+ }
5037
+ return root ;
5038
+ } else {
5039
+ return value ;
5040
+ }
5041
+ }
5042
+
5000
5043
void release () {
5001
5044
useCount .decrementAndGet ();
5002
5045
}
@@ -5120,7 +5163,7 @@ private Method cacheMethod(Method method) {
5120
5163
try {
5121
5164
// cache the Method with the largest depth with a null returnType
5122
5165
CacheKey lookupKey = CacheKey .newMethodKey (method .getName (), parameterTypes , null );
5123
- cache .insert (lookupKey , method );
5166
+ cache .insertRoot (lookupKey , method );
5124
5167
} finally {
5125
5168
cache .release ();
5126
5169
}
@@ -5188,7 +5231,7 @@ private Field cacheField(Field field) {
5188
5231
if (declaringClass == this ) {
5189
5232
// cache the Field returned from getField() with a null returnType
5190
5233
CacheKey lookupKey = CacheKey .newFieldKey (field .getName (), null );
5191
- cache .insert (lookupKey , field );
5234
+ cache .insertRoot (lookupKey , field );
5192
5235
}
5193
5236
} finally {
5194
5237
cache .release ();
@@ -5349,7 +5392,7 @@ private Method[] cacheMethods(Method[] methods, CacheKey cacheKey) {
5349
5392
if (cache == null ) {
5350
5393
cache = acquireReflectCache ();
5351
5394
}
5352
- cache .insert (cacheKey , methods );
5395
+ cache .insertRoot (cacheKey , methods );
5353
5396
} finally {
5354
5397
if (cache != null ) {
5355
5398
cache .release ();
@@ -5433,7 +5476,7 @@ private Field[] cacheFields(Field[] fields, CacheKey cacheKey) {
5433
5476
if (cache == null ) {
5434
5477
cache = acquireReflectCache ();
5435
5478
}
5436
- cache .insert (cacheKey , fields );
5479
+ cache .insertRoot (cacheKey , fields );
5437
5480
} finally {
5438
5481
if (cache != null ) {
5439
5482
cache .release ();
@@ -5499,7 +5542,7 @@ private Constructor<T>[] cacheConstructors(Constructor<T>[] constructors, CacheK
5499
5542
CacheKey key = CacheKey .newConstructorKey (getParameterTypes (constructors [i ]));
5500
5543
constructors [i ] = cache .insertIfAbsent (key , constructors [i ]);
5501
5544
}
5502
- cache .insert (cacheKey , constructors );
5545
+ cache .insertRoot (cacheKey , constructors );
5503
5546
} finally {
5504
5547
cache .release ();
5505
5548
}
@@ -5548,6 +5591,30 @@ Object setMethodHandleCache(Object cache) {
5548
5591
return result ;
5549
5592
}
5550
5593
5594
+ static <T extends AccessibleObject > T getRoot (T object ) {
5595
+ /*[IF JAVA_SPEC_VERSION >= 17]*/
5596
+ return SharedSecrets .getJavaLangReflectAccess ().getRoot (object );
5597
+ /*[ELSEIF JAVA_SPEC_VERSION >= 11] */
5598
+ try {
5599
+ return (T ) getRootMethod .invoke (object , NoArgs );
5600
+ } catch (IllegalAccessException | InvocationTargetException e ) {
5601
+ throw newInternalError (e );
5602
+ }
5603
+ /*[ELSE] JAVA_SPEC_VERSION >= 11 */
5604
+ try {
5605
+ if (object instanceof Executable ) {
5606
+ return (T ) getRootMethod .invoke (object , NoArgs );
5607
+ } else if (object instanceof Field ) {
5608
+ return (T ) rootField .get (object );
5609
+ } else {
5610
+ throw newInternalError (new IllegalArgumentException ("Unexpected AccessibleObject subclass: " + object .getClass ().getSimpleName ()));
5611
+ }
5612
+ } catch (IllegalAccessException | InvocationTargetException e ) {
5613
+ throw newInternalError (e );
5614
+ }
5615
+ /*[ENDIF] JAVA_SPEC_VERSION >= 17 */
5616
+ }
5617
+
5551
5618
ConstantPool getConstantPool () {
5552
5619
return SharedSecrets .getJavaLangAccess ().getConstantPool (this );
5553
5620
}
0 commit comments