81 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
81 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
82 */ |
82 */ |
83 |
83 |
84 package jdk.internal.dynalink; |
84 package jdk.internal.dynalink; |
85 |
85 |
|
86 import java.lang.invoke.CallSite; |
86 import java.lang.invoke.MethodHandles; |
87 import java.lang.invoke.MethodHandles; |
87 import java.lang.invoke.MethodHandles.Lookup; |
88 import java.lang.invoke.MethodHandles.Lookup; |
88 import java.lang.invoke.MethodType; |
89 import java.lang.invoke.MethodType; |
89 import java.util.Arrays; |
90 import java.util.Arrays; |
90 import java.util.Collections; |
91 import java.util.Collections; |
91 import java.util.List; |
92 import java.util.List; |
92 import java.util.StringTokenizer; |
93 import java.util.StringTokenizer; |
93 import jdk.internal.dynalink.support.NameCodec; |
94 import jdk.internal.dynalink.support.NameCodec; |
94 |
95 |
95 /** |
96 /** |
96 * An immutable descriptor of a call site. It is an immutable object that contains all the information about a call |
97 * Interface for objects describing a call site. A call site descriptor contains |
97 * site: the class performing the lookups, the name of the method being invoked, and the method signature. Call site descriptors are used in this library in place of passing a real call site to |
98 * all the information about a call site necessary for linking it: the class |
98 * guarding linkers so they aren't tempted to directly manipulate the call sites. The constructors of built-in |
99 * performing the lookups, the name of the method being invoked, and the method |
99 * {@link RelinkableCallSite} implementations all need a call site descriptor. Even if you create your own call site |
100 * signature. Call site descriptors are used in Dynalink in place of passing |
100 * descriptors consider using {@link CallSiteDescriptor#tokenizeName(String)} in your implementation. |
101 * {@link CallSite} objects to linkers so they can't directly manipulate them. |
|
102 * The constructors of built-in {@link RelinkableCallSite} implementations all |
|
103 * take a call site descriptor. Call site descriptors must be immutable. |
101 */ |
104 */ |
102 public interface CallSiteDescriptor { |
105 public interface CallSiteDescriptor { |
103 /** |
106 /** |
104 * A permission to invoke the {@link #getLookup()} method. It is named {@code "dynalink.getLookup"}. |
107 * A runtime permission to invoke the {@link #getLookup()} method. It is |
105 */ |
108 * named {@code "dynalink.getLookup"}. |
106 public static final RuntimePermission GET_LOOKUP_PERMISSION = new RuntimePermission("dynalink.getLookup"); |
109 */ |
107 |
110 public static final RuntimePermission GET_LOOKUP_PERMISSION = |
108 /** |
111 new RuntimePermission("dynalink.getLookup"); |
109 * The index of the name token that will carry the operation scheme prefix (usually, "dyn"). |
112 |
|
113 /** |
|
114 * The index of the name token that will carry the operation scheme prefix, |
|
115 * e.g. {@code "dyn"} for operations specified by Dynalink itself. |
110 */ |
116 */ |
111 public static final int SCHEME = 0; |
117 public static final int SCHEME = 0; |
112 /** |
118 |
113 * The index of the name token that will usually carry the operation name. |
119 /** |
114 */ |
120 * The index of the name token that carries the operation name, at least |
115 |
121 * when using the {@code "dyn"} scheme. |
116 public static final int OPERATOR=1; |
122 */ |
117 /** |
123 |
118 * The index of the name token that will usually carry a name of an operand (of a property, method, etc.) |
124 public static final int OPERATOR = 1; |
119 */ |
125 |
120 |
126 /** |
121 public static final int NAME_OPERAND=2; |
127 * The index of the name token that carries the name of an operand (e.g. a |
122 |
128 * property or a method), at least when using the {@code "dyn"} scheme. |
123 /** |
129 */ |
124 * Character used to delimit tokens in an call site name. |
130 public static final int NAME_OPERAND = 2; |
|
131 |
|
132 /** |
|
133 * String used to delimit tokens in a call site name; its value is |
|
134 * {@code ":"}, that is the colon character. |
125 */ |
135 */ |
126 public static final String TOKEN_DELIMITER = ":"; |
136 public static final String TOKEN_DELIMITER = ":"; |
127 |
137 |
128 /** |
138 /** |
129 * Character used to delimit operation names in a composite operation specification. |
139 * String used to delimit operation names in a composite operation name; |
|
140 * its value is {@code "|"}, that is the pipe character. |
130 */ |
141 */ |
131 public static final String OPERATOR_DELIMITER = "|"; |
142 public static final String OPERATOR_DELIMITER = "|"; |
132 |
143 |
133 /** |
144 /** |
134 * Returns the number of tokens in the name of the method at the call site. Method names are tokenized with the |
145 * Returns the number of tokens in the name of the method at the call site. |
135 * colon ":" character, i.e. "dyn:getProp:color" would be the name used to describe a method that retrieves the |
146 * Method names are tokenized with the {@link #TOKEN_DELIMITER} character |
136 * property named "color" on the object it is invoked on. |
147 * character, e.g. {@code "dyn:getProp:color"} would be the name used to |
|
148 * describe a method that retrieves the property named "color" on the object |
|
149 * it is invoked on. |
137 * @return the number of tokens in the name of the method at the call site. |
150 * @return the number of tokens in the name of the method at the call site. |
138 */ |
151 */ |
139 public int getNameTokenCount(); |
152 public int getNameTokenCount(); |
140 |
153 |
141 /** |
154 /** |
142 * Returns the <i>i<sup>th</sup></i> token in the method name at the call site. Method names are tokenized with the |
155 * Returns the <i>i<sup>th</sup></i> token in the method name at the call |
143 * colon ":" character. |
156 * site. Method names are tokenized with the {@link #TOKEN_DELIMITER} |
144 * @param i the index of the token. Must be between 0 (inclusive) and {@link #getNameTokenCount()} (exclusive) |
157 * character. |
145 * @throws IllegalArgumentException if the index is outside the allowed range. |
158 * @param i the index of the token. Must be between 0 (inclusive) and |
146 * @return the <i>i<sup>th</sup></i> token in the method name at the call site. The returned strings are interned. |
159 * {@link #getNameTokenCount()} (exclusive). |
|
160 * @throws IllegalArgumentException if the index is outside the allowed |
|
161 * range. |
|
162 * @return the <i>i<sup>th</sup></i> token in the method name at the call |
|
163 * site. |
147 */ |
164 */ |
148 public String getNameToken(int i); |
165 public String getNameToken(int i); |
149 |
166 |
150 /** |
167 /** |
151 * Returns the name of the method at the call site. Note that the object internally only stores the tokenized name, |
168 * Returns the full (untokenized) name of the method at the call site. |
152 * and has to reconstruct the full name from tokens on each invocation. |
169 * @return the full (untokenized) name of the method at the call site. |
153 * @return the name of the method at the call site. |
|
154 */ |
170 */ |
155 public String getName(); |
171 public String getName(); |
156 |
172 |
157 /** |
173 /** |
158 * The type of the method at the call site. |
174 * The type of the method at the call site. |
160 * @return type of the method at the call site. |
176 * @return type of the method at the call site. |
161 */ |
177 */ |
162 public MethodType getMethodType(); |
178 public MethodType getMethodType(); |
163 |
179 |
164 /** |
180 /** |
165 * Returns the lookup passed to the bootstrap method. |
181 * Returns the lookup that should be used to find method handles to set as |
166 * @return the lookup passed to the bootstrap method. |
182 * targets of the call site described by this descriptor. When creating |
167 * @throws SecurityException if the lookup isn't the {@link MethodHandles#publicLookup()} and a security |
183 * descriptors from a {@link java.lang.invoke} bootstrap method, it should |
168 * manager is present, and a check for {@code RuntimePermission("dynalink.getLookup")} (available as |
184 * be the lookup passed to the bootstrap. An implementation should use |
|
185 * {@link #checkLookup(MethodHandles.Lookup)} to ensure the necessary |
|
186 * security properties. |
|
187 * @return the lookup that should be used to find method handles to set as |
|
188 * targets of the call site described by this descriptor. |
|
189 * @throws SecurityException if the lookup isn't the |
|
190 * {@link MethodHandles#publicLookup()} and a security manager is present, |
|
191 * and a check for {@code RuntimePermission("dynalink.getLookup")} |
|
192 * (a canonical instance of which is available as |
169 * {@link #GET_LOOKUP_PERMISSION}) fails. |
193 * {@link #GET_LOOKUP_PERMISSION}) fails. |
170 */ |
194 */ |
171 public Lookup getLookup(); |
195 public Lookup getLookup(); |
172 |
196 |
173 /** |
197 /** |
174 * Creates a new call site descriptor from this descriptor, which is identical to this, except it changes the method |
198 * Creates a new call site descriptor from this descriptor, which is |
175 * type. |
199 * identical to this, except it changes the method type. |
176 * |
200 * |
177 * @param newMethodType the new method type |
201 * @param newMethodType the new method type |
178 * @return a new call site descriptor, with the method type changed. |
202 * @return a new call site descriptor, with the method type changed. |
179 */ |
203 */ |
180 public CallSiteDescriptor changeMethodType(MethodType newMethodType); |
204 public CallSiteDescriptor changeMethodType(MethodType newMethodType); |
181 |
205 |
182 |
206 |
183 /** |
207 /** |
184 * Tokenizes a composite operation name along pipe characters. I.e. if you have a "dyn:getElem|getProp|getMethod" |
208 * Tokenizes a composite operation name of this descriptor along |
185 * operation, returns a list of ["getElem", "getProp", "getMethod"]. The tokens are not interned. |
209 * {@link #OPERATOR_DELIMITER} characters. E.g. if this descriptor's name is |
186 * @return a list of tokens |
210 * {@code "dyn:getElem|getProp|getMethod"}, then it returns a list of |
|
211 * {@code ["getElem", "getProp", "getMethod"]}. |
|
212 * @return a list of operator tokens. |
187 */ |
213 */ |
188 public default List<String> tokenizeOperators() { |
214 public default List<String> tokenizeOperators() { |
189 final String ops = getNameToken(CallSiteDescriptor.OPERATOR); |
215 final String ops = getNameToken(CallSiteDescriptor.OPERATOR); |
190 final StringTokenizer tok = new StringTokenizer(ops, CallSiteDescriptor.OPERATOR_DELIMITER); |
216 final StringTokenizer tok = new StringTokenizer(ops, CallSiteDescriptor.OPERATOR_DELIMITER); |
191 final int count = tok.countTokens(); |
217 final int count = tok.countTokens(); |
198 } |
224 } |
199 return Arrays.asList(tokens); |
225 return Arrays.asList(tokens); |
200 } |
226 } |
201 |
227 |
202 /** |
228 /** |
203 * Checks if the current access context is granted the {@code RuntimePermission("dynalink.getLookup")} |
229 * Checks if the current access context is granted the |
204 * permission, if the system contains a security manager, and the passed lookup is not the |
230 * {@code RuntimePermission("dynalink.getLookup")} permission, if the |
205 * {@link MethodHandles#publicLookup()}. |
231 * system contains a security manager, and the passed lookup is not the |
|
232 * {@link MethodHandles#publicLookup()}. This method should be used in all |
|
233 * implementations of {@link #getLookup()} method to ensure that only |
|
234 * code with permission can retrieve the lookup object. |
206 * @param lookup the lookup being checked for access |
235 * @param lookup the lookup being checked for access |
207 * @return the passed in lookup if there's either no security manager in the system, or the passed lookup |
236 * @return the passed in lookup if there's either no security manager in |
208 * is the public lookup, or the current access context is granted the relevant permission. |
237 * the system, or the passed lookup is the public lookup, or the current |
209 * @throws SecurityException if the system contains a security manager, and the passed lookup is not the |
238 * access context is granted the relevant permission. |
210 * {@link MethodHandles#publicLookup()}, and the current access context is not granted the relevant |
239 * @throws SecurityException if the system contains a security manager, and |
211 * permission. |
240 * the passed lookup is not the public lookup, and the current access |
|
241 * context is not granted the relevant permission. |
212 */ |
242 */ |
213 public static Lookup checkLookup(final Lookup lookup) { |
243 public static Lookup checkLookup(final Lookup lookup) { |
214 final SecurityManager sm = System.getSecurityManager(); |
244 final SecurityManager sm = System.getSecurityManager(); |
215 if (sm != null && lookup != MethodHandles.publicLookup()) { |
245 if (sm != null && lookup != MethodHandles.publicLookup()) { |
216 sm.checkPermission(GET_LOOKUP_PERMISSION); |
246 sm.checkPermission(GET_LOOKUP_PERMISSION); |
217 } |
247 } |
218 return lookup; |
248 return lookup; |
219 } |
249 } |
220 |
250 |
221 /** |
251 /** |
222 * Tokenizes the composite name along colons, as well as {@link NameCodec#decode(String) demangles} and interns |
252 * Tokenizes the composite name along {@link #TOKEN_DELIMITER} characters, |
223 * the tokens. The first two tokens are not demangled as they are supposed to be the naming scheme and the name of |
253 * as well as {@link NameCodec#decode(String) demangles} and interns the |
224 * the operation which can be expected to consist of just alphabetical characters. |
254 * tokens. The first two tokens are not demangled as they are supposed to |
225 * @param name the composite name consisting of colon-separated, possibly mangled tokens. |
255 * be the naming scheme and the name of the operation which can be expected |
226 * @return an array of tokens |
256 * to consist of just alphabetical characters. |
|
257 * @param name the composite name consisting of |
|
258 * {@link #TOKEN_DELIMITER}-separated, possibly mangled tokens. |
|
259 * @return an array of unmangled, interned tokens. |
227 */ |
260 */ |
228 public static String[] tokenizeName(final String name) { |
261 public static String[] tokenizeName(final String name) { |
229 final StringTokenizer tok = new StringTokenizer(name, CallSiteDescriptor.TOKEN_DELIMITER); |
262 final StringTokenizer tok = new StringTokenizer(name, CallSiteDescriptor.TOKEN_DELIMITER); |
230 final String[] tokens = new String[tok.countTokens()]; |
263 final String[] tokens = new String[tok.countTokens()]; |
231 for(int i = 0; i < tokens.length; ++i) { |
264 for(int i = 0; i < tokens.length; ++i) { |