87 import java.lang.invoke.MethodHandles.Lookup; |
87 import java.lang.invoke.MethodHandles.Lookup; |
88 import java.util.Objects; |
88 import java.util.Objects; |
89 import jdk.internal.dynalink.CallSiteDescriptor; |
89 import jdk.internal.dynalink.CallSiteDescriptor; |
90 |
90 |
91 /** |
91 /** |
92 * A base class for call site descriptor implementations. Provides reconstruction of the name from the tokens, |
92 * A base class for call site descriptor implementations. Provides |
93 * as well as generally useful {@code equals}, {@code hashCode}, and {@code toString} methods. For security |
93 * reconstruction of the name from the tokens, as well as generally useful |
94 * and performance reasons, subclasses must implement {@link #lookupEquals(AbstractCallSiteDescriptor)}, |
94 * {@code equals}, {@code hashCode}, and {@code toString} methods. In order to |
|
95 * both prevent unprivileged access to its internal {@link MethodHandles.Lookup} |
|
96 * object, and at the same time not force privileged access to it from |
|
97 * {@code equals}, {@code hashCode}, and {@code toString} methods, subclasses |
|
98 * must implement {@link #lookupEquals(AbstractCallSiteDescriptor)}, |
95 * {@link #lookupHashCode()} and {@link #lookupToString()} methods. |
99 * {@link #lookupHashCode()} and {@link #lookupToString()} methods. |
|
100 * Additionally, {@link #equalsInKind(AbstractCallSiteDescriptor)} should be |
|
101 * overridden instead of {@link #equals(Object)} to compare descriptors in |
|
102 * subclasses; it is only necessary if they have implementation-specific |
|
103 * properties other than the standard name, type, and lookup. |
96 * @param <T> The call site descriptor subclass |
104 * @param <T> The call site descriptor subclass |
97 */ |
105 */ |
98 public abstract class AbstractCallSiteDescriptor<T extends AbstractCallSiteDescriptor<T>> implements CallSiteDescriptor { |
106 public abstract class AbstractCallSiteDescriptor<T extends AbstractCallSiteDescriptor<T>> implements CallSiteDescriptor { |
99 |
107 |
100 @Override |
108 @Override |
101 public String getName() { |
109 public String getName() { |
102 return appendName(new StringBuilder(getNameLength())).toString(); |
110 return appendName(new StringBuilder(getNameLength())).toString(); |
103 } |
111 } |
104 |
112 |
|
113 /** |
|
114 * Checks if this call site descriptor is equality to another object. It is |
|
115 * considered equal iff and only if they belong to the exact same class, and |
|
116 * have the same name, method type, and lookup. Subclasses with additional |
|
117 * properties should override |
|
118 * {@link #equalsInKind(AbstractCallSiteDescriptor)} instead of this method. |
|
119 * @param obj the object checked for equality |
|
120 * @return true if they are equal, false otherwise |
|
121 */ |
105 @SuppressWarnings("unchecked") |
122 @SuppressWarnings("unchecked") |
106 @Override |
123 @Override |
107 public boolean equals(final Object obj) { |
124 public boolean equals(final Object obj) { |
108 return obj != null && obj.getClass() == getClass() && equalsInKind((T)obj); |
125 return obj != null && obj.getClass() == getClass() && equalsInKind((T)obj); |
109 } |
126 } |
110 |
127 |
111 /** |
128 /** |
112 * Returns true if this call site descriptor is equal to the passed, non-null call site descriptor of the |
129 * Returns true if this call site descriptor is equal to the passed, |
113 * same class. |
130 * non-null call site descriptor of the same class. |
114 * @param csd the other call site descriptor. |
131 * @param csd the other call site descriptor. |
115 * @return true if they are equal. |
132 * @return true if they are equal. |
116 */ |
133 */ |
117 protected boolean equalsInKind(final T csd) { |
134 protected boolean equalsInKind(final T csd) { |
118 if(csd == this) { |
135 if(csd == this) { |
132 } |
149 } |
133 return lookupEquals(csd); |
150 return lookupEquals(csd); |
134 } |
151 } |
135 |
152 |
136 /** |
153 /** |
137 * Returns true if this call site descriptor's lookup is equal to the other call site descriptor's lookup. |
154 * Returns true if this call site descriptor's lookup is equal to the other |
138 * Typical implementation should try to obtain the other lookup directly without going through |
155 * call site descriptor's lookup. Typical implementation should try to |
139 * {@link #getLookup()} (e.g. directly using the implementation) and then delegate to |
156 * obtain the other lookup directly without going through privileged |
|
157 * {@link #getLookup()} (e.g. by reading the field as the type system |
|
158 * enforces that they are of the same class) and then delegate to |
140 * {@link #lookupsEqual(MethodHandles.Lookup, MethodHandles.Lookup)}. |
159 * {@link #lookupsEqual(MethodHandles.Lookup, MethodHandles.Lookup)}. |
141 * @param other the other lookup |
160 * @param other the other lookup |
142 * @return true if the lookups are equal |
161 * @return true if the lookups are equal |
143 */ |
162 */ |
144 protected abstract boolean lookupEquals(T other); |
163 protected abstract boolean lookupEquals(T other); |
145 |
164 |
|
165 /** |
|
166 * Compares two lookup objects for value-based equality. They are considered |
|
167 * equal if they have the same |
|
168 * {@link java.lang.invoke.MethodHandles.Lookup#lookupClass()} and |
|
169 * {@link java.lang.invoke.MethodHandles.Lookup#lookupModes()}. |
|
170 * @param l1 first lookup |
|
171 * @param l2 second lookup |
|
172 * @return true if the two lookups are equal, false otherwise. |
|
173 */ |
146 protected static boolean lookupsEqual(final Lookup l1, final Lookup l2) { |
174 protected static boolean lookupsEqual(final Lookup l1, final Lookup l2) { |
147 if(l1 == l2) { |
175 if(l1 == l2) { |
148 return true; |
176 return true; |
149 } |
177 } else if (l1 == null || l2 == null) { |
150 if(l1.lookupClass() != l2.lookupClass()) { |
178 return false; |
|
179 } else if(l1.lookupClass() != l2.lookupClass()) { |
151 return false; |
180 return false; |
152 } |
181 } |
153 return l1.lookupModes() == l2.lookupModes(); |
182 return l1.lookupModes() == l2.lookupModes(); |
154 } |
183 } |
155 |
184 |
162 } |
191 } |
163 return h * 31 + getMethodType().hashCode(); |
192 return h * 31 + getMethodType().hashCode(); |
164 } |
193 } |
165 |
194 |
166 /** |
195 /** |
167 * Return the hash code of this call site descriptor's {@link Lookup} object. Typical |
196 * Return the hash code of this call site descriptor's {@link Lookup} |
168 * implementation should delegate to {@link #lookupHashCode(MethodHandles.Lookup)}. |
197 * object. Typical implementation should delegate to |
169 * @return the hash code of this call site descriptor's {@link Lookup} object. |
198 * {@link #lookupHashCode(MethodHandles.Lookup)}. |
|
199 * @return the hash code of this call site descriptor's {@link Lookup} |
|
200 * object. |
170 */ |
201 */ |
171 protected abstract int lookupHashCode(); |
202 protected abstract int lookupHashCode(); |
172 |
203 |
|
204 /** |
|
205 * Returns a value-based hash code for the passed lookup object. It is |
|
206 * based on the lookup object's |
|
207 * {@link java.lang.invoke.MethodHandles.Lookup#lookupClass()} and |
|
208 * {@link java.lang.invoke.MethodHandles.Lookup#lookupModes()} values. |
|
209 * @param lookup the lookup object. |
|
210 * @return a hash code for the object. Returns 0 for null. |
|
211 */ |
173 protected static int lookupHashCode(final Lookup lookup) { |
212 protected static int lookupHashCode(final Lookup lookup) { |
174 return lookup.lookupClass().hashCode() + 31 * lookup.lookupModes(); |
213 return lookup != null ? lookup.lookupClass().hashCode() + 31 * lookup.lookupModes() : 0; |
175 } |
214 } |
176 |
215 |
177 @Override |
216 @Override |
178 public String toString() { |
217 public String toString() { |
179 final String mt = getMethodType().toString(); |
218 final String mt = getMethodType().toString(); |
181 final StringBuilder b = new StringBuilder(l.length() + 1 + mt.length() + getNameLength()); |
220 final StringBuilder b = new StringBuilder(l.length() + 1 + mt.length() + getNameLength()); |
182 return appendName(b).append(mt).append("@").append(l).toString(); |
221 return appendName(b).append(mt).append("@").append(l).toString(); |
183 } |
222 } |
184 |
223 |
185 /** |
224 /** |
186 * Return a string representation of this call site descriptor's {@link Lookup} object. Typically will |
225 * Return a string representation of this call site descriptor's |
187 * return {@link Lookup#toString()}. |
226 * {@link Lookup} object. Typically will return |
188 * @return a string representation of this call site descriptor's {@link Lookup} object. |
227 * {@link java.lang.invoke.MethodHandles.Lookup#toString()}. |
|
228 * @return a string representation of this call site descriptor's |
|
229 * {@link Lookup} object. |
189 */ |
230 */ |
190 protected abstract String lookupToString(); |
231 protected abstract String lookupToString(); |
191 |
232 |
192 private int getNameLength() { |
233 private int getNameLength() { |
193 final int c = getNameTokenCount(); |
234 final int c = getNameTokenCount(); |