Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-aarch32-jdk8u
Path: blob/jdk8u272-b10-aarch32-20201026/nashorn/src/jdk/internal/dynalink/ChainedCallSite.java
48795 views
1
/*
2
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
/*
27
* This file is available under and governed by the GNU General Public
28
* License version 2 only, as published by the Free Software Foundation.
29
* However, the following notice accompanied the original version of this
30
* file, and Oracle licenses the original version of this file under the BSD
31
* license:
32
*/
33
/*
34
Copyright 2009-2013 Attila Szegedi
35
36
Licensed under both the Apache License, Version 2.0 (the "Apache License")
37
and the BSD License (the "BSD License"), with licensee being free to
38
choose either of the two at their discretion.
39
40
You may not use this file except in compliance with either the Apache
41
License or the BSD License.
42
43
If you choose to use this file in compliance with the Apache License, the
44
following notice applies to you:
45
46
You may obtain a copy of the Apache License at
47
48
http://www.apache.org/licenses/LICENSE-2.0
49
50
Unless required by applicable law or agreed to in writing, software
51
distributed under the License is distributed on an "AS IS" BASIS,
52
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
53
implied. See the License for the specific language governing
54
permissions and limitations under the License.
55
56
If you choose to use this file in compliance with the BSD License, the
57
following notice applies to you:
58
59
Redistribution and use in source and binary forms, with or without
60
modification, are permitted provided that the following conditions are
61
met:
62
* Redistributions of source code must retain the above copyright
63
notice, this list of conditions and the following disclaimer.
64
* Redistributions in binary form must reproduce the above copyright
65
notice, this list of conditions and the following disclaimer in the
66
documentation and/or other materials provided with the distribution.
67
* Neither the name of the copyright holder nor the names of
68
contributors may be used to endorse or promote products derived from
69
this software without specific prior written permission.
70
71
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
72
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
73
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
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;
85
86
import java.lang.invoke.MethodHandle;
87
import java.lang.invoke.MethodHandles;
88
import java.util.Iterator;
89
import java.util.LinkedList;
90
import java.util.concurrent.atomic.AtomicReference;
91
import jdk.internal.dynalink.linker.GuardedInvocation;
92
import jdk.internal.dynalink.support.AbstractRelinkableCallSite;
93
import jdk.internal.dynalink.support.Lookup;
94
95
/**
96
* A relinkable call site that maintains a chain of linked method handles. In the default implementation, up to 8 method
97
* handles can be chained, cascading from one to the other through
98
* {@link MethodHandles#guardWithTest(MethodHandle, MethodHandle, MethodHandle)}. When this call site has to link a new
99
* method handle and the length of the chain is already at the maximum, it will throw away the oldest method handle.
100
* Switchpoint-invalidated handles in the chain are removed eagerly (on each linking request, and whenever a
101
* switchpoint-invalidated method handle is traversed during invocation). There is currently no profiling
102
* attached to the handles in the chain, so they are never reordered based on usage; the most recently linked method
103
* handle is always at the start of the chain.
104
*/
105
public class ChainedCallSite extends AbstractRelinkableCallSite {
106
private static final MethodHandle PRUNE_CATCHES =
107
MethodHandles.insertArguments(
108
Lookup.findOwnSpecial(
109
MethodHandles.lookup(),
110
"prune",
111
MethodHandle.class,
112
MethodHandle.class,
113
boolean.class),
114
2,
115
true);
116
117
private static final MethodHandle PRUNE_SWITCHPOINTS =
118
MethodHandles.insertArguments(
119
Lookup.findOwnSpecial(
120
MethodHandles.lookup(),
121
"prune",
122
MethodHandle.class,
123
MethodHandle.class,
124
boolean.class),
125
2,
126
false);
127
128
private final AtomicReference<LinkedList<GuardedInvocation>> invocations = new AtomicReference<>();
129
130
/**
131
* Creates a new chained call site.
132
* @param descriptor the descriptor for the call site.
133
*/
134
public ChainedCallSite(final CallSiteDescriptor descriptor) {
135
super(descriptor);
136
}
137
138
/**
139
* The maximum number of method handles in the chain. Defaults to 8. You can override it in a subclass if you need
140
* to change the value. If your override returns a value less than 1, the code will break.
141
* @return the maximum number of method handles in the chain.
142
*/
143
protected int getMaxChainLength() {
144
return 8;
145
}
146
147
@Override
148
public void relink(final GuardedInvocation guardedInvocation, final MethodHandle fallback) {
149
relinkInternal(guardedInvocation, fallback, false, false);
150
}
151
152
@Override
153
public void resetAndRelink(final GuardedInvocation guardedInvocation, final MethodHandle fallback) {
154
relinkInternal(guardedInvocation, fallback, true, false);
155
}
156
157
private MethodHandle relinkInternal(final GuardedInvocation invocation, final MethodHandle relink, final boolean reset, final boolean removeCatches) {
158
final LinkedList<GuardedInvocation> currentInvocations = invocations.get();
159
@SuppressWarnings({ "unchecked", "rawtypes" })
160
final LinkedList<GuardedInvocation> newInvocations =
161
currentInvocations == null || reset ? new LinkedList<>() : (LinkedList)currentInvocations.clone();
162
163
// First, prune the chain of invalidated switchpoints, we always do this
164
// We also remove any catches if the remove catches flag is set
165
for(final Iterator<GuardedInvocation> it = newInvocations.iterator(); it.hasNext();) {
166
final GuardedInvocation inv = it.next();
167
if(inv.hasBeenInvalidated() || (removeCatches && inv.getException() != null)) {
168
it.remove();
169
}
170
}
171
172
// prune() is allowed to invoke this method with invocation == null meaning we're just pruning the chain and not
173
// adding any new invocations to it.
174
if(invocation != null) {
175
// Remove oldest entry if we're at max length
176
if(newInvocations.size() == getMaxChainLength()) {
177
newInvocations.removeFirst();
178
}
179
newInvocations.addLast(invocation);
180
}
181
182
// prune-and-invoke is used as the fallback for invalidated switchpoints. If a switchpoint gets invalidated, we
183
// rebuild the chain and get rid of all invalidated switchpoints instead of letting them linger.
184
final MethodHandle pruneAndInvokeSwitchPoints = makePruneAndInvokeMethod(relink, getPruneSwitchpoints());
185
final MethodHandle pruneAndInvokeCatches = makePruneAndInvokeMethod(relink, getPruneCatches());
186
187
// Fold the new chain
188
MethodHandle target = relink;
189
for(final GuardedInvocation inv: newInvocations) {
190
target = inv.compose(target, pruneAndInvokeSwitchPoints, pruneAndInvokeCatches);
191
}
192
193
// If nobody else updated the call site while we were rebuilding the chain, set the target to our chain. In case
194
// we lost the race for multithreaded update, just do nothing. Either the other thread installed the same thing
195
// we wanted to install, or otherwise, we'll be asked to relink again.
196
if(invocations.compareAndSet(currentInvocations, newInvocations)) {
197
setTarget(target);
198
}
199
return target;
200
}
201
202
/**
203
* Get the switchpoint pruning function for a chained call site
204
* @return function that removes invalidated switchpoints tied to callsite guard chain and relinks
205
*/
206
protected MethodHandle getPruneSwitchpoints() {
207
return PRUNE_SWITCHPOINTS;
208
}
209
210
/**
211
* Get the catch pruning function for a chained call site
212
* @return function that removes all catches tied to callsite guard chain and relinks
213
*/
214
protected MethodHandle getPruneCatches() {
215
return PRUNE_CATCHES;
216
}
217
218
/**
219
* Creates a method that rebuilds our call chain, pruning it of any invalidated switchpoints, and then invokes that
220
* chain.
221
* @param relink the ultimate fallback for the chain (the {@code DynamicLinker}'s relink).
222
* @return a method handle for prune-and-invoke
223
*/
224
private MethodHandle makePruneAndInvokeMethod(final MethodHandle relink, final MethodHandle prune) {
225
// Bind prune to (this, relink)
226
final MethodHandle boundPrune = MethodHandles.insertArguments(prune, 0, this, relink);
227
// Make it ignore all incoming arguments
228
final MethodHandle ignoreArgsPrune = MethodHandles.dropArguments(boundPrune, 0, type().parameterList());
229
// Invoke prune, then invoke the call site target with original arguments
230
return MethodHandles.foldArguments(MethodHandles.exactInvoker(type()), ignoreArgsPrune);
231
}
232
233
@SuppressWarnings("unused")
234
private MethodHandle prune(final MethodHandle relink, final boolean catches) {
235
return relinkInternal(null, relink, false, catches);
236
}
237
}
238
239