From 57494c431d51ba2a87f218fa2bdb7ef9c188d469 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Fri, 11 Mar 2016 15:30:20 -0800 Subject: [PATCH 01/36] 8151750: Mark ChangingInterests.java as intermittently failing Reviewed-by: lancea --- jdk/test/java/nio/channels/Selector/ChangingInterests.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jdk/test/java/nio/channels/Selector/ChangingInterests.java b/jdk/test/java/nio/channels/Selector/ChangingInterests.java index c3e1dbd0964..bd8ab27a1b5 100644 --- a/jdk/test/java/nio/channels/Selector/ChangingInterests.java +++ b/jdk/test/java/nio/channels/Selector/ChangingInterests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, 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 @@ -23,6 +23,7 @@ /* @test * @bug 7200742 + * @key intermittent * @summary Test that Selector doesn't spin when changing interest ops */ From 1c1cec5a6f54edfab2c4f5c5ffc6c1309e15c7d3 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Fri, 11 Mar 2016 17:07:57 -0800 Subject: [PATCH 02/36] 8151734: Mark Unreachable.java and MaxRetries.java as intermittently failing Reviewed-by: weijun --- jdk/test/sun/security/krb5/auto/MaxRetries.java | 3 ++- jdk/test/sun/security/krb5/auto/Unreachable.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/jdk/test/sun/security/krb5/auto/MaxRetries.java b/jdk/test/sun/security/krb5/auto/MaxRetries.java index 5c5da91653f..d23cd1043b5 100644 --- a/jdk/test/sun/security/krb5/auto/MaxRetries.java +++ b/jdk/test/sun/security/krb5/auto/MaxRetries.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, 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 @@ -24,6 +24,7 @@ /* * @test * @bug 6844193 + * @key intermittent * @compile -XDignore.symbol.file MaxRetries.java * @run main/othervm/timeout=300 MaxRetries * @summary support max_retries in krb5.conf diff --git a/jdk/test/sun/security/krb5/auto/Unreachable.java b/jdk/test/sun/security/krb5/auto/Unreachable.java index 52339786a9f..b010b54837e 100644 --- a/jdk/test/sun/security/krb5/auto/Unreachable.java +++ b/jdk/test/sun/security/krb5/auto/Unreachable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, 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 @@ -24,6 +24,7 @@ /* * @test * @bug 7162687 + * @key intermittent * @summary enhance KDC server availability detection * @compile -XDignore.symbol.file Unreachable.java * @run main/othervm/timeout=10 Unreachable From bfb7e8cd0755d7c2a4411afa999e786eb97a8319 Mon Sep 17 00:00:00 2001 From: Michael Haupt Date: Sun, 13 Mar 2016 20:26:29 +0100 Subject: [PATCH 03/36] 8150782: findClass / accessClass throw unexpected exceptions Reviewed-by: sundar --- .../java/lang/invoke/MethodHandles.java | 19 +++- .../lang/invoke/t8150782/TestAccessClass.java | 80 +++++++++++++++++ .../java/lang/invoke/t8150782/TestCls.java | 38 ++++++++ .../lang/invoke/t8150782/TestFindClass.java | 90 +++++++++++++++++++ .../java/lang/invoke/t8150782/TestLookup.java | 67 ++++++++++++++ 5 files changed, 292 insertions(+), 2 deletions(-) create mode 100644 jdk/test/java/lang/invoke/t8150782/TestAccessClass.java create mode 100644 jdk/test/java/lang/invoke/t8150782/TestCls.java create mode 100644 jdk/test/java/lang/invoke/t8150782/TestFindClass.java create mode 100644 jdk/test/java/lang/invoke/t8150782/TestLookup.java diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index 70791273212..dea7d6c6c14 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -99,13 +99,16 @@ public class MethodHandles { *

* As a matter of pure convention, the {@linkplain Lookup#lookupClass lookup class} * of this lookup object will be {@link java.lang.Object}. + * Consequently, the lookup context of this lookup object will be the bootstrap + * class loader, which means it cannot find user classes. * *

* Discussion: * The lookup class can be changed to any other class {@code C} using an expression of the form * {@link Lookup#in publicLookup().in(C.class)}. * Since all classes have equal access to public names, - * such a change would confer no new access rights. + * such a change would confer no new access rights, + * but may change the lookup context by virtue of changing the class loader. * A public lookup object is always subject to * security manager checks. * Also, it cannot access @@ -641,6 +644,11 @@ public class MethodHandles { * then no members, not even public members, will be accessible. * (In all other cases, public members will continue to be accessible.) * + *

+ * The resulting lookup's capabilities for loading classes + * (used during {@link #findClass} invocations) + * are determined by the lookup class' loader, + * which may change due to this operation. * * @param requestedLookupClass the desired lookup class for the new lookup object * @return a lookup object which reports the desired lookup class @@ -939,13 +947,17 @@ assertEquals("[x, y, z]", pb.command().toString()); /** * Looks up a class by name from the lookup context defined by this {@code Lookup} object. The static * initializer of the class is not run. + *

+ * The lookup context here is determined by the {@linkplain #lookupClass() lookup class}, its class + * loader, and the {@linkplain #lookupModes() lookup modes}. In particular, the method first attempts to + * load the requested class, and then determines whether the class is accessible to this lookup object. * * @param targetName the fully qualified name of the class to be looked up. * @return the requested class. * @exception SecurityException if a security manager is present and it * refuses access * @throws LinkageError if the linkage fails - * @throws ClassNotFoundException if the class does not exist. + * @throws ClassNotFoundException if the class cannot be loaded by the lookup class' loader. * @throws IllegalAccessException if the class is not accessible, using the allowed access * modes. * @exception SecurityException if a security manager is present and it @@ -960,6 +972,9 @@ assertEquals("[x, y, z]", pb.command().toString()); /** * Determines if a class can be accessed from the lookup context defined by this {@code Lookup} object. The * static initializer of the class is not run. + *

+ * The lookup context here is determined by the {@linkplain #lookupClass() lookup class} and the + * {@linkplain #lookupModes() lookup modes}. * * @param targetClass the class to be access-checked * diff --git a/jdk/test/java/lang/invoke/t8150782/TestAccessClass.java b/jdk/test/java/lang/invoke/t8150782/TestAccessClass.java new file mode 100644 index 00000000000..5acf3f3bee0 --- /dev/null +++ b/jdk/test/java/lang/invoke/t8150782/TestAccessClass.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2016, 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. + */ + +/* @test + * @compile TestAccessClass.java TestCls.java + * @run testng/othervm -ea -esa test.java.lang.invoke.t8150782.TestAccessClass + */ +package test.java.lang.invoke.t8150782; + +import java.lang.invoke.*; + +import static java.lang.invoke.MethodHandles.*; + +import static org.testng.AssertJUnit.*; + +import org.testng.annotations.*; + +public class TestAccessClass { + + private static boolean initializedClass1; + + private static class Class1 { + static { + initializedClass1 = true; + } + } + + @Test + public void initializerNotRun() throws IllegalAccessException { + lookup().accessClass(Class1.class); + assertFalse(initializedClass1); + } + + @Test + public void returnsSameClass() throws IllegalAccessException, ClassNotFoundException { + Class aClass = lookup().accessClass(Class1.class); + assertEquals(Class1.class, aClass); + } + + @DataProvider + Object[][] illegalAccessAccess() { + return new Object[][] { + {publicLookup(), Class1.class}, + {publicLookup(), TestCls.getPrivateSIC()} + }; + } + + @Test(dataProvider = "illegalAccessAccess", expectedExceptions = {IllegalAccessException.class}) + public void illegalAccessExceptionTest(Lookup lookup, Class klass) throws IllegalAccessException, ClassNotFoundException { + lookup.accessClass(klass); + } + + @Test + public void okAccess() throws IllegalAccessException { + lookup().accessClass(TestCls.getPrivateSIC()); + } + +} diff --git a/jdk/test/java/lang/invoke/t8150782/TestCls.java b/jdk/test/java/lang/invoke/t8150782/TestCls.java new file mode 100644 index 00000000000..1aec2657d0a --- /dev/null +++ b/jdk/test/java/lang/invoke/t8150782/TestCls.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016, 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 test.java.lang.invoke.t8150782; + +import static java.lang.invoke.MethodHandles.*; + +public class TestCls { + + public static final Lookup LOOKUP = lookup(); + + private static class PrivateSIC {} + public static Class getPrivateSIC() { return PrivateSIC.class; } + public static Lookup getLookupForPrivateSIC() { return lookup(); } + +} + diff --git a/jdk/test/java/lang/invoke/t8150782/TestFindClass.java b/jdk/test/java/lang/invoke/t8150782/TestFindClass.java new file mode 100644 index 00000000000..b49118c2b16 --- /dev/null +++ b/jdk/test/java/lang/invoke/t8150782/TestFindClass.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2016, 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. + */ + +/* @test + * @compile TestFindClass.java TestCls.java + * @run testng/othervm -ea -esa test.java.lang.invoke.t8150782.TestFindClass + */ +package test.java.lang.invoke.t8150782; + +import java.lang.invoke.*; + +import static java.lang.invoke.MethodHandles.*; + +import static org.testng.AssertJUnit.*; + +import org.testng.annotations.*; + +public class TestFindClass { + + private static final String PACKAGE_PREFIX = "test.java.lang.invoke.t8150782."; + + private static boolean initializedClass1; + + private static class Class1 { + static { + initializedClass1 = true; + } + } + + @Test + public void initializerNotRun() throws IllegalAccessException, ClassNotFoundException { + lookup().findClass(PACKAGE_PREFIX + "TestFindClass$Class1"); + assertFalse(initializedClass1); + } + + @Test + public void returnsRequestedClass() throws IllegalAccessException, ClassNotFoundException { + Class aClass = lookup().findClass(PACKAGE_PREFIX + "TestFindClass$Class1"); + assertEquals(Class1.class, aClass); + } + + @Test(expectedExceptions = {ClassNotFoundException.class}) + public void classNotFoundExceptionTest() throws IllegalAccessException, ClassNotFoundException { + lookup().findClass(PACKAGE_PREFIX + "TestFindClass$NonExistent"); + } + + @DataProvider + Object[][] illegalAccessFind() { + return new Object[][] { + {publicLookup(), PACKAGE_PREFIX + "TestFindClass$Class1"}, + {publicLookup(), PACKAGE_PREFIX + "TestCls$PrivateSIC"} + }; + } + + /** + * Assertion: @throws IllegalAccessException if the class is not accessible, using the allowed access modes. + */ + @Test(dataProvider = "illegalAccessFind", expectedExceptions = {ClassNotFoundException.class}) + public void illegalAccessExceptionTest(Lookup lookup, String className) throws IllegalAccessException, ClassNotFoundException { + lookup.findClass(className); + } + + @Test + public void okAccess() throws IllegalAccessException, ClassNotFoundException { + lookup().findClass(PACKAGE_PREFIX + "TestCls$PrivateSIC"); + } + +} diff --git a/jdk/test/java/lang/invoke/t8150782/TestLookup.java b/jdk/test/java/lang/invoke/t8150782/TestLookup.java new file mode 100644 index 00000000000..9a3e2cd9085 --- /dev/null +++ b/jdk/test/java/lang/invoke/t8150782/TestLookup.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016, 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. + */ + +/* @test + * @run testng/othervm -ea -esa test.java.lang.invoke.t8150782.TestLookup + */ +package test.java.lang.invoke.t8150782; + +import org.testng.annotations.Test; + +import static java.lang.invoke.MethodHandles.*; + +import static org.testng.AssertJUnit.*; + +public class TestLookup { + + @Test + public void testClassLoaderChange() { + Lookup lookup = lookup(); + assertNotNull(lookup.lookupClass().getClassLoader()); + Lookup lookup2 = lookup.in(Object.class); + assertNull(lookup2.lookupClass().getClassLoader()); + } + + @Test(expectedExceptions = {ClassNotFoundException.class}) + public void testPublicCannotLoadUserClass() throws IllegalAccessException, ClassNotFoundException { + Lookup lookup = publicLookup(); + lookup.findClass("test.java.lang.invoke.t8150782.TestCls"); + } + + @Test + public void testPublicCanLoadSystemClass() throws IllegalAccessException, ClassNotFoundException { + Lookup lookup = publicLookup(); + lookup.findClass("java.util.HashMap"); + } + + @Test + public void testPublicInChangesClassLoader() { + Lookup lookup = publicLookup(); + assertNull(lookup.lookupClass().getClassLoader()); + Lookup lookup2 = lookup.in(TestCls.class); + assertNotNull(lookup2.lookupClass().getClassLoader()); + } + +} From cc3d80e38ac213233aa69b468597cf46e90c3857 Mon Sep 17 00:00:00 2001 From: Michael Haupt Date: Mon, 14 Mar 2016 08:10:44 +0100 Subject: [PATCH 04/36] 8151778: TestLookup.java fails after push of JDK-8150782 Reviewed-by: darcy --- jdk/test/java/lang/invoke/t8150782/TestLookup.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/test/java/lang/invoke/t8150782/TestLookup.java b/jdk/test/java/lang/invoke/t8150782/TestLookup.java index 9a3e2cd9085..833ac70f254 100644 --- a/jdk/test/java/lang/invoke/t8150782/TestLookup.java +++ b/jdk/test/java/lang/invoke/t8150782/TestLookup.java @@ -24,6 +24,7 @@ */ /* @test + * @compile TestLookup.java TestCls.java * @run testng/othervm -ea -esa test.java.lang.invoke.t8150782.TestLookup */ package test.java.lang.invoke.t8150782; From c53d88d41f668950d44ef7c4f1059c43ea9dab8f Mon Sep 17 00:00:00 2001 From: Amy Lu Date: Mon, 14 Mar 2016 19:46:19 +0800 Subject: [PATCH 05/36] 8151798: Mark java/util/TimeZone/Bug6772689.java as intermittently failing and demote to tier2 Reviewed-by: lancea --- jdk/test/TEST.groups | 2 ++ jdk/test/java/util/TimeZone/Bug6772689.java | 1 + 2 files changed, 3 insertions(+) diff --git a/jdk/test/TEST.groups b/jdk/test/TEST.groups index ea9a6d6fa7e..8b3a337c346 100644 --- a/jdk/test/TEST.groups +++ b/jdk/test/TEST.groups @@ -32,6 +32,7 @@ tier1 = \ -java/util/WeakHashMap/GCDuringIteration.java \ -java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java \ -java/util/concurrent/forkjoin/FJExceptionTableLeak.java \ + -java/util/TimeZone/Bug6772689.java \ sun/nio/cs/ISO8859x.java \ java/nio/Buffer \ com/sun/crypto/provider/Cipher \ @@ -42,6 +43,7 @@ tier2 = \ java/util/WeakHashMap/GCDuringIteration.java \ java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java \ java/util/concurrent/forkjoin/FJExceptionTableLeak.java \ + java/util/TimeZone/Bug6772689.java \ :jdk_io \ :jdk_nio \ -sun/nio/cs/ISO8859x.java \ diff --git a/jdk/test/java/util/TimeZone/Bug6772689.java b/jdk/test/java/util/TimeZone/Bug6772689.java index f730567013d..a1ce49682b4 100644 --- a/jdk/test/java/util/TimeZone/Bug6772689.java +++ b/jdk/test/java/util/TimeZone/Bug6772689.java @@ -24,6 +24,7 @@ /* * @test * @bug 6772689 + * @key intermittent * @summary Test for standard-to-daylight transitions at midnight: * date stays on the given day. */ From c6a6f496a86de67082b1535c5e0053bf27ec45de Mon Sep 17 00:00:00 2001 From: Abhijit Roy Date: Sat, 12 Mar 2016 00:58:39 +0530 Subject: [PATCH 06/36] 8151062: Unclosed parenthesis in java.util.EnumMap.clone() Javadoc Reviewed-by: rriggs --- jdk/src/java.base/share/classes/java/util/EnumMap.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/java.base/share/classes/java/util/EnumMap.java b/jdk/src/java.base/share/classes/java/util/EnumMap.java index 686a0a9b98e..e6d63cf4ae8 100644 --- a/jdk/src/java.base/share/classes/java/util/EnumMap.java +++ b/jdk/src/java.base/share/classes/java/util/EnumMap.java @@ -718,7 +718,7 @@ public class EnumMap, V> extends AbstractMap } /** - * Returns a shallow copy of this enum map. (The values themselves + * Returns a shallow copy of this enum map. The values themselves * are not cloned. * * @return a shallow copy of this enum map From 887760ee885c5aa796e625e356f67a501f6f65ec Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Mon, 14 Mar 2016 10:48:18 -0700 Subject: [PATCH 07/36] 8151835: Mark SmallPrimeExponentP.java as intermittently failing Reviewed-by: vinnie --- jdk/test/sun/security/mscapi/SmallPrimeExponentP.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/test/sun/security/mscapi/SmallPrimeExponentP.java b/jdk/test/sun/security/mscapi/SmallPrimeExponentP.java index 1ee0f5bb069..0013bd86e03 100644 --- a/jdk/test/sun/security/mscapi/SmallPrimeExponentP.java +++ b/jdk/test/sun/security/mscapi/SmallPrimeExponentP.java @@ -32,6 +32,7 @@ import java.security.interfaces.RSAPrivateCrtKey; /* * @test * @bug 8023546 + * @key intermittent * @modules java.base/sun.security.x509 * java.base/sun.security.tools.keytool * @summary sun/security/mscapi/ShortRSAKey1024.sh fails intermittently From 04c17721d6d45ba7426ff63f0f76f23a39dbccc3 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Mon, 14 Mar 2016 16:13:09 -0700 Subject: [PATCH 08/36] 8151847: rmic should support v53 classfiles Reviewed-by: alanb --- .../share/classes/sun/tools/java/RuntimeConstants.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/src/jdk.rmic/share/classes/sun/tools/java/RuntimeConstants.java b/jdk/src/jdk.rmic/share/classes/sun/tools/java/RuntimeConstants.java index 87fa33f6197..1c7ada16f06 100644 --- a/jdk/src/jdk.rmic/share/classes/sun/tools/java/RuntimeConstants.java +++ b/jdk/src/jdk.rmic/share/classes/sun/tools/java/RuntimeConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, 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 @@ -67,7 +67,7 @@ public interface RuntimeConstants { /* Class File Constants */ int JAVA_MAGIC = 0xcafebabe; int JAVA_MIN_SUPPORTED_VERSION = 45; - int JAVA_MAX_SUPPORTED_VERSION = 52; + int JAVA_MAX_SUPPORTED_VERSION = 53; int JAVA_MAX_SUPPORTED_MINOR_VERSION = 0; /* Generate class file version for 1.1 by default */ From 569de7b0ea85f9bd95e0bc53966f329f60a9dfec Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Tue, 15 Mar 2016 12:38:35 +0800 Subject: [PATCH 09/36] 8151785: Doc typo in src/../java/util/stream/PipelineHelper.java Change from "intoWrapped" to "copyInto". Reviewed-by: rriggs --- .../share/classes/java/util/stream/PipelineHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/java.base/share/classes/java/util/stream/PipelineHelper.java b/jdk/src/java.base/share/classes/java/util/stream/PipelineHelper.java index 081f68d1a0e..8d989930386 100644 --- a/jdk/src/java.base/share/classes/java/util/stream/PipelineHelper.java +++ b/jdk/src/java.base/share/classes/java/util/stream/PipelineHelper.java @@ -98,7 +98,7 @@ abstract class PipelineHelper { * @implSpec * The implementation behaves as if: *

{@code
-     *     intoWrapped(wrapSink(sink), spliterator);
+     *     copyInto(wrapSink(sink), spliterator);
      * }
* * @param sink the {@code Sink} to receive the results From 99bfb14042e8d9ba3aa28dcdd015e0a2042f0a5f Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Tue, 1 Mar 2016 12:33:04 -0800 Subject: [PATCH 10/36] 8147755: ASM should create correct constant tag for invokestatic on handle point to interface static method Updates asm to v5.1 Reviewed-by: forax --- .../org/objectweb/asm/ClassReader.java | 27 +- .../org/objectweb/asm/ClassWriter.java | 47 +- .../jdk/internal/org/objectweb/asm/Frame.java | 2 +- .../internal/org/objectweb/asm/Handle.java | 60 +- .../jdk/internal/org/objectweb/asm/Label.java | 9 +- .../org/objectweb/asm/MethodVisitor.java | 19 +- .../org/objectweb/asm/MethodWriter.java | 14 +- .../jdk/internal/org/objectweb/asm/Type.java | 14 +- .../internal/org/objectweb/asm/TypePath.java | 8 +- .../org/objectweb/asm/TypeReference.java | 44 +- .../objectweb/asm/commons/AdviceAdapter.java | 4 +- .../asm/commons/AnnotationRemapper.java | 108 +++ .../objectweb/asm/commons/ClassRemapper.java | 161 ++++ .../objectweb/asm/commons/FieldRemapper.java | 100 +++ .../asm/commons/InstructionAdapter.java | 2 +- .../asm/commons/LocalVariablesSorter.java | 14 - .../objectweb/asm/commons/MethodRemapper.java | 252 ++++++ .../org/objectweb/asm/commons/Remapper.java | 23 +- .../commons/RemappingAnnotationAdapter.java | 2 + .../asm/commons/RemappingClassAdapter.java | 2 + .../asm/commons/RemappingFieldAdapter.java | 2 + .../asm/commons/RemappingMethodAdapter.java | 2 + .../commons/RemappingSignatureAdapter.java | 2 + .../asm/commons/SerialVersionUIDAdder.java | 7 +- .../asm/commons/SignatureRemapper.java | 188 +++++ .../objectweb/asm/commons/SimpleRemapper.java | 6 + .../asm/signature/SignatureVisitor.java | 8 +- .../asm/signature/SignatureWriter.java | 4 +- .../org/objectweb/asm/tree/InsnList.java | 3 + .../org/objectweb/asm/util/ASMifier.java | 12 +- .../asm/util/CheckMethodAdapter.java | 3 + .../org/objectweb/asm/util/Printer.java | 786 ++++++++++++++++-- .../objectweb/asm/util/TraceClassVisitor.java | 26 +- .../asm/util/TraceSignatureVisitor.java | 14 +- .../internal/org/objectweb/asm/version.txt | 8 +- 35 files changed, 1773 insertions(+), 210 deletions(-) create mode 100644 jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AnnotationRemapper.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/ClassRemapper.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/FieldRemapper.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/MethodRemapper.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SignatureRemapper.java diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java index c9bf9d30225..523851fd70a 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java @@ -1199,7 +1199,14 @@ public class ClassReader { if (labels[label] == null) { readLabel(label, labels).status |= Label.DEBUG; } - labels[label].line = readUnsignedShort(v + 12); + Label l = labels[label]; + while (l.line > 0) { + if (l.next == null) { + l.next = new Label(); + } + l = l.next; + } + l.line = readUnsignedShort(v + 12); v += 4; } } @@ -1314,9 +1321,15 @@ public class ClassReader { // visits the label and line number for this offset, if any Label l = labels[offset]; if (l != null) { + Label next = l.next; + l.next = null; mv.visitLabel(l); if ((context.flags & SKIP_DEBUG) == 0 && l.line > 0) { mv.visitLineNumber(l.line, l); + while (next != null) { + mv.visitLineNumber(next.line, l); + next = next.next; + } } } @@ -1857,8 +1870,7 @@ public class ClassReader { v += 2; break; case 'B': // pointer to CONSTANT_Byte - av.visit(name, - (byte) readInt(items[readUnsignedShort(v)])); + av.visit(name, (byte) readInt(items[readUnsignedShort(v)])); v += 2; break; case 'Z': // pointer to CONSTANT_Boolean @@ -1868,13 +1880,11 @@ public class ClassReader { v += 2; break; case 'S': // pointer to CONSTANT_Short - av.visit(name, - (short) readInt(items[readUnsignedShort(v)])); + av.visit(name, (short) readInt(items[readUnsignedShort(v)])); v += 2; break; case 'C': // pointer to CONSTANT_Char - av.visit(name, - (char) readInt(items[readUnsignedShort(v)])); + av.visit(name, (char) readInt(items[readUnsignedShort(v)])); v += 2; break; case 's': // pointer to CONSTANT_Utf8 @@ -2515,11 +2525,12 @@ public class ClassReader { int tag = readByte(index); int[] items = this.items; int cpIndex = items[readUnsignedShort(index + 1)]; + boolean itf = b[cpIndex - 1] == ClassWriter.IMETH; String owner = readClass(cpIndex, buf); cpIndex = items[readUnsignedShort(cpIndex + 2)]; String name = readUTF8(cpIndex, buf); String desc = readUTF8(cpIndex + 2, buf); - return new Handle(tag, owner, name, desc); + return new Handle(tag, owner, name, desc, itf); } } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java index f5b24254ece..2e3d62b0369 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java @@ -1081,7 +1081,7 @@ public class ClassWriter extends ClassVisitor { } } else if (cst instanceof Handle) { Handle h = (Handle) cst; - return newHandleItem(h.tag, h.owner, h.name, h.desc); + return newHandleItem(h.tag, h.owner, h.name, h.desc, h.itf); } else { throw new IllegalArgumentException("value " + cst); } @@ -1216,10 +1216,12 @@ public class ClassWriter extends ClassVisitor { * the name of the field or method. * @param desc * the descriptor of the field or method. + * @param itf + * true if the owner is an interface. * @return a new or an already existing method type reference item. */ Item newHandleItem(final int tag, final String owner, final String name, - final String desc) { + final String desc, final boolean itf) { key4.set(HANDLE_BASE + tag, owner, name, desc); Item result = get(key4); if (result == null) { @@ -1228,8 +1230,7 @@ public class ClassWriter extends ClassVisitor { } else { put112(HANDLE, tag, - newMethod(owner, name, desc, - tag == Opcodes.H_INVOKEINTERFACE)); + newMethod(owner, name, desc, itf)); } result = new Item(index++, key4); put(result); @@ -1259,10 +1260,44 @@ public class ClassWriter extends ClassVisitor { * the descriptor of the field or method. * @return the index of a new or already existing method type reference * item. + * + * @deprecated this method is superseded by + * {@link #newHandle(int, String, String, String, boolean)}. */ + @Deprecated public int newHandle(final int tag, final String owner, final String name, final String desc) { - return newHandleItem(tag, owner, name, desc).index; + return newHandle(tag, owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE); + } + + /** + * Adds a handle to the constant pool of the class being build. Does nothing + * if the constant pool already contains a similar item. This method is + * intended for {@link Attribute} sub classes, and is normally not needed by + * class generators or adapters. + * + * @param tag + * the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, + * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, + * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, + * {@link Opcodes#H_INVOKESTATIC}, + * {@link Opcodes#H_INVOKESPECIAL}, + * {@link Opcodes#H_NEWINVOKESPECIAL} or + * {@link Opcodes#H_INVOKEINTERFACE}. + * @param owner + * the internal name of the field or method owner class. + * @param name + * the name of the field or method. + * @param desc + * the descriptor of the field or method. + * @param itf + * true if the owner is an interface. + * @return the index of a new or already existing method type reference + * item. + */ + public int newHandle(final int tag, final String owner, final String name, + final String desc, final boolean itf) { + return newHandleItem(tag, owner, name, desc, itf).index; } /** @@ -1294,7 +1329,7 @@ public class ClassWriter extends ClassVisitor { int hashCode = bsm.hashCode(); bootstrapMethods.putShort(newHandle(bsm.tag, bsm.owner, bsm.name, - bsm.desc)); + bsm.desc, bsm.isInterface())); int argsLength = bsmArgs.length; bootstrapMethods.putShort(argsLength); diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Frame.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Frame.java index bb7ff8f5147..811b74c7242 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Frame.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Frame.java @@ -192,7 +192,7 @@ final class Frame { private static final int LOCAL = 0x2000000; /** - * Kind of the types that are relative to the stack of an input stack + * Kind of the the types that are relative to the stack of an input stack * map frame. The value of such types is a position relatively to the top of * this stack. */ diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Handle.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Handle.java index e8b2859b05d..407c1d99774 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Handle.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Handle.java @@ -93,6 +93,12 @@ public final class Handle { */ final String desc; + + /** + * Indicate if the owner is an interface or not. + */ + final boolean itf; + /** * Constructs a new field or method handle. * @@ -113,12 +119,44 @@ public final class Handle { * @param desc * the descriptor of the field or method designated by this * handle. + * + * @deprecated this constructor has been superseded + * by {@link #Handle(int, String, String, String, boolean)}. */ + @Deprecated public Handle(int tag, String owner, String name, String desc) { + this(tag, owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE); + } + + /** + * Constructs a new field or method handle. + * + * @param tag + * the kind of field or method designated by this Handle. Must be + * {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, + * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, + * {@link Opcodes#H_INVOKEVIRTUAL}, + * {@link Opcodes#H_INVOKESTATIC}, + * {@link Opcodes#H_INVOKESPECIAL}, + * {@link Opcodes#H_NEWINVOKESPECIAL} or + * {@link Opcodes#H_INVOKEINTERFACE}. + * @param owner + * the internal name of the class that owns the field or method + * designated by this handle. + * @param name + * the name of the field or method designated by this handle. + * @param desc + * the descriptor of the field or method designated by this + * handle. + * @param itf + * true if the owner is an interface. + */ + public Handle(int tag, String owner, String name, String desc, boolean itf) { this.tag = tag; this.owner = owner; this.name = name; this.desc = desc; + this.itf = itf; } /** @@ -164,6 +202,17 @@ public final class Handle { return desc; } + /** + * Returns true if the owner of the field or method designated + * by this handle is an interface. + * + * @return true if the owner of the field or method designated + * by this handle is an interface. + */ + public boolean isInterface() { + return itf; + } + @Override public boolean equals(Object obj) { if (obj == this) { @@ -173,13 +222,13 @@ public final class Handle { return false; } Handle h = (Handle) obj; - return tag == h.tag && owner.equals(h.owner) && name.equals(h.name) - && desc.equals(h.desc); + return tag == h.tag && itf == h.itf && owner.equals(h.owner) + && name.equals(h.name) && desc.equals(h.desc); } @Override public int hashCode() { - return tag + owner.hashCode() * name.hashCode() * desc.hashCode(); + return tag + (itf? 64: 0) + owner.hashCode() * name.hashCode() * desc.hashCode(); } /** @@ -187,13 +236,16 @@ public final class Handle { * representation is: * *
+     * for a reference to a class:
      * owner '.' name desc ' ' '(' tag ')'
+     * for a reference to an interface:
+     * owner '.' name desc ' ' '(' tag ' ' itf ')'
      * 
* * . As this format is unambiguous, it can be parsed if necessary. */ @Override public String toString() { - return owner + '.' + name + desc + " (" + tag + ')'; + return owner + '.' + name + desc + " (" + tag + (itf? " itf": "") + ')'; } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Label.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Label.java index bbea0001235..63e42a020bc 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Label.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Label.java @@ -160,7 +160,11 @@ public class Label { int status; /** - * The line number corresponding to this label, if known. + * The line number corresponding to this label, if known. If there are + * several lines, each line is stored in a separate label, all linked via + * their next field (these links are created in ClassReader and removed just + * before visitLabel is called, so that this does not impact the rest of the + * code). */ int line; @@ -268,7 +272,8 @@ public class Label { * The next basic block in the basic block stack. This stack is used in the * main loop of the fix point algorithm used in the second step of the * control flow analysis algorithms. It is also used in - * {@link #visitSubroutine} to avoid using a recursive method. + * {@link #visitSubroutine} to avoid using a recursive method, and in + * ClassReader to temporarily store multiple source lines for a label. * * @see MethodWriter#visitMaxs */ diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java index 0bb1a05b805..1448067a467 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java @@ -62,15 +62,16 @@ package jdk.internal.org.objectweb.asm; * A visitor to visit a Java method. The methods of this class must be called in * the following order: ( visitParameter )* [ * visitAnnotationDefault ] ( visitAnnotation | - * visitTypeAnnotation | visitAttribute )* [ - * visitCode ( visitFrame | visitXInsn | - * visitLabel | visitInsnAnnotation | - * visitTryCatchBlock | visitTryCatchBlockAnnotation | - * visitLocalVariable | visitLocalVariableAnnotation | - * visitLineNumber )* visitMaxs ] visitEnd. In - * addition, the visitXInsn and visitLabel methods must - * be called in the sequential order of the bytecode instructions of the visited - * code, visitInsnAnnotation must be called after the annotated + * visitParameterAnnotation visitTypeAnnotation | + * visitAttribute )* [ visitCode ( visitFrame | + * visitXInsn | visitLabel | + * visitInsnAnnotation | visitTryCatchBlock | + * visitTryCatchAnnotation | visitLocalVariable | + * visitLocalVariableAnnotation | visitLineNumber )* + * visitMaxs ] visitEnd. In addition, the + * visitXInsn and visitLabel methods must be called in + * the sequential order of the bytecode instructions of the visited code, + * visitInsnAnnotation must be called after the annotated * instruction, visitTryCatchBlock must be called before the * labels passed as arguments have been visited, * visitTryCatchBlockAnnotation must be called after the diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java index e02fad465d9..c2e4031e304 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java @@ -2061,7 +2061,7 @@ class MethodWriter extends MethodVisitor { } int size = 8; if (code.length > 0) { - if (code.length > 65536) { + if (code.length > 65535) { throw new RuntimeException("Method code too large!"); } cw.newUTF8("Code"); @@ -2735,11 +2735,13 @@ class MethodWriter extends MethodVisitor { l = l.successor; } // Update the offsets in the uninitialized types - for (i = 0; i < cw.typeTable.length; ++i) { - Item item = cw.typeTable[i]; - if (item != null && item.type == ClassWriter.TYPE_UNINIT) { - item.intVal = getNewOffset(allIndexes, allSizes, 0, - item.intVal); + if (cw.typeTable != null) { + for (i = 0; i < cw.typeTable.length; ++i) { + Item item = cw.typeTable[i]; + if (item != null && item.type == ClassWriter.TYPE_UNINIT) { + item.intVal = getNewOffset(allIndexes, allSizes, 0, + item.intVal); + } } } // The stack map frames are not serialized yet, so we don't need diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Type.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Type.java index 633a4a024ea..056ace15fa8 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Type.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Type.java @@ -654,7 +654,7 @@ public class Type { * @return the descriptor corresponding to this Java type. */ public String getDescriptor() { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); getDescriptor(buf); return buf.toString(); } @@ -672,7 +672,7 @@ public class Type { */ public static String getMethodDescriptor(final Type returnType, final Type... argumentTypes) { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); buf.append('('); for (int i = 0; i < argumentTypes.length; ++i) { argumentTypes[i].getDescriptor(buf); @@ -689,7 +689,7 @@ public class Type { * @param buf * the string buffer to which the descriptor must be appended. */ - private void getDescriptor(final StringBuffer buf) { + private void getDescriptor(final StringBuilder buf) { if (this.buf == null) { // descriptor is in byte 3 of 'off' for primitive types (buf == // null) @@ -729,7 +729,7 @@ public class Type { * @return the descriptor corresponding to the given class. */ public static String getDescriptor(final Class c) { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); getDescriptor(buf, c); return buf.toString(); } @@ -743,7 +743,7 @@ public class Type { */ public static String getConstructorDescriptor(final Constructor c) { Class[] parameters = c.getParameterTypes(); - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); buf.append('('); for (int i = 0; i < parameters.length; ++i) { getDescriptor(buf, parameters[i]); @@ -760,7 +760,7 @@ public class Type { */ public static String getMethodDescriptor(final Method m) { Class[] parameters = m.getParameterTypes(); - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); buf.append('('); for (int i = 0; i < parameters.length; ++i) { getDescriptor(buf, parameters[i]); @@ -778,7 +778,7 @@ public class Type { * @param c * the class whose descriptor must be computed. */ - private static void getDescriptor(final StringBuffer buf, final Class c) { + private static void getDescriptor(final StringBuilder buf, final Class c) { Class d = c; while (true) { if (d.isPrimitive()) { diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypePath.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypePath.java index a48a39d8b46..31fe2bc6826 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypePath.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypePath.java @@ -71,25 +71,25 @@ public class TypePath { * A type path step that steps into the element type of an array type. See * {@link #getStep getStep}. */ - public static final int ARRAY_ELEMENT = 0; + public final static int ARRAY_ELEMENT = 0; /** * A type path step that steps into the nested type of a class type. See * {@link #getStep getStep}. */ - public static final int INNER_TYPE = 1; + public final static int INNER_TYPE = 1; /** * A type path step that steps into the bound of a wildcard type. See * {@link #getStep getStep}. */ - public static final int WILDCARD_BOUND = 2; + public final static int WILDCARD_BOUND = 2; /** * A type path step that steps into a type argument of a generic type. See * {@link #getStep getStep}. */ - public static final int TYPE_ARGUMENT = 3; + public final static int TYPE_ARGUMENT = 3; /** * The byte array where the path is stored, in Java class file format. diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypeReference.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypeReference.java index b366df0afb7..4caf8f10db0 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypeReference.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypeReference.java @@ -74,133 +74,133 @@ public class TypeReference { * The sort of type references that target a type parameter of a generic * class. See {@link #getSort getSort}. */ - public static final int CLASS_TYPE_PARAMETER = 0x00; + public final static int CLASS_TYPE_PARAMETER = 0x00; /** * The sort of type references that target a type parameter of a generic * method. See {@link #getSort getSort}. */ - public static final int METHOD_TYPE_PARAMETER = 0x01; + public final static int METHOD_TYPE_PARAMETER = 0x01; /** * The sort of type references that target the super class of a class or one * of the interfaces it implements. See {@link #getSort getSort}. */ - public static final int CLASS_EXTENDS = 0x10; + public final static int CLASS_EXTENDS = 0x10; /** * The sort of type references that target a bound of a type parameter of a * generic class. See {@link #getSort getSort}. */ - public static final int CLASS_TYPE_PARAMETER_BOUND = 0x11; + public final static int CLASS_TYPE_PARAMETER_BOUND = 0x11; /** * The sort of type references that target a bound of a type parameter of a * generic method. See {@link #getSort getSort}. */ - public static final int METHOD_TYPE_PARAMETER_BOUND = 0x12; + public final static int METHOD_TYPE_PARAMETER_BOUND = 0x12; /** * The sort of type references that target the type of a field. See * {@link #getSort getSort}. */ - public static final int FIELD = 0x13; + public final static int FIELD = 0x13; /** * The sort of type references that target the return type of a method. See * {@link #getSort getSort}. */ - public static final int METHOD_RETURN = 0x14; + public final static int METHOD_RETURN = 0x14; /** * The sort of type references that target the receiver type of a method. * See {@link #getSort getSort}. */ - public static final int METHOD_RECEIVER = 0x15; + public final static int METHOD_RECEIVER = 0x15; /** * The sort of type references that target the type of a formal parameter of * a method. See {@link #getSort getSort}. */ - public static final int METHOD_FORMAL_PARAMETER = 0x16; + public final static int METHOD_FORMAL_PARAMETER = 0x16; /** * The sort of type references that target the type of an exception declared * in the throws clause of a method. See {@link #getSort getSort}. */ - public static final int THROWS = 0x17; + public final static int THROWS = 0x17; /** * The sort of type references that target the type of a local variable in a * method. See {@link #getSort getSort}. */ - public static final int LOCAL_VARIABLE = 0x40; + public final static int LOCAL_VARIABLE = 0x40; /** * The sort of type references that target the type of a resource variable * in a method. See {@link #getSort getSort}. */ - public static final int RESOURCE_VARIABLE = 0x41; + public final static int RESOURCE_VARIABLE = 0x41; /** * The sort of type references that target the type of the exception of a * 'catch' clause in a method. See {@link #getSort getSort}. */ - public static final int EXCEPTION_PARAMETER = 0x42; + public final static int EXCEPTION_PARAMETER = 0x42; /** * The sort of type references that target the type declared in an * 'instanceof' instruction. See {@link #getSort getSort}. */ - public static final int INSTANCEOF = 0x43; + public final static int INSTANCEOF = 0x43; /** * The sort of type references that target the type of the object created by * a 'new' instruction. See {@link #getSort getSort}. */ - public static final int NEW = 0x44; + public final static int NEW = 0x44; /** * The sort of type references that target the receiver type of a * constructor reference. See {@link #getSort getSort}. */ - public static final int CONSTRUCTOR_REFERENCE = 0x45; + public final static int CONSTRUCTOR_REFERENCE = 0x45; /** * The sort of type references that target the receiver type of a method * reference. See {@link #getSort getSort}. */ - public static final int METHOD_REFERENCE = 0x46; + public final static int METHOD_REFERENCE = 0x46; /** * The sort of type references that target the type declared in an explicit * or implicit cast instruction. See {@link #getSort getSort}. */ - public static final int CAST = 0x47; + public final static int CAST = 0x47; /** * The sort of type references that target a type parameter of a generic * constructor in a constructor call. See {@link #getSort getSort}. */ - public static final int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48; + public final static int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48; /** * The sort of type references that target a type parameter of a generic * method in a method call. See {@link #getSort getSort}. */ - public static final int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49; + public final static int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49; /** * The sort of type references that target a type parameter of a generic * constructor in a constructor reference. See {@link #getSort getSort}. */ - public static final int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; + public final static int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; /** * The sort of type references that target a type parameter of a generic * method in a method reference. See {@link #getSort getSort}. */ - public static final int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; + public final static int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; /** * The type reference value in Java class file format. diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java index c07917784df..00dccd549f0 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java @@ -388,10 +388,10 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes } break; case PUTFIELD: + popValue(); popValue(); if (longOrDouble) { popValue(); - popValue(); } break; // case GETFIELD: @@ -619,7 +619,7 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes } /** - * Called at the beginning of the method or after super class class call in + * Called at the beginning of the method or after super class call in * the constructor.
*
* diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AnnotationRemapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AnnotationRemapper.java new file mode 100644 index 00000000000..3482ac95f6c --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AnnotationRemapper.java @@ -0,0 +1,108 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm.commons; + +import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + +/** + * An {@link AnnotationVisitor} adapter for type remapping. + * + * @author Eugene Kuleshov + */ +public class AnnotationRemapper extends AnnotationVisitor { + + protected final Remapper remapper; + + public AnnotationRemapper(final AnnotationVisitor av, + final Remapper remapper) { + this(Opcodes.ASM5, av, remapper); + } + + protected AnnotationRemapper(final int api, final AnnotationVisitor av, + final Remapper remapper) { + super(api, av); + this.remapper = remapper; + } + + @Override + public void visit(String name, Object value) { + av.visit(name, remapper.mapValue(value)); + } + + @Override + public void visitEnum(String name, String desc, String value) { + av.visitEnum(name, remapper.mapDesc(desc), value); + } + + @Override + public AnnotationVisitor visitAnnotation(String name, String desc) { + AnnotationVisitor v = av.visitAnnotation(name, remapper.mapDesc(desc)); + return v == null ? null : (v == av ? this : new AnnotationRemapper(v, + remapper)); + } + + @Override + public AnnotationVisitor visitArray(String name) { + AnnotationVisitor v = av.visitArray(name); + return v == null ? null : (v == av ? this : new AnnotationRemapper(v, + remapper)); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/ClassRemapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/ClassRemapper.java new file mode 100644 index 00000000000..8a8ea738ae9 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/ClassRemapper.java @@ -0,0 +1,161 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm.commons; + +import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.FieldVisitor; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.TypePath; + +/** + * A {@link ClassVisitor} for type remapping. + * + * @author Eugene Kuleshov + */ +public class ClassRemapper extends ClassVisitor { + + protected final Remapper remapper; + + protected String className; + + public ClassRemapper(final ClassVisitor cv, final Remapper remapper) { + this(Opcodes.ASM5, cv, remapper); + } + + protected ClassRemapper(final int api, final ClassVisitor cv, + final Remapper remapper) { + super(api, cv); + this.remapper = remapper; + } + + @Override + public void visit(int version, int access, String name, String signature, + String superName, String[] interfaces) { + this.className = name; + super.visit(version, access, remapper.mapType(name), remapper + .mapSignature(signature, false), remapper.mapType(superName), + interfaces == null ? null : remapper.mapTypes(interfaces)); + } + + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc), + visible); + return av == null ? null : createAnnotationRemapper(av); + } + + @Override + public AnnotationVisitor visitTypeAnnotation(int typeRef, + TypePath typePath, String desc, boolean visible) { + AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath, + remapper.mapDesc(desc), visible); + return av == null ? null : createAnnotationRemapper(av); + } + + @Override + public FieldVisitor visitField(int access, String name, String desc, + String signature, Object value) { + FieldVisitor fv = super.visitField(access, + remapper.mapFieldName(className, name, desc), + remapper.mapDesc(desc), remapper.mapSignature(signature, true), + remapper.mapValue(value)); + return fv == null ? null : createFieldRemapper(fv); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, + String signature, String[] exceptions) { + String newDesc = remapper.mapMethodDesc(desc); + MethodVisitor mv = super.visitMethod(access, remapper.mapMethodName( + className, name, desc), newDesc, remapper.mapSignature( + signature, false), + exceptions == null ? null : remapper.mapTypes(exceptions)); + return mv == null ? null : createMethodRemapper(mv); + } + + @Override + public void visitInnerClass(String name, String outerName, + String innerName, int access) { + // TODO should innerName be changed? + super.visitInnerClass(remapper.mapType(name), outerName == null ? null + : remapper.mapType(outerName), innerName, access); + } + + @Override + public void visitOuterClass(String owner, String name, String desc) { + super.visitOuterClass(remapper.mapType(owner), name == null ? null + : remapper.mapMethodName(owner, name, desc), + desc == null ? null : remapper.mapMethodDesc(desc)); + } + + protected FieldVisitor createFieldRemapper(FieldVisitor fv) { + return new FieldRemapper(fv, remapper); + } + + protected MethodVisitor createMethodRemapper(MethodVisitor mv) { + return new MethodRemapper(mv, remapper); + } + + protected AnnotationVisitor createAnnotationRemapper(AnnotationVisitor av) { + return new AnnotationRemapper(av, remapper); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/FieldRemapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/FieldRemapper.java new file mode 100644 index 00000000000..13f8b7fd154 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/FieldRemapper.java @@ -0,0 +1,100 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm.commons; + +import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.FieldVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.TypePath; + +/** + * A {@link FieldVisitor} adapter for type remapping. + * + * @author Eugene Kuleshov + */ +public class FieldRemapper extends FieldVisitor { + + private final Remapper remapper; + + public FieldRemapper(final FieldVisitor fv, final Remapper remapper) { + this(Opcodes.ASM5, fv, remapper); + } + + protected FieldRemapper(final int api, final FieldVisitor fv, + final Remapper remapper) { + super(api, fv); + this.remapper = remapper; + } + + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + AnnotationVisitor av = fv.visitAnnotation(remapper.mapDesc(desc), + visible); + return av == null ? null : new AnnotationRemapper(av, remapper); + } + + @Override + public AnnotationVisitor visitTypeAnnotation(int typeRef, + TypePath typePath, String desc, boolean visible) { + AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath, + remapper.mapDesc(desc), visible); + return av == null ? null : new AnnotationRemapper(av, remapper); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java index 8ecb1c9c4b1..2df144ef70c 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java @@ -73,7 +73,7 @@ import jdk.internal.org.objectweb.asm.Type; */ public class InstructionAdapter extends MethodVisitor { - public static final Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;"); + public final static Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;"); /** * Creates a new {@link InstructionAdapter}. Subclasses must not use this diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java index 5d02c53768d..7aad39658e8 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java @@ -104,11 +104,6 @@ public class LocalVariablesSorter extends MethodVisitor { */ protected int nextLocal; - /** - * Indicates if at least one local variable has moved due to remapping. - */ - private boolean changed; - /** * Creates a new {@link LocalVariablesSorter}. Subclasses must not use * this constructor. Instead, they must use the @@ -228,11 +223,6 @@ public class LocalVariablesSorter extends MethodVisitor { "ClassReader.accept() should be called with EXPAND_FRAMES flag"); } - if (!changed) { // optimization for the case where mapping = identity - mv.visitFrame(type, nLocal, local, nStack, stack); - return; - } - // creates a copy of newLocals Object[] oldLocals = new Object[newLocals.length]; System.arraycopy(newLocals, 0, oldLocals, 0, oldLocals.length); @@ -328,7 +318,6 @@ public class LocalVariablesSorter extends MethodVisitor { int local = newLocalMapping(type); setLocalType(local, type); setFrameLocal(local, t); - changed = true; return local; } @@ -396,9 +385,6 @@ public class LocalVariablesSorter extends MethodVisitor { } else { value--; } - if (value != var) { - changed = true; - } return value; } diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/MethodRemapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/MethodRemapper.java new file mode 100644 index 00000000000..486cc6b7c57 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/MethodRemapper.java @@ -0,0 +1,252 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm.commons; + +import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.Handle; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.TypePath; + +/** + * A {@link LocalVariablesSorter} for type mapping. + * + * @author Eugene Kuleshov + */ +public class MethodRemapper extends MethodVisitor { + + protected final Remapper remapper; + + public MethodRemapper(final MethodVisitor mv, final Remapper remapper) { + this(Opcodes.ASM5, mv, remapper); + } + + protected MethodRemapper(final int api, final MethodVisitor mv, + final Remapper remapper) { + super(api, mv); + this.remapper = remapper; + } + + @Override + public AnnotationVisitor visitAnnotationDefault() { + AnnotationVisitor av = super.visitAnnotationDefault(); + return av == null ? av : new AnnotationRemapper(av, remapper); + } + + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc), + visible); + return av == null ? av : new AnnotationRemapper(av, remapper); + } + + @Override + public AnnotationVisitor visitTypeAnnotation(int typeRef, + TypePath typePath, String desc, boolean visible) { + AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath, + remapper.mapDesc(desc), visible); + return av == null ? av : new AnnotationRemapper(av, remapper); + } + + @Override + public AnnotationVisitor visitParameterAnnotation(int parameter, + String desc, boolean visible) { + AnnotationVisitor av = super.visitParameterAnnotation(parameter, + remapper.mapDesc(desc), visible); + return av == null ? av : new AnnotationRemapper(av, remapper); + } + + @Override + public void visitFrame(int type, int nLocal, Object[] local, int nStack, + Object[] stack) { + super.visitFrame(type, nLocal, remapEntries(nLocal, local), nStack, + remapEntries(nStack, stack)); + } + + private Object[] remapEntries(int n, Object[] entries) { + for (int i = 0; i < n; i++) { + if (entries[i] instanceof String) { + Object[] newEntries = new Object[n]; + if (i > 0) { + System.arraycopy(entries, 0, newEntries, 0, i); + } + do { + Object t = entries[i]; + newEntries[i++] = t instanceof String ? remapper + .mapType((String) t) : t; + } while (i < n); + return newEntries; + } + } + return entries; + } + + @Override + public void visitFieldInsn(int opcode, String owner, String name, + String desc) { + super.visitFieldInsn(opcode, remapper.mapType(owner), + remapper.mapFieldName(owner, name, desc), + remapper.mapDesc(desc)); + } + + @Deprecated + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc) { + if (api >= Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, + opcode == Opcodes.INVOKEINTERFACE); + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc, final boolean itf) { + if (api < Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, itf); + } + + private void doVisitMethodInsn(int opcode, String owner, String name, + String desc, boolean itf) { + // Calling super.visitMethodInsn requires to call the correct version + // depending on this.api (otherwise infinite loops can occur). To + // simplify and to make it easier to automatically remove the backward + // compatibility code, we inline the code of the overridden method here. + // IMPORTANT: THIS ASSUMES THAT visitMethodInsn IS NOT OVERRIDDEN IN + // LocalVariableSorter. + if (mv != null) { + mv.visitMethodInsn(opcode, remapper.mapType(owner), + remapper.mapMethodName(owner, name, desc), + remapper.mapMethodDesc(desc), itf); + } + } + + @Override + public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, + Object... bsmArgs) { + for (int i = 0; i < bsmArgs.length; i++) { + bsmArgs[i] = remapper.mapValue(bsmArgs[i]); + } + super.visitInvokeDynamicInsn( + remapper.mapInvokeDynamicMethodName(name, desc), + remapper.mapMethodDesc(desc), (Handle) remapper.mapValue(bsm), + bsmArgs); + } + + @Override + public void visitTypeInsn(int opcode, String type) { + super.visitTypeInsn(opcode, remapper.mapType(type)); + } + + @Override + public void visitLdcInsn(Object cst) { + super.visitLdcInsn(remapper.mapValue(cst)); + } + + @Override + public void visitMultiANewArrayInsn(String desc, int dims) { + super.visitMultiANewArrayInsn(remapper.mapDesc(desc), dims); + } + + @Override + public AnnotationVisitor visitInsnAnnotation(int typeRef, + TypePath typePath, String desc, boolean visible) { + AnnotationVisitor av = super.visitInsnAnnotation(typeRef, typePath, + remapper.mapDesc(desc), visible); + return av == null ? av : new AnnotationRemapper(av, remapper); + } + + @Override + public void visitTryCatchBlock(Label start, Label end, Label handler, + String type) { + super.visitTryCatchBlock(start, end, handler, type == null ? null + : remapper.mapType(type)); + } + + @Override + public AnnotationVisitor visitTryCatchAnnotation(int typeRef, + TypePath typePath, String desc, boolean visible) { + AnnotationVisitor av = super.visitTryCatchAnnotation(typeRef, typePath, + remapper.mapDesc(desc), visible); + return av == null ? av : new AnnotationRemapper(av, remapper); + } + + @Override + public void visitLocalVariable(String name, String desc, String signature, + Label start, Label end, int index) { + super.visitLocalVariable(name, remapper.mapDesc(desc), + remapper.mapSignature(signature, true), start, end, index); + } + + @Override + public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, + TypePath typePath, Label[] start, Label[] end, int[] index, + String desc, boolean visible) { + AnnotationVisitor av = super.visitLocalVariableAnnotation(typeRef, + typePath, start, end, index, remapper.mapDesc(desc), visible); + return av == null ? av : new AnnotationRemapper(av, remapper); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/Remapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/Remapper.java index d5edd06363f..b90aee05590 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/Remapper.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/Remapper.java @@ -168,17 +168,19 @@ public abstract class Remapper { Handle h = (Handle) value; return new Handle(h.getTag(), mapType(h.getOwner()), mapMethodName( h.getOwner(), h.getName(), h.getDesc()), - mapMethodDesc(h.getDesc())); + mapMethodDesc(h.getDesc()), h.isInterface()); } return value; } /** - * + * @param signature + * signature for mapper * @param typeSignature * true if signature is a FieldTypeSignature, such as the * signature parameter of the ClassVisitor.visitField or * MethodVisitor.visitLocalVariable methods + * @return signature rewritten as a string */ public String mapSignature(String signature, boolean typeSignature) { if (signature == null) { @@ -186,7 +188,7 @@ public abstract class Remapper { } SignatureReader r = new SignatureReader(signature); SignatureWriter w = new SignatureWriter(); - SignatureVisitor a = createRemappingSignatureAdapter(w); + SignatureVisitor a = createSignatureRemapper(w); if (typeSignature) { r.acceptType(a); } else { @@ -195,9 +197,18 @@ public abstract class Remapper { return w.toString(); } + /** + * @deprecated use {@link #createSignatureRemapper} instead. + */ + @Deprecated protected SignatureVisitor createRemappingSignatureAdapter( SignatureVisitor v) { - return new RemappingSignatureAdapter(v, this); + return new SignatureRemapper(v, this); + } + + protected SignatureVisitor createSignatureRemapper( + SignatureVisitor v) { + return createRemappingSignatureAdapter(v); } /** @@ -245,6 +256,10 @@ public abstract class Remapper { /** * Map type name to the new name. Subclasses can override. + * + * @param typeName + * the type name + * @return new name, default implementation is the identity. */ public String map(String typeName) { return typeName; diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingAnnotationAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingAnnotationAdapter.java index b9a1bc874aa..af0fe2b4fb4 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingAnnotationAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingAnnotationAdapter.java @@ -65,8 +65,10 @@ import jdk.internal.org.objectweb.asm.Opcodes; /** * An {@link AnnotationVisitor} adapter for type remapping. * + * //@deprecated use {@link AnnotationRemapper} instead. * @author Eugene Kuleshov */ +//@Deprecated public class RemappingAnnotationAdapter extends AnnotationVisitor { protected final Remapper remapper; diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingClassAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingClassAdapter.java index 28b736be7a4..e36d79e931d 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingClassAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingClassAdapter.java @@ -69,8 +69,10 @@ import jdk.internal.org.objectweb.asm.TypePath; /** * A {@link ClassVisitor} for type remapping. * + * @deprecated use {@link ClassRemapper} instead. * @author Eugene Kuleshov */ +@Deprecated public class RemappingClassAdapter extends ClassVisitor { protected final Remapper remapper; diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingFieldAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingFieldAdapter.java index 9d94e5ee327..8bafee1bf4a 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingFieldAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingFieldAdapter.java @@ -67,8 +67,10 @@ import jdk.internal.org.objectweb.asm.TypePath; /** * A {@link FieldVisitor} adapter for type remapping. * + * @deprecated use {@link FieldRemapper} instead. * @author Eugene Kuleshov */ +@Deprecated public class RemappingFieldAdapter extends FieldVisitor { private final Remapper remapper; diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java index d5493a1b1b5..f58963db6ef 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java @@ -69,8 +69,10 @@ import jdk.internal.org.objectweb.asm.TypePath; /** * A {@link LocalVariablesSorter} for type mapping. * + * //@deprecated use {@link MethodRemapper} instead. * @author Eugene Kuleshov */ +//@Deprecated public class RemappingMethodAdapter extends LocalVariablesSorter { protected final Remapper remapper; diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java index 3b8ab02a3f1..4aa8428f344 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java @@ -65,8 +65,10 @@ import jdk.internal.org.objectweb.asm.signature.SignatureVisitor; /** * A {@link SignatureVisitor} adapter for type mapping. * + * @deprecated use {@link SignatureRemapper} instead. * @author Eugene Kuleshov */ +@Deprecated public class RemappingSignatureAdapter extends SignatureVisitor { private final SignatureVisitor v; diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java index cd407fd8063..0486710dd47 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java @@ -234,7 +234,7 @@ public class SerialVersionUIDAdder extends ClassVisitor { public void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { - computeSVUID = (access & Opcodes.ACC_INTERFACE) == 0; + computeSVUID = (access & Opcodes.ACC_ENUM) == 0; if (computeSVUID) { this.name = name; @@ -396,6 +396,11 @@ public class SerialVersionUIDAdder extends ClassVisitor { /* * 2. The class modifiers written as a 32-bit integer. */ + int access = this.access; + if ((access & Opcodes.ACC_INTERFACE) != 0) { + access = (svuidMethods.size() > 0) ? (access | Opcodes.ACC_ABSTRACT) + : (access & ~Opcodes.ACC_ABSTRACT); + } dos.writeInt(access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT)); diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SignatureRemapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SignatureRemapper.java new file mode 100644 index 00000000000..cf18f2bbb58 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SignatureRemapper.java @@ -0,0 +1,188 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm.commons; + +import java.util.Stack; + +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.signature.SignatureVisitor; + +/** + * A {@link SignatureVisitor} adapter for type mapping. + * + * @author Eugene Kuleshov + */ +public class SignatureRemapper extends SignatureVisitor { + + private final SignatureVisitor v; + + private final Remapper remapper; + + private Stack classNames = new Stack(); + + public SignatureRemapper(final SignatureVisitor v, final Remapper remapper) { + this(Opcodes.ASM5, v, remapper); + } + + protected SignatureRemapper(final int api, final SignatureVisitor v, + final Remapper remapper) { + super(api); + this.v = v; + this.remapper = remapper; + } + + @Override + public void visitClassType(String name) { + classNames.push(name); + v.visitClassType(remapper.mapType(name)); + } + + @Override + public void visitInnerClassType(String name) { + String outerClassName = classNames.pop(); + String className = outerClassName + '$' + name; + classNames.push(className); + String remappedOuter = remapper.mapType(outerClassName) + '$'; + String remappedName = remapper.mapType(className); + int index = remappedName.startsWith(remappedOuter) ? remappedOuter + .length() : remappedName.lastIndexOf('$') + 1; + v.visitInnerClassType(remappedName.substring(index)); + } + + @Override + public void visitFormalTypeParameter(String name) { + v.visitFormalTypeParameter(name); + } + + @Override + public void visitTypeVariable(String name) { + v.visitTypeVariable(name); + } + + @Override + public SignatureVisitor visitArrayType() { + v.visitArrayType(); + return this; + } + + @Override + public void visitBaseType(char descriptor) { + v.visitBaseType(descriptor); + } + + @Override + public SignatureVisitor visitClassBound() { + v.visitClassBound(); + return this; + } + + @Override + public SignatureVisitor visitExceptionType() { + v.visitExceptionType(); + return this; + } + + @Override + public SignatureVisitor visitInterface() { + v.visitInterface(); + return this; + } + + @Override + public SignatureVisitor visitInterfaceBound() { + v.visitInterfaceBound(); + return this; + } + + @Override + public SignatureVisitor visitParameterType() { + v.visitParameterType(); + return this; + } + + @Override + public SignatureVisitor visitReturnType() { + v.visitReturnType(); + return this; + } + + @Override + public SignatureVisitor visitSuperclass() { + v.visitSuperclass(); + return this; + } + + @Override + public void visitTypeArgument() { + v.visitTypeArgument(); + } + + @Override + public SignatureVisitor visitTypeArgument(char wildcard) { + v.visitTypeArgument(wildcard); + return this; + } + + @Override + public void visitEnd() { + v.visitEnd(); + classNames.pop(); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SimpleRemapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SimpleRemapper.java index 56b9bb57dcf..ebf59f4bf53 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SimpleRemapper.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SimpleRemapper.java @@ -85,6 +85,12 @@ public class SimpleRemapper extends Remapper { return s == null ? name : s; } + @Override + public String mapInvokeDynamicMethodName(String name, String desc) { + String s = map('.' + name + desc); + return s == null ? name : s; + } + @Override public String mapFieldName(String owner, String name, String desc) { String s = map(owner + '.' + name); diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureVisitor.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureVisitor.java index 9114bcd348e..8ad2de61230 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureVisitor.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureVisitor.java @@ -68,7 +68,7 @@ import jdk.internal.org.objectweb.asm.Opcodes; *
    *
  • ClassSignature = ( visitFormalTypeParameter * visitClassBound? visitInterfaceBound* )* ( - * visitSuperClass visitInterface* )
  • + * visitSuperclass visitInterface* ) *
  • MethodSignature = ( visitFormalTypeParameter * visitClassBound? visitInterfaceBound* )* ( * visitParameterType* visitReturnType @@ -88,17 +88,17 @@ public abstract class SignatureVisitor { /** * Wildcard for an "extends" type argument. */ - public static final char EXTENDS = '+'; + public final static char EXTENDS = '+'; /** * Wildcard for a "super" type argument. */ - public static final char SUPER = '-'; + public final static char SUPER = '-'; /** * Wildcard for a normal type argument. */ - public static final char INSTANCEOF = '='; + public final static char INSTANCEOF = '='; /** * The ASM API version implemented by this visitor. The value of this field diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureWriter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureWriter.java index 0d761663ea0..a1eceb8d5c9 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureWriter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureWriter.java @@ -69,9 +69,9 @@ import jdk.internal.org.objectweb.asm.Opcodes; public class SignatureWriter extends SignatureVisitor { /** - * Buffer used to construct the signature. + * Builder used to construct the signature. */ - private final StringBuffer buf = new StringBuffer(); + private final StringBuilder buf = new StringBuilder(); /** * Indicates if the signature contains formal type parameters. diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/InsnList.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/InsnList.java index 8dec6eda0bd..768130c94c1 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/InsnList.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/InsnList.java @@ -205,6 +205,9 @@ public class InsnList { /** * Returns an iterator over the instructions in this list. * + * @param index + * index of instruction for the iterator to start at + * * @return an iterator over the instructions in this list. */ @SuppressWarnings("unchecked") diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/ASMifier.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/ASMifier.java index 26e208a4cef..d7c1becfe46 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/ASMifier.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/ASMifier.java @@ -856,7 +856,11 @@ public class ASMifier extends Printer { buf.append("{\n").append("av0 = ").append(name) .append(".visitLocalVariableAnnotation("); buf.append(typeRef); - buf.append(", TypePath.fromString(\"").append(typePath).append("\"), "); + if (typePath == null) { + buf.append(", null, "); + } else { + buf.append(", TypePath.fromString(\"").append(typePath).append("\"), "); + } buf.append("new Label[] {"); for (int i = 0; i < start.length; ++i) { buf.append(i == 0 ? " " : ", "); @@ -934,7 +938,11 @@ public class ASMifier extends Printer { buf.append("{\n").append("av0 = ").append(name).append(".") .append(method).append("("); buf.append(typeRef); - buf.append(", TypePath.fromString(\"").append(typePath).append("\"), "); + if (typePath == null) { + buf.append(", null, "); + } else { + buf.append(", TypePath.fromString(\"").append(typePath).append("\"), "); + } appendConstant(desc); buf.append(", ").append(visible).append(");\n"); text.add(buf.toString()); diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java index 25673195f1c..a0afdc650a8 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java @@ -437,6 +437,9 @@ public class CheckMethodAdapter extends MethodVisitor { * will not perform any data flow check (see * {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}). * + * @param api + * the ASM API version implemented by this CheckMethodAdapter. + * Must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. * @param mv * the method visitor to which this adapter must delegate calls. * @param labels diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/Printer.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/Printer.java index 87e79f47e14..650e1f0b878 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/Printer.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/Printer.java @@ -171,6 +171,10 @@ public abstract class Printer { /** * Constructs a new {@link Printer}. + * + * @param api + * the ASM API version implemented by this printer. Must be one + * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. */ protected Printer(final int api) { this.api = api; @@ -179,34 +183,103 @@ public abstract class Printer { } /** - * Class header. See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visit}. + * Class header. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visit}. + * + * @param version + * the class version. + * @param access + * the class's access flags (see {@link Opcodes}). This parameter + * also indicates if the class is deprecated. + * @param name + * the internal name of the class (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). + * @param signature + * the signature of this class. May be null if the class + * is not a generic one, and does not extend or implement generic + * classes or interfaces. + * @param superName + * the internal of name of the super class (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). + * For interfaces, the super class is {@link Object}. May be + * null, but only for the {@link Object} class. + * @param interfaces + * the internal names of the class's interfaces (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). + * May be null. */ public abstract void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces); /** - * Class source. See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitSource}. + * Class source. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitSource}. + * + * @param source + * the name of the source file from which the class was compiled. + * May be null. + * @param debug + * additional debug information to compute the correspondance + * between source and compiled elements of the class. May be + * null. */ - public abstract void visitSource(final String file, final String debug); + public abstract void visitSource(final String source, final String debug); /** - * Class outer class. See - * {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitOuterClass}. + * Class outer class. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitOuterClass}. + * + * Visits the enclosing class of the class. This method must be called only + * if the class has an enclosing class. + * + * @param owner + * internal name of the enclosing class of the class. + * @param name + * the name of the method that contains the class, or + * null if the class is not enclosed in a method of its + * enclosing class. + * @param desc + * the descriptor of the method that contains the class, or + * null if the class is not enclosed in a method of its + * enclosing class. */ public abstract void visitOuterClass(final String owner, final String name, final String desc); /** - * Class annotation. See - * {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitAnnotation}. + * Class annotation. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitAnnotation}. + * + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public abstract Printer visitClassAnnotation(final String desc, final boolean visible); /** - * Class type annotation. See - * {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitTypeAnnotation}. + * Class type annotation. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitTypeAnnotation}. + * + * @param typeRef + * a reference to the annotated type. The sort of this type + * reference must be + * {@link jdk.internal.org.objectweb.asm.TypeReference#CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, + * {@link jdk.internal.org.objectweb.asm.TypeReference#CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} + * or {@link jdk.internal.org.objectweb.asm.TypeReference#CLASS_EXTENDS CLASS_EXTENDS}. + * See {@link jdk.internal.org.objectweb.asm.TypeReference}. + * @param typePath + * the path to the annotated type argument, wildcard bound, array + * element type, or static inner type within 'typeRef'. May be + * null if the annotation targets 'typeRef' as a whole. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public Printer visitClassTypeAnnotation(final int typeRef, final TypePath typePath, final String desc, final boolean visible) { @@ -214,26 +287,85 @@ public abstract class Printer { } /** - * Class attribute. See - * {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitAttribute}. + * Class attribute. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitAttribute}. + * + * @param attr + * an attribute. */ public abstract void visitClassAttribute(final Attribute attr); /** - * Class inner name. See - * {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitInnerClass}. + * Class inner name. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitInnerClass}. + * + * @param name + * the internal name of an inner class (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). + * @param outerName + * the internal name of the class to which the inner class + * belongs (see {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). + * May be null for not member classes. + * @param innerName + * the (simple) name of the inner class inside its enclosing + * class. May be null for anonymous inner classes. + * @param access + * the access flags of the inner class as originally declared in + * the enclosing class. */ public abstract void visitInnerClass(final String name, final String outerName, final String innerName, final int access); /** - * Class field. See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitField}. + * Class field. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitField}. + * + * @param access + * the field's access flags (see {@link Opcodes}). This parameter + * also indicates if the field is synthetic and/or deprecated. + * @param name + * the field's name. + * @param desc + * the field's descriptor (see {@link jdk.internal.org.objectweb.asm.Type Type}). + * @param signature + * the field's signature. May be null if the field's + * type does not use generic types. + * @param value + * the field's initial value. This parameter, which may be + * null if the field does not have an initial value, + * must be an {@link Integer}, a {@link Float}, a {@link Long}, a + * {@link Double} or a {@link String} (for int, + * float, long or String fields + * respectively). This parameter is only used for static + * fields. Its value is ignored for non static fields, which + * must be initialized through bytecode instructions in + * constructors or methods. + * @return the printer */ public abstract Printer visitField(final int access, final String name, final String desc, final String signature, final Object value); /** - * Class method. See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitMethod}. + * Class method. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitMethod}. + * + * @param access + * the method's access flags (see {@link Opcodes}). This + * parameter also indicates if the method is synthetic and/or + * deprecated. + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type Type}). + * @param signature + * the method's signature. May be null if the method + * parameters, return type and exceptions do not use generic + * types. + * @param exceptions + * the internal names of the method's exception classes (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). May be + * null. + * @return the printer */ public abstract Printer visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions); @@ -248,26 +380,64 @@ public abstract class Printer { // ------------------------------------------------------------------------ /** - * Annotation value. See {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visit}. + * Annotation value. + * See {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visit}. + * + * @param name + * the value name. + * @param value + * the actual value, whose type must be {@link Byte}, + * {@link Boolean}, {@link Character}, {@link Short}, + * {@link Integer} , {@link Long}, {@link Float}, {@link Double}, + * {@link String} or {@link jdk.internal.org.objectweb.asm.Type} + * or OBJECT or ARRAY sort. + * This value can also be an array of byte, boolean, short, char, int, + * long, float or double values (this is equivalent to using + * {@link #visitArray visitArray} and visiting each array element + * in turn, but is more convenient). */ public abstract void visit(final String name, final Object value); /** - * Annotation enum value. See - * {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visitEnum}. + * Annotation enum value. + * See {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visitEnum}. + * + * Visits an enumeration value of the annotation. + * + * @param name + * the value name. + * @param desc + * the class descriptor of the enumeration class. + * @param value + * the actual enumeration value. */ public abstract void visitEnum(final String name, final String desc, final String value); /** - * Nested annotation value. See - * {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visitAnnotation}. + * Nested annotation value. + * See {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visitAnnotation}. + * + * @param name + * the value name. + * @param desc + * the class descriptor of the nested annotation class. + * @return the printer */ public abstract Printer visitAnnotation(final String name, final String desc); /** - * Annotation array value. See - * {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visitArray}. + * Annotation array value. + * See {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visitArray}. + * + * Visits an array value of the annotation. Note that arrays of primitive + * types (such as byte, boolean, short, char, int, long, float or double) + * can be passed as value to {@link #visit visit}. This is what + * {@link jdk.internal.org.objectweb.asm.ClassReader} does. + * + * @param name + * the value name. + * @return the printer */ public abstract Printer visitArray(final String name); @@ -281,15 +451,35 @@ public abstract class Printer { // ------------------------------------------------------------------------ /** - * Field annotation. See - * {@link jdk.internal.org.objectweb.asm.FieldVisitor#visitAnnotation}. + * Field annotation. + * See {@link jdk.internal.org.objectweb.asm.FieldVisitor#visitAnnotation}. + * + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public abstract Printer visitFieldAnnotation(final String desc, final boolean visible); /** - * Field type annotation. See - * {@link jdk.internal.org.objectweb.asm.FieldVisitor#visitTypeAnnotation}. + * Field type annotation. + * See {@link jdk.internal.org.objectweb.asm.FieldVisitor#visitTypeAnnotation}. + * + * @param typeRef + * a reference to the annotated type. The sort of this type + * reference must be {@link jdk.internal.org.objectweb.asm.TypeReference#FIELD FIELD}. + * See {@link jdk.internal.org.objectweb.asm.TypeReference}. + * @param typePath + * the path to the annotated type argument, wildcard bound, array + * element type, or static inner type within 'typeRef'. May be + * null if the annotation targets 'typeRef' as a whole. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public Printer visitFieldTypeAnnotation(final int typeRef, final TypePath typePath, final String desc, final boolean visible) { @@ -297,13 +487,17 @@ public abstract class Printer { } /** - * Field attribute. See - * {@link jdk.internal.org.objectweb.asm.FieldVisitor#visitAttribute}. + * Field attribute. + * See {@link jdk.internal.org.objectweb.asm.FieldVisitor#visitAttribute}. + * + * @param attr + * an attribute. */ public abstract void visitFieldAttribute(final Attribute attr); /** - * Field end. See {@link jdk.internal.org.objectweb.asm.FieldVisitor#visitEnd}. + * Field end. + * See {@link jdk.internal.org.objectweb.asm.FieldVisitor#visitEnd}. */ public abstract void visitFieldEnd(); @@ -312,29 +506,58 @@ public abstract class Printer { // ------------------------------------------------------------------------ /** - * Method parameter. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitParameter(String, int)}. + * Method parameter. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitParameter(String, int)}. + * + * @param name + * parameter name or null if none is provided. + * @param access + * the parameter's access flags, only ACC_FINAL, + * ACC_SYNTHETIC or/and ACC_MANDATED are + * allowed (see {@link Opcodes}). */ public void visitParameter(String name, int access) { throw new RuntimeException("Must be overriden"); } /** - * Method default annotation. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitAnnotationDefault}. + * Method default annotation. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitAnnotationDefault}. + * + * @return the printer */ public abstract Printer visitAnnotationDefault(); /** - * Method annotation. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitAnnotation}. + * Method annotation. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitAnnotation}. + * + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public abstract Printer visitMethodAnnotation(final String desc, final boolean visible); /** - * Method type annotation. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTypeAnnotation}. + * Method type annotation. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTypeAnnotation}. + * + * @param typeRef + * a reference to the annotated type. The sort of this type + * reference must be {@link jdk.internal.org.objectweb.asm.TypeReference#FIELD FIELD}. + * See {@link jdk.internal.org.objectweb.asm.TypeReference}. + * @param typePath + * the path to the annotated type argument, wildcard bound, array + * element type, or static inner type within 'typeRef'. May be + * null if the annotation targets 'typeRef' as a whole. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public Printer visitMethodTypeAnnotation(final int typeRef, final TypePath typePath, final String desc, final boolean visible) { @@ -342,64 +565,225 @@ public abstract class Printer { } /** - * Method parameter annotation. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitParameterAnnotation}. + * Method parameter annotation. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitParameterAnnotation}. + * + * @param parameter + * the parameter index. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public abstract Printer visitParameterAnnotation(final int parameter, final String desc, final boolean visible); /** - * Method attribute. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitAttribute}. + * Method attribute. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitAttribute}. + * + * @param attr + * an attribute. */ public abstract void visitMethodAttribute(final Attribute attr); /** - * Method start. See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitCode}. + * Method start. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitCode}. */ public abstract void visitCode(); /** - * Method stack frame. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitFrame}. + * Method stack frame. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitFrame}. + * + * Visits the current state of the local variables and operand stack + * elements. This method must(*) be called just before any + * instruction i that follows an unconditional branch instruction + * such as GOTO or THROW, that is the target of a jump instruction, or that + * starts an exception handler block. The visited types must describe the + * values of the local variables and of the operand stack elements just + * before i is executed.
    + *
    + * (*) this is mandatory only for classes whose version is greater than or + * equal to {@link Opcodes#V1_6 V1_6}.
    + *
    + * The frames of a method must be given either in expanded form, or in + * compressed form (all frames must use the same format, i.e. you must not + * mix expanded and compressed frames within a single method): + *
      + *
    • In expanded form, all frames must have the F_NEW type.
    • + *
    • In compressed form, frames are basically "deltas" from the state of + * the previous frame: + *
        + *
      • {@link Opcodes#F_SAME} representing frame with exactly the same + * locals as the previous frame and with the empty stack.
      • + *
      • {@link Opcodes#F_SAME1} representing frame with exactly the same + * locals as the previous frame and with single value on the stack ( + * nStack is 1 and stack[0] contains value for the + * type of the stack item).
      • + *
      • {@link Opcodes#F_APPEND} representing frame with current locals are + * the same as the locals in the previous frame, except that additional + * locals are defined (nLocal is 1, 2 or 3 and + * local elements contains values representing added types).
      • + *
      • {@link Opcodes#F_CHOP} representing frame with current locals are the + * same as the locals in the previous frame, except that the last 1-3 locals + * are absent and with the empty stack (nLocals is 1, 2 or 3).
      • + *
      • {@link Opcodes#F_FULL} representing complete frame data.
      • + *
      + *
    • + *
    + *
    + * In both cases the first frame, corresponding to the method's parameters + * and access flags, is implicit and must not be visited. Also, it is + * illegal to visit two or more frames for the same code location (i.e., at + * least one instruction must be visited between two calls to visitFrame). + * + * @param type + * the type of this stack map frame. Must be + * {@link Opcodes#F_NEW} for expanded frames, or + * {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, + * {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or + * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for + * compressed frames. + * @param nLocal + * the number of local variables in the visited frame. + * @param local + * the local variable types in this frame. This array must not be + * modified. Primitive types are represented by + * {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, + * {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, + * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or + * {@link Opcodes#UNINITIALIZED_THIS} (long and double are + * represented by a single element). Reference types are + * represented by String objects (representing internal names), + * and uninitialized types by Label objects (this label + * designates the NEW instruction that created this uninitialized + * value). + * @param nStack + * the number of operand stack elements in the visited frame. + * @param stack + * the operand stack types in this frame. This array must not be + * modified. Its content has the same format as the "local" + * array. + * @throws IllegalStateException + * if a frame is visited just after another one, without any + * instruction between the two (unless this frame is a + * Opcodes#F_SAME frame, in which case it is silently ignored). */ public abstract void visitFrame(final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack); /** - * Method instruction. See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitInsn} - * . + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitInsn} + * + * @param opcode + * the opcode of the instruction to be visited. This opcode is + * either NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, + * ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, + * FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, + * LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, + * IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, + * SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, + * DUP2_X2, SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, + * IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM, + * FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR, + * IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D, + * L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S, + * LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN, + * DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, + * or MONITOREXIT. */ public abstract void visitInsn(final int opcode); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitIntInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitIntInsn}. + * + * @param opcode + * the opcode of the instruction to be visited. This opcode is + * either BIPUSH, SIPUSH or NEWARRAY. + * @param operand + * the operand of the instruction to be visited.
    + * When opcode is BIPUSH, operand value should be between + * Byte.MIN_VALUE and Byte.MAX_VALUE.
    + * When opcode is SIPUSH, operand value should be between + * Short.MIN_VALUE and Short.MAX_VALUE.
    + * When opcode is NEWARRAY, operand value should be one of + * {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR}, + * {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE}, + * {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT}, + * {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}. */ public abstract void visitIntInsn(final int opcode, final int operand); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitVarInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitVarInsn}. + * + * @param opcode + * the opcode of the local variable instruction to be visited. + * This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, + * ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET. + * @param var + * the operand of the instruction to be visited. This operand is + * the index of a local variable. */ public abstract void visitVarInsn(final int opcode, final int var); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTypeInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTypeInsn}. + * + /** + * Visits a type instruction. A type instruction is an instruction that + * takes the internal name of a class as parameter. + * + * @param opcode + * the opcode of the type instruction to be visited. This opcode + * is either NEW, ANEWARRAY, CHECKCAST or INSTANCEOF. + * @param type + * the operand of the instruction to be visited. This operand + * must be the internal name of an object or array class (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). */ public abstract void visitTypeInsn(final int opcode, final String type); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitFieldInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitFieldInsn}. + * + * @param opcode + * the opcode of the type instruction to be visited. This opcode + * is either GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD. + * @param owner + * the internal name of the field's owner class (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). + * @param name + * the field's name. + * @param desc + * the field's descriptor (see {@link jdk.internal.org.objectweb.asm.Type Type}). */ public abstract void visitFieldInsn(final int opcode, final String owner, final String name, final String desc); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMethodInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMethodInsn}. + * + * @param opcode + * the opcode of the type instruction to be visited. This opcode + * is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or + * INVOKEINTERFACE. + * @param owner + * the internal name of the method's owner class (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type Type}). */ @Deprecated public void visitMethodInsn(final int opcode, final String owner, @@ -413,8 +797,22 @@ public abstract class Printer { } /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMethodInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMethodInsn}. + * + * @param opcode + * the opcode of the type instruction to be visited. This opcode + * is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or + * INVOKEINTERFACE. + * @param owner + * the internal name of the method's owner class (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type Type}). + * @param itf + * if the method's owner class is an interface. */ public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc, final boolean itf) { @@ -430,59 +828,181 @@ public abstract class Printer { } /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitInvokeDynamicInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitInvokeDynamicInsn}. + * + * Visits an invokedynamic instruction. + * + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type Type}). + * @param bsm + * the bootstrap method. + * @param bsmArgs + * the bootstrap method constant arguments. Each argument must be + * an {@link Integer}, {@link Float}, {@link Long}, + * {@link Double}, {@link String}, {@link jdk.internal.org.objectweb.asm.Type} or {@link Handle} + * value. This method is allowed to modify the content of the + * array so a caller should expect that this array may change. */ public abstract void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitJumpInsn}. + * Method jump instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitJumpInsn}. + * + * @param opcode + * the opcode of the type instruction to be visited. This opcode + * is either IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, + * IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, + * IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL. + * @param label + * the operand of the instruction to be visited. This operand is + * a label that designates the instruction to which the jump + * instruction may jump. */ public abstract void visitJumpInsn(final int opcode, final Label label); /** - * Method label. See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLabel}. + * Method label. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLabel}. + * + * @param label + * a {@link Label Label} object. */ public abstract void visitLabel(final Label label); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLdcInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLdcInsn}. + * + * Visits a LDC instruction. Note that new constant types may be added in + * future versions of the Java Virtual Machine. To easily detect new + * constant types, implementations of this method should check for + * unexpected constant types, like this: + * + *
    +     * if (cst instanceof Integer) {
    +     *     // ...
    +     * } else if (cst instanceof Float) {
    +     *     // ...
    +     * } else if (cst instanceof Long) {
    +     *     // ...
    +     * } else if (cst instanceof Double) {
    +     *     // ...
    +     * } else if (cst instanceof String) {
    +     *     // ...
    +     * } else if (cst instanceof Type) {
    +     *     int sort = ((Type) cst).getSort();
    +     *     if (sort == Type.OBJECT) {
    +     *         // ...
    +     *     } else if (sort == Type.ARRAY) {
    +     *         // ...
    +     *     } else if (sort == Type.METHOD) {
    +     *         // ...
    +     *     } else {
    +     *         // throw an exception
    +     *     }
    +     * } else if (cst instanceof Handle) {
    +     *     // ...
    +     * } else {
    +     *     // throw an exception
    +     * }
    +     * 
    + * + * @param cst + * the constant to be loaded on the stack. This parameter must be + * a non null {@link Integer}, a {@link Float}, a {@link Long}, a + * {@link Double}, a {@link String}, a {@link jdk.internal.org.objectweb.asm.Type} + * of OBJECT or ARRAY sort for .class constants, for classes whose + * version is 49.0, a {@link jdk.internal.org.objectweb.asm.Type} of METHOD sort or a + * {@link Handle} for MethodType and MethodHandle constants, for + * classes whose version is 51.0. */ public abstract void visitLdcInsn(final Object cst); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitIincInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitIincInsn}. + * + * @param var + * index of the local variable to be incremented. + * @param increment + * amount to increment the local variable by. */ public abstract void visitIincInsn(final int var, final int increment); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTableSwitchInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTableSwitchInsn}. + * + * @param min + * the minimum key value. + * @param max + * the maximum key value. + * @param dflt + * beginning of the default handler block. + * @param labels + * beginnings of the handler blocks. labels[i] is the + * beginning of the handler block for the min + i key. */ public abstract void visitTableSwitchInsn(final int min, final int max, final Label dflt, final Label... labels); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLookupSwitchInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLookupSwitchInsn}. + * + * @param dflt + * beginning of the default handler block. + * @param keys + * the values of the keys. + * @param labels + * beginnings of the handler blocks. labels[i] is the + * beginning of the handler block for the keys[i] key. */ public abstract void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMultiANewArrayInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMultiANewArrayInsn}. + * + * @param desc + * an array type descriptor (see {@link jdk.internal.org.objectweb.asm.Type Type}). + * @param dims + * number of dimensions of the array to allocate. */ public abstract void visitMultiANewArrayInsn(final String desc, final int dims); /** - * Instruction type annotation. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitInsnAnnotation}. + * Instruction type annotation. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitInsnAnnotation}. + * + * @param typeRef + * a reference to the annotated type. The sort of this type + * reference must be {@link jdk.internal.org.objectweb.asm.TypeReference#INSTANCEOF INSTANCEOF}, + * {@link jdk.internal.org.objectweb.asm.TypeReference#NEW NEW}, + * {@link jdk.internal.org.objectweb.asm.TypeReference#CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, + * {@link jdk.internal.org.objectweb.asm.TypeReference#METHOD_REFERENCE METHOD_REFERENCE}, + * {@link jdk.internal.org.objectweb.asm.TypeReference#CAST CAST}, + * {@link jdk.internal.org.objectweb.asm.TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, + * {@link jdk.internal.org.objectweb.asm.TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT}, + * {@link jdk.internal.org.objectweb.asm.TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, + * or {@link jdk.internal.org.objectweb.asm.TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}. + * See {@link jdk.internal.org.objectweb.asm.TypeReference}. + * @param typePath + * the path to the annotated type argument, wildcard bound, array + * element type, or static inner type within 'typeRef'. May be + * null if the annotation targets 'typeRef' as a whole. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public Printer visitInsnAnnotation(final int typeRef, final TypePath typePath, final String desc, final boolean visible) { @@ -490,15 +1010,44 @@ public abstract class Printer { } /** - * Method exception handler. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTryCatchBlock}. + * Method exception handler. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTryCatchBlock}. + * + * @param start + * beginning of the exception handler's scope (inclusive). + * @param end + * end of the exception handler's scope (exclusive). + * @param handler + * beginning of the exception handler's code. + * @param type + * internal name of the type of exceptions handled by the + * handler, or null to catch any exceptions (for + * "finally" blocks). + * @throws IllegalArgumentException + * if one of the labels has already been visited by this visitor + * (by the {@link #visitLabel visitLabel} method). */ public abstract void visitTryCatchBlock(final Label start, final Label end, final Label handler, final String type); /** - * Try catch block type annotation. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTryCatchAnnotation}. + * Try catch block type annotation. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTryCatchAnnotation}. + * + * @param typeRef + * a reference to the annotated type. The sort of this type + * reference must be {@link jdk.internal.org.objectweb.asm.TypeReference#EXCEPTION_PARAMETER + * EXCEPTION_PARAMETER}. + * See {@link jdk.internal.org.objectweb.asm.TypeReference}. + * @param typePath + * the path to the annotated type argument, wildcard bound, array + * element type, or static inner type within 'typeRef'. May be + * null if the annotation targets 'typeRef' as a whole. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public Printer visitTryCatchAnnotation(final int typeRef, final TypePath typePath, final String desc, final boolean visible) { @@ -506,16 +1055,62 @@ public abstract class Printer { } /** - * Method debug info. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLocalVariable}. + * Method debug info. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLocalVariable}. + * + * @param name + * the name of a local variable. + * @param desc + * the type descriptor of this local variable. + * @param signature + * the type signature of this local variable. May be + * null if the local variable type does not use generic + * types. + * @param start + * the first instruction corresponding to the scope of this local + * variable (inclusive). + * @param end + * the last instruction corresponding to the scope of this local + * variable (exclusive). + * @param index + * the local variable's index. + * @throws IllegalArgumentException + * if one of the labels has not already been visited by this + * visitor (by the {@link #visitLabel visitLabel} method). */ public abstract void visitLocalVariable(final String name, final String desc, final String signature, final Label start, final Label end, final int index); /** - * Local variable type annotation. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTryCatchAnnotation}. + * Local variable type annotation. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTryCatchAnnotation}. + * + * @param typeRef + * a reference to the annotated type. The sort of this type + * reference must be {@link jdk.internal.org.objectweb.asm.TypeReference#LOCAL_VARIABLE + * LOCAL_VARIABLE} or {@link jdk.internal.org.objectweb.asm.TypeReference#RESOURCE_VARIABLE + * RESOURCE_VARIABLE}. + * See {@link jdk.internal.org.objectweb.asm.TypeReference}. + * @param typePath + * the path to the annotated type argument, wildcard bound, array + * element type, or static inner type within 'typeRef'. May be + * null if the annotation targets 'typeRef' as a whole. + * @param start + * the fist instructions corresponding to the continuous ranges + * that make the scope of this local variable (inclusive). + * @param end + * the last instructions corresponding to the continuous ranges + * that make the scope of this local variable (exclusive). This + * array must have the same size as the 'start' array. + * @param index + * the local variable's index in each range. This array must have + * the same size as the 'start' array. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public Printer visitLocalVariableAnnotation(final int typeRef, final TypePath typePath, final Label[] start, final Label[] end, @@ -524,19 +1119,34 @@ public abstract class Printer { } /** - * Method debug info. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLineNumber}. + * Method debug info. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLineNumber}. + * + * @param line + * a line number. This number refers to the source file from + * which the class was compiled. + * @param start + * the first instruction corresponding to this line number. + * @throws IllegalArgumentException + * if start has not already been visited by this + * visitor (by the {@link #visitLabel visitLabel} method). */ public abstract void visitLineNumber(final int line, final Label start); /** - * Method max stack and max locals. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMaxs}. + * Method max stack and max locals. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMaxs}. + * + * @param maxStack + * maximum stack size of the method. + * @param maxLocals + * maximum number of local variables for the method. */ public abstract void visitMaxs(final int maxStack, final int maxLocals); /** - * Method end. See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitEnd}. + * Method end. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitEnd}. */ public abstract void visitMethodEnd(); diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceClassVisitor.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceClassVisitor.java index 97163ce47f1..e927bff9ea5 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceClassVisitor.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceClassVisitor.java @@ -74,34 +74,36 @@ import jdk.internal.org.objectweb.asm.TypePath; * visitor chain to trace the class that is visited at a given point in this * chain. This may be useful for debugging purposes. *

    - * The trace printed when visiting the {@code Hello} class is the following: + * The trace printed when visiting the Hello class is the following: + *

    *

    * - *
    {@code
    + * 
      * // class version 49.0 (49) // access flags 0x21 public class Hello {
      *
      * // compiled from: Hello.java
      *
    - * // access flags 0x1 public  ()V ALOAD 0 INVOKESPECIAL
    - * java/lang/Object  ()V RETURN MAXSTACK = 1 MAXLOCALS = 1
    + * // access flags 0x1 public <init> ()V ALOAD 0 INVOKESPECIAL
    + * java/lang/Object <init> ()V RETURN MAXSTACK = 1 MAXLOCALS = 1
      *
      * // access flags 0x9 public static main ([Ljava/lang/String;)V GETSTATIC
    - * java/lang/System out Ljava/io/PrintStream; LDC "hello"
    + * java/lang/System out Ljava/io/PrintStream; LDC "hello"
      * INVOKEVIRTUAL java/io/PrintStream println (Ljava/lang/String;)V RETURN
      * MAXSTACK = 2 MAXLOCALS = 1 }
    - * }
    + *
    * - *
    where {@code Hello} is defined by: + * where Hello is defined by: + *

    *

    * - *
    {@code
    + * 
      * public class Hello {
      *
      *     public static void main(String[] args) {
    - *         System.out.println("hello");
    + *         System.out.println("hello");
      *     }
      * }
    - * }
    + *
    * *
    * @@ -135,7 +137,7 @@ public final class TraceClassVisitor extends ClassVisitor { * * @param cv * the {@link ClassVisitor} to which this visitor delegates - * calls. May be {@code null}. + * calls. May be null. * @param pw * the print writer to be used to print the class. */ @@ -148,7 +150,7 @@ public final class TraceClassVisitor extends ClassVisitor { * * @param cv * the {@link ClassVisitor} to which this visitor delegates - * calls. May be {@code null}. + * calls. May be null. * @param p * the object that actually converts visit events into text. * @param pw diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceSignatureVisitor.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceSignatureVisitor.java index f4925846c59..ef78b14b8a2 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceSignatureVisitor.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceSignatureVisitor.java @@ -70,7 +70,7 @@ import jdk.internal.org.objectweb.asm.signature.SignatureVisitor; */ public final class TraceSignatureVisitor extends SignatureVisitor { - private final StringBuffer declaration; + private final StringBuilder declaration; private boolean isInterface; @@ -82,9 +82,9 @@ public final class TraceSignatureVisitor extends SignatureVisitor { private boolean seenInterface; - private StringBuffer returnType; + private StringBuilder returnType; - private StringBuffer exceptions; + private StringBuilder exceptions; /** * Stack used to keep track of class types that have arguments. Each element @@ -106,10 +106,10 @@ public final class TraceSignatureVisitor extends SignatureVisitor { public TraceSignatureVisitor(final int access) { super(Opcodes.ASM5); isInterface = (access & Opcodes.ACC_INTERFACE) != 0; - this.declaration = new StringBuffer(); + this.declaration = new StringBuilder(); } - private TraceSignatureVisitor(final StringBuffer buf) { + private TraceSignatureVisitor(final StringBuilder buf) { super(Opcodes.ASM5); this.declaration = buf; } @@ -175,14 +175,14 @@ public final class TraceSignatureVisitor extends SignatureVisitor { declaration.append('('); } declaration.append(')'); - returnType = new StringBuffer(); + returnType = new StringBuilder(); return new TraceSignatureVisitor(returnType); } @Override public SignatureVisitor visitExceptionType() { if (exceptions == null) { - exceptions = new StringBuffer(); + exceptions = new StringBuilder(); } else { exceptions.append(", "); } diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/version.txt b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/version.txt index 5ba3a332b48..5c62bb6faf9 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/version.txt +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/version.txt @@ -1,12 +1,12 @@ Path: . -Working Copy Root Path: /hudson/jobs/objectweb-init/workspace/asm-svn-2014-10-15 +Working Copy Root Path: /hudson/jobs/objectweb-init/workspace/asm-svn-2016-01-25 URL: file:///svnroot/asm/trunk/asm Repository Root: file:///svnroot/asm Repository UUID: 271bd773-ee82-43a6-9b2b-1890ed8ce7f9 -Revision: 1772 +Revision: 1795 Node Kind: directory Schedule: normal Last Changed Author: ebruneton -Last Changed Rev: 1772 -Last Changed Date: 2014-09-06 09:13:07 +0200 (Sat, 06 Sep 2014) +Last Changed Rev: 1795 +Last Changed Date: 2016-01-24 14:17:10 +0100 (Sun, 24 Jan 2016) From a42172d65bad78299f588eacf476b5943ab6abdf Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Thu, 3 Mar 2016 09:12:05 -0800 Subject: [PATCH 11/36] 8149159: Clean up Unsafe Reviewed-by: jrose, kvn, stsmirno, chegar, aph, psandoz, redestad, twisti --- .../classes/jdk/internal/misc/Unsafe.java | 547 +++++++++++-- .../share/classes/sun/misc/Unsafe.java | 720 ++++++++++++------ .../jdk/internal/misc/Unsafe/CopyMemory.java | 667 ++++++++++++++++ .../jdk/internal/misc/Unsafe/CopySwap.java | 16 - 4 files changed, 1627 insertions(+), 323 deletions(-) create mode 100644 jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java b/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java index 8905977111b..db643df591b 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java @@ -40,6 +40,15 @@ import jdk.internal.HotSpotIntrinsicCandidate; * Although the class and all methods are public, use of this class is * limited because only trusted code can obtain instances of it. * + * Note: It is the resposibility of the caller to make sure + * arguments are checked before methods of this class are + * called. While some rudimentary checks are performed on the input, + * the checks are best effort and when performance is an overriding + * priority, as when methods of this class are optimized by the + * runtime compiler, some or all checks (if any) may be elided. Hence, + * the caller must not rely on the checks and corresponding + * exceptions! + * * @author John R. Rose * @see #getUnsafe */ @@ -358,6 +367,169 @@ public final class Unsafe { @HotSpotIntrinsicCandidate public native void putAddress(long address, long x); + + + /// helper methods for validating various types of objects/values + + /** + * Create an exception reflecting that some of the input was invalid + * + * Note: It is the resposibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @return an exception object + */ + private RuntimeException invalidInput() { + return new IllegalArgumentException(); + } + + /** + * Check if a value is 32-bit clean (32 MSB are all zero) + * + * @param value the 64-bit value to check + * + * @return true if the value is 32-bit clean + */ + private boolean is32BitClean(long value) { + return value >>> 32 == 0; + } + + /** + * Check the validity of a size (the equivalent of a size_t) + * + * @throws RuntimeException if the size is invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void checkSize(long size) { + if (ADDRESS_SIZE == 4) { + // Note: this will also check for negative sizes + if (!is32BitClean(size)) { + throw invalidInput(); + } + } else if (size < 0) { + throw invalidInput(); + } + } + + /** + * Check the validity of a native address (the equivalent of void*) + * + * @throws RuntimeException if the address is invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void checkNativeAddress(long address) { + if (ADDRESS_SIZE == 4) { + // Accept both zero and sign extended pointers. A valid + // pointer will, after the +1 below, either have produced + // the value 0x0 or 0x1. Masking off the low bit allows + // for testing against 0. + if ((((address >> 32) + 1) & ~1) != 0) { + throw invalidInput(); + } + } + } + + /** + * Check the validity of an offset, relative to a base object + * + * @param o the base object + * @param offset the offset to check + * + * @throws RuntimeException if the size is invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void checkOffset(Object o, long offset) { + if (ADDRESS_SIZE == 4) { + // Note: this will also check for negative offsets + if (!is32BitClean(offset)) { + throw invalidInput(); + } + } else if (offset < 0) { + throw invalidInput(); + } + } + + /** + * Check the validity of a double-register pointer + * + * Note: This code deliberately does *not* check for NPE for (at + * least) three reasons: + * + * 1) NPE is not just NULL/0 - there is a range of values all + * resulting in an NPE, which is not trivial to check for + * + * 2) It is the responsibility of the callers of Unsafe methods + * to verify the input, so throwing an exception here is not really + * useful - passing in a NULL pointer is a critical error and the + * must not expect an exception to be thrown anyway. + * + * 3) the actual operations will detect NULL pointers anyway by + * means of traps and signals (like SIGSEGV). + * + * @param o Java heap object, or null + * @param offset indication of where the variable resides in a Java heap + * object, if any, else a memory address locating the variable + * statically + * + * @throws RuntimeException if the pointer is invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void checkPointer(Object o, long offset) { + if (o == null) { + checkNativeAddress(offset); + } else { + checkOffset(o, offset); + } + } + + /** + * Check if a type is a primitive array type + * + * @param c the type to check + * + * @return true if the type is a primitive array type + */ + private void checkPrimitiveArray(Class c) { + Class componentType = c.getComponentType(); + if (componentType == null || !componentType.isPrimitive()) { + throw invalidInput(); + } + } + + /** + * Check that a pointer is a valid primitive array type pointer + * + * Note: pointers off-heap are considered to be primitive arrays + * + * @throws RuntimeException if the pointer is invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void checkPrimitivePointer(Object o, long offset) { + checkPointer(o, offset); + + if (o != null) { + // If on heap, it it must be a primitive array + checkPrimitiveArray(o.getClass()); + } + } + + /// wrappers for malloc, realloc, free: /** @@ -367,7 +539,16 @@ public final class Unsafe { * aligned for all value types. Dispose of this memory by calling {@link * #freeMemory}, or resize it with {@link #reallocateMemory}. * - * @throws IllegalArgumentException if the size is negative or too large + * Note: It is the resposibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if the size is negative or too large * for the native size_t type * * @throws OutOfMemoryError if the allocation is refused by the system @@ -375,7 +556,32 @@ public final class Unsafe { * @see #getByte(long) * @see #putByte(long, byte) */ - public native long allocateMemory(long bytes); + public long allocateMemory(long bytes) { + allocateMemoryChecks(bytes); + + if (bytes == 0) { + return 0; + } + + long p = allocateMemory0(bytes); + if (p == 0) { + throw new OutOfMemoryError(); + } + + return p; + } + + /** + * Validate the arguments to allocateMemory + * + * @throws RuntimeException if the arguments are invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void allocateMemoryChecks(long bytes) { + checkSize(bytes); + } /** * Resizes a new block of native memory, to the given size in bytes. The @@ -387,14 +593,50 @@ public final class Unsafe { * #reallocateMemory}. The address passed to this method may be null, in * which case an allocation will be performed. * - * @throws IllegalArgumentException if the size is negative or too large + * Note: It is the resposibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if the size is negative or too large * for the native size_t type * * @throws OutOfMemoryError if the allocation is refused by the system * * @see #allocateMemory */ - public native long reallocateMemory(long address, long bytes); + public long reallocateMemory(long address, long bytes) { + reallocateMemoryChecks(address, bytes); + + if (bytes == 0) { + freeMemory(address); + return 0; + } + + long p = (address == 0) ? allocateMemory0(bytes) : reallocateMemory0(address, bytes); + if (p == 0) { + throw new OutOfMemoryError(); + } + + return p; + } + + /** + * Validate the arguments to reallocateMemory + * + * @throws RuntimeException if the arguments are invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void reallocateMemoryChecks(long address, long bytes) { + checkPointer(null, address); + checkSize(bytes); + } /** * Sets all bytes in a given block of memory to a fixed value @@ -411,9 +653,28 @@ public final class Unsafe { * If the effective address and length are (resp.) even modulo 4 or 2, * the stores take place in units of 'int' or 'short'. * + * Note: It is the resposibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if any of the arguments is invalid + * * @since 1.7 */ - public native void setMemory(Object o, long offset, long bytes, byte value); + public void setMemory(Object o, long offset, long bytes, byte value) { + setMemoryChecks(o, offset, bytes, value); + + if (bytes == 0) { + return; + } + + setMemory0(o, offset, bytes, value); + } /** * Sets all bytes in a given block of memory to a fixed value @@ -426,6 +687,19 @@ public final class Unsafe { setMemory(null, address, bytes, value); } + /** + * Validate the arguments to setMemory + * + * @throws RuntimeException if the arguments are invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void setMemoryChecks(Object o, long offset, long bytes, byte value) { + checkPrimitivePointer(o, offset); + checkSize(bytes); + } + /** * Sets all bytes in a given block of memory to a copy of another * block. @@ -441,12 +715,31 @@ public final class Unsafe { * If the effective addresses and length are (resp.) even modulo 4 or 2, * the transfer takes place in units of 'int' or 'short'. * + * Note: It is the resposibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if any of the arguments is invalid + * * @since 1.7 */ - @HotSpotIntrinsicCandidate - public native void copyMemory(Object srcBase, long srcOffset, - Object destBase, long destOffset, - long bytes); + public void copyMemory(Object srcBase, long srcOffset, + Object destBase, long destOffset, + long bytes) { + copyMemoryChecks(srcBase, srcOffset, destBase, destOffset, bytes); + + if (bytes == 0) { + return; + } + + copyMemory0(srcBase, srcOffset, destBase, destOffset, bytes); + } + /** * Sets all bytes in a given block of memory to a copy of another * block. This provides a single-register addressing mode, @@ -458,15 +751,22 @@ public final class Unsafe { copyMemory(null, srcAddress, null, destAddress, bytes); } - private boolean isPrimitiveArray(Class c) { - Class componentType = c.getComponentType(); - return componentType != null && componentType.isPrimitive(); + /** + * Validate the arguments to copyMemory + * + * @throws RuntimeException if any of the arguments is invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void copyMemoryChecks(Object srcBase, long srcOffset, + Object destBase, long destOffset, + long bytes) { + checkSize(bytes); + checkPrimitivePointer(srcBase, srcOffset); + checkPrimitivePointer(destBase, destOffset); } - private native void copySwapMemory0(Object srcBase, long srcOffset, - Object destBase, long destOffset, - long bytes, long elemSize); - /** * Copies all elements from one block of memory to another block, * *unconditionally* byte swapping the elements on the fly. @@ -476,39 +776,23 @@ public final class Unsafe { * as discussed in {@link #getInt(Object,long)}. When the object reference is null, * the offset supplies an absolute base address. * + * Note: It is the resposibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if any of the arguments is invalid + * * @since 9 */ public void copySwapMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes, long elemSize) { - if (bytes < 0) { - throw new IllegalArgumentException(); - } - if (elemSize != 2 && elemSize != 4 && elemSize != 8) { - throw new IllegalArgumentException(); - } - if (bytes % elemSize != 0) { - throw new IllegalArgumentException(); - } - if ((srcBase == null && srcOffset == 0) || - (destBase == null && destOffset == 0)) { - throw new NullPointerException(); - } - - // Must be off-heap, or primitive heap arrays - if (srcBase != null && (srcOffset < 0 || !isPrimitiveArray(srcBase.getClass()))) { - throw new IllegalArgumentException(); - } - if (destBase != null && (destOffset < 0 || !isPrimitiveArray(destBase.getClass()))) { - throw new IllegalArgumentException(); - } - - // Sanity check size and offsets on 32-bit platforms. Most - // significant 32 bits must be zero. - if (ADDRESS_SIZE == 4 && - (bytes >>> 32 != 0 || srcOffset >>> 32 != 0 || destOffset >>> 32 != 0)) { - throw new IllegalArgumentException(); - } + copySwapMemoryChecks(srcBase, srcOffset, destBase, destOffset, bytes, elemSize); if (bytes == 0) { return; @@ -517,6 +801,22 @@ public final class Unsafe { copySwapMemory0(srcBase, srcOffset, destBase, destOffset, bytes, elemSize); } + private void copySwapMemoryChecks(Object srcBase, long srcOffset, + Object destBase, long destOffset, + long bytes, long elemSize) { + checkSize(bytes); + + if (elemSize != 2 && elemSize != 4 && elemSize != 8) { + throw invalidInput(); + } + if (bytes % elemSize != 0) { + throw invalidInput(); + } + + checkPrimitivePointer(srcBase, srcOffset); + checkPrimitivePointer(destBase, destOffset); + } + /** * Copies all elements from one block of memory to another block, byte swapping the * elements on the fly. @@ -535,9 +835,40 @@ public final class Unsafe { * #allocateMemory} or {@link #reallocateMemory}. The address passed to * this method may be null, in which case no action is taken. * + * Note: It is the resposibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if any of the arguments is invalid + * * @see #allocateMemory */ - public native void freeMemory(long address); + public void freeMemory(long address) { + freeMemoryChecks(address); + + if (address == 0) { + return; + } + + freeMemory0(address); + } + + /** + * Validate the arguments to freeMemory + * + * @throws RuntimeException if the arguments are invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void freeMemoryChecks(long address) { + checkPointer(null, address); + } /// random queries @@ -546,7 +877,7 @@ public final class Unsafe { * {@link #staticFieldOffset}, {@link #objectFieldOffset}, * or {@link #arrayBaseOffset}. */ - public static final int INVALID_FIELD_OFFSET = -1; + public static final int INVALID_FIELD_OFFSET = -1; /** * Reports the location of a given field in the storage allocation of its @@ -566,7 +897,13 @@ public final class Unsafe { * must preserve all bits of static field offsets. * @see #getInt(Object, long) */ - public native long objectFieldOffset(Field f); + public long objectFieldOffset(Field f) { + if (f == null) { + throw new NullPointerException(); + } + + return objectFieldOffset0(f); + } /** * Reports the location of a given static field, in conjunction with {@link @@ -585,7 +922,13 @@ public final class Unsafe { * this method reports its result as a long value. * @see #getInt(Object, long) */ - public native long staticFieldOffset(Field f); + public long staticFieldOffset(Field f) { + if (f == null) { + throw new NullPointerException(); + } + + return staticFieldOffset0(f); + } /** * Reports the location of a given static field, in conjunction with {@link @@ -597,7 +940,13 @@ public final class Unsafe { * not be used in any way except as argument to the get and put routines in * this class. */ - public native Object staticFieldBase(Field f); + public Object staticFieldBase(Field f) { + if (f == null) { + throw new NullPointerException(); + } + + return staticFieldBase0(f); + } /** * Detects if the given class may need to be initialized. This is often @@ -605,14 +954,26 @@ public final class Unsafe { * class. * @return false only if a call to {@code ensureClassInitialized} would have no effect */ - public native boolean shouldBeInitialized(Class c); + public boolean shouldBeInitialized(Class c) { + if (c == null) { + throw new NullPointerException(); + } + + return shouldBeInitialized0(c); + } /** * Ensures the given class has been initialized. This is often * needed in conjunction with obtaining the static field base of a * class. */ - public native void ensureClassInitialized(Class c); + public void ensureClassInitialized(Class c) { + if (c == null) { + throw new NullPointerException(); + } + + ensureClassInitialized0(c); + } /** * Reports the offset of the first element in the storage allocation of a @@ -624,7 +985,14 @@ public final class Unsafe { * @see #getInt(Object, long) * @see #putInt(Object, long, int) */ - public native int arrayBaseOffset(Class arrayClass); + public int arrayBaseOffset(Class arrayClass) { + if (arrayClass == null) { + throw new NullPointerException(); + } + + return arrayBaseOffset0(arrayClass); + } + /** The value of {@code arrayBaseOffset(boolean[].class)} */ public static final int ARRAY_BOOLEAN_BASE_OFFSET @@ -673,7 +1041,14 @@ public final class Unsafe { * @see #getInt(Object, long) * @see #putInt(Object, long, int) */ - public native int arrayIndexScale(Class arrayClass); + public int arrayIndexScale(Class arrayClass) { + if (arrayClass == null) { + throw new NullPointerException(); + } + + return arrayIndexScale0(arrayClass); + } + /** The value of {@code arrayIndexScale(boolean[].class)} */ public static final int ARRAY_BOOLEAN_INDEX_SCALE @@ -717,10 +1092,12 @@ public final class Unsafe { * other primitive types (as stored in native memory blocks) is determined * fully by their information content. */ - public native int addressSize(); + public int addressSize() { + return ADDRESS_SIZE; + } /** The value of {@code addressSize()} */ - public static final int ADDRESS_SIZE = theUnsafe.addressSize(); + public static final int ADDRESS_SIZE = theUnsafe.addressSize0(); /** * Reports the size in bytes of a native memory page (whatever that is). @@ -735,9 +1112,22 @@ public final class Unsafe { * Tells the VM to define a class, without security checks. By default, the * class loader and protection domain come from the caller's class. */ - public native Class defineClass(String name, byte[] b, int off, int len, - ClassLoader loader, - ProtectionDomain protectionDomain); + public Class defineClass(String name, byte[] b, int off, int len, + ClassLoader loader, + ProtectionDomain protectionDomain) { + if (b == null) { + throw new NullPointerException(); + } + if (len < 0) { + throw new ArrayIndexOutOfBoundsException(); + } + + return defineClass0(name, b, off, len, loader, protectionDomain); + } + + public native Class defineClass0(String name, byte[] b, int off, int len, + ClassLoader loader, + ProtectionDomain protectionDomain); /** * Defines a class but does not make it known to the class loader or system dictionary. @@ -755,7 +1145,13 @@ public final class Unsafe { * @param data bytes of a class file * @param cpPatches where non-null entries exist, they replace corresponding CP entries in data */ - public native Class defineAnonymousClass(Class hostClass, byte[] data, Object[] cpPatches); + public Class defineAnonymousClass(Class hostClass, byte[] data, Object[] cpPatches) { + if (hostClass == null || data == null) { + throw new NullPointerException(); + } + + return defineAnonymousClass0(hostClass, data, cpPatches); + } /** * Allocates an instance but does not run any constructor. @@ -1290,7 +1686,13 @@ public final class Unsafe { * @return the number of samples actually retrieved; or -1 * if the load average is unobtainable. */ - public native int getLoadAverage(double[] loadavg, int nelems); + public int getLoadAverage(double[] loadavg, int nelems) { + if (nelems < 0 || nelems > 3 || nelems > loadavg.length) { + throw new ArrayIndexOutOfBoundsException(); + } + + return getLoadAverage0(loadavg, nelems); + } // The following contain CAS-based Java implementations used on // platforms not supporting native instructions @@ -1718,9 +2120,6 @@ public final class Unsafe { } // JVM interface methods - private native boolean unalignedAccess0(); - private native boolean isBigEndian0(); - // BE is true iff the native endianness of this platform is big. private static final boolean BE = theUnsafe.isBigEndian0(); @@ -1820,4 +2219,26 @@ public final class Unsafe { private static short convEndian(boolean big, short n) { return big == BE ? n : Short.reverseBytes(n) ; } private static int convEndian(boolean big, int n) { return big == BE ? n : Integer.reverseBytes(n) ; } private static long convEndian(boolean big, long n) { return big == BE ? n : Long.reverseBytes(n) ; } + + + + private native long allocateMemory0(long bytes); + private native long reallocateMemory0(long address, long bytes); + private native void freeMemory0(long address); + private native void setMemory0(Object o, long offset, long bytes, byte value); + @HotSpotIntrinsicCandidate + private native void copyMemory0(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes); + private native void copySwapMemory0(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes, long elemSize); + private native long objectFieldOffset0(Field f); + private native long staticFieldOffset0(Field f); + private native Object staticFieldBase0(Field f); + private native boolean shouldBeInitialized0(Class c); + private native void ensureClassInitialized0(Class c); + private native int arrayBaseOffset0(Class arrayClass); + private native int arrayIndexScale0(Class arrayClass); + private native int addressSize0(); + private native Class defineAnonymousClass0(Class hostClass, byte[] data, Object[] cpPatches); + private native int getLoadAverage0(double[] loadavg, int nelems); + private native boolean unalignedAccess0(); + private native boolean isBigEndian0(); } diff --git a/jdk/src/java.base/share/classes/sun/misc/Unsafe.java b/jdk/src/java.base/share/classes/sun/misc/Unsafe.java index 77d2c8afa71..15ba929c32f 100644 --- a/jdk/src/java.base/share/classes/sun/misc/Unsafe.java +++ b/jdk/src/java.base/share/classes/sun/misc/Unsafe.java @@ -25,7 +25,7 @@ package sun.misc; -import jdk.internal.HotSpotIntrinsicCandidate; +import jdk.internal.vm.annotation.ForceInline; import jdk.internal.misc.VM; import sun.reflect.CallerSensitive; import sun.reflect.Reflection; @@ -39,21 +39,29 @@ import java.security.ProtectionDomain; * Although the class and all methods are public, use of this class is * limited because only trusted code can obtain instances of it. * + * Note: It is the resposibility of the caller to make sure + * arguments are checked before methods of this class are + * called. While some rudimentary checks are performed on the input, + * the checks are best effort and when performance is an overriding + * priority, as when methods of this class are optimized by the + * runtime compiler, some or all checks (if any) may be elided. Hence, + * the caller must not rely on the checks and corresponding + * exceptions! + * * @author John R. Rose * @see #getUnsafe */ public final class Unsafe { - private static native void registerNatives(); static { - registerNatives(); sun.reflect.Reflection.registerMethodsToFilter(Unsafe.class, "getUnsafe"); } private Unsafe() {} private static final Unsafe theUnsafe = new Unsafe(); + private static final jdk.internal.misc.Unsafe theInternalUnsafe = jdk.internal.misc.Unsafe.getUnsafe(); /** * Provides the caller with the capability of performing unsafe @@ -150,8 +158,10 @@ public final class Unsafe { * @throws RuntimeException No defined exceptions are thrown, not even * {@link NullPointerException} */ - @HotSpotIntrinsicCandidate - public native int getInt(Object o, long offset); + @ForceInline + public int getInt(Object o, long offset) { + return theInternalUnsafe.getInt(o, offset); + } /** * Stores a value into a given Java variable. @@ -173,15 +183,19 @@ public final class Unsafe { * @throws RuntimeException No defined exceptions are thrown, not even * {@link NullPointerException} */ - @HotSpotIntrinsicCandidate - public native void putInt(Object o, long offset, int x); + @ForceInline + public void putInt(Object o, long offset, int x) { + theInternalUnsafe.putInt(o, offset, x); + } /** * Fetches a reference value from a given Java variable. * @see #getInt(Object, long) */ - @HotSpotIntrinsicCandidate - public native Object getObject(Object o, long offset); + @ForceInline + public Object getObject(Object o, long offset) { + return theInternalUnsafe.getObject(o, offset); + } /** * Stores a reference value into a given Java variable. @@ -193,51 +207,95 @@ public final class Unsafe { * are updated. * @see #putInt(Object, long, int) */ - @HotSpotIntrinsicCandidate - public native void putObject(Object o, long offset, Object x); + @ForceInline + public void putObject(Object o, long offset, Object x) { + theInternalUnsafe.putObject(o, offset, x); + } /** @see #getInt(Object, long) */ - @HotSpotIntrinsicCandidate - public native boolean getBoolean(Object o, long offset); + @ForceInline + public boolean getBoolean(Object o, long offset) { + return theInternalUnsafe.getBoolean(o, offset); + } + /** @see #putInt(Object, long, int) */ - @HotSpotIntrinsicCandidate - public native void putBoolean(Object o, long offset, boolean x); + @ForceInline + public void putBoolean(Object o, long offset, boolean x) { + theInternalUnsafe.putBoolean(o, offset, x); + } + /** @see #getInt(Object, long) */ - @HotSpotIntrinsicCandidate - public native byte getByte(Object o, long offset); + @ForceInline + public byte getByte(Object o, long offset) { + return theInternalUnsafe.getByte(o, offset); + } + /** @see #putInt(Object, long, int) */ - @HotSpotIntrinsicCandidate - public native void putByte(Object o, long offset, byte x); + @ForceInline + public void putByte(Object o, long offset, byte x) { + theInternalUnsafe.putByte(o, offset, x); + } + /** @see #getInt(Object, long) */ - @HotSpotIntrinsicCandidate - public native short getShort(Object o, long offset); + @ForceInline + public short getShort(Object o, long offset) { + return theInternalUnsafe.getShort(o, offset); + } + /** @see #putInt(Object, long, int) */ - @HotSpotIntrinsicCandidate - public native void putShort(Object o, long offset, short x); + @ForceInline + public void putShort(Object o, long offset, short x) { + theInternalUnsafe.putShort(o, offset, x); + } + /** @see #getInt(Object, long) */ - @HotSpotIntrinsicCandidate - public native char getChar(Object o, long offset); + @ForceInline + public char getChar(Object o, long offset) { + return theInternalUnsafe.getChar(o, offset); + } + /** @see #putInt(Object, long, int) */ - @HotSpotIntrinsicCandidate - public native void putChar(Object o, long offset, char x); + @ForceInline + public void putChar(Object o, long offset, char x) { + theInternalUnsafe.putChar(o, offset, x); + } + /** @see #getInt(Object, long) */ - @HotSpotIntrinsicCandidate - public native long getLong(Object o, long offset); + @ForceInline + public long getLong(Object o, long offset) { + return theInternalUnsafe.getLong(o, offset); + } + /** @see #putInt(Object, long, int) */ - @HotSpotIntrinsicCandidate - public native void putLong(Object o, long offset, long x); + @ForceInline + public void putLong(Object o, long offset, long x) { + theInternalUnsafe.putLong(o, offset, x); + } + /** @see #getInt(Object, long) */ - @HotSpotIntrinsicCandidate - public native float getFloat(Object o, long offset); + @ForceInline + public float getFloat(Object o, long offset) { + return theInternalUnsafe.getFloat(o, offset); + } + /** @see #putInt(Object, long, int) */ - @HotSpotIntrinsicCandidate - public native void putFloat(Object o, long offset, float x); + @ForceInline + public void putFloat(Object o, long offset, float x) { + theInternalUnsafe.putFloat(o, offset, x); + } + /** @see #getInt(Object, long) */ - @HotSpotIntrinsicCandidate - public native double getDouble(Object o, long offset); + @ForceInline + public double getDouble(Object o, long offset) { + return theInternalUnsafe.getDouble(o, offset); + } + /** @see #putInt(Object, long, int) */ - @HotSpotIntrinsicCandidate - public native void putDouble(Object o, long offset, double x); + @ForceInline + public void putDouble(Object o, long offset, double x) { + theInternalUnsafe.putDouble(o, offset, x); + } + // These read VM internal data. @@ -248,7 +306,10 @@ public final class Unsafe { * @param address a memory address locating the variable * @return the value fetched from the indicated native variable */ - public native Object getUncompressedObject(long address); + @ForceInline + public Object getUncompressedObject(long address) { + return theInternalUnsafe.getUncompressedObject(address); + } /** * Fetches the {@link java.lang.Class} Java mirror for the given native @@ -257,7 +318,10 @@ public final class Unsafe { * @param metaspaceKlass a native metaspace {@code Klass} pointer * @return the {@link java.lang.Class} Java mirror */ - public native Class getJavaMirror(long metaspaceKlass); + @ForceInline + public Class getJavaMirror(long metaspaceKlass) { + return theInternalUnsafe.getJavaMirror(metaspaceKlass); + } /** * Fetches a native metaspace {@code Klass} pointer for the given Java @@ -266,7 +330,10 @@ public final class Unsafe { * @param o Java heap object for which to fetch the class pointer * @return a native metaspace {@code Klass} pointer */ - public native long getKlassPointer(Object o); + @ForceInline + public long getKlassPointer(Object o) { + return theInternalUnsafe.getKlassPointer(o); + } // These work on values in the C heap. @@ -277,8 +344,10 @@ public final class Unsafe { * * @see #allocateMemory */ - @HotSpotIntrinsicCandidate - public native byte getByte(long address); + @ForceInline + public byte getByte(long address) { + return theInternalUnsafe.getByte(address); + } /** * Stores a value into a given memory address. If the address is zero, or @@ -287,45 +356,83 @@ public final class Unsafe { * * @see #getByte(long) */ - @HotSpotIntrinsicCandidate - public native void putByte(long address, byte x); + @ForceInline + public void putByte(long address, byte x) { + theInternalUnsafe.putByte(address, x); + } /** @see #getByte(long) */ - @HotSpotIntrinsicCandidate - public native short getShort(long address); + @ForceInline + public short getShort(long address) { + return theInternalUnsafe.getShort(address); + } + /** @see #putByte(long, byte) */ - @HotSpotIntrinsicCandidate - public native void putShort(long address, short x); + @ForceInline + public void putShort(long address, short x) { + theInternalUnsafe.putShort(address, x); + } + /** @see #getByte(long) */ - @HotSpotIntrinsicCandidate - public native char getChar(long address); + @ForceInline + public char getChar(long address) { + return theInternalUnsafe.getChar(address); + } + /** @see #putByte(long, byte) */ - @HotSpotIntrinsicCandidate - public native void putChar(long address, char x); + @ForceInline + public void putChar(long address, char x) { + theInternalUnsafe.putChar(address, x); + } + /** @see #getByte(long) */ - @HotSpotIntrinsicCandidate - public native int getInt(long address); + @ForceInline + public int getInt(long address) { + return theInternalUnsafe.getInt(address); + } + /** @see #putByte(long, byte) */ - @HotSpotIntrinsicCandidate - public native void putInt(long address, int x); + @ForceInline + public void putInt(long address, int x) { + theInternalUnsafe.putInt(address, x); + } + /** @see #getByte(long) */ - @HotSpotIntrinsicCandidate - public native long getLong(long address); + @ForceInline + public long getLong(long address) { + return theInternalUnsafe.getLong(address); + } + /** @see #putByte(long, byte) */ - @HotSpotIntrinsicCandidate - public native void putLong(long address, long x); + @ForceInline + public void putLong(long address, long x) { + theInternalUnsafe.putLong(address, x); + } + /** @see #getByte(long) */ - @HotSpotIntrinsicCandidate - public native float getFloat(long address); + @ForceInline + public float getFloat(long address) { + return theInternalUnsafe.getFloat(address); + } + /** @see #putByte(long, byte) */ - @HotSpotIntrinsicCandidate - public native void putFloat(long address, float x); + @ForceInline + public void putFloat(long address, float x) { + theInternalUnsafe.putFloat(address, x); + } + /** @see #getByte(long) */ - @HotSpotIntrinsicCandidate - public native double getDouble(long address); + @ForceInline + public double getDouble(long address) { + return theInternalUnsafe.getDouble(address); + } + /** @see #putByte(long, byte) */ - @HotSpotIntrinsicCandidate - public native void putDouble(long address, double x); + @ForceInline + public void putDouble(long address, double x) { + theInternalUnsafe.putDouble(address, x); + } + /** * Fetches a native pointer from a given memory address. If the address is @@ -341,8 +448,10 @@ public final class Unsafe { * * @see #allocateMemory */ - @HotSpotIntrinsicCandidate - public native long getAddress(long address); + @ForceInline + public long getAddress(long address) { + return theInternalUnsafe.getAddress(address); + } /** * Stores a native pointer into a given memory address. If the address is @@ -354,8 +463,11 @@ public final class Unsafe { * * @see #getAddress(long) */ - @HotSpotIntrinsicCandidate - public native void putAddress(long address, long x); + @ForceInline + public void putAddress(long address, long x) { + theInternalUnsafe.putAddress(address, x); + } + /// wrappers for malloc, realloc, free: @@ -366,7 +478,16 @@ public final class Unsafe { * aligned for all value types. Dispose of this memory by calling {@link * #freeMemory}, or resize it with {@link #reallocateMemory}. * - * @throws IllegalArgumentException if the size is negative or too large + * Note: It is the resposibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if the size is negative or too large * for the native size_t type * * @throws OutOfMemoryError if the allocation is refused by the system @@ -374,7 +495,10 @@ public final class Unsafe { * @see #getByte(long) * @see #putByte(long, byte) */ - public native long allocateMemory(long bytes); + @ForceInline + public long allocateMemory(long bytes) { + return theInternalUnsafe.allocateMemory(bytes); + } /** * Resizes a new block of native memory, to the given size in bytes. The @@ -386,14 +510,26 @@ public final class Unsafe { * #reallocateMemory}. The address passed to this method may be null, in * which case an allocation will be performed. * - * @throws IllegalArgumentException if the size is negative or too large + * Note: It is the resposibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if the size is negative or too large * for the native size_t type * * @throws OutOfMemoryError if the allocation is refused by the system * * @see #allocateMemory */ - public native long reallocateMemory(long address, long bytes); + @ForceInline + public long reallocateMemory(long address, long bytes) { + return theInternalUnsafe.reallocateMemory(address, bytes); + } /** * Sets all bytes in a given block of memory to a fixed value @@ -410,9 +546,23 @@ public final class Unsafe { * If the effective address and length are (resp.) even modulo 4 or 2, * the stores take place in units of 'int' or 'short'. * + * Note: It is the resposibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if any of the arguments is invalid + * * @since 1.7 */ - public native void setMemory(Object o, long offset, long bytes, byte value); + @ForceInline + public void setMemory(Object o, long offset, long bytes, byte value) { + theInternalUnsafe.setMemory(o, offset, bytes, value); + } /** * Sets all bytes in a given block of memory to a fixed value @@ -421,8 +571,9 @@ public final class Unsafe { * *

    Equivalent to {@code setMemory(null, address, bytes, value)}. */ + @ForceInline public void setMemory(long address, long bytes, byte value) { - setMemory(null, address, bytes, value); + theInternalUnsafe.setMemory(address, bytes, value); } /** @@ -440,12 +591,26 @@ public final class Unsafe { * If the effective addresses and length are (resp.) even modulo 4 or 2, * the transfer takes place in units of 'int' or 'short'. * + * Note: It is the resposibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if any of the arguments is invalid + * * @since 1.7 */ - @HotSpotIntrinsicCandidate - public native void copyMemory(Object srcBase, long srcOffset, - Object destBase, long destOffset, - long bytes); + @ForceInline + public void copyMemory(Object srcBase, long srcOffset, + Object destBase, long destOffset, + long bytes) { + theInternalUnsafe.copyMemory(srcBase, srcOffset, destBase, destOffset, bytes); + } + /** * Sets all bytes in a given block of memory to a copy of another * block. This provides a single-register addressing mode, @@ -453,8 +618,9 @@ public final class Unsafe { * * Equivalent to {@code copyMemory(null, srcAddress, null, destAddress, bytes)}. */ + @ForceInline public void copyMemory(long srcAddress, long destAddress, long bytes) { - copyMemory(null, srcAddress, null, destAddress, bytes); + theInternalUnsafe.copyMemory(srcAddress, destAddress, bytes); } /** @@ -462,9 +628,23 @@ public final class Unsafe { * #allocateMemory} or {@link #reallocateMemory}. The address passed to * this method may be null, in which case no action is taken. * + * Note: It is the resposibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if any of the arguments is invalid + * * @see #allocateMemory */ - public native void freeMemory(long address); + @ForceInline + public void freeMemory(long address) { + theInternalUnsafe.freeMemory(address); + } /// random queries @@ -473,7 +653,7 @@ public final class Unsafe { * {@link #staticFieldOffset}, {@link #objectFieldOffset}, * or {@link #arrayBaseOffset}. */ - public static final int INVALID_FIELD_OFFSET = -1; + public static final int INVALID_FIELD_OFFSET = jdk.internal.misc.Unsafe.INVALID_FIELD_OFFSET; /** * Reports the location of a given field in the storage allocation of its @@ -493,7 +673,10 @@ public final class Unsafe { * must preserve all bits of static field offsets. * @see #getInt(Object, long) */ - public native long objectFieldOffset(Field f); + @ForceInline + public long objectFieldOffset(Field f) { + return theInternalUnsafe.objectFieldOffset(f); + } /** * Reports the location of a given static field, in conjunction with {@link @@ -512,7 +695,10 @@ public final class Unsafe { * this method reports its result as a long value. * @see #getInt(Object, long) */ - public native long staticFieldOffset(Field f); + @ForceInline + public long staticFieldOffset(Field f) { + return theInternalUnsafe.staticFieldOffset(f); + } /** * Reports the location of a given static field, in conjunction with {@link @@ -524,7 +710,10 @@ public final class Unsafe { * not be used in any way except as argument to the get and put routines in * this class. */ - public native Object staticFieldBase(Field f); + @ForceInline + public Object staticFieldBase(Field f) { + return theInternalUnsafe.staticFieldBase(f); + } /** * Detects if the given class may need to be initialized. This is often @@ -532,14 +721,20 @@ public final class Unsafe { * class. * @return false only if a call to {@code ensureClassInitialized} would have no effect */ - public native boolean shouldBeInitialized(Class c); + @ForceInline + public boolean shouldBeInitialized(Class c) { + return theInternalUnsafe.shouldBeInitialized(c); + } /** * Ensures the given class has been initialized. This is often * needed in conjunction with obtaining the static field base of a * class. */ - public native void ensureClassInitialized(Class c); + @ForceInline + public void ensureClassInitialized(Class c) { + theInternalUnsafe.ensureClassInitialized(c); + } /** * Reports the offset of the first element in the storage allocation of a @@ -551,43 +746,37 @@ public final class Unsafe { * @see #getInt(Object, long) * @see #putInt(Object, long, int) */ - public native int arrayBaseOffset(Class arrayClass); + @ForceInline + public int arrayBaseOffset(Class arrayClass) { + return theInternalUnsafe.arrayBaseOffset(arrayClass); + } /** The value of {@code arrayBaseOffset(boolean[].class)} */ - public static final int ARRAY_BOOLEAN_BASE_OFFSET - = theUnsafe.arrayBaseOffset(boolean[].class); + public static final int ARRAY_BOOLEAN_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_BOOLEAN_BASE_OFFSET; /** The value of {@code arrayBaseOffset(byte[].class)} */ - public static final int ARRAY_BYTE_BASE_OFFSET - = theUnsafe.arrayBaseOffset(byte[].class); + public static final int ARRAY_BYTE_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET; /** The value of {@code arrayBaseOffset(short[].class)} */ - public static final int ARRAY_SHORT_BASE_OFFSET - = theUnsafe.arrayBaseOffset(short[].class); + public static final int ARRAY_SHORT_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_SHORT_BASE_OFFSET; /** The value of {@code arrayBaseOffset(char[].class)} */ - public static final int ARRAY_CHAR_BASE_OFFSET - = theUnsafe.arrayBaseOffset(char[].class); + public static final int ARRAY_CHAR_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_CHAR_BASE_OFFSET; /** The value of {@code arrayBaseOffset(int[].class)} */ - public static final int ARRAY_INT_BASE_OFFSET - = theUnsafe.arrayBaseOffset(int[].class); + public static final int ARRAY_INT_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_INT_BASE_OFFSET; /** The value of {@code arrayBaseOffset(long[].class)} */ - public static final int ARRAY_LONG_BASE_OFFSET - = theUnsafe.arrayBaseOffset(long[].class); + public static final int ARRAY_LONG_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_LONG_BASE_OFFSET; /** The value of {@code arrayBaseOffset(float[].class)} */ - public static final int ARRAY_FLOAT_BASE_OFFSET - = theUnsafe.arrayBaseOffset(float[].class); + public static final int ARRAY_FLOAT_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_FLOAT_BASE_OFFSET; /** The value of {@code arrayBaseOffset(double[].class)} */ - public static final int ARRAY_DOUBLE_BASE_OFFSET - = theUnsafe.arrayBaseOffset(double[].class); + public static final int ARRAY_DOUBLE_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_DOUBLE_BASE_OFFSET; /** The value of {@code arrayBaseOffset(Object[].class)} */ - public static final int ARRAY_OBJECT_BASE_OFFSET - = theUnsafe.arrayBaseOffset(Object[].class); + public static final int ARRAY_OBJECT_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_OBJECT_BASE_OFFSET; /** * Reports the scale factor for addressing elements in the storage @@ -600,43 +789,37 @@ public final class Unsafe { * @see #getInt(Object, long) * @see #putInt(Object, long, int) */ - public native int arrayIndexScale(Class arrayClass); + @ForceInline + public int arrayIndexScale(Class arrayClass) { + return theInternalUnsafe.arrayIndexScale(arrayClass); + } /** The value of {@code arrayIndexScale(boolean[].class)} */ - public static final int ARRAY_BOOLEAN_INDEX_SCALE - = theUnsafe.arrayIndexScale(boolean[].class); + public static final int ARRAY_BOOLEAN_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_BOOLEAN_INDEX_SCALE; /** The value of {@code arrayIndexScale(byte[].class)} */ - public static final int ARRAY_BYTE_INDEX_SCALE - = theUnsafe.arrayIndexScale(byte[].class); + public static final int ARRAY_BYTE_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_BYTE_INDEX_SCALE; /** The value of {@code arrayIndexScale(short[].class)} */ - public static final int ARRAY_SHORT_INDEX_SCALE - = theUnsafe.arrayIndexScale(short[].class); + public static final int ARRAY_SHORT_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_SHORT_INDEX_SCALE; /** The value of {@code arrayIndexScale(char[].class)} */ - public static final int ARRAY_CHAR_INDEX_SCALE - = theUnsafe.arrayIndexScale(char[].class); + public static final int ARRAY_CHAR_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_CHAR_INDEX_SCALE; /** The value of {@code arrayIndexScale(int[].class)} */ - public static final int ARRAY_INT_INDEX_SCALE - = theUnsafe.arrayIndexScale(int[].class); + public static final int ARRAY_INT_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_INT_INDEX_SCALE; /** The value of {@code arrayIndexScale(long[].class)} */ - public static final int ARRAY_LONG_INDEX_SCALE - = theUnsafe.arrayIndexScale(long[].class); + public static final int ARRAY_LONG_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_LONG_INDEX_SCALE; /** The value of {@code arrayIndexScale(float[].class)} */ - public static final int ARRAY_FLOAT_INDEX_SCALE - = theUnsafe.arrayIndexScale(float[].class); + public static final int ARRAY_FLOAT_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_FLOAT_INDEX_SCALE; /** The value of {@code arrayIndexScale(double[].class)} */ - public static final int ARRAY_DOUBLE_INDEX_SCALE - = theUnsafe.arrayIndexScale(double[].class); + public static final int ARRAY_DOUBLE_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_DOUBLE_INDEX_SCALE; /** The value of {@code arrayIndexScale(Object[].class)} */ - public static final int ARRAY_OBJECT_INDEX_SCALE - = theUnsafe.arrayIndexScale(Object[].class); + public static final int ARRAY_OBJECT_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_OBJECT_INDEX_SCALE; /** * Reports the size in bytes of a native pointer, as stored via {@link @@ -644,16 +827,22 @@ public final class Unsafe { * other primitive types (as stored in native memory blocks) is determined * fully by their information content. */ - public native int addressSize(); + @ForceInline + public int addressSize() { + return theInternalUnsafe.addressSize(); + } /** The value of {@code addressSize()} */ - public static final int ADDRESS_SIZE = theUnsafe.addressSize(); + public static final int ADDRESS_SIZE = theInternalUnsafe.addressSize(); /** * Reports the size in bytes of a native memory page (whatever that is). * This value will always be a power of two. */ - public native int pageSize(); + @ForceInline + public int pageSize() { + return theInternalUnsafe.pageSize(); + } /// random trusted operations from JNI: @@ -662,9 +851,12 @@ public final class Unsafe { * Tells the VM to define a class, without security checks. By default, the * class loader and protection domain come from the caller's class. */ - public native Class defineClass(String name, byte[] b, int off, int len, - ClassLoader loader, - ProtectionDomain protectionDomain); + @ForceInline + public Class defineClass(String name, byte[] b, int off, int len, + ClassLoader loader, + ProtectionDomain protectionDomain) { + return theInternalUnsafe.defineClass(name, b, off, len, loader, protectionDomain); + } /** * Defines a class but does not make it known to the class loader or system dictionary. @@ -682,18 +874,26 @@ public final class Unsafe { * @param data bytes of a class file * @param cpPatches where non-null entries exist, they replace corresponding CP entries in data */ - public native Class defineAnonymousClass(Class hostClass, byte[] data, Object[] cpPatches); + @ForceInline + public Class defineAnonymousClass(Class hostClass, byte[] data, Object[] cpPatches) { + return theInternalUnsafe.defineAnonymousClass(hostClass, data, cpPatches); + } /** * Allocates an instance but does not run any constructor. * Initializes the class if it has not yet been. */ - @HotSpotIntrinsicCandidate - public native Object allocateInstance(Class cls) - throws InstantiationException; + @ForceInline + public Object allocateInstance(Class cls) + throws InstantiationException { + return theInternalUnsafe.allocateInstance(cls); + } /** Throws the exception without telling the verifier. */ - public native void throwException(Throwable ee); + @ForceInline + public void throwException(Throwable ee) { + theInternalUnsafe.throwException(ee); + } /** * Atomically updates Java variable to {@code x} if it is currently @@ -704,10 +904,12 @@ public final class Unsafe { * * @return {@code true} if successful */ - @HotSpotIntrinsicCandidate - public final native boolean compareAndSwapObject(Object o, long offset, - Object expected, - Object x); + @ForceInline + public final boolean compareAndSwapObject(Object o, long offset, + Object expected, + Object x) { + return theInternalUnsafe.compareAndSwapObject(o, offset, expected, x); + } /** * Atomically updates Java variable to {@code x} if it is currently @@ -718,10 +920,12 @@ public final class Unsafe { * * @return {@code true} if successful */ - @HotSpotIntrinsicCandidate - public final native boolean compareAndSwapInt(Object o, long offset, - int expected, - int x); + @ForceInline + public final boolean compareAndSwapInt(Object o, long offset, + int expected, + int x) { + return theInternalUnsafe.compareAndSwapInt(o, offset, expected, x); + } /** * Atomically updates Java variable to {@code x} if it is currently @@ -732,88 +936,126 @@ public final class Unsafe { * * @return {@code true} if successful */ - @HotSpotIntrinsicCandidate - public final native boolean compareAndSwapLong(Object o, long offset, - long expected, - long x); + @ForceInline + public final boolean compareAndSwapLong(Object o, long offset, + long expected, + long x) { + return theInternalUnsafe.compareAndSwapLong(o, offset, expected, x); + } /** * Fetches a reference value from a given Java variable, with volatile * load semantics. Otherwise identical to {@link #getObject(Object, long)} */ - @HotSpotIntrinsicCandidate - public native Object getObjectVolatile(Object o, long offset); + @ForceInline + public Object getObjectVolatile(Object o, long offset) { + return theInternalUnsafe.getObjectVolatile(o, offset); + } /** * Stores a reference value into a given Java variable, with * volatile store semantics. Otherwise identical to {@link #putObject(Object, long, Object)} */ - @HotSpotIntrinsicCandidate - public native void putObjectVolatile(Object o, long offset, Object x); + @ForceInline + public void putObjectVolatile(Object o, long offset, Object x) { + theInternalUnsafe.putObjectVolatile(o, offset, x); + } /** Volatile version of {@link #getInt(Object, long)} */ - @HotSpotIntrinsicCandidate - public native int getIntVolatile(Object o, long offset); + @ForceInline + public int getIntVolatile(Object o, long offset) { + return theInternalUnsafe.getIntVolatile(o, offset); + } /** Volatile version of {@link #putInt(Object, long, int)} */ - @HotSpotIntrinsicCandidate - public native void putIntVolatile(Object o, long offset, int x); + @ForceInline + public void putIntVolatile(Object o, long offset, int x) { + theInternalUnsafe.putIntVolatile(o, offset, x); + } /** Volatile version of {@link #getBoolean(Object, long)} */ - @HotSpotIntrinsicCandidate - public native boolean getBooleanVolatile(Object o, long offset); + @ForceInline + public boolean getBooleanVolatile(Object o, long offset) { + return theInternalUnsafe.getBooleanVolatile(o, offset); + } /** Volatile version of {@link #putBoolean(Object, long, boolean)} */ - @HotSpotIntrinsicCandidate - public native void putBooleanVolatile(Object o, long offset, boolean x); + @ForceInline + public void putBooleanVolatile(Object o, long offset, boolean x) { + theInternalUnsafe.putBooleanVolatile(o, offset, x); + } /** Volatile version of {@link #getByte(Object, long)} */ - @HotSpotIntrinsicCandidate - public native byte getByteVolatile(Object o, long offset); + @ForceInline + public byte getByteVolatile(Object o, long offset) { + return theInternalUnsafe.getByteVolatile(o, offset); + } /** Volatile version of {@link #putByte(Object, long, byte)} */ - @HotSpotIntrinsicCandidate - public native void putByteVolatile(Object o, long offset, byte x); + @ForceInline + public void putByteVolatile(Object o, long offset, byte x) { + theInternalUnsafe.putByteVolatile(o, offset, x); + } /** Volatile version of {@link #getShort(Object, long)} */ - @HotSpotIntrinsicCandidate - public native short getShortVolatile(Object o, long offset); + @ForceInline + public short getShortVolatile(Object o, long offset) { + return theInternalUnsafe.getShortVolatile(o, offset); + } /** Volatile version of {@link #putShort(Object, long, short)} */ - @HotSpotIntrinsicCandidate - public native void putShortVolatile(Object o, long offset, short x); + @ForceInline + public void putShortVolatile(Object o, long offset, short x) { + theInternalUnsafe.putShortVolatile(o, offset, x); + } /** Volatile version of {@link #getChar(Object, long)} */ - @HotSpotIntrinsicCandidate - public native char getCharVolatile(Object o, long offset); + @ForceInline + public char getCharVolatile(Object o, long offset) { + return theInternalUnsafe.getCharVolatile(o, offset); + } /** Volatile version of {@link #putChar(Object, long, char)} */ - @HotSpotIntrinsicCandidate - public native void putCharVolatile(Object o, long offset, char x); + @ForceInline + public void putCharVolatile(Object o, long offset, char x) { + theInternalUnsafe.putCharVolatile(o, offset, x); + } /** Volatile version of {@link #getLong(Object, long)} */ - @HotSpotIntrinsicCandidate - public native long getLongVolatile(Object o, long offset); + @ForceInline + public long getLongVolatile(Object o, long offset) { + return theInternalUnsafe.getLongVolatile(o, offset); + } /** Volatile version of {@link #putLong(Object, long, long)} */ - @HotSpotIntrinsicCandidate - public native void putLongVolatile(Object o, long offset, long x); + @ForceInline + public void putLongVolatile(Object o, long offset, long x) { + theInternalUnsafe.putLongVolatile(o, offset, x); + } /** Volatile version of {@link #getFloat(Object, long)} */ - @HotSpotIntrinsicCandidate - public native float getFloatVolatile(Object o, long offset); + @ForceInline + public float getFloatVolatile(Object o, long offset) { + return theInternalUnsafe.getFloatVolatile(o, offset); + } /** Volatile version of {@link #putFloat(Object, long, float)} */ - @HotSpotIntrinsicCandidate - public native void putFloatVolatile(Object o, long offset, float x); + @ForceInline + public void putFloatVolatile(Object o, long offset, float x) { + theInternalUnsafe.putFloatVolatile(o, offset, x); + } /** Volatile version of {@link #getDouble(Object, long)} */ - @HotSpotIntrinsicCandidate - public native double getDoubleVolatile(Object o, long offset); + @ForceInline + public double getDoubleVolatile(Object o, long offset) { + return theInternalUnsafe.getDoubleVolatile(o, offset); + } /** Volatile version of {@link #putDouble(Object, long, double)} */ - @HotSpotIntrinsicCandidate - public native void putDoubleVolatile(Object o, long offset, double x); + @ForceInline + public void putDoubleVolatile(Object o, long offset, double x) { + theInternalUnsafe.putDoubleVolatile(o, offset, x); + } /** * Version of {@link #putObjectVolatile(Object, long, Object)} @@ -824,16 +1066,22 @@ public final class Unsafe { * * Corresponds to C11 atomic_store_explicit(..., memory_order_release). */ - @HotSpotIntrinsicCandidate - public native void putOrderedObject(Object o, long offset, Object x); + @ForceInline + public void putOrderedObject(Object o, long offset, Object x) { + theInternalUnsafe.putOrderedObject(o, offset, x); + } /** Ordered/Lazy version of {@link #putIntVolatile(Object, long, int)} */ - @HotSpotIntrinsicCandidate - public native void putOrderedInt(Object o, long offset, int x); + @ForceInline + public void putOrderedInt(Object o, long offset, int x) { + theInternalUnsafe.putOrderedInt(o, offset, x); + } /** Ordered/Lazy version of {@link #putLongVolatile(Object, long, long)} */ - @HotSpotIntrinsicCandidate - public native void putOrderedLong(Object o, long offset, long x); + @ForceInline + public void putOrderedLong(Object o, long offset, long x) { + theInternalUnsafe.putOrderedLong(o, offset, x); + } /** * Unblocks the given thread blocked on {@code park}, or, if it is @@ -847,8 +1095,10 @@ public final class Unsafe { * * @param thread the thread to unpark. */ - @HotSpotIntrinsicCandidate - public native void unpark(Object thread); + @ForceInline + public void unpark(Object thread) { + theInternalUnsafe.unpark(thread); + } /** * Blocks current thread, returning when a balancing @@ -861,8 +1111,10 @@ public final class Unsafe { * because {@code unpark} is, so it would be strange to place it * elsewhere. */ - @HotSpotIntrinsicCandidate - public native void park(boolean isAbsolute, long time); + @ForceInline + public void park(boolean isAbsolute, long time) { + theInternalUnsafe.park(isAbsolute, time); + } /** * Gets the load average in the system run queue assigned @@ -879,7 +1131,10 @@ public final class Unsafe { * @return the number of samples actually retrieved; or -1 * if the load average is unobtainable. */ - public native int getLoadAverage(double[] loadavg, int nelems); + @ForceInline + public int getLoadAverage(double[] loadavg, int nelems) { + return theInternalUnsafe.getLoadAverage(loadavg, nelems); + } // The following contain CAS-based Java implementations used on // platforms not supporting native instructions @@ -895,13 +1150,9 @@ public final class Unsafe { * @return the previous value * @since 1.8 */ - @HotSpotIntrinsicCandidate + @ForceInline public final int getAndAddInt(Object o, long offset, int delta) { - int v; - do { - v = getIntVolatile(o, offset); - } while (!compareAndSwapInt(o, offset, v, v + delta)); - return v; + return theInternalUnsafe.getAndAddInt(o, offset, delta); } /** @@ -915,13 +1166,9 @@ public final class Unsafe { * @return the previous value * @since 1.8 */ - @HotSpotIntrinsicCandidate + @ForceInline public final long getAndAddLong(Object o, long offset, long delta) { - long v; - do { - v = getLongVolatile(o, offset); - } while (!compareAndSwapLong(o, offset, v, v + delta)); - return v; + return theInternalUnsafe.getAndAddLong(o, offset, delta); } /** @@ -935,13 +1182,9 @@ public final class Unsafe { * @return the previous value * @since 1.8 */ - @HotSpotIntrinsicCandidate + @ForceInline public final int getAndSetInt(Object o, long offset, int newValue) { - int v; - do { - v = getIntVolatile(o, offset); - } while (!compareAndSwapInt(o, offset, v, newValue)); - return v; + return theInternalUnsafe.getAndSetInt(o, offset, newValue); } /** @@ -955,13 +1198,9 @@ public final class Unsafe { * @return the previous value * @since 1.8 */ - @HotSpotIntrinsicCandidate + @ForceInline public final long getAndSetLong(Object o, long offset, long newValue) { - long v; - do { - v = getLongVolatile(o, offset); - } while (!compareAndSwapLong(o, offset, v, newValue)); - return v; + return theInternalUnsafe.getAndSetLong(o, offset, newValue); } /** @@ -975,13 +1214,9 @@ public final class Unsafe { * @return the previous value * @since 1.8 */ - @HotSpotIntrinsicCandidate + @ForceInline public final Object getAndSetObject(Object o, long offset, Object newValue) { - Object v; - do { - v = getObjectVolatile(o, offset); - } while (!compareAndSwapObject(o, offset, v, newValue)); - return v; + return theInternalUnsafe.getAndSetObject(o, offset, newValue); } @@ -997,8 +1232,10 @@ public final class Unsafe { * provide a LoadLoad barrier also provide a LoadStore barrier for free. * @since 1.8 */ - @HotSpotIntrinsicCandidate - public native void loadFence(); + @ForceInline + public void loadFence() { + theInternalUnsafe.loadFence(); + } /** * Ensures that loads and stores before the fence will not be reordered with @@ -1012,8 +1249,10 @@ public final class Unsafe { * provide a StoreStore barrier also provide a LoadStore barrier for free. * @since 1.8 */ - @HotSpotIntrinsicCandidate - public native void storeFence(); + @ForceInline + public void storeFence() { + theInternalUnsafe.storeFence(); + } /** * Ensures that loads and stores before the fence will not be reordered @@ -1024,15 +1263,8 @@ public final class Unsafe { * Corresponds to C11 atomic_thread_fence(memory_order_seq_cst). * @since 1.8 */ - @HotSpotIntrinsicCandidate - public native void fullFence(); - - /** - * Throws IllegalAccessError; for use by the VM for access control - * error support. - * @since 1.8 - */ - private static void throwIllegalAccessError() { - throw new IllegalAccessError(); + @ForceInline + public void fullFence() { + theInternalUnsafe.fullFence(); } } diff --git a/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java b/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java new file mode 100644 index 00000000000..c87bb1b6895 --- /dev/null +++ b/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java @@ -0,0 +1,667 @@ +/* + * Copyright (c) 2016, 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. + * + * 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. + */ + +import jdk.internal.misc.Unsafe; +import java.lang.reflect.Field; + +/* + * @test + * @summary Test Unsafe.copyMemory + * @modules java.base/jdk.internal.misc + */ +public class CopyMemory { + private static final boolean DEBUG = Boolean.getBoolean("CopyMemory.DEBUG"); + + public static final long KB = 1024; + public static final long MB = KB * 1024; + public static final long GB = MB * 1024; + + private static final Unsafe UNSAFE; + private static final int SMALL_COPY_SIZE = 32; + private static final int BASE_ALIGNMENT = 16; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + } + + private static long alignDown(long value, long alignment) { + return value & ~(alignment - 1); + } + + private static long alignUp(long value, long alignment) { + return (value + alignment - 1) & ~(alignment - 1); + } + + private static boolean isAligned(long value, long alignment) { + return value == alignDown(value, alignment); + } + + private CopyMemory() { + } + + /** + * Generate verification data for a given offset + * + * The verification data is used to verify that the correct bytes + * have indeed been copied and byte swapped. + * + * The data is generated based on the offset (in bytes) into the + * source buffer. For a native buffer the offset is relative to + * the base pointer. For a heap array it is relative to the + * address of the first array element. + * + * This method will return the result of doing an elementSize byte + * read starting at offset (in bytes). + * + * @param offset offset into buffer + * @param elemSize size (in bytes) of the element + * + * @return the verification data, only the least significant + * elemSize*8 bits are set, zero extended + */ + private long getVerificationDataForOffset(long offset, long elemSize) { + byte[] bytes = new byte[(int)elemSize]; + + for (long i = 0; i < elemSize; i++) { + bytes[(int)i] = (byte)(offset + i); + } + + long o = UNSAFE.arrayBaseOffset(byte[].class); + + switch ((int)elemSize) { + case 1: return Byte.toUnsignedLong(UNSAFE.getByte(bytes, o)); + case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(bytes, o)); + case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(bytes, o)); + case 8: return UNSAFE.getLongUnaligned(bytes, o); + default: throw new IllegalArgumentException("Invalid element size: " + elemSize); + } + } + + /** + * Verify byte swapped data + * + * @param ptr the data to verify + * @param srcOffset the srcOffset (in bytes) from which the copy started, + * used as key to regenerate the verification data + * @param dstOffset the offset (in bytes) in the array at which to start + * the verification, relative to the first element in the array + * @param size size (in bytes) of data to to verify + * @param elemSize size (in bytes) of the individual array elements + * + * @throws RuntimeException if an error is found + */ + private void verifySwappedData(GenericPointer ptr, long srcOffset, long dstOffset, long size, long elemSize) { + for (long offset = 0; offset < size; offset += elemSize) { + long expectedUnswapped = getVerificationDataForOffset(srcOffset + offset, elemSize); + long expected = byteSwap(expectedUnswapped, elemSize); + + long actual = getArrayElem(ptr, dstOffset + offset, elemSize); + + if (expected != actual) { + throw new RuntimeException("srcOffset: 0x" + Long.toHexString(srcOffset) + + " dstOffset: 0x" + Long.toHexString(dstOffset) + + " size: 0x" + Long.toHexString(size) + + " offset: 0x" + Long.toHexString(offset) + + " expectedUnswapped: 0x" + Long.toHexString(expectedUnswapped) + + " expected: 0x" + Long.toHexString(expected) + + " != actual: 0x" + Long.toHexString(actual)); + } + } + } + + /** + * Initialize an array with verification friendly data + * + * @param ptr pointer to the data to initialize + * @param size size (in bytes) of the data + * @param elemSize size (in bytes) of the individual elements + */ + private void initVerificationData(GenericPointer ptr, long size, long elemSize) { + for (long offset = 0; offset < size; offset++) { + byte data = (byte)getVerificationDataForOffset(offset, 1); + + if (ptr.isOnHeap()) { + UNSAFE.putByte(ptr.getObject(), ptr.getOffset() + offset, data); + } else { + UNSAFE.putByte(ptr.getOffset() + offset, data); + } + } + } + + /** + * Allocate a primitive array + * + * @param size size (in bytes) of all the array elements (elemSize * length) + * @param elemSize the size of the array elements + * + * @return a newly allocated primitive array + */ + Object allocArray(long size, long elemSize) { + int length = (int)(size / elemSize); + + switch ((int)elemSize) { + case 1: return new byte[length]; + case 2: return new short[length]; + case 4: return new int[length]; + case 8: return new long[length]; + default: + throw new IllegalArgumentException("Invalid element size: " + elemSize); + } + } + + /** + * Get the value of a primitive array entry + * + * @param ptr pointer to the data + * @param offset offset (in bytes) of the array element, relative to the first element in the array + * + * @return the array element, as an unsigned long + */ + private long getArrayElem(GenericPointer ptr, long offset, long elemSize) { + if (ptr.isOnHeap()) { + Object o = ptr.getObject(); + int index = (int)(offset / elemSize); + + if (o instanceof short[]) { + short[] arr = (short[])o; + return Short.toUnsignedLong(arr[index]); + } else if (o instanceof int[]) { + int[] arr = (int[])o; + return Integer.toUnsignedLong(arr[index]); + } else if (o instanceof long[]) { + long[] arr = (long[])o; + return arr[index]; + } else { + throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName()); + } + } else { + long addr = ptr.getOffset() + offset; + + switch ((int)elemSize) { + case 1: return Byte.toUnsignedLong(UNSAFE.getByte(addr)); + case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(null, addr)); + case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(null, addr)); + case 8: return UNSAFE.getLongUnaligned(null, addr); + default: throw new IllegalArgumentException("Invalid element size: " + elemSize); + } + } + } + + private void putValue(long addr, long elemSize, long value) { + switch ((int)elemSize) { + case 1: UNSAFE.putByte(addr, (byte)value); break; + case 2: UNSAFE.putShortUnaligned(null, addr, (short)value); break; + case 4: UNSAFE.putIntUnaligned(null, addr, (int)value); break; + case 8: UNSAFE.putLongUnaligned(null, addr, value); break; + default: throw new IllegalArgumentException("Invalid element size: " + elemSize); + } + } + + /** + * Get the size of the elements for an array + * + * @param o a primitive heap array + * + * @return the size (in bytes) of the individual array elements + */ + private long getArrayElemSize(Object o) { + if (o instanceof short[]) { + return 2; + } else if (o instanceof int[]) { + return 4; + } else if (o instanceof long[]) { + return 8; + } else { + throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName()); + } + } + + /** + * Byte swap a value + * + * @param value the value to swap, only the bytes*8 least significant bits are used + * @param size size (in bytes) of the value + * + * @return the byte swapped value in the bytes*8 least significant bits + */ + private long byteSwap(long value, long size) { + switch ((int)size) { + case 2: return Short.toUnsignedLong(Short.reverseBytes((short)value)); + case 4: return Integer.toUnsignedLong(Integer.reverseBytes((int)value)); + case 8: return Long.reverseBytes(value); + default: throw new IllegalArgumentException("Invalid element size: " + size); + } + } + + /** + * Verify data which has *not* been byte swapped + * + * @param ptr the data to verify + * @param startOffset the offset (in bytes) at which to start the verification + * @param size size (in bytes) of the data to verify + * + * @throws RuntimeException if an error is found + */ + private void verifyUnswappedData(GenericPointer ptr, long startOffset, long srcOffset, long size) { + for (long i = 0; i < size; i++) { + byte expected = (byte)getVerificationDataForOffset(srcOffset + i, 1); + + byte actual; + if (ptr.isOnHeap()) { + actual = UNSAFE.getByte(ptr.getObject(), ptr.getOffset() + startOffset + i); + } else { + actual = UNSAFE.getByte(ptr.getOffset() + startOffset + i); + } + + if (expected != actual) { + throw new RuntimeException("startOffset: 0x" + Long.toHexString(startOffset) + + " srcOffset: 0x" + Long.toHexString(srcOffset) + + " size: 0x" + Long.toHexString(size) + + " i: 0x" + Long.toHexString(i) + + " expected: 0x" + Long.toHexString(expected) + + " != actual: 0x" + Long.toHexString(actual)); + } + } + } + + + /** + * Copy and byte swap data from the source to the destination + * + * This method will pre-populate the whole source and destination + * buffers with verification friendly data. It will then use + * copypMemory to fill part of the destination buffer with + * data from the source. Some space (padding) will be + * left before and after the data in the destination buffer, which + * should not be touched/overwritten by the copy call. + * + * Note: Both source and destination buffers will be overwritten! + * + * @param src source buffer to copy from + * @param srcOffset the offset (in bytes) in the source buffer, relative to + * the first array element, at which to start reading data + * @param dst destination buffer to copy to + * @param dstOffset the offset (in bytes) in the destination + * buffer, relative to the first array element, at which to + * start writing data + * @param bufSize the size (in bytes) of the src and dst arrays + * @param copyBytes the size (in bytes) of the copy to perform, + * must be a multiple of elemSize + * + * @throws RuntimeException if an error is found + */ + private void testCopy(GenericPointer src, long srcOffset, + GenericPointer dst, long dstOffset, + long bufSize, long copyBytes) { + if (srcOffset + copyBytes > bufSize) { + throw new IllegalArgumentException( + "srcOffset (" + srcOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")"); + } + if (dstOffset + copyBytes > bufSize) { + throw new IllegalArgumentException( + "dstOffset (" + dstOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")"); + } + + // Initialize the whole source buffer with a verification friendly pattern (no 0x00 bytes) + initVerificationData(src, bufSize, 1); + if (!src.equals(dst)) { + initVerificationData(dst, bufSize, 1); + } + + if (DEBUG) { + System.out.println("===before==="); + for (int offset = 0; offset < bufSize; offset++) { + long srcValue = getArrayElem(src, offset, 1); + long dstValue = getArrayElem(dst, offset, 1); + + System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) + + " src=0x" + Long.toHexString(srcValue) + + " dst=0x" + Long.toHexString(dstValue)); + } + } + + // Copy & swap data into the middle of the destination buffer + UNSAFE.copyMemory(src.getObject(), + src.getOffset() + srcOffset, + dst.getObject(), + dst.getOffset() + dstOffset, + copyBytes); + + if (DEBUG) { + System.out.println("===after==="); + for (int offset = 0; offset < bufSize; offset++) { + long srcValue = getArrayElem(src, offset, 1); + long dstValue = getArrayElem(dst, offset, 1); + + System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) + + " src=0x" + Long.toHexString(srcValue) + + " dst=0x" + Long.toHexString(dstValue)); + } + } + + // Verify the the front padding is unchanged + verifyUnswappedData(dst, 0, 0, dstOffset); + + // Verify copied data + verifyUnswappedData(dst, dstOffset, srcOffset, copyBytes); + + // Verify that the back back padding is unchanged + long frontAndDataBytes = dstOffset + copyBytes; + long trailingBytes = bufSize - frontAndDataBytes; + verifyUnswappedData(dst, frontAndDataBytes, frontAndDataBytes, trailingBytes); + } + + /** + * Test various configurations copying from one buffer to the other + * + * @param src the source buffer to copy from + * @param dst the destination buffer to copy to + * @param size size (in bytes) of the buffers + * @param elemSize size (in bytes) of the individual elements + * + * @throws RuntimeException if an error is found + */ + public void testBufferPair(GenericPointer src, GenericPointer dst, long size, long elemSize) { + // offset in source from which to start reading data + for (long srcOffset = 0; srcOffset < size; srcOffset += (src.isOnHeap() ? elemSize : 1)) { + + // offset in destination at which to start writing data + for (int dstOffset = 0; dstOffset < size; dstOffset += (dst.isOnHeap() ? elemSize : 1)) { + + // number of bytes to copy + long maxCopyBytes = Math.min(size - srcOffset, size - dstOffset); + for (long copyBytes = 0; copyBytes < maxCopyBytes; copyBytes += elemSize) { + try { + testCopy(src, srcOffset, dst, dstOffset, size, copyBytes); + } catch (RuntimeException e) { + // Wrap the exception in another exception to catch the relevant configuration data + throw new RuntimeException("testBufferPair: " + + "src=" + src + + " dst=" + dst + + " elemSize=0x" + Long.toHexString(elemSize) + + " copyBytes=0x" + Long.toHexString(copyBytes) + + " srcOffset=0x" + Long.toHexString(srcOffset) + + " dstOffset=0x" + Long.toHexString(dstOffset), + e); + } + } + } + } + } + + /** + * Test copying between various permutations of buffers + * + * @param buffers buffers to permute (src x dst) + * @param size size (in bytes) of buffers + * @param elemSize size (in bytes) of individual elements + * + * @throws RuntimeException if an error is found + */ + public void testPermuteBuffers(GenericPointer[] buffers, long size, long elemSize) { + for (int srcIndex = 0; srcIndex < buffers.length; srcIndex++) { + for (int dstIndex = 0; dstIndex < buffers.length; dstIndex++) { + testBufferPair(buffers[srcIndex], buffers[dstIndex], size, elemSize); + } + } + } + + /** + * Test copying of a specific element size + * + * @param size size (in bytes) of buffers to allocate + * @param elemSize size (in bytes) of individual elements + * + * @throws RuntimeException if an error is found + */ + private void testElemSize(long size, long elemSize) { + long buf1Raw = 0; + long buf2Raw = 0; + + try { + buf1Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); + long buf1 = alignUp(buf1Raw, BASE_ALIGNMENT); + + buf2Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); + long buf2 = alignUp(buf2Raw, BASE_ALIGNMENT); + + GenericPointer[] buffers = { + new GenericPointer(buf1), + new GenericPointer(buf2), + new GenericPointer(allocArray(size, elemSize)), + new GenericPointer(allocArray(size, elemSize)) + }; + + testPermuteBuffers(buffers, size, elemSize); + } finally { + if (buf1Raw != 0) { + UNSAFE.freeMemory(buf1Raw); + } + if (buf2Raw != 0) { + UNSAFE.freeMemory(buf2Raw); + } + } + } + + /** + * Verify that small copies work + */ + private void testSmallCopy() { + int smallBufSize = SMALL_COPY_SIZE; + + testElemSize(smallBufSize, 1); + } + + + /** + * Verify that large copies work + */ + private void testLargeCopy() { + long size = 2 * GB + 8; + long bufRaw = 0; + + // Check that a large native copy succeeds + try { + try { + bufRaw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); + } catch (OutOfMemoryError e) { + // Accept failure, skip test + return; + } + + long buf = alignUp(bufRaw, BASE_ALIGNMENT); + + UNSAFE.copyMemory(null, buf, null, buf, size); + } catch (Exception e) { + throw new RuntimeException("copyMemory of large buffer failed"); + } finally { + if (bufRaw != 0) { + UNSAFE.freeMemory(bufRaw); + } + } + } + + /** + * Run positive tests + * + * @throws RuntimeException if an error is found + */ + private void testPositive() { + testSmallCopy(); + testLargeCopy(); + } + + /** + * Run negative tests, testing corner cases and the various exceptions + * + * @throws RuntimeException if an error is found + */ + private void testNegative() { + long bufRaw = 0; + + try { + bufRaw = UNSAFE.allocateMemory(1024); + long buf = alignUp(bufRaw, BASE_ALIGNMENT); + short[] arr = new short[16]; + + // Check illegal sizes + System.out.println("Testing negative size"); + try { + UNSAFE.copyMemory(null, buf, null, buf, -1); + throw new RuntimeException("copyMemory failed to throw IAE for size=-1"); + } catch (IllegalArgumentException e) { + // good + } + + System.out.println("Testing negative srcOffset"); + try { + // Check that negative srcOffset throws an IAE + UNSAFE.copyMemory(arr, -1, arr, UNSAFE.arrayBaseOffset(arr.getClass()), 16); + throw new RuntimeException("copyMemory failed to throw IAE for srcOffset=-1"); + } catch (IllegalArgumentException e) { + // good + } + + System.out.println("Testing negative destOffset"); + try { + // Check that negative dstOffset throws an IAE + UNSAFE.copyMemory(arr, UNSAFE.arrayBaseOffset(arr.getClass()), arr, -1, 16); + throw new RuntimeException("copyMemory failed to throw IAE for destOffset=-1"); + } catch (IllegalArgumentException e) { + // good + } + + System.out.println("Testing reference array"); + try { + // Check that a reference array destination throws IAE + UNSAFE.copyMemory(null, buf, new Object[16], UNSAFE.arrayBaseOffset(Object[].class), 16); + throw new RuntimeException("copyMemory failed to throw IAE"); + } catch (IllegalArgumentException e) { + // good + } + + // Check that invalid source & dest pointers throw IAEs (only relevant on 32-bit platforms) + if (UNSAFE.addressSize() == 4) { + long invalidPtr = (long)1 << 35; // Pick a random bit in upper 32 bits + + try { + // Check that an invalid (not 32-bit clean) source pointer throws IAE + UNSAFE.copyMemory(null, invalidPtr, null, buf, 16); + throw new RuntimeException("copyMemory failed to throw IAE for srcOffset 0x" + + Long.toHexString(invalidPtr)); + } catch (IllegalArgumentException e) { + // good + } + + try { + // Check that an invalid (not 32-bit clean) source pointer throws IAE + UNSAFE.copyMemory(null, buf, null, invalidPtr, 16); + throw new RuntimeException("copyMemory failed to throw IAE for destOffset 0x" + + Long.toHexString(invalidPtr)); + } catch (IllegalArgumentException e) { + // good + } + } + } finally { + if (bufRaw != 0) { + UNSAFE.freeMemory(bufRaw); + } + } + } + + /** + * Run all tests + * + * @throws RuntimeException if an error is found + */ + private void test() { + testPositive(); + testNegative(); + } + + public static void main(String[] args) { + CopyMemory cs = new CopyMemory(); + cs.test(); + } + + /** + * Helper class to represent a "pointer" - either a heap array or + * a pointer to a native buffer. + * + * In the case of a native pointer, the Object is null and the offset is + * the absolute address of the native buffer. + * + * In the case of a heap object, the Object is a primitive array, and + * the offset will be set to the base offset to the first element, meaning + * the object and the offset together form a double-register pointer. + */ + static class GenericPointer { + private final Object o; + private final long offset; + + private GenericPointer(Object o, long offset) { + this.o = o; + this.offset = offset; + } + + public String toString() { + return "GenericPointer(o={" + o + "}, offset=0x" + Long.toHexString(offset) + ")"; + } + + public boolean equals(Object other) { + if (!(other instanceof GenericPointer)) { + return false; + } + + GenericPointer otherp = (GenericPointer)other; + + return o == otherp.o && offset == otherp.offset; + } + + GenericPointer(Object o) { + this(o, UNSAFE.arrayBaseOffset(o.getClass())); + } + + GenericPointer(long offset) { + this(null, offset); + } + + public boolean isOnHeap() { + return o != null; + } + + public Object getObject() { + return o; + } + + public long getOffset() { + return offset; + } + } +} diff --git a/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java b/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java index ba61e23fcc9..bb94c200765 100644 --- a/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java +++ b/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java @@ -586,22 +586,6 @@ public class CopySwap { } } - try { - // Check that a NULL source throws NPE - UNSAFE.copySwapMemory(null, 0, null, buf, 16, 2); - throw new RuntimeException("copySwapMemory failed to throw NPE"); - } catch (NullPointerException e) { - // good - } - - try { - // Check that a NULL destination throws NPE - UNSAFE.copySwapMemory(null, buf, null, 0, 16, 2); - throw new RuntimeException("copySwapMemory failed to throw NPE"); - } catch (NullPointerException e) { - // good - } - try { // Check that a reference array destination throws IAE UNSAFE.copySwapMemory(null, buf, new Object[16], UNSAFE.arrayBaseOffset(Object[].class), 16, 8); From f6ca30aea569ad3877535a0849870afc290e9e0f Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 3 Mar 2016 23:57:07 +0300 Subject: [PATCH 12/36] 8150465: Unsafe methods to produce uninitialized arrays Reviewed-by: jrose, kvn, psandoz, aph, twisti, flar --- .../classes/jdk/internal/misc/Unsafe.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java b/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java index db643df591b..8b8a0ff9531 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java @@ -1161,6 +1161,59 @@ public final class Unsafe { public native Object allocateInstance(Class cls) throws InstantiationException; + /** + * Allocates an array of a given type, but does not do zeroing. + *

    + * This method should only be used in the very rare cases where a high-performance code + * overwrites the destination array completely, and compilers cannot assist in zeroing elimination. + * In an overwhelming majority of cases, a normal Java allocation should be used instead. + *

    + * Users of this method are required to overwrite the initial (garbage) array contents + * before allowing untrusted code, or code in other threads, to observe the reference + * to the newly allocated array. In addition, the publication of the array reference must be + * safe according to the Java Memory Model requirements. + *

    + * The safest approach to deal with an uninitialized array is to keep the reference to it in local + * variable at least until the initialization is complete, and then publish it once, either + * by writing it to a volatile field, or storing it into a final field in constructor, + * or issuing a {@link #storeFence} before publishing the reference. + *

    + * @implnote This method can only allocate primitive arrays, to avoid garbage reference + * elements that could break heap integrity. + * + * @param componentType array component type to allocate + * @param length array size to allocate + * @throws IllegalArgumentException if component type is null, or not a primitive class; + * or the length is negative + */ + public Object allocateUninitializedArray(Class componentType, int length) { + if (componentType == null) { + throw new IllegalArgumentException("Component type is null"); + } + if (!componentType.isPrimitive()) { + throw new IllegalArgumentException("Component type is not primitive"); + } + if (length < 0) { + throw new IllegalArgumentException("Negative length"); + } + return allocateUninitializedArray0(componentType, length); + } + + @HotSpotIntrinsicCandidate + private Object allocateUninitializedArray0(Class componentType, int length) { + // These fallbacks provide zeroed arrays, but intrinsic is not required to + // return the zeroed arrays. + if (componentType == byte.class) return new byte[length]; + if (componentType == boolean.class) return new boolean[length]; + if (componentType == short.class) return new short[length]; + if (componentType == char.class) return new char[length]; + if (componentType == int.class) return new int[length]; + if (componentType == float.class) return new float[length]; + if (componentType == long.class) return new long[length]; + if (componentType == double.class) return new double[length]; + return null; + } + /** Throws the exception without telling the verifier. */ public native void throwException(Throwable ee); From e583f827a8268378e8110c641a6575665e496e36 Mon Sep 17 00:00:00 2001 From: Sharath Ballal Date: Mon, 7 Mar 2016 20:59:35 +0300 Subject: [PATCH 13/36] 8147456: Parsing of argument for -agentpath can write outside of allocated memory Reviewed-by: sspitsyn, dholmes --- jdk/test/com/sun/jdi/BadAgentPath.java | 46 ++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 jdk/test/com/sun/jdi/BadAgentPath.java diff --git a/jdk/test/com/sun/jdi/BadAgentPath.java b/jdk/test/com/sun/jdi/BadAgentPath.java new file mode 100644 index 00000000000..e8a349b46e1 --- /dev/null +++ b/jdk/test/com/sun/jdi/BadAgentPath.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016, 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. + * + * 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. + */ + +import jdk.testlibrary.OutputAnalyzer; +import jdk.testlibrary.ProcessTools; +import jdk.testlibrary.Utils; + +/* @test + * @bug 8147456 + * @summary Check that providing a non-existing -agentpath gives a proper error. + * @author Sharath Ballal + * + * @library /lib/testlibrary + * @modules java.management + * @build jdk.testlibrary.* + * @build BadAgentPath + * @run driver BadAgentPath + */ + +public class BadAgentPath { + + public static void main(String[] args) throws Throwable { + OutputAnalyzer output = ProcessTools.executeTestJvm("-agentpath:/badAgent/agent", "-version"); + output.shouldContain("Could not find agent library /badAgent/agent"); + } +} From 27c0bb6266f64edefecbe5bce0c3c681bfd9a613 Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Tue, 15 Mar 2016 06:53:45 -0700 Subject: [PATCH 14/36] 8151858: update ASM 5.1 to accept V53.0 classfiles Reviewed-by: forax, sundar --- .../classes/jdk/internal/org/objectweb/asm/ClassReader.java | 2 +- .../share/classes/jdk/internal/org/objectweb/asm/Opcodes.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java index 523851fd70a..90593f58fc3 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java @@ -195,7 +195,7 @@ public class ClassReader { public ClassReader(final byte[] b, final int off, final int len) { this.b = b; // checks the class version - if (readShort(off + 6) > Opcodes.V1_8) { + if (readShort(off + 6) > Opcodes.V1_9) { throw new IllegalArgumentException(); } // parses the constant pool diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java index 286853352d2..d40facdafa4 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java @@ -87,6 +87,7 @@ public interface Opcodes { int V1_6 = 0 << 16 | 50; int V1_7 = 0 << 16 | 51; int V1_8 = 0 << 16 | 52; + int V1_9 = 0 << 16 | 53; // access flags From 829d62738ceb569ab20d5bf66983efe39c09f773 Mon Sep 17 00:00:00 2001 From: Roger Riggs Date: Wed, 16 Mar 2016 13:16:14 -0400 Subject: [PATCH 15/36] 8085887: java.time.format.FormatStyle.LONG or FULL causes unchecked exception 8076528: LocalTime.format() throws exception when FormatStyle is LONG or FULL Reviewed-by: sherman, scolebourne --- .../java/time/format/DateTimeFormatter.java | 9 ++ .../time/format/DateTimeFormatterBuilder.java | 3 + .../time/format/DateTimePrintContext.java | 10 +- .../java/time/temporal/TemporalQueries.java | 102 ++++++++++++++---- .../time/format/TestDateTimeFormatter.java | 76 +++++++++++++ 5 files changed, 178 insertions(+), 22 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java index 01498d340a5..80895c8a8a2 100644 --- a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java +++ b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java @@ -619,6 +619,9 @@ public final class DateTimeFormatter { * The returned formatter has a chronology of ISO set to ensure dates in * other calendar systems are correctly converted. * It has no override zone and uses the {@link ResolverStyle#SMART SMART} resolver style. + * The {@code FULL} and {@code LONG} styles typically require a time-zone. + * When formatting using these styles, a {@code ZoneId} must be available, + * either by using {@code ZonedDateTime} or {@link DateTimeFormatter#withZone}. * * @param timeStyle the formatter style to obtain, not null * @return the time formatter, not null @@ -647,6 +650,9 @@ public final class DateTimeFormatter { * The returned formatter has a chronology of ISO set to ensure dates in * other calendar systems are correctly converted. * It has no override zone and uses the {@link ResolverStyle#SMART SMART} resolver style. + * The {@code FULL} and {@code LONG} styles typically require a time-zone. + * When formatting using these styles, a {@code ZoneId} must be available, + * either by using {@code ZonedDateTime} or {@link DateTimeFormatter#withZone}. * * @param dateTimeStyle the formatter style to obtain, not null * @return the date-time formatter, not null @@ -675,6 +681,9 @@ public final class DateTimeFormatter { * The returned formatter has a chronology of ISO set to ensure dates in * other calendar systems are correctly converted. * It has no override zone and uses the {@link ResolverStyle#SMART SMART} resolver style. + * The {@code FULL} and {@code LONG} styles typically require a time-zone. + * When formatting using these styles, a {@code ZoneId} must be available, + * either by using {@code ZonedDateTime} or {@link DateTimeFormatter#withZone}. * * @param dateStyle the date formatter style to obtain, not null * @param timeStyle the time formatter style to obtain, not null diff --git a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java index 441ac711110..17d9759f51f 100644 --- a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -1256,6 +1256,9 @@ public final class DateTimeFormatterBuilder { * During formatting, the chronology is obtained from the temporal object * being formatted, which may have been overridden by * {@link DateTimeFormatter#withChronology(Chronology)}. + * The {@code FULL} and {@code LONG} styles typically require a time-zone. + * When formatting using these styles, a {@code ZoneId} must be available, + * either by using {@code ZonedDateTime} or {@link DateTimeFormatter#withZone}. *

    * During parsing, if a chronology has already been parsed, then it is used. * Otherwise the default from {@code DateTimeFormatter.withChronology(Chronology)} diff --git a/jdk/src/java.base/share/classes/java/time/format/DateTimePrintContext.java b/jdk/src/java.base/share/classes/java/time/format/DateTimePrintContext.java index 310f6598fc9..811bd5b2ee1 100644 --- a/jdk/src/java.base/share/classes/java/time/format/DateTimePrintContext.java +++ b/jdk/src/java.base/share/classes/java/time/format/DateTimePrintContext.java @@ -218,6 +218,13 @@ final class DateTimePrintContext { } return query.queryFrom(this); } + + @Override + public String toString() { + return temporal + + (effectiveChrono != null ? " with chronology " + effectiveChrono : "") + + (effectiveZone != null ? " with zone " + effectiveZone : ""); + } }; } @@ -279,7 +286,8 @@ final class DateTimePrintContext { R getValue(TemporalQuery query) { R result = temporal.query(query); if (result == null && optional == 0) { - throw new DateTimeException("Unable to extract value: " + temporal.getClass()); + throw new DateTimeException("Unable to extract " + + query + " from temporal " + temporal); } return result; } diff --git a/jdk/src/java.base/share/classes/java/time/temporal/TemporalQueries.java b/jdk/src/java.base/share/classes/java/time/temporal/TemporalQueries.java index 6b1777a9471..9df66bb7cd2 100644 --- a/jdk/src/java.base/share/classes/java/time/temporal/TemporalQueries.java +++ b/jdk/src/java.base/share/classes/java/time/temporal/TemporalQueries.java @@ -341,58 +341,118 @@ public final class TemporalQueries { /** * A strict query for the {@code ZoneId}. */ - static final TemporalQuery ZONE_ID = (temporal) -> - temporal.query(TemporalQueries.ZONE_ID); + static final TemporalQuery ZONE_ID = new TemporalQuery<>() { + @Override + public ZoneId queryFrom(TemporalAccessor temporal) { + return temporal.query(TemporalQueries.ZONE_ID); + } + + @Override + public String toString() { + return "ZoneId"; + } + }; /** * A query for the {@code Chronology}. */ - static final TemporalQuery CHRONO = (temporal) -> - temporal.query(TemporalQueries.CHRONO); + static final TemporalQuery CHRONO = new TemporalQuery<>() { + @Override + public Chronology queryFrom(TemporalAccessor temporal) { + return temporal.query(TemporalQueries.CHRONO); + } + + @Override + public String toString() { + return "Chronology"; + } + }; + /** * A query for the smallest supported unit. */ - static final TemporalQuery PRECISION = (temporal) -> - temporal.query(TemporalQueries.PRECISION); + static final TemporalQuery PRECISION = new TemporalQuery<>() { + @Override + public TemporalUnit queryFrom(TemporalAccessor temporal) { + return temporal.query(TemporalQueries.PRECISION); + } + + @Override + public String toString() { + return "Precision"; + } + }; //----------------------------------------------------------------------- /** * A query for {@code ZoneOffset} returning null if not found. */ - static final TemporalQuery OFFSET = (temporal) -> { - if (temporal.isSupported(OFFSET_SECONDS)) { - return ZoneOffset.ofTotalSeconds(temporal.get(OFFSET_SECONDS)); + static final TemporalQuery OFFSET = new TemporalQuery<>() { + @Override + public ZoneOffset queryFrom(TemporalAccessor temporal) { + if (temporal.isSupported(OFFSET_SECONDS)) { + return ZoneOffset.ofTotalSeconds(temporal.get(OFFSET_SECONDS)); + } + return null; + } + + @Override + public String toString() { + return "ZoneOffset"; } - return null; }; /** * A lenient query for the {@code ZoneId}, falling back to the {@code ZoneOffset}. */ - static final TemporalQuery ZONE = (temporal) -> { - ZoneId zone = temporal.query(ZONE_ID); - return (zone != null ? zone : temporal.query(OFFSET)); + static final TemporalQuery ZONE = new TemporalQuery<>() { + @Override + public ZoneId queryFrom(TemporalAccessor temporal) { + ZoneId zone = temporal.query(ZONE_ID); + return (zone != null ? zone : temporal.query(OFFSET)); + } + + @Override + public String toString() { + return "Zone"; + } }; /** * A query for {@code LocalDate} returning null if not found. */ - static final TemporalQuery LOCAL_DATE = (temporal) -> { - if (temporal.isSupported(EPOCH_DAY)) { - return LocalDate.ofEpochDay(temporal.getLong(EPOCH_DAY)); + static final TemporalQuery LOCAL_DATE = new TemporalQuery<>() { + @Override + public LocalDate queryFrom(TemporalAccessor temporal) { + if (temporal.isSupported(EPOCH_DAY)) { + return LocalDate.ofEpochDay(temporal.getLong(EPOCH_DAY)); + } + return null; + } + + @Override + public String toString() { + return "LocalDate"; } - return null; }; /** * A query for {@code LocalTime} returning null if not found. */ - static final TemporalQuery LOCAL_TIME = (temporal) -> { - if (temporal.isSupported(NANO_OF_DAY)) { - return LocalTime.ofNanoOfDay(temporal.getLong(NANO_OF_DAY)); + static final TemporalQuery LOCAL_TIME = new TemporalQuery<>() { + @Override + public LocalTime queryFrom(TemporalAccessor temporal) { + if (temporal.isSupported(NANO_OF_DAY)) { + return LocalTime.ofNanoOfDay(temporal.getLong(NANO_OF_DAY)); + } + return null; + } + + @Override + public String toString() { + return "LocalTime"; } - return null; }; } diff --git a/jdk/test/java/time/test/java/time/format/TestDateTimeFormatter.java b/jdk/test/java/time/test/java/time/format/TestDateTimeFormatter.java index 1bfa4799320..c9c513fa542 100644 --- a/jdk/test/java/time/test/java/time/format/TestDateTimeFormatter.java +++ b/jdk/test/java/time/test/java/time/format/TestDateTimeFormatter.java @@ -79,19 +79,24 @@ import java.time.YearMonth; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; +import java.time.chrono.Chronology; import java.time.chrono.ThaiBuddhistChronology; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.DecimalStyle; import java.time.format.SignStyle; +import java.time.format.TextStyle; +import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; import java.util.Locale; import java.util.function.Function; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** * Test DateTimeFormatter. + * @bug 8085887 */ @Test public class TestDateTimeFormatter { @@ -196,4 +201,75 @@ public class TestDateTimeFormatter { assertTrue(msg.contains("11:30:56"), msg); } + @DataProvider(name="nozone_exception_cases") + Object[][] exceptionCases() { + return new Object[][] { + {LocalDateTime.of(2000, 1, 1, 1, 1), "z", "ZoneId"}, + {OffsetDateTime.of(2000, 1, 1, 3, 3, 3, 0, ZoneOffset.ofTotalSeconds(60)), "z", "ZoneId"}, + }; + } + + // Test cases that should throw an exception with a cogent message + // containing the Type being queried and the Temporal being queried. + @Test(dataProvider="nozone_exception_cases") + public void test_throws_message(Temporal temporal, String pattern, String queryName) { + DateTimeFormatter fmt = DateTimeFormatter.ofPattern(pattern); + try { + fmt.format(temporal); + fail("Format using \"" + pattern + "\" with " + + temporal + " should have failed"); + } catch (DateTimeException dte) { + String msg = dte.getMessage(); + // Verify message contains the type that is missing and the temporal value + assertTrue(msg.contains(queryName), + String.format("\"%s\" missing from %s", queryName, msg)); + String s = temporal.toString(); + assertTrue(msg.contains(s), + String.format("\"%s\" missing from %s", s, msg)); + } + + } + + // Test cases that should throw an exception with a cogent message when missing the Chronology + @Test + public void test_throws_message_chrono() { + Chronology chrono = ThaiBuddhistChronology.INSTANCE; + DateTimeFormatter fmt = new DateTimeFormatterBuilder().appendZoneId().toFormatter() + .withChronology(chrono); + LocalTime now = LocalTime.now(); + try { + fmt.format(now); + fail("Format using appendZoneId() should have failed"); + } catch (DateTimeException dte) { + String msg = dte.getMessage(); + // Verify message contains the type that is missing and the temporal value + assertTrue(msg.contains("ZoneId"), + String.format("\"%s\" missing from %s", "ZoneId", msg)); + assertTrue(msg.contains(chrono.toString()), + String.format("\"%s\" missing from %s", chrono.toString(), msg)); + } + + } + + // Test cases that should throw an exception with a cogent message when missing the ZoneId + @Test + public void test_throws_message_zone() { + ZoneId zone = ZoneId.of("Pacific/Honolulu"); + DateTimeFormatter fmt = new DateTimeFormatterBuilder().appendChronologyId().toFormatter() + .withZone(zone); + LocalTime now = LocalTime.now(); + try { + fmt.format(now); + fail("Format using appendChronologyId() should have failed"); + } catch (DateTimeException dte) { + String msg = dte.getMessage(); + // Verify message contains the type that is missing and the temporal value + assertTrue(msg.contains("Chronology"), + String.format("\"%s\" missing from %s", "Chronology", msg)); + assertTrue(msg.contains(zone.toString()), + String.format("\"%s\" missing from %s", zone.toString(), msg)); + } + + } + } From bda07f129a3aaa99e5ed6d4e590ac45e897a45bf Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Wed, 16 Mar 2016 14:04:12 -0700 Subject: [PATCH 16/36] 8151233: Unify CopySwap and CopyMemory tests Reviewed-by: dholmes --- .../jdk/internal/misc/Unsafe/CopyCommon.java | 607 ++++++++++++++++++ .../jdk/internal/misc/Unsafe/CopyMemory.java | 537 +--------------- .../jdk/internal/misc/Unsafe/CopySwap.java | 552 +--------------- 3 files changed, 615 insertions(+), 1081 deletions(-) create mode 100644 jdk/test/jdk/internal/misc/Unsafe/CopyCommon.java diff --git a/jdk/test/jdk/internal/misc/Unsafe/CopyCommon.java b/jdk/test/jdk/internal/misc/Unsafe/CopyCommon.java new file mode 100644 index 00000000000..65e2b587388 --- /dev/null +++ b/jdk/test/jdk/internal/misc/Unsafe/CopyCommon.java @@ -0,0 +1,607 @@ +/* + * Copyright (c) 2016, 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. + * + * 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. + */ + +import jdk.internal.misc.Unsafe; +import java.lang.reflect.Field; + +/** + * Helper class to support testing of Unsafe.copyMemory and Unsafe.copySwapMemory + */ +public class CopyCommon { + private static final boolean DEBUG = Boolean.getBoolean("CopyCommon.DEBUG"); + + public static final long KB = 1024; + public static final long MB = KB * 1024; + public static final long GB = MB * 1024; + + static final int SMALL_COPY_SIZE = 32; + static final int BASE_ALIGNMENT = 16; + + protected static final Unsafe UNSAFE; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + } + + static long alignDown(long value, long alignment) { + return value & ~(alignment - 1); + } + + static long alignUp(long value, long alignment) { + return (value + alignment - 1) & ~(alignment - 1); + } + + static boolean isAligned(long value, long alignment) { + return value == alignDown(value, alignment); + } + + CopyCommon() { + } + + /** + * Generate verification data for a given offset + * + * The verification data is used to verify that the correct bytes + * have indeed been copied and byte swapped. + * + * The data is generated based on the offset (in bytes) into the + * source buffer. For a native buffer the offset is relative to + * the base pointer. For a heap array it is relative to the + * address of the first array element. + * + * This method will return the result of doing an elementSize byte + * read starting at offset (in bytes). + * + * @param offset offset into buffer + * @param elemSize size (in bytes) of the element + * + * @return the verification data, only the least significant + * elemSize*8 bits are set, zero extended + */ + private long getVerificationDataForOffset(long offset, long elemSize) { + byte[] bytes = new byte[(int)elemSize]; + + for (long i = 0; i < elemSize; i++) { + bytes[(int)i] = (byte)(offset + i); + } + + long o = UNSAFE.arrayBaseOffset(byte[].class); + + switch ((int)elemSize) { + case 1: return Byte.toUnsignedLong(UNSAFE.getByte(bytes, o)); + case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(bytes, o)); + case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(bytes, o)); + case 8: return UNSAFE.getLongUnaligned(bytes, o); + default: throw new IllegalArgumentException("Invalid element size: " + elemSize); + } + } + + /** + * Verify byte swapped data + * + * @param ptr the data to verify + * @param srcOffset the srcOffset (in bytes) from which the copy started, + * used as key to regenerate the verification data + * @param dstOffset the offset (in bytes) in the array at which to start + * the verification, relative to the first element in the array + * @param size size (in bytes) of data to to verify + * @param elemSize size (in bytes) of the individual array elements + * + * @throws RuntimeException if an error is found + */ + private void verifySwappedData(GenericPointer ptr, long srcOffset, long dstOffset, long size, long elemSize) { + for (long offset = 0; offset < size; offset += elemSize) { + long expectedUnswapped = getVerificationDataForOffset(srcOffset + offset, elemSize); + long expected = byteSwap(expectedUnswapped, elemSize); + + long actual = getArrayElem(ptr, dstOffset + offset, elemSize); + + if (expected != actual) { + throw new RuntimeException("srcOffset: 0x" + Long.toHexString(srcOffset) + + " dstOffset: 0x" + Long.toHexString(dstOffset) + + " size: 0x" + Long.toHexString(size) + + " offset: 0x" + Long.toHexString(offset) + + " expectedUnswapped: 0x" + Long.toHexString(expectedUnswapped) + + " expected: 0x" + Long.toHexString(expected) + + " != actual: 0x" + Long.toHexString(actual)); + } + } + } + + /** + * Initialize an array with verification friendly data + * + * @param ptr pointer to the data to initialize + * @param size size (in bytes) of the data + * @param elemSize size (in bytes) of the individual elements + */ + private void initVerificationData(GenericPointer ptr, long size, long elemSize) { + for (long offset = 0; offset < size; offset++) { + byte data = (byte)getVerificationDataForOffset(offset, 1); + + if (ptr.isOnHeap()) { + UNSAFE.putByte(ptr.getObject(), ptr.getOffset() + offset, data); + } else { + UNSAFE.putByte(ptr.getOffset() + offset, data); + } + } + } + + /** + * Allocate a primitive array + * + * @param size size (in bytes) of all the array elements (elemSize * length) + * @param elemSize the size of the array elements + * + * @return a newly allocated primitive array + */ + Object allocArray(long size, long elemSize) { + int length = (int)(size / elemSize); + + switch ((int)elemSize) { + case 1: return new byte[length]; + case 2: return new short[length]; + case 4: return new int[length]; + case 8: return new long[length]; + default: + throw new IllegalArgumentException("Invalid element size: " + elemSize); + } + } + + /** + * Get the value of a primitive array entry + * + * @param ptr pointer to the data + * @param offset offset (in bytes) of the array element, relative to the first element in the array + * + * @return the array element, as an unsigned long + */ + private long getArrayElem(GenericPointer ptr, long offset, long elemSize) { + if (ptr.isOnHeap()) { + Object o = ptr.getObject(); + int index = (int)(offset / elemSize); + + if (o instanceof short[]) { + short[] arr = (short[])o; + return Short.toUnsignedLong(arr[index]); + } else if (o instanceof int[]) { + int[] arr = (int[])o; + return Integer.toUnsignedLong(arr[index]); + } else if (o instanceof long[]) { + long[] arr = (long[])o; + return arr[index]; + } else { + throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName()); + } + } else { + long addr = ptr.getOffset() + offset; + + switch ((int)elemSize) { + case 1: return Byte.toUnsignedLong(UNSAFE.getByte(addr)); + case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(null, addr)); + case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(null, addr)); + case 8: return UNSAFE.getLongUnaligned(null, addr); + default: throw new IllegalArgumentException("Invalid element size: " + elemSize); + } + } + } + + private void putValue(long addr, long elemSize, long value) { + switch ((int)elemSize) { + case 1: UNSAFE.putByte(addr, (byte)value); break; + case 2: UNSAFE.putShortUnaligned(null, addr, (short)value); break; + case 4: UNSAFE.putIntUnaligned(null, addr, (int)value); break; + case 8: UNSAFE.putLongUnaligned(null, addr, value); break; + default: throw new IllegalArgumentException("Invalid element size: " + elemSize); + } + } + + /** + * Get the size of the elements for an array + * + * @param o a primitive heap array + * + * @return the size (in bytes) of the individual array elements + */ + private long getArrayElemSize(Object o) { + if (o instanceof short[]) { + return 2; + } else if (o instanceof int[]) { + return 4; + } else if (o instanceof long[]) { + return 8; + } else { + throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName()); + } + } + + /** + * Byte swap a value + * + * @param value the value to swap, only the bytes*8 least significant bits are used + * @param size size (in bytes) of the value + * + * @return the byte swapped value in the bytes*8 least significant bits + */ + private long byteSwap(long value, long size) { + switch ((int)size) { + case 2: return Short.toUnsignedLong(Short.reverseBytes((short)value)); + case 4: return Integer.toUnsignedLong(Integer.reverseBytes((int)value)); + case 8: return Long.reverseBytes(value); + default: throw new IllegalArgumentException("Invalid element size: " + size); + } + } + + /** + * Verify data which has *not* been byte swapped + * + * @param ptr the data to verify + * @param startOffset the offset (in bytes) at which to start the verification + * @param size size (in bytes) of the data to verify + * + * @throws RuntimeException if an error is found + */ + private void verifyUnswappedData(GenericPointer ptr, long startOffset, long srcOffset, long size) { + for (long i = 0; i < size; i++) { + byte expected = (byte)getVerificationDataForOffset(srcOffset + i, 1); + + byte actual; + if (ptr.isOnHeap()) { + actual = UNSAFE.getByte(ptr.getObject(), ptr.getOffset() + startOffset + i); + } else { + actual = UNSAFE.getByte(ptr.getOffset() + startOffset + i); + } + + if (expected != actual) { + throw new RuntimeException("startOffset: 0x" + Long.toHexString(startOffset) + + " srcOffset: 0x" + Long.toHexString(srcOffset) + + " size: 0x" + Long.toHexString(size) + + " i: 0x" + Long.toHexString(i) + + " expected: 0x" + Long.toHexString(expected) + + " != actual: 0x" + Long.toHexString(actual)); + } + } + } + + + /** + * Copy and byte swap data from the source to the destination + * + * This method will pre-populate the whole source and destination + * buffers with verification friendly data. It will then copy data + * to fill part of the destination buffer with data from the + * source, optionally byte swapping the copied elements on the + * fly. Some space (padding) will be left before and after the + * data in the destination buffer, which should not be + * touched/overwritten by the copy call. + * + * Note: Both source and destination buffers will be overwritten! + * + * @param src source buffer to copy from + * @param srcOffset the offset (in bytes) in the source buffer, relative to + * the first array element, at which to start reading data + * @param dst destination buffer to copy to + * @param dstOffset the offset (in bytes) in the destination + * buffer, relative to the first array element, at which to + * start writing data + * @param bufSize the size (in bytes) of the src and dst arrays + * @param copyBytes the size (in bytes) of the copy to perform, + * must be a multiple of elemSize + * @param elemSize the size (in bytes) of the elements + * @param swap true if elements should be byte swapped + * + * @throws RuntimeException if an error is found + */ + void testCopyGeneric(GenericPointer src, long srcOffset, + GenericPointer dst, long dstOffset, + long bufSize, long copyBytes, long elemSize, boolean swap) { + if (swap) { + if (!isAligned(copyBytes, elemSize)) { + throw new IllegalArgumentException( + "copyBytes (" + copyBytes + ") must be a multiple of elemSize (" + elemSize + ")"); + } + if (src.isOnHeap() && !isAligned(srcOffset, elemSize)) { + throw new IllegalArgumentException( + "srcOffset (" + srcOffset + ") must be a multiple of elemSize (" + elemSize + ")"); + } + if (dst.isOnHeap() && !isAligned(dstOffset, elemSize)) { + throw new IllegalArgumentException( + "dstOffset (" + dstOffset + ") must be a multiple of elemSize (" + elemSize + ")"); + } + } + + if (srcOffset + copyBytes > bufSize) { + throw new IllegalArgumentException( + "srcOffset (" + srcOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")"); + } + if (dstOffset + copyBytes > bufSize) { + throw new IllegalArgumentException( + "dstOffset (" + dstOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")"); + } + + // Initialize the whole source buffer with a verification friendly pattern (no 0x00 bytes) + initVerificationData(src, bufSize, elemSize); + if (!src.equals(dst)) { + initVerificationData(dst, bufSize, elemSize); + } + + if (DEBUG) { + System.out.println("===before==="); + for (int offset = 0; offset < bufSize; offset += elemSize) { + long srcValue = getArrayElem(src, offset, elemSize); + long dstValue = getArrayElem(dst, offset, elemSize); + + System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) + + " src=0x" + Long.toHexString(srcValue) + + " dst=0x" + Long.toHexString(dstValue)); + } + } + + if (swap) { + // Copy & swap data into the middle of the destination buffer + UNSAFE.copySwapMemory(src.getObject(), + src.getOffset() + srcOffset, + dst.getObject(), + dst.getOffset() + dstOffset, + copyBytes, + elemSize); + } else { + // Copy & swap data into the middle of the destination buffer + UNSAFE.copyMemory(src.getObject(), + src.getOffset() + srcOffset, + dst.getObject(), + dst.getOffset() + dstOffset, + copyBytes); + } + + if (DEBUG) { + System.out.println("===after==="); + for (int offset = 0; offset < bufSize; offset += elemSize) { + long srcValue = getArrayElem(src, offset, elemSize); + long dstValue = getArrayElem(dst, offset, elemSize); + + System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) + + " src=0x" + Long.toHexString(srcValue) + + " dst=0x" + Long.toHexString(dstValue)); + } + } + + // Verify the the front padding is unchanged + verifyUnswappedData(dst, 0, 0, dstOffset); + + if (swap) { + // Verify swapped data + verifySwappedData(dst, srcOffset, dstOffset, copyBytes, elemSize); + } else { + // Verify copied/unswapped data + verifyUnswappedData(dst, dstOffset, srcOffset, copyBytes); + } + + // Verify that the back padding is unchanged + long frontAndCopyBytes = dstOffset + copyBytes; + long trailingBytes = bufSize - frontAndCopyBytes; + verifyUnswappedData(dst, frontAndCopyBytes, frontAndCopyBytes, trailingBytes); + } + + /** + * Test various configurations of copying and optionally swapping data + * + * @param src the source buffer to copy from + * @param dst the destination buffer to copy to + * @param size size (in bytes) of the buffers + * @param elemSize size (in bytes) of the individual elements + * + * @throws RuntimeException if an error is found + */ + public void testBufferPair(GenericPointer src, GenericPointer dst, long size, long elemSize, boolean swap) { + // offset in source from which to start reading data + for (long srcOffset = 0; srcOffset < size; srcOffset += (src.isOnHeap() ? elemSize : 1)) { + + // offset in destination at which to start writing data + for (int dstOffset = 0; dstOffset < size; dstOffset += (dst.isOnHeap() ? elemSize : 1)) { + + // number of bytes to copy + long maxCopyBytes = Math.min(size - srcOffset, size - dstOffset); + for (long copyBytes = 0; copyBytes < maxCopyBytes; copyBytes += elemSize) { + try { + testCopyGeneric(src, srcOffset, dst, dstOffset, size, copyBytes, elemSize, swap); + } catch (RuntimeException e) { + // Wrap the exception in another exception to catch the relevant configuration data + throw new RuntimeException("testBufferPair: " + + "src=" + src + + " dst=" + dst + + " elemSize=0x" + Long.toHexString(elemSize) + + " copyBytes=0x" + Long.toHexString(copyBytes) + + " srcOffset=0x" + Long.toHexString(srcOffset) + + " dstOffset=0x" + Long.toHexString(dstOffset) + + " swap=" + swap, + e); + } + } + } + } + } + + /** + * Test copying between various permutations of buffers + * + * @param buffers buffers to permute (src x dst) + * @param size size (in bytes) of buffers + * @param elemSize size (in bytes) of individual elements + * + * @throws RuntimeException if an error is found + */ + public void testPermuteBuffers(GenericPointer[] buffers, long size, long elemSize, boolean swap) { + System.out.println("testPermuteBuffers(buffers, " + size + ", " + elemSize + ", " + swap + ")"); + for (int srcIndex = 0; srcIndex < buffers.length; srcIndex++) { + for (int dstIndex = 0; dstIndex < buffers.length; dstIndex++) { + testBufferPair(buffers[srcIndex], buffers[dstIndex], size, elemSize, swap); + } + } + } + + /** + * Test copying of a specific element size + * + * @param size size (in bytes) of buffers to allocate + * @param elemSize size (in bytes) of individual elements + * + * @throws RuntimeException if an error is found + */ + private void testElemSize(long size, long elemSize, boolean swap) { + long buf1Raw = 0; + long buf2Raw = 0; + + try { + buf1Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); + long buf1 = alignUp(buf1Raw, BASE_ALIGNMENT); + + buf2Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); + long buf2 = alignUp(buf2Raw, BASE_ALIGNMENT); + + GenericPointer[] buffers = { + new GenericPointer(buf1), + new GenericPointer(buf2), + new GenericPointer(allocArray(size, elemSize)), + new GenericPointer(allocArray(size, elemSize)) + }; + + testPermuteBuffers(buffers, size, elemSize, swap); + } finally { + if (buf1Raw != 0) { + UNSAFE.freeMemory(buf1Raw); + } + if (buf2Raw != 0) { + UNSAFE.freeMemory(buf2Raw); + } + } + } + + /** + * Verify that small copies work + */ + void testSmallCopy(boolean swap) { + int smallBufSize = SMALL_COPY_SIZE; + int minElemSize = swap ? 2 : 1; + int maxElemSize = swap ? 8 : 1; + + // Test various element types and heap/native combinations + for (long elemSize = minElemSize; elemSize <= maxElemSize; elemSize <<= 1) { + testElemSize(smallBufSize, elemSize, swap); + } + } + + + /** + * Verify that large copies work + */ + void testLargeCopy(boolean swap) { + long size = 2 * GB + 8; + long bufRaw = 0; + + // Check that a large native copy succeeds + try { + try { + bufRaw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); + } catch (OutOfMemoryError e) { + // Accept failure, skip test + return; + } + + long buf = alignUp(bufRaw, BASE_ALIGNMENT); + + if (swap) { + UNSAFE.copySwapMemory(null, buf, null, buf, size, 8); + } else { + UNSAFE.copyMemory(null, buf, null, buf, size); + } + } catch (Exception e) { + throw new RuntimeException("copy of large buffer failed (swap=" + swap + ")"); + } finally { + if (bufRaw != 0) { + UNSAFE.freeMemory(bufRaw); + } + } + } + + /** + * Helper class to represent a "pointer" - either a heap array or + * a pointer to a native buffer. + * + * In the case of a native pointer, the Object is null and the offset is + * the absolute address of the native buffer. + * + * In the case of a heap object, the Object is a primitive array, and + * the offset will be set to the base offset to the first element, meaning + * the object and the offset together form a double-register pointer. + */ + static class GenericPointer { + private final Object o; + private final long offset; + + private GenericPointer(Object o, long offset) { + this.o = o; + this.offset = offset; + } + + public String toString() { + return "GenericPointer(o={" + o + "}, offset=0x" + Long.toHexString(offset) + ")"; + } + + public boolean equals(Object other) { + if (!(other instanceof GenericPointer)) { + return false; + } + + GenericPointer otherp = (GenericPointer)other; + + return o == otherp.o && offset == otherp.offset; + } + + GenericPointer(Object o) { + this(o, UNSAFE.arrayBaseOffset(o.getClass())); + } + + GenericPointer(long offset) { + this(null, offset); + } + + public boolean isOnHeap() { + return o != null; + } + + public Object getObject() { + return o; + } + + public long getOffset() { + return offset; + } + } +} diff --git a/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java b/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java index c87bb1b6895..d4879e603f1 100644 --- a/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java +++ b/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java @@ -29,492 +29,18 @@ import java.lang.reflect.Field; * @summary Test Unsafe.copyMemory * @modules java.base/jdk.internal.misc */ -public class CopyMemory { - private static final boolean DEBUG = Boolean.getBoolean("CopyMemory.DEBUG"); - - public static final long KB = 1024; - public static final long MB = KB * 1024; - public static final long GB = MB * 1024; - - private static final Unsafe UNSAFE; - private static final int SMALL_COPY_SIZE = 32; - private static final int BASE_ALIGNMENT = 16; - - static { - try { - Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); - f.setAccessible(true); - UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); - } catch (Exception e) { - throw new RuntimeException("Unable to get Unsafe instance.", e); - } - } - - private static long alignDown(long value, long alignment) { - return value & ~(alignment - 1); - } - - private static long alignUp(long value, long alignment) { - return (value + alignment - 1) & ~(alignment - 1); - } - - private static boolean isAligned(long value, long alignment) { - return value == alignDown(value, alignment); - } - +public class CopyMemory extends CopyCommon { private CopyMemory() { } - /** - * Generate verification data for a given offset - * - * The verification data is used to verify that the correct bytes - * have indeed been copied and byte swapped. - * - * The data is generated based on the offset (in bytes) into the - * source buffer. For a native buffer the offset is relative to - * the base pointer. For a heap array it is relative to the - * address of the first array element. - * - * This method will return the result of doing an elementSize byte - * read starting at offset (in bytes). - * - * @param offset offset into buffer - * @param elemSize size (in bytes) of the element - * - * @return the verification data, only the least significant - * elemSize*8 bits are set, zero extended - */ - private long getVerificationDataForOffset(long offset, long elemSize) { - byte[] bytes = new byte[(int)elemSize]; - - for (long i = 0; i < elemSize; i++) { - bytes[(int)i] = (byte)(offset + i); - } - - long o = UNSAFE.arrayBaseOffset(byte[].class); - - switch ((int)elemSize) { - case 1: return Byte.toUnsignedLong(UNSAFE.getByte(bytes, o)); - case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(bytes, o)); - case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(bytes, o)); - case 8: return UNSAFE.getLongUnaligned(bytes, o); - default: throw new IllegalArgumentException("Invalid element size: " + elemSize); - } - } - - /** - * Verify byte swapped data - * - * @param ptr the data to verify - * @param srcOffset the srcOffset (in bytes) from which the copy started, - * used as key to regenerate the verification data - * @param dstOffset the offset (in bytes) in the array at which to start - * the verification, relative to the first element in the array - * @param size size (in bytes) of data to to verify - * @param elemSize size (in bytes) of the individual array elements - * - * @throws RuntimeException if an error is found - */ - private void verifySwappedData(GenericPointer ptr, long srcOffset, long dstOffset, long size, long elemSize) { - for (long offset = 0; offset < size; offset += elemSize) { - long expectedUnswapped = getVerificationDataForOffset(srcOffset + offset, elemSize); - long expected = byteSwap(expectedUnswapped, elemSize); - - long actual = getArrayElem(ptr, dstOffset + offset, elemSize); - - if (expected != actual) { - throw new RuntimeException("srcOffset: 0x" + Long.toHexString(srcOffset) + - " dstOffset: 0x" + Long.toHexString(dstOffset) + - " size: 0x" + Long.toHexString(size) + - " offset: 0x" + Long.toHexString(offset) + - " expectedUnswapped: 0x" + Long.toHexString(expectedUnswapped) + - " expected: 0x" + Long.toHexString(expected) + - " != actual: 0x" + Long.toHexString(actual)); - } - } - } - - /** - * Initialize an array with verification friendly data - * - * @param ptr pointer to the data to initialize - * @param size size (in bytes) of the data - * @param elemSize size (in bytes) of the individual elements - */ - private void initVerificationData(GenericPointer ptr, long size, long elemSize) { - for (long offset = 0; offset < size; offset++) { - byte data = (byte)getVerificationDataForOffset(offset, 1); - - if (ptr.isOnHeap()) { - UNSAFE.putByte(ptr.getObject(), ptr.getOffset() + offset, data); - } else { - UNSAFE.putByte(ptr.getOffset() + offset, data); - } - } - } - - /** - * Allocate a primitive array - * - * @param size size (in bytes) of all the array elements (elemSize * length) - * @param elemSize the size of the array elements - * - * @return a newly allocated primitive array - */ - Object allocArray(long size, long elemSize) { - int length = (int)(size / elemSize); - - switch ((int)elemSize) { - case 1: return new byte[length]; - case 2: return new short[length]; - case 4: return new int[length]; - case 8: return new long[length]; - default: - throw new IllegalArgumentException("Invalid element size: " + elemSize); - } - } - - /** - * Get the value of a primitive array entry - * - * @param ptr pointer to the data - * @param offset offset (in bytes) of the array element, relative to the first element in the array - * - * @return the array element, as an unsigned long - */ - private long getArrayElem(GenericPointer ptr, long offset, long elemSize) { - if (ptr.isOnHeap()) { - Object o = ptr.getObject(); - int index = (int)(offset / elemSize); - - if (o instanceof short[]) { - short[] arr = (short[])o; - return Short.toUnsignedLong(arr[index]); - } else if (o instanceof int[]) { - int[] arr = (int[])o; - return Integer.toUnsignedLong(arr[index]); - } else if (o instanceof long[]) { - long[] arr = (long[])o; - return arr[index]; - } else { - throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName()); - } - } else { - long addr = ptr.getOffset() + offset; - - switch ((int)elemSize) { - case 1: return Byte.toUnsignedLong(UNSAFE.getByte(addr)); - case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(null, addr)); - case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(null, addr)); - case 8: return UNSAFE.getLongUnaligned(null, addr); - default: throw new IllegalArgumentException("Invalid element size: " + elemSize); - } - } - } - - private void putValue(long addr, long elemSize, long value) { - switch ((int)elemSize) { - case 1: UNSAFE.putByte(addr, (byte)value); break; - case 2: UNSAFE.putShortUnaligned(null, addr, (short)value); break; - case 4: UNSAFE.putIntUnaligned(null, addr, (int)value); break; - case 8: UNSAFE.putLongUnaligned(null, addr, value); break; - default: throw new IllegalArgumentException("Invalid element size: " + elemSize); - } - } - - /** - * Get the size of the elements for an array - * - * @param o a primitive heap array - * - * @return the size (in bytes) of the individual array elements - */ - private long getArrayElemSize(Object o) { - if (o instanceof short[]) { - return 2; - } else if (o instanceof int[]) { - return 4; - } else if (o instanceof long[]) { - return 8; - } else { - throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName()); - } - } - - /** - * Byte swap a value - * - * @param value the value to swap, only the bytes*8 least significant bits are used - * @param size size (in bytes) of the value - * - * @return the byte swapped value in the bytes*8 least significant bits - */ - private long byteSwap(long value, long size) { - switch ((int)size) { - case 2: return Short.toUnsignedLong(Short.reverseBytes((short)value)); - case 4: return Integer.toUnsignedLong(Integer.reverseBytes((int)value)); - case 8: return Long.reverseBytes(value); - default: throw new IllegalArgumentException("Invalid element size: " + size); - } - } - - /** - * Verify data which has *not* been byte swapped - * - * @param ptr the data to verify - * @param startOffset the offset (in bytes) at which to start the verification - * @param size size (in bytes) of the data to verify - * - * @throws RuntimeException if an error is found - */ - private void verifyUnswappedData(GenericPointer ptr, long startOffset, long srcOffset, long size) { - for (long i = 0; i < size; i++) { - byte expected = (byte)getVerificationDataForOffset(srcOffset + i, 1); - - byte actual; - if (ptr.isOnHeap()) { - actual = UNSAFE.getByte(ptr.getObject(), ptr.getOffset() + startOffset + i); - } else { - actual = UNSAFE.getByte(ptr.getOffset() + startOffset + i); - } - - if (expected != actual) { - throw new RuntimeException("startOffset: 0x" + Long.toHexString(startOffset) + - " srcOffset: 0x" + Long.toHexString(srcOffset) + - " size: 0x" + Long.toHexString(size) + - " i: 0x" + Long.toHexString(i) + - " expected: 0x" + Long.toHexString(expected) + - " != actual: 0x" + Long.toHexString(actual)); - } - } - } - - - /** - * Copy and byte swap data from the source to the destination - * - * This method will pre-populate the whole source and destination - * buffers with verification friendly data. It will then use - * copypMemory to fill part of the destination buffer with - * data from the source. Some space (padding) will be - * left before and after the data in the destination buffer, which - * should not be touched/overwritten by the copy call. - * - * Note: Both source and destination buffers will be overwritten! - * - * @param src source buffer to copy from - * @param srcOffset the offset (in bytes) in the source buffer, relative to - * the first array element, at which to start reading data - * @param dst destination buffer to copy to - * @param dstOffset the offset (in bytes) in the destination - * buffer, relative to the first array element, at which to - * start writing data - * @param bufSize the size (in bytes) of the src and dst arrays - * @param copyBytes the size (in bytes) of the copy to perform, - * must be a multiple of elemSize - * - * @throws RuntimeException if an error is found - */ - private void testCopy(GenericPointer src, long srcOffset, - GenericPointer dst, long dstOffset, - long bufSize, long copyBytes) { - if (srcOffset + copyBytes > bufSize) { - throw new IllegalArgumentException( - "srcOffset (" + srcOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")"); - } - if (dstOffset + copyBytes > bufSize) { - throw new IllegalArgumentException( - "dstOffset (" + dstOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")"); - } - - // Initialize the whole source buffer with a verification friendly pattern (no 0x00 bytes) - initVerificationData(src, bufSize, 1); - if (!src.equals(dst)) { - initVerificationData(dst, bufSize, 1); - } - - if (DEBUG) { - System.out.println("===before==="); - for (int offset = 0; offset < bufSize; offset++) { - long srcValue = getArrayElem(src, offset, 1); - long dstValue = getArrayElem(dst, offset, 1); - - System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) + - " src=0x" + Long.toHexString(srcValue) + - " dst=0x" + Long.toHexString(dstValue)); - } - } - - // Copy & swap data into the middle of the destination buffer - UNSAFE.copyMemory(src.getObject(), - src.getOffset() + srcOffset, - dst.getObject(), - dst.getOffset() + dstOffset, - copyBytes); - - if (DEBUG) { - System.out.println("===after==="); - for (int offset = 0; offset < bufSize; offset++) { - long srcValue = getArrayElem(src, offset, 1); - long dstValue = getArrayElem(dst, offset, 1); - - System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) + - " src=0x" + Long.toHexString(srcValue) + - " dst=0x" + Long.toHexString(dstValue)); - } - } - - // Verify the the front padding is unchanged - verifyUnswappedData(dst, 0, 0, dstOffset); - - // Verify copied data - verifyUnswappedData(dst, dstOffset, srcOffset, copyBytes); - - // Verify that the back back padding is unchanged - long frontAndDataBytes = dstOffset + copyBytes; - long trailingBytes = bufSize - frontAndDataBytes; - verifyUnswappedData(dst, frontAndDataBytes, frontAndDataBytes, trailingBytes); - } - - /** - * Test various configurations copying from one buffer to the other - * - * @param src the source buffer to copy from - * @param dst the destination buffer to copy to - * @param size size (in bytes) of the buffers - * @param elemSize size (in bytes) of the individual elements - * - * @throws RuntimeException if an error is found - */ - public void testBufferPair(GenericPointer src, GenericPointer dst, long size, long elemSize) { - // offset in source from which to start reading data - for (long srcOffset = 0; srcOffset < size; srcOffset += (src.isOnHeap() ? elemSize : 1)) { - - // offset in destination at which to start writing data - for (int dstOffset = 0; dstOffset < size; dstOffset += (dst.isOnHeap() ? elemSize : 1)) { - - // number of bytes to copy - long maxCopyBytes = Math.min(size - srcOffset, size - dstOffset); - for (long copyBytes = 0; copyBytes < maxCopyBytes; copyBytes += elemSize) { - try { - testCopy(src, srcOffset, dst, dstOffset, size, copyBytes); - } catch (RuntimeException e) { - // Wrap the exception in another exception to catch the relevant configuration data - throw new RuntimeException("testBufferPair: " + - "src=" + src + - " dst=" + dst + - " elemSize=0x" + Long.toHexString(elemSize) + - " copyBytes=0x" + Long.toHexString(copyBytes) + - " srcOffset=0x" + Long.toHexString(srcOffset) + - " dstOffset=0x" + Long.toHexString(dstOffset), - e); - } - } - } - } - } - - /** - * Test copying between various permutations of buffers - * - * @param buffers buffers to permute (src x dst) - * @param size size (in bytes) of buffers - * @param elemSize size (in bytes) of individual elements - * - * @throws RuntimeException if an error is found - */ - public void testPermuteBuffers(GenericPointer[] buffers, long size, long elemSize) { - for (int srcIndex = 0; srcIndex < buffers.length; srcIndex++) { - for (int dstIndex = 0; dstIndex < buffers.length; dstIndex++) { - testBufferPair(buffers[srcIndex], buffers[dstIndex], size, elemSize); - } - } - } - - /** - * Test copying of a specific element size - * - * @param size size (in bytes) of buffers to allocate - * @param elemSize size (in bytes) of individual elements - * - * @throws RuntimeException if an error is found - */ - private void testElemSize(long size, long elemSize) { - long buf1Raw = 0; - long buf2Raw = 0; - - try { - buf1Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); - long buf1 = alignUp(buf1Raw, BASE_ALIGNMENT); - - buf2Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); - long buf2 = alignUp(buf2Raw, BASE_ALIGNMENT); - - GenericPointer[] buffers = { - new GenericPointer(buf1), - new GenericPointer(buf2), - new GenericPointer(allocArray(size, elemSize)), - new GenericPointer(allocArray(size, elemSize)) - }; - - testPermuteBuffers(buffers, size, elemSize); - } finally { - if (buf1Raw != 0) { - UNSAFE.freeMemory(buf1Raw); - } - if (buf2Raw != 0) { - UNSAFE.freeMemory(buf2Raw); - } - } - } - - /** - * Verify that small copies work - */ - private void testSmallCopy() { - int smallBufSize = SMALL_COPY_SIZE; - - testElemSize(smallBufSize, 1); - } - - - /** - * Verify that large copies work - */ - private void testLargeCopy() { - long size = 2 * GB + 8; - long bufRaw = 0; - - // Check that a large native copy succeeds - try { - try { - bufRaw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); - } catch (OutOfMemoryError e) { - // Accept failure, skip test - return; - } - - long buf = alignUp(bufRaw, BASE_ALIGNMENT); - - UNSAFE.copyMemory(null, buf, null, buf, size); - } catch (Exception e) { - throw new RuntimeException("copyMemory of large buffer failed"); - } finally { - if (bufRaw != 0) { - UNSAFE.freeMemory(bufRaw); - } - } - } - /** * Run positive tests * * @throws RuntimeException if an error is found */ private void testPositive() { - testSmallCopy(); - testLargeCopy(); + testSmallCopy(false); + testLargeCopy(false); } /** @@ -527,7 +53,7 @@ public class CopyMemory { try { bufRaw = UNSAFE.allocateMemory(1024); - long buf = alignUp(bufRaw, BASE_ALIGNMENT); + long buf = CopyCommon.alignUp(bufRaw, CopyCommon.BASE_ALIGNMENT); short[] arr = new short[16]; // Check illegal sizes @@ -609,59 +135,4 @@ public class CopyMemory { CopyMemory cs = new CopyMemory(); cs.test(); } - - /** - * Helper class to represent a "pointer" - either a heap array or - * a pointer to a native buffer. - * - * In the case of a native pointer, the Object is null and the offset is - * the absolute address of the native buffer. - * - * In the case of a heap object, the Object is a primitive array, and - * the offset will be set to the base offset to the first element, meaning - * the object and the offset together form a double-register pointer. - */ - static class GenericPointer { - private final Object o; - private final long offset; - - private GenericPointer(Object o, long offset) { - this.o = o; - this.offset = offset; - } - - public String toString() { - return "GenericPointer(o={" + o + "}, offset=0x" + Long.toHexString(offset) + ")"; - } - - public boolean equals(Object other) { - if (!(other instanceof GenericPointer)) { - return false; - } - - GenericPointer otherp = (GenericPointer)other; - - return o == otherp.o && offset == otherp.offset; - } - - GenericPointer(Object o) { - this(o, UNSAFE.arrayBaseOffset(o.getClass())); - } - - GenericPointer(long offset) { - this(null, offset); - } - - public boolean isOnHeap() { - return o != null; - } - - public Object getObject() { - return o; - } - - public long getOffset() { - return offset; - } - } } diff --git a/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java b/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java index bb94c200765..4cbd8b709d2 100644 --- a/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java +++ b/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java @@ -29,507 +29,18 @@ import java.lang.reflect.Field; * @summary Test Unsafe.copySwapMemory * @modules java.base/jdk.internal.misc */ -public class CopySwap { - private static final boolean DEBUG = Boolean.getBoolean("CopySwap.DEBUG"); - - public static final long KB = 1024; - public static final long MB = KB * 1024; - public static final long GB = MB * 1024; - - private static final Unsafe UNSAFE; - private static final int SMALL_COPY_SIZE = 32; - private static final int BASE_ALIGNMENT = 16; - - static { - try { - Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); - f.setAccessible(true); - UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); - } catch (Exception e) { - throw new RuntimeException("Unable to get Unsafe instance.", e); - } - } - - private static long alignDown(long value, long alignment) { - return value & ~(alignment - 1); - } - - private static long alignUp(long value, long alignment) { - return (value + alignment - 1) & ~(alignment - 1); - } - - private static boolean isAligned(long value, long alignment) { - return value == alignDown(value, alignment); - } - +public class CopySwap extends CopyCommon { private CopySwap() { } - /** - * Generate verification data for a given offset - * - * The verification data is used to verify that the correct bytes - * have indeed been copied and byte swapped. - * - * The data is generated based on the offset (in bytes) into the - * source buffer. For a native buffer the offset is relative to - * the base pointer. For a heap array it is relative to the - * address of the first array element. - * - * This method will return the result of doing an elementSize byte - * read starting at offset (in bytes). - * - * @param offset offset into buffer - * @param elemSize size (in bytes) of the element - * - * @return the verification data, only the least significant - * elemSize*8 bits are set, zero extended - */ - private long getVerificationDataForOffset(long offset, long elemSize) { - byte[] bytes = new byte[(int)elemSize]; - - for (long i = 0; i < elemSize; i++) { - bytes[(int)i] = (byte)(offset + i); - } - - long o = UNSAFE.arrayBaseOffset(byte[].class); - - switch ((int)elemSize) { - case 1: return Byte.toUnsignedLong(UNSAFE.getByte(bytes, o)); - case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(bytes, o)); - case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(bytes, o)); - case 8: return UNSAFE.getLongUnaligned(bytes, o); - default: throw new IllegalArgumentException("Invalid element size: " + elemSize); - } - } - - /** - * Verify byte swapped data - * - * @param ptr the data to verify - * @param srcOffset the srcOffset (in bytes) from which the copy started, - * used as key to regenerate the verification data - * @param dstOffset the offset (in bytes) in the array at which to start - * the verification, relative to the first element in the array - * @param size size (in bytes) of data to to verify - * @param elemSize size (in bytes) of the individual array elements - * - * @throws RuntimeException if an error is found - */ - private void verifySwappedData(GenericPointer ptr, long srcOffset, long dstOffset, long size, long elemSize) { - for (long offset = 0; offset < size; offset += elemSize) { - long expectedUnswapped = getVerificationDataForOffset(srcOffset + offset, elemSize); - long expected = byteSwap(expectedUnswapped, elemSize); - - long actual = getArrayElem(ptr, dstOffset + offset, elemSize); - - if (expected != actual) { - throw new RuntimeException("srcOffset: 0x" + Long.toHexString(srcOffset) + - " dstOffset: 0x" + Long.toHexString(dstOffset) + - " size: 0x" + Long.toHexString(size) + - " offset: 0x" + Long.toHexString(offset) + - " expectedUnswapped: 0x" + Long.toHexString(expectedUnswapped) + - " expected: 0x" + Long.toHexString(expected) + - " != actual: 0x" + Long.toHexString(actual)); - } - } - } - - /** - * Initialize an array with verification friendly data - * - * @param ptr pointer to the data to initialize - * @param size size (in bytes) of the data - * @param elemSize size (in bytes) of the individual elements - */ - private void initVerificationData(GenericPointer ptr, long size, long elemSize) { - for (long offset = 0; offset < size; offset++) { - byte data = (byte)getVerificationDataForOffset(offset, 1); - - if (ptr.isOnHeap()) { - UNSAFE.putByte(ptr.getObject(), ptr.getOffset() + offset, data); - } else { - UNSAFE.putByte(ptr.getOffset() + offset, data); - } - } - } - - /** - * Allocate a primitive array - * - * @param size size (in bytes) of all the array elements (elemSize * length) - * @param elemSize the size of the array elements - * - * @return a newly allocated primitive array - */ - Object allocArray(long size, long elemSize) { - int length = (int)(size / elemSize); - - switch ((int)elemSize) { - case 2: return new short[length]; - case 4: return new int[length]; - case 8: return new long[length]; - default: - throw new IllegalArgumentException("Invalid element size: " + elemSize); - } - } - - /** - * Get the value of a primitive array entry - * - * @param ptr pointer to the data - * @param offset offset (in bytes) of the array element, relative to the first element in the array - * - * @return the array element, as an unsigned long - */ - private long getArrayElem(GenericPointer ptr, long offset, long elemSize) { - if (ptr.isOnHeap()) { - Object o = ptr.getObject(); - int index = (int)(offset / elemSize); - - if (o instanceof short[]) { - short[] arr = (short[])o; - return Short.toUnsignedLong(arr[index]); - } else if (o instanceof int[]) { - int[] arr = (int[])o; - return Integer.toUnsignedLong(arr[index]); - } else if (o instanceof long[]) { - long[] arr = (long[])o; - return arr[index]; - } else { - throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName()); - } - } else { - long addr = ptr.getOffset() + offset; - - switch ((int)elemSize) { - case 1: return Byte.toUnsignedLong(UNSAFE.getByte(addr)); - case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(null, addr)); - case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(null, addr)); - case 8: return UNSAFE.getLongUnaligned(null, addr); - default: throw new IllegalArgumentException("Invalid element size: " + elemSize); - } - } - } - - private void putValue(long addr, long elemSize, long value) { - switch ((int)elemSize) { - case 1: UNSAFE.putByte(addr, (byte)value); break; - case 2: UNSAFE.putShortUnaligned(null, addr, (short)value); break; - case 4: UNSAFE.putIntUnaligned(null, addr, (int)value); break; - case 8: UNSAFE.putLongUnaligned(null, addr, value); break; - default: throw new IllegalArgumentException("Invalid element size: " + elemSize); - } - } - - /** - * Get the size of the elements for an array - * - * @param o a primitive heap array - * - * @return the size (in bytes) of the individual array elements - */ - private long getArrayElemSize(Object o) { - if (o instanceof short[]) { - return 2; - } else if (o instanceof int[]) { - return 4; - } else if (o instanceof long[]) { - return 8; - } else { - throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName()); - } - } - - /** - * Byte swap a value - * - * @param value the value to swap, only the bytes*8 least significant bits are used - * @param size size (in bytes) of the value - * - * @return the byte swapped value in the bytes*8 least significant bits - */ - private long byteSwap(long value, long size) { - switch ((int)size) { - case 2: return Short.toUnsignedLong(Short.reverseBytes((short)value)); - case 4: return Integer.toUnsignedLong(Integer.reverseBytes((int)value)); - case 8: return Long.reverseBytes(value); - default: throw new IllegalArgumentException("Invalid element size: " + size); - } - } - - /** - * Verify data in a heap array which has *not* been byte swapped - * - * @param ptr the data to verify - * @param startOffset the offset (in bytes) at which to start the verification - * @param size size (in bytes) of the data to verify - * - * @throws RuntimeException if an error is found - */ - private void verifyUnswappedData(GenericPointer ptr, long startOffset, long size) { - for (long elemOffset = startOffset; elemOffset < startOffset + size; elemOffset++) { - byte expected = (byte)getVerificationDataForOffset(elemOffset, 1); - - byte actual; - if (ptr.isOnHeap()) { - actual = UNSAFE.getByte(ptr.getObject(), ptr.getOffset() + elemOffset); - } else { - actual = UNSAFE.getByte(ptr.getOffset() + elemOffset); - } - - if (expected != actual) { - throw new RuntimeException("startOffset: 0x" + Long.toHexString(startOffset) + - " size: 0x" + Long.toHexString(size) + - " elemOffset: 0x" + Long.toHexString(elemOffset) + - " expected: 0x" + Long.toHexString(expected) + - " != actual: 0x" + Long.toHexString(actual)); - } - } - } - - - /** - * Copy and byte swap data from the source to the destination - * - * This method will pre-populate the whole source and destination - * buffers with verification friendly data. It will then use - * copySwapMemory to fill part of the destination buffer with - * swapped data from the source. Some space (padding) will be - * left before and after the data in the destination buffer, which - * should not be touched/overwritten by the copy call. - * - * Note: Both source and destination buffers will be overwritten! - * - * @param src source buffer to copy from - * @param srcOffset the offset (in bytes) in the source buffer, relative to - * the first array element, at which to start reading data - * @param dst destination buffer to copy to - * @param dstOffset the offset (in bytes) in the destination - * buffer, relative to the first array element, at which to - * start writing data - * @param bufSize the size (in bytes) of the src and dst arrays - * @param copyBytes the size (in bytes) of the copy to perform, - * must be a multiple of elemSize - * @param elemSize the size (in bytes) of the elements to byte swap - * - * @throws RuntimeException if an error is found - */ - private void testCopySwap(GenericPointer src, long srcOffset, - GenericPointer dst, long dstOffset, - long bufSize, long copyBytes, long elemSize) { - if (!isAligned(copyBytes, elemSize)) { - throw new IllegalArgumentException( - "copyBytes (" + copyBytes + ") must be a multiple of elemSize (" + elemSize + ")"); - } - if (src.isOnHeap() && !isAligned(srcOffset, elemSize)) { - throw new IllegalArgumentException( - "srcOffset (" + srcOffset + ") must be a multiple of elemSize (" + elemSize + ")"); - } - if (dst.isOnHeap() && !isAligned(dstOffset, elemSize)) { - throw new IllegalArgumentException( - "dstOffset (" + dstOffset + ") must be a multiple of elemSize (" + elemSize + ")"); - } - if (srcOffset + copyBytes > bufSize) { - throw new IllegalArgumentException( - "srcOffset (" + srcOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")"); - } - if (dstOffset + copyBytes > bufSize) { - throw new IllegalArgumentException( - "dstOffset (" + dstOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")"); - } - - // Initialize the whole source buffer with a verification friendly pattern (no 0x00 bytes) - initVerificationData(src, bufSize, elemSize); - if (!src.equals(dst)) { - initVerificationData(dst, bufSize, elemSize); - } - - if (DEBUG) { - System.out.println("===before==="); - for (int offset = 0; offset < bufSize; offset += elemSize) { - long srcValue = getArrayElem(src, offset, elemSize); - long dstValue = getArrayElem(dst, offset, elemSize); - - System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) + - " src=0x" + Long.toHexString(srcValue) + - " dst=0x" + Long.toHexString(dstValue)); - } - } - - // Copy & swap data into the middle of the destination buffer - UNSAFE.copySwapMemory(src.getObject(), - src.getOffset() + srcOffset, - dst.getObject(), - dst.getOffset() + dstOffset, - copyBytes, - elemSize); - - if (DEBUG) { - System.out.println("===after==="); - for (int offset = 0; offset < bufSize; offset += elemSize) { - long srcValue = getArrayElem(src, offset, elemSize); - long dstValue = getArrayElem(dst, offset, elemSize); - - System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) + - " src=0x" + Long.toHexString(srcValue) + - " dst=0x" + Long.toHexString(dstValue)); - } - } - - // Verify the the front padding is unchanged - verifyUnswappedData(dst, 0, dstOffset); - - // Verify swapped data - verifySwappedData(dst, srcOffset, dstOffset, copyBytes, elemSize); - - // Verify that the back back padding is unchanged - long frontAndDataBytes = dstOffset + copyBytes; - long trailingBytes = bufSize - frontAndDataBytes; - verifyUnswappedData(dst, frontAndDataBytes, trailingBytes); - } - - /** - * Test various configurations copy-swapping from one buffer to the other - * - * @param src the source buffer to copy from - * @param dst the destination buffer to copy to - * @param size size (in bytes) of the buffers - * @param elemSize size (in bytes) of the individual elements - * - * @throws RuntimeException if an error is found - */ - public void testBufferPair(GenericPointer src, GenericPointer dst, long size, long elemSize) { - // offset in source from which to start reading data - for (long srcOffset = 0; srcOffset < size; srcOffset += (src.isOnHeap() ? elemSize : 1)) { - - // offset in destination at which to start writing data - for (int dstOffset = 0; dstOffset < size; dstOffset += (dst.isOnHeap() ? elemSize : 1)) { - - // number of bytes to copy - long maxCopyBytes = Math.min(size - srcOffset, size - dstOffset); - for (long copyBytes = 0; copyBytes < maxCopyBytes; copyBytes += elemSize) { - try { - testCopySwap(src, srcOffset, dst, dstOffset, size, copyBytes, elemSize); - } catch (RuntimeException e) { - // Wrap the exception in another exception to catch the relevant configuration data - throw new RuntimeException("testBufferPair: " + - "src=" + src + - " dst=" + dst + - " elemSize=0x" + Long.toHexString(elemSize) + - " copyBytes=0x" + Long.toHexString(copyBytes) + - " srcOffset=0x" + Long.toHexString(srcOffset) + - " dstOffset=0x" + Long.toHexString(dstOffset), - e); - } - } - } - } - } - - /** - * Test copying between various permutations of buffers - * - * @param buffers buffers to permute (src x dst) - * @param size size (in bytes) of buffers - * @param elemSize size (in bytes) of individual elements - * - * @throws RuntimeException if an error is found - */ - public void testPermuteBuffers(GenericPointer[] buffers, long size, long elemSize) { - for (int srcIndex = 0; srcIndex < buffers.length; srcIndex++) { - for (int dstIndex = 0; dstIndex < buffers.length; dstIndex++) { - testBufferPair(buffers[srcIndex], buffers[dstIndex], size, elemSize); - } - } - } - - /** - * Test copying of a specific element size - * - * @param size size (in bytes) of buffers to allocate - * @param elemSize size (in bytes) of individual elements - * - * @throws RuntimeException if an error is found - */ - private void testElemSize(long size, long elemSize) { - long buf1Raw = 0; - long buf2Raw = 0; - - try { - buf1Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); - long buf1 = alignUp(buf1Raw, BASE_ALIGNMENT); - - buf2Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); - long buf2 = alignUp(buf2Raw, BASE_ALIGNMENT); - - GenericPointer[] buffers = { - new GenericPointer(buf1), - new GenericPointer(buf2), - new GenericPointer(allocArray(size, elemSize)), - new GenericPointer(allocArray(size, elemSize)) - }; - - testPermuteBuffers(buffers, size, elemSize); - } finally { - if (buf1Raw != 0) { - UNSAFE.freeMemory(buf1Raw); - } - if (buf2Raw != 0) { - UNSAFE.freeMemory(buf2Raw); - } - } - } - - /** - * Verify that small copy swaps work - */ - private void testSmallCopy() { - int smallBufSize = SMALL_COPY_SIZE; - - // Test various element types and heap/native combinations - for (long elemSize = 2; elemSize <= 8; elemSize <<= 1) { - testElemSize(smallBufSize, elemSize); - } - } - - - /** - * Verify that large copy swaps work - */ - private void testLargeCopy() { - long size = 2 * GB + 8; - long bufRaw = 0; - - // Check that a large native copy succeeds - try { - try { - bufRaw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); - } catch (OutOfMemoryError e) { - // Accept failure, skip test - return; - } - - long buf = alignUp(bufRaw, BASE_ALIGNMENT); - - UNSAFE.copySwapMemory(null, buf, null, buf, size, 8); - } catch (Exception e) { - throw new RuntimeException("copySwapMemory of large buffer failed"); - } finally { - if (bufRaw != 0) { - UNSAFE.freeMemory(bufRaw); - } - } - } - /** * Run positive tests * * @throws RuntimeException if an error is found */ private void testPositive() { - testSmallCopy(); - testLargeCopy(); + testSmallCopy(true); + testLargeCopy(true); } /** @@ -542,7 +53,7 @@ public class CopySwap { try { bufRaw = UNSAFE.allocateMemory(1024); - long buf = alignUp(bufRaw, BASE_ALIGNMENT); + long buf = CopyCommon.alignUp(bufRaw, CopyCommon.BASE_ALIGNMENT); short[] arr = new short[16]; // Check various illegal element sizes @@ -637,59 +148,4 @@ public class CopySwap { CopySwap cs = new CopySwap(); cs.test(); } - - /** - * Helper class to represent a "pointer" - either a heap array or - * a pointer to a native buffer. - * - * In the case of a native pointer, the Object is null and the offset is - * the absolute address of the native buffer. - * - * In the case of a heap object, the Object is a primitive array, and - * the offset will be set to the base offset to the first element, meaning - * the object and the offset together form a double-register pointer. - */ - static class GenericPointer { - private final Object o; - private final long offset; - - private GenericPointer(Object o, long offset) { - this.o = o; - this.offset = offset; - } - - public String toString() { - return "GenericPointer(o={" + o + "}, offset=0x" + Long.toHexString(offset) + ")"; - } - - public boolean equals(Object other) { - if (!(other instanceof GenericPointer)) { - return false; - } - - GenericPointer otherp = (GenericPointer)other; - - return o == otherp.o && offset == otherp.offset; - } - - GenericPointer(Object o) { - this(o, UNSAFE.arrayBaseOffset(o.getClass())); - } - - GenericPointer(long offset) { - this(null, offset); - } - - public boolean isOnHeap() { - return o != null; - } - - public Object getObject() { - return o; - } - - public long getOffset() { - return offset; - } - } } From 9a55e05cfb4cf1ea7812dc0ab549e11ea65883e2 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 17 Mar 2016 08:47:46 -0700 Subject: [PATCH 17/36] 8152043: (fs) Remove dynamic loopup of Win32 API functions in WindowsNativeDispatcher needed to support Windows XP and Server 2003 Remove dynamic lookup of Win32 functions which was required to support Windows XP and Windows Server 2003. Reviewed-by: alanb --- .../libnio/fs/WindowsNativeDispatcher.c | 70 ++----------------- 1 file changed, 6 insertions(+), 64 deletions(-) diff --git a/jdk/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c b/jdk/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c index 8075d046763..eeb6456ae6a 100644 --- a/jdk/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c +++ b/jdk/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, 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 @@ -23,10 +23,6 @@ * questions. */ -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 -#endif - #include #include #include @@ -77,21 +73,6 @@ static jfieldID backupResult_bytesTransferred; static jfieldID backupResult_context; -/** - * Win32 APIs not available in Windows XP - */ -typedef HANDLE (WINAPI* FindFirstStream_Proc)(LPCWSTR, STREAM_INFO_LEVELS, LPVOID, DWORD); -typedef BOOL (WINAPI* FindNextStream_Proc)(HANDLE, LPVOID); - -typedef BOOLEAN (WINAPI* CreateSymbolicLinkProc) (LPCWSTR, LPCWSTR, DWORD); -typedef BOOL (WINAPI* GetFinalPathNameByHandleProc) (HANDLE, LPWSTR, DWORD, DWORD); - -static FindFirstStream_Proc FindFirstStream_func; -static FindNextStream_Proc FindNextStream_func; - -static CreateSymbolicLinkProc CreateSymbolicLink_func; -static GetFinalPathNameByHandleProc GetFinalPathNameByHandle_func; - static void throwWindowsException(JNIEnv* env, DWORD lastError) { jobject x = JNU_NewObjectByName(env, "sun/nio/fs/WindowsException", "(I)V", lastError); @@ -108,7 +89,6 @@ JNIEXPORT void JNICALL Java_sun_nio_fs_WindowsNativeDispatcher_initIDs(JNIEnv* env, jclass this) { jclass clazz; - HMODULE h; clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$FirstFile"); CHECK_NULL(clazz); @@ -175,24 +155,6 @@ Java_sun_nio_fs_WindowsNativeDispatcher_initIDs(JNIEnv* env, jclass this) CHECK_NULL(backupResult_bytesTransferred); backupResult_context = (*env)->GetFieldID(env, clazz, "context", "J"); CHECK_NULL(backupResult_context); - - // get handle to kernel32 - if (GetModuleHandleExW((GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | - GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT), - (LPCWSTR)&CreateFileW, &h) != 0) - { - // requires Windows Server 2003 or newer - FindFirstStream_func = - (FindFirstStream_Proc)GetProcAddress(h, "FindFirstStreamW"); - FindNextStream_func = - (FindNextStream_Proc)GetProcAddress(h, "FindNextStreamW"); - - // requires Windows Vista or newer - CreateSymbolicLink_func = - (CreateSymbolicLinkProc)GetProcAddress(h, "CreateSymbolicLinkW"); - GetFinalPathNameByHandle_func = - (GetFinalPathNameByHandleProc)GetProcAddress(h, "GetFinalPathNameByHandleW"); - } } JNIEXPORT jlong JNICALL @@ -404,12 +366,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_FindFirstStream0(JNIEnv* env, jclass thi LPCWSTR lpFileName = jlong_to_ptr(address); HANDLE handle; - if (FindFirstStream_func == NULL) { - JNU_ThrowInternalError(env, "Should not get here"); - return; - } - - handle = (*FindFirstStream_func)(lpFileName, FindStreamInfoStandard, &data, 0); + handle = FindFirstStreamW(lpFileName, FindStreamInfoStandard, &data, 0); if (handle != INVALID_HANDLE_VALUE) { jstring name = (*env)->NewString(env, data.cStreamName, (jsize)wcslen(data.cStreamName)); if (name == NULL) @@ -433,12 +390,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_FindNextStream(JNIEnv* env, jclass this, WIN32_FIND_STREAM_DATA data; HANDLE h = (HANDLE)jlong_to_ptr(handle); - if (FindNextStream_func == NULL) { - JNU_ThrowInternalError(env, "Should not get here"); - return NULL; - } - - if ((*FindNextStream_func)(h, &data) != 0) { + if (FindNextStreamW(h, &data) != 0) { return (*env)->NewString(env, data.cStreamName, (jsize)wcslen(data.cStreamName)); } else { if (GetLastError() != ERROR_HANDLE_EOF) @@ -1087,13 +1039,8 @@ Java_sun_nio_fs_WindowsNativeDispatcher_CreateSymbolicLink0(JNIEnv* env, LPCWSTR link = jlong_to_ptr(linkAddress); LPCWSTR target = jlong_to_ptr(targetAddress); - if (CreateSymbolicLink_func == NULL) { - JNU_ThrowInternalError(env, "Should not get here"); - return; - } - /* On Windows 64-bit this appears to succeed even when there is insufficient privileges */ - if ((*CreateSymbolicLink_func)(link, target, (DWORD)flags) == 0) + if (CreateSymbolicLinkW(link, target, (DWORD)flags) == 0) throwWindowsException(env, GetLastError()); } @@ -1155,12 +1102,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_GetFinalPathNameByHandle(JNIEnv* env, HANDLE h = (HANDLE)jlong_to_ptr(handle); DWORD len; - if (GetFinalPathNameByHandle_func == NULL) { - JNU_ThrowInternalError(env, "Should not get here"); - return NULL; - } - - len = (*GetFinalPathNameByHandle_func)(h, path, MAX_PATH, 0); + len = GetFinalPathNameByHandleW(h, path, MAX_PATH, 0); if (len > 0) { if (len < MAX_PATH) { rv = (*env)->NewString(env, (const jchar *)path, (jsize)len); @@ -1168,7 +1110,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_GetFinalPathNameByHandle(JNIEnv* env, len += 1; /* return length does not include terminator */ lpBuf = (WCHAR*)malloc(len * sizeof(WCHAR)); if (lpBuf != NULL) { - len = (*GetFinalPathNameByHandle_func)(h, lpBuf, len, 0); + len = GetFinalPathNameByHandleW(h, lpBuf, len, 0); if (len > 0) { rv = (*env)->NewString(env, (const jchar *)lpBuf, (jsize)len); } else { From 872d60701a342adebf363579edfdbace682e12f6 Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Fri, 18 Mar 2016 13:14:53 +0000 Subject: [PATCH 18/36] 8149169: SSLSocketInputRecord.decodeInputRecord buffer overflow Reviewed-by: xuelei --- .../sun/security/ssl/SSLSocketImpl.java | 27 +-- .../LargePacketAfterHandshakeTest.java | 183 ++++++++++++++++++ 2 files changed, 197 insertions(+), 13 deletions(-) create mode 100644 jdk/test/sun/security/ssl/SSLSocketImpl/LargePacketAfterHandshakeTest.java diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java index 86b772c09da..412c3ec8544 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, 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 @@ -365,17 +365,6 @@ public final class SSLSocketImpl extends BaseSSLSocketImpl { /* Class and subclass dynamic debugging support */ private static final Debug debug = Debug.getInstance("ssl"); - /* - * Is it the first application record to write? - */ - private boolean isFirstAppOutputRecord = true; - - /* - * If AppOutputStream needs to delay writes of small packets, we - * will use this to store the data until we actually do the write. - */ - private ByteArrayOutputStream heldRecordBuffer = null; - /* * Whether local cipher suites preference in server side should be * honored during handshaking? @@ -998,9 +987,21 @@ public final class SSLSocketImpl extends BaseSSLSocketImpl { Plaintext plainText = null; while (((state = getConnectionState()) != cs_CLOSED) && (state != cs_ERROR) && (state != cs_APP_CLOSED)) { - // clean the buffer + + /* + * clean the buffer and check if it is too small, e.g. because + * the AppInputStream did not have the chance to see the + * current packet length but rather something like that of the + * handshake before. In that case we return 0 at this point to + * give the caller the chance to adjust the buffer. + */ if (buffer != null) { buffer.clear(); + + if (buffer.remaining() < + inputRecord.bytesInCompletePacket(sockInput)) { + return 0; + } } /* diff --git a/jdk/test/sun/security/ssl/SSLSocketImpl/LargePacketAfterHandshakeTest.java b/jdk/test/sun/security/ssl/SSLSocketImpl/LargePacketAfterHandshakeTest.java new file mode 100644 index 00000000000..fd7ae8fa3c9 --- /dev/null +++ b/jdk/test/sun/security/ssl/SSLSocketImpl/LargePacketAfterHandshakeTest.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2016, 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. + * + * 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. + */ + +// +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. +// + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; + +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; + +/* + * @test + * @bug 8149169 + * @summary Test for BufferOverflowException during read from SSLSocket when + * large packet is coming from server after server initiated handshake + * @run main/othervm LargePacketAfterHandshakeTest + */ +public class LargePacketAfterHandshakeTest { + static String pathToStores = "../../../../javax/net/ssl/etc"; + static String keyStoreFile = "keystore"; + static String trustStoreFile = "truststore"; + static String passwd = "passphrase"; + + volatile static int serverport = -1; + volatile static boolean serverReady = false; + volatile static boolean clientDone = false; + volatile static Exception serverException = null; + + public static void runServer() { + try { + System.out.println("Server: Started server thread."); + SSLServerSocketFactory ssf = + (SSLServerSocketFactory)SSLServerSocketFactory.getDefault(); + SSLServerSocket s = (SSLServerSocket)ssf.createServerSocket(0); + serverport = s.getLocalPort(); + System.out.println("Server: Started, listening on port " + + serverport + "."); + serverReady = true; + SSLSocket c = (SSLSocket)s.accept(); + s.close(); + System.out.println( + "Server: Accepted client connection and closed server socket."); + BufferedReader r = new BufferedReader( + new InputStreamReader(c.getInputStream())); + BufferedWriter w = new BufferedWriter( + new OutputStreamWriter(c.getOutputStream())); + String echostring = r.readLine(); + System.out.println("Server: Read " + echostring.length() + + " chars of input data."); + c.startHandshake(); + System.out.println("Server: Kicked new handshake."); + w.write(echostring); + w.newLine(); + w.flush(); + System.out.println("Server: Echoed " + echostring.length() + + " chars of input data."); + while (!clientDone) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + System.out.println("Server: Caught InterruptedException."); + } + } + r.close(); + w.close(); + c.close(); + System.out.println( + "Server: Closed streams and client socket, exiting."); + } catch (Exception e) { + System.out.println("Server: Caught Exception."); + e.printStackTrace(); + serverReady = true; + serverException = e; + } + } + + public static void runClient() throws IOException { + try { + SSLSocketFactory f = + (SSLSocketFactory)SSLSocketFactory.getDefault(); + System.out.println("Client: Initialized."); + while (!serverReady) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + System.out.println("Client: Caught InterruptedException."); + } + } + SSLSocket c = (SSLSocket)f.createSocket("localhost", serverport); + BufferedWriter w = new BufferedWriter( + new OutputStreamWriter(c.getOutputStream())); + BufferedReader r = new BufferedReader( + new InputStreamReader(c.getInputStream())); + System.out.println("Client: Connected."); + String echoPattern = "Otto"; + StringBuilder echoBuilder = + new StringBuilder(4500 + echoPattern.length()); + while (echoBuilder.length() < 4500) { + echoBuilder.append(echoPattern); + } + String echostring = echoBuilder.toString(); + w.write(echostring); + w.newLine(); + w.flush(); + System.out.println("Client: Sent " + echostring.length() + + " chars of data."); + String echoresponse = r.readLine(); + clientDone = true; + System.out.println("Client: Read " + echoresponse.length() + + " chars of data."); + w.close(); + r.close(); + c.close(); + System.out.println("Client: Closed streams and socket, exiting."); + } catch (IOException e) { + System.out.println("Client: Caught Exception."); + e.printStackTrace(); + clientDone = true; + throw e; + } + } + + public static void main(String[] args) throws Exception { + String keyFilename = System.getProperty("test.src", "./") + "/" + + pathToStores + "/" + keyStoreFile; + String trustFilename = System.getProperty("test.src", "./") + "/" + + pathToStores + "/" + trustStoreFile; + + System.setProperty("javax.net.ssl.keyStore", keyFilename); + System.setProperty("javax.net.ssl.keyStorePassword", passwd); + System.setProperty("javax.net.ssl.trustStore", trustFilename); + System.setProperty("javax.net.ssl.trustStorePassword", passwd); + + Thread serverThread = new Thread() { + @Override + public void run() { + runServer(); + } + }; + serverThread.start(); + runClient(); + while (serverThread.isAlive()) { + try { + serverThread.join(); + } catch (InterruptedException e) { + System.out.println("Main: Caught InterruptedException " + + " waiting for server Thread."); + } + } + if (serverException != null) { + throw serverException; + } + } +} From cb8aa405a6f62b28cbe1636fa350fb23c9298cbe Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Sun, 20 Mar 2016 00:03:43 +0000 Subject: [PATCH 19/36] 8152221: Use try-with-resource in test templates Reviewed-by: weijun --- .../templates/SSLSocketSSLEngineTemplate.java | 227 +++++++++--------- .../net/ssl/templates/SSLSocketTemplate.java | 53 ++-- 2 files changed, 135 insertions(+), 145 deletions(-) diff --git a/jdk/test/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java b/jdk/test/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java index d7f0d38cdee..fd5ec86e4ef 100644 --- a/jdk/test/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java +++ b/jdk/test/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java @@ -101,9 +101,6 @@ public class SSLSocketSSLEngineTemplate { private static final boolean debug = false; private final SSLContext sslc; private SSLEngine serverEngine; // server-side SSLEngine - private SSLSocket sslSocket; // client-side socket - private ServerSocket serverSocket; // server-side Socket, generates the... - private Socket socket; // server-side socket that will read private final byte[] serverMsg = "Hi there Client, I'm a Server.".getBytes(); @@ -217,132 +214,128 @@ public class SSLSocketSSLEngineTemplate { private void runTest(boolean direct) throws Exception { boolean serverClose = direct; - serverSocket = new ServerSocket(); - serverSocket.setReuseAddress(false); - serverSocket.bind(null); - int port = serverSocket.getLocalPort(); - Thread thread = createClientThread(port, serverClose); + // generates the server-side Socket + try (ServerSocket serverSocket = new ServerSocket()) { + serverSocket.setReuseAddress(false); + serverSocket.bind(null); + int port = serverSocket.getLocalPort(); + Thread thread = createClientThread(port, serverClose); - socket = serverSocket.accept(); - socket.setSoTimeout(500); - serverSocket.close(); + createSSLEngine(); + createBuffers(direct); - createSSLEngine(); - createBuffers(direct); + // server-side socket that will read + try (Socket socket = serverSocket.accept()) { + socket.setSoTimeout(500); - try { - boolean closed = false; - // will try to read one more time in case client message - // is fragmented to multiple pieces - boolean retry = true; + boolean closed = false; + // will try to read one more time in case client message + // is fragmented to multiple pieces + boolean retry = true; - InputStream is = socket.getInputStream(); - OutputStream os = socket.getOutputStream(); + InputStream is = socket.getInputStream(); + OutputStream os = socket.getOutputStream(); - SSLEngineResult serverResult; // results from last operation + SSLEngineResult serverResult; // results from last operation - /* - * Examining the SSLEngineResults could be much more involved, - * and may alter the overall flow of the application. - * - * For example, if we received a BUFFER_OVERFLOW when trying - * to write to the output pipe, we could reallocate a larger - * pipe, but instead we wait for the peer to drain it. - */ - byte[] inbound = new byte[8192]; - byte[] outbound = new byte[8192]; + /* + * Examining the SSLEngineResults could be much more involved, + * and may alter the overall flow of the application. + * + * For example, if we received a BUFFER_OVERFLOW when trying + * to write to the output pipe, we could reallocate a larger + * pipe, but instead we wait for the peer to drain it. + */ + byte[] inbound = new byte[8192]; + byte[] outbound = new byte[8192]; - while (!isEngineClosed(serverEngine)) { - int len; + while (!isEngineClosed(serverEngine)) { + int len; - // Inbound data - log("================"); + // Inbound data + log("================"); - // Read from the Client side. - try { - len = is.read(inbound); - if (len == -1) { - throw new Exception("Unexpected EOF"); - } - cTOs.put(inbound, 0, len); - } catch (SocketTimeoutException ste) { - // swallow. Nothing yet, probably waiting on us. - } - - cTOs.flip(); - - serverResult = serverEngine.unwrap(cTOs, serverIn); - log("server unwrap: ", serverResult); - runDelegatedTasks(serverResult, serverEngine); - cTOs.compact(); - - // Outbound data - log("----"); - - serverResult = serverEngine.wrap(serverOut, sTOc); - log("server wrap: ", serverResult); - runDelegatedTasks(serverResult, serverEngine); - - sTOc.flip(); - - if ((len = sTOc.remaining()) != 0) { - sTOc.get(outbound, 0, len); - os.write(outbound, 0, len); - // Give the other side a chance to process - } - - sTOc.compact(); - - if (!closed && (serverOut.remaining() == 0)) { - closed = true; - - /* - * We'll alternate initiatating the shutdown. - * When the server initiates, it will take one more - * loop, but tests the orderly shutdown. - */ - if (serverClose) { - serverEngine.closeOutbound(); - } - serverIn.flip(); - - /* - * A sanity check to ensure we got what was sent. - */ - if (serverIn.remaining() != clientMsg.length) { - if (retry && serverIn.remaining() < clientMsg.length) { - log("Need to read more from client"); - retry = false; - continue; - } else { - throw new Exception("Client: Data length error"); + // Read from the Client side. + try { + len = is.read(inbound); + if (len == -1) { + throw new Exception("Unexpected EOF"); } + cTOs.put(inbound, 0, len); + } catch (SocketTimeoutException ste) { + // swallow. Nothing yet, probably waiting on us. } - for (int i = 0; i < clientMsg.length; i++) { - if (clientMsg[i] != serverIn.get()) { - throw new Exception("Client: Data content error"); - } + cTOs.flip(); + + serverResult = serverEngine.unwrap(cTOs, serverIn); + log("server unwrap: ", serverResult); + runDelegatedTasks(serverResult, serverEngine); + cTOs.compact(); + + // Outbound data + log("----"); + + serverResult = serverEngine.wrap(serverOut, sTOc); + log("server wrap: ", serverResult); + runDelegatedTasks(serverResult, serverEngine); + + sTOc.flip(); + + if ((len = sTOc.remaining()) != 0) { + sTOc.get(outbound, 0, len); + os.write(outbound, 0, len); + // Give the other side a chance to process } - serverIn.compact(); + + sTOc.compact(); + + if (!closed && (serverOut.remaining() == 0)) { + closed = true; + + /* + * We'll alternate initiatating the shutdown. + * When the server initiates, it will take one more + * loop, but tests the orderly shutdown. + */ + if (serverClose) { + serverEngine.closeOutbound(); + } + serverIn.flip(); + + /* + * A sanity check to ensure we got what was sent. + */ + if (serverIn.remaining() != clientMsg.length) { + if (retry && + serverIn.remaining() < clientMsg.length) { + log("Need to read more from client"); + retry = false; + continue; + } else { + throw new Exception( + "Client: Data length error"); + } + } + + for (int i = 0; i < clientMsg.length; i++) { + if (clientMsg[i] != serverIn.get()) { + throw new Exception( + "Client: Data content error"); + } + } + serverIn.compact(); + } + } + } catch (Exception e) { + serverException = e; + } finally { + // Wait for the client to join up with us. + if (thread != null) { + thread.join(); } } - } catch (Exception e) { - serverException = e; } finally { - if (socket != null) { - socket.close(); - } - - // Wait for the client to join up with us. - if (thread != null) { - thread.join(); - } - - if (sslSocket != null) { - sslSocket.close(); - } - if (serverException != null) { if (clientException != null) { serverException.initCause(clientException); @@ -369,11 +362,9 @@ public class SSLSocketSSLEngineTemplate { @Override public void run() { - try { - Thread.sleep(1000); // Give server time to finish setup. - - sslSocket = (SSLSocket) sslc.getSocketFactory(). - createSocket("localhost", port); + // client-side socket + try (SSLSocket sslSocket = (SSLSocket)sslc.getSocketFactory(). + createSocket("localhost", port)) { OutputStream os = sslSocket.getOutputStream(); InputStream is = sslSocket.getInputStream(); diff --git a/jdk/test/javax/net/ssl/templates/SSLSocketTemplate.java b/jdk/test/javax/net/ssl/templates/SSLSocketTemplate.java index 920f4056267..12dfcaacae5 100644 --- a/jdk/test/javax/net/ssl/templates/SSLSocketTemplate.java +++ b/jdk/test/javax/net/ssl/templates/SSLSocketTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, 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 @@ -85,26 +85,26 @@ public class SSLSocketTemplate { */ void doServerSide() throws Exception { SSLServerSocketFactory sslssf = - (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); - SSLServerSocket sslServerSocket = - (SSLServerSocket) sslssf.createServerSocket(serverPort); + (SSLServerSocketFactory)SSLServerSocketFactory.getDefault(); + try (SSLServerSocket sslServerSocket = + (SSLServerSocket)sslssf.createServerSocket(serverPort)) { - serverPort = sslServerSocket.getLocalPort(); + serverPort = sslServerSocket.getLocalPort(); - /* - * Signal Client, we're ready for his connect. - */ - serverReady = true; + /* + * Signal Client, we're ready for his connect. + */ + serverReady = true; - SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); - InputStream sslIS = sslSocket.getInputStream(); - OutputStream sslOS = sslSocket.getOutputStream(); + try (SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept()) { + InputStream sslIS = sslSocket.getInputStream(); + OutputStream sslOS = sslSocket.getOutputStream(); - sslIS.read(); - sslOS.write(85); - sslOS.flush(); - - sslSocket.close(); + sslIS.read(); + sslOS.write(85); + sslOS.flush(); + } + } } /* @@ -123,18 +123,17 @@ public class SSLSocketTemplate { } SSLSocketFactory sslsf = - (SSLSocketFactory) SSLSocketFactory.getDefault(); - SSLSocket sslSocket = (SSLSocket) - sslsf.createSocket("localhost", serverPort); + (SSLSocketFactory)SSLSocketFactory.getDefault(); + try (SSLSocket sslSocket = + (SSLSocket)sslsf.createSocket("localhost", serverPort)) { - InputStream sslIS = sslSocket.getInputStream(); - OutputStream sslOS = sslSocket.getOutputStream(); + InputStream sslIS = sslSocket.getInputStream(); + OutputStream sslOS = sslSocket.getOutputStream(); - sslOS.write(280); - sslOS.flush(); - sslIS.read(); - - sslSocket.close(); + sslOS.write(280); + sslOS.flush(); + sslIS.read(); + } } /* From b69f398c06adc467694aa870bfa2ed318cb7587b Mon Sep 17 00:00:00 2001 From: Huaming Li Date: Sun, 20 Mar 2016 07:35:20 +0000 Subject: [PATCH 20/36] 8151582: (ch) test java/nio/channels/AsyncCloseAndInterrupt.java failing due to "Connection succeeded" Reviewed-by: bpb, rriggs, alanb --- .../nio/channels/AsyncCloseAndInterrupt.java | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/jdk/test/java/nio/channels/AsyncCloseAndInterrupt.java b/jdk/test/java/nio/channels/AsyncCloseAndInterrupt.java index 4172efe0daf..d897fa0ea55 100644 --- a/jdk/test/java/nio/channels/AsyncCloseAndInterrupt.java +++ b/jdk/test/java/nio/channels/AsyncCloseAndInterrupt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, 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 @@ -23,6 +23,7 @@ /* @test * @bug 4460583 4470470 4840199 6419424 6710579 6596323 6824135 6395224 7142919 + * 8151582 * @run main/othervm AsyncCloseAndInterrupt * @summary Comprehensive test of asynchronous closing and interruption * @author Mark Reinhold @@ -89,7 +90,7 @@ public class AsyncCloseAndInterrupt { private static void initRefuser() throws IOException { refuser = ServerSocketChannel.open(); - refuser.socket().bind(wildcardAddress); + refuser.bind(wildcardAddress, 1); // use minimum backlog } // Dead pipe source and sink @@ -349,7 +350,7 @@ public class AsyncCloseAndInterrupt { static final Op CONNECT = new Op("connect") { void setup() { - waitPump("connect wait for pumping refuser ..."); + waitPump("connect waiting for pumping refuser ..."); } void doIO(InterruptibleChannel ich) throws IOException { SocketChannel sc = (SocketChannel)ich; @@ -361,7 +362,7 @@ public class AsyncCloseAndInterrupt { static final Op FINISH_CONNECT = new Op("finishConnect") { void setup() { - waitPump("finishConnect wait for pumping refuser ..."); + waitPump("finishConnect waiting for pumping refuser ..."); } void doIO(InterruptibleChannel ich) throws IOException { SocketChannel sc = (SocketChannel)ich; @@ -498,12 +499,11 @@ public class AsyncCloseAndInterrupt { private static volatile boolean pumpReady = false; private static void waitPump(String msg){ - pumpReady = false; log.println(msg); - while (!pumpReady){ sleep(200); } + log.println(msg + " done"); } // Create a pump thread dedicated to saturate refuser's connection backlog @@ -520,28 +520,34 @@ public class AsyncCloseAndInterrupt { // Saturate the refuser's connection backlog so that further connection // attempts will be blocked + pumpReady = false; while (!pumpDone) { SocketChannel sc = SocketChannel.open(); sc.configureBlocking(false); boolean connected = sc.connect(refuser.socket().getLocalSocketAddress()); // Assume that the connection backlog is saturated if a - // client cannot connect to the refuser within 50 miliseconds + // client cannot connect to the refuser within 50 milliseconds long start = System.currentTimeMillis(); - while (!connected && (System.currentTimeMillis() - start < 50)) { + while (!pumpReady && !connected + && (System.currentTimeMillis() - start < 50)) { connected = sc.finishConnect(); } if (connected) { // Retain so that finalizer doesn't close refuserClients.add(sc); - pumpReady = false; } else { sc.close(); pumpReady = true; } } + for (SocketChannel sc : refuserClients) { + sc.close(); + } + refuser.close(); + log.println("Stop pumping refuser ..."); return refuserClients.size(); } @@ -565,8 +571,6 @@ public class AsyncCloseAndInterrupt { sleep(50); } while (!t.ready); - sleep(100); - switch (test) { case TEST_INTR: From 4b4f61a64affbf3afd42cdefbee801301b9c99a7 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 21 Mar 2016 10:27:50 +0100 Subject: [PATCH 21/36] 8131913: jdk/internal/jline/console/StripAnsiTest.java can't run in the background Avoid using a real terminal in tests. Reviewed-by: rfield --- jdk/test/jdk/internal/jline/console/StripAnsiTest.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/jdk/test/jdk/internal/jline/console/StripAnsiTest.java b/jdk/test/jdk/internal/jline/console/StripAnsiTest.java index f9b03cecc23..46f919e0a12 100644 --- a/jdk/test/jdk/internal/jline/console/StripAnsiTest.java +++ b/jdk/test/jdk/internal/jline/console/StripAnsiTest.java @@ -23,14 +23,16 @@ /** * @test - * @bug 8080679 - * @modules jdk.internal.le/jdk.internal.jline.console + * @bug 8080679 8131913 + * @modules jdk.internal.le/jdk.internal.jline + * jdk.internal.le/jdk.internal.jline.console * @summary Verify ConsoleReader.stripAnsi strips escape sequences from its input correctly. */ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.lang.reflect.Method; +import jdk.internal.jline.UnsupportedTerminal; import jdk.internal.jline.console.ConsoleReader; public class StripAnsiTest { @@ -41,7 +43,7 @@ public class StripAnsiTest { void run() throws Exception { ByteArrayInputStream in = new ByteArrayInputStream(new byte[0]); ByteArrayOutputStream out = new ByteArrayOutputStream(); - ConsoleReader reader = new ConsoleReader(in, out); + ConsoleReader reader = new ConsoleReader(in, out, new UnsupportedTerminal()); String withAnsi = "0\033[s1\033[2J2\033[37;4m3"; String expected = "0123"; From 6b7a41ca2bf049f3447ddc3a987fcef058631595 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Mon, 21 Mar 2016 08:48:34 -0700 Subject: [PATCH 22/36] 8060097: sun/net/idn/TestStringPrep.java failed Reviewed-by: michaelm --- jdk/test/sun/net/idn/TestStringPrep.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/jdk/test/sun/net/idn/TestStringPrep.java b/jdk/test/sun/net/idn/TestStringPrep.java index 20b4f5d3659..984ecb8a785 100644 --- a/jdk/test/sun/net/idn/TestStringPrep.java +++ b/jdk/test/sun/net/idn/TestStringPrep.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -24,7 +24,7 @@ /* * @test * @summary Unit test for sun.net.idn.Punycode - * @bug 4737170 + * @bug 4737170 8060097 * @modules java.base/sun.net.idn java.base/sun.text.normalizer * @library . * @compile -XDignore.symbol.file TestStringPrep.java NFS4StringPrep.java @@ -41,6 +41,7 @@ import java.text.ParseException; import java.io.InputStream; +import java.util.Locale; import sun.net.idn.StringPrep; import sun.text.normalizer.UCharacterIterator; @@ -209,7 +210,7 @@ public class TestStringPrep { src = "THISISATEST"; byte[] dest = NFS4StringPrep.cs_prepare(src.getBytes("UTF-8"), false); String destStr = new String(dest, "UTF-8"); - if(!src.toLowerCase().equals(destStr)){ + if(!src.toLowerCase(Locale.ROOT).equals(destStr)){ fail("Did not get expected output. Expected: "+ prettify(src)+ " Got: " + prettify(destStr)); } @@ -274,7 +275,7 @@ public class TestStringPrep { private static String hex(char ch) { StringBuffer result = new StringBuffer(); - String foo = Integer.toString(ch,16).toUpperCase(); + String foo = Integer.toString(ch,16).toUpperCase(Locale.ROOT); for (int i = foo.length(); i < 4; ++i) { result.append('0'); } From d110d8b320c4b6008ab3297ba27bbf998126fa47 Mon Sep 17 00:00:00 2001 From: Nadeesh TV Date: Mon, 21 Mar 2016 14:24:11 -0400 Subject: [PATCH 23/36] 8032051: "ZonedDateTime" class "parse" method fails with short time zone offset ("+01") Reviewed-by: rriggs, scolebourne --- .../java/time/format/DateTimeFormatter.java | 6 + .../time/format/DateTimeFormatterBuilder.java | 53 ++++++--- .../time/tck/java/time/TCKZonedDateTime.java | 1 + .../format/TCKDateTimeFormatterBuilder.java | 107 ++++++++++++++++++ .../time/format/TCKOffsetPrinterParser.java | 24 ++++ 5 files changed, 177 insertions(+), 14 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java index 80895c8a8a2..3478af25761 100644 --- a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java +++ b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java @@ -932,6 +932,7 @@ public final class DateTimeFormatter { *

  • The {@link #ISO_LOCAL_DATE_TIME} *
  • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then * they will be handled even though this is not part of the ISO-8601 standard. + * The offset parsing is lenient, which allows the minutes and seconds to be optional. * Parsing is case insensitive. *
*

@@ -944,7 +945,9 @@ public final class DateTimeFormatter { ISO_OFFSET_DATE_TIME = new DateTimeFormatterBuilder() .parseCaseInsensitive() .append(ISO_LOCAL_DATE_TIME) + .parseLenient() .appendOffsetId() + .parseStrict() .toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE); } @@ -1169,6 +1172,7 @@ public final class DateTimeFormatter { *

  • If the offset is not available to format or parse then the format is complete. *
  • The {@link ZoneOffset#getId() offset ID} without colons. If the offset has * seconds then they will be handled even though this is not part of the ISO-8601 standard. + * The offset parsing is lenient, which allows the minutes and seconds to be optional. * Parsing is case insensitive. * *

    @@ -1187,7 +1191,9 @@ public final class DateTimeFormatter { .appendValue(MONTH_OF_YEAR, 2) .appendValue(DAY_OF_MONTH, 2) .optionalStart() + .parseLenient() .appendOffset("+HHMMss", "Z") + .parseStrict() .toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE); } diff --git a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java index 17d9759f51f..d7baf69c5b5 100644 --- a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -866,7 +866,9 @@ public final class DateTimeFormatterBuilder { * Appends the zone offset, such as '+01:00', to the formatter. *

    * This appends an instruction to format/parse the offset ID to the builder. - * This is equivalent to calling {@code appendOffset("+HH:MM:ss", "Z")}. + * This is equivalent to calling {@code appendOffset("+HH:mm:ss", "Z")}. + * See {@link #appendOffset(String, String)} for details on formatting + * and parsing. * * @return this, for chaining, not null */ @@ -886,9 +888,18 @@ public final class DateTimeFormatterBuilder { * If the offset cannot be obtained then an exception is thrown unless the * section of the formatter is optional. *

    - * During parsing, the offset is parsed using the format defined below. - * If the offset cannot be parsed then an exception is thrown unless the - * section of the formatter is optional. + * When parsing in strict mode, the input must contain the mandatory + * and optional elements are defined by the specified pattern. + * If the offset cannot be parsed then an exception is thrown unless + * the section of the formatter is optional. + *

    + * When parsing in lenient mode, only the hours are mandatory - minutes + * and seconds are optional. The colons are required if the specified + * pattern contains a colon. If the specified pattern is "+HH", the + * presence of colons is determined by whether the character after the + * hour digits is a colon or not. + * If the offset cannot be parsed then an exception is thrown unless + * the section of the formatter is optional. *

    * The format of the offset is controlled by a pattern which must be one * of the following: @@ -902,6 +913,10 @@ public final class DateTimeFormatterBuilder { *

  • {@code +HH:MM:ss} - hour and minute, with second if non-zero, with colon *
  • {@code +HHMMSS} - hour, minute and second, no colon *
  • {@code +HH:MM:SS} - hour, minute and second, with colon + *
  • {@code +HHmmss} - hour, with minute if non-zero or with minute and + * second if non-zero, no colon + *
  • {@code +HH:mm:ss} - hour, with minute if non-zero or with minute and + * second if non-zero, with colon * * The "no offset" text controls what text is printed when the total amount of * the offset fields to be output is zero. @@ -3318,7 +3333,7 @@ public final class DateTimeFormatterBuilder { */ static final class OffsetIdPrinterParser implements DateTimePrinterParser { static final String[] PATTERNS = new String[] { - "+HH", "+HHmm", "+HH:mm", "+HHMM", "+HH:MM", "+HHMMss", "+HH:MM:ss", "+HHMMSS", "+HH:MM:SS", + "+HH", "+HHmm", "+HH:mm", "+HHMM", "+HH:MM", "+HHMMss", "+HH:MM:ss", "+HHMMSS", "+HH:MM:SS", "+HHmmss", "+HH:mm:ss", }; // order used in pattern builder static final OffsetIdPrinterParser INSTANCE_ID_Z = new OffsetIdPrinterParser("+HH:MM:ss", "Z"); static final OffsetIdPrinterParser INSTANCE_ID_ZERO = new OffsetIdPrinterParser("+HH:MM:ss", "0"); @@ -3365,11 +3380,11 @@ public final class DateTimeFormatterBuilder { int output = absHours; buf.append(totalSecs < 0 ? "-" : "+") .append((char) (absHours / 10 + '0')).append((char) (absHours % 10 + '0')); - if (type >= 3 || (type >= 1 && absMinutes > 0)) { + if ((type >= 3 && type < 9) || (type >= 9 && absSeconds > 0) || (type >= 1 && absMinutes > 0)) { buf.append((type % 2) == 0 ? ":" : "") .append((char) (absMinutes / 10 + '0')).append((char) (absMinutes % 10 + '0')); output += absMinutes; - if (type >= 7 || (type >= 5 && absSeconds > 0)) { + if (type == 7 || type == 8 || (type >= 5 && absSeconds > 0)) { buf.append((type % 2) == 0 ? ":" : "") .append((char) (absSeconds / 10 + '0')).append((char) (absSeconds % 10 + '0')); output += absSeconds; @@ -3387,6 +3402,15 @@ public final class DateTimeFormatterBuilder { public int parse(DateTimeParseContext context, CharSequence text, int position) { int length = text.length(); int noOffsetLen = noOffsetText.length(); + int parseType = type; + if (context.isStrict() == false) { + if ((parseType > 0 && (parseType % 2) == 0) || + (parseType == 0 && length > position + 3 && text.charAt(position + 3) == ':')) { + parseType = 10; + } else { + parseType = 9; + } + } if (noOffsetLen == 0) { if (position == length) { return context.setParsedField(OFFSET_SECONDS, 0, position, position); @@ -3407,9 +3431,9 @@ public final class DateTimeFormatterBuilder { int negative = (sign == '-' ? -1 : 1); int[] array = new int[4]; array[0] = position + 1; - if ((parseNumber(array, 1, text, true) || - parseNumber(array, 2, text, type >=3) || - parseNumber(array, 3, text, false)) == false) { + if ((parseNumber(array, 1, text, true, parseType) || + parseNumber(array, 2, text, parseType >= 3 && parseType < 9, parseType) || + parseNumber(array, 3, text, parseType == 7 || parseType == 8, parseType)) == false) { // success long offsetSecs = negative * (array[1] * 3600L + array[2] * 60L + array[3]); return context.setParsedField(OFFSET_SECONDS, offsetSecs, position, array[0]); @@ -3417,7 +3441,7 @@ public final class DateTimeFormatterBuilder { } // handle special case of empty no offset text if (noOffsetLen == 0) { - return context.setParsedField(OFFSET_SECONDS, 0, position, position + noOffsetLen); + return context.setParsedField(OFFSET_SECONDS, 0, position, position); } return ~position; } @@ -3429,14 +3453,15 @@ public final class DateTimeFormatterBuilder { * @param arrayIndex the index to parse the value into * @param parseText the offset ID, not null * @param required whether this number is required + * @param parseType the offset pattern type * @return true if an error occurred */ - private boolean parseNumber(int[] array, int arrayIndex, CharSequence parseText, boolean required) { - if ((type + 3) / 2 < arrayIndex) { + private boolean parseNumber(int[] array, int arrayIndex, CharSequence parseText, boolean required, int parseType) { + if ((parseType + 3) / 2 < arrayIndex) { return false; // ignore seconds/minutes } int pos = array[0]; - if ((type % 2) == 0 && arrayIndex > 1) { + if ((parseType % 2) == 0 && arrayIndex > 1) { if (pos + 1 > parseText.length() || parseText.charAt(pos) != ':') { return required; } diff --git a/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java b/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java index ad87637605b..db21759b3dd 100644 --- a/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java +++ b/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java @@ -761,6 +761,7 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { {"2012-06-30T12:30:40-01:00[UT-01:00]", 2012, 6, 30, 12, 30, 40, 0, "UT-01:00"}, {"2012-06-30T12:30:40-01:00[UTC-01:00]", 2012, 6, 30, 12, 30, 40, 0, "UTC-01:00"}, {"2012-06-30T12:30:40+01:00[Europe/London]", 2012, 6, 30, 12, 30, 40, 0, "Europe/London"}, + {"2012-06-30T12:30:40+01", 2012, 6, 30, 12, 30, 40, 0, "+01:00"}, }; } diff --git a/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java index c5a017c911e..696ba8109cc 100644 --- a/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java +++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java @@ -59,11 +59,13 @@ */ package tck.java.time.format; +import static java.time.format.DateTimeFormatter.BASIC_ISO_DATE; import static java.time.temporal.ChronoField.DAY_OF_MONTH; import static java.time.temporal.ChronoField.HOUR_OF_DAY; import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoField.NANO_OF_SECOND; +import static java.time.temporal.ChronoField.OFFSET_SECONDS; import static java.time.temporal.ChronoField.YEAR; import static org.testng.Assert.assertEquals; @@ -73,6 +75,7 @@ import java.time.YearMonth; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; +import java.time.format.DateTimeParseException; import java.time.format.SignStyle; import java.time.format.TextStyle; import java.time.temporal.Temporal; @@ -339,6 +342,18 @@ public class TCKDateTimeFormatterBuilder { {"+HH", 2, 0, 45, "+02"}, {"+HH", 2, 30, 45, "+02"}, + {"+HHmm", 2, 0, 0, "+02"}, + {"+HHmm", -2, 0, 0, "-02"}, + {"+HHmm", 2, 30, 0, "+0230"}, + {"+HHmm", 2, 0, 45, "+02"}, + {"+HHmm", 2, 30, 45, "+0230"}, + + {"+HH:mm", 2, 0, 0, "+02"}, + {"+HH:mm", -2, 0, 0, "-02"}, + {"+HH:mm", 2, 30, 0, "+02:30"}, + {"+HH:mm", 2, 0, 45, "+02"}, + {"+HH:mm", 2, 30, 45, "+02:30"}, + {"+HHMM", 2, 0, 0, "+0200"}, {"+HHMM", -2, 0, 0, "-0200"}, {"+HHMM", 2, 30, 0, "+0230"}, @@ -374,6 +389,20 @@ public class TCKDateTimeFormatterBuilder { {"+HH:MM:SS", 2, 30, 0, "+02:30:00"}, {"+HH:MM:SS", 2, 0, 45, "+02:00:45"}, {"+HH:MM:SS", 2, 30, 45, "+02:30:45"}, + + {"+HHmmss", 2, 0, 0, "+02"}, + {"+HHmmss", -2, 0, 0, "-02"}, + {"+HHmmss", 2, 30, 0, "+0230"}, + {"+HHmmss", 2, 0, 45, "+020045"}, + {"+HHmmss", 2, 30, 45, "+023045"}, + + {"+HH:mm:ss", 2, 0, 0, "+02"}, + {"+HH:mm:ss", -2, 0, 0, "-02"}, + {"+HH:mm:ss", 2, 30, 0, "+02:30"}, + {"+HH:mm:ss", 2, 0, 45, "+02:00:45"}, + {"+HH:mm:ss", 2, 30, 45, "+02:30:45"}, + + }; } @@ -878,4 +907,82 @@ public class TCKDateTimeFormatterBuilder { assertEquals(parsed.getLong(MINUTE_OF_HOUR), 30L); } + @DataProvider(name="lenientOffsetParseData") + Object[][] data_lenient_offset_parse() { + return new Object[][] { + {"+HH", "+01", 3600}, + {"+HH", "+0101", 3660}, + {"+HH", "+010101", 3661}, + {"+HH", "+01", 3600}, + {"+HH", "+01:01", 3660}, + {"+HH", "+01:01:01", 3661}, + {"+HHmm", "+01", 3600}, + {"+HHmm", "+0101", 3660}, + {"+HHmm", "+010101", 3661}, + {"+HH:mm", "+01", 3600}, + {"+HH:mm", "+01:01", 3660}, + {"+HH:mm", "+01:01:01", 3661}, + {"+HHMM", "+01", 3600}, + {"+HHMM", "+0101", 3660}, + {"+HHMM", "+010101", 3661}, + {"+HH:MM", "+01", 3600}, + {"+HH:MM", "+01:01", 3660}, + {"+HH:MM", "+01:01:01", 3661}, + {"+HHMMss", "+01", 3600}, + {"+HHMMss", "+0101", 3660}, + {"+HHMMss", "+010101", 3661}, + {"+HH:MM:ss", "+01", 3600}, + {"+HH:MM:ss", "+01:01", 3660}, + {"+HH:MM:ss", "+01:01:01", 3661}, + {"+HHMMSS", "+01", 3600}, + {"+HHMMSS", "+0101", 3660}, + {"+HHMMSS", "+010101", 3661}, + {"+HH:MM:SS", "+01", 3600}, + {"+HH:MM:SS", "+01:01", 3660}, + {"+HH:MM:SS", "+01:01:01", 3661}, + {"+HHmmss", "+01", 3600}, + {"+HHmmss", "+0101", 3660}, + {"+HHmmss", "+010101", 3661}, + {"+HH:mm:ss", "+01", 3600}, + {"+HH:mm:ss", "+01:01", 3660}, + {"+HH:mm:ss", "+01:01:01", 3661}, + }; + } + + @Test(dataProvider="lenientOffsetParseData") + public void test_lenient_offset_parse_1(String pattern, String offset, int offsetSeconds) { + assertEquals(new DateTimeFormatterBuilder().parseLenient().appendOffset(pattern, "Z").toFormatter().parse(offset).get(OFFSET_SECONDS), + offsetSeconds); + } + + @Test + public void test_lenient_offset_parse_2() { + assertEquals(new DateTimeFormatterBuilder().parseLenient().appendOffsetId().toFormatter().parse("+01").get(OFFSET_SECONDS), + 3600); + } + + @Test(expectedExceptions=DateTimeParseException.class) + public void test_strict_appendOffsetId() { + assertEquals(new DateTimeFormatterBuilder().appendOffsetId().toFormatter().parse("+01").get(OFFSET_SECONDS), + 3600); + } + + @Test(expectedExceptions=DateTimeParseException.class) + public void test_strict_appendOffset_1() { + assertEquals(new DateTimeFormatterBuilder().appendOffset("+HH:MM:ss", "Z").toFormatter().parse("+01").get(OFFSET_SECONDS), + 3600); + } + + @Test(expectedExceptions=DateTimeParseException.class) + public void test_strict_appendOffset_2() { + assertEquals(new DateTimeFormatterBuilder().appendOffset("+HHMMss", "Z").toFormatter().parse("+01").get(OFFSET_SECONDS), + 3600); + } + + @Test + public void test_basic_iso_date() { + assertEquals(BASIC_ISO_DATE.parse("20021231+01").get(OFFSET_SECONDS), 3600); + assertEquals(BASIC_ISO_DATE.parse("20021231+0101").get(OFFSET_SECONDS), 3660); + } + } diff --git a/jdk/test/java/time/tck/java/time/format/TCKOffsetPrinterParser.java b/jdk/test/java/time/tck/java/time/format/TCKOffsetPrinterParser.java index 76cfa56f88d..d841172ce90 100644 --- a/jdk/test/java/time/tck/java/time/format/TCKOffsetPrinterParser.java +++ b/jdk/test/java/time/tck/java/time/format/TCKOffsetPrinterParser.java @@ -199,6 +199,30 @@ public class TCKOffsetPrinterParser { {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_M0023, "-00:23:00"}, {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_M012345, "-01:23:45"}, {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "-00:00:45"}, + + {"+HH:mm:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_UTC, "Z"}, + {"+HH:mm:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_P0100, "+01"}, + {"+HH:mm:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_P0123, "+01:23"}, + {"+HH:mm:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_P0023, "+00:23"}, + {"+HH:mm:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_P012345, "+01:23:45"}, + {"+HH:mm:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "-00:00:45"}, + {"+HH:mm:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_M0100, "-01"}, + {"+HH:mm:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_M0123, "-01:23"}, + {"+HH:mm:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_M0023, "-00:23"}, + {"+HH:mm:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_M012345, "-01:23:45"}, + {"+HH:mm:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "-00:00:45"}, + + {"+HHmmss", "Z", DT_2012_06_30_12_30_40, OFFSET_UTC, "Z"}, + {"+HHmmss", "Z", DT_2012_06_30_12_30_40, OFFSET_P0100, "+01"}, + {"+HHmmss", "Z", DT_2012_06_30_12_30_40, OFFSET_P0123, "+0123"}, + {"+HHmmss", "Z", DT_2012_06_30_12_30_40, OFFSET_P0023, "+0023"}, + {"+HHmmss", "Z", DT_2012_06_30_12_30_40, OFFSET_P012345, "+012345"}, + {"+HHmmss", "Z", DT_2012_06_30_12_30_40, OFFSET_P000045, "+000045"}, + {"+HHmmss", "Z", DT_2012_06_30_12_30_40, OFFSET_M0100, "-01"}, + {"+HHmmss", "Z", DT_2012_06_30_12_30_40, OFFSET_M0123, "-0123"}, + {"+HHmmss", "Z", DT_2012_06_30_12_30_40, OFFSET_M0023, "-0023"}, + {"+HHmmss", "Z", DT_2012_06_30_12_30_40, OFFSET_M012345, "-012345"}, + {"+HHmmss", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "-000045"}, }; } From 99f5d7fd7462aad7a2a0413cf6ec8f239cea8797 Mon Sep 17 00:00:00 2001 From: Sibabrata Sahoo Date: Mon, 21 Mar 2016 11:54:23 -0700 Subject: [PATCH 24/36] 8150512: Update test for jdk.security.provider.preferred security property Reviewed-by: ascarpino --- .../jca/PreferredProviderNegativeTest.java | 77 ++++---- .../security/jca/PreferredProviderTest.java | 173 +++++++++++------- 2 files changed, 145 insertions(+), 105 deletions(-) diff --git a/jdk/test/sun/security/jca/PreferredProviderNegativeTest.java b/jdk/test/sun/security/jca/PreferredProviderNegativeTest.java index 5d69d998eb9..c6f5cf28c87 100644 --- a/jdk/test/sun/security/jca/PreferredProviderNegativeTest.java +++ b/jdk/test/sun/security/jca/PreferredProviderNegativeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, 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 @@ -21,55 +21,52 @@ * questions. */ -/** - * @test - * @bug 8076359 8133151 - * @summary Test for jdk.security.provider.preferred security property - * @requires os.name == "SunOS" - * @run main/othervm PreferredProviderNegativeTest preJCESet AES:OracleUcrypto false - * @run main/othervm PreferredProviderNegativeTest preJCESet AES:SunNegative true - * @run main/othervm PreferredProviderNegativeTest afterJCESet AES:SunJGSS - * @run main/othervm PreferredProviderNegativeTest afterJCESet AES:SunECNegative - * @run main/othervm PreferredProviderNegativeTest invalidAlg AESNegative:SunJCE - */ - import java.security.Security; import java.security.NoSuchAlgorithmException; import javax.crypto.Cipher; import javax.crypto.NoSuchPaddingException; +/** + * @test + * @bug 8076359 8133151 8150512 + * @summary Test for jdk.security.provider.preferred security property + * @run main/othervm PreferredProviderNegativeTest preSet AES false + * @run main/othervm PreferredProviderNegativeTest preSet AES:SunNegative true + * @run main/othervm PreferredProviderNegativeTest afterSet AES:SunJGSS + * @run main/othervm PreferredProviderNegativeTest afterSet AES:SunECNegative + * @run main/othervm PreferredProviderNegativeTest invalidAlg AESInvalid:SunJCE + */ public class PreferredProviderNegativeTest { + static final String SEC_PREF_PROP = "jdk.security.provider.preferred"; + /* * Test security property could be set by valid and invalid provider * before JCE was loaded */ public static void preJCESet(String value, boolean negativeProvider) throws NoSuchAlgorithmException, NoSuchPaddingException { - Security.setProperty("jdk.security.provider.preferred", value); - if (!Security.getProperty("jdk.security.provider.preferred") - .equals(value)) { - throw new RuntimeException( - "Test Failed:The property wasn't set"); + Security.setProperty(SEC_PREF_PROP, value); + + if (!Security.getProperty(SEC_PREF_PROP).equals(value)) { + throw new RuntimeException("Test Failed:The property wasn't set"); } String[] arrays = value.split(":"); Cipher cipher = Cipher.getInstance(arrays[0]); - if (negativeProvider) { if (cipher.getProvider().getName().equals(arrays[1])) { throw new RuntimeException( - "Test Failed:The provider shouldn't be set"); + "Test Failed:The provider shouldn't be set."); } } else { if (!cipher.getProvider().getName().equals(arrays[1])) { - throw new RuntimeException( - "Test Faild:The provider could be set " - + "by valid provider "); + throw new RuntimeException("Test Faild:The provider could be " + + "set by valid provider."); } } - System.out.println("Test Pass"); + System.out.println("Test Pass."); } /* @@ -81,10 +78,10 @@ public class PreferredProviderNegativeTest { String[] arrays = value.split(":"); Cipher cipher = Cipher.getInstance(arrays[0]); - Security.setProperty("jdk.security.provider.preferred", value); + Security.setProperty(SEC_PREF_PROP, value); if (!cipher.getProvider().getName().equals("SunJCE")) { - throw new RuntimeException( - "Test Failed:The security property can't be updated after JCE load."); + throw new RuntimeException("Test Failed:The security property can't" + + " be updated after JCE load."); } System.out.println("Test Pass"); } @@ -94,10 +91,11 @@ public class PreferredProviderNegativeTest { String[] arrays = value.split(":"); try { - Security.setProperty("jdk.security.provider.preferred", value); + Security.setProperty(SEC_PREF_PROP, value); Cipher.getInstance(arrays[0]); } catch (NoSuchAlgorithmException e) { - System.out.println("Test Pass:Got NoSuchAlgorithmException as expired"); + System.out.println( + "Test Pass:Got NoSuchAlgorithmException as expired"); return; } throw new RuntimeException( @@ -106,15 +104,25 @@ public class PreferredProviderNegativeTest { public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException { - boolean negativeProvider; if (args.length >= 2) { switch (args[0]) { - case "preJCESet": - negativeProvider = Boolean.valueOf(args[2]); - PreferredProviderNegativeTest.preJCESet(args[1], negativeProvider); + case "preSet": + boolean negativeProvider = Boolean.valueOf(args[2]); + boolean solaris = System.getProperty("os.name") + .toLowerCase().contains("sun"); + String value = args[1]; + if (args[1].split(":").length < 2) { + if (solaris) { + value += ":OracleUcrypto"; + } else { + value += ":SunJCE"; + } + } + PreferredProviderNegativeTest.preJCESet( + value, negativeProvider); break; - case "afterJCESet": + case "afterSet": PreferredProviderNegativeTest.afterJCESet(args[1]); break; case "invalidAlg": @@ -127,4 +135,3 @@ public class PreferredProviderNegativeTest { } } } - diff --git a/jdk/test/sun/security/jca/PreferredProviderTest.java b/jdk/test/sun/security/jca/PreferredProviderTest.java index b7eace2d90e..56aa4a0210e 100644 --- a/jdk/test/sun/security/jca/PreferredProviderTest.java +++ b/jdk/test/sun/security/jca/PreferredProviderTest.java @@ -21,97 +21,131 @@ * questions. */ -/** - * @test - * @bug 8076359 8133151 8145344 - * @summary Test the value for new jdk.security.provider.preferred security property - * @requires os.name == "SunOS" - */ - -import java.security.KeyFactory; import java.security.MessageDigest; +import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.Security; +import java.security.Provider; import java.util.Arrays; import java.util.List; import javax.crypto.Cipher; import javax.crypto.NoSuchPaddingException; +/** + * @test + * @bug 8076359 8133151 8145344 8150512 + * @summary Test the value for new jdk.security.provider.preferred + * security property + */ public class PreferredProviderTest { - private static final List SPARC_DATA = Arrays.asList( - new DataTuple("SHA1", "SUN"), new DataTuple("SHA-1", "SUN"), - new DataTuple("SHA-224", "SUN"), new DataTuple("SHA-256", "SUN"), - new DataTuple("SHA-384", "SUN"), new DataTuple("SHA-512", "SUN")); - private static final List X86_DATA = Arrays - .asList(new DataTuple("RSA", "SunRsaSign")); - - public void RunTest(String type) + public void RunTest(String type, String os) throws NoSuchAlgorithmException, NoSuchPaddingException { - String preferredProvider = Security - .getProperty("jdk.security.provider.preferred"); + String actualProvider = null; - if (type.equals("sparcv9")) { - if (!preferredProvider.equals( - "AES:SunJCE, SHA1:SUN, SHA-224:SUN, SHA-256:SUN, SHA-384:SUN, SHA-512:SUN")) { - throw new RuntimeException( - "Test Failed: wrong jdk.security.provider.preferred " - + "value on solaris-sparcv9"); - } - for (DataTuple dataTuple : SPARC_DATA) { - MessageDigest md = MessageDigest - .getInstance(dataTuple.algorithm); - actualProvider = md.getProvider().getName(); - if (!actualProvider.equals(dataTuple.provider)) { - throw new RuntimeException(String.format( - "Test Failed:Got wrong " - + "provider from Solaris-sparcv9 platform," - + "Expected Provider: %s, Returned Provider: %s", - dataTuple.provider, actualProvider)); - } - } - } else if (type.equals("amd64")) { - if (!preferredProvider.equals("AES:SunJCE, RSA:SunRsaSign")) { - throw new RuntimeException( - "Test Failed: wrong jdk.security.provider.preferred " - + "value on solaris-x86"); - } - for (DataTuple dataTuple : X86_DATA) { - KeyFactory keyFactory = KeyFactory - .getInstance(dataTuple.algorithm); - actualProvider = keyFactory.getProvider().getName(); - if (!actualProvider.equals(dataTuple.provider)) { - throw new RuntimeException(String.format( - "Test Failed:Got wrong " - + "provider from Solaris-x86 platform," - + "Expected Provider: %s, Returned Provider: %s", - dataTuple.provider, actualProvider)); - } - } + boolean solaris = os.contains("sun"); + String preferredProp + = "AES/GCM/NoPadding:SunJCE, MessageDigest.SHA-256:SUN"; + System.out.printf("%nExecuting test for the platform '%s'%n", os); + if (!solaris) { + //For other platform it will try to set the preferred algorithm and + //Provider and verify the usage of it. + Security.setProperty( + "jdk.security.provider.preferred", preferredProp); + verifyPreferredProviderProperty(os, type, preferredProp); + + verifyDigestProvider(os, type, Arrays.asList( + new DataTuple("SHA-256", "SUN"))); } else { - throw new RuntimeException("Test Failed: wrong platform value"); + //For solaris the preferred algorithm/provider is already set in + //java.security file which will be verified. + switch (type) { + case "sparcv9": + preferredProp = "AES:SunJCE, SHA1:SUN, SHA-224:SUN," + + " SHA-256:SUN, SHA-384:SUN, SHA-512:SUN"; + verifyPreferredProviderProperty(os, type, preferredProp); + + verifyDigestProvider(os, type, Arrays.asList( + new DataTuple("SHA1", "SUN"), + new DataTuple("SHA-1", "SUN"), + new DataTuple("SHA-224", "SUN"), + new DataTuple("SHA-256", "SUN"), + new DataTuple("SHA-384", "SUN"), + new DataTuple("SHA-512", "SUN"))); + break; + case "amd64": + preferredProp = "AES:SunJCE, RSA:SunRsaSign"; + verifyPreferredProviderProperty(os, type, preferredProp); + + verifyKeyFactoryProvider(os, type, Arrays.asList( + new DataTuple("RSA", "SunRsaSign"))); + break; + } + verifyDigestProvider(os, type, Arrays.asList( + new DataTuple("MD5", "OracleUcrypto"))); } Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); actualProvider = cipher.getProvider().getName(); if (!actualProvider.equals("SunJCE")) { - throw new RuntimeException(String.format( - "Test Failed:Got wrong provider from Solaris-%s platform, " - + "Expected Provider: SunJCE, Returned Provider: %s", - type, actualProvider)); + throw new RuntimeException(String.format("Test Failed:Got wrong " + + "provider from %s-%s platform, Expected Provider: SunJCE," + + " Returned Provider: %s", os, type, actualProvider)); } + } - MessageDigest md = MessageDigest.getInstance("MD5"); - actualProvider = md.getProvider().getName(); - if (!actualProvider.equals("OracleUcrypto")) { + private static void verifyPreferredProviderProperty(String os, String arch, + String preferred) { + String preferredProvider + = Security.getProperty("jdk.security.provider.preferred"); + if (!preferredProvider.equals(preferred)) { throw new RuntimeException(String.format( - "Test Failed:Got wrong provider from Solaris-%s platform," - + "Expected Provider: OracleUcrypto, Returned Provider: %s", - type, actualProvider)); + "Test Failed: wrong jdk.security.provider.preferred value " + + "on %s-%s", os, arch)); + } + System.out.println( + "Preferred provider security property verification complete."); + } + + private static void verifyDigestProvider(String os, String arch, + List algoProviders) throws NoSuchAlgorithmException { + for (DataTuple dataTuple : algoProviders) { + System.out.printf( + "Verifying MessageDigest for '%s'%n", dataTuple.algorithm); + MessageDigest md = MessageDigest.getInstance(dataTuple.algorithm); + matchProvider(md.getProvider(), dataTuple.provider, + dataTuple.algorithm, os, arch); + } + System.out.println( + "Preferred MessageDigest algorithm verification successful."); + } + + private static void verifyKeyFactoryProvider(String os, String arch, + List algoProviders) throws NoSuchAlgorithmException { + for (DataTuple dataTuple : algoProviders) { + System.out.printf( + "Verifying KeyFactory for '%s'%n", dataTuple.algorithm); + KeyFactory kf = KeyFactory.getInstance(dataTuple.algorithm); + matchProvider(kf.getProvider(), dataTuple.provider, + dataTuple.algorithm, os, arch); + } + System.out.println( + "Preferred KeyFactory algorithm verification successful."); + } + + private static void matchProvider(Provider provider, String expected, + String algo, String os, String arch) { + if (!provider.getName().equals(expected)) { + throw new RuntimeException(String.format( + "Test Failed:Got wrong provider from %s-%s platform, " + + "for algorithm %s. Expected Provider: %s," + + " Returned Provider: %s", os, arch, algo, + expected, provider.getName())); } } private static class DataTuple { + private final String provider; private final String algorithm; @@ -123,10 +157,9 @@ public class PreferredProviderTest { public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException { - - String arch = System.getProperty("os.arch"); + String os = System.getProperty("os.name").toLowerCase(); + String arch = System.getProperty("os.arch").toLowerCase(); PreferredProviderTest pp = new PreferredProviderTest(); - pp.RunTest(arch); + pp.RunTest(arch, os); } } - From f9bf9d54618cf4ddd6b94c84400c5fde445064f2 Mon Sep 17 00:00:00 2001 From: Aleksei Efimov Date: Mon, 21 Mar 2016 21:58:50 +0300 Subject: [PATCH 25/36] 8145039: JAXB marshaller fails with ClassCastException on classes generated by xjc Reviewed-by: lancea --- jdk/test/TEST.groups | 3 +- .../bind/xjc/8145039/JaxbMarshallTest.java | 158 ++++++++++++++++++ .../javax/xml/bind/xjc/8145039/testSchema.xsd | 21 +++ 3 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 jdk/test/javax/xml/bind/xjc/8145039/JaxbMarshallTest.java create mode 100644 jdk/test/javax/xml/bind/xjc/8145039/testSchema.xsd diff --git a/jdk/test/TEST.groups b/jdk/test/TEST.groups index 8b3a337c346..96b24c224dc 100644 --- a/jdk/test/TEST.groups +++ b/jdk/test/TEST.groups @@ -494,7 +494,8 @@ needs_jdk = \ sun/reflect/CallerSensitive/MissingCallerSensitive.java \ sun/security/util/Resources/NewNamesFormat.java \ vm/verifier/defaultMethods/DefaultMethodRegressionTestsRun.java \ - javax/xml/ws/clientjar/TestWsImport.java + javax/xml/ws/clientjar/TestWsImport.java \ + javax/xml/bind/xjc/8145039/JaxbMarshallTest.java # JRE adds further tests to compact3 # diff --git a/jdk/test/javax/xml/bind/xjc/8145039/JaxbMarshallTest.java b/jdk/test/javax/xml/bind/xjc/8145039/JaxbMarshallTest.java new file mode 100644 index 00000000000..37b817d0b4d --- /dev/null +++ b/jdk/test/javax/xml/bind/xjc/8145039/JaxbMarshallTest.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2016, 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. + * + * 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. + */ + +/* + * @test + * @bug 8145039 + * @summary Check that marshalling of xjc generated class doesn't throw + * ClassCast exception. + * @modules javax.xml.bind + * @library /lib/testlibrary + * @run testng/othervm JaxbMarshallTest + */ + +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; +import java.util.Arrays; +import java.util.List; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.Marshaller; +import jdk.testlibrary.JDKToolLauncher; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +public class JaxbMarshallTest { + + @BeforeTest + public void setUp() throws IOException { + // Create test directory inside scratch + testWorkDir = Paths.get(System.getProperty("user.dir", ".")); + // Save its URL + testWorkDirUrl = testWorkDir.toUri().toURL(); + // Get test source directory path + testSrcDir = Paths.get(System.getProperty("test.src", ".")); + // Get path of xjc result folder + xjcResultDir = testWorkDir.resolve(TEST_PACKAGE); + // Copy schema document file to scratch directory + Files.copy(testSrcDir.resolve(XSD_FILENAME), testWorkDir.resolve(XSD_FILENAME), REPLACE_EXISTING); + } + + + /* + * Test does the following steps to reproduce problem reported by 8145039: + * 1. Copy test schema to JTREG scratch folder + * 2. Run xjc on test schema file + * 3. Compile generated java files with test javac + * 4. Marshall the new list instance to ensure that + * ClassCastException is not thrown + */ + @Test + public void marshallClassCastExceptionTest() throws Exception { + JAXBContext jaxbContext; + Marshaller marshaller; + URLClassLoader jaxbContextClassLoader; + // Generate java classes by xjc + runXjc(XSD_FILENAME); + // Compile xjc generated java files + compileXjcGeneratedClasses(); + + // Create JAXB context based on xjc generated package. + // Need to create URL class loader ot make compiled classes discoverable + // by JAXB context + jaxbContextClassLoader = URLClassLoader.newInstance(new URL[] {testWorkDirUrl}); + jaxbContext = JAXBContext.newInstance( TEST_PACKAGE, jaxbContextClassLoader); + + // Create instance of Xjc generated data type. + // Java classes were compiled during the test execution hence reflection + // is needed here + Class classLongListClass = jaxbContextClassLoader.loadClass(TEST_CLASS); + Object objectLongListClass = classLongListClass.newInstance(); + // Get 'getIn' method object + Method getInMethod = classLongListClass.getMethod( GET_LIST_METHOD, (Class [])null ); + // Invoke 'getIn' method + List inList = (List)getInMethod.invoke(objectLongListClass); + // Add values into the jaxb object list + inList.add(Long.valueOf(0)); + inList.add(Long.valueOf(43)); + inList.add(Long.valueOf(1000000123)); + + // Marshall constructed complex type variable to standard output. + // In case of failure the ClassCastException will be thrown + marshaller = jaxbContext.createMarshaller(); + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + marshaller.marshal(objectLongListClass, System.out); + } + + // Compile schema file into java classes definitions + void runXjc(String xsdFileName) throws Exception { + // Prepare process builder to run schemagen tool and save its output + JDKToolLauncher xjcLauncher = JDKToolLauncher.createUsingTestJDK("xjc"); + xjcLauncher.addToolArg(xsdFileName); + System.out.println("Executing xjc command: " + Arrays.asList(xjcLauncher.getCommand())); + ProcessBuilder pb = new ProcessBuilder(xjcLauncher.getCommand()); + // Set xjc work directory with the input java file + pb.directory(testWorkDir.toFile()); + pb.inheritIO(); + Process p = pb.start(); + p.waitFor(); + p.destroy(); + } + + // Compile java classes with javac tool + void compileXjcGeneratedClasses() throws Exception { + JDKToolLauncher javacLauncher = JDKToolLauncher.createUsingTestJDK("javac"); + javacLauncher.addToolArg(xjcResultDir.resolve("ObjectFactory.java").toString()); + javacLauncher.addToolArg(xjcResultDir.resolve("TypesLongList.java").toString()); + javacLauncher.addToolArg(xjcResultDir.resolve("package-info.java").toString()); + System.out.println("Compiling xjc generated classes: " + Arrays.asList(javacLauncher.getCommand())); + ProcessBuilder pb = new ProcessBuilder(javacLauncher.getCommand()); + pb.inheritIO(); + pb.directory(testWorkDir.toFile()); + Process p = pb.start(); + p.waitFor(); + p.destroy(); + } + + // Test schema filename + static final String XSD_FILENAME = "testSchema.xsd"; + // Package of java classes generated by xjc + static final String TEST_PACKAGE = "testns_package"; + // Name of generated java class + static final String TEST_CLASS = TEST_PACKAGE+".TypesLongList"; + // Method to get the list from xjc generated class + static final String GET_LIST_METHOD = "getIn"; + // Test working directory + Path testWorkDir; + // Test working directory URL + URL testWorkDirUrl; + // Directory with test src + Path testSrcDir; + // Directory with java files generated by xjc + Path xjcResultDir; +} diff --git a/jdk/test/javax/xml/bind/xjc/8145039/testSchema.xsd b/jdk/test/javax/xml/bind/xjc/8145039/testSchema.xsd new file mode 100644 index 00000000000..f625d0607d0 --- /dev/null +++ b/jdk/test/javax/xml/bind/xjc/8145039/testSchema.xsd @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + From 5abe6e1f23622a2b3f324279265246d9c7f05f74 Mon Sep 17 00:00:00 2001 From: Xueming Shen Date: Mon, 21 Mar 2016 15:59:27 -0700 Subject: [PATCH 26/36] 8152352: Compiling warnings in zip_util.c blocks devkit to build with --with-zlib=system Reviewed-by: naoto --- jdk/src/java.base/share/native/libzip/zip_util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/src/java.base/share/native/libzip/zip_util.c b/jdk/src/java.base/share/native/libzip/zip_util.c index 9ae765b6a55..4837fc81c66 100644 --- a/jdk/src/java.base/share/native/libzip/zip_util.c +++ b/jdk/src/java.base/share/native/libzip/zip_util.c @@ -1408,7 +1408,7 @@ InflateFully(jzfile *zip, jzentry *entry, void *buf, char **msg) case Z_OK: break; case Z_STREAM_END: - if (count != 0 || strm.total_out != entry->size) { + if (count != 0 || strm.total_out != (uInt)entry->size) { *msg = "inflateFully: Unexpected end of stream"; inflateEnd(&strm); return JNI_FALSE; @@ -1528,7 +1528,7 @@ ZIP_InflateFully(void *inBuf, jlong inLen, void *outBuf, jlong outLen, char **pm case Z_OK: break; case Z_STREAM_END: - if (strm.total_out != outLen) { + if (strm.total_out != (uInt)outLen) { *pmsg = "INFLATER_inflateFully: Unexpected end of stream"; inflateEnd(&strm); return JNI_FALSE; From 41786c2118f1472c177b058821972b6602b5c3b5 Mon Sep 17 00:00:00 2001 From: "Tagir F. Valeev" Date: Tue, 22 Mar 2016 16:28:50 +0100 Subject: [PATCH 27/36] 8151123: Collectors.summingDouble/averagingDouble unnecessarily call mapper twice Reviewed-by: psandoz --- .../share/classes/java/util/stream/Collectors.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/util/stream/Collectors.java b/jdk/src/java.base/share/classes/java/util/stream/Collectors.java index 97e05c326ec..da80728f255 100644 --- a/jdk/src/java.base/share/classes/java/util/stream/Collectors.java +++ b/jdk/src/java.base/share/classes/java/util/stream/Collectors.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, 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 @@ -656,8 +656,9 @@ public final class Collectors { */ return new CollectorImpl<>( () -> new double[3], - (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t)); - a[2] += mapper.applyAsDouble(t);}, + (a, t) -> { double val = mapper.applyAsDouble(t); + sumWithCompensation(a, val); + a[2] += val;}, (a, b) -> { sumWithCompensation(a, b[0]); a[2] += b[2]; return sumWithCompensation(a, b[1]); }, @@ -768,7 +769,7 @@ public final class Collectors { */ return new CollectorImpl<>( () -> new double[4], - (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t)); a[2]++; a[3]+= mapper.applyAsDouble(t);}, + (a, t) -> { double val = mapper.applyAsDouble(t); sumWithCompensation(a, val); a[2]++; a[3]+= val;}, (a, b) -> { sumWithCompensation(a, b[0]); sumWithCompensation(a, b[1]); a[2] += b[2]; a[3] += b[3]; return a; }, a -> (a[2] == 0) ? 0.0d : (computeFinalSum(a) / a[2]), CH_NOID); From 89599944c63ef36ca14465dd8a516119cab1ff19 Mon Sep 17 00:00:00 2001 From: "Tagir F. Valeev" Date: Tue, 22 Mar 2016 16:28:52 +0100 Subject: [PATCH 28/36] 8148748: ArrayList.subList().spliterator() is not late-binding Reviewed-by: psandoz --- .../share/classes/java/util/ArrayList.java | 72 ++++++++++++++++++- .../SpliteratorLateBindingFailFastTest.java | 5 +- 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/util/ArrayList.java b/jdk/src/java.base/share/classes/java/util/ArrayList.java index fca4ae228f3..8569de8129f 100644 --- a/jdk/src/java.base/share/classes/java/util/ArrayList.java +++ b/jdk/src/java.base/share/classes/java/util/ArrayList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, 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 @@ -1281,8 +1281,74 @@ public class ArrayList extends AbstractList public Spliterator spliterator() { checkForComodification(); - return new ArrayListSpliterator<>(ArrayList.this, offset, - offset + this.size, this.modCount); + + return new Spliterator<>() { + private int index = offset; // current index, modified on advance/split + private int fence = -1; // -1 until used; then one past last index + private int expectedModCount; // initialized when fence set + + private int getFence() { // initialize fence to size on first use + int hi; // (a specialized variant appears in method forEach) + if ((hi = fence) < 0) { + expectedModCount = modCount; + hi = fence = offset + size; + } + return hi; + } + + public ArrayListSpliterator trySplit() { + int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; + return (lo >= mid) ? null : // divide range in half unless too small + new ArrayListSpliterator<>(ArrayList.this, lo, index = mid, + expectedModCount); + } + + public boolean tryAdvance(Consumer action) { + Objects.requireNonNull(action); + int hi = getFence(), i = index; + if (i < hi) { + index = i + 1; + @SuppressWarnings("unchecked") E e = (E)elementData[i]; + action.accept(e); + if (ArrayList.this.modCount != expectedModCount) + throw new ConcurrentModificationException(); + return true; + } + return false; + } + + public void forEachRemaining(Consumer action) { + Objects.requireNonNull(action); + int i, hi, mc; // hoist accesses and checks from loop + ArrayList lst = ArrayList.this; + Object[] a; + if ((a = lst.elementData) != null) { + if ((hi = fence) < 0) { + mc = modCount; + hi = offset + size; + } + else + mc = expectedModCount; + if ((i = index) >= 0 && (index = hi) <= a.length) { + for (; i < hi; ++i) { + @SuppressWarnings("unchecked") E e = (E) a[i]; + action.accept(e); + } + if (lst.modCount == mc) + return; + } + } + throw new ConcurrentModificationException(); + } + + public long estimateSize() { + return (long) (getFence() - index); + } + + public int characteristics() { + return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED; + } + }; } } diff --git a/jdk/test/java/util/Spliterator/SpliteratorLateBindingFailFastTest.java b/jdk/test/java/util/Spliterator/SpliteratorLateBindingFailFastTest.java index e6180e34b61..dc961b15e5a 100644 --- a/jdk/test/java/util/Spliterator/SpliteratorLateBindingFailFastTest.java +++ b/jdk/test/java/util/Spliterator/SpliteratorLateBindingFailFastTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, 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 @@ -52,6 +52,7 @@ import static org.testng.Assert.*; /** * @test + * @bug 8148748 * @summary Spliterator last-binding and fail-fast tests * @run testng SpliteratorLateBindingFailFastTest */ @@ -120,8 +121,8 @@ public class SpliteratorLateBindingFailFastTest { } void addList(Function, ? extends List> l) { - // @@@ If collection is instance of List then add sub-list tests addCollection(l); + addCollection(l.andThen(list -> list.subList(0, list.size()))); } void addMap(Function, ? extends Map> mapConstructor) { From 81c10514557d1e723f436b2b4809c18b880c8929 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Tue, 22 Mar 2016 15:37:55 -0700 Subject: [PATCH 29/36] 8151957: ObjectInputStream - Use new convenience method for immutable Map creation during static initialization Initialize primClasses primitive type name-to-class mapping using a new Map.of() conveience method. Reviewed-by: lancea, redestad, smarks --- .../classes/java/io/ObjectInputStream.java | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java index 73741eb4bcb..dbf10bd757d 100644 --- a/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java +++ b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, 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 @@ -36,7 +36,7 @@ import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.Arrays; -import java.util.HashMap; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import static java.io.ObjectStreamClass.processQueue; @@ -212,20 +212,20 @@ public class ObjectInputStream /** marker for unshared objects in internal handle table */ private static final Object unsharedMarker = new Object(); - /** table mapping primitive type names to corresponding class objects */ - private static final HashMap> primClasses - = new HashMap<>(8, 1.0F); - static { - primClasses.put("boolean", boolean.class); - primClasses.put("byte", byte.class); - primClasses.put("char", char.class); - primClasses.put("short", short.class); - primClasses.put("int", int.class); - primClasses.put("long", long.class); - primClasses.put("float", float.class); - primClasses.put("double", double.class); - primClasses.put("void", void.class); - } + /** + * immutable table mapping primitive type names to corresponding + * class objects + */ + private static final Map> primClasses = + Map.of("boolean", boolean.class, + "byte", byte.class, + "char", char.class, + "short", short.class, + "int", int.class, + "long", long.class, + "float", float.class, + "double", double.class, + "void", void.class); private static class Caches { /** cache of subclass security audit results */ From 666a2ae49a29c7e0492133ddb876623ca4227ccc Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Wed, 23 Mar 2016 14:54:30 +0530 Subject: [PATCH 30/36] 8152268: jjs tool makefile should use --addmods ALL-SYSTEM Reviewed-by: alanb, hannesw --- jdk/make/launcher/Launcher-jdk.scripting.nashorn.shell.gmk | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/make/launcher/Launcher-jdk.scripting.nashorn.shell.gmk b/jdk/make/launcher/Launcher-jdk.scripting.nashorn.shell.gmk index 4b3049cbc09..3dd56d3a554 100644 --- a/jdk/make/launcher/Launcher-jdk.scripting.nashorn.shell.gmk +++ b/jdk/make/launcher/Launcher-jdk.scripting.nashorn.shell.gmk @@ -27,5 +27,6 @@ include LauncherCommon.gmk $(eval $(call SetupBuildLauncher, jjs, \ MAIN_CLASS := jdk.nashorn.tools.jjs.Main, \ + JAVA_ARGS := -addmods ALL-SYSTEM, \ CFLAGS := -DENABLE_ARG_FILES, \ )) From 5669c583c4f8ab63a1a0fa3f831336652d6ee082 Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Wed, 23 Mar 2016 12:25:08 +0000 Subject: [PATCH 31/36] 8149017: Delayed provider selection broken in RSA client key exchange Reviewed-by: coffeys --- .../security/ssl/RSAClientKeyExchange.java | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/RSAClientKeyExchange.java b/jdk/src/java.base/share/classes/sun/security/ssl/RSAClientKeyExchange.java index b374b8c42d7..7b8387fb684 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/RSAClientKeyExchange.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/RSAClientKeyExchange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, 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 @@ -115,10 +115,31 @@ final class RSAClientKeyExchange extends HandshakeMessage { byte[] encoded = null; try { + boolean needFailover = false; Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1); - boolean needFailover = !KeyUtil.isOracleJCEProvider( - cipher.getProvider().getName()); + try { + // Try UNWRAP_MODE mode firstly. + cipher.init(Cipher.UNWRAP_MODE, privateKey, + new TlsRsaPremasterSecretParameterSpec( + maxVersion.v, currentVersion.v), + generator); + + // The provider selection can be delayed, please don't call + // any Cipher method before the call to Cipher.init(). + needFailover = !KeyUtil.isOracleJCEProvider( + cipher.getProvider().getName()); + } catch (InvalidKeyException | UnsupportedOperationException iue) { + if (debug != null && Debug.isOn("handshake")) { + System.out.println("The Cipher provider " + + cipher.getProvider().getName() + + " caused exception: " + iue.getMessage()); + } + + needFailover = true; + } + if (needFailover) { + // Use DECRYPT_MODE and dispose the previous initialization. cipher.init(Cipher.DECRYPT_MODE, privateKey); boolean failed = false; try { @@ -134,10 +155,7 @@ final class RSAClientKeyExchange extends HandshakeMessage { maxVersion.v, currentVersion.v, encoded, generator); } else { - cipher.init(Cipher.UNWRAP_MODE, privateKey, - new TlsRsaPremasterSecretParameterSpec( - maxVersion.v, currentVersion.v), - generator); + // the cipher should have been initialized preMaster = (SecretKey)cipher.unwrap(encrypted, "TlsRsaPremasterSecret", Cipher.SECRET_KEY); } From 9057c75425963568fc5cb075f12342eeff94bb80 Mon Sep 17 00:00:00 2001 From: Abhijit Roy Date: Wed, 23 Mar 2016 19:57:42 +0530 Subject: [PATCH 32/36] 8151868: Typo in java.time.Instant until(Temporal endExclusive, TemporalUnit unit) Reviewed-by: rriggs, lancea, scolebourne --- jdk/src/java.base/share/classes/java/time/Instant.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/java.base/share/classes/java/time/Instant.java b/jdk/src/java.base/share/classes/java/time/Instant.java index f49c3b7a506..75ed2c32039 100644 --- a/jdk/src/java.base/share/classes/java/time/Instant.java +++ b/jdk/src/java.base/share/classes/java/time/Instant.java @@ -1106,7 +1106,7 @@ public final class Instant * complete units between the two instants. * The {@code Temporal} passed to this method is converted to a * {@code Instant} using {@link #from(TemporalAccessor)}. - * For example, the amount in days between two dates can be calculated + * For example, the amount in seconds between two dates can be calculated * using {@code startInstant.until(endInstant, SECONDS)}. *

    * There are two equivalent ways of using this method. From 734d72b94382af2095b0e0e88a69850e639235cb Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Wed, 23 Mar 2016 09:21:01 -0700 Subject: [PATCH 33/36] 8152197: Single place to specify module-specific information for images build Reviewed-by: alanb, erikj --- jdk/make/gensrc/GensrcModuleLoaderMap.gmk | 100 +--------------------- 1 file changed, 2 insertions(+), 98 deletions(-) diff --git a/jdk/make/gensrc/GensrcModuleLoaderMap.gmk b/jdk/make/gensrc/GensrcModuleLoaderMap.gmk index 7e8fb339f5d..859017d2a6d 100644 --- a/jdk/make/gensrc/GensrcModuleLoaderMap.gmk +++ b/jdk/make/gensrc/GensrcModuleLoaderMap.gmk @@ -25,103 +25,7 @@ include Modules.gmk -BOOT_MODULES := -UPGRADEABLE_MDOULES := -AGGREGATOR_MDOULES := -OTHER_PLATFORM_MODULES := - -# Hook to include the corresponding custom file, if present. -$(eval $(call IncludeCustomExtension, jdk, gensrc/GensrcModuleLoaderMap.gmk)) - -BOOT_MODULES += \ - java.base \ - java.datatransfer \ - java.desktop \ - java.httpclient \ - java.instrument \ - java.logging \ - java.management \ - java.naming \ - java.prefs \ - java.rmi \ - java.security.jgss \ - java.security.sasl \ - java.sql \ - java.xml \ - java.xml.crypto \ - jdk.httpserver \ - jdk.management \ - jdk.sctp \ - jdk.security.auth \ - jdk.security.jgss \ - # - -# to be deprivileged -BOOT_MODULES += \ - java.compiler \ - java.scripting \ - java.sql.rowset \ - java.smartcardio \ - jdk.charsets \ - jdk.naming.rmi \ - # - -UPGRADEABLE_MODULES += \ - java.activation \ - java.annotations.common \ - java.corba \ - java.transaction \ - java.xml.bind \ - java.xml.ws \ - # - -AGGREGATOR_MODULES += \ - java.compact1 \ - java.compact2 \ - java.compact3 \ - java.se \ - java.se.ee \ - # - -OTHER_PLATFORM_MODULES += \ - jdk.accessibility \ - jdk.crypto.ec \ - jdk.crypto.pkcs11 \ - jdk.dynalink \ - jdk.jsobject \ - jdk.xml.dom \ - jdk.localedata \ - jdk.naming.dns \ - jdk.scripting.nashorn \ - jdk.zipfs \ - # - -ifeq ($(OPENJDK_TARGET_OS), macsox) - BOOT_MODULES += jdk.deploy.osx -endif -ifeq ($(OPENJDK_TARGET_OS), windows) - OTHER_PLATFORM_MODULES += jdk.crypto.mscapi -endif -ifeq ($(OPENJDK_TARGET_OS), solaris) - OTHER_PLATFORM_MODULES += jdk.crypto.ucrypto -endif - -# Param 1 - Name of module -define ReadImportMetaData - ifneq ($$(wildcard $(IMPORT_MODULES_MAKE)/$$(strip $1)/build.properties), ) - classloader := - include $(IMPORT_MODULES_MAKE)/$$(strip $1)/build.properties - ifeq ($$(classloader), boot) - BOOT_MODULES += $1 - else ifeq ($$(classloader), ext) - OTHER_PLATFORM_MODULES += $1 - endif - endif -endef - -IMPORTED_MODULES := $(call FindImportedModules) -$(foreach m, $(IMPORTED_MODULES), $(eval $(call ReadImportMetaData, $m))) - +$(eval $(call ReadImportMetaData)) # Replacing double-comma with a single comma is to workaround the issue # with some version of make on windows that doesn't substitute spaces @@ -132,7 +36,7 @@ $(strip \ ) endef BOOT_MODULES_LIST := $(call SubstComma, $(BOOT_MODULES)) -PLATFORM_MODULES_LIST := $(call SubstComma, $(UPGRADEABLE_MODULES) $(AGGREGATOR_MODULES) $(OTHER_PLATFORM_MODULES)) +PLATFORM_MODULES_LIST := $(call SubstComma, $(PLATFORM_MODULES)) VARDEPS_VALUE := $(BOOT_MODULES_LIST) $(PLATFORM_MODULES_LIST) VARDEPS_FILE := $(call DependOnVariable, VARDEPS_VALUE) From 009009ded7e3d8a51f13aecdc12379ed47fba466 Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Wed, 23 Mar 2016 09:23:07 -0700 Subject: [PATCH 34/36] 8152227: Remove jdk.deploy.osx module descriptor Reviewed-by: alanb, redestad --- .../macosx/classes/module-info.java | 30 ------------------- 1 file changed, 30 deletions(-) delete mode 100644 jdk/src/jdk.deploy.osx/macosx/classes/module-info.java diff --git a/jdk/src/jdk.deploy.osx/macosx/classes/module-info.java b/jdk/src/jdk.deploy.osx/macosx/classes/module-info.java deleted file mode 100644 index 024273599c0..00000000000 --- a/jdk/src/jdk.deploy.osx/macosx/classes/module-info.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2014, 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. - */ - -module jdk.deploy.osx { - requires java.desktop; - requires java.scripting; -} - From 48eb2e9ded71ced3fa42740da7551674d7350917 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Wed, 23 Mar 2016 18:24:35 +0100 Subject: [PATCH 35/36] 8151281: Module java.httpclient could use System.Logger instead of PlatformLogger Reviewed-by: mchung, michaelm --- .../share/classes/java/net/http/Log.java | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/Log.java b/jdk/src/java.httpclient/share/classes/java/net/http/Log.java index d696854c5b5..986a8fd1503 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/Log.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/Log.java @@ -24,7 +24,6 @@ package java.net.http; import java.util.Locale; -import sun.util.logging.PlatformLogger; /** * -Djava.net.HttpClient.log=errors,requests,headers,frames[:type:type2:..],content @@ -35,9 +34,11 @@ import sun.util.logging.PlatformLogger; * * Logger name is "java.net.http.HttpClient" */ -class Log { +// implements System.Logger in order to be skipped when printing the caller's +// information +abstract class Log implements System.Logger { - final static String logProp = "java.net.http.HttpClient.log"; + static final String logProp = "java.net.http.HttpClient.log"; public static final int OFF = 0; public static final int ERRORS = 0x1; @@ -55,7 +56,7 @@ class Log { public static final int ALL = CONTROL| DATA | WINDOW_UPDATES; static int frametypes; - static sun.util.logging.PlatformLogger logger; + static final System.Logger logger; static { String s = Utils.getNetProperty(logProp); @@ -111,7 +112,9 @@ class Log { } } if (logging != OFF) { - logger = PlatformLogger.getLogger("java.net.http.HttpClient"); + logger = System.getLogger("java.net.http.HttpClient"); + } else { + logger = null; } } @@ -137,34 +140,38 @@ class Log { static void logError(String s) { if (errors()) - logger.info("ERROR: " + s); + logger.log(Level.INFO, "ERROR: " + s); } static void logError(Throwable t) { if (errors()) { String s = Utils.stackTrace(t); - logger.info("ERROR: " + s); + logger.log(Level.INFO, "ERROR: " + s); } } static void logSSL(String s) { if (ssl()) - logger.info("SSL: " + s); + logger.log(Level.INFO, "SSL: " + s); } static void logRequest(String s) { if (requests()) - logger.info("REQUEST: " + s); + logger.log(Level.INFO, "REQUEST: " + s); } static void logResponse(String s) { if (requests()) - logger.info("RESPONSE: " + s); + logger.log(Level.INFO, "RESPONSE: " + s); } static void logHeaders(String s) { if (headers()) - logger.info("HEADERS: " + s); + logger.log(Level.INFO, "HEADERS: " + s); } + + // not instantiable + private Log() {} + // END HTTP2 } From 315df6c52c5eb264f790f6cb130d9b4192c3964a Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Wed, 23 Mar 2016 17:05:04 -0700 Subject: [PATCH 36/36] 8152143: jlink --include-locales should gracefully detect certain user error Reviewed-by: mchung --- .../plugins/IncludeLocalesPlugin.java | 16 +++-- .../tools/jlink/resources/plugins.properties | 13 +++- .../plugins/IncludeLocalesPluginTest.java | 67 +++++++++++++------ 3 files changed, 70 insertions(+), 26 deletions(-) diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java index c901f052f31..8a37d8c518e 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java @@ -155,9 +155,13 @@ public final class IncludeLocalesPlugin implements TransformerPlugin, ResourcePr @Override public void configure(Map config) { - priorityList = Arrays.stream(config.get(NAME).split(",")) - .map(Locale.LanguageRange::new) - .collect(Collectors.toList()); + try { + priorityList = Arrays.stream(config.get(NAME).split(",")) + .map(Locale.LanguageRange::new) + .collect(Collectors.toList()); + } catch (IllegalArgumentException iae) { + throw new PluginException(iae.getLocalizedMessage()); + } } @Override @@ -168,7 +172,7 @@ public final class IncludeLocalesPlugin implements TransformerPlugin, ResourcePr // jdk.localedata module validation Set packages = module.getAllPackages(); if (!packages.containsAll(LOCALEDATA_PACKAGES)) { - throw new PluginException("Missing locale data packages in jdk.localedata:\n\t" + + throw new PluginException(PluginsResourceBundle.getMessage(NAME + ".missingpackages") + LOCALEDATA_PACKAGES.stream() .filter(pn -> !packages.contains(pn)) .collect(Collectors.joining(",\n\t"))); @@ -186,6 +190,10 @@ public final class IncludeLocalesPlugin implements TransformerPlugin, ResourcePr filtered = filterLocales(available); + if (filtered.isEmpty()) { + throw new PluginException(PluginsResourceBundle.getMessage(NAME + ".nomatchinglocales")); + } + try { String value = META_FILES + filtered.stream() .map(s -> includeLocaleFilePatterns(s)) diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties index b43e0814eb3..0fd33da26b0 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties @@ -68,9 +68,18 @@ zip.argument=[comma separated list of resource paths] zip.description=ZIP Compression -include-locales.argument=[,]* +include-locales.argument=\ +[,]* -include-locales.description=BCP 47 language tags separated by a comma, allowing locale matching\ndefined in RFC 4647. eg: en,ja,*-IN +include-locales.description=\ +BCP 47 language tags separated by a comma, allowing locale matching\n\ +defined in RFC 4647. eg: en,ja,*-IN + +include-locales.missingpackages=\ +Missing locale data packages in jdk.localedata:\n\t + +include-locales.nomatchinglocales=\ +No matching locales found. Check the specified pattern. main.status.ok=Functional. diff --git a/jdk/test/tools/jlink/plugins/IncludeLocalesPluginTest.java b/jdk/test/tools/jlink/plugins/IncludeLocalesPluginTest.java index b29c30fb7ba..26c217eb57a 100644 --- a/jdk/test/tools/jlink/plugins/IncludeLocalesPluginTest.java +++ b/jdk/test/tools/jlink/plugins/IncludeLocalesPluginTest.java @@ -21,26 +21,18 @@ * questions. */ -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.lang.reflect.Layer; -import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import java.util.stream.Stream; import jdk.tools.jlink.plugin.Plugin; +import jdk.tools.jlink.plugin.PluginException; import jdk.tools.jlink.internal.PluginRepository; +import jdk.tools.jlink.internal.TaskHelper; +import jdk.tools.jlink.internal.plugins.PluginsResourceBundle; import tests.Helper; import tests.JImageGenerator; import tests.JImageValidator; +import tests.Result; /* * @test @@ -50,6 +42,7 @@ import tests.JImageValidator; * @modules java.base/jdk.internal.jimage * jdk.jdeps/com.sun.tools.classfile * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jlink.internal.plugins * jdk.jlink/jdk.tools.jmod * jdk.jlink/jdk.tools.jimage * jdk.compiler @@ -65,6 +58,7 @@ public class IncludeLocalesPluginTest { private final static int EXPECTED_LOCATIONS = 1; private final static int UNEXPECTED_PATHS = 2; private final static int AVAILABLE_LOCALES = 3; + private final static int ERROR_MESSAGE = 4; private final static Object[][] testData = { // without --include-locales option: should include all locales @@ -144,6 +138,7 @@ public class IncludeLocalesPluginTest { "yav_CM yo yo_BJ yo_NG zgh zgh_MA zh zh_CN zh_CN_#Hans zh_HK " + "zh_HK_#Hans zh_HK_#Hant zh_MO_#Hans zh_MO_#Hant zh_SG zh_SG_#Hans " + "zh_TW zh_TW_#Hant zh__#Hans zh__#Hant zu zu_ZA", + "", }, // All English/Japanese locales @@ -173,6 +168,7 @@ public class IncludeLocalesPluginTest { "en_PW en_RW en_SB en_SC en_SD en_SG en_SH en_SL en_SS en_SX en_SZ " + "en_TC en_TK en_TO en_TT en_TV en_TZ en_UG en_UM en_US en_US_POSIX " + "en_VC en_VG en_VI en_VU en_WS en_ZA en_ZM en_ZW ja ja_JP ja_JP_JP_#u-ca-japanese", + "", }, // All locales in India @@ -201,6 +197,7 @@ public class IncludeLocalesPluginTest { "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_zh.class"), " as_IN bn_IN bo_IN brx_IN en en_IN en_US en_US_POSIX gu_IN hi_IN kn_IN " + "kok_IN ks_IN_#Arab ml_IN mr_IN ne_IN or_IN pa_IN_#Guru ta_IN te_IN ur_IN", + "", }, // Thai @@ -220,6 +217,7 @@ public class IncludeLocalesPluginTest { "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ja.class", "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_zh.class"), " en en_US en_US_POSIX th th_TH th_TH_TH_#u-nu-thai", + "", }, // Hong Kong @@ -242,6 +240,7 @@ public class IncludeLocalesPluginTest { "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ja.class", "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_th.class"), " en en_US en_US_POSIX zh_HK zh_HK_#Hans zh_HK_#Hant", + "", }, // Norwegian @@ -265,6 +264,7 @@ public class IncludeLocalesPluginTest { "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ja.class", "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_th.class"), " en en_US en_US_POSIX nb nb_NO nb_SJ nn nn_NO no no_NO no_NO_NY", + "", }, // Hebrew/Indonesian/Yiddish @@ -290,6 +290,25 @@ public class IncludeLocalesPluginTest { "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ja.class", "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_th.class"), " en en_US en_US_POSIX in in_ID iw iw_IL ji ji_001", + "", + }, + + // Error case: No matching locales + {"--include-locales=xyz", + null, + null, + null, + new PluginException( + PluginsResourceBundle.getMessage("include-locales.nomatchinglocales")) + .toString(), + }, + + // Error case: Invalid argument + {"--include-locales=zh_HK", + null, + null, + null, + "range=zh_hk", }, }; @@ -304,20 +323,28 @@ public class IncludeLocalesPluginTest { for (Object[] data : testData) { // create image for each test data - Path image = JImageGenerator.getJLinkTask() + Result result = JImageGenerator.getJLinkTask() .modulePath(helper.defaultModulePath()) .output(helper.createNewImageDir(moduleName)) .addMods("jdk.localedata") .option((String)data[INCLUDE_LOCALES_OPTION]) - .call().assertSuccess(); + .call(); - // test locale data entries - testLocaleDataEntries(image, - (List)data[EXPECTED_LOCATIONS], - (List)data[UNEXPECTED_PATHS]); + String errorMsg = (String)data[ERROR_MESSAGE]; + if (errorMsg.isEmpty()) { + Path image = result.assertSuccess(); - // test available locales - testAvailableLocales(image, (String)data[AVAILABLE_LOCALES]); + // test locale data entries + testLocaleDataEntries(image, + (List)data[EXPECTED_LOCATIONS], + (List)data[UNEXPECTED_PATHS]); + + // test available locales + testAvailableLocales(image, (String)data[AVAILABLE_LOCALES]); + } else { + result.assertFailure(new TaskHelper(TaskHelper.JLINK_BUNDLE) + .getMessage("error.prefix") + " " +errorMsg); + } } }