From d845c9092c57e69c01f150112ec530202bb56a3d Mon Sep 17 00:00:00 2001 From: Phil Race Date: Wed, 14 Dec 2016 08:48:08 -0800 Subject: [PATCH 01/22] 8171074: Test api/javax_swing/UIManager/index.html\#Methods is failing Reviewed-by: ssadetsky, alexsch --- .../share/classes/javax/swing/UIManager.java | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/javax/swing/UIManager.java b/jdk/src/java.desktop/share/classes/javax/swing/UIManager.java index 9b9cad72d67..8fdfb1138bb 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/UIManager.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/UIManager.java @@ -629,16 +629,7 @@ public class UIManager implements Serializable } else { Class lnfClass = SwingUtilities.loadSystemClass(className); - try { - LookAndFeel laf = - (LookAndFeel)lnfClass.newInstance(); - setLookAndFeel(laf); - } catch (ReflectiveOperationException | IllegalArgumentException e) { - InstantiationException ex = - new InstantiationException("Wrapped Exception"); - ex.initCause(e); - throw ex; - } + setLookAndFeel((LookAndFeel)(lnfClass.newInstance())); } } From 2c877752fe013e11d5a4e6615a0c2dba20488b33 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Thu, 15 Dec 2016 20:09:13 +0300 Subject: [PATCH 02/22] 8131347: new @BeanProperty annotation: inconsistent behavior for "enumerationValues" Reviewed-by: avstepan --- .../share/classes/java/beans/PropertyDescriptor.java | 5 +++-- .../8130937/TestBooleanBeanProperties.java | 10 +++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/java/beans/PropertyDescriptor.java b/jdk/src/java.desktop/share/classes/java/beans/PropertyDescriptor.java index 5eb7a3c0c57..373b7ad6fff 100644 --- a/jdk/src/java.desktop/share/classes/java/beans/PropertyDescriptor.java +++ b/jdk/src/java.desktop/share/classes/java/beans/PropertyDescriptor.java @@ -183,9 +183,10 @@ public class PropertyDescriptor extends FeatureDescriptor { setShortDescription(description.toString()); } Object values = info.get(PropertyInfo.Name.enumerationValues); - if (values != null) { - setValue(PropertyInfo.Name.enumerationValues.name(), values); + if (values == null) { + values = new Object[0]; } + setValue(PropertyInfo.Name.enumerationValues.name(), values); this.baseName = base; } diff --git a/jdk/test/java/beans/Introspector/8130937/TestBooleanBeanProperties.java b/jdk/test/java/beans/Introspector/8130937/TestBooleanBeanProperties.java index 494985cde68..c047c5f45c4 100644 --- a/jdk/test/java/beans/Introspector/8130937/TestBooleanBeanProperties.java +++ b/jdk/test/java/beans/Introspector/8130937/TestBooleanBeanProperties.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 @@ -28,7 +28,7 @@ import java.beans.PropertyDescriptor; /** * @test - * @bug 8130937 + * @bug 8130937 8131347 * @summary Tests the booleans properties of the BeanProperty annotation * @library .. */ @@ -76,6 +76,9 @@ public final class TestBooleanBeanProperties { if (getValue(pd, "visualUpdate") != isVS) { throw new RuntimeException("required should be: " + isVS); } + if (pd.getValue("enumerationValues") == null) { + throw new RuntimeException("enumerationValues should be empty array"); + } } private static boolean getValue(PropertyDescriptor pd, String value) { @@ -107,7 +110,8 @@ public final class TestBooleanBeanProperties { } @BeanProperty(bound = true, expert = true, hidden = true, - preferred = true, required = true, visualUpdate = true) + preferred = true, required = true, visualUpdate = true, + enumerationValues = {}) public void setValue(int value) { this.value = value; } From 45e7f76530b5c500387617cc6c11937b39630614 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Thu, 15 Dec 2016 14:30:12 -0800 Subject: [PATCH 03/22] 8039273: Font related files should not be modified in ${java.home}/lib Reviewed-by: serb, naoto --- .../share/classes/sun/awt/FontConfiguration.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/sun/awt/FontConfiguration.java b/jdk/src/java.desktop/share/classes/sun/awt/FontConfiguration.java index 3945940be2d..68deeb3aeaf 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/FontConfiguration.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/FontConfiguration.java @@ -182,11 +182,17 @@ public abstract class FontConfiguration { throw new Error("java.home property not set"); } javaLib = javaHome + File.separator + "lib"; + String javaConfFonts = javaHome + + File.separator + "conf" + + File.separator + "fonts"; String userConfigFile = System.getProperty("sun.awt.fontconfig"); if (userConfigFile != null) { fontConfigFile = new File(userConfigFile); } else { - fontConfigFile = findFontConfigFile(javaLib); + fontConfigFile = findFontConfigFile(javaConfFonts); + if (fontConfigFile == null) { + fontConfigFile = findFontConfigFile(javaLib); + } } } @@ -275,8 +281,11 @@ public abstract class FontConfiguration { return null; } - private File findFontConfigFile(String javaLib) { - String baseName = javaLib + File.separator + "fontconfig"; + private File findFontConfigFile(String dir) { + if (!(new File(dir)).exists()) { + return null; + } + String baseName = dir + File.separator + "fontconfig"; File configFile; String osMajorVersion = null; if (osVersion != null && osName != null) { From 6275fb99b0e3da7bac979da03c30c12c9536d5db Mon Sep 17 00:00:00 2001 From: Ajit Ghaisas Date: Fri, 16 Dec 2016 12:02:10 +0530 Subject: [PATCH 04/22] 8134612: clipboard.getData(dataFlavor) can throw UnsupportedFlavorException for registered data flavor Reviewed-by: alexsch, serb --- .../ConstructFlavoredObjectTest.java | 58 +++++++++++++------ 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/jdk/test/java/awt/datatransfer/ConstructFlavoredObjectTest/ConstructFlavoredObjectTest.java b/jdk/test/java/awt/datatransfer/ConstructFlavoredObjectTest/ConstructFlavoredObjectTest.java index d7c9769ffb5..7b901388a71 100644 --- a/jdk/test/java/awt/datatransfer/ConstructFlavoredObjectTest/ConstructFlavoredObjectTest.java +++ b/jdk/test/java/awt/datatransfer/ConstructFlavoredObjectTest/ConstructFlavoredObjectTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -31,34 +31,57 @@ import javax.swing.TransferHandler; /* * @test * @key headful - * @bug 8130329 + * @bug 8130329 8134612 8133719 * @summary Audit Core Reflection in module java.desktop AWT/Miscellaneous area * for places that will require changes to work with modules * @author Alexander Scherbatiy + * @run main/othervm ConstructFlavoredObjectTest COPY + * @run main/othervm ConstructFlavoredObjectTest PASTE */ public class ConstructFlavoredObjectTest { - private static final String TEST_MIME_TYPE = "text/plain;class=" - + MyStringReader.class.getName(); - public static void main(String[] args) throws Exception { - final DataFlavor dataFlavor = new DataFlavor(TEST_MIME_TYPE); - SystemFlavorMap systemFlavorMap = (SystemFlavorMap) SystemFlavorMap. - getDefaultFlavorMap(); - systemFlavorMap.addUnencodedNativeForFlavor(dataFlavor, "TEXT"); - systemFlavorMap.addFlavorForUnencodedNative("TEXT", dataFlavor); + if (args[0].equals("COPY")) { - TransferHandler transferHandler = new TransferHandler("Test Handler"); + // Copy a simple text string on to the System clipboard - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - transferHandler.exportToClipboard(new JLabel("Test"), clipboard, - TransferHandler.COPY); + final String TEXT_MIME_TYPE = DataFlavor.javaJVMLocalObjectMimeType + + ";class=" + String.class.getName(); - Object clipboardData = clipboard.getData(dataFlavor); + final DataFlavor dataFlavor = new DataFlavor(TEXT_MIME_TYPE); + SystemFlavorMap systemFlavorMap = + (SystemFlavorMap) SystemFlavorMap.getDefaultFlavorMap(); + systemFlavorMap.addUnencodedNativeForFlavor(dataFlavor, "TEXT"); + systemFlavorMap.addFlavorForUnencodedNative("TEXT", dataFlavor); - if (!(clipboardData instanceof MyStringReader)) { - throw new RuntimeException("Wrong clipboard data!"); + TransferHandler transferHandler = new TransferHandler("text"); + + String text = "This is sample export text"; + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + transferHandler.exportToClipboard(new JLabel(text), clipboard, + TransferHandler.COPY); + } + else if (args[0].equals("PASTE")) { + + // Try to read text data from the System clipboard + + final String TEST_MIME_TYPE = "text/plain;class=" + + MyStringReader.class.getName(); + + final DataFlavor dataFlavor = new DataFlavor(TEST_MIME_TYPE); + SystemFlavorMap systemFlavorMap = (SystemFlavorMap) SystemFlavorMap. + getDefaultFlavorMap(); + systemFlavorMap.addUnencodedNativeForFlavor(dataFlavor, "TEXT"); + systemFlavorMap.addFlavorForUnencodedNative("TEXT", dataFlavor); + + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + + Object clipboardData = clipboard.getData(dataFlavor); + + if (!(clipboardData instanceof MyStringReader)) { + throw new RuntimeException("Wrong clipboard data!"); + } } } @@ -78,3 +101,4 @@ public class ConstructFlavoredObjectTest { } } } + From f2654d02ec6317362343ea1baba89a2b0d8471a5 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 16 Dec 2016 16:09:52 -0800 Subject: [PATCH 05/22] 8171363: [PIT] Four Windows-specific tests fail with InaccessibleObjectException when calling Field.setAccessible() Reviewed-by: mchung --- .../EmbeddedFrame/DisplayChangedTest/DisplayChangedTest.java | 4 ++-- .../EmbeddedFrameGrabTest/EmbeddedFrameGrabTest.java | 4 ++-- jdk/test/javax/swing/JFileChooser/4847375/bug4847375.java | 4 ++-- jdk/test/javax/swing/JFileChooser/6741890/bug6741890.java | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/jdk/test/java/awt/EmbeddedFrame/DisplayChangedTest/DisplayChangedTest.java b/jdk/test/java/awt/EmbeddedFrame/DisplayChangedTest/DisplayChangedTest.java index d423789ef8c..082681bd69b 100644 --- a/jdk/test/java/awt/EmbeddedFrame/DisplayChangedTest/DisplayChangedTest.java +++ b/jdk/test/java/awt/EmbeddedFrame/DisplayChangedTest/DisplayChangedTest.java @@ -23,12 +23,12 @@ /* @test - @bug 4980592 + @bug 4980592 8171363 @summary switching user in XP causes an NPE in sun.awt.windows.WWindowPeer.displayChanged @requires (os.family == "windows") @modules java.desktop/java.awt.peer - @modules java.desktop/sun.awt.windows + @modules java.desktop/sun.awt.windows:open @modules java.desktop/sun.awt @author son@sparc.spb.su: area=embedded @run main DisplayChangedTest diff --git a/jdk/test/java/awt/EmbeddedFrame/EmbeddedFrameGrabTest/EmbeddedFrameGrabTest.java b/jdk/test/java/awt/EmbeddedFrame/EmbeddedFrameGrabTest/EmbeddedFrameGrabTest.java index 1f9f1e5af3e..5249dca3b14 100644 --- a/jdk/test/java/awt/EmbeddedFrame/EmbeddedFrameGrabTest/EmbeddedFrameGrabTest.java +++ b/jdk/test/java/awt/EmbeddedFrame/EmbeddedFrameGrabTest/EmbeddedFrameGrabTest.java @@ -23,12 +23,12 @@ /* @test - @bug 6345002 + @bug 6345003 8171363 @summary grab problems with EmbeddedFrame @requires (os.family == "windows") @modules java.desktop/java.awt.peer @modules java.desktop/sun.awt - @modules java.desktop/sun.awt.windows + @modules java.desktop/sun.awt.windows:open @author Oleg.Semenov@sun.com area=EmbeddedFrame @run main EmbeddedFrameGrabTest */ diff --git a/jdk/test/javax/swing/JFileChooser/4847375/bug4847375.java b/jdk/test/javax/swing/JFileChooser/4847375/bug4847375.java index 33012922cab..494e9ed5485 100644 --- a/jdk/test/javax/swing/JFileChooser/4847375/bug4847375.java +++ b/jdk/test/javax/swing/JFileChooser/4847375/bug4847375.java @@ -23,11 +23,11 @@ /* * @test - * @bug 4847375 + * @bug 4847375 8171363 * @summary JFileChooser Create New Folder button is disabled incorrectly * @author Pavel Porvatov * @modules java.desktop/sun.awt - * java.desktop/sun.awt.shell + * java.desktop/sun.awt.shell:+open */ import sun.awt.OSInfo; diff --git a/jdk/test/javax/swing/JFileChooser/6741890/bug6741890.java b/jdk/test/javax/swing/JFileChooser/6741890/bug6741890.java index 89d08c88d5b..d89722de677 100644 --- a/jdk/test/javax/swing/JFileChooser/6741890/bug6741890.java +++ b/jdk/test/javax/swing/JFileChooser/6741890/bug6741890.java @@ -22,11 +22,11 @@ */ /* @test - @bug 6741890 + @bug 6741890 8171363 @summary Deadlock in Win32ShellFolderManager2 @author Pavel Porvatov @modules java.desktop/sun.awt - java.desktop/sun.awt.shell + java.desktop/sun.awt.shell:+open @run main bug6741890 */ From a2cd969a52c2a32fb96e65665b6fe0e3b5b433cf Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Tue, 6 Dec 2016 14:54:11 +0100 Subject: [PATCH 06/22] 8170798: Fix minor issues in java2d and sound coding Reviewed-by: prr, serb --- .../native/libfontmanager/layout/ScriptAndLanguageTags.cpp | 3 ++- .../share/native/libfontmanager/layout/ThaiShaping.cpp | 2 +- .../share/native/libfontmanager/layout/ThaiShaping.h | 5 +++-- .../share/native/libfontmanager/layout/ThaiStateTables.cpp | 2 +- .../unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_Ports.c | 3 ++- .../unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_Ports.c | 3 ++- .../unix/native/libjsound/PLATFORM_API_SolarisOS_Ports.c | 3 ++- 7 files changed, 13 insertions(+), 8 deletions(-) diff --git a/jdk/src/java.desktop/share/native/libfontmanager/layout/ScriptAndLanguageTags.cpp b/jdk/src/java.desktop/share/native/libfontmanager/layout/ScriptAndLanguageTags.cpp index 57d8ac43ac9..459c12a78bd 100644 --- a/jdk/src/java.desktop/share/native/libfontmanager/layout/ScriptAndLanguageTags.cpp +++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/ScriptAndLanguageTags.cpp @@ -33,13 +33,14 @@ * Generated on: 10/26/2010 02:53:33 PM PDT */ +#include "LEScripts.h" #include "LETypes.h" #include "ScriptAndLanguageTags.h" #include "OpenTypeLayoutEngine.h" U_NAMESPACE_BEGIN -const LETag OpenTypeLayoutEngine::scriptTags[] = { +const LETag OpenTypeLayoutEngine::scriptTags[scriptCodeCount] = { zyyyScriptTag, /* 'zyyy' (COMMON) */ zinhScriptTag, /* 'zinh' (INHERITED) */ arabScriptTag, /* 'arab' (ARABIC) */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/layout/ThaiShaping.cpp b/jdk/src/java.desktop/share/native/libfontmanager/layout/ThaiShaping.cpp index b0e4d5fe95e..a77db0afcd2 100644 --- a/jdk/src/java.desktop/share/native/libfontmanager/layout/ThaiShaping.cpp +++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/ThaiShaping.cpp @@ -302,7 +302,7 @@ le_int32 ThaiShaping::compose(const LEUnicode *input, le_int32 offset, le_int32 le_uint8 charClass; // Decompose SARA AM into NIKHAHIT + SARA AA - if (ch == CH_SARA_AM && isLegalHere(ch, state)) { + if (ch == CH_SARA_AM && isLegalHere(ch, state) && conState < stateCount) { outputIndex = conOutput; state = getNextState(CH_NIKHAHIT, conState, inputIndex, glyphSet, errorChar, charClass, output, glyphStorage, outputIndex); diff --git a/jdk/src/java.desktop/share/native/libfontmanager/layout/ThaiShaping.h b/jdk/src/java.desktop/share/native/libfontmanager/layout/ThaiShaping.h index be697f7b30b..3b93277b3fe 100644 --- a/jdk/src/java.desktop/share/native/libfontmanager/layout/ThaiShaping.h +++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/ThaiShaping.h @@ -80,7 +80,8 @@ public: tG = 5, tH = 6, tR = 7, - tS = 8 + tS = 8, + stateCount = 52 }; struct StateTransition @@ -100,7 +101,7 @@ private: ThaiShaping(); static const le_uint8 classTable[]; - static const StateTransition thaiStateTable[][classCount]; + static const StateTransition thaiStateTable[stateCount][classCount]; inline static StateTransition getTransition(le_uint8 state, le_uint8 currClass); diff --git a/jdk/src/java.desktop/share/native/libfontmanager/layout/ThaiStateTables.cpp b/jdk/src/java.desktop/share/native/libfontmanager/layout/ThaiStateTables.cpp index e613fb1ecb9..98a218741f4 100644 --- a/jdk/src/java.desktop/share/native/libfontmanager/layout/ThaiStateTables.cpp +++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/ThaiStateTables.cpp @@ -49,7 +49,7 @@ const le_uint8 ThaiShaping::classTable[] = { /*0E50*/ NON, NON, NON, NON, NON, NON, NON, NON, NON, NON, NON, NON }; -const ThaiShaping::StateTransition ThaiShaping::thaiStateTable[][ThaiShaping::classCount] = { +const ThaiShaping::StateTransition ThaiShaping::thaiStateTable[ThaiShaping::stateCount][ThaiShaping::classCount] = { //+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| N C C C L F F F B B B T A A A N A A A | //| O O O O V V V V V V D O D D D I V V V | diff --git a/jdk/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_Ports.c b/jdk/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_Ports.c index 0ecfac684c9..b58b67c82c7 100644 --- a/jdk/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_Ports.c +++ b/jdk/src/java.desktop/unix/native/libjsound/PLATFORM_API_BsdOS_ALSA_Ports.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -385,6 +385,7 @@ void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator) { int isStereo; char* type; snd_mixer_selem_channel_id_t channel; + memset(controls, 0, sizeof(controls)); TRACE0("> PORT_GetControls\n"); if (id == NULL) { diff --git a/jdk/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_Ports.c b/jdk/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_Ports.c index 47f3c3f6d89..b973cc839fd 100644 --- a/jdk/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_Ports.c +++ b/jdk/src/java.desktop/unix/native/libjsound/PLATFORM_API_LinuxOS_ALSA_Ports.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -385,6 +385,7 @@ void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator) { int isStereo; char* type; snd_mixer_selem_channel_id_t channel; + memset(controls, 0, sizeof(controls)); TRACE0("> PORT_GetControls\n"); if (id == NULL) { diff --git a/jdk/src/java.desktop/unix/native/libjsound/PLATFORM_API_SolarisOS_Ports.c b/jdk/src/java.desktop/unix/native/libjsound/PLATFORM_API_SolarisOS_Ports.c index 44cc6fc3fdc..6d8cc68ab87 100644 --- a/jdk/src/java.desktop/unix/native/libjsound/PLATFORM_API_SolarisOS_Ports.c +++ b/jdk/src/java.desktop/unix/native/libjsound/PLATFORM_API_SolarisOS_Ports.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2007, 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 @@ -390,6 +390,7 @@ void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator) { int controlCount = 0; INT32 type; int selectable = 1; + memset(controls, 0, sizeof(controls)); TRACE4(">PORT_GetControls(id=%p, portIndex=%d). controlIDs=%p, maxControlCount=%d\n", id, portIndex, info->controlIDs, info->maxControlCount); From 254d34cdf1fe6b33c720488513149889b0792c11 Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Tue, 20 Dec 2016 11:53:07 +0300 Subject: [PATCH 07/22] 8074883: Tab key should move to focused button in a button group Reviewed-by: alexsch, serb --- .../classes/javax/swing/JToggleButton.java | 91 ++++++++++++++ .../ButtonGroupFocusTest.java | 119 ++++++++++++++++++ 2 files changed, 210 insertions(+) create mode 100644 jdk/test/javax/swing/JRadioButton/ButtonGroupFocus/ButtonGroupFocusTest.java diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JToggleButton.java b/jdk/src/java.desktop/share/classes/javax/swing/JToggleButton.java index da9387e3061..56de72a03fb 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JToggleButton.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JToggleButton.java @@ -34,6 +34,7 @@ import javax.accessibility.*; import java.io.ObjectOutputStream; import java.io.IOException; +import java.util.Iterator; /** * An implementation of a two-state button. @@ -208,6 +209,96 @@ public class JToggleButton extends AbstractButton implements Accessible { return true; } + private JToggleButton getGroupSelection(FocusEvent.Cause cause) { + switch (cause) { + case ACTIVATION: + case TRAVERSAL: + case TRAVERSAL_UP: + case TRAVERSAL_DOWN: + case TRAVERSAL_FORWARD: + case TRAVERSAL_BACKWARD: + ButtonModel model = getModel(); + JToggleButton selection = this; + if (model instanceof DefaultButtonModel) { + ButtonGroup group = ((DefaultButtonModel) model).getGroup(); + if (group != null && group.getSelection() != null + && !group.isSelected(model)) { + Iterator iterator = + group.getElements().asIterator(); + while (iterator.hasNext()) { + AbstractButton member = iterator.next(); + if (group.isSelected(member.getModel())) { + if (member instanceof JToggleButton && + member.isVisible() && member.isDisplayable() && + member.isEnabled() && member.isFocusable()) { + selection = (JToggleButton) member; + } + break; + } + } + } + } + return selection; + default: + return this; + } + } + + /** + * If this toggle button is a member of the {@link ButtonGroup} which has + * another toggle button which is selected and can be the focus owner, + * and the focus cause argument denotes window activation or focus + * traversal action of any direction the result of the method execution + * is the same as calling + * {@link Component#requestFocus(FocusEvent.Cause)} on the toggle button + * selected in the group. + * In all other cases the result of the method is the same as calling + * {@link Component#requestFocus(FocusEvent.Cause)} on this toggle button. + * + * @param cause the cause why the focus is requested + * @see ButtonGroup + * @see Component#requestFocus(FocusEvent.Cause) + * @see FocusEvent.Cause + * + * @since 9 + */ + @Override + public void requestFocus(FocusEvent.Cause cause) { + getGroupSelection(cause).requestFocusUnconditionally(cause); + } + + private void requestFocusUnconditionally(FocusEvent.Cause cause) { + super.requestFocus(cause); + } + + /** + * If this toggle button is a member of the {@link ButtonGroup} which has + * another toggle button which is selected and can be the focus owner, + * and the focus cause argument denotes window activation or focus + * traversal action of any direction the result of the method execution + * is the same as calling + * {@link Component#requestFocusInWindow(FocusEvent.Cause)} on the toggle + * button selected in the group. + * In all other cases the result of the method is the same as calling + * {@link Component#requestFocusInWindow(FocusEvent.Cause)} on this toggle + * button. + * + * @param cause the cause why the focus is requested + * @see ButtonGroup + * @see Component#requestFocusInWindow(FocusEvent.Cause) + * @see FocusEvent.Cause + * + * @since 9 + */ + public boolean requestFocusInWindow(FocusEvent.Cause cause) { + return getGroupSelection(cause) + .requestFocusInWindowUnconditionally(cause); + } + + private boolean requestFocusInWindowUnconditionally(FocusEvent.Cause cause) { + return super.requestFocusInWindow(cause); + } + // ********************************************************************* /** diff --git a/jdk/test/javax/swing/JRadioButton/ButtonGroupFocus/ButtonGroupFocusTest.java b/jdk/test/javax/swing/JRadioButton/ButtonGroupFocus/ButtonGroupFocusTest.java new file mode 100644 index 00000000000..f7118aa3fba --- /dev/null +++ b/jdk/test/javax/swing/JRadioButton/ButtonGroupFocus/ButtonGroupFocusTest.java @@ -0,0 +1,119 @@ +/* + * 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 8074883 + * @summary Tab key should move to focused button in a button group + * @run main ButtonGroupFocusTest + */ + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; + +public class ButtonGroupFocusTest { + + private static JRadioButton button1; + private static JRadioButton button2; + private static JRadioButton button3; + private static JRadioButton button4; + private static JRadioButton button5; + private static Robot robot; + private static JFrame frame; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + robot.setAutoDelay(100); + + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame(); + Container contentPane = frame.getContentPane(); + contentPane.setLayout(new FlowLayout()); + button1 = new JRadioButton("Button 1"); + contentPane.add(button1); + button2 = new JRadioButton("Button 2"); + contentPane.add(button2); + button3 = new JRadioButton("Button 3"); + contentPane.add(button3); + button4 = new JRadioButton("Button 4"); + contentPane.add(button4); + button5 = new JRadioButton("Button 5"); + contentPane.add(button5); + ButtonGroup group = new ButtonGroup(); + group.add(button1); + group.add(button2); + group.add(button3); + + group = new ButtonGroup(); + group.add(button4); + group.add(button5); + + button2.setSelected(true); + + frame.pack(); + frame.setVisible(true); + }); + + robot.waitForIdle(); + robot.delay(200); + + SwingUtilities.invokeAndWait(() -> { + if( !button2.hasFocus() ) { + frame.dispose(); + throw new RuntimeException( + "Button 2 should get focus after activation"); + } + }); + + robot.keyPress(KeyEvent.VK_TAB); + robot.keyRelease(KeyEvent.VK_TAB); + + robot.waitForIdle(); + robot.delay(200); + + SwingUtilities.invokeAndWait(() -> { + if( !button4.hasFocus() ) { + frame.dispose(); + throw new RuntimeException( + "Button 4 should get focus"); + } + button3.setSelected(true); + }); + + robot.keyPress(KeyEvent.VK_TAB); + robot.keyRelease(KeyEvent.VK_TAB); + + robot.waitForIdle(); + robot.delay(200); + + SwingUtilities.invokeAndWait(() -> { + if( !button3.hasFocus() ) { + frame.dispose(); + throw new RuntimeException( + "selected Button 3 should get focus"); + } + }); + + SwingUtilities.invokeLater(frame::dispose); + } +} From 7f0e76447752f818f8401d24d3ca3bdbe05475e9 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Tue, 20 Dec 2016 17:34:11 -0800 Subject: [PATCH 08/22] 8029360: java/rmi/transport/dgcDeadLock/DGCDeadLock.java failing intermittently Reviewed-by: dfuchs --- jdk/test/ProblemList.txt | 2 - jdk/test/java/rmi/testlibrary/REGISTRY.java | 40 ++++++++++++---- .../java/rmi/testlibrary/RegistryRunner.java | 34 +++++++++---- .../transport/dgcDeadLock/DGCDeadLock.java | 48 ++++++++++--------- .../rmi/transport/dgcDeadLock/TestImpl.java | 17 ++----- 5 files changed, 85 insertions(+), 56 deletions(-) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index cc645799e09..a9078f3ca6b 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -203,8 +203,6 @@ java/rmi/activation/Activatable/extLoadedImpl/ext.sh 8062724 generic- sun/rmi/rmic/newrmic/equivalence/run.sh 8145980 generic-all -java/rmi/transport/dgcDeadLock/DGCDeadLock.java 8029360 macosx-all - java/rmi/registry/readTest/readTest.sh 7146543 generic-all ############################################################################ diff --git a/jdk/test/java/rmi/testlibrary/REGISTRY.java b/jdk/test/java/rmi/testlibrary/REGISTRY.java index d372198160b..6cd866a70da 100644 --- a/jdk/test/java/rmi/testlibrary/REGISTRY.java +++ b/jdk/test/java/rmi/testlibrary/REGISTRY.java @@ -33,28 +33,48 @@ import java.io.IOException; */ public class REGISTRY extends JavaVM { - private static double startTimeout = 20_000 * TestLibrary.getTimeoutFactor(); + private static final double START_TIMEOUT = + 20_000 * TestLibrary.getTimeoutFactor(); + private static final String DEFAULT_RUNNER = "RegistryRunner"; private int port = -1; - private REGISTRY(OutputStream out, OutputStream err, + private REGISTRY(String runner, OutputStream out, OutputStream err, String options, int port) { - super("RegistryRunner", options, Integer.toString(port), out, err); + super(runner, options, Integer.toString(port), out, err); + try { + Class runnerClass = Class.forName(runner); + if (!RegistryRunner.class.isAssignableFrom(runnerClass)) { + throw new RuntimeException("runner class must be RegistryRunner" + + " or its sub class"); + } + } catch (ClassNotFoundException ex) { + throw new RuntimeException(ex); + } this.port = port; } public static REGISTRY createREGISTRY() { - return createREGISTRY(System.out, System.err, "", 0); + return createREGISTRYWithRunner(DEFAULT_RUNNER, System.out, System.err, "", 0); } public static REGISTRY createREGISTRY(OutputStream out, OutputStream err, String options, int port) { + return createREGISTRYWithRunner(DEFAULT_RUNNER, out, err, options, port); + } + + public static REGISTRY createREGISTRYWithRunner(String runner, String options) { + return createREGISTRYWithRunner(runner, System.out, System.err, options, 0); + } + + public static REGISTRY createREGISTRYWithRunner(String runner, OutputStream out, + OutputStream err, String options, int port) { options += " --add-exports=java.rmi/sun.rmi.registry=ALL-UNNAMED" - + " --add-exports=java.rmi/sun.rmi.server=ALL-UNNAMED" - + " --add-exports=java.rmi/sun.rmi.transport=ALL-UNNAMED" - + " --add-exports=java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED"; - REGISTRY reg = new REGISTRY(out, err, options, port); - return reg; + + " --add-exports=java.rmi/sun.rmi.server=ALL-UNNAMED" + + " --add-exports=java.rmi/sun.rmi.transport=ALL-UNNAMED" + + " --add-exports=java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED"; + REGISTRY reg = new REGISTRY(runner, out, err, options, port); + return reg; } /** @@ -65,7 +85,7 @@ public class REGISTRY extends JavaVM { public void start() throws IOException { super.start(); long startTime = System.currentTimeMillis(); - long deadline = TestLibrary.computeDeadline(startTime, (long)startTimeout); + long deadline = TestLibrary.computeDeadline(startTime, (long)START_TIMEOUT); while (true) { try { Thread.sleep(1000); diff --git a/jdk/test/java/rmi/testlibrary/RegistryRunner.java b/jdk/test/java/rmi/testlibrary/RegistryRunner.java index f79403ca617..af3f4452540 100644 --- a/jdk/test/java/rmi/testlibrary/RegistryRunner.java +++ b/jdk/test/java/rmi/testlibrary/RegistryRunner.java @@ -95,17 +95,17 @@ public class RegistryRunner extends UnicastRemoteObject return port; } - public static void main(String[] args) { - + /** + * port 0 means to use ephemeral port to start registry. + */ + protected static int init(String[] args) { try { if (args.length == 0) { System.err.println("Usage: "); System.exit(0); } int port = -1; - try { - port = Integer.parseInt(args[0]); - } catch (NumberFormatException ignore) { } + port = Integer.parseInt(args[0]); // create a registry registry = LocateRegistry.createRegistry(port); @@ -118,14 +118,30 @@ public class RegistryRunner extends UnicastRemoteObject Naming.rebind("rmi://localhost:" + port + "/RemoteExiter", exiter); - // this output is important for REGISTRY to get the port - // where rmiregistry is serving - System.out.println(PORT_LABEL_START + port + PORT_LABEL_END); - + return port; } catch (Exception e) { System.err.println(e.getMessage()); e.printStackTrace(); System.exit(-1); } + return -1; + } + + /** + * REGISTRY.start() will filter the output of registry subprocess, + * when valid port is detected, REGISTRY.start() returns. + * So, for subclass, it's important to call this method after registry + * is initialized and necessary remote objects have been bound. + */ + protected static void notify(int port) { + // this output is important for REGISTRY to get the port + // where rmiregistry is serving + System.out.println(PORT_LABEL_START + port + PORT_LABEL_END); + System.out.flush(); + } + + public static void main(String[] args) { + int port = init(args); + notify(port); } } diff --git a/jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java b/jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java index 5e0f69ace45..9d700c4786b 100644 --- a/jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java +++ b/jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, 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 @@ -33,7 +33,7 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary Test TestImpl TestImpl_Stub + * @build TestLibrary Test TestImpl REGISTRY RegistryRunner * @run main/othervm/policy=security.policy/timeout=360 DGCDeadLock */ @@ -55,11 +55,12 @@ import java.rmi.*; import java.io.*; public class DGCDeadLock implements Runnable { - private static final int REGISTRY_PORT = TestLibrary.getUnusedRandomPort(); final static public int HOLD_TARGET_TIME = 25000; - public static int TEST_FAIL_TIME = HOLD_TARGET_TIME + 30000; - public static boolean finished = false; - static DGCDeadLock test = new DGCDeadLock(); + public static final double TEST_FAIL_TIME = + (HOLD_TARGET_TIME + 30000) * TestLibrary.getTimeoutFactor(); + public static volatile boolean finished = false; + static final DGCDeadLock test = new DGCDeadLock(); + static volatile int registryPort = -1; static { System.setProperty("sun.rmi.transport.cleanInterval", "50"); @@ -67,7 +68,7 @@ public class DGCDeadLock implements Runnable { static public void main(String[] args) { - JavaVM testImplVM = null; + REGISTRY testImplVM = null; System.err.println("\nregression test for 4118056\n"); TestLibrary.suggestSecurityManager("java.rmi.RMISecurityManager"); @@ -75,18 +76,15 @@ public class DGCDeadLock implements Runnable { try { String options = " -Djava.security.policy=" + TestParams.defaultPolicy + - " --add-exports java.rmi/sun.rmi.registry=ALL-UNNAMED" + - " --add-exports java.rmi/sun.rmi.server=ALL-UNNAMED" + " --add-opens java.rmi/sun.rmi.transport=ALL-UNNAMED" + - " --add-exports java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED" + " -Djava.rmi.dgc.leaseValue=500000" + - " -Dsun.rmi.dgc.checkInterval=" + + " -Dsun.rmi.dgc.checkInterval=" + (HOLD_TARGET_TIME - 5000) + - " -Drmi.registry.port=" + REGISTRY_PORT + "" ; - testImplVM = new JavaVM("TestImpl", options, ""); + testImplVM = REGISTRY.createREGISTRYWithRunner("TestImpl", options); testImplVM.start(); + registryPort = testImplVM.getPort(); synchronized (test) { Thread t = new Thread(test); @@ -94,7 +92,7 @@ public class DGCDeadLock implements Runnable { t.start(); // wait for the remote calls to take place - test.wait(TEST_FAIL_TIME); + test.wait((long)TEST_FAIL_TIME); } if (!finished) { @@ -106,8 +104,12 @@ public class DGCDeadLock implements Runnable { "finished in time."); } catch (Exception e) { - testImplVM = null; - TestLibrary.bomb("test failed", e); + TestLibrary.bomb("test failed in main()", e); + } finally { + if (testImplVM != null) { + testImplVM.shutdown(); + testImplVM = null; + } } } @@ -115,12 +117,9 @@ public class DGCDeadLock implements Runnable { try { String echo = null; - // give the test remote object time to initialize. - Thread.currentThread().sleep(8000); - // create a test client Test foo = (Test) Naming.lookup("rmi://:" + - REGISTRY_PORT + + registryPort + "/Foo"); echo = foo.echo("Hello world"); System.err.println("Test object created."); @@ -139,7 +138,7 @@ public class DGCDeadLock implements Runnable { //import "Bar" Test bar = (Test) Naming.lookup("rmi://:" + - REGISTRY_PORT + + registryPort + "/Bar"); /* infinite loop to show the liveness of Client, @@ -155,11 +154,16 @@ public class DGCDeadLock implements Runnable { finished = true; } catch (RemoteException e) { + System.err.println("catch RemoteException"); + e.printStackTrace(); } } catch (Exception e) { - TestLibrary.bomb("test failed", e); + TestLibrary.bomb("test failed in run()", e); } finally { + synchronized(this) { + notify(); + } } } } diff --git a/jdk/test/java/rmi/transport/dgcDeadLock/TestImpl.java b/jdk/test/java/rmi/transport/dgcDeadLock/TestImpl.java index 774e38ae6db..76af7b759db 100644 --- a/jdk/test/java/rmi/transport/dgcDeadLock/TestImpl.java +++ b/jdk/test/java/rmi/transport/dgcDeadLock/TestImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, 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 @@ -34,7 +34,7 @@ import java.util.*; import java.rmi.registry.*; import java.rmi.server.*; -public class TestImpl extends UnicastRemoteObject +public class TestImpl extends RegistryRunner implements Test { static Thread locker = null; static TestImpl foo = null; @@ -53,12 +53,8 @@ public class TestImpl extends UnicastRemoteObject } static public void main(String[] args) { - Registry registry = null; - try { - int registryPort = Integer.parseInt(System.getProperty("rmi.registry.port")); - registry = java.rmi.registry.LocateRegistry. - createRegistry(registryPort); + int registryPort = RegistryRunner.init(args); //export "Foo" foo = new TestImpl(); @@ -75,16 +71,11 @@ public class TestImpl extends UnicastRemoteObject } catch (Exception e) { throw new RemoteException(e.getMessage()); } - Thread.sleep(DGCDeadLock.TEST_FAIL_TIME); - System.err.println("object vm exiting..."); - System.exit(0); + RegistryRunner.notify(registryPort); } catch (Exception e) { System.err.println(e.getMessage()); e.printStackTrace(); - } finally { - TestLibrary.unexport(registry); - registry = null; } } From 1dbd8833deb380230a730fd81561947fd68b82df Mon Sep 17 00:00:00 2001 From: Amy Lu Date: Wed, 21 Dec 2016 12:15:11 +0800 Subject: [PATCH 09/22] 8171824: Remove OpenNonIntegralNumberOfSampleframes.java and ServerIdentityTest.java from ProblemList Reviewed-by: rriggs --- jdk/test/ProblemList.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index a9078f3ca6b..46772740c6b 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -217,8 +217,6 @@ sun/security/tools/jarsigner/warnings/BadKeyUsageTest.java 8026393 generic- sun/security/ssl/SSLSocketImpl/AsyncSSLSocketClose.java 8161232 macosx-all -sun/net/www/protocol/https/HttpsClient/ServerIdentityTest.java 8171043 windows-all - javax/net/ssl/DTLS/PacketLossRetransmission.java 8169086 macosx-x64 ############################################################################ @@ -232,8 +230,6 @@ javax/sound/sampled/Clip/Drain/ClipDrain.java 7062792 generic-all javax/sound/sampled/Mixers/DisabledAssertionCrash.java 7067310 generic-all -javax/sound/sampled/Clip/OpenNonIntegralNumberOfSampleframes.java 8168881 generic-all - ############################################################################ # jdk_imageio From f75520730b3a006401da1413fe572a101e6b51f1 Mon Sep 17 00:00:00 2001 From: John Jiang Date: Tue, 20 Dec 2016 23:09:27 -0800 Subject: [PATCH 10/22] 8168935: sun/security/ssl/SSLContextImpl/TrustTrustedCert.java failed Intermittently TrustTrustedCert.java uses SSLSocketTemplate to avoid timeout failure Reviewed-by: xuelei --- .../net/ssl/templates/SSLSocketTemplate.java | 8 + .../ssl/SSLContextImpl/TrustTrustedCert.java | 268 +++--------------- 2 files changed, 50 insertions(+), 226 deletions(-) diff --git a/jdk/test/javax/net/ssl/templates/SSLSocketTemplate.java b/jdk/test/javax/net/ssl/templates/SSLSocketTemplate.java index 19bf9f85e04..356abc10e34 100644 --- a/jdk/test/javax/net/ssl/templates/SSLSocketTemplate.java +++ b/jdk/test/javax/net/ssl/templates/SSLSocketTemplate.java @@ -175,6 +175,13 @@ public class SSLSocketTemplate { return false; } + /* + * Configure the server side socket. + */ + protected void configureServerSocket(SSLServerSocket socket) { + + } + /* * ============================================= * Define the client and server side operations. @@ -211,6 +218,7 @@ public class SSLSocketTemplate { SSLServerSocketFactory sslssf = context.getServerSocketFactory(); SSLServerSocket sslServerSocket = (SSLServerSocket)sslssf.createServerSocket(serverPort); + configureServerSocket(sslServerSocket); serverPort = sslServerSocket.getLocalPort(); // Signal the client, the server is ready to accept connection. diff --git a/jdk/test/sun/security/ssl/SSLContextImpl/TrustTrustedCert.java b/jdk/test/sun/security/ssl/SSLContextImpl/TrustTrustedCert.java index b10431b6444..ba7323abcec 100644 --- a/jdk/test/sun/security/ssl/SSLContextImpl/TrustTrustedCert.java +++ b/jdk/test/sun/security/ssl/SSLContextImpl/TrustTrustedCert.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -32,6 +32,7 @@ * @test * @bug 7113275 8164846 * @summary compatibility issue with MD2 trust anchor and old X509TrustManager + * @library /javax/net/ssl/templates * @run main/othervm TrustTrustedCert PKIX TLSv1.1 true * @run main/othervm TrustTrustedCert PKIX TLSv1.1 false * @run main/othervm TrustTrustedCert SunX509 TLSv1.1 false @@ -40,7 +41,6 @@ */ import java.net.*; -import java.util.*; import java.io.*; import javax.net.ssl.*; import java.security.*; @@ -49,21 +49,7 @@ import java.security.spec.*; import java.security.interfaces.*; import java.util.Base64; - -public class TrustTrustedCert { - - /* - * ============================================================= - * 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; +public class TrustTrustedCert extends SSLSocketTemplate { /* * Certificates and key used in the test. @@ -124,89 +110,61 @@ public class TrustTrustedCert { "A5kokFb+E3Gplu29tJvCUpfwgBFRS+wmkvtiaU/tiyDcVgDO+An5DwedxxdVzqiE\n" + "njWHoKY3axDQ8OU=\n"; - static char passphrase[] = "passphrase".toCharArray(); - /* - * Is the server ready to serve? - */ - volatile static boolean serverReady = false; - - /* - * Turn on SSL debugging? - */ - static boolean debug = false; - - /* - * 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 { - SSLContext context = generateSSLContext(); - SSLServerSocketFactory sslssf = context.getServerSocketFactory(); - SSLServerSocket sslServerSocket = - (SSLServerSocket)sslssf.createServerSocket(serverPort); - sslServerSocket.setNeedClientAuth(true); - 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('A'); - sslOS.flush(); - - sslSocket.close(); + @Override + protected SSLContext createServerSSLContext() throws Exception { + return generateSSLContext(); } - /* - * 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 { + @Override + protected void configureServerSocket(SSLServerSocket socket) { + socket.setNeedClientAuth(true); + } - /* - * Wait for server to get started. - */ - while (!serverReady) { - Thread.sleep(50); - } + @Override + protected void runServerApplication(SSLSocket socket) throws Exception { + InputStream sslIS = socket.getInputStream(); + OutputStream sslOS = socket.getOutputStream(); - SSLSocket sslSocket = null; try { - SSLContext context = generateSSLContext(); - SSLSocketFactory sslsf = context.getSocketFactory(); + sslIS.read(); + sslOS.write('A'); + sslOS.flush(); + } catch (SSLHandshakeException e) { + if (expectFail && !e.toString().contains("certificate_unknown")) { + throw new RuntimeException( + "Expected to see certificate_unknown in exception output", + e); + } + } + } - sslSocket = (SSLSocket)sslsf.createSocket("localhost", serverPort); + @Override + protected SSLContext createClientSSLContext() throws Exception { + return generateSSLContext(); + } - // enable the specified TLS protocol - sslSocket.setEnabledProtocols(new String[] {tlsProtocol}); + @Override + protected void runClientApplication(SSLSocket socket) throws Exception { + // enable the specified TLS protocol + socket.setEnabledProtocols(new String[] { tlsProtocol }); - InputStream sslIS = sslSocket.getInputStream(); - OutputStream sslOS = sslSocket.getOutputStream(); + InputStream sslIS = socket.getInputStream(); + OutputStream sslOS = socket.getOutputStream(); + + try { sslOS.write('B'); sslOS.flush(); sslIS.read(); } catch (SSLHandshakeException e) { - // focus in on the CertPathValidatorException + // focus on the CertPathValidatorException Throwable t = e.getCause().getCause(); - if ((t == null) || (expectFail && - !t.toString().contains("MD5withRSA"))) { + if ((t == null) + || (expectFail && !t.toString().contains("MD5withRSA"))) { throw new RuntimeException( - "Expected to see MD5withRSA in exception output " + t); + "Expected to see MD5withRSA in exception output", t); } - } finally { - if (sslSocket != null) sslSocket.close(); } } @@ -343,13 +301,6 @@ public class TrustTrustedCert { } } - - // 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 { /* * Get the customized arguments. @@ -367,144 +318,9 @@ public class TrustTrustedCert { Security.setProperty("jdk.tls.disabledAlgorithms", "SSLv3, RC4, DH keySize < 768"); - if (debug) - System.setProperty("javax.net.debug", "all"); - /* * Start the tests. */ - new TrustTrustedCert(); - } - - Thread clientThread = null; - Thread serverThread = null; - - /* - * Primary constructor, used to drive remainder of the test. - * - * Fork off the other side, then do your work. - */ - TrustTrustedCert() throws Exception { - try { - if (separateServerThread) { - startServer(true); - startClient(false); - } else { - startClient(true); - startServer(false); - } - } catch (Exception e) { - System.out.println("Unexpected exception: "); - e.printStackTrace(); - } - - /* - * Wait for other side to close down. - */ - if (separateServerThread) { - serverThread.join(); - } else { - clientThread.join(); - } - - /* - * When we get here, the test is pretty much over. - * Which side threw the error? - */ - Exception local; - Exception remote; - String whichRemote; - - if (separateServerThread) { - remote = serverException; - local = clientException; - whichRemote = "server"; - } else { - remote = clientException; - local = serverException; - whichRemote = "client"; - } - - /* - * If both failed, return the curthread's exception, but also - * print the remote side Exception - */ - if ((local != null) && (remote != null)) { - System.out.println(whichRemote + " also threw:"); - remote.printStackTrace(); - System.out.println(); - throw local; - } - - if (remote != null) { - throw remote; - } - - if (local != null) { - throw local; - } - } - - 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; - if (!expectFail) { - // only record if we weren't expecting. - // client side will record exception - serverException = e; - } - } - } - }; - serverThread.start(); - } else { - try { - doServerSide(); - } catch (Exception e) { - // only record if we weren't expecting. - // client side will record exception - if (!expectFail) { - 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; - } - } + new TrustTrustedCert().run(); } } From 4879be16e2141b1e8efae2498d3296064a4bb040 Mon Sep 17 00:00:00 2001 From: Bhanu Prakash Gopularam Date: Wed, 21 Dec 2016 08:12:49 +0000 Subject: [PATCH 11/22] 8160036: Java API doc for method minusMonths in LocalDateTime class needs correction Java API doc needs correction Reviewed-by: rriggs, scolebourne --- .../share/classes/java/time/LocalDateTime.java | 8 ++++---- .../share/classes/java/time/OffsetDateTime.java | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/time/LocalDateTime.java b/jdk/src/java.base/share/classes/java/time/LocalDateTime.java index 0366333638d..e10c9c842b2 100644 --- a/jdk/src/java.base/share/classes/java/time/LocalDateTime.java +++ b/jdk/src/java.base/share/classes/java/time/LocalDateTime.java @@ -1407,8 +1407,8 @@ public final class LocalDateTime * *

