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