76 printArgs = lookup.findStatic(thisClass, |
76 printArgs = lookup.findStatic(thisClass, |
77 "printArgs", MethodType.methodType(void.class, Object[].class)); |
77 "printArgs", MethodType.methodType(void.class, Object[].class)); |
78 } |
78 } |
79 private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String name, MethodType type) { |
79 private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String name, MethodType type) { |
80 // ignore caller and name, but match the type: |
80 // ignore caller and name, but match the type: |
81 return new ConstantCallSite(MethodHandles.collectArguments(printArgs, type)); |
81 return new ConstantCallSite(printArgs.asType(type)); |
82 } |
82 } |
83 </pre></blockquote> |
83 </pre></blockquote> |
84 * @author John Rose, JSR 292 EG |
84 * @author John Rose, JSR 292 EG |
85 */ |
85 */ |
86 abstract |
86 abstract |
87 public class CallSite { |
87 public class CallSite { |
88 private static final Access IMPL_TOKEN = Access.getToken(); |
88 private static final Access IMPL_TOKEN = Access.getToken(); |
|
89 static { MethodHandleImpl.initStatics(); } |
89 |
90 |
90 // Fields used only by the JVM. Do not use or change. |
91 // Fields used only by the JVM. Do not use or change. |
91 private MemberName vmmethod; // supplied by the JVM (ref. to calling method) |
92 private MemberName vmmethod; // supplied by the JVM (ref. to calling method) |
92 private int vmindex; // supplied by the JVM (BCI within calling method) |
93 private int vmindex; // supplied by the JVM (BCI within calling method) |
93 |
94 |
152 this.vmindex = callerBCI; |
153 this.vmindex = callerBCI; |
153 this.vmmethod = callerMethod; |
154 this.vmmethod = callerMethod; |
154 } |
155 } |
155 |
156 |
156 /** |
157 /** |
157 * Report the current linkage state of the call site, a value which may change over time. |
158 * Returns the target method of the call site, according to the |
158 * <p> |
159 * behavior defined by this call site's specific class. |
159 * If a {@code CallSite} object is returned |
160 * The immediate subclasses of {@code CallSite} document the |
160 * from the bootstrap method of the {@code invokedynamic} instruction, |
161 * class-specific behaviors of this method. |
161 * the {@code CallSite} is permanently bound to that instruction. |
162 * |
162 * When the {@code invokedynamic} instruction is executed, the target method |
|
163 * of its associated call site object is invoked directly. |
|
164 * It is as if the instruction calls {@code getTarget} and then |
|
165 * calls {@link MethodHandle#invokeExact invokeExact} on the result. |
|
166 * <p> |
|
167 * Unless specified differently by a subclass, |
|
168 * the interactions of {@code getTarget} with memory are the same |
|
169 * as of a read from an ordinary variable, such as an array element or a |
|
170 * non-volatile, non-final field. |
|
171 * <p> |
|
172 * In particular, the current thread may choose to reuse the result |
|
173 * of a previous read of the target from memory, and may fail to see |
|
174 * a recent update to the target by another thread. |
|
175 * <p> |
|
176 * In a {@linkplain ConstantCallSite constant call site}, the {@code getTarget} method behaves |
|
177 * like a read from a {@code final} field of the {@code CallSite}. |
|
178 * <p> |
|
179 * In a {@linkplain VolatileCallSite volatile call site}, the {@code getTarget} method behaves |
|
180 * like a read from a {@code volatile} field of the {@code CallSite}. |
|
181 * <p> |
|
182 * This method may not be overridden by application code. |
|
183 * @return the current linkage state of the call site, its target method handle |
163 * @return the current linkage state of the call site, its target method handle |
184 * @see ConstantCallSite |
164 * @see ConstantCallSite |
185 * @see VolatileCallSite |
165 * @see VolatileCallSite |
186 * @see #setTarget |
166 * @see #setTarget |
187 */ |
167 * @see ConstantCallSite#getTarget |
188 public final MethodHandle getTarget() { |
168 * @see MutableCallSite#getTarget |
189 return getTarget0(); |
169 * @see VolatileCallSite#getTarget |
190 } |
170 */ |
191 |
171 public abstract MethodHandle getTarget(); |
192 /** |
172 |
193 * Privileged implementations can override this to force final or volatile semantics on getTarget. |
173 /** |
194 */ |
174 * Updates the target method of this call site, according to the |
195 /*package-private*/ |
175 * behavior defined by this call site's specific class. |
196 MethodHandle getTarget0() { |
176 * The immediate subclasses of {@code CallSite} document the |
197 return target; |
177 * class-specific behaviors of this method. |
198 } |
|
199 |
|
200 /** |
|
201 * Set the target method of this call site. |
|
202 * <p> |
178 * <p> |
203 * Unless a subclass of CallSite documents otherwise, |
179 * The type of the new target must be {@linkplain MethodType#equals equal to} |
204 * the interactions of {@code setTarget} with memory are the same |
180 * the type of the old target. |
205 * as of a write to an ordinary variable, such as an array element or a |
181 * |
206 * non-volatile, non-final field. |
|
207 * <p> |
|
208 * In particular, unrelated threads may fail to see the updated target |
|
209 * until they perform a read from memory. |
|
210 * Stronger guarantees can be created by putting appropriate operations |
|
211 * into the bootstrap method and/or the target methods used |
|
212 * at any given call site. |
|
213 * @param newTarget the new target |
182 * @param newTarget the new target |
214 * @throws NullPointerException if the proposed new target is null |
183 * @throws NullPointerException if the proposed new target is null |
215 * @throws WrongMethodTypeException if the proposed new target |
184 * @throws WrongMethodTypeException if the proposed new target |
216 * has a method type that differs from the previous target |
185 * has a method type that differs from the previous target |
217 * @throws UnsupportedOperationException if the call site is |
186 * @see CallSite#getTarget |
218 * in fact a {@link ConstantCallSite} |
187 * @see ConstantCallSite#setTarget |
219 */ |
188 * @see MutableCallSite#setTarget |
220 public void setTarget(MethodHandle newTarget) { |
189 * @see VolatileCallSite#setTarget |
221 checkTargetChange(this.target, newTarget); |
190 */ |
222 setTargetNormal(newTarget); |
191 public abstract void setTarget(MethodHandle newTarget); |
223 } |
|
224 |
192 |
225 void checkTargetChange(MethodHandle oldTarget, MethodHandle newTarget) { |
193 void checkTargetChange(MethodHandle oldTarget, MethodHandle newTarget) { |
226 MethodType oldType = oldTarget.type(); |
194 MethodType oldType = oldTarget.type(); |
227 MethodType newType = newTarget.type(); // null check! |
195 MethodType newType = newTarget.type(); // null check! |
228 if (!newType.equals(oldType)) |
196 if (!newType.equals(oldType)) |
234 } |
202 } |
235 |
203 |
236 /** |
204 /** |
237 * Produce a method handle equivalent to an invokedynamic instruction |
205 * Produce a method handle equivalent to an invokedynamic instruction |
238 * which has been linked to this call site. |
206 * which has been linked to this call site. |
239 * <p>If this call site is a {@linkplain ConstantCallSite constant call site}, |
207 * <p> |
240 * this method simply returns the call site's target, since that will never change. |
208 * This method is equivalent to the following code: |
241 * <p>Otherwise, this method is equivalent to the following code: |
209 * <blockquote><pre> |
242 * <p><blockquote><pre> |
|
243 * MethodHandle getTarget, invoker, result; |
210 * MethodHandle getTarget, invoker, result; |
244 * getTarget = MethodHandles.lookup().bind(this, "getTarget", MethodType.methodType(MethodHandle.class)); |
211 * getTarget = MethodHandles.publicLookup().bind(this, "getTarget", MethodType.methodType(MethodHandle.class)); |
245 * invoker = MethodHandles.exactInvoker(this.type()); |
212 * invoker = MethodHandles.exactInvoker(this.type()); |
246 * result = MethodHandles.foldArguments(invoker, getTarget) |
213 * result = MethodHandles.foldArguments(invoker, getTarget) |
247 * </pre></blockquote> |
214 * </pre></blockquote> |
|
215 * |
248 * @return a method handle which always invokes this call site's current target |
216 * @return a method handle which always invokes this call site's current target |
249 */ |
217 */ |
250 public final MethodHandle dynamicInvoker() { |
218 public abstract MethodHandle dynamicInvoker(); |
251 if (this instanceof ConstantCallSite) { |
219 |
252 return getTarget0(); // will not change dynamically |
220 /*non-public*/ MethodHandle makeDynamicInvoker() { |
253 } |
|
254 MethodHandle getTarget = MethodHandleImpl.bindReceiver(IMPL_TOKEN, GET_TARGET, this); |
221 MethodHandle getTarget = MethodHandleImpl.bindReceiver(IMPL_TOKEN, GET_TARGET, this); |
255 MethodHandle invoker = MethodHandles.exactInvoker(this.type()); |
222 MethodHandle invoker = MethodHandles.exactInvoker(this.type()); |
256 return MethodHandles.foldArguments(invoker, getTarget); |
223 return MethodHandles.foldArguments(invoker, getTarget); |
257 } |
224 } |
|
225 |
258 private static final MethodHandle GET_TARGET; |
226 private static final MethodHandle GET_TARGET; |
259 static { |
227 static { |
260 try { |
228 try { |
261 GET_TARGET = MethodHandles.Lookup.IMPL_LOOKUP. |
229 GET_TARGET = MethodHandles.Lookup.IMPL_LOOKUP. |
262 findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class)); |
230 findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class)); |