OpenJDK / jdk8u / jdk8u / jdk
changeset 10023:bbece7eab49f
Merge
author | lana |
---|---|
date | Tue, 16 Sep 2014 14:16:55 -0700 |
parents | 25788892a672 2be3555a6a37 |
children | 083041dc0035 |
files | |
diffstat | 29 files changed, 2034 insertions(+), 181 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/classes/javax/management/remote/rmi/RMIConnector.java Tue Sep 16 11:51:52 2014 -0700 +++ b/src/share/classes/javax/management/remote/rmi/RMIConnector.java Tue Sep 16 14:16:55 2014 -0700 @@ -1335,66 +1335,94 @@ int maxNotifications, long timeout) throws IOException, ClassNotFoundException { - IOException org; + boolean retried = false; while (true) { // used for a successful re-connection + // or a transient network problem try { return connection.fetchNotifications(clientSequenceNumber, maxNotifications, - timeout); + timeout); // return normally } catch (IOException ioe) { - org = ioe; + // Examine the chain of exceptions to determine whether this + // is a deserialization issue. If so - we propagate the + // appropriate exception to the caller, who will then + // proceed with fetching notifications one by one + rethrowDeserializationException(ioe); - // inform of IOException try { communicatorAdmin.gotIOException(ioe); + // reconnection OK, back to "while" to do again + } catch (IOException ee) { + boolean toClose = false; - // The connection should be re-established. - continue; - } catch (IOException ee) { - // No more fetch, the Exception will be re-thrown. - break; - } // never reached - } // never reached + synchronized (this) { + if (terminated) { + // the connection is closed. + throw ioe; + } else if (retried) { + toClose = true; + } + } + + if (toClose) { + // JDK-8049303 + // We received an IOException - but the communicatorAdmin + // did not close the connection - possibly because + // the original exception was raised by a transient network + // problem? + // We already know that this exception is not due to a deserialization + // issue as we already took care of that before involving the + // communicatorAdmin. Moreover - we already made one retry attempt + // at fetching the same batch of notifications - and the + // problem persisted. + // Since trying again doesn't seem to solve the issue, we will now + // close the connection. Doing otherwise might cause the + // NotifFetcher thread to die silently. + final Notification failedNotif = + new JMXConnectionNotification( + JMXConnectionNotification.FAILED, + this, + connectionId, + clientNotifSeqNo++, + "Failed to communicate with the server: " + ioe.toString(), + ioe); + + sendNotification(failedNotif); + + try { + close(true); + } catch (Exception e) { + // OK. + // We are closing + } + throw ioe; // the connection is closed here. + } else { + // JDK-8049303 possible transient network problem, + // let's try one more time + retried = true; + } + } + } } + } + private void rethrowDeserializationException(IOException ioe) + throws ClassNotFoundException, IOException { // specially treating for an UnmarshalException - if (org instanceof UnmarshalException) { - UnmarshalException ume = (UnmarshalException)org; - - if (ume.detail instanceof ClassNotFoundException) - throw (ClassNotFoundException) ume.detail; - - /* In Sun's RMI implementation, if a method return - contains an unserializable object, then we get - UnmarshalException wrapping WriteAbortedException - wrapping NotSerializableException. In that case we - extract the NotSerializableException so that our - caller can realize it should try to skip past the - notification that presumably caused it. It's not - certain that every other RMI implementation will - generate this exact exception sequence. If not, we - will not detect that the problem is due to an - unserializable object, and we will stop trying to - receive notifications from the server. It's not - clear we can do much better. */ - if (ume.detail instanceof WriteAbortedException) { - WriteAbortedException wae = - (WriteAbortedException) ume.detail; - if (wae.detail instanceof IOException) - throw (IOException) wae.detail; - } - } else if (org instanceof MarshalException) { + if (ioe instanceof UnmarshalException) { + throw ioe; // the fix of 6937053 made ClientNotifForwarder.fetchNotifs + // fetch one by one with UnmarshalException + } else if (ioe instanceof MarshalException) { // IIOP will throw MarshalException wrapping a NotSerializableException // when a server fails to serialize a response. - MarshalException me = (MarshalException)org; + MarshalException me = (MarshalException)ioe; if (me.detail instanceof NotSerializableException) { throw (NotSerializableException)me.detail; } } - // Not serialization problem, simply re-throw the orginal exception - throw org; + // Not serialization problem, return. } protected Integer addListenerForMBeanRemovedNotif()
--- a/src/share/classes/javax/swing/text/FlowView.java Tue Sep 16 11:51:52 2014 -0700 +++ b/src/share/classes/javax/swing/text/FlowView.java Tue Sep 16 14:16:55 2014 -0700 @@ -800,14 +800,22 @@ @Override protected void forwardUpdate(DocumentEvent.ElementChange ec, DocumentEvent e, Shape a, ViewFactory f) { - calculateUpdateIndexes(e); - // Send update event to all views followed by the changed place. - lastUpdateIndex = Math.max((getViewCount() - 1), 0); - for (int i = firstUpdateIndex; i <= lastUpdateIndex; i++) { - View v = getView(i); - if (v != null) { - Shape childAlloc = getChildAllocation(i, a); - forwardUpdateToView(v, e, childAlloc, f); + // Update the view responsible for the changed element by invocation of + // super method. + super.forwardUpdate(ec, e, a, f); + // Re-calculate the update indexes and update the views followed by + // the changed place. Note: we update the views only when insertion or + // removal takes place. + DocumentEvent.EventType type = e.getType(); + if (type == DocumentEvent.EventType.INSERT || + type == DocumentEvent.EventType.REMOVE) { + firstUpdateIndex = Math.min((lastUpdateIndex + 1), (getViewCount() - 1)); + lastUpdateIndex = Math.max((getViewCount() - 1), 0); + for (int i = firstUpdateIndex; i <= lastUpdateIndex; i++) { + View v = getView(i); + if (v != null) { + v.updateAfterChange(); + } } } }
--- a/src/share/classes/javax/swing/text/GlyphView.java Tue Sep 16 11:51:52 2014 -0700 +++ b/src/share/classes/javax/swing/text/GlyphView.java Tue Sep 16 14:16:55 2014 -0700 @@ -971,6 +971,14 @@ } } + /** {@inheritDoc} */ + @Override + void updateAfterChange() { + // Drop the break spots. They will be re-calculated during + // layout. It is necessary for proper line break calculation. + breakSpots = null; + } + /** * Class to hold data needed to justify this GlyphView in a PargraphView.Row */
--- a/src/share/classes/javax/swing/text/View.java Tue Sep 16 11:51:52 2014 -0700 +++ b/src/share/classes/javax/swing/text/View.java Tue Sep 16 14:16:55 2014 -0700 @@ -1199,6 +1199,13 @@ } /** + * Updates the view to reflect the changes. + */ + void updateAfterChange() { + // Do nothing by default. Should be overridden in subclasses, if any. + } + + /** * Forwards the <code>DocumentEvent</code> to the give child view. This * simply messages the view with a call to <code>insertUpdate</code>, * <code>removeUpdate</code>, or <code>changedUpdate</code> depending
--- a/src/share/classes/sun/awt/SunToolkit.java Tue Sep 16 11:51:52 2014 -0700 +++ b/src/share/classes/sun/awt/SunToolkit.java Tue Sep 16 14:16:55 2014 -0700 @@ -386,7 +386,7 @@ * null or the target can't be found, a null with be returned. */ public static AppContext targetToAppContext(Object target) { - if (target == null || GraphicsEnvironment.isHeadless()) { + if (target == null) { return null; } AppContext context = getAppContext(target); @@ -460,12 +460,10 @@ * via targetToAppContext() above. */ public static void insertTargetMapping(Object target, AppContext appContext) { - if (!GraphicsEnvironment.isHeadless()) { - if (!setAppContext(target, appContext)) { - // Target is not a Component/MenuComponent, use the private Map - // instead. - appContextMap.put(target, appContext); - } + if (!setAppContext(target, appContext)) { + // Target is not a Component/MenuComponent, use the private Map + // instead. + appContextMap.put(target, appContext); } }
--- a/src/share/classes/sun/security/ssl/Handshaker.java Tue Sep 16 11:51:52 2014 -0700 +++ b/src/share/classes/sun/security/ssl/Handshaker.java Tue Sep 16 14:16:55 2014 -0700 @@ -656,8 +656,15 @@ */ ProtocolList getActiveProtocols() { if (activeProtocols == null) { + boolean enabledSSL20Hello = false; ArrayList<ProtocolVersion> protocols = new ArrayList<>(4); for (ProtocolVersion protocol : enabledProtocols.collection()) { + // Need not to check the SSL20Hello protocol. + if (protocol.v == ProtocolVersion.SSL20Hello.v) { + enabledSSL20Hello = true; + continue; + } + boolean found = false; for (CipherSuite suite : enabledCipherSuites.collection()) { if (suite.isAvailable() && suite.obsoleted > protocol.v && @@ -684,6 +691,11 @@ "No available cipher suite for " + protocol); } } + + if (!protocols.isEmpty() && enabledSSL20Hello) { + protocols.add(ProtocolVersion.SSL20Hello); + } + activeProtocols = new ProtocolList(protocols); }
--- a/src/solaris/classes/sun/java2d/xr/XRSolidSrcPict.java Tue Sep 16 11:51:52 2014 -0700 +++ b/src/solaris/classes/sun/java2d/xr/XRSolidSrcPict.java Tue Sep 16 14:16:55 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -31,12 +31,14 @@ XRSurfaceData srcPict; XRColor xrCol; - int curPixVal = -1; + int curPixVal; public XRSolidSrcPict(XRBackend con, int parentXid) { this.con = con; xrCol = new XRColor(); + curPixVal = 0xFF000000; + int solidPixmap = con.createPixmap(parentXid, 32, 1, 1); int solidSrcPictXID = con.createPicture(solidPixmap, XRUtils.PictStandardARGB32); con.setPictureRepeat(solidSrcPictXID, XRUtils.RepeatNormal);
--- a/src/windows/native/java/net/NetworkInterface.c Tue Sep 16 11:51:52 2014 -0700 +++ b/src/windows/native/java/net/NetworkInterface.c Tue Sep 16 14:16:55 2014 -0700 @@ -1014,9 +1014,11 @@ case MIB_IF_TYPE_FDDI: case IF_TYPE_IEEE80211: len = ifRowP->dwPhysAddrLen; - ret = (*env)->NewByteArray(env, len); - if (!IS_NULL(ret)) { - (*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *) ifRowP->bPhysAddr); + if (len > 0) { + ret = (*env)->NewByteArray(env, len); + if (!IS_NULL(ret)) { + (*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *) ifRowP->bPhysAddr); + } } break; }
--- a/test/TEST.groups Tue Sep 16 11:51:52 2014 -0700 +++ b/test/TEST.groups Tue Sep 16 14:16:55 2014 -0700 @@ -124,15 +124,27 @@ jdk_security3 = \ javax/security \ + -javax/security/auth/kerberos \ com/sun/security \ + -com/sun/security/jgss \ com/sun/org/apache/xml/internal/security \ sun/security \ + -sun/security/krb5 \ + -sun/security/jgss \ + javax/net \ lib/security +jdk_security4 = \ + com/sun/security/jgss \ + javax/security/auth/kerberos \ + sun/security/krb5 \ + sun/security/jgss + jdk_security = \ :jdk_security1 \ :jdk_security2 \ - :jdk_security3 + :jdk_security3 \ + :jdk_security4 jdk_text = \ java/text \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/awt/Graphics2D/WhiteTextColorTest.java Tue Sep 16 14:16:55 2014 -0700 @@ -0,0 +1,76 @@ +/* + * 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. + * + * 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 java.awt.*; +import java.awt.image.*; +import javax.swing.*; + +/** + * @test + * @bug 8056009 + * @summary tests whether Graphics.setColor-calls with Color.white are ignored directly + * after pipeline initialization for a certain set of operations. + * @author ceisserer + */ +public class WhiteTextColorTest extends Frame { + public static volatile boolean success = false; + + public WhiteTextColorTest() { + Image dstImg = getGraphicsConfiguration() + .createCompatibleVolatileImage(30, 20); + Graphics g = dstImg.getGraphics(); + + g.setColor(Color.BLACK); + g.fillRect(0, 0, dstImg.getWidth(null), dstImg.getHeight(null)); + g.setColor(Color.WHITE); + g.drawString("Test", 0, 15); + + BufferedImage readBackImg = new BufferedImage(dstImg.getWidth(null), + dstImg.getHeight(null), BufferedImage.TYPE_INT_RGB); + readBackImg.getGraphics().drawImage(dstImg, 0, 0, null); + + for (int x = 0; x < readBackImg.getWidth(); x++) { + for (int y = 0; y < readBackImg.getHeight(); y++) { + int pixel = readBackImg.getRGB(x, y); + + // In case a single white pixel is found, the + // setColor(Color.WHITE) + // call before was not ignored and the bug is not present + if (pixel == 0xFFFFFFFF) { + return; + } + } + } + + throw new RuntimeException("Test Failed"); + } + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + new WhiteTextColorTest(); + } + }); + } +} +
--- a/test/java/lang/instrument/NMTHelper.java Tue Sep 16 11:51:52 2014 -0700 +++ b/test/java/lang/instrument/NMTHelper.java Tue Sep 16 14:16:55 2014 -0700 @@ -21,8 +21,12 @@ * questions. */ +import java.io.File; +import java.io.FileWriter; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.Arrays; +import java.util.stream.Collectors; import sun.management.ManagementFactoryHelper; import com.sun.management.DiagnosticCommandMBean; @@ -32,8 +36,8 @@ executeDcmd("vmNativeMemory", "baseline"); } - // Total: reserved=3484685KB +293KB, committed=266629KB +293KB - private static Pattern totalLine = Pattern.compile("^Total: reserved=\\d+KB .*KB, committed=\\d+KB (.*)KB$"); + // Total: reserved=3484685KB +293KB, committed=266629KB +293KB + private static Pattern totalLine = Pattern.compile("^Total: reserved=\\d+KB .*KB, committed=\\d+KB (.*)KB$"); public static long committedDiff() throws Exception { String res = (String) executeDcmd("vmNativeMemory", "detail.diff"); @@ -53,14 +57,14 @@ Object[] dcmdArgs = {args}; String[] signature = {String[].class.getName()}; - try { - System.out.print("> " + cmd + " "); - for (String s : args) { - System.out.print(s + " "); - } - System.out.println(":"); + String cmdString = cmd + " " + + Arrays.stream(args).collect(Collectors.joining(" ")); + File f = new File("dcmdoutput-" + cmd + "-" + System.currentTimeMillis() + ".txt"); + System.out.println("Output from Dcmd '" + cmdString + "' is being written to file " + f); + try (FileWriter fw = new FileWriter(f)) { + fw.write("> " + cmdString + ":"); String result = (String) dcmd.invoke(cmd, dcmdArgs, signature); - System.out.println(result); + fw.write(result); return result; } catch(Exception ex) { ex.printStackTrace();
--- a/test/java/lang/instrument/RedefineBigClass.sh Tue Sep 16 11:51:52 2014 -0700 +++ b/test/java/lang/instrument/RedefineBigClass.sh Tue Sep 16 14:16:55 2014 -0700 @@ -27,7 +27,7 @@ # @author Daniel D. Daugherty # # @run shell MakeJAR3.sh RedefineBigClassAgent 'Can-Redefine-Classes: true' -# @run build BigClass RedefineBigClassApp +# @run build BigClass RedefineBigClassApp NMTHelper # @run shell/timeout=600 RedefineBigClass.sh #
--- a/test/java/lang/instrument/RetransformBigClass.sh Tue Sep 16 11:51:52 2014 -0700 +++ b/test/java/lang/instrument/RetransformBigClass.sh Tue Sep 16 14:16:55 2014 -0700 @@ -27,7 +27,7 @@ # @author Daniel D. Daugherty # # @run shell MakeJAR4.sh RetransformBigClassAgent SimpleIdentityTransformer 'Can-Retransform-Classes: true' -# @run build BigClass RetransformBigClassApp +# @run build BigClass RetransformBigClassApp NMTHelper # @run shell/timeout=600 RetransformBigClass.sh #
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/invoke/LFCaching/LFCachingTestCase.java Tue Sep 16 14:16:55 2014 -0700 @@ -0,0 +1,78 @@ +/* + * 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. + * + * 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 java.lang.invoke.MethodHandle; +import java.lang.reflect.InvocationTargetException; + +/** + * Abstract class for lambda forms caching testing. + * + * @author kshefov + */ +public abstract class LFCachingTestCase extends LambdaFormTestCase { + + /** + * Constructor for lambda forms caching test case. + * + * @param testMethod A method from {@code j.l.i.MethodHandles} class that + * returns a {@code j.l.i.MethodHandle} instance. + */ + protected LFCachingTestCase(TestMethods testMethod) { + super(testMethod); + } + + /** + * Checks that the lambda forms of the two adapter method handles adapter1 + * and adapter2 are the same. + * + * @param adapter1 First method handle. + * @param adapter2 Second method handle. + */ + public void checkLFCaching(MethodHandle adapter1, MethodHandle adapter2) { + try { + + if (!adapter1.type().equals(adapter2.type())) { + throw new Error("TESTBUG: Types of the two method handles are not the same"); + } + + Object lambdaForm0 = LambdaFormTestCase.INTERNAL_FORM.invoke(adapter1); + Object lambdaForm1 = LambdaFormTestCase.INTERNAL_FORM.invoke(adapter2); + + if (lambdaForm0 == null || lambdaForm1 == null) { + throw new Error("Unexpected error: One or both lambda forms of the method handles are null"); + } + + if (lambdaForm0 != lambdaForm1) { + System.err.println("Lambda form 0 toString is:"); + System.err.println(lambdaForm0); + System.err.println("Lambda form 1 toString is:"); + System.err.println(lambdaForm1); + throw new AssertionError("Error: Lambda forms of the two method handles" + + " are not the same. LF cahing does not work"); + } + } catch (IllegalAccessException | IllegalArgumentException | + SecurityException | InvocationTargetException ex) { + throw new Error("Unexpected exception: ", ex); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/invoke/LFCaching/LFGarbageCollectedTest.java Tue Sep 16 14:16:55 2014 -0700 @@ -0,0 +1,102 @@ +/* + * 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. + * + * 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 LFGarbageCollectedTest + * @bug 8046703 + * @summary Test verifies that lambda forms are garbage collected + * @author kshefov + * @library /lib/testlibrary/jsr292 /lib/testlibrary + * @build TestMethods + * @build LambdaFormTestCase + * @build LFGarbageCollectedTest + * @run main/othervm/timeout=600 -Djava.lang.invoke.MethodHandle.USE_LF_EDITOR=true -DtestLimit=150 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI LFGarbageCollectedTest + */ + +import java.lang.invoke.MethodHandle; +import java.lang.ref.PhantomReference; +import java.lang.ref.ReferenceQueue; +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.Map; + +/** + * Lambda forms garbage collection test class. + */ +public final class LFGarbageCollectedTest extends LambdaFormTestCase { + + /** + * Constructor for a lambda forms garbage collection test case. + * + * @param testMethod A method from {@code j.l.i.MethodHandles} class that + * returns a {@code j.l.i.MethodHandle} instance. + */ + public LFGarbageCollectedTest(TestMethods testMethod) { + super(testMethod); + } + + @Override + public void doTest() { + try { + Map<String, Object> data = getTestMethod().getTestCaseData(); + MethodHandle adapter; + try { + adapter = getTestMethod().getTestCaseMH(data, TestMethods.Kind.ONE); + } catch (NoSuchMethodException ex) { + throw new Error("Unexpected exception: ", ex); + } + Object lambdaForm = LambdaFormTestCase.INTERNAL_FORM.invoke(adapter); + if (lambdaForm == null) { + throw new Error("Unexpected error: Lambda form of the method handle is null"); + } + ReferenceQueue rq = new ReferenceQueue(); + PhantomReference ph = new PhantomReference(lambdaForm, rq); + lambdaForm = null; + data = null; + adapter = null; + for (int i = 0; i < 1000 && !ph.isEnqueued(); i++) { + System.gc(); + } + if (!ph.isEnqueued()) { + throw new AssertionError("Error: Lambda form is not garbage collected"); + } + } catch (IllegalAccessException | IllegalArgumentException | + InvocationTargetException ex) { + throw new Error("Unexpected exception: ", ex); + } + } + + /** + * Main routine for lambda forms garbage collection test. + * + * @param args Accepts no arguments. + */ + public static void main(String[] args) { + // The "identity" and "constant" methods should be removed from this test, + // because their lambda forms are stored in a static filed and are not GC'ed. + // There can be only 5 such LFs for each method, so no memory leak happens. + EnumSet<TestMethods> testMethods = EnumSet.complementOf(EnumSet.of(TestMethods.IDENTITY, TestMethods.CONSTANT)); + LambdaFormTestCase.runTests(LFGarbageCollectedTest::new, testMethods); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java Tue Sep 16 14:16:55 2014 -0700 @@ -0,0 +1,111 @@ +/* + * 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. + * + * 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 LFMultiThreadCachingTest + * @bug 8046703 + * @summary Test verifies that lambda forms are cached when run with multiple threads + * @author kshefov + * @library /lib/testlibrary/jsr292 /lib/testlibrary + * @build TestMethods + * @build LambdaFormTestCase + * @build LFCachingTestCase + * @build LFMultiThreadCachingTest + * @run main/othervm/timeout=300 -Djava.lang.invoke.MethodHandle.USE_LF_EDITOR=true LFMultiThreadCachingTest + */ + +import java.lang.invoke.MethodHandle; +import java.util.EnumSet; +import java.util.Map; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.CyclicBarrier; + +/** + * Multiple threaded lambda forms caching test class. + */ +public final class LFMultiThreadCachingTest extends LFCachingTestCase { + private static final TestMethods.Kind[] KINDS; + static { + EnumSet<TestMethods.Kind> set = EnumSet.complementOf(EnumSet.of(TestMethods.Kind.EXCEPT)); + KINDS = set.toArray(new TestMethods.Kind[set.size()]); + if (KINDS.length < 2) { + throw new Error("TESTBUG: KINDS.length[" + KINDS.length + "] should be at least 2"); + } + } + private static final int CORES = Math.max(KINDS.length, Runtime.getRuntime().availableProcessors()); + + /** + * Constructor a for multiple threaded lambda forms caching test case. + * + * @param testMethod A method from {@code j.l.i.MethodHandles} class that + * returns a {@code j.l.i.MethodHandle} instance. + */ + public LFMultiThreadCachingTest(TestMethods testMethod) { + super(testMethod); + } + + @Override + public void doTest() { + Map<String, Object> data = getTestMethod().getTestCaseData(); + ConcurrentLinkedQueue<MethodHandle> adapters = new ConcurrentLinkedQueue<>(); + CyclicBarrier begin = new CyclicBarrier(CORES); + CountDownLatch end = new CountDownLatch(CORES); + for (int i = 0; i < CORES; ++i) { + TestMethods.Kind kind = KINDS[i % KINDS.length]; + new Thread(() -> { + try { + begin.await(); + adapters.add(getTestMethod().getTestCaseMH(data, kind)); + } catch (InterruptedException | BrokenBarrierException | IllegalAccessException | NoSuchMethodException ex) { + throw new Error("Unexpected exception: ", ex); + } finally { + end.countDown(); + } + }).start(); + } + try { + end.await(); + } catch (InterruptedException ex) { + throw new Error("Unexpected exception: ", ex); + } + if (adapters.size() < CORES) { + throw new Error("adapters size[" + adapters.size() + "] is less than " + CORES); + } + MethodHandle prev = adapters.poll(); + for (MethodHandle current : adapters) { + checkLFCaching(prev, current); + prev = current; + } + } + + /** + * Main routine for multiple threaded lambda forms caching test. + * + * @param args Accepts no arguments. + */ + public static void main(String[] args) { + LambdaFormTestCase.runTests(LFMultiThreadCachingTest::new, EnumSet.allOf(TestMethods.class)); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java Tue Sep 16 14:16:55 2014 -0700 @@ -0,0 +1,78 @@ +/* + * 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. + * + * 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 LFSingleThreadCachingTest + * @bug 8046703 + * @summary Test verifies that lambda forms are cached when run with single thread + * @author kshefov + * @library /lib/testlibrary/jsr292 /lib/testlibrary + * @build TestMethods + * @build LambdaFormTestCase + * @build LFCachingTestCase + * @build LFSingleThreadCachingTest + * @run main/othervm/timeout=300 -Djava.lang.invoke.MethodHandle.USE_LF_EDITOR=true LFSingleThreadCachingTest + */ + +import java.lang.invoke.MethodHandle; +import java.util.EnumSet; +import java.util.Map; + +/** + * Single threaded lambda forms caching test class. + */ +public final class LFSingleThreadCachingTest extends LFCachingTestCase { + + /** + * Constructor for a single threaded lambda forms caching test case. + * + * @param testMethod A method from {@code j.l.i.MethodHandles} class that + * returns a {@code j.l.i.MethodHandle} instance. + */ + public LFSingleThreadCachingTest(TestMethods testMethod) { + super(testMethod); + } + + @Override + public void doTest() { + MethodHandle adapter1; + MethodHandle adapter2; + Map<String, Object> data = getTestMethod().getTestCaseData(); + try { + adapter1 = getTestMethod().getTestCaseMH(data, TestMethods.Kind.ONE); + adapter2 = getTestMethod().getTestCaseMH(data, TestMethods.Kind.TWO); + } catch (NoSuchMethodException | IllegalAccessException ex) { + throw new Error("Unexpected exception: ", ex); + } + checkLFCaching(adapter1, adapter2); + } + + /** + * Main routine for single threaded lambda forms caching test. + * + * @param args Accepts no arguments. + */ + public static void main(String[] args) { + LambdaFormTestCase.runTests(LFSingleThreadCachingTest::new, EnumSet.allOf(TestMethods.class)); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/invoke/LFCaching/LambdaFormTestCase.java Tue Sep 16 14:16:55 2014 -0700 @@ -0,0 +1,117 @@ +/* + * 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. + * + * 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 com.oracle.testlibrary.jsr292.Helper; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.function.Function; + +/** + * Lambda forms caching test case class. Contains all necessary test routines to + * test lambda forms caching in method handles returned by methods of + * MethodHandles class. + * + * @author kshefov + */ +public abstract class LambdaFormTestCase { + + private final static String METHOD_HANDLE_CLASS_NAME = "java.lang.invoke.MethodHandle"; + private final static String INTERNAL_FORM_METHOD_NAME = "internalForm"; + + /** + * Reflection link to {@code j.l.i.MethodHandle.internalForm} method. It is + * used to get a lambda form from a method handle. + */ + protected final static Method INTERNAL_FORM; + + static { + try { + Class mhClass = Class.forName(METHOD_HANDLE_CLASS_NAME); + INTERNAL_FORM = mhClass.getDeclaredMethod(INTERNAL_FORM_METHOD_NAME); + INTERNAL_FORM.setAccessible(true); + } catch (Exception ex) { + throw new Error("Unexpected exception: ", ex); + } + } + + private final TestMethods testMethod; + + /** + * Test case constructor. Generates test cases with random method types for + * given methods form {@code j.l.i.MethodHandles} class. + * + * @param testMethod A method from {@code j.l.i.MethodHandles} class which + * returns a {@code j.l.i.MethodHandle}. + */ + protected LambdaFormTestCase(TestMethods testMethod) { + this.testMethod = testMethod; + } + + public TestMethods getTestMethod() { + return testMethod; + } + + /** + * Routine that executes a test case. + */ + public abstract void doTest(); + + /** + * Runs a number of test cases defined by the size of testCases list. + * + * @param ctor constructor of LambdaFormCachingTest or its child classes + * object. + * @param testMethods list of test methods + */ + public static void runTests(Function<TestMethods, LambdaFormTestCase> ctor, Collection<TestMethods> testMethods) { + boolean passed = true; + int testCounter = 0; + int failCounter = 0; + long iterations = Math.max(1, Helper.TEST_LIMIT / testMethods.size()); + for (long i = 0; i < iterations; i++) { + System.err.println(String.format("Iteration %d:", i)); + for (TestMethods testMethod : testMethods) { + LambdaFormTestCase testCase = ctor.apply(testMethod); + try { + System.err.printf("Tested LF caching feature with MethodHandles.%s method.%n", + testCase.getTestMethod().name); + testCase.doTest(); + System.err.println("PASSED"); + } catch (Throwable t) { + t.printStackTrace(); + System.err.println("FAILED"); + passed = false; + failCounter++; + } + testCounter++; + } + } + if (!passed) { + throw new Error(String.format("%d of %d test cases FAILED! %n" + + "Rerun the test with the same \"-Dseed=\" option as in the log file!", + failCounter, testCounter)); + } else { + System.err.println(String.format("All %d test cases PASSED!", testCounter)); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/invoke/LFCaching/TestMethods.java Tue Sep 16 14:16:55 2014 -0700 @@ -0,0 +1,698 @@ +/* + * 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. + * + * 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 com.oracle.testlibrary.jsr292.Helper; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Enumeration containing information about methods from + * {@code j.l.i.MethodHandles} class that are used for testing lambda forms + * caching. + * + * @author kshefov + */ +public enum TestMethods { + + FOLD_ARGUMENTS("foldArguments") { + @Override + public Map<String, Object> getTestCaseData() { + Map<String, Object> data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int modifierMHArgNum = Helper.RNG.nextInt(realArity + 1); + data.put("modifierMHArgNum", modifierMHArgNum); + Class<?> combinerReturnType; + if (realArity == 0) { + combinerReturnType = void.class; + } else { + combinerReturnType = Helper.RNG.nextBoolean() ? void.class : mtTarget.parameterType(0); + } + data.put("combinerReturnType", combinerReturnType); + return data; + } + + @Override + protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + Class<?> combinerReturnType = (Class) data.get("combinerReturnType"); + int modifierMHArgNum = (int) data.get("modifierMHArgNum"); + MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), kind); + Class<?> rType = mtTarget.returnType(); + int combListStart = (combinerReturnType == void.class) ? 0 : 1; + if (modifierMHArgNum < combListStart) { + modifierMHArgNum = combListStart; + } + MethodHandle combiner = TestMethods.methodHandleGenerator(combinerReturnType, + mtTarget.parameterList().subList(combListStart, + modifierMHArgNum), kind); + return MethodHandles.foldArguments(target, combiner); + } + }, + DROP_ARGUMENTS("dropArguments") { + @Override + public Map<String, Object> getTestCaseData() { + Map<String, Object> data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int dropArgsPos = Helper.RNG.nextInt(realArity + 1); + data.put("dropArgsPos", dropArgsPos); + MethodType mtDropArgs = TestMethods.randomMethodTypeGenerator( + Helper.RNG.nextInt(Helper.MAX_ARITY - realArity)); + data.put("mtDropArgs", mtDropArgs); + return data; + } + + @Override + protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + MethodType mtDropArgs = (MethodType) data.get("mtDropArgs"); + int dropArgsPos = (int) data.get("dropArgsPos"); + MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), kind); + int mtTgtSlotsCount = TestMethods.argSlotsCount(mtTarget); + int mtDASlotsCount = TestMethods.argSlotsCount(mtDropArgs); + List<Class<?>> fakeParList; + if (mtTgtSlotsCount + mtDASlotsCount > Helper.MAX_ARITY - 1) { + fakeParList = TestMethods.reduceArgListToSlotsCount(mtDropArgs.parameterList(), + Helper.MAX_ARITY - mtTgtSlotsCount - 1); + } else { + fakeParList = mtDropArgs.parameterList(); + } + return MethodHandles.dropArguments(target, dropArgsPos, fakeParList); + } + }, + EXPLICIT_CAST_ARGUMENTS("explicitCastArguments") { + @Override + public Map<String, Object> getTestCaseData() { + Map<String, Object> data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY / 2); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + MethodType mtExcplCastArgs = TestMethods.randomMethodTypeGenerator(realArity); + if (mtTarget.returnType() == void.class) { + mtExcplCastArgs = MethodType.methodType(void.class, + mtExcplCastArgs.parameterArray()); + } + if (mtExcplCastArgs.returnType() == void.class) { + mtExcplCastArgs = MethodType.methodType(mtTarget.returnType(), + mtExcplCastArgs.parameterArray()); + } + data.put("mtExcplCastArgs", mtExcplCastArgs); + return data; + } + + @Override + protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + MethodType mtExcplCastArgs = (MethodType) data.get("mtExcplCastArgs"); + MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), kind); + return MethodHandles.explicitCastArguments(target, mtExcplCastArgs); + } + }, + FILTER_ARGUMENTS("filterArguments") { + @Override + public Map<String, Object> getTestCaseData() { + Map<String, Object> data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY / 2); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int filterArgsPos = Helper.RNG.nextInt(realArity + 1); + data.put("filterArgsPos", filterArgsPos); + int filtersArgsArrayLength = Helper.RNG.nextInt(realArity + 1 - filterArgsPos); + data.put("filtersArgsArrayLength", filtersArgsArrayLength); + MethodType mtFilter = TestMethods.randomMethodTypeGenerator(filtersArgsArrayLength); + data.put("mtFilter", mtFilter); + return data; + } + + @Override + protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + MethodType mtFilter = (MethodType) data.get("mtFilter"); + int filterArgsPos = (int) data.get("filterArgsPos"); + int filtersArgsArrayLength = (int) data.get("filtersArgsArrayLength"); + MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), kind); + MethodHandle[] filters = new MethodHandle[filtersArgsArrayLength]; + for (int i = 0; i < filtersArgsArrayLength; i++) { + filters[i] = TestMethods.filterGenerator(mtFilter.parameterType(i), + mtTarget.parameterType(filterArgsPos + i), kind); + } + return MethodHandles.filterArguments(target, filterArgsPos, filters); + } + }, + FILTER_RETURN_VALUE("filterReturnValue") { + @Override + public Map<String, Object> getTestCaseData() { + Map<String, Object> data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int filterArgsPos = Helper.RNG.nextInt(realArity + 1); + int filtersArgsArrayLength = Helper.RNG.nextInt(realArity + 1 - filterArgsPos); + MethodType mtFilter = TestMethods.randomMethodTypeGenerator(filtersArgsArrayLength); + data.put("mtFilter", mtFilter); + return data; + } + + @Override + protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + MethodType mtFilter = (MethodType) data.get("mtFilter"); + MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), kind); + MethodHandle filter = TestMethods.filterGenerator(mtTarget.returnType(), + mtFilter.returnType(), kind); + return MethodHandles.filterReturnValue(target, filter); + } + }, + INSERT_ARGUMENTS("insertArguments") { + @Override + public Map<String, Object> getTestCaseData() { + Map<String, Object> data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int insertArgsPos = Helper.RNG.nextInt(realArity + 1); + data.put("insertArgsPos", insertArgsPos); + int insertArgsArrayLength = Helper.RNG.nextInt(realArity + 1 - insertArgsPos); + MethodType mtInsertArgs = MethodType.methodType(void.class, mtTarget.parameterList() + .subList(insertArgsPos, insertArgsPos + insertArgsArrayLength)); + data.put("mtInsertArgs", mtInsertArgs); + return data; + } + + @Override + protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + MethodType mtInsertArgs = (MethodType) data.get("mtInsertArgs"); + int insertArgsPos = (int) data.get("insertArgsPos"); + MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), kind); + Object[] insertList = Helper.randomArgs(mtInsertArgs.parameterList()); + return MethodHandles.insertArguments(target, insertArgsPos, insertList); + } + }, + PERMUTE_ARGUMENTS("permuteArguments") { + @Override + public Map<String, Object> getTestCaseData() { + Map<String, Object> data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY / 2); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int[] permuteArgsReorderArray = new int[realArity]; + int mtParmuteArgsNum = Helper.RNG.nextInt(Helper.MAX_ARITY); + mtParmuteArgsNum = mtParmuteArgsNum == 0 ? 1 : mtParmuteArgsNum; + MethodType mtPermuteArgs = TestMethods.randomMethodTypeGenerator(mtParmuteArgsNum); + mtTarget = mtTarget.changeReturnType(mtPermuteArgs.returnType()); + for (int i = 0; i < realArity; i++) { + int mtPermuteArgsParNum = Helper.RNG.nextInt(mtPermuteArgs.parameterCount()); + permuteArgsReorderArray[i] = mtPermuteArgsParNum; + mtTarget = mtTarget.changeParameterType( + i, mtPermuteArgs.parameterType(mtPermuteArgsParNum)); + } + data.put("mtTarget", mtTarget); + data.put("permuteArgsReorderArray", permuteArgsReorderArray); + data.put("mtPermuteArgs", mtPermuteArgs); + return data; + } + + @Override + protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + MethodType mtPermuteArgs = (MethodType) data.get("mtPermuteArgs"); + int[] permuteArgsReorderArray = (int[]) data.get("permuteArgsReorderArray"); + MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), kind); + return MethodHandles.permuteArguments(target, mtPermuteArgs, permuteArgsReorderArray); + } + }, + THROW_EXCEPTION("throwException") { + @Override + public Map<String, Object> getTestCaseData() { + Map<String, Object> data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + return data; + } + + @Override + protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + Class<?> rType = mtTarget.returnType(); + return MethodHandles.throwException(rType, Exception.class + ); + } + }, + GUARD_WITH_TEST("guardWithTest") { + @Override + public Map<String, Object> getTestCaseData() { + Map<String, Object> data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int modifierMHArgNum = Helper.RNG.nextInt(realArity + 1); + data.put("modifierMHArgNum", modifierMHArgNum); + return data; + } + + @Override + protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + int modifierMHArgNum = (int) data.get("modifierMHArgNum"); + TestMethods.Kind targetKind; + TestMethods.Kind fallbackKind; + if (kind.equals(TestMethods.Kind.ONE)) { + targetKind = TestMethods.Kind.ONE; + fallbackKind = TestMethods.Kind.TWO; + } else { + targetKind = TestMethods.Kind.TWO; + fallbackKind = TestMethods.Kind.ONE; + } + MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), targetKind); + MethodHandle fallback = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), fallbackKind); + MethodHandle test = TestMethods.methodHandleGenerator(boolean.class, + mtTarget.parameterList().subList(0, modifierMHArgNum), kind); + return MethodHandles.guardWithTest(test, target, fallback); + } + }, + CATCH_EXCEPTION("catchException") { + @Override + public Map<String, Object> getTestCaseData() { + Map<String, Object> data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int modifierMHArgNum = Helper.RNG.nextInt(realArity + 1); + data.put("modifierMHArgNum", modifierMHArgNum); + return data; + } + + @Override + protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + int modifierMHArgNum = (int) data.get("modifierMHArgNum"); + MethodHandle target; + if (kind.equals(TestMethods.Kind.ONE)) { + target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), TestMethods.Kind.ONE); + } else { + target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), TestMethods.Kind.EXCEPT); + } + List<Class<?>> handlerParamList = new ArrayList<>(mtTarget.parameterCount() + 1); + handlerParamList.add(Exception.class); + handlerParamList.addAll(mtTarget.parameterList().subList(0, modifierMHArgNum)); + MethodHandle handler = TestMethods.methodHandleGenerator( + mtTarget.returnType(), handlerParamList, TestMethods.Kind.TWO); + return MethodHandles.catchException(target, Exception.class, handler); + } + }, + INVOKER("invoker") { + @Override + public Map<String, Object> getTestCaseData() { + Map<String, Object> data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + return data; + } + + @Override + protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + return MethodHandles.invoker(mtTarget); + } + }, + EXACT_INVOKER("exactInvoker") { + @Override + public Map<String, Object> getTestCaseData() { + Map<String, Object> data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + return data; + } + + @Override + protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + return MethodHandles.exactInvoker(mtTarget); + } + }, + SPREAD_INVOKER("spreadInvoker") { + @Override + public Map<String, Object> getTestCaseData() { + Map<String, Object> data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int modifierMHArgNum = Helper.RNG.nextInt(realArity + 1); + data.put("modifierMHArgNum", modifierMHArgNum); + return data; + } + + @Override + protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + int modifierMHArgNum = (int) data.get("modifierMHArgNum"); + return MethodHandles.spreadInvoker(mtTarget, modifierMHArgNum); + } + }, + ARRAY_ELEMENT_GETTER("arrayElementGetter") { + @Override + public Map<String, Object> getTestCaseData() { + Map<String, Object> data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + return data; + } + + @Override + protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + Class<?> rType = mtTarget.returnType(); + if (rType == void.class) { + rType = Object.class; + } + return MethodHandles.arrayElementGetter(Array.newInstance(rType, 2).getClass()); + } + }, + ARRAY_ELEMENT_SETTER("arrayElementSetter") { + @Override + public Map<String, Object> getTestCaseData() { + Map<String, Object> data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + return data; + } + + @Override + protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + Class<?> rType = mtTarget.returnType(); + if (rType == void.class) { + rType = Object.class; + } + return MethodHandles.arrayElementSetter(Array.newInstance(rType, 2).getClass()); + } + }, + CONSTANT("constant") { + @Override + public Map<String, Object> getTestCaseData() { + Map<String, Object> data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + return data; + } + + @Override + protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + Class<?> rType = mtTarget.returnType(); + if (rType == void.class) { + rType = Object.class; + } + if (rType.equals(boolean.class)) { + // There should be the same return values because for default values there are special "zero" forms + return MethodHandles.constant(rType, true); + } else { + return MethodHandles.constant(rType, kind.getValue(rType)); + } + } + }, + IDENTITY("identity") { + @Override + public Map<String, Object> getTestCaseData() { + Map<String, Object> data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + return data; + } + + @Override + protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + Class<?> rType = mtTarget.returnType(); + if (rType == void.class) { + rType = Object.class; + } + return MethodHandles.identity(rType); + } + }; + + /** + * Test method's name. + */ + public final String name; + + private TestMethods(String name) { + this.name = name; + } + + protected MethodHandle getMH(Map<String, Object> data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + throw new UnsupportedOperationException("TESTBUG: getMH method is not implemented for test method " + this); + } + + /** + * Creates an adapter method handle depending on a test method from + * MethodHandles class. Adapter is what is returned by the test method. This + * method is able to create two kinds of adapters, their type will be the + * same, but return values are different. + * + * @param data a Map containing data to create a method handle, can be + * obtained by {@link #getTestCaseData} method + * @param kind defines whether adapter ONE or adapter TWO will be + * initialized. Should be equal to TestMethods.Kind.ONE or + * TestMethods.Kind.TWO + * @return Method handle adapter that behaves according to + * TestMethods.Kind.ONE or TestMethods.Kind.TWO + * @throws java.lang.NoSuchMethodException + * @throws java.lang.IllegalAccessException + */ + public MethodHandle getTestCaseMH(Map<String, Object> data, TestMethods.Kind kind) + throws NoSuchMethodException, IllegalAccessException { + if (data == null) { + throw new Error(String.format("TESTBUG: Data for test method %s is not prepared", + this.name)); + } + if (!kind.equals(TestMethods.Kind.ONE) && !kind.equals(TestMethods.Kind.TWO)) { + throw new IllegalArgumentException("TESTBUG: Wrong \"kind\" (" + kind + + ") arg to getTestCaseMH function." + + " Should be Kind.ONE or Kind.TWO"); + } + return getMH(data, kind); + } + + /** + * Returns a data Map needed for {@link #getTestCaseMH} method. + * + * @return data Map needed for {@link #getTestCaseMH} method + */ + public Map<String, Object> getTestCaseData() { + throw new UnsupportedOperationException( + "TESTBUG: getTestCaseData method is not implemented for test method " + this); + } + + /** + * Enumeration used in methodHandleGenerator to define whether a MH returned + * by this method returns "2" in different type representations, "4", or + * throw an Exception. + */ + public static enum Kind { + + ONE(2), + TWO(4), + EXCEPT(0); + + private final int value; + + private Object getValue(Class<?> cl) { + return Helper.castToWrapper(value, cl); + } + + private MethodHandle getBasicMH(Class<?> rType) throws NoSuchMethodException, IllegalAccessException { + MethodHandle result = null; + switch (this) { + case ONE: + case TWO: + if (rType.equals(void.class)) { + result = MethodHandles.lookup().findVirtual(Kind.class, "returnVoid", MethodType.methodType(void.class)); + result = MethodHandles.insertArguments(result, 0, this); + } else { + result = MethodHandles.constant(rType, getValue(rType)); + } + break; + case EXCEPT: + result = MethodHandles.throwException(rType, Exception.class); + result = MethodHandles.insertArguments(result, 0, new Exception()); + break; + } + return result; + } + + private void returnVoid() { + } + + private Kind(int value) { + this.value = value; + } + } + + /** + * Routine used to obtain a randomly generated method type. + * + * @param arity Arity of returned method type. + * @return MethodType generated randomly. + */ + private static MethodType randomMethodTypeGenerator(int arity) { + final Class<?>[] CLASSES = { + Object.class, + int.class, + boolean.class, + byte.class, + short.class, + char.class, + long.class, + float.class, + double.class + }; + if (arity > Helper.MAX_ARITY) { + throw new IllegalArgumentException( + String.format("Arity should not exceed %d!", Helper.MAX_ARITY)); + } + List<Class<?>> list = Helper.randomClasses(CLASSES, arity); + list = Helper.getParams(list, false, arity); + int i = Helper.RNG.nextInt(CLASSES.length + 1); + Class<?> rtype = i == CLASSES.length ? void.class : CLASSES[i]; + return MethodType.methodType(rtype, list); + } + + /** + * Routine used to obtain a method handles of a given type an kind (return + * value). + * + * @param returnType Type of MH return value. + * @param argTypes Types of MH args. + * @param kind Defines whether the obtained MH returns "1" or "2". + * @return Method handle of the given type. + * @throws NoSuchMethodException + * @throws IllegalAccessException + */ + private static MethodHandle methodHandleGenerator(Class<?> returnType, + List<Class<?>> argTypes, TestMethods.Kind kind) + throws NoSuchMethodException, IllegalAccessException { + MethodHandle result; + result = kind.getBasicMH(returnType); + return Helper.addTrailingArgs(result, argTypes.size(), argTypes); + } + + /** + * Routine that generates filter method handles to test + * MethodHandles.filterArguments method. + * + * @param inputType Filter's argument type. + * @param returnType Filter's return type. + * @param kind Filter's return value definer. + * @return A filter method handle, that takes one argument. + * @throws NoSuchMethodException + * @throws IllegalAccessException + */ + private static MethodHandle filterGenerator(Class<?> inputType, Class<?> returnType, + TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodHandle tmpMH = kind.getBasicMH(returnType); + if (inputType.equals(void.class)) { + return tmpMH; + } + ArrayList<Class<?>> inputTypeList = new ArrayList<>(1); + inputTypeList.add(inputType); + return Helper.addTrailingArgs(tmpMH, 1, inputTypeList); + } + + private static int argSlotsCount(MethodType mt) { + int result = 0; + for (Class cl : mt.parameterArray()) { + if (cl.equals(long.class) || cl.equals(double.class)) { + result += 2; + } else { + result++; + } + } + return result; + } + + private static List<Class<?>> reduceArgListToSlotsCount(List<Class<?>> list, + int desiredSlotCount) { + List<Class<?>> result = new ArrayList<>(desiredSlotCount); + int count = 0; + for (Class<?> cl : list) { + if (count >= desiredSlotCount) { + break; + } + if (cl.equals(long.class) || cl.equals(double.class)) { + count += 2; + } else { + count++; + } + result.add(cl); + } + return result; + } +}
--- a/test/java/lang/invoke/MethodHandles/CatchExceptionTest.java Tue Sep 16 11:51:52 2014 -0700 +++ b/test/java/lang/invoke/MethodHandles/CatchExceptionTest.java Tue Sep 16 14:16:55 2014 -0700 @@ -43,6 +43,7 @@ public class CatchExceptionTest { private static final List<Class<?>> ARGS_CLASSES; protected static final int MAX_ARITY = Helper.MAX_ARITY - 1; + static { Class<?> classes[] = { Object.class, @@ -53,11 +54,8 @@ double[].class, String.class, }; - List<Class<?>> list = new ArrayList<>(MAX_ARITY); - for (int i = 0; i < MAX_ARITY; ++i) { - list.add(classes[Helper.RNG.nextInt(classes.length)]); - } - ARGS_CLASSES = Collections.unmodifiableList(list); + ARGS_CLASSES = Collections.unmodifiableList( + Helper.randomClasses(classes, MAX_ARITY)); } private final TestCase testCase; @@ -67,7 +65,6 @@ private int dropped; private MethodHandle thrower; - public CatchExceptionTest(TestCase testCase, final boolean isVararg, final int argsCount, final int catchDrops) { this.testCase = testCase; @@ -108,37 +105,7 @@ } private List<Class<?>> getThrowerParams(boolean isVararg, int argsCount) { - boolean unmodifiable = true; - List<Class<?>> classes; - classes = ARGS_CLASSES.subList(0, - Math.min(argsCount, (MAX_ARITY / 2) - 1)); - int extra = 0; - if (argsCount >= MAX_ARITY / 2) { - classes = new ArrayList<>(classes); - unmodifiable = false; - extra = (int) classes.stream().filter(Helper::isDoubleCost).count(); - int i = classes.size(); - while (classes.size() + extra < argsCount) { - Class<?> aClass = ARGS_CLASSES.get(i); - if (Helper.isDoubleCost(aClass)) { - ++extra; - if (classes.size() + extra >= argsCount) { - break; - } - } - classes.add(aClass); - } - } - if (isVararg && classes.size() > 0) { - if (unmodifiable) { - classes = new ArrayList<>(classes); - } - int last = classes.size() - 1; - Class<?> aClass = classes.get(classes.size() - 1); - aClass = Array.newInstance(aClass, 2).getClass(); - classes.set(last, aClass); - } - return classes; + return Helper.getParams(ARGS_CLASSES, isVararg, argsCount); }
--- a/test/java/net/NetworkInterface/Test.java Tue Sep 16 11:51:52 2014 -0700 +++ b/test/java/net/NetworkInterface/Test.java Tue Sep 16 14:16:55 2014 -0700 @@ -22,7 +22,9 @@ */ /* @test - * @bug 4405354 6594296 + * @bug 4405354 6594296 8058216 + * @run main Test + * @run main/othervm -Djava.net.preferIPv4Stack=true Test * @summary Basic tests for NetworkInterface */ import java.net.NetworkInterface;
--- a/test/javax/management/monitor/AttributeArbitraryDataTypeTest.java Tue Sep 16 11:51:52 2014 -0700 +++ b/test/javax/management/monitor/AttributeArbitraryDataTypeTest.java Tue Sep 16 14:16:55 2014 -0700 @@ -58,9 +58,9 @@ public class AttributeArbitraryDataTypeTest implements NotificationListener { // Flag to notify that a message has been received - private boolean counterMessageReceived = false; - private boolean gaugeMessageReceived = false; - private boolean stringMessageReceived = false; + private volatile boolean counterMessageReceived = false; + private volatile boolean gaugeMessageReceived = false; + private volatile boolean stringMessageReceived = false; // Match enum public enum Match { do_not_match_0, @@ -195,21 +195,33 @@ " has reached or exceeded the threshold"); echo("\t\tDerived Gauge = " + n.getDerivedGauge()); echo("\t\tTrigger = " + n.getTrigger()); - counterMessageReceived = true; + + synchronized (this) { + counterMessageReceived = true; + notifyAll(); + } } else if (type.equals(MonitorNotification. THRESHOLD_HIGH_VALUE_EXCEEDED)) { echo("\t\t" + n.getObservedAttribute() + " has reached or exceeded the high threshold"); echo("\t\tDerived Gauge = " + n.getDerivedGauge()); echo("\t\tTrigger = " + n.getTrigger()); - gaugeMessageReceived = true; + + synchronized (this) { + gaugeMessageReceived = true; + notifyAll(); + } } else if (type.equals(MonitorNotification. STRING_TO_COMPARE_VALUE_MATCHED)) { echo("\t\t" + n.getObservedAttribute() + " matches the string-to-compare value"); echo("\t\tDerived Gauge = " + n.getDerivedGauge()); echo("\t\tTrigger = " + n.getTrigger()); - stringMessageReceived = true; + + synchronized (this) { + stringMessageReceived = true; + notifyAll(); + } } else { echo("\t\tSkipping notification of type: " + type); } @@ -358,6 +370,17 @@ // Check if notification was received // + synchronized (this) { + while (!counterMessageReceived) { + try { + wait(); + } catch (InterruptedException e) { + System.err.println("Got unexpected exception: " + e); + e.printStackTrace(); + break; + } + } + } if (counterMessageReceived) { echo("\tOK: CounterMonitor notification received"); } else { @@ -525,6 +548,17 @@ // Check if notification was received // + synchronized (this) { + while (!gaugeMessageReceived) { + try { + wait(); + } catch (InterruptedException e) { + System.err.println("Got unexpected exception: " + e); + e.printStackTrace(); + break; + } + } + } if (gaugeMessageReceived) { echo("\tOK: GaugeMonitor notification received"); } else { @@ -680,6 +714,17 @@ // Check if notification was received // + synchronized (this) { + while (!stringMessageReceived) { + try { + wait(); + } catch (InterruptedException e) { + System.err.println("Got unexpected exception: " + e); + e.printStackTrace(); + break; + } + } + } if (stringMessageReceived) { echo("\tOK: StringMonitor notification received"); } else {
--- a/test/javax/management/monitor/CounterMonitorTest.java Tue Sep 16 11:51:52 2014 -0700 +++ b/test/javax/management/monitor/CounterMonitorTest.java Tue Sep 16 14:16:55 2014 -0700 @@ -43,9 +43,6 @@ // modulus number private Number modulus = new Integer(7); - // offset number - private int offset = 0; - // difference mode flag private boolean differenceModeFlag = true; @@ -58,9 +55,6 @@ // counter values private int[] values = new int[] {4, 6, 9, 11}; - // time to wait for notification (in seconds) - private int timeout = 5; - // flag to notify that a message has been received private volatile boolean messageReceived = false; @@ -92,8 +86,9 @@ echo("\t\t" + n.getObservedAttribute() + " has reached or exceeded the threshold"); echo("\t\tDerived Gauge = " + n.getDerivedGauge()); - messageReceived = true; + synchronized (this) { + messageReceived = true; notifyAll(); } } else { @@ -205,22 +200,17 @@ } /* - * Wait until timeout reached + * Wait messageReceived to be true */ - void doWait() { - for (int i = 0; i < timeout; i++) { - echo("\tdoWait: Waiting for " + timeout + " seconds. " + - "i = " + i + ", messageReceived = " + messageReceived); - if (messageReceived) { + synchronized void doWait() { + while (!messageReceived) { + try { + wait(); + } catch (InterruptedException e) { + System.err.println("Got unexpected exception: " + e); + e.printStackTrace(); break; } - try { - synchronized (this) { - wait(1000); - } - } catch (InterruptedException e) { - // OK: Ignore... - } } }
--- a/test/javax/management/monitor/NonComparableAttributeValueTest.java Tue Sep 16 11:51:52 2014 -0700 +++ b/test/javax/management/monitor/NonComparableAttributeValueTest.java Tue Sep 16 14:16:55 2014 -0700 @@ -39,7 +39,7 @@ public class NonComparableAttributeValueTest implements NotificationListener { // Flag to notify that a message has been received - private boolean messageReceived = false; + private volatile boolean messageReceived = false; // MBean class public class ObservedObject implements ObservedObjectMBean { @@ -69,7 +69,11 @@ echo("\t\t" + n.getObservedAttribute() + " is null"); echo("\t\tDerived Gauge = " + n.getDerivedGauge()); echo("\t\tTrigger = " + n.getTrigger()); - messageReceived = true; + + synchronized (this) { + messageReceived = true; + notifyAll(); + } } else { echo("\t\tSkipping notification of type: " + type); } @@ -134,12 +138,9 @@ echo(">>> START the CounterMonitor"); counterMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: CounterMonitor notification received"); } else { @@ -212,12 +213,9 @@ echo(">>> START the GaugeMonitor"); gaugeMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: GaugeMonitor notification received"); } else { @@ -289,12 +287,9 @@ echo(">>> START the StringMonitor"); stringMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: StringMonitor notification received"); } else { @@ -334,6 +329,21 @@ } /* + * Wait messageReceived to be true + */ + synchronized void doWait() { + while (!messageReceived) { + try { + wait(); + } catch (InterruptedException e) { + System.err.println("Got unexpected exception: " + e); + e.printStackTrace(); + break; + } + } + } + + /* * Standalone entry point. * * Run the test and report to stdout.
--- a/test/javax/management/monitor/ReflectionExceptionTest.java Tue Sep 16 11:51:52 2014 -0700 +++ b/test/javax/management/monitor/ReflectionExceptionTest.java Tue Sep 16 14:16:55 2014 -0700 @@ -87,7 +87,11 @@ echo("\tObservedAttribute: " + mn.getObservedAttribute()); echo("\tDerivedGauge: " + mn.getDerivedGauge()); echo("\tTrigger: " + mn.getTrigger()); - messageReceived = true; + + synchronized (this) { + messageReceived = true; + notifyAll(); + } } } } @@ -135,12 +139,9 @@ echo(">>> START the CounterMonitor"); counterMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: CounterMonitor got RUNTIME_ERROR notification!"); } else { @@ -203,12 +204,9 @@ echo(">>> START the GaugeMonitor"); gaugeMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: GaugeMonitor got RUNTIME_ERROR notification!"); } else { @@ -270,12 +268,9 @@ echo(">>> START the StringMonitor"); stringMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: StringMonitor got RUNTIME_ERROR notification!"); } else { @@ -349,8 +344,23 @@ } } + /* + * Wait messageReceived to be true + */ + synchronized void doWait() { + while (!messageReceived) { + try { + wait(); + } catch (InterruptedException e) { + System.err.println("Got unexpected exception: " + e); + e.printStackTrace(); + break; + } + } + } + // Flag to notify that a message has been received - private boolean messageReceived = false; + private volatile boolean messageReceived = false; private MBeanServer server; private ObjectName obsObjName;
--- a/test/javax/management/monitor/RuntimeExceptionTest.java Tue Sep 16 11:51:52 2014 -0700 +++ b/test/javax/management/monitor/RuntimeExceptionTest.java Tue Sep 16 14:16:55 2014 -0700 @@ -86,7 +86,11 @@ echo("\tObservedAttribute: " + mn.getObservedAttribute()); echo("\tDerivedGauge: " + mn.getDerivedGauge()); echo("\tTrigger: " + mn.getTrigger()); - messageReceived = true; + + synchronized (this) { + messageReceived = true; + notifyAll(); + } } } } @@ -134,12 +138,9 @@ echo(">>> START the CounterMonitor"); counterMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: CounterMonitor got RUNTIME_ERROR notification!"); } else { @@ -202,12 +203,9 @@ echo(">>> START the GaugeMonitor"); gaugeMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: GaugeMonitor got RUNTIME_ERROR notification!"); } else { @@ -269,12 +267,9 @@ echo(">>> START the StringMonitor"); stringMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: StringMonitor got RUNTIME_ERROR notification!"); } else { @@ -347,8 +342,23 @@ } } + /* + * Wait messageReceived to be true + */ + synchronized void doWait() { + while (!messageReceived) { + try { + wait(); + } catch (InterruptedException e) { + System.err.println("Got unexpected exception: " + e); + e.printStackTrace(); + break; + } + } + } + // Flag to notify that a message has been received - private boolean messageReceived = false; + private volatile boolean messageReceived = false; private MBeanServer server; private ObjectName obsObjName;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/javax/net/ssl/TLSv12/ProtocolFilter.java Tue Sep 16 14:16:55 2014 -0700 @@ -0,0 +1,315 @@ +/* + * 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. + * + * 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. + +/* + * @test + * @bug 8052406 + * @summary SSLv2Hello protocol may be filter out unexpectedly + * @run main/othervm ProtocolFilter + */ + +import java.io.*; +import java.net.*; +import javax.net.ssl.*; + +public class ProtocolFilter { + + /* + * ============================================================= + * Set the various variables needed for the tests, then + * specify what tests to run on each side. + */ + + /* + * Should we run the client or server in a separate thread? + * Both sides can throw exceptions, but do you have a preference + * as to which side should be the main thread. + */ + static boolean separateServerThread = false; + + /* + * Where do we find the keystores? + */ + static String pathToStores = "../../../../sun/security/ssl/etc"; + static String keyStoreFile = "keystore"; + static String trustStoreFile = "truststore"; + static String passwd = "passphrase"; + + /* + * Is the server ready to serve? + */ + volatile static boolean serverReady = false; + + /* + * Turn on SSL debugging? + */ + static boolean debug = false; + + /* + * If the client or server is doing some kind of object creation + * that the other side depends on, and that thread prematurely + * exits, you may experience a hang. The test harness will + * terminate all hung threads after its timeout has expired, + * currently 3 minutes by default, but you might try to be + * smart about it.... + */ + + /* + * Define the server side of the test. + * + * If the server prematurely exits, serverReady will be set to true + * to avoid infinite hangs. + */ + void doServerSide() throws Exception { + SSLServerSocketFactory sslssf = + (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); + SSLServerSocket sslServerSocket = + (SSLServerSocket) sslssf.createServerSocket(serverPort); + + // Only enable cipher suites for TLS v1.2. + sslServerSocket.setEnabledCipherSuites( + new String[]{"TLS_RSA_WITH_AES_128_CBC_SHA256"}); + + serverPort = sslServerSocket.getLocalPort(); + + /* + * Signal Client, we're ready for his connect. + */ + serverReady = true; + + SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); + InputStream sslIS = sslSocket.getInputStream(); + OutputStream sslOS = sslSocket.getOutputStream(); + + sslIS.read(); + sslOS.write(85); + sslOS.flush(); + + sslSocket.close(); + } + + /* + * Define the client side of the test. + * + * If the server prematurely exits, serverReady will be set to true + * to avoid infinite hangs. + */ + void doClientSide() throws Exception { + + /* + * Wait for server to get started. + */ + while (!serverReady) { + Thread.sleep(50); + } + + SSLSocketFactory sslsf = + (SSLSocketFactory) SSLSocketFactory.getDefault(); + SSLSocket sslSocket = (SSLSocket) + sslsf.createSocket("localhost", serverPort); + + // Enable all supported protocols, including SSLv2Hello. + sslSocket.setEnabledProtocols(sslSocket.getSupportedProtocols()); + + InputStream sslIS = sslSocket.getInputStream(); + OutputStream sslOS = sslSocket.getOutputStream(); + + sslOS.write(280); + sslOS.flush(); + sslIS.read(); + + sslSocket.close(); + } + + /* + * ============================================================= + * The remainder is just support stuff + */ + + // use any free port by default + volatile int serverPort = 0; + + volatile Exception serverException = null; + volatile Exception clientException = null; + + 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); + + if (debug) + System.setProperty("javax.net.debug", "all"); + + /* + * Start the tests. + */ + new ProtocolFilter(); + } + + Thread clientThread = null; + Thread serverThread = null; + + /* + * Primary constructor, used to drive remainder of the test. + * + * Fork off the other side, then do your work. + */ + ProtocolFilter() throws Exception { + Exception startException = null; + try { + if (separateServerThread) { + startServer(true); + startClient(false); + } else { + startClient(true); + startServer(false); + } + } catch (Exception e) { + startException = e; + } + + /* + * Wait for other side to close down. + */ + if (separateServerThread) { + if (serverThread != null) { + serverThread.join(); + } + } else { + if (clientThread != null) { + clientThread.join(); + } + } + + /* + * When we get here, the test is pretty much over. + * Which side threw the error? + */ + Exception local; + Exception remote; + + if (separateServerThread) { + remote = serverException; + local = clientException; + } else { + remote = clientException; + local = serverException; + } + + Exception exception = null; + + /* + * Check various exception conditions. + */ + if ((local != null) && (remote != null)) { + // If both failed, return the curthread's exception. + local.initCause(remote); + exception = local; + } else if (local != null) { + exception = local; + } else if (remote != null) { + exception = remote; + } else if (startException != null) { + exception = startException; + } + + /* + * If there was an exception *AND* a startException, + * output it. + */ + if (exception != null) { + if (exception != startException && startException != null) { + exception.addSuppressed(startException); + } + throw exception; + } + + // Fall-through: no exception to throw! + } + + void startServer(boolean newThread) throws Exception { + if (newThread) { + serverThread = new Thread() { + public void run() { + try { + doServerSide(); + } catch (Exception e) { + /* + * Our server thread just died. + * + * Release the client, if not active already... + */ + System.err.println("Server died..."); + serverReady = true; + serverException = e; + } + } + }; + serverThread.start(); + } else { + try { + doServerSide(); + } catch (Exception e) { + serverException = e; + } finally { + serverReady = true; + } + } + } + + void startClient(boolean newThread) throws Exception { + if (newThread) { + clientThread = new Thread() { + public void run() { + try { + doClientSide(); + } catch (Exception e) { + /* + * Our client thread just died. + */ + System.err.println("Client died..."); + clientException = e; + } + } + }; + clientThread.start(); + } else { + try { + doClientSide(); + } catch (Exception e) { + clientException = e; + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/javax/swing/text/View/8048110/bug8048110.java Tue Sep 16 14:16:55 2014 -0700 @@ -0,0 +1,121 @@ +/* + * 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. + * + * 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 8048110 + * @summary Using tables in JTextPane leads to infinite loop in FlowLayout.layoutRow + * @author Dmitry Markov + * @run main bug8048110 + */ + +import sun.awt.SunToolkit; + +import javax.swing.*; +import javax.swing.text.Element; +import javax.swing.text.html.HTMLDocument; +import javax.swing.text.html.HTMLEditorKit; +import java.awt.*; + +public class bug8048110 { + private static SunToolkit toolkit = (SunToolkit)Toolkit.getDefaultToolkit(); + private static Object lock = new Object(); + private static boolean isRealSyncPerformed = false; + private static final String htmlText = "<table width=\"100%\" cellpadding=\"10\" cellspacing=\"5\" align=\"center\">" + + "<tr><th align=\"left\" bgcolor=\"#bec3c6\">Devices</th><th align=\"left\" bgcolor=\"#bec3c6\">State</th></tr>" + + "<tr><td align=\"left\" bgcolor=\"#bec3c6\">PC</td><td align=\"left\" bgcolor=\"#46a055\">Ok</td></tr></table>"; + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + createAndShowGUI(); + } + }); + + Thread thread = new Thread() { + @Override + public void run() { + toolkit.realSync(); + synchronized (lock) { + isRealSyncPerformed = true; + lock.notifyAll(); + } + } + }; + thread.start(); + + synchronized (lock) { + if (!isRealSyncPerformed) { + lock.wait(5000); + } + } + + if (!isRealSyncPerformed) { + throw new RuntimeException("Test Failed!"); + } + } + + private static void createAndShowGUI() { + try { + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + HTMLEditorKit editorKit = new HTMLEditorKit(); + JTextPane textPane = new JTextPane(); + textPane.setContentType("text/html"); + textPane.setEditorKit(editorKit); + textPane.setText("Initial text without table"); + + JFrame frame = new JFrame("bug8048110"); + frame.getContentPane().add(textPane, BorderLayout.CENTER); + frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + frame.setSize(500, 200); + frame.setVisible(true); + + textPane.setDocument(textPane.getEditorKit().createDefaultDocument()); + HTMLDocument htmlDocument = (HTMLDocument) textPane.getDocument(); + Element firstParagraph = findFirstElement(textPane.getDocument().getDefaultRootElement(), "p"); + + try { + htmlDocument.setInnerHTML(firstParagraph, htmlText); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + private static Element findFirstElement(Element e, String name) { + String elementName = e.getName(); + if (elementName != null && elementName.equalsIgnoreCase(name)) { + return e; + } + for (int i = 0; i < e.getElementCount(); i++) { + Element result = findFirstElement(e.getElement(i), name); + if (result != null) { + return result; + } + } + return null; + } +} +
--- a/test/lib/testlibrary/jsr292/com/oracle/testlibrary/jsr292/Helper.java Tue Sep 16 11:51:52 2014 -0700 +++ b/test/lib/testlibrary/jsr292/com/oracle/testlibrary/jsr292/Helper.java Tue Sep 16 14:16:55 2014 -0700 @@ -52,7 +52,7 @@ public static final long TEST_LIMIT; static { String str = System.getProperty("testLimit"); - TEST_LIMIT = str != null ? Long.parseUnsignedLong(str) : 2_000L; + TEST_LIMIT = str != null ? Long.parseUnsignedLong(str) : 2000L; System.out.printf("-DtestLimit=%d%n", TEST_LIMIT); } @@ -116,6 +116,48 @@ return size <= lag ? null : calledLog.get(size - lag - 1); } + public static List<Class<?>> randomClasses(Class<?>[] classes, int size) { + List<Class<?>> result = new ArrayList<>(size); + for (int i = 0; i < size; ++i) { + result.add(classes[RNG.nextInt(classes.length)]); + } + return result; + } + + public static List<Class<?>> getParams(List<Class<?>> classes, + boolean isVararg, int argsCount) { + boolean unmodifiable = true; + List<Class<?>> result = classes.subList(0, + Math.min(argsCount, (MAX_ARITY / 2) - 1)); + int extra = 0; + if (argsCount >= MAX_ARITY / 2) { + result = new ArrayList<>(result); + unmodifiable = false; + extra = (int) result.stream().filter(Helper::isDoubleCost).count(); + int i = result.size(); + while (result.size() + extra < argsCount) { + Class<?> aClass = classes.get(i); + if (Helper.isDoubleCost(aClass)) { + ++extra; + if (result.size() + extra >= argsCount) { + break; + } + } + result.add(aClass); + } + } + if (isVararg && result.size() > 0) { + if (unmodifiable) { + result = new ArrayList<>(result); + } + int last = result.size() - 1; + Class<?> aClass = result.get(last); + aClass = Array.newInstance(aClass, 2).getClass(); + result.set(last, aClass); + } + return result; + } + public static MethodHandle addTrailingArgs(MethodHandle target, int nargs, List<Class<?>> classes) { int targetLen = target.type().parameterCount(); @@ -230,7 +272,7 @@ return randomArgs(params.toArray(new Class<?>[params.size()])); } - private static Object castToWrapper(Object value, Class<?> dst) { + public static Object castToWrapper(Object value, Class<?> dst) { Object wrap = null; if (value instanceof Number) { wrap = castToWrapperOrNull(((Number) value).longValue(), dst); @@ -268,7 +310,7 @@ if (dst == byte.class || dst == Byte.class) { return (byte) (value); } - if (dst == boolean.class || dst == boolean.class) { + if (dst == boolean.class || dst == Boolean.class) { return ((value % 29) & 1) == 0; } return null;