74 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER 75 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 76 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 77 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 78 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 79 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 80 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 81 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 82 */ 83 84 package jdk.internal.dynalink.support; 85 86 import java.lang.invoke.MethodHandles; 87 import java.lang.invoke.MethodHandles.Lookup; 88 import java.lang.invoke.MethodType; 89 import java.lang.ref.Reference; 90 import java.lang.ref.WeakReference; 91 import java.util.Arrays; 92 import java.util.Collections; 93 import java.util.List; 94 import java.util.StringTokenizer; 95 import java.util.WeakHashMap; 96 import jdk.internal.dynalink.CallSiteDescriptor; 97 98 /** 99 * Usable as a default factory for call site descriptor implementations. It is weakly canonicalizing, meaning it will 100 * return the same immutable call site descriptor for identical inputs, i.e. repeated requests for a descriptor 101 * signifying public lookup for "dyn:getProp:color" of type "Object(Object)" will return the same object as long as 102 * a previously created, at least softly reachable one exists. It also uses several different implementations of the 103 * {@link CallSiteDescriptor} internally, and chooses the most space-efficient one based on the input. 104 * @author Attila Szegedi 105 */ 106 public class CallSiteDescriptorFactory { 107 private static final WeakHashMap<CallSiteDescriptor, Reference<CallSiteDescriptor>> publicDescs = 108 new WeakHashMap<>(); 109 110 111 private CallSiteDescriptorFactory() { 112 } 113 114 /** 115 * Creates a new call site descriptor instance. The actual underlying class of the instance is dependent on the 116 * passed arguments to be space efficient; i.e. if you only use the public lookup, you'll get back an 117 * implementation that doesn't waste space on storing the lookup object. 118 * @param lookup the lookup that determines access rights at the call site. If your language runtime doesn't have 119 * equivalents of Java access concepts, just use {@link MethodHandles#publicLookup()}. Must not be null. 120 * @param name the name of the method at the call site. Must not be null. 121 * @param methodType the type of the method at the call site. Must not be null. 122 * @return a call site descriptor representing the input. Note that although the method name is "create", it will 123 * in fact return a weakly-referenced canonical instance. 124 */ 125 public static CallSiteDescriptor create(final Lookup lookup, final String name, final MethodType methodType) { 126 name.getClass(); // NPE check 127 methodType.getClass(); // NPE check 128 lookup.getClass(); // NPE check 129 final String[] tokenizedName = tokenizeName(name); 130 if(isPublicLookup(lookup)) { 131 return getCanonicalPublicDescriptor(createPublicCallSiteDescriptor(tokenizedName, methodType)); 132 } 133 return new LookupCallSiteDescriptor(tokenizedName, methodType, lookup); 134 } 135 136 static CallSiteDescriptor getCanonicalPublicDescriptor(final CallSiteDescriptor desc) { 137 synchronized(publicDescs) { 138 final Reference<CallSiteDescriptor> ref = publicDescs.get(desc); 139 if(ref != null) { 140 final CallSiteDescriptor canonical = ref.get(); 141 if(canonical != null) { 142 return canonical; 143 } 144 } 145 publicDescs.put(desc, createReference(desc)); 146 } 147 return desc; 148 } | 74 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER 75 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 76 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 77 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 78 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 79 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 80 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 81 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 82 */ 83 84 package jdk.internal.dynalink.support; 85 86 import java.lang.invoke.MethodHandles; 87 import java.lang.invoke.MethodHandles.Lookup; 88 import java.lang.invoke.MethodType; 89 import java.lang.ref.Reference; 90 import java.lang.ref.WeakReference; 91 import java.util.Arrays; 92 import java.util.Collections; 93 import java.util.List; 94 import java.util.Objects; 95 import java.util.StringTokenizer; 96 import java.util.WeakHashMap; 97 import jdk.internal.dynalink.CallSiteDescriptor; 98 99 /** 100 * Usable as a default factory for call site descriptor implementations. It is weakly canonicalizing, meaning it will 101 * return the same immutable call site descriptor for identical inputs, i.e. repeated requests for a descriptor 102 * signifying public lookup for "dyn:getProp:color" of type "Object(Object)" will return the same object as long as 103 * a previously created, at least softly reachable one exists. It also uses several different implementations of the 104 * {@link CallSiteDescriptor} internally, and chooses the most space-efficient one based on the input. 105 * @author Attila Szegedi 106 */ 107 public class CallSiteDescriptorFactory { 108 private static final WeakHashMap<CallSiteDescriptor, Reference<CallSiteDescriptor>> publicDescs = 109 new WeakHashMap<>(); 110 111 112 private CallSiteDescriptorFactory() { 113 } 114 115 /** 116 * Creates a new call site descriptor instance. The actual underlying class of the instance is dependent on the 117 * passed arguments to be space efficient; i.e. if you only use the public lookup, you'll get back an 118 * implementation that doesn't waste space on storing the lookup object. 119 * @param lookup the lookup that determines access rights at the call site. If your language runtime doesn't have 120 * equivalents of Java access concepts, just use {@link MethodHandles#publicLookup()}. Must not be null. 121 * @param name the name of the method at the call site. Must not be null. 122 * @param methodType the type of the method at the call site. Must not be null. 123 * @return a call site descriptor representing the input. Note that although the method name is "create", it will 124 * in fact return a weakly-referenced canonical instance. 125 */ 126 public static CallSiteDescriptor create(final Lookup lookup, final String name, final MethodType methodType) { 127 Objects.requireNonNull(name); 128 Objects.requireNonNull(methodType); 129 Objects.requireNonNull(lookup); 130 final String[] tokenizedName = tokenizeName(name); 131 if(isPublicLookup(lookup)) { 132 return getCanonicalPublicDescriptor(createPublicCallSiteDescriptor(tokenizedName, methodType)); 133 } 134 return new LookupCallSiteDescriptor(tokenizedName, methodType, lookup); 135 } 136 137 static CallSiteDescriptor getCanonicalPublicDescriptor(final CallSiteDescriptor desc) { 138 synchronized(publicDescs) { 139 final Reference<CallSiteDescriptor> ref = publicDescs.get(desc); 140 if(ref != null) { 141 final CallSiteDescriptor canonical = ref.get(); 142 if(canonical != null) { 143 return canonical; 144 } 145 } 146 publicDescs.put(desc, createReference(desc)); 147 } 148 return desc; 149 } |