Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/jcl/src/java.base/share/classes/java/lang/invoke/BruteArgumentMoverHandle.java
12513 views
1
/*[INCLUDE-IF Sidecar17 & !OPENJDK_METHODHANDLES]*/
2
/*******************************************************************************
3
* Copyright (c) 2013, 2020 IBM Corp. and others
4
*
5
* This program and the accompanying materials are made available under
6
* the terms of the Eclipse Public License 2.0 which accompanies this
7
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
8
* or the Apache License, Version 2.0 which accompanies this distribution and
9
* is available at https://www.apache.org/licenses/LICENSE-2.0.
10
*
11
* This Source Code may also be made available under the following
12
* Secondary Licenses when the conditions for such availability set
13
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
14
* General Public License, version 2 with the GNU Classpath
15
* Exception [1] and GNU General Public License, version 2 with the
16
* OpenJDK Assembly Exception [2].
17
*
18
* [1] https://www.gnu.org/software/classpath/license.html
19
* [2] http://openjdk.java.net/legal/assembly-exception.html
20
*
21
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
22
*******************************************************************************/
23
package java.lang.invoke;
24
25
abstract class ArgumentMoverHandle extends PassThroughHandle {
26
27
/** Base class for handles that can alter how arguments are passed to another handle.
28
* The "permute" array indicates what arguments to pass to the next handle,
29
* in what order. If this handle takes N arguments, then integers from
30
* 0..N-1 indicate that the corresponding argument to this handle should be
31
* passed on to the next handle. Any other integer results in a call to
32
* the "extra_" method of the right return type.
33
*
34
* For example, suppose you have an ArgumentMoverHandle "amh" taking 3
35
* arguments and having a permute array of [2,25,1,1,-4,0]. That would mean
36
* that calling this:
37
*
38
* amh.invokeExact(x,y,z);
39
*
40
* is equivalent to this:
41
*
42
* amh.next.invokeExact(z, amh.extra_L(25), y, y, amd.extra_L(-4), x);
43
*
44
* ...assuming that all arguments are objects. (If they're not, a
45
* different extra_ method would be called.)
46
*
47
* Subclasses can implement the extra_ method in any way they want.
48
*/
49
50
final MethodHandle next;
51
final int[] permute;
52
53
protected ArgumentMoverHandle(MethodType type, MethodHandle next, int[] permute, Object infoAffectingThunks, MethodHandle equivalent) {
54
super(equivalent, infoAffectingThunks);
55
this.next = next;
56
this.permute = permute;
57
}
58
59
protected ArgumentMoverHandle(ArgumentMoverHandle originalHandle, MethodType newType) {
60
super(originalHandle, newType);
61
this.next = originalHandle.next;
62
this.permute = originalHandle.permute;
63
}
64
65
66
// {{{ JIT support
67
68
protected ThunkTuple computeThunks(Object arg) {
69
return thunkTable().get(new ThunkKeyWithObjectArray(ThunkKey.computeThunkableType(type()), (Object[])arg));
70
}
71
72
// This implements the argument permutation protocol.
73
// Ints 0..N-1 refer to the incoming arguments to the thunk; all other
74
// numbers are passed to the extra_X function returning the appropriate
75
// type, and subclasses can decide what they mean.
76
static native int permuteArgs(int argPlaceholder);
77
78
// Thunks can only fabricate static calls, but we want virtual calls,
79
// so here are a bunch of wrappers.
80
private static boolean extra_Z(ArgumentMoverHandle handle, int index){ return handle.extra_Z(index); }
81
private static byte extra_B(ArgumentMoverHandle handle, int index){ return handle.extra_B(index); }
82
private static char extra_C(ArgumentMoverHandle handle, int index){ return handle.extra_C(index); }
83
private static short extra_S(ArgumentMoverHandle handle, int index){ return handle.extra_S(index); }
84
private static int extra_I(ArgumentMoverHandle handle, int index){ return handle.extra_I(index); }
85
private static long extra_J(ArgumentMoverHandle handle, int index){ return handle.extra_J(index); }
86
private static float extra_F(ArgumentMoverHandle handle, int index){ return handle.extra_F(index); }
87
private static double extra_D(ArgumentMoverHandle handle, int index){ return handle.extra_D(index); }
88
private static Object extra_L(ArgumentMoverHandle handle, int index){ return handle.extra_L(index); }
89
90
// Subclasses can implement whichever of these they need
91
native boolean extra_Z(int index);
92
native byte extra_B(int index);
93
native char extra_C(int index);
94
native short extra_S(int index);
95
native int extra_I(int index);
96
native long extra_J(int index);
97
native float extra_F(int index);
98
native double extra_D(int index);
99
native Object extra_L(int index);
100
101
// }}} JIT support
102
103
void compareWithArgumentMover(ArgumentMoverHandle left, Comparator c) {
104
c.compareStructuralParameter(left.permute.length, this.permute.length);
105
for (int i = 0; (i < left.permute.length) && (i < this.permute.length); i++) {
106
c.compareStructuralParameter(left.permute[i], this.permute[i]);
107
}
108
c.compareChildHandle(left.next, this.next);
109
}
110
111
}
112
113
final class BruteArgumentMoverHandle extends ArgumentMoverHandle {
114
115
/** An ArgumentMoverHandle that can hold additional values to pass to the next handle.
116
* The "extra" array contains the values to pass along. In addition, for
117
* performance reasons, the first few arguments are also redundantly stored
118
* in fields of the BruteArgumentMoverHandle object, which allows us to
119
* avoid unboxing primitives, and also reduces the number of levels of
120
* indirection needed to access objects.
121
*
122
* The extra_ methods take an integer i from -1 to -N, where N is the
123
* length of the extra array. They return extra[-1-i], or a faster equivalent.
124
*
125
* This functionality is enough to compose any number and sequence of
126
* insertArguments, permuteArguments, and dropArguments operations, as well
127
* as asType operations that do only boxing / unboxing and integer widening.
128
* This is the main "value add" of ArgumentMoverHandle: it collapses whole
129
* chains of these handles into a single handle, most of whose functionality
130
* is performed at creation time instead of invocation time.
131
*
132
* (Generally, other asType operations need AsType handles because they are
133
* not composable. For example, casting an argument to class A and then to
134
* B actually does necessitate two checkcasts if A and B are unrelated types.)
135
*/
136
137
final Object[] extra;
138
139
// Save a level of indirection for the first few objects.
140
final Object extra_L0;
141
final Object extra_L1;
142
final Object extra_L2;
143
final Object extra_L3;
144
final Object extra_L4;
145
146
// Save a couple of levels of indirection for inserted ints.
147
// Also, mark as non-final so we leave the loads in the residual code.
148
// They can be treated as honourary finals in full-custom thunks.
149
int extra_I0;
150
int extra_I1;
151
int extra_I2;
152
int extra_I3;
153
int extra_I4;
154
155
// Longs too.
156
long extra_J0;
157
long extra_J1;
158
long extra_J2;
159
long extra_J3;
160
long extra_J4;
161
162
protected BruteArgumentMoverHandle(MethodType type, MethodHandle next, int[] permute, Object[] extra, MethodHandle equivalent) {
163
super(type, next, permute, infoAffectingThunks(next, permute, extra), equivalent);
164
this.extra = extra;
165
// This code is a bit contorted just to satisfy javac
166
if (extra.length >= 1) {
167
extra_L0 = extra[0];
168
if (extra_L0 instanceof Integer) {
169
extra_I0 = (Integer)extra_L0;
170
} else if (extra_L0 instanceof Long) {
171
extra_J0 = (Long)extra_L0;
172
}
173
} else {
174
extra_L0 = null;
175
}
176
if (extra.length >= 2) {
177
extra_L1 = extra[1];
178
if (extra_L1 instanceof Integer) {
179
extra_I1 = (Integer)extra_L1;
180
} else if (extra_L1 instanceof Long) {
181
extra_J1 = (Long)extra_L1;
182
}
183
} else {
184
extra_L1 = null;
185
}
186
if (extra.length >= 3) {
187
extra_L2 = extra[2];
188
if (extra_L2 instanceof Integer) {
189
extra_I2 = (Integer)extra_L2;
190
} else if (extra_L2 instanceof Long) {
191
extra_J2 = (Long)extra_L2;
192
}
193
} else {
194
extra_L2 = null;
195
}
196
if (extra.length >= 4) {
197
extra_L3 = extra[3];
198
if (extra_L3 instanceof Integer) {
199
extra_I3 = (Integer)extra_L3;
200
} else if (extra_L3 instanceof Long) {
201
extra_J3 = (Long)extra_L3;
202
}
203
} else {
204
extra_L3 = null;
205
}
206
if (extra.length >= 5) {
207
extra_L4 = extra[4];
208
if (extra_L4 instanceof Integer) {
209
extra_I4 = (Integer)extra_L4;
210
} else if (extra_L4 instanceof Long) {
211
extra_J4 = (Long)extra_L4;
212
}
213
} else {
214
extra_L4 = null;
215
}
216
}
217
218
protected BruteArgumentMoverHandle(BruteArgumentMoverHandle originalHandle, MethodType newType) {
219
super(originalHandle, newType);
220
extra = originalHandle.extra;
221
extra_L0 = originalHandle.extra_L0;
222
extra_L1 = originalHandle.extra_L1;
223
extra_L2 = originalHandle.extra_L2;
224
extra_L3 = originalHandle.extra_L3;
225
extra_L4 = originalHandle.extra_L4;
226
extra_I0 = originalHandle.extra_I0;
227
extra_I1 = originalHandle.extra_I1;
228
extra_I2 = originalHandle.extra_I2;
229
extra_I3 = originalHandle.extra_I3;
230
extra_I4 = originalHandle.extra_I4;
231
extra_J0 = originalHandle.extra_J0;
232
extra_J1 = originalHandle.extra_J1;
233
extra_J2 = originalHandle.extra_J2;
234
extra_J3 = originalHandle.extra_J3;
235
extra_J4 = originalHandle.extra_J4;
236
}
237
238
@Override
239
MethodHandle cloneWithNewType(MethodType newType) {
240
return new BruteArgumentMoverHandle(this, newType);
241
}
242
243
static int[] identityPermute(MethodType type) {
244
int[] result = new int[type.parameterCount()];
245
for (int i = 0; i < result.length; i++) {
246
result[i] = i;
247
}
248
return result;
249
}
250
251
static int[] composePermute(int[] inner, int[] outer, int outerExtraIndexOffset) {
252
int innerLength = inner.length;
253
int[] result = new int[innerLength];
254
for (int i = 0; i < innerLength; i++) {
255
int index = inner[i];
256
if ((0 <= index) && (index < outer.length)) {
257
result[i] = outer[inner[i]];
258
} else {
259
result[i] = index + outerExtraIndexOffset;
260
}
261
}
262
return result;
263
}
264
265
static int[] insertPermute(int[] originalPermute, int insertLocation, int numValues, int startingIndex) {
266
// TODO: A variant that takes a MethodType instead of originalPermute so we don't have to bother with identityPermute
267
int[] result = new int[originalPermute.length + numValues];
268
for (int i = 0; i < insertLocation; i++) {
269
result[i] = originalPermute[i];
270
}
271
for (int i = 0; i < numValues; i++) {
272
result[insertLocation + i] = startingIndex - i;
273
}
274
for (int i = insertLocation; i < originalPermute.length; i++) {
275
result[i + numValues] = originalPermute[i];
276
}
277
return result;
278
}
279
280
final MethodHandle permuteArguments(MethodType permuteType, int... outerPermute) throws NullPointerException, IllegalArgumentException {
281
if (isUnnecessaryPermute(permuteType, outerPermute)) {
282
return this;
283
}
284
285
return new BruteArgumentMoverHandle(
286
permuteType,
287
next,
288
composePermute(this.permute, outerPermute, 0),
289
extra,
290
new PermuteHandle(permuteType, this.equivalent, outerPermute)
291
);
292
}
293
294
final MethodHandle insertArguments(MethodHandle equivalent, MethodHandle unboxingHandle, int location, Object... outerValues) {
295
MethodHandle result;
296
int[] insertPermute = insertPermute(identityPermute(equivalent.type), location, outerValues.length, -1);
297
int[] combinedPermute = composePermute(this.permute, insertPermute, -outerValues.length);
298
Object[] combinedExtra;
299
if (this.extra.length >= 1) {
300
combinedExtra = java.util.Arrays.copyOf(outerValues, outerValues.length + this.extra.length);
301
System.arraycopy(this.extra, 0, combinedExtra, outerValues.length, this.extra.length);
302
} else {
303
combinedExtra = outerValues;
304
}
305
result = new BruteArgumentMoverHandle(
306
equivalent.type(),
307
next,
308
combinedPermute,
309
combinedExtra,
310
equivalent
311
);
312
return result;
313
}
314
315
// {{{ JIT support
316
317
private static final ThunkTable _thunkTable = new ThunkTable();
318
protected ThunkTable thunkTable(){ return _thunkTable; }
319
320
final Object extra_L(int index) {
321
if (index == -1) {
322
return extra_L0;
323
} else if (index == -2) {
324
return extra_L1;
325
} else if (index == -3) {
326
return extra_L2;
327
} else if (index == -4) {
328
return extra_L3;
329
} else if (index == -5) {
330
return extra_L4;
331
} else {
332
return extra[-1 - index];
333
}
334
}
335
336
final int extra_I(int index) {
337
if (index == -1) {
338
return extra_I0;
339
} else if (index == -2) {
340
return extra_I1;
341
} else if (index == -3) {
342
return extra_I2;
343
} else if (index == -4) {
344
return extra_I3;
345
} else if (index == -5) {
346
return extra_I4;
347
} else {
348
return (Integer)extra[-1 - index];
349
}
350
}
351
352
final long extra_J(int index) {
353
if (index == -1) {
354
return extra_J0;
355
} else if (index == -2) {
356
return extra_J1;
357
} else if (index == -3) {
358
return extra_J2;
359
} else if (index == -4) {
360
return extra_J3;
361
} else if (index == -5) {
362
return extra_J4;
363
} else {
364
return (Long)extra[-1 - index];
365
}
366
}
367
368
// Unbox if needed. These allow us to skip an AsTypeHandle just for unboxing,
369
// though it does impose a checkcast unless the jit can eliminate it.
370
//
371
final boolean extra_Z(int index) {
372
return (Boolean)extra_L(index);
373
}
374
final byte extra_B(int index) {
375
return (Byte)extra_L(index); }
376
final short extra_S(int index) {
377
return (Short)extra_L(index); }
378
final char extra_C(int index) {
379
return (Character)extra_L(index);
380
}
381
final float extra_F(int index) {
382
return (Float)extra_L(index);
383
}
384
final double extra_D(int index) {
385
return (Double)extra_L(index);
386
}
387
388
private static Object[] infoAffectingThunks(MethodHandle next, int[] permute, Object[] extra) {
389
// The location and number of values to insert affects the code generated in shareable thunks,
390
// as does the thunkableType of the next handle.
391
// The actual inserted values don't affect shareable thunks.
392
Object[] result = {ThunkKey.computeThunkableType(next.type()), permute};
393
return result;
394
}
395
396
static native int permuteArgs(int argPlaceholder, Object extra_L0, Object extra_L1, Object extra_L2, Object extra_L3, Object extra_L4, Object[] extra);
397
398
@FrameIteratorSkip
399
private final int invokeExact_thunkArchetype_X(int argPlaceholder) {
400
if (ILGenMacros.isShareableThunk()) {
401
undoCustomizationLogic(next);
402
}
403
if (!ILGenMacros.isCustomThunk()) {
404
doCustomizationLogic();
405
}
406
return ILGenMacros.invokeExact_X(
407
next,
408
permuteArgs(argPlaceholder, this.extra_L0, this.extra_L1, this.extra_L2, this.extra_L3, this.extra_L4, this.extra));
409
}
410
411
// }}} JIT support
412
final void compareWith(MethodHandle right, Comparator c) {
413
if (right instanceof BruteArgumentMoverHandle) {
414
((BruteArgumentMoverHandle)right).compareWithBruteArgumentMover(this, c);
415
} else {
416
c.fail();
417
}
418
}
419
420
final void compareWithArgumentMover(ArgumentMoverHandle left, Comparator c) {
421
// If left were an BruteArgumentMoverHandle, we'd be in
422
// compareWithBruteArgumentMover, so it doesn't match.
423
c.fail();
424
}
425
426
final void compareWithBruteArgumentMover(BruteArgumentMoverHandle left, Comparator c) {
427
c.compareStructuralParameter(left.extra.length, this.extra.length);
428
for (int i = 0; (i < left.extra.length) && (i < this.extra.length); i++) {
429
c.compareUserSuppliedParameter(left.extra[i], this.extra[i]);
430
}
431
super.compareWithArgumentMover(left, c);
432
}
433
434
}
435
436