91 import jdk.internal.dynalink.linker.GuardedInvocation; |
91 import jdk.internal.dynalink.linker.GuardedInvocation; |
92 import jdk.internal.dynalink.support.AbstractRelinkableCallSite; |
92 import jdk.internal.dynalink.support.AbstractRelinkableCallSite; |
93 import jdk.internal.dynalink.support.Lookup; |
93 import jdk.internal.dynalink.support.Lookup; |
94 |
94 |
95 /** |
95 /** |
96 * A relinkable call site that maintains a chain of linked method handles. In the default implementation, up to 8 method |
96 * A relinkable call site that implements a polymorphic inline caching strategy. |
97 * handles can be chained, cascading from one to the other through |
97 * It remembers up to 8 {@link GuardedInvocation}s it was linked with, and on |
98 * {@link MethodHandles#guardWithTest(MethodHandle, MethodHandle, MethodHandle)}. When this call site has to link a new |
98 * each relink request builds a cascading chain of method handles of one |
99 * method handle and the length of the chain is already at the maximum, it will throw away the oldest method handle. |
99 * invocation falling back to the next one. The number of remembered invocations |
100 * Switchpoint-invalidated handles in the chain are removed eagerly (on each linking request, and whenever a |
100 * can be customized by overriding {@link #getMaxChainLength()} in a subclass. |
101 * switchpoint-invalidated method handle is traversed during invocation). There is currently no profiling |
101 * When this call site is relinked with a new invocation and the length of the |
102 * attached to the handles in the chain, so they are never reordered based on usage; the most recently linked method |
102 * chain is already at the maximum, it will throw away the oldest invocation. |
103 * handle is always at the start of the chain. |
103 * Invocations with invalidated switch points and ones for which their |
|
104 * invalidating exception triggered are removed eagerly from the chain. The |
|
105 * invocations are never reordered; the most recently linked method handle is |
|
106 * always at the start of the chain and the least recently linked at its end. |
|
107 * The call site can be safely relinked on more than one thread concurrently. |
|
108 * Race conditions in linking are resolved by throwing away the |
|
109 * {@link GuardedInvocation} produced on the losing thread without incorporating |
|
110 * it into the chain, so it can lead to repeated linking for the same arguments. |
104 */ |
111 */ |
105 public class ChainedCallSite extends AbstractRelinkableCallSite { |
112 public class ChainedCallSite extends AbstractRelinkableCallSite { |
106 private static final MethodHandle PRUNE_CATCHES; |
113 private static final MethodHandle PRUNE_CATCHES; |
107 private static final MethodHandle PRUNE_SWITCHPOINTS; |
114 private static final MethodHandle PRUNE_SWITCHPOINTS; |
108 static { |
115 static { |
128 public ChainedCallSite(final CallSiteDescriptor descriptor) { |
135 public ChainedCallSite(final CallSiteDescriptor descriptor) { |
129 super(descriptor); |
136 super(descriptor); |
130 } |
137 } |
131 |
138 |
132 /** |
139 /** |
133 * The maximum number of method handles in the chain. Defaults to 8. You can override it in a subclass if you need |
140 * The maximum number of method handles in the chain. Defaults to 8. You can |
134 * to change the value. If your override returns a value less than 1, the code will break. |
141 * override it in a subclass if you need to change the value. |
135 * @return the maximum number of method handles in the chain. |
142 * @return the maximum number of method handles in the chain. The return |
|
143 * value is checked, and if your override returns a value less than 1, a |
|
144 * {@link RuntimeException} will be thrown. |
136 */ |
145 */ |
137 protected int getMaxChainLength() { |
146 protected int getMaxChainLength() { |
138 return 8; |
147 return 8; |
139 } |
148 } |
140 |
149 |
141 @Override |
150 @Override |
142 public void relink(final GuardedInvocation guardedInvocation, final MethodHandle fallback) { |
151 public void relink(final GuardedInvocation guardedInvocation, final MethodHandle relinkAndInvoke) { |
143 relinkInternal(guardedInvocation, fallback, false, false); |
152 relinkInternal(guardedInvocation, relinkAndInvoke, false, false); |
144 } |
153 } |
145 |
154 |
146 @Override |
155 @Override |
147 public void resetAndRelink(final GuardedInvocation guardedInvocation, final MethodHandle fallback) { |
156 public void resetAndRelink(final GuardedInvocation guardedInvocation, final MethodHandle relinkAndInvoke) { |
148 relinkInternal(guardedInvocation, fallback, true, false); |
157 relinkInternal(guardedInvocation, relinkAndInvoke, true, false); |
149 } |
158 } |
150 |
159 |
151 private MethodHandle relinkInternal(final GuardedInvocation invocation, final MethodHandle relink, final boolean reset, final boolean removeCatches) { |
160 private MethodHandle relinkInternal(final GuardedInvocation invocation, final MethodHandle relink, final boolean reset, final boolean removeCatches) { |
152 final Object currentInvocations = invocations; |
161 final Object currentInvocations = invocations; |
153 final LinkedList<GuardedInvocation> newInvocations; |
162 final LinkedList<GuardedInvocation> newInvocations; |
214 |
223 |
215 } |
224 } |
216 /** |
225 /** |
217 * Creates a method that rebuilds our call chain, pruning it of any invalidated switchpoints, and then invokes that |
226 * Creates a method that rebuilds our call chain, pruning it of any invalidated switchpoints, and then invokes that |
218 * chain. |
227 * chain. |
219 * @param relink the ultimate fallback for the chain (the {@code DynamicLinker}'s relink). |
228 * @param relinkAndInvoke the ultimate fallback for the chain passed from the dynamic linker. |
220 * @return a method handle for prune-and-invoke |
229 * @return a method handle for prune-and-invoke |
221 */ |
230 */ |
222 private MethodHandle makePruneAndInvokeMethod(final MethodHandle relink, final MethodHandle prune) { |
231 private MethodHandle makePruneAndInvokeMethod(final MethodHandle relinkAndInvoke, final MethodHandle prune) { |
223 // Bind prune to (this, relink) |
232 // Bind prune to (this, relink) |
224 final MethodHandle boundPrune = MethodHandles.insertArguments(prune, 0, this, relink); |
233 final MethodHandle boundPrune = MethodHandles.insertArguments(prune, 0, this, relinkAndInvoke); |
225 // Make it ignore all incoming arguments |
234 // Make it ignore all incoming arguments |
226 final MethodHandle ignoreArgsPrune = MethodHandles.dropArguments(boundPrune, 0, type().parameterList()); |
235 final MethodHandle ignoreArgsPrune = MethodHandles.dropArguments(boundPrune, 0, type().parameterList()); |
227 // Invoke prune, then invoke the call site target with original arguments |
236 // Invoke prune, then invoke the call site target with original arguments |
228 return MethodHandles.foldArguments(MethodHandles.exactInvoker(type()), ignoreArgsPrune); |
237 return MethodHandles.foldArguments(MethodHandles.exactInvoker(type()), ignoreArgsPrune); |
229 } |
238 } |