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 }
|