* For example, 2008-02-29 (leap year) minus one year would result in the - * invalid date 2009-02-29 (standard year). Instead of returning an invalid - * result, the last valid day of the month, 2009-02-28, is selected instead. + * invalid date 2007-02-29 (standard year). Instead of returning an invalid + * result, the last valid day of the month, 2007-02-28, is selected instead. *

* This instance is immutable and unaffected by this method call. * @@ -1431,8 +1431,8 @@ public final class LocalDateTime * *

* For example, 2007-03-31 minus one month would result in the invalid date - * 2007-04-31. Instead of returning an invalid result, the last valid day - * of the month, 2007-04-30, is selected instead. + * 2007-02-31. Instead of returning an invalid result, the last valid day + * of the month, 2007-02-28, is selected instead. *

* This instance is immutable and unaffected by this method call. * diff --git a/jdk/src/java.base/share/classes/java/time/OffsetDateTime.java b/jdk/src/java.base/share/classes/java/time/OffsetDateTime.java index 34c70bce3d7..075638a6f68 100644 --- a/jdk/src/java.base/share/classes/java/time/OffsetDateTime.java +++ b/jdk/src/java.base/share/classes/java/time/OffsetDateTime.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, 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 @@ -1393,8 +1393,8 @@ public final class OffsetDateTime * *

* For example, 2008-02-29 (leap year) minus one year would result in the - * invalid date 2009-02-29 (standard year). Instead of returning an invalid - * result, the last valid day of the month, 2009-02-28, is selected instead. + * invalid date 2007-02-29 (standard year). Instead of returning an invalid + * result, the last valid day of the month, 2007-02-28, is selected instead. *

* This instance is immutable and unaffected by this method call. * @@ -1417,8 +1417,8 @@ public final class OffsetDateTime * *

* For example, 2007-03-31 minus one month would result in the invalid date - * 2007-04-31. Instead of returning an invalid result, the last valid day - * of the month, 2007-04-30, is selected instead. + * 2007-02-31. Instead of returning an invalid result, the last valid day + * of the month, 2007-02-28, is selected instead. *

* This instance is immutable and unaffected by this method call. * @@ -1437,7 +1437,7 @@ public final class OffsetDateTime * the month and year fields as necessary to ensure the result remains valid. * The result is only invalid if the maximum/minimum year is exceeded. *

- * For example, 2008-12-31 minus one week would result in 2009-01-07. + * For example, 2009-01-07 minus one week would result in 2008-12-31. *

* This instance is immutable and unaffected by this method call. * @@ -1456,7 +1456,7 @@ public final class OffsetDateTime * month and year fields as necessary to ensure the result remains valid. * The result is only invalid if the maximum/minimum year is exceeded. *

- * For example, 2008-12-31 minus one day would result in 2009-01-01. + * For example, 2009-01-01 minus one day would result in 2008-12-31. *

