/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import annotations.BootstrapMethod;
import annotations.CalledByIndy;
import java.lang.invoke.CallSite;
import java.lang.invoke.ConstantCallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
class TestReturnValues extends TestBase {
static CallSite bsm(MethodHandles.Lookup lookup, String name, MethodType methodType)
throws Throwable {
MethodHandle mh = lookup.findStatic(TestReturnValues.class, name, methodType);
return new ConstantCallSite(mh);
}
//
// Methods that pass through a single argument.
// Used to check return path.
//
static byte passThrough(byte value) {
return value;
}
static char passThrough(char value) {
return value;
}
static double passThrough(double value) {
return value;
}
static float passThrough(float value) {
return value;
}
static int passThrough(int value) {
return value;
}
static Object passThrough(Object value) {
return value;
}
static Object[] passThrough(Object[] value) {
return value;
}
static long passThrough(long value) {
return value;
}
static short passThrough(short value) {
return value;
}
static void passThrough() {}
static boolean passThrough(boolean value) {
return value;
}
// byte
@CalledByIndy(
bootstrapMethod =
@BootstrapMethod(enclosingType = TestReturnValues.class, name = "bsm"),
fieldOrMethodName = "passThrough",
returnType = byte.class,
parameterTypes = {byte.class})
private static byte passThroughCallSite(byte value) {
assertNotReached();
return (byte) 0;
}
// char
@CalledByIndy(
bootstrapMethod =
@BootstrapMethod(enclosingType = TestReturnValues.class, name = "bsm"),
fieldOrMethodName = "passThrough",
returnType = char.class,
parameterTypes = {char.class})
private static char passThroughCallSite(char value) {
assertNotReached();
return 'Z';
}
// double
@CalledByIndy(
bootstrapMethod =
@BootstrapMethod(enclosingType = TestReturnValues.class, name = "bsm"),
fieldOrMethodName = "passThrough",
returnType = double.class,
parameterTypes = {double.class})
private static double passThroughCallSite(double value) {
assertNotReached();
return Double.NaN;
}
// float
@CalledByIndy(
bootstrapMethod =
@BootstrapMethod(enclosingType = TestReturnValues.class, name = "bsm"),
fieldOrMethodName = "passThrough",
returnType = float.class,
parameterTypes = {float.class})
private static float passThroughCallSite(float value) {
assertNotReached();
return Float.NaN;
}
// int
@CalledByIndy(
bootstrapMethod =
@BootstrapMethod(enclosingType = TestReturnValues.class, name = "bsm"),
fieldOrMethodName = "passThrough",
returnType = int.class,
parameterTypes = {int.class})
private static int passThroughCallSite(int value) {
assertNotReached();
return 0;
}
// long
@CalledByIndy(
bootstrapMethod =
@BootstrapMethod(enclosingType = TestReturnValues.class, name = "bsm"),
fieldOrMethodName = "passThrough",
returnType = long.class,
parameterTypes = {long.class})
private static long passThroughCallSite(long value) {
assertNotReached();
return Long.MIN_VALUE;
}
// Object
@CalledByIndy(
bootstrapMethod =
@BootstrapMethod(enclosingType = TestReturnValues.class, name = "bsm"),
fieldOrMethodName = "passThrough",
returnType = Object.class,
parameterTypes = {Object.class})
private static Object passThroughCallSite(Object value) {
assertNotReached();
return null;
}
// Object[]
@CalledByIndy(
bootstrapMethod =
@BootstrapMethod(enclosingType = TestReturnValues.class, name = "bsm"),
fieldOrMethodName = "passThrough",
returnType = Object[].class,
parameterTypes = {Object[].class})
private static Object[] passThroughCallSite(Object[] value) {
assertNotReached();
return null;
}
// short
@CalledByIndy(
bootstrapMethod =
@BootstrapMethod(enclosingType = TestReturnValues.class, name = "bsm"),
fieldOrMethodName = "passThrough",
returnType = short.class,
parameterTypes = {short.class})
private static short passThroughCallSite(short value) {
assertNotReached();
return (short) 0;
}
// void
@CalledByIndy(
bootstrapMethod =
@BootstrapMethod(enclosingType = TestReturnValues.class, name = "bsm"),
fieldOrMethodName = "passThrough",
returnType = void.class,
parameterTypes = {})
private static void passThroughCallSite() {
assertNotReached();
}
// boolean
@CalledByIndy(
bootstrapMethod =
@BootstrapMethod(enclosingType = TestReturnValues.class, name = "bsm"),
fieldOrMethodName = "passThrough",
returnType = boolean.class,
parameterTypes = {boolean.class})
private static boolean passThroughCallSite(boolean value) {
assertNotReached();
return false;
}
private static void testByteReturnValues() {
byte[] values = {Byte.MIN_VALUE, Byte.MAX_VALUE};
for (byte value : values) {
assertEquals(value, (byte) passThroughCallSite(value));
}
}
private static void testCharReturnValues() {
char[] values = {
Character.MIN_VALUE,
Character.MAX_HIGH_SURROGATE,
Character.MAX_LOW_SURROGATE,
Character.MAX_VALUE
};
for (char value : values) {
assertEquals(value, (char) passThroughCallSite(value));
}
}
private static void testDoubleReturnValues() {
double[] values = {
Double.MIN_VALUE,
Double.MIN_NORMAL,
Double.NaN,
Double.POSITIVE_INFINITY,
Double.NEGATIVE_INFINITY,
Double.MAX_VALUE
};
for (double value : values) {
assertEquals(value, (double) passThroughCallSite(value));
}
}
private static void testFloatReturnValues() {
float[] values = {
Float.MIN_VALUE,
Float.MIN_NORMAL,
Float.NaN,
Float.POSITIVE_INFINITY,
Float.NEGATIVE_INFINITY,
Float.MAX_VALUE
};
for (float value : values) {
assertEquals(value, (float) passThroughCallSite(value));
}
}
private static void testIntReturnValues() {
int[] values = {Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.SIZE, -Integer.SIZE};
for (int value : values) {
assertEquals(value, (int) passThroughCallSite(value));
}
}
private static void testLongReturnValues() {
long[] values = {Long.MIN_VALUE, Long.MAX_VALUE, (long) Long.SIZE, (long) -Long.SIZE};
for (long value : values) {
assertEquals(value, (long) passThroughCallSite(value));
}
}
private static void testObjectReturnValues() {
Object[] values = {null, "abc", Integer.valueOf(123)};
for (Object value : values) {
assertEquals(value, (Object) passThroughCallSite(value));
}
Object[] otherValues = (Object[]) passThroughCallSite(values);
assertEquals(values.length, otherValues.length);
for (int i = 0; i < otherValues.length; ++i) {
assertEquals(values[i], otherValues[i]);
}
}
private static void testShortReturnValues() {
short[] values = {
Short.MIN_VALUE, Short.MAX_VALUE, (short) Short.SIZE, (short) -Short.SIZE
};
for (short value : values) {
assertEquals(value, (short) passThroughCallSite(value));
}
}
private static void testVoidReturnValues() {
long l = Long.MIN_VALUE;
double d = Double.MIN_VALUE;
passThroughCallSite(); // Initializes call site
assertEquals(Long.MIN_VALUE, l);
assertEquals(Double.MIN_VALUE, d);
l = Long.MAX_VALUE;
d = Double.MAX_VALUE;
passThroughCallSite(); // re-uses existing call site
assertEquals(Long.MAX_VALUE, l);
assertEquals(Double.MAX_VALUE, d);
}
private static void testBooleanReturnValues() {
boolean[] values = {true, false, true, false, false};
for (boolean value : values) {
assertEquals(value, (boolean) passThroughCallSite(value));
}
}
public static void test() {
System.out.println(TestReturnValues.class.getName());
// Two passes here - the first is for the call site creation and invoke path, the second
// for the lookup and invoke path.
for (int pass = 0; pass < 2; ++pass) {
testByteReturnValues(); // B
testCharReturnValues(); // C
testDoubleReturnValues(); // D
testFloatReturnValues(); // F
testIntReturnValues(); // I
testLongReturnValues(); // J
testObjectReturnValues(); // L
testShortReturnValues(); // S
testVoidReturnValues(); // S
testBooleanReturnValues(); // Z
}
}
}