Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/invoke/util/ValueConversions.java
38918 views
1
/*
2
* Copyright (c) 2008, 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
package sun.invoke.util;
27
28
import java.lang.invoke.MethodHandle;
29
import java.lang.invoke.MethodHandles;
30
import java.lang.invoke.MethodHandles.Lookup;
31
import java.lang.invoke.MethodType;
32
import java.util.EnumMap;
33
34
public class ValueConversions {
35
private static final Class<?> THIS_CLASS = ValueConversions.class;
36
private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
37
38
/** Thread-safe canonicalized mapping from Wrapper to MethodHandle
39
* with unsynchronized reads and synchronized writes.
40
* It's safe to publish MethodHandles by data race because they are immutable. */
41
private static class WrapperCache {
42
/** EnumMap uses preconstructed array internally, which is constant during it's lifetime. */
43
private final EnumMap<Wrapper, MethodHandle> map = new EnumMap<>(Wrapper.class);
44
45
public MethodHandle get(Wrapper w) {
46
return map.get(w);
47
}
48
public synchronized MethodHandle put(final Wrapper w, final MethodHandle mh) {
49
// Simulate CAS to avoid racy duplication
50
MethodHandle prev = map.putIfAbsent(w, mh);
51
if (prev != null) return prev;
52
return mh;
53
}
54
}
55
56
private static WrapperCache[] newWrapperCaches(int n) {
57
WrapperCache[] caches = new WrapperCache[n];
58
for (int i = 0; i < n; i++)
59
caches[i] = new WrapperCache();
60
return caches;
61
}
62
63
/// Converting references to values.
64
65
// There are several levels of this unboxing conversions:
66
// no conversions: exactly Integer.valueOf, etc.
67
// implicit conversions sanctioned by JLS 5.1.2, etc.
68
// explicit conversions as allowed by explicitCastArguments
69
70
static int unboxInteger(Integer x) {
71
return x;
72
}
73
static int unboxInteger(Object x, boolean cast) {
74
if (x instanceof Integer)
75
return (Integer) x;
76
return primitiveConversion(Wrapper.INT, x, cast).intValue();
77
}
78
79
static byte unboxByte(Byte x) {
80
return x;
81
}
82
static byte unboxByte(Object x, boolean cast) {
83
if (x instanceof Byte)
84
return (Byte) x;
85
return primitiveConversion(Wrapper.BYTE, x, cast).byteValue();
86
}
87
88
static short unboxShort(Short x) {
89
return x;
90
}
91
static short unboxShort(Object x, boolean cast) {
92
if (x instanceof Short)
93
return (Short) x;
94
return primitiveConversion(Wrapper.SHORT, x, cast).shortValue();
95
}
96
97
static boolean unboxBoolean(Boolean x) {
98
return x;
99
}
100
static boolean unboxBoolean(Object x, boolean cast) {
101
if (x instanceof Boolean)
102
return (Boolean) x;
103
return (primitiveConversion(Wrapper.BOOLEAN, x, cast).intValue() & 1) != 0;
104
}
105
106
static char unboxCharacter(Character x) {
107
return x;
108
}
109
static char unboxCharacter(Object x, boolean cast) {
110
if (x instanceof Character)
111
return (Character) x;
112
return (char) primitiveConversion(Wrapper.CHAR, x, cast).intValue();
113
}
114
115
static long unboxLong(Long x) {
116
return x;
117
}
118
static long unboxLong(Object x, boolean cast) {
119
if (x instanceof Long)
120
return (Long) x;
121
return primitiveConversion(Wrapper.LONG, x, cast).longValue();
122
}
123
124
static float unboxFloat(Float x) {
125
return x;
126
}
127
static float unboxFloat(Object x, boolean cast) {
128
if (x instanceof Float)
129
return (Float) x;
130
return primitiveConversion(Wrapper.FLOAT, x, cast).floatValue();
131
}
132
133
static double unboxDouble(Double x) {
134
return x;
135
}
136
static double unboxDouble(Object x, boolean cast) {
137
if (x instanceof Double)
138
return (Double) x;
139
return primitiveConversion(Wrapper.DOUBLE, x, cast).doubleValue();
140
}
141
142
private static MethodType unboxType(Wrapper wrap, int kind) {
143
if (kind == 0)
144
return MethodType.methodType(wrap.primitiveType(), wrap.wrapperType());
145
return MethodType.methodType(wrap.primitiveType(), Object.class, boolean.class);
146
}
147
148
private static final WrapperCache[] UNBOX_CONVERSIONS = newWrapperCaches(4);
149
150
private static MethodHandle unbox(Wrapper wrap, int kind) {
151
// kind 0 -> strongly typed with NPE
152
// kind 1 -> strongly typed but zero for null,
153
// kind 2 -> asType rules: accept multiple box types but only widening conversions with NPE
154
// kind 3 -> explicitCastArguments rules: allow narrowing conversions, zero for null
155
WrapperCache cache = UNBOX_CONVERSIONS[kind];
156
MethodHandle mh = cache.get(wrap);
157
if (mh != null) {
158
return mh;
159
}
160
// slow path
161
switch (wrap) {
162
case OBJECT:
163
case VOID:
164
throw new IllegalArgumentException("unbox "+wrap);
165
}
166
// look up the method
167
String name = "unbox" + wrap.wrapperSimpleName();
168
MethodType type = unboxType(wrap, kind);
169
try {
170
mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
171
} catch (ReflectiveOperationException ex) {
172
mh = null;
173
}
174
if (mh != null) {
175
if (kind > 0) {
176
boolean cast = (kind != 2);
177
mh = MethodHandles.insertArguments(mh, 1, cast);
178
}
179
if (kind == 1) { // casting but exact (null -> zero)
180
mh = mh.asType(unboxType(wrap, 0));
181
}
182
return cache.put(wrap, mh);
183
}
184
throw new IllegalArgumentException("cannot find unbox adapter for " + wrap
185
+ (kind <= 1 ? " (exact)" : kind == 3 ? " (cast)" : ""));
186
}
187
188
/** Return an exact unboxer for the given primitive type. */
189
public static MethodHandle unboxExact(Wrapper type) {
190
return unbox(type, 0);
191
}
192
193
/** Return an exact unboxer for the given primitive type, with optional null-to-zero conversion.
194
* The boolean says whether to throw an NPE on a null value (false means unbox a zero).
195
* The type of the unboxer is of a form like (Integer)int.
196
*/
197
public static MethodHandle unboxExact(Wrapper type, boolean throwNPE) {
198
return unbox(type, throwNPE ? 0 : 1);
199
}
200
201
/** Return a widening unboxer for the given primitive type.
202
* Widen narrower primitive boxes to the given type.
203
* Do not narrow any primitive values or convert null to zero.
204
* The type of the unboxer is of a form like (Object)int.
205
*/
206
public static MethodHandle unboxWiden(Wrapper type) {
207
return unbox(type, 2);
208
}
209
210
/** Return a casting unboxer for the given primitive type.
211
* Widen or narrow primitive values to the given type, or convert null to zero, as needed.
212
* The type of the unboxer is of a form like (Object)int.
213
*/
214
public static MethodHandle unboxCast(Wrapper type) {
215
return unbox(type, 3);
216
}
217
218
static private final Integer ZERO_INT = 0, ONE_INT = 1;
219
220
/// Primitive conversions
221
/**
222
* Produce a Number which represents the given value {@code x}
223
* according to the primitive type of the given wrapper {@code wrap}.
224
* Caller must invoke intValue, byteValue, longValue (etc.) on the result
225
* to retrieve the desired primitive value.
226
*/
227
public static Number primitiveConversion(Wrapper wrap, Object x, boolean cast) {
228
// Maybe merge this code with Wrapper.convert/cast.
229
Number res;
230
if (x == null) {
231
if (!cast) return null;
232
return ZERO_INT;
233
}
234
if (x instanceof Number) {
235
res = (Number) x;
236
} else if (x instanceof Boolean) {
237
res = ((boolean)x ? ONE_INT : ZERO_INT);
238
} else if (x instanceof Character) {
239
res = (int)(char)x;
240
} else {
241
// this will fail with the required ClassCastException:
242
res = (Number) x;
243
}
244
Wrapper xwrap = Wrapper.findWrapperType(x.getClass());
245
if (xwrap == null || !cast && !wrap.isConvertibleFrom(xwrap))
246
// this will fail with the required ClassCastException:
247
return (Number) wrap.wrapperType().cast(x);
248
return res;
249
}
250
251
/**
252
* The JVM verifier allows boolean, byte, short, or char to widen to int.
253
* Support exactly this conversion, from a boxed value type Boolean,
254
* Byte, Short, Character, or Integer.
255
*/
256
public static int widenSubword(Object x) {
257
if (x instanceof Integer)
258
return (int) x;
259
else if (x instanceof Boolean)
260
return fromBoolean((boolean) x);
261
else if (x instanceof Character)
262
return (char) x;
263
else if (x instanceof Short)
264
return (short) x;
265
else if (x instanceof Byte)
266
return (byte) x;
267
else
268
// Fail with a ClassCastException.
269
return (int) x;
270
}
271
272
/// Converting primitives to references
273
274
static Integer boxInteger(int x) {
275
return x;
276
}
277
278
static Byte boxByte(byte x) {
279
return x;
280
}
281
282
static Short boxShort(short x) {
283
return x;
284
}
285
286
static Boolean boxBoolean(boolean x) {
287
return x;
288
}
289
290
static Character boxCharacter(char x) {
291
return x;
292
}
293
294
static Long boxLong(long x) {
295
return x;
296
}
297
298
static Float boxFloat(float x) {
299
return x;
300
}
301
302
static Double boxDouble(double x) {
303
return x;
304
}
305
306
private static MethodType boxType(Wrapper wrap) {
307
// be exact, since return casts are hard to compose
308
Class<?> boxType = wrap.wrapperType();
309
return MethodType.methodType(boxType, wrap.primitiveType());
310
}
311
312
private static final WrapperCache[] BOX_CONVERSIONS = newWrapperCaches(1);
313
314
public static MethodHandle boxExact(Wrapper wrap) {
315
WrapperCache cache = BOX_CONVERSIONS[0];
316
MethodHandle mh = cache.get(wrap);
317
if (mh != null) {
318
return mh;
319
}
320
// look up the method
321
String name = "box" + wrap.wrapperSimpleName();
322
MethodType type = boxType(wrap);
323
try {
324
mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
325
} catch (ReflectiveOperationException ex) {
326
mh = null;
327
}
328
if (mh != null) {
329
return cache.put(wrap, mh);
330
}
331
throw new IllegalArgumentException("cannot find box adapter for " + wrap);
332
}
333
334
/// Constant functions
335
336
static void ignore(Object x) {
337
// no value to return; this is an unbox of null
338
}
339
340
static void empty() {
341
}
342
343
static Object zeroObject() {
344
return null;
345
}
346
347
static int zeroInteger() {
348
return 0;
349
}
350
351
static long zeroLong() {
352
return 0;
353
}
354
355
static float zeroFloat() {
356
return 0;
357
}
358
359
static double zeroDouble() {
360
return 0;
361
}
362
363
private static final WrapperCache[] CONSTANT_FUNCTIONS = newWrapperCaches(2);
364
365
public static MethodHandle zeroConstantFunction(Wrapper wrap) {
366
WrapperCache cache = CONSTANT_FUNCTIONS[0];
367
MethodHandle mh = cache.get(wrap);
368
if (mh != null) {
369
return mh;
370
}
371
// slow path
372
MethodType type = MethodType.methodType(wrap.primitiveType());
373
switch (wrap) {
374
case VOID:
375
mh = EMPTY;
376
break;
377
case OBJECT:
378
case INT: case LONG: case FLOAT: case DOUBLE:
379
try {
380
mh = IMPL_LOOKUP.findStatic(THIS_CLASS, "zero"+wrap.wrapperSimpleName(), type);
381
} catch (ReflectiveOperationException ex) {
382
mh = null;
383
}
384
break;
385
}
386
if (mh != null) {
387
return cache.put(wrap, mh);
388
}
389
390
// use zeroInt and cast the result
391
if (wrap.isSubwordOrInt() && wrap != Wrapper.INT) {
392
mh = MethodHandles.explicitCastArguments(zeroConstantFunction(Wrapper.INT), type);
393
return cache.put(wrap, mh);
394
}
395
throw new IllegalArgumentException("cannot find zero constant for " + wrap);
396
}
397
398
private static final MethodHandle CAST_REFERENCE, IGNORE, EMPTY;
399
static {
400
try {
401
MethodType idType = MethodType.genericMethodType(1);
402
MethodType ignoreType = idType.changeReturnType(void.class);
403
CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType);
404
IGNORE = IMPL_LOOKUP.findStatic(THIS_CLASS, "ignore", ignoreType);
405
EMPTY = IMPL_LOOKUP.findStatic(THIS_CLASS, "empty", ignoreType.dropParameterTypes(0, 1));
406
} catch (NoSuchMethodException | IllegalAccessException ex) {
407
throw newInternalError("uncaught exception", ex);
408
}
409
}
410
411
public static MethodHandle ignore() {
412
return IGNORE;
413
}
414
415
/** Return a method that casts its second argument (an Object) to the given type (a Class). */
416
public static MethodHandle cast() {
417
return CAST_REFERENCE;
418
}
419
420
/// Primitive conversions.
421
// These are supported directly by the JVM, usually by a single instruction.
422
// In the case of narrowing to a subword, there may be a pair of instructions.
423
// In the case of booleans, there may be a helper routine to manage a 1-bit value.
424
// This is the full 8x8 matrix (minus the diagonal).
425
426
// narrow double to all other types:
427
static float doubleToFloat(double x) { // bytecode: d2f
428
return (float) x;
429
}
430
static long doubleToLong(double x) { // bytecode: d2l
431
return (long) x;
432
}
433
static int doubleToInt(double x) { // bytecode: d2i
434
return (int) x;
435
}
436
static short doubleToShort(double x) { // bytecodes: d2i, i2s
437
return (short) x;
438
}
439
static char doubleToChar(double x) { // bytecodes: d2i, i2c
440
return (char) x;
441
}
442
static byte doubleToByte(double x) { // bytecodes: d2i, i2b
443
return (byte) x;
444
}
445
static boolean doubleToBoolean(double x) {
446
return toBoolean((byte) x);
447
}
448
449
// widen float:
450
static double floatToDouble(float x) { // bytecode: f2d
451
return x;
452
}
453
// narrow float:
454
static long floatToLong(float x) { // bytecode: f2l
455
return (long) x;
456
}
457
static int floatToInt(float x) { // bytecode: f2i
458
return (int) x;
459
}
460
static short floatToShort(float x) { // bytecodes: f2i, i2s
461
return (short) x;
462
}
463
static char floatToChar(float x) { // bytecodes: f2i, i2c
464
return (char) x;
465
}
466
static byte floatToByte(float x) { // bytecodes: f2i, i2b
467
return (byte) x;
468
}
469
static boolean floatToBoolean(float x) {
470
return toBoolean((byte) x);
471
}
472
473
// widen long:
474
static double longToDouble(long x) { // bytecode: l2d
475
return x;
476
}
477
static float longToFloat(long x) { // bytecode: l2f
478
return x;
479
}
480
// narrow long:
481
static int longToInt(long x) { // bytecode: l2i
482
return (int) x;
483
}
484
static short longToShort(long x) { // bytecodes: f2i, i2s
485
return (short) x;
486
}
487
static char longToChar(long x) { // bytecodes: f2i, i2c
488
return (char) x;
489
}
490
static byte longToByte(long x) { // bytecodes: f2i, i2b
491
return (byte) x;
492
}
493
static boolean longToBoolean(long x) {
494
return toBoolean((byte) x);
495
}
496
497
// widen int:
498
static double intToDouble(int x) { // bytecode: i2d
499
return x;
500
}
501
static float intToFloat(int x) { // bytecode: i2f
502
return x;
503
}
504
static long intToLong(int x) { // bytecode: i2l
505
return x;
506
}
507
// narrow int:
508
static short intToShort(int x) { // bytecode: i2s
509
return (short) x;
510
}
511
static char intToChar(int x) { // bytecode: i2c
512
return (char) x;
513
}
514
static byte intToByte(int x) { // bytecode: i2b
515
return (byte) x;
516
}
517
static boolean intToBoolean(int x) {
518
return toBoolean((byte) x);
519
}
520
521
// widen short:
522
static double shortToDouble(short x) { // bytecode: i2d (implicit 's2i')
523
return x;
524
}
525
static float shortToFloat(short x) { // bytecode: i2f (implicit 's2i')
526
return x;
527
}
528
static long shortToLong(short x) { // bytecode: i2l (implicit 's2i')
529
return x;
530
}
531
static int shortToInt(short x) { // (implicit 's2i')
532
return x;
533
}
534
// narrow short:
535
static char shortToChar(short x) { // bytecode: i2c (implicit 's2i')
536
return (char)x;
537
}
538
static byte shortToByte(short x) { // bytecode: i2b (implicit 's2i')
539
return (byte)x;
540
}
541
static boolean shortToBoolean(short x) {
542
return toBoolean((byte) x);
543
}
544
545
// widen char:
546
static double charToDouble(char x) { // bytecode: i2d (implicit 'c2i')
547
return x;
548
}
549
static float charToFloat(char x) { // bytecode: i2f (implicit 'c2i')
550
return x;
551
}
552
static long charToLong(char x) { // bytecode: i2l (implicit 'c2i')
553
return x;
554
}
555
static int charToInt(char x) { // (implicit 'c2i')
556
return x;
557
}
558
// narrow char:
559
static short charToShort(char x) { // bytecode: i2s (implicit 'c2i')
560
return (short)x;
561
}
562
static byte charToByte(char x) { // bytecode: i2b (implicit 'c2i')
563
return (byte)x;
564
}
565
static boolean charToBoolean(char x) {
566
return toBoolean((byte) x);
567
}
568
569
// widen byte:
570
static double byteToDouble(byte x) { // bytecode: i2d (implicit 'b2i')
571
return x;
572
}
573
static float byteToFloat(byte x) { // bytecode: i2f (implicit 'b2i')
574
return x;
575
}
576
static long byteToLong(byte x) { // bytecode: i2l (implicit 'b2i')
577
return x;
578
}
579
static int byteToInt(byte x) { // (implicit 'b2i')
580
return x;
581
}
582
static short byteToShort(byte x) { // bytecode: i2s (implicit 'b2i')
583
return (short)x;
584
}
585
static char byteToChar(byte x) { // bytecode: i2b (implicit 'b2i')
586
return (char)x;
587
}
588
// narrow byte to boolean:
589
static boolean byteToBoolean(byte x) {
590
return toBoolean(x);
591
}
592
593
// widen boolean to all types:
594
static double booleanToDouble(boolean x) {
595
return fromBoolean(x);
596
}
597
static float booleanToFloat(boolean x) {
598
return fromBoolean(x);
599
}
600
static long booleanToLong(boolean x) {
601
return fromBoolean(x);
602
}
603
static int booleanToInt(boolean x) {
604
return fromBoolean(x);
605
}
606
static short booleanToShort(boolean x) {
607
return fromBoolean(x);
608
}
609
static char booleanToChar(boolean x) {
610
return (char)fromBoolean(x);
611
}
612
static byte booleanToByte(boolean x) {
613
return fromBoolean(x);
614
}
615
616
// helpers to force boolean into the conversion scheme:
617
static boolean toBoolean(byte x) {
618
// see javadoc for MethodHandles.explicitCastArguments
619
return ((x & 1) != 0);
620
}
621
static byte fromBoolean(boolean x) {
622
// see javadoc for MethodHandles.explicitCastArguments
623
return (x ? (byte)1 : (byte)0);
624
}
625
626
private static final WrapperCache[] CONVERT_PRIMITIVE_FUNCTIONS = newWrapperCaches(Wrapper.values().length);
627
628
public static MethodHandle convertPrimitive(Wrapper wsrc, Wrapper wdst) {
629
WrapperCache cache = CONVERT_PRIMITIVE_FUNCTIONS[wsrc.ordinal()];
630
MethodHandle mh = cache.get(wdst);
631
if (mh != null) {
632
return mh;
633
}
634
// slow path
635
Class<?> src = wsrc.primitiveType();
636
Class<?> dst = wdst.primitiveType();
637
MethodType type = MethodType.methodType(dst, src);
638
if (wsrc == wdst) {
639
mh = MethodHandles.identity(src);
640
} else {
641
assert(src.isPrimitive() && dst.isPrimitive());
642
try {
643
mh = IMPL_LOOKUP.findStatic(THIS_CLASS, src.getSimpleName()+"To"+capitalize(dst.getSimpleName()), type);
644
} catch (ReflectiveOperationException ex) {
645
mh = null;
646
}
647
}
648
if (mh != null) {
649
assert(mh.type() == type) : mh;
650
return cache.put(wdst, mh);
651
}
652
653
throw new IllegalArgumentException("cannot find primitive conversion function for " +
654
src.getSimpleName()+" -> "+dst.getSimpleName());
655
}
656
657
public static MethodHandle convertPrimitive(Class<?> src, Class<?> dst) {
658
return convertPrimitive(Wrapper.forPrimitiveType(src), Wrapper.forPrimitiveType(dst));
659
}
660
661
private static String capitalize(String x) {
662
return Character.toUpperCase(x.charAt(0))+x.substring(1);
663
}
664
665
// handy shared exception makers (they simplify the common case code)
666
private static InternalError newInternalError(String message, Throwable cause) {
667
return new InternalError(message, cause);
668
}
669
private static InternalError newInternalError(Throwable cause) {
670
return new InternalError(cause);
671
}
672
}
673
674