1 /*
  2  * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package jdk.internal.reflect;
 27 
 28 import java.io.Externalizable;
 29 import java.io.ObjectInputStream;
 30 import java.io.ObjectOutputStream;
 31 import java.io.ObjectStreamClass;
 32 import java.io.OptionalDataException;
 33 import java.io.Serializable;
 34 import java.lang.invoke.MethodHandle;
 35 import java.lang.invoke.MethodHandles;
 36 import java.lang.reflect.Constructor;
 37 import java.lang.reflect.Executable;
 38 import java.lang.reflect.Field;
 39 import java.lang.reflect.InvocationTargetException;
 40 import java.lang.reflect.Method;
 41 import java.lang.reflect.Modifier;
 42 import java.security.PrivilegedAction;
 43 import java.util.Properties;
 44 import jdk.internal.access.JavaLangReflectAccess;
 45 import jdk.internal.access.SharedSecrets;
 46 import jdk.internal.misc.VM;
 47 import jdk.internal.vm.annotation.Stable;
 48 import sun.security.action.GetPropertyAction;
 49 import sun.security.util.SecurityConstants;
 50 
 51 /** <P> The master factory for all reflective objects, both those in
 52     java.lang.reflect (Fields, Methods, Constructors) as well as their
 53     delegates (FieldAccessors, MethodAccessors, ConstructorAccessors).
 54     </P>
 55 
 56     <P> The methods in this class are extremely unsafe and can cause
 57     subversion of both the language and the verifier. For this reason,
 58     they are all instance methods, and access to the constructor of
 59     this factory is guarded by a security check, in similar style to
 60     {@link jdk.internal.misc.Unsafe}. </P>
 61 */
 62 
 63 public class ReflectionFactory {
 64 
 65     private static final ReflectionFactory soleInstance = new ReflectionFactory();
 66 
 67 
 68     /* Method for static class initializer <clinit>, or null */
 69     private static volatile Method hasStaticInitializerMethod;
 70 
 71     private final JavaLangReflectAccess langReflectAccess;
 72     private ReflectionFactory() {
 73         this.langReflectAccess = SharedSecrets.getJavaLangReflectAccess();
 74     }
 75 
 76     /**
 77      * A convenience class for acquiring the capability to instantiate
 78      * reflective objects.  Use this instead of a raw call to {@link
 79      * #getReflectionFactory} in order to avoid being limited by the
 80      * permissions of your callers.
 81      *
 82      * <p>An instance of this class can be used as the argument of
 83      * <code>AccessController.doPrivileged</code>.
 84      */
 85     public static final class GetReflectionFactoryAction
 86         implements PrivilegedAction<ReflectionFactory> {
 87         public ReflectionFactory run() {
 88             return getReflectionFactory();
 89         }
 90     }
 91 
 92     /**
 93      * Provides the caller with the capability to instantiate reflective
 94      * objects.
 95      *
 96      * <p> First, if there is a security manager, its
 97      * <code>checkPermission</code> method is called with a {@link
 98      * java.lang.RuntimePermission} with target
 99      * <code>"reflectionFactoryAccess"</code>.  This may result in a
100      * security exception.
101      *
102      * <p> The returned <code>ReflectionFactory</code> object should be
103      * carefully guarded by the caller, since it can be used to read and
104      * write private data and invoke private methods, as well as to load
105      * unverified bytecodes.  It must never be passed to untrusted code.
106      *
107      * @exception SecurityException if a security manager exists and its
108      *             <code>checkPermission</code> method doesn't allow
109      *             access to the RuntimePermission "reflectionFactoryAccess".  */
110     public static ReflectionFactory getReflectionFactory() {
111         @SuppressWarnings("removal")
112         SecurityManager security = System.getSecurityManager();
113         if (security != null) {
114             security.checkPermission(
115                 SecurityConstants.REFLECTION_FACTORY_ACCESS_PERMISSION);
116         }
117         return soleInstance;
118     }
119 
120     //--------------------------------------------------------------------------
121     //
122     // Routines used by java.lang.reflect
123     //
124     //
125 
126     /*
127      * Note: this routine can cause the declaring class for the field
128      * be initialized and therefore must not be called until the
129      * first get/set of this field.
130      * @param field the field
131      * @param override true if caller has overridden accessibility
132      */
133     public FieldAccessor newFieldAccessor(Field field, boolean override) {
134         Field root = langReflectAccess.getRoot(field);
135         if (root != null) {
136             // FieldAccessor will use the root unless the modifiers have
137             // been overridden
138             if (root.getModifiers() == field.getModifiers() || !override) {
139                 field = root;
140             }
141         }
142         boolean isFinal = Modifier.isFinal(field.getModifiers());
143         boolean isReadOnly = isFinal && (!override || langReflectAccess.isTrustedFinalField(field));
144         if (useFieldHandleAccessor()) {
145             return MethodHandleAccessorFactory.newFieldAccessor(field, isReadOnly);
146         } else {
147             return UnsafeFieldAccessorFactory.newFieldAccessor(field, isReadOnly);
148         }
149     }
150 
151     public MethodAccessor newMethodAccessor(Method method, boolean callerSensitive) {
152         // use the root Method that will not cache caller class
153         Method root = langReflectAccess.getRoot(method);
154         if (root != null) {
155             method = root;
156         }
157 
158         if (useMethodHandleAccessor()) {
159             return MethodHandleAccessorFactory.newMethodAccessor(method, callerSensitive);
160         } else {
161             if (noInflation() && !method.getDeclaringClass().isHidden()) {
162                 return generateMethodAccessor(method);
163             } else {
164                 NativeMethodAccessorImpl acc = new NativeMethodAccessorImpl(method);
165                 return acc.getParent();
166             }
167         }
168     }
169 
170     /**
171      * Generate the MethodAccessor that invokes the given method with
172      * bytecode invocation.
173      */
174     static MethodAccessorImpl generateMethodAccessor(Method method) {
175         return (MethodAccessorImpl)new MethodAccessorGenerator()
176                 .generateMethod(method.getDeclaringClass(),
177                                 method.getName(),
178                                 method.getParameterTypes(),
179                                 method.getReturnType(),
180                                 method.getExceptionTypes(),
181                                 method.getModifiers());
182     }
183 
184     public ConstructorAccessor newConstructorAccessor(Constructor<?> c) {
185         Class<?> declaringClass = c.getDeclaringClass();
186         if (Modifier.isAbstract(declaringClass.getModifiers())) {
187             return new InstantiationExceptionConstructorAccessorImpl(null);
188         }
189         if (declaringClass == Class.class) {
190             return new InstantiationExceptionConstructorAccessorImpl
191                 ("Can not instantiate java.lang.Class");
192         }
193 
194         // use the root Constructor that will not cache caller class
195         Constructor<?> root = langReflectAccess.getRoot(c);
196         if (root != null) {
197             c = root;
198         }
199 
200         if (useMethodHandleAccessor()) {
201             return MethodHandleAccessorFactory.newConstructorAccessor(c);
202         } else {
203             // Bootstrapping issue: since we use Class.newInstance() in
204             // the ConstructorAccessor generation process, we have to
205             // break the cycle here.
206             if (Reflection.isSubclassOf(declaringClass, ConstructorAccessorImpl.class)) {
207                 return new BootstrapConstructorAccessorImpl(c);
208             }
209 
210             if (noInflation() && !c.getDeclaringClass().isHidden()) {
211                 return new MethodAccessorGenerator().
212                         generateConstructor(c.getDeclaringClass(),
213                                             c.getParameterTypes(),
214                                             c.getExceptionTypes(),
215                                             c.getModifiers());
216             } else {
217                 NativeConstructorAccessorImpl acc = new NativeConstructorAccessorImpl(c);
218                 return acc.getParent();
219             }
220         }
221     }
222 
223     //--------------------------------------------------------------------------
224     //
225     // Routines used by java.lang
226     //
227     //
228 
229     /** Creates a new java.lang.reflect.Constructor. Access checks as
230         per java.lang.reflect.AccessibleObject are not overridden. */
231     public Constructor<?> newConstructor(Class<?> declaringClass,
232                                          Class<?>[] parameterTypes,
233                                          Class<?>[] checkedExceptions,
234                                          int modifiers,
235                                          int slot,
236                                          String signature,
237                                          byte[] annotations,
238                                          byte[] parameterAnnotations)
239     {
240         return langReflectAccess.newConstructor(declaringClass,
241                                                 parameterTypes,
242                                                 checkedExceptions,
243                                                 modifiers,
244                                                 slot,
245                                                 signature,
246                                                 annotations,
247                                                 parameterAnnotations);
248     }
249 
250     /** Gets the ConstructorAccessor object for a
251         java.lang.reflect.Constructor */
252     public ConstructorAccessor getConstructorAccessor(Constructor<?> c) {
253         return langReflectAccess.getConstructorAccessor(c);
254     }
255 
256     /** Sets the ConstructorAccessor object for a
257         java.lang.reflect.Constructor */
258     public void setConstructorAccessor(Constructor<?> c,
259                                        ConstructorAccessor accessor)
260     {
261         langReflectAccess.setConstructorAccessor(c, accessor);
262     }
263 
264     /** Makes a copy of the passed method. The returned method is a
265         "child" of the passed one; see the comments in Method.java for
266         details. */
267     public Method copyMethod(Method arg) {
268         return langReflectAccess.copyMethod(arg);
269     }
270 
271     /** Makes a copy of the passed method. The returned method is NOT
272      * a "child" but a "sibling" of the Method in arg. Should only be
273      * used on non-root methods. */
274     public Method leafCopyMethod(Method arg) {
275         return langReflectAccess.leafCopyMethod(arg);
276     }
277 
278 
279     /** Makes a copy of the passed field. The returned field is a
280         "child" of the passed one; see the comments in Field.java for
281         details. */
282     public Field copyField(Field arg) {
283         return langReflectAccess.copyField(arg);
284     }
285 
286     /** Makes a copy of the passed constructor. The returned
287         constructor is a "child" of the passed one; see the comments
288         in Constructor.java for details. */
289     public <T> Constructor<T> copyConstructor(Constructor<T> arg) {
290         return langReflectAccess.copyConstructor(arg);
291     }
292 
293     /** Gets the byte[] that encodes TypeAnnotations on an executable.
294      */
295     public byte[] getExecutableTypeAnnotationBytes(Executable ex) {
296         return langReflectAccess.getExecutableTypeAnnotationBytes(ex);
297     }
298 
299     public Class<?>[] getExecutableSharedParameterTypes(Executable ex) {
300         return langReflectAccess.getExecutableSharedParameterTypes(ex);
301     }
302 
303     public <T> T newInstance(Constructor<T> ctor, Object[] args, Class<?> caller)
304         throws IllegalAccessException, InstantiationException, InvocationTargetException
305     {
306         return langReflectAccess.newInstance(ctor, args, caller);
307     }
308 
309     //--------------------------------------------------------------------------
310     //
311     // Routines used by serialization
312     //
313     //
314 
315     public final Constructor<?> newConstructorForExternalization(Class<?> cl) {
316         if (!Externalizable.class.isAssignableFrom(cl)) {
317             return null;
318         }
319         try {
320             Constructor<?> cons = cl.getConstructor();
321             cons.setAccessible(true);
322             return cons;
323         } catch (NoSuchMethodException ex) {
324             return null;
325         }
326     }
327 
328     public final Constructor<?> newConstructorForSerialization(Class<?> cl,
329                                                                Constructor<?> constructorToCall)
330     {
331         if (constructorToCall.getDeclaringClass() == cl) {
332             constructorToCall.setAccessible(true);
333             return constructorToCall;
334         }
335         return generateConstructor(cl, constructorToCall);
336     }
337 
338     /**
339      * Given a class, determines whether its superclass has
340      * any constructors that are accessible from the class.
341      * This is a special purpose method intended to do access
342      * checking for a serializable class and its superclasses
343      * up to, but not including, the first non-serializable
344      * superclass. This also implies that the superclass is
345      * always non-null, because a serializable class must be a
346      * class (not an interface) and Object is not serializable.
347      *
348      * @param cl the class from which access is checked
349      * @return whether the superclass has a constructor accessible from cl
350      */
351     private boolean superHasAccessibleConstructor(Class<?> cl) {
352         Class<?> superCl = cl.getSuperclass();
353         assert Serializable.class.isAssignableFrom(cl);
354         assert superCl != null;
355         if (packageEquals(cl, superCl)) {
356             // accessible if any non-private constructor is found
357             for (Constructor<?> ctor : superCl.getDeclaredConstructors()) {
358                 if ((ctor.getModifiers() & Modifier.PRIVATE) == 0) {
359                     return true;
360                 }
361             }
362             if (Reflection.areNestMates(cl, superCl)) {
363                 return true;
364             }
365             return false;
366         } else {
367             // sanity check to ensure the parent is protected or public
368             if ((superCl.getModifiers() & (Modifier.PROTECTED | Modifier.PUBLIC)) == 0) {
369                 return false;
370             }
371             // accessible if any constructor is protected or public
372             for (Constructor<?> ctor : superCl.getDeclaredConstructors()) {
373                 if ((ctor.getModifiers() & (Modifier.PROTECTED | Modifier.PUBLIC)) != 0) {
374                     return true;
375                 }
376             }
377             return false;
378         }
379     }
380 
381     /**
382      * Returns a constructor that allocates an instance of cl and that then initializes
383      * the instance by calling the no-arg constructor of its first non-serializable
384      * superclass. This is specified in the Serialization Specification, section 3.1,
385      * in step 11 of the deserialization process. If cl is not serializable, returns
386      * cl's no-arg constructor. If no accessible constructor is found, or if the
387      * class hierarchy is somehow malformed (e.g., a serializable class has no
388      * superclass), null is returned.
389      *
390      * @param cl the class for which a constructor is to be found
391      * @return the generated constructor, or null if none is available
392      */
393     public final Constructor<?> newConstructorForSerialization(Class<?> cl) {
394         Class<?> initCl = cl;
395         while (Serializable.class.isAssignableFrom(initCl)) {
396             Class<?> prev = initCl;
397             if ((initCl = initCl.getSuperclass()) == null ||
398                 (!disableSerialConstructorChecks() && !superHasAccessibleConstructor(prev))) {
399                 return null;
400             }
401         }
402         Constructor<?> constructorToCall;
403         try {
404             constructorToCall = initCl.getDeclaredConstructor();
405             int mods = constructorToCall.getModifiers();
406             if ((mods & Modifier.PRIVATE) != 0 ||
407                     ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 &&
408                             !packageEquals(cl, initCl))) {
409                 return null;
410             }
411         } catch (NoSuchMethodException ex) {
412             return null;
413         }
414         return generateConstructor(cl, constructorToCall);
415     }
416 
417     private final Constructor<?> generateConstructor(Class<?> cl,
418                                                      Constructor<?> constructorToCall) {
419 
420 
421         ConstructorAccessor acc = new MethodAccessorGenerator().
422             generateSerializationConstructor(cl,
423                                              constructorToCall.getParameterTypes(),
424                                              constructorToCall.getExceptionTypes(),
425                                              constructorToCall.getModifiers(),
426                                              constructorToCall.getDeclaringClass());
427         Constructor<?> c = newConstructor(constructorToCall.getDeclaringClass(),
428                                           constructorToCall.getParameterTypes(),
429                                           constructorToCall.getExceptionTypes(),
430                                           constructorToCall.getModifiers(),
431                                           langReflectAccess.
432                                           getConstructorSlot(constructorToCall),
433                                           langReflectAccess.
434                                           getConstructorSignature(constructorToCall),
435                                           langReflectAccess.
436                                           getConstructorAnnotations(constructorToCall),
437                                           langReflectAccess.
438                                           getConstructorParameterAnnotations(constructorToCall));
439         setConstructorAccessor(c, acc);
440         c.setAccessible(true);
441         return c;
442     }
443 
444     public final MethodHandle readObjectForSerialization(Class<?> cl) {
445         return findReadWriteObjectForSerialization(cl, "readObject", ObjectInputStream.class);
446     }
447 
448     public final MethodHandle readObjectNoDataForSerialization(Class<?> cl) {
449         return findReadWriteObjectForSerialization(cl, "readObjectNoData", null);
450     }
451 
452     public final MethodHandle writeObjectForSerialization(Class<?> cl) {
453         return findReadWriteObjectForSerialization(cl, "writeObject", ObjectOutputStream.class);
454     }
455 
456     private final MethodHandle findReadWriteObjectForSerialization(Class<?> cl,
457                                                                    String methodName,
458                                                                    Class<?> streamClass) {
459         if (!Serializable.class.isAssignableFrom(cl)) {
460             return null;
461         }
462 
463         try {
464             Method meth = streamClass == null ? cl.getDeclaredMethod(methodName)
465                     : cl.getDeclaredMethod(methodName, streamClass);
466             int mods = meth.getModifiers();
467             if (meth.getReturnType() != Void.TYPE ||
468                     Modifier.isStatic(mods) ||
469                     !Modifier.isPrivate(mods)) {
470                 return null;
471             }
472             meth.setAccessible(true);
473             return MethodHandles.lookup().unreflect(meth);
474         } catch (NoSuchMethodException ex) {
475             return null;
476         } catch (IllegalAccessException ex1) {
477             throw new InternalError("Error", ex1);
478         }
479     }
480 
481     /**
482      * Returns a MethodHandle for {@code writeReplace} on the serializable class
483      * or null if no match found.
484      * @param cl a serializable class
485      * @returnss the {@code writeReplace} MethodHandle or {@code null} if not found
486      */
487     public final MethodHandle writeReplaceForSerialization(Class<?> cl) {
488         return getReplaceResolveForSerialization(cl, "writeReplace");
489     }
490 
491     /**
492      * Returns a MethodHandle for {@code readResolve} on the serializable class
493      * or null if no match found.
494      * @param cl a serializable class
495      * @returns the {@code writeReplace} MethodHandle or {@code null} if not found
496      */
497     public final MethodHandle readResolveForSerialization(Class<?> cl) {
498         return getReplaceResolveForSerialization(cl, "readResolve");
499     }
500 
501     /**
502      * Lookup readResolve or writeReplace on a class with specified
503      * signature constraints.
504      * @param cl a serializable class
505      * @param methodName the method name to find
506      * @returns a MethodHandle for the method or {@code null} if not found or
507      *       has the wrong signature.
508      */
509     private MethodHandle getReplaceResolveForSerialization(Class<?> cl,
510                                                            String methodName) {
511         if (!Serializable.class.isAssignableFrom(cl)) {
512             return null;
513         }
514 
515         Class<?> defCl = cl;
516         while (defCl != null) {
517             try {
518                 Method m = defCl.getDeclaredMethod(methodName);
519                 if (m.getReturnType() != Object.class) {
520                     return null;
521                 }
522                 int mods = m.getModifiers();
523                 if (Modifier.isStatic(mods) | Modifier.isAbstract(mods)) {
524                     return null;
525                 } else if (Modifier.isPublic(mods) | Modifier.isProtected(mods)) {
526                     // fall through
527                 } else if (Modifier.isPrivate(mods) && (cl != defCl)) {
528                     return null;
529                 } else if (!packageEquals(cl, defCl)) {
530                     return null;
531                 }
532                 try {
533                     // Normal return
534                     m.setAccessible(true);
535                     return MethodHandles.lookup().unreflect(m);
536                 } catch (IllegalAccessException ex0) {
537                     // setAccessible should prevent IAE
538                     throw new InternalError("Error", ex0);
539                 }
540             } catch (NoSuchMethodException ex) {
541                 defCl = defCl.getSuperclass();
542             }
543         }
544         return null;
545     }
546 
547     /**
548      * Returns true if the given class defines a static initializer method,
549      * false otherwise.
550      */
551     public final boolean hasStaticInitializerForSerialization(Class<?> cl) {
552         Method m = hasStaticInitializerMethod;
553         if (m == null) {
554             try {
555                 m = ObjectStreamClass.class.getDeclaredMethod("hasStaticInitializer",
556                         new Class<?>[]{Class.class});
557                 m.setAccessible(true);
558                 hasStaticInitializerMethod = m;
559             } catch (NoSuchMethodException ex) {
560                 throw new InternalError("No such method hasStaticInitializer on "
561                         + ObjectStreamClass.class, ex);
562             }
563         }
564         try {
565             return (Boolean) m.invoke(null, cl);
566         } catch (InvocationTargetException | IllegalAccessException ex) {
567             throw new InternalError("Exception invoking hasStaticInitializer", ex);
568         }
569     }
570 
571     /**
572      * Return the accessible constructor for OptionalDataException signaling eof.
573      * @returns the eof constructor for OptionalDataException
574      */
575     public final Constructor<OptionalDataException> newOptionalDataExceptionForSerialization() {
576         try {
577             Constructor<OptionalDataException> boolCtor =
578                     OptionalDataException.class.getDeclaredConstructor(Boolean.TYPE);
579             boolCtor.setAccessible(true);
580             return boolCtor;
581         } catch (NoSuchMethodException ex) {
582             throw new InternalError("Constructor not found", ex);
583         }
584     }
585 
586     //--------------------------------------------------------------------------
587     //
588     // Internals only below this point
589     //
590 
591     // Package-private to be accessible to NativeMethodAccessorImpl
592     // and NativeConstructorAccessorImpl
593     static int inflationThreshold() {
594         return config().inflationThreshold;
595     }
596 
597     static boolean noInflation() {
598         return config().noInflation;
599     }
600 
601     static boolean useMethodHandleAccessor() {
602         return (config().useDirectMethodHandle & METHOD_MH_ACCESSOR) == METHOD_MH_ACCESSOR;
603     }
604 
605     static boolean useFieldHandleAccessor() {
606         return (config().useDirectMethodHandle & FIELD_MH_ACCESSOR) == FIELD_MH_ACCESSOR;
607     }
608 
609     static boolean useNativeAccessorOnly() {
610         return config().useNativeAccessorOnly;
611     }
612 
613     private static boolean disableSerialConstructorChecks() {
614         return config().disableSerialConstructorChecks;
615     }
616 
617     // New implementation uses direct invocation of method handles
618     private static final int METHOD_MH_ACCESSOR = 0x1;
619     private static final int FIELD_MH_ACCESSOR = 0x2;
620     private static final int ALL_MH_ACCESSORS = METHOD_MH_ACCESSOR | FIELD_MH_ACCESSOR;
621 
622     /**
623      * The configuration is lazily initialized after the module system is initialized. The
624      * default config would be used before the proper config is loaded.
625      *
626      * The static initializer of ReflectionFactory is run before the system properties are set up.
627      * The class initialization is caused by the class initialization of java.lang.reflect.Method
628      * (more properly, caused by the class initialization for java.lang.reflect.AccessibleObject)
629      * that happens very early VM startup, initPhase1.
630      */
631     private static @Stable Config config;
632 
633     // "Inflation" mechanism. Loading bytecodes to implement
634     // Method.invoke() and Constructor.newInstance() currently costs
635     // 3-4x more than an invocation via native code for the first
636     // invocation (though subsequent invocations have been benchmarked
637     // to be over 20x faster). Unfortunately this cost increases
638     // startup time for certain applications that use reflection
639     // intensively (but only once per class) to bootstrap themselves.
640     // To avoid this penalty we reuse the existing JVM entry points
641     // for the first few invocations of Methods and Constructors and
642     // then switch to the bytecode-based implementations.
643 
644     private static final Config DEFAULT_CONFIG = new Config(false, // noInflation
645                                                             15, // inflationThreshold
646                                                             ALL_MH_ACCESSORS, // useDirectMethodHandle
647                                                             false, // useNativeAccessorOnly
648                                                             false); // disableSerialConstructorChecks
649 
650     /**
651      * The configurations for the reflection factory. Configurable via
652      * system properties but only available after ReflectionFactory is
653      * loaded during early VM startup.
654      *
655      * Note that the default implementations of the object methods of
656      * this Config record (toString, equals, hashCode) use indy,
657      * which is available to use only after initPhase1. These methods
658      * are currently not called, but should they be needed, a workaround
659      * is to override them.
660      */
661     private record Config(boolean noInflation,
662                           int inflationThreshold,
663                           int useDirectMethodHandle,
664                           boolean useNativeAccessorOnly,
665                           boolean disableSerialConstructorChecks) {
666     }
667 
668     private static Config config() {
669         Config c = config;
670         if (c != null) {
671             return c;
672         }
673 
674         // Defer initialization until module system is initialized so as
675         // to avoid inflation and spinning bytecode in unnamed modules
676         // during early startup.
677         if (!VM.isModuleSystemInited()) {
678             return DEFAULT_CONFIG;
679         }
680 
681         return config = loadConfig();
682     }
683 
684     private static Config loadConfig() {
685         assert VM.isModuleSystemInited();
686 
687         boolean noInflation = DEFAULT_CONFIG.noInflation;
688         int inflationThreshold = DEFAULT_CONFIG.inflationThreshold;
689         int useDirectMethodHandle = DEFAULT_CONFIG.useDirectMethodHandle;
690         boolean useNativeAccessorOnly = DEFAULT_CONFIG.useNativeAccessorOnly;
691         boolean disableSerialConstructorChecks = DEFAULT_CONFIG.disableSerialConstructorChecks;
692 
693         Properties props = GetPropertyAction.privilegedGetProperties();
694         String val = props.getProperty("sun.reflect.noInflation");
695         if (val != null && val.equals("true")) {
696             noInflation = true;
697         }
698 
699         val = props.getProperty("sun.reflect.inflationThreshold");
700         if (val != null) {
701             try {
702                 inflationThreshold = Integer.parseInt(val);
703             } catch (NumberFormatException e) {
704                 throw new RuntimeException("Unable to parse property sun.reflect.inflationThreshold", e);
705             }
706         }
707         val = props.getProperty("jdk.reflect.useDirectMethodHandle");
708         if (val != null) {
709             if (val.equals("false")) {
710                 useDirectMethodHandle = 0;
711             } else if (val.equals("methods")) {
712                 useDirectMethodHandle = METHOD_MH_ACCESSOR;
713             } else if (val.equals("fields")) {
714                 useDirectMethodHandle = FIELD_MH_ACCESSOR;
715             }
716         }
717         val = props.getProperty("jdk.reflect.useNativeAccessorOnly");
718         if (val != null && val.equals("true")) {
719             useNativeAccessorOnly = true;
720         }
721 
722         disableSerialConstructorChecks =
723             "true".equals(props.getProperty("jdk.disableSerialConstructorChecks"));
724 
725         return new Config(noInflation,
726                           inflationThreshold,
727                           useDirectMethodHandle,
728                           useNativeAccessorOnly,
729                           disableSerialConstructorChecks);
730     }
731 
732     /**
733      * Returns true if classes are defined in the classloader and same package, false
734      * otherwise.
735      * @param cl1 a class
736      * @param cl2 another class
737      * @returns true if the two classes are in the same classloader and package
738      */
739     private static boolean packageEquals(Class<?> cl1, Class<?> cl2) {
740         assert !cl1.isArray() && !cl2.isArray();
741 
742         if (cl1 == cl2) {
743             return true;
744         }
745 
746         return cl1.getClassLoader() == cl2.getClassLoader() &&
747                 cl1.getPackageName() == cl2.getPackageName();
748     }
749 
750 }