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