1 /*
   2  * Copyright (c) 2020, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 package java.lang.invoke;
  25 
  26 import jdk.internal.loader.BuiltinClassLoader;
  27 import jdk.internal.misc.VM;
  28 
  29 final class LambdaProxyClassArchive {
  30     private static final boolean dumpArchive;
  31     private static final boolean sharingEnabled;
  32 
  33     static {
  34         dumpArchive = VM.isCDSDumpingEnabled();
  35         sharingEnabled = VM.isCDSSharingEnabled();
  36     }
  37 
  38     /**
  39      * Check if CDS dynamic dump is enabled.
  40      */
  41     static boolean isDumpArchive() {
  42         return dumpArchive;
  43     }
  44 
  45     /**
  46      * Check if CDS sharing is enabled.
  47      */
  48     static boolean isSharingEnabled() {
  49         return sharingEnabled;
  50     }
  51 
  52     /**
  53      * Check if the class is loaded by a built-in class loader.
  54      */
  55     static boolean loadedByBuiltinLoader(Class<?> cls) {
  56         ClassLoader cl = cls.getClassLoader();
  57         return (cl == null || (cl instanceof BuiltinClassLoader)) ? true : false;
  58     }
  59 
  60     private static native void addToArchive(Class<?> caller,
  61                                             String invokedName,
  62                                             MethodType invokedType,
  63                                             MethodType samMethodType,
  64                                             MemberName implMethod,
  65                                             MethodType instantiatedMethodType,
  66                                             Class<?> lambdaProxyClass);
  67 
  68     private static native Class<?> findFromArchive(Class<?> caller,
  69                                                    String invokedName,
  70                                                    MethodType invokedType,
  71                                                    MethodType samMethodType,
  72                                                    MemberName implMethod,
  73                                                    MethodType instantiatedMethodType,
  74                                                    boolean initialize);
  75 
  76     /**
  77      * Registers the lambdaProxyClass into CDS archive.
  78      * The VM will store the lambdaProxyClass into a hash table
  79      * using the first six argumennts as the key.
  80      *
  81      * CDS only archives lambda proxy class if it's not serializable
  82      * and no marker interfaces and no additional bridges, and if it is
  83      * loaded by a built-in class loader.
  84      */
  85     static boolean register(Class<?> caller,
  86                             String invokedName,
  87                             MethodType invokedType,
  88                             MethodType samMethodType,
  89                             MethodHandle implMethod,
  90                             MethodType instantiatedMethodType,
  91                             boolean isSerializable,
  92                             Class<?>[] markerInterfaces,
  93                             MethodType[] additionalBridges,
  94                             Class<?> lambdaProxyClass) {
  95         if (!isDumpArchive())
  96             throw new IllegalStateException("should only register lambda proxy class at dump time");
  97 
  98         if (loadedByBuiltinLoader(caller) &&
  99             !isSerializable && markerInterfaces.length == 0 && additionalBridges.length == 0) {
 100             addToArchive(caller, invokedName, invokedType, samMethodType,
 101                          implMethod.internalMemberName(), instantiatedMethodType,
 102                          lambdaProxyClass);
 103             return true;
 104         }
 105         return false;
 106     }
 107 
 108     /**
 109      * Lookup a lambda proxy class from the CDS archive using the first
 110      * six arguments as the key.
 111      *
 112      * CDS only archives lambda proxy class if it's not serializable
 113      * and no marker interfaces and no additional bridges, and if it is
 114      * loaded by a built-in class loader.
 115      */
 116     static Class<?> find(Class<?> caller,
 117                          String invokedName,
 118                          MethodType invokedType,
 119                          MethodType samMethodType,
 120                          MethodHandle implMethod,
 121                          MethodType instantiatedMethodType,
 122                          boolean isSerializable,
 123                          Class<?>[] markerInterfaces,
 124                          MethodType[] additionalBridges,
 125                          boolean initialize) {
 126         if (isDumpArchive())
 127             throw new IllegalStateException("cannot load class from CDS archive at dump time");
 128 
 129         if (!loadedByBuiltinLoader(caller) ||
 130             !isSharingEnabled() || isSerializable || markerInterfaces.length > 0 || additionalBridges.length > 0)
 131             return null;
 132 
 133         return findFromArchive(caller, invokedName, invokedType, samMethodType,
 134                                implMethod.internalMemberName(), instantiatedMethodType, initialize);
 135     }
 136 }