* This instance is immutable and unaffected by this method call. * From 6802af0822c8c01ed4f622ae5682b0c574d61c7a Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Wed, 21 Dec 2016 20:16:29 +0530 Subject: [PATCH 12/22] 8170618: jmod should validate if any exported or open package is missing Reviewed-by: jlaskey, chegar --- .../classes/jdk/tools/jmod/JmodTask.java | 20 ++++++++++++++++ .../jdk/tools/jmod/resources/jmod.properties | 1 + jdk/test/tools/jmod/JmodTest.java | 23 ++++++++++++++++++- 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java index ecc53f9ea0a..beb70184f18 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java @@ -74,6 +74,7 @@ import java.util.MissingResourceException; import java.util.Optional; import java.util.ResourceBundle; import java.util.Set; +import java.util.TreeSet; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -497,6 +498,7 @@ public class JmodTask { // Add (or replace) the Packages attribute if (packages != null) { + validatePackages(descriptor, packages); extender.packages(packages); } @@ -530,6 +532,24 @@ public class JmodTask { } } + private void validatePackages(ModuleDescriptor descriptor, Set packages) { + Set nonExistPackages = new TreeSet<>(); + descriptor.exports().stream() + .map(Exports::source) + .filter(pn -> !packages.contains(pn)) + .forEach(nonExistPackages::add); + + descriptor.opens().stream() + .map(Opens::source) + .filter(pn -> !packages.contains(pn)) + .forEach(nonExistPackages::add); + + if (!nonExistPackages.isEmpty()) { + throw new CommandException("err.missing.export.or.open.packages", + descriptor.name(), nonExistPackages); + } + } + /* * Hasher resolves a module graph using the --hash-modules PATTERN * as the roots. diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties index f87810236d0..dbbfd03a74d 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties @@ -107,6 +107,7 @@ err.missing.arg=no value given for {0} err.internal.error=internal error: {0} {1} {2} err.invalid.dryrun.option=--dry-run can only be used with hash mode err.module.descriptor.not.found=Module descriptor not found +err.missing.export.or.open.packages=Packages that are exported or open in {0} are not present: {1} warn.invalid.arg=Invalid classname or pathname not exist: {0} warn.no.module.hashes=No hashes recorded: no module specified for hashing depends on {0} warn.module.resolution.fail=No hashes recorded: {0} diff --git a/jdk/test/tools/jmod/JmodTest.java b/jdk/test/tools/jmod/JmodTest.java index 970320ad9a5..4a6a1c51479 100644 --- a/jdk/test/tools/jmod/JmodTest.java +++ b/jdk/test/tools/jmod/JmodTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8142968 8166568 + * @bug 8142968 8166568 8166286 8170618 * @summary Basic test for jmod * @library /lib/testlibrary * @modules jdk.compiler @@ -114,6 +114,27 @@ public class JmodTest { .assertSuccess(); } + // JDK-8170618 - jmod should validate if any exported or open package is missing + @Test + public void testMissingPackages() throws IOException { + Path apaDir = EXPLODED_DIR.resolve("apa"); + Path classesDir = EXPLODED_DIR.resolve("apa").resolve("classes"); + if (Files.exists(classesDir)) + FileUtils.deleteFileTreeWithRetry(classesDir); + assertTrue(compileModule("apa", classesDir)); + FileUtils.deleteFileTreeWithRetry(classesDir.resolve("jdk")); + Path jmod = MODS_DIR.resolve("apa.jmod"); + jmod("create", + "--class-path", classesDir.toString(), + jmod.toString()) + .assertFailure() + .resultChecker(r -> { + assertContains(r.output, "Packages that are exported or open in apa are not present: [jdk.test.apa]"); + }); + if (Files.exists(classesDir)) + FileUtils.deleteFileTreeWithRetry(classesDir); + } + @Test public void testList() throws IOException { String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); From f986518c51fb9282371c600b60b3dd511ceff730 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Wed, 21 Dec 2016 07:49:36 -0800 Subject: [PATCH 13/22] 8165664: (ch) sun.nio.ch.SocketAdaptor does not respect timeout in case of system date/time change and blocks Change System.currentTimeMillis() to System.nanoTime() Reviewed-by: martin, rriggs --- .../classes/sun/nio/ch/SocketAdaptor.java | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/jdk/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java b/jdk/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java index bf43c8b2317..68d795b3441 100644 --- a/jdk/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java +++ b/jdk/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -31,7 +31,7 @@ import java.nio.*; import java.nio.channels.*; import java.security.AccessController; import java.security.PrivilegedExceptionAction; - +import java.util.concurrent.TimeUnit; // Make a socket channel look like a socket. // @@ -99,17 +99,19 @@ public class SocketAdaptor try { if (sc.connect(remote)) return; - long to = timeout; + long timeoutNanos = + TimeUnit.NANOSECONDS.convert(timeout, + TimeUnit.MILLISECONDS); for (;;) { if (!sc.isOpen()) throw new ClosedChannelException(); - long st = System.currentTimeMillis(); + long startTime = System.nanoTime(); - int result = sc.poll(Net.POLLCONN, to); + int result = sc.poll(Net.POLLCONN, timeout); if (result > 0 && sc.finishConnect()) break; - to -= System.currentTimeMillis() - st; - if (to <= 0) { + timeoutNanos -= System.nanoTime() - startTime; + if (timeoutNanos <= 0) { try { sc.close(); } catch (IOException x) { } @@ -194,18 +196,20 @@ public class SocketAdaptor int n; if ((n = sc.read(bb)) != 0) return n; - long to = timeout; + long timeoutNanos = + TimeUnit.NANOSECONDS.convert(timeout, + TimeUnit.MILLISECONDS); for (;;) { if (!sc.isOpen()) throw new ClosedChannelException(); - long st = System.currentTimeMillis(); - int result = sc.poll(Net.POLLIN, to); + long startTime = System.nanoTime(); + int result = sc.poll(Net.POLLIN, timeout); if (result > 0) { if ((n = sc.read(bb)) != 0) return n; } - to -= System.currentTimeMillis() - st; - if (to <= 0) + timeoutNanos -= System.nanoTime() - startTime; + if (timeoutNanos <= 0) throw new SocketTimeoutException(); } } finally { From 8f9235fc563a8d2d44ca08900b7ab2704496d023 Mon Sep 17 00:00:00 2001 From: Nadeesh TV Date: Wed, 21 Dec 2016 18:45:34 +0000 Subject: [PATCH 14/22] 8145633: Adjacent value parsing not supported for Localized Patterns Enhance the localized weekfields to take part in adjacent value parsing Reviewed-by: rriggs, scolebourne --- .../time/format/DateTimeFormatterBuilder.java | 76 ++++++++++++--- .../time/format/TCKLocalizedFieldParser.java | 93 +++++++++++++++++-- 2 files changed, 152 insertions(+), 17 deletions(-) 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 0e6eb066fd3..0feafd41d09 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 @@ -1774,16 +1774,20 @@ public final class DateTimeFormatterBuilder { if (count > 1) { throw new IllegalArgumentException("Too many pattern letters: " + cur); } - appendInternal(new WeekBasedFieldPrinterParser(cur, count)); + appendValue(new WeekBasedFieldPrinterParser(cur, count, count, count)); } else if (cur == 'w') { // Fields defined by Locale if (count > 2) { throw new IllegalArgumentException("Too many pattern letters: " + cur); } - appendInternal(new WeekBasedFieldPrinterParser(cur, count)); + appendValue(new WeekBasedFieldPrinterParser(cur, count, count, 2)); } else if (cur == 'Y') { // Fields defined by Locale - appendInternal(new WeekBasedFieldPrinterParser(cur, count)); + if (count == 2) { + appendValue(new WeekBasedFieldPrinterParser(cur, count, count, 2)); + } else { + appendValue(new WeekBasedFieldPrinterParser(cur, count, count, 19)); + } } else { throw new IllegalArgumentException("Unknown pattern letter: " + cur); } @@ -1843,7 +1847,10 @@ public final class DateTimeFormatterBuilder { } break; case 'c': - if (count == 2) { + if (count == 1) { + appendValue(new WeekBasedFieldPrinterParser(cur, count, count, count)); + break; + } else if (count == 2) { throw new IllegalArgumentException("Invalid pattern \"cc\""); } /*fallthrough*/ @@ -1858,8 +1865,8 @@ public final class DateTimeFormatterBuilder { switch (count) { case 1: case 2: - if (cur == 'c' || cur == 'e') { - appendInternal(new WeekBasedFieldPrinterParser(cur, count)); + if (cur == 'e') { + appendValue(new WeekBasedFieldPrinterParser(cur, count, count, count)); } else if (cur == 'E') { appendText(field, TextStyle.SHORT); } else { @@ -4770,8 +4777,9 @@ public final class DateTimeFormatterBuilder { * the field is to be printed or parsed. * The locale is needed to select the proper WeekFields from which * the field for day-of-week, week-of-month, or week-of-year is selected. + * Hence the inherited field NumberPrinterParser.field is unused. */ - static final class WeekBasedFieldPrinterParser implements DateTimePrinterParser { + static final class WeekBasedFieldPrinterParser extends NumberPrinterParser { private char chr; private int count; @@ -4780,12 +4788,55 @@ public final class DateTimeFormatterBuilder { * * @param chr the pattern format letter that added this PrinterParser. * @param count the repeat count of the format letter + * @param minWidth the minimum field width, from 1 to 19 + * @param maxWidth the maximum field width, from minWidth to 19 */ - WeekBasedFieldPrinterParser(char chr, int count) { + WeekBasedFieldPrinterParser(char chr, int count, int minWidth, int maxWidth) { + this(chr, count, minWidth, maxWidth, 0); + } + + /** + * Constructor. + * + * @param chr the pattern format letter that added this PrinterParser. + * @param count the repeat count of the format letter + * @param minWidth the minimum field width, from 1 to 19 + * @param maxWidth the maximum field width, from minWidth to 19 + * @param subsequentWidth the width of subsequent non-negative numbers, 0 or greater, + * -1 if fixed width due to active adjacent parsing + */ + WeekBasedFieldPrinterParser(char chr, int count, int minWidth, int maxWidth, + int subsequentWidth) { + super(null, minWidth, maxWidth, SignStyle.NOT_NEGATIVE, subsequentWidth); this.chr = chr; this.count = count; } + /** + * Returns a new instance with fixed width flag set. + * + * @return a new updated printer-parser, not null + */ + @Override + WeekBasedFieldPrinterParser withFixedWidth() { + if (subsequentWidth == -1) { + return this; + } + return new WeekBasedFieldPrinterParser(chr, count, minWidth, maxWidth, -1); + } + + /** + * Returns a new instance with an updated subsequent width. + * + * @param subsequentWidth the width of subsequent non-negative numbers, 0 or greater + * @return a new updated printer-parser, not null + */ + @Override + WeekBasedFieldPrinterParser withSubsequentWidth(int subsequentWidth) { + return new WeekBasedFieldPrinterParser(chr, count, minWidth, maxWidth, + this.subsequentWidth + subsequentWidth); + } + @Override public boolean format(DateTimePrintContext context, StringBuilder buf) { return printerParser(context.getLocale()).format(context, buf); @@ -4810,10 +4861,12 @@ public final class DateTimeFormatterBuilder { case 'Y': field = weekDef.weekBasedYear(); if (count == 2) { - return new ReducedPrinterParser(field, 2, 2, 0, ReducedPrinterParser.BASE_DATE, 0); + return new ReducedPrinterParser(field, 2, 2, 0, ReducedPrinterParser.BASE_DATE, + this.subsequentWidth); } else { return new NumberPrinterParser(field, count, 19, - (count < 4) ? SignStyle.NORMAL : SignStyle.EXCEEDS_PAD, -1); + (count < 4) ? SignStyle.NORMAL : SignStyle.EXCEEDS_PAD, + this.subsequentWidth); } case 'e': case 'c': @@ -4828,7 +4881,8 @@ public final class DateTimeFormatterBuilder { default: throw new IllegalStateException("unreachable"); } - return new NumberPrinterParser(field, (count == 2 ? 2 : 1), 2, SignStyle.NOT_NEGATIVE); + return new NumberPrinterParser(field, minWidth, maxWidth, SignStyle.NOT_NEGATIVE, + this.subsequentWidth); } @Override diff --git a/jdk/test/java/time/tck/java/time/format/TCKLocalizedFieldParser.java b/jdk/test/java/time/tck/java/time/format/TCKLocalizedFieldParser.java index eef99fc7add..6286a1dd321 100644 --- a/jdk/test/java/time/tck/java/time/format/TCKLocalizedFieldParser.java +++ b/jdk/test/java/time/tck/java/time/format/TCKLocalizedFieldParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, 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 @@ -66,9 +66,11 @@ import java.text.ParsePosition; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; +import java.time.format.DateTimeParseException; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalField; import java.time.temporal.WeekFields; +import java.util.Locale; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -79,12 +81,17 @@ import test.java.time.format.AbstractTestPrinterParser; */ @Test public class TCKLocalizedFieldParser extends AbstractTestPrinterParser { - + public static final WeekFields WEEKDEF = WeekFields.of(Locale.US); + public static final TemporalField WEEK_BASED_YEAR = WEEKDEF.weekBasedYear(); + public static final TemporalField WEEK_OF_WEEK_BASED_YEAR = WEEKDEF.weekOfWeekBasedYear(); + public static final TemporalField DAY_OF_WEEK = WEEKDEF.dayOfWeek(); //----------------------------------------------------------------------- @DataProvider(name="FieldPatterns") Object[][] provider_fieldPatterns() { return new Object[][] { - {"e", "6", 0, 1, 6}, + {"e", "6", 0, 1, 6}, + {"ee", "06", 0, 2, 6}, + {"c", "6", 0, 1 , 6}, {"W", "3", 0, 1, 3}, {"w", "29", 0, 2, 29}, {"ww", "29", 0, 2, 29}, @@ -99,6 +106,7 @@ public class TCKLocalizedFieldParser extends AbstractTestPrinterParser { WeekFields weekDef = WeekFields.of(locale); TemporalField field = null; switch(pattern.charAt(0)) { + case 'c' : case 'e' : field = weekDef.dayOfWeek(); break; @@ -176,9 +184,9 @@ public class TCKLocalizedFieldParser extends AbstractTestPrinterParser { {"Y-w-e", "2008-01-1", 0, 9, LocalDate.of(2007, 12, 30)}, {"Y-w-e", "2008-52-1", 0, 9, LocalDate.of(2008, 12, 21)}, {"Y-w-e", "2008-52-7", 0, 9, LocalDate.of(2008, 12, 27)}, - {"Y-w-e", "2009-01-01", 0, 10, LocalDate.of(2008, 12, 28)}, - {"Y-w-e", "2009-01-04", 0, 10, LocalDate.of(2008, 12, 31)}, - {"Y-w-e", "2009-01-05", 0, 10, LocalDate.of(2009, 1, 1)}, + {"Y-w-e", "2009-01-1", 0, 9, LocalDate.of(2008, 12, 28)}, + {"Y-w-e", "2009-01-4", 0, 9, LocalDate.of(2008, 12, 31)}, + {"Y-w-e", "2009-01-5", 0, 9, LocalDate.of(2009, 1, 1)}, }; } @@ -202,4 +210,77 @@ public class TCKLocalizedFieldParser extends AbstractTestPrinterParser { } } + //----------------------------------------------------------------------- + @DataProvider(name = "adjacentValuePatterns1") + Object[][] provider_adjacentValuePatterns1() { + return new Object[][] { + {"YYww", WEEK_BASED_YEAR, WEEK_OF_WEEK_BASED_YEAR, "1612", 2016, 12}, + {"YYYYww", WEEK_BASED_YEAR, WEEK_OF_WEEK_BASED_YEAR, "201612", 2016, 12}, + }; + } + + @Test(dataProvider = "adjacentValuePatterns1") + public void test_adjacentValuePatterns1(String pattern, TemporalField field1, TemporalField field2, + String text, int expected1, int expected2) { + DateTimeFormatter df = new DateTimeFormatterBuilder() + .appendPattern(pattern).toFormatter(Locale.US); + ParsePosition ppos = new ParsePosition(0); + TemporalAccessor parsed = df.parseUnresolved(text, ppos); + assertEquals(parsed.get(field1), expected1); + assertEquals(parsed.get(field2), expected2); + } + + @DataProvider(name = "adjacentValuePatterns2") + Object[][] provider_adjacentValuePatterns2() { + return new Object[][] { + {"YYYYwwc", WEEK_BASED_YEAR, WEEK_OF_WEEK_BASED_YEAR, DAY_OF_WEEK, + "2016121", 2016, 12, 1}, + {"YYYYwwee", WEEK_BASED_YEAR, WEEK_OF_WEEK_BASED_YEAR, DAY_OF_WEEK, + "20161201", 2016, 12, 1}, + {"YYYYwwe", WEEK_BASED_YEAR, WEEK_OF_WEEK_BASED_YEAR, DAY_OF_WEEK, + "2016121", 2016, 12, 1}, + }; + } + + @Test(dataProvider = "adjacentValuePatterns2") + public void test_adjacentValuePatterns2(String pattern, TemporalField field1, TemporalField field2, + TemporalField field3, String text, int expected1, int expected2, int expected3) { + DateTimeFormatter df = new DateTimeFormatterBuilder() + .appendPattern(pattern).toFormatter(Locale.US); + ParsePosition ppos = new ParsePosition(0); + TemporalAccessor parsed = df.parseUnresolved(text, ppos); + assertEquals(parsed.get(field1), expected1); + assertEquals(parsed.get(field2), expected2); + assertEquals(parsed.get(field3), expected3); + } + + @Test + public void test_adjacentValuePatterns3() { + String pattern = "yyyyMMddwwc"; + String text = "20120720296"; + DateTimeFormatter df = new DateTimeFormatterBuilder() + .appendPattern(pattern).toFormatter(Locale.US); + ParsePosition ppos = new ParsePosition(0); + TemporalAccessor parsed = df.parseUnresolved(text, ppos); + assertEquals(parsed.get(DAY_OF_WEEK), 6); + assertEquals(parsed.get(WEEK_OF_WEEK_BASED_YEAR), 29); + LocalDate result = LocalDate.parse(text, df); + LocalDate expectedValue = LocalDate.of(2012, 07, 20); + assertEquals(result, expectedValue, "LocalDate incorrect for " + pattern); + } + + @DataProvider(name = "invalidPatterns") + Object[][] provider_invalidPatterns() { + return new Object[][] { + {"W", "01"}, + {"c", "01"}, + {"e", "01"}, + {"yyyyMMddwwc", "201207202906"}, // 1 extra digit in the input + }; + } + + @Test(dataProvider = "invalidPatterns", expectedExceptions = DateTimeParseException.class) + public void test_invalidPatterns(String pattern, String value) { + DateTimeFormatter.ofPattern(pattern).parse(value); + } } From ce3243b0a66718bf30231226673e9a98b7a1bdc2 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Wed, 21 Dec 2016 11:54:42 -0800 Subject: [PATCH 15/22] 8056205: (fs) Potential for NPE in Files.walkFileTree if closing directory fails Change incorrect ioe != null to ioe == null Reviewed-by: rriggs --- .../share/classes/java/nio/file/FileTreeWalker.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/nio/file/FileTreeWalker.java b/jdk/src/java.base/share/classes/java/nio/file/FileTreeWalker.java index b7dc93ad0f5..f1ad8d0804d 100644 --- a/jdk/src/java.base/share/classes/java/nio/file/FileTreeWalker.java +++ b/jdk/src/java.base/share/classes/java/nio/file/FileTreeWalker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -353,12 +353,13 @@ class FileTreeWalker implements Closeable { } } - // no next entry so close and pop directory, creating corresponding event + // no next entry so close and pop directory, + // creating corresponding event if (entry == null) { try { top.stream().close(); } catch (IOException e) { - if (ioe != null) { + if (ioe == null) { ioe = e; } else { ioe.addSuppressed(e); From bdab1d842f968d66ce38e0db0eb10f0aaaf95100 Mon Sep 17 00:00:00 2001 From: Doug Lea Date: Wed, 21 Dec 2016 14:22:53 -0800 Subject: [PATCH 16/22] 8171051: LinkedBlockingQueue spliterator needs to support node self-linking Reviewed-by: martin, smarks, psandoz --- .../util/concurrent/LinkedBlockingDeque.java | 243 ++++++++++------- .../util/concurrent/LinkedBlockingQueue.java | 245 +++++++++++------- .../util/concurrent/tck/Collection8Test.java | 219 +++++++++++++++- .../tck/LinkedBlockingDeque8Test.java | 76 ++++++ .../tck/LinkedBlockingQueue8Test.java | 76 ++++++ 5 files changed, 661 insertions(+), 198 deletions(-) create mode 100644 jdk/test/java/util/concurrent/tck/LinkedBlockingDeque8Test.java create mode 100644 jdk/test/java/util/concurrent/tck/LinkedBlockingQueue8Test.java diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/LinkedBlockingDeque.java b/jdk/src/java.base/share/classes/java/util/concurrent/LinkedBlockingDeque.java index 708ab3d1820..7f653e844b5 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/LinkedBlockingDeque.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/LinkedBlockingDeque.java @@ -39,6 +39,7 @@ import java.util.AbstractQueue; import java.util.Collection; import java.util.Iterator; import java.util.NoSuchElementException; +import java.util.Objects; import java.util.Spliterator; import java.util.Spliterators; import java.util.concurrent.locks.Condition; @@ -740,8 +741,7 @@ public class LinkedBlockingDeque * @throws IllegalArgumentException {@inheritDoc} */ public int drainTo(Collection c, int maxElements) { - if (c == null) - throw new NullPointerException(); + Objects.requireNonNull(c); if (c == this) throw new IllegalArgumentException(); if (maxElements <= 0) @@ -985,6 +985,16 @@ public class LinkedBlockingDeque } } + /** + * Used for any element traversal that is not entirely under lock. + * Such traversals must handle both: + * - dequeued nodes (p.next == p) + * - (possibly multiple) interior removed nodes (p.item == null) + */ + Node succ(Node p) { + return (p == (p = p.next)) ? first : p; + } + /** * Returns an iterator over the elements in this deque in proper sequence. * The elements will be returned in order from first (head) to last (tail). @@ -1024,8 +1034,8 @@ public class LinkedBlockingDeque /** * nextItem holds on to item fields because once we claim that * an element exists in hasNext(), we must return item read - * under lock (in advance()) even if it was in the process of - * being removed when hasNext() was called. + * under lock even if it was in the process of being removed + * when hasNext() was called. */ E nextItem; @@ -1038,48 +1048,17 @@ public class LinkedBlockingDeque abstract Node firstNode(); abstract Node nextNode(Node n); + private Node succ(Node p) { + return (p == (p = nextNode(p))) ? firstNode() : p; + } + AbstractItr() { // set to initial position final ReentrantLock lock = LinkedBlockingDeque.this.lock; lock.lock(); try { - next = firstNode(); - nextItem = (next == null) ? null : next.item; - } finally { - lock.unlock(); - } - } - - /** - * Returns the successor node of the given non-null, but - * possibly previously deleted, node. - */ - private Node succ(Node n) { - // Chains of deleted nodes ending in null or self-links - // are possible if multiple interior nodes are removed. - for (;;) { - Node s = nextNode(n); - if (s == null) - return null; - else if (s.item != null) - return s; - else if (s == n) - return firstNode(); - else - n = s; - } - } - - /** - * Advances next. - */ - void advance() { - final ReentrantLock lock = LinkedBlockingDeque.this.lock; - lock.lock(); - try { - // assert next != null; - next = succ(next); - nextItem = (next == null) ? null : next.item; + if ((next = firstNode()) != null) + nextItem = next.item; } finally { lock.unlock(); } @@ -1090,14 +1069,65 @@ public class LinkedBlockingDeque } public E next() { - if (next == null) + Node p; + if ((p = next) == null) throw new NoSuchElementException(); - lastRet = next; + lastRet = p; E x = nextItem; - advance(); + final ReentrantLock lock = LinkedBlockingDeque.this.lock; + lock.lock(); + try { + E e = null; + for (p = nextNode(p); p != null && (e = p.item) == null; ) + p = succ(p); + next = p; + nextItem = e; + } finally { + lock.unlock(); + } return x; } + public void forEachRemaining(Consumer action) { + // A variant of forEachFrom + Objects.requireNonNull(action); + Node p; + if ((p = next) == null) return; + lastRet = p; + next = null; + final ReentrantLock lock = LinkedBlockingDeque.this.lock; + final int batchSize = 32; + Object[] es = null; + int n, len = 1; + do { + lock.lock(); + try { + if (es == null) { + p = nextNode(p); + for (Node q = p; q != null; q = succ(q)) + if (q.item != null && ++len == batchSize) + break; + es = new Object[len]; + es[0] = nextItem; + nextItem = null; + n = 1; + } else + n = 0; + for (; p != null && n < len; p = succ(p)) + if ((es[n] = p.item) != null) { + lastRet = p; + n++; + } + } finally { + lock.unlock(); + } + for (int i = 0; i < n; i++) { + @SuppressWarnings("unchecked") E e = (E) es[i]; + action.accept(e); + } + } while (n > 0 && p != null); + } + public void remove() { Node n = lastRet; if (n == null) @@ -1116,25 +1146,30 @@ public class LinkedBlockingDeque /** Forward iterator */ private class Itr extends AbstractItr { + Itr() {} // prevent access constructor creation Node firstNode() { return first; } Node nextNode(Node n) { return n.next; } } /** Descending iterator */ private class DescendingItr extends AbstractItr { + DescendingItr() {} // prevent access constructor creation Node firstNode() { return last; } Node nextNode(Node n) { return n.prev; } } - /** A customized variant of Spliterators.IteratorSpliterator */ + /** + * A customized variant of Spliterators.IteratorSpliterator. + * Keep this class in sync with (very similar) LBQSpliterator. + */ private final class LBDSpliterator implements Spliterator { static final int MAX_BATCH = 1 << 25; // max batch array size; Node current; // current node; null until initialized int batch; // batch size for splits boolean exhausted; // true when no more nodes - long est; // size estimate + long est = size(); // size estimate - LBDSpliterator() { est = size(); } + LBDSpliterator() {} public long estimateSize() { return est; } @@ -1143,8 +1178,7 @@ public class LinkedBlockingDeque int b = batch; int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1; if (!exhausted && - (((h = current) != null && h != h.next) - || (h = first) != null) + ((h = current) != null || (h = first) != null) && h.next != null) { Object[] a = new Object[n]; final ReentrantLock lock = LinkedBlockingDeque.this.lock; @@ -1152,10 +1186,10 @@ public class LinkedBlockingDeque Node p = current; lock.lock(); try { - if (((p != null && p != p.next) || (p = first) != null) - && p.item != null) - for (; p != null && i < n; p = p.next) - a[i++] = p.item; + if (p != null || (p = first) != null) + for (; p != null && i < n; p = succ(p)) + if ((a[i] = p.item) != null) + i++; } finally { lock.unlock(); } @@ -1176,51 +1210,39 @@ public class LinkedBlockingDeque return null; } - public void forEachRemaining(Consumer action) { - if (action == null) throw new NullPointerException(); - if (exhausted) - return; - exhausted = true; - final ReentrantLock lock = LinkedBlockingDeque.this.lock; - Node p = current; - current = null; - do { + public boolean tryAdvance(Consumer action) { + Objects.requireNonNull(action); + if (!exhausted) { E e = null; + final ReentrantLock lock = LinkedBlockingDeque.this.lock; lock.lock(); try { - if ((p != null && p != p.next) || (p = first) != null) { - e = p.item; - p = p.next; - } + Node p; + if ((p = current) != null || (p = first) != null) + do { + e = p.item; + p = succ(p); + } while (e == null && p != null); + exhausted = ((current = p) == null); } finally { lock.unlock(); } - if (e != null) + if (e != null) { action.accept(e); - } while (p != null); + return true; + } + } + return false; } - public boolean tryAdvance(Consumer action) { - if (action == null) throw new NullPointerException(); - if (exhausted) - return false; - final ReentrantLock lock = LinkedBlockingDeque.this.lock; - Node p = current; - E e = null; - lock.lock(); - try { - if ((p != null && p != p.next) || (p = first) != null) { - e = p.item; - p = p.next; - } - } finally { - lock.unlock(); + public void forEachRemaining(Consumer action) { + Objects.requireNonNull(action); + if (!exhausted) { + exhausted = true; + Node p = current; + current = null; + forEachFrom(action, p); } - exhausted = ((current = p) == null); - if (e == null) - return false; - action.accept(e); - return true; } public int characteristics() { @@ -1250,6 +1272,48 @@ public class LinkedBlockingDeque return new LBDSpliterator(); } + /** + * @throws NullPointerException {@inheritDoc} + */ + public void forEach(Consumer action) { + Objects.requireNonNull(action); + forEachFrom(action, null); + } + + /** + * Runs action on each element found during a traversal starting at p. + * If p is null, traversal starts at head. + */ + void forEachFrom(Consumer action, Node p) { + // Extract batches of elements while holding the lock; then + // run the action on the elements while not + final ReentrantLock lock = this.lock; + final int batchSize = 32; // max number of elements per batch + Object[] es = null; // container for batch of elements + int n, len = 0; + do { + lock.lock(); + try { + if (es == null) { + if (p == null) p = first; + for (Node q = p; q != null; q = succ(q)) + if (q.item != null && ++len == batchSize) + break; + es = new Object[len]; + } + for (n = 0; p != null && n < len; p = succ(p)) + if ((es[n] = p.item) != null) + n++; + } finally { + lock.unlock(); + } + for (int i = 0; i < n; i++) { + @SuppressWarnings("unchecked") E e = (E) es[i]; + action.accept(e); + } + } while (n > 0 && p != null); + } + /** * Saves this deque to a stream (that is, serializes it). * @@ -1290,8 +1354,7 @@ public class LinkedBlockingDeque last = null; // Read in all elements and place in queue for (;;) { - @SuppressWarnings("unchecked") - E item = (E)s.readObject(); + @SuppressWarnings("unchecked") E item = (E)s.readObject(); if (item == null) break; add(item); diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/LinkedBlockingQueue.java b/jdk/src/java.base/share/classes/java/util/concurrent/LinkedBlockingQueue.java index 95c6f2cdc1b..f60b4f6bfa0 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/LinkedBlockingQueue.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/LinkedBlockingQueue.java @@ -39,6 +39,7 @@ import java.util.AbstractQueue; import java.util.Collection; import java.util.Iterator; import java.util.NoSuchElementException; +import java.util.Objects; import java.util.Spliterator; import java.util.Spliterators; import java.util.concurrent.atomic.AtomicInteger; @@ -234,14 +235,6 @@ public class LinkedBlockingQueue extends AbstractQueue putLock.unlock(); } -// /** -// * Tells whether both locks are held by current thread. -// */ -// boolean isFullyLocked() { -// return (putLock.isHeldByCurrentThread() && -// takeLock.isHeldByCurrentThread()); -// } - /** * Creates a {@code LinkedBlockingQueue} with a capacity of * {@link Integer#MAX_VALUE}. @@ -517,7 +510,8 @@ public class LinkedBlockingQueue extends AbstractQueue * Unlinks interior Node p with predecessor trail. */ void unlink(Node p, Node trail) { - // assert isFullyLocked(); + // assert putLock.isHeldByCurrentThread(); + // assert takeLock.isHeldByCurrentThread(); // p.next is not changed, to allow iterators that are // traversing p to maintain their weak-consistency guarantee. p.item = null; @@ -701,8 +695,7 @@ public class LinkedBlockingQueue extends AbstractQueue * @throws IllegalArgumentException {@inheritDoc} */ public int drainTo(Collection c, int maxElements) { - if (c == null) - throw new NullPointerException(); + Objects.requireNonNull(c); if (c == this) throw new IllegalArgumentException(); if (maxElements <= 0) @@ -740,6 +733,16 @@ public class LinkedBlockingQueue extends AbstractQueue } } + /** + * Used for any element traversal that is not entirely under lock. + * Such traversals must handle both: + * - dequeued nodes (p.next == p) + * - (possibly multiple) interior removed nodes (p.item == null) + */ + Node succ(Node p) { + return (p == (p = p.next)) ? head.next : p; + } + /** * Returns an iterator over the elements in this queue in proper sequence. * The elements will be returned in order from first (head) to last (tail). @@ -760,48 +763,80 @@ public class LinkedBlockingQueue extends AbstractQueue * still have it to return even if lost race with a take etc. */ - private Node current; + private Node next; + private E nextItem; private Node lastRet; - private E currentElement; Itr() { fullyLock(); try { - current = head.next; - if (current != null) - currentElement = current.item; + if ((next = head.next) != null) + nextItem = next.item; } finally { fullyUnlock(); } } public boolean hasNext() { - return current != null; + return next != null; } public E next() { + Node p; + if ((p = next) == null) + throw new NoSuchElementException(); + lastRet = p; + E x = nextItem; fullyLock(); try { - if (current == null) - throw new NoSuchElementException(); - lastRet = current; - E item = null; - // Unlike other traversal methods, iterators must handle both: - // - dequeued nodes (p.next == p) - // - (possibly multiple) interior removed nodes (p.item == null) - for (Node p = current, q;; p = q) { - if ((q = p.next) == p) - q = head.next; - if (q == null || (item = q.item) != null) { - current = q; - E x = currentElement; - currentElement = item; - return x; - } - } + E e = null; + for (p = p.next; p != null && (e = p.item) == null; ) + p = succ(p); + next = p; + nextItem = e; } finally { fullyUnlock(); } + return x; + } + + public void forEachRemaining(Consumer action) { + // A variant of forEachFrom + Objects.requireNonNull(action); + Node p; + if ((p = next) == null) return; + lastRet = p; + next = null; + final int batchSize = 32; + Object[] es = null; + int n, len = 1; + do { + fullyLock(); + try { + if (es == null) { + p = p.next; + for (Node q = p; q != null; q = succ(q)) + if (q.item != null && ++len == batchSize) + break; + es = new Object[len]; + es[0] = nextItem; + nextItem = null; + n = 1; + } else + n = 0; + for (; p != null && n < len; p = succ(p)) + if ((es[n] = p.item) != null) { + lastRet = p; + n++; + } + } finally { + fullyUnlock(); + } + for (int i = 0; i < n; i++) { + @SuppressWarnings("unchecked") E e = (E) es[i]; + action.accept(e); + } + } while (n > 0 && p != null); } public void remove() { @@ -825,42 +860,39 @@ public class LinkedBlockingQueue extends AbstractQueue } } - /** A customized variant of Spliterators.IteratorSpliterator */ - static final class LBQSpliterator implements Spliterator { + /** + * A customized variant of Spliterators.IteratorSpliterator. + * Keep this class in sync with (very similar) LBDSpliterator. + */ + private final class LBQSpliterator implements Spliterator { static final int MAX_BATCH = 1 << 25; // max batch array size; - final LinkedBlockingQueue queue; Node current; // current node; null until initialized int batch; // batch size for splits boolean exhausted; // true when no more nodes - long est; // size estimate - LBQSpliterator(LinkedBlockingQueue queue) { - this.queue = queue; - this.est = queue.size(); - } + long est = size(); // size estimate + + LBQSpliterator() {} public long estimateSize() { return est; } public Spliterator trySplit() { Node h; - final LinkedBlockingQueue q = this.queue; int b = batch; int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1; if (!exhausted && - ((h = current) != null || (h = q.head.next) != null) && - h.next != null) { + ((h = current) != null || (h = head.next) != null) + && h.next != null) { Object[] a = new Object[n]; int i = 0; Node p = current; - q.fullyLock(); + fullyLock(); try { - if (p != null || (p = q.head.next) != null) { - do { + if (p != null || (p = head.next) != null) + for (; p != null && i < n; p = succ(p)) if ((a[i] = p.item) != null) - ++i; - } while ((p = p.next) != null && i < n); - } + i++; } finally { - q.fullyUnlock(); + fullyUnlock(); } if ((current = p) == null) { est = 0L; @@ -879,53 +911,22 @@ public class LinkedBlockingQueue extends AbstractQueue return null; } - public void forEachRemaining(Consumer action) { - if (action == null) throw new NullPointerException(); - final LinkedBlockingQueue q = this.queue; - if (!exhausted) { - exhausted = true; - Node p = current; - do { - E e = null; - q.fullyLock(); - try { - if (p == null) - p = q.head.next; - while (p != null) { - e = p.item; - p = p.next; - if (e != null) - break; - } - } finally { - q.fullyUnlock(); - } - if (e != null) - action.accept(e); - } while (p != null); - } - } - public boolean tryAdvance(Consumer action) { - if (action == null) throw new NullPointerException(); - final LinkedBlockingQueue q = this.queue; + Objects.requireNonNull(action); if (!exhausted) { E e = null; - q.fullyLock(); + fullyLock(); try { - if (current == null) - current = q.head.next; - while (current != null) { - e = current.item; - current = current.next; - if (e != null) - break; - } + Node p; + if ((p = current) != null || (p = head.next) != null) + do { + e = p.item; + p = succ(p); + } while (e == null && p != null); + exhausted = ((current = p) == null); } finally { - q.fullyUnlock(); + fullyUnlock(); } - if (current == null) - exhausted = true; if (e != null) { action.accept(e); return true; @@ -934,9 +935,20 @@ public class LinkedBlockingQueue extends AbstractQueue return false; } + public void forEachRemaining(Consumer action) { + Objects.requireNonNull(action); + if (!exhausted) { + exhausted = true; + Node p = current; + current = null; + forEachFrom(action, p); + } + } + public int characteristics() { - return Spliterator.ORDERED | Spliterator.NONNULL | - Spliterator.CONCURRENT; + return (Spliterator.ORDERED | + Spliterator.NONNULL | + Spliterator.CONCURRENT); } } @@ -957,7 +969,48 @@ public class LinkedBlockingQueue extends AbstractQueue * @since 1.8 */ public Spliterator spliterator() { - return new LBQSpliterator(this); + return new LBQSpliterator(); + } + + /** + * @throws NullPointerException {@inheritDoc} + */ + public void forEach(Consumer action) { + Objects.requireNonNull(action); + forEachFrom(action, null); + } + + /** + * Runs action on each element found during a traversal starting at p. + * If p is null, traversal starts at head. + */ + void forEachFrom(Consumer action, Node p) { + // Extract batches of elements while holding the lock; then + // run the action on the elements while not + final int batchSize = 32; // max number of elements per batch + Object[] es = null; // container for batch of elements + int n, len = 0; + do { + fullyLock(); + try { + if (es == null) { + if (p == null) p = head.next; + for (Node q = p; q != null; q = succ(q)) + if (q.item != null && ++len == batchSize) + break; + es = new Object[len]; + } + for (n = 0; p != null && n < len; p = succ(p)) + if ((es[n] = p.item) != null) + n++; + } finally { + fullyUnlock(); + } + for (int i = 0; i < n; i++) { + @SuppressWarnings("unchecked") E e = (E) es[i]; + action.accept(e); + } + } while (n > 0 && p != null); } /** diff --git a/jdk/test/java/util/concurrent/tck/Collection8Test.java b/jdk/test/java/util/concurrent/tck/Collection8Test.java index 8d7e48c8764..d58b367171f 100644 --- a/jdk/test/java/util/concurrent/tck/Collection8Test.java +++ b/jdk/test/java/util/concurrent/tck/Collection8Test.java @@ -39,6 +39,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.ConcurrentModificationException; import java.util.Deque; import java.util.HashSet; import java.util.Iterator; @@ -368,10 +369,113 @@ public class Collection8Test extends JSR166TestCase { } } + /** + * All elements removed in the middle of CONCURRENT traversal. + */ + public void testElementRemovalDuringTraversal() { + Collection c = impl.emptyCollection(); + ThreadLocalRandom rnd = ThreadLocalRandom.current(); + int n = rnd.nextInt(6); + ArrayList copy = new ArrayList(); + for (int i = 0; i < n; i++) { + Object x = impl.makeElement(i); + copy.add(x); + c.add(x); + } + ArrayList iterated = new ArrayList(); + ArrayList spliterated = new ArrayList(); + Spliterator s = c.spliterator(); + Iterator it = c.iterator(); + for (int i = rnd.nextInt(n + 1); --i >= 0; ) { + assertTrue(s.tryAdvance(spliterated::add)); + if (rnd.nextBoolean()) assertTrue(it.hasNext()); + iterated.add(it.next()); + } + Consumer alwaysThrows = e -> { throw new AssertionError(); }; + if (s.hasCharacteristics(Spliterator.CONCURRENT)) { + c.clear(); // TODO: many more removal methods + if (testImplementationDetails + && !(c instanceof java.util.concurrent.ArrayBlockingQueue)) { + if (rnd.nextBoolean()) + assertFalse(s.tryAdvance(alwaysThrows)); + else + s.forEachRemaining(alwaysThrows); + } + if (it.hasNext()) iterated.add(it.next()); + if (rnd.nextBoolean()) assertIteratorExhausted(it); + } + assertTrue(copy.containsAll(iterated)); + assertTrue(copy.containsAll(spliterated)); + } + + /** + * Some elements randomly disappear in the middle of traversal. + */ + public void testRandomElementRemovalDuringTraversal() { + Collection c = impl.emptyCollection(); + ThreadLocalRandom rnd = ThreadLocalRandom.current(); + int n = rnd.nextInt(6); + ArrayList copy = new ArrayList(); + for (int i = 0; i < n; i++) { + Object x = impl.makeElement(i); + copy.add(x); + c.add(x); + } + ArrayList iterated = new ArrayList(); + ArrayList spliterated = new ArrayList(); + ArrayList removed = new ArrayList(); + Spliterator s = c.spliterator(); + Iterator it = c.iterator(); + if (! (s.hasCharacteristics(Spliterator.CONCURRENT) || + s.hasCharacteristics(Spliterator.IMMUTABLE))) + return; + for (int i = rnd.nextInt(n + 1); --i >= 0; ) { + assertTrue(s.tryAdvance(e -> {})); + if (rnd.nextBoolean()) assertTrue(it.hasNext()); + it.next(); + } + Consumer alwaysThrows = e -> { throw new AssertionError(); }; + // TODO: many more removal methods + if (rnd.nextBoolean()) { + for (Iterator z = c.iterator(); z.hasNext(); ) { + Object e = z.next(); + if (rnd.nextBoolean()) { + try { + z.remove(); + } catch (UnsupportedOperationException ok) { return; } + removed.add(e); + } + } + } else { + Predicate randomlyRemove = e -> { + if (rnd.nextBoolean()) { removed.add(e); return true; } + else return false; + }; + c.removeIf(randomlyRemove); + } + s.forEachRemaining(spliterated::add); + while (it.hasNext()) + iterated.add(it.next()); + assertTrue(copy.containsAll(iterated)); + assertTrue(copy.containsAll(spliterated)); + assertTrue(copy.containsAll(removed)); + if (s.hasCharacteristics(Spliterator.CONCURRENT)) { + ArrayList iteratedAndRemoved = new ArrayList(iterated); + ArrayList spliteratedAndRemoved = new ArrayList(spliterated); + iteratedAndRemoved.retainAll(removed); + spliteratedAndRemoved.retainAll(removed); + assertTrue(iteratedAndRemoved.size() <= 1); + assertTrue(spliteratedAndRemoved.size() <= 1); + if (testImplementationDetails + && !(c instanceof java.util.concurrent.ArrayBlockingQueue)) + assertTrue(spliteratedAndRemoved.isEmpty()); + } + } + /** * Various ways of traversing a collection yield same elements */ - public void testIteratorEquivalence() { + public void testTraversalEquivalence() { Collection c = impl.emptyCollection(); ThreadLocalRandom rnd = ThreadLocalRandom.current(); int n = rnd.nextInt(6); @@ -438,6 +542,43 @@ public class Collection8Test extends JSR166TestCase { } } + /** + * Iterator.forEachRemaining has same behavior as Iterator's + * default implementation. + */ + public void testForEachRemainingConsistentWithDefaultImplementation() { + Collection c = impl.emptyCollection(); + if (!testImplementationDetails + || c.getClass() == java.util.LinkedList.class) + return; + ThreadLocalRandom rnd = ThreadLocalRandom.current(); + int n = 1 + rnd.nextInt(3); + for (int i = 0; i < n; i++) c.add(impl.makeElement(i)); + ArrayList iterated = new ArrayList(); + ArrayList iteratedForEachRemaining = new ArrayList(); + Iterator it1 = c.iterator(); + Iterator it2 = c.iterator(); + assertTrue(it1.hasNext()); + assertTrue(it2.hasNext()); + c.clear(); + Object r1, r2; + try { + while (it1.hasNext()) iterated.add(it1.next()); + r1 = iterated; + } catch (ConcurrentModificationException ex) { + r1 = ConcurrentModificationException.class; + assertFalse(impl.isConcurrent()); + } + try { + it2.forEachRemaining(iteratedForEachRemaining::add); + r2 = iteratedForEachRemaining; + } catch (ConcurrentModificationException ex) { + r2 = ConcurrentModificationException.class; + assertFalse(impl.isConcurrent()); + } + assertEquals(r1, r2); + } + /** * Calling Iterator#remove() after Iterator#forEachRemaining * should (maybe) remove last element @@ -577,6 +718,41 @@ public class Collection8Test extends JSR166TestCase { assertTrue(found.isEmpty()); } + /** TODO: promote to a common utility */ + static T chooseOne(T ... ts) { + return ts[ThreadLocalRandom.current().nextInt(ts.length)]; + } + + /** TODO: more random adders and removers */ + static Runnable adderRemover(Collection c, E e) { + return chooseOne( + () -> { + assertTrue(c.add(e)); + assertTrue(c.contains(e)); + assertTrue(c.remove(e)); + assertFalse(c.contains(e)); + }, + () -> { + assertTrue(c.add(e)); + assertTrue(c.contains(e)); + assertTrue(c.removeIf(x -> x == e)); + assertFalse(c.contains(e)); + }, + () -> { + assertTrue(c.add(e)); + assertTrue(c.contains(e)); + for (Iterator it = c.iterator();; ) + if (it.next() == e) { + try { it.remove(); } + catch (UnsupportedOperationException ok) { + c.remove(e); + } + break; + } + assertFalse(c.contains(e)); + }); + } + /** * Motley crew of threads concurrently randomly hammer the collection. */ @@ -616,17 +792,20 @@ public class Collection8Test extends JSR166TestCase { () -> checkArraySanity.accept(c.toArray()), () -> checkArraySanity.accept(c.toArray(emptyArray)), () -> { - assertTrue(c.add(one)); - assertTrue(c.contains(one)); - assertTrue(c.remove(one)); - assertFalse(c.contains(one)); - }, - () -> { - assertTrue(c.add(two)); - assertTrue(c.contains(two)); - assertTrue(c.remove(two)); - assertFalse(c.contains(two)); - }, + Object[] a = new Object[5]; + Object three = impl.makeElement(3); + Arrays.fill(a, 0, a.length, three); + Object[] x = c.toArray(a); + if (x == a) + for (int i = 0; i < a.length && a[i] != null; i++) + checkSanity.accept(a[i]); + // A careful reading of the spec does not support: + // for (i++; i < a.length; i++) assertSame(three, a[i]); + else + checkArraySanity.accept(x); + }, + adderRemover(c, one), + adderRemover(c, two), }; final List tasks = Arrays.stream(frobbers) @@ -684,6 +863,22 @@ public class Collection8Test extends JSR166TestCase { } } + /** + * Spliterator.getComparator throws IllegalStateException iff the + * spliterator does not report SORTED. + */ + public void testGetComparator_IllegalStateException() { + Collection c = impl.emptyCollection(); + Spliterator s = c.spliterator(); + boolean reportsSorted = s.hasCharacteristics(Spliterator.SORTED); + try { + s.getComparator(); + assertTrue(reportsSorted); + } catch (IllegalStateException ex) { + assertFalse(reportsSorted); + } + } + // public void testCollection8DebugFail() { // fail(impl.klazz().getSimpleName()); // } diff --git a/jdk/test/java/util/concurrent/tck/LinkedBlockingDeque8Test.java b/jdk/test/java/util/concurrent/tck/LinkedBlockingDeque8Test.java new file mode 100644 index 00000000000..44dcedc0f01 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/LinkedBlockingDeque8Test.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +/* + * 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: + * + * Written by Doug Lea and Martin Buchholz with assistance from + * members of JCP JSR-166 Expert Group and released to the public + * domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import java.util.concurrent.LinkedBlockingDeque; +import java.util.Spliterator; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class LinkedBlockingDeque8Test extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return newTestSuite(LinkedBlockingDeque8Test.class); + } + + /** + * Spliterator.getComparator always throws IllegalStateException + */ + public void testSpliterator_getComparator() { + assertThrows(IllegalStateException.class, + () -> new LinkedBlockingDeque().spliterator().getComparator()); + } + + /** + * Spliterator characteristics are as advertised + */ + public void testSpliterator_characteristics() { + LinkedBlockingDeque q = new LinkedBlockingDeque(); + Spliterator s = q.spliterator(); + int characteristics = s.characteristics(); + int required = Spliterator.CONCURRENT + | Spliterator.NONNULL + | Spliterator.ORDERED; + assertEquals(required, characteristics & required); + assertTrue(s.hasCharacteristics(required)); + assertEquals(0, characteristics + & (Spliterator.DISTINCT + | Spliterator.IMMUTABLE + | Spliterator.SORTED)); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/LinkedBlockingQueue8Test.java b/jdk/test/java/util/concurrent/tck/LinkedBlockingQueue8Test.java new file mode 100644 index 00000000000..9900c33da70 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/LinkedBlockingQueue8Test.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +/* + * 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: + * + * Written by Doug Lea and Martin Buchholz with assistance from + * members of JCP JSR-166 Expert Group and released to the public + * domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import java.util.concurrent.LinkedBlockingQueue; +import java.util.Spliterator; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class LinkedBlockingQueue8Test extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return newTestSuite(LinkedBlockingQueue8Test.class); + } + + /** + * Spliterator.getComparator always throws IllegalStateException + */ + public void testSpliterator_getComparator() { + assertThrows(IllegalStateException.class, + () -> new LinkedBlockingQueue().spliterator().getComparator()); + } + + /** + * Spliterator characteristics are as advertised + */ + public void testSpliterator_characteristics() { + LinkedBlockingQueue q = new LinkedBlockingQueue(); + Spliterator s = q.spliterator(); + int characteristics = s.characteristics(); + int required = Spliterator.CONCURRENT + | Spliterator.NONNULL + | Spliterator.ORDERED; + assertEquals(required, characteristics & required); + assertTrue(s.hasCharacteristics(required)); + assertEquals(0, characteristics + & (Spliterator.DISTINCT + | Spliterator.IMMUTABLE + | Spliterator.SORTED)); + } + +} From 1414335f7157e469a4bdd5383260ae454be6c96b Mon Sep 17 00:00:00 2001 From: Doug Lea Date: Wed, 21 Dec 2016 14:26:52 -0800 Subject: [PATCH 17/22] 8170484: Miscellaneous changes imported from jsr166 CVS 2016-12 Reviewed-by: martin, smarks, psandoz --- .../share/classes/java/util/ArrayDeque.java | 20 +- .../share/classes/java/util/ArrayList.java | 104 ++++---- .../classes/java/util/PriorityQueue.java | 86 +++--- .../classes/java/util/SplittableRandom.java | 2 +- .../share/classes/java/util/Vector.java | 93 +++---- .../util/concurrent/ArrayBlockingQueue.java | 14 +- .../concurrent/ConcurrentLinkedDeque.java | 131 ++++++--- .../concurrent/ConcurrentLinkedQueue.java | 248 +++++++++++++----- .../util/concurrent/CopyOnWriteArrayList.java | 6 + .../util/concurrent/CopyOnWriteArraySet.java | 6 + .../java/util/concurrent/CyclicBarrier.java | 3 +- .../java/util/concurrent/DelayQueue.java | 3 +- .../classes/java/util/concurrent/Phaser.java | 2 +- .../concurrent/PriorityBlockingQueue.java | 27 +- .../ScheduledThreadPoolExecutor.java | 3 +- .../util/concurrent/SubmissionPublisher.java | 23 +- .../locks/ReentrantReadWriteLock.java | 2 +- .../util/concurrent/tck/JSR166TestCase.java | 29 +- .../tck/ScheduledExecutorSubclassTest.java | 4 +- .../tck/SubmissionPublisherTest.java | 3 + .../concurrent/tck/ThreadLocalRandomTest.java | 47 ++-- .../java/util/concurrent/tck/VectorTest.java | 15 +- 22 files changed, 543 insertions(+), 328 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/util/ArrayDeque.java b/jdk/src/java.base/share/classes/java/util/ArrayDeque.java index 0122f9e52e5..de78bdc9e9a 100644 --- a/jdk/src/java.base/share/classes/java/util/ArrayDeque.java +++ b/jdk/src/java.base/share/classes/java/util/ArrayDeque.java @@ -146,16 +146,16 @@ public class ArrayDeque extends AbstractCollection if (jump < needed || (newCapacity = (oldCapacity + jump)) - MAX_ARRAY_SIZE > 0) newCapacity = newCapacity(needed, jump); - elements = Arrays.copyOf(elements, newCapacity); + final Object[] es = elements = Arrays.copyOf(elements, newCapacity); // Exceptionally, here tail == head needs to be disambiguated - if (tail < head || (tail == head && elements[head] != null)) { + if (tail < head || (tail == head && es[head] != null)) { // wrap around; slide first leg forward to end of array int newSpace = newCapacity - oldCapacity; - System.arraycopy(elements, head, - elements, head + newSpace, + System.arraycopy(es, head, + es, head + newSpace, oldCapacity - head); - Arrays.fill(elements, head, head + newSpace, null); - head += newSpace; + for (int i = head, to = (head += newSpace); i < to; i++) + es[i] = null; } } @@ -873,6 +873,9 @@ public class ArrayDeque extends AbstractCollection } } + /** + * @throws NullPointerException {@inheritDoc} + */ public void forEach(Consumer action) { Objects.requireNonNull(action); final Object[] es = elements; @@ -1035,11 +1038,14 @@ public class ArrayDeque extends AbstractCollection /** * Nulls out slots starting at array index i, upto index end. + * Condition i == end means "empty" - nothing to do. */ private static void circularClear(Object[] es, int i, int end) { + // assert 0 <= i && i < es.length; + // assert 0 <= end && end < es.length; for (int to = (i <= end) ? end : es.length; ; i = 0, to = end) { - Arrays.fill(es, i, to, null); + for (; i < to; i++) es[i] = null; if (to == end) break; } } 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 732b9641a68..dbaa725dacb 100644 --- a/jdk/src/java.base/share/classes/java/util/ArrayList.java +++ b/jdk/src/java.base/share/classes/java/util/ArrayList.java @@ -576,8 +576,9 @@ public class ArrayList extends AbstractList */ public void clear() { modCount++; - Arrays.fill(elementData, 0, size, null); - size = 0; + final Object[] es = elementData; + for (int to = size, i = size = 0; i < to; i++) + es[i] = null; } /** @@ -665,10 +666,14 @@ public class ArrayList extends AbstractList outOfBoundsMsg(fromIndex, toIndex)); } modCount++; - final Object[] es = elementData; - final int oldSize = size; - System.arraycopy(es, toIndex, es, fromIndex, oldSize - toIndex); - Arrays.fill(es, size -= (toIndex - fromIndex), oldSize, null); + shiftTailOverGap(elementData, fromIndex, toIndex); + } + + /** Erases the gap from lo to hi, by sliding down following elements. */ + private void shiftTailOverGap(Object[] es, int lo, int hi) { + System.arraycopy(es, hi, es, lo, size - hi); + for (int to = size, i = (size -= hi - lo); i < to; i++) + es[i] = null; } /** @@ -756,25 +761,25 @@ public class ArrayList extends AbstractList w += end - r; throw ex; } finally { - final int oldSize = size, deleted = end - w; - modCount += deleted; - System.arraycopy(es, end, es, w, oldSize - end); - Arrays.fill(es, size -= deleted, oldSize, null); + modCount += end - w; + shiftTailOverGap(es, w, end); } } return modified; } /** - * Save the state of the {@code ArrayList} instance to a stream (that - * is, serialize it). + * Saves the state of the {@code ArrayList} instance to a stream + * (that is, serializes it). * + * @param s the stream + * @throws java.io.IOException if an I/O error occurs * @serialData The length of the array backing the {@code ArrayList} * instance is emitted (int), followed by all of its elements * (each an {@code Object}) in the proper order. */ private void writeObject(java.io.ObjectOutputStream s) - throws java.io.IOException{ + throws java.io.IOException { // Write out element count, and any hidden stuff int expectedModCount = modCount; s.defaultWriteObject(); @@ -793,8 +798,12 @@ public class ArrayList extends AbstractList } /** - * Reconstitute the {@code ArrayList} instance from a stream (that is, - * deserialize it). + * Reconstitutes the {@code ArrayList} instance from a stream (that is, + * deserializes it). + * @param s the stream + * @throws ClassNotFoundException if the class of a serialized object + * could not be found + * @throws java.io.IOException if an I/O error occurs */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { @@ -1285,9 +1294,8 @@ public class ArrayList extends AbstractList public Spliterator spliterator() { checkForComodification(); - // ArrayListSpliterator is not used because late-binding logic - // is different here - return new Spliterator<>() { + // ArrayListSpliterator not used here due to late-binding + 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 @@ -1301,12 +1309,11 @@ public class ArrayList extends AbstractList return hi; } - public ArrayListSpliterator trySplit() { + public ArrayList.ArrayListSpliterator trySplit() { int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; - // ArrayListSpliterator could be used here as the source is already bound + // ArrayListSpliterator can be used here as the source is already bound return (lo >= mid) ? null : // divide range in half unless too small - new ArrayListSpliterator<>(root, lo, index = mid, - expectedModCount); + root.new ArrayListSpliterator(lo, index = mid, expectedModCount); } public boolean tryAdvance(Consumer action) { @@ -1348,7 +1355,7 @@ public class ArrayList extends AbstractList } public long estimateSize() { - return (long) (getFence() - index); + return getFence() - index; } public int characteristics() { @@ -1358,6 +1365,9 @@ public class ArrayList extends AbstractList } } + /** + * @throws NullPointerException {@inheritDoc} + */ @Override public void forEach(Consumer action) { Objects.requireNonNull(action); @@ -1385,11 +1395,11 @@ public class ArrayList extends AbstractList */ @Override public Spliterator spliterator() { - return new ArrayListSpliterator<>(this, 0, -1, 0); + return new ArrayListSpliterator(0, -1, 0); } /** Index-based split-by-two, lazily initialized Spliterator */ - static final class ArrayListSpliterator implements Spliterator { + final class ArrayListSpliterator implements Spliterator { /* * If ArrayLists were immutable, or structurally immutable (no @@ -1423,15 +1433,12 @@ public class ArrayList extends AbstractList * these streamlinings. */ - private final ArrayList list; private int index; // current index, modified on advance/split private int fence; // -1 until used; then one past last index private int expectedModCount; // initialized when fence set - /** Create new spliterator covering the given range */ - ArrayListSpliterator(ArrayList list, int origin, int fence, - int expectedModCount) { - this.list = list; // OK if null unless traversed + /** Creates new spliterator covering the given range. */ + ArrayListSpliterator(int origin, int fence, int expectedModCount) { this.index = origin; this.fence = fence; this.expectedModCount = expectedModCount; @@ -1439,23 +1446,17 @@ public class ArrayList extends AbstractList private int getFence() { // initialize fence to size on first use int hi; // (a specialized variant appears in method forEach) - ArrayList lst; if ((hi = fence) < 0) { - if ((lst = list) == null) - hi = fence = 0; - else { - expectedModCount = lst.modCount; - hi = fence = lst.size; - } + expectedModCount = modCount; + hi = fence = size; } return hi; } - public ArrayListSpliterator trySplit() { + 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<>(list, lo, index = mid, - expectedModCount); + new ArrayListSpliterator(lo, index = mid, expectedModCount); } public boolean tryAdvance(Consumer action) { @@ -1464,9 +1465,9 @@ public class ArrayList extends AbstractList int hi = getFence(), i = index; if (i < hi) { index = i + 1; - @SuppressWarnings("unchecked") E e = (E)list.elementData[i]; + @SuppressWarnings("unchecked") E e = (E)elementData[i]; action.accept(e); - if (list.modCount != expectedModCount) + if (modCount != expectedModCount) throw new ConcurrentModificationException(); return true; } @@ -1475,13 +1476,13 @@ public class ArrayList extends AbstractList public void forEachRemaining(Consumer action) { int i, hi, mc; // hoist accesses and checks from loop - ArrayList lst; Object[] a; + Object[] a; if (action == null) throw new NullPointerException(); - if ((lst = list) != null && (a = lst.elementData) != null) { + if ((a = elementData) != null) { if ((hi = fence) < 0) { - mc = lst.modCount; - hi = lst.size; + mc = modCount; + hi = size; } else mc = expectedModCount; @@ -1490,7 +1491,7 @@ public class ArrayList extends AbstractList @SuppressWarnings("unchecked") E e = (E) a[i]; action.accept(e); } - if (lst.modCount == mc) + if (modCount == mc) return; } } @@ -1498,7 +1499,7 @@ public class ArrayList extends AbstractList } public long estimateSize() { - return (long) (getFence() - index); + return getFence() - index; } public int characteristics() { @@ -1518,6 +1519,9 @@ public class ArrayList extends AbstractList return (bits[i >> 6] & (1L << i)) == 0; } + /** + * @throws NullPointerException {@inheritDoc} + */ @Override public boolean removeIf(Predicate filter) { return removeIf(filter, 0, size); @@ -1552,9 +1556,7 @@ public class ArrayList extends AbstractList for (i = beg; i < end; i++) if (isClear(deathRow, i - beg)) es[w++] = es[i]; - final int oldSize = size; - System.arraycopy(es, end, es, w, oldSize - end); - Arrays.fill(es, size -= (end - w), oldSize, null); + shiftTailOverGap(es, w, end); return true; } else { if (modCount != expectedModCount) diff --git a/jdk/src/java.base/share/classes/java/util/PriorityQueue.java b/jdk/src/java.base/share/classes/java/util/PriorityQueue.java index 7a99a39e369..db0cfd70913 100644 --- a/jdk/src/java.base/share/classes/java/util/PriorityQueue.java +++ b/jdk/src/java.base/share/classes/java/util/PriorityQueue.java @@ -522,6 +522,8 @@ public class PriorityQueue extends AbstractQueue */ private int expectedModCount = modCount; + Itr() {} // prevent access constructor creation + public boolean hasNext() { return cursor < size || (forgetMeNot != null && !forgetMeNot.isEmpty()); @@ -631,7 +633,7 @@ public class PriorityQueue extends AbstractQueue * promoting x up the tree until it is greater than or equal to * its parent, or is the root. * - * To simplify and speed up coercions and comparisons. the + * To simplify and speed up coercions and comparisons, the * Comparable and Comparator versions are separated into different * methods that are otherwise identical. (Similarly for siftDown.) * @@ -727,11 +729,18 @@ public class PriorityQueue extends AbstractQueue /** * Establishes the heap invariant (described above) in the entire tree, * assuming nothing about the order of the elements prior to the call. + * This classic algorithm due to Floyd (1964) is known to be O(size). */ @SuppressWarnings("unchecked") private void heapify() { - for (int i = (size >>> 1) - 1; i >= 0; i--) - siftDown(i, (E) queue[i]); + final Object[] es = queue; + final int half = (size >>> 1) - 1; + if (comparator == null) + for (int i = half; i >= 0; i--) + siftDownComparable(i, (E) es[i]); + else + for (int i = half; i >= 0; i--) + siftDownUsingComparator(i, (E) es[i]); } /** @@ -812,23 +821,16 @@ public class PriorityQueue extends AbstractQueue * @since 1.8 */ public final Spliterator spliterator() { - return new PriorityQueueSpliterator<>(this, 0, -1, 0); + return new PriorityQueueSpliterator(0, -1, 0); } - static final class PriorityQueueSpliterator implements Spliterator { - /* - * This is very similar to ArrayList Spliterator, except for - * extra null checks. - */ - private final PriorityQueue pq; + final class PriorityQueueSpliterator implements Spliterator { private int index; // current index, modified on advance/split private int fence; // -1 until first use private int expectedModCount; // initialized when fence set /** Creates new spliterator covering the given range. */ - PriorityQueueSpliterator(PriorityQueue pq, int origin, int fence, - int expectedModCount) { - this.pq = pq; + PriorityQueueSpliterator(int origin, int fence, int expectedModCount) { this.index = origin; this.fence = fence; this.expectedModCount = expectedModCount; @@ -837,68 +839,54 @@ public class PriorityQueue extends AbstractQueue private int getFence() { // initialize fence to size on first use int hi; if ((hi = fence) < 0) { - expectedModCount = pq.modCount; - hi = fence = pq.size; + expectedModCount = modCount; + hi = fence = size; } return hi; } - public PriorityQueueSpliterator trySplit() { + public PriorityQueueSpliterator trySplit() { int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; return (lo >= mid) ? null : - new PriorityQueueSpliterator<>(pq, lo, index = mid, - expectedModCount); + new PriorityQueueSpliterator(lo, index = mid, expectedModCount); } @SuppressWarnings("unchecked") public void forEachRemaining(Consumer action) { - int i, hi, mc; // hoist accesses and checks from loop - PriorityQueue q; Object[] a; if (action == null) throw new NullPointerException(); - if ((q = pq) != null && (a = q.queue) != null) { - if ((hi = fence) < 0) { - mc = q.modCount; - hi = q.size; - } - else - mc = expectedModCount; - if ((i = index) >= 0 && (index = hi) <= a.length) { - for (E e;; ++i) { - if (i < hi) { - if ((e = (E) a[i]) == null) // must be CME - break; - action.accept(e); - } - else if (q.modCount != mc) - break; - else - return; - } - } + if (fence < 0) { fence = size; expectedModCount = modCount; } + final Object[] a = queue; + int i, hi; E e; + for (i = index, index = hi = fence; i < hi; i++) { + if ((e = (E) a[i]) == null) + break; // must be CME + action.accept(e); } - throw new ConcurrentModificationException(); + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); } + @SuppressWarnings("unchecked") public boolean tryAdvance(Consumer action) { if (action == null) throw new NullPointerException(); - int hi = getFence(), lo = index; - if (lo >= 0 && lo < hi) { - index = lo + 1; - @SuppressWarnings("unchecked") E e = (E)pq.queue[lo]; - if (e == null) + if (fence < 0) { fence = size; expectedModCount = modCount; } + int i; + if ((i = index) < fence) { + index = i + 1; + E e; + if ((e = (E) queue[i]) == null + || modCount != expectedModCount) throw new ConcurrentModificationException(); action.accept(e); - if (pq.modCount != expectedModCount) - throw new ConcurrentModificationException(); return true; } return false; } public long estimateSize() { - return (long) (getFence() - index); + return getFence() - index; } public int characteristics() { diff --git a/jdk/src/java.base/share/classes/java/util/SplittableRandom.java b/jdk/src/java.base/share/classes/java/util/SplittableRandom.java index 579102a2bc7..1a6653d56c7 100644 --- a/jdk/src/java.base/share/classes/java/util/SplittableRandom.java +++ b/jdk/src/java.base/share/classes/java/util/SplittableRandom.java @@ -375,7 +375,7 @@ public final class SplittableRandom { * may, and typically does, vary across program invocations. */ public SplittableRandom() { // emulate defaultGen.split() - long s = defaultGen.getAndAdd(2 * GOLDEN_GAMMA); + long s = defaultGen.getAndAdd(GOLDEN_GAMMA << 1); this.seed = mix64(s); this.gamma = mixGamma(s + GOLDEN_GAMMA); } diff --git a/jdk/src/java.base/share/classes/java/util/Vector.java b/jdk/src/java.base/share/classes/java/util/Vector.java index 7c9d2cbc99b..59add640a01 100644 --- a/jdk/src/java.base/share/classes/java/util/Vector.java +++ b/jdk/src/java.base/share/classes/java/util/Vector.java @@ -306,9 +306,9 @@ public class Vector modCount++; if (newSize > elementData.length) grow(newSize); - for (int i = newSize; i < elementCount; i++) - elementData[i] = null; - elementCount = newSize; + final Object[] es = elementData; + for (int to = elementCount, i = elementCount = newSize; i < to; i++) + es[i] = null; } /** @@ -675,9 +675,10 @@ public class Vector * method (which is part of the {@link List} interface). */ public synchronized void removeAllElements() { - Arrays.fill(elementData, 0, elementCount, null); + final Object[] es = elementData; + for (int to = elementCount, i = elementCount = 0; i < to; i++) + es[i] = null; modCount++; - elementCount = 0; } /** @@ -980,6 +981,9 @@ public class Vector return bulkRemove(e -> !c.contains(e)); } + /** + * @throws NullPointerException {@inheritDoc} + */ @Override public boolean removeIf(Predicate filter) { Objects.requireNonNull(filter); @@ -1024,7 +1028,8 @@ public class Vector for (i = beg; i < end; i++) if (isClear(deathRow, i - beg)) es[w++] = es[i]; - Arrays.fill(es, elementCount = w, end, null); + for (i = elementCount = w; i < end; i++) + es[i] = null; return true; } else { if (modCount != expectedModCount) @@ -1152,19 +1157,25 @@ public class Vector * (If {@code toIndex==fromIndex}, this operation has no effect.) */ protected synchronized void removeRange(int fromIndex, int toIndex) { - final Object[] es = elementData; - final int oldSize = elementCount; - System.arraycopy(es, toIndex, es, fromIndex, oldSize - toIndex); - modCount++; - Arrays.fill(es, elementCount -= (toIndex - fromIndex), oldSize, null); + shiftTailOverGap(elementData, fromIndex, toIndex); + } + + /** Erases the gap from lo to hi, by sliding down following elements. */ + private void shiftTailOverGap(Object[] es, int lo, int hi) { + System.arraycopy(es, hi, es, lo, elementCount - hi); + for (int to = elementCount, i = (elementCount -= hi - lo); i < to; i++) + es[i] = null; } /** - * Save the state of the {@code Vector} instance to a stream (that - * is, serialize it). + * Saves the state of the {@code Vector} instance to a stream + * (that is, serializes it). * This method performs synchronization to ensure the consistency * of the serialized data. + * + * @param s the stream + * @throws java.io.IOException if an I/O error occurs */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { @@ -1337,6 +1348,9 @@ public class Vector } } + /** + * @throws NullPointerException {@inheritDoc} + */ @Override public synchronized void forEach(Consumer action) { Objects.requireNonNull(action); @@ -1349,6 +1363,9 @@ public class Vector throw new ConcurrentModificationException(); } + /** + * @throws NullPointerException {@inheritDoc} + */ @Override public synchronized void replaceAll(UnaryOperator operator) { Objects.requireNonNull(operator); @@ -1387,21 +1404,19 @@ public class Vector */ @Override public Spliterator spliterator() { - return new VectorSpliterator<>(this, null, 0, -1, 0); + return new VectorSpliterator(null, 0, -1, 0); } /** Similar to ArrayList Spliterator */ - static final class VectorSpliterator implements Spliterator { - private final Vector list; + final class VectorSpliterator implements Spliterator { private Object[] array; private int index; // current index, modified on advance/split private int fence; // -1 until used; then one past last index private int expectedModCount; // initialized when fence set - /** Create new spliterator covering the given range */ - VectorSpliterator(Vector list, Object[] array, int origin, int fence, + /** Creates new spliterator covering the given range. */ + VectorSpliterator(Object[] array, int origin, int fence, int expectedModCount) { - this.list = list; this.array = array; this.index = origin; this.fence = fence; @@ -1411,10 +1426,10 @@ public class Vector private int getFence() { // initialize on first use int hi; if ((hi = fence) < 0) { - synchronized (list) { - array = list.elementData; - expectedModCount = list.modCount; - hi = fence = list.elementCount; + synchronized (Vector.this) { + array = elementData; + expectedModCount = modCount; + hi = fence = elementCount; } } return hi; @@ -1423,8 +1438,7 @@ public class Vector public Spliterator trySplit() { int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; return (lo >= mid) ? null : - new VectorSpliterator<>(list, array, lo, index = mid, - expectedModCount); + new VectorSpliterator(array, lo, index = mid, expectedModCount); } @SuppressWarnings("unchecked") @@ -1435,7 +1449,7 @@ public class Vector if (getFence() > (i = index)) { index = i + 1; action.accept((E)array[i]); - if (list.modCount != expectedModCount) + if (modCount != expectedModCount) throw new ConcurrentModificationException(); return true; } @@ -1444,28 +1458,15 @@ public class Vector @SuppressWarnings("unchecked") public void forEachRemaining(Consumer action) { - int i, hi; // hoist accesses and checks from loop - Vector lst; Object[] a; if (action == null) throw new NullPointerException(); - if ((lst = list) != null) { - if ((hi = fence) < 0) { - synchronized (lst) { - expectedModCount = lst.modCount; - a = array = lst.elementData; - hi = fence = lst.elementCount; - } - } - else - a = array; - if (a != null && (i = index) >= 0 && (index = hi) <= a.length) { - while (i < hi) - action.accept((E) a[i++]); - if (lst.modCount == expectedModCount) - return; - } - } - throw new ConcurrentModificationException(); + final int hi = getFence(); + final Object[] a = array; + int i; + for (i = index, index = hi; i < hi; i++) + action.accept((E) a[i]); + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); } public long estimateSize() { diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/ArrayBlockingQueue.java b/jdk/src/java.base/share/classes/java/util/concurrent/ArrayBlockingQueue.java index 2688e17f725..d2eddf9af3f 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/ArrayBlockingQueue.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/ArrayBlockingQueue.java @@ -675,12 +675,14 @@ public class ArrayBlockingQueue extends AbstractQueue /** * Nulls out slots starting at array index i, upto index end. - * If i == end, the entire array is cleared! + * Condition i == end means "full" - the entire array is cleared. */ private static void circularClear(Object[] items, int i, int end) { + // assert 0 <= i && i < items.length; + // assert 0 <= end && end < items.length; for (int to = (i < end) ? end : items.length; ; i = 0, to = end) { - Arrays.fill(items, i, to, null); + for (; i < to; i++) items[i] = null; if (to == end) break; } } @@ -1011,6 +1013,11 @@ public class ArrayBlockingQueue extends AbstractQueue * expected element to remove, in lastItem. Yes, we may fail to * remove lastItem from the queue if it moved due to an interleaved * interior remove while in detached mode. + * + * Method forEachRemaining, added in Java 8, is treated similarly + * to hasNext returning false, in that we switch to detached mode, + * but we regard it as an even stronger request to "close" this + * iteration, and don't bother supporting subsequent remove(). */ private class Itr implements Iterator { /** Index to look for new nextItem; NONE at end */ @@ -1432,6 +1439,9 @@ public class ArrayBlockingQueue extends AbstractQueue Spliterator.CONCURRENT)); } + /** + * @throws NullPointerException {@inheritDoc} + */ public void forEach(Consumer action) { Objects.requireNonNull(action); final ReentrantLock lock = this.lock; diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java index 5c1c7069da7..c2667e2082c 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java @@ -48,6 +48,7 @@ import java.util.Queue; import java.util.Spliterator; import java.util.Spliterators; import java.util.function.Consumer; +import java.util.function.Predicate; /** * An unbounded concurrent {@linkplain Deque deque} based on linked nodes. @@ -864,8 +865,8 @@ public class ConcurrentLinkedDeque public E peekFirst() { for (Node p = first(); p != null; p = succ(p)) { - E item = p.item; - if (item != null) + final E item; + if ((item = p.item) != null) return item; } return null; @@ -873,8 +874,8 @@ public class ConcurrentLinkedDeque public E peekLast() { for (Node p = last(); p != null; p = pred(p)) { - E item = p.item; - if (item != null) + final E item; + if ((item = p.item) != null) return item; } return null; @@ -896,8 +897,9 @@ public class ConcurrentLinkedDeque public E pollFirst() { for (Node p = first(); p != null; p = succ(p)) { - E item = p.item; - if (item != null && ITEM.compareAndSet(p, item, null)) { + final E item; + if ((item = p.item) != null + && ITEM.compareAndSet(p, item, null)) { unlink(p); return item; } @@ -907,8 +909,9 @@ public class ConcurrentLinkedDeque public E pollLast() { for (Node p = last(); p != null; p = pred(p)) { - E item = p.item; - if (item != null && ITEM.compareAndSet(p, item, null)) { + final E item; + if ((item = p.item) != null + && ITEM.compareAndSet(p, item, null)) { unlink(p); return item; } @@ -993,9 +996,10 @@ public class ConcurrentLinkedDeque public boolean removeFirstOccurrence(Object o) { Objects.requireNonNull(o); for (Node p = first(); p != null; p = succ(p)) { - E item = p.item; - if (item != null && o.equals(item) && - ITEM.compareAndSet(p, item, null)) { + final E item; + if ((item = p.item) != null + && o.equals(item) + && ITEM.compareAndSet(p, item, null)) { unlink(p); return true; } @@ -1018,9 +1022,10 @@ public class ConcurrentLinkedDeque public boolean removeLastOccurrence(Object o) { Objects.requireNonNull(o); for (Node p = last(); p != null; p = pred(p)) { - E item = p.item; - if (item != null && o.equals(item) && - ITEM.compareAndSet(p, item, null)) { + final E item; + if ((item = p.item) != null + && o.equals(item) + && ITEM.compareAndSet(p, item, null)) { unlink(p); return true; } @@ -1039,8 +1044,8 @@ public class ConcurrentLinkedDeque public boolean contains(Object o) { if (o != null) { for (Node p = first(); p != null; p = succ(p)) { - E item = p.item; - if (item != null && o.equals(item)) + final E item; + if ((item = p.item) != null && o.equals(item)) return true; } } @@ -1181,8 +1186,8 @@ public class ConcurrentLinkedDeque int charLength = 0; int size = 0; for (Node p = first(); p != null;) { - E item = p.item; - if (item != null) { + final E item; + if ((item = p.item) != null) { if (a == null) a = new String[4]; else if (size == a.length) @@ -1207,8 +1212,8 @@ public class ConcurrentLinkedDeque restartFromHead: for (;;) { int size = 0; for (Node p = first(); p != null;) { - E item = p.item; - if (item != null) { + final E item; + if ((item = p.item) != null) { if (x == null) x = new Object[4]; else if (size == x.length) @@ -1360,8 +1365,8 @@ public class ConcurrentLinkedDeque nextItem = null; break; } - E item = p.item; - if (item != null) { + final E item; + if ((item = p.item) != null) { nextNode = p; nextItem = item; break; @@ -1391,36 +1396,33 @@ public class ConcurrentLinkedDeque /** Forward iterator */ private class Itr extends AbstractItr { + Itr() {} // prevent access constructor creation Node startNode() { return first(); } Node nextNode(Node p) { return succ(p); } } /** Descending iterator */ private class DescendingItr extends AbstractItr { + DescendingItr() {} // prevent access constructor creation Node startNode() { return last(); } Node nextNode(Node p) { return pred(p); } } /** A customized variant of Spliterators.IteratorSpliterator */ - static final class CLDSpliterator implements Spliterator { + final class CLDSpliterator implements Spliterator { static final int MAX_BATCH = 1 << 25; // max batch array size; - final ConcurrentLinkedDeque queue; Node current; // current node; null until initialized int batch; // batch size for splits boolean exhausted; // true when no more nodes - CLDSpliterator(ConcurrentLinkedDeque queue) { - this.queue = queue; - } public Spliterator trySplit() { Node p; - final ConcurrentLinkedDeque q = this.queue; int b = batch; int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1; if (!exhausted && - ((p = current) != null || (p = q.first()) != null)) { + ((p = current) != null || (p = first()) != null)) { if (p.item == null && p == (p = p.next)) - current = p = q.first(); + current = p = first(); if (p != null && p.next != null) { Object[] a = new Object[n]; int i = 0; @@ -1428,7 +1430,7 @@ public class ConcurrentLinkedDeque if ((a[i] = p.item) != null) ++i; if (p == (p = p.next)) - p = q.first(); + p = first(); } while (p != null && i < n); if ((current = p) == null) exhausted = true; @@ -1447,14 +1449,13 @@ public class ConcurrentLinkedDeque public void forEachRemaining(Consumer action) { Node p; if (action == null) throw new NullPointerException(); - final ConcurrentLinkedDeque q = this.queue; if (!exhausted && - ((p = current) != null || (p = q.first()) != null)) { + ((p = current) != null || (p = first()) != null)) { exhausted = true; do { E e = p.item; if (p == (p = p.next)) - p = q.first(); + p = first(); if (e != null) action.accept(e); } while (p != null); @@ -1464,14 +1465,13 @@ public class ConcurrentLinkedDeque public boolean tryAdvance(Consumer action) { Node p; if (action == null) throw new NullPointerException(); - final ConcurrentLinkedDeque q = this.queue; if (!exhausted && - ((p = current) != null || (p = q.first()) != null)) { + ((p = current) != null || (p = first()) != null)) { E e; do { e = p.item; if (p == (p = p.next)) - p = q.first(); + p = first(); } while (e == null && p != null); if ((current = p) == null) exhausted = true; @@ -1508,7 +1508,7 @@ public class ConcurrentLinkedDeque * @since 1.8 */ public Spliterator spliterator() { - return new CLDSpliterator(this); + return new CLDSpliterator(); } /** @@ -1527,8 +1527,8 @@ public class ConcurrentLinkedDeque // Write out all elements in the proper order. for (Node p = first(); p != null; p = succ(p)) { - E item = p.item; - if (item != null) + final E item; + if ((item = p.item) != null) s.writeObject(item); } @@ -1563,6 +1563,57 @@ public class ConcurrentLinkedDeque initHeadTail(h, t); } + /** + * @throws NullPointerException {@inheritDoc} + */ + public boolean removeIf(Predicate filter) { + Objects.requireNonNull(filter); + return bulkRemove(filter); + } + + /** + * @throws NullPointerException {@inheritDoc} + */ + public boolean removeAll(Collection c) { + Objects.requireNonNull(c); + return bulkRemove(e -> c.contains(e)); + } + + /** + * @throws NullPointerException {@inheritDoc} + */ + public boolean retainAll(Collection c) { + Objects.requireNonNull(c); + return bulkRemove(e -> !c.contains(e)); + } + + /** Implementation of bulk remove methods. */ + private boolean bulkRemove(Predicate filter) { + boolean removed = false; + for (Node p = first(), succ; p != null; p = succ) { + succ = succ(p); + final E item; + if ((item = p.item) != null + && filter.test(item) + && ITEM.compareAndSet(p, item, null)) { + unlink(p); + removed = true; + } + } + return removed; + } + + /** + * @throws NullPointerException {@inheritDoc} + */ + public void forEach(Consumer action) { + Objects.requireNonNull(action); + E item; + for (Node p = first(); p != null; p = succ(p)) + if ((item = p.item) != null) + action.accept(item); + } + // VarHandle mechanics private static final VarHandle HEAD; private static final VarHandle TAIL; diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java index 56ccb3317fa..b3dd5df8e73 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java @@ -47,6 +47,7 @@ import java.util.Queue; import java.util.Spliterator; import java.util.Spliterators; import java.util.function.Consumer; +import java.util.function.Predicate; /** * An unbounded thread-safe {@linkplain Queue queue} based on linked nodes. @@ -112,7 +113,7 @@ public class ConcurrentLinkedQueue extends AbstractQueue /* * This is a modification of the Michael & Scott algorithm, * adapted for a garbage-collected environment, with support for - * interior node deletion (to support remove(Object)). For + * interior node deletion (to support e.g. remove(Object)). For * explanation, read the paper. * * Note that like most non-blocking algorithms in this package, @@ -160,12 +161,13 @@ public class ConcurrentLinkedQueue extends AbstractQueue * it is possible for tail to lag behind head (why not)? * * CASing a Node's item reference to null atomically removes the - * element from the queue. Iterators skip over Nodes with null - * items. Prior implementations of this class had a race between - * poll() and remove(Object) where the same element would appear - * to be successfully removed by two concurrent operations. The - * method remove(Object) also lazily unlinks deleted Nodes, but - * this is merely an optimization. + * element from the queue, leaving a "dead" node that should later + * be unlinked (but unlinking is merely an optimization). + * Interior element removal methods (other than Iterator.remove()) + * keep track of the predecessor node during traversal so that the + * node can be CAS-unlinked. Some traversal methods try to unlink + * any deleted nodes encountered during traversal. See comments + * in bulkRemove. * * When constructing a Node (before enqueuing it) we avoid paying * for a volatile write to item. This allows the cost of enqueue @@ -289,6 +291,21 @@ public class ConcurrentLinkedQueue extends AbstractQueue return (p == next) ? head : next; } + /** + * Tries to CAS pred.next (or head, if pred is null) from c to p. + */ + private boolean tryCasSuccessor(Node pred, Node c, Node p) { + // assert c.item == null; + // assert c != p; + if (pred != null) + return NEXT.compareAndSet(pred, c, p); + if (HEAD.compareAndSet(this, c, p)) { + NEXT.setRelease(c, c); + return true; + } + return false; + } + /** * Inserts the specified element at the tail of this queue. * As the queue is unbounded, this method will never return {@code false}. @@ -326,12 +343,11 @@ public class ConcurrentLinkedQueue extends AbstractQueue } public E poll() { - restartFromHead: - for (;;) { - for (Node h = head, p = h, q;;) { - E item = p.item; - - if (item != null && ITEM.compareAndSet(p, item, null)) { + restartFromHead: for (;;) { + for (Node h = head, p = h, q;; p = q) { + final E item; + if ((item = p.item) != null + && ITEM.compareAndSet(p, item, null)) { // Successful CAS is the linearization point // for item to be removed from this queue. if (p != h) // hop two nodes at a time @@ -344,25 +360,21 @@ public class ConcurrentLinkedQueue extends AbstractQueue } else if (p == q) continue restartFromHead; - else - p = q; } } } public E peek() { - restartFromHead: - for (;;) { - for (Node h = head, p = h, q;;) { - E item = p.item; - if (item != null || (q = p.next) == null) { + restartFromHead: for (;;) { + for (Node h = head, p = h, q;; p = q) { + final E item; + if ((item = p.item) != null + || (q = p.next) == null) { updateHead(h, p); return item; } else if (p == q) continue restartFromHead; - else - p = q; } } } @@ -376,9 +388,8 @@ public class ConcurrentLinkedQueue extends AbstractQueue * of losing a race to a concurrent poll(). */ Node first() { - restartFromHead: - for (;;) { - for (Node h = head, p = h, q;;) { + restartFromHead: for (;;) { + for (Node h = head, p = h, q;; p = q) { boolean hasItem = (p.item != null); if (hasItem || (q = p.next) == null) { updateHead(h, p); @@ -386,8 +397,6 @@ public class ConcurrentLinkedQueue extends AbstractQueue } else if (p == q) continue restartFromHead; - else - p = q; } } } @@ -440,14 +449,24 @@ public class ConcurrentLinkedQueue extends AbstractQueue * @return {@code true} if this queue contains the specified element */ public boolean contains(Object o) { - if (o != null) { - for (Node p = first(); p != null; p = succ(p)) { - E item = p.item; - if (item != null && o.equals(item)) + if (o == null) return false; + restartFromHead: for (;;) { + for (Node p = head, c = p, pred = null, q; p != null; p = q) { + final E item; + if ((item = p.item) != null && o.equals(item)) return true; + if (c != p && tryCasSuccessor(pred, c, p)) + c = p; + q = p.next; + if (item != null || c != p) { + pred = p; + c = q; + } + else if (p == q) + continue restartFromHead; } + return false; } - return false; } /** @@ -462,27 +481,28 @@ public class ConcurrentLinkedQueue extends AbstractQueue * @return {@code true} if this queue changed as a result of the call */ public boolean remove(Object o) { - if (o != null) { - Node next, pred = null; - for (Node p = first(); p != null; pred = p, p = next) { - boolean removed = false; - E item = p.item; - if (item != null) { - if (!o.equals(item)) { - next = succ(p); - continue; - } - removed = ITEM.compareAndSet(p, item, null); - } - - next = succ(p); - if (pred != null && next != null) // unlink - NEXT.weakCompareAndSet(pred, p, next); + if (o == null) return false; + restartFromHead: for (;;) { + for (Node p = head, c = p, pred = null, q; p != null; p = q) { + final E item; + final boolean removed = + (item = p.item) != null + && o.equals(item) + && ITEM.compareAndSet(p, item, null); + if (c != p && tryCasSuccessor(pred, c, p)) + c = p; if (removed) return true; + q = p.next; + if (item != null || c != p) { + pred = p; + c = q; + } + else if (p == q) + continue restartFromHead; } + return false; } - return false; } /** @@ -553,8 +573,8 @@ public class ConcurrentLinkedQueue extends AbstractQueue int charLength = 0; int size = 0; for (Node p = first(); p != null;) { - E item = p.item; - if (item != null) { + final E item; + if ((item = p.item) != null) { if (a == null) a = new String[4]; else if (size == a.length) @@ -579,8 +599,8 @@ public class ConcurrentLinkedQueue extends AbstractQueue restartFromHead: for (;;) { int size = 0; for (Node p = first(); p != null;) { - E item = p.item; - if (item != null) { + final E item; + if ((item = p.item) != null) { if (x == null) x = new Object[4]; else if (size == x.length) @@ -697,7 +717,7 @@ public class ConcurrentLinkedQueue extends AbstractQueue restartFromHead: for (;;) { Node h, p, q; for (p = h = head;; p = q) { - E item; + final E item; if ((item = p.item) != null) { nextNode = p; nextItem = item; @@ -762,8 +782,8 @@ public class ConcurrentLinkedQueue extends AbstractQueue // Write out all elements in the proper order. for (Node p = first(); p != null; p = succ(p)) { - Object item = p.item; - if (item != null) + final E item; + if ((item = p.item) != null) s.writeObject(item); } @@ -801,23 +821,18 @@ public class ConcurrentLinkedQueue extends AbstractQueue } /** A customized variant of Spliterators.IteratorSpliterator */ - static final class CLQSpliterator implements Spliterator { + final class CLQSpliterator implements Spliterator { static final int MAX_BATCH = 1 << 25; // max batch array size; - final ConcurrentLinkedQueue queue; Node current; // current node; null until initialized int batch; // batch size for splits boolean exhausted; // true when no more nodes - CLQSpliterator(ConcurrentLinkedQueue queue) { - this.queue = queue; - } public Spliterator trySplit() { Node p; - final ConcurrentLinkedQueue q = this.queue; int b = batch; int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1; if (!exhausted && - ((p = current) != null || (p = q.first()) != null) && + ((p = current) != null || (p = first()) != null) && p.next != null) { Object[] a = new Object[n]; int i = 0; @@ -825,7 +840,7 @@ public class ConcurrentLinkedQueue extends AbstractQueue if ((a[i] = p.item) != null) ++i; if (p == (p = p.next)) - p = q.first(); + p = first(); } while (p != null && i < n); if ((current = p) == null) exhausted = true; @@ -843,14 +858,13 @@ public class ConcurrentLinkedQueue extends AbstractQueue public void forEachRemaining(Consumer action) { Node p; if (action == null) throw new NullPointerException(); - final ConcurrentLinkedQueue q = this.queue; if (!exhausted && - ((p = current) != null || (p = q.first()) != null)) { + ((p = current) != null || (p = first()) != null)) { exhausted = true; do { E e = p.item; if (p == (p = p.next)) - p = q.first(); + p = first(); if (e != null) action.accept(e); } while (p != null); @@ -860,14 +874,13 @@ public class ConcurrentLinkedQueue extends AbstractQueue public boolean tryAdvance(Consumer action) { Node p; if (action == null) throw new NullPointerException(); - final ConcurrentLinkedQueue q = this.queue; if (!exhausted && - ((p = current) != null || (p = q.first()) != null)) { + ((p = current) != null || (p = first()) != null)) { E e; do { e = p.item; if (p == (p = p.next)) - p = q.first(); + p = first(); } while (e == null && p != null); if ((current = p) == null) exhausted = true; @@ -905,7 +918,100 @@ public class ConcurrentLinkedQueue extends AbstractQueue */ @Override public Spliterator spliterator() { - return new CLQSpliterator(this); + return new CLQSpliterator(); + } + + /** + * @throws NullPointerException {@inheritDoc} + */ + public boolean removeIf(Predicate filter) { + Objects.requireNonNull(filter); + return bulkRemove(filter); + } + + /** + * @throws NullPointerException {@inheritDoc} + */ + public boolean removeAll(Collection c) { + Objects.requireNonNull(c); + return bulkRemove(e -> c.contains(e)); + } + + /** + * @throws NullPointerException {@inheritDoc} + */ + public boolean retainAll(Collection c) { + Objects.requireNonNull(c); + return bulkRemove(e -> !c.contains(e)); + } + + public void clear() { + bulkRemove(e -> true); + } + + /** + * Tolerate this many consecutive dead nodes before CAS-collapsing. + * Amortized cost of clear() is (1 + 1/MAX_HOPS) CASes per element. + */ + private static final int MAX_HOPS = 8; + + /** Implementation of bulk remove methods. */ + private boolean bulkRemove(Predicate filter) { + boolean removed = false; + restartFromHead: for (;;) { + int hops = MAX_HOPS; + // c will be CASed to collapse intervening dead nodes between + // pred (or head if null) and p. + for (Node p = head, c = p, pred = null, q; p != null; p = q) { + final E item; boolean pAlive; + if (pAlive = ((item = p.item) != null)) { + if (filter.test(item)) { + if (ITEM.compareAndSet(p, item, null)) + removed = true; + pAlive = false; + } + } + if ((q = p.next) == null || pAlive || --hops == 0) { + // p might already be self-linked here, but if so: + // - CASing head will surely fail + // - CASing pred's next will be useless but harmless. + if (c != p && tryCasSuccessor(pred, c, p)) + c = p; + // if c != p, CAS failed, so abandon old pred + if (pAlive || c != p) { + hops = MAX_HOPS; + pred = p; + c = q; + } + } else if (p == q) + continue restartFromHead; + } + return removed; + } + } + + /** + * @throws NullPointerException {@inheritDoc} + */ + public void forEach(Consumer action) { + Objects.requireNonNull(action); + restartFromHead: for (;;) { + for (Node p = head, c = p, pred = null, q; p != null; p = q) { + final E item; + if ((item = p.item) != null) + action.accept(item); + if (c != p && tryCasSuccessor(pred, c, p)) + c = p; + q = p.next; + if (item != null || c != p) { + pred = p; + c = q; + } + else if (p == q) + continue restartFromHead; + } + return; + } } // VarHandle mechanics diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java b/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java index 47da30c7cd3..d52a515eb9a 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java @@ -793,6 +793,9 @@ public class CopyOnWriteArrayList } } + /** + * @throws NullPointerException {@inheritDoc} + */ public void forEach(Consumer action) { if (action == null) throw new NullPointerException(); for (Object x : getArray()) { @@ -801,6 +804,9 @@ public class CopyOnWriteArrayList } } + /** + * @throws NullPointerException {@inheritDoc} + */ public boolean removeIf(Predicate filter) { if (filter == null) throw new NullPointerException(); return bulkRemove(filter); diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArraySet.java b/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArraySet.java index 5895ecd40f9..6e4ad018d2f 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArraySet.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArraySet.java @@ -411,10 +411,16 @@ public class CopyOnWriteArraySet extends AbstractSet && compareSets(al.getArray(), (Set) o) == 0); } + /** + * @throws NullPointerException {@inheritDoc} + */ public boolean removeIf(Predicate filter) { return al.removeIf(filter); } + /** + * @throws NullPointerException {@inheritDoc} + */ public void forEach(Consumer action) { al.forEach(action); } diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/CyclicBarrier.java b/jdk/src/java.base/share/classes/java/util/concurrent/CyclicBarrier.java index 97aae44a888..269bec4caf2 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/CyclicBarrier.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/CyclicBarrier.java @@ -149,7 +149,8 @@ public class CyclicBarrier { * but no subsequent reset. */ private static class Generation { - boolean broken; // initially false + Generation() {} // prevent access constructor creation + boolean broken; // initially false } /** The lock for guarding barrier entry */ diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/DelayQueue.java b/jdk/src/java.base/share/classes/java/util/concurrent/DelayQueue.java index d564fc39839..03c52ff08a1 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/DelayQueue.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/DelayQueue.java @@ -547,8 +547,7 @@ public class DelayQueue extends AbstractQueue public E next() { if (cursor >= array.length) throw new NoSuchElementException(); - lastRet = cursor; - return (E)array[cursor++]; + return (E)array[lastRet = cursor++]; } public void remove() { diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/Phaser.java b/jdk/src/java.base/share/classes/java/util/concurrent/Phaser.java index 0a87239ea29..ab0b884a2c2 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/Phaser.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/Phaser.java @@ -179,7 +179,7 @@ import java.util.concurrent.locks.LockSupport; * void startTasks(List tasks, int iterations) { * Phaser phaser = new Phaser() { * protected boolean onAdvance(int phase, int registeredParties) { - * return phase >= iterations || registeredParties == 0; + * return phase >= iterations - 1 || registeredParties == 0; * } * }; * phaser.register(); diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java b/jdk/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java index 64f03b6940c..078bbffd87d 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java @@ -345,11 +345,9 @@ public class PriorityBlockingQueue extends AbstractQueue * promoting x up the tree until it is greater than or equal to * its parent, or is the root. * - * To simplify and speed up coercions and comparisons. the + * To simplify and speed up coercions and comparisons, the * Comparable and Comparator versions are separated into different * methods that are otherwise identical. (Similarly for siftDown.) - * These methods are static, with heap state as arguments, to - * simplify use in light of possible comparator exceptions. * * @param k the position to fill * @param x the item to insert @@ -435,6 +433,7 @@ public class PriorityBlockingQueue extends AbstractQueue /** * Establishes the heap invariant (described above) in the entire tree, * assuming nothing about the order of the elements prior to the call. + * This classic algorithm due to Floyd (1964) is known to be O(size). */ private void heapify() { Object[] array = queue; @@ -878,8 +877,7 @@ public class PriorityBlockingQueue extends AbstractQueue public E next() { if (cursor >= array.length) throw new NoSuchElementException(); - lastRet = cursor; - return (E)array[cursor++]; + return (E)array[lastRet = cursor++]; } public void remove() { @@ -936,15 +934,12 @@ public class PriorityBlockingQueue extends AbstractQueue /** * Immutable snapshot spliterator that binds to elements "late". */ - static final class PBQSpliterator implements Spliterator { - final PriorityBlockingQueue queue; + final class PBQSpliterator implements Spliterator { Object[] array; int index; int fence; - PBQSpliterator(PriorityBlockingQueue queue, Object[] array, - int index, int fence) { - this.queue = queue; + PBQSpliterator(Object[] array, int index, int fence) { this.array = array; this.index = index; this.fence = fence; @@ -953,14 +948,14 @@ public class PriorityBlockingQueue extends AbstractQueue final int getFence() { int hi; if ((hi = fence) < 0) - hi = fence = (array = queue.toArray()).length; + hi = fence = (array = toArray()).length; return hi; } - public PBQSpliterator trySplit() { + public PBQSpliterator trySplit() { int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; return (lo >= mid) ? null : - new PBQSpliterator(queue, array, lo, index = mid); + new PBQSpliterator(array, lo, index = mid); } @SuppressWarnings("unchecked") @@ -969,7 +964,7 @@ public class PriorityBlockingQueue extends AbstractQueue if (action == null) throw new NullPointerException(); if ((a = array) == null) - fence = (a = queue.toArray()).length; + fence = (a = toArray()).length; if ((hi = fence) <= a.length && (i = index) >= 0 && i < (index = hi)) { do { action.accept((E)a[i]); } while (++i < hi); @@ -987,7 +982,7 @@ public class PriorityBlockingQueue extends AbstractQueue return false; } - public long estimateSize() { return (long)(getFence() - index); } + public long estimateSize() { return getFence() - index; } public int characteristics() { return Spliterator.NONNULL | Spliterator.SIZED | Spliterator.SUBSIZED; @@ -1012,7 +1007,7 @@ public class PriorityBlockingQueue extends AbstractQueue * @since 1.8 */ public Spliterator spliterator() { - return new PBQSpliterator(this, null, 0, -1); + return new PBQSpliterator(null, 0, -1); } // VarHandle mechanics diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java b/jdk/src/java.base/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java index 5ab89f89957..98c7e1cac8d 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java @@ -1306,8 +1306,7 @@ public class ScheduledThreadPoolExecutor public Runnable next() { if (cursor >= array.length) throw new NoSuchElementException(); - lastRet = cursor; - return array[cursor++]; + return array[lastRet = cursor++]; } public void remove() { diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java b/jdk/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java index 5d96cae3f82..28e98a361ef 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java @@ -195,6 +195,7 @@ public class SubmissionPublisher implements Flow.Publisher, /** Fallback if ForkJoinPool.commonPool() cannot support parallelism */ private static final class ThreadPerTaskExecutor implements Executor { + ThreadPerTaskExecutor() {} // prevent access constructor creation public void execute(Runnable r) { new Thread(r).start(); } } @@ -1454,7 +1455,17 @@ public class SubmissionPublisher implements Flow.Publisher, */ private boolean checkControl(Flow.Subscriber s, int c) { boolean stat = true; - if ((c & ERROR) != 0) { + if ((c & SUBSCRIBE) != 0) { + if (CTL.compareAndSet(this, c, c & ~SUBSCRIBE)) { + try { + if (s != null) + s.onSubscribe(this); + } catch (Throwable ex) { + onError(ex); + } + } + } + else if ((c & ERROR) != 0) { Throwable ex = pendingError; ctl = DISABLED; // no need for CAS if (ex != null) { // null if errorless cancel @@ -1465,16 +1476,6 @@ public class SubmissionPublisher implements Flow.Publisher, } } } - else if ((c & SUBSCRIBE) != 0) { - if (CTL.compareAndSet(this, c, c & ~SUBSCRIBE)) { - try { - if (s != null) - s.onSubscribe(this); - } catch (Throwable ex) { - onError(ex); - } - } - } else { detach(); stat = false; diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java b/jdk/src/java.base/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java index 5a9d8bc2980..d228f73d39c 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java @@ -138,7 +138,7 @@ import jdk.internal.vm.annotation.ReservedStackAccess; *

 {@code
  * class CachedData {
  *   Object data;
- *   volatile boolean cacheValid;
+ *   boolean cacheValid;
  *   final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
  *
  *   void processCachedData() {
diff --git a/jdk/test/java/util/concurrent/tck/JSR166TestCase.java b/jdk/test/java/util/concurrent/tck/JSR166TestCase.java
index 390639b7f2b..ff686081cd2 100644
--- a/jdk/test/java/util/concurrent/tck/JSR166TestCase.java
+++ b/jdk/test/java/util/concurrent/tck/JSR166TestCase.java
@@ -35,13 +35,30 @@
 
 /*
  * @test
- * @summary JSR-166 tck tests
+ * @summary JSR-166 tck tests (conformance testing mode)
+ * @build *
+ * @modules java.management
+ * @run junit/othervm/timeout=1000 JSR166TestCase
+ */
+
+/*
+ * @test
+ * @summary JSR-166 tck tests (whitebox tests allowed)
+ * @build *
  * @modules java.base/java.util.concurrent:open
  *          java.management
- * @build *
- * @run junit/othervm/timeout=1000 -Djsr166.testImplementationDetails=true JSR166TestCase
- * @run junit/othervm/timeout=1000 -Djava.util.concurrent.ForkJoinPool.common.parallelism=0 -Djsr166.testImplementationDetails=true JSR166TestCase
- * @run junit/othervm/timeout=1000 -Djava.util.concurrent.ForkJoinPool.common.parallelism=1 -Djava.util.secureRandomSeed=true JSR166TestCase
+ * @run junit/othervm/timeout=1000
+ *      -Djsr166.testImplementationDetails=true
+ *      JSR166TestCase
+ * @run junit/othervm/timeout=1000
+ *      -Djsr166.testImplementationDetails=true
+ *      -Djava.util.concurrent.ForkJoinPool.common.parallelism=0
+ *      JSR166TestCase
+ * @run junit/othervm/timeout=1000
+ *      -Djsr166.testImplementationDetails=true
+ *      -Djava.util.concurrent.ForkJoinPool.common.parallelism=1
+ *      -Djava.util.secureRandomSeed=true
+ *      JSR166TestCase
  */
 
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
@@ -543,6 +560,8 @@ public class JSR166TestCase extends TestCase {
                 "DoubleAdderTest",
                 "ForkJoinPool8Test",
                 "ForkJoinTask8Test",
+                "LinkedBlockingDeque8Test",
+                "LinkedBlockingQueue8Test",
                 "LongAccumulatorTest",
                 "LongAdderTest",
                 "SplittableRandomTest",
diff --git a/jdk/test/java/util/concurrent/tck/ScheduledExecutorSubclassTest.java b/jdk/test/java/util/concurrent/tck/ScheduledExecutorSubclassTest.java
index 30cf187a64b..aaad2c93679 100644
--- a/jdk/test/java/util/concurrent/tck/ScheduledExecutorSubclassTest.java
+++ b/jdk/test/java/util/concurrent/tck/ScheduledExecutorSubclassTest.java
@@ -71,9 +71,9 @@ public class ScheduledExecutorSubclassTest extends JSR166TestCase {
     }
 
     static class CustomTask implements RunnableScheduledFuture {
-        RunnableScheduledFuture task;
+        private final RunnableScheduledFuture task;
         volatile boolean ran;
-        CustomTask(RunnableScheduledFuture t) { task = t; }
+        CustomTask(RunnableScheduledFuture task) { this.task = task; }
         public boolean isPeriodic() { return task.isPeriodic(); }
         public void run() {
             ran = true;
diff --git a/jdk/test/java/util/concurrent/tck/SubmissionPublisherTest.java b/jdk/test/java/util/concurrent/tck/SubmissionPublisherTest.java
index 9478cf3f86d..51279254bcd 100644
--- a/jdk/test/java/util/concurrent/tck/SubmissionPublisherTest.java
+++ b/jdk/test/java/util/concurrent/tck/SubmissionPublisherTest.java
@@ -402,6 +402,7 @@ public class SubmissionPublisherTest extends JSR166TestCase {
 
     /**
      * Closing a publisher exceptionally causes onError to subscribers
+     * after they are subscribed
      */
     public void testCloseExceptionallyError() {
         SubmissionPublisher p = basicPublisher();
@@ -412,9 +413,11 @@ public class SubmissionPublisherTest extends JSR166TestCase {
         p.submit(1);
         p.closeExceptionally(new SPException());
         assertTrue(p.isClosed());
+        s1.awaitSubscribe();
         s1.awaitError();
         assertTrue(s1.nexts <= 1);
         assertEquals(1, s1.errors);
+        s2.awaitSubscribe();
         s2.awaitError();
         assertTrue(s2.nexts <= 1);
         assertEquals(1, s2.errors);
diff --git a/jdk/test/java/util/concurrent/tck/ThreadLocalRandomTest.java b/jdk/test/java/util/concurrent/tck/ThreadLocalRandomTest.java
index 394bc464142..d805c4d61de 100644
--- a/jdk/test/java/util/concurrent/tck/ThreadLocalRandomTest.java
+++ b/jdk/test/java/util/concurrent/tck/ThreadLocalRandomTest.java
@@ -85,32 +85,41 @@ public class ThreadLocalRandomTest extends JSR166TestCase {
      */
     public void testNext() throws ReflectiveOperationException {
         ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        final java.lang.reflect.Method m;
         try {
-            java.lang.reflect.Method m
-                = ThreadLocalRandom.class.getDeclaredMethod(
+            m = ThreadLocalRandom.class.getDeclaredMethod(
                     "next", new Class[] { int.class });
             m.setAccessible(true);
+        } catch (SecurityException acceptable) {
+            // Security manager may deny access
+            return;
+        } catch (Exception ex) {
+            // jdk9 module system may deny access
+            if (ex.getClass().getSimpleName()
+                .equals("InaccessibleObjectException"))
+                return;
+            throw ex;
+        }
 
-            int i;
-            {
-                int val = new java.util.Random().nextInt(4);
-                for (i = 0; i < NCALLS; i++) {
-                    int q = (int) m.invoke(rnd, new Object[] { 2 });
-                    if (val == q) break;
-                }
-                assertTrue(i < NCALLS);
+        int i;
+        {
+            int val = new java.util.Random().nextInt(4);
+            for (i = 0; i < NCALLS; i++) {
+                int q = (int) m.invoke(rnd, new Object[] { 2 });
+                if (val == q) break;
             }
+            assertTrue(i < NCALLS);
+        }
 
-            {
-                int r = (int) m.invoke(rnd, new Object[] { 3 });
-                for (i = 0; i < NCALLS; i++) {
-                    int q = (int) m.invoke(rnd, new Object[] { 3 });
-                    assertTrue(q < (1<<3));
-                    if (r != q) break;
-                }
-                assertTrue(i < NCALLS);
+        {
+            int r = (int) m.invoke(rnd, new Object[] { 3 });
+            for (i = 0; i < NCALLS; i++) {
+                int q = (int) m.invoke(rnd, new Object[] { 3 });
+                assertTrue(q < (1<<3));
+                if (r != q) break;
             }
-        } catch (SecurityException acceptable) {}
+            assertTrue(i < NCALLS);
+        }
     }
 
     /**
diff --git a/jdk/test/java/util/concurrent/tck/VectorTest.java b/jdk/test/java/util/concurrent/tck/VectorTest.java
index 087b0ed20bc..a1494875b2a 100644
--- a/jdk/test/java/util/concurrent/tck/VectorTest.java
+++ b/jdk/test/java/util/concurrent/tck/VectorTest.java
@@ -58,9 +58,22 @@ public class VectorTest extends JSR166TestCase {
             }
         }
         return newTestSuite(
-                // VectorTest.class,
+                VectorTest.class,
                 CollectionTest.testSuite(new Implementation()),
                 CollectionTest.testSuite(new SubListImplementation()));
     }
 
+    /**
+     * tests for setSize()
+     */
+    public void testSetSize() {
+        Vector v = new Vector();
+        for (int n : new int[] { 100, 5, 50 }) {
+            v.setSize(n);
+            assertEquals(n, v.size());
+            assertNull(v.get(0));
+            assertNull(v.get(n - 1));
+        }
+    }
+
 }

From 6a35fe0f1b358aba9f8271ce7c8a3a93e1d4e063 Mon Sep 17 00:00:00 2001
From: Hamlin Li 
Date: Wed, 21 Dec 2016 18:34:34 -0800
Subject: [PATCH 18/22] 8073080: TEST_BUG:
 sun/rmi/transport/tcp/DeadCachedConnection.java fails due to
 "ConnectException: Connection refused to host"

Reviewed-by: rriggs
---
 .../java/rmi/testlibrary/RegistryRunner.java  |  2 +-
 .../transport/tcp/DeadCachedConnection.java   | 88 +++++++++----------
 2 files changed, 41 insertions(+), 49 deletions(-)

diff --git a/jdk/test/java/rmi/testlibrary/RegistryRunner.java b/jdk/test/java/rmi/testlibrary/RegistryRunner.java
index af3f4452540..e8c9ab45873 100644
--- a/jdk/test/java/rmi/testlibrary/RegistryRunner.java
+++ b/jdk/test/java/rmi/testlibrary/RegistryRunner.java
@@ -36,7 +36,7 @@ public class RegistryRunner extends UnicastRemoteObject
     implements RemoteExiter
 {
     private static final String PORT_LABEL_START = "RegistryRunner.port.start:";
-    private static final String PORT_LABEL_END = "RegistryRunner.port.end";
+    private static final String PORT_LABEL_END = ":RegistryRunner.port.end";
 
     private static Registry registry = null;
     private static RemoteExiter exiter = null;
diff --git a/jdk/test/sun/rmi/transport/tcp/DeadCachedConnection.java b/jdk/test/sun/rmi/transport/tcp/DeadCachedConnection.java
index 9ec9d043923..cbc34f7687e 100644
--- a/jdk/test/sun/rmi/transport/tcp/DeadCachedConnection.java
+++ b/jdk/test/sun/rmi/transport/tcp/DeadCachedConnection.java
@@ -29,7 +29,7 @@
  *          java.rmi/sun.rmi.server
  *          java.rmi/sun.rmi.transport
  *          java.rmi/sun.rmi.transport.tcp
- * @build TestLibrary JavaVM
+ * @build TestLibrary REGISTRY RegistryRunner
  * @run main/othervm DeadCachedConnection
  */
 
@@ -60,73 +60,65 @@ import java.rmi.registry.*;
 import java.rmi.server.*;
 
 public class DeadCachedConnection {
-    static public final int regport = TestLibrary.getUnusedRandomPort();
 
     static public void main(String[] argv)
         throws Exception {
-        // establish the registry (we hope)
-        System.err.println ("Starting registry on port " + regport);
-        DeadCachedConnection.makeRegistry(regport);
-
-        // Get a handle to the registry
-        Registry reg = null;
-        System.err.println ("Locating just-started registry...");
         try {
-            reg = LocateRegistry.getRegistry(regport);
-        } catch (RemoteException e) {
-            throw new InternalError ("Can't find registry after starting it.");
-        }
+            Registry reg = null;
+            int port = makeRegistry(0);
 
-        // Contact the registry by invoking something on it.
-        System.err.println ("Connecting to registry...");
-        String[] junk = reg.list();
+            // Get a handle to the registry
+            System.err.println ("Locating just-started registry...");
+            try {
+                reg = LocateRegistry.getRegistry(port);
+            } catch (RemoteException e) {
+                throw new InternalError ("Can't find registry after starting it.");
+            }
 
-        // Kill and restart the registry
-        System.err.println("Killing registry...");
-        DeadCachedConnection.killRegistry();
-        System.err.println("Restarting registry...");
-        DeadCachedConnection.makeRegistry(regport);
+            // Contact the registry by invoking something on it.
+            System.err.println ("Connecting to registry...");
+            String[] junk = reg.list();
 
-        // Try again (this is the test)
-        System.err.println("Trying to use registry in spite of stale cache...");
-        junk = reg.list();
+            // Kill and restart the registry
+            System.err.println("Killing registry...");
+            killRegistry();
+            System.err.println("Restarting registry...");
+            makeRegistry(port);
 
-        // we're happy
-        System.err.println("Test succeeded.");
-        try {
-            DeadCachedConnection.killRegistry();
-        } catch (Exception foo) {
+            // Try again (this is the test)
+            System.err.println("Trying to use registry in spite of stale cache...");
+            junk = reg.list();
+
+            System.err.println("Test succeeded.");
+        } catch (Exception e) {
+            TestLibrary.bomb(e);
+        } finally {
+            // dont leave the registry around to affect other tests.
+            killRegistry();
         }
     }
 
-    public static void makeRegistry(int p) {
-        // sadly, we can't kill a registry if we have too-close control
-        // over it.  We must make it in a subprocess, and then kill the
-        // subprocess when it has served our needs.
-
+    public static int makeRegistry(int port) {
         try {
-            JavaVM jvm =
-                new JavaVM("sun.rmi.registry.RegistryImpl", "", Integer.toString(p));
-            jvm.start();
-            DeadCachedConnection.subreg = jvm;
-
+            subreg = REGISTRY.createREGISTRY(System.out, System.err, "", port);
+            subreg.start();
+            int regPort = subreg.getPort();
+            System.out.println("Starting registry on port " + regPort);
+            return regPort;
         } catch (IOException e) {
             // one of these is summarily dropped, can't remember which one
             System.out.println ("Test setup failed - cannot run rmiregistry");
             TestLibrary.bomb("Test setup failed - cannot run test", e);
         }
-        // Slop - wait for registry to come up.  This is stupid.
-        try {
-            Thread.sleep (5000);
-        } catch (Exception whatever) {
-        }
+        return -1;
     }
-    private static JavaVM subreg = null;
+
+    private static REGISTRY subreg = null;
 
     public static void killRegistry() throws InterruptedException {
-        if (DeadCachedConnection.subreg != null) {
-            DeadCachedConnection.subreg.terminate();
+        if (subreg != null) {
+            subreg.shutdown();
+            subreg = null;
         }
-        DeadCachedConnection.subreg = null;
     }
 }

From ea0870c789e3660832ef31556f9fe462ad09fa1a Mon Sep 17 00:00:00 2001
From: Xue-Lei Andrew Fan 
Date: Thu, 22 Dec 2016 03:35:44 +0000
Subject: [PATCH 19/22] 6972386: issues with String.toLowerCase/toUpperCase

Reviewed-by: weijun
---
 .../share/classes/sun/security/provider/CtrDrbg.java          | 2 +-
 .../share/classes/sun/security/x509/AlgorithmId.java          | 4 ++--
 .../oracle/security/ucrypto/NativeCipherWithJavaPadding.java  | 3 ++-
 3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/jdk/src/java.base/share/classes/sun/security/provider/CtrDrbg.java b/jdk/src/java.base/share/classes/sun/security/provider/CtrDrbg.java
index d595dd46e95..316e9eac98c 100644
--- a/jdk/src/java.base/share/classes/sun/security/provider/CtrDrbg.java
+++ b/jdk/src/java.base/share/classes/sun/security/provider/CtrDrbg.java
@@ -80,7 +80,7 @@ public class CtrDrbg extends AbstractDrbg {
     @Override
     protected void chooseAlgorithmAndStrength() {
         if (requestedAlgorithm != null) {
-            algorithm = requestedAlgorithm.toUpperCase();
+            algorithm = requestedAlgorithm.toUpperCase(Locale.ROOT);
             int supportedStrength = alg2strength(algorithm);
             if (requestedInstantiationSecurityStrength >= 0) {
                 int tryStrength = getStandardStrength(
diff --git a/jdk/src/java.base/share/classes/sun/security/x509/AlgorithmId.java b/jdk/src/java.base/share/classes/sun/security/x509/AlgorithmId.java
index a7754e67301..d77ba65dfc1 100644
--- a/jdk/src/java.base/share/classes/sun/security/x509/AlgorithmId.java
+++ b/jdk/src/java.base/share/classes/sun/security/x509/AlgorithmId.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
@@ -1009,7 +1009,7 @@ public class AlgorithmId implements Serializable, DerEncoder {
      * @return the default alg, might be null if unsupported
      */
     public static String getDefaultSigAlgForKey(PrivateKey k) {
-        switch (k.getAlgorithm().toUpperCase()) {
+        switch (k.getAlgorithm().toUpperCase(Locale.ROOT)) {
             case "EC":
                 return ecStrength(KeyUtil.getKeySize(k))
                     + "withECDSA";
diff --git a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeCipherWithJavaPadding.java b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeCipherWithJavaPadding.java
index 56ddee9726b..211582c4ed9 100644
--- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeCipherWithJavaPadding.java
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeCipherWithJavaPadding.java
@@ -28,6 +28,7 @@ package com.oracle.security.ucrypto;
 import java.nio.ByteBuffer;
 import java.util.Set;
 import java.util.Arrays;
+import java.util.Locale;
 import java.util.concurrent.ConcurrentSkipListSet;
 import java.lang.ref.*;
 
@@ -262,7 +263,7 @@ public class NativeCipherWithJavaPadding extends CipherSpi {
         throws NoSuchAlgorithmException, NoSuchPaddingException {
         this.nc = nc;
         this.blockSize = nc.engineGetBlockSize();
-        if (paddingScheme.toUpperCase().equals("PKCS5PADDING")) {
+        if (paddingScheme.toUpperCase(Locale.ROOT).equals("PKCS5PADDING")) {
             padding = new PKCS5Padding(blockSize);
         } else {
             throw new NoSuchAlgorithmException("Unsupported padding scheme: " + paddingScheme);

From 716457d7f5ad6000fd62281948537d60ca006e6a Mon Sep 17 00:00:00 2001
From: Rachna Goel 
Date: Thu, 22 Dec 2016 06:05:31 +0000
Subject: [PATCH 20/22] 8167143: CLDR timezone parsing does not work for all
 locales

Reviewed-by: naoto
---
 jdk/make/gensrc/GensrcLocaleData.gmk          |   6 +-
 .../tools/cldrconverter/CLDRConverter.java    |  35 ++-
 .../classes/java/text/DateFormatSymbols.java  |  10 -
 .../classes/java/util/ResourceBundle.java     |  26 +-
 jdk/test/java/util/Currency/CurrencyTest.java |   6 +-
 jdk/test/java/util/TimeZone/Bug8167143.java   | 279 ++++++++++++++++++
 .../sun/util/locale/provider/Bug8038436.java  |  14 +-
 7 files changed, 343 insertions(+), 33 deletions(-)
 create mode 100644 jdk/test/java/util/TimeZone/Bug8167143.java

diff --git a/jdk/make/gensrc/GensrcLocaleData.gmk b/jdk/make/gensrc/GensrcLocaleData.gmk
index e7d19951cce..7d83b555bb5 100644
--- a/jdk/make/gensrc/GensrcLocaleData.gmk
+++ b/jdk/make/gensrc/GensrcLocaleData.gmk
@@ -64,7 +64,7 @@ endif
 BASE_LOCALES := en en-US
 
 # Locales that don't have any resource files should be included here.
-ALL_NON_BASE_LOCALES := ja-JP-JP nb-NO nn-NO th-TH-TH
+ALL_NON_BASE_LOCALES := ja-JP-JP th-TH-TH
 
 SED_BASEARGS := -e 's|$(HASH)warn This file is preprocessed before being compiled|// -- This file was mechanically generated: Do not edit! -- //|g'
 SED_NONBASEARGS := $(SED_BASEARGS)
@@ -89,6 +89,10 @@ define CaptureLocale
   $1_NON_BASE_LOCALES := $$(subst zh-MO,zh-MO$$(SPACE)zh-Hant-MO, $$($1_NON_BASE_LOCALES))
   $1_NON_BASE_LOCALES := $$(subst zh-TW,zh-TW$$(SPACE)zh-Hant-TW, $$($1_NON_BASE_LOCALES))
 
+# Adding implict locales nn-NO and nb-NO
+  $1_NON_BASE_LOCALES += nn-NO  nb-NO
+  $1_NON_BASE_LOCALES := $$(sort $$($1_NON_BASE_LOCALES))
+
   ALL_BASE_LOCALES += $$($1_BASE_LOCALES)
   ALL_NON_BASE_LOCALES += $$($1_NON_BASE_LOCALES)
 
diff --git a/jdk/make/src/classes/build/tools/cldrconverter/CLDRConverter.java b/jdk/make/src/classes/build/tools/cldrconverter/CLDRConverter.java
index 59b1054a000..22ff322c804 100644
--- a/jdk/make/src/classes/build/tools/cldrconverter/CLDRConverter.java
+++ b/jdk/make/src/classes/build/tools/cldrconverter/CLDRConverter.java
@@ -487,10 +487,43 @@ public class CLDRConverter {
             metaInfo.get("AvailableLocales").add(toLanguageTag(bundle.getID()));
             addLikelySubtags(metaInfo, "AvailableLocales", bundle.getID());
         }
-
+        addCldrImplicitLocales(metaInfo);
         bundleGenerator.generateMetaInfo(metaInfo);
     }
 
+    /**
+     * These are the Locales that are implicitly supported by CLDR.
+     * Adding them explicitly as likelySubtags here, will ensure that
+     * COMPAT locales do not precede them during ResourceBundle search path.
+     */
+    private static void addCldrImplicitLocales(Map> metaInfo) {
+        metaInfo.get("LocaleNames").add("zh-Hans-CN");
+        metaInfo.get("LocaleNames").add("zh-Hans-SG");
+        metaInfo.get("LocaleNames").add("zh-Hant-HK");
+        metaInfo.get("LocaleNames").add("zh-Hant-MO");
+        metaInfo.get("LocaleNames").add("zh-Hant-TW");
+        metaInfo.get("CurrencyNames").add("zh-Hans-CN");
+        metaInfo.get("CurrencyNames").add("zh-Hans-SG");
+        metaInfo.get("CurrencyNames").add("zh-Hant-HK");
+        metaInfo.get("CurrencyNames").add("zh-Hant-MO");
+        metaInfo.get("CurrencyNames").add("zh-Hant-TW");
+        metaInfo.get("TimeZoneNames").add("zh-Hans-CN");
+        metaInfo.get("TimeZoneNames").add("zh-Hans-SG");
+        metaInfo.get("TimeZoneNames").add("zh-Hant-HK");
+        metaInfo.get("TimeZoneNames").add("zh-Hant-MO");
+        metaInfo.get("TimeZoneNames").add("zh-Hant-TW");
+        metaInfo.get("TimeZoneNames").add("zh-HK");
+        metaInfo.get("CalendarData").add("zh-Hans-CN");
+        metaInfo.get("CalendarData").add("zh-Hans-SG");
+        metaInfo.get("CalendarData").add("zh-Hant-HK");
+        metaInfo.get("CalendarData").add("zh-Hant-MO");
+        metaInfo.get("CalendarData").add("zh-Hant-TW");
+        metaInfo.get("FormatData").add("zh-Hans-CN");
+        metaInfo.get("FormatData").add("zh-Hans-SG");
+        metaInfo.get("FormatData").add("zh-Hant-HK");
+        metaInfo.get("FormatData").add("zh-Hant-MO");
+        metaInfo.get("FormatData").add("zh-Hant-TW");
+    }
     static final Map aliases = new HashMap<>();
 
     /**
diff --git a/jdk/src/java.base/share/classes/java/text/DateFormatSymbols.java b/jdk/src/java.base/share/classes/java/text/DateFormatSymbols.java
index 0c9b50ae152..0360631a02d 100644
--- a/jdk/src/java.base/share/classes/java/text/DateFormatSymbols.java
+++ b/jdk/src/java.base/share/classes/java/text/DateFormatSymbols.java
@@ -758,16 +758,6 @@ public class DateFormatSymbols implements Serializable, Cloneable {
                     dfs = y;
                 }
             }
-            // If the bundle's locale isn't the target locale, put another cache
-            // entry for the bundle's locale.
-            Locale bundleLocale = resource.getLocale();
-            if (!bundleLocale.equals(locale)) {
-                SoftReference z
-                    = cachedInstances.putIfAbsent(bundleLocale, ref);
-                if (z != null && z.get() == null) {
-                    cachedInstances.replace(bundleLocale, z, ref);
-                }
-            }
         }
 
         // Copy the field values from dfs to this instance.
diff --git a/jdk/src/java.base/share/classes/java/util/ResourceBundle.java b/jdk/src/java.base/share/classes/java/util/ResourceBundle.java
index 78e86e5f2f4..109ca64a42e 100644
--- a/jdk/src/java.base/share/classes/java/util/ResourceBundle.java
+++ b/jdk/src/java.base/share/classes/java/util/ResourceBundle.java
@@ -2942,17 +2942,6 @@ public abstract class ResourceBundle {
                             script = "Hans";
                             break;
                         }
-                    } else if (script.length() > 0 && region.length() == 0) {
-                        // Supply region(country) for users who still package Chinese
-                        // bundles using old convension.
-                        switch (script) {
-                        case "Hans":
-                            region = "CN";
-                            break;
-                        case "Hant":
-                            region = "TW";
-                            break;
-                        }
                     }
                 }
 
@@ -2983,6 +2972,21 @@ public abstract class ResourceBundle {
                 }
                 if (script.length() > 0) {
                     list.add(Locale.getInstance(language, script, "", "", null));
+                    // Special handling for Chinese
+                    if (language.equals("zh")) {
+                        if (region.length() == 0) {
+                            // Supply region(country) for users who still package Chinese
+                            // bundles using old convension.
+                            switch (script) {
+                                case "Hans":
+                                    region = "CN";
+                                    break;
+                                case "Hant":
+                                    region = "TW";
+                                    break;
+                            }
+                        }
+                    }
 
                     // With script, after truncating variant, region and script,
                     // start over without script.
diff --git a/jdk/test/java/util/Currency/CurrencyTest.java b/jdk/test/java/util/Currency/CurrencyTest.java
index 58839392e6d..54b05afe978 100644
--- a/jdk/test/java/util/Currency/CurrencyTest.java
+++ b/jdk/test/java/util/Currency/CurrencyTest.java
@@ -23,7 +23,7 @@
 /*
  * @test
  * @bug 4290801 4692419 4693631 5101540 5104960 6296410 6336600 6371531
- *    6488442 7036905 8008577 8039317 8074350 8074351 8150324
+ *    6488442 7036905 8008577 8039317 8074350 8074351 8150324 8167143
  * @summary Basic tests for Currency class.
  * @modules java.base/java.util:open
  *          jdk.localedata
@@ -188,7 +188,7 @@ public class CurrencyTest {
     static void testSymbols() {
         testSymbol("USD", Locale.US, "$");
         testSymbol("EUR", Locale.GERMANY, "\u20AC");
-        testSymbol("USD", Locale.PRC, "USD");
+        testSymbol("USD", Locale.PRC, "US$");
     }
 
     static void testSymbol(String currencyCode, Locale locale, String expectedSymbol) {
@@ -262,7 +262,7 @@ public class CurrencyTest {
         testDisplayName("KRW", Locale.KOREAN, "\ub300\ud55c\ubbfc\uad6d \uc6d0");
         testDisplayName("SEK", new Locale("sv"), "svensk krona");
         testDisplayName("CNY", Locale.SIMPLIFIED_CHINESE, "\u4eba\u6c11\u5e01");
-        testDisplayName("TWD", Locale.TRADITIONAL_CHINESE, "\u65b0\u81fa\u5e63");
+        testDisplayName("TWD", Locale.TRADITIONAL_CHINESE, "\u65b0\u53f0\u5e63");
     }
 
     static void testDisplayName(String currencyCode, Locale locale, String expectedName) {
diff --git a/jdk/test/java/util/TimeZone/Bug8167143.java b/jdk/test/java/util/TimeZone/Bug8167143.java
new file mode 100644
index 00000000000..7f7794ce2c0
--- /dev/null
+++ b/jdk/test/java/util/TimeZone/Bug8167143.java
@@ -0,0 +1,279 @@
+/*
+ * 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 8167143
+ * @summary Test
+ * Timezone parsing works for all locales for default providers prefernce
+ * as well as when  prefernce list is [COMPAT, CLDR],
+ * CLDR implict locales are correctly reflected,
+ * th_TH bundle is not wrongly cached in DateFormatSymbols,
+ * correct candidate locale list is retrieved for
+ * zh_Hant and zh_Hans and
+ * Implict COMPAT Locales nn-NO, nb-NO are reflected in available locales
+ * for all Providers for COMPAT.
+ * @modules java.base/sun.util.locale.provider
+ *          java.base/sun.util.spi
+ *          jdk.localedata
+ * @run main/othervm -Djava.locale.providers=COMPAT,CLDR Bug8167143 testTimeZone
+ * @run main/othervm  Bug8167143 testTimeZone
+ * @run main/othervm -Djava.locale.providers=CLDR Bug8167143 testCldr
+ * @run main/othervm  Bug8167143 testCache
+ * @run main/othervm  Bug8167143 testCandidateLocales
+ * @run main/othervm  -Djava.locale.providers=COMPAT Bug8167143 testCompat
+ */
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.TimeZone;
+
+import sun.util.locale.provider.LocaleProviderAdapter;
+import sun.util.locale.provider.LocaleProviderAdapter.Type;
+
+public class Bug8167143 {
+
+    private static final TimeZone REYKJAVIK = TimeZone.getTimeZone("Atlantic/Reykjavik");
+    private static final TimeZone NEW_YORK = TimeZone.getTimeZone("America/New_York");
+    private static final TimeZone GMT = TimeZone.getTimeZone("GMT");
+
+    private static final List CLDR_IMPLICIT_LOCS = List.of(Locale.forLanguageTag("zh-Hans-CN"),
+            Locale.forLanguageTag("zh-Hans-SG"),
+            Locale.forLanguageTag("zh-Hant-HK"),
+            Locale.forLanguageTag("zh-Hant-TW"),
+            Locale.forLanguageTag("zh-Hant-MO"));
+
+    private static final List COMPAT_IMPLICIT_LOCS = List.of(Locale.forLanguageTag("nn-NO"),
+            Locale.forLanguageTag("nb-NO"));
+    /**
+     * List of candidate locales for zh_Hant
+     */
+    private static final List ZH_HANT_CANDLOCS = List.of(
+            Locale.forLanguageTag("zh-Hant"),
+            Locale.forLanguageTag("zh-TW"),
+            Locale.forLanguageTag("zh"),
+            Locale.ROOT);
+    /**
+     * List of candidate locales for zh_Hans
+     */
+    private static final List ZH_HANS_CANDLOCS = List.of(
+            Locale.forLanguageTag("zh-Hans"),
+            Locale.forLanguageTag("zh-CN"),
+            Locale.forLanguageTag("zh"),
+            Locale.ROOT);
+
+    public static void main(String[] args) {
+        switch (args[0]) {
+            case "testTimeZone":
+                testTimeZoneParsing();
+                break;
+            case "testCldr":
+                testImplicitCldrLocales();
+                break;
+            case "testCache":
+                testDateFormatSymbolsCache();
+                break;
+            case "testCandidateLocales":
+                testCandidateLocales();
+                break;
+            case "testCompat":
+                testImplicitCompatLocales();
+                break;
+            default:
+                throw new RuntimeException("no test was specified.");
+        }
+    }
+
+    /**
+     * Check that if Locale Provider Preference list is Default, or if Locale
+     * Provider Preference List is COMPAT,CLDR SimplDateFormat parsing works for
+     * all Available Locales.
+     */
+    private static void testTimeZoneParsing() {
+        Set locales = Set.of(Locale.forLanguageTag("zh-hant"), new Locale("no", "NO", "NY"));
+        // Set locales = Set.of(Locale.getAvailableLocales());
+        locales.forEach((locale) -> {
+            final SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd z", locale);
+            for (final TimeZone tz : new TimeZone[]{REYKJAVIK, GMT, NEW_YORK}) {
+                try {
+                    sdf.parse("2000/02/10 " + tz.getDisplayName(locale));
+                } catch (ParseException e) {
+                    throw new RuntimeException("TimeZone Parsing failed with Locale "
+                            + locale + " for TimeZone  " + tz.getDisplayName(), e);
+                }
+            }
+        });
+    }
+
+    /**
+     * Check that locales implicitly supported from CLDR are reflected in output
+     * from getAvailbleLocales() for each bundle.
+     *
+     */
+    private static void testImplicitCldrLocales() {
+        LocaleProviderAdapter cldr = LocaleProviderAdapter.forType(Type.CLDR);
+        checkPresenceCldr("CurrencyNameProvider",
+                cldr.getCurrencyNameProvider().getAvailableLocales());
+        checkPresenceCldr("LocaleNameProvider",
+                cldr.getLocaleNameProvider().getAvailableLocales());
+        checkPresenceCldr("TimeZoneNameProvider",
+                cldr.getTimeZoneNameProvider().getAvailableLocales());
+        checkPresenceCldr("CalendarDataProvider",
+                cldr.getCalendarDataProvider().getAvailableLocales());
+        checkPresenceCldr("CalendarNameProvider",
+                cldr.getCalendarProvider().getAvailableLocales());
+    }
+
+    private static void checkPresenceCldr(String testName, Locale[] got) {
+        List gotLocalesList = Arrays.asList(got);
+        List gotList = new ArrayList<>(gotLocalesList);
+        if (!testName.equals("TimeZoneNameProvider")) {
+            if (!gotList.removeAll(CLDR_IMPLICIT_LOCS)) {
+                // check which locale are not present in retrievedLocales List.
+                List expectedLocales = new ArrayList<>(CLDR_IMPLICIT_LOCS);
+                expectedLocales.removeAll(gotList);
+                throw new RuntimeException("Locales those not correctly reflected are "
+                        + expectedLocales + " for test " + testName);
+            }
+        } else {
+            // check one extra locale zh_HK for TimeZoneNameProvider
+            Locale zh_HK = Locale.forLanguageTag("zh-HK");
+            if (!gotList.removeAll(CLDR_IMPLICIT_LOCS) && gotList.remove(zh_HK)) {
+                //check which locale are not present in retrievedLocales List
+                List expectedLocales = new ArrayList<>(CLDR_IMPLICIT_LOCS);
+                expectedLocales.add(zh_HK);
+                expectedLocales.removeAll(gotList);
+                throw new RuntimeException("Locales those not correctly reflected are "
+                        + expectedLocales + " for test " + testName);
+            }
+        }
+    }
+
+    /**
+     * Check that if Locale Provider Preference list is default and if
+     * SimpleDateFormat instance for th-TH-TH is created first, then JRE bundle
+     * for th-TH should not be cached in cache of DateFormatSymbols class.
+     */
+    private static void testDateFormatSymbolsCache() {
+        Locale th_TH_TH = new Locale("th", "TH", "TH");
+        Locale th_TH = new Locale("th", "TH");
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd z", th_TH_TH);
+        String[][] thTHTHZoneStrings = sdf.getDateFormatSymbols().getZoneStrings();
+        String[][] thTHZoneStrings = sdf.getDateFormatSymbols().getZoneStrings();
+        if (Arrays.equals(thTHTHZoneStrings, thTHZoneStrings)) {
+            throw new RuntimeException("th_TH bundle still cached with DateFormatSymbols"
+                    + "cache for locale  " + th_TH
+            );
+        }
+    }
+
+    /**
+     * Check that candidate locales list retrieved for zh__Hant and for zh__Hans
+     * do not have first candidate locale as zh_TW_Hant and zh_CN_Hans
+     * respectively.
+     */
+    private static void testCandidateLocales() {
+        ResourceBundle.Control Control = ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT);
+        Locale zh_Hant = Locale.forLanguageTag("zh-Hant");
+        Locale zh_Hans = Locale.forLanguageTag("zh-Hans");
+        List zhHantCandidateLocs = Control.getCandidateLocales("", zh_Hant);
+        List zhHansCandidateLocs = Control.getCandidateLocales("", zh_Hans);
+        if (!zhHantCandidateLocs.equals(ZH_HANT_CANDLOCS)) {
+            reportDifference(zhHantCandidateLocs, ZH_HANT_CANDLOCS, "zh_Hant");
+
+        }
+        if (!zhHansCandidateLocs.equals(ZH_HANS_CANDLOCS)) {
+            reportDifference(zhHansCandidateLocs, ZH_HANS_CANDLOCS, "zh_Hans");
+
+        }
+    }
+
+    private static void reportDifference(List got, List expected, String locale) {
+        List retrievedList = new ArrayList<>(got);
+        List expectedList = new ArrayList<>(expected);
+        retrievedList.removeAll(expectedList);
+        expectedList.removeAll(retrievedList);
+        if ((retrievedList.size() > 0) && (expectedList.size() > 0)) {
+            throw new RuntimeException(" retrievedList contain extra candidate locales " + retrievedList
+                    + " and missing candidate locales " + expectedList
+                    + "for locale " + locale);
+        }
+        if ((retrievedList.size() > 0)) {
+            throw new RuntimeException(" retrievedList contain extra candidate locales " + retrievedList
+                    + "for locale " + locale);
+        }
+        if ((expectedList.size() > 0)) {
+            throw new RuntimeException(" retrievedList contain extra candidate locales " + expectedList
+                    + "for locale " + locale);
+        }
+    }
+
+    /**
+     * checks that locales nn-NO  and nb-NO should be present in list of supported locales for
+     * all Providers for COMPAT.
+     */
+    private static void testImplicitCompatLocales() {
+        LocaleProviderAdapter jre = LocaleProviderAdapter.forJRE();
+        checkPresenceCompat("BreakIteratorProvider",
+            jre.getBreakIteratorProvider().getAvailableLocales());
+        checkPresenceCompat("CollatorProvider",
+            jre.getCollatorProvider().getAvailableLocales());
+        checkPresenceCompat("DateFormatProvider",
+            jre.getDateFormatProvider().getAvailableLocales());
+        checkPresenceCompat("DateFormatSymbolsProvider",
+            jre.getDateFormatSymbolsProvider().getAvailableLocales());
+        checkPresenceCompat("DecimalFormatSymbolsProvider",
+            jre.getDecimalFormatSymbolsProvider().getAvailableLocales());
+        checkPresenceCompat("NumberFormatProvider",
+            jre.getNumberFormatProvider().getAvailableLocales());
+        checkPresenceCompat("CurrencyNameProvider",
+            jre.getCurrencyNameProvider().getAvailableLocales());
+        checkPresenceCompat("LocaleNameProvider",
+            jre.getLocaleNameProvider().getAvailableLocales());
+        checkPresenceCompat("TimeZoneNameProvider",
+            jre.getTimeZoneNameProvider().getAvailableLocales());
+        checkPresenceCompat("CalendarDataProvider",
+            jre.getCalendarDataProvider().getAvailableLocales());
+        checkPresenceCompat("CalendarNameProvider",
+            jre.getCalendarNameProvider().getAvailableLocales());
+        checkPresenceCompat("CalendarProvider",
+            jre.getCalendarProvider().getAvailableLocales());
+    }
+
+    private static void checkPresenceCompat(String testName, Locale[] got) {
+        List gotLocalesList = Arrays.asList(got);
+        List gotList = new ArrayList<>(gotLocalesList);
+            if (!gotList.removeAll(COMPAT_IMPLICIT_LOCS)) {
+                // check which Implicit locale are not present in retrievedLocales List.
+                List implicitLocales = new ArrayList<>(COMPAT_IMPLICIT_LOCS);
+                implicitLocales.removeAll(gotList);
+                throw new RuntimeException("Locales those not correctly reflected are "
+                        + implicitLocales + " for test " + testName);
+            }
+    }
+}
diff --git a/jdk/test/sun/util/locale/provider/Bug8038436.java b/jdk/test/sun/util/locale/provider/Bug8038436.java
index cc578410fb1..3d4f0822b7a 100644
--- a/jdk/test/sun/util/locale/provider/Bug8038436.java
+++ b/jdk/test/sun/util/locale/provider/Bug8038436.java
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8038436 8158504 8065555
+ * @bug 8038436 8158504 8065555 8167143
  * @summary Test for changes in 8038436
  * @modules java.base/sun.util.locale.provider
  *          java.base/sun.util.spi
@@ -120,7 +120,7 @@ public class Bug8038436 {
         "fi, fi-FI, fr, fr-BE, fr-CA, fr-CH, fr-FR, ga, ga-IE, he, he-IL, " +
         "hi-IN, hr, hr-HR, hu, hu-HU, id, id-ID, is, is-IS, it, it-CH, it-IT, " +
         "ja, ja-JP, ko, ko-KR, lt, lt-LT, lv, lv-LV, mk, mk-MK, ms, ms-MY, mt, " +
-        "mt-MT, nl, nl-BE, nl-NL, no, no-NO, no-NO, pl, pl-PL, pt, pt-BR, " +
+        "mt-MT, nb-NO, nl, nl-BE, nl-NL, nn-NO, no, no-NO, no-NO, pl, pl-PL, pt, pt-BR, " +
         "pt-PT, ro, ro-RO, ru, ru-RU, sk, sk-SK, sl, sl-SI, sq, sq-AL, sr, " +
         "sr-BA, sr-CS, sr-Latn, sr-Latn-ME, sr-ME, sr-RS, sv, sv-SE, th, th-TH, " +
         "tr, tr-TR, uk, uk-UA, und, vi, vi-VN, zh, zh-CN, zh-HK, zh-Hans-CN, " +
@@ -130,7 +130,7 @@ public class Bug8038436 {
     static final String[] decimalfspLocs = bipLocs;
     static final String[] calnpLocs = bipLocs;
     static final String[] cpLocs = ("ar, be, bg, ca, cs, da, el, es, et, fi, " +
-        "fr, he, hi, hr, hu, is, ja, ko, lt, lv, mk, no, pl, ro, ru, sk, sl, " +
+        "fr, he, hi, hr, hu, is, ja, ko, lt, lv, mk, nb-NO, nn-NO, no, pl, ro, ru, sk, sl, " +
         "sq, sr, sr-Latn, sv, th, tr, uk, und, vi, zh, zh-HK, zh-Hant-HK, " +
         "zh-Hant-TW, zh-TW, ").split(",\\s*");
     static final String[] nfpLocs = ("ar, ar-AE, ar-BH, ar-DZ, ar-EG, ar-IQ, " +
@@ -160,22 +160,22 @@ public class Bug8038436 {
         "es-PA, es-PE, es-PR, es-PY, es-SV, es-US, es-UY, es-VE, et-EE, fi-FI, " +
         "fr, fr-BE, fr-CA, fr-CH, fr-FR, fr-LU, ga-IE, he-IL, hi-IN, hr-HR, " +
         "hu-HU, id-ID, is-IS, it, it-CH, it-IT, ja, ja-JP, ko, ko-KR, lt-LT, " +
-        "lv-LV, mk-MK, ms-MY, mt-MT, nl-BE, nl-NL, no-NO, pl-PL, pt, pt-BR, " +
+        "lv-LV, mk-MK, ms-MY, mt-MT, nb-NO, nl-BE, nl-NL, nn-NO, no-NO, pl-PL, pt, pt-BR, " +
         "pt-PT, ro-RO, ru-RU, sk-SK, sl-SI, sq-AL, sr-BA, sr-CS, sr-Latn-BA, " +
         "sr-Latn-ME, sr-Latn-RS, sr-ME, sr-RS, sv, sv-SE, th-TH, tr-TR, uk-UA, " +
         "und, vi-VN, zh-CN, zh-HK, zh-Hans-CN, zh-Hans-SG, zh-Hant-HK, " +
         "zh-Hant-TW, zh-SG, zh-TW, ").split(",\\s*");
     static final String[] lnpLocs = ("ar, be, bg, ca, cs, da, de, el, el-CY, " +
         "en, en-MT, en-PH, en-SG, es, es-US, et, fi, fr, ga, he, hi, hr, hu, " +
-        "id, is, it, ja, ko, lt, lv, mk, ms, mt, nl, no, no-NO, pl, pt, pt-BR, " +
+        "id, is, it, ja, ko, lt, lv, mk, ms, mt, nb-NO, nl, nn-NO, no, no-NO, pl, pt, pt-BR, " +
         "pt-PT, ro, ru, sk, sl, sq, sr, sr-Latn, sv, th, tr, uk, und, vi, zh, " +
         "zh-HK, zh-Hans-SG, zh-Hant-HK, zh-Hant-TW, zh-SG, zh-TW, ").split(",\\s*");
     static final String[] tznpLocs = ("de, en, en-CA, en-GB, en-IE, es, fr, hi, " +
-        "it, ja, ko, pt-BR, sv, und, zh-CN, zh-HK, zh-Hans-CN, zh-Hant-HK, " +
+        "it, ja, ko, nb-NO, nn-NO, pt-BR, sv, und, zh-CN, zh-HK, zh-Hans-CN, zh-Hant-HK, " +
         "zh-Hant-TW, zh-TW, ").split(",\\s*");
     static final String[] caldpLocs = ("ar, be, bg, ca, cs, da, de, el, el-CY, " +
         "en, en-GB, en-IE, en-MT, es, es-ES, es-US, et, fi, fr, fr-CA, he, hi, " +
-        "hr, hu, id-ID, is, it, ja, ko, lt, lv, mk, ms-MY, mt, mt-MT, nl, no, " +
+        "hr, hu, id-ID, is, it, ja, ko, lt, lv, mk, ms-MY, mt, mt-MT, nb-NO, nl, nn-NO, no, " +
         "pl, pt, pt-BR, pt-PT, ro, ru, sk, sl, sq, sr, sr-Latn-BA, sr-Latn-ME, " +
         "sr-Latn-RS, sv, th, tr, uk, und, vi, zh, ").split(",\\s*");
     static final String[] calpLocs = caldpLocs;

From 3312369cf57f092845ab9ba442c8f0435d947fc7 Mon Sep 17 00:00:00 2001
From: Sibabrata Sahoo 
Date: Wed, 21 Dec 2016 23:57:12 -0800
Subject: [PATCH 21/22] 8161232: AsyncSSLSocketClose.java test fails timeout

AsyncSSLSocketClose.java test fails timeout

Reviewed-by: xuelei
---
 jdk/test/ProblemList.txt | 2 --
 1 file changed, 2 deletions(-)

diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt
index 46772740c6b..6230a3cd1f6 100644
--- a/jdk/test/ProblemList.txt
+++ b/jdk/test/ProblemList.txt
@@ -215,8 +215,6 @@ sun/security/tools/keytool/ListKeychainStore.sh                 8156889 macosx-a
 
 sun/security/tools/jarsigner/warnings/BadKeyUsageTest.java      8026393 generic-all
 
-sun/security/ssl/SSLSocketImpl/AsyncSSLSocketClose.java         8161232 macosx-all
-
 javax/net/ssl/DTLS/PacketLossRetransmission.java                8169086 macosx-x64
 
 ############################################################################

From 7c3de194b5631d67a6ed575be490c2c8225b59a1 Mon Sep 17 00:00:00 2001
From: Vinnie Ryan 
Date: Thu, 22 Dec 2016 17:15:33 +0000
Subject: [PATCH 22/22] 8171443: (spec) An ALPN callback function may also
 ignore ALPN

Reviewed-by: xuelei, wetmore
---
 jdk/src/java.base/share/classes/javax/net/ssl/SSLEngine.java | 4 +++-
 jdk/src/java.base/share/classes/javax/net/ssl/SSLSocket.java | 4 +++-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngine.java b/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngine.java
index 2c724f73a67..9613661afc2 100644
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngine.java
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngine.java
@@ -1338,7 +1338,7 @@ public abstract class SSLEngine {
     /**
      * Registers a callback function that selects an application protocol
      * value for a SSL/TLS/DTLS handshake.
-     * The function overrides any values set using
+     * The function overrides any values supplied using
      * {@link SSLParameters#setApplicationProtocols
      * SSLParameters.setApplicationProtocols} and it supports the following
      * type parameters:
@@ -1354,6 +1354,8 @@ public abstract class SSLEngine {
      * 
{@code String} *
The function's result is an application protocol name, or null to * indicate that none of the advertised names are acceptable. + * If the return value is an empty {@code String} then application + * protocol indications will not be used. * If the return value is null (no value chosen) or is a value that * was not advertised by the peer, the underlying protocol will * determine what action to take. (For example, ALPN will send a diff --git a/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocket.java b/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocket.java index ebbc9d9eb8d..2a00d8f7f26 100644 --- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocket.java +++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocket.java @@ -749,7 +749,7 @@ public abstract class SSLSocket extends Socket /** * Registers a callback function that selects an application protocol * value for a SSL/TLS/DTLS handshake. - * The function overrides any values set using + * The function overrides any values supplied using * {@link SSLParameters#setApplicationProtocols * SSLParameters.setApplicationProtocols} and it supports the following * type parameters: @@ -765,6 +765,8 @@ public abstract class SSLSocket extends Socket *
{@code String} *
The function's result is an application protocol name, or null to * indicate that none of the advertised names are acceptable. + * If the return value is an empty {@code String} then application + * protocol indications will not be used. * If the return value is null (no value chosen) or is a value that * was not advertised by the peer, the underlying protocol will * determine what action to take. (For example, ALPN will send a