Merge "Revert "Support niceness-based priority calls"" into main
diff --git a/libart/src/main/java/java/lang/invoke/StaticFieldVarHandle.java b/libart/src/main/java/java/lang/invoke/StaticFieldVarHandle.java
index c834d76..3b06df2 100644
--- a/libart/src/main/java/java/lang/invoke/StaticFieldVarHandle.java
+++ b/libart/src/main/java/java/lang/invoke/StaticFieldVarHandle.java
@@ -33,7 +33,7 @@
static StaticFieldVarHandle create(Field staticField) {
assert Modifier.isStatic(staticField.getModifiers());
- // TODO(b/379259800): should this be handled at the invocation?
+ // TODO(b/399619087): Make initialization lazy.
MethodHandleStatics.UNSAFE.ensureClassInitialized(staticField.getDeclaringClass());
return new StaticFieldVarHandle(staticField);
}
diff --git a/luni/src/test/java/libcore/java/lang/invoke/MethodHandleAccessorsTest.java b/luni/src/test/java/libcore/java/lang/invoke/MethodHandleAccessorsTest.java
index 50363cf..5465375 100644
--- a/luni/src/test/java/libcore/java/lang/invoke/MethodHandleAccessorsTest.java
+++ b/luni/src/test/java/libcore/java/lang/invoke/MethodHandleAccessorsTest.java
@@ -16,8 +16,6 @@
package libcore.java.lang.invoke;
-import junit.framework.TestCase;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.WrongMethodTypeException;
@@ -26,7 +24,12 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-public class MethodHandleAccessorsTest extends junit.framework.TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class MethodHandleAccessorsTest {
public static class ValueHolder {
public boolean m_z = false;
public byte m_b = 0;
@@ -38,6 +41,16 @@
public long m_j = 0;
public String m_l = "a";
+ public volatile boolean m_v_z = false;
+ public volatile byte m_v_b = 0;
+ public volatile char m_v_c = 'a';
+ public volatile short m_v_s = 0;
+ public volatile int m_v_i = 0;
+ public volatile float m_v_f = 0.0f;
+ public volatile double m_v_d = 0.0;
+ public volatile long m_v_j = 0;
+ public volatile String m_v_l = "a";
+
public static boolean s_z;
public static byte s_b;
public static char s_c;
@@ -48,6 +61,17 @@
public static long s_j;
public static String s_l;
+ public static boolean s_v_z;
+ public static byte s_v_b;
+ public static char s_v_c;
+ public static short s_v_s;
+ public static int s_v_i;
+ public static float s_v_f;
+ public static double s_v_d;
+ public static long s_v_j;
+ public static String s_v_l;
+
+
public final int m_fi = 0xa5a5a5a5;
public static final int s_fi = 0x5a5a5a5a;
}
@@ -533,6 +557,7 @@
resultFor(primitive, PrimitiveType.String, accessor, AccessorType.SGET));
}
+ @Test
public void testBooleanSettersAndGetters() throws Throwable {
ValueHolder valueHolder = new ValueHolder();
MethodHandles.Lookup lookup = MethodHandles.lookup();
@@ -540,19 +565,34 @@
boolean[] booleans = {false, true, false};
for (boolean b : booleans) {
Boolean boxed = Boolean.valueOf(b);
+
tryAccessor(lookup.findSetter(ValueHolder.class, "m_z", boolean.class),
valueHolder, PrimitiveType.Boolean, boxed, AccessorType.IPUT);
tryAccessor(lookup.findGetter(ValueHolder.class, "m_z", boolean.class),
valueHolder, PrimitiveType.Boolean, boxed, AccessorType.IGET);
assertTrue(valueHolder.m_z == b);
+
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_v_z", boolean.class),
+ valueHolder, PrimitiveType.Boolean, boxed, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_v_z", boolean.class),
+ valueHolder, PrimitiveType.Boolean, boxed, AccessorType.IGET);
+ assertTrue(valueHolder.m_v_z == b);
+
tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_z", boolean.class),
valueHolder, PrimitiveType.Boolean, boxed, AccessorType.SPUT);
tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_z", boolean.class),
valueHolder, PrimitiveType.Boolean, boxed, AccessorType.SGET);
assertTrue(ValueHolder.s_z == b);
+
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_v_z", boolean.class),
+ valueHolder, PrimitiveType.Boolean, boxed, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_v_z", boolean.class),
+ valueHolder, PrimitiveType.Boolean, boxed, AccessorType.SGET);
+ assertTrue(ValueHolder.s_v_z == b);
}
}
+ @Test
public void testByteSettersAndGetters() throws Throwable {
ValueHolder valueHolder = new ValueHolder();
MethodHandles.Lookup lookup = MethodHandles.lookup();
@@ -560,19 +600,33 @@
byte[] bytes = {(byte) 0x73, (byte) 0xfe};
for (byte b : bytes) {
Byte boxed = Byte.valueOf(b);
+
tryAccessor(lookup.findSetter(ValueHolder.class, "m_b", byte.class),
valueHolder, PrimitiveType.Byte, boxed, AccessorType.IPUT);
tryAccessor(lookup.findGetter(ValueHolder.class, "m_b", byte.class),
valueHolder, PrimitiveType.Byte, boxed, AccessorType.IGET);
assertTrue(valueHolder.m_b == b);
+
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_v_b", byte.class),
+ valueHolder, PrimitiveType.Byte, boxed, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_v_b", byte.class),
+ valueHolder, PrimitiveType.Byte, boxed, AccessorType.IGET);
+ assertTrue(valueHolder.m_v_b == b);
+
tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_b", byte.class),
valueHolder, PrimitiveType.Byte, boxed, AccessorType.SPUT);
tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_b", byte.class),
valueHolder, PrimitiveType.Byte, boxed, AccessorType.SGET);
assertTrue(ValueHolder.s_b == b);
- }
+
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_v_b", byte.class),
+ valueHolder, PrimitiveType.Byte, boxed, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_v_b", byte.class),
+ valueHolder, PrimitiveType.Byte, boxed, AccessorType.SGET);
+ assertTrue(ValueHolder.s_v_b == b); }
}
+ @Test
public void testCharSettersAndGetters() throws Throwable {
ValueHolder valueHolder = new ValueHolder();
MethodHandles.Lookup lookup = MethodHandles.lookup();
@@ -580,19 +634,34 @@
char[] chars = {'a', 'b', 'c'};
for (char c : chars) {
Character boxed = Character.valueOf(c);
+
tryAccessor(lookup.findSetter(ValueHolder.class, "m_c", char.class),
valueHolder, PrimitiveType.Char, boxed, AccessorType.IPUT);
tryAccessor(lookup.findGetter(ValueHolder.class, "m_c", char.class),
valueHolder, PrimitiveType.Char, boxed, AccessorType.IGET);
assertTrue(valueHolder.m_c == c);
+
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_v_c", char.class),
+ valueHolder, PrimitiveType.Char, boxed, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_v_c", char.class),
+ valueHolder, PrimitiveType.Char, boxed, AccessorType.IGET);
+ assertTrue(valueHolder.m_v_c == c);
+
tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_c", char.class),
valueHolder, PrimitiveType.Char, boxed, AccessorType.SPUT);
tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_c", char.class),
valueHolder, PrimitiveType.Char, boxed, AccessorType.SGET);
assertTrue(ValueHolder.s_c == c);
+
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_v_c", char.class),
+ valueHolder, PrimitiveType.Char, boxed, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_v_c", char.class),
+ valueHolder, PrimitiveType.Char, boxed, AccessorType.SGET);
+ assertTrue(ValueHolder.s_v_c == c);
}
}
+ @Test
public void testShortSettersAndGetters() throws Throwable {
ValueHolder valueHolder = new ValueHolder();
MethodHandles.Lookup lookup = MethodHandles.lookup();
@@ -600,19 +669,34 @@
short[] shorts = {(short) 0x1234, (short) 0x4321};
for (short s : shorts) {
Short boxed = Short.valueOf(s);
+
tryAccessor(lookup.findSetter(ValueHolder.class, "m_s", short.class),
valueHolder, PrimitiveType.Short, boxed, AccessorType.IPUT);
tryAccessor(lookup.findGetter(ValueHolder.class, "m_s", short.class),
valueHolder, PrimitiveType.Short, boxed, AccessorType.IGET);
assertTrue(valueHolder.m_s == s);
+
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_v_s", short.class),
+ valueHolder, PrimitiveType.Short, boxed, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_v_s", short.class),
+ valueHolder, PrimitiveType.Short, boxed, AccessorType.IGET);
+ assertTrue(valueHolder.m_v_s == s);
+
tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_s", short.class),
valueHolder, PrimitiveType.Short, boxed, AccessorType.SPUT);
tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_s", short.class),
valueHolder, PrimitiveType.Short, boxed, AccessorType.SGET);
assertTrue(ValueHolder.s_s == s);
+
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_v_s", short.class),
+ valueHolder, PrimitiveType.Short, boxed, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_v_s", short.class),
+ valueHolder, PrimitiveType.Short, boxed, AccessorType.SGET);
+ assertTrue(ValueHolder.s_v_s == s);
}
}
+ @Test
public void testIntSettersAndGetters() throws Throwable {
ValueHolder valueHolder = new ValueHolder();
MethodHandles.Lookup lookup = MethodHandles.lookup();
@@ -620,19 +704,34 @@
int[] ints = {-100000000, 10000000};
for (int i : ints) {
Integer boxed = Integer.valueOf(i);
+
tryAccessor(lookup.findSetter(ValueHolder.class, "m_i", int.class),
valueHolder, PrimitiveType.Int, boxed, AccessorType.IPUT);
tryAccessor(lookup.findGetter(ValueHolder.class, "m_i", int.class),
valueHolder, PrimitiveType.Int, boxed, AccessorType.IGET);
assertTrue(valueHolder.m_i == i);
+
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_v_i", int.class),
+ valueHolder, PrimitiveType.Int, boxed, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_v_i", int.class),
+ valueHolder, PrimitiveType.Int, boxed, AccessorType.IGET);
+ assertTrue(valueHolder.m_v_i == i);
+
tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_i", int.class),
valueHolder, PrimitiveType.Int, boxed, AccessorType.SPUT);
tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_i", int.class),
valueHolder, PrimitiveType.Int, boxed, AccessorType.SGET);
assertTrue(ValueHolder.s_i == i);
+
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_v_i", int.class),
+ valueHolder, PrimitiveType.Int, boxed, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_v_i", int.class),
+ valueHolder, PrimitiveType.Int, boxed, AccessorType.SGET);
+ assertTrue(ValueHolder.s_v_i == i);
}
}
+ @Test
public void testFloatSettersAndGetters() throws Throwable {
ValueHolder valueHolder = new ValueHolder();
MethodHandles.Lookup lookup = MethodHandles.lookup();
@@ -640,19 +739,34 @@
float[] floats = {0.99f, -1.23e-17f};
for (float f : floats) {
Float boxed = Float.valueOf(f);
+
tryAccessor(lookup.findSetter(ValueHolder.class, "m_f", float.class),
valueHolder, PrimitiveType.Float, boxed, AccessorType.IPUT);
tryAccessor(lookup.findGetter(ValueHolder.class, "m_f", float.class),
valueHolder, PrimitiveType.Float, boxed, AccessorType.IGET);
assertTrue(valueHolder.m_f == f);
+
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_v_f", float.class),
+ valueHolder, PrimitiveType.Float, boxed, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_v_f", float.class),
+ valueHolder, PrimitiveType.Float, boxed, AccessorType.IGET);
+ assertTrue(valueHolder.m_v_f == f);
+
tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_f", float.class),
valueHolder, PrimitiveType.Float, boxed, AccessorType.SPUT);
tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_f", float.class),
valueHolder, PrimitiveType.Float, boxed, AccessorType.SGET);
assertTrue(ValueHolder.s_f == f);
+
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_v_f", float.class),
+ valueHolder, PrimitiveType.Float, boxed, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_v_f", float.class),
+ valueHolder, PrimitiveType.Float, boxed, AccessorType.SGET);
+ assertTrue(ValueHolder.s_v_f == f);
}
}
+ @Test
public void testDoubleSettersAndGetters() throws Throwable {
ValueHolder valueHolder = new ValueHolder();
MethodHandles.Lookup lookup = MethodHandles.lookup();
@@ -665,14 +779,28 @@
tryAccessor(lookup.findGetter(ValueHolder.class, "m_d", double.class),
valueHolder, PrimitiveType.Double, boxed, AccessorType.IGET);
assertTrue(valueHolder.m_d == d);
+
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_v_d", double.class),
+ valueHolder, PrimitiveType.Double, boxed, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_v_d", double.class),
+ valueHolder, PrimitiveType.Double, boxed, AccessorType.IGET);
+ assertTrue(valueHolder.m_v_d == d);
+
tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_d", double.class),
valueHolder, PrimitiveType.Double, boxed, AccessorType.SPUT);
tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_d", double.class),
valueHolder, PrimitiveType.Double, boxed, AccessorType.SGET);
assertTrue(ValueHolder.s_d == d);
+
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_v_d", double.class),
+ valueHolder, PrimitiveType.Double, boxed, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_v_d", double.class),
+ valueHolder, PrimitiveType.Double, boxed, AccessorType.SGET);
+ assertTrue(ValueHolder.s_v_d == d);
}
}
+ @Test
public void testLongSettersAndGetters() throws Throwable {
ValueHolder valueHolder = new ValueHolder();
MethodHandles.Lookup lookup = MethodHandles.lookup();
@@ -680,19 +808,34 @@
long[] longs = {0x0123456789abcdefl, 0xfedcba9876543210l};
for (long j : longs) {
Long boxed = Long.valueOf(j);
+
tryAccessor(lookup.findSetter(ValueHolder.class, "m_j", long.class),
valueHolder, PrimitiveType.Long, boxed, AccessorType.IPUT);
tryAccessor(lookup.findGetter(ValueHolder.class, "m_j", long.class),
valueHolder, PrimitiveType.Long, boxed, AccessorType.IGET);
assertTrue(valueHolder.m_j == j);
+
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_v_j", long.class),
+ valueHolder, PrimitiveType.Long, boxed, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_v_j", long.class),
+ valueHolder, PrimitiveType.Long, boxed, AccessorType.IGET);
+ assertTrue(valueHolder.m_v_j == j);
+
tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_j", long.class),
valueHolder, PrimitiveType.Long, boxed, AccessorType.SPUT);
tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_j", long.class),
valueHolder, PrimitiveType.Long, boxed, AccessorType.SGET);
assertTrue(ValueHolder.s_j == j);
+
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_v_j", long.class),
+ valueHolder, PrimitiveType.Long, boxed, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_v_j", long.class),
+ valueHolder, PrimitiveType.Long, boxed, AccessorType.SGET);
+ assertTrue(ValueHolder.s_v_j == j);
}
}
+ @Test
public void testStringSettersAndGetters() throws Throwable {
ValueHolder valueHolder = new ValueHolder();
MethodHandles.Lookup lookup = MethodHandles.lookup();
@@ -704,14 +847,28 @@
tryAccessor(lookup.findGetter(ValueHolder.class, "m_l", String.class),
valueHolder, PrimitiveType.String, s, AccessorType.IGET);
assertTrue(s.equals(valueHolder.m_l));
+
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_v_l", String.class),
+ valueHolder, PrimitiveType.String, s, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_v_l", String.class),
+ valueHolder, PrimitiveType.String, s, AccessorType.IGET);
+ assertTrue(s.equals(valueHolder.m_v_l));
+
tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_l", String.class),
valueHolder, PrimitiveType.String, s, AccessorType.SPUT);
tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_l", String.class),
valueHolder, PrimitiveType.String, s, AccessorType.SGET);
assertTrue(s.equals(ValueHolder.s_l));
+
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_v_l", String.class),
+ valueHolder, PrimitiveType.String, s, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_v_l", String.class),
+ valueHolder, PrimitiveType.String, s, AccessorType.SGET);
+ assertTrue(s.equals(ValueHolder.s_v_l));
}
}
+ @Test
public void testLookup() throws Throwable {
// NB having a static field test here is essential for
// this test. MethodHandles need to ensure the class
@@ -755,6 +912,7 @@
} catch (IllegalAccessException e) {}
}
+ @Test
public void testStaticGetter() throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle h0 = lookup.findStaticGetter(ValueHolder.class, "s_fi", int.class);
@@ -777,6 +935,7 @@
} catch (WrongMethodTypeException e) {}
}
+ @Test
public void testMemberGetter() throws Throwable {
ValueHolder valueHolder = new ValueHolder();
MethodHandles.Lookup lookup = MethodHandles.lookup();
@@ -810,6 +969,7 @@
return Float.valueOf(-7.77f);
}
+ @Test
public void testMemberSetter() throws Throwable {
ValueHolder valueHolder = new ValueHolder();
MethodHandles.Lookup lookup = MethodHandles.lookup();
@@ -866,6 +1026,7 @@
} catch (WrongMethodTypeException e) {}
}
+ @Test
public void testStaticSetter() throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle h0 = lookup.findStaticSetter(ValueHolder.class, "s_f", float.class);
@@ -919,4 +1080,40 @@
fail();
} catch (WrongMethodTypeException e) {}
}
+
+ @Test
+ public void throws_wmte_when_too_many_arguments_are_supplied() throws Throwable {
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+ MethodHandle setter = lookup.findStaticSetter(ValueHolder.class, "s_f", float.class);
+
+ try {
+ setter.invokeExact(0f, 1);
+ fail("Should throw WMTE");
+ } catch (WrongMethodTypeException ignored) {}
+
+ try {
+ setter.invokeExact(0f, 1, 2);
+ fail("Should throw WMTE");
+ } catch (WrongMethodTypeException ignored) {}
+
+ try {
+ setter.invokeExact(0f, 1, 2, 3);
+ fail("Should throw WMTE");
+ } catch (WrongMethodTypeException ignored) {}
+
+ try {
+ setter.invokeExact(0f, 1, 2, 3, 4);
+ fail("Should throw WMTE");
+ } catch (WrongMethodTypeException ignored) {}
+
+ try {
+ setter.invokeExact(0f, 1, 2, 3, 4, 5);
+ fail("Should throw WMTE");
+ } catch (WrongMethodTypeException ignored) {}
+
+ try {
+ setter.invokeExact(0f, 1, 2, 3, 4, 5, "str");
+ fail("Should throw WMTE");
+ } catch (WrongMethodTypeException ignored) {}
+ }
}
diff --git a/luni/src/test/java/libcore/java/text/DateFormatSymbolsTest.java b/luni/src/test/java/libcore/java/text/DateFormatSymbolsTest.java
index baa3344..eaa5df0 100644
--- a/luni/src/test/java/libcore/java/text/DateFormatSymbolsTest.java
+++ b/luni/src/test/java/libcore/java/text/DateFormatSymbolsTest.java
@@ -16,6 +16,9 @@
package libcore.java.text;
+import libcore.test.annotation.NonMts;
+import libcore.test.reasons.NonMtsReasons;
+
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
@@ -156,6 +159,7 @@
}
// http://b/7955614
+ @NonMts(reason = NonMtsReasons.ICU_VERSION_DEPENDENCY)
public void test_getZoneStrings_Apia() {
String[][] array = DateFormatSymbols.getInstance(Locale.US).getZoneStrings();
@@ -165,9 +169,9 @@
// "GMT" strings for the short names.
if (row[0].equals("Pacific/Apia")) {
TimeZone apiaTz = TimeZone.getTimeZone("Pacific/Apia");
- assertEquals("Apia Standard Time", row[1]);
+ assertEquals("Samoa Standard Time", row[1]);
assertEquals(formattedStandardTimeOffset(apiaTz), row[2]);
- assertEquals("Apia Daylight Time", row[3]);
+ assertEquals("Samoa Daylight Time", row[3]);
assertEquals(formattedDstOffset(apiaTz), row[4]);
}
}
diff --git a/luni/src/test/java/libcore/java/util/TimeZoneTest.java b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
index 2dcd992..f4bcc80 100644
--- a/luni/src/test/java/libcore/java/util/TimeZoneTest.java
+++ b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
@@ -375,10 +375,11 @@
}
// http://b/7955614
+ @NonMts(reason = NonMtsReasons.ICU_VERSION_DEPENDENCY)
public void testApia() {
TimeZone tz = TimeZone.getTimeZone("Pacific/Apia");
- assertEquals("Apia Daylight Time", tz.getDisplayName(true, TimeZone.LONG, Locale.US));
- assertEquals("Apia Standard Time", tz.getDisplayName(false, TimeZone.LONG, Locale.US));
+ assertEquals("Samoa Daylight Time", tz.getDisplayName(true, TimeZone.LONG, Locale.US));
+ assertEquals("Samoa Standard Time", tz.getDisplayName(false, TimeZone.LONG, Locale.US));
long samoaStandardTime = 1630315635000L; // 30 Aug 2021
long samoaDst = 1614504435000L; // 28 Feb 2021
diff --git a/ojluni/src/main/java/java/lang/invoke/DirectMethodHandle.java b/ojluni/src/main/java/java/lang/invoke/DirectMethodHandle.java
new file mode 100644
index 0000000..2495b12
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/invoke/DirectMethodHandle.java
@@ -0,0 +1,572 @@
+/*
+ * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import static java.lang.invoke.MethodHandleStatics.UNSAFE;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import jdk.internal.vm.annotation.ForceInline;
+
+// Android-changed: currently only 4 methods and the Holder class are needed, hence not importing
+// entire file.
+/**
+ * The flavor of method handle which implements a constant reference
+ * to a class member.
+ * @author jrose
+ */
+class DirectMethodHandle {
+
+ @ForceInline
+ /*non-public*/
+ static long fieldOffset(Object accessorObj) {
+ // Note: We return a long because that is what Unsafe.getObject likes.
+ // We store a plain int because it is more compact.
+ // Android-changed: there is only MethodHandleImpl.
+ // return ((Accessor)accessorObj).fieldOffset;
+ return ((MethodHandleImpl) accessorObj).field.getOffset();
+ }
+
+ @ForceInline
+ /*non-public*/
+ static Object checkBase(Object obj) {
+ // Note that the object's class has already been verified,
+ // since the parameter type of the Accessor method handle
+ // is either member.getDeclaringClass or a subclass.
+ // This was verified in DirectMethodHandle.make.
+ // Therefore, the only remaining check is for null.
+ // Since this check is *not* guaranteed by Unsafe.getInt
+ // and its siblings, we need to make an explicit one here.
+ return Objects.requireNonNull(obj);
+ }
+
+
+ @ForceInline
+ /*non-public*/
+ static Object staticBase(Object accessorObj) {
+ // Android-changed: there is only MethodHandleImpl.
+ // return ((StaticAccessor)accessorObj).staticBase;
+ return ((MethodHandleImpl) accessorObj).field.getDeclaringClass();
+ }
+
+ @ForceInline
+ /*non-public*/
+ static long staticOffset(Object accessorObj) {
+ // Android-changed: there is only MethodHandleImpl.
+ // return ((StaticAccessor)accessorObj).staticOffset;
+ return ((MethodHandleImpl) accessorObj).field.getOffset();
+ }
+
+ // BEGIN Android-added: different mechanism to tie actual implementation to a MethodHandle.
+ static Method getImplementation(String name, List<Class<?>> parameters) {
+ return ACCESSOR_IMPLEMENTATIONS.get(new MethodKey(name, parameters));
+ }
+
+ private static final Map<MethodKey, Method> ACCESSOR_IMPLEMENTATIONS;
+
+ static {
+ UNSAFE.ensureClassInitialized(Holder.class);
+
+ // 4 access kinds, 9 basic types and fields can be volatile or non-volatile.
+ HashMap<MethodKey, Method> accessorMethods = HashMap.newHashMap(4 * 9 * 2);
+
+ for (Method m : Holder.class.getDeclaredMethods()) {
+ accessorMethods.put(
+ new MethodKey(m.getName(), Arrays.asList(m.getParameterTypes())), m);
+ }
+
+ ACCESSOR_IMPLEMENTATIONS = Collections.unmodifiableMap(accessorMethods);
+ }
+
+ private static final class MethodKey {
+ private final String name;
+ private final List<Class<?>> arguments;
+
+ MethodKey(String name, List<Class<?>> arguments) {
+ this.name = Objects.requireNonNull(name);
+ this.arguments = Objects.requireNonNull(arguments);
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * name.hashCode() + arguments.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof MethodKey methodKey) {
+ return name.equals(methodKey.name) && arguments.equals(methodKey.arguments);
+ }
+
+ return false;
+ }
+ }
+ // END Android-added: different mechanism to tie actual implementation to a MethodHandle.
+
+ // Android-changed: upstream inserts implementation at the link time (straight to bytecode, w/o
+ // compilation).
+ // Do not change this class manually: check AccessorMethodHandlesGenerator.
+ /* Placeholder class for DirectMethodHandles generated ahead of time */
+ static final class Holder {
+ static void putBoolean(Object base, boolean value, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ UNSAFE.putBoolean(base, offset, value);
+ }
+
+ static void putBooleanVolatile(Object base, boolean value, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ UNSAFE.putBooleanVolatile(base, offset, value);
+ }
+
+ static void putByte(Object base, byte value, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ UNSAFE.putByte(base, offset, value);
+ }
+
+ static void putByteVolatile(Object base, byte value, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ UNSAFE.putByteVolatile(base, offset, value);
+ }
+
+ static void putChar(Object base, char value, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ UNSAFE.putChar(base, offset, value);
+ }
+
+ static void putCharVolatile(Object base, char value, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ UNSAFE.putCharVolatile(base, offset, value);
+ }
+
+ static void putShort(Object base, short value, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ UNSAFE.putShort(base, offset, value);
+ }
+
+ static void putShortVolatile(Object base, short value, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ UNSAFE.putShortVolatile(base, offset, value);
+ }
+
+ static void putInt(Object base, int value, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ UNSAFE.putInt(base, offset, value);
+ }
+
+ static void putIntVolatile(Object base, int value, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ UNSAFE.putIntVolatile(base, offset, value);
+ }
+
+ static void putLong(Object base, long value, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ UNSAFE.putLong(base, offset, value);
+ }
+
+ static void putLongVolatile(Object base, long value, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ UNSAFE.putLongVolatile(base, offset, value);
+ }
+
+ static void putDouble(Object base, double value, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ UNSAFE.putDouble(base, offset, value);
+ }
+
+ static void putDoubleVolatile(Object base, double value, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ UNSAFE.putDoubleVolatile(base, offset, value);
+ }
+
+ static void putFloat(Object base, float value, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ UNSAFE.putFloat(base, offset, value);
+ }
+
+ static void putFloatVolatile(Object base, float value, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ UNSAFE.putFloatVolatile(base, offset, value);
+ }
+
+ static void putReference(Object base, Object value, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ UNSAFE.putReference(base, offset, value);
+ }
+
+ static void putReferenceVolatile(Object base, Object value, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ UNSAFE.putReferenceVolatile(base, offset, value);
+ }
+
+ static boolean getBoolean(Object base, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ return UNSAFE.getBoolean(base, offset);
+ }
+
+ static boolean getBooleanVolatile(Object base, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ return UNSAFE.getBooleanVolatile(base, offset);
+ }
+
+ static byte getByte(Object base, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ return UNSAFE.getByte(base, offset);
+ }
+
+ static byte getByteVolatile(Object base, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ return UNSAFE.getByteVolatile(base, offset);
+ }
+
+ static char getChar(Object base, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ return UNSAFE.getChar(base, offset);
+ }
+
+ static char getCharVolatile(Object base, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ return UNSAFE.getCharVolatile(base, offset);
+ }
+
+ static short getShort(Object base, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ return UNSAFE.getShort(base, offset);
+ }
+
+ static short getShortVolatile(Object base, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ return UNSAFE.getShortVolatile(base, offset);
+ }
+
+ static int getInt(Object base, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ return UNSAFE.getInt(base, offset);
+ }
+
+ static int getIntVolatile(Object base, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ return UNSAFE.getIntVolatile(base, offset);
+ }
+
+ static long getLong(Object base, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ return UNSAFE.getLong(base, offset);
+ }
+
+ static long getLongVolatile(Object base, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ return UNSAFE.getLongVolatile(base, offset);
+ }
+
+ static double getDouble(Object base, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ return UNSAFE.getDouble(base, offset);
+ }
+
+ static double getDoubleVolatile(Object base, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ return UNSAFE.getDoubleVolatile(base, offset);
+ }
+
+ static float getFloat(Object base, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ return UNSAFE.getFloat(base, offset);
+ }
+
+ static float getFloatVolatile(Object base, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ return UNSAFE.getFloatVolatile(base, offset);
+ }
+
+ static Object getReference(Object base, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ return UNSAFE.getReference(base, offset);
+ }
+
+ static Object getReferenceVolatile(Object base, MethodHandleImpl mh) {
+ checkBase(base);
+ long offset = fieldOffset(mh);
+ return UNSAFE.getReferenceVolatile(base, offset);
+ }
+
+ static void putBoolean(boolean value, MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ UNSAFE.putBoolean(base, offset, value);
+ }
+
+ static void putBooleanVolatile(boolean value, MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ UNSAFE.putBooleanVolatile(base, offset, value);
+ }
+
+ static void putByte(byte value, MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ UNSAFE.putByte(base, offset, value);
+ }
+
+ static void putByteVolatile(byte value, MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ UNSAFE.putByteVolatile(base, offset, value);
+ }
+
+ static void putChar(char value, MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ UNSAFE.putChar(base, offset, value);
+ }
+
+ static void putCharVolatile(char value, MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ UNSAFE.putCharVolatile(base, offset, value);
+ }
+
+ static void putShort(short value, MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ UNSAFE.putShort(base, offset, value);
+ }
+
+ static void putShortVolatile(short value, MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ UNSAFE.putShortVolatile(base, offset, value);
+ }
+
+ static void putInt(int value, MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ UNSAFE.putInt(base, offset, value);
+ }
+
+ static void putIntVolatile(int value, MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ UNSAFE.putIntVolatile(base, offset, value);
+ }
+
+ static void putLong(long value, MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ UNSAFE.putLong(base, offset, value);
+ }
+
+ static void putLongVolatile(long value, MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ UNSAFE.putLongVolatile(base, offset, value);
+ }
+
+ static void putDouble(double value, MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ UNSAFE.putDouble(base, offset, value);
+ }
+
+ static void putDoubleVolatile(double value, MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ UNSAFE.putDoubleVolatile(base, offset, value);
+ }
+
+ static void putFloat(float value, MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ UNSAFE.putFloat(base, offset, value);
+ }
+
+ static void putFloatVolatile(float value, MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ UNSAFE.putFloatVolatile(base, offset, value);
+ }
+
+ static void putReference(Object value, MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ UNSAFE.putReference(base, offset, value);
+ }
+
+ static void putReferenceVolatile(Object value, MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ UNSAFE.putReferenceVolatile(base, offset, value);
+ }
+
+ static boolean getBoolean(MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ return UNSAFE.getBoolean(base, offset);
+ }
+
+ static boolean getBooleanVolatile(MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ return UNSAFE.getBooleanVolatile(base, offset);
+ }
+
+ static byte getByte(MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ return UNSAFE.getByte(base, offset);
+ }
+
+ static byte getByteVolatile(MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ return UNSAFE.getByteVolatile(base, offset);
+ }
+
+ static char getChar(MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ return UNSAFE.getChar(base, offset);
+ }
+
+ static char getCharVolatile(MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ return UNSAFE.getCharVolatile(base, offset);
+ }
+
+ static short getShort(MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ return UNSAFE.getShort(base, offset);
+ }
+
+ static short getShortVolatile(MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ return UNSAFE.getShortVolatile(base, offset);
+ }
+
+ static int getInt(MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ return UNSAFE.getInt(base, offset);
+ }
+
+ static int getIntVolatile(MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ return UNSAFE.getIntVolatile(base, offset);
+ }
+
+ static long getLong(MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ return UNSAFE.getLong(base, offset);
+ }
+
+ static long getLongVolatile(MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ return UNSAFE.getLongVolatile(base, offset);
+ }
+
+ static double getDouble(MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ return UNSAFE.getDouble(base, offset);
+ }
+
+ static double getDoubleVolatile(MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ return UNSAFE.getDoubleVolatile(base, offset);
+ }
+
+ static float getFloat(MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ return UNSAFE.getFloat(base, offset);
+ }
+
+ static float getFloatVolatile(MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ return UNSAFE.getFloatVolatile(base, offset);
+ }
+
+ static Object getReference(MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ return UNSAFE.getReference(base, offset);
+ }
+
+ static Object getReferenceVolatile(MethodHandleImpl mh) {
+ Object base = staticBase(mh);
+ long offset = staticOffset(mh);
+ return UNSAFE.getReferenceVolatile(base, offset);
+ }
+ }
+}
diff --git a/ojluni/src/main/java/java/lang/invoke/MethodHandleImpl.java b/ojluni/src/main/java/java/lang/invoke/MethodHandleImpl.java
index db2c932..8a2fa8b 100644
--- a/ojluni/src/main/java/java/lang/invoke/MethodHandleImpl.java
+++ b/ojluni/src/main/java/java/lang/invoke/MethodHandleImpl.java
@@ -26,6 +26,8 @@
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
// Android-changed: Android specific implementation.
// The whole class was implemented from scratch for the Android runtime based
@@ -38,13 +40,71 @@
* @hide
*/
public class MethodHandleImpl extends MethodHandle implements Cloneable {
- private Field field;
+ // TODO(b/297147201): create separate AccessorMethodHandle class and move target and field
+ // into it.
+ // Used by runtime only.
+ private final long target;
private Object targetClassOrMethodHandleInfo;
- private long target;
+ Field field;
MethodHandleImpl(long artFieldOrMethod, int handleKind, MethodType type) {
super(artFieldOrMethod, handleKind, type);
this.targetClassOrMethodHandleInfo = getMemberInternal().getDeclaringClass();
+ this.target = 0;
+ }
+
+ MethodHandleImpl(Field field, int handleKind, MethodType type) {
+ super(field.getArtField(), handleKind, type);
+ // To make sure that we won't operate on uninitialized fields.
+ // TODO (b/399619087): make initialization lazy.
+ MethodHandleStatics.UNSAFE.ensureClassInitialized(field.getDeclaringClass());
+ this.targetClassOrMethodHandleInfo = getMemberInternal().getDeclaringClass();
+ this.field = field;
+ this.target = resolveTarget(handleKind, field);
+ }
+
+ private static long resolveTarget(int handleKind, Field field) {
+ StringBuilder name = new StringBuilder();
+
+ if (handleKind == MethodHandle.SGET || handleKind == MethodHandle.IGET) {
+ name.append("get");
+ } else if (handleKind == MethodHandle.SPUT || handleKind == MethodHandle.IPUT) {
+ name.append("put");
+ } else {
+ throw new AssertionError("Unexpected handleKind: " + handleKind);
+ }
+
+ Class<?> type = field.getType();
+
+ if (type.isPrimitive()) {
+ String fieldTypeName = type.getName();
+ name.append(Character.toUpperCase(fieldTypeName.charAt(0)));
+ name.append(fieldTypeName.substring(1));
+ } else {
+ name.append("Reference");
+ }
+
+ if (Modifier.isVolatile(field.getModifiers())) {
+ name.append("Volatile");
+ }
+
+ List<Class<?>> signature = new ArrayList<>(3);
+ if (!Modifier.isStatic(field.getModifiers())) {
+ signature.add(Object.class);
+ }
+ if (handleKind == MethodHandle.SPUT || handleKind == MethodHandle.IPUT) {
+ if (type.isPrimitive()) {
+ signature.add(type);
+ } else {
+ signature.add(Object.class);
+ }
+ }
+ signature.add(MethodHandleImpl.class);
+ Method target = DirectMethodHandle.getImplementation(name.toString(), signature);
+ if (target == null) {
+ throw new InternalError("DirectMethodHandle$Holder is missing a method");
+ }
+ return target.getArtMethod();
}
@Override
diff --git a/ojluni/src/main/java/java/lang/invoke/MethodHandles.java b/ojluni/src/main/java/java/lang/invoke/MethodHandles.java
index c6f7162..7bd59b2 100644
--- a/ojluni/src/main/java/java/lang/invoke/MethodHandles.java
+++ b/ojluni/src/main/java/java/lang/invoke/MethodHandles.java
@@ -1545,7 +1545,7 @@
default:
throw new IllegalArgumentException("Invalid kind " + kind);
}
- return new MethodHandleImpl(field.getArtField(), kind, methodType);
+ return new MethodHandleImpl(field, kind, methodType);
}
/**
diff --git a/openjdk_java_files.bp b/openjdk_java_files.bp
index 9dc4a79..b8057de 100644
--- a/openjdk_java_files.bp
+++ b/openjdk_java_files.bp
@@ -262,6 +262,7 @@
"ojluni/src/main/java/java/lang/invoke/LambdaConversionException.java",
"ojluni/src/main/java/java/lang/invoke/CallSite.java",
"ojluni/src/main/java/java/lang/invoke/ConstantCallSite.java",
+ "ojluni/src/main/java/java/lang/invoke/DirectMethodHandle.java",
"ojluni/src/main/java/java/lang/invoke/MethodHandle.java",
"ojluni/src/main/java/java/lang/invoke/MethodHandles.java",
"ojluni/src/main/java/java/lang/invoke/MethodHandleImpl.java",
diff --git a/tools/codegen/Android.bp b/tools/codegen/Android.bp
new file mode 100644
index 0000000..a7fb857
--- /dev/null
+++ b/tools/codegen/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2025 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.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "libcore_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["libcore_license"],
+}
+
+java_binary_host {
+ name: "libcore-methodhandles-accessors-codegen",
+ srcs: ["src/**/*.java"],
+ manifest: "src/manifest.txt",
+}
diff --git a/tools/codegen/src/libcore/codegen/AccessorMethodHandlesGenerator.java b/tools/codegen/src/libcore/codegen/AccessorMethodHandlesGenerator.java
new file mode 100644
index 0000000..1814f9d
--- /dev/null
+++ b/tools/codegen/src/libcore/codegen/AccessorMethodHandlesGenerator.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2025 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.
+ */
+
+package libcore.codegen;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.StringJoiner;
+
+/**
+ * Generates methods of {@link DirectMethodHandle.Holder} class.
+ */
+public class AccessorMethodHandlesGenerator {
+
+ static String capitalize(String str) {
+ if (str.isEmpty()) {
+ throw new IllegalArgumentException("Can't capitalize empty string");
+ }
+ return Character.toUpperCase(str.charAt(0)) + str.substring(1);
+ }
+
+ enum HandleKind {
+ IPUT,
+ IGET,
+ SPUT,
+ SGET;
+
+ public boolean isStatic() {
+ return this == SGET || this == SPUT;
+ }
+ public boolean isPut() {
+ return this == IPUT || this == SPUT;
+ }
+ public boolean isGet() {
+ return !isPut();
+ }
+
+ /* Prefix of a method in Holder class implementing this HandleKind. */
+ public String prefix() {
+ if (isPut()) {
+ return "put";
+ } else {
+ return "get";
+ }
+ }
+ }
+
+ enum BasicType {
+ BOOLEAN,
+ BYTE,
+ CHAR,
+ SHORT,
+ INT,
+ LONG,
+ DOUBLE,
+ FLOAT,
+ REFERENCE;
+
+ public String typeName() {
+ return this == REFERENCE ? "Object" : name().toLowerCase(Locale.ROOT);
+ }
+
+ /* Returns a string corresponding to a method parameter of this type named as paramName,
+ * for example "int paramName".
+ */
+ public String param(String paramName) {
+ return typeName() + " " + paramName;
+ }
+ }
+
+ static String parameters(HandleKind kind, BasicType actingUpon) {
+ var params = new ArrayList<String>();
+ if (!kind.isStatic()) {
+ params.add(BasicType.REFERENCE.param("base"));
+ }
+
+ if (kind.isPut()) {
+ params.add(actingUpon.param("value"));
+ }
+
+ // There is always MethodHandle object.
+ params.add("MethodHandleImpl mh");
+
+ return String.join(", ", params);
+ }
+
+ static String function(HandleKind kind, BasicType actingUpon, boolean isVolatile) {
+ var sb = new StringBuilder();
+ var modifiersAndReturnType = new StringJoiner(" ");
+ modifiersAndReturnType.add("static");
+ if (kind.isPut()) {
+ modifiersAndReturnType.add("void");
+ } else {
+ modifiersAndReturnType.add(actingUpon.typeName());
+ }
+ sb.append(modifiersAndReturnType).append(" ");
+ sb.append(kind.prefix()).append(capitalize(actingUpon.name().toLowerCase(Locale.ROOT)));
+ if (isVolatile) {
+ sb.append("Volatile");
+ }
+ sb.append("(").append(parameters(kind, actingUpon)).append(") {\n");
+
+ if (kind.isStatic()) {
+ sb.append(" ").append("Object base = staticBase(mh);\n");
+ sb.append(" ").append("long offset = staticOffset(mh);\n");
+ } else {
+ sb.append(" ").append("checkBase(base);\n");
+ sb.append(" ").append("long offset = fieldOffset(mh);\n");
+ }
+ var accessMode = isVolatile ? "Volatile" : "";
+ sb.append(" ");
+ if (kind.isGet()) {
+ sb.append("return UNSAFE.")
+ .append(kind.prefix())
+ .append(capitalize(actingUpon.name().toLowerCase(Locale.ROOT)))
+ .append(accessMode)
+ .append("(base, offset);");
+ } else {
+ sb.append("UNSAFE.")
+ .append(kind.prefix())
+ .append(capitalize(actingUpon.name().toLowerCase(Locale.ROOT)))
+ .append(accessMode)
+ .append("(base, offset, value);");
+ }
+
+ sb.append("\n}\n");
+ return sb.toString();
+ }
+
+ public static void main(String[] args) {
+ for (HandleKind kind : HandleKind.values()) {
+ for (BasicType name : BasicType.values()) {
+ for (boolean isVolatile : List.of(false, true)) {
+ System.out.println(function(kind, name, isVolatile));
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/codegen/src/manifest.txt b/tools/codegen/src/manifest.txt
new file mode 100644
index 0000000..452cead9
--- /dev/null
+++ b/tools/codegen/src/manifest.txt
@@ -0,0 +1 @@
+Main-Class: libcore.codegen.AccessorMethodHandlesGenerator
\ No newline at end